📄 periph.c
字号:
// Reference Manual for more information
// Set the stretch to 5
CKCON = (CKCON&(~bmSTRETCH)) | 5;
FIFORESET = 2;
// we're quad-buffered, so we need to arm EP2 four times
EP2BCL = 0x80;
EP2BCL = 0x80;
EP2BCL = 0x80;
EP2BCL = 0x80;
// Reset the stretch to 0
CKCON = (CKCON&(~bmSTRETCH)) | FW_STRETCH_VALUE;
}
// check for tri-state signal on WAKEUP pin
// If the tri-state pin is set, disconnect and sleep until we have control of the bus again.
// if the pin is not set,
void checkATAEnable()
{
WAKEUPCS = 0x45;
if ((WAKEUPCS & 0x40) || (!bNewAt2pinout && !VBUS_PRESENT)) // check VBUS and old part's VBUS detector
{
#if STANDBY_IMMEDIATE
WORD i;
#endif
// Disconnect
USBCS |= bmDISCON;
// Standby Immediate means that we MUST drive the bus in all modes.
// Turn it on even though we may have the tristate flag set too.
// Once we're driving the bus and disconnected, we're done. Return so that the
// background sleep code can send the standby command.
#if STANDBY_IMMEDIATE
driveATABus();
//////////////////////////////////////////////////
// Special purpose power-saving code.
//
// Expected conditions:
// Self-powered, no bus-sharing, single IDE device
//
// This code will wait 500ms before turning off the drive.
// This is to debounce any short sleep conditions that occur, like the
// ~75ms sleep period that many hosts do during startup.
//////////////////////////////////////////////////
USBCS |= bmNOSYNSOF;
USBIRQ |= bmSOF;
for (i = 0; i < 100; i++)
{
EZUSB_Delay(1);
if ((USBIRQ & bmSOF) && !VBUS_PRESENT)
break;
}
if (!((USBIRQ & bmSOF) && !VBUS_PRESENT))
{
standbyImmediate();
}
while (!VBUS_PRESENT)
;
// Now that we're done waiting for WAKEUP# exclusively, make sure we wake up on D+ too!
WAKEUPCS = 0x45;
EZUSB_Delay(30); // Switch debounce time -- It's okay to use EZUSB_Delay here because we will never return to any version that we may have interrupted.
softReset();
#else
abortGPIF();
// Reset the FIFOs
FIFORESET = 6;
ResetAndArmEp2();
if (bATA_EN || (!bNewAt2pinout && (WAKEUPCS & 0x40)))
triStateATABus();
// Just sit here until we are re-enabled.
EA = 0; // In case we have higher priority interrupts
EZUSB_Delay(30); // Switch debounce time -- It's okay to use EZUSB_Delay here because we will never return to any version that we may have interrupted.
// New pinout - Now that we're just waiting for WAKEUP# to go high, set polarity to active high, enable ONLY that wakeup source and sleep
// Old pinout - WAKEUP = ATA_EN, PA6 = VBUS_PRESENT. If we're here due to WAKEUP, go to sleep. If not we must stay awake.
if (bNewAt2pinout || (WAKEUPCS & 0x40))
{
WAKEUPCS = bmWU | bmWUPOL | bmWUEN; // 0x51
EZUSB_Susp(); // Place processor in idle mode.
}
else
{
while (!VBUS_PRESENT)
;
}
// Some designs use this signal to swap drives. Force drive ID on restart.
if (bSEARCH_ATA_ON_WAKEUP)
deviceCount = 0x80;
// Now that we're done waiting for WAKEUP# exclusively, make sure we wake up on D+ too!
WAKEUPCS = 0x45;
EZUSB_Delay(30); // Switch debounce time -- It's okay to use EZUSB_Delay here because we will never return to any version that we may have interrupted.
softReset();
#endif
}
else
// Turn on the bus for non-bus-powered drives here. Bus-powered drives will be turned on
// in the background after the bus is turned on.
if (!VBUS_POWERED)
{
driveATABus();
if (deviceCount == 1 || deviceCount == 2)
USBCS &= ~bmDISCON; // Connect to USB if we've completed drive ID.
}
}
BYTE checkCBW()
{
// Check for "USBC"
if (EP2FIFOBUF[0] != 'U' ||
EP2FIFOBUF[1] != 'S' ||
EP2FIFOBUF[2] != 'B' ||
EP2FIFOBUF[3] != 'C')
{
return(USBS_FAILED);
}
else
{
if (EP2BC != 31)
// Error -- Stall the endpoint
return(USBS_FAILED);
}
return(USBS_PASSED);
}
BYTE processConfigCBCommand()
{
BYTE addr = EP2FIFOBUF[CONFIG_CB_EEPROM_ADDR_LSB];
BYTE ConfigCBSubCommand = EP2FIFOBUF[CONFIG_CB_SUBCOMMAND_OFFSET];
switch (ConfigCBSubCommand)
{
case CONFIG_CB_SUBCOMMAND_EEPROM_RW:
{
WORD len;
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
if (!directionIn)
{
if (EEPROMWrite(dataTransferLenLSW, CONFIG_SPACE_START))
{
stallEP2OUT();
return(USBS_FAILED);
}
}
else
{
while (dataTransferLenLSW)
{
len = min(dataTransferLenLSW,wPacketSize);
// wait for an available EP buffer
while (EP6CS & bmEPFULL)
;
if(EEPROMRead(addr+CONFIG_SPACE_START,len,EP6FIFOBUF))
{
failedIn();
return(USBS_FAILED);
}
EP6BCH = MSB(len);
EP6BCL = LSB(len);
dataTransferLenLSW -= len;
addr += wPacketSize;
}
}
return(USBS_PASSED);
}
case CONFIG_CB_SUBCOMMAND_MFG:
{
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
/**************************************************************************
Byte Bit(s) Test / 3-State Control Register Name
0 0 Reserved
0 3:1 DA[2:0]
0 5:4 CS#[1:0]
0 6 VBUS
0 7 ARESET#
1 0 NDIOW
1 1 NDIOR
1 2 NDMACK
1 3 IORDY
1 4 DMARQ
1 5 ATA_EN
1 6 MFG_SEL
1 7 DD[15:0] 3-State Active hi 3-state buffer enable for ATA data bus.
2 7:0 DD[7:0]
3 7:0 DD[15:8]
4 7:0 Reserved
5 7:0 Reserved
6 7:0 Reserved
**************************************************************************/
if (directionIn)
{
OEA = 0x00; // Allow us to read the pins, not drive 'em.
waitForInBuffer();
AUTOPTRL2 = LSB(EP6FIFOBUF);
XAUTODAT2 = IOA; // Byte 0
XAUTODAT2 = (GPIFIDLECTL & 0x7) // Bits 0-2
| ((GPIFREADYSTAT & 0x3) << 3) // Bits 3-4
| ((WAKEUPCS & 0x40) >> 1) // Bit 5
| ((BYTE)mfgMode << 6) // Bit 6
| (OEB & 0x80); // Bit 7
XAUTODAT2 = IOB;
XAUTODAT2 = IOD;
EP6BCH = 0;
EP6BCL = dataTransferLenLSW;
}
else
{
// Wait for host to send data
while(EP2CS & bmEPEMPTY)
;
IOA = EP2FIFOBUF[0];
OEA = PORTA_OE; // PORTA is all output except PA.6(VBUS) and PA.0 (IRQ)
PORTACFG = 0; // Turn off alternate function
GPIFIDLECTL = 0x70 | (EP2FIFOBUF[1] & 0x7);
IFCONFIG &= ~3; // Turn off GPIF control of ports B and D.
if (EP2FIFOBUF[1] & 0x80)
{
IOB = EP2FIFOBUF[2];
IOD = EP2FIFOBUF[3];
OEB = 0xff;
OED = 0xff;
}
else
{
OEB = 0;
OED = 0;
}
// Give up the buffer
EP2BCL = 0x80;
}
dataTransferLen = 0;
return(USBS_PASSED);
}
// ATACB
#if ATACB_ENABLE
case CONFIG_CB_COMMAND:
{
return(processATACB());
}
#endif
default:
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
if (dataTransferLen)
{
if (directionIn)
failedIn();
else
stallEP2OUT();
}
return (USBS_FAILED);
}
}
void enterMfgMode()
{
// Default hardware setup
bATA_UDMA_ENABLE = 1;
bATAPI_UDMA_ENABLE = 1;
bWAIT_FOR_BUSY_BIT = 0;
bENABLE_WRITE_CACHE_MODE_PAGE= 0;
bCOMPLIANCE_MODE = 0;
bSHORT_PACKET_BEFORE_STALL = 1;
bSRST_ENABLE = 1;
bSKIP_PIN_RESET = 1;
bBUTTON_PINOUT = 0;
bATA_ENABLED = 1;
bBIG_PACKAGE = 1;
bATA_EN = 1;
bNewAt2pinout = 1;
bHS_INDICATOR = 0;
bDRVPWRVLD_POLARITY = 0;
bDRVPWRVLD_ENABLE = 0; // CF!
setDefaultConfig();
mymemmovexx(halfKBuffer, (char xdata *) &DeviceDscr, (WORD)&DscrEndOffset);
halfKBuffer[(BYTE) &IntrfcClassFullSpeedOffset] = 0xff;
halfKBuffer[2 + halfKBuffer[(BYTE) &SerialNumberIndexOffset]*2-16] = 'M';
bDRVPWRVLD_ENABLE = 0; // Turn off CF
ATA_ENABLED = 0; // Turn off ATA
mfgMode = 1; // We can also go into mfg mode if RESET# is pulled low. This is checked in initUSB after the ports have been configured.
}
void setDefaultConfig()
{
// Default hardware setup
// bATA_UDMA_ENABLE = 1;
// bATAPI_UDMA_ENABLE = 1;
// bWAIT_FOR_BUSY_BIT = 0;
// bENABLE_WRITE_CACHE_MODE_PAGE= 0;
//
// bCOMPLIANCE_MODE = 0;
// bSHORT_PACKET_BEFORE_STALL = 1;
// bSRST_ENABLE = 1;
// bSKIP_PIN_RESET = 1;
// bBUTTON_PINOUT = 0;
// bATA_ENABLED = 1;
// bBIG_PACKAGE = 1;
// bATA_EN = 1;
// bNewAt2pinout = 1;
// bHS_INDICATOR = 0;
// bDRVPWRVLD_POLARITY = 0;
// bDRVPWRVLD_ENABLE = 0; // CF!
// Default config
mx2_config_data.Signature = AT2LP_EEPROM_SIGNATURE;
mx2_config_data.ApmValue = 0;
mx2_config_data.AtaInitTimeout = 0x80;
mx2_config_data.UdmaConfig = 0xD4;
mx2_config_data.PioConfig = 0x7;
mx2_config_data.AtaCommand = CONFIG_CB_COMMAND;
mx2_config_data.Lun0String = mx2_config_data.Lun1String = 0;
mx2_config_data.GpioData = 0;
mx2_config_data.GpioOE = 0;
mx2_config_data.delayAfterReset = 0; // 20ms chunks. 0 = 50 for backward compatibility.
mx2_config_data.MiscConfig2 = 0;
miscConfig2 = 0;
}
void triStateATABus()
{
// Data bus is already tristated between read/writes
// Tri-state port A
// Tristate GPIF CTL lines
GPIFCTLCFG = 0x80; //
GPIFIDLECTL = 0;
OEA = 0;
OEC = PORTC_OE_SUSPEND;
IOEShadow |= nPWR500; // Turn off the CF power
IOE = IOEShadow;
OEE = PORTE_OE_SUSPEND | (mx2_config_data.GpioOE << 2);
}
void driveATABus()
{
GPIFCTLCFG = 0x0; //
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
OEA = PORTA_OE;
OEC = PORTC_OE;
OEE = PORTE_OE | (mx2_config_data.GpioOE << 2);
checkGPIOonPA3();
}
// When we are bus-powered, we have to tri-state the ATA bus
// when we are powered off. Otherwise power will leak
// through the ATA bus signals an mess up the startup.
void powerOff()
{
IOEShadow |= nPWR500; // Turn off the CF power
IOE = IOEShadow;
// If we're a bus-powered device, the ATA bus mus be floated during suspend.
if(VBUS_POWERED)
triStateATABus();
}
void powerOn()
{
if (Configuration == 1)
// "PWR500 will only be asserted if VBUSPWRD is asserted (or when we don't have a VBUSPWRD input)"
if (VBUS_POWERED)
{
if (CF_DETECT_ || ejected || !bDRVPWRVLD_ENABLE)
return;
IOEShadow &= ~nPWR500; // Turn on the CF power
IOE = IOEShadow;
driveATABus(); // Only manipulate the bus drivers if we're bus-powered.
EZUSB_Delay(DELAY_AFTER_POWERUP); // Wait for device to power up
hardwareReset();
EZUSB_Delay(90); // Mitsumi CR-4808TE(CYSD007) is a good test for this number.
}
}
// Get the sector count and prevCmd fields set up for the next command.
void fastSCSIStart()
{
// Update the sector based on the command group (see spc 4.3.3 and 4.3.4)
if ((prevCmd[0] & 0xe0) == 0xa0) // 12 byte command
*((unsigned long *) &prevCmd[2]) += *((unsigned long *) &prevCmd[6]);
else if ((prevCmd[0] & 0xe0) == 0x20) // 10 byte commands (0xa0, 0xb0)
*((unsigned long *) &prevCmd[2]) += *((unsigned int *) &prevCmd[7]);
else if ((prevCmd[0] & 0xe0) == 0x40) // 10 byte commands (0xc0, 0xd0)
*((unsigned long *) &prevCmd[2]) += *((unsigned int *) &prevCmd[7]);
// get our saved transfer length and sector count from the previous transfer
dataTransferLen = prevDataTransferLen;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -