http://blog.csdn.net/tankai19880619/article/details/11639185

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

一、程序在内核中的位置

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

2.USB总线驱动

kernel/drivers/usb/core/driver.c

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  1. usb_register(&uvc_driver.driver);

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

1.设备注册

kernel/drivers/base/core.c

[cpp] view plaincopy
  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

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

3.总线注册

kernel/drivers/base/bus.c

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  1. static irqreturn_t ehci_irq (struct usb_hcd *hcd){
  2. usb_hcd_poll_rh_status(hcd);
  3. }

kernel/drivers/usb/core/hcd.c

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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创建线程处看到。

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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),该线程才会睡眠!

int usb_hub_init(void)
{
pid_t pid;

if (usb_register(&hub_driver) < 0) {
printk(KERN_ERR "%s: can't register hub driver\n",
usbcore_name);
return -1;
}

pid = kernel_thread(hub_thread, NULL, CLONE_KERNEL);
if (pid >= 0) {
khubd_pid = pid;

return 0;
}

/* Fall through if kernel_thread failed */
usb_deregister(&hub_driver);
printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);

return -1;
}

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  1. void bus_probe_device(struct device *dev){
  2. ret = device_attach(dev);
  3. }

kernel/drivers/base/dd.c

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  1. int driver_register(struct device_driver *drv){  //所有的驱动注册都要走这里!!!!!!!
  2. ret = bus_add_driver(drv);
  3. }

kernel/drivers/base/bus.c

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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.设备描述符

[plain] view plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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设备(下)

    Linux下的硬件驱动--USB设备(下)(驱动开发部分) 文档选项 打印本页 将此页作为电子邮件发送 未显示需要 JavaScript 的文档选项 级别: 初级 赵明, 联想软件设计中心嵌入式研发处 ...

  2. Linux下的硬件驱动——USB设备

    想起当初对于破安卓手机,挂在系统上可是费了好些劲,今偶遇USB驱动开发,收集备用,哪天一生气,说不定也写一个linux下的手机驱动,类似于91手机助手的,也不用配置了. Linux下的硬件驱动--US ...

  3. Linux下的硬件驱动——USB设备(上)(驱动配置部分)

    USB设备越来越多,而Linux在硬件配置上仍然没有做到完全即插即用,对于Linux怎样配置和使用他们,也越来越成为困扰我们的一大问题.本文着力从Linux系统下设备驱动的架构,去阐述怎样去使用和配置 ...

  4. Linux下的硬件驱动——USB设备配置以及开发

    Linux下的硬件驱动--USB设备(上)(驱动配置部分) USB设备越来越多,而Linux在硬件配置上仍然没有做到完全即插即用,对于Linux怎样配置和使用他们,也越来越成为困扰我们的一大问题.本文 ...

  5. linux关于usb的使用,linux之常见的使用USB设备,linuxusb设备这些USB设备包括U

    linux之常见的使用USB设备,linuxusb设备这些USB设备包括U 软驱这个曾经的鸡肋终于彻底从电脑上消失了,取而代之的是容量更大,携带更方便,传输速度更快的USB设备.这些USB设备包括U盘 ...

  6. linux 设备型号,根据USB设备硬件信息获取Android设备型号

    前些日子,自己接手专门为Android设备开发的数据恢复软件,第一次作为项目经理带队进行项目开发. 其中为了解决设备和型号的对应关系,用于区分当前接入系统的设备是USB设备,并且是Android设备而 ...

  7. 通过mtd读写flash_【转】 Linux下读写FLASH驱动——MTD设备分析

    最近在学习驱动读写flash的代码部分.经历了可笑的过程:开始我知道flash用通过spi口来读写.所以就到了driver/spi 下面看相关代码.发现有个spidev.c里面有read/write/ ...

  8. linux 安装到usb设备,如何通过 USB 设备来安装 CentOS

    如何通过 USB 设备来安装 CentOS  其它用户比较喜欢「另类方法」部分内的某些做法,而且已证实适用于 CentOS-6. 以下程序已经被不同用户所测试,但未必能涵盖所有可能性.CentOS 计 ...

  9. linux自动挂载usb光驱,Linux下使用Usbmount实现USB设备自动挂载

    Usbmount 工具可以实现usb设备得自动加/卸载. $ sudo apt-get install usbmount usbmount的配置文件为/etc/usbmount/usbmount.co ...

  10. linux自动挂载usb打印机,Linux下使用Usbmount实现USB设备自动挂载

    Usbmount 工具可以实现usb设备得自动加/卸载. $$ sudo apt-get install usbmount usbmount的配置文件为/etc/usbmount/usbmount.c ...

最新文章

  1. 元素序列几个常用排序算法:一
  2. net的retrofit--WebApiClient库
  3. python数码时钟代码_Python+Pyqt实现简单GUI电子时钟
  4. Html跨页面调用函数,一个cshtml如何在另一个cshtml中调用一个函数?
  5. linux多进程编程(一)
  6. indesign图片规定在左下角_InDesign如何为目录模板设置母版
  7. 机器人学基础——位姿
  8. php图文编辑,ThinkPHP整合百度Ueditor编辑器的图文教程
  9. 什么是广域网(WAN)?
  10. 植物大战僵尸修改金币以及关卡
  11. IOS入门之StoryBoard
  12. 安卓案例:利用视图翻页器实现引导页
  13. 企业如何开通商户版微信支付及收款码?
  14. Math对象属性与方法
  15. Win32编程---在窗体添加一个按钮
  16. Android Telephony纲要
  17. 四大维度全景揭秘阿里巴巴智能对话开发平台 1
  18. 华为系统是计算机类型吗,华为Mate10秒变PC能否开启手机取代PC时代
  19. 大数据时代,隐私不能粗放管理
  20. 证照之星XE升级版本证件照制作工具

热门文章

  1. 后端开挂:3行代码 = 8个接口
  2. 基于SpringBoot +Vue+ ElementUI 开发的多用户博客管理平台,就是这么简单!
  3. 脑洞:如果地府需要一个后台管理系统,你会如何设计?
  4. 一文理清Mybatis中resultType与resultMap之间的关系和使用场景
  5. Spring Cloud Alibaba即将正式毕业,Netflix之后新生力量值得期待!
  6. 阿里云Redis开发规范
  7. android opencv 书籍,opencv android
  8. linux 服务器拦截http请求,详解Linux屏蔽浏览器上http请求警报的方法
  9. LAPJV算法学习笔记
  10. python meshgrid()理解