URL
https://opencores.org/ocsvn/gecko3/gecko3/trunk
Subversion Repositories gecko3
[/] [gecko3/] [trunk/] [GECKO3COM/] [gecko3com-fw/] [firmware/] [lib/] [usb_common.c] - Rev 9
Compare with Previous | Blame | View Log
/* -*- 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 <stdint.h> #include <stdio.h> #include "usb_common.h" #include "fx2regs.h" #include "syncdelay.h" #include "fx2utils.h" #include "isr.h" #include "usb_descriptors.h" #include "usb_requests.h" #include "debugprint.h" #ifdef USB_DFU_SUPPORT #include "usb_dfu.h" #endif 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 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 (); #ifdef USB_DFU_SUPPORT usb_dfu_state = DFU_STATE_appIDLE; #endif } static void isr_HIGHSPEED (void) interrupt { clear_usb_irq (); setup_descriptors (); #ifdef USB_DFU_SUPPORT usb_dfu_state = DFU_STATE_appIDLE; #endif } 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 return &EP1INCS + (ep >> 1); // EP2CS -1; 2, 4, 6, 8 are consecutive } #ifdef USB_DFU_SUPPORT static void setup_dfu_descriptors (void) { current_device_descr = dfu_mode_device_descr; current_config_descr = dfu_mode_config_descr; } static void isr_DFURESET (void) interrupt { clear_usb_irq (); setup_dfu_descriptors (); usb_dfu_state = DFU_STATE_dfuIDLE; } void usb_toggle_dfu_handlers (void) { if(usb_dfu_state == DFU_STATE_appIDLE){ hook_uv (UV_USBRESET, (unsigned short) isr_DFURESET); hook_uv (UV_HIGHSPEED, (unsigned short) isr_DFURESET); } else { hook_uv (UV_USBRESET, (unsigned short) isr_USBRESET); hook_uv (UV_HIGHSPEED, (unsigned short) isr_HIGHSPEED); usb_dfu_state = DFU_STATE_appIDLE; } } #endif void usb_handle_setup_packet (void) { _usb_got_SUDAV = 0; switch (bRequestType & bmRT_TYPE_MASK){ case bmRT_TYPE_CLASS: // call the application code class requests. // If it handles the command it returns non-zero if (!app_class_cmd ()) fx2_stall_ep0 (); break; case bmRT_TYPE_RESERVED: fx2_stall_ep0 (); // we don't handle these. indicate error break; case bmRT_TYPE_VENDOR: // call the application code for vendor commands. // 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; #ifdef USB_DFU_SUPPORT case DT_DFU_FUNCTIONAL: SUDPTRH = MSB (dfu_mode_functional_descr); SUDPTRL = LSB (dfu_mode_functional_descr); break; #endif 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; EP2CS &= ~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; }