Windows Phone 8.1 驱动开发——如何调用ACPI Method

来源:互联网 发布:学java能做游戏吗 编辑:程序博客网 时间:2024/06/04 23:33
今天给大家讲解一下,在KMDF(Kernel-Mode Driver Framework)中是如何调用ACPI配置表中用户定义的Method。在ACPI中,凡是以下划线开头的Method(如_STA)都系统预定义的Method,它们都由Windows OS自己调用,其他用户自定义Method则由驱动程序调用。


ACPI Method

首先我们来看一段在ACPI中定义的Method:

//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)    }...}
从代码中可以看到,该TEST设备提供了2个Method:GETD()和SETD()。全局变量DATA为4字节数组,GETD()方法用于读取DATA的数据并传给驱动程序,SETD()则用于将驱动程序传过来的数据写入DATA中去。用C语言的表现形式来描述它们的话,就可以写成这样:uchar* GETD(void); 和 void SETD(uchar* data);


IOCTL_ACPI_EVAL_METHOD 请求

驱动程序可以通过调用WdfIoTargetSendIoctlSynchronously()函数发送IOCTL_ACPI_EVAL_METHOD请求给ACPI驱动来调用ACPI Method。关于该IOCTL更详细的信息,请查阅MSDN文档:IOCTL_ACPI_EVAL_METHOD control code

在编写KMDF驱动之前,我们需要先了解一下以下4个结构体:

    ACPI_EVAL_INPUT_BUFFER

    ACPI_EVAL_INPUT_BUFFER_COMPLEX

    ACPI_EVAL_OUTPUT_BUFFER

    ACPI_METHOD_ARGUMENT


ACPI_EVAL_INPUT_BUFFER结构体

结构体定义如下:

typedef struct _ACPI_EVAL_INPUT_BUFFER {  ULONG Signature;  union {    UCHAR MethodName[4];    ULONG MethodNameAsUlong;  };} ACPI_EVAL_INPUT_BUFFER, *PACPI_EVAL_INPUT_BUFFER;
该结构体用于调用一个不带输入参数的ACPI Method,假设要访问的Method为GETD(),在发送IOCTL_ACPI_EVAL_METHOD请求之前,需要对其成员变量进行如下设置:
  • 设置Signature为ACPI_EVAL_INPUT_BUFFER_SIGNATURE
  • 设置MethodName为 'GETD' 或设置MethodNameAsUlong为 (ULONG)('DTEG')
关于该结构体更详细的信息,请查阅MSDN文档:ACPI_EVAL_INPUT_BUFFER structure 


ACPI_EVAL_INPUT_BUFFER_COMPLEX结构体

结构体定义如下:

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;
该结构体用于调用一个带输入参数的ACPI Method,用来传递输入参数,假设要访问的Method为SETD(),在发送IOCTL_ACPI_EVAL_METHOD请求之前,需要对其成员变量进行如下设置:
  • 设置Signature为ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE
  • 设置MethodName为 'SETD' 或设置MethodNameAsUlong为 (ULONG)('DTES')
  • 设置Size的值,该值表示Argument[ANYSIZE_ARRAY]整个数组的字节大小
  • 设置ArgumentCount的值,这里为1
  • 给结构体成员Argument赋值,设置输入参数
关于该结构体更详细的信息,请查阅MSDN文档:ACPI_EVAL_INPUT_BUFFER_COMPLEX structure 


ACPI_EVAL_OUTPUT_BUFFER结构体

结构体定义如下:

typedef struct _ACPI_EVAL_OUTPUT_BUFFER {  ULONG                Signature;  ULONG                Length;  ULONG                Count;  ACPI_METHOD_ARGUMENT Argument[ANYSIZE_ARRAY];} ACPI_EVAL_OUTPUT_BUFFER;

该结构体用于返回ACPI Method执行后的输出参数,输出参数将被保存在Argument成员变量中,Signature的值必须为ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE,Length表示整个ACPI_EVAL_OUTPUT_BUFFER结构体的字节大小,Count记录了有多少个Argument成员。关于该结构体更详细的信息,请查阅MSDN文档:ACPI_EVAL_OUTPUT_BUFFER structure 


ACPI_METHOD_ARGUMENT结构体

结构体定义如下:

typedef struct _ACPI_METHOD_ARGUMENT  USHORT Type;  USHORT DataLength;  union {    ULONG Argument;    UCHAR Data[ANYSIZE_ARRAY];  };} ACPI_METHOD_ARGUMENT;

该结构体才是真正存储输入、输出参数的地方。其中

Type定义了参数的类型,它的值有以下几种:

    ACPI_METHOD_ARGUMENT_INTEGER

    ACPI_METHOD_ARGUMENT_STRING

    ACPI_METHOD_ARGUMENT_BUFFER

    ACPI_METHOD_ARGUMENT_PACKAGE

DataLength为数组Data的字节大小。

关于该结构体更详细的信息,请查阅MSDN文档:ACPI_METHOD_ARGUMENT structure 


Sample Code

访问不带输入参数的ACPI Method:
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;}


访问带输入参数的ACPI Method:

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;}


关于ACPI Control Method更详细的用法,请查阅MSDN官方文档:Evaluating ACPI Control Methods Synchronously



0 0