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