X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Fntoskrnl%2Fio%2Fpnpmgr%2Fpnpreport.c;h=334a9ce26cb0f524d1ae2adbad9af245b35a6f53;hp=e11c4b0263e933f1f85bc5b3807bb1b751702e8c;hb=4c9fecffae35de4fb0b6b87ff9a546fe8d7ffe26;hpb=4ee89fa8f2f3dbb1fba09da4ae4c9f2771ba2561 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; } /*