📄 atapiio.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#include "atamain.h"
#undef ZONE_IO
#define ZONE_IO 1
BOOL CDisk::SendIOCommand(DWORD dwStartSector, DWORD dwNumberOfSectors, BYTE bCmd)
{
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:SendIOCommand - Sector %d SectorsLeft %x Command %x\r\n"), dwStartSector,dwNumberOfSectors,bCmd));
SelectDevice();
if (WaitOnBusy(FALSE))
{
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:SendIOCommand - Can't send a command!!! Status:%x Error:%x \r\n"), GetAltStatus(),GetError()));
return (FALSE);
}
//
// To transfer 256 Sectors set Sector Count Register to 0.
//
if(dwNumberOfSectors == MAX_SECT_PER_COMMAND)
dwNumberOfSectors = 0;
WriteSectorCount((BYTE)dwNumberOfSectors);
if (m_fLBAMode == TRUE)
{
WriteSectorNumber( (BYTE)dwStartSector);
WriteLowCount((BYTE)(dwStartSector >> 8));
WriteHighCount((BYTE)(dwStartSector >> 16));
WriteDriveHeadReg((BYTE)((dwStartSector >> 24) | ATA_HEAD_LBA_MODE) | ((m_dwDevice == 0 ) ? ATA_HEAD_DRIVE_1 : ATA_HEAD_DRIVE_2));
} else { // translate LBA to CHS format
DWORD dwSectors = m_DiskInfo.di_sectors;
DWORD dwHeads = m_DiskInfo.di_heads;
WriteSectorNumber((BYTE)((dwStartSector % dwSectors) + 1));
WriteLowCount((BYTE) (dwStartSector /(dwSectors*dwHeads)));
WriteHighCount((BYTE)((dwStartSector /(dwSectors*dwHeads)) >> 8));
WriteDriveHeadReg((BYTE)(((dwStartSector/dwSectors)% dwHeads) | ((m_dwDevice == 0 ) ? ATA_HEAD_DRIVE_1 : ATA_HEAD_DRIVE_2)));
}
WriteCommand(bCmd);
return (TRUE);
}
/*------------------------------------------------------------------------------------------*/
BYTE CDisk::WaitOnBusy(BOOL fBase)
{
DWORD i,j;
BYTE bStatus;
for (i=0; i< DEFAULT_WAIT_CHECK_ITER; i++) {
for (j=0; j<DEFAULT_WAIT_SAMPLE_TIMES; j++) {
bStatus = fBase ? GetBaseStatus() : GetAltStatus();
if (!(bStatus & ATA_STATUS_BUSY)) {
return bStatus & (ATA_STATUS_ERROR |ATA_STATUS_BUSY);
}
}
StallExecution(DEFAULT_WAIT_STALL_TIME);
}
return bStatus & (ATA_STATUS_ERROR |ATA_STATUS_BUSY);
}
/*------------------------------------------------------------------------------------------*/
BOOL CDisk::WaitForDisc(BYTE bStatusType, DWORD dwTimeOut, DWORD dwPeriod)
{
BYTE bStatusRead;
bStatusRead = 0;
if (dwPeriod == 0)
dwPeriod = dwTimeOut;
while( TRUE) {
bStatusRead = GetAltStatus();
switch (bStatusType) {
case WAIT_TYPE_BUSY:
if (bStatusRead & ATA_STATUS_BUSY) {
DEBUGMSG(ZONE_IO, (TEXT("ATAPI:WaitForDisc - WAIT_TYPE_BUSY\r\n")));
goto ExitDone;
}
break;
case WAIT_TYPE_NOT_BUSY:
if (!(bStatusRead & ATA_STATUS_BUSY)) {
DEBUGMSG(ZONE_IO, (TEXT("ATAPI:WaitForDisc - WAIT_TYPE_NOT_BUSY\r\n")));
goto ExitDone;
}
break;
case WAIT_TYPE_READY:
if (bStatusRead & ATA_STATUS_READY) {
DEBUGMSG(ZONE_IO, (TEXT("ATAPI:WaitForDisc - WAIT_TYPE_READY\r\n")));
StallExecution(100);
goto ExitDone;
}
break;
case WAIT_TYPE_DRQ:
if (bStatusRead & ATA_STATUS_DATA_REQ) {
DEBUGMSG(ZONE_IO, (TEXT("ATAPI:WaitForDisc - WAIT_TYPE_DRQ\r\n")));
goto ExitDone;
}
break;
case WAIT_TYPE_NOT_DRQ:
if (!(bStatusRead & ATA_STATUS_DATA_REQ)) {
DEBUGMSG(ZONE_IO, (TEXT("ATAPI:WaitForDisc - WAIT_TYPE_NOT_DRQ\r\n")));
goto ExitDone;
}
break;
case WAIT_TYPE_ERROR:
if (bStatusRead & ATA_STATUS_ERROR) {
DEBUGMSG(ZONE_IO, (TEXT("ATAPI:WaitForDisc - WAIT_TYPE_ERROR\r\n")));
goto ExitDone;
}
break;
}
if ((int)dwTimeOut > 0) {
StallExecution(dwPeriod);
dwTimeOut -= dwPeriod;
} else {
DEBUGMSG(ZONE_ERROR, (TEXT("ATAPI:WaitForDisc - TimeOut !!! WaitType = %ld Status=%02X\r\n"), bStatusType, bStatusRead));
return ERROR_GEN_FAILURE;
}
}
ExitDone:
return ERROR_SUCCESS;
}
/*------------------------------------------------------------------------------------------*/
//
// Wait for DRQ is set and device is read
// to transfer data or timeout is occured
// Return (Status == ATA_STATUS_DATA_REQ)
//
BOOL CDisk::WaitForDRQ()
{
DWORD i,j;
BYTE bStatus;
for (i=0; i< DEFAULT_WAIT_CHECK_ITER; i++) {
for (j=0; j<DEFAULT_WAIT_SAMPLE_TIMES; j++) {
bStatus = GetAltStatus() & (ATA_STATUS_BUSY|ATA_STATUS_DATA_REQ);
if (bStatus & ATA_STATUS_BUSY) {
continue;
}
if (bStatus & ATA_STATUS_DATA_REQ){
DEBUGMSG(ZONE_IO, (TEXT("ATAPI: ATA_STATUS_DATA_REQ J=: %x \r\n"),j));
return TRUE;
}
StallExecution(DEFAULT_WAIT_STALL_TIME);
}
DEBUGMSG( ZONE_WARNING, (TEXT("ATAPI:WaitForDRQ Status=%02X Error=%02X Reason=%02X\r\n"), GetAltStatus(), GetError(), GetReason()));
}
//RetailPrint1("ATAPIPCI: ATA_STATUS_DATA_REQ (Sleep)i= %x \r\n",i);
return(bStatus == ATA_STATUS_DATA_REQ);
}
/*------------------------------------------------------------------------------------------*/
//
//
// Returns: An interrupt reason for success; ATA_INTR_ERROR otherwise
//
// - ATA_INTR_CMD if Device ready to accept command packed
// - ATA_INTR_READ if Device ready to transfer Data to Host
// - ATA_INTR_WRITE if Device ready to read Data from Host
// - ATA_INTR_MSG if Device ready to send message to Host
// - ATA_INTR_READY if Device completed command processing
//
//
// ATAPI Interrupt Reason & Status Reg. Results
//
// DRQ-IO-CoD
//#define ATA_INTR_CMD 5 // 1- 0 - 1 (5) ATA Device acknowledge command
//#define ATA_INTR_MSG 7 // 1- 1 - 1 (7) ATA Device ready to send MSG (Future) to host
//#define ATA_INTR_READ 6 // 1- 1 - 0 (6) ATA Device ready to transfer data to host
//#define ATA_INTR_WRITE 4 // 1- 0 - 0 (4) ATA Device ready to receive data from host
//#define ATA_INTR_READY 3 // 0- 1 - 1 (3) ATA Device Processing Completed
//#define ATA_INTR_ERROR 0 // Return value in case of Device error
//#define ATA_INTR_DMA 8 // DMA Interrupt
WORD CDisk::CheckIntrState()
{
BYTE bReason, bDRQ;
WaitOnBusy(FALSE);
bReason = GetReason() & (ATA_IR_CoD | ATA_IR_IO);
bDRQ = GetAltStatus() & ATA_STATUS_DATA_REQ;
if (bDRQ)
bReason |=4;
if (bReason < 3)
return((WORD) ATA_INTR_READY);
return ((WORD) bReason);
}
/*------------------------------------------------------------------------------------------*/
//
// The smalest transfer unit between Ata device and host is one WORD.
// We have to save the last read but unused byte for the following
// transaction.
void CDisk::ReadBuffer(PBYTE pBuffer,DWORD dwCount)
{
//
// This is very unefficient way to solve word allignment violation.
union {
WORD us;
BYTE uc[2];
}unisc;
if (dwCount == 0)
return;
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadBuffer Entry Status: %x\r\n"),GetAltStatus()));
// Check whether required byte was already read in previous transaction!
// Value -1 in m_wNextByte means - no byte was read.
if (m_wNextByte != 0xFFFF) {
DEBUGMSG( ZONE_WARNING, (TEXT("ATAPI:ReadBuffer - Unaligned buffer on prevous read!!!\r\n")));
// Update the first byte.
*pBuffer++ = (BYTE) m_wNextByte;
dwCount--;
}
//
// Check allignemt of pBuffer
//
if ((DWORD) pBuffer & 1) {
DEBUGMSG( ZONE_WARNING, (TEXT("ATAPI:ReadBuffer - Unaligned buffer !!!\r\n")));
while (dwCount> 1)
{
unisc.us = ReadWord();
*pBuffer++= unisc.uc[0];
*pBuffer++= unisc.uc[1];
dwCount-=2;
}
} else {
ReadWordBuffer((PWORD)pBuffer,(DWORD)(dwCount)/sizeof(SHORT));
pBuffer += dwCount;
dwCount &= 1; // If 1, we need to read the next byte yet
pBuffer -= dwCount; // Adjust pBuffer if its value is odd
}
//
// Also we have to read one Word event if need only one byte.
// Save unused byte and use it as the first byte in the following SG buffer.
if (dwCount == 1) {
DEBUGMSG( ZONE_WARNING, (TEXT("ATAPI:ReadBuffer - reading one word!!!\r\n")));
unisc.us = ReadWord();
*pBuffer= unisc.uc[0];
m_wNextByte = (WORD)unisc.uc[1]; // Save byte for the next SG if
}
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:ReadBuffer Exit Status: %x\r\n"),GetAltStatus()));
}
/*------------------------------------------------------------------------------------------*/
//
// The smalest transfer unit between Ata device and the host is one WORD.
// We have to save the last read but unused byte for the following
// transaction.
void CDisk::WriteBuffer(PBYTE pBuffer, DWORD dwCount)
{
//
// This is very inefficient way to solve word allignment violation.
union {
WORD us;
BYTE uc[2];
}unisc;
if (dwCount == 0)
return;
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:WriteBuffer Entry Status: %x\r\n"),GetAltStatus()));
// Check whether one byte left from the previous transaction!
// Value -1 in m_wNextByte means - no byteleft.
if (m_wNextByte != 0xFFFF) {
// Update the first byte
DEBUGMSG( ZONE_WARNING, (TEXT("ATAPI:ReadBuffer - Unaligned buffer on prevous read!!!\r\n")));
unisc.uc[0] = (BYTE) m_wNextByte;
unisc.uc[1] = *pBuffer++;
dwCount--;
WriteWord(unisc.us);
}
//
// Check allignemt of pBuffer
//
if ((DWORD) pBuffer & 1) {
DEBUGMSG( ZONE_WARNING, (TEXT("ATAPI:ReadBuffer - Unaligned buffer !!!\r\n")));
while (dwCount> 1) {
unisc.uc[0] = *pBuffer++;
unisc.uc[1] = *pBuffer++;
WriteWord(unisc.us);
dwCount-=2;
}
} else {
WriteWordBuffer((PWORD)pBuffer,(DWORD)(dwCount)/sizeof(SHORT));
pBuffer += dwCount;
dwCount &= 1; // If 1, we need to write the next byte yet
pBuffer -= dwCount; // Adjust pBuffer if its value is odd
}
//
// Also we have to transfer one Word event if need only one byte.
// Save unused byte and use it as the first byte in the following SG buffer.
if (dwCount == 1) {
DEBUGMSG( ZONE_WARNING, (TEXT("ATAPI:ReadBuffer - reading one word!!!\r\n")));
m_wNextByte = (WORD) *pBuffer; // Save byte for the next SG if
}
DEBUGMSG( ZONE_IO, (TEXT("ATAPI:WriteBuffer Exit Status: %x\r\n"),GetAltStatus()));
}
/*------------------------------------------------------------------------------------------*/
#define IDE_COMMAND_SET_FEATURE 0xEF
BOOL CDisk::SetTransferMode(BYTE bMode)
{
BYTE bError, bStatus;
SelectDevice();
WaitForDisc(WAIT_TYPE_NOT_BUSY, 100);
WaitForDisc(WAIT_TYPE_READY, 1000);
WaitOnBusy(TRUE);
SelectDevice();
WriteFeature(ATA_SET_TRANSFER_MODE);
WriteSectorCount( bMode);
WriteSectorNumber(0);
WriteLowCount(0);
WriteHighCount(0);
WriteCommand( IDE_COMMAND_SET_FEATURE);
SelectDevice();
WaitOnBusy(TRUE);
//
// Set Default PIO mode
//
SelectDevice();
WaitForDisc(WAIT_TYPE_NOT_BUSY, 200);
bStatus = GetBaseStatus();
bError = GetError();
DEBUGMSG( 1, (TEXT("ATAPI:SetTransferMode Mode=%02X Status=%02X Error=%02X\r\n"), bMode, bStatus, bError));
if ((bStatus & 0x1) && (bError & 0x4)) {
ResetController(FALSE);
return FALSE;
}
return TRUE;
}
void CDisk::SetBestTransferMode()
{
if ((m_dwBestPioMode != -1) && (m_dwBestPioMode >= 2)) {
SetTransferMode( (BYTE)m_dwBestPioMode | ATA_PIO_FCT_MODE);
}
#if 0
if (m_dwBestMwDmaMode != -1) {
SetTransferMode( (BYTE)m_dwBestMwDmaMode | ATA_DMA_MULTI_WORD_MODE);
}
if (m_dwBestUDmaMode != -1) {
SetTransferMode( (BYTE)m_dwBestUDmaMode | ATA_DMA_ULTRA_MODE);
}
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -