|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
switch.c
Abstract:
Button and lid support for the power policy manager
Author:
Ken Reneris (kenr) 17-Jan-1997
Revision History:
--*/
#include "pop.h"
VOID PopTriggerSwitch ( IN PPOP_SWITCH_DEVICE SwitchDevice, IN ULONG Flag, IN PPOWER_ACTION_POLICY Action );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, PopSystemButtonHandler)
#pragma alloc_text(PAGE, PopResetSwitchTriggers)
#pragma alloc_text(PAGE, PopTriggerSwitch)
#endif
VOID PopSystemButtonHandler ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++
Routine Description:
This function is the irp handler function to handle the completion if a query switch status irp. On completion this IRP is recycled to the next request.
N.B. PopPolicyLock must be held.
Arguments:
DeviceObject - DeviceObject of the switch device
Irp - Irp which has completed
Context - type of switch device
Return Value:
None.
--*/ { PIO_STACK_LOCATION IrpSp; PPOP_SWITCH_DEVICE SwitchDevice; ULONG IoctlCode; PLIST_ENTRY ListEntry; ULONG DisabledCaps;
ASSERT_POLICY_LOCK_OWNED();
IrpSp = IoGetCurrentIrpStackLocation(Irp); SwitchDevice = (PPOP_SWITCH_DEVICE) Context;
if (NT_SUCCESS (Irp->IoStatus.Status)) {
if (!SwitchDevice->GotCaps) {
//
// We have never gotten any button capabilities yet.
// Try and get them now.
//
SwitchDevice->Caps = 0; if (SwitchDevice->IrpBuffer & SYS_BUTTON_POWER) { PopSetCapability (&PopCapabilities.PowerButtonPresent); SwitchDevice->Caps |= SYS_BUTTON_POWER; }
if (SwitchDevice->IrpBuffer & SYS_BUTTON_SLEEP) { PopSetCapability (&PopCapabilities.SleepButtonPresent); SwitchDevice->Caps |= SYS_BUTTON_SLEEP; }
if (SwitchDevice->IrpBuffer & SYS_BUTTON_LID) { PopSetCapability (&PopCapabilities.LidPresent); SwitchDevice->Caps |= SYS_BUTTON_LID; }
SwitchDevice->IrpBuffer = 0; SwitchDevice->GotCaps = TRUE;
//
// If no capabilities, indicate failure to cause
// the device to be closed
//
if (SwitchDevice->Caps == 0) { SwitchDevice->IsFailed = TRUE; }
} else {
//
// We've been called before so we know what the buttons are supposed
// to do. Check to see if any of our buttons have triggered an
// event.
//
PopTriggerSwitch (SwitchDevice, SYS_BUTTON_LID, &PopPolicy->LidClose); PopTriggerSwitch (SwitchDevice, SYS_BUTTON_POWER, &PopPolicy->PowerButton); PopTriggerSwitch (SwitchDevice, SYS_BUTTON_SLEEP, &PopPolicy->SleepButton);
//
// If the wake button is signalled, drop the triggered states
// and set the user as being present
//
if (SwitchDevice->IrpBuffer & SYS_BUTTON_WAKE) { SwitchDevice->TriggerState = 0; PopUserPresentSet (0); } }
IoctlCode = IOCTL_GET_SYS_BUTTON_EVENT;
} else { if (!SwitchDevice->IsInitializing) { //
// Unexpected error
//
PoPrint (PO_ERROR, ("PopSystemButtonHandler: unexpected error %x\n", Irp->IoStatus.Status)); SwitchDevice->GotCaps = FALSE; SwitchDevice->IsFailed = TRUE; IoctlCode = 0; } else { IoctlCode = IOCTL_GET_SYS_BUTTON_CAPS; SwitchDevice->IsInitializing = FALSE; } }
if (SwitchDevice->IsFailed) {
//
// Close the device
//
PoPrint (PO_WARN, ("PopSystemButtonHandler: removing button device\n")); RemoveEntryList (&SwitchDevice->Link); IoFreeIrp (Irp); ObDereferenceObject (DeviceObject);
//
// Enumerate the remaining switch devices and disable capabilities
// which no longer exist.
//
DisabledCaps = SwitchDevice->Caps; ExFreePool(SwitchDevice);
ListEntry = PopSwitches.Flink; while (ListEntry != &PopSwitches) { SwitchDevice = CONTAINING_RECORD(ListEntry, POP_SWITCH_DEVICE, Link); DisabledCaps &= ~SwitchDevice->Caps; ListEntry = ListEntry->Flink; } if (DisabledCaps & SYS_BUTTON_POWER) { PoPrint(PO_WARN,("PopSystemButtonHandler : removing power button\n")); PopClearCapability (&PopCapabilities.PowerButtonPresent); } if (DisabledCaps & SYS_BUTTON_SLEEP) { PoPrint(PO_WARN,("PopSystemButtonHandler : removing sleep button\n")); PopClearCapability (&PopCapabilities.SleepButtonPresent); } if (DisabledCaps & SYS_BUTTON_LID) { PoPrint(PO_WARN,("PopSystemButtonHandler : removing lid switch\n")); PopClearCapability (&PopCapabilities.LidPresent); }
} else {
//
// Send notify IRP to the device to wait for new switch state
//
IrpSp = IoGetNextIrpStackLocation(Irp); IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL; IrpSp->Parameters.DeviceIoControl.IoControlCode = IoctlCode; IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG); IrpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ULONG); Irp->AssociatedIrp.SystemBuffer = &SwitchDevice->IrpBuffer; IoSetCompletionRoutine (Irp, PopCompletePolicyIrp, NULL, TRUE, TRUE, TRUE); IoCallDriver (DeviceObject, Irp); } }
VOID PopTriggerSwitch ( IN PPOP_SWITCH_DEVICE SwitchDevice, IN ULONG Flag, IN PPOWER_ACTION_POLICY Action ) { POP_ACTION_TRIGGER Trigger;
if ((SwitchDevice->Caps & SYS_BUTTON_LID) && (Flag == SYS_BUTTON_LID)) {
//
// Somebody opened or closed a lid.
//
SwitchDevice->Opened = !(SwitchDevice->Opened);
//
// Notify the PowerState callback.
//
ExNotifyCallback ( ExCbPowerState, UIntToPtr(PO_CB_LID_SWITCH_STATE), UIntToPtr(SwitchDevice->Opened) );
//
// Now tell win32k.sys that the lid is open.
//
if( SwitchDevice->Opened ) { PopDisplayRequired(0); }
}
//
// Check if event is signalled
//
if (SwitchDevice->IrpBuffer & Flag) {
if (SwitchDevice->TriggerState & Flag) { //
// We're in the middle of servicing an action
// just like this one already.
//
PopSetNotificationWork (PO_NOTIFY_BUTTON_RECURSE);
} else {
//
// Initiate action for this event
//
RtlZeroMemory (&Trigger, sizeof(Trigger)); Trigger.Type = PolicyDeviceSystemButton; Trigger.Flags = PO_TRG_SET;
PopSetPowerAction ( &Trigger, 0, Action, PowerSystemSleeping1, SubstituteLightestOverallDownwardBounded );
SwitchDevice->TriggerState |= (UCHAR) Flag; } } }
VOID PopResetSwitchTriggers ( VOID ) /*++
Routine Description:
This function clears the triggered status on all switch devices
N.B. PopPolicyLock must be held.
Arguments:
None
Return Value:
Status
--*/ { PLIST_ENTRY Link; PPOP_SWITCH_DEVICE SwitchDevice;
ASSERT_POLICY_LOCK_OWNED();
//
// Clear flag bits
//
for (Link = PopSwitches.Flink; Link != &PopSwitches; Link = Link->Flink) { SwitchDevice = CONTAINING_RECORD (Link, POP_SWITCH_DEVICE, Link); SwitchDevice->TriggerState = 0; } }
|