zoukankan      html  css  js  c++  java
  • 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>
    Hello,this is %s module!
    
    ",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 !
    ");
     93     printk("Input system initialize successfu!
    
    ");
     94     return 0;
     95 }
     96 //exit
     97 static void __exit key_input_exit(void)
     98 {
     99     printk("<0>
    Goodbye,%s!
    
    ",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!
    
    ");
    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");
    View Code

    附应用程序:

     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 !!!
    ");
    24         exit(1);
    25     }
    26     printf("open successful!
    ");
    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 
    ",ev_key.type, ev_key.code,ev_key.value);
    32             if(EV_SYN == ev_key.type)
    33                 printf("syn event
    
    ");
    34         }
    35     }
    36     close(fd);
    37     return 0;
    38 }
    View Code
  • 相关阅读:
    【题解】2021.3.6 杂题记录
    【题解】雅礼集训 2017 Day7 题解
    【题解】雅礼集训 2018 Day1 题解
    【题解】「WC2018」通道 [*hard]
    【题解】「CTSC2018」暴力写挂 [*hard]
    【题解】CF1485 简要题解
    【题解】「NOI2019」机器人 [*hard]
    制表符的行为
    Error: Permission denied @ apply2files
    text-align 设置 justify 后不生效
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4309329.html
Copyright © 2011-2022 走看看