我们打开unusual_devs.h吧,随便看一下,发现里边就是很多一个个UNUSUAL_DEV宏,每一行就是这么一个宏,毫无疑问它对应一种设备,我们从其中挑一个来看,比如挑一个三星的吧,过去在Intel的时候,前辈们会说,若不是当初我们对自己太自信了,这个世界上又怎么有三星的生存空间.说的是上世纪末,Intel决定提高flash产品的价格,而Nokia这个大客户不干了,它想找别人,一个叫三星的小公司鬼魅般的出现了,没有人相信这样一个小公司能够满足Nokia,可是,韩国人,韩国人的韧劲不仅仅是体现在足球场上.于是,世界上有了三星,Nokia养活了三星,而Intel,在flash这一领域失去了一个重要的客户,副CEO也为此引咎辞职了.而下面这个设备,正是来自三星的一个flash产品.
711 /* Submitted by Hartmut Wahl <hwahl@hwahl.de>*/
712 UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001,
713 "Samsung",
714 "Digimax 410",
715 US_SC_DEVICE, US_PR_DEVICE, NULL,
716 US_FL_FIX_INQUIRY),
Digimax 410,熟悉数码相机的哥们儿大概对三星的这款410万像素3倍光学变焦的产品不会陌生,不过数码相机更新得很快,这款2002年推出的相机如今当然也算是很一般了,市场上卖的话也就1500以下,不过当时刚推出的时候也是3000到4000元的.ok,我们来看这一行是什么意思.
UNUSUAL_DEV这个宏被定义过两次,当然,#define了之后再下一次#define之前有一个#undef,否则就重复定义了.在storage_usb_ids之前,它的定义是
116 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, /
117 vendorName, productName,useProtocol, useTransport, /
118 initFunction, flags) /
119 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) }
USB_DEVICE_VER的定义在include/linux/usb.h中,
448 /**
449 * USB_DEVICE_VER - macro used to describe a specific usb device with a version range
450 * @vend: the 16 bit USB Vendor ID
451 * @prod: the 16 bit USB Product ID
452 * @lo: the bcdDevice_lo value
453 * @hi: the bcdDevice_hi value
454 *
455 * This macro is used to create a struct usb_device_id that matches a
456 * specific device, with a version range.
457 */
458 #define USB_DEVICE_VER(vend,prod,lo,hi) /
459 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, .idVendor = (vend), .idProduct = (prod), .bcdDevice_lo = (lo), .bcdDevice_hi = (hi)
所以这行最终出现在storage_usb_ids中的意思就是令match_flags为 USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,idVendor为0x0839,idProduct为0x000a,bcdDevice_lo为0x0001,bcdDevice_hi为0x0001.
而在us_unusal_dev_list这张表之前,UNUSUAL_DEV又被定义为:
168 #undef UNUSUAL_DEV
169 #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, /
170 vendor_name, product_name, use_protocol, use_transport, /
171 init_function, Flags) /
172 { /
173 .vendorName = vendor_name, /
174 .productName = product_name, /
175 .useProtocol = use_protocol, /
176 .useTransport = use_transport, /
177 .initFunction = init_function, /
178 .flags = Flags, /
179 }
Ok.这样这个宏的意思又是令vendorName为"Samsung",令productName为"Digimax 410",而useProtocol为US_SC_DEVICE, useTransport为US_PR_DEVICE,initFunction为NULL,flag为US_FL_FIX_INQUIRY.
看明白了吗?首先不去管各项的具体含义,至少我们看出来,针对同一个文件,我们使用两次定义UNUSUAL_DEV这个宏的方法,两次利用了它的不同元素,换言之,UNUSUAL_DEV这个宏本来可以设定10个参数,而storage_usb_ids中需要使用其中的前4个参数,同时us_unusual_dev_list中需要使用其中的后6个参数,所以在unusual_devs.h中定义的一行起了两个作用.我们注意到不管是storage_usb_ids数组还是us_unusual_dev_list,其中都通过这么一行把unusual_devs.h文件给包含了进来.storage_usb_ids中:
121 static struct usb_device_id storage_usb_ids [] = {
122
123 # include "unusual_devs.h"
124 #undef UNUSUAL_DEV
us_unusual_dev_list中:
181 static struct us_unusual_dev us_unusual_dev_list[] = {
182 # include "unusual_devs.h"
183 # undef UNUSUAL_DEV
而我们之所以使用两个数组的原因是,storage_usb_ids是提供给usb core的,它需要比较driver和device从而确定设备是被这个driver所支持的,我们只需要比较四项就可以了,因为这四项已经足以确定一个设备了,厂商,产品,序列号.比较这些就够了,而us_unusual_dev_list这个数组中的元素是我们接下来的代码要用的,比如它用什么协议,它有什么初始化函数,所以我们使用了两个数组.而我们需要注意的是,这两个数组中元素的顺序是一样的,所以我们从storage_usb_ids中得到的id_index用于us_unusual_dev_list也是可以的,表示的还是同一个设备.而这也就是我们刚才在get_device_info中看到的.
472 struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index];
473 struct usb_device_id *id = &storage_usb_ids[id_index];
这样,unusual_dev和id就各取所需了.下面我们将会用到这两个指针.暂且不表.
总结陈词,最后具体解释一下这行为三星这款数码相机写的语句,
1. 关于match_flags,它的值是USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,这是一个宏,它就告诉usb core,要比较这样几个方面,idVendor,idProduct,bcdDevice_lo,bcdDevice_hi,其中idVendor和下面的vendorName是对应的,而idProduct和下面的productName是对应的,业内为每家公司编一个号,这样便于管理,比如三星的编号就是0x0839,那么三星的产品中就会在其设备描述符中idVendor的烙上0x0839.而三星自己的每种产品也会有个编号,和Digimax 410对应的编号就是0x000a,而bcdDevice_lo和bcdDevice_hi共同组成一个具体设备的编号(device release number),bcd就意味着这个编号是二进制的格式.
2. vendorName和productName不用再说了, "Samsung"和"Digimax 410".
3. useProtocol为US_SC_DEVICE, useTransport为US_PR_DEVICE,这种情况就说明对于这种设备,它属于什么subclass,它使用什么通信协议,得从设备描述符里边去读取,它都写在那里边了.一会我们会看到我们的代码中会如何判断这个的.
4. initFunction等于NULL,这个很有意义的,这个函数就是设备的初始化函数,一般的设备都不需要这个函数,但是有些设备它偏要标新立异,它就告诉你,要用我的设备你必须先做一些初始化,于是它提供了一个函数,initFunction当然是一个函数指针,这里如果不为NULL的话,到时候就会被调用,以后我们会看到代码中对这个指针进行了判断.如果为空不理睬,否则就会执行.比如我们看下面两处,惠普的两个设备,它就提供了一个叫做init_8200e的初始化函数,
63 UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
64 "HP",
65 "CD-Writer+ 8200e",
66 US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
67
68 UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
69 "HP",
70 "CD-Writer+ CD-4e",
71 US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
5. flag等于US_FL_FIX_INQUIRY,这个flag可以设为很多值,这个flag的存在本身就表示这个设备有些与众不同,因为一般的设备是不用这个flag的,有这个flag就表明这个设备可能在某些地方需要进行特殊的处理,所以今后在代码中我们会看到突然跳出一句,判断us->flag等于某个咚咚不,如果等于,就执行一些代码,如果不等于,那就不做任何事情.这个flag的存在也使得我们可以方便处理一些设备的bug,比如正常的设备你问它吃了吗?它就回答吃了.可是不正常的设备可能就会根本不回答,或者回答北京房价真贵!于是对于这种设备,可能我们就需要一些专门的代码来对付.具体到这个US_FL_FIX_INQUIRY,这个flag这么一设置,就表明这个设备在接受到INQUIRY命令的时候会有一些异常的特征,所以以后我们会在代码里看到我们是如何处理它的.设置了这个flag的当然不只是三星的这款相机,别的设备也有可能设置的.
6. 既然明白了unusual_devs.h的作用,那么很显然的一个事情,如果一个厂家推出了一个新的设备,它有一些新的特征,而目前的设备驱动不足以完全支持它,那么厂家首先需要做的事情就是在unusual_devs.h中添加一个UNUSUAL_DEV来定义自己的设备,然后再看是否需要给内核打补丁以及如何打.因此这几年unusual_devs.h这个文件的长度也是慢慢在增长.