android 电容屏(二):驱动调试之基本概念篇

关键词:android  电容屏 tp 工作队列 中断 多点触摸协议
平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0 
平台:S5PV310(samsung exynos 4210) 

作者:xubin341719(欢迎转载,请注明作者)

参考网站:http://edsionte.com/techblog/archives/1582
这部分参考别人的多一点

android 电容屏(一):电容屏基本原理篇

android 电容屏(二):驱动调试之基本概念篇

android 电容屏(三):驱动调试之驱动程序分析篇

电容屏驱动调试先了解Linux电容屏驱动中几个常用的概念:
              中断下半部-工作队列;
              input机制;
              Linux与Android 多点触摸协议。

 

一、中断下半部-工作队列

1、中断

先看一下宋宝华先生的《linux设备驱动开发详解》里面对中断的描述吧。这本书个人感觉 写的比较好,从开始学驱动到现在,还能从中得到不少知识。

设备的中断会打断内核中进程的正常调度和运行,系统对更高吞吐率的追求势必要求中断服务程序尽可能地短小精悍。但是,这个良好的愿望往往与现实并不吻合。在大多数真实的系统中,当中断到来时,要完成的工作往往并不会是短小的,它可能要进行较大量的耗时处理。如下图描述了Linux内核的中断处理机制。为了在中断执行时间尽可能短和中断处理需完成大量工作之间找到一个平衡点,Linux将中断处理程序分解为两个半部:顶半部(top  half)和底半部(bottom half)。顶半部完成尽可能少的比较紧急的功能,它往往只是简单地读取寄存器中的中断状态并清除中断标志后就进行“登记中断”的工作。“登记中断”意味着将底半部处理程序挂到该设备的底半部执行队列中去。这样,顶半部执行的速度就会很快,可以服务更多的中断请求。现在,中断处理工作的重心就落在了底半部的头上,它来完成中断事件的绝大多数任务。底半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断,这也是底半部和顶半部的最大不同,因为顶半部往往被设计成不可中断。底半部则相对来说并不是非常紧急的,而且相对比较耗时,不在硬件中断服务程序中执行。尽管顶半部、底半部的结合能够改善系统的响应能力,但是,僵化地认为Linux设备驱动中的中断处理一定要分两个半部则是不对的。如果中断要处理的工作本身很少,则完全可以直接在顶半部全部完成。

其实上面这一段大致说明一个问题,那就是:中断要尽可能耗时比较短,尽快恢复系统正常调试,所以把中断触发、中断执行分开,也就是所说的“上半部分(中断触发)、底半部(中断执行)”,其实就是我们后面说的中断上下文。下半部分一般有tasklet、工作队列实现,触摸屏中中断实现以工作队列形式实现的,所以我们今天重点讲工作队列。

2、为什么还需要工作队列?

工作队列(work queue)是另外一种将中断的部分工作推后的一种方式,它可以实现一些tasklet不能实现的工作,比如工作队列机制可以睡眠。这种差异的本质原因是,在工作队列机制中,将推后的工作交给一个称之为工作者线程(worker thread)的内核线程去完成(单核下一般会交给默认的线程events/0)。因此,在该机制中,当内核在执行中断的剩余工作时就处在进程上下文(process context)中。也就是说由工作队列所执行的中断代码会表现出进程的一些特性,最典型的就是可以重新调度甚至睡眠。

对于tasklet机制(中断处理程序也是如此),内核在执行时处于中断上下文(interrupt context)中。而中断上下文与进程毫无瓜葛,所以在中断上下文中就不能睡眠。因此,选择tasklet还是工作队列来完成下半部分应该不难选择。当推后的那部分中断程序需要睡眠时,工作队列毫无疑问是你的最佳选择;否则,还是用tasklet吧。

3、中断上下文

有上面那个图可以看出上下两部分吧,就是上下文吧,这个比较好理解。

看下别人比较专业的解释:

在了解中断上下文时,先来回顾另一个熟悉概念:进程上下文(这个中文翻译真的不是很好理解,用“环境”比它好很多)。一般的进程运行在用户态,如果这个进程进行了系统调用,那么此时用户空间中的程序就进入了内核空间,并且称内核代表该进程运行于内核空间中。由于用户空间和内核空间具有不同的地址映射,并且用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行。这样就产生了进程上下文。

所谓的进程上下文,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容。当内核需要切换到另一个进程时(上下文切换),它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态继续执行。上述所说的工作队列所要做的工作都交给工作者线程来处理,因此它可以表现出进程的一些特性,比如说可以睡眠等。              对于中断而言,是硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理,中断上下文就可以理解为硬件传递过来的这些参数和内核需要保存的一些环境,主要是被中断的进程的环境。因此处于中断上下文的tasklet不会有睡眠这样的特性。

4、工作队列的使用方法

内核中通过下述结构体来表示一个具体的工作:

[cpp] view plaincopy

  1. struct work_struct
  2. {
  3. unsigned long pending;//这个工作是否正在等待处理
  4. struct list_head entry;//链接所有工作的链表,形成工作队列
  5. void (*func)(void *);//处理函数
  6. void *data;//传递给处理函数的参数
  7. void *wq_data;//内部使用数据
  8. struct timer_list timer;//延迟的工作队列所用到的定时器
  9. };

而这些工作(结构体)链接成的链表就是所谓的工作队列。工作者线程会在被唤醒时执行链表上的所有工作,当一个工作被执行完毕后,相应的work_struct结构体也会被删除。当这个工作链表上没有工作时,工作线程就会休眠。

(1)、通过如下宏可以创建一个要推后的完成的工作:

[cpp] view plaincopy

  1. DECLARE_WORK(name,void(*func)(void*),void*data);

(2)、也可以通过下述宏动态创建一个工作:

[cpp] view plaincopy

  1. INIT_WORK(struct work_struct*work,void(*func)(void*),void *data);

与tasklet类似,每个工作都有具体的工作队列处理函数,原型如下:

[cpp] view plaincopy

  1. void work_handler(void *data)

将工作队列机制对应到具体的中断程序中,即那些被推后的工作将会在func所指向的那个工作队列处理函数中被执行。

(3)、实现了工作队列处理函数后,就需要schedule_work函数对这个工作进行调度,就像这样:

[cpp] view plaincopy

  1. schedule_work(&work);

这样work会马上就被调度,一旦工作线程被唤醒,这个工作就会被执行(因为其所在工作队列会被执行)。

二、input子系统概述 可见文章基于 mini2440 电阻式触摸屏(三):Linux输入子系统(InputSubsystem)

按键、鼠标、触摸屏、电池信息等,都是通过input子系统上报。

三、Linux与Android 多点触摸协议

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

1、使用说明

单点触摸信息是以ABS承载并按一定顺序发送,如BTN_TOUCH、ABS_X、ABS_Y、SYNC。而多点触摸信息则是以ABS_MT承载并按一定顺序发送,如ABS_MT_POSITION_X、ABS_MT_POSITION_Y,然后通过调用input_mt_sync()产生一个 SYN_MT_REPORT event来标记一个点的结束,告诉接收方接收当前手指的信息并准备接收其它手指的触控信息。最后调用 input_sync()函数上报触摸信息开始动作并告诉接收方开始接收下一系列多点触摸信息。

协议定义了一系列ABS_MT事件,这些事件被分为几大类,充许只应用其中的一部份,多点触摸最小的事件集中应包括ABS_MT_TOUCH_MAJOR、ABS_MT_POSITION_X和 ABS_MT_POSITION_Y,以此来实现多点触摸。如果设备支持ABS_MT_WIDTH_MAJOR这个事件,那么此事件可以提供手指触摸接触面积大小。触摸方向等信息可以由ABS_MT_TOUCH_MINOR, ABS_MT_WIDTH_MINOR and ABS_MT_ORIENTATION提供。ABS_MT_TOOL_TYPE提供触摸设备的类别,如手或是笔或是其它。最后有些设备可能会支持ABS_MT_TRACKING_ID,用来支持硬件跟踪多点信息,即该点属于哪一条线等。

[cpp] view plaincopy

  1. 下面是两点触摸支持的最小事件集序列:
  2. ABS_MT_TOUCH_MAJOR
  3. ABS_MT_POSITION_X
  4. ABS_MT_POSITION_Y
  5. SYN_MT_REPORT //上报第一个点
  6. ABS_MT_TOUCH_MAJOR
  7. ABS_MT_POSITION_X
  8. ABS_MT_POSITION_Y
  9. SYN_MT_REPORT //上报第二个点
  10. ………… //完成多点上报
  11. SYN_REPORT //开始动作

