ACPI相关(9)- Generic Button Device

下文介绍了ACPI规范对通用按钮设备的支持情况。

1、概述

通用按钮设备是一种标准设备,用于通过硬件中断报告按钮事件,并将这些中断映射到人机接口设备(HID)规范中定义的特定usage。这些设备包括:音量控制,摄像头控制,背光控制,wifi控制。为了向OS表示按钮的功能,需要两条信息:HID控件的Usage和控件所属的HID集合的Us/age。这类设备的HID值为:ACPI0011。

Usage是HID Report Descriptor的一部分,可用来表明一个特殊的控制,或一组控制。每个Usage包含一个usage ID, usage name, 和一个详细的描述。Usage由16bit的Usage page和16bit的Usage ID组成。例如,“音量调高”按钮在使用者控件集合(“Usage page 为0x0C,Usage ID为 0x01”)中被标识为“音量调高使用量”(Usage page 为0x0C,Usage ID为 0xE9)。

下表通用按键设备控制器方法

名称

描述

_CRS

仅中断资源(GpioInt()和Interrupt())对此设备有效。列出的每个中断都必须发出一个不同的按钮事件信号。

_DSD

提供了HID按钮设备的描述符,使用UUID FA6BD625-9CE8-470D-A2C7-B3CA36C4282E.

 

2、中断

通用按钮设备的中断要求沿边沿触发而不是电平触发,因为在接收到中断后,没有为驱动程序定义接口来使驱动程序停顿中断线。 中断的极性(ActiveLow / High与ActiveBoth)由与中断关联的HIDusage的usage类型确定,下表中所述

表设备极性说明

usage类型

中断极性

说明

OSC - One Shot Control

ActiveHigh/

ActiveLow

按下按键产生中断事件

示例:静音按钮

MC - Momentary

Control

ActiveBoth

按下和释放按钮均触发一个中断。

示例:鼠标左键。

RTC - Re-trigger

Control

ActiveBoth

按下和释放按钮均应触发一个中断。在按下按钮时,操作系统将反复重新执行按下按钮时将执行的操作。示例:按住音量调高按钮时,将反复增加音量。

OOC - On/Off

Control

ActiveHigh/

ActiveLow

OR

ActiveBoth

可以通过以下任何一种方式来实现开/关控制:

  1. 两个按钮,开和关。
  2. 单个按钮,每次按下时切换开/关状态。
  3. 拨动开关可机械地保持On / Off状态。

 

尽管原则上可以使用_DSM(特定于设备的方法)来实现_DSD提供的功能,但不建议这样做。由于_DSD更适合提供设备配置数据,因此应在适用的情况下将其用于此目的。_DSD每次评估时都必须返回相同的数据,因此,如果不能保证,则必须使用_DSM代替它。注意:_DSD除了返回数据外,不应写入设备寄存器。

3、按钮usage和集合

HID usage表包含各种按钮的标准化usage的详尽列表。 下中列出了在计算设备上找到的一些常用按钮及其usage。有关完整列表,请参阅“HID Usage Tables”。

按钮被分组在HID集合下。 操作系统通常会理解几个HID集合,例如键盘集合,用户控件集合,无线无线电控件集合等。

Button

Usage Page / Usage

Usage Type

Interrupt

Polarity

Power

Generic Desktop Page (0x01)

System Power Down (0x01)

OSC

ActiveBoth

Volume Up

Consumer Page (0x0C)

Volume Increment (0xE9)

RTC

ActiveBoth

Volume Down

Consumer Page (0x0C)

Volume Decrement (0xEA)

RTC

ActiveBoth

Camera Shutter

Camera Control Page (0x90)

Camera Shutter (0x21)

OSC

Active High/

ActiveLow

Display Brightness

Up

Consumer Page (0x0C) Display Brightness Increment (0x6F)

RTC

ActiveBoth

Display Brightness

Down

Consumer Page (0x0C)

Display Brightness Decrement (0x6F)

RTC

ActiveBoth

Wireless Radio

Button

Generic Desktop Page (0x01)

Wireless Radio Button (0xC6)

OOC

ActiveHigh/

ActiveLow

Wireless Radio Slider

Switch

Generic Desktop Page (0x01)

Wireless Radio Slider Switch (0xC8)

OOC

ActiveBoth

流程及实现

  1. 固件中的实现

在UEFI DSDT中添加下面对象:

Device (BTNS)

{

    Name (_HID, "ACPI0011")

    Name (_CRS, ResourceTemplate() {

      GpioInt(Edge, ActiveBoth, ExclusiveAndWake, PullUp, , "\\_SB.GPO0")                                                                                                      

    })

    Name (_DSD, Package(2) {

      ToUUID ("FA6BD625-9CE8-470D-A2C7-B3CA36C4282E"),

      Package() {

        Package(5) {

          0,

  1,

          0,

          0x0c,

          0x01

        },

        Package(5) {

          1,

          0,

          1,

          0x01,

          0x81

        },

      }

    })

  }

HID控件的Usage和控件所属的HID集合的Us/age。这类设备的HID值为:ACPI0011。内核驱动soc_button_array.c通过识别此HID来加载相应驱动。

GpioInt宏申明了此GPIO中断管教信息。每个中断引脚都配置为在两个边沿都中断的非共享(独占),边沿触发(边沿)中断资源(ActiveBoth)。

\\_SB.GPO0查找名称空间中GPIO控制器对象,解析相关信息。

UUID:FA6BD625-9CE8-470D-A2C7-B3CA36C4282E唯一表示了_DSD对象作为申明Generic Buttons Device设备使用。

Package对象中包含了按钮相关信息,通过解析这些package对象来确定具体按钮。

5. 内核中的流程

5.1设备初始化流程

在drivers/input/misc/soc_button_array.c文件soc_button_probe函数中,通过调用soc_button_get_button_info函数进行generic按钮设备对象的初始化。

soc_button_get_button_info评估_DSD对象,获取关于GPIO按钮及中断信息。

最后调用soc_button_device_create接口将设备注册到内核中。

5.2设备驱动初始化

在drivers/input/keyboard/gpio_keys.c文件gpio_keys_probe函数中,获取设备初始化信息,调用gpio_keys_setup_key函数配置对应GPIO管脚中断,并注册相应中断处理函数。

调用input_register_device函数将设备注册到input子系统。

如按钮设备支持唤醒系统,则调用device_init_wakeup函数将设备作为唤醒源注册到系统中。

5.3中断触发

在gpio_keys_setup_key()函数中,先使用gpio_is_valid来测试端口是否合法,然后使用gpio_request_one进行GPIO的申请,同时将引脚配置成输入,通过irq =gpio_to_irq(button_irq)将引脚设为外部中断,同时获得的中断号赋值给bdata_irq,然后设置外部中断服务函数isr = gpio_keys_gpio_isr以及配置中断处理标志irqflag为上升沿触发和下降沿触发,。最后通过 error =request_any_context_irq(bdata->irq, isr, irqflags,desc, bdata)来完成中断服务的注册。
在对input进行配置时,由input->open =gpio_keys_open;
input->close=gpio_keys_close可知通过gpio_keys_open/gpio_keys_close
函数可以对GPIO端口进行打开和关闭,对GPIO端口进行控制。
该程序中具体的中断流程如下:
(1) 首先完成中断的配置以及注册
(2)按键按下时,触发外部中断,调用中断服务程序gpio_keys_gpio_isr,使用定时器进行消抖,然后调用工作队列中的gpio_keys_gpio_work_func()函数
(3)通过gpio_keys_gpio_report_events()函数中的gpio_get_value_cansleep(button_gpio)函数来对按键进行扫描,获得按键值,使用input_event传递事件信息,最后使用input_sync()完成事件的同步。
(4)最后使用intgpio_keys_remove()中完成卸载,该函数主要是删除定时器,取消工作队列的工作,释放申请的引脚, 通过input_unregister_device(input)注销输入设备, 最后通过kfree(ddata)释放之前申请的数据内存空间。

6、调试问题

调通从DSDT中添加相关上述对象解析,以及后续gpio-key驱动使用,到上报带input核心整个过程遇到的问题:
1、[ 3.105468] No GPIO consumer (null) found, desc: ffffffea
在解析GpioInt(Edge, ActiveBoth, ExclusiveAndWake, PullUp, , "\\_SB.GPO0") 时,获取到_SB.GPO0对象,解析GPIO信息时出错。
2、[ 6.671875] gpio-keys gpio-keys.0.auto: Unable to claim irq 87; error -22
   [ 6.679687] gpio-keys: probe of gpio-keys.0.auto failed with error -22
目前龙芯GPIO驱动不支持IRQ_TYPE_EDGE_BOTH类型中断出发方式。添加对应代码解决。
3、[ 6.792968] gpio-keys gpio-keys.0.auto: Unable to get irq number for GPIO 19, error -6
目前龙芯GPIO驱动没有实现chip.to_irq函数。添加对应代码解决。
4、上述解析完成后,将GPIO03管脚引出,手动触发中断,无中断相应。
添加irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);设置中断出发方式,产生相应中断。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值