彩世界平台-彩世界时时app-彩世界开奖app苹果下载

热门关键词: 彩世界平台,彩世界时时app,彩世界开奖app苹果下载

您的位置:彩世界平台 > 彩世界开奖app苹果下载 > 《Linux那些事儿之我是USB》我是U盘(16)冬天来了

《Linux那些事儿之我是USB》我是U盘(16)冬天来了

发布时间:2019-09-07 00:36编辑:彩世界开奖app苹果下载浏览(101)

     

     

    看完了get_transport()继续看get_protocol()函数和get_pipes()函数。仍然是来自drivers/usb/storage/usb.c中:

    打开unusual_devs.h吧,之前我们看了它的最后几行,但是如果你仔细看的话会发现最后几行和前面的一些行有着明显的不同。最后几行都是USUAL_DEV的宏,而前面则全是UNUSUAL_DEV的宏,随便看一下,发现每一行就是这么一个宏,毫无疑问它对应一种设备,我们从其中挑一个来看,比如挑一个三星的吧。

     

     

    672 static int get_protocol(struct us_data *us)

    下面这个设备,正是来自三星的一个Flash产品。

     

     

    673 {

    1092 /* Submitted by Hartmut Wahl <[email protected]>*/

     

     

    674   switch (us->subclass) {

    1093 UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001,

     

     

    675    caseUS_SC_RBC:

    1094                "Sa msung",

     

     

    676        us->protocol_name = "Reduced Block Commands (RBC)";

    1095                "Digimax 410",

     

     

    677        us->proto_handler = usb_stor_transparent_scsi_command;

    1096                US_SC_DEVICE, US_PR_DEVICE, NULL,

     

     

    678         break;

    1097                US_FL_FIX_INQUIRY),

     

     

    679

    Digimax 410,熟悉数码照相机的人大概对三星的这款410万像素3倍光学变焦的产品不会陌生,不过数码照相机更新得很快,这款在2002年推出的相机如今当然也算是很一般了,市场上卖的话也就在1500元以下,不过当时刚推出时也是3000元到4000元的。我们来看这一行是什么意思。

     

     

    680   case US_SC_8020:

    UNUSUAL_DEV这个宏的定义以及它所利用的USB_DEVICE_VER的定义我们前面都已经看到了。

     

     

    681         us->protocol_name = "8020i";

    所以这段对三星设备的描述的UNUSUAL_DEV最终出现在storage_usb_ids中的意思就是令match_flags为USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,idVendor为0x0839,idProduct为0x000a,bcdDevice_lo为0x0001,bcdDevice_hi为0x0001。可是你会问了,这里我们看到的这个UNUSUAL_DEV里面有10个参数,可是刚才我们看到的USB_DEVICE_VER却只能处理其中的前几个,后面那些怎么办呢?呵呵,你可曾注意到,在数组storage_usb_ids里面,有如下两行:

     

     

    682         us->proto_handler = usb_stor_ATAPI_command;

    141 #undef UNUSUAL_DEV

     

     

    683         us->max_lun = 0;

    142 #undef USUAL_DEV

     

     

    684         break;

    明明定义了这两个宏,为什么又undef掉呢?事实上,在storage_usb_ids和us_unusual_dev_list这两个数组之间,我们又看到了下面这一段:

     

     

    685

    161 #define UNUSUAL_DEV(idVendor, idProduct,bcdDeviceMin, bcdDeviceMax,

     

     

    686    caseUS_SC_QIC:

    162               vendor_name, product_name,use_protocol, use_transport,

     

     

    687         us->protocol_name = "QIC-157";

    163              init_function, Flags)

     

     

    688       us->proto_handler = usb_stor_qic157_command;

    164 {

     

     

    689        us->max_lun = 0;

    165    .vendorName= vendor_name,    

     

     

    690         break;

    166    .productName= product_name,   

     

     

    691

    167    .useProtocol= use_protocol,   

     

     

    692    caseUS_SC_8070:

    168    .useTransport= use_transport, 

     

     

    693       us->protocol_name = "8070i";

    169    .initFunction= init_function, 

     

     

    694        us->proto_handler = usb_stor_ATAPI_command;

    170 }

     

     

    695      us->max_lun= 0;

    171

     

     

    696        break;

    172 #define USUAL_DEV(use_protocol, use_transport,use_type)

     

     

    697

    173 {

     

     

    698    caseUS_SC_SCSI:

    174   .useProtocol = use_protocol,   

     

     

    699       us->protocol_name = "Transparent SCSI";

    175     .useTransport= use_transport, 

     

     

    700         us->proto_handler = usb_stor_transparent_scsi_command;

    176 }

     

     

    701         break;

    UNUSUAL_DEV和USUAL_DEV竟然被定义了两次。这样对于三星产品来说,这个宏的意思又是令vendorName为“Sa msung”,令productName为“Digimax410”,而useProtocol为US_SC_DEVICE,useTransport为US_PR_DEVICE,initFunction为NULL,flag为US_FL_FIX_INQUIRY。

     

     

    702

    看明白了吗?首先不去管各项的具体含义,至少我们看出来,针对同一个文件,我们使用两次定义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文件给包含了进来。

     

     

    703    caseUS_SC_UFI:

    而我们之所以使用两个数组的原因是,storage_usb_ids是提供给USB Core的,它需要比较驱动和设备从而确定设备是被这个驱动所支持的,我们只需要比较四项就可以了,因为这四项已经足以确定一个设备的厂商、产品、序列号。比较这些就够了,而us_unusual_dev_list这个数组中的元素是我们接下来的代码要用的,比如它用什么协议,它有什么初始化函数,所以我们使用了两个数组。而我们需要注意的是,这两个数组中元素的顺序是一样的,所以我们从storage_usb_ids中得到的id_index用于us_unusual_dev_list也是可以的,表示的还是同一个设备。而这也就是我们刚才在get_device_info()->find_unusual()中看到的。

     

     

    704        us->protocol_name = "Uniform Floppy Interface (UFI)";

    482 static struct us_unusual_dev*find_unusual(const struct usb_device_id *id)

     

     

    705         us->proto_handler = usb_stor_ufi_command;

    483 {

     

     

    706        break;

    484   const int id_index = id -storage_usb_ids;

     

     

    707

    485     return&us_unusual_dev_list[id_index];

     

     

    708 #ifdef CONFIG_USB_STORAGE_ISD200

    486 }

     

     

    709   case US_SC_ISD200:

    看得出来,id_index可以脚踏两只船,在storage_usb_ids和us_unusual_dev_list之间游刃有余。而find_unusual()这个函数的真实作用就是返回一个us_unusual_dev的指针。

     

     

    710        us->protocol_name = "ISD200 ATA/ATAPI";

    494    structus_unusual_dev *unusual_dev = find_unusual(id);

     

     

    711         us->proto_handler = isd200_ata_command;

    这个指针之后就将被用到。

     

     

    712        break;

    最后具体解释一下这行为三星这款数码相机写的语句。

     

     

    713 #endif

    (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就意味着这个编号是二进制的格式。

     

     

    714

    (2).vendorName和productName为“Sa msung”和“Digimax410”。

     

     

    715   default:

    (3).useProtocol为US_SC_DEVICE,useTransport为US_PR_DEVICE,这种情况就说明对于这种设备,它属于什么SubClass,它使用什么通信协议,得从设备描述符里面去读取,它都写在那里面了。一会儿会看到我们的代码中会如何判断这个的。

     

     

    716        return -EIO;

    (4).initFunction等于NULL,这个很有意义的,这个函数就是设备的初始化函数,一般的设备都不需要这个函数,但是有些设备偏要标新立异,它就告诉你,要用我的设备必须先做一些初始化,于是它提供了一个函数,initFunction,当然这是一个函数指针,这里如果不为NULL的话,到时候就会被调用,以后我们会看到代码中对这个指针进行了判断。如果为空不理睬,否则就会执行。比如我们看下面两款设备,它们就分别提供了一个叫做usb_stor_sddr09_init()和usb_stor_sddr09_dpcm_init()的初始化函数,

     

     

    717    }

    422 #ifdef CONFIG_USB_STORAGE_SDDR09

     

     

    718     US_DEBUGP("Protocol:%sn", us->protocol_name);

    423 UNUSUAL_DEV(  0x04e6, 0x0003, 0x0000, 0x9999,

     

     

    719    return 0;

    424                "Sandisk",

     

     

    720 }

    425                "ImageMate SDDR09",

     

     

    这段代码非常浅显易懂。根据us->subclass来判断。对于U盘来说,spec里面规定了,它的SubClass是US_SC_SCSI,所以这里就是两句赋值语句:一个是令us的protocol_name为“Transparent SCSI”,另一个是令us的proto_handler为usb_stor_transparent_scsi_command,后者又是一个函数指针。

    426                US_SC_SCSI, US_PR_EUSB_SDDR09, usb_stor_sddr09_init,

     

     

    然后是get_pipes(),来自drivers/usb/storage/usb.c:

    427                0),

     

     

    723 static int get_pipes(struct us_data *us)

    428

     

     

    724 {

    429 /* This entry is from [email protected]*/

     

     

    725    structusb_host_interface *altsetting =

    430 UNUSUAL_DEV(  0x04e6, 0x0005, 0x0100, 0x0208,

     

     

    726                us->pusb_intf->cur_altsetting;

    431                "SCM Microsyste ms",

     

     

    727    int i;

    432                "eUSB SmartMedia / CompactFlash Adapter",

     

     

    728   struct usb_endpoint_descriptor*ep;

    433                US_SC_SCSI, US_PR_DPCM_USB, usb_stor_sddr09_dpcm_init,

     

     

    729   struct usb_endpoint_descriptor*ep_in = NULL;

    434                0),

     

     

    730   struct usb_endpoint_descriptor*ep_out = NULL;

    435 #endif

     

     

    731    structusb_endpoint_descriptor *ep_int = NULL;

    (5)flag等于US_FL_FIX_INQUIRY,这个flag可以设为很多值,它的存在本身就表示这个设备有一些与众不同,因为一般的设备是不用这个flag的,有这个flag就表明这个设备可能在某些地方需要进行特殊的处理,所以今后在代码中我们会看到突然跳出一句,判断us->flag等于某个数值,如果等于,就执行一些代码;如果不等于,那就不做任何事情。这个flag的存在也使得我们可以方便处理一些设备的Bug,比如正常的设备你问它:“吃了吗?”它就回答:“吃了”。可是不正常的设备可能就会根本不回答,或者回答:“北京房价真高!”于是对于这种设备,可能我们就需要一些专门的代码来对付。具体到这个US_FL_FIX_INQUIRY,这个flag这么一设置,就表明这个设备在接收到INQUIRY命令时会有一些异常的特征,所以以后我们会在代码里看到我们是如何处理它的。设置了这个flag的当然不止是三星的这款相机,别的设备也有可能设置的。

     

     

    732

    (6)既然明白了unusual_devs.h的作用,那么要做的是很显然的一件事情,如果一个厂家推出了一个新的设备,它有一些新的特征,而目前的设备驱动不足以完全支持它,那么厂家首先需要做的事情就是在unusual_devs.h中添加一个UNUSUAL_DEV来定义自己的设备,然后再看是否需要给内核打补丁以及如何打。因此这几年unusual_devs.h这个文件的长度也是慢慢在增长。

     

    ...

    733    /*

     

    734    * Find the first endpoint of each type we need.

     

    735     * We are expecting a minimum of 2endpoints - in and out (bulk).

     

    736     * An optional interrupt-in is OK(necessary for CBI protocol).

     

    737    * We will ignore any others.

     

    738    */

     

    739  for (i = 0; i <altsetting->desc.bNumEndpoints; i++) {

     

    740        ep = &altsetting->endpoint[i].desc;

     

    741

     

    742         if (usb_endpoint_xfer_bulk(ep)) {

     

    743             if (usb_endpoint_dir_in(ep)) {

     

    744                 if (!ep_in)

     

    745                    ep_in = ep;

     

    746             } else {

     

    747                  if (!ep_out)

     

    748                      ep_out = ep;

     

    749              }

     

    750       }

     

    751

     

    752        else if (usb_endpoint_is_int_in(ep)) {

     

    753           if (!ep_int)

     

    754                ep_int = ep;

     

    755        }

     

    756   }

     

    757

    本文由彩世界平台发布于彩世界开奖app苹果下载,转载请注明出处:《Linux那些事儿之我是USB》我是U盘(16)冬天来了

    关键词: