rk3399/rk3399pro 触摸屏从底层到应用层分析

rk3399/rk3399pro 触摸屏从底层到应用层分析 2023-12-07 08:54:53 861

1.背景

需要了解触摸屏当人按下之后,触摸点的一些信息,比如触摸点的坐标(x,y),以及触摸力度等等。以官方rk3399pro开发板硬件为基础,来了解相关信息。

2.内核驱动

2.1层次框图

该部分内核驱动属于输入子系统部分,大概的层次关系如下图:

其中事件处理层的函数都是通过input_register_handler()函数注册到input_handler_list链表中,搜索input_register_handler注册函数,就可以看到都是事件处理层里的函数:

所以最终如下图所示:

右边的驱动事件处理,内核是已经写好了的,所以我们的触摸屏只需要写具体的驱动设备,然后内核会与触摸屏驱动tsdev.c自动连接

2.2相关结构体和函数

结构体:

struct input_dev {     
       void *private;
       const char *name;  //设备名字
       const char *phys;  //文件路径,比如 input/buttons
       const char *uniq;  
       struct input_id id;

       unsigned long evbit[NBITS(EV_MAX)];  //表示支持哪类事件,常用有以下几种事件(可以多选)
       //EV_SYN      同步事件,当使用input_event()函数后,就要使用这个上报个同步事件
       //EV_KEY       键盘事件
       //EV_REL       (relative)相对坐标事件,比如鼠标
       //EV_ABS       (absolute)绝对坐标事件,比如摇杆、触摸屏感应
       //EV_MSC      其他事件,功能
       //EV_LED       LED灯事件
       //EV_SND      (sound)声音事件
       //EV_REP       重复键盘按键事件
       //(内部会定义一个定时器,若有键盘按键事件一直按下/松开,就重复定时,时间一到就上报事件)  

       //EV_FF         受力事件
       //EV_PWR      电源事件
       //EV_FF_STATUS  受力状态事件

       unsigned long keybit[NBITS(KEY_MAX)];   //存放支持的键盘按键值
       //键盘变量定义在:include/linux/input.h, 比如: KEY_L(按键L)、BTN_TOUCH(触摸屏的按键)

       unsigned long relbit[NBITS(REL_MAX)];    //存放支持的相对坐标值
       unsigned long absbit[NBITS(ABS_MAX)];   //存放支持的绝对坐标值,存放下面4个absxxx[]
       unsigned long mscbit[NBITS(MSC_MAX)];   //存放支持的其它事件,也就是功能
       unsigned long ledbit[NBITS(LED_MAX)];    //存放支持的各种状态LED
       unsigned long sndbit[NBITS(SND_MAX)];    //存放支持的各种声音
       unsigned long ffbit[NBITS(FF_MAX)];       //存放支持的受力设备
       unsigned long swbit[NBITS(SW_MAX)];     //存放支持的开关功能
         ... ...


/*以下4个数组都会保存在上面成员absbit[]里,数组号为:ABS_xx ,位于include/linux/input.h */
/*比如数组0,标志就是ABS_X,以下4个的absXXX[0]就是表示绝对位移X方向的最大值、最小值... */
/*对于触摸屏常用的标志有:
ABS_X(X坐标方向), ABS_Y(Y坐标方向), ABS_PRESSURE(压力方向,比如绘图,越用力线就越粗)* / 
       int absmax[ABS_MAX + 1];      //绝对坐标的最大值
       int absmin[ABS_MAX + 1];      //绝对坐标的最小值
       int absfuzz[ABS_MAX + 1];     //绝对坐标的干扰值,默认为0,
       int absflat[ABS_MAX + 1];     //绝对坐标的平焊位置,默认为0
... ...

函数:

struct input_dev *input_allocate_device(void);  //向内存中分配input_dev结构体

input_free_device(struct input_dev *dev);   //释放内存中的input_dev结构体

input_register_device(struct input_dev *dev);   //注册一个input_dev,若有对应的驱动事件,
则在/sys/class/input下创建这个类设备

input_unregister_device(struct input_dev *dev);   //卸载/sys/class/input目录下的
input_dev这个类设备


set_bit(nr,p);                  //设置某个结构体成员p里面的某位等于nr,支持这个功能
/* 比如:
set_bit(EV_KEY,buttons_dev->evbit);   //设置input_dev结构体buttons_dev->evbit支持EV_KEY
set_bit(KEY_S,buttons_dev->keybit);  //设置input_dev结构体buttons_dev->keybit支持按键”S”
*/

input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat); 
//设置绝对位移的支持参数
//dev: 需要设置的input_dev结构体
//axis : 需要设置的数组号,常用的有: ABS_X(X坐标方向), ABS_Y(Y坐标方向), ABS_PRESSURE(压力方向)//min: axis方向的最小值, max:axis方向的最大值, fuzz: axis方向的干扰值, flat:axis方向的平焊位置


input_report_abs(struct input_dev *dev, unsigned int code, int value);   
//上报EV_ABS事件
//该函数实际就是调用的input_event(dev, EV_ABS, code, value);
//*dev :要上报哪个input_dev驱动设备的事件
// code: EV_ABS事件里支持的哪个方向,比如X坐标方向则填入: ABS_X
//value:对应的方向的值,比如X坐标126

input_report_key(struct input_dev *dev, unsigned int code, int value);  
//上报EV_KEY事件 

input_sync(struct input_dev *dev); //同步事件通知,通知系统有事件上报

struct  clk *clk_get(struct device *dev, const char *id);    
//获得*id模块的时钟,返回一个clk结构体
//*dev:填0即可,     *id:模块名字, 比如"adc","i2c"等,名字定义在clock.c中

clk_enable(struct clk *clk);   
//开启clk_get()到的模块时钟,就是使能CLKCON寄存器的某个模块的位

2.3不同触摸芯片驱动位置

不同触摸芯片驱动位置在内核里面,路径如下:

kernel/drivers/input/touchscreen

大概的文件结构:

zl@zl-Lenovo:~/workspace-rk/rk3399pro/rk3399pro-linux/kernel/drivers/input$ tree touchscreen/
touchscreen/
├── 88pm860x-ts.c
├── ad7877.c
├── ad7879.c
├── ad7879.h
├── ad7879-i2c.c
├── ad7879-spi.c
├── ads7846.c
├── ar1021_i2c.c
├── atmel_mxt_ts.c
├── atmel_mxt_ts.o
├── atmel-wm97xx.c
├── auo-pixcir-ts.c
├── bcm_iproc_tsc.c
├── bu21013_ts.c
├── built-in.o
├── chipone_icn8318.c
├── colibri-vf50-ts.c
├── cy8ctmg110_ts.c
├── cy8c_touchpad.c
├── cyttsp4_core.c
├── cyttsp4_core.h
├── cyttsp4_i2c.c
├── cyttsp4_spi.c
├── cyttsp_core.c
├── cyttsp_core.h
├── cyttsp_i2c.c
├── cyttsp_i2c_common.c
├── cyttsp_spi.c
├── da9034-ts.c
├── da9052_tsi.c
├── dynapro.c
├── edt-ft5x06.c
├── eeti_ts.c
├── egalax_ts.c
├── elants_i2c.c
├── elants_i2c.o
├── elo.c
├── ft6236.c
├── fujitsu_ts.c
├── goodix.c
├── gsl3673_800x1280.c
├── gsl3673_800x1280.h
├── gsl3673.c
├── gsl3673.h
├── gsl3673.o
├── gsl_point_id.c
├── gsl_point_id.o
├── gslx6801.c
├── gslx6801.h
├── gslx680a.c
├── gslx680.c
├── gslx680_d708
│   ├── Makefile
│   ├── rockchip_gsl3670.h
│   ├── rockchip_gslX680_88v.h
│   └── rockchip_gslX680.c
├── gslx680_firefly.c
├── gslx680_firefly.h
├── gslx680.h
├── gslx680.o
├── gslx680_pad.c
├── gslx680_pad.h
├── gt1x
│   ├── built-in.o
│   ├── gt1x.c
│   ├── gt1x_extents.c
│   ├── gt1x_extents.o
│   ├── gt1x_firmware.h
│   ├── gt1x_generic.c
│   ├── gt1x_generic.h
│   ├── gt1x_generic.o
│   ├── gt1x.h
│   ├── gt1x.o
│   ├── gt1x_tools.c
│   ├── gt1x_tools.o
│   ├── gt1x_update.c
│   ├── gt1x_update.o
│   ├── Makefile
│   ├── modules.builtin
│   └── modules.order
├── gt9xx
│   ├── built-in.o
│   ├── goodix_gt9xx.o
│   ├── goodix_tool.c
│   ├── GT9110P_Config_20160217_1526_2048_97.cfg
│   ├── GT9271_Config_20170526.cfg
│   ├── gt9xx.c
│   ├── gt9xx_cfg.h
│   ├── gt9xx_firmware.h
│   ├── gt9xx.h
│   ├── gt9xx.o
│   ├── gt9xx_update.c
│   ├── gt9xx_update.o
│   ├── Makefile
│   ├── modules.builtin
│   ├── modules.order
│   ├── WGJ10162B_GT9271_1060_Config_20140821_1341110X42.cfg
│   ├── WGJ10162_GT9271_Config_20140820_182456.cfg
│   ├── WGJ10187_GT910_Config_20140623_104014_0X41.cfg
│   ├── WGJ10187_GT9271_Config_20140623_104014_0X41.cfg
│   ├── WGJ89006B_GT911_Config_20140625_085816_0X43.cfg
│   └── WGJ89006B_GT9271_Config_20140625_085816_0X41.cfg
├── gunze.c
├── hampshire.c
├── hp680_ts_input.c
├── htcpen.c
├── ili210x.c
├── imx6ul_tsc.c
├── inexio.c
├── intel-mid-touch.c
├── ipaq-micro-ts.c
├── jornada720_ts.c
├── Kconfig
├── lpc32xx_ts.c
├── mainstone-wm97xx.c
├── Makefile
├── max11801_ts.c
├── mc13783_ts.c
├── mcs5000_ts.c
├── migor_ts.c
├── mk712.c
├── mms114.c
├── modules.builtin
├── modules.order
├── mtouch.c
├── of_touchscreen.c
├── of_touchscreen.o
├── pcap_ts.c
├── penmount.c
├── pixcir_i2c_ts.c
├── rohm_bu21023.c
├── s3c2410_ts.c
├── st1232.c
├── stmpe-ts.c
├── sun4i-ts.c
├── sur40.c
├── sx8654.c
├── ti_am335x_tsc.c
├── touchit213.c
├── touchright.c
├── touchwin.c
├── tp_gslx680_board.h
├── tps6507x-ts.c
├── tp_suspend.h
├── tsc2004.c
├── tsc2005.c
├── tsc2007.c
├── tsc200x-core.c
├── tsc200x-core.h
├── tsc40.c
├── ucb1400_ts.c
├── usbtouchscreen.c
├── usbtouchscreen.o
├── vtl_ts
│   ├── apk.c
│   ├── apk.h
│   ├── chip.c
│   ├── chip.h
│   ├── f307&f317&f316_CT363S_01_V10_F7E9_140212.dat
│   ├── LX20JS06_A1_CT363_V03_5198_121015.dat
│   ├── lx--js77_97_CT365_V01_E7DA_130419.dat
│   ├── Makefile
│   ├── tp_fw.h
│   ├── vtl_ts.c
│   ├── vtl_ts.h
│   └── wgj36js07_A1_CT363_V01_0187_140306.dat
├── w90p910_ts.c
├── wacom_i2c.c
├── wacom_w8001.c
├── wdt87xx_i2c.c
├── wm831x-ts.c
├── wm9705.c
├── wm9712.c
├── wm9713.c
├── wm97xx-core.c
├── zforce_ts.c
└── zylonite-wm97xx.c

4 directories, 173 files

2.4触摸芯片确认

对于一个开发板用的什么触摸芯片,可以从硬件资料查看,也可以从启动log里面查看,比如rk3399pro开发板buildroot文件系统开机log如下:

[0.548500] input: gsl3673 as /devices/platform/ff3d0000.i2c/i2c-4/4-0040/input/input1

从这个开机信息中,可以看到用的触摸芯片是gsl3673,并且注册的是input1设备,这样当这个触摸芯片有事件上报的时候,我们可以通过查看/dev/input/event1的信息来查看,命令行中查看的方法是:

[root@rk3399pro:/userdata]# hexdump /dev/input/event1
0000000 f7bd 62aa 0000 0000 7f40 0002 0000 0000
0000010 0003 0039 0001 0000 f7bd 62aa 0000 0000
0000020 7f40 0002 0000 0000 0003 003a 002a 0000
0000030 f7bd 62aa 0000 0000 7f40 0002 0000 0000
0000040 0003 0018 002a 0000 f7bd 62aa 0000 0000
0000050 7f40 0002 0000 0000 0003 0030 002a 0000
0000060 f7bd 62aa 0000 0000 7f40 0002 0000 0000
0000070 0003 0035 0324 0000 f7bd 62aa 0000 0000

关于hexdump分析键盘或者触摸屏的信息的有关内容,后面会继续整理。

3.应用层解析

从内核驱动的分析来看,触摸屏驱动拿到数据之后,会上报相应的事件,我们可以在应用层,通过读取/dev/input/event1的内容,来解析上报的信息。

3.1解析源码

#include <stdio.h>
#include <stdio.h>
#include <errno.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

static int fd = 0;
static struct input_event ts;

int touch_init()
{
    fd = open("/dev/input/event1", O_RDONLY);
    if(fd == -1)
    {
        printf("[%s]:[%d] open event file error\r\n", __FUNCTION__, __LINE__);
        return -1;
    }
    printf("open event1 success\n");
}

int get_xy(int *x,int *y)
{
    read(fd,&ts,sizeof(ts));
    printf("ts.type:%d,ts.code:0x%x\n",ts.type,ts.code);
    if(ts.type == EV_ABS && ts.code == ABS_MT_POSITION_X)
    {
        *x = ts.value;
        return 0;
    }
    if(ts.type == EV_ABS && ts.code == ABS_MT_POSITION_Y)
    {
        *y = ts.value;
        return 0;
    }
    if(ts.type == EV_ABS && ts.code == ABS_PRESSURE)
    {
        printf("ts.value:%d\n",ts.value);
        return 0;
    }

    return -1;
}

int main()
{
    int x,y,tmp;
    touch_init();
    while(1)
    {
        tmp = get_xy(&x, &y);
        if(tmp == 0)
        {
            printf("get position x:%d,y:%d\r\n",x,y);
        }
        else
        {
            printf("type error\n");
        }
    }
}

上面的源码,只解析了x,y坐标和压力数据,需要其他数据的话,可以根据相应类型,进行解析。type和code的值,定义在input-event-codes.h里面。

关于input_event结构体:

struct timeval {
    __kernel_time_t tv_sec; /* seconds,32bit /
    __kernel_suseconds_t tv_usec; / microseconds,32bit */
};

struct input_event {
    struct timeval time; //时间
    __u16 type; //事件类型
    __u16 code; //事件键值
    __s32 value; //值
};

4.关于压力值说明

有时候需要读取压力值,也就是手指按下的力度,对于触摸屏解码芯片和屏幕,有的是支持的,而有的不支持,并且支持的里面,也是分不同情况的,所以总结罗列下大概的情况:

  • 第一种,触摸芯片不支持,这种情况下,只能拿到坐标值,压力值拿不到。

  • 第二种,触摸芯片支持,但是因为无法准确提供压力值,所以提供了手指接触面的直径,从侧面反映手指按下的力度,这个时候会通过两个事件上报相应的值:ABS_MT_TOUCH_MAJOR和ABS_MT_WIDTH_MAJOR 。 ABS_MT_TOUCH_MAJOR表示了手指接触TP的直径的近似。ABS_MT_WIDTH_MAJOR是手指的直径的近似。当手指和触摸屏接触的越紧密,则压力越大,手指和屏幕接触的面积(直径)也会越大。而手指的直径通常是一个常量。这样ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR就可以用来表示压力了。而且这个值在[0,255)间。

  • 第三种,触摸芯片支持,并且可以准确提供压力值,这个时候也会通过一个事件来上报: ABS_MT_PRESSUR,这个用来上报更准确的手指触摸屏幕时候的压力值。

5.扩展hexdump分析event值

hexdump: 查看文件的内容,比如二进制文件中包含的某些字符串,通常用来调试驱动用

结合前面的 input_event 结构体:

struct timeval {
    __kernel_time_t tv_sec; /* seconds,32bit /
    __kernel_suseconds_t tv_usec; / microseconds,32bit */
};

struct input_event {
    struct timeval time; //时间
    __u16 type; //事件类型
    __u16 code; //事件键值
    __s32 value; //值
};

5.1调试键盘驱动

以按开发板的按键 KEY_L,为例(因为数据是从低到高打印的,所以数据是反的):

//按键键盘驱动
# hexdump /dev/input/event0

/*按下时:*/
//hexdump序列号                       微妙         键盘事件    code=KEY_L     value=1(按下)
 0000000             07c6 0000      faa2 000b      0001        0026          0001 0000
//hexdump序列号                       微妙         同步事件       code        value=0 
 0000010            07c6 0000      faac 000b       0000        0000          0000 0000

/*松开时:*/
//hexdump序列号                       微妙         键盘事件     code=0x26     value=0(松开)
 0000020             07c6 0000     cf67 000d        0001        0026         0000 0000
//hexdump序列号                       微妙         同步事件      code         value=0 
 0000030             07c6 0000     cf70 000d        0000        0000         0000 0000

5.2调试触摸屏驱动

//触摸屏驱动
# hexdump /dev/input/event1 
//hexdump序列号                       微妙        绝对坐标事件    code=ABS_X   X坐标值 
0000000               0412 0000      6ef0 000c      0003          0000      0239 0000
//hexdump序列号                       微妙        绝对坐标事件    code=ABS_Y   Y坐标值
0000010                 0412 0000    6f08 000c      0003          0001      01ae 0000
//hexdump序列号                       微妙        绝对坐标事件    code=压力     压力值
0000020             0412 0000        6f0c 000c      0003          0018      0001 0000
//hexdump序列号                       微妙        键盘事件       code=触摸按键  value=1(按下)
0000030              0412 0000       6f10 000c      0001          014a      0001 0000
//hexdump序列号                       微妙        同步事件      
0000040             0412 0000        6f13 000c      0000          0000      0000 0000

//hexdump序列号                       微妙        绝对坐标事件    code=压力     压力值
00000b0               023b 0000      872d 000c      0003          0018      0000 0000

//hexdump序列号                       微妙        键盘事件      code=触摸按键  value=0(松开)
00000b0            0412 0000         1f5b 000d     0001          014a       0000 0000
//hexdump序列号                       微妙        同步事件      
00000c0             0412 0000        1f70 000d     0000          0000       0000 0000

类似的方法,也可以使用getevent命令,但是这个命令有的系统默认是不带的。

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区