2、Event原语

接触”一词用来描述一个物体直接碰到另一个物体的表面。

ABS_MT_TOUCH_MAJOR描述了主接触面的长轴,它和X,Y同一个单位,如果一个面的分辨率为X*Y,则ABS_MT_TOUCH_MAJOR的最大值为sqrt(X^2+Y^2)

[cpp] view plaincopy

  1. <span style="white-space:pre">  </span>ABS_MT_TOUCH_MINOR描述了接触面的短轴,如果接触面是圆形,它可以不用。
  2. ABS_MT_WIDTH_MAJOR描述了接触工具的长轴
  3. ABS_MT_WIDTH_MINOR描述了接触工具的短轴
  4. ABS_MT_TOUCH_MAJOR := max(X, Y)
  5. ABS_MT_TOUCH_MINOR := min(X, Y)
  6. ABS_MT_ORIENTATION := bool(X > Y)

以上四个参数可以用来生成额外的触摸信息,ABS_MT_TOUCH_MAJOR/ABS_MT_WIDTH_MAJOR的比率可以用来描述压力。

ABS_MT_ORIENTATION

ABS_MT_POSITION_X接触面的中心点X坐标

ABS_MT_POSITION_Y接触面的中心点Y坐标

ABS_MT_TOOL_TYPE描述接触工具类型,很多内核驱动无法区分此参数如手指及笔,如果是这样,该参数可以不用,协议目前支持MT_TOOL_FINGER和MT_TOOL_PEN两种类型。

ABS_MT_BLOB_ID形状集ID,集合几个点以描述一个形状,很多驱动没有形状属性,此参数可以不用。ABS_MT_TRACKING_ID描述了从接触开始到释放的整个过程的集合,如果设备不支持,此参数可是不用。

3、触摸轨迹

仅有少数设备可以明触的标识真实的 trackingID,多数情况下 trackingID只能来标识一次触摸动作的过程。

4、手势

多点触摸指定的应用是创建手势动作, TOUCH和 WIDTH参数经常用来区别手指的压力和手指间的距离,另外 MINOR类的参数可以用来区别设备的接触面的大小(点接触还是面接触),ORIENTATION可以产生旋转事件。

5、在Linux内核支持的基础上,Android在其2.0源码中加入多点触摸功能(android4.0中间层有所不同)

由此触摸屏在Android的frameworks被完全分为2种实现途径:单点触摸屏的单点方式,多点触摸屏的单点和多点方式。

在Linux的input.h中,多点触摸功能依赖于以下几个主要的软件位:

[cpp] view plaincopy

  1. ……
  2. #define SYN_REPORT0
  3. #define SYN_CONFIG1
  4. #define SYN_MT_REPORT2
  5. ……
  6. #define ABS_MT_TOUCH_MAJOR0x30
  7. #define ABS_MT_TOUCH_MINOR0x31
  8. #define ABS_MT_WIDTH_MAJOR0x32
  9. #define ABS_MT_WIDTH_MINOR0x33
  10. #define ABS_MT_ORIENTATION0x34
  11. #define ABS_MT_POSITION_X0x35
  12. #define ABS_MT_POSITION_Y0x36
  13. #define ABS_MT_TOOL_TYPE0x37
  14. #define ABS_MT_BLOB_ID0x38
  15. ……

在Android中对应的软件位定义在RawInputEvent.java中:

[cpp] view plaincopy

  1. ……
  2. public class RawInputEvent {
  3. ……
  4. public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
  5. ……
  6. public static final int ABS_MT_TOUCH_MAJOR = 0x30;
  7. public static final int ABS_MT_TOUCH_MINOR = 0x31;
  8. public static final int ABS_MT_WIDTH_MAJOR = 0x32;
  9. public static final int ABS_MT_WIDTH_MINOR = 0x33;
  10. public static final int ABS_MT_ORIENTATION = 0x34;
  11. public static final int ABS_MT_POSITION_X = 0x35;
  12. public static final int ABS_MT_POSITION_Y = 0x36;
  13. public static final int ABS_MT_TOOL_TYPE = 0x37;
  14. public static final int ABS_MT_BLOB_ID = 0x38;
  15. ……
  16. public static final int SYN_REPORT = 0;
  17. public static final int SYN_CONFIG = 1;
  18. public static final int SYN_MT_REPORT = 2;
  19. ……

在Android中,多点触摸的实现方法在具体的代码实现中和单点是完全区分开的。在Android代码的EventHub.cpp中,单点屏和多点屏由如下代码段来判定:

[cpp] view plaincopy

  1. int EventHub::open_device(const char *deviceName)
  2. {
  3. ……
  4. if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
  5. && test_bit(ABS_MT_POSITION_X, abs_bitmask)
  6. && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
  7. device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;
  8. //LOGI("It is a multi-touch screen!");
  9. }
  10. //single-touch?
  11. else if (test_bit(BTN_TOUCH, key_bitmask)
  12. && test_bit(ABS_X, abs_bitmask)
  13. && test_bit(ABS_Y, abs_bitmask)) {
  14. device->classes |= CLASS_TOUCHSCREEN;
  15. //LOGI("It is a single-touch screen!");
  16. }
  17. ……
  18. }

我们知道,在触摸屏驱动中,通常在probe函数中会调用input_set_abs_params给设备的input_dev结构体初始化,这些input_dev的参数会在Android的EventHub.cpp中被读取。如上可知,如果我们的触摸屏想被当成多点屏被处理,只需要在驱动中给input_dev额外增加以下几个参数即可:

[cpp] view plaincopy

  1. input_set_abs_params(mcs_data.input, ABS_MT_POSITION_X, pdata->abs_x_min, pdata->abs_x_max, 0, 0);
  2. input_set_abs_params(mcs_data.input, ABS_MT_POSITION_Y, pdata->abs_y_min, pdata->abs_y_max, 0, 0);
  3. input_set_abs_params(mcs_data.input, ABS_MT_TOUCH_MAJOR, 0, 15, 0, 0);//相当于单点屏的ABX_PRESSURE
  4. input_set_abs_params(mcs_data.input, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0);//相当于单点屏的ABS_TOOL_WIDTH

由于多点触摸技术需要采集到多个点,然后再一起处理这些点,所以在软件实现中需要保证每一波点的准确性和完整性。因此,Linux内核提供了input_mt_sync(struct input_dev * input)函数。在每波的每个点上报后需要紧跟一句input_mt_sync(),当这波所有点上报后再使用input_sync()进行同步。

[cpp] view plaincopy

    1. 例如一波要上报3个点:
    2. ……
    3. input_mt_sync(input);
    4. ……
    5. input_mt_sync(input);
    6. ……
    7. input_mt_sync(input);
    8. input_sync(input);
    9. 注:即使是仅上报一个点的单点事件,也需要一次input_mt_sync。<span style="font-family:Arial, Helvetica, sans-serif;"><span style="white-space: normal;">
    10. </span></span>

android 电容屏(二):驱动调试之基本概念篇

时间: 2024-10-11 01:47:11

android 电容屏(二):驱动调试之基本概念篇的相关文章

android 电容屏(一):电容屏基本原理篇

关键词:android  电容屏 tp  ITO 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV310(samsung exynos 4210)  作者:xubin341719(欢迎转载,请注明作者) android 电容屏(一):电容屏基本原理篇 android 电容屏(二):驱动调试之基本概念篇 android 电容屏(三):驱动调试之驱动程序分析篇 一.电容屏工作原理 触摸屏的工作原理概括来说就是上报坐标值,X轴.Y轴的值.前面

android 电容屏(三):驱动调试之驱动程序分析篇

平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博客:http://weibo.com/cpjphone   以goodix的gt8105为例 一.总体架构 硬件部分:先看一个总体的图吧,其实触摸屏原理也比较简单,触摸屏和主控芯片间的联系,如下主要有三部分: 1.IIC部分,初始化gt8105的数据和传回主控制的坐标位置信息就是通过IIC这条线传输

android 电容屏(四):驱动调试之驱动程序分析篇 -- FocalTech

