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