Linux那些事儿之我是U盘(17)冬天来了,春天还会远吗?(一)

整个usb-storage模块的代码中,其最灵魂的部分在一个叫做usb_stor_control_thread()的函数中,而那也自然是我们整个故事的高潮.这个函数的调用有些特殊,我们是从usb_stor_acquire_resources()函数进入的,而后者我们即将遇到,它在整部戏中只出现过一次,storage_probe,行号为998的地方.然而在此之前,有四个函数挡在我们面前,它们就是get_device_info,get_transport,get_protocol,get_pipes.如我前面所说,两个人要走到一起,首先要了解彼此,这四个函数就是让driver去认识device.这一点我们从名字上也能看出来.driver需要知道device姓甚名谁,所以有了get_device_info,driver需要知道device喜欢用什么方式沟通,是用QQ还是用msn还是只用手机短信,如果是某一种,那么账号是多少,或者手机号是多少,写代码的人把这些工作分配给了get_transport,get_protocol,get_pipes.

实际上,这四个函数,加上之前刚说过的那个associate_dev(),是整个故事中最平淡最枯燥的部分,第一次读这部分代码总让人困惑,怎么没看见一点usb数据通信啊?完全没有看到usb hostusb device是如何在交流的,这是usb?这一刻,这颗浮躁的心,在这个城市,迷失了.但是,我们知道,爱情,并非都与风花雪月有关,友情,并非总与疯斗打闹有关.这几个函数应该说是给后面做铺垫,红花总要有绿叶配,没有这段代码的铺垫,到了后面usb设备恐怕也无法正常工作吧.不过,一个利好消息是,这几个函数我们只会遇见这一次,它们在整个故事中就这么一次露脸的机会,像我们每个人的青春,只有一次,无法回头.和我们每个人的青春一样,都是绝版的.所以,让我们享受这段平淡无奇的代码吧.

get_device_info, 这个函数定义于drivers/usb/storage/usb.c:

466 /* Get the unusual_devs entries and the string descriptors */
467 static void get_device_info(struct us_data *us, int id_index)
468 {
469 struct usb_device *dev = us->pusb_dev;
470 struct usb_interface_descriptor *idesc =
471 &us->pusb_intf->cur_altsetting->desc;
472 struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index];
473 struct usb_device_id *id = &storage_usb_ids[id_index];
474
475 /* Store the entries */
476 us->unusual_dev = unusual_dev;
477 us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ?
478 idesc->bInterfaceSubClass :
479 unusual_dev->useProtocol;
480 us->protocol = (unusual_dev->useTransport == US_PR_DEVICE) ?
481 idesc->bInterfaceProtocol :
482 unusual_dev->useTransport;
483 us->flags = unusual_dev->flags;
484
485 /* Log a message if a non-generic unusual_dev entry contains an
486 * unnecessary subclass or protocol override. This may stimulate
487 * reports from users that will help us remove unneeded entries
488 * from the unusual_devs.h table.
489 */
490 if (id->idVendor || id->idProduct) {
491 static char *msgs[3] = {
492 "an unneeded SubClass entry",
493 "an unneeded Protocol entry",
494 "unneeded SubClass and Protocol entries"};
495 struct usb_device_descriptor *ddesc = &dev->descriptor;
496 int msg = -1;
497
498 if (unusual_dev->useProtocol != US_SC_DEVICE &&
499 us->subclass == idesc->bInterfaceSubClass)
500 msg += 1;
501 if (unusual_dev->useTransport != US_PR_DEVICE &&
502 us->protocol == idesc->bInterfaceProtocol)
503 msg += 2;
504 if (msg >= 0 && !(unusual_dev->flags & US_FL_NEED_OVERRIDE))
505 printk(KERN_NOTICE USB_STORAGE "This device "
506 "(%04x,%04x,%04x S %02x P %02x)"
507 " has %s in unusual_devs.h/n"
508 " Please send a copy of this message to "
509 "<[email protected]>/n",
510 ddesc->idVendor, ddesc->idProduct,
511 ddesc->bcdDevice,
512 idesc->bInterfaceSubClass,
513 idesc->bInterfaceProtocol,
514 msgs[msg]);
515 }
516
517 /* Read the device's string descriptors */
518 if (dev->descriptor.iManufacturer)
519 usb_string(dev, dev->descriptor.iManufacturer,
520 us->vendor, sizeof(us->vendor));
521 if (dev->descriptor.iProduct)
522 usb_string(dev, dev->descriptor.iProduct,
523 us->product, sizeof(us->product));
524 if (dev->descriptor.iSerialNumber)
525 usb_string(dev, dev->descriptor.iSerialNumber,
526 us->serial, sizeof(us->serial));
527
528 /* Use the unusual_dev strings if the device didn't provide them */
529 if (strlen(us->vendor) == 0) {
530 if (unusual_dev->vendorName)
531 strlcpy(us->vendor, unusual_dev->vendorName,
532 sizeof(us->vendor));
533 else
534 strcpy(us->vendor, "Unknown");
535 }
536 if (strlen(us->product) == 0) {
537 if (unusual_dev->productName)
538 strlcpy(us->product, unusual_dev->productName,
539 sizeof(us->product));
540 else
541 strcpy(us->product, "Unknown");
542 }
543 if (strlen(us->serial) == 0)
544 strcpy(us->serial, "None");
545
546 US_DEBUGP("Vendor: %s, Product: %s/n", us->vendor, us->product);
547 }

469,不多说,dev还是那个dev.

470,struct usb_interface_descriptor *idesc,这个也无须再说,之前那个associate_dev函数里已经介绍过这个结构体,而且整个故事就是针对一个interface,一个interface就对应一个interface描述符.所以不管在哪里看到,她总还是她.

472, struct us_unusual_dev,这个结构体是第一次出现,她定义于drivers/usb/storage/usb.h,

55 /*
56 * Unusual device list definitions
57 */
58
59 struct us_unusual_dev {
60 const char* vendorName;
61 const char* productName;
62 __u8 useProtocol;
63 __u8 useTransport;
64 int (*initFunction)(struct us_data *);
65 unsigned int flags;
66 };

而等号右边的us_unusal_dev_list是一个数组,定义于drivers/usb/storage/usb.c:

157 /* This is the list of devices we recognize, along with their flag data */

158

159 /* The vendor name should be kept at eight characters or less, and

160 * the product name should be kept at 16 characters or less. If a device

161 * has the US_FL_FIX_INQUIRY flag, then the vendor and product names

162 * normally generated by a device thorugh the INQUIRY response will be

163 * taken from this list, and this is the reason for the above size

164 * restriction. However, if the flag is not present, then you

165 * are free to use as many characters as you like.

166 */

167

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 }

180

181 static struct us_unusual_dev us_unusual_dev_list[] = {

182 # include "unusual_devs.h"

183 # undef UNUSUAL_DEV

184 /* Control/Bulk transport for all SubClass values */

185 { .useProtocol = US_SC_RBC,

186 .useTransport = US_PR_CB},

187 { .useProtocol = US_SC_8020,

188 .useTransport = US_PR_CB},

189 { .useProtocol = US_SC_QIC,

190 .useTransport = US_PR_CB},

191 { .useProtocol = US_SC_UFI,

192 .useTransport = US_PR_CB},

193 { .useProtocol = US_SC_8070,

194 .useTransport = US_PR_CB},

195 { .useProtocol = US_SC_SCSI,

196 .useTransport = US_PR_CB},

197

198 /* Control/Bulk/Interrupt transport for all SubClass values */

199 { .useProtocol = US_SC_RBC,

200 .useTransport = US_PR_CBI},

201 { .useProtocol = US_SC_8020,

202 .useTransport = US_PR_CBI},

203 { .useProtocol = US_SC_QIC,

204 .useTransport = US_PR_CBI},

205 { .useProtocol = US_SC_UFI,

206 .useTransport = US_PR_CBI},

207 { .useProtocol = US_SC_8070,

208 .useTransport = US_PR_CBI},

209 { .useProtocol = US_SC_SCSI,

210 .useTransport = US_PR_CBI},

211

212 /* Bulk-only transport for all SubClass values */

213 { .useProtocol = US_SC_RBC,

214 .useTransport = US_PR_BULK},

215 { .useProtocol = US_SC_8020,

216 .useTransport = US_PR_BULK},

217 { .useProtocol = US_SC_QIC,

218 .useTransport = US_PR_BULK},

219 { .useProtocol = US_SC_UFI,

220 .useTransport = US_PR_BULK},

221 { .useProtocol = US_SC_8070,

222 .useTransport = US_PR_BULK},

223 #if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE)

224 { .useProtocol = US_SC_SCSI,

225 .useTransport = US_PR_BULK},

226 #endif

227

228 /* Terminating entry */

229 { NULL }

230 };

无可奈何花落去,似曾相识燕归来.这个数组看上去特别面熟对不对?可曾记得当初我们见过的那个storage_usb_ids,仔细对比一下会发现,这两个数组的元素个数完全一样,只不过,一个由是struct usb_device_id结构体构成的,另一个则是struct us_unusual_dev结构体构成的,其实这两个表格是一一对应的,它们也都定义于同一个文件中. 细心一点会注意到,UNUSUAL_DEV这个宏在这个文件里被定义了两次,这是干嘛用的?听仔细了,我们曾经提过unusual_devs.h这个文件,这个文件的作用是什么?假设没有这个文件,那么storage_usb_ids这张表就是用USB_INTERFACE_INFO这个宏定义了几种常规的usb mass storage的设备,比如,

{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },

这一行就是定义一个设备的bInterfaceClass,bInterfaceSubClass,bInterfaceProtocol,也就是说一个usb interface只要其这三个项特点与这张表里定义的任何一行匹配,那么就可以把这个设备和这个驱动绑定,但是这三个条件毕竟只是规定了一些主流的或者说常规的设备的特点,这个世界上usb mass storage设备有许多种,林子大了,什么鸟都有.如果你的设备不符合这三个条件但是你仍然要用这个驱动怎么办?或者说你的设备不一般,在正式工作之前需要进行一些初始化的操作,你想自己提供一个初始化函数,那怎么办?伟大的Linux内核开发者们为你准备了一个文件,它就是让诸多usb mass storage设备厂家欢欣鼓舞的unusual_devs.h,有了它,厂家们不用再为自己的设备不被Linux内核支持而烦恼了.虽然我们的U盘基本上不属于这些另类设备,但作为一个有责任心的社会主义新青年,我们有必要为这个文件说两句.

你可能感兴趣的:(linux)