linux的input子系统(二)
2014-05-02 17:14
267 查看
咱们接着上一篇的内容继续啊,如果你看的莫名其妙那就看看《linux的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所支持的事件类
最后要说的注释部分就是input_report_key()了,这个函数就是当事件产生时,给子系统报告的函数。下面是常用的报告函数:
现在驱动写完了,可能大家想具体测试一下,好吧,那咱们下一篇从应用层的角度来看input子系统,同时也写一个简单的测试程序看看咱们写的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_SYN 0x00 #define EV_KEY 0x01 #define EV_REL 0x02 #define EV_ABS 0x03 #define EV_MSC 0x04 #define EV_SW 0x05 #define EV_LED 0x11 #define EV_SND 0x12 #define EV_REP 0x14 #define EV_FF 0x15 #define EV_PWR 0x16 #define EV_FF_STATUS 0x17 #define EV_MAX 0x1f #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设备驱动程序,好吧,伙伴们,下一篇见!
相关文章推荐
- Linux设备驱动之input子系统
- Linux kernel input子系统
- 查看Linux input子系统信息
- Linux的input输入子系统:总体框架
- Linux Input子系统--概述
- Linux下的Input子系统(三)
- linux驱动——input输入子系统(1)—输入子系统核心层(Input Core)
- Linux Input子系统之第一篇(input_dev/input_handle/input_handler)
- 【Linux系统编程应用】 Linux Input子系统(一)
- linux input子系统分析--概述与数据结构
- Linux输入子系统:输入设备编程指南 -- input-programming.txt
- linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例
- linux内核input子系统解析
- linux input输入子系统分析《四》:input子系统整体流程全面分析
- Linux设备模型之input子系统详解(二)
- linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例
- Linux设备驱动之——input子系统
- Linux输入子系统:输入设备编程指南 -- input-programming.txt
- Linux输入子系统:输入设备编程指南 -- input-programming.txt .
- linux的Input子系统获取Device Name