Today, let's explain how to invoke the user-defined method in the ACPI configuration table in the Kmdf (Kernel-mode Driver Framework). In ACPI, any method, such as _sta, that begins with an underscore, is a system-predefined method that is called by the Windows OS itself, and the other user-defined method is called by the driver.
ACPI Method
First, let's look at a method defined in ACPI:
//Global Buffer
Name(DATA, Buffer(0x4) { 0x00, 0x00, 0x00, 0x00})
Device (TEST)
{
Name (_HID, "TEST001")
Name (_UID, 1)
...
Method(GETD, 0x0, NotSerialized)
{
return (DATA)
}
Method(SETD, 0x1, NotSerialized)
{
Store(Arg0, DATA)
}
...
}
As you can see from the code, the test device provides 2 method:getd () and setd (). The global variable data is a 4-byte array, and the getd () method is used to read data and pass it to the driver, and setd () is used to write the data passed by the driver into data. To describe them in the form of a C expression, it can be written like this: uchar* getd (void); and void setd (uchar* data);
Ioctl_acpi_eval_method Request
The driver can invoke the ACPI Method by calling the wdfiotargetsendioctlsynchronously () function to send an IOCTL_ACPI_EVAL_METHOD request to the ACPI driver. For more detailed information on the IOCTL, please refer to the MSDN documentation:ioctl_acpi_eval_method Control Code
Before we write the Kmdf driver, we need to look at the following 4 structures:
Acpi_eval_input_buffer
Acpi_eval_input_buffer_complex
Acpi_eval_output_buffer
Acpi_method_argument
Acpi_eval_input_buffer Structural Body
The structure is defined as follows:
typedef struct _ACPI_EVAL_INPUT_BUFFER {
ULONG Signature;
union {
UCHAR MethodName[4];
ULONG MethodNameAsUlong;
};
} ACPI_EVAL_INPUT_BUFFER, *PACPI_EVAL_INPUT_BUFFER;
The struct is used to invoke awith no input parametersACPI method, assuming that the method to be accessed is getd (), the member variables need to be set as follows before the Ioctl_acpi_eval_method request is sent:
- Set SIGNATURE to acpi_eval_input_buffer_signature
- Set MethodName to ' getd ' or set Methodnameasulong to (ULONG) (' Dteg ')
For more detailed information on this structure, please refer to the MSDN documentation:
acpi_eval_input_buffer Structure
Acpi_eval_input_buffer_complex Structural Body
The structure is defined as follows:
typedef struct _ACPI_EVAL_INPUT_BUFFER_COMPLEX {
ULONG Signature;
union {
UCHAR MethodName[4];
ULONG MethodNameAsUlong;
};
ULONG Size;
ULONG ArgumentCount;
ACPI_METHOD_ARGUMENT Argument[ANYSIZE_ARRAY];
} ACPI_EVAL_INPUT_BUFFER_COMPLEX, *PACPI_EVAL_INPUT_BUFFER_COMPLEX;
The struct is used to invoke awith input parametersACPI method, which is used to pass input parameters, assuming that the Method to be accessed is setd (), the member variables need to be set as follows before the Ioctl_acpi_eval_method request is sent:
- Set SIGNATURE to acpi_eval_input_buffer_complex_signature
- Set MethodName to ' setd ' or set Methodnameasulong to (ULONG) (' DTEs ')
- Sets the value of size that represents the byte size of the entire array of Argument[anysize_array]
- Set the value of ArgumentCount, here is 1
- Assign values to struct member argument, set input parameters
For more detailed information on this structure, please refer to the MSDN documentation:
Acpi_eval_input_buffer_complex Structure
Acpi_eval_output_buffer Structural Body
The structure is defined as follows:
typedef struct _ACPI_EVAL_OUTPUT_BUFFER {
ULONG Signature;
ULONG Length;
ULONG Count;
ACPI_METHOD_ARGUMENT Argument[ANYSIZE_ARRAY];
} ACPI_EVAL_OUTPUT_BUFFER;
The struct is used to return the output parameter after the ACPI method executes, the output parameter is saved in the argument member variable, and the value of SIGNATURE must be acpi_eval_output_buffer_signature. Length indicates the byte size of the entire acpi_eval_output_buffer struct, and count records how many argument members are there. For more detailed information on this structure, please refer to the MSDN documentation:acpi_eval_output_buffer structure
Acpi_method_argument Structural Body
The structure is defined as follows:
typedef struct _ACPI_METHOD_ARGUMENT
USHORT Type;
USHORT DataLength;
union {
ULONG Argument;
UCHAR Data[ANYSIZE_ARRAY];
};
} ACPI_METHOD_ARGUMENT;
The structure is the place where the input and output parameters are really stored. which
Type defines the types of the parameters, which have the following values:
Acpi_method_argument_integer
Acpi_method_argument_string
Acpi_method_argument_buffer
Acpi_method_argument_package
Datalength the byte size for the array data.
For more detailed information on this structure, please refer to the MSDN documentation:acpi_method_argument structure
Sample Code
To access ACPI Method without input parameters:
NTSTATUS ACPIGetData(WDFDEVICE FxDevice, void *pBuffer)
{
NTSTATUS Status;
WDF_MEMORY_DESCRIPTOR InputDescriptor;
WDF_MEMORY_DESCRIPTOR OutputDescriptor;
ACPI_EVAL_INPUT_BUFFER InputBuffer;
ACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
WDFIOTARGET IoTarget;
ULONG SizeReturned;
USHORT DataLength;
PAGED_CODE();
//
// Signature and Method name in reverse
//
InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
InputBuffer.MethodNameAsUlong = (ULONG) ('DTEG');
//
// Use following WDF method to initialize memory descriptor
// The memory descriptor is initialized with the input buffer we have defined.
//
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&InputDescriptor,
(PVOID)&InputBuffer,
sizeof(ACPI_EVAL_INPUT_BUFFER));
RtlZeroMemory(&OutputBuffer, sizeof(OutputBuffer));
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&OutputDescriptor,
(PVOID)&OutputBuffer,
sizeof(ACPI_EVAL_OUTPUT_BUFFER));
//
// Get handle for underlying ACPI layer
//
IoTarget = WdfDeviceGetIoTarget(FxDevice);
//
// Send synchronous request
//
Status = WdfIoTargetSendIoctlSynchronously(IoTarget,
NULL,
IOCTL_ACPI_EVAL_METHOD,
&InputDescriptor,
&OutputDescriptor,
NULL,
&SizeReturned);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Verify output signature and length
//
if ((OutputBuffer.Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE)
&& (OutputBuffer.Argument[0].Type == ACPI_METHOD_ARGUMENT_BUFFER))
{
//
// Extract data from buffer
//
DataLength = OutputBuffer.Argument[0].DataLength;
memcpy_s((UINT8*)pBuffer,
(DataLength * sizeof(UINT8)),
(UINT8*)OutputBuffer.Argument[0].Data,
(DataLength * sizeof(UINT8)));
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_ACPI_INVALID_DATA;
}
exit:
return Status;
}
To access the ACPI Method with input parameters:
NTSTATUS ACPISetData(WDFDEVICE FxDevice, void *pBuffer)
{
NTSTATUS Status;
WDF_MEMORY_DESCRIPTOR InputDescriptor;
WDF_MEMORY_DESCRIPTOR OutputDescriptor;
ACPI_EVAL_INPUT_BUFFER_COMPLEX InputBuffer;
ACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
WDFIOTARGET IoTarget;
ULONG SizeReturned;
PAGED_CODE();
//
// Signature and Method name in reverse
//
InputBuffer.MethodNameAsUlong = (ULONG)('DTES');
InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
InputBuffer.ArgumentCount = 1;
InputBuffer.Size = InputBuffer.ArgumentCount * sizeof(ACPI_METHOD_ARGUMENT);
InputBuffer.Argument[0].Type = ACPI_METHOD_ARGUMENT_BUFFER;
InputBuffer.Argument[0].DataLength = 4;
memcpy_s(InputBuffer.Argument[0].Data, InputBuffer.Argument[0].DataLength,
pBuffer, InputBuffer.Argument[0].DataLength);
//
// Use following WDF method to initialize memory descriptor
// The memory descriptor is initialized with the input buffer we have defined.
//
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&InputDescriptor,
(PVOID)&InputBuffer,
sizeof(ACPI_EVAL_INPUT_BUFFER_COMPLEX));
RtlZeroMemory(&OutputBuffer, sizeof(OutputBuffer));
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&OutputDescriptor,
(PVOID)&OutputBuffer,
sizeof(ACPI_EVAL_OUTPUT_BUFFER));
//
// Get handle for underlying ACPI layer
//
IoTarget = WdfDeviceGetIoTarget(FxDevice);
//
// Send synchronous request
//
Status = WdfIoTargetSendIoctlSynchronously(IoTarget,
NULL,
IOCTL_ACPI_EVAL_METHOD,
&InputDescriptor,
&OutputDescriptor,
NULL,
&SizeReturned);
if (!NT_SUCCESS(Status))
{
goto exit;
}
else
{
//
// Verify output signature and length
//
if ( (OutputBuffer.Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE)
&& (OutputBuffer.Argument[0].Type == ACPI_METHOD_ARGUMENT_BUFFER))
{
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_ACPI_INVALID_DATA;
}
}
exit:
return Status;
}
For more detailed usage of ACPI control method, consult the MSDN official documentation:evaluating ACPI control Methods synchronously
Windows Phone 8.1 Driver Development--How to invoke ACPI Method