input输入子系统之按键驱动
来源:互联网 发布:君将哀而生之乎的乎 编辑:程序博客网 时间:2024/06/08 05:47
内核版本:linux-2.6.32.2
关于input子系统的基础知识看上一篇博客,网上的资料也是大同小异,也是linux设备驱动模型之一。
下面开始介绍这一个按键驱动程序。
①dev_init
static int __init dev_init(void){ /*request irq*/ s3c24xx_request_irq(); /* Initialise input stuff */ button_dev = input_allocate_device();//普通的出错判断。 if (!button_dev) { printk(KERN_ERR "Unable to allocate the input device !!\n"); return -ENOMEM; }//填充button_dev这个结构体 button_dev->name = "cyx"; button_dev->id.bustype = BUS_RS232; button_dev->id.vendor = 0xDEAD; button_dev->id.product = 0xBEEF; button_dev->id.version = 0x0100; button_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT(EV_SYN); //set_bit(EV_KEY, button_dev->evbit)//支持EV_KEY事件 /*设置支持哪些按键这里设置支持6个按键设置按键的类型和所支持的键,EV_KEY为按键类型,KEY_ESC、KEY_1-5为所支持的键,由于我希望我的按键取1-6,从include/linux/input.h中查询相关的宏可以知道我选择支持的键为1-6,当然你也可以选择你自己喜欢的键值,如果你选择的不是1-6,应用程序取得的按键号ev_key.code也会根据你的设置而改变*/ set_bit(KEY_1, button_dev->keybit); set_bit(KEY_2, button_dev->keybit); set_bit(KEY_3, button_dev->keybit); set_bit(KEY_4, button_dev->keybit); set_bit(KEY_5, button_dev->keybit); set_bit(KEY_6, button_dev->keybit); //printk("KEY_RESERVED=%d ,KEY_1=%d",KEY_RESERVED,KEY_1); input_register_device(button_dev); //注册input设备 printk ("initialized\n"); return 0; }
在dev_init中,调用了函数s3c24xx_request_irq,其实这一个函数实现的功能完全可以在init中来实现。其中初始化函数中有以下几个地方需要注意。
button_dev = input_allocate_device();这个函数是给button_dev这个结构体分配空间,这里的button_dev这个结构体就是input子系统中的input_dev这个结构体。是整个input子系统的信息存储结构体。
②s3c24xx_request_irq每一按键的中断注册函数
//注册每一个按键的中断。/* 依次申请中断,并设置六个中断类型标识为IRQ_TYPE_EDGE_BOTH,代表高低电平都会触发中断。 request_irq其它几个参数分别是中断号;中断处理函数;设备名;最后一个参数为dev_id, 共享中断时使用,必须唯一,用每个结构体的起始地址来表示能够保证id的唯一性。*/ static int s3c24xx_request_irq(void){ int i; int err = 0; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { if (button_irqs[i].irq < 0) { continue; } /* IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH */ err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH, button_irqs[i].name, (void *)&button_irqs[i]); if (err) break; }/*错误处理*/ if (err) { i--; for (; i >= 0; i--) { if (button_irqs[i].irq < 0) { continue; } disable_irq(button_irqs[i].irq); free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); } return -EBUSY; } return 0;}
每一个按键的中断注册函数也就不说太多,程序的注释应该可以说明白了。需要注意的是这个参数IRQ_TYPE_EDGE_BOTH,这个参数决定了按键在按下和弹起的过程中都会产生中断,具体的现象一会上图。
③从②中的中断注册函数中可以知道,中断的实现函数是buttons_interrupt
//在注册中断的函数中实现了这个函数。static irqreturn_t buttons_interrupt(int irq, void *dev_id){ struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id; int down; udelay(0); /*获取按键值*/ down = !s3c2410_gpio_getpin(button_irqs->pin); //down: 1(按下),0(弹起) if (!down) { /*报告事件*/ key_values = button_irqs->number; //printk("====>rising key_values=%d\n",key_values); if(key_values==0)//这里的button_dev,其实就是input_dev,这个时候已经开始将整个input的信息交给上层了。 input_report_key(button_dev, KEY_1, 0); if(key_values==1) input_report_key(button_dev, KEY_2, 0); if(key_values==2) input_report_key(button_dev, KEY_3, 0); if(key_values==3) input_report_key(button_dev, KEY_4, 0); if(key_values==4) input_report_key(button_dev, KEY_5, 0); if(key_values==5) input_report_key(button_dev, KEY_6, 0); /*报告结束这个函数的名字起的太狗血,说是同步,其实就是告诉报告结束的意思。 */ input_sync(button_dev); } else { key_values = button_irqs->number; //printk("====>falling key_values=%d\n",key_values); if(key_values==0) input_report_key(button_dev, KEY_1, 1); if(key_values==1) input_report_key(button_dev, KEY_2, 1); if(key_values==2) input_report_key(button_dev, KEY_3, 1); if(key_values==3) input_report_key(button_dev, KEY_4, 1); if(key_values==4) input_report_key(button_dev, KEY_5, 1); if(key_values==5) input_report_key(button_dev, KEY_6, 1); input_sync(button_dev); } return IRQ_RETVAL(IRQ_HANDLED);}
主要结构式通过一个if的判断来实现了事件的发生判断和报告。最后使用input_sync(button_dev); 这个函数来结束报告。这里需要说一下参数的传递方向。
关于if(key_values==0)
input_report_key(button_dev, KEY_1, 0);
这一部分检测的值传递流程:
①key_values = button_irqs->number;
②static struct button_irq_desc button_irqs [] = {
{IRQ_EINT8 , S3C2410_GPG(0) , S3C2410_GPG0_EINT8 , 0, "KEY0"},
{IRQ_EINT11, S3C2410_GPG(3) , S3C2410_GPG3_EINT11 , 1, "KEY1"},
{IRQ_EINT13, S3C2410_GPG(5) , S3C2410_GPG5_EINT13 , 2, "KEY2"},
{IRQ_EINT14, S3C2410_GPG(6) , S3C2410_GPG6_EINT14 , 3, "KEY3"},
{IRQ_EINT15, S3C2410_GPG(7) , S3C2410_GPG7_EINT15 , 4, "KEY4"},
{IRQ_EINT19, S3C2410_GPG(11), S3C2410_GPG11_EINT19, 5, "KEY5"},
};
OK,到这里就是针对寄存器的读取了,所以就可以判断按键的状态了。
④button_irq_desc这个结构体如下所示。
struct button_irq_desc { int irq; //中断号 int pin; //按键引脚 int pin_setting; //按键引脚设置 int number; //按键编号 char *name; //按键名称};
这个结构体的填充:
static struct button_irq_desc button_irqs [] = { {IRQ_EINT8 , S3C2410_GPG(0) , S3C2410_GPG0_EINT8 , 0, "KEY0"}, {IRQ_EINT11, S3C2410_GPG(3) , S3C2410_GPG3_EINT11 , 1, "KEY1"}, {IRQ_EINT13, S3C2410_GPG(5) , S3C2410_GPG5_EINT13 , 2, "KEY2"}, {IRQ_EINT14, S3C2410_GPG(6) , S3C2410_GPG6_EINT14 , 3, "KEY3"}, {IRQ_EINT15, S3C2410_GPG(7) , S3C2410_GPG7_EINT15 , 4, "KEY4"}, {IRQ_EINT19, S3C2410_GPG(11), S3C2410_GPG11_EINT19, 5, "KEY5"},};
⑤dev_exit驱动退出函数
static void __exit dev_exit(void){ int i; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { if (button_irqs[i].irq < 0) { continue; } free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); } input_unregister_device(button_dev);}
中断退出函数中主要实现了中断的释放和input设备的释放。
下面粘出应用程序:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/select.h>#include <sys/time.h>#include <errno.h>#include <linux/input.h>int main(void){int fd;int key_value,i=0,count;struct input_event ev_key;fd = open("/dev/input/event1", 666);//根据实际情况来设置文件,文件名根据/sys/class/input目录下的设备号来确定if (fd < 0) {perror("open device buttons");exit(1);}for (;;) {count = read(fd,&ev_key,sizeof(struct input_event));for(i=0; i<(int)count/sizeof(struct input_event); i++)if(EV_KEY==ev_key.type) printf("type:%d,code:%d,value:%d\n", ev_key.type,ev_key.code,ev_key.value);if(EV_SYN==ev_key.type) printf("syn event\n\n"); } close(fd); return 0;}
需要注意的是fd = open("/dev/input/event1", 666);这一个部分,大家先记住,我马上上图。
现在开始说一说程序在编译过程中出现的问题还没有弄懂的问题:
①还是老问题,告诉这个那个没有定义,我去国嵌linux-2.6.32.2的内核中找了一下,这次不幸了,没有找到关于input-button的成型程序,但是根据错误的类型找到了这个路径下的文件——————/drivers/char/Keyboard.c这个目录下定义的很多变量和名称和我的程序都很类似,菜鸟的我直接把这个文件的头文件全部拷贝到了自己的程序里。再进行make编译内核模块之后顺利通过。增加的头文件如下:
#include <linux/kbd_kern.h>#include <linux/kbd_diacr.h>#include <linux/vt_kern.h>#include <linux/sysrq.h>#include <linux/input.h>#include <linux/reboot.h>#include <linux/notifier.h>#include <linux/jiffies.h>
②内核模块顺利编译过了,那么久insmod吧,下图是insmod后的景象。
自我感觉异常良好,顺利的insmod了。
那么就开始第二部./app吧。但是在执行应用程序之后开始提示的是找不到文件。回头去应用程序中看fd = open("/dev/input/event1", 666);不知道这里应该写什么。
但是如上图中的在insmod成功之后出现了一个路径/sys/devices/virtual/input/input1,我在应用程序中打开了这个路径 /sys/devices/virtual/input/input1,但是提示这不是一个文件。
这就是问题的所在,我现在还不知道怎么寻找input子系统的设备文件。
但是后来想到了一个办法来排除。
下图是在没有insmod这个模块之前/dev/input目录下的情况。
这个时候/dev/input目录下只有两个文event0和mice。
再让我们看一下insmod之后/dev/input目录下的内容。
insmod之后出现了event1,我可以确定只有这一个驱动被insmod(由于前面的其他驱动可以确定没有出现其他的驱动)。所以应用程序fd = open("/dev/input/event1", 666);最后定型。
老谢没有仔细说这里到底是怎么回事,所以我索性先记住这里的驱动程序就是挂接到/dev/input目录下,但是这个event1的名字是哪里来的,我还是不懂。
额,最后驱动函数执行的图没有保存下来,但是现象很简单,就是按下和弹起按键都会产生中断,同时打印每一个按键的信息。
- input输入子系统之按键驱动
- Linux的input输入子系统:设备驱动之按键驱动
- 输入子系统之按键驱动
- Linux input 子系统应用之按键驱动
- linux输入子系统之按键驱动
- linux输入子系统之按键驱动
- linux输入子系统之按键驱动
- linux输入子系统之按键驱动
- 按键驱动之使用输入子系统架构
- input子系统基础之按键5——按键驱动
- Linux驱动之input输入子系统
- linux输入子系统--按键驱动
- 输入子系统 OK6410按键驱动
- 4412驱动-输入子系统按键
- input输入子系统驱动分析
- 输入设备驱动(input子系统)
- 4412驱动-input 输入子系统
- linux驱动---Input 输入子系统
- 比较有用的log4j.properties
- HDOJ 1257 最少拦截系统 贪心算法again! so easy...........................
- ORA-01219错误
- 解决jsp参数传递乱码的问题
- C++11 多线程
- input输入子系统之按键驱动
- IO(IO概述、字符流以及缓冲区)
- Nmap、Netcat、Hping3工具对比
- servlet 处理文件上传的方法【记录】
- java程序员面试中的多线程问题
- .net(c#)提取多层嵌套的JSON
- vector容器中存放结构体类型的变量
- HDOJ 1800 Flying to the Mars 盲目搜索......................so easy...........
- 【白羊座今日运势】