1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Power IRP management test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 #include "PoIrp.h"
10 
11 static PDRIVER_OBJECT TestDriverObject;
12 static KMT_MESSAGE_HANDLER TestMessageHandler;
13 
14 static PDEVICE_OBJECT DeviceObject1;
15 static PDEVICE_OBJECT DeviceObject2;
16 static PDEVICE_OBJECT DeviceObject3;
17 
18 static
19 NTSTATUS
CreateTestDevices(_In_ PDRIVER_OBJECT DriverObject)20 CreateTestDevices(
21     _In_ PDRIVER_OBJECT DriverObject)
22 {
23     NTSTATUS Status;
24     PDEVICE_OBJECT AttachedDevice;
25 
26     Status = IoCreateDevice(DriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject1);
27     if (!NT_SUCCESS(Status))
28         return Status;
29 
30     DeviceObject1->Flags &= ~DO_DEVICE_INITIALIZING;
31 
32     Status = IoCreateDevice(DriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject2);
33     if (!NT_SUCCESS(Status))
34     {
35         IoDeleteDevice(DeviceObject1);
36         return Status;
37     }
38 
39     AttachedDevice = IoAttachDeviceToDeviceStack(DeviceObject2, DeviceObject1);
40     ok(AttachedDevice == DeviceObject1, "Device attached to %p is %p, expected %p\n", DeviceObject2, AttachedDevice, DeviceObject1);
41     if (AttachedDevice == NULL)
42     {
43         IoDeleteDevice(DeviceObject2);
44         IoDeleteDevice(DeviceObject1);
45         return STATUS_UNSUCCESSFUL;
46     }
47 
48     DeviceObject2->Flags &= ~DO_DEVICE_INITIALIZING;
49 
50     Status = IoCreateDevice(DriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject3);
51     if (!NT_SUCCESS(Status))
52     {
53         IoDetachDevice(DeviceObject1);
54         IoDeleteDevice(DeviceObject2);
55         IoDeleteDevice(DeviceObject1);
56         return Status;
57     }
58 
59     AttachedDevice = IoAttachDeviceToDeviceStack(DeviceObject3, DeviceObject1);
60     ok(AttachedDevice == DeviceObject2, "Device attached to %p is %p, expected %p\n", DeviceObject2, AttachedDevice, DeviceObject2);
61     if (AttachedDevice == NULL)
62     {
63         IoDeleteDevice(DeviceObject3);
64         IoDetachDevice(DeviceObject1);
65         IoDeleteDevice(DeviceObject2);
66         IoDeleteDevice(DeviceObject1);
67         return STATUS_UNSUCCESSFUL;
68     }
69 
70     DeviceObject3->Flags &= ~DO_DEVICE_INITIALIZING;
71 
72     return Status;
73 }
74 
75 NTSTATUS
TestEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PCUNICODE_STRING RegistryPath,_Out_ PCWSTR * DeviceName,_Inout_ INT * Flags)76 TestEntry(
77     _In_ PDRIVER_OBJECT DriverObject,
78     _In_ PCUNICODE_STRING RegistryPath,
79     _Out_ PCWSTR *DeviceName,
80     _Inout_ INT *Flags)
81 {
82     NTSTATUS Status = STATUS_SUCCESS;
83 
84     PAGED_CODE();
85 
86     UNREFERENCED_PARAMETER(RegistryPath);
87 
88     TestDriverObject = DriverObject;
89 
90     *DeviceName = L"PoIrp";
91     *Flags = TESTENTRY_NO_EXCLUSIVE_DEVICE;
92 
93     KmtRegisterMessageHandler(0, NULL, TestMessageHandler);
94 
95     return Status;
96 }
97 
98 VOID
TestUnload(IN PDRIVER_OBJECT DriverObject)99 TestUnload(
100     IN PDRIVER_OBJECT DriverObject)
101 {
102     UNREFERENCED_PARAMETER(DriverObject);
103 
104     PAGED_CODE();
105 }
106 
107 //
108 // PoRequestPowerIrp test
109 //
110 static KEVENT TestDoneEvent;
111 static PIRP RequestedPowerIrp;
112 static PIRP RequestedPowerIrpReturned;
113 
114 static
115 VOID
116 NTAPI
RequestedPowerCompletion(_In_ PDEVICE_OBJECT DeviceObject,_In_ UCHAR MinorFunction,_In_ POWER_STATE PowerState,_In_opt_ PVOID Context,_In_ PIO_STATUS_BLOCK IoStatus)117 RequestedPowerCompletion(
118     _In_ PDEVICE_OBJECT DeviceObject,
119     _In_ UCHAR MinorFunction,
120     _In_ POWER_STATE PowerState,
121     _In_opt_ PVOID Context,
122     _In_ PIO_STATUS_BLOCK IoStatus)
123 {
124     PIRP Irp;
125     PIO_STACK_LOCATION IoStackLocation;
126 
127     ok_eq_pointer(DeviceObject, DeviceObject2);
128     ok_eq_uint(MinorFunction, IRP_MN_SET_POWER);
129     ok_eq_uint(PowerState.DeviceState, PowerDeviceD0);
130     ok_eq_pointer(Context, &RequestedPowerIrp);
131     Irp = CONTAINING_RECORD(IoStatus, IRP, IoStatus);
132     ok_eq_pointer(Irp, RequestedPowerIrp);
133     ok_eq_ulongptr(IoStatus->Information, 7);
134     ok_eq_hex(IoStatus->Status, STATUS_WAIT_3);
135     KeSetEvent(&TestDoneEvent, IO_NO_INCREMENT, FALSE);
136 
137     ok_eq_uint(Irp->StackCount, 5);
138     ok_eq_uint(Irp->CurrentLocation, 4);
139     ok_eq_pointer(Irp->Tail.Overlay.Thread, NULL);
140     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
141     ok_eq_uint(IoStackLocation->MajorFunction, 0);
142     ok_eq_uint(IoStackLocation->MinorFunction, 0);
143     ok_eq_pointer(IoStackLocation->CompletionRoutine, NULL);
144     ok_eq_pointer(IoStackLocation->Context, NULL);
145     ok_eq_pointer(IoStackLocation->Parameters.Others.Argument1, DeviceObject);
146     ok_eq_pointer(IoStackLocation->Parameters.Others.Argument2, (PVOID)(ULONG_PTR)MinorFunction);
147     ok_eq_pointer(IoStackLocation->Parameters.Others.Argument3, (PVOID)(ULONG_PTR)PowerState.SystemState);
148     ok_eq_pointer(IoStackLocation->Parameters.Others.Argument4, Context);
149 }
150 
151 static
152 NTSTATUS
RequestedPowerIrpHandler(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp,_In_ PIO_STACK_LOCATION IoStackLocation)153 RequestedPowerIrpHandler(
154     _In_ PDEVICE_OBJECT DeviceObject,
155     _In_ PIRP Irp,
156     _In_ PIO_STACK_LOCATION IoStackLocation)
157 {
158     if (RequestedPowerIrp == NULL)
159         RequestedPowerIrp = Irp;
160     else
161         ok_eq_pointer(Irp, RequestedPowerIrp);
162 
163     ok_eq_uint(Irp->StackCount, 5);
164     ok_eq_ulongptr(Irp->IoStatus.Information, 0);
165     ok_eq_hex(Irp->IoStatus.Status, STATUS_NOT_SUPPORTED);
166     ok_eq_pointer(Irp->Tail.Overlay.Thread, NULL);
167     ok_eq_uint(IoStackLocation->MajorFunction, IRP_MJ_POWER);
168     ok_eq_uint(IoStackLocation->MinorFunction, IRP_MN_SET_POWER);
169     ok_eq_pointer(IoStackLocation->Context, RequestedPowerCompletion);
170     ok_eq_uint(IoStackLocation->Parameters.Power.Type, DevicePowerState);
171     ok_eq_uint(IoStackLocation->Parameters.Power.State.DeviceState, PowerDeviceD0);
172 
173     if (DeviceObject == DeviceObject1)
174     {
175         ok_eq_uint(Irp->CurrentLocation, 3);
176         Irp->IoStatus.Information = 7;
177         Irp->IoStatus.Status = STATUS_WAIT_3;
178         PoStartNextPowerIrp(Irp);
179         IoCompleteRequest(Irp, IO_NO_INCREMENT);
180         return STATUS_SUCCESS;
181     }
182     else if (DeviceObject == DeviceObject2)
183     {
184         ok_eq_uint(Irp->CurrentLocation, 3);
185         PoStartNextPowerIrp(Irp);
186         IoSkipCurrentIrpStackLocation(Irp);
187         return PoCallDriver(DeviceObject1, Irp);
188     }
189     else if (DeviceObject == DeviceObject3)
190     {
191         ok_eq_uint(Irp->CurrentLocation, 3);
192         PoStartNextPowerIrp(Irp);
193         IoSkipCurrentIrpStackLocation(Irp);
194         return PoCallDriver(DeviceObject2, Irp);
195     }
196     else
197     {
198         ok(0, "\n");
199         PoStartNextPowerIrp(Irp);
200         IoCompleteRequest(Irp, IO_NO_INCREMENT);
201         return STATUS_NOT_SUPPORTED;
202     }
203 }
204 
205 static
206 VOID
TestPoRequestPowerIrp(VOID)207 TestPoRequestPowerIrp(VOID)
208 {
209     NTSTATUS Status;
210     POWER_STATE PowerState;
211 
212     KmtRegisterIrpHandler(IRP_MJ_POWER, NULL, RequestedPowerIrpHandler);
213 
214     KeInitializeEvent(&TestDoneEvent, NotificationEvent, FALSE);
215 
216     PowerState.DeviceState = PowerDeviceD0;
217     Status = PoRequestPowerIrp(DeviceObject2,
218                                IRP_MN_SET_POWER,
219                                PowerState,
220                                RequestedPowerCompletion,
221                                &RequestedPowerIrp,
222                                &RequestedPowerIrpReturned);
223     ok(Status == STATUS_PENDING, "PoRequestPowerIrp returned %lx\n", Status);
224     ok_eq_pointer(RequestedPowerIrpReturned, RequestedPowerIrp);
225 
226     Status = KeWaitForSingleObject(&TestDoneEvent, Executive, KernelMode, FALSE, NULL);
227     ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
228     KmtUnregisterIrpHandler(IRP_MJ_POWER, NULL, RequestedPowerIrpHandler);
229 }
230 
231 
232 //
233 // Message handler
234 //
235 static
236 NTSTATUS
TestMessageHandler(_In_ PDEVICE_OBJECT DeviceObject,_In_ ULONG ControlCode,_In_ PVOID Buffer OPTIONAL,_In_ SIZE_T InLength,_Inout_ PSIZE_T OutLength)237 TestMessageHandler(
238     _In_ PDEVICE_OBJECT DeviceObject,
239     _In_ ULONG ControlCode,
240     _In_ PVOID Buffer OPTIONAL,
241     _In_ SIZE_T InLength,
242     _Inout_ PSIZE_T OutLength)
243 {
244     NTSTATUS Status = STATUS_SUCCESS;
245 
246     PAGED_CODE();
247 
248     switch (ControlCode)
249     {
250         case IOCTL_RUN_TEST:
251         {
252             Status = CreateTestDevices(TestDriverObject);
253             ok_eq_hex(Status, STATUS_SUCCESS);
254             if (!NT_SUCCESS(Status))
255                 return Status;
256 
257             TestPoRequestPowerIrp();
258 
259             IoDetachDevice(DeviceObject2);
260             IoDeleteDevice(DeviceObject3);
261             IoDetachDevice(DeviceObject1);
262             IoDeleteDevice(DeviceObject2);
263             IoDeleteDevice(DeviceObject1);
264 
265             break;
266         }
267         default:
268             return STATUS_NOT_SUPPORTED;
269     }
270 
271     return Status;
272 }
273