《Linux總線、設備與驅動》USB設備發現機制

說明:本分析基於mstar801平臺Linux2.6.35.11內核,其餘內核版本僅供參考。linux

1、程序在內核中的位置git

1.usb host作爲pci總線下的一個設備存在(嵌入式系統中有可能也會直接掛在CPU上);這部分驅動由廠家實現,本分析以mstar爲例。ide

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.cui

  1. usb_register(&uvc_driver.driver);  

2、全部總線、設備和驅動的註冊函數spa

1.設備註冊.net

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.ccode

  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);  

3、具體分析

狀況一:當插入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部分

3、usb相關結構說明

1.設備描述符

[plain] view plain copy
  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.配置描述符

[plain] view plain copy
  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.接口描述符
[plain] view plain copy
  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.端點描述符
[plain] view plain copy
  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。

5、urb數據傳輸分析

未完待續

相關文章
相關標籤/搜索