赞
踩
限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。
本文基于 linux-4.14.132
内核代码进行分析。
其中:
1. Host 就是 USB 主机控制器(HCD),就是常说的 OHCI,UHCI,EHCI,xHCI , 内核用数据结构 struct usb_hcd 来描述。
2. RootHub 是集成到 USB 主机控制器(HCD) Host 的根集线器,根集线器上的端口用于连接USB设备:Hub或Func。
3. Func 表示USB设备,如U盘等。
一个 USB 主机控制器(HCD) 上最多可连接 127 个设备(HUB或Func),每个设备在枚举完成后会分配1个地址,地址区间为1~127,特殊地址0用于在设备枚举期间和主机控制器通信。
USB 主机(如带 Linux 系统的设备) USB Slave 设备 ---------------------------------------- ------------------------------ | USB设备驱动 | | | | ^ | | | | | | | | | v | | | | USB Core | | | | ^ | | | | | | | 如U盘、USB鼠标键盘 驱动固件 | | v | | | | USB主机控制器驱动(OHCI/UHCI/EHCI/xHCI) | | | | ^ | | | | | | | | | v | | | | USB主机控制器 | | | ---------------------------------------- ------------------------------ ^ ^ | | | USB 总线 | ------------------------------------------------
一个 USB 外设,它包含一系列的描述符,这些描述符用于定义 USB 外设的功能特性和行为逻辑。描述符包含以下类型:
设备描述符:每个设备有且仅有1个设备描述符。它定义设备的 PID & VID,包含的配置描述符的个数信息。
配置描述符:设备支持的接口数等信息。
接口描述符:接口包含的端点数,支持的协议类别、子类别,协议类型等信息。
端点描述符:端点是USB通信的基本单位。端点描述符包含端点类别、缓冲大小、地址等信息。
......
由于 USB 协议栈的内容过于庞大,也不是本文的重点,本篇将不做展开,感兴趣的童鞋可以参考 USB 官网 相关资料。
/* drivers/usb/core/usb.c */ static int __init usb_init(void) { int retval; ... /* * USB 调试系统初始化: * . 创建目录 /sys/kernel/debug/usb * . 创建文件 /sys/kernel/debug/usb/devices */ retval = usb_debugfs_init(); if (retval) goto out; ... retval = bus_register(&usb_bus_type); /* 注册 USB 总线类型 */ if (retval) goto bus_register_failed; /* * USB 总线 notifier 注册: * 在 usb device 或 interface 注册、注销时,增加、移除相关的 sysfs 目录树。 */ retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); if (retval) goto bus_notifier_failed; ... retval = usb_hub_init(); /* 注册 USB HUB 驱动 */ if (retval) goto hub_init_failed; /* 注册 USB device 通用驱动 */ retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); if (!retval) goto out; ... bus_notifier_failed: bus_unregister(&usb_bus_type); bus_register_failed: ... usb_debugfs_cleanup() out: return retval; } subsys_initcall(usb_init);
/* drivers/usb/core/hub.c */ static const struct usb_device_id hub_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS, .idVendor = USB_VENDOR_GENESYS_LOGIC, .bInterfaceClass = USB_CLASS_HUB, .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND}, { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, .bDeviceClass = USB_CLASS_HUB}, { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, .bInterfaceClass = USB_CLASS_HUB}, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, hub_id_table); static struct usb_driver hub_driver = { /* USB HUB 驱动 */ .name = "hub", .probe = hub_probe, .disconnect = hub_disconnect, .suspend = hub_suspend, .resume = hub_resume, .reset_resume = hub_reset_resume, .pre_reset = hub_pre_reset, .post_reset = hub_post_reset, .unlocked_ioctl = hub_ioctl, .id_table = hub_id_table, .supports_autosuspend = 1, }; int usb_hub_init(void) { /* 注册 USB HUB 驱动 */ if (usb_register(&hub_driver) < 0) { printk(KERN_ERR "%s: can't register hub driver\n", usbcore_name); return -1; } /* * The workqueue needs to be freezable to avoid interfering with * USB-PERSIST port handover. Otherwise it might see that a full-speed * device was gone before the EHCI controller had handed its port * over to the companion full-speed controller. */ hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0); if (hub_wq) return 0; ... }
USB 设备通用驱动 usb_generic_driver
注册:
/* drivers/usb/core/driver.c */ int usb_register_device_driver(struct usb_device_driver *new_udriver, struct module *owner) { int retval = 0; new_udriver->drvwrap.for_devices = 1; /* 标记为 device 级别的驱动 */ new_udriver->drvwrap.driver.name = 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); ... return retval; }
/* include/linux/usb.h */ /* use a define to avoid include chaining to get THIS_MODULE & friends */ #define usb_register(driver) \ usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME) /* drivers/usb/core/driver.c */ int usb_register_driver(struct usb_driver *new_driver, struct module *owner, const char *mod_name) { int retval = 0; ... new_driver->drvwrap.for_devices = 0; /* 标记为 interface 级别驱动 */ new_driver->drvwrap.driver.name = 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); ... return retval; }
上面的代码主要完成了以下3项工作:
1. USB 总线类型注册
2. USB HUB 驱动注册
3. USB 设备通用驱动注册
我们以支持 USB 2.0 的 EHCI USB 主机控制器
驱动为例进行阐述,而其它 OHCI,UHCI,xHCI
的主机控制器驱动,读者可自行阅读相关代码进行分析。
static int __init ehci_platform_init(void)
{
/* ehci-platform: EHCI generic platform driver */
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
/* 初始化 EHCI 主机控制器驱动 */
ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides);
/* 注册 EHCI 主机控制器 platform 驱动 */
return platform_driver_register(&ehci_platform_driver);
}
/* drivers/usb/host/ehci-hcd.c */ /* EHCI 主机控制器驱动 */ static const struct hc_driver ehci_hc_driver = { .description = hcd_name, .product_desc = "EHCI Host Controller", ... /* * generic hardware linkage */ .irq = ehci_irq, .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, .hcd_priv_size = sizeof(struct ehci_hcd), /* * basic lifecycle operations */ .reset = ehci_setup, .start = ehci_run, .stop = ehci_stop, .shutdown = ehci_shutdown, /* * managing i/o requests and associated device resources */ .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .endpoint_disable = ehci_endpoint_disable, .endpoint_reset = ehci_endpoint_reset, .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, /* * scheduling support */ .get_frame_number = ehci_get_frame, /* * root hub support */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, /* * device support */ .free_dev = ehci_remove_device, }; void ehci_init_driver(struct hc_driver *drv, const struct ehci_driver_overrides *over) { /* Copy the generic table to drv and then apply the overrides */ *drv = ehci_hc_driver; if (over) { drv->hcd_priv_size += over->extra_priv_size; if (over->reset) drv->reset = over->reset; if (over->port_power) drv->port_power = over->port_power; } }
USB 主机控制器(HCD)驱动
用数据结构 struct hc_driver
抽象。
看一下全志 H3 平台 EHCI
的 DTS 配置:
ehci0: usb@01c1a000 {
compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
reg = <0x01c1a000 0x100>;
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_EHCI0>, <&ccu CLK_BUS_OHCI0>;
resets = <&ccu RST_BUS_EHCI0>, <&ccu RST_BUS_OHCI0>;
status = "okay";
};
在系统启动期间,会为该 EHCI 主机控制器
创建一个 platform_device
对象,然后在注册 EHCI 主机控制器的 platform_driver
驱动时,触发 EHCI 主机控制器
platform 设备驱动的加载:
/* drivers/usb/host/echi-platform.c */ static const struct of_device_id vt8500_ehci_ids[] = { ... { .compatible = "generic-ehci", }, ... {} }; MODULE_DEVICE_TABLE(of, vt8500_ehci_ids); static struct platform_driver ehci_platform_driver = { .id_table = ehci_platform_table, .probe = ehci_platform_probe, .remove = ehci_platform_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ehci-platform", .pm = &ehci_platform_pm_ops, .of_match_table = vt8500_ehci_ids, .acpi_match_table = ACPI_PTR(ehci_acpi_match), } }; /* 加载 ECHI 的 platform_driver 驱动 */ static int ehci_platform_probe(struct platform_device *dev) { struct usb_hcd *hcd; ... int err, irq, phy_num, clk = 0, rst; ... /* * 解析中断配置: * interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; */ irq = platform_get_irq(dev, 0); ... /* 创建 USB ECHI 主机控制器(HCD)对象 */ hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, dev_name(&dev->dev)); ... ... /* 注册 USB ECHI 主机控制器对象 */ err = usb_add_hcd(hcd, irq, IRQF_SHARED); ... platform_set_drvdata(dev, hcd); return err; }
/* drivers/usb/core/hcd.c */ struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name) { return __usb_create_hcd(driver, dev, dev, bus_name, NULL); } struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, struct device *sysdev, struct device *dev, const char *bus_name, struct usb_hcd *primary_hcd) { struct usb_hcd *hcd; hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL); ... ... hcd->self.controller = dev; /* EHCI 的 platform_device */ ... hcd->self.bus_name = bus_name; init_timer(&hcd->rh_timer); hcd->rh_timer.function = rh_timer_func; hcd->rh_timer.data = (unsigned long) hcd; #ifdef CONFIG_PM INIT_WORK(&hcd->wakeup_work, hcd_resume_work); #endif hcd->driver = driver; /* 设定 EHCI 主机控制器的驱动: ehci_platform_hc_driver */ hcd->speed = driver->flags & HCD_MASK; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; return hcd; } int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { int retval; struct usb_device *rhdev; ... /* ehci-platform 1c1a000.usb: EHCI Host Controller */ dev_info(hcd->self.controller, "%s\n", hcd->product_desc/*ehci_hc_driver.product_desc*/); ... retval = hcd_buffer_create(hcd); ... retval = usb_register_bus(&hcd->self); ... ... /* 创建 ECHI 主机控制器 ROOT HUB 设备对象 */ rhdev = usb_alloc_dev(NULL, &hcd->self, 0); ... hcd->self.root_hub = rhdev; ... switch (hcd->speed) { ... case HCD_USB2: rhdev->speed = USB_SPEED_HIGH; break; ... } ... if (hcd->driver->reset) { /* 配置 EHCI 主机控制器 */ retval = hcd->driver->reset(hcd); /* ehci_setup() */ ... } /* initialize tasklets */ init_giveback_urb_bh(&hcd->high_prio_bh); init_giveback_urb_bh(&hcd->low_prio_bh); ... if (usb_hcd_is_primary_hcd(hcd) && irqnum) { /* 注册 ECHI 主机控制器中断处理接口 ehci_irq() */ retval = usb_hcd_request_irqs(hcd, irqnum, irqflags); ... } hcd->state = HC_STATE_RUNNING; /* 启动 EHCI 主机控制器 */ retval = hcd->driver->start(hcd); /* ehci_run() */ /* starting here, usbcore will pay attention to this root hub */ /* ECHI 主机控制器 ROOT HUB 设备对象注册 和 驱动加载 */ retval = register_root_hub(hcd); ... return retval; } static int usb_register_bus(struct usb_bus *bus) { ... busnum = idr_alloc(&usb_bus_idr, bus, 1, USB_MAXBUS, GFP_KERNEL); bus->busnum = busnum; ... usb_notify_add_bus(bus); /* ehci-platform 1c1a000.usb: new USB bus registered, assigned bus number 1 */ dev_info (bus->controller, "new USB bus registered, assigned bus " "number %d\n", bus->busnum); return 0; } /* 创建 USB 设备对象 (usb_device) */ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) // drivers/usb/core/usb.c { struct usb_device *dev; dev = kzalloc(sizeof(*dev), GFP_KERNEL); ... device_initialize(&dev->dev); dev->dev.bus = &usb_bus_type; dev->dev.type = &usb_device_type; dev->dev.groups = usb_device_groups; ... dev->state = USB_STATE_ATTACHED; ... dev->portnum = port1; dev->bus = bus; dev->parent = parent; ... return dev; } static int usb_hcd_request_irqs(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags) { if (hcd->driver->irq) { ... retval = request_irq(irqnum, &usb_hcd_irq, irqflags, hcd->irq_descr, hcd); ... hcd->irq = irqnum; ... } else { ... } return 0; }
来看 EHCI
主机控制器 ROOT HUB
设备对象注册和驱动加载的细节:
/* drivers/usb/core/hcd.c */ static int register_root_hub(struct usb_hcd *hcd) { struct device *parent_dev = hcd->self.controller; struct usb_device *usb_dev = hcd->self.root_hub; const int devnum = 1; int retval; usb_dev->devnum = devnum; usb_dev->bus->devnum_next = devnum + 1; ... usb_set_device_state(usb_dev, USB_STATE_ADDRESS); usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); ... retval = usb_new_device (usb_dev); ... return retval; }
/* drivers/usb/core/hub.c */ int usb_new_device(struct usb_device *udev) { ... err = usb_enumerate_device(udev); /* Read descriptors */ ... /* Tell the world! */ /* * usb usb1: New USB device found, idVendor=1d6b, idProduct=0002 * usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1 * usb usb1: Product: EHCI Host Controller * usb usb1: Manufacturer: Linux 4.14.111 ehci_hcd * usb usb1: SerialNumber: 1c1a000.usb */ announce_device(udev); /* * 注册 ECHI 控制器的 ROOT HUB 设备到 driver core , * 这将触发 HUB 驱动 hub_driver 加载: 即触发 hub_probe() . */ err = device_add(&udev->dev); ... (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); ... return err; } /* ECHI 主机控制器的 ROOT HUB 驱动加载 */ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_hub *hub; ... /* We found a hub */ dev_info(&intf->dev, "USB hub found\n"); /* hub 1-0:1.0: USB hub found */ /* 创建 USB HUB 对象 */ hub = kzalloc(sizeof(*hub), GFP_KERNEL); ... ... hub->intfdev = &intf->dev; hub->hdev = hdev; INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); INIT_WORK(&hub->events, hub_event); /* 设置用来处理 HUB 上 USB 设备枚举过程的 work */ ... ... if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) /* 配置 HUB */ return 0; ... } static int hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) { hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL); ... hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); ... hub->descriptor = kzalloc(sizeof(*hub->descriptor), GFP_KERNEL); ... /* * 读取 HUB 设备 @hdev 的 【HUB 描述符】 到 @hub->descriptor , * 搞清楚 HUB 上有几个 USB 连接端口。 */ ret = get_hub_descriptor(hdev, hub->descriptor); ... maxchild = hub->descriptor->bNbrPorts; /* * 如: hub 1-0:1.0: 1 port detected * 这日志表明,hub 1-0:1.0 上,物理上只有1个接口(1 port) * * hub 1-0:1.0: 6 ports detected * hub 2-0:1.0: 2 ports detected * hub 2-2:1.0: 7 ports detected */ dev_info(hub_dev, "%d port%s detected\n", maxchild, (maxchild == 1) ? "" : "s"); /* 为 HUB 上的 USB 端口创建对象 */ hub->ports = kzalloc(maxchild * sizeof(struct usb_port *), GFP_KERNEL); ... ... hub->urb = usb_alloc_urb(0, GFP_KERNEL); /* 分配用于 HUB 中断处理的 URB 对象 */ /* 初始化用于 HUB 中断处理的 URB 对象: 中断 URB complete 处理回调设为 hub_irq() */ usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval); ... for (i = 0; i < maxchild; i++) { /* 为 HUB 上的 usb 端口创建设备对象,并注册到 driver core */ ret = usb_hub_create_port_device(hub, i + 1); ... } hdev->maxchild = i; ... hub_activate(hub, HUB_INIT); return 0; } static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) { ... /* Scan all ports that need attention */ kick_hub_wq(hub); ... } static void kick_hub_wq(struct usb_hub *hub) { if (hub->disconnected || work_pending(&hub->events)) return; ... if (queue_work(hub_wq, &hub->events)) /* 触发 hub_event() */ return; ... }
从上面的代码看到,USB 主机控制器
用数据结构 struct usb_hcd
描述;USB HUB 设备
用数据结构 struct usb_hub
描述;USB HUB 上的端口
用数据结构 struct usb_port
描述;USB 端口上挂接的设备
用数据结构 struct usb_device
描述。
当设备插入到 USB 端口时,会产生中断信号,然后内核调用 HUB 的中断处理接口 hub_irq()
来处理中断信号:
/* drivers/usb/core/hub.c */ /* completion function, fires on port status changes and various faults */ static void hub_irq(struct urb *urb) { hub->nerrors = 0; /* Something happened, let hub_wq figure it out */ kick_hub_wq(hub); /* 调度 work: 触发 hub_event() 进一步处理设备插入事件 */ ... } static void hub_event(struct work_struct *work) { struct usb_device *hdev; struct usb_interface *intf; struct usb_hub *hub; struct device *hub_dev; u16 hubstatus; u16 hubchange; int i, ret; hub = container_of(work, struct usb_hub, events); hdev = hub->hdev; hub_dev = hub->intfdev; intf = to_usb_interface(hub_dev); ... /* deal with port status changes */ for (i = 1; i <= hdev->maxchild; i++) { struct usb_port *port_dev = hub->ports[i - 1]; /* HUB 的第 @i 个端口 */ if (test_bit(i, hub->event_bits) || test_bit(i, hub->change_bits)/* 端口上发生状态变化: 设备插入、拔出 */ || test_bit(i, hub->wakeup_bits)) { ... port_event(hub, i); /* 处理端口上的事件 */ ... } } ... } static void port_event(struct usb_hub *hub, int port1) __must_hold(&port_dev->status_lock) { int connect_change; connect_change = test_bit(port1, hub->change_bits); clear_bit(port1, hub->event_bits); clear_bit(port1, hub->wakeup_bits); if (hub_port_status(hub, port1, &portstatus, &portchange) < 0) return; ... if (connect_change) hub_port_connect_change(hub, port1, portstatus, portchange); } static void hub_port_connect_change(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange) __must_hold(&port_dev->status_lock { ... clear_bit(port1, hub->change_bits); ... usb_unlock_port(port_dev); hub_port_connect(hub, port1, portstatus, portchange); usb_lock_port(port_dev); } static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange) { ... status = 0; for (i = 0; i < SET_CONFIG_TRIES; i++) { udev = usb_alloc_dev(hdev, hdev->bus, port1); ... /* 复位设备, 为设备分配地址, 获取设备描述符(usb_device_descriptor) */ ... status = hub_port_init(hub, udev, port1, i); ... /* Run it through the hoops (find a driver, etc) */ if (!status) { ... status = usb_new_device(udev); /* 匹配设备到驱动,然后加载设备驱动 */ ... } } } static int hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, int retry_counter) { ... retval = hub_port_reset(hub, port1, udev, delay, false); ... if (udev->speed == USB_SPEED_WIRELESS) /* USB 无线网卡 */ speed = "variable speed Wireless"; else speed = usb_speed_string(udev->speed); /* 速度类型转字串描述 */ /* * 打印 USB 设备的 速度、编号、驱动名。如: * [ 1.928574] usb 2-1: new full-speed USB device number 2 using uhci_hcd * [ 2.261085] usb 2-2: new full-speed USB device number 3 using uhci_hcd */ if (udev->speed < USB_SPEED_SUPER) /* 非 USB 3.0: USB 2.5, USB 2.0, USB 1.0 */ dev_info(&udev->dev, "%s %s USB device number %d using %s\n", (udev->config) ? "reset" : "new", speed, devnum, driver_name); ... /* 获取 设备配置描述符 (USB_REQ_GET_DESCRIPTOR) 到 @udev->descriptor */ retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); ... } int usb_new_device(struct usb_device *udev) { ... /* 读取设备 配置描述符、字符串描述符、OTG 描述符、 quirk 配置 */ err = usb_enumerate_device(udev); /* Read descriptors */ ... ... /* Tell the world! */ announce_device(udev); /* usb usb2: New USB device found, idVendor=1d6b, idProduct=0002 */ ... err = device_add(&udev->dev); /* 添加设备到 driver core,将触发 USB 设备和驱动配对 */ ... ... return err; }
USB 设备驱动的匹配和加载概要流程如下:
device_add()
bus_add_device(dev)
bus_probe_device(dev)
device_initial_probe(dev)
__device_attach(dev, true)
bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver)
driver_match_device(drv, dev) /* 配对 USB 设备 和 驱动 */
driver_probe_device(drv, dev) /* 加载 USB 设备驱动 */
这里我们假定 USB 设备驱动
比 USB 设备
先注册。对于 USB 设备
比其 设备驱动
先注册的情形,匹配和加载过程是类似的,这里不再赘述。
USB 设备驱动匹配加载过程,对于不同类别的设备,过程上存在着一定差异,下面取几个典型的类别设备驱动匹配加载过程进行分析。
HUB 类设备
驱动加载过程前面在讲述 EHCI
主机控制器集成的 ROOT HUB
设备驱动加载过程中,没有描述 HUB 驱动和设备的匹配细节,我们将在本小节展开。对于非 ROOT HUB
和 ROOT HUB
设备的驱动加载过程,它们同样是通过 usb_new_device()
接口来加载驱动:
usb_new_device(udev)
device_add(&udev->dev)
...
driver_match_device(drv, dev) /* 配对 USB 设备 和 驱动 */
driver_probe_device(drv, dev) /* 加载 USB 设备驱动 */
下面就来看看 HUB 类设备驱动加载的细节 :
/* drivers/base/base.h */
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
/* 此处 drv->bus->match = usb_bus_type.match = usb_device_match() */
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
/* drivers/usb/core/driver.c */ static int usb_device_match(struct device *dev, struct device_driver *drv) { /* devices and interfaces are handled separately */ /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { /* interface drivers never match devices */ if (!is_usb_device_driver(drv)) /* 不是 device 级别的驱动,表示不匹配 */ return 0; /* TODO: Add real matching code */ return 1; /* 新插入的设备总是走这里: 先匹配到 usb_generic_driver */ } else if (is_usb_interface(dev)) { /* interface 设备驱动匹配,在后面详述 */ ... } return 0; }
所有新发现的 USB 设备(HUB 也是 USB 设备),首先都会先匹配到 USB 设备通用驱动 usb_generic_driver
,然后进入该驱动的 usb_probe_device()
接口:
driver_probe_device(drv, dev)
really_probe(dev, drv)
drv->probe(dev) = usb_probe_device()
/* drivers/usb/core/driver.c */
static int usb_probe_device(struct device *dev)
{
int error = 0;
...
if (!error)
error = udriver->probe(udev); /* generic_probe() */
return error;
}
/* drivers/usb/core/generic.c */ static int generic_probe(struct usb_device *udev) { int err, c; ... if (udev->authorized == 0) ... else { c = usb_choose_configuration(udev); if (c >= 0) { err = usb_set_configuration(udev, c); ... } } ... return 0; }
/* drivers/usb/core/message.c */ int usb_set_configuration(struct usb_device *dev, int configuration) { ... /* Allocate memory for new interfaces before doing anything else, * so that if we run out then nothing will have changed. */ n = nintf = 0; if (cp) { /* 为 USB 设备 的 所有 interface 创建对象 */ nintf = cp->desc.bNumInterfaces; new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), GFP_NOIO); ... for (; n < nintf; ++n) { new_interfaces[n] = kzalloc(sizeof(struct usb_interface), GFP_NOIO); ... } ... } ... /* 初始化 USB 设备的 所有 interface 设备 */ for (i = 0; i < nintf; ++i) { struct usb_interface_cache *intfc; struct usb_interface *intf; struct usb_host_interface *alt; cp->interface[i] = intf = new_interfaces[i]; ... alt = usb_altnum_to_altsetting(intf, 0); ... intf->cur_altsetting = alt; usb_enable_interface(dev, intf, true); intf->dev.parent = &dev->dev; intf->dev.driver = NULL; intf->dev.bus = &usb_bus_type; intf->dev.type = &usb_if_device_type; ... device_initialize(&intf->dev); ... } kfree(new_interfaces); /* 发送 SET_CONFIGURATION 请求 */ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, 0, configuration, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); ... dev->actconfig = cp; ... usb_set_device_state(dev, USB_STATE_CONFIGURED); ... for (i = 0; i < nintf; ++i) { struct usb_interface *intf = cp->interface[i]; ... device_enable_async_suspend(&intf->dev); /* * 添加 USB interface 设备到 driver core , * 触发 USB interface 设备驱动匹配流程 。 */ ret = device_add(&intf->dev); ... create_intf_ep_devs(intf); } usb_autosuspend_device(dev); return 0; }
device_add(&udev->dev) ... driver_match_device(drv, dev) /* 配对 USB 设备 和 驱动 */ driver_probe_device(drv, dev) /* 加载 USB 设备驱动 */ static inline int driver_match_device(struct device_driver *drv, struct device *dev) { /* 此处 drv->bus->match = usb_bus_type.match = usb_device_match() */ return drv->bus->match ? drv->bus->match(dev, drv) : 1; } static int usb_device_match(struct device *dev, struct device_driver *drv) { /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { /* USB interface 设备驱动匹配不走这里 */ ... } else if (is_usb_interface(dev)) { /* USB interface 设备驱动匹配走这里 */ 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)) /* hub_driver 在这里成立 */ return 0; intf = to_usb_interface(dev); usb_drv = to_usb_driver(drv); /* hub_driver */ 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 外设(如 U盘、USB 键鼠)读取到的 设备描述符
、interface 描述符
信息,匹配到 hub_driver
的 usb_device_id
表后,将加载 HUB 类设备的驱动:
driver_probe_device(drv, dev) /* 加载 USB 设备驱动 */
really_probe(dev, drv)
drv->probe(dev) = usb_probe_interface()
/* drivers/usb/core/driver.c */ /* called from driver core with dev locked */ static int usb_probe_interface(struct device *dev) { struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf = to_usb_interface(dev); struct usb_device *udev = interface_to_usbdev(intf); const struct usb_device_id *id; int error = -ENODEV; ... ... error = driver->probe(intf, id); /* 进入 HUB 驱动入口: hub_probe() */ ... .... return error; }
到此,HUB 类设备(包括 ROOT HUB
和 非 ROOT HUB
)驱动的加载过程完成。
非 HUB 类设备
驱动加载过程如 RealTek 的 R8152 USB 网卡,看它的驱动定义:
/* drivers/net/usb/r8152.c */ #define REALTEK_USB_DEVICE(vend, prod) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS, \ .idVendor = (vend), \ .idProduct = (prod), \ .bInterfaceClass = USB_CLASS_VENDOR_SPEC \ }, \ { \ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | \ USB_DEVICE_ID_MATCH_DEVICE, \ .idVendor = (vend), \ .idProduct = (prod), \ .bInterfaceClass = USB_CLASS_COMM, \ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ .bInterfaceProtocol = USB_CDC_PROTO_NONE /* table of devices that work with this driver */ static const struct usb_device_id rtl8152_table[] = { ... {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)}, ... {} }; MODULE_DEVICE_TABLE(usb, rtl8152_table); static struct usb_driver rtl8152_driver = { .name = MODULENAME, .id_table = rtl8152_table, .probe = rtl8152_probe, .disconnect = rtl8152_disconnect, .suspend = rtl8152_suspend, .resume = rtl8152_resume, .reset_resume = rtl8152_reset_resume, .pre_reset = rtl8152_pre_reset, .post_reset = rtl8152_post_reset, .supports_autosuspend = 1, .disable_hub_initiated_lpm = 1, }; module_usb_driver(rtl8152_driver);
当 usb_device_match()
匹配过程中,读取到 R8152 网卡设备描述符的 VID & PID 信息
,匹配到驱动的 rtl8152_driver
的 ID 匹配表 rtl8152_table[]
,则加载 R8152 驱动 rtl8152_driver
,进入 rtl8152_probe()
执行。
还有的 USB 设备,它们驱动的匹配表不指定 VID & PID,而是指定 interface class 信息。像这种情形,驱动的匹配是通过读取设备的 interface 描述符,然后提取其中的 interface class 信息进行匹配。
/* drivers/usb/class/usblp.c */ static const struct usb_device_id usblp_ids[] = { { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 1) }, ... { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, usblp_ids); static struct usb_driver usblp_driver = { .name = "usblp", .probe = usblp_probe, .disconnect = usblp_disconnect, .suspend = usblp_suspend, .resume = usblp_resume, .id_table = usblp_ids, .supports_autosuspend = 1, }; module_usb_driver(usblp_driver);
这是一个 USB 打印机类别设备的通用驱动,当从打印机的 interface 描述符
提取到的 class 信息,与驱动匹配表的 class 信息 USB_CLASS_PRINTER
匹配时,将加载驱动,进入驱动接口 usblp_probe()
执行。
还有更多其它驱动匹配的情形,细节呈现在 usb_device_match()
中,函数的逻辑不复杂,不在此处展开,感兴趣的读者可以自行阅读代码研究。
《Universal Serial Bus Specification》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。