USB驱动分析(三)

来源:互联网 发布:大型网络海战游戏 编辑:程序博客网 时间:2024/04/28 15:51

需要注意的是,这些调试信息得是我们打开了编译选项CONFIG_USB_STORAGE_DEBUG才有意义的,这里也看出来了,如果这个选项为0,那么这几个宏就什么也不干,因为它们被赋为空了.关于US_DEBUG系列的这几个宏,就讲这么多,之后再碰上,将直接过滤掉,不予多说.
关于prink和kmalloc,这两个函数也没有太多需要说的,对大多数人来讲,就把printk当成printf,把kmalloc当成malloc即可,只不过是这两个函数是专门用于内核代码中的.一个是打印一些东西,一个是申请内存空间.
931行呢?id_index干嘛用的?让我们在下节不见不散吧.Be there or be square!-孙楠如是说.

storage_probe这个函数挺有意思的,总长度不足100行,但是干了许多事情,这就像足球场上的后腰,比如切尔西的马克莱莱,在场上并不起眼,但是却为整个团队做出了卓越的贡献.也有很多评论家说银河战舰皇家马德里这几年的衰落正是从赶走这个不起眼的马克莱莱开始的.
在讲id_index之前,我们继续贴storage_probe的代码:
    943         init_MUTEX(&(us->dev_semaphore));
    944         init_MUTEX_LOCKED(&(us->sema));
    945         init_completion(&(us->notify));
    946         init_waitqueue_head(&us->dev_reset_wait);
    947         init_waitqueue_head(&us->scsi_scan_wait);
    948         init_completion(&us->scsi_scan_done);
    949
    950         /* Associate the us_data structure with the USB device */
    951         result = associate_dev(us, intf);
    952         if (result)
    953                 goto BadDevice;
    954
    955         /*
    956          * Get the unusual_devs entries and the descriptors
    957          *
    958          * id_index is calculated in the declaration to be the index number
    959          * of the match from the usb_device_id table, so we can find the
    960          * corresponding entry in the private table.
    961          */
    962         get_device_info(us, id_index);
storage_probe这个函数之所以短小,是因为它调用了大量的函数.所以,看起来短短一段代码,实际上却要花费我们读代码的人好几个小时,想想真是觉得不划算,难怪朱自清先生看到这个storage_probe函数的时候,不禁感慨,燕子去了,有再来的时候,杨柳枯了,有再青的时候,桃花谢了,有再开的时候,但是,聪明的你告诉我,我们读这段不足100行的函数花掉的时间为何一去不复返呢?
其实我们不知道id_index也不影响对后面问题的理解,甚至某种意义上来说,花太多笔墨去讲这个id_index有一点喧宾夺主的感觉,但是,有时候,有些事情,你明知它是无奈的事,无奈的心情,却还要无奈的面对,无奈的去选择,有时想无奈的逃避都不可能,因为我们都被无奈禁锢了.比如这里,注意到962行出现了一个get_device_info的函数,它的一个参数就是id_index,所以,我们别无选择,只能看看这个id_index究竟是干嘛的.
上节我们注意到id_index=id-storage_usb_ids,id我们知道,storage_probe函数的两个形参之一,而storage_usb_ids,不是别人,正是我们曾经赋给usb_storage_driver的成员id_table的值.忘记了id_table的可以回去看.它实际上就是一张表格,告诉全世界我这个driver支持怎样的一些设备.storage_usb_ids同样来自drivers/usb/storage/usb.c中,
    111 /* The entries in this table, except for final ones here
    112  * (USB_MASS_STORAGE_CLASS and the empty entry), correspond,
    113  * line for line with the entries of us_unsuaul_dev_list[].
    114  */
    115
    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) }
    120
    121 static struct usb_device_id storage_usb_ids [] = {
    122
    123 #       include "unusual_devs.h"
    124 #undef UNUSUAL_DEV
    125         /* Control/Bulk transport for all SubClass values */
    126         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },
    127         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CB) },
    128         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CB) },
    129         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CB) },
    130         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CB) },
    131         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CB) },
    132
    133         /* Control/Bulk/Interrupt transport for all SubClass values */
    134         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CBI) },
    135         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CBI) },
    136         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CBI) },
    137         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CBI) },
    138         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CBI) },
    139         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CBI) },
    140
    141         /* Bulk-only transport for all SubClass values */
    142         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_BULK) },
    143         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_BULK) },
    144         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) },
    145         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
    146         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
    147 #if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE)
    148         { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
    149 #endif
    150
    151         /* Terminating entry */
    152         { }
    153 };
注意到这是一个struct usb_device_id结构体的数组,所以即使我们用下半身思考也能知道,其中每一项必然是一个struct usb_device_id的结构体变量.我们先来看USB_INTERFACE_INFO这个咚咚,很显然这是一个宏,来自include/linux/usb.h,
    473 /**
    474  * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces
    475  * @cl: bInterfaceClass value
    476  * @sc: bInterfaceSubClass value
    477  * @pr: bInterfaceProtocol value
    478  *
    479  * This macro is used to create a struct usb_device_id that matches a
    480  * specific class of interfaces.
    481  */
    482 #define USB_INTERFACE_INFO(cl,sc,pr) \
    483         .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
每一个USB_INTERFACE_INFO就是构造一个struct usb_device_id的结构体变量,回顾一下我们之前给出的struct usb_device_id的定义,这里实际上就是为其中的四个元素赋了值,它们是match_flags,bInterfaceClass,bInterfaceSubClass,bInterfaceProtocol.这里不得不说的是,这个世界上有许许多多的usb设备,它们各有各的特点,为了区分它们,usb规范,或者说usb协议,把usb设备分成了很多类,然而每个类又分成子类,这很好理解,我们一个大学也是如此,先是分成很多个学院,比如我们复旦大学,信息学院,经济学院,管理学院,外文学院,等等.然后每个学院又被分为很多个系,比如信息学院,下面分了电子工程系,微电子系,计算机系,通信工程系,然后可能每个系下边又分了各个专业,usb协议也是这样干的,首先每个Interface属于一个Class,(为什么是把Interface分类,而不把Device分类?前面讲过了,在usb设备驱动中,不用再提Device,因为每个设备驱动对应的是一种Interface,而不是一种Device),然后Class下面又分了SubClass,完了SubClass下面又按各种设备所遵循的不同的通信协议继续细分.usb协议里边为每一种Class,每一种SubClass,每一种Protocol定义一个数值,比如mass storage的Class就是0x08,而这里USB_CLASS_MASS_STORAGE这个宏在include/linux/usb_ch9.h中定义,其值正是8.
我们拿第126行来举例,
  { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },
  把这个宏展开,就是说定义了这么一个usb_device_id结构体变量,其match_flags=USB_DEVICE_ID_MATCH_INT_INFO,而bInterfaceClass=USB_CLASS_MASS_STORAGE,bInterfaceSubClass=US_SC_RBC,而bInterfaceProtocol=US_PR_CB.
USB_CLASS_MASS_STORAGE就不用再说了,咱们这个驱动程序所支持的每一种设备都是属于这个类,或者说这个Class.但是这个Class里边包含不同的SubClass,比如subclass 02为CD-ROM设备,04为软盘驱动器,06为通用SCSI类设备.而通信协议则主要有CBI协议和Bulk-Only协议.
像US_SC_RBC这些关于sub class的宏的定义是在文件drivers/usb/storage/protocol.h中:
     47 /* Sub Classes */
     48
     49 #define US_SC_RBC       0x01            /* Typically, flash devices */
     50 #define US_SC_8020      0x02            /* CD-ROM */
     51 #define US_SC_QIC       0x03            /* QIC-157 Tapes */
     52 #define US_SC_UFI       0x04            /* Floppy */
     53 #define US_SC_8070      0x05            /* Removable media */
     54 #define US_SC_SCSI      0x06            /* Transparent */
     55 #define US_SC_ISD200    0x07            /* ISD200 ATA */
而像US_PR_CB这些关于传输协议的宏则在另一个文件中,drivers/usb/storage/transport.h
  /* Protocols */
#define US_PR_CBI       0x00            /* Control/Bulk/Interrupt */
#define US_PR_CB        0x01            /* Control/Bulk w/o interrupt */
#define US_PR_BULK      0x50            /* bulk only */
这个文件中还定义了更多的协议,不过我们暂时只需要知道这三种,因为其她协议都是专门针对一些特殊设备的,在storage_usb_ids数组中使用宏USB_INTERFACE_INFO定义的usb_device_id都只是用的这三种协议.(US_PR_CBI和US_PR_CB这两种协议在usb协议中都唤作CBI,不过之间有点差别.)而对于一些特殊的设备,则还在unusual_devs.h文件中有专门的一些变量定义,我们暂且不去关注它们.
说了这许多,U盘属于其中的哪一种呢?usb协议中规定,U盘的Subclass是属于US_SC_SCSI的.而其通信协议使用的是Bulk-Only的.显然这些东西我们后来都会用得上.
那么这里还有一个match_flag,它又是表示什么意思?USB_INTERFACE_INFO这个宏貌似把所有的设备的match_flag都给设成了USB_DEVICE_ID_MATCH_INT_INFO,这是为啥?这个宏来自include/linux/usb.h,
    435 #define USB_DEVICE_ID_MATCH_INT_INFO \
    436         (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL)
match_flag这个咚咚是给usb core去用的,usb core负责给设备寻找适合她的driver,负责给driver寻找适合他的device,它所比较的就是struct usb_device_id的变量,而struct usb_device_id结构体中有许多成员,那么是不是一定要把每一个成员都给比较一下呢,其实没有必要那么细,差不多就行了,比如咱们这里,就是告诉usb core,你只要比较bInterfaceClass,bInterfaceSubClass,bInterfaceProtocol即可.include/linux/mod_devicetable.h中针对struct usb_device_id中的每一个要比较的项定义了一个宏:
    121 /* Some useful macros to use to create struct usb_device_id */
    122 #define USB_DEVICE_ID_MATCH_VENDOR              0x0001
    123 #define USB_DEVICE_ID_MATCH_PRODUCT             0x0002
    124 #define USB_DEVICE_ID_MATCH_DEV_LO              0x0004
    125 #define USB_DEVICE_ID_MATCH_DEV_HI              0x0008
    126 #define USB_DEVICE_ID_MATCH_DEV_CLASS           0x0010
    127 #define USB_DEVICE_ID_MATCH_DEV_SUBCLASS        0x0020
    128 #define USB_DEVICE_ID_MATCH_DEV_PROTOCOL        0x0040
    129 #define USB_DEVICE_ID_MATCH_INT_CLASS           0x0080
    130 #define USB_DEVICE_ID_MATCH_INT_SUBCLASS        0x0100
    131 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL        0x0200
回去对比一下struct usb_device_id就知道这些宏是什么意思了.
然后我们再看storage_usb_ids中那个#include "unusual_devs.h",实际上这个文件也是在我们这个drivers/usb/storage/目录下面,它里边定义了一些特殊的设备,也是以struct usb_device_id结构体变量的形式,这些设备或者是有一些别的设备不具备的特性,或者是他们遵循的通信协议有些与众不同,比如,它既不是Bulk-Only也不是CBI,像这些不按常理出牌的设备,写代码的同志们把他们单独给列了出来.整理在这个文件中.当然,从大的类来分,它们依然是属于usb mass storage这个类别的,否则也没必要放在这个目录下面了.
至此,我们可以知道storage_usb_ids这个表是怎么回事了.usb core为每个设备在这张表里查找,如果找到了某一行和这个设备相匹配,那么该行就是我们前面提到的那个storage_probe()的参数id.所以id_index=id-storage_usb_ids就是如其字面意义那样,在表中的编号.至于这个编号有什么用,那我们骑驴看唱本.总之,费这么大劲干了这么一件事,总是有它的意义的.
最后,总结陈词,这个所谓的花名册,就好比我们大学生申请国外学校,每个人都会事先搜集一大批学校名单,然后结合各方面,比如师资力量,是否牛的导师够多,比如经济实力,是否能给够多的奖学金,比如教授本人资历,是否获得过重大奖项,取得过何种成绩,比如学校声望, 是否是名校,综合这些来看最终确定一份名单,就是自己真正心仪的学校花名册.那么那个match_flags是什么意思呢,而有的同学嫌这样太麻烦,又或者他们可能只是需要一个能发学历的,像杨澜老公吴征所获得博士学位的那个巴林顿大学那样卖假文凭的学校也许就能满足他们了,那么他们就不必去评估那么多项,反正他们心中的match_flags就是能够和吴征成为校友就可以了,管它是否因为该学校被取缔以后他们也会像吴征那样痛失母校呢.
罗马不是一天建成的.在让U盘工作之前,其实我们的驱动作了很多准备工作.
我们继续跟着感觉走,storage_probe(),943行至948行,一系列的以init_*命名的函数在此刻被调用,这里涉及了一些锁机制,等待机制,不过只是初始化,暂且不理睬,到后面用到的时候再细说,不过请记住,这几行每一行都是有用的.后面自然会用得着.
此时,我们先往下走,951行associate_dev()和962行get_device_info(),这两个函数是我们目前需要看的,一个一个来.
先看associate_dev(),定义于drivers/usb/storage/usb.c,
429 /* Associate our private data with the USB device */
    430 static int associate_dev(struct us_data *us, struct usb_interface *intf)
    431 {
    432         US_DEBUGP("-- %s\n", __FUNCTION__);
    433
    434         /* Fill in the device-related fields */
    435         us->pusb_dev = interface_to_usbdev(intf);
    436         us->pusb_intf = intf;
    437         us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
    438         US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",
    439                         us->pusb_dev->descriptor.idVendor,
    440                         us->pusb_dev->descriptor.idProduct,
    441                         us->pusb_dev->descriptor.bcdDevice);
    442         US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n",
    443                         intf->cur_altsetting->desc.bInterfaceSubClass,
    444                         intf->cur_altsetting->desc.bInterfaceProtocol);
    445
    446         /* Store our private data in the interface */
    447         usb_set_intfdata(intf, us);
    448
    449         /* Allocate the device-related DMA-mapped buffers */
    450         us->cr = usb_buffer_alloc(us->pusb_dev, sizeof(*us->cr),
    451                         GFP_KERNEL, &us->cr_dma);
    452         if (!us->cr) {
    453                 US_DEBUGP("usb_ctrlrequest allocation failed\n");
    454                 return -ENOMEM;
    455         }
    456
    457         us->iobuf = usb_buffer_alloc(us->pusb_dev, US_IOBUF_SIZE,
    458                         GFP_KERNEL, &us->iobuf_dma);
    459         if (!us->iobuf) {
    460                 US_DEBUGP("I/O buffer allocation failed\n");
    461                 return -ENOMEM;
    462         }
    463         return 0;
    464 }
  我们首先来关注函数associate_dev的参数, struct us_data *us,传递给它的是us,这个不用多说了吧,此前刚刚为它申请了内存,并且初始化各成员为0. 这个us将一直陪伴我们走下去,直到我们的故事结束.所以其重要性不言而喻. struct usb_interface *intf,这个也不用说,storage_probe()函数传进来的两个参数之一.总之,此处郑重申明一次,struct us_data的结构体指针us,struct usb_interface结构体的指针intf,以及struct usb_device结构体和struct usb_device_id结构体在整个U盘驱动的故事中是唯一的,每次提到都是那个. 而以后我们会遇上的几个重要的数据结构,struct urb urb,struct scsi_cmnd srb这也非常重要,但是它们并不唯一,也许每次遇上都不一样,就像演戏一样.前边这几个数据结构的变量就像那些主角,而之后遇见的urb啊,srb啊,虽然频繁露面,但是只是群众演员,只不过这次是路人甲,下次是路人乙. 所以,以后我们将只说us,不再说struct us_data *us,struct usb_interface * intf也将只用intf来代替.
us之所以重要,是因为接下来很多函数都要用到它以及它的各个成员.实际上目前这个函数,associate_dev所做的事情就是为us的各成员赋值,毕竟此刻us和我们之前提到的那些struct usb_device啊,struct usb_interface啊,还没有一点关系.因而,这个函数,以及这之后的好几个函数都是为了给us的各成员赋上适当的值,之所以如此兴师动众去为它赋值,主要就是因为后面要利用它.所谓天下没有免费的午餐.
432行,本来无须多讲,因为只是一个debug语句,不过提一下__FUNCTION__这个"宏",gcc 2.95以后的版本支持这么一个冬冬,这个"宏"在编译的时候会被转换为函数名(字符串),这里自然就是"associate_dev"这么一个字符串,于是函数执行到这里就会打印一句话告诉世人我们执行到这个函数来了,这种做法显然会有利于咱们调试程序.不过这个冬冬实际上不是宏,因为预处理器对她一无所知.她的心只有编译器才懂.
435行,pusb_dev,就是point of usb device的意思.struct us_data中的一个成员,按照我们刚才约定的规矩,此刻我将说us的一个成员,us->pusb_dev= interface_to_usbdev(intf), interface_to_usbdev我们前面已经讲过,其含义正如字面表示的那样,把一个struct interface结构体的指针转换成一个struct usb_device的结构体指针.前面我们说过,struct usb_device对我们没有什么用,但是usb core层的一些函数要求使用这个参数,所以我们不得已而为止,正所谓人在江湖身不由己.
436行,把intf赋给us的pusb_intf.
437行,us的ifnum, 先看intf的cur_altsetting,这个容易令外行混淆.usb设备有一个configuration的概念,这个我们前面讲协议的时候说了,而这里又有一个setting,咋一看有些奇怪,这两个词不是一回事吗.这时候,就体现出外语水平了,上过新东方没上过新东方,背没背过俞敏洪的GRE红宝书,在这时候就体现出差距了.还是拿我们最熟悉的手机来打比方,configuration不说了,setting,一个手机可能各种配置都确定了,是振动还是铃声已经确定了,各种功能都确定了,但是声音的大小还可以变吧,通常手机的音量是一格一格的变动,大概也就5,6格,那么这个可以算一个setting吧.这里cur_altsetting就是表示的当前的这个setting,或者说设置.cur_altsetting是一个struct usb_host_interface的指针,这个结构体定义于include/linux/usb.h:
51 /* host-side wrapper for one interface setting's parsed descriptors */
     52 struct usb_host_interface {
     53         struct usb_interface_descriptor desc;
     54
     55         /* array of desc.bNumEndpoint endpoints associated with this
     56          * interface setting.  these will be in no particular order.
     57          */
     58         struct usb_host_endpoint *endpoint;
     59
     60         unsigned char *extra;   /* Extra descriptors */
     61         int extralen;
     62 };
