⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atareset.c

📁 Cy68013的应用——USB2.0接口转IDE、CF卡接口
💻 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 + -