本文来分享MSC(USB Mass Storage)设备的描述符,类请求,命令数据状态协议。以下都是基于Bulk-Only传输方式(BOT),因为这种方式是最普遍使用的方式。
参考文档
《Universal Serial Bus Mass Storage Class Bulk-Only Transport》描述:描述符,类相关请求,CBW,CSW等内容。
《Universal Serial Bus Mass Storage Class Specification Overview》描述:各种编码信息,Subclass编码,Protocol编码,类相关请求Request编码,类相关描述符编码.
《Universal Serial Bus Mass Storage Specification For Bootability Revision 1.0 October 25, 2004》描述:支持Boot设备的,CBW中的CBWCB内容,即INQUIRY,READ(10),WRITE(10)等命令。
《Universal Serial Bus Mass Storage Class UFI Command Specification Revision 1.0 December 14, 1998》:上面一个文档介绍的是Boot MSC设备支持的一些命令,本文档介绍的是所有的命令。常见命令参考二者之一即可。
本规范没有定义特定于类的描述符。使用以下标准描述符。
参考文档《Universal Serial Bus Mass Storage Class Bulk-Only Transport Revision 1.0 September 31, 1999》
bDeviceClass,bDeviceSubClass,bDeviceProtocol都为0,即在接口描述符中指定设备类和子类,而不是在设备描述符中。
还有就是iSerialNumber必须要有,见后面的字符串描述符说明。
配置描述符没什么特殊的
该设备应支持至少一个接口,此处称为批量数据接口。仅包含批量数据接口的设备使用三个端点(控制端点,Bulk-IN,Bulk-Out)。
bDeviceClass
见https://www.usb.org/defined-class-codes
0x08 MASS STORAGE Class.
bDeviceSubClass:
在《Universal Serial Bus Mass Storage Class Specification Overview》中定义:
其中0x06 对应SCSI
bDeviceProtocol:
在《Universal Serial Bus Mass Storage Class Specification Overview》中定义:
其中0x50 BULK-ONLY TRANSPORT
其中CBI只能用于全速的软盘驱动,不得用于高速设备或软盘驱动器以外的设备。不建议在任何新设计中使用CBI。
MSC设备应支持至少三个端点:控制、批量输入和批量输出。控制端点无需描述,所以只需要Bulk-In和Bulk-Out描述符。
Bulk-In端点描述符
用于IN数据和CSW状态
Bulk_out端点描述符
用于OUT数据和CBW命令
设备描述符的iSerialNumber字段,为包含序列号的字符串描述符的索引。
序列号应至少包含12位有效数字,表示为UNICODE字符串,所以字符串至少为2+2x12=26字节。序列号的最后12位数字对于每个USB idVendor和idProduct对都是唯一的。
主机可以通过连接16位idVendor、16位idProduct和由iSerialNumber索引的字符串描述符的最后12个字符表示的值来生成全局唯一标识符。
对应的字符串格式为: 注意是UNICODE编码,即12位数字一个数字对应两个字节。
字符串只能包含以下
0030h ~ 0039h 即"0" ~ "9"
0041h ~ 0046h 即"A" ~ "F"
类相关请求发送的目的都是接口。
参考文档《Universal Serial Bus Mass Storage Class Bulk-Only Transport Revision 1.0 September 31, 1999》
请求的bRequest 在《Universal Serial Bus Mass Storage Class Specification Overview》中定义,如下:
此请求用于重置大容量存储设备及其相关接口。
在发送CBW 之前必须先进行该操作,该请求通过控制端点发送,
设备的Bulk端点的TOGGLE状态和STALL状态不受该RESET影响。
设备对该请求的状态阶段进行NAK,直到完成RESET状态
该请求格式如下
即
• bmRequestType: 类, 接口, 主机到设备.
• bRequest =255 (FFh)
• wValue= 0
• wIndex =接口号
• wLength =0
设备可以多个逻辑单元,共享设备共同的特性。主机通过CBW中的bCBWLUN字段指定发给哪一个逻辑单元。该请求用于获取设备最大的LUN数。设备上的LUN从0开始编号,最大到15。
请求格式如下:
即
• bmRequestType: 类, 接口, 主机到设备.
• bRequest =254 (FEh)
• wValue=0
• wIndex =接口号
• wLength =1
设备返回一个字节的数据,其中包含设备支持的最大LUN编号(注意不是最大LUN数而是编号,编号是从0开始的)。如果设备支持四个LUN,则LUN的编号将从0到3,返回值为3。如果没有LUN与设备关联,则返回的值应为0。主机不得向不存在的LUN发送CBW。
不支持多个LUN的设备可能会STALL响应该命令。
参考文档《Universal Serial Bus Mass Storage Class Bulk-Only Transport Revision 1.0 September 31, 1999》
MSC的Bulk-Only Transport方式,数据读写,分为三个步骤,即命令-数据-状态.
数据流如下
主机应在相关数据OUT之前发送CBW,设备应在相关CBW之后和相关CSW之前发送数据IN。
主机可以在发送相关联的CBW之前请求数据IN或CSW。
如果dCBWDataTransferLength为零,则设备和主机不得在CBW和相关CSW之间传输数据。
在主机收到任何未完成的CBW的CSW之前,主机不得发送新的CBW。如果主机在中间没有CSW或RESET的情况下发出两个连续的CBW,则设备对第二个CBW的响应是不确定的。
本规范不支持单个命令中进行双向数据传输。
CBW用于传达要做什么;
CBW从数据包边界开始(后面的数据,CSW也一样);
CBW以短包结束,传输31个字节;
CBW按照小端,低字节在前传输。
CBW内容的具体含义如下
dCBWSignature:
固定为43425355h(小端),用于标志CBW。
dCBWTag:
主机发送的CBW标签。设备在相应的CSW的dCSWTag字段中将此字段的内容回传给主机。这样可以关联CBW和CSW,知道CSW对应的是哪个CBW。
dCBWDataTransferLength:
在执行此命令期间,主机希望在批量输入或批量输出端点上传输的数据字节数。如果此字段为0,则设备和主机不在CBW和相关CSW之间传输数据,并且设备应忽略bmCBWFlags中方向位的值。
bmCBWFlags:
bit7: 0:out 即主机到设备 1:IN即设备到主机。
bit[6:0]: 主机设置为0。
bCBWLUN:
命令块要发送到的设备的逻辑单元号(LUN)。对于支持多个LUN的设备,主机将此命令块所寻址的LUN放入此字段。否则,主机将此字段设置为零。
bCBWCBLength:
CBWCB的有效长度(以字节为单位)。定义了命令块的有效长度。合法值是1到16(01h到10h)。
CBWCB:
设备要执行的命令块。设备将此字段中的第一个字节解释为由bInterfaceSubClass标识的命令集定义的命令块。如果设备支持的命令集使用长度小于16(10h)字节的命令块,则应首先传输有效字节,从偏移量15(Fh)处的字节开始。设备忽略超出偏移字节(15+bCBWCCBLength-1)的CBWCB字段的内容。
设备对主机发过来的CBW先进行是否有效判断,条件如下(同时满足):
lCBW是在设备发送CSW之后或reset之后接收的
l收到的CBW是31字节
ldCBWSignature 为43425355h
然后进行是否有意义判断,条件如下(同时满足):
l所有保留Reserved位为0
lbCBWLUN是有效的LUN值
lbCBWCBLength和CBWCB的内容都符合bInterfaceSubClass。
CSW从数据包边界开始;
CSW以短数据包结束,传输13(0Dh)字节;
CSW按照小端,低字节在前传输。
CSW内容的具体含义如下
dCSWSignature:
固定为53425355h(小端),用于表示CSW。
dCSWTag:
设备将此字段设置为对应CBW的dCBWTag。
dCSWDataResidue:
对于OUT,设备在此报告dCBWDataTransferLength中所述的预期数据量与设备处理的实际数据量之间的差异。
对于IN,设备在此报告dCBWDataTransferLength中所述的预期数据量与设备发送的实际数据量之间的差异。
简而言之就是剩余未处理的数据。
dCSWDataResidue不得超过dCBWDataTransferLength, 即最多是设备不处理或者不发送数据,此时dCSWDataResidue=dCBWDataTransferLength。
bCSWStatus:
用于表示命令的成功或失败。如果命令成功完成,设备应将此字节设置为零。
非零值表示命令执行过程中出现故障
bCSWStatus含义如下:
主机对设备发过来的CSW先进行是否有效判断,条件如下(同时满足):
l收到的CSW是13字节
ldCSWSignature=53425355h
ldCSWTag=dCBWTag
然后进行是否有意义判断,条件如下(任一满足):
lbCSWStatus值为00h或01h且dCSWDataResidue小于或等于dCBWDataTransferLength
lbCSWStatus = 02h.
主机和设备如何保持同步。
主机使用方向位和dCBWDataTransferLength字段指示CBW中的预期传输。
然后,设备确定实际方向和数据传输长度。
设备按照6-主机/设备数据传输中的定义进行响应,通过传输数据、指定STALL端点并返回相应的CSW。
命令传输:
主机通过批量输出端点发送31字节的CBW。
设备接收CBW并进行ACK来表示CBW的运输成功。
如果主机在命令传输期间检测到批量输出端点的STALL,主机应响应Reset Recovery。
数据传输:
所有数据传输应从数据包边界开始。
主机按照dCBWDataTransferLength和Direction位的指定,进行OUT或者IN传输。
为了在数据传输完成之前报告错误并最大限度地提高数据完整性,设备可以通过STALL端点来终止命令。
状态传输:
主机通过IN读13字节CSW, 主机处理流程如下
如果主机收到无效的CSW,则主机应该要执行重置恢复Reset Recovery。如果主机收到无意义的CSW,则主机可以执行重置恢复Reset Recovery, 但是如果所是CSW中的bCSWStatus=0x02表示Phase Error这种无意义情况, 主机要进行Reset Recovery 处理。
Reset Recovery 处理过程如下:
1.Bulk-Only Mass Storage Reset
2.对Bulk-In端点Clear Feature
3.对Bulk-Out端点Clear Feature
设备通过STALL对应管道来中止传输。但是总线上是不是出现STALL也要看设备准备STALL时刚好主机是否有继续请求数据。
如果CBW无效,设备对后续的Bulk-IN进行STALL。
设备对后续的Bulk-Out进行STALL或者接收但是丢弃。
上述状态保持到主机进行Reset Recovery。
CBW无意义时设备如何响应未定义。
设备对于内部错误
会STALL后面任意的IN和OUT传输, 并在CSW中返回Phase Error 即(bCSWStatus = 02h);
或者STALL后面所有的IN和OUT传输, 直到Reset Recovery。
在识别出CBW有效且有意义后,设备仍可能无法满足命令。设备应通过返回命令失败状态(bCSWStatus=01h)来报告此情况。
在识别出CBW有效且有意义后,在没有内部错误的情况下,设备可能会检测到无法满足主机对数据传输期望的情况,如bmCBWFlags字段的Direction位和CBW的dCBWDataTransferLength字段所示。在某些情况下,设备可能需要重置才能恢复。在这些情况下,设备应返回相位误差状态(bCSWStatus=02h)。关于哪些情况导致相位错误与非相位错误状态的详细信息,有“十三种情况”如下
上表按照列看,分三种情况
1~3
即Hn, 主机设置dCBWDataTransferLength=0,即不期望后续传输数据.
一般要求
方向位的值不应影响这些情况的结果
对于主机要求如下
对于设备要求如下
4~8
当dCBWDataTransferLength不为零且方向位为1(数据输入)时,表示主机期望从设备接收数据。
对于主机要求如下
对于设备要求如下
9~13
当dCBWDataTransferLength不为零且方向位为0(数据输出)时,表示主机希望向设备发送数据。
一般要求
主机不得发送零长度的数据包
对于主机要求
对于设备要求
以上分享了MSC(USB Mass Storage)设备的描述符,类请求,命令数据状态协议。可以看到MSC设备其实是比较简单的,从描述符和交互来说都比较简单清晰,不像UVC,UAC等有非常多的类相关的请求。