📄 ide.c
字号:
if (!bATA_ENABLED)
{
hardwareReset();
EZUSB_Delay(90);
}
}
EZUSB_Delay(30);
ATAPIIdDevice(); // Identify the device
initDriveAfterReset(); // Set up 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
return(1);
}
WORD stuffLBAandSector() // Stuff the LBA registers
{
WORD sectorcount;
writeATA_DRIVESEL_REG();
waitForBusyBit();
// First stuff the length register (number of sectors to read)
if (wCmdSectorCount & 0xff00)
{
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
{
sectorcount = wCmdSectorCount;
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;
}
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];
((BYTE *) &wCmdSectorCount)[0] = EP2FIFOBUF[CBW_DATA_START+7];
((BYTE *) &wCmdSectorCount)[1] = EP2FIFOBUF[CBW_DATA_START+8];
// 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 EP2Manual()
{
// cancel AUTO OUT mode, put IFCLK back to normal
IFCONFIG = IFCONFIG_DEFAULT;
EP2FIFOCFG = bmZEROLENIN | bmWORDWIDE;
}
void fastReadStart()
{
// bump the LBA to what we think it will be
// dwLBA += *((WORD *) &prevCmd[7]);
// now put the bumped LBA in our previous CBW buffer for later comparison
*((unsigned long *) &prevCmd[2]) = dwLBA;
// get our saved transfer length from the previous transfer
dataTransferLen = prevDataTransferLen;
wCmdSectorCount = gSectorcount; // Retrieve stored value from last command
gSectorcount = stuffLBAandSector();
initUdmaRead();
}
bit fastReadComplete()
{
bit error;
// this is basically from idereadcommand()
while (dataTransferLen)
{
// initUdmaRead();
error = 0;
if (bExtAddrSupport)
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_DMAREAD_RETRY_EXT);
else
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_DMAREAD_RETRY);
prepUDMA(MSB(gSectorcount),LSB(gSectorcount),0);
readUDMA(); // Words = sectors * 256
// 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;
EP6Manual();
failedIn();
error = 1; // Set an error flag here, but don't return yet. Still have to load an error code.
}
if (readATAPI_STATUS_REG() & ATAPI_STATUS_ERROR_BIT)
{
loadSensePtrFromErrorRegister(1);
// No need to do failedIn() -- Already checked above to see that all data has been xferred.
EP6Manual();
return(USBS_FAILED);
}
// If the xfer failed but the drive didn't detect an error, ask the host to retry by setting a CRC error
else if (error)
{
sensePtr = senseCRCError;
EP6Manual();
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 (gSectorcount == 0x100)
{
dataTransferLenMSW -= 2;
gSectorcount = stuffLBAandSector();
}
else
dataTransferLen = 0;
}//while (dataTransferLen)
attemptFastRead = 1;
EP6Manual();
return(USBS_PASSED);
}
void fastWriteStart()
{
// now put the bumped LBA in our previous CBW buffer for later comparison
*((unsigned long *) &prevCmd[2]) = dwLBA;
// get our saved transfer length and sector count from the previous transfer
dataTransferLen = prevDataTransferLen;
wCmdSectorCount = gSectorcount;
gSectorcount = stuffLBAandSector();
}
bit fastWriteComplete()
{
// We cannot do this until we process the CBW! Don't move it into fastReadStart
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)
{
// 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;
if (gSectorcount == 0x100)
prepUDMA(0x1,00,00); // 64k Transfers = 128K
else
prepUDMA(MSB(gSectorcount),LSB(gSectorcount),0);
writeUDMA();
if ((GPIFTCMSW || GPIFTCLSW))
{
stallEP2OUT();
attemptFastWrite = 0;
goto stopOnShortPacket;
}
// Check status to clear interrupt.
if (readATAPI_STATUS_REG() & ATAPI_STATUS_ERROR_BIT)
{
goto stopOnShortPacket;
}
else
{
// Two choices -- Either we're limited to 0x100 sectors, or limited to dataTransferLen.
if (gSectorcount == 0x100)
{
dataTransferLenMSW -= 2;
gSectorcount = stuffLBAandSector();
}
else
{
dataTransferLen = 0; // This will terminate the loop anyway. The break; just makes it faster
break;
}
}
} // While (dataTransferLen)
stopOnShortPacket:
EP2Manual();
if (readATAPI_STATUS_REG() & ATAPI_STATUS_ERROR_BIT)
{
loadSensePtrFromErrorRegister(0);
attemptFastWrite = 0;
return(USBS_FAILED);
}
else
return(USBS_PASSED);
}
/////////////////////////////////////////////////////////////////////////////////
#endif // DEVICE_TYPE_IS_IDE
/////////////////////////////////////////////////////////////////////////////////
void waitForInBuffer()
{
while((EP2468STAT & bmEP6FULL)); // Wait for an available buffer from the host
return;
}
void writeATA_DRIVESEL_REG()
{
writePIO8(ATA_DRIVESEL_REG, 0xe0 | ((BYTE)bMasterSlave << 4));
}
#if DEVICE_TYPE_IS_IDE || ATACB_ENABLE
void EP6Manual()
{
// switch the EP back to manual mode
EP6FIFOCFG = bmZEROLENIN | bmWORDWIDE;
WRITEDELAY();
IFCONFIG = IFCONFIG_DEFAULT;
}
////////////////////////////////////////////////////////////////
//
// loadEP6BC()
//
// Sends a short (less than one packet) response back to the host. If the host asked for 0
// length data, don't send anything.
//
/////////////////////////////////////////////////////////////////
void loadEP6BC(WORD dataLen)
{
WORD packetLen;
bit bPaddedPacket = 0;
// If the host asked for 0 data, give him 0 data!
if (!dataTransferLenLSW)
return;
packetLen = min(dataTransferLen, dataLen);
if (packetLen || (SHORT_PACKET_BEFORE_STALL))
{
// pad the really short responses
if (dataTransferLen <= wPacketSize)
{
bPaddedPacket = 1;
EP6BCH = MSB(dataTransferLenLSW);
EP6BCL = LSB(dataTransferLenLSW);
}
else
{
EP6BCH = MSB(packetLen);
EP6BCL = LSB(packetLen);
}
dataTransferLen -= packetLen;
}
if (packetLen & (wPacketSize - 1))
bShortPacketSent = 1;
if (!bPaddedPacket)
failedIn(); // This doesn't set status, just STALLs the IN endpoint if needed.
}
#endif
BYTE flushCache()
{
writeATA_DRIVESEL_REG();
sensePtr = senseOk;
checkForMedia(1);
if (sensePtr != senseOk)
return(USBS_FAILED);
waitForBusyBit();
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_FLUSH_CACHE);
waitForBusyBit();
return (USBS_PASSED);
}
#if STANDBY_IMMEDIATE
// Added for power saving on HDD devices in systems WITHOUT CF
// Only writes to the current LUN. Multiple LUNs not supported.
void standbyImmediate()
{
if (driveIsInStandby)
return;
driveIsInStandby = 1;
writeATA_DRIVESEL_REG();
waitForBusyBit();
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_STANDBY_IMMEDIATE);
waitForBusyBit();
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -