Cleaning up USB code, getting nearer to BBB mass storage.
[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(GoodFETMAXUSB):
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, 0x00, 0x00, 0x00, 0x01
102     
103     ];
104
105 #Configuration Descriptor
106     CD=[
107
108   0x09, #Length
109   0x02, #Type
110   0x20, #Total Length
111   0x00, 0x01, 0x01, 0x00, 0xE0, 0x00, 0x09, 0x04, 0x00, 0x00,
112   0x02, #Num Endpoints
113   0x08, #Mass Storage Bulk Only
114   0x06, #SCSI
115   0x50, 0x00,
116   
117   #OUT EP1
118   0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00,
119   #IN EP3
120   0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
121
122 ];
123     strDesc=[
124 # STRING descriptor 0--Language string
125 "\x04\x03\x09\x04",
126 # [
127 #         0x04,                 # bLength
128 #       0x03,                   # bDescriptorType = string
129 #       0x09,0x04               # wLANGID(L/H) = English-United Sates
130 # ],
131 # STRING descriptor 1--Manufacturer ID
132 "\x10\x03G\x00o\x00o\x00d\x00F\x00E\x00T\x00",
133 # STRING descriptor 2 - Product ID
134 "\x1C\x03M\x00A\x00S\x00S\x00 \x00E\x00m\x00u\x00l\x00a\x00t\x00o\x00r\x00",
135 # STRING descriptor 3 - Serial Number ID
136 "\x14\x03S\x00/\x00N\x00 \x003\x004\x002\x000\x00E\x00"
137 ];
138
139     def send_descriptor(self,SUD):
140         """Send the USB descriptors based upon the setup data."""
141         desclen=0;
142         reqlen=ord(SUD[wLengthL])+256*ord(SUD[wLengthH]); #16-bit length
143         desctype=ord(SUD[wValueH]);
144         
145         if desctype==GD_DEVICE:
146             desclen=self.DD[0];
147             ddata=self.DD;
148         elif desctype==GD_CONFIGURATION:
149             desclen=self.CD[2];
150             ddata=self.CD;
151         elif desctype==GD_STRING:
152             desclen=self.strDesc[ord(SUD[wValueL])][0];
153             ddata=self.strDesc[ord(SUD[wValueL])];
154         
155         #TODO Configuration, String, Hid, and Report
156         
157         if desclen>0:
158             sendlen=min(reqlen,desclen);
159             self.writebytes(rEP0FIFO,ddata);
160             self.wregAS(rEP0BC,sendlen);
161         else:
162             print "Stalling in send_descriptor() for lack of handler for %02x." % desctype;
163             self.STALL_EP0(SUD);
164     def set_configuration(self,SUD):
165         """Set the configuration."""
166         bmSUSPIE=0x10;
167         configval=ord(SUD[wValueL]);
168         if(configval>0):
169             self.SETBIT(rUSBIEN,bmSUSPIE);
170         self.rregAS(rFNADDR);
171     def get_status(self,SUD):
172         """Get the USB Setup Status."""
173         testbyte=ord(SUD[bmRequestType])
174         
175         #Toward Device
176         if testbyte==0x80:
177             self.wreg(rEP0FIFO,0x03); #Enable RWU and self-powered
178             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
179             self.wregAS(rEP0BC,2);    #Load byte count, arm transfer, and ack CTL.
180         #Toward Interface
181         elif testbyte==0x81:
182             self.wreg(rEP0FIFO,0x00);
183             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
184             self.wregAS(rEP0BC,2);
185         #Toward Endpoint
186         elif testbyte==0x82:
187             if(ord(SUD[wIndexL])==0x83):
188                 print "This code almost certainly doesn't work.";
189                 self.wreg(rEP0FIFO,0x01); #Stall EP3
190                 self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
191                 self.wregAS(rEP0BC,2);
192             else:
193                 self.STALL_EP0(SUD);
194         else:
195             self.STALL_EP0(SUD);
196     
197     def do_IN3(self):
198         """Handle IN3 input event."""
199         #Don't bother clearing interrupt flag, that's done by sending the reply.
200         print "Got an input event, no idea what to do about it.";
201         #This would be for FTDI emulation.  Not for Mass Storage.
202         #self.wreg(rEP3INFIFO,0x01);      #Modem 
203         #self.wreg(rEP3INFIFO,0x00);      #Line 
204         #self.wreg(rEP3INFIFO,0x00);
205         self.wregAS(rEP3INBC,0);
206         
207         
208     def do_OUT1(self):
209         """Handle an OUT1 output event."""
210         print "Got an output event, printing the result.";
211         l=self.rreg(rEP1OUTBC);
212         frame=self.readbytesAS(rEP1OUTFIFO,l);
213         self.handleCBW(frame);
214     lastCBW="";
215     def handleCBW(self,cbw):
216         """Handles an incoming Command Block Wrapper.  See USB Mass
217         Storage Class for details."""
218         
219         if len(cbw)!=31:
220             print "Invalid CBW length of %i bytes.  Aborting." % len(cbw);
221         sig=cbw[0:4];
222         if sig!="USBC":
223             print "Invalid CBW signature: %s.  Should be USBC; aborting." % sig;
224             return;
225         self.lastCBW=cbw;
226         
227         dtlen=ord(cbw[8])+(ord(cbw[9])<<8)+(ord(cbw[10])<<16)+(ord(cbw[11])<<24);
228         flags=ord(cbw[12]);
229         dtdir=flags&0x80; # 0x80 for dev->host, 0x00 for host->dev
230         lun=ord(cbw[13])&0x0F; # Should be zero, as we only reported one LUN.
231         cblen=ord(cbw[14])&0x1F;
232         cb=cbw[15:31];
233         self.handleCB(cb,cblen,dtlen,dtdir);
234         
235     def handleCB(self,cb,cblen,dtlen,dtdir):
236         """Handles a command block, then replies with a CSW."""
237         print "Got command block 0x%02x, length %i bytes" % (
238             ord(cb[0]), dtlen);
239         verb=ord(cb[0]);
240         status=00; #good, set to 1 for bad.
241         if verb==0x00: # Test Unit Ready
242             response=[0,0,0,0,0,0];
243             self.writebytes(rEP3INFIFO,
244                        response);
245             self.wregAS(rEP3INBC,len(response));
246             while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
247                 #Wait for the packet to complete before sending the next.
248                 print "Waiting to complete inquiry."
249                 pass;
250         elif verb==0x03: # Request Sense
251             print "Responding to Request Sense.  Needed for Macs.";
252             response=[0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
253                       0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
254                       0x00, 0x00,
255                       0,0,0,0,0];
256             status=1;
257             self.writebytes(rEP3INFIFO,
258                        response);
259             self.wregAS(rEP3INBC,len(response));
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         elif verb==0x12: #Inquiry
265             print "Responding to CB inquiry.";
266             response=[
267                 0x00,
268                 0x80, # make 0x80 for removable media
269                 0x05, # SPC2
270                 0x02, # SPC2
271                 0x1f, #Additional length.
272                 0x00, 0x00, 0x00,
273                 #Manufacturer
274                 ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0,
275                 #Device name
276                 ord('G'),ord('o'),ord('o'),ord('d'),ord('F'),ord('E'),ord('T'),0,
277                 0,0,0,0,0,0,0,0,
278                 ord('0'),ord('.'),ord('0'),ord('1')]
279             self.writebytes(rEP3INFIFO,
280                             response);
281             self.wregAS(rEP3INBC,len(response));
282             while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ):
283                 #Wait for the packet to complete before sending the next.
284                 print "Waiting to complete inquiry."
285                 pass;
286         else:
287             print "ERROR: Unknown command block verb %02x." % verb;
288             status=1; #Command Failed
289             if dtlen>0:
290                 print "Exiting, as %i bytes are expected to be transfered toward %i." % (
291                     dtlen,dtdir);
292                     
293                 sys.exit();
294         cbw=self.lastCBW;
295         
296         #Now we need to send the CSW.
297         csw=[
298             #Standard prefix.
299             ord('U'),ord('S'),ord('B'),ord('S'),
300             #CBW key; must be the same as the one we're replying to.
301             ord(cbw[4]),ord(cbw[5]),ord(cbw[6]),ord(cbw[7]),
302             #CSW Data Residue, probably oughtn't be zeroed.
303             0,0,0,
304             #Status byte: 00 for good, 01 for bad.
305             status];
306         self.writebytes(rEP3INFIFO,
307                         csw);
308         self.wregAS(rEP3INBC,len(csw));
309         
310         
311         self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the IRQ bit.
312         return;
313 #Initialize FET and set baud rate
314 client=GoodFETMAXUSBMass();
315 client.serInit()
316
317 client.MAXUSBsetup();
318 client.massinit();
319