www.pudn.com > EP26_Bulk.zip > fw.c


//----------------------------------------------------------------------------- 
//   File:      fw.c 
//   Contents:   Firmware frameworks task dispatcher and device request parser 
//            source. 
// 
// indent 3.  NO TABS! 
// 
// $Revision: 18 $ 
// $Date: 12/04/01 5:33p $ 
// 
//   Copyright (c) 1997 AnchorChips, Inc. All rights reserved 
//----------------------------------------------------------------------------- 
#include "fx2.h" 
#include "fx2regs.h" 
#include "io.h" 
#include "serial.h" 
 
//----------------------------------------------------------------------------- 
// Constants 
//----------------------------------------------------------------------------- 
#define DELAY_COUNT   0x9248*8L  // Delay for 8 sec at 24Mhz, 4 sec at 48 
#define _IFREQ  48000            // IFCLK constant for Synchronization Delay 
#define _CFREQ  48000            // CLKOUT constant for Synchronization Delay 
 
//----------------------------------------------------------------------------- 
// Random Macros 
//----------------------------------------------------------------------------- 
#define   min(a,b) (((a)<(b))?(a):(b)) 
#define   max(a,b) (((a)>(b))?(a):(b)) 
 
  // Registers which require a synchronization delay, see section 15.14 
  // FIFORESET        FIFOPINPOLAR 
  // INPKTEND         OUTPKTEND 
  // EPxBCH:L         REVCTL 
  // GPIFTCB3         GPIFTCB2 
  // GPIFTCB1         GPIFTCB0 
  // EPxFIFOPFH:L     EPxAUTOINLENH:L 
  // EPxFIFOCFG       EPxGPIFFLGSEL 
  // PINFLAGSxx       EPxFIFOIRQ 
  // EPxFIFOIE        GPIFIRQ 
  // GPIFIE           GPIFADRH:L 
  // UDMACRCH:L       EPxGPIFTRIG 
  // GPIFTRIG 
   
  // Note: The pre-REVE EPxGPIFTCH/L register are affected, as well... 
  //      ...these have been replaced by GPIFTC[B3:B0] registers 
   
#include "fx2sdly.h"             // Define _IFREQ and _CFREQ above this #include 
 
//----------------------------------------------------------------------------- 
// Global Variables 
//----------------------------------------------------------------------------- 
volatile BOOL   GotSUD; 
BOOL      Rwuen; 
BOOL      Selfpwr; 
volatile BOOL   Sleep;                  // Sleep mode enable flag 
 
WORD   pDeviceDscr;   // Pointer to Device Descriptor; Descriptors may be moved 
WORD   pDeviceQualDscr; 
WORD   pHighSpeedConfigDscr; 
WORD   pFullSpeedConfigDscr;    
WORD   pConfigDscr; 
WORD   pOtherConfigDscr;    
WORD   pStringDscr;    
 
//----------------------------------------------------------------------------- 
// Prototypes 
//----------------------------------------------------------------------------- 
void SetupCommand(void); 
void TD_Init(void); 
void TD_Poll(void); 
BOOL TD_Suspend(void); 
BOOL TD_Resume(void); 
 
BOOL DR_GetDescriptor(void); 
BOOL DR_SetConfiguration(void); 
BOOL DR_GetConfiguration(void); 
BOOL DR_SetInterface(void); 
BOOL DR_GetInterface(void); 
BOOL DR_GetStatus(void); 
BOOL DR_ClearFeature(void); 
BOOL DR_SetFeature(void); 
BOOL DR_VendorCmnd(void); 
 
// this table is used by the epcs macro  
const char code  EPCS_Offset_Lookup_Table[] = 
{ 
   0,    // EP1OUT 
   1,    // EP1IN 
   2,    // EP2OUT 
   2,    // EP2IN 
   3,    // EP4OUT 
   3,    // EP4IN 
   4,    // EP6OUT 
   4,    // EP6IN 
   5,    // EP8OUT 
   5,    // EP8IN 
}; 
 
// macro for generating the address of an endpoint's control and status register (EPnCS) 
#define epcs(EP) (EPCS_Offset_Lookup_Table[(EP & 0x7E) | (EP > 128)] + 0xE6A1) 
 
//----------------------------------------------------------------------------- 
// Code 
//----------------------------------------------------------------------------- 
 
// Task dispatcher 
void main(void) 
{ 
   DWORD   i; 
   WORD   offset; 
   DWORD   DevDescrLen; 
   DWORD   j=0; 
   WORD   IntDescrAddr; 
   WORD   ExtDescrAddr; 
  	 
   // Initialize Global States 
   Sleep = FALSE;               // Disable sleep mode 
   Rwuen = FALSE;               // Disable remote wakeup 
   Selfpwr = FALSE;            // Disable self powered 
   GotSUD = FALSE;               // Clear "Got setup data" flag 
 
   // Initialize user device 
   TD_Init(); 
	IO_Init(); 
	REG_Init(); 
   // The following section of code is used to relocate the descriptor table.  
   // Since the SUDPTRH and SUDPTRL are assigned the address of the descriptor  
   // table, the descriptor table must be located in on-part memory. 
   // The 4K demo tools locate all code sections in external memory. 
   // The descriptor table is relocated by the frameworks ONLY if it is found  
   // to be located in external memory. 
   pDeviceDscr = (WORD)&DeviceDscr; 
   pDeviceQualDscr = (WORD)&DeviceQualDscr; 
   pHighSpeedConfigDscr = (WORD)&HighSpeedConfigDscr; 
   pFullSpeedConfigDscr = (WORD)&FullSpeedConfigDscr; 
   pStringDscr = (WORD)&StringDscr; 
 
   if ((WORD)&DeviceDscr & 0xe000) 
   { 
      IntDescrAddr = INTERNAL_DSCR_ADDR; 
      ExtDescrAddr = (WORD)&DeviceDscr; 
      DevDescrLen = (WORD)&UserDscr - (WORD)&DeviceDscr + 2; 
      for (i = 0; i < DevDescrLen; i++) 
         *((BYTE xdata *)IntDescrAddr+i) = 0xCD; 
      for (i = 0; i < DevDescrLen; i++) 
         *((BYTE xdata *)IntDescrAddr+i) = *((BYTE xdata *)ExtDescrAddr+i); 
      pDeviceDscr = IntDescrAddr; 
      offset = (WORD)&DeviceDscr - INTERNAL_DSCR_ADDR; 
      pDeviceQualDscr -= offset; 
      pConfigDscr -= offset; 
      pOtherConfigDscr -= offset; 
      pHighSpeedConfigDscr -= offset; 
      pFullSpeedConfigDscr -= offset; 
      pStringDscr -= offset; 
   } 
 
   EZUSB_IRQ_ENABLE();            // Enable USB interrupt (INT2) 
   EZUSB_ENABLE_RSMIRQ();            // Wake-up interrupt 
 
   INTSETUP |= (bmAV2EN | bmAV4EN);     // Enable INT 2 & 4 autovectoring 
 
   USBIE |= bmSUDAV | bmSUTOK | bmSUSP | bmURES | bmHSGRANT;   // Enable selected interrupts 
	 
   SerialPort_Init(); 
   EA = 1;                  // Enable 8051 interrupts 
 
#ifndef NO_RENUM 
   // Renumerate if necessary.  Do this by checking the renum bit.  If it 
   // is already set, there is no need to renumerate.  The renum bit will 
   // already be set if this firmware was loaded from an eeprom. 
   if(!(USBCS & bmRENUM)) 
   { 
       EZUSB_Discon(TRUE);   // renumerate 
   } 
#endif 
 
   // unconditionally re-connect.  If we loaded from eeprom we are 
   // disconnected and need to connect.  If we just renumerated this 
   // is not necessary but doesn't hurt anything 
   USBCS &=~bmDISCON; 
 
   CKCON = (CKCON&(~bmSTRETCH)) | FW_STRETCH_VALUE; // Set stretch to 0 (after renumeration) 
 
   // clear the Sleep flag. 
   Sleep = FALSE; 
 
   // Task Dispatcher 
   while(TRUE)               // Main Loop 
   { 
      if(GotSUD)            // Wait for SUDAV 
      { 
         SetupCommand();          // Implement setup command 
           GotSUD = FALSE;            // Clear SUDAV flag 
      } 
 
      // Poll User Device 
      // NOTE: Idle mode stops the processor clock.  There are only two 
      // ways out of idle mode, the WAKEUP pin, and detection of the USB 
      // resume state on the USB bus.  The timers will stop and the 
      // processor will not wake up on any other interrupts. 
      if (Sleep) 
          { 
          if(TD_Suspend()) 
              {  
              Sleep = FALSE;            // Clear the "go to sleep" flag.  Do it here to prevent any race condition between wakeup and the next sleep. 
              do 
                  { 
                    EZUSB_Susp();         // Place processor in idle mode. 
                  } 
                while(!Rwuen && EZUSB_EXTWAKEUP()); 
                // Must continue to go back into suspend if the host has disabled remote wakeup 
                // *and* the wakeup was caused by the external wakeup pin. 
                 
             // 8051 activity will resume here due to USB bus or Wakeup# pin activity. 
             EZUSB_Resume();   // If source is the Wakeup# pin, signal the host to Resume.       
             TD_Resume(); 
              }    
          } 
      TD_Poll(); 
   } 
} 
 
// Device request parser 
void SetupCommand(void) 
{ 
   void   *dscr_ptr; 
 
   switch(SETUPDAT[1]) 
   { 
      case SC_GET_DESCRIPTOR:                  // *** Get Descriptor 
         if(DR_GetDescriptor()) 
            switch(SETUPDAT[3])          
            { 
               case GD_DEVICE:            // Device 
                  SUDPTRH = MSB(pDeviceDscr); 
                  SUDPTRL = LSB(pDeviceDscr); 
                  break; 
               case GD_DEVICE_QUALIFIER:            // Device Qualifier 
                  SUDPTRH = MSB(pDeviceQualDscr); 
                  SUDPTRL = LSB(pDeviceQualDscr); 
                  break; 
               case GD_CONFIGURATION:         // Configuration 
                  SUDPTRH = MSB(pConfigDscr); 
                  SUDPTRL = LSB(pConfigDscr); 
                  break; 
               case GD_OTHER_SPEED_CONFIGURATION:  // Other Speed Configuration 
                  SUDPTRH = MSB(pOtherConfigDscr); 
                  SUDPTRL = LSB(pOtherConfigDscr); 
                  break; 
               case GD_STRING:            // String 
                  if(dscr_ptr = (void *)EZUSB_GetStringDscr(SETUPDAT[2])) 
                  { 
                     SUDPTRH = MSB(dscr_ptr); 
                     SUDPTRL = LSB(dscr_ptr); 
                  } 
                  else  
                     EZUSB_STALL_EP0();   // Stall End Point 0 
                  break; 
               default:            // Invalid request 
                  EZUSB_STALL_EP0();      // Stall End Point 0 
            } 
         break; 
      case SC_GET_INTERFACE:                  // *** Get Interface 
         DR_GetInterface(); 
         break; 
      case SC_SET_INTERFACE:                  // *** Set Interface 
         DR_SetInterface(); 
         break; 
      case SC_SET_CONFIGURATION:               // *** Set Configuration 
         DR_SetConfiguration(); 
         break; 
      case SC_GET_CONFIGURATION:               // *** Get Configuration 
         DR_GetConfiguration(); 
         break; 
      case SC_GET_STATUS:                  // *** Get Status 
         if(DR_GetStatus()) 
            switch(SETUPDAT[0]) 
            { 
               case GS_DEVICE:            // Device 
                  EP0BUF[0] = ((BYTE)Rwuen << 1) | (BYTE)Selfpwr; 
                  EP0BUF[1] = 0; 
                  EP0BCH = 0; 
                  EP0BCL = 2; 
                  break; 
               case GS_INTERFACE:         // Interface 
                  EP0BUF[0] = 0; 
                  EP0BUF[1] = 0; 
                  EP0BCH = 0; 
                  EP0BCL = 2; 
                  break; 
               case GS_ENDPOINT:         // End Point 
                  EP0BUF[0] = *(BYTE xdata *) epcs(SETUPDAT[4]) & bmEPSTALL; 
                  EP0BUF[1] = 0; 
                  EP0BCH = 0; 
                  EP0BCL = 2; 
                  break; 
               default:            // Invalid Command 
                  EZUSB_STALL_EP0();      // Stall End Point 0 
            } 
         break; 
      case SC_CLEAR_FEATURE:                  // *** Clear Feature 
         if(DR_ClearFeature()) 
            switch(SETUPDAT[0]) 
            { 
               case FT_DEVICE:            // Device 
                  if(SETUPDAT[2] == 1) 
                     Rwuen = FALSE;       // Disable Remote Wakeup 
                  else 
                     EZUSB_STALL_EP0();   // Stall End Point 0 
                  break; 
               case FT_ENDPOINT:         // End Point 
                  if(SETUPDAT[2] == 0) 
                  { 
                     *(BYTE xdata *) epcs(SETUPDAT[4]) &= ~bmEPSTALL; 
                     EZUSB_RESET_DATA_TOGGLE( SETUPDAT[4] ); 
                  } 
                  else 
                     EZUSB_STALL_EP0();   // Stall End Point 0 
                  break; 
            } 
         break; 
      case SC_SET_FEATURE:                  // *** Set Feature 
         if(DR_SetFeature()) 
            switch(SETUPDAT[0]) 
            { 
               case FT_DEVICE:            // Device 
                  if(SETUPDAT[2] == 1) 
                     Rwuen = TRUE;      // Enable Remote Wakeup 
                  else if(SETUPDAT[2] == 2) 
                     // Set Feature Test Mode.  The core handles this request.  However, it is 
                     // necessary for the firmware to complete the handshake phase of the 
                     // control transfer before the chip will enter test mode.  It is also 
                     // necessary for FX2 to be physically disconnected (D+ and D-) 
                     // from the host before it will enter test mode. 
                     break; 
                  else 
                     EZUSB_STALL_EP0();   // Stall End Point 0 
                  break; 
               case FT_ENDPOINT:         // End Point 
                  *(BYTE xdata *) epcs(SETUPDAT[4]) |= bmEPSTALL; 
                  break; 
            } 
         break; 
      default:                     // *** Invalid Command 
         if(DR_VendorCmnd()) 
            EZUSB_STALL_EP0();            // Stall End Point 0 
   } 
 
   // Acknowledge handshake phase of device request 
   EP0CS |= bmHSNAK; 
} 
 
// Wake-up interrupt handler 
void resume_isr(void) interrupt WKUP_VECT 
{ 
   EZUSB_CLEAR_RSMIRQ(); 
}