输入子系统概念介绍
输入子系统框架
struct pin_desc pins_desc[4] = { {IRQ_EINT(26), "S2", EXYNOS4_GPX3(2), KEY_L}, {IRQ_EINT(27), "S3", EXYNOS4_GPX3(3), KEY_S}, {IRQ_EINT(28), "S4", EXYNOS4_GPX3(4), KEY_ENTER}, {IRQ_EINT(29), "S5", EXYNOS4_GPX3(5), KEY_LEFTSHIFT}, };
由这里知道 k1->KEY_L k2->KEY_S k3->KEY_ENTER
// cat /proc/bus/input/devices 列出当前系统下注册的所有输入设备 /* 测试方法,将当前终端的标准输入重定向到驱动框架所产生的tty设备上 * exec 0</dev/tty1 */
首先输入:cat /dev/tty1
设备描述:input_dev结构 struct input_dev中有两个成员为:evbit:、keybit: evbit: 事件类型(包括EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等) keybit: 按键类型(当事件类型为EV_KEY时包括BTN_LEFT,BTN_0,BTN_1,BTN_MIDDLE等) 实现设备驱动核心工作是:向系统报告按键、触摸屏等输入事件(event,通过input_event结构描述),不再需要关心文件操作接口。驱动报告事件经过inputCore和Eventhandler到达用户空间。 注册输入设备函数: int input_register_device(struct input_dev *dev) 注销输入设备函数: void input_unregister_device(struct input_dev *dev) 驱动实现——初始化(事件支持):set_bit()告诉input输入子系统支持哪些事件,哪些按键。例如: set_bit(EV_KEY,button_dev.evbit) (其中button_dev是struct input_dev类型) 驱动实现——报告事件: input_event(buttons_dev, EV_KEY, pindesc->key_val, 0); 或者: 用于报告EV_KEY,EV_REL,EV_ABS事件的函数分别为 void input_report_key(struct input_dev *dev,unsigned int code,int value) void input_report_rel(struct input_dev *dev,unsigned int code,int value) void input_report_abs(struct input_dev *dev,unsigned int code,int value) 驱动实现——报告结束: input_sync()同步用于告诉input core子系统报告结束。 通过input 输入子系统,具体的输入设备驱动只需要完成如下工作: 1、在模块加载函数中告知input子系统它可以报告的事件: 设备驱动通过set_bit()告诉input子系统它支持哪些事件: set_bit(EV_KEY,button_dev.evbit) 2、在模块加载设备函数中注册输入设备。 注册输入设备的函数为:int input_register_device(struct input_dev *dev) 3、驱动实现——报告事件:input_event(buttons_dev, EV_KEY, pindesc->key_val, 0); 4、 事件同步,告知事件的接受者驱动已经发出了一个完整的报告;input_sync() 5、在模块卸载函数中注销输入设备: 注销输入设备函数: void input_unregister_device(struct input_dev *dev)
代码
/* 参考drivers\input\keyboard\gpio_keys.c */ #include <linux/module.h> #include <linux/version.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/sched.h> #include <linux/pm.h> #include <linux/sysctl.h> #include <linux/proc_fs.h> #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/input.h> #include <linux/irq.h> #include <asm/gpio.h> #include <asm/io.h> #include <linux/timer.h> /*timer*/ #include <asm/uaccess.h> /*jiffies*/ //#include <asm/arch/regs-gpio.h> struct pin_desc{ int irq; char *name; unsigned int pin; unsigned int key_val; }; struct pin_desc pins_desc[4] = { {IRQ_EINT(26), "S2", EXYNOS4_GPX3(2), KEY_H}, {IRQ_EINT(27), "S3", EXYNOS4_GPX3(3), KEY_S}, {IRQ_EINT(28), "S4", EXYNOS4_GPX3(4), KEY_ENTER}, {IRQ_EINT(29), "S5", EXYNOS4_GPX3(5), KEY_LEFTSHIFT}, }; static struct input_dev *buttons_dev; static struct pin_desc *irq_pd; static struct timer_list buttons_timer; static irqreturn_t buttons_irq(int irq, void *dev_id) { /* 10ms后启动定时器 */ irq_pd = (struct pin_desc *)dev_id; mod_timer(&buttons_timer, jiffies+HZ/100); return IRQ_RETVAL(IRQ_HANDLED); } static void buttons_timer_function(unsigned long data) { struct pin_desc * pindesc = irq_pd; unsigned int pinval; if (!pindesc) return; pinval = gpio_get_value(pindesc->pin); if (pinval) { /* 松开 : 最后一个参数: 0-松开, 1-按下 */ input_event(buttons_dev, EV_KEY, pindesc->key_val, 0); input_sync(buttons_dev); } else { /* 按下 */ input_event(buttons_dev, EV_KEY, pindesc->key_val, 1); input_sync(buttons_dev); } } static int buttons_init(void) { int i; /* 1. 分配一个input_dev结构体 */ buttons_dev = input_allocate_device();; /* 2. 设置 */ /* 2.1 能产生哪类事件 */ set_bit(EV_KEY, buttons_dev->evbit); //按住按键不放的话就连续输入 set_bit(EV_REP, buttons_dev->evbit); /* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */ set_bit(KEY_H, buttons_dev->keybit); set_bit(KEY_S, buttons_dev->keybit); set_bit(KEY_ENTER, buttons_dev->keybit); set_bit(KEY_LEFTSHIFT, buttons_dev->keybit); /* 3. 注册 */ input_register_device(buttons_dev); /* 4. 硬件相关的操作 */ init_timer(&buttons_timer); buttons_timer.function = buttons_timer_function; add_timer(&buttons_timer); for (i = 0; i < 4; i++) { request_irq(pins_desc[i].irq, buttons_irq, (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING), pins_desc[i].name, &pins_desc[i]); } return 0; } static void buttons_exit(void) { int i; for (i = 0; i < 4; i++) { free_irq(pins_desc[i].irq, &pins_desc[i]); } del_timer(&buttons_timer); input_unregister_device(buttons_dev); input_free_device(buttons_dev); } module_init(buttons_init); module_exit(buttons_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("xiangtan da xue chenhaipan"); MODULE_VERSION("2017.5.4");