Input子系统框架参考:

02_输入子系统_猩猩の點燈的博客-CSDN博客

电阻式多点触摸驱动参考:

05_触摸屏驱动_猩猩の點燈的博客-CSDN博客

一:电容触摸屏知识点

1、电容触摸屏是I2C接口,需要触摸IC,因此框架为I2C设备驱动框架。

2、通过中断引脚(INT)向Linux内核上报触摸信息,因此需要用到Linux中断驱动框架,坐标上报在中断服务函数中完成。

3、触摸屏的坐标信息,屏幕按下和抬起信息都属于Linux和input子系统,因此向Linux内核上报触摸屏坐标信息就得用到input子系统。

二:多点触摸(MT)协议

1、MT协议被分为两种类型,TypeA和TypeB

TypeA:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据(较少使用)

TypeB:适用于有硬件追踪并且能区分触摸点的触摸设备,此类型的设备通过一个slot更新某一个触摸点的信息。

触摸点的信息通过一系列的ABS_MT事件上报给Linux内核,只有ABS_MT事件是用于多点触摸的:

#define ABS_MT_SLOT      0x2f    /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR  0x30    /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR  0x31    /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR  0x32    /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR  0x33    /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION  0x34    /* Ellipse orientation */
#define ABS_MT_POSITION_X   0x35    /* Center X touch position */
#define ABS_MT_POSITION_Y   0x36    /* Center Y touch position */
#define ABS_MT_TOOL_TYPE    0x37    /* Type of touching device */
#define ABS_MT_BLOB_ID      0x38    /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID  0x39    /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE     0x3a    /* Pressure on contact area */
#define ABS_MT_DISTANCE     0x3b    /* Contact hover distance */
#define ABS_MT_TOOL_X       0x3c    /* Center X tool position */
#define ABS_MT_TOOL_Y       0x3d    /* Center Y tool position */

其中最常用的ABS_MT_POSITION_X和ABS_MT_POSITION_Y用来上报触摸点的(X,Y)坐标信息,ABS_MT_SLOT用来上报触摸点ID,对于TypeB类型设备需要用到ABS_MT_TRACKING_ID事件来区分触摸点。

2、上报数据

TypeA:void input_mt_sync(struct input_dev *dev)

该函数会触发SYN_MT_REPORT事件,此事件会通知接受者获取当前触摸数据,并且准备接受下一个触摸点数据。

TypeB:void input_mt_slot(struct input_dev *dev, int slot)

该函数第二个参数slot用于指定当前上报的触摸点信息,并触发ABS_MT_SLOT事件,此事件会告诉接收者当前正在更新的是哪个触摸点(slot)的数据。

两种类型的设备最终都要调用input_sync()函数来标识多点触摸信息传输完成,告诉接收者处理之前累积的信息,并且准备好下一次接收。TypeB设备驱动需要给每个识别出来的触摸点分配一个slot,后面使用这个slot来上报触摸点信息,可以通过slot的ABS_MT_TRACKING_ID来新增,替换或删除触摸点,ID为-1表示slot未使用,一个不存在的ID表示一个新加的触摸点,一个ID如果不存在了就表示删除了。一旦检测到某个slot关联的触摸点ID发生了变化,驱动就应该改变这个slot的ABS_TM_TRACKING_ID,使这个slot失效,如果硬件设备追踪到了比他正在上报的还要多的触摸点,那么驱动就应该发送BTN_TOOL_*TAP消息,并且调用input_mt_report_pointer_emulation()函数,将此函数的第二个参数use_count设置为false。

3、上报时序

TypeA:

(1)通过ABS_MT_POSITION_X或者ABS_MT_POSITION_Y上报坐标数据,通过input_report_abs实现;

(2)上报SYN_MT_REPORT事件,通过input_my_sync实现;

(3)上报SYN_REPORT事件,通过input_sync实现。

每上报完一轮触摸点信息就调用一次input_sync函数,也就是发送一个SYN_REPORT。

static irqreturn_t xxx_handler(int irq, void *dev_id)
{ret = xxx_read_data(ts);for (i = 0; i < MAX_FINGERS; i++){input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);   input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);     input_mt_sync(input_dev);}input_sync(input_dev);
}

TypeB:

(1)上报ABS_MT_SLOT事件,也就是触摸点对应的SLOT,每次上报一个触摸点坐标前先使用input_mt_slot函数上报当前触摸点slot,其实就是触摸点ID,需要由触摸IC提供。

(2)根据TypeB要求,每个SLOT必须关联一个ABS_MT_TRACKING_ID,通过修改SLOT关联的ABS_MT_TRACKING_ID来完成对触摸点的添加,替换和删除。具体用到的函数为input_mt_report_slot_state,如果是添加新的触摸点,此函数第三个参数active要设置为true,linux会自动分配一个ABS_MT_TRACKING_ID值。

(3)上报触摸点X和Y坐标值,使用函数input_report_abs来完成。

(4)上传所有触摸点坐标后就可以发送SYN_REPORT事件,使用input_sync函数

static void xxx_report_events(struct input_dev *input, const struct touchdata *touchdata)
{bool touch;for (i = 0; i < MAX_TOUCHES; i++)  {input_mt_slot(input, i);input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);input_report_abs(input, ABS_MT_POSITION_X, x);input_report_abs(input, ABS_MT_POSITION_Y, y);}input_mt_report_pointer_emulation(input, false);input_sync(input);
}

三:多点触摸API函数

1、input_mt_init_slots:用于初始化MT的输入slots。

int input_mt_init_slots( struct input_dev *dev, unsigned int num_slots, unsigned int flags)

2、input_mt_slot:用于TypeB类型产生ABS_MT_SLOT事件,告诉内核当前上报的是哪个触摸点的坐标数据。

void input_mt_slot(struct input_dev *dev, int slot)

3、input_mt_report_slot_state:用于TypeB类型产生ABS_MT_TRACKING_ID和ABS_MT_TOOL_TYPE事件。

void input_mt_report_slot_state( struct input_dev *dev, unsigned int tool_type,bool active)

4、input_report_abs:用于TypeA和TypeB类型上报触摸点坐标信息。

void input_report_abs( struct input_dev *dev,unsigned int code,int value)

5、input_mt_report_pointer_emulation:如果追踪到的触摸点数量多于当前上报的数量,驱动程序使用BTN_TOOL_TAP事件来通知用户空间当前追踪到的触摸点总数量,然后调用该函数并将ues_count参数设置为false。否则为true,表示当前的触摸点数量。

void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)

四:多点触摸驱动示例

1、修改设备树文件

(1)添加FT5426触摸芯片IO,共4个IO(复位,中断,I2C2的SCL,SDA)

复位IO和中断IO是普通的GPIO:

pinctrl_tsc: tscgrp {fsl, pin = <MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09  0x10B0MX6UL_PAD_GPIO1_IO09__GPIO1_IO09    0xF080>;
};

I2C2的IO:

pinctrl_i2c2: i2c2grp {fsl,pins = <MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0>;
};

(2)添加FT5426节点

&i2c2 {clock_frequency = <100000>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c2>;status = "okay";... ...ft5426: ft5426@38 {compatible = "edt, edt-ft5426";reg = <0x38>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_tsc>;interrupt-parent = <&gpio1>;interrupts = <9 0>;reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;};
};

2、驱动

#include <linux/module.h>
#include <linux/ratelimit.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/input/edt-ft5x06.h>
#include <linux/i2c.h>#define MAX_SUPPORT_POINTS 5 /* 5 点触摸 */
#define TOUCH_EVENT_DOWN 0x00 /* 按下 */
#define TOUCH_EVENT_UP 0x01 /* 抬起 */
#define TOUCH_EVENT_ON 0x02 /* 接触 */
#define TOUCH_EVENT_RESERVED 0x03 /* 保留 *//* FT5X06 寄存器相关宏定义 */
#define FT5X06_TD_STATUS_REG 0X02 /* 状态寄存器地址 */
#define FT5x06_DEVICE_MODE_REG 0X00 /* 模式寄存器 */
#define FT5426_IDG_MODE_REG 0XA4 /* 中断模式 */
#define FT5X06_READLEN 29 /* 要读取的寄存器个数 */struct tsc_dev {struct device_node *nd;int irq_pin, reset_pin;int irqnum;void *private_data;struct input_dev *input;struct i2c_client *client;
};static struct tsc_dev tsc;static int tsc_reset(struct i2c_client *client, struct tsc_dev *dev)
{int ret = 0;if(gpio_is_valid(dev->reset_pin)) {ret = devm_gpio_request_one(&client->dev, dev->reset_pin, GPIOF_OUT_INIT_LOW, "edt-ft5x06 reset");if(ret) {return ret;}msleep(5);gpio_set_value(dev->reset_pin, 1);msleep(300);}return 0;
}static int tsc_read_regs(struct tsc_dev *dev, u8 reg, void *val, int len)
{int ret;struct i2c_msg msg[2];struct i2c_client *client = (struct i2c_client *)dev->client;/* msg[0]为发送要读取的首地址 */msg[0].addr = client->addr;           /* ft5x06地址 */msg[0].flags = 0;                    /* 标记为发送数据 */msg[0].buf = &reg;                    /* 读取的首地址 */msg[0].len = 1;                        /* reg长度*//* msg[1]读取数据 */msg[1].addr = client->addr;           /* ft5x06地址 */msg[1].flags = I2C_M_RD;         /* 标记为读取数据*/msg[1].buf = val;                  /* 读取数据缓冲区 */msg[1].len = len;                 /* 要读取的数据长度*/ret = i2c_transfer(client->adapter, msg, 2);if(ret == 2){ret = 0;} else {ret = -EREMOTEIO;}return ret;
}static s32 tsc_write_regs(struct tsc_dev *dev, u8 reg, u8 *buf, u8 len)
{u8 b[256];struct i2c_msg msg;struct i2c_client *client = (struct i2c_client *)dev->client;b[0] = reg;memcpy(&b[1], buf, len);msg.addr = client->addr;msg.flags = 0;msg.buf = b;msg.len = len + 1;return i2c_transfer(client->adapter, &msg, 1);
}static void tsc_write_reg(struct tsc_dev *dev, u8 reg, u8 data)
{u8 buf = 0;buf = data;tsc_write_regs(dev, reg, &buf, 1);
}static irqreturn_t tsc_handler(int irq, void *dev_id)
{struct tsc_dev *multidata = dev_id;uint8_t rdbuf[29];int i, type, x, y, id;int offset, tplen;int ret;bool down;offset = 1;  /* 偏移 1,也就是 0X02+1=0x03,从 0X03 开始是触摸值 */tplen = 6;   /* 一个触摸点有 6 个寄存器来保存触摸值 */memset(rdbuf, 0, sizeof(rdbuf));/* 读取 FT5X06 触摸点坐标从 0X02 寄存器开始,连续读取 29 个寄存器 */ret = tsc_read_regs(multidata, FT5X06_TD_STATUS_REG, rdbuf, FT5X06_READLEN);if(ret)goto fail;/* 上报每一个触摸点坐标 */for(i = 0; i < MAX_SUPPORT_POINTS; i++){uint8_t *buf = &rdbuf[i * tplen + offset];/* 以第一个触摸点为例,寄存器 TOUCH1_XH(地址 0X03),各位描述如下:* bit7:6 Event flag 0:按下 1:释放 2:接触 3:没有事件* bit5:4 保留* bit3:0 X 轴触摸点的 11~8 位。*/type = buf[0] >> 6;   /* 获取触摸类型 */if(type == TOUCH_EVENT_RESERVED)continue;/* 我们所使用的触摸屏和 FT5X06 是反过来的 */x = ((buf[2] << 8) | buf[3]) & 0x0fff;y = ((buf[0] << 8) | buf[1]) & 0x0fff;/* 以第一个触摸点为例,寄存器 TOUCH1_YH(地址 0X05),各位描述如下:* bit7:4 Touch ID 触摸 ID,表示是哪个触摸点* bit3:0 Y 轴触摸点的 11~8 位。*/id = (buf[2] >> 4) & 0x0f;down = type != TOUCH_EVENT_UP;input_mt_slot(multidata->input, id);input_mt_report_slot_state(multidata->input, MT_TOOL_FINGER, down);if(!down)continue;input_report_abs(multidata->input, ABS_MT_POSITION_X, x);input_report_abs(multidata->input, ABS_MT_POSITION_Y, y);}input_mt_report_pointer_emulation(multidata->input, true);input_sync(multidata->input);fail:return IRQ_HANDLED;
}static int tsc_irq(struct i2c_client *client, struct tsc_dev *dev)
{int ret = 0;/* 1,申请中断 GPIO */if(gpio_is_valid(dev->irq_pin)){ret = devm_gpio_request_one(&client->dev, dev->irq_pin, GPIOF_IN, "edt-ft5x06 irq");if(ret){dev_err(&client->dev, "Failed to request GPIO %d, error %d\n", dev->irq_pin, ret);return ret;}}/* 2,申请中断,client->irq 就是 IO 中断, */ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, tsc_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, &tsc);if(ret){dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");return ret;}return 0;
}static int tsc_probe(struct i2c_client *client, const struct i2c_device_id *id)
{int ret = 0;tsc.client = client;/* 1,获取设备树中的中断和复位引脚 */tsc.irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);tsc.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);/* 2,复位 FT5x06 */ret = tsc_reset(client, &tsc);if(ret < 0) {goto fail;}/* 3,初始化中断 */ret = tsc_irq(client, &tsc);    if(ret < 0) {goto fail;}/* 4,初始化 FT5X06 */tsc_write_reg(&tsc, FT5x06_DEVICE_MODE_REG, 0);tsc_write_reg(&tsc, FT5426_IDG_MODE_REG, 1);/* 5,input 设备注册 */tsc.input = devm_input_allocate_device(&client->dev);if(!tsc.input) {ret = -ENOMEM;goto fail;}tsc.input->name  = client->name;tsc.input->id.bustype = BUS_I2C;tsc.input->dev.parent = &client->dev;__set_bit(EV_KEY, tsc.input->evbit);__set_bit(EV_ABS, tsc.input->evbit);__set_bit(BTN_TOUCH, tsc.input->keybit);input_set_abs_params(tsc.input, ABS_X, 0, 1024, 0, 0);input_set_abs_params(tsc.input, ABS_Y, 0, 600, 0, 0);input_set_abs_params(tsc.input, ABS_MT_POSITION_X, 0, 1024, 0, 0);input_set_abs_params(tsc.input, ABS_MT_POSITION_Y, 0, 600, 0, 0);ret = input_mt_init_slots(tsc.input, MAX_SUPPORT_POINTS, 0);if(ret){goto fail;}ret = input_register_device(tsc.input);if(ret){goto fail;}return 0;fail:return ret;
}static int tsc_remove(struct i2c_client *client)
{input_unregister_device(tsc.input);return 0;
}static const struct i2c_device_id ft5x06_ts_id[] = {{"edt-ft5206", 0, },{"edt-ft5426", 0, },{/* */},
};static const struct of_device_id ft5x06_of_match[] = {{.compatible = "edt,edt-ft5206",},{.compatible = "edt,edt-ft5426",},{/* */}
};static struct i2c_driver tsc_driver = {.driver = {.owner = THIS_MODULE,.name = "edt_ft5x06",.of_match_table = of_match_ptr(ft5x06_of_match),},.id_table = ft5x06_ts_id,.probe = tsc_probe,.remove = tsc_remove,
};static int tsc_init(void)
{int ret = 0;ret = i2c_add_driver(&tsc_driver);return ret;
}static void tsc_exit(void)
{i2c_del_driver(&tsc_driver);
}module_init(tsc_init);
module_exit(tsc_exit);
MODULE_LICENSE("GPL");

DeviceDriver(十四):多点触摸(MT协议,Input子系统)相关推荐

  1. HCIP第十四天(MPLS协议)

    目录 MPLS(多协议标签交换) 包交换 标签交换 包交换的优化过程 MPLS(多协议标签交换) 包交换 数据组成数据包,在网络中的各个节点传递,最准到达目标,即路由转发的过程. 1.查两张表,即路由 ...

  2. CCNA笔记之第十四节:RIP协议(1)

    1. RIP:路由选择信息协议:(Routing Information Protocol) 1) Metric:跳数 (RIP只适合小网络,最大跳数16跳:第16跳不可达) 2) 管理距离值:(AD ...

  3. 【正点原子Linux连载】第六十四章 Linux 多点电容触摸屏实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  4. Linux 驱动开发 六十六:多点触控(MT)协议

    文档路径:Documentation\input\multi-touch-protocol.txt. 一.介绍 为了充分利用新的多点触摸和多用户设备的功能,需要一种从多个触摸点(即与设备表面直接接触的 ...

  5. linux input子系统 — TP A/B(Slot)协议【转】

    本文转载自:http://blog.csdn.net/u012719256/article/details/53609906 将A/B协议这部分单独拿出来说一方面是因为这部分内容是比较容易忽视的,周围 ...

  6. 多点触摸与单点触摸接口主要区别【转】

    转自:http://blog.csdn.net/eleven_yy/article/details/7723079 上发单点触摸事件 input_report_key(input,ABS_MT_TRA ...

  7. Linux Android 多点触摸协议 原文出自【比特网】,转载请保留原文链接:http://soft.chinabyte.com/os/71/12306571.shtml

    为了使用功能强大的多点触控设备,就需要一种方案去上报用户层所需的详细的手指触摸数据.这个文档所描述的多点触控协议可以让内核驱动程序向用户层上报任意多指的数据信息. 使用说明 单点触摸信息是以ABS承载 ...

  8. MTK 驱动(65)---Android 多点触摸协议(Multi-touch Protocol)

    Android 多点触摸协议(Multi-touch Protocol) Android 多点触摸协议Multi-touch Protocol A协议 B协议 代码编写 Protocol A Prot ...

  9. Linux 驱动开发 四十八:Linux INPUT 子系统实验

    一.input 子系统简介 input 就是输入的意思,因此 input 子系统就是管理输入的子系统,是 Linux 内核针对某一类设备而创建的框架. 比如按键输入.键盘.鼠标.触摸屏等等这些都属于输 ...

  10. Linux/Android多点触摸协议

    链接点击打开链接 关于Linux多点触摸协议大家可以参考kernel中的文档:https://www.kernel.org/doc/Documentation/input/multi-touch-pr ...

最新文章

  1. Solr索引和基本数据操作
  2. windows下利用sox批量将PCM转为WAV
  3. C#内建接口:IEnumerable
  4. Eclipse 使用 CodeMix 插件 开发 Vue.js
  5. mysql8 修改加密方式_mysql8修改密码加密方式
  6. nginx 日志配置_Nginx记录日志到systemd journal
  7. python中syntaxerror_【已解决】Python中两个星号**参数去传递给函数出错:SyntaxError invalid syntax...
  8. 写了一篇关于餐饮业陷入困境的文章
  9. linux、window中源码安装maven
  10. oracle wm_concat(column)函数的使用
  11. Autodesk Inventor探索——齿轮参数化建模
  12. 关于上采样方法总结(插值和深度学习)
  13. 指数分布的样本和是充分统计量
  14. 在excel中如何筛选重复数据_Excel数据筛选操作总结之数据透视表
  15. js中的强制类型转换和进制数表达
  16. IIS的配置和网站发布
  17. 软件公司的项目经理岗位职责
  18. Javascript学习笔记(13_2) --js事件案例(小人快跑)
  19. python 发送get 请求
  20. 【python】plt.cm.Spectral,颜色分配

热门文章

  1. 硬件电路学习之开尔文电桥双臂讲解
  2. Pytorch-IMDB电影评论情感分析
  3. 将Kali Linux中的Firefox浏览器语言设置为中文
  4. oracle 统计标准误差,标准偏差和标准误差的区别
  5. android+复制大文件,手机SD卡无法复制拷贝大文件的解决方法
  6. iOS 获取手机通信录(仿微信 支付宝 手机话费 流量充值效果)
  7. ThreadPoolExecutor线程池终止
  8. Python处理Excel数据分组
  9. BetaFlight模块设计之十一:GyroAcc任务分析
  10. 公开信息查询的一些方法,查征信,查婚姻状况,查询公开个人信息