input子系统驱动代码分析
下面的代码是使用input子系统框架实现了按键输入检测的驱动程序
/*
* jz2440 buttons driver
**/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/input.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
static struct input_dev *buttons_dev;
static struct timer_list buttons_timer; /* 该变量不能直接定义为指针变量,否则在init_timer()中传入使用时,因为传入的是空指针系统报错 */
static struct button_irq_desc{
int irq; /* 中断号 */
unsigned long flags; /* 中断标志,用来定义中断的触发方式 */
char *name; /* 中断名称 */
unsigned int pin; /* 引脚 */
unsigned int key_val;/* 键值 */
};
static struct button_irq_desc button_irqs[] = {
{IRQ_EINT0, IRQT_BOTHEDGE, "KEY1", S3C2410_GPF0, KEY_L}, /* S2 */
{IRQ_EINT2, IRQT_BOTHEDGE, "KEY2", S3C2410_GPF2, KEY_S}, /* S3 */
{IRQ_EINT11, IRQT_BOTHEDGE, "KEY3", S3C2410_GPG3, KEY_ENTER}, /* S4 */
{IRQ_EINT19, IRQT_BOTHEDGE, "KEY4", S3C2410_GPG11, KEY_LEFTSHIFT}, /* S5 */
};
static struct button_irq_desc *pin_desc;
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
pin_desc = (struct button_irq_desc *)dev_id;
/* 10ms后启动定时器 */
mod_timer(&buttons_timer, jiffies+HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
static void buttons_timer_function(unsigned long data)
{
unsigned int pinval;
if (!pin_desc)
return;
/* 获取对应引脚的值 */
pinval = s3c2410_gpio_getpin(pin_desc->pin);
if (pinval)
{
/* 松开 : 最后一个参数: 0-松开, 1-按下 */
input_event(buttons_dev, EV_KEY, pin_desc->key_val, 0);
input_sync(buttons_dev);
}
else
{
/* 按下 */
input_event(buttons_dev, EV_KEY, pin_desc->key_val, 1);
input_sync(buttons_dev);
}
}
static int __init s3c2440_buttons_init(void)
{
int error, i;
/* 1. 分配一个input_dev结构体 */
buttons_dev = input_allocate_device();
if (!buttons_dev)
return -ENOMEM;
/* 2. 设置 */
/* 设置能产生哪类事件 */
set_bit(EV_KEY, buttons_dev->evbit); /* 可以产生按键类事件 */
set_bit(EV_REP, buttons_dev->evbit); /* 可以产生重复类事件 */
/* 设置能产生这类事件中的哪些事件:L, S, ENTER, LEFTSHIFT */
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. 注册 */
error = input_register_device(buttons_dev);
if (error) {
printk(KERN_ERR "Unable to register buttons input device\n");
goto fail;
}
/* 4. 硬件相关的操作 */
/* 注册一个定时器用于按键消抖 */
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
/* 申请中断 */
for(i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++){
request_irq(button_irqs[i].irq, buttons_interrupt, button_irqs[i].flags, button_irqs[i].name, &button_irqs[i]);
}
return 0;
fail:
input_free_device(buttons_dev);
return error;
}
static void __exit s3c2440_buttons_exit(void)
{
int i;
/* 释放中断 */
for(i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++){
free_irq(button_irqs[i].irq, &button_irqs[i]);
}
/* 删除定时器 */
del_timer(&buttons_timer);
input_unregister_device(buttons_dev);
input_free_device(buttons_dev);
}
module_init(s3c2440_buttons_init);
module_exit(s3c2440_buttons_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jason.tian");
MODULE_VERSION("0.0.1");
MODULE_DESCRIPTION("S3C2440 buttons Driver");
按照上述代码总结input子系统驱动程序操作步骤如下:
分配一个input_dev结构体(使用input_allocate_device()函数);
对input_dev结构体成员进行设置;
设置能产生哪类事件,例如:
set_bit(EV_KEY, buttons_dev->evbit); /* 可以产生按键类事件 */ set_bit(EV_REP, buttons_dev->evbit); /* 可以产生重复类事件 */
设置能产生这类事件中的哪些事件,例如:
/* 设置能产生这类事件中的哪些事件:L, S, ENTER, LEFTSHIFT */ 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);
注册(使用input_register_device()函数注册);
硬件相关的操作;
当有数据产生后,使用input_event()函数进行上报,并使用input_sync()函数产生一个同步信号;