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 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 /* Open the device */ 183 InitializeObjectAttributes(&ObjectAttributes, 184 Notification->SymbolicLinkName, 185 OBJ_KERNEL_HANDLE, 186 NULL, 187 NULL); 188 Status = ZwOpenFile(&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 DPRINT1("ZwOpenFile() failed with status 0x%08lx\n", Status); 197 return Status; 198 } 199 Status = ObReferenceObjectByHandle(FileHandle, 200 FILE_READ_DATA, 201 IoFileObjectType, 202 KernelMode, 203 (PVOID*)&FileObject, 204 NULL); 205 if (!NT_SUCCESS(Status)) 206 { 207 DPRINT1("ObReferenceObjectByHandle() failed with status 0x%08lx\n", Status); 208 ZwClose(FileHandle); 209 return Status; 210 } 211 DeviceObject = IoGetRelatedDeviceObject(FileObject); 212 ObDereferenceObject(FileObject); 213 214 /* Get capabilities (IOCTL_GET_SYS_BUTTON_CAPS) */ 215 KeInitializeEvent(&Event, NotificationEvent, FALSE); 216 Irp = IoBuildDeviceIoControlRequest(IOCTL_GET_SYS_BUTTON_CAPS, 217 DeviceObject, 218 NULL, 219 0, 220 &Caps, 221 sizeof(Caps), 222 FALSE, 223 &Event, 224 &IoStatusBlock); 225 if (!Irp) 226 { 227 DPRINT1("IoBuildDeviceIoControlRequest() failed\n"); 228 ZwClose(FileHandle); 229 return STATUS_INSUFFICIENT_RESOURCES; 230 } 231 Status = IoCallDriver(DeviceObject, Irp); 232 if (Status == STATUS_PENDING) 233 { 234 DPRINT("IOCTL_GET_SYS_BUTTON_CAPS pending\n"); 235 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); 236 Status = IoStatusBlock.Status; 237 } 238 if (!NT_SUCCESS(Status)) 239 { 240 DPRINT1("Sending IOCTL_GET_SYS_BUTTON_CAPS failed with status 0x%08x\n", Status); 241 ZwClose(FileHandle); 242 return STATUS_INSUFFICIENT_RESOURCES; 243 } 244 245 DPRINT("Device capabilities: 0x%x\n", Caps); 246 if (Caps & SYS_BUTTON_POWER) 247 { 248 DPRINT("POWER button present\n"); 249 PopCapabilities.PowerButtonPresent = TRUE; 250 } 251 252 if (Caps & SYS_BUTTON_SLEEP) 253 { 254 DPRINT("SLEEP button present\n"); 255 PopCapabilities.SleepButtonPresent = TRUE; 256 } 257 258 if (Caps & SYS_BUTTON_LID) 259 { 260 DPRINT("LID present\n"); 261 PopCapabilities.LidPresent = TRUE; 262 } 263 264 SysButtonContext = ExAllocatePoolWithTag(NonPagedPool, 265 sizeof(SYS_BUTTON_CONTEXT), 266 'IWOP'); 267 if (!SysButtonContext) 268 { 269 DPRINT1("ExAllocatePoolWithTag() failed\n"); 270 ZwClose(FileHandle); 271 return STATUS_INSUFFICIENT_RESOURCES; 272 } 273 274 /* Queue a work item to get sys button event */ 275 SysButtonContext->WorkItem = IoAllocateWorkItem(DeviceObject); 276 SysButtonContext->DeviceObject = DeviceObject; 277 if (!SysButtonContext->WorkItem) 278 { 279 DPRINT1("IoAllocateWorkItem() failed\n"); 280 ZwClose(FileHandle); 281 ExFreePoolWithTag(SysButtonContext, 'IWOP'); 282 return STATUS_INSUFFICIENT_RESOURCES; 283 } 284 IoQueueWorkItem(SysButtonContext->WorkItem, 285 PopGetSysButton, 286 DelayedWorkQueue, 287 SysButtonContext); 288 289 ZwClose(FileHandle); 290 return STATUS_SUCCESS; 291 } 292 else 293 { 294 DPRINT1("Removal of a power capable device not implemented\n"); 295 return STATUS_NOT_IMPLEMENTED; 296 } 297 } 298