400 lines
8.1 KiB
C
400 lines
8.1 KiB
C
/*++
|
|
|
|
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);
|
|
}
|