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

来源:互联网 发布:linux echo写入 编辑:程序博客网 时间:2024/04/23 23:15

整个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                                 "<linux-usb-devel@lists.sourceforge.net>/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盘基本上不属于这些另类设备,但作为一个有责任心的社会主义新青年,我们有必要为这个文件说两句.