input子系统框架



 

一、输入子系统框架

输入子系统由核心层(Input Core)、驱动层和事件处理层(Event Handler)三部份组成,如下图所示,一个输入事件通过 Driver -> InputCore ->Eventhandler -> userspace 的顺序到达用户空间传给应用程序。

 

                      input子系统框架_第1张图片

 

设备驱动层:将底层的硬件输入事件转化为统一事件形式,向输入核心(Input Core)汇报。
核心层:承上启下:对输入子系统进行了抽象, 对下提供了设备驱动的接口,对上提供了Event Handler层的编程接口。
事件处理层:和用户层交互,提供设备的read和write等函数。

二、主要数据结构

                                            表 1     Input Subsystemmain data structure

数据结构

用途

定义位置

具体数据结构的分配和初始化

Struct input_dev

驱动层物理Input设备的基本数据结构

Input.h

通常在具体的设备驱动中分配和填充具体的设备结构

Struct Evdev

Struct Mousedev

Struct Keybdev…

Event Handler层逻辑Input设备的数据结构

Evdev.c

Mousedev.c

Keybdev.c

Evdev.c/Mouedev.c …中分配

 

Struct Input_handler

Event Handler的结构

Input.h

Event Handler层,定义一个具体的Event Handler

Struct Input_handle

用来创建驱动层DevHandler链表的链表项结构

Input.h

Event Handler层中分配,包含在Evdev/Mousedev…中。

Struct input_event

驱动层向核心层上报数据的结构

Input.h

在驱动层中断函数中创建

 

下面详解介绍各个数据结构:

(1)设备驱动层

    每个输入设备用structinput_dev表示,通过input_register_device向核心层注册输入设备
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)];
 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 keycodemax;//支持的按键值的个数
 unsigned int keycodesize;//每个键值的字节数
 void *keycode;//存储按键值的数组首地址
 int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
 int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);

 

 struct ff_device *ff;
 unsigned int repeat_key;//最近一次按键值,用于连击
 struct timer_list timer;//自动连击计时器
 int sync;//最后一次同步后没有新的事件置1


 int abs[ABS_MAX + 1];
 int rep[REP_MAX + 1];

 

 unsigned longkey[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)];

 

 int absmax[ABS_MAX + 1];
 int absmin[ABS_MAX + 1];
 int absfuzz[ABS_MAX + 1];
 int absflat[ABS_MAX + 1];

 

 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;
 int going_away;

 

 struct device dev;//设备模型相关
 /*static LIST_HEAD(input_dev_list);input子系统维护的设备链表*/
 struct list_head h_list;// 将input_handle加入输入设备维护的input_handle链表
 struct list_head node;//将该设备挂靠到输入子系统维护的全局input_dev_list设备链表上

};

 

input子系统将硬件产生的事件统一用structinput_event来表示。

struct input_event {
        struct timeval time;//事件发生的时间
        unsigned short type;//事件的类型
        unsigned short code;//事件的代码
        unsigned int value; //事件的值

}

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

如果需要特定的事件处理器来处理这个设备的话,这几个就非常重要,因为子系统核心是通过他们,将设备驱动与事件处理层联系起来的。但是因为触摸屏驱动所用的事件处理器为evdev,匹配所有,所有这个初始化也无关紧要。

(2)事件处理层

 input子系统使用structinput_handler代表事件处理层的处理器,通过input_register_handler向核心层注册。

struct input_handler {
       void *private;
       //
当设备驱动层有事件上报时将导致该函数被调用
       void (*event)(struct input_handle *handle,unsigned int type, unsigned int code, int value);
       //
当调用input_register_device和input_register_handler的时候将导致该函数被调用
       int (*connect)(struct input_handler*handler, struct input_dev *dev, const struct input_device_id *id);
       void (*disconnect)(struct input_handle*handle);
       void (*start)(struct input_handle*handle);
       const struct file_operations*fops;//handler
提供的读写等操作函数
       int minor;//次设备号
       const char *name;
       const struct input_device_id *id_table;//
支持的input_dev的设备id
       const struct input_device_id *blacklist;//禁止的input_dev的设备id
       struct list_head h_list ;//将input_handle加入事件处理器维护的input_handle链表
       /*staticLIST_HEAD(input_handler_list);input子系统维护的事件处理链表*/
       struct list_head node;//将该input_hander挂靠在input_handler_list链表中使用
};

 

当input_device或input_handler注册的时候,如果设备驱动层的input_device和事件处理层的input_handler有相匹配的话,input子系统就新建一个input_handle连联系它们。其实质就是:将新建的input_handle分别挂靠在input_dev和input_handler的h_list链表上去。这样一个input_dev就可以根据它的它的input_handle链表找到它的事件处理方法

 

input_handler,同样input_handler也可以根据它的input_handle链表找到它能处理的设备input_dev。可以这么说input_handle是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_head d_node; //用于将该input_handle加入到它关联的input_dev的h_list链表中
     struct list_head h_node; //用于将该input_handle加入到它关联的input_handler的h_list链表中
};

 

通过input_register_handle向核心层注册,将自己分别挂在了input_dev input_handlerh_list上。

 

三、工作流程

 

input子系统框架_第2张图片

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(input,driver)