input子系统分析
来源:互联网 发布:西医综合网络课程 编辑:程序博客网 时间:2024/06/16 18:28
linux系统中,input输入子系统驱动主要可以分为:设备驱动层、input core层和input handler事件处理层。
设备驱动层提供具体用户设备驱动,由struct input-dev 结构表示,input_register_device来注册。
input handler事件处理层 主要和用户空间交互
input core 层负责管理系统中的input dev设备和inputhander事件处理,并起到承上启下作用,负责输入设备驱动和input handler之间信息传输
input子系统结构如图:
主要分为两部分:设备驱动层的注册、handler的注册,在注册的过程中会有handle的创建以及它的作用,会说明设备驱动与handler是如何匹配的
设备驱动层的注册
注册一个input设备主要是对input_register_device的分析
1、 input_dev结构
struct input_dev {
const char *name; /*设备名*/
struct input_id id; /*id号,用于匹配事件处理层handler*/
unsigned longevbit[BITS_TO_LONGS(EV_CNT)]; /*用于记录支持的事件类型的位图*/
unsigned longkeybit[BITS_TO_LONGS(KEY_CNT)]; /*记录支持的按键值的位图*/
unsigned longrelbit[BITS_TO_LONGS(REL_CNT)]; /*记录支持的相对坐标的位图 */
unsigned longabsbit[BITS_TO_LONGS(ABS_CNT)]; /*记录支持的绝对坐标的位图 */
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned longledbit[BITS_TO_LONGS(LED_CNT)]; /*led */
unsigned longsndbit[BITS_TO_LONGS(SND_CNT)]; /*beep*/
unsigned int keycodemax; /*支持的按键值的个数*/
unsigned int keycodesize; /*每个键值的字节数 */
void *keycode; /*存储按键值的数组首地址*/
int (*setkeycode)(structinput_dev *dev, const struct input_keymap_entry *ke,
unsigned int *old_keycode); /* 修改键值的函数,可选 */
int (*getkeycode)(structinput_dev *dev,
struct input_keymap_entry *ke); /* 获取扫描码的键值,可选 */
unsigned int repeat_key; /*最近一次按键值,用于连击*/
struct timer_list timer; /*自动连击计时器 */
struct input_mt *mt; /*多点触控状态*/
struct input_absinfo *absinfo; /*绝对轴信息(当前值,最小值,最大值,平,模糊,解析度)*/
unsigned longkey[BITS_TO_LONGS(KEY_CNT)]; /*反映当前按键状态的位图 */
unsigned longled[BITS_TO_LONGS(LED_CNT)]; /*反映当前led状态的位图 */
unsigned longsnd[BITS_TO_LONGS(SND_CNT)]; /*反映当前beep状态的位图 */
int (*open)(struct input_dev*dev); /*打开函数 */
void (*close)(struct input_dev*dev); /*关闭函数 */
int (*flush)(struct input_dev*dev, struct file *file); /* 断开连接时冲洗数据 */
struct list_head h_list;
struct list_head node;
struct device dev;
};
现在通过分析注册之前的配置过程,理解input_dev结构作用。
input_allocate_device() //初始化一个设备
dev.type = &input_dev_type;
dev.class = &input_class;
device_initialize(dev);
dev->name = xxx_DEVICE; //设备名
dev->id.vendor =0x00; //设备id的配置
dev->id.product =pid;
dev->id.version=vid;
set_bit(EV_ABS, dev->evbit); //支持绝对坐标事件 (为了不影响分析,事件支持全部类型在文章末尾列出)
set_bit(EV_KEY, dev->evbit); //支持按键事件
set_bit(ABS_X, dev->absbit); //相对于屏幕的绝对x坐标
set_bit(ABS_Y, dev->absbit); //相对于屏幕的绝对y坐标
set_bit(ABS_PRESSURE, dev->absbit);//绝对坐标事件压力值
set_bit(BTN_TOUCH,tpd->dev->keybit);// 触摸接触事件
set_bit(INPUT_PROP_DIRECT,dev->propbit);//表明设备的坐标直接和屏幕坐标向对应
//设置坐标的位置范围(例如480*720的屏幕TPD_RES_X=480,TPD_RES_Y=720),预示着超出这个范围不再有效
input_set_abs_params(tpd->dev,ABS_MT_POSITION_X, 0, TPD_RES_X, 0, 0);
input_set_abs_params(tpd->dev,ABS_MT_POSITION_Y, 0, TPD_RES_Y, 0, 0);
2、 input_register_device函数操作
device_add(&dev->dev); //input_dev->dev注册
list_add_tail(&dev->node,&input_dev_list); //加入input链表
//遍历input_handler_list,取出每一个handler进行input_attach_handler操作
list_for_each_entry(handler,&input_handler_list, node)
input_attach_handler(dev,handler);
----- >input_attach_handler(structinput_dev *dev, struct input_handler *handler)
----- > input_match_device(handler,dev);
handler->connect(handler, dev,id);
input_dev与handler匹配,匹配成功之后connect,查看input_match_device源码,可以发现匹配的关键是input_dev->id,
这里暂时不分析connect操作,这一步在handler注册的时候再进行分析。到此完成了input_dev的注册
handler的注册过程
1、input_handler结构
struct input_handler {
void *private;
void (*event)(structinput_handle *handle, unsigned int type, unsigned int code, int value); //事件处理程序
void (*events)(structinput_handle *handle,
const struct input_value *vals, unsignedint count);//事件序列处理程序
bool (*filter)(structinput_handle *handle, unsigned int type, unsigned int code, int value); //事件处理适配器
bool (*match)(structinput_handler *handler, struct input_dev *dev);// id比较
int (*connect)(structinput_handler *handler, struct input_dev *dev, const struct input_device_id*id); //上面用到的connect程序
void (*disconnect)(structinput_handle *handle);// disconnect处理程序
void (*start)(structinput_handle *handle); //启动处理程序
int minor; //input设备结点的次设备号
const char *name;
const struct input_device_id*id_table; //id_table
struct list_head h_list;
struct list_head node;
};
2、一个具体的handler注册过程(这里以input自带的evdev为例子,分析一下一个handler是如何注册的。源码位置:kernel/input/evdev.c)staticint __init evdev_init(void){
returninput_register_handler(&evdev_handler);
}
int input_register_handler(struct input_handler *handler){
list_add_tail(&handler->node,&input_handler_list); //把handler假如list
list_for_each_entry(dev,&input_dev_list, node) //与input_dev匹配(这里在input_dev注册的最后出现过的)
input_attach_handler(dev,handler);
}
现在,来分析一下connect操作(上面未分析的),这里显示了handle把handler和input联系起来static struct input_handler evdev_handler = {
.event = evdev_event,
.events = evdev_events,
.connect = evdev_connect, //这个操作
.disconnect = evdev_disconnect,
.legacy_minors = true,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
static void evdev_disconnect(struct input_handle *handle){
struct evdev *evdev;
dev_set_name(&evdev->dev, "event%d", dev_no); //设备的name
evdev->handle.dev = input_get_device(dev); //已经匹配成功后,得到handle->dev(在handle定义 struct input_dev *dev;)
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler; //handle->handler
device_initialize(&evdev->dev);
error =input_register_handle(&evdev->handle); //注册handle(把handle加到一个list里面)
error =device_add(&evdev->dev); //创建设备(上层访问的设备),它的主设备号在kernel/drivers/input/input.c中定义,并实现访问方法
到此,完成了input子系统分析。
至于input如何把数据上报到userspace的,举个例子: 在触摸屏驱动中,通过i2c得到触摸坐标或按键,通过 input_report_abs、input_report_key便可以把数据传递到上层。具体的过程可以通过芯片厂的源码来分析。
input_dev事件支持类型
types对应于一个相同逻辑输入结构的一组Codes。每个type都有一组可用的codes用于产生输入事件。每个type可用的codes的详细信息请参考Codes一节的内容。
EV_SYN: 用于事件间的分割标志。事件可能按时间或空间进行分割,就像在多点触摸协议中的例子。
EV_KEY: 用来描述键盘,按键或者类似键盘设备的状态变化。
EV_REL:用来描述相对坐标轴上数值的变化,例如:鼠标向左方移动了5个单位。
EV_ABS:用来描述相对坐标轴上数值的变化,例如:描述触摸屏上坐标的值。
EV_MSC:当不能匹配现有的类型时,使用该类型进行描述。
EV_SW: 用来描述具备两种状态的输入开关。
EV_LED:用于控制设备上的LED灯的开和关。
EV_SND: 用来给设备输出提示声音。
EV_REP:用于可以自动重复的设备(autorepeating)。
EV_FF:用来给输入设备发送强制回馈命令
EV_PWR: 特别用于电源开关的输入。.
EV_FF_STATUS:用于接收设备的强制反馈状态。
正常情况下,用户空间基于设备发出的数据(比如事件的types)来建立一个输入设备,当两个设备都发出相同的事件types时,这时设备特性就可以提供额外的识别信息。
INPUT_PROP_DIRECT + INPUT_PROP_POINTER:
INPUT_PROP_DIRECT特性表明设备的坐标直接和屏幕坐标向对应(无需琐碎的转换操作,像缩放,反转,旋转等)。非直接输入设备则需要一些必要的变换,比如触摸板上绝对到相对的变换。典型的直接输入设备有:触摸屏,手写板;非直接输入设备有:触摸板,鼠标。
INPUT_PROP_POINTER特性表明设备不是利用屏幕来获取输入信息,从而需要一个屏幕上的指针来跟踪用户的移动。典型的指针设备有:触控板,鼠标;非指针设备:触摸屏。
如果INPUT_PROP_DIRECT或者 INPUT_PROP_POINTER都没有设置,设备将会被认为是未定义,它的类型需要按传统的方式利用事件的types推导出来。
INPUT_PROP_BUTTONPAD:
有些触摸板,它的按键位于触摸板的底部,这样按下触摸板会产生一次按键消息,对于这种设备,应该设置该特性。
- linux input 子系统分析
- Linux input子系统分析
- input子系统分析
- 内核input子系统分析
- Input子系统分析
- input子系统分析
- input子系统分析一
- input子系统分析二
- 代码分析:input子系统
- input子系统分析
- input 子系统分析
- Input子系统分析
- input输入子系统分析
- input子系统 详细分析
- input子系统分析
- input子系统分析
- android Input子系统分析
- input子系统分析
- java测试类调用LDAP服务器客户端信息实行增删改查
- 使用MarkDown编辑器
- php页面运行时间记录
- POJ 3090 Visible Lattice Points(欧拉函数)
- vsphere中的evc介绍
- input子系统分析
- android开发之用户头像上传
- hdu5113(dfs+剪枝)
- 安卓 NDK JNI 使用(五) -- so , jar 包
- demo1 JAVA笔记
- 循环队列
- jquery网页加载进度条NProgress.js
- Linux网络编程--自定义套接字描述符判定函数issockettype
- Ubuntu下 git 服务器的搭建。