Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反正这个是没变的,在android的底层开发中对于Linux的基本驱动程序设计还是没变的,当然Android底层机制也增加几个属于android自己的机制。
输入子系统由驱动层、输入子系统核心、事件处理层三部分组成。一个输入事件,如鼠标移动、键盘按下等通过Driver->Inputcore->Event
handler->userspace的顺序到达用户控件的应用程序。Android中的input设备驱动主要包括:游戏杆(joystick)、鼠标(mouse)和事件设备(Event)。
1、Input输入子系统的构架,在网上找到两幅灰常漂亮的图。
驱动层:将底层的硬件输入转化为统一事件形式,向输入核心(Input
Core)汇报。
输入子系统核心:承上启下。为驱动层提供输入设备注册与操作接口,如:input_register_device;通知事件处理层对事件进行处理;在/Proc下产生相应的设备信息
事件处理层:主要是和用户空间交互。(Linux中在用户空间将所有的设备都当作文件来处理,由于在一般的驱动程序中都有提供fops接口,以及在/dev下生成相应的设备文件nod,这些操作在输入子系统中由事件处理层完成)
下面这幅更漂亮,更直观的能看出input型输入子系统究竟是什么咚咚,更能够体现出,用户空间,内核空间,驱动程序是怎么关联起来的。。。
Input驱动同样也是字符设备,主设备号是13,次设备号是64~95之间自动生成的,这个Input驱动程序那是相当相当的复杂。在android内核中主要需要关注一下几个文件
a)include/linux/input.h(驱动头文件)
b)driver/input/input.c (驱动核心实现,包含大量的操作接口)
c)driver/input/event.c
(event机制)
d)driver/input/joydev.c
(joystick驱动)
e)driver/input/mousedev.c(鼠标驱动)
其实上面这些东西都不要我们自己去实现内核已经帮我们实现好了,不过我们在写硬件驱动的时候需要和Inputcore交互,所以需要用到上面这些函数中的接口,也就是说上面这些函数是透明的。
2、Event事件驱动原理及其实现
+++++++++Event事件驱动原理
在内核中,用input_dev来描述一个Input设备,该结构的定义如下,其中内核中使用input_register_device(struct
input_dev *dev)来注册一个input设备
这个结构体好长,所以就列了几个。。。。它的定义在input.h当中
struct input_dev {
。。。。。。。。。。。
struct
input_id id;
bool
sync;struct device dev;
struct
list_head h_list; //
struct
list_head node; //input_handle链表的list节点
};
=======================
用input_handler表示input设备的接口,使用input_register_handler(structinput_handler
*handler)注册设备接口
struct
input_handler {
void
*private;
。。。。。。。。。。
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;
struct
list_head node;
};
+++++++++Event事件驱动实现过程
1) Input设备注册
int input_register_device(struct input_dev *dev)
{
static
atomic_t input_no = ATOMIC_INIT(0);
struct
input_handler *handler;
const char
*path;
int
error;
__set_bit(EV_SYN, dev->evbit);//see to
inpu.h
__clear_bit(KEY_RESERVED, dev->keybit);
input_cleanse_bitmasks(dev);
init_timer(&dev->timer);
//处理重复按键.如果没赋值则为其赋默认的值
if
(!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD])
{
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}
if
(!dev->getkeycode)//获取键的扫描码
dev->getkeycode =
input_default_getkeycode;
if
(!dev->setkeycode)//设置键值
dev->setkeycode =
input_default_setkeycode;
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);
//将input_dev中封装的device注册到sysfs
error =
device_add(&dev->dev);
if
(error)
return error;
path =
kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified
device", path ? path : "N/A");
kfree(path);
error =
mutex_lock_interruptible(&input_mutex);
if (error)
{
device_del(&dev->dev);
return error;
}
//将input_device挂到input_dev_list链表中
list_add_tail(&dev->node,
&input_dev_list);
//对挂载在input_dev_list中的每一个handler调用input_attach_handler(dev,
handler);
list_for_each_entry(handler,
&input_handler_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return
0;
}
上述函数首先将input_device挂接到input_dev_list链表上,然后对挂载在input_dev_list中的每一个handler调用input_attach_handler(dev,
handler)来进行匹配,举个例子,设备模型中的device和driver的匹配,所有的input
device都挂载在input_dev_list上而所有的handler都挂载在input_handler_list上,那么它们是怎么联系起来的?匹配过程如下
static int input_attach_handler(struct input_dev *dev, struct
input_handler *handler)
{
const struct
input_device_id *id;
int
error;
id =
input_match_device(handler, dev);
if
(!id)
return -ENODEV;
error =
handler->connect(handler, dev, id);
if (error
&& error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s,
"
"error: %d\n",
handler->name,
kobject_name(&dev->dev.kobj), error);
return
error;
}
上面函数调用input_match_device来对handler,
dev通过input_device_id
*id来进行匹配如果匹配成功则调用handler->connect来关联struct
input_dev *dev, 和struct input_handler
*handler结构。下面看看input_match_device(handler,
dev)的过程
#define MATCH_BIT(bit, max) \
for (i = 0; i < BITS_TO_LONGS(max); i++)
\
if ((id->bit&
dev->bit) != id->bit) \
break; \
if (i != BITS_TO_LONGS(max)) \
continue;
static const struct input_device_id *input_match_device(struct
input_handler *handler,struct input_dev *dev)
{
const struct
input_device_id *id;
int i;
for (id =
handler->id_table; id->flags || id->driver_info; id++)
{//flags配置匹配的类型
if (id->flags &
INPUT_DEVICE_ID_MATCH_BUS)//匹配总线类型
if (id->bustype != dev->id.bustype)
continue;
if (id->flags &
INPUT_DEVICE_ID_MATCH_VENDOR)//匹配厂商
if (id->vendor != dev->id.vendor)
continue;
if (id->flags &
INPUT_DEVICE_ID_MATCH_PRODUCT)//匹配制造商
if (id->product != dev->id.product)
continue;
if (id->flags &
INPUT_DEVICE_ID_MATCH_VERSION)//匹配版本号
if (id->version != dev->id.version)
continue;
//如果上面的id->flags匹配成功或者是id->flags没有定义则执行下面的函数
MATCH_BIT(evbit, EV_MAX);
MATCH_BIT(keybit, KEY_MAX);
MATCH_BIT(relbit, REL_MAX);
MATCH_BIT(absbit, ABS_MAX);
MATCH_BIT(mscbit, MSC_MAX);
MATCH_BIT(ledbit, LED_MAX);
MATCH_BIT(sndbit, SND_MAX);
MATCH_BIT(ffbit, FF_MAX);
MATCH_BIT(swbit, SW_MAX);
if (!handler->match ||
handler->match(handler, dev))
return id;
}
return
NULL;
}
驱动层只是把输入设备注册到输入子系统中,驱动层的代码本身是没有创建设备节点的,而是由EventHander层调用InputCore中的函数来实现,当某个事件触发时都将通过input
_event()来将input event传送到input.c中,再由input.c分配事件到每一个"input
handler"
2)input
_event是怎么实现的
void input_event(struct input_dev *dev,unsigned int type, unsigned
int code, int value)
{
unsigned
long flags;
if
(is_event_supported(type, dev->evbit, EV_MAX)) {
spin_lock_irqsave(&dev->event_lock,
flags);
add_input_randomness(type, code, value);
input_handle_event(dev, type, code, value);
spin_unlock_irqrestore(&dev->event_lock,
flags);
}
}
static
void input_handle_event(struct input_dev *dev,unsigned int type,
unsigned int code, int value)
{
int
disposition = INPUT_IGNORE_EVENT;
switch
(type) {
case
EV_SYN:
switch (code) {
case SYN_CONFIG:
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT:
if (!dev->sync) {
dev->sync = true;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case SYN_MT_REPORT:
dev->sync = false;
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
break;
case
EV_KEY:
if (is_event_supported(code, dev->keybit,
KEY_MAX) &&
!!test_bit(code, dev->key) != value) {
if (value != 2) {
__change_bit(code, dev->key);
if (value)
input_start_autorepeat(dev, code);
else
input_stop_autorepeat(dev);
}