20150301 IMX257 输入子系统

20150301 IMX257 输入子系统

2015-03-01 李海沿

一、输入子系统

1.输入子系统结构体定义


struct input_dev{

const char *name; 设备名

const char *phys; 设备在系统中路径

const char *uniq;

struct input_id id; 用于匹配input hander参数

unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

unsigned long evbit[BITS_TO_LONGS(EV_CNT)];

//设备所支持事件类型,主要有EV_SYNC,EV_KEY,EV_REL,EV_ABS等

unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //按键所对应的位图

unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相对坐标对应位图

unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //绝对坐标对应位图

unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];

unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];

unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];

unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];

unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

unsigned int hint_events_per_packet;

unsigned int keycodemax;

unsigned int keycodesize;

void *keycode;

int (*setkeycode)(struct input_dev *dev, const struct input_keymap_entry *ke, unsigned int *old_keycode);

int (*getkeycode)(struct input_dev *dev, struct input_keymap_entry *ke);

struct ff_device *ff;

unsigned int repeat_key;

struct timer_list timer;

int rep[REP_CNT];

struct input_mt_slot *mt;

int mtsize;

int slot;

int trkid;

struct input_absinfo *absinfo;

unsigned long key[BITS_TO_LONGS(KEY_CNT)]; //按键对应的键值

unsigned long led[BITS_TO_LONGS(LED_CNT)]; //LED对应的指示灯状态

unsigned long snd[BITS_TO_LONGS(SND_CNT)];

unsigned long sw[BITS_TO_LONGS(SW_CNT)];

int (*open)(struct input_dev *dev);

void (*close)(struct input_dev *dev);

int (*flush)(struct input_dev *dev, struct file *file);

int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

//事件处理函数,主要是接收用户下发的命令,如点亮led;

struct input_handle __rcu *grab;

spinlock_t event_lock;

struct mutex mutex;

unsigned int users;

bool going_away;

bool sync;

struct device dev;

struct list_headh_list; //设备所支持的input handle;

struct list_headnode;

};

输入设备信息:


输入设备信息,匹配input hander时主要用下面参数

struct input_id {

__u16 bustype; 总线类型

__u16 vendor; 产家编号

__u16 product; 产品编号

__u16 version; 版本信息

};

2.输入设备事件处理结构


用于 输入设备事件处理 的数据结构:

struct input_handler {

void *private;

void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);

bool (*match)(struct input_handler *handler, struct input_dev *dev);

int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

//当输入设备和input handler相匹配时调用该函数;

void (*disconnect)(struct input_handle *handle);

void (*start)(struct input_handle *handle);

const struct file_operations *fops; //所支持的file operation操作;

int minor;

const char *name;

const struct input_device_id *id_table; //所有能够支持的输入设备;

struct list_headh_list;

struct list_headnode;

};

3. 链接input_dev 和input_handler 的结构体


连接input-dev 和input handler的数据结构:

struct input_handle {

void *private;

int open;

const char *name;

struct input_dev *dev; input dev

struct input_handler *handler; input handler

struct list_headd_node;

struct list_headh_node;

};

4. 注册和注销函数


int input_register_device(struct input_dev *dev)

int input_unregister_device(struct input_dev *dev)

5. 驱动事件支持

设备驱动通过set_bit()告诉input子系统它支持哪些事件,哪些按键。例如:


set_bit(EV_KEY,button_dev.evbit)

struct input_dev中的两个成员:

evbit--事件类型

keybit--按键类型

事件类型:

EV_RST--reset

EV_REL--相对坐标

EV_MSC--其它

EV_SND--声音

EV_FF--力反馈

EV_KEY--按键

EV_ABS--绝对坐标

EV_LED--led

EV_REP--repeat

当事件类型为EV_KEY时,还需指明按键类型:

BTN_LEFT--鼠标左键

BTN_RIGHT--鼠标右键

BTN_MIDDLE--鼠标中键

BTN_0--数字0键

BTN_1--数字1键

6. 事件报告


Void input_event(struct input_dev *dev,unsigned int type,unsigned int code,int value);

//报告指定type,code的输入事件

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); //报告绝对坐标

Void input_sync(struct input_dev *dev);

//报告同步事件 在触摸屏驱动设计中,一次坐标及按下状态的整个报告过程如下:

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(struct input_dev *dev); //同步

structinput_event {

struct timeval time;

__u16 type;

__u16 code;

__s32 value;

};

① code

事件的代码。如果事件类型是EV_KEY,该代码则为设备的键盘代码。例如:键盘上的按键代码值为0--127,鼠标按键代码为0x110---0x116,其中0x110(BTN_LEFT)为鼠标左键,0x111(BTN_RIGHT)为鼠标左键,其它代码含义参考include/linux/input.h文件。

②value

事件的值。若事件的类型是EV_KEY,当按键按下时值为1,松开值为0

报告完毕之后,input_sync()通知系统接受,告诉input core:此次报告已结束。

二、程序分析

1.定义输入子系统结构体

2.设置GPIO引脚模式及初始化GPIO中断

3.输入子系统相关设置

如图所示:

80行 分配一个input_dev结构体

82行 设置输入子系统支持按键操作

83行 设置支持按键的类型为BTN_0

84行 设置名字和初始化名字

86行 注册输入子系统

4.初始化定时器,用于防抖动

5.发生按键操作时,进入中断中断,开启定时器

如图所示,全局保存发生发生中断的引脚,然后开启定时器,在定时器中断函数中处理。

6.定时器中断函数

如图所示,在定时器中断函数中,获取发生按键的键值,然后使用input_report_key函数向系统报告事件,接着就是使用input_sync函数通知接收者,报告完毕。

7. 在exit函数中注销

如图所示,在exit函数中,将我们前面申请的GPIO端口和GPIO中断都释放,然后删除定时器,

接着就是注销我们的输入子系统,释放输入子系统结构体。

8.测试: 在应用程序中打开设备

如图所示,在/dev/input/下面有event1。

9.读取输入子系统

如图所示,

我们使用read函数来读取输入子系统的数据,注意此处我们得到的是一个input_event的结构体。

接着如果我们的信息是按键按下,则打印按键一些信息,如果是通知信息,则打印syn event。

10.编译测试

