一、分層
驅動層:輸入設備的具體驅動程序,向內核層報告輸入內容
核心層:為驅動層提供輸入設備的注冊和操作接口,通知事件層對輸入事件進行處理
事件層:和用戶空間進行交互
input子系統所有的設備主設備號都是13,在使用input系統的時候不需要去注冊字符設備,只需要向系統申請一個input_device即可
二、流程
2.1注冊input_device
input設備由input_dev結構體表示,定義在include/linux/input.h中
①使用input_allocate_device函數申請一個input_dev
返回值:申請到的input_dev
②初始化input_dev的事件類型和事件值
也就是初始化input_dev結構體
③使用input_register_device函數向系統注冊input_dev
dev:要注冊的input_dev
返回值:0成功,負值失敗
④注銷注冊的input_dev
⑤釋放申請的input_dev
2.2上報輸入事件
用于上報指定的事件和事件值
dev:需要上報的input_dev
type:上報的事件類型,如EV_KEY
code:事件碼,比如KEY_0
value:事件值,比如1表示按鍵按下
還有其他API函數:
2.3上報同步事件
三、input_event結構體
表示所有的輸入事件,定義在include/uapi/linux/input.h中,用戶程序通過input_event獲取到具體的事件和相關值
time:事件發生的事件
type:事件類型
code:事件碼
value:值
四、三種設置事件的方法
五、調試
cat /proc/bus/input/devices能夠查看輸入設備的具體信息。
六、input子系統架構
input子系統分為三個部分:input設備驅動層,input 核心層,input 事件處理層。
input設備驅動層是接近硬件的一層,負責獲取輸入設備的輸入數據和上報數據,對應的就是我們寫的各種設備驅動,比如觸摸屏。
input核心層是內核自帶的一層,負責給input設備驅動層和input 事件處理層提供服務接口,是兩者的橋梁。
input 事件處理層負責給提供一個個input_event形式的消息給應用層,代表的數據結構是input_handler,代表的文件是evdev.c。
input 核心層
在/driver/input/input.c中,使用subsys_initcall進行input核心層的注冊。
1.注冊input_class設備類,表現形式是在/sys/class下創建目錄”input”
2.初始化input相關的/proc結構,表現形式是在/proc中創建bus/input/devices和bus/input/devices
3.注冊主設備號為13,次設備號從0開始的1024個設備。(13,0)-(13,1023),都使用同一套file_operations操作集。
input_dev注冊
在設備驅動層,注冊一個input設備驅動需要三個步驟。
1.使用input_allocate_device申請一個input_dev實例(內存)
2.設置input設備的能力,比如支持什么事件?支持這個事件下的什么功能?表征這個功能的狀態?分別對應的就是input_event消息的type,code,value。
3.使用input_register_device注冊一個input_dev.
下面看看注冊input_dev做了什么,內核是如何管理的。
input_dev數據結構
~~struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long propbit[~~BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
unsigned int hint_events_per_packet;
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode);
int (*getkeycode)(struct input_dev *dev,
struct input_keymap_entry *ke);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int rep[REP_CNT];
struct input_mt *mt;
struct input_absinfo *absinfo;
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle __rcu *grab;
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
struct device dev;
struct list_head h_list;
struct list_head node;
unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;
bool devres_managed;
};