1635 lines
48 KiB
C
1635 lines
48 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1995 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
pnpsubs.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the plug-and-play initialization
|
|||
|
subroutines for the I/O system.
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Shie-Lin Tzong (shielint) 30-Jan-1995
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "iop.h"
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
|
|||
|
extern ULONG IopPeripheralCount[];
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopIsDuplicatedResourceLists(
|
|||
|
IN PCM_RESOURCE_LIST Configuration1,
|
|||
|
IN PCM_RESOURCE_LIST Configuration2
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopInitializeHardwareConfiguration(
|
|||
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopSetupConfigurationTree(
|
|||
|
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
|
|||
|
IN HANDLE Handle,
|
|||
|
IN PUNICODE_STRING ParentName,
|
|||
|
IN INTERFACE_TYPE InterfaceType,
|
|||
|
IN BUS_DATA_TYPE BusDataType,
|
|||
|
IN ULONG BusNumber
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopInitializeRegistryNode(
|
|||
|
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
|
|||
|
IN HANDLE EnumHandle,
|
|||
|
IN PUNICODE_STRING ParentKeyName,
|
|||
|
IN PUNICODE_STRING KeyName,
|
|||
|
IN ULONG Instance,
|
|||
|
IN INTERFACE_TYPE InterfaceType,
|
|||
|
IN BUS_DATA_TYPE BusDataType,
|
|||
|
IN ULONG BusNumber
|
|||
|
);
|
|||
|
|
|||
|
#endif // _PNP_POWER_
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopInitServiceEnumList (
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
#if 0
|
|||
|
BOOLEAN
|
|||
|
IopInitializeBusKey(
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PUNICODE_STRING KeyName,
|
|||
|
IN OUT PVOID WorkName
|
|||
|
);
|
|||
|
#endif
|
|||
|
BOOLEAN
|
|||
|
IopInitializeDeviceKey(
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PUNICODE_STRING KeyName,
|
|||
|
IN OUT PVOID WorkName
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopInitializeDeviceInstanceKey(
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PUNICODE_STRING KeyName,
|
|||
|
IN OUT PVOID WorkName
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#if _PNP_POWER_
|
|||
|
#pragma alloc_text(INIT, IopIsDuplicatedResourceLists)
|
|||
|
#pragma alloc_text(INIT, IopInitializeHardwareConfiguration)
|
|||
|
#pragma alloc_text(INIT, IopSetupConfigurationTree)
|
|||
|
#pragma alloc_text(INIT, IopInitializeRegistryNode)
|
|||
|
#endif // _PNP_POWER_
|
|||
|
#pragma alloc_text(INIT, IopInitServiceEnumList)
|
|||
|
#if 0
|
|||
|
#pragma alloc_text(INIT, IopInitializeBusKey)
|
|||
|
#endif
|
|||
|
#pragma alloc_text(INIT, IopInitializeDeviceKey)
|
|||
|
#pragma alloc_text(INIT, IopInitializeDeviceInstanceKey)
|
|||
|
#pragma alloc_text(INIT, IopInitializePlugPlayServices)
|
|||
|
#endif
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
BOOLEAN
|
|||
|
IopIsDuplicatedResourceLists(
|
|||
|
IN PCM_RESOURCE_LIST Configuration1,
|
|||
|
IN PCM_RESOURCE_LIST Configuration2
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine compares two set of resource lists to
|
|||
|
determine if they are exactly the same.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Configuration1 - Supplies a pointer to the first set of resource.
|
|||
|
|
|||
|
Configuration2 - Supplies a pointer to the second set of resource.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
returns TRUE if the two set of resources are the same;
|
|||
|
otherwise a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG resource1Size, resource2Size;
|
|||
|
BOOLEAN sameResource = FALSE;
|
|||
|
|
|||
|
resource1Size = IopDetermineResourceListSize(Configuration1);
|
|||
|
resource2Size = IopDetermineResourceListSize(Configuration2);
|
|||
|
if (resource1Size == resource2Size) {
|
|||
|
if (!memcmp(Configuration1, Configuration2, resource1Size)) {
|
|||
|
sameResource = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
return sameResource;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopInitializeHardwareConfiguration(
|
|||
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine creates \\Registry\Machine\Sysem\Enum\Root node in
|
|||
|
the registry and calls worker routine to put the hardware
|
|||
|
information detected by arc firmware/ntdetect to the Enum\Root
|
|||
|
branch.
|
|||
|
This routine and its worker routines use both pnp scratch buffer1
|
|||
|
and scratch buffer2.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LoaderBlock - supplies a pointer to the LoaderBlock passed in from the
|
|||
|
OS Loader.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
NTSTATUS code for sucess or reason of failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
HANDLE baseHandle;
|
|||
|
UNICODE_STRING unicodeName, rootName;
|
|||
|
PCONFIGURATION_COMPONENT_DATA currentEntry;
|
|||
|
PCONFIGURATION_COMPONENT component;
|
|||
|
INTERFACE_TYPE interfaceType;
|
|||
|
BUS_DATA_TYPE busDataType;
|
|||
|
ULONG busNumber, i;
|
|||
|
|
|||
|
unicodeName.Length = 0;
|
|||
|
unicodeName.MaximumLength = PNP_LARGE_SCRATCH_BUFFER_SIZE;
|
|||
|
unicodeName.Buffer = IopPnpScratchBuffer1;
|
|||
|
PiWstrToUnicodeString(&rootName, REGSTR_KEY_ROOTENUM);
|
|||
|
RtlAppendStringToString((PSTRING)&unicodeName,
|
|||
|
(PSTRING)&rootName);
|
|||
|
currentEntry = (PCONFIGURATION_COMPONENT_DATA)LoaderBlock->ConfigurationRoot;
|
|||
|
|
|||
|
if (currentEntry) {
|
|||
|
|
|||
|
//
|
|||
|
// Open\Create \\Registry\Machine\System\CurrentControlSet\Enum\Root and use the
|
|||
|
// returned handle as the BaseHandle to build the Arc keys.
|
|||
|
//
|
|||
|
|
|||
|
status = IopOpenRegistryKey(&baseHandle,
|
|||
|
NULL,
|
|||
|
&CmRegistryMachineSystemCurrentControlSetEnumRootName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
currentEntry = currentEntry->Child;
|
|||
|
|
|||
|
while (currentEntry != NULL) {
|
|||
|
|
|||
|
component = ¤tEntry->ComponentEntry;
|
|||
|
|
|||
|
//
|
|||
|
// We are only interested in isa, or internal bus component.
|
|||
|
// For other busses, they will be picked up by bus enumerators.
|
|||
|
//
|
|||
|
|
|||
|
if (component->Class == AdapterClass) {
|
|||
|
if (component->Type == MultiFunctionAdapter) {
|
|||
|
_strupr(component->Identifier);
|
|||
|
if (!strstr(component->Identifier, "PNP")) {
|
|||
|
if (!_stricmp(component->Identifier, "ISA")) {
|
|||
|
interfaceType = Isa;
|
|||
|
busNumber = 0;
|
|||
|
busDataType = MaximumBusDataType;
|
|||
|
} else if (!_stricmp(component->Identifier, "INTERNAL")) {
|
|||
|
interfaceType = Internal;
|
|||
|
busNumber = 0;
|
|||
|
busDataType = MaximumBusDataType;
|
|||
|
#if defined(_X86_)
|
|||
|
} else if (!_stricmp(component->Identifier, "MCA")) {
|
|||
|
interfaceType = MicroChannel;
|
|||
|
busNumber = 0;
|
|||
|
busDataType = Pos;
|
|||
|
#endif
|
|||
|
} else {
|
|||
|
currentEntry = currentEntry->Sibling;
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#if defined(_X86_)
|
|||
|
else if (component->Type == EisaAdapter) {
|
|||
|
interfaceType = Eisa;
|
|||
|
busNumber = 0;
|
|||
|
busDataType = EisaConfiguration;
|
|||
|
} else {
|
|||
|
currentEntry = currentEntry->Sibling;
|
|||
|
continue;
|
|||
|
}
|
|||
|
#endif
|
|||
|
#if 0
|
|||
|
//
|
|||
|
// Reset peripheral count before processing a bus.
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i <= MaximumType; i++) {
|
|||
|
IopPeripheralCount[i] = 0;
|
|||
|
}
|
|||
|
#endif
|
|||
|
status = IopSetupConfigurationTree(currentEntry->Child,
|
|||
|
baseHandle,
|
|||
|
&unicodeName,
|
|||
|
interfaceType,
|
|||
|
busDataType,
|
|||
|
busNumber
|
|||
|
);
|
|||
|
}
|
|||
|
currentEntry = currentEntry->Sibling;
|
|||
|
}
|
|||
|
NtClose(baseHandle);
|
|||
|
return(status);
|
|||
|
} else {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopSetupConfigurationTree(
|
|||
|
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
|
|||
|
IN HANDLE Handle,
|
|||
|
IN PUNICODE_STRING WorkName,
|
|||
|
IN INTERFACE_TYPE InterfaceType,
|
|||
|
IN BUS_DATA_TYPE BusDataType,
|
|||
|
IN ULONG BusNumber
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine traverses loader configuration tree and register
|
|||
|
desired hardware information to System\Enuk\Root registry data base.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CurrentEntry - Supplies a pointer to a loader configuration
|
|||
|
tree or subtree.
|
|||
|
|
|||
|
Handle - Supplies the handle to the registry where we can create new key.
|
|||
|
|
|||
|
WorkName - Supplies a pointer to a unicode string to specify the
|
|||
|
parent key name of current entry.
|
|||
|
|
|||
|
InterfaceType - Specify the Interface type of the bus that the
|
|||
|
CurrentEntry component resides.
|
|||
|
|
|||
|
BusDataType - Specify the data/configuration type of the bus that the
|
|||
|
CurrentEntry component resides.
|
|||
|
|
|||
|
BusNumber - Specify the Bus Number of the bus that the CurrentEntry
|
|||
|
component resides. If Bus number is -1, it means InterfaceType
|
|||
|
and BusNumber are meaningless for this component.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PCONFIGURATION_COMPONENT component;
|
|||
|
UNICODE_STRING keyName;
|
|||
|
UNICODE_STRING unicodeName;
|
|||
|
static ULONG peripheralCount = 0, controllerCount = 0;
|
|||
|
BOOLEAN freeKeyName = FALSE, nameMapped;
|
|||
|
// BUGBUG (shielint): initialize pnpId for now to avoid compiler warning.
|
|||
|
PWSTR pnpId = NULL;
|
|||
|
STRING stringName;
|
|||
|
USHORT namePosition;
|
|||
|
|
|||
|
//
|
|||
|
// Process current entry first
|
|||
|
//
|
|||
|
|
|||
|
if (CurrentEntry) {
|
|||
|
component = &CurrentEntry->ComponentEntry;
|
|||
|
nameMapped = FALSE;
|
|||
|
#if 0
|
|||
|
switch (component->Type) {
|
|||
|
case DiskController:
|
|||
|
pnpId = L"DiskController";
|
|||
|
break;
|
|||
|
case TapeController:
|
|||
|
pnpId = L"PNP0100";
|
|||
|
break;
|
|||
|
case CdromController:
|
|||
|
pnpId = L"PNP0200";
|
|||
|
break;
|
|||
|
case WormController:
|
|||
|
pnpId = L"PNP0300";
|
|||
|
break;
|
|||
|
case SerialController:
|
|||
|
pnpId = L"PNP0400";
|
|||
|
break;
|
|||
|
case NetworkController:
|
|||
|
pnpId = L"PNP0500";
|
|||
|
break;
|
|||
|
case DisplayController:
|
|||
|
pnpId = L"PNP0600";
|
|||
|
break;
|
|||
|
case ParallelController:
|
|||
|
pnpId = L"PNP0700";
|
|||
|
break;
|
|||
|
case PointerController:
|
|||
|
pnpId = L"PNP0800";
|
|||
|
break;
|
|||
|
case KeyboardController:
|
|||
|
pnpId = L"PNP0900";
|
|||
|
break;
|
|||
|
case AudioController:
|
|||
|
pnpId = L"PNP1000";
|
|||
|
break;
|
|||
|
case OtherController:
|
|||
|
pnpId = L"PNP1100";
|
|||
|
break;
|
|||
|
case DiskPeripheral:
|
|||
|
pnpId = L"PNP1200";
|
|||
|
break;
|
|||
|
case FloppyDiskPeripheral:
|
|||
|
pnpId = L"PNP1300";
|
|||
|
break;
|
|||
|
case TapePeripheral:
|
|||
|
pnpId = L"PNP1400";
|
|||
|
break;
|
|||
|
case ModemPeripheral:
|
|||
|
pnpId = L"PNP1500";
|
|||
|
break;
|
|||
|
case MonitorPeripheral:
|
|||
|
pnpId = L"PNP1600";
|
|||
|
break;
|
|||
|
case PrinterPeripheral:
|
|||
|
pnpId = L"PNP1700";
|
|||
|
break;
|
|||
|
case PointerPeripheral:
|
|||
|
pnpId = L"PNP1800";
|
|||
|
break;
|
|||
|
case KeyboardPeripheral:
|
|||
|
pnpId = L"PNP1900";
|
|||
|
break;
|
|||
|
case TerminalPeripheral:
|
|||
|
pnpId = L"PNP2000";
|
|||
|
break;
|
|||
|
case OtherPeripheral:
|
|||
|
pnpId = L"PNP2100";
|
|||
|
break;
|
|||
|
case LinePeripheral:
|
|||
|
pnpId = L"PNP2200";
|
|||
|
break;
|
|||
|
case NetworkPeripheral:
|
|||
|
pnpId = L"PNP2300";
|
|||
|
break;
|
|||
|
}
|
|||
|
#endif
|
|||
|
//
|
|||
|
// if we did NOT successfully mapped a PNP id for the component, we
|
|||
|
// will create a special key name and the key will be processed by
|
|||
|
// user mode inf file later.
|
|||
|
//
|
|||
|
|
|||
|
if (nameMapped) {
|
|||
|
RtlCreateUnicodeString(&keyName, pnpId);
|
|||
|
} else {
|
|||
|
RtlInitUnicodeString(&unicodeName, L"Arc");
|
|||
|
IopConcatenateUnicodeStrings(&keyName,
|
|||
|
&unicodeName,
|
|||
|
&CmTypeName[component->Type]);
|
|||
|
freeKeyName = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize and copy current component to Enum\Root if it is
|
|||
|
// the one we're insterested in.
|
|||
|
//
|
|||
|
|
|||
|
namePosition = WorkName->Length;
|
|||
|
status = IopInitializeRegistryNode(
|
|||
|
CurrentEntry,
|
|||
|
Handle,
|
|||
|
WorkName,
|
|||
|
&keyName,
|
|||
|
IopPeripheralCount[component->Type]++,
|
|||
|
InterfaceType,
|
|||
|
BusDataType,
|
|||
|
BusNumber
|
|||
|
);
|
|||
|
|
|||
|
if (freeKeyName) {
|
|||
|
RtlFreeUnicodeString(&keyName);
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Process the child entry of current entry
|
|||
|
//
|
|||
|
|
|||
|
status = IopSetupConfigurationTree(CurrentEntry->Child,
|
|||
|
Handle,
|
|||
|
WorkName,
|
|||
|
InterfaceType,
|
|||
|
BusDataType,
|
|||
|
BusNumber
|
|||
|
);
|
|||
|
|
|||
|
WorkName->Length = namePosition;
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Process all the Siblings of current entry
|
|||
|
//
|
|||
|
|
|||
|
status = IopSetupConfigurationTree(CurrentEntry->Sibling,
|
|||
|
Handle,
|
|||
|
WorkName,
|
|||
|
InterfaceType,
|
|||
|
BusDataType,
|
|||
|
BusNumber
|
|||
|
);
|
|||
|
|
|||
|
return(status);
|
|||
|
} else {
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopInitializeRegistryNode(
|
|||
|
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
|
|||
|
IN HANDLE EnumRootHandle,
|
|||
|
IN PUNICODE_STRING WorkName,
|
|||
|
IN PUNICODE_STRING KeyName,
|
|||
|
IN ULONG Instance,
|
|||
|
IN INTERFACE_TYPE InterfaceType,
|
|||
|
IN BUS_DATA_TYPE BusDataType,
|
|||
|
IN ULONG BusNumber
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine creates a node for the current firmware component
|
|||
|
and puts component data to the data part of the node.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CurrentEntry - Supplies a pointer to a configuration component.
|
|||
|
|
|||
|
EnumRootHandle - Supplies the handle of Enum key under which we will build
|
|||
|
our new key.
|
|||
|
|
|||
|
WorkName - Supplies a point to a unicode string which is the name of
|
|||
|
its parent node.
|
|||
|
|
|||
|
KeyName - Suppiles a pointer to a UNICODE string which will be the name
|
|||
|
of the new key.
|
|||
|
|
|||
|
Instance - Supplies an instance number of KeyName.
|
|||
|
|
|||
|
InterfaceType - Specify the Interface type of the bus that the
|
|||
|
CurrentEntry component resides. (See BusNumber also)
|
|||
|
|
|||
|
BusDataType - Specifies the configuration type of the bus.
|
|||
|
|
|||
|
BusNumber - Specify the Bus Number of the bus that the CurrentEntry
|
|||
|
component resides on. If Bus number is -1, it means InterfaceType
|
|||
|
and BusNumber are meaningless for this component.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS status;
|
|||
|
HANDLE handle, keyHandle;
|
|||
|
UNICODE_STRING unicodeName, unicodeValueName;
|
|||
|
PCONFIGURATION_COMPONENT component;
|
|||
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation, serviceInfo = NULL;
|
|||
|
PWSTR service = (PWSTR)NULL, p;
|
|||
|
ULONG disposition, foundAlready, dataLength = 0;
|
|||
|
ULONG serviceLength = 0, tmpValue, emptyResource = 0;
|
|||
|
BOOLEAN newKey = FALSE;
|
|||
|
PCM_RESOURCE_LIST dataArea, configuration1;
|
|||
|
CHAR unicodeBuffer[20];
|
|||
|
PUCHAR resourceBuffer = IopPnpScratchBuffer2;
|
|||
|
BOOLEAN freeDataArea = FALSE, isDuplicated;
|
|||
|
|
|||
|
component = &CurrentEntry->ComponentEntry;
|
|||
|
|
|||
|
//
|
|||
|
// Open/Create a key under Enum/Root bransh. If fails,
|
|||
|
// exit (nothing we can do.)
|
|||
|
//
|
|||
|
|
|||
|
status = IopOpenRegistryKeyPersist (
|
|||
|
&keyHandle,
|
|||
|
EnumRootHandle,
|
|||
|
KeyName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
&disposition
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
#if 0 // not sure if we need it
|
|||
|
|
|||
|
//
|
|||
|
// If the key is newly created, set its NewDevice value to TRUE so that
|
|||
|
// user mode Pnp mgr can initiate a device installation. The NewDevice
|
|||
|
// value will be reset by user mode Pnp mgr. SO , we don't touch it here.
|
|||
|
//
|
|||
|
|
|||
|
if (disposition == REG_CREATED_NEW_KEY) {
|
|||
|
newKey = TRUE;
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_NEWDEVICE);
|
|||
|
tmpValue = 1;
|
|||
|
NtSetValueKey(
|
|||
|
keyHandle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof (tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_STATIC);
|
|||
|
NtSetValueKey(
|
|||
|
keyHandle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
if (component->Type > OtherController) {
|
|||
|
|
|||
|
//
|
|||
|
// The current component is a peripheral.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Create a new instance key under KeyName
|
|||
|
//
|
|||
|
|
|||
|
PiUlongToInstanceKeyUnicodeString(&unicodeName, unicodeBuffer, 20, Instance);
|
|||
|
status = IopOpenRegistryKeyPersist (
|
|||
|
&handle,
|
|||
|
keyHandle,
|
|||
|
&unicodeName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
&disposition
|
|||
|
);
|
|||
|
NtClose(keyHandle);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto init_Exit;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Create all the default value entry for the newly created key.
|
|||
|
// Service = (do NOT create)
|
|||
|
// BaseDevicePath = WorkName
|
|||
|
// FoundAtEnum = 1
|
|||
|
// InterfaceType = InterfaceType (only for bus device)
|
|||
|
// SystemBusNumber = BusNumber (only for bus device)
|
|||
|
// BusDataType = BusDataType (only for bus device)
|
|||
|
//
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_BASEDEVICEPATH);
|
|||
|
p = WorkName->Buffer;
|
|||
|
p += WorkName->Length / sizeof(WCHAR);
|
|||
|
*p = UNICODE_NULL;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_SZ,
|
|||
|
WorkName->Buffer,
|
|||
|
WorkName->Length + sizeof (UNICODE_NULL)
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_FOUNDATENUM);
|
|||
|
tmpValue = 1;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_SYSTEMBUSNUMBER);
|
|||
|
tmpValue = BusNumber;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_INTERFACETYPE);
|
|||
|
tmpValue = InterfaceType;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_BUSDATATYPE);
|
|||
|
tmpValue = BusDataType;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
NtClose(handle);
|
|||
|
|
|||
|
//
|
|||
|
// Append keyanme and instance key name to workname
|
|||
|
// (In fact, we don't need to do this because there
|
|||
|
// is nothing under peripheral component.)
|
|||
|
//
|
|||
|
//
|
|||
|
// Append KeyName to workname
|
|||
|
//
|
|||
|
|
|||
|
p = WorkName->Buffer;
|
|||
|
p += WorkName->Length / sizeof(WCHAR);
|
|||
|
*p = OBJ_NAME_PATH_SEPARATOR;
|
|||
|
WorkName->Length += sizeof (WCHAR);
|
|||
|
RtlAppendStringToString((PSTRING)WorkName,
|
|||
|
(PSTRING)KeyName);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Current component is a controller
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Append KeyName to workname
|
|||
|
//
|
|||
|
|
|||
|
p = WorkName->Buffer;
|
|||
|
p += WorkName->Length / sizeof(WCHAR);
|
|||
|
*p = OBJ_NAME_PATH_SEPARATOR;
|
|||
|
WorkName->Length += sizeof (WCHAR);
|
|||
|
RtlAppendStringToString((PSTRING)WorkName,
|
|||
|
(PSTRING)KeyName);
|
|||
|
|
|||
|
//
|
|||
|
// We need to convert the h/w tree configuration data format from
|
|||
|
// CM_PARTIAL_RESOURCE_DESCRIPTIOR to CM_RESOURCE_LIST.
|
|||
|
//
|
|||
|
|
|||
|
if (CurrentEntry->ConfigurationData) {
|
|||
|
|
|||
|
//
|
|||
|
// This component has configuration data, we copy the data
|
|||
|
// to our work area, add some more data items and copy the new
|
|||
|
// configuration data to the registry.
|
|||
|
//
|
|||
|
|
|||
|
dataLength = component->ConfigurationDataLength +
|
|||
|
FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
|
|||
|
PartialResourceList) +
|
|||
|
FIELD_OFFSET(CM_RESOURCE_LIST, List);
|
|||
|
dataArea = (PCM_RESOURCE_LIST)resourceBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure our reserved area is big enough to hold the data.
|
|||
|
//
|
|||
|
|
|||
|
if (dataLength > PNP_LARGE_SCRATCH_BUFFER_SIZE) {
|
|||
|
|
|||
|
//
|
|||
|
// If reserved area is not big enough, we resize our reserved
|
|||
|
// area. If, unfortunately, the reallocation fails, we simply
|
|||
|
// loss the configuration data of this particular component.
|
|||
|
//
|
|||
|
|
|||
|
dataArea = (PCM_RESOURCE_LIST)ExAllocatePool(
|
|||
|
PagedPool,
|
|||
|
dataLength
|
|||
|
);
|
|||
|
|
|||
|
if (dataArea) {
|
|||
|
freeDataArea = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
if (dataArea) {
|
|||
|
RtlMoveMemory((PUCHAR)&dataArea->List->PartialResourceList.Version,
|
|||
|
CurrentEntry->ConfigurationData,
|
|||
|
component->ConfigurationDataLength
|
|||
|
);
|
|||
|
dataArea->Count = 1;
|
|||
|
dataArea->List[0].InterfaceType = InterfaceType;
|
|||
|
dataArea->List[0].BusNumber = BusNumber;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (CurrentEntry->ConfigurationData == NULL || !dataArea) {
|
|||
|
|
|||
|
//
|
|||
|
// This component has NO configuration data (or we can't resize
|
|||
|
// our reserved area to hold the data), we simple add whatever
|
|||
|
// is required to set up a CM_FULL_RESOURCE_LIST.
|
|||
|
//
|
|||
|
|
|||
|
dataArea = (PCM_RESOURCE_LIST)&emptyResource;
|
|||
|
dataLength = FIELD_OFFSET(CM_RESOURCE_LIST, List);
|
|||
|
}
|
|||
|
|
|||
|
if (!newKey) {
|
|||
|
|
|||
|
//
|
|||
|
// If the key exists already, we need to check if current entry
|
|||
|
// already being converted (most likely the answer is yes.). If it already
|
|||
|
// converted, we simply set "FoundAtEnum=" to TRUE. Otherwise, we will
|
|||
|
// create it.
|
|||
|
//
|
|||
|
|
|||
|
tmpValue = 0;
|
|||
|
PiUlongToInstanceKeyUnicodeString(&unicodeName, unicodeBuffer, 20, tmpValue);
|
|||
|
status = IopOpenRegistryKey (&handle,
|
|||
|
keyHandle,
|
|||
|
&unicodeName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
while (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// if the current key has been Found/Enum'ed already, we need
|
|||
|
// to skip it.
|
|||
|
//
|
|||
|
|
|||
|
foundAlready = 0;
|
|||
|
status = IopGetRegistryValue (handle,
|
|||
|
REGSTR_VALUE_FOUNDATENUM,
|
|||
|
&keyValueInformation);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if (keyValueInformation->DataLength != 0) {
|
|||
|
foundAlready = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
|
|||
|
if (!foundAlready) {
|
|||
|
keyValueInformation = NULL;
|
|||
|
status = IopGetRegistryValue (handle,
|
|||
|
REGSTR_VALUE_DETECTSIGNATURE,
|
|||
|
&keyValueInformation);
|
|||
|
if (NT_SUCCESS(status) && keyValueInformation->DataLength != 0) {
|
|||
|
configuration1 = (PCM_RESOURCE_LIST)KEY_VALUE_DATA(keyValueInformation);
|
|||
|
} else if (status == STATUS_OBJECT_NAME_NOT_FOUND ||
|
|||
|
keyValueInformation->DataLength == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// If no "DetectSignature =" value entry, we set up an empty
|
|||
|
// CM_RESOURCE_LIST.
|
|||
|
//
|
|||
|
|
|||
|
configuration1 = (PCM_RESOURCE_LIST)&emptyResource;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// To detect ARC duplicated components, we should be able
|
|||
|
// to simply compare the RAW resource list. If they are the
|
|||
|
// same *most likely* they are duplicates. This includes
|
|||
|
// the case that both resource list are empty. (if they
|
|||
|
// are empty, we should be able to simply pick up the
|
|||
|
// key and use it.)
|
|||
|
//
|
|||
|
|
|||
|
isDuplicated = IopIsDuplicatedResourceLists(
|
|||
|
configuration1,
|
|||
|
dataArea);
|
|||
|
if (!isDuplicated) {
|
|||
|
|
|||
|
//
|
|||
|
// BUGBUG We should also check for bus info.
|
|||
|
//
|
|||
|
|
|||
|
isDuplicated = IopIsDuplicatedDevices(
|
|||
|
configuration1,
|
|||
|
dataArea,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (keyValueInformation) {
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
if (isDuplicated) {
|
|||
|
PiWstrToUnicodeString( &unicodeValueName, REGSTR_VALUE_FOUNDATENUM);
|
|||
|
tmpValue = 1;
|
|||
|
status = NtSetValueKey(handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
NtClose(handle);
|
|||
|
NtClose(keyHandle);
|
|||
|
goto init_Exit0;
|
|||
|
}
|
|||
|
}
|
|||
|
NtClose(handle);
|
|||
|
tmpValue++;
|
|||
|
PiUlongToInstanceKeyUnicodeString(&unicodeName,
|
|||
|
unicodeBuffer,
|
|||
|
20,
|
|||
|
tmpValue);
|
|||
|
status = IopOpenRegistryKey (&handle,
|
|||
|
keyHandle,
|
|||
|
&unicodeName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
Instance = tmpValue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We need to create the new instance key if we can come here...
|
|||
|
//
|
|||
|
|
|||
|
PiUlongToInstanceKeyUnicodeString(&unicodeName, unicodeBuffer, 20, Instance);
|
|||
|
status = IopOpenRegistryKeyPersist (
|
|||
|
&handle,
|
|||
|
keyHandle,
|
|||
|
&unicodeName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtClose(keyHandle);
|
|||
|
PNP_ASSERT(NT_SUCCESS(status), "IopInitRegistryNode: Fail to create new key.");
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto init_Exit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Newly created key --
|
|||
|
//
|
|||
|
// Create all the default value entry for the newly created key.
|
|||
|
// Service =
|
|||
|
#if 0
|
|||
|
// NewInstance = 1
|
|||
|
#endif
|
|||
|
// FoundAtEnum = 1
|
|||
|
// Configuration =
|
|||
|
// InterfaceType = InterfaceType
|
|||
|
// SystemBusNumber = BusNumber
|
|||
|
// BusDataType = BusDataType
|
|||
|
//
|
|||
|
|
|||
|
#if 0
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_NEWINSTANCE);
|
|||
|
tmpValue = 1;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
#endif
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_FOUNDATENUM);
|
|||
|
tmpValue = 1;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
#if 0
|
|||
|
|
|||
|
//
|
|||
|
// SystemBusNumber, InterfaceType and BusDataType are for Bus
|
|||
|
// devices only. For ntdetect/arc detected devices, we don't set
|
|||
|
// up bus devices.
|
|||
|
//
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_SYSTEMBUSNUMBER);
|
|||
|
tmpValue = BusNumber;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_INTERFACETYPE);
|
|||
|
tmpValue = InterfaceType;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_BUSDATATYPE);
|
|||
|
tmpValue = BusDataType;
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
#endif
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_CONFIGURATION);
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_RESOURCE_LIST,
|
|||
|
dataArea,
|
|||
|
dataLength
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_DETECTSIGNATURE);
|
|||
|
NtSetValueKey(
|
|||
|
handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_RESOURCE_LIST,
|
|||
|
dataArea,
|
|||
|
dataLength
|
|||
|
);
|
|||
|
NtClose(handle);
|
|||
|
}
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
init_Exit0:
|
|||
|
p = WorkName->Buffer;
|
|||
|
p += WorkName->Length / sizeof(WCHAR);
|
|||
|
*p = OBJ_NAME_PATH_SEPARATOR;
|
|||
|
WorkName->Length += sizeof (WCHAR);
|
|||
|
RtlAppendStringToString((PSTRING)WorkName,
|
|||
|
(PSTRING)&unicodeName);
|
|||
|
init_Exit:
|
|||
|
if (freeDataArea) {
|
|||
|
ExFreePool(dataArea);
|
|||
|
}
|
|||
|
if (serviceInfo) {
|
|||
|
ExFreePool(serviceInfo);
|
|||
|
}
|
|||
|
return(status);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#endif // _PNP_POWER_
|
|||
|
NTSTATUS
|
|||
|
IopInitServiceEnumList (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine scans through System\Enum\Root subtree and assigns device
|
|||
|
instances to their corresponding Service\name\Enum\Root entries. Basically,
|
|||
|
this routine establishes the Enum branches of service list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the final status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
HANDLE baseHandle;
|
|||
|
UNICODE_STRING workName, tmpName;
|
|||
|
|
|||
|
//
|
|||
|
// Open System\CurrentControlSet\Enum key and call worker routine to recursively
|
|||
|
// scan through the subkeys.
|
|||
|
//
|
|||
|
|
|||
|
status = IopOpenRegistryKeyPersist(&baseHandle,
|
|||
|
NULL,
|
|||
|
&CmRegistryMachineSystemCurrentControlSetEnumRootName,
|
|||
|
KEY_READ,
|
|||
|
TRUE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
workName.Buffer = (PWSTR)IopPnpScratchBuffer1;
|
|||
|
RtlFillMemory((PUCHAR)IopPnpScratchBuffer1, PNP_LARGE_SCRATCH_BUFFER_SIZE, 0);
|
|||
|
workName.MaximumLength = PNP_LARGE_SCRATCH_BUFFER_SIZE;
|
|||
|
workName.Length = 0;
|
|||
|
#if 1 // only look at ROOT key
|
|||
|
PiWstrToUnicodeString(&tmpName, REGSTR_KEY_ROOTENUM);
|
|||
|
RtlAppendStringToString((PSTRING)&workName, (PSTRING)&tmpName);
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Enumerate all subkeys under the System\CCS\Enum\Root.
|
|||
|
//
|
|||
|
|
|||
|
status = IopApplyFunctionToSubKeys(baseHandle,
|
|||
|
NULL,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
#if 0
|
|||
|
IopInitializeBusKey,
|
|||
|
#else
|
|||
|
IopInitializeDeviceKey,
|
|||
|
#endif
|
|||
|
&workName
|
|||
|
);
|
|||
|
NtClose(baseHandle);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
#if 0
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopInitializeBusKey(
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PUNICODE_STRING KeyName,
|
|||
|
IN OUT PVOID WorkName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is a callback function for IopApplyFunctionToSubKeys.
|
|||
|
It is called for each subkey under HKLM\System\Enum.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
KeyHandle - Supplies a handle to this key.
|
|||
|
|
|||
|
KeyName - Supplies the name of this key.
|
|||
|
|
|||
|
WorkName - points to the unicodestring which describes the path up to
|
|||
|
this key.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
TRUE to continue the enumeration.
|
|||
|
FALSE to abort it.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
USHORT length;
|
|||
|
PWSTR p;
|
|||
|
PUNICODE_STRING unicodeName = WorkName;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
length = unicodeName->Length;
|
|||
|
|
|||
|
p = unicodeName->Buffer;
|
|||
|
if ( unicodeName->Length / sizeof(WCHAR) != 0) {
|
|||
|
p += unicodeName->Length / sizeof(WCHAR);
|
|||
|
*p = OBJ_NAME_PATH_SEPARATOR;
|
|||
|
unicodeName->Length += sizeof (WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
RtlAppendStringToString((PSTRING)unicodeName, (PSTRING)KeyName);
|
|||
|
|
|||
|
//
|
|||
|
// Enumerate all subkeys under the System\Enum.
|
|||
|
//
|
|||
|
|
|||
|
status = IopApplyFunctionToSubKeys(KeyHandle,
|
|||
|
NULL,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
IopInitializeDeviceKey,
|
|||
|
WorkName
|
|||
|
);
|
|||
|
unicodeName->Length = length; // Should be zero
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
#endif // 0
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopInitializeDeviceKey(
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PUNICODE_STRING KeyName,
|
|||
|
IN OUT PVOID WorkName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is a callback function for IopApplyFunctionToSubKeys.
|
|||
|
It is called for each subkey under HKLM\System\CCS\Enum\BusKey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
KeyHandle - Supplies a handle to this key.
|
|||
|
|
|||
|
KeyName - Supplies the name of this key.
|
|||
|
|
|||
|
WorkName - points to the unicodestring which describes the path up to
|
|||
|
this key.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
TRUE to continue the enumeration.
|
|||
|
FALSE to abort it.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
USHORT length;
|
|||
|
PWSTR p;
|
|||
|
PUNICODE_STRING unicodeName = WorkName;
|
|||
|
|
|||
|
length = unicodeName->Length;
|
|||
|
|
|||
|
p = unicodeName->Buffer;
|
|||
|
if ( unicodeName->Length / sizeof(WCHAR) != 0) {
|
|||
|
p += unicodeName->Length / sizeof(WCHAR);
|
|||
|
*p = OBJ_NAME_PATH_SEPARATOR;
|
|||
|
unicodeName->Length += sizeof (WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
RtlAppendStringToString((PSTRING)unicodeName, (PSTRING)KeyName);
|
|||
|
|
|||
|
//
|
|||
|
// Enumerate all subkeys under the current device key.
|
|||
|
//
|
|||
|
|
|||
|
IopApplyFunctionToSubKeys(KeyHandle,
|
|||
|
NULL,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
IopInitializeDeviceInstanceKey,
|
|||
|
WorkName
|
|||
|
);
|
|||
|
unicodeName->Length = length;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopInitializeDeviceInstanceKey(
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PUNICODE_STRING KeyName,
|
|||
|
IN OUT PVOID WorkName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is a callback function for IopApplyFunctionToSubKeys.
|
|||
|
It is called for each subkey under HKLM\System\Enum\BusKey\DeviceKey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
KeyHandle - Supplies a handle to this key.
|
|||
|
|
|||
|
KeyName - Supplies the name of this key.
|
|||
|
|
|||
|
WorkName - points to the unicodestring which describes the path up to
|
|||
|
this key.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
TRUE to continue the enumeration.
|
|||
|
FALSE to abort it.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UNICODE_STRING unicodeName, serviceName;
|
|||
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|||
|
NTSTATUS status;
|
|||
|
BOOLEAN duplicate = FALSE;
|
|||
|
ULONG foundAtEnum, deviceFlags, instance, tmpValue1, tmpValue2;
|
|||
|
USHORT length;
|
|||
|
PUNICODE_STRING pUnicode;
|
|||
|
|
|||
|
//
|
|||
|
// Get the "Problem" value entry to determine what we need to do with
|
|||
|
// the device instance key.
|
|||
|
//
|
|||
|
|
|||
|
deviceFlags = 0;
|
|||
|
status = IopGetRegistryValue ( KeyHandle,
|
|||
|
REGSTR_VALUE_PROBLEM,
|
|||
|
&keyValueInformation
|
|||
|
);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if ((keyValueInformation->Type == REG_DWORD) &&
|
|||
|
(keyValueInformation->DataLength >= sizeof(ULONG))) {
|
|||
|
deviceFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
|
|||
|
if (deviceFlags == CM_PROB_MOVED) {
|
|||
|
|
|||
|
//
|
|||
|
// If the device instance was moved, we simply delete the key.
|
|||
|
// The key will be deleted once the caller close the open handle.
|
|||
|
//
|
|||
|
|
|||
|
NtDeleteKey(KeyHandle);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The device instance key exists. We need to propagate the ConfigFlag
|
|||
|
// to problem and StatusFlags
|
|||
|
//
|
|||
|
|
|||
|
deviceFlags = 0;
|
|||
|
status = IopGetRegistryValue(KeyHandle,
|
|||
|
REGSTR_VALUE_CONFIG_FLAGS,
|
|||
|
&keyValueInformation);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if ((keyValueInformation->Type == REG_DWORD) &&
|
|||
|
(keyValueInformation->DataLength >= sizeof(ULONG))) {
|
|||
|
deviceFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
if (deviceFlags & CONFIGFLAG_REINSTALL) {
|
|||
|
|
|||
|
tmpValue1 = CM_PROB_REINSTALL; // Problem
|
|||
|
tmpValue2 = DN_HAS_PROBLEM; // StatusFlags
|
|||
|
} else {
|
|||
|
tmpValue1 = tmpValue2 = 0;
|
|||
|
}
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_PROBLEM);
|
|||
|
NtSetValueKey(KeyHandle,
|
|||
|
&unicodeName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue1,
|
|||
|
sizeof(tmpValue1)
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_STATUSFLAGS);
|
|||
|
NtSetValueKey(KeyHandle,
|
|||
|
&unicodeName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue2,
|
|||
|
sizeof(tmpValue2)
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Get the "DuplicateOf" value entry to determine if the device instance
|
|||
|
// should be registered. If the device instance is duplicate, We don't
|
|||
|
// add it to its service key's enum branch.
|
|||
|
//
|
|||
|
|
|||
|
status = IopGetRegistryValue ( KeyHandle,
|
|||
|
REGSTR_VALUE_DUPLICATEOF,
|
|||
|
&keyValueInformation
|
|||
|
);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if ((keyValueInformation->Type == REG_SZ) &&
|
|||
|
(keyValueInformation->DataLength > 0)) {
|
|||
|
duplicate = TRUE;
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
|
|||
|
if (!duplicate) {
|
|||
|
|
|||
|
//
|
|||
|
// Combine WorkName and KeyName to form device instance path
|
|||
|
// and register this device instance by
|
|||
|
// constructing new value entry for ServiceKeyName\Enum key.
|
|||
|
// i.e., <Number> = <PathToSystemEnumBranch>
|
|||
|
//
|
|||
|
|
|||
|
pUnicode = (PUNICODE_STRING)WorkName;
|
|||
|
length = pUnicode->Length; // Save WorkName
|
|||
|
if (pUnicode->Buffer[pUnicode->Length / sizeof(WCHAR) - 1] != OBJ_NAME_PATH_SEPARATOR) {
|
|||
|
pUnicode->Buffer[pUnicode->Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
|
|||
|
pUnicode->Length += 2;
|
|||
|
}
|
|||
|
RtlAppendStringToString((PSTRING)pUnicode, (PSTRING)KeyName);
|
|||
|
PpDeviceRegistration(pUnicode, TRUE);
|
|||
|
pUnicode->Length = length; // Restore WorkName
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the "Service=" value entry from KeyHandle
|
|||
|
//
|
|||
|
|
|||
|
keyValueInformation = NULL;
|
|||
|
serviceName.Length = 0;
|
|||
|
status = IopGetRegistryValue ( KeyHandle,
|
|||
|
REGSTR_VALUE_SERVICE,
|
|||
|
&keyValueInformation
|
|||
|
);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Append the new instance to its corresponding
|
|||
|
// Service\Name\Enum.
|
|||
|
//
|
|||
|
|
|||
|
if ((keyValueInformation->Type == REG_SZ) &&
|
|||
|
(keyValueInformation->DataLength != 0)) {
|
|||
|
|
|||
|
//
|
|||
|
// Set up ServiceKeyName unicode string
|
|||
|
//
|
|||
|
|
|||
|
IopRegistryDataToUnicodeString(
|
|||
|
&serviceName,
|
|||
|
(PWSTR)KEY_VALUE_DATA(keyValueInformation),
|
|||
|
keyValueInformation->DataLength
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do not Free keyValueInformation
|
|||
|
//
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The Pnp mgr set FoundAtEnum to 0 for everything under system\ccs\enum.
|
|||
|
// For the stuff under Root we need to set them to 1 except if their
|
|||
|
// CsConfigFlags was set to CSCONFIGFLAG_DO_NOT_CREATE.
|
|||
|
//
|
|||
|
|
|||
|
foundAtEnum = 1;
|
|||
|
status = RtlUnicodeStringToInteger(KeyName, 10, &instance);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if (serviceName.Length != 0) {
|
|||
|
status = IopGetDeviceInstanceCsConfigFlags(
|
|||
|
&serviceName,
|
|||
|
instance,
|
|||
|
&deviceFlags
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(status) && (deviceFlags & CSCONFIGFLAG_DO_NOT_CREATE)) {
|
|||
|
foundAtEnum = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (keyValueInformation) {
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_FOUNDATENUM);
|
|||
|
NtSetValueKey(KeyHandle,
|
|||
|
&unicodeName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&foundAtEnum,
|
|||
|
sizeof(foundAtEnum)
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Clean up "NtLogicalDevicePaths=" and "NtPhysicalDevicePaths=" of this key
|
|||
|
//
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_NT_PHYSICAL_DEVICE_PATHS);
|
|||
|
NtDeleteValueKey(KeyHandle, &unicodeName);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_NT_LOGICAL_DEVICE_PATHS);
|
|||
|
NtDeleteValueKey(KeyHandle, &unicodeName);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopInitializePlugPlayServices(
|
|||
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine initializes kernel mode Plug and Play services.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LoaderBlock - supplies a pointer to the LoaderBlock passed in from the
|
|||
|
OS Loader.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
NTSTATUS code for sucess or reason of failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
HANDLE hTreeHandle, parentHandle, handle;
|
|||
|
UNICODE_STRING unicodeName;
|
|||
|
ULONG foundAtEnum;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate two one-page scratch buffers to be used by our
|
|||
|
// initialization code. This avoids constant pool allocations.
|
|||
|
//
|
|||
|
|
|||
|
IopPnpScratchBuffer1 = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE);
|
|||
|
if (!IopPnpScratchBuffer1) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
IopPnpScratchBuffer2 = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE);
|
|||
|
if (!IopPnpScratchBuffer2) {
|
|||
|
ExFreePool(IopPnpScratchBuffer1);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Next open/create System\CurrentControlSet\Enum\Root key.
|
|||
|
//
|
|||
|
|
|||
|
status = IopOpenRegistryKey (
|
|||
|
&parentHandle,
|
|||
|
NULL,
|
|||
|
&CmRegistryMachineSystemCurrentControlSet,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto init_Exit;
|
|||
|
}
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_ENUM);
|
|||
|
status = IopOpenRegistryKeyPersist (
|
|||
|
&handle,
|
|||
|
parentHandle,
|
|||
|
&unicodeName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtClose(parentHandle);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto init_Exit;
|
|||
|
}
|
|||
|
|
|||
|
parentHandle = handle;
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_ROOTENUM);
|
|||
|
status = IopOpenRegistryKeyPersist (
|
|||
|
&handle,
|
|||
|
parentHandle,
|
|||
|
&unicodeName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtClose(parentHandle);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto init_Exit;
|
|||
|
}
|
|||
|
NtClose(handle);
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
|
|||
|
//
|
|||
|
// Convert Hardware/Firmware tree to Pnp required format.
|
|||
|
//
|
|||
|
|
|||
|
status = IopInitializeHardwareConfiguration(LoaderBlock);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto init_Exit;
|
|||
|
}
|
|||
|
#endif // _PNP_POWER_
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the FoundAtEnum= value entry to 1 for HTREE\ROOT\0
|
|||
|
//
|
|||
|
|
|||
|
status = IopOpenRegistryKey(&handle,
|
|||
|
NULL,
|
|||
|
&CmRegistryMachineSystemCurrentControlSetEnumName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_HTREE_ROOT_0);
|
|||
|
status = IopOpenRegistryKeyPersist(&hTreeHandle,
|
|||
|
handle,
|
|||
|
&unicodeName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
NtClose(handle);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_FOUNDATENUM);
|
|||
|
foundAtEnum = 1;
|
|||
|
NtSetValueKey(hTreeHandle,
|
|||
|
&unicodeName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&foundAtEnum,
|
|||
|
sizeof(foundAtEnum)
|
|||
|
);
|
|||
|
NtClose(hTreeHandle);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up Enum subkey for service list.
|
|||
|
//
|
|||
|
|
|||
|
status = IopInitServiceEnumList();
|
|||
|
|
|||
|
init_Exit:
|
|||
|
|
|||
|
//
|
|||
|
// Free our scratch buffers and exit.
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(IopPnpScratchBuffer1);
|
|||
|
ExFreePool(IopPnpScratchBuffer2);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|