`
dato0123
  • 浏览: 970325 次
文章分类
社区版块
存档分类
最新评论

《Linux那些事儿之我是USB》我是U盘(27)彼岸花的传说(六)

 
阅读更多

我们继续接着上一节往下看。fill_inquiry_response(),这个函数来自drivers/usb/storage/usb.c中。

266 void fill_inquiry_response(struct us_data *us,unsigned char *data,

267unsigned int data_len)

268 {

269 if (data_len<36) // You lose.

270 return;

271

272 if(data[0]&0x20){ /* USB device currently not connected. Return

273peripheral qualifier 001b ("...however, the

274physical device is not currently connected

275to this logical unit") and leave vendor and

276productidentification empty. ("If the target

277does store some of the INQUIRY data on the

278device, it may return zeros or ASCII spaces

279(20h) in those fields until the data is

280available from the device."). */

281 me mset(data+8,0,28);

282 } else {

283 u16 bcdDevice =le16_to_cpu(us->pusb_dev->descriptor.bcdDevice);

284 memcpy(data+8,us->unusual_dev->vendorName,

285strlen(us->unusual_dev->vendorName) > 8 ? 8 :

286strlen(us->unusual_dev->vendorName));

287 memcpy(data+16, us->unusual_dev->productName,

288strlen(us->unusual_dev->productName) > 16 ? 16 :

289strlen(us->unusual_dev->productName));

290 data[32] = 0x30 + ((bcdDevice>>12) & 0x0F);

291 data[33] = 0x30 + ((bcdDevice>>8) &0x0F);

292 data[34]= 0x30 + ((bcdDevice>>4) & 0x0F);

293 data[35] = 0x30 + ((bcdDevice) & 0x0F);

294 }

295

296 usb_stor_set_xfer_buf(data,data_len, us->srb);

297 }

故事发生得太突然,会让人产生幻觉。 本来我们正儿八经用来处理SCSI命令的函数是后面将要讲的proto_handler(),但想不到我们在这里开始接触SCSI命令了。理由正是因为像Sony这几款PEG产品做得不好,连最基本的SCSI命令INQUIRY都不支持,然后又想在Linux中使用,那没办法了,所以就准备一个函数来修复这个问题吧,毫无疑问,这属于硬件上的一个Bug。

什么是INQUIRY命令?前面也提过,INQUIRY命令是最基本的一个SCSI命令。比如主机第一次探测设备时就要用INQUIRY命令来了解这是一个什么设备,如果SCSI总线上有一个插槽插了一个设备,那么SCSI主机就问它,你是SCSI磁盘,还是SCSI磁带,又或是SCSI的CD ROM呢?作为设备,它内部一定有一段固件程序,即所谓的firmware。它就在接收到主机的INQUIRY命令之后做出回答。

具体应该怎么回答?当然是依据SCSI协议中规定的格式了。不仅仅INQUIRY命令,对于每一个命令都应该如此。只要对方问:“天王盖地虎”。作为设备就该回答:“宝塔镇河妖。”这其实就好比我们对对联,这都是不成文的规矩,而开发SCSI的人把这些写成了规范,它就变成了成文的规矩了。具体来说, 设备在受到INQUIRY命令查询时,它的相应遵从SCSI协议中面规定的标准格式,标准格式规定了,响应数据必须至少包含36个字节。所以252行,如果data_len小于36,那就别往下走了,返回吧。

如果你对SCSI协议很陌生,还是没有明白INQUIRY命令究竟是做什么,那么推荐一个工具给你,你可以试一试,以便有一个直观的印象,其实INQUIRY命令就是查询,查询设备的一些基本信息。从软件的角度来说,在主机扫描时,或者说枚举时,向每一个设备发送这个命令,并且获得回答,驱动程序从此就会保存这些信息,因为这些信息之后可能都会用到或者说其中的一部分会被用到。这里推荐的工具是sg_utils3,这是一个软件包,Linux中可以使用的软件包,到处都有,下了之后安装上,然后它包含一个应用程序sg_inq,这其实就是给设备发送INQUIRY命令用的,用法如下所示:

[root@localhost ~]# sg_inq -36 /dev/sda

standard INQUIRY:

PQual=0 Device_type=0 RMB=1 version=0x02[SCSI-2]

[AERC=0] [TrmTsk=0] NormACA=0 HiSUP=0Resp_data_format=2

SCCS=0 ACC=0 TGPS=0 3PC=0 Protect=0 BQue=0

EncServ=0 MultiP=0 [MChngr=0] [ACKREQQ=0]Addr16=0

[RelAdr=0] WBus16=0 Sync=0 Linked=0[TranDis=0] CmdQue=0

length=36 (0x24)Peripheral device type: disk

Vendor identification: Intel

Product identification: Flash Disk

Product revision level: 2.00

这里我使用的是Intel生产的一块U盘,使用sg_inq命令可以查询到关于这块U盘的基本信息。实际上sg_inq可以查询所有SCSI设备的信息,因为INQUIRY本来就是一个标准的SCSI命令。当然以上这些信息中,我们之后用得到的大概也就是Vendor ID,Product ID,Product revision,以及length,device type--disk,还有中括号里的SCSI-2,这代表遵守的SCSI的版本。SCSI协议也发展了这么多年,当然也有不同的版本了。

有了直观的印象了我们就继续看代码,272行,判断data[0]是否是20h,20h有什么特别的吗?当然。SCSI协议中规定了,标准的INQUIRY data的data[0],总共有8个bit。其中bit7~bi5被称为peripheral qualifier(三位),而bit4~bit0被称为perpheral device type(五位),它们代表了不同的含义,但是20h就表示peripheralqualifier这个外围设备限定符为001b,而peripheral device type这个外围设备类型则为00h。查阅SCSI协议可知,后者代表的是设备类型为磁盘,或者说直接访问设备,前者代表的是目标设备的当前LUN支持这种类型。然而,实际的物理设备并没有连接在当前LUN上。在data[36]中,从data[8]一直到data[35]这28个字节保存的都是厂商和产品的信息。SCSI协议中写了,如果设备中保存这些信息,那么它可以暂时先返回0x20h,因为现在是系统poweron时期或者是reset期间,要尽量减少延时,于是fill_inquiry_response()就会把data[8]到data[35]都给设置成0。等到保存在设备上的这些信息可以读了再去读。

如果不是20h,比如我们这里传递进来的data[0]就是0,那么看284行,data[8]开始的8个字节可以保存厂商相关的信息,对于,us->unusual_dev,我们早已不陌生,struct us_data结构体中的成员struct us_unusual_dev *unusual_dev,我们在storage_probe()时曾经把us_unusual_dev_list[]数组中的对应元素赋给了它,而us_unusua_dev_list[]又来自unusual_devs.h,都是预先定义好了的。所以这里就是把其中的vendorName复制到data数组中来,但是如果vendorName超过8个字符了那可不行,只取前8个就行了。当然像Intel就不存在这个问题了,只有5个字符,大多数公司也都是8个字符以内,比如长一点的名字有Motorola,Samsung也都没问题。同样productName也是一样的方法,复制到data数组中来,协议中规定了,从16开始存放productName,不能超过16个字符,那么“Flash Disk”也没有问题。关于标准的INQUIRY数据格式,可以参看SCSI Primary Command-4文档。

然后可以看290行,us->pusb_dev->descriptor.bcdDevice,struct us_data中有一个成员struct usb_device *pusb_dev,而struct usb_device中有一个成员struct usb_device_descriptordescriptor,而structusb_device_descriptor中的成员__u16 bcdDevice,表示制造商指定的产品的版本号,“道上”的规定是用版本号,制造商id和产品id来标志一个设备。bcdDevice一共16位,是以bcd码的方式保存的信息,也就是说,每4位代表一个十进制的数,比如00110110 1001 0111就代表的3697。而在SCSI标准的INQUIRY data中,data[32]到data[35]被定义为保存这四个数,并且要求以ASCII码的方式保存。ASCII码中48对应咱们日常的0,49对应1,50对应2,也就是说得在现有数字的基础上加上48,或者说加上0x30。这就是290行到293行所表达的意思。

一切准备好了之后,我们就可以把data数组,这个包含36个字符的信息发送到SCSI命令指定的位置了,即srb指定的位置。这正是296行中usb_stor_set_xfer_buf的所作所为。

在接着讲296行这个函数usb_stor_set_xfer_buf之前,先解释一下之前定义data_ptr[36]时初始化的前8个元素。它们的含义都和scsi协议规定的对应。data_ptr[0]不用说了,data_ptr[1]被赋为0x80,这表明这个设备是可移除的,data_ptr[2]被赋为0x02这说明设备遵循SCSI-2协议,data_ptr[3]被赋为0x02,说明数据格式遵循国际标准化组织所规定的格式,而data_ptr[4]被称为additional length,附加参数的长度,即除了用这么一个标准格式的数据响应之外,可能还会返回更多的一些信息。这里设置的是0x1F。
分享到:
评论

相关推荐

    Linux那些事儿之我是USB(第2版)

    ### Linux那些事儿之我是USB(第2版)关键知识点概览 #### 一、书籍概述 - **核心主题**:本书主要围绕Linux内核中的USB子系统展开,深入剖析其工作原理和技术细节。 - **目标读者**:面向Linux初学者、驱动开发者...

    linux那些事儿之我是USB.zip

    本压缩包文件"linux那些事儿之我是USB.zip"包含了深入理解Linux USB驱动及内核相关知识的九个文档,包括Block层、EHCI主机控制器、HUB、PCI、SCSI硬盘、Sysfs、UHCI、USB core以及U盘。这些文档旨在提供一个系统性的...

    Linux那些事儿之我是USB

    ### Linux那些事儿之我是USB —— USB技术在Linux下的实现与探索 #### 引言 在探讨《Linux那些事儿之我是USB》这篇文章之前,我们先简单回顾一下文章的背景及主要内容。该文由一位自称对Linux并无太多好感的作者...

    Linux那些事儿

    Linux那些事儿之我是U盘 Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是...

    Linux那些事儿之我是U盘.pdf

    Linux那些事儿之我是U盘-有书签版.pdf

    linux那些事儿我是USB.pdf

    在《Linux那些事儿之我是U盘》这篇诙谐幽默的技术文章中,作者以独特的视角介绍了Linux内核2.6版本中USB驱动的相关知识。通过轻松的叙述方式,让读者在轻松愉快的氛围中理解复杂的USB驱动原理及其在Linux系统中的...

    Linux那些事儿1-9合集

    读过《linux那些事儿之我是U盘》的人,都知道其风格,我就不多说了。 导读: linux那些事儿之我是U盘 linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制...

    Linux那些事儿之我是U盘

    根据给定的信息,“Linux那些事儿之我是U盘”这一标题及描述主要聚焦于USB技术在Linux环境下的工作原理和技术细节。接下来,我们将基于这个主题展开深入探讨,涵盖USB技术的基本概念、USB在Linux系统中的实现机制...

    LINUX\Linux那些事儿系列

    3. **Linux那些事儿之我是U盘.pdf**: USB闪存驱动器,通常称为U盘,是常见的便携式存储设备。这部分可能讲述Linux如何识别、挂载和管理U盘,包括使用ums(USB Mass Storage)驱动程序,以及如何处理文件系统的读写...

    Linux那些事儿之全集

    导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了

    Linux那些事儿系列.rar

    》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...

    linux 那些事儿全集

    “Linux那些事儿之我是U盘.pdf”将关注通用串行总线(USB)闪存驱动器。这部分会解释Linux如何识别和处理USB闪存设备,包括文件系统的挂载和数据交换过程。 “Linux那些事儿之我是USB Core.pdf”涉及Linux内核的USB...

    linux的那些事儿全集

    Linux那些事儿之我是Block层 Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs ...Linux那些事儿之我是U盘

    Linux那些事儿之我是XXX全集.rar

    "Linux那些事儿之我是XXX全集"这个资源集合,旨在深入剖析Linux内核中的关键组件,特别是与USB(通用串行总线)相关的部分,包括USB core、U盘、UHCI、PCI、SCSI硬盘、Block层和Hub等核心概念。这些文件将通过源代码...

    linux那些事儿之我是U盘

    ### Linux与USB存储设备——《Linux那些事儿之我是U盘》知识点提炼 #### 引言 本文基于一篇幽默且深入的教程《Linux那些事儿之我是U盘》,该文章通过作者的亲身经历和深入浅出的讲解,介绍了Linux操作系统中USB存储...

Global site tag (gtag.js) - Google Analytics