本人用的触摸屏IC是FocalTech公司的ft5306,是一款i2c的电容屏多点触控芯片.对于它的整体驱动官方已经给了,我们就触摸屏和按键部分的代码做相关说明.说明其中应该注意的地方. 对于所有的input设备,报告input事件时候都分这么几部分,首先在probe文件中设置设备发送的事件类型.按键类型.设置设备一些属性信息.然后在发送事件时候要根据probe的设置来发送事件,否则就会被判为无效忽略掉. 一.触摸屏部分 1.设备配置 对于触摸屏,必须支持的事件类型有以下这么三个: __set_

LCD屏背光驱动调试心得---血的教训

开发板:明远智睿MY-IMX6-EK140 内核源码:linux-3.14.52 背光驱动IC:MP3202 调光原理:通过开发板的核心板PWM4引脚控制MP3202的EN脚,输出不同的占空比从而达到输出平均电流的不同,这样就可以达到调节背光亮度的目的 调试过程: 1.从硬件图可以看出核心板的PWM4引脚连接到了背光驱动IC MP3202的EN脚,所以我们通过搜索PWM4来找设备树上的硬件节点 2.在明远智睿MY-IMX6-EK140设备树,arch/arm/boot/dts/myimx6ek1

【转】 Android BCM4330 蓝牙BT驱动调试记录

原文网址:http://blog.csdn.net/dwyane_zhang/article/details/7180779 网上关于BT的驱动很少,所以我在开发过程中把其中的步骤记录下来.供大家相互学习讨论. 一.关于BT driver的移植: 1. Enablebluetootch in BoadConfig.mk BOARD_HAVE_BLUETOOTH := true 2.实现BT电源管理rfkill驱动. Kernel/driver/bluetooth/bluetooth-power.

基于GPL329xx linux平台电容屏gsl1680的驱动调试分析

因客户有用到了gsl1680 7寸电容屏,所以拿了一块过来,便在329xx的平台上面开始调试了. 大概浏览了一下所提供的资料,只有介绍模组的资料跟一份中文版的datasheet,datasheet只是说了个大概,没有提到读取触摸坐标的寄存器.不过还好有给一份在其他处理器平台的驱动,所以读取坐标的部分代码移植过来就可以了. gsl1680接口跟其他的电容屏一样,也是i2c接口的,貌似市面上的电容屏都是i2c接口,电容屏自带了微控制器MCU,用与处理采样,坐标转换等,还有一些抖动算法处理,完后将坐标

电容屏驱动技术

目录 一  电容屏介绍 二  input输入子系统 三  mtk ctp 软件控制流程 四  mtk平台调试ctp需要修改的地方 一.电容屏介绍介绍 1.电容式触摸屏的类型主要有两种: (1)表面电容式: 表面电容式利用位于四个角落的传感器以及均匀分布整个表面的薄膜,有一个普通的ITO层和一个金属边框,当一根手 指触摸屏幕时,从板面上放出电荷,感应在触屏的四角完成,不需要复杂的ITO图案: (2)投射式电容: 采用一个或多个精心设计,被蚀烛的ITO,这些 ITO层通过蛀蚀形成多个水平和垂直电极,

i.mx6 lvds接口的DE模式液晶屏驱动调试

我这篇文章主要讲述i.mx6 平台下 采用DE模式的lvds液晶屏的驱动调试, 阅读该文章之前请先阅读如下两篇我转载的文章,这两篇文章是理解我这篇文章的基础知识. 1.        lcd fb参数如何计算: http://blog.csdn.net/liuhuahan/article/details/43447657 2.        camera_lcd之DE和HV模式区别 http://blog.csdn.net/liuhuahan/article/details/43489269 详

【驱动】TP电容屏驱动—3.TP报点协议A/B

USB多点触控上报协议详解USB HID-compliant mouse报点协议解析 本篇文章主要是对usb 多点触控给Windows上报点位时上报的数据解析.至于usb怎样枚举出一个多点触控在这不做解释,网上有很多教程.1.当你的usb hid设备枚举正常后,你可以使用bus hound看到你的usb 设备里有一个新增的HID-compliant mouse接口.可以通过usbTreeView查看对应的端点,我这里的该接口对应的是端点1.所以上报触摸点时,通过端点1上报就好. 2.window