📄 ep931xide.cpp
字号:
BOOL fRet = TRUE;
DWORD dwRet;
//
// Wait for the IDE interrupt. If it doesn't occur, timeout.
//
dwRet = WaitForSingleObject( m_pPort->m_hIdeIntEvent, dwTimeOut);
//
// If we are currently using DMA, switch to PIO mode to read the
// registers.
//
m_pPort->PIOMode();
if (dwRet == WAIT_TIMEOUT )
{
fRet = FALSE;
}
else if (dwRet != WAIT_OBJECT_0 && dwTimeOut >0)
{
//
// This case is for if we don't use the interrupt.
// Not applicable for us.
//
if (!WaitForDisc( WAIT_TYPE_DRQ, dwTimeOut, 10))
{
fRet = FALSE;
}
}
//
// Ack interrupt!!!!!
//
bStatus = GetBaseStatus();
if (bStatus & ATA_STATUS_ERROR )
{
DEBUGMSG( ZONE_WARNING, (TEXT("CEP931xDisk::WaitforInterrupt bStatus = 0x%02x\n"), (ULONG) bStatus));
bStatus = GetError();
fRet = FALSE;
}
//
// Clear the IDE interrupt.
//
InterruptDone(SYSINTR_IDE);
return fRet;
}
//****************************************************************************
// WaitForDMARQCleared
//****************************************************************************
// Wait for DMARQ to be cleared.
//
//
BOOL WaitForDMARQCleared(ULONG ulTime)
{
BOOL bRet = TRUE;
LARGE_INTEGER liStart, liCurrent;
ULONG ulIdeCtrl;
QueryPerformanceCounter(&liStart);
for(;;)
{
QueryPerformanceCounter(&liCurrent);
ulIdeCtrl = *IDE_CTRL;
if(!(ulIdeCtrl & IDE_CTRL_DMARQ))
{
break;
}
if(ULONG(liCurrent.QuadPart - liStart.QuadPart) > ulTime)
{
bRet = FALSE;
}
}
return bRet;
}
//****************************************************************************
// CEP931xPort::WaitForDmaInterrupt
//****************************************************************************
// Waits for the IDE interrupt. This is used for waiting in PIO mode.
//
// dwTimeOut - Time out in mS
//
// Return TRUE - Success
// FALSE - Failure
//
ULONG CEP931xPort::WaitForDmaInterrupt(DWORD dwTimeOut)
{
BYTE bStatus;
BOOL fRet = TRUE;
DWORD dwWaitRet;
ULONG ulRet = DMAWAIT_NOERROR;
// LARGE_INTEGER liStart, liCurrent;
// volatile register ULONG ulIdeCtrl;
// volatile register ULONG ulDmaM2MInt;
BOOL b;
b = QueryPerformanceCounter(&m_liTotalStart);
//
// Wait for the IDE interrupt. If it doesn't occur, timeout.
//
dwWaitRet = WaitForMultipleObjects( 2, m_hIstEvent, FALSE, dwTimeOut);
b = QueryPerformanceCounter(&m_liTotalEnd);
//
// Both IDE and DMA interrupts never occured, report an error.
//
if (dwWaitRet == (WAIT_OBJECT_0 + DMA_EVENT))
{
#if 0
if(m_bWaitForDMARQCleared)
{
dwWaitRet = WaitForDMARQCleared(10000)?WAIT_OBJECT_0:WAIT_TIMEOUT;
}
else
{
dwWaitRet = WaitForSingleObject(m_hIstEvent[IDE_EVENT], 10);
//
// If DMARQ is cleared the transfer occured successfully but
// the interrupt never asserted. Use DMARQ from now on.
//
ulIdeCtrl = *IDE_CTRL;
if(!(ulIdeCtrl & IDE_CTRL_DMARQ))
{
m_bWaitForDMARQCleared = 1;
dwWaitRet = WAIT_OBJECT_0;
}
}
#endif // 0
dwWaitRet = WaitForSingleObject(m_hIstEvent[IDE_EVENT], 10);
if(dwWaitRet == WAIT_TIMEOUT)
{
//
// The IDE interface is asking for more data.
//
DEBUGMSG
(
ZONE_DMA,
(TEXT("CEP931xPort::WaitForDmaInterrupt DMA transfer completed but IDE interface is requesting to recieve more data.\r\n"))
);
if(!m_fDMARead)
{
//
// DMA Hardware Write bug #1
//
CleanUpDmaUDMAWrite();
ulRet = DMAWAIT_ERROR_WRITE_1;
DEBUGMSG
(
ZONE_DMA,
(TEXT("CEP931xPort::WaitForDmaInterrupt Hit DMA Write Bug #1.\r\n"))
);
}
else
{
ulRet = DMAWAIT_ERROR;
}
}
}
else if (dwWaitRet == (WAIT_OBJECT_0 + IDE_EVENT))
{
dwWaitRet = WaitForSingleObject(m_hIstEvent[DMA_EVENT], 10);
if(dwWaitRet == WAIT_TIMEOUT)
{
//
// The DMA interface is asking for more data.
//
DEBUGMSG
(
ZONE_DMA,
(TEXT("CEP931xPort::WaitForDmaInterrupt IDE transfer completed but DMA is requesting to send more data.\r\n"))
);
if(!m_fDMARead)
{
DEBUGMSG
(
ZONE_DMA,
(TEXT("CEP931xPort::WaitForDmaInterrupt Hit DMA Write Bug #2.\r\n"))
);
//
// If we ever hit write bug #2 use pio mode since we cannot detect
// write bug #2 all of the time.
//
// m_bForcePIO = TRUE;
ulRet = DMAWAIT_ERROR_WRITE_2;
// DumpDmaState();
// DumpIDEState();
}
else
{
DEBUGMSG
(
ZONE_DMA,
(TEXT("CEP931xPort::WaitForDmaInterrupt Hit DMA Read Bug #1.\r\n"))
);
ulRet = DMAWAIT_ERROR_READ_1;
}
}
}
else
{
DEBUGMSG
(
ZONE_DMA,
(TEXT("CEP931xPort::WaitForDmaInterrupt Both IDE and DMA interrupts did not occur.\r\n"))
);
ulRet = DMAWAIT_ERROR;
}
//
// Switch to PIO mode.
//
PIOMode();
DEBUGMSG
(
ZONE_DMA,
(
TEXT("CEP931xPort::WaitForDmaInterrupt Event = %d, IDE= %d DMA = %d.\r\n"),
ULONG(m_liTotalEnd.QuadPart - m_liTotalStart.QuadPart),
ULONG(m_liIdeEnd.QuadPart - m_liIdeStart.QuadPart),
ULONG(m_liDmaEnd.QuadPart - m_liDmaStart.QuadPart)
)
);
//
// Ack interrupt!!!!!
//
// bStatus = GetBaseStatus();
bStatus = (BYTE) ATAReadRegister(CSDA_STAT_REG) & 0xFF;
//*************************************************************************
// Seagate St340014A has DRQ asserted after the transfer has been completed
// also DMARQ goes high after this read?
//*************************************************************************
if ((bStatus & ATA_STATUS_ERROR) /* || (bStatus & ATA_STATUS_DATA_REQ ) */ )
{
DEBUGMSG
(
ZONE_WARNING,
(
TEXT("CEP931xPort::WaitForDmaInterrupt bStatus = 0x%04x\n"),
(ULONG) bStatus
)
);
// bStatus = GetError();
bStatus = (BYTE)ATAReadRegister(CSDA_ERROR_REG);
if(ulRet == DMAWAIT_NOERROR)
{
ulRet = DMAWAIT_ERROR;
}
}
return ulRet;
}
//****************************************************************************
// CEP931xDisk::WaitForDmaInterrupt
//****************************************************************************
// Waits for the IDE interrupt. This is used for waiting in PIO mode.
//
// dwTimeOut - Time out in mS
//
// Return TRUE - Success
// FALSE - Failure
//
ULONG CEP931xDisk::WaitForDmaInterrupt(DWORD dwTimeOut)
{
ULONG ulRet;
ulRet = m_pPort->WaitForDmaInterrupt(dwTimeOut);
if(m_pPort->m_fDMARead)
{
m_DmaStatistics.ulDmaTotalRead++;
}
else
{
m_DmaStatistics.ulDmaTotalWrite++;
}
switch(ulRet)
{
case DMAWAIT_NOERROR:
m_DmaStatistics.ulDmaNoError++;
break;
case DMAWAIT_ERROR:
m_DmaStatistics.ulDmaOtherError++;
break;
case DMAWAIT_ERROR_WRITE_1:
m_DmaStatistics.ulDmaWriteBug1++;
break;
case DMAWAIT_ERROR_WRITE_2:
m_DmaStatistics.ulDmaWriteBug2++;
break;
case DMAWAIT_ERROR_READ_1:
m_DmaStatistics.ulDmaReadBug1++;
break;
default:
break;
}
return ulRet;
}
//****************************************************************************
// CEP931xDisk::EnableInterrupt
//****************************************************************************
//
//
//
void CEP931xDisk::EnableInterrupt()
{
GetBaseStatus();// Ack interrupt!!!!!
InterruptDone(SYSINTR_IDE);
}
#define ATA_DMA_ULTRA_MODE 0x40
//****************************************************************************
// CEP931xDisk::SetBestTransferMode
//****************************************************************************
// Sets the Best Transfer mode based on the registry and the device
// specifcations.
//
// m_dwBestUDmaMode Comes from the drive.
// m_ulBestUDmaModeReg Comes frm the registry.
//
//
void CEP931xDisk::SetBestTransferMode()
{
ULONG ulMwDmaMode, ulUDmaMode;
if ((m_dwBestPioMode != -1) && (m_dwBestPioMode >= 2))
{
SetTransferMode( (BYTE)m_dwBestPioMode | ATA_PIO_FCT_MODE);
}
ulMwDmaMode = (int)m_ulBestMwDmaModeReg>(int) m_dwBestMwDmaMode?
m_dwBestMwDmaMode:
m_ulBestMwDmaModeReg;
ulUDmaMode = (int)m_ulBestUDmaModeReg > (int)m_dwBestUDmaMode?
m_dwBestUDmaMode:
m_ulBestUDmaModeReg;
if(m_fUDMAActive && ulUDmaMode != -1)
{
m_dwTransferModeCurrent = (UDMA_MODE0 << ulUDmaMode);
SetTransferMode( (BYTE)ulUDmaMode | ATA_DMA_ULTRA_MODE);
DEBUGMSG
(
ZONE_INIT,
(
(L"ATAPI:SetBestTransferMode Current mode is UDMA mode = %1x\r\n"),
ulUDmaMode
)
);
m_fForcePIO = FALSE;
}
//
// If the Drive supports UDMA but it is not enabled, set the mode to
// mode 0 so that the other drive works.
//
// You can't mix UDMA on one drive and MDMA on the other.
//
else if(m_dwBestUDmaMode != -1)
{
SetTransferMode( (BYTE) (UDMA_MODE0 | ATA_DMA_ULTRA_MODE));
m_fForcePIO = TRUE;
}
else
{
m_pPort->m_fForcePIO = TRUE;
m_fForcePIO = TRUE;
}
// else if (ulMwDmaMode != -1 )
// {
// m_dwTransferModeCurrent = (MWDMA_MODE0 << ulMwDmaMode);
// SetTransferMode( (BYTE)ulMwDmaMode | ATA_DMA_MULTI_WORD_MODE);
// //* * * CAMSDB - Added this for setting the mode in CPort class. (START)
// m_pPort->m_ulCurrentMode = m_dwTransferModeCurrent;
// //* * * CAMSDB - Added this for setting the mode in CPort class. (END)
//
// DEBUGMSG
// (
// ZONE_INIT,
// (
// (L"ATAPI:SetBestTransferMode Current mode is MDMA mode = %1x\r\n"),
// ulMwDmaMode
// )
// );
// }
}
//****************************************************************************
// CEP931xDisk::ForceTransferMode
//****************************************************************************
// fUDMAActive - Acts exactly like UDMAActive Registry setting.
// UDmaMode - Acts exactly like UDMAMode Registry setting.
//
DWORD CEP931xDisk::ForceTransferMode(BOOL fUDMAActive, ULONG ulUDmaMode)
{
m_fUDMAActive = fUDMAActive;
m_ulBestUDmaModeReg = ulUDmaMode;
//
// Reset the read and write failure bugs for testing.
//
m_fReadBug1Failure = FALSE;
m_fWriteBug1Failure = FALSE;
m_fWriteBug2Failure = FALSE;
SetBestTransferMode();
return ERROR_SUCCESS;
}
//****************************************************************************
// CEP931xDisk::IsDMASupported
//****************************************************************************
// For DMA to be supported the following:
// 1. Both Drives must support UDMA.
// 2.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -