📄 cdio.cpp
字号:
DWORD dwStartSector = dwLBAAddr;
WORD wSectorSize;
ULONG ulWaitReturn;
ULONG ulNumRetries;
BOOL bRetryUsingPIO = FALSE;
DEBUGMSG( ZONE_CDROM, (TEXT("+CDisk::ReadCdRomDMA\r\n")));
if( bRawMode)
{
wSectorSize = CDROM_RAW_SECTOR_SIZE;
}
else
{
wSectorSize = CDROM_SECTOR_SIZE;
}
// Process the SG buffers in blocks of MAX_CD_SECT_PER_COMMAND. Each DMA request will have a new SG_BUF array
// which will be a subset of the original request, and may start/stop in the middle of the original buffer.
while (dwNumSectors)
{
dwSectorsToTransfer = (dwNumSectors > MAX_CD_SECT_PER_COMMAND) ? MAX_CD_SECT_PER_COMMAND : dwNumSectors;
DWORD dwBufferLeft = dwSectorsToTransfer * wSectorSize;
DWORD dwNumSg = 0;
while (dwBufferLeft)
{
DWORD dwCurBufferLen = pSgBuf[dwEndBufferNum].sb_len - dwEndBufferOffset;
if (dwBufferLeft < dwCurBufferLen)
{
// The buffer left for this block is less than the current SG buffer length
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_buf = pSgBuf[dwEndBufferNum].sb_buf + dwEndBufferOffset;
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_len = dwBufferLeft;
dwEndBufferOffset += dwBufferLeft;
dwBufferLeft = 0;
}
else
{
// The buffer left for this block is greater than or equal to the current SG buffer length. Move on to the next SG buffer.
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_buf = pSgBuf[dwEndBufferNum].sb_buf + dwEndBufferOffset;
CurBuffer[dwEndBufferNum - dwStartBufferNum].sb_len = dwCurBufferLen;
dwEndBufferOffset = 0;
dwEndBufferNum++;
dwBufferLeft -= dwCurBufferLen;
}
dwNumSg++;
}
//WaitForInterrupt(0);
ulNumRetries = 0;
for(;;)
{
if(ulNumRetries >= MAX_DMARETRYS)
{
dwError = ERROR_READ_FAULT;
bRetryUsingPIO = TRUE;
break;
}
if (!SetupDMA(CurBuffer, dwNumSg, ATA_CMD_READ_DMA))
{
dwError = ERROR_READ_FAULT;
break;
}
SetupCdRomRead( wSectorSize == CDROM_RAW_SECTOR_SIZE ? TRUE : FALSE, dwStartSector, dwSectorsToTransfer, &CmdPkt);
wCount = (SHORT)((dwSectorsToTransfer * wSectorSize) >> 1);
if (!AtapiSendCommand(&CmdPkt, wCount, IsReadDMASupported()))
{
dwError = ERROR_READ_FAULT;
AbortDMA();
break;
}
//
// Wait for Busy to be cleared. DRQ and DMARQ are asserted.
// Wait a maximium of 5 Second to spin up the drive.
//
WaitOnDMARQForCD(5000);
//
// Begin DMA always returns true
//
BeginDMA(TRUE);
ulWaitReturn = WaitForDmaInterrupt(DISK_IO_TIME_OUT);
//
// Dma Completed Successfully
//
if(ulWaitReturn == DMAWAIT_NOERROR )
{
EndDMA();
WaitOnBusy(FALSE);
// Fix for the bug #35612, copy from CDROM to HDD.
// Change from dwSgCount to dwNumSg.
CompleteDMA( (PSG_BUF)CurBuffer, dwNumSg, TRUE);
break;
}
//
// Hit EP931x hardware DMA bug.
//
else if(ulWaitReturn == DMAWAIT_ERROR_WRITE_1 )
{
DEBUGMSG
(
ZONE_ERROR,
(
TEXT("ATAPI:ReadCdRomDMA Failed Retrying\r\n")
)
);
AbortDMA();
ulNumRetries++;
}
else if (ulWaitReturn == DMAWAIT_ERROR_WRITE_2)
{
DEBUGMSG
(
ZONE_ERROR,
(
TEXT("ATAPI:ReadCdRomDMA Failed, Switching to PIO\r\n")
)
);
AbortDMA();
m_fWriteBug2Failure = TRUE;
bRetryUsingPIO = TRUE;
dwError = ERROR_WRITE_FAULT;
break;
}
else if (ulWaitReturn == DMAWAIT_ERROR_READ_1)
{
DEBUGMSG
(
ZONE_ERROR,
(
TEXT("ATAPI:ReadCdRomDMA Failed, Switching to PIO\r\n")
)
);
AbortDMA();
m_fReadBug1Failure = TRUE;
bRetryUsingPIO = TRUE;
dwError = ERROR_READ_FAULT ;
break;
}
//
// Other Error.
//
else
{
DEBUGMSG
(
ZONE_ERROR,
(
TEXT("ATAPI:ReadCdRomDMA Failed Not Retrying \r\n")
)
);
AbortDMA();
bRetryUsingPIO = TRUE;
dwError = ERROR_READ_FAULT;
break;
}
}
dwStartSector += dwSectorsToTransfer;
dwStartBufferNum = dwEndBufferNum;
dwNumSectors -= dwSectorsToTransfer;
}
//ExitFailure:
if (dwError != ERROR_SUCCESS)
{
if(bRetryUsingPIO)
{
dwError = ReadCdRomPIO
(
bRawMode,
dwLBAAddr,
dwTransferLength,
dwSgCount,
pSgBuf,
pBytesRead
);
}
}
else
{
*pBytesRead = dwTransferLength * wSectorSize;
}
DEBUGMSG( ZONE_CDROM, (TEXT("-CDisk::ReadCdRomDMA\r\n")));
return dwError;
}
//****************************************************************************
// CDisk::ReadCdRomPIO
//****************************************************************************
// Performs a CDROM PIO read.
//
//
DWORD CDisk::ReadCdRomPIO
(
BOOL bRawMode,
DWORD dwLBAAddr,
DWORD dwTransferLength,
DWORD dwSgCount,
SGX_BUF *pSgBuf,
DWORD *pBytesRead
)
{
ATAPI_COMMAND_PACKET CmdPkt;
WORD wSectorSize;
DWORD dwError = ERROR_SUCCESS;
if( bRawMode)
{
wSectorSize = CDROM_RAW_SECTOR_SIZE;
}
else
{
wSectorSize = CDROM_SECTOR_SIZE;
}
SetupCdRomRead(bRawMode, dwLBAAddr, dwTransferLength, &CmdPkt);
if (AtapiSendCommand(&CmdPkt, wSectorSize, IsReadDMASupported()))
{
if (!AtapiReceiveData(pSgBuf, dwSgCount,pBytesRead))
{
dwError = ERROR_READ_FAULT;
}
}
else
{
dwError = ERROR_READ_FAULT;
}
return dwError;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
//---------------------------------------------------------------------------
//
// Send command to ATA Device.
//
//---------------------------------------------------------------------------
BOOL CDisk::AtapiSendCommand(PATAPI_COMMAND_PACKET pCmdPkt, WORD wCount, BOOL fDMA)
{
// Set the Drive/Head registers
SelectDevice();
GetBaseStatus();
SelectDevice();
if (WaitOnBusy(FALSE))
{
if (GetError() & ATA_STATUS_ERROR)
{
return FALSE;
}
}
//
// Calls Interrupt done for the IDE interrupt.
//
if(m_fInterruptSupported && IsDRQTypeIRQ())
{
EnableInterrupt();
}
WriteSectorCount(0);
WriteSectorNumber(0);
// Set the byte tranfer count
if (wCount)
{
WriteLowCount((BYTE)(0xff & wCount));
WriteHighCount((BYTE)(0xff & (wCount >> 8)));
}
else
{
WriteLowCount(0xFE);
WriteHighCount(0xFF);
}
//
// Set PIO or DMA Mode as specified in bFlags. 0 = PIO, 1 = DMA
//
WriteFeature(fDMA ? 0x1 : 0x0);
WaitForDisc( WAIT_TYPE_NOT_BUSY, 200);
//
// Write ATAPI into command register.
//
SelectDevice();
//
// Atapi Packet Command
//
WriteCommand(ATAPI_CMD_COMMAND);
WaitForDisc( WAIT_TYPE_NOT_BUSY, 200);
//
// Check how device is reporting CPU attention: DRQ or INTRQ?
// INTRQ within 10 ms!!!
//
if (m_fInterruptSupported && IsDRQTypeIRQ())
{
// ATA_INTR_CMD is expected
//
if (!WaitForInterrupt(DISK_IO_TIME_OUT))
{
DEBUGMSG( ZONE_IO | ZONE_CDROM, (TEXT("ATAPI:AtapiSendCommand - Wait for ATA_INTR_CMD Interrupt (DevId %x) \r\n"), m_dwDeviceId));
return FALSE;
}
}
//
// Device will assert DRQ within (50us or 3ms) if no interrupt id used
// Wait for not BSY and DRQ
//
if (!WaitForDRQ())
{
DEBUGMSG( ZONE_IO | ZONE_CDROM, (TEXT("ATAPIPCI:AtapiSendCommand 1 - ATAWaitForDisc failed with: %x (DevId %x)\r\n"), GetError(), m_dwDeviceId));
return FALSE;
}
//
// This should clear the interrupt.
//
if(m_fInterruptSupported)
{
EnableInterrupt();
}
//
// Write the ATAPI Command Packet.
//
WriteWordBuffer( (LPWORD)pCmdPkt, GetPacketSize()/sizeof(WORD));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -