/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/po/events.c * PURPOSE: Power Manager * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) */ /* INCLUDES ******************************************************************/ #include #define NDEBUG #include /* GLOBALS *******************************************************************/ typedef struct _SYS_BUTTON_CONTEXT { PDEVICE_OBJECT DeviceObject; PIO_WORKITEM WorkItem; KEVENT Event; IO_STATUS_BLOCK IoStatusBlock; ULONG SysButton; } SYS_BUTTON_CONTEXT, *PSYS_BUTTON_CONTEXT; static VOID NTAPI PopGetSysButton( IN PDEVICE_OBJECT DeviceObject, IN PVOID Context); PKWIN32_POWEREVENT_CALLOUT PopEventCallout; extern PCALLBACK_OBJECT SetSystemTimeCallback; /* FUNCTIONS *****************************************************************/ VOID NTAPI PoNotifySystemTimeSet(VOID) { KIRQL OldIrql; /* Check if Win32k registered a notification callback */ if (PopEventCallout) { /* Raise to dispatch */ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* Notify the callback */ ExNotifyCallback(SetSystemTimeCallback, NULL, NULL); /* Lower IRQL back */ KeLowerIrql(OldIrql); } } static NTSTATUS NTAPI PopGetSysButtonCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PSYS_BUTTON_CONTEXT SysButtonContext = Context; ULONG SysButton; /* The DeviceObject can be NULL, so use the one we stored */ DeviceObject = SysButtonContext->DeviceObject; /* FIXME: What do do with the sys button event? */ SysButton = *(PULONG)Irp->AssociatedIrp.SystemBuffer; { DPRINT1("A device reported the event 0x%x (", SysButton); if (SysButton & SYS_BUTTON_POWER) DbgPrint(" POWER"); if (SysButton & SYS_BUTTON_SLEEP) DbgPrint(" SLEEP"); if (SysButton & SYS_BUTTON_LID) DbgPrint(" LID"); if (SysButton == 0) DbgPrint(" WAKE"); DbgPrint(" )\n"); if (SysButton & SYS_BUTTON_POWER) { /* FIXME: Read registry for the action we should perform here */ DPRINT1("Initiating shutdown after power button event\n"); ZwShutdownSystem(ShutdownNoReboot); } } /* Allocate a new workitem to send the next IOCTL_GET_SYS_BUTTON_EVENT */ SysButtonContext->WorkItem = IoAllocateWorkItem(DeviceObject); if (!SysButtonContext->WorkItem) { DPRINT("IoAllocateWorkItem() failed\n"); ExFreePoolWithTag(SysButtonContext, 'IWOP'); return STATUS_SUCCESS; } IoQueueWorkItem(SysButtonContext->WorkItem, PopGetSysButton, DelayedWorkQueue, SysButtonContext); return STATUS_SUCCESS /* STATUS_CONTINUE_COMPLETION */; } static VOID NTAPI PopGetSysButton( IN PDEVICE_OBJECT DeviceObject, IN PVOID Context) { PSYS_BUTTON_CONTEXT SysButtonContext = Context; PIO_WORKITEM CurrentWorkItem = SysButtonContext->WorkItem; PIRP Irp; /* Get button pressed (IOCTL_GET_SYS_BUTTON_EVENT) */ KeInitializeEvent(&SysButtonContext->Event, NotificationEvent, FALSE); Irp = IoBuildDeviceIoControlRequest(IOCTL_GET_SYS_BUTTON_EVENT, DeviceObject, NULL, 0, &SysButtonContext->SysButton, sizeof(SysButtonContext->SysButton), FALSE, &SysButtonContext->Event, &SysButtonContext->IoStatusBlock); if (Irp) { IoSetCompletionRoutine(Irp, PopGetSysButtonCompletion, SysButtonContext, TRUE, FALSE, FALSE); IoCallDriver(DeviceObject, Irp); } else { DPRINT1("IoBuildDeviceIoControlRequest() failed\n"); ExFreePoolWithTag(SysButtonContext, 'IWOP'); } IoFreeWorkItem(CurrentWorkItem); } NTSTATUS NTAPI PopAddRemoveSysCapsCallback(IN PVOID NotificationStructure, IN PVOID Context) { PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification; PSYS_BUTTON_CONTEXT SysButtonContext; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE FileHandle; PDEVICE_OBJECT DeviceObject; PFILE_OBJECT FileObject; PIRP Irp; IO_STATUS_BLOCK IoStatusBlock; KEVENT Event; BOOLEAN Arrival; ULONG Caps; NTSTATUS Status; DPRINT("PopAddRemoveSysCapsCallback(%p %p)\n", NotificationStructure, Context); Notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION)NotificationStructure; if (Notification->Version != 1) return STATUS_REVISION_MISMATCH; if (Notification->Size != sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION)) return STATUS_INVALID_PARAMETER; if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID)) Arrival = TRUE; else if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID)) Arrival = FALSE; else return STATUS_INVALID_PARAMETER; if (Arrival) { DPRINT("Arrival of %wZ\n", Notification->SymbolicLinkName); /* Open the device */ InitializeObjectAttributes(&ObjectAttributes, Notification->SymbolicLinkName, OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenFile(&FileHandle, FILE_READ_DATA, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, 0); if (!NT_SUCCESS(Status)) { DPRINT1("ZwOpenFile() failed with status 0x%08lx\n", Status); return Status; } Status = ObReferenceObjectByHandle(FileHandle, FILE_READ_DATA, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("ObReferenceObjectByHandle() failed with status 0x%08lx\n", Status); ZwClose(FileHandle); return Status; } DeviceObject = IoGetRelatedDeviceObject(FileObject); ObDereferenceObject(FileObject); /* Get capabilities (IOCTL_GET_SYS_BUTTON_CAPS) */ KeInitializeEvent(&Event, NotificationEvent, FALSE); Irp = IoBuildDeviceIoControlRequest(IOCTL_GET_SYS_BUTTON_CAPS, DeviceObject, NULL, 0, &Caps, sizeof(Caps), FALSE, &Event, &IoStatusBlock); if (!Irp) { DPRINT1("IoBuildDeviceIoControlRequest() failed\n"); ZwClose(FileHandle); return STATUS_INSUFFICIENT_RESOURCES; } Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { DPRINT("IOCTL_GET_SYS_BUTTON_CAPS pending\n"); KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); Status = IoStatusBlock.Status; } if (!NT_SUCCESS(Status)) { DPRINT1("Sending IOCTL_GET_SYS_BUTTON_CAPS failed with status 0x%08x\n", Status); ZwClose(FileHandle); return STATUS_INSUFFICIENT_RESOURCES; } /* FIXME: What do do with the capabilities? */ { DPRINT("Device capabilities: 0x%x (", Caps); if (Caps & SYS_BUTTON_POWER) DPRINT(" POWER"); if (Caps & SYS_BUTTON_SLEEP) DPRINT(" SLEEP"); if (Caps & SYS_BUTTON_LID) DPRINT(" LID"); DPRINT(" )\n"); } SysButtonContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(SYS_BUTTON_CONTEXT), 'IWOP'); if (!SysButtonContext) { DPRINT1("ExAllocatePoolWithTag() failed\n"); ZwClose(FileHandle); return STATUS_INSUFFICIENT_RESOURCES; } /* Queue a work item to get sys button event */ SysButtonContext->WorkItem = IoAllocateWorkItem(DeviceObject); SysButtonContext->DeviceObject = DeviceObject; if (!SysButtonContext->WorkItem) { DPRINT1("IoAllocateWorkItem() failed\n"); ZwClose(FileHandle); ExFreePoolWithTag(SysButtonContext, 'IWOP'); return STATUS_INSUFFICIENT_RESOURCES; } IoQueueWorkItem(SysButtonContext->WorkItem, PopGetSysButton, DelayedWorkQueue, SysButtonContext); ZwClose(FileHandle); return STATUS_SUCCESS; } else { DPRINT1("Removal of a power capable device not implemented\n"); return STATUS_NOT_IMPLEMENTED; } }