它的成员desc是一个struct usb_interface_descriptor结构体变量,这个结构体的定义是和usb协议直接对应的,定义于include/linux/usb_ch9.h.(这里取名为"ch9"是因为这个文件很多东西对应于usb spec 2.0中的第九章,chapter 9.):
    242 /* USB_DT_INTERFACE: Interface descriptor */
    243 struct usb_interface_descriptor {
    244         __u8  bLength;
    245         __u8  bDescriptorType;
    246
    247         __u8  bInterfaceNumber;
    248         __u8  bAlternateSetting;
    249         __u8  bNumEndpoints;
    250         __u8  bInterfaceClass;
    251         __u8  bInterfaceSubClass;
    252         __u8  bInterfaceProtocol;
    253         __u8  iInterface;
    254 } __attribute__ ((packed));
而其中我们这里提到的是bInterfaceNumber,一个设备可以有多个Interface,于是每一个Interface当然就得用个编号了,要不然咋区分啊?所有这些描述符里的冬冬都是出厂的时候就固化在设备里边的,而我们这里之所以可以用bInterfaceNumber来赋值,是因为usbcore在为设备初始化的时候就已经做足了这些功课.否则的话,我们真是寸步难行.
总之,us->ifnum就是这样,最终就是等于咱们眼下这个interface的编号.
438到444行就是两句调试语句,打印更多一些描述符信息,包括device描述符和interface描述符.
447行, usb_set_intfdata(),这其实是一个内联函数,她就一行代码,也是定义于include/linux/usb.h中:
    138 static inline void usb_set_intfdata (struct usb_interface *intf, void *data)
    139 {
    140         dev_set_drvdata(&intf->dev, data);
    141 }
  有趣的是,dev_set_drvdata这个函数也是内联函数,也只有一行代码,她定义于include/linux/device.h中:
302 static inline void
    303 dev_set_drvdata (struct device *dev, void *data)
    304 {
    305         dev->driver_data = data;
    306 }
  所以,结合来看,最终做的事情就是让&intf->dev->driver_data=data,即&intf->dev->driver_data=us.
再往下走,就是申请内存了,us->cr和us->iobuf都是指针,这里让它们指向两段内存空间,下面会用得到.需要注意的是usb_buffer_alloc(),这个函数是usbcore提供的,我们只管调用即可.从名字上就能知道它是用来申请内存的,第一个参数就是struct usb_device结构体的指针,所以我们要传递一个pusb_dev,第三个参数,GFP_KERNEL,是一个内存申请的flag,通常内存申请都用这个flag,除非是中断上下文,不能睡眠,那就得用GPF_ATOMIC,这里没那么多要求.第二个参数申请的buffer的大小,对于cr,传递的是sizeof(*us->cr),而对于iobuf,传递的是US_IOBUF_SIZE,这是一个宏,大小是64,是我们自己定义的,来自drivers/usb/storage/usb.h:
     91 /*
     92  * We provide a DMA-mapped I/O buffer for use with small USB transfers.
     93  * It turns out that CB[I] needs a 12-byte buffer and Bulk-only needs a
     94  * 31-byte buffer.  But Freecom needs a 64-byte buffer, so that's the
     95  * size we'll allocate.
     96  */
     97
     98 #define US_IOBUF_SIZE           64      /* Size of the DMA-mapped I/O buffer */
而usb_buffer_alloc()的第四个参数有些意思了,第一次我们传递的是&us->cr_dma,第二次传递的是&us->iobuf_dma,这涉及到dma传输.这两个咚咚此前我们都没有赋过值,相反它们是在这个函数调用之后被赋上值的.cr_dma和iobuf_dma都是dma_addr_t类型的变量,这个数据类型是Linux内核中专门为dma传输而准备的.为了支持dma传输,usb_buffer_alloc不仅仅是申请了地址,并且建立了dma映射,cr_dma和iobuf_dma就是记录着cr和iobuf的dma地址.关于什么是cr,关于这些dma地址究竟有什么用,我们稍候就会遇到,那时候再讲也不迟.现在需要知道的就是usb_buffer_alloc申请的空间分别返回给了cr和iobuf.顺便提一下,用usb_buffer_alloc申请的内存空间需要用它的搭档usb_buffer_free()来释放.
452行和459行,每一次申请完内存就要检查成功与否,这是惯例.驱动程序能否驱动设备,关键就是看能否申请到内存空间,任何一处内存空间申请失败,整个驱动程序就没法正常工作.这就像如今找对象,谈婚姻,总是要看有没有房子.没有房子的话,那么基本上爱情也就没戏.然而现实中要拥有房子比计算机里分配内存却要难上许多,许多.可怜的我们这一代人,当我们不能挣钱的时候,房子是分配的,当我们能挣钱的时候,却发现房子已经买不起了.哭…

整个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 host和usb 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盘基本上不属于这些另类设备,但作为一个有责任心的社会主义新青年,我们有必要为这个文件说两句.
我们打开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这个文件的长度也是慢慢在增长。
 
从两张表得到了我们需要的冬冬,然后下面的代码就是围绕着这两个指针来展开了.(unusual_dev和id)
476行,把unusual_dev给记录在us里边,反正us里边也有这么一个成员.这样记录下来日后要用起来就方便了,因为us是贯穿整个故事的,所以访问他的成员很方便,随时都可以,但是us_unusual_dev_list以及storage_usb_ids这两张表这次之后就不会再用了.因为我们已经得到了我们想要的,所以我们就不用再去骚扰这两个数组了.
477至483行,给us的另外三个成员赋值,subclass,protocol,flags.比如我们的U盘,它属于主流设备,在us_unusual_dev_list列表中能找到它,其subclass是US_SC_SCSI,而protocol是Bulk-only,即这里用宏US_PR_BULK所代表的.(224行和225行.)关于US_SC_DEVICE和US_PR_DEVICE我们之前讲那个三星的数码相机的时候已经看到了,它就表示subclass和protocol得从设备的描述符里边读出来.这样做看起来很滑稽,因为三星完全可以把subclass和protocol在UNUSUAL_DEV中写清楚,何必让我们再去读设备描述符呢.然而,我们可以想象,它这样的好处是定义一个UNUSUAL_DEV可以代表几种设备,即它可以让几个不同subclass的设备共用这么一个宏,或者几个不同protocol的设备共用这么一个宏.能省一点就省一点吧,这里体现了开源社区人们勤俭节约的高尚品德. 需要特别指出的是us->flags,对于U盘来说,它当然没有什么flags需要设定,但是unusual_devs.h中的很多设备都设置了各种flags,稍后在代码中我们会看到,时不时我们就得判断一下是否某个flag设置了,通常是如果设置了,就要多执行某段代码,以满足某种要求.
490至515行,这是一段纯粹的调试代码,对我们理解usb没有任何意义的.这段代码检查unusual_devs.h,看是否这个文件定义了一行没有意义的句子.什么叫没有意义?我们刚才看见了,如果这个设备设了US_SC_DEVICE,那么其subclass将从描述符中读出来,如果不然,则让subclass=unusual_dev->useProtocol,但是如果后者又真的和描述符里读出来的一样,那么这个设备就没有必要把自己的useProtocol定义在unusual_devs.h中了,因为反正也可以从描述符里读出来.还不如和大众一样设为US_SC_DEVICE得了.就比如我们来看下面这行代表一个Sony的Memory Stick产品的代码:
    371 UNUSUAL_DEV(  0x054c, 0x0069, 0x0000, 0x9999,
    372                 "Sony",
    373                 "Memorystick MSC-U03",
    374                 US_SC_UFI, US_PR_CB, NULL,
    375                 US_FL_SINGLE_LUN ),
我们看到其useProtocol这一栏里写了US_SC_UFI,这表明它自称是属于UFI这个subclass的,但是如果我们从它的描述符里边读出来也是这个,那就没有必要注明在这里了,这里直接写成US_SC_DEVICE好了.当然,总的来说这段代码有些傻.写代码的是希望能够更好的管理unusual_devs.h,希望它不要不断的增加,他总希望能够从这个文件里删除一些行,并且即使不能删除一行,也希望每一行都看上去整齐一点,让这个文件看上去更加小巧玲珑,更加精致.而不是无休的增加,不息的扩充.于是我们也只能对其良苦用心多一份理解吧.
518至526行,这里调用了一个来自usb core的函数,usb_string,这个函数的作用是获得一个设备的字符串描述符.咦?怎么跳出来一个叫做字符串描述符的冬冬?之前不是只讲了四种描述符吗?没错,设备描述符,配置描述符,接口描述符,端点描述符,这是每个设备都有的,而还有些描述符是可有可无的,字符串描述符就是这么一种情况,有的设备有,有的设备没有.又比如,hub,它就有一个hub描述符,这当然是一般的设备没有的.那么字符串描述符是干嘛的呢?有些东西模糊一些也未偿不是一件好事,看得太透彻了才知道很残酷.如果你一定要知道的话,举个例子,我的机器里很多usb设备,有一个和lspci类似的命令,可以查看一下,这个命令就是lsusb.你也可以试一下,安装一个软件包usbutils,然后就可以使用这个命令.我们看:
localhost:~/test # lsusb
Bus 004 Device 003: ID 0ea0:1001 Ours Technology, Inc.
Bus 004 Device 002: ID 04b4:6560 Cypress Semiconductor Corp. CY7C65640 USB-2.0 "TetraHub"
Bus 004 Device 001: ID 0000:0000
Bus 003 Device 001: ID 0000:0000
Bus 002 Device 002: ID 0624:0294 Avocent Corp.
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 001: ID 0000:0000
看这个第二行, Cypress Semiconductor Corp., 这么一长串的东西,你说哪来的?是不是应该从设备里来?设备的那几个标准描述符,整个描述符的大小也不一定放得下这么一长串,所以,一些设备专门准备了一些字符串描述符(string descriptor).就用来记这些长串的东西,我们结合刚才的518行开始讲,如果设备描述符里边iManufacturer不为0,那么调用usb_string,这句话具体做了什么?就是根据iManufactuer的值得到公司名字,而iManufactuer的第一个字母i,就表示index,它记录的是真正的公司名字保存在哪一个字符串描述符中,因为字符串描述符可以有多个,那么必然就有个号码来区分,接下来几行,iProduct记录了产品名在第几个字符串描述符中,iSerialNumber记录了产品序列号在第几个字符串描述中,然后调用usb_string这个函数,就把真正的字符串描述符里的冬冬给记录了下来.我们看到,我们三次调用的时候分别传递了us->vendor,us->product,us->serial.这样函数调用结束之后,这三个里面就记录了必要的信息,于是以后我们就可以用了.
得到了us->vendor,us->product,us->serial,那么下面528直到547行就不需要多讲了,就是说如果得到的东西是空的,(得到的是空可以有两种可能,一个是设备根本就没提供这些字符串描述符,另一种情况是usb_string函数没能成功,但是这个函数不成功也无所谓,没影响.)那也没关系,毕竟这些信息我们可有可无,无非是打印出来给客户看看.如果unusual_dev里边有的话,那就拷贝过来,如果也没有,那没办法,设为Unknown.而序列号这个就索性置为None好了,最后US_DEBUGP把这些信息给打印出来,如果你打开了debug开关,那么你会在日志文件里看到这么一句话,在/var/log/messages里边.
至此,get_device_info这个函数就结束了他的使命.在usb storage这部戏里,他将不再出场.但我想说,对于usb storage这整个模块来说,主角配角不重要,每个函数都是画布上的一抹色彩.就像我们每一个人,不也是别人人生中的配角,但总是自己人生的主角吗?

原创粉丝点击