?? diskmain.cpp
字號:
// HPIOI1:Check_Status
// -------------------
HPIOI1_Check_Status:;
__try {
bStatus = GetAltStatus();
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_ERROR, (_T(
"Atapi!CDisk::SendIdentifyDevice> Exception\r\n"
)));
fResult = FALSE;
goto exit;
}
if (!(bStatus & (ATA_STATUS_BUSY|ATA_STATUS_DATA_REQ))) { // BSY=0 and DRQ=0
// 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) {
cbIdentifyDeviceData /= 2;
ReadWordBuffer((PWORD)&m_Id, cbIdentifyDeviceData);
}
else {
ReadByteBuffer((PBYTE)&m_Id, cbIdentifyDeviceData);
}
// ignore extraneous data
while (GetAltStatus() & ATA_STATUS_DATA_REQ ) {
if (m_f16Bit) {
ReadWord();
}
else {
ReadByte();
}
}
// Return to Host Idle protocol
exit:;
return fResult;
}
// ----------------------------------------------------------------------------
// Function: Identify
// This function initiates communication with the device. If the
// appropriate device is detected on the channel, then instruct the device
// to execute a diagnostic. Issue IDENTIFY DEVICE/IDENTIFY PACKET DEVICE.
// Validate the IDENTIFY data. Inspect IDENTIFY data (if ATA, determine
// which read/write commands to use, store disk geometry, etc.)
//
// Parameters:
// None
// ----------------------------------------------------------------------------
BOOL
CDisk::Identify(
)
{
DWORD dwBlockSize = 0; // size of IDENTIFY DEVICE/IDENTIFY PACKET DEVICE information
WORD wDevType = 0; // command packet set implemented by device (e.g., direct-access, CD-ROM, etc.)
DWORD dwCHS = 0; // whether the registry specifies that the device is to use C/H/S mode
BYTE bDiagnosticCode; // SendExecuteDeviceDiagnostic argument
BOOL fIsAtapi; // SendExecuteDeviceDiagnostic argument
TakeCS();
// test for device present
if (!IsDevicePresent()) {
ReleaseCS();
return FALSE;
}
// issue EXECUTE DEVICE DIAGNOSTIC; determine whether device is ATA or ATAPI
// (ignore the result of this call, as old devices fail to respond correctly)
SendExecuteDeviceDiagnostic(&bDiagnosticCode, &fIsAtapi);
// try ATA device
if (SendIdentifyDevice(FALSE)) { // fIsAtapi=FALSE
m_fAtapiDevice = FALSE;
// ALi IDE/ATA controller tweak for supporting a DMA-enabled ATAPI device
if (2 == m_pPort->m_pDskReg[m_dwDeviceId]->dwDMA) { // 0=PIO, 1=DMA, 2=ATA DMA only
m_fDMAActive = TRUE;
}
}
else {
// try ATAPI device
if (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; any empty
// channel may return invalid data
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 IDENTIFY DEVICE/IDENTIFY PACKET DEVICE data and supported transfer modes
PIDENTIFY_DATA pId = &m_Id;
DUMPIDENTIFY(pId);
DUMPSUPPORTEDTRANSFERMODES(pId);
// ATA/ATAPI-3 compatible devices store command packet set implemented by
// device in bits 12-8 of word 0 of IDENTIFY DEVICE/IDENTIFY PACKET DEVICE
// data (this information is retired in ATA/ATAPI-6)
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;
// ATAPI devices use ATAPI read/write commands; ATA devices support
// single- and multi-sector transfers; if this is an ATA device, then
// select multi-sector transfers, if supported
if (!IsAtapiDevice()) {
// default to single-sector transfers
m_bReadCommand = ATA_CMD_READ; m_bWriteCommand = ATA_CMD_WRITE;
if (m_Id.MaximumBlockTransfer != 0) {
// device supports multi-sector transfers; enable multi-sector
// transfers; issue SET MULTIPLE MODE command
SelectDevice();
WriteSectorCount((BYTE)m_Id.MaximumBlockTransfer);
WriteCommand(ATA_CMD_SET_MULTIPLE);
if (!WaitOnBusy(FALSE) && (GetAltStatus() & ATA_STATUS_READY)) {
m_bReadCommand = ATA_CMD_MULTIPLE_READ; m_bWriteCommand = ATA_CMD_MULTIPLE_WRITE;
m_bSectorsPerBlock = m_Id.MaximumBlockTransfer;
}
else {
DEBUGMSG(ZONE_INIT, (_T(
"Atapi!CDisk::Identify> (Warning) Failed to enable multi-sector transfers; using single-sector transfers\r\n"
)));
}
}
}
m_fLBAMode = (m_Id.Capabilities & 0x0200) ? TRUE : FALSE;
m_DiskInfo.di_flags = DISK_INFO_FLAG_MBR; // all ATA storage devices have an MBR
m_DiskInfo.di_bytes_per_sect = BYTES_PER_SECTOR; // start with 512, then go with SetInfo changes
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;
}
else {
m_DiskInfo.di_total_sectors= m_DiskInfo.di_cylinders*m_DiskInfo.di_heads*m_DiskInfo.di_sectors;
}
return TRUE;
}
// ----------------------------------------------------------------------------
// Function: ValidateSg
// Map embedded pointers
//
// Parameters:
// pSgReq -
// InBufLen -
// ----------------------------------------------------------------------------
BOOL
CDisk::ValidateSg(
PSG_REQ pSgReq,
DWORD InBufLen
)
{
if (PSLGetCallerTrust() != OEM_CERTIFY_TRUST) {
if (pSgReq && InBufLen >= (sizeof(SG_REQ) + sizeof(SG_BUF) * (pSgReq->sr_num_sg - 1))) {
DWORD dwIndex;
for (dwIndex = 0; dwIndex < pSgReq -> sr_num_sg; dwIndex++) {
pSgReq->sr_sglist[dwIndex].sb_buf = (PUCHAR)MapCallerPtr((LPVOID)pSgReq->sr_sglist[dwIndex].sb_buf,pSgReq->sr_sglist[dwIndex].sb_len);
}
}
else {
return FALSE;
}
}
return TRUE;
}
// ----------------------------------------------------------------------------
// Function: ValidateSg
// Map embedded pointers
//
// Parameters:
// pCdrom -
// InBufLen -
// ----------------------------------------------------------------------------
BOOL
CDisk::ValidateSg(
PCDROM_READ pCdrom,
DWORD InBufLen
)
{
if (PSLGetCallerTrust() != OEM_CERTIFY_TRUST) {
if (pCdrom && InBufLen >= (sizeof(CDROM_READ) + sizeof(SGX_BUF) * (pCdrom->sgcount - 1))) {
DWORD dwIndex;
for (dwIndex = 0; dwIndex < pCdrom-> sgcount; dwIndex++) {
pCdrom->sglist[dwIndex].sb_buf = (PUCHAR)MapCallerPtr((LPVOID)pCdrom->sglist[dwIndex].sb_buf,pCdrom->sglist[dwIndex].sb_len);
}
}
else {
return FALSE;
}
}
return TRUE;
}
// ----------------------------------------------------------------------------
// Function: SendDiskPowerCommand
// Put the device into a specified power state. The optional parameter is
// programmed into the Sector Count register, which is used for the
// ATA NEW CMD IDLE and ATA CMD STANDBY commands.
//
// Parameters:
// bCmd -
// bParam -
// ----------------------------------------------------------------------------
BOOL
CDisk::SendDiskPowerCommand(
BYTE bCmd,
BYTE bParam
)
{
BYTE bError, bStatus;
BOOL fOk = TRUE;
if(ZONE_CELOG) CeLogData(TRUE, CELID_ATAPI_POWERCOMMAND, &bCmd, sizeof(bCmd), 0, CELZONE_ALWAYSON, 0, FALSE);
// HI:Check_Status (Host Idle); wait until BSY=0 and DRQ=0
// read Status register
while (1) {
bStatus = GetAltStatus();
if (!(bStatus & (0x80|0x08))) break; // BSY := Bit 7, DRQ := Bit 3
Sleep(5);
}
// HI:Device_Select; select device
SelectDevice();
// HI:Check_Status (Host Idle); wait until BSY=0 and DRQ=0
// read Status register
while (1) {
bStatus = GetAltStatus();
if (!(bStatus & (0x80|0x08))) break; // BSY := Bit 7, DRQ := Bit 3
Sleep(5);
}
// HI:Write_Parameters
WriteSectorCount(bParam);
// WriteAltDriveController(0x00); // disable interrupt (nIEN := Bit 1 of Device Control register)
// HI:Write_Command
WriteCommand(bCmd);
// transition to non-data command protocol
// HND:INTRQ_Wait
// transition to HND:Check_Status
// read Status register
while (1) { // BSY := Bit 7
bStatus = GetAltStatus();
bError = GetError();
if (bError & 0x04) { // ABRT := Bit 2
// command was aborted
DEBUGMSG(ZONE_ERROR, (_T(
"Atapi!CDisk::SendDiskPowerCommand> Failed to send command 0x%x, parameter 0x%x\r\n"
), bCmd, bParam));
fOk = FALSE;
break;
}
if (!(bStatus & 0x80)) break; // BSY := Bit 7
Sleep(5);
}
// transition to host idle protocol
return fOk;
}
// ----------------------------------------------------------------------------
// Function: GetDiskPowerInterface
// Return the power management object associated with this device
//
// Parameters:
// None
// ----------------------------------------------------------------------------
CDiskPower *
CDisk::GetDiskPowerInterface(
void
)
{
CDiskPower *pDiskPower = new CDiskPower;
return pDiskPower;
}
// ----------------------------------------------------------------------------
// Function: SetDiskPowerState
// Map a power state to an ATA power management command and issue the
// command
//
// Parameters:
// newDx -
// ----------------------------------------------------------------------------
BOOL
CDisk::SetDiskPowerState(
CEDEVICE_POWER_STATE newDx
)
{
BYTE bCmd;
if (ZONE_CELOG) {
DWORD dwDx = (DWORD) newDx;
CeLogData(TRUE, CELID_ATAPI_SETDEVICEPOWER, &dwDx, sizeof(dwDx), 0, CELZONE_ALWAYSON, 0, FALSE);
}
// on D0 go to IDLE to minimize latency during disk accesses
if(newDx == D0 || newDx == D1) {
bCmd = ATA_CMD_IDLE_IMMEDIATE;
}
else if(newDx == D2) {
bCmd = ATA_CMD_STANDBY_IMMEDIATE;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -