Added godfet.maxusbdfu for USD Device Firmware Update emulation with the Facedancer.
[goodfet] / client / goodfet.maxusbdfu
1 #!/usr/bin/env python
2
3 #DFU USB Device Emulator
4 #by Travis Goodspeed
5
6 import sys;
7 import binascii;
8 import array;
9 import time;
10
11 from GoodFETMAXUSB import *;
12
13 class GoodFETMAXUSBDFU(GoodFETMAXUSBDevice):
14     usbverbose=False;
15     """This emulates the DFU USB to Serial chips."""
16     def dfuinit(self,vid=0xFFFF,pid=0x0004):
17         """Initialize a USB DFU device."""
18         self.usb_disconnect();
19         time.sleep(1);
20         self.usb_connect();
21         self.dfurun(vid,pid);
22     def dfurun(self,vid,pid):
23         """Main loop of the USB DFU emulator."""
24         print "Starting a DFU device as %04X:%04X" % (vid,pid);
25         sys.stdout.flush();
26         #Set the VID and PID.
27         self.DD[8]=vid&0xFF;
28         self.DD[9]=(vid>>8)&0xFF;
29         self.DD[10]=pid&0xFF;
30         self.DD[11]=(pid>>8)&0xFF;
31         
32         #Run the service loop.
33         while 1:
34             self.service_irqs();
35     def do_SETUP(self):
36         """Handle USB Enumeration"""
37         #Grab the SETUP packet from the buffer.
38         SUD=self.readbytes(rSUDFIFO,8);
39         
40         #Parse the SETUP packet
41         #print "Handling a setup packet of %s" % self.setup2str(SUD);
42         setuptype=(ord(SUD[bmRequestType])&0x60);
43         if setuptype==0x00:
44             self.std_request(SUD);
45         elif setuptype==0x20:
46             self.class_request(SUD);
47         elif setuptype==0x40:
48             self.vendor_request(SUD);
49         else:
50             print "Unknown request type 0x%02x." % ord(SUD[bmRequestType])
51             self.STALL_EP0(SUD);
52     def printblock(self,block,data):
53         """Prints a block, perhaps inserting it into the dump file."""
54         s="";
55         for foo in data:
56             s=s+("%02x "%ord(foo));
57         print "BLOCK %04x : %s" % (block,s);
58         sys.stdout.flush(); #Needed for the tee command.
59         return;
60     def handle_dfu_download(self,SUD):
61         """Sometimes this comes from a Class request, sometimes a Vendor."""
62         #Compute the total length, though we'll be accepting 64-byte chunks.
63         l=(
64             ord(SUD[wLengthL])+
65             (ord(SUD[wLengthH])<<8)
66             );
67         block=ord(SUD[wValueL])+ (ord(SUD[wValueH])<<8);
68         b="";
69         while len(b)<l:
70             while not(self.rreg(rEPIRQ)&bmOUT0DAVIRQ): pass;
71             b=b+self.readbytes(rEP0FIFO,min(l,64));
72             self.wreg(rEPIRQ,bmOUT0DAVIRQ); #Clear the bit
73             if self.usbverbose: print "Got %i/%i bytes." % (len(b),l);
74         
75         self.printblock(block,b);
76         
77         
78         #Signify that we got everything.
79         self.wregAS(rEP0BC,0);
80         
81         if self.usbverbose: print "Completed data block.";
82         return;
83     DFUIDLE=0x02;
84     DFUDNIDLE=0x05;
85     DFUUPIDLE=0x09;
86     DFUDNBUSY=0x04
87     dfustate=DFUIDLE; #Some clients get picky about this.
88     def class_request(self,SUD):
89         """Handle a class request."""
90         
91         request=ord(SUD[bRequest]);
92         
93         if request==0: #DETACH
94             print "DFU DETACH; this probably means the download is complete.";
95             self.wregAS(rEP0BC,0);
96             return;
97         elif request==1: #Download
98             self.handle_dfu_download(SUD);
99             self.dfustate=self.DFUDNIDLE;
100             return;
101         elif request==2: #Upload
102             print "TODO Implement uploads.";
103             pass;
104         elif request==3: #GetStatus
105             self.writebytes(rEP0FIFO,
106                             [0,0,0,0,0,0]);
107             self.wregAS(rEP0BC,6);
108             return;
109         elif request==4: #ClearStatus
110             pass;
111         elif request==5: #GetState
112             print "Returning state of %02x." % self.dfustate
113             #Send some sort of reply.
114             #self.wreg(rEP0FIFO,0x02); #DFU IDLE
115             self.wreg(rEP0FIFO,self.dfustate);
116             self.wregAS(rEP0BC,1);
117             #Don't send reply twice.
118             return;
119         elif request==6: #Abort
120             print "DFU ABORT.";
121             self.dfustate=self.DFUDNIDLE;
122             self.wregAS(rEP0BC,0);
123             return;
124         
125         print "Blindly accepting unhandled class request %02x" % request;
126         self.wregAS(rEP0BC,0);
127     def vendor_request(self,SUD):
128         """Handle an DFU vendor request."""
129         request=ord(SUD[bRequest]);
130         
131         print "Blindly accepting unhandled vendor request %02x" % request;
132         self.wregAS(rEP0BC,0);
133     def std_request(self,SUD):
134         """Handles a standard setup request."""
135         setuptype=ord(SUD[bRequest]);
136         if setuptype==SR_GET_DESCRIPTOR: self.send_descriptor(SUD);
137         #elif setuptype==SR_SET_FEATURE: self.feature(1);
138         elif setuptype==SR_SET_CONFIGURATION: self.set_configuration(SUD);
139         elif setuptype==SR_GET_STATUS: self.get_status(SUD);
140         elif setuptype==SR_SET_ADDRESS: self.rregAS(rFNADDR);
141         elif setuptype==SR_GET_INTERFACE: self.get_interface(SUD);
142         else:
143             print "Stalling Unknown standard setup request type %02x" % setuptype;
144             self.STALL_EP0(SUD);
145     
146     def get_interface(self,SUD):
147         """Handles a setup request for SR_GET_INTERFACE."""
148         if ord(SUD[wIndexL]==0):
149             self.wreg(rEP0FIFO,0);
150             self.wregAS(rEP0BC,1);
151         else:
152             self.STALL_EP0(SUD);
153     
154
155
156
157 #Device Descriptor; be sure to overwrite VID and PID.
158     DD=[0x12,                   # bLength = 18d
159         0x01,                   # bDescriptorType = Device (1)
160         0x10,0x01,              # bcdUSB(L/H) USB spec rev (BCD)
161         0x00,0x00,0x00,         # bDeviceClass, bDeviceSubClass, bDeviceProtocol
162         0x40,                   # bMaxPacketSize0 EP0 is 64 bytes
163         0x03,0x04,              # idVendor(L/H)--  Offset 8,9
164         0x72,0x83,              # idProduct(L/H)-- Offset 10,11
165         0x01,0x00,              # bcdDevice--1234
166         1,2,3,                  # iManufacturer, iProduct, iSerialNumber
167         1                       # One configuration.
168         ];
169 #Configuration Descriptor
170     CD=[0x09,                   # bLength
171         0x02,                   # bDescriptorType = Config
172         0x20,0x00,              # wTotalLength(L/H) = 34 bytes (0x22)
173         0x01,                   # bNumInterfaces
174         0x01,                   # bConfigValue
175         0x00,                   # iConfiguration
176         0xE0,                   # bmAttributes. b7=1 b6=self-powered b5=RWU supported
177         0x01,                   # MaxPower is 2 ma
178 # INTERFACE Descriptor
179         0x09,                   # length = 9
180         0x04,                   # type = IF
181         0x00,                   # IF #0
182         0x00,                   # bAlternate Setting
183         0x02,                   # bNum Endpoints
184         0xFE,                   # bInterfaceClass = FF=vendor
185         0x01,0x02,              # bInterfaceSubClass, bInterfaceProtocol
186         0x00,                   # iInterface
187 # IN Endpoint Descriptor, unused.
188         0x07,                   # bLength
189         0x05,                   # bDescriptorType (Endpoint)
190         0x83,                   # bEndpointAddress (EP3-IN)             
191         0x02,                   # bmAttributes  (bulk)
192         64,0,                   # wMaxPacketSize (64)
193         00,
194 # OUT Endpoint Descriptor, unused.
195         0x07,                   # bLength
196         0x05,                   # bDescriptorType (Endpoint)
197         0x01,                   # bEndpointAddress (EP1-OUT)            
198         0x02,                   # bmAttributes  (bulk)
199         64,0,                   # wMaxPacketSize (64)
200         00];
201     strDesc=[
202 # STRING descriptor 0--Language string
203 "\x04\x03\x09\x04",
204 # [
205 #         0x04,                 # bLength
206 #       0x03,                   # bDescriptorType = string
207 #       0x09,0x04               # wLANGID(L/H) = English-United Sates
208 # ],
209 # STRING descriptor 1--Manufacturer ID
210 "\x10\x03G\x00o\x00o\x00d\x00F\x00E\x00T\x00",
211 # STRING descriptor 2 - Product ID
212 "\x18\x03D\x00F\x00U\x00 \x00 \x00E\x00m\x00u\x00l\x00a\x00t\x00o\x00r\x00 \x00 \x00 \x00 \x00 \x00",
213 # STRING descriptor 3 - Serial Number ID
214 "\x14\x03S\x00/\x00N\x00 \x003\x004\x002\x000\x00E\x00"
215 ];
216
217
218     def set_configuration(self,SUD):
219         """Set the configuration."""
220         bmSUSPIE=0x10;
221         configval=ord(SUD[wValueL]);
222         if(configval>0):
223             self.SETBIT(rUSBIEN,bmSUSPIE);
224         self.rregAS(rFNADDR);
225     def get_status(self,SUD):
226         """Get the USB Setup Status."""
227         testbyte=ord(SUD[bmRequestType])
228         
229         #Toward Device
230         if testbyte==0x80:
231             self.wreg(rEP0FIFO,0x03); #Enable RWU and self-powered
232             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
233             self.wregAS(rEP0BC,2);    #Load byte count, arm transfer, and ack CTL.
234         #Toward Interface
235         elif testbyte==0x81:
236             self.wreg(rEP0FIFO,0x00);
237             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
238             self.wregAS(rEP0BC,2);
239         #Toward Endpoint
240         elif testbyte==0x82:
241             if(ord(SUD[wIndexL])==0x83):
242                 self.wreg(rEP0FIFO,0x01); #Stall EP3
243                 self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
244                 self.wregAS(rEP0BC,2);
245             else:
246                 self.STALL_EP0(SUD);
247         else:
248             self.STALL_EP0(SUD);
249     def service_irqs(self):
250         """Handle USB interrupt events."""
251         
252         epirq=self.rreg(rEPIRQ);
253         usbirq=self.rreg(rUSBIRQ);
254         
255         #Are we being asked for setup data?
256         if(epirq&bmSUDAVIRQ): #Setup Data Requested
257             self.wreg(rEPIRQ,bmSUDAVIRQ); #Clear the bit
258             self.do_SETUP();
259         elif(epirq&bmIN3BAVIRQ): #EN3-IN packet
260             #print "IN3 event.";
261             #self.do_IN3();
262             self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit
263         elif(epirq&bmOUT1DAVIRQ): #OUT1-OUT packet
264             print "OUT1 event.";
265             self.do_OUT1();
266             self.wregAS(rEPIRQ,bmOUT1DAVIRQ); #Clear the bit *AFTER* servicing.
267         #else:
268         #    self.do_IN3();
269     
270     typestring="GoodFET emulates DFU properly, if you can read this!\n";
271     typepos=0;
272     
273     def typeletter(self,key):
274         """Type a letter on IN3.  Zero for keyup."""
275         if type(key)==str: key=ord(key);
276         
277         self.wreg(rEP3INFIFO,0x01);      #Modem Status
278         self.wreg(rEP3INFIFO,0x00);      #Line Status
279         self.wreg(rEP3INFIFO,key);
280         self.wregAS(rEP3INBC,3);
281     def do_IN3(self):
282         """Handle IN3 input event."""
283         #Don't bother clearing interrupt flag, that's done by sending the reply.
284         
285     def do_OUT1(self):
286         """Handle an OUT1 output event."""
287         print """
288 Got an output event, but it's not part of the DFU standard so this
289 client can't know what to do with it.  Usually, this needs some sort
290 of acknowledgment to tell the host that you are switching into.
291 """;
292         
293         l=self.rreg(rEP1OUTBC);
294         frame=self.readbytesAS(rEP1OUTFIFO,l);
295         print "DFU OUT1: %s" % frame[1:len(frame)];
296         
297
298
299 if(len(sys.argv)<3):
300     print "Usage: %s VID PID" % sys.argv[0];
301     print "";
302     print """Example VID/PID pairs:
303 \tFFFF 0004 -- Ubertooth               ( Tested )
304 \t0483 DF11 -- STM32                   (Untested)
305 \t03EB 2F.. -- Atmel DFU               (Untested)
306 """
307     sys.exit();
308
309
310 #Initialize FET and set baud rate
311 client=GoodFETMAXUSBDFU();
312 client.serInit()
313
314 vid=int(sys.argv[1],16);
315 pid=int(sys.argv[2],16);
316
317 client.MAXUSBsetup();
318
319 print """
320 The DFU emulator is now running.  Any firmware which is downloaded to
321 the virtual device will be locked to this console, beginning with the
322 block device."""
323
324 client.dfuinit(vid,pid);
325