mirror of
https://github.com/reactos/reactos.git
synced 2024-11-10 00:34:39 +00:00
62473c84e9
svn path=/branches/reactos-yarotows/; revision=46920
502 lines
16 KiB
C
502 lines
16 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
* FILE: ntoskrnl/io/pnpmgr/pnpinit.c
|
|
* PURPOSE: PnP Initialization Code
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
typedef struct _IOPNP_DEVICE_EXTENSION
|
|
{
|
|
PWCHAR CompatibleIdList;
|
|
ULONG CompatibleIdListSize;
|
|
} IOPNP_DEVICE_EXTENSION, *PIOPNP_DEVICE_EXTENSION;
|
|
|
|
PUNICODE_STRING PiInitGroupOrderTable;
|
|
ULONG PiInitGroupOrderTableCount;
|
|
INTERFACE_TYPE PnpDefaultInterfaceType;
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
INTERFACE_TYPE
|
|
NTAPI
|
|
IopDetermineDefaultInterfaceType(VOID)
|
|
{
|
|
/* FIXME: ReactOS doesn't support MicroChannel yet */
|
|
return Isa;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IopInitializeArbiters(VOID)
|
|
{
|
|
/* FIXME: TODO */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
PiInitCacheGroupInformation(VOID)
|
|
{
|
|
HANDLE KeyHandle;
|
|
NTSTATUS Status;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
|
|
PUNICODE_STRING GroupTable;
|
|
ULONG Count;
|
|
UNICODE_STRING GroupString =
|
|
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
|
|
L"\\Control\\ServiceGroupOrder");
|
|
|
|
/* ReactOS HACK for SETUPLDR */
|
|
if (KeLoaderBlock->SetupLdrBlock)
|
|
{
|
|
/* Bogus data */
|
|
PiInitGroupOrderTableCount = 0;
|
|
PiInitGroupOrderTable = (PVOID)0xBABEB00B;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Open the registry key */
|
|
Status = IopOpenRegistryKeyEx(&KeyHandle,
|
|
NULL,
|
|
&GroupString,
|
|
KEY_READ);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Get the list */
|
|
Status = IopGetRegistryValue(KeyHandle, L"List", &KeyValueInformation);
|
|
ZwClose(KeyHandle);
|
|
|
|
/* Make sure we got it */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Make sure it's valid */
|
|
if ((KeyValueInformation->Type == REG_MULTI_SZ) &&
|
|
(KeyValueInformation->DataLength))
|
|
{
|
|
/* Convert it to unicode strings */
|
|
Status = PnpRegMultiSzToUnicodeStrings(KeyValueInformation,
|
|
&GroupTable,
|
|
&Count);
|
|
|
|
/* Cache it for later */
|
|
PiInitGroupOrderTable = GroupTable;
|
|
PiInitGroupOrderTableCount = Count;
|
|
}
|
|
else
|
|
{
|
|
/* Fail */
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* Free the information */
|
|
ExFreePool(KeyValueInformation);
|
|
}
|
|
}
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
USHORT
|
|
NTAPI
|
|
PpInitGetGroupOrderIndex(IN HANDLE ServiceHandle)
|
|
{
|
|
NTSTATUS Status;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
|
|
ULONG i;
|
|
PVOID Buffer;
|
|
UNICODE_STRING Group;
|
|
PAGED_CODE();
|
|
|
|
/* Make sure we have a cache */
|
|
if (!PiInitGroupOrderTable) return -1;
|
|
|
|
/* If we don't have a handle, the rest is easy -- return the count */
|
|
if (!ServiceHandle) return PiInitGroupOrderTableCount + 1;
|
|
|
|
/* Otherwise, get the group value */
|
|
Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
|
|
if (!NT_SUCCESS(Status)) return PiInitGroupOrderTableCount;
|
|
|
|
/* Make sure we have a valid string */
|
|
ASSERT(KeyValueInformation->Type == REG_SZ);
|
|
ASSERT(KeyValueInformation->DataLength);
|
|
|
|
/* Convert to unicode string */
|
|
Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
|
|
PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length);
|
|
Group.MaximumLength = KeyValueInformation->DataLength;
|
|
Group.Buffer = Buffer;
|
|
|
|
/* Loop the groups */
|
|
for (i = 0; i < PiInitGroupOrderTableCount; i++)
|
|
{
|
|
/* Try to find a match */
|
|
if (RtlEqualUnicodeString(&Group, &PiInitGroupOrderTable[i], TRUE)) break;
|
|
}
|
|
|
|
/* We're done */
|
|
ExFreePool(KeyValueInformation);
|
|
return i;
|
|
}
|
|
|
|
USHORT
|
|
NTAPI
|
|
PipGetDriverTagPriority(IN HANDLE ServiceHandle)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE KeyHandle = NULL;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueInformationTag;
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueInformationGroupOrderList;
|
|
PVOID Buffer;
|
|
UNICODE_STRING Group;
|
|
PULONG GroupOrder;
|
|
ULONG i = -1, Count, Tag = 0;
|
|
UNICODE_STRING GroupString =
|
|
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
|
|
L"\\Control\\ServiceGroupOrder");
|
|
|
|
/* Open the key */
|
|
Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &GroupString, KEY_READ);
|
|
if (!NT_SUCCESS(Status)) goto Quickie;
|
|
|
|
/* Read the group */
|
|
Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
|
|
if (!NT_SUCCESS(Status)) goto Quickie;
|
|
|
|
/* Make sure we have a group */
|
|
if ((KeyValueInformation->Type == REG_SZ) &&
|
|
(KeyValueInformation->DataLength))
|
|
{
|
|
/* Convert to unicode string */
|
|
Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
|
|
PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length);
|
|
Group.MaximumLength = KeyValueInformation->DataLength;
|
|
Group.Buffer = Buffer;
|
|
}
|
|
|
|
/* Now read the tag */
|
|
Status = IopGetRegistryValue(ServiceHandle, L"Tag", &KeyValueInformationTag);
|
|
if (!NT_SUCCESS(Status)) goto Quickie;
|
|
|
|
/* Make sure we have a tag */
|
|
if ((KeyValueInformationTag->Type == REG_DWORD) &&
|
|
(KeyValueInformationTag->DataLength))
|
|
{
|
|
/* Read it */
|
|
Tag = *(PULONG)((ULONG_PTR)KeyValueInformationTag +
|
|
KeyValueInformationTag->DataOffset);
|
|
}
|
|
|
|
/* We can get rid of this now */
|
|
ExFreePool(KeyValueInformationTag);
|
|
|
|
/* Now let's read the group's tag order */
|
|
Status = IopGetRegistryValue(KeyHandle,
|
|
Group.Buffer,
|
|
&KeyValueInformationGroupOrderList);
|
|
|
|
/* We can get rid of this now */
|
|
Quickie:
|
|
if (KeyValueInformation) ExFreePool(KeyValueInformation);
|
|
if (KeyHandle) NtClose(KeyHandle);
|
|
if (!NT_SUCCESS(Status)) return -1;
|
|
|
|
/* We're on the success path -- validate the tag order*/
|
|
if ((KeyValueInformationGroupOrderList->Type == REG_BINARY) &&
|
|
(KeyValueInformationGroupOrderList->DataLength))
|
|
{
|
|
/* Get the order array */
|
|
GroupOrder = (PULONG)((ULONG_PTR)KeyValueInformationGroupOrderList +
|
|
KeyValueInformationGroupOrderList->DataOffset);
|
|
|
|
/* Get the count */
|
|
Count = *GroupOrder;
|
|
ASSERT(((Count + 1) * sizeof(ULONG)) <=
|
|
KeyValueInformationGroupOrderList->DataLength);
|
|
|
|
/* Now loop each tag */
|
|
GroupOrder++;
|
|
for (i = 1; i <= Count; i++)
|
|
{
|
|
/* If we found it, we're out */
|
|
if (Tag == *GroupOrder) break;
|
|
|
|
/* Try the next one */
|
|
GroupOrder++;
|
|
}
|
|
}
|
|
|
|
/* Last buffer to free */
|
|
ExFreePool(KeyValueInformationGroupOrderList);
|
|
return i;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
PipCallDriverAddDevice(IN PDEVICE_NODE DeviceNode,
|
|
IN BOOLEAN LoadDriver,
|
|
IN PDRIVER_OBJECT DriverObject)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE EnumRootKey, SubKey, ControlKey, ClassKey, PropertiesKey;
|
|
UNICODE_STRING ClassGuid, Properties;
|
|
UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
|
|
UNICODE_STRING ControlClass =
|
|
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
|
|
PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
|
|
PWCHAR Buffer;
|
|
|
|
/* Open enumeration root key */
|
|
Status = IopOpenRegistryKeyEx(&EnumRootKey,
|
|
NULL,
|
|
&EnumRoot,
|
|
KEY_READ);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Open instance subkey */
|
|
Status = IopOpenRegistryKeyEx(&SubKey,
|
|
EnumRootKey,
|
|
&DeviceNode->InstancePath,
|
|
KEY_READ);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
|
|
ZwClose(EnumRootKey);
|
|
return Status;
|
|
}
|
|
|
|
/* Get class GUID */
|
|
Status = IopGetRegistryValue(SubKey,
|
|
REGSTR_VAL_CLASSGUID,
|
|
&KeyValueInformation);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Convert to unicode string */
|
|
Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
|
|
PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &ClassGuid.Length);
|
|
ClassGuid.MaximumLength = KeyValueInformation->DataLength;
|
|
ClassGuid.Buffer = Buffer;
|
|
|
|
/* Open the key */
|
|
Status = IopOpenRegistryKeyEx(&ControlKey,
|
|
NULL,
|
|
&ControlClass,
|
|
KEY_READ);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* No class key */
|
|
DPRINT1("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
|
|
ClassKey = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* Open the class key */
|
|
Status = IopOpenRegistryKeyEx(&ClassKey,
|
|
ControlKey,
|
|
&ClassGuid,
|
|
KEY_READ);
|
|
ZwClose(ControlKey);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* No class key */
|
|
DPRINT1("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
|
|
ClassKey = NULL;
|
|
}
|
|
}
|
|
|
|
/* Check if we made it till here */
|
|
if (ClassKey)
|
|
{
|
|
/* Get the device properties */
|
|
RtlInitUnicodeString(&Properties, REGSTR_KEY_DEVICE_PROPERTIES);
|
|
Status = IopOpenRegistryKeyEx(&PropertiesKey,
|
|
ClassKey,
|
|
&Properties,
|
|
KEY_READ);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* No properties */
|
|
DPRINT("IopOpenRegistryKeyEx() failed with Status %08X\n", Status);
|
|
PropertiesKey = NULL;
|
|
}
|
|
}
|
|
|
|
/* Free the registry data */
|
|
ExFreePool(KeyValueInformation);
|
|
}
|
|
|
|
/* Do ReactOS-style setup */
|
|
IopAttachFilterDrivers(DeviceNode, TRUE);
|
|
Status = IopInitializeDevice(DeviceNode, DriverObject);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
IopAttachFilterDrivers(DeviceNode, FALSE);
|
|
Status = IopStartDevice(DeviceNode);
|
|
}
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IopInitializePlugPlayServices(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG Disposition;
|
|
HANDLE KeyHandle, EnumHandle, ParentHandle, TreeHandle;
|
|
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
|
|
PDEVICE_OBJECT Pdo;
|
|
|
|
/* Initialize locks and such */
|
|
KeInitializeSpinLock(&IopDeviceTreeLock);
|
|
|
|
/* Get the default interface */
|
|
PnpDefaultInterfaceType = IopDetermineDefaultInterfaceType();
|
|
|
|
/* Initialize arbiters */
|
|
Status = IopInitializeArbiters();
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Setup the group cache */
|
|
Status = PiInitCacheGroupInformation();
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Open the current control set */
|
|
Status = IopOpenRegistryKeyEx(&KeyHandle,
|
|
NULL,
|
|
&KeyName,
|
|
KEY_ALL_ACCESS);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Create the enum key */
|
|
RtlInitUnicodeString(&KeyName, REGSTR_KEY_ENUM);
|
|
Status = IopCreateRegistryKeyEx(&EnumHandle,
|
|
KeyHandle,
|
|
&KeyName,
|
|
KEY_ALL_ACCESS,
|
|
REG_OPTION_NON_VOLATILE,
|
|
&Disposition);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Check if it's a new key */
|
|
if (Disposition == REG_CREATED_NEW_KEY)
|
|
{
|
|
/* FIXME: DACLs */
|
|
DPRINT1("Need to build DACL\n");
|
|
}
|
|
|
|
/* Create the root key */
|
|
ParentHandle = EnumHandle;
|
|
RtlInitUnicodeString(&KeyName, REGSTR_KEY_ROOTENUM);
|
|
Status = IopCreateRegistryKeyEx(&EnumHandle,
|
|
ParentHandle,
|
|
&KeyName,
|
|
KEY_ALL_ACCESS,
|
|
REG_OPTION_NON_VOLATILE,
|
|
&Disposition);
|
|
NtClose(ParentHandle);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
NtClose(EnumHandle);
|
|
|
|
/* Open the root key now */
|
|
RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
|
|
Status = IopOpenRegistryKeyEx(&EnumHandle,
|
|
NULL,
|
|
&KeyName,
|
|
KEY_ALL_ACCESS);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Create the root dev node */
|
|
RtlInitUnicodeString(&KeyName, REGSTR_VAL_ROOT_DEVNODE);
|
|
Status = IopCreateRegistryKeyEx(&TreeHandle,
|
|
EnumHandle,
|
|
&KeyName,
|
|
KEY_ALL_ACCESS,
|
|
REG_OPTION_NON_VOLATILE,
|
|
NULL);
|
|
NtClose(EnumHandle);
|
|
if (NT_SUCCESS(Status)) NtClose(TreeHandle);
|
|
}
|
|
|
|
/* Create the root driver */
|
|
Status = IoCreateDriver(NULL, PnpRootDriverEntry);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("IoCreateDriverObject() failed\n");
|
|
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
|
|
}
|
|
|
|
/* Create the root PDO */
|
|
Status = IoCreateDevice(IopRootDriverObject,
|
|
sizeof(IOPNP_DEVICE_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_CONTROLLER,
|
|
0,
|
|
FALSE,
|
|
&Pdo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("IoCreateDevice() failed\n");
|
|
KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
|
|
}
|
|
|
|
/* This is a bus enumerated device */
|
|
Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
|
|
|
|
/* Create the root device node */
|
|
IopRootDeviceNode = PipAllocateDeviceNode(Pdo);
|
|
|
|
/* Set flags */
|
|
IopRootDeviceNode->Flags |= DNF_STARTED + DNF_PROCESSED + DNF_ENUMERATED +
|
|
DNF_MADEUP + DNF_NO_RESOURCE_REQUIRED +
|
|
DNF_ADDED;
|
|
|
|
/* Create instance path */
|
|
RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
|
|
REGSTR_VAL_ROOT_DEVNODE);
|
|
|
|
/* Call the add device routine */
|
|
IopRootDriverObject->DriverExtension->AddDevice(IopRootDriverObject,
|
|
IopRootDeviceNode->PhysicalDeviceObject);
|
|
|
|
/* Initialize PnP-Event notification support */
|
|
Status = IopInitPlugPlayEvents();
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Report the device to the user-mode pnp manager */
|
|
IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
|
|
&IopRootDeviceNode->InstancePath);
|
|
|
|
/* Initialize the Bus Type GUID List */
|
|
PnpBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
|
|
RtlZeroMemory(PnpBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
|
|
ExInitializeFastMutex(&PnpBusTypeGuidList->Lock);
|
|
|
|
/* Launch the firmware mapper */
|
|
Status = IopUpdateRootKey();
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Close the handle to the control set */
|
|
NtClose(KeyHandle);
|
|
|
|
/* We made it */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* EOF */
|