本文將詳細講述 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); 這就調用到我們自己寫的代碼裏面了 ,
整個流程大概 就是這樣 :