linux输入子系统
本篇文章通过按键驱动为例讲解输入子系统的开发流程。
输入子系统由驱动层、输入子系统核心、事件处理层三部分组成。一个输入事件,如鼠标移动、键盘按下等通过Driver->Inputcore->Event handler->userspace的顺序到达用户控件的应用程序。
用于报告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_event函数上报事件。
set_bit告诉input输入子系统支持哪些事件,哪些按键。
事件类型包括EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等。
变量定义及初始化
struct pin_desc{ int irq; char *name; unsigned int pin; unsigned int key_val; }; struct pin_desc pins_desc[4] = { {IRQ_EINT0, "S2", S3C2410_GPF0, KEY_L}, {IRQ_EINT2, "S3", S3C2410_GPF2, KEY_S}, {IRQ_EINT11, "S4", S3C2410_GPG3, KEY_ENTER}, {IRQ_EINT19, "S5", S3C2410_GPG11, KEY_LEFTSHIFT}, }; static struct input_dev *buttons_dev; static struct pin_desc *irq_pd; static struct timer_list buttons_timer;
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设置能产生这类操作里的哪些事件
set_bit(KEY_L, 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(&buttosn_timer); buttons_timer.function = buttons_timer_function; add_timer(&buttons_timer);
5.申请按键中断
for (i=0;i<4;i++) { request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]); }
6.中断处理函数,在中断中保存当前按下按键的信息,并打开定时器
static irqreturn_t buttons_irq(int irq, void *dev_id) { irq_pd = (struct pin_desc*)dev_id; mod_timer(&buttons_timer, jiffies + HZ/100); return IRQ_RETVAL(IRQ_HANDLed); }
7.定时器中断,用于消除按键抖动,上报事件
static void buttons_timer_function(unsigned long data) { struct pin_desc *pindesc = irq_pd; unsigned int pinval; if (!pindesc) { return; } pinval = s3c2410_gpio_getpin(pindesc->pin); if (pinval) { /* 松开 */ input_event(buttons_dev, EV_KEY, pindesc->key_val, 0);//上报事件 input_sync(buttons_dev); //同步用于告诉input core子系统报告结束 } else { /* 按下 */ input_event(buttons_dev, EV_KEY, pindesc->key, 1); input_sync(buttons_dev); } }