diff options
Diffstat (limited to 'firmware/fx2/lib')
-rw-r--r-- | firmware/fx2/lib/.gitignore | 18 | ||||
-rw-r--r-- | firmware/fx2/lib/Makefile.am | 79 | ||||
-rw-r--r-- | firmware/fx2/lib/delay.c | 76 | ||||
-rw-r--r-- | firmware/fx2/lib/fx2utils.c | 54 | ||||
-rw-r--r-- | firmware/fx2/lib/i2c-compiler-bug.c | 129 | ||||
-rw-r--r-- | firmware/fx2/lib/i2c.c | 123 | ||||
-rw-r--r-- | firmware/fx2/lib/isr.c | 167 | ||||
-rw-r--r-- | firmware/fx2/lib/timer.c | 49 | ||||
-rw-r--r-- | firmware/fx2/lib/usb_common.c | 386 |
9 files changed, 1081 insertions, 0 deletions
diff --git a/firmware/fx2/lib/.gitignore b/firmware/fx2/lib/.gitignore new file mode 100644 index 000000000..04f253234 --- /dev/null +++ b/firmware/fx2/lib/.gitignore @@ -0,0 +1,18 @@ +/*.ihx +/*.lnk +/*.lst +/*.map +/*.mem +/*.rel +/*.rst +/*.sym +/blink_leds.asm +/usrp_common.asm +/command_loop.asm +/fpga.asm +/*.asm +/usrp_gpif.c +/usrp_gpif_inline.h +/*.lib +/Makefile +/Makefile.in diff --git a/firmware/fx2/lib/Makefile.am b/firmware/fx2/lib/Makefile.am new file mode 100644 index 000000000..f9e1b2317 --- /dev/null +++ b/firmware/fx2/lib/Makefile.am @@ -0,0 +1,79 @@ +# +# Copyright 2003 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +EXTRA_DIST = \ + delay.c \ + fx2utils.c \ + i2c.c \ + isr.c \ + timer.c \ + usb_common.c + + + +DEFINES= +FW_INCLUDES=-I$(top_srcdir)/include + +# with EA = 0, the FX2 implements a portion of the 8051 "external memory" +# on chip. This memory is mapped like this: +# +# The bottom 8K of memory (0x0000 - 0x1fff) is used for both data and +# code accesses. There's also 512 bytes for data only from 0xe000 - 0xe1ff. +# +# We tell the linker to start the xdata segment at 0x1800, 6K up from +# the bottom. + +LINKOPTS = --code-loc 0x0000 --code-size 0x1800 --xram-loc 0x1800 --xram-size 0x0800 + +LIBRARY = libfx2.lib + +LIBOBJS = \ + delay.rel \ + fx2utils.rel \ + i2c.rel \ + isr.rel \ + timer.rel \ + usb_common.rel + + + +all: libfx2.lib + +.c.rel: + $(XCC) $(FW_INCLUDES) $(DEFINES) -c $< -o $@ + +$(LIBRARY): $(LIBOBJS) + -rm -f $(LIBRARY) + touch $(LIBRARY) + for obj in $(LIBOBJS); do basename $$obj .rel >> $(LIBRARY) ; done + + +CLEANFILES = \ + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib + +DISTCLEANFILES = \ + *.ihx *.lnk *.lst *.map *.mem *.rel *.rst *.sym *.asm *.lib + +install: all + + +# dependencies + diff --git a/firmware/fx2/lib/delay.c b/firmware/fx2/lib/delay.c new file mode 100644 index 000000000..13cf0eec8 --- /dev/null +++ b/firmware/fx2/lib/delay.c @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * Delay approximately 1 microsecond (including overhead in udelay). + */ +static void +udelay1 (void) _naked +{ + _asm ; lcall that got us here took 4 bus cycles + ret ; 4 bus cycles + _endasm; +} + +/* + * delay for approximately usecs microseconds + */ +void +udelay (unsigned char usecs) +{ + do { + udelay1 (); + } while (--usecs != 0); +} + + +/* + * Delay approximately 1 millisecond. + * We're running at 48 MHz, so we need 48,000 clock cycles. + * + * Note however, that each bus cycle takes 4 clock cycles (not obvious, + * but explains the factor of 4 problem below). + */ +static void +mdelay1 (void) _naked +{ + _asm + mov dptr,#(-1200 & 0xffff) +002$: + inc dptr ; 3 bus cycles + mov a, dpl ; 2 bus cycles + orl a, dph ; 2 bus cycles + jnz 002$ ; 3 bus cycles + + ret + _endasm; +} + +void +mdelay (unsigned int msecs) +{ + do { + mdelay1 (); + } while (--msecs != 0); +} + + diff --git a/firmware/fx2/lib/fx2utils.c b/firmware/fx2/lib/fx2utils.c new file mode 100644 index 000000000..64ffcc896 --- /dev/null +++ b/firmware/fx2/lib/fx2utils.c @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "fx2utils.h" +#include "fx2regs.h" +#include "delay.h" + +void +fx2_stall_ep0 (void) +{ + EP0CS |= bmEPSTALL; +} + +void +fx2_reset_data_toggle (unsigned char ep) +{ + TOGCTL = ((ep & 0x80) >> 3 | (ep & 0x0f)); + TOGCTL |= bmRESETTOGGLE; +} + +void +fx2_renumerate (void) +{ + USBCS |= bmDISCON | bmRENUM; + + // mdelay (1500); // FIXME why 1.5 seconds? + mdelay (250); // FIXME why 1.5 seconds? + + USBIRQ = 0xff; // clear any pending USB irqs... + EPIRQ = 0xff; // they're from before the renumeration + + EXIF &= ~bmEXIF_USBINT; + + USBCS &= ~bmDISCON; // reconnect USB +} diff --git a/firmware/fx2/lib/i2c-compiler-bug.c b/firmware/fx2/lib/i2c-compiler-bug.c new file mode 100644 index 000000000..360b779bc --- /dev/null +++ b/firmware/fx2/lib/i2c-compiler-bug.c @@ -0,0 +1,129 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "i2c.h" +#include "fx2regs.h" +#include <string.h> + + +// issue a stop bus cycle and wait for completion + + +// returns non-zero if successful, else 0 +unsigned char +i2c_read (unsigned char addr, xdata unsigned char *buf, unsigned char len) +{ + volatile unsigned char junk; + + if (len == 0) // reading zero bytes always works + return 1; + + // memset (buf, 0, len); // FIXME, remove + + while (I2CS & bmSTOP) // wait for stop to clear + ; + + + I2CS = bmSTART; + I2DAT = (addr << 1) | 1; // write address and direction (1's the read bit) + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + + if (len == 1) + I2CS |= bmLASTRD; + + junk = I2DAT; // trigger the first read cycle + +#if 1 + while (len != 1){ + while ((I2CS & bmDONE) == 0) + ; + + if (I2CS & bmBERR) + goto fail; + + len--; + if (len == 1) + I2CS |= bmLASTRD; + + *buf++ = I2DAT; // get data, trigger another read + } +#endif + + // wait for final byte + + while ((I2CS & bmDONE) == 0) + ; + + if (I2CS & bmBERR) + goto fail; + + I2CS |= bmSTOP; + *buf = I2DAT; + + return 1; + + fail: + I2CS |= bmSTOP; + return 0; +} + + + +// returns non-zero if successful, else 0 +unsigned char +i2c_write (unsigned char addr, xdata const unsigned char *buf, unsigned char len) +{ + while (I2CS & bmSTOP) // wait for stop to clear + ; + + I2CS = bmSTART; + I2DAT = (addr << 1) | 0; // write address and direction (0's the write bit) + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + + while (len > 0){ + I2DAT = *buf++; + len--; + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + } + + I2CS |= bmSTOP; + return 1; + + fail: + I2CS |= bmSTOP; + return 0; +} diff --git a/firmware/fx2/lib/i2c.c b/firmware/fx2/lib/i2c.c new file mode 100644 index 000000000..0f238b5cf --- /dev/null +++ b/firmware/fx2/lib/i2c.c @@ -0,0 +1,123 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "i2c.h" +#include "fx2regs.h" +#include <string.h> + + +// issue a stop bus cycle and wait for completion + + +// returns non-zero if successful, else 0 +unsigned char +i2c_read (unsigned char addr, xdata unsigned char *buf, unsigned char len) +{ + volatile unsigned char junk; + + if (len == 0) // reading zero bytes always works + return 1; + + while (I2CS & bmSTOP) // wait for stop to clear + ; + + I2CS = bmSTART; + I2DAT = (addr << 1) | 1; // write address and direction (1's the read bit) + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + + if (len == 1) + I2CS |= bmLASTRD; + + junk = I2DAT; // trigger the first read cycle + + while (--len != 0){ + while ((I2CS & bmDONE) == 0) + ; + + if (I2CS & bmBERR) + goto fail; + + if (len == 1) + I2CS |= bmLASTRD; + + *buf++ = I2DAT; // get data, trigger another read + } + + // wait for final byte + + while ((I2CS & bmDONE) == 0) + ; + + if (I2CS & bmBERR) + goto fail; + + I2CS |= bmSTOP; + *buf = I2DAT; + + return 1; + + fail: + I2CS |= bmSTOP; + return 0; +} + + + +// returns non-zero if successful, else 0 +unsigned char +i2c_write (unsigned char addr, xdata const unsigned char *buf, unsigned char len) +{ + while (I2CS & bmSTOP) // wait for stop to clear + ; + + I2CS = bmSTART; + I2DAT = (addr << 1) | 0; // write address and direction (0's the write bit) + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + + while (len > 0){ + I2DAT = *buf++; + len--; + + while ((I2CS & bmDONE) == 0) + ; + + if ((I2CS & bmBERR) || (I2CS & bmACK) == 0) // no device answered... + goto fail; + } + + I2CS |= bmSTOP; + return 1; + + fail: + I2CS |= bmSTOP; + return 0; +} diff --git a/firmware/fx2/lib/isr.c b/firmware/fx2/lib/isr.c new file mode 100644 index 000000000..05412daf5 --- /dev/null +++ b/firmware/fx2/lib/isr.c @@ -0,0 +1,167 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "isr.h" +#include "fx2regs.h" +#include "syncdelay.h" + +extern xdata unsigned char _standard_interrupt_vector[]; +extern xdata unsigned char _usb_autovector[]; +extern xdata unsigned char _fifo_gpif_autovector[]; + +#define LJMP_OPCODE 0x02 + +/* + * Hook standard interrupt vector. + * + * vector_number is from the SV_<foo> list. + * addr is the address of the interrupt service routine. + */ +void +hook_sv (unsigned char vector_number, unsigned short addr) +{ + bit t; + + // sanity checks + + if (vector_number < SV_MIN || vector_number > SV_MAX) + return; + + if ((vector_number & 0x0f) != 0x03 && (vector_number & 0x0f) != 0x0b) + return; + + t = EA; + EA = 0; + _standard_interrupt_vector[vector_number] = LJMP_OPCODE; + _standard_interrupt_vector[vector_number + 1] = addr >> 8; + _standard_interrupt_vector[vector_number + 2] = addr & 0xff; + EA = t; +} + +/* + * Hook usb interrupt vector. + * + * vector_number is from the UV_<foo> list. + * addr is the address of the interrupt service routine. + */ +void +hook_uv (unsigned char vector_number, unsigned short addr) +{ + bit t; + + // sanity checks + + if (vector_number < UV_MIN || vector_number > UV_MAX) + return; + + if ((vector_number & 0x3) != 0) + return; + + t = EA; + EA = 0; + _usb_autovector[vector_number] = LJMP_OPCODE; + _usb_autovector[vector_number + 1] = addr >> 8; + _usb_autovector[vector_number + 2] = addr & 0xff; + EA = t; +} + +/* + * Hook fifo/gpif interrupt vector. + * + * vector_number is from the FGV_<foo> list. + * addr is the address of the interrupt service routine. + */ +void +hook_fgv (unsigned char vector_number, unsigned short addr) +{ + bit t; + + // sanity checks + + if (vector_number < FGV_MIN || vector_number > FGV_MAX) + return; + + if ((vector_number & 0x3) != 0) + return; + + t = EA; + EA = 0; + _fifo_gpif_autovector[vector_number] = LJMP_OPCODE; + _fifo_gpif_autovector[vector_number + 1] = addr >> 8; + _fifo_gpif_autovector[vector_number + 2] = addr & 0xff; + EA = t; +} + +/* + * One time call to enable autovectoring for both USB and FIFO/GPIF. + * + * This disables all USB and FIFO/GPIF interrupts and clears + * any pending interrupts too. It leaves the master USB and FIFO/GPIF + * interrupts enabled. + */ +void +setup_autovectors (void) +{ + // disable master usb and fifo/gpif interrupt enables + EIUSB = 0; + EIEX4 = 0; + + hook_sv (SV_INT_2, (unsigned short) _usb_autovector); + hook_sv (SV_INT_4, (unsigned short) _fifo_gpif_autovector); + + // disable all fifo interrupt enables + SYNCDELAY; + EP2FIFOIE = 0; SYNCDELAY; + EP4FIFOIE = 0; SYNCDELAY; + EP6FIFOIE = 0; SYNCDELAY; + EP8FIFOIE = 0; SYNCDELAY; + + // clear all pending fifo irqs + EP2FIFOIRQ = 0xff; SYNCDELAY; + EP4FIFOIRQ = 0xff; SYNCDELAY; + EP6FIFOIRQ = 0xff; SYNCDELAY; + EP8FIFOIRQ = 0xff; SYNCDELAY; + + IBNIE = 0; + IBNIRQ = 0xff; + NAKIE = 0; + NAKIRQ = 0xff; + USBIE = 0; + USBIRQ = 0xff; + EPIE = 0; + EPIRQ = 0xff; + SYNCDELAY; GPIFIE = 0; + SYNCDELAY; GPIFIRQ = 0xff; + USBERRIE = 0; + USBERRIRQ = 0xff; + CLRERRCNT = 0; + + INTSETUP = bmAV2EN | bmAV4EN | bmINT4IN; + + // clear master irq's for usb and fifo/gpif + EXIF &= ~bmEXIF_USBINT; + EXIF &= ~bmEXIF_IE4; + + // enable master usb and fifo/gpif interrrupts + EIUSB = 1; + EIEX4 = 1; +} diff --git a/firmware/fx2/lib/timer.c b/firmware/fx2/lib/timer.c new file mode 100644 index 000000000..97e2f7cf9 --- /dev/null +++ b/firmware/fx2/lib/timer.c @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "timer.h" +#include "fx2regs.h" +#include "isr.h" + +/* + * Arrange to have isr_tick_handler called at 100 Hz. + * + * The cpu clock is running at 48e6. The input to the timer + * is 48e6 / 12 = 4e6. + * + * We arrange to have the timer overflow every 40000 clocks == 100 Hz + */ + +#define RELOAD_VALUE ((unsigned short) -40000) + +void +hook_timer_tick (unsigned short isr_tick_handler) +{ + ET2 = 0; // disable timer 2 interrupts + hook_sv (SV_TIMER_2, isr_tick_handler); + + RCAP2H = RELOAD_VALUE >> 8; // setup the auto reload value + RCAP2L = RELOAD_VALUE; + + T2CON = 0x04; // interrupt on overflow; reload; run + ET2 = 1; // enable timer 2 interrupts +} diff --git a/firmware/fx2/lib/usb_common.c b/firmware/fx2/lib/usb_common.c new file mode 100644 index 000000000..3b0547b2f --- /dev/null +++ b/firmware/fx2/lib/usb_common.c @@ -0,0 +1,386 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usb_common.h" +#include "fx2regs.h" +#include "syncdelay.h" +#include "fx2utils.h" +#include "isr.h" +#include "usb_descriptors.h" +#include "usb_requests.h" + +extern xdata char str0[]; +extern xdata char str1[]; +extern xdata char str2[]; +extern xdata char str3[]; +extern xdata char str4[]; +extern xdata char str5[]; + + +#define bRequestType SETUPDAT[0] +#define bRequest SETUPDAT[1] +#define wValueL SETUPDAT[2] +#define wValueH SETUPDAT[3] +#define wIndexL SETUPDAT[4] +#define wIndexH SETUPDAT[5] +#define wLengthL SETUPDAT[6] +#define wLengthH SETUPDAT[7] + +#define MSB(x) (((unsigned short) x) >> 8) +#define LSB(x) (((unsigned short) x) & 0xff) + +volatile bit _usb_got_SUDAV; + +unsigned char _usb_config = 0; +unsigned char _usb_alt_setting = 0; // FIXME really 1/interface + +xdata unsigned char *current_device_descr; +xdata unsigned char *current_devqual_descr; +xdata unsigned char *current_config_descr; +xdata unsigned char *other_config_descr; + +static void +setup_descriptors (void) +{ + if (USBCS & bmHSM){ // high speed mode + current_device_descr = high_speed_device_descr; + current_devqual_descr = high_speed_devqual_descr; + current_config_descr = high_speed_config_descr; + other_config_descr = full_speed_config_descr; + } + else { + current_device_descr = full_speed_device_descr; + current_devqual_descr = full_speed_devqual_descr; + current_config_descr = full_speed_config_descr; + other_config_descr = high_speed_config_descr; + } + + // whack the type fields + // FIXME, may not be required. + // current_config_descr[1] = DT_CONFIG; + // other_config_descr[1] = DT_OTHER_SPEED; +} + +static void +isr_SUDAV (void) interrupt +{ + clear_usb_irq (); + _usb_got_SUDAV = 1; +} + +static void +isr_USBRESET (void) interrupt +{ + clear_usb_irq (); + setup_descriptors (); +} + +static void +isr_HIGHSPEED (void) interrupt +{ + clear_usb_irq (); + setup_descriptors (); +} + +void +usb_install_handlers (void) +{ + setup_descriptors (); // ensure that they're set before use + + hook_uv (UV_SUDAV, (unsigned short) isr_SUDAV); + hook_uv (UV_USBRESET, (unsigned short) isr_USBRESET); + hook_uv (UV_HIGHSPEED, (unsigned short) isr_HIGHSPEED); + + USBIE = bmSUDAV | bmURES | bmHSGRANT; +} + +// On the FX2 the only plausible endpoints are 0, 1, 2, 4, 6, 8 +// This doesn't check to see that they're enabled + +unsigned char +plausible_endpoint (unsigned char ep) +{ + ep &= ~0x80; // ignore direction bit + + if (ep > 8) + return 0; + + if (ep == 1) + return 1; + + return (ep & 0x1) == 0; // must be even +} + +// return pointer to control and status register for endpoint. +// only called with plausible_endpoints + +xdata volatile unsigned char * +epcs (unsigned char ep) +{ + if (ep == 0x01) // ep1 has different in and out CS regs + return EP1OUTCS; + + if (ep == 0x81) + return EP1INCS; + + ep &= ~0x80; // ignore direction bit + + if (ep == 0x00) // ep0 + return EP0CS; + + return EP2CS + (ep >> 1); // 2, 4, 6, 8 are consecutive +} + +void +usb_handle_setup_packet (void) +{ + _usb_got_SUDAV = 0; + + // handle the standard requests... + + switch (bRequestType & bmRT_TYPE_MASK){ + + case bmRT_TYPE_CLASS: + case bmRT_TYPE_RESERVED: + fx2_stall_ep0 (); // we don't handle these. indicate error + break; + + case bmRT_TYPE_VENDOR: + // call the application code. + // If it handles the command it returns non-zero + + if (!app_vendor_cmd ()) + fx2_stall_ep0 (); + break; + + case bmRT_TYPE_STD: + // these are the standard requests... + + if ((bRequestType & bmRT_DIR_MASK) == bmRT_DIR_IN){ + + //////////////////////////////////// + // handle the IN requests + //////////////////////////////////// + + switch (bRequest){ + + case RQ_GET_CONFIG: + EP0BUF[0] = _usb_config; // FIXME app should handle + EP0BCH = 0; + EP0BCL = 1; + break; + + // -------------------------------- + + case RQ_GET_INTERFACE: + EP0BUF[0] = _usb_alt_setting; // FIXME app should handle + EP0BCH = 0; + EP0BCL = 1; + break; + + // -------------------------------- + + case RQ_GET_DESCR: + switch (wValueH){ + + case DT_DEVICE: + SUDPTRH = MSB (current_device_descr); + SUDPTRL = LSB (current_device_descr); + break; + + case DT_DEVQUAL: + SUDPTRH = MSB (current_devqual_descr); + SUDPTRL = LSB (current_devqual_descr); + break; + + case DT_CONFIG: + if (0 && wValueL != 1) // FIXME only a single configuration + fx2_stall_ep0 (); + else { + SUDPTRH = MSB (current_config_descr); + SUDPTRL = LSB (current_config_descr); + } + break; + + case DT_OTHER_SPEED: + if (0 && wValueL != 1) // FIXME only a single configuration + fx2_stall_ep0 (); + else { + SUDPTRH = MSB (other_config_descr); + SUDPTRL = LSB (other_config_descr); + } + break; + + case DT_STRING: + if (wValueL >= nstring_descriptors) + fx2_stall_ep0 (); + else { + xdata char *p = string_descriptors[wValueL]; + SUDPTRH = MSB (p); + SUDPTRL = LSB (p); + } + break; + + default: + fx2_stall_ep0 (); // invalid request + break; + } + break; + + // -------------------------------- + + case RQ_GET_STATUS: + switch (bRequestType & bmRT_RECIP_MASK){ + case bmRT_RECIP_DEVICE: + EP0BUF[0] = bmGSDA_SELF_POWERED; // FIXME app should handle + EP0BUF[1] = 0; + EP0BCH = 0; + EP0BCL = 2; + break; + + case bmRT_RECIP_INTERFACE: + EP0BUF[0] = 0; + EP0BUF[1] = 0; + EP0BCH = 0; + EP0BCL = 2; + break; + + case bmRT_RECIP_ENDPOINT: + if (plausible_endpoint (wIndexL)){ + EP0BUF[0] = *epcs (wIndexL) & bmEPSTALL; + EP0BUF[1] = 0; + EP0BCH = 0; + EP0BCL = 2; + } + else + fx2_stall_ep0 (); + break; + + default: + fx2_stall_ep0 (); + break; + } + break; + + // -------------------------------- + + case RQ_SYNCH_FRAME: // not implemented + default: + fx2_stall_ep0 (); + break; + } + } + + else { + + //////////////////////////////////// + // handle the OUT requests + //////////////////////////////////// + + switch (bRequest){ + + case RQ_SET_CONFIG: + _usb_config = wValueL; // FIXME app should handle + break; + + case RQ_SET_INTERFACE: + _usb_alt_setting = wValueL; // FIXME app should handle + break; + + // -------------------------------- + + case RQ_CLEAR_FEATURE: + switch (bRequestType & bmRT_RECIP_MASK){ + + case bmRT_RECIP_DEVICE: + switch (wValueL){ + case FS_DEV_REMOTE_WAKEUP: + default: + fx2_stall_ep0 (); + } + break; + + case bmRT_RECIP_ENDPOINT: + if (wValueL == FS_ENDPOINT_HALT && plausible_endpoint (wIndexL)){ + *epcs (wIndexL) &= ~bmEPSTALL; + fx2_reset_data_toggle (wIndexL); + } + else + fx2_stall_ep0 (); + break; + + default: + fx2_stall_ep0 (); + break; + } + break; + + // -------------------------------- + + case RQ_SET_FEATURE: + switch (bRequestType & bmRT_RECIP_MASK){ + + case bmRT_RECIP_DEVICE: + switch (wValueL){ + case FS_TEST_MODE: + // hardware handles this after we complete SETUP phase handshake + break; + + case FS_DEV_REMOTE_WAKEUP: + default: + fx2_stall_ep0 (); + break; + } + } + break; + + case bmRT_RECIP_ENDPOINT: + switch (wValueL){ + case FS_ENDPOINT_HALT: + if (plausible_endpoint (wIndexL)) + *epcs (wIndexL) |= bmEPSTALL; + else + fx2_stall_ep0 (); + break; + + default: + fx2_stall_ep0 (); + break; + } + break; + + // -------------------------------- + + case RQ_SET_ADDRESS: // handled by fx2 hardware + case RQ_SET_DESCR: // not implemented + default: + fx2_stall_ep0 (); + } + + } + break; + + } // bmRT_TYPE_MASK + + // ack handshake phase of device request + EP0CS |= bmHSNAK; +} |