[NTOSKRNL]
[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 if (SysButton & SYS_BUTTON_POWER)
84 {
85 /* FIXME: Read registry for the action we should perform here */
86 DPRINT1("Initiating shutdown after power button event\n");
87
88 ZwShutdownSystem(ShutdownNoReboot);
89 }
90
91 }
92
93 /* Allocate a new workitem to send the next IOCTL_GET_SYS_BUTTON_EVENT */
94 SysButtonContext->WorkItem = IoAllocateWorkItem(DeviceObject);
95 if (!SysButtonContext->WorkItem)
96 {
97 DPRINT("IoAllocateWorkItem() failed\n");
98 ExFreePool(SysButtonContext);
99 return STATUS_SUCCESS;
100 }
101 IoQueueWorkItem(
102 SysButtonContext->WorkItem,
103 PopGetSysButton,
104 DelayedWorkQueue,
105 SysButtonContext);
106
107 return STATUS_SUCCESS /* STATUS_CONTINUE_COMPLETION */;
108 }
109
110 static VOID
111 NTAPI
112 PopGetSysButton(
113 IN PDEVICE_OBJECT DeviceObject,
114 IN PVOID Context)
115 {
116 PSYS_BUTTON_CONTEXT SysButtonContext = Context;
117 PIO_WORKITEM CurrentWorkItem = SysButtonContext->WorkItem;
118 PIRP Irp;
119
120 /* Get button pressed (IOCTL_GET_SYS_BUTTON_EVENT) */
121 KeInitializeEvent(&SysButtonContext->Event, NotificationEvent, FALSE);
122 Irp = IoBuildDeviceIoControlRequest(
123 IOCTL_GET_SYS_BUTTON_EVENT,
124 DeviceObject,
125 NULL,
126 0,
127 &SysButtonContext->SysButton,
128 sizeof(SysButtonContext->SysButton),
129 FALSE,
130 &SysButtonContext->Event,
131 &SysButtonContext->IoStatusBlock);
132 if (Irp)
133 {
134 IoSetCompletionRoutine(
135 Irp,
136 PopGetSysButtonCompletion,
137 SysButtonContext,
138 TRUE,
139 FALSE,
140 FALSE);
141 IoCallDriver(DeviceObject, Irp);
142 }
143 else
144 {
145 DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
146 ExFreePool(SysButtonContext);
147 }
148
149 IoFreeWorkItem(CurrentWorkItem);
150 }
151
152 NTSTATUS
153 NTAPI
154 PopAddRemoveSysCapsCallback(IN PVOID NotificationStructure,
155 IN PVOID Context)
156 {
157 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification;
158 PSYS_BUTTON_CONTEXT SysButtonContext;
159 OBJECT_ATTRIBUTES ObjectAttributes;
160 HANDLE FileHandle;
161 PDEVICE_OBJECT DeviceObject;
162 PFILE_OBJECT FileObject;
163 PIRP Irp;
164 IO_STATUS_BLOCK IoStatusBlock;
165 KEVENT Event;
166 BOOLEAN Arrival;
167 ULONG Caps;
168 NTSTATUS Status;
169 UNICODE_STRING DeviceName;
170 UNICODE_STRING DeviceNamePrefix = RTL_CONSTANT_STRING(L"\\??\\");
171
172 DPRINT("PopAddRemoveSysCapsCallback(%p %p)\n",
173 NotificationStructure, Context);
174
175 Notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION)NotificationStructure;
176 if (Notification->Version != 1)
177 return STATUS_REVISION_MISMATCH;
178 if (Notification->Size != sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION))
179 return STATUS_INVALID_PARAMETER;
180 if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID) == sizeof(GUID)))
181 Arrival = TRUE;
182 else if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID) == sizeof(GUID)))
183 Arrival = FALSE;
184 else
185 return STATUS_INVALID_PARAMETER;
186
187 if (Arrival)
188 {
189 DPRINT("Arrival of %wZ\n", Notification->SymbolicLinkName);
190
191 DeviceName.Length = 0;
192 DeviceName.MaximumLength = Notification->SymbolicLinkName->MaximumLength + DeviceNamePrefix.MaximumLength;
193 DeviceName.Buffer = ExAllocatePool(PagedPool, DeviceName.MaximumLength);
194 if (!DeviceName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
195
196 RtlCopyUnicodeString(&DeviceName, &DeviceNamePrefix);
197 RtlAppendUnicodeStringToString(&DeviceName, Notification->SymbolicLinkName);
198
199 DPRINT("Opening handle to %wZ\n", &DeviceName);
200
201 /* Open the device */
202 InitializeObjectAttributes(
203 &ObjectAttributes,
204 &DeviceName,
205 OBJ_KERNEL_HANDLE,
206 NULL,
207 NULL);
208 Status = ZwOpenFile(
209 &FileHandle,
210 FILE_READ_DATA,
211 &ObjectAttributes,
212 &IoStatusBlock,
213 FILE_SHARE_READ | FILE_SHARE_WRITE,
214 0);
215 if (!NT_SUCCESS(Status))
216 {
217 DPRINT("ZwOpenFile() failed with status 0x%08lx\n", Status);
218 return Status;
219 }
220 Status = ObReferenceObjectByHandle(
221 FileHandle,
222 FILE_READ_DATA,
223 IoFileObjectType,
224 ExGetPreviousMode(),
225 (PVOID*)&FileObject,
226 NULL);
227 if (!NT_SUCCESS(Status))
228 {
229 DPRINT("ObReferenceObjectByHandle() failed with status 0x%08lx\n", Status);
230 ZwClose(FileHandle);
231 return Status;
232 }
233 DeviceObject = IoGetRelatedDeviceObject(FileObject);
234 ObDereferenceObject(FileObject);
235
236 /* Get capabilities (IOCTL_GET_SYS_BUTTON_CAPS) */
237 KeInitializeEvent(&Event, NotificationEvent, FALSE);
238 Irp = IoBuildDeviceIoControlRequest(
239 IOCTL_GET_SYS_BUTTON_CAPS,
240 DeviceObject,
241 NULL,
242 0,
243 &Caps,
244 sizeof(Caps),
245 FALSE,
246 &Event,
247 &IoStatusBlock);
248 if (!Irp)
249 {
250 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
251 ZwClose(FileHandle);
252 return STATUS_INSUFFICIENT_RESOURCES;
253 }
254 Status = IoCallDriver(DeviceObject, Irp);
255 if (Status == STATUS_PENDING)
256 {
257 DPRINT("IOCTL_GET_SYS_BUTTON_CAPS pending\n");
258 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
259 Status = IoStatusBlock.Status;
260 }
261 if (!NT_SUCCESS(Status))
262 {
263 DPRINT("Sending IOCTL_GET_SYS_BUTTON_CAPS failed with status 0x%08x\n", Status);
264 ZwClose(FileHandle);
265 return STATUS_INSUFFICIENT_RESOURCES;
266 }
267
268 /* FIXME: What do do with the capabilities? */
269 {
270 DPRINT1("Device capabilities: 0x%x (", Caps);
271 if (Caps & SYS_BUTTON_POWER) DbgPrint(" POWER");
272 if (Caps & SYS_BUTTON_SLEEP) DbgPrint(" SLEEP");
273 if (Caps & SYS_BUTTON_LID) DbgPrint(" LID");
274 DbgPrint(" )\n");
275 }
276
277 SysButtonContext = ExAllocatePool(NonPagedPool, sizeof(SYS_BUTTON_CONTEXT));
278 if (!SysButtonContext)
279 {
280 DPRINT("ExAllocatePool() failed\n");
281 ZwClose(FileHandle);
282 return STATUS_INSUFFICIENT_RESOURCES;
283 }
284
285 /* Queue a work item to get sys button event */
286 SysButtonContext->WorkItem = IoAllocateWorkItem(DeviceObject);
287 SysButtonContext->DeviceObject = DeviceObject;
288 if (!SysButtonContext->WorkItem)
289 {
290 DPRINT("IoAllocateWorkItem() failed\n");
291 ZwClose(FileHandle);
292 ExFreePool(SysButtonContext);
293 return STATUS_INSUFFICIENT_RESOURCES;
294 }
295 IoQueueWorkItem(
296 SysButtonContext->WorkItem,
297 PopGetSysButton,
298 DelayedWorkQueue,
299 SysButtonContext);
300
301 ZwClose(FileHandle);
302 return STATUS_SUCCESS;
303 }
304 else
305 {
306 DPRINT1("Removal of a power capable device not implemented\n");
307 return STATUS_NOT_IMPLEMENTED;
308 }
309 }