📄 ide.c
字号:
{
BYTE pagenum;
pagenum = EP2FIFOBUF[CBW_DATA_START+2] & 0x3F; // identify page (see p.141 SCSI 2ed.)
EP2BCL = 0x80; // relinquish control of the bulk buffer occupied by the CBW
sensePtr = senseOk;
checkForMedia(1);
if (sensePtr != senseOk)
{
failedIn();
return(USBS_FAILED);
}
waitForInBuffer();
if((pagenum != 0x05) && (pagenum != 0x3F)
&& (pagenum != 0x01) && (pagenum != 0x08) && (pagenum != 0x1B))
{ // only respond to requests for certain pages (the mandatory ones plus page 5)
sensePtr = senseInvalidFieldInCDB;
failedIn();
return(USBS_FAILED);
}
// If one of the supported pages is requested, return the 8 byte Mode Parameter Header
// plus a single 12 byte page. Only the Mode Data length (LSB) is significant in the
// Mode Parameter Header. It has a Vendor Specific Medium Type Code in byte 2, and
// a 1 bit WP Write Protect bit in byte 3 that are not initialized here.
// Pages 0x01, and 0x08 do not have significant data - they are spoofed.
// Page 0x1B has a TLUN field in byte 3 that is initialized to 1 (as per ISD).
// Page 0x05 does contain information that is needed to boot to HDD and CDROM.
// Page 0x3F, All Pages, is also responded to.
// The supported pages are (see INF-8070_1_3.pdf p37 Table 25):
// case 0x01: // Read-Write Error Recovery Page
// case 0x08: // Caching Page
// case 0x05: // Flexible Disk Page: needed to boot from USB
// case 0x1B: // Removable Block Access Capabilities Page
// case 0x3F: // All (4) Pages
// The format used is:
// Mode parameter header (4 or 8 bytes)
// Block descriptors (not supported)
// Mode page
EP8FIFOBUF[0] = 0x00;
mymemmovexx(EP8FIFOBUF+1, EP8FIFOBUF, 100-1); // clear buffer - <100 bytes in all responses
AUTOPTRL2 = LSB(EP8FIFOBUF);
if (cmd == MODE_SENSE_10)
{
XAUTODAT2 = MSB(0);
if (pagenum == 0x3f)
XAUTODAT2 = LSB(8-2 + 12*4); // return 12 bytes for each page
else
XAUTODAT2 = LSB(8-2 + 12*1); // return 12 bytes for each page
AUTOPTRL2 = LSB(EP8FIFOBUF) + 8; // The rest of the header is zeroes. Start the pages at byte 8.
}
else
{
if (pagenum == 0x3f)
XAUTODAT2 = LSB(4-1 + 12*4); // Header is 4 bytes long, data from each page is 12 bytes.
else
XAUTODAT2 = LSB(4-1 + 12*1);
AUTOPTRL2 = LSB(EP8FIFOBUF) + 4;
}
if((pagenum == 0x05) || (pagenum == 0x3F))
{
XAUTODAT2 = 5; // fill out the page num - fields are all 0x0
XAUTODAT2 = 12-2; // set individual Page Length -- return 12 for all commands
if(EZUSB_HIGHSPEED())
{
XAUTODAT2 = 0xFF; // HS Transfer Rate (MSB) (field limited to 65Mb/Sec)
XAUTODAT2 = 0xFF; // HS Transfer Rate (LSB)
}
else
{
XAUTODAT2 = 0x2E; // FS Transfer Rate (MSB) (12Mb/Sec)
XAUTODAT2 = 0xE0; // FS Transfer Rate (LSB)
}
XAUTODAT2 = ActiveLunConfigData.NumHeads; // #Heads
XAUTODAT2 = ActiveLunConfigData.NumSectPerTrack; // #SectorsPerTrack
XAUTODAT2 = (ATA_SECTOR_SIZE >> 8) & 0xff; // Data Bytes per sector (truncated)
XAUTODAT2 = (ATA_SECTOR_SIZE >> 0) & 0xff; // Data Bytes per sector
XAUTODAT2 = ActiveLunConfigData.NumCylindersMSB; // #Cyl MSB
XAUTODAT2 = ActiveLunConfigData.NumCylindersLSB; // #Cyl LSB
XAUTODAT2 = 0;
XAUTODAT2 = 0;
}
if(pagenum == 0x1B || pagenum == 0x3f)
{
XAUTODAT2 = 0x1b; // fill out the page num
XAUTODAT2 = 12-2; // set individual Page Length -- return 12 for all commands
XAUTODAT2 = 0;
XAUTODAT2 = 0x01; // set TLUN = 1 for page 0x1B
AUTOPTRL2 += 8; // 8 zeroes too.
}
if(pagenum == 0x1 || pagenum == 0x3f)
{
XAUTODAT2 = 0x1; // fill out the page num
XAUTODAT2 = 12-2; // set individual Page Length -- return 12 for all commands
AUTOPTRL2 += 10; // 10 zeroes too.
}
if(pagenum == 0x8 || pagenum == 0x3f)
{
XAUTODAT2 = 0x8; // fill out the page num
XAUTODAT2 = 12-2; // set individual Page Length -- return 12 for all commands
AUTOPTRL2 += 10; // 10 zeroes too.
}
loadEP8BC(AUTOPTRL2);
sensePtr = senseOk;
return(USBS_PASSED);
} // end case
default:
{
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
sensePtr = senseInvalidOpcode;
failedIn();
return(USBS_FAILED);
}
}
}
bit generalIDEOutCommand()
{
BYTE cmd;
cmd = EP2FIFOBUF[0xf];
switch (cmd)
{
case WRITE_06:
case WRITE_10:
case WRITE_AND_VERIFY_10:
{
sensePtr = senseOk;
checkForMedia(1);
if (sensePtr == senseOk)
{
return(ideWriteCommand(cmd));
}
else
{
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
if (dataTransferLen)
stallEP2OUT();
return(USBS_FAILED);
}
}
///////////////////////////////////////////////////////////
// Spoofed commands
case MODE_SELECT_06: // Note that these are in BOTH the read and write areas in case they are sent with no data
case MODE_SELECT_10:
{
bit bShortPacketReceived = 0;
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
// Toss away all of the data received with the command
while (dataTransferLen && !bShortPacketReceived)
{
if(!(EP2CS & bmEPEMPTY))
{
dataTransferLen -= EP2BC;
if (EP2BC != wPacketSize)
bShortPacketReceived = 1;
EP2BCL = 0x80;
}
}
// This command is allowed to have data.
sensePtr = senseOk;
checkForMedia(1);
if (sensePtr == senseOk)
return(USBS_PASSED);
else
return(USBS_FAILED);
}
default:
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
if (dataTransferLen)
stallEP2OUT();
sensePtr = senseInvalidOpcode;
return(USBS_FAILED);
break;
}
}
void waitForInBuffer()
{
while((EP8CS & bmEPFULL)); // Wait for an available buffer from the host
return;
}
static bit ideReadCommand(BYTE command)
{
BYTE driveStatus;
WORD sectorcount;
BYTE i;
WORD wordCtr;
if (command == VERIFY_10)
dataTransferLen = (DWORD)((EP2FIFOBUF[CBW_DATA_START+7] << (8+9)) + EP2FIFOBUF[CBW_DATA_START+8]) << 9; // Multiplying by ATA_SECTOR_SIZE takes 90 bytes more than this.
switch (command)
{
case READ_06:
{
((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;
break;
}
default:
IDEPrepareForXfer();
}
// This loop breaks up the 32 bit length into 8 bits * sectors.
// For example, a read of 0x10000 turns into 0x80 sectors.
while (dataTransferLen)
{
sectorcount = stuffLBAandSector(1);
if (!ActiveLunConfigData.udmaMode || (command == VERIFY_10) || (dataTransferLenLSW & 0x1ff)) // UDMA cannot handle sub-sector sized reads
{
// Execute the read command
if (bExtAddrSupport)
{
if ((command == VERIFY_10))
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_VERIFY_10_EXT);
else
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_READ_10_EXT);
}
else
{
if ((command == VERIFY_10))
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 ((command == VERIFY_10))
{
if(waitForBusyBit() == USBS_FAILED)
{
loadSensePtrFromErrorRegister(1);
dataTransferLen = 0; // This command has no data but this loop uses dataTransferLen as a counter.
return(USBS_FAILED);
}
else
{
if (sectorcount == 0x100)
dataTransferLenMSW -= 2;
else
dataTransferLen = 0;
continue;
}
}
// Wait for drive non-busy before starting xfer
while (readPIO8(ATAPI_ALT_STATUS_REG) & ATAPI_STATUS_BUSY_BIT)
;
// 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)
{
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;
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);
while (!gpifIdle()) // Wait for xfer to complete
;
OUTATAPI = ATAPI_IDLE_VALUE;
EP8BCH = MSB(wThisPacketSize);
EP8BCL = 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 (!(EP8CS & bmEPEMPTY))
;
FIFORESET = 8;
}
}
}//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
// switch the EP back to manual mode
EP8FIFOCFG = bmZEROLENIN | bmWORDWIDE;
WRITEDELAY();
IFCONFIG = IFCONFIG_DEFAULT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -