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

来源:互联网 发布:数据分析界面 编辑:程序博客网 时间:2024/04/20 08:51

结束了get_device_info,我们继续沿着storage_probe一步一步走下去.为了保持原汁原味,我们贴代码的原则是一个函数的每一行都贴出来.get_device_info962,我们已经贴过,所以下面从963行开始了.

    963

    964 #ifdef CONFIG_USB_STORAGE_SDDR09

    965         if (us->protocol == US_PR_EUSB_SDDR09 ||

    966                         us->protocol == US_PR_DPCM_USB) {

    967                 /* set the configuration -- STALL is an acceptable response here */

    968                 if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) {

    969                         US_DEBUGP("active config #%d != 1 ??/n", us->pusb_dev

    970                                 ->actconfig->desc.bConfigurationValue);

    971                         goto BadDevice;

    972                 }

    973                 result = usb_reset_configuration(us->pusb_dev);

    974

    975                 US_DEBUGP("Result of usb_reset_configuration is %d/n", result);

    976                 if (result == -EPIPE) {

    977                         US_DEBUGP("-- stall on control interface/n");

    978                 } else if (result != 0) {

    979                         /* it's not a stall, but another error -- time to bail */

    980                         US_DEBUGP("-- Unknown error.  Rejecting device/n");

    981                         goto BadDevice;

    982                 }

    983         }

    984 #endif

看到这段代码,我笑了.因为#ifdef CONFIG_USB_STORAGE_SDDR09说明这段代码跟我们无关.关于这些编译选项我们前面已然提过,第六感告诉我们这个选项是针对某种特殊产品的,对于这种特殊的产品,它在某些方面有它自己的要求,所以它会有它特殊的代码.具体到这个选项,我们看一下drivers/usb/storage/Kconfig文件,这个文件里边介绍了该目录下每一个编译选项的作用.

     99 config USB_STORAGE_SDDR09

    100         bool "SanDisk SDDR-09 (and other SmartMedia) support (EXPERIMENTAL)"

    101         depends on USB_STORAGE && EXPERIMENTAL

    102         help

    103           Say Y here to include additional code to support the Sandisk SDDR-09

    104           SmartMedia reader in the USB Mass Storage driver.

    105           Also works for the Microtech Zio! SmartMedia reader.

可以看到,如果要支持Sandisk SDDR-09 SmartMedia的读卡器,那你就打开这个编译选项吧.Sandisk是公司名,玩数码的人对这家公司不会陌生,中文名叫晟碟,这是一家全球最大的闪存数据存储产品供应商.SmartMedia(简称SM)卡通常用于数码相机中,也曾一度被用于MP3,它也是一种flash memory存储卡.不过如今市面上很少有SM卡了,因为其兼容性不好.眼下用得比较多的应该是CF(Compact Flash).而读卡器就是用来把卡里边的数据读出来,使用USB接口,从原理上来看和U盘也是差不多. (顺便介绍一下,U盘和存储卡的区别吧,我们所讲的U盘,就是可以直接读写的存储器,而存储卡需要外部设备才能进行访问,如手机的闪存卡,数码相机的闪存卡等就只是一张卡,电脑不能直接对其进行访问,这就需要一种叫"读卡器"的外部设备进行识别,存储卡有多种,XDCFSDSM等等,有些读卡器具有"多合一"的功能,可以对不同的闪存卡进行读写.而我们这段代码里以及接下来的代码中每一个条件编译开关显然对应的是一种读卡器.她们属于不同的厂商的不同的产品.)

继续,这就是我们前面提到过的三个函数.get_transport,get_protocol,get_pipes.一旦结束了这三个函数,我们就将进入本故事的高潮部分.而在这之前,我们只能一个一个来看.好在这几个函数虽然不短,但是真正有用的信息只有一点点,所以可以很快的看完.

    985

    986         /* Get the transport, protocol, and pipe settings */

    987         result = get_transport(us);

    988         if (result)

    989                 goto BadDevice;

    990         result = get_protocol(us);

    991         if (result)

    992                 goto BadDevice;

    993         result = get_pipes(us);

    994         if (result)

    995                 goto BadDevice;

第一个,get_transport(us),

    549 /* Get the transport settings */

    550 static int get_transport(struct us_data *us)

    551 {

    552         switch (us->protocol) {

    553         case US_PR_CB:

    554                 us->transport_name = "Control/Bulk";

    555                 us->transport = usb_stor_CB_transport;

    556                 us->transport_reset = usb_stor_CB_reset;

    557                 us->max_lun = 7;

    558                 break;

    559

    560         case US_PR_CBI:

    561                 us->transport_name = "Control/Bulk/Interrupt";

    562                 us->transport = usb_stor_CBI_transport;

    563                 us->transport_reset = usb_stor_CB_reset;

    564                 us->max_lun = 7;

    565                 break;

    566

    567         case US_PR_BULK:

    568                 us->transport_name = "Bulk";

    569                 us->transport = usb_stor_Bulk_transport;

    570                 us->transport_reset = usb_stor_Bulk_reset;

    571                 break;

    572

    573 #ifdef CONFIG_USB_STORAGE_HP8200e

    574         case US_PR_SCM_ATAPI:

    575                 us->transport_name = "SCM/ATAPI";

    576                 us->transport = hp8200e_transport;

    577                 us->transport_reset = usb_stor_CB_reset;

    578                 us->max_lun = 1;

    579                 break;

    580 #endif

    581

    582 #ifdef CONFIG_USB_STORAGE_SDDR09

    583         case US_PR_EUSB_SDDR09:

    584                 us->transport_name = "EUSB/SDDR09";

    585                 us->transport = sddr09_transport;

    586                 us->transport_reset = usb_stor_CB_reset;

587                 us->max_lun = 0;

    588                 break;

    589 #endif

    590

    591 #ifdef CONFIG_USB_STORAGE_SDDR55

    592         case US_PR_SDDR55:

    593                 us->transport_name = "SDDR55";

    594                 us->transport = sddr55_transport;

    595                 us->transport_reset = sddr55_reset;

    596                 us->max_lun = 0;

    597                 break;

    598 #endif

    599

    600 #ifdef CONFIG_USB_STORAGE_DPCM

    601         case US_PR_DPCM_USB:

    602                 us->transport_name = "Control/Bulk-EUSB/SDDR09";

    603                 us->transport = dpcm_transport;

    604                 us->transport_reset = usb_stor_CB_reset;

    605                 us->max_lun = 1;

    606                 break;

    607 #endif

    608

    609 #ifdef CONFIG_USB_STORAGE_FREECOM

    610         case US_PR_FREECOM:

    611                 us->transport_name = "Freecom";

    612                 us->transport = freecom_transport;

    613                 us->transport_reset = usb_stor_freecom_reset;

    614                 us->max_lun = 0;

    615                 break;

    616 #endif

    617

    618 #ifdef CONFIG_USB_STORAGE_DATAFAB

    619         case US_PR_DATAFAB:

    620                 us->transport_name  = "Datafab Bulk-Only";

    621                 us->transport = datafab_transport;

    622                 us->transport_reset = usb_stor_Bulk_reset;

    623                 us->max_lun = 1;

    624                 break;

    625 #endif

    626

627 #ifdef CONFIG_USB_STORAGE_JUMPSHOT

    628         case US_PR_JUMPSHOT:

    629                 us->transport_name  = "Lexar Jumpshot Control/Bulk";

    630                 us->transport = jumpshot_transport;

    631                 us->transport_reset = usb_stor_Bulk_reset;

    632                 us->max_lun = 1;

    633                 break;

    634 #endif

    635

    636         default:

    637                 return -EIO;

    638         }

    639         US_DEBUGP("Transport: %s/n", us->transport_name);

    640

    641         /* fix for single-lun devices */

    642         if (us->flags & US_FL_SINGLE_LUN)

    643                 us->max_lun = 0;

    644         return 0;

645 }

咋一看,这么长一段,用长沙话讲,这叫非洲老头子跳高()老子一跳.(长沙话一个音)不过明眼人一看,就知道了,主要就是一个switch,选择语句,语法上来说很简单,谭浩强大哥的书里边介绍的很清楚.所以我们看懂这段代码不难,只是,我想说的是,虽然这里做出一个选择不难,但是不同选择就意味着后来整个故事会有千差万别的结局,当鸟儿选择在两翼上系上黄金,就意味着它放弃展翅高飞;选择云天搏击,就意味着放弃身外的负累.所以,此处,我们需要仔细的看清楚我们究竟选择了怎样一条路.很显然,前面我们已经说过,对于U,spec规定了,它就属于Bulk-only的传输方式,即它的us->protocol就是US_PR_BULK.这是我们刚刚在get_device_info中确定下来的.于是,在整个switch段落中,我们所执行的只是US_PR_BULK这一段,,

ustransport_name被赋值为”Bulk”,transport被赋值为usb_stor_Bulk_transport,transport_reset被赋值为usb_stor_Bulk_reset.其中我们最需要记住的是,us的成员transporttransport_reset是两个函数指针.程序员们把这个称作钩子.这两个赋值我们需要牢记,日后我们定会用到它们的,因为这正是我们真正的数据传输的时候调用的冬冬.关于usb_stor_Bulk_*的这两个函数,咱们到时候调用了再来看.现在只需知道,日后我们一定会回过来看这个赋值的.

573行到634,不用多说了,这里就全是与各种特定产品相关的一些编译开关,它们有些自己定义一些传输函数,有些则共用那些通用的函数.

641,判断us->flags,还记得我们在讲unusual_devs.h文件的时候说的那个flags,这里第一次用上了.有些设备设置了US_FL_SINGLE_LUN这么一个flag,就表明它是只有一个LUN.像这样的设备挺多的,随便从unusual_devs.h中抓一个出来:

    338 UNUSUAL_DEV(  0x054c, 0x002d, 0x0100, 0x0100,

    339                 "Sony",

    340                 "Memorystick MSAC-US1",

    341                 US_SC_DEVICE, US_PR_DEVICE, NULL,

    342                 US_FL_SINGLE_LUN ),

比如这个SonyMemorystick.中文名叫记忆棒,大小就跟箭牌口香糖似的,也是一种存储芯片,Sony公司推出的,广泛用于Sony的各种数码产品中.比如数码相机,数码摄影机.

有人问了,啥是LUN?logical unit number.通常在谈到scsi设备的时候不可避免的要说起LUN.关于LUN,曾几何时,一位来自Novell(SUSE)的参与开发Linux内核中usb子系统的工程师这样对我说,一个lun就是一个device中的一个drive.换言之,usb中引入lun的目的在于,举例来说,有些读卡器可以有多个插槽,比如就是两个,其中一个支持CF,另一个支持SD,那么这种情况要区分这两个插槽里的冬冬,就得引入lun这么一个词.这叫逻辑单元.很显然,U盘这样简单的设备其LUN必然是一个.有时候,人们常把U盘中一个分区当作一个LUN,这样说可能对小学三年级以下的朋友是可以接受的,但是作为一个成年人,不应该这么理解.

知道了LUN以后,自然就可以知道US_FL_SINGLE_LUN是干嘛了,这个flag的意义很明显,直截了当的告诉你,我这个设备只有一个LUN,它不支持多个LUN.max_lun又是什么意思?us中的成员max_lun等于一个设备所支持的最大的lun.即如果一个设备支持四个LUNs,那么这四个LUN的编号就是0,1,2,3,max_lun就是3.如果一个设备不用支持多个LUN,那么它的max_lun就是0.所以这里max_lun就是设为了0.

另外一个需要注意的地方是,比较一下各个case语句,发现, US_PR_BULK和别的case不一样,别的case下面都设置了us->max_lun,而对应于Bulk-Only协议的这个case,它没有设置us->max_lun,这是为何?别急,后来我们会专门有一个函数去读取这个值的,之所以不设,是因为这个值由设备说了算,必须向设备查询,这是Bulk-Only协议规定的.所以我们之后会遇见usb_stor_Bulk_max_lun()函数,它将负责获取这个max lun.而我依然要声明一次,这个函数对我们U盘是没啥意义的,咱们这个值肯定是0.

至此,get_transport()也结束了,get_device_info一样.我们目前所看到的这些函数都不得不面对现实,对它们来说,凋谢是最终的结果,盛开只是一个过程...而对我们来说,要到达终点,那么和这些函数狭路相逢,终不能幸免.然而,不管这部分代码有多么重要,也不过是我们整个长途旅程中,来去匆匆的转机站,无论停留多久,始终要离去坐另一班机. 

原创粉丝点击