基于“xxx” Androidx平台的驱动及系统开发 之 触摸板篇

目录

  • 一、基于全志 A133 Android10平台,适配1366x768 - ilitek2511触摸
    • 1、原理图分析
    • 2、驱动移植与适配
    • 3、补丁和资源文件
  • 二、基于瑞芯微 RK3566 Android11平台,适配GT9XX触摸
    • 1、原理图分析
    • 2、补丁及资源文件
  • 三、遇到的问题与解决
    • 1、基于amlogic Android9平台,使用(V-By-One接口LCD屏,USB接口触摸板)的一体式触摸屏
    • 2、基于RK3566 Android11平台,使用(LVDS接口LCD屏,I2C接口触摸板)的分离式触摸屏
    • 3、基于GT9XX触摸IC 触摸出现 -> "点偏位" 或 "划线异常不连续"
      • ◕对该触摸驱动如何通过“CTP_CFG_GROUPx”这个配置组表更新到触摸IC寄存器内部的
      • 有些人可能是通过外部去对触摸进行矫正的,那么就需要把自动写入对应的配置信息组表功能给关了
    • 4、在屏幕熄屏情况下做触摸唤醒屏幕功能,但是内核版本原因,无法使用原厂提供的手势识别功能

一、基于全志 A133 Android10平台,适配1366x768 - ilitek2511触摸

1、原理图分析

在这里插入图片描述  ilitek2511触摸使用的时I2C通信,因此重点关注SDA(数据)、SCK(时钟)、INT(中断)、RST(复位)这四个引脚即可。

2、驱动移植与适配

  首先我们需要弄清除,触摸驱动是干嘛的,其实它只不过是通过I2C通信方式获取触摸板上触发的每个坐标点信息,通过事件方式上报,像这种通用的事件上报方式(触摸屏),上层的HAL、Framework等,原生Android或者原厂都是已经给做好了,已经只需要移植驱动层即可,一般别的层无需做修改的。
  通过触摸IC厂商提供的驱动移植资料修改设备树,如下图原厂提供的设备树和我修改好的设备树。
在这里插入图片描述
  设备树配置好后,直接将相关的驱动文件拷贝到 a\longan\kernel\linux-4.9\drivers\input\touchscreen 目录下创建的ilitek文件夹下即可,如下图所示。
在这里插入图片描述  通过以上操作,基本是已经将触摸驱动移植好了。

3、补丁和资源文件

下载链接

二、基于瑞芯微 RK3566 Android11平台,适配GT9XX触摸

1、原理图分析

在这里插入图片描述

2、补丁及资源文件

  这里就不多分析了,直接给上补丁文件。
下载链接

三、遇到的问题与解决

1、基于amlogic Android9平台,使用(V-By-One接口LCD屏,USB接口触摸板)的一体式触摸屏

出现问题1:明明获取的USB设备,但是一直处于disconnected断开,一直打印不支持该USB设备,日志如下图所示
在这里插入图片描述
解决方法1:其实这个是控制板卡上的液晶屏的参数设置不对引起的,使得它们与触摸控制器不匹配,从而使触摸屏功能无法正常工作。因此只需要更具屏幕规格书修改屏幕参数即可。

2、基于RK3566 Android11平台,使用(LVDS接口LCD屏,I2C接口触摸板)的分离式触摸屏

出现问题1:因为触摸板和LCD屏是分离的,因此有可能出现整合者将触摸板和LCD屏摆放的起始方向不一致 或者 触摸板默认竖屏,而屏幕默认横屏, 这两种原因都会导致触摸和显示UI对不上。
解决方法1:在device/rockchip/3566x/目录下的build.prop文件中添加 persist.sys.touch.orientation=90, 如我设置90就是说将触摸板旋转方向为90度,这样就可以使UI和触摸板对上了。

3、基于GT9XX触摸IC 触摸出现 -> “点偏位” 或 “划线异常不连续”

出现的问题1:在原厂提供的文档可以可知,一般每一种触摸IC都有对应的“CTP_CFG_GROUP”这个触摸配置组的,它作用就是优化矫正触摸的。
解决方法1:在drivers\input\touchscreen\gt9xxnew\gt9xx.h文件中将原厂提供的.cfg峰位文件内从内容替换对应CTP_CFG_GROUPx中的内容,如果不确定CTP_CFG_GROUPx是哪个,那可以选择最无脑的方法,将CTP_CFG_GROUP[1~n]中的内容都给替换掉即可。

◕对该触摸驱动如何通过“CTP_CFG_GROUPx”这个配置组表更新到触摸IC寄存器内部的

  找到drivers\input\touchscreen\gt9xxnew\gt9xx.c这个文件,该文件是触摸主功能的驱动文件。
  在goodix_ts_probe函数下找到如下图的函数调用:
在这里插入图片描述
  通过该函数索引到函数实现的位置,这里我把源码贴出来,已注释方式解释了。

/*******************************************************
Function:
    Initialize gtp.
Input:
    ts: goodix private data
Output:
    Executive outcomes.
        0: succeed, otherwise: failed
*******************************************************/
static s32 gtp_init_panel(struct goodix_ts_data *ts)
{
    s32 ret = -1;

#if GTP_DRIVER_SEND_CFG
    s32 i = 0;
    u8 check_sum = 0;
    u8 opr_buf[16] = {0};
    u8 sensor_id = 0;
    
	/***************************(1)*********************************/
	/* 这一部分是获取gt9xx.h文件定义的CTP_CFG_GROUPx配置信息组的信息到cfg_info_groupx[]中 */
    u8 cfg_info_group1[] = CTP_CFG_GROUP1;
    u8 cfg_info_group2[] = CTP_CFG_GROUP2;
    u8 cfg_info_group3[] = CTP_CFG_GROUP3;
    u8 cfg_info_group4[] = CTP_CFG_GROUP4;
    u8 cfg_info_group5[] = CTP_CFG_GROUP5;
    u8 cfg_info_group6[] = CTP_CFG_GROUP6;
    u8 cfg_info_group7[] = CTP_CFG_GROUP7;
	u8 cfg_info_group8[] = CTP_CFG_GROUP8;
	/***************************(1)*********************************/
	
	/***************************(2)*********************************/
	/* 这个是创建send_cfg_buf数组,将上面活动的cfg_info_groupx信息保以元素存到该数组里 */
    u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
                        cfg_info_group4, cfg_info_group5, cfg_info_group6,
						cfg_info_group7, cfg_info_group8};
	/***************************(2)*********************************/
	
	/***************************(3)*********************************/
	/* CFG_GROUP_LEN这个方法在gt9xx.h文件中有定义,原型是#define CFG_GROUP_LEN(p_cfg_grp)  (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])),它是计算数组的长度的 */
    u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
                          CFG_GROUP_LEN(cfg_info_group2),
                          CFG_GROUP_LEN(cfg_info_group3),
                          CFG_GROUP_LEN(cfg_info_group4),
                          CFG_GROUP_LEN(cfg_info_group5),
                          CFG_GROUP_LEN(cfg_info_group6),
                          CFG_GROUP_LEN(cfg_info_group7),
						  CFG_GROUP_LEN(cfg_info_group8)};
	/***************************(3)*********************************/
        dprintk(DEBUG_INIT,"Config Groups Lengths: %d, %d, %d, %d, %d, %d, %d, %d\n",
        cfg_info_len[0], cfg_info_len[1], cfg_info_len[2], cfg_info_len[3],
        cfg_info_len[4], cfg_info_len[5], cfg_info_len[6], cfg_info_len[7]);

#if GTP_COMPATIBLE_MODE
    if (CHIP_TYPE_GT9F == ts->chip_type)
    {
        ts->fw_error = 0;
    }
    else
#endif
    {
    /***************************(4)*********************************/
    /* 检测固件是否正常 */
        ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
        if (SUCCESS == ret)
        {
            if (opr_buf[0] != 0xBE)
            {
                ts->fw_error = 1;
                printk("Firmware error, no config sent!\n");
                return -1;
            }
        }
    /***************************(4)*********************************/
    }
    
	/***************************(5)*********************************/
    if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
        (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
        (!cfg_info_len[5]) && (!cfg_info_len[6]) &&
		(!cfg_info_len[7]))
    {
    	/* 如果所有配置信息组内容都为空,sensor_id值设置为0 */
        sensor_id = 0;
    }
    else
    {
    #if GTP_COMPATIBLE_MODE
        msleep(50);
    #endif
 //       ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
 		
 		/* 下面是判断配置信息的名称是对应哪个触摸IC的名称,从而再设置其对应的sensor_id值 */
		dprintk(DEBUG_INIT,"CTP name : %s\n",config_info.name);
        if (!strcmp(config_info.name,"gt9271_mb976a9")){
            = 0;
            dprintk(DEBUG_INIT,"gt9xx:sensor_id = %d\n",sensor_id);

		} else if (!strcmp(config_info.name,"gt9110_wt097")){
            sensor_id = 1;
            dprintk(DEBUG_INIT,"gt9xx:sensor_id = %d\n",sensor_id);

		} else if (!strcmp(config_info.name,"gt9271_wt097")){
            sensor_id = 2;
            dprintk(DEBUG_INIT,"gt9xx:sensor_id = %d\n",sensor_id);

		} else if (!strcmp(config_info.name,"gt9110_g200")){
            sensor_id = 3;
            dprintk(DEBUG_INIT,"gt9xx:sensor_id = %d\n",sensor_id);

		} else if (!strcmp(config_info.name,"gt9271_noah")){
            sensor_id = 4;
            dprintk(DEBUG_INIT,"gt9xx:sensor_id = %d\n",sensor_id);
		} else if (!strcmp(config_info.name,"gt9271_p2")){
            sensor_id = 5;
            dprintk(DEBUG_INIT,"gt9xx:sensor_id = %d\n",sensor_id);
		} else if (!strcmp(config_info.name, "gt911_1060")) {
			sensor_id = 6;
			dprintk(DEBUG_INIT,"gt9xx:sensor_id = %d\n",sensor_id);
		} else if (!strcmp(config_info.name, "gt911_784")) {
			sensor_id = 7;
			dprintk(DEBUG_INIT,"gt9xx:sensor_id = %d\n",sensor_id);
		} else {
            sensor_id = 0;
            dprintk(DEBUG_INIT,"gt9xx:sensor_id = %d\n",sensor_id);
		}
		ret = SUCCESS;
        if (SUCCESS == ret)
        {
            if (sensor_id >= 0x08)
            {
                printk("Invalid sensor_id(0x%02X), No Config Sent!\n", sensor_id);
                ts->pnl_init_error = 1;
                return -1;
            }
        }
        else
        {
            printk("Failed to get sensor_id, No config sent!\n");
            ts->pnl_init_error = 1;
            return -1;
        }
        dprintk(DEBUG_INIT,"Sensor_ID: %d", sensor_id);
    }
	/***************************(5)*********************************/

	/***************************(6)*********************************/
	/* 上面设置的sensor_id值就是用来选择send_cfg_buf数组对应的触配置信息组元素的,这里获取对应配置信息组表的长度 */
    ts->gtp_cfg_len = cfg_info_len[sensor_id];
    /***************************(6)*********************************/
    
    dprintk(DEBUG_INIT,"CTP_CONFIG_GROUP%d used, config length: %d\n", sensor_id + 1, ts->gtp_cfg_len);
	
	/***************************(7)*********************************/
	/* 用获取对应配置信息组表的长度与定义的配置信息组表最小长度作对比,确保配置信息组表的数据在长度上是符合的 */
    if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
    {
        printk("Config Group%d is INVALID CONFIG GROUP(Len: %d)! NO Config Sent! You need to check you header file CFG_GROUP section!\n", sensor_id+1, ts->gtp_cfg_len);
        ts->pnl_init_error = 1;
        return -1;
    }
    /***************************(7)*********************************/

#if GTP_COMPATIBLE_MODE
    if (CHIP_TYPE_GT9F == ts->chip_type)
    {
        ts->fixed_cfg = 0;
    }
    else
#endif
    {
    /***************************(8)*********************************/
    /* 获取IC寄存器对应的配置信息版本 */
        ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);

        if (ret == SUCCESS)
        {
            dprintk(DEBUG_INIT,"CFG_GROUP%d Config Version: %d, 0x%02X; IC Config Version: %d, 0x%02X\n", sensor_id+1,
                        send_cfg_buf[sensor_id][0], send_cfg_buf[sensor_id][0], opr_buf[0], opr_buf[0]);

            if (opr_buf[0] < 155)
            {
                grp_cfg_version = send_cfg_buf[sensor_id][0];       // backup group config version
                send_cfg_buf[sensor_id][0] = 0x00;
                ts->fixed_cfg = 0;	/* 如果是opr_buf[0] < 155这种条件下,那么这个配置信息组不设置为固定不变标志 */
            }
            else        // treated as fixed config, not send config
            {
                dprintk(DEBUG_INIT,"Ic fixed config with config version(%d, 0x%02X)\n", opr_buf[0], opr_buf[0]);
                ts->fixed_cfg = 1;	/* 配置信息组设置为固定不变标志 */
                gtp_get_info(ts);
                return 0;
            }
        }
        else
        {
            printk("Failed to get ic config version!No config sent!\n");
            return -1;
        }
    /***************************(8)*********************************/
    }
	
	/***************************(9)*********************************/
	/* 将send_cfg_buf[sensor_id]这个对应的配置信息组表信息拷贝到 config[GTP_ADDR_LENGTH]这个数组指定的开始位置中 */
    memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
    memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
    /***************************(9)*********************************/

#if GTP_CUSTOM_CFG
    config[RESOLUTION_LOC]     = (u8)GTP_MAX_WIDTH;
    config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
    config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
    config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);

    if (GTP_INT_TRIGGER == 0)  //RISING
    {
        config[TRIGGER_LOC] &= 0xfe;
    }
    else if (GTP_INT_TRIGGER == 1)  //FALLING
    {
        config[TRIGGER_LOC] |= 0x01;
    }
#endif  // GTP_CUSTOM_CFG

	/***************************(10)*********************************/
	/* 计算校验和,并将校验和设置到config数组中 */
    check_sum = 0;
    for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
    {
        check_sum += config[i];
    }
    config[ts->gtp_cfg_len] = (~check_sum) + 1;
    /***************************(10)*********************************/

#else // driver not send config

    ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
    ret = gtp_i2c_read(ts->client, config, ts->gtp_cfg_len + GTP_ADDR_LENGTH);
    if (ret < 0)
    {
        GTP_ERROR("Read Config Failed, Using Default Resolution & INT Trigger!");
        ts->abs_x_max = GTP_MAX_WIDTH;
        ts->abs_y_max = GTP_MAX_HEIGHT;
        ts->int_trigger_type = GTP_INT_TRIGGER;
    }

#endif // GTP_DRIVER_SEND_CFG

	/***************************(11)*********************************/
	/* 修正abs_x_max、abs_y_max、int_trigger_type的值   */
    if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0))
    {
        ts->abs_x_max = (config[RESOLUTION_LOC + 1] << 8) + config[RESOLUTION_LOC];
        ts->abs_y_max = (config[RESOLUTION_LOC + 3] << 8) + config[RESOLUTION_LOC + 2];
        ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03;
    }
	/***************************(11)*********************************/
	
#if GTP_COMPATIBLE_MODE
    if (CHIP_TYPE_GT9F == ts->chip_type)
    {
        u8 sensor_num = 0;
        u8 driver_num = 0;
        u8 have_key = 0;

        have_key = (config[GTP_REG_HAVE_KEY - GTP_REG_CONFIG_DATA + 2] & 0x01);

        if (1 == ts->is_950)
        {
            driver_num = config[GTP_REG_MATRIX_DRVNUM - GTP_REG_CONFIG_DATA + 2];
            sensor_num = config[GTP_REG_MATRIX_SENNUM - GTP_REG_CONFIG_DATA + 2];
            if (have_key)
            {
                driver_num--;
            }
            ts->bak_ref_len = (driver_num * (sensor_num - 1) + 2) * 2 * 6;
        }
        else
        {
            driver_num = (config[CFG_LOC_DRVA_NUM] & 0x1F) + (config[CFG_LOC_DRVB_NUM]&0x1F);
            if (have_key)
            {
                driver_num--;
            }
            sensor_num = (config[CFG_LOC_SENS_NUM] & 0x0F) + ((config[CFG_LOC_SENS_NUM] >> 4) & 0x0F);
            ts->bak_ref_len = (driver_num * (sensor_num - 2) + 2) * 2;
        }

        GTP_INFO("Drv * Sen: %d * %d(key: %d), X_MAX: %d, Y_MAX: %d, TRIGGER: 0x%02x",
           driver_num, sensor_num, have_key, ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type);
        return 0;
    }
    else
#endif
    {
    #if GTP_DRIVER_SEND_CFG
    /***************************(12)*********************************/
    /* 通过调用gtp_send_cfg将已经整好的config配置信息组表数据写入到触摸IC对应的寄存器中 */
        ret = gtp_send_cfg(ts->client);
        if (ret < 0)
        {
            GTP_ERROR("Send config error.");
        }
        // set config version to CTP_CFG_GROUP, for resume to send config
        config[GTP_ADDR_LENGTH] = grp_cfg_version;
        check_sum = 0;
        for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
        {
            check_sum += config[i];
        }
        config[ts->gtp_cfg_len] = (~check_sum) + 1;
    /***************************(12)*********************************/
    #endif
        GTP_INFO("X_MAX: %d, Y_MAX: %d, TRIGGER: 0x%02x", ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type);
    }

    msleep(10);
    return 0;
}

  gtp_send_cfg函数原型,如下所示:

/*******************************************************
Function:
    Send config.
Input:
    client: i2c device.
Output:
    result of i2c write operation.
        1: succeed, otherwise: failed
*********************************************************/

s32 gtp_send_cfg(struct i2c_client *client)
{
    s32 ret = 2;

#if GTP_DRIVER_SEND_CFG
    s32 retry = 0;
    struct goodix_ts_data *ts = i2c_get_clientdata(client);

    if (ts->fixed_cfg)
    {
        GTP_INFO("Ic fixed config, no config sent!");
        return 0;
    }
    else if (ts->pnl_init_error)
    {
        GTP_INFO("Error occured in init_panel, no config sent");
        return 0;
    }

    GTP_INFO("Driver send config.");
    for (retry = 0; retry < 5; retry++)
    {
        ret = gtp_i2c_write(client, config , GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
        if (ret > 0)
        {
            break;
        }
    }
#endif
    return ret;
}

有些人可能是通过外部去对触摸进行矫正的,那么就需要把自动写入对应的配置信息组表功能给关了

  在gt9xx.h文件中将#define GTP_DRIVER_SEND_CFG 1设置成0即可。

4、在屏幕熄屏情况下做触摸唤醒屏幕功能,但是内核版本原因,无法使用原厂提供的手势识别功能

出现问题1:由于我使用的内核版本与移植的触摸驱动使用的内核版本相差较大,导致无法使用原厂提供的手势识别功能。
须知:一般来说,触摸芯片厂商提供的触摸驱动内部有自带手势识别处理程序,也就是说一般是带有触摸唤醒的功能的。但是,一般默认是不使能的,也就是需要通过宏定义取打开的,我这里以Goodix Touchscreen驱动举例:

static void goodix_ts_work_func(struct work_struct *work)

  这个函数就是处理手势识别的处理工作函数,那么这个就需要先启用“GTP_GESTURE_WAKEUP”这个宏定义才能开启手势功能的程序,而手势功能的程序需要启用“CONFIG_HAS_EARLYSUSPEND”这个挂起功能宏定义,才能让手势功能正常使用,但遗憾的是开启“CONFIG_HAS_EARLYSUSPEND”这个挂机功能的宏定义,有几个使用的内核接口函数都不存在,也就说明该驱动程序的手势功能在我这个Linux内核版本不支持。
解决方法1:我的Linux内核版本不支持,因此只能自己手动获取屏幕熄屏和亮屏状态,然后在上报触摸事件是上报“KEY_POWER”事件来开启屏幕。所以我需要先获取屏幕是开启还是休眠状态,通过这个状态去控制是否上报“KEY_POWER”事件来开启屏幕,从而避免在开屏状态下上报了“KEY_POWER”事件导致关屏发生。
  这里我将我修改的补丁贴出,如下所示:

commit cdc3304684b7d6ef469a2e8ef401e5882ef07748
Author: dengjiawen <1411471554@qq.com>
Date:   Fri Oct 20 14:32:46 2023 +0800

    屏幕息屏或者睡眠模式下,可触摸唤醒屏幕(基于gt9xx触摸系列添加该功能)

diff --git a/longan/kernel/linux-4.9/drivers/input/touchscreen/gt9xxnew/gt9xx.c b/longan/kernel/linux-4.9/drivers/input/touchscreen/gt9xxnew/gt9xx.c
index 77dc9bc566..af1bc4be38 100644
--- a/longan/kernel/linux-4.9/drivers/input/touchscreen/gt9xxnew/gt9xx.c
+++ b/longan/kernel/linux-4.9/drivers/input/touchscreen/gt9xxnew/gt9xx.c
@@ -50,7 +50,9 @@
 #include <linux/irq.h>
 #include "gt9xx.h"
 #include <linux/pm_runtime.h>
+#include "../../../video/fbdev/sunxi/disp2/disp/dev_disp.h"
 
+extern int get_screen_status(void);     /* 声明引入获取屏幕状态函数 */
 #ifdef CONFIG_PM
 #include <linux/pm.h>
 #endif
@@ -664,6 +666,22 @@ static void gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w)
     input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
     input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
     input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
+
+/************************* 获取屏幕状态,上报KEY_POWER事件来打开屏幕 *********************************/
+    printk("get_screen_status = %d\n",get_screen_status());
+    if(get_screen_status()) {
+        /* 亮屏状态,不发出KEY_POWER事件唤醒屏幕 */
+        printk("screen is open\n");
+    } else {
+        /* 熄屏状态,发出KEY_POWER事件唤醒屏幕 */
+        input_event(ts->input_dev,EV_KEY,KEY_POWER,1);
+        input_sync(ts->input_dev);
+        input_event(ts->input_dev,EV_KEY,KEY_POWER,0);
+        input_sync(ts->input_dev);
+        printk("screen is close,in open the screen......\n");
+    }
+/*****************************************************************************************************/
+
     input_mt_sync(ts->input_dev);
 #endif
 
@@ -2150,7 +2168,7 @@ static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
 #if GTP_ICS_SLOT_REPORT
     input_mt_init_slots(ts->input_dev, 16);     // in case of "out of memory"
 #else
-    ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+    ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) | BIT_MASK(EV_KEY);    /* 增加外部按键事件掩码,用于KEY_POWER事件 */
 #endif
     __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
 
@@ -2169,7 +2187,7 @@ if(gtp_gesture_wakeup)
        input_set_capability(ts->input_dev, EV_KEY, ctp_key_list[index]);
     }
 //#endif
-
+    input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);     /* 将按键功能 KEY_POWER 添加到输入设备中的按键功能列表中。这意味着输入设备可以检测到并报告关于电源键的按下和释放事件 */
 if(1 == exchange_x_y_flag)
     swap(ts->abs_x_max, ts->abs_y_max);
 
diff --git a/longan/kernel/linux-4.9/drivers/video/fbdev/sunxi/disp2/disp/dev_disp.c b/longan/kernel/linux-4.9/drivers/video/fbdev/sunxi/disp2/disp/dev_disp.c
index 16c45a6529..8c3006fd25 100644
--- a/longan/kernel/linux-4.9/drivers/video/fbdev/sunxi/disp2/disp/dev_disp.c
+++ b/longan/kernel/linux-4.9/drivers/video/fbdev/sunxi/disp2/disp/dev_disp.c
@@ -97,6 +97,8 @@ int composer_init(struct disp_drv_info *p_disp_drv);
 int hwc_dump(char *buf);
 #endif
 
+static int screen_status = 0;	/* 定义一个静态的屏幕状态变量 */
+
 static void disp_shutdown(struct platform_device *pdev);
 static ssize_t disp_sys_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
@@ -3009,6 +3011,7 @@ static int disp_runtime_suspend(struct device *dev)
 		if (ret < 0) {
 			dev_err(dev, "can't request output direction lcd_pwr_gpio gpio \n");
 		}
+		screen_status = 0;
 	}
 	pr_info("%s finish\n", __func__);
 
@@ -3077,6 +3080,7 @@ static int disp_runtime_resume(struct device *dev)
 		if (ret < 0) {
 			dev_err(dev, "can't request output direction lcd_pwr_gpio gpio \n");
 		}
+		screen_status = 1;
 	}
 	pr_info("%s finish\n", __func__);
 
@@ -3111,6 +3115,14 @@ static int disp_runtime_idle(struct device *dev)
 }
 #endif
 
+/* 实现获取屏幕状态的函数,并导出共享 */
+int get_screen_status(void)
+{
+	return screen_status;
+}
+EXPORT_SYMBOL(get_screen_status);
+/***********************************/
+
 int disp_suspend(struct device *dev)
 {
 	u32 screen_id = 0;

解决方法2:修改原厂驱动源码,使其手势功能程序兼容本地使用的内核版本。
  在gt9xx.c文件中找到static void goodix_ts_work_func(struct work_struct *work)这个函数,这个函数就是处理事件上报功能的,如下图是我截取的原厂驱动双击屏幕开屏的程序段。
在这里插入图片描述
  这图程序可以看出,它是通过读取记录触摸手势状态的寄存器值来判断触发双击开屏功能的,如果触发了那么就会上报"KEY_POWER"事件来达到开屏目的,而它的屏幕状态通过doze_status这个静态变量取设置与判断的,最后会清除记录触摸手势状态的寄存器的值。
  至于具体修改方法就自行取尝试啦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/432155.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Pytorch学习07_torchvision中数据集的使用

torchvision torchvision 是 PyTorch 生态系统中的一个用于计算机视觉任务的包&#xff0c;它提供了一系列用于图像和视频处理的工具和数据集。torchvision 可以帮助你加载、预处理、增强和可视化图像数据&#xff0c;并提供了一些经典的计算机视觉模型和预训练权重&#xff0…

计算机网络——24路由器组成

路由器组成 路由器的结构概况 高层面(非常简化的)通用路由器体系架构 路由&#xff1a;运行路由选择算法&#xff0f;协议 (RIP, OSPF, BGP) - 生成 路由表转发&#xff1a;从输入到输出链路交换数据报 - 根据路由表进行分组的转发 输入端口功能 分布式交换&#xff1a; 根…

SkyWalking链路追踪上下文TraceContext的traceId生成的实现原理剖析

结论先行 【结论】 SkyWalking通过字节码增强技术实现&#xff0c;结合依赖注入和控制反转思想&#xff0c;以SkyWalking方式将追踪身份traceId编织到链路追踪上下文TraceContext中。 是不是很有趣&#xff0c;很有意思&#xff01;&#xff01;&#xff01; 【收获】 skywal…

什么是jwt

jwt是JSON Web Token&#xff0c;由3部分构成&#xff1a; 头部Header&#xff1a;头部包含了两部分&#xff0c;token 类型和采用的加密算法&#xff08;可为none&#xff0c;后端应限制加密算法&#xff0c;不以这里为准&#xff09;。 载荷Payload&#xff1a;这部分才是重要…

Linux网络隧道协议IPIP认知(基于Linux network namespace 的 IPIP 隧道通信)

写在前面 博文内容为 Linux 隧道通信 IPIP认知内容涉及&#xff1a;ipip 介绍&#xff0c;一个 ipip 通信 Demo 以及数据帧流转分析理解不足小伙伴帮忙指正 某些人和事&#xff0c;哪怕没有缘分&#xff0c;是路边的风景&#xff0c;可是只要看一眼&#xff0c;依然会让人觉得…

空间直角坐标系、大地坐标系、平面坐标系介绍

空间直角坐标系、大地坐标系、平面坐标系 2017-04-11 13:53 ( 一)空间直角坐标系 空间直角坐标系的坐标原点位于参考椭球的中心,Z轴指向参考椭球的北极,X轴指向起始子午面与赤道的交点,Y轴位于赤道面上切按右手系于X轴呈90度夹角,某点中的坐标可用该点在此坐标系的各…

九型人格测试,3号成就型人格的职业分析

成就型人格&#xff08;也叫3号人格&#xff09;&#xff0c;在九型人格中&#xff0c;是一种喜欢争强好胜的人格&#xff08;这跟和平型人格具有强烈的对比性&#xff09;。这种人格的人&#xff0c;对于一切给自己带来成就感的事情会表现得非常上心&#xff0c;不会有丝毫地疏…

【鸿蒙 HarmonyOS 4.0】多设备响应式布局

一、背景 在渲染页面时&#xff0c;需要根据不同屏幕大小渲染出不同的效果&#xff0c;动态的判断设备屏幕大小&#xff0c;便需要采用多设备响应式布局。这种设计方法能够动态适配各种屏幕大小&#xff0c;确保网站在不同设备上都能呈现出最佳的效果。 二、媒体查询&#xf…

EMO在哪体验?阿里对口型视频生成工具EMO下载地址?阿里巴巴新模型EMO的技术原理

这几天&#xff0c;阿里的对口型视频生成工具EMO火了。根据官方宣传&#xff0c;EMO只需要上传一张图片和一段音频就可以一键生成对口型视频&#xff0c;而且视频中的嘴型还可以与声音匹配。这项技术支持多语言、对话、唱歌以及快速语速的适配&#xff0c;但也可能成为制造虚假…

[两个栈实现队列]

[两个栈实现队列] 一、题目二、思路三、代码 一、题目 二、思路 //思路:两个栈实现队列&#xff0c;栈是先入后出&#xff0c;队列是队尾入&#xff0c;对头出&#xff0c;&#xff08;先入先出&#xff09;&#xff0c;那么可以这样干&#xff0c;假设一个栈Pushst&#xff0c…

C++ Python网易云音乐播放器

程序示例精选 网易云音乐播放器 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《网易云音乐播放器》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读。 学习与应用推荐首选。…

Javaweb之SpringBootWeb案例之自动配置案例的自定义starter实现的详细解析

3.2.4.2 自定义starter实现 自定义starter的步骤我们刚才已经分析了&#xff0c;接下来我们就按照分析的步骤来完成自定义starter的开发。 首先我们先来创建两个Maven模块&#xff1a; 1). aliyun-oss-spring-boot-starter模块 创建完starter模块后&#xff0c;删除多余的文件…

CSS的文本样式属性值,web前端开发规范

正文 介绍下半连接队列 服务器第一次接收到客户端的SYN后&#xff0c;会处于SYN-REVD阶段&#xff0c;此时双方还没有建立完全的连接&#xff0c; 服务器会把此种状态下请求连接放在一个队列里&#xff0c;我们把这种队列称为半连接队列 已经完成三次握手并建立连接&#xff…

html 文字滚动

<marquee> 标签 创建文字滚动的标签 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>wzgd</title></head><body><marquee direction"left" height"30" width"600&q…

图解 TCP 拥塞控制

文章目录 什么是拥塞控制拥塞控制算法慢启动拥塞避免快速恢复 TCP拥塞控制状态机 什么是拥塞控制 拥塞控制是一种 确保网络中的数据包以可持续的速率传输 的机制&#xff0c;避免因为数据包太多而超过网络当前的承载能力&#xff0c;导致网络性能下降&#xff0c;甚至产生大量…

golang 注释插件

Goanno插件 自动生成golang注释,该插件为 Intellij/Goland 中的 golang 提供自动生成注释 如何使用&#xff1f; control command / (for windows: control alt /)&#xff08;生成注释&#xff09;Right click -> Generate -> Goanno&#xff08;生成注释&#x…

【框架学习 | 第一篇】一篇文章读懂MyBatis

文章目录 1.Mybatis介绍1.1Mybatis历史1.2Mybatis特点1.3与其他持久化框架对比1.4对象关系映射——ORM 2.搭建Mybatis2.1引入依赖2.2创建核心配置文件2.3创建表、实体类、mapper接口2.4创建映射文件2.4.1映射文件命名位置规则2.4.2编写映射文件2.4.3修改核心配置文件中映射文件…

flutterpageview动画,小程序FMP优化实录

是否能进一步优化自己的代码 1.保存在内存中的图片&#xff0c;是否做过压缩处理再保存在内存里否则可能由于图片质量太高&#xff0c;导致 OOM 2.Intent 传递的数据太大&#xff0c;会导致页面跳转过慢。太大的数据可以通过持久化的形式传递&#xff0c;例如读写文件 3.频繁…

could not publish server configuration for tomcat at localhost

1&#xff0c;报错信息如图&#xff1a; 2&#xff0c;找到servers双击&#xff0c;选择Modules&#xff0c;如果有两个webModules ,remove一个&#xff0c; 3&#xff0c;如果重启还是报错&#xff0c;干脆两个都remove&#xff0c;双击tomcat服务add And Remove重新添加

【论文翻译】结构化状态空间模型

文章目录 3.2 对角结构化状态空间模型3.2.1 S4D:对角SSM算法3.2.2 完整应用实例 3.3 对角化加低秩&#xff08;DPLR&#xff09;参数化3.3.1 DPLR 状态空间核算法3.3.2 S4-DPLR 算法和计算复杂度3.3.3赫尔维兹&#xff08;稳定&#xff09;DPLR形式 这篇文章是Mamba作者博士论文…