目录
一个简单的input设备驱动,先直接上代码
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/irq.h>
#include <asm/io.h>
static struct input_dev *button_dev;
static irqreturn_t button_interrupt(int irq, void *dummy)
{
input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);
input_sync(button_dev);
return IRQ_HANDLED;
}
static int __init button_init(void)
{
int error;
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
return -EBUSY;
}
button_dev = input_allocate_device();
if (!button_dev) {
printk(KERN_ERR "button.c: Not enough memory\n");
error = -ENOMEM;
goto err_free_irq;
}
button_dev->evbit[0] = BIT_MASK(EV_KEY);
button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
error = input_register_device(button_dev);
if (error) {
printk(KERN_ERR "button.c: Failed to register device\n");
goto err_free_dev;
}
return 0;
err_free_dev:
input_free_device(button_dev);
err_free_irq:
free_irq(BUTTON_IRQ, button_interrupt);
return error;
}
static void __exit button_exit(void)
{
input_unregister_device(button_dev);
free_irq(BUTTON_IRQ, button_interrupt);
}
module_init(button_init);
module_exit(button_exit);
input子系统是Linux下所有输入设备的一个集合,大多数都放在drivers/input目录下,也有一些放在drivers/platform,drivers/hid 。
代码解析
1、中断注册
request_irq主要负责注册一个中断,当有按键按下时,执行中断处理函数button_interrupt。
2、设备注册
- 先分配一个input_dev空间button_dev;
- 设定好响应的事件button_dev->evbit[0]=BIT_MASK(EV_KEY)响应的类型,这里指定的一个key类型,当然可以EV_SYNC(标记不同的事件比如时间和空间都改变的多触控协议)、EV_REL(相对位移改变比如鼠标)、EV_ABS(绝对位移的设备比如触摸屏)、EV_MSC(混杂设备)、EV_SW(二进制的开关设备)、EV_LED(改变LED开关设备)、EV_SND(输出声音设备)、EV_REP(自动重复设备)、EV_FF(强制设备输出反馈信息)、EV_POW(特殊的电源开关)、EV_FF_STATUS(接收强制返回回馈信息的状态);
- 存储key有哪些状态值,也就是有哪些keycode,方便在中断中对相应的keycode做相应处理;
- input_register_device至此完成input设备驱动的注册登记。
3、中断处理函数
这里混合了按下和抬起两个操作的写法,也可以将两者分开,当按下的时候input_report_key最后一个参数为1、当抬起来的时候为0.
static irqreturn_t button_interrupt(int irq, void *dummy)
{
if(inb(BUTTON_PORT)){ // keydown
input_report_key(button_dev, BTN_0, 1);
}else{ // keyup
input_report_key(button_dev, BTN_0, 0);
}
input_sync(button_dev);
return IRQ_HANDLED;
}