ft5x0x驅動分析

硬件: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子系統等知識點。本篇文章只是簡略的分析觸摸屏驅動的工作流程,對於其中涉及到的知識點未做詳細解釋。

發佈了32 篇原創文章 · 獲贊 35 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章