Linux那些事儿 之 戏说USB(大结局)还是那个match
生活随笔
收集整理的這篇文章主要介紹了
Linux那些事儿 之 戏说USB(大结局)还是那个match
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
從上次在幾米的向左走向右走遇到usb總線的那個match函數(shù)usb_device_match()開始到現(xiàn)在,遇到了設(shè)備,遇到了設(shè)備驅(qū)動,遇到了接口,也遇到了接口驅(qū)動,期間還多次遇到usb_device_match()。
每個設(shè)備也都有一條共同之路,與hub初戀,失身于usb_generic_driver,嫁給了接口驅(qū)動,被usb總線保養(yǎng)。設(shè)備沒有真正自由過,剛開始時在Default狀態(tài)動彈不得,稍后步入Address,無論外頭風(fēng)光多好,都得與usb_generic_driver長廂廝守,沒得選擇,終于達(dá)到了Configured,又必須為自己的接口殫精竭慮,以便usb_device_match()能夠?yàn)樗鼈冋乙粋€好人家。
不管怎么說,在這里我們會再次與usb_device_match()相遇,看看它怎么在接口和驅(qū)動之間搭起那座橋。
當(dāng)時講到struct usb_driver結(jié)構(gòu)的時候并沒有詳細(xì)講它里面表示動態(tài)id的那個結(jié)構(gòu)體struct usb_dynids,但是做人要厚道,不能太CCTV,所以現(xiàn)在補(bǔ)充一下,這個結(jié)構(gòu)的定義在include/linux/usb.h里
13行,你可能會問為什么這里不詳細(xì)介紹一下struct usb_device_id結(jié)構(gòu),主要是《我是U盤里》已經(jīng)說得非常之詳細(xì)和有趣了,俺這里實(shí)在沒必要耗費(fèi)時間和口舌去說它,另一方面,它里面的那些元素都相當(dāng)?shù)谋┞逗椭卑?#xff0c;我相信依你的智商一眼就能明白個八九不離十。
那么這個for循環(huán)就是輪詢設(shè)備花名冊里的每個設(shè)備,如果符合了條件id->idVendor || id->bDeviceClass || id->bInterfaceClass || id->driver_info,就調(diào)用函數(shù)usb_match_one_id做深層次的匹配。本來,在動態(tài)id出現(xiàn)之前這個地方是沒有usb_match_one_id這么一個函數(shù)的,所有的匹配都在這個for循環(huán)里直接做了,但是動態(tài)id出現(xiàn)之后,同時出現(xiàn)了前面提到的usb_match_dynamic_id函數(shù),要在動態(tài)id鏈表里做同樣的匹配,這就要避免代碼重復(fù),于是就將那些重復(fù)的代碼提出來,組成了usb_match_one_id函數(shù)。
for循環(huán)的條件里可能出現(xiàn)的一種情況是,id的其它字段都為空,只有driver_info字段有實(shí)實(shí)在在的內(nèi)容,這種情況下匹配是肯定成功的,不信的話等會兒你可以看usb_match_one_id(),這種驅(qū)動對usb接口來說是比較隨便的那種,不管啥接口都能和她對得上眼,為什么會出現(xiàn)這種情況?咱們已經(jīng)知道,匹配成功后,接著就會調(diào)用驅(qū)動自己的probe函數(shù),驅(qū)動在它里面還會對接口做進(jìn)一步的檢查,如果真出現(xiàn)了這里所說的情況,意思也就是驅(qū)動將所有的檢查接口,和接口培養(yǎng)感情的步驟都攬?jiān)谧约旱膒robe函數(shù)里了,它會在那個時候?qū)river_info的內(nèi)容取出來,然后想怎么處理就怎么處理,本來么,id里邊兒的driver_info就是給驅(qū)動保存數(shù)據(jù)用的。
還是看看usb_match_one_id()究竟是怎么匹配的吧,定義也在driver.c里
11行,獲得接口采用的設(shè)置,設(shè)置里可是有接口描述符的,要匹配接口和驅(qū)動,接口描述符里的信息是必不可少的。
12行,從接口的struct usb_interface結(jié)構(gòu)體獲得usb設(shè)備的struct usb_device結(jié)構(gòu)體,interface_to_usbdev的定義在include/linux/usb.h里
14行,這里又冒出來個usb_match_device(),接口和驅(qū)動之間的感情還真不是那么好培養(yǎng)的,一層一層的。不過既然存在就是有來頭的,它也不會毫無根據(jù)的出現(xiàn),這里雖說是在接口和接口驅(qū)動之間匹配,但是接口的parent也是必須要符合條件的,這即合情也合理啊,你好不容易鼓足了勇氣向一個走在大街上一見鐘情的mm表白,你覺得mm的第一反應(yīng)是什么?依照行規(guī),很可能就是:你爸是干嗎的?是大款么?是當(dāng)官的么?你要說不,那就別等第二反應(yīng)了。所以說接口要想得到驅(qū)動的芳心,自己的parent符合驅(qū)動的條件也是很重要的,usb_match_device()就是專門來匹配接口parent的。同樣在driver.c里定義
驅(qū)動的花名冊里每個設(shè)備都對應(yīng)了一個struct usb_device_id結(jié)構(gòu)體,這個結(jié)構(gòu)體里有很多字段,都是驅(qū)動設(shè)定好的條條框框,接口必須完全滿足里面的條件才能夠被驅(qū)動所接受,所以說匹配的過程就是檢查接口是否滿足這些條件的過程。
當(dāng)然你可以每次都按照id的內(nèi)容一個一個的比較下去,但是經(jīng)常來說,一個驅(qū)動往往只是想設(shè)定其中的某幾項(xiàng),并不要求struct usb_device_id結(jié)構(gòu)里的所有那些條件都要滿足。match_flags就是為了方便各種各樣的需求而生的,驅(qū)動可以將自己的條件組合起來,match_flags的每一位對應(yīng)一個條件,驅(qū)動care哪個條件了,就將那一位置1,否則就置0。當(dāng)然,內(nèi)核里對每個驅(qū)動可能會care的條件都定義成了宏,供驅(qū)動去組合,它們都在include/linux/mod_devicetable.h里定義
這個core的故事,從match開始,到match結(jié)束,它雖說不會遍及core的邊邊角角所有部分,但應(yīng)該也有那么十之七八。在match的兩端是設(shè)備和設(shè)備的驅(qū)動,是接口和接口的驅(qū)動,這個故事里遇到的人,遇到的事,早就安排在那里了,由不得我們?nèi)ミx擇。在人生的路口上,早已經(jīng)安排了那些人,那些事,決定你向左走還是向右走。既然如此,那就隨便走好了,想那么多干什么呢?
每個設(shè)備也都有一條共同之路,與hub初戀,失身于usb_generic_driver,嫁給了接口驅(qū)動,被usb總線保養(yǎng)。設(shè)備沒有真正自由過,剛開始時在Default狀態(tài)動彈不得,稍后步入Address,無論外頭風(fēng)光多好,都得與usb_generic_driver長廂廝守,沒得選擇,終于達(dá)到了Configured,又必須為自己的接口殫精竭慮,以便usb_device_match()能夠?yàn)樗鼈冋乙粋€好人家。
不管怎么說,在這里我們會再次與usb_device_match()相遇,看看它怎么在接口和驅(qū)動之間搭起那座橋。
static int usb_device_match(struct device *dev, struct device_driver *drv)
{/* devices and interfaces are handled separately */if (is_usb_device(dev)) {/* interface drivers never match devices */if (!is_usb_device_driver(drv))return 0;/* TODO: Add real matching code */return 1;} else if (is_usb_interface(dev)) {struct usb_interface *intf;struct usb_driver *usb_drv;const struct usb_device_id *id;/* device drivers never match interfaces */if (is_usb_device_driver(drv))return 0;intf = to_usb_interface(dev);usb_drv = to_usb_driver(drv);id = usb_match_id(intf, usb_drv->id_table);if (id)return 1;id = usb_match_dynamic_id(intf, usb_drv);if (id)return 1;}return 0;
}設(shè)備那條路已經(jīng)走過了,現(xiàn)在走走13行接口那條路。19行,接口驅(qū)動的for_devices在usb_register _driver()里被初始化為0,所以這個把門兒的會痛痛快快的放行,繼續(xù)往下走,22行,遇到一對兒似曾相識的宏to_usb_interface和to_usb_driver,之所以說似曾相識,是因?yàn)樵缦纫呀?jīng)遇到過一對兒to_usb_device和to_usb_device_driver。這兩對兒一對兒用于接口和接口驅(qū)動,一對兒用于設(shè)備和設(shè)備驅(qū)動,意思都很直白,還是看看include/linux/usb.h里的定義
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)再往下走,就是兩個函數(shù)usb_match_id和usb_match_dynamic_id,它們都是用來完成實(shí)際的匹配工作的,只不過前一個是從驅(qū)動的id_table里找,看接口是不是被驅(qū)動所支持,后一個是從驅(qū)動的動態(tài)id鏈表dynids里找。驅(qū)動的id表分id_table和dynids兩種。顯然25~31這幾行的意思就是將id_table放在一個比較高的優(yōu)先級的位置,從它里面找不到接口了才再從動態(tài)id鏈表里找。
當(dāng)時講到struct usb_driver結(jié)構(gòu)的時候并沒有詳細(xì)講它里面表示動態(tài)id的那個結(jié)構(gòu)體struct usb_dynids,但是做人要厚道,不能太CCTV,所以現(xiàn)在補(bǔ)充一下,這個結(jié)構(gòu)的定義在include/linux/usb.h里
struct usb_dynids {spinlock_t lock;struct list_head list;
};它只有兩個字段,一把鎖,一個鏈表,都是在usb_register _driver()里面初始化的,這個list是驅(qū)動動態(tài)id鏈表的頭兒,它里面的每個節(jié)點(diǎn)是用另外一個結(jié)構(gòu)struct usb_dynid來表示
struct usb_dynid {struct list_head node;struct usb_device_id id;
};這里面就出現(xiàn)了一個struct usb_device_id結(jié)構(gòu)體,也就是設(shè)備的id,每次添加一個動態(tài)id,就會向驅(qū)動的動態(tài)id鏈表里添加一個struct usb_dynid結(jié)構(gòu)體。你現(xiàn)在應(yīng)該可以想像到usb_match_id和usb_match_dynamic_id這兩個函數(shù)除了查找的地方不一樣,其它應(yīng)該是沒什么差別的。所以接下來咱們只深入探討一下usb_match_id函數(shù),至于usb_match_dynamic_id(),如果你實(shí)在無聊暫時找不到人生目標(biāo)也可以去看看。它們都在driver.c里定義
const struct usb_device_id *usb_match_id(struct usb_interface *interface,const struct usb_device_id *id)
{/* proc_connectinfo in devio.c may call us with id == NULL. */if (id == NULL)return NULL;/* It is important to check that id->driver_info is nonzero,since an entry that is all zeroes except for a nonzeroid->driver_info is the way to create an entry thatindicates that the driver want to examine everydevice and interface. */for (; id->idVendor || id->idProduct || id->bDeviceClass ||id->bInterfaceClass || id->driver_info; id++) {if (usb_match_one_id(interface, id))return id;}return NULL;
}5行,參數(shù)id指向的是驅(qū)動的那個設(shè)備花名冊,即id_table,如果它為空,那肯定就是不可能會匹配成功了。
13行,你可能會問為什么這里不詳細(xì)介紹一下struct usb_device_id結(jié)構(gòu),主要是《我是U盤里》已經(jīng)說得非常之詳細(xì)和有趣了,俺這里實(shí)在沒必要耗費(fèi)時間和口舌去說它,另一方面,它里面的那些元素都相當(dāng)?shù)谋┞逗椭卑?#xff0c;我相信依你的智商一眼就能明白個八九不離十。
那么這個for循環(huán)就是輪詢設(shè)備花名冊里的每個設(shè)備,如果符合了條件id->idVendor || id->bDeviceClass || id->bInterfaceClass || id->driver_info,就調(diào)用函數(shù)usb_match_one_id做深層次的匹配。本來,在動態(tài)id出現(xiàn)之前這個地方是沒有usb_match_one_id這么一個函數(shù)的,所有的匹配都在這個for循環(huán)里直接做了,但是動態(tài)id出現(xiàn)之后,同時出現(xiàn)了前面提到的usb_match_dynamic_id函數(shù),要在動態(tài)id鏈表里做同樣的匹配,這就要避免代碼重復(fù),于是就將那些重復(fù)的代碼提出來,組成了usb_match_one_id函數(shù)。
for循環(huán)的條件里可能出現(xiàn)的一種情況是,id的其它字段都為空,只有driver_info字段有實(shí)實(shí)在在的內(nèi)容,這種情況下匹配是肯定成功的,不信的話等會兒你可以看usb_match_one_id(),這種驅(qū)動對usb接口來說是比較隨便的那種,不管啥接口都能和她對得上眼,為什么會出現(xiàn)這種情況?咱們已經(jīng)知道,匹配成功后,接著就會調(diào)用驅(qū)動自己的probe函數(shù),驅(qū)動在它里面還會對接口做進(jìn)一步的檢查,如果真出現(xiàn)了這里所說的情況,意思也就是驅(qū)動將所有的檢查接口,和接口培養(yǎng)感情的步驟都攬?jiān)谧约旱膒robe函數(shù)里了,它會在那個時候?qū)river_info的內(nèi)容取出來,然后想怎么處理就怎么處理,本來么,id里邊兒的driver_info就是給驅(qū)動保存數(shù)據(jù)用的。
還是看看usb_match_one_id()究竟是怎么匹配的吧,定義也在driver.c里
int usb_match_one_id(struct usb_interface *interface,const struct usb_device_id *id)
{struct usb_host_interface *intf;struct usb_device *dev;/* proc_connectinfo in devio.c may call us with id == NULL. */if (id == NULL)return 0;intf = interface->cur_altsetting;dev = interface_to_usbdev(interface);if (!usb_match_device(dev, id))return 0;return usb_match_one_id_intf(dev, intf, id);
}8行,這個id指向的就是驅(qū)動id_table里的某一項(xiàng)了。
11行,獲得接口采用的設(shè)置,設(shè)置里可是有接口描述符的,要匹配接口和驅(qū)動,接口描述符里的信息是必不可少的。
12行,從接口的struct usb_interface結(jié)構(gòu)體獲得usb設(shè)備的struct usb_device結(jié)構(gòu)體,interface_to_usbdev的定義在include/linux/usb.h里
#define to_usb_device(d) container_of(d, struct usb_device, dev)static inline struct usb_device *interface_to_usbdev(struct usb_interface *intf)
{return to_usb_device(intf->dev.parent);
}usb設(shè)備和它里面的接口是怎么關(guān)聯(lián)起來的呢?就是上面的那個parent,接口的parent早在usb_generic_driver的generic_probe函數(shù)向設(shè)備模型提交設(shè)備里的每個接口的時候就被初始化好了,而且指定為接口所在的那個usb設(shè)備。這么一回顧,interface_to_usbdev的意思就很明顯了。
14行,這里又冒出來個usb_match_device(),接口和驅(qū)動之間的感情還真不是那么好培養(yǎng)的,一層一層的。不過既然存在就是有來頭的,它也不會毫無根據(jù)的出現(xiàn),這里雖說是在接口和接口驅(qū)動之間匹配,但是接口的parent也是必須要符合條件的,這即合情也合理啊,你好不容易鼓足了勇氣向一個走在大街上一見鐘情的mm表白,你覺得mm的第一反應(yīng)是什么?依照行規(guī),很可能就是:你爸是干嗎的?是大款么?是當(dāng)官的么?你要說不,那就別等第二反應(yīng)了。所以說接口要想得到驅(qū)動的芳心,自己的parent符合驅(qū)動的條件也是很重要的,usb_match_device()就是專門來匹配接口parent的。同樣在driver.c里定義
int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
{if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&id->idVendor != le16_to_cpu(dev->descriptor.idVendor))return 0;if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&id->idProduct != le16_to_cpu(dev->descriptor.idProduct))return 0;/* No need to test id->bcdDevice_lo != 0, since 0 is nevergreater than any unsigned number. */if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))return 0;if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))return 0;if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&(id->bDeviceClass != dev->descriptor.bDeviceClass))return 0;if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&(id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))return 0;if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))return 0;return 1;
}這個函數(shù)采用了排比的修辭手法,美觀的同時也增加了可讀性。這一個個的if條件里都有一部分是將id 的match_flags和一個宏相與,所以弄明白match_flags的意思就很關(guān)鍵。罷了罷了,本來說不再浪費(fèi)口舌在id里的那些字段上了,不過為了減少你驀然回首的次數(shù),這里再說一下這個match_flags。
驅(qū)動的花名冊里每個設(shè)備都對應(yīng)了一個struct usb_device_id結(jié)構(gòu)體,這個結(jié)構(gòu)體里有很多字段,都是驅(qū)動設(shè)定好的條條框框,接口必須完全滿足里面的條件才能夠被驅(qū)動所接受,所以說匹配的過程就是檢查接口是否滿足這些條件的過程。
當(dāng)然你可以每次都按照id的內(nèi)容一個一個的比較下去,但是經(jīng)常來說,一個驅(qū)動往往只是想設(shè)定其中的某幾項(xiàng),并不要求struct usb_device_id結(jié)構(gòu)里的所有那些條件都要滿足。match_flags就是為了方便各種各樣的需求而生的,驅(qū)動可以將自己的條件組合起來,match_flags的每一位對應(yīng)一個條件,驅(qū)動care哪個條件了,就將那一位置1,否則就置0。當(dāng)然,內(nèi)核里對每個驅(qū)動可能會care的條件都定義成了宏,供驅(qū)動去組合,它們都在include/linux/mod_devicetable.h里定義
#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200你用自己的火眼金睛很容易的就能看出來這些數(shù)字分別表示了一個u16整數(shù),也就是match_flags中的某一位。驅(qū)動比較在意哪個方面,就可以將match_flags里對應(yīng)的位置1,在和接口匹配的時候自動就會去比較驅(qū)動設(shè)置的那個條件是否滿足。那整個usb_match_device()函數(shù)就沒什么說的了,就是從match_flags那里得到驅(qū)動都在意哪些條件,然后將設(shè)備保存在自己描述符里的自身信息與id里的相應(yīng)條件進(jìn)行比較,有一項(xiàng)比較不成功就說明匹配失敗,如果一項(xiàng)符合了就接著看下一項(xiàng),接口parent都滿足條件了,就返回1,表示匹配成功了。
還是回到usb_match_one_id()繼續(xù)往下看,假設(shè)你運(yùn)氣還不錯,parent滿足了驅(qū)動的所有條件,那就調(diào)用函數(shù)usb_match_one_id_intf
int usb_match_one_id_intf(struct usb_device *dev,struct usb_host_interface *intf,const struct usb_device_id *id)
{/* The interface class, subclass, protocol and number should never be* checked for a match if the device class is Vendor Specific,* unless the match record specifies the Vendor ID. */if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |USB_DEVICE_ID_MATCH_INT_SUBCLASS |USB_DEVICE_ID_MATCH_INT_PROTOCOL |USB_DEVICE_ID_MATCH_INT_NUMBER)))return 0;if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&(id->bInterfaceClass != intf->desc.bInterfaceClass))return 0;if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))return 0;if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))return 0;if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&(id->bInterfaceNumber != intf->desc.bInterfaceNumber))return 0;return 1;
}8行。這行的意思是,如果接口的parent,usb設(shè)備是屬于廠商定義的class,也就是不屬于storage等等標(biāo)準(zhǔn)的class,就不再檢查接口的class,subclass和protocol了,除非match_flags里指定了條件USB_DEVICE_ID_MATCH_VENDOR。16行之后的三個if也不用多說,前面是檢查接口parent的,這里就是檢查接口本身是不是滿足驅(qū)動的條件的。
當(dāng)上面各個函數(shù)進(jìn)行的所有檢查都完全匹配時,usb總線的match函數(shù)usb_device_match就會返回1表示匹配成功,之后接著就會去調(diào)用驅(qū)動的probe函數(shù)做更深入的處理,什么樣的處理?這是每個驅(qū)動才知道的事情,反正到此為止,core的任務(wù)是已經(jīng)圓滿完成了,咱們的故事也就該結(jié)束了。
這個core的故事,從match開始,到match結(jié)束,它雖說不會遍及core的邊邊角角所有部分,但應(yīng)該也有那么十之七八。在match的兩端是設(shè)備和設(shè)備的驅(qū)動,是接口和接口的驅(qū)動,這個故事里遇到的人,遇到的事,早就安排在那里了,由不得我們?nèi)ミx擇。在人生的路口上,早已經(jīng)安排了那些人,那些事,決定你向左走還是向右走。既然如此,那就隨便走好了,想那么多干什么呢?
總結(jié)
以上是生活随笔為你收集整理的Linux那些事儿 之 戏说USB(大结局)还是那个match的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 长期吸烟却又喜欢喝茶的人,后来怎么样了?
- 下一篇: 《深入理解Android:Wi-Fi,N