本章将介绍Linux输入子系统的驱动开发。Linux的输入子系统不仅支持鼠标、键盘等常规输入设备,而且还支持蜂鸣器、触摸屏等设备。本章将对Linux输入子系统进行详细的分析。
输入子系统大致实现方法:
底层驱动层(input_dev)-----<通过结构体input_handle关联>-----输入事件处理层类接口(input_handler)-----<输入核心层input.c>-----应用层
17.1 input子系统入门
输入子系统又叫input子系统。其构建非常灵活,只需要调用一些简单的函数,就可以将一个输入设备的功能呈现给应用程序。本节将从一个实例开始,介绍编写输入子系统驱动程序的方法。
17.1.1 简单的实例
本节将讲述一个简单的输入设备驱动实例。这个输入设备只有一个按键,按键被连接到一条中断线上,当按键被按下时,将产生一个中断,内核将检测到这个中断,并对其进行处理。该实例的代码如下:
01 #include <asm/irq.h>
02 #include <asm/io.h>
03 static struct input_dev *button_dev; /*输入设备结构体*/
04 static irqreturn_t button_interrupt(int irq, void *dummy) /*中断处理函数*/
05 {
06 input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);
/*向输入子系统报告产生按键事件*/
07 input_sync(button_dev); /*通知接收者,一个报告发送完毕*/
08 return IRQ_HANDLED;
09 }
10 static int __init button_init(void) /*加载函数*/
11 {
12 int error;
13 if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) /*申请中断处理函数*/
14 {
15 /*申请失败,则打印出错信息*/
16 printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_
irq);
17 return -EBUSY;
18 }
19 button_dev = input_allocate_device(); /*分配一个设备结构体*/
20 if (!button_dev) /*判断分配是否成功*/
21 {
22 printk(KERN_ERR "button.c: Not enough memory\n");
23 error = -ENOMEM;
24 goto err_free_irq;
25 }
26 button_dev->evbit[0] = BIT_MASK(EV_KEY); /*设置按键信息*/
27 button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
28 error = input_register_device(button_dev); /*注册一个输入设备*/
29 if (error)
30 {
31 printk(KERN_ERR "button.c: Failed to register device\n");
32 goto err_free_dev;
33 }
34 return 0;
35 err_free_dev: /*以下是错误处理*/
36 input_free_device(button_dev);
37 err_free_irq:
38 free_irq(BUTTON_IRQ, button_interrupt);
39 return error;
40 }
41 static void __exit button_exit(void) /*卸载函数*/
42 {
43 input_unregister_device(button_dev); /*注销按键设备*/
44 free_irq(BUTTON_IRQ, button_interrupt); /*释放按键占用的中断线*/
45 }
46 module_init(button_init);
47 module_exit(button_exit);
这个实例程序代码比较简单,在初始化函数button_init()中注册了一个中断处理函数,然后调用input_allocate_device()函数分配了一个input_dev结构体,并调用input_register_device()函数对其进行了注册。在中断处理函数button_interrupt()中,实例将接收到的按键信息上报给input子系统。从而通过input子系统,向用户态程序提供按键输入信息。
本实例采用了中断方式,除了中断相关的代码外,实例中包含了一些input子系统提供的函数,现对其中一些重要的函数进行分析。
第19行的input_allocate_device()函数在内存中为输入设备结构体分配一个空间,并对其主要的成员进行了初始化。驱动开发人员为了更深入的了解input子系统,应该对其代码有一点的认识,该函数的代码如下:
- 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); /*模块引用技术加1*/
- }
- return dev;
- }
该函数返回一个指向input_dev类型的指针,该结构体是一个输入设备结构体,包含了输入设备的一些相关信息,如设备支持的按键码、设备的名称、设备支持的事件等。在本章用到这个结构体时,将对其进行详细介绍。此处将注意力集中在实例中的函数上。