测试平台

宿主机平台:Ubuntu 12.04.4 LTS

目标机:Easy-ARM IMX283

目标机内核:Linux 2.6.35.3

触摸屏基础知识

一、结构

  上图是电阻触摸屏的一个侧面剖视图。手指触摸的表面是一个硬涂层,用以保护下面的PET层。PET层是很薄的有弹性的PET薄膜,当表面被触摸时它会向下弯曲,并使得下面的两层ITO涂层能够相互接触并在该点连通电路。两个ITO层之间是约千分之一英寸厚的一些隔离支点使两层分开。最下面是一个透明的硬底层用来支撑上面的结构,通常是玻璃或者塑料。
        电阻触摸屏的多层结构会导致很大的光损失,对于手持设备通常需要加大背光源来弥补透光性不好的问题,但这样也会增加电池的消耗。电阻式触摸屏的优点是它的屏和控制系统都比较便宜,反应灵敏度也很好。

二、触摸坐标的计算

   ITO陶瓷层分为了上下两层,中间用隔离支点分开,这两层是X层和Y层。可以看成如下结构:

当没有触摸按下时,X层和Y层是分离的,此时就测不到电压

其中X层上X-到X+和Y-到Y+的电阻是均匀分布的,其电路等效图如下:

1、计算Y坐标,在Y+电极施加驱动电压V,Y-接地,芯片通过X+测量接触点的电压。

由于ITO层均匀导电,触点电压与V电压之比等于触点Y坐标与屏高度之比。

y/height = Vx/Vdrv

y = (Vx/Vdrv) * height

2、计算X坐标,在X+电极施加驱动电压V, X-电极接地,Y+做为引出端测量得到接触点的电压,由于ITO层均匀导电,触点电压与Vdrive电压之比等于触点X坐标与屏宽度之比。

x = (Vy/Vdrv) * width

测得的电压通常由ADC转化为数字信号,再进行简单处理就可以做为坐标判断触点的实际位置。另外触点压力的计算在此不再赘述。

触摸屏驱动实现

Linux将触摸屏驱动放在输入子系统 input 中。

input子系统

接下来我们回顾以下 input 子系统。

Linux内核的输入子系统为鼠标、键盘、触摸屏、游戏杆等输入设备提供了驱动框架。当程序员要为自己的输入设备编写驱动程序时,只需要实现从设备获取输入事件即可。

linux输入子系统的体系结构可以分为三个层面,分别为:硬件驱动层、子系统核心层、事件处理层;

1)设备驱动层

在给输入设备编写驱动程序时,需要为输入设备实现一个设备驱动。设备驱动包含的设备信息有:

(1) 设备的总线类型、厂商、 产品、版本号、名称等身份信息;
(2) 设备可产生的事件类型;
(3) 各事件类型的分量。
当输入设备发生输入事件时,驱动程序要把输入事件向输入子系统报告。

2)事件管理层

分为事件类、 MOUSE 类、游戏杆类型,所 以内核源码为这三种类型的输入设备分别实现了 evdev 、 mousedev 、 joydev 事件管理器。

3)核心层,即 drivers/input/input.c 起着桥梁的作用。

下面我们来剖析触摸屏驱动实现过程

触摸屏驱动分析

1 触摸屏 平台设备注册

板级文件中实现平台设备的注册、平台设备资源、平台设备私有数据

#if defined(CONFIG_TOUCHSCREEN_MXS) || defined(CONFIG_TOUCHSCREEN_MXS_MODULE)
// 平台设备私有数据(adc相关参数)
static struct mxs_touchscreen_plat_data mx28_ts_data = {
.x_plus_chan = LRADC_TOUCH_X_PLUS,
.x_minus_chan = LRADC_TOUCH_X_MINUS,
.y_plus_chan = LRADC_TOUCH_Y_PLUS,
.y_minus_chan = LRADC_TOUCH_Y_MINUS,
.x_plus_val = BM_LRADC_CTRL0_XPULSW,
.x_minus_val = BF_LRADC_CTRL0_XNURSW(2),
.y_plus_val = BF_LRADC_CTRL0_YPLLSW(1),
.y_minus_val = BM_LRADC_CTRL0_YNLRSW,
.x_plus_mask = BM_LRADC_CTRL0_XPULSW,
.x_minus_mask = BM_LRADC_CTRL0_XNURSW,
.y_plus_mask = BM_LRADC_CTRL0_YPLLSW,
.y_minus_mask = BM_LRADC_CTRL0_YNLRSW,
}; // 平台设备资源(寻址地址空间、中断等资源)
static struct resource mx28_ts_res[] = {
{
.flags = IORESOURCE_MEM,
.start = LRADC_PHYS_ADDR,
.end = LRADC_PHYS_ADDR + 0x2000 - 1,
},
{
.flags = IORESOURCE_IRQ,
.start = IRQ_LRADC_TOUCH,
.end = IRQ_LRADC_TOUCH,
},
{
.flags = IORESOURCE_IRQ,
.start = IRQ_LRADC_CH5,
.end = IRQ_LRADC_CH5,
},
}; static void __init mx28_init_ts(void)
{
struct platform_device *pdev; pdev = mxs_get_device("mxs-ts", 0); //获取"mxs-ts"设备
if (pdev == NULL || IS_ERR(pdev))
return;
pdev->resource = mx28_ts_res;
pdev->num_resources = ARRAY_SIZE(mx28_ts_res);
pdev->dev.platform_data = &mx28_ts_data;
mxs_add_device(pdev, 3); //添加到注册设备列表
}
#else
static void __init mx28_init_ts(void)
{
;
}
#endif

2 触摸屏 平台驱动注册

开发板的触摸驱动位置 drivers\input\touchscreen\mxs-ts.c

static struct platform_driver mxs_ts_driver = {
.probe = mxs_ts_probe,
.remove = __devexit_p(mxs_ts_remove),
#ifdef CONFIG_PM
.suspend = mxs_ts_suspend,
.resume = mxs_ts_resume,
#endif
.driver = {
.name = "mxs-ts",
},
}; static int __init mxs_ts_init(void)
{
return platform_driver_register(&mxs_ts_driver); //平台驱动注册,"mxs-ts"匹配触发 mxs_ts_probe
}

驱动安装时触发平台驱动注册,与平台设备 "mxs-ts" 匹配后触发 mxs_ts_probe函数

mxs_ts_probe 主要实现:

1.通过传递的平台设备私有数据来设置 input设备驱动参数,然后通过 input_register_device 注册该触摸设备;

2.获取平台设备资源,配置 lradc 及其中断;

request_irq(info->touch_irq, ts_handler, IRQF_DISABLED, "mxs_ts_touch", info);

当外部触摸时,触发 adc 中断,进入 ts_handler 中断函数,读取对应的 adc 值,然后通过上报给事件管理器

input_report_abs(info->idev, ABS_Y, info->x); //info->x 反应y方向的变化
input_report_abs(info->idev, ABS_X, info->y);
input_report_abs(info->idev, ABS_PRESSURE, pressure);
input_sync(info->idev);

3. input 驱动机制浅析

1 首先时 input 子系统初始化时的字符设备注册 (\drivers\input\input.c),这样就有了 dev/input 主设备

static int __init input_init(void)
{
int err; input_init_abs_bypass(); err = class_register(&input_class);
if (err) {
printk(KERN_ERR "input: unable to register input_dev class\n");
return err;
} err = input_proc_init();
if (err)
goto fail1; err = register_chrdev(INPUT_MAJOR, "input", &input_fops); //创建主设备号为13的"input"字符设备
if (err) {
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
goto fail2;
} return 0; fail2: input_proc_exit();
fail1: class_unregister(&input_class);
return err;
}

下面来分析 input_register_handle 和 input_register_device

其中 input_register_device 由设备驱动调用,生成子设备

input_register_handle 由事件管理器调用

在 input_register_device 中

list_add_tail(&dev->node, &input_dev_list);    //将这个dev放到input_dev_list链表中 
list_for_each_entry(handler, &input_handler_list, node) 
  input_attach_handler(dev, handler);

list_for_each_entry()函数会将每个input_handle从链表中取出,放到handler中,最后会调用input_attach_handler()函数,将每个input_handle的id_table进行判断,若两者支持便进行连接。

在 input_register_handle 中

list_add_tail(&handler->node, &input_handler_list);  //将这个input_handler放到input_handler_list链表中
list_for_each_entry(dev, &input_dev_list, node) 
  input_attach_handler(dev, handler);

list_for_each_entry()函数会将每个dev从链表中取出,放到dev中,最后会调用input_attach_handler()函数,将每个dev与handle的id_table进行判断,若两者支持便进行连接。

触摸的事件管理器实现是 evdev.c

evdev驱动模块支持时,就会

static int __init evdev_init(void)
{
    return input_register_handler(&evdev_handler);
}
 
evdev_connect()函数,对

input_attach_handler()函数先看是否匹配 input_match_device(handler, dev); //匹配两者

然后调用 handler->connect(handler, dev, id); 进行连接

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int error; id = input_match_device(handler, dev); //匹配两者
if (!id)
return -ENODEV; error = handler->connect(handler, dev, id);
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error); return error;
}

如下图所示,开发板使用的是4线电阻触摸屏,该4线连接在ADC引脚上,该引脚专门是用来接收模拟输入信号.

