? ? 本文來分享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等有非常多的類相關的請求。