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.
1430 lines
41 KiB
1430 lines
41 KiB
|
|
/*++
|
|
|
|
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 pPcCardData = (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 = *pPcCardData;
|
|
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 (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 (EventDpcDelay > PCMCIA_MAX_EVENT_DPC_DELAY) {
|
|
EventDpcDelay = PCMCIA_MAX_EVENT_DPC_DELAY;
|
|
}
|
|
|
|
|
|
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->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;
|
|
}
|
|
|