1434 lines
39 KiB
C
1434 lines
39 KiB
C
|
||
/*++
|
||
|
||
Copyright (c) 1997-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
registry.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code that manipulates the ARC firmware
|
||
tree and other elements in the registry.
|
||
|
||
Author:
|
||
|
||
Bob Rinne
|
||
Ravisankar Pudipeddi (ravisp) 1 Dec 1996
|
||
Neil Sandlin (neilsa) June 1 1999
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History :
|
||
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
//
|
||
// Internal References
|
||
//
|
||
|
||
VOID
|
||
PcmciaGetRegistryContextRange(
|
||
IN HANDLE instanceHandle,
|
||
IN PCWSTR Name,
|
||
IN OPTIONAL const PCMCIA_CONTEXT_RANGE IncludeRange[],
|
||
IN OPTIONAL const PCMCIA_CONTEXT_RANGE ExcludeRange[],
|
||
OUT PPCMCIA_CONTEXT pContext
|
||
);
|
||
|
||
ULONG
|
||
PcmciaGetDetectedFdoIrqMask(
|
||
IN PFDO_EXTENSION FdoExtension
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaScanHardwareDescription(
|
||
VOID
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaGetHardwareDetectedIrqMask(
|
||
IN HANDLE handlePcCard
|
||
);
|
||
|
||
//
|
||
//
|
||
// Registry related definitions
|
||
//
|
||
#define PCMCIA_REGISTRY_PARAMETERS_KEY L"Pcmcia\\Parameters"
|
||
#define PCMCIA_REGISTRY_DETECTED_DEVICE_KEY L"ControllerProperties"
|
||
|
||
|
||
//
|
||
// Per controller values (in control\class)
|
||
//
|
||
|
||
#define PCMCIA_REGISTRY_PCI_CONTEXT_VALUE L"CBSSCSContextRanges"
|
||
#define PCMCIA_REGISTRY_CB_CONTEXT_VALUE L"CBSSCBContextRanges"
|
||
#define PCMCIA_REGISTRY_EXCA_CONTEXT_VALUE L"CBSSEXCAContextRanges"
|
||
#define PCMCIA_REGISTRY_CACHED_IRQMASK L"CachedIrqMask"
|
||
#define PCMCIA_REGISTRY_COMPATIBLE_TYPE L"CompatibleControllerType"
|
||
#define PCMCIA_REGISTRY_VOLTAGE_PREFERENCE L"VoltagePreference"
|
||
|
||
//
|
||
// Irq detection values (in hardware\description)
|
||
//
|
||
|
||
#define PCMCIA_REGISTRY_CONTROLLER_TYPE L"OtherController"
|
||
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,PcmciaLoadGlobalRegistryValues)
|
||
#pragma alloc_text(INIT,PcmciaScanHardwareDescription)
|
||
#pragma alloc_text(INIT,PcmciaGetHardwareDetectedIrqMask)
|
||
#pragma alloc_text(PAGE,PcmciaGetControllerRegistrySettings)
|
||
#pragma alloc_text(PAGE,PcmciaGetRegistryFdoIrqMask)
|
||
#pragma alloc_text(PAGE,PcmciaGetDetectedFdoIrqMask)
|
||
#pragma alloc_text(PAGE,PcmciaGetLegacyDetectedControllerType)
|
||
#pragma alloc_text(PAGE,PcmciaSetLegacyDetectedControllerType)
|
||
#pragma alloc_text(PAGE,PcmciaGetRegistryContextRange)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaGetHardwareDetectedIrqMask(
|
||
HANDLE handlePcCard
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine looks through the OtherController key for pccard entries
|
||
created by NTDETECT. For each entry, the IRQ scan data is read in and
|
||
saved for later.
|
||
|
||
|
||
Arguments:
|
||
|
||
handlePcCard - open handle to "OtherController" key in registry at
|
||
HARDWARE\Description\System\MultifunctionAdapter\<ISA>
|
||
|
||
Return value:
|
||
|
||
status
|
||
|
||
--*/
|
||
{
|
||
#define VALUE2_BUFFER_SIZE sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(CM_PCCARD_DEVICE_DATA) + sizeof(CM_FULL_RESOURCE_DESCRIPTOR)
|
||
UCHAR valueBuffer[VALUE2_BUFFER_SIZE];
|
||
PKEY_VALUE_PARTIAL_INFORMATION valueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) valueBuffer;
|
||
|
||
NTSTATUS status;
|
||
KEY_FULL_INFORMATION KeyFullInfo;
|
||
PKEY_BASIC_INFORMATION subKeyInfo = NULL;
|
||
OBJECT_ATTRIBUTES attributes;
|
||
UNICODE_STRING strSubKey = {0};
|
||
UNICODE_STRING strIdentifier;
|
||
UNICODE_STRING strConfigData;
|
||
HANDLE handleSubKey = NULL;
|
||
ULONG subKeyInfoSize;
|
||
ULONG index;
|
||
ULONG resultLength;
|
||
|
||
RtlInitUnicodeString(&strIdentifier, L"Identifier");
|
||
RtlInitUnicodeString(&strConfigData, L"Configuration Data");
|
||
|
||
status = ZwQueryKey(handlePcCard,
|
||
KeyFullInformation,
|
||
&KeyFullInfo,
|
||
sizeof(KeyFullInfo),
|
||
&resultLength);
|
||
|
||
if ((!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW))) {
|
||
goto cleanup;
|
||
}
|
||
|
||
strSubKey.MaximumLength = (USHORT) KeyFullInfo.MaxNameLen;
|
||
subKeyInfoSize = sizeof(KEY_BASIC_INFORMATION) + KeyFullInfo.MaxNameLen;
|
||
subKeyInfo = ExAllocatePool(PagedPool, subKeyInfoSize);
|
||
|
||
if (!subKeyInfo) {
|
||
goto cleanup;
|
||
}
|
||
|
||
for (index=0;;index++) {
|
||
|
||
//
|
||
// Loop through the children of the PcCardController key
|
||
//
|
||
|
||
status = ZwEnumerateKey(handlePcCard,
|
||
index,
|
||
KeyBasicInformation,
|
||
subKeyInfo,
|
||
subKeyInfoSize,
|
||
&resultLength);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Init the name
|
||
//
|
||
|
||
if (subKeyInfo->NameLength > strSubKey.MaximumLength) {
|
||
continue;
|
||
}
|
||
strSubKey.Length = (USHORT) subKeyInfo->NameLength;
|
||
strSubKey.Buffer = subKeyInfo->Name;
|
||
|
||
//
|
||
// Get a handle to a child of PcCardController
|
||
//
|
||
|
||
|
||
InitializeObjectAttributes(&attributes,
|
||
&strSubKey,
|
||
0, //Attributes
|
||
handlePcCard,
|
||
NULL //SecurityDescriptor
|
||
);
|
||
|
||
if (handleSubKey) {
|
||
// close handle from previous iteration
|
||
ZwClose(handleSubKey);
|
||
handleSubKey = NULL;
|
||
}
|
||
|
||
status = ZwOpenKey(&handleSubKey, MAXIMUM_ALLOWED, &attributes);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Get the value of "Identifier"
|
||
//
|
||
|
||
status = ZwQueryValueKey(handleSubKey,
|
||
&strIdentifier,
|
||
KeyValuePartialInformation,
|
||
valueInfo,
|
||
VALUE2_BUFFER_SIZE,
|
||
&resultLength);
|
||
|
||
|
||
if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW)) {
|
||
PWCHAR pData = (PWCHAR)valueInfo->Data;
|
||
|
||
if ((valueInfo->DataLength == 17*sizeof(WCHAR)) &&
|
||
(pData[0] == (WCHAR)'P') &&
|
||
(pData[1] == (WCHAR)'c') &&
|
||
(pData[2] == (WCHAR)'C') &&
|
||
(pData[3] == (WCHAR)'a') &&
|
||
(pData[4] == (WCHAR)'r') &&
|
||
(pData[5] == (WCHAR)'d')) {
|
||
|
||
//
|
||
// Get the IRQ detection data
|
||
//
|
||
status = ZwQueryValueKey(handleSubKey,
|
||
&strConfigData,
|
||
KeyValuePartialInformation,
|
||
valueInfo,
|
||
VALUE2_BUFFER_SIZE,
|
||
&resultLength);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
PCM_FULL_RESOURCE_DESCRIPTOR pFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) valueInfo->Data;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) pFullDesc->PartialResourceList.PartialDescriptors;
|
||
|
||
if ((pPartialDesc->Type == CmResourceTypeDeviceSpecific) &&
|
||
(pPartialDesc->u.DeviceSpecificData.DataSize == sizeof(CM_PCCARD_DEVICE_DATA))) {
|
||
|
||
PCM_PCCARD_DEVICE_DATA pData = (PCM_PCCARD_DEVICE_DATA) ((ULONG_PTR)&pPartialDesc->u.DeviceSpecificData + 3*sizeof(ULONG));
|
||
PPCMCIA_NTDETECT_DATA pNewData;
|
||
|
||
pNewData = ExAllocatePool(PagedPool, sizeof(PCMCIA_NTDETECT_DATA));
|
||
|
||
if (pNewData == NULL) {
|
||
goto cleanup;
|
||
}
|
||
|
||
pNewData->PcCardData = *pData;
|
||
pNewData->Next = pNtDetectDataList;
|
||
pNtDetectDataList = pNewData;
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
cleanup:
|
||
if (handleSubKey) {
|
||
ZwClose(handleSubKey);
|
||
}
|
||
|
||
if (subKeyInfo) {
|
||
ExFreePool(subKeyInfo);
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
ULONG
|
||
PcmciaGetDetectedFdoIrqMask(
|
||
IN PFDO_EXTENSION FdoExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine looks through the cached PCMCIA_NTDETECT_DATA entries
|
||
to see if there was an entry for this controller. It then returns the
|
||
detected irq mask for that controller.
|
||
|
||
Arguments:
|
||
|
||
FdoExtension - The fdo extension corresponding to the PCMCIA controller
|
||
|
||
Return value:
|
||
|
||
status
|
||
|
||
--*/
|
||
{
|
||
|
||
PPCMCIA_NTDETECT_DATA pData;
|
||
PCM_PCCARD_DEVICE_DATA pPcCardData;
|
||
ULONG detectedIrqMask = 0;
|
||
|
||
if (FdoExtension->SocketList == NULL) {
|
||
return 0;
|
||
}
|
||
|
||
for (pData = pNtDetectDataList; pData != NULL; pData = pData->Next) {
|
||
|
||
pPcCardData = &pData->PcCardData;
|
||
|
||
|
||
if (CardBusExtension(FdoExtension)) {
|
||
|
||
if (!(pPcCardData->Flags & PCCARD_DEVICE_PCI) || ((pPcCardData->BusData) == 0) ||
|
||
((pPcCardData->BusData & 0xff) != FdoExtension->PciBusNumber) ||
|
||
(((pPcCardData->BusData >> 8) & 0xff) != FdoExtension->PciDeviceNumber)) {
|
||
continue;
|
||
}
|
||
|
||
SetFdoFlag(FdoExtension, PCMCIA_FDO_IRQ_DETECT_DEVICE_FOUND);
|
||
|
||
if (!(pPcCardData->Flags & PCCARD_MAP_ERROR)) {
|
||
//
|
||
// we found the device, and the map looks good
|
||
//
|
||
break;
|
||
}
|
||
|
||
} else {
|
||
|
||
if ((pPcCardData->Flags & PCCARD_DEVICE_PCI) ||
|
||
(pPcCardData->LegacyBaseAddress != (ULONG_PTR)FdoExtension->SocketList->AddressPort)) {
|
||
continue;
|
||
}
|
||
|
||
SetFdoFlag(FdoExtension, PCMCIA_FDO_IRQ_DETECT_DEVICE_FOUND);
|
||
|
||
if (!(pPcCardData->Flags & PCCARD_MAP_ERROR)) {
|
||
//
|
||
// we found the device, and the map looks good
|
||
//
|
||
break;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
if (pData) {
|
||
ULONG i;
|
||
//
|
||
// Found the entry
|
||
//
|
||
// Since we don't currently handle "rewired" irqs, we can compact
|
||
// it down to a bit mask, throwing away irqs that are wired, say
|
||
// IRQ12 on the controller to IRQ15 on the isa bus.
|
||
//
|
||
|
||
for (i = 1; i < 16; i++) {
|
||
if (pPcCardData->IRQMap[i] == i) {
|
||
detectedIrqMask |= (1<<i);
|
||
}
|
||
}
|
||
SetFdoFlag(FdoExtension, PCMCIA_FDO_IRQ_DETECT_COMPLETED);
|
||
}
|
||
return detectedIrqMask;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaScanHardwareDescription(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine finds the "OtherController" entry in
|
||
HARDWARE\Description\System\MultifunctionAdapter\<ISA>. This is
|
||
where NTDETECT stores irq scan results.
|
||
|
||
It also looks for machines that aren't supported, for example MCA
|
||
bus.
|
||
|
||
Arguments:
|
||
|
||
Return value:
|
||
|
||
status
|
||
|
||
--*/
|
||
{
|
||
#define VALUE_BUFFER_SIZE sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3*sizeof(WCHAR)
|
||
|
||
UCHAR valueBuffer[VALUE_BUFFER_SIZE];
|
||
PKEY_VALUE_PARTIAL_INFORMATION valueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) valueBuffer;
|
||
PKEY_BASIC_INFORMATION subKeyInfo = NULL;
|
||
KEY_FULL_INFORMATION KeyFullInfo;
|
||
|
||
HANDLE handleRoot = NULL;
|
||
HANDLE handleSubKey = NULL;
|
||
HANDLE handlePcCard = NULL;
|
||
UNICODE_STRING strRoot, strIdentifier;
|
||
UNICODE_STRING strSubKey = {0};
|
||
UNICODE_STRING strPcCard = {0};
|
||
NTSTATUS status;
|
||
OBJECT_ATTRIBUTES attributes;
|
||
ULONG subKeyInfoSize;
|
||
ULONG resultLength;
|
||
ULONG index;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Get a handle to the MultifunctionAdapter key
|
||
//
|
||
|
||
RtlInitUnicodeString(&strRoot, L"\\Registry\\MACHINE\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter");
|
||
RtlInitUnicodeString(&strIdentifier, L"Identifier");
|
||
RtlInitUnicodeString(&strPcCard, PCMCIA_REGISTRY_CONTROLLER_TYPE);
|
||
|
||
InitializeObjectAttributes(&attributes,
|
||
&strRoot,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL);
|
||
|
||
status = ZwOpenKey(&handleRoot, MAXIMUM_ALLOWED, &attributes);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
status = ZwQueryKey(handleRoot,
|
||
KeyFullInformation,
|
||
&KeyFullInfo,
|
||
sizeof(KeyFullInfo),
|
||
&resultLength);
|
||
|
||
if ((!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW))) {
|
||
goto cleanup;
|
||
}
|
||
|
||
strSubKey.MaximumLength = (USHORT) KeyFullInfo.MaxNameLen;
|
||
subKeyInfoSize = sizeof(KEY_BASIC_INFORMATION) + KeyFullInfo.MaxNameLen;
|
||
subKeyInfo = ExAllocatePool(PagedPool, subKeyInfoSize);
|
||
|
||
if (!subKeyInfo) {
|
||
goto cleanup;
|
||
}
|
||
|
||
for (index=0;;index++) {
|
||
|
||
//
|
||
// Loop through the children of "MultifunctionAdapter"
|
||
//
|
||
|
||
status = ZwEnumerateKey(handleRoot,
|
||
index,
|
||
KeyBasicInformation,
|
||
subKeyInfo,
|
||
subKeyInfoSize,
|
||
&resultLength);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Init the name
|
||
//
|
||
|
||
if (subKeyInfo->NameLength > strSubKey.MaximumLength) {
|
||
continue;
|
||
}
|
||
strSubKey.Length = (USHORT) subKeyInfo->NameLength;
|
||
strSubKey.Buffer = subKeyInfo->Name;
|
||
|
||
//
|
||
// Get a handle to a child of MultifunctionAdapter
|
||
//
|
||
|
||
|
||
InitializeObjectAttributes(&attributes,
|
||
&strSubKey,
|
||
0, //Attributes
|
||
handleRoot,
|
||
NULL //SecurityDescriptor
|
||
);
|
||
|
||
if (handleSubKey) {
|
||
// close handle from previous iteration
|
||
ZwClose(handleSubKey);
|
||
handleSubKey = NULL;
|
||
}
|
||
|
||
status = ZwOpenKey(&handleSubKey, MAXIMUM_ALLOWED, &attributes);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
//
|
||
// Get the value of "Identifier"
|
||
//
|
||
|
||
status = ZwQueryValueKey(handleSubKey,
|
||
&strIdentifier,
|
||
KeyValuePartialInformation,
|
||
valueInfo,
|
||
VALUE_BUFFER_SIZE,
|
||
&resultLength);
|
||
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
PWCHAR pData = (PWCHAR)valueInfo->Data;
|
||
|
||
if ((valueInfo->DataLength == 4*sizeof(WCHAR)) &&
|
||
(pData[0] == (WCHAR)'M') &&
|
||
(pData[1] == (WCHAR)'C') &&
|
||
(pData[2] == (WCHAR)'A') &&
|
||
(pData[3] == UNICODE_NULL)) {
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
goto cleanup;
|
||
}
|
||
|
||
if ((valueInfo->DataLength == 4*sizeof(WCHAR)) &&
|
||
(pData[0] == (WCHAR)'I') &&
|
||
(pData[1] == (WCHAR)'S') &&
|
||
(pData[2] == (WCHAR)'A') &&
|
||
(pData[3] == UNICODE_NULL)) {
|
||
|
||
InitializeObjectAttributes(&attributes,
|
||
&strPcCard,
|
||
0, //Attributes
|
||
handleSubKey,
|
||
NULL //SecurityDescriptor
|
||
);
|
||
|
||
status = ZwOpenKey(&handlePcCard, MAXIMUM_ALLOWED, &attributes);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
status = PcmciaGetHardwareDetectedIrqMask(handlePcCard);
|
||
ZwClose(handlePcCard);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
cleanup:
|
||
if (handleRoot) {
|
||
ZwClose(handleRoot);
|
||
}
|
||
|
||
if (handleSubKey) {
|
||
ZwClose(handleSubKey);
|
||
}
|
||
|
||
if (subKeyInfo) {
|
||
ExFreePool(subKeyInfo);
|
||
}
|
||
|
||
if (status == STATUS_NO_SUCH_DEVICE) {
|
||
//
|
||
// Must be an MCA machine
|
||
//
|
||
return status;
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaLoadGlobalRegistryValues(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called at driver init time to load in various global
|
||
options from the registry.
|
||
These are read in from SYSTEM\CurrentControlSet\Services\Pcmcia\Parameters.
|
||
|
||
Arguments:
|
||
|
||
none
|
||
|
||
Return value:
|
||
|
||
none
|
||
|
||
--*/
|
||
{
|
||
PRTL_QUERY_REGISTRY_TABLE parms;
|
||
NTSTATUS status;
|
||
ULONG parmsSize;
|
||
ULONG i;
|
||
|
||
status = PcmciaScanHardwareDescription();
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Needs a null entry to terminate the list
|
||
//
|
||
|
||
parmsSize = sizeof(RTL_QUERY_REGISTRY_TABLE) * (GlobalInfoCount+1);
|
||
|
||
parms = ExAllocatePool(PagedPool, parmsSize);
|
||
|
||
if (!parms) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(parms, parmsSize);
|
||
|
||
//
|
||
// Fill in the query table from our table
|
||
//
|
||
|
||
for (i = 0; i < GlobalInfoCount; i++) {
|
||
parms[i].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
parms[i].Name = GlobalRegistryInfo[i].Name;
|
||
parms[i].EntryContext = GlobalRegistryInfo[i].pValue;
|
||
parms[i].DefaultType = REG_DWORD;
|
||
parms[i].DefaultData = &GlobalRegistryInfo[i].Default;
|
||
parms[i].DefaultLength = sizeof(ULONG);
|
||
}
|
||
|
||
//
|
||
// Perform the query
|
||
//
|
||
|
||
status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
|
||
PCMCIA_REGISTRY_PARAMETERS_KEY,
|
||
parms,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
//
|
||
// This is possible during text mode setup
|
||
//
|
||
|
||
for (i = 0; i < GlobalInfoCount; i++) {
|
||
*GlobalRegistryInfo[i].pValue = GlobalRegistryInfo[i].Default;
|
||
}
|
||
}
|
||
|
||
if (initSoundsEnabled) {
|
||
PcmciaGlobalFlags |= PCMCIA_GLOBAL_SOUNDS_ENABLED;
|
||
}
|
||
|
||
if (initUsePolledCsc) {
|
||
PcmciaGlobalFlags |= PCMCIA_GLOBAL_FORCE_POLL_MODE;
|
||
}
|
||
|
||
if (initDisableAcpiNameSpaceCheck) {
|
||
PcmciaGlobalFlags |= PCMCIA_DISABLE_ACPI_NAMESPACE_CHECK;
|
||
}
|
||
|
||
if (initDefaultRouteR2ToIsa) {
|
||
PcmciaGlobalFlags |= PCMCIA_DEFAULT_ROUTE_R2_TO_ISA;
|
||
}
|
||
|
||
if (!pcmciaIsaIrqRescanComplete) {
|
||
UNICODE_STRING unicodeKey, unicodeValue;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
HANDLE handle;
|
||
ULONG value;
|
||
|
||
//
|
||
// This mechanism is used to throw away the cached ISA irq map values. To do this
|
||
// only once, we make sure a value in the registry is zero (or non-existant), and
|
||
// here we set it to one.
|
||
//
|
||
|
||
RtlInitUnicodeString(&unicodeKey,
|
||
L"\\Registry\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Pcmcia\\Parameters");
|
||
RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));
|
||
InitializeObjectAttributes(&objectAttributes,
|
||
&unicodeKey,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (NT_SUCCESS(ZwOpenKey(&handle, KEY_READ | KEY_WRITE, &objectAttributes))) {
|
||
|
||
RtlInitUnicodeString(&unicodeValue, PCMCIA_REGISTRY_ISA_IRQ_RESCAN_COMPLETE);
|
||
value = 1;
|
||
|
||
ZwSetValueKey(handle,
|
||
&unicodeValue,
|
||
0,
|
||
REG_DWORD,
|
||
&value,
|
||
sizeof(value));
|
||
|
||
ZwClose(handle);
|
||
}
|
||
|
||
}
|
||
|
||
ExFreePool(parms);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaGetControllerRegistrySettings(
|
||
IN OUT PFDO_EXTENSION FdoExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine looks in the registry to see if a compatible controller type
|
||
was specified in the INF.
|
||
|
||
Arguments:
|
||
|
||
FdoExtension - The fdo extension corresponding to the PCMCIA controller
|
||
|
||
Return value:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||
UNICODE_STRING KeyName;
|
||
HANDLE instanceHandle;
|
||
UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
|
||
PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
|
||
ULONG length;
|
||
BOOLEAN UseLegacyIrqMask = TRUE;
|
||
ULONG detectedIrqMask;
|
||
|
||
if (FdoExtension->Pdo) {
|
||
status = IoOpenDeviceRegistryKey(FdoExtension->Pdo,
|
||
PLUGPLAY_REGKEY_DRIVER,
|
||
KEY_READ,
|
||
&instanceHandle
|
||
);
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
instanceHandle = NULL;
|
||
}
|
||
|
||
if (instanceHandle) {
|
||
|
||
//
|
||
// Look to see if a controller ID was specified
|
||
//
|
||
RtlInitUnicodeString(&KeyName, PCMCIA_REGISTRY_COMPATIBLE_TYPE);
|
||
|
||
status = ZwQueryValueKey(instanceHandle,
|
||
&KeyName,
|
||
KeyValuePartialInformation,
|
||
value,
|
||
sizeof(buffer),
|
||
&length);
|
||
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
PcmciaSetControllerType(FdoExtension, *(PPCMCIA_CONTROLLER_TYPE)(value->Data));
|
||
}
|
||
|
||
//
|
||
// Check for voltage preference
|
||
// When an 3v R2 card is plugged in, and the controller
|
||
// sets both 5v and 3.3v, this allows 3.3v to be preferred.
|
||
//
|
||
RtlInitUnicodeString(&KeyName, PCMCIA_REGISTRY_VOLTAGE_PREFERENCE);
|
||
|
||
status = ZwQueryValueKey(instanceHandle,
|
||
&KeyName,
|
||
KeyValuePartialInformation,
|
||
value,
|
||
sizeof(buffer),
|
||
&length);
|
||
|
||
|
||
if (NT_SUCCESS(status) && (*(PULONG)(value->Data) == 33)) {
|
||
SetDeviceFlag(FdoExtension, PCMCIA_FDO_PREFER_3V);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Retrieve context ranges
|
||
//
|
||
|
||
PcmciaGetRegistryContextRange(instanceHandle,
|
||
PCMCIA_REGISTRY_PCI_CONTEXT_VALUE,
|
||
DefaultPciContextSave,
|
||
NULL,
|
||
&FdoExtension->PciContext
|
||
);
|
||
|
||
PcmciaGetRegistryContextRange(instanceHandle,
|
||
PCMCIA_REGISTRY_CB_CONTEXT_VALUE,
|
||
DefaultCardbusContextSave,
|
||
ExcludeCardbusContextRange,
|
||
&FdoExtension->CardbusContext
|
||
);
|
||
|
||
PcmciaGetRegistryContextRange(instanceHandle,
|
||
PCMCIA_REGISTRY_EXCA_CONTEXT_VALUE,
|
||
NULL,
|
||
NULL,
|
||
&FdoExtension->ExcaContext);
|
||
|
||
|
||
if (instanceHandle) {
|
||
ZwClose(instanceHandle);
|
||
}
|
||
|
||
|
||
FdoExtension->IoLow = globalIoLow;
|
||
FdoExtension->IoHigh = globalIoHigh;
|
||
FdoExtension->ReadyDelayIter = globalReadyDelayIter;
|
||
FdoExtension->ReadyStall = globalReadyStall;
|
||
FdoExtension->AttributeMemoryLow = globalAttributeMemoryLow;
|
||
FdoExtension->AttributeMemoryHigh = globalAttributeMemoryHigh;
|
||
|
||
if (FdoExtension->ControllerType == PcmciaDatabook) {
|
||
FdoExtension->AttributeMemoryAlignment = TCIC_WINDOW_ALIGNMENT;
|
||
} else {
|
||
FdoExtension->AttributeMemoryAlignment = PCIC_WINDOW_ALIGNMENT;
|
||
}
|
||
|
||
//
|
||
// Assign default attribute memory window size
|
||
//
|
||
|
||
if (globalAttributeMemorySize == 0) {
|
||
switch (FdoExtension->ControllerType) {
|
||
|
||
case PcmciaDatabook:
|
||
FdoExtension->AttributeMemorySize = TCIC_WINDOW_SIZE;
|
||
break;
|
||
default:
|
||
FdoExtension->AttributeMemorySize = PCIC_WINDOW_SIZE;
|
||
break;
|
||
}
|
||
} else {
|
||
FdoExtension->AttributeMemorySize = globalAttributeMemorySize;
|
||
}
|
||
|
||
//
|
||
// See if the user asked for some special IRQ routing considerations based
|
||
// on controller type
|
||
//
|
||
|
||
if (CardBusExtension(FdoExtension)) {
|
||
|
||
//
|
||
// route to PCI based on controller type
|
||
//
|
||
|
||
if (pcmciaIrqRouteToPciController) {
|
||
ULONG ctlr = pcmciaIrqRouteToPciController;
|
||
|
||
//
|
||
// Check for exact match, or class if only a class was specified
|
||
//
|
||
if ((ctlr == FdoExtension->ControllerType) ||
|
||
((PcmciaClassFromControllerType(ctlr) == ctlr) && (ctlr == PcmciaClassFromControllerType(FdoExtension->ControllerType)))) {
|
||
|
||
SetFdoFlag(FdoExtension, PCMCIA_FDO_PREFER_PCI_ROUTING);
|
||
}
|
||
}
|
||
|
||
//
|
||
// route to ISA based on controller type
|
||
//
|
||
|
||
if (pcmciaIrqRouteToIsaController) {
|
||
ULONG ctlr = pcmciaIrqRouteToIsaController;
|
||
|
||
//
|
||
// Check for exact match, or class if only a class was specified
|
||
//
|
||
if ((ctlr == FdoExtension->ControllerType) ||
|
||
((PcmciaClassFromControllerType(ctlr) == ctlr) && (ctlr == PcmciaClassFromControllerType(FdoExtension->ControllerType)))) {
|
||
|
||
SetFdoFlag(FdoExtension, PCMCIA_FDO_PREFER_ISA_ROUTING);
|
||
}
|
||
}
|
||
|
||
//
|
||
// route to PCI based on controller location
|
||
//
|
||
|
||
if (pcmciaIrqRouteToPciLocation) {
|
||
ULONG loc = pcmciaIrqRouteToPciLocation;
|
||
|
||
if ( ((loc & 0xff) == FdoExtension->PciBusNumber) &&
|
||
(((loc >> 8) & 0xff) == FdoExtension->PciDeviceNumber)) {
|
||
|
||
SetFdoFlag(FdoExtension, PCMCIA_FDO_FORCE_PCI_ROUTING);
|
||
}
|
||
}
|
||
|
||
//
|
||
// route to ISA based on controller location
|
||
//
|
||
|
||
if (pcmciaIrqRouteToIsaLocation) {
|
||
ULONG loc = pcmciaIrqRouteToIsaLocation;
|
||
|
||
if ( ((loc & 0xff) == FdoExtension->PciBusNumber) &&
|
||
(((loc >> 8) & 0xff) == FdoExtension->PciDeviceNumber)) {
|
||
|
||
SetFdoFlag(FdoExtension, PCMCIA_FDO_FORCE_ISA_ROUTING);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
PcmciaGetRegistryFdoIrqMask(
|
||
IN OUT PFDO_EXTENSION FdoExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine fills in the field "AllocatedIrqMask" in the specified
|
||
fdo extension.
|
||
|
||
Arguments:
|
||
|
||
instanceHandle - open registry key for this controller
|
||
pIrqMask - pointer to variable to receive irq mask
|
||
|
||
Return value:
|
||
|
||
none
|
||
|
||
--*/
|
||
{
|
||
ULONG irqMask, cachedIrqMask = 0;
|
||
UNICODE_STRING KeyName;
|
||
NTSTATUS status;
|
||
UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
|
||
PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
|
||
ULONG length;
|
||
HANDLE instanceHandle;
|
||
ULONG detectedIrqMask;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (globalOverrideIrqMask) {
|
||
|
||
irqMask = globalOverrideIrqMask;
|
||
|
||
} else {
|
||
|
||
detectedIrqMask = PcmciaGetDetectedFdoIrqMask(FdoExtension);
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
|
||
if (FdoExtension->Pdo) {
|
||
status = IoOpenDeviceRegistryKey(FdoExtension->Pdo,
|
||
PLUGPLAY_REGKEY_DRIVER,
|
||
KEY_READ,
|
||
&instanceHandle
|
||
);
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// Here we cache the value, and accumulate bits so that
|
||
// our mask improves with time.
|
||
//
|
||
RtlInitUnicodeString(&KeyName, PCMCIA_REGISTRY_CACHED_IRQMASK);
|
||
|
||
if (pcmciaIsaIrqRescanComplete) {
|
||
status = ZwQueryValueKey(instanceHandle,
|
||
&KeyName,
|
||
KeyValuePartialInformation,
|
||
value,
|
||
sizeof(buffer),
|
||
&length);
|
||
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
cachedIrqMask = *(PULONG)(value->Data);
|
||
}
|
||
}
|
||
|
||
irqMask = detectedIrqMask | cachedIrqMask;
|
||
|
||
if ((cachedIrqMask != irqMask) || !pcmciaIsaIrqRescanComplete) {
|
||
//
|
||
// something changed, update the cached value
|
||
//
|
||
ZwSetValueKey(instanceHandle, &KeyName, 0, REG_DWORD, &irqMask, sizeof(irqMask));
|
||
}
|
||
|
||
ZwClose(instanceHandle);
|
||
} else {
|
||
//
|
||
// Hmmm, no key. Can't cache the value
|
||
//
|
||
irqMask = detectedIrqMask;
|
||
}
|
||
|
||
if (pcmciaDisableIsaPciRouting && (PcmciaCountOnes(irqMask) < 2)) {
|
||
//
|
||
// Perhaps irq detection is broken... fall back on old NT4 behavior
|
||
//
|
||
irqMask = 0;
|
||
}
|
||
}
|
||
|
||
irqMask &= ~globalFilterIrqMask;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_INFO, "IrqMask %08x (ovr %08x, flt %08x, det %08x, cache %08x)\n",
|
||
irqMask, globalOverrideIrqMask, globalFilterIrqMask, detectedIrqMask, cachedIrqMask));
|
||
|
||
FdoExtension->DetectedIrqMask = (USHORT)irqMask;
|
||
}
|
||
|
||
|
||
VOID
|
||
PcmciaGetRegistryContextRange(
|
||
IN HANDLE instanceHandle,
|
||
IN PCWSTR Name,
|
||
IN OPTIONAL const PCMCIA_CONTEXT_RANGE IncludeRange[],
|
||
IN OPTIONAL const PCMCIA_CONTEXT_RANGE ExcludeRange[],
|
||
OUT PPCMCIA_CONTEXT pContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns a buffer containing the contents of the
|
||
data which set by the controller's inf definition (AddReg). The value
|
||
is in CurrentControlSet\Control\Class\{GUID}\{Instance}.
|
||
|
||
Arguments:
|
||
|
||
FdoExtension - The fdo extension corresponding to the PCMCIA controller
|
||
Name - The name of the value in the registry
|
||
IncludeRange - defines areas in the range that must be included
|
||
ExcludeRange - defines areas in the range that must be excluded
|
||
|
||
Return value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
#define PCMCIA_MAX_CONTEXT_ENTRIES 128
|
||
#define MAX_RANGE_OFFSET 256
|
||
|
||
NTSTATUS status;
|
||
UNICODE_STRING unicodeKeyName;
|
||
UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
|
||
PCMCIA_MAX_CONTEXT_ENTRIES*sizeof(PCMCIA_CONTEXT_RANGE)];
|
||
PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
|
||
UCHAR rangeMap[MAX_RANGE_OFFSET] = {0};
|
||
PPCMCIA_CONTEXT_RANGE newRange;
|
||
LONG rangeCount;
|
||
ULONG rangeLength;
|
||
ULONG bufferLength;
|
||
UCHAR lastEntry;
|
||
ULONG keyLength;
|
||
USHORT i, j;
|
||
USHORT startOffset, endOffset;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Initialize the range map with the minimum range
|
||
//
|
||
|
||
if (IncludeRange) {
|
||
for (i = 0; IncludeRange[i].wLen != 0; i++) {
|
||
|
||
startOffset = IncludeRange[i].wOffset;
|
||
endOffset = IncludeRange[i].wOffset + IncludeRange[i].wLen - 1;
|
||
|
||
if ((startOffset >= MAX_RANGE_OFFSET) ||
|
||
(endOffset >= MAX_RANGE_OFFSET)) {
|
||
continue;
|
||
}
|
||
|
||
for (j = startOffset; j <= endOffset; j++) {
|
||
rangeMap[j] = 0xff;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if (instanceHandle) {
|
||
RtlInitUnicodeString(&unicodeKeyName, Name);
|
||
|
||
status = ZwQueryValueKey(instanceHandle,
|
||
&unicodeKeyName,
|
||
KeyValuePartialInformation,
|
||
value,
|
||
sizeof(buffer),
|
||
&keyLength);
|
||
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Merge in the range specified in the registry
|
||
//
|
||
newRange = (PPCMCIA_CONTEXT_RANGE) value->Data;
|
||
for (i = 0; i < value->DataLength/sizeof(PCMCIA_CONTEXT_RANGE); i++) {
|
||
|
||
startOffset = newRange[i].wOffset;
|
||
endOffset = newRange[i].wOffset + newRange[i].wLen - 1;
|
||
|
||
if ((startOffset >= MAX_RANGE_OFFSET) ||
|
||
(endOffset >= MAX_RANGE_OFFSET)) {
|
||
continue;
|
||
}
|
||
|
||
for (j = startOffset; j <= endOffset; j++) {
|
||
rangeMap[j] = 0xff;
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Filter out registers defined in the exclude range
|
||
//
|
||
|
||
if (ExcludeRange) {
|
||
for (i = 0; ExcludeRange[i].wLen != 0; i++) {
|
||
|
||
startOffset = ExcludeRange[i].wOffset;
|
||
endOffset = ExcludeRange[i].wOffset + ExcludeRange[i].wLen - 1;
|
||
|
||
if ((startOffset >= MAX_RANGE_OFFSET) ||
|
||
(endOffset >= MAX_RANGE_OFFSET)) {
|
||
continue;
|
||
}
|
||
|
||
for (j = startOffset; j <= endOffset; j++) {
|
||
rangeMap[j] = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Now build the resulting merged range in the buffer on the
|
||
// stack, and figure out how big it is.
|
||
//
|
||
newRange = (PPCMCIA_CONTEXT_RANGE) buffer;
|
||
rangeCount = -1;
|
||
bufferLength = 0;
|
||
lastEntry = 0;
|
||
|
||
for (i = 0; i < MAX_RANGE_OFFSET; i++) {
|
||
|
||
if (rangeMap[i]) {
|
||
bufferLength++;
|
||
if (lastEntry) {
|
||
//
|
||
// This new byte belongs to the current range
|
||
//
|
||
newRange[rangeCount].wLen++;
|
||
} else {
|
||
//
|
||
// Starting a new range
|
||
//
|
||
if (rangeCount == (PCMCIA_MAX_CONTEXT_ENTRIES - 1)) {
|
||
break;
|
||
}
|
||
rangeCount++;
|
||
newRange[rangeCount].wOffset = i;
|
||
newRange[rangeCount].wLen = 1;
|
||
}
|
||
|
||
}
|
||
lastEntry = rangeMap[i];
|
||
}
|
||
rangeCount++;
|
||
|
||
pContext->Range = NULL;
|
||
pContext->RangeCount = 0;
|
||
|
||
if (rangeCount) {
|
||
//
|
||
// Length of data
|
||
//
|
||
rangeLength = rangeCount*sizeof(PCMCIA_CONTEXT_RANGE);
|
||
|
||
pContext->Range = ExAllocatePool(NonPagedPool, rangeLength);
|
||
|
||
if (pContext->Range != NULL) {
|
||
RtlCopyMemory(pContext->Range, buffer, rangeLength);
|
||
pContext->RangeCount = (ULONG)rangeCount;
|
||
pContext->BufferLength = bufferLength;
|
||
|
||
//
|
||
// Find the length of the longest individual range
|
||
//
|
||
pContext->MaxLen = 0;
|
||
for (i = 0; i < rangeCount; i++) {
|
||
if (pContext->Range[i].wLen > pContext->MaxLen) {
|
||
pContext->MaxLen = pContext->Range[i].wLen;
|
||
}
|
||
}
|
||
} else {
|
||
ASSERT(pContext->Range != NULL);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaGetLegacyDetectedControllerType(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN OUT PPCMCIA_CONTROLLER_TYPE ControllerType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the previously remembered controller type
|
||
for the supplied pcmcia controller by poking in the registry
|
||
at the appropriate places
|
||
|
||
Arguments:
|
||
|
||
Pdo - The Physical device object corresponding to the PCMCIA controller
|
||
ControllerType - pointer to the object in which the controller type will
|
||
be returned
|
||
|
||
|
||
Return value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
UNICODE_STRING unicodeKeyName;
|
||
HANDLE instanceHandle=NULL;
|
||
HANDLE parametersHandle = NULL;
|
||
RTL_QUERY_REGISTRY_TABLE queryTable[3];
|
||
ULONG controllerType;
|
||
ULONG invalid = 0xffffffff;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
try {
|
||
status = IoOpenDeviceRegistryKey(Pdo,
|
||
PLUGPLAY_REGKEY_DEVICE,
|
||
KEY_READ,
|
||
&instanceHandle
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
leave;
|
||
}
|
||
|
||
RtlInitUnicodeString(&unicodeKeyName, PCMCIA_REGISTRY_DETECTED_DEVICE_KEY);
|
||
InitializeObjectAttributes(
|
||
&objectAttributes,
|
||
&unicodeKeyName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
instanceHandle,
|
||
NULL);
|
||
|
||
status = ZwOpenKey(¶metersHandle,
|
||
KEY_READ,
|
||
&objectAttributes);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
leave;
|
||
}
|
||
|
||
|
||
RtlZeroMemory(queryTable, sizeof(queryTable));
|
||
|
||
queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
||
queryTable[0].Name = L"ControllerType";
|
||
queryTable[0].EntryContext = &controllerType;
|
||
queryTable[0].DefaultType = REG_DWORD;
|
||
queryTable[0].DefaultData = &invalid;
|
||
queryTable[0].DefaultLength = sizeof(ULONG);
|
||
|
||
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
||
(PWSTR) parametersHandle,
|
||
queryTable,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
leave;
|
||
}
|
||
|
||
if (controllerType == invalid) {
|
||
*ControllerType = PcmciaIntelCompatible;
|
||
} else {
|
||
*ControllerType = (PCMCIA_CONTROLLER_TYPE) controllerType;
|
||
}
|
||
|
||
} finally {
|
||
|
||
if (instanceHandle != NULL) {
|
||
ZwClose(instanceHandle);
|
||
}
|
||
|
||
if (parametersHandle != NULL) {
|
||
ZwClose(parametersHandle);
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaSetLegacyDetectedControllerType(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PCMCIA_CONTROLLER_TYPE ControllerType
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine 'remembers' - by setting a value in the registry -
|
||
the type of the pcmcia controller that has been legacy detected
|
||
to be retrieved and used in subsequent boots - if legacy re-detection
|
||
of the controller is not performed
|
||
|
||
Arguments:
|
||
|
||
Pdo - The Physical device object corresponding to the PCMCIA controller
|
||
DeviceExtension - Device extension of the fdo corresponding to the
|
||
controller
|
||
|
||
Return value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
HANDLE instanceHandle;
|
||
NTSTATUS status;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
HANDLE parametersHandle;
|
||
UNICODE_STRING unicodeString;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Get a handle to the registry devnode for this pdo
|
||
//
|
||
|
||
status = IoOpenDeviceRegistryKey(Pdo,
|
||
PLUGPLAY_REGKEY_DEVICE,
|
||
KEY_CREATE_SUB_KEY,
|
||
&instanceHandle);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
|
||
//
|
||
// Open or create a sub-key for this devnode to store
|
||
// the information in
|
||
//
|
||
|
||
RtlInitUnicodeString(&unicodeString, PCMCIA_REGISTRY_DETECTED_DEVICE_KEY);
|
||
|
||
InitializeObjectAttributes(&objectAttributes,
|
||
&unicodeString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
instanceHandle,
|
||
NULL);
|
||
|
||
status = ZwCreateKey(¶metersHandle,
|
||
KEY_SET_VALUE,
|
||
&objectAttributes,
|
||
0,
|
||
NULL,
|
||
REG_OPTION_NON_VOLATILE,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ZwClose(instanceHandle);
|
||
return status;
|
||
}
|
||
//
|
||
// Set the controller type value in the registry
|
||
//
|
||
RtlInitUnicodeString(&unicodeString, L"ControllerType");
|
||
status = ZwSetValueKey(parametersHandle,
|
||
&unicodeString,
|
||
0,
|
||
REG_DWORD,
|
||
&ControllerType,
|
||
sizeof(ControllerType));
|
||
ZwClose(parametersHandle);
|
||
ZwClose(instanceHandle);
|
||
return status;
|
||
}
|
||
|