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
IopSynchronousCall(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIO_STACK_LOCATION IoStackLocation,_Out_ PVOID * Information)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
PiIrpStartDevice(_In_ PDEVICE_NODE DeviceNode)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
PiIrpStopDevice(_In_ PDEVICE_NODE DeviceNode)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
PiIrpQueryStopDevice(_In_ PDEVICE_NODE DeviceNode)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
PiIrpCancelStopDevice(_In_ PDEVICE_NODE DeviceNode)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
PiIrpQueryDeviceRelations(_In_ PDEVICE_NODE DeviceNode,_In_ DEVICE_RELATION_TYPE Type)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_RESOURCES (0x0A)
200 NTSTATUS
PiIrpQueryResources(_In_ PDEVICE_NODE DeviceNode,_Out_ PCM_RESOURCE_LIST * Resources)201 PiIrpQueryResources(
202 _In_ PDEVICE_NODE DeviceNode,
203 _Out_ PCM_RESOURCE_LIST *Resources)
204 {
205 PAGED_CODE();
206
207 ASSERT(DeviceNode);
208
209 ULONG_PTR longRes;
210 IO_STACK_LOCATION stack = {
211 .MajorFunction = IRP_MJ_PNP,
212 .MinorFunction = IRP_MN_QUERY_RESOURCES
213 };
214
215 NTSTATUS status;
216 status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longRes);
217 if (NT_SUCCESS(status))
218 {
219 *Resources = (PVOID)longRes;
220 }
221
222 return status;
223 }
224
225 // IRP_MN_QUERY_RESOURCE_REQUIREMENTS (0x0B)
226 NTSTATUS
PiIrpQueryResourceRequirements(_In_ PDEVICE_NODE DeviceNode,_Out_ PIO_RESOURCE_REQUIREMENTS_LIST * Resources)227 PiIrpQueryResourceRequirements(
228 _In_ PDEVICE_NODE DeviceNode,
229 _Out_ PIO_RESOURCE_REQUIREMENTS_LIST *Resources)
230 {
231 PAGED_CODE();
232
233 ASSERT(DeviceNode);
234
235 ULONG_PTR longRes;
236 IO_STACK_LOCATION stack = {
237 .MajorFunction = IRP_MJ_PNP,
238 .MinorFunction = IRP_MN_QUERY_RESOURCE_REQUIREMENTS
239 };
240
241 NTSTATUS status;
242 status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longRes);
243 if (NT_SUCCESS(status))
244 {
245 *Resources = (PVOID)longRes;
246 }
247
248 return status;
249 }
250
251 // IRP_MN_QUERY_DEVICE_TEXT (0x0C)
252 NTSTATUS
PiIrpQueryDeviceText(_In_ PDEVICE_NODE DeviceNode,_In_ LCID LocaleId,_In_ DEVICE_TEXT_TYPE Type,_Out_ PWSTR * DeviceText)253 PiIrpQueryDeviceText(
254 _In_ PDEVICE_NODE DeviceNode,
255 _In_ LCID LocaleId,
256 _In_ DEVICE_TEXT_TYPE Type,
257 _Out_ PWSTR *DeviceText)
258 {
259 PAGED_CODE();
260
261 ASSERT(DeviceNode);
262 ASSERT(DeviceNode->State == DeviceNodeUninitialized);
263
264 ULONG_PTR longText;
265 IO_STACK_LOCATION stack = {
266 .MajorFunction = IRP_MJ_PNP,
267 .MinorFunction = IRP_MN_QUERY_DEVICE_TEXT,
268 .Parameters.QueryDeviceText.DeviceTextType = Type,
269 .Parameters.QueryDeviceText.LocaleId = LocaleId
270 };
271
272 NTSTATUS status;
273 status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longText);
274 if (NT_SUCCESS(status))
275 {
276 *DeviceText = (PVOID)longText;
277 }
278
279 return status;
280 }
281
282 // IRP_MN_QUERY_PNP_DEVICE_STATE (0x14)
283 NTSTATUS
PiIrpQueryPnPDeviceState(_In_ PDEVICE_NODE DeviceNode,_Out_ PPNP_DEVICE_STATE DeviceState)284 PiIrpQueryPnPDeviceState(
285 _In_ PDEVICE_NODE DeviceNode,
286 _Out_ PPNP_DEVICE_STATE DeviceState)
287 {
288 PAGED_CODE();
289
290 ASSERT(DeviceNode);
291 ASSERT(DeviceNode->State == DeviceNodeStartPostWork ||
292 DeviceNode->State == DeviceNodeStarted);
293
294 ULONG_PTR longState;
295 IO_STACK_LOCATION stack = {
296 .MajorFunction = IRP_MJ_PNP,
297 .MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE
298 };
299
300 NTSTATUS status;
301 status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longState);
302 if (NT_SUCCESS(status))
303 {
304 *DeviceState = longState;
305 }
306
307 return status;
308 }
309