一、分層
驅(qū)動(dòng)層:輸入設(shè)備的具體驅(qū)動(dòng)程序,向內(nèi)核層報(bào)告輸入內(nèi)容
核心層:為驅(qū)動(dòng)層提供輸入設(shè)備的注冊和操作接口,通知事件層對輸入事件進(jìn)行處理
事件層:和用戶空間進(jìn)行交互
input子系統(tǒng)所有的設(shè)備主設(shè)備號都是13,在使用input系統(tǒng)的時(shí)候不需要去注冊字符設(shè)備,只需要向系統(tǒng)申請一個(gè)input_device即可
二、流程
2.1注冊input_device
input設(shè)備由input_dev結(jié)構(gòu)體表示,定義在include/linux/input.h中
①使用input_allocate_device函數(shù)申請一個(gè)input_dev
返回值:申請到的input_dev
②初始化input_dev的事件類型和事件值
也就是初始化input_dev結(jié)構(gòu)體
③使用input_register_device函數(shù)向系統(tǒng)注冊input_dev
dev:要注冊的input_dev
返回值:0成功,負(fù)值失敗
④注銷注冊的input_dev
⑤釋放申請的input_dev
2.2上報(bào)輸入事件
用于上報(bào)指定的事件和事件值
dev:需要上報(bào)的input_dev
type:上報(bào)的事件類型,如EV_KEY
code:事件碼,比如KEY_0
value:事件值,比如1表示按鍵按下
還有其他API函數(shù):
2.3上報(bào)同步事件
三、input_event結(jié)構(gòu)體
表示所有的輸入事件,定義在include/uapi/linux/input.h中,用戶程序通過input_event獲取到具體的事件和相關(guān)值
time:事件發(fā)生的事件
type:事件類型
code:事件碼
value:值
四、三種設(shè)置事件的方法
五、調(diào)試
cat /proc/bus/input/devices能夠查看輸入設(shè)備的具體信息。
六、input子系統(tǒng)架構(gòu)
input子系統(tǒng)分為三個(gè)部分:input設(shè)備驅(qū)動(dòng)層,input 核心層,input 事件處理層。
input設(shè)備驅(qū)動(dòng)層是接近硬件的一層,負(fù)責(zé)獲取輸入設(shè)備的輸入數(shù)據(jù)和上報(bào)數(shù)據(jù),對應(yīng)的就是我們寫的各種設(shè)備驅(qū)動(dòng),比如觸摸屏。
input核心層是內(nèi)核自帶的一層,負(fù)責(zé)給input設(shè)備驅(qū)動(dòng)層和input 事件處理層提供服務(wù)接口,是兩者的橋梁。
input 事件處理層負(fù)責(zé)給提供一個(gè)個(gè)input_event形式的消息給應(yīng)用層,代表的數(shù)據(jù)結(jié)構(gòu)是input_handler,代表的文件是evdev.c。
input 核心層
在/driver/input/input.c中,使用subsys_initcall進(jìn)行input核心層的注冊。
1.注冊input_class設(shè)備類,表現(xiàn)形式是在/sys/class下創(chuàng)建目錄”input”
2.初始化input相關(guān)的/proc結(jié)構(gòu),表現(xiàn)形式是在/proc中創(chuàng)建bus/input/devices和bus/input/devices
3.注冊主設(shè)備號為13,次設(shè)備號從0開始的1024個(gè)設(shè)備。(13,0)-(13,1023),都使用同一套file_operations操作集。
input_dev注冊
在設(shè)備驅(qū)動(dòng)層,注冊一個(gè)input設(shè)備驅(qū)動(dòng)需要三個(gè)步驟。
1.使用input_allocate_device申請一個(gè)input_dev實(shí)例(內(nèi)存)
2.設(shè)置input設(shè)備的能力,比如支持什么事件?支持這個(gè)事件下的什么功能?表征這個(gè)功能的狀態(tài)?分別對應(yīng)的就是input_event消息的type,code,value。
3.使用input_register_device注冊一個(gè)input_dev.
下面看看注冊input_dev做了什么,內(nèi)核是如何管理的。
input_dev數(shù)據(jù)結(jié)構(gòu)
~~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;
};