/*++ 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 #include #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; }