《Linux那些事儿之我是USB》我是U盘(15)冬天来了,春天还会远吗?(一)
在整个usb-storage模块的代码中,其最灵魂的部分在一个叫做usb_stor_control_thread()的函数中,而那也自然是我们整个故事的高潮。这个函数的调用有一些特殊,是从usb_stor_acquire_resources()函数进入的,而后者我们即将遇到,它在整部戏中只出现过一次,即storage_probe中,行号为1005的地方。
然而在此之前,有四个函数挡在我们面前,它们就是get_device_info,get_transport,get_protocol,get_pipes。如我前面所说,两个人要走到一起,首先要了解彼此,这四个函数就是让驱动去认识设备的。这一点我们从名字上也能看出来。驱动需要知道设备的名字,所以有了get_device_info,驱动需要知道设备是哪一种类型,写代码的人把这些工作分配给了get_transport,get_protocol和get_pipes。
实际上,这四个函数,加上之前刚说过的associate_dev()函数,是整个故事中最平淡最枯燥的部分,第一次读这部分代码总让人困惑,怎么没看见一点USB数据通信?完全没有看到USB主机和USB设备是如何在交流的,这是USB吗?这几个函数应该说是给后面做铺垫,红花总要有绿叶配,没有这段代码的铺垫,到了后面USB设备恐怕也无法正常工作吧。不过,一个好消息是,这几个函数我们只会遇见这一次,它们在整个故事中就这么一次露脸的机会,像我们每个人的青春,只有一次,无法回头。所以,让我们享受这段平淡无奇的代码吧。
get_device_info,这个函数定义于drivers/usb/storage/usb.c中:
488 /* Get the unusual_devs entries and the stringdescriptors */
489 static int get_device_info(struct us_data *us,const struct usb_device_id *id)
490 {
491 struct usb_device *dev =us->pusb_dev;
492 structusb_interface_descriptor *idesc =
493 &us->pusb_intf->cur_altsetting->desc;
494 struct us_unusual_dev *unusual_dev= find_unusual(id);
495
496 /*Store the entries */
497 us->unusual_dev= unusual_dev;
498 us->subclass= (unusual_dev->useProtocol == US_SC_DEVICE) ?
499idesc->bInterfaceSubClass:
500unusual_dev->useProtocol;
501 us->protocol= (unusual_dev->useTransport == US_PR_DEVICE) ?
502idesc->bInterfaceProtocol :
503unusual_dev->useTransport;
504 us->flags =USB_US_ORIG_FLAGS(id->driver_info);
505
506 if(us->flags & US_FL_IGNORE_DEVICE) {
507 printk(KERN_INFO USB_STORAGE "deviceignored\n");
508 return -ENODEV;
509 }
510
511 /*
512 * This flag is onlyneeded when we're in high-speed, so let's
513 * disable it if we're in full-speed
514 */
515 if(dev->speed != USB_SPEED_HIGH)
516 us->flags&= ~US_FL_GO_SLOW;
517
518 /* Log a message if a non-genericunusual_dev entry contains an
519 * unnecessary subclass or protocol override. This may stimulate
520 * reports from users that will help usremove unneeded entries
521 * from the unusual_devs.h table.
522 */
523 if(id->idVendor || id->idProduct) {
524 static const char * msgs[3] = {
525"an unneeded SubClass entry",
526"an unneeded Protocol entry",
527"unneeded SubClass and Protocol entries"};
528 struct usb_device_descriptor *ddesc =&dev->descriptor;
529 int msg = -1;
530
531 if (unusual_dev->useProtocol != US_SC_DEVICE &&
532us->subclass == idesc->bInterfaceSubClass)
533 msg += 1;
534 if(unusual_dev->useTransport != US_PR_DEVICE &&
535us->protocol == idesc->bInterfaceProtocol)
536 msg += 2;
537 if ( msg >= 0 && !(us->flags& US_FL_NEED_OVERRIDE))
538 printk(KERN_NOTICE USB_STORAGE"This device "
539 "(%04x,%04x,%04x S %02x P%02x)"
540 " has %s in unusual_devs.h(kernel"
541 " %s)\n"
542 " Please send a copy of this message to "
543 "<linux-usb-devel@lists.sourceforge.net>\n",
544 le16_to_cpu(ddesc->idVendor),
545 le16_to_cpu(ddesc->idProduct),
546 le16_to_cpu(ddesc->bcdDevice),
547 idesc->bInterfaceSubClass,
548 idesc->bInterfaceProtocol,
549 msgs[ msg],
550 utsname()->release);
551 }
552
553 return0;
554 }
492行,struct usb_interface_descriptor *idesc,这个也无需再说,在之前的associate_dev函数中已经介绍过这个结构体,而且整个故事就是针对一个接口的,一个接口就对应一个接口描述符。
494行,struct us_unusual_dev,这个结构体是第一次出现,它定义于drivers/usb/storage/usb.h中:
61 struct us_unusual_dev {
62 constchar* vendorName;
63 const char*productName;
64 __u8 useProtocol;
65 __u8 useTransport;
66 int(*initFunction)(struct us_data *);
67 };
而“=”右边的find_unusual()函数定义于drivers/usb/storage/usb.c中:
482 static struct us_unusual_dev*find_unusual(const struct usb_device_id *id)
483 {
484 const int id_index = id - storage_usb_ids;
485 return&us_unusual_dev_list[id_index];
486 }
us_unusual_dev_list是一个数组,定义于drivers/usb/storage/usb.c:
178 static struct us_unusual_devus_unusual_dev_list[] = {
179 # include "unusual_devs.h"
180 # undef UNUSUAL_DEV
181 # undef USUAL_DEV
182
183 /* Terminating entry */
184 {NULL }
185 };
Linux代码中有很多奇怪的地方,可是像us_unusual_dev_list这个数组这么奇怪还真没见过。为了了解这个数组以及find_unusual()函数,我们先来看一看这个storage_usb_ids。它不是别人,正是我们曾经赋给usb_storage_driver的成员id_table的值。忘记了id_table的可以回去看。它实际上就是一张表格,告诉全世界driver支持怎样的一些设备。storage_usb_ids同样来自drivers/usb/storage/usb.c中:
138 static struct usb_device_id storage_usb_ids []= {
139
140 # include"unusual_devs.h"
141 #undef UNUSUAL_DEV
142 #undef USUAL_DEV
143 /*Terminating entry */
144 { }
145 };
这么一看,us_unusual_dev_list和storage_usb_ids俨然是双胞胎啊!唯一的区别只是前者多了一个NULL。这里最莫名其妙的就是包含了一个文件,于是让我们先来查看这个unusual_devs.h文件到底是干什么的?先看一下这个文件最下面的一些行:
1476 /* Control/Bulk transport for all SubClassvalues */
1477 USUAL_DEV(US_SC_RBC, US_PR_CB,USB_US_TYPE_STOR),
1478 USUAL_DEV(US_SC_8020, US_PR_CB,USB_US_TYPE_STOR),
1479 USUAL_DEV(US_SC_QIC, US_PR_CB,USB_US_TYPE_STOR),
1480 USUAL_DEV(US_SC_UFI, US_PR_CB,USB_US_TYPE_STOR),
1481 USUAL_DEV(US_SC_8070, US_PR_CB, USB_US_TYPE_STOR),
1482 USUAL_DEV(US_SC_SCSI, US_PR_CB,USB_US_TYPE_STOR),
1483
1484 /* Control/Bulk/Interrupt transport for allSubClass values */
1485 USUAL_DEV(US_SC_RBC, US_PR_CBI,USB_US_TYPE_STOR),
1486 USUAL_DEV(US_SC_8020, US_PR_CBI,USB_US_TYPE_STOR),
1487 USUAL_DEV(US_SC_QIC, US_PR_CBI,USB_US_TYPE_STOR),
1488 USUAL_DEV(US_SC_UFI, US_PR_CBI,USB_US_TYPE_STOR),
1489 USUAL_DEV(US_SC_8070, US_PR_CBI,USB_US_TYPE_STOR),
1490 USUAL_DEV(US_SC_SCSI, US_PR_CBI,USB_US_TYPE_STOR),
1491
1492 /* Bulk-only transport for all SubClassvalues */
1493 USUAL_DEV(US_SC_RBC, US_PR_BULK,USB_US_TYPE_STOR),
1494 USUAL_DEV(US_SC_8020, US_PR_BULK,USB_US_TYPE_STOR),
1495 USUAL_DEV(US_SC_QIC, US_PR_BULK,USB_US_TYPE_STOR),
1496 USUAL_DEV(US_SC_UFI, US_PR_BULK,USB_US_TYPE_STOR),
1497 USUAL_DEV(US_SC_8070, US_PR_BULK,USB_US_TYPE_STOR),
1498 USUAL_DEV(US_SC_SCSI, US_PR_BULK, 0),
USUAL_DEV以及UNUSUAL_DEV均定义于drivers/usb/storage/usb.c中:
128 #define UNUSUAL_DEV(id_vendor, id_product,bcdDeviceMin, bcdDeviceMax, \
129vendorName, productName,useProtocol, useTransport, \
130initFunction, flags) \
131 { USB_DEVICE_VER(id_vendor, id_product,bcdDeviceMin,bcdDeviceMax), \
132.driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
133
134 #define USUAL_DEV(useProto, useTrans, useType)\
135 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE,useProto, useTrans), \
136.driver_info = (USB_US_TYPE_STOR<<24) }
注意到我们看的是structusb_device_id结构体的数组,其中每一项必然是一个struct usb_device_id的结构体变量。我们先来看USB_DEVICE_VER和USB_INTERFACE_INFO,很显然这两个都是宏,来自include/linux/usb.h:
715 /**
716 *USB_DEVICE_VER - macro used to describe a specific usb device with a
717*version range
718 *@vend: the 16 bit USB Vendor ID
719 *@prod: the 16 bit USB Product ID
720 *@lo: the bcdDevice_lo value
721 *@hi: the bcdDevice_hi value
722 *
723 *This macro is used to create a struct usb_device_id that matches a
724 *specific device, with a version range.
725*/
726 #define USB_DEVICE_VER(vend,prod,lo,hi) \
727 .match_flags =USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \
728 .idVendor = (vend), .idProduct =(prod), \
729 .bcdDevice_lo = (lo),.bcdDevice_hi = (hi)
744 /**
745 *USB_INTERFACE_INFO - macro used to describe a class of usb interfaces
746 *@cl: bInterfaceClass value
747 *@sc: bInterfaceSubClass value
748 *@pr: bInterfaceProtocol value
749 *
750 *This macro is used to create a struct usb_device_id that matches a
751 *specific class of interfaces.
752*/
753 #define USB_INTERFACE_INFO(cl,sc,pr) \
754.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl),\
755 .bInterfaceSubClass = (sc), .bInterfaceProtocol= (pr)
756
每一个USB_DEVICE_VER或者USB_INTERFACE_INFO就是构造一个struct usb_device_id的结构体变量,回顾一下struct usb_device_id的定义,这里实际上就是为其中的四个元素赋了值,它们是match_flags、bInterfaceClass、bInterfaceSubClass和bInterfaceProtocol。
这里不得不说的是,这个世界上有许许多多的USB设备,它们各有各的特点,为了区分它们,USB规范或者说USB协议,把USB设备分成了很多类,然而每个类又分成子类。这很好理解,我们的大学也是如此,先是分成很多个学院,然后每个学院又被分为很多个系,比如信息学院,下面分了电子工程系、微电子系、计算机系、通信工程系,然后可能每个系下边又分了各个专业。USB协议也是,首先每个接口属于一个Class,(为什么是把接口分类,而不把设备分类?前面讲过了,在USB设备驱动中,不用再提设备,因为每个设备驱动对应的是一种接口,而不是一种设备),然后Class下面分了SubClass,接着SubClass下面又按各种设备所遵循的不同的通信协议继续细分。
USB协议中为每一种Class、每一种SubClass和每一种Protocol定义一个数值,比如Mass Storage的Class就是0x08,而这里USB_CLASS_MASS_STORAGE这个宏在include/linux/usb/ch9.h中定义,其值正是8。
我们拿第1477行来举例。
1477 USUAL_DEV(US_SC_RBC, US_PR_CB,USB_US_TYPE_STOR),
把这个宏展开,就是说定义了这么一个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这些关于SubClass的宏的定义是在文件include/linux/usb_usual.h中:
74 #define US_SC_RBC 0x01/* Typically, flash devices */
75 #define US_SC_8020 0x02/* CD-ROM */
76 #define US_SC_QIC 0x03 /* QIC-157 Tapes */
77 #define US_SC_UFI 0x04/* Floppy */
78 #define US_SC_8070 0x05/* Removable media */
79 #define US_SC_SCSI 0x06/* Transparent */
80 #define US_SC_ISD200 0x07/* ISD200 ATA */
81 #define US_SC_MIN US_SC_RBC
82 #define US_SC_MAX US_SC_ISD200
83
84 #define US_SC_DEVICE 0xff/* Use device's value */
而像US_PR_CB这些关于传输协议的宏也定义于同一个文件中:
88 #define US_PR_CBI 0x00/* Control/Bulk/Interrupt */
89 #define US_PR_CB 0x01/* Control/Bulk w/o interrupt */
90 #define US_PR_BULK 0x50/* bulk only */
91 #ifdef CONFIG_USB_STORAGE_USBAT
92 #define US_PR_USBAT 0x80/* SCM-ATAPI bridge */
93 #endif
94 #ifdef CONFIG_USB_STORAGE_SDDR09
95 #define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */
96 #endif
97 #ifdef CONFIG_USB_STORAGE_SDDR55
98 #define US_PR_SDDR55 0x82/* SDDR-55 (made up) */
99 #endif
100 #define US_PR_DPCM_USB 0xf0/* Combination CB/SDDR09 */
101 #ifdef CONFIG_USB_STORAGE_FREECOM
102 #define US_PR_FREECOM 0xf1/* Freecom */
103 #endif
104 #ifdef CONFIG_USB_STORAGE_DATAFAB
105 #define US_PR_DATAFAB 0xf2/* Datafab chipsets */
106 #endif
107 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
108 #define US_PR_JUMPSHOT 0xf3/* Lexar Jumpshot */
109 #endif
110 #ifdef CONFIG_USB_STORAGE_ALAUDA
111 #define US_PR_ALAUDA 0xf4/* Alauda chipsets */
112 #endif
113 #ifdef CONFIG_USB_STORAGE_KARMA
114 #define US_PR_KARMA 0xf5/* Rio Karma */
115 #endif
116
117 #define US_PR_DEVICE 0xff/* Use device's value */
说了这么多,U盘属于其中的哪一种呢?USB协议中规定,U盘的SubClass是属于US_SC_SCSI的,而其通信协议使用的是Bulk-Only的,即这里看到的US_PR_BULK。显然这些东西我们后来都会用得上。
那么这里还有一个match_flag,它又是表示什么意思?USB_INTERFACE_INFO这个宏好像把所有的设备的match_flag都给设成了USB_DEVICE_ID_MATCH_INT_INFO,这是为什么?这个宏来自include/linux/usb.h:
699 #define USB_DEVICE_ID_MATCH_INT_INFO \
700(USB_DEVICE_ID_MATCH_INT_CLASS | \
701USB_DEVICE_ID_MATCH_INT_SUBCLASS | \
702USB_DEVICE_ID_MATCH_INT_PROTOCOL)
match_flag这个东西是给USB Core去用的,USB Core负责给设备寻找适合它的驱动,负责给驱动寻找适合它的设备,它所比较的就是struct usb_device_id的变量,而struct usb_device_id结构体中有许多成员,那么是不是一定要把每一个成员都给比较一下呢?其实就是告诉USB Core,你只要比较bInterfaceClass,bInterfaceSubClass和bInterfaceProtocol即可。include/linux/mod_devicetable.h中针对struct usb_device_id中的每一个要比较的项定义了一个宏:
122 /* Some useful macros to use to create structusb_device_id */
123 #define USB_DEVICE_ID_MATCH_VENDOR0x0001
124 #define USB_DEVICE_ID_MATCH_PRODUCT0x0002
125 #define USB_DEVICE_ID_MATCH_DEV_LO0x0004
126 #define USB_DEVICE_ID_MATCH_DEV_HI0x0008
127 #define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
128 #define USB_DEVICE_ID_MATCH_DEV_SUBCLASS0x0020
129 #define USB_DEVICE_ID_MATCH_DEV_PROTOCOL0x0040
130 #define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
131 #define USB_DEVICE_ID_MATCH_INT_SUBCLASS0x0100
132 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL0x0200
回去对比一下structusb_device_id就知道这些宏是什么意思了。
但是你一定有一个疑问,那就是为什么会有一个USUAL_DEV和一个UNUSUAL_DEV这样两个宏的存在,它们之间有什么区别呢?顾名思义,有些设备属于普通设备,而有些设备却并不是普通设备,它们或者是有一些别的设备不具备的特性,或者是他们遵循的通信协议有些与众不同,比如,它既不是Bulk-Only也不是CBI,像这些不按常理出牌的设备,写代码的人把它们单独给列了出来。当然,从大的分类来看,它们依然是属于USB Mass Storage这个类别的,否则也没必要放在这个目录下面了。
为了包容这些另类的设备,伟大的Linux内核开发人员们为它们准备了一个文件,它就是让诸多USB Mass Storage设备厂家欢欣鼓舞的unusual_devs.h,有了它,厂家们不用再为自己的设备不被Linux内核支持而烦恼了。
《Linux那些事儿之我是USB》我是U盘(15)冬天来了,春天还会远吗?(一)相关推荐
- 【转】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盘(18)冬天来了,春天还会远吗?(四)
结束了get_device_info,我们继续沿着storage_probe一步一步地走下去.继续,这就是我们前面提到过的三个函数,get_transport.get_protocol和get_pip ...
- 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 ...
最新文章
- tomcat环境变量参数catalina.home和catalina.base的设置位置
- 19-chgrp命令
- vector的去重操作
- ARM(IMX6U)裸机主频和时钟
- Mybatis3 (2)xml映射文件
- tomcat开发远程调试端口以及利用eclipse进行远程调试
- 内存引起的几种故障的解决
- SAP License:SE16如何删除或合修改数据库表
- Windows10 关闭自动更新
- 我了解的一些线阵相机知识
- hive 如何将数组转成字符串_HIve字符串函数
- 盘点40个最佳项目管理工具大全
- 推荐4个好用、接收邮件及时的临时邮箱
- CentOS 7下的软件安装方法总结
- 畅写Office云端SDK :“硬核”赋予企业应用在线文档I在线协作编辑I在线预览I在线格式转换服务
- 【项目组件】liquibase管理项目数据库
- MT6735调试s5k3m2摄像头isp timout
- Typecho博客评论生成随机用户头像
- jquery限制只能输入英文逗号和数字
- React面试题最全
热门文章
- oracle 配置不能保存,Oracle Net Manager保存网络配置提示无效条目Error writing entr
- vue获取上级路由地址
- 微信小程序Day4学习笔记
- 古墓丽影10linux,《古墓丽影:崛起》推出Linux系统版:Ubuntu 17.10可玩
- 在网上打印双面和单面的资料哪里打印价格便宜
- 实现简单的轮播图(单张图片、多张图片)
- 复旦大学python教程_安装python-复旦大学大数据学院.pdf
- 复旦赵卫东:大数据的系统观
- .net输入汉字转拼音
- php 日期format不要零_DateFormat PHP Class (php 处置日期)