文章目录
- 系列文章目录
- 一、注册 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
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_register
把 usb_generic_driver
驱动注册到 USB 总线 usb_bus_type
上。我们知道,每当驱动注册到总线上,其会识别挂载在总线上的设备。即识别 xHCI 简单分析 一文中 xhci_pci_probe
节扫描到的设备(register_root_hub
)。
从上面的脑图可以看出,由于 usb_bus_type.probe
为空,所以其调用的是 usb_generic_driver.generic_probe
。
generic_probe
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_register
对 usb_driver
进一步初始化,并注册到总线 usb_bus_type
上。driver_register
函数调用流程如下。
driver_register
从上图可知,其先调用总线的 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
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
结构体描述 hub
。hub->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;
}
☆