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

📄 ide.c

📁 Cy68013的应用——USB2.0接口转IDE、CF卡接口
💻 C
📖 第 1 页 / 共 3 页
字号:

         // If there's anything left in the count regs, we've got a problem.  
         // We will have to STALL in the IN endpoint to stop the host.
         if (GPIFTCMSW || GPIFTCLSW)
            {
            if ((GPIFTCLSW & 0xff))      // Check for short packet already sent
               bShortPacketSent = 1;
            failedIn();
            }

         driveStatus = readATAPI_STATUS_REG();
         if (driveStatus & ATAPI_STATUS_ERROR_BIT) 
            {
            loadSensePtrFromErrorRegister(1);
            // No need to do failedIn() -- Already checked above to see that all data has been xferred.
            return(USBS_FAILED);
            }

         // Two choices -- Either we're limited to 0x100 sectors, or limited to dataTransferLen.
         // BUGBUG -- No capability here to report Hi > Di.
         if (sectorcount == 0x100)
            dataTransferLenMSW -= 2;
         else
            dataTransferLen = 0;
      }
   }//while (dataTransferLen)
   
   return(USBS_PASSED);
}   

static bit ideWriteCommand(BYTE command)
{
   WORD savebc;
   BYTE driveStatus;
   WORD sectorcount; 
   BYTE i; 
   
   if (command != WRITE_06)
      IDEPrepareForXfer();
   else
      {
      ((BYTE *) &dwLBA)[0] = 0;
      ((BYTE *) &dwLBA)[1] = EP2FIFOBUF[CBW_DATA_START+1] & 0x1f;
      ((BYTE *) &dwLBA)[2] = EP2FIFOBUF[CBW_DATA_START+2];
      ((BYTE *) &dwLBA)[3] = EP2FIFOBUF[CBW_DATA_START+3];

      // relinquish control of the bulk buffer occupied by the CBW
      EP2BCL = 0x80;     
      }

   // If there's no valid data length, just exit once we've freed the CBW buffer
   if (dataTransferLen < ATA_SECTOR_SIZE)
      return USBS_PASSED;

   // If we're going to do DMA, set up the FIFO ONE time before we start
   // It's safe to init while a transfer is taking place, but risky to switch back to manual mode
   // during a transfer.
   if (ActiveLunConfigData.udmaMode && !(dataTransferLenLSW & 0x1ff))
      initUdmaWrite();

   // Send the command to the drive
   // This loop breaks up the 32 bit length into 8 bits * sectors.
   // For example, a read of 0x10000 turns into 0x80 sectors.
   while (dataTransferLen >= ATA_SECTOR_SIZE)
   {
      // Wait for drive non-busy before starting xfer
      while (readPIO8(ATAPI_ALT_STATUS_REG) & ATAPI_STATUS_BUSY_BIT)
         ;

      sectorcount = stuffLBAandSector(0);
        
      if (ActiveLunConfigData.udmaMode && !(dataTransferLenLSW & 0x1ff))
      {
         // Execute the write command
         if (bExtAddrSupport)
            writePIO8(ATA_COMMAND_REG, ATA_COMMAND_DMAWRITE_RETRY_EXT);
         else
            writePIO8(ATA_COMMAND_REG, ATA_COMMAND_DMAWRITE_RETRY);
         
         if (sectorcount == 0x100)
            writeUDMA((DWORD)0x10000);     // 64k Transfers = 128K
         else
            writeUDMA((dataTransferLen) >> 1);
         
         // Check status to clear interrupt.
         driveStatus = readATAPI_STATUS_REG();
         
         if (driveStatus & ATAPI_STATUS_ERROR_BIT) 
         {
            loadSensePtrFromErrorRegister(0);
            return(USBS_FAILED);
         }
         else
         {
            if (sectorcount == 0x100)
               dataTransferLenMSW -= 2;
            else
               dataTransferLen = 0;
         }
      }
      else
      {
         if (ActiveLunConfigData.udmaMode)
         {
            // cancel AUTO OUT mode.  
            EP2FIFOCFG = bmWORDWIDE;
            WRITEDELAY();
            IFCONFIG = IFCONFIG_DEFAULT;
         }
         // Execute the write command
         if (bExtAddrSupport)
            writePIO8(ATA_COMMAND_REG, ATA_COMMAND_WRITE_10_EXT);
         else
            writePIO8(ATA_COMMAND_REG, ATA_COMMAND_WRITE_10);
         
         while (sectorcount--)
         {
            BYTE limit;
   
            // Wait for the drive to be non-busy and have either data or an error
            while (1)
            {
               driveStatus = readATAPI_STATUS_REG();                             
               if ((driveStatus & (ATAPI_STATUS_BUSY_BIT | ATAPI_STATUS_DRQ_BIT)) == ATAPI_STATUS_DRQ_BIT)
                  break;
               if ((driveStatus & (ATAPI_STATUS_BUSY_BIT | ATAPI_STATUS_ERROR_BIT)) == ATAPI_STATUS_ERROR_BIT)
                  goto stopOnShortPacket;
            }
               
            // Normal case -- Got a sector.  Send it to the drive (in 8 chunks)
            if (wPacketSize == 0x40)
               limit = 8;
            else
               limit = 1;
   
            for (i = 0; i < limit; i++)
            {
               while(EP2CS & bmEPEMPTY);       // Wait for host to send data
               savebc = (EP2BCH << 8) | EP2BCL;
                   
               // Terminate xfer on receipt of short packet, otherwise drop
               // into streamlined case
               if (savebc < wPacketSize)
               {
                  EP2BCL = 0;
                  writePIO16(ATAPI_DATA_REG, savebc);     // Add 1 to allow odd xfers.
                  
                  dataTransferLen -= savebc + i * wPacketSize;
                  goto stopOnShortPacket;
               }
               else
               {
                  EP2BCL = 0;
                  writePIO16(ATAPI_DATA_REG, wPacketSize);
               }
            }
            dataTransferLen -= ATA_SECTOR_SIZE; // Returned a full sector.
         }  // while (sectorcount) 
      } // else (if udma)
   } // While (dataTransferLen)
    
stopOnShortPacket:
   // cancel AUTO OUT mode, put IFCLK back to normal
   if (!bCompactFlash)
      EP2FIFOCFG = bmWORDWIDE;
   WRITEDELAY();
   IFCONFIG = IFCONFIG_DEFAULT;

   if (readATAPI_STATUS_REG() & ATAPI_STATUS_ERROR_BIT)
      {
      loadSensePtrFromErrorRegister(0);
      return(USBS_FAILED);
      }
   else
      return(USBS_PASSED);
}


/* This command is only used for removable DRIVES, not removable media.  An example of removable drive is Compact Flash */
//static bit checkForMedia()
//{
//   return(1);
//}

WORD stuffLBAandSector(bit readWrite)      // Stuff the LBA registers
{
   WORD sectorcount;

   writeATA_DRIVESEL_REG();

   // First stuff the length register (number of sectors to read)
   if (dataTransferLenMSW & 0xfffe)
   {
      if (bExtAddrSupport)
         writePIO8(ATA_SECTOR_COUNT_REG, 1);     // if (bExtAddrSupport) we need to stuff the MSB
      writePIO8(ATA_SECTOR_COUNT_REG, 0);     // 0 means 256 blocks of 512 bytes -- Max drive xfer, max TC
      sectorcount = 0x100;
   }
   else
   {
      // Round sectorcount up for reads, down for writes
      if (readWrite)
         sectorcount = (dataTransferLenLSW + ATA_SECTOR_SIZE-1)/ATA_SECTOR_SIZE + (dataTransferLenMSW & 1) * 0x80;
      else
         sectorcount = (dataTransferLenLSW)/ATA_SECTOR_SIZE + (dataTransferLenMSW & 1) * 0x80;

      if (bExtAddrSupport)
         writePIO8(ATA_SECTOR_COUNT_REG, 0);      // for extended addressing
      writePIO8(ATA_SECTOR_COUNT_REG, sectorcount);       // divide len into blocks
   }

   if (bExtAddrSupport)
      {
      writePIO8(ATA_LBA_LSB_REG,  ((BYTE *) &dwLBA)[0]);    // LBA (31:24)
      writePIO8(ATA_LBA_2SB_REG,  0);                       // LBA (39:32)
      writePIO8(ATA_LBA_MSB_REG,  0);                       // LBA (47:40)
      }

   writePIO8(ATA_LBA_LSB_REG,  ((BYTE *) &dwLBA)[3]);    // LBA (7:0)
   writePIO8(ATA_LBA_2SB_REG,  ((BYTE *) &dwLBA)[2]);    // LBA (15:8)
   writePIO8(ATA_LBA_MSB_REG,  ((BYTE *) &dwLBA)[1]);    // LBA (23:16)

   if (!bExtAddrSupport)
      {      
      writePIO8(ATA_DRIVESEL_REG, ((BYTE *) &dwLBA)[0] | 0xe0 | ((BYTE)bMasterSlave << 4));
      }

   dwLBA += sectorcount;
   return sectorcount;
}

void writeATA_DRIVESEL_REG()
{
   writePIO8(ATA_DRIVESEL_REG, 0xe0 | ((BYTE)bMasterSlave << 4));
}


static void IDEPrepareForXfer()
{
   writeATA_DRIVESEL_REG();
   waitForBusyBit();
      // Oddly enough, an error bit is okay here.  It means that the LAST command failed, not this one.
      // A new command is required to clear many error conditions.
    
   ((BYTE *) &dwLBA)[0] = EP2FIFOBUF[CBW_DATA_START+2];
   ((BYTE *) &dwLBA)[1] = EP2FIFOBUF[CBW_DATA_START+3];
   ((BYTE *) &dwLBA)[2] = EP2FIFOBUF[CBW_DATA_START+4];
   ((BYTE *) &dwLBA)[3] = EP2FIFOBUF[CBW_DATA_START+5];

   // relinquish control of the bulk buffer occupied by the CBW
   EP2BCL = 0x80;     
}

static BYTE loadSensePtrFromErrorRegister(bit readWrite)
{  
   BYTE error;

   error = readPIO8(ATAPI_ERROR_REG);
   if (!error)
      sensePtr = senseOk;
   else if (error & 0x80)       // CRC
      sensePtr = senseCRCError;
   else if (error & 0x02)  // No media present
      sensePtr = senseNoMedia;
   else if (error & 0x20)  // Media changed
      sensePtr = senseMediaChanged;
   else if (error & 0x10)  // Addr out of range 
      sensePtr = senseAddrNotFound;
   else if (error & 0x40)  // Uncorrectable read error / Write Protect
      {
      if (readWrite)
         sensePtr = senseReadError;
      else 
         sensePtr = senseWriteProtected;
      }
   else if (error & 0x08)  // Media change requested -- No good translation for this one.
      sensePtr = senseInvalidOpcode;
   else if (error & 0x04)  // Command not supported or CRC error or request out of range
      {
      if (readWrite)
         sensePtr = senseReadError;
      else 
         sensePtr = senseWriteFault;
      }
   else
      sensePtr = senseInvalidOpcode;

   return(error);
}

void loadEP8BC(WORD dataLen)
{
   WORD packetLen;

   packetLen = min(dataTransferLen, dataLen);
   if (packetLen || (SHORT_PACKET_BEFORE_STALL))
   {
      EP8BCH = MSB(packetLen);
      EP8BCL = LSB(packetLen);
   
      dataTransferLen -= packetLen;
   }
}

// Check to see if a new CF is inserted.  Called before executing every command to make sure
// we have media.  Called from TD_Poll to detect status changes between host activity.
// If we're not looking at a CF device, still check for CF but return 1 -- Media here.  
//
// Input -- commandProcessing:  When set to 0, we will not modify the sensePtr, we will just look for CF changes.
bit checkForMedia(bit commandProcessing)
{
   #if COMPACT_FLASH
   // Check for new media every time, not just when the last command addressed a CF
   // If there's no media, just set the noFlashMedia flag.  If the host tries to execute
   // a command w/o media, we report "no media".
   // On the transition from no media to media, we must wait until the host tries to 
   // send a command, then report "media changed".
   if (OUTATAPI & CF_DETECT_)
      {
      noFlashMedia = 1;
      }

   if (bCompactFlash && commandProcessing)
      {
      // If there's no media, the noMedia flag will be set above.  Just load sensePtr and return.
      // We cannot do this above because we the CF only owns the sensePtr when its LUN is selected.
      if (OUTATAPI & CF_DETECT_)
         {
         sensePtr = senseNoMedia;
         return (0);   
         }
      else  // CF detected case
         {
         // If the noFlashMedia flag is set, we're transitioning from no media to media inserted.
         if (noFlashMedia)
            {
            //bFirstTime = 1;         // Force hard reset, no matter what
            //resetATAPIDevice();
            cfHardwareReset();

            ATAPIIdDevice();        // Identify the device

            // move the drive identification stuff to LUN0.  Compact flash is always LUN0.
            LunBits[0] = ActiveLunBits;
            mymemmove((BYTE *)&DeviceConfigData[0],(BYTE *)&ActiveLunConfigData, sizeof(DEVICE_CONFIG_DATA));
            sensePtr = senseMediaChanged;
            noFlashMedia = 0;
            return (0);       // 0 will force the code through the error path.
            }
         return (1);
         }
      }
   else
   #endif
      return(1);
}
/////////////////////////////////////////////////////////////////////////////////
#endif      // DEVICE_TYPE_IS_IDE
/////////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -