mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
71fefa32db
* Add an NDK header to define INIT_FUNCTION/INIT_SECTION globally * Use _declspec(allocate(x)) and _declspec(code_seg(x)) on MSVC versions that support it * Use INIT_FUNCTION on functions only and INIT_SECTION on data only (required by MSVC) * Place INIT_FUNCTION before the return type (required by MSVC) * Make sure declarations and implementations share the same modifiers (required by MSVC) * Add a global linker option to suppress warnings about defined but unused INIT section * Merge INIT section into .text in freeldr
556 lines
18 KiB
C
556 lines
18 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;
|
|
USHORT 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;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
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");
|
|
|
|
/* 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 = (USHORT)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;
|
|
USHORT 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 = (USHORT)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 Count, Tag = 0;
|
|
USHORT i = -1;
|
|
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 = (USHORT)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;
|
|
HANDLE ControlKey, ClassKey = NULL, 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 for '%wZ' with status 0x%lx\n",
|
|
&EnumRoot, Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Open instance subkey */
|
|
Status = IopOpenRegistryKeyEx(&SubKey,
|
|
EnumRootKey,
|
|
&DeviceNode->InstancePath,
|
|
KEY_READ);
|
|
ZwClose(EnumRootKey);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
|
|
&DeviceNode->InstancePath, Status);
|
|
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 = (USHORT)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 for '%wZ' with status 0x%lx\n",
|
|
&ControlClass, Status);
|
|
}
|
|
else
|
|
{
|
|
/* Open the class key */
|
|
Status = IopOpenRegistryKeyEx(&ClassKey,
|
|
ControlKey,
|
|
&ClassGuid,
|
|
KEY_READ);
|
|
ZwClose(ControlKey);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* No class key */
|
|
DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
|
|
&ClassGuid, Status);
|
|
}
|
|
}
|
|
|
|
/* 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 for '%wZ' with status 0x%lx\n",
|
|
&Properties, Status);
|
|
PropertiesKey = NULL;
|
|
}
|
|
else
|
|
{
|
|
ZwClose(PropertiesKey);
|
|
}
|
|
}
|
|
|
|
/* Free the registry data */
|
|
ExFreePool(KeyValueInformation);
|
|
}
|
|
|
|
/* Do ReactOS-style setup */
|
|
Status = IopAttachFilterDrivers(DeviceNode, SubKey, ClassKey, TRUE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
IopRemoveDevice(DeviceNode);
|
|
goto Exit;
|
|
}
|
|
|
|
Status = IopInitializeDevice(DeviceNode, DriverObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Status = IopAttachFilterDrivers(DeviceNode, SubKey, ClassKey, FALSE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
IopRemoveDevice(DeviceNode);
|
|
goto Exit;
|
|
}
|
|
|
|
Status = IopStartDevice(DeviceNode);
|
|
|
|
Exit:
|
|
/* Close keys and return status */
|
|
ZwClose(SubKey);
|
|
if (ClassKey != NULL)
|
|
{
|
|
ZwClose(ClassKey);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
NTSTATUS
|
|
NTAPI
|
|
IopInitializePlugPlayServices(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG Disposition;
|
|
HANDLE KeyHandle, EnumHandle, ParentHandle, TreeHandle, ControlHandle;
|
|
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
|
|
UNICODE_STRING PnpManagerDriverName = RTL_CONSTANT_STRING(DRIVER_ROOT_NAME L"PnpManager");
|
|
PDEVICE_OBJECT Pdo;
|
|
|
|
/* Initialize locks and such */
|
|
KeInitializeSpinLock(&IopDeviceTreeLock);
|
|
KeInitializeSpinLock(&IopDeviceActionLock);
|
|
InitializeListHead(&IopDeviceActionRequestList);
|
|
|
|
/* 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 control key */
|
|
RtlInitUnicodeString(&KeyName, L"Control");
|
|
Status = IopCreateRegistryKeyEx(&ControlHandle,
|
|
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)
|
|
{
|
|
HANDLE DeviceClassesHandle;
|
|
|
|
/* Create the device classes key */
|
|
RtlInitUnicodeString(&KeyName, L"DeviceClasses");
|
|
Status = IopCreateRegistryKeyEx(&DeviceClassesHandle,
|
|
ControlHandle,
|
|
&KeyName,
|
|
KEY_ALL_ACCESS,
|
|
REG_OPTION_NON_VOLATILE,
|
|
&Disposition);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
ZwClose(DeviceClassesHandle);
|
|
}
|
|
|
|
ZwClose(ControlHandle);
|
|
|
|
/* 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 */
|
|
}
|
|
|
|
/* 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(&PnpManagerDriverName, 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 */
|