OpenCores
URL https://opencores.org/ocsvn/gecko3/gecko3/trunk

Subversion Repositories gecko3

[/] [gecko3/] [trunk/] [GECKO3COM/] [gecko3com-fw/] [firmware/] [lib/] [usb_common.c] - Rev 20

Go to most recent revision | 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;
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.