Hi,欢迎来到中国嵌入式培训高端品牌 - 在线365bet<北京总部官网>,专注嵌入式工程师培养13年!
当前位置: > 嵌入式学院 > 嵌入式学习 > 讲师博文 > Input子系统剖析
Input子系统剖析
时间:2017-05-25作者:华清远见

1.input子系统框架图

input子系统解决什么问题?

解决不同input硬件在应用层与驱动层之间的信息的传输;

(1)用户层

各层之间通信的基本单位就是事件,任何一个输入设备的动作都可以抽象成一个事件。事件有三种属性:类型(type),编码(code),值(value)。

(2)事件处理层

事件处理层负责与用户程序打交道,将硬件驱动层传来的事件报告给用户程序。

(3)核心层

核心层是链接设备驱动层与事件处理层之间的纽带与桥梁,向下提供驱动层的接口,向上提供事件处理层的接口。

(4)设备驱动层

硬件驱动层负责操作具体的硬件设备,这层的代码是针对具体的驱动程序的,需要驱动程序的作者来编写。

 

2.input各层的相关数据结构

Input子系统的主设备号:13

[1]事件结构体

input类设备,在驱动层与应用层进行标准类输入事件的传送驱动层封装具体的事件结构体,从驱动层返回到应用层,再在应用层进行该结构体

struct input_event {

struct timeval time;//具体的时间点

__u16 type;//输入事件的类型:鼠标,键盘,触摸屏

__u16 code;//事件编码值:键盘那个键的编码,鼠标左右键,移动

__s32 value;//操作值:按下,抬起,移动多少

};

事件处理器

struct input_handler {

void *private;//私有数据域

void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);//事件处理

void (*events)(struct input_handle *handle,//事件顺序处理

      const struct input_value *vals, unsigned int count);

bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);//过滤正常事件

bool (*match)(struct input_handler *handler, struct input_dev *dev);//匹配dev与 //handler

int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);//dev与handler匹配上执行connect函数

void (*disconnect)(struct input_handle *handle);//分离handler

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

 

bool legacy_minors;

int minor;//能支持的设备的次设备号

const char *name;//名称

 

const struct input_device_id *id_table;//驱动能够处理的设备表

struct input_device_id {

kernel_ulong_t flags;

__u16 bustype;

__u16 vendor;

__u16 product;

__u16 version;

kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];

kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];

kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];

kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];

kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];

kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];

kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];

kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];

kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];

kernel_ulong_t driver_info;

};

struct list_head h_list;//添加至input_handle的链表

struct list_head node;//添加至input_handler_list

};

[2]核心层相关

struct input_handle {  

    void *private;   //每个配对的事件处理器都会分配一个对应的设备结构,如evdev事件处理器的evdev结构,注意这个结构与设备驱动层的input_dev不同,初始化handle时,保存到这里。   

    int open;        //打开标志,每个input_handle 打开后才能操作,这个一般通过事件处理器的open方法间接设置   

    const char *name;   

    struct input_dev *dev;  //关联的input_dev结构   

    struct input_handler *handler; //关联的input_handler结构   

    struct list_head    d_node;  //input_handle通过d_node连接到了input_dev上的h_list链表上   

    struct list_head    h_node;  //input_handle通过h_node连接到了input_handler的h_list链表上   

};  

[3]input设备结构体

struct input_dev {

const char *name;//设备名

const char *phys;//设备的物理路径所属的系统层次

const char *uniq;//设备的唯一标识代码

struct input_id id;//设备ID

struct input_id {//标识设备驱动特征

__u16 bustype;

__u16 vendor;

__u16 product;

__u16 version;

};

 

unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];//设备的位图的特殊

 

unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//表示能产生的事件类型

#define EV_SYN 0x00//同步类事件

#define EV_KEY 0x01//按键事件

#define EV_REL 0x02//相对位移事件

#define EV_ABS 0x03//绝对位移事件

#define EV_MSC 0x04

#define EV_SW 0x05

#define EV_LED 0x11

#define EV_SND 0x12

#define EV_REP 0x14

#define EV_FF 0x15

#define EV_PWR 0x16

#define EV_FF_STATUS 0x17

#define EV_MAX 0x1f

#define EV_CNT (EV_MAX+1)

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 *mt;//多点触控状态

 

struct input_absinfo *absinfo;/轴线分辨率

//设备当前状态的反馈

unsigned long key[BITS_TO_LONGS(KEY_CNT)];

unsigned long led[BITS_TO_LONGS(LED_CNT)];

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);

//事件处理层结构体

struct input_handle __rcu *grab;

 

spinlock_t event_lock;

struct mutex mutex;

 

unsigned int users;

bool going_away;

 

struct device dev;

 

struct list_head h_list;//连接input_handle

struct list_head node;//将input_dev连接成链表

 

unsigned int num_vals;

unsigned int max_vals;

struct input_value *vals;

 

bool devres_managed;

};

 

3.Input子系统的各个函数接口

(1)事件处理层相关

int input_register_handler(struct input_handler *handler);

功能:注册input_handler

参数:struct input_handler的结构体指针

返回值:成功 :0    失败:错误码的绝对值

 

void input_unregister_handler(struct input_handler *handler);

功能:注销input_handler

参数:struct input_handler的结构体指针

返回值:无

 

(2)核心层相关

int input_register_handle(struct input_handle *handle);

功能:注册input_handle

参数:struct input_handle的结构体指针

返回值:成功 :0    失败:错误码的绝对值

 

void input_unregister_handle(struct input_handle *handle)

功能:注销input_handle

参数:struct input_handle的结构体指针

返回值:无

 

(3)设备驱动层相关

struct input_dev *input_allocate_device(void)

功能:申请input_device

参数:  struct input_device结构体指针

返回值:成功:struct input_dev结构体指针

失败:NULL

void input_free_device(struct input_dev *dev)

功能:释放input_device

参数:  struct input_device结构体指针

返回值:无

 

int input_register_device(struct input_dev *dev);

功能:注册input_device

参数:struct input_device的结构体指针

返回值:成功 :0    失败:错误码的绝对值

 

void input_unregister_device(struct input_dev *dev)

功能:注销input_device

参数:struct input_device的结构体指针

返回值:无

 

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

功能:上报事件

参数:struct input_dev *dev:input设备结构体指针

Type:事件类型

Code:事件代码

Value:事件值

返回值:无

 

static inline void input_sync(struct input_dev *dev)

功能:同步事件

参数:struct input_dev *dev:input设备结构体指针

返回值:无

 

static inline void set_bit(int nr, volatile unsigned long *addr)

功能:设置事件类型或者具体事件

参数:int nr:具体的事件类型或者具体事件

 volatile unsigned long *addr:事件类型或具体事件

返回值:无

 

4.input子系统的源码分析

参考:driver/input/evdev.c

evdev_init

input_register_handler

INIT_LIST_HEAD(&handler->h_list);//初始化input_handler中的h_list链表

list_add_tail(&handler->node, &input_handler_list);//将input_handler加入  //input_handler_list

list_for_each_entry(dev, &input_dev_list, node)//从input_dev_list链表中查找

  //input_dev

input_attach_handler(dev, handler);//若input_dev与input_handler相匹配,则执行  //该函数

id = input_match_device(handler, dev);//比较struct input_handler中struct //input_device_id中的flags进行设备属性 //信息判断

根据id->flag检查id是否匹配。id->flag记录需要匹配哪些域。

“if((id->bit[i]&dev->bit[i])!=id->bit[i])”,这句话意味着id支持的事件种类是dev支持的事件的子集就算匹配了。如果某个handler的id除了id->driver_info之外的域都为0,那么此handler可以和任意dev匹配。实际上<内核>/driver/input/evdev.c中就是这么初始化id的。现在总结一下input_dev注册的过程:一个input_dev注册的过程主要是在将自己加入input_dev_list,然后在input_handler_list中找到id和事件种类相匹配的handler并与之建立连接的过程。 input_dev产生的事件会分发给所有建立连接的handler。下面继续分析事件的传递

 

 

error = handler->connect(handler, dev, id);//当匹配完成之后自动执行  //input_handler中的connect函数进行  //匹配连接

//查找具体的connect的函数实现

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)

init_waitqueue_head(&evdev->wait);//初始化等待队列头

error = input_register_handle(&evdev->handle);//注册input_handle

//将input_handle的d_node成员挂接到input_dev->h_list

list_add_tail_rcu(&handle->d_node,&dev->h_list);

//将input_handle的h_node成员挂接到input_handler->h_list

list_add_tail_rcu(&handle->h_node, &handler->h_list);

cdev_init(&evdev->cdev, &evdev_fops);//由此可知,在connect中主要

实现了字符设备及相关操作方法集合的绑定;

该input子系统相关的操作方法如下:

static const struct file_operations evdev_fops = {

.owner= THIS_MODULE,

.read= evdev_read,

.write= evdev_write,

.poll = evdev_poll,

.open= evdev_open,

.release = evdev_release,

.unlocked_ioctl = evdev_ioctl,

#ifdef CONFIG_COMPAT

.compat_ioctl = evdev_ioctl_compat,

#endif

.fasync= evdev_fasync,

.flush= evdev_flush,

.llseek= no_llseek,

};

分析input子系统事件上报的函数调用:

evdev_read

static ssize_t evdev_read(struct file *file, char __user *buffer,size_t count, loff_t *ppos)

error = wait_event_interruptible(evdev->wait,client->packet_head != client->tail ||

!evdev->exist || client->revoked);//阻塞时,将不满 //足条件的事件添加至等待队列,全局搜索evdev->wait

wake_up_interruptible(&evdev->wait);//唤醒等待队列,在evdev_pass_values中被调

evdev_events();//evdev_pass_values被evdev_events调用

evdev_event();//evdev_events被evdev_event调用

综上得:事件最终由input_handler中的event上报。

 

具体的evdev_events();的上报事件的实现:

evdev_events

evdev_pass_values

__pass_event(client, &event);

client->buffer[client->head++] = *event;//将input_event存放至client的 //input_event数组中;

//如果事件类型是同步且上报,则触发异步通知

if (event->type == EV_SYN && event->code == SYN_REPORT) {

client->packet_head = client->head;

kill_fasync(&client->fasync, SIGIO, POLL_IN);//触发异步通知

}

此时查找evdev_handler->evdev_connect经查看得知,connect主要实现了struct event的结构体填充和一个字符设备驱动的程序编写;

cdev_init(&evdev->cdev, &evdev_fops);//跳入evdev_fops

evdev_fops:

----->evdev_fasync

返回fasync_helper(fd, file, on, &client->fasync);

----->evdev_read

evdev_fetch_next_event(client, &event)

have_event = client->packet_head != client->tail;

//将client中的input_event赋值给event 

*event = client->buffer[client->tail++];

input_event_to_user(buffer + read, &event);//给用户层上报事件

if (copy_to_user(buffer, &compat_event,sizeof(struct input_event_compat)));

综上所述:事件通过input_event来进行传递;

Input_event上报流程分析:

input_event

input_pass_values(dev, dev->vals, dev->num_vals);

input_to_handler(handle, vals, count);

handler->event(handle, v->type, v->code, v->value);

 

5.Input子系统的归纳总结


发表评论

全国咨询电话:400-706-1880,双休日及节假日请致电值班手机:15010390966

在线咨询: 曹老师QQ(619366077), 余老师QQ(2657985593), 李老师QQ(2814652411), 徐老师QQ(1462495461)

企业培训洽谈专线:010-82600901,院校合作洽谈专线:010-82600350,在线咨询:QQ(248856300)

Copyright 2004-2017 华清远见教育集团 版权所有 ,沪ICP备10038863号,京公海网安备110108001117号