usb裝置probe過程

2021-07-25 02:58:49 字數 3311 閱讀 7645

本文將詳細講述2.6.22 下的乙個usb 裝置插上linux 系統的pc 後是如何一步一步調到我們的usb 裝置驅動的probe 函式的, 我們知道我們的usb 驅動的probe 函式中的乙個引數是inte***ce 結構, 因此一般來說,  乙個usb 裝置中的任何乙個介面都應該有對應的乙個驅動程式, 當然也有例外( 如cdc-acm).

我們知道usb 裝置都是通過插入上層hub 的乙個port 來連入系統並進而被系統發現的, 當usb裝置插入乙個hub 時, 該hub 的那個port 的狀態就會改變, 從而系統就會知道這個改變, 此時會呼叫hub_port_connect_change() 

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

該函式建立乙個usb_device 的物件udev, 並初始化它, 接著呼叫usb_new_device() 來獲取這個usb 裝置的各種描述符並為每個inte***ce 找到對用的driver.

int usb_new_device(struct usb_device*udev)

該函式首先呼叫usb_get_configuration()來獲取裝置的各種描述符(裝置描述符, 配置描述符等), 接著呼叫device_add() 來把這個usb 裝置新增到usb 系統中去,也就是在這個過程中系統回去為這個裝置找到相應的驅動. 在2.6的早期的一些版本中在分析配置描述符後得到inte***ce 的同時把inte***ce 作為裝置來呼叫device_add() 的

int device_add(struct device*dev)

這個函式是個通用的裝置管理函式, 它會為每個裝置呼叫bus_add_device 來把這個裝置新增到相應bus 的裝置列表中去. 接著呼叫bus_attach_device() 來匹配對應的驅動程式, 對於usb 裝置來說第一次呼叫bus_attach_device() 時的引數dev 代表的是整個usb 裝置(以後usb 裝置中的inte***ce 也會作為裝置呼叫這個函式).

int bus_attach_device(struct device*dev)

這個函式就是用來為裝置找到相應的裝置驅動程式的( 通過呼叫device_attach() 實現).

int device_attach(struct device*dev)

該函式呼叫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*))

該函式遍歷bus 上的所有驅動程式, 並為每個驅動呼叫fn() 來檢視是否匹配. 這裡的fn就是__device_attach.

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

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

對於usb 驅動來說, 我們通過usb_registe()r 來註冊我們的驅動程式, 這個函式會為我們的驅動程式物件(usb_driver) 中的bus 指定為usb_bus_type:

structbus_type usb_bus_type =

因此對於usb 驅動會首先呼叫usb_device_match().

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

else 

}這個函式只是做一些粗略的匹配, 如果匹配成功則返回1, 然後由really_probe 來做進一步的匹配, 如果匹配失敗則返回0, 並且really_probe 也不會在執行. 這個函式的呼叫保證了dev,drv 要麼都是裝置級別的(即dev 代表usb 裝置,drv 代表usb 裝置驅動), 要麼都是介面級別的( 即dev代表usb 裝置的乙個inte***ce,drv 代表usb 介面驅動).

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

對於usb 來說這個函式的呼叫有2 種分支, 1:dev,drv 代表的是裝置級別的, 2dev,drv 代表的是介面級別的. 其他情況組合在usb_device_match 中被過濾掉了,

分支1: dev,drv 代表的是裝置級別:

此時的drv 肯定是usb_generic_driver. 因為在當前的usb 系統中只有這個driver 是代表整個裝置的驅動, 它是在usb_init 中被註冊的, 而我們通常寫的usb 驅動都是代表乙個inte***ce 的.

struct usb_device_driver usb_generic_driver =

因此, 此時的drv->probe 將呼叫generic_probe().

static int generic_probe(struct usb_device*udev)…}

該函式為這個usb 裝置選擇乙個合適的配置, 並註冊這個配置下面的inte***ce.

int usb_set_configuration(struct usb_device *dev,int configuration)…}

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

分支2: dev,drv 代表的是inte***ce 級別:

此時的dev 代表著乙個inte***ce, 而drv 就代表了我們自己的usb 驅動.但是我們應當看到drv 是device_driver 型別, 而我們寫的usb 驅動的型別一般是usb_driver, 因此這裡的probe 和我們自己寫的probe 顯然不是同乙個. 實際上這裡的drv 是我們的驅動物件裡內嵌的乙個子物件( 因為linux下所以的驅動都必須用device_driver來代表,).那這個子物件的probe函式是在**賦值的呢?這就要看usb_register函式了,

跟蹤這個函式我們可以看到這裡的probe 函式實際上是usb_probe_inte***ce( 所有的usb inte***ce 驅動都是一樣的).

static intusb_probe_inte***ce(struct device *dev)

driver->probe(intf,id); 這就呼叫到我們自己寫的**裡面了,

整個流程大概就是這樣:

原文:

DTS裝置進入probe前的過程

使用device tree後,驅動需要與.dts中描述的裝置結點進行匹配,從而引發驅動的probe 函式執行。對於i2c和spi從裝置而言,同樣也可以透過of match table新增匹配的.dts中的相關結點的compatible屬性 dts檔案是一種ascii 文字格式的device tree...

USB裝置驅動載入過程

本文摘自 使用者插入usb裝置 usb匯流排 或者是pci匯流排,這個不太清楚,反正就是匯流排來著 識別到插入了usb裝置。匯流排和usb裝置進行通訊,獲取usb的硬體id 產品id,以及bcdversion。根據這些資訊組成裝置硬體id號 vid x pid x rev x。匯流排根據usb裝置的...

USB裝置列舉過程

當裝置連線到主機時,按照以下順序進行列舉 1.連線了裝置的hub 在host 查詢其狀態改變端點時返回對應的bitmap,告知host 某個port 狀態發生了改變。2.主機向hub 查詢該port 的狀態,得知有裝置連線,並知道了該裝置的基本特性。3.主機等待 至少100ms 裝置上電穩定,然後向...