linux的input子系统(二)

来源:互联网 发布:相册自动排版软件 编辑:程序博客网 时间:2024/06/05 11:08

咱们接着上一篇的内容继续啊,如果你看的莫名其妙那就看看《linux的input子系统(一)》吧,首先我把上一篇提到的按键驱动的源代码附上吧,咱们以源代码为线索一一述说嘛。

#include<linux/input.h>#include<linux/module.h>#include<linux/init.h>#include<linux/kernel.h>#include<linux/delay.h>#include<asm/irq.h>#include<linux/irq.h>#include<asm/io.h>#include<linux/interrupt.h>#include<asm/uaccess.h>#include<mach/hardware.h>#include<linux/platform_device.h>#include<mach/map.h>#include<mach/gpio.h>#include<mach/regs-clock.h>#include<mach/regs-gpio.h>struct button_desc {int gpio;int number;char *name;struct input_dev *button_dev;//定义一个输入设备};static struct button_desc buttons[] = {{ S5PV210_GPH2(0), 0, "KEY0" },};static irqreturn_t button_interrupt(int irq, void *dummy){input_report_key(buttons[0].button_dev, BTN_0, gpio_get_value(buttons[0].gpio) & 1);//在中断里把按键的值提交到核心层,要注意中断是由于按键的按下或者释放而产生的input_sync(buttons[0].button_dev);//这个函数是做一个同步的作用,当然在这里其实没什么作用,不过像在触摸屏里面就有用了return IRQ_HANDLED;}static int __init button_init(void){int error;int irq;irq = gpio_to_irq(buttons[0].gpio);if(request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_BOTH, buttons[0].name, (void *)&buttons[0])){printk(KERN_ERR "button.c: Can't allocate irq %d\n", irq);return -EBUSY;}buttons[0].button_dev = input_allocate_device();//分配一个input设备,当然里面做了一些必要的处理if(!buttons[0].button_dev){printk(KERN_ERR "button.c: Not enough memory\n");error = -ENOMEM;goto err_free_irq;}buttons[0].button_dev->evbit[0] = BIT_MASK(EV_KEY);//设备支持的事件类型buttons[0].button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);//事件EV_KEY支持的事件码buttons[0].button_dev->name = "KEY0";buttons[0].button_dev->phys = "s5pv210/input0";error = input_register_device(buttons[0].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(buttons[0].button_dev);//当注册失败时,就调用这个函数释放输入设备err_free_irq:free_irq(irq, button_interrupt);return error; }static void __exit button_exit(void){int irq;irq = gpio_to_irq(buttons[0].gpio);input_unregister_device(buttons[0].button_dev);//卸载input的输入设备free_irq(irq, (void *)&buttons[0]);}module_init(button_init);module_exit(button_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("yingdong xie");
这个程序是按linux-3.0.8/Documentation/input/input-programming.txt文档中讲的为模板在smart210上的实现,可能写的很是粗糙,有许多地方需要改进,但基本的功能还是完成的,看到上面的注释部分了吧,这是编写设备的input驱动常用到的一些函数,也是咱们要讲的重点。

看驱动嘛,肯定是要从button_init开始了。在button_init中第一个看到的注释部分input_allocate_device()这个函数,从名字看就是就是分配一个input设备,没错,不过在它里面还做了一些input设备的初始化工作,这个在以后的文章中详细介绍,因为咱们这里是讨论怎么写设备驱动,所以知道是干什么的就行了,不是这里的重点。接下来的红色部分标识为设备支持的事件和具体事件支持的事件嘛,这里简单的说一下什么事件,什么是事件码!linux中定义了许多事件,包括按键事件、相对坐标事件、绝对坐标事件等,比如说咱们写的按键驱动就用按键事件了,如果要写鼠标驱动,那就应该还需要相对坐标事件了,那事件就可以理解为:具体设备产生的要让input子系统处理的数据类型,因为对鼠标来说,它就是用相对坐标来表示移动的,而按键的话其实就是按下和释放嘛。正是因为每种设备要处理的数据不一样,linux才抽象了许多事件,这样便于管理,这也就是为什么“事件处理层中”对应着:evdev.c、tsdev.c、mousedev.c等好多文件,在这些文件中做了对具体事件的处理。下一个问题,什么是事件码?事件码定义了事件的精确类型,一类事件包括了好多用于产生事件的事件码。也就是说,事件是一个集合,而事件码就是这个集合里面的具体的元素了。就比如说这里的BTN_0代表了smart210上面的一按键一样。关于这部分可以参考linux-3.0.8/Documentation/input/event-codes.txt文档。这里注意:一个设备可以支持一个或多个事件类型。每个事件类型下面还需要设置具体的触发事件码。下面是linux-3.0.8所支持的事件类

#define EV_SYN0x00#define EV_KEY0x01#define EV_REL0x02#define EV_ABS0x03#define EV_MSC0x04#define EV_SW0x05#define EV_LED0x11#define EV_SND0x12#define EV_REP0x14#define EV_FF0x15#define EV_PWR0x16#define EV_FF_STATUS0x17#define EV_MAX0x1f#define EV_CNT(EV_MAX+1)
再接下来的注释部分就是注册input设备驱动的部分了,下面是注册和注销函数:

int input_register_device(struct input_dev *dev)void input_unregister_device(struct input_dev *dev)
其实在注册函数里对input设备做了进一步的初始化,并且通过把input设备与事件处理层里的具体事件处理驱动做匹配,匹配的依据就是上面初始化里面的input设备定义的支持的事件以及事件码,当然可能还有什么总线类型啊,id号等。当然通过注册函数,告诉了input子系统产生了一个input设备。

最后要说的注释部分就是input_report_key()了,这个函数就是当事件产生时,给子系统报告的函数。下面是常用的报告函数:

用于报告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)    如果你觉得麻烦,你也可以只记住1个函数(因为上述函数都是通过它实现的)void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
写一个input的设备驱动的一些主要的函数就讲完了,现在再总体上梳理一下写input设备驱动的过程:a.用input_dev定义一个input设备;b.用input_allocate_device()给定义的input设备分配内存;c.初始化input的特征,比如是按键类型;d.把input设备注册到子系统。

现在驱动写完了,可能大家想具体测试一下,好吧,那咱们下一篇从应用层的角度来看input子系统,同时也写一个简单的测试程序看看咱们写的input设备驱动程序,好吧,伙伴们,下一篇见!


0 0