linux輸入子系統就是乙個基於分層模式的系統,其基本的層次分解如下圖所示。
在圖中我們可以發現輸入子系統主要包括三個部分裝置驅動層(input driver)、核心層(input core)和輸入事件驅動層。輸入子系統的劃分使得輸入裝置的驅動程式設計越來越簡單,但是其中的思想採用我們學習的重點和難點。
input子系統處理輸入事務,任何輸入裝置的驅動程式都可以通過input輸入子系統提供的介面註冊到核心,利用子系統提供的功能來與使用者空間互動。輸入裝置一般包括鍵盤,滑鼠,觸控螢幕等,在核心中都是以輸入裝置出現的。下面分析input輸入子系統的結構,以及功能實現。
1. input子系統是分層結構的,總共分為三層: 硬體驅動層,子系統核心層,事件處理層。
(1)、其中硬體驅動層負責操作具體的硬體裝置,這層的**是針對具體的驅動程式的,需要驅動程式的作者來編寫。
(2)、子系統核心層是鏈結其他兩個層之間的紐帶與橋梁,向下提供驅動層的介面,向上提供事件處理層的介面。
(3)、事件處理層負責與使用者程式打交道,將硬體驅動層傳來的事件報告給使用者程式。
2. 各層之間通訊的基本單位就是事件,任何乙個輸入裝置的動作都可以抽象成一種事件,如鍵盤的按下,觸控螢幕的按下,滑鼠的移動等。事件有三種屬性:型別(type),編碼(code),值(value),input子系統支援的所有事件都定義在input.h中,包括所有支援的型別,所屬型別支援的編碼等。事件傳送的方向是 硬體驅動層-->子系統核心-->事件處理層-->使用者空間。
在驅動程式設計中,我們對於裝置的驅動設計主要集中在裝置驅動層的實現,但是這與之前的裝置驅動開發存在較大的差別,主要是因為裝置驅動不再是編寫基本操作的實現過程,也就是不在是對struct file_operations 這個結構體物件的填充和實現。在輸入裝置驅動中的主要實現包括下面幾個過程:
1、分配乙個輸入裝置物件。並完成響應結構體元素的填充,主要包括支援的事件型別和事件代號等。
分配物件的函式:
struct input_dev *input_allocate_device(void);
釋放物件函式:
void input_free_device(struct input_dev *dev);
設定支援的事件型別和事件**:
通常採用set_bit函式實現:
設定支援的事件型別(支援按鍵事件)
set_bit(ev_key,input_dev->evbit);
設定支援的事件**(支援按鍵1)
set_bit(key_1, input_dev->keybit);
2、完成輸入裝置物件的註冊,將裝置物件註冊到輸入子系統當中去,當然也有對應的釋放函式。
註冊裝置到核心:
int input_register_device(struct input_dev *dev);
登出裝置:
void input_unregister_device(struct input_dev *dev);
3、向核心層(input core)匯報事件的發生以及傳輸事件型別和事件**等。這一部分通常是採用中斷的方法實現,在中斷中向上一層次(input core)傳送發生事件的事件型別、事件代號以及事件對應的值等。但是上報的內容結構體都是基於乙個固定結構體的
struct input_event,在使用者空間也可以採用這個結構體實現對事件的訪問。
structinput_event ;/
*埠集合*
/static const
int gpios[numbers_buttons]=;
/*事件代號集合*
/static const
int keys[numbers_buttons]=;
/*中斷處理程式*
/static irqreturn_t button_interrupt(
int irq,void* p)}/
*返回值*
/return irq_retval(irq_handled);}
/*裝置初始化函式*
/static int __init tq2440_button_init(void)
/*設定相應的事件處理型別,按鍵事件*
/set_bit(ev_key,button_dev-
>evbit);/
*申請中斷*
/for
(i= 0; i < numbers_buttons;
++ i)
/*裝置名,防止出現錯誤*
/button_dev-
>name= input_name;
/*註冊輸入裝置*
/err
= input_register_device(button_dev);if
(err
)printk(
"initialized\n");
return 0;
/*錯誤處理*
/err_free_dev:
/*登出裝置*
/input_unregister_device(button_dev)
;return err;}
/*裝置退出函式*
/static void __exit tq2440_button_exit(void)}/
*載入和解除安裝*
/module_init(tq2440_button_init)
;module_exit(tq2440_button_exit);/
*license和作者資訊*
/module_license(
"gpl");
module_author(
"gp-");
測試**:
#include
#include
#include
#include
#include
#include
#include
/*事件結構體*
/struct input_event buff;
int main(
int argc,char *
*argv)
while
(1)}
close(fd)
;exit
(0);}
測試效果:
從效果上來看,**基本上實現了按鍵的識別,但是該驅動程式的問題是按鍵並不能實現消抖操作。
蛻變成蝶 Linux裝置驅動之按鍵裝置驅動
在上述的驅動系列部落格中,我們已經了解了關於阻塞和非阻塞 非同步通知 輪詢 記憶體和i o口訪問 併發控制等知識,按鍵裝置驅動相對來說是比較簡單的,本章內容可以加深我們對字元裝置驅動架構 阻塞與非阻塞 中斷定時器等相關知識的理解。在嵌入式的系統中,按鍵的硬體原理簡單,就是通過乙個上拉電阻將處理器的外...
Linux裝置驅動之《字元裝置驅動》
linux裝置中最大的特點就是裝置操作猶如檔案操作一般,在應用層看來,硬體裝置只是乙個裝置檔案。應用程式可以像操作檔案一樣對硬體裝置進行操作,如open close read write 等。下面是乙個字元裝置驅動程式的簡單實現test.c 模組分析 1.初始化裝置驅動的結構體 struct fil...
Linux裝置驅動之字元裝置驅動
一 linux裝置的分類 linux系統將裝置分成三種基本型別,每個模組通常實現為其中某一類 字元模組 塊模組或網路模組。這三種型別有 字元裝置 字元裝置是個能夠像位元組流 類似檔案 一樣被訪問的裝置,由字元裝置驅動程式來實現這種特性。字元裝置可以通過檔案系統節點來訪問,比如 dev tty1等。這...