Added a buggy but minimally functional FTDI emulator.
[goodfet] / client / goodfet.maxusbftdi
1 #!/usr/bin/env python
2
3 #FTDI USB Device Emulator
4 #by Travis Goodspeed
5
6 import sys;
7 import binascii;
8 import array;
9
10 from GoodFETMAXUSB import *;
11
12 class GoodFETMAXUSBFTDI(GoodFETMAXUSB):
13     """This emulates the FTDI USB to Serial chips."""
14     def hidinit(self):
15         """Initialize a USB FTDI device."""
16         self.usb_disconnect();
17         self.usb_connect();
18         self.hidrun();
19         
20     def hidrun(self):
21         """Main loop of the USB FTDI emulator."""
22         print "Starting a FTDI device.  This won't return.";
23         while 1:
24             self.service_irqs();
25     def do_SETUP(self):
26         """Handle USB Enumeration"""
27         
28         #Grab the SETUP packet from the buffer.
29         SUD=self.readbytes(rSUDFIFO,8);
30         
31         #Parse the SETUP packet
32         print "Handling a setup packet of %s" % self.setup2str(SUD);
33         setuptype=(ord(SUD[bmRequestType])&0x60);
34         if setuptype==0x00:
35             self.std_request(SUD);
36         elif setuptype==0x20:
37             self.class_request(SUD);
38         elif setuptype==0x40:
39             self.vendor_request(SUD);
40         else:
41             print "Unknown request type 0x%02x." % ord(SUD[bmRequestType])
42             self.STALL_EP0(SUD);
43     def ftdi_request(self,SUD):
44         """Handle an FTDI request."""
45         
46     def class_request(self,SUD):
47         """Handle a class request."""
48         print "Stalling a class request.";
49         self.STALL_EP0(SUD);
50     def vendor_request(self,SUD):
51         """Handle an FTDI vendor request."""
52         request=ord(SUD[bRequest]);
53         
54         if request==0:   #reset
55             pass
56         elif request==1: #modem_ctrl
57             valuel=ord(SUD[wValueL])
58             valueh=ord(SUD[wValueH]);
59             dtr=valuel&1;
60             rts=(valuel&2)>>1;
61             dtren=valueh&1;
62             rtsen=(valueh&2)>>1;
63             
64             if dtren: print "DTR is enabled, value %i" % dtr;
65             if rtsen: print "RTS is enabled, value %i" % rts;
66             
67             pass;
68         elif request==2: #set_flow_ctrl
69             indexh=ord(SUD[wIndexH]);
70             indexl=ord(SUD[wIndexL]);
71             if indexh==0:
72                 print "SET_FLOW_CTRL to no handshaking.";
73             if indexl&1:
74                 print "SET_FLOW_CTRL for RTS/CTS handshaking.";
75             if indexl&2:
76                 print "SET_FLOW_CTRL for DTR/DSR handshaking.";
77             if indexl&4:
78                 print "SET_FLOW_CTRL for XON/XOFF handshaking.";
79             
80             pass;
81         elif request==3: #set_baud_rate
82             print "Baud rate set to %i." % ord(SUD[wValueL]);
83             pass;
84         elif request==4: #set_data
85             pass;
86         elif request==5: #get_status
87             print "I don't know how to send the status.";
88             pass; #FIXME
89         elif request==6: #set_event_char
90             pass;
91         elif request==7: #set_error_char
92             pass;
93         elif request==9: #set_latency_timer
94             print "Expected to set latency timer to 0x%02x." % ord(SUD[wValueL]);
95             pass;
96         elif request==0x0a: #get_latency_timer
97             print "Bullshitting a value for the latency timer."
98             #Send some sort of reply.
99             self.wreg(rEP0FIFO,0x01);
100             self.wreg(rEP0FIFO,0x00);
101             self.wregAS(rEP0BC,2);
102             #Don't send reply twice.
103             return;
104             
105         
106         print "Blindly accepting vendor request";
107         #self.wreg(rEP0FIFO,0);
108         self.wregAS(rEP0BC,0);
109     def std_request(self,SUD):
110         """Handles a standard setup request."""
111         setuptype=ord(SUD[bRequest]);
112         if setuptype==SR_GET_DESCRIPTOR: self.send_descriptor(SUD);
113         elif setuptype==SR_SET_FEATURE: self.feature(1);
114         elif setuptype==SR_SET_CONFIGURATION: self.set_configuration(SUD);
115         elif setuptype==SR_GET_STATUS: self.get_status(SUD);
116         elif setuptype==SR_SET_ADDRESS: self.rregAS(rFNADDR);
117         elif setuptype==SR_GET_INTERFACE: self.get_interface(SUD);
118         else:
119             print "Stalling Unknown standard setup request type %02x" % setuptype;
120             self.STALL_EP0(SUD);
121     
122     def get_interface(self,SUD):
123         """Handles a setup request for SR_GET_INTERFACE."""
124         if ord(SUD[wIndexL]==0):
125             self.wreg(rEP0FIFO,0);
126             self.wregAS(rEP0BC,1);
127         else:
128             self.STALL_EP0(SUD);
129     
130
131 #0403:6001
132
133 #Device Descriptor
134     DD=[0x12,                   # bLength = 18d
135         0x01,                   # bDescriptorType = Device (1)
136         0x00,0x01,              # bcdUSB(L/H) USB spec rev (BCD)
137         0x00,0x00,0x00,         # bDeviceClass, bDeviceSubClass, bDeviceProtocol
138         0x40,                   # bMaxPacketSize0 EP0 is 64 bytes
139         0x03,0x04,              # idVendor(L/H)--FTDI is 0403
140         0x01,0x60,              # idProduct(L/H)--6001
141         0x34,0x12,              # bcdDevice--1234
142         1,2,3,                  # iManufacturer, iProduct, iSerialNumber
143         1];
144 #Configuration Descriptor
145     CD=[0x09,                   # bLength
146         0x02,                   # bDescriptorType = Config
147         0x20,0x00,              # wTotalLength(L/H) = 34 bytes (0x22)
148         0x01,                   # bNumInterfaces
149         0x01,                   # bConfigValue
150         0x00,                   # iConfiguration
151         0xE0,                   # bmAttributes. b7=1 b6=self-powered b5=RWU supported
152         0x01,                   # MaxPower is 2 ma
153 # INTERFACE Descriptor
154         0x09,                   # length = 9
155         0x04,                   # type = IF
156         0x00,                   # IF #0
157         0x00,                   # bAlternate Setting
158         0x02,                   # bNum Endpoints
159         0xFF,                   # bInterfaceClass = FF=vendor
160         0xFF,0xFF,              # bInterfaceSubClass, bInterfaceProtocol
161         0x02,                   # iInterface
162 # HID Descriptor--It's at CD[18]
163         # 0x09,                 # bLength
164         # 0x21,                 # bDescriptorType = HID
165         # 0x10,0x01,            # bcdHID(L/H) Rev 1.1
166         # 0x00,                 # bCountryCode (none)
167         # 0x01,                 # bNumDescriptors (one report descriptor)
168         # 0x22,                 # bDescriptorType       (report)
169         # 43,0,                   # CD[25]: wDescriptorLength(L/H) (report descriptor size is 43 bytes)
170 # Endpoint Descriptor
171         0x07,                   # bLength
172         0x05,                   # bDescriptorType (Endpoint)
173         0x83,                   # bEndpointAddress (EP3-IN)             
174         0x02,                   # bmAttributes  (interrupt)
175         64,0,                   # wMaxPacketSize (64)
176         10,
177 # Endpoint Descriptor
178         0x07,                   # bLength
179         0x05,                   # bDescriptorType (Endpoint)
180         0x01,                   # bEndpointAddress (EP1-OUT)            
181         0x02,                   # bmAttributes  (interrupt)
182         64,0,                   # wMaxPacketSize (64)
183         10];
184     strDesc=[
185 # STRING descriptor 0--Language string
186 "\x04\x03\x09\x04",
187 # [
188 #         0x04,                 # bLength
189 #       0x03,                   # bDescriptorType = string
190 #       0x09,0x04               # wLANGID(L/H) = English-United Sates
191 # ],
192 # STRING descriptor 1--Manufacturer ID
193 "\x0c\x03M\x00a\x00x\x00i\x00m\x00",
194 # [
195 #         12,                   # bLength
196 #       0x03,                   # bDescriptorType = string
197 #       'M',0,'a',0,'x',0,'i',0,'m',0 # text in Unicode
198 # ], 
199 # STRING descriptor 2 - Product ID
200 "\x18\x03M\x00A\x00X\x003\x004\x002\x000\x00E\x00 \x00E\x00n\x00u\x00m\x00 \x00C\x00o\x00d\x00e\x00",
201 # [     24,                     # bLength
202 #       0x03,                   # bDescriptorType = string
203 #       'M',0,'A',0,'X',0,'3',0,'4',0,'2',0,'0',0,'E',0,' ',0,
204 #         'E',0,'n',0,'u',0,'m',0,' ',0,'C',0,'o',0,'d',0,'e',0
205 # ],
206
207
208 # STRING descriptor 3 - Serial Number ID
209 "\x14\x03S\x00/\x00N\x00 \x003\x004\x002\x000\x00E\x00"
210 # [       20,                   # bLength
211 #       0x03,                   # bDescriptorType = string
212 #       'S',0,                          
213 #       '/',0,
214 #       'N',0,
215 #       ' ',0,
216 #       '3',0,
217 #       '4',0,
218 #       '2',0,
219 #       '0',0,
220 #         'E',0,
221 # ]
222 ];
223     RepD=[
224         0x05,0x01,              # Usage Page (generic desktop)
225         0x09,0x06,              # Usage (keyboard)
226         0xA1,0x01,              # Collection
227         0x05,0x07,              #   Usage Page 7 (keyboard/keypad)
228         0x19,0xE0,              #   Usage Minimum = 224
229         0x29,0xE7,              #   Usage Maximum = 231
230         0x15,0x00,              #   Logical Minimum = 0
231         0x25,0x01,              #   Logical Maximum = 1
232         0x75,0x01,              #   Report Size = 1
233         0x95,0x08,              #   Report Count = 8
234         0x81,0x02,              #  Input(Data,Variable,Absolute)
235         0x95,0x01,              #   Report Count = 1
236         0x75,0x08,              #   Report Size = 8
237         0x81,0x01,              #  Input(Constant)
238         0x19,0x00,              #   Usage Minimum = 0
239         0x29,0x65,              #   Usage Maximum = 101
240         0x15,0x00,              #   Logical Minimum = 0,
241         0x25,0x65,              #   Logical Maximum = 101
242         0x75,0x08,              #   Report Size = 8
243         0x95,0x01,              #   Report Count = 1
244         0x81,0x00,              #  Input(Data,Variable,Array)
245         0xC0]
246     def send_descriptor(self,SUD):
247         """Send the USB descriptors based upon the setup data."""
248         desclen=0;
249         reqlen=ord(SUD[wLengthL])+256*ord(SUD[wLengthH]); #16-bit length
250         desctype=ord(SUD[wValueH]);
251         
252         if desctype==GD_DEVICE:
253             desclen=self.DD[0];
254             ddata=self.DD;
255         elif desctype==GD_CONFIGURATION:
256             desclen=self.CD[2];
257             ddata=self.CD;
258         elif desctype==GD_STRING:
259             desclen=self.strDesc[ord(SUD[wValueL])][0];
260             ddata=self.strDesc[ord(SUD[wValueL])];
261         elif desctype==GD_REPORT:
262             desclen=self.CD[25];
263             ddata=self.RepD;
264         
265         #TODO Configuration, String, Hid, and Report
266         
267         if desclen>0:
268             sendlen=min(reqlen,desclen);
269             self.writebytes(rEP0FIFO,ddata);
270             self.wregAS(rEP0BC,sendlen);
271         else:
272             print "Stalling in send_descriptor() for lack of handler for %02x." % desctype;
273             self.STALL_EP0(SUD);
274     def set_configuration(self,SUD):
275         """Set the configuration."""
276         bmSUSPIE=0x10;
277         configval=ord(SUD[wValueL]);
278         if(configval>0):
279             self.SETBIT(rUSBIEN,bmSUSPIE);
280         self.rregAS(rFNADDR);
281     def get_status(self,SUD):
282         """Get the USB Setup Status."""
283         testbyte=ord(SUD[bmRequestType])
284         
285         #Toward Device
286         if testbyte==0x80:
287             self.wreg(rEP0FIFO,0x03); #Enable RWU and self-powered
288             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
289             self.wregAS(rEP0BC,2);    #Load byte count, arm transfer, and ack CTL.
290         #Toward Interface
291         elif testbyte==0x81:
292             self.wreg(rEP0FIFO,0x00);
293             self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
294             self.wregAS(rEP0BC,2);
295         #Toward Endpoint
296         elif testbyte==0x82:
297             if(ord(SUD[wIndexL])==0x83):
298                 self.wreg(rEP0FIFO,0x01); #Stall EP3
299                 self.wreg(rEP0FIFO,0x00); #Second byte is always zero.
300                 self.wregAS(rEP0BC,2);
301             else:
302                 self.STALL_EP0(SUD);
303         else:
304             self.STALL_EP0(SUD);
305     def service_irqs(self):
306         """Handle USB interrupt events."""
307         
308         epirq=self.rreg(rEPIRQ);
309         usbirq=self.rreg(rUSBIRQ);
310         
311         #Are we being asked for setup data?
312         if(epirq&bmSUDAVIRQ): #Setup Data Requested
313             self.wreg(rEPIRQ,bmSUDAVIRQ); #Clear the bit
314             self.do_SETUP();
315         elif(epirq&bmIN3BAVIRQ): #EN3-IN packet
316             self.do_IN3();
317         elif(epirq&bmOUT1DAVIRQ): #OUT1-OUT packet
318             self.wreg(rEPIRQ,bmOUT1DAVIRQ); #Clear the bit
319             self.do_OUT1();
320         
321     
322     
323     typephase=0;
324     typestring="                      GoodFET emulating FTDI!";
325     typepos=0;
326     
327     def asc2hid(self,ascii):
328         """Translate ASCII to an USB keycode."""
329         a=ascii;
330         if a>='a' and a<='z':
331             return ord(a)-ord('a')+4;
332         elif a>='A' and a<='Z':
333             return ord(a)-ord('A')+4;
334         elif a==' ':
335             return 0x2C; #space
336         else:
337             return 0; #key-up
338     def type_IN3(self):
339         """Type next letter in buffer."""
340         if self.typepos>=len(self.typestring):
341             self.typeletter(0);
342         elif self.typephase==0:
343             self.typephase=1;
344             self.typeletter(0);
345         else:
346             typephase=0;
347             self.typeletter(self.typestring[self.typepos]);
348             self.typepos=self.typepos+1;
349         return;
350     def typeletter(self,key):
351         """Type a letter on IN3.  Zero for keyup."""
352         #if type(key)==str: key=ord(key);
353         #Send a key-up.
354         self.wreg(rEP3INFIFO,0);
355         self.wreg(rEP3INFIFO,0);
356         self.wreg(rEP3INFIFO,self.asc2hid(key));
357         self.wreg(rEP3INBC,3);
358     def do_IN3(self):
359         """Handle IN3 input event."""
360         #Don't bother clearing interrupt flag, that's done by sending the reply.
361         #print "Got an input event, sending back some garbage that might be right.";
362         self.type_IN3();
363     def do_OUT1(self):
364         """Handle an OUT1 output event."""
365         print "Got an output event, printing the result.";
366         frame=self.readbytes(rEP1OUTFIFO,64);
367         #print "Got %s" % frame;
368
369 #Initialize FET and set baud rate
370 client=GoodFETMAXUSBFTDI();
371 client.serInit()
372
373
374 client.MAXUSBsetup();
375 client.hidinit();
376