#!/usr/bin/env python #DFU USB Device Emulator #by Travis Goodspeed import sys; import binascii; import array; import time; from GoodFETMAXUSB import *; class GoodFETMAXUSBDFU(GoodFETMAXUSBDevice): usbverbose=False; """This emulates the DFU USB to Serial chips.""" def dfuinit(self,vid=0xFFFF,pid=0x0004): """Initialize a USB DFU device.""" self.usb_disconnect(); time.sleep(1); self.usb_connect(); self.dfurun(vid,pid); def dfurun(self,vid,pid): """Main loop of the USB DFU emulator.""" print "Starting a DFU device as %04X:%04X" % (vid,pid); sys.stdout.flush(); #Set the VID and PID. self.DD[8]=vid&0xFF; self.DD[9]=(vid>>8)&0xFF; self.DD[10]=pid&0xFF; self.DD[11]=(pid>>8)&0xFF; #Run the service loop. 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 printblock(self,block,data): """Prints a block, perhaps inserting it into the dump file.""" s=""; for foo in data: s=s+("%02x "%ord(foo)); print "BLOCK %04x : %s" % (block,s); sys.stdout.flush(); #Needed for the tee command. return; def handle_dfu_download(self,SUD): """Sometimes this comes from a Class request, sometimes a Vendor.""" #Compute the total length, though we'll be accepting 64-byte chunks. l=( ord(SUD[wLengthL])+ (ord(SUD[wLengthH])<<8) ); block=ord(SUD[wValueL])+ (ord(SUD[wValueH])<<8); b=""; while len(b)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 #print "IN3 event."; #self.do_IN3(); self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit elif(epirq&bmOUT1DAVIRQ): #OUT1-OUT packet print "OUT1 event."; self.do_OUT1(); self.wregAS(rEPIRQ,bmOUT1DAVIRQ); #Clear the bit *AFTER* servicing. #else: # self.do_IN3(); typestring="GoodFET emulates DFU properly, if you can read this!\n"; typepos=0; def typeletter(self,key): """Type a letter on IN3. Zero for keyup.""" if type(key)==str: key=ord(key); self.wreg(rEP3INFIFO,0x01); #Modem Status self.wreg(rEP3INFIFO,0x00); #Line Status self.wreg(rEP3INFIFO,key); self.wregAS(rEP3INBC,3); def do_IN3(self): """Handle IN3 input event.""" #Don't bother clearing interrupt flag, that's done by sending the reply. def do_OUT1(self): """Handle an OUT1 output event.""" print """ Got an output event, but it's not part of the DFU standard so this client can't know what to do with it. Usually, this needs some sort of acknowledgment to tell the host that you are switching into. """; l=self.rreg(rEP1OUTBC); frame=self.readbytesAS(rEP1OUTFIFO,l); print "DFU OUT1: %s" % frame[1:len(frame)]; if(len(sys.argv)<3): print "Usage: %s VID PID" % sys.argv[0]; print ""; print """Example VID/PID pairs: \tFFFF 0004 -- Ubertooth ( Works ) \t0483 DF11 -- STM32 (Untested) \t03EB 2F.. -- Atmel DFU (Untested) \t05AC 1227 -- Apple iBoot (Untested) """ sys.exit(); #Initialize FET and set baud rate client=GoodFETMAXUSBDFU(); client.serInit() vid=int(sys.argv[1],16); pid=int(sys.argv[2],16); client.MAXUSBsetup(); print """ The DFU emulator is now running. Any firmware which is downloaded to the virtual device will be locked to this console, beginning with the block device.""" client.dfuinit(vid,pid);