USB Root Hub 分析_xHci



文章目录

  • 系列文章目录
  • 一、注册 usb_generic_driver
  • usb_generic_driver
  • usb_bus_type
  • usb_register_device_driver
  • generic_probe
  • choose_configuration
  • usb_hub_init
  • usb_register
  • driver_register
  • usb_device_match
  • hub_probe
  • hub_configure
  • hub_irq
  • kick_khubd



一、注册 usb_generic_driver

USB Root Hub 分析_usb_02

static int __init usb_init(void)
{
	// ...
	retval = bus_register(&usb_bus_type);
	// ...
	retval = usb_hub_init();
	retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
	// ...
}

usb_generic_driver

struct usb_device_driver usb_generic_driver = {
	.name =	"usb",
	.probe = generic_probe,
	.disconnect = generic_disconnect,
#ifdef	CONFIG_PM
	.suspend = generic_suspend,
	.resume = generic_resume,
#endif
	.supports_autosuspend = 1,
};

usb_bus_type

struct bus_type usb_bus_type = {
	.name =		"usb",
	.match =	usb_device_match,
	.uevent =	usb_uevent,
	.suspend =	usb_suspend,
	.resume =	usb_resume,
};

usb_register_device_driver

int usb_register_device_driver(struct usb_device_driver *new_udriver,
		struct module *owner)
{
	// ...
	new_udriver->drvwrap.for_devices = 1;
	new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
	new_udriver->drvwrap.driver.bus = &usb_bus_type;
	new_udriver->drvwrap.driver.probe = usb_probe_device;
	new_udriver->drvwrap.driver.remove = usb_unbind_device;
	new_udriver->drvwrap.driver.owner = owner;

	retval = driver_register(&new_udriver->drvwrap.driver);
	// ...
}
EXPORT_SYMBOL_GPL(usb_register_device_driver);

    usb_register_device_driver 函数中 driver_registerusb_generic_driver 驱动注册到 USB 总线 usb_bus_type 上。我们知道,每当驱动注册到总线上,其会识别挂载在总线上的设备。即识别 xHCI 简单分析 一文中 xhci_pci_probe 节扫描到的设备(register_root_hub)。

USB Root Hub 分析_usb_03

   从上面的脑图可以看出,由于 usb_bus_type.probe 为空,所以其调用的是 usb_generic_driver.generic_probe

generic_probe

USB Root Hub 分析_bc_04

static int generic_probe(struct usb_device *udev)
{
	// ...
	c = choose_configuration(udev);
	if (c >= 0) {
		err = usb_set_configuration(udev, c);
		// ...
	}
	/* USB device state == configured ... usable */
	usb_notify_add_device(udev);

	return 0;
}

    choose_configuration 就是这样按照自己的标准挑选了一个比较合自己心意的配置。usb_set_configuration 配置 USB 设备。

choose_configuration

int usb_set_configuration(struct usb_device *dev, int configuration)
{
	// ...
	for (i = 0; i < nintf; ++i) {
		// ...
		intf->cur_altsetting = alt;
		usb_enable_interface(dev, intf);
		intf->dev.parent = &dev->dev;
		intf->dev.driver = NULL;
		intf->dev.bus = &usb_bus_type;
		intf->dev.type = &usb_if_device_type;
		intf->dev.dma_mask = dev->dev.dma_mask;
		device_initialize (&intf->dev);
		// ...
	}
	// ...
	for (i = 0; i < nintf; ++i) {
		struct usb_interface *intf = cp->interface[i];
		// ...
		ret = device_add (&intf->dev);
		// ...
	}
	// ...
}

    usb_set_configuration 中对 USB 设备的每个接口进行初始化(创建 device 结构,并初始化),并挂载到总线 usb_bus_type 上 。这里是 Root Hub,所以相应的 hub 驱动会识别这些 device 。接下来我们看下 hub 的驱动。

usb_hub_init

static int __init usb_init(void)
{
	// ...
	retval = usb_hub_init();
	// ...
}

