Linux input系统数据上报流程

本文详细解析了Linux input系统中触屏设备的数据上报流程,从触屏驱动、input_report_abs()函数、handler的注册与匹配到数据的读取。文章以4.19.6内核版本的ft6236.c驱动为例,介绍了如何从中断处理到input_event(),再到handler的connect(),最终完成设备和handler的连接。通过对input_handler_list和input_dev_list的理解,阐述了数据如何从硬件读取并传递到用户空间。
摘要由CSDN通过智能技术生成

作为鸡生蛋系列文章,这里主要关注Linux input系统,
主要为触摸事件上报流程.

读该文章最好有对linux驱动的入门知识.
其实当你自己去分析了input系统后,再分析别的就相对很轻松了,
linux里好多套路都差不多的.

本文例子以ft6236.c驱动为例, 当然你也可以用goodix或者别的触摸来分析.
但是分析基于的内核版本用4.19.6(我写这篇文档时最新稳定版)
(https://git.kernel.org/pub/sc...
文档可参看
<<linux-4.19.6>>/Documentation/input/input.rst
<<linux-4.19.6>>/Documentation/input/input-programming.rst

触屏设备驱动

eg:
(https://source.codeaurora.org...

static irqreturn_t ft6236_interrupt(int irq, void *dev_id)
{
......//5. 中断处理中读数据
    error = ft6236_read(ft6236->client, 0, sizeof(buf), &buf);
......
    for (i = 0; i < touches; i++) {
        struct ft6236_touchpoint *point = &buf.points[i];
        u16 x = ((point->xhi & 0xf) << 8) | buf.points[i].xlo;
        u16 y = ((point->yhi & 0xf) << 8) | buf.points[i].ylo;
......
        input_mt_slot(input, id);
        input_mt_report_slot_state(input, MT_TOOL_FINGER, act);
......//5. 上报数据, ABS即坐标的绝对值
            input_report_abs(input, ABS_MT_POSITION_X, x);
            input_report_abs(input, ABS_MT_POSITION_Y, y);
......
    input_mt_sync_frame(input);
    input_sync(input);
......
}

//2. probe函数, 当设备与驱动匹配上时会执行该函数
static int ft6236_probe(struct i2c_client *client,
            const struct i2c_device_id *id)
{
......// 3. input设备申请
    input = devm_input_allocate_device(dev);
......
    ft6236->input = input;
    input->name = client->name;
    input->id.bustype = BUS_I2C;
......// 3. input设备参数/能力申明
        input_set_abs_params(input, ABS_MT_POSITION_X, 0,
                     ft6236->max_x, fuzz_x, 0);
        input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
                     ft6236->max_y, fuzz_y, 0);
......
    error = input_mt_init_slots(input, FT6236_MAX_TOUCH_POINTS,
                    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
...... 5. 中断来时回调到ft6236_interrupt
    error = devm_request_threaded_irq(dev, client->irq, NULL,
                      ft6236_interrupt, IRQF_ONESHOT,
                      client->name, ft6236);
......4. 注册为Input类设备
    error = input_register_device(input);
......
}
  //of table和id table在设备和驱动匹配时会用到
#ifdef CONFIG_OF
static const struct of_device_id ft6236_of_match[] = {
.....
MODULE_DEVICE_TABLE(of, ft6236_of_match);
#endif

static const struct i2c_device_id ft6236_id[] = {
.....
MODULE_DEVICE_TABLE(i2c, ft6236_id);

static struct i2c_driver ft6236_driver = {
    .driver = {
        .name = "ft6236",
        .of_match_table = of_match_ptr(ft6236_of_match),
    },
    .probe = ft6236_probe,
    .id_table = ft6236_id,
};
//1. 模块init, 这是一个宏定义, 里面包含了, module_init, i2c的添加驱动注册,
//module_init可以理解为对该文件的加载顺序,其它的还有core_initcall late_initcall等
module_i2c_driver(ft6236_driver);

简单说明下实现一个触屏驱动包含以下内容

  1. 文件和模块init
  2. 按照linux设备模型填充i2c驱动(设备一般在dts里配置,这里不提)
  3. 设备和驱动匹配上后,执行驱动的probe()函数, probe()里申请input device, 能力填充, 再在里面将设备注册为input类
  4. 当点击屏后,中断来了,回调中断处理函数
  5. 中断处理里, 通过i2c的方法从硬件读取数据,并进行上报.

注意, 触屏上报有个多点触摸协议,可参看文档
<<linux-4.19.6>>/Documentation/input/multi-touch-protocol.rst

上报--input_report_abs()

我们的重点是想知道数据上报流程, 所以自然要分析input_report_abs()

include/linux/input.h
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
    input_event(dev, EV_ABS, code, value);
}

可以看到其为内联函数, 为input_event(,EV_ABS, ...)的二次封装;

input_report_key()       -+                  +- EV_KEY
input_report_rel()       -|                  |- EV_REL
input_report_abs()       -|                  |- EV_ABS
input_report_ff_status() -|--input_event() --|- EV_FF_STATUS
input_report_switch()    -|                  |- EV_SW
input_sync()             -|                  |- EV_SYN, SYN_REPORT
input_mt_sync()          -+                  +- EV_SYN, SYN_MT_REPORT

对于我们的根据来说,即
input_event(dev, EV_ABS, ABS_MT_POSITION_X, 坐标值)

drivers/input/input.c
void input_event(struct input_dev *dev,
         unsigned int type, unsigned int code, int value)
{
....//event是否支持, 这个和驱动里probe()时填充能力,设置参数有关,略过
    if (is_event_supported(type, dev->evbit, EV_MAX)) {
....
        input_handle_event(dev, type, code, value);
...
}

static void input_handle_event(struct input_dev *dev,
                   unsigned int type, unsigned int code, int value)
{
    int disposition = input_get_disposition(dev, type, code, &value); //得到disposition
......
    if (disposition & INPUT_FLUSH) {
        if (dev->num_vals >= 2)
            input_pass_values(dev, dev->vals, dev->num_vals);
        dev->num_vals = 0;
    } else if (dev->num_vals >= dev->max_vals - 2) {
        dev->vals[dev->num_vals++] = input_value_sync;
        input_pass_values(dev, dev->vals, dev->num_vals);  //**<--> 重点,
        dev->num_vals = 0;
    }

}

还记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值