MODULE UsbStorageBase;
IMPORT SYSTEM, KernelLog, Kernel, Commands, Disks, Plugins, Usbdi, Debug := UsbDebug, Lib := UsbUtilities;
CONST
NoData* = {};
DataIn* = {1};
DataOut* = {2};
ResOk* = Disks.Ok;
ResWriteProtected* = Disks.WriteProtected;
ResDeviceInUse* = Disks.DeviceInUse;
ResMediaChanged* = Disks.MediaChanged;
ResMediaMissing* = Disks.MediaMissing;
ResUnsupported* = Disks.Unsupported;
ResTimeout* = 30;
ResShortTransfer* = 31;
ResDeviceNotReady* = 32;
ResDeviceNotReadyInit* = 33;
ResSenseError* = 34;
ResError* = 35;
ResFatalError* = 36;
ResDisconnected* = 37;
MethodCBI* = 1;
MethodCB* = 2;
MethodBulkOnly* = 3;
MethodSCMShuttle* = 4;
ProtocolUFI* = 100;
ProtocolUTS* = 101;
ProtocolRBC* = 102;
Protocol8020* = 103;
Protocol8070* = 104;
ProtocolQIC157* = 105;
UfiFormatUnit = 04H;
UfiInquiry = 12H;
UfiStartStop = 1BH;
UfiModeSelect = 55H;
UfiModeSense = 5AH;
UfiAllowRemoval = 1EH;
UfiRead10* = 28H;
UfiRead12 = 0A8H;
UfiReadCapacity = 25H;
UfiReadFormatCapacity = 23H;
UfiRequestSense = 03H;
UfiRezeroUnit = 01H;
UfiSeek10 = 2BH;
UfiSendDiag = 1DH;
UfiTestUnitReady = 00H;
UfiVerify = 2FH;
UfiWrite10 = 2AH;
UfiWrite12 = 0AAH;
UfiWriteNVerify = 2EH;
DtSbcDirectAccess = 00H;
DtCDROM = 05H;
DtOpticalMemory = 07H;
DtRbcDirectAccess = 0EH;
RemovableBit = {7};
PcCurrentValues = 0;
PcChangeableValues = 1;
PcDefaultValues = 2;
PcSavedValues = 3;
PageRwErrorRecovery = 01H;
PageFlexibleDisk = 05H;
PageBlockAccessCapacities = 1BH;
PageTimerAndProtect = 1CH;
PageAll = 3FH;
TransferTimeout = 20000;
CommandTimeout = 5000;
TYPE
InquiryResult = POINTER TO RECORD
deviceType : LONGINT;
removable : BOOLEAN;
ansiVersion : LONGINT;
additionalLength : LONGINT;
validStrings : BOOLEAN;
vendor : ARRAY 9 OF CHAR;
product : ARRAY 17 OF CHAR;
revision : ARRAY 5 OF CHAR;
END;
FlexibleDiskPage = POINTER TO RECORD
TransferRate : LONGINT;
NumberOfHeads : LONGINT;
SectorsPerTrack : LONGINT;
BytesPerSector : LONGINT;
NumberOfCylinders : LONGINT;
MotorOnDelay, MotorOffDelay : LONGINT;
MediumRotationRate : LONGINT;
END;
TYPE
UsbStorageDevice = OBJECT (Disks.Device)
VAR
usbDriver : StorageDriver;
lun : LONGINT;
transportProtocol : LONGINT;
number : LONGINT;
next : UsbStorageDevice;
PROCEDURE Transfer* (op, block, num: LONGINT; VAR data: ARRAY OF CHAR; ofs: LONGINT; VAR diskres: LONGINT);
VAR direction : SET; cmd : ARRAY 12 OF CHAR; i, tlen, trans, offset, num0 : LONGINT;
BEGIN {EXCLUSIVE}
IF (op = Disks.Read) OR (op = Disks.Write) THEN
FOR i := 0 TO 11 DO cmd[i] := 0X; END;
IF op = Disks.Read THEN
cmd[0] := CHR(UfiRead10); direction := DataIn;
ELSE
cmd[0] := CHR(UfiWrite10); direction := DataOut;
END;
cmd[1] := CHR(SYSTEM.LSH(lun, 5));
offset := ofs; num0 := num;
WHILE num > 0 DO
IF num > 65000 THEN trans := 65000; ELSE trans := num END;
cmd[2] := CHR(SYSTEM.LSH(block, -24));
cmd[3] := CHR(SYSTEM.LSH(block, -16));
cmd[4] := CHR(SYSTEM.LSH(block, -8));
cmd[5] := CHR(block);
cmd[7] := CHR(SYSTEM.LSH(trans, -8));
cmd[8] := CHR(trans);
cmd[9] := 0X;
diskres := usbDriver.InvokeTransport(cmd, 12, direction, data, offset, trans * blockSize, tlen, TransferTimeout);
IF diskres # Disks.Ok THEN RETURN; END;
block := block + trans;
num := num - trans;
offset := offset + (trans * blockSize);
END;
IF Disks.Stats THEN
IF (op = Disks.Read) THEN
INC (NnofReads);
IF (diskres = ResOk) THEN INC (NbytesRead, num0 * blockSize);
ELSE INC (NnofErrors);
END;
ELSE
INC (NnofWrites);
IF (diskres = ResOk) THEN INC (NbytesWritten, num0 * blockSize);
ELSE INC (NnofErrors);
END;
END;
END;
ELSE
diskres := Disks.Unsupported;
IF Disks.Stats THEN INC (NnofOthers); END;
END;
END Transfer;
PROCEDURE GetSize* (VAR size, res: LONGINT);
BEGIN {EXCLUSIVE}
IF Debug.Trace & Debug.traceInfo THEN KernelLog.String("UsbStorage: GetSize: "); KernelLog.Ln; END;
res := usbDriver.WaitForReady(lun, 5000);
IF (res # ResOk) & (res # ResMediaChanged) THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: GetCapacity: command failed: "); ShowRes(res); KernelLog.Ln; END;
RETURN;
END;
blockSize := 0; size := 0;
res := usbDriver.ReadCapacity(lun, size, blockSize);
IF ((res # ResOk) & (res # ResShortTransfer)) THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ReadCapacity: command failed: "); ShowRes(res); KernelLog.Ln; END;
RETURN;
END;
res := ResOk;
END GetSize;
PROCEDURE Handle*(VAR msg: Disks.Message; VAR diskres: LONGINT);
VAR cmd : ARRAY 12 OF CHAR; i : LONGINT; fdp : FlexibleDiskPage;
BEGIN {EXCLUSIVE}
FOR i := 0 TO 11 DO cmd[i] := CHR(0); END;
IF msg IS Disks.GetGeometryMsg THEN
IF transportProtocol = ProtocolUFI THEN
WITH msg : Disks.GetGeometryMsg DO
fdp := usbDriver.ModeSense(lun, 0, PageFlexibleDisk, 32);
IF fdp # NIL THEN
msg.spt := fdp.SectorsPerTrack;
msg.hds := fdp.NumberOfHeads;
msg.cyls := fdp.NumberOfCylinders;
ELSE
msg.spt := 18; msg.hds := 2; msg.cyls := 80;
END;
IF Debug.Trace & Debug.traceScRequests THEN
KernelLog.String("UsbStorageBase: Disk geometry CHS:");
KernelLog.Int(msg.cyls, 0); KernelLog.String("x"); KernelLog.Int(msg.hds, 0); KernelLog.String("x"); KernelLog.Int(msg.spt, 0); KernelLog.Ln;
END;
END;
diskres := Disks.Ok;
ELSE
diskres := Disks.Unsupported;
END;
ELSIF msg IS Disks.LockMsg THEN
diskres := usbDriver.PreventMediumRemoval(lun, TRUE);
ELSIF msg IS Disks.UnlockMsg THEN
diskres := usbDriver.PreventMediumRemoval(lun, FALSE);
ELSIF msg IS Disks.EjectMsg THEN
diskres := usbDriver.EjectMedia(lun);
ELSE
diskres := Disks.Unsupported;
END;
END Handle;
END UsbStorageDevice;
TYPE
StorageDriver* = OBJECT (Usbdi.Driver);
VAR
sdevs- : UsbStorageDevice;
description* : Plugins.Description;
transportProtocol*, transportMethod* : LONGINT;
bulkIn*, bulkOut*, interrupt* : LONGINT;
bulkInPipe-, bulkOutPipe-, interruptPipe-, defaultPipe- : Usbdi.Pipe;
initialize* : BOOLEAN;
timer : Kernel.Timer;
PROCEDURE Reset*(timeout : LONGINT) : LONGINT;
BEGIN
HALT(301); RETURN 0;
END Reset;
PROCEDURE Transport*(cmd : ARRAY OF CHAR; cmdlen : LONGINT; dir : SET;
VAR buffer : ARRAY OF CHAR; ofs, bufferlen : LONGINT; VAR tlen : LONGINT; timeout : LONGINT) : LONGINT;
BEGIN
HALT(301); RETURN 0;
END Transport;
PROCEDURE GetMaxLun*(VAR lun : LONGINT) : LONGINT;
BEGIN
HALT(301); RETURN 0;
END GetMaxLun;
PROCEDURE TestUnitReady(lun : LONGINT) : LONGINT;
VAR cmd : ARRAY 12 OF CHAR; i, ignore : LONGINT;
BEGIN
cmd[0] := CHR(UfiTestUnitReady);
cmd[1] := CHR(SYSTEM.LSH(lun, 5));
FOR i := 2 TO 11 DO cmd[i] := 0X; END;
RETURN InvokeTransport(cmd, 12, NoData, cmd, 0, 0, ignore, 30000);
END TestUnitReady;
PROCEDURE WaitForReady(lun, timeout : LONGINT) : LONGINT;
VAR retry, res : LONGINT;
BEGIN
IF Debug.Trace & Debug.traceScRequests THEN KernelLog.String("UsbStorageBase: WaitForReady..."); KernelLog.Ln; END;
retry := 0;
LOOP
res := TestUnitReady(lun);
IF (res = ResDisconnected) THEN
EXIT;
ELSIF (res = ResDeviceNotReady) OR (res = ResMediaChanged) THEN
ELSE
INC(retry);
END;
IF (retry > 3) OR (timeout < 0) THEN EXIT; END;
Wait(100);
timeout := timeout - 100;
END;
IF Debug.Trace & Debug.traceScRequests THEN KernelLog.String("UsbStorageBase: WaitForReady done, res: "); ShowRes(res); KernelLog.Ln; END;
RETURN res;
END WaitForReady;
PROCEDURE EjectMedia(lun : LONGINT) : LONGINT;
VAR cmd, data : ARRAY 12 OF CHAR; i, tlen, res : LONGINT;
BEGIN
cmd[0] := CHR(UfiStartStop);
cmd[1] := CHR(SYSTEM.LSH(lun, 5));
FOR i := 2 TO 11 DO cmd[i] := 0X; END;
cmd[4] := CHR(2);
res := InvokeTransport(cmd, 12, DataOut, data, 0, 0, tlen, CommandTimeout);
RETURN res;
END EjectMedia;
PROCEDURE PreventMediumRemoval(lun : LONGINT; prevent : BOOLEAN) : LONGINT;
VAR cmd, data : ARRAY 12 OF CHAR; i, tlen, res : LONGINT;
BEGIN
cmd[0] := CHR(UfiAllowRemoval);
cmd[1] := CHR(SYSTEM.LSH(lun, 5));
FOR i := 2 TO 11 DO cmd[i] := 0X; END;
IF prevent THEN cmd[4] := CHR(1); END;
res := InvokeTransport(cmd, 12, DataOut, data, 0, 0, tlen, CommandTimeout);
RETURN res;
END PreventMediumRemoval;
PROCEDURE SendDiagnostic(lun : LONGINT) : LONGINT;
VAR cmd, data : ARRAY 12 OF CHAR; i, tlen, res : LONGINT;
BEGIN
cmd[0] := CHR(UfiSendDiag);
cmd[1] := CHR(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, SYSTEM.LSH(lun, 5)) + {2}));
FOR i := 2 TO 11 DO cmd[i] := 0X; END;
res := InvokeTransport(cmd, 12, DataOut, data, 0, 0, tlen, CommandTimeout);
RETURN res;
END SendDiagnostic;
PROCEDURE ReadCapacity(lun : LONGINT; VAR blocks, blocksize : LONGINT) : LONGINT;
VAR cmd, data : ARRAY 12 OF CHAR; res, i, tlen : LONGINT;
BEGIN
IF Debug.Trace & Debug.traceInfo THEN KernelLog.String("UsbStorage: ReadCapacity: "); KernelLog.Ln; END;
cmd[0] := CHR(UfiReadCapacity);
cmd[1] := CHR(SYSTEM.LSH(lun, 5));
FOR i := 2 TO 11 DO cmd[i] := CHR(0); END;
blocks := 0; blocksize := 0;
res := InvokeTransport(cmd, 12, DataIn, data, 0, 8, tlen, TransferTimeout);
IF (res # ResOk) THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: ReadCapacity: command failed: "); ShowRes(res); KernelLog.Ln; END;
RETURN res;
END;
FOR i := 0 TO 3 DO
blocks := blocks*100H + ORD(data[i]);
blocksize := blocksize*100H + ORD(data[4+i])
END;
INC(blocks);
res := ResOk;
IF Debug.Trace & Debug.traceInfo THEN
KernelLog.String("UsbStorage: Disk info: Blocks: "); KernelLog.Int(blocks, 0);
KernelLog.String(" blocksize: "); KernelLog.Int(blocksize, 0); KernelLog.String(" size: "); KernelLog.Int(blocks*blocksize, 0);
KernelLog.Ln;
END;
RETURN ResOk;
END ReadCapacity;
PROCEDURE Inquiry(lun : LONGINT) : InquiryResult;
VAR cmd : ARRAY 12 OF CHAR; data : ARRAY 36 OF CHAR; result : InquiryResult; i, j, tlen, res : LONGINT;
BEGIN
IF Debug.Trace & Debug.traceInfo THEN
KernelLog.String("UsbStorage: Inquiry logical device "); KernelLog.Int(lun, 0); KernelLog.String("... "); KernelLog.Ln;
END;
FOR i := 0 TO 11 DO cmd[i] := CHR(0); END;
cmd[0] := CHR(UfiInquiry);
cmd[1] := CHR(SYSTEM.LSH(lun, 5));
cmd[4] := CHR(36);
res := InvokeTransport(cmd, 12, DataIn, data, 0, 36, tlen, 50000);
IF ((res # Disks.Ok) & (res # ResShortTransfer)) OR (tlen < 5) THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Fatal, inquiry device error: "); ShowRes(res); KernelLog.Ln; END;
RETURN NIL;
END;
NEW(result);
result.deviceType := ORD(data[0]) MOD 32;
IF SYSTEM.VAL(SET, ORD(data[1])) * RemovableBit # {} THEN
result.removable := TRUE;
END;
result.ansiVersion := ORD(data[2]) MOD 8;
result.additionalLength := ORD(data[4]);
IF transportProtocol = ProtocolRBC THEN
IF result.deviceType # DtRbcDirectAccess THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: RBC device type is not 0EH"); KernelLog.Ln; END;
RETURN NIL;
END;
ELSIF (result.deviceType # DtSbcDirectAccess) & (result.deviceType # DtCDROM) & (result.deviceType # DtOpticalMemory) THEN
IF Debug.Trace & Debug.traceInfo THEN KernelLog.String("UsbStorage: Device is not a storage device"); KernelLog.Ln; END;
RETURN NIL;
END;
IF tlen >= 36 THEN
result.validStrings := TRUE;
j := 0; FOR i := 8 TO 15 DO result.vendor[j] := data[i]; INC(j); END; result.vendor[8] := 0X;
j := 0; FOR i := 16 TO 31 DO result.product[j] := data[i]; INC(j); END; result.product[16] := 0X;
j := 0; FOR i := 32 TO 35 DO result.revision[j] := data[i]; INC(j); END; result.revision[4] := 0X;
END;
IF Debug.Trace & Debug.traceInfo THEN ShowInquiryResult(result); END;
RETURN result;
END Inquiry;
PROCEDURE ModeSense(lun, pagecontrol, page, length : LONGINT) : FlexibleDiskPage;
VAR cmd : ARRAY 12 OF CHAR; data : Usbdi.BufferPtr; actLen, res : LONGINT; fdp : FlexibleDiskPage;
PROCEDURE ParseFlexibleDiskPage(page : Usbdi.BufferPtr; index : LONGINT) : FlexibleDiskPage;
VAR temp : LONGINT; fdp : FlexibleDiskPage;
BEGIN
ASSERT((page # NIL) & (LEN(page) - index >= 32));
ASSERT(SYSTEM.VAL(LONGINT, (SYSTEM.VAL(SET, page[index]) * {0..5})) = PageFlexibleDisk);
NEW(fdp);
temp := SYSTEM.LSH(ORD(page[index+2]), 8) + ORD(page[index+3]);
IF temp = 00FAH THEN fdp.TransferRate := 250;
ELSIF temp = 012CH THEN fdp.TransferRate := 300;
ELSIF temp = 01F4H THEN fdp.TransferRate := 500;
ELSIF temp = 03E8H THEN fdp.TransferRate := 1000;
ELSIF temp = 07D0H THEN fdp.TransferRate := 2000;
ELSIF temp = 1388H THEN fdp.TransferRate := 5000;
ELSIF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: ParseFlexibleDiskPage: Warning: Parse error"); KernelLog.Ln;
END;
fdp.NumberOfHeads := ORD(page[index+4]);
fdp.SectorsPerTrack := ORD(page[index+5]);
fdp.BytesPerSector := SYSTEM.LSH(ORD(page[index+6]), 8) + ORD(page[index+7]);
fdp.NumberOfCylinders := SYSTEM.LSH(ORD(page[index+8]), 8) + ORD(page[index+9]);
fdp.MotorOnDelay := ORD(page[index+19]);
fdp.MotorOffDelay := ORD(page[index+20]);
IF fdp.MotorOffDelay = 0FFH THEN fdp.MotorOffDelay := 0; END;
fdp.MediumRotationRate := SYSTEM.LSH(ORD(page[index+28]), 8) + ORD(page[index+29]);
IF Debug.Trace & Debug.traceInfo THEN ShowFlexibleDiskPage(fdp); END;
RETURN fdp;
END ParseFlexibleDiskPage;
BEGIN
length := length + 8;
cmd[0] := CHR(UfiModeSense);
cmd[1] := CHR(SYSTEM.LSH(lun, 5));
cmd[2] := CHR(SYSTEM.LSH(pagecontrol, 6) + page);
cmd[3] := CHR(0);
cmd[5] := CHR(0);
cmd[6] := CHR(0);
cmd[7] := CHR(SYSTEM.LSH(length, -8));
cmd[8] := CHR(length);
cmd[9] := CHR(0);
cmd[10] := CHR(0);
cmd[11] := CHR(0);
NEW(data, length);
res := InvokeTransport (cmd, 12, DataIn, data^, 0, length, actLen, CommandTimeout);
IF ((res # Disks.Ok) OR ((res # ResShortTransfer) & (actLen < length))) THEN
IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: UFI Mode Sense command failed."); KernelLog.Ln; END;
RETURN NIL;
END;
IF (ORD(data[1]) + 100H*SYSTEM.VAL(LONGINT, ORD(data[0]))) # length + 8 THEN
IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: ModeSense: Error: Wrong Mode Data Length returned."); KernelLog.Ln; END;
RETURN NIL;
END;
CASE page OF
PageFlexibleDisk : fdp := ParseFlexibleDiskPage(data, 8);
ELSE
IF Debug.Level >= Debug.Warnings THEN
KernelLog.String("UsbStorage: ModeSense: Parsing of page type "); KernelLog.Hex(page,-2);
KernelLog.String(" not (yet) supported."); KernelLog.Ln;
END;
END;
RETURN fdp;
END ModeSense;
PROCEDURE RequestSense(lun, cmdlen : LONGINT) : LONGINT;
VAR
cmd : ARRAY 12 OF CHAR; data : ARRAY 36 OF CHAR;
key, asc, ascq : CHAR;
information : LONGINT;
i, tlen, res : LONGINT;
BEGIN
IF Debug.Trace & Debug.traceSensing THEN KernelLog.String("UsbStorage: Doing auto sense..."); KernelLog.Ln; END;
IF (transportProtocol = ProtocolUTS) OR (transportProtocol = ProtocolRBC) THEN
cmdlen := 6;
END;
FOR i := 0 TO 11 DO cmd[i] := CHR(0); END;
cmd[0] := CHR(UfiRequestSense);
cmd[1] := CHR(SYSTEM.LSH(lun, 5));
cmd[4] := CHR(18);
res := Transport(cmd, cmdlen, DataIn, data, 0, 18, tlen, 2000);
IF (res = ResDisconnected) THEN
RETURN res;
ELSIF (res = ResShortTransfer) THEN
IF (tlen < 14) THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Crappy device gives not enough sense data"); KernelLog.Ln; END;
RETURN ResSenseError;
ELSE
END;
ELSIF (transportProtocol = ProtocolUFI) & (res = ResSenseError) THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: UFI autosense TransportSenseError"); KernelLog.Ln; END;
ELSIF res # ResOk THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Sense error on protocol sense"); KernelLog.Ln; END;
res := Reset(5000);
RETURN ResSenseError;
END;
key := CHR(ORD(data[2]) MOD 16); asc := data[12]; ascq := data[13];
IF Debug.Trace & Debug.traceSensing THEN
IF SYSTEM.VAL(SET, ORD(data[0])) * {7} # {} THEN
information := ORD(data[3]) + 10H*ORD(data[4]) + 100H*ORD(data[5]) + 1000H*ORD(data[6]);
END;
ShowSenseData(key, asc, ascq, information, SYSTEM.VAL(SET, ORD(data[0])) * {7} # {});
END;
IF key = 0X THEN
IF (res = ResOk) OR (res = ResShortTransfer) THEN RETURN ResOk; END;
RETURN ResError;
ELSIF (key = 1X) THEN RETURN ResOk;
ELSIF (key = 2X) & (asc = 4X) & (ascq = 01X) THEN RETURN ResDeviceNotReady;
ELSIF (key = 2X) & (asc = 4X) & (ascq = 02X) THEN RETURN ResDeviceNotReadyInit;
ELSIF (key = 2X) & (asc = 4X) & (ascq = 04X) THEN RETURN ResDeviceInUse;
ELSIF (key = 2X) & (asc = 4X) & (ascq = 0FFX) THEN RETURN ResDeviceInUse;
ELSIF (key = 2X) & (asc = 6X) & (ascq = 00X) THEN RETURN ResError;
ELSIF (key = 2X) & (asc = 8X) & (ascq = 00X) THEN RETURN ResError;
ELSIF (key = 2X) & (asc = 8X) & (ascq = 01X) THEN RETURN ResTimeout;
ELSIF (key = 2X) & (asc = 8X) & (ascq = 80X) THEN RETURN ResError;
ELSIF (key = 2X) & (asc = 3AX) & (ascq = 0X) THEN RETURN ResMediaMissing;
ELSIF (key = 2X) THEN RETURN ResError;
ELSIF (key = 3X) THEN RETURN ResError;
ELSIF (key = 4X) THEN RETURN ResError;
ELSIF (key = 5X) THEN RETURN ResUnsupported;
ELSIF (key = 6X) & (asc = 28X) & (ascq = 00X) THEN RETURN ResMediaChanged;
ELSIF (key = 6X) & (asc = 29X) & (ascq = 0X) THEN RETURN ResDeviceNotReady;
ELSIF (key = 6X) THEN RETURN ResDeviceNotReady;
ELSIF (key = 7X) THEN RETURN ResWriteProtected;
ELSE
RETURN ResError;
END;
END RequestSense;
PROCEDURE InvokeTransport (cmd : ARRAY OF CHAR; cmdlen : INTEGER; dir : SET;
VAR data : ARRAY OF CHAR; ofs, datalen : LONGINT; VAR tlen : LONGINT; timeout : LONGINT) : LONGINT;
VAR
sensecmdlen, res, retry, i : LONGINT; forceRetry : BOOLEAN;
BEGIN {EXCLUSIVE}
IF transportProtocol = ProtocolUFI THEN
cmdlen := 12; sensecmdlen := 12;
ELSIF (transportProtocol = ProtocolUTS) OR (transportProtocol = ProtocolRBC) THEN
sensecmdlen := 6;
ELSIF (transportProtocol = Protocol8020) OR (transportProtocol = Protocol8070) THEN
cmdlen := 12; sensecmdlen := 12;
ELSIF transportProtocol = ProtocolQIC157 THEN
cmdlen := 12; sensecmdlen := 12;
END;
retry := 0;
LOOP
IF Debug.Trace & Debug.traceScTransfers THEN
KernelLog.String("UsbStorageBase: [cmd: ");
IF transportProtocol = ProtocolUFI THEN ShowUFICmd(cmd[0]); END;
FOR i := 0 TO cmdlen-1 DO KernelLog.String(" "); KernelLog.Hex(ORD(cmd[i]), -2); END;
KernelLog.String(" BufferLen: "); KernelLog.Int(datalen, 0); KernelLog.String(" Bytes]");
KernelLog.Ln;
END;
res := Transport(cmd, cmdlen, dir, data, ofs, datalen, tlen, timeout);
IF Debug.Trace & Debug.traceScTransfers THEN
KernelLog.String("UsbStorageBase: Sent "); KernelLog.Int(cmdlen, 0); KernelLog.String(" bytes commands, res: ");
ShowRes(res); KernelLog.Ln;
END;
IF (res = ResDisconnected) THEN
RETURN res;
END;
forceRetry := FALSE;
IF (res = ResFatalError) OR (res = ResTimeout) THEN
res := Reset(5000);
IF res # ResOk THEN
RETURN ResFatalError;
ELSE
forceRetry := TRUE;
res := ResError;
END;
END;
IF (res = ResShortTransfer) & (transportMethod # MethodCB) THEN
IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorageBase: Had a short read"); KernelLog.Ln; END;
RETURN ResShortTransfer;
END;
IF (res = ResOk) & (transportMethod # MethodCB) THEN
RETURN ResOk;
END;
IF (transportMethod = MethodCB) & (transportProtocol = ProtocolUFI) & ((res = ResOk) OR (res = ResShortTransfer)) THEN
IF (ORD(cmd[0]) = UfiInquiry) OR (ORD(cmd[0]) = UfiRequestSense) THEN RETURN res; END;
END;
res := RequestSense(SYSTEM.VAL(LONGINT, SYSTEM.LSH(SYSTEM.VAL(SET, ORD(cmd[1])) * {5..7}, -5)), sensecmdlen);
IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorageBase: Sent sense command, res: "); ShowRes(res); KernelLog.Ln; END;
IF (res = ResWriteProtected) OR (res = ResDeviceInUse) OR (res = ResMediaMissing) OR (res = ResUnsupported) OR (res = ResDisconnected)THEN
RETURN res;
END;
IF forceRetry OR (res = ResDeviceNotReady) THEN
INC(retry);
IF retry = 4 THEN
IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorageBase: Too many protocol retries, giving up"); KernelLog.Ln; END;
EXIT;
ELSE
IF Debug.Trace & Debug.traceScTransfers THEN KernelLog.String("UsbStorageBase: Retry #"); KernelLog.Int(retry, 0); KernelLog.Ln; END;
END;
ELSE
EXIT;
END;
Wait(50);
END;
RETURN res;
END InvokeTransport;
PROCEDURE Initialization*() : BOOLEAN;
BEGIN
RETURN TRUE;
END Initialization;
PROCEDURE RegisterDevice(lun : LONGINT) : BOOLEAN;
VAR stordev : UsbStorageDevice; info : InquiryResult; i, j : LONGINT;
BEGIN
info := Inquiry(lun);
IF info # NIL THEN
NEW(stordev);
stordev.SetName("USB");
IF info.validStrings THEN
Lib.TrimWS(info.vendor);
stordev.desc := ""; i := 0; j := 0;
LOOP
IF (i >= LEN(info.vendor)) OR (info.vendor[i] = 0X) THEN EXIT; END;
stordev.desc[j] := info.vendor[i];
INC(i); INC(j);
END;
IF j # 0 THEN stordev.desc[j] := " "; INC(j); END;
Lib.TrimWS(info.product);
i := 0;
LOOP
IF (i >= LEN(info.product)) OR (info.product[i] = 0X) THEN EXIT; END;
stordev.desc[j] := info.product[i];
INC(i); INC(j);
END;
stordev.desc[j] := 0X;
ELSE
stordev.desc := description;
END;
stordev.lun := lun;
stordev.transportProtocol := transportProtocol;
stordev.blockSize := 0;
stordev.flags := {}; stordev.table := NIL; stordev.openCount := 0;
stordev.usbDriver := SELF;
IF (info.deviceType = DtCDROM) OR (info.deviceType = DtOpticalMemory) THEN
stordev.flags := stordev.flags + {Disks.ReadOnly};
END;
IF info.removable THEN stordev.flags := stordev.flags + {Disks.Removable}; END;
diskManager.Add(stordev);
RETURN TRUE;
ELSE
IF Debug.Level >= Debug.Default THEN
KernelLog.String("UsbStorage: Inquiry for device LUN "); KernelLog.Int(lun, 0); KernelLog.String(" failed."); KernelLog.Ln;
END;
RETURN FALSE;
END;
END RegisterDevice;
PROCEDURE RegisterDevices() : BOOLEAN;
VAR lun, maxlun, res : LONGINT; succeeded : LONGINT;
BEGIN
maxlun := 0; succeeded := 0;
IF transportMethod = MethodBulkOnly THEN
res := GetMaxLun(maxlun);
IF res = ResOk THEN
IF Debug.Trace & Debug.traceInfo THEN KernelLog.String("UsbStorageBase: MaxLUN is "); KernelLog.Int(maxlun, 0); KernelLog.Ln; END;
ELSIF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorageBase: GetMaxLun failed: "); ShowRes(res); KernelLog.Ln;
END;
END;
FOR lun := 0 TO maxlun DO
IF RegisterDevice(lun) THEN INC(succeeded); END;
END;
RETURN succeeded > 0;
END RegisterDevices;
PROCEDURE Connect*(): BOOLEAN;
BEGIN
defaultPipe := device.GetPipe(0);
bulkInPipe := device.GetPipe(bulkIn);
bulkOutPipe := device.GetPipe(bulkOut);
IF (bulkInPipe=NIL) OR (bulkOutPipe=NIL) THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Could not allocate pipes"); KernelLog.Ln; END;
RETURN FALSE;
END;
IF (interrupt # 0) & (transportMethod # MethodBulkOnly) THEN
interruptPipe := device.GetPipe(interrupt);
IF interruptPipe = NIL THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Could not allocate interrupt pipe."); KernelLog.Ln; END;
RETURN FALSE;
END;
END;
IF initialize & ~Initialization() THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Could not initialize device."); KernelLog.Ln; END;
RETURN FALSE;
END;
IF ~RegisterDevices() THEN
IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbStorage: Error while registering new devices."); KernelLog.Ln; END;
RETURN FALSE;
END;
RETURN TRUE;
END Connect;
PROCEDURE Disconnect*;
BEGIN
diskManager.RemovedDriver(SELF);
END Disconnect;
PROCEDURE Wait(ms : LONGINT);
BEGIN
timer.Sleep(ms);
END Wait;
PROCEDURE &Init*;
BEGIN
NEW(timer);
END Init;
END StorageDriver;
TYPE
DiskManager = OBJECT
VAR
storageDeviceList : UsbStorageDevice;
suffixUsed : ARRAY 100 OF BOOLEAN;
regName : ARRAY 32 OF CHAR;
res : LONGINT;
PROCEDURE Add*(dev : UsbStorageDevice);
VAR i : LONGINT;
BEGIN {EXCLUSIVE}
ASSERT(dev#NIL);
dev.next := storageDeviceList.next; storageDeviceList.next := dev;
i := 0; WHILE suffixUsed[i] & (i < 100) DO INC(i) END;
IF (i = 99) & suffixUsed[99] THEN
KernelLog.String("UsbStorage: Can't register storage device. Maximal 100 devices supported."); KernelLog.Ln;
RETURN;
END;
suffixUsed[i] := TRUE; dev.number := i;
i := 1; WHILE (dev.name[i] # 0X) & (i < 32) DO INC(i); END;
IF (dev.name[i] # 0X) THEN
KernelLog.String("UsbStorage: Error: Couldn't register the device "); KernelLog.String(dev.name);
KernelLog.String(" (device names shall be 2-30 characters long (incl. 0X)"); KernelLog.Ln;
suffixUsed[dev.number] := FALSE;
RETURN;
END;
COPY(dev.name, regName);
IF dev.number < 10 THEN
regName[i] := CHR(ORD("0") + dev.number); regName[i+1] := 0X;
ELSIF dev.number < 100 THEN
regName[i] := CHR(ORD("0") + dev.number DIV 10);
regName[i+1] := CHR(ORD("0") + dev.number MOD 10); regName[i+2] := 0X;
END;
dev.SetName(regName);
Disks.registry.Add(dev, res);
IF res # Plugins.Ok THEN
KernelLog.String("UsbStorage: Error: Couldn't add device to Disks.registry (Error code: ");
KernelLog.Int(res, 0); KernelLog.String(")"); KernelLog.Ln;
suffixUsed[dev.number] := FALSE;
RETURN;
END;
IF Debug.Verbose THEN
KernelLog.String("UsbStorage: Storage device "); KernelLog.String(dev.name);
KernelLog.String(" ("); KernelLog.String(dev.desc); KernelLog.String(") is now accessible."); KernelLog.Ln;
END;
END Add;
PROCEDURE Remove*(dev : UsbStorageDevice);
VAR temp : UsbStorageDevice;
BEGIN {EXCLUSIVE}
temp:=storageDeviceList;
WHILE (temp.next#NIL) & (temp.next.name#dev.name) DO temp:=temp.next; END;
IF (temp.next=NIL) OR (temp.next.name#dev.name) THEN
IF Debug.Level >= Debug.Warnings THEN KernelLog.String("UsbStorage: Warning: Couldn't remove device from registry (device not found)"); KernelLog.Ln; END;
ELSE
temp.next := temp.next.next;
Disks.registry.Remove(dev);
suffixUsed[dev.number]:=FALSE;
END;
IF Debug.Verbose THEN
KernelLog.String("UsbStorage: Removed storage device "); KernelLog.String(dev.name);
KernelLog.String(" ("); KernelLog.String(dev.desc); KernelLog.String(")"); KernelLog.Ln;
END;
END Remove;
PROCEDURE RemovedDriver*(driver : StorageDriver);
VAR temp : UsbStorageDevice;
BEGIN {EXCLUSIVE}
temp := storageDeviceList;
WHILE(temp # NIL) & (temp.next # NIL) DO
IF temp.next.usbDriver = driver THEN
Disks.registry.Remove(temp.next);
suffixUsed[temp.next.number] := FALSE;
IF Debug.Verbose THEN
KernelLog.String("UsbStorage: Remove storage device "); KernelLog.String(temp.next.name);
KernelLog.String(" ("); KernelLog.String(temp.next.desc); KernelLog.String(")"); KernelLog.Ln;
END;
temp.next := temp.next.next;
ELSE
temp := temp.next;
END;
END;
END RemovedDriver;
PROCEDURE RemoveAll*;
VAR temp : UsbStorageDevice;
BEGIN {EXCLUSIVE}
temp := storageDeviceList.next;
WHILE temp # NIL DO
Disks.registry.Remove(temp);
suffixUsed[temp.number] := FALSE;
temp := temp.next;
END;
storageDeviceList.next := NIL;
IF Debug.Verbose THEN KernelLog.Enter; KernelLog.String("UsbStorage: All storage devices removed."); KernelLog.Exit; END;
END RemoveAll;
PROCEDURE Show;
VAR temp : UsbStorageDevice;
BEGIN
KernelLog.String("UsbStorage: Accessible USB storage devices:"); KernelLog.Ln;
IF storageDeviceList.next=NIL THEN
KernelLog.String("No devices registred.");
ELSE
temp := storageDeviceList.next;
WHILE temp # NIL DO
KernelLog.String(temp.name); KernelLog.String(" ("); KernelLog.String(temp.desc); KernelLog.String(")"); KernelLog.Ln;
temp := temp.next;
END;
KernelLog.Ln;
END;
END Show;
PROCEDURE &Init*;
BEGIN
NEW(storageDeviceList);
END Init;
END DiskManager;
VAR
diskManager- : DiskManager;
performance- : LONGINT;
PROCEDURE ShowUFICmd(cmd : CHAR) ;
BEGIN
IF Debug.Trace THEN
CASE ORD(cmd) OF
04H : KernelLog.String("Format Unit");
| 12H : KernelLog.String("Inquiry");
| 55H : KernelLog.String("Mode Select");
| 5AH : KernelLog.String("Mode Sense");
| 1EH : KernelLog.String("Prevent-Allow Media Removal");
| 28H : KernelLog.String("Read(10)");
| 0A8H : KernelLog.String("Read(12)");
| 25H : KernelLog.String("Read Capacity");
| 23H : KernelLog.String("Read Format Capabilities");
| 03H : KernelLog.String("Request Sense");
| 01H : KernelLog.String("Rezero");
| 2BH : KernelLog.String("Seek(10)");
| 1DH : KernelLog.String("Send Diagnostic");
| 1BH :KernelLog.String("Start-Stop Unit");
| 00H : KernelLog.String("Test Unit Ready");
| 2FH : KernelLog.String("Verify");
| 2AH : KernelLog.String("Write(10)");
| 0AAH : KernelLog.String("Write(12)");
| 2EH : KernelLog.String("Write and Verify");
ELSE
KernelLog.String("Unknown Command("); KernelLog.Int(ORD(cmd), 0); KernelLog.String(")");
END;
END;
END ShowUFICmd;
PROCEDURE ShowInquiryResult(i : InquiryResult);
BEGIN
IF Debug.Trace THEN
KernelLog.String("Inquiry data:"); KernelLog.Ln;
IF i # NIL THEN
KernelLog.String(" Peripheral device type: "); KernelLog.Int(i.deviceType, 0);
IF i.removable THEN KernelLog.String(" [removable]"); ELSE KernelLog.String(" [not removable]"); END; KernelLog.Ln;
KernelLog.String(" ANSI version: "); KernelLog.Int(i.ansiVersion, 0); KernelLog.Ln;
KernelLog.String(" Additional Length: "); KernelLog.Int(i.additionalLength, 0); KernelLog.String("B"); KernelLog.Ln;
KernelLog.String(" Vendor: "); KernelLog.String(i.vendor); KernelLog.Ln;
KernelLog.String(" Product: "); KernelLog.String(i.product); KernelLog.Ln;
KernelLog.String(" Revision: "); KernelLog.String(i.revision); KernelLog.Ln;
ELSE
KernelLog.String("Information not available");
END;
END;
END ShowInquiryResult;
PROCEDURE ShowFlexibleDiskPage(fdp : FlexibleDiskPage);
BEGIN
IF Debug.Trace THEN
KernelLog.String("UsbStorage: Flexible Disk Page Contents: "); KernelLog.Ln;
IF fdp # NIL THEN
KernelLog.String(" Transfer rate: "); KernelLog.Int(fdp.TransferRate, 0); KernelLog.String(" kbits/s"); KernelLog.Ln;
KernelLog.String(" Cylinders: "); KernelLog.Int(fdp.NumberOfCylinders, 0);
KernelLog.String(" Heads: "); KernelLog.Int(fdp.NumberOfHeads, 0);
KernelLog.String(" SectorsPerTrack: "); KernelLog.Int(fdp.SectorsPerTrack, 0);
KernelLog.String(" BytesPerSector: "); KernelLog.Int(fdp.BytesPerSector, 0); KernelLog.Ln;
KernelLog.String(" Motordelay On: "); KernelLog.Int(fdp.MotorOnDelay, 0);
KernelLog.String(" Off: "); IF fdp.MotorOffDelay = 0 THEN KernelLog.String("Don't turn off!!"); ELSE KernelLog.Int(fdp.MotorOffDelay, 0); END;
KernelLog.Ln;
KernelLog.String(" Medium Rotation rate: "); KernelLog.Int(fdp.MediumRotationRate, 0); KernelLog.String(" rpm"); KernelLog.Ln;
ELSE
KernelLog.String("Information not available"); KernelLog.Ln;
END;
END;
END ShowFlexibleDiskPage;
PROCEDURE ShowSenseData(key, asc, ascq : CHAR; information : LONGINT; valid : BOOLEAN);
BEGIN
IF Debug.Trace THEN
KernelLog.String("UsbStorage: Sense Key: "); KernelLog.Int(ORD(key), 0);
KernelLog.String(" asc: "); KernelLog.Hex(ORD(asc), 0); KernelLog.String(" ascq: "); KernelLog.Hex(ORD(ascq), 0); KernelLog.String(" -> ");
IF key = 0X THEN KernelLog.String("Device reports error, but auto-sense gives 0X");
ELSIF (key = 1X) & (asc = 17X) & (ascq = 01X) THEN KernelLog.String("Recovered data with retries");
ELSIF (key = 1X) & (asc = 18X) & (ascq = 00X) THEN KernelLog.String("Recovered data with ECC");
ELSIF (key = 1X) THEN KernelLog.String("Recovered Error");
ELSIF (key = 2X) & (asc = 04X) & (ascq = 01X) THEN KernelLog.String("Logical drive not ready, becoming ready");
ELSIF (key = 2X) & (asc = 04X) & (ascq = 02X) THEN KernelLog.String("Logical drive not ready - initialization required");
ELSIF (key = 2X) & (asc = 04X) & (ascq = 04X) THEN KernelLog.String("Logical unit not ready - format in progress");
ELSIF (key = 2X) & (asc = 04X) & (ascq = 0FFX) THEN KernelLog.String("Logical drive not ready - device is busy");
ELSIF (key = 2X) & (asc = 06X) & (ascq = 00X) THEN KernelLog.String("No reference position found");
ELSIF (key = 2X) & (asc = 08X) & (ascq = 00X) THEN KernelLog.String("Logical unit communication failure");
ELSIF (key = 2X) & (asc = 08X) & (ascq = 01X) THEN KernelLog.String("Logical unit communication timeout");
ELSIF (key = 2X) & (asc = 08X) & (ascq = 80X) THEN KernelLog.String("Logical unit communication overrun");
ELSIF (key = 2X) & (asc = 3AX) & (ascq = 00X) THEN KernelLog.String("Medium not present");
ELSIF (key = 2X) & (asc = 54X) & (ascq = 00X) THEN KernelLog.String("USB to host system interface failure");
ELSIF (key = 2X) & (asc = 80X) & (ascq = 00X) THEN KernelLog.String("Insufficient resources");
ELSIF (key = 2X) & (asc = 0FFX) & (ascq = 0FFX) THEN KernelLog.String("Unknown error");
ELSIF (key = 2X) THEN KernelLog.String("Not Ready");
ELSIF (key = 3X) & (asc = 02X) & (ascq = 00X) THEN KernelLog.String("No seek complete");
ELSIF (key = 3X) & (asc = 03X) & (ascq = 00X) THEN KernelLog.String("Write fault");
ELSIF (key = 3X) & (asc = 10X) & (ascq = 00X) THEN KernelLog.String("ID CRC Error");
ELSIF (key = 3X) & (asc = 11X) & (ascq = 00X) THEN KernelLog.String("Unrecovered read error");
ELSIF (key = 3X) & (asc = 12X) & (ascq = 00X) THEN KernelLog.String("Address mark not found for ID field");
ELSIF (key = 3X) & (asc = 13X) & (ascq = 00X) THEN KernelLog.String("Address mark not found for data field");
ELSIF (key = 3X) & (asc = 14X) & (ascq = 00X) THEN KernelLog.String("Recorded entity not found");
ELSIF (key = 3X) & (asc = 30X) & (ascq = 01X) THEN KernelLog.String("Cannot read medium - unknown format");
ELSIF (key = 3X) & (asc = 31X) & (ascq = 01X) THEN KernelLog.String("Format command failed");
ELSIF (key = 3X) THEN KernelLog.String("Medium Error");
ELSIF (key = 4X) & (asc = 40X) THEN KernelLog.String("Diagnostic failure on component "); KernelLog.Int(ORD(ascq), 0);
ELSIF (key = 4X) THEN KernelLog.String("Hardware Error");
ELSIF (key = 5X) & (asc = 1AX) & (ascq = 00X) THEN KernelLog.String("Parameter list length error");
ELSIF (key = 5X) & (asc = 20X) & (ascq = 00X) THEN KernelLog.String("Invalid command operation code");
ELSIF (key = 5X) & (asc = 21X) & (ascq = 00X) THEN KernelLog.String("Logical block address out of range");
ELSIF (key = 5X) & (asc = 24X) & (ascq = 00X) THEN KernelLog.String("Invalid field in command packet");
ELSIF (key = 5X) & (asc = 25X) & (ascq = 00X) THEN KernelLog.String("Logical unit not supported");
ELSIF (key = 5X) & (asc = 26X) & (ascq = 00X) THEN KernelLog.String("Invalid field in parameter list");
ELSIF (key = 5X) & (asc = 26X) & (ascq = 01X) THEN KernelLog.String("Parameter not supported");
ELSIF (key = 5X) & (asc = 26X) & (ascq = 02X) THEN KernelLog.String("Parameter value invalid");
ELSIF (key = 5X) & (asc = 39X) & (ascq = 00X) THEN KernelLog.String("Saving parameters not supported");
ELSIF (key = 5X) THEN KernelLog.String("Illegal Request");
ELSIF (key = 6X) & (asc = 28X) & (ascq = 00X) THEN KernelLog.String("Not ready to ready transition - media changed");
ELSIF (key = 6X) & (asc = 29X) & (ascq = 00X) THEN KernelLog.String("PowerOnReset, retrying");
ELSIF (key = 6X) & (asc = 2FX) & (ascq = 00X) THEN KernelLog.String("Commands cleared by another indicator");
ELSIF (key = 6X) THEN KernelLog.String("Unit Attention");
ELSIF (key = 7X) & (asc = 27X) & (ascq = 00X) THEN KernelLog.String("Write protected media");
ELSIF (key = 7X) THEN KernelLog.String("Data Protected");
ELSIF (key = 8X) THEN KernelLog.String("Blank Check");
ELSIF (key = 9X) THEN KernelLog.String("Vendor Specific");
ELSIF (key = 0AX) THEN KernelLog.String("Reserved");
ELSIF (key = 0BX) & (asc = 4EX) & (ascq = 00X) THEN KernelLog.String("Overlapped command attemted");
ELSIF (key = 0BX) THEN KernelLog.String("Aborted command");
ELSIF (key = 0CX) THEN KernelLog.String("Reserved");
ELSIF (key = 0DX) THEN KernelLog.String("Volume Overflow");
ELSIF (key = 0EX) THEN KernelLog.String("Miscompare");
ELSIF (key = 0FX) THEN KernelLog.String("Reserved");
ELSE KernelLog.String("Unkown");
END;
IF valid THEN KernelLog.String(" [information: "); KernelLog.Int(information, 0); KernelLog.String("]"); END;
KernelLog.Ln;
END;
END ShowSenseData;
PROCEDURE ShowRes(res : LONGINT);
BEGIN
IF Debug.Level >= Debug.Errors THEN
CASE res OF
ResOk: KernelLog.String("OK");
|ResWriteProtected: KernelLog.String("Write-Protected");
|ResDeviceInUse: KernelLog.String("DeviceInUse");
|ResMediaChanged: KernelLog.String("MediaChanged");
|ResMediaMissing: KernelLog.String("MediaMissing");
|ResUnsupported: KernelLog.String("Unsupported");
|ResTimeout: KernelLog.String("Timeout");
|ResShortTransfer: KernelLog.String("ShortTransfer");
|ResDeviceNotReady: KernelLog.String("DeviceNotReady");
|ResDeviceNotReadyInit: KernelLog.String("DeviceNotReady-need init");
|ResSenseError: KernelLog.String("SenseError");
|ResError: KernelLog.String("Error");
|ResFatalError: KernelLog.String("FatalError");
|ResDisconnected: KernelLog.String("Disconnected");
ELSE
KernelLog.String("Unknown(res="); KernelLog.Int(res, 0); KernelLog.String(")");
END;
END;
END ShowRes;
PROCEDURE Show*(context : Commands.Context);
VAR table : Plugins.Table; i : LONGINT;
BEGIN
diskManager.Show;
Disks.registry.GetAll(table);
context.out.String("Storage devices registered at Disks.registry:"); context.out.Ln;
IF table = NIL THEN
context.out.String("No devices registered."); context.out.Ln;
ELSE
FOR i := 0 TO LEN(table)-1 DO
context.out.String(table[i].name); context.out.String(" ("); context.out.String(table[i].desc); context.out.String(")"); context.out.Ln;
END;
END;
END Show;
PROCEDURE SetMax*(context : Commands.Context);
BEGIN
context.out.String("UsbStorage: Max performance mode."); context.out.Ln;
performance := Usbdi.MaxPerformance;
END SetMax;
PROCEDURE SetNormal*(context : Commands.Context);
BEGIN
context.out.String("UsbStorage: Normal performance mode."); context.out.Ln;
performance := Usbdi.Normal;
END SetNormal;
BEGIN
NEW(diskManager);
performance := Usbdi.MaxPerformance;
END UsbStorageBase.
UsbStorage.Install ~ SystemTools.Free UsbStorage ~
UsbStorage.Show ~