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 } 305