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

📄 ide.c

📁 cy68013a USB2.0 highspeed mass storage source code
💻 C
📖 第 1 页 / 共 4 页
字号:
   
         // set up for GPIF transfer - wordwide
         //EP6GPIFTCH = MSB(wPacketSize >> 1);     
         //EP6GPIFTCL = LSB(wPacketSize >> 1);
         
         while (sectorcount--)
         {
            // 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)
                  break;
            }

            // If there's an error, the drive may still want to send us the data.
            if (driveStatus & ATAPI_STATUS_ERROR_BIT)
               {
               loadSensePtrFromErrorRegister(1);
               if (driveStatus & ATAPI_STATUS_DRQ_BIT)
                  for (wordCtr = 0; wordCtr < 0x100; wordCtr++)
                     readPIO8(ATAPI_DATA_REG);
               failedIn();
               return(USBS_FAILED);  
               }
            else
            {
               BYTE bLimit;
               WORD wThisPacketSize;
               BYTE i;

               if (wPacketSize == 0x40)
                  bLimit = 8;
               else 
                  bLimit = 1;
               for (i = 0; i < bLimit && dataTransferLen; i++)
               {
                  waitForInBuffer();

                  wThisPacketSize = min(wPacketSize, dataTransferLen);
                  readPIO16(wThisPacketSize);
                  while (!gpifIdle())     // Wait for xfer to complete
                     ;
                  EP6BCH = MSB(wThisPacketSize);
                  EP6BCL = LSB(wThisPacketSize);
                  dataTransferLen -= wThisPacketSize; 
               }
               // Check for residue at the drive.  If it's there, read it all.
               if (i < bLimit || wThisPacketSize != wPacketSize)
               {
                  while (readATAPI_STATUS_REG() & ATAPI_STATUS_DRQ_BIT)
                      readPIO8(ATAPI_DATA_REG);
                  // Now we have up to 511 bytes of crap in the FIFO.
                  // Wait for the IN endpoint to be empty, then reset the FIFO
                  while (!(EP6CS & bmEPEMPTY))
                     ;
                  FIFORESET = 6;
               }
            }
            wCmdSectorCount -= 0x1;
         }//while (sectorcount--)
      }
      else  // transfer is udma mode
      {
         initUdmaRead();
         if (bExtAddrSupport)
            writePIO8(ATA_COMMAND_REG, ATA_COMMAND_DMAREAD_RETRY_EXT);
         else
            writePIO8(ATA_COMMAND_REG, ATA_COMMAND_DMAREAD_RETRY);
         prepUDMA(MSB(sectorcount),LSB(sectorcount),0);     // (DWORD) sectorcount << 8
         readUDMA();     // Words = sectors * 256

         // switch the EP back to manual mode
         EP6Manual();
         attemptFastRead = 1;
         attemptFastWrite = 0;

         // 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.
         // This is the Hi > Di case.
         if (GPIFTCMSW || GPIFTCLSW)
            {
            if ((GPIFTCLSW & 0xff))      // Check for short packet already sent
               bShortPacketSent = 1;
            failedIn();
            attemptFastRead = 0;
            }

         // Clear the interrupt by reading the status reg.
         while ((driveStatus = readATAPI_STATUS_REG()) & ATAPI_STATUS_BUSY_BIT)
            ;
         if (driveStatus & ATAPI_STATUS_ERROR_BIT) 
            {
            loadSensePtrFromErrorRegister(1);
            if (sensePtr == senseCRCError)
               slowDownOnUDMAErrors();
               
            attemptFastRead = 0;
            // No need to do failedIn() -- Already checked above to see that all data has been xferred.
            return(USBS_FAILED);
            }

         // In the Hi > Di case, we could still not have an error.
         if (attemptFastRead == 0)
            return(USBS_PASSED);

         if (udmaErrorCount)
            udmaErrorCount--;

         if (sectorcount == 0x100)
            {
            dataTransferLenMSW -= 2;
            wCmdSectorCount -= 0x100;
            }
         else
            {
            dataTransferLen23W -= LSB(sectorcount) << 1;
            wCmdSectorCount -= sectorcount;
            }
      }
   }//while (dataTransferLen)

   // This check is active whenever Hi > Dn or Hi > Di.
   if (dataTransferLen)
      {
      failedIn();
      attemptFastRead = 0;
      return (USBS_PASSED);
      }
      
   return(USBS_PASSED);
}   

