国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

迅為IMX6ULL開發板Linux下電容觸摸屏實驗-驅動框架

發布時間:2020-11-27 10:00    發布者:就是塔塔
如今觸摸屏的使用越來越廣泛,從手機、平板到蜂巢取貨等場合,都是用了觸摸屏,觸摸屏的使用非常便捷高效。在本章就來學習一下如何在 Linux 下編寫電容觸摸屏驅動。
54.1 Linux  下電容觸摸屏驅動框架
54.1.1  多點觸摸協議詳解

在前面的裸板實驗中,已經詳細講解過了電容觸摸驅動的基本原理,根據前面的實驗可以總結出電容觸摸屏驅動其實就是一下幾種 linux 驅動框架的組合:
① IIC 設備驅動,因為電容觸摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 設備驅動。
② 通過中斷引腳(INT)向 linux 內核上報觸摸信息,因此需要用到 linux 中斷驅動框架。坐標的上報在中斷服務函數中完成。
③ 觸摸屏的坐標信息、屏幕按下和抬起信息都屬于 linux 的 input 子系統,因此向 linux 內核上報觸摸屏坐標信息就得使用 input 子系統。只是,我們得按照 linux 內核規定的規則來上報坐標信息。
在上面的驅動框架組合中我們發現 I2C 驅動、中斷驅動、input 子系統都已經學習了解過了,還沒有學習過 input 子系統下的多點電容觸摸協議,這個就是本章學習的重點,linux 內核中有一份文檔詳細的講解了多點電容觸摸屏協議,文檔路徑為:Documentation/input/multitouch-protocol.txt。
MT 協議被分為兩種類型,TypeA 和 TypeB,這兩種類型的區別如下:
TypeA:適用于觸摸點不能被區分或者追蹤,此類型的設備上報原始數據(此類型在實際使用中非常少!)。
Type B:適用于有硬件追蹤并能區分觸摸點的觸摸設備,此類型設備通過 slot 更新某一個觸摸點的信息,FT5426 就屬于此類型,一般的多點電容觸摸屏 IC 都有此能力。
觸摸點的信息通過一系列的 ABS_MT 事件(有的資料也叫消息)上報給 linux 內核,只有 ABS_MT 事件是用于多點觸摸的,ABS_MT 事件定義在文件 linux/input.h 中,相關事件如下所示:
852 #define ABS_MT_SLOT 0x2f /* MT slot being modified */
853 #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
854 #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
855 #define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
856 #define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
857 #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
858 #define ABS_MT_POSITION_X 0x35 /* Center X touch position */
859 #define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
860 #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
861 #define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
862 #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
863 #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
864 #define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
865 #define ABS_MT_TOOL_X 0x3c /* Center X tool position */
866 #define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
在上面這些眾多的 ABS_MT 事件中,我們最常用的就是 ABS_MT_SLOT 、 ABS_MT_POSITION_X 、ABS_MT_POSITION_Y 和 ABS_MT_TRACKING_ID 。其中 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 用來上報觸摸點的 (X,Y) 坐標信息,ABS_MT_SLOT 用來上報觸摸點 ID ,對于 Type B 類型的設備,需要用到ABS_MT_TRACKING_ID 事件來區分觸摸點。
對于 TypeA 類型的設備,通過 input_mt_sync()函數來隔離不同的觸摸點數據信息,此函數原型如下所示:
void input_mt_sync(struct input_dev *dev)
此函數只要一個參數,類型為 input_dev,用于指定具體的 input_dev 設備。input_mt_sync()函數會觸發 SYN_MT_REPORT 事件,此事件會通知接收者獲取當前觸摸數據,并且準備接收下一個觸摸點數據。
對于 Type B 類型的設備,上報觸摸點信息的時候需要通過 input_mt_slot()函數區分是哪一個觸摸點,input_mt_slot()函數原型如下所示:
void input_mt_slot(struct input_dev *dev, int slot)
此函數有兩個參數,第一個參數是 input_dev 設備,第二個參數 slot 用于指定當前上報的是哪個觸摸點信息。input_mt_slot()函數會觸發 ABS_MT_SLOT 事件,此事件會告訴接收者當前正在更新的是哪個觸摸點(slot)的數據。
不管是哪個類型的設備,最終都要調用 input_sync()函數來標識多點觸摸信息傳輸完成,告訴接收者處理之前累計的所有消息,并且準備好下一次接收。Type B 和 Type A 相比最大的區別就是 Type B 可以區分出觸摸點, 因此可以減少發送到用戶空間的數據。Type B 使用 slot 協議區分具體的觸摸點,slot 需要用
到 ABS_MT_TRACKING_ID 消息,這個 ID 需要硬件提供,或者通過原始數據計算出來。對于 TypeA 設備,內核驅動需要一次性將觸摸屏上所有的觸摸點信息全部上報,每個觸摸點的信息在本次上報事件流中的順序不重要,因為事件的過濾和手指(觸摸點)跟蹤是在內核空間處理的。
Type B 設備驅動需要給每個識別出來的觸摸點分配一個 slot,后面使用這個 slot 來上報觸摸點信息。可以通過 slot 的 ABS_MT_TRACKING_ID 來新增、替換或刪除觸摸點。一個非負數的 ID 表示一個有效的觸摸點,-1 這個 ID 表示未使用 slot。一個以前不存在的 ID 表示這是一個新加的觸摸點,一個 ID 如果再也不存在了就表示刪除了。
有些設備識別或追蹤的觸摸點信息要比他上報的多,這些設備驅動應該給硬件上報的每個觸摸點分配一個 Type B 的 slot。一旦檢測到某一個 slot 關聯的觸摸點 ID 發生了變化,驅動就應該改變這個 slot 的ABS_MT_TRACKING_ID,使這個 slot 失效。如果硬件設備追蹤到了比他正在上報的還要多的觸摸點,那么驅動程序應該發送 BTN_TOOL_*TAP 消息,并且調用 input_mt_report_pointer_emulation()函數,將此函數的第二個參數 use_count 設置為 false。
54.1.2 Type A  觸摸點信息上報時序
對于 Type A 類型的設備,發送觸摸點信息的時序如下所示,這里以 2 個觸摸點為例:
1 ABS_MT_POSITION_X x[0]
2 ABS_MT_POSITION_Y y[0]
3 SYN_MT_REPORT
4 ABS_MT_POSITION_X x[1]
5 ABS_MT_POSITION_Y y[1]
6 SYN_MT_REPORT
7 SYN_REPORT
第 1 行,通過 ABS_MT_POSITION_X 事件上報第一個觸摸點的 X 坐標數據,通過 input_report_abs 函數實現,下面同理。
第 2 行,通過 ABS_MT_POSITION_Y 事件上報第一個觸摸點的 Y 坐標數據。
第 3 行,上報 SYN_MT_REPORT 事件,通過調用 input_mt_sync 函數來實現。
第 4 行,通過 ABS_MT_POSITION_X 事件上報第二個觸摸點的 X 坐標數據。
第 5 行,通過 ABS_MT_POSITION_Y 事件上報第二個觸摸點的 Y 坐標數據。
第 6 行,上報 SYN_MT_REPORT 事件,通過調用 input_mt_sync 函數來實現。
第 7 行,上報 SYN_REPORT 事件,通過調用 input_sync 函數實現。
我們在編寫 TypeA 類型的多點觸摸驅動的時候就需要按照上述代碼中的時序上報坐標信息。Linux 內核 里 面 也 有 Type A 類 型 的 多 點 觸 摸 驅 動 , 找 到 st2332.c 這 個 驅 動 文 件 , 路 徑 為drivers/input/touchscreen/st1232.c,找到 st1232_ts_irq_handler 函數,此函數里面就是上報觸摸點坐標信息的。
103 static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
104 {
......
111 ret = st1232_ts_read_data(ts);
112 if (ret < 0)
113 goto end;
114
115 /* multi touch protocol */
116 for (i = 0; i < MAX_FINGERS; i++) {
117 if (!finger
.is_valid)
118 continue;
119
120 input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger
.t);
121 input_report_abs(input_dev, ABS_MT_POSITION_X, finger
.x);
122 input_report_abs(input_dev, ABS_MT_POSITION_Y, finger
.y);
123 input_mt_sync(input_dev);
124 count++;
125 }
......
140
141 /* SYN_REPORT */
142 input_sync(input_dev);
143
144 end:
145 return IRQ_HANDLED;
146 }
第 111 行,獲取所有觸摸點信息。
第 116~125 行,按照 Type A 類型輪流上報所有的觸摸點坐標信息,第 121 和 122 行分別上報觸摸點的(X,Y)軸坐標,也就是 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 事件。每上報完一個觸摸點坐標,都要在第 123 行調用 input_mt_sync 函數上報一個 SYN_MT_REPORT 信息。
第 142 行,每上報完一輪觸摸點信息就調用一次 input_sync 函數,也就是發送一個 SYN_REPORT 事件

54.1.3 Type B  觸摸點信息上報時序
對于 Type B 類型的設備,發送觸摸點信息的時序如下所示,這里以 2 個觸摸點為例:
1 ABS_MT_SLOT 0
2 ABS_MT_TRACKING_ID 45
3 ABS_MT_POSITION_X x[0]
4 ABS_MT_POSITION_Y y[0]
5 ABS_MT_SLOT 1
6 ABS_MT_TRACKING_ID 46
7 ABS_MT_POSITION_X x[1]
8 ABS_MT_POSITION_Y y[1]
9 SYN_REPORT
第 1 行,上報 ABS_MT_SLOT 事件,也就是觸摸點對應的 SLOT。每次上報一個觸摸點坐標之前要先使用 input_mt_slot 函數上報當前觸摸點 SLOT,觸摸點的 SLOT 其實就是觸摸點 ID,需要由觸摸 IC 提供。
第 2 行,根據 Type B 的要求,每個 SLOT 必須關聯一個 ABS_MT_TRACKING_ID,通過修改 SLOT 關聯 的 ABS_MT_TRACKING_ID 來 完 成 對 觸 摸 點 的 添 加 、 替 換 或 刪 除 。 具 體 用 到 的 函 數 就 是input_mt_report_slot_state,如果是添加一個新的觸摸點,那么此函數的第三個參數 active 要設置為 true,linux 內核會自動分配一個 ABS_MT_TRACKING_ID 值,不需要用戶去指定具體的 ABS_MT_TRACKING_ID 值。
第 3 行,上報觸摸點 0 的 X 軸坐標,使用函數 input_report_abs 來完成。
第 4 行,上報觸摸點 0 的 Y 軸坐標,使用函數 input_report_abs 來完成。
第 5~8 行,和第 1~4 行類似,只是換成了上報觸摸點 0 的(X,Y)坐標信息
第 9 行,當所有的觸摸點坐標都上傳完畢以后就得發送 SYN_REPORT 事件,使用 input_sync 函數來完成。
當一個觸摸點移除以后,同樣需要通過 SLOT 關聯的 ABS_MT_TRACKING_ID 來處理,時序如下所示:
1 ABS_MT_TRACKING_ID -1
2 SYN_REPORT
第 1 行,當一個觸摸點(SLOT)移除以后,需要通過 ABS_MT_TRACKING_ID 事件發送一個-1 給內核。方法很簡單,同樣使用 input_mt_report_slot_state 函數來完成,只需要將此函數的第三個參數 active 設置為false 即可,不需要用戶手動去設置-1。
第 2 行,當所有的觸摸點坐標都上傳完畢以后就得發送 SYN_REPORT 事件。
當要編寫 Type B 類型的多點觸摸驅動的時候就需要按照上述代碼中的時序上報坐標信息。Linux 內核里面有大量的 Type B 類型的多點觸摸驅動程序,我們可以參考這些現成的驅動程序來編寫自己的驅動代碼。這里就以 ili210x 這個觸摸驅動 IC 為例,看看是 Type B 類型是如何上報觸摸點坐標信息的。找到ili210x.c 這個驅動文件,路徑 為 drivers/input/touchscreen/ili210x.c,找到 ili210x_report_events 函數,此函數就是用于上報 ili210x 觸摸坐標信息的,函數內容如下所示:
78 static void ili210x_report_events(struct input_dev *input,
79 const struct touchdata *touchdata)
80 {
81 int i;
82 bool touch;
83 unsigned int x, y;
84 const struct finger *finger;
85
86 for (i = 0; i < MAX_TOUCHES; i++) {
87 input_mt_slot(input, i);
88
89 finger = &touchdata->finger
;
90
91 touch = touchdata->status & (1 << i);
92 input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
93 if (touch) {
94 x = finger->x_low | (finger->x_high << 8);
95 y = finger->y_low | (finger->y_high << 8);
96
97 input_report_abs(input, ABS_MT_POSITION_X, x);
98 input_report_abs(input, ABS_MT_POSITION_Y, y);
99 }
100 }
101
102 input_mt_report_pointer_emulation(input, false);
103 input_sync(input);
104 }
第 86~100 行,使用 for 循環實現上報所有的觸摸點坐標,第 87 行調用 input_mt_slot 函數上報ABS_MT_SLOT 事件。第 92 行調用 input_mt_report_slot_state 函數上報 ABS_MT_TRACKING_ID 事件,也就是給 SLOT 關聯一個 ABS_MT_TRACKING_ID。第 97 和 98 行使用 input_report_abs 函數上報觸摸點對應的(X,Y)坐標值。
第 103 行,使用 input_sync 函數上報 SYN_REPORT 事件。

54.1.4 MT  其他事件的使用
在 54.1.1 小節中給出了 Linux 所支持的所有 ABS_MT 事件,大家可以根據實際需求將這些事件組成各種事件組合。最簡單的組合就是 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y,可以通過在這兩個事件上報觸摸點,如果設備支持的話,還可以使用 ABS_MT_TOUCH_MAJOR 和 ABS_MT_WIDTH_MAJOR 這兩個消息 上 報 觸 摸 面 積 信 息 , 關 于 其 他 ABS_MT 事 件 的 具 體 含 義 大 家 可 以 查 看 Linux 內 核 中 的multi-touch-protocol.txt 文檔,這里我們重點補充一下 ABS_MT_TOOL_TYPE 事件。
ABS_MT_TOOL_TYPE 事件用于上報觸摸工具類型,很多內核驅動都不能區分出觸摸設備類型,是手指還是觸摸筆?這種情況下,這個事件可以忽略掉。目前的協議支持 MT_TOOL_FINGER(手指)、MT_TOOL_PEN(筆)和 MT_TOOL_PALM(手掌)這三種觸摸設備類,于 Type B 類 型 ,此事件由 input 子系統內核處理。如果驅動程序需要上報 ABS_MT_TOOL_TYPE 事件,那么可以使用 input_mt_report_slot_state 函數來完成此工作。
關于 Linux 系統下的多點觸摸(MT)協議就講解到這里,簡單總結一下,MT 協議隸屬于 linux 的 input子系統,驅動通過大量的 ABS_MT 事件向 linux 內核上報多點觸摸坐標數據。根據觸摸 IC 的不同,分為TypeA 和 Type B 兩種類型,不同的類型其上報時序不同,目前使用最多的是 Type B 類型。

54.1.5  多點觸摸使用到的 API  函數
根據前面的講解,我們知道 linux 下的多點觸摸協議其實就是通過不同的事件來上報觸摸點坐標信息,這些事件都是通過 Linux 內核提供的對應 API 函數實現的,本小節我們來看一下一些常見的 API 函數。
1 、input_mt_init_slots  函數
input_mt_init_slots 函數用于初始化 MT 的輸入 slots,編寫 MT 驅動的時候必須先調用此函數初始化slots,此函數定義在文件 drivers/input/input-mt.c 中,函數原型如下所示:
int input_mt_init_slots( struct input_dev *dev,
unsigned int num_slots,
unsigned int flags)
函數參數和返回值含義如下:
dev: MT 設備對應的 input_dev,因為 MT 設備隸屬于 input_dev。
num_slots:設備要使用的 SLOT 數量,也就是觸摸點的數量。
flags:其他一些 flags 信息,可設置的 flags 如下所示:
#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */
#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */
#define INPUT_MT_DROP_UNUSED0x0004 /* drop contacts not seen in frame */
#define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */
#define INPUT_MT_SEMI_MT 0x0010 /* semi-mt device, finger count handled manually */
可以采用‘|’運算來同時設置多個 flags 標識。
返回值:0,成功;負值,失敗。
2 、input_mt_slot  函數
此函數用于 Type B 類型,此函數用于產生 ABS_MT_SLOT 事件,告訴內核當前上報的是哪個觸摸點的坐標數據,此函數定義在文件 include/linux/input/mt.h 中,函數原型如下所示:
void input_mt_slot(struct input_dev *dev,
int slot)
函數參數和返回值含義如下:
dev: MT 設備對應的 input_dev。
slot:當前發送的是哪個 slot 的坐標信息,也就是哪個觸摸點。
返回值:無。
3 、input_mt_report_slot_state  函數
此 函 數 用 于 Type B 類 型 , 用 于 產 生 ABS_MT_TRACKING_ID 和 ABS_MT_TOOL_TYPE 事 件 ,ABS_MT_TRACKING_ID 事件給 slot 關聯一個 ABS_MT_TRACKING_ID , ABS_MT_TOOL_TYPE 事件指定觸摸類 型(是筆還是手指等)。此函數定義在文件 drivers/input/input-mt.c 中,此函數原型如下所示:
void input_mt_report_slot_state( struct input_dev *dev,
unsigned int tool_type,
bool active)
函數參數和返回值含義如下:
dev: MT 設備對應的 input_dev。
tool_type:觸摸類型,可以選擇 MT_TOOL_FINGER(手指)、MT_TOOL_PEN(筆)或MT_TOOL_PALM(手掌),對于多點電容觸摸屏來說一般都是手指。
active:true,連續觸摸,input 子系統內核會自動分配一個 ABS_MT_TRACKING_ID 給 slot。
false,觸摸點抬起,表示某個觸摸點無效了,input 子系統內核會分配一個-1 給 slot,表示觸摸點溢出。
返回值:無。
4 、input_report_abs  函數
TypeA 和 Type B 類 型 都 使 用 此 函 數 上 報 觸 摸 點 坐 標 信 息 , 通 過 ABS_MT_POSITION_X 和ABS_MT_POSITION_Y 事件實現 X 和 Y 軸坐標信息上報。此函數定義在文件 include/linux/input.h 中,函數
原型如下所示:
void input_report_abs( struct input_dev *dev,
unsigned int code,
int value)
函數參數和返回值含義如下:
dev: MT 設備對應的 input_dev。
code:要上報的是什么數據,可以設置為 ABS_MT_POSITION_X 或 ABS_MT_POSITION_Y,也就是 X 軸或者 Y 軸坐標數據。
value:具體的 X 軸或 Y 軸坐標數據值。
返回值:無。
5 、input_mt_report_pointer_emulation  函數
如果追蹤到的觸摸點數量多于當前上報的數量,驅動程序使用 BTN_TOOL_TAP 事件來通知用戶空間當前追蹤到的觸摸點總數量,然后調用 input_mt_report_pointer_emulation 函數將 use_count 參數設置為false。否則的話將 use_count 參數設置為 true,表示當前的觸摸點數量(此函數會獲取到具體的觸摸點數量,不需要用戶給出),此函數定義在文件 drivers/input/input-mt.c 中,函數原型如下:
void input_mt_report_pointer_emulation(struct input_dev *dev,
bool use_count)
函數參數和返回值含義如下:
dev: MT 設備對應的 input_dev。
use_count:true,有效的觸摸點數量;false,追蹤到的觸摸點數量多于當前上報的數量。
返回值:無。

54.1.6  多點電容觸摸驅動框架
前面幾小節已經詳細的講解了 linux 下多點觸摸屏驅動原理,本小節我們來梳理一下 linux 下多點電容觸摸驅動的編寫框架和步驟。首先確定驅動需要用到哪些知識點,哪些框架?根據前面的分析,我們在編寫驅動的時候需要注意一下幾點:
① 多點電容觸摸芯片的接口,一般都為 I2C 接口,因此驅動主框架肯定是 I2C。
② linux 里面一般都是通過中斷來上報觸摸點坐標信息,因此需要用到中斷框架。
③ 多點電容觸摸屬于 input 子系統,因此還要用到 input 子系統框架。
④ 在中斷處理程序中按照 linux 的 MT 協議上報坐標信息。
根據上面的分析,多點電容觸摸驅動編寫框架以及步驟如下:
1 、I2C  驅動框架
驅動總體采用 I2C 框架,參考框架代碼如下所示:
1 /* 設備樹匹配表 */
2 static const struct i2c_device_id xxx_ts_id[] = {
3 { "xxx", 0, },
4 { /* sentinel */ }
5 };
6
7 /* 設備樹匹配表 */
8 static const struct of_device_id xxx_of_match[] = {
9 { .compatible = "xxx", },
10 { /* sentinel */ }
11 };
12
13 /* i2c 驅動結構體 */
14 static struct i2c_driver ft5x06_ts_driver = {
15 .driver = {
16 .owner = THIS_MODULE,
17 .name = "edt_ft5x06",
18 .of_match_table = of_match_ptr(xxx_of_match),
19 },
20 .id_table = xxx_ts_id,
21 .probe = xxx_ts_probe,
22 .remove = xxx_ts_remove,
23 };
24
25 /*
26 * @description : 驅動入口函數
27 * @param : 無
28 * @return : 無
29 */
30 static int __init xxx_init(void)
31 {
32 int ret = 0;
33
34 ret = i2c_add_driver(&xxx_ts_driver);
35
36 return ret;
37 }
38
39 /*
40 * @description : 驅動出口函數
41 * @param : 無
42 * @return : 無
43 */
44 static void __exit xxx_exit(void)
45 {
46 i2c_del_driver(&ft5x06_ts_driver);
47 }
48
49 module_init(xxx_init);
50 module_exit(xxx_exit);
51 MODULE_LICENSE("GPL");
52 MODULE_AUTHOR("topeet");
當設備樹中觸摸 IC 的設備節點和驅動匹配以后,第 21 行的 xxx_ts_probe 函數就會執行,我們可以在此函數中初始化觸摸 IC,中斷和 input 子系統等。
2摸 、初始化觸摸 IC和 、中斷和 input  子系統
初始化操作都是在 xxx_ts_probe 函數中完成,參考框架如下所示:
1 static int xxx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
2 {
3 struct input_dev *input;
4
5 /* 1、初始化 I2C */
6 ......
7
8 /* 2,申請中斷, */
9 devm_request_threaded_irq(&client->dev, client->irq, NULL,
10 xxx_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
11 client->name, &xxx);
12 ......
13
14 /* 3,input 設備申請與初始化 */
15 input = devm_input_allocate_device(&client->dev);
16
17 input->name = client->name;
18 input->id.bustype = BUS_I2C;
19 input->dev.parent = &client->dev;
20 ......
21
22 /* 4,初始化 input 和 MT */
23 __set_bit(EV_ABS, input->evbit);
24 __set_bit(BTN_TOUCH, input->keybit);
25
26 input_set_abs_params(input, ABS_X, 0, width, 0, 0);
27 input_set_abs_params(input, ABS_Y, 0, height, 0, 0);
28 input_set_abs_params(input, ABS_MT_POSITION_X,0, width, 0, 0);
29 input_set_abs_params(input, ABS_MT_POSITION_Y,0, height, 0, 0);
30 input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
31 ......
32
33 /* 5,注冊 input_dev */
34 input_register_device(input);
35 ......
36 }
第 5~7 行,首先肯定是初始化觸摸芯片,包括芯片的相關 IO,比如復位、中斷等 IO 引腳,然后就是芯片本身的初始化,也就是配置觸摸芯片的相關寄存器。
第 9 行,因為一般觸摸芯片都是通過中斷來向系統上報觸摸點坐標信息的,因此我們需要初始化中斷。大家可能會發現第 9 行并沒有使用 request_irq 函數申請中斷,而是采用了 devm_request_threaded_irq 這個函數,為什么使用這個函數呢?是不是 request_irq 函數不能使用?答案肯定不是的,這里用 request_irq函數是絕對沒問題的。那為何要用 devm_request_threaded_irq 呢?這里我們就簡單的介紹一下這個 API
函數,devm_request_threaded_irq 函數特點如下:
① 用于申請中斷,作用和 request_irq 函數類似。
② 此函數的作用是中斷線程化,大家如果直接在網上搜索“devm_request_threaded_irq”會發現相關解釋很少。但是大家去搜索 request_threaded_irq 函數就會有很多講解的博客和帖子,這兩個函數在名字上的差別就是前者比后者多了個“devm_”前綴,“devm_”前綴稍后講解。大家應該注意到了
“request_threaded_irq”相比“request_irq”多了個 threaded 函數,也就是線程的意思。那么為什么要中斷線程化呢?我們都是知道硬件中斷具有最高優先級,不論什么時候只要硬件中斷發生,那么內核都會終止當前正在執行的操作,轉而去執行中斷處理程序(不考慮關閉中斷和中斷優先級的情況),如果中斷非常頻
繁的話那么內核將會頻繁的執行中斷處理程序,導致任務得不到及時的處理。中斷線程化以后中斷將作為內核線程運行,而且也可以被賦予不同的優先級,任務的優先級可能比中斷線程的優先級高,這樣做的目的就是保證高優先級的任務能被優先處理。大家可能會疑問,前面不是說可以將比較耗時的中斷放到下半
部(bottom half)處理嗎?雖然下半部可以被延遲處理,但是依舊先于線程執行,中斷線程化可以讓這些比較耗時的下半部與進程進行公平競爭。
要注意,并不是所有的中斷都可以被線程化,重要的中斷就不能這么操作。對于觸摸屏而言只要手指放到屏幕上,它可能就會一直產生中斷(視具體芯片而定,FT5426 是這樣的),中斷處理程序里面需要通過 I2C讀取觸摸信息并上報給內核,I2C 的速度最大只有 400KHz,算是低速外設。不斷的產生中斷、讀取觸摸信
息、上報信息會導致處理器在觸摸中斷上花費大量的時間,但是觸摸相對來說不是那么重要的事件,因此可以將觸摸中斷線程化。如果你覺得觸摸中斷很重要,那么就可以不將其進行線程化處理。總之,要不要將一個中斷進行線程化處理是需要自己根據實際情況去衡量的。
③ 最后來看一下“devm_”前綴,在 linux 內核中有很多的申請資源類的 API 函數都有對應的“devm_”前綴版本。比如 devm_request_irq 和 request_irq 這兩個函數,這兩個函數都是申請中斷的,我們使用request_irq 函數申請中斷的時候,如果驅動初始化失敗的話就要調用 free_irq 函數對申請成功的 irq 進行
釋放,卸載驅動的時候也需要我們手動調用 free_irq 來釋放 irq。假如我們的驅動里面申請了很多資源,比如:gpio、irq、input_dev,那么就需要添加很多goto 語句對其做處理,當這樣的標簽多了以后代碼看起來就不整潔了。“devm_”函數就是為了處理這種情況而誕生的,“devm_”函數最大的作用就是:
使用“devm_”前綴的函數申請到的資源可以由系統自動釋放,不需要我們手動處理。 如果我們使用devm_request_threaded_irq 函數來申請中斷,那么就不需要我們再調用 free_irq 函數對其進行釋放。大家可以注意一下,帶有“devm_”前綴的都是一些和設備資源管理有關的函數。關于“devm_”函數的實現原理這里就不做詳細的講解了,我們的重點在于學會如何使用這些 API 函數,感興趣的可以查閱一些其他文檔或者帖子來看一下“devm_”函數的實現原理。
第 15 行,接下來就是申請 input_dev,因為多點電容觸摸屬于 input 子系統。這里同樣使用devm_input_allocate_device 函數來申請 input_dev,也就是我們前面講解的 input_allocate_device 函數加“devm_”前綴版本。申請到 input_dev 以后還需要對其進行初始化操作。
第 23~24 行,設置 input_dev 需要上報的事件為 EV_ABS 和 BTN_TOUCH,因為多點電容屏的觸摸坐標為絕對值,因此需要上報 EV_ABS 事件。觸摸屏有按下和抬起之分,因此需要上報 BTN_TOUCH 按鍵。
第 26~29 行,調用 input_set_abs_params 函數設置 EV_ABS 事件需要上報 ABS_X、ABS_Y、ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y。單點觸摸需要上報 ABS_X 和 ABS_Y,對于多點觸摸需要上報 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y。
第 30 行,調用 input_mt_init_slots 函數初始化多點電容觸摸的 slots。
第 34 行,調用 input_register_device 函數系統注冊前面申請到的 input_dev。
3 、上報坐標信息
最后就是在中斷服務程序中上報讀取到的坐標信息,根據所使用的多點電容觸摸設備類型選擇使用TypeA 還是 Type B 時序。由于大多數的設備都是 Type B 類型,因此這里就以 Type B 類型為例講解一下上報過程,參考驅動框架如下所示:
1 static irqreturn_t xxx_handler(int irq, void *dev_id)
2 {
3
4 int num; /* 觸摸點數量 */
5 int x[n], y[n]; /* 保存坐標值 */
6
7 /* 1、從觸摸芯片獲取各個觸摸點坐標值 */
8 ......
9
10 /* 2、上報每一個觸摸點坐標 */
11 for (i = 0; i < num; i++) {
12 input_mt_slot(input, id);
13 input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
14 input_report_abs(input, ABS_MT_POSITION_X, x
);
15 input_report_abs(input, ABS_MT_POSITION_Y, y
);
16 }
17 ......
18
19 input_sync(input);
20 ......
21
22 return IRQ_HANDLED;
23 }
進入中斷處理程序以后首先肯定是從觸摸 IC 里面讀取觸摸坐標以及觸摸點數量,假設觸摸點數量保存到 num 變量,觸摸點坐標存放到 x,y 數組里面。
第 11~16 行,循環上報每一個觸摸點坐標,一定要按照 Type B 類型的時序進行。
第 19 行,每一輪觸摸點坐標上報完畢以后就調用一次 input_sync 函數發送一個 SYN_REPORT 事件。
關于多點電容觸摸驅動框架就講解到這里,接下來我們就實際編寫一個多點電容觸摸驅動程序。

