📄 ide.c
字号:
// 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 + -