BYTE ideWriteCommand(BYTE command)
{
   BYTE driveStatus = 0;
   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];

      wCmdSectorCount = EP2FIFOBUF[CBW_DATA_START+4];
      // relinquish control of the bulk buffer occupied by the CBW
      EP2BCL = 0x80;     
      }

   gSectorcount = wCmdSectorCount;     // Save the cmdSectorCount for use in fast writes

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

   // Check for Ho < Do phase error (case 13)
   if (wCmdSectorCount > dataTransferLen23W/2)
      return (USBS_PHASE_ERROR);

   // 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();
      prevDataTransferLen = dataTransferLen;
      mymemmoveix(prevCmd,&EP2FIFOBUF[0x0F],10);  // prepare command buffer for fast write attempt
      }


   // 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 && wCmdSectorCount)
   {
      sectorcount = stuffLBAandSector();
        
      if (ActiveLunConfigData.udmaMode && !(dataTransferLenLSW & 0x1ff)
         )
      {
         // Wait for drive non-busy before starting xfer
         while (readATAPI_ALT_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
            ;

         // Execute the write command
         if (bExtAddrSupport)
            writePIO8(ATA_COMMAND_REG, ATA_COMMAND_DMAWRITE_RETRY_EXT);
         else
            writePIO8(ATA_COMMAND_REG, ATA_COMMAND_DMAWRITE_RETRY);

         attemptFastWrite = 1;
         attemptFastRead = 0;

         if (sectorcount == 0x100)
            prepUDMA(0x1,00,00);     // 64k Transfers = 128K
         else
            prepUDMA(MSB(sectorcount),LSB(sectorcount),0);
         writeUDMA();

         // If the host is still trying to send us data, stall EP2.
         // We must check for data remaining in the current xfer and data remaining in subsequent xfers.
         // 
         if (GPIFTCMSW || GPIFTCLSW)
         {
            stallEP2OUT();
            attemptFastWrite = 0;
            driveStatus = readATAPI_STATUS_REG();
            goto stopOnShortPacketOrError;
         }
         
         // Check status to clear interrupt.
         if ((driveStatus = readATAPI_STATUS_REG()) & ATAPI_STATUS_ERROR_BIT) 
         {
            if (wCmdSectorCount > 0x100)
               stallEP2OUT();
            attemptFastWrite = 0;
            goto stopOnShortPacketOrError;
         }
         else
         {
            if (sectorcount == 0x100)
               {
               dataTransferLenMSW -= 2;
               wCmdSectorCount -= 0x100;
               }
            else
               {
               dataTransferLen23W -= LSB(sectorcount) << 1;
               wCmdSectorCount -= sectorcount;
               }
         }
      }
      else
      {
         attemptFastWrite = 0;
         // Are we finishing an odd-length UDMA?
         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 stopOnShortPacketOrError;
            }
               
            // 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++)
            {
               WORD savebc;

               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(savebc+1);     // Add 1 to allow odd xfers.
                  
                  // This looks wrong, but i is always 0 when wPacketSize is 0x200.
                  dataTransferLen -= savebc + i * 0x40; /*wPacketSize*/
                  goto stopOnShortPacketOrError;
               }
               else
               {
                  EP2BCL = 0;
                  writePIO16(wPacketSize);
               }
            }
            dataTransferLen -= ATA_SECTOR_SIZE; // Returned a full sector.
            wCmdSectorCount -= 0x1;
         }  // while (sectorcount) 
      } // else (if udma)
   } // While (dataTransferLen)
    
   // This check is active whenever Ho > Do or Ho > Dn.
   if (dataTransferLen)
      {
      stallEP2OUT();
      attemptFastWrite = 0;
      }

stopOnShortPacketOrError:
   // cancel AUTO OUT mode, put IFCLK back to normal
   IFCONFIG = IFCONFIG_DEFAULT;
   EP2FIFOCFG = bmZEROLENIN | bmWORDWIDE;

   if (driveStatus & ATAPI_STATUS_ERROR_BIT)
      {
      loadSensePtrFromErrorRegister(0);
      return(USBS_FAILED);
      }

   return(USBS_PASSED);
}


/* This command is only used for removable DRIVES, not removable media.  An example of removable drive is Compact Flash */
// 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)
{
   // 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 (CF_DETECT_ || ejected || !bDRVPWRVLD_ENABLE)
      {
      noFlashMedia = 1;
      
      if (!(IOEShadow & nPWR500))    // Turn off the CF power if it's on
         powerOff();            
      }

   if (bCompactFlash && commandProcessing)  // This check assures that the CF waves get loaded.
      {

      if (CF_DETECT_)      // If the media is gone, there is no reason to keep the ejected flag set.
         ejected = 0;

      // 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 (CF_DETECT_ || ejected || !bDRVPWRVLD_ENABLE || !Configuration)
         {
         sensePtr = senseNoMedia;
         if (!(IOEShadow & nPWR500))    // Turn off the CF power if it's on
            powerOff();             // Turn off the power
         return (0);   
         }
      else  // CF detected case
         {
         // Check for ALL of the following to be true to see if we're resuming from suspend:
         // -- The noFlashMedia flag is cleared (indicating media present)
         // -- We're bus powered
         // -- Power is off, we are resuming from suspend.
         // -- Configuration is set (we have authorization for power)
         if (!noFlashMedia && VBUS_POWERED && (IOEShadow & nPWR500) && Configuration)
            powerOn();

         // If the noFlashMedia flag is set, we're transitioning from no media to media inserted.
         if (noFlashMedia && Configuration)
            {
            // Turn on the power
            // "PWR500 will only be asserted if VBUSPWRD is asserted (or when we don't have a VBUSPWRD input)"
            EZUSB_Delay(10);
            if (VBUS_POWERED)
               powerOn();             // Turn on the power
            else
               {
               // If we don't control the power, we may want to reset the new device.
               // If there are other devices on the bus, this will reset them too, but we have no choice.

⌨️ 快捷键说明

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