Linux触摸驱动分析的更多相关文章

  1. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

  2. Linux spi驱动分析(二)----SPI核心(bus、device_driver和device)

    一.spi总线注册 这里所说的SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void).程序如下: 点击(此处 ...

  3. Linux I2C驱动分析(三)----i2c_dev驱动和应用层分析 【转】

    本文转载自:http://blog.chinaunix.net/uid-21558711-id-3959287.html 分类: LINUX 原文地址:Linux I2C驱动分析(三)----i2c_ ...

  4. 基于335X的Linux网口驱动分析

    基于335X的linux网口驱动分析 一. 系统构成 1.  硬件平台 AM335X 2.  LINUX内核版本 4.4.12 二. 网口驱动构架(mdio部分) mdio网口驱动部分 使用 总线.设 ...

  5. linux驱动基础系列--Linux I2c驱动分析

    前言 主要是想对Linux I2c驱动框架有一个整体的把控,因此会忽略协议上的某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型.sysfs等也不进行详细说明原理,涉及到i2c协议部分也只 ...

  6. Linux gadget驱动分析1------驱动加载过程

    为了解决一个问题,简单看了一遍linux gadget驱动的加载流程.做一下记录. 使用的内核为linux 2.6.35 硬件为芯唐NUC950. gadget是在UDC驱动上面的一层,如果要编写ga ...

  7. Linux UART驱动分析

    1. 介绍 8250是IBM PC及兼容机使用的一种串口芯片; 16550是一种带先进先出(FIFO)功能的8250系列串口芯片; 16550A则是16550的升级版本, 修复了FIFO相关BUG, ...

  8. linux gsensor驱动分析【转】

    本文转载自:http://blog.sina.com.cn/s/blog_89f592f501013sr2.html 本文以Bma250驱动为例子,详细介绍Gsensor设计的一个模板. gsenso ...

  9. linux串口驱动分析——发送数据

    一.应用程序中write函数到底层驱动历程 和前文提到的一样,首先先注册串口,使用uart_register_driver函数,依次分别为tty_register_driver,cdev_init函数 ...

随机推荐

  1. QT常用控件(一)——菜单栏和对话框

    引言 QMainWindow 是一个为用户提供主窗口程序的类,包含一个菜单栏(menu bar).多个工具栏(tool bars).多个锚接部件(dock widgets).一个状态栏(status ...

  2. C++动态内存管理与源码剖析

    引言 在本篇文章中,我们主要剖析c++中的动态内存管理,包括malloc.new expression.operator new.array new和allocator内存分配方法以及对应的内存释放方 ...

  3. web浏览器知识点

    网页是怎么形成的 前端的代码(英文字母)---->浏览器渲染 ------- >  客户眼中的效果 浏览器(显示代码) 游览器是网页显示,运行的平台,常用的的游览器有IE(Edge).火狐 ...

  4. CCS box-flex属性

    box-flex==按比例分配父标签的宽度or高度空间 1.非固定分配 eg.一块地总150平方分配给三孩子,按照2:1:1分 #老大 { 房子-分配: 2; } = 75平 #老二 { 房子-分配: ...

  5. UE4点选源码分析

    在UE插件开发中,时常会用到场景预览窗口的功能,也经常会有点选场景里的物体而同步改变工具界面的需求,网上教程多为讲解如何打开一个预览界面.在最近的一次需求开发中,我粗读了关卡编辑器和蓝图编辑器的Vie ...

  6. 【python与机器学习实战】感知机和支持向量机学习笔记(一)

    对<Python与机器学习实战>一书阅读的记录,对于一些难以理解的地方查阅了资料辅以理解并补充和记录,重新梳理一下感知机和SVM的算法原理,加深记忆. 1.感知机 感知机的基本概念 感知机 ...

  7. 5年Android开发诉苦:47天21家面试,半年空档期觉得整个人生都被毁了

    近日,我在逛某社交论坛时,发现一位做了五年的Android开发将自己这段时间的所有面试经历发表了出来,根据网友自己提供的信息显示,主要面试的地点都在北京,上海等地. 微软和亚马逊刚面试完一面,都是以算 ...

  8. gRPC学习之三:初试GO版gRPC开发

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. RabbitMQ的生产者消息确认(Publisher Confirms and Returns)和消费者ACK

    https://www.cnblogs.com/wangzhongqiu/p/7815529.html https://blog.csdn.net/u012129558/article/details ...

  10. Linux 多进程编程实例(一)

    文章目录 目标: main.c process1.c process2.c 目标: 一个进程,创建两个子进程,利用exec函数族使两个子进程执行不同的程序.子进程1执行ls -l命令后正常返回,子进程 ...