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

今天给大家讲解一下,在KMDF(Kernel-Mode Driver Framework)中是如何调用ACPI配置表中用户定义的Method。在ACPI中,凡是以下划线开头的Method(如_STA)都系统预定义的Method,它们都由Windows OS自己调用,其他用户自定义Method则由驱动程序调用。

ACPI Method

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

//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)
    }

	...
}

从代码中可以看到,该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

时间: 2024-12-18 19:42:39

Windows Phone 8.1 驱动开发——如何调用ACPI Method的相关文章

Windows内核安全与驱动开发

这篇是计算机中Windows Mobile/Symbian类的优质预售推荐<Windows内核安全与驱动开发>. 编辑推荐 本书适合计算机安全软件从业人员.计算机相关专业院校学生以及有一定C语言和操作系统基础知识的编程爱好者阅读. 内容简介 本书的前身是<天书夜读--从汇编语言到Windows内核编程>和<寒江独钓--Windows内核安全编程>.与Windows客户端安全软件开发相关的驱动程序开发是本书的主题.书中的程序使用环境从32位到64位,从Windows XP

Windows Phone 8.1 驱动开发——注册表read/write

在做Windows Phone驱动开发时,时常需要和注册表打交道,因此,作为手机驱动开发人员,有必要了解一下注册表相关的知识.本人目前对注册表也不怎么了解,也只是大概的知道在Windows Phone下,驱动的inf文件并不像桌面Windows那样提供驱动自动安装程序,在Windows Phone下,inf文件最终会被解析成注册表信息并添加到注册表中.我们驱动往往将一些硬件参数保存在注册表中,因此在软件编程时,自然就会涉及到注册表的读写更新操作. 本人目前在做触摸屏驱动时,就涉及到了注册表的读写

Windows Phone 8.1 驱动开发——SPB 简介

SPB是Simple Peripheral Bus的简称,直译过来就是简单外设总线,它包括I2C总线.SPI总线.SPB是在Windows 8以后才被驱动支持的,而在之前如果系统想访问I2C外围设备,则只能通过BIOS程序间接的访问,没法直接访问外设寄存器.在系统启动时,ACPI固件会根据配置表扫描SPB设备,并将它们的资源信息传递给PnP(即插即用设备)管理器,这些资源就包括I2C从设备地址.I2C总线时钟频率以及该设备的中断号.需要注意的一点,在ACPI资源配置表中,是不允许使用Memory

Windows驱动开发(中间层)

Windows驱动开发 一.前言 依据<Windows内核安全与驱动开发>及MSDN等网络质料进行学习开发. 二.初步环境 1.下载安装WDK7.1.0(WinDDK\7600.16385.1) 地址:https://msdn.microsoft.com/en-us/windows/hardware/hh852365 2.下载InstDrv软件(用于安装.启动.停止.卸载驱动) 界面如下: 注:srvinstw.exe 也可以安装.卸载sys文件,但需要手动开启.关闭,即在cmd命令窗口下执行

【转】Windows驱动开发如何入门

1.http://blog.csdn.net/charlessimonyi/article/details/50904854 (2016年03月16日 14:55:36) 2. 搞Windows驱动开发是一件痛苦的事情,特别是初学Windows驱动开发.有的人觉得Windows驱动开发就是把开发包WDK下载下来,然后只要掌握了C/C++语言,接下来无非就是类库调来调去,像调用MFC.QT之类的库那样,看着书和MSDN上的文档来就行了.等真正接触以后才发现根本不是那么一回事,痛苦源于以下几点: 痛

Windows 驱动开发 - 基础1

原来的驱动开发都是WDM(Windows Driver Model)的,那时微软推出DDK(Driver Developer Kit)工具. 现在微软进行了升级由WDF(Windows Driver Foundation)来替代WDM,同时推出WDK(Windows Driver Kit)工具. 安装WDK要求的最低系统为Win XP SP3以上. 推荐使用的IDE:VS2010 一.WDM与WDF的区别 (1) 前者使用面向过程,后者可使用面向对象. (2) 前者可开发总线筛选驱动程序; 后者

Windows驱动开发基础(八)内存管理

Windows驱动开发基础系列,转载请标明出处:http://blog.csdn.net/ikerpeng/article/details/38826159 就32位的计算机来说,他有4G的真实的物理内存.但是这样是不够的,于是引入了虚拟内存的概念.使得每一个进程都有4G的虚拟内存. 虚拟内存实际上就是采用了一种映射的方式.4G的内存实际上被分页.一般来说一个页的大小是4K.也是说它被分为了1M个页.在这么多的页里面,有一部分是对应于物理内存的(可以是多对一的):有一部分是对应于磁盘上的空间,但

Windows 驱动开发 - 1

上篇<Windows 驱动开发 - 基础2>已经介绍了windows大概的框架.那么使用WDF有那些的不同呢? 我们知道在WDF中,KMDF是必须的.而KMDF是架构在WDM之上的.  WDM驱动程序模型 在 WDM 驱动程序模型中,每个硬件设备至少有两个驱动程序.其中一个驱动程序我们称为功能(function)驱动程序,通常它就是你认为的那个硬件设备驱动程序.它了解使硬件工作的所有细节,负责初始化 I/O 操作,有责任处理 I/O 操作完成时所带来的中断事件,有责任为用户提供一种设备适合的控

Windows 驱动开发基础(九)内核函数

Windows 驱动开发基础系列,转载请标明出处:http://blog.csdn.net/ikerpeng/article/details/38849861 这里主要介绍3类Windows的内核函数:字符串处理函数,文件操作函数, 注册表读写函数.(这些函数都是运行时函数,所以都有Rtl字样) 1 字符串处理函数 首先驱动程序中,常用的字符串包括4种:CHAR (打印的时候注意小写%s), WCHAR(打印的时候注意大写%S), ANSI_STRING, UNICODE_STRING.后面两种