[NTOS:PNP] Implement PlugPlayControlStartDevice control class

This control class is triggered when a driver is being installed for a
non-critical device. The driver info should already be in the registry
so we just need to push the device through the state graph

Meanwhile, combine the code for similar control classes into
PiControlSyncDeviceAction routine

CORE-17463 CORE-17490
This commit is contained in:
Victor Perevertkin 2021-03-16 02:17:14 +03:00
parent 029accdcf7
commit 59a5dba443
No known key found for this signature in database
GPG key ID: C750B7222E9C7830
3 changed files with 60 additions and 51 deletions

View file

@ -534,7 +534,8 @@ typedef enum _DEVICE_ACTION
PiActionEnumDeviceTree,
PiActionEnumRootDevices,
PiActionResetDevice,
PiActionAddBootDevices
PiActionAddBootDevices,
PiActionStartDevice
} DEVICE_ACTION;
//

View file

@ -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;

View file

@ -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: