Purlvin's private Weblog ‹℘›

through the EyE, through the Life

Monthly Archives: August 2006

《黑洞频率》(Frequency)

对约翰沙勒文来说,他最想改变的一件事就是回到1969年的1012日那天,并且让他父亲在布朗区的大火中死里逃生,因为那场悲剧使得他的生活蒙上一层无法摆脱的阴影,即使他父亲是个救火英雄,而他也是一个尽忠职守的好警察。

  三十年后十月的某个晚上,约翰意外地找到他父亲生前的火腿族无线电,在随兴的拨接下,他竟和一个陌生男子搭上线,也许是天意,也有可能是神秘的黑洞力量,让北极光对电波频率产生异变。结果和他隔空对话的不是别人,正是他三十年前还在人世的父亲。

  几经波折父子两人终于再不可思议的时空重迭中相认,却不得不感叹人事已非。不过约翰灵机一动而向他父亲透漏他将要出任务救一场大火,要如何避开他的生死关头。

  没想到救了他父亲一命之后,不但让约翰周遭的事物重新洗牌,也改变了他母亲的命运,原来一直和约翰相依为命的护士母亲,反而遭到一个连续杀人犯「南丁格尔杀人魔」的毒手。

  这时约翰和他的父亲相隔三十年的时空,靠着一台无线电,他们必须和时间竞赛,如何才能找出悬案的真凶?如何才能挽救他母亲命在旦夕的危险?



很早就在《科幻世界》上看到这部影片的介绍,没想到无意间让我给看到了。时隔多年,真正看到了这部电影竟还能有点印象,真是奇怪的很。

看完之后,印象深刻并且其科幻元素,也不是所谓的种种看点,真正让我感到的是那段父子情。影片结尾时,全家人都能在一起,大家一起打棒球,真是幸福啊。

USB读取U盘数据技术文档-3

根目录区(Root Directory Region)
ROOT区中存放着分区根目录下的目录项信息。每个目录项都是占用32字节,但是一个文件或目录可以占用多个目录项,从而实现长文件名的存储。
对于一个文件或目录至少有一个目录项来存放相关的信息,这就是短文件名目录项,在读取文件时需要关注其中的数据:
1.短文件名(offset=0,length=11),前8个字节为文件名,后3个字节为扩展名。若不满则用空格(0x20)填充。
2.文件属性(offset=11,length=1),一般为存档(0x20)和目录(0x10),但该字节为0x0f是说明该目录项为长文件名目录项,这个留待稍后重点讨论。
3.起始Cluster地址(offset=26,length=2),通过该地址就能从FAT区中查到下一个Cluster地址,从而读取整个文件。
4.文件长度(offset=28,length=4),文件系统中文件是按Cluster来占用存储空间,往往最后一个Cluster都没有占满。因而超出文件长度的数据为无用数据,读取文件时应舍弃。
长文件名的处理
前面提到的目录项均是以短文件名8.3的格式存储(文件名8个字符,扩展名3个字符)为例,如此一来所有的文件和目录都可以用一个目录项来表示。然而实际上不是如此,更多的时候使用的长是文件名来表示一个文件的,这就需要有特殊的表示方式来表示长文件名。
获取一个文件或目录的信息的长文件名方法如下:首先读取该目录项的文件属性,若为0x0F则说明是长文件名,然后读取第一个字节,将该字节减去0x40所得到的值是其后还有多少个目录项同属于这个文件或目录,或者一共有多少个长文件名目录项(每个文件或目录都有且仅有一个短文件目录项),而这个目录项则为长文件名目录项的最后一项,之后的目录项依次为长文件名的倒数第二项、倒数第三项……在这个文件或目录所有目录项中最后的一个目录项就是原来的短文件名目录项,保存着文件或目录的属性、起始Cluster地址和长度等信息。从短文件名目录项倒数向上,则长文件名目录项的第一个字节依次为0x01,0x02……读取的时候也按照这个顺序即可。
长文件名目录项的32Byte中并非全部用来存放文件名,其中还包含文件属性、校验信息。而且存放字符时使用的还是Unicode编码,所以每个字符都占用两个字节(数字、ASCII码也是占两个字节),一个目录项也仅仅能存放13个字符。并且由于很多设备不支持Unicode,在实际读取时需要将中文的Unicode转换为GB码,具体操作就是使用一个二者的转换表,通过查表来获取对应的编码。而ASCII字符的转换就相对容易,只需将高位的0x00去掉即可。
并且在实际读取的过程中,由于长文件名目录项可能会跨越两个Block,而在读取文件信息的时候又需要先从短文件目录项开始读取,也就是新读一个block获取短文件名目录项及前半部分长文件名目录项,再回头来读旧Block读取长文件名目录项的剩下部分。对于这个问题的一个解决方法是开设文件名缓冲区,通过计算缓冲区的内对应目录项的地址,分段读取长文件名,但这样的代价是需要很大的缓冲区,并且需注意偏移量不要越界了,否则会出现莫名其妙的错误。
文件或目录的读取过程
对于根目录下一个文件或目录的读取的步骤如下:先从所有目录项的短文件名目录项中得到起始Cluster地址,然后在FAT区查找下一个Cluster地址(FAT中两个字节为一项,起始FFF8为第0项,使用文件或目录的起始Cluster地址作为项的offset,从而得到下一个Cluster的地址),同理可以得到文件或目录所有的Cluster。得到Cluster地址还不能直接得到文件或目录的数据,因为对Flash的操作是按Block而非Cluster,所有还需将得到的Cluster地址换算为Block地址,其方法是将DATA+(Cluster-2)×BPB_SecPerClus。这是因为DATA区的起始地址就是Cluster地址为2的地方,通过上面的公式就能算出对应的Block地址。需要注意的是,在文件是按Cluster存储的,换算到Block地址后,要一次连续读满一个Cluster。
对于在子目录中对文件或目录的操作和在根目录中的类似,同样可以得到一个起始Cluster地址,通过在FAT区中查找下一个Cluster地址,就能得到超出一个Cluster的目录项了,直到没有下一个Cluster为止。与根目录相比除了将连续存储变成了链式存储之外,还稍微有所区别。在子目录所对应的起始Cluster的前两个目录项的文件名为“.”和“..”,分别指代当前的目录和上一级目录。这两个目录项中保存的起始Cluster地址,也分别指的是当前目录的Cluster地址和上一级目录的Cluster地址。若“..”目录项中的起始地址为0x00,则表明上一级目录为根目录。注意,此处使用之前的公式换算成Block地址可能会有问题,需要单独处理。子目录中其他目录项与根目录区中的完全相同,这里就不累述了。

根目录区(Root Directory Region)
ROOT区中存放着分区根目录下的目录项信息。每个目录项都是占用32字节,但是一个文件或目录可以占用多个目录项,从而实现长文件名的存储。
对于一个文件或目录至少有一个目录项来存放相关的信息,这就是短文件名目录项,在读取文件时需要关注其中的数据:
1.短文件名(offset=0,length=11),前8个字节为文件名,后3个字节为扩展名。若不满则用空格(0x20)填充。
2.文件属性(offset=11,length=1),一般为存档(0x20)和目录(0x10),但该字节为0x0f是说明该目录项为长文件名目录项,这个留待稍后重点讨论。
3.起始Cluster地址(offset=26,length=2),通过该地址就能从FAT区中查到下一个Cluster地址,从而读取整个文件。
4.文件长度(offset=28,length=4),文件系统中文件是按Cluster来占用存储空间,往往最后一个Cluster都没有占满。因而超出文件长度的数据为无用数据,读取文件时应舍弃。
长文件名的处理
前面提到的目录项均是以短文件名8.3的格式存储(文件名8个字符,扩展名3个字符)为例,如此一来所有的文件和目录都可以用一个目录项来表示。然而实际上不是如此,更多的时候使用的长是文件名来表示一个文件的,这就需要有特殊的表示方式来表示长文件名。
获取一个文件或目录的信息的长文件名方法如下:首先读取该目录项的文件属性,若为0x0F则说明是长文件名,然后读取第一个字节,将该字节减去0x40所得到的值是其后还有多少个目录项同属于这个文件或目录,或者一共有多少个长文件名目录项(每个文件或目录都有且仅有一个短文件目录项),而这个目录项则为长文件名目录项的最后一项,之后的目录项依次为长文件名的倒数第二项、倒数第三项……在这个文件或目录所有目录项中最后的一个目录项就是原来的短文件名目录项,保存着文件或目录的属性、起始Cluster地址和长度等信息。从短文件名目录项倒数向上,则长文件名目录项的第一个字节依次为0x01,0x02……读取的时候也按照这个顺序即可。
长文件名目录项的32Byte中并非全部用来存放文件名,其中还包含文件属性、校验信息。而且存放字符时使用的还是Unicode编码,所以每个字符都占用两个字节(数字、ASCII码也是占两个字节),一个目录项也仅仅能存放13个字符。并且由于很多设备不支持Unicode,在实际读取时需要将中文的Unicode转换为GB码,具体操作就是使用一个二者的转换表,通过查表来获取对应的编码。而ASCII字符的转换就相对容易,只需将高位的0x00去掉即可。
并且在实际读取的过程中,由于长文件名目录项可能会跨越两个Block,而在读取文件信息的时候又需要先从短文件目录项开始读取,也就是新读一个block获取短文件名目录项及前半部分长文件名目录项,再回头来读旧Block读取长文件名目录项的剩下部分。对于这个问题的一个解决方法是开设文件名缓冲区,通过计算缓冲区的内对应目录项的地址,分段读取长文件名,但这样的代价是需要很大的缓冲区,并且需注意偏移量不要越界了,否则会出现莫名其妙的错误。
文件或目录的读取过程
对于根目录下一个文件或目录的读取的步骤如下:先从所有目录项的短文件名目录项中得到起始Cluster地址,然后在FAT区查找下一个Cluster地址(FAT中两个字节为一项,起始FFF8为第0项,使用文件或目录的起始Cluster地址作为项的offset,从而得到下一个Cluster的地址),同理可以得到文件或目录所有的Cluster。得到Cluster地址还不能直接得到文件或目录的数据,因为对Flash的操作是按Block而非Cluster,所有还需将得到的Cluster地址换算为Block地址,其方法是将DATA+(Cluster-2)×BPB_SecPerClus。这是因为DATA区的起始地址就是Cluster地址为2的地方,通过上面的公式就能算出对应的Block地址。需要注意的是,在文件是按Cluster存储的,换算到Block地址后,要一次连续读满一个Cluster。
对于在子目录中对文件或目录的操作和在根目录中的类似,同样可以得到一个起始Cluster地址,通过在FAT区中查找下一个Cluster地址,就能得到超出一个Cluster的目录项了,直到没有下一个Cluster为止。与根目录相比除了将连续存储变成了链式存储之外,还稍微有所区别。在子目录所对应的起始Cluster的前两个目录项的文件名为“.”和“..”,分别指代当前的目录和上一级目录。这两个目录项中保存的起始Cluster地址,也分别指的是当前目录的Cluster地址和上一级目录的Cluster地址。若“..”目录项中的起始地址为0x00,则表明上一级目录为根目录。注意,此处使用之前的公式换算成Block地址可能会有问题,需要单独处理。子目录中其他目录项与根目录区中的完全相同,这里就不累述了。

USB读取U盘数据技术文档-2

Flash存储与FAT16文件系统
Flash存储器的结构
由于现在Flash的容量普遍较大,对于Flash的操作往往都是按块(Block)来进行的,为了与磁盘兼容,Flash存储器中Block的大小均为512Byte。因而Block就成为对Flash操作的最小单位,下文说提及的地址如没有特别指出都是指Block的地址。
Flash存储器的FAT16文件系统
目前Flash存储器中比较常见的文件系统有FAT16和FAT32,这里重点介绍FAT16文件系统的操作。使用FAT16文件系统格式化后的Flash存储介质的一般会被分以下四个部分:保留分区(Reserved Region)、FAT(File Allocation Table)区(文件分配表区)、根目录区(Root Directory Region)、文件和目录数据区(Data)。
保留分区(Reserved Region)
若U盘具有引导功能,则保留分区又可分成以下两个部分:MBR(Master Boot Record)主引导记录、DBR(Dos Boot Record)操作系统引导记录。
MBR是U盘引导所必须的,但是在PC上却往往却又是不可见的。即使对U盘进行格式化,该部分内容也不受影响。使用软件工具WinHex能观察到DBR、FAT、ROOT、DATA内的内容,但却观察不到MBR的内容。并且即使是有MBR的U盘,WinHex中也是将DBR以地址0x00开始。但在实际使用USB访问U盘时,地址0x00开始的Block是MBR,而地址0x20的Block才是DBR。
若U盘不具有引导功能,则保留分区只还有DBR,并且是以地址0x00开始。
MBR中包含了存取介质的分区信息,实际中U盘一般只有一个分区,所以就可以忽略MBR的信息,而将重点放在读取DBR中的若干内容,用以定位FAT、ROOT和DATA的开始地址。
DBR(Dos Boot Record)操作系统引导记录
DBR中又包含三部分内容:BPB(BIOS Parameter Block)引导扇区、Executable Code引导代码、0x55AA结束标志。其中最重要的是BPB,通过解析其中数据的含义可以获得存储介质中文件系统的特定参数。
实际读取U盘时需要关注是以下几个数据:
1.BS_jmpBoot(offset=0,length=3),只需关注第一个字节是否为0xEB或0xE9,以此来区分DBR和MBR。
2.BPB_SecPerClus(offset=13,length=1),该字节指出了每个簇(Cluster)所占的块(Block)数。对于Flash的底层操作是按最小单位Block进行的,但是在文件系统中却又是以Cluster来管理的。每个文件及目录所占用的最小单位都是Cluster, FAT区中存储的链接地址同样也是指Cluster地址。
3.BPB_RootEntCnt(offset=17,length=2),该数据说明了ROOT区中根目录的项数。根目录中每项都是32个字节,用目录项数×32÷512就能得到ROOT区的长度。不过一般FAT16中该处为512,即ROOT区占用32个Block。
4.BPB_FATSz16(offset=22,length=2),此处是指FAT区所占的扇区数,通过这个数据就能得到ROOT区的起始地址。
5.BPB_HiddSec(offset=28,length=4),该段数据说明了隐藏扇区的数目,实际上就是指DBR至FAT区之间的长度。
得到以上数据就可以很容易的计算出FAT区、ROOT区、DATA区的开始地址:
FAT=offset+BPB_HiddSec(offset是指DBR开始的地址,可以检测BPB的一个字节来确定是0x00还是0x20)
ROOT=FAT+BPB_FATSz16×2(必须有两个FAT区)
DATA=ROOT+32(FAT16中BPB_RootEntCnt一般为512)
FAT(File Allocation Table)区
FAT区用于存储当前Cluster的下一个Cluster的地址。读取文件时只需从目录项中获取文件起始Cluster地址,然后通过查找FAT区中对应地址中的值就可以获得第二个Cluster的地址,如此不断往复就能得到整个文件。
FAT区以0xFFF8开始,其中每一项都是两个字节(16bit,以此来命名FAT16,同理FAT12每项即为12bit)。FAT的第0项(0xFFF8)为FAT区起始标志,而第1项则为固定值0xFFFF,所以目录项中文件的Cluster起始地址最小为0x02。
FAT区中项的值为0xFFF8~0xFFFF则表明是文件的最后一个Cluster。

Flash存储与FAT16文件系统
Flash存储器的结构
由于现在Flash的容量普遍较大,对于Flash的操作往往都是按块(Block)来进行的,为了与磁盘兼容,Flash存储器中Block的大小均为512Byte。因而Block就成为对Flash操作的最小单位,下文说提及的地址如没有特别指出都是指Block的地址。
Flash存储器的FAT16文件系统
目前Flash存储器中比较常见的文件系统有FAT16和FAT32,这里重点介绍FAT16文件系统的操作。使用FAT16文件系统格式化后的Flash存储介质的一般会被分以下四个部分:保留分区(Reserved Region)、FAT(File Allocation Table)区(文件分配表区)、根目录区(Root Directory Region)、文件和目录数据区(Data)。
保留分区(Reserved Region)
若U盘具有引导功能,则保留分区又可分成以下两个部分:MBR(Master Boot Record)主引导记录、DBR(Dos Boot Record)操作系统引导记录。
MBR是U盘引导所必须的,但是在PC上却往往却又是不可见的。即使对U盘进行格式化,该部分内容也不受影响。使用软件工具WinHex能观察到DBR、FAT、ROOT、DATA内的内容,但却观察不到MBR的内容。并且即使是有MBR的U盘,WinHex中也是将DBR以地址0x00开始。但在实际使用USB访问U盘时,地址0x00开始的Block是MBR,而地址0x20的Block才是DBR。
若U盘不具有引导功能,则保留分区只还有DBR,并且是以地址0x00开始。
MBR中包含了存取介质的分区信息,实际中U盘一般只有一个分区,所以就可以忽略MBR的信息,而将重点放在读取DBR中的若干内容,用以定位FAT、ROOT和DATA的开始地址。
DBR(Dos Boot Record)操作系统引导记录
DBR中又包含三部分内容:BPB(BIOS Parameter Block)引导扇区、Executable Code引导代码、0x55AA结束标志。其中最重要的是BPB,通过解析其中数据的含义可以获得存储介质中文件系统的特定参数。
实际读取U盘时需要关注是以下几个数据:
1.BS_jmpBoot(offset=0,length=3),只需关注第一个字节是否为0xEB或0xE9,以此来区分DBR和MBR。
2.BPB_SecPerClus(offset=13,length=1),该字节指出了每个簇(Cluster)所占的块(Block)数。对于Flash的底层操作是按最小单位Block进行的,但是在文件系统中却又是以Cluster来管理的。每个文件及目录所占用的最小单位都是Cluster, FAT区中存储的链接地址同样也是指Cluster地址。
3.BPB_RootEntCnt(offset=17,length=2),该数据说明了ROOT区中根目录的项数。根目录中每项都是32个字节,用目录项数×32÷512就能得到ROOT区的长度。不过一般FAT16中该处为512,即ROOT区占用32个Block。
4.BPB_FATSz16(offset=22,length=2),此处是指FAT区所占的扇区数,通过这个数据就能得到ROOT区的起始地址。
5.BPB_HiddSec(offset=28,length=4),该段数据说明了隐藏扇区的数目,实际上就是指DBR至FAT区之间的长度。
得到以上数据就可以很容易的计算出FAT区、ROOT区、DATA区的开始地址:
FAT=offset+BPB_HiddSec(offset是指DBR开始的地址,可以检测BPB的一个字节来确定是0x00还是0x20)
ROOT=FAT+BPB_FATSz16×2(必须有两个FAT区)
DATA=ROOT+32(FAT16中BPB_RootEntCnt一般为512)
FAT(File Allocation Table)区
FAT区用于存储当前Cluster的下一个Cluster的地址。读取文件时只需从目录项中获取文件起始Cluster地址,然后通过查找FAT区中对应地址中的值就可以获得第二个Cluster的地址,如此不断往复就能得到整个文件。
FAT区以0xFFF8开始,其中每一项都是两个字节(16bit,以此来命名FAT16,同理FAT12每项即为12bit)。FAT的第0项(0xFFF8)为FAT区起始标志,而第1项则为固定值0xFFFF,所以目录项中文件的Cluster起始地址最小为0x02。
FAT区中项的值为0xFFF8~0xFFFF则表明是文件的最后一个Cluster。

USB读取U盘数据技术文档-1

