UsbStorageBot.Mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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) : LONGINT;
  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) : LONGINT;
  75. VAR status : Usbdi.Status; i, residual : LONGINT;
  76. b: Usbdi.Buffer;
  77. BEGIN (* No concurrency allowed *)
  78. ASSERT((cmdlen > 0) & (cmdlen <= 16)); (* [2], page 14 *)
  79. (* set up dCBWSignature *)
  80. CBWbuffer[0] := 55X; CBWbuffer[1] := 53X; CBWbuffer[2] := 42X; CBWbuffer[3] := 43X;
  81. (* set up dCBWTag - will be echoed by the device *)
  82. INC(seqNbr);
  83. CBWbuffer[4] := CHR(seqNbr);
  84. CBWbuffer[5] := CHR(LSH(seqNbr, -8));
  85. CBWbuffer[6] := CHR(LSH(seqNbr, -16));
  86. CBWbuffer[7] := CHR(LSH(seqNbr, -24));
  87. (* set up dCBWDataTransferLength *)
  88. CBWbuffer[8] := CHR(bufferlen);
  89. CBWbuffer[9] := CHR(LSH(bufferlen, -8));
  90. CBWbuffer[10] := CHR(LSH(bufferlen, -16));
  91. CBWbuffer[11] := CHR(LSH(bufferlen, -24));
  92. (* set up bmCBWFlags *)
  93. IF dir = Base.DataIn THEN CBWbuffer[12] := 80X; ELSE CBWbuffer[12] := 0X; END;
  94. (* set bCBWLUN *)
  95. CBWbuffer[13] := CHR(SYSTEM.VAL(LONGINT, LSH(SYSTEM.VAL(SET, ORD(cmd[1])) * {5..7}, -5)));
  96. (*set bCBWCBLength *)
  97. CBWbuffer[14] := CHR(cmdlen);
  98. FOR i := 15 TO 30 DO CBWbuffer[i] := 0X; END;
  99. (* copy CBWCB *)
  100. FOR i := 0 TO cmdlen-1 DO CBWbuffer[15+i] := cmd[i]; END;
  101. IF Debug.Trace & Debug.traceCBWs THEN
  102. KernelLog.String("Sending CBW: "); FOR i := 0 TO LEN(CBWbuffer)-1 DO KernelLog.Hex(ORD(CBWbuffer[i]), -2); KernelLog.Char(" "); END; KernelLog.Ln;
  103. END;
  104. (* send the CBW *)
  105. IF Base.performance = Usbdi.MaxPerformance THEN bulkOutPipe.mode := Usbdi.MaxPerformance; ELSE bulkOutPipe.mode := Usbdi.MinCpu; END;
  106. status := bulkOutPipe.Transfer(31, 0, CBWbuffer);
  107. IF (status = Usbdi.Disconnected) THEN
  108. RETURN Base.ResDisconnected;
  109. ELSIF status # Usbdi.Ok THEN (* sending the CBW failed -> Perform reset recovery [2], page 15 *)
  110. RETURN Base.ResFatalError;
  111. END;
  112. (* If there is data to send, enter the data stage *)
  113. IF bufferlen # 0 THEN
  114. NEW(b, bufferlen);
  115. FOR i := 0 TO bufferlen - 1 DO b[i] := buffer[ofs + i] END;
  116. IF Debug.Trace & Debug.traceScTransfers THEN
  117. KernelLog.String("UsbStorage: Data Phase: Transfering "); KernelLog.Int(bufferlen, 0); KernelLog.String(" Bytes to ");
  118. IF dir = Base.DataIn THEN KernelLog.String("Host Controller"); ELSIF dir = Base.DataOut THEN KernelLog.String("Device"); ELSE HALT(301); END;
  119. KernelLog.Ln;
  120. END;
  121. IF dir = Base.DataIn THEN
  122. IF Base.performance = Usbdi.MaxPerformance THEN bulkInPipe.mode := Usbdi.Normal; ELSE bulkInPipe.mode := Usbdi.MinCpu; END;
  123. bulkInPipe.SetTimeout(timeout);
  124. status := bulkInPipe.Transfer(bufferlen, 0(*ofs*), b);
  125. tlen := bulkInPipe.GetActLen();
  126. ELSIF dir = Base.DataOut THEN
  127. bulkOutPipe.SetTimeout(timeout);
  128. IF Base.performance = Usbdi.MaxPerformance THEN bulkOutPipe.mode := Usbdi.Normal; ELSE bulkOutPipe.mode := Usbdi.MinCpu; END;
  129. status := bulkOutPipe.Transfer(bufferlen, 0(*ofs*), b);
  130. tlen := bulkOutPipe.GetActLen();
  131. ELSE HALT(303);
  132. END;
  133. FOR i := 0 TO tlen - 1 DO buffer[ofs + i] := b[i] END;
  134. (* clear halt if STALL occured, but do not abort!!! *)
  135. IF status = Usbdi.Stalled THEN
  136. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: Stall on BulkOnly data phase"); KernelLog.Ln; END;
  137. (* only abort if clear halt fails *)
  138. IF ((dir = Base.DataIn) & (~bulkInPipe.ClearHalt())) OR ((dir = Base.DataOut) & (~bulkOutPipe.ClearHalt())) THEN
  139. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on BulkOnly clear halt"); KernelLog.Ln; END;
  140. RETURN Base.ResFatalError;
  141. END;
  142. ELSIF status = Usbdi.InProgress THEN
  143. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Timeout on BulkOnly data phase"); KernelLog.Ln; END;
  144. RETURN Base.ResTimeout;
  145. ELSIF status = Usbdi.Disconnected THEN
  146. RETURN Base.ResDisconnected;
  147. ELSIF status = Usbdi.Error THEN
  148. (* allow short packets and stalls !!! *)
  149. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on BulkOnly data phase"); KernelLog.Ln; END;
  150. RETURN Base.ResFatalError;
  151. END;
  152. ELSE
  153. tlen := 0;
  154. END;
  155. (* enter the status phase - Get the CSW *)
  156. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorage: Getting BulkOnly CSW"); KernelLog.Ln; END;
  157. IF Base.performance = Usbdi.MaxPerformance THEN bulkInPipe.mode := Usbdi.MaxPerformance; ELSE bulkInPipe.mode := Usbdi.MinCpu; END;
  158. bulkInPipe.SetTimeout(timeout);
  159. status := bulkInPipe.Transfer(13, 0, CSWbuffer);
  160. IF status = Usbdi.InProgress THEN
  161. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Timeout in CSW phase"); KernelLog.Ln; END;
  162. RETURN Base.ResFatalError
  163. ELSIF status = Usbdi.Disconnected THEN
  164. RETURN Base.ResDisconnected;
  165. ELSIF status # Usbdi.Ok THEN
  166. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: Could not get CSW, must retry CSW phase"); KernelLog.Ln; END;
  167. IF (status = Usbdi.Stalled) & ~bulkInPipe.ClearHalt() THEN
  168. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on BulkOnly clear halt"); KernelLog.Ln; END;
  169. RETURN Base.ResFatalError;
  170. END;
  171. (* Host shall retry to get CSW ([2], page 19) *)
  172. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: Retrying BulkOnly CSW"); KernelLog.Ln; END;
  173. status := bulkInPipe.Transfer(13, 0, CSWbuffer);
  174. IF (status = Usbdi.Disconnected) THEN
  175. RETURN Base.ResDisconnected;
  176. ELSIF status # Usbdi.Ok THEN
  177. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: 2nd try to get CSW failed"); KernelLog.Ln; END;
  178. RETURN Base.ResFatalError;
  179. END;
  180. END;
  181. IF Debug.Trace & Debug.traceCSWs THEN
  182. KernelLog.String("Received CSW: "); FOR i := 0 TO 12 DO KernelLog.Hex(ORD(CSWbuffer[i]), -2); KernelLog.Char(" "); END; KernelLog.Ln;
  183. END;
  184. (* Check whether the CSW is valid. If it's not, perform a reset recovery ([2], page 18) *)
  185. (* Validity: Check CSW signature *)
  186. IF (CSWbuffer[0] # 55X) OR (CSWbuffer[1] # 53X) OR (CSWbuffer[2] # 42X) OR (CSWbuffer[3] # 53X) THEN
  187. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Device did not send a valid CSW! (wrong signature)"); KernelLog.Ln; END;
  188. RETURN Base.ResFatalError;
  189. END;
  190. (* Validity: check the dCSWTag *)
  191. IF (CSWbuffer[4] # CBWbuffer[4]) OR (CSWbuffer[5] # CBWbuffer[5]) OR (CSWbuffer[6] # CBWbuffer[6]) OR (CSWbuffer[7] # CBWbuffer[7]) THEN
  192. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Device sent wrong tag in CSW"); KernelLog.Ln; END;
  193. RETURN Base.ResFatalError;
  194. END;
  195. (* Check whether the CSW is meaningful *)
  196. residual := ORD(CSWbuffer[8]) + 10H*ORD(CSWbuffer[9]) + 100H*ORD(CSWbuffer[10]) + 1000H*ORD(CSWbuffer[11]);
  197. (* Meaning: bCSWStatus *)
  198. IF (CSWbuffer[12] = 0X) & (residual <= bufferlen) THEN (* CSW meaningful; Command Passed *)
  199. IF residual # 0 THEN
  200. tlen := bufferlen - residual;
  201. RETURN Base.ResShortTransfer;
  202. ELSE
  203. RETURN Base.ResOk;
  204. END;
  205. ELSIF (CSWbuffer[12] = 1X) & (residual <= bufferlen) THEN (* CSW meaningful; Command Error *)
  206. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: CSW reports Error"); KernelLog.Ln; END;
  207. RETURN Base.ResError;
  208. ELSIF CSWbuffer[12] = 2X THEN (* Phase Error: Perform reset recovery [2], page 16*)
  209. IF Debug.Trace & Debug.Trace & Debug.traceCSWs THEN KernelLog.String("UsbStorage: CSW reports Phase Error"); KernelLog.Ln; END;
  210. RETURN Base.ResFatalError;
  211. ELSE (* CSW not meaningful -> Perform reset recovery *)
  212. IF Debug.Trace THEN KernelLog.String("UsbStorage: CSW not meaningful"); KernelLog.Ln; END;
  213. RETURN Base.ResFatalError;
  214. END;
  215. END Transport;
  216. PROCEDURE &Init*;
  217. BEGIN
  218. Init^; NEW(CBWbuffer, 31); NEW(CSWbuffer, 13); seqNbr := 0;
  219. END Init;
  220. END BulkOnlyTransport;
  221. END UsbStorageBot.