Android12 偶现触摸失灵

一、触摸问题

生产线 在烧录固件时,会偶然出现稍完之后屏幕触摸用不了。前期以为是烧录没弄好,后面又发生,就怀疑与产品有关了。

首先进行抓日志分析:有问题的设备先确认下dmesg信息

adb连接设备进行日志抓取:
logcat > /sdcard/logcat.log
dmesg  > /sdcard/dmesg.log

确认问题日志信息如下:

[    6.224059] ___touch_compatible_probe() start____ 
[    6.225273] \x0avfs_read return ret=12
[    6.225292] touch_compatible:Not first Start the system,Already read touch\xef\xbc\x9aUSB_touch
[    6.225297] LOUHN in touch_module_init:USB_touch
[    6.225514] pwm-backlight backlight1: backlight1 supply power not found, using dummy regulator
[    6.225780] pwm-backlight backlight1: Linked as a consumer to regulator.0
[    6.225837] pwm-backlight backlight1: Dropping the link to regulator.0
[    6.249039] usb 1-1: new high-speed USB device number 3 using ehci-platform
[    6.400229] usb 1-1: New USB device found, idVendor=a69c, idProduct=8801, bcdDevice= 1.00
[    6.400245] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3

根据找出有问题的日志片段,我们可以进行详细的分析:

  1. touch_compatible_probe() start:说明这时刚刚开始触摸匹配。

  2. touch_compatible:Not first Start the system,Already read touch\xef\xbc\x9aUSB_touch:该消息表明这不是系统的第一次启动,之前已经读取了触摸输入设备,且是通过 USB 接口连接的。

  3. LOUHN in touch_module_init:USB_touch:指明正在初始化的触摸模块是通过 USB 接口连接的。

但是我们的触摸是I2C触摸,为什么会识别成USB触摸呢?所以我们要到的驱动里去看一下这个touch_compatible_probe()函数的实现。

触摸驱动路径:

Android12.0/kernel-4.19/drivers/input/touchscreen/touch_adapter_driver/touch_adapter.c

 touch_compatible_probe实现:

static int touch_compatible_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0,i = 0;
     struct device_node *np = client->dev.of_node;
    printk("___%s() start____ \n", __func__);

    ret = read_touch_type(TOUCH_TYPE_FILE,touch_type,31);
    if(ret) {
        printk("touch_compatible:read %s faild ret=%d!",TOUCH_TYPE_FILE,ret);
        return -ENOMEM;
    } else {
        if( strlen(touch_type) ) {//touch_type不为空,则说明不是第一次启动
             printk("touch_compatible:Not first Start the system,Already read touch:%s\n",touch_type);
             touch_module_init(touch_type);
             return 0;
        }
    }
    comp_irq_gpio = of_get_named_gpio(np, "compatible,riq-gpio",0);
    comp_reset_gpio = of_get_named_gpio(np, "compatible,reset-gpio", 0);
    //gtp_request_io_port
    ret = gpio_request(comp_reset_gpio, "touch_gpio_reset");
    ret += gpio_request(comp_irq_gpio, "touch_gpio_irq");
    if(!ret) {
            for (i = 0; i < (sizeof(ts_list) / sizeof(touchscreen)); i++) {
            if (ts_list[i].check_i2c_func) {
                if((ts_list[i].check_i2c_func)(client, ts_list[i].i2c_addr)) {
                    printk("Found Touch I2C IC: %s\n",ts_list[i].touch_name);
                    if (save_data_to_file(TOUCH_TYPE_FILE,ts_list[i].touch_name,strlen(ts_list[i].touch_name)) ) {
                        printk("touch_compatible:save %s faild!",TOUCH_TYPE_FILE);
                        return -ENOMEM;
                    }
                    touch_module_init(ts_list[i].touch_name);
                    break;
                }
            } else {
                printk("Touch[%s] Handle function is NULL\n", ts_list[i].touch_name);
            }
            if (i == ((sizeof(ts_list) / sizeof(touchscreen) -1)) ) {
                save_data_to_file(TOUCH_TYPE_FILE,USB_TOUCH,strlen(ts_list[i].touch_name));//没有匹配到I2C触摸,默认为USB触摸
                return 0;
            }
            }

    }

    return 0;
}

 由上述信息可知:

        根据触摸屏驱动的probe 函数, 首先通过读取一个文件来获取触摸屏类型,如果读取成功并且触摸屏类型不为空,则说明不是第一次启动系统,直接根据触摸屏类型进行初始化,并返回成功。如果触摸屏类型为空,说明是第一次启动系统,并使用 gpio_request() 函数获取设备树中指定的 GPIO 引脚名称获取对应的 GPIO 号。如果请求成功,循环遍历 ts_list 数组中的元素,逐个检查是否存在 I2C 触摸设备。如果存在 I2C 触摸设备,打印信息并将触摸设备的名称写入 TOUCH_TYPE_FILE 文件中,然后调用touch_module_init进行触摸模块的初始化,最后跳出循环。如果循环结束后仍未找到匹配的 I2C 触摸设备,将默认将触摸设备类型写入 TOUCH_TYPE_FILE 文件中。

        该函数的主要功能是通过 I2C 获取与触摸设备有关的信息,并根据配置信息选择不同的触摸模块进行初始化。如果没有找到匹配的触摸设备,将默认选择 USB 触摸设备进行初始化。

        很明显,出现问题的设备就是识别为了USB触摸,但我们使用的是I2C触摸,所以才会导致触摸无法使用的情况。我们先找到TOUCH_TYPE_FILE这个文件,进行删除,定位一下原因。

        文件位置查找:

Android12.0/kernel-4.19/drivers/input/touchscreen/touch_adapter_driver/touch_compatible.h

         可知TOUCH_TYPE_FILE的文件路径在 /data/hardware_status/touch_type

       对 touch_type 进行删除后重新创建,触摸能正常使用。

       初步考虑是烧录固件的时候没有接入I2C触摸,烧录完成后才进行组装。所以第一次并未识别到I2C触摸屏,如果没有找到任何匹配的I2C触摸屏设备,那么会调用save_data_to_file函数将触摸屏类型设置为USB触摸。后面和工厂的生产线落实确实是这种情况。

二、解决方案

1、设计思路

2、kernel代码修改

kernel-4.19/drivers/input/touchscreen/touch_adapter_driver/touch_adapter.c
diff --git a/drivers/input/touchscreen/touch_adapter_driver/touch_adapter.c
b/drivers/input/touchscreen/touch_adapter_driver/touch_adapter.c
index b26f09c63318..6510bb1ebbb6 100755
--- a/drivers/input/touchscreen/touch_adapter_driver/touch_adapter.c
+++ b/drivers/input/touchscreen/touch_adapter_driver/touch_adapter.c
@@ -60,7 +60,7 @@ static int read_touch_type(const char * file_path,char*buff, int size)
mm_segment_t old_fs;
    loff_t pos;
    int ret=0;
    - file = filp_open(file_path,O_CREAT|O_RDWR,0664);

    + file = filp_open(file_path,O_CREAT|O_RDWR, 0666);
     // 修改创建的"/data/hardware_status/touch_type" 权限⽤于上层修改
    if(IS_ERR(file))
        {
            printk("\nfile_read: filp_open fail!\n");
@@ -84,7 +84,7 @@ static int save_data_to_file(const char* save_file_name,
char *buff, int size)
    int ret=0;
    printk("save_file_name = %s!\n",save_file_name);
    - fp = filp_open(save_file_name, O_RDWR | O_CREAT, 0644);
    + fp = filp_open(save_file_name, O_RDWR | O_CREAT, 0666); // 修改权限
    if (IS_ERR(fp))
        {
            printk("\nsave_data_to_file create file error\n");
@@ -435,7 +435,8 @@ static int touch_compatible_probe(struct i2c_client
*client, const struct i2c_de
    printk("Touch[%s] Handle function is NULL\n",
    ts_list[i].touch_name);
    }
    if (i == ((sizeof(ts_list) / sizeof(touchscreen) -1)) ) {
    -save_data_to_file(TOUCH_TYPE_FILE,USB_TOUCH,strlen(ts_list[i].touch_name));
    //没有匹配到I2C触摸,默认为USB触摸
    + // 若识别不到触摸兼容内的I2C设备,则等待下⼀次设备重启检测,并打印⽇志
    + printk("Not found I2C touch present.");
    + save_data_to_file(TOUCH_TYPE_FILE,USB_TOUCH,strlen(ts_list[i].touch_name));
    //没有匹配到I2C触摸,默认为USB触摸
    return 0;
    }
}

3、framework代码修改

frameworks/native/services/inputflinger/reader/EventHub.cpp
diff --git a/services/inputflinger/reader/EventHub.cpp
b/services/inputflinger/reader/EventHub.cpp
index 3067d87293..1f7011d5a0 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -61,6 +61,9 @@
    using android::base::StringPrintf;
    using namespace android::flag_operators;
    +#define USB_TOUCH "USB_touch"
    +#define TOUCH_TYPE_FILE "/data/hardware_status/touch_type"
    +
    namespace android {
        static const char* DEVICE_PATH = "/dev/input";
@@ -1846,6 +1849,35 @@ void
EventHub::reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier&
identifier.bus, obfuscatedId.c_str(),
classes.get());
}
+//保存数据⾄⽂件
+static void save_data_to_file(const std::string& filename, const std::string&
data)
+{
    + FILE* file = std::fopen(filename.c_str(), "r");
    + if (file != nullptr) {
    + std::fseek(file, 0, SEEK_END); // 移动⽂件指针到⽂件末尾
    + long size = std::ftell(file); // 获取当前⽂件指针的偏移量,即⽂件⼤⼩
    +
    + if (size > 0) {
    + ALOGW("File already exists and has data. Data will not be written.");
    + std::fclose(file);
    + return ;
            + }
    +
    + std::fclose(file);
+ }
    + // 将USB_touch写⼊⽂件
    + file = std::fopen(filename.c_str(), "w");
    + if (file != nullptr) {
    + std::fwrite(data.c_str(), sizeof(char), data.size(), file);
    + std::fclose(file);
    + ALOGW("Data saved to TOUCH_TYPE_FILE successfully.");
    + } else {
    + ALOGW("Failed to open the TOUCH_TYPE_FILE.");
    + }
    +

    + return ;
    +}
    +
void EventHub::openDeviceLocked(const std::string& devicePath) {
@@ -2138,9 +2170,16 @@ void EventHub::openDeviceLocked(const std::string&
devicePath) {
    device->classes |= InputDeviceClass::MIC;
}
    + char value[120];
    // 获取特定产品的内部USB触摸节点信息
    + property_get("ro.touchinput.internal", value, "");
    +
    // Determine whether the device is external or internal.
    // 若⽆USB触摸则不会进⼊下⽅if判断内,即进⼊if判断后 device->identifier.location.c_str() ⼀定有值
    if (device->isExternalDeviceLocked()) {
        - device->classes |= InputDeviceClass::EXTERNAL;
        + if (strcmp(device->identifier.location.c_str(), value)){
        // 若与产品的属性不等,则作为副屏,设置外部触摸属性
    + device->classes |= InputDeviceClass::EXTERNAL;
    + } else if ( strcmp(device->identifier.location.c_str(), value) == 0) {
    // 若与产品的属性相等,则写⼊⽂件信息
    + save_data_to_file(TOUCH_TYPE_FILE, USB_TOUCH);
    + }
    }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春风从不入睡、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值