USB读取U盘数据技术文档
USB通信与Mass Storage协议
相关描述符和设置
对于U盘此类的大容量存取介质,USB一般是使用Mass Storage协议来进行通信的。然而在使用Mass Storage协议通信之前主机需先获取设备的相关信息,并进行一些设置。
对于读取U盘所用的Mass Storage协议而言,端点描述符和传输协议是需要关注的。传输协议一般有CBI(Control/Bulk/Interrupt Protocol)和Bulk_Only Transport两种,并且在同种传输方式下又分多种指令集。而U盘一般常用Bulk_Only传输方式和SCSI指令集。
Bulk_Only的传输方式中需要用到Bulk_In和Bulk_Out两个端点,而对于不同U盘,这两个端点号是不尽相同的。所以首先要获取Bulk_In和Bulk_Out这两个端点号,方可进行USB的正常通信。
Mass Storage协议与Bulk_Only传输协议
Mass Storage协议中包括CBI和Bulk_Only两种传输协议,但后者较为简单也比较常用。
Bulk_Only传输协议是将指令和数据按照一定的格式进行封装,其格式如下:CBW(Command Block Wrapper)->[DATA]->CSW(Command Status Wrapper)。CBW是主机向U盘发送指令的命令封包,U盘在接受到CBW后根据相应的指令集对命令解析,作出回应。或向主机发送数据,或接受数据,或不进行任何数据操作。完成数据部分的操作后,U盘会向主机发送CSW,以反馈命令的执行情况。
CBW(Command Block Wrapper)
主机通过这个包来通知U盘做何种操作以及传递的数据量。CBW是以0x55534243(Little Endian)开始。CBW中的数据项dCBWTAG可以任意取,在CSW中会返回同样的数据以作验证用。dCBWDataTransferLength表征之后传输DATA的长度,该长度根据不同指令返回数据的多少来决定。若是使用READ10指令来读取U盘,则可以赋值为0x200。bmCbWFlags指示了数据传输的方向。主机读数据为0x80,写则为0x00。bCBWLUN是指分区号,一般U盘只有一个分区,写入0x00即可。bCBWCBLength是其后CBWCB(指令)的有效长度,由于CBW的长度固定为31Byte,不足的部分将由0x00填充。CBWCB因具体指令集而异,一般U盘使用SCSI。也有些使用UFI,但UFI是基于SCSI指令集的,因而会发现一些常用的指令是完全一样的。
在CBWCB中常用的SCSI指令的数据结构中有一项Logical Unit Number可以忽略,使用0x00来填充。这是由于现在使用的SCSI指令集通常是指SCSI-2,而Logical Unit Number是为了和SCSI-1兼容用的。另外还需注意的是对于其后的多个字节的数据项如地址,都是以低字节作为高位的(Big Endian),与整个命令包中各项的以低地址开始(Little Endian)有所区别。
DATA包
DATA包没有任何特殊之初,仅仅只包含数据而已。不过对于指令PREVENT-ALLOW MEDIUM REMOVAL和TEST UNIT READY是没有数据包的。接受完CBW后,U盘会直接返回CSW。
CSW(Command Status Wrapper)
CSW是U盘对执行指令的反馈,其长度为13个字节。若是以0x55535342开始则表明CSW是正常的,当然还要对比一下CBW包的dCBWTag和此处的dCSWTag是否一致,以及dCSWDataResidue的剩余长度是否正确。特别需要关注的是最后一个字节bCSWStatus,若是0x00则一切正常,否则就要找原因了。
U盘的访问流程
使用软件工具Bus Hound监测PC对U盘访问的整个过程如下:(对端点、地址的设置)->Inquiry->Read Format Capacities->Read Capacity->Read10(0x00 Block)…然而实际使用时在对端点和地址设置正确的前提下,直接使用READ10指令读取U盘也是没有任何问题的。
另外有些U盘在设置地址时会出错,这时只需将端口重置,再设置一次地址即可。