本文地址:http://m.qingdxww.cn/thread-748976-1-1.html     【打印本頁】

本站部分文章為轉載或網友發布,目的在于傳遞和分享信息,并不代表本網贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據著作權人的要求,第一時間更正或刪除。
您需要登錄后才可以發表評論 登錄 | 立即注冊

廠商推薦

  • Microchip視頻專區
  • 利用SAM E54 Xplained Pro評估工具包演示CAN轉USB橋接器以及基于CAN的主機和自舉程序應用程序
  • 使用SAM-IoT Wx v2開發板演示AWS IoT Core應用程序
  • 使用Harmony3加速TCP/IP應用的開發培訓教程
  • 集成高級模擬外設的PIC18F-Q71家族介紹培訓教程
  • 貿澤電子(Mouser)專區

相關視頻

關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
快速回復 返回頂部 返回列表
主站蜘蛛池模板: 99久久国内精品成人免费 | 高清视频一区二区 | 91极品女神嫩模在线播放 | 国产精品九九九久久九九 | 妖精视频国产精品 | 新四虎影院 | 欧美色亚洲图 | 丁香六月久久 | 亚洲三级欧美 | 韩国本免费一级毛片免费 | 岛国大片在线播放 | 视频网站免费看 | 榴莲视频app下载安装 | 国产日韩精品欧美一区 | 日本不卡在线观看 | 日韩大片 | 国产极品视频 | 免费精品国产 | 国产一区欧美二区 | 婷婷综合亚洲 | 97视屏| 日本一区二区三区欧美在线观看 | 精品自拍视频在线观看 | 青青草原综合网 | 免费精品国偷自产在线读大二 | 爱操在线 | 亚洲免费视频一区二区三区 | 成人一区二区丝袜美腿 | 黄色免费网站大全 | 亚欧色视频在线观看免费 | 天美传媒果冻传媒星空传媒 | 久久蜜桃| 在线视频久草 | www五月婷婷 | 日韩无砖专区体验区 | 欧美一区二区三区综合色视频 | 国产产一区二区三区久久毛片国语 | 牛牛影视精品一区二区在线看 | 麻豆视频网站 | 免费人成网站在线播放 | 91国在线高清视频 |