附驱动程序:

  1 /******************************
  2     linux key_inputSystem
  3  *****************************/
  4 #include <linux/module.h>
  5 #include <linux/init.h>
  6 #include <linux/kernel.h>
  7 #include <linux/delay.h>
  8 #include <linux/types.h>
  9 #include <linux/ioctl.h>
 10 #include <linux/gpio.h>
 11 #include <linux/fs.h>
 12 #include <linux/device.h>
 13 #include <linux/uaccess.h>
 14 #include <linux/irq.h>
 15 #include <linux/wait.h>
 16 #include <linux/sched.h>//error: ‘TASK_INTERRUPTIBLE‘ undeclared
 17 #include <linux/interrupt.h>
 18 #include <linux/input.h>
 19 #include <asm/irq.h>
 20 #include <asm/io.h>
 21
 22 #include "mx257_gpio.h"
 23 #include "mx25_pins.h"
 24 #include "iomux.h"
 25
 26 #define Driver_NAME "key_input"
 27 #define GPIO2_10    MX25_PIN_A24
 28 //定义各个按键按下的键值
 29 struct pin_desc{
 30     unsigned int pin;
 31     unsigned int key_val;
 32 };
 33 //当按键按下时,键值分别为 以下值
 34 struct pin_desc pins_desc[1] = {
 35     {GPIO2_10,    0x05},
 36 };
 37
 38 static struct input_dev *key_input_dev;//输入子系统设备结构体
 39 static struct timer_list key_timer;    //定时器结构体
 40 static struct pin_desc *pin_desc_irq; //保存发生中断的引脚信息
 41
 42 //定时器到时函数
 43 static int key_timer_function(unsigned long data){
 44     struct pin_desc *pin_desc_tmp = pin_desc_irq;    //发生中断的引脚信息
 45     unsigned int pinval_tmp;        //按键键值缓冲
 46     if(!pin_desc_tmp)
 47         return 0;
 48     pinval_tmp = gpio_get_value(IOMUX_TO_GPIO(pin_desc_tmp->pin));//获取键值
 49     if(!pinval_tmp){
 50         input_report_key(key_input_dev, BTN_0,0);
 51         input_sync(key_input_dev);                //报告完毕,通知接收者
 52     }else{
 53         input_report_key(key_input_dev, BTN_0, 1);
 54         input_sync(key_input_dev);                //报告完毕,通知接收者
 55     }
 56     return 0;
 57 }
 58 /* 中断程序key_irq */
 59 static irqreturn_t key_irq_function(int irq, void *dev_id)
 60 {
 61     pin_desc_irq = (struct pin_desc *)dev_id; //获取中断引脚的信息
 62     mod_timer(&key_timer,jiffies+HZ/50);    //开启定时器,时间20ms
 63
 64     return IRQ_RETVAL(IRQ_HANDLED);
 65 }
 66 //初始化函数
 67 static int __init  key_input_init(void)
 68 {
 69     printk("<0>\nHello,this is %s module!\n\n",Driver_NAME);
 70
 71     mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5);//设备引脚为GPIO模式
 72      gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10");//申请IO端口使用
 73     gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10));//设备引脚为输入
 74     //设备引脚为上拉输入
 75     mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_100K_PU);
 76     if(request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq_function, IRQF_TRIGGER_FALLING, "key_GPIO2_10", &pins_desc[0]))
 77         return -1;
 78
 79     //input输入子系统设置
 80     key_input_dev = input_allocate_device();//分配一个input_dev结构体
 81     //设置能产生哪些事件
 82     key_input_dev->evbit[0] = BIT_MASK(EV_KEY);   //设置按键信息
 83     key_input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
 84     key_input_dev->name = "key_input_name";
 85     key_input_dev->dev.init_name = "key_input_init_name";
 86     input_register_device(key_input_dev);
 87
 88     init_timer(&key_timer);    //初始化定时器
 89     key_timer.function = &key_timer_function;    //设置定时器处理函数
 90     add_timer(&key_timer);    //将该定时器加入内核
 91
 92     printk("<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING !\n");
 93     printk("Input system initialize successfu!\n\n");
 94     return 0;
 95 }
 96 //exit
 97 static void __exit key_input_exit(void)
 98 {
 99     printk("<0>\nGoodbye,%s!\n\n",Driver_NAME);
100     /* free gpios */
101     free_irq(IOMUX_TO_IRQ(GPIO2_10),  &pins_desc[0]);
102     mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5);
103     gpio_free(IOMUX_TO_GPIO(GPIO2_10));
104
105     del_timer(&key_timer);        //删除定时器
106     input_unregister_device(key_input_dev);    //注销驱动
107     input_free_device(key_input_dev);        //释放结构体内存
108     printk("Input system unregister successfu!\n\n");
109 }
110
111 /* 这两行指定驱动程序的初始化函数和卸载函数 */
112 module_init(key_input_init);
113 module_exit(key_input_exit);
114
115 /* 描述驱动程序的一些信息,不是必须的 */
116 MODULE_AUTHOR("Lover雪");
117 MODULE_VERSION("0.1.0");
118 MODULE_DESCRIPTION("IMX257 key Driver");
119 MODULE_LICENSE("GPL");

附应用程序:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <sys/stat.h>
 6 #include <fcntl.h>
 7 #include <termios.h>
 8 #include <errno.h>
 9 #include <limits.h>
10 #include <time.h>
11 #include <linux/input.h>
12 #include "mx257_gpio.h"
13
14
15 int main(int argc, char **argv)
16 {
17     int fd;
18     int key_value,i=0,count;
19     struct input_event ev_key;
20
21     fd = open("/dev/input/event1",O_RDWR);
22     if(fd < 0){
23         printf("can‘t open !!!\n");
24         exit(1);
25     }
26     printf("open successful!\n");
27     while(1){
28         count = read(fd,&ev_key,sizeof(struct input_event));
29         for(i = 0; i<(int)count/sizeof(struct input_event); i++){
30             if(EV_KEY == ev_key.type)
31                 printf("type: %d ,code: %d ,value: %d \n",ev_key.type, ev_key.code,ev_key.value);
32             if(EV_SYN == ev_key.type)
33                 printf("syn event\n\n");
34         }
35     }
36     close(fd);
37     return 0;
38 }

时间: 2024-11-07 22:34:09

20150301 IMX257 输入子系统的相关文章

20150303 IMX257 输入子系统(二)之键盘模拟

20150303 IMX257 输入子系统(二)之键盘模拟 2015-03-03 李海沿 前面我们已经详细介绍了基本的知识:地址http://www.cnblogs.com/lihaiyan/p/4309329.html 接下来,我们使用IMX257的IO引脚中断+Linux输入子系统实现一个模拟键盘按键.实现的效果是,我们使用IO模拟按键L.按键S和Enter键 这三个按键. 这次我们就不再多废话了,直接上程序,大家看代码: 实验效果图: 如图所示: 我们依次按下三个按键 第一个按键 显示的键

输入子系统之按键驱动

上一篇博文<input输入子系统框架分析>,尝试使用这种驱动模型来看一个按键驱动程序. 下面的程序是根据韦东山老师写的代码进行修改的,我的开发板是tq2440. button.c文件: #include <linux/module.h> #include <linux/version.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h>

基于输入子系统的按键驱动程序

输入子系统框图: 基于输入子系统的按键驱动程序步骤: 1.分配input_dev结构体 2.设置这个结构体 3.注册 4.硬件相关操作(有数据产生时调用 input_event来上报). 1.分配input_dev结构体 首先要定义这个结构体:static struct input_dev *buttons_dev; 然后在init函数中进行以下操作:buttons_dev = input_allocate_device(); 2.设置这个结构体 使用set_bit来设置这一个位,能设置以下参数

Linux 输入子系统

Technorati 标签: Kernel 输入子系统 Input      在Linux中,输入设备(如按键.键盘.触摸屏.鼠标等)是典型的字符设备,其一般的工作机理,是底层在按键.触摸时,触发一个中断,或者驱动通过定时器定时查询,通过这两种方式通知CPU,CPU然后通过SPI.I2C或I/O接口读取键值.坐标等数据,放入缓冲区,字符设备驱动管理该缓冲区,向上提供read接口供应用程序使用.      在上述的工作流程中,只有终端.读取数值是根具体硬件设备相关,而输入事件的缓冲区管理以及字符设

Linux输入子系统框架分析(1)

在Linux下的输入设备键盘.触摸屏.鼠标等都可以用输入子系统来实现驱动.输入子系统分为三层,核心层和设备驱动层,事件层.核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现.我们在设备驱动层将输入事件上报给核心层input.c,核心层找到匹配的事件层,将事件交给事件层处理,事件层处理完后传递到用户空间. 我们最终要搞清楚的是在用户空间调用open和read最终在内核中是怎样处理的,向内核上报的事件又是谁处理的,处理完后是怎样传递到用户空间的? 上面两个图是输入子系统的框架. 下面

输入子系统概念介绍

输入子系统在内核中的位置:/driver/input drivers/input/input.c: input_init ---> err = register_chrdev(INPUT_MAJOR, "input", &input_fops); static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file, }; 问:怎么读按键? inpu

Android底层开发之Linux输入子系统要不要推断系统休眠状态上报键值

Android底层开发之Linux输入子系统要不要推断系统休眠状态上报键值 题外话:一个问题研究到最后,那边记录文档的前半部分基本上都是没用的,甚至是错误的. 重点在最后,前边不过一些假想猜測. http://blog.csdn.net/kangear/article/details/40072707 在调试一下红外遥控器input驱动时,直接採用的是一个半成品的驱动在上边实现的自己的设备的匹配,但同一时候遇到了一些关于input输入子系统的疑惑. 按键一般有「按下和抬起」两个状态一般使用0和1

Linux输入子系统(Input Subsystem)

Linux输入子系统(Input Subsystem) http://blog.csdn.net/lbmygf/article/details/7360084 input子系统分析  http://blog.chinaunix.net/uid-27717694-id-3758334.html

linux input输入子系统应用分析

输入设备(如按键.键盘.触摸屏.鼠标等)是典型的字符设备,其一般的工作机理是底层在按键.触摸等动作发送时产生一个中断(或驱动通过timer定时查询),然后CPU通过SPI.I2 C或外部存储器总线读取键值.坐标等数据,放入1个缓冲区,字符设备驱动管理该缓冲区,而驱动的read()接口让用户可以读取键值.坐标等数据. 显然,在这些工作中,只是中断.读值是设备相关的,而输入事件的缓冲区管理以及字符设备驱动的file_operations接口则对输入设备是通用的.基于此,内核设计了输入子系统,由核心层