[NTOS:PNP] Implement NT5.2-like DEVICE_NODE state management
[reactos.git] / ntoskrnl / io / pnpmgr / pnpirp.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Shortcuts for sending different IRP_MJ_PNP requests
5 * COPYRIGHT: Copyright 2010 Sir Richard <sir_richard@svn.reactos.org>
6 * Copyright 2020 Victor Perevertkin <victor.perevertkin@reactos.org>
7 */
8
9 #include <ntoskrnl.h>
10 #define NDEBUG
11 #include <debug.h>
12
13 NTSTATUS
14 IopSynchronousCall(
15 _In_ PDEVICE_OBJECT DeviceObject,
16 _In_ PIO_STACK_LOCATION IoStackLocation,
17 _Out_ PVOID *Information)
18 {
19 PIRP Irp;
20 PIO_STACK_LOCATION IrpStack;
21 IO_STATUS_BLOCK IoStatusBlock;
22 KEVENT Event;
23 NTSTATUS Status;
24 PDEVICE_OBJECT TopDeviceObject;
25 PAGED_CODE();
26
27 /* Call the top of the device stack */
28 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
29
30 /* Allocate an IRP */
31 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
32 if (!Irp)
33 {
34 ObDereferenceObject(TopDeviceObject);
35 return STATUS_INSUFFICIENT_RESOURCES;
36 }
37
38 /* Initialize to failure */
39 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
40 Irp->IoStatus.Information = IoStatusBlock.Information = 0;
41
42 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
43 if ((IoStackLocation->MajorFunction == IRP_MJ_PNP) &&
44 (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS))
45 {
46 /* Copy the resource requirements list into the IOSB */
47 Irp->IoStatus.Information =
48 IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
49 }
50
51 /* Initialize the event */
52 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
53
54 /* Set them up */
55 Irp->UserIosb = &IoStatusBlock;
56 Irp->UserEvent = &Event;
57
58 /* Queue the IRP */
59 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
60 IoQueueThreadIrp(Irp);
61
62 /* Copy-in the stack */
63 IrpStack = IoGetNextIrpStackLocation(Irp);
64 *IrpStack = *IoStackLocation;
65
66 /* Call the driver */
67 Status = IoCallDriver(TopDeviceObject, Irp);
68 /* Otherwise we may get stuck here or have IoStatusBlock not populated */
69 ASSERT(!KeAreAllApcsDisabled());
70 if (Status == STATUS_PENDING)
71 {
72 /* Wait for it */
73 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
74 Status = IoStatusBlock.Status;
75 }
76
77 /* Remove the reference */
78 ObDereferenceObject(TopDeviceObject);
79
80 /* Return the information */
81 *Information = (PVOID)IoStatusBlock.Information;
82 return Status;
83 }
84
85 // IRP_MN_START_DEVICE (0x00)
86 NTSTATUS
87 PiIrpStartDevice(
88 _In_ PDEVICE_NODE DeviceNode)
89 {
90 PAGED_CODE();
91
92 ASSERT(DeviceNode);
93 ASSERT(DeviceNode->State == DeviceNodeResourcesAssigned);
94
95 PVOID info;
96 IO_STACK_LOCATION stack = {
97 .MajorFunction = IRP_MJ_PNP,
98 .MinorFunction = IRP_MN_START_DEVICE,
99 .Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList,
100 .Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated
101 };
102
103 // Vista+ does an asynchronous call
104 NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, &info);
105 DeviceNode->CompletionStatus = status;
106 return status;
107 }
108
109 // IRP_MN_STOP_DEVICE (0x04)
110 NTSTATUS
111 PiIrpStopDevice(
112 _In_ PDEVICE_NODE DeviceNode)
113 {
114 PAGED_CODE();
115
116 ASSERT(DeviceNode);
117 ASSERT(DeviceNode->State == DeviceNodeQueryStopped);
118
119 PVOID info;
120 IO_STACK_LOCATION stack = {
121 .MajorFunction = IRP_MJ_PNP,
122 .MinorFunction = IRP_MN_STOP_DEVICE
123 };
124
125 // Drivers should never fail a IRP_MN_STOP_DEVICE request
126 NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, &info);
127 ASSERT(NT_SUCCESS(status));
128 return status;
129 }
130
131 // IRP_MN_QUERY_STOP_DEVICE (0x05)
132 NTSTATUS
133 PiIrpQueryStopDevice(
134 _In_ PDEVICE_NODE DeviceNode)
135 {
136 PAGED_CODE();
137
138 ASSERT(DeviceNode);
139 ASSERT(DeviceNode->State == DeviceNodeStarted);
140
141 PVOID info;
142 IO_STACK_LOCATION stack = {
143 .MajorFunction = IRP_MJ_PNP,
144 .MinorFunction = IRP_MN_QUERY_STOP_DEVICE
145 };
146
147 NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, &info);
148 DeviceNode->CompletionStatus = status;
149 return status;
150 }
151
152 // IRP_MN_CANCEL_STOP_DEVICE (0x06)
153 NTSTATUS
154 PiIrpCancelStopDevice(
155 _In_ PDEVICE_NODE DeviceNode)
156 {
157 PAGED_CODE();
158
159 ASSERT(DeviceNode);
160 ASSERT(DeviceNode->State == DeviceNodeQueryStopped);
161
162 PVOID info;
163 IO_STACK_LOCATION stack = {
164 .MajorFunction = IRP_MJ_PNP,
165 .MinorFunction = IRP_MN_CANCEL_STOP_DEVICE
166 };
167
168 // in fact we don't care which status is returned here
169 NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, &info);
170 ASSERT(NT_SUCCESS(status));
171 return status;
172 }
173
174 // IRP_MN_QUERY_DEVICE_RELATIONS (0x07)
175 NTSTATUS
176 PiIrpQueryDeviceRelations(
177 _In_ PDEVICE_NODE DeviceNode,
178 _In_ DEVICE_RELATION_TYPE Type)
179 {
180 PAGED_CODE();
181
182 ASSERT(DeviceNode);
183 ASSERT(DeviceNode->State == DeviceNodeStarted);
184
185 IO_STACK_LOCATION stack = {
186 .MajorFunction = IRP_MJ_PNP,
187 .MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS,
188 .Parameters.QueryDeviceRelations.Type = Type
189 };
190
191 // Vista+ does an asynchronous call
192 NTSTATUS status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject,
193 &stack,
194 (PVOID)&DeviceNode->OverUsed1.PendingDeviceRelations);
195 DeviceNode->CompletionStatus = status;
196 return status;
197 }
198
199 // IRP_MN_QUERY_PNP_DEVICE_STATE (0x14)
200 NTSTATUS
201 PiIrpQueryPnPDeviceState(
202 _In_ PDEVICE_NODE DeviceNode,
203 _Out_ PPNP_DEVICE_STATE DeviceState)
204 {
205 PAGED_CODE();
206
207 ASSERT(DeviceNode);
208 ASSERT(DeviceNode->State == DeviceNodeStartPostWork ||
209 DeviceNode->State == DeviceNodeStarted);
210
211 ULONG_PTR longState;
212 IO_STACK_LOCATION stack = {
213 .MajorFunction = IRP_MJ_PNP,
214 .MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE
215 };
216
217 NTSTATUS status;
218 status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longState);
219 if (NT_SUCCESS(status))
220 {
221 *DeviceState = longState;
222 }
223
224 return status;
225 }