/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    handlers.c

Abstract:

    GPE and Operation Region handlers for the ACPI Embedded Controller Driver

Author:

    Bob Moore (Intel)

Environment:

Notes:


Revision History:

--*/

#include "ecp.h"

NTSTATUS
AcpiEcOpRegionCompletion (
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp,
    IN PVOID                Context
    )
/*++

Routine Description:

    This routine starts or continues servicing the device's work queue

Arguments:

    DeviceObject    - EC device object
    Irp             - Completing Irp
    Context         - Not Used

Return Value:

    Status

--*/
{
    PACPI_OPREGION_CALLBACK completionHandler;
    PIO_STACK_LOCATION      irpSp = IoGetCurrentIrpStackLocation( Irp );
    PVOID                   completionContext;

    //
    // Grab the arguments from the irp
    //
    completionHandler = (PACPI_OPREGION_CALLBACK) irpSp->Parameters.Others.Argument1;
    completionContext = (PVOID) irpSp->Parameters.Others.Argument2;

    EcPrint(
        EC_HANDLER,
        ("AcpiEcOpRegionCompletion: Callback: %08lx Context: %08lx\n",
         completionHandler, completionContext )
        );

    //
    // What happened?
    //
    if (!NT_SUCCESS(Irp->IoStatus.Status)) {

        EcPrint(
            EC_ERROR,
            ("AcpiEcOpRegionCompletion: region IO failed: %x\n",
             Irp->IoStatus.Status)
            );

    }

    //
    // Invoke the AML interpreter's callback
    //
    (completionHandler)( completionContext );

    //
    // We are done with this irp and the irp
    //
    IoFreeIrp( Irp );

    //
    // Return always return this --- because had to free the irp
    //
    return STATUS_MORE_PROCESSING_REQUIRED;
}



NTSTATUS
EXPORT
AcpiEcOpRegionHandler (
    ULONG                   AccessType,
    PVOID                   OpRegion,
    ULONG                   Address,
    ULONG                   Size,
    PULONG                  Data,
    ULONG_PTR               Context,
    PACPI_OPREGION_CALLBACK CompletionHandler,
    PVOID                   CompletionContext
    )
/*++

Routine Description:

    This routine handles requests to service the EC operation region

Arguments:

    AccessType          - Read or Write data
    OpRegion            - Operation region object
    Address             - Address within the EC address space
    Size                - Number of bytes to transfer
    Data                - Data buffer to transfer to/from
    Context             - EcData
    CompletionHandler   - AMLI handler to call when operation is complete
    CompletionContext   - Context to pass to the AMLI handler

Return Value:

    Status

Notes:

    Optimization 1: Queue the IRP directly.
    Optimization 2: Queue the context, modify service loop handle it

--*/
{
    LARGE_INTEGER       startingOffset;
    NTSTATUS            status;
    PECDATA             ecData = (PECDATA) Context;
    PIO_STACK_LOCATION  irpSp;
    PIRP                irp;

    EcPrint(
        (EC_HANDLER | EC_OPREGION),
        ("AcpiEcOpRegionHandler: %s Addr=%x Data = %x EcData=%x, Irql=%x\n",
         (AccessType == ACPI_OPREGION_READ ? "read" : "write"),
         Address, *Data, ecData, KeGetCurrentIrql() )
        );

    //
    // Parameter validation will be done in AcpiEcReadWrite
    //

    //
    // Determine where the read will occur
    //
    startingOffset.LowPart = Address;
    startingOffset.HighPart = 0;

    //
    // Allocate an IRP for ourselves. Since we are going to send this
    // irp to ourselves, we know that we only need 1 stack location for it
    // However, to make life easier for ourselves, we will allocate a
    // second one as well and store some data on it.
    //
    irp = IoAllocateIrp( 2, FALSE );
    if (!irp) {

        EcPrint(EC_ERROR, ("AcpiEcOpRegionHandler: Couldn't allocate Irp\n"));
        
        //
        // Retun -1 for data
        //
        RtlFillMemory (Data, Size, 0xff);
        CompletionHandler( CompletionContext );

        //
        // Always return STATUS_PENDING because ACPI interpreter doesn't handle errors.
        //
        return STATUS_PENDING;

    }

    //
    // Fill in the top location so that we can use it ourselves
    //
    irpSp = IoGetNextIrpStackLocation( irp );
    irpSp->Parameters.Others.Argument1 = (PVOID) CompletionHandler;
    irpSp->Parameters.Others.Argument2 = (PVOID) CompletionContext;
    IoSetNextIrpStackLocation( irp );

    //
    // Fill out the irp with the request info
    //
    irpSp = IoGetNextIrpStackLocation( irp );
    irpSp->MajorFunction = (AccessType == ACPI_OPREGION_READ ? IRP_MJ_READ : IRP_MJ_WRITE);
    irpSp->Parameters.Read.ByteOffset.HighPart = 0;
    irpSp->Parameters.Read.ByteOffset.LowPart = Address;
    irpSp->Parameters.Read.Length = Size;
    irp->AssociatedIrp.SystemBuffer = Data;

    //
    // Set a completion routine
    //
    IoSetCompletionRoutine(
        irp,
        AcpiEcOpRegionCompletion,
        NULL,
        TRUE,
        TRUE,
        TRUE
        );

    //
    // Send to the front-end of the EC driver as a normal I/O request
    //
    status = IoCallDriver( ecData->DeviceObject, irp);
    EcPrint(
        EC_HANDLER,
        ("AcpiEcOpRegionHandler: Exiting - Data=%08lx Status=%08lx\n",
         (UCHAR) *Data, status)
        );

    return STATUS_PENDING;
    //
    // Always return STATUS_PENDING since actual status has been returned
    // by the calback function.
    //
}



BOOLEAN
AcpiEcGpeServiceRoutine (
        IN PVOID GpeVectorObject,
        IN PVOID ServiceContext
    )
/*++

Routine Description:

    Routine to service the EC based on a General Purpose Event

Arguments:

    GpeVectorObject     - Object associated with this GPE
    ServiceContext      - EcData

Return Value:

    TRUE, since we always handle this GPE

--*/
{

    PECDATA EcData = (PECDATA) ServiceContext;

    EcPrint (EC_HANDLER, ("AcpiEcGpeServiceRoutine: Vobj=%Lx, EcData=%Lx\n",
                        GpeVectorObject, EcData));

    AcpiEcLogAction (EcData, EC_ACTION_INTERRUPT, 0);
    AcpiEcServiceDevice (EcData);

    return (TRUE);
}