probe,disconnect,id_table,这三个元素中首先要登场亮相的是id_table,它是干什么用的呢?
我们说过,一个设备只能绑定一个驱动,但驱动并非只能支持一种设备。道理很简单,比如我有两块U盘,那么我可以一起都插入,但是我只需要加载一个模块,usb-storage。没听说过插入两块U盘就得加载两次驱动程序的,除非这两块U盘本身就得使用不同的驱动程序。也正是因为一个模块可以被多个设备共用,才会有“模块计数”这个说法。
既然一个驱动可以支持多个设备,那么当发现一个设备时,如何知道哪个才是它的驱动呢?这就是id_table的用处,让每一个struct usb_driver准备一张表,里面注明该驱动支持哪些设备,这总可以了吧。如果这个设备属于这张表里的,那么绑定,如果不属于这张表里的,那么不好意思,您请便。
id_table来自struct usb_driver中:
const struct usb_device_id *id_table;
它实际上是一个指针,一个structusb_device_id结构体的指针,当然赋了值以后就是代表一个数组名了,正如我们在定义struct usb_driver usb_storage_driver中所赋的值那样,.id_table=storage_usb_ids,那好,我们来看一下usb_device_id这究竟是怎样一个结构体。
struct usb_device_id来自include/linux/mod_devicetable.h:
98 struct usb_device_id {
99 /* whichfields to match against? */
100 __u16match_flags;
101
102 /* Used for product specificmatches; range is inclusive */
103 __u16idVendor;
104 __u16idProduct;
105 __u16bcdDevice_lo;
106 __u16bcdDevice_hi;
107
108 /*Used for device class matches */
109 __u8bDeviceClass;
110 __u8bDeviceSubClass;
111 __u8bDeviceProtocol;
112
113 /* Used for interface classmatches */
114 __u8bInterfaceClass;
115 __u8bInterfaceSubClass;
116 __u8bInterfaceProtocol;
117
118 /*not matched against */
119 kernel_ulong_t driver_info;
120 };
实际上这个结构体对每一个USB设备来说,就相当于是它的身份证,记录了它的一些基本信息。通常我们的身份证上会记录我们的姓名,性别,出生年月,户口地址等,而USB设备也有它需要记录的信息,以区分它和别的USB设备。比如Vendor-厂家,Product-产品,以及其他一些比如产品编号、产品的类别、遵循的协议,这些都会在USB的规范里边找到对应的成员。
于是我们知道,一个usb_driver会把它的id表和每一个USB设备的实际情况进行比较,如果该设备的实际情况和这张表里的某一个id相同,准确地说,只有这许多特征都吻合,才能够把一个USB设备和这个USB驱动进行绑定,这些特征哪怕差一点也不行。
那么USB设备的实际情况是什么时候建立起来的?在介绍.probe指针之前有必要先谈一谈另一个数据结构了,它就是struct usb_device。