797 lines
23 KiB
C
797 lines
23 KiB
C
/*++
|
||
|
||
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
|
||
|
||
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
|
||
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;
|
||
}
|
||
|