UsbStorageScm.Mod 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. MODULE UsbStorageScm; (** AUTHOR "cplattner/staubesv"; PURPOSE "SCM transport layer of USB mass storage driver"; *)
  2. (**
  3. * SCSI commands borrowed from SCSI.Mod.
  4. *
  5. * History:
  6. *
  7. * 09.02.2006 First release (staubesv)
  8. *)
  9. IMPORT
  10. SYSTEM, KernelLog, Kernel,
  11. Usbdi, Base := UsbStorageBase, Debug := UsbDebug, UsbStorageCbi;
  12. CONST
  13. (* Constans for the SCM USB-ATAPI Shuttle device *)
  14. ScmATA = 40X; ScmISA = 50X;
  15. (* Data registers *)
  16. ScmUioEpad = 80X; ScmUioCdt = 40X; ScmUio1 = 20X; ScmUio0 = 10X;
  17. (* User i/o enable registers *)
  18. ScmUioDrvrst = 80X; ScmUioAckd = 40X; ScmUioOE1 = 20X; ScmUioOE0 = 10X;
  19. TYPE
  20. (* SCM Shuttle Transport Layer *)
  21. SCMTransport* = OBJECT(UsbStorageCbi.CBITransport) (* same Reset procedure as CBITransport -> inherit it *)
  22. VAR
  23. (* these buffers will be re-used; they are created in &Init *)
  24. command : Usbdi.BufferPtr;
  25. buffer : Usbdi.BufferPtr;
  26. timer : Kernel.Timer;
  27. PROCEDURE ScmShortPack(p1, p2 : CHAR) : INTEGER;
  28. BEGIN
  29. RETURN SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, ORD(p2)*256) + SYSTEM.VAL(SET, ORD(p1)));
  30. END ScmShortPack;
  31. PROCEDURE ScmSendControl(dir : SET; req, reqtyp, value, index : LONGINT; VAR buffer : Usbdi.Buffer;
  32. ofs, bufferlen, timeout : LONGINT) : WORD;
  33. VAR status : Usbdi.Status; ignore : LONGINT;
  34. BEGIN
  35. IF Debug.Trace & Debug.traceScTransfers THEN
  36. KernelLog.String("UsbStorage: Sending SCM Control:"); KernelLog.String(" Direction: ");
  37. IF dir = Base.DataIn THEN KernelLog.String("In");
  38. ELSIF dir = Base.DataOut THEN KernelLog.String("Out");
  39. ELSE KernelLog.String("Unknown");
  40. END;
  41. KernelLog.String(" Bufferlen: "); KernelLog.Int(bufferlen, 0); KernelLog.String(" Offset: "); KernelLog.Int(ofs, 0); KernelLog.Ln;
  42. END;
  43. IF (bufferlen > 0) & (bufferlen+ofs > LEN(buffer)) THEN
  44. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmSendControl: Buffer underrun"); KernelLog.Ln; END;
  45. RETURN Base.ResFatalError;
  46. END;
  47. IF device.Request(SYSTEM.VAL(SET, reqtyp), req, value, index, bufferlen, buffer) # Usbdi.Ok THEN
  48. status := defaultPipe.GetStatus(ignore);
  49. IF status = Usbdi.Stalled THEN
  50. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Stall on Transport SCM Control"); KernelLog.Ln; END;
  51. IF defaultPipe.ClearHalt() THEN
  52. RETURN Base.ResError;
  53. ELSE
  54. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on Transport SCM clear halt on Controlpipe"); KernelLog.Ln; END;
  55. RETURN Base.ResFatalError;
  56. END;
  57. END;
  58. IF status = Usbdi.InProgress THEN
  59. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Timeout on Transport SCM Control"); KernelLog.Ln; END;
  60. RETURN Base.ResTimeout;
  61. ELSIF status = Usbdi.Disconnected THEN
  62. RETURN Base.ResDisconnected;
  63. ELSIF status # Usbdi.Ok THEN
  64. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on Transport SCM Control"); KernelLog.Ln; END;
  65. RETURN Base.ResFatalError;
  66. END;
  67. END;
  68. RETURN Base.ResOk;
  69. END ScmSendControl;
  70. PROCEDURE ScmBulkTransport(dir : SET; VAR buffer : Usbdi.Buffer; ofs, bufferlen : LONGINT;
  71. VAR tlen : LONGINT; timeout : LONGINT) : LONGINT;
  72. VAR status : Usbdi.Status;
  73. BEGIN
  74. IF Debug.Trace & Debug.traceScTransfers THEN
  75. KernelLog.String("UsbStorage: Transfering SCM Data: Direction: ");
  76. IF dir = Base.DataIn THEN KernelLog.String("IN");
  77. ELSIF dir = Base.DataOut THEN KernelLog.String("OUT");
  78. ELSE KernelLog.String("Unknown");
  79. END;
  80. KernelLog.String(" Bufferlen: "); KernelLog.Int(bufferlen, 0); KernelLog.String(" Offset: "); KernelLog.Int(ofs, 0);
  81. KernelLog.Ln;
  82. END;
  83. tlen := 0;
  84. IF bufferlen = 0 THEN RETURN Base.ResOk END;
  85. IF bufferlen + ofs > LEN(buffer) THEN
  86. IF Debug.Level >= Debug.Errors THEN
  87. KernelLog.String("UsbStorage: ScmBulkTransport: Buffer underrun");
  88. KernelLog.String(" (buffer length: "); KernelLog.Int(LEN(buffer), 0); KernelLog.String(")"); KernelLog.Ln;
  89. END;
  90. RETURN Base.ResFatalError;
  91. END;
  92. IF dir = Base.DataIn THEN
  93. bulkInPipe.SetTimeout(timeout);
  94. status := bulkInPipe.Transfer(bufferlen, ofs, buffer);
  95. tlen := bulkInPipe.GetActLen();
  96. ELSIF dir = Base.DataOut THEN
  97. bulkOutPipe.SetTimeout(timeout);
  98. status := bulkOutPipe.Transfer(bufferlen, ofs, buffer);
  99. tlen := bulkOutPipe.GetActLen();
  100. ELSE
  101. HALT(301);
  102. END;
  103. (* clear halt if STALL occured, but do not abort!!! *)
  104. IF status = Usbdi.Stalled THEN
  105. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Stall on SCM data phase"); KernelLog.Ln; END;
  106. (* only abort if clear halt fails *)
  107. IF ((dir=Base.DataIn) & ~bulkInPipe.ClearHalt()) OR ((dir=Base.DataOut) & ~bulkOutPipe.ClearHalt()) THEN
  108. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on SCM bulk clear halt"); KernelLog.Ln; END;
  109. RETURN Base.ResFatalError;
  110. END;
  111. END;
  112. IF status = Usbdi.InProgress THEN
  113. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Timeout on SCM data phase"); KernelLog.Ln; END;
  114. RETURN Base.ResTimeout;
  115. ELSIF status = Usbdi.Disconnected THEN
  116. RETURN Base.ResDisconnected;
  117. ELSIF status = Usbdi.Error THEN
  118. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Failure on SCM bulk"); KernelLog.Ln; END;
  119. RETURN Base.ResFatalError;
  120. END;
  121. IF tlen # bufferlen THEN
  122. IF Debug.Level >= Debug.Errors THEN
  123. KernelLog.String("UsbStorage: ScmBulkTransport short read: ");
  124. KernelLog.Int(bufferlen, 0); KernelLog.Char("/"); KernelLog.Int(tlen, 0); KernelLog.Ln;
  125. END;
  126. RETURN Base.ResShortTransfer;
  127. END;
  128. RETURN Base.ResOk;
  129. END ScmBulkTransport;
  130. PROCEDURE ScmWaitNotBusy(timeout : LONGINT) : WORD;
  131. VAR status : CHAR; res : WORD;
  132. BEGIN
  133. LOOP
  134. res := ScmRead(ScmATA, 17X, status, 1000);
  135. IF res # Base.ResOk THEN
  136. IF (res = Base.ResDisconnected) OR (res = Base.ResFatalError) THEN RETURN res ELSE RETURN Base.ResError END;
  137. ELSIF (SYSTEM.VAL(SET, status) * {0}) # {} THEN
  138. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmWaitNotBusy: check condition"); KernelLog.Ln; END;
  139. RETURN Base.ResError;
  140. ELSIF (SYSTEM.VAL(SET, status) * {5}) # {} THEN
  141. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmWaitNotBusy: device fault"); KernelLog.Ln; END;
  142. RETURN Base.ResFatalError;
  143. ELSIF (SYSTEM.VAL(SET, status) * {7}) = {} THEN
  144. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorage: ScmWaitNotBusy: good"); KernelLog.Ln; END;
  145. RETURN Base.ResOk;
  146. END;
  147. IF timeout # -1 THEN
  148. timeout := timeout - 10; IF timeout < 0 THEN EXIT END;
  149. END;
  150. Wait(10);
  151. END;
  152. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmWaitNotBusy: Timeout"); KernelLog.Ln; END;
  153. RETURN Base.ResTimeout;
  154. END ScmWaitNotBusy;
  155. PROCEDURE ScmReadUserIO(VAR dataflags: CHAR; timeout : LONGINT) : WORD;
  156. VAR res : WORD;
  157. BEGIN
  158. res := ScmSendControl(Base.DataIn, 82H, 0C0H, 0, 0, buffer^, 0, 1, timeout);
  159. dataflags := buffer[0];
  160. RETURN res;
  161. END ScmReadUserIO;
  162. PROCEDURE ScmWriteUserIO(enableflags, dataflags: CHAR; timeout : LONGINT) : WORD;
  163. BEGIN
  164. RETURN ScmSendControl(Base.DataOut, 82H, 40H, ScmShortPack(enableflags, dataflags), 0, Usbdi.NoData, 0, 0, timeout);
  165. END ScmWriteUserIO;
  166. PROCEDURE ScmRead(access, reg : CHAR; VAR content: CHAR; timeout : LONGINT) : WORD;
  167. VAR res : WORD;
  168. BEGIN
  169. res := ScmSendControl(Base.DataIn, ORD(access), 0C0H, ORD(reg), 0, buffer^, 0, 1, timeout);
  170. content := buffer[0];
  171. RETURN res;
  172. END ScmRead;
  173. PROCEDURE ScmWrite(access, reg, content : CHAR; timeout : LONGINT) : WORD;
  174. BEGIN
  175. access := SYSTEM.VAL(CHAR, SYSTEM.VAL(SET, access) + {0});
  176. RETURN ScmSendControl(Base.DataOut, ORD(access), 040H, ScmShortPack(reg, content), 0, Usbdi.NoData, 0, 0, timeout);
  177. END ScmWrite;
  178. PROCEDURE ScmMultipleWrite(access : CHAR; VAR registers, dataout: ARRAY OF CHAR; numregs, timeout : LONGINT) : WORD;
  179. VAR res: WORD; i, tlen : LONGINT;
  180. BEGIN
  181. IF numregs > 7 THEN
  182. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmMultipleWrite: Numregs > 7."); KernelLog.Ln;END;
  183. RETURN Base.ResFatalError;
  184. END;
  185. command[0] := 40X;
  186. command[1] := SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, access)+ {0,1,2}));
  187. command[2] := 0X;
  188. command[3] := 0X;
  189. command[4] := 0X;
  190. command[5] := 0X;
  191. command[6] := CHR(numregs*2);
  192. command[7] := CHR(LSH(numregs*2, -8));
  193. FOR i:= 0 TO numregs - 1 DO
  194. buffer[i*2] := registers[i];
  195. buffer[(i*2)+1] := dataout[i];
  196. END;
  197. res := ScmSendControl(Base.DataOut, 80H, 040H, 0, 0, command^, 0, 8, timeout);
  198. IF res # Base.ResOk THEN RETURN res END;
  199. res := ScmBulkTransport(Base.DataOut, buffer^, 0, numregs*2, tlen, timeout);
  200. IF res # Base.ResOk THEN RETURN res END;
  201. RETURN ScmWaitNotBusy(timeout);
  202. END ScmMultipleWrite;
  203. PROCEDURE ScmReadBlock(access, reg : CHAR; VAR content : Usbdi.Buffer; ofs, len: LONGINT; VAR tlen : LONGINT; timeout : LONGINT): WORD;
  204. VAR res : WORD;
  205. BEGIN
  206. command[0] := 0C0X;
  207. command[1] := SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, access)+ {1}));
  208. command[2] := reg;
  209. command[3] := 0X;
  210. command[4] := 0X;
  211. command[5] := 0X;
  212. command[6] := CHR(len);
  213. command[7] := CHR(LSH(len, -8));
  214. tlen := 0;
  215. res := ScmSendControl(Base.DataOut, 80H, 40H, 0, 0, command^, 0, 8, timeout);
  216. IF res # Base.ResOk THEN RETURN res END;
  217. res := ScmBulkTransport(Base.DataIn, content, ofs, len, tlen, timeout);
  218. RETURN res;
  219. END ScmReadBlock;
  220. PROCEDURE ScmWriteBlock(access, reg : CHAR; VAR content : Usbdi.Buffer; ofs, len : LONGINT; VAR tlen : LONGINT; timeout : LONGINT): WORD;
  221. VAR res : WORD;
  222. BEGIN
  223. command[0] := 40X;
  224. command[1] := SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, access)+ {0,1}));
  225. command[2] := reg;
  226. command[3] := 0X;
  227. command[4] := 0X;
  228. command[5] := 0X;
  229. command[6] := CHR(len);
  230. command[7] := CHR(LSH(len, -8));
  231. tlen := 0;
  232. res := ScmSendControl(Base.DataOut, 80H, 40H, 0, 0, command^, 0, 8, timeout);
  233. IF res # Base.ResOk THEN RETURN res END;
  234. res := ScmBulkTransport(Base.DataOut, content, ofs, len, tlen, timeout);
  235. IF res # Base.ResOk THEN RETURN res END;
  236. RETURN ScmWaitNotBusy(timeout);
  237. END ScmWriteBlock;
  238. PROCEDURE ScmRWBlockTest(access : CHAR; VAR registers, dataout : ARRAY OF CHAR;
  239. numregs :INTEGER; datareg, statusreg, atapitimeout, qualifier : CHAR; dir : SET; VAR content : Usbdi.Buffer;
  240. ofs, contentlen: LONGINT; VAR tlen : LONGINT; timeout : LONGINT): WORD;
  241. VAR
  242. tmpreg : CHAR;
  243. status : CHAR;
  244. i, msgindex, msglen : INTEGER;
  245. tmplen : LONGINT;
  246. res : WORD;
  247. BEGIN
  248. IF numregs > 19 THEN
  249. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmRWBlockTest too many registers"); KernelLog.Ln; END;
  250. RETURN Base.ResFatalError;
  251. END;
  252. ASSERT(LEN(command)>=16);
  253. command[0] := 40X;
  254. command[1] := SYSTEM.VAL(CHAR, SYSTEM.VAL(SET,access) + {0,1,2});
  255. command[2] := 7X;
  256. command[3] := 17X;
  257. command[4] := 0FCX;
  258. command[5] := 0E7X;
  259. command[6] := CHR(numregs*2);
  260. command[7] := CHR(LSH(numregs*2, -8));
  261. IF dir = Base.DataOut THEN
  262. command[8] := 40X;
  263. command[9] := SYSTEM.VAL(CHAR, SYSTEM.VAL(SET, access) + {0,2});
  264. ELSIF dir = Base.DataIn THEN
  265. command[8] := 0C0X;
  266. command[9] := SYSTEM.VAL(CHAR, SYSTEM.VAL(SET, access) + {2});
  267. ELSE
  268. HALT(303)
  269. END;
  270. command[10] := datareg;
  271. command[11] := statusreg;
  272. command[12] := atapitimeout;
  273. command[13] := qualifier;
  274. command[14] := CHR(contentlen);
  275. command[15] := CHR(LSH(contentlen, -8));
  276. FOR i:=0 TO numregs -1 DO
  277. buffer[i*2] := registers[i]; buffer[(i*2)+1] := dataout[i];
  278. END;
  279. tlen := 0;
  280. FOR i := 0 TO 19 DO
  281. IF i = 0 THEN msgindex := 0; msglen := 16 ELSE msgindex := 8; msglen := 8 END;
  282. res := ScmSendControl(Base.DataOut, 80H, 40H, 0, 0, command^, msgindex, msglen, 1000);
  283. IF res # Base.ResOk THEN
  284. IF (res = Base.ResFatalError) OR (res = Base.ResTimeout) OR (res = Base.ResDisconnected) THEN RETURN res ELSE RETURN Base.ResError END;
  285. END;
  286. IF i = 0 THEN
  287. res := ScmBulkTransport(Base.DataOut, buffer^, 0, numregs*2, tmplen, 1000);
  288. IF res # Base.ResOk THEN
  289. IF (res = Base.ResFatalError) OR (res = Base.ResTimeout) OR (res = Base.ResDisconnected) THEN RETURN res ELSE RETURN Base.ResError END;
  290. END;
  291. END;
  292. res := ScmBulkTransport(dir, content, 0, contentlen, tlen, timeout);
  293. IF res = Base.ResShortTransfer THEN
  294. IF (dir = Base.DataIn) & (i=0) THEN (* hm. makes somehow no sense, but that's life *)
  295. IF ~bulkOutPipe.ClearHalt() THEN
  296. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmRWBlockTest clear halt failed"); KernelLog.Ln; END;
  297. END
  298. END;
  299. IF dir = Base.DataOut THEN tmpreg := 17X; ELSE tmpreg := 0EX; END;
  300. res := ScmRead(ScmATA, tmpreg, status, 1000);
  301. IF res # Base.ResOk THEN
  302. IF (res = Base.ResFatalError) OR (res = Base.ResDisconnected) OR (res = Base.ResTimeout) THEN RETURN res ELSE RETURN Base.ResError END;
  303. ELSIF (SYSTEM.VAL(SET, status) * {0}) # {} THEN
  304. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmRWBlockTest: check condition"); KernelLog.Ln; END;
  305. RETURN Base.ResError;
  306. ELSIF (SYSTEM.VAL(SET, status) * {5}) # {} THEN
  307. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmRWBlockTest: device fault"); KernelLog.Ln; END;
  308. RETURN Base.ResFatalError;
  309. END;
  310. ELSE
  311. RETURN ScmWaitNotBusy(timeout);
  312. END;
  313. END;
  314. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmRWBlockTest failed 20 times!"); KernelLog.Ln; END;
  315. RETURN Base.ResError;
  316. END ScmRWBlockTest;
  317. PROCEDURE ScmSelectAndTestRegisters() : BOOLEAN;
  318. VAR selector : INTEGER; status : CHAR;
  319. BEGIN
  320. FOR selector := 0A0H TO 0B0H BY 10H DO (* actually, test 0A0H and 0B0H *)
  321. IF ScmWrite(ScmATA, 16X, CHR(selector), 1000) # Base.ResOk THEN RETURN FALSE END;
  322. IF ScmRead(ScmATA, 17X, status, 1000) # Base.ResOk THEN RETURN FALSE END;
  323. IF ScmRead(ScmATA, 16X, status, 1000) # Base.ResOk THEN RETURN FALSE END;
  324. IF ScmRead(ScmATA, 14X, status, 1000) # Base.ResOk THEN RETURN FALSE END;
  325. IF ScmRead(ScmATA, 15X, status, 1000) # Base.ResOk THEN RETURN FALSE END;
  326. IF ScmWrite(ScmATA, 14X, 55X, 1000) # Base.ResOk THEN RETURN FALSE END;
  327. IF ScmWrite(ScmATA, 15X, 0AAX, 1000) # Base.ResOk THEN RETURN FALSE END;
  328. IF ScmRead(ScmATA, 14X, status, 1000) # Base.ResOk THEN RETURN FALSE END;
  329. IF ScmRead(ScmATA, 15X, status, 1000) # Base.ResOk THEN RETURN FALSE END;
  330. END;
  331. RETURN TRUE;
  332. END ScmSelectAndTestRegisters;
  333. PROCEDURE ScmSetShuttleFeatures(externaltrigger, eppcontrol, maskbyte, testpattern, subcountH, subcountL : CHAR) : BOOLEAN;
  334. BEGIN
  335. command[0] := 40X;
  336. command[1] := 81X;
  337. command[2] := eppcontrol;
  338. command[3] := externaltrigger;
  339. command[4] := testpattern;
  340. command[5] := maskbyte;
  341. command[6] := subcountL;
  342. command[7] := subcountH;
  343. IF ScmSendControl(Base.DataOut, 80H, 40H, 0, 0, command^, 0, 8, 1000) # Base.ResOk THEN
  344. RETURN FALSE;
  345. ELSE
  346. RETURN TRUE;
  347. END;
  348. END ScmSetShuttleFeatures;
  349. PROCEDURE Initialization*() : BOOLEAN;
  350. VAR status : CHAR; res : WORD;
  351. BEGIN
  352. IF Debug.Trace & Debug.traceScInit THEN KernelLog.String("UsbStorage: Initializing SCM USB-ATAPI Shuttle... "); KernelLog.Ln; END;
  353. res := ScmWriteUserIO(SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, ScmUioOE0) + SYSTEM.VAL(SET, ScmUioOE1))),
  354. SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, ScmUioEpad) + SYSTEM.VAL(SET, ScmUio1))), 1000);
  355. IF res # Base.ResOk THEN
  356. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 1"); KernelLog.Ln; END;
  357. RETURN FALSE;
  358. END;
  359. Wait(2000);
  360. res := ScmReadUserIO(status, 1000);
  361. IF res # Base.ResOk THEN
  362. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 2"); KernelLog.Ln; END;
  363. RETURN FALSE;
  364. END;
  365. res := ScmReadUserIO(status, 1000);
  366. IF res # Base.ResOk THEN
  367. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 3"); KernelLog.Ln; END;
  368. RETURN FALSE;
  369. END;
  370. res := ScmWriteUserIO(SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, ScmUioDrvrst) + SYSTEM.VAL(SET, ScmUioOE0)
  371. + SYSTEM.VAL(SET, ScmUioOE1))), SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, ScmUioEpad)
  372. + SYSTEM.VAL(SET, ScmUio1))), 1000);
  373. IF res # Base.ResOk THEN
  374. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 4"); KernelLog.Ln; END;
  375. RETURN FALSE;
  376. END;
  377. res := ScmWriteUserIO(SYSTEM.VAL(CHAR, SYSTEM.VAL(SET, ScmUioOE0) + SYSTEM.VAL(SET, ScmUioOE1)),
  378. SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, ScmUioEpad) + SYSTEM.VAL(SET, ScmUio1))), 1000);
  379. IF res # Base.ResOk THEN
  380. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 5"); KernelLog.Ln; END;
  381. RETURN FALSE;
  382. END;
  383. Wait(250);
  384. res := ScmWrite(ScmISA, 03FX, 080X, 1000);
  385. IF res # Base.ResOk THEN
  386. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 6"); KernelLog.Ln; END;
  387. RETURN FALSE;
  388. END;
  389. res := ScmRead(ScmISA, 027X, status, 1000);
  390. IF res # Base.ResOk THEN
  391. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 7"); KernelLog.Ln; END;
  392. RETURN FALSE;
  393. END;
  394. res := ScmReadUserIO(status, 1000);
  395. IF res # Base.ResOk THEN
  396. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 8"); KernelLog.Ln; END;
  397. RETURN FALSE;
  398. END;
  399. IF ~ScmSelectAndTestRegisters() THEN
  400. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 9"); KernelLog.Ln; END;
  401. RETURN FALSE;
  402. END;
  403. res := ScmReadUserIO(status, 1000);
  404. IF res # Base.ResOk THEN
  405. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 10"); KernelLog.Ln; END;
  406. RETURN FALSE;
  407. END;
  408. res := ScmWriteUserIO(SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, ScmUioAckd) + SYSTEM.VAL(SET, ScmUioOE0)
  409. + SYSTEM.VAL(SET, ScmUioOE1))), SYSTEM.VAL(CHAR, (SYSTEM.VAL(SET, ScmUioEpad)
  410. + SYSTEM.VAL(SET, ScmUio1))), 1000);
  411. IF res # Base.ResOk THEN
  412. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 11"); KernelLog.Ln; END;
  413. RETURN FALSE;
  414. END;
  415. res := ScmReadUserIO(status, 1000);
  416. IF res # Base.ResOk THEN
  417. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 12"); KernelLog.Ln; END;
  418. RETURN FALSE;
  419. END;
  420. Wait(1400);
  421. res := ScmReadUserIO(status, 1000);
  422. IF res # Base.ResOk THEN
  423. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 13"); KernelLog.Ln; END;
  424. RETURN FALSE;
  425. END;
  426. IF ~ScmSelectAndTestRegisters() THEN
  427. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 14"); KernelLog.Ln; END;
  428. RETURN FALSE;
  429. END;
  430. IF ~ScmSetShuttleFeatures(83X, 0X, 88X, 08X, 15X, 14X) THEN
  431. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM Init error, step 15"); KernelLog.Ln; END;
  432. RETURN FALSE;
  433. END;
  434. IF Debug.Trace & Debug.traceScInit THEN KernelLog.String("UsbStorage: Initialization done."); KernelLog.Ln; END;
  435. RETURN TRUE;
  436. END Initialization;
  437. PROCEDURE Transport*(cmd : ARRAY OF CHAR; cmdlen : LONGINT; dir : SET;
  438. VAR buffer : ARRAY OF CHAR; ofs, bufferlen : LONGINT; VAR tlen : LONGINT; timeout : LONGINT) : WORD;
  439. VAR
  440. registers, data : ARRAY 32 OF CHAR;
  441. i : LONGINT; res : WORD;
  442. status : CHAR;
  443. atapilen, tmplen, sector, transfered : LONGINT;
  444. j : LONGINT;
  445. BEGIN
  446. IF Debug.Trace & Debug.traceScTransfers THEN
  447. KernelLog.String("UsbStorage: Transport:");
  448. KernelLog.String(" Direction: ");
  449. IF dir = Base.DataIn THEN KernelLog.String("In");
  450. ELSIF dir = Base.DataOut THEN KernelLog.String("Out");
  451. ELSE KernelLog.String("Unknown");
  452. END;
  453. KernelLog.String(" Bufferlen: "); KernelLog.Int(bufferlen, 0); KernelLog.String(" Offset: "); KernelLog.Int(ofs, 0);
  454. KernelLog.String(" Cmd: ");
  455. IF cmdlen = 0 THEN KernelLog.String("None");
  456. ELSE
  457. FOR j := 0 TO cmdlen-1 DO KernelLog.Int(ORD(cmd[j]), 0); KernelLog.Char(" "); END;
  458. END;
  459. KernelLog.Ln;
  460. END;
  461. registers[0] := 11X;
  462. registers[1] := 12X;
  463. registers[2] := 13X;
  464. registers[3] := 14X;
  465. registers[4] := 15X;
  466. registers[5] := 16X;
  467. registers[6] := 17X;
  468. data[0] := 0X;
  469. data[1] := 0X;
  470. data[2] := 0X;
  471. data[3] := CHR(bufferlen);
  472. data[4] := CHR(LSH(bufferlen, -8));
  473. data[5] := 0B0X;
  474. data[6] := 0A0X;
  475. FOR i:= 7 TO 18 DO
  476. registers[i] := 010X;
  477. IF (i - 7) >= cmdlen THEN data[i] := 0X; ELSE data[i] := cmd[i-7]; END;
  478. END;
  479. tlen := 0;
  480. IF dir = Base.DataOut THEN
  481. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM DataOut not supported!!!"); KernelLog.Ln; END;
  482. RETURN Base.ResUnsupported;
  483. END;
  484. IF bufferlen > 65535 THEN
  485. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Too large request for SCM USB-ATAPI Shuttle"); KernelLog.Ln; END;
  486. RETURN Base.ResUnsupported;
  487. END;
  488. IF cmd[0] = CHR(Base.UfiRead10) THEN
  489. IF bufferlen < 10000H THEN
  490. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorage: Doing SCM single read"); KernelLog.Ln; END;
  491. res := ScmRWBlockTest(ScmATA, registers, data, 19, 10X, 17X, 0FDX, 30X, Base.DataIn, buffer, ofs, bufferlen, tlen, timeout);
  492. RETURN res;
  493. ELSE
  494. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorage: Doing SCM multi read"); KernelLog.Ln; END;
  495. tmplen := (65535 DIV sdevs.blockSize) * sdevs.blockSize;
  496. sector := LSH(ScmShortPack(data[10], data[9]), 16) + ScmShortPack(data[12], data[11]);
  497. transfered := 0;
  498. WHILE transfered # bufferlen DO
  499. IF tmplen > (bufferlen - transfered) THEN tmplen := bufferlen - transfered END;
  500. data[3] := CHR(tmplen);
  501. data[4] := CHR(LSH(tmplen, -8));
  502. data[9] := CHR(LSH(sector, -24));
  503. data[10] := CHR(LSH(sector, -16));
  504. data[11] := CHR(LSH(sector, -8));
  505. data[12] := CHR(sector);
  506. data[14] := CHR(LSH(tmplen DIV sdevs.blockSize, -8));
  507. data[15] := CHR(tmplen DIV sdevs.blockSize);
  508. res := ScmRWBlockTest(ScmATA, registers, data, 19, 10X, 17X, 0FDX, 30X, Base.DataIn, buffer, ofs+transfered, tmplen, atapilen, timeout);
  509. transfered := transfered + atapilen; tlen := transfered;
  510. sector := sector + (tmplen DIV sdevs.blockSize);
  511. IF res # Base.ResOk THEN RETURN res END;
  512. END;
  513. RETURN Base.ResOk;
  514. END;
  515. END;
  516. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorage: Sending SCM registers"); KernelLog.Ln; END;
  517. res := ScmMultipleWrite(ScmATA, registers, data, 7, 1000);
  518. IF (res = Base.ResDisconnected) THEN
  519. RETURN res;
  520. ELSIF (res # Base.ResOk) THEN
  521. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM register setup failed"); KernelLog.Ln; END;
  522. RETURN Base.ResError
  523. END;
  524. IF cmdlen # 12 THEN
  525. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM command len # 12"); KernelLog.Ln; END;
  526. RETURN Base.ResFatalError;
  527. END;
  528. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorage: Sending SCM command"); KernelLog.Ln; END;
  529. res := ScmWriteBlock(ScmATA, 10X, cmd, 0, 12, tmplen, timeout);
  530. IF (res = Base.ResDisconnected) THEN
  531. RETURN res;
  532. ELSIF res # Base.ResOk THEN
  533. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: SCM command transfer failed"); KernelLog.Ln; END;
  534. RETURN Base.ResError
  535. END;
  536. IF (bufferlen # 0) & (dir = Base.DataIn) THEN
  537. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorage: SCM data transfer"); KernelLog.Ln; END;
  538. res := ScmRead(ScmATA, 014X, status, 1000);
  539. IF (res = Base.ResDisconnected) THEN
  540. RETURN res;
  541. ELSIF res # Base.ResOk THEN
  542. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmRead failed"); KernelLog.Ln; END;
  543. RETURN Base.ResError
  544. END;
  545. atapilen := ORD(status);
  546. IF bufferlen > 255 THEN
  547. res := ScmRead(ScmATA, 015X, status, 1000);
  548. IF (res = Base.ResDisconnected) THEN
  549. RETURN res;
  550. ELSIF res # Base.ResOk THEN
  551. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmRead2 failed"); KernelLog.Ln; END;
  552. RETURN res;
  553. END;
  554. atapilen := atapilen + (ORD(status) * 256);
  555. END;
  556. IF Debug.Trace & Debug.traceScTransfers THEN
  557. KernelLog.String("UsbStorage: Scm Transfer: Want: "); KernelLog.Int(bufferlen, 0);
  558. KernelLog.String(" / have: "); KernelLog.Int(atapilen, 0); KernelLog.Ln;
  559. END;
  560. tmplen := atapilen;
  561. IF atapilen < bufferlen THEN
  562. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Scm has FEWER bytes in the atapi buffer"); KernelLog.Ln; END;
  563. ELSIF atapilen > bufferlen THEN
  564. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Scm has MORE bytes in the atapi buffer"); KernelLog.Ln; END;
  565. tmplen := bufferlen;
  566. END;
  567. res := ScmReadBlock(ScmATA, 10X, buffer, ofs, tmplen, tlen, timeout);
  568. IF Debug.Trace & Debug.traceScTransfers THEN
  569. IF (res = Base.ResOk) OR (res = Base.ResShortTransfer) THEN
  570. KernelLog.String("UsbStorage: wanted: "); KernelLog.Int(tmplen, 0);
  571. KernelLog.String(" / got: "); KernelLog.Int(tlen, 0); KernelLog.Ln;
  572. END;
  573. END;
  574. IF (res = Base.ResOk) & (atapilen < bufferlen) THEN res := Base.ResShortTransfer END;
  575. IF (res # Base.ResOk) & (res # Base.ResShortTransfer) THEN
  576. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ScmReadBlock failed"); KernelLog.Ln; END;
  577. RETURN res;
  578. END;
  579. ELSE
  580. tlen := 0;
  581. END;
  582. RETURN Base.ResOk;
  583. END Transport;
  584. PROCEDURE Wait(ms : LONGINT);
  585. BEGIN
  586. timer.Sleep(ms);
  587. END Wait;
  588. PROCEDURE &Init*;
  589. BEGIN
  590. Init^; NEW(command, 16); NEW(buffer, 64); NEW(timer);
  591. END Init;
  592. END SCMTransport;
  593. END UsbStorageScm.