USB HID keyboard client for the MAX3420.
authortravisutk <travisutk@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Sun, 26 Feb 2012 03:58:09 +0000 (03:58 +0000)
committertravisutk <travisutk@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Sun, 26 Feb 2012 03:58:09 +0000 (03:58 +0000)
The entire USB device is defined in Python, for easy fuzzing.

git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@1100 12e2690d-a6be-4b82-a7b7-67c4a43b65c8

client/GoodFETMAXUSB.py [new file with mode: 0644]
client/goodfet.maxusb [new file with mode: 0755]
client/goodfet.maxusbhid [new file with mode: 0755]
client/goodfet.nrf

diff --git a/client/GoodFETMAXUSB.py b/client/GoodFETMAXUSB.py
new file mode 100644 (file)
index 0000000..bf257c8
--- /dev/null
@@ -0,0 +1,446 @@
+#!/usr/bin/env python
+# GoodFET Client Library for Maxim USB Chips.
+# 
+# (C) 2012 Travis Goodspeed <travis at radiantmachines.com>
+#
+# This code is being rewritten and refactored.  You've been warned!
+
+import sys, time, string, cStringIO, struct, glob, os;
+
+from GoodFET import GoodFET;
+
+#Handy registers.
+rEP0FIFO=0
+rEP1OUTFIFO=1
+rEP2INFIFO=2
+rEP3INFIFO=3
+rSUDFIFO=4
+rEP0BC=5
+rEP1OUTBC=6
+rEP2INBC=7
+rEP3INBC=8
+rEPSTALLS=9
+rCLRTOGS=10
+rEPIRQ=11
+rEPIEN=12
+rUSBIRQ=13
+rUSBIEN=14
+rUSBCTL=15
+rCPUCTL=16
+rPINCTL=17
+rREVISION=18
+rFNADDR=19
+rIOPINS=20
+
+# R11 EPIRQ register bits
+bmSUDAVIRQ =0x20
+bmIN3BAVIRQ =0x10
+bmIN2BAVIRQ =0x08
+bmOUT1DAVIRQ= 0x04
+bmOUT0DAVIRQ= 0x02
+bmIN0BAVIRQ =0x01
+
+# R12 EPIEN register bits
+bmSUDAVIE   =0x20
+bmIN3BAVIE  =0x10
+bmIN2BAVIE  =0x08
+bmOUT1DAVIE =0x04
+bmOUT0DAVIE =0x02
+bmIN0BAVIE  =0x01
+
+
+# ************************
+# Standard USB Requests
+SR_GET_STATUS          =0x00   # Get Status
+SR_CLEAR_FEATURE       =0x01   # Clear Feature
+SR_RESERVED            =0x02   # Reserved
+SR_SET_FEATURE         =0x03   # Set Feature
+SR_SET_ADDRESS         =0x05   # Set Address
+SR_GET_DESCRIPTOR      =0x06   # Get Descriptor
+SR_SET_DESCRIPTOR      =0x07   # Set Descriptor
+SR_GET_CONFIGURATION   =0x08   # Get Configuration
+SR_SET_CONFIGURATION   =0x09   # Set Configuration
+SR_GET_INTERFACE       =0x0a   # Get Interface
+SR_SET_INTERFACE       =0x0b   # Set Interface
+
+# Get Descriptor codes 
+GD_DEVICE              =0x01   # Get device descriptor: Device
+GD_CONFIGURATION       =0x02   # Get device descriptor: Configuration
+GD_STRING              =0x03   # Get device descriptor: String
+GD_HID                 =0x21   # Get descriptor: HID
+GD_REPORT              =0x22   # Get descriptor: Report
+
+# SETUP packet offsets
+bmRequestType           =0
+bRequest                       =1
+wValueL                        =2
+wValueH                        =3
+wIndexL                        =4
+wIndexH                        =5
+wLengthL               =6
+wLengthH               =7
+
+# HID bRequest values
+GET_REPORT             =1
+GET_IDLE               =2
+GET_PROTOCOL            =3
+SET_REPORT             =9
+SET_IDLE               =0x0A
+SET_PROTOCOL            =0x0B
+INPUT_REPORT            =1
+
+
+
+
+class GoodFETMAXUSB(GoodFET):
+    MAXUSBAPP=0x40;
+    def MAXUSBsetup(self):
+        """Move the FET into the MAXUSB application."""
+        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.
+        
+    def MAXUSBtrans8(self,byte):
+        """Read and write 8 bits by MAXUSB."""
+        data=self.MAXUSBtrans([byte]);
+        return ord(data[0]);
+    
+    def MAXUSBtrans(self,data):
+        """Exchange data by MAXUSB."""
+        self.data=data;
+        self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
+        return self.data;
+
+    def rreg(self,reg):
+        """Peek 8 bits from a register."""
+        data=[reg<<3,0];
+        self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
+        return ord(self.data[1]);
+    def rregAS(self,reg):
+        """Peek 8 bits from a register, setting AS."""
+        data=[(reg<<3)|1,0];
+        self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
+        return ord(self.data[1]);
+    def wreg(self,reg,value):
+        """Poke 8 bits into a register."""
+        data=[(reg<<3)|2,value];
+        self.writecmd(self.MAXUSBAPP,0x00,len(data),data);        
+        return value;
+    def wregAS(self,reg,value):
+        """Poke 8 bits into a register, setting AS."""
+        data=[(reg<<3)|3,value];
+        self.writecmd(self.MAXUSBAPP,0x00,len(data),data);        
+        return value;
+    def readbytes(self,reg,length):
+        """Peek some bytes from a register."""
+        data=[(reg<<3)]+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));
+        print "GET %02x==%s" % (reg,ashex);
+        return toret;
+    def writebytes(self,reg,tosend):
+        """Poke some bytes into a register."""
+        data="";
+        if type(tosend)==str:
+            data=chr((reg<<3)|2)+tosend;
+        else:
+            data=[(reg<<3)|2]+tosend;
+            ashex="";
+            for foo in tosend:
+                ashex=ashex+(" %02x"%foo);
+            print "PUT %02x:=%s" % (reg,ashex)
+        self.writecmd(self.MAXUSBAPP,0x00,len(data),data);
+    def usb_connect(self):
+        """Connect the USB port."""
+        
+        #disconnect D+ pullup if host turns off VBUS
+        self.wreg(rUSBCTL,0x48);
+    def STALL_EP0(self):
+        """Stall for an unknown event."""
+        print "Stalling.";
+        self.wreg(rEPSTALLS,0x23); #All three stall bits.
+    def SETBIT(self,reg,val):
+        """Set a bit in a register."""
+        self.wreg(reg,self.rreg(reg)|val);
+class GoodFETMAXUSBHID(GoodFETMAXUSB):
+    """This is an example HID keyboard driver, loosely based on the
+    MAX3420 examples."""
+    def hidinit(self):
+        """Initialize a USB HID device."""
+        self.usb_connect();
+        self.hidrun();
+        
+    def hidrun(self):
+        """Main loop of the USB HID emulator."""
+        print "Starting a HID 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 type 0x%02x" % ord(SUD[bmRequestType]);
+        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();
+    def class_request(self,SUD):
+        """Handle a class request."""
+        print "Stalling a class request.";
+        self.STALL_EP0();
+    def vendor_request(self,SUD):
+        print "Stalling a vendor request.";
+        self.STALL_EP0();
+    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();
+    
+    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();
+    
+    #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
+       0x6A,0x0B,              # idVendor(L/H)--Maxim is 0B6A
+       0x46,0x53,              # idProduct(L/H)--5346
+       0x34,0x12,              # bcdDevice--1234
+       1,2,3,                  # iManufacturer, iProduct, iSerialNumber
+       1];
+    #Configuration Descriptor
+    CD=[0x09,                  # bLength
+       0x02,                   # bDescriptorType = Config
+       0x22,0x00,              # wTotalLength(L/H) = 34 bytes
+       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
+       0x01,                   # bNum Endpoints
+       0x03,                   # bInterfaceClass = HID
+       0x00,0x00,              # bInterfaceSubClass, bInterfaceProtocol
+       0x00,                   # 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)             
+       0x03,                   # 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();
+    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();
+        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!";
+    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 event."""
+        #Don't bother clearing interrupt flag, that's done by sending the reply.
+        self.type_IN3();
+        
diff --git a/client/goodfet.maxusb b/client/goodfet.maxusb
new file mode 100755 (executable)
index 0000000..5b7372c
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+#GoodFET MAXIM MAX3421 and MAX3420 Client
+#by Travis Goodspeed
+
+import sys;
+import binascii;
+import array;
+
+from GoodFETMAXUSB import GoodFETMAXUSB;
+
+if(len(sys.argv)==1):
+    print "Usage: %s verb [objects]\n" % sys.argv[0];
+    print "%s info" % sys.argv[0];
+    print "%s iotest" % sys.argv[0];
+    print "%s peek 0x$start [0x$stop]" % sys.argv[0];
+    print "%s poke 0x$adr 0x$val" % sys.argv[0];
+    sys.exit();
+
+#Initialize FET and set baud rate
+client=GoodFETMAXUSB();
+client.serInit()
+
+
+client.MAXUSBsetup();
+
+if(sys.argv[1]=="regs"):
+    for adr in range(9,21): #*1024):
+        val=client.rreg(adr);
+        print "r%02i:=%02x" % (adr,val);
+if(sys.argv[1]=="iotest"):
+    while 1:
+        client.wreg(20,client.rreg(20)>>4);
+if(sys.argv[1]=="peek"):
+    print "TODO";
+if(sys.argv[1]=="poke"):
+    print "TODO";
diff --git a/client/goodfet.maxusbhid b/client/goodfet.maxusbhid
new file mode 100755 (executable)
index 0000000..cc355f7
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+#GoodFET MAXIM MAX3421 and MAX3420 Client
+#by Travis Goodspeed
+
+import sys;
+import binascii;
+import array;
+
+from GoodFETMAXUSB import GoodFETMAXUSBHID;
+
+#Initialize FET and set baud rate
+client=GoodFETMAXUSBHID();
+client.serInit()
+
+
+client.MAXUSBsetup();
+client.hidinit();
+
index 6b00081..42f3b72 100755 (executable)
@@ -89,7 +89,6 @@ def printmspacket(packet,offset=1):
             letter=ord(',');
         elif ct[9]==0x37:
             letter=ord('.');
-        
         else:
             print "Unknown character 0x%02x." % ct[9];
             letter=ord('?');