From 4c9fecffae35de4fb0b6b87ff9a546fe8d7ffe26 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 1 Apr 2010 06:58:32 +0000 Subject: [PATCH] [NTOSKRNL] - Change PnpRootCreateDevice's ServiceName parameter to be a full service name so it can be used by IoReportDetectedDevice (for reporting devices without the "LEGACY_" prefix) and change all of its callers accordingly - Remove the broken implementation of IoReportDetectedDevice and replace it with a fully working implementation - There is still a bug that it creates a new device instance every boot, but unlike the previous code, at least it creates one ;-) svn path=/trunk/; revision=46639 --- reactos/ntoskrnl/io/pnpmgr/pnpmgr.c | 29 ++- reactos/ntoskrnl/io/pnpmgr/pnpreport.c | 263 +++++++++++++++++++++++-- reactos/ntoskrnl/io/pnpmgr/pnproot.c | 4 +- 3 files changed, 270 insertions(+), 26 deletions(-) diff --git a/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c b/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c index 502787fc41f..4e820883b59 100644 --- a/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c +++ b/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c @@ -46,11 +46,12 @@ typedef struct _INVALIDATE_DEVICE_RELATION_DATA /* FUNCTIONS *****************************************************************/ -static NTSTATUS +NTSTATUS IopAssignDeviceResources( IN PDEVICE_NODE DeviceNode, OUT ULONG *pRequiredSize); -static NTSTATUS + +NTSTATUS IopTranslateDeviceResources( IN PDEVICE_NODE DeviceNode, IN ULONG RequiredSize); @@ -361,6 +362,8 @@ IopCreateDeviceNode(PDEVICE_NODE ParentNode, PDEVICE_NODE Node; NTSTATUS Status; KIRQL OldIrql; + UNICODE_STRING FullServiceName; + UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_"); DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n", ParentNode, PhysicalDeviceObject, ServiceName); @@ -375,7 +378,22 @@ IopCreateDeviceNode(PDEVICE_NODE ParentNode, if (!PhysicalDeviceObject) { - Status = PnpRootCreateDevice(ServiceName, &PhysicalDeviceObject); + if (ServiceName) + { + FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName->Length; + FullServiceName.Length = 0; + FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength); + if (!FullServiceName.Buffer) + { + ExFreePool(Node); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix); + RtlAppendUnicodeStringToString(&FullServiceName, ServiceName); + } + + Status = PnpRootCreateDevice(ServiceName ? &FullServiceName : NULL, &PhysicalDeviceObject); if (!NT_SUCCESS(Status)) { DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status); @@ -709,7 +727,6 @@ IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, } -static NTSTATUS IopSetDeviceInstanceData(HANDLE InstanceKey, PDEVICE_NODE DeviceNode) @@ -799,7 +816,7 @@ IopSetDeviceInstanceData(HANDLE InstanceKey, } -static NTSTATUS +NTSTATUS IopAssignDeviceResources( IN PDEVICE_NODE DeviceNode, OUT ULONG *pRequiredSize) @@ -1014,7 +1031,7 @@ ByeBye: } -static NTSTATUS +NTSTATUS IopTranslateDeviceResources( IN PDEVICE_NODE DeviceNode, IN ULONG RequiredSize) diff --git a/reactos/ntoskrnl/io/pnpmgr/pnpreport.c b/reactos/ntoskrnl/io/pnpmgr/pnpreport.c index e11c4b0263e..334a9ce26cb 100644 --- a/reactos/ntoskrnl/io/pnpmgr/pnpreport.c +++ b/reactos/ntoskrnl/io/pnpmgr/pnpreport.c @@ -3,7 +3,7 @@ * COPYRIGHT: GPL - See COPYING in the top level directory * FILE: ntoskrnl/io/pnpmgr/pnpreport.c * PURPOSE: Device Changes Reporting Functions - * PROGRAMMERS: Filip Navara (xnavara@volny.cz) + * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) */ /* INCLUDES ******************************************************************/ @@ -12,6 +12,90 @@ #define NDEBUG #include +NTSTATUS +NTAPI +IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, + OUT PHANDLE Handle); + +NTSTATUS +IopAssignDeviceResources( + IN PDEVICE_NODE DeviceNode, + OUT ULONG *pRequiredSize); + +NTSTATUS +IopSetDeviceInstanceData(HANDLE InstanceKey, + PDEVICE_NODE DeviceNode); + +NTSTATUS +IopTranslateDeviceResources( + IN PDEVICE_NODE DeviceNode, + IN ULONG RequiredSize); + +NTSTATUS +IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, + PVOID Context); + +/* PRIVATE FUNCTIONS *********************************************************/ + +PWCHAR +IopGetInterfaceTypeString(INTERFACE_TYPE IfType) +{ + switch (IfType) + { + case Internal: + return L"Internal"; + + case Isa: + return L"Isa"; + + case Eisa: + return L"Eisa"; + + case MicroChannel: + return L"MicroChannel"; + + case TurboChannel: + return L"TurboChannel"; + + case PCIBus: + return L"PCIBus"; + + case VMEBus: + return L"VMEBus"; + + case NuBus: + return L"NuBus"; + + case PCMCIABus: + return L"PCMCIABus"; + + case CBus: + return L"CBus"; + + case MPIBus: + return L"MPIBus"; + + case MPSABus: + return L"MPSABus"; + + case ProcessorInternal: + return L"ProcessorInternal"; + + case PNPISABus: + return L"PNPISABus"; + + case PNPBus: + return L"PNPBus"; + + case Vmcs: + return L"Vmcs"; + + default: + DPRINT1("Invalid bus type: %d\n", IfType); + return NULL; + } +} + /* PUBLIC FUNCTIONS **********************************************************/ /* @@ -30,29 +114,56 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject, { PDEVICE_NODE DeviceNode; PDEVICE_OBJECT Pdo; - NTSTATUS Status = STATUS_SUCCESS; + NTSTATUS Status; + HANDLE InstanceKey; + ULONG RequiredLength; + UNICODE_STRING ValueName, ServiceName; + WCHAR HardwareId[256]; + PWCHAR IfString; + ULONG IdLength; - DPRINT("__FUNCTION__ (DeviceObject %p, *DeviceObject %p)\n", + DPRINT("IoReportDetectedDevice (DeviceObject %p, *DeviceObject %p)\n", DeviceObject, DeviceObject ? *DeviceObject : NULL); - /* if *DeviceObject is not NULL, we must use it as a PDO, and don't create a new one */ + /* Create the service name (eg. ACPI_HAL) */ + ServiceName.Buffer = DriverObject->DriverName.Buffer + + sizeof(DRIVER_ROOT_NAME) / sizeof(WCHAR) - 1; + ServiceName.Length = DriverObject->DriverName.Length - + sizeof(DRIVER_ROOT_NAME) + sizeof(WCHAR); + ServiceName.MaximumLength = ServiceName.Length; + + /* If the interface type is unknown, treat it as internal */ + if (LegacyBusType == InterfaceTypeUndefined) + LegacyBusType = Internal; + + /* Get the string equivalent of the interface type */ + IfString = IopGetInterfaceTypeString(LegacyBusType); + + /* If NULL is returned then it's a bad type */ + if (!IfString) + return STATUS_INVALID_PARAMETER; + + /* We use the caller's PDO if they supplied one */ if (DeviceObject && *DeviceObject) { Pdo = *DeviceObject; + DeviceNode = IopGetDeviceNode(*DeviceObject); } else { - UNICODE_STRING ServiceName; - ServiceName.Buffer = DriverObject->DriverName.Buffer + - sizeof(DRIVER_ROOT_NAME) / sizeof(WCHAR) - 1; - ServiceName.Length = DriverObject->DriverName.Length - - sizeof(DRIVER_ROOT_NAME) + sizeof(WCHAR); - ServiceName.MaximumLength = ServiceName.Length; - - /* create a new PDO and return it in *DeviceObject */ + /* Create the PDO */ + Status = PnpRootCreateDevice(&ServiceName, + &Pdo); + if (!NT_SUCCESS(Status)) + { + DPRINT("PnpRootCreateDevice() failed (Status 0x%08lx)\n", Status); + return Status; + } + + /* Create the device node for the new PDO */ Status = IopCreateDeviceNode(IopRootDeviceNode, + Pdo, NULL, - &ServiceName, &DeviceNode); if (!NT_SUCCESS(Status)) @@ -60,13 +171,129 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject, DPRINT("IopCreateDeviceNode() failed (Status 0x%08lx)\n", Status); return Status; } + } + + /* We don't call AddDevice for devices reported this way */ + IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED); + + /* We don't send IRP_MN_START_DEVICE */ + IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); + + /* This is a legacy driver for this device */ + IopDeviceNodeSetFlag(DeviceNode, DNF_LEGACY_DRIVER); + + /* Perform a manual configuration of our device */ + IopActionInterrogateDeviceStack(DeviceNode, DeviceNode->Parent); + IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent); + + /* Open a handle to the instance path key */ + Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, &InstanceKey); + if (!NT_SUCCESS(Status)) + return Status; + + /* Add DETECTEDInterfaceType\DriverName */ + IdLength = 0; + IdLength += swprintf(&HardwareId[IdLength], + L"DETECTED%ls\\%wZ", + IfString, + &ServiceName); + HardwareId[IdLength++] = UNICODE_NULL; + + /* Add DETECTED\DriverName */ + IdLength += swprintf(&HardwareId[IdLength], + L"DETECTED\\%wZ", + &ServiceName); + HardwareId[IdLength++] = UNICODE_NULL; + + /* Terminate the string with another null */ + HardwareId[IdLength] = UNICODE_NULL; + + /* Store the value for CompatibleIDs */ + RtlInitUnicodeString(&ValueName, L"CompatibleIDs"); + Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId, IdLength * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + { + DPRINT("Failed to write the compatible IDs: 0x%x\n", Status); + ZwClose(InstanceKey); + return Status; + } - Pdo = DeviceNode->PhysicalDeviceObject; - if (DeviceObject) *DeviceObject = Pdo; - } + /* Add a hardware ID if the driver didn't report one */ + RtlInitUnicodeString(&ValueName, L"HardwareID"); + if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND) + { + /* Just use our most specific compatible ID */ + IdLength = 0; + IdLength += swprintf(&HardwareId[IdLength], + L"DETECTED%ls\\%wZ", + IfString, + &ServiceName); + HardwareId[++IdLength] = UNICODE_NULL; + + /* Write the value to the registry */ + Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_SZ, HardwareId, IdLength * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + { + DPRINT("Failed to write the hardware ID: 0x%x\n", Status); + ZwClose(InstanceKey); + return Status; + } + } + + /* Assign the resources to the device node */ + DeviceNode->BootResources = ResourceList; + DeviceNode->ResourceRequirements = ResourceRequirements; + + /* Set appropriate flags */ + if (DeviceNode->BootResources) + IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); + + if (DeviceNode->ResourceRequirements) + IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_REPORTED); + else + IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED); + + /* Write the resource information to the registry */ + IopSetDeviceInstanceData(InstanceKey, DeviceNode); + + /* Close the instance key handle */ + ZwClose(InstanceKey); - /* we don't need to call AddDevice and send IRP_MN_START_DEVICE */ - return Status; + /* If the caller didn't get the resources assigned for us, do it now */ + if (!ResourceAssigned) + { + IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES); + Status = IopAssignDeviceResources(DeviceNode, &RequiredLength); + if (NT_SUCCESS(Status)) + { + Status = IopTranslateDeviceResources(DeviceNode, RequiredLength); + if (NT_SUCCESS(Status)) + IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED); + } + IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES); + + /* See if we failed */ + if (!NT_SUCCESS(Status)) + { + DPRINT("Assigning resources failed: 0x%x\n", Status); + return Status; + } + } + + /* Report the device's enumeration to umpnpmgr */ + IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED, + &DeviceNode->InstancePath); + + /* Report the device's arrival to umpnpmgr */ + IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, + &DeviceNode->InstancePath); + + DPRINT1("Reported device: %S (%wZ)\n", HardwareId, &DeviceNode->InstancePath); + + /* Return the PDO */ + if (DeviceObject) *DeviceObject = Pdo; + + return STATUS_SUCCESS; } /* diff --git a/reactos/ntoskrnl/io/pnpmgr/pnproot.c b/reactos/ntoskrnl/io/pnpmgr/pnproot.c index 5a5bf85c3eb..c622cba2e8b 100644 --- a/reactos/ntoskrnl/io/pnpmgr/pnproot.c +++ b/reactos/ntoskrnl/io/pnpmgr/pnproot.c @@ -134,7 +134,7 @@ PnpRootCreateDevice( IN PDEVICE_OBJECT *PhysicalDeviceObject) { PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension; - UNICODE_STRING UnknownServiceName = RTL_CONSTANT_STRING(L"UNKNOWN"); + UNICODE_STRING UnknownServiceName = RTL_CONSTANT_STRING(L"LEGACY_UNKNOWN"); PUNICODE_STRING LocalServiceName; PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension; WCHAR DevicePath[MAX_PATH + 1]; @@ -154,7 +154,7 @@ PnpRootCreateDevice( DPRINT("Creating a PnP root device for service '%wZ'\n", LocalServiceName); /* Search for a free instance ID */ - _snwprintf(DevicePath, sizeof(DevicePath) / sizeof(WCHAR), L"%s\\LEGACY_%wZ", REGSTR_KEY_ROOTENUM, LocalServiceName); + _snwprintf(DevicePath, sizeof(DevicePath) / sizeof(WCHAR), L"%s\\%wZ", REGSTR_KEY_ROOTENUM, LocalServiceName); for (i = 0; i < 9999; i++) { _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", i); -- 2.17.1