本文將詳細講述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 裝置上電穩定,然後向...