diff options
Diffstat (limited to 'firmware/fx2/lib/usb_common.c')
| -rw-r--r-- | firmware/fx2/lib/usb_common.c | 386 | 
1 files changed, 386 insertions, 0 deletions
| 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; +} | 
