您的位置:首页 > 运维架构 > Linux

ft5x0x驱动分析

2016-06-12 21:11 162 查看
硬件:TINY4412

软件:source insight 3.5

 

Tiny4412的触摸屏驱动是友善之臂已经写好的,为了学习并理解触摸屏驱动的框架,来分析下ft5x06_ts.c驱动文件。

在Linux系统中,触摸屏驱动的流程如下:

首先进行I2C设备的初始化,输入子系统设备的配置创建,中断、工作队列等的初始化,然后等待被触摸。如果有触摸事件,产生中断并调用中断处理函数,中断处理函数向工作队列提交一个任务(初始化时挂接好的工作函数),最后进入该工作函数(即中断的底半部)通过I2C读取触摸屏当前数据,通过input上报给系统。

 

 一、设备相关部分

触摸屏的设备板级信息在Mach-tiny4412.c该文件中:



需要注意的是这里的ifdef条件编译,在需要自己编写并实现触摸屏驱动时(不使用自带的驱动),就需要手动定义宏CONFIG_TOUCHSCREEN_FT5X0X,否则驱动匹配不到设备。同样,在ft5x0x_pdata结构体中,也有该宏,触摸屏的硬件参数如下:



二、驱动部分

下面从头开始分析驱动代码:驱动的入口函数module_init(),在驱动的最后位置:



1.接着看ft5x0x_ts_init()内部的内容:



该函数直接返回了调用函数i2c_add_driver(&ft5x0x_ts_driver),这个函数的作用就是将&ft5x0x_ts_driver注册到i2c_driver链表中,在每次注册完i2c_device或i2c_driver后,都会有一个匹配的过程,主要是通过名字匹配,如果匹配成功,则会调用i2c_driver的probe()函数。

2.i2c_driver驱动的定义

FT5X0X芯片可以利用I2C和SPI进行通信的触摸屏,tiny4412通过I2C来读取触摸屏的坐标等数据。Ft5x0x_ts_driver定义如下:



其中id_table表示i2c设备的name和data,i2c_driver和i2c_device的匹配规则就是根据id_table进行匹配的。ft5x0x_ts_id定义如下:





也就是说驱动与设备进行匹配的name为ft5x0x_ts。当驱动与设备匹配成功后,就会调用i2c_driver的probe()函数。

3.ft5x0x_ts_probe()函数

接下来一步步分析驱动中特别重要的函数probe(),在probe()函数中,首先定义了两个比较重要的结构体:



ft5x0x_i2c_platform_data结构体主要就是为了接受i2c_client中i2c_board_info传来的资源。ft5x0x_ts_data结构体主要是为了整合驱动所需要使用的所有资源,包括中断、屏幕参数、工作队列等。



4.接下来分析工作队列



(1)在老的内核中,这个宏是如此定义的#defineINIT_WORK(_work,_func,_data),第三个参数作为第二个参数的参数传递过去。但是在新的内核中INIT_WORK()宏的定义如下:



那怎么传递data呢?

该宏会在定义的work工作队列里面添加一个工作任务,该任务_func,主要用来处理中断。比如在中断里面要做很多的事情,但是比较耗时,这时就可以把耗时的工作放到工作队列,说白了就是系统延时调度的一个自定义函数。

例如在触摸屏驱动中INIT_WORK(&ts->work, ft5x0x_ts_pen_irq_work);就是初始化一个work,并绑定其处理函数。关于该函数的调度问题,后面讨论。

(2)create_singlethread_workqueue():创建工作者线程,等待CPU的调度,最后调用工作队列中的工作函数.

 (3) input_dev = input_allocate_device();输入子系统提供该接口函数在内存中分配一个设备结构体,并对其主要成员进行了初始化。

5.输入设备初始化



(1)    set_bit():告诉input输入子系统支持哪些事件

(2)    input_set_abs_params(struct input_dev *dev,int axis,int min,intmax,int fuzz,int flat);

参数依次为设备指针,坐标轴,最小值,最大值,分辨率,基准值

(3)    在输入设备初始化完后,再进行输入设备的注册:



输入设备的注册也是利用输入子系统提供的函数input_register_device()。注册input_device的过程就是为input_device设置默认值,并将其挂以input_dev_list,与链表在input_handler_list的handler相匹配,如果匹配成功,就会调用handler的connect函数。

6.最后再来分析触摸屏驱动的中断



通过调用request_irq()注册中断入口函数,注册中断后,马上关闭中断,待驱动配置好后再开启中断。

三、驱动流程



    1.首先,初始化工作:INIT_WORK()会将工作和工作函数绑定好,也就是ft5x0x_ts_pen_irq_work()函数为工作函数,之后通过调用create_singlethread_workqueue()来创建工作队列并在其内部分配好内核线程(利用内核线程不断地扫描工作队列中是否有等待的工作)。当屏幕被触摸时,产生中断并进入到中断处理函数ft5x0x_ts_interrupt(),如下:



在中断处理函数中,首先要关闭中断,但是不能用disable_irq()来关闭中断。由于disable_irq()中会调用synchronize_irq()函数等待中断返回,所以在中断处理程序中不能使用disable_irq,否则会导致CPU被synchronize_irq独占而发生系统崩溃。

关闭中断后,通过调用queue_work()把指定的工作交给指定的工作队列,然后等待安全的时候在执行工作队列中的工作函数,由内核线程负责完成。queue_work()类似于schedule_work(),区别在于queue_work()把指定的工作交给自己创建的工作队列而不是缺省队列。

2.当工作队列中的工作函数得到调度执行,就来到了中断的“下半部”处理,工作队列推后执行的任务------ft5x0x_ts_pen_irq_work()函数。



在“下半部”处理时,首先利用container_of求得ft5x0x_ts_data结构体的首地址。其中struct ft5x0x_ts_data *ts = container_of(work, structft5x0x_ts_data, work);这句的主要目的就是为了解决我们之前所说的data跑哪去了,在这里使用container_of宏来求出data的指针。然后调用ft5x0x_read_data()函数通过I2C读取触摸屏当前数据,该函数如下:


  





      首先根据是否支持多点触控选择不同的选项,调用ft5x0x_i2c_rxdata()函数获取触摸屏坐标,将坐标值记录在数组buf中:



在I2C通讯的时候,需要接收或者发送I2C数据时就调用了I2C核心提供的函数i2c_transfer(),该函数通常被封装成i2c_master_send()以及i2c_master_recv()。

i2c_transfer()函数本身也不具备驱动适配器物理硬件完成消息交互的能力,它只是寻找到i2c_adapter对应的i2c_algorithm,并使用i2c_algorithm的master_xfer()函数真正驱动硬件流程。如果支持多点触控,根据ft5x0x芯片手册来获取不同点的X、Y坐标值:









获取坐标值后,调用ft5x0x_ts_report()函数将获取到的事件以及坐标点等信息上报给输入子系统,在上报的过程中,需要特别注意的是上报结束的同步信号:



调用input_mt_sync()函数来声明一次数据的结束。由于多点触摸需要采集多个点,然后再一起处理这些点,所以在软件实现中需要保证每一波点的准确性和完整性,因此在每波点上报后需要紧跟一句input_mt_sync(),然后等所有点上报完成后在使用input_sync()进行同步,input_sync()用于事件同步,它告知事件的接收者:驱动已经发出了一个完整的报告。

四、总结

      触摸屏驱动用到的知识点比较多,也都比较复杂,中断机制、工作队列、输入子系统、I2C子系统等知识点。本篇文章只是简略的分析触摸屏驱动的工作流程,对于其中涉及到的知识点未做详细解释。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息