More muck raking.
[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         #Don't bother clearing interrupt flag, that's done by sending the reply.
172         print "Got an input event, no idea what to do about it.";
173         #This would be for FTDI emulation.  Not for Mass Storage.
174         #self.wreg(rEP3INFIFO,0x01);      #Modem 
175         #self.wreg(rEP3INFIFO,0x00);      #Line 
176         #self.wreg(rEP3INFIFO,0x00);
177         #self.wregAS(rEP3INBC,0);
178         
179         
180     def do_OUT1(self):
181         """Handle an OUT1 output event."""
182         print "Got an output event, printing the result.";
183         l=self.rreg(rEP1OUTBC);
184         frame=self.readbytes(rEP1OUTFIFO,l);
185         self.handleCBW(frame);
186     lastCBW="";
187     def handleCBW(self,cbw):
188         """Handles an incoming Command Block Wrapper.  See USB Mass
189         Storage Class for details."""
190         
191         if len(cbw)!=31:
192             print "Invalid CBW length of %i bytes.  Aborting." % len(cbw);
193             return;
194         sig=cbw[0:4];
195         if sig!="USBC":
196             print "Invalid CBW signature: %s.  Should be USBC; aborting." % sig;
197             return;
198         self.lastCBW=cbw;
199         
200         dtlen=ord(cbw[8])+(ord(cbw[9])<<8)+(ord(cbw[10])<<16)+(ord(cbw[11])<<24);
201         flags=ord(cbw[12]);
202         dtdir=flags&0x80; # 0x80 for dev->host, 0x00 for host->dev
203         lun=ord(cbw[13])&0x0F; # Should be zero, as we only reported one LUN.
204         cblen=ord(cbw[14])&0x1F;
205         cb=cbw[15:31];
206         self.handleCB(cb,cblen,dtlen,dtdir);
207         
208     def handleCB(self,cb,cblen,dtlen,dtdir):
209         """Handles a command block, then replies with a CSW."""
210         print "\nGot command block 0x%02x, requesting 0x%02x bytes" % (
211             ord(cb[0]), dtlen);
212         verb=ord(cb[0]);
213         status=00; #good, set to 1 for bad.
214         if verb==0x00: # Test Unit Ready
215             response=[0,0,0,0,0,0];
216             self.writebytes(rEP3INFIFO,
217                        response);
218             self.wreg(rEP3INBC,len(response));
219             while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
220                 #Wait for the packet to complete before sending the next.
221                 print "Waiting to complete inquiry."
222                 pass;
223         elif verb==0x03: # Request Sense
224             print "Responding to Request Sense.  Needed for Macs.";
225             response=[0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
226                       0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
227                       0x00, 0x00,
228                       0,0,0,0,0];
229             status=1;
230             self.writebytes(rEP3INFIFO,
231                             response);
232             self.wreg(rEP3INBC,len(response));
233             #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
234             #    #Wait for the packet to complete before sending the next.
235             #    print "Waiting to complete inquiry."
236             #    pass;
237         elif verb==0x12: #Inquiry
238             #print "Responding to CB inquiry.";
239             response=[
240                 0x00, # 00 for Direct, 1F for "no floppy"
241                 0x80, # make 0x80 for removable media
242                 0x00, # Version
243                 0x01, # Response Data Format
244                 0x1f, #Additional length.
245                 0x00, 0x00, 0x00,
246                 #Manufacturer
247                 ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0x20,
248                 #Device name
249                 ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0x20,
250                 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
251                 ord('0'),ord('.'),ord('0'),ord('1')]
252             #print "Sending %i byte reply to %i byte query." % (
253             #        len(response),dtlen);
254             #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
255             #    #Wait for the packet to complete before sending the next.
256             #    print "Waiting to complete inquiry."
257             #    pass;
258             self.writebytes(rEP3INFIFO,
259                             response);
260             self.wregAS(rEP3INBC,
261                         dtlen);
262                         #len(response));
263             #self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit
264             #while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
265             #    #Wait for the packet to complete before sending the next.
266             #    print "Waiting to complete inquiry."
267             #    pass;
268         else:
269             print "ERROR: Unknown command block verb %02x." % verb;
270             status=1; #Command Failed
271             if dtlen>0:
272                 print "Exiting, as %i bytes are expected to be transfered toward %i." % (
273                     dtlen,dtdir);
274                     
275                 sys.exit();
276         cbw=self.lastCBW;
277         
278         #Now we need to send the CSW.
279         csw=[
280             #Standard prefix.
281             ord('U'),ord('S'),ord('B'),ord('S'),
282             #CBW key; must be the same as the one we're replying to.
283             ord(cbw[4]),ord(cbw[5]),ord(cbw[6]),ord(cbw[7]),
284             #CSW Data Residue, probably oughtn't be zeroed.
285             0,0,0,
286             #Status byte: 00 for good, 01 for bad.
287             status];
288         self.writebytes(rEP3INFIFO,
289                         csw);
290         self.wregAS(rEP3INBC,len(csw));
291         
292         
293         self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the IRQ bit.
294         return;
295 #Initialize FET and set baud rate
296 client=GoodFETMAXUSBMass();
297 client.serInit()
298
299 client.MAXUSBsetup();
300 client.massinit();
301