diskmain.cpp
来自「6410BSP3」· C++ 代码 · 共 1,948 行 · 第 1/5 页
CPP
1,948 行
// an error occurred
if (dwRetries < HPIOI1_CHECK_STATUS_RETRIES) {
dwRetries++;
Sleep(5);
goto HPIOI1_Check_Status;
}
fResult = FALSE;
goto exit;
}
if (bStatus & ATA_STATUS_BUSY) { // BSY=1
goto HPIOI1_Check_Status;
}
if (!(bStatus & ATA_STATUS_BUSY) && (bStatus & ATA_STATUS_DATA_REQ)) { // BSY=0 and DRQ=1
goto HPIOI2_Transfer_Data;
}
// HPIOI2:Transfer_Data
// --------------------
// (IDENTIFY [ATAPI] DEVICE only returns a single DRQ data block)
HPIOI2_Transfer_Data:;
cbIdentifyDeviceData = sizeof(IDENTIFY_DATA);
DEBUGCHK(cbIdentifyDeviceData <= BYTES_PER_SECTOR);
// read result of IDENTIFY DEVICE/IDENTIFY PACKET DEVICE
if (m_f16Bit) {
USHORT temp[sizeof(IDENTIFY_DATA)/2];
USHORT value;
cbIdentifyDeviceData /= 2;
ReadWordBuffer((PWORD)temp, cbIdentifyDeviceData);
for (DWORD i=0; i<cbIdentifyDeviceData ; i++)
{
value = ((*(temp + i)& 0xff00) >> 8) & 0xff;
value |= ((*(temp + i)& 0xff ) << 8) & 0xff00;
*(((USHORT *)(&m_Id)) + i) = value;
}
}
else {
ReadByteBuffer((PBYTE)&m_Id, cbIdentifyDeviceData);
}
// ignore extraneous data
while (GetAltStatus() & ATA_STATUS_DATA_REQ ) {
if (m_f16Bit) {
ReadWord();
}
else {
ReadByte();
}
}
*((UINT32 *)(m_pATAReg + ATA_CFG)) &= ~(0x40);
// Return to Host Idle protocol
exit:;
// clear pending interrupt, if applicable
GetBaseStatus();
return fResult;
}
// ----------------------------------------------------------------------------
// Function: Identify
// This function initiates communication with a device. If the
// appropriate device is detected on the current channel, then issue an
// EXECUTE DEVICE DIAGNOSTIC to determine whether the device is a master
// or slave and ATA or ATAPI device. Then, issue an IDENTIFY DEVICE/
// IDENTIFY PACKET DEVICE and select the appropriate READ/WRITE command.
// Finally, assemble the device's associated DISK_INFO structure.
//
// Parameters:
// None
// ----------------------------------------------------------------------------
BOOL CDisk::Identify()
{
DWORD dwBlockSize = 0; // Size of IDENTIFY DEVICE/IDENTIFY PACKET DEVICE information.
WORD wDevType = 0; // Supported command packet set (e.g., direct-access, CD-ROM, etc.).
TakeCS();
// If device isn't present, exit.
if (FALSE == IsDevicePresent()) {
ReleaseCS();
return FALSE;
}
// Issue EXECUTE DEVICE DIAGNOSTIC. Determine whether the device is ATA or
// ATAPI (ignore the result of this call, as old devices fail to respond
// correctly).
BYTE bDiagnosticCode;
BOOL fIsAtapi;
SendExecuteDeviceDiagnostic(&bDiagnosticCode, &fIsAtapi);
// Is this an ATA device?
if (TRUE == SendIdentifyDevice(FALSE)) { // fIsAtapi=FALSE
m_fAtapiDevice = FALSE;
// Some IDE controllers have problems with ATAPI DMA.
if (2 == m_pPort->m_pDskReg[m_dwDeviceId]->dwDMA) { // 0=PIO, 1=DMA, 2=ATA DMA only
m_fDMAActive = TRUE;
}
}
// Is this an ATAPI device?
else if (TRUE == SendIdentifyDevice(TRUE)) { // fIsAtapi=TRUE
m_fAtapiDevice = TRUE;
}
else {
DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T("Atapi!CDisk::Identify> Device failed to respond to IDENTIFY DEVICE and IDENTIFY PACKET DEVICE\r\n")));
ReleaseCS();
return FALSE;
}
ReleaseCS();
// Validate IDENTIFY DEVICE/IDENTIFY PACKET DEVICE signature; an empty
// channel may return invalid data.
DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::Identify> ATA-Disk Total Sector Size 0x%x\r\n"), m_Id.TotalUserAddressableSectors));
if ((m_Id.GeneralConfiguration == 0) || (m_Id.GeneralConfiguration == 0xffff) ||
(m_Id.GeneralConfiguration == 0xff7f) ||
(m_Id.GeneralConfiguration == 0x7fff) ||
((m_Id.GeneralConfiguration == m_Id.IntegrityWord) && (m_Id.NumberOfCurrentCylinders == m_Id.IntegrityWord))
) {
DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T(
"Atapi!CDisk::Identify> General configuration(%04X) not valid; device not present\r\n"
), m_Id.GeneralConfiguration));
return FALSE;
}
// Dump IDENTFY DEVICE/IDENTIFY PACKET DEVICE data.
PIDENTIFY_DATA pId = &m_Id;
DUMPIDENTIFY(pId);
DUMPSUPPORTEDTRANSFERMODES(pId);
// ATA/ATAPI-3 compatible devices store the supported command packet set in
// bits 12-8 of word 0 of IDENTIFY DEVICE/IDENTIFY PACKET DEVICE data (this
// information is retired in ATA/ATAPI-6). Determine which command packet
// set is implemented by the device.
wDevType = (m_Id.GeneralConfiguration >> 8) & 0x1F;
switch (wDevType) {
case ATA_IDDEVICE_UNKNOWN:
return FALSE;
case ATA_IDDEVICE_CDROM:
m_dwDeviceFlags |= DFLAGS_DEVICE_CDROM;
break;
case ATA_IDDEVICE_DISK:
break;
case ATA_IDDEVICE_OPTICAL_MEM:
break;
default:
DEBUGMSG(ZONE_INIT, (_T("Atapi!CDisk::Identify> Assuming direct-access device (hard disk drive)\r\n")));
break;
}
// This is redundant, but various routines use this information.
m_dwDeviceFlags |= DFLAGS_DEVICE_PRESENT;
m_dwDeviceFlags |= (IsAtapiDevice()) ? DFLAGS_ATAPI_DEVICE : 0;
m_dwDeviceFlags |= (IsRemoveableDevice()) ? DFLAGS_REMOVABLE_DRIVE : 0;
// ATA devices support two flavors of read/write commands: READ/WRITE
// SECTOR(S) and READ/WRITE MULTIPLE. READ/WRITE SECTOR(S) use a fixed DRQ
// data block size of 1 sector and READ/WRITE MULTIPLE use a driver-
// specified (variable) DRQ data block size of up to 255 sectors.
if (FALSE == IsAtapiDevice()) {
// Default to READ/WRITE SECTOR(S).
m_bReadCommand = ATA_CMD_READ;
m_bWriteCommand = ATA_CMD_WRITE;
m_bSectorsPerBlock = 1;
// Is READ/WRITE MULTIPLE supported?
if (0 != m_Id.MaximumBlockTransfer) {
// The device supports a variable DRQ data block size. Set the DRQ
// data block size to the minimum of the registry-specified DRQ
// data block size and the maximum DRQ data block size supported by
// the device.
if (0 == m_pPort->m_pDskReg[m_dwDeviceId]->dwDrqDataBlockSize) {
// Use device's maximum DRQ data block size.
m_bSectorsPerBlock = m_Id.MaximumBlockTransfer;
}
else {
m_bSectorsPerBlock = MIN((BYTE)(m_pPort->m_pDskReg[m_dwDeviceId]->dwDrqDataBlockSize / SECTOR_SIZE), m_Id.MaximumBlockTransfer);
}
SelectDevice();
WriteSectorCount(m_bSectorsPerBlock);
WriteCommand(ATA_CMD_SET_MULTIPLE);
if ((FALSE == WaitOnBusy(FALSE)) && (ATA_STATUS_READY & GetAltStatus())) {
m_bReadCommand = ATA_CMD_MULTIPLE_READ;
m_bWriteCommand = ATA_CMD_MULTIPLE_WRITE;
DEBUGMSG(ZONE_INIT, (_T("Atapi!CDisk::Identify> Set DRQ data block size to %d sectors (READ/WRITE MULTIPLE sectors per interrupt)\r\n"), m_bSectorsPerBlock));
}
else {
// Revert DRQ data block size.
DEBUGMSG(ZONE_INIT, (_T("Atapi!CDisk::Identify> Failed to set DRQ data block size to %d sectors; using READ/WRITE SECTOR(S)\r\n"), m_bSectorsPerBlock));
m_bSectorsPerBlock = 1;
}
}
}
m_bDMAReadCommand = ATA_CMD_READ_DMA;
m_bDMAWriteCommand = ATA_CMD_WRITE_DMA;
// Assemble DISK_INFO structure.
m_fLBAMode = (m_Id.Capabilities & 0x0200) ? TRUE : FALSE;
m_DiskInfo.di_flags = DISK_INFO_FLAG_MBR;
m_DiskInfo.di_bytes_per_sect = BYTES_PER_SECTOR;
m_DiskInfo.di_cylinders = m_Id.NumberOfCylinders;
m_DiskInfo.di_heads = m_Id.NumberOfHeads;
m_DiskInfo.di_sectors = m_Id.SectorsPerTrack;
if (m_fLBAMode) {
m_DiskInfo.di_total_sectors = m_Id.TotalUserAddressableSectors;
ConfigLBA48(); // set m_fUseLBA48 if applicable
}
else {
m_DiskInfo.di_total_sectors = m_DiskInfo.di_cylinders*m_DiskInfo.di_heads * m_DiskInfo.di_sectors;
}
return TRUE;
}
// ----------------------------------------------------------------------------
// Function: ConfigLBA48
// This is a helper function which is called after the IDENTIFY_DEVICE
// command has been successfully executed. It parses the results
// of the IDENTIFY_DEVICE command to determine if 48-bit LBA is supported
// by the device.
//
// Parameters:
// None
// ----------------------------------------------------------------------------
void CDisk::ConfigLBA48(void)
{
PIDENTIFY_DATA pId = (PIDENTIFY_DATA)&m_Id;
if (m_pPort->m_pController->m_pIdeReg->dwDisable48BitLBA)
{
m_fUseLBA48 = FALSE;
return;
}
// Word 87 (CommandSetFeatureDefault):
// bit 14 is set and bit 15 is cleared if config data
// in word 86 (CommandSetFeatureEnabled2) is valid.
// Note that this is only valid for non-ATAPI devices
if ( !IsAtapiDevice() &&
(pId->CommandSetFeatureDefault & (1 << 14)) &&
!(pId->CommandSetFeatureDefault & (1 << 15)) &&
(pId->CommandSetFeatureEnabled2 & (1 << 10)) )
{
DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> Device supports 48-bit LBA\r\n")));
DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> Max LBA Address = 0x%08x%08x"),
pId->lMaxLBAAddress[1],
pId->lMaxLBAAddress[0]));
DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> Device supports 48-bit LBA\r\n")));
DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> Max LBA Address = 0x%08x, 0x%08x"),
pId->lMaxLBAAddress[1],
pId->lMaxLBAAddress[0]));
m_fUseLBA48 = TRUE;
// The CE file system currently supports a maximum of 32-bit sector addresses,
if (pId->lMaxLBAAddress[1] == 0)
{
m_DiskInfo.di_total_sectors = pId->lMaxLBAAddress[0];
DEBUGMSG(ZONE_INIT, (TEXT("Atapi!CDisk::ConfigLBA48> This disk supports LBA48 mode and total sector 0x%x\r\n"), m_DiskInfo.di_total_sectors));
}
else
m_DiskInfo.di_total_sectors = 0xFFFFFFFF; // Couldn't find MAX_DWORD
ASSERT(pId->lMaxLBAAddress[1] <= 0x10000);
// CDisk::Identify has determined whether or not the device supports multi-sector transfers
// Update read/write command to use [READ|WRITE] [SECTORS|MULTIPLE] EXT
if (m_bReadCommand == ATA_CMD_READ)
{
m_bReadCommand = ATA_CMD_READ_SECTOR_EXT;
m_bWriteCommand = ATA_CMD_WRITE_SECTOR_EXT;
}
else // CDisk::Identify has determined that the devce supports multi-sector transfers
{
m_bReadCommand = ATA_CMD_READ_MULTIPLE_EXT;
m_bWriteCommand = ATA_CMD_WRITE_MULTIPLE_EXT;
}
m_bDMAReadCommand = ATA_CMD_READ_DMA_EXT;
m_bDMAWriteCommand = ATA_CMD_WRITE_DMA_EXT;
}
else
{
m_fUseLBA48 = FALSE;
}
}
// ----------------------------------------------------------------------------
// Function: ValidateSg
// Map embedded pointers
//
// Parameters:
// pSgReq -
// InBufLen - The size of the actual buffer as specified by the user.
// This needs to be cross checked with pSgReq->sr_num_sg to
// prevent buffer overflows
// saveoldptrs - Your old pointers are saved here. Must be at least
// pSgReq->sr_num_sg in size
// ----------------------------------------------------------------------------
BOOL
CDisk::ValidateSg(
PSG_REQ pSgReq,
DWORD InBufLen,
DWORD dwArgType,
OUT PUCHAR * saveoldptrs
)
{
DWORD dwIndex ;
PUCHAR ptemp;
if (NULL == pSgReq) {
ASSERT(pSgReq);
return FALSE;
}
if (InBufLen < sizeof(SG_REQ)) {
ASSERT(InBufLen >= sizeof(SG_REQ));
return FALSE;
}
// pSgReq is a sterile copy of the caller's SG_REQ; we're supposed to map
// the embedded sb_bufs back into the SG_REQ
if(
!(pSgReq->sr_num_sg >= 1) ||
!(pSgReq->sr_num_sg <= MAX_SG_BUF) ||
!((sizeof(SG_REQ) + sizeof(SG_BUF)*(pSgReq->sr_num_sg-1)) == InBufLen) ||
!(pSgReq->sr_num_sec > 0))
{
ASSERT(pSgReq->sr_num_sg >= 1);
ASSERT(pSgReq->sr_num_sg <= MAX_SG_BUF);
ASSERT((sizeof(SG_REQ) + sizeof(SG_BUF)*(pSgReq->sr_num_sg-1)) == InBufLen);
ASSERT(pSgReq->sr_num_sec > 0);
return FALSE;
}
for (dwIndex = 0; dwIndex < pSgReq->sr_num_sg; dwIndex++) {
if (
(NULL == pSgReq->sr_sglist[dwIndex].sb_buf) ||
(0 == pSgReq->sr_sglist[dwIndex].sb_len)
) {
goto CleanUpLeak;
}
// Verify embedded pointer access and map user mode pointers
if (FAILED(CeOpenCallerBuffer(
(PVOID *)&ptemp,
(LPVOID)pSgReq->sr_sglist[dwIndex].sb_buf,
pSgReq->sr_sglist[dwIndex].sb_len,
dwArgType,
FALSE)))
{
goto CleanUpLeak;
}
saveoldptrs[dwIndex] = pSgReq->sr_sglist[dwIndex].sb_buf;
pSgReq->sr_sglist[dwIndex].sb_buf = ptemp;
if (NULL == pSgReq->sr_sglist[dwIndex].sb_buf) {
goto CleanUpLeak;
}
}
return TRUE;
CleanUpLeak:
if (FAILED(UnmapSg(
pSgReq->sr_sglist,
saveoldptrs,
dwIndex,
dwArgType)))
{
ASSERT(!"Cleanup call to CeCloseCallerBuffer failed unexpectedly");
return FALSE;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?