在第五節我們說過會專門分析函數usb_device_match,以體現模型的重要性。同時,我們還是要守信用的。
再貼一遍代碼,看代碼就要不厭其煩。
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;usb_device_driver
/* TODO: Add real matching code */
return 1;
usb_device
} 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;
}
前面說過,總線上掛着兩條鏈表,一條是設備鏈表,一條是驅動鏈表,經過漫長的歲月里的煎熬,終於通過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 */注釋的含義了嗎????含蓄的我都不想再解釋了。
/** * struct usb_driver - identifies USB interface driver to usbcore * @name: The driver name should be unique among USB drivers, * and should normally be the same as the module name. * @probe: Called to see if the driver is willing to manage a particular * interface on a device. If it is, probe returns zero and uses * usb_set_intfdata() to associate driver-specific data with the * interface. It may also use usb_set_interface() to specify the * appropriate altsetting. If unwilling to manage the interface, * return -ENODEV, if genuine IO errors occured, an appropriate * negative errno value. * @disconnect: Called when the interface is no longer accessible, usually * because its device has been (or is being) disconnected or the * driver module is being unloaded. * @ioctl: Used for drivers that want to talk to userspace through * the "usbfs" filesystem. This lets devices provide ways to * expose information to user space regardless of where they * do (or don't) show up otherwise in the filesystem. * @suspend: Called when the device is going to be suspended by the system. * @resume: Called when the device is being resumed by the system. * @reset_resume: Called when the suspended device has been reset instead * of being resumed. * @pre_reset: Called by usb_reset_device() when the device * is about to be reset. * @post_reset: Called by usb_reset_device() after the device * has been reset * @id_table: USB drivers use ID table to support hotplugging. * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set * or your driver's probe function will never get called. * @dynids: used internally to hold the list of dynamically added device * ids for this driver. * @drvwrap: Driver-model core structure wrapper. * @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be * added to this driver by preventing the sysfs file from being created. * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend * for interfaces bound to this driver. * @soft_unbind: if set to 1, the USB core will not kill URBs and disable * endpoints before calling the driver's disconnect method. * * USB interface drivers must provide a name, probe() and disconnect() * methods, and an id_table. Other driver fields are optional. * * The id_table is used in hotplugging. It holds a set of descriptors, * and specialized data may be associated with each entry. That table * is used by both user and kernel mode hotplugging support. * * The probe() and disconnect() methods are called in a context where * they can sleep, but they should avoid abusing the privilege. Most * work to connect to a device should be done when the device is opened, * and undone at the last close. The disconnect code needs to address * concurrency issues with respect to open() and close() methods, as * well as forcing all pending I/O requests to complete (by unlinking * them as necessary, and blocking until the unlinks complete). */
struct usb_driver {
const char *name;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id);
void (*disconnect) (struct usb_interface *intf);
int (*ioctl) (struct usb_interface *intf, unsigned int code,
void *buf);
int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
int (*reset_resume)(struct usb_interface *intf);
int (*pre_reset)(struct usb_interface *intf);
int (*post_reset)(struct usb_interface *intf);
const struct usb_device_id *id_table;
struct usb_dynids dynids;
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int soft_unbind:1;
};
這么長,為什么要貼出來,重要啊!還有什么比這注釋看的更讓人有勁有味的?
每個寫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設備驅動與接口驅動到底都有多大的不同。
/** * struct usb_device_driver - identifies USB device driver to usbcore * @name: The driver name should be unique among USB drivers, * and should normally be the same as the module name. * @probe: Called to see if the driver is willing to manage a particular * device. If it is, probe returns zero and uses dev_set_drvdata() * to associate driver-specific data with the device. If unwilling * to manage the device, return a negative errno value. * @disconnect: Called when the device is no longer accessible, usually * because it has been (or is being) disconnected or the driver's * module is being unloaded. * @suspend: Called when the device is going to be suspended by the system. * @resume: Called when the device is being resumed by the system. * @drvwrap: Driver-model core structure wrapper. * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend * for devices bound to this driver. * * USB drivers must provide all the fields listed above except drvwrap. */
struct usb_device_driver {
const char *name;
int (*probe) (struct usb_device *udev);
void (*disconnect) (struct usb_device *udev);
int (*suspend) (struct usb_device *udev, pm_message_t message);
int (*resume) (struct usb_device *udev, pm_message_t message);
struct usbdrv_wrap drvwrap;
unsigned int supports_autosuspend:1;
};
再一次連注釋附上,表示這個結構體很重要。
這個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世界里的整個人生旅程。