Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NTOS:PNP] Implement PlugPlayControlStartDevice control class and use it #3481

Merged
merged 3 commits into from Mar 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 3 additions & 6 deletions base/services/umpnpmgr/rpcserver.c
Expand Up @@ -3081,17 +3081,14 @@ static CONFIGRET
EnableDeviceInstance(
_In_ LPWSTR pszDeviceInstance)
{
PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
CONFIGRET ret = CR_SUCCESS;
NTSTATUS Status;

DPRINT("Enable device instance %S\n", pszDeviceInstance);

RtlInitUnicodeString(&ResetDeviceData.DeviceInstance,
pszDeviceInstance);
Status = NtPlugPlayControl(PlugPlayControlResetDevice,
&ResetDeviceData,
sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
RtlInitUnicodeString(&ControlData.DeviceInstance, pszDeviceInstance);
Status = NtPlugPlayControl(PlugPlayControlStartDevice, &ControlData, sizeof(ControlData));
if (!NT_SUCCESS(Status))
ret = NtStatusToCrError(Status);

Expand Down
38 changes: 28 additions & 10 deletions base/setup/usetup/devinst.c
Expand Up @@ -39,20 +39,25 @@ typedef struct
/* FUNCTIONS ****************************************************************/

static BOOLEAN
ResetDevice(
IN LPCWSTR DeviceId)
AreDriversLoaded(
IN PCWSTR DeviceId)
{
PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
NTSTATUS Status;

RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, DeviceId);
Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
if (!NT_SUCCESS(Status))
RtlInitUnicodeString(&PlugPlayData.DeviceInstance, DeviceId);
PlugPlayData.Operation = PNP_GET_DEVICE_STATUS;

Status = NtPlugPlayControl(PlugPlayControlDeviceStatus, &PlugPlayData, sizeof(PlugPlayData));
if (NT_SUCCESS(Status))
{
return (_Bool)((PlugPlayData.DeviceStatus & DN_DRIVER_LOADED) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return (_Bool)((PlugPlayData.DeviceStatus & DN_DRIVER_LOADED) &&
return (BOOLEAN)((PlugPlayData.DeviceStatus & DN_DRIVER_LOADED) &&

(you can use the same return type as the function.)

!(PlugPlayData.DeviceStatus & DN_HAS_PROBLEM));
}
else
{
DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status);
return FALSE;
}
return TRUE;
}

static BOOLEAN
Expand Down Expand Up @@ -81,6 +86,10 @@ InstallDriver(
NTSTATUS Status;
BOOLEAN deviceInstalled = FALSE;

/* First check if the driver needs any action at all */
if (AreDriversLoaded(DeviceId))
return TRUE;

/* Check if we know the hardware */
if (!SpInfFindFirstLine(hInf, L"HardwareIdsDatabase", HardwareId, &Context))
return FALSE;
Expand Down Expand Up @@ -190,8 +199,17 @@ InstallDriver(
(wcslen(Driver) + 1) * sizeof(WCHAR));
if (NT_SUCCESS(Status))
{
/* Restart the device, so it will use the driver we registered */
deviceInstalled = ResetDevice(DeviceId);
/* We've registered the driver, time to start a device */
PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData;
RtlInitUnicodeString(&ControlData.DeviceInstance, DeviceId);

Status = NtPlugPlayControl(PlugPlayControlStartDevice, &ControlData, sizeof(ControlData));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtPlugPlayControl() failed with status 0x%08x\n", Status);
}

deviceInstalled = NT_SUCCESS(Status);
}

INF_FreeData(Driver);
Expand Down
3 changes: 2 additions & 1 deletion ntoskrnl/include/internal/io.h
Expand Up @@ -534,7 +534,8 @@ typedef enum _DEVICE_ACTION
PiActionEnumDeviceTree,
PiActionEnumRootDevices,
PiActionResetDevice,
PiActionAddBootDevices
PiActionAddBootDevices,
PiActionStartDevice
} DEVICE_ACTION;

//
Expand Down
18 changes: 18 additions & 0 deletions ntoskrnl/io/pnpmgr/devaction.c
Expand Up @@ -2482,6 +2482,8 @@ ActionToStr(
return "PiActionResetDevice";
case PiActionAddBootDevices:
return "PiActionAddBootDevices";
case PiActionStartDevice:
return "PiActionStartDevice";
default:
return "(request unknown)";
}
Expand Down Expand Up @@ -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;
Expand Down
90 changes: 40 additions & 50 deletions ntoskrnl/io/pnpmgr/plugplay.c
Expand Up @@ -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.
Expand Down Expand Up @@ -1042,23 +1008,26 @@ IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData)
return Status;
}


static NTSTATUS
IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_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)
{
Expand All @@ -1069,7 +1038,25 @@ IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_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);

Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -1362,12 +1358,6 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass,
// case PlugPlayControlTargetDeviceRelation:
// case PlugPlayControlQueryConflictList:
// case PlugPlayControlRetrieveDock:

case PlugPlayControlResetDevice:
if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA))
return STATUS_INVALID_PARAMETER;
return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer);

