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.
798 lines
26 KiB
798 lines
26 KiB
/*++
|
|
|
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
detect.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that controls the PCMCIA slots.
|
|
|
|
Authors:
|
|
|
|
Bob Rinne (BobRi) 3-Nov-1994
|
|
Neil Sandlin (neilsa) June 1 1999
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
Modified for plug'n'play support
|
|
Ravisankar Pudipeddi (ravisp) 1 Dec 1996
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaDetectControllers(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PPCMCIA_DETECT_ROUTINE PcmciaDetectFn
|
|
);
|
|
|
|
NTSTATUS
|
|
PcmciaReportDetectedDevice(
|
|
IN PFDO_EXTENSION DeviceExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PcmciaAllocateOpenMemoryWindow(
|
|
IN PFDO_EXTENSION DeviceExtension,
|
|
IN PPHYSICAL_ADDRESS PhysicalAddress,
|
|
IN PULONG PhysicalAddressSize
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
// #pragma alloc_text(INIT,PcmciaLegacyDetectionOk)
|
|
#pragma alloc_text(INIT,PcmciaDetectPcmciaControllers)
|
|
#pragma alloc_text(INIT,PcmciaDetectControllers)
|
|
#pragma alloc_text(INIT,PcmciaReportDetectedDevice)
|
|
#pragma alloc_text(INIT,PcmciaAllocateOpenMemoryWindow)
|
|
#endif
|
|
|
|
|
|
#if 0
|
|
|
|
BOOLEAN
|
|
PcmciaLegacyDetectionOk(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Checks if legacy detection needs to be done for pcmcia controllers
|
|
|
|
Arguments
|
|
|
|
None
|
|
|
|
Return Value
|
|
|
|
TRUE - If legacy detection can be done
|
|
FALSE - If legacy detection should NOT be attempted
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING unicodeKey, unicodeValue;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
HANDLE handle;
|
|
UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+
|
|
sizeof(ULONG)];
|
|
PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
|
|
ULONG length;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString(&unicodeKey,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Pnp");
|
|
|
|
RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
&unicodeKey,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(ZwOpenKey(&handle,
|
|
KEY_QUERY_VALUE,
|
|
&objectAttributes))) {
|
|
//
|
|
// Key doesn't exist
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
RtlInitUnicodeString(&unicodeValue, L"DisableFirmwareMapper");
|
|
|
|
status = ZwQueryValueKey(handle,
|
|
&unicodeValue,
|
|
KeyValuePartialInformation,
|
|
value,
|
|
sizeof(buffer),
|
|
&length);
|
|
ZwClose(handle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// Value doesn't exist
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
if (value->Type == REG_DWORD) {
|
|
//
|
|
// If value is non-zero don't do legacy detection
|
|
// otherwise it's ok
|
|
//
|
|
return ((ULONG) (*((PULONG)value->Data)) ? FALSE : TRUE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaDetectPcmciaControllers(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Detects appropriate PCMCIA controllers both ISA & PCI based
|
|
in the system.
|
|
|
|
Arguments:
|
|
|
|
DriverObject Just as passed in to DriverEntry
|
|
RegistryPath
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS if any PCMCIA controllers were found
|
|
STATUS_NO_SUCH_DEVICE otherwise
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS pcicIsaStatus = STATUS_UNSUCCESSFUL, tcicStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// We enumerate the PCI devices first to ensure that the ISA detect
|
|
// doesn't probe those address ports which are already claimed by
|
|
// detected PCI devices
|
|
//
|
|
pcicIsaStatus = PcmciaDetectControllers(DriverObject, RegistryPath, PcicIsaDetect);
|
|
|
|
tcicStatus = PcmciaDetectControllers(DriverObject, RegistryPath, TcicDetect);
|
|
|
|
//
|
|
// Indicate success if we found any controllers
|
|
//
|
|
return ((NT_SUCCESS(pcicIsaStatus) ||
|
|
NT_SUCCESS(tcicStatus) ) ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaDetectControllers(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PPCMCIA_DETECT_ROUTINE PcmciaDetectFn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Detects PCMCIA controllers in the system and reports them. This is called
|
|
by PcmciaDetectPcmciaControllers. This reports bus specific controllers.
|
|
|
|
Arguments:
|
|
DriverObject, RegistryPath - See DriverEntry
|
|
PcmciaDetectFn - Pointer to the function that actually probes the hardware
|
|
to find PCMCIA controllers. So this routine can be called
|
|
with an ISA detect function or a PCI detect function for eg.
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS Found one or more PCMCIA controllers
|
|
STATUS_NO_SUCH_DEVICE No controllers found.
|
|
STATUS_INSUFFICIENT_RESOURCES Pool allocation failures etc.
|
|
|
|
--*/
|
|
{
|
|
|
|
PFDO_EXTENSION deviceExtension = NULL;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
NTSTATUS detectStatus;
|
|
BOOLEAN controllerDetected = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Allocate a dummy device extension which is used by the Pcic & Tcic detect modules
|
|
// Have to do this since the original detection code required device extensions
|
|
// Too painful to change this structure now.
|
|
//
|
|
deviceExtension = ExAllocatePool(NonPagedPool, sizeof(FDO_EXTENSION));
|
|
if (deviceExtension == NULL) {
|
|
DebugPrint((PCMCIA_DEBUG_FAIL, "Cannot allocate pool for FDO extension\n"));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
do {
|
|
|
|
RtlZeroMemory(deviceExtension, sizeof(FDO_EXTENSION));
|
|
|
|
deviceExtension->RegistryPath = RegistryPath;
|
|
deviceExtension->DriverObject = DriverObject;
|
|
|
|
detectStatus = (*PcmciaDetectFn)(deviceExtension);
|
|
|
|
if (detectStatus != STATUS_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
controllerDetected = TRUE;
|
|
|
|
status = PcmciaReportDetectedDevice(deviceExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaDetectControllers: PcmciaReportDetectedDevice "
|
|
"failed, status %x\n", status));
|
|
continue;
|
|
}
|
|
|
|
} while (detectStatus != STATUS_NO_MORE_ENTRIES);
|
|
|
|
ExFreePool(deviceExtension);
|
|
|
|
if (controllerDetected) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return (STATUS_NO_SUCH_DEVICE);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaReportDetectedDevice(
|
|
IN PFDO_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reports the PCMCIA controllers detected to the IO subsystem which creates the
|
|
madeup devnodes for these DeviceObjects.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - DeviceExtension for the DeviceObject (FDO) of the PCMCIA controller
|
|
being reported
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_OBJECT pdo = NULL, fdo, lowerDevice;
|
|
PFDO_EXTENSION fdoExtension;
|
|
ULONG pcmciaInterruptVector;
|
|
KIRQL pcmciaInterruptLevel;
|
|
KAFFINITY pcmciaAffinity;
|
|
PSOCKET socket;
|
|
NTSTATUS status;
|
|
ULONG pcmciaIrq;
|
|
ULONG count, ioResourceReqSize;
|
|
PHYSICAL_ADDRESS halMemoryAddress;
|
|
ULONG addressSpace;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST ioResourceReq=NULL;
|
|
PIO_RESOURCE_LIST ioResourceList;
|
|
PIO_RESOURCE_DESCRIPTOR ioResourceDesc;
|
|
PCM_RESOURCE_LIST allocatedResources;
|
|
PCM_RESOURCE_LIST scratchResources;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmResourceDesc;
|
|
BOOLEAN translated;
|
|
UCHAR option;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Do initial setup in our "fake" device extension
|
|
//
|
|
PcmciaGetControllerRegistrySettings(DeviceExtension);
|
|
|
|
DeviceExtension->Configuration.InterruptPin = 0;
|
|
DeviceExtension->Configuration.Interrupt.u.Interrupt.Vector = 0;
|
|
DeviceExtension->Configuration.Interrupt.u.Interrupt.Level = 0;
|
|
|
|
count=0;
|
|
//
|
|
// Get an 'open' memory window
|
|
//
|
|
status = PcmciaAllocateOpenMemoryWindow(DeviceExtension,
|
|
&DeviceExtension->PhysicalBase,
|
|
&DeviceExtension->AttributeMemorySize);
|
|
count++;
|
|
|
|
if (DeviceExtension->Configuration.UntranslatedPortAddress) {
|
|
count++;
|
|
}
|
|
|
|
ioResourceReqSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + (count-1)*sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
|
|
ioResourceReq = ExAllocatePool(PagedPool, ioResourceReqSize);
|
|
if (ioResourceReq == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlZeroMemory(ioResourceReq, ioResourceReqSize);
|
|
|
|
ioResourceReq->ListSize = ioResourceReqSize;
|
|
ioResourceReq->InterfaceType = Isa; // DeviceExtension->Configuration.InterfaceType;
|
|
ioResourceReq->BusNumber = DeviceExtension->Configuration.BusNumber;
|
|
ioResourceReq->SlotNumber= DeviceExtension->Configuration.SlotNumber;
|
|
ioResourceReq->AlternativeLists=1;
|
|
|
|
ioResourceList = &(ioResourceReq->List[0]);
|
|
ioResourceList->Version = IO_RESOURCE_LIST_VERSION;
|
|
ioResourceList->Revision = IO_RESOURCE_LIST_REVISION;
|
|
ioResourceList->Count = count;
|
|
|
|
ioResourceDesc = ioResourceList->Descriptors;
|
|
|
|
//
|
|
//Request IO
|
|
//
|
|
if (DeviceExtension->Configuration.UntranslatedPortAddress) {
|
|
ioResourceDesc->Option = 0;
|
|
ioResourceDesc->Type = CmResourceTypePort;
|
|
ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
ioResourceDesc->Flags = CM_RESOURCE_PORT_IO;
|
|
ioResourceDesc->u.Port.MinimumAddress.LowPart = (ULONG)(DeviceExtension->Configuration.UntranslatedPortAddress);
|
|
ioResourceDesc->u.Port.MaximumAddress.LowPart = (ULONG)(DeviceExtension->Configuration.UntranslatedPortAddress+
|
|
DeviceExtension->Configuration.PortSize - 1);
|
|
ioResourceDesc->u.Port.Length = DeviceExtension->Configuration.PortSize;
|
|
ioResourceDesc->u.Port.Alignment = 1;
|
|
ioResourceDesc++;
|
|
}
|
|
|
|
//
|
|
// Request memory
|
|
//
|
|
ioResourceDesc->Option = 0;
|
|
ioResourceDesc->Type = CmResourceTypeMemory;
|
|
ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
ioResourceDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
|
|
if (DeviceExtension->PhysicalBase.QuadPart) {
|
|
ioResourceDesc->u.Memory.MinimumAddress = DeviceExtension->PhysicalBase;
|
|
ioResourceDesc->u.Memory.MaximumAddress.QuadPart = DeviceExtension->PhysicalBase.QuadPart+DeviceExtension->AttributeMemorySize-1;
|
|
ioResourceDesc->u.Memory.Length = DeviceExtension->AttributeMemorySize;
|
|
ioResourceDesc->u.Memory.Alignment = 1;
|
|
ioResourceDesc++;
|
|
} else {
|
|
//
|
|
ioResourceDesc->u.Memory.MinimumAddress.LowPart = DeviceExtension->AttributeMemoryLow;
|
|
ioResourceDesc->u.Memory.MaximumAddress.LowPart = DeviceExtension->AttributeMemoryHigh;
|
|
ioResourceDesc->u.Memory.Length = DeviceExtension->AttributeMemorySize;
|
|
switch (DeviceExtension->ControllerType) {
|
|
|
|
case PcmciaDatabook: {
|
|
ioResourceDesc->u.Memory.Alignment = TCIC_WINDOW_ALIGNMENT;
|
|
break;
|
|
}
|
|
default: {
|
|
ioResourceDesc->u.Memory.Alignment = PCIC_WINDOW_ALIGNMENT;
|
|
break;
|
|
}
|
|
}
|
|
ioResourceDesc++;
|
|
}
|
|
|
|
|
|
status = IoAssignResources(DeviceExtension->RegistryPath,
|
|
NULL,
|
|
DeviceExtension->DriverObject,
|
|
NULL,
|
|
ioResourceReq,
|
|
&allocatedResources
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// Log an event here
|
|
//
|
|
PcmciaLogError(DeviceExtension, PCMCIA_NO_RESOURCES, 1, 0);
|
|
|
|
DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaReportDetectedDevice: IoAssignResources failed status %x\n",
|
|
status));
|
|
ExFreePool(ioResourceReq);
|
|
return status;
|
|
}
|
|
|
|
|
|
//
|
|
// Fish out the Memory Base allocated to this controller from the
|
|
// nether depths of the CM_RESOURCE_LIST
|
|
//
|
|
count = allocatedResources->List[0].PartialResourceList.Count;
|
|
cmResourceDesc = &(allocatedResources->List[0].PartialResourceList.PartialDescriptors[0]);
|
|
|
|
while (count--) {
|
|
switch (cmResourceDesc->Type) {
|
|
|
|
case CmResourceTypeMemory: {
|
|
|
|
DeviceExtension->PhysicalBase = cmResourceDesc->u.Memory.Start;
|
|
DeviceExtension->AttributeMemorySize = cmResourceDesc->u.Memory.Length;
|
|
|
|
addressSpace=0;
|
|
translated = HalTranslateBusAddress(Isa,
|
|
0,
|
|
cmResourceDesc->u.Memory.Start,
|
|
&addressSpace,
|
|
&halMemoryAddress);
|
|
ASSERT(translated);
|
|
if (addressSpace) {
|
|
DeviceExtension->AttributeMemoryBase = (PUCHAR)(halMemoryAddress.QuadPart);
|
|
DeviceExtension->Flags &= ~PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
|
|
}
|
|
|
|
else {
|
|
DeviceExtension->AttributeMemoryBase = MmMapIoSpace(halMemoryAddress,
|
|
cmResourceDesc->u.Memory.Length,
|
|
FALSE);
|
|
DeviceExtension->Flags |= PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
|
|
}
|
|
DebugPrint((PCMCIA_DEBUG_INFO,
|
|
"Attribute Memory Physical Base: %x Virtual Addr: %x\n",
|
|
DeviceExtension->PhysicalBase,
|
|
DeviceExtension->AttributeMemoryBase));
|
|
break;
|
|
}
|
|
// Don't bother to parse IO, it was a fixed resource requirement which we already know about
|
|
}
|
|
cmResourceDesc++;
|
|
}
|
|
|
|
//
|
|
// Free resources so IoReportDetectedDevice can assign them for the PDO
|
|
//
|
|
IoAssignResources(DeviceExtension->RegistryPath,
|
|
NULL,
|
|
DeviceExtension->DriverObject,
|
|
NULL,
|
|
NULL,
|
|
&scratchResources
|
|
);
|
|
|
|
pdo = NULL;
|
|
status = IoReportDetectedDevice(
|
|
DeviceExtension->DriverObject,
|
|
InterfaceTypeUndefined,
|
|
-1,
|
|
-1,
|
|
allocatedResources,
|
|
ioResourceReq,
|
|
FALSE,
|
|
&pdo
|
|
);
|
|
|
|
ExFreePool(allocatedResources);
|
|
ExFreePool(ioResourceReq);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaReportDetectedDevice: IoReportDetectedDevice failed\n"));
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Set up registry params for the madeup pdo so we'll recognize it on the next boot
|
|
// when the PNP manager gives us an AddDevice/IRP_MN_START_DEVICE
|
|
//
|
|
PcmciaSetLegacyDetectedControllerType(pdo, DeviceExtension->ControllerType);
|
|
|
|
//
|
|
// The I/O subsystem has created the true PDO which we will use during this boot. So we
|
|
// have to attach to this PDO, and initialize our new FDO extension to values already set
|
|
// into our original (fake) FDO extension.
|
|
//
|
|
|
|
status = PcmciaAddDevice(DeviceExtension->DriverObject, pdo);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaReportDetectedDevice: AddDevice failed status %x\n", status));
|
|
return status;
|
|
}
|
|
|
|
pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
//
|
|
// Head of list is our fdo
|
|
//
|
|
fdo = FdoList;
|
|
fdoExtension = fdo->DeviceExtension;
|
|
|
|
//
|
|
// Copy in the rest of the config. from the DeviceExtension
|
|
//
|
|
fdoExtension->SocketList = DeviceExtension->SocketList;
|
|
fdoExtension->Configuration = DeviceExtension->Configuration;
|
|
fdoExtension->PhysicalBase = DeviceExtension->PhysicalBase;
|
|
fdoExtension->AttributeMemoryBase = DeviceExtension->AttributeMemoryBase;
|
|
fdoExtension->AttributeMemorySize = DeviceExtension->AttributeMemorySize;
|
|
fdoExtension->Flags = DeviceExtension->Flags;
|
|
|
|
// Reinitialize the socket's device extensions
|
|
//
|
|
for (socket = fdoExtension->SocketList; socket!=NULL; socket=socket->NextSocket) {
|
|
socket->DeviceExtension = fdoExtension;
|
|
}
|
|
|
|
fdoExtension->Flags |= PCMCIA_DEVICE_STARTED;
|
|
//
|
|
// This is legacy detected..
|
|
//
|
|
fdoExtension->Flags |= PCMCIA_DEVICE_LEGACY_DETECTED;
|
|
|
|
status=PcmciaStartPcmciaController(fdo);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
fdoExtension->Flags &= ~PCMCIA_DEVICE_STARTED;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaAllocateOpenMemoryWindow(
|
|
IN PFDO_EXTENSION DeviceExtension,
|
|
IN PPHYSICAL_ADDRESS PhysicalAddress,
|
|
IN PULONG PhysicalAddressSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search the 640K to 1MB region for an open area to be used
|
|
for mapping PCCARD attribute memory.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
A physical address for the window to the card or zero meaning
|
|
there is no opening.
|
|
|
|
--*/
|
|
|
|
{
|
|
#define NUMBER_OF_TEST_BYTES 25
|
|
PHYSICAL_ADDRESS physicalMemoryAddress;
|
|
PHYSICAL_ADDRESS halMemoryAddress;
|
|
BOOLEAN translated;
|
|
ULONG untranslatedAddress;
|
|
PUCHAR memoryAddress;
|
|
PUCHAR bogus;
|
|
ULONG addressSpace;
|
|
ULONG index;
|
|
UCHAR memory[NUMBER_OF_TEST_BYTES];
|
|
PCM_RESOURCE_LIST cmResourceList = NULL;
|
|
PCM_PARTIAL_RESOURCE_LIST cmPartialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmResourceDesc;
|
|
BOOLEAN conflict = TRUE;
|
|
NTSTATUS status;
|
|
ULONG windowSize, windowAlignment;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
cmResourceList = ExAllocatePool(PagedPool, sizeof(CM_RESOURCE_LIST));
|
|
if (!cmResourceList) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlZeroMemory(cmResourceList, sizeof(CM_RESOURCE_LIST));
|
|
cmResourceList->Count = 1;
|
|
cmResourceList->List[0].InterfaceType = Isa;
|
|
cmPartialResourceList = &(cmResourceList->List[0].PartialResourceList);
|
|
cmPartialResourceList->Version = 1;
|
|
cmPartialResourceList->Revision = 1;
|
|
cmPartialResourceList->Count = 1;
|
|
cmResourceDesc = cmPartialResourceList->PartialDescriptors;
|
|
cmResourceDesc->Type = CmResourceTypeMemory;
|
|
cmResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
cmResourceDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
|
|
|
|
//
|
|
// Size of the attr. memory window
|
|
//
|
|
switch (DeviceExtension->ControllerType) {
|
|
|
|
case PcmciaDatabook: {
|
|
windowSize = TCIC_WINDOW_SIZE;
|
|
windowAlignment = TCIC_WINDOW_ALIGNMENT;
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
windowSize = PCIC_WINDOW_SIZE;
|
|
windowAlignment = PCIC_WINDOW_ALIGNMENT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (untranslatedAddress = DeviceExtension->AttributeMemoryLow;
|
|
untranslatedAddress < DeviceExtension->AttributeMemoryHigh;
|
|
untranslatedAddress += windowAlignment) {
|
|
|
|
if (untranslatedAddress == 0xc0000) {
|
|
|
|
//
|
|
// This is VGA. Keep this test if the for loop should
|
|
// ever change.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check if it's available
|
|
//
|
|
cmResourceDesc->u.Memory.Start.LowPart = untranslatedAddress;
|
|
cmResourceDesc->u.Memory.Length = windowSize;
|
|
|
|
status=IoReportResourceForDetection(
|
|
DeviceExtension->DriverObject,
|
|
cmResourceList,
|
|
sizeof(CM_RESOURCE_LIST),
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&conflict);
|
|
if (!NT_SUCCESS(status) || conflict) {
|
|
//
|
|
// This range's already taken. Move on to the next
|
|
//
|
|
continue;
|
|
}
|
|
|
|
addressSpace = 0;
|
|
physicalMemoryAddress.LowPart = untranslatedAddress;
|
|
physicalMemoryAddress.HighPart = 0;
|
|
|
|
translated = HalTranslateBusAddress(Isa,
|
|
0,
|
|
physicalMemoryAddress,
|
|
&addressSpace,
|
|
&halMemoryAddress);
|
|
|
|
if (!translated) {
|
|
|
|
//
|
|
// HAL doesn't like this translation
|
|
//
|
|
|
|
continue;
|
|
}
|
|
if (addressSpace) {
|
|
memoryAddress = (PUCHAR)(halMemoryAddress.QuadPart);
|
|
} else {
|
|
memoryAddress = MmMapIoSpace(halMemoryAddress, windowSize, FALSE);
|
|
}
|
|
|
|
//
|
|
// Test the memory window to determine if it is a BIOS, video
|
|
// memory, or open memory. Only want to keep the window if it
|
|
// is not being used by something else.
|
|
//
|
|
|
|
for (index = 0; index < NUMBER_OF_TEST_BYTES; index++) {
|
|
memory[index] = READ_REGISTER_UCHAR(memoryAddress + index);
|
|
if (index) {
|
|
if (memory[index] != memory[index - 1]) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (index == NUMBER_OF_TEST_BYTES) {
|
|
|
|
//
|
|
// There isn't a BIOS here
|
|
//
|
|
|
|
UCHAR memoryPattern[NUMBER_OF_TEST_BYTES];
|
|
BOOLEAN changed = FALSE;
|
|
|
|
//
|
|
// Check for video memory - open memory should always remain
|
|
// the same regardless what the changes are. Change the
|
|
// pattern previously found.
|
|
//
|
|
|
|
for (index = 0; index < NUMBER_OF_TEST_BYTES; index++) {
|
|
memoryPattern[index] = ~memory[index];
|
|
WRITE_REGISTER_UCHAR(memoryAddress + index,
|
|
memoryPattern[index]);
|
|
}
|
|
|
|
//
|
|
// See if the pattern in memory changed.
|
|
// Some system exhibit a problem where the memory pattern
|
|
// seems to be cached. If this code is debugged it will
|
|
// work as expected, but if it is run normally it will
|
|
// always return that the memory changed. This random
|
|
// wandering seems to remove this problem.
|
|
//
|
|
|
|
for (index = 0; index < NUMBER_OF_TEST_BYTES; index++) {
|
|
memoryPattern[index] = 0;
|
|
}
|
|
bogus = ExAllocatePool(PagedPool, 64 * 1024);
|
|
|
|
if (bogus) {
|
|
for (index = 0; index < 64 * 1024; index++) {
|
|
bogus[index] = 0;
|
|
}
|
|
ExFreePool(bogus);
|
|
}
|
|
|
|
//
|
|
// Now go off and do the actual check to see if the memory
|
|
// changed.
|
|
//
|
|
|
|
for (index = 0; index < NUMBER_OF_TEST_BYTES; index++) {
|
|
|
|
if ((memoryPattern[index] = READ_REGISTER_UCHAR(memoryAddress + index)) != memory[index]) {
|
|
|
|
//
|
|
// It changed - this is not an area of open memory
|
|
//
|
|
|
|
changed = TRUE;
|
|
}
|
|
WRITE_REGISTER_UCHAR(memoryAddress + index,
|
|
memory[index]);
|
|
}
|
|
|
|
if (!changed) {
|
|
|
|
//
|
|
// Area isn't a BIOS and didn't change when written.
|
|
// Use this region for the memory window to PCMCIA
|
|
// attribute memory.
|
|
//
|
|
|
|
PhysicalAddress->LowPart = untranslatedAddress;
|
|
PhysicalAddress->HighPart = 0;
|
|
*PhysicalAddressSize = windowSize;
|
|
if (!addressSpace) {
|
|
MmUnmapIoSpace(memoryAddress, windowSize);
|
|
}
|
|
ExFreePool(cmResourceList);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (!addressSpace) {
|
|
MmUnmapIoSpace(memoryAddress, windowSize);
|
|
}
|
|
}
|
|
ExFreePool(cmResourceList);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|