《Linux那些事儿之我是USB》我是U盘(18)冬天来了,春天还会远吗?(四)
结束了get_device_info,我们继续沿着storage_probe一步一步地走下去。继续,这就是我们前面提到过的三个函数,get_transport、get_protocol和get_pipes。一旦结束了这三个函数,我们就将进入本故事的高潮部分。而在这之前,我们只能一个一个地来看。好在这几个函数虽然不短,但是真正有用的信息只有一点,所以可以很快看完。
993 /* Get the transport, protocol,and pipe settings */
994 result = get_transport(us);
995 if(result)
996 goto BadDevice;
997 result =get_protocol(us);
998 if(result)
999 goto BadDevice;
1000 result = get_pipes(us);
1001 if(result)
1002 goto BadDevice;
第1个,get_transport(us)。
557 static int get_transport(struct us_data *us)
558 {
559 switch(us->protocol) {
560 caseUS_PR_CB:
561 us->transport_name = "Control/Bulk";
562 us->transport = usb_stor_CB_transport;
563 us->transport_reset = usb_stor_CB_reset;
564 us->max_lun = 7;
565 break;
566
567 case US_PR_CBI:
568 us->transport_name ="Control/Bulk/Interrupt";
569 us->transport = usb_stor_CBI_transport;
570 us->transport_reset = usb_stor_CB_reset;
571 us->max_lun = 7;
572 break;
573
574 case US_PR_BULK:
575 us->transport_name = "Bulk";
576 us->transport = usb_stor_Bulk_transport;
577 us->transport_reset = usb_stor_Bulk_reset;
578 break;
579
580 #ifdef CONFIG_USB_STORAGE_USBAT
581 caseUS_PR_USBAT:
582 us->transport_name = "Shuttle USBAT";
583 us->transport = usbat_transport;
584 us->transport_reset = usb_stor_CB_reset;
585 us->max_lun = 1;
586 break;
587 #endif
588
589 #ifdef CONFIG_USB_STORAGE_SDDR09
590 caseUS_PR_EUSB_SDDR09:
591 us->transport_name ="EUSB/SDDR09";
592 us->transport = sddr09_transport;
593 us->transport_reset = usb_stor_CB_reset;
594 us->max_lun = 0;
595 break;
596 #endif
597
598 #ifdef CONFIG_USB_STORAGE_SDDR55
599 case US_PR_SDDR55:
600 us->transport_name = "SDDR55";
601 us->transport = sddr55_transport;
602 us->transport_reset = sddr55_reset;
603 us->max_lun = 0;
604 break;
605 #endif
606
607 #ifdef CONFIG_USB_STORAGE_DPCM
608 caseUS_PR_DPCM_USB:
609 us->transport_name ="Control/Bulk-EUSB/SDDR09";
610 us->transport = dpcm_transport;
611 us->transport_reset= usb_stor_CB_reset;
612 us->max_lun = 1;
613 break;
614 #endif
615
616 #ifdef CONFIG_USB_STORAGE_FREECOM
617 case US_PR_FREECOM:
618 us->transport_name = "Freecom";
619 us->transport = freecom_transport;
620 us->transport_reset =usb_stor_freecom_reset;
621 us->max_lun = 0;
622 break;
623 #endif
624
625 #ifdef CONFIG_USB_STORAGE_DATAFAB
626 case US_PR_DATAFAB:
627 us->transport_name ="Datafab Bulk-Only";
628 us->transport = datafab_transport;
629 us->transport_reset = usb_stor_Bulk_reset;
630 us->max_lun = 1;
631 break;
632 #endif
633
634 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
635 case US_PR_JUMPSHOT:
636 us->transport_name ="Lexar Jumpshot Control/Bulk";
637 us->transport = jumpshot_transport;
638 us->transport_reset = usb_stor_Bulk_reset;
639 us->max_lun = 1;
640 break;
641 #endif
642
643 #ifdef CONFIG_USB_STORAGE_ALAUDA
644 case US_PR_ALAUDA:
645 us->transport_name = "Alauda Control/Bulk";
646 us->transport = alauda_transport;
647 us->transport_reset = usb_stor_Bulk_reset;
648 us->max_lun = 1;
649 break;
650 #endif
651
652 #ifdef CONFIG_USB_STORAGE_KARMA
653 caseUS_PR_KARMA:
654 us->transport_name = "Rio Karma/Bulk";
655 us->transport = rio_karma_transport;
656 us->transport_reset = usb_stor_Bulk_reset;
657 break;
658 #endif
659
660 default:
661 return -EIO;
662 }
663 US_DEBUGP("Transport:%s\n", us->transport_name);
664
665 /* fix for single-lun devices */
666 if(us->flags & US_FL_SINGLE_LUN)
667 us->max_lun = 0;
668 return 0;
669 }
乍一看,这么长一段,不过明眼人一看就知道了,主要就是一个switch,选择语句,语法上来说很简单,所以我们看懂这段代码不难。只是,我想说的是,虽然这里做出一个选择不难,但是不同选择就意味着后来整个故事会有千差万别的结局,当鸟儿选择在两翼上系上黄金,就意味着它放弃展翅高飞;选择云天搏击,就意味着放弃身外的负累。
所以,此处,我们需要仔细地看清楚我们究竟选择了怎样一条路。很显然,前面我们已经说过,对于U盘,spec规定了,它就属于Bulk-only的传输方式,即它的us->protocol就是US_PR_BULK。这是我们刚刚在get_device_info中确定下来的。于是,在整个switch段落中,我们所执行的只是US_PR_BULK这一段,即us的transport_name被赋值为“Bulk”,transport被赋值为usb_stor_Bulk_transport,transport_reset被赋值为usb_stor_Bulk_reset。其中我们最需要记住的是,us的成员transport和transport_reset是两个函数指针。程序员们把这个称作“钩子”。这两个赋值我们需要牢记,日后我们一定会用到它们,因为这正是我们真正的数据传输时调用的东西。关于usb_stor_Bulk_*的这两个函数,到时候调用了再来看。现在只需知道,日后我们一定会回过来看这个赋值的。
580行到658行,不用多说了,这里全是与各种特定产品相关的一些编译开关,它们有一些自己定义一些传输函数,有些则共用通用的函数。
666行,判断us->flags,还记得我们在讲unusual_devs.h文件时说的flags吧,这里第一次用上了。有些设备设置了US_FL_SINGLE_LUN这个flag,就表明它是只有一个LUN的。像这样的设备挺多的,随便从unusual_devs.h中抓一个出来:
596 UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100,
597 "Sony",
598 "Memorystick MSAC-US1",
599 US_SC_DEVICE, US_PR_DEVICE, NULL,
600 US_FL_SINGLE_LUN ),
比如这个Sony的Memorystick。中文名叫“记忆棒”,大小就与口香糖一样,也是一种存储芯片。它是Sony公司推出的,广泛用于Sony的各种数码产品中,比如数码照相机、数码摄影机。
LUN就是Logical Unit Number。通常在谈到SCSI设备时不可避免要说起LUN。关于LUN,曾几何时,一位来自Novell的参与开发Linux内核中USB子系统的工程师这样对我说,一个LUN就是设备中的一个驱动。下面举例来说一下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协议规定的。在drivers/usb/storage/transport.c中定义了一个usb_stor_Bulk_max_lun()函数,它将负责获取这个max lun。而我依然要声明一次,这个函数对我们U盘没有什么意义,这个值肯定是0,所以这个函数咱们就不去理睬了。
至此,get_transport()也结束了,和get_device_info()一样。我们目前所看到的这些函数都不得不面对现实,对它们来说,凋谢是最终的结果,盛开只是一个过程。而对我们来说,要到达终点,那么和这些函数狭路相逢,终不能幸免。然而,不管这部分代码有多么重要,也不过是我们整个长途旅程中,来去匆匆的转机站,无论停留多久,始终要离去坐另一班机。
《Linux那些事儿之我是USB》我是U盘(18)冬天来了,春天还会远吗?(四)相关推荐
- 【转】Linux那些事儿 之 戏说USB(21)向左走,向右走
他们彼此深信,是瞬间迸发的热情,让他们相遇: 这样的确定是美丽的,但变幻无常更为美丽: 他们素未谋面,所以他们确定,彼此并无任何瓜葛, 但是自街道.楼梯.大堂传来的话语, 他们也许擦肩而过一百万次了吧 ...
- Linux那些事儿 之 戏说USB(19)设备
转载地址:http://blog.csdn.net/fudan_abc/article/details/1807800 第一眼看到struct usb_device这个结构,我仿佛置身于衡山路的酒吧里 ...
- 【转】Linux那些事儿 之 戏说USB(19)设备
第一眼看到struct usb_device这个结构,我仿佛置身于衡山路的酒吧里,盯着舞池里扭动的符号,眼神迷离. 交大里苟了几年,毕业了又是住在学校附近的徐虹北路上,沿着虹桥路走过去,到徐家汇不过1 ...
- Linux那些事儿 之 戏说USB(5)我是谁
我是谁?USB一遍一遍问着自己,当然它不会真的是一颗树.USB只是Linux庞大家族里的一个小部落,host controller是它们的族长,族里的每个USB设备都需要被系统识别,被我们识别.虽然清 ...
- 《Linux那些事儿之我是USB》我是U盘(15)冬天来了,春天还会远吗?(一)
在整个usb-storage模块的代码中,其最灵魂的部分在一个叫做usb_stor_control_thread()的函数中,而那也自然是我们整个故事的高潮.这个函数的调用有一些特殊,是从usb_st ...
- Linux那些事儿 之 戏说USB(3)我是一棵树
从拓扑上来看,USB子系统并不以总线的方式来部署,它是一颗由几个点对点的连接构成的树. 它主要包括了USB连接.USB host controller和USB device三个部分.而USB devi ...
- Linux那些事儿 之 戏说USB(33)字符串描述符
关于字符串描述符,前面的前面已经简单描述过了,地位仅次于设备/配置/接口/端点四大描述符,那四大设备必须得支持,而字符串描述符对设备来说则是可选的. 这并不是就说字符串描述符不重要,对咱们来说,字符串 ...
- Linux那些事儿 之 戏说USB(25)设备的生命线(八)
回到struct usb_hcd,继续努力的往下看. 7行,又见kref,usb主机控制器的引用计数.struct usb_hcd也有自己专用的引用计数函数,看drivers/usb/core/hcd ...
- Linux那些事儿 之 戏说USB(22)设备的生命线(五)
下面接着看那三个基本点. 第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/core/urb.c里定义. struct ur ...
最新文章
- nonatomic,assign,copy,retain的区别
- 亚马逊查询关键词排名的工具_查询关键词排名收录的作用与操作
- 物理搬砖问题_搬砖姿势:风法
- 任正非:鸿蒙最快1年可媲美iOS;首例Apple Card用户遭盗刷;Firefox 69.0.3 发布 | 极客头条...
- [实战]MVC5+EF6+MySql企业网盘实战(24)——视频列表
- linux 搭建cloudreve win映射网络驱动器WebDav
- SQL十进制和十六进制相互转换
- 扫雷小游戏-纯网页版
- php简单的日历代码,php日历代码(附演示效果)
- Android 滑动放大,Android多点触控实现对图片放大缩小平移,惯性滑动等功能
- office365彻底卸载教程
- win10锁屏壁纸文件夹位置
- 2021-02-02美赛前MATLAB的学习笔记(机器学习(分类、聚类、深度学习))
- 加密一条保序的数据流
- 网络图片缩略图查看工具
- 《机电传动控制》——直流电机调速仿真作业
- 从iOS 11看怎样设计APP图标
- oracle exp导出很慢,oracleexp导出慢
- 入门CG板绘须知:学插画需要学好素描吗?
- iOS 开发,工程中混合使用 ARC 和非ARC