📄 ide.c
字号:
else // STOP_START_UNIT:
{
if (options & 0xf0)
{
if ((options & 0xf0) > 0x10 &&
(options & 0xf0) < 0x70)
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_STANDBY_IMMEDIATE);
}
else if ((options & 3) == 2)
{
if (bCompactFlash)
ejected = 1;
else
writePIO8(ATA_COMMAND_REG, ATA_COMMAND_MEDIA_EJECT);
}
}
waitForBusyBit();
if (readATAPI_STATUS_REG() & ATAPI_STATUS_ERROR_BIT)
{
BYTE error = loadSensePtrFromErrorRegister(1);
if (error & 4) // command not supported -- Non removable media, return PASS
{
sensePtr = senseOk;
return(USBS_PASSED);
}
else if ((error & 2) && (options & 3) == 2)
sensePtr = senseCantEject;
return(USBS_FAILED);
}
else
return(USBS_PASSED);
break;
}
case MODE_SENSE_06:
case MODE_SENSE_10:
{
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
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
EP6FIFOBUF[0] = 0x00;
mymemmovexx(EP6FIFOBUF+1, EP6FIFOBUF, 200-1); // clear buffer - <200 bytes in all responses
if (cmd == MODE_SENSE_10)
{
AUTOPTRL2 = LSB(EP6FIFOBUF) + 8; // The rest of the header is zeroes. Start the pages at byte 8.
}
else
{
AUTOPTRL2 = LSB(EP6FIFOBUF) + 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 (bENABLE_WRITE_CACHE_MODE_PAGE)
if(pagenum == 0x8 || pagenum == 0x3f)
{
XAUTODAT2 = 0x8; // fill out the page num
XAUTODAT2 = 0x14-2; // set individual Page Length -- 0x14
XAUTODAT2 = bWriteCacheDisabled ? 0 : 4; // Report write cache enabled or disabled.
AUTOPTRL2 += 13-3; // Skip to the # of cache segments area (byte 13, we've done 3 so far)
XAUTODAT2 = 0x10; // 10 Cache segments
XAUTODAT2 = 0x10; // 4K (this is fake data!)
XAUTODAT2 = 0x00;
AUTOPTRL2 += 4; // Skip the last 4 bytes
}
if (cmd == MODE_SENSE_10)
EP6FIFOBUF[1] = AUTOPTRL2-2;
else
EP6FIFOBUF[0] = AUTOPTRL2-1;
loadEP6BC(AUTOPTRL2);
sensePtr = senseOk;
return(USBS_PASSED);
} // end case
////////////////////////////////////////////////////////////////
// Check for phase error -- Write in a read wrapper
case WRITE_10:
case WRITE_AND_VERIFY_10:
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
sensePtr = senseInvalidOpcode;
failedIn();
return(USBS_PHASE_ERROR);
default:
{
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
sensePtr = senseInvalidOpcode;
failedIn();
return(USBS_FAILED);
}
}
}
BYTE 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;
stallEP2OUT();
return(USBS_FAILED);
}
}
case SYNCHRONIZE_CACHE:
{
return(flushCache());
}
///////////////////////////////////////////////////////////
// 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
// Add kludge for Mac Jaguar OS. Wait for extra OUT packets to show up so we process them properly.
EZUSB_Delay(5);
case MODE_SELECT_10:
{
bit bShortPacketReceived = 0;
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
// Only process one mode select -- Write caching
// When we're done, discard the data just like any other mode select.
if (dataTransferLen)
{
BYTE offset;
while(EP2CS & bmEPEMPTY)
;
// Skip past block descriptor to get to the page.
if (cmd == MODE_SELECT_06)
offset = 4+EP2FIFOBUF[3];
else
offset = 8+EP2FIFOBUF[7];
// If the page is 8, use it.
if (EP2FIFOBUF[offset] == 8)
{
bWriteCacheDisabled = (~EP2FIFOBUF[offset+2]) & 4;
setFeatures(bWriteCacheDisabled ?
SET_FEATURES_WRITE_CACHE_DISABLE : SET_FEATURES_WRITE_CACHE_ENABLE, 0);
}
}
// Toss away all of the data received with the command
while (dataTransferLen && !bShortPacketReceived)
{
if(!(EP2CS & bmEPEMPTY))
{
dataTransferLen -= min(EP2BC, dataTransferLen);
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);
}
//////////////////////////////////////////////////////////////////////
// Check for phase error -- Read command in a write wrapper
case INQUIRY:
case READ_06:
case READ_10:
case READ_FORMAT_CAPACITIES:
case READ_CAPACITY:
case REQUEST_SENSE:
case MODE_SENSE_06:
case MODE_SENSE_10:
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
stallEP2OUT();
sensePtr = senseInvalidOpcode;
return(USBS_PHASE_ERROR);
default:
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
stallEP2OUT();
sensePtr = senseInvalidOpcode;
return(USBS_FAILED);
break;
}
}
static BYTE ideReadCommand(BYTE command)
{
BYTE driveStatus;
WORD sectorcount;
WORD wordCtr;
if (command == VERIFY_10)
{
// Stuff dataTranferLen with 00 (sector count << 1) 00
dataTransferLenLSB = 0;
dataTransferLen23W = (EP2FIFOBUF[CBW_DATA_START+7] << (8+1)) + (EP2FIFOBUF[CBW_DATA_START+8] << 1);
dataTransferLenMSB = 0;
}
// Prepare for fast read
mymemmoveix(prevCmd,&EP2FIFOBUF[0x0F],10);
prevDataTransferLen = dataTransferLen;
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];
wCmdSectorCount = EP2FIFOBUF[CBW_DATA_START+4];
// relinquish control of the bulk buffer occupied by the CBW
EP2BCL = 0x80;
break;
}
default:
IDEPrepareForXfer();
}
if (wCmdSectorCount > dataTransferLen23W/2)
{
failedIn();
return (USBS_PHASE_ERROR);
}
gSectorcount = wCmdSectorCount; // Save the cmdSectorCount for use in fast reads
// This loop breaks up the 32 bit length into 8 bits * sectors.
// For example, a read of 0x10000 turns into 0x80 sectors.
while (dataTransferLen && wCmdSectorCount)
{
sectorcount = stuffLBAandSector();
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. The verify code path doesn't get any further than this IF statement.
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;
wCmdSectorCount -= 0x100;
}
else
dataTransferLen = 0;
continue;
}
}
// Wait for drive non-busy before starting xfer
while (readATAPI_ALT_STATUS_REG() & ATAPI_STATUS_BUSY_BIT)
;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -