1 | /* -*- c++ -*- */
|
---|
2 | /*-----------------------------------------------------------------------------
|
---|
3 | * Common USB code for FX2
|
---|
4 | *-----------------------------------------------------------------------------
|
---|
5 | * Code taken from USRP2 firmware (GNU Radio Project), version 3.0.2,
|
---|
6 | * Copyright 2003 Free Software Foundation, Inc.
|
---|
7 | *-----------------------------------------------------------------------------
|
---|
8 | * This code is part of usbjtag. usbjtag is free software; you can redistribute
|
---|
9 | * it and/or modify it under the terms of the GNU General Public License as
|
---|
10 | * published by the Free Software Foundation; either version 2 of the License,
|
---|
11 | * or (at your option) any later version. usbjtag is distributed in the hope
|
---|
12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
---|
13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | * GNU General Public License for more details. You should have received a
|
---|
15 | * copy of the GNU General Public License along with this program in the file
|
---|
16 | * COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
---|
17 | * St, Fifth Floor, Boston, MA 02110-1301 USA
|
---|
18 | *-----------------------------------------------------------------------------
|
---|
19 | */
|
---|
20 |
|
---|
21 | #include "usb_common.h"
|
---|
22 | #include "fx2regs.h"
|
---|
23 | #include "syncdelay.h"
|
---|
24 | #include "fx2utils.h"
|
---|
25 | #include "isr.h"
|
---|
26 | #include "usb_descriptors.h"
|
---|
27 | #include "usb_requests.h"
|
---|
28 |
|
---|
29 | extern xdata char str0[];
|
---|
30 | extern xdata char str1[];
|
---|
31 | extern xdata char str2[];
|
---|
32 | extern xdata char str3[];
|
---|
33 | extern xdata char str4[];
|
---|
34 | extern xdata char str5[];
|
---|
35 |
|
---|
36 | volatile bit _usb_got_SUDAV;
|
---|
37 |
|
---|
38 | unsigned char _usb_config = 0;
|
---|
39 | unsigned char _usb_alt_setting = 0; // FIXME really 1/interface
|
---|
40 |
|
---|
41 | xdata unsigned char *current_device_descr;
|
---|
42 | xdata unsigned char *current_devqual_descr;
|
---|
43 | xdata unsigned char *current_config_descr;
|
---|
44 | xdata unsigned char *other_config_descr;
|
---|
45 |
|
---|
46 | static void
|
---|
47 | setup_descriptors (void)
|
---|
48 | {
|
---|
49 | if (USBCS & bmHSM){ // high speed mode
|
---|
50 | current_device_descr = high_speed_device_descr;
|
---|
51 | current_devqual_descr = high_speed_devqual_descr;
|
---|
52 | current_config_descr = high_speed_config_descr;
|
---|
53 | other_config_descr = full_speed_config_descr;
|
---|
54 | EP8AUTOINLENH = 0x02; SYNCDELAY; // Size in bytes of the IN data automatically commited (512 bytes here)
|
---|
55 | EP8AUTOINLENL = 0x00; SYNCDELAY; // Can use signal PKTEND if you want to commit a shorter packet
|
---|
56 | }
|
---|
57 | else {
|
---|
58 | current_device_descr = full_speed_device_descr;
|
---|
59 | current_devqual_descr = full_speed_devqual_descr;
|
---|
60 | current_config_descr = full_speed_config_descr;
|
---|
61 | other_config_descr = high_speed_config_descr;
|
---|
62 | EP8AUTOINLENH = 0x00; SYNCDELAY; // Size in bytes of the IN data automatically commited (64 bytes here)
|
---|
63 | EP8AUTOINLENL = 0x40; SYNCDELAY; // Can use signal PKTEND if you want to commit a shorter packet
|
---|
64 | }
|
---|
65 |
|
---|
66 | // whack the type fields
|
---|
67 | // FIXME, may not be required.
|
---|
68 | // current_config_descr[1] = DT_CONFIG;
|
---|
69 | // other_config_descr[1] = DT_OTHER_SPEED;
|
---|
70 | }
|
---|
71 |
|
---|
72 | static void
|
---|
73 | isr_SUDAV (void) interrupt
|
---|
74 | {
|
---|
75 | clear_usb_irq ();
|
---|
76 | _usb_got_SUDAV = 1;
|
---|
77 | }
|
---|
78 |
|
---|
79 | static void
|
---|
80 | isr_USBRESET (void) interrupt
|
---|
81 | {
|
---|
82 | clear_usb_irq ();
|
---|
83 | setup_descriptors ();
|
---|
84 | }
|
---|
85 |
|
---|
86 | static void
|
---|
87 | isr_HIGHSPEED (void) interrupt
|
---|
88 | {
|
---|
89 | clear_usb_irq ();
|
---|
90 | setup_descriptors ();
|
---|
91 | }
|
---|
92 |
|
---|
93 | void
|
---|
94 | usb_install_handlers (void)
|
---|
95 | {
|
---|
96 | setup_descriptors (); // ensure that they're set before use
|
---|
97 |
|
---|
98 | hook_uv (UV_SUDAV, (unsigned short) isr_SUDAV);
|
---|
99 | hook_uv (UV_USBRESET, (unsigned short) isr_USBRESET);
|
---|
100 | hook_uv (UV_HIGHSPEED, (unsigned short) isr_HIGHSPEED);
|
---|
101 |
|
---|
102 | USBIE = bmSUDAV | bmURES | bmHSGRANT;
|
---|
103 | }
|
---|
104 |
|
---|
105 | // On the FX2 the only plausible endpoints are 0, 1, 2, 4, 6, 8
|
---|
106 | // This doesn't check to see that they're enabled
|
---|
107 |
|
---|
108 | unsigned char
|
---|
109 | plausible_endpoint (unsigned char ep)
|
---|
110 | {
|
---|
111 | ep &= ~0x80; // ignore direction bit
|
---|
112 |
|
---|
113 | if (ep > 8)
|
---|
114 | return 0;
|
---|
115 |
|
---|
116 | if (ep == 1)
|
---|
117 | return 1;
|
---|
118 |
|
---|
119 | return (ep & 0x1) == 0; // must be even
|
---|
120 | }
|
---|
121 |
|
---|
122 | // return pointer to control and status register for endpoint.
|
---|
123 | // only called with plausible_endpoints
|
---|
124 |
|
---|
125 | xdata volatile unsigned char *
|
---|
126 | epcs (unsigned char ep)
|
---|
127 | {
|
---|
128 | if (ep == 0x01) // ep1 has different in and out CS regs
|
---|
129 | return EP1OUTCS;
|
---|
130 |
|
---|
131 | if (ep == 0x81)
|
---|
132 | return EP1INCS;
|
---|
133 |
|
---|
134 | ep &= ~0x80; // ignore direction bit
|
---|
135 |
|
---|
136 | if (ep == 0x00) // ep0
|
---|
137 | return EP0CS;
|
---|
138 |
|
---|
139 | return EP2CS + (ep >> 1); // 2, 4, 6, 8 are consecutive
|
---|
140 | }
|
---|
141 |
|
---|
142 | void
|
---|
143 | usb_handle_setup_packet (void)
|
---|
144 | {
|
---|
145 | _usb_got_SUDAV = 0;
|
---|
146 |
|
---|
147 | // handle the standard requests...
|
---|
148 |
|
---|
149 | switch (bRequestType & bmRT_TYPE_MASK){
|
---|
150 |
|
---|
151 | case bmRT_TYPE_CLASS:
|
---|
152 | case bmRT_TYPE_RESERVED:
|
---|
153 | fx2_stall_ep0 (); // we don't handle these. indicate error
|
---|
154 | break;
|
---|
155 |
|
---|
156 | case bmRT_TYPE_VENDOR:
|
---|
157 | // call the application code.
|
---|
158 | // If it handles the command it returns non-zero
|
---|
159 |
|
---|
160 | if (!app_vendor_cmd ())
|
---|
161 | fx2_stall_ep0 ();
|
---|
162 | break;
|
---|
163 |
|
---|
164 | case bmRT_TYPE_STD:
|
---|
165 | // these are the standard requests...
|
---|
166 |
|
---|
167 | if ((bRequestType & bmRT_DIR_MASK) == bmRT_DIR_IN){
|
---|
168 |
|
---|
169 | ////////////////////////////////////
|
---|
170 | // handle the IN requests
|
---|
171 | ////////////////////////////////////
|
---|
172 |
|
---|
173 | switch (bRequest){
|
---|
174 |
|
---|
175 | case RQ_GET_CONFIG:
|
---|
176 | EP0BUF[0] = _usb_config; // FIXME app should handle
|
---|
177 | EP0BCH = 0;
|
---|
178 | EP0BCL = 1;
|
---|
179 | break;
|
---|
180 |
|
---|
181 | // --------------------------------
|
---|
182 |
|
---|
183 | case RQ_GET_INTERFACE:
|
---|
184 | EP0BUF[0] = _usb_alt_setting; // FIXME app should handle
|
---|
185 | EP0BCH = 0;
|
---|
186 | EP0BCL = 1;
|
---|
187 | break;
|
---|
188 |
|
---|
189 | // --------------------------------
|
---|
190 |
|
---|
191 | case RQ_GET_DESCR:
|
---|
192 | switch (wValueH){
|
---|
193 |
|
---|
194 | case DT_DEVICE:
|
---|
195 | SUDPTRH = MSB (current_device_descr);
|
---|
196 | SUDPTRL = LSB (current_device_descr);
|
---|
197 | break;
|
---|
198 |
|
---|
199 | case DT_DEVQUAL:
|
---|
200 | SUDPTRH = MSB (current_devqual_descr);
|
---|
201 | SUDPTRL = LSB (current_devqual_descr);
|
---|
202 | break;
|
---|
203 |
|
---|
204 | case DT_CONFIG:
|
---|
205 | if (0 && wValueL != 1) // FIXME only a single configuration
|
---|
206 | fx2_stall_ep0 ();
|
---|
207 | else {
|
---|
208 | SUDPTRH = MSB (current_config_descr);
|
---|
209 | SUDPTRL = LSB (current_config_descr);
|
---|
210 | }
|
---|
211 | break;
|
---|
212 |
|
---|
213 | case DT_OTHER_SPEED:
|
---|
214 | if (0 && wValueL != 1) // FIXME only a single configuration
|
---|
215 | fx2_stall_ep0 ();
|
---|
216 | else {
|
---|
217 | SUDPTRH = MSB (other_config_descr);
|
---|
218 | SUDPTRL = LSB (other_config_descr);
|
---|
219 | }
|
---|
220 | break;
|
---|
221 |
|
---|
222 | case DT_STRING:
|
---|
223 | if (wValueL >= nstring_descriptors)
|
---|
224 | fx2_stall_ep0 ();
|
---|
225 | else {
|
---|
226 | xdata char *p = string_descriptors[wValueL];
|
---|
227 | SUDPTRH = MSB (p);
|
---|
228 | SUDPTRL = LSB (p);
|
---|
229 | }
|
---|
230 | break;
|
---|
231 |
|
---|
232 | default:
|
---|
233 | fx2_stall_ep0 (); // invalid request
|
---|
234 | break;
|
---|
235 | }
|
---|
236 | break;
|
---|
237 |
|
---|
238 | // --------------------------------
|
---|
239 |
|
---|
240 | case RQ_GET_STATUS:
|
---|
241 | switch (bRequestType & bmRT_RECIP_MASK){
|
---|
242 | case bmRT_RECIP_DEVICE:
|
---|
243 | EP0BUF[0] = 0;
|
---|
244 | EP0BUF[1] = 0;
|
---|
245 | EP0BCH = 0;
|
---|
246 | EP0BCL = 2;
|
---|
247 | break;
|
---|
248 |
|
---|
249 | case bmRT_RECIP_INTERFACE:
|
---|
250 | EP0BUF[0] = 0;
|
---|
251 | EP0BUF[1] = 0;
|
---|
252 | EP0BCH = 0;
|
---|
253 | EP0BCL = 2;
|
---|
254 | break;
|
---|
255 |
|
---|
256 | case bmRT_RECIP_ENDPOINT:
|
---|
257 | if (plausible_endpoint (wIndexL)){
|
---|
258 | EP0BUF[0] = *epcs (wIndexL) & bmEPSTALL;
|
---|
259 | EP0BUF[1] = 0;
|
---|
260 | EP0BCH = 0;
|
---|
261 | EP0BCL = 2;
|
---|
262 | }
|
---|
263 | else
|
---|
264 | fx2_stall_ep0 ();
|
---|
265 | break;
|
---|
266 |
|
---|
267 | default:
|
---|
268 | fx2_stall_ep0 ();
|
---|
269 | break;
|
---|
270 | }
|
---|
271 | break;
|
---|
272 |
|
---|
273 | // --------------------------------
|
---|
274 |
|
---|
275 | case RQ_SYNCH_FRAME: // not implemented
|
---|
276 | default:
|
---|
277 | fx2_stall_ep0 ();
|
---|
278 | break;
|
---|
279 | }
|
---|
280 | }
|
---|
281 |
|
---|
282 | else {
|
---|
283 |
|
---|
284 | ////////////////////////////////////
|
---|
285 | // handle the OUT requests
|
---|
286 | ////////////////////////////////////
|
---|
287 |
|
---|
288 | switch (bRequest){
|
---|
289 |
|
---|
290 | case RQ_SET_CONFIG:
|
---|
291 | IOE &= ~(1 << 6);
|
---|
292 | _usb_config = wValueL; // FIXME app should handle
|
---|
293 | break;
|
---|
294 |
|
---|
295 | case RQ_SET_INTERFACE:
|
---|
296 | _usb_alt_setting = wValueL; // FIXME app should handle
|
---|
297 | break;
|
---|
298 |
|
---|
299 | // --------------------------------
|
---|
300 |
|
---|
301 | case RQ_CLEAR_FEATURE:
|
---|
302 | switch (bRequestType & bmRT_RECIP_MASK){
|
---|
303 |
|
---|
304 | case bmRT_RECIP_DEVICE:
|
---|
305 | switch (wValueL){
|
---|
306 | case FS_DEV_REMOTE_WAKEUP:
|
---|
307 | default:
|
---|
308 | fx2_stall_ep0 ();
|
---|
309 | }
|
---|
310 | break;
|
---|
311 |
|
---|
312 | case bmRT_RECIP_ENDPOINT:
|
---|
313 | if (wValueL == FS_ENDPOINT_HALT && plausible_endpoint (wIndexL)){
|
---|
314 | *epcs (wIndexL) &= ~bmEPSTALL;
|
---|
315 | fx2_reset_data_toggle (wIndexL);
|
---|
316 | }
|
---|
317 | else
|
---|
318 | fx2_stall_ep0 ();
|
---|
319 | break;
|
---|
320 |
|
---|
321 | default:
|
---|
322 | fx2_stall_ep0 ();
|
---|
323 | break;
|
---|
324 | }
|
---|
325 | break;
|
---|
326 |
|
---|
327 | // --------------------------------
|
---|
328 |
|
---|
329 | case RQ_SET_FEATURE:
|
---|
330 | switch (bRequestType & bmRT_RECIP_MASK){
|
---|
331 |
|
---|
332 | case bmRT_RECIP_DEVICE:
|
---|
333 | switch (wValueL){
|
---|
334 | case FS_TEST_MODE:
|
---|
335 | // hardware handles this after we complete SETUP phase handshake
|
---|
336 | break;
|
---|
337 |
|
---|
338 | case FS_DEV_REMOTE_WAKEUP:
|
---|
339 | default:
|
---|
340 | fx2_stall_ep0 ();
|
---|
341 | break;
|
---|
342 | }
|
---|
343 | }
|
---|
344 | break;
|
---|
345 |
|
---|
346 | case bmRT_RECIP_ENDPOINT:
|
---|
347 | switch (wValueL){
|
---|
348 | case FS_ENDPOINT_HALT:
|
---|
349 | if (plausible_endpoint (wIndexL))
|
---|
350 | *epcs (wIndexL) |= bmEPSTALL;
|
---|
351 | else
|
---|
352 | fx2_stall_ep0 ();
|
---|
353 | break;
|
---|
354 |
|
---|
355 | default:
|
---|
356 | fx2_stall_ep0 ();
|
---|
357 | break;
|
---|
358 | }
|
---|
359 | break;
|
---|
360 |
|
---|
361 | // --------------------------------
|
---|
362 |
|
---|
363 | case RQ_SET_ADDRESS: // handled by fx2 hardware
|
---|
364 | case RQ_SET_DESCR: // not implemented
|
---|
365 | default:
|
---|
366 | fx2_stall_ep0 ();
|
---|
367 | }
|
---|
368 |
|
---|
369 | }
|
---|
370 | break;
|
---|
371 |
|
---|
372 | } // bmRT_TYPE_MASK
|
---|
373 |
|
---|
374 | // ack handshake phase of device request
|
---|
375 | EP0CS |= bmHSNAK;
|
---|
376 | }
|
---|