diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h index 269264b9e27..5e84f8e120f 100644 --- a/ntoskrnl/include/internal/io.h +++ b/ntoskrnl/include/internal/io.h @@ -534,7 +534,8 @@ typedef enum _DEVICE_ACTION PiActionEnumDeviceTree, PiActionEnumRootDevices, PiActionResetDevice, - PiActionAddBootDevices + PiActionAddBootDevices, + PiActionStartDevice } DEVICE_ACTION; // diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c index 7bf77afae3e..5d354ddc62c 100644 --- a/ntoskrnl/io/pnpmgr/devaction.c +++ b/ntoskrnl/io/pnpmgr/devaction.c @@ -2482,6 +2482,8 @@ ActionToStr( return "PiActionResetDevice"; case PiActionAddBootDevices: return "PiActionAddBootDevices"; + case PiActionStartDevice: + return "PiActionStartDevice"; default: return "(request unknown)"; } @@ -2540,6 +2542,22 @@ PipDeviceActionWorker( status = STATUS_SUCCESS; break; + case PiActionStartDevice: + // This action is triggered from usermode, when a driver is installed + // for a non-critical PDO + if (deviceNode->State == DeviceNodeInitialized && + !(deviceNode->Flags & DNF_HAS_PROBLEM)) + { + PiDevNodeStateMachine(deviceNode); + } + else + { + DPRINT1("NOTE: attempt to start an already started/uninitialized device %wZ\n", + &deviceNode->InstancePath); + status = STATUS_UNSUCCESSFUL; + } + break; + default: DPRINT1("Unimplemented device action %u\n", Request->Action); status = STATUS_NOT_IMPLEMENTED; diff --git a/ntoskrnl/io/pnpmgr/plugplay.c b/ntoskrnl/io/pnpmgr/plugplay.c index 6c0e84fdb92..28e243dcd79 100644 --- a/ntoskrnl/io/pnpmgr/plugplay.c +++ b/ntoskrnl/io/pnpmgr/plugplay.c @@ -186,40 +186,6 @@ IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName) return Status; } -static NTSTATUS -IopPnpEnumerateDevice(PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA DeviceData) -{ - PDEVICE_OBJECT DeviceObject; - UNICODE_STRING DeviceInstance; - NTSTATUS Status = STATUS_SUCCESS; - - Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceData->DeviceInstance); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - DPRINT("IopPnpEnumerateDevice(%wZ)\n", &DeviceInstance); - - /* Get the device object */ - DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); - if (DeviceInstance.Buffer != NULL) - { - ExFreePool(DeviceInstance.Buffer); - } - if (DeviceObject == NULL) - { - return STATUS_NO_SUCH_DEVICE; - } - - Status = PiPerformSyncDeviceAction(DeviceObject, PiActionEnumDeviceTree); - - ObDereferenceObject(DeviceObject); - - return Status; -} - - /* * Remove the current PnP event from the tail of the event queue * and signal IopPnpNotifyEvent if there is yet another event in the queue. @@ -1042,23 +1008,26 @@ IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData) return Status; } - -static NTSTATUS -IopResetDevice(PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData) +static +NTSTATUS +PiControlSyncDeviceAction( + _In_ PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceData, + _In_ PLUGPLAY_CONTROL_CLASS ControlClass) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status; UNICODE_STRING DeviceInstance; - Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance); + ASSERT(ControlClass == PlugPlayControlEnumerateDevice || + ControlClass == PlugPlayControlStartDevice || + ControlClass == PlugPlayControlResetDevice); + + Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceData->DeviceInstance); if (!NT_SUCCESS(Status)) { return Status; } - DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance); - - /* Get the device object */ DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance); if (DeviceInstance.Buffer != NULL) { @@ -1069,7 +1038,25 @@ IopResetDevice(PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ResetDeviceData) return STATUS_NO_SUCH_DEVICE; } - Status = PiPerformSyncDeviceAction(DeviceObject, PiActionResetDevice); + DEVICE_ACTION Action; + + switch (ControlClass) + { + case PlugPlayControlEnumerateDevice: + Action = PiActionEnumDeviceTree; + break; + case PlugPlayControlStartDevice: + Action = PiActionStartDevice; + break; + case PlugPlayControlResetDevice: + Action = PiActionResetDevice; + break; + default: + UNREACHABLE; + break; + } + + Status = PiPerformSyncDeviceAction(DeviceObject, Action); ObDereferenceObject(DeviceObject); @@ -1309,12 +1296,21 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, case PlugPlayControlEnumerateDevice: if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA)) return STATUS_INVALID_PARAMETER; - return IopPnpEnumerateDevice((PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA)Buffer); + // the Flags field is not used anyway + return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer, + PlugPlayControlClass); // case PlugPlayControlRegisterNewDevice: // case PlugPlayControlDeregisterDevice: // case PlugPlayControlInitializeDevice: -// case PlugPlayControlStartDevice: + + case PlugPlayControlStartDevice: + case PlugPlayControlResetDevice: + if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)) + return STATUS_INVALID_PARAMETER; + return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer, + PlugPlayControlClass); + // case PlugPlayControlUnlockDevice: // case PlugPlayControlQueryAndRemoveDevice: @@ -1362,12 +1358,6 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, // case PlugPlayControlTargetDeviceRelation: // case PlugPlayControlQueryConflictList: // case PlugPlayControlRetrieveDock: - - case PlugPlayControlResetDevice: - if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)) - return STATUS_INVALID_PARAMETER; - return IopResetDevice((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer); - // case PlugPlayControlHaltDevice: // case PlugPlayControlGetBlockedDriverList: