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