色偷偷偷久久伊人大杳蕉,色爽交视频免费观看,欧美扒开腿做爽爽爽a片,欧美孕交alscan巨交xxx,日日碰狠狠躁久久躁蜜桃

x
x

迅為IMX6ULL開發(fā)板Linux下電容觸摸屏實(shí)驗(yàn)-驅(qū)動(dòng)框架

發(fā)布時(shí)間:2020-11-27 10:00    發(fā)布者:就是塔塔
關(guān)鍵詞: 迅為 , IMX6ULL , 開發(fā)板 , Linux , 電容觸摸屏
如今觸摸屏的使用越來(lái)越廣泛,從手機(jī)、平板到蜂巢取貨等場(chǎng)合,都是用了觸摸屏,觸摸屏的使用非常便捷高效。在本章就來(lái)學(xué)習(xí)一下如何在 Linux 下編寫電容觸摸屏驅(qū)動(dòng)。
54.1 Linux  下電容觸摸屏驅(qū)動(dòng)框架
54.1.1  多點(diǎn)觸摸協(xié)議詳解

在前面的裸板實(shí)驗(yàn)中,已經(jīng)詳細(xì)講解過(guò)了電容觸摸驅(qū)動(dòng)的基本原理,根據(jù)前面的實(shí)驗(yàn)可以總結(jié)出電容觸摸屏驅(qū)動(dòng)其實(shí)就是一下幾種 linux 驅(qū)動(dòng)框架的組合:
① IIC 設(shè)備驅(qū)動(dòng),因?yàn)殡娙萦|摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 設(shè)備驅(qū)動(dòng)。
② 通過(guò)中斷引腳(INT)向 linux 內(nèi)核上報(bào)觸摸信息,因此需要用到 linux 中斷驅(qū)動(dòng)框架。坐標(biāo)的上報(bào)在中斷服務(wù)函數(shù)中完成。
③ 觸摸屏的坐標(biāo)信息、屏幕按下和抬起信息都屬于 linux 的 input 子系統(tǒng),因此向 linux 內(nèi)核上報(bào)觸摸屏坐標(biāo)信息就得使用 input 子系統(tǒng)。只是,我們得按照 linux 內(nèi)核規(guī)定的規(guī)則來(lái)上報(bào)坐標(biāo)信息。
在上面的驅(qū)動(dòng)框架組合中我們發(fā)現(xiàn) I2C 驅(qū)動(dòng)、中斷驅(qū)動(dòng)、input 子系統(tǒng)都已經(jīng)學(xué)習(xí)了解過(guò)了,還沒(méi)有學(xué)習(xí)過(guò) input 子系統(tǒng)下的多點(diǎn)電容觸摸協(xié)議,這個(gè)就是本章學(xué)習(xí)的重點(diǎn),linux 內(nèi)核中有一份文檔詳細(xì)的講解了多點(diǎn)電容觸摸屏協(xié)議,文檔路徑為:Documentation/input/multitouch-protocol.txt。
MT 協(xié)議被分為兩種類型,TypeA 和 TypeB,這兩種類型的區(qū)別如下:
TypeA:適用于觸摸點(diǎn)不能被區(qū)分或者追蹤,此類型的設(shè)備上報(bào)原始數(shù)據(jù)(此類型在實(shí)際使用中非常少!)。
Type B:適用于有硬件追蹤并能區(qū)分觸摸點(diǎn)的觸摸設(shè)備,此類型設(shè)備通過(guò) slot 更新某一個(gè)觸摸點(diǎn)的信息,F(xiàn)T5426 就屬于此類型,一般的多點(diǎn)電容觸摸屏 IC 都有此能力。
觸摸點(diǎn)的信息通過(guò)一系列的 ABS_MT 事件(有的資料也叫消息)上報(bào)給 linux 內(nèi)核,只有 ABS_MT 事件是用于多點(diǎn)觸摸的,ABS_MT 事件定義在文件 linux/input.h 中,相關(guān)事件如下所示:
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 用來(lái)上報(bào)觸摸點(diǎn)的 (X,Y) 坐標(biāo)信息,ABS_MT_SLOT 用來(lái)上報(bào)觸摸點(diǎn) ID ,對(duì)于 Type B 類型的設(shè)備,需要用到ABS_MT_TRACKING_ID 事件來(lái)區(qū)分觸摸點(diǎn)。
對(duì)于 TypeA 類型的設(shè)備,通過(guò) input_mt_sync()函數(shù)來(lái)隔離不同的觸摸點(diǎn)數(shù)據(jù)信息,此函數(shù)原型如下所示:
void input_mt_sync(struct input_dev *dev)
此函數(shù)只要一個(gè)參數(shù),類型為 input_dev,用于指定具體的 input_dev 設(shè)備。input_mt_sync()函數(shù)會(huì)觸發(fā) SYN_MT_REPORT 事件,此事件會(huì)通知接收者獲取當(dāng)前觸摸數(shù)據(jù),并且準(zhǔn)備接收下一個(gè)觸摸點(diǎn)數(shù)據(jù)。
對(duì)于 Type B 類型的設(shè)備,上報(bào)觸摸點(diǎn)信息的時(shí)候需要通過(guò) input_mt_slot()函數(shù)區(qū)分是哪一個(gè)觸摸點(diǎn),input_mt_slot()函數(shù)原型如下所示:
void input_mt_slot(struct input_dev *dev, int slot)
此函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是 input_dev 設(shè)備,第二個(gè)參數(shù) slot 用于指定當(dāng)前上報(bào)的是哪個(gè)觸摸點(diǎn)信息。input_mt_slot()函數(shù)會(huì)觸發(fā) ABS_MT_SLOT 事件,此事件會(huì)告訴接收者當(dāng)前正在更新的是哪個(gè)觸摸點(diǎn)(slot)的數(shù)據(jù)。
不管是哪個(gè)類型的設(shè)備,最終都要調(diào)用 input_sync()函數(shù)來(lái)標(biāo)識(shí)多點(diǎn)觸摸信息傳輸完成,告訴接收者處理之前累計(jì)的所有消息,并且準(zhǔn)備好下一次接收。Type B 和 Type A 相比最大的區(qū)別就是 Type B 可以區(qū)分出觸摸點(diǎn), 因此可以減少發(fā)送到用戶空間的數(shù)據(jù)。Type B 使用 slot 協(xié)議區(qū)分具體的觸摸點(diǎn),slot 需要用
到 ABS_MT_TRACKING_ID 消息,這個(gè) ID 需要硬件提供,或者通過(guò)原始數(shù)據(jù)計(jì)算出來(lái)。對(duì)于 TypeA 設(shè)備,內(nèi)核驅(qū)動(dòng)需要一次性將觸摸屏上所有的觸摸點(diǎn)信息全部上報(bào),每個(gè)觸摸點(diǎn)的信息在本次上報(bào)事件流中的順序不重要,因?yàn)槭录倪^(guò)濾和手指(觸摸點(diǎn))跟蹤是在內(nèi)核空間處理的。
Type B 設(shè)備驅(qū)動(dòng)需要給每個(gè)識(shí)別出來(lái)的觸摸點(diǎn)分配一個(gè) slot,后面使用這個(gè) slot 來(lái)上報(bào)觸摸點(diǎn)信息。可以通過(guò) slot 的 ABS_MT_TRACKING_ID 來(lái)新增、替換或刪除觸摸點(diǎn)。一個(gè)非負(fù)數(shù)的 ID 表示一個(gè)有效的觸摸點(diǎn),-1 這個(gè) ID 表示未使用 slot。一個(gè)以前不存在的 ID 表示這是一個(gè)新加的觸摸點(diǎn),一個(gè) ID 如果再也不存在了就表示刪除了。
有些設(shè)備識(shí)別或追蹤的觸摸點(diǎn)信息要比他上報(bào)的多,這些設(shè)備驅(qū)動(dòng)應(yīng)該給硬件上報(bào)的每個(gè)觸摸點(diǎn)分配一個(gè) Type B 的 slot。一旦檢測(cè)到某一個(gè) slot 關(guān)聯(lián)的觸摸點(diǎn) ID 發(fā)生了變化,驅(qū)動(dòng)就應(yīng)該改變這個(gè) slot 的ABS_MT_TRACKING_ID,使這個(gè) slot 失效。如果硬件設(shè)備追蹤到了比他正在上報(bào)的還要多的觸摸點(diǎn),那么驅(qū)動(dòng)程序應(yīng)該發(fā)送 BTN_TOOL_*TAP 消息,并且調(diào)用 input_mt_report_pointer_emulation()函數(shù),將此函數(shù)的第二個(gè)參數(shù) use_count 設(shè)置為 false。
54.1.2 Type A  觸摸點(diǎn)信息上報(bào)時(shí)序
對(duì)于 Type A 類型的設(shè)備,發(fā)送觸摸點(diǎn)信息的時(shí)序如下所示,這里以 2 個(gè)觸摸點(diǎn)為例:
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 行,通過(guò) ABS_MT_POSITION_X 事件上報(bào)第一個(gè)觸摸點(diǎn)的 X 坐標(biāo)數(shù)據(jù),通過(guò) input_report_abs 函數(shù)實(shí)現(xiàn),下面同理。
第 2 行,通過(guò) ABS_MT_POSITION_Y 事件上報(bào)第一個(gè)觸摸點(diǎn)的 Y 坐標(biāo)數(shù)據(jù)。
第 3 行,上報(bào) SYN_MT_REPORT 事件,通過(guò)調(diào)用 input_mt_sync 函數(shù)來(lái)實(shí)現(xiàn)。
第 4 行,通過(guò) ABS_MT_POSITION_X 事件上報(bào)第二個(gè)觸摸點(diǎn)的 X 坐標(biāo)數(shù)據(jù)。
第 5 行,通過(guò) ABS_MT_POSITION_Y 事件上報(bào)第二個(gè)觸摸點(diǎn)的 Y 坐標(biāo)數(shù)據(jù)。
第 6 行,上報(bào) SYN_MT_REPORT 事件,通過(guò)調(diào)用 input_mt_sync 函數(shù)來(lái)實(shí)現(xiàn)。
第 7 行,上報(bào) SYN_REPORT 事件,通過(guò)調(diào)用 input_sync 函數(shù)實(shí)現(xiàn)。
我們?cè)诰帉?TypeA 類型的多點(diǎn)觸摸驅(qū)動(dòng)的時(shí)候就需要按照上述代碼中的時(shí)序上報(bào)坐標(biāo)信息。Linux 內(nèi)核 里 面 也 有 Type A 類 型 的 多 點(diǎn) 觸 摸 驅(qū) 動(dòng) , 找 到 st2332.c 這 個(gè) 驅(qū) 動(dòng) 文 件 , 路 徑 為drivers/input/touchscreen/st1232.c,找到 st1232_ts_irq_handler 函數(shù),此函數(shù)里面就是上報(bào)觸摸點(diǎn)坐標(biāo)信息的。
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 行,獲取所有觸摸點(diǎn)信息。
第 116~125 行,按照 Type A 類型輪流上報(bào)所有的觸摸點(diǎn)坐標(biāo)信息,第 121 和 122 行分別上報(bào)觸摸點(diǎn)的(X,Y)軸坐標(biāo),也就是 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 事件。每上報(bào)完一個(gè)觸摸點(diǎn)坐標(biāo),都要在第 123 行調(diào)用 input_mt_sync 函數(shù)上報(bào)一個(gè) SYN_MT_REPORT 信息。
第 142 行,每上報(bào)完一輪觸摸點(diǎn)信息就調(diào)用一次 input_sync 函數(shù),也就是發(fā)送一個(gè) SYN_REPORT 事件

54.1.3 Type B  觸摸點(diǎn)信息上報(bào)時(shí)序
對(duì)于 Type B 類型的設(shè)備,發(fā)送觸摸點(diǎn)信息的時(shí)序如下所示,這里以 2 個(gè)觸摸點(diǎn)為例:
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 行,上報(bào) ABS_MT_SLOT 事件,也就是觸摸點(diǎn)對(duì)應(yīng)的 SLOT。每次上報(bào)一個(gè)觸摸點(diǎn)坐標(biāo)之前要先使用 input_mt_slot 函數(shù)上報(bào)當(dāng)前觸摸點(diǎn) SLOT,觸摸點(diǎn)的 SLOT 其實(shí)就是觸摸點(diǎn) ID,需要由觸摸 IC 提供。
第 2 行,根據(jù) Type B 的要求,每個(gè) SLOT 必須關(guān)聯(lián)一個(gè) ABS_MT_TRACKING_ID,通過(guò)修改 SLOT 關(guān)聯(lián) 的 ABS_MT_TRACKING_ID 來(lái) 完 成 對(duì) 觸 摸 點(diǎn) 的 添 加 、 替 換 或 刪 除 。 具 體 用 到 的 函 數(shù) 就 是input_mt_report_slot_state,如果是添加一個(gè)新的觸摸點(diǎn),那么此函數(shù)的第三個(gè)參數(shù) active 要設(shè)置為 true,linux 內(nèi)核會(huì)自動(dòng)分配一個(gè) ABS_MT_TRACKING_ID 值,不需要用戶去指定具體的 ABS_MT_TRACKING_ID 值。
第 3 行,上報(bào)觸摸點(diǎn) 0 的 X 軸坐標(biāo),使用函數(shù) input_report_abs 來(lái)完成。
第 4 行,上報(bào)觸摸點(diǎn) 0 的 Y 軸坐標(biāo),使用函數(shù) input_report_abs 來(lái)完成。
第 5~8 行,和第 1~4 行類似,只是換成了上報(bào)觸摸點(diǎn) 0 的(X,Y)坐標(biāo)信息
第 9 行,當(dāng)所有的觸摸點(diǎn)坐標(biāo)都上傳完畢以后就得發(fā)送 SYN_REPORT 事件,使用 input_sync 函數(shù)來(lái)完成。
當(dāng)一個(gè)觸摸點(diǎn)移除以后,同樣需要通過(guò) SLOT 關(guān)聯(lián)的 ABS_MT_TRACKING_ID 來(lái)處理,時(shí)序如下所示:
1 ABS_MT_TRACKING_ID -1
2 SYN_REPORT
第 1 行,當(dāng)一個(gè)觸摸點(diǎn)(SLOT)移除以后,需要通過(guò) ABS_MT_TRACKING_ID 事件發(fā)送一個(gè)-1 給內(nèi)核。方法很簡(jiǎn)單,同樣使用 input_mt_report_slot_state 函數(shù)來(lái)完成,只需要將此函數(shù)的第三個(gè)參數(shù) active 設(shè)置為false 即可,不需要用戶手動(dòng)去設(shè)置-1。
第 2 行,當(dāng)所有的觸摸點(diǎn)坐標(biāo)都上傳完畢以后就得發(fā)送 SYN_REPORT 事件。
當(dāng)要編寫 Type B 類型的多點(diǎn)觸摸驅(qū)動(dòng)的時(shí)候就需要按照上述代碼中的時(shí)序上報(bào)坐標(biāo)信息。Linux 內(nèi)核里面有大量的 Type B 類型的多點(diǎn)觸摸驅(qū)動(dòng)程序,我們可以參考這些現(xiàn)成的驅(qū)動(dòng)程序來(lái)編寫自己的驅(qū)動(dòng)代碼。這里就以 ili210x 這個(gè)觸摸驅(qū)動(dòng) IC 為例,看看是 Type B 類型是如何上報(bào)觸摸點(diǎn)坐標(biāo)信息的。找到ili210x.c 這個(gè)驅(qū)動(dòng)文件,路徑 為 drivers/input/touchscreen/ili210x.c,找到 ili210x_report_events 函數(shù),此函數(shù)就是用于上報(bào) ili210x 觸摸坐標(biāo)信息的,函數(shù)內(nèi)容如下所示:
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 循環(huán)實(shí)現(xiàn)上報(bào)所有的觸摸點(diǎn)坐標(biāo),第 87 行調(diào)用 input_mt_slot 函數(shù)上報(bào)ABS_MT_SLOT 事件。第 92 行調(diào)用 input_mt_report_slot_state 函數(shù)上報(bào) ABS_MT_TRACKING_ID 事件,也就是給 SLOT 關(guān)聯(lián)一個(gè) ABS_MT_TRACKING_ID。第 97 和 98 行使用 input_report_abs 函數(shù)上報(bào)觸摸點(diǎn)對(duì)應(yīng)的(X,Y)坐標(biāo)值。
第 103 行,使用 input_sync 函數(shù)上報(bào) SYN_REPORT 事件。

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

54.1.5  多點(diǎn)觸摸使用到的 API  函數(shù)
根據(jù)前面的講解,我們知道 linux 下的多點(diǎn)觸摸協(xié)議其實(shí)就是通過(guò)不同的事件來(lái)上報(bào)觸摸點(diǎn)坐標(biāo)信息,這些事件都是通過(guò) Linux 內(nèi)核提供的對(duì)應(yīng) API 函數(shù)實(shí)現(xiàn)的,本小節(jié)我們來(lái)看一下一些常見(jiàn)的 API 函數(shù)。
1 、input_mt_init_slots  函數(shù)
input_mt_init_slots 函數(shù)用于初始化 MT 的輸入 slots,編寫 MT 驅(qū)動(dòng)的時(shí)候必須先調(diào)用此函數(shù)初始化slots,此函數(shù)定義在文件 drivers/input/input-mt.c 中,函數(shù)原型如下所示:
int input_mt_init_slots( struct input_dev *dev,
unsigned int num_slots,
unsigned int flags)
函數(shù)參數(shù)和返回值含義如下:
dev: MT 設(shè)備對(duì)應(yīng)的 input_dev,因?yàn)?MT 設(shè)備隸屬于 input_dev。
num_slots:設(shè)備要使用的 SLOT 數(shù)量,也就是觸摸點(diǎn)的數(shù)量。
flags:其他一些 flags 信息,可設(shè)置的 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 */
可以采用‘|’運(yùn)算來(lái)同時(shí)設(shè)置多個(gè) flags 標(biāo)識(shí)。
返回值:0,成功;負(fù)值,失敗。
2 、input_mt_slot  函數(shù)
此函數(shù)用于 Type B 類型,此函數(shù)用于產(chǎn)生 ABS_MT_SLOT 事件,告訴內(nèi)核當(dāng)前上報(bào)的是哪個(gè)觸摸點(diǎn)的坐標(biāo)數(shù)據(jù),此函數(shù)定義在文件 include/linux/input/mt.h 中,函數(shù)原型如下所示:
void input_mt_slot(struct input_dev *dev,
int slot)
函數(shù)參數(shù)和返回值含義如下:
dev: MT 設(shè)備對(duì)應(yīng)的 input_dev。
slot:當(dāng)前發(fā)送的是哪個(gè) slot 的坐標(biāo)信息,也就是哪個(gè)觸摸點(diǎn)。
返回值:無(wú)。
3 、input_mt_report_slot_state  函數(shù)
此 函 數(shù) 用 于 Type B 類 型 , 用 于 產(chǎn) 生 ABS_MT_TRACKING_ID 和 ABS_MT_TOOL_TYPE 事 件 ,ABS_MT_TRACKING_ID 事件給 slot 關(guān)聯(lián)一個(gè) ABS_MT_TRACKING_ID , ABS_MT_TOOL_TYPE 事件指定觸摸類 型(是筆還是手指等)。此函數(shù)定義在文件 drivers/input/input-mt.c 中,此函數(shù)原型如下所示:
void input_mt_report_slot_state( struct input_dev *dev,
unsigned int tool_type,
bool active)
函數(shù)參數(shù)和返回值含義如下:
dev: MT 設(shè)備對(duì)應(yīng)的 input_dev。
tool_type:觸摸類型,可以選擇 MT_TOOL_FINGER(手指)、MT_TOOL_PEN(筆)或MT_TOOL_PALM(手掌),對(duì)于多點(diǎn)電容觸摸屏來(lái)說(shuō)一般都是手指。
active:true,連續(xù)觸摸,input 子系統(tǒng)內(nèi)核會(huì)自動(dòng)分配一個(gè) ABS_MT_TRACKING_ID 給 slot。
false,觸摸點(diǎn)抬起,表示某個(gè)觸摸點(diǎn)無(wú)效了,input 子系統(tǒng)內(nèi)核會(huì)分配一個(gè)-1 給 slot,表示觸摸點(diǎn)溢出。
返回值:無(wú)。
4 、input_report_abs  函數(shù)
TypeA 和 Type B 類 型 都 使 用 此 函 數(shù) 上 報(bào) 觸 摸 點(diǎn) 坐 標(biāo) 信 息 , 通 過(guò) ABS_MT_POSITION_X 和ABS_MT_POSITION_Y 事件實(shí)現(xiàn) X 和 Y 軸坐標(biāo)信息上報(bào)。此函數(shù)定義在文件 include/linux/input.h 中,函數(shù)
原型如下所示:
void input_report_abs( struct input_dev *dev,
unsigned int code,
int value)
函數(shù)參數(shù)和返回值含義如下:
dev: MT 設(shè)備對(duì)應(yīng)的 input_dev。
code:要上報(bào)的是什么數(shù)據(jù),可以設(shè)置為 ABS_MT_POSITION_X 或 ABS_MT_POSITION_Y,也就是 X 軸或者 Y 軸坐標(biāo)數(shù)據(jù)。
value:具體的 X 軸或 Y 軸坐標(biāo)數(shù)據(jù)值。
返回值:無(wú)。
5 、input_mt_report_pointer_emulation  函數(shù)
如果追蹤到的觸摸點(diǎn)數(shù)量多于當(dāng)前上報(bào)的數(shù)量,驅(qū)動(dòng)程序使用 BTN_TOOL_TAP 事件來(lái)通知用戶空間當(dāng)前追蹤到的觸摸點(diǎn)總數(shù)量,然后調(diào)用 input_mt_report_pointer_emulation 函數(shù)將 use_count 參數(shù)設(shè)置為false。否則的話將 use_count 參數(shù)設(shè)置為 true,表示當(dāng)前的觸摸點(diǎn)數(shù)量(此函數(shù)會(huì)獲取到具體的觸摸點(diǎn)數(shù)量,不需要用戶給出),此函數(shù)定義在文件 drivers/input/input-mt.c 中,函數(shù)原型如下:
void input_mt_report_pointer_emulation(struct input_dev *dev,
bool use_count)
函數(shù)參數(shù)和返回值含義如下:
dev: MT 設(shè)備對(duì)應(yīng)的 input_dev。
use_count:true,有效的觸摸點(diǎn)數(shù)量;false,追蹤到的觸摸點(diǎn)數(shù)量多于當(dāng)前上報(bào)的數(shù)量。
返回值:無(wú)。

54.1.6  多點(diǎn)電容觸摸驅(qū)動(dòng)框架
前面幾小節(jié)已經(jīng)詳細(xì)的講解了 linux 下多點(diǎn)觸摸屏驅(qū)動(dòng)原理,本小節(jié)我們來(lái)梳理一下 linux 下多點(diǎn)電容觸摸驅(qū)動(dòng)的編寫框架和步驟。首先確定驅(qū)動(dòng)需要用到哪些知識(shí)點(diǎn),哪些框架?根據(jù)前面的分析,我們?cè)诰帉戲?qū)動(dòng)的時(shí)候需要注意一下幾點(diǎn):
① 多點(diǎn)電容觸摸芯片的接口,一般都為 I2C 接口,因此驅(qū)動(dòng)主框架肯定是 I2C。
② linux 里面一般都是通過(guò)中斷來(lái)上報(bào)觸摸點(diǎn)坐標(biāo)信息,因此需要用到中斷框架。
③ 多點(diǎn)電容觸摸屬于 input 子系統(tǒng),因此還要用到 input 子系統(tǒng)框架。
④ 在中斷處理程序中按照 linux 的 MT 協(xié)議上報(bào)坐標(biāo)信息。
根據(jù)上面的分析,多點(diǎn)電容觸摸驅(qū)動(dòng)編寫框架以及步驟如下:
1 、I2C  驅(qū)動(dòng)框架
驅(qū)動(dòng)總體采用 I2C 框架,參考框架代碼如下所示:
1 /* 設(shè)備樹匹配表 */
2 static const struct i2c_device_id xxx_ts_id[] = {
3 { "xxx", 0, },
4 { /* sentinel */ }
5 };
6
7 /* 設(shè)備樹匹配表 */
8 static const struct of_device_id xxx_of_match[] = {
9 { .compatible = "xxx", },
10 { /* sentinel */ }
11 };
12
13 /* i2c 驅(qū)動(dòng)結(jié)構(gòu)體 */
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 : 驅(qū)動(dòng)入口函數(shù)
27 * @param : 無(wú)
28 * @return : 無(wú)
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 : 驅(qū)動(dòng)出口函數(shù)
41 * @param : 無(wú)
42 * @return : 無(wú)
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");
當(dāng)設(shè)備樹中觸摸 IC 的設(shè)備節(jié)點(diǎn)和驅(qū)動(dòng)匹配以后,第 21 行的 xxx_ts_probe 函數(shù)就會(huì)執(zhí)行,我們可以在此函數(shù)中初始化觸摸 IC,中斷和 input 子系統(tǒng)等。
2摸 、初始化觸摸 IC和 、中斷和 input  子系統(tǒng)
初始化操作都是在 xxx_ts_probe 函數(shù)中完成,參考框架如下所示:
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,申請(qǐng)中斷, */
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 設(shè)備申請(qǐng)與初始化 */
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,注冊(cè) input_dev */
34 input_register_device(input);
35 ......
36 }
第 5~7 行,首先肯定是初始化觸摸芯片,包括芯片的相關(guān) IO,比如復(fù)位、中斷等 IO 引腳,然后就是芯片本身的初始化,也就是配置觸摸芯片的相關(guān)寄存器。
第 9 行,因?yàn)橐话阌|摸芯片都是通過(guò)中斷來(lái)向系統(tǒng)上報(bào)觸摸點(diǎn)坐標(biāo)信息的,因此我們需要初始化中斷。大家可能會(huì)發(fā)現(xiàn)第 9 行并沒(méi)有使用 request_irq 函數(shù)申請(qǐng)中斷,而是采用了 devm_request_threaded_irq 這個(gè)函數(shù),為什么使用這個(gè)函數(shù)呢?是不是 request_irq 函數(shù)不能使用?答案肯定不是的,這里用 request_irq函數(shù)是絕對(duì)沒(méi)問(wèn)題的。那為何要用 devm_request_threaded_irq 呢?這里我們就簡(jiǎn)單的介紹一下這個(gè) API
函數(shù),devm_request_threaded_irq 函數(shù)特點(diǎn)如下:
① 用于申請(qǐng)中斷,作用和 request_irq 函數(shù)類似。
② 此函數(shù)的作用是中斷線程化,大家如果直接在網(wǎng)上搜索“devm_request_threaded_irq”會(huì)發(fā)現(xiàn)相關(guān)解釋很少。但是大家去搜索 request_threaded_irq 函數(shù)就會(huì)有很多講解的博客和帖子,這兩個(gè)函數(shù)在名字上的差別就是前者比后者多了個(gè)“devm_”前綴,“devm_”前綴稍后講解。大家應(yīng)該注意到了
“request_threaded_irq”相比“request_irq”多了個(gè) threaded 函數(shù),也就是線程的意思。那么為什么要中斷線程化呢?我們都是知道硬件中斷具有最高優(yōu)先級(jí),不論什么時(shí)候只要硬件中斷發(fā)生,那么內(nèi)核都會(huì)終止當(dāng)前正在執(zhí)行的操作,轉(zhuǎn)而去執(zhí)行中斷處理程序(不考慮關(guān)閉中斷和中斷優(yōu)先級(jí)的情況),如果中斷非常頻
繁的話那么內(nèi)核將會(huì)頻繁的執(zhí)行中斷處理程序,導(dǎo)致任務(wù)得不到及時(shí)的處理。中斷線程化以后中斷將作為內(nèi)核線程運(yùn)行,而且也可以被賦予不同的優(yōu)先級(jí),任務(wù)的優(yōu)先級(jí)可能比中斷線程的優(yōu)先級(jí)高,這樣做的目的就是保證高優(yōu)先級(jí)的任務(wù)能被優(yōu)先處理。大家可能會(huì)疑問(wèn),前面不是說(shuō)可以將比較耗時(shí)的中斷放到下半
部(bottom half)處理嗎?雖然下半部可以被延遲處理,但是依舊先于線程執(zhí)行,中斷線程化可以讓這些比較耗時(shí)的下半部與進(jìn)程進(jìn)行公平競(jìng)爭(zhēng)。
要注意,并不是所有的中斷都可以被線程化,重要的中斷就不能這么操作。對(duì)于觸摸屏而言只要手指放到屏幕上,它可能就會(huì)一直產(chǎn)生中斷(視具體芯片而定,F(xiàn)T5426 是這樣的),中斷處理程序里面需要通過(guò) I2C讀取觸摸信息并上報(bào)給內(nèi)核,I2C 的速度最大只有 400KHz,算是低速外設(shè)。不斷的產(chǎn)生中斷、讀取觸摸信
息、上報(bào)信息會(huì)導(dǎo)致處理器在觸摸中斷上花費(fèi)大量的時(shí)間,但是觸摸相對(duì)來(lái)說(shuō)不是那么重要的事件,因此可以將觸摸中斷線程化。如果你覺(jué)得觸摸中斷很重要,那么就可以不將其進(jìn)行線程化處理?傊灰獙⒁粋(gè)中斷進(jìn)行線程化處理是需要自己根據(jù)實(shí)際情況去衡量的。
③ 最后來(lái)看一下“devm_”前綴,在 linux 內(nèi)核中有很多的申請(qǐng)資源類的 API 函數(shù)都有對(duì)應(yīng)的“devm_”前綴版本。比如 devm_request_irq 和 request_irq 這兩個(gè)函數(shù),這兩個(gè)函數(shù)都是申請(qǐng)中斷的,我們使用request_irq 函數(shù)申請(qǐng)中斷的時(shí)候,如果驅(qū)動(dòng)初始化失敗的話就要調(diào)用 free_irq 函數(shù)對(duì)申請(qǐng)成功的 irq 進(jìn)行
釋放,卸載驅(qū)動(dòng)的時(shí)候也需要我們手動(dòng)調(diào)用 free_irq 來(lái)釋放 irq。假如我們的驅(qū)動(dòng)里面申請(qǐng)了很多資源,比如:gpio、irq、input_dev,那么就需要添加很多goto 語(yǔ)句對(duì)其做處理,當(dāng)這樣的標(biāo)簽多了以后代碼看起來(lái)就不整潔了!癲evm_”函數(shù)就是為了處理這種情況而誕生的,“devm_”函數(shù)最大的作用就是:
使用“devm_”前綴的函數(shù)申請(qǐng)到的資源可以由系統(tǒng)自動(dòng)釋放,不需要我們手動(dòng)處理。 如果我們使用devm_request_threaded_irq 函數(shù)來(lái)申請(qǐng)中斷,那么就不需要我們?cè)僬{(diào)用 free_irq 函數(shù)對(duì)其進(jìn)行釋放。大家可以注意一下,帶有“devm_”前綴的都是一些和設(shè)備資源管理有關(guān)的函數(shù)。關(guān)于“devm_”函數(shù)的實(shí)現(xiàn)原理這里就不做詳細(xì)的講解了,我們的重點(diǎn)在于學(xué)會(huì)如何使用這些 API 函數(shù),感興趣的可以查閱一些其他文檔或者帖子來(lái)看一下“devm_”函數(shù)的實(shí)現(xiàn)原理。
第 15 行,接下來(lái)就是申請(qǐng) input_dev,因?yàn)槎帱c(diǎn)電容觸摸屬于 input 子系統(tǒng)。這里同樣使用devm_input_allocate_device 函數(shù)來(lái)申請(qǐng) input_dev,也就是我們前面講解的 input_allocate_device 函數(shù)加“devm_”前綴版本。申請(qǐng)到 input_dev 以后還需要對(duì)其進(jìn)行初始化操作。
第 23~24 行,設(shè)置 input_dev 需要上報(bào)的事件為 EV_ABS 和 BTN_TOUCH,因?yàn)槎帱c(diǎn)電容屏的觸摸坐標(biāo)為絕對(duì)值,因此需要上報(bào) EV_ABS 事件。觸摸屏有按下和抬起之分,因此需要上報(bào) BTN_TOUCH 按鍵。
第 26~29 行,調(diào)用 input_set_abs_params 函數(shù)設(shè)置 EV_ABS 事件需要上報(bào) ABS_X、ABS_Y、ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y。單點(diǎn)觸摸需要上報(bào) ABS_X 和 ABS_Y,對(duì)于多點(diǎn)觸摸需要上報(bào) ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y。
第 30 行,調(diào)用 input_mt_init_slots 函數(shù)初始化多點(diǎn)電容觸摸的 slots。
第 34 行,調(diào)用 input_register_device 函數(shù)系統(tǒng)注冊(cè)前面申請(qǐng)到的 input_dev。
3 、上報(bào)坐標(biāo)信息
最后就是在中斷服務(wù)程序中上報(bào)讀取到的坐標(biāo)信息,根據(jù)所使用的多點(diǎn)電容觸摸設(shè)備類型選擇使用TypeA 還是 Type B 時(shí)序。由于大多數(shù)的設(shè)備都是 Type B 類型,因此這里就以 Type B 類型為例講解一下上報(bào)過(guò)程,參考驅(qū)動(dòng)框架如下所示:
1 static irqreturn_t xxx_handler(int irq, void *dev_id)
2 {
3
4 int num; /* 觸摸點(diǎn)數(shù)量 */
5 int x[n], y[n]; /* 保存坐標(biāo)值 */
6
7 /* 1、從觸摸芯片獲取各個(gè)觸摸點(diǎn)坐標(biāo)值 */
8 ......
9
10 /* 2、上報(bào)每一個(gè)觸摸點(diǎn)坐標(biāo) */
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 }
進(jìn)入中斷處理程序以后首先肯定是從觸摸 IC 里面讀取觸摸坐標(biāo)以及觸摸點(diǎn)數(shù)量,假設(shè)觸摸點(diǎn)數(shù)量保存到 num 變量,觸摸點(diǎn)坐標(biāo)存放到 x,y 數(shù)組里面。
第 11~16 行,循環(huán)上報(bào)每一個(gè)觸摸點(diǎn)坐標(biāo),一定要按照 Type B 類型的時(shí)序進(jìn)行。
第 19 行,每一輪觸摸點(diǎn)坐標(biāo)上報(bào)完畢以后就調(diào)用一次 input_sync 函數(shù)發(fā)送一個(gè) SYN_REPORT 事件。
關(guān)于多點(diǎn)電容觸摸驅(qū)動(dòng)框架就講解到這里,接下來(lái)我們就實(shí)際編寫一個(gè)多點(diǎn)電容觸摸驅(qū)動(dòng)程序。

本文地址:http://m.54549.cn/thread-748976-1-1.html     【打印本頁(yè)】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問(wèn)題,我們將根據(jù)著作權(quán)人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評(píng)論 登錄 | 立即注冊(cè)

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號(hào) | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表