[DDK]: Merge 46183 from header-branch.
[reactos.git] / reactos / ntoskrnl / po / events.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/po/events.c
5 * PURPOSE: Power Manager
6 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 typedef struct _SYS_BUTTON_CONTEXT
18 {
19 PDEVICE_OBJECT DeviceObject;
20 PIO_WORKITEM WorkItem;
21 KEVENT Event;
22 IO_STATUS_BLOCK IoStatusBlock;
23 ULONG SysButton;
24 } SYS_BUTTON_CONTEXT, *PSYS_BUTTON_CONTEXT;
25
26 static VOID
27 NTAPI
28 PopGetSysButton(
29 IN PDEVICE_OBJECT DeviceObject,
30 IN PVOID Context);
31
32 PKWIN32_POWEREVENT_CALLOUT PopEventCallout;
33 extern PCALLBACK_OBJECT SetSystemTimeCallback;
34
35 /* FUNCTIONS *****************************************************************/
36
37 VOID
38 NTAPI
39 PoNotifySystemTimeSet(VOID)
40 {
41 KIRQL OldIrql;
42
43 /* Check if Win32k registered a notification callback */
44 if (PopEventCallout)
45 {
46 /* Raise to dispatch */
47 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
48
49 /* Notify the callback */
50 ExNotifyCallback(SetSystemTimeCallback, NULL, NULL);
51
52 /* Lower IRQL back */
53 KeLowerIrql(OldIrql);
54 }
55 }
56
57 static NTSTATUS
58 NTAPI
59 PopGetSysButtonCompletion(
60 IN PDEVICE_OBJECT DeviceObject,
61 IN PIRP Irp,
62 IN PVOID Context)
63 {
64 PSYS_BUTTON_CONTEXT SysButtonContext = Context;
65 ULONG SysButton;
66
67 if (Irp->PendingReturned)
68 IoMarkIrpPending(Irp);
69
70 /* The DeviceObject can be NULL, so use the one we stored */
71 DeviceObject = SysButtonContext->DeviceObject;
72
73 /* FIXME: What do do with the sys button event? */
74 SysButton = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
75 {
76 DPRINT1("A device reported the event 0x%x (", SysButton);
77 if (SysButton & SYS_BUTTON_POWER) DbgPrint(" POWER");
78 if (SysButton & SYS_BUTTON_SLEEP) DbgPrint(" SLEEP");
79 if (SysButton & SYS_BUTTON_LID) DbgPrint(" LID");
80 if (SysButton == 0) DbgPrint(" WAKE");
81 DbgPrint(" )\n");
82 }
83
84 /* Allocate a new workitem to send the next IOCTL_GET_SYS_BUTTON_EVENT */
85 SysButtonContext->WorkItem = IoAllocateWorkItem(DeviceObject);
86 if (!SysButtonContext->WorkItem)
87 {
88 DPRINT("IoAllocateWorkItem() failed\n");
89 ExFreePool(SysButtonContext);
90 return STATUS_SUCCESS;
91 }
92 IoQueueWorkItem(
93 SysButtonContext->WorkItem,
94 PopGetSysButton,
95 DelayedWorkQueue,
96 SysButtonContext);
97
98 return STATUS_SUCCESS /* STATUS_CONTINUE_COMPLETION */;
99 }
100
101 static VOID
102 NTAPI
103 PopGetSysButton(
104 IN PDEVICE_OBJECT DeviceObject,
105 IN PVOID Context)
106 {
107 PSYS_BUTTON_CONTEXT SysButtonContext = Context;
108 PIO_WORKITEM CurrentWorkItem = SysButtonContext->WorkItem;
109 PIRP Irp;
110
111 /* Get button pressed (IOCTL_GET_SYS_BUTTON_EVENT) */
112 KeInitializeEvent(&SysButtonContext->Event, NotificationEvent, FALSE);
113 Irp = IoBuildDeviceIoControlRequest(
114 IOCTL_GET_SYS_BUTTON_EVENT,
115 DeviceObject,
116 NULL,
117 0,
118 &SysButtonContext->SysButton,
119 sizeof(SysButtonContext->SysButton),
120 FALSE,
121 &SysButtonContext->Event,
122 &SysButtonContext->IoStatusBlock);
123 if (Irp)
124 {
125 IoSetCompletionRoutine(
126 Irp,
127 PopGetSysButtonCompletion,
128 SysButtonContext,
129 TRUE,
130 FALSE,
131 FALSE);
132 IoCallDriver(DeviceObject, Irp);
133 }
134 else
135 {
136 DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
137 ExFreePool(SysButtonContext);
138 }
139
140 IoFreeWorkItem(CurrentWorkItem);
141 }
142
143 NTSTATUS
144 NTAPI
145 PopAddRemoveSysCapsCallback(IN PVOID NotificationStructure,
146 IN PVOID Context)
147 {
148 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification;
149 PSYS_BUTTON_CONTEXT SysButtonContext;
150 OBJECT_ATTRIBUTES ObjectAttributes;
151 HANDLE FileHandle;
152 PDEVICE_OBJECT DeviceObject;
153 PFILE_OBJECT FileObject;
154 PIRP Irp;
155 IO_STATUS_BLOCK IoStatusBlock;
156 KEVENT Event;
157 BOOLEAN Arrival;
158 ULONG Caps;
159 NTSTATUS Status;
160
161 DPRINT("PopAddRemoveSysCapsCallback(%p %p)\n",
162 NotificationStructure, Context);
163
164 Notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION)NotificationStructure;
165 if (Notification->Version != 1)
166 return STATUS_REVISION_MISMATCH;
167 if (Notification->Size != sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION))
168 return STATUS_INVALID_PARAMETER;
169 if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID) == sizeof(GUID)))
170 Arrival = TRUE;
171 else if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID) == sizeof(GUID)))
172 Arrival = FALSE;
173 else
174 return STATUS_INVALID_PARAMETER;
175
176 if (Arrival)
177 {
178 DPRINT("Arrival of %wZ\n", Notification->SymbolicLinkName);
179
180 /* Open the device */
181 InitializeObjectAttributes(
182 &ObjectAttributes,
183 Notification->SymbolicLinkName,
184 OBJ_KERNEL_HANDLE,
185 NULL,
186 NULL);
187 Status = ZwOpenFile(
188 &FileHandle,
189 FILE_READ_DATA,
190 &ObjectAttributes,
191 &IoStatusBlock,
192 FILE_SHARE_READ | FILE_SHARE_WRITE,
193 0);
194 if (!NT_SUCCESS(Status))
195 {
196 DPRINT("ZwOpenFile() failed with status 0x%08lx\n", Status);
197 return Status;
198 }
199 Status = ObReferenceObjectByHandle(
200 FileHandle,
201 FILE_READ_DATA,
202 IoFileObjectType,
203 ExGetPreviousMode(),
204 (PVOID*)&FileObject,
205 NULL);
206 if (!NT_SUCCESS(Status))
207 {
208 DPRINT("ObReferenceObjectByHandle() failed with status 0x%08lx\n", Status);
209 ZwClose(FileHandle);
210 return Status;
211 }
212 DeviceObject = IoGetRelatedDeviceObject(FileObject);
213 ObDereferenceObject(FileObject);
214
215 /* Get capabilities (IOCTL_GET_SYS_BUTTON_CAPS) */
216 KeInitializeEvent(&Event, NotificationEvent, FALSE);
217 Irp = IoBuildDeviceIoControlRequest(
218 IOCTL_GET_SYS_BUTTON_CAPS,
219 DeviceObject,
220 NULL,
221 0,
222 &Caps,
223 sizeof(Caps),
224 FALSE,
225 &Event,
226 &IoStatusBlock);
227 if (!Irp)
228 {
229 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
230 ZwClose(FileHandle);
231 return STATUS_INSUFFICIENT_RESOURCES;
232 }
233 Status = IoCallDriver(DeviceObject, Irp);
234 if (Status == STATUS_PENDING)
235 {
236 DPRINT("IOCTL_GET_SYS_BUTTON_CAPS pending\n");
237 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
238 Status = IoStatusBlock.Status;
239 }
240 if (!NT_SUCCESS(Status))
241 {
242 DPRINT("Sending IOCTL_GET_SYS_BUTTON_CAPS failed with status 0x%08x\n", Status);
243 ZwClose(FileHandle);
244 return STATUS_INSUFFICIENT_RESOURCES;
245 }
246
247 /* FIXME: What do do with the capabilities? */
248 {
249 DPRINT1("Device capabilities: 0x%x (", Caps);
250 if (Caps & SYS_BUTTON_POWER) DbgPrint(" POWER");
251 if (Caps & SYS_BUTTON_SLEEP) DbgPrint(" SLEEP");
252 if (Caps & SYS_BUTTON_LID) DbgPrint(" LID");
253 DbgPrint(" )\n");
254 }
255
256 SysButtonContext = ExAllocatePool(NonPagedPool, sizeof(SYS_BUTTON_CONTEXT));
257 if (!SysButtonContext)
258 {
259 DPRINT("ExAllocatePool() failed\n");
260 ZwClose(FileHandle);
261 return STATUS_INSUFFICIENT_RESOURCES;
262 }
263
264 /* Queue a work item to get sys button event */
265 SysButtonContext->WorkItem = IoAllocateWorkItem(DeviceObject);
266 SysButtonContext->DeviceObject = DeviceObject;
267 if (!SysButtonContext->WorkItem)
268 {
269 DPRINT("IoAllocateWorkItem() failed\n");
270 ZwClose(FileHandle);
271 ExFreePool(SysButtonContext);
272 return STATUS_INSUFFICIENT_RESOURCES;
273 }
274 IoQueueWorkItem(
275 SysButtonContext->WorkItem,
276 PopGetSysButton,
277 DelayedWorkQueue,
278 SysButtonContext);
279
280 ZwClose(FileHandle);
281 return STATUS_SUCCESS;
282 }
283 else
284 {
285 DPRINT1("Removal of a power capable device not implemented\n");
286 return STATUS_NOT_IMPLEMENTED;
287 }
288 }