赞
踩
介绍一下Android系统中如何实现触屏唤醒设备的功能,也就是说Android设备在息屏状态下、通过触摸屏幕来唤醒系统、点亮屏幕。之前有客户需要这种功能,这里简单记录一下!
测试平台:正点原子ATK-DLRK3588开发板
测试系统:Android12/13
简单说一下触屏唤醒功能的实现思路:其实就是参考power按键唤醒来做,我们知道在Android系统中,亮屏状态下按下power按键会息屏;同理,息屏状态下按下power按键会唤醒屏幕(亮屏)。
当用户按下power按键时,底层驱动只是上报了一个KEY_POWER按键事件,也就是说通过KEY_POWER按键事件就可以触发息屏或唤醒屏幕的操作。
我们可以参考这种设计,在息屏状态下,触摸屏驱动如果检测到用户有触屏操作(触屏会产生中断),那么就上报一个KEY_POWER按键事件,以此来唤醒系统、点亮屏幕!
接下来看下具体如何去修改代码。主要分为以下三步:
本文基于正点原子ATK-DLRK3588开发板搭配MIPI屏进行验证、测试。触摸驱动源码所在路径为:kernel-5.10/drivers/input/touchscreen/gt9xx/gt9xx.c。
根据上面的分析,对代码进行修改。
在触摸驱动中监听显示屏亮屏和息屏事件,并记录当前状态(当前是息屏状态、还是亮屏状态)。使用Linux内核的notifier(事件通知链)机制可以实现对亮屏/息屏事件的监听。notifier是Linux内核的一种异步通信机制,用于在内核各个模块、子系统之间进行事件通知;因为内核中一些模块对其它模块产生的事件(状态发生改变)很感兴趣,它需要时刻关注该模块产生的事件并做出相应的处理。
notifier的运行机制包括两个角色:
具体如何使用notifier,本文不做过多介绍,请读者自行百度,网上一大堆文章!
进入Linux内核源码目录,打开drivers/input/touchscreen/tp_suspend.h文件:
vi drivers/input/touchscreen/tp_suspend.h
tp_suspend.h头文件会被gt9xx.c包含。
Linux内核中,当显示设备发生息屏或亮屏这种状态变化时,会产生FB_EVENT_BLANK事件,然后它会通知所有对FB_EVENT_BLANK事件感兴趣的模块。所以我们需要在触摸驱动中注册对FB_EVENT_BLANK事件的回调函数,这部分代码gt9xx触摸驱动中已经实现了,不需要自己去写,我们只需修改此回调函数的内容,在回调函数中只需记录当前状态即可!
打开tp_suspend.h头文件后,找到fb_notifier_callback函数,此函数便是对FB_EVENT_BLANK事件的回调函数,将fb_notifier_callback函数中原有代码删除,并替换成如下代码:
- static inline int fb_notifier_callback(struct notifier_block *self,
- unsigned long action, void *data)
- {
- struct tp_device *tp;
- struct fb_event *event = data;
-
- tp = container_of(self, struct tp_device, fb_notif);
-
- //判断此事件是否为FB_EVENT_BLANK事件
- if (action != FB_EVENT_BLANK)
- return NOTIFY_DONE;
-
- //将当前状态保存至status变量中
- atomic_set(&tp->status, *((int *)event->data));
- //将power_flag标志位重置为0
- atomic_set(&tp->power_flag, 0);
-
- return NOTIFY_OK;
- }
status和power_flag均为atomic类型变量,用于实现原子操作。power_flag变量用于标识触摸驱动中是否已经上报了KEY_POWER按键事件,避免重复上报。
在tp_suspend.h文件中找到struct tp_device结构体的定义,将status和power_flag变量添加进去,如下所示:
- struct tp_device{
- struct notifier_block fb_notif;
- struct notifier_block ebc_notif;
- int(*tp_suspend)(struct tp_device*);
- int(*tp_resume)(struct tp_device*);
- struct mutex ops_lock;
- atomic_t status;//此变量原本就存在,只需修改其类型为atomic_t即可!
- atomic_t power_flag;
- };
在tp_suspend.h文件中找到tp_register_fb函数,加入对status和power_flag变量的初始化代码,如下所示:
- //删除掉 tp->status = FB_BLANK_UNBLANK; 添加下面两行
- atomic_set(&tp->status, FB_BLANK_UNBLANK);
- atomic_set(&tp->power_flag, 0);
然后再找到ebc_notifier_callback函数,将其代码全部删除,如下所示:
以上修改完成后保存退出!
打开drivers/input/touchscreen/gt9xx/gt9xx.c文件:
vi drivers/input/touchscreen/gt9xx/gt9xx.c
找到goodix_ts_irq_handler函数,此函数为触摸中断服务函数,当用户触屏时会调用该函数。在goodix_ts_irq_handler函数中添加如下代码:
- //如果显示屏当前为息屏状态,则执行如下代码
- if (atomic_read(&ts->tp.status) != FB_BLANK_UNBLANK) {
-
- //如果power_flag标志为0,则执行如下代码
- if (atomic_read(&ts->tp.power_flag) == 0) {
- //上报KEY_POWER按键按下事件
- input_report_key(ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev); //同步
-
- //上报KEY_POWER按键松开事件
- input_report_key(ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev); //同步
-
- //将power_flag设置为1,表示已经上报了KEY_POWER按键事件,避免重复上报
- atomic_set(&ts->tp.power_flag, 1);
- }
- }
这段代码会判断当前是否为息屏状态,如果是息屏状态并且power_flag标志为0,则上报KEY_POWER按键事件,上报完成后将power_flag标志置为1,避免重复上报。
找到gtp_request_input_dev函数,并找到该函数中的如下3行代码:
- #if GTP_GESTURE_WAKEUP
- input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
- #endif
GTP_GESTURE_WAKEUP这个宏默认没定义,我们需要将这一对条件编译指令注释掉使能对input_set_capability函数的调用,如下所示:
调用input_set_capability函数设置触摸屏设备支持上报KEY_POWER按键事件的能力。
以上修改完成后保存退出!
打开kernel/power/suspend.c文件:
vi kernel/power/suspend.c
找到pm_suspend函数,添加如下代码:
- if (state > PM_SUSPEND_TO_IDLE)
- state = PM_SUSPEND_TO_IDLE;
不要让系统进入深度睡眠状态,深度睡眠状态下触屏操作无法唤醒,只能通过power按键唤醒。
修改完成后保存退出!
在Android SDK根目录下执行如下命令重新编译Linux内核源码:
source build/envsetup.sh
lunch ATK_DLRK3588-userdebug
./build.sh -KA -J10
将编译生成的boot.img烧录到开发板上进行测试。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。