input设备驱动开发
Posted 四季帆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了input设备驱动开发相关的知识,希望对你有一定的参考价值。
1. 作为输入设备的驱动开发者,需要做以下几步:
在驱动加载模块中,设置你的input设备支持的事件类型,类型参见表1设置;
注册中断处理函数,例如键盘设备需要编写按键的抬起、放下,触摸屏设备需要编写按下、抬起、绝对移动,鼠标设备需要编写单击、抬起、相对移动,并且需要在必要的时候提交硬件数据(键值/坐标/状态等等);
将输入设备注册到输入子系统中。
表1:事件类型
EV_SYN 0x00 同步事件
EV_KEY 0x01 按键事件
EV_REL 0x02 相对坐标(如:鼠标移动,报告相对最后一次位置的偏移)
EV_ABS 0x03 绝对坐标(如:触摸屏或操作杆,报告绝对的坐标位置)
EV_MSC 0x04 其它
EV_SW 0x05 开关
EV_LED 0x11 按键/设备灯
EV_SND 0x12 声音/警报
EV_REP 0x14 重复
EV_FF 0x15 力反馈
EV_PWR 0x16 电源
EV_MAX 0x1f 事件类型最大个数和提供位掩码支持
EV_FF_STATUS 0x17 力反馈状态
Linux输入子系统提供了设备驱动层上报输入事件的函数,在include/linux/input.h中:
//上报按键事件
voidinput_report_key(struct input_dev *dev, unsigned int code, int value);
//上报相对坐标事件
voidinput_report_rel(struct input_dev *dev, unsigned int code, int value);
//上报绝对坐标事件
voidinput_report_abs(struct input_dev *dev, unsigned int code, int value);
当上报输入事件之后,需要调用下面的函数来通知输入子系统,以处理设备产生的完整事件:
void input_sync(struct input_dev *dev);
输入子系统的一些位操作NBITS、BIT、LONG经常被用到:
#define NBITS(x) (((x)/BITS_PER_LONG)+1) //通过位x获取数组的长度
#define BIT(x) (1UL<<((x)%BITS_PER_LONG)) //返回位x在数组中的位域
#define LONG(x) ((x)/BITS_PER_LONG) //返回位x的索引
2. 输入设备驱动的简单案例
在Linux内核文档的documentation/input下,有一个input-programming.txt文件,讲解了编写输入设备驱动程序的核心步骤。
提供的案例代码描述了一个button设备,当有按下/释放发生时,BUTTON_IRQ被触发,产生的事件通过BUTTON_PORT引脚获取(即把BUTTON_PORT引脚的电平状态上报),以下是驱动的源代码:
#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;
//由于案例代码只产生一个按键的值,因此input_sync()在这里不起关键作用。但如果是
//一个触摸屏,即有x坐标和y坐标,则需要通过input_sync()函数把x和y坐标完整地传递
//给输入子系统。
static void button_interrupt(int irq, void*dummy, struct pt_regs *fp)
input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);
input_sync(button_dev);
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(EV_KEY);
button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
//把button_dev输入设备挂入输入设备链表中,并且通知事件处理层调用connect函数完成
//设备和事件处理(handler)的绑定,当用户打开设备时,便能够调用到相应的事件处理接口
//获得硬件上报的数据了 */
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设备驱动开发的主要内容,如果未能解决你的问题,请参考以下文章