You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1243 lines
36 KiB
1243 lines
36 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
//
|
|
// File: util.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "ide.h"
|
|
|
|
#pragma alloc_text(NONPAGE, IdePortChannelEmpty)
|
|
#pragma alloc_text(PAGE, DigestResourceList)
|
|
#pragma alloc_text(PAGE, AtapiBuildIoAddress)
|
|
#pragma alloc_text(PAGE, IdeGetDeviceCapabilities)
|
|
|
|
#pragma alloc_text(NONPAGE, IdePortpWaitOnBusyEx)
|
|
|
|
#pragma alloc_text(PAGE, IdeCreateIdeDirectory)
|
|
|
|
#ifdef DPC_FOR_EMPTY_CHANNEL
|
|
BOOLEAN
|
|
IdePortIdentifyDevice(
|
|
IN PIDE_REGISTERS_1 CmdRegBase,
|
|
IN PIDE_REGISTERS_2 CtrlRegBase,
|
|
IN ULONG MaxIdeDevice
|
|
)
|
|
{
|
|
UCHAR statusByte1;
|
|
ULONG retryCount=4;
|
|
BOOLEAN emptyChannel=TRUE;
|
|
ULONG deviceNumber=0;
|
|
ULONG i;
|
|
|
|
retryCount = 4;
|
|
emptyChannel = TRUE;
|
|
deviceNumber = 0;
|
|
|
|
retryIdentifier:
|
|
|
|
//
|
|
// Select the master device
|
|
//
|
|
SelectIdeDevice(CmdRegBase, deviceNumber, 0);
|
|
|
|
//
|
|
// write out indentifier to readable and writable io registers
|
|
//
|
|
WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
|
|
WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
|
|
|
|
//
|
|
// Check if indentifier can be read back.
|
|
//
|
|
if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) ||
|
|
(READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) {
|
|
|
|
statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command);
|
|
|
|
DebugPrint((2,
|
|
"IdePortChannelEmpty: status read back from Master (%x)\n",
|
|
statusByte1));
|
|
|
|
if (statusByte1 & IDE_STATUS_BUSY) {
|
|
|
|
i = 0;
|
|
|
|
//
|
|
// Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that
|
|
// warm boots don't clear.
|
|
//
|
|
|
|
do {
|
|
KeStallExecutionProcessor(1000);
|
|
statusByte1 = READ_PORT_UCHAR(CmdRegBase->Command);
|
|
DebugPrint((3,
|
|
"IdePortChannelEmpty: First access to status %x\n",
|
|
statusByte1));
|
|
} while ((statusByte1 & IDE_STATUS_BUSY) && ++i < 10);
|
|
|
|
if (retryCount-- && (!(statusByte1 & IDE_STATUS_BUSY))) {
|
|
goto retryIdentifier;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Select slave.
|
|
//
|
|
deviceNumber++;
|
|
|
|
SelectIdeDevice(CmdRegBase, deviceNumber, 0);
|
|
|
|
//
|
|
// write out indentifier to readable and writable io registers
|
|
//
|
|
WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
|
|
WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
|
|
|
|
//
|
|
// Check if indentifier can be read back.
|
|
//
|
|
if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) ||
|
|
(READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) {
|
|
|
|
statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command);
|
|
|
|
DebugPrint((2,
|
|
"IdePortChannelEmpty: status read back from Slave (%x)\n",
|
|
statusByte1));
|
|
|
|
} else {
|
|
|
|
emptyChannel = FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
emptyChannel = FALSE;
|
|
}
|
|
|
|
deviceNumber++;
|
|
|
|
if ( (deviceNumber < MaxIdeDevice) && emptyChannel ) {
|
|
goto retryIdentifier;
|
|
}
|
|
|
|
return emptyChannel;
|
|
|
|
} //IdePortIdentifyDevice
|
|
|
|
ULONG
|
|
IdePortChannelEmptyQuick (
|
|
IN PIDE_REGISTERS_1 CmdRegBase,
|
|
IN PIDE_REGISTERS_2 CtrlRegBase,
|
|
IN ULONG MaxIdeDevice,
|
|
IN PULONG CurrentDevice,
|
|
IN PULONG moreWait,
|
|
IN PULONG NoRetry
|
|
)
|
|
{
|
|
//
|
|
// try EXECUTE_DIAGNOSTICS. No.
|
|
//
|
|
|
|
//
|
|
// statusByte1 needs to be initialized to ff
|
|
//
|
|
UCHAR statusByte1=0xff;
|
|
|
|
UCHAR statusByte2;
|
|
ULONG i;
|
|
BOOLEAN allStatusBytesAllFs;
|
|
|
|
allStatusBytesAllFs = TRUE;
|
|
|
|
DebugPrint((1, "ChannelEmptyQuick: wait=%d, Device=%d\n",
|
|
*moreWait, *CurrentDevice));
|
|
if (*moreWait) {
|
|
|
|
(*moreWait)--;
|
|
|
|
SelectIdeDevice(CmdRegBase, (*CurrentDevice), 0);
|
|
|
|
IdePortWaitOnBusyExK (CmdRegBase, statusByte1, 0xff);
|
|
|
|
DebugPrint((1, "ATAPI: Status after first retry=%x\n", statusByte1));
|
|
|
|
if (statusByte1==0xff) {
|
|
(*CurrentDevice)++;
|
|
*moreWait=0;
|
|
}
|
|
}
|
|
|
|
if (*moreWait && (statusByte1 & IDE_STATUS_BUSY)) {
|
|
|
|
return STATUS_RETRY;
|
|
}
|
|
|
|
if (!(*NoRetry) && (statusByte1 & IDE_STATUS_BUSY) &&
|
|
((statusByte1 != 0xfe) &&
|
|
(statusByte1 != 0xff))) {
|
|
|
|
DebugPrint((1,
|
|
"ATAPI: IdePortChannelEmpty: channel looks busy 0x%x. try a reset\n",
|
|
statusByte1));
|
|
|
|
//
|
|
// channel look hung or busy
|
|
//
|
|
// try a hard reset to bring it to idle
|
|
WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_RESET_CONTROLLER);
|
|
|
|
//
|
|
// ATA-2 spec requires a minimum of 5 microsec stall here
|
|
//
|
|
KeStallExecutionProcessor (10);
|
|
|
|
WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_REENABLE_CONTROLLER);
|
|
|
|
i=*CurrentDevice;
|
|
SelectIdeDevice(CmdRegBase, i, 0);
|
|
IdePortWaitOnBusyExK (CmdRegBase, statusByte1, 0xff);
|
|
if ((statusByte1 & IDE_STATUS_BUSY) && (statusByte1 != 0xff)) {
|
|
*moreWait=2; //wait for 2 more timer ticks
|
|
*NoRetry=1;
|
|
return STATUS_RETRY;
|
|
}
|
|
}
|
|
|
|
if (statusByte1 != 0xFF) {
|
|
allStatusBytesAllFs = FALSE;
|
|
(*CurrentDevice)++;
|
|
}
|
|
|
|
for (i=*CurrentDevice; i<MaxIdeDevice && allStatusBytesAllFs; i++) {
|
|
|
|
//
|
|
// make sure device is not busy
|
|
//
|
|
|
|
//
|
|
// Select the master device
|
|
//
|
|
SelectIdeDevice(CmdRegBase, i, 0);
|
|
|
|
if (Is98LegacyIde(CmdRegBase)) {
|
|
if (READ_PORT_UCHAR(CmdRegBase->DriveSelect) != (((i & 0x1) << 4) | 0xA0)) {
|
|
//
|
|
// Bad controller.
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
GetStatus(CmdRegBase, statusByte1);
|
|
DebugPrint((1, "ATAPI:status for device %d after GetStatus=%x\n",i, statusByte1));
|
|
|
|
if (statusByte1 == 0xff) {
|
|
continue;
|
|
}
|
|
|
|
if (statusByte1 == 0xfe) {
|
|
continue;
|
|
}
|
|
|
|
IdePortWaitOnBusyExK (CmdRegBase, statusByte1, 0xff);
|
|
|
|
if ((statusByte1 & 0xfe) == 0xfe) {
|
|
continue;
|
|
}
|
|
|
|
if (statusByte1 & IDE_STATUS_BUSY) {
|
|
DebugPrint((1, "ATAPI: Re-init the counts:device=%d, status=%x",
|
|
i, statusByte1));
|
|
*CurrentDevice=i;
|
|
*moreWait=2;
|
|
*NoRetry=0;
|
|
return STATUS_RETRY;
|
|
}
|
|
|
|
if (statusByte1 != 0xFF) {
|
|
allStatusBytesAllFs = FALSE;
|
|
}
|
|
}
|
|
|
|
if (allStatusBytesAllFs) {
|
|
|
|
//
|
|
// all status bytes are 0xff,
|
|
// no controller at this location
|
|
//
|
|
return 1;
|
|
}
|
|
|
|
i=(IdePortIdentifyDevice(CmdRegBase, CtrlRegBase, MaxIdeDevice)) ? 1: 0;
|
|
return i;
|
|
|
|
}//IdePortChannelEmptyQuick
|
|
|
|
|
|
#endif
|
|
|
|
BOOLEAN
|
|
IdePortChannelEmpty (
|
|
IN PIDE_REGISTERS_1 CmdRegBase,
|
|
IN PIDE_REGISTERS_2 CtrlRegBase,
|
|
IN ULONG MaxIdeDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
quickly check whether a IDE channel exist at the given io location
|
|
|
|
Arguments:
|
|
|
|
CmdRegBase - command registers
|
|
|
|
CtrlRegBase - control registers
|
|
|
|
MaxIdeDevice - number of max devices
|
|
|
|
Return Value:
|
|
|
|
TRUE - Yes, the channel is empty
|
|
FALSE - No, the channel is not empty
|
|
|
|
--*/
|
|
{
|
|
|
|
UCHAR statusByte1;
|
|
UCHAR statusByte2;
|
|
ULONG retryCount;
|
|
ULONG i;
|
|
BOOLEAN emptyChannel;
|
|
ULONG deviceNumber;
|
|
BOOLEAN allStatusBytesAllFs;
|
|
|
|
allStatusBytesAllFs = TRUE;
|
|
for (i=0; i<MaxIdeDevice; i++) {
|
|
|
|
//
|
|
// make sure device is not busy
|
|
//
|
|
|
|
//
|
|
// Select the master device
|
|
//
|
|
SelectIdeDevice(CmdRegBase, i, 0);
|
|
|
|
if (Is98LegacyIde(CmdRegBase)) {
|
|
if (READ_PORT_UCHAR(CmdRegBase->DriveSelect) != (((i & 0x1) << 4) | 0xA0)) {
|
|
//
|
|
// Bad controller.
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
GetStatus(CmdRegBase, statusByte1);
|
|
|
|
if (statusByte1 == 0xff) {
|
|
continue;
|
|
}
|
|
|
|
if (statusByte1 == 0xfe) {
|
|
continue;
|
|
}
|
|
|
|
IdePortWaitOnBusyEx (CmdRegBase, &statusByte1, 0xff);
|
|
|
|
if ((statusByte1 & IDE_STATUS_BUSY) &&
|
|
((statusByte1 != 0xfe) &&
|
|
(statusByte1 != 0xff))) {
|
|
|
|
DebugPrint((1,
|
|
"IdePortChannelEmpty: channel looks busy 0x%x. try a reset\n",
|
|
statusByte1));
|
|
|
|
|
|
//
|
|
// channel look hung or busy
|
|
//
|
|
// try a hard reset to bring it to idle
|
|
WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_RESET_CONTROLLER);
|
|
|
|
//
|
|
// ATA-2 spec requires a minimum of 5 microsec stall here
|
|
//
|
|
KeStallExecutionProcessor (10);
|
|
|
|
WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_REENABLE_CONTROLLER);
|
|
|
|
SelectIdeDevice(CmdRegBase, i, 0);
|
|
IdePortWaitOnBusyEx (CmdRegBase, &statusByte1, 0xff);
|
|
}
|
|
|
|
if (statusByte1 != 0xFF) {
|
|
allStatusBytesAllFs = FALSE;
|
|
}
|
|
}
|
|
|
|
if (allStatusBytesAllFs) {
|
|
|
|
//
|
|
// all status bytes are 0xff,
|
|
// no controller at this location
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef DPC_FOR_EMPTY_CHANNEL
|
|
return IdePortIdentifyDevice(CmdRegBase, CtrlRegBase, MaxIdeDevice);
|
|
#endif
|
|
retryCount = 4;
|
|
emptyChannel = TRUE;
|
|
deviceNumber = 0;
|
|
|
|
retryIdentifier:
|
|
|
|
//
|
|
// Select the master device
|
|
//
|
|
SelectIdeDevice(CmdRegBase, deviceNumber, 0);
|
|
|
|
//
|
|
// write out indentifier to readable and writable io registers
|
|
//
|
|
WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
|
|
WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
|
|
|
|
//
|
|
// Check if indentifier can be read back.
|
|
//
|
|
if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) ||
|
|
(READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) {
|
|
|
|
statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command);
|
|
|
|
DebugPrint((2,
|
|
"IdePortChannelEmpty: status read back from Master (%x)\n",
|
|
statusByte1));
|
|
|
|
if (statusByte1 & IDE_STATUS_BUSY) {
|
|
|
|
i = 0;
|
|
|
|
//
|
|
// Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that
|
|
// warm boots don't clear.
|
|
//
|
|
|
|
do {
|
|
KeStallExecutionProcessor(1000);
|
|
statusByte1 = READ_PORT_UCHAR(CmdRegBase->Command);
|
|
DebugPrint((3,
|
|
"IdePortChannelEmpty: First access to status %x\n",
|
|
statusByte1));
|
|
} while ((statusByte1 & IDE_STATUS_BUSY) && ++i < 10);
|
|
|
|
if (retryCount-- && (!(statusByte1 & IDE_STATUS_BUSY))) {
|
|
goto retryIdentifier;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Select slave.
|
|
//
|
|
deviceNumber++;
|
|
|
|
SelectIdeDevice(CmdRegBase, deviceNumber, 0);
|
|
|
|
//
|
|
// write out indentifier to readable and writable io registers
|
|
//
|
|
WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
|
|
WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
|
|
|
|
//
|
|
// Check if indentifier can be read back.
|
|
//
|
|
if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) ||
|
|
(READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) {
|
|
|
|
statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command);
|
|
|
|
DebugPrint((2,
|
|
"IdePortChannelEmpty: status read back from Slave (%x)\n",
|
|
statusByte1));
|
|
|
|
} else {
|
|
|
|
emptyChannel = FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
emptyChannel = FALSE;
|
|
}
|
|
|
|
deviceNumber++;
|
|
|
|
if ( (deviceNumber < MaxIdeDevice) && emptyChannel ) {
|
|
goto retryIdentifier;
|
|
}
|
|
|
|
return emptyChannel;
|
|
|
|
} //IdePortChannelEmpty
|
|
|
|
NTSTATUS
|
|
DigestResourceList (
|
|
IN OUT PIDE_RESOURCE IdeResource,
|
|
IN PCM_RESOURCE_LIST ResourceList,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *IrqPartialDescriptors
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
|
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
|
|
ULONG resourceListSize;
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
BOOLEAN foundCommandBase;
|
|
BOOLEAN foundControlBase;
|
|
BOOLEAN foundIrqLevel;
|
|
BOOLEAN resourceIsCommandPort;
|
|
|
|
BOOLEAN AtdiskPrimaryClaimed;
|
|
BOOLEAN AtdiskSecondaryClaimed;
|
|
|
|
PHYSICAL_ADDRESS tranlatedAddress;
|
|
|
|
IDE_REGISTERS_1 baseIoAddress1;
|
|
ULONG baseIoAddress1Length;
|
|
|
|
|
|
fullResourceList = ResourceList->List;
|
|
resourceListSize = 0;
|
|
|
|
DebugPrint ((5, "IdePort: DigestResourceList()\n"));
|
|
|
|
foundCommandBase = FALSE;
|
|
foundControlBase = FALSE;
|
|
foundIrqLevel = FALSE;
|
|
*IrqPartialDescriptors = NULL;
|
|
status = STATUS_SUCCESS;
|
|
|
|
AtdiskPrimaryClaimed = FALSE;
|
|
AtdiskSecondaryClaimed = FALSE;
|
|
|
|
for (i = 0;
|
|
(i < ResourceList->Count) && NT_SUCCESS(status);
|
|
i++) {
|
|
|
|
partialResourceList = &(fullResourceList->PartialResourceList);
|
|
partialDescriptors = fullResourceList->PartialResourceList.PartialDescriptors;
|
|
|
|
AtapiBuildIoAddress ((PUCHAR)partialDescriptors[0].u.Port.Start.QuadPart,
|
|
0,
|
|
&baseIoAddress1,
|
|
NULL,
|
|
&baseIoAddress1Length,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
|
|
for (j = 0;
|
|
(j < partialResourceList->Count) && NT_SUCCESS(status);
|
|
j++) {
|
|
|
|
resourceIsCommandPort = FALSE;
|
|
|
|
if (!Is98LegacyIde(&baseIoAddress1)) {
|
|
|
|
if (((partialDescriptors[j].Type == CmResourceTypePort) ||
|
|
(partialDescriptors[j].Type == CmResourceTypeMemory)) &&
|
|
(partialDescriptors[j].u.Port.Length == baseIoAddress1Length)) {
|
|
|
|
resourceIsCommandPort = TRUE;
|
|
|
|
}
|
|
} else {
|
|
|
|
if (((partialDescriptors[j].Type == CmResourceTypePort) ||
|
|
(partialDescriptors[j].Type == CmResourceTypeMemory)) &&
|
|
(partialDescriptors[j].u.Port.Start.QuadPart == IDE_NEC98_COMMAND_PORT_ADDRESS)){
|
|
|
|
resourceIsCommandPort = TRUE;
|
|
|
|
} else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
|
|
(partialDescriptors[j].Type == CmResourceTypeMemory)) &&
|
|
(partialDescriptors[j].u.Port.Start.QuadPart != IDE_NEC98_COMMAND_PORT_ADDRESS) &&
|
|
(partialDescriptors[j].u.Port.Start.QuadPart != (IDE_NEC98_COMMAND_PORT_ADDRESS + 0x10C))) {
|
|
|
|
//
|
|
// This is not the base port address for Legacy ide on NEC98;
|
|
//
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (resourceIsCommandPort) {
|
|
|
|
if (foundCommandBase) {
|
|
|
|
//
|
|
// got this before, just ignore it
|
|
//
|
|
// status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
if (!Is98LegacyIde(&baseIoAddress1)) {
|
|
|
|
if (partialDescriptors[j].u.Port.Start.QuadPart == IDE_STANDARD_PRIMARY_ADDRESS) {
|
|
|
|
AtdiskPrimaryClaimed = TRUE;
|
|
|
|
} else if (partialDescriptors[j].u.Port.Start.QuadPart == IDE_STANDARD_SECONDARY_ADDRESS) {
|
|
|
|
AtdiskSecondaryClaimed = TRUE;
|
|
}
|
|
|
|
} else {
|
|
|
|
AtdiskPrimaryClaimed = TRUE;
|
|
AtdiskSecondaryClaimed = TRUE;
|
|
}
|
|
|
|
if (partialDescriptors[j].Type == CmResourceTypePort) {
|
|
|
|
IdeResource->TranslatedCommandBaseAddress =
|
|
(PUCHAR)(ULONG_PTR)partialDescriptors[j].u.Port.Start.QuadPart;
|
|
|
|
IdeResource->CommandBaseAddressSpace = IO_SPACE;
|
|
|
|
} else if (partialDescriptors[j].Type == CmResourceTypeMemory) {
|
|
|
|
IdeResource->TranslatedCommandBaseAddress = MmMapIoSpace(
|
|
partialDescriptors[j].u.Port.Start,
|
|
baseIoAddress1Length,
|
|
FALSE);
|
|
|
|
IdeResource->CommandBaseAddressSpace = MEMORY_SPACE;
|
|
|
|
} else {
|
|
|
|
IdeResource->TranslatedCommandBaseAddress = FALSE;
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
if (IdeResource->TranslatedCommandBaseAddress) {
|
|
|
|
foundCommandBase = TRUE;
|
|
|
|
} else {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
} else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
|
|
(partialDescriptors[j].Type == CmResourceTypeMemory)) &&
|
|
((partialDescriptors[j].u.Port.Length == 1) ||
|
|
(partialDescriptors[j].u.Port.Length == 2) ||
|
|
(partialDescriptors[j].u.Port.Length == 4))) {
|
|
|
|
if (foundControlBase) {
|
|
|
|
//
|
|
// got this before, just ignore it
|
|
//
|
|
// status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
PHYSICAL_ADDRESS p;
|
|
//
|
|
// Probably the control block register
|
|
//
|
|
|
|
p = partialDescriptors[j].u.Port.Start;
|
|
|
|
if (partialDescriptors[j].u.Port.Length == 4) {
|
|
|
|
//
|
|
// this will happen only in native mode since
|
|
// the range length is 1 for legacy systems
|
|
//
|
|
p.QuadPart += 2;
|
|
}
|
|
|
|
if (partialDescriptors[j].Type == CmResourceTypePort) {
|
|
|
|
IdeResource->TranslatedControlBaseAddress =
|
|
(PUCHAR)(ULONG_PTR)p.QuadPart;
|
|
|
|
IdeResource->ControlBaseAddressSpace = IO_SPACE;
|
|
|
|
} else if (partialDescriptors[j].Type == CmResourceTypeMemory) {
|
|
|
|
IdeResource->TranslatedControlBaseAddress = MmMapIoSpace(
|
|
p,
|
|
1,
|
|
FALSE);
|
|
|
|
IdeResource->ControlBaseAddressSpace = MEMORY_SPACE;
|
|
|
|
} else {
|
|
|
|
IdeResource->TranslatedControlBaseAddress = FALSE;
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
if (IdeResource->TranslatedControlBaseAddress) {
|
|
|
|
foundControlBase = TRUE;
|
|
|
|
} else {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
} else if (partialDescriptors[j].Type == CmResourceTypeInterrupt) {
|
|
|
|
if (foundIrqLevel) {
|
|
|
|
//
|
|
// got this before, just ignore it
|
|
//
|
|
// status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Probably the device IRQ
|
|
//
|
|
|
|
//
|
|
// May want to disable device interrupt here
|
|
//
|
|
|
|
//
|
|
// Save interrupt level.
|
|
//
|
|
|
|
IdeResource->InterruptLevel = partialDescriptors[j].u.Interrupt.Level;
|
|
IdeResource->InterruptMode = partialDescriptors[j].Flags & CM_RESOURCE_INTERRUPT_LATCHED ?
|
|
Latched :
|
|
LevelSensitive;
|
|
|
|
*IrqPartialDescriptors = partialDescriptors + j;
|
|
|
|
foundIrqLevel = TRUE;
|
|
}
|
|
|
|
} else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
|
|
(partialDescriptors[j].Type == CmResourceTypeMemory)) &&
|
|
((partialDescriptors[j].u.Port.Length >= 16) &&
|
|
(partialDescriptors[j].u.Port.Length <= 32)) ) {
|
|
|
|
if (foundControlBase || foundCommandBase) {
|
|
|
|
//
|
|
// got this before, just ignore it
|
|
//
|
|
// status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
PHYSICAL_ADDRESS ctrlAddr;
|
|
|
|
//
|
|
// Probably a pcmcia device that has its command and control
|
|
// registers lumped into one I/O range
|
|
//
|
|
// We are guessing the control block register is the second
|
|
// from the last i/o space. Some standard!
|
|
//
|
|
|
|
ctrlAddr.QuadPart = partialDescriptors[j].u.Port.Start.QuadPart +
|
|
partialDescriptors[j].u.Port.Length - 2;
|
|
|
|
if (partialDescriptors[j].Type == CmResourceTypePort) {
|
|
|
|
IdeResource->TranslatedCommandBaseAddress =
|
|
(PUCHAR)(ULONG_PTR)partialDescriptors[j].u.Port.Start.QuadPart;
|
|
|
|
IdeResource->CommandBaseAddressSpace = IO_SPACE;
|
|
|
|
IdeResource->TranslatedControlBaseAddress =
|
|
(PUCHAR)(ULONG_PTR)ctrlAddr.QuadPart;
|
|
|
|
IdeResource->ControlBaseAddressSpace = IO_SPACE;
|
|
|
|
} else if (partialDescriptors[j].Type == CmResourceTypeMemory) {
|
|
|
|
IdeResource->TranslatedCommandBaseAddress = MmMapIoSpace(
|
|
partialDescriptors[j].u.Port.Start,
|
|
baseIoAddress1Length,
|
|
FALSE);
|
|
|
|
IdeResource->CommandBaseAddressSpace = MEMORY_SPACE;
|
|
|
|
IdeResource->TranslatedControlBaseAddress = MmMapIoSpace(
|
|
ctrlAddr,
|
|
1,
|
|
FALSE);
|
|
|
|
IdeResource->ControlBaseAddressSpace = MEMORY_SPACE;
|
|
|
|
} else {
|
|
|
|
IdeResource->TranslatedCommandBaseAddress = FALSE;
|
|
IdeResource->TranslatedControlBaseAddress = FALSE;
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
if (IdeResource->TranslatedCommandBaseAddress) {
|
|
|
|
foundCommandBase = TRUE;
|
|
|
|
} else {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (IdeResource->TranslatedControlBaseAddress) {
|
|
|
|
foundControlBase = TRUE;
|
|
|
|
} else {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + partialResourceList->Count);
|
|
}
|
|
|
|
if (foundCommandBase && foundControlBase && NT_SUCCESS(status)) {
|
|
|
|
IdeResource->AtdiskPrimaryClaimed = AtdiskPrimaryClaimed;
|
|
IdeResource->AtdiskSecondaryClaimed = AtdiskSecondaryClaimed;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
DebugPrint((0, "IdePort: pnp manager gave me bad ressources!\n"));
|
|
|
|
if (foundCommandBase &&
|
|
(IdeResource->CommandBaseAddressSpace == MEMORY_SPACE)) {
|
|
|
|
MmUnmapIoSpace (
|
|
IdeResource->TranslatedCommandBaseAddress,
|
|
baseIoAddress1Length
|
|
);
|
|
|
|
IdeResource->TranslatedCommandBaseAddress = 0;
|
|
}
|
|
|
|
if (foundControlBase &&
|
|
(IdeResource->ControlBaseAddressSpace == MEMORY_SPACE)) {
|
|
|
|
MmUnmapIoSpace (
|
|
IdeResource->TranslatedControlBaseAddress,
|
|
1
|
|
);
|
|
|
|
IdeResource->TranslatedControlBaseAddress = 0;
|
|
}
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
} // DigestResourceList
|
|
|
|
VOID
|
|
AtapiBuildIoAddress (
|
|
IN PUCHAR CmdBaseAddress,
|
|
IN PUCHAR CtrlBaseAddress,
|
|
OUT PIDE_REGISTERS_1 BaseIoAddress1,
|
|
OUT PIDE_REGISTERS_2 BaseIoAddress2,
|
|
OUT PULONG BaseIoAddress1Length,
|
|
OUT PULONG BaseIoAddress2Length,
|
|
OUT PULONG MaxIdeDevice,
|
|
OUT PULONG MaxIdeTargetId
|
|
)
|
|
{
|
|
PUCHAR baseIoAddress;
|
|
BOOLEAN LegacyIdeOfNec98;
|
|
|
|
LegacyIdeOfNec98 = FALSE;
|
|
|
|
if (IsNEC_98) {
|
|
if (CmdBaseAddress == (PUCHAR)IDE_NEC98_COMMAND_PORT_ADDRESS) {
|
|
LegacyIdeOfNec98 = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!LegacyIdeOfNec98) {
|
|
|
|
//
|
|
// Build command registers.
|
|
//
|
|
|
|
baseIoAddress = CmdBaseAddress;
|
|
|
|
if (BaseIoAddress1) {
|
|
BaseIoAddress1->RegistersBaseAddress = baseIoAddress;
|
|
|
|
BaseIoAddress1->Data = (PUSHORT)baseIoAddress;
|
|
BaseIoAddress1->Error = baseIoAddress + 1;
|
|
BaseIoAddress1->BlockCount = baseIoAddress + 2;
|
|
BaseIoAddress1->BlockNumber = baseIoAddress + 3;
|
|
BaseIoAddress1->CylinderLow = baseIoAddress + 4;
|
|
BaseIoAddress1->CylinderHigh = baseIoAddress + 5;
|
|
BaseIoAddress1->DriveSelect = baseIoAddress + 6;
|
|
BaseIoAddress1->Command = baseIoAddress + 7;
|
|
|
|
}
|
|
|
|
//
|
|
// Build control registers.
|
|
//
|
|
|
|
baseIoAddress = CtrlBaseAddress;
|
|
|
|
if (BaseIoAddress2) {
|
|
|
|
BaseIoAddress2->RegistersBaseAddress = baseIoAddress;
|
|
|
|
BaseIoAddress2->DeviceControl = baseIoAddress;
|
|
BaseIoAddress2->DriveAddress = baseIoAddress + 1;
|
|
}
|
|
|
|
if (BaseIoAddress1Length) {
|
|
*BaseIoAddress1Length = 8;
|
|
}
|
|
|
|
if (BaseIoAddress2Length) {
|
|
*BaseIoAddress2Length = 1;
|
|
}
|
|
|
|
if (MaxIdeDevice) {
|
|
*MaxIdeDevice = MAX_IDE_DEVICE;
|
|
}
|
|
|
|
if (MaxIdeTargetId) {
|
|
*MaxIdeTargetId = MAX_IDE_DEVICE;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Build command registers.
|
|
//
|
|
|
|
baseIoAddress = CmdBaseAddress;
|
|
|
|
if (BaseIoAddress1) {
|
|
BaseIoAddress1->RegistersBaseAddress = baseIoAddress;
|
|
|
|
BaseIoAddress1->Data = (PUSHORT)baseIoAddress;
|
|
BaseIoAddress1->Error = baseIoAddress + 2;
|
|
BaseIoAddress1->BlockCount = baseIoAddress + 4;
|
|
BaseIoAddress1->BlockNumber = baseIoAddress + 6;
|
|
BaseIoAddress1->CylinderLow = baseIoAddress + 8;
|
|
BaseIoAddress1->CylinderHigh = baseIoAddress + 10;
|
|
BaseIoAddress1->DriveSelect = baseIoAddress + 12;
|
|
BaseIoAddress1->Command = baseIoAddress + 14;
|
|
}
|
|
|
|
//
|
|
// Build control registers.
|
|
//
|
|
|
|
baseIoAddress = CtrlBaseAddress;
|
|
|
|
if (BaseIoAddress2) {
|
|
|
|
BaseIoAddress2->RegistersBaseAddress = baseIoAddress;
|
|
|
|
BaseIoAddress2->DeviceControl = baseIoAddress;
|
|
BaseIoAddress2->DriveAddress = baseIoAddress + 2;
|
|
}
|
|
|
|
if (BaseIoAddress1Length) {
|
|
*BaseIoAddress1Length = 1;
|
|
}
|
|
|
|
if (BaseIoAddress2Length) {
|
|
*BaseIoAddress2Length = 1;
|
|
}
|
|
|
|
if (MaxIdeDevice) {
|
|
*MaxIdeDevice = MAX_IDE_DEVICE * MAX_IDE_LINE;
|
|
}
|
|
|
|
if (MaxIdeTargetId) {
|
|
*MaxIdeTargetId = MAX_IDE_DEVICE * MAX_IDE_LINE;
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
} // AtapiBuildIoAddress
|
|
|
|
NTSTATUS
|
|
IdePortpWaitOnBusyEx (
|
|
IN PIDE_REGISTERS_1 CmdRegBase,
|
|
IN OUT PUCHAR Status,
|
|
IN UCHAR BadStatus
|
|
#if DBG
|
|
,
|
|
IN PCSTR FileName,
|
|
IN ULONG LineNumber
|
|
#endif
|
|
)
|
|
{
|
|
UCHAR status;
|
|
ULONG sec;
|
|
ULONG i;
|
|
|
|
for (sec=0; sec<2; sec++) {
|
|
|
|
/**/
|
|
/* one second loop */
|
|
/**/
|
|
|
|
for (i=0; i<200000; i++) {
|
|
|
|
GetStatus(CmdRegBase, status);
|
|
|
|
if (status == BadStatus) {
|
|
|
|
break;
|
|
|
|
} else if (status & IDE_STATUS_BUSY) {
|
|
|
|
KeStallExecutionProcessor(5);
|
|
continue;
|
|
|
|
} else {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (status == BadStatus) {
|
|
|
|
break;
|
|
|
|
} else if (status & IDE_STATUS_BUSY) {
|
|
|
|
DebugPrint ((1, "ATAPI: after 1 sec wait, device is still busy with 0x%x status = 0x%x\n", CmdRegBase->RegistersBaseAddress, (ULONG) (status)));
|
|
|
|
} else {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
*Status = status;
|
|
|
|
if ((status & IDE_STATUS_BUSY) && (status != BadStatus)) {
|
|
|
|
DebugPrint ((0, "WaitOnBusy failed in %s line %u. 0x%x status = 0x%x\n", FileName, LineNumber, CmdRegBase->RegistersBaseAddress, (ULONG) (status)));
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
} // IdePortpWaitOnBusyEx
|
|
|
|
static PVOID IdeDirectory = NULL;
|
|
VOID
|
|
IdeCreateIdeDirectory(
|
|
VOID
|
|
)
|
|
{
|
|
UNICODE_STRING unicodeDirectoryName;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
|
|
HANDLE directory;
|
|
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString(
|
|
&unicodeDirectoryName,
|
|
DEVICE_OJBECT_BASE_NAME);
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&unicodeDirectoryName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
|
|
NULL,
|
|
NULL);
|
|
|
|
status = ZwCreateDirectoryObject(&directory,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&objectAttributes);
|
|
|
|
if(NT_SUCCESS(status)) {
|
|
|
|
ObReferenceObjectByHandle(directory,
|
|
FILE_READ_ATTRIBUTES,
|
|
NULL,
|
|
KernelMode,
|
|
&IdeDirectory,
|
|
NULL);
|
|
ZwClose(directory);
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
IdeGetDeviceCapabilities(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PDEVICE_CAPABILITIES DeviceCapabilities
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends the get capabilities irp to the given stack
|
|
|
|
Arguments:
|
|
|
|
DeviceObject A device object in the stack whose capabilities we want
|
|
DeviceCapabilites Where to store the answer
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
IO_STATUS_BLOCK ioStatus;
|
|
KEVENT pnpEvent;
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT targetObject;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PIRP pnpIrp;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Initialize the capabilities that we will send down
|
|
//
|
|
RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
|
|
DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
|
|
DeviceCapabilities->Version = 1;
|
|
DeviceCapabilities->Address = -1;
|
|
DeviceCapabilities->UINumber = -1;
|
|
//
|
|
// Initialize the event
|
|
//
|
|
KeInitializeEvent( &pnpEvent, SynchronizationEvent, FALSE );
|
|
|
|
//
|
|
// Get the irp that we will send the request to
|
|
//
|
|
targetObject = IoGetAttachedDeviceReference( DeviceObject );
|
|
|
|
//
|
|
// Build an Irp
|
|
//
|
|
pnpIrp = IoBuildSynchronousFsdRequest(
|
|
IRP_MJ_PNP,
|
|
targetObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&pnpEvent,
|
|
&ioStatus
|
|
);
|
|
if (pnpIrp == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto IdeGetDeviceCapabilitiesExit;
|
|
|
|
}
|
|
|
|
//
|
|
// Pnp Irps all begin life as STATUS_NOT_SUPPORTED;
|
|
//
|
|
pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
pnpIrp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Get the top of stack
|
|
//
|
|
irpStack = IoGetNextIrpStackLocation( pnpIrp );
|
|
if (irpStack == NULL) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto IdeGetDeviceCapabilitiesExit;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the top of stack
|
|
//
|
|
RtlZeroMemory( irpStack, sizeof(IO_STACK_LOCATION ) );
|
|
irpStack->MajorFunction = IRP_MJ_PNP;
|
|
irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
|
|
irpStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
|
|
|
|
//
|
|
// Make sure that there are no completion routines set
|
|
//
|
|
IoSetCompletionRoutine(
|
|
pnpIrp,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
FALSE,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Call the driver
|
|
//
|
|
status = IoCallDriver( targetObject, pnpIrp );
|
|
if (status == STATUS_PENDING) {
|
|
|
|
//
|
|
// Block until the irp comes back
|
|
//
|
|
KeWaitForSingleObject(
|
|
&pnpEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
status = ioStatus.Status;
|
|
|
|
}
|
|
|
|
IdeGetDeviceCapabilitiesExit:
|
|
//
|
|
// Done with reference
|
|
//
|
|
ObDereferenceObject( targetObject );
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return status;
|
|
}
|