USB读取U盘数据技术文档
USB通信与Mass Storage协议
相关描述符和设置
对于U盘此类的大容量存取介质,USB一般是使用Mass Storage协议来进行通信的。然而在使用Mass Storage协议通信之前主机需先获取设备的相关信息,并进行一些设置。
对于读取U盘所用的Mass Storage协议而言,端点描述符和传输协议是需要关注的。传输协议一般有CBI(Control/Bulk/Interrupt Protocol)和Bulk_Only Transport两种,并且在同种传输方式下又分多种指令集。而U盘一般常用Bulk_Only传输方式和SCSI指令集。
Bulk_Only的传输方式中需要用到Bulk_In和Bulk_Out两个端点,而对于不同U盘,这两个端点号是不尽相同的。所以首先要获取Bulk_In和Bulk_Out这两个端点号,方可进行USB的正常通信。
Mass Storage协议与Bulk_Only传输协议
Mass Storage协议中包括CBI和Bulk_Only两种传输协议,但后者较为简单也比较常用。
Bulk_Only传输协议是将指令和数据按照一定的格式进行封装,其格式如下:CBW(Command Block Wrapper)->[DATA]->CSW(Command Status Wrapper)。CBW是主机向U盘发送指令的命令封包,U盘在接受到CBW后根据相应的指令集对命令解析,作出回应。或向主机发送数据,或接受数据,或不进行任何数据操作。完成数据部分的操作后,U盘会向主机发送CSW,以反馈命令的执行情况。
CBW(Command Block Wrapper)
主机通过这个包来通知U盘做何种操作以及传递的数据量。CBW是以0x55534243(Little Endian)开始。CBW中的数据项dCBWTAG可以任意取,在CSW中会返回同样的数据以作验证用。dCBWDataTransferLength表征之后传输DATA的长度,该长度根据不同指令返回数据的多少来决定。若是使用READ10指令来读取U盘,则可以赋值为0x200。bmCbWFlags指示了数据传输的方向。主机读数据为0x80,写则为0x00。bCBWLUN是指分区号,一般U盘只有一个分区,写入0x00即可。bCBWCBLength是其后CBWCB(指令)的有效长度,由于CBW的长度固定为31Byte,不足的部分将由0x00填充。CBWCB因具体指令集而异,一般U盘使用SCSI。也有些使用UFI,但UFI是基于SCSI指令集的,因而会发现一些常用的指令是完全一样的。
在CBWCB中常用的SCSI指令的数据结构中有一项Logical Unit Number可以忽略,使用0x00来填充。这是由于现在使用的SCSI指令集通常是指SCSI-2,而Logical Unit Number是为了和SCSI-1兼容用的。另外还需注意的是对于其后的多个字节的数据项如地址,都是以低字节作为高位的(Big Endian),与整个命令包中各项的以低地址开始(Little Endian)有所区别。
DATA包
DATA包没有任何特殊之初,仅仅只包含数据而已。不过对于指令PREVENT-ALLOW MEDIUM REMOVAL和TEST UNIT READY是没有数据包的。接受完CBW后,U盘会直接返回CSW。
CSW(Command Status Wrapper)
CSW是U盘对执行指令的反馈,其长度为13个字节。若是以0x55535342开始则表明CSW是正常的,当然还要对比一下CBW包的dCBWTag和此处的dCSWTag是否一致,以及dCSWDataResidue的剩余长度是否正确。特别需要关注的是最后一个字节bCSWStatus,若是0x00则一切正常,否则就要找原因了。
U盘的访问流程
使用软件工具Bus Hound监测PC对U盘访问的整个过程如下:(对端点、地址的设置)->Inquiry->Read Format Capacities->Read Capacity->Read10(0x00 Block)…然而实际使用时在对端点和地址设置正确的前提下,直接使用READ10指令读取U盘也是没有任何问题的。
另外有些U盘在设置地址时会出错,这时只需将端口重置,再设置一次地址即可。

一点点的迷茫

不知为什么这些天来一直有些迷茫,什么都懒得去做。
每天都睡很久了,头却依然不时的有些痛。
总是有些心神不宁,各种事情总是会在脑中浮现,无法让自己静下心来。
假期彻底要结束了,而好多好多的事还没有做好,努力想做的事也由于自己的太过理想而暂时无法实现,唉……
快点开始上课吧,愿正常的上课能自己好些。