//-----------------------------------------------------------------------------
// Copyright (c) 1999-2001 Cypress Semiconductor, Inc. All rights reserved
//-----------------------------------------------------------------------------
//
// This file contains the device initialization code.
//
// $Workfile: atareset.c $
// $Date: 6/30/05 10:48a $
// $Revision: 6 $
//-----------------------------------------------------------------------------
#include "fx2.h"
#include "fx2regs.h"
#include "gpif.h"
#include "globals.h"
// Cannot define these in "globals" because then they will end up in halfKbuffer
MX2_CONFIG_DATA xdata mx2_config_data;
static void detectSCSIvsATA() {
EZUSB_Delay(8); // 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 passing self-test result
if (!readPIO8(ATAPI_ERROR_REG)) 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(0);
if ((readATAPI_ALT_STATUS_REG() & (ATAPI_STATUS_DRQ_BIT | ATAPI_STATUS_ERROR_BIT)) == ATAPI_STATUS_DRQ_BIT) {
bit oldEA = EA;
EA = 0;
FetchDeviceIdentifyIntoEp6();
// Add a hack for Takaya CD1016 -- Needs recovery time after ID command
EZUSB_Delay(1);
bDevicePresent = 1;
EA = oldEA;
}
// else if (readATAPI_STATUS_REG())
// bDevicePresent = 1;
}
static 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();
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);
}
if (mx2_config_data.delayAfterReset) EZUSB_Delay(mx2_config_data.delayAfterReset * 20);
else EZUSB_Delay(DELAY_AFTER_RESET);
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// ATAInit() -- Drive reset and discovery
//
// Inputs:
// DeviceCount -- Determines if drive discovery variables must be initialized
// bFirstTime -- Determines if drive discovery is necessary
//
// Outputs:
// deviceCount -- Set from 0x8x to 1 or 2 when the drive count is known.
// LunBits[] -- set to reflect drive parameters
// bFirstTime -- cleared when this routine is completed
//
///////////////////////////////////////////////////////////////////////////////////////////
void ATAInit()
{
BYTE j;
if (bFirstTime || deviceCount > 0x7f)
{
// Locally initialize globals used by ATAInit.
deviceCount = 0x80;
LunBitsH = LunBitsL = ActiveLunBits = 0; // zeroes out bCompactFlash, bScsi, bExtAddrSupport
// if there is a CF device, increment our deviceCount so that any detected
// ATA/ATAPI devices get assigned to LUN1
if (bDRVPWRVLD_ENABLE)
deviceCount = 0x81;
}
if (ATA_ENABLED)
{
resetATAPIDevice();
// keep searching for ATA/ATAPI device until we find at least one
if (deviceCount > 0x7f) // syk
{
while (!(LunBitsL || LunBitsH))
{
for (j=(deviceCount & 3);j<MAX_LUN;j++)
{
// Clearing ActiveLunBits clears the bMasterSlaveBit (i.e. we will search for the master the next time
// through this loop)
ActiveLunBits = 0;
bMasterSlave = j;
detectSCSIvsATA();
if (bDevicePresent)
{
if (deviceCount&1) LunBitsH=ActiveLunBits; else LunBitsL=ActiveLunBits;
deviceCount++;
}
}
if (!(LunBitsL || LunBitsH))
if (bDRVPWRVLD_ENABLE)
{
// Cycle power on the CF if it seems to be interfering
IOEShadow |= nPWR500; // Turn off the power
IOE = IOEShadow;
EZUSB_Delay(10);
IOEShadow &= ~nPWR500; // Turn on the power
IOE = IOEShadow;
EZUSB_Delay(10);
}
}
for (currentLunNum=0;currentLunNum<(deviceCount&3);currentLunNum++)
{
ActiveLunBits = currentLunNum&1?LunBitsH:LunBitsL;
if (bDevicePresent)
{
FIFORESET = 0x06; // Make sure that the IN buffer is empty
ATAPIIdDevice();
mymemmove((BYTE *)&DeviceConfigData[currentLunNum],(BYTE *)&ActiveLunConfigData, sizeof(DEVICE_CONFIG_DATA));
if (currentLunNum&1) LunBitsH=ActiveLunBits; else LunBitsL=ActiveLunBits;
}
}
}
}
if (bDRVPWRVLD_ENABLE)
{
ActiveLunBits = 0;
bDevicePresent = 1;
bCompactFlash = 1;
bMasterSlave = 0; // CF is always the master
LunBitsL = ActiveLunBits;
}
for (currentLunNum = 0; currentLunNum < (deviceCount & 3); currentLunNum++)
{
ActiveLunBits = currentLunNum&1 ? LunBitsH : LunBitsL;
mymemmove((BYTE *)&ActiveLunConfigData,(BYTE *)&DeviceConfigData[currentLunNum], sizeof(DEVICE_CONFIG_DATA));
if (!bCompactFlash) // Compact Flash is configured when it's detected, not at startup.
initDriveAfterReset(); // Take info collected into activeLunConfigData and configure the drive.
}
deviceCount &= 0x3; // Clear flag bits
bFirstTime = 0;
// CompactFlash hasn't loaded it's waves yet. Force gear shift on first msg.
currentLunNum = 0xff;
}
// PIO3 waves are PIO waves but with 6 instead of 4 in the wave 0 and wave 1 lenbr field
// 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 SendDeviceIdentifyCommand(bit waitForINTRQ)
{
// do
{
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.
// SYK -- I'm not sure I believe this. 8.13.5 says that you must set DRDY on completion.
// We use this command for two reasons. One is to get the info, the other is as part of
// drive detection. The drive detection algorithm takes care of command completion on its own.
if (waitForINTRQ)
WAIT_FOR_INTRQ();
readATAPI_STATUS_REG(); // Clear the INTRQ
waitForBusyBit();
}
// This function reads device IDENTIFY data from the drive and into EP6FIFOBUF. 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 EP6FIFOBUF that could
// occur if a USB reset happens.
void FetchDeviceIdentifyIntoEp6() {
BYTE saveIt = EP6FIFOCFG;
// Read the data from the drive. EP6FIFOBUF is used to store the data since we only
// need it temporarily.
EP6FIFOCFG = saveIt & 0xF7; // disable automode
readPIO16(ATA_SECTOR_SIZE);
while (!gpifIdle()); // wait for the read to complete before continuing
OUTATAPI = (BYTE)(ATAPI_IDLE_VALUE);
EP6FIFOCFG = saveIt; // re-enable automode if it was set before.
}
void ATAPIIdDevice() {
bit oldEA;
SendDeviceIdentifyCommand(1);
// The code used to wait here until it saw the DRDY bit (0x40. This bit is obsolete, but still supported by almost all devices.
// However, the TEAC CRN8245 drive will respond with ONLY the ATAPI_STATUS_DRQ_BIT set.
// This was kind of overkill anyway, since the INTRQ line has already indicated that the device is done with the command.
while (!(readATAPI_STATUS_REG() & ATAPI_STATUS_DRQ_BIT));
// We need to disable interrupts while using EP6FIFOBUF. 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 EP6 FIFO.
// It would be bad if that happened just as we were reading drive data into EP6FIFOBUF.
// The following code segment will complete in a deterministic amount of time.
oldEA = EA;
EA = 0;
FetchDeviceIdentifyIntoEp6();
// Add a hack for Takaya CD1016 -- Needs recovery time after ID command
EZUSB_Delay(1);
#if CSM_SUPPORT
mymemmovexx(CSMSerial, EP6FIFOBUF+ATAPI_INQUIRY_SERIAL, IDE_ID_SERIAL_LEN);
#endif
#if USE_ATAPI_DEVICE_SERIAL_NUMBER || USE_ATA_DEVICE_SERIAL_NUMBER
if ((bScsi && USE_ATAPI_DEVICE_SERIAL_NUMBER) || (!bScsi && USE_ATA_DEVICE_SERIAL_NUMBER)) {
BYTE xdata *ptr = &halfKBuffer[(BYTE) &SerialNumberStringDscrOffset + 2];
BYTE len = (halfKBuffer[(BYTE) &SerialNumberStringDscrOffset] >> 1) - 1; // Structure len is bytes, we want unicode (words)
BYTE i;
for (i=0;i<len;i++, ptr += 2) {
BYTE mychar = EP6FIFOBUF[i+ATAPI_INQUIRY_SERIAL];
#if NIBBLE_CONVERT_SERIAL_NUMBER
{
BYTE serialChar = (mychar >> 4) + '0';
if (serialChar > '9') serialChar += 'A' - '9' - 1;
*ptr = serialChar;
ptr += 2;
i++;
serialChar = (mychar & 0x0F) + '0';
if (serialChar > '9') serialChar += 'A' - '9' - 1;
*ptr = serialChar;
}
#else
*ptr = mychar;
#endif
}
}
#endif
// 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 (EP6FIFOBUF[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] = EP6FIFOBUF[0+IDE_ID_TOTAL_48_BIT_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[2] = EP6FIFOBUF[1+IDE_ID_TOTAL_48_BIT_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[1] = EP6FIFOBUF[2+IDE_ID_TOTAL_48_BIT_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[0] = EP6FIFOBUF[3+IDE_ID_TOTAL_48_BIT_SECTORS_LSW];
}else{
bExtAddrSupport = 0;
// This is actually smaller than a loop of 4!!
((BYTE *)&ActiveLunConfigData.driveCapacity)[3] = EP6FIFOBUF[0+IDE_ID_TOTAL_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[2] = EP6FIFOBUF[1+IDE_ID_TOTAL_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[1] = EP6FIFOBUF[2+IDE_ID_TOTAL_SECTORS_LSW];
((BYTE *)&ActiveLunConfigData.driveCapacity)[0] = EP6FIFOBUF[3+IDE_ID_TOTAL_SECTORS_LSW];
}
ActiveLunConfigData.NumCylindersMSB = EP6FIFOBUF[IDENTIFY_NUM_CYLINDERS_MSB];
ActiveLunConfigData.NumCylindersLSB = EP6FIFOBUF[IDENTIFY_NUM_CYLINDERS_LSB];
ActiveLunConfigData.NumHeads = EP6FIFOBUF[IDENTIFY_NUM_HEADS];
ActiveLunConfigData.NumSectPerTrack = EP6FIFOBUF[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 = EP6FIFOBUF[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 (EP6FIFOBUF[IDENTIFY_FIELD_VALIDITY] & 0x04) {
BYTE supportedUdmaModes = 0;
supportedUdmaModes = EP6FIFOBUF[IDENTIFY_UDMA_MODES] & UDMA_MODES;
if (bScsi && !(ATAPI_UDMA_ENABLE)) supportedUdmaModes = 0;
if (!bScsi && !(ATA_UDMA_ENABLE)) supportedUdmaModes = 0;
if (bCompactFlash && !bCF_USES_UDMA) 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;
}
// Check for DMA
if (!ActiveLunConfigData.udmaMode) {
BYTE supportedDmaModes = 0;
supportedDmaModes = EP6FIFOBUF[IDENTIFY_DMA_MODES] & DMA_MODES;
if (bCompactFlash && !bCF_USES_UDMA) supportedDmaModes = 0;
if (supportedDmaModes & DMA_MODE2) ActiveLunConfigData.udmaMode = TRANSFER_MODE_DMA2;
}
ActiveLunConfigData.commandSetSupport = EP6FIFOBUF[IDENTIFY_COMMAND_SET_SUPPORT];
// We are done with EP6FIFOBUF. reset the EP6FIFO so the internal pointers are pointing
// back at the start of it and then re-enable interrupts.
FIFORESET = 0x06;
EA = oldEA;
initDriveAfterReset();
ActiveLunConfigData.driveCapacity -= 1; // The command that reads drive capacity actually wants the last valid LBA.
}
void configureATATransferMode(BYTE mode) {
if (setFeatures(0x3, mode) == USBS_FAILED)
if ((mode & TRANSFER_MODE_UDMA0) || (mode & TRANSFER_MODE_DMA0))
ActiveLunConfigData.udmaMode = DeviceConfigData[currentLunNum].udmaMode = 0;
}
bit setFeatures(BYTE command, BYTE subcommand) {
// select the drive and set new speed
writeATA_DRIVESEL_REG();
waitForBusyBit();
writePIO8(ATA_SECTOR_COUNT_REG, subcommand);
writePIO8(ATAPI_FEATURE_REG, command); // opcode 0x03 used for transfer mode
writePIO8(ATAPI_COMMAND_REG, ATAPI_COMMAND_SET_FEATURES); // execute the command
return waitForBusyBit();
}
void ISRINT4() interrupt 10 {
if (!(EP01STAT & bmEP1INBSY)) {
EP1INBUF[0] = IOE >> 2;
EP1INBUF[1] = (USBCS&0x80 ? 2 : 0) | VBUSPWRD;
EP1INBC = 2;
}
// Clear the interrupt
EXIF &= ~bmIE4;
}
// 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;
}
// Check for ATA_ENABLE
// check for tri-state signal on WAKEUP pin. If it's active and we're not tristated,
// reset the CPU
checkATAEnable();
#if HID_SUPPORT
if (!(USBCS & bmDISCON)) {
BYTE buttons = (IOE & 0x7f) | ((IOA & 0x08) << 4);
if (oldButtons != buttons) {
if (!(EP01STAT & bmEP1INBSY)) {
EP1INBUF[0] = buttons;
EP1INBUF[1] = (USBCS&0x80 ? 2 : 0) | VBUSPWRD;
EP1INBC = 2;
oldButtons = buttons;
}
}
}
#endif
}
void initDriveAfterReset() {
// 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 ((ActiveLunConfigData.commandSetSupport & APM_FEATURE) && (APM_VALUE)) {
setFeatures(SET_FEATURE_APM_ENABLE, APM_VALUE);
}
}
| Vorgefundene Kodierung: ASCII (7 bit) | 2
|