一、USB设备描述符
一个USB设备描述符中可以有多个配置描述符,即USB设备可以有多种配置;一个配置描述符中可以有多个接口描述符,即USB设备可以支持多种功能(接口);一个接口描述符中可以有多个端点描述符。 一设备至少要包含设备描述符、配置描述符和接口描述符,如果USB设备没有端点描述符,则它仅仅用默认管道与主机进行数据传输。 接口,表示逻辑上的设备,比如USB声卡可以分为接口1-录音设备,接口2-播放设备。 访问设备时,即访问某个接口,接口表示逻辑设备。 传输数据时,即读写某个端口,端口是数据通道。
1.1 设备描述符
/* USB_DT_DEVICE: Device descriptor */ struct usb_device_descriptor { __u8 bLength; //该结构体大小 __u8 bDescriptorType; //描述符类型 (此处应为0x01,即设备描述符) __le16 bcdUSB; //usb版本号 200 -> USB2.0 __u8 bDeviceClass; //设备类 __u8 bDeviceSubClass; //设备类子类 __u8 bDeviceProtocol; //设备协议,以上三点都是USB官方定义 __u8 bMaxPacketSize0; //端点0最大包大小 (只能为8,16,32,64) __le16 idVendor; //厂家id __le16 idProduct; //产品id __le16 bcdDevice; //设备出厂编号 __u8 iManufacturer; //描述厂商信息的字符串描述符的索引值 __u8 iProduct; //描述产品信息的字串描述符的索引值 __u8 iSerialNumber; //描述设备序列号信息的字串描述符的索引值 __u8 bNumConfigurations; //可能的配置描述符的数目 } __attribute__ ((packed));
1.2 配置描述符
struct usb_config_descriptor { __u8 bLength; //该结构体大小 __u8 bDescriptorType;//描述符类型(本结构体中固定为0x02) __le16 wTotalLength; //该配置下,信息的总长度(包括配置,接口,端点和设备类及厂商定义的描述符) __u8 bNumInterfaces; //接口的个数 __u8 bConfigurationValue; //Set_Configuration命令所需要的参数值,用来选定此配置 __u8 iConfiguration; //描述该配置的字符串描述的索引值 __u8 bmAttributes;//供电模式的选择 __u8 bMaxPower;//设备从总线提取的最大电流 } __attribute__ ((packed));
1.3 接口描述符
struct usb_interface_descriptor { __u8 bLength; //该结构体大小 __u8 bDescriptorType;//接口描述符的类型编号(0x04) __u8 bInterfaceNumber; //该接口的编号 __u8 bAlternateSetting; //备用的接口描述符编号 __u8 bNumEndpoints; //该接口使用的端点数,不包括端点0 __u8 bInterfaceClass; //接口类 __u8 bInterfaceSubClass; //子类 __u8 bInterfaceProtocol; //协议 __u8 iInterface;//描述此接口的字串描述表的索引值 } __attribute__ ((packed));
配置描述符中包含了一个或多个接口描述符,这里的“接口”并不是指物理存在的接口,在这里把它称之为“功能”更易理解些,例如一个设备既有录音的功能又有扬声器的功能,则这个设备至少就有两个“接口”。
1.4 端点描述符
/* USB_DT_ENDPOINT: Endpoint descriptor */ struct usb_endpoint_descriptor { __u8 bLength; //端点描述符字节数大小(7个字节) __u8 bDescriptorType;//端点描述符类型编号(0x05) __u8 bEndpointAddress; //此描述表所描述的端点的地址、方向 : // bit3~bit0:端点号,bit6~bit4:保留, // bit7:方向,如果是控制端点则忽略,0-输出端点(主机到设备)1-输入端点(设备到主机) __u8 bmAttributes; // 端点特性,bit1~bit0 表示传输类型,其他位保留 // 00-控制传输 01-实时传输 10-批量传输 11-中断传输 __le16 wMaxPacketSize; //端点收、发的最大包大小 __u8 bInterval; // 中断传输模式中主机查询端点的时间间隔。 // 对于实时传输的端点此域必需为1,表示周期为1ms。对于中断传输的端点此域值的范围为1ms到255ms /* NOTE: these two are _only_ in audio endpoints. */ /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ __u8 bRefresh; __u8 bSynchAddress; } __attribute__ ((packed));
端点是设备与主机之间进行数据传输的逻辑接口,除配置使用的端点0(控制端点,一般一个设备只有一个控制端点)为双向端口外,其它均为单向。端点描述符描述了数据的传输类型、传输方向、数据包大小和端点号(也可称为端点地址)等。
除了描述符中描述的端点外,每个设备必须要有一个默认的控制型端点,地址为0,它的数据传输为双向,而且没有专门的描述符,只是在设备描述符中定义了它的最大包长度。主机通过此端点向设备发送命令,获得设备的各种描述符的信息,并通过它来配置设备。
1.5 字符描述符
struct usb_string_descriptor { __u8 bLength; // 此描述表的字节数(bString域的数值N+2) __u8 bDescriptorType; // 字串描述表类型(此处应为0x03)
__le16 wData[1]; /* UTF-16LE encoded */ } __attribute__ ((packed));
1.6 人机接口描述符
USB 设备中有一大类就是 HID 设备,即 Human Interface Devices,人机接口设备。这类设备包括鼠标、键盘等,主要用于人与计算机进行交互。 它是 USB 协议最早支持的一种设备类。 HID 设备可以作为低速、全速、高速设备用。由于 HID 设备要求用户输入能得到及时响应,故其传输方式通常采用中断方式。 在 USB 协议中, HID 设备的定义放置在接口描述符中, USB 的设备描述符和配置描述符中不包含 HID 设备的信息。因此,对于某些特定的 HID 设备,可以定义多个接口,只有其中一个接口为 HID 设备类即可。
1.7 USB描述符的类型值
二、USB总线驱动程序
2.1 usb core
初始化内核USB总线及提供USB相关API,为设备驱动和HCD的交互提供桥梁。
usb_init
static int __init usb_init(void) { int retval; if (usb_disabled()) { pr_info("%s: USB support disabled\n", usbcore_name); return 0; } usb_init_pool_max();
usb_debugfs_init();
usb_acpi_register(); retval = bus_register(&usb_bus_type); -----------------(1) if (retval) goto bus_register_failed; retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); if (retval) goto bus_notifier_failed; retval = usb_major_init(); if (retval) goto major_init_failed; retval = usb_register(&usbfs_driver); ---------------------------(2) if (retval) goto driver_register_failed; retval = usb_devio_init(); if (retval) goto usb_devio_init_failed; retval = usb_hub_init(); -----------------------------------(3) if (retval) goto hub_init_failed; retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);-------(4) if (!retval) goto out;
usb_hub_cleanup(); hub_init_failed: usb_devio_cleanup(); usb_devio_init_failed: usb_deregister(&usbfs_driver); driver_register_failed: usb_major_cleanup(); major_init_failed: bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); bus_notifier_failed: bus_unregister(&usb_bus_type); bus_register_failed: usb_acpi_unregister(); usb_debugfs_cleanup(); out: return retval; }
(1)USB是基于总线-驱动-设备模型的框架,其初始化阶段一个重点任务就是完成USB总线的创建。usb_bus_type提供了驱动和设备匹配的匹配函数,后面注册设备和驱动时会调用到。
usb_bus_type
struct bus_type usb_bus_type = { .name = "usb", .match = usb_device_match, //调用这个匹配函数 .uevent = usb_uevent, .need_parent_lock = true, };
使用bus_register接口注册USB总线,会创建出两条链表用来分别存放向USB总线注册的设备和驱动。如下:
int bus_register(struct bus_type *bus) { 。。。。
INIT_LIST_HEAD(&priv->interfaces); __mutex_init(&priv->mutex, "subsys mutex", key); klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); //设备链表 klist_init(&priv->klist_drivers, NULL, NULL); // 驱动链表
retval = add_probe_files(bus); if (retval) goto bus_probe_files_fail;
retval = bus_add_groups(bus, bus->bus_groups); 。。。。。。。 } EXPORT_SYMBOL_GPL(bus_register);
另外一篇具体分析bus_register的具体做了哪些事情。
(2)usbfs_driver 是usb 接口驱动,注册接口驱动。一个设备可以有多个接口,每个接口对应着不同的功能。在usb总线注册USB接口驱动,该驱动被放在usb总线的驱动链表中。
usbfs_driver
struct usb_driver usbfs_driver = { .name = "usbfs", .probe = driver_probe, .disconnect = driver_disconnect, .suspend = driver_suspend, .resume = driver_resume, .supports_autosuspend = 1, };
(3)初始化 usb hub, 初始化一个USB设备集线器,用来检测USB设备的连接和断开。
usb_hub_init()
int usb_hub_init(void) { if (usb_register(&hub_driver) < 0) { -----------------------(1) 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); --------(2) if (hub_wq) return 0;
/* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); pr_err("%s: can't allocate workqueue for usb hub\n", usbcore_name);
return -1; }
(3.1)注册 hub_driver.
hu_driver
static struct usb_driver hub_driver = { .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, };
(3.2) 创建一个工作队列usb_hub_wq, 用来处理USB设备的断开、连接等事件。在内核低版本中,是创建了内核线程,khubd_task = kthread_run(hub_thread, NULL, "khubd"); 而在内核高版本是使用的工作队列。
接着向usb 总线注册一个hub设备,触发 hub_probe,把hub event 压入hub_wq 工作队列
hub_probe -> hub_configure -> usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval); // usb_fill_int_urb 接口创建了一个中断类型的 USB请求控制块 hub_irq -> kick_hub_wq(hub) -> queue_work(hub_wq, &hub->events); //hub events 压入hub_wq 队列
(4) usb_register_device_driver(&usb_generic_driver, THIS_MODULE),向usb总线驱动链表中,注册 usb 设备驱动 usb_generic_driver。
usb_generic_driver
//drivers/usb/core/generic.c
struct usb_device_driver usb_generic_driver = { .name = "usb", .match = usb_generic_driver_match, .probe = usb_generic_driver_probe, .disconnect = usb_generic_driver_disconnect, #ifdef CONFIG_PM .suspend = usb_generic_driver_suspend, .resume = usb_generic_driver_resume, #endif .supports_autosuspend = 1, };
2.2 注册USB设备驱动
路径: drivers/usb/core/driver.c
int usb_register_device_driver(struct usb_device_driver *new_udriver, struct module *owner) { int retval = 0;
if (usb_disabled()) return -ENODEV;
new_udriver->drvwrap.for_devices = 1; new_udriver->drvwrap.driver.name = new_udriver->name; new_udriver->drvwrap.driver.bus = &usb_bus_type;
//usb 设备匹配,先会调用usb_probe_device,然后在该接口中调用driver的probe new_udriver->drvwrap.driver.probe = usb_probe_device; new_udriver->drvwrap.driver.remove = usb_unbind_device; new_udriver->drvwrap.driver.owner = owner; new_udriver->drvwrap.driver.dev_groups = new_udriver->dev_groups;
retval = driver_register(&new_udriver->drvwrap.driver);
if (!retval) { pr_info("%s: registered new device driver %s\n", usbcore_name, new_udriver->name); /* * Check whether any device could be better served with * this new driver */ bus_for_each_dev(&usb_bus_type, NULL, new_udriver, __usb_bus_reprobe_drivers); } else { pr_err("%s: error %d registering device driver %s\n", usbcore_name, retval, new_udriver->name); }
return retval; } EXPORT_SYMBOL_GPL(usb_register_device_driver);
usb_register_device_driver 注册一个通用USB设备驱动,而不是USB接口驱动。
2.3 usb_register 和 usb_register_device_driver 区别
usb_register 注册一个USB接口驱动,一个设备可以有多个接口,一个接口表示一种功能。比如USB声卡设备,有两个接口,一个播放接口,一个录音接口。
//drivers/usb/core/driver.c
#define usb_register(driver) \ usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
int usb_register_driver(struct usb_driver *new_driver, struct module *owner, const char *mod_name) { int retval = 0;
if (usb_disabled()) return -ENODEV;
new_driver->drvwrap.for_devices = 0; new_driver->drvwrap.driver.name = new_driver->name; new_driver->drvwrap.driver.bus = &usb_bus_type;
// 对应的usb接口“设备”被匹配时,首先会调用usb_probe_interface,然后在该接口中调用driver的probe 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; new_driver->drvwrap.driver.dev_groups = new_driver->dev_groups; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list);
retval = driver_register(&new_driver->drvwrap.driver); if (retval) goto out;
retval = usb_create_newid_files(new_driver); if (retval) goto out_newid;
pr_info("%s: registered new interface driver %s\n", usbcore_name, new_driver->name);
out: return retval;
out_newid: driver_unregister(&new_driver->drvwrap.driver);
pr_err("%s: error %d registering interface driver %s\n", usbcore_name, retval, new_driver->name); goto out; } EXPORT_SYMBOL_GPL(usb_register_driver);
总结:USB core注册了一个USB总线,并向USB总线中注册了三个驱动,分别是USB接口驱动、HUB驱动、USB设备驱动。其中在注册HUB驱动前创建了一个hub_wq 工作队列,用来处理hub上USB设备事件,比如插入和拔出;在HUB驱动的probe函数中,创建了一个urb并为其注册了一个timer中断处理函数hub_irq,hub wq 处理USB设备事件。
三、USB主机控制器驱动(HCD)
usb 主机控制器驱动 注册,有的使用platform_dirver 注册进系统,有的使用 pci_driver 注册进系统。具体使用哪种方式注册进系统,是根据usb控制器的硬件连接方式决定的。
我的PC机的XHCI驱动,就是pci_driver 方式
3.1下面分析以 platform 总线注册的OHCI主控驱动。
usb 主机控制器设备
// arch/arm/mach-s3c/mach-smdk2440.c
MACHINE_START(S3C2440, "SMDK2440") /* Maintainer: Ben Dooks
.init_irq = s3c2440_init_irq, .map_io = smdk2440_map_io, .init_machine = smdk2440_machine_init, .init_time = smdk2440_init_time, MACHINE_END
static void __init smdk2440_machine_init(void) { s3c24xx_fb_set_platdata(&smdk2440_fb_info); s3c_i2c0_set_platdata(NULL); /* Configure the I2S pins (GPE0...GPE4) in correct mode */ s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), S3C_GPIO_PULL_NONE); platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices)); smdk_machine_init(); }
static struct platform_device *smdk2440_devices[] __initdata = { &s3c_device_ohci, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, };
// arch/arm/mach-s3c/devs.c struct platform_device s3c_device_ohci = { .name = "s3c2410-ohci", .id = -1, .num_resources = ARRAY_SIZE(s3c_usb_resource), .resource = s3c_usb_resource, .dev = { .dma_mask = &samsung_device_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), } }; };
usb 主机控制器 驱动
// .config CONFIG_ARCH_S3C2410=y
// drivers/usb/host/ohci-hcd.c #ifdef CONFIG_ARCH_S3C2410 #include "ohci-s3c2410.c" #define PLATFORM_DRIVER ohci_hcd_s3c2410_driver #endif
static int __init ohci_hcd_mod_init(void) { int retval = 0;
if (usb_disabled()) return -ENODEV;
printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name); pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, sizeof (struct ed), sizeof (struct td));
#ifdef PS3_SYSTEM_BUS_DRIVER if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { retval = ps3_system_bus_driver_register( &PS3_SYSTEM_BUS_DRIVER); if (retval < 0) goto error_ps3; } #endif
#ifdef PLATFORM_DRIVER retval = platform_driver_register(&PLATFORM_DRIVER); if (retval < 0) goto error_platform; #endif
#ifdef OF_PLATFORM_DRIVER retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); if (retval < 0) goto error_of_platform; #endif
#ifdef SA1111_DRIVER retval = sa1111_driver_register(&SA1111_DRIVER); if (retval < 0) goto error_sa1111; #endif
#ifdef PCI_DRIVER retval = pci_register_driver(&PCI_DRIVER); if (retval < 0) goto error_pci; #endif
return retval;
/* Error path */ #ifdef PCI_DRIVER error_pci: #endif #ifdef SA1111_DRIVER sa1111_driver_unregister(&SA1111_DRIVER); error_sa1111: #endif #ifdef OF_PLATFORM_DRIVER of_unregister_platform_driver(&OF_PLATFORM_DRIVER); error_of_platform: #endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); error_platform: #endif #ifdef PS3_SYSTEM_BUS_DRIVER if (firmware_has_feature(FW_FEATURE_PS3_LV1)) ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); error_ps3: #endif return retval; } module_init(ohci_hcd_mod_init);
// drivers/usb/host/ohci-s3c2410.c static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_probe, .remove = ohci_hcd_s3c2410_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "s3c2410-ohci", .pm = &ohci_hcd_s3c2410_pm_ops, .of_match_table = ohci_hcd_s3c2410_dt_ids, }, };
主机控制器 设备和驱动匹配
//drivers/base/*
platform_driver_register-> driver_register-> bus_add_driver-> driver_attach-> bus_for_each_dev-> // 从平台总线的的设备链表中,取出每一项设备进行匹配 __driver_attach->
driver_match_device->// 此总线类型为平台总线,其存在match函数,即调用platform_match进行匹配
device_driver_attach-> //通过driver_match_device 驱动和设备匹配后,这个函数负责绑定,调用really_probe driver_probe_device-> really_probe->
drv-probe
static int __driver_attach(struct device *dev, void *data) { ......
ret = driver_match_device(drv, dev); .......... device_driver_attach(drv, dev);
return 0; }
// 平台总线 struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .dma_configure = platform_dma_configure, .pm = &platform_dev_pm_ops, }; EXPORT_SYMBOL_GPL(platform_bus_type);
static int platform_match(struct device * dev, struct device_driver * drv) {
struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */ if (pdev->driver_override) return !strcmp(pdev->driver_override, drv->name);
/* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1;
/* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1;
/* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0); // 平台总线匹配设备和驱动的名称 }
// ohci 设备 name = "s3c2410-ohci"
struct platform_device s3c_device_ohci = { .name = "s3c2410-ohci", .id = -1, .num_resources = ARRAY_SIZE(s3c_usb_resource), .resource = s3c_usb_resource, .dev = { .dma_mask = &samsung_device_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), } };
// ohci 驱动 name = "s3c2410-ohci"
static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_probe, .remove = ohci_hcd_s3c2410_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "s3c2410-ohci", .pm = &ohci_hcd_s3c2410_pm_ops, .of_match_table = ohci_hcd_s3c2410_dt_ids, }, };
匹配成功调用驱动的probe函数。
driver_probe_device-> // 在此函数中匹配成功的话,就会去调用驱动的probe函数 really_probe-> drv->probe(dev)
usb 主机控制器驱动的probe 函数
ohci_hcd_s3c2410_probe -> usb_add_hcd -> //向usb 增加主控驱动 rhdev = usb_alloc_dev //申请root hub hcd->self.root_hub = rhdev register_root_hub -> usb_new_device -> device_add -> bus_attach_device -> device_attach -> bus_for_each_drv -> // 从usb总线的的驱动链表中,取出每一项驱动进行匹配 __device_attach -> driver_match_device-> // 此总线类型为USB总线,其存在match函数,即调用usb_device_match进行匹配 driver_probe_device-> // 在此函数中匹配成功的话,就会去调用驱动的probe函数 really_probe-> drv->probe(dev)
上面在注册设备时,调用的__driver_attach进行绑定,现在注册驱动,调用__device_attach进行绑定。
接着分析:usb_device_match
static inline int is_usb_device(const struct device *dev) { return dev->type == &usb_device_type; }
/* Do the same for device drivers and interface drivers. */
static inline int is_usb_device_driver(struct device_driver *drv) { // struct device_driver 中 struct usbdrv_wrap 中的for_devices变量为1,则为USB设备驱动 // 上节USB Core中向USB总线注册的USB设备驱动中有将该变量设置为1(new_udriver->drvwrap.for_devices = 1;) return container_of(drv, struct usbdrv_wrap, driver)-> for_devices; }
static int usb_device_match(struct device *dev, struct device_driver *drv) { // USB设备 和 USB接口“设备”分开处理 /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { // 处理USB设备 /* interface drivers never match devices */ if (!is_usb_device_driver(drv)) return 0;
/* TODO: Add real matching code */ return 1;
} else { // 处理USB接口设备 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; }
probe 向USB总线注册一个root hub 设备,从usb总线的的驱动链表中,取出每一项驱动进行匹配。在USB Core中已经向总线注册了三个驱动(USB设备驱动、USB接口驱动、USB hub驱动),根据条件匹配到USB设备驱动,则去调用USB设备驱动的probe函数。
usb 设备驱动的probe函数:
struct usb_device_driver usb_generic_driver = { .name = "usb", .match = usb_generic_driver_match, .probe = usb_generic_driver_probe, .disconnect = usb_generic_driver_disconnect, #ifdef CONFIG_PM .suspend = usb_generic_driver_suspend, .resume = usb_generic_driver_resume, #endif .supports_autosuspend = 1, };
usb_generic_driver_probe(struct usb_device *udev) -> // 从上分析流程知udev为USB root hub设备 usb_set_configuration -> device_add -> // 创建USB接口设备,USB root hub接口设备被创建,device_add 又开始重复上面函数的流程
之后匹配到USB Core中注册的USB hub驱动,执行USB hub驱动的probe函数,该probe函数中,创建了一个urb并为其注册了一个中断处理函数hub_irq,hub_wq来处理USB设备事件(插入、拔出)。至此,系统启动初始化时关于USB的内容分析完成。USB Core和USB HCD的成功建立联系,为之后的USB设备驱动提供API。
推荐阅读
发表评论