int usb_hub_init(void)
{
	if (usb_register(&hub_driver) < 0) {
		printk(KERN_ERR "%s: can't register hub driver\n",
			usbcore_name);
		return -1;
	}

	khubd_task = kthread_run(hub_thread, NULL, "khubd");
	if (!IS_ERR(khubd_task))
		return 0;

	/* Fall through if kernel_thread failed */
	usb_deregister(&hub_driver);
	printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);

	return -1;
}

static struct usb_driver hub_driver = {
	.name =		"hub",
	.probe =	hub_probe,
	.disconnect =	hub_disconnect,
	.suspend =	hub_suspend,
	.resume =	hub_resume,
	.pre_reset =	hub_pre_reset,
	.post_reset =	hub_post_reset,
	.ioctl =	hub_ioctl,
	.id_table =	hub_id_table,
	.supports_autosuspend =	1,
};

    usb_hub_init 函数注册 hub_driver 驱动,并且创建 hub_thread 内核线程。

usb_register

static inline int usb_register(struct usb_driver *driver)
{
	return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}

int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
			const char *mod_name)
{
	// ...
	new_driver->drvwrap.for_devices = 0;
	new_driver->drvwrap.driver.name = (char *) new_driver->name;
	new_driver->drvwrap.driver.bus = &usb_bus_type;
	new_driver->drvwrap.driver.probe = usb_probe_interface;
	new_driver->drvwrap.driver.remove = usb_unbind_interface;
	new_driver->drvwrap.driver.owner = owner;
	new_driver->drvwrap.driver.mod_name = mod_name;
	spin_lock_init(&new_driver->dynids.lock);
	INIT_LIST_HEAD(&new_driver->dynids.list);

	retval = driver_register(&new_driver->drvwrap.driver);
	// ...
}
EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);

    usb_registerusb_driver 进一步初始化,并注册到总线 usb_bus_type 上。driver_register 函数调用流程如下。

driver_register

USB Root Hub 分析_初始化_05

    从上图可知,其先调用总线的 match 函数,然后若总线上有 probe 函数则调用它,否则调用驱动的 probe 函数。

usb_device_match

static int usb_device_match(struct device *dev, struct device_driver *drv)
{
	/* devices and interfaces are handled separately */
	if (is_usb_device(dev)) {

		/* interface drivers never match devices */
		if (!is_usb_device_driver(drv))
			return 0;

		/* TODO: Add real matching code */
		return 1;

	} else {
		struct usb_interface *intf;
		struct usb_driver *usb_drv;
		const struct usb_device_id *id;

		/* device drivers never match interfaces */
		if (is_usb_device_driver(drv))
			return 0;

		intf = to_usb_interface(dev);
		usb_drv = to_usb_driver(drv);

		id = usb_match_id(intf, usb_drv->id_table);
		if (id)
			return 1;

		id = usb_match_dynamic_id(intf, usb_drv);
		if (id)
			return 1;
	}

	return 0;
}

    usb_device_match 从整体和接口两个方面来判定驱动与设备是否匹配。匹配则进一步调用 probe 函数,否则出错返回。在这里我们匹配的刚才的接口设备,所以其会调用 hub 驱动的 hub_probe 函数。

hub_probe

USB Root Hub 分析_PCIe_06

static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_host_interface *desc;
	struct usb_endpoint_descriptor *endpoint;
	struct usb_device *hdev;
	struct usb_hub *hub;

	desc = intf->cur_altsetting;
	// hdev 描述 USB 设备(HUB,描述整体,不是接口)
	hdev = interface_to_usbdev(intf);
	// ...
	// 接口描述其是 hub,所以创建 hub 结构体描述 hub
	hub = kzalloc(sizeof(*hub), GFP_KERNEL);
	// ...
	INIT_LIST_HEAD(&hub->event_list);
	hub->intfdev = &intf->dev;
	hub->hdev = hdev;
	INIT_DELAYED_WORK(&hub->leds, led_work);

	usb_set_intfdata (intf, hub);
	intf->needs_remote_wakeup = 1;

	if (hdev->speed == USB_SPEED_HIGH)
		highspeed_hubs++;

	if (hub_configure(hub, endpoint) >= 0)
		return 0;

	hub_disconnect (intf);
	return -ENODEV;
}

    接口描述其是 hub,所以创建 usb_hub 结构体描述 hubhub->intfdev 指向 hub 接口设备hub->hdev 指向 USB 设备(HUB)。hub_probe 函数调用 hub_configure 使用端点 0 初始化 hub

