說明:本分析基於mstar801平臺Linux2.6.35.11內核,其餘內核版本僅供參考。linux
1、程序在內核中的位置git
1.usb host作爲pci總線下的一個設備存在(嵌入式系統中有可能也會直接掛在CPU上);這部分驅動由廠家實現,本分析以mstar爲例。ide
2.USB總線驅動函數
kernel/drivers/usb/core/driver.c大數據
- EXPORT_SYMBOL_GPL(usb_register_driver);
- EXPORT_SYMBOL_GPL(usb_deregister);
- EXPORT_SYMBOL_GPL(usb_register_device_driver);
- EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
- struct bus_type usb_bus_type = {
- .name = "usb",
- .match = usb_device_match,
- .uevent = usb_uevent,
- };
kernel/drivers/usb/core/usb.c
- static int __init usb_init(void){
- bus_register(&usb_bus_type);
- usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
- }
3.uvc camera設備驅動
kernel/drivers/media/video/uvc/uvc_driver.cui
- usb_register(&uvc_driver.driver);
2、全部總線、設備和驅動的註冊函數spa
1.設備註冊.net
kernel/drivers/base/core.c線程
- int device_register(struct device *dev){
- device_initialize(dev);
- return device_add(dev);
- }
- int device_add(struct device *dev){ //全部的設備註冊都須要走這裏!!!!!!
- error = bus_add_device(dev);
- kobject_uevent(&dev->kobj, KOBJ_ADD); //上報uevent事件
- bus_probe_device(dev); //添加到總線
- }
2.驅動註冊
kernel/drivers/base/driver.ccode
- int driver_register(struct device_driver *drv){ //全部的驅動註冊都要走這裏!!!!!!!
- ret = bus_add_driver(drv); //添加到總線
- }
3.總線註冊
kernel/drivers/base/bus.c
- 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
- module_init(ehci_hcd_init);
- #define PCI_DRIVER ehci_pci_driver //利用pci中斷
- #define PLATFORM_DRIVER ehci_hcd_mstar_driver //利用定時器輪詢
- static int __init ehci_hcd_init(void){
- #ifdef PLATFORM_DRIVER
- platform_driver_register(&PLATFORM_DRIVER);
- #endif
- #ifdef PCI_DRIVER
- pci_register_driver(&PCI_DRIVER);
- #endif
- }
下邊分兩種狀況:
==============================================
定時器輪詢:
kernel/drivers/usb/host/ehci-mstar.c
- static struct platform_driver ehci_hcd_mstar_driver = {
- .probe = ehci_hcd_mstar_drv_probe,
- };
- static int ehci_hcd_mstar_drv_probe(struct platform_device *pdev){
- usb_ehci_mstar_probe(&ehci_mstar_hc_driver, &hcd, pdev);
- }
- int usb_ehci_mstar_probe(const struct hc_driver *driver,struct usb_hcd **hcd_out, struct platform_device *dev){
- usb_create_hcd(driver, &dev->dev, "mstar");
- }
kernel/drivers/usb/core/hcd.c
- struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name){
- return usb_create_shared_hcd(driver, dev, bus_name, NULL);
- }
- struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name, struct usb_hcd *primary_hcd){
- init_timer(&hcd->rh_timer);
- hcd->rh_timer.function = rh_timer_func;
- }
- static void rh_timer_func (unsigned long _hcd) {
- usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
- }
- void usb_hcd_poll_rh_status(struct usb_hcd *hcd){
- hcd->driver->hub_status_data(hcd, buffer);
- usb_hcd_giveback_urb(hcd, urb, 0);
- }
===================
當有pci中斷髮生後:
kernel/drivers/usb/host/ehci-pci.c
- static struct pci_driver ehci_pci_driver = {
- .id_table = pci_ids,
- }
- static const struct pci_device_id pci_ids [] = { {
- .driver_data = (unsigned long) &ehci_pci_hc_driver,
- }
- }
- static const struct hc_driver ehci_pci_hc_driver = {
- .irq = ehci_irq, //中斷
- .hub_status_data = ehci_hub_status_data,
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- }
kernel/drivers/usb/host/ehci-hcd.c
- static irqreturn_t ehci_irq (struct usb_hcd *hcd){
- usb_hcd_poll_rh_status(hcd);
- }
kernel/drivers/usb/core/hcd.c
- void usb_hcd_poll_rh_status(struct usb_hcd *hcd){
- hcd->driver->hub_status_data(hcd, buffer);
- usb_hcd_giveback_urb(hcd, urb, 0);
- }
kernel/drivers/usb/host/ehci-hub.c
- static int ehci_hub_status_data (struct usb_hcd *hcd, char *buf){
-
- }
=====================================================================
從以上分析能夠看出;不管是定時器輪詢仍是pci中斷,最終都會執行usb_hcd_giveback_urb函數:
kernel/drivers/usb/core/hcd.c
- void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status){
- urb->complete (urb);
- }
而上處urv->complete函數其實就是以下的hub_irq函數,後邊會分析:
kernel/drivers/usb/core/hub.c
- static void hub_irq(struct urb *urb){
- kick_khubd(hub);
- }
2.USB core即USB總線部分代碼——能夠看到hub是第一個USB設備並且與USB總線密切相關
kernel/drivers/usb/core/usb.c
- subsys_initcall(usb_init);
- struct bus_type usb_bus_type = {
- .name = "usb",
- .match = usb_device_match,
- .uevent = usb_uevent,
- };
- static int __init usb_init(void){
- bus_register(&usb_bus_type);
- usb_register_device_driver(&usb_generic_driver, THIS_MODULE); //USB設備驅動,在沒有root hub時使用
- usb_hub_init();
- }
kernel/drivers/usb/core/hub.c
- static struct usb_driver hub_driver = {
- .name = "hub",
- .probe = hub_probe,
- };
- int usb_hub_init(void){
- usb_register(&hub_driver); //USB設備驅動,第一個USB設備—root hub
- kthread_run(hub_thread, NULL, "khubd");
- }
=====================================
插句話:下邊就是以前咱們說的urv->complete被賦爲hub_irq函數的過程;
這裏說明一下:hub的探測函數的執行是在守護線程第一次運行時的狀況;爲何不須要USB總線輪詢後或PCI總線中斷後就執行?咱們會在後邊hub建立線程處看到。
- static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id){
- hub_configure(hub, endpoint);
- }
- static int hub_configure(struct usb_hub *hub,struct usb_endpoint_descriptor *endpoint){
- usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval);
- }
kernel/include/linux/usb.h
- static inline void usb_fill_int_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *transfer_buffer, int buffer_length,
- usb_complete_t complete_fn, void *context, int interval){
- urb->complete = complete_fn;
- }
=============================================
kernel/drivers/usb/core/hub.c
這裏特別強調:hub設備是第一個USB設備,也是必須的USB設備;它不須要經過USB總線定時器輪詢或PCI總線中斷來觸發。從下邊代碼也能夠看出,在執行第一次hub_events以後(hub驅動的probe函數被執行、urv->complete被賦值hub_irq),該線程纔會睡眠!
- static int hub_thread(void *__unused){
- do {
- hub_events(); //重要!最核心部分
- wait_event_freezable(khubd_wait,!list_empty(&hub_event_list) || kthread_should_stop());
- } while (!kthread_should_stop() || !list_empty(&hub_event_list));
- }
- //內核守護線程khubd,它被kick_khubd喚醒(當prot上狀態發生變化時,USB host會調用usb_hcd_poll_rh_status去查詢usb root hub port狀態,並調用hub中的interrupt urb的回調函數hub_irq,最終去喚醒usb內核守護線程)、經過自身調用wait_event_freezable進入睡眠。
- static void hub_events(void){
- if (connect_change) hub_port_connect_change(hub, i, portstatus, portchange);
- }
- static void hub_port_connect_change(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange){
- status = hub_port_init(hub, udev, port1, i);
- status = usb_new_device(udev);
- }
- int usb_new_device(struct usb_device *udev){
- err = device_add(&udev->dev);
- (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
- /*
- kernel/drivers/usb/core/endpoint.c
- int usb_create_ep_devs(struct device *parent,struct usb_host_endpoint *endpoint,struct usb_device *udev){
- device_register(&ep_dev->dev);
- }
- */
- }
kernel/drivers/base/core.c
- int device_add(struct device *dev){ //全部的設備註冊都須要走這裏!!!!!!
- error = bus_add_device(dev);
- kobject_uevent(&dev->kobj, KOBJ_ADD); //上報uevent事件
- bus_probe_device(dev);
- }
kernel/drivers/base/bus.c
- void bus_probe_device(struct device *dev){
- ret = device_attach(dev);
- }
kernel/drivers/base/dd.c
- int device_attach(struct device *dev){
- ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
- }
kernel/drivers/base/bus.c
- int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,void *data, int (*fn)(struct device_driver *, void *)){
- while ((drv = next_driver(&i)) && !error)
- error = fn(drv, data);
- }
kernel/drivers/base/dd.c
- static int __device_attach(struct device_driver *drv, void *data){
- if (!driver_match_device(drv, dev))
- return 0;
- /*
- kernel/drivers/base/base.h
- static inline int driver_match_device(struct device_driver *drv,struct device *dev){
- return drv->bus->match ? drv->bus->match(dev, drv) : 1;
- }
- kernel/drivers/usb/core/driver.c
- static int usb_device_match(struct device *dev, struct device_driver *drv){
- intf = to_usb_interface(dev);
- usb_drv = to_usb_driver(drv);
- if (id) return 1;
- id = usb_match_dynamic_id(intf, usb_drv);
- if (id) return 1;
- return 0;
- }
- */
- return driver_probe_device(drv, dev);
- }
- int driver_probe_device(struct device_driver *drv, struct device *dev){
- ret = really_probe(dev, drv);
- }
- static int really_probe(struct device *dev, struct device_driver *drv){
- dev->driver = drv;
- if (dev->bus->probe) {
- ret = dev->bus->probe(dev);
- if (ret) goto probe_failed;
- } else if (drv->probe) {
- ret = drv->probe(dev);
- if (ret) goto probe_failed;
- }
- }
狀況二:當加入USB設備驅動時,也會經過USB core調用mattch函數去匹配設備。
kernel/drivers/media/video/uvc/uvc_driver.c
- struct uvc_driver uvc_driver = {
- .driver = {
- .name = "uvcvideo",
- .probe = uvc_probe,
- .disconnect = uvc_disconnect,
- .suspend = uvc_suspend,
- .resume = uvc_resume,
- .reset_resume = uvc_reset_resume,
- .id_table = uvc_ids,
- .supports_autosuspend = 1,
- },
- };
- module_init(uvc_init);
- static int __init uvc_init(void){
- result = usb_register(&uvc_driver.driver);
- }
kernel/include/linux/usb.h
- static inline int usb_register(struct usb_driver *driver){
- return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
- }
kernel/drivers/usb/core/driver.c
- int usb_register_driver(struct usb_driver *new_driver, struct module *owner, const char *mod_name){
- retval = driver_register(&new_driver->drvwrap.driver);
- }
kernel/drivers/base/driver.c
- int driver_register(struct device_driver *drv){ //全部的驅動註冊都要走這裏!!!!!!!
- ret = bus_add_driver(drv);
- }
kernel/drivers/base/bus.c
- int bus_add_driver(struct device_driver *drv){
- error = driver_attach(drv);
- kobject_uevent(&priv->kobj, KOBJ_ADD);
- }
kernel/drivers/base/dd.c
- int driver_attach(struct device_driver *drv){
- return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
- }
kernel/drivers/base/bus.c
- int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *)){
- while ((dev = next_device(&i)) && !error) error = fn(dev, data);
- }
kernel/drivers/base/dd.c
- static int __driver_attach(struct device *dev, void *data){
- if (!driver_match_device(drv, dev)) return 0;
- /*
- kernel/drivers/base/base.h
- static inline int driver_match_device(struct device_driver *drv,struct device *dev){
- return drv->bus->match ? drv->bus->match(dev, drv) : 1;
- }
- kernel/drivers/usb/core/driver.c
- static int usb_device_match(struct device *dev, struct device_driver *drv){
- intf = to_usb_interface(dev);
- usb_drv = to_usb_driver(drv);
- if (id) return 1;
- id = usb_match_dynamic_id(intf, usb_drv);
- if (id) return 1;
- return 0;
- }
- */
- if (!dev->driver) driver_probe_device(drv, dev);
- }
- int driver_probe_device(struct device_driver *drv, struct device *dev){
- ret = really_probe(dev, drv);
- }
- static int really_probe(struct device *dev, struct device_driver *drv){
- dev->driver = drv;
- if (dev->bus->probe) {
- ret = dev->bus->probe(dev);
- if (ret) goto probe_failed;
- } else if (drv->probe) {
- ret = drv->probe(dev);
- if (ret) goto probe_failed;
- }
- }
3.總結
通過分析,總結:
(1).當總線上插入設備、總線會調用設備註冊函數device_add/device_register;
(2).當insmod設備驅動、module_init函數裏邊必定有driver_register;
(3).經過上邊分析,如上兩個函數最終都會調用到總線驅動的match函數、進行匹配;如USB的總線match函數以下:
kernel/drivers/usb/core/driver.c
- struct bus_type usb_bus_type = {
- .name = "usb",
- .match = usb_device_match,
- .uevent = usb_uevent,
- .pm = &usb_bus_pm_ops,
- };
- static int usb_device_match(struct device *dev, struct device_driver *drv)
- {
- /* devices and interfaces are handled separately */
- if (is_usb_device(dev)) {
-
- /* interface drivers never match devices */
- if (!is_usb_device_driver(drv))
- return 0;
-
- /* TODO: Add real matching code */
- return 1;
-
- } else if (is_usb_interface(dev)) {
- struct usb_interface *intf;
- struct usb_driver *usb_drv;
- const struct usb_device_id *id;
-
- /* device drivers never match interfaces */
- if (is_usb_device_driver(drv))
- return 0;
-
- intf = to_usb_interface(dev);
- usb_drv = to_usb_driver(drv);
-
- id = usb_match_id(intf, usb_drv->id_table);//USB是匹配驅動中的id_table
- if (id)
- return 1;
-
- id = usb_match_dynamic_id(intf, usb_drv);
- if (id)
- return 1;
- }
-
- return 0;
- }
下邊也看看UVC Camera驅動的id_table:
kernel/drivers/media/video/uvc/uvc_driver.c
- struct uvc_driver uvc_driver = {
- .driver = {
- .name = "uvcvideo",
- .probe = uvc_probe,
- .disconnect = uvc_disconnect,
- .suspend = uvc_suspend,
- .resume = uvc_resume,
- .reset_resume = uvc_reset_resume,
- .id_table = uvc_ids,
- .supports_autosuspend = 1,
- },
- };
- static struct usb_device_id uvc_ids[] = {
- /* Microsoft Lifecam NX-6000 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x045e,
- .idProduct = 0x00f8,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Microsoft Lifecam VX-7000 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x045e,
- .idProduct = 0x0723,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Logitech Quickcam Fusion */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c1,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam Orbit MP */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c2,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam Pro for Notebook */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c3,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam Pro 5000 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c5,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam OEM Dell Notebook */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c6,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam OEM Cisco VT Camera II */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c7,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Apple Built-In iSight */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x05ac,
- .idProduct = 0x8501,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_BUILTIN_ISIGHT },
- /* Genesys Logic USB 2.0 PC Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x05e3,
- .idProduct = 0x0505,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* MT6227 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0e8d,
- .idProduct = 0x0004,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Syntek (HP Spartan) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x5212,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Samsung Q310) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x5931,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Asus F9SG */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a31,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Asus U3S) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a33,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Lenovo Thinkpad SL500 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x17ef,
- .idProduct = 0x480b,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Ecamm Pico iMage */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x18cd,
- .idProduct = 0xcafe,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
- /* Bodelin ProScopeHR */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_DEV_HI
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x19ab,
- .idProduct = 0x1000,
- .bcdDevice_hi = 0x0126,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STATUS_INTERVAL },
- /* SiGma Micro USB Web Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x1c4f,
- .idProduct = 0x3000,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_IGNORE_SELECTOR_UNIT
- | UVC_QUIRK_PRUNE_CONTROLS },
- /* Generic USB Video Class */
- { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
- {}
- };
(4).若是匹配成功,會執行設備驅動的probe函數。
咱們關心的設備節點的建立也是在設備驅動的探測函數中被建立(由於這時的設備註冊會附帶主次設備號,內核經過netlink上報uevent事件後、用戶空間的udevd服務會執行mknod建立設備節點)詳見Linux驅動中uevent、netlink及kobject初探——kobject部分 和 Linux驅動中uevent、netlink及kobject初探——ueventd部分。
3、usb相關結構說明
1.設備描述符
- struct usb_device_descriptor {
- __u8 bLength; --描述符長度
- __u8 bDescriptorType; --描述符類型:設備描述符0x01
- __le16 bcdUSB; --usb規範版本號
- __u8 bDeviceClass; --類代碼
- __u8 bDeviceSubClass; --子類代碼
- __u8 bDeviceProtocol; --協議代碼
- __u8 bMaxPacketSize0; --端點0支持最大數
- __le16 idVendor; --供應商ID
- __le16 idProduct; --產品ID
- __le16 bcdDevice; --設備版本號
- __u8 iManufacturer; --供應商字符串描述符的索引值
- __u8 iProduct; --產品字符串描述符的索引值
- __u8 iSerialNumber; --設備序列號
- __u8 bNumConfigurations; --所支持的配置數
- } __attribute__ ((packed)); --結構體字符類型對齊
2.配置描述符
- struct usb_config_descriptor {
- __u8 bLength; --描述符長度
- __u8 bDescriptorType; --描述符類型
- __le16 wTotalLength; --配置信息的總長度
- __u8 bNumInterfaces; --所支持的接口數
- __u8 bConfigurationValue; --配置值
- __u8 iConfiguration; --字符串描述符的索引值
- __u8 bmAttributes; --配置特徵
- __u8 bMaxPower; --所需最大的總線電流
- } __attribute__ ((packed));
3.接口描述符
- struct usb_interface_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bInterfaceNumber; --接口編號
- __u8 bAlternateSetting; --備用接口標號
- __u8 bNumEndpoints; --接口數目
- __u8 bInterfaceClass; --接口類型
- __u8 bInterfaceSubClass; --接口子類型
- __u8 bInterfaceProtocol; --接口所用協議
- __u8 iInterface; --接口索引字符串數值
- } __attribute__ ((packed));
4.端點描述符
- struct usb_endpoint_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bEndpointAddress; --端點號包括傳輸方向
- __u8 bmAttributes; --端點屬性
- __le16 wMaxPacketSize; --最大數據包長度
- __u8 bInterval; --訪問間隔
- __u8 bRefresh;
- __u8 bSynchAddress;
- } __attribute__ ((packed));
usb總線驅動中對於設備和設備驅動的匹配函數,其實就是上述1和3的匹配過程
見:kernel/drivers/usb/core/driver.c中usb_device_match函數,這部分能夠進一步分析;在此、我再也不分析。
大體會匹配設備所屬類(Input設備?Camera設備?Audio設備?或顯示設備等)和VID、PID。
5、urb數據傳輸分析
未完待續