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.
1067 lines
35 KiB
1067 lines
35 KiB
/*++
|
|
|
|
Copyright (C) 1997-99 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
detect.c
|
|
|
|
Abstract:
|
|
|
|
This contain legacy detection routines
|
|
|
|
Author:
|
|
|
|
Joe Dai (joedai)
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ideport.h"
|
|
|
|
#if !defined(NO_LEGACY_DRIVERS)
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, IdePortDetectLegacyController)
|
|
#pragma alloc_text(INIT, IdePortCreateDetectionList)
|
|
#pragma alloc_text(INIT, IdePortTranslateAddress)
|
|
#pragma alloc_text(INIT, IdePortFreeTranslatedAddress)
|
|
#pragma alloc_text(INIT, IdePortDetectAlias)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
NTSTATUS
|
|
IdePortDetectLegacyController (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Detect legacy IDE controllers and report them to PnP
|
|
|
|
Arguments:
|
|
|
|
DriverObject - this driver's driver object
|
|
|
|
RegistryPath - this driver's registry path
|
|
|
|
Return Value:
|
|
|
|
NT Status
|
|
|
|
--*/
|
|
{
|
|
ULONG cmResourceListSize;
|
|
PCM_RESOURCE_LIST cmResourceList = NULL;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR cmFullResourceDescriptor;
|
|
PCM_PARTIAL_RESOURCE_LIST cmPartialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartialDescriptors;
|
|
|
|
BOOLEAN conflictDetected;
|
|
BOOLEAN resourceIsCmdPort;
|
|
|
|
PDEVICE_OBJECT detectedPhysicalDeviceObject;
|
|
PFDO_EXTENSION fdoExtension = NULL;
|
|
|
|
UNICODE_STRING deviceClassName;
|
|
|
|
NTSTATUS status;
|
|
PDETECTION_PORT detectionPort;
|
|
ULONG numPort;
|
|
|
|
ULONG portNumber;
|
|
ULONG deviceNumber;
|
|
ULONG descriptorNumber;
|
|
ULONG cmdAddressSpace;
|
|
ULONG ctrlAddressSpace;
|
|
PUCHAR cmdRegBase;
|
|
PUCHAR ctrlRegBase;
|
|
IDE_REGISTERS_1 baseIoAddress1;
|
|
IDE_REGISTERS_2 baseIoAddress2;
|
|
PHYSICAL_ADDRESS cmdRegMemoryBase;
|
|
PHYSICAL_ADDRESS ctrlRegMemoryBase;
|
|
UCHAR statusByte;
|
|
ULONG baseIoAddress1Length;
|
|
ULONG baseIoAddress2Length;
|
|
ULONG maxIdeDevice;
|
|
|
|
UCHAR altMasterStatus;
|
|
UCHAR altSlaveStatus;
|
|
|
|
|
|
#if !defined (ALWAYS_DO_LEGACY_DETECTION)
|
|
if (!IdePortOkToDetectLegacy(DriverObject)) {
|
|
|
|
//
|
|
// legacy detection is not enabled
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// make up a list of popular legacy I/O ports
|
|
//
|
|
status = IdePortCreateDetectionList (
|
|
DriverObject,
|
|
&detectionPort,
|
|
&numPort
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// Resource Requirement List
|
|
//
|
|
cmResourceListSize = sizeof (CM_RESOURCE_LIST) +
|
|
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (((!IsNEC_98) ? 3 : 12) - 1);
|
|
cmResourceList = ExAllocatePool (PagedPool, cmResourceListSize);
|
|
if (cmResourceList == NULL){
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
goto GetOut;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(cmResourceList, cmResourceListSize);
|
|
RtlInitUnicodeString(&deviceClassName, L"ScsiAdapter");
|
|
|
|
for (portNumber=0; portNumber<numPort; portNumber++) {
|
|
|
|
//
|
|
// Build io address structure.
|
|
//
|
|
|
|
AtapiBuildIoAddress ( (PUCHAR)detectionPort[portNumber].CommandRegisterBase,
|
|
(PUCHAR)detectionPort[portNumber].ControlRegisterBase,
|
|
&baseIoAddress1,
|
|
&baseIoAddress2,
|
|
&baseIoAddress1Length,
|
|
&baseIoAddress2Length,
|
|
&maxIdeDevice,
|
|
NULL);
|
|
|
|
//
|
|
// Build resource requirement list
|
|
//
|
|
cmResourceList->Count = 1;
|
|
|
|
cmFullResourceDescriptor = cmResourceList->List;
|
|
cmFullResourceDescriptor->InterfaceType = Isa;
|
|
cmFullResourceDescriptor->BusNumber = 0;
|
|
|
|
cmPartialResourceList = &cmFullResourceDescriptor->PartialResourceList;
|
|
cmPartialResourceList->Version = 1;
|
|
cmPartialResourceList->Revision = 1;
|
|
cmPartialResourceList->Count = 3;
|
|
|
|
cmPartialDescriptors = cmPartialResourceList->PartialDescriptors;
|
|
|
|
cmPartialDescriptors[0].Type = CmResourceTypePort;
|
|
cmPartialDescriptors[0].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
cmPartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO |
|
|
(!Is98LegacyIde(&baseIoAddress1)? CM_RESOURCE_PORT_10_BIT_DECODE :
|
|
CM_RESOURCE_PORT_16_BIT_DECODE);
|
|
cmPartialDescriptors[0].u.Port.Length = baseIoAddress1Length;
|
|
cmPartialDescriptors[0].u.Port.Start.QuadPart = detectionPort[portNumber].CommandRegisterBase;
|
|
|
|
cmPartialDescriptors[1].Type = CmResourceTypePort;
|
|
cmPartialDescriptors[1].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
cmPartialDescriptors[1].Flags = CM_RESOURCE_PORT_IO |
|
|
(!Is98LegacyIde(&baseIoAddress1)? CM_RESOURCE_PORT_10_BIT_DECODE :
|
|
CM_RESOURCE_PORT_16_BIT_DECODE);
|
|
cmPartialDescriptors[1].u.Port.Length = 1;
|
|
cmPartialDescriptors[1].u.Port.Start.QuadPart = detectionPort[portNumber].ControlRegisterBase;
|
|
|
|
cmPartialDescriptors[2].Type = CmResourceTypeInterrupt;
|
|
cmPartialDescriptors[2].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
cmPartialDescriptors[2].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
|
|
cmPartialDescriptors[2].u.Interrupt.Level = detectionPort[portNumber].IrqLevel;
|
|
cmPartialDescriptors[2].u.Interrupt.Vector = detectionPort[portNumber].IrqLevel;
|
|
cmPartialDescriptors[2].u.Interrupt.Affinity = -1;
|
|
|
|
if (Is98LegacyIde(&baseIoAddress1)) {
|
|
|
|
ULONG resourceCount;
|
|
ULONG commandRegisters;
|
|
|
|
commandRegisters = detectionPort[portNumber].CommandRegisterBase + 2;
|
|
resourceCount = 3;
|
|
|
|
while (commandRegisters < (IDE_NEC98_COMMAND_PORT_ADDRESS + 0x10)) {
|
|
cmPartialDescriptors[resourceCount].Type = CmResourceTypePort;
|
|
cmPartialDescriptors[resourceCount].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
cmPartialDescriptors[resourceCount].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
cmPartialDescriptors[resourceCount].u.Port.Length = 1;
|
|
cmPartialDescriptors[resourceCount].u.Port.Start.QuadPart = commandRegisters;
|
|
|
|
resourceCount++;
|
|
commandRegisters += 2;
|
|
}
|
|
|
|
cmPartialDescriptors[resourceCount].Type = CmResourceTypePort;
|
|
cmPartialDescriptors[resourceCount].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
cmPartialDescriptors[resourceCount].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
cmPartialDescriptors[resourceCount].u.Port.Length = 2;
|
|
cmPartialDescriptors[resourceCount].u.Port.Start.QuadPart = (ULONG_PTR)SELECT_IDE_PORT;
|
|
|
|
resourceCount++;
|
|
|
|
cmPartialDescriptors[resourceCount].Type = CmResourceTypePort;
|
|
cmPartialDescriptors[resourceCount].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
cmPartialDescriptors[resourceCount].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
cmPartialDescriptors[resourceCount].u.Port.Length = 1;
|
|
cmPartialDescriptors[resourceCount].u.Port.Start.QuadPart = (ULONG_PTR)SELECT_IDE_PORT + 3;
|
|
|
|
resourceCount++;
|
|
|
|
cmPartialResourceList->Count = resourceCount;
|
|
}
|
|
|
|
//
|
|
// check to see if the resource is available
|
|
// if not, assume no legacy IDE controller
|
|
// is at the this location
|
|
//
|
|
for (deviceNumber=0; deviceNumber<2; deviceNumber++) {
|
|
|
|
status = IoReportResourceForDetection (
|
|
DriverObject,
|
|
cmResourceList,
|
|
cmResourceListSize,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&conflictDetected
|
|
);
|
|
|
|
if (NT_SUCCESS(status) && !conflictDetected) {
|
|
|
|
//
|
|
// got our resources
|
|
//
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
IoReportResourceForDetection (
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&conflictDetected
|
|
);
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// try 16 bit decode
|
|
//
|
|
cmPartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
cmPartialDescriptors[1].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
|
|
if (Is98LegacyIde(&baseIoAddress1)) {
|
|
ULONG k;
|
|
|
|
for (k=3; k<12; k++) {
|
|
cmPartialDescriptors[k].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// translate the i/o port via Hal
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
if (Is98LegacyIde(&baseIoAddress1)) {
|
|
for (descriptorNumber=3; descriptorNumber<12; descriptorNumber++) {
|
|
cmdRegBase = NULL;
|
|
cmdAddressSpace = IO_SPACE;
|
|
|
|
status = IdePortTranslateAddress (
|
|
cmFullResourceDescriptor->InterfaceType,
|
|
cmFullResourceDescriptor->BusNumber,
|
|
cmPartialDescriptors[descriptorNumber].u.Port.Start,
|
|
cmPartialDescriptors[descriptorNumber].u.Port.Length,
|
|
&cmdAddressSpace,
|
|
&cmdRegBase,
|
|
&cmdRegMemoryBase
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
cmdRegBase = NULL;
|
|
ctrlRegBase = NULL;
|
|
cmdAddressSpace = IO_SPACE;
|
|
|
|
status = IdePortTranslateAddress (
|
|
cmFullResourceDescriptor->InterfaceType,
|
|
cmFullResourceDescriptor->BusNumber,
|
|
cmPartialDescriptors[0].u.Port.Start,
|
|
cmPartialDescriptors[0].u.Port.Length,
|
|
&cmdAddressSpace,
|
|
&cmdRegBase,
|
|
&cmdRegMemoryBase
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
ctrlRegBase = NULL;
|
|
ctrlAddressSpace = IO_SPACE;
|
|
status = IdePortTranslateAddress (
|
|
cmFullResourceDescriptor->InterfaceType,
|
|
cmFullResourceDescriptor->BusNumber,
|
|
cmPartialDescriptors[1].u.Port.Start,
|
|
cmPartialDescriptors[1].u.Port.Length,
|
|
&ctrlAddressSpace,
|
|
&ctrlRegBase,
|
|
&ctrlRegMemoryBase
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// 2nd build io address structure.
|
|
//
|
|
|
|
AtapiBuildIoAddress ( cmdRegBase,
|
|
ctrlRegBase,
|
|
&baseIoAddress1,
|
|
&baseIoAddress2,
|
|
&baseIoAddress1Length,
|
|
&baseIoAddress2Length,
|
|
&maxIdeDevice,
|
|
NULL);
|
|
|
|
//
|
|
// The IBM Aptiva ide channel with the external cdrom doesn't power up with any device selected
|
|
// we must select a device; otherwise, we get a 0xff from all IO ports
|
|
//
|
|
SelectIdeDevice(&baseIoAddress1, 0, 0);
|
|
altMasterStatus = IdePortInPortByte(baseIoAddress2.DeviceControl);
|
|
|
|
SelectIdeDevice(&baseIoAddress1, 1, 0);
|
|
altSlaveStatus = IdePortInPortByte(baseIoAddress2.DeviceControl);
|
|
|
|
if ((!Is98LegacyIde(&baseIoAddress1)) && (altMasterStatus == 0xff) && (altSlaveStatus == 0xff)) {
|
|
|
|
//
|
|
// the alternate status byte is 0xff,
|
|
// guessing we have a SCSI adapter (DPT) that emulate IDE controller
|
|
// say the channel is empty, let the real SCSI driver picks up
|
|
// the controller
|
|
//
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
//
|
|
// Note: The IDE port on SB16/AWE32 does not have the alternate status
|
|
// register. Because of this alternate status test, we will fail to
|
|
// detect this IDE port. However, this IDE port should be enumerated
|
|
// by ISA-PnP bus driver.
|
|
//
|
|
|
|
} else if (IdePortChannelEmpty (&baseIoAddress1, &baseIoAddress2, maxIdeDevice)) {
|
|
|
|
//
|
|
// channel looks empty
|
|
//
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
} else {
|
|
|
|
BOOLEAN deviceFound;
|
|
IDENTIFY_DATA IdentifyData;
|
|
ULONG i;
|
|
|
|
for (i=0; i<maxIdeDevice; i++) {
|
|
|
|
if (Is98LegacyIde(&baseIoAddress1)) {
|
|
UCHAR driveHeadReg;
|
|
|
|
//
|
|
// Check master device only.
|
|
//
|
|
|
|
if ( i & 0x1 ) {
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check device is present.
|
|
//
|
|
|
|
SelectIdeDevice(&baseIoAddress1, i, 0);
|
|
driveHeadReg = IdePortInPortByte(baseIoAddress1.DriveSelect);
|
|
|
|
if (driveHeadReg != ((i & 0x1) << 4 | 0xA0)) {
|
|
//
|
|
// Bad controller.
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Is there a ATA device?
|
|
//
|
|
deviceFound = IssueIdentify(
|
|
&baseIoAddress1,
|
|
&baseIoAddress2,
|
|
i,
|
|
IDE_COMMAND_IDENTIFY,
|
|
TRUE,
|
|
&IdentifyData
|
|
);
|
|
if (deviceFound) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Is there a ATAPI device?
|
|
//
|
|
deviceFound = IssueIdentify(
|
|
&baseIoAddress1,
|
|
&baseIoAddress2,
|
|
i,
|
|
IDE_COMMAND_ATAPI_IDENTIFY,
|
|
TRUE,
|
|
&IdentifyData
|
|
);
|
|
if (deviceFound) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!deviceFound) {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
//
|
|
// if we didn't found anything,
|
|
// unmap the reosurce
|
|
//
|
|
|
|
if (cmdRegBase) {
|
|
|
|
IdePortFreeTranslatedAddress (
|
|
cmdRegBase,
|
|
cmPartialDescriptors[0].u.Port.Length,
|
|
cmdAddressSpace
|
|
);
|
|
|
|
if (Is98LegacyIde(&baseIoAddress1)) {
|
|
for (descriptorNumber=3; descriptorNumber<12; descriptorNumber++) {
|
|
IdePortFreeTranslatedAddress (
|
|
cmdRegBase,
|
|
cmPartialDescriptors[descriptorNumber].u.Port.Length,
|
|
cmdAddressSpace
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ctrlRegBase) {
|
|
|
|
IdePortFreeTranslatedAddress (
|
|
ctrlRegBase,
|
|
cmPartialDescriptors[1].u.Port.Length,
|
|
ctrlAddressSpace
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// check for alias ports
|
|
//
|
|
if (cmPartialDescriptors[0].Flags & CM_RESOURCE_PORT_10_BIT_DECODE) {
|
|
|
|
if (!IdePortDetectAlias (&baseIoAddress1)) {
|
|
|
|
cmPartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
cmPartialDescriptors[1].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
|
|
if (Is98LegacyIde(&baseIoAddress1)) {
|
|
for (descriptorNumber=3; descriptorNumber<12; descriptorNumber++) {
|
|
cmPartialDescriptors[descriptorNumber].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// release the resources we have grab, IoReportDetectedDevice()
|
|
// will grab them for us again when we call and it will grab them
|
|
// on behalf of the detected PDO.
|
|
//
|
|
IoReportResourceForDetection (
|
|
DriverObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&conflictDetected
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
detectedPhysicalDeviceObject = NULL;
|
|
|
|
status = IoReportDetectedDevice(DriverObject,
|
|
InterfaceTypeUndefined,
|
|
-1,
|
|
-1,
|
|
cmResourceList,
|
|
NULL,
|
|
FALSE,
|
|
&detectedPhysicalDeviceObject);
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
|
|
//
|
|
// create a FDO and attach it to the detected PDO
|
|
//
|
|
status = ChannelAddChannel (
|
|
DriverObject,
|
|
detectedPhysicalDeviceObject,
|
|
&fdoExtension
|
|
);
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
|
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
|
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
|
|
ULONG i, j;
|
|
|
|
//
|
|
// translate resources
|
|
//
|
|
fullResourceList = cmResourceList->List;
|
|
for (i=0; i<cmResourceList->Count; i++) {
|
|
|
|
partialResourceList = &(fullResourceList->PartialResourceList);
|
|
partialDescriptors = fullResourceList->PartialResourceList.PartialDescriptors;
|
|
|
|
for (j=0; j<partialResourceList->Count; j++) {
|
|
|
|
resourceIsCmdPort = FALSE;
|
|
|
|
if (!Is98LegacyIde(&baseIoAddress1)) {
|
|
|
|
if ((partialDescriptors[j].Type == CmResourceTypePort) &&
|
|
(partialDescriptors[j].u.Port.Length == baseIoAddress1Length)) {
|
|
|
|
resourceIsCmdPort = TRUE;
|
|
}
|
|
} else {
|
|
|
|
if ((partialDescriptors[j].Type == CmResourceTypePort) &&
|
|
(partialDescriptors[j].u.Port.Start.QuadPart == IDE_NEC98_COMMAND_PORT_ADDRESS)) {
|
|
|
|
resourceIsCmdPort = TRUE;
|
|
|
|
} else if ((partialDescriptors[j].Type == CmResourceTypePort) &&
|
|
(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 (resourceIsCmdPort) {
|
|
|
|
if (cmdAddressSpace == MEMORY_SPACE) {
|
|
|
|
partialDescriptors[j].Type = CmResourceTypeMemory;
|
|
partialDescriptors[j].u.Memory.Start = cmdRegMemoryBase;
|
|
partialDescriptors[j].u.Memory.Length = partialDescriptors[j].u.Port.Length;
|
|
|
|
} else {
|
|
|
|
partialDescriptors[j].u.Port.Start.QuadPart = (ULONG_PTR) cmdRegBase;
|
|
}
|
|
|
|
} else if ((partialDescriptors[j].Type == CmResourceTypePort) &&
|
|
(partialDescriptors[j].u.Port.Length == 1)) {
|
|
|
|
if (ctrlAddressSpace == MEMORY_SPACE) {
|
|
|
|
partialDescriptors[j].Type = CmResourceTypeMemory;
|
|
partialDescriptors[j].u.Memory.Start = ctrlRegMemoryBase;
|
|
partialDescriptors[j].u.Memory.Length = partialDescriptors[j].u.Port.Length;
|
|
|
|
} else {
|
|
|
|
partialDescriptors[j].u.Port.Start.QuadPart = (ULONG_PTR) ctrlRegBase;
|
|
}
|
|
|
|
} else if (partialDescriptors[j].Type == CmResourceTypeInterrupt) {
|
|
|
|
partialDescriptors[j].u.Interrupt.Vector = HalGetInterruptVector(fullResourceList->InterfaceType,
|
|
fullResourceList->BusNumber,
|
|
partialDescriptors[j].u.Interrupt.Level,
|
|
partialDescriptors[j].u.Interrupt.Vector,
|
|
(PKIRQL) &partialDescriptors[j].u.Interrupt.Level,
|
|
&partialDescriptors[j].u.Interrupt.Affinity);
|
|
}
|
|
}
|
|
fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + j);
|
|
}
|
|
|
|
//
|
|
// start the FDO
|
|
//
|
|
status = ChannelStartChannel (fdoExtension,
|
|
cmResourceList); // callee is keeping this if no error
|
|
}
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
//
|
|
// go through the remove sequence
|
|
//
|
|
if (fdoExtension) {
|
|
|
|
ChannelRemoveChannel (fdoExtension);
|
|
|
|
IoDetachDevice (fdoExtension->AttacheeDeviceObject);
|
|
|
|
IoDeleteDevice (fdoExtension->DeviceObject);
|
|
}
|
|
|
|
DebugPrint ((0, "IdePort: Unable to start detected device\n"));
|
|
ASSERT (FALSE);
|
|
|
|
} else {
|
|
|
|
IoInvalidateDeviceRelations (
|
|
fdoExtension->AttacheePdo,
|
|
BusRelations
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GetOut:
|
|
if (cmResourceList) {
|
|
ExFreePool (cmResourceList);
|
|
}
|
|
|
|
if (detectionPort) {
|
|
ExFreePool (detectionPort);
|
|
}
|
|
|
|
return status;
|
|
|
|
} //IdePortDetectLegacyController
|
|
|
|
|
|
|
|
NTSTATUS
|
|
IdePortCreateDetectionList (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
OUT PDETECTION_PORT *DetectionPort,
|
|
OUT PULONG NumPort
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
create a list of popular legacy ports
|
|
|
|
Arguments:
|
|
|
|
DriverObject - this driver's driver object
|
|
|
|
DetectionPort - pointer to port list
|
|
|
|
NumPort - number of ports in the list
|
|
|
|
Return Value:
|
|
|
|
NT Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
CCHAR deviceBuffer[50];
|
|
ANSI_STRING ansiString;
|
|
UNICODE_STRING subKeyPath;
|
|
HANDLE subServiceKey;
|
|
|
|
PDETECTION_PORT detectionPort;
|
|
ULONG numDevices;
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
CUSTOM_DEVICE_PARAMETER customDeviceParameter;
|
|
|
|
PCONFIGURATION_INFORMATION configurationInformation = IoGetConfigurationInformation();
|
|
|
|
numDevices = 0;
|
|
status = STATUS_SUCCESS;
|
|
|
|
#ifdef DRIVER_PARAMETER_REGISTRY_SUPPORT
|
|
|
|
//
|
|
// look for non-standard legacy port setting in the registry
|
|
// 9
|
|
do {
|
|
sprintf (deviceBuffer, "Parameters\\Device%d", numDevices);
|
|
RtlInitAnsiString(&ansiString, deviceBuffer);
|
|
status = RtlAnsiStringToUnicodeString(&subKeyPath, &ansiString, TRUE);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
subServiceKey = IdePortOpenServiceSubKey (
|
|
DriverObject,
|
|
&subKeyPath
|
|
);
|
|
|
|
RtlFreeUnicodeString (&subKeyPath);
|
|
|
|
if (subServiceKey) {
|
|
|
|
numDevices++;
|
|
IdePortCloseServiceSubKey (
|
|
subServiceKey
|
|
);
|
|
|
|
} else {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
} while (NT_SUCCESS(status));
|
|
|
|
#endif // DRIVER_PARAMETER_REGISTRY_SUPPORT
|
|
|
|
//
|
|
// always have at least 4 to return
|
|
//
|
|
detectionPort = ExAllocatePool (
|
|
PagedPool,
|
|
(numDevices + 4) * sizeof (DETECTION_PORT)
|
|
);
|
|
|
|
if (detectionPort) {
|
|
|
|
for (i = j = 0; i < numDevices; i++) {
|
|
|
|
#ifdef DRIVER_PARAMETER_REGISTRY_SUPPORT
|
|
|
|
//
|
|
// look for non-standard legacy port setting in the registry
|
|
//
|
|
|
|
sprintf (deviceBuffer, "Parameters\\Device%d", i);
|
|
RtlInitAnsiString(&ansiString, deviceBuffer);
|
|
status = RtlAnsiStringToUnicodeString(&subKeyPath, &ansiString, TRUE);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
subServiceKey = IdePortOpenServiceSubKey (
|
|
DriverObject,
|
|
&subKeyPath
|
|
);
|
|
|
|
RtlFreeUnicodeString (&subKeyPath);
|
|
|
|
if (subServiceKey) {
|
|
|
|
RtlZeroMemory (
|
|
&customDeviceParameter,
|
|
sizeof (CUSTOM_DEVICE_PARAMETER)
|
|
);
|
|
|
|
IdeParseDeviceParameters (
|
|
subServiceKey,
|
|
&customDeviceParameter
|
|
);
|
|
|
|
if (customDeviceParameter.CommandRegisterBase) {
|
|
|
|
detectionPort[j].CommandRegisterBase =
|
|
customDeviceParameter.CommandRegisterBase;
|
|
|
|
detectionPort[j].ControlRegisterBase =
|
|
customDeviceParameter.CommandRegisterBase + 0x206;
|
|
|
|
detectionPort[j].IrqLevel =
|
|
customDeviceParameter.IrqLevel;
|
|
|
|
j++;
|
|
}
|
|
|
|
IdePortCloseServiceSubKey (
|
|
subServiceKey
|
|
);
|
|
}
|
|
}
|
|
#endif // DRIVER_PARAMETER_REGISTRY_SUPPORT
|
|
}
|
|
|
|
//
|
|
// populate the list with popular i/o ports
|
|
//
|
|
|
|
if ( !IsNEC_98 ) {
|
|
if (configurationInformation->AtDiskPrimaryAddressClaimed == FALSE) {
|
|
|
|
detectionPort[j].CommandRegisterBase = 0x1f0;
|
|
detectionPort[j].ControlRegisterBase = 0x1f0 + 0x206;
|
|
detectionPort[j].IrqLevel = 14;
|
|
j++;
|
|
}
|
|
|
|
if (configurationInformation->AtDiskSecondaryAddressClaimed == FALSE) {
|
|
|
|
detectionPort[j].CommandRegisterBase = 0x170;
|
|
detectionPort[j].ControlRegisterBase = 0x170 + 0x206;
|
|
detectionPort[j].IrqLevel = 15;
|
|
j++;
|
|
}
|
|
|
|
detectionPort[j].CommandRegisterBase = 0x1e8;
|
|
detectionPort[j].ControlRegisterBase = 0x1e8 + 0x206;
|
|
detectionPort[j].IrqLevel = 11;
|
|
// DEC Hi-Note hack
|
|
// detectionPort[j].ControlRegisterBase = 0x1e8 + 0x1f - 0x2;
|
|
// detectionPort[j].IrqLevel = 7;
|
|
// DEC Hi-Note hack
|
|
j++;
|
|
|
|
detectionPort[j].CommandRegisterBase = 0x168;
|
|
detectionPort[j].ControlRegisterBase = 0x168 + 0x206;
|
|
detectionPort[j].IrqLevel = 10;
|
|
j++;
|
|
|
|
} else { // IsNEC_98
|
|
|
|
if ((configurationInformation->AtDiskPrimaryAddressClaimed == FALSE) &&
|
|
(configurationInformation->AtDiskSecondaryAddressClaimed == FALSE)) {
|
|
|
|
detectionPort[j].CommandRegisterBase = 0x640;
|
|
detectionPort[j].ControlRegisterBase = 0x640 + 0x10c; //0x74c
|
|
detectionPort[j].IrqLevel = 9;
|
|
j++;
|
|
}
|
|
|
|
}
|
|
|
|
*NumPort = j;
|
|
*DetectionPort = detectionPort;
|
|
return STATUS_SUCCESS;
|
|
} else {
|
|
|
|
*NumPort = 0;
|
|
*DetectionPort = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
} // IdePortCreateDetectionList
|
|
|
|
|
|
NTSTATUS
|
|
IdePortTranslateAddress (
|
|
IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN PHYSICAL_ADDRESS StartAddress,
|
|
IN LONG Length,
|
|
IN OUT PULONG AddressSpace,
|
|
OUT PVOID *TranslatedAddress,
|
|
OUT PPHYSICAL_ADDRESS TranslatedMemoryAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
translate i/o address
|
|
|
|
Arguments:
|
|
|
|
InterfaceType - bus interface
|
|
|
|
BusNumber - bus number
|
|
|
|
StartAddress - address to translate
|
|
|
|
Length - number of byte to translate
|
|
|
|
AddressSpace - address space for the given address
|
|
|
|
Return Value:
|
|
|
|
AddressSpace - address space for the translated address
|
|
|
|
TranslatedAddress - translated address
|
|
|
|
TranslatedMemoryAddress - tranlated memory address if translated to memory space
|
|
|
|
NT Status
|
|
|
|
--*/
|
|
{
|
|
PHYSICAL_ADDRESS translatedAddress;
|
|
|
|
ASSERT (Length);
|
|
ASSERT (AddressSpace);
|
|
ASSERT (TranslatedAddress);
|
|
|
|
*TranslatedAddress = NULL;
|
|
TranslatedMemoryAddress->QuadPart = (ULONGLONG) NULL;
|
|
|
|
if (HalTranslateBusAddress(InterfaceType,
|
|
BusNumber,
|
|
StartAddress,
|
|
AddressSpace,
|
|
&translatedAddress)) {
|
|
|
|
|
|
if (*AddressSpace == IO_SPACE) {
|
|
|
|
*TranslatedAddress = (PVOID) translatedAddress.u.LowPart;
|
|
|
|
} else if (*AddressSpace == MEMORY_SPACE) {
|
|
|
|
//
|
|
// translated address is in memory space,
|
|
// need to map it to I/O space.
|
|
//
|
|
*TranslatedMemoryAddress = translatedAddress;
|
|
|
|
*TranslatedAddress = MmMapIoSpace(
|
|
translatedAddress,
|
|
Length,
|
|
FALSE);
|
|
}
|
|
}
|
|
|
|
if (*TranslatedAddress) {
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
} // IdePortTranslateAddress
|
|
|
|
|
|
VOID
|
|
IdePortFreeTranslatedAddress (
|
|
IN PVOID TranslatedAddress,
|
|
IN LONG Length,
|
|
IN ULONG AddressSpace
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
free resources created for a translated address
|
|
|
|
Arguments:
|
|
|
|
TranslatedAddress - translated address
|
|
|
|
Length - number of byte to translated
|
|
|
|
AddressSpace - address space for the translated address
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (TranslatedAddress) {
|
|
|
|
if (AddressSpace == MEMORY_SPACE) {
|
|
|
|
MmUnmapIoSpace (
|
|
TranslatedAddress,
|
|
Length
|
|
);
|
|
}
|
|
}
|
|
return;
|
|
} // IdePortFreeTranslatedAddress
|
|
|
|
|
|
BOOLEAN
|
|
IdePortDetectAlias (
|
|
PIDE_REGISTERS_1 CmdRegBase
|
|
)
|
|
{
|
|
PIDE_REGISTERS_1 cmdRegBaseAlias;
|
|
PUCHAR cylinderHighAlias;
|
|
PUCHAR cylinderLowAlias;
|
|
|
|
//
|
|
// alias port
|
|
//
|
|
cylinderHighAlias = (PUCHAR) ((ULONG_PTR) CmdRegBase->CylinderHigh | (1 << 15));
|
|
cylinderLowAlias = (PUCHAR) ((ULONG_PTR) CmdRegBase->CylinderLow | (1 << 15));
|
|
|
|
IdePortOutPortByte (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
|
|
IdePortOutPortByte (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
|
|
|
|
//
|
|
// Check if indentifier can be read back via the alias port
|
|
//
|
|
if ((IdePortInPortByte (cylinderHighAlias) != SAMPLE_CYLINDER_HIGH_VALUE) ||
|
|
(IdePortInPortByte (cylinderLowAlias) != SAMPLE_CYLINDER_LOW_VALUE)) {
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
#endif // NO_LEGACY_DRIVERS
|