【RK3588】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函数中原有代码删除,并替换成如下代码:

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函数,将其代码全部删除,如下所示:

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

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函数中添加如下代码:

    //如果显示屏当前为息屏状态,则执行如下代码
    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按键事件的能力。

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

2.3 修改suspend.c

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

vi kernel/power/suspend.c

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

	if (state > PM_SUSPEND_TO_IDLE)
		state = PM_SUSPEND_TO_IDLE;

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

修改完成后保存退出!

3.编译测试

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

source build/envsetup.sh

lunch ATK_DLRK3588-userdebug

./build.sh -KA -J10

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

  • 30
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值