实例代码如下:
#include <linux/input.h> #include <linux/module.h> #include <linux/init.h> #include <asm/irq.h> #include <asm/io.h> #define BUTTON_IRQ 123 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);/*向输入子系统报告产生按键事件*/ ===========》》》》》【3】 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 ", BUTTON_IRQ); return -EBUSY; } button_dev=input_allocate_device();/*分配一个设备结构体*/ ===========》》》》》》【1】 if(!button_dev) { printk(KERN_ERR"button.c:Not enough memory "); 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);/*注册一个输入设备*/ ===========》》》》》》【2】 if(error) { printk(KERN_ERR"failed to register device "); 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);
【1】input_allocate_device()函数分配一个input_dev结构体,输入设备用input_dev结构体描述。
struct input_dev *input_allocate_device(void) { struct input_dev *dev; dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);/*分配一个input_dev结构体,并初始化为0*/ if (dev) { dev->dev.type = &input_dev_type;/*初始化设备类型*/ dev->dev.class = &input_class;/*设置为输入设备类*/ device_initialize(&dev->dev);/*初始化device结构*/ 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; }
【2】input_register_device()将input_dev结构体注册到输入子系统核心中。
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. */ __set_bit(EV_SYN, dev->evbit);/*设置input_dev所支持的事件类型,由input_dev的evbit成员来表示*/ /* KEY_RESERVED is not supposed to be transmitted to userspace. */ __clear_bit(KEY_RESERVED, dev->keybit); /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); /* * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. */ init_timer(&dev->timer);/*初始化一个timer定时器,为处理重复击键*/ if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { dev->timer.data = (long) dev; dev->timer.function = input_repeat_key; dev->rep[REP_DELAY] = 250;/*这两个值没有定义则设为默认,为自动处理重复按键定义*/ dev->rep[REP_PERIOD] = 33; } /*检查函数是否定义,未定义则使用默认*/ if (!dev->getkeycode) dev->getkeycode = input_default_getkeycode;/*得到键值*/ if (!dev->setkeycode) dev->setkeycode = input_default_setkeycode;/*设置键值*/ dev_set_name(&dev->dev, "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);/*设置input_dev中的device 的名字,以input0/1/2出现在sysfs文件系统中*/ error = device_add(&dev->dev); if (error) return error; path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); printk(KERN_INFO "input: %s as %s ", dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); kfree(path); error = mutex_lock_interruptible(&input_mutex); if (error) { device_del(&dev->dev); return error; } list_add_tail(&dev->node, &input_dev_list);/*加入链表*/ list_for_each_entry(handler, &input_handler_list, node) input_attach_handler(dev, handler);/*调用input_attach_handler来匹配input_dev和handler*/===========》》》》》》【2.1】 input_wakeup_procfs_readers(); mutex_unlock(&input_mutex); return 0; }
其中input_dev所支持的事件类型在include/linux/input.h中定义,如下:
【2.1】input_attach_handler()匹配input_dev和handler。
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) { const struct input_device_id *id; int error; id = input_match_device(handler, dev);/*handler 与dev之间的匹配*/ if (!id) return -ENODEV; error = handler->connect(handler, dev, id);/*匹配成功,则调用connect将handler与dev连接起来*/ if (error && error != -ENODEV) printk(KERN_ERR "input: failed to attach handler %s to device %s, " "error: %d ", handler->name, kobject_name(&dev->dev.kobj), error); return error; }
总结【2】:注册input device 就是为input device 设置默认值,并将其挂接到input_dev_list中,并且与挂载在input_handler_list中的handler相匹配,如果匹配成功,则调用connect。
【3】input_report_key()向输入子系统报告发生的事件:
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_KEY, code, !!value); }
input_event()报告指定type、value的输入事件:
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { unsigned long flags; if (is_event_supported(type, dev->evbit, EV_MAX)) { spin_lock_irqsave(&dev->event_lock, flags); add_input_randomness(type, code, value); input_handle_event(dev, type, code, value);//向输入子系统传送事件信息,,不继续深入分析了-------------------------!! spin_unlock_irqrestore(&dev->event_lock, flags); } }