前言

上一节有展示Android Input子系统的架构图,这里我们关心Linux kernel层

android input 确认 android input系统_设备驱动



可以看到kernel层分为三层:

输入子系统设备驱动:处理与硬件相关的信息,调用input API注册输入设备,并把数据往上报

输入子系统核心层:为事件处理层和设备驱动层提供API接口调用

输入子系统事件处理:通过核心层的API获取输入事件上报的数据,定义input API与应用层交互

数据结构

数据结构

代码位置

描述

struct input_dev

input.h

input设备驱动中的实例

struct evdevstruct mousedev

struct keybdev

evdev.c

mousedev.c

keybdev.c

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

struct input_handler

input.h

Event Handler的结构,handler层实例化对象

struct input_handle

input.h

用于创建驱动层input_dev和handler链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//kernel/include/linux/input.h
/* 描述输入设备 */
struct input_dev {			//代表一个输入设备
	const char *name;		//设备名字,sys文件名
	//...
	struct input_id id;		//与handler匹配:总线类型、厂商、版本等
	/* 输入设备支持时间的位图bitmap */
	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 int keycodemax;		//支持按键值个数
	int (*setkeycode)();			//修改当前keymap
	int (*getkeycode)();			//检索keymap

    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;		//当前占用该设备的input_handle
	//...
	struct list_head	h_list;				//handle链表,链接此input_dev
	struct list_head	node;				//链入input_dev_list
	//...
};

/*事件处理*/
struct input_handler {
	void *private;
	void (*event)();		//处理设备驱动报告的事件
	void (*events)();
	bool (*filter)();
	bool (*match)();
	int (*connect)();		//连接handler和input_dev
	void (*disconnect)();	//断开连接
	void (*start)();		//启动指定handle的handler函数

	bool legacy_minors;
	int minor;
	const char *name;		//handler名

	const struct input_device_id *id_table;	//输入设备id列表,匹配input_dev设备信息

	struct list_head	h_list;	//链入handle链表
	struct list_head	node;	//链入input_handler_list
};

/* 
 * 连接 input_dev 和 handler 的桥梁
 * 一个 input_dev 可以对应多个 handler , 一个 handler 也可以对应多个dev
*/
struct input_handle {
	int open; // 设备打开次数(上层访问次数)
	const char *name;

	struct input_dev *dev;  // 所属 input_dev
	struct input_handler *handler; // 所属 handler

	struct list_head	d_node; // 链入对应 input_dev 的 h_list
	struct list_head	h_node; // 链入对应 handler 的 h_list
};
/* 事件载体,输入子系统的事件包装为 input_event 上传到 Framework*/
struct input_event {
 struct timeval time; // 时间戳
 __u16 type;  // 事件类型
 __u16 code;  // 事件代码
 __s32 value;  // 事件值,如坐标的偏移值
};

对于handler和device,分别用链表input_handler_listinput_device_list进行维护,这两条是全局链表

input_handle结构体代表一个成功配对的input_devinput_handlerinput_handle没有一个全局的链表,它注册的时候将自己分别挂在input_device_listinput_handler_listh_list上;同时,input_handle的成员.dev,关联到input_dev结构,.handler关联到input_handler结构。

输入子系统流程
  • 子系统入口函数:subsys_initcall(input_init);
  • class_register(&input_class):在/sys/class下创建input类
  • input_proc_init():在/proc下建立相关文件
  • register_chrdev_region(MKDEV(INPUT_MAJOR, 0), INPUT_MAX_CHAR_DEVICES, "input"):申请字符设备主设备号为13
  • 注册input设备
  • 添加设备
  • 把输入设备挂到输入设备链表input_dev_list
  • 遍历input_handler_list链表,查找并匹配输入设备对应的时间处理层,如果匹配上,就调用handlerconnect函数进行连接。
  • 事件处理入口函数:module_init(evdev_init); -> input_register_handler
  • 把设备处理器挂到全局的input子系统设备链表input_handler_list
  • 遍历input_dev_list,与每一个input_dev进行匹配:input_attach_handler
  • input_attach_handler
  • input_match_device
  • handler->connect
  • 申请此设备号:input_get_new_monor
  • 设置设备节点名称/dev/eventX
  • 设置应用层使用的设备号
  • input_dev设备驱动和handler事件处理层的关联:input_register_handler
  • 将设备加入到Linux设备模型:device_add
  • 上报事件
  • input_report_xx()
  • input_event()
  • input_sync
  • input_event()