Sync with trunk (r48545)
[reactos.git] / 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 UNICODE_STRING DeviceName;
161 UNICODE_STRING DeviceNamePrefix = RTL_CONSTANT_STRING(L"\\??\\");
162
163 DPRINT("PopAddRemoveSysCapsCallback(%p %p)\n",
164 NotificationStructure, Context);
165
166 Notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION)NotificationStructure;
167 if (Notification->Version != 1)
168 return STATUS_REVISION_MISMATCH;
169 if (Notification->Size != sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION))
170 return STATUS_INVALID_PARAMETER;
171 if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID) == sizeof(GUID)))
172 Arrival = TRUE;
173 else if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID) == sizeof(GUID)))
174 Arrival = FALSE;
175 else
176 return STATUS_INVALID_PARAMETER;
177
178 if (Arrival)
179 {
180 DPRINT("Arrival of %wZ\n", Notification->SymbolicLinkName);
181
182 DeviceName.Length = 0;
183 DeviceName.MaximumLength = Notification->SymbolicLinkName->MaximumLength + DeviceNamePrefix.MaximumLength;
184 DeviceName.Buffer = ExAllocatePool(PagedPool, DeviceName.MaximumLength);
185 if (!DeviceName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
186
187 RtlCopyUnicodeString(&DeviceName, &DeviceNamePrefix);
188 RtlAppendUnicodeStringToString(&DeviceName, Notification->SymbolicLinkName);
189
190 DPRINT("Opening handle to %wZ\n", &DeviceName);
191
192 /* Open the device */
193 InitializeObjectAttributes(
194 &ObjectAttributes,
195 &DeviceName,
196 OBJ_KERNEL_HANDLE,
197 NULL,
198 NULL);
199 Status = ZwOpenFile(
200 &FileHandle,
201 FILE_READ_DATA,
202 &ObjectAttributes,
203 &IoStatusBlock,
204 FILE_SHARE_READ | FILE_SHARE_WRITE,
205 0);
206 if (!NT_SUCCESS(Status))
207 {
208 DPRINT("ZwOpenFile() failed with status 0x%08lx\n", Status);
209 return Status;
210 }
211 Status = ObReferenceObjectByHandle(
212 FileHandle,
213 FILE_READ_DATA,
214 IoFileObjectType,
215 ExGetPreviousMode(),
216 (PVOID*)&FileObject,
217 NULL);
218 if (!NT_SUCCESS(Status))
219 {
220 DPRINT("ObReferenceObjectByHandle() failed with status 0x%08lx\n", Status);
221 ZwClose(FileHandle);
222 return Status;
223 }
224 DeviceObject = IoGetRelatedDeviceObject(FileObject);
225 ObDereferenceObject(FileObject);
226
227 /* Get capabilities (IOCTL_GET_SYS_BUTTON_CAPS) */
228 KeInitializeEvent(&Event, NotificationEvent, FALSE);
229 Irp = IoBuildDeviceIoControlRequest(
230 IOCTL_GET_SYS_BUTTON_CAPS,
231 DeviceObject,
232 NULL,
233 0,
234 &Caps,
235 sizeof(Caps),
236 FALSE,
237 &Event,
238 &IoStatusBlock);
239 if (!Irp)
240 {
241 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
242 ZwClose(FileHandle);
243 return STATUS_INSUFFICIENT_RESOURCES;
244 }
245 Status = IoCallDriver(DeviceObject, Irp);
246 if (Status == STATUS_PENDING)
247 {
248 DPRINT("IOCTL_GET_SYS_BUTTON_CAPS pending\n");
249 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
250 Status = IoStatusBlock.Status;
251 }
252 if (!NT_SUCCESS(Status))
253 {
254 DPRINT("Sending IOCTL_GET_SYS_BUTTON_CAPS failed with status 0x%08x\n", Status);
255 ZwClose(FileHandle);
256 return STATUS_INSUFFICIENT_RESOURCES;
257 }
258
259 /* FIXME: What do do with the capabilities? */
260 {
261 DPRINT1("Device capabilities: 0x%x (", Caps);
262 if (Caps & SYS_BUTTON_POWER) DbgPrint(" POWER");
263 if (Caps & SYS_BUTTON_SLEEP) DbgPrint(" SLEEP");
264 if (Caps & SYS_BUTTON_LID) DbgPrint(" LID");
265 DbgPrint(" )\n");
266 }
267
268 SysButtonContext = ExAllocatePool(NonPagedPool, sizeof(SYS_BUTTON_CONTEXT));
269 if (!SysButtonContext)
270 {
271 DPRINT("ExAllocatePool() failed\n");
272 ZwClose(FileHandle);
273 return STATUS_INSUFFICIENT_RESOURCES;
274 }
275
276 /* Queue a work item to get sys button event */
277 SysButtonContext->WorkItem = IoAllocateWorkItem(DeviceObject);
278 SysButtonContext->DeviceObject = DeviceObject;
279 if (!SysButtonContext->WorkItem)
280 {
281 DPRINT("IoAllocateWorkItem() failed\n");
282 ZwClose(FileHandle);
283 ExFreePool(SysButtonContext);
284 return STATUS_INSUFFICIENT_RESOURCES;
285 }
286 IoQueueWorkItem(
287 SysButtonContext->WorkItem,
288 PopGetSysButton,
289 DelayedWorkQueue,
290 SysButtonContext);
291
292 ZwClose(FileHandle);
293 return STATUS_SUCCESS;
294 }
295 else
296 {
297 DPRINT1("Removal of a power capable device not implemented\n");
298 return STATUS_NOT_IMPLEMENTED;
299 }
300 }