input驱动在linux内核中经常会用到,比如按键类: power button,一般用gpio来做按键模拟,还有touch key等。触摸屏,键盘鼠标,gsensor,gameport等。本文结合一例子对input驱动模型做探讨。
下面是linux文档中的例子。
#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;//将该button设备定义为input_dev类型
static irqreturn_t button_interrupt(int irq, void *dummy)//中断处理函数
{
input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);//向上层汇报键值//BTN_0,inb(BUTTON_PORT) & 1表示是通码还是断码
input_sync(button_dev);//等待结构体数据都填好后,即数据同步后发送给上层。
return IRQ_HANDLED;
}
static int __init button_init(void)//button设备的初始化
{
int error;
//中断申请,BUTTON_IRQ是中断源,button_interrupt是中断处理函数,0表示中//断类型,是上升沿,下降沿之类,在linux 2.6.35表示0是IRQF_TRIGGER_NONE //类型;”button”是设备名字;NULL表示设备的相关数据为空
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);//表示该input设备是按键事件
button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);//设置按键的键值
error = input_register_device(button_dev);//注册input设备
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); // button设备初始化部分,生成模块。Linux驱动特有的结构
module_exit(button_exit);//设备注销模块
上面是比较简单的注册 input 设备中断处理例子。
注意几个API函数:
1):
set_bit(EV_KEY, button_dev.evbit); set_bit(BTN_0, button_dev.keybit);
分别用来设置设备所产生的事件以及上报的按键值。Struct iput_dev 中有两个成员,一个是evbit.一个是keybit.分别用表示设备所支持的动作和按键类型。
2): input_register_device(&button_dev);
用来注册一个input device.
3): input_report_key()
用来上层上报一个按键动作
4): input_sync()
等待结构体数据都填好后,本次事件操作已完成,数据同步后发送给上层。
一.首先来分析input_allocate_device
struct input_dev *input_allocate_device(void)
{
struct input_dev *dev;
// 使用kzalloc函数分配内存
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
if (dev) {
dev->dev.type = &input_dev_type;
dev->dev.class = &input_class;
device_initialize(&dev->dev);
mutex_init(&dev->mutex);
spin_lock_init(&dev->event_lock);
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
__module_get(THIS_MODULE);
}
return dev;
}
内存分配成功后,向其成员变量赋值,主要包括input_dev_type(包括设备属性group,设备uevent事件),input_class(设备名以及设备节点),以及设备初始化(kobject是在里初始化的,为创建设备文件系统做准备),还有自旋锁的初始化等。
二、注册函数input_register_device
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler *handler;
const char *path;
int error;
/* Every input device generates EV_SYN/SYN_REPORT events. */
//所有设备都支持EV_SYN这种事件类型
__set_bit(EV_SYN, dev->evbit);
/* KEY_RESERVED is not supposed to be transmitted to userspace. */
__clear_bit(KEY_RESERVED, dev->ke