457 lines
9 KiB
C
457 lines
9 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
eclowio.c
|
||
|
||
Abstract:
|
||
|
||
Interface module to ACPI driver functions. It encapsulates the grungy Irp details.
|
||
|
||
Author:
|
||
|
||
Bob Moore (Intel)
|
||
|
||
Environment:
|
||
|
||
Notes:
|
||
|
||
|
||
Revision History:
|
||
|
||
00-Feb-15 [vincentg] - modified to use oprghdlr.sys to register/deregister
|
||
op region handler
|
||
|
||
--*/
|
||
|
||
#include "ecp.h"
|
||
#include "oprghdlr.h"
|
||
#include <initguid.h>
|
||
#include <wdmguid.h>
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, AcpiEcGetAcpiInterfaces)
|
||
#pragma alloc_text(PAGE, AcpiEcGetGpeVector)
|
||
#pragma alloc_text(PAGE, AcpiEcInstallOpRegionHandler)
|
||
#pragma alloc_text(PAGE, AcpiEcRemoveOpRegionHandler)
|
||
#endif
|
||
|
||
NTSTATUS
|
||
AcpiEcGetAcpiInterfaces (
|
||
IN PECDATA EcData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Call ACPI driver to get the direct-call interfaces.
|
||
|
||
|
||
Arguments:
|
||
|
||
EcData - Pointer to the EC driver device extension
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
KEVENT event;
|
||
IO_STATUS_BLOCK ioStatus;
|
||
NTSTATUS status;
|
||
PIRP irp;
|
||
PIO_STACK_LOCATION irpSp;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Initialize an event to block on
|
||
//
|
||
KeInitializeEvent( &event, SynchronizationEvent, FALSE );
|
||
|
||
//
|
||
// Build an irp
|
||
//
|
||
irp = IoBuildSynchronousFsdRequest(
|
||
IRP_MJ_PNP,
|
||
EcData->LowerDeviceObject,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
&event,
|
||
&ioStatus
|
||
);
|
||
|
||
if (!irp) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||
irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Get the the current irp location
|
||
//
|
||
irpSp = IoGetNextIrpStackLocation( irp );
|
||
|
||
//
|
||
// Use QUERY_INTERFACE to get the address of the direct-call
|
||
// ACPI interfaces.
|
||
//
|
||
irpSp->MajorFunction = IRP_MJ_PNP;
|
||
irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||
irpSp->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_ACPI_INTERFACE_STANDARD;
|
||
irpSp->Parameters.QueryInterface.Version = 1;
|
||
irpSp->Parameters.QueryInterface.Size = sizeof (AcpiInterfaces);
|
||
irpSp->Parameters.QueryInterface.Interface = (PINTERFACE) &AcpiInterfaces;
|
||
irpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
||
|
||
//
|
||
// send the request down
|
||
//
|
||
status = IoCallDriver( EcData->LowerDeviceObject, irp );
|
||
if (status == STATUS_PENDING) {
|
||
|
||
KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
|
||
status = ioStatus.Status;
|
||
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
AcpiEcGetGpeVector (
|
||
IN PECDATA EcData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Run the _GPE method (Under the EC device in the namespace) to get the
|
||
GPE vector assigned to the EC.
|
||
|
||
Note: This routine is called at PASSIVE_LEVEL
|
||
|
||
Arguments:
|
||
|
||
EcData - Pointer to the EC driver device extension
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
ACPI_EVAL_INPUT_BUFFER inputBuffer;
|
||
ACPI_EVAL_OUTPUT_BUFFER outputBuffer;
|
||
KEVENT event;
|
||
IO_STATUS_BLOCK ioStatus;
|
||
NTSTATUS status;
|
||
PACPI_METHOD_ARGUMENT argument;
|
||
PIRP irp;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Initialize the event
|
||
//
|
||
KeInitializeEvent( &event, SynchronizationEvent, FALSE );
|
||
|
||
//
|
||
// Initialize the input buffer
|
||
//
|
||
RtlZeroMemory( &inputBuffer, sizeof(ACPI_EVAL_INPUT_BUFFER) );
|
||
inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
||
inputBuffer.MethodNameAsUlong = CM_GPE_METHOD;
|
||
|
||
//
|
||
// Initialize the output buffer
|
||
//
|
||
RtlZeroMemory( &outputBuffer, sizeof(ACPI_EVAL_OUTPUT_BUFFER ) );
|
||
|
||
//
|
||
// Initialize an IRP
|
||
//
|
||
irp = IoBuildDeviceIoControlRequest(
|
||
IOCTL_ACPI_EVAL_METHOD,
|
||
EcData->LowerDeviceObject,
|
||
&inputBuffer,
|
||
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
||
&outputBuffer,
|
||
sizeof(ACPI_EVAL_OUTPUT_BUFFER),
|
||
FALSE,
|
||
&event,
|
||
&ioStatus
|
||
);
|
||
|
||
//
|
||
// Irp initialization failed?
|
||
//
|
||
if (!irp) {
|
||
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto AcpiEcGetGpeVectorExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Send to ACPI driver
|
||
//
|
||
status = IoCallDriver (EcData->LowerDeviceObject, irp);
|
||
if (status == STATUS_PENDING) {
|
||
|
||
//
|
||
// Wait for request to be completed
|
||
//
|
||
KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
|
||
|
||
//
|
||
// Get the real status
|
||
//
|
||
status = ioStatus.Status;
|
||
|
||
}
|
||
|
||
//
|
||
// Did we fail the request?
|
||
//
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
goto AcpiEcGetGpeVectorExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Sanity checks
|
||
//
|
||
ASSERT( ioStatus.Information >= sizeof(ACPI_EVAL_OUTPUT_BUFFER) );
|
||
if (ioStatus.Information < sizeof(ACPI_EVAL_OUTPUT_BUFFER) ||
|
||
outputBuffer.Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE ||
|
||
outputBuffer.Count == 0) {
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
goto AcpiEcGetGpeVectorExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Crack the result
|
||
//
|
||
argument = &(outputBuffer.Argument[0]);
|
||
|
||
//
|
||
// We are expecting an integer
|
||
//
|
||
if (argument->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
|
||
|
||
status = STATUS_ACPI_INVALID_DATA;
|
||
goto AcpiEcGetGpeVectorExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Get the value
|
||
//
|
||
EcData->GpeVector = (UCHAR) argument->Argument;
|
||
|
||
AcpiEcGetGpeVectorExit:
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
AcpiEcConnectGpeVector (
|
||
IN PECDATA EcData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Call ACPI driver to connect the EC driver to a GPE vector
|
||
|
||
|
||
Arguments:
|
||
|
||
EcData - Pointer to the EC driver device extension
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
|
||
return (AcpiInterfaces.GpeConnectVector (
|
||
AcpiInterfaces.Context,
|
||
EcData->GpeVector,
|
||
Latched, // Edge triggered
|
||
FALSE, // Can't be shared
|
||
AcpiEcGpeServiceRoutine,
|
||
EcData,
|
||
&EcData->GpeVectorObject));
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
AcpiEcDisconnectGpeVector (
|
||
IN PECDATA EcData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Call ACPI driver to disconnect the EC driver from a GPE vector. Called
|
||
from device unload, stop.
|
||
|
||
|
||
Arguments:
|
||
|
||
EcData - Pointer to the EC driver device extension
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
|
||
if (EcData->GpeVectorObject) {
|
||
|
||
status = AcpiInterfaces.GpeDisconnectVector (EcData->GpeVectorObject);
|
||
EcData->GpeVectorObject = NULL;
|
||
|
||
} else {
|
||
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
AcpiEcInstallOpRegionHandler(
|
||
IN PECDATA EcData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Call ACPI driver to install the EC driver operation region handler
|
||
|
||
|
||
Arguments:
|
||
|
||
EcData - Pointer to the EC driver device extension
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE ();
|
||
|
||
status = RegisterOpRegionHandler (EcData->LowerDeviceObject,
|
||
ACPI_OPREGION_ACCESS_AS_COOKED,
|
||
ACPI_OPREGION_REGION_SPACE_EC,
|
||
(PACPI_OP_REGION_HANDLER) AcpiEcOpRegionHandler,
|
||
EcData,
|
||
0,
|
||
&EcData->OperationRegionObject);
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
AcpiEcRemoveOpRegionHandler (
|
||
IN PECDATA EcData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Call ACPI driver to remove the EC driver operation region handler.
|
||
Called from device unload, stop.
|
||
|
||
|
||
Arguments:
|
||
|
||
EcData - Pointer to the EC driver device extension
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE ();
|
||
|
||
status = DeRegisterOpRegionHandler (EcData->LowerDeviceObject,
|
||
EcData->OperationRegionObject);
|
||
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
AcpiEcForwardIrpAndWait (
|
||
IN PECDATA EcData,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Utility routine to send an irp down, and wait for the result.
|
||
|
||
|
||
Arguments:
|
||
|
||
EcData - Pointer to the EC driver device extension
|
||
Irp - Irp to send and complete
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
KEVENT pdoStartedEvent;
|
||
NTSTATUS status;
|
||
|
||
|
||
KeInitializeEvent (&pdoStartedEvent, SynchronizationEvent, FALSE);
|
||
|
||
IoCopyCurrentIrpStackLocationToNext (Irp);
|
||
IoSetCompletionRoutine (Irp, AcpiEcIoCompletion, &pdoStartedEvent,
|
||
TRUE, TRUE, TRUE);
|
||
|
||
//
|
||
// Always wait for the completion routine
|
||
//
|
||
|
||
status = IoCallDriver (EcData->LowerDeviceObject, Irp);
|
||
if (status == STATUS_PENDING) {
|
||
|
||
KeWaitForSingleObject (&pdoStartedEvent, Executive, KernelMode, FALSE, NULL);
|
||
status = Irp->IoStatus.Status;
|
||
}
|
||
return status;
|
||
}
|
||
|