/*++ 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\ 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<. 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; }