[KMTESTS:PO]
[reactos.git] / rostests / kmtests / ntos_po / PoIrp_drv.c
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
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
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
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
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 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
140 ok_eq_pointer(IoStackLocation->Parameters.Others.Argument1, DeviceObject);
141 ok_eq_pointer(IoStackLocation->Parameters.Others.Argument2, (PVOID)MinorFunction);
142 ok_eq_pointer(IoStackLocation->Parameters.Others.Argument3, (PVOID)PowerState.SystemState);
143 ok_eq_pointer(IoStackLocation->Parameters.Others.Argument4, Context);
144 }
145
146 static
147 NTSTATUS
148 RequestedPowerIrpHandler(
149 _In_ PDEVICE_OBJECT DeviceObject,
150 _In_ PIRP Irp,
151 _In_ PIO_STACK_LOCATION IoStackLocation)
152 {
153 if (RequestedPowerIrp == NULL)
154 RequestedPowerIrp = Irp;
155 else
156 ok_eq_pointer(Irp, RequestedPowerIrp);
157
158 ok_eq_uint(Irp->StackCount, 5);
159 ok_eq_ulongptr(Irp->IoStatus.Information, 0);
160 ok_eq_hex(Irp->IoStatus.Status, STATUS_NOT_SUPPORTED);
161 ok_eq_uint(IoStackLocation->MajorFunction, IRP_MJ_POWER);
162 ok_eq_uint(IoStackLocation->MinorFunction, IRP_MN_SET_POWER);
163 ok_eq_uint(IoStackLocation->Parameters.Power.Type, DevicePowerState);
164 ok_eq_uint(IoStackLocation->Parameters.Power.State.DeviceState, PowerDeviceD0);
165
166 if (DeviceObject == DeviceObject1)
167 {
168 ok_eq_uint(Irp->CurrentLocation, 3);
169 Irp->IoStatus.Information = 7;
170 Irp->IoStatus.Status = STATUS_WAIT_3;
171 PoStartNextPowerIrp(Irp);
172 IoCompleteRequest(Irp, IO_NO_INCREMENT);
173 return STATUS_SUCCESS;
174 }
175 else if (DeviceObject == DeviceObject2)
176 {
177 ok_eq_uint(Irp->CurrentLocation, 3);
178 PoStartNextPowerIrp(Irp);
179 IoSkipCurrentIrpStackLocation(Irp);
180 return PoCallDriver(DeviceObject1, Irp);
181 }
182 else if (DeviceObject == DeviceObject3)
183 {
184 ok_eq_uint(Irp->CurrentLocation, 3);
185 PoStartNextPowerIrp(Irp);
186 IoSkipCurrentIrpStackLocation(Irp);
187 return PoCallDriver(DeviceObject2, Irp);
188 }
189 else
190 {
191 ok(0, "\n");
192 PoStartNextPowerIrp(Irp);
193 IoCompleteRequest(Irp, IO_NO_INCREMENT);
194 return STATUS_NOT_SUPPORTED;
195 }
196 }
197
198 static
199 VOID
200 TestPoRequestPowerIrp(VOID)
201 {
202 NTSTATUS Status;
203 POWER_STATE PowerState;
204
205 KmtRegisterIrpHandler(IRP_MJ_POWER, NULL, RequestedPowerIrpHandler);
206
207 KeInitializeEvent(&TestDoneEvent, NotificationEvent, FALSE);
208
209 PowerState.DeviceState = PowerDeviceD0;
210 Status = PoRequestPowerIrp(DeviceObject2,
211 IRP_MN_SET_POWER,
212 PowerState,
213 RequestedPowerCompletion,
214 &RequestedPowerIrp,
215 &RequestedPowerIrpReturned);
216 ok(Status == STATUS_PENDING, "PoRequestPowerIrp returned %lx\n", Status);
217 ok_eq_pointer(RequestedPowerIrpReturned, RequestedPowerIrp);
218
219 Status = KeWaitForSingleObject(&TestDoneEvent, Executive, KernelMode, FALSE, NULL);
220 ok(Status == STATUS_SUCCESS, "Status = %lx\n", Status);
221 KmtUnregisterIrpHandler(IRP_MJ_POWER, NULL, RequestedPowerIrpHandler);
222 }
223
224
225 //
226 // Message handler
227 //
228 static
229 NTSTATUS
230 TestMessageHandler(
231 _In_ PDEVICE_OBJECT DeviceObject,
232 _In_ ULONG ControlCode,
233 _In_ PVOID Buffer OPTIONAL,
234 _In_ SIZE_T InLength,
235 _Inout_ PSIZE_T OutLength)
236 {
237 NTSTATUS Status = STATUS_SUCCESS;
238
239 PAGED_CODE();
240
241 switch (ControlCode)
242 {
243 case IOCTL_RUN_TEST:
244 {
245 Status = CreateTestDevices(TestDriverObject);
246 ok_eq_hex(Status, STATUS_SUCCESS);
247 if (!NT_SUCCESS(Status))
248 return Status;
249
250 TestPoRequestPowerIrp();
251
252 IoDetachDevice(DeviceObject2);
253 IoDeleteDevice(DeviceObject3);
254 IoDetachDevice(DeviceObject1);
255 IoDeleteDevice(DeviceObject2);
256 IoDeleteDevice(DeviceObject1);
257
258 break;
259 }
260 default:
261 return STATUS_NOT_SUPPORTED;
262 }
263
264 return Status;
265 }