一、分层
驱动层:输入设备的具体驱动程序,向内核层报告输入内容
核心层:为驱动层提供输入设备的注册和操作接口,通知事件层对输入事件进行处理
事件层:和用户空间进行交互
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;
};