new maxusb library
[goodfet] / client / MAXUSBApp.py
1 # MAXUSBApp.py
2 #
3 # Contains class definition for MAXUSBApp.
4
5 from util import *
6 from Facedancer import *
7 from USB import *
8 from USBDevice import USBDeviceRequest
9
10 class MAXUSBApp(FacedancerApp):
11     app_name = "MAXUSB"
12     app_num = 0x40
13
14     reg_ep0_fifo                    = 0x00
15     reg_ep1_out_fifo                = 0x01
16     reg_ep2_in_fifo                 = 0x02
17     reg_ep3_in_fifo                 = 0x03
18     reg_setup_data_fifo             = 0x04
19     reg_ep0_byte_count              = 0x05
20     reg_ep1_out_byte_count          = 0x06
21     reg_ep2_in_byte_count           = 0x07
22     reg_ep3_in_byte_count           = 0x08
23     reg_ep_stalls                   = 0x09
24     reg_clr_togs                    = 0x0a
25     reg_endpoint_irq                = 0x0b
26     reg_endpoint_interrupt_enable   = 0x0c
27     reg_usb_irq                     = 0x0d
28     reg_usb_interrupt_enable        = 0x0e
29     reg_usb_control                 = 0x0f
30     reg_cpu_control                 = 0x10
31     reg_pin_control                 = 0x11
32     reg_revision                    = 0x12
33     reg_function_address            = 0x13
34     reg_io_pins                     = 0x14
35
36     # bitmask values for reg_endpoint_irq = 0x0b
37     is_setup_data_avail             = 0x20     # SUDAVIRQ
38     is_in3_buffer_avail             = 0x10     # IN3BAVIRQ
39     is_in2_buffer_avail             = 0x08     # IN2BAVIRQ
40     is_out1_data_avail              = 0x04     # OUT1DAVIRQ
41     is_out0_data_avail              = 0x02     # OUT0DAVIRQ
42     is_in0_buffer_avail             = 0x01     # IN0BAVIRQ
43
44     # bitmask values for reg_usb_control = 0x0f
45     usb_control_vbgate              = 0x40
46     usb_control_connect             = 0x08
47
48     # bitmask values for reg_pin_control = 0x11
49     interrupt_level                 = 0x08
50     full_duplex                     = 0x10
51
52     def __init__(self, device, verbose=0):
53         FacedancerApp.__init__(self, device, verbose)
54
55         self.connected_device = None
56
57         self.enable()
58
59         if verbose > 0:
60             rev = self.read_register(self.reg_revision)
61             print(self.app_name, "revision", rev)
62
63         # set duplex and negative INT level (from GoodFEDMAXUSB.py)
64         self.write_register(self.reg_pin_control,
65                 self.full_duplex | self.interrupt_level)
66
67     def init_commands(self):
68         self.read_register_cmd  = FacedancerCommand(self.app_num, 0x00, b'')
69         self.write_register_cmd = FacedancerCommand(self.app_num, 0x00, b'')
70         self.enable_app_cmd     = FacedancerCommand(self.app_num, 0x10, b'')
71         self.ack_cmd            = FacedancerCommand(self.app_num, 0x00, b'\x01')
72
73     def read_register(self, reg_num, ack=False):
74         if self.verbose > 1:
75             print(self.app_name, "reading register 0x%02x" % reg_num)
76
77         self.read_register_cmd.data = bytearray([ reg_num << 3, 0 ])
78         if ack:
79             self.write_register_cmd.data[0] |= 1
80
81         self.device.writecmd(self.read_register_cmd)
82
83         resp = self.device.readcmd()
84
85         if self.verbose > 2:
86             print(self.app_name, "read register 0x%02x has value 0x%02x" %
87                     (reg_num, resp.data[1]))
88
89         return resp.data[1]
90
91     def write_register(self, reg_num, value, ack=False):
92         if self.verbose > 2:
93             print(self.app_name, "writing register 0x%02x with value 0x%02x" %
94                     (reg_num, value))
95
96         self.write_register_cmd.data = bytearray([ (reg_num << 3) | 2, value ])
97         if ack:
98             self.write_register_cmd.data[0] |= 1
99
100         self.device.writecmd(self.write_register_cmd)
101         self.device.readcmd()
102
103     def get_version(self):
104         return self.read_register(self.reg_revision)
105
106     def ack_status_stage(self):
107         if self.verbose > 5:
108             print(self.app_name, "sending ack!")
109
110         self.device.writecmd(self.ack_cmd)
111         self.device.readcmd()
112
113     def connect(self, usb_device):
114         self.write_register(self.reg_usb_control, self.usb_control_vbgate |
115                 self.usb_control_connect)
116
117         self.connected_device = usb_device
118
119         if self.verbose > 0:
120             print(self.app_name, "connected device", self.connected_device.name)
121
122     def disconnect(self):
123         self.write_register(self.reg_usb_control, self.usb_control_vbgate)
124
125         if self.verbose > 0:
126             print(self.app_name, "disconnected device", self.connected_device.name)
127         self.connected_device = None
128
129     def clear_irq_bit(self, reg, bit):
130         self.write_register(reg, bit)
131
132     def read_bytes(self, reg, n):
133         if self.verbose > 2:
134             print(self.app_name, "reading", n, "bytes from register", reg)
135
136         data = bytes([ (reg << 3) ] + ([0] * n))
137         cmd = FacedancerCommand(self.app_num, 0x00, data)
138
139         self.device.writecmd(cmd)
140         resp = self.device.readcmd()
141
142         if self.verbose > 3:
143             print(self.app_name, "read", len(resp.data) - 1, "bytes from register", reg)
144
145         return resp.data[1:]
146
147     def write_bytes(self, reg, data):
148         data = bytes([ (reg << 3) | 3 ]) + data
149         cmd = FacedancerCommand(self.app_num, 0x00, data)
150
151         self.device.writecmd(cmd)
152         self.device.readcmd() # null response
153
154         if self.verbose > 3:
155             print(self.app_name, "wrote", len(data) - 1, "bytes to register", reg)
156
157     # HACK: but given the limitations of the MAX chips, it seems necessary
158     def send_on_endpoint(self, ep_num, data):
159         if ep_num == 0:
160             fifo_reg = self.reg_ep0_fifo
161             bc_reg = self.reg_ep0_byte_count
162         elif ep_num == 2:
163             fifo_reg = self.reg_ep2_in_fifo
164             bc_reg = self.reg_ep2_in_byte_count
165         elif ep_num == 3:
166             fifo_reg = self.reg_ep3_in_fifo
167             bc_reg = self.reg_ep3_in_byte_count
168         else:
169             raise ValueError('endpoint ' + str(ep_num) + ' not supported')
170
171         self.write_bytes(fifo_reg, data)
172         self.write_register(bc_reg, len(data), ack=True)
173
174         if self.verbose > 1:
175             print(self.app_name, "wrote", bytes_as_hex(data), "to endpoint",
176                     ep_num)
177
178     # TODO
179     def read_from_endpoint(self, ep_num):
180         pass
181
182     def stall_ep0(self):
183         if self.verbose > 0:
184             print(self.app_name, "stalling endpoint 0")
185
186         self.write_register(self.reg_ep_stalls, 0x23)
187
188     def service_irqs(self):
189         while True:
190             irq = self.read_register(self.reg_endpoint_irq)
191
192             if self.verbose > 3:
193                 print(self.app_name, "read endpoint irq: 0x%02x" % irq)
194
195             if self.verbose > 2:
196                 if irq & ~ (self.is_in0_buffer_avail \
197                         | self.is_in2_buffer_avail | self.is_in3_buffer_avail):
198                     print(self.app_name, "notable irq: 0x%02x" % irq)
199
200             if irq & self.is_setup_data_avail:
201                 self.clear_irq_bit(self.reg_endpoint_irq, self.is_setup_data_avail)
202
203                 b = self.read_bytes(self.reg_setup_data_fifo, 8)
204                 req = USBDeviceRequest(b)
205                 self.connected_device.handle_request(req)
206
207             if irq & self.is_out1_data_avail:
208                 data = b'' # TODO: read from out1
209                 self.connected_device.handle_data_available(1, data)
210                 self.clear_irq_bit(self.reg_endpoint_irq, self.is_out1_data_avail)
211
212             if irq & self.is_in2_buffer_avail:
213                 self.connected_device.handle_buffer_available(2)
214
215             if irq & self.is_in3_buffer_avail:
216                 self.connected_device.handle_buffer_available(3)
217