UsbStorageBot.Mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. MODULE UsbStorageBot; (** AUTHOR "staubesv"; PURPOSE "Bulk-Only transport layer of USB mass storage driver"; *)
  2. (**
  3. * References:
  4. *
  5. * - Universal Serial Bus Mass Storage Class Bulk-Only Transport, Revision 1.0, September 31, 1999
  6. * www.usb.org
  7. *
  8. * History:
  9. *
  10. * 09.02.2006 First release (staubesv)
  11. * 05.07.2006 Adapted to Usbi (staubesv)
  12. *)
  13. IMPORT
  14. SYSTEM, KernelLog,
  15. Usbdi, Base := UsbStorageBase, Debug := UsbDebug;
  16. TYPE
  17. (* USB mass storage class bulk only transport layer *)
  18. BulkOnlyTransport* = OBJECT(Base.StorageDriver)
  19. VAR
  20. CBWbuffer : Usbdi.BufferPtr;
  21. CSWbuffer : Usbdi.BufferPtr;
  22. seqNbr : LONGINT;
  23. (* Perform reset recovery, i.e. send Bulk-Only Mass Storage Reset command via default control pipe and *)
  24. (* then clear the EndpointHalt feature of the bulk in and bulk out endpoints of the USB device. The request *)
  25. (* shall ready the device for the next CBW from the host. See [2], pages 7 & 16 *)
  26. PROCEDURE Reset*(timeout : LONGINT) : WORD;
  27. VAR critical : BOOLEAN; status : Usbdi.Status;
  28. BEGIN
  29. IF Debug.Trace & Debug.traceScRequests THEN KernelLog.String("UsbStorage: Doing reset recovery ... "); END;
  30. (* Mass storage devices request: Bulk-Only Mass Storage Reset *)
  31. status := device.Request(Usbdi.ToDevice + Usbdi.Class + Usbdi.Interface, 255, 0, interface.bInterfaceNumber, 0, Usbdi.NoData);
  32. IF (status = Usbdi.Disconnected) THEN
  33. RETURN Base.ResDisconnected;
  34. ELSIF status # Usbdi.Ok THEN
  35. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Mass storage reset failed."); KernelLog.Ln; END;
  36. RETURN Base.ResFatalError;
  37. END;
  38. IF bulkInPipe.IsHalted() THEN critical := ~bulkInPipe.ClearHalt(); END;
  39. IF bulkOutPipe.IsHalted() THEN critical := critical OR ~bulkOutPipe.ClearHalt(); END;
  40. IF critical THEN
  41. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on BulkOnly reset ClearHalt"); KernelLog.Ln; END;
  42. RETURN Base.ResFatalError;
  43. END;
  44. IF Debug.Trace & Debug.traceScRequests THEN KernelLog.String("UsbStorage: Reset recovery succeeded."); KernelLog.Ln; END;
  45. RETURN Base.ResOk;
  46. END Reset;
  47. (* The Get Max LUN device request is used to determine the number of logical units supported by the device *)
  48. PROCEDURE GetMaxLun*(VAR maxlun : LONGINT): LONGINT;
  49. VAR buffer : Usbdi.BufferPtr; status : Usbdi.Status;
  50. BEGIN
  51. IF Debug.Trace & Debug.traceScRequests THEN KernelLog.String("UsbStorage: GetMaxLUN.... "); END;
  52. NEW(buffer, 1);
  53. status := device.Request(Usbdi.ToHost + Usbdi.Class + Usbdi.Interface, 254, 0, interface.bInterfaceNumber, 1, buffer^);
  54. IF status = Usbdi.Ok THEN
  55. maxlun := ORD(buffer[0]);
  56. IF Debug.Trace & Debug.traceScRequests THEN KernelLog.String("MaxLUN is: "); KernelLog.Int(maxlun, 0); KernelLog.Ln; END;
  57. RETURN Base.ResOk;
  58. ELSIF status = Usbdi.Stalled THEN (* Devices that do not suppoert multiple LUNs may stall this command *)
  59. maxlun := 0;
  60. IF Debug.Trace & Debug.traceScRequests THEN KernelLog.String("MaxLUN request not supported (STALL)"); KernelLog.Ln; END;
  61. RETURN Base.ResOk;
  62. ELSIF status = Usbdi.Disconnected THEN
  63. RETURN Base.ResDisconnected;
  64. ELSE
  65. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: GetMaxLUN request failed."); KernelLog.Ln; END;
  66. RETURN Base.ResFatalError;
  67. END;
  68. END GetMaxLun;
  69. (* Process a bulk-only transfer. A three stage protocol is used: *)
  70. (* 1. Send command block wrapper (CBW) to device *)
  71. (* 2. Dataphase (optional) *)
  72. (* 3. Receive command status word (CSW) from device *)
  73. PROCEDURE Transport*(cmd : ARRAY OF CHAR; cmdlen : LONGINT; dir : SET;
  74. VAR buffer : ARRAY OF CHAR; ofs, bufferlen : LONGINT; VAR tlen : LONGINT; timeout : LONGINT) : WORD;
  75. VAR status : Usbdi.Status; i, residual : LONGINT;
  76. BEGIN (* No concurrency allowed *)
  77. ASSERT((cmdlen > 0) & (cmdlen <= 16)); (* [2], page 14 *)
  78. (* set up dCBWSignature *)
  79. CBWbuffer[0] := 55X; CBWbuffer[1] := 53X; CBWbuffer[2] := 42X; CBWbuffer[3] := 43X;
  80. (* set up dCBWTag - will be echoed by the device *)
  81. INC(seqNbr);
  82. CBWbuffer[4] := CHR(seqNbr);
  83. CBWbuffer[5] := CHR(LSH(seqNbr, -8));
  84. CBWbuffer[6] := CHR(LSH(seqNbr, -16));
  85. CBWbuffer[7] := CHR(LSH(seqNbr, -24));
  86. (* set up dCBWDataTransferLength *)
  87. CBWbuffer[8] := CHR(bufferlen);
  88. CBWbuffer[9] := CHR(LSH(bufferlen, -8));
  89. CBWbuffer[10] := CHR(LSH(bufferlen, -16));
  90. CBWbuffer[11] := CHR(LSH(bufferlen, -24));
  91. (* set up bmCBWFlags *)
  92. IF dir = Base.DataIn THEN CBWbuffer[12] := 80X; ELSE CBWbuffer[12] := 0X; END;
  93. (* set bCBWLUN *)
  94. CBWbuffer[13] := CHR(SYSTEM.VAL(LONGINT, LSH(SYSTEM.VAL(SET, ORD(cmd[1])) * {5..7}, -5)));
  95. (*set bCBWCBLength *)
  96. CBWbuffer[14] := CHR(cmdlen);
  97. FOR i := 15 TO 30 DO CBWbuffer[i] := 0X; END;
  98. (* copy CBWCB *)
  99. FOR i := 0 TO cmdlen-1 DO CBWbuffer[15+i] := cmd[i]; END;
  100. IF Debug.Trace & Debug.traceCBWs THEN
  101. KernelLog.String("Sending CBW: "); FOR i := 0 TO LEN(CBWbuffer)-1 DO KernelLog.Hex(ORD(CBWbuffer[i]), -2); KernelLog.Char(" "); END; KernelLog.Ln;
  102. END;
  103. (* send the CBW *)
  104. IF Base.performance = Usbdi.MaxPerformance THEN bulkOutPipe.mode := Usbdi.MaxPerformance; ELSE bulkOutPipe.mode := Usbdi.MinCpu; END;
  105. status := bulkOutPipe.Transfer(31, 0, CBWbuffer^);
  106. IF (status = Usbdi.Disconnected) THEN
  107. RETURN Base.ResDisconnected;
  108. ELSIF status # Usbdi.Ok THEN (* sending the CBW failed -> Perform reset recovery [2], page 15 *)
  109. RETURN Base.ResFatalError;
  110. END;
  111. (* If there is data to send, enter the data stage *)
  112. IF bufferlen # 0 THEN
  113. IF Debug.Trace & Debug.traceScTransfers THEN
  114. KernelLog.String("UsbStorage: Data Phase: Transfering "); KernelLog.Int(bufferlen, 0); KernelLog.String(" Bytes to ");
  115. IF dir = Base.DataIn THEN KernelLog.String("Host Controller"); ELSIF dir = Base.DataOut THEN KernelLog.String("Device"); ELSE HALT(301); END;
  116. KernelLog.Ln;
  117. END;
  118. IF dir = Base.DataIn THEN
  119. IF Base.performance = Usbdi.MaxPerformance THEN bulkInPipe.mode := Usbdi.Normal; ELSE bulkInPipe.mode := Usbdi.MinCpu; END;
  120. bulkInPipe.SetTimeout(timeout);
  121. status := bulkInPipe.Transfer(bufferlen, ofs, buffer);
  122. tlen := bulkInPipe.GetActLen();
  123. ELSIF dir = Base.DataOut THEN
  124. bulkOutPipe.SetTimeout(timeout);
  125. IF Base.performance = Usbdi.MaxPerformance THEN bulkOutPipe.mode := Usbdi.Normal; ELSE bulkOutPipe.mode := Usbdi.MinCpu; END;
  126. status := bulkOutPipe.Transfer(bufferlen, ofs, buffer);
  127. tlen := bulkOutPipe.GetActLen();
  128. ELSE HALT(303);
  129. END;
  130. (* clear halt if STALL occured, but do not abort!!! *)
  131. IF status = Usbdi.Stalled THEN
  132. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: Stall on BulkOnly data phase"); KernelLog.Ln; END;
  133. (* only abort if clear halt fails *)
  134. IF ((dir = Base.DataIn) & (~bulkInPipe.ClearHalt())) OR ((dir = Base.DataOut) & (~bulkOutPipe.ClearHalt())) THEN
  135. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on BulkOnly clear halt"); KernelLog.Ln; END;
  136. RETURN Base.ResFatalError;
  137. END;
  138. ELSIF status = Usbdi.InProgress THEN
  139. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Timeout on BulkOnly data phase"); KernelLog.Ln; END;
  140. RETURN Base.ResTimeout;
  141. ELSIF status = Usbdi.Disconnected THEN
  142. RETURN Base.ResDisconnected;
  143. ELSIF status = Usbdi.Error THEN
  144. (* allow short packets and stalls !!! *)
  145. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on BulkOnly data phase"); KernelLog.Ln; END;
  146. RETURN Base.ResFatalError;
  147. END;
  148. ELSE
  149. tlen := 0;
  150. END;
  151. (* enter the status phase - Get the CSW *)
  152. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorage: Getting BulkOnly CSW"); KernelLog.Ln; END;
  153. IF Base.performance = Usbdi.MaxPerformance THEN bulkInPipe.mode := Usbdi.MaxPerformance; ELSE bulkInPipe.mode := Usbdi.MinCpu; END;
  154. bulkInPipe.SetTimeout(timeout);
  155. status := bulkInPipe.Transfer(13, 0, CSWbuffer^);
  156. IF status = Usbdi.InProgress THEN
  157. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Timeout in CSW phase"); KernelLog.Ln; END;
  158. RETURN Base.ResFatalError
  159. ELSIF status = Usbdi.Disconnected THEN
  160. RETURN Base.ResDisconnected;
  161. ELSIF status # Usbdi.Ok THEN
  162. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: Could not get CSW, must retry CSW phase"); KernelLog.Ln; END;
  163. IF (status = Usbdi.Stalled) & ~bulkInPipe.ClearHalt() THEN
  164. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on BulkOnly clear halt"); KernelLog.Ln; END;
  165. RETURN Base.ResFatalError;
  166. END;
  167. (* Host shall retry to get CSW ([2], page 19) *)
  168. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: Retrying BulkOnly CSW"); KernelLog.Ln; END;
  169. status := bulkInPipe.Transfer(13, 0, CSWbuffer^);
  170. IF (status = Usbdi.Disconnected) THEN
  171. RETURN Base.ResDisconnected;
  172. ELSIF status # Usbdi.Ok THEN
  173. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: 2nd try to get CSW failed"); KernelLog.Ln; END;
  174. RETURN Base.ResFatalError;
  175. END;
  176. END;
  177. IF Debug.Trace & Debug.traceCSWs THEN
  178. KernelLog.String("Received CSW: "); FOR i := 0 TO 12 DO KernelLog.Hex(ORD(CSWbuffer[i]), -2); KernelLog.Char(" "); END; KernelLog.Ln;
  179. END;
  180. (* Check whether the CSW is valid. If it's not, perform a reset recovery ([2], page 18) *)
  181. (* Validity: Check CSW signature *)
  182. IF (CSWbuffer[0] # 55X) OR (CSWbuffer[1] # 53X) OR (CSWbuffer[2] # 42X) OR (CSWbuffer[3] # 53X) THEN
  183. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Device did not send a valid CSW! (wrong signature)"); KernelLog.Ln; END;
  184. RETURN Base.ResFatalError;
  185. END;
  186. (* Validity: check the dCSWTag *)
  187. IF (CSWbuffer[4] # CBWbuffer[4]) OR (CSWbuffer[5] # CBWbuffer[5]) OR (CSWbuffer[6] # CBWbuffer[6]) OR (CSWbuffer[7] # CBWbuffer[7]) THEN
  188. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Device sent wrong tag in CSW"); KernelLog.Ln; END;
  189. RETURN Base.ResFatalError;
  190. END;
  191. (* Check whether the CSW is meaningful *)
  192. residual := ORD(CSWbuffer[8]) + 10H*ORD(CSWbuffer[9]) + 100H*ORD(CSWbuffer[10]) + 1000H*ORD(CSWbuffer[11]);
  193. (* Meaning: bCSWStatus *)
  194. IF (CSWbuffer[12] = 0X) & (residual <= bufferlen) THEN (* CSW meaningful; Command Passed *)
  195. IF residual # 0 THEN
  196. tlen := bufferlen - residual;
  197. RETURN Base.ResShortTransfer;
  198. ELSE
  199. RETURN Base.ResOk;
  200. END;
  201. ELSIF (CSWbuffer[12] = 1X) & (residual <= bufferlen) THEN (* CSW meaningful; Command Error *)
  202. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: CSW reports Error"); KernelLog.Ln; END;
  203. RETURN Base.ResError;
  204. ELSIF CSWbuffer[12] = 2X THEN (* Phase Error: Perform reset recovery [2], page 16*)
  205. IF Debug.Trace & Debug.Trace & Debug.traceCSWs THEN KernelLog.String("UsbStorage: CSW reports Phase Error"); KernelLog.Ln; END;
  206. RETURN Base.ResFatalError;
  207. ELSE (* CSW not meaningful -> Perform reset recovery *)
  208. IF Debug.Trace THEN KernelLog.String("UsbStorage: CSW not meaningful"); KernelLog.Ln; END;
  209. RETURN Base.ResFatalError;
  210. END;
  211. END Transport;
  212. PROCEDURE &Init*;
  213. BEGIN
  214. Init^; NEW(CBWbuffer, 31); NEW(CSWbuffer, 13); seqNbr := 0;
  215. END Init;
  216. END BulkOnlyTransport;
  217. END UsbStorageBot.