1548 lines
37 KiB
C
1548 lines
37 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
acpictl.c
|
||
|
||
Abstract:
|
||
|
||
This module handles all of the INTERNAL_DEVICE_CONTROLS requested to
|
||
the ACPI driver
|
||
|
||
Author:
|
||
|
||
Stephane Plante (splante)
|
||
|
||
Environment:
|
||
|
||
NT Kernel Mode Driver only
|
||
|
||
Revision History:
|
||
|
||
01-05-98 - SGP - Complete Rewrite
|
||
01-13-98 - SGP - Cleaned up the Eval Post-Processing
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
NTSTATUS
|
||
ACPIIoctlAcquireGlobalLock(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpStack
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine acquires the global lock for another device driver
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device object stack that wants the lock
|
||
Irp - The irp with the request in it
|
||
Irpstack - The current stack within the irp
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PACPI_GLOBAL_LOCK newLock;
|
||
PACPI_MANIPULATE_GLOBAL_LOCK_BUFFER outputBuffer;
|
||
ULONG outputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
//
|
||
// Remember that we don't be returning any data
|
||
//
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Is the irp have a minimum size buffer?
|
||
//
|
||
if (outputLength < sizeof(ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER) ) {
|
||
|
||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||
goto ACPIIoctlAcquireGlobalLockExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Grab a pointer at the input buffer
|
||
//
|
||
outputBuffer = (PACPI_MANIPULATE_GLOBAL_LOCK_BUFFER)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
if (outputBuffer->Signature != ACPI_ACQUIRE_GLOBAL_LOCK_SIGNATURE) {
|
||
|
||
status = STATUS_INVALID_PARAMETER_1;
|
||
goto ACPIIoctlAcquireGlobalLockExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate storage for the lock
|
||
//
|
||
newLock = ExAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
sizeof(ACPI_GLOBAL_LOCK),
|
||
'LcpA'
|
||
);
|
||
if (newLock == NULL) {
|
||
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ACPIIoctlAcquireGlobalLockExit;
|
||
|
||
}
|
||
RtlZeroMemory( newLock, sizeof(ACPI_GLOBAL_LOCK) );
|
||
|
||
//
|
||
// Initialize the new lock and the request
|
||
//
|
||
outputBuffer->LockObject = newLock;
|
||
Irp->IoStatus.Information = sizeof(ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER);
|
||
newLock->LockContext = Irp;
|
||
newLock->Type = ACPI_GL_QTYPE_IRP;
|
||
|
||
//
|
||
// Mark the irp as pending, since we can block while acquire the lock
|
||
//
|
||
IoMarkIrpPending( Irp );
|
||
|
||
//
|
||
// Request the lock now
|
||
//
|
||
status = ACPIAsyncAcquireGlobalLock( newLock );
|
||
if (status == STATUS_PENDING) {
|
||
|
||
return status;
|
||
|
||
}
|
||
ACPIIoctlAcquireGlobalLockExit:
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIoctlAsyncEvalControlMethod(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpStack
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to handle a control method request asynchronously
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device object to run the method on
|
||
Irp - The irp with the request in it
|
||
IrpStack - THe current stack within the Irp
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PNSOBJ methodObject;
|
||
POBJDATA argumentData = NULL;
|
||
POBJDATA resultData = NULL;
|
||
ULONG argumentCount = 0;
|
||
|
||
//
|
||
// Do the pre processing on the irp
|
||
//
|
||
status = ACPIIoctlEvalPreProcessing(
|
||
DeviceObject,
|
||
Irp,
|
||
IrpStack,
|
||
NonPagedPool,
|
||
&methodObject,
|
||
&resultData,
|
||
&argumentData,
|
||
&argumentCount
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
goto ACPIIoctlAsyncEvalControlMethodExit;
|
||
|
||
}
|
||
|
||
//
|
||
// At this point, we can run the async method
|
||
//
|
||
status = AMLIAsyncEvalObject(
|
||
methodObject,
|
||
resultData,
|
||
argumentCount,
|
||
argumentData,
|
||
ACPIIoctlAsyncEvalControlMethodCompletion,
|
||
Irp
|
||
);
|
||
|
||
//
|
||
// We no longer need the arguments now. Note, that we should clean up
|
||
// the argument list because it contains pointer to another block of
|
||
// allocated data. Freeing something in the middle of the block would be
|
||
// very bad.
|
||
//
|
||
if (argumentData != NULL) {
|
||
|
||
ExFreePool( argumentData );
|
||
argumentData = NULL;
|
||
|
||
}
|
||
|
||
//
|
||
// Check the return data now
|
||
//
|
||
if (status == STATUS_PENDING) {
|
||
|
||
return status;
|
||
|
||
} else if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Do the post processing ourselves
|
||
//
|
||
status = ACPIIoctlEvalPostProcessing(
|
||
Irp,
|
||
resultData
|
||
);
|
||
AMLIFreeDataBuffs( resultData, 1 );
|
||
|
||
}
|
||
|
||
ACPIIoctlAsyncEvalControlMethodExit:
|
||
|
||
//
|
||
// No longer need this data
|
||
//
|
||
if (resultData != NULL) {
|
||
|
||
ExFreePool( resultData );
|
||
|
||
}
|
||
|
||
//
|
||
// If we got here, then we must complete the irp and return
|
||
//
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
return status;
|
||
}
|
||
|
||
VOID EXPORT
|
||
ACPIIoctlAsyncEvalControlMethodCompletion(
|
||
IN PNSOBJ AcpiObject,
|
||
IN NTSTATUS Status,
|
||
IN POBJDATA ObjectData,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called after the interpreter has had a chance to run
|
||
the method
|
||
|
||
Arguments:
|
||
|
||
AcpiObject - The object that the method was run on
|
||
Status - The status of the eval
|
||
ObjectData - The result of the eval
|
||
Context - Specific to the caller
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PIRP irp = (PIRP) Context;
|
||
|
||
//
|
||
// Did we succeed the request?
|
||
//
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// Do the work now
|
||
//
|
||
Status = ACPIIoctlEvalPostProcessing(
|
||
irp,
|
||
ObjectData
|
||
);
|
||
AMLIFreeDataBuffs( ObjectData, 1 );
|
||
|
||
}
|
||
|
||
//
|
||
// No longer need this data
|
||
//
|
||
ExFreePool( ObjectData );
|
||
|
||
//
|
||
// If our completion routine got called, then AMLIAsyncEvalObject returned
|
||
// STATUS_PENDING. Be sure to mark the IRP pending before we complete it.
|
||
//
|
||
IoMarkIrpPending(irp);
|
||
|
||
//
|
||
// Complete the request
|
||
//
|
||
irp->IoStatus.Status = Status;
|
||
IoCompleteRequest( irp, IO_NO_INCREMENT );
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIoctlCalculateOutputBuffer(
|
||
IN POBJDATA ObjectData,
|
||
IN PACPI_METHOD_ARGUMENT Argument,
|
||
IN BOOLEAN TopLevel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to fill the contents of Argument with the
|
||
information provided by the ObjectData. This function is recursive.
|
||
|
||
It assumes that the correct amount of storage was allocated for Argument.
|
||
|
||
Note: To add the ability to return nested packages without breaking W2K
|
||
behavior, the outermost package is not part of the output buffer.
|
||
I.e. anything that was a package will have its outermost
|
||
ACPI_EVAL_OUTPUT_BUFFER.Count be more than 1.
|
||
|
||
Arguments:
|
||
|
||
ObjectData - The information that we need to propogate
|
||
Argument - The location to propogate that information
|
||
TopLevel - Indicates whether we are at the top level of recursion
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
POBJDATA objData;
|
||
PPACKAGEOBJ package;
|
||
ULONG count;
|
||
ULONG packageCount;
|
||
ULONG packageSize;
|
||
PACPI_METHOD_ARGUMENT packageArgument;
|
||
|
||
ASSERT( Argument );
|
||
|
||
//
|
||
// Fill in the output buffer arguments
|
||
//
|
||
if (ObjectData->dwDataType == OBJTYPE_INTDATA) {
|
||
|
||
Argument->Type = ACPI_METHOD_ARGUMENT_INTEGER;
|
||
Argument->DataLength = sizeof(ULONG);
|
||
Argument->Argument = (ULONG) ObjectData->uipDataValue;
|
||
|
||
} else if (ObjectData->dwDataType == OBJTYPE_STRDATA ||
|
||
ObjectData->dwDataType == OBJTYPE_BUFFDATA) {
|
||
|
||
Argument->Type = (ObjectData->dwDataType == OBJTYPE_STRDATA ?
|
||
ACPI_METHOD_ARGUMENT_STRING : ACPI_METHOD_ARGUMENT_BUFFER);
|
||
Argument->DataLength = (USHORT)ObjectData->dwDataLen;
|
||
RtlCopyMemory(
|
||
Argument->Data,
|
||
ObjectData->pbDataBuff,
|
||
ObjectData->dwDataLen
|
||
);
|
||
|
||
} else if (ObjectData->dwDataType == OBJTYPE_PKGDATA) {
|
||
|
||
package = (PPACKAGEOBJ) ObjectData->pbDataBuff;
|
||
|
||
//
|
||
// Get the size of the space necessary to store a package's
|
||
// data. We are really only interested in the amount of
|
||
// data the package will consume *without* its header
|
||
// information. Passing TRUE as the last parameter will
|
||
// give us that.
|
||
//
|
||
|
||
packageSize = 0;
|
||
packageCount = 0;
|
||
status = ACPIIoctlCalculateOutputBufferSize(ObjectData,
|
||
&packageSize,
|
||
&packageCount,
|
||
TRUE);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
ASSERT(packageCount == package->dwcElements);
|
||
|
||
if (!TopLevel) {
|
||
//
|
||
// Create a package argument.
|
||
//
|
||
|
||
Argument->Type = ACPI_METHOD_ARGUMENT_PACKAGE;
|
||
Argument->DataLength = (USHORT)packageSize;
|
||
|
||
packageArgument = (PACPI_METHOD_ARGUMENT)
|
||
((PUCHAR)Argument + FIELD_OFFSET(ACPI_METHOD_ARGUMENT, Data));
|
||
|
||
} else {
|
||
|
||
packageArgument = Argument;
|
||
}
|
||
|
||
for (count = 0; count < package->dwcElements; count++) {
|
||
|
||
objData = &(package->adata[count]);
|
||
status = ACPIIoctlCalculateOutputBuffer(
|
||
objData,
|
||
packageArgument,
|
||
FALSE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Point to the next argument
|
||
//
|
||
|
||
packageArgument = ACPI_METHOD_NEXT_ARGUMENT(packageArgument);
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// We don't understand this data type, we won't return anything
|
||
//
|
||
return STATUS_ACPI_INVALID_DATA;
|
||
|
||
}
|
||
|
||
//
|
||
// Success
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIoctlCalculateOutputBufferSize(
|
||
IN POBJDATA ObjectData,
|
||
IN PULONG BufferSize,
|
||
IN PULONG BufferCount,
|
||
IN BOOLEAN TopLevel
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine (recursively) calculates the amount of buffer space required
|
||
to hold the flattened contents of ObjectData. This information is returned
|
||
in BufferSize data location...
|
||
|
||
If the ObjectData structure contains information that cannot be expressed
|
||
to the user, then this routine will return a failure code.
|
||
|
||
Arguments:
|
||
|
||
ObjectData - The object whose size we have to calculate
|
||
BufferSize - Where to put that size
|
||
BufferCount - The number of elements that we are allocating for
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
POBJDATA objData;
|
||
PPACKAGEOBJ package;
|
||
ULONG bufferLength;
|
||
ULONG count;
|
||
ULONG packageCount;
|
||
ULONG dummyCount;
|
||
|
||
//
|
||
// Determine how much buffer space is required to hold the
|
||
// flattened data structure
|
||
//
|
||
if (ObjectData->dwDataType == OBJTYPE_INTDATA) {
|
||
|
||
bufferLength = ACPI_METHOD_ARGUMENT_LENGTH( sizeof(ULONG) );
|
||
*BufferCount = 1;
|
||
|
||
} else if (ObjectData->dwDataType == OBJTYPE_STRDATA ||
|
||
ObjectData->dwDataType == OBJTYPE_BUFFDATA) {
|
||
|
||
bufferLength = ACPI_METHOD_ARGUMENT_LENGTH( ObjectData->dwDataLen );
|
||
*BufferCount = 1;
|
||
|
||
} else if (ObjectData->dwDataType == OBJTYPE_PKGDATA) {
|
||
|
||
//
|
||
// Remember that walking the package means that we have accounted for
|
||
// the length of the package and the number of elements within the
|
||
// package
|
||
//
|
||
packageCount = 0;
|
||
|
||
//
|
||
// Walk the package
|
||
//
|
||
package = (PPACKAGEOBJ) ObjectData->pbDataBuff;
|
||
|
||
if (!TopLevel) {
|
||
|
||
//
|
||
// Packages are contained in an ACPI_METHOD_ARGUMENT structure.
|
||
// So add enough for the overhead of one of these before looking
|
||
// at the children.
|
||
//
|
||
bufferLength = FIELD_OFFSET(ACPI_METHOD_ARGUMENT, Data);
|
||
*BufferCount = 1;
|
||
|
||
} else {
|
||
|
||
bufferLength = 0;
|
||
*BufferCount = package->dwcElements;
|
||
}
|
||
|
||
for (count = 0; count < package->dwcElements; count++) {
|
||
|
||
objData = &(package->adata[count]);
|
||
status = ACPIIoctlCalculateOutputBufferSize(
|
||
objData,
|
||
BufferSize,
|
||
&dummyCount,
|
||
FALSE
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
}
|
||
|
||
} else if (ObjectData->dwDataType == OBJTYPE_UNKNOWN) {
|
||
|
||
*BufferCount = 1;
|
||
bufferLength = 0;
|
||
|
||
} else {
|
||
|
||
//
|
||
// We don't understand this data type, so we won't return anything
|
||
//
|
||
ASSERT(FALSE);
|
||
return STATUS_ACPI_INVALID_DATA;
|
||
}
|
||
|
||
//
|
||
// Update the package lengths
|
||
//
|
||
ASSERT( BufferSize && BufferCount );
|
||
*BufferSize += bufferLength;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIoctlEvalControlMethod(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpStack
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to handle a control method request synchronously
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device object to run the method on
|
||
Irp - The irp with the request in it
|
||
IrpStack - THe current stack within the Irp
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PNSOBJ methodObject;
|
||
POBJDATA argumentData = NULL;
|
||
POBJDATA resultData = NULL;
|
||
ULONG argumentCount = 0;
|
||
|
||
//
|
||
// Do the pre processing on the irp
|
||
//
|
||
status = ACPIIoctlEvalPreProcessing(
|
||
DeviceObject,
|
||
Irp,
|
||
IrpStack,
|
||
PagedPool,
|
||
&methodObject,
|
||
&resultData,
|
||
&argumentData,
|
||
&argumentCount
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
goto ACPIIoctlEvalControlMethodExit;
|
||
|
||
}
|
||
|
||
//
|
||
// At this point, we can run the async method
|
||
//
|
||
status = AMLIEvalNameSpaceObject(
|
||
methodObject,
|
||
resultData,
|
||
argumentCount,
|
||
argumentData
|
||
);
|
||
|
||
//
|
||
// We no longer need the arguments now
|
||
//
|
||
if (argumentData != NULL) {
|
||
|
||
ExFreePool( argumentData );
|
||
argumentData = NULL;
|
||
|
||
}
|
||
|
||
//
|
||
// Check the return data now and fake a call to the completion routine
|
||
//
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Do the post processing now
|
||
//
|
||
status = ACPIIoctlEvalPostProcessing(
|
||
Irp,
|
||
resultData
|
||
);
|
||
AMLIFreeDataBuffs( resultData, 1 );
|
||
|
||
}
|
||
|
||
ACPIIoctlEvalControlMethodExit:
|
||
|
||
//
|
||
// No longer need this data
|
||
//
|
||
if (resultData != NULL) {
|
||
|
||
ExFreePool( resultData );
|
||
|
||
}
|
||
|
||
//
|
||
// If we got here, then we must complete the irp and return
|
||
//
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIoctlEvalPostProcessing(
|
||
IN PIRP Irp,
|
||
IN POBJDATA ObjectData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles convering the ObjectData into information
|
||
that can be passed back into the irp.
|
||
|
||
N.B. This routine does *not* complete the irp. The caller must
|
||
do that. This routine is also *not* pageable
|
||
|
||
Arguments:
|
||
|
||
Irp - The irp that will hold the results
|
||
ObjectData - The result to convert
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Same as in Irp->IoStatus.Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PACPI_EVAL_OUTPUT_BUFFER outputBuffer;
|
||
PACPI_METHOD_ARGUMENT arg;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
ULONG bufferLength = 0;
|
||
ULONG outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
||
ULONG packageCount = 0;
|
||
|
||
//
|
||
// If we don't have an output buffer, then we can complete the request
|
||
//
|
||
if (outputLength == 0) {
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
//
|
||
// Count the amount of space taken up by the flattened data and how many
|
||
// elements of data are contained therein
|
||
//
|
||
bufferLength = 0;
|
||
packageCount = 0;
|
||
status = ACPIIoctlCalculateOutputBufferSize(
|
||
ObjectData,
|
||
&bufferLength,
|
||
&packageCount,
|
||
TRUE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// We don't understand a data type in the handling of the data, so
|
||
// we won't return anything
|
||
//
|
||
Irp->IoStatus.Information = 0;
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
//
|
||
// Add in the fudge factor that we need to account for the Output buffer
|
||
//
|
||
bufferLength += (sizeof(ACPI_EVAL_OUTPUT_BUFFER) -
|
||
sizeof(ACPI_METHOD_ARGUMENT) );
|
||
|
||
if (bufferLength < sizeof(ACPI_EVAL_OUTPUT_BUFFER)) {
|
||
bufferLength = sizeof(ACPI_EVAL_OUTPUT_BUFFER);
|
||
}
|
||
|
||
//
|
||
// Setup the Output buffer
|
||
//
|
||
if (outputLength >= sizeof(ACPI_EVAL_OUTPUT_BUFFER)) {
|
||
|
||
outputBuffer = (PACPI_EVAL_OUTPUT_BUFFER) Irp->AssociatedIrp.SystemBuffer;
|
||
outputBuffer->Signature = ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE;
|
||
outputBuffer->Length = bufferLength;
|
||
outputBuffer->Count = packageCount;
|
||
arg = outputBuffer->Argument;
|
||
|
||
}
|
||
|
||
//
|
||
// Make sure that we have enough output buffer space
|
||
//
|
||
if (bufferLength > outputLength) {
|
||
|
||
Irp->IoStatus.Information = sizeof(ACPI_EVAL_OUTPUT_BUFFER);
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
|
||
|
||
} else {
|
||
|
||
Irp->IoStatus.Information = bufferLength;
|
||
|
||
}
|
||
|
||
status = ACPIIoctlCalculateOutputBuffer(
|
||
ObjectData,
|
||
arg,
|
||
TRUE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// We don't understand a data type in the handling of the data, so we
|
||
// won't return anything
|
||
//
|
||
Irp->IoStatus.Information = 0;
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIoctlEvalPreProcessing(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpStack,
|
||
IN POOL_TYPE PoolType,
|
||
OUT PNSOBJ *MethodObject,
|
||
OUT POBJDATA *ResultData,
|
||
OUT POBJDATA *ArgumentData,
|
||
OUT ULONG *ArgumentCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine converts the request in an Irp into the structures
|
||
required by the AML Interpreter
|
||
|
||
N.B. This routine does *not* complete the irp. The caller must
|
||
do that. This routine is also *not* pageable
|
||
|
||
Arguments:
|
||
|
||
Irp - The request
|
||
IrpStack - The current stack location in the request
|
||
PoolType - Which type of memory to allocate
|
||
MethodObject - Pointer to which object to run
|
||
ResultData - Pointer to where to store the result
|
||
ArgumentData - Pointer to the arguments
|
||
ArgumentCount - Potiner to the number of arguments
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PACPI_EVAL_INPUT_BUFFER inputBuffer;
|
||
PNSOBJ acpiObject;
|
||
PNSOBJ methodObject;
|
||
POBJDATA argumentData = NULL;
|
||
POBJDATA resultData = NULL;
|
||
UCHAR methodName[5];
|
||
ULONG argumentCount = 0;
|
||
ULONG inputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
|
||
ULONG outputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
||
//
|
||
// Do this step before we do anything else --- this way we won't
|
||
// overwrite anything is someone tries to return some data
|
||
//
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Is the irp have a minimum size buffer?
|
||
//
|
||
if (inputLength < sizeof(ACPI_EVAL_INPUT_BUFFER) ) {
|
||
|
||
return STATUS_INFO_LENGTH_MISMATCH;
|
||
|
||
}
|
||
|
||
//
|
||
// Do we have a non-null output length? if so, then it must meet the
|
||
// minimum size
|
||
//
|
||
if (outputLength != 0 && outputLength < sizeof(ACPI_EVAL_OUTPUT_BUFFER)) {
|
||
|
||
return STATUS_BUFFER_TOO_SMALL;
|
||
|
||
}
|
||
|
||
//
|
||
// Grab a pointer at the input buffer
|
||
//
|
||
inputBuffer = (PACPI_EVAL_INPUT_BUFFER) Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
//
|
||
// Convert the name to a null terminated string
|
||
//
|
||
RtlZeroMemory( methodName, 5 * sizeof(UCHAR) );
|
||
RtlCopyMemory( methodName, inputBuffer->MethodName, sizeof(NAMESEG) );
|
||
|
||
//
|
||
// Search for the name space object that corresponds to the one that we
|
||
// being asked about
|
||
//
|
||
acpiObject = OSConvertDeviceHandleToPNSOBJ( DeviceObject );
|
||
if (acpiObject == NULL) {
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
|
||
}
|
||
status = AMLIGetNameSpaceObject(
|
||
methodName,
|
||
acpiObject,
|
||
&methodObject,
|
||
NSF_LOCAL_SCOPE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
//
|
||
// Allocate memory for return data
|
||
//
|
||
resultData = ExAllocatePoolWithTag( PoolType, sizeof(OBJDATA), 'RcpA' );
|
||
if (resultData == NULL) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
//
|
||
// What we do is really based on what the signature in this buffer is
|
||
//
|
||
switch (inputBuffer->Signature) {
|
||
case ACPI_EVAL_INPUT_BUFFER_SIGNATURE:
|
||
|
||
//
|
||
// Nothing to do here
|
||
//
|
||
break;
|
||
|
||
case ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE:
|
||
case ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING_SIGNATURE:
|
||
|
||
//
|
||
// We need to create a single argument to pass to the function
|
||
//
|
||
argumentCount = 1;
|
||
argumentData = ExAllocatePoolWithTag(
|
||
PoolType,
|
||
sizeof(OBJDATA),
|
||
'AcpA'
|
||
);
|
||
if (argumentData == NULL) {
|
||
|
||
ExFreePool( resultData );
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
//
|
||
// Initialize the argument to the proper value
|
||
//
|
||
RtlZeroMemory( argumentData, sizeof(OBJDATA) );
|
||
if (inputBuffer->Signature == ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE) {
|
||
|
||
PACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER integerBuffer;
|
||
|
||
integerBuffer = (PACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER) inputBuffer;
|
||
|
||
argumentData->dwDataType = OBJTYPE_INTDATA;
|
||
argumentData->uipDataValue = integerBuffer->IntegerArgument;
|
||
|
||
} else {
|
||
|
||
PACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING stringBuffer;
|
||
|
||
stringBuffer = (PACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING) inputBuffer;
|
||
|
||
argumentData->dwDataType = OBJTYPE_STRDATA;
|
||
argumentData->dwDataLen = stringBuffer->StringLength;
|
||
argumentData->pbDataBuff = stringBuffer->String;
|
||
|
||
}
|
||
break;
|
||
|
||
case ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE: {
|
||
|
||
PACPI_EVAL_INPUT_BUFFER_COMPLEX complexBuffer;
|
||
PACPI_METHOD_ARGUMENT methodArgument;
|
||
ULONG i;
|
||
|
||
complexBuffer = (PACPI_EVAL_INPUT_BUFFER_COMPLEX) inputBuffer;
|
||
|
||
//
|
||
// Do we need to create any arguments?
|
||
//
|
||
if (complexBuffer->ArgumentCount == 0) {
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Create the object data structures to hold these arguments
|
||
//
|
||
argumentCount = complexBuffer->ArgumentCount;
|
||
methodArgument = complexBuffer->Argument;
|
||
argumentData = ExAllocatePoolWithTag(
|
||
PoolType,
|
||
sizeof(OBJDATA) * argumentCount,
|
||
'AcpA'
|
||
);
|
||
if (argumentData == NULL) {
|
||
|
||
ExFreePool( resultData );
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
RtlZeroMemory( argumentData, argumentCount * sizeof(OBJDATA) );
|
||
for (i = 0; i < argumentCount; i++) {
|
||
|
||
if (methodArgument->Type == ACPI_METHOD_ARGUMENT_INTEGER) {
|
||
|
||
(argumentData[i]).dwDataType = OBJTYPE_INTDATA;
|
||
(argumentData[i]).uipDataValue = methodArgument->Argument;
|
||
|
||
} else {
|
||
|
||
(argumentData[i]).dwDataLen = methodArgument->DataLength;
|
||
(argumentData[i]).pbDataBuff = methodArgument->Data;
|
||
if (methodArgument->Type == ACPI_METHOD_ARGUMENT_STRING) {
|
||
|
||
(argumentData[i]).dwDataType = OBJTYPE_STRDATA;
|
||
|
||
} else {
|
||
|
||
(argumentData[i]).dwDataType = OBJTYPE_BUFFDATA;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Look at the next method
|
||
//
|
||
methodArgument = ACPI_METHOD_NEXT_ARGUMENT( methodArgument );
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
}
|
||
default:
|
||
|
||
return STATUS_INVALID_PARAMETER_1;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the proper pointers
|
||
//
|
||
*MethodObject = methodObject;
|
||
*ResultData = resultData;
|
||
*ArgumentData = argumentData;
|
||
*ArgumentCount = argumentCount;
|
||
|
||
//
|
||
// Done pre-processing
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIoctlRegisterOpRegionHandler(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpStack
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handle the registration of the an Operation Region
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The DeviceObject that the region is getting
|
||
registered on
|
||
Irp - The request
|
||
IrpStack - Our part of the request
|
||
|
||
Return Value
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PACPI_REGISTER_OPREGION_HANDLER_BUFFER inputBuffer;
|
||
PACPI_UNREGISTER_OPREGION_HANDLER_BUFFER outputBuffer;
|
||
PNSOBJ regionObject;
|
||
PVOID opregionObject;
|
||
ULONG accessType;
|
||
ULONG inputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
|
||
ULONG outputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
||
ULONG regionSpace;
|
||
|
||
//
|
||
// Grab the acpi object that corresponds to the current one
|
||
//
|
||
regionObject = OSConvertDeviceHandleToPNSOBJ( DeviceObject );
|
||
|
||
//
|
||
// Preload this value. This is so that we don't have to remember how
|
||
// many bytes we will return
|
||
//
|
||
Irp->IoStatus.Information = sizeof(ACPI_REGISTER_OPREGION_HANDLER_BUFFER);
|
||
|
||
//
|
||
// Is the irp have a minimum size buffer?
|
||
//
|
||
if (inputLength < sizeof(ACPI_REGISTER_OPREGION_HANDLER_BUFFER) ) {
|
||
|
||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||
goto ACPIIoctlRegisterOpRegionHandlerExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Do we have a non-null output length? if so, then it must meet the
|
||
// minimum size
|
||
//
|
||
if (outputLength < sizeof(ACPI_UNREGISTER_OPREGION_HANDLER_BUFFER) ) {
|
||
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
goto ACPIIoctlRegisterOpRegionHandlerExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Grab a pointer at the input buffer
|
||
//
|
||
inputBuffer = (PACPI_REGISTER_OPREGION_HANDLER_BUFFER)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
//
|
||
// Is this an input buffer?
|
||
//
|
||
if (inputBuffer->Signature != ACPI_REGISTER_OPREGION_HANDLER_BUFFER_SIGNATURE) {
|
||
|
||
status = STATUS_ACPI_INVALID_DATA;
|
||
goto ACPIIoctlRegisterOpRegionHandlerExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Set the correct access type
|
||
//
|
||
switch (inputBuffer->AccessType) {
|
||
case ACPI_OPREGION_ACCESS_AS_RAW:
|
||
|
||
accessType = EVTYPE_RS_RAWACCESS;
|
||
break;
|
||
|
||
case ACPI_OPREGION_ACCESS_AS_COOKED:
|
||
|
||
accessType = EVTYPE_RS_COOKACCESS;
|
||
break;
|
||
|
||
default:
|
||
|
||
status = STATUS_ACPI_INVALID_DATA;
|
||
goto ACPIIoctlRegisterOpRegionHandlerExit;
|
||
}
|
||
|
||
//
|
||
// Set the correct region space
|
||
//
|
||
switch (inputBuffer->RegionSpace) {
|
||
case ACPI_OPREGION_REGION_SPACE_MEMORY:
|
||
|
||
regionSpace = REGSPACE_MEM;
|
||
break;
|
||
|
||
case ACPI_OPREGION_REGION_SPACE_IO:
|
||
|
||
regionSpace = REGSPACE_IO;
|
||
break;
|
||
|
||
case ACPI_OPREGION_REGION_SPACE_PCI_CONFIG:
|
||
|
||
regionSpace = REGSPACE_PCICFG;
|
||
break;
|
||
|
||
case ACPI_OPREGION_REGION_SPACE_EC:
|
||
|
||
regionSpace = REGSPACE_EC;
|
||
break;
|
||
|
||
case ACPI_OPREGION_REGION_SPACE_SMB:
|
||
|
||
regionSpace = REGSPACE_SMB;
|
||
break;
|
||
|
||
case ACPI_OPREGION_REGION_SPACE_CMOS_CONFIG:
|
||
|
||
regionSpace = REGSPACE_CMOSCFG;
|
||
break;
|
||
|
||
case ACPI_OPREGION_REGION_SPACE_PCIBARTARGET:
|
||
|
||
regionSpace = REGSPACE_PCIBARTARGET;
|
||
break;
|
||
|
||
default:
|
||
|
||
if (inputBuffer->RegionSpace >= 0x80 &&
|
||
inputBuffer->RegionSpace <= 0xff ) {
|
||
|
||
//
|
||
// This one is vendor-defined. Just use
|
||
// the value that the vendor passed in.
|
||
//
|
||
|
||
regionSpace = inputBuffer->RegionSpace;
|
||
break;
|
||
}
|
||
|
||
status = STATUS_ACPI_INVALID_DATA;
|
||
goto ACPIIoctlRegisterOpRegionHandlerExit;
|
||
}
|
||
|
||
//
|
||
// Evaluate the registration
|
||
//
|
||
status = RegisterOperationRegionHandler(
|
||
regionObject,
|
||
accessType,
|
||
regionSpace,
|
||
(PFNHND) inputBuffer->Handler,
|
||
(ULONG_PTR)inputBuffer->Context,
|
||
&opregionObject
|
||
);
|
||
|
||
//
|
||
// If we succeeded, then setup the output buffer
|
||
//
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
outputBuffer = (PACPI_UNREGISTER_OPREGION_HANDLER_BUFFER)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
outputBuffer->Signature = ACPI_UNREGISTER_OPREGION_HANDLER_BUFFER_SIGNATURE;
|
||
outputBuffer->OperationRegionObject = opregionObject;
|
||
Irp->IoStatus.Information =
|
||
sizeof(ACPI_UNREGISTER_OPREGION_HANDLER_BUFFER);
|
||
|
||
}
|
||
|
||
ACPIIoctlRegisterOpRegionHandlerExit:
|
||
|
||
//
|
||
// Done with the request
|
||
//
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
//
|
||
// return with the status code
|
||
//
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIoctlReleaseGlobalLock(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpStack
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to release the global lock
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The Device object that is releasing the lock
|
||
Irp - The request
|
||
IrpStack - Our part of the request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PACPI_GLOBAL_LOCK acpiLock;
|
||
PACPI_MANIPULATE_GLOBAL_LOCK_BUFFER inputBuffer;
|
||
ULONG inputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
||
//
|
||
// Remember that we don't be returning any data
|
||
//
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Is the irp have a minimum size buffer?
|
||
//
|
||
if (inputLength < sizeof(ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER) ) {
|
||
|
||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||
goto ACPIIoctlReleaseGlobalLockExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Grab a pointer at the input buffer
|
||
//
|
||
inputBuffer = (PACPI_MANIPULATE_GLOBAL_LOCK_BUFFER)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
if (inputBuffer->Signature != ACPI_RELEASE_GLOBAL_LOCK_SIGNATURE) {
|
||
|
||
status = STATUS_INVALID_PARAMETER_1;
|
||
goto ACPIIoctlReleaseGlobalLockExit;
|
||
|
||
}
|
||
acpiLock = inputBuffer->LockObject;
|
||
|
||
//
|
||
// Release the lock now
|
||
//
|
||
status = ACPIReleaseGlobalLock( acpiLock );
|
||
|
||
//
|
||
// Free the memory for the lock
|
||
//
|
||
ExFreePool( acpiLock );
|
||
|
||
ACPIIoctlReleaseGlobalLockExit:
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIoctlUnRegisterOpRegionHandler(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpStack
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handle the unregistration of the an Operation Region
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The DeviceObject that the region is getting
|
||
registered on
|
||
Irp - The request
|
||
IrpStack - Our part of the request
|
||
|
||
NTSTATUS
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PACPI_UNREGISTER_OPREGION_HANDLER_BUFFER inputBuffer;
|
||
PNSOBJ regionObject;
|
||
ULONG inputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
||
//
|
||
// Grab the region object that corresponds to the requested on
|
||
//
|
||
regionObject = OSConvertDeviceHandleToPNSOBJ( DeviceObject );
|
||
|
||
//
|
||
// Is the irp have a minimum size buffer?
|
||
//
|
||
if (inputLength < sizeof(ACPI_UNREGISTER_OPREGION_HANDLER_BUFFER) ) {
|
||
|
||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||
goto ACPIIoctlUnRegisterOpRegionHandlerExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Grab a pointer at the input buffer
|
||
//
|
||
inputBuffer = (PACPI_UNREGISTER_OPREGION_HANDLER_BUFFER)
|
||
Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
//
|
||
// Evaluate the registration
|
||
//
|
||
status = UnRegisterOperationRegionHandler(
|
||
regionObject,
|
||
inputBuffer->OperationRegionObject
|
||
);
|
||
|
||
ACPIIoctlUnRegisterOpRegionHandlerExit:
|
||
|
||
//
|
||
// Done with the request
|
||
//
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = 0;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
//
|
||
// return with the status code
|
||
//
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIIrpDispatchDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles the INTERNAL_DEVICE_CONTROLs that are sent to
|
||
an ACPI Device Object
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device object that received the request
|
||
Irp - The request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp );
|
||
ULONG ioctlCode;
|
||
|
||
//
|
||
// Make sure that this is an internally generated irp
|
||
//
|
||
if (Irp->RequestorMode != KernelMode) {
|
||
|
||
status = ACPIDispatchForwardIrp( DeviceObject, Irp );
|
||
return status;
|
||
|
||
}
|
||
|
||
//
|
||
// Grab what we need out of the current irp stack
|
||
//
|
||
ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
|
||
|
||
//
|
||
// What is the IOCTL that we need to handle?
|
||
//
|
||
switch (ioctlCode ) {
|
||
case IOCTL_ACPI_ASYNC_EVAL_METHOD:
|
||
|
||
//
|
||
// Handle this elsewhere
|
||
//
|
||
status = ACPIIoctlAsyncEvalControlMethod(
|
||
DeviceObject,
|
||
Irp,
|
||
irpStack
|
||
);
|
||
break;
|
||
|
||
case IOCTL_ACPI_EVAL_METHOD:
|
||
|
||
//
|
||
// Handle this elsewhere
|
||
//
|
||
status = ACPIIoctlEvalControlMethod(
|
||
DeviceObject,
|
||
Irp,
|
||
irpStack
|
||
);
|
||
break;
|
||
|
||
case IOCTL_ACPI_REGISTER_OPREGION_HANDLER:
|
||
|
||
//
|
||
// Handle this elsewhere
|
||
//
|
||
status = ACPIIoctlRegisterOpRegionHandler(
|
||
DeviceObject,
|
||
Irp,
|
||
irpStack
|
||
);
|
||
break;
|
||
|
||
case IOCTL_ACPI_UNREGISTER_OPREGION_HANDLER:
|
||
|
||
//
|
||
// Handle this elsewhere
|
||
//
|
||
status = ACPIIoctlUnRegisterOpRegionHandler(
|
||
DeviceObject,
|
||
Irp,
|
||
irpStack
|
||
);
|
||
break;
|
||
|
||
case IOCTL_ACPI_ACQUIRE_GLOBAL_LOCK:
|
||
|
||
//
|
||
// Handle this elsewhere
|
||
//
|
||
status = ACPIIoctlAcquireGlobalLock(
|
||
DeviceObject,
|
||
Irp,
|
||
irpStack
|
||
);
|
||
break;
|
||
|
||
case IOCTL_ACPI_RELEASE_GLOBAL_LOCK:
|
||
|
||
//
|
||
// Handle this elsewhere
|
||
//
|
||
status = ACPIIoctlReleaseGlobalLock(
|
||
DeviceObject,
|
||
Irp,
|
||
irpStack
|
||
);
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// Handle this with the default mechanism
|
||
//
|
||
status = ACPIDispatchForwardIrp( DeviceObject, Irp );
|
||
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return status;
|
||
|
||
}
|
||
|