📄 atareset.c
字号:
//-----------------------------------------------------------------------------
// Copyright (c) 1999-2001 Cypress Semiconductor, Inc. All rights reserved
//-----------------------------------------------------------------------------
//
// This file contains the device initialization code.
//
// $Workfile: atareset.c $
// $Date: 7/23/02 3:51p $
// $Revision: 28 $
//-----------------------------------------------------------------------------
#include "fx2.h"
#include "fx2regs.h"
#include "gpif.h"
#include "globals.h"
void detectSCSIvsATA();
// PIO3 waves are PIO waves but with 6 instead of 4 in the wave 0 and wave 1 lenbr field
void resetATAPIDevice()
{
sensePtr = senseDeviceReset;
if (bFirstTime)
EZUSB_Delay(DELAY_AFTER_POWERUP); // Wait for stable power -- Sony CDU4811 and Maxtor 34098 (40G) are good tests for this
/////////////////////////////////////////////////////////////////////////////////////
// Perform hardware reset ONCE on reset, then obey the skip pin reset flag
if ((bFirstTime) || !(SKIP_PIN_RESET))
{
hardwareReset();
bFirstTime = 0;
EZUSB_Delay(90); // Mitsumi CR-4808TE(CYSD007) is a good test for this number.
// give devices a chance to recover after ATA reset
}
/////////////////////////////////////////////////////////////////////////////////////
// Perform software reset and retest for SCSI vs ATA
else if (SRST_ENABLE)
{
writePIO8(ATAPI_CONTROL_REG, ATAPI_CONTROL_REG_SOFT_RESET);
EZUSB_Delay(50);
writePIO8(ATAPI_CONTROL_REG, 0);
}
EZUSB_Delay(DELAY_AFTER_RESET);
}
// Uses these globals:
// bMasterSlave
// Stuffs these globals:
// bScsi -- Set to 1 if EB14 is detected in the LBA registers
// bDevicePresent -- Set to 1 if device is found, 0 if not found
void detectSCSIvsATA()
{
EZUSB_Delay(5); // Wait 5 ms to be polite
writePIO8(ATAPI_CONTROL_REG, 0); // Make sure that SRST is not set
writeATA_DRIVESEL_REG();
// wait for the busy bit to clear. Even if there is no device, the busy bit will
// go to zero because of the pulldown on D7
waitForBusyBit();
writeATA_DRIVESEL_REG();
writePIO8(ATAPI_NULL_REG, ~0xE0); // Make sure that the bus is NOT still floating at 0xa0
// Read back the Drive Select register. If it contains what we wrote to it, then
// there may be a device here. Otherwise return.
if (!((readPIO8(ATA_DRIVESEL_REG) & 0xF0) == (0xE0 | ((BYTE) bMasterSlave << 4))))
return;
// Check for special SCSI byte count value. EB14 indicates an ATAPI device.
// If we read EB14, we know we have a real scsi device and we can quit
if (readPIO8(ATAPI_BYTE_COUNT_MSB) == 0xeb && readPIO8(ATAPI_BYTE_COUNT_LSB) == 0x14)
{
bScsi = 1;
}
// We now have identified a device that's responding to our commands. If we have
// selected the slave, it could be a master responding for the slave device.
// ATA devices in this case can be detected by seeing a 0 in the status register.
if (!bMasterSlave) // Master devices are done here.
{
bDevicePresent = 1;
return;
}
if (bScsi)
{
SendDeviceIdentifyCommand();
if (readATAPI_STATUS_REG() & ATAPI_STATUS_DRDY_BIT)
{
bit oldEA = EA;
EA = 0;
FetchDeviceIdentifyIntoEp8();
bDevicePresent = 1;
EA = oldEA;
}
}
else if (readATAPI_STATUS_REG())
bDevicePresent = 1;
}
void SendDeviceIdentifyCommand()
{
BYTE driveStatus;
// Wait for the register block to be non-busy and for a "drive ready" condition
do
{
writeATA_DRIVESEL_REG();
driveStatus = readATAPI_STATUS_REG();
} while((driveStatus & (ATAPI_STATUS_BUSY_BIT)) ); // Do-while
// writePIO8(ATA_ERROR_REG, 0); // Copied from Phoenix BIOS
// writePIO8(ATAPI_CONTROL_REG, 0); // Added later -- Make sure the nIEN bit is clear (active)
// writePIO8(ATA_SECTOR_COUNT_REG, 1);
// writePIO8(ATA_LBA_LSB_REG , 0);
// writePIO8(ATA_LBA_2SB_REG , 0);
// writePIO8(ATA_LBA_MSB_REG , 0);
// writeATA_DRIVESEL_REG();
// waitForBusyBit();
// Send Identify device command
if (bScsi)
writePIO8(ATAPI_COMMAND_REG, ATAPI_COMMAND_ID_DEVICE);
else
writePIO8(ATAPI_COMMAND_REG, IDE_COMMAND_ID_DEVICE);
// Wait for the register block to be non-busy. Cannot depend on the DRDY bit since some
// ATAPI devices will not set it on an A1 command.
waitForBusyBit();
}
// This function reads device IDENTIFY data from the drive and into EP8FIFOBUF. You must first call
// SendDeviceIdentifyCommand() to send the IDENTIFY command to the drive. Interrrupts must be
// disabled around calls to this function to avoid simultaneous access to EP8FIFOBUF that could
// occur if a USB reset happens.
void FetchDeviceIdentifyIntoEp8()
{
BYTE saveIt;
// Read the data from the drive. EP8FIFOBUF is used to store the data since we only
// need it temporarily.
saveIt = EP8FIFOCFG;
EP8FIFOCFG = saveIt & ~bmAUTOIN; // disable automode
readPIO16(ATAPI_DATA_REG, BUFFER_SIZE);
while (!gpifIdle()) // wait for the read to complete before continuing
;
OUTATAPI = ATAPI_IDLE_VALUE;
EP8FIFOCFG = saveIt; // re-enable automode if it was set before.
}
void ATAPIIdDevice()
{
BYTE i;
BYTE commandSetSupport;
bit oldEA;
SendDeviceIdentifyCommand();
while (!(readATAPI_STATUS_REG() & ATAPI_STATUS_DRDY_BIT))
;
// We need to disable interrupts while using EP8FIFOBUF. Here's why. It is possible
// (even probable) that we could get a USB reset while doing drive identification.
// One of the things that occurs in the USB reset ISR is a reset of the EP8 FIFO.
// It would be bad if that happened just as we were reading drive data into EP8FIFOBUF.
// The following code segment will complete in a deterministic amount of time.
oldEA = EA;
EA = 0;
FetchDeviceIdentifyIntoEp8();
if ((bScsi && USE_ATAPI_DEVICE_SERIAL_NUMBER) || (!bScsi && USE_ATA_DEVICE_SERIAL_NUMBER))
{
BYTE xdata *ptr = &halfKBuffer[(BYTE) &SerialNumberStringDscrOffset + 2];
for (i=0;i<ATAPI_INQUIRY_SERIAL_LEN;i++)
{
BYTE mychar = EP8FIFOBUF[i+ATAPI_INQUIRY_SERIAL];
#if NIBBLE_CONVERT_SERIAL_NUMBER
{
*ptr = mychar >> 4;
*ptr += '0';
if (*ptr > '9')
*ptr += 'A' - '9';
ptr += 2;
*ptr = mychar & 0x0F;
*ptr += '0';
if (*ptr > '9')
*ptr += 'A' - '9';
}
#else
{
*ptr = mychar;
}
#endif
}
}
else
{
BYTE xdata *ptr = &halfKBuffer[(BYTE) &SerialNumberIndexOffset];
// *ptr = 0;
}
// Check for large disk (48 bit) support. ATA-6 spec below....
// 6.2.1
// 4) The contents of words (61:60) and (103:100) shall not be used to determine if 48-bit addressing is
// supported. IDENTIFY DEVICE bit 10 word 83 indicates support for 48-bit addressing.
if (EP8FIFOBUF[IDENTIFY_48BIT_ADDRESSING+1] & (1<<2))
{
bExtAddrSupport = 1;
// This is actually smaller than a loop of 4!!
// Yes, this only supports 0x100 00 00 00 sectors, which is 220,000GB (industry GB, not true)
((BYTE *)&ActiveLunConfigData.driveCapacity)[3] = EP8FIFOBUF[0+IDE_ID_TOTAL_48_BIT_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[2] = EP8FIFOBUF[1+IDE_ID_TOTAL_48_BIT_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[1] = EP8FIFOBUF[2+IDE_ID_TOTAL_48_BIT_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[0] = EP8FIFOBUF[3+IDE_ID_TOTAL_48_BIT_SECTORS_LSW];
}
else
{
bExtAddrSupport = 0;
// This is actually smaller than a loop of 4!!
((BYTE *)&ActiveLunConfigData.driveCapacity)[3] = EP8FIFOBUF[0+IDE_ID_TOTAL_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[2] = EP8FIFOBUF[1+IDE_ID_TOTAL_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[1] = EP8FIFOBUF[2+IDE_ID_TOTAL_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[0] = EP8FIFOBUF[3+IDE_ID_TOTAL_SECTORS_LSW];
}
ActiveLunConfigData.NumCylindersMSB = EP8FIFOBUF[IDENTIFY_NUM_CYLINDERS_MSB];
ActiveLunConfigData.NumCylindersLSB = EP8FIFOBUF[IDENTIFY_NUM_CYLINDERS_LSB];
ActiveLunConfigData.NumHeads = EP8FIFOBUF[IDENTIFY_NUM_HEADS];
ActiveLunConfigData.NumSectPerTrack = EP8FIFOBUF[IDENTIFY_NUM_SECT_PER_TRACK];
// check for PIO3 support (or greater). PIO support is reported in the
// IDENTIFY data from the drive. AND the modes supported by the drive with
// the PIO enables from the configuration eeprom to enable only selected modes.
ActiveLunConfigData.MaxPIO = EP8FIFOBUF[IDENTIFY_ADVANCED_PIO] & PIO_MODES;
ActiveLunConfigData.udmaMode = 0;
// Check for UDMA support. UDMA support is reported in the IDENTIFY data
// from the drive. AND the modes supported by the drive with the UDMA mode
// enables from the configuration eeprom to enable only selected modes.
if (EP8FIFOBUF[IDENTIFY_FIELD_VALIDITY] & bmBIT2)
{
BYTE supportedUdmaModes = 0;
supportedUdmaModes = EP8FIFOBUF[IDENTIFY_UDMA_MODES] & UDMA_MODES;
if (bScsi && !(ATAPI_UDMA_ENABLE))
supportedUdmaModes = 0;
if (!bScsi && !(ATA_UDMA_ENABLE))
supportedUdmaModes = 0;
if (supportedUdmaModes & UDMA_MODE5)
{
ActiveLunConfigData.udmaMode = TRANSFER_MODE_UDMA5;
}
else if (supportedUdmaModes & UDMA_MODE4)
{
ActiveLunConfigData.udmaMode = TRANSFER_MODE_UDMA4;
}
else if (supportedUdmaModes & UDMA_MODE2)
{
ActiveLunConfigData.udmaMode = TRANSFER_MODE_UDMA2;
}
}
commandSetSupport = EP8FIFOBUF[IDENTIFY_COMMAND_SET_SUPPORT];
// We are done with EP8FIFOBUF. reset the EP8FIFO so the internal pointers are pointing
// back at the start of it and then re-enable interrupts.
FIFORESET = 0x08;
EA = oldEA;
// If UDMA is supported, enable it. Then, enable the highest PIO mode
if (bCompactFlash)
{
}
else if (ActiveLunConfigData.udmaMode)
{
configureATATransferMode(ActiveLunConfigData.udmaMode);
}
else
{
// Default waveform is PIO0. Shift up for PIO3 and PIO4
if(ActiveLunConfigData.MaxPIO & PIO4)
{
if (!ActiveLunConfigData.udmaMode)
configureATATransferMode(PIO_MODE4); // SCR_PIO4=0x0C, PIO-mode4
}
else if(ActiveLunConfigData.MaxPIO & PIO3)
{
if (!ActiveLunConfigData.udmaMode)
configureATATransferMode(PIO_MODE3); // SCR_PIO3=0x0B, PIO-mode3
}
}
// enable Advanced Power Management (APM) if supported by the drive and
// specified in the configuration eeprom
if ((commandSetSupport & APM_FEATURE) &&
(APM_VALUE))
{
writeATA_DRIVESEL_REG();
waitForBusyBit();
writePIO8(ATA_SECTOR_COUNT_REG, APM_VALUE);
writePIO8(ATAPI_FEATURE_REG, SET_FEATURE_APM_ENABLE); // write the APM enable sub-command
writePIO8(ATAPI_COMMAND_REG, ATAPI_COMMAND_SET_FEATURES); // execute the command
}
ActiveLunConfigData.driveCapacity -= 1; // The command that reads drive capacity actually wants the last valid LBA.
return;
}
void configureATATransferMode(BYTE mode)
{
// select the drive and set new speed
writeATA_DRIVESEL_REG();
waitForBusyBit();
writePIO8(ATA_SECTOR_COUNT_REG, mode);
writePIO8(ATAPI_FEATURE_REG, 0x03); // opcode 0x03 used for transfer mode
writePIO8(ATAPI_COMMAND_REG, ATAPI_COMMAND_SET_FEATURES); // execute the command
waitForBusyBit();
}
// Timer ISR -- Cannot be placed with the other ISRs because we want the
// compiler to generate the vector.
void ISRtimer0() interrupt 1
{
if (!hertz61ticks--)
{
seconds--;
hertz61ticks = 61;
};
#if ATA_ENABLE_PIN
{
// Check for ATA_ENABLE
// check for tri-state signal on WAKEUP pin. If it's active and we're not tristated,
// reset the CPU
WAKEUPCS = 0x45;
if (WAKEUPCS & 0x40)
{
// Disconnect
USBCS |= bmDISCON;
// Reset the FIFOs
FIFORESET = 8;
ResetAndArmEp2();
// Data bus is already tristated between read/writes
// Tri-state GPIF CTL lines
GPIFCTLCFG = 0x80;
GPIFIDLECTL = 0;
// Tri-state port A
OEA = 0;
// Just sit here until we are re-enabled.
EA = 0; // In case we have higher priority interrupts
while(WAKEUPCS & 0x40)
WAKEUPCS = 0x45; // Write 1 to the bit to clear it.
softReset();
}
}
#endif
#if VBUS_DETECT
// check to see if VBus has gone away. If so, we need to disconnect
// from USB. Likewise, if Vbus is present we need to connect to USB,
if (!VBUS_PRESENT)
{
USBCS |= bmDISCON;
}
else
{
USBCS &= ~bmDISCON;
}
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -