Fixed capacity issues; goodfet.maxusbmass now enumerates a 2MB disk.
[goodfet] / client / goodfet.maxusbmass
index 950d67d..ea7769a 100755 (executable)
@@ -11,7 +11,7 @@ import time;
 
 from GoodFETMAXUSB import *;
 
-class GoodFETMAXUSBMass(GoodFETMAXUSB):
+class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
     """This emulates a USB Mass Storage device."""
     def massinit(self):
         """Initialize a USB Mass Storage device."""
@@ -37,7 +37,6 @@ class GoodFETMAXUSBMass(GoodFETMAXUSB):
         if setuptype==0x00:
             self.std_request(SUD);
         elif setuptype==0x20:
-            print "XXXXXXXXXX Got a class request."
             self.class_request(SUD);
         elif setuptype==0x40:
             self.vendor_request(SUD);
@@ -46,7 +45,20 @@ class GoodFETMAXUSBMass(GoodFETMAXUSB):
             self.STALL_EP0(SUD);
     def class_request(self,SUD):
         """Handle a class request."""
-        print "Stalling a class request.";
+        requesttype=ord(SUD[bmRequestType]);
+        request=ord(SUD[bRequest]);
+        if requesttype==0xA1 and request==0xFE:
+            print "Reporting 0 as the maximum LUN.";
+            #This is a Get Max LUN request.
+            #Return 1-byte maximum Logical Unit Number
+            self.wreg(rEP0FIFO,0x00); # Just one LUN.
+            self.wregAS(rEP0BC,1); # ARM and fire!
+            return; #Don't stall.
+        if requesttype==0x21 and request==0xff:
+            print "Received BBB reset."
+            self.wregAS(rEP0BC,0); # ARM and fire!
+            return; #Don't stall.
+        print "Stalling an unknown class request: %s" % self.setup2str(SUD);
         self.STALL_EP0(SUD);
     def vendor_request(self,SUD):
         """Handle a vendor request."""
@@ -64,9 +76,11 @@ class GoodFETMAXUSBMass(GoodFETMAXUSB):
         elif setuptype==SR_SET_ADDRESS: self.rregAS(rFNADDR);
         elif setuptype==SR_GET_INTERFACE: self.get_interface(SUD);
         else:
-            print "Stalling Unknown standard setup request type %02x" % setuptype;
-            self.STALL_EP0(SUD);
-    
+            #print "Stalling Unknown standard setup request type %02x" % setuptype;
+            #self.STALL_EP0(SUD);
+            print "Accepting unknown standard setup request type %02x" % setuptype;
+            self.wregAS(rEP0BC,0);
+            
     def get_interface(self,SUD):
         """Handles a setup request for SR_GET_INTERFACE."""
         if ord(SUD[wIndexL]==0):
@@ -76,7 +90,6 @@ class GoodFETMAXUSBMass(GoodFETMAXUSB):
             self.STALL_EP0(SUD);
     
 
-#0403:6001
 
 #Device Descriptor
     DD=[ 
@@ -85,7 +98,9 @@ class GoodFETMAXUSBMass(GoodFETMAXUSB):
     0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
     0x81, 0x07, #Sandisk 
     0x50, 0x51, #SDCZ2 Cruzer Mini Flash Drive (thin)
-    0x00, 0x03, 0x00, 0x00, 0x00, 0x01
+    0x00, 0x03,
+    0x01, 0x02, 0x03, #Strings
+    0x01
     
     ];
 
@@ -101,10 +116,10 @@ class GoodFETMAXUSBMass(GoodFETMAXUSB):
   0x06, #SCSI
   0x50, 0x00,
   
+  #OUT EP1
+  0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00,
   #IN EP3
   0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
-  #OUT EP1
-  0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00
 
 ];
     strDesc=[
@@ -123,38 +138,6 @@ class GoodFETMAXUSBMass(GoodFETMAXUSB):
 "\x14\x03S\x00/\x00N\x00 \x003\x004\x002\x000\x00E\x00"
 ];
 
-    def send_descriptor(self,SUD):
-        """Send the USB descriptors based upon the setup data."""
-        desclen=0;
-        reqlen=ord(SUD[wLengthL])+256*ord(SUD[wLengthH]); #16-bit length
-        desctype=ord(SUD[wValueH]);
-        
-        if desctype==GD_DEVICE:
-            desclen=self.DD[0];
-            ddata=self.DD;
-        elif desctype==GD_CONFIGURATION:
-            desclen=self.CD[2];
-            ddata=self.CD;
-        elif desctype==GD_STRING:
-            desclen=self.strDesc[ord(SUD[wValueL])][0];
-            ddata=self.strDesc[ord(SUD[wValueL])];
-        
-        #TODO Configuration, String, Hid, and Report
-        
-        if desclen>0:
-            sendlen=min(reqlen,desclen);
-            self.writebytes(rEP0FIFO,ddata);
-            self.wregAS(rEP0BC,sendlen);
-        else:
-            print "Stalling in send_descriptor() for lack of handler for %02x." % desctype;
-            self.STALL_EP0(SUD);
-    def set_configuration(self,SUD):
-        """Set the configuration."""
-        bmSUSPIE=0x10;
-        configval=ord(SUD[wValueL]);
-        if(configval>0):
-            self.SETBIT(rUSBIEN,bmSUSPIE);
-        self.rregAS(rFNADDR);
     def get_status(self,SUD):
         """Get the USB Setup Status."""
         testbyte=ord(SUD[bmRequestType])
@@ -177,53 +160,161 @@ class GoodFETMAXUSBMass(GoodFETMAXUSB):
                 self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
                 self.wregAS(rEP0BC,2);
             else:
+                print "Stalling unknown status.";
                 self.STALL_EP0(SUD);
         else:
+            print "Stalling unknown status.";
             self.STALL_EP0(SUD);
-    def service_irqs(self):
-        """Handle USB interrupt events."""
-        
-        epirq=self.rreg(rEPIRQ);
-        usbirq=self.rreg(rUSBIRQ);
-        
-        #Are we being asked for setup data?
-        if(epirq&bmSUDAVIRQ): #Setup Data Requested
-            self.wreg(rEPIRQ,bmSUDAVIRQ); #Clear the bit
-            self.do_SETUP();
-        elif(epirq&bmIN3BAVIRQ): #EN3-IN packet
-            self.do_IN3();
-            #self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit
-        elif(epirq&bmOUT1DAVIRQ): #OUT1-OUT packet
-            self.do_OUT1();
-            self.wregAS(rEPIRQ,bmOUT1DAVIRQ); #Clear the bit *AFTER* servicing.
-        #else:
-        #    self.do_IN3();
-    
-    typestring="GoodFET emulates Mass properly, if you can read this!\n";
-    typepos=0;
     
     def do_IN3(self):
         """Handle IN3 input event."""
-        #Don't bother clearing interrupt flag, that's done by sending the reply.
-        #self.type_IN3();
-        print "Got an input event, no idea what to do about it.";
-        self.wreg(rEP3INFIFO,0x01);      #Modem Status
-        self.wreg(rEP3INFIFO,0x00);      #Line Status
-        self.wreg(rEP3INFIFO,0x00);
-        self.wregAS(rEP3INBC,3);
+        # Do nothing here, as it'll be taken care of elsewhere.  The
+        # interrupt just means that the buffer is empty, not that we
+        # are expected to fill it.
+        
     def do_OUT1(self):
         """Handle an OUT1 output event."""
         print "Got an output event, printing the result.";
         l=self.rreg(rEP1OUTBC);
-        frame=self.readbytesAS(rEP1OUTFIFO,l);
-        print "Mass OUT: %s" % frame[1:len(frame)];
-        #self.type_IN3();
-
+        frame=self.readbytes(rEP1OUTFIFO,l);
+        self.handleCBW(frame);
+        
+    lastCBW="";
+    def handleCBW(self,cbw):
+        """Handles an incoming Command Block Wrapper.  See USB Mass
+        Storage Class for details."""
+        
+        if len(cbw)!=31:
+            print "Invalid CBW length of %i bytes.  Aborting." % len(cbw);
+            return;
+        sig=cbw[0:4];
+        if sig!="USBC":
+            print "Invalid CBW signature: %s.  Should be USBC; aborting." % sig;
+            return;
+        self.lastCBW=cbw;
+        
+        dtlen=ord(cbw[8])+(ord(cbw[9])<<8)+(ord(cbw[10])<<16)+(ord(cbw[11])<<24);
+        flags=ord(cbw[12]);
+        dtdir=flags&0x80; # 0x80 for dev->host, 0x00 for host->dev
+        lun=ord(cbw[13])&0x0F; # Should be zero, as we only reported one LUN.
+        cblen=ord(cbw[14])&0x1F;
+        cb=cbw[15:31];
+        self.handleCB(cb,cblen,dtlen,dtdir);
+        
+    def handleCB(self,cb,cblen,dtlen,dtdir):
+        """Handles a command block, then replies with a CSW."""
+        print "\nGot command block 0x%02x, requesting 0x%02x bytes" % (
+            ord(cb[0]), dtlen);
+        verb=ord(cb[0]);
+        status=00; #good, set to 1 for bad.
+        if verb==0x00: # Test Unit Ready
+            # Send nothing, just the success code.
+            status=0;
+        elif verb==0x03: # Request Sense
+            print "Responding to Request Sense.  Needed for Macs.";
+            response=[0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
+                      0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+                      0x00, 0x00,
+                      0,0,0,0,0];
+            #status=1;
+            self.writebytes(rEP3INFIFO,
+                            response);
+            self.wreg(rEP3INBC,len(response));
+        elif verb==0x12: #Inquiry
+            #print "Responding to CB inquiry.";
+            response=[
+                0x00, # 00 for Direct, 1F for "no floppy"
+                0x80, # make 0x80 for removable media
+                0x00, # Version
+                0x01, # Response Data Format
+                0x1f, #Additional length.
+                0x00, 0x00, 0x00,
+                #Manufacturer
+                ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0x20,
+                #Device name
+                ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0x20,
+                0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+                ord('0'),ord('.'),ord('0'),ord('1')]
+            #print "Sending %i byte reply to %i byte query." % (
+            #        len(response),dtlen);
+            #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
+            #    #Wait for the packet to complete before sending the next.
+            #    print "Waiting to complete inquiry."
+            #    pass;
+            self.writebytes(rEP3INFIFO,
+                            response);
+            self.wregAS(rEP3INBC,
+                        dtlen);
+                        #len(response));
+            #self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit
+            #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
+            #    #Wait for the packet to complete before sending the next.
+            #    print "Waiting to complete inquiry."
+            #    pass;
+        elif verb==0x1e: #Prevent/Allow Removal
+            # Give a good status to pretend we understand.
+            status=0x00;
+        elif verb==0x1A: #Mode Sense (6)
+            # 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));
+        elif verb==0x23: #Read Format Capacity
+            response=[
+                0x00, 0,0x00,0x08, #Capacity list length.
+                0,0x00,x10,0x00,   # Number of sectors, implying 10MB.
+                0x01,0x00,            #reserved/desciptor code.
+                0x02,0x00             # 512 bytes/sector.  Why is this twice?
+                ];
+            self.writebytes(rEP3INFIFO,
+                            response);
+            self.wregAS(rEP3INBC,
+                        len(response));
+        elif verb==0x25: #Read Capacity
+            response=[
+                0x00, 0,0x0f,0xFF, # Last LBA; might have endianness backward.
+                0x00,0x00,0x02,0x00   # Block length of 512 bytes.
+                ];
+            self.writebytes(rEP3INFIFO,
+                            response);
+            self.wregAS(rEP3INBC,
+                        len(response));
+        elif verb==0x28: #READ SECTOR
+            print "Haven't implemented READ SECTOR.";
+            sys.exit();
+        elif verb==0x2A: #WRITE SECTOR
+            print "Haven't implemented WRITE SECTOR.";
+            sys.exit();
+        else:
+            print "ERROR: Unknown SCSI command block verb %02x." % verb;
+            status=1; #Command Failed
+            if dtlen>0:
+                print "Perhaps I should send %i bytes of dummy data here." % dtlen;
+            sys.exit(1);
+        cbw=self.lastCBW;
+        
+        #Now we need to send the CSW.
+        csw=[
+            #Standard prefix.
+            ord('U'),ord('S'),ord('B'),ord('S'),
+            #CBW key; must be the same as the one we're replying to.
+            ord(cbw[4]),ord(cbw[5]),ord(cbw[6]),ord(cbw[7]),
+            #CSW Data Residue, probably oughtn't be zeroed.
+            0,0,0,0,
+            #Status byte: 00 for good, 01 for bad.
+            status];
+        self.writebytes(rEP3INFIFO,
+                        csw);
+        self.wregAS(rEP3INBC,len(csw));
+        
+        
+        return;
 #Initialize FET and set baud rate
 client=GoodFETMAXUSBMass();
 client.serInit()
 
-
 client.MAXUSBsetup();
 client.massinit();