Windows Phone 8.1 driver development-how to call ACPI Method and drive acpi Development
Today, we will explain how to call the Method defined in the ACPI configuration table in KMDF (Kernel-Mode Driver Framework. In ACPI, all methods starting with an underscore (such as _ STA) are pre-defined methods, which are called by Windows OS, other user-defined methods are called by the driver.
ACPI Method
First, let's take a look at the Method defined in ACPI:
//Global BufferName(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) }...}
The Code shows that the TEST device provides two methods: GETD () and SETD (). The global variable DATA is a 4-byte array. The GETD () method is used to read DATA and send it to the driver. The SETD () method is used to write the DATA transmitted by the driver into the DATA. To describe them in the C language, you can write them as follows: uchar * GETD (void); and void SETD (uchar * data );
IOCTL_ACPI_EVAL_METHOD request
The driver can call the ACPI Method by calling the WdfIoTargetSendIoctlSynchronously () function and sending the IOCTL_ACPI_EVAL_METHOD request to the ACPI driver. For more information about IOCTL, refer to the MSDN documentation:IOCTL_ACPI_EVAL_METHOD control code
Before writing the KMDF driver, we need to understand the following four structures:
ACPI_EVAL_INPUT_BUFFER
ACPI_EVAL_INPUT_BUFFER_COMPLEX
ACPI_EVAL_OUTPUT_BUFFER
ACPI_METHOD_ARGUMENT
ACPI_EVAL_INPUT_BUFFER struct
Struct 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;
This struct is used to call an ACPI Method without input parameters. Assume that the Method to be accessed is GETD (). Before sending an IOCTL_ACPI_EVAL_METHOD request, you need to set its member variables as follows:
- Set SignatureACPI_EVAL_INPUT_BUFFER_SIGNATURE
- Set MethodName'Getd'Or set MethodNameAsUlong(ULONG) ('dteg ')
For more details about this struct, refer to the MSDN documentation:
ACPI_EVAL_INPUT_BUFFER structure
ACPI_EVAL_INPUT_BUFFER_COMPLEX struct
Struct 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;
This struct is used to call an ACPI Method with input parameters to pass the input parameters. Assume that the Method to be accessed is SETD (), before sending the IOCTL_ACPI_EVAL_METHOD request, you need to set its member variables as follows:
- Set SignatureACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE
- Set MethodName'Setd'Or set MethodNameAsUlong(ULONG) ('dtes ')
- Sets the Size value, which indicates the byte Size of the entire array of Argument [ANYSIZE_ARRAY]
- Set the value of ArgumentCount. Here it is 1
- Assign a value to the structure member Argument and set the input parameters.
For more details about this struct, refer to the MSDN documentation:
ACPI_EVAL_INPUT_BUFFER_COMPLEX structure
ACPI_EVAL_OUTPUT_BUFFER struct
Struct 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;
This struct is used to return the output parameters after the ACPI Method is executed. The output parameters are saved in the Argument member variables, and the value of Signature must beACPI_EVAL_OUTPUT_BUFFER_SIGNATURELength indicates the byte size of the entire ACPI_EVAL_OUTPUT_BUFFER struct, and Count records the number of Argument members. For more details about this struct, refer to the MSDN documentation:ACPI_EVAL_OUTPUT_BUFFER structure
ACPI_METHOD_ARGUMENT struct
Struct is defined as follows:
typedef struct _ACPI_METHOD_ARGUMENT USHORT Type; USHORT DataLength; union { ULONG Argument; UCHAR Data[ANYSIZE_ARRAY]; };} ACPI_METHOD_ARGUMENT;
This struct is where the input and output parameters are actually stored. Where
Type defines the parameter Type, which has the following values:
ACPI_METHOD_ARGUMENT_INTEGER
ACPI_METHOD_ARGUMENT_STRING
ACPI_METHOD_ARGUMENT_BUFFER
ACPI_METHOD_ARGUMENT_PACKAGE
DataLength is the byte size of the array Data.
For more details about this struct, refer to the MSDN documentation:ACPI_METHOD_ARGUMENT structure
Sample Code
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;}
Access 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, refer to the official MSDN documentation:Evaluating ACPI Control Methods Synchronously