485 lines
11 KiB
C
485 lines
11 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1997 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
button.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Fixed button support
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Stephane Plante (splante)
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
NT Kernel Model Driver only
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
July 7, 1997 - Complete Rewrite
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pch.h"
|
|||
|
|
|||
|
PDEVICE_OBJECT FixedButtonDeviceObject;
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, ACPIButtonStartDevice)
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Spinlock to protect the thermal list
|
|||
|
//
|
|||
|
KSPIN_LOCK AcpiButtonLock;
|
|||
|
|
|||
|
//
|
|||
|
// List entry to store the thermal requests on
|
|||
|
//
|
|||
|
LIST_ENTRY AcpiButtonList;
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ACPIButtonCancelRequest(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine cancels an outstanding button request
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the device which as a request being cancelled
|
|||
|
Irp - the cancelling irp
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL oldIrql;
|
|||
|
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
|||
|
|
|||
|
//
|
|||
|
// We no longer need the cancel lock
|
|||
|
//
|
|||
|
IoReleaseCancelSpinLock( Irp->CancelIrql );
|
|||
|
|
|||
|
//
|
|||
|
// We do however need the button queue lock
|
|||
|
//
|
|||
|
KeAcquireSpinLock( &AcpiButtonLock, &oldIrql );
|
|||
|
|
|||
|
//
|
|||
|
// Remove the irp from the list that it is on
|
|||
|
//
|
|||
|
RemoveEntryList( &(Irp->Tail.Overlay.ListEntry) );
|
|||
|
|
|||
|
//
|
|||
|
// Complete the irp now
|
|||
|
//
|
|||
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|||
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
ACPIButtonCompletePendingIrps(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN ULONG ButtonEvent
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine completes any pending button irp sent to the specified
|
|||
|
device object with the knowledge of which button events have occured
|
|||
|
|
|||
|
The respective's button's spinlock is held during this call
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the target button object
|
|||
|
ButtonEvent - the button event that occured
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if we completed an irp, FALSE, otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOLEAN handledRequest = FALSE;
|
|||
|
KIRQL oldIrql;
|
|||
|
LIST_ENTRY doneList;
|
|||
|
PDEVICE_OBJECT targetObject;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
PIRP irp;
|
|||
|
PLIST_ENTRY listEntry;
|
|||
|
PULONG resultBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the list that will hold the requests that we need to
|
|||
|
// complete
|
|||
|
//
|
|||
|
InitializeListHead( &doneList );
|
|||
|
|
|||
|
//
|
|||
|
// Acquire the thermal lock so that we can pend these requests
|
|||
|
//
|
|||
|
KeAcquireSpinLock( &AcpiButtonLock, &oldIrql );
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list of pending irps to see which ones match this extension
|
|||
|
//
|
|||
|
listEntry = AcpiButtonList.Flink;
|
|||
|
while (listEntry != &AcpiButtonList) {
|
|||
|
|
|||
|
//
|
|||
|
// Grab the irp from the list entry and update the next list entry
|
|||
|
// that we will look at
|
|||
|
//
|
|||
|
irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
|
|||
|
listEntry = listEntry->Flink;
|
|||
|
|
|||
|
//
|
|||
|
// We need the current irp stack location
|
|||
|
//
|
|||
|
irpSp = IoGetCurrentIrpStackLocation( irp );
|
|||
|
|
|||
|
//
|
|||
|
// what is the target object for this irp?
|
|||
|
//
|
|||
|
targetObject = irpSp->DeviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// Is this an irp that we care about? IE: does the does target mage
|
|||
|
// the ones specified in this function
|
|||
|
//
|
|||
|
if (targetObject != DeviceObject) {
|
|||
|
|
|||
|
continue;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// At this point, we need to set the cancel routine to NULL because
|
|||
|
// we are going to take care of this irp and we don't want it cancelled
|
|||
|
// underneath us
|
|||
|
//
|
|||
|
if (IoSetCancelRoutine(irp, NULL) == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Cancel routine is active. stop processing this irp and move on
|
|||
|
//
|
|||
|
continue;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// set the data to return in the irp
|
|||
|
//
|
|||
|
resultBuffer = (PULONG) irp->AssociatedIrp.SystemBuffer;
|
|||
|
*resultBuffer = ButtonEvent;
|
|||
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
irp->IoStatus.Information = sizeof(ULONG);
|
|||
|
|
|||
|
//
|
|||
|
// Remove the entry from the list
|
|||
|
//
|
|||
|
RemoveEntryList( &(irp->Tail.Overlay.ListEntry) );
|
|||
|
|
|||
|
//
|
|||
|
// Insert the list onto the next queue, so that we know how to
|
|||
|
// complete it later on
|
|||
|
//
|
|||
|
InsertTailList( &doneList, &(irp->Tail.Overlay.ListEntry) );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// At this point, droup our button lock
|
|||
|
//
|
|||
|
KeReleaseSpinLock( &AcpiButtonLock, oldIrql );
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list of irps to be completed
|
|||
|
//
|
|||
|
listEntry = doneList.Flink;
|
|||
|
while (listEntry != &doneList) {
|
|||
|
|
|||
|
//
|
|||
|
// Grab the irp from the list entry, update the next list entry
|
|||
|
// that we will look at, and complete the request
|
|||
|
//
|
|||
|
irp = CONTAINING_RECORD( listEntry, IRP, Tail.Overlay.ListEntry );
|
|||
|
listEntry = listEntry->Flink;
|
|||
|
RemoveEntryList( &(irp->Tail.Overlay.ListEntry) );
|
|||
|
|
|||
|
//
|
|||
|
// Complete the request and remember that we handled a request
|
|||
|
//
|
|||
|
IoCompleteRequest( irp, IO_NO_INCREMENT );
|
|||
|
handledRequest = TRUE;
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return wether or not we handled a request
|
|||
|
//
|
|||
|
return handledRequest;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ACPIButtonDeviceControl (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Fixed button device IOCTL handler
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - fixed feature button device object
|
|||
|
Irp - the ioctl request
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL oldIrql;
|
|||
|
NTSTATUS status;
|
|||
|
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
|||
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PULONG resultBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Do not allow user mode IRPs in this routine
|
|||
|
//
|
|||
|
if (Irp->RequestorMode != KernelMode) {
|
|||
|
|
|||
|
return ACPIDispatchIrpInvalid( DeviceObject, Irp );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
resultBuffer = (PULONG) Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|||
|
case IOCTL_GET_SYS_BUTTON_CAPS:
|
|||
|
|
|||
|
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG)) {
|
|||
|
|
|||
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
*resultBuffer = deviceExtension->Button.Capabilities;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|||
|
break;
|
|||
|
|
|||
|
case IOCTL_GET_SYS_BUTTON_EVENT:
|
|||
|
|
|||
|
//
|
|||
|
// Make sure our buffer is big enough
|
|||
|
//
|
|||
|
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG)) {
|
|||
|
|
|||
|
Irp->IoStatus.Status = status = STATUS_INFO_LENGTH_MISMATCH;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Grab the button lock, queue the request to the proper place, and
|
|||
|
// make sure to set a cancel routine
|
|||
|
//
|
|||
|
KeAcquireSpinLock( &AcpiButtonLock, &oldIrql );
|
|||
|
IoSetCancelRoutine( Irp, ACPIButtonCancelRequest);
|
|||
|
if (Irp->Cancel && IoSetCancelRoutine( Irp, NULL) ) {
|
|||
|
|
|||
|
//
|
|||
|
// If we got here, that measn that the irp has been cancelled and
|
|||
|
// that we beat the IO manager to the ButtonLock. So release the
|
|||
|
// irp and mark the irp as being cancelled
|
|||
|
//
|
|||
|
KeReleaseSpinLock( &AcpiButtonLock, oldIrql );
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
Irp->IoStatus.Status = status = STATUS_CANCELLED;
|
|||
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we got here, that means we are going to the queue the request and so
|
|||
|
// some work on it later
|
|||
|
//
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
|
|||
|
//
|
|||
|
// Queue the irp into a queue
|
|||
|
//
|
|||
|
InsertTailList( &AcpiButtonList, &(Irp->Tail.Overlay.ListEntry) );
|
|||
|
|
|||
|
//
|
|||
|
// Done with the lock at this point
|
|||
|
//
|
|||
|
KeReleaseSpinLock( &AcpiButtonLock, oldIrql );
|
|||
|
|
|||
|
//
|
|||
|
// Fire off the work thread
|
|||
|
//
|
|||
|
status = ACPIButtonEvent( DeviceObject, 0, NULL );
|
|||
|
break ;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
status = STATUS_NOT_SUPPORTED;
|
|||
|
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|||
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ACPIButtonEvent (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN ULONG ButtonEvent,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine applies and event mask and irp to the button device.
|
|||
|
If there's a pending event and an irp to handle it, the irp will
|
|||
|
be completed
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - fixed feature button device object
|
|||
|
ButtonEvent - events to apply to the device
|
|||
|
Irp - irp to capture the next events
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOLEAN completedIrp;
|
|||
|
KIRQL oldIrql;
|
|||
|
NTSTATUS status;
|
|||
|
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
|||
|
PULONG resultBuffer;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( Irp );
|
|||
|
|
|||
|
if ((ButtonEvent & (SYS_BUTTON_SLEEP | SYS_BUTTON_POWER | SYS_BUTTON_WAKE)) &&
|
|||
|
!(deviceExtension->Button.Capabilities & SYS_BUTTON_LID)) {
|
|||
|
|
|||
|
//
|
|||
|
// Notify that the user is present, except if we happen to be
|
|||
|
// messing with the lid. The kernel will set the user-present
|
|||
|
// bit there, and we don't want the screen to turn on when
|
|||
|
// the user closes the lid.
|
|||
|
//
|
|||
|
|
|||
|
PoSetSystemState (ES_USER_PRESENT);
|
|||
|
}
|
|||
|
|
|||
|
if (!DeviceObject) {
|
|||
|
|
|||
|
return (STATUS_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set pending info
|
|||
|
//
|
|||
|
KeAcquireSpinLock (&(deviceExtension->Button.SpinLock), &oldIrql);
|
|||
|
deviceExtension->Button.Events |= ButtonEvent;
|
|||
|
|
|||
|
//
|
|||
|
// Are there any outstanding events? If so, then try to complete all
|
|||
|
// the pending irps against that button with the list of events
|
|||
|
//
|
|||
|
if (deviceExtension->Button.Events) {
|
|||
|
|
|||
|
completedIrp = ACPIButtonCompletePendingIrps(
|
|||
|
DeviceObject,
|
|||
|
deviceExtension->Button.Events
|
|||
|
);
|
|||
|
if (completedIrp) {
|
|||
|
|
|||
|
deviceExtension->Button.Events = 0;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
KeReleaseSpinLock (&(deviceExtension->Button.SpinLock), oldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Always return pending
|
|||
|
//
|
|||
|
return STATUS_PENDING;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ACPIButtonStartDevice (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Start device function for the fixed feature power and sleep device
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - fixed feature button device object
|
|||
|
Irp - the start request
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
Status = ACPIInternalSetDeviceInterface (
|
|||
|
DeviceObject,
|
|||
|
(LPGUID) &GUID_DEVICE_SYS_BUTTON
|
|||
|
);
|
|||
|
|
|||
|
Irp->IoStatus.Status = Status;
|
|||
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|