從USB設備插上到驅動probe調用流程分析

本文將詳細講述 2.6.22 下 的一個 USB 設備插上 linux 系 統 PC 後是如何一步一步調到我們的 usb 設 備驅動的 probe 函數的 , 我們知道我們的 USB 驅 動的 probe 函數中的一個參數是 interface 結 構 , 因此一般來說 ,  一 個 USB 設備中的任何一個接口都應該有對應的一個驅動程序 , 當 然也有例外 ( cdc-acm).

我們知道 USB 設備都是通過插入上層 HUB 的 一個 Port 來連入系統並進而被系統發現的 , USB 設 備插入一個 HUB , HUB 的 那個 port 的狀態就會改變 , 從而系統就會 知道這個改變 , 此時會調用 hub_port_connect_change()  /*driver/usb/core/hub.c*/

static void hub_connect_change(struct usb_hub *hub, int portl, u16 portstatus, u16 portchange)

{

….

usb_new_device(udev);

}

該函數創建一個 usb_device 的對象 udev, 並 初始化它 , 接着調用 usb_new_device() 來 獲取這個 usb 設備的各種描述符併爲每個 interface 找 到對用的 driver.

int usb_new_device(struct usb_device *udev)

{

  ….

err = usb_get_configuration(udev);

  ….

device_add(&udev->dev);

}

該函數首先調用 usb_get_configuration() 來 獲取設備的各種描述符 ( 設備描述符 , 配置描 述符等 ), 接着調用 device_add() 來 把這個 USB 設備添加到 USB 系統中去 , 也 就是在這個過程中系統回去爲這個設備找到相應的驅動 . 2.6 的 早期的一些版本中在分析配置描述符後得到 interface 的同時把 interface 作 爲設備來調用 device_add()

int device_add(struct device *dev)

{

….

if((error = bus_add_device(dev)))

bus_attach_device(dev);

}

這個函數是個通用的設備管 理 函數 , 它會爲每個設備調用 bus_add_device 來 把這個設備添加到相應 bus 的設備列表中去 . 接 着調用 bus_attach_device() 來匹配對應的驅動程序 , 對 於 USB 設備來說第一次調用 bus_attach_device() 時 的參數 dev 代表的是整個 usb 設備 ( 以 後 usb 設備中的 interface 也會作 爲設備調用這個函數 ).

int bus_attach_device(struct device *dev)

{

ret = device_attach(dev);

}

這個函數就是用來爲設備找到相應的設備驅動程序的 ( 通過調 用 device_attach() 實現 ).

int device_attach(struct device *dev)

{

ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

}

該函數調用 bus_for_each_drv() 來從總線 上已註冊的所有驅動中找出匹配的驅動程序 .

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);  // 返回 0 將 繼續搜索 , 返回錯誤值將停止搜索 .

}

該函數遍歷 bus 上 的所有驅動程序 , 併爲每個驅動調用 fn() 來 查看是否匹配 . 這裏的 fn 就是 __device_attach.

static int __device_attach(struct device_driver *drv, void *data)

{

struct device *dev = data;

return driver_probe_device(drv, dev);

}

int driver_probe_device(struct device *drv, struct device *dev)

{

  

   if(drv->bus->match && !drv->bus_match(dev, drv))

  

 

   ret = really_probe(dev, drv);

}

    對 於 usb 驅動來說 , 我們通過 usb_registe()r 來 註冊我們的驅動程序 , 這個函數會爲我們的驅動程序對象 (usb_driver) 中 的 bus 指定爲 usb_bus_type:

   Struct bus_type usb_bus_type = {

  

   .match = usb_device_match,

   ….

}

因此對於 usb 驅動會首先調用 usb_device_match().

static int usb_device_match(struct device *dev, struct device_driver *drv)

{

     if(is_usb_device(dev)) {  /*dev 代 表整個 usb 設備 */

          ….

}

else   /*dev 代表一個 usb 設 備 interface*/

{

  

   usb_match_id();

  

   usb_match_dynamic_id();

  

}

}

這個函數只是做一些粗略的匹配 , 如果匹配成功則返回 1, 然 後由 really_probe 來做進一步的匹配 , 如 果匹配失敗則返回 0, 並且 really_probe 也 不會在執行 . 這個函數的調用保證了 dev, drv 要 麼都是設備級別的 ( dev 代表 usb 設 備 ,drv 代表 usb 設備驅動 ), 要 麼都是接口級別的 ( dev 代表 usb 設 備的一個 interface,drv 代表 usb 接 口驅動 ).

static int really_probe(struct device *dev, struct device_driver *drv)

{

  

   dev->driver = drv;  // 先 賦值 , 以後的 probe 過程中會用到

   else if(drv->probe)

           ret = drv->probe(dev);

probe_failed:

   dev->drvier = NULL;  //probe 失 敗 , 重設它

  

}

對於 usb 來說這個函數的調用有 2 種 分支 , 1: dev,drv 代表的是設備級別的 , 2 dev,drv 代表的是接口級別的 . 其他情況組合在 usb_device_match 中 被過濾掉了 ,

分支 1: dev,drv 代表的是設備級別 :

此時的 drv 肯定是 usb_generic_driver. 因 爲在當前的 usb 系統中只有這個 driver 是 代表整個設備的驅動 , 它是在 usb_init 中 被註冊的 , 而我們通常寫的 usb 驅動都是代 表一個 interface .

struct usb_device_driver usb_generic_driver = {

  

   .probe = generic_probe,

  

}

因此 , 此時的 drv->probe 將 調用 generic_probe().

static int generic_probe(struct usb_device *udev)

{

  

   c = choose_configuration(dev);

   if(c >= 0) {

   err = usb_set_configuration(udev, c);  // 設 置 配置 , 並註冊 interface.

  

}

}

該函數爲這個 usb 設備選擇一個合適的配置 , 並 註冊這個配置下面的 interface.

int usb_set_configuration(struct usb_device *dev, int configuration)

{

  

   for(I = 0; I < nintf; i++) {

   struct usb_interface *intf = cp->interface[i];

  

   device_add(&intf->dev);

  

}

  

}

該函數比較重要 , 但我們只關心 probe 過 程因此省掉了很多東西 . 它爲當前配置下的每個 interface 調 用 device_add() 函數 , 根據前面 的分析可知 , 這個過程將會走到接下來我們要分析的分支 2.

分支 2: dev,drv 代表的是 interface 級 別 :

此時的 dev 代表着一個 interface, drv 就 代表了我們自己的 usb 驅動 . 但是我們應當 看到 drv device_driver 類 型 , 而我們寫的 usb 驅動的類型一般是 usb_driver, 因 此這裏的 probe 和我們自己寫的 probe 顯 然不是同一個 . 實際上這裏的 drv 是我們的 驅動對象裏內嵌的一個子對象 ( 因爲 linux 下 所以的驅動都必須用 device_driver 來代表 ,). 那 這個子對象的 probe 函數是在哪裏賦值的呢 ? 這 就要看 usb_register 函數了 ,

跟蹤這個函數 我們可以看到這裏的 probe 函數實際上是 usb_probe_interface( 所 有的 usb interface 驅動都是一樣的 ).

  static int usb_probe_interface(struct device *dev)

{

  struct driver = to_usb_driver(dev->driver);  //dev->driver  really_probe 中 設置 .

 

  error = driver->probe(intf, id);   // 這 個就是我們自己寫的 probe 函數了 .

 

}

  driver->probe(intf, id); 這就調用到我們自己寫的代碼裏面了 ,

 

整個流程大概 就是這樣 :

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章