📄 ide.c
字号:
stallEP2OUT();
return(USBS_FAILED);
break;
}
}
void waitForInBuffer()
{
while((EP8CS & bmEPFULL)); // Wait for an available buffer from the host
return;
}
static bit ideReadCommand(bit verify)
{
BYTE driveStatus;
WORD sectorcount;
BYTE i;
WORD wordCtr;
writePIO8(ATA_DRIVESEL_REG, 0xe0);
if (waitForBusyBit() == USBS_FAILED)
{
// 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;
// This loop breaks up the 32 bit length into 8 bits * sectors.
// For example, a read of 0x10000 turns into 0x80 sectors.
while (dataTransferLen)
{
dwLBAtoLBARegs();
// First stuff the length register (number of sectors to read)
if (dataTransferLenMSW & 0xfffe)
{
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 = (dataTransferLenLSW + ATA_SECTOR_SIZE-1)/ATA_SECTOR_SIZE + (dataTransferLenMSW & 1) * 0x80;
writePIO8(ATA_SECTOR_COUNT_REG, 0); // for extended addressing
writePIO8(ATA_SECTOR_COUNT_REG, sectorcount); // divide len into blocks
}
dwLBA += sectorcount;
if (!udmaMode || verify || (dataTransferLenLSW & 0x1ff)) // UDMA cannot handle sub-sector sized reads
{
// Execute the read command
if (bExtAddrSupport)
{
if (verify)
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_VERIFY_10_EXT);
else
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_READ_10_EXT);
}
else
{
if (verify)
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_VERIFY_10);
else
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_READ_10);
}
// The verify command reads from the drive, but doesn't transfer data
// to us.
if (verify)
{
if(waitForBusyBit() == USBS_FAILED)
return(USBS_FAILED);
else
continue;
}
// set up for GPIF transfer - wordwide
//EP8GPIFTCH = MSB(wPacketSize >> 1);
//EP8GPIFTCL = 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)
{
readPIO8(ATAPI_ERROR_REG);
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;
if (wPacketSize == 0x40)
bLimit = 8;
else
bLimit = 1;
for (i = 0; i < bLimit && dataTransferLen; i++)
{
waitForInBuffer();
wThisPacketSize = min(wPacketSize, dataTransferLen);
readPIO16(ATAPI_DATA_REG, wThisPacketSize+1);
while (!gpifIdle()) // Wait for xfer to complete
;
EP8BCH = MSB(wThisPacketSize);
EP8BCL = LSB(wThisPacketSize);
dataTransferLen -= wThisPacketSize;
}
}
}//while (sectorcount--)
}
else // transfer is udma mode
{
initUdmaRead();
if (bExtAddrSupport)
writePIO8(ATAPI_COMMAND_REG, ATA_COMMAND_DMAREAD_RETRY_EXT);
else
writePIO8(ATAPI_COMMAND_REG, ATA_COMMAND_DMAREAD_RETRY);
readUDMA((DWORD) sectorcount << 8); // Words = sectors * 256
driveStatus = readATAPI_STATUS_REG();
if (driveStatus & ATAPI_STATUS_ERROR_BIT)
{
if (readPIO8(ATAPI_ERROR_REG) & ATAPI_ERROR_ICRC_BIT)
{
sensePtr = senseCRCError;
}
// No need to do failedIn() -- All data is already 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()
{
WORD savebc;
BYTE driveStatus;
WORD sectorcount;
BYTE i;
writePIO8(ATA_DRIVESEL_REG, 0xe0);
if (waitForBusyBit() == USBS_FAILED)
{
// 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;
// If there's no data length, just exit once we've freed the CBW buffer
if (!dataTransferLen)
return USBS_PASSED;
// 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)
{
dwLBAtoLBARegs(); // Stuff the LBA registers
// First stuff the length register (number of sectors to write)
if (dataTransferLenMSW & 0xfffe)
{
writePIO8(ATA_SECTOR_COUNT_REG, 0x1); // 1 for ext addr support
writePIO8(ATA_SECTOR_COUNT_REG, 0x0); // 0 means 256 blocks of 512
sectorcount = 0x100;
}
else
{
sectorcount = (dataTransferLenLSW+ATA_SECTOR_SIZE-1)/ATA_SECTOR_SIZE
+ (dataTransferLenMSW & 1) * 0x80;
writePIO8(ATA_SECTOR_COUNT_REG, 0); // 0 for MSB of ext address
writePIO8(ATA_SECTOR_COUNT_REG, sectorcount); // divide len into blocks
}
dwLBA += sectorcount;
if (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) >> 1);
// Check status to clear interrupt.
driveStatus = readATAPI_STATUS_REG();
if (driveStatus & ATAPI_STATUS_ERROR_BIT)
{
driveStatus = readPIO8(ATAPI_ERROR_REG);
if (driveStatus & ATAPI_ERROR_ICRC_BIT)
{
sensePtr = senseCRCError;
}
return(USBS_FAILED);
}
else
{
if (sectorcount == 0x100)
dataTransferLenMSW -= 2;
else
dataTransferLen = 0;
}
}
else
{
// 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)
break;
}
// 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+1); // 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:
if (driveStatus & ATAPI_STATUS_ERROR_BIT)
return(USBS_FAILED);
else
return(USBS_PASSED);
}
// Don't have the ability to sense media (yet)
static bit checkForMedia()
{
return(1);
}
void dwLBAtoLBARegs() // Stuff the LBA registers
{
writePIO8(ATA_DRIVESEL_REG, 0xe0);
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);
}
}
/////////////////////////////////////////////////////////////////////////////////
#endif // DEVICE_TYPE_IS_IDE
/////////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -