Linux输入子系统框架
1:Input输入子系统总体框架
Linux内核的输入子系统是对分散的,多种不同类别的输入设备(如键盘,鼠标,触摸屏)等字符设备进行统一处理的一层抽象,就是在字符设备驱动上抽象出的一层。但是这些输入设备都各有不同,那么输入子系统也就只能实现他们的共性,差异性则由设备驱动来实现,而差异性最直观的表现在这些设备功能上的不同。但是,为了更好的理解Linux的输入子系统,我们有必要仔细研究下它的框架。
Linux输入子系统将输入驱动抽象为三层:设备驱动层、核心层、事件处理层,其内在联系如下图所示:
下面先对这三个部分做一个简要的概括,后面的分析也是基于这三个部分:
设备驱动层:主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层
核心层:为设备驱动层提供了规范和接口。设备驱动层只关心如何驱动硬件并获得硬件数据,然后调用核心层提供的接口,核心层自动把数据提交给事件处理层
事件处理层:是用户编程的接口(设备节点),并处理驱动层提交的数据处理
本篇博文所述均是基于linux 3.4.5内核,android 4.2.2版本,硬件平台基于MT6589平台.
2:Input子系统分层分析
2.1:在分析这三部分之前,首先我们先看看input.h这个头文件,因为输入子系统的很多重要结构体都是在里面定义的。
路径:kernel/include/linux/input.h
重要结构体之input_dev:
struct input_dev {
const char *name; //设备名称
const char *phys; //设备在系统的物理路径
const char *uniq; //设备唯一识别符
struct input_id id; //设备ID,包含总线ID(PCI,USB)、厂商ID,与input_handler匹配时用到
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; //bitmap of device properties and quirks
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; //keycode表的大小
unsigned int keycodesize; //keycode表中的元素个数
void *keycode; //设备的键盘表
//配置keycode表
int (*setkeycode)(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode);
//获取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; //当前使用的handle
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
bool sync;
struct device dev;
struct list_head h_list; //h_list是一个链表头,用来把handle挂载在这个上
struct list_head node; //这个node是用来连到input_dev_list上的
};
重要结构体之input_handler:
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);
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;
struct list_head h_list; //h_list是一个链表头,用来把handle挂载在这个上
struct list_head node; //这个node是用来连到input_handler_list上的
};
重要结构体之input_handle:
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_dev的h_list
struct list_head h_node; //连到input_handler的h_list
};
重要结构体之evdev_client:
/*在进程打开event设备的时候调用evdev的open方法,在open中创建和初始化*/
struct evdev_client {
unsigned int head; //针对buffer数组的索引
unsigned int tail; //针对buffer数组的索引,当head和tail相等的时候,说明没事件
unsigned int packet_head; /* [future] position of the first element of next packet */
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct wake_lock wake_lock;
bool use_wake_lock;
char name[28];
struct fasync_struct *fasync; //异步通知函数
struct evdev *evdev; //evdev设备
struct list_head node; //evdev_client链表项
int clkid;
unsigned int bufsize;
struct input_event buffer[]; //一个input_event数据结构的数组,input_event代表一个事件
};
重要结构体之evdev:
<pre name="code" class="cpp">/*evdev结构体在配对成功的时候生成,由handler_connect生成*/
struct evdev {
int open; //打开引用计数
int minor; //次设备号
struct input_handle handle; //关联的input_handle
wait_queue_head_t wait; //等待队列
struct evdev_client __rcu *grab;
struct list_head client_list; //evdev_client链表,说明一个evdev设备可以处理多个evdev_client,可以有多个进程访问
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
bool exist;
};
另外,input.h中还定义了可以支持哪些事件类型,这些只是大类事件,每个事件下还有具体区分:
/*
* Event types
*/
#define EV_SYN 0x00 //同步时间
#define EV_KEY 0x01 //绝对二进制值,如键盘或者按钮
#define EV_REL 0x02 //绝对结果,如鼠标设备
#define EV_ABS 0x03 //绝对整数值,如TP,操纵杆
#define EV_MSC 0x04 //其他类
#define EV_SW 0x05 //开关事件
#define EV_LED 0x11 //led或其他指示设备
#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&#