📄 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"
//-----------------------------------------------------------------------------
// 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();
// 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)
{
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();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -