1、程序
在上一节中介绍了Linux内核中的输入子系统的框架,在对输入子系统框架有了大概的了解之后,这一节来实际的编写代码,加深对输入子系统的理解,
在写程序之前先来梳理一下,使用输入子系统编写程序的步骤
1、最开始肯定是要注册一个代表物理硬件的input_device,这样的话,在内核成功识别之后才能对我们需要操作
的设备进行操作,
2、提供对应的硬件操作函数
可以看出,在使用这个框架来编写程序之后,我们需要做的事情其实就已经很少了,下面来完成使用开发板上的按键模拟键盘的效果,只写关键性的代码
//定义全局变量
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;
//入口函数
static int buttons_init(void)
{
/* 1. 分配一个input_dev结构体 */
buttons_dev = input_allocate_device();
/* 2. 设置 */
/* 能产生哪类事件(按键类和重复类) */
set_bit(EV_KEY, buttons_dev->evbit);
set_bit(EV_REP, buttons_dev->evbit);
/* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
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(&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, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]);
}
return 0;
}
//出口函数
static void buttons_exit(void)
{
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);
}
//按键中断函数,在该函数里将定时器的超时时间进行延迟
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 = s3c2410_gpio_getpin(pindesc->pin);
if (pinval)
{
/*
使用input_event上报事件
松开 : 最后一个参数: 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);
}
2、总结
和上一节分析的一样,在使用输入子系统的时候需要人为的注册input_handler和input_device,但是这里只注册了input_device,这是因为在内核里已经有了能支持按键的Input_handler了,
在evdev.c中注册的input_handler来看,它的id_table如上所示,表示可以匹配所有的设备,那么,我们注册的按键类设备肯定可以被它所匹配到,匹配成功之后调用evdev.connect函数创建设备,可以在开发板上ls /dev/evevt * 命令来查看,在加载驱动模块之前,该目录下只有一个输入设备,加载完驱动之后,目录下又多了一个设备,之后就可以进行测试了,好了,今天的程序就写到这里。