📄 periph.c
字号:
#pragma NOIV // Do not generate interrupt vectors
//-----------------------------------------------------------------------------
// File: periph.c
// Contents: Hooks required to implement USB peripheral function.
//
// Copyright (c) 1997 AnchorChips, Inc. All rights reserved
//
// $Workfile: periph.c $
// $Date: 7/23/02 5:20p $
// $Revision: 24 $
//-----------------------------------------------------------------------------
#include "fx2.h"
#include "fx2regs.h"
#include "gpif.h"
#include "atapi.h"
#include "globals.h"
//-----------------------------------------------------------------------------
// Task Dispatcher hooks
// The following hooks are called by the task dispatcher.
//-----------------------------------------------------------------------------
void TD_Init(void) // Called once at startup
{
// 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;
bSwitchToHighSpeed = 0;
if (bFirstTime)
bHighSpeedEnabled = 0;
// Enable both autoptrs. ONLY use AUTOPTR2 for writing small amounts of data to EP8buf. NEVER load
// AUTOPTR1H again.
AUTOPTRSETUP = 0x7;
AUTOPTRH2 = MSB(EP8FIFOBUF);
// relocate descriptor data to halfKBuffer. The bus powered version of us uses a HID descriptor set.
// 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.
if (bFirstTime)
{
#if BUS_POWERED
mymemmovexx(halfKBuffer, (char xdata *) &HIDDeviceDscr, (WORD)&HIDDeviceDscrEndOffset);
CT1 = 2; // Disable high speed state machine
#else
mymemmovexx(halfKBuffer, (char xdata *) &DeviceDscr, (WORD)&DscrEndOffset);
#endif
}
// init state/reset variables
currentState = UNCONFIGURED;
phaseErrorState = 0;
deviceCount = 0;
LunBits[0] = LunBits[1] = ActiveLunBits = 0;
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;
}
char const code usbcString[] = "USBC";
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(!(EP2CS & bmEPEMPTY))
{
// 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 = EP8CS = bmEPSTALL;
phaseErrorState = 1;
}
}
if (bSwitchToHighSpeed)
{
EZUSB_Delay(2000);
// enable high-speed state machine
CT1 = 0;
bSwitchToHighSpeed = 0;
bHighSpeedEnabled = 1;
// Switch to the new (mass storage) descriptor set
mymemmovexx(halfKBuffer, (char xdata *) &DeviceDscr, (WORD)&DscrEndOffset);
// disconnect and reconnect so we attach at high-speed if this is
// a high-speed host
EZUSB_Discon(TRUE);
USBCS &=~bmDISCON;
// since the host has sent us a set configuration, we know we are plugged
// into a high power port. we can now draw more than 100mA, so crank up
// the CPU clock and GPIF interface
IFCONFIG = IFCONFIG_DEFAULT;
CPUCS = bmCLKSPD1 | bmCLKINV; // set clock to 48MHz. clock output disabled. inverted.
}
checkForMedia(0);
}
//-----------------------------------------------------------------------------
// Support functions for specific device
//-----------------------------------------------------------------------------
void initUSB(void)
{
#if REVC_4611_BOARD
PORTACFG = 0;
#else
PORTACFG = 0x01; // set up PORTA for port I/O
#endif
// Configure our outputs to drive ONLY if the ATA_ENABLE pin is active
#if ATA_ENABLE_PIN
{
WAKEUPCS = 0x45;
if (!(WAKEUPCS & 0x40))
{
OUTATAPI = ATAPI_IDLE_VALUE; // includes RESET line PA.0
OEA = PORTA_OE; // PORTA is all output except PA.0(INTRQ) AND PA.6(DASP#)
}
}
#else
{
OUTATAPI = ATAPI_IDLE_VALUE; // includes RESET line PA.0
OEA = PORTA_OE; // PORTA is all output except PA.0(INTRQ) AND PA.6(DASP#)
}
#endif
// Make Interrupt 0 level triggered
IT0 = 0;
// 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.
#if !BUS_POWERED
IFCONFIG = IFCONFIG_DEFAULT;
CPUCS = bmCLKSPD1 | bmCLKINV; // set clock to 48MHz. clock output disabled. inverted.
#endif
FIFOPINPOLAR = 0x00; // ff pin is active low
PINFLAGSAB = 0x00; // FLAGA PF for FIFO selected by FIFOADR[1..0]
PINFLAGSCD = 0x00; // FLAGB FF for FIFO selected by FIFOADR[1..0]
// GPIF and CTL configuration
GPIFCTLCFG = 0x00; //
GPIFIDLECTL = 0x77; // x111x111 - CTL3 not enabled
// ||||||||_CTL0 = 1 during idle
// |||||||__CTL1 = 1 during idle
// ||||||___CTL2 = 1 during idle
// ||||_____CTL0 output enable
// |||______CTL1 output enable
// ||_______CTL2 output enable
//
GPIFIDLECS = 0; // tristate data bus during idle interval
GPIFWFSELECT = (2 << 6) | (3 << 4) | (0 << 2) | (1); // Single write is 2, Single read is 3, write is 0, Read is waveform 1
// 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
EP8CFG = 0xE0; // ep8 is valid BULK IN 512 double buffered
EP8FIFOCFG = bmZEROLENIN | bmWORDWIDE; // set EP8: 0x05=MANUAL, 0x0D=AUTOIN
// 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 = EP1INCFG = EP4CFG = EP6CFG = 0x22;
// disbable Auto Arm
REVCTL = bmNOAUTOARM;
// arm the OUT endpoint. By default OUT endpoints come up unarmed.
ResetAndArmEp2();
// reset the EP8 FIFO. If we are here as the result of a USB reset or MSC
// Reset Recovery, EP8 may need to be cleaned up.
FIFORESET = 0x08;
}
// Stalls EP2OUT endpoint.
void stallEP2OUT()
{
// Check to see if stall is needed. If it is, STALL the endpoint.
// After we have set the STALL, make sure we didn't get the last packet while we were STALLing.
WORD x;
if (EP2468STAT & bmEP2EMPTY)
x = 0;
else
x = EP2FIFOBCL + (EP2FIFOBCH << 8) + EP2BC;
// if (dataTransferLen > ((x + 1) & 0xfffe)) // Round up to allow for odd xfer lengths
if (dataTransferLen > x)
{
EP2CS |= bmEPSTALL;
EZUSB_Delay(100);
if (EP2CS & bmEPSTALL)
x=1234;
// If the host has already cleared the STALL, the EP will be empty here, but we will drop safely through the if()
if (EP2468STAT & bmEP2EMPTY)
x = 0;
else
x = EP2FIFOBCL + (EP2FIFOBCH << 8) + EP2BC;
if (dataTransferLen > x)
{
ResetAndArmEp2(); // Stall no longer needed
EP2CS = 0; // Clear stall 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] >> 7;
}
void processCBW()
{
BYTE CbwLun;
processCBWHeader();
CbwLun = EP2FIFOBUF[CBW_LUN];
if (!(CbwLun == currentLunNum))
{
// Before we change waveforms, tell the ATA interface that we're going to talk to the master.
// This allows us to use some of the ATA signals for the CF while the slave device ignores them.
// This works well as long as we don't write to a register that affects both devices, like
// the device select register, or the SRST bit in the control register.
mymemmove((BYTE *)&ActiveLunConfigData,(BYTE *)&DeviceConfigData[CbwLun], sizeof(DEVICE_CONFIG_DATA));
ActiveLunBits = LunBits[CbwLun];
currentLunNum = CbwLun;
if (bCompactFlash)
{
// The CF waveforms are stored within the PIO0 waves in lines 2 and 3.
// This makes their offset 4 + 8 for each line = 4+16.
// The transfer length is 8 (one full line) + 4 (the active part of the next line).
mymemmovexx(&GPIF_WAVE_DATA, (BYTE xdata *) WaveDataPioUDMA+16+4, 8 + 4);
mymemmovexx(&(GPIF_WAVE_DATA) + 32, (BYTE xdata *) WaveDataPioUDMA+32+16+4, 8 + 4);
EP2FIFOCFG = EP8FIFOCFG = bmZEROLENIN; // CF is byte-wide
}
else
{
EP2FIFOCFG = EP8FIFOCFG = bmZEROLENIN | bmWORDWIDE; // ATA/ATAPI is word-wide
// We've switched devices. Do we need to switch PIO modes too?
// if (!(DeviceConfigData[0].MaxPIO == DeviceConfigData[1].MaxPIO))
// ALWAYS switch. It's easier than special casing startup.
{
// switch to PIO4
if(ActiveLunConfigData.MaxPIO & PIO4)
{
mymemmovexx(&GPIF_WAVE_DATA, (BYTE xdata *) WaveDataPioUDMA+4, 8 + 4);
mymemmovexx(&(GPIF_WAVE_DATA) + 32, (BYTE xdata *) WaveDataPioUDMA+32+4, 8 + 4);
}
// switch to PIO3
else if(ActiveLunConfigData.MaxPIO & PIO3)
{
mymemmovexx(&GPIF_WAVE_DATA, (BYTE xdata *) WaveDataPioUDMA+4, 8 + 4);
mymemmovexx(&(GPIF_WAVE_DATA) + 32, (BYTE xdata *) WaveDataPioUDMA+32+4, 8 + 4);
((BYTE xdata *)&GPIF_WAVE_DATA)[0] = 0x6;
((BYTE xdata *)&GPIF_WAVE_DATA)[32] = 0x6;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -