X-Git-Url: http://git.rot13.org/?p=goodfet;a=blobdiff_plain;f=client%2FGoodFETMAXUSB.py;h=a9145fdba9cd8f5b70fc8d60c59452de5b6958b5;hp=30fb06e430b05a66f9f864f5c4a30cf212222337;hb=a8b686459e73c8a37df4537083a675fc21de4699;hpb=35580fd76085fbc1c80000097cbd72e34ad5edee diff --git a/client/GoodFETMAXUSB.py b/client/GoodFETMAXUSB.py index 30fb06e..a9145fd 100644 --- a/client/GoodFETMAXUSB.py +++ b/client/GoodFETMAXUSB.py @@ -90,7 +90,7 @@ GD_STRING =0x03 # Get device descriptor: String GD_HID =0x21 # Get descriptor: HID GD_REPORT =0x22 # Get descriptor: Report -# SETUP packet offsets +# SETUP packet header offsets bmRequestType =0 bRequest =1 wValueL =2 @@ -203,9 +203,50 @@ bmHXFRDNIRQ =0x80 class GoodFETMAXUSB(GoodFET): MAXUSBAPP=0x40; + usbverbose=True; + + 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(); + if(epirq&bmOUT1DAVIRQ): #OUT1-OUT packet + self.do_OUT1(); + self.wreg(rEPIRQ,bmOUT1DAVIRQ); #Clear the bit *AFTER* servicing. + if(epirq&bmIN3BAVIRQ): #IN3-IN packet + self.do_IN3(); + #self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit + if(epirq&bmIN2BAVIRQ): #IN2 packet + self.do_IN2(); + #self.wreg(rEPIRQ,bmIN2BAVIRQ); #Clear the bit + #else: + # print "No idea how to service this IRQ: %02x" % epirq; + def do_IN2(self): + """Overload this.""" + def do_IN3(self): + """Overload this.""" + def do_OUT1(self): + """Overload this.""" + if self.usbverbose: print "Ignoring an OUT1 interrupt."; + def setup2str(self,SUD): + """Converts the header of a setup packet to a string.""" + return "bmRequestType=0x%02x, bRequest=0x%02x, wValue=0x%04x, wIndex=0x%04x, wLength=0x%04x" % ( + ord(SUD[0]), ord(SUD[1]), + ord(SUD[2])+(ord(SUD[3])<<8), + ord(SUD[4])+(ord(SUD[5])<<8), + ord(SUD[6])+(ord(SUD[7])<<8) + ); + def MAXUSBsetup(self): """Move the FET into the MAXUSB application.""" self.writecmd(self.MAXUSBAPP,0x10,0,self.data); #MAXUSB/SETUP + self.writecmd(self.MAXUSBAPP,0x10,0,self.data); #MAXUSB/SETUP + self.writecmd(self.MAXUSBAPP,0x10,0,self.data); #MAXUSB/SETUP print "Connected to MAX342x Rev. %x" % (self.rreg(rREVISION)); self.wreg(rPINCTL,0x18); #Set duplex and negative INT level. @@ -248,8 +289,39 @@ class GoodFETMAXUSB(GoodFET): ashex=""; for foo in toret: ashex=ashex+(" %02x"%ord(foo)); - print "GET %02x==%s" % (reg,ashex); + if self.usbverbose: print "GET %02x==%s" % (reg,ashex); + return toret; + def readbytesAS(self,reg,length): + """Peek some bytes from a register, acking prior transfer.""" + data=[(reg<<3)|1]+range(0,length); + self.writecmd(self.MAXUSBAPP,0x00,len(data),data); + toret=self.data[1:len(self.data)]; + ashex=""; + for foo in toret: + ashex=ashex+(" %02x"%ord(foo)); + if self.usbverbose: print "GETAS %02x==%s" % (reg,ashex); return toret; + def fifo_ep3in_tx(self,data): + """Sends the data out of EP3 in 64-byte chunks.""" + #Wait for the buffer to be free before starting. + while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ): pass; + + count=len(data); + pos=0; + while count>0: + #Send 64-byte chunks or the remainder. + c=min(count,64); + self.writebytes(rEP3INFIFO, + data[pos:pos+c]); + self.wregAS(rEP3INBC,c); + count=count-c; + pos=pos+c; + + #Wait for the buffer to be free before continuing. + while not(self.rreg(rEPIRQ)&bmIN3BAVIRQ): pass; + + return; + def ctl_write_nd(self,request): """Control Write with no data stage. Assumes PERADDR is set and the SUDFIFO contains the 8 setup bytes. Returns with @@ -318,9 +390,11 @@ class GoodFETMAXUSB(GoodFET): #Very innefficient, move this to C if performance is needed. for j in range(0,pktsize): self.xfrdata=self.xfrdata+[self.rreg(rRCVFIFO)]; + xfrsize=self.xfrdata[0]; self.wreg(rHIRQ,bmRCVDAVIRQ); #Clear IRQ xfrlen=xfrlen+pktsize; #Add byte count to total transfer length. + print "%i / %i" % (xfrlen,xfrsize) #Packet is complete if: # 1. The device sent a short packet, 0: toret=toret+chr(c); return toret; +class GoodFETMAXUSBDevice(GoodFETMAXUSB): + + 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=ord(self.strDesc[ord(SUD[wValueL])][0]); + ddata=self.strDesc[ord(SUD[wValueL])]; + elif desctype==GD_HID: + #Don't know how to do this yet. + pass; + elif desctype==GD_REPORT: + desclen=self.CD[25]; + ddata=self.RepD; + #TODO Configuration, String, Hid, and Report -class GoodFETMAXUSBHID(GoodFETMAXUSB): + if desclen>0: + #Reduce desclen if asked for fewer bytes. + desclen=min(reqlen,desclen); + #Send those bytes. + self.writebytes(rEP0FIFO,ddata[0:desclen]); + self.wregAS(rEP0BC,desclen); + 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); +class GoodFETMAXUSBHID(GoodFETMAXUSBDevice): """This is an example HID keyboard driver, loosely based on the MAX3420 examples.""" def hidinit(self): """Initialize a USB HID device.""" + self.usb_disconnect(); self.usb_connect(); + self.hidrun(); def hidrun(self): @@ -555,7 +681,10 @@ class GoodFETMAXUSBHID(GoodFETMAXUSB): SUD=self.readbytes(rSUDFIFO,8); #Parse the SETUP packet - print "Handling a setup packet type 0x%02x" % ord(SUD[bmRequestType]); + print "Handling a setup packet of %s" % self.setup2str(SUD); + + self.OsLastConfigType=ord(SUD[bmRequestType]); + self.typepos=0; setuptype=(ord(SUD[bmRequestType])&0x60); if setuptype==0x00: self.std_request(SUD); @@ -565,27 +694,28 @@ class GoodFETMAXUSBHID(GoodFETMAXUSB): self.vendor_request(SUD); else: print "Unknown request type 0x%02x." % ord(SUD[bmRequestType]) - self.STALL_EP0(); + self.STALL_EP0(SUD); def class_request(self,SUD): """Handle a class request.""" print "Stalling a class request."; - self.STALL_EP0(); + self.STALL_EP0(SUD); def vendor_request(self,SUD): print "Stalling a vendor request."; - self.STALL_EP0(); + self.STALL_EP0(SUD); 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_FEATURE: + # self.rregAS(rFNADDR); + # # 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(); + self.STALL_EP0(SUD); def get_interface(self,SUD): """Handles a setup request for SR_GET_INTERFACE.""" @@ -593,9 +723,10 @@ class GoodFETMAXUSBHID(GoodFETMAXUSB): self.wreg(rEP0FIFO,0); self.wregAS(rEP0BC,1); else: - self.STALL_EP0(); + self.STALL_EP0(SUD); - #Device Descriptor + OsLastConfigType=-1; +#Device Descriptor DD=[0x12, # bLength = 18d 0x01, # bDescriptorType = Device (1) 0x00,0x01, # bcdUSB(L/H) USB spec rev (BCD) @@ -606,7 +737,7 @@ class GoodFETMAXUSBHID(GoodFETMAXUSB): 0x34,0x12, # bcdDevice--1234 1,2,3, # iManufacturer, iProduct, iSerialNumber 1]; - #Configuration Descriptor +#Configuration Descriptor CD=[0x09, # bLength 0x02, # bDescriptorType = Config 0x22,0x00, # wTotalLength(L/H) = 34 bytes @@ -701,41 +832,7 @@ class GoodFETMAXUSBHID(GoodFETMAXUSB): 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(); - 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]) @@ -757,60 +854,90 @@ class GoodFETMAXUSBHID(GoodFETMAXUSB): self.wreg(rEP0FIFO,0x00); #Second byte is always zero. self.wregAS(rEP0BC,2); else: - self.STALL_EP0(); + self.STALL_EP0(SUD); else: - self.STALL_EP0(); - 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(); - if(epirq&bmIN3BAVIRQ): #EN3-IN packet - self.do_IN3(); - - - typephase=0; - typestring=" Python does USB HID!"; + self.STALL_EP0(SUD); + typepos=0; - + typestrings={ + -1 : "Python does USB HID!\n", # Unidentified OS. This is the default typestring. + 0x00 : "OSX Hosts don't recognize Maxim keyboards.\n", # We have to identify as an Apple keyboard to get arround the unknown keyboard error. + 0xA1 : "Python does USB HID on Linux!\n", + 0x81 : " Python does USB HID on Windows!\n", # Windows requires a bit of a delay. Maybe we can watch for a keyboard reset command? + } + def typestring(self): + if self.typestrings.has_key(self.OsLastConfigType): + return self.typestrings[self.OsLastConfigType]; + else: + return self.typestrings[-1]; + # http://www.win.tue.nl/~aeb/linux/kbd/scancodes-14.html + # Escape=0x29 Backsp=0x2A Space=0x2C CapsLock=0x39 Menu=0x65 + keymaps={ + 'en_US' :[ ' abcdefghijklmnopqrstuvwxyz1234567890\n\t -=[]\\\\;\'`,./', + '''    ''', # LeftCtrl + ' ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*() {}?+||:"~<>?', # LeftShift + '', # LeftCtrl & LeftShift + ' abc'], # LeftAlt + 'Dvorak' :[ ' axje.uidchtnmbrl\'poygk,qf;1234567890\n\t []/=\\\\s-`wvz', + '''        ''', # LeftCtrl + ' AXJE UIDCHTNMBRL"POYGK='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 + if type(ascii)!=str: + return (0,0); # Send NoEvent if not passed a character + if ascii==' ': + return (0,0x2C); # space + for modset in self.keymap(): + keycode=modset.find(ascii); + if keycode != -1: + modifier = self.keymap().index(modset) + return (modifier, keycode); + return (0,0); 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; + """Type next letter in buffer.""" + string=self.typestring(); + if self.typepos>=len(string): + self.typeletter(0); # Send NoEvent to indicate key-up + exit(0); + self.typepos=0; # Repeat typestring forever! + # This would be a great place to enable a typethrough mode so the host operator can control the target + else: + if self.usbverbose: + sys.stdout.write(string[self.typepos]); + sys.stdout.flush(); + self.typeletter(string[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); + mod=0; + if type(key)==str: + (mod, key) = self.asc2hid(key); + self.wreg(rEP3INFIFO,mod); self.wreg(rEP3INFIFO,0); - self.wreg(rEP3INFIFO,self.asc2hid(key)); + self.wreg(rEP3INFIFO,key); self.wreg(rEP3INBC,3); def do_IN3(self): """Handle IN3 event.""" #Don't bother clearing interrupt flag, that's done by sending the reply. - self.type_IN3(); + if self.OsLastConfigType != -1: # Wait for some configuration before stuffing keycodes down the pipe + self.type_IN3();