Mass storage emulation now works well enough to emulate a readable, mountable disk.
authortravisutk <travisutk@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Thu, 30 Aug 2012 02:01:27 +0000 (02:01 +0000)
committertravisutk <travisutk@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Thu, 30 Aug 2012 02:01:27 +0000 (02:01 +0000)
git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@1247 12e2690d-a6be-4b82-a7b7-67c4a43b65c8

client/GoodFETMAXUSB.py
client/goodfet.maxusbmass
firmware/apps/radios/ccspi.c

index af95558..b35ba51 100644 (file)
@@ -203,6 +203,7 @@ bmHXFRDNIRQ     =0x80
 
 class GoodFETMAXUSB(GoodFET):
     MAXUSBAPP=0x40;
+    usbverbose=True;
     
     def service_irqs(self):
         """Handle USB interrupt events."""
@@ -231,7 +232,7 @@ class GoodFETMAXUSB(GoodFET):
         """Overload this."""
     def do_OUT1(self):
         """Overload this."""
-        print "Ignoring an OUT1 interrupt.";
+        if self.usbverbose: print "Ignoring an OUT1 interrupt.";
     def setup2str(self,SUD):
         """Converts the header of a setup packet to a string."""
         return "bmRequestType=0x%02x, bRequest=0x%02x, wValue=0x%04x, wIndex=0x%04x, wLength=0x%04x" % (
@@ -286,7 +287,7 @@ class GoodFETMAXUSB(GoodFET):
         ashex="";
         for foo in toret:
             ashex=ashex+(" %02x"%ord(foo));
-        print "GET   %02x==%s" % (reg,ashex);
+        if self.usbverbose: print "GET   %02x==%s" % (reg,ashex);
         return toret;
     def readbytesAS(self,reg,length):
         """Peek some bytes from a register, acking prior transfer."""
@@ -296,7 +297,7 @@ class GoodFETMAXUSB(GoodFET):
         ashex="";
         for foo in toret:
             ashex=ashex+(" %02x"%ord(foo));
-        print "GETAS %02x==%s" % (reg,ashex);
+        if self.usbverbose: print "GETAS %02x==%s" % (reg,ashex);
         return toret;
     def ctl_write_nd(self,request):
         """Control Write with no data stage.  Assumes PERADDR is set
@@ -413,13 +414,13 @@ class GoodFETMAXUSB(GoodFET):
         data="";
         if type(tosend)==str:
             data=chr((reg<<3)|3)+tosend;
-            print "PUT %02x:=%s (0x%02x bytes)" % (reg,tosend,len(data))
+            if self.usbverbose: print "PUT %02x:=%s (0x%02x bytes)" % (reg,tosend,len(data))
         else:
             data=[(reg<<3)|3]+tosend;
             ashex="";
             for foo in tosend:
                 ashex=ashex+(" %02x"%foo);
-            print "PUT %02x:=%s (0x%02x bytes)" % (reg,ashex,len(data))
+            if self.usbverbose: print "PUT %02x:=%s (0x%02x bytes)" % (reg,ashex,len(data))
         self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
     def usb_connect(self):
         """Connect the USB port."""
index 66c2e81..0882642 100755 (executable)
@@ -14,6 +14,9 @@ from GoodFETMAXUSB import *;
 class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
     """This emulates a USB Mass Storage device."""
     
+    #Too much data to watch everything.
+    usbverbose=False;
+
     def getSectorData(self,lba):
         """Overload this to return data from a given 512-byte sector."""
         print "You forgot to overload getSectorData().  Returning something neighborly.";
@@ -54,9 +57,14 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
         return sector;
     def putSectorData(self,lba,block):
         """Overload this to write data to a given 512-byte sector."""
-        
+        print "You forgot to overload putSectorData().  Ignoring sector write.";
         return;
     
+    def getSectorCount(self):
+        """Returns the number of viable Logical Block Addresses."""
+        print "You forgot to overload getSectorCount().  Guessing 0x200.";
+        return 0x200;
+    
     def massinit(self):
         """Initialize a USB Mass Storage device."""
         self.usb_disconnect();
@@ -66,8 +74,9 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
         
     def massrun(self):
         """Main loop of the USB Mass Storage emulator."""
-        print "Starting a Mass Storage device.  This doesn't work yet.";
+        print "Starting a Mass Storage device.";
         while 1:
+            sys.stdout.flush();
             self.service_irqs();
     def do_SETUP(self):
         """Handle USB Enumeration"""
@@ -218,7 +227,6 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
         
     def do_OUT1(self):
         """Handle an OUT1 output event."""
-        print "Got an output event, printing the result.";
         l=self.rreg(rEP1OUTBC);
         frame=self.readbytes(rEP1OUTFIFO,l);
         self.handleCBW(frame);
@@ -247,8 +255,9 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
         
     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);
+        if self.usbverbose:
+            print "Got command block, type 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
@@ -317,8 +326,10 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
             self.wregAS(rEP3INBC,
                         len(response));
         elif verb==0x25: #Read Capacity
+            lastlba=self.getSectorCount();
             response=[
-                0x00, 0,0x0f,0xFF, # Last LBA; might have endianness backward.
+                #0x00, 0, 0x0f, 0xFF, # Last LBA
+                (lastlba>>24)&0xFF, (lastlba>>16)&0xFF, (lastlba>>8)&0xFF, lastlba&0xFF, # Last LBA
                 0x00,0x00,0x02,0x00   # Block length of 512 bytes.
                 ];
             self.writebytes(rEP3INFIFO,
@@ -335,10 +346,15 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
                 );
             count=dtlen/512;
             print "Fetching %i blocks starting at  LBA %i." % (count,baselba);
+            if count>32:
+                count=0;
+                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);
             for i in range(0,count):
-                data=self.getSectorData(baselba+count);
+                data=self.getSectorData(baselba+i);
                 for j in range(0,8):
-                    print "Sending block fragment %i,%i" % (i,j);
+                    #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];
@@ -374,10 +390,73 @@ class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
         
         
         return;
+
+class GoodFETMAXUSBMassFile(GoodFETMAXUSBMass):
+    """This emulates a USB Mass Storage Device, providing a file as
+    its image.  Writes are not yet supported, and this is very slow.
+    Performance hacks will come after the code stabilizes."""
+    
+    datafile=None;
+    datafilelen=None;
+    def openImage(self,filename):
+        """Opens an image for use.  Call this *before* massinit()."""
+        self.datafile=open(filename,"rb");
+        print "Opened an image with %i blocks." % self.getSectorCount();
+    def putSectorData(self,lba,block):
+        """Writes a 512-byte sector to the lba address."""
+        print "Writes aren't yet supported.";
+        return;
+    
+    def getSectorData(self,lba):
+        """Returns data from a 512-byte sector."""
+        toret="";
+        
+        #Seek to the appropraite block.
+        #print "Seeking to position %i"% (lba*512)
+        self.datafile.seek(lba*512,0);
+        pos=self.datafile.tell();
+        if pos!=lba*512:
+            print "SEEK ERROR: Seeked to %i (lba=%i), but now I'm at %i (lba=%i)" % (
+                lba*512,lba,
+                pos,pos/512);
+            #sys.exit();
+        
+        #Dump the data out, assuming no blocking and filling with nonsense.
+        toret=self.datafile.read(512);
+        if len(toret)<512:
+            print "Holy hell, I only have %i bytes of 512." % len(toret);
+        
+        toretbytes=range(0,len(toret));
+        for b in range(0,len(toret)): toretbytes[b]=ord(toret[b]);
+        return toretbytes;
+        
+    def getSectorCount(self):
+        """Returns the number of viable Logical Block Addresses."""
+        
+        # Python must have a better way to read a file length, but for
+        # now we just read the whole damned thing and then throw it
+        # away.  With present performance, we can't read anything
+        # large enough for this to be a problem.
+        if self.datafilelen==None:
+            self.datafile.seek(0);
+            self.datafilelen=len(self.datafile.read());
+        if self.datafilelen%512!=0:
+            print "ERROR: Image does not have an integer number of blocks!"
+            print "%i \% 512 == %i" % (self.datafilelen,
+                                       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();
+
+
 #Initialize FET and set baud rate
-client=GoodFETMAXUSBMass();
+client=GoodFETMAXUSBMassFile();
 client.serInit()
 
+client.openImage(sys.argv[1]);
+
 client.MAXUSBsetup();
 client.massinit();
 
index 7c72ddd..9c6b09c 100644 (file)
@@ -249,9 +249,9 @@ void ccspi_handle_fn( uint8_t const app,
       SETSS;
       */
       
-      //Only should transmit length of one more than the reported
-      // length of the frame, which holds the length byte:
-      txdata(app,verb,i&0x7F);
+      //Only should transmit a packet if the length is legal.
+      if(cmddata[0]&0x80) i=0;
+      txdata(app,verb,i);
     }else{
       //No packet.
       txdata(app,verb,0);