xref: /reactos/ntoskrnl/io/pnpmgr/pnpirp.c (revision 2196a06f)
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_DEVICE_TEXT (0x0C)
200 NTSTATUS
201 PiIrpQueryDeviceText(
202     _In_ PDEVICE_NODE DeviceNode,
203     _In_ LCID LocaleId,
204     _In_ DEVICE_TEXT_TYPE Type,
205     _Out_ PWSTR *DeviceText)
206 {
207     PAGED_CODE();
208 
209     ASSERT(DeviceNode);
210     ASSERT(DeviceNode->State == DeviceNodeUninitialized);
211 
212     ULONG_PTR longText;
213     IO_STACK_LOCATION stack = {
214         .MajorFunction = IRP_MJ_PNP,
215         .MinorFunction = IRP_MN_QUERY_DEVICE_TEXT,
216         .Parameters.QueryDeviceText.DeviceTextType = Type,
217         .Parameters.QueryDeviceText.LocaleId = LocaleId
218     };
219 
220     NTSTATUS status;
221     status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longText);
222     if (NT_SUCCESS(status))
223     {
224         *DeviceText = (PVOID)longText;
225     }
226 
227     return status;
228 }
229 
230 // IRP_MN_QUERY_PNP_DEVICE_STATE (0x14)
231 NTSTATUS
232 PiIrpQueryPnPDeviceState(
233     _In_ PDEVICE_NODE DeviceNode,
234     _Out_ PPNP_DEVICE_STATE DeviceState)
235 {
236     PAGED_CODE();
237 
238     ASSERT(DeviceNode);
239     ASSERT(DeviceNode->State == DeviceNodeStartPostWork ||
240            DeviceNode->State == DeviceNodeStarted);
241 
242     ULONG_PTR longState;
243     IO_STACK_LOCATION stack = {
244         .MajorFunction = IRP_MJ_PNP,
245         .MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE
246     };
247 
248     NTSTATUS status;
249     status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject, &stack, (PVOID)&longState);
250     if (NT_SUCCESS(status))
251     {
252         *DeviceState = longState;
253     }
254 
255     return status;
256 }
257