xref: /reactos/ntoskrnl/io/pnpmgr/pnpirp.c (revision cdf90707)
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_RESOURCES (0x0A)
200 NTSTATUS
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
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
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
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