// case PlugPlayControlHaltDevice:
// case PlugPlayControlGetBlockedDriverList:

Expand Down
38 changes: 22 additions & 16 deletions sdk/include/ndk/cmtypes.h
Expand Up @@ -453,14 +453,26 @@ typedef struct _PLUGPLAY_EVENT_BLOCK
// Plug and Play Control Classes
//

// Class 0x00
// PlugPlayControlEnumerateDevice (0x00)
typedef struct _PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA
{
UNICODE_STRING DeviceInstance;
ULONG Flags;
} PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA, *PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA;

// Class 0x06
// PlugPlayControlRegisterNewDevice (0x1)
// PlugPlayControlDeregisterDevice (0x2)
// PlugPlayControlInitializeDevice (0x3)
// PlugPlayControlStartDevice (0x4)
// PlugPlayControlUnlockDevice (0x5)
// PlugPlayControlResetDevice (0x14)
// PlugPlayControlHaltDevice (0x15)
typedef struct _PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA
{
UNICODE_STRING DeviceInstance;
} PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA, *PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA;

// PlugPlayControlQueryAndRemoveDevice (0x06)
typedef struct _PLUGPLAY_CONTROL_QUERY_REMOVE_DATA
{
UNICODE_STRING DeviceInstance;
Expand All @@ -470,7 +482,7 @@ typedef struct _PLUGPLAY_CONTROL_QUERY_REMOVE_DATA
ULONG NameLength;
} PLUGPLAY_CONTROL_QUERY_REMOVE_DATA, *PPLUGPLAY_CONTROL_QUERY_REMOVE_DATA;

// Class 0x07
// PlugPlayControlUserResponse (0x07)
typedef struct _PLUGPLAY_CONTROL_USER_RESPONSE_DATA
{
ULONG Unknown1;
Expand All @@ -479,7 +491,7 @@ typedef struct _PLUGPLAY_CONTROL_USER_RESPONSE_DATA
ULONG Unknown4;
} PLUGPLAY_CONTROL_USER_RESPONSE_DATA, *PPLUGPLAY_CONTROL_USER_RESPONSE_DATA;

// Class 0x09
// PlugPlayControlGetInterfaceDeviceList (0x09)
typedef struct _PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
{
UNICODE_STRING DeviceInstance;
Expand All @@ -489,7 +501,7 @@ typedef struct _PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
ULONG BufferSize;
} PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA, *PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA;

//Class 0x0A
// PlugPlayControlProperty (0x0A)
typedef struct _PLUGPLAY_CONTROL_PROPERTY_DATA
{
UNICODE_STRING DeviceInstance;
Expand All @@ -498,7 +510,7 @@ typedef struct _PLUGPLAY_CONTROL_PROPERTY_DATA
ULONG BufferSize;
} PLUGPLAY_CONTROL_PROPERTY_DATA, *PPLUGPLAY_CONTROL_PROPERTY_DATA;

// Class 0x0C
// PlugPlayControlGetRelatedDevice (0x0C)
typedef struct _PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
{
UNICODE_STRING TargetDeviceInstance;
Expand All @@ -507,7 +519,7 @@ typedef struct _PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
ULONG RelatedDeviceInstanceLength;
} PLUGPLAY_CONTROL_RELATED_DEVICE_DATA, *PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA;

// Class 0x0E
// PlugPlayControlDeviceStatus (0x0E)
typedef struct _PLUGPLAY_CONTOL_STATUS_DATA
{
UNICODE_STRING DeviceInstance;
Expand All @@ -516,14 +528,14 @@ typedef struct _PLUGPLAY_CONTOL_STATUS_DATA
ULONG DeviceProblem;
} PLUGPLAY_CONTROL_STATUS_DATA, *PPLUGPLAY_CONTROL_STATUS_DATA;

// Class 0x0F
// PlugPlayControlGetDeviceDepth (0x0F)
typedef struct _PLUGPLAY_CONTROL_DEPTH_DATA
{
UNICODE_STRING DeviceInstance;
ULONG Depth;
} PLUGPLAY_CONTROL_DEPTH_DATA, *PPLUGPLAY_CONTROL_DEPTH_DATA;

// Class 0x10
// PlugPlayControlQueryDeviceRelations (0x10)
typedef struct _PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
{
UNICODE_STRING DeviceInstance;
Expand All @@ -532,19 +544,13 @@ typedef struct _PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
PWCHAR Buffer;
} PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA, *PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA;

// Class 0x13
// PlugPlayControlRetrieveDock (0x13)
typedef struct _PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA
{
ULONG DeviceInstanceLength;
PWSTR DeviceInstance;
} PLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA, *PPLUGPLAY_CONTROL_RETRIEVE_DOCK_DATA;

// Class 0x14
typedef struct _PLUGPLAY_CONTROL_RESET_DEVICE_DATA
{
UNICODE_STRING DeviceInstance;
} PLUGPLAY_CONTROL_RESET_DEVICE_DATA, *PPLUGPLAY_CONTROL_RESET_DEVICE_DATA;

//
// Plug and Play Bus Type Definition
//
Expand Down