Imported Upstream version 3.0
[debian/gnuradio] / usrp / firmware / src / usrp2 / usrp_main.c
1 /* 
2  * USRP - Universal Software Radio Peripheral
3  *
4  * Copyright (C) 2003,2004 Free Software Foundation, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Boston, MA  02110-1301  USA
19  */
20
21 #include "usrp_common.h"
22 #include "usrp_commands.h"
23 #include "fpga.h"
24 #include "usrp_gpif_inline.h"
25 #include "timer.h"
26 #include "i2c.h"
27 #include "isr.h"
28 #include "usb_common.h"
29 #include "fx2utils.h"
30 #include "usrp_globals.h"
31 #include "usrp_i2c_addr.h"
32 #include <string.h>
33 #include "spi.h"
34 #include "eeprom_io.h"
35 #include "usb_descriptors.h"
36
37 /*
38  * offsets into boot eeprom for configuration values
39  */
40 #define HW_REV_OFFSET             5
41 #define SERIAL_NO_OFFSET        248
42 #define SERIAL_NO_LEN             8
43
44
45 #define bRequestType    SETUPDAT[0]
46 #define bRequest        SETUPDAT[1]
47 #define wValueL         SETUPDAT[2]
48 #define wValueH         SETUPDAT[3]
49 #define wIndexL         SETUPDAT[4]
50 #define wIndexH         SETUPDAT[5]
51 #define wLengthL        SETUPDAT[6]
52 #define wLengthH        SETUPDAT[7]
53
54
55 unsigned char g_tx_enable = 0;
56 unsigned char g_rx_enable = 0;
57 unsigned char g_rx_overrun = 0;
58 unsigned char g_tx_underrun = 0;
59
60 /*
61  * the host side fpga loader code pushes an MD5 hash of the bitstream
62  * into hash1.
63  */
64 #define   USRP_HASH_SIZE      16
65 xdata at USRP_HASH_SLOT_1_ADDR unsigned char hash1[USRP_HASH_SIZE];
66
67 static void
68 get_ep0_data (void)
69 {
70   EP0BCL = 0;                   // arm EP0 for OUT xfer.  This sets the busy bit
71
72   while (EP0CS & bmEPBUSY)      // wait for busy to clear
73     ;
74 }
75
76 /*
77  * Handle our "Vendor Extension" commands on endpoint 0.
78  * If we handle this one, return non-zero.
79  */
80 unsigned char
81 app_vendor_cmd (void)
82 {
83   if (bRequestType == VRT_VENDOR_IN){
84
85     /////////////////////////////////
86     //    handle the IN requests
87     /////////////////////////////////
88
89     switch (bRequest){
90
91     case VRQ_GET_STATUS:
92       switch (wIndexL){
93
94       case GS_TX_UNDERRUN:
95         EP0BUF[0] = g_tx_underrun;
96         g_tx_underrun = 0;
97         EP0BCH = 0;
98         EP0BCL = 1;
99         break;
100
101       case GS_RX_OVERRUN:
102         EP0BUF[0] = g_rx_overrun;
103         g_rx_overrun = 0;
104         EP0BCH = 0;
105         EP0BCL = 1;
106         break;
107
108       default:
109         return 0;
110       }
111       break;
112
113     case VRQ_I2C_READ:
114       if (!i2c_read (wValueL, EP0BUF, wLengthL))
115         return 0;
116
117       EP0BCH = 0;
118       EP0BCL = wLengthL;
119       break;
120       
121     case VRQ_SPI_READ:
122       if (!spi_read (wValueH, wValueL, wIndexH, wIndexL, EP0BUF, wLengthL))
123         return 0;
124
125       EP0BCH = 0;
126       EP0BCL = wLengthL;
127       break;
128
129     default:
130       return 0;
131     }
132   }
133
134   else if (bRequestType == VRT_VENDOR_OUT){
135
136     /////////////////////////////////
137     //    handle the OUT requests
138     /////////////////////////////////
139
140     switch (bRequest){
141
142     case VRQ_SET_LED:
143       switch (wIndexL){
144       case 0:
145         set_led_0 (wValueL);
146         break;
147         
148       case 1:
149         set_led_1 (wValueL);
150         break;
151         
152       default:
153         return 0;
154       }
155       break;
156       
157     case VRQ_FPGA_LOAD:
158       switch (wIndexL){                 // sub-command
159       case FL_BEGIN:
160         return fpga_load_begin ();
161         
162       case FL_XFER:
163         get_ep0_data ();
164         return fpga_load_xfer (EP0BUF, EP0BCL);
165         
166       case FL_END:
167         return fpga_load_end ();
168         
169       default:
170         return 0;
171       }
172       break;
173       
174
175     case VRQ_FPGA_SET_RESET:
176       fpga_set_reset (wValueL);
177       break;
178       
179     case VRQ_FPGA_SET_TX_ENABLE:
180       fpga_set_tx_enable (wValueL);
181       break;
182       
183     case VRQ_FPGA_SET_RX_ENABLE:
184       fpga_set_rx_enable (wValueL);
185       break;
186
187     case VRQ_FPGA_SET_TX_RESET:
188       fpga_set_tx_reset (wValueL);
189       break;
190       
191     case VRQ_FPGA_SET_RX_RESET:
192       fpga_set_rx_reset (wValueL);
193       break;
194
195     case VRQ_I2C_WRITE:
196       get_ep0_data ();
197       if (!i2c_write (wValueL, EP0BUF, EP0BCL))
198         return 0;
199       break;
200
201     case VRQ_SPI_WRITE:
202       get_ep0_data ();
203       if (!spi_write (wValueH, wValueL, wIndexH, wIndexL, EP0BUF, EP0BCL))
204         return 0;
205       break;
206
207     default:
208       return 0;
209     }
210
211   }
212   else
213     return 0;    // invalid bRequestType
214
215   return 1;
216 }
217
218
219
220 static void
221 main_loop (void)
222 {
223   setup_flowstate_common ();
224
225   while (1){
226
227     if (usb_setup_packet_avail ())
228       usb_handle_setup_packet ();
229     
230   
231     if (GPIFTRIG & bmGPIF_IDLE){
232
233       // OK, GPIF is idle.  Let's try to give it some work.
234
235       // First check for underruns and overruns
236
237       if (UC_BOARD_HAS_FPGA && (USRP_PA & (bmPA_TX_UNDERRUN | bmPA_RX_OVERRUN))){
238       
239         // record the under/over run
240         if (USRP_PA & bmPA_TX_UNDERRUN)
241           g_tx_underrun = 1;
242
243         if (USRP_PA & bmPA_RX_OVERRUN)
244           g_rx_overrun = 1;
245
246         // tell the FPGA to clear the flags
247         fpga_clear_flags ();
248       }
249
250       // Next see if there are any "OUT" packets waiting for our attention,
251       // and if so, if there's room in the FPGA's FIFO for them.
252
253       if (g_tx_enable && !(EP24FIFOFLGS & 0x02)){  // USB end point fifo is not empty...
254
255         if (fpga_has_room_for_packet ()){          // ... and FPGA has room for packet
256
257           GPIFTCB1 = 0x01;      SYNCDELAY;
258           GPIFTCB0 = 0x00;      SYNCDELAY;
259
260           setup_flowstate_write ();
261
262           SYNCDELAY;
263           GPIFTRIG = bmGPIF_EP2_START | bmGPIF_WRITE;   // start the xfer
264           SYNCDELAY;
265
266           while (!(GPIFTRIG & bmGPIF_IDLE)){
267             // wait for the transaction to complete
268           }
269         }
270       }
271
272       // See if there are any requests for "IN" packets, and if so
273       // whether the FPGA's got any packets for us.
274
275       if (g_rx_enable && !(EP6CS & bmEPFULL)){  // USB end point fifo is not full...
276
277         if (fpga_has_packet_avail ()){          // ... and FPGA has packet available
278
279           GPIFTCB1 = 0x01;      SYNCDELAY;
280           GPIFTCB0 = 0x00;      SYNCDELAY;
281
282           setup_flowstate_read ();
283
284           SYNCDELAY;
285           GPIFTRIG = bmGPIF_EP6_START | bmGPIF_READ;    // start the xfer
286           SYNCDELAY;
287
288           while (!(GPIFTRIG & bmGPIF_IDLE)){
289             // wait for the transaction to complete
290           }
291
292           SYNCDELAY;
293           INPKTEND = 6; // tell USB we filled buffer (6 is our endpoint num)
294         }
295       }
296     }
297   }
298 }
299
300
301 /*
302  * called at 100 Hz from timer2 interrupt
303  *
304  * Toggle led 0
305  */
306 void
307 isr_tick (void) interrupt
308 {
309   static unsigned char  count = 1;
310   
311   if (--count == 0){
312     count = 50;
313     USRP_LED_REG ^= bmLED0;
314   }
315
316   clear_timer_irq ();
317 }
318
319 /*
320  * Read h/w rev code and serial number out of boot eeprom and
321  * patch the usb descriptors with the values.
322  */
323 void
324 patch_usb_descriptors(void)
325 {
326   static xdata unsigned char hw_rev;
327   static xdata unsigned char serial_no[8];
328   unsigned char i;
329
330   eeprom_read(I2C_ADDR_BOOT, HW_REV_OFFSET, &hw_rev, 1);        // LSB of device id
331   usb_desc_hw_rev_binary_patch_location_0[0] = hw_rev;
332   usb_desc_hw_rev_binary_patch_location_1[0] = hw_rev;
333   usb_desc_hw_rev_ascii_patch_location_0[0] = hw_rev + '0';     // FIXME if we get > 9
334
335   eeprom_read(I2C_ADDR_BOOT, SERIAL_NO_OFFSET, serial_no, SERIAL_NO_LEN);
336
337   for (i = 0; i < SERIAL_NO_LEN; i++){
338     unsigned char ch = serial_no[i];
339     if (ch == 0xff)     // make unprogrammed EEPROM default to '0'
340       ch = '0';
341     usb_desc_serial_number_ascii[i << 1] = ch;
342   }
343 }
344
345 void
346 main (void)
347 {
348 #if 0
349   g_rx_enable = 0;      // FIXME (work around initialization bug)
350   g_tx_enable = 0;
351   g_rx_overrun = 0;
352   g_tx_underrun = 0;
353 #endif
354
355   memset (hash1, 0, USRP_HASH_SIZE);    // zero fpga bitstream hash.  This forces reload
356   
357   init_usrp ();
358   init_gpif ();
359   
360   // if (UC_START_WITH_GSTATE_OUTPUT_ENABLED)
361   IFCONFIG |= bmGSTATE;                 // no conflict, start with it on
362
363   set_led_0 (0);
364   set_led_1 (0);
365   
366   EA = 0;               // disable all interrupts
367
368   patch_usb_descriptors();
369
370   setup_autovectors ();
371   usb_install_handlers ();
372   hook_timer_tick ((unsigned short) isr_tick);
373
374   EIEX4 = 1;            // disable INT4 FIXME
375   EA = 1;               // global interrupt enable
376
377   fx2_renumerate ();    // simulates disconnect / reconnect
378
379   main_loop ();
380 }