input子系统框架、核心层、输入事件驱动层详解
来源:互联网 发布:英雄无敌2 for mac 编辑:程序博客网 时间:2024/05/16 00:30
一、input子系统架构总览
1、input子系统分为三层
(1)最上层:输入事件驱动层,evdev.c和mousedev.c和joydev.c属于这一层
(2)中间层:输入核心层,input.c属于这一层
(3)最下层:输入设备驱动层,drivers/input/xxx 文件夹下
2、input类设备驱动开发方法
(1)输入事件驱动层和输入核心层不需要动,只需要编写设备驱动层
(2)设备驱动层编写的接口和调用模式已定义好,驱动工程师的核心工作量是对具体输入设备硬件的操作和性能调优。
(3)input子系统不算复杂,学习时要注意“标准模式”四个字。
二、输入核心层源码input.c分析
1、核心模块注册input_init
(1)class_register
(2)input_proc_init
(3)register_chrdev
2、核心层给驱动提供的接口函数是:
(1)input_allocate_device
(2)input_set_capability
(3)input_register_device
3、核心层给输入事件驱动层提供的接口函数是
(1)input_register_handler
(2)input_register_handle
上面对应的主要结构体分别是
Input子系统的三个重要结构体:
input_dev 是硬件驱动层,代表一个input设备。
input_handler 是事件处理层,代表一个事件处理器。
input_handle 个人认为属于核心层,代表一个配对的input设备与input事件处理器。
struct input_dev { const char *name; const char *phys; const char *uniq; struct input_id id; //输入设备的设备信息 unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; 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)];//声音事件的子事件 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)]; 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;//指向input_handle spinlock_t event_lock; struct mutex mutex; unsigned int users; bool going_away; bool sync; struct device dev; struct list_head h_list;//链表头链接该设备关联的input_handle struct list_head node;//链接到全局input_dev_list };
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和device的联系*/ 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; int minor; const char *name; const struct input_device_id *id_table; //该handler所支持的input dev id struct list_head h_list;//链表头,指向它所支持的设备链表 struct list_head node; //链接到全局input_handler_list };
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; //通过d_node把input_handler链接到input_dev上的h_list链表头 struct list_head h_node;//通过h_node把input_dev链接到input_handler的h_list链表头 };
在(1)int input_register_device(struct input_dev *dev)接口函数主要做的事情有:
设置一些能力
这里最为重要,把要注册的设备添加到链表里去(讲白了就是去注册这个input_dev结构体),以便人家在 input_register_handler的时候可以在input_dev_list里面去找,然后配对上,执行error = handler->connect(handler, dev, id)函数。但是在这里呢是,注册设备,所以是到input_handler_list里面去找,有没有一个handler是和它相配对,配对上了之后呢就会去执行error = handler->connect(handler, dev, id);最后去唤醒,不再阻塞。
注:handler和device的匹配
(1)input_attach_handler
input_match_device 匹配device和handler
handler->connect(handler, dev, id) 连接device和handler
(2)int input_register_handler(struct input_handler *handler)里面做的事情和上面是一样的,
**input_table[handler->minor >> 5] = handler;
真正往内核里面注册一个handler,最大支持8个。
static struct input_handler input_table[8];*
(3)int input_register_handle(struct input_handle *handle)
handle结构体里面有两个变量,
struct list_head d_node;
struct list_head h_node;
注册函数里面就是填充这两个变量,
list_add_rcu(&handle->d_node, &dev->h_list);
list_add_tail_rcu(&handle->h_node, &handler->h_list);
这样,将handle对象关联到dev和handler对象。关联的细节如下:
在驱动端利用dev对象采集数据,通过dev的h_list列表找到对应的handle对象,再通过handle对象找到handler对象,这个过程就是从驱动端到处理端的全过程。
将handle挂到所对应input device的h_list链表上.还将handle挂到对应的handler的hlist链表上.如果handler定
义了start函数,将调用之. 到这里,我们已经看到了input device, handler和handle是怎么关联起来的了
三、输入事件驱动层evdev.c
1、static int __init evdev_init(void)
直接注册了一个handler,input_register_handler(&evdev_handler);
**
**static struct input_handler evdev_handler = { .event = evdev_event, .connect = evdev_connect, .disconnect = evdev_disconnect, .fops = &evdev_fops, .minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids,};**
这里重点是evdev_event,evdev_connect;
对应用层封装的结构体是struct input_event { struct timeval time; __u16 type; //类型 __u16 code; //什么样的一个事件、按键事件呢还是触摸屏事件再或者鼠标移动事件 __s32 value; //这个值是多少};
注:驱动层向应用层汇报事件调用的接口函数是 input_report_key(),位于核心层input.c
input_report_key()函数向输入子系统报告发生的事件,该函数的代码如下: static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);
}
该函数的第 1 个参数是产生事件的输入设备, 2 个参数是产生的事件, 3 个参数是事件的值。需要注意的是, 第2 个参数可以取类似 BTN_0、 BTN_1、BTN_LEFT、BTN_RIGHT 等值,这些键值被定义在 include/linux/input.h 文件中。
当第 2 个参数为按键时,第 3 个参数表示按键的状态,value 值为 0 表示按键释放,非 0 表示按键按下。
- input子系统框架、核心层、输入事件驱动层详解
- linux驱动——input输入子系统(1)—输入子系统核心层(Input Core)
- linux设备驱动之输入(input)子系统——核心层实现
- linux input子系统分析--子系统核心.事件处理层.事件传递过程
- android input子系统之二:核心层
- linux驱动由浅入深系列:输入子系统之一(input子系统概述、应用层读取event)
- android input子系统分析---驱动层
- input子系统事件处理层evdev分析
- android input子系统之三:事件层
- android input子系统分析---事件层
- 2.输入系统驱动(2)-input系统框架层分析
- input子系统基础之按键4——输入核心层源码分析
- input子系统二 驱动层input设备注册
- input子系统二 驱动层input设备注册
- input子系统二 驱动层input设备注册
- Linux内核驱动之Input子系统设备驱动层
- input子系统三 核心层和处理器注册
- input子系统三 核心层和处理器注册
- 缓存的主键的生成策略
- XTUExper数值计算方法 C语言实现
- Java经典算法大全(一)
- 响应式编程笔记
- 史上最全干货:Android中的Intent
- input子系统框架、核心层、输入事件驱动层详解
- C语言求二维数组a所有偶数元素之和
- js中的构造函数,原型,原型链,继承
- windows安装Apache,注册服务出现“(OS 5)拒绝访问。 : AH00369: Failed to open the WinNT service manager..."
- 背包、队列和栈
- PHP 获取一段时间内列表
- 类的继承习题
- 好RESTful API的设计原则
- 用户体验设计学习总结(上)