www.pudn.com > HID firmware for the EZ-USB FX2 in C.zip > fw.c


//----------------------------------------------------------------------------- 
//   File:      fw.c 
//   Contents:   Firmware frameworks task dispatcher and device request parser 
//            source. 
// 
// indent 3.  NO TABS! 
// 
// $Revision: 1 $ 
// $Date: 10/03/03 3:01p $ 
// 
//   Copyright (c) 1997 AnchorChips, Inc. All rights reserved 
//----------------------------------------------------------------------------- 
#include "fx2.h" 
#include "fx2regs.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;    
 
extern code HIDDscr; 
extern code REPORTDSCR ReportDscr;  
extern code ReportDscrEnd; 
extern code StringDscr1,StringDscr2,StringDscr0; 
//----------------------------------------------------------------------------- 
// 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(); 
 
   // 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 
   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) 
{ 
    
   unsigned int	i, j,ReportLength; 
 
   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 
					switch(SETUPDAT[2])			// switch on wValueL 
					{ 
						case 0:					// String index 1 
							SUDPTRH = MSB(&StringDscr0); 
							SUDPTRL = LSB(&StringDscr0); 
						break; 
						case 1:					// String index 1 
							SUDPTRH = MSB(&StringDscr1); 
							SUDPTRL = LSB(&StringDscr1); 
						break; 
						case 2:					// String index 2 
							SUDPTRH = MSB(&StringDscr2); 
							SUDPTRL = LSB(&StringDscr2); 
						break; 
 
						default:				// Invalid string index requested 
							EZUSB_STALL_EP0(); 
				}  
 
			 	break; 
				case GD_HID:					// Get-Descriptor: HID 
					SUDPTRH = MSB(&HIDDscr); 
					SUDPTRL = LSB(&HIDDscr); 
				break; 
				case GD_REPORT:					// Get-Descriptor: Report 
				 
				//A HID report does not have a length field which the SIE can read  
				//to determine how many bytes to send using the Setup Data Pointer.  
				//Hence we need to 'manually' send the data. 
     
				ReportLength = (WORD)&ReportDscrEnd - (WORD)&ReportDscr;	 
				AUTOPTR1H = MSB(&ReportDscr); 
				AUTOPTR1L = LSB(&ReportDscr); 
				while(ReportLength) 
				{ 
					j = min(ReportLength,64);		// smaller of ReportSize or IN0 Buffer (64 bytes) 
					for(i=0;i