1.1 Mass Storage
1.1.1 请求过程(setup端点)
1)主机发送标准请求
2)发出两个类请求:Bulk-Only Mass Storage Reset请求、GetMaxLUN请求。
Bulk-Only Mass Storage Reset没有数据阶段,只在状态阶段告诉主机设备的Reset过程完成与否。如果在状态阶段返回ACK,那么主机就认为设备已经Reset完毕并准备好接收CBW了。
Get Max LUN要求设备返回一个字节的数据给主机,以表明此USB设备有多少个逻辑设备。返回的这个数据就是最大的设备逻辑号(Logic Unit Number),范围是0到15。例如,如果返回2,那么代表有0、1、2三个逻辑设备。
1.1.2 数据交换过程(bulk端点)
通过bulk端点进行的数据传输,都遵循这样一个过程,即三个阶段:
CBW->DATA->CSW
CBW是一个数据块,携带主机发给设备的SCSI命令。接收了CBW后,设备就可以从中知道在接下来的DATA阶段中该干什么。
DATA阶段有三种情况:无数据需要传输,IN传输(设备到主机)或OUT传输(主机到设备)。
CSW阶段反馈这次传输的结果给主机。
其中值得注意的是:
在设备枚举完成之后,主机发出的第一个bulkOUT事务就是请求向设备发出CBW。所以设备可以通过这第一次的bulkOUT事务来判定第一次bulk数据传输的开始。此后的bulk数据传输就按照上述的三个阶段反复执行。也就是说,第一次传输CBW后,如果有数据要传输,那么就会经历DATA阶段,然后进入CSW阶段;如果没有数据要传输,则直接进入CSW阶段,就此一次传输结束。接下来,如果又有传输,那么再发出CBW。因此,设备可以认为CSW完成后收到的下一个bulk OUT事务就是主机请求传输新的CBW。
CBW[12](CBW数据块的第13个字节)指明了传输方向,CBW[8-11]指明了传输的数据长度。实际上,CBW中的SCSI命令就暗含了数据要传输的方向和数据长度,因为SCSI规范中已明确规定这个命令所对应的数据格式。(在完整的应用中,要将CBW中的传输方向、数据长度与SCSI命令所表明的传输方向和数据长度做比较,不对应就要进行错误处理(Mass Storage Bulk-Only文档中有相关描述),不过正常情况下二者是匹配的,试验的时候可以暂时不理)。
CSW[12](CSW数据块的第13个字节)这个字节很重要,它为0则表示此次传输成功,非0就是不成功。在DATA阶段的数据传完(或者无需数据传输)之后,主机会发出IN事务请求设备返回CSW。如果CSW传送的是不成功的信息,那么主机会接着发送另一个命令来获取失败的详细信息(即RequestSense命令)。
CBW指令格式
CBW(Command Block Wrapper)的长度为31个字节,具体定义如下图:
dCBWSignature: CBW的标识,固定值:43425355h(little endian)。
dCBWTag: 主机发送的一个命令块标识,设备需要原样作为dCSWTag(CSW中的一部分)再发送给Host;主要用于关联CSW到对应的CBW。
dCBWDataTransferLength: 本次CBW命令要求在命令与回应之间传输的字节数。如果为0,则不传输数据。
bmCBWFlags: 反映数据传输的方向,0x00 表示来自Host,0x80 表示发至Host;
bCBWLUN: 对于有多个LUN逻辑单元的设备,用来选择具体目标。如果没有多个LUN,则写0。
bCBWCBLength: 命令的长度,范围在0~16。
CBWCB: 传输的具体命令,符合bInterfaceSubClass.中定义的命令规范,此处是SCSI指令集。
CSW(Command StatusWrapper)状态格式
CSW的长度为13个字节,是对应CBW指令的状态返回,它指示了上一条指令执行是否成功,具体定义如下:
dCSWSignature: CSW的标识,固定值:53425355h(little endian)。
dCSWTag: 设置这个标识和CBW中的dCBWTag一致,参照上面关于dCBWTag的解释。
dCSWDataResidue: 还需要传送的数据,此数据根据dCBWDataTransferLength-本次已经传送的数据得到。
bCSWStatus: 指示命令的执行状态。如果命令正确执行,bCSWStatus返回0 ,不正确返回1,phase错返回2(当HOST收到此错误时需要对Device复位)。
U盘不仅仅是USB设备,它还是一种存储设备,类似硬盘,USB协议本身没有定义对存储设备操作的指令,所以需要通过SCSI来完成读写等操作。注意在interface描述符中:
bInterfaceClass= 0x08
bInterfaceSubClass= 0x06
bInterfaceProtocol= 0x50