/*++ Copyright (c) 1997 Microsoft Corporation Module Name: acpioprg.c Abstract: This module provides support for registering ACPI operation regions Author: Stephane Plante (splante) Environment: NT Kernel Mode Driver Only --*/ #include "pch.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE,RegisterOperationRegionHandler) #endif NTSTATUS EXPORT InternalRawAccessOpRegionHandler ( IN ULONG dwAccType, IN PFIELDUNITOBJ FieldUnit, IN POBJDATA data, IN ULONG_PTR Context, IN PFNAA CompletionHandler, IN PVOID IntContext ) { NTSTATUS status; PNSOBJ HostDevice = NULL; PACPI_POWER_INFO DeviceNode; PVOID DeviceHandle; // // Get the device // status = AMLIGetFieldUnitRegionObj( FieldUnit, &HostDevice ); if ( AMLIERR( status ) != AMLIERR_NONE || HostDevice == NULL) { return (STATUS_UNSUCCESSFUL); } HostDevice = NSGETPARENT(HostDevice); ACPIPrint( ( ACPI_PRINT_IO, "Raw OpRegion Access on field unit object %x device %x\n", FieldUnit, HostDevice )); if ( (!HostDevice) || (NSGETOBJTYPE(HostDevice)!=OBJTYPE_DEVICE) ) { return (STATUS_UNSUCCESSFUL); } DeviceNode = OSPowerFindPowerInfo(HostDevice); if ( DeviceNode == NULL ) { return (STATUS_UNSUCCESSFUL); } DeviceHandle = DeviceNode->Context; ACPIPrint( ( ACPI_PRINT_IO, "DeviceHandle %x\n", DeviceHandle ) ); if ( !(POPREGIONHANDLER)Context || !(((POPREGIONHANDLER)Context)->Handler) ) { return (STATUS_UNSUCCESSFUL); } return( (((POPREGIONHANDLER)Context)->Handler)( dwAccType, FieldUnit, data, ((POPREGIONHANDLER)Context)->HandlerContext, CompletionHandler, IntContext ) ); } NTSTATUS EXPORT InternalOpRegionHandler ( IN ULONG dwAccType, IN PNSOBJ pnsOpRegion, IN ULONG dwAddr, IN ULONG dwSize, IN PULONG pdwData, IN ULONG_PTR Context, IN PFNAA CompletionHandler, IN PVOID IntContext ) { PNSOBJ HostDevice; PACPI_POWER_INFO DeviceNode; PVOID DeviceHandle; NTSTATUS status; HostDevice = NSGETPARENT(pnsOpRegion); ACPIPrint( ( ACPI_PRINT_IO, "OpRegion Access on region %x device %x\n", pnsOpRegion, HostDevice ) ); if ( (!HostDevice) || (NSGETOBJTYPE(HostDevice) != OBJTYPE_DEVICE) ) { return (STATUS_UNSUCCESSFUL); } DeviceNode = OSPowerFindPowerInfo (HostDevice); if ( DeviceNode == NULL ) { return (STATUS_UNSUCCESSFUL); } DeviceHandle = DeviceNode->Context; ACPIPrint( ( ACPI_PRINT_IO, "DeviceHandle %x\n", DeviceHandle ) ); if ( !(POPREGIONHANDLER)Context || !(((POPREGIONHANDLER)Context)->Handler) ) { return (STATUS_UNSUCCESSFUL); } status = (((POPREGIONHANDLER)Context)->Handler) ( dwAccType, pnsOpRegion, dwAddr, dwSize, pdwData, ((POPREGIONHANDLER)Context)->HandlerContext, CompletionHandler, IntContext); ACPIPrint( ( ACPI_PRINT_IO, "Return from OR handler - status %x\n", status ) ); return (status); } // // Register to receive accesses to the specified operation region // NTSTATUS RegisterOperationRegionHandler ( IN PNSOBJ RegionParent, IN ULONG AccessType, IN ULONG RegionSpace, IN PFNHND Handler, IN ULONG_PTR Context, OUT PVOID *OperationRegionObject ) { NTSTATUS status; OBJDATA regArgs[2]; POPREGIONHANDLER HandlerNode; PNSOBJ regObject; PAGED_CODE(); *OperationRegionObject = NULL; status = STATUS_SUCCESS; // // Allocate a new Operation Region Object // HandlerNode = ExAllocatePool (NonPagedPool, sizeof(OPREGIONHANDLER)); if ( !HandlerNode ) { return (STATUS_INSUFFICIENT_RESOURCES); } // // Init the Operation Region Object // HandlerNode->Handler = Handler; HandlerNode->HandlerContext = (PVOID)Context; HandlerNode->AccessType = AccessType; HandlerNode->RegionSpace = RegionSpace; // // Raw or Cooked access supported // switch ( AccessType ) { case EVTYPE_RS_COOKACCESS: status = AMLIRegEventHandler( AccessType, RegionSpace, InternalOpRegionHandler, (ULONG_PTR)HandlerNode ); if ( AMLIERR(status) != AMLIERR_NONE ) { status = STATUS_UNSUCCESSFUL; } break; case EVTYPE_RS_RAWACCESS: status = AMLIRegEventHandler( AccessType, RegionSpace, InternalRawAccessOpRegionHandler, (ULONG_PTR)HandlerNode ); if ( AMLIERR(status) != AMLIERR_NONE ) { status = STATUS_UNSUCCESSFUL; } break; default: status = STATUS_INVALID_PARAMETER; break; } // // Cleanup if needed // if ( !NT_SUCCESS (status) ) { ExFreePool (HandlerNode); return (status); } // // Remember the handler // *OperationRegionObject = HandlerNode; // // Can we find something? // if ( RegionParent == NULL ) { // // Do nothing // return (STATUS_SUCCESS); } // // see if there is a _REG object to run // status = AMLIGetNameSpaceObject( "_REG", RegionParent, ®Object, NSF_LOCAL_SCOPE ); if ( !NT_SUCCESS(status) ) { // // Nothing to do // return (STATUS_SUCCESS); } // // Initialize the parameters // RtlZeroMemory( regArgs, sizeof(OBJDATA) * 2 ); regArgs[0].dwDataType = OBJTYPE_INTDATA; regArgs[0].uipDataValue = RegionSpace; regArgs[1].dwDataType = OBJTYPE_INTDATA; regArgs[1].uipDataValue = 1; // // Eval the request. We can do this asynchronously since we don't actually // care when the registration is complete // AMLIAsyncEvalObject( regObject, NULL, 2, regArgs, NULL, NULL ); // // Done // return (STATUS_SUCCESS); } // // UnRegister to receive accesses to the specified operation region // NTSTATUS UnRegisterOperationRegionHandler ( IN PNSOBJ RegionParent, IN PVOID OperationRegionObject ) { NTSTATUS status; OBJDATA regArgs[2]; PNSOBJ regObject; POPREGIONHANDLER HandlerNode = (POPREGIONHANDLER) OperationRegionObject; PAGED_CODE(); // // Is there a _REG method that we should run? // if ( RegionParent != NULL ) { status = AMLIGetNameSpaceObject( "_REG", RegionParent, ®Object, NSF_LOCAL_SCOPE ); if ( NT_SUCCESS(status) ) { // // Initialize the parameters // RtlZeroMemory( regArgs, sizeof(OBJDATA) * 2 ); regArgs[0].dwDataType = OBJTYPE_INTDATA; regArgs[0].uipDataValue = HandlerNode->RegionSpace; regArgs[1].dwDataType = OBJTYPE_INTDATA; regArgs[1].uipDataValue = 0; // // Eval the request. We don't care what it returns, but we must do // it synchronously // AMLIEvalNameSpaceObject( regObject, NULL, 2, regArgs ); } } // // Call interpreter with null handler to remove the handler for this access/region // status = AMLIRegEventHandler( HandlerNode->AccessType, HandlerNode->RegionSpace, NULL, 0 ); if ( AMLIERR(status) != AMLIERR_NONE ) { return (STATUS_UNSUCCESSFUL); } // // Cleanup // ExFreePool (HandlerNode); return (STATUS_SUCCESS); }