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