📄 ide_func.c
字号:
/* Device PIO Transfer Mode Set */
ATACmd.reg01 = 0x03;
ATACmd.reg02 = 0x08 | DevicePara[DeviceCnt].PioMode;
ATACmd.reg07 = SET_FEATURS;
result = ATA_IFATACommandOutA( portNumber, masterSlave, ATA_IF_PIO_MODE2, &ATACmd );
if( result != STATUS_SUCCESS ){
return result;
}
/* BSY negate wait */
result = StatusWait( portNumber, masterSlave );
/* ERROR Complete Check */
if( ( DeviceStatus.status & 0x01 ) ){
return STATUS_SUCCESS;
}
/* Set the UltraDMA transfer mode */
if( (identifydata[106] & 0x04) ){
DevicePara[DeviceCnt].UltraEnb = ENABLE;
if( (identifydata[176] & 0xC0) ){
DevicePara[DeviceCnt].UltraMode = IDE_FUNC_ULTRA_MODE6;
}else{
if( (identifydata[176] & 0x20) ){
DevicePara[DeviceCnt].UltraMode = IDE_FUNC_ULTRA_MODE5;
}else{
if( (identifydata[176] & 0x10) ){
DevicePara[DeviceCnt].UltraMode = IDE_FUNC_ULTRA_MODE4;
}else{
if( (identifydata[176] & 0x08) ){
DevicePara[DeviceCnt].UltraMode = IDE_FUNC_ULTRA_MODE3;
}else{
if( (identifydata[176] & 0x04) ){
DevicePara[DeviceCnt].UltraMode = IDE_FUNC_ULTRA_MODE2;
}else{
if( (identifydata[176] & 0x02) ){
DevicePara[DeviceCnt].UltraMode = IDE_FUNC_ULTRA_MODE1;
}else{
DevicePara[DeviceCnt].UltraMode = IDE_FUNC_ULTRA_MODE0;
}
}
}
}
}
}
/* Device UltraDMA Mode Set */
ATACmd.reg01 = 0x03;
ATACmd.reg02 = 0x40 | DevicePara[DeviceCnt].UltraMode;
ATACmd.reg07 = SET_FEATURS;
result = ATA_IFATACommandOutA( portNumber, masterSlave, ATA_IF_PIO_MODE2, &ATACmd );
if( result != STATUS_SUCCESS ){
return result;
}
/* BSY negate wait */
result = StatusWait( portNumber, masterSlave );
/* ERROR Complete Check */
if( ( DeviceStatus.status & 0x01 ) ){
return STATUS_SUCCESS;
}
}else{
DevicePara[DeviceCnt].UltraEnb = DISABLE;
}
/* Set MultiWordDma transfer mode */
if( (identifydata[126] & 0x04) ){
DevicePara[DeviceCnt].DmaMode = IDE_FUNC_MULTI_MODE2;
}else{
if( (identifydata[126] & 0x02) ){
DevicePara[DeviceCnt].DmaMode = IDE_FUNC_MULTI_MODE1;
}else{
DevicePara[DeviceCnt].DmaMode = IDE_FUNC_MULTI_MODE0;
}
}
/* UltraDma Enabel Check */
if( DevicePara[DeviceCnt].UltraEnb == DISABLE ){
/* Device MultiWordDma Mode Set */
ATACmd.reg01 = 0x03;
ATACmd.reg02 = 0x20 | DevicePara[DeviceCnt].DmaMode;
ATACmd.reg07 = SET_FEATURS;
result = ATA_IFATACommandOutA( portNumber, masterSlave, ATA_IF_PIO_MODE2, &ATACmd );
if( result != STATUS_SUCCESS ){
return result;
}
/* BSY negate wait */
result = StatusWait( portNumber, masterSlave );
/* ERROR Complete Check */
if( ( DeviceStatus.status & 0x01 ) ){
return STATUS_SUCCESS;
}
}
/* DMA Transfer Mode Set */
/* BIG Drive Mode Set */
if( SelectDeviceNo[DeviceCnt].type == IDE_FUNC_HDD ){
if( (identifydata[167] & 0x04) ){
DevicePara[DeviceCnt].BigDrive = ENABLE;
pList->bigDrive[DeviceCnt] = IDE_FUNC_HDD_BIG;
}else{
DevicePara[DeviceCnt].BigDrive = DISABLE;
pList->bigDrive[DeviceCnt] = IDE_FUNC_HDD_NORMAL;
}
}
/* IDENTIFY information field */
// corresponding to the Big Endian
pList->identify[DeviceCnt].IdeTrack = ( identifydata[2] + ( identifydata[3] << 8 ));
pList->identify[DeviceCnt].IdeCylinder = ( identifydata[6] + ( identifydata[7] << 8 ));
pList->identify[DeviceCnt].IdeHeader = ( identifydata[12] + ( identifydata[13] << 8 ));
for( i = 0; i < 40; i += 2 ){
pList->identify[DeviceCnt].DevicePara[i + 0] = identifydata[54 + i + 1];
pList->identify[DeviceCnt].DevicePara[i + 1] = identifydata[54 + i + 0];
}
if (DevicePara[DeviceCnt].BigDrive == ENABLE) {
pList->identify[DeviceCnt].MaxLba =
( identifydata[200] + ( identifydata[201] << 8 ) + ( identifydata[202] << 16 ) + ( identifydata[203] << 24 ));
}
else{
pList->identify[DeviceCnt].MaxLba =
( identifydata[120] + ( identifydata[121] << 8 ) + ( identifydata[122] << 16 ) + ( identifydata[123] << 24 ));
}
/* Update the device count that connected */
DeviceCnt ++;
return STATUS_SUCCESS;
}
/*
////////////////////////////////////////////////////////////////////////
// Function_Name: StatusWait
//
// description : Get status
//
//
// argument : USHORT id Identifier of the upper layer
// USHORT portNumber The initialized port No.
//
// return : LONG status Processing result
//
////////////////////////////////////////////////////////////////////////
*/
static LONG StatusWait( USHORT portNumber, UCHAR masterSlave )
{
LONG result;
while(1){
/* STATUS READ */
result = ATA_IFGetStatus( portNumber, masterSlave, &DeviceStatus );
if( result != STATUS_SUCCESS ){
return result;
}
/* Waiting for BSY negate */
if( !( DeviceStatus.status & 0x80 ) ){
return STATUS_SUCCESS;
}
}
}
/*
////////////////////////////////////////////////////////////////////////
// Function_Name: IDE_FuncGetDeviceParameter
//
// description : Get the detailed information of the specified device.
//
//
//
// argument : USHORT id Identifier of the upper layer
// USHORT deviceNo Device No. The parameter is acquired from this device.
// UCHAR *pDataptr pointer of the parameter field
//
// return : LONG status Processing result
//
////////////////////////////////////////////////////////////////////////
*/
LONG IDE_FuncGetDeviceParameter( USHORT id, USHORT deviceNo, UCHAR *pDataptr )
{
LONG result;
if( deviceNo >= DeviceCnt ){
/* Parameter error */
return STATUS_INVALID_PARAMETER;
}
/* ATA Command Clear */
ATACmd.reg01 = 0x00;
ATACmd.reg02 = 0x00;
ATACmd.reg03 = 0x00;
ATACmd.reg04 = 0x00;
ATACmd.reg05 = 0x00;
ATACmd.reg06 = 0x00;
/* ATA Function Port Lock */
result = ATA_IFLockPort( SelectDeviceNo[deviceNo].portNumber );
if( result != STATUS_SUCCESS ){
return result;
}
/* Device Type Check */
if( SelectDeviceNo[deviceNo].type == IDE_FUNC_HDD ){
/* ATA Identify Device Command Set */
ATACmd.reg07 = IDENTIFY_DEVICE;
}else{
/* ATA Identify Packet Device Command Set */
ATACmd.reg07 = IDENTIFY_PACKET_DEVICE;
}
/* Send ATA command */
result = ATA_IFATACommandOutA( SelectDeviceNo[deviceNo].portNumber,
SelectDeviceNo[deviceNo].MasterSlave,
DevicePara[deviceNo].PioMode, &ATACmd );
if(result != STATUS_SUCCESS ){
ATA_IFUnlockPort( SelectDeviceNo[deviceNo].portNumber );
return result;
}
/* Waiting for BSY negate */
result = StatusWait(SelectDeviceNo[deviceNo].portNumber, SelectDeviceNo[deviceNo].MasterSlave );
if(result != STATUS_SUCCESS ){
ATA_IFUnlockPort( SelectDeviceNo[deviceNo].portNumber );
return result;
}
/* Check DQR assert */
if( !( DeviceStatus.status & 0x08 ) ){
ATA_IFUnlockPort( SelectDeviceNo[deviceNo].portNumber );
return STATUS_UNSUCCESSFUL;
}
/* Read IDENTIFY DEVICE DATA */
TranPara.transfersize = 0x200;
TranPara.direction = ATA_IF_IDE_IN;
TranPara.dataPointer = (ULONG)( pDataptr);
result = ATA_IFPIODataTransfer( SelectDeviceNo[deviceNo].portNumber, SelectDeviceNo[deviceNo].MasterSlave, &TranPara );
if(result != STATUS_SUCCESS ){
ATA_IFUnlockPort( SelectDeviceNo[deviceNo].portNumber );
return result;
}
/* Waiting for BSY negate */
result = StatusWait(SelectDeviceNo[deviceNo].portNumber, SelectDeviceNo[deviceNo].MasterSlave );
/* ATA Function Port Unlock */
ATA_IFUnlockPort( SelectDeviceNo[deviceNo].portNumber );
if(result != STATUS_SUCCESS ){
return result;
}
/* ERROR Complete Check */
if( ( DeviceStatus.status & 0x01 ) ){
return STATUS_UNSUCCESSFUL;
}
/* Complete */
return STATUS_SUCCESS;
}
/*
////////////////////////////////////////////////////////////////////////
// Function_Name: IDE_FuncCommandOut
//
// description : Send command to the spaecified device
//
//
//
// argument : USHORT id Identifier of the upper layer
// USHORT deviceNo No. of the device that issues command
// UCHAR transferMode Data transfer mode (PIO/DMA)
// IDE_FUNCCMDPARA *pCmdBlock command block
//
// return : LONG status Processing result
//
////////////////////////////////////////////////////////////////////////
*/
LONG IDE_FuncCommandOut( USHORT id, USHORT deviceNo, UCHAR transferMode, IDE_FUNCCMDPARA *pCmdBlock )
{
LONG result;
/* Check the specified deviceNo. */
if( deviceNo >= DeviceCnt ){
/* Parameter error */
return STATUS_INVALID_PARAMETER;
}
/* Check if the specified Device command is on executing */
if( CMDState[deviceNo].status == IDE_FUNC_CMD_EXEC ){
/* Parameter error */
return IDE_FUNC_STATUS_CMD_EXEC;
}
if( CMDState[deviceNo].id != id ){
if( CMDState[deviceNo].status == IDE_FUNC_CMD_COMP ){
/* Parameter error */
return IDE_FUNC_STATUS_CMD_EXEC;
}
}
/* ATA Function PORT Lock */
result = ATA_IFLockPort( SelectDeviceNo[deviceNo].portNumber );
if( result != STATUS_SUCCESS ){
return result;
}
/* Device Type Check */
if( SelectDeviceNo[deviceNo].type == IDE_FUNC_HDD ){
/* Check if the command mode is set to ATA Device */
if( pCmdBlock->commandMode == IDE_FUNC_ATA ){
/* ATA Command */
result = ATACommandSet( deviceNo, transferMode, pCmdBlock );
}else{
/* ATAPI Command */
result = ATAPItoATACommandSet( deviceNo, transferMode, pCmdBlock );
}
}else{
/* Check if the command mode is set to ATAPI Device */
if( pCmdBlock->commandMode == IDE_FUNC_ATA ){
/* ATA Command */
/* Parameter error */
return STATUS_INVALID_PARAMETER;
}
/* ATAPI Command */
result = ATAPICommandSet( deviceNo, transferMode, pCmdBlock );
}
if( result == STATUS_SUCCESS ){
/* Set the specified device command state to ON EXECUTING */
CMDState[deviceNo].status = IDE_FUNC_CMD_EXEC;
CMDState[deviceNo].id = id;
}else{
ATA_IFUnlockPort( SelectDeviceNo[deviceNo].portNumber );
}
return result;
}
/*
////////////////////////////////////////////////////////////////////////
// Function_Name: ATACommandSet
//
// description : Send the ATA command to the specified device
//
// argument : USHORT deviceNo No of the device that issues command
// UCHAR transferMode data transfer mode (PIO/DMA)
// IDE_FUNCCMDPARA *pCmdBlock command block
//
// return : LONG status Processing result
//
////////////////////////////////////////////////////////////////////////
*/
static LONG ATACommandSet( USHORT deviceNo, UCHAR transferMode, IDE_FUNCCMDPARA *pCmdBlock )
{
UCHAR driveSelect;
/* Command Code Check */
if( pCmdBlock->commandBlock[7] == HDD_BIGDRV_READ || pCmdBlock->commandBlock[7] == HDD_BIGDRV_WRITE ||
pCmdBlock->commandBlock[7] == READ_SECTOR_BIG || pCmdBlock->commandBlock[7] == WRITE_SECTOR_BIG ||
pCmdBlock->commandBlock[7] == FLUSH_CACHE_EXT || pCmdBlock->commandBlock[7] == READ_NATIVE_MAX_ADDRESS_EXT ||
pCmdBlock->commandBlock[7] == READ_VERIFY_SECTOR_EXT || pCmdBlock->commandBlock[7] == SET_MAX_ADDRESS_EXT ){
/* BIG Drive Enable Check */
if( DevicePara[deviceNo].BigDrive == DISABLE ){
return STATUS_INVALID_PARAMETER;
}
/* COMMAND Copy */
ATACmd.reg01 = pCmdBlock->commandBlock[1];
ATACmd.reg02 = pCmdBlock->commandBlock[2];
ATACmd.reg03 = pCmdBlock->commandBlock[3];
ATACmd.reg04 = pCmdBlock->commandBlock[4];
ATACmd.reg05 = pCmdBlock->commandBlock[5];
ATACmd.reg06 = pCmdBlock->commandBlock[6];
ATACmd.reg07 = pCmdBlock->commandBlock[7];
ATACmd.BigDriveReg02 = pCmdBlock->commandBlock[8];
ATACmd.BigDriveReg03 = pCmdBlock->commandBlock[9];
ATACmd.BigDriveReg04 = pCmdBlock->commandBlock[10];
ATACmd.BigDriveReg05 = pCmdBlock->commandBlock[11];
/* Sector LBA Set */
TransferLba = (ULONG)( ( pCmdBlock->commandBlock[9] * 0x1000000) + ( pCmdBlock->commandBlock[5] * 0x10000) +
( pCmdBlock->commandBlock[4] * 0x100) + pCmdBlock->commandBlock[3] );
/* Master/Slave Set & BIG Drive Flag Set */
driveSelect = SelectDeviceNo[deviceNo].MasterSlave | SEL_BIG_DRIVE;
}else{
/* COMMAND Copy */
ATACmd.reg01 = pCmdBlock->commandBlock[1];
ATACmd.reg02 = pCmdBlock->commandBlock[2];
ATACmd.reg03 = pCmdBlock->commandBlock[3];
ATACmd.reg04 = pCmdBlock->commandBlock[4];
ATACmd.reg05 = pCmdBlock->commandBlock[5];
ATACmd.reg06 = pCmdBlock->commandBlock[6];
ATACmd.reg07 = pCmdBlock->commandBlock[7];
/* Sector LBA Set */
TransferLba = (ULONG)( ( pCmdBlock->commandBlock[6] * 0x1000000) + ( pCmdBlock->commandBlock[5] * 0x10000) +
( pCmdBlock->commandBlock[4] * 0x100) + pCmdBlock->commandBlock[3] );
/* Master/Slave Set */
driveSelect = SelectDeviceNo[deviceNo].MasterSlave;
}
/* Send ATA command */
return( ATA_IFATACommandOutA( SelectDeviceNo[deviceNo].portNumber, driveSelect,
DevicePara[deviceNo].PioMode, &ATACmd ) );
}
/*
////////////////////////////////////////////////////////////////////////
// Function_Name: ATAPItoATACommandSet
//
// description : Change the ATAPI command to the ATA command,and send to the specofied device.
//
// argument : USHORT deviceNo No. of the device that issues command
// UCHAR transferMode Data transfer mode(PIO/DMA)
// IDE_FUNCCMDPARA *pCmdBlock Command block
//
// return : LONG status Processing result
//
////////////////////////////////////////////////////////////////////////
*/
static LONG ATAPItoATACommandSet( USHORT deviceNo, UCHAR transferMode, IDE_FUNCCMDPARA *pCmdBlock)
{
UCHAR driveSelect;
/* Command Code Check */
switch( pCmdBlock->commandBlock[0] ){
case READ10:
case WRITE10:
/* ATAPI Read10/Write10 Command -> ATA READ/WRITE Command */
if( DevicePara[deviceNo].BigDrive == ENABLE ){
/* HDD BIG Drive */
ATACmd.reg01 = 0x00;
ATACmd.reg02 = pCmdBlock->commandBlock[8];
ATACmd.reg03 = pCmdBlock->commandBlock[5];
ATACmd.reg04 = pCmdBlock->commandBlock[4];
ATACmd.reg05 = pCmdBlock->commandBlock[3];
ATACmd.reg06 = 0x00;
ATACmd.BigDriveReg02 = pCmdBlock->commandBlock[7];
ATACmd.BigDriveReg03 = pCmdBlock->commandBlock[2];
ATACmd.BigDriveReg04 = 0x00;
ATACmd.BigDriveReg05 = 0x00;
ATACmd.BigDriveReg06 = 0x00;
}else{
/* HDD Drive */
if( ( pCmdBlock->commandBlock[7] != 0x00) || ( (pCmdBlock->commandBlock[2] & 0xF0) != 0x00 ) ){
return STATUS_INVALID_PARAMETER;
}
ATACmd.reg01 = 0x00;
ATACmd.reg02 = pCmdBlock->commandBlock[8];
ATACmd.reg03 = pCmdBlock->commandBlock[5];
ATACmd.reg04 = pCmdBlock->commandBlock[4];
ATACmd.reg05 = pCmdBlock->commandBlock[3];
ATACmd.reg06 = pCmdBlock->commandBlock[2];
ATACmd.BigDriveReg02 = 0x00;
ATACmd.BigDriveReg03 = 0x00;
ATACmd.BigDriveReg04 = 0x00;
ATACmd.BigDriveReg05 = 0x00;
ATACmd.BigDriveReg06 = 0x00;
}
/* Sector LBA Set */
TransferLba = (ULONG)( ( pCmdBlock->commandBlock[2] * 0x1000000) + ( pCmdBlock->commandBlock[3] * 0x10000) +
( pCmdBlock->commandBlock[4] * 0x100) + pCmdBlock->commandBlock[5] );
break;
case READ12:
case WRITE12:
/* ATAPI Read10/Write10 Command -> ATA READ/WRITE Command */
if( DevicePara[deviceNo].BigDrive == ENABLE ){
/* HDD BIG Drive */
if( pCmdBlock->commandBlock[6] != 0x00 || pCmdBlock->commandBlock[7] != 0x00 ){
return STATUS_INVALID_PARAMETER;
}
ATACmd.reg01 = 0x00;
ATACmd.reg02 = pCmdBlock->commandBlock[9];
ATACmd.reg03 = pCmdBlock->commandBlock[5];
ATACmd.reg04 = pCmdBlock->commandBlock[4];
ATACmd.reg05 = pCmdBlock->commandBlock[3];
ATACmd.reg06 = 0x00;
ATACmd.BigDriveReg02 = pCmdBlock->commandBlock[8];
ATACmd.BigDriveReg03 = pCmdBlock->commandBlock[2];
ATACmd.BigDriveReg04 = 0x00;
ATACmd.BigDriveReg05 = 0x00;
ATACmd.BigDriveReg06 = 0x00;
}else{
/* HDD Drive */
if( pCmdBlock->commandBlock[6] != 0x00 || pCmdBlock->commandBlock[7] != 0x00 ||
pCmdBlock->commandBlock[8] != 0x00 || ( (pCmdBlock->commandBlock[2] & 0xF0) != 0x00 )){
return STATUS_INVALID_PARAMETER;
}
ATACmd.reg01 = 0x00;
ATACmd.reg02 = pCmdBlock->commandBlock[9];
ATACmd.reg03 = pCmdBlock->commandBlock[5];
ATACmd.reg04 = pCmdBlock->commandBlock[4];
ATACmd.reg05 = pCmdBlock->commandBlock[3];
ATACmd.reg06 = pCmdBlock->commandBlock[2];
ATACmd.BigDriveReg02 = 0x00;
ATACmd.BigDriveReg03 = 0x00;
ATACmd.BigDriveReg04 = 0x00;
ATACmd.BigDriveReg05 = 0x00;
ATACmd.BigDriveReg06 = 0x00;
}
/* Sector LBA Set */
TransferLba = (ULONG)( ( pCmdBlock->commandBlock[2] * 0x1000000) + ( pCmdBlock->commandBlock[3] * 0x10000) +
( pCmdBlock->commandBlock[4] * 0x100) + pCmdBlock->commandBlock[5] );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -