目录
输入子系统的简介
输入子系统的组成部分:
输入子系统的工作流程
输入子系统的优势和作用
设备树相关API函数
注册输入子系统
取消输入子系统的注册
输入子系统核心结构体的初始化
释放输入子系统的核心结构体
输入子系统事件上报
按键事件的上报
上报事件的同步
相关例程
例程简介
例程分享
Linux内核的输入子系统(Input Subsystem)主要用于处理各种输入设备的报告,并将其转换为通用的相关的事件上传给用户空间。
1. 抽象化
输入子系统实现了底层输入设备与上层输入处理之间的抽象,通过统一的接口使两者解耦,上层只需要处理通用的输入事件,不关心具体是哪种输入设备。
2. 统一处理
对各类输入设备的报告进行统一格式的封装,然后由通用的输入核心进行处理,简化上层逻辑。
3. 热插拔支持
支持输入设备的热插拔,并动态感知新增设备或移除设备,自动处理输入设备的添加和删除。
4. 输入设备模型
构建输入设备的模型,管理输入设备的属性、capable信息等,通过sysfs接口导出到用户空间。
5. 支持多种设备
keyboard, mouse, touchscreen, joystick等很多种类的输入设备可以通过输入子系统统一处理。
6. 灵活性好
通过不同的映射表,一个输入事件可以很容易映射到不同的键值,为不同需求提供支持。
总体来说,输入子系统很好地抽象和封装了底层输入设备,简化了输入处理逻辑,提高了Linux系统的移植性,也使得上层应用程序的输入支持更加灵活方便。输入子系统屏蔽了不同设备的差异,为用户空间提供统一的输入抽象,使得上层应用可以独立于具体设备实现。
头文件
linux/input.h
原型
int input_register_device(struct input_dev *dev)
参数
struct input_dev *dev 输入子系统的核心结构体
返回值
成功 0
失败 负数
struct input_dev {
const char *name; 名字 会出现在sys目录下
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; 支持的事件的类型
#define EV_SYN (0x00) //同步事件,用于同步多个输入事件的状态,例如在一次事件序列中标记事件的开始和结束。
#defineEV_KEY (0x01) //按键事件,用于表示按键的按下和松开。
#defineEV_REL (0x02) //相对事件,用于表示相对输入设备的移动,例如鼠标的相对位移。
#defineEV_ABS (0x03) //绝对事件,用于表示绝对输入设备的位置,例如触摸屏的绝对坐标。
#define EV_MSC (0x04) //杂项事件,用于表示一些杂项的事件,例如时间戳。
#define EV_SW (0x05) //开关事件,用于表示开关类设备的状态变化。
#define EV_LED (0x11) //LED事件,用于表示LED灯的状态变化。
#define EV_SND (0x12) //声音事件,用于表示声音设备的状态变化。
#define EV_REP (0x14) //重复事件,用于表示按键的重复事件或永久事件。
#define EV_FF (0x15) //力反馈事件,用于表示力反馈设备的事件。
#define EV_PWR (0x16) //电源事件,用于表示电源设备的状态变化。
#define EV_FF_STATUS (0x17) //力反馈状态事件,用于表示力反馈设备的状态变化。
#define EV_MAX (0x1f) //事件类型的最大值。
#define EV_CNT (EV_MAX+1) //事件类型的数量,用于表示事件类型的总数。 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; 支持的按键 一一对应 set_bit()
}
输入子系统的核心结构体不能直接定义,必须要借助于内核提供的核心结构体的初始化的函数
头文件
linux/input.h
原型
void input_unregister_device(struct input_dev *dev)
参数
struct input_dev *dev 输入子系统的核心结构体
返回值
无
头文件
linux/input.h
原型
struct input_dev *input_allocate_device(void)
参数
无
返回值
成功 核心结构体的指针
失败 NULL
头文件
linux/input.h
原型
void input_free_device(struct input_dev *dev);
参数
struct input_dev *dev 输入子系统的核心结构体
返回值
无
头文件
linux/input.h
原型
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
参数
struct input_dev *dev 核心结构体
unsigned int type 事件的类型
unsigned int code 具体哪一个设备
int value 上报的真实的值
返回值
无
头文件
linux/input.h
原型
void input_report_key(struct input_dev *dev, unsigned int code, int value)
参数
struct input_dev *dev 输入子系统的核心结构体
unsigned int code 哪一个按键
int value 1 按下 0松开
无
头文件
linux/input.h
原型
void input_sync(struct input_dev *dev)
参数
struct input_dev *dev 输入子系统
返回值
无
这个输入子系统的例程实现了对一个按键的支持,主要功能包括:
通过中断检测按键动作,在经过过滤消抖后,上报按键事件到输入子系统。输入子系统会负责发送这些事件到用户空间,交给相关任务处理。
#include
#include
#include
#include
#include
#include
#include
#include
struct input_dev *myinput = NULL;
int irq_num;
struct timer_list mytimer;
/*定时器的回调函数,用于判断按键是否真的按下*/
void mytimer_func(unsigned long data){
if(gpio_get_value(EXYNOS4_GPX3(2)) == 0){ //获取按键状态
input_report_key(myinput, KEY_1, 1); //按键事件上报
}
else{
input_report_key(myinput, KEY_1, 0);
}
//上报事件的同步
input_sync(myinput);
}
/*中断回调函数*/
irqreturn_t myirq_func(int num, void * data){
//启动定时器,延时15ms,用于消抖
mod_timer(&mytimer, jiffies + msecs_to_jiffies(15));
return 0;
}
/*驱动设备的加载函数*/
static int __init myinput_init(void){
int ret;
//初始化输入子系统的核心结构体
myinput = input_allocate_device();
myinput->name = "yyy";
//向内核注册输入子系统
set_bit(EV_KEY, myinput->evbit); //按键事件
set_bit(EV_REP, myinput->evbit); //重复事件
set_bit(KEY_1, myinput->keybit);
ret = input_register_device(myinput);
//获取中断号
irq_num = gpio_to_irq(EXYNOS4_GPX3(2));
//使能中断号
enable_irq(irq_num);
//向内核注册中断号
ret = request_irq(irq_num, myirq_func, IRQ_TYPE_EDGE_BOTH, "my_input", NULL);
//初始化定时器
mytimer.expires = jiffies + 1 * HZ;
mytimer.function = mytimer_func;
init_timer(&mytimer);
return 0;
}
/*驱动设备的卸载*/
static void __exit myinput_exit(void){
//取消注册
input_unregister_device(myinput);
}
module_init(myinput_init);
module_exit(myinput_exit);
MODULE_LICENSE("GPL");