1 //
2 // Copyright (c) 2010-2018 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Storage;
12 using Antmicro.Renode.Utilities;
13 using System.IO;
14 
15 namespace Antmicro.Renode.Peripherals.USBDeprecated
16 {
17     public class MassStorage: IUSBPeripheral, IDisposable
18     {
19         public event Action <uint> SendInterrupt
20         {
21             add {}
22             remove {}
23         }
24 
25         public event Action <uint> SendPacket
26         {
27             add {}
28             remove {}
29         }
30 
31         byte[] controlPacket;
32         uint addr;
33 
GetAddress()34         public uint GetAddress()
35         {
36             return addr;
37         }
38 
GetSpeed()39         public USBDeviceSpeed GetSpeed()
40         {
41             return USBDeviceSpeed.High;
42         }
43 
Dispose()44         public void Dispose()
45         {
46             lbaBackend.Dispose();
47         }
48 
MassStorage(int numberOfBlocks, int blockSize = 512)49         public MassStorage(int numberOfBlocks, int blockSize = 512)
50         {
51             lbaBackend = new LBABackend(numberOfBlocks, blockSize);
52             Init();
53         }
54 
MassStorage(string underlyingFile, int? numberOfBlocks = null, int blockSize = 512, bool persistent = true)55         public MassStorage(string underlyingFile, int? numberOfBlocks = null, int blockSize = 512, bool persistent = true)
56         {
57             lbaBackend = new LBABackend(underlyingFile, numberOfBlocks, blockSize, persistent);
58             Init();
59 
60         }
61 
62         public string ImageFile
63         {
64             get
65             {
66                 return lbaBackend.UnderlyingFile;
67             }
68             set
69             {
70                 if(lbaBackend != null)
71                 {
72                     lbaBackend.Dispose();
73                 }
74                 if(!File.Exists(value))
75                 {
76                     if(lbaBackend.UnderlyingFile != null && File.Exists(lbaBackend.UnderlyingFile))
77                     {
78                         FileCopier.Copy(lbaBackend.UnderlyingFile, value);
79                     }
80                     else
81                     {
82                         lbaBackend = new LBABackend(value, lbaBackend.NumberOfBlocks, lbaBackend.BlockSize);
83                         return;
84                     }
85                 }
86                 lbaBackend = new LBABackend(value, lbaBackend.BlockSize);
87             }
88         }
89 
Reset()90         public void Reset()
91         {
92             //throw new NotImplementedException();
93         }
94 
95         #region IUSBDevice implementation
ProcessClassGet(USBPacket packet, USBSetupPacket setupPacket)96         public byte[] ProcessClassGet(USBPacket packet, USBSetupPacket setupPacket)
97         {
98             byte request = setupPacket.request;
99             switch((MassStorageRequestCode)request)
100             {
101 
102             case MassStorageRequestCode.GetMaxLUN:
103                 controlPacket = new [] {MaxLun};
104                 return new [] {MaxLun};
105             default:
106                 controlPacket = new byte[0];
107                 return new byte[0];
108             }
109         }
110 
GetDescriptor(USBPacket packet, USBSetupPacket setupPacket)111         public byte[] GetDescriptor(USBPacket packet, USBSetupPacket setupPacket)
112         {
113             var type = (DescriptorType)((setupPacket.value & 0xff00) >> 8);
114             switch(type)
115             {
116             case DescriptorType.Device:
117                 controlPacket = deviceDescriptor.ToArray();
118                 break;
119             case DescriptorType.Configuration:
120                 controlPacket = configurationDescriptor.ToArray();
121                 break;
122             case DescriptorType.DeviceQualifier:
123                 controlPacket = deviceQualifierDescriptor.ToArray();
124                 break;
125             case DescriptorType.InterfacePower:
126                 throw new NotImplementedException("Interface Power Descriptor is not yet implemented. Please contact AntMicro for further support.");
127             case DescriptorType.OtherSpeedConfiguration:
128                 controlPacket = otherConfigurationDescriptor.ToArray();
129                 break;
130             case DescriptorType.String:
131                 uint index = (uint)(setupPacket.value & 0xff);
132                 if(index == 0)
133                 {
134                     stringDescriptor = new StringUSBDescriptor(1);
135                     stringDescriptor.LangId[0] = EnglishLangId;
136                 }
137                 else
138                 {
139                     stringDescriptor = new StringUSBDescriptor(stringValues[setupPacket.index][index]);
140                 }
141                 controlPacket = stringDescriptor.ToArray();
142                 break;
143             default:
144                 this.Log(LogLevel.Warning, "Unsupported descriptor");
145                 return null;
146             }
147             return controlPacket;
148         }
149 
WriteDataBulk(USBPacket packet)150         public void WriteDataBulk(USBPacket packet)
151         {
152             if(packet.data != null && packet.bytesToTransfer != 31)
153             {
154                 oData.AddRange(packet.data);
155             }
156             else if(packet.bytesToTransfer == 31 || oData.Count > 0)
157             {
158                 byte[] data;
159                 var cbw = new CommandBlockWrapper();
160                 var cdb = new SCSI.CommandDescriptorBlock();
161                 if(packet.bytesToTransfer == 31)
162                 {
163                     data = packet.data;
164                 }
165                 else
166                 {
167                     data = oData.ToArray();
168                     oData.Clear();
169                 }
170                 if(!cbw.Fill(data))
171                 {
172                     if(writeFlag)
173                     {
174                         writeFlag = false;
175                         lbaBackend.Write((int)writeCDB.LogicalBlockAddress, data, (int)writeCDB.TransferLength);
176                         writeCSW.DataResidue -= (uint)(data.Length);
177                         transmissionQueue.Enqueue(writeCSW.ToArray());
178 
179                     }
180                     else
181                     {
182                         //throw new InvalidOperationException ("Corrupted Command Block Wrapper");
183                         this.Log(LogLevel.Warning, "Corrupted Command Block Wrapper");
184                     }
185                 }
186                 else
187                 {
188                     ReceiveCommandBlockWrapper(cbw, cdb, data);
189                 }
190             }
191         }
192 
ReceiveCommandBlockWrapper(CommandBlockWrapper cbw, SCSI.CommandDescriptorBlock cdb, byte[] data)193         void ReceiveCommandBlockWrapper(CommandBlockWrapper cbw, SCSI.CommandDescriptorBlock cdb, byte[] data)
194         {
195             this.DebugLog("Received Command Block Wrapper");
196             var csw = new CommandStatusWrapper();
197             var cdbData = new byte[cbw.Length];
198             Array.Copy(data, 15, cdbData, 0, cbw.Length);
199             cdb.Fill(cdbData);
200             switch((SCSI.CommandDescriptorBlock.GroupCode)cdb.OperationCode)
201             {
202             case SCSI.CommandDescriptorBlock.GroupCode.Inquiry:
203                 csw.Tag = cbw.Tag;
204                 csw.DataResidue = 0x00;
205                 csw.Status = 0x00;
206                 transmissionQueue.Enqueue(inquiry.ToArray());
207                 //enqueue inquiry data
208                 transmissionQueue.Enqueue(csw.ToArray());
209                 break;
210             case SCSI.CommandDescriptorBlock.GroupCode.ModeSense:
211                 var msc = new SCSI.ModeSenseCommand();
212                 msc.Fill(cdbData);
213                 var retArr = new byte[192];
214                 retArr[0] = 0x03;
215                 //FIXME: probably it should return sth with more sense
216                 csw.Tag = cbw.Tag;
217                 csw.DataResidue = cbw.DataTransferLength - 0x03;
218                 csw.Status = 0x00;
219                 transmissionQueue.Enqueue(retArr);
220                 transmissionQueue.Enqueue(csw.ToArray());
221                 break;
222             case SCSI.CommandDescriptorBlock.GroupCode.PreventAllowMediumRemoval:
223                 csw.Tag = cbw.Tag;
224                 csw.DataResidue = 0x00;
225                 csw.Status = 0x00;
226                 transmissionQueue.Enqueue(csw.ToArray());
227                 break;
228             case SCSI.CommandDescriptorBlock.GroupCode.Read10:
229                 var dataRead = lbaBackend.Read((int)cdb.LogicalBlockAddress, (int)cdb.TransferLength);
230                 csw.Tag = cbw.Tag;
231                 csw.DataResidue = (uint)(cbw.DataTransferLength - dataRead.Length);
232                 csw.Status = 0x00;
233                 transmissionQueue.Enqueue(dataRead);
234                 transmissionQueue.Enqueue(csw.ToArray());
235                 break;
236             case SCSI.CommandDescriptorBlock.GroupCode.Write10:
237                 writeFlag = true;
238                 //next write command could be data
239                 csw.Tag = cbw.Tag;
240                 csw.DataResidue = cbw.DataTransferLength;
241                 csw.Status = 0x00;
242                 writeCSW = csw;
243                 writeCDB = cdb;
244                 //transmissionQueue.Enqueue(csw.ToArray());
245                 break;
246             case SCSI.CommandDescriptorBlock.GroupCode.ReadCapacity:
247                 var capData = new SCSI.CapacityDataStructure();
248                 capData.ReturnedLBA = (uint)lbaBackend.NumberOfBlocks - 1;
249                 capData.BlockLength = (uint)lbaBackend.BlockSize;
250                 csw.Tag = cbw.Tag;
251                 csw.DataResidue = 0x00;
252                 csw.Status = 0x00;
253                 transmissionQueue.Enqueue(capData.ToArray());
254                 transmissionQueue.Enqueue(csw.ToArray());
255                 break;
256 	    case SCSI.CommandDescriptorBlock.GroupCode.RequestSense:
257 		// TODO: this was copied from TestUnitReady. do a proper implementation
258                 csw.Tag = cbw.Tag;
259                 csw.DataResidue = 0x00;
260                 csw.Status = 0x00;
261                 transmissionQueue.Enqueue(csw.ToArray());
262 	    	break;
263             case SCSI.CommandDescriptorBlock.GroupCode.TestUnitReady:
264                 csw.Tag = cbw.Tag;
265                 csw.DataResidue = 0x00;
266                 csw.Status = 0x00;
267                 transmissionQueue.Enqueue(csw.ToArray());
268                 break;
269             default:
270                 this.Log(LogLevel.Warning, "Unsuported Command Code: 0x{0:X}", cdb.OperationCode);
271                 break;
272             }
273         }
274 
WriteDataControl(USBPacket packet)275         public void WriteDataControl(USBPacket packet)
276         {
277 
278         }
279 
WriteInterrupt(USBPacket packet)280         public byte[] WriteInterrupt(USBPacket packet)
281         {
282             return null;
283         }
284 
285         byte[] currentIDataRegister;
286         int currentIDataPointer;
287         List<byte> oData;
288 
GetDataBulk(USBPacket packet)289         public byte[] GetDataBulk(USBPacket packet)
290         {
291 
292             USBPacket pack;
293             pack.data = null;
294             pack.ep = 0;
295             pack.bytesToTransfer = 0;
296             if(oData.Count != 0)
297             {
298                 WriteDataBulk(pack);
299                 oData.Clear();
300             }
301             if(transmissionQueue.Count > 0)
302             {
303                 if(packet.bytesToTransfer > 0)
304                 {
305                     var dataPacket = new byte[packet.bytesToTransfer];
306                     if(currentIDataRegister == null)
307                     {
308                         currentIDataRegister = transmissionQueue.Dequeue();
309 
310                     }
311                     Array.Copy(currentIDataRegister, currentIDataPointer, dataPacket, 0, (int)packet.bytesToTransfer);
312                     currentIDataPointer += (int)packet.bytesToTransfer;
313                     if(currentIDataPointer >= currentIDataRegister.Length)
314                     {
315                         currentIDataRegister = null;
316                         currentIDataPointer = 0;
317                     }
318 
319                     return dataPacket;
320                 }
321                 //TODO: Rly? A nie przypadkiem "Trying to read 0 bytes"?
322                 this.Log(LogLevel.Warning, "Trying to read from empty queue");
323                 return new byte[0];
324 
325             }
326             return null;
327         }
328 
GetTransferStatus()329         public byte GetTransferStatus()
330         {
331             return 0;
332         }
333 
GetDataControl(USBPacket packet)334         public byte[] GetDataControl(USBPacket packet)
335         {
336             return controlPacket;
337         }
338 
ProcessClassSet(USBPacket packet, USBSetupPacket setupPacket)339         public void ProcessClassSet(USBPacket packet, USBSetupPacket setupPacket)
340         {
341             byte request = setupPacket.request;
342 
343             switch((MassStorageRequestCode)request)
344             {
345             case MassStorageRequestCode.MassStorageReset:
346                 this.DebugLog("Mass storage reset");
347                 break;
348             default:
349                 this.Log(LogLevel.Warning, "Unknown Class Set Code ({0:X})", request);
350                 break;
351             }
352         }
353 
SetDataToggle(byte endpointNumber)354         public void SetDataToggle(byte endpointNumber)
355         {
356             throw new NotImplementedException();
357         }
358 
CleanDataToggle(byte endpointNumber)359         public void CleanDataToggle(byte endpointNumber)
360         {
361             throw new NotImplementedException();
362         }
363 
ToggleDataToggle(byte endpointNumber)364         public void ToggleDataToggle(byte endpointNumber)
365         {
366             throw new NotImplementedException();
367         }
368 
GetDataToggle(byte endpointNumber)369         public bool GetDataToggle(byte endpointNumber)
370         {
371             throw new NotImplementedException();
372         }
373 
ClearFeature(USBPacket packet, USBSetupPacket setupPacket)374         public void ClearFeature(USBPacket packet, USBSetupPacket setupPacket)
375         {
376             throw new NotImplementedException();
377         }
378 
GetConfiguration()379         public byte[] GetConfiguration()
380         {
381             throw new NotImplementedException();
382         }
383 
GetInterface(USBPacket packet, USBSetupPacket setupPacket)384         public byte[] GetInterface(USBPacket packet, USBSetupPacket setupPacket)
385         {
386             throw new NotImplementedException();
387         }
388 
GetStatus(USBPacket packet, USBSetupPacket setupPacket)389         public byte[] GetStatus(USBPacket packet, USBSetupPacket setupPacket)
390         {
391             controlPacket = new byte[2];
392             var recipient = (MessageRecipient)(setupPacket.requestType & 0x3);
393             switch(recipient)
394             {
395             case MessageRecipient.Device:
396                 controlPacket[0] = (byte)(((configurationDescriptor.RemoteWakeup ? 1 : 0) << 1) | (configurationDescriptor.SelfPowered ? 1 : 0));
397                 break;
398             case MessageRecipient.Endpoint:
399                 //TODO: endpoint halt status
400                 goto default;
401             default:
402                 controlPacket[0] = 0;
403                 break;
404             }
405             return controlPacket;
406         }
407 
SetAddress(uint address)408         public void SetAddress(uint address)
409         {
410             addr = address;
411         }
412 
SetConfiguration(USBPacket packet, USBSetupPacket setupPacket)413         public void SetConfiguration(USBPacket packet, USBSetupPacket setupPacket)
414         {
415             // throw new NotImplementedException();
416         }
417 
SetDescriptor(USBPacket packet, USBSetupPacket setupPacket)418         public void SetDescriptor(USBPacket packet, USBSetupPacket setupPacket)
419         {
420             throw new NotImplementedException();
421         }
422 
SetFeature(USBPacket packet, USBSetupPacket setupPacket)423         public void SetFeature(USBPacket packet, USBSetupPacket setupPacket)
424         {
425             throw new NotImplementedException();
426         }
427 
SetInterface(USBPacket packet, USBSetupPacket setupPacket)428         public void SetInterface(USBPacket packet, USBSetupPacket setupPacket)
429         {
430             throw new NotImplementedException();
431         }
432 
SyncFrame(uint endpointId)433         public void SyncFrame(uint endpointId)
434         {
435             throw new NotImplementedException();
436         }
437 
WriteData(byte[] data)438         public void WriteData(byte[] data)
439         {
440 
441         }
442 
GetData()443         public byte[] GetData()
444         {
445 
446             return null;
447         }
448 
ProcessVendorGet(USBPacket packet, USBSetupPacket setupPacket)449         public byte[] ProcessVendorGet(USBPacket packet, USBSetupPacket setupPacket)
450         {
451             throw new NotImplementedException();
452         }
453 
ProcessVendorSet(USBPacket packet, USBSetupPacket setupPacket)454         public void ProcessVendorSet(USBPacket packet, USBSetupPacket setupPacket)
455         {
456             throw new NotImplementedException();
457         }
458         #endregion
459 
Init()460         void Init()
461         {
462             endpointDescriptor = new EndpointUSBDescriptor[NumberOfEndpoints];
463             for(int i = 0; i < NumberOfEndpoints; i++)
464             {
465                 endpointDescriptor[i] = new EndpointUSBDescriptor();
466             }
467             FillEndpointsDescriptors(endpointDescriptor);
468             interfaceDescriptor[0].EndpointDescriptor = endpointDescriptor;
469             configurationDescriptor.InterfaceDescriptor = interfaceDescriptor;
470             inquiry.FillVendor("Generic ");
471             inquiry.FillIdentification("STORAGE DEVICE  ");
472             inquiry.FillRevision("0207");
473             oData = new List<byte>();
474         }
475 
476         #region Massage Data Structure
477 
478         private Queue<byte[]> transmissionQueue = new Queue<byte[]>();
479 
480         #endregion
481 
482         #region Device constans
483         private const byte MaxLun = 0;
484         private const byte NumberOfEndpoints = 2;
485         private const ushort EnglishLangId = 0x09;
486 
487         #endregion
488 
489         #region Mass Storage data structures
490 
491         private class CommandBlockWrapper
492         {
493 
Fill(byte[] data)494             public bool Fill(byte[] data)
495             {
496                 if(data.Length != 31)
497                 {
498                     return false;
499                 }
500 
501                 this.Signature = BitConverter.ToUInt32(data, 0);
502 
503                 if(this.Signature != ProperSignature)
504                 {
505                     return false;
506                 }
507                 this.Tag = BitConverter.ToUInt32(data, 4);
508                 this.DataTransferLength = BitConverter.ToUInt32(data, 8);
509                 this.Flags = data[12];
510                 this.LogicalUnitNumber = (byte)(data[13] & (byte)(0x0fu));
511                 this.Length = (byte)(data[14] & (byte)(0x1fu));
512 
513                 return true;
514             }
515 
516             private const uint ProperSignature = 0x43425355;
517             public uint Signature;
518             public uint Tag;
519             public uint DataTransferLength;
520             public byte Flags;
521             public byte LogicalUnitNumber;
522             public byte Length;
523         }
524 
525         private class CommandStatusWrapper
526         {
ToArray()527             public byte[] ToArray()
528             {
529                 arr[0] = (byte)(CommandStatusWrapperSignature & 0xFF);
530                 arr[1] = (byte)((CommandStatusWrapperSignature & 0xFF00) >> 8);
531                 arr[2] = (byte)((CommandStatusWrapperSignature & 0xFF0000) >> 16);
532                 arr[3] = (byte)((CommandStatusWrapperSignature & 0xFF000000) >> 24);
533 
534                 arr[4] = (byte)(Tag & 0xFF);
535                 arr[5] = (byte)((Tag & 0xFF00) >> 8);
536                 arr[6] = (byte)((Tag & 0xFF0000) >> 16);
537                 arr[7] = (byte)((Tag & 0xFF000000) >> 24);
538 
539                 arr[8] = (byte)(DataResidue & 0xFF);
540                 arr[9] = (byte)((DataResidue & 0xFF00) >> 8);
541                 arr[10] = (byte)((DataResidue & 0xFF0000) >> 16);
542                 arr[11] = (byte)((DataResidue & 0xFF000000) >> 24);
543 
544                 arr[12] = Status;
545 
546                 return arr;
547             }
548             private byte[] arr = new byte[13];
549             private const uint CommandStatusWrapperSignature = 0x53425355;
550             public uint Tag;
551             public uint DataResidue;
552             public byte Status;
553         }
554 
555         #endregion
556 
557         #region USB descriptors
558 
559         private ConfigurationUSBDescriptor configurationDescriptor = new ConfigurationUSBDescriptor
560         {
561             ConfigurationIndex = 0,
562             SelfPowered = false,
563             NumberOfInterfaces = 1,
564             RemoteWakeup = true,
565             MaxPower = 250, //500mA
566             ConfigurationValue = 1
567         };
568         private ConfigurationUSBDescriptor otherConfigurationDescriptor = new ConfigurationUSBDescriptor();
569         private StringUSBDescriptor stringDescriptor;
570         private StandardUSBDescriptor deviceDescriptor = new StandardUSBDescriptor
571         {
572             DeviceClass=0x00,//specified in interface descritor
573             DeviceSubClass = 0x00,//specified in interface descritor
574             USB = 0x0200,
575             DeviceProtocol = 0x00,//specified in interface descritor
576             MaxPacketSize = 64,
577             VendorId = 0x05e3,
578             ProductId = 0x0727,
579             Device = 0x0207,
580             ManufacturerIndex = 0,
581             ProductIndex = 0,
582             SerialNumberIndex = 0,
583             NumberOfConfigurations = 1
584         };
585         private DeviceQualifierUSBDescriptor deviceQualifierDescriptor = new DeviceQualifierUSBDescriptor();
586         private EndpointUSBDescriptor[] endpointDescriptor;
587         private InterfaceUSBDescriptor[] interfaceDescriptor = new[]{new InterfaceUSBDescriptor
588         {
589             AlternateSetting = 0,
590             InterfaceNumber = 0,
591             NumberOfEndpoints = NumberOfEndpoints,
592             InterfaceClass = 0x08, //vendor specific
593             InterfaceProtocol = 0x50, //Bulk only
594             InterfaceSubClass = 0x06, //SCSI transparent
595             InterfaceIndex = 0
596         }
597         };
598         private Dictionary<ushort, string[]> stringValues = new Dictionary<ushort, string[]>
599         {
600             {EnglishLangId, new string[]{
601                     "",
602                     "Mass Storage",
603                     "0xALLMAN",
604                     "Configuration",
605                     "AntMicro"
606                 }}
607         };
608 
FillEndpointsDescriptors(EndpointUSBDescriptor[] endpointDesc)609         private void FillEndpointsDescriptors(EndpointUSBDescriptor[] endpointDesc)
610         {
611             endpointDesc[0].EndpointNumber = 1;
612             endpointDesc[0].InEnpoint = true;
613             endpointDesc[0].TransferType = EndpointUSBDescriptor.TransferTypeEnum.Bulk;
614             endpointDesc[0].MaxPacketSize = 512;
615             endpointDesc[0].SynchronizationType = EndpointUSBDescriptor.SynchronizationTypeEnum.NoSynchronization;
616             endpointDesc[0].UsageType = EndpointUSBDescriptor.UsageTypeEnum.Data;
617             endpointDesc[0].Interval = 0;
618 
619             endpointDesc[1].EndpointNumber = 2;
620             endpointDesc[1].InEnpoint = false;
621             endpointDesc[1].TransferType = EndpointUSBDescriptor.TransferTypeEnum.Bulk;
622             endpointDesc[1].MaxPacketSize = 512;
623             endpointDesc[1].SynchronizationType = EndpointUSBDescriptor.SynchronizationTypeEnum.NoSynchronization;
624             endpointDesc[1].UsageType = EndpointUSBDescriptor.UsageTypeEnum.Data;
625             endpointDesc[1].Interval = 0;
626 
627 
628         }
629 
630         private SCSI.StandardInquiryData inquiry = new SCSI.StandardInquiryData//all data sniffed from real device
631         {
632 
633             PeripheralQualifier = (byte)SCSI.PeripheralQualifier.Connected,
634             PeripheralDeviceType = (byte)SCSI.PeripheralDeviceType.DirectAccessBlockDevice,
635             RMB = true,
636             Version = (byte)SCSI.VersionCode.NotStandard,
637             NormalACASupport = false,
638             HierachicalSupport = false,
639             ResponseDataFormat = 0x00,
640             AdditionalLength = 0x29,
641             SCCSupport = false,
642             AccessControlsCoordintor = false,
643             TargetPortGroupSupport = 0x00,
644             ThirdPartyCopy = false,
645             Protect = false,
646             BasingQueuing = false,
647             EnclosureServices = false,
648             VS1 = false,
649             MultiPort = false,
650             MediumChanger = false,
651             ADDR16 = false,
652             WBUS16a = false,
653             Sync = false,
654             LinkedCommand = false,
655             VS2 = false
656 
657         };
658 
659         private enum MassStorageRequestCode
660         {
661             AcceptDeviceSpecificCommand = 0x00,
662             GetRequest = 0xFC,
663             PutRequest = 0xFD,
664             GetMaxLUN = 0xFE,
665             MassStorageReset = 0xFE//Bulk Only
666         }
667      #endregion
668 
669      #region lba backend
670 
671         private LBABackend lbaBackend;
672         private CommandStatusWrapper writeCSW;
673         private SCSI.CommandDescriptorBlock writeCDB;
674         private bool writeFlag;
675 
676      #endregion
677 
678 
679     }
680 
681 }
682