fix endianness in device descriptor
[goodfet] / client / goodfet.maxusbmass
index da42c90..8c12923 100755 (executable)
@@ -8,9 +8,33 @@ import sys;
 import binascii;
 import array;
 import time;
+import warnings
 
 from GoodFETMAXUSB import *;
 
+warnings.warn(
+"""The libraries upon which this program depends will soon be deprecated in
+favor of the USB*.py libraries.  See facedancer-umass.py (forthcoming) for an
+example of this program written using the new libraries."""
+)
+
+# This constant is kinda complicated and very ugly.  The idea is that
+# if we take too long in any given transaction, the host will abort.
+# How many blocks we can send depends upon timeouts on both sides,
+# with (at least in Linux) the behavior that aborting early causes the
+# disk to reset with only warning and no real errors.  Somewhere
+# there's a way to provide this constant to the host, in which case
+# stalling and waiting for a reset will no longer be necessary.
+
+MAXBLOCKSPERTRANSFER=128
+
+def zeros(length):
+    """Returns a list of zeroes of the specified length."""
+    l=range(0,length);
+    for foo in l:
+        l[foo]=0;
+    return l;
+
 class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
     """This emulates a USB Mass Storage device."""
     
@@ -277,7 +301,7 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
             #print "Responding to CB inquiry.";
             response=[
                 0x00, # 00 for Direct, 1F for "no floppy"
-                0x80, # make 0x80 for removable media
+                0x80, # make 0x80 for removable media, 0x00 for fixed
                 0x00, # Version
                 0x01, # Response Data Format
                 0x1f, #Additional length.
@@ -290,6 +314,8 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
                 ord('0'),ord('.'),ord('0'),ord('1')]
             #print "Sending %i byte reply to %i byte query." % (
             #        len(response),dtlen);
+            while len(response)<dtlen:
+                response=response+[0];
             #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
             #    #Wait for the packet to complete before sending the next.
             #    print "Waiting to complete inquiry."
@@ -307,18 +333,26 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
         elif verb==0x1e: #Prevent/Allow Removal
             # Give a good status to pretend we understand.
             status=0x00;
-        elif verb==0x1A: #Mode Sense (6)
+        elif verb==0x1A or verb==0x5A: #Mode Sense (6 or 10)
             # I should probably send six bytes here.
-            response=[0x12,0,0,0, 0,0,0,0x1C];
-            self.writebytes(rEP3INFIFO,
-                            response);
-            self.wregAS(rEP3INBC,
-                        len(response));
+            page=ord(cb[2])&0x3F;
+            print "Mode Sense (6) requesting %i byte Page Code %02x" % (
+                dtlen,page);
+            #This is completely wrong.
+            response=[0x07,0,0,0, 0,0,0,0x1C];
+            # response=[0x37,0x00,0x00,0x08,0x00,0x00,0x00,0x00, 0x00,0x00,0x02,0x00,0x01,0x0a,0x80,0x00,
+            #           0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x08,0x12,0x04,0x00,0x00,0x00,0x00,0x00,
+            #           0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x0a,0x0a,0x02,0x00,
+            #           0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x1e];
+            if page!=0x3f:
+                print "Unknown page, returning empty page.";
+                response=[0x07,0,0,0, 0,0,0,0];
+            self.fifo_ep3in_tx(response);
         elif verb==0x23: #Read Format Capacity
             response=[
-                0x00, 0,0x00,0x08, #Capacity list length.
-                0,0x00,0x10,0x00,   # Number of sectors, implying 10MB.
-                0x01,0x00,            #reserved/desciptor code.
+                0x00, 0,0x00,0x08,    # Capacity list length.
+                0,0x00,0x10,0x00,     # Number of sectors, implying 10MB.  Should come from image.
+                0x01,0x00,            # reserved/desciptor code.
                 0x02,0x00             # 512 bytes/sector.  Why is this twice?
                 ];
             self.writebytes(rEP3INFIFO,
@@ -346,32 +380,40 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
                 );
             count=dtlen/512;
             print "Fetching %i blocks starting at  LBA %i." % (count,baselba);
-            if count>32:
+            if count>MAXBLOCKSPERTRANSFER:
                 count=0;
-                status=1; #Fail if we're asked to read more than 32 blocks.
+                #status=1; #Fail if we're asked to read more than 32 blocks.
                 #Now we need to stall EP3.  It's not acceptable to just forget to transmit.
                 self.wreg(rEPSTALLS,0x10);
+                return;
             for i in range(0,count):
                 data=self.getSectorData(baselba+i);
-                for j in range(0,8):
-                    #print "Sending block fragment %i,%i" % (i,j);
-                    #Transmit each 64-byte block fragment, then wait for next.
-                    while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ): pass;
-                    response=data[j*64:j*64+64];
-                    self.writebytes(rEP3INFIFO,
-                                    response);
-                    self.wregAS(rEP3INBC,
-                                64);
+                self.fifo_ep3in_tx(data);
+                
+                # for j in range(0,8):
+                #     #print "Sending block fragment %i,%i" % (i,j);
+                #     #Transmit each 64-byte block fragment, then wait for next.
+                #     while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ): pass;
+                #     response=data[j*64:j*64+64];
+                #     self.writebytes(rEP3INFIFO,
+                #                     response);
+                #     self.wregAS(rEP3INBC,
+                #                 64);
             #sys.exit();
         elif verb==0x2A: #WRITE SECTOR
-            print "Haven't implemented WRITE SECTOR.";
+            print "Haven't implemented WRITE SECTOR.  This will end badly.";
+            #sys.exit();
+        elif verb==0x1B: #EJECT/RETRACT DISK
+            print "Haven't implemented SCSI Start Stop Unit Command (1B)";
+            print "https://en.wikipedia.org/wiki/SCSI_Start_Stop_Unit_Command";
             #sys.exit();
         else:
             print "ERROR: Unknown SCSI command block verb %02x." % verb;
-            status=1; #Command Failed
+            status=0x02; #Command Failed
             if dtlen>0:
-                print "Perhaps I should send %i bytes of dummy data here." % dtlen;
-            sys.exit(1);
+                print "Sending %i bytes of dummy data here." % dtlen;
+                self.fifo_ep3in_tx(zeros(dtlen));
+            #sys.exit(1);
         cbw=self.lastCBW;
         
         #Now we need to send the CSW.
@@ -446,6 +488,7 @@ class GoodFETMAXUSBMassFile(GoodFETMAXUSBMass):
                                        self.datafilelen%512);
             sys.exit();
         return self.datafilelen/512-1;
+
 if(len(sys.argv)==1):
     print "Usage: %s disk.img\n" % sys.argv[0];
     sys.exit();