#!/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();