说明:本分析基于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. }

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

从以上分析可以看出;不论是定时器轮询还是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. /* interface drivers never match devices */
  12. if (!is_usb_device_driver(drv))
  13. return 0;
  14. /* TODO: Add real matching code */
  15. return 1;
  16. } else if (is_usb_interface(dev)) {
  17. struct usb_interface *intf;
  18. struct usb_driver *usb_drv;
  19. const struct usb_device_id *id;
  20. /* device drivers never match interfaces */
  21. if (is_usb_device_driver(drv))
  22. return 0;
  23. intf = to_usb_interface(dev);
  24. usb_drv = to_usb_driver(drv);
  25. id = usb_match_id(intf, usb_drv->id_table);//USB是匹配驱动中的id_table
  26. if (id)
  27. return 1;
  28. id = usb_match_dynamic_id(intf, usb_drv);
  29. if (id)
  30. return 1;
  31. }
  32. return 0;
  33. }

下边也看看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数据传输分析

未完待续

《Linux总线、设备与驱动》USB设备发现机制的更多相关文章

  1. Linux下的硬件驱动——USB设备(转载)

    usb_bulk_msg函数 当对usb设备进行一次读或者写时,usb_bulk_msg 函数是非常有用的; 然而, 当你需要连续地对设备进行读/写时,建议你建立一个自己的urbs,同时将urbs 提 ...

  2. 利用mass storage class 做免驱动usb设备.

    当需要使用usb bulk传输,想让设备像串口通讯那样和PC主机通信, 通常需要自己做一个PC端的驱动,比较麻烦. 为避免在pc上编写usb设备驱动的麻烦,可以将设备做成mass storage 类的 ...

  3. USB设备驱动总结

    现象:把USB设备接到PC        (韦老师总结) 1. 右下角弹出"发现android phone" 2. 跳出一个对话框,提示你安装驱动程序 问1. 既然还没有" ...

  4. USB设备驱动

    在Linux 内核中,使用usb_driver 结构体描述一个USB 设备驱动,usb_driver 结构体的定义如代码清单20.11 所示.代码清单20.11 usb_driver 结构体 stru ...

  5. USB设备驱动概述

    USB设备驱动 ·  )USB Hub:每个USBHost控制器都会自带一个USB Hub,被称为根(Root)Hub.这个根Hub可以接子(Sub)Hub,每个Hub上挂载USB设备.一般PC有8个 ...

  6. 虚拟机下Linux读取USB设备的问题虚拟机下Linux无法读取USB设备的解决方案

    我们在虚拟机中识别USB设备有三种情况导致Linux系统不能读取到USB设备: 1. .当虚拟机的USB服务没有开启的时候 2. 若虚拟机的USB连接的设置选项没有设置好 3. Widows抢先一步, ...

  7. USB设备驱动程序学习笔记(一)

    现象:把USB设备接到PC1. 右下角弹出"发现android phone"2. 跳出一个对话框,提示你安装驱动程序 问1. 既然还没有"驱动程序",为何能知道 ...

  8. 12、USB设备驱动程序

    linux-3.4.2\driver\hid\usbhid\usbmouse.c 内核只带USB驱动程序 (hub和usb是两个不同的设备,hub在内核上电的过程中在usb_hub_init函数中调用 ...

  9. USB协议-USB设备的枚举过程

    USB主机在检测到USB设备插入后,就要对设备进行枚举了.为什么要枚举?枚举就是从设备读取各种描述符信息,这样主机就可以根据这些信息来加载合适的驱动程序,从而知道设备是什么样的设备,如何进行通信等. ...

  10. USB设备的基本概念

    在终端用户看来,USB设备为主机提供了多种多样的附加功能,如文件传输,声音播放等,但对USB主机来说,它与所有USB设备的接口都是一致的.一个USB设备由3个功能模块组成:USB总线接口.USB逻辑设 ...

随机推荐

  1. List元素为泛型时的注意事项

    最近的项目赶得非常紧,这节奏跟最近的天气一点也不搭调. 编码的过程,遇到一个关于List的小问题. 在调用List.add(E e)的时候范了一个小毛病,很自然地认为list中存储的是 E  对象的另 ...

  2. [leetcode trie]212. Word Search II

    Given a 2D board and a list of words from the dictionary, find all words in the board. Each word mus ...

  3. bzoj4399 魔法少女LJJ 线段树合并

    只看题面绝对做不出系列.... 注意到\(c \leqslant 7\),因此不会有删边操作(那样例删边干嘛) 注意到\(2, 5\)操作十分的有趣,启示我们拿线段树合并来做 操作\(7\)很好处理 ...

  4. 20162307 课堂测试 hash

    20162307 课堂测试 hash 作业要求 利用除留余数法为下列关键字集合的存储设计hash函数,并画出分别用开放寻址法和拉链法解决冲突得到的空间存储状态(散列因子取0.75) 关键字集合:85, ...

  5. UVALive 4426 Blast the Enemy! 计算几何求重心

    D - Blast the Enemy! Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Subm ...

  6. POJ 1654 Area 计算几何

    #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> usi ...

  7. 使用NFS启动Tiny4412开发板根文件系统

      1.Ubuntu14.04上搭建NFS服务 1.1.安装NFS服务 $ sudo apt-get install nfs-kernel-server    //安装NFS服务 1.2 创建Tiny ...

  8. [重要更新][Quartus II][14.1正式版]

    [Quartus II][14.1正式版] ----14.1版本最大的变化就是增加了2大系列的器件库: MAX 10和Arria 10.这2大系列据Altera中国区代理 骏龙科技的人说,就是为了和X ...

  9. RAD Studio 2010~XE8 官方 ISO 下载地址 (2015-03-28更新)

    http://bbs.csdn.net/topics/390816856 RAD Studio XE8 目前最新版 v22.0.19027.8951 官方 ISO 文件下载(6.72GB):http: ...

  10. Netdata----Linux 性能实时监测工具

    https://my-netdata.io/ https://github.com/firehol/netdata/wiki http://soluck.iteye.com/blog/2291618