a40ca1a266ac58d084412d130de31cfaabf7c079
[goodfet] / client / goodfet.maxusbmass
1 #!/usr/bin/env python
2
3 #USB Mass Storage Emulator
4 #by Travis Goodspeed
5 #with thanks to Brandon Wilson and his Linky project.
6
7 import sys;
8 import binascii;
9 import array;
10 import time;
11
12 from GoodFETMAXUSB import *;
13
14 class GoodFETMAXUSBMass(GoodFETMAXUSBDevice):
15     """This emulates a USB Mass Storage device."""
16     def massinit(self):
17         """Initialize a USB Mass Storage device."""
18         self.usb_disconnect();
19         time.sleep(1);
20         self.usb_connect();
21         self.massrun();
22         
23     def massrun(self):
24         """Main loop of the USB Mass Storage emulator."""
25         print "Starting a Mass Storage device.  This doesn't work yet.";
26         while 1:
27             self.service_irqs();
28     def do_SETUP(self):
29         """Handle USB Enumeration"""
30         
31         #Grab the SETUP packet from the buffer.
32         SUD=self.readbytes(rSUDFIFO,8);
33         
34         #Parse the SETUP packet
35         print "Handling a setup packet of %s" % self.setup2str(SUD);
36         setuptype=(ord(SUD[bmRequestType])&0x60);
37         if setuptype==0x00:
38             self.std_request(SUD);
39         elif setuptype==0x20:
40             self.class_request(SUD);
41         elif setuptype==0x40:
42             self.vendor_request(SUD);
43         else:
44             print "Unknown bmRequestType=0x%02x." % ord(SUD[bmRequestType])
45             self.STALL_EP0(SUD);
46     def class_request(self,SUD):
47         """Handle a class request."""
48         requesttype=ord(SUD[bmRequestType]);
49         request=ord(SUD[bRequest]);
50         if requesttype==0xA1 and request==0xFE:
51             print "Reporting 0 as the maximum LUN.";
52             #This is a Get Max LUN request.
53             #Return 1-byte maximum Logical Unit Number
54             self.wreg(rEP0FIFO,0x00); # Just one LUN.
55             self.wregAS(rEP0BC,1); # ARM and fire!
56             return; #Don't stall.
57         if requesttype==0x21 and request==0xff:
58             print "Received BBB reset."
59             self.wregAS(rEP0BC,0); # ARM and fire!
60             return; #Don't stall.
61         print "Stalling an unknown class request: %s" % self.setup2str(SUD);
62         self.STALL_EP0(SUD);
63     def vendor_request(self,SUD):
64         """Handle a vendor request."""
65         request=ord(SUD[bRequest]);
66         print "Why the hell is there a vendor request?";
67         #self.wreg(rEP0FIFO,0);
68         self.wregAS(rEP0BC,0);
69     def std_request(self,SUD):
70         """Handles a standard setup request."""
71         setuptype=ord(SUD[bRequest]);
72         if setuptype==SR_GET_DESCRIPTOR: self.send_descriptor(SUD);
73         #elif setuptype==SR_SET_FEATURE: self.feature(1);
74         elif setuptype==SR_SET_CONFIGURATION: self.set_configuration(SUD);
75         elif setuptype==SR_GET_STATUS: self.get_status(SUD);
76         elif setuptype==SR_SET_ADDRESS: self.rregAS(rFNADDR);
77         elif setuptype==SR_GET_INTERFACE: self.get_interface(SUD);
78         else:
79             #print "Stalling Unknown standard setup request type %02x" % setuptype;
80             #self.STALL_EP0(SUD);
81             print "Accepting unknown standard setup request type %02x" % setuptype;
82             self.wregAS(rEP0BC,0);
83             
84     def get_interface(self,SUD):
85         """Handles a setup request for SR_GET_INTERFACE."""
86         if ord(SUD[wIndexL]==0):
87             self.wreg(rEP0FIFO,0);
88             self.wregAS(rEP0BC,1);
89         else:
90             self.STALL_EP0(SUD);
91     
92
93
94 #Device Descriptor
95     DD=[ 
96         
97     0x12, #length
98     0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
99     0x81, 0x07, #Sandisk 
100     0x50, 0x51, #SDCZ2 Cruzer Mini Flash Drive (thin)
101     0x00, 0x03,
102     0x01, 0x02, 0x03, #Strings
103     0x01
104     
105     ];
106
107 #Configuration Descriptor
108     CD=[
109
110   0x09, #Length
111   0x02, #Type
112   0x20, #Total Length
113   0x00, 0x01, 0x01, 0x00, 0xE0, 0x00, 0x09, 0x04, 0x00, 0x00,
114   0x02, #Num Endpoints
115   0x08, #Mass Storage Bulk Only
116   0x06, #SCSI
117   0x50, 0x00,
118   
119   #OUT EP1
120   0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00,
121   #IN EP3
122   0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
123
124 ];
125     strDesc=[
126 # STRING descriptor 0--Language string
127 "\x04\x03\x09\x04",
128 # [
129 #         0x04,                 # bLength
130 #       0x03,                   # bDescriptorType = string
131 #       0x09,0x04               # wLANGID(L/H) = English-United Sates
132 # ],
133 # STRING descriptor 1--Manufacturer ID
134 "\x10\x03G\x00o\x00o\x00d\x00F\x00E\x00T\x00",
135 # STRING descriptor 2 - Product ID
136 "\x1C\x03M\x00A\x00S\x00S\x00 \x00E\x00m\x00u\x00l\x00a\x00t\x00o\x00r\x00",
137 # STRING descriptor 3 - Serial Number ID
138 "\x14\x03S\x00/\x00N\x00 \x003\x004\x002\x000\x00E\x00"
139 ];
140
141     def get_status(self,SUD):
142         """Get the USB Setup Status."""
143         testbyte=ord(SUD[bmRequestType])
144         
145         #Toward Device
146         if testbyte==0x80:
147             self.wreg(rEP0FIFO,0x03); #Enable RWU and self-powered
148             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
149             self.wregAS(rEP0BC,2);    #Load byte count, arm transfer, and ack CTL.
150         #Toward Interface
151         elif testbyte==0x81:
152             self.wreg(rEP0FIFO,0x00);
153             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
154             self.wregAS(rEP0BC,2);
155         #Toward Endpoint
156         elif testbyte==0x82:
157             if(ord(SUD[wIndexL])==0x83):
158                 print "This code almost certainly doesn't work.";
159                 self.wreg(rEP0FIFO,0x01); #Stall EP3
160                 self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
161                 self.wregAS(rEP0BC,2);
162             else:
163                 print "Stalling unknown status.";
164                 self.STALL_EP0(SUD);
165         else:
166             print "Stalling unknown status.";
167             self.STALL_EP0(SUD);
168     
169     def do_IN3(self):
170         """Handle IN3 input event."""
171         # Do nothing here, as it'll be taken care of elsewhere.  The
172         # interrupt just means that the buffer is empty, not that we
173         # are expected to fill it.
174         
175     def do_OUT1(self):
176         """Handle an OUT1 output event."""
177         print "Got an output event, printing the result.";
178         l=self.rreg(rEP1OUTBC);
179         frame=self.readbytes(rEP1OUTFIFO,l);
180         self.handleCBW(frame);
181         
182     lastCBW="";
183     def handleCBW(self,cbw):
184         """Handles an incoming Command Block Wrapper.  See USB Mass
185         Storage Class for details."""
186         
187         if len(cbw)!=31:
188             print "Invalid CBW length of %i bytes.  Aborting." % len(cbw);
189             return;
190         sig=cbw[0:4];
191         if sig!="USBC":
192             print "Invalid CBW signature: %s.  Should be USBC; aborting." % sig;
193             return;
194         self.lastCBW=cbw;
195         
196         dtlen=ord(cbw[8])+(ord(cbw[9])<<8)+(ord(cbw[10])<<16)+(ord(cbw[11])<<24);
197         flags=ord(cbw[12]);
198         dtdir=flags&0x80; # 0x80 for dev->host, 0x00 for host->dev
199         lun=ord(cbw[13])&0x0F; # Should be zero, as we only reported one LUN.
200         cblen=ord(cbw[14])&0x1F;
201         cb=cbw[15:31];
202         self.handleCB(cb,cblen,dtlen,dtdir);
203         
204     def handleCB(self,cb,cblen,dtlen,dtdir):
205         """Handles a command block, then replies with a CSW."""
206         print "\nGot command block 0x%02x, requesting 0x%02x bytes" % (
207             ord(cb[0]), dtlen);
208         verb=ord(cb[0]);
209         status=00; #good, set to 1 for bad.
210         if verb==0x00: # Test Unit Ready
211             response=[0,0,0,0,0,0];
212             self.writebytes(rEP3INFIFO,
213                        response);
214             self.wreg(rEP3INBC,len(response));
215             while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
216                 #Wait for the packet to complete before sending the next.
217                 print "Waiting to complete inquiry."
218                 pass;
219         elif verb==0x03: # Request Sense
220             print "Responding to Request Sense.  Needed for Macs.";
221             response=[0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
222                       0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
223                       0x00, 0x00,
224                       0,0,0,0,0];
225             status=1;
226             self.writebytes(rEP3INFIFO,
227                             response);
228             self.wreg(rEP3INBC,len(response));
229             #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
230             #    #Wait for the packet to complete before sending the next.
231             #    print "Waiting to complete inquiry."
232             #    pass;
233         elif verb==0x12: #Inquiry
234             #print "Responding to CB inquiry.";
235             response=[
236                 0x00, # 00 for Direct, 1F for "no floppy"
237                 0x80, # make 0x80 for removable media
238                 0x00, # Version
239                 0x01, # Response Data Format
240                 0x1f, #Additional length.
241                 0x00, 0x00, 0x00,
242                 #Manufacturer
243                 ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0x20,
244                 #Device name
245                 ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0x20,
246                 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
247                 ord('0'),ord('.'),ord('0'),ord('1')]
248             #print "Sending %i byte reply to %i byte query." % (
249             #        len(response),dtlen);
250             #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
251             #    #Wait for the packet to complete before sending the next.
252             #    print "Waiting to complete inquiry."
253             #    pass;
254             self.writebytes(rEP3INFIFO,
255                             response);
256             self.wregAS(rEP3INBC,
257                         dtlen);
258                         #len(response));
259             #self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit
260             #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
261             #    #Wait for the packet to complete before sending the next.
262             #    print "Waiting to complete inquiry."
263             #    pass;
264         else:
265             print "ERROR: Unknown command block verb %02x." % verb;
266             status=1; #Command Failed
267             if dtlen>0:
268                 print "Exiting, as %i bytes are expected to be transfered toward %i." % (
269                     dtlen,dtdir);
270                     
271                 sys.exit();
272         cbw=self.lastCBW;
273         
274         #Now we need to send the CSW.
275         csw=[
276             #Standard prefix.
277             ord('U'),ord('S'),ord('B'),ord('S'),
278             #CBW key; must be the same as the one we're replying to.
279             ord(cbw[4]),ord(cbw[5]),ord(cbw[6]),ord(cbw[7]),
280             #CSW Data Residue, probably oughtn't be zeroed.
281             0,0,0,0,
282             #Status byte: 00 for good, 01 for bad.
283             status];
284         self.writebytes(rEP3INFIFO,
285                         csw);
286         self.wregAS(rEP3INBC,len(csw));
287         
288         
289         self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the IRQ bit.
290         return;
291 #Initialize FET and set baud rate
292 client=GoodFETMAXUSBMass();
293 client.serInit()
294
295 client.MAXUSBsetup();
296 client.massinit();
297