zoukankan      html  css  js  c++  java
  • 《Linux总线、设备与驱动》USB设备发现机制

    说明:本分析基于mstar801平台Linux2.6.35.11内核,其他内核版本仅供参考。

    一、程序在内核中的位置

    1.usb host做为pci总线下的一个设备存在(嵌入式系统中有可能也会直接挂在CPU上);这部分驱动由厂家实现,本分析以mstar为例。

    2.USB总线驱动

    kernel/drivers/usb/core/driver.c

    1. EXPORT_SYMBOL_GPL(usb_register_driver);  
    2. EXPORT_SYMBOL_GPL(usb_deregister);  
    3. EXPORT_SYMBOL_GPL(usb_register_device_driver);  
    4. EXPORT_SYMBOL_GPL(usb_deregister_device_driver);  
    5. struct bus_type usb_bus_type = {  
    6.     .name =     "usb",  
    7.     .match =    usb_device_match,  
    8.     .uevent =   usb_uevent,  
    9. };  
    kernel/drivers/usb/core/usb.c
    1. static int __init usb_init(void){  
    2.   bus_register(&usb_bus_type);  
    3.   usb_register_device_driver(&usb_generic_driver, THIS_MODULE);  
    4. }  
    3.uvc camera设备驱动

    kernel/drivers/media/video/uvc/uvc_driver.c

    1. usb_register(&uvc_driver.driver);  

    二、所有总线、设备和驱动的注册函数

    1.设备注册

    kernel/drivers/base/core.c

    1. int device_register(struct device *dev){  
    2.   device_initialize(dev);  
    3.   return device_add(dev);  
    4. }  
    5. int device_add(struct device *dev){  //所有的设备注册都需要走这里!!!!!!  
    6.   error = bus_add_device(dev);  
    7.   kobject_uevent(&dev->kobj, KOBJ_ADD);  //上报uevent事件  
    8.   bus_probe_device(dev);  //添加到总线  
    9. }  
    2.驱动注册

    kernel/drivers/base/driver.c

    1. int driver_register(struct device_driver *drv){  //所有的驱动注册都要走这里!!!!!!!  
    2.   ret = bus_add_driver(drv);  //添加到总线  
    3. }  
    3.总线注册

    kernel/drivers/base/bus.c

    1. int bus_register(struct bus_type *bus);  

    三、具体分析

    情况一:当插入USB设备时USB host会检测到这一事件;然后通过USB core去匹配驱动。

      当守护程序第一次运行(特殊USB设备USB hub就是这种情况)或usb port上状态发生变化(其余所有USB设备插入都是这种情况)守护进程被唤醒时,会运行hub_events函数、USB的枚举过程就是由它完成。

    1.USB host部分代码

    说明:从硬件层面来看,ehci主控器从PCI总线桥接,是PCI驱动程序实例。

    kernel/drivers/usb/host/ehci-hcd.c

    1. module_init(ehci_hcd_init);  
    2. #define PCI_DRIVER      ehci_pci_driver    //利用pci中断  
    3. #define PLATFORM_DRIVER                 ehci_hcd_mstar_driver    //利用定时器轮询  
    4. static int __init ehci_hcd_init(void){  
    5. #ifdef PLATFORM_DRIVER  
    6.   platform_driver_register(&PLATFORM_DRIVER);  
    7. #endif  
    8. #ifdef PCI_DRIVER  
    9.   pci_register_driver(&PCI_DRIVER);  
    10. #endif  
    11. }  
    下边分两种情况:

    ==============================================

    定时器轮询:

    kernel/drivers/usb/host/ehci-mstar.c

    1. static struct platform_driver ehci_hcd_mstar_driver = {  
    2.   .probe          = ehci_hcd_mstar_drv_probe,  
    3. };  
    4. static int ehci_hcd_mstar_drv_probe(struct platform_device *pdev){  
    5.   usb_ehci_mstar_probe(&ehci_mstar_hc_driver, &hcd, pdev);  
    6. }  
    7. int usb_ehci_mstar_probe(const struct hc_driver *driver,struct usb_hcd **hcd_out, struct platform_device *dev){  
    8.   usb_create_hcd(driver, &dev->dev, "mstar");  
    9. }  
    kernel/drivers/usb/core/hcd.c
    1. struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name){  
    2.   return usb_create_shared_hcd(driver, dev, bus_name, NULL);  
    3. }  
    4. struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name, struct usb_hcd *primary_hcd){  
    5.   init_timer(&hcd->rh_timer);  
    6.   hcd->rh_timer.function = rh_timer_func;  
    7. }  
    8. static void rh_timer_func (unsigned long _hcd)                                                                                                   {  
    9.   usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);  
    10. }  
    11. void usb_hcd_poll_rh_status(struct usb_hcd *hcd){  
    12.   hcd->driver->hub_status_data(hcd, buffer);  
    13.   usb_hcd_giveback_urb(hcd, urb, 0);    
    14. }  

    ===================

    当有pci中断发生后:

    kernel/drivers/usb/host/ehci-pci.c

    1. static struct pci_driver ehci_pci_driver = {  
    2.   .id_table = pci_ids,  
    3. }  
    4. static const struct pci_device_id pci_ids [] = { {  
    5.     .driver_data =  (unsigned long) &ehci_pci_hc_driver,  
    6.   }  
    7. }  
    8. static const struct hc_driver ehci_pci_hc_driver = {  
    9.   .irq =          ehci_irq,  //中断  
    10.   .hub_status_data =  ehci_hub_status_data,  
    11.   .urb_enqueue = ehci_urb_enqueue,  
    12.   .urb_dequeue = ehci_urb_dequeue,  
    13. }  
    kernel/drivers/usb/host/ehci-hcd.c
    1. static irqreturn_t ehci_irq (struct usb_hcd *hcd){  
    2.   usb_hcd_poll_rh_status(hcd);  
    3. }  

    kernel/drivers/usb/core/hcd.c

    1. void usb_hcd_poll_rh_status(struct usb_hcd *hcd){  
    2.   hcd->driver->hub_status_data(hcd, buffer);  
    3.   usb_hcd_giveback_urb(hcd, urb, 0);  
    4. }  

    kernel/drivers/usb/host/ehci-hub.c

    1. static int ehci_hub_status_data (struct usb_hcd *hcd, char *buf){  
    2.   
    3. }  

    =====================================================================

    从以上分析可以看出;不论是定时器轮询还是pci中断,最终都会执行usb_hcd_giveback_urb函数:

    kernel/drivers/usb/core/hcd.c

    1. void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status){  
    2.   urb->complete (urb);  
    3. }  

    而上处urv->complete函数其实就是如下的hub_irq函数,后边会分析:

    kernel/drivers/usb/core/hub.c

    1. static void hub_irq(struct urb *urb){  
    2.   kick_khubd(hub);  
    3. }  

    2.USB core即USB总线部分代码——可以看到hub是第一个USB设备而且与USB总线密切相关

    kernel/drivers/usb/core/usb.c

    1. subsys_initcall(usb_init);  
    2. struct bus_type usb_bus_type = {  
    3.   .name =         "usb",  
    4.   .match =        usb_device_match,  
    5.   .uevent =       usb_uevent,  
    6. };  
    7. static int __init usb_init(void){  
    8.   bus_register(&usb_bus_type);  
    9.   usb_register_device_driver(&usb_generic_driver, THIS_MODULE);  //USB设备驱动,在没有root hub时使用  
    10.   usb_hub_init();  
    11. }  
    kernel/drivers/usb/core/hub.c
    1. static struct usb_driver hub_driver = {  
    2.   .name =         "hub",  
    3.   .probe =        hub_probe,  
    4. };  
    5. int usb_hub_init(void){  
    6.   usb_register(&hub_driver);  //USB设备驱动,第一个USB设备—root hub  
    7.   kthread_run(hub_thread, NULL, "khubd");  
    8. }  

    =====================================

    插句话:下边就是之前我们说的urv->complete被赋为hub_irq函数的过程;

    这里说明一下:hub的探测函数的执行是在守护线程第一次运行时的情况;为什么不需要USB总线轮询后或PCI总线中断后就执行?我们会在后边hub创建线程处看到。

    1. static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id){  
    2.   hub_configure(hub, endpoint);  
    3. }  
    4. static int hub_configure(struct usb_hub *hub,struct usb_endpoint_descriptor *endpoint){  
    5.   usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);  
    6. }  
    kernel/include/linux/usb.h
    1. static inline void usb_fill_int_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length,  
    2. usb_complete_t complete_fn, void *context, int interval){  
    3.   urb->complete = complete_fn;  
    4. }  
    =============================================

    kernel/drivers/usb/core/hub.c

    这里特别强调:hub设备是第一个USB设备,也是必须的USB设备;它不需要通过USB总线定时器轮询或PCI总线中断来触发。从下边代码也可以看出,在执行第一次hub_events之后(hub驱动的probe函数被执行、urv->complete被赋值hub_irq),该线程才会睡眠!

    1. static int hub_thread(void *__unused){  
    2.   do {  
    3.     hub_events(); //重要!最核心部分  
    4.     wait_event_freezable(khubd_wait,!list_empty(&hub_event_list) || kthread_should_stop());  
    5.   } while (!kthread_should_stop() || !list_empty(&hub_event_list));  
    6. }    
    7. //内核守护线程khubd,它被kick_khubd唤醒(当prot上状态发生变化时,USB host会调用usb_hcd_poll_rh_status去查询usb root hub port状态,并调用hub中的interrupt urb的回调函数hub_irq,最终去唤醒usb内核守护线程)、通过自身调用wait_event_freezable进入睡眠。     
    8. static void hub_events(void){  
    9.   if (connect_change)  hub_port_connect_change(hub, i, portstatus, portchange);  
    10. }  
    11. static void hub_port_connect_change(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange){  
    12.   status = hub_port_init(hub, udev, port1, i);  
    13.   status = usb_new_device(udev);  
    14. }  
    15. int usb_new_device(struct usb_device *udev){  
    16.   err = device_add(&udev->dev);  
    17.   (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);  
    18.   /* 
    19.   kernel/drivers/usb/core/endpoint.c 
    20.   int usb_create_ep_devs(struct device *parent,struct usb_host_endpoint *endpoint,struct usb_device *udev){ 
    21.     device_register(&ep_dev->dev); 
    22.   } 
    23.   */  
    24. }  
    kernel/drivers/base/core.c
    1. int device_add(struct device *dev){  //所有的设备注册都需要走这里!!!!!!  
    2.   error = bus_add_device(dev);  
    3.   kobject_uevent(&dev->kobj, KOBJ_ADD);  //上报uevent事件  
    4.   bus_probe_device(dev);  
    5. }  
    kernel/drivers/base/bus.c
    1. void bus_probe_device(struct device *dev){  
    2.   ret = device_attach(dev);  
    3. }  
    kernel/drivers/base/dd.c
    1. int device_attach(struct device *dev){  
    2.   ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);  
    3. }  
    kernel/drivers/base/bus.c
    1. int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,void *data, int (*fn)(struct device_driver *, void *)){  
    2.   while ((drv = next_driver(&i)) && !error)  
    3.     error = fn(drv, data);  
    4. }  
    kernel/drivers/base/dd.c
    1. static int __device_attach(struct device_driver *drv, void *data){  
    2.   if (!driver_match_device(drv, dev))  
    3.     return 0;  
    4.   /* 
    5.   kernel/drivers/base/base.h 
    6.   static inline int driver_match_device(struct device_driver *drv,struct device *dev){ 
    7.     return drv->bus->match ? drv->bus->match(dev, drv) : 1; 
    8.   } 
    9.   kernel/drivers/usb/core/driver.c 
    10.   static int usb_device_match(struct device *dev, struct device_driver *drv){ 
    11.     intf = to_usb_interface(dev); 
    12.     usb_drv = to_usb_driver(drv); 
    13.     if (id)  return 1; 
    14.     id = usb_match_dynamic_id(intf, usb_drv); 
    15.     if (id)  return 1; 
    16.     return 0; 
    17.   } 
    18.   */  
    19.   return driver_probe_device(drv, dev);  
    20. }  
    21. int driver_probe_device(struct device_driver *drv, struct device *dev){  
    22.   ret = really_probe(dev, drv);  
    23. }  
    24. static int really_probe(struct device *dev, struct device_driver *drv){  
    25.   dev->driver = drv;  
    26.   if (dev->bus->probe) {  
    27.     ret = dev->bus->probe(dev);  
    28.     if (ret)  goto probe_failed;  
    29.   } else if (drv->probe) {  
    30.     ret = drv->probe(dev);  
    31.     if (ret)  goto probe_failed;  
    32.   }  
    33. }  
    情况二:当加入USB设备驱动时,也会通过USB core调用mattch函数去匹配设备。

    kernel/drivers/media/video/uvc/uvc_driver.c

    1. struct uvc_driver uvc_driver = {  
    2.   .driver = {  
    3.     .name       = "uvcvideo",  
    4.     .probe      = uvc_probe,  
    5.     .disconnect = uvc_disconnect,  
    6.     .suspend    = uvc_suspend,  
    7.     .resume     = uvc_resume,  
    8.     .reset_resume   = uvc_reset_resume,  
    9.     .id_table   = uvc_ids,  
    10.     .supports_autosuspend = 1,  
    11.   },  
    12. };  
    13. module_init(uvc_init);  
    14. static int __init uvc_init(void){  
    15.   result = usb_register(&uvc_driver.driver);  
    16. }  
    kernel/include/linux/usb.h
    1. static inline int usb_register(struct usb_driver *driver){  
    2.   return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);  
    3. }  
    kernel/drivers/usb/core/driver.c
    1. int usb_register_driver(struct usb_driver *new_driver, struct module *owner, const char *mod_name){  
    2.   retval = driver_register(&new_driver->drvwrap.driver);  
    3. }  
    kernel/drivers/base/driver.c   
    1. int driver_register(struct device_driver *drv){  //所有的驱动注册都要走这里!!!!!!!  
    2.   ret = bus_add_driver(drv);  
    3. }  
    kernel/drivers/base/bus.c
    1. int bus_add_driver(struct device_driver *drv){  
    2.   error = driver_attach(drv);  
    3.   kobject_uevent(&priv->kobj, KOBJ_ADD);  
    4. }  
    kernel/drivers/base/dd.c
    1. int driver_attach(struct device_driver *drv){  
    2.   return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);  
    3. }  
    kernel/drivers/base/bus.c
    1. int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *)){  
    2.   while ((dev = next_device(&i)) && !error)  error = fn(dev, data);  
    3. }  
    kernel/drivers/base/dd.c
    1. static int __driver_attach(struct device *dev, void *data){  
    2.   if (!driver_match_device(drv, dev)) return 0;  
    3.   /* 
    4.   kernel/drivers/base/base.h 
    5.   static inline int driver_match_device(struct device_driver *drv,struct device *dev){ 
    6.     return drv->bus->match ? drv->bus->match(dev, drv) : 1; 
    7.   } 
    8.   kernel/drivers/usb/core/driver.c 
    9.   static int usb_device_match(struct device *dev, struct device_driver *drv){ 
    10.     intf = to_usb_interface(dev); 
    11.     usb_drv = to_usb_driver(drv); 
    12.     if (id)  return 1; 
    13.     id = usb_match_dynamic_id(intf, usb_drv); 
    14.     if (id)  return 1; 
    15.     return 0; 
    16.   } 
    17.   */  
    18.   if (!dev->driver) driver_probe_device(drv, dev);  
    19. }  
    20. int driver_probe_device(struct device_driver *drv, struct device *dev){  
    21.   ret = really_probe(dev, drv);  
    22. }  
    23. static int really_probe(struct device *dev, struct device_driver *drv){  
    24.   dev->driver = drv;  
    25.   if (dev->bus->probe) {  
    26.     ret = dev->bus->probe(dev);  
    27.     if (ret)  goto probe_failed;  
    28.   } else if (drv->probe) {  
    29.     ret = drv->probe(dev);  
    30.     if (ret)  goto probe_failed;  
    31.   }  
    32. }  

    3.总结

    经过分析,总结:

    (1).当总线上插入设备、总线会调用设备注册函数device_add/device_register;

    (2).当insmod设备驱动、module_init函数里边一定有driver_register;

    (3).通过上边分析,如上两个函数最终都会调用到总线驱动的match函数、进行匹配;如USB的总线match函数如下:

    kernel/drivers/usb/core/driver.c

    1. struct bus_type usb_bus_type = {  
    2.         .name =         "usb",  
    3.         .match =        usb_device_match,  
    4.         .uevent =       usb_uevent,  
    5.         .pm =           &usb_bus_pm_ops,  
    6. };  
    7. static int usb_device_match(struct device *dev, struct device_driver *drv)  
    8. {  
    9.         /* devices and interfaces are handled separately */  
    10.         if (is_usb_device(dev)) {  
    11.   
    12.                 /* interface drivers never match devices */  
    13.                 if (!is_usb_device_driver(drv))  
    14.                         return 0;  
    15.   
    16.                 /* TODO: Add real matching code */  
    17.                 return 1;  
    18.   
    19.         } else if (is_usb_interface(dev)) {  
    20.                 struct usb_interface *intf;  
    21.                 struct usb_driver *usb_drv;  
    22.                 const struct usb_device_id *id;  
    23.   
    24.                 /* device drivers never match interfaces */  
    25.                 if (is_usb_device_driver(drv))  
    26.                         return 0;  
    27.   
    28.                 intf = to_usb_interface(dev);  
    29.                 usb_drv = to_usb_driver(drv);  
    30.   
    31.                 id = usb_match_id(intf, usb_drv->id_table);//USB是匹配驱动中的id_table  
    32.                 if (id)  
    33.                         return 1;  
    34.   
    35.                 id = usb_match_dynamic_id(intf, usb_drv);  
    36.                 if (id)  
    37.                         return 1;  
    38.         }  
    39.   
    40.         return 0;  
    41. }  

    下边也看看UVC Camera驱动的id_table:

    kernel/drivers/media/video/uvc/uvc_driver.c

    1. struct uvc_driver uvc_driver = {  
    2.   .driver = {  
    3.     .name       = "uvcvideo",  
    4.     .probe      = uvc_probe,  
    5.     .disconnect = uvc_disconnect,  
    6.     .suspend    = uvc_suspend,  
    7.     .resume     = uvc_resume,  
    8.     .reset_resume   = uvc_reset_resume,  
    9.     .id_table   = uvc_ids,  
    10.     .supports_autosuspend = 1,  
    11.   },  
    12. };  
    13. static struct usb_device_id uvc_ids[] = {  
    14.     /* Microsoft Lifecam NX-6000 */  
    15.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    16.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    17.       .idVendor     = 0x045e,  
    18.       .idProduct        = 0x00f8,  
    19.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    20.       .bInterfaceSubClass   = 1,  
    21.       .bInterfaceProtocol   = 0,  
    22.       .driver_info      = UVC_QUIRK_PROBE_MINMAX },  
    23.     /* Microsoft Lifecam VX-7000 */  
    24.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    25.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    26.       .idVendor     = 0x045e,  
    27.       .idProduct        = 0x0723,  
    28.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    29.       .bInterfaceSubClass   = 1,  
    30.       .bInterfaceProtocol   = 0,  
    31.       .driver_info      = UVC_QUIRK_PROBE_MINMAX },  
    32.     /* Logitech Quickcam Fusion */  
    33.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    34.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    35.       .idVendor     = 0x046d,  
    36.       .idProduct        = 0x08c1,  
    37.       .bInterfaceClass  = USB_CLASS_VENDOR_SPEC,  
    38.       .bInterfaceSubClass   = 1,  
    39.       .bInterfaceProtocol   = 0 },  
    40.     /* Logitech Quickcam Orbit MP */  
    41.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    42.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    43.       .idVendor     = 0x046d,  
    44.       .idProduct        = 0x08c2,  
    45.       .bInterfaceClass  = USB_CLASS_VENDOR_SPEC,  
    46.       .bInterfaceSubClass   = 1,  
    47.       .bInterfaceProtocol   = 0 },  
    48.     /* Logitech Quickcam Pro for Notebook */  
    49.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    50.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    51.       .idVendor     = 0x046d,  
    52.       .idProduct        = 0x08c3,  
    53.       .bInterfaceClass  = USB_CLASS_VENDOR_SPEC,  
    54.       .bInterfaceSubClass   = 1,  
    55.       .bInterfaceProtocol   = 0 },  
    56.     /* Logitech Quickcam Pro 5000 */  
    57.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    58.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    59.       .idVendor     = 0x046d,  
    60.       .idProduct        = 0x08c5,  
    61.       .bInterfaceClass  = USB_CLASS_VENDOR_SPEC,  
    62.       .bInterfaceSubClass   = 1,  
    63.       .bInterfaceProtocol   = 0 },  
    64.     /* Logitech Quickcam OEM Dell Notebook */  
    65.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    66.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    67.       .idVendor     = 0x046d,  
    68.       .idProduct        = 0x08c6,  
    69.       .bInterfaceClass  = USB_CLASS_VENDOR_SPEC,  
    70.       .bInterfaceSubClass   = 1,  
    71.       .bInterfaceProtocol   = 0 },  
    72.     /* Logitech Quickcam OEM Cisco VT Camera II */  
    73.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    74.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    75.       .idVendor     = 0x046d,  
    76.       .idProduct        = 0x08c7,  
    77.       .bInterfaceClass  = USB_CLASS_VENDOR_SPEC,  
    78.       .bInterfaceSubClass   = 1,  
    79.       .bInterfaceProtocol   = 0 },  
    80.     /* Apple Built-In iSight */  
    81.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    82.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    83.       .idVendor     = 0x05ac,  
    84.       .idProduct        = 0x8501,  
    85.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    86.       .bInterfaceSubClass   = 1,  
    87.       .bInterfaceProtocol   = 0,  
    88.       .driver_info      = UVC_QUIRK_PROBE_MINMAX  
    89.                 | UVC_QUIRK_BUILTIN_ISIGHT },  
    90.     /* Genesys Logic USB 2.0 PC Camera */  
    91.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    92.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    93.       .idVendor     = 0x05e3,  
    94.       .idProduct        = 0x0505,  
    95.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    96.       .bInterfaceSubClass   = 1,  
    97.       .bInterfaceProtocol   = 0,  
    98.       .driver_info      = UVC_QUIRK_STREAM_NO_FID },  
    99.     /* MT6227 */  
    100.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    101.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    102.       .idVendor     = 0x0e8d,  
    103.       .idProduct        = 0x0004,  
    104.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    105.       .bInterfaceSubClass   = 1,  
    106.       .bInterfaceProtocol   = 0,  
    107.       .driver_info      = UVC_QUIRK_PROBE_MINMAX },  
    108.     /* Syntek (HP Spartan) */  
    109.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    110.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    111.       .idVendor     = 0x174f,  
    112.       .idProduct        = 0x5212,  
    113.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    114.       .bInterfaceSubClass   = 1,  
    115.       .bInterfaceProtocol   = 0,  
    116.       .driver_info      = UVC_QUIRK_STREAM_NO_FID },  
    117.     /* Syntek (Samsung Q310) */  
    118.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    119.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    120.       .idVendor     = 0x174f,  
    121.       .idProduct        = 0x5931,  
    122.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    123.       .bInterfaceSubClass   = 1,  
    124.       .bInterfaceProtocol   = 0,  
    125.       .driver_info      = UVC_QUIRK_STREAM_NO_FID },  
    126.     /* Asus F9SG */  
    127.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    128.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    129.       .idVendor     = 0x174f,  
    130.       .idProduct        = 0x8a31,  
    131.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    132.       .bInterfaceSubClass   = 1,  
    133.       .bInterfaceProtocol   = 0,  
    134.       .driver_info      = UVC_QUIRK_STREAM_NO_FID },  
    135.     /* Syntek (Asus U3S) */  
    136.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    137.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    138.       .idVendor     = 0x174f,  
    139.       .idProduct        = 0x8a33,  
    140.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    141.       .bInterfaceSubClass   = 1,  
    142.       .bInterfaceProtocol   = 0,  
    143.       .driver_info      = UVC_QUIRK_STREAM_NO_FID },  
    144.     /* Lenovo Thinkpad SL500 */  
    145.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    146.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    147.       .idVendor     = 0x17ef,  
    148.       .idProduct        = 0x480b,  
    149.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    150.       .bInterfaceSubClass   = 1,  
    151.       .bInterfaceProtocol   = 0,  
    152.       .driver_info      = UVC_QUIRK_STREAM_NO_FID },  
    153.     /* Ecamm Pico iMage */  
    154.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    155.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    156.       .idVendor     = 0x18cd,  
    157.       .idProduct        = 0xcafe,  
    158.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    159.       .bInterfaceSubClass   = 1,  
    160.       .bInterfaceProtocol   = 0,  
    161.       .driver_info      = UVC_QUIRK_PROBE_EXTRAFIELDS },  
    162.     /* Bodelin ProScopeHR */  
    163.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    164.                 | USB_DEVICE_ID_MATCH_DEV_HI  
    165.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    166.       .idVendor     = 0x19ab,  
    167.       .idProduct        = 0x1000,  
    168.       .bcdDevice_hi     = 0x0126,  
    169.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    170.       .bInterfaceSubClass   = 1,  
    171.       .bInterfaceProtocol   = 0,  
    172.       .driver_info      = UVC_QUIRK_STATUS_INTERVAL },  
    173.     /* SiGma Micro USB Web Camera */  
    174.     { .match_flags      = USB_DEVICE_ID_MATCH_DEVICE  
    175.                 | USB_DEVICE_ID_MATCH_INT_INFO,  
    176.       .idVendor     = 0x1c4f,  
    177.       .idProduct        = 0x3000,  
    178.       .bInterfaceClass  = USB_CLASS_VIDEO,  
    179.       .bInterfaceSubClass   = 1,  
    180.       .bInterfaceProtocol   = 0,  
    181.       .driver_info      = UVC_QUIRK_PROBE_MINMAX  
    182.                 | UVC_QUIRK_IGNORE_SELECTOR_UNIT  
    183.                 | UVC_QUIRK_PRUNE_CONTROLS },  
    184.     /* Generic USB Video Class */  
    185.     { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },  
    186.     {}  
    187. };  
    (4).如果匹配成功,会执行设备驱动的probe函数。我们关心的设备节点的创建也是在设备驱动的探测函数中被创建(因为这时的设备注册会附带主次设备号,内核通过netlink上报uevent事件后、用户空间的udevd服务会执行mknod创建设备节点)详见Linux驱动中uevent、netlink及kobject初探——kobject部分 和 Linux驱动中uevent、netlink及kobject初探——ueventd部分

    三、usb相关结构说明

    1.设备描述符

    1. struct usb_device_descriptor {  
    2.  __u8  bLength;              --描述符长度  
    3.  __u8  bDescriptorType;      --描述符类型:设备描述符0x01  
    4.  __le16 bcdUSB;              --usb规范版本号  
    5.  __u8  bDeviceClass;         --类代码  
    6.  __u8  bDeviceSubClass;      --子类代码  
    7.  __u8  bDeviceProtocol;      --协议代码  
    8.  __u8  bMaxPacketSize0;      --端点0支持最大数  
    9.  __le16 idVendor;            --供应商ID  
    10.  __le16 idProduct;           --产品ID  
    11.  __le16 bcdDevice;           --设备版本号  
    12.  __u8  iManufacturer;        --供应商字符串描述符的索引值  
    13.  __u8  iProduct;             --产品字符串描述符的索引值  
    14.  __u8  iSerialNumber;        --设备序列号  
    15.  __u8  bNumConfigurations;   --所支持的配置数  
    16. } __attribute__ ((packed));   --结构体字符类型对齐  

    2.配置描述符

    1. struct usb_config_descriptor {  
    2.  __u8  bLength;              --描述符长度  
    3.  __u8  bDescriptorType;      --描述符类型  
    4.  __le16 wTotalLength;        --配置信息的总长度  
    5.  __u8  bNumInterfaces;       --所支持的接口数  
    6.  __u8  bConfigurationValue;  --配置值  
    7.  __u8  iConfiguration;       --字符串描述符的索引值  
    8.  __u8  bmAttributes;         --配置特征  
    9.  __u8  bMaxPower;            --所需最大的总线电流  
    10. } __attribute__ ((packed));  
    3.接口描述符
    1. struct usb_interface_descriptor {  
    2.  __u8  bLength;  
    3.  __u8  bDescriptorType;  
    4.  __u8  bInterfaceNumber;     --接口编号  
    5.  __u8  bAlternateSetting;    --备用接口标号  
    6.  __u8  bNumEndpoints;        --接口数目  
    7.  __u8  bInterfaceClass;      --接口类型  
    8.  __u8  bInterfaceSubClass;   --接口子类型  
    9.  __u8  bInterfaceProtocol;   --接口所用协议  
    10.  __u8  iInterface;           --接口索引字符串数值  
    11. } __attribute__ ((packed));  
    4.端点描述符
    1. struct usb_endpoint_descriptor {  
    2.  __u8  bLength;  
    3.  __u8  bDescriptorType;  
    4.  __u8  bEndpointAddress;      --端点号包括传输方向  
    5.  __u8  bmAttributes;          --端点属性  
    6.  __le16 wMaxPacketSize;       --最大数据包长度  
    7.  __u8  bInterval;             --访问间隔  
    8.  __u8  bRefresh;                
    9.  __u8  bSynchAddress;  
    10. } __attribute__ ((packed));  

    usb总线驱动中对于设备和设备驱动的匹配函数,其实就是上述1和3的匹配过程

    见:kernel/drivers/usb/core/driver.c中usb_device_match函数,这部分可以进一步分析;在此、我不再分析。

    大致会匹配设备所属类(Input设备?Camera设备?Audio设备?或显示设备等)和VID、PID。

    五、urb数据传输分析

    未完待续

  • 相关阅读:
    MD支持新标签跳转
    线上问题cpu100处理记录
    OpenShift 4.6方式下OperatorHub的变化
    OpenShift 4.5.7 版本基础镜像下载
    GLPI企业使用(一),连接AD域,LDAP登录。
    GLPI配置文件说明:默认权限组
    企业服务器规划
    港股通转托管
    mui实现下拉刷新以及click事件无法响应问题
    asp.net core+websocket实现实时通信
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/8321798.html
Copyright © 2011-2022 走看看