hub_configure

static int hub_configure(struct usb_hub *hub,
	struct usb_endpoint_descriptor *endpoint)
{
	// hub 设备
	struct usb_device *hdev = hub->hdev;
	// hub 接口设备
	struct device *hub_dev = hub->intfdev;
	// ...
	hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
			&hub->buffer_dma);
	// ...
	hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
	// ...
	ret = get_hub_descriptor(hdev, hub->descriptor,
			sizeof(*hub->descriptor));
	// ...
	hdev->maxchild = hub->descriptor->bNbrPorts;
	// ...
	INIT_LIST_HEAD (&hub->tt.clear_list);
	INIT_WORK (&hub->tt.kevent, hub_tt_kevent);
	switch (hdev->descriptor.bDeviceProtocol) {
		// ...
		case 2:
			ret = usb_set_interface(hdev, 0, 1);
		// ...
	}
	// ...
	ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
	// ...
	ret = hub_hub_status(hub, &hubstatus, &hubchange);
	// ...
	hub->urb = usb_alloc_urb(0, GFP_KERNEL);
	// ...
	usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
		hub, endpoint->bInterval);
	hub->urb->transfer_dma = hub->buffer_dma;
	hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	// ...
	hub_power_on(hub);
	hub_activate(hub);
	// ...
}

    hub_configure 中调用了 usb_fill_int_urb() 函数,并且把 hub_irq 作为一个参数传递了进去,最终把 urb->complete 赋值为 hub_irq 。然后,主机控制器会定期询问 Hub,每当 Hub 端口上有一个设备插入或者拔除时,它就会向主机控制器打小报告。具体来说,从硬件的角度看,就是 Hub 会向主机控制器返回一些信息,或者说 Data,这个 Data 被称作 “Hub and Port Status Change Bitmap”,而从软件角度来看,主机控制器的驱动程序接下来会在处理好这个过程的 urb 之后,调用该 urb 的 complete 函数,对于 Hub 来说,这个函数就是 hub_irq()

hub_irq

static void hub_irq(struct urb *urb)
{
	struct usb_hub *hub = urb->context;
	// ...
	switch (urb->status) {
	// ...
	/* let khubd handle things */
	case 0:			/* we got data:  port status changed */
		bits = 0;
		for (i = 0; i < urb->actual_length; ++i)
			bits |= ((unsigned long) ((*hub->buffer)[i]))
					<< (i*8);
		hub->event_bits[0] = bits;
		break;
	}

	hub->nerrors = 0;

	/* Something happened, let khubd figure it out */
	kick_khubd(hub);

resubmit:
	if (hub->quiescing)
		return;

	if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
			&& status != -ENODEV && status != -EPERM)
		dev_err (hub->intfdev, "resubmit --> %d\n", status);
}

kick_khubd

static void kick_khubd(struct usb_hub *hub)
{
	unsigned long	flags;

	/* Suppress autosuspend until khubd runs */
	to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;

	spin_lock_irqsave(&hub_event_lock, flags);
	if (list_empty(&hub->event_list)) {
		list_add_tail(&hub->event_list, &hub_event_list);
		wake_up(&khubd_wait);
	}
	spin_unlock_irqrestore(&hub_event_lock, flags);
}

    kick_khubd(),触发 Hub 的 event_list,于是再次调用 hub_events() 函数。在 usb_hub_init 函数中,我们创建了 hub_thread 内核线程,其会调用 hub_events()

static int hub_thread(void *__unused)
{
	do {
		hub_events();
		wait_event_interruptible(khubd_wait,
				!list_empty(&hub_event_list) ||
				kthread_should_stop());
		try_to_freeze();
	} while (!kthread_should_stop() || !list_empty(&hub_event_list));

	pr_debug("%s: khubd exiting\n", usbcore_name);
	return 0;
}