Quelltext /~heha/basteln/PC/fx2/fx2ata-200917.zip/atareset.c

//-----------------------------------------------------------------------------
//  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