• linux 输入子系统(3)----事件处理(input_handler层)


    输入子系统主要设计input_dev、input_handler、input_handle。如下:

     

    【1】每个struct input_dev代表一个输入设备

    struct input_dev {
     const char *name;//设备名
     const char *phys;
     const char *uniq;
     struct input_id id;//用于匹配事件处理层handler
     
     unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//用于记录支持的事件类型的位图
     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)];//led
     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];//beep
     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
     unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
     
     unsigned int keycodemax;//支持的按键值的个数
     unsigned int keycodesize;//每个键值的字节数
     void *keycode;//存储按键值的数组首地址
     int (*setkeycode)(struct input_dev *dev,
         unsigned int scancode, unsigned int keycode);//修改键值的函数,可选
     int (*getkeycode)(struct input_dev *dev,
         unsigned int scancode, unsigned int *keycode);//获取扫描码的键值,可选
     
     struct ff_device *ff;
     
     unsigned int repeat_key;//最近一次按键值,用于连击
     struct timer_list timer;//自动连击计时器
     
     int sync;//最后一次同步后没有新的事件置1
     
     int abs[ABS_CNT];//当前各个坐标的值
     int rep[REP_MAX + 1];//自动连击的参数
     
     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)];//反映当前beep状态的位图
     unsigned long sw[BITS_TO_LONGS(SW_CNT)];
     
       /*tp驱动代码里一般使用input_set_abs_params函数设置
         函数参数从右往左依次代表输入设备指针、坐标轴、最小值、最大值、分辨率、基准值。
          最后两个参数也可以填为0,代表设备非常精确并且总能精确的回到中心位置。*/
     int absmax[ABS_CNT];//记录各个坐标的最大值
     int absmin[ABS_CNT];//记录各个坐标的最小值
     int absfuzz[ABS_CNT];//记录各个坐标的分辨率
     int absflat[ABS_CNT];//记录各个坐标的基准值
     int absres[ABS_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);//回调函数,可选
     
     struct input_handle *grab;
     
     spinlock_t event_lock;
     struct mutex mutex;
     
     unsigned int users;
     bool going_away;
     
     struct device dev;
     
     struct list_head h_list;//handle链表
     struct list_head node;//input_dev链表
    };

    struct input_event是事件传送的载体,输入子系统的事件都是包装成struct input_event传给用户空间。各个成员如下所示:

    /* include/linux/input.h */
    struct input_event {
     struct timeval time;//时间戳
     __u16 type;//事件类型
     __u16 code;//事件代码
     __s32 value;//事件值,如坐标的偏移值
    };
    struct input_dev注册的时候需要跟匹配的hanlder建立连接,匹配的依据就是struct input_dev所包含的struct input_id。

    /* include/linux/input.h */
    struct input_id {
     __u16 bustype;//总线类型
     __u16 vendor;//生产商编号
     __u16 product;//产品编号
     __u16 version;//版本号
    };

    【2】input_handler这个结构体是事件驱动的主体,每一种处理方式对应一个handler结构体。注册input_handler,其实就是将input_hangler加入到input_handler_list当中。使用input_register_handler注册。

    /* include/linux/input.h */
    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);
        //连接handler和input_dev的函数指针
     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
        //断开连接函数指针
     void (*disconnect)(struct input_handle *handle);
        //为给定的handle启动handler函数指针
     void (*start)(struct input_handle *handle);
     
        //文件操作结构体
     const struct file_operations *fops;
        //这个handler可以使用的32个次设备号的最小值
     int minor;
        //此handler的名字
     const char *name;
     
        //可以处理的input_device_ids列表
     const struct input_device_id *id_table;
        //需要被忽略的input_device_ids列表
            const struct input_device_id *blacklist;
     
        //用来连接handle的链表链表节点。每个与此handler相关的handle都放入此链表
     struct list_head h_list;
        //用来放入全局handler链表的节点
     struct list_head node;
    };

    【3】input_handle这个结构体用来连接input_dev和input_handler。用input_register_handle()注册。

    /* include/linux/input.h */
    struct input_handle {
     
     void *private;//私有数据指针
     
     int open;//记录本设备被打开的次数
     const char *name;//创建此handle的handler所赋予的名字
     
     struct input_dev *dev;//指向附着的input_dev
     struct input_handler *handler;//指向创建此handle的handler
     
     struct list_head d_node;//链表节点,用来加入附着的input_dev
     struct list_head h_node;//链表节点,用来加入附着的input_handler
    };

    input_dev、input_handler、input_handle之间的关系

    其中 input_dev_list 为全局输入设备链表、input_handler_list为全局handler处理器链表。

    event执行过程:

    input_report_key() ------> input_event() -----> input_handle_event() -----> input_pass_event()    ====>>  handle->handler->event();

    如下图:

  • 相关阅读:
    Oracle
    Oracle11g服务详细介绍及哪些服务是必须开启的?
    数据结构——二叉树树的遍历理论与实现
    MapReduce新版客户端API源码分析
    【编程范式】汇编解释swap方法
    iPhone、iPod和iPad离线固件升级的方法
    Linux备份
    mysql下用户和密码生成管理
    The secret of ROWID
    linux文件权限解说
  • 原文地址:https://www.cnblogs.com/hello2mhb/p/3366703.html
Copyright © 2020-2023  润新知