当前位置:   article > 正文

【RK3588】Android系统触屏唤醒功能的实现_android 唤醒屏幕

android 唤醒屏幕

介绍一下Android系统中如何实现触屏唤醒设备的功能,也就是说Android设备在息屏状态下、通过触摸屏幕来唤醒系统、点亮屏幕。之前有客户需要这种功能,这里简单记录一下!

测试平台:正点原子ATK-DLRK3588开发板

测试系统:Android12/13

1.触屏唤醒功能的实现思路

简单说一下触屏唤醒功能的实现思路:其实就是参考power按键唤醒来做,我们知道在Android系统中,亮屏状态下按下power按键会息屏;同理,息屏状态下按下power按键会唤醒屏幕(亮屏)。

当用户按下power按键时,底层驱动只是上报了一个KEY_POWER按键事件,也就是说通过KEY_POWER按键事件就可以触发息屏或唤醒屏幕的操作。

我们可以参考这种设计,在息屏状态下,触摸屏驱动如果检测到用户有触屏操作(触屏会产生中断),那么就上报一个KEY_POWER按键事件,以此来唤醒系统、点亮屏幕!

接下来看下具体如何去修改代码。主要分为以下三步:

  • 监听FB_EVENT_BLANK事件,并记录显示屏当前的状态(亮屏或息屏状态);
  • 当用户触摸屏幕时,判断当前是否为息屏状态,如果是息屏状态则上报KEY_POWER按键事件;
  • 不要让系统进入深度睡眠状态,深度睡眠状态下触屏操作无法唤醒,只能通过power按键唤醒。

2.代码修改

本文基于正点原子ATK-DLRK3588开发板搭配MIPI进行验证、测试。触摸驱动源码所在路径为:kernel-5.10/drivers/input/touchscreen/gt9xx/gt9xx.c

根据上面的分析,对代码进行修改。

2.1 修改tp_suspend.h

在触摸驱动中监听显示屏亮屏和息屏事件,并记录当前状态(当前是息屏状态、还是亮屏状态)。使用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函数中原有代码删除,并替换成如下代码:

  1. static inline int fb_notifier_callback(struct notifier_block *self,
  2. unsigned long action, void *data)
  3. {
  4. struct tp_device *tp;
  5. struct fb_event *event = data;
  6. tp = container_of(self, struct tp_device, fb_notif);
  7. //判断此事件是否为FB_EVENT_BLANK事件
  8. if (action != FB_EVENT_BLANK)
  9. return NOTIFY_DONE;
  10. //将当前状态保存至status变量中
  11. atomic_set(&tp->status, *((int *)event->data));
  12. //将power_flag标志位重置为0
  13. atomic_set(&tp->power_flag, 0);
  14. return NOTIFY_OK;
  15. }

status和power_flag均为atomic类型变量,用于实现原子操作。power_flag变量用于标识触摸驱动中是否已经上报了KEY_POWER按键事件,避免重复上报。

在tp_suspend.h文件中找到struct tp_device结构体的定义,将status和power_flag变量添加进去,如下所示:

  1. struct tp_device{
  2. struct notifier_block fb_notif;
  3. struct notifier_block ebc_notif;
  4. int(*tp_suspend)(struct tp_device*);
  5. int(*tp_resume)(struct tp_device*);
  6. struct mutex ops_lock;
  7. atomic_t status;//此变量原本就存在,只需修改其类型为atomic_t即可!
  8. atomic_t power_flag;
  9. };

在tp_suspend.h文件中找到tp_register_fb函数,加入对status和power_flag变量的初始化代码,如下所示:

  1. //删除掉 tp->status = FB_BLANK_UNBLANK; 添加下面两行
  2. atomic_set(&tp->status, FB_BLANK_UNBLANK);
  3. atomic_set(&tp->power_flag, 0);

然后再找到ebc_notifier_callback函数,将其代码全部删除,如下所示:

以上修改完成后保存退出!

2.2 修改gt9xx.c

打开drivers/input/touchscreen/gt9xx/gt9xx.c文件:

vi drivers/input/touchscreen/gt9xx/gt9xx.c

找到goodix_ts_irq_handler函数,此函数为触摸中断服务函数,当用户触屏时会调用该函数。在goodix_ts_irq_handler函数中添加如下代码:

  1. //如果显示屏当前为息屏状态,则执行如下代码
  2. if (atomic_read(&ts->tp.status) != FB_BLANK_UNBLANK) {
  3. //如果power_flag标志为0,则执行如下代码
  4. if (atomic_read(&ts->tp.power_flag) == 0) {
  5. //上报KEY_POWER按键按下事件
  6. input_report_key(ts->input_dev, KEY_POWER, 1);
  7. input_sync(ts->input_dev); //同步
  8. //上报KEY_POWER按键松开事件
  9. input_report_key(ts->input_dev, KEY_POWER, 0);
  10. input_sync(ts->input_dev); //同步
  11. //将power_flag设置为1,表示已经上报了KEY_POWER按键事件,避免重复上报
  12. atomic_set(&ts->tp.power_flag, 1);
  13. }
  14. }

这段代码会判断当前是否为息屏状态,如果是息屏状态并且power_flag标志为0,则上报KEY_POWER按键事件,上报完成后将power_flag标志置为1,避免重复上报。

找到gtp_request_input_dev函数,并找到该函数中的如下3行代码:

  1. #if GTP_GESTURE_WAKEUP
  2. input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
  3. #endif

GTP_GESTURE_WAKEUP这个宏默认没定义,我们需要将这一对条件编译指令注释掉使能对input_set_capability函数的调用,如下所示:

调用input_set_capability函数设置触摸屏设备支持上报KEY_POWER按键事件的能力。

以上修改完成后保存退出!

2.3 修改suspend.c

打开kernel/power/suspend.c文件:

vi kernel/power/suspend.c

找到pm_suspend函数,添加如下代码:

  1. if (state > PM_SUSPEND_TO_IDLE)
  2. state = PM_SUSPEND_TO_IDLE;

不要让系统进入深度睡眠状态,深度睡眠状态下触屏操作无法唤醒,只能通过power按键唤醒。

修改完成后保存退出!

3.编译测试

在Android SDK根目录下执行如下命令重新编译Linux内核源码:

source build/envsetup.sh

lunch ATK_DLRK3588-userdebug

./build.sh -KA -J10

将编译生成的boot.img烧录到开发板上进行测试。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/888965
推荐阅读
相关标签
  

闽ICP备14008679号