From 0921c40dfa9f0b9d47ab6eef38f416a732f56968 Mon Sep 17 00:00:00 2001 From: travisutk Date: Thu, 17 May 2012 19:37:58 +0000 Subject: [PATCH 1/1] Added a buggy but minimally functional FTDI emulator. Strings still say that it's Maxim. git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@1173 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- client/goodfet.maxusbftdi | 376 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100755 client/goodfet.maxusbftdi diff --git a/client/goodfet.maxusbftdi b/client/goodfet.maxusbftdi new file mode 100755 index 0000000..8848c31 --- /dev/null +++ b/client/goodfet.maxusbftdi @@ -0,0 +1,376 @@ +#!/usr/bin/env python + +#FTDI USB Device Emulator +#by Travis Goodspeed + +import sys; +import binascii; +import array; + +from GoodFETMAXUSB import *; + +class GoodFETMAXUSBFTDI(GoodFETMAXUSB): + """This emulates the FTDI USB to Serial chips.""" + def hidinit(self): + """Initialize a USB FTDI device.""" + self.usb_disconnect(); + self.usb_connect(); + self.hidrun(); + + def hidrun(self): + """Main loop of the USB FTDI emulator.""" + print "Starting a FTDI device. This won't return."; + while 1: + self.service_irqs(); + def do_SETUP(self): + """Handle USB Enumeration""" + + #Grab the SETUP packet from the buffer. + SUD=self.readbytes(rSUDFIFO,8); + + #Parse the SETUP packet + print "Handling a setup packet of %s" % self.setup2str(SUD); + setuptype=(ord(SUD[bmRequestType])&0x60); + if setuptype==0x00: + self.std_request(SUD); + elif setuptype==0x20: + self.class_request(SUD); + elif setuptype==0x40: + self.vendor_request(SUD); + else: + print "Unknown request type 0x%02x." % ord(SUD[bmRequestType]) + self.STALL_EP0(SUD); + def ftdi_request(self,SUD): + """Handle an FTDI request.""" + + def class_request(self,SUD): + """Handle a class request.""" + print "Stalling a class request."; + self.STALL_EP0(SUD); + def vendor_request(self,SUD): + """Handle an FTDI vendor request.""" + request=ord(SUD[bRequest]); + + if request==0: #reset + pass + elif request==1: #modem_ctrl + valuel=ord(SUD[wValueL]) + valueh=ord(SUD[wValueH]); + dtr=valuel&1; + rts=(valuel&2)>>1; + dtren=valueh&1; + rtsen=(valueh&2)>>1; + + if dtren: print "DTR is enabled, value %i" % dtr; + if rtsen: print "RTS is enabled, value %i" % rts; + + pass; + elif request==2: #set_flow_ctrl + indexh=ord(SUD[wIndexH]); + indexl=ord(SUD[wIndexL]); + if indexh==0: + print "SET_FLOW_CTRL to no handshaking."; + if indexl&1: + print "SET_FLOW_CTRL for RTS/CTS handshaking."; + if indexl&2: + print "SET_FLOW_CTRL for DTR/DSR handshaking."; + if indexl&4: + print "SET_FLOW_CTRL for XON/XOFF handshaking."; + + pass; + elif request==3: #set_baud_rate + print "Baud rate set to %i." % ord(SUD[wValueL]); + pass; + elif request==4: #set_data + pass; + elif request==5: #get_status + print "I don't know how to send the status."; + pass; #FIXME + elif request==6: #set_event_char + pass; + elif request==7: #set_error_char + pass; + elif request==9: #set_latency_timer + print "Expected to set latency timer to 0x%02x." % ord(SUD[wValueL]); + pass; + elif request==0x0a: #get_latency_timer + print "Bullshitting a value for the latency timer." + #Send some sort of reply. + self.wreg(rEP0FIFO,0x01); + self.wreg(rEP0FIFO,0x00); + self.wregAS(rEP0BC,2); + #Don't send reply twice. + return; + + + print "Blindly accepting vendor request"; + #self.wreg(rEP0FIFO,0); + self.wregAS(rEP0BC,0); + def std_request(self,SUD): + """Handles a standard setup request.""" + setuptype=ord(SUD[bRequest]); + if setuptype==SR_GET_DESCRIPTOR: self.send_descriptor(SUD); + elif setuptype==SR_SET_FEATURE: self.feature(1); + elif setuptype==SR_SET_CONFIGURATION: self.set_configuration(SUD); + elif setuptype==SR_GET_STATUS: self.get_status(SUD); + elif setuptype==SR_SET_ADDRESS: self.rregAS(rFNADDR); + elif setuptype==SR_GET_INTERFACE: self.get_interface(SUD); + else: + print "Stalling Unknown standard setup request type %02x" % setuptype; + self.STALL_EP0(SUD); + + def get_interface(self,SUD): + """Handles a setup request for SR_GET_INTERFACE.""" + if ord(SUD[wIndexL]==0): + self.wreg(rEP0FIFO,0); + self.wregAS(rEP0BC,1); + else: + self.STALL_EP0(SUD); + + +#0403:6001 + +#Device Descriptor + DD=[0x12, # bLength = 18d + 0x01, # bDescriptorType = Device (1) + 0x00,0x01, # bcdUSB(L/H) USB spec rev (BCD) + 0x00,0x00,0x00, # bDeviceClass, bDeviceSubClass, bDeviceProtocol + 0x40, # bMaxPacketSize0 EP0 is 64 bytes + 0x03,0x04, # idVendor(L/H)--FTDI is 0403 + 0x01,0x60, # idProduct(L/H)--6001 + 0x34,0x12, # bcdDevice--1234 + 1,2,3, # iManufacturer, iProduct, iSerialNumber + 1]; +#Configuration Descriptor + CD=[0x09, # bLength + 0x02, # bDescriptorType = Config + 0x20,0x00, # wTotalLength(L/H) = 34 bytes (0x22) + 0x01, # bNumInterfaces + 0x01, # bConfigValue + 0x00, # iConfiguration + 0xE0, # bmAttributes. b7=1 b6=self-powered b5=RWU supported + 0x01, # MaxPower is 2 ma +# INTERFACE Descriptor + 0x09, # length = 9 + 0x04, # type = IF + 0x00, # IF #0 + 0x00, # bAlternate Setting + 0x02, # bNum Endpoints + 0xFF, # bInterfaceClass = FF=vendor + 0xFF,0xFF, # bInterfaceSubClass, bInterfaceProtocol + 0x02, # iInterface +# HID Descriptor--It's at CD[18] + # 0x09, # bLength + # 0x21, # bDescriptorType = HID + # 0x10,0x01, # bcdHID(L/H) Rev 1.1 + # 0x00, # bCountryCode (none) + # 0x01, # bNumDescriptors (one report descriptor) + # 0x22, # bDescriptorType (report) + # 43,0, # CD[25]: wDescriptorLength(L/H) (report descriptor size is 43 bytes) +# Endpoint Descriptor + 0x07, # bLength + 0x05, # bDescriptorType (Endpoint) + 0x83, # bEndpointAddress (EP3-IN) + 0x02, # bmAttributes (interrupt) + 64,0, # wMaxPacketSize (64) + 10, +# Endpoint Descriptor + 0x07, # bLength + 0x05, # bDescriptorType (Endpoint) + 0x01, # bEndpointAddress (EP1-OUT) + 0x02, # bmAttributes (interrupt) + 64,0, # wMaxPacketSize (64) + 10]; + strDesc=[ +# STRING descriptor 0--Language string +"\x04\x03\x09\x04", +# [ +# 0x04, # bLength +# 0x03, # bDescriptorType = string +# 0x09,0x04 # wLANGID(L/H) = English-United Sates +# ], +# STRING descriptor 1--Manufacturer ID +"\x0c\x03M\x00a\x00x\x00i\x00m\x00", +# [ +# 12, # bLength +# 0x03, # bDescriptorType = string +# 'M',0,'a',0,'x',0,'i',0,'m',0 # text in Unicode +# ], +# STRING descriptor 2 - Product ID +"\x18\x03M\x00A\x00X\x003\x004\x002\x000\x00E\x00 \x00E\x00n\x00u\x00m\x00 \x00C\x00o\x00d\x00e\x00", +# [ 24, # bLength +# 0x03, # bDescriptorType = string +# 'M',0,'A',0,'X',0,'3',0,'4',0,'2',0,'0',0,'E',0,' ',0, +# 'E',0,'n',0,'u',0,'m',0,' ',0,'C',0,'o',0,'d',0,'e',0 +# ], + + +# STRING descriptor 3 - Serial Number ID +"\x14\x03S\x00/\x00N\x00 \x003\x004\x002\x000\x00E\x00" +# [ 20, # bLength +# 0x03, # bDescriptorType = string +# 'S',0, +# '/',0, +# 'N',0, +# ' ',0, +# '3',0, +# '4',0, +# '2',0, +# '0',0, +# 'E',0, +# ] +]; + RepD=[ + 0x05,0x01, # Usage Page (generic desktop) + 0x09,0x06, # Usage (keyboard) + 0xA1,0x01, # Collection + 0x05,0x07, # Usage Page 7 (keyboard/keypad) + 0x19,0xE0, # Usage Minimum = 224 + 0x29,0xE7, # Usage Maximum = 231 + 0x15,0x00, # Logical Minimum = 0 + 0x25,0x01, # Logical Maximum = 1 + 0x75,0x01, # Report Size = 1 + 0x95,0x08, # Report Count = 8 + 0x81,0x02, # Input(Data,Variable,Absolute) + 0x95,0x01, # Report Count = 1 + 0x75,0x08, # Report Size = 8 + 0x81,0x01, # Input(Constant) + 0x19,0x00, # Usage Minimum = 0 + 0x29,0x65, # Usage Maximum = 101 + 0x15,0x00, # Logical Minimum = 0, + 0x25,0x65, # Logical Maximum = 101 + 0x75,0x08, # Report Size = 8 + 0x95,0x01, # Report Count = 1 + 0x81,0x00, # Input(Data,Variable,Array) + 0xC0] + def send_descriptor(self,SUD): + """Send the USB descriptors based upon the setup data.""" + desclen=0; + reqlen=ord(SUD[wLengthL])+256*ord(SUD[wLengthH]); #16-bit length + desctype=ord(SUD[wValueH]); + + if desctype==GD_DEVICE: + desclen=self.DD[0]; + ddata=self.DD; + elif desctype==GD_CONFIGURATION: + desclen=self.CD[2]; + ddata=self.CD; + elif desctype==GD_STRING: + desclen=self.strDesc[ord(SUD[wValueL])][0]; + ddata=self.strDesc[ord(SUD[wValueL])]; + elif desctype==GD_REPORT: + desclen=self.CD[25]; + ddata=self.RepD; + + #TODO Configuration, String, Hid, and Report + + if desclen>0: + sendlen=min(reqlen,desclen); + self.writebytes(rEP0FIFO,ddata); + self.wregAS(rEP0BC,sendlen); + else: + print "Stalling in send_descriptor() for lack of handler for %02x." % desctype; + self.STALL_EP0(SUD); + def set_configuration(self,SUD): + """Set the configuration.""" + bmSUSPIE=0x10; + configval=ord(SUD[wValueL]); + if(configval>0): + self.SETBIT(rUSBIEN,bmSUSPIE); + self.rregAS(rFNADDR); + def get_status(self,SUD): + """Get the USB Setup Status.""" + testbyte=ord(SUD[bmRequestType]) + + #Toward Device + if testbyte==0x80: + self.wreg(rEP0FIFO,0x03); #Enable RWU and self-powered + self.wreg(rEP0FIFO,0x00); #Second byte is always zero. + self.wregAS(rEP0BC,2); #Load byte count, arm transfer, and ack CTL. + #Toward Interface + elif testbyte==0x81: + self.wreg(rEP0FIFO,0x00); + self.wreg(rEP0FIFO,0x00); #Second byte is always zero. + self.wregAS(rEP0BC,2); + #Toward Endpoint + elif testbyte==0x82: + if(ord(SUD[wIndexL])==0x83): + self.wreg(rEP0FIFO,0x01); #Stall EP3 + self.wreg(rEP0FIFO,0x00); #Second byte is always zero. + self.wregAS(rEP0BC,2); + else: + self.STALL_EP0(SUD); + else: + self.STALL_EP0(SUD); + def service_irqs(self): + """Handle USB interrupt events.""" + + epirq=self.rreg(rEPIRQ); + usbirq=self.rreg(rUSBIRQ); + + #Are we being asked for setup data? + if(epirq&bmSUDAVIRQ): #Setup Data Requested + self.wreg(rEPIRQ,bmSUDAVIRQ); #Clear the bit + self.do_SETUP(); + elif(epirq&bmIN3BAVIRQ): #EN3-IN packet + self.do_IN3(); + elif(epirq&bmOUT1DAVIRQ): #OUT1-OUT packet + self.wreg(rEPIRQ,bmOUT1DAVIRQ); #Clear the bit + self.do_OUT1(); + + + + typephase=0; + typestring=" GoodFET emulating FTDI!"; + typepos=0; + + def asc2hid(self,ascii): + """Translate ASCII to an USB keycode.""" + a=ascii; + if a>='a' and a<='z': + return ord(a)-ord('a')+4; + elif a>='A' and a<='Z': + return ord(a)-ord('A')+4; + elif a==' ': + return 0x2C; #space + else: + return 0; #key-up + def type_IN3(self): + """Type next letter in buffer.""" + if self.typepos>=len(self.typestring): + self.typeletter(0); + elif self.typephase==0: + self.typephase=1; + self.typeletter(0); + else: + typephase=0; + self.typeletter(self.typestring[self.typepos]); + self.typepos=self.typepos+1; + return; + def typeletter(self,key): + """Type a letter on IN3. Zero for keyup.""" + #if type(key)==str: key=ord(key); + #Send a key-up. + self.wreg(rEP3INFIFO,0); + self.wreg(rEP3INFIFO,0); + self.wreg(rEP3INFIFO,self.asc2hid(key)); + self.wreg(rEP3INBC,3); + def do_IN3(self): + """Handle IN3 input event.""" + #Don't bother clearing interrupt flag, that's done by sending the reply. + #print "Got an input event, sending back some garbage that might be right."; + self.type_IN3(); + def do_OUT1(self): + """Handle an OUT1 output event.""" + print "Got an output event, printing the result."; + frame=self.readbytes(rEP1OUTFIFO,64); + #print "Got %s" % frame; + +#Initialize FET and set baud rate +client=GoodFETMAXUSBFTDI(); +client.serInit() + + +client.MAXUSBsetup(); +client.hidinit(); + -- 2.20.1