usb驅動開發10之usb_device_match


在第五節我們說過會專門分析函數usb_device_match,以體現模型的重要性。同時,我們還是要守信用的。

再貼一遍代碼,看代碼就要不厭其煩。

 

 
        

前面說過,總線上掛着兩條鏈表,一條是設備鏈表,一條是驅動鏈表,經過漫長的歲月里的煎熬,終於通過usb_device_match這位大媒人的牽引下一個個的匹配成功了,當然也會有失敗哦,緣分天注定嘛。

USB的世界里,設備和驅動對於我們來說是不可言傳的玄機,對於它們來說只是usb_device_match函數的兩端。usb_device_match函數為它們指明哪個才是它們命中注定的緣。第一次遇到這個函數的時候,就說了這里有兩條路,一條給USB設備走,一條給USB接口走。

is_usb_device函數相當於是一個把門的,在進入關卡前需要安檢一樣。

static inline int is_usb_device(const struct device *dev)

{

return dev->type == &usb_device_type;

}

is_usb_device函數里的usb_device_type定義如下:

struct device_type usb_device_type = {

.name = "usb_device",

.release = usb_release_dev,

};

假設現在過來一個設備,經過判斷,它要走的是設備這條路,可問題是,這個設備的type字段啥時候被初始化成usb_device_type了,暫且不表,帶着疑問上路吧?

is_usb_device_driver函數臉上寫着我是用來判斷是不是usb device driver的,那咱們就要討論什么是usb device driver?前面一直都說一個usb接口對應一個usb驅動。對嗎?你是不是曾經懷疑過?我可以負責任的告訴你,你記得沒錯,一個接口就是要對應一個usb驅動,可是我們不能只鑽到接口的那個口里邊兒,我們應該眼光放的更加開闊些,要知道接口在usb的世界里並不是老大,它上邊兒還有配置,還有設備,都比它大。每個接口對應了一個獨立的功能,是需要專門的驅動來和它交流,但是接口畢竟整體是作為一個usb設備而存在的,設備還可以有不同的配置,我們還可以為設備指定特定的配置,那誰來做這個事情?接口驅動么?它還不夠級別,它的級別只夠和接口會談會談。這個和整個usb設備進行對等交流的光榮任務就交給了struct usb_device _driver,即usb設備驅動,它和usb的接口驅動struct usb_driver都定義在include/linux/usb.h文件里。現在明白/* interface drivers never match devices */注釋的含義了嗎????含蓄的我都不想再解釋了。

 

這么長,為什么要貼出來,重要啊!還有什么比這注釋看的更讓人有勁有味的?

每個寫usb驅動的人心中都有一個usb_driver。一般來說,我們平時所謂的編寫usb驅動指的也就是寫usb接口的驅動,需要以一個struct usb_driver結構的對象為中心,以設備的接口提供的功能為基礎,開展usb驅動的建設。

name,驅動程序的名字。

probe,用來看看這個usb驅動是否願意接受某個(或多個)接口的函數。每個驅動自誕生起,它的另一半就已經確定了,這個函數就是來判斷哪個才是她苦苦等待的那個他。當然,這個他應該是他們,因為一個驅動往往可以支持多個接口。

disconnect,當接口失去聯系,或使用rmmod卸載驅動將它和接口強行分開時這個函數就會被調用。

ioctl,當你的驅動通過usbfs和用戶空間交流的需要的話,就使用它吧。

suspend,resume,分別在設備被掛起和喚醒時使用。

pre_reset,post_reset,分別在設備將要復位(reset)和已經復位后使用。

id_table,驅動支持的所有設備的花名冊,驅動就靠這張表兒來識別是不是支持哪個設備接口的。

dynids,支持動態id的。什么是動態id?本來前面剛說每個驅動誕生時她的另一半在id_table里就已經確定了,加入了動態id的機制。即使驅動已經加載了,也可以添加新的id給她,只要新id代表的設備存在。怎么添加新的id?到驅動所在的地方瞅瞅,也就是/sys/bus/usb/drivers目錄下邊兒,那里列出的每個目錄就代表了一個usb驅動,隨便選一個進去,能夠看到一個new_id文件吧,使用echo將廠商和產品id寫進去就可以了。看看Greg舉的一個例子

echo 0557 2008 > /sys/bus/usb/drivers/foo_driver/new_id

就可以將16進制值0557和2008寫到foo_driver驅動的設備id表里取。

drvwrap,這個字段有點意思,struct usbdrv_wrap結構的,也在include/linux/usb.h里定義。

struct usbdrv_wrap {

struct device_driver driver;

int for_devices;

};

這個結構里面只有一個struct device_driver結構的對象和一個for_devices的整型字段。回想一下linux的設備模型,我們的心頭就會產生這樣的疑問,這里的struct device_driver對象不是應該嵌入到struct usb_driver結構里么,為什么又要包裝一層?主要是驅動在usb的世界里不得已分成了設備驅動和接口驅動兩種,為了區分這兩種驅動,就中間加了這么一層,添了個for_devices標志來判斷是哪種(雖然用int整型)。大家發現沒,之前見識過的結構里,很多不是1就是0的標志使用的是位字段,特別是幾個這樣的標志放一塊兒的時候,而這里的for_devices雖然也只能有兩個值,但卻沒有使用位字段,為什么?簡單的說就是這里沒那個必要,那些使用位字段的是幾個在一塊兒,可以節省點兒存儲空間,而這里只有這么一個,就是使用位字段也節省不了,就不用多此一舉了,這個大家都知道哈。其實就這么說為了加個判斷標志就硬生生的塞這么一層,還是會有點模糊的,不過,其它字段不敢說,這個drvwrap咱們以后肯定還會遇到它,這里先有個概念,混個面熟,等到再次相遇的那一刻,你可能就會明白它的用心。

no_dynamic_id,可以用來禁止動態id的。

supports_autosuspend,對autosuspend的支持,如果設置為0的話,就不再允許綁定到這個驅動的接口autosuspend。

struct usb_driver結構就暫時了解到這里,咱們再來看看所謂的usb設備驅動與接口驅動到底都有多大的不同。

 

 
        

再一次連注釋附上,表示這個結構體很重要。

這個usb設備驅動比前面的接口驅動要少了很多東西外,剩下的將參數里的struct usb_interface換成struct usb_device后就幾乎一摸一樣了。友情提醒一下,這里說的是幾乎,而不是完全,這是因為probe,它的參數里與接口驅動里的probe相比少了那個設備的花名冊,也就是說它不用再去根據花名冊來判斷是不是願意接受一個usb設備。即它來者不拒,接受所有的usb設備。在內核里找來找去,也就只能找得着它在drivers/usb/core/generic.c文件里定義了usb_generic_driver這么一個對象

struct usb_device_driver usb_generic_driver = {

.name = "usb",

.probe = generic_probe,

.disconnect = generic_disconnect,

#ifdef CONFIG_PM

.suspend = generic_suspend,

.resume = generic_resume,

#endif

.supports_autosuspend = 1,

};

即使這么一個獨苗兒,也早在usb_init函數就已經注冊給usb子系統了。

不管怎么說,總算是把usb接口的驅動和設備的驅動給過了一下,還是回到這節開頭兒的usb_device_match函數,目前為止,設備這條路已經比較清晰了。就是如果設備過來了,走到了設備這條路,然后要判斷下驅動是不是設備驅動,是不是針對整個設備的,如果不是的話,對不起,雖然這條路走對了,可是沿這條路,設備找不到對應的驅動,匹配不成功,就直接返回了,那如果驅動也確實是設備驅動那?代碼里是直接返回1,表示匹配成功了。

現在是不是可以理解usb_device_match這里多了一條給設備走的路。暫時告別usb_device_match函數,我們去分析usb設備在usb世界里的整個人生旅程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM