📄 periph.c
字号:
#pragma NOIV // Do not generate interrupt vectors
//-----------------------------------------------------------------------------
// File: periph.c
// Contents: Hooks required to implement USB peripheral function.
//
// Copyright (c) 1997-2003 Cypress Semiconductor, Inc. All rights reserved
//
// $Archive: /USB/atapifx2/CY4611B/periph.c $
// $Date: 6/30/05 10:48a $
// $Revision: 9 $
//-----------------------------------------------------------------------------
#include "fx2.h"
#include "fx2regs.h"
#include "gpif.h"
#include "atapi.h"
#include "globals.h"
extern BOOL Sleep;
extern BOOL Rwuen;
void clearResetLine();
//-----------------------------------------------------------------------------
// Task Dispatcher hooks
// The following hooks are called by the task dispatcher.
//-----------------------------------------------------------------------------
void TD_Init(void) // Called once at startup
{
bit bError;
// set our first_time flag. This is set to the timer start bit. The timer start
// bit will only be set if we have already been here before.
bFirstTime = !TR0;
phaseErrorState = 0;
bScsiRegsPreloaded = 0;
attemptFastScsi = 0;
// Enable both autoptrs. ONLY use AUTOPTR2 for writing small amounts of data to EP6buf. NEVER load
// AUTOPTR1H again.
AUTOPTRSETUP = 0x7;
AUTOPTRH2 = MSB(EP6FIFOBUF);
// Only do the copy the first time we run because we modify the descriptor version in HalfKBuffer.
// We know it's the first time if the timer isn't running yet.
// There are three possible startup conditions:
// -- AT2 classic EEPROM present. Turns off many new features, including EP1
// -- AT2LP EEPROM present. As defined in the datasheet
// -- Bad signature found. Assumed to be an unprogrammed EEPROM. Skip drive ID and wait for mfg mode command.
if (bFirstTime)
{
bError = 1;
eepromAddr = EEPROM_ADDR;
bError = EEPROMRead(CONFIG_SPACE_START,sizeof(MX2_CONFIG_DATA), (BYTE xdata *) &mx2_config_data);
miscConfig = mx2_config_data.MiscConfig;
miscConfig2 = mx2_config_data.MiscConfig2;
// Secret bit for 400Khz EEPROM read)
if (bATA_UDMA_ENABLE)
{
bATA_UDMA_ENABLE = 0;
I2CTL |= bm400KHZ;
}
miscConfig |= mx2_config_data.UdmaConfig & 0xc0;
pinConfig = mx2_config_data.PinConfig;
mymemmovexx(halfKBuffer, (char xdata *) &DeviceDscr, (BYTE)&DscrEndOffset);
sensePtrs[0] = sensePtrs[1] = sensePtr = senseMediaChanged;
if (bError)
eepromAddr = 0x52; // Config for dev board if error is detected.
// Missing signature: Read the dscr.a51 file for the VID/PID. Enter mfg mode.
if (!(mx2_config_data.Signature == MX2_EEPROM_SIGNATURE || mx2_config_data.Signature == AT2LP_EEPROM_SIGNATURE))
{
// relocate USB descriptors to RAM
// load the deecriptors from the rom.
mymemmovexx(halfKBuffer, (char xdata *) &DeviceDscr, (WORD)&DscrEndOffset);
setDefaultConfig();
enterMfgMode();
}
else
{
mfgMode = 0;
// relocate USB descriptors to RAM
// load the deecriptors from the eeprom.
// the descriptor data starts at offset 16 in the eeprom
EEPROMRead(CONFIG_SPACE_START+sizeof(MX2_CONFIG_DATA),BUFFER_SIZE,halfKBuffer);
// Almost all of the AT2LP bits are RESERVED=0 in the AT2 EEPROM. Set the non-reserved ones here.
if (mx2_config_data.Signature == MX2_EEPROM_SIGNATURE)
{
bATA_ENABLED = 1;
bNewAt2pinout = 0;
}
else
{
bNewAt2pinout = 1;
IOEShadow |= mx2_config_data.GpioData << 2;
IOE = IOEShadow;
OEE |= mx2_config_data.GpioOE << 2;
checkGPIOonPA3();
}
////////////////////////////////////////////////////////////////////////////////
// Check for RESET shorted to DD7 to signal mfg mode. This allows devices
// to be reprogrammed without a drive attached. If the firsttime flag is set,
// the GPIF isn't set up yet, so we can treat DD7 like a normal pin.
//
// Check procedure:
// 1) Check for VBUS -- No VBUS = no check
// 2) Float the reset line. If it floats high, abort.
// 3) Reset is now low. Drive DD7 high. If RESET is now high, enter mfg mode.
WAKEUPCS = 0x45;
if (!(WAKEUPCS & 0x40)) // check VBUS and old part's VBUS detector
{
OEA &= ~ATAPI_RESET_BIT;
if (!ATAPI_RESET_)
{
OEB = 0x80;
PB7 = 0x80;
if (ATAPI_RESET_)
enterMfgMode();
OEB = 0x0;
}
OEA |= ATAPI_RESET_BIT;
}
}
}
// init state/reset variables
currentState = UNCONFIGURED;
// 0x80 is used as a flag value to tell us that we still need to complete drive ID.
// if (bFirstTime || !deviceCount)
// {
// deviceCount = 0x80;
// LunBits[0] = LunBits[1] = ActiveLunBits = 0; // zeroes out bCompactFlash, bScsi, bExtAddrSupport
// }
attemptFastRead = attemptFastWrite = 0;
// In order to properly support HID and CSM, we have to parse part of the descriptors.
// If there is more than one descriptor, some offsets are pulled from the descriptors.
HIDIntrfcDscrOffset = CSMIntrfcDscrOffset = 0;
if (bNewAt2pinout)
{
#define INTRFC_OFFSET 4
{
xdata BYTE *ptr;
for (ptr = halfKBuffer+ (BYTE) &FullSpeedConfigDscrOffset;
MSB(ptr) == MSB(halfKBuffer) && *ptr != 0; ptr += *ptr)
{
if (ptr[1] == DSCR_INTRFC)
{
if (ptr[5] == 3) // HID class code
HIDIntrfcDscrOffset = LSB(ptr);
else if (ptr[5] == 0xd)
CSMIntrfcDscrOffset = LSB(ptr);
}
// Existing EEPROMs may contain 0x88 for EP8IN instead of 0x86 for EP6IN. Fix it on the fly.
else if (ptr[1] == DSCR_ENDPNT && ptr[2] == 0x88)
ptr[2] = 0x86;
}
}
}
else // for old AT2 pinout, must modify the descriptor from EP8IN to EP6IN
{
if (halfKBuffer[(BYTE) &FullSpeedConfigDscrOffset+ DSCR_CONFIG_LEN + DSCR_INTRFC_LEN + 2] == 0x88)
halfKBuffer[(BYTE) &FullSpeedConfigDscrOffset+ DSCR_CONFIG_LEN + DSCR_INTRFC_LEN + 2] = 0x86;
if (halfKBuffer[(BYTE) &FullSpeedConfigDscrOffset+ DSCR_CONFIG_LEN + DSCR_INTRFC_LEN + DSCR_ENDPNT_LEN + 2] == 0x88)
halfKBuffer[(BYTE) &FullSpeedConfigDscrOffset+ DSCR_CONFIG_LEN + DSCR_INTRFC_LEN + DSCR_ENDPNT_LEN + 2] = 0x86;
}
initUSB(); // configure output ports and endpoint params
mymemmovexx(&GPIF_WAVE_DATA, (BYTE xdata *) WaveDataPioUDMA, 128); // load wave forms in memory
// Set up timer 0 to act as the timeout counter.
// The default setting for the debugger uses timer 1
TMOD = 0x21; // Timer 1 set up for debugger (just in case). Timer 0 is 16 bit counter
CKCON = 0x10; // Same setting as debugger for T1, T0 is CPU/12 (4Mhz input)
ET0 = 1; // Enable timer interrupt (needed to do software count of 61hz overflows)
TR0 = 1;
}
void TD_Poll(void) // Called repeatedly while the device is idle
{
WORD count = 0;
// check EP2 EMPTY(busy) bit in EP2468STAT (SFR), core set's this bit when FIFO is empty
if(!(EP2468STAT & bmEP2EMPTY))
{
// Check for "USBC"
if (checkCBW() == USBS_PASSED)
{
// Good packet, forward to the device.
processCBW();
}
else
{
// if we receive an invalid CBW, STALL both bulk endpoints and remain that
// way until reset recovery (MSC BOT 6.6.1)
EP2CS = EP6CS = bmEPSTALL;
phaseErrorState = 1;
}
}
#if DEVICE_TYPE_IS_IDE
checkForMedia(0);
#endif
}
//-----------------------------------------------------------------------------
// Support functions for specific device
//-----------------------------------------------------------------------------
void initUSB(void)
{
DBUG &= ~0x01; // Turn off phase-picker power savings. (DBUG at 0xE6F8)
PORTACFG = 0;
OUTATAPI = ATAPI_IDLE_VALUE;
nLOWPWR = 0; // active low -- Indicates active (0) vs suspend (tri-state)
IOEShadow = nPWR500 | ATAPUEN;
IOE = IOEShadow; // active low -- Start with power OFF
OEC = PORTC_OE;
if(VBUS_POWERED)
{
OEE |= (PORTE_OE_SUSPEND);
triStateATABus();
}
else
OEE |= PORTE_OE;
// Enable INT4 to latch the GPIOs
EXIF &= ~bmIE4; // Clear any pending interrupts
EIEX4 = 1; // Enable INT4 interrupts
// INTSETUP is configured elsewhere.
// if we are trying to operate in bus powered mode, we want to defer setting the
// CPU clock speed or configuring the GPIF until we have been configured. This
// is to keep our current under 100mA.
IFCONFIG = IFCONFIG_DEFAULT;
CPUCS = bmCLKSPD1 | bmCLKINV; // set clock to 48MHz. clock output disabled. inverted.
// FIFOPINPOLAR = 0x00; // ff pin is active low -- This is the default
// PINFLAGSAB = 0x00; // FLAGA PF for FIFO selected by FIFOADR[1..0] -- 0 is the default
PINFLAGSCD = 0x00; // FLAGB FF for FIFO selected by FIFOADR[1..0]
// GPIF and CTL configuration
checkATAEnable(); // Sets GPIFIDLECTL, OEA
GPIFIDLECS = 0; // tristate data bus during idle interval
GPIFREADYCFG = 0x20; // Turn on TCXpire as a ready source
GPIFTCB3 = 0; // Set this ONCE, not every time. No xfers longer than 24 bits.
FLOWEQ0CTL = 0x00; // UDMA init that's the same for both read and write
FLOWSTBEDGE = 0x03; //
GPIFHOLDAMOUNT = 0x01; //
GPIFWFSELECT = GPIFWFSELECT_DEFAULT;
// Endpoint initialization
EP2CFG = 0xA0; // ep2 is valid BULK OUT 512 quad buffered
EP2FIFOCFG = 0x05; // WORDWIDE=1M MANUAL
EP2FIFOPFH = 0x00; // PF=0 when BC > PF -> Decis=0 (1 byte in FIFO)
EP2FIFOPFL = 0x00; // PF and BC refer to the current pkt -> PKTSTAT=0
// EP2GPIFPFSTOP = 0; // Do not stop on PF -- This is the default
EP6CFG = 0xE0; // ep6 is valid BULK IN 512 double buffered
EP6FIFOCFG = 0x05; // set EP6: 0x05=MANUAL, 0x0D=AUTOIN
EP1INCFG = 0x80 | 0x30; // EP1IN is valid INTERRUPT in
// mark all unused endpoints invalid - setting each reg to 0x22 instead of just clearing
// the valid bit to save code space. 0x22 basically sets all of these endpoints to
// not valid, bulk, double 512 buffered.
EP1OUTCFG = EP4CFG = EP8CFG = 0x22;
// disbable Auto Arm
REVCTL = bmNOAUTOARM;
// arm the OUT endpoint. By default OUT endpoints come up unarmed.
ResetAndArmEp2();
// reset the EP6 FIFO. If we are here as the result of a USB reset or MSC
// Reset Recovery, EP6 may need to be cleaned up.
FIFORESET = 0x06;
if (!IN_MASS_STORAGE_CLASS_RESET)
AlternateSetting = Configuration = 0;
}
// Stalls EP2OUT endpoint.
//
// This routine automatically handles several problematic OUT STALL cases.
//
// 1) The host is still PINGing us on the OUT endpoint, we set the stall bit and he reads it. (Normal case)
// 2) We want to STALL the endpoint, but the host is done sending all of the data from the command.
// In this case, we cannot tell the host about the STALL.
// 3) The host is in the process of sending an OUT packet when we get here.
//
void stallEP2OUT()
{
if (!dataTransferLen)
return;
FIFORESET = bmNAKALL; // NACK all xfers from the host.
// Wait one packet time -- 50uS at full-speed, 10us at high-speed
{
BYTE count;
BYTE i;
if (EZUSB_HIGHSPEED())
count = 10;
else
count = 50;
for (; count; count--)
i = halfKBuffer[0];
}
{
// Check to see if stall is needed. If it is, STALL the endpoint.
// If we have already received all of the data for the command, STALLing the endpoint
// will only cause the NEXT command to fail.
WORD x;
if (EP2468STAT & bmEP2EMPTY)
x = EP2FIFOBCL + (EP2FIFOBCH << 8);
else
x = EP2FIFOBCL + (EP2FIFOBCH << 8) + EP2BC;
if (dataTransferLen > x)
{
EP2CS |= bmEPSTALL;
}
}
FIFORESET = 0; // Clear the NAKALL bit.
}
// This function pulls common information out of the CBW
void processCBWHeader()
{
currentState = RECEIVED_CBW; // This will prevent us from processing CBWs in the ISR.
// Save the tag for use in the response
cbwTagLow = *((WORD volatile xdata*)(EP2FIFOBUF+CBW_TAG));
cbwTagHi = *((WORD volatile xdata*)(EP2FIFOBUF+CBW_TAG+2));
// Get the length (convert from little endian)
*(((BYTE *) &dataTransferLen)+3) = (EP2FIFOBUF+CBW_DATA_TRANSFER_LEN_LSB)[0]; // "Residue"
*(((BYTE *) &dataTransferLen)+2) = (EP2FIFOBUF+CBW_DATA_TRANSFER_LEN_LSB)[1]; // "Residue"
*(((BYTE *) &dataTransferLen)+1) = (EP2FIFOBUF+CBW_DATA_TRANSFER_LEN_LSB)[2]; // "Residue"
*(((BYTE *) &dataTransferLen)+0) = (EP2FIFOBUF+CBW_DATA_TRANSFER_LEN_LSB)[3]; // "Residue"
directionIn = EP2FIFOBUF[CBW_FLAGS] & 0x80;
}
void processCBW()
{
BYTE CbwLun;
CbwLun = EP2FIFOBUF[CBW_LUN];
#if DEVICE_TYPE_IS_IDE
if (attemptFastRead)
{
if (CbwLun == currentLunNum && !(mymemcmpa(prevCmd,&EP2FIFOBUF[0x0F],10+1)))
{
BYTE status;
attemptFastRead = 0;
status = fastReadComplete();
// Save the tag for use in the response
cbwTagLow = *((WORD volatile xdata*)(EP2FIFOBUF+CBW_TAG));
cbwTagHi = *((WORD volatile xdata*)(EP2FIFOBUF+CBW_TAG+2));
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
sendUSBS(status);
currentState = WAIT_FOR_CBW;
return;
}
else
{
// switch the EP back to manual mode and drop through to normal processing
EP6Manual();
attemptFastRead = 0;
}
}
else if (attemptFastWrite)
{
if (CbwLun == currentLunNum && !(mymemcmpa(prevCmd,&EP2FIFOBUF[0x0F],10+1)))
{
BYTE status;
attemptFastWrite = 0;
// Save the tag for use in the response
cbwTagLow = *((WORD volatile xdata*)(EP2FIFOBUF+CBW_TAG));
cbwTagHi = *((WORD volatile xdata*)(EP2FIFOBUF+CBW_TAG+2));
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
status = fastWriteComplete();
sendUSBS(status);
currentState = WAIT_FOR_CBW;
return;
}
else
{
// switch the EP back to manual mode and drop through to normal processing
EP2Manual();
attemptFastWrite = 0;
}
}
else
#endif // DEVICE_TYPE_IS_IDE
if (attemptFastScsi)
{
attemptFastScsi = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -