linux系统提供了input子系统,按键、触摸屏、键盘、鼠标等输入设备都可以利用input接口函数来实现设备驱动。
在linux内核中,input设备用input_dev结构体描述,试用input子系统实现输入设备驱动的时候,驱动的核心工作是向系统报告按键、触摸屏、键盘、鼠标等输入事件(event,通过input_event结构体描述),不再需要关心文件操作接口,因为input子系统已经完成了文件操作接口。驱动报告的事件经过InputCore和Eventhandler最终到达用户空间。
通过input子系统,具体的输入设备驱动只需要完成如下工作。
(1)在模块加载函数中告知input子系统它可以报告的事件。
设备驱动通过set_bit()告诉input子系统它支持哪些事件,如下所示:
set_bit(EV_KEY, button_dev.evbit);
int input_register_device(struct input_dev *dev);
主要的事件类型包括EV_KEY(按键事件)、EV_REL(相对值,如光标移动,报告的是相对最后一次位置的偏移)和EV_ABS(绝对值,如触摸屏和操纵杆,它们工作在绝对坐标系统)。
用于报告EV_KEY、EV_REL和EV_ABS事件的函数分别为:
void input_report_key(struct input_dev *dev, unsigned int code, int value); void input_report_rel(struct input_dev *dev, unsigned int code, int value); void input_report_abs(struct input_dev *dev, unsigned int code, int value);
例如,在触摸屏设备驱动中,一次坐标及按下状态的整个报告过程如下:
input_report_abs(input_dev, ABS_X, x); //X坐标 input_report_abs(input_dev, ABS_Y, y); //Y坐标 input_report_abs(input_dev, ABS_PRESSURE, pres); //压力 input_sync(input_dev); //同步
void input_unregister_device(struct input_dev *dev);
/*在按键中断中报告事件*/ static void button_interrupt(int irq, void *dummy, struct pt_regs *fp) { input_report_key(&button_dev, BTN_!, inb(BUTTON_PORT), 1); input_sync(&button_dev); } static int __init button_init(void) { /*申请中断*/ 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.evbit[0] = BIT(EV_KEY); //支持EV_KEY事件 button_dev.keybit[LONG(BIT_0)] = BIT(BTN_0); input_register_device(&button_dev); //注册input设备 } static void __exit button_exit(void) { input_unregister_device(&button_dev); free_irq(BUTTON_IRQ, button_interrupt); }