12.2 linux USB框架分析(詳細註冊match匹配過程)

 首先咱們先來簡單說一說USB的框架,以後在來具體分析源碼,以便加深理解!其實USB的框架比較像「平臺總線、設備、驅動」的框架,也分爲總線、設備、驅動三大塊。其中總線驅動是已經由內核完成的,一旦接入usb設備,總線驅動程序就會找到能處理該設備的驅動進行處理!咱們進入文件系統的/sys/bus目錄下能夠看到不少總線目錄,usb目錄就在其中,咱們進入usb目錄,會看到devices和drivers!

linux usb

 
下面咱們來看源碼:
 
#define subsys_initcall(fn) module_init(fn)
subsys_initcall(usb_init);
      bus_register(&usb_bus_type);//註釋1
           __bus_register(subsys, &__key);
                 retval = kset_register(&priv->subsys);
                      kobject_add_internal(&k->kobj);
                            kobj_kset_join(kobj);
                                   //將usb總線加入到總線鏈表裏面,sys/bus目錄下就是全部的總線目錄
                                  list_add_tail(&kobj->entry, &kobj->kset->list);
                            create_dir(kobj);
                                 sysfs_create_dir(kobj); //具體的目錄在這裏建立
                 //在總線下建立了devices目錄,據我分析這裏並無添加設備鏈表,由於尚未去發現設備
                priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
                 //在總線下建立了drivers目錄,據我分析這裏並無添加驅動鏈表,由於尚未去註冊驅動
               klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);  //初始化設備鏈表
               klist_init(&priv->klist_drivers, NULL, NULL);  //初始化驅動鏈表
     retval = usb_major_init();//這裏面註冊了一個字符設備
           //#define USB_MAJOR  180,cat /proc/devices能夠觀察到
          register_chrdev(USB_MAJOR, "usb", &usb_fops);
      retval = usb_hub_init();
           usb_register(&hub_driver) //將hub.c裏面的 hub_driver加入到usb總線下的驅動鏈表裏
                usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
                      driver_register(&new_driver->drvwrap.driver);
                           bus_add_driver(drv);
                                 driver_attach(drv);
                                        //匹配devices與drivers,調用 __driver_attach
                                       bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
                                               __driver_attach
                                                      driver_match_device(drv, dev)
                                                               //調用總線上的match,檢測驅動與設備是否匹配
                                                             drv->bus->match ? drv->bus->match(dev, drv) : 1;
                                                       driver_probe_device(drv, dev);
                                                              really_probe(dev, drv);
                                                                      drv->probe(dev);  //調用hub.c裏面的驅動的probe函數,這裏的drv是device_driver結構體,其在usb_register_driver過程當中經過new_driver->drvwrap.driver.probe = usb_probe_interface;來設置,這個probe會調用driver中的probe
                                                                            hub_probe
                                                                                  hub_configure(hub, endpoint)
                                                                                          //這裏註冊了中斷,一旦接入新的usb設備就會調用 hub_irq
                                                                                         usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp,
                                                                                                   hub_irq,hub, endpoint->bInterval);
           khubd_task = kthread_run(hub_thread, NULL, "khubd");  //啓動 hub_thread這個線程
                 hub_thread
                        //#define wait_event_freezable(wq, condition)   wait_event_interruptible(wq, condition)
                       //將當前進程加入到等待隊列中,進程在這裏停下來了,咱們須要看看那裏喚醒進程
                       wait_event_freezable(khubd_wait,!list_empty(&hub_event_list) ||kthread_should_sto());
                        //一旦接入新的usb設備,就會調用 hub_irq
                             hub_irq
                                   kick_khubd(hub);
                                          wake_up(&khubd_wait); //喚醒等待隊列裏面的進程,執行hub_events();
                             hub_events();
                                 hub_port_connect_change(hub, i,portstatus, portchange);
                                       hub_port_init(hub, udev, port1, i);
                                             udev = usb_alloc_dev(hdev, hdev->bus, port1);
                                             choose_devnum(udev); //選擇usb設備地址
                                                   hub_set_address(udev, devnum); //將選擇的地址告訴usb設備
                                                   usb_get_device_descriptor(udev, 8); //得到設備描述符
                                                   usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); //再次得到設備描述符
                                        usb_new_device(udev);
                                                usb_enumerate_device(udev);
                                                       usb_get_configuration(udev); //得到配置信息
                                                         //得到產品信息
                                                       udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
                                                         //得到製造商信息
                                                       udev->manufacturer = usb_cache_string(udev,udev->descriptor.iManufacturer);
                                                         //得到序列號信息
                                                       udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
                                                       device_add(&udev->dev);
                                                            bus_add_device(dev); //將usb設備加入到usb總線旗下的設備列表裏面
                                                            bus_probe_device(dev);
                                                                    device_attach(dev);
                                                                            //對全部的驅動,調用 __device_attach判斷設備與驅動是否匹配
                                                                          bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
                                                                                 driver_match_device(drv, dev)
                                                                                           //調用總線下的match函數來判斷設備與驅動時候是否匹配
                                                                                         drv->bus->match ? drv->bus->match(dev, drv) : 1;
                                                                                  driver_probe_device(drv, dev);
                                                                                         really_probe(dev, drv);
                            //說明: //調用hub.c裏面的驅動的probe函數,這裏的drv是device_driver結構體,其在usb_register_driver過程當中經過new_driver->drvwrap.driver.probe = usb_probe_interface;來設置,這個probe會調用driver中的probe
                                                                                                #drv->probe(dev); //一旦匹配的話就會調用驅動的probe函數(有問題)
      //將generic .c裏面的 usb_generic_driver 加入到usb總線下的驅動鏈表裏
       retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
 
下面咱們來看看usb總線的match函數:
usb_device_match
        usb_match_id(intf, usb_drv->id_table)
               usb_match_one_id(interface, id)
                     usb_match_device(dev, id)
根據驅動id和設備信息是否匹配來判斷是否匹配
 
關於判斷匹配,上面的分析中涉及到了兩次,第一次匹配時hub.c裏面定義的驅動與匹配,第二次是咱們本身定義的驅動匹配具體的設備!
第一次hub中也是調用usb_register來註冊,發現hub設備匹配id_table時調用hub的probe函數,第二次是設備和咱們的驅動
 
由此咱們的usb框架就很清楚了,雖然是分爲三大塊,可是涉及具體的驅動,咱們能夠分爲兩層:usb總線驅動層和usb設備驅動層。系統初始化過程當中會使usb進程進入休眠,一旦接入usb設備,就會喚醒進程,獲取設備的相關信息,而後遍歷驅動鏈表,調用總線的match函數來尋找與設備相匹配的驅動,一旦找到,就會調用驅動的porbe函數!框架很簡單,咱們寫usb驅動,要作的就是寫usb設備驅動,而主要的工做就在probe函數裏面完成!
相關文章
相關標籤/搜索