UsbStorageBase.Mod 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202
  1. MODULE UsbStorageBase; (** AUTHOR "staubesv"; PURPOSE " USB Mass Storage Driver Base Class"; *)
  2. (**
  3. * Bluebottle USB Mass Storage Driver Base Class
  4. *
  5. * This module is the base for all USB mass storage device drivers. There are three different transport layers:
  6. *
  7. * UsbStorageCbi.Mod CB/I transport layer
  8. * UsbStorageBot.Mod Bulk-only transport layer
  9. * UsbStorageScm.Mod SCM transport layer
  10. *
  11. * This driver is based on the work of Christian Plattner.
  12. *
  13. * Usage:
  14. *
  15. * UsbStorageBase.Show ~ displays a list of all USB storage devices
  16. *
  17. * References:
  18. *
  19. * [1] Universal Serial Bus Mass Storage Class Specification Overview, Revision 1.2, June 23, 2003
  20. * [2] Universal Serial Bus Mass Storage Class UFI Command Specification, Revision 1.0, December 1998
  21. * [3] Universal Serial Bus Mass Storage Specification for Bootability, Revision 1.0, October 25, 2004
  22. *
  23. * All references available at www.usb.org
  24. *
  25. * History:
  26. *
  27. * 30.09.2000 cp first release
  28. * 20.10.2000 cp many improvements (BulkOnly, UTS)
  29. * 20.11.2005 Added support for logical devices, use Disks.Mod-compatible result codes on transport layer (staubesv)
  30. * 24.11.2005 Added UFI commands TestUnitReady, Allow/Prevent medium removal (staubesv)
  31. * 29.11.2005 Added UFI commands SendDiagnostic and Start/Stop Unit (used and therefore named to EjectMedia,
  32. * moved ReadCapacity to USB layer (staubesv)
  33. * 13.12.2005 Adapted to USBDI changes (staubesv)
  34. * 14.12.2005 UsbStorageDevice.Transfer, GetSize & Handle made exclusive (staubesv)
  35. * 15.12.2005 Fixed Bulk-Only reset recovery (staubesv)
  36. * 19.12.2005 Trim vendor/product strings (staubesv)
  37. * 03.01.2006 Use sequence number for CSW tag (staubesv)
  38. * 05.01.2006 Added TraceCBWs & TraceCSWs trace options (staubesv)
  39. * 12.01.2006 Removed data copying/memory allocation (staubesv)
  40. * 09.02.2006 Refactored driver: Introduced UsbStorageBase, UsbStorageCbi, UsbStorageBot,
  41. * UsbStorageScm, UsbStorageBoot (staubesv)
  42. * 28.06.2006 Use UsbUtilties (staubesv)
  43. * 09.08.2006 Inquiry, TestUnitReady, ReadCapacity, Read & Write commands length set to 12 bytes since lower values broke the CBI Layer (staubesv)
  44. * 26.03.2007 Added NnofReads, NnofWrites, NnofOthers and NnofErrors statistics (staubesv)
  45. *)
  46. IMPORT SYSTEM, KernelLog, Kernel, Commands, Disks, Plugins, Usbdi, Debug := UsbDebug, Lib := UsbUtilities;
  47. CONST
  48. NoData* = {};
  49. DataIn* = {1};
  50. DataOut* = {2};
  51. (* Result codes *)
  52. (* From Disks.Mod *)
  53. ResOk* = Disks.Ok;
  54. ResWriteProtected* = Disks.WriteProtected;
  55. ResDeviceInUse* = Disks.DeviceInUse;
  56. ResMediaChanged* = Disks.MediaChanged;
  57. ResMediaMissing* = Disks.MediaMissing;
  58. ResUnsupported* = Disks.Unsupported;
  59. (* USB Storage Device Driver specific *)
  60. ResTimeout* = 30;
  61. ResShortTransfer* = 31;
  62. ResDeviceNotReady* = 32;
  63. ResDeviceNotReadyInit* = 33; (* Device need to be initialized *)
  64. ResSenseError* = 34; (* Do sensing *)
  65. ResError* = 35;
  66. ResFatalError* = 36; (* Device needs to be resetted *)
  67. ResDisconnected* = 37;
  68. MethodCBI* = 1;
  69. MethodCB* = 2;
  70. MethodBulkOnly* = 3;
  71. MethodSCMShuttle* = 4;
  72. ProtocolUFI* = 100; (* UFI *)
  73. ProtocolUTS* = 101; (* USB TRANSPARENT SCSI => UTS (plattner definition) *)
  74. ProtocolRBC* = 102; (* RBC = reduced block commands, often used for flash devices *)
  75. Protocol8020* = 103; (* ATAPI for CDROM *)
  76. Protocol8070* = 104; (* ATAPI for floppy drives and similar devices *)
  77. ProtocolQIC157* = 105; (* QIC, meaning the tape company. Typically used by tape devices *)
  78. (* UFI Commands according UFI Command Specification *)
  79. UfiFormatUnit = 04H; (* Format unformatted media; not implemented *)
  80. UfiInquiry = 12H; (* Get device information *)
  81. UfiStartStop = 1BH; (* Request a removable-media device to load or unload its media; partially implemented *)
  82. UfiModeSelect = 55H; (* Allow the host to set parameters in a peripheral (mode sense should be issued prior to mode select); not implemented *)
  83. UfiModeSense = 5AH; (* Report parameters to the host. *)
  84. UfiAllowRemoval = 1EH; (* Prevent or allow the removal of media from a removable media device *)
  85. UfiRead10* = 28H; (* Transfer binary data from the media to the host *)
  86. UfiRead12 = 0A8H; (* Transfer binary data from the media to the host not implemented *)
  87. UfiReadCapacity = 25H; (* Report current media capacity *)
  88. UfiReadFormatCapacity = 23H; (* Read current media capacity and formattable capacities supported by media; not implemented *)
  89. UfiRequestSense = 03H; (* Tansfer status sense data to the host *)
  90. UfiRezeroUnit = 01H; (* Position a head of the drive to zero track not implemented *)
  91. UfiSeek10 = 2BH; (* Seek the device to a specified address not implemented *)
  92. UfiSendDiag = 1DH; (* Perform a hard reset and execute diagnostics *)
  93. UfiTestUnitReady = 00H; (* Request the device to report if it's ready *)
  94. UfiVerify = 2FH; (* Verify data on the media not implemented *)
  95. UfiWrite10 = 2AH; (* Transfer binary data from the host to the media *)
  96. UfiWrite12 = 0AAH; (* Transfer binary data from the host to the media not implemented *)
  97. UfiWriteNVerify = 2EH; (* Transfer binary data from the host to the media and verify data not implemented *)
  98. (* Device types as reported by the UFI Inquiry command *)
  99. DtSbcDirectAccess = 00H;
  100. DtCDROM = 05H;
  101. DtOpticalMemory = 07H;
  102. DtRbcDirectAccess = 0EH;
  103. RemovableBit = {7};
  104. (* UfiModeSense constants: Page Control Field *)
  105. PcCurrentValues = 0;
  106. PcChangeableValues = 1;
  107. PcDefaultValues = 2;
  108. PcSavedValues = 3;
  109. (* UfiModeSense constants: Page Code field *)
  110. PageRwErrorRecovery = 01H;
  111. PageFlexibleDisk = 05H;
  112. PageBlockAccessCapacities = 1BH;
  113. PageTimerAndProtect = 1CH;
  114. PageAll = 3FH; (* only for mode sense command *)
  115. (* Timeout values in milliseconds *)
  116. TransferTimeout = 20000;
  117. CommandTimeout = 5000;
  118. TYPE
  119. (* Information delivered by UFI Inquiry command *)
  120. InquiryResult = POINTER TO RECORD
  121. deviceType : LONGINT; (* Peripheral device type; 00h: direct access device (floppy), 1FH > none *)
  122. removable : BOOLEAN; (* Removable media bit *)
  123. ansiVersion : LONGINT; (* Should be 0 for compatible devices *)
  124. additionalLength : LONGINT;
  125. validStrings : BOOLEAN; (* Are the fields below valid? *)
  126. vendor : ARRAY 9 OF CHAR;
  127. product : ARRAY 17 OF CHAR;
  128. revision : ARRAY 5 OF CHAR;
  129. END;
  130. (* Information delivered by UFI Mode Sense Command when Flexible Disk Page is requested *)
  131. FlexibleDiskPage = POINTER TO RECORD
  132. TransferRate : LONGINT; (* kbits/s *)
  133. NumberOfHeads : LONGINT;
  134. SectorsPerTrack : LONGINT; (* 1 - 63 *)
  135. BytesPerSector : LONGINT;
  136. NumberOfCylinders : LONGINT;
  137. MotorOnDelay, MotorOffDelay : LONGINT;
  138. MediumRotationRate : LONGINT; (* r.p.m. *)
  139. END;
  140. TYPE
  141. UsbStorageDevice = OBJECT (Disks.Device)
  142. VAR
  143. usbDriver : StorageDriver;
  144. lun : LONGINT; (* Logical Unit Number of this storage device*)
  145. transportProtocol : LONGINT;
  146. (* Fields used by the DiskManager *)
  147. number : LONGINT; (* Suffix appended to name to get unique device name *)
  148. next : UsbStorageDevice;
  149. PROCEDURE Transfer* (op, block, num: LONGINT; VAR data: ARRAY OF CHAR; ofs: LONGINT; VAR diskres: WORD);
  150. VAR direction : SET; cmd : ARRAY 12 OF CHAR; i, tlen, trans, offset, num0 : LONGINT;
  151. BEGIN {EXCLUSIVE}
  152. IF (op = Disks.Read) OR (op = Disks.Write) THEN
  153. FOR i := 0 TO 11 DO cmd[i] := 0X; END;
  154. IF op = Disks.Read THEN
  155. cmd[0] := CHR(UfiRead10); direction := DataIn;
  156. ELSE
  157. cmd[0] := CHR(UfiWrite10); direction := DataOut;
  158. END;
  159. cmd[1] := CHR(LSH(lun, 5)); (* Logical device number *)
  160. offset := ofs; num0 := num;
  161. WHILE num > 0 DO
  162. IF num > 65000 THEN trans := 65000; ELSE trans := num END;
  163. cmd[2] := CHR(LSH(block, -24));
  164. cmd[3] := CHR(LSH(block, -16));
  165. cmd[4] := CHR(LSH(block, -8));
  166. cmd[5] := CHR(block);
  167. cmd[7] := CHR(LSH(trans, -8));
  168. cmd[8] := CHR(trans);
  169. cmd[9] := 0X;
  170. diskres := usbDriver.InvokeTransport(cmd, 12, direction, data, offset, trans * blockSize, tlen, TransferTimeout);
  171. IF diskres # Disks.Ok THEN RETURN; END;
  172. block := block + trans;
  173. num := num - trans;
  174. offset := offset + (trans * blockSize);
  175. END;
  176. IF Disks.Stats THEN
  177. IF (op = Disks.Read) THEN
  178. INC (NnofReads);
  179. IF (diskres = ResOk) THEN INC (NbytesRead, num0 * blockSize);
  180. ELSE INC (NnofErrors);
  181. END;
  182. ELSE
  183. INC (NnofWrites);
  184. IF (diskres = ResOk) THEN INC (NbytesWritten, num0 * blockSize);
  185. ELSE INC (NnofErrors);
  186. END;
  187. END;
  188. END;
  189. ELSE
  190. diskres := Disks.Unsupported;
  191. IF Disks.Stats THEN INC (NnofOthers); END;
  192. END;
  193. END Transfer;
  194. (** Get number of blocks and size of blocks using the UFI Read Capacity command *)
  195. PROCEDURE GetSize* (VAR size: LONGINT; VAR res: WORD);
  196. BEGIN {EXCLUSIVE}
  197. IF Debug.Trace & Debug.traceInfo THEN KernelLog.String("UsbStorage: GetSize: "); KernelLog.Ln; END;
  198. (* Some devices I've seen didn't like to be asked for their capacity when no medium was inserted... *)
  199. res := usbDriver.WaitForReady(lun, 5000);
  200. IF (res # ResOk) & (res # ResMediaChanged) THEN
  201. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: GetCapacity: command failed: "); ShowRes(res); KernelLog.Ln; END;
  202. RETURN;
  203. END;
  204. blockSize := 0; size := 0;
  205. res := usbDriver.ReadCapacity(lun, size, blockSize);
  206. IF ((res # ResOk) & (res # ResShortTransfer)) THEN
  207. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ReadCapacity: command failed: "); ShowRes(res); KernelLog.Ln; END;
  208. RETURN;
  209. END;
  210. res := ResOk; (* Allow short transfer *)
  211. END GetSize;
  212. PROCEDURE Handle*(VAR msg: Disks.Message; VAR diskres: WORD);
  213. VAR cmd : ARRAY 12 OF CHAR; i : LONGINT; fdp : FlexibleDiskPage;
  214. BEGIN {EXCLUSIVE}
  215. FOR i := 0 TO 11 DO cmd[i] := CHR(0); END;
  216. IF msg IS Disks.GetGeometryMsg THEN
  217. IF transportProtocol = ProtocolUFI THEN
  218. WITH msg : Disks.GetGeometryMsg DO
  219. (* TODO: But what if the user changes the medium... *)
  220. fdp := usbDriver.ModeSense(lun, 0, PageFlexibleDisk, 32);
  221. IF fdp # NIL THEN
  222. msg.spt := fdp.SectorsPerTrack;
  223. msg.hds := fdp.NumberOfHeads;
  224. msg.cyls := fdp.NumberOfCylinders;
  225. ELSE
  226. (* assume 1440KB floppy disk *)
  227. msg.spt := 18; msg.hds := 2; msg.cyls := 80;
  228. END;
  229. IF Debug.Trace & Debug.traceScRequests THEN
  230. KernelLog.String("UsbStorageBase: Disk geometry CHS:");
  231. KernelLog.Int(msg.cyls, 0); KernelLog.String("x"); KernelLog.Int(msg.hds, 0); KernelLog.String("x"); KernelLog.Int(msg.spt, 0); KernelLog.Ln;
  232. END;
  233. END;
  234. diskres := Disks.Ok;
  235. ELSE
  236. diskres := Disks.Unsupported;
  237. END;
  238. ELSIF msg IS Disks.LockMsg THEN
  239. diskres := usbDriver.PreventMediumRemoval(lun, TRUE);
  240. ELSIF msg IS Disks.UnlockMsg THEN
  241. diskres := usbDriver.PreventMediumRemoval(lun, FALSE);
  242. ELSIF msg IS Disks.EjectMsg THEN
  243. diskres := usbDriver.EjectMedia(lun);
  244. ELSE
  245. diskres := Disks.Unsupported;
  246. END;
  247. END Handle;
  248. END UsbStorageDevice;
  249. TYPE
  250. StorageDriver* = OBJECT (Usbdi.Driver);
  251. VAR
  252. sdevs- : UsbStorageDevice; (* list of storage devices associated to this driver *)
  253. description* : Plugins.Description;
  254. transportProtocol*, transportMethod* : LONGINT;
  255. bulkIn*, bulkOut*, interrupt* : LONGINT; (* adresses of the used endpoints *)
  256. bulkInPipe-, bulkOutPipe-, interruptPipe-, defaultPipe- : Usbdi.Pipe;
  257. initialize* : BOOLEAN; (* if TRUE, the Initialization() procedure is called *)
  258. timer : Kernel.Timer;
  259. (** Transport layer specific reset procedure *)
  260. PROCEDURE Reset*(timeout : LONGINT) : WORD;
  261. BEGIN
  262. HALT(301); RETURN 0; (* abstract *)
  263. END Reset;
  264. (** Transport layer specific transfer procedure *)
  265. PROCEDURE Transport*(cmd : ARRAY OF CHAR; cmdlen : LONGINT; dir : SET;
  266. VAR buffer : ARRAY OF CHAR; ofs, bufferlen : LONGINT; VAR tlen : LONGINT; timeout : LONGINT) : WORD;
  267. BEGIN
  268. HALT(301); RETURN 0; (* abstract *)
  269. END Transport;
  270. (* Bulk-only transport layer only *)
  271. PROCEDURE GetMaxLun*(VAR lun : LONGINT) : LONGINT;
  272. BEGIN
  273. HALT(301); RETURN 0; (* abstract *)
  274. END GetMaxLun;
  275. (* UFI command: Test whether the specified logical unit is ready *)
  276. PROCEDURE TestUnitReady(lun : LONGINT) : WORD;
  277. VAR cmd : ARRAY 12 OF CHAR; i, ignore : LONGINT;
  278. BEGIN
  279. cmd[0] := CHR(UfiTestUnitReady);
  280. cmd[1] := CHR(LSH(lun, 5));
  281. FOR i := 2 TO 11 DO cmd[i] := 0X; END;
  282. RETURN InvokeTransport(cmd, 12, NoData, cmd, 0, 0, ignore, 30000);
  283. END TestUnitReady;
  284. (* Issues TestUnitReady commands until device is ready or an error occurs *)
  285. PROCEDURE WaitForReady(lun, timeout : LONGINT) : WORD;
  286. VAR retry : LONGINT; res : WORD;
  287. BEGIN
  288. IF Debug.Trace & Debug.traceScRequests THEN KernelLog.String("UsbStorageBase: WaitForReady..."); KernelLog.Ln; END;
  289. retry := 0;
  290. LOOP
  291. res := TestUnitReady(lun);
  292. IF (res = ResDisconnected) THEN
  293. EXIT;
  294. ELSIF (res = ResDeviceNotReady) OR (res = ResMediaChanged) THEN
  295. (* continue *)
  296. ELSE
  297. INC(retry);
  298. END;
  299. IF (retry > 3) OR (timeout < 0) THEN EXIT; END;
  300. Wait(100);
  301. timeout := timeout - 100;
  302. END;
  303. IF Debug.Trace & Debug.traceScRequests THEN KernelLog.String("UsbStorageBase: WaitForReady done, res: "); ShowRes(res); KernelLog.Ln; END;
  304. RETURN res;
  305. END WaitForReady;
  306. (* UFI command: Start/Stop Unit. *)
  307. (* Note: Since UFI devices control the motor on/off themselves, it's not implemented here. *)
  308. (* We just use the command to eject the media, thus the name *)
  309. PROCEDURE EjectMedia(lun : LONGINT) : WORD;
  310. VAR cmd, data : ARRAY 12 OF CHAR; i, tlen : LONGINT; res : WORD;
  311. BEGIN
  312. cmd[0] := CHR(UfiStartStop);
  313. cmd[1] := CHR(LSH(lun, 5));
  314. FOR i := 2 TO 11 DO cmd[i] := 0X; END;
  315. cmd[4] := CHR(2); (* Eject *)
  316. res := InvokeTransport(cmd, 12, DataOut, data, 0, 0, tlen, CommandTimeout);
  317. RETURN res;
  318. END EjectMedia;
  319. (* UFI command: Prevent/Allow Medium Removal *)
  320. PROCEDURE PreventMediumRemoval(lun : LONGINT; prevent : BOOLEAN) : WORD;
  321. VAR cmd, data : ARRAY 12 OF CHAR; i, tlen : LONGINT; res : WORD;
  322. BEGIN
  323. cmd[0] := CHR(UfiAllowRemoval);
  324. cmd[1] := CHR(LSH(lun, 5));
  325. FOR i := 2 TO 11 DO cmd[i] := 0X; END;
  326. IF prevent THEN cmd[4] := CHR(1); END;
  327. res := InvokeTransport(cmd, 12, DataOut, data, 0, 0, tlen, CommandTimeout);
  328. RETURN res;
  329. END PreventMediumRemoval;
  330. (* UFI command: Request UFI device to do a reset or perform a self-test *)
  331. PROCEDURE SendDiagnostic(lun : LONGINT) : WORD;
  332. VAR cmd, data : ARRAY 12 OF CHAR; i, tlen : LONGINT; res : WORD;
  333. BEGIN
  334. cmd[0] := CHR(UfiSendDiag);
  335. cmd[1] := CHR(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, LSH(lun, 5)) + {2}));
  336. FOR i := 2 TO 11 DO cmd[i] := 0X; END;
  337. res := InvokeTransport(cmd, 12, DataOut, data, 0, 0, tlen, CommandTimeout);
  338. RETURN res;
  339. END SendDiagnostic;
  340. (* UFI command: Get the number of blocks and the blocksize of the specified logical unit *)
  341. PROCEDURE ReadCapacity(lun : LONGINT; VAR blocks, blocksize : LONGINT) : WORD;
  342. VAR cmd, data : ARRAY 12 OF CHAR; res: WORD; i, tlen : LONGINT;
  343. BEGIN
  344. IF Debug.Trace & Debug.traceInfo THEN KernelLog.String("UsbStorage: ReadCapacity: "); KernelLog.Ln; END;
  345. cmd[0] := CHR(UfiReadCapacity);
  346. cmd[1] := CHR(LSH(lun, 5));
  347. FOR i := 2 TO 11 DO cmd[i] := CHR(0); END;
  348. blocks := 0; blocksize := 0;
  349. res := InvokeTransport(cmd, 12, DataIn, data, 0, 8, tlen, TransferTimeout);
  350. IF (res # ResOk) THEN
  351. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ReadCapacity: command failed: "); ShowRes(res); KernelLog.Ln; END;
  352. RETURN res;
  353. END;
  354. FOR i := 0 TO 3 DO
  355. blocks := blocks*100H + ORD(data[i]);
  356. blocksize := blocksize*100H + ORD(data[4+i])
  357. END;
  358. INC(blocks); (* The device reports the highest valid block address -> also count block zero *)
  359. res := ResOk; (* allow short transfers *)
  360. IF Debug.Trace & Debug.traceInfo THEN
  361. KernelLog.String("UsbStorage: Disk info: Blocks: "); KernelLog.Int(blocks, 0);
  362. KernelLog.String(" blocksize: "); KernelLog.Int(blocksize, 0); KernelLog.String(" size: "); KernelLog.Int(blocks*blocksize, 0);
  363. KernelLog.Ln;
  364. END;
  365. RETURN ResOk;
  366. END ReadCapacity;
  367. (* UFI command: Inquiry the specified locigal unit; Returns NIL in error case *)
  368. PROCEDURE Inquiry(lun : LONGINT) : InquiryResult;
  369. VAR cmd : ARRAY 12 OF CHAR; data : ARRAY 36 OF CHAR; result : InquiryResult; i, j, tlen : LONGINT; res : WORD;
  370. BEGIN
  371. IF Debug.Trace & Debug.traceInfo THEN
  372. KernelLog.String("UsbStorage: Inquiry logical device "); KernelLog.Int(lun, 0); KernelLog.String("... "); KernelLog.Ln;
  373. END;
  374. FOR i := 0 TO 11 DO cmd[i] := CHR(0); END;
  375. cmd[0] := CHR(UfiInquiry);
  376. cmd[1] := CHR(LSH(lun, 5));
  377. cmd[4] := CHR(36); (* maximum allocation length *)
  378. res := InvokeTransport(cmd, 12, DataIn, data, 0, 36, tlen, 50000);
  379. IF ((res # Disks.Ok) & (res # ResShortTransfer)) OR (tlen < 5) THEN
  380. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Fatal, inquiry device error: "); ShowRes(res); KernelLog.Ln; END;
  381. RETURN NIL;
  382. END;
  383. NEW(result);
  384. result.deviceType := ORD(data[0]) MOD 32;
  385. IF SYSTEM.VAL(SET, ORD(data[1])) * RemovableBit # {} THEN
  386. result.removable := TRUE;
  387. END;
  388. result.ansiVersion := ORD(data[2]) MOD 8;
  389. result.additionalLength := ORD(data[4]);
  390. IF transportProtocol = ProtocolRBC THEN
  391. IF result.deviceType # DtRbcDirectAccess THEN
  392. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: RBC device type is not 0EH"); KernelLog.Ln; END;
  393. RETURN NIL;
  394. END;
  395. ELSIF (result.deviceType # DtSbcDirectAccess) & (result.deviceType # DtCDROM) & (result.deviceType # DtOpticalMemory) THEN
  396. IF Debug.Trace & Debug.traceInfo THEN KernelLog.String("UsbStorage: Device is not a storage device"); KernelLog.Ln; END;
  397. RETURN NIL;
  398. END;
  399. IF tlen >= 36 THEN
  400. result.validStrings := TRUE;
  401. j := 0; FOR i := 8 TO 15 DO result.vendor[j] := data[i]; INC(j); END; result.vendor[8] := 0X;
  402. j := 0; FOR i := 16 TO 31 DO result.product[j] := data[i]; INC(j); END; result.product[16] := 0X;
  403. j := 0; FOR i := 32 TO 35 DO result.revision[j] := data[i]; INC(j); END; result.revision[4] := 0X;
  404. END;
  405. IF Debug.Trace & Debug.traceInfo THEN ShowInquiryResult(result); END;
  406. RETURN result;
  407. END Inquiry;
  408. (* The mode sense command allows the UFI device to report medium or device parameters to the host *)
  409. PROCEDURE ModeSense(lun, pagecontrol, page, length : LONGINT) : FlexibleDiskPage;
  410. VAR cmd : ARRAY 12 OF CHAR; data : Usbdi.BufferPtr; actLen : LONGINT; res : WORD; fdp : FlexibleDiskPage;
  411. (* page[index] is first byte of flexible disk page *)
  412. PROCEDURE ParseFlexibleDiskPage(page : Usbdi.BufferPtr; index : LONGINT) : FlexibleDiskPage;
  413. VAR temp : LONGINT; fdp : FlexibleDiskPage;
  414. BEGIN
  415. ASSERT((page # NIL) & (LEN(page) - index >= 32));
  416. ASSERT(SYSTEM.VAL(LONGINT, (SYSTEM.VAL(SET, page[index]) * {0..5})) = PageFlexibleDisk);
  417. NEW(fdp);
  418. temp := LSH(ORD(page[index+2]), 8) + ORD(page[index+3]);
  419. IF temp = 00FAH THEN fdp.TransferRate := 250;
  420. ELSIF temp = 012CH THEN fdp.TransferRate := 300;
  421. ELSIF temp = 01F4H THEN fdp.TransferRate := 500;
  422. ELSIF temp = 03E8H THEN fdp.TransferRate := 1000;
  423. ELSIF temp = 07D0H THEN fdp.TransferRate := 2000;
  424. ELSIF temp = 1388H THEN fdp.TransferRate := 5000;
  425. ELSIF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: ParseFlexibleDiskPage: Warning: Parse error"); KernelLog.Ln;
  426. END;
  427. fdp.NumberOfHeads := ORD(page[index+4]);
  428. fdp.SectorsPerTrack := ORD(page[index+5]);
  429. fdp.BytesPerSector := LSH(ORD(page[index+6]), 8) + ORD(page[index+7]);
  430. fdp.NumberOfCylinders := LSH(ORD(page[index+8]), 8) + ORD(page[index+9]);
  431. fdp.MotorOnDelay := ORD(page[index+19]);
  432. fdp.MotorOffDelay := ORD(page[index+20]);
  433. IF fdp.MotorOffDelay = 0FFH THEN fdp.MotorOffDelay := 0; (* don't turn it off !! *) END;
  434. fdp.MediumRotationRate := LSH(ORD(page[index+28]), 8) + ORD(page[index+29]);
  435. IF Debug.Trace & Debug.traceInfo THEN ShowFlexibleDiskPage(fdp); END;
  436. RETURN fdp;
  437. END ParseFlexibleDiskPage;
  438. BEGIN
  439. length := length + 8; (* 8 additional bytes for mode parameter header *)
  440. cmd[0] := CHR(UfiModeSense);
  441. cmd[1] := CHR(LSH(lun, 5)); (* logical unit number *)
  442. cmd[2] := CHR(LSH(pagecontrol, 6) + page);
  443. cmd[3] := CHR(0); (* reserved *)
  444. cmd[5] := CHR(0); (* reserved *)
  445. cmd[6] := CHR(0); (* reserved *)
  446. cmd[7] := CHR(LSH(length, -8)); (* Parameter List Length (MSB)*)
  447. cmd[8] := CHR(length); (* Parameter List Length (LSB) *)
  448. cmd[9] := CHR(0); (* reserved *)
  449. cmd[10] := CHR(0); (* reserved *)
  450. cmd[11] := CHR(0); (* reserved *)
  451. NEW(data, length);
  452. res := InvokeTransport (cmd, 12, DataIn, data^, 0, length, actLen, CommandTimeout);
  453. IF ((res # Disks.Ok) OR ((res # ResShortTransfer) & (actLen < length))) THEN
  454. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: UFI Mode Sense command failed."); KernelLog.Ln; END;
  455. RETURN NIL;
  456. END;
  457. IF (ORD(data[1]) + 100H*SYSTEM.VAL(LONGINT, ORD(data[0]))) # length + 8 THEN
  458. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: ModeSense: Error: Wrong Mode Data Length returned."); KernelLog.Ln; END;
  459. RETURN NIL;
  460. END;
  461. (* parse the result *)
  462. CASE page OF
  463. PageFlexibleDisk : fdp := ParseFlexibleDiskPage(data, 8);
  464. ELSE
  465. IF Debug.Level >= Debug.Warnings THEN
  466. KernelLog.String("UsbStorage: ModeSense: Parsing of page type "); KernelLog.Hex(page,-2);
  467. KernelLog.String(" not (yet) supported."); KernelLog.Ln;
  468. END;
  469. END;
  470. RETURN fdp;
  471. END ModeSense;
  472. (* UFI command: The Request Sense command instructs the UFI device to transfer sense data to the host for
  473. * the specified logical unit *)
  474. PROCEDURE RequestSense(lun, cmdlen : LONGINT) : WORD;
  475. VAR
  476. cmd : ARRAY 12 OF CHAR; data : ARRAY 36 OF CHAR;
  477. key, asc, ascq : CHAR;
  478. information : LONGINT;
  479. i, tlen : LONGINT; res : WORD;
  480. BEGIN
  481. IF Debug.Trace & Debug.traceSensing THEN KernelLog.String("UsbStorage: Doing auto sense..."); KernelLog.Ln; END;
  482. IF (transportProtocol = ProtocolUTS) OR (transportProtocol = ProtocolRBC) THEN
  483. cmdlen := 6;
  484. END;
  485. FOR i := 0 TO 11 DO cmd[i] := CHR(0); END;
  486. cmd[0] := CHR(UfiRequestSense);
  487. cmd[1] := CHR(LSH(lun, 5));
  488. cmd[4] := CHR(18); (* allocation length (max. 18 Bytes) *)
  489. res := Transport(cmd, cmdlen, DataIn, data, 0, 18, tlen, 2000);
  490. IF (res = ResDisconnected) THEN
  491. RETURN res;
  492. ELSIF (res = ResShortTransfer) THEN
  493. IF (tlen < 14) THEN
  494. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Crappy device gives not enough sense data"); KernelLog.Ln; END;
  495. RETURN ResSenseError;
  496. ELSE
  497. (* sense >= 14 is ok *)
  498. END;
  499. ELSIF (transportProtocol = ProtocolUFI) & (res = ResSenseError) THEN
  500. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: UFI autosense TransportSenseError"); KernelLog.Ln; END;
  501. (* thats ok *)
  502. ELSIF res # ResOk THEN
  503. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Sense error on protocol sense"); KernelLog.Ln; END;
  504. res := Reset(5000);
  505. RETURN ResSenseError;
  506. END;
  507. key := CHR(ORD(data[2]) MOD 16); asc := data[12]; ascq := data[13];
  508. IF Debug.Trace & Debug.traceSensing THEN
  509. IF SYSTEM.VAL(SET, ORD(data[0])) * {7} # {} THEN (* information field is valid *)
  510. information := ORD(data[3]) + 10H*ORD(data[4]) + 100H*ORD(data[5]) + 1000H*ORD(data[6]);
  511. END;
  512. ShowSenseData(key, asc, ascq, information, SYSTEM.VAL(SET, ORD(data[0])) * {7} # {});
  513. END;
  514. IF key = 0X THEN (* No sense -> okay *)
  515. IF (res = ResOk) OR (res = ResShortTransfer) THEN RETURN ResOk; END;
  516. RETURN ResError;
  517. ELSIF (key = 1X) THEN RETURN ResOk; (* Recovered error -> okay *)
  518. ELSIF (key = 2X) & (asc = 4X) & (ascq = 01X) THEN RETURN ResDeviceNotReady; (* Logical drive not ready - becoming ready *)
  519. ELSIF (key = 2X) & (asc = 4X) & (ascq = 02X) THEN RETURN ResDeviceNotReadyInit; (* Logical drive not ready - initialization required *)
  520. ELSIF (key = 2X) & (asc = 4X) & (ascq = 04X) THEN RETURN ResDeviceInUse; (* Logical drive not ready - format in progress *)
  521. ELSIF (key = 2X) & (asc = 4X) & (ascq = 0FFX) THEN RETURN ResDeviceInUse; (* Logical drive not ready - device is busy *)
  522. ELSIF (key = 2X) & (asc = 6X) & (ascq = 00X) THEN RETURN ResError; (* No reference position found *)
  523. ELSIF (key = 2X) & (asc = 8X) & (ascq = 00X) THEN RETURN ResError; (* Logical unit communication failure *)
  524. ELSIF (key = 2X) & (asc = 8X) & (ascq = 01X) THEN RETURN ResTimeout; (* Logical unit communication timeout *)
  525. ELSIF (key = 2X) & (asc = 8X) & (ascq = 80X) THEN RETURN ResError; (* Logical unit communication overrun *)
  526. ELSIF (key = 2X) & (asc = 3AX) & (ascq = 0X) THEN RETURN ResMediaMissing; (* Medium not present *)
  527. ELSIF (key = 2X) THEN RETURN ResError;
  528. ELSIF (key = 3X) THEN RETURN ResError; (* Medium Error *)
  529. ELSIF (key = 4X) THEN RETURN ResError; (* Hardware Error *)
  530. ELSIF (key = 5X) THEN RETURN ResUnsupported; (* Illegal Request *)
  531. ELSIF (key = 6X) & (asc = 28X) & (ascq = 00X) THEN RETURN ResMediaChanged;
  532. ELSIF (key = 6X) & (asc = 29X) & (ascq = 0X) THEN RETURN ResDeviceNotReady; (* PowerOnReset *)
  533. ELSIF (key = 6X) THEN RETURN ResDeviceNotReady;
  534. ELSIF (key = 7X) THEN RETURN ResWriteProtected;
  535. ELSE
  536. RETURN ResError;
  537. END;
  538. END RequestSense;
  539. (* PROCEDURE ReadWrite10(lun, blockSize, op, block, num : LONGINT; VAR data : ARRAY OF CHAR; ofs : LONGINT; VAR diskres : LONGINT);
  540. VAR cmd : ARRAY 12 OF CHAR; trans, tlen, i, res : LONGINT; direction : SET;
  541. BEGIN
  542. FOR i:= 0 TO 11 DO cmd[i] := 0X; END;
  543. IF op = Disks.Read THEN
  544. cmd[0] := CHR(UfiRead10); direction := DataIn;
  545. ELSE
  546. cmd[0] := CHR(UfiWrite10); direction := DataOut;
  547. END;
  548. cmd[1] := CHR(LSH(lun, 5)); (* Logical device number *)
  549. WHILE num > 0 DO
  550. IF num > 65000 THEN trans := 65000; ELSE trans := num END;
  551. trans := trans * blockSize;
  552. cmd[2] := CHR(LSH(block, -24));
  553. cmd[3] := CHR(LSH(block, -16));
  554. cmd[4] := CHR(LSH(block, -8));
  555. cmd[5] := CHR(block);
  556. cmd[7] := CHR(LSH(num, -8));
  557. cmd[8] := CHR(num);
  558. diskres := InvokeTransport(cmd, 12, direction, data, ofs, trans, tlen, TransferTimeout);
  559. IF diskres # Disks.Ok THEN RETURN; END;
  560. block := block + trans;
  561. num := num - trans;
  562. END;
  563. END ReadWrite10;
  564. PROCEDURE ReadWrite12(lun, op, block, num : LONGINT; VAR data : ARRAY OF CHAR; ofs : LONGINT; VAR diskres : LONGINT);
  565. VAR cmd : ARRAY 12 OF CHAR; trans, tlen, i, res : LONGINT; direction : SET;
  566. BEGIN
  567. ASSERT(num < MAX(LONGINT));
  568. FOR i:= 0 TO 11 DO cmd[i] := 0X; END;
  569. IF op = Disks.Read THEN
  570. cmd[0] := CHR(UfiRead12); direction := DataIn;
  571. ELSE
  572. cmd[0] := CHR(UfiWrite12); direction := DataOut;
  573. END;
  574. cmd[1] := CHR(LSH(lun, 5)); (* Logical device number *)
  575. cmd[2] := CHR(LSH(block, -24));
  576. cmd[3] := CHR(LSH(block, -16));
  577. cmd[4] := CHR(LSH(block, -8));
  578. cmd[5] := CHR(block);
  579. cmd[6] := CHR(LSH(num, -24));
  580. cmd[7] := CHR(LSH(num, -16));
  581. cmd[8] := CHR(LSH(num, -8));
  582. cmd[9] := CHR(num);
  583. diskres := InvokeTransport(cmd, 12, direction, data, ofs, trans, tlen, TransferTimeout);
  584. END ReadWrite12; *)
  585. (* Generic Transport Handler *)
  586. PROCEDURE InvokeTransport (cmd : ARRAY OF CHAR; cmdlen : INTEGER; dir : SET;
  587. VAR data : ARRAY OF CHAR; ofs, datalen : LONGINT; VAR tlen : LONGINT; timeout : LONGINT) : WORD;
  588. VAR
  589. sensecmdlen, retry, i : LONGINT; res: WORD; forceRetry : BOOLEAN;
  590. BEGIN {EXCLUSIVE}
  591. (* here one could add additional stuff for the different protocols *)
  592. IF transportProtocol = ProtocolUFI THEN
  593. cmdlen := 12; sensecmdlen := 12;
  594. ELSIF (transportProtocol = ProtocolUTS) OR (transportProtocol = ProtocolRBC) THEN
  595. (* all ok *) sensecmdlen := 6;
  596. ELSIF (transportProtocol = Protocol8020) OR (transportProtocol = Protocol8070) THEN
  597. cmdlen := 12; sensecmdlen := 12;
  598. ELSIF transportProtocol = ProtocolQIC157 THEN
  599. cmdlen := 12; sensecmdlen := 12;
  600. END;
  601. retry := 0; (* retries for "power up/reset" and "lun becoming ready" *)
  602. LOOP
  603. IF Debug.Trace & Debug.traceScTransfers THEN
  604. KernelLog.String("UsbStorageBase: [cmd: ");
  605. IF transportProtocol = ProtocolUFI THEN ShowUFICmd(cmd[0]); END;
  606. FOR i := 0 TO cmdlen-1 DO KernelLog.String(" "); KernelLog.Hex(ORD(cmd[i]), -2); END;
  607. KernelLog.String(" BufferLen: "); KernelLog.Int(datalen, 0); KernelLog.String(" Bytes]");
  608. KernelLog.Ln;
  609. END;
  610. res := Transport(cmd, cmdlen, dir, data, ofs, datalen, tlen, timeout);
  611. IF Debug.Trace & Debug.traceScTransfers THEN
  612. KernelLog.String("UsbStorageBase: Sent "); KernelLog.Int(cmdlen, 0); KernelLog.String(" bytes commands, res: ");
  613. ShowRes(res); KernelLog.Ln;
  614. END;
  615. IF (res = ResDisconnected) THEN
  616. RETURN res;
  617. END;
  618. forceRetry := FALSE;
  619. IF (res = ResFatalError) OR (res = ResTimeout) THEN
  620. res := Reset(5000); (* ignore res *)
  621. IF res # ResOk THEN
  622. (* TODO:
  623. lun := SYSTEM.VAL(LONGINT, LSH(SYSTEM.VAL(SET, ORD(cmd[1])) * {5..7}, -5));
  624. res := SendDiagnostic(lun); (* hardware reset; ignore res *) *)
  625. RETURN ResFatalError;
  626. ELSE
  627. forceRetry := TRUE;
  628. res := ResError; (* retry *)
  629. END;
  630. END;
  631. IF (res = ResShortTransfer) & (transportMethod # MethodCB) THEN
  632. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorageBase: Had a short read"); KernelLog.Ln; END;
  633. RETURN ResShortTransfer;
  634. END;
  635. (* Do an auto-sense if something was not ok or if we are using the CB (not CBI) transport method *)
  636. IF (res = ResOk) & (transportMethod # MethodCB) THEN
  637. RETURN ResOk;
  638. END;
  639. (* It makes no sense to auto-sense on Inquiry/Sense on UFI/CB (not CBI)*)
  640. IF (transportMethod = MethodCB) & (transportProtocol = ProtocolUFI) & ((res = ResOk) OR (res = ResShortTransfer)) THEN
  641. IF (ORD(cmd[0]) = UfiInquiry) OR (ORD(cmd[0]) = UfiRequestSense) THEN RETURN res; END;
  642. END;
  643. res := RequestSense(SYSTEM.VAL(LONGINT, LSH(SYSTEM.VAL(SET, ORD(cmd[1])) * {5..7}, -5)), sensecmdlen);
  644. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorageBase: Sent sense command, res: "); ShowRes(res); KernelLog.Ln; END;
  645. IF (res = ResWriteProtected) OR (res = ResDeviceInUse) OR (res = ResMediaMissing) OR (res = ResUnsupported) OR (res = ResDisconnected)THEN
  646. RETURN res; (* don't retry *)
  647. END;
  648. IF forceRetry OR (res = ResDeviceNotReady) THEN
  649. INC(retry);
  650. IF retry = 4 THEN
  651. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorageBase: Too many protocol retries, giving up"); KernelLog.Ln; END;
  652. EXIT;
  653. ELSE
  654. IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorageBase: Retry #"); KernelLog.Int(retry, 0); KernelLog.Ln; END;
  655. END;
  656. ELSE
  657. EXIT;
  658. END;
  659. Wait(50); (* try again *)
  660. END;
  661. RETURN res;
  662. END InvokeTransport;
  663. PROCEDURE Initialization*() : BOOLEAN;
  664. BEGIN
  665. (* dummy *)
  666. RETURN TRUE;
  667. END Initialization;
  668. PROCEDURE RegisterDevice(lun : LONGINT) : BOOLEAN;
  669. VAR stordev : UsbStorageDevice; info : InquiryResult; i, j : LONGINT;
  670. BEGIN
  671. info := Inquiry(lun);
  672. IF info # NIL THEN
  673. NEW(stordev);
  674. stordev.SetName("USB");
  675. IF info.validStrings THEN (* override description *)
  676. Lib.TrimWS(info.vendor);
  677. stordev.desc := ""; i := 0; j := 0;
  678. LOOP (* append vendor string *)
  679. IF (i >= LEN(info.vendor)) OR (info.vendor[i] = 0X) THEN EXIT; END;
  680. stordev.desc[j] := info.vendor[i];
  681. INC(i); INC(j);
  682. END;
  683. IF j # 0 THEN stordev.desc[j] := " "; INC(j); END;
  684. Lib.TrimWS(info.product);
  685. i := 0;
  686. LOOP (* append product string *)
  687. IF (i >= LEN(info.product)) OR (info.product[i] = 0X) THEN EXIT; END;
  688. stordev.desc[j] := info.product[i];
  689. INC(i); INC(j);
  690. END;
  691. stordev.desc[j] := 0X;
  692. ELSE (* use USB vendor/product strings *)
  693. stordev.desc := description;
  694. END;
  695. stordev.lun := lun;
  696. stordev.transportProtocol := transportProtocol;
  697. stordev.blockSize := 0;
  698. stordev.flags := {}; stordev.table := NIL; stordev.openCount := 0;
  699. stordev.usbDriver := SELF;
  700. IF (info.deviceType = DtCDROM) OR (info.deviceType = DtOpticalMemory) THEN
  701. stordev.flags := stordev.flags + {Disks.ReadOnly};
  702. END;
  703. IF info.removable THEN stordev.flags := stordev.flags + {Disks.Removable}; END;
  704. diskManager.Add(stordev);
  705. RETURN TRUE;
  706. ELSE
  707. IF Debug.Level >= Debug.Default THEN
  708. KernelLog.String("UsbStorage: Inquiry for device LUN "); KernelLog.Int(lun, 0); KernelLog.String(" failed."); KernelLog.Ln;
  709. END;
  710. RETURN FALSE;
  711. END;
  712. END RegisterDevice;
  713. PROCEDURE RegisterDevices() : BOOLEAN;
  714. VAR lun, maxlun, res : LONGINT; succeeded : LONGINT; (* How many storage device were added to the disk manager? *)
  715. BEGIN
  716. maxlun := 0; succeeded := 0;
  717. IF transportMethod = MethodBulkOnly THEN (* logical devices support *)
  718. res := GetMaxLun(maxlun);
  719. IF res = ResOk THEN
  720. IF Debug.Trace & Debug.traceInfo THEN KernelLog.String("UsbStorageBase: MaxLUN is "); KernelLog.Int(maxlun, 0); KernelLog.Ln; END;
  721. ELSIF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorageBase: GetMaxLun failed: "); ShowRes(res); KernelLog.Ln;
  722. END;
  723. END;
  724. FOR lun := 0 TO maxlun DO
  725. IF RegisterDevice(lun) THEN INC(succeeded); END;
  726. END;
  727. RETURN succeeded > 0;
  728. END RegisterDevices;
  729. PROCEDURE Connect*(): BOOLEAN;
  730. BEGIN
  731. (* note that this procedure is common to the Bulkonly, CB and CB/I transport layer *)
  732. (* get the default control pipe *)
  733. defaultPipe := device.GetPipe(0);
  734. (* get the bulk pipes *)
  735. bulkInPipe := device.GetPipe(bulkIn);
  736. bulkOutPipe := device.GetPipe(bulkOut);
  737. IF (bulkInPipe=NIL) OR (bulkOutPipe=NIL) THEN
  738. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Could not allocate pipes"); KernelLog.Ln; END;
  739. RETURN FALSE;
  740. END;
  741. (* if the interface support a interrupt endpoint, get the corresponding pipe *)
  742. IF (interrupt # 0) & (transportMethod # MethodBulkOnly) THEN
  743. interruptPipe := device.GetPipe(interrupt);
  744. IF interruptPipe = NIL THEN
  745. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Could not allocate interrupt pipe."); KernelLog.Ln; END;
  746. RETURN FALSE;
  747. END;
  748. END;
  749. IF initialize & ~Initialization() THEN
  750. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Could not initialize device."); KernelLog.Ln; END;
  751. RETURN FALSE;
  752. END;
  753. IF ~RegisterDevices() THEN
  754. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Error while registering new devices."); KernelLog.Ln; END;
  755. RETURN FALSE;
  756. END;
  757. RETURN TRUE;
  758. END Connect;
  759. PROCEDURE Disconnect*;
  760. BEGIN
  761. diskManager.RemovedDriver(SELF);
  762. END Disconnect;
  763. PROCEDURE Wait(ms : LONGINT);
  764. BEGIN
  765. timer.Sleep(ms);
  766. END Wait;
  767. PROCEDURE &Init*;
  768. BEGIN
  769. NEW(timer);
  770. END Init;
  771. END StorageDriver;
  772. TYPE
  773. (* Manages a list of all installed USB storage devices and registers/unregisters them at the Disks.registry *)
  774. DiskManager = OBJECT
  775. VAR
  776. storageDeviceList : UsbStorageDevice;
  777. suffixUsed : ARRAY 100 OF BOOLEAN;
  778. regName : ARRAY 32 OF CHAR;
  779. res : WORD;
  780. PROCEDURE Add*(dev : UsbStorageDevice);
  781. VAR i : LONGINT;
  782. BEGIN {EXCLUSIVE}
  783. ASSERT(dev#NIL);
  784. (* add new device to list *)
  785. dev.next := storageDeviceList.next; storageDeviceList.next := dev;
  786. (* get unused suffix *)
  787. i := 0; WHILE suffixUsed[i] & (i < 100) DO INC(i) END;
  788. IF (i = 99) & suffixUsed[99] THEN
  789. KernelLog.String("UsbStorage: Can't register storage device. Maximal 100 devices supported."); KernelLog.Ln;
  790. RETURN;
  791. END;
  792. (* generate unique device name *)
  793. suffixUsed[i] := TRUE; dev.number := i;
  794. i := 1; WHILE (dev.name[i] # 0X) & (i < 32) DO INC(i); END;
  795. IF (dev.name[i] # 0X) THEN
  796. KernelLog.String("UsbStorage: Error: Couldn't register the device "); KernelLog.String(dev.name);
  797. KernelLog.String(" (device names shall be 2-30 characters long (incl. 0X)"); KernelLog.Ln;
  798. suffixUsed[dev.number] := FALSE;
  799. RETURN;
  800. END;
  801. COPY(dev.name, regName);
  802. IF dev.number < 10 THEN
  803. regName[i] := CHR(ORD("0") + dev.number); regName[i+1] := 0X;
  804. ELSIF dev.number < 100 THEN
  805. regName[i] := CHR(ORD("0") + dev.number DIV 10);
  806. regName[i+1] := CHR(ORD("0") + dev.number MOD 10); regName[i+2] := 0X;
  807. END;
  808. dev.SetName(regName);
  809. Disks.registry.Add(dev, res);
  810. IF res # Plugins.Ok THEN
  811. KernelLog.String("UsbStorage: Error: Couldn't add device to Disks.registry (Error code: ");
  812. KernelLog.Int(res, 0); KernelLog.String(")"); KernelLog.Ln;
  813. suffixUsed[dev.number] := FALSE;
  814. RETURN;
  815. END;
  816. IF Debug.Verbose THEN
  817. KernelLog.String("UsbStorage: Storage device "); KernelLog.String(dev.name);
  818. KernelLog.String(" ("); KernelLog.String(dev.desc); KernelLog.String(") is now accessible."); KernelLog.Ln;
  819. END;
  820. END Add;
  821. (** Remove storage device from Disks.registry. *)
  822. PROCEDURE Remove*(dev : UsbStorageDevice);
  823. VAR temp : UsbStorageDevice;
  824. BEGIN {EXCLUSIVE}
  825. temp:=storageDeviceList;
  826. WHILE (temp.next#NIL) & (temp.next.name#dev.name) DO temp:=temp.next; END;
  827. IF (temp.next=NIL) OR (temp.next.name#dev.name) THEN
  828. IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: Warning: Couldn't remove device from registry (device not found)"); KernelLog.Ln; END;
  829. ELSE
  830. temp.next := temp.next.next;
  831. Disks.registry.Remove(dev);
  832. suffixUsed[dev.number]:=FALSE;
  833. END;
  834. IF Debug.Verbose THEN
  835. KernelLog.String("UsbStorage: Removed storage device "); KernelLog.String(dev.name);
  836. KernelLog.String(" ("); KernelLog.String(dev.desc); KernelLog.String(")"); KernelLog.Ln;
  837. END;
  838. END Remove;
  839. (* Remove all storage devices associated to the specifed storage device driver *)
  840. PROCEDURE RemovedDriver*(driver : StorageDriver);
  841. VAR temp : UsbStorageDevice;
  842. BEGIN {EXCLUSIVE}
  843. temp := storageDeviceList;
  844. WHILE(temp # NIL) & (temp.next # NIL) DO
  845. IF temp.next.usbDriver = driver THEN
  846. Disks.registry.Remove(temp.next);
  847. suffixUsed[temp.next.number] := FALSE;
  848. IF Debug.Verbose THEN
  849. KernelLog.String("UsbStorage: Remove storage device "); KernelLog.String(temp.next.name);
  850. KernelLog.String(" ("); KernelLog.String(temp.next.desc); KernelLog.String(")"); KernelLog.Ln;
  851. END;
  852. temp.next := temp.next.next;
  853. ELSE
  854. temp := temp.next;
  855. END;
  856. END;
  857. END RemovedDriver;
  858. (* Removes all USB storage devices from the Disks.registry. *)
  859. PROCEDURE RemoveAll*;
  860. VAR temp : UsbStorageDevice;
  861. BEGIN {EXCLUSIVE}
  862. temp := storageDeviceList.next;
  863. WHILE temp # NIL DO
  864. Disks.registry.Remove(temp);
  865. suffixUsed[temp.number] := FALSE;
  866. temp := temp.next;
  867. END;
  868. storageDeviceList.next := NIL;
  869. IF Debug.Verbose THEN KernelLog.Enter; KernelLog.String("UsbStorage: All storage devices removed."); KernelLog.Exit; END;
  870. END RemoveAll;
  871. (* Displays a list of all USB storage devices which are registered at the DiskManager *)
  872. PROCEDURE Show;
  873. VAR temp : UsbStorageDevice;
  874. BEGIN
  875. KernelLog.String("UsbStorage: Accessible USB storage devices:"); KernelLog.Ln;
  876. IF storageDeviceList.next=NIL THEN
  877. KernelLog.String("No devices registred.");
  878. ELSE
  879. temp := storageDeviceList.next;
  880. WHILE temp # NIL DO
  881. KernelLog.String(temp.name); KernelLog.String(" ("); KernelLog.String(temp.desc); KernelLog.String(")"); KernelLog.Ln;
  882. temp := temp.next;
  883. END;
  884. KernelLog.Ln;
  885. END;
  886. END Show;
  887. PROCEDURE &Init*;
  888. BEGIN
  889. NEW(storageDeviceList);
  890. END Init;
  891. END DiskManager;
  892. VAR
  893. diskManager- : DiskManager;
  894. performance- : LONGINT;
  895. (* displays the UFI command to KernelLog *)
  896. PROCEDURE ShowUFICmd(cmd : CHAR) ;
  897. BEGIN
  898. IF Debug.Trace THEN
  899. CASE ORD(cmd) OF
  900. 04H : KernelLog.String("Format Unit");
  901. | 12H : KernelLog.String("Inquiry");
  902. | 55H : KernelLog.String("Mode Select");
  903. | 5AH : KernelLog.String("Mode Sense");
  904. | 1EH : KernelLog.String("Prevent-Allow Media Removal");
  905. | 28H : KernelLog.String("Read(10)");
  906. | 0A8H : KernelLog.String("Read(12)");
  907. | 25H : KernelLog.String("Read Capacity");
  908. | 23H : KernelLog.String("Read Format Capabilities");
  909. | 03H : KernelLog.String("Request Sense");
  910. | 01H : KernelLog.String("Rezero");
  911. | 2BH : KernelLog.String("Seek(10)");
  912. | 1DH : KernelLog.String("Send Diagnostic");
  913. | 1BH :KernelLog.String("Start-Stop Unit");
  914. | 00H : KernelLog.String("Test Unit Ready");
  915. | 2FH : KernelLog.String("Verify");
  916. | 2AH : KernelLog.String("Write(10)");
  917. | 0AAH : KernelLog.String("Write(12)");
  918. | 2EH : KernelLog.String("Write and Verify");
  919. ELSE
  920. KernelLog.String("Unknown Command("); KernelLog.Int(ORD(cmd), 0); KernelLog.String(")");
  921. END;
  922. END;
  923. END ShowUFICmd;
  924. PROCEDURE ShowInquiryResult(i : InquiryResult);
  925. BEGIN
  926. IF Debug.Trace THEN
  927. KernelLog.String("Inquiry data:"); KernelLog.Ln;
  928. IF i # NIL THEN
  929. KernelLog.String(" Peripheral device type: "); KernelLog.Int(i.deviceType, 0);
  930. IF i.removable THEN KernelLog.String(" [removable]"); ELSE KernelLog.String(" [not removable]"); END; KernelLog.Ln;
  931. KernelLog.String(" ANSI version: "); KernelLog.Int(i.ansiVersion, 0); KernelLog.Ln;
  932. KernelLog.String(" Additional Length: "); KernelLog.Int(i.additionalLength, 0); KernelLog.String("B"); KernelLog.Ln;
  933. KernelLog.String(" Vendor: "); KernelLog.String(i.vendor); KernelLog.Ln;
  934. KernelLog.String(" Product: "); KernelLog.String(i.product); KernelLog.Ln;
  935. KernelLog.String(" Revision: "); KernelLog.String(i.revision); KernelLog.Ln;
  936. ELSE
  937. KernelLog.String("Information not available");
  938. END;
  939. END;
  940. END ShowInquiryResult;
  941. PROCEDURE ShowFlexibleDiskPage(fdp : FlexibleDiskPage);
  942. BEGIN
  943. IF Debug.Trace THEN
  944. KernelLog.String("UsbStorage: Flexible Disk Page Contents: "); KernelLog.Ln;
  945. IF fdp # NIL THEN
  946. KernelLog.String(" Transfer rate: "); KernelLog.Int(fdp.TransferRate, 0); KernelLog.String(" kbits/s"); KernelLog.Ln;
  947. KernelLog.String(" Cylinders: "); KernelLog.Int(fdp.NumberOfCylinders, 0);
  948. KernelLog.String(" Heads: "); KernelLog.Int(fdp.NumberOfHeads, 0);
  949. KernelLog.String(" SectorsPerTrack: "); KernelLog.Int(fdp.SectorsPerTrack, 0);
  950. KernelLog.String(" BytesPerSector: "); KernelLog.Int(fdp.BytesPerSector, 0); KernelLog.Ln;
  951. KernelLog.String(" Motordelay On: "); KernelLog.Int(fdp.MotorOnDelay, 0);
  952. KernelLog.String(" Off: "); IF fdp.MotorOffDelay = 0 THEN KernelLog.String("Don't turn off!!"); ELSE KernelLog.Int(fdp.MotorOffDelay, 0); END;
  953. KernelLog.Ln;
  954. KernelLog.String(" Medium Rotation rate: "); KernelLog.Int(fdp.MediumRotationRate, 0); KernelLog.String(" rpm"); KernelLog.Ln;
  955. ELSE
  956. KernelLog.String("Information not available"); KernelLog.Ln;
  957. END;
  958. END;
  959. END ShowFlexibleDiskPage;
  960. PROCEDURE ShowSenseData(key, asc, ascq : CHAR; information : LONGINT; valid : BOOLEAN);
  961. BEGIN
  962. IF Debug.Trace THEN
  963. KernelLog.String("UsbStorage: Sense Key: "); KernelLog.Int(ORD(key), 0);
  964. KernelLog.String(" asc: "); KernelLog.Hex(ORD(asc), 0); KernelLog.String(" ascq: "); KernelLog.Hex(ORD(ascq), 0); KernelLog.String(" -> ");
  965. IF key = 0X THEN KernelLog.String("Device reports error, but auto-sense gives 0X");
  966. ELSIF (key = 1X) & (asc = 17X) & (ascq = 01X) THEN KernelLog.String("Recovered data with retries");
  967. ELSIF (key = 1X) & (asc = 18X) & (ascq = 00X) THEN KernelLog.String("Recovered data with ECC");
  968. ELSIF (key = 1X) THEN KernelLog.String("Recovered Error");
  969. ELSIF (key = 2X) & (asc = 04X) & (ascq = 01X) THEN KernelLog.String("Logical drive not ready, becoming ready");
  970. ELSIF (key = 2X) & (asc = 04X) & (ascq = 02X) THEN KernelLog.String("Logical drive not ready - initialization required");
  971. ELSIF (key = 2X) & (asc = 04X) & (ascq = 04X) THEN KernelLog.String("Logical unit not ready - format in progress");
  972. ELSIF (key = 2X) & (asc = 04X) & (ascq = 0FFX) THEN KernelLog.String("Logical drive not ready - device is busy");
  973. ELSIF (key = 2X) & (asc = 06X) & (ascq = 00X) THEN KernelLog.String("No reference position found");
  974. ELSIF (key = 2X) & (asc = 08X) & (ascq = 00X) THEN KernelLog.String("Logical unit communication failure");
  975. ELSIF (key = 2X) & (asc = 08X) & (ascq = 01X) THEN KernelLog.String("Logical unit communication timeout");
  976. ELSIF (key = 2X) & (asc = 08X) & (ascq = 80X) THEN KernelLog.String("Logical unit communication overrun");
  977. ELSIF (key = 2X) & (asc = 3AX) & (ascq = 00X) THEN KernelLog.String("Medium not present");
  978. ELSIF (key = 2X) & (asc = 54X) & (ascq = 00X) THEN KernelLog.String("USB to host system interface failure");
  979. ELSIF (key = 2X) & (asc = 80X) & (ascq = 00X) THEN KernelLog.String("Insufficient resources");
  980. ELSIF (key = 2X) & (asc = 0FFX) & (ascq = 0FFX) THEN KernelLog.String("Unknown error");
  981. ELSIF (key = 2X) THEN KernelLog.String("Not Ready");
  982. ELSIF (key = 3X) & (asc = 02X) & (ascq = 00X) THEN KernelLog.String("No seek complete");
  983. ELSIF (key = 3X) & (asc = 03X) & (ascq = 00X) THEN KernelLog.String("Write fault");
  984. ELSIF (key = 3X) & (asc = 10X) & (ascq = 00X) THEN KernelLog.String("ID CRC Error");
  985. ELSIF (key = 3X) & (asc = 11X) & (ascq = 00X) THEN KernelLog.String("Unrecovered read error");
  986. ELSIF (key = 3X) & (asc = 12X) & (ascq = 00X) THEN KernelLog.String("Address mark not found for ID field");
  987. ELSIF (key = 3X) & (asc = 13X) & (ascq = 00X) THEN KernelLog.String("Address mark not found for data field");
  988. ELSIF (key = 3X) & (asc = 14X) & (ascq = 00X) THEN KernelLog.String("Recorded entity not found");
  989. ELSIF (key = 3X) & (asc = 30X) & (ascq = 01X) THEN KernelLog.String("Cannot read medium - unknown format");
  990. ELSIF (key = 3X) & (asc = 31X) & (ascq = 01X) THEN KernelLog.String("Format command failed");
  991. ELSIF (key = 3X) THEN KernelLog.String("Medium Error");
  992. ELSIF (key = 4X) & (asc = 40X) THEN KernelLog.String("Diagnostic failure on component "); KernelLog.Int(ORD(ascq), 0);
  993. ELSIF (key = 4X) THEN KernelLog.String("Hardware Error");
  994. ELSIF (key = 5X) & (asc = 1AX) & (ascq = 00X) THEN KernelLog.String("Parameter list length error");
  995. ELSIF (key = 5X) & (asc = 20X) & (ascq = 00X) THEN KernelLog.String("Invalid command operation code");
  996. ELSIF (key = 5X) & (asc = 21X) & (ascq = 00X) THEN KernelLog.String("Logical block address out of range");
  997. ELSIF (key = 5X) & (asc = 24X) & (ascq = 00X) THEN KernelLog.String("Invalid field in command packet");
  998. ELSIF (key = 5X) & (asc = 25X) & (ascq = 00X) THEN KernelLog.String("Logical unit not supported");
  999. ELSIF (key = 5X) & (asc = 26X) & (ascq = 00X) THEN KernelLog.String("Invalid field in parameter list");
  1000. ELSIF (key = 5X) & (asc = 26X) & (ascq = 01X) THEN KernelLog.String("Parameter not supported");
  1001. ELSIF (key = 5X) & (asc = 26X) & (ascq = 02X) THEN KernelLog.String("Parameter value invalid");
  1002. ELSIF (key = 5X) & (asc = 39X) & (ascq = 00X) THEN KernelLog.String("Saving parameters not supported");
  1003. ELSIF (key = 5X) THEN KernelLog.String("Illegal Request");
  1004. ELSIF (key = 6X) & (asc = 28X) & (ascq = 00X) THEN KernelLog.String("Not ready to ready transition - media changed");
  1005. ELSIF (key = 6X) & (asc = 29X) & (ascq = 00X) THEN KernelLog.String("PowerOnReset, retrying");
  1006. ELSIF (key = 6X) & (asc = 2FX) & (ascq = 00X) THEN KernelLog.String("Commands cleared by another indicator");
  1007. ELSIF (key = 6X) THEN KernelLog.String("Unit Attention");
  1008. ELSIF (key = 7X) & (asc = 27X) & (ascq = 00X) THEN KernelLog.String("Write protected media");
  1009. ELSIF (key = 7X) THEN KernelLog.String("Data Protected");
  1010. ELSIF (key = 8X) THEN KernelLog.String("Blank Check");
  1011. ELSIF (key = 9X) THEN KernelLog.String("Vendor Specific");
  1012. ELSIF (key = 0AX) THEN KernelLog.String("Reserved");
  1013. ELSIF (key = 0BX) & (asc = 4EX) & (ascq = 00X) THEN KernelLog.String("Overlapped command attemted");
  1014. ELSIF (key = 0BX) THEN KernelLog.String("Aborted command");
  1015. ELSIF (key = 0CX) THEN KernelLog.String("Reserved");
  1016. ELSIF (key = 0DX) THEN KernelLog.String("Volume Overflow");
  1017. ELSIF (key = 0EX) THEN KernelLog.String("Miscompare");
  1018. ELSIF (key = 0FX) THEN KernelLog.String("Reserved");
  1019. ELSE KernelLog.String("Unkown");
  1020. END;
  1021. IF valid THEN KernelLog.String(" [information: "); KernelLog.Int(information, 0); KernelLog.String("]"); END;
  1022. KernelLog.Ln;
  1023. END;
  1024. END ShowSenseData;
  1025. PROCEDURE ShowRes(res : WORD);
  1026. BEGIN
  1027. IF Debug.Level >= Debug.Errors THEN
  1028. CASE res OF
  1029. ResOk: KernelLog.String("OK");
  1030. |ResWriteProtected: KernelLog.String("Write-Protected");
  1031. |ResDeviceInUse: KernelLog.String("DeviceInUse");
  1032. |ResMediaChanged: KernelLog.String("MediaChanged");
  1033. |ResMediaMissing: KernelLog.String("MediaMissing");
  1034. |ResUnsupported: KernelLog.String("Unsupported");
  1035. |ResTimeout: KernelLog.String("Timeout");
  1036. |ResShortTransfer: KernelLog.String("ShortTransfer");
  1037. |ResDeviceNotReady: KernelLog.String("DeviceNotReady");
  1038. |ResDeviceNotReadyInit: KernelLog.String("DeviceNotReady-need init");
  1039. |ResSenseError: KernelLog.String("SenseError");
  1040. |ResError: KernelLog.String("Error");
  1041. |ResFatalError: KernelLog.String("FatalError");
  1042. |ResDisconnected: KernelLog.String("Disconnected");
  1043. ELSE
  1044. KernelLog.String("Unknown(res="); KernelLog.Int(res, 0); KernelLog.String(")");
  1045. END;
  1046. END;
  1047. END ShowRes;
  1048. (** Shows all devices which are registered at the UsbStorage Disk Manager and the Disks.registry *)
  1049. PROCEDURE Show*(context : Commands.Context);
  1050. VAR table : Plugins.Table; i : LONGINT;
  1051. BEGIN
  1052. (* show all devices which are registered at the UsbStorage disk manager *)
  1053. diskManager.Show;
  1054. (* show all devices registered at Disks.registry *)
  1055. Disks.registry.GetAll(table);
  1056. context.out.String("Storage devices registered at Disks.registry:"); context.out.Ln;
  1057. IF table = NIL THEN
  1058. context.out.String("No devices registered."); context.out.Ln;
  1059. ELSE
  1060. FOR i := 0 TO LEN(table)-1 DO
  1061. context.out.String(table[i].name); context.out.String(" ("); context.out.String(table[i].desc); context.out.String(")"); context.out.Ln;
  1062. END;
  1063. END;
  1064. END Show;
  1065. (* ToBeRemoved *)
  1066. PROCEDURE SetMax*(context : Commands.Context);
  1067. BEGIN
  1068. context.out.String("UsbStorage: Max performance mode."); context.out.Ln;
  1069. performance := Usbdi.MaxPerformance;
  1070. END SetMax;
  1071. (* ToBeRemoved *)
  1072. PROCEDURE SetNormal*(context : Commands.Context);
  1073. BEGIN
  1074. context.out.String("UsbStorage: Normal performance mode."); context.out.Ln;
  1075. performance := Usbdi.Normal;
  1076. END SetNormal;
  1077. BEGIN
  1078. NEW(diskManager);
  1079. performance := Usbdi.MaxPerformance;
  1080. END UsbStorageBase.
  1081. UsbStorage.Install ~ System.Free UsbStorage ~
  1082. UsbStorage.Show ~