|
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
PnpEisa.c
Abstract:
This file implements Eisa related code.
Author:
Shie-Lin Tzong (shielint)
Environment:
Kernel Mode.
Notes:
Revision History:
--*/
#include "pnpmgrp.h"
#pragma hdrstop
#ifdef POOL_TAGGING
#undef ExAllocatePool
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'iepP')
#endif
#define EISA_DEVICE_NODE_NAME L"EisaResources"
#define BUFFER_LENGTH 50
NTSTATUS EisaGetEisaDevicesResources ( OUT PCM_RESOURCE_LIST *ResourceList, OUT PULONG ResourceLength );
NTSTATUS EisaBuildSlotsResources ( IN ULONG SlotMasks, IN ULONG NumberMasks, OUT PCM_RESOURCE_LIST *Resource, OUT ULONG *Length );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, EisaBuildEisaDeviceNode)
#pragma alloc_text(INIT, EisaGetEisaDevicesResources)
#pragma alloc_text(INIT, EisaBuildSlotsResources)
#endif
NTSTATUS EisaBuildEisaDeviceNode ( VOID )
/*++
Routine Description:
This routine build an registry key to report eisa resources to arbiters.
Arguments:
None.
Return Value:
NTSTATUS code.
--*/
{ NTSTATUS status; ULONG disposition, tmpValue; WCHAR buffer[BUFFER_LENGTH];
UNICODE_STRING unicodeString; HANDLE rootHandle, deviceHandle, instanceHandle, logConfHandle;
PCM_RESOURCE_LIST resourceList; ULONG resourceLength;
status = EisaGetEisaDevicesResources(&resourceList, &resourceLength); if (!NT_SUCCESS(status) || resourceList == NULL) { return STATUS_UNSUCCESSFUL; }
PiWstrToUnicodeString(&unicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\Root"); status = IopOpenRegistryKeyEx( &rootHandle, NULL, &unicodeString, KEY_ALL_ACCESS );
if (!NT_SUCCESS(status)) { if (resourceList) { ExFreePool (resourceList); } return status; }
PiWstrToUnicodeString(&unicodeString, EISA_DEVICE_NODE_NAME); status = IopCreateRegistryKeyEx( &deviceHandle, rootHandle, &unicodeString, KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, NULL );
ZwClose(rootHandle); if (!NT_SUCCESS(status)) { if (resourceList) { ExFreePool (resourceList); } return status; }
PiWstrToUnicodeString( &unicodeString, L"0000" ); status = IopCreateRegistryKeyEx( &instanceHandle, deviceHandle, &unicodeString, KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, &disposition ); ZwClose(deviceHandle); if (NT_SUCCESS(status)) {
//
// If the key already exists because it was explicitly migrated
// during textmode setup, we should still consider it a "new key".
//
if (disposition != REG_CREATED_NEW_KEY) { PKEY_VALUE_FULL_INFORMATION keyValueInformation;
status = IopGetRegistryValue(instanceHandle, REGSTR_VALUE_MIGRATED, &keyValueInformation); if (NT_SUCCESS(status)) {
if ((keyValueInformation->Type == REG_DWORD) && (keyValueInformation->DataLength == sizeof(ULONG)) && ((*(PULONG)KEY_VALUE_DATA(keyValueInformation)) != 0)) { disposition = REG_CREATED_NEW_KEY; }
ExFreePool(keyValueInformation);
PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_MIGRATED); ZwDeleteValueKey(instanceHandle, &unicodeString); } }
if (disposition == REG_CREATED_NEW_KEY) {
PiWstrToUnicodeString( &unicodeString, L"DeviceDesc" ); wcsncpy(buffer, L"Device to report Eisa Slot Resources", sizeof(buffer) / sizeof(WCHAR)); buffer[(sizeof(buffer) / sizeof(WCHAR)) - 1] = UNICODE_NULL;
ZwSetValueKey(instanceHandle, &unicodeString, 0, REG_SZ, buffer, (ULONG)((wcslen(buffer) + 1) * sizeof(WCHAR)) );
PiWstrToUnicodeString( &unicodeString, L"HardwareID" ); RtlZeroMemory(buffer, BUFFER_LENGTH * sizeof(WCHAR)); wcsncpy(buffer, L"*Eisa_Resource_Device", sizeof(buffer) / sizeof(WCHAR)); buffer[(sizeof(buffer) / sizeof(WCHAR)) - 1] = UNICODE_NULL;
ZwSetValueKey(instanceHandle, &unicodeString, 0, REG_MULTI_SZ, buffer, (ULONG)((wcslen(buffer) + 2) * sizeof(WCHAR)) );
PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_CONFIG_FLAGS); tmpValue = 0; ZwSetValueKey(instanceHandle, &unicodeString, TITLE_INDEX_VALUE, REG_DWORD, &tmpValue, sizeof(tmpValue) );
}
PiWstrToUnicodeString( &unicodeString, REGSTR_KEY_LOGCONF ); status = IopCreateRegistryKeyEx( &logConfHandle, instanceHandle, &unicodeString, KEY_ALL_ACCESS, REG_OPTION_NON_VOLATILE, NULL ); ZwClose(instanceHandle); if (NT_SUCCESS(status)) { PiWstrToUnicodeString( &unicodeString, REGSTR_VAL_BOOTCONFIG );
status = ZwSetValueKey(logConfHandle, &unicodeString, 0, REG_RESOURCE_LIST, resourceList, resourceLength ); ZwClose(logConfHandle); } } if (resourceList) { ExFreePool (resourceList); } return status; }
NTSTATUS EisaGetEisaDevicesResources ( OUT PCM_RESOURCE_LIST *ResourceList, OUT PULONG ResourceLength )
/*++
Routine Description:
This routine builds a cm resource list for all the eisa slots.
Arguments:
None.
Return Value:
A CmResourceList.
--*/
{ NTSTATUS status = STATUS_SUCCESS; HANDLE handle; PKEY_VALUE_FULL_INFORMATION keyValueInformation; UNICODE_STRING unicodeString; ULONG slotMasks = 0, numberMasks = 0, i;
*ResourceList = NULL; *ResourceLength = 0;
//
// Open LocalMachine\Hardware\Description
//
//PiWstrToUnicodeString(&unicodeString, L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM\\EisaAdapter\\0");
PiWstrToUnicodeString(&unicodeString, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\EisaAdapter"); status = IopOpenRegistryKeyEx( &handle, NULL, &unicodeString, KEY_READ ); if (NT_SUCCESS(status)) { status = IopGetRegistryValue(handle, L"Configuration Data", &keyValueInformation ); if (NT_SUCCESS(status)) { PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor; PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDescriptor;
resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
if ((keyValueInformation->DataLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) && (resourceDescriptor->PartialResourceList.Count > 0) ) { LONG eisaInfoLength; PCM_EISA_SLOT_INFORMATION eisaInfo;
partialResourceDescriptor = resourceDescriptor->PartialResourceList.PartialDescriptors; if (partialResourceDescriptor->Type == CmResourceTypeDeviceSpecific) { eisaInfo = (PCM_EISA_SLOT_INFORMATION) ((PUCHAR)partialResourceDescriptor + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); eisaInfoLength = (LONG)partialResourceDescriptor->u.DeviceSpecificData.DataSize;
//
// Parse the eisa slot info to find the eisa slots with device installed.
//
for (i = 0; i < 0x10 && eisaInfoLength > 0; i++) { if (eisaInfo->ReturnCode == EISA_INVALID_SLOT) { break; } if (eisaInfo->ReturnCode != EISA_EMPTY_SLOT && (i != 0)) { slotMasks |= (1 << i); numberMasks++; } if (eisaInfo->ReturnCode == EISA_EMPTY_SLOT) { eisaInfoLength -= sizeof(CM_EISA_SLOT_INFORMATION); eisaInfo++; } else { eisaInfoLength -= sizeof(CM_EISA_SLOT_INFORMATION) + eisaInfo->NumberFunctions * sizeof(CM_EISA_FUNCTION_INFORMATION); eisaInfo = (PCM_EISA_SLOT_INFORMATION) ((PUCHAR)eisaInfo + eisaInfo->NumberFunctions * sizeof(CM_EISA_FUNCTION_INFORMATION) + sizeof(CM_EISA_SLOT_INFORMATION)); } }
if (slotMasks) { status = EisaBuildSlotsResources(slotMasks, numberMasks, ResourceList, ResourceLength); } }
} ExFreePool(keyValueInformation); } ZwClose(handle); } return status; }
NTSTATUS EisaBuildSlotsResources ( IN ULONG SlotMasks, IN ULONG NumberMasks, OUT PCM_RESOURCE_LIST *Resources, OUT ULONG *Length )
/*++
Routine Description:
This routine build a cm resource list for all the io resources used by the eisa devices.
Arguments:
SlotMask - a mask to indicate the valid eisa slot.
Return Value:
A pointer to a CM_RESOURCE_LIST.
--*/
{ PCM_RESOURCE_LIST resources = NULL; PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc; ULONG slot;
*Length = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (NumberMasks - 1); resources = ExAllocatePool(PagedPool, *Length); if (resources) { resources->Count = 1; resources->List[0].InterfaceType = Eisa; resources->List[0].BusNumber = 0; resources->List[0].PartialResourceList.Version = 0; resources->List[0].PartialResourceList.Revision = 0; resources->List[0].PartialResourceList.Count = NumberMasks; partialDesc = resources->List[0].PartialResourceList.PartialDescriptors; slot = 0; // ignore slot 0
while (SlotMasks) { SlotMasks >>= 1; slot++; if (SlotMasks & 1) { partialDesc->Type = CmResourceTypePort; partialDesc->ShareDisposition = CmResourceShareDeviceExclusive; partialDesc->Flags = CM_RESOURCE_PORT_16_BIT_DECODE + CM_RESOURCE_PORT_IO; partialDesc->u.Port.Start.LowPart = slot << 12; partialDesc->u.Port.Start.HighPart = 0; partialDesc->u.Port.Length = 0x1000; partialDesc++; } } *Resources = resources; return STATUS_SUCCESS; } else { return STATUS_NO_MEMORY; } }
|