/* FUNCTIONS *****************************************************************/
-static NTSTATUS
+NTSTATUS
IopAssignDeviceResources(
IN PDEVICE_NODE DeviceNode,
OUT ULONG *pRequiredSize);
-static NTSTATUS
+
+NTSTATUS
IopTranslateDeviceResources(
IN PDEVICE_NODE DeviceNode,
IN ULONG RequiredSize);
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);
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);
}
-static
NTSTATUS
IopSetDeviceInstanceData(HANDLE InstanceKey,
PDEVICE_NODE DeviceNode)
}
-static NTSTATUS
+NTSTATUS
IopAssignDeviceResources(
IN PDEVICE_NODE DeviceNode,
OUT ULONG *pRequiredSize)
}
-static NTSTATUS
+NTSTATUS
IopTranslateDeviceResources(
IN PDEVICE_NODE DeviceNode,
IN ULONG RequiredSize)
* 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 ******************************************************************/
#define NDEBUG
#include <debug.h>
+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 **********************************************************/
/*
{
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))
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;
}
/*