/* * 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 #define NDEBUG #include /* 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 */