您的位置:首页 > 移动开发 > Android开发

android4.0 input子系统分析(kernel部分)

2014-04-26 16:32 387 查看
一、前言

前面我们分析了android的input子系统的android部分的代码,下面我们继续来分析kernel部分的,对于这个系统kernel部分和标准linux差别不大,

google在原linux基础上增加了一些代码以使其更适合手持设备,比如支持多点触控设备,支持android特有的4个按键等等。我们会一步一步的分析

内核代码,来分析出input系统的工作原理。

二、input设备类的注册

在input系统android部分我们知道了,在android层的eventhub中,建立了一个epoll,来监控/dev/input目录下有效的input设备所有事件,如果有

事件输入的话就会读出当前事件,然后交给android上层处理。所使用的方法也是 open(),read(),close()的标准方法。因此我们要分析这个input

系统的话,要从/dev/input下的设备文件分的实现析其,他的实现代码在android\kernel\drivers\input\input.c文件中,input也是内核的一个模块

我们从模块的初始化看起subsys_initcall(input_init);

[cpp]
view plaincopyprint?

static int __init input_init(void)
{
int err;

err = class_register(&input_class); //注册input设备类--------

if (err) { |
pr_err("unable to register input_dev class\n"); |
return err; |
} V
/****************************************************************
struct class input_class = {
.name = "input",
.devnode = input_devnode,
};
********************************************************************/
err = input_proc_init(); //建立input类proc文件系统 见下面

if (err)
goto fail1;

err = register_chrdev(INPUT_MAJOR, "input", &input_fops);//注册字符设备驱动,此中包含了设备的具体操作函数 见下面

if (err) {
pr_err("unable to register char major %d", INPUT_MAJOR);
goto fail2;
}

return 0;

fail2: input_proc_exit();
fail1: class_unregister(&input_class);
return err;
}

static int __init input_init(void)
{
int err;

err = class_register(&input_class);    //注册input设备类--------
if (err) {                                                  |
pr_err("unable to register input_dev class\n");         |
return err;                                             |
}                                                           V
/****************************************************************
struct class input_class = {
.name        = "input",
.devnode    = input_devnode,
};
********************************************************************/
err = input_proc_init();    //建立input类proc文件系统   见下面
if (err)
goto fail1;

err = register_chrdev(INPUT_MAJOR, "input", &input_fops);//注册字符设备驱动,此中包含了设备的具体操作函数 见下面
if (err) {
pr_err("unable to register char major %d", INPUT_MAJOR);
goto fail2;
}

return 0;

fail2:    input_proc_exit();
fail1:    class_unregister(&input_class);
return err;
}


1.proc文件系统建立

我们首先对proc文件系统做一个介绍:/proc 文件系统是一个特殊的软件创建的文件系统, 内核用来输出消息到外界./proc 下的每个

文件都绑到一个内核函数上, 当文件被读的时候即时产生文件内容. 我们已经见到一些这样的文件起作用; 例如, /proc/modules, 常

常返回当前已加载的模块列表./proc 在 Linux 系统中非常多地应用. 很多现代 Linux 发布中的工具, 例如ps, top, 以及 uptime,

从 /proc 中获取它们的信息. 一些设备驱动也通过/proc 输出信息, 你的也可以这样做. /proc 文件系统是动态的, 因此你的模块

可以在任何时候添加或去除条目.-------Linux 设备驱动 第三版

input_proc_init()代码在android\kernel\drivers\input\input.c中

[cpp]
view plaincopyprint?

static int __init input_proc_init(void)
{
struct proc_dir_entry *entry;

proc_bus_input_dir = proc_mkdir("bus/input", NULL);//为input类创建/proc/bus/input目录

if (!proc_bus_input_dir) |
return -ENOMEM; V
/*********************************************************************************
proc_mkdir()函数定义在android\kernel_imx\fs\proc\generic.c中,这个函数调用
调用proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent);
这个函数定义也在这个文件中
struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
struct proc_dir_entry *parent)
{
struct proc_dir_entry *ent;

ent = __proc_create(&parent, name, S_IFDIR | mode, 2);
if (ent) {
if (proc_register(parent, ent) < 0) {
kfree(ent);
ent = NULL;
}
}
return ent;
}
函数调用__proc_create()定义在本文件中

static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
const char *name,
mode_t mode,
nlink_t nlink)
{
..................
if (xlate_proc_name(name, parent, &fn) != 0)//将name整理成/proc/name
goto out;
...................
//分配内存
ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
if (!ent) goto out;
//初始化这个这个proc子系统
memset(ent, 0, sizeof(struct proc_dir_entry));
memcpy(((char *) ent) + sizeof(struct proc_dir_entry), fn, len + 1);
ent->name = ((char *) ent) + sizeof(*ent);
ent->namelen = len;
ent->mode = mode;
ent->nlink = nlink;
atomic_set(&ent->count, 1);
ent->pde_users = 0;
spin_lock_init(&ent->pde_unload_lock);
ent->pde_unload_completion = NULL;
INIT_LIST_HEAD(&ent->pde_openers);//得到队列回首地址
out:
return ent;
}
到了这里我们就创建好了这个proc文件系统的子目录,下面继续创建设备文件
**************************************************************************************/
entry = proc_create("devices", 0, proc_bus_input_dir, //创建devices这个设备文件

&input_devices_fileops);
if (!entry)
goto fail1;

entry = proc_create("handlers", 0, proc_bus_input_dir,//创建handlers这个设备文件

&input_handlers_fileops);
if (!entry)
goto fail2;

return 0;

fail2: remove_proc_entry("devices", proc_bus_input_dir);
fail1: remove_proc_entry("bus/input", NULL);
return -ENOMEM;
}

static int __init input_proc_init(void)
{
struct proc_dir_entry *entry;

proc_bus_input_dir = proc_mkdir("bus/input", NULL);//为input类创建/proc/bus/input目录
if (!proc_bus_input_dir)        |
return -ENOMEM;             V
/*********************************************************************************
proc_mkdir()函数定义在android\kernel_imx\fs\proc\generic.c中,这个函数调用
调用proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent);
这个函数定义也在这个文件中
struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
struct proc_dir_entry *parent)
{
struct proc_dir_entry *ent;

ent = __proc_create(&parent, name, S_IFDIR | mode, 2);
if (ent) {
if (proc_register(parent, ent) < 0) {
kfree(ent);
ent = NULL;
}
}
return ent;
}
函数调用__proc_create()定义在本文件中

static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
const char *name,
mode_t mode,
nlink_t nlink)
{
..................
if (xlate_proc_name(name, parent, &fn) != 0)//将name整理成/proc/name
goto out;
...................
//分配内存
ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
if (!ent) goto out;
//初始化这个这个proc子系统
memset(ent, 0, sizeof(struct proc_dir_entry));
memcpy(((char *) ent) + sizeof(struct proc_dir_entry), fn, len + 1);
ent->name = ((char *) ent) + sizeof(*ent);
ent->namelen = len;
ent->mode = mode;
ent->nlink = nlink;
atomic_set(&ent->count, 1);
ent->pde_users = 0;
spin_lock_init(&ent->pde_unload_lock);
ent->pde_unload_completion = NULL;
INIT_LIST_HEAD(&ent->pde_openers);//得到队列回首地址
out:
return ent;
}
到了这里我们就创建好了这个proc文件系统的子目录,下面继续创建设备文件
**************************************************************************************/
entry = proc_create("devices", 0, proc_bus_input_dir,   //创建devices这个设备文件
&input_devices_fileops);
if (!entry)
goto fail1;

entry = proc_create("handlers", 0, proc_bus_input_dir,//创建handlers这个设备文件
&input_handlers_fileops);
if (!entry)
goto fail2;

return 0;

fail2:    remove_proc_entry("devices", proc_bus_input_dir);
fail1: remove_proc_entry("bus/input", NULL);
return -ENOMEM;
}
这里创建了两个proc文件

a) 我们先看entry = proc_create("devices", 0, proc_bus_input_dir,&input_devices_fileops);

proc_create()是在proc_bus_input_dir创建名字为"devices"的proc文件,这个文件支持的操作由

input_devices_fileops来定义。当我们对这个文件读、写、查找时就是调用了他里面相应的函数,因

此我们重点来看这个参数

static const struct file_operations input_devices_fileops = {

.owner = THIS_MODULE,

.open = input_proc_devices_open,

.poll = input_proc_devices_poll,

.read = seq_read,

.llseek = seq_lseek,

.release = seq_release,

};

从这里看出,这个文件支持open poll read seek release这5个操作,这里还涉及到seq_file这个内核文件接口

我们再来介绍一下它:由于特殊性, 在/proc 下的大文件的实现有点麻烦.一直以来, /proc 方法因为当输出数量

变大时的错误实现变得声名狼藉. 作为一种清理 /proc 代码以及使内核开发者活得轻松些的方法, 添加了 seq_file

接口. 这个接口提供了简单的一套函数来实现大内核虚拟文件.set_file 接口假定你在创建一个虚拟文件, 它涉及

一系列的必须返回给用户空间的项. 为使用 seq_file, 你必须创建一个简单的 "iterator" 对象, 它能在

序列里建立一个位置, 向前进, 并且输出序列里的一个项.---------摘自LDD3

总的来讲seq_file是小的的proc文件以链表的形式合成一个大的文件,而方便用户使用。

下面我们一一来分析这几个函数

[cpp]
view plaincopyprint?

.open = input_proc_devices_open 打开文件
static int input_proc_devices_open(struct inode *inode, struct file *file)
{
return seq_open(file, &input_devices_seq_ops);//根据input_devices_seq_ops 初始化一个seq_file

}
input_devices_seq_ops的定义
static const struct seq_operations input_devices_seq_ops = {
.start = input_devices_seq_start, //起始位输入设备链表input_dev_list的首地址. input_dev_list是系统维护的所有输入设备的一个链表,

//通过这个链表可以访问系统所有的input设备

.next = input_devices_seq_next, //根据input_dev_list链表查找下个设备

.stop = input_seq_stop,
.show = input_devices_seq_show, //从设备连表里提取出哪些内容到seq_file中

}; |
V
static int input_devices_seq_show(struct seq_file *seq, void *v)
{
。。。。。。
seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", //首先会是设备厂家ID ,产品ID,驱动版本

dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);

seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); //设备名字

seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : ""); //设备物理设备文件路径

seq_printf(seq, "S: Sysfs=%s\n", path ? path : ""); //设备sysfs中的路径

seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : ""); //啥东西不认识

seq_printf(seq, "H: Handlers="); // input链表中的路径

list_for_each_entry(handle, &dev->h_list, d_node)
seq_printf(seq, "%s ", handle->name);
seq_putc(seq, '\n');

input_seq_print_bitmap(seq, "PROP", dev->propbit, INPUT_PROP_MAX); //设备的各种信息

input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX);
if (test_bit(EV_KEY, dev->evbit))
input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);
if (test_bit(EV_REL, dev->evbit))
input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);
if (test_bit(EV_ABS, dev->evbit))
input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);
if (test_bit(EV_MSC, dev->evbit))
input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);
if (test_bit(EV_LED, dev->evbit))
input_seq_print_bitmap(seq, "LED", dev->ledbit, LED_MAX);
if (test_bit(EV_SND, dev->evbit))
input_seq_print_bitmap(seq, "SND", dev->sndbit, SND_MAX);
if (test_bit(EV_FF, dev->evbit))
input_seq_print_bitmap(seq, "FF", dev->ffbit, FF_MAX);
if (test_bit(EV_SW, dev->evbit))
input_seq_print_bitmap(seq, "SW", dev->swbit, SW_MAX);

seq_putc(seq, '\n');

kfree(path);
return 0;
}

.open   = input_proc_devices_open 打开文件
static int input_proc_devices_open(struct inode *inode, struct file *file)
{
return seq_open(file, &input_devices_seq_ops);//根据input_devices_seq_ops 初始化一个seq_file
}
input_devices_seq_ops的定义
static const struct seq_operations input_devices_seq_ops = {
.start	= input_devices_seq_start,  //起始位输入设备链表input_dev_list的首地址. input_dev_list是系统维护的所有输入设备的一个链表,
//通过这个链表可以访问系统所有的input设备
.next	= input_devices_seq_next,   //根据input_dev_list链表查找下个设备
.stop	= input_seq_stop,
.show	= input_devices_seq_show,   //从设备连表里提取出哪些内容到seq_file中
};                  |
V
static int input_devices_seq_show(struct seq_file *seq, void *v)
{
。。。。。。
seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",  //首先会是设备厂家ID ,产品ID,驱动版本
dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);

seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : "");    //设备名字
seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");    //设备物理设备文件路径
seq_printf(seq, "S: Sysfs=%s\n", path ? path : "");             //设备sysfs中的路径
seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : "");    //啥东西不认识
seq_printf(seq, "H: Handlers=");                                    // input链表中的路径

list_for_each_entry(handle, &dev->h_list, d_node)
seq_printf(seq, "%s ", handle->name);
seq_putc(seq, '\n');

input_seq_print_bitmap(seq, "PROP", dev->propbit, INPUT_PROP_MAX);  //设备的各种信息

input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX);
if (test_bit(EV_KEY, dev->evbit))
input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);
if (test_bit(EV_REL, dev->evbit))
input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX);
if (test_bit(EV_ABS, dev->evbit))
input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX);
if (test_bit(EV_MSC, dev->evbit))
input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX);
if (test_bit(EV_LED, dev->evbit))
input_seq_print_bitmap(seq, "LED", dev->ledbit, LED_MAX);
if (test_bit(EV_SND, dev->evbit))
input_seq_print_bitmap(seq, "SND", dev->sndbit, SND_MAX);
if (test_bit(EV_FF, dev->evbit))
input_seq_print_bitmap(seq, "FF", dev->ffbit, FF_MAX);
if (test_bit(EV_SW, dev->evbit))
input_seq_print_bitmap(seq, "SW", dev->swbit, SW_MAX);

seq_putc(seq, '\n');

kfree(path);
return 0;
}


也就是说当我们打开devices这个文件的时候,应该可以读到所有设备的上面这些配置信息。

.poll = input_proc_devices_poll,//poll查询等待

[cpp]
view plaincopyprint?

static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &input_devices_poll_wait, wait);
if (file->f_version != input_devices_state) {
file->f_version = input_devices_state;
return POLLIN | POLLRDNORM;
}

return 0;
}

static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &input_devices_poll_wait, wait);
if (file->f_version != input_devices_state) {
file->f_version = input_devices_state;
return POLLIN | POLLRDNORM;
}

return 0;
}


.read = seq_read,

.llseek = seq_lseek,

.release = seq_release,

这三个都是seq_file的标准操作函数,实现文件的读取查找和关闭,不多做说明。

总结来看,这个device这个文件就是input设备的描述文件,他从input_dev_list中读取设备信息,然后放到seq_file中

供使用者方便的查看设备。

b) entry = proc_create("handlers", 0, proc_bus_input_dir,&input_handlers_fileops);

这个proc文件还是看参数input_handlers_fileops

[cpp]
view plaincopyprint?

static const struct file_operations input_handlers_fileops = {
.owner = THIS_MODULE,
.open = input_proc_handlers_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};

static const struct file_operations input_handlers_fileops = {
.owner		= THIS_MODULE,
.open		= input_proc_handlers_open,
.read		= seq_read,
.llseek		= seq_lseek,
.release	= seq_release,
};


同样的

.read = seq_read,

.llseek
= seq_lseek,

.release
= seq_release

这三个都是seq_file的标准操作函数不做说明,重点来看

.open = input_proc_handlers_open,

[cpp]
view plaincopyprint?

static int input_proc_handlers_open(struct inode *inode, struct file *file)
{
return seq_open(file, &input_handlers_seq_ops);
}
参数input_handlers_seq_ops的定义
static const struct seq_operations input_handlers_seq_ops = {
.start = input_handlers_seq_start, //返回input_handler_list的首地址。每个input设备的输入事件,都可以附加它的处理程序,这个处理程序可以通过input_handler连接到设备上

//同一时间可以有不同的程序连接到不同的输入设备上,这个链表就是维护不同设备和其处理事件的连接结构体的链表

.next = input_handlers_seq_next, //链表下一个节点

.stop = input_seq_stop,
.show = input_handlers_seq_show, //打开这个文件所显示的信息

}; |
V
static int input_handlers_seq_show(struct seq_file *seq, void *v)
{
struct input_handler *handler = container_of(v, struct input_handler, node);
union input_seq_state *state = (union input_seq_state *)&seq->private;

seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);//编号 和 handler的名字

if (handler->filter)
seq_puts(seq, " (filter)"); //有没有filter

if (handler->fops)
seq_printf(seq, " Minor=%d", handler->minor);//表示 handler 实现的文件操作集,这里不是很重要。

seq_putc(seq, '\n');

return 0;
}

static int input_proc_handlers_open(struct inode *inode, struct file *file)
{
return seq_open(file, &input_handlers_seq_ops);
}
参数input_handlers_seq_ops的定义
static const struct seq_operations input_handlers_seq_ops = {
.start	= input_handlers_seq_start, //返回input_handler_list的首地址。每个input设备的输入事件,都可以附加它的处理程序,这个处理程序可以通过input_handler连接到设备上
//同一时间可以有不同的程序连接到不同的输入设备上,这个链表就是维护不同设备和其处理事件的连接结构体的链表
.next	= input_handlers_seq_next,  //链表下一个节点
.stop	= input_seq_stop,
.show	= input_handlers_seq_show, //打开这个文件所显示的信息
};                      |
V
static int input_handlers_seq_show(struct seq_file *seq, void *v)
{
struct input_handler *handler = container_of(v, struct input_handler, node);
union input_seq_state *state = (union input_seq_state *)&seq->private;

seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);//编号 和 handler的名字
if (handler->filter)
seq_puts(seq, " (filter)");             //有没有filter
if (handler->fops)
seq_printf(seq, " Minor=%d", handler->minor);//表示 handler 实现的文件操作集,这里不是很重要。
seq_putc(seq, '\n');

return 0;
}


到了这里input设备类的proc文件系统已经建立完成了,总结一下,这个文件系统,提供了设备查询,设备事件处理程序关联方法,就是为了方便用户使用的一个接口。

2.注册字符设备

err = register_chrdev(INPUT_MAJOR, "input", &input_fops);注册一个字符设备,其主设备号为INPUT_MAJOR input设备,此设备号在0~256之间,由系统自动指定

这个字符设备的操作函数集input_fops:

static const struct file_operations input_fops = {

.owner = THIS_MODULE,

.open = input_open_file,

.llseek = noop_llseek,

};

input设备支持open 和 seek两种操作。

到了这里整个input设备类的注册已经完成了。总结一下,input设备类注册过程,首先注册一个类,然后注册proc文件系统,最后注册input的字符设备。

二、input设备注册

一个输入设备要加载到系统中,需要调用int input_register_device(struct input_dev *dev)

[cpp]
view plaincopyprint?

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;

/* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit); //强制加入 EV_SYN 事件

/* KEY_RESERVED is not supposed to be transmitted to userspace. */
__clear_bit(KEY_RESERVED, dev->keybit); //用户空间不支持KEY_RESERVED

/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev);

if (!dev->hint_events_per_packet)
dev->hint_events_per_packet =
input_estimate_events_per_packet(dev);

/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*//初始化设备连击计时器,如果驱动没有填写连击参数就使用默认值
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", //input设备的名字叫 input0 input1 input2.。。。。

(unsigned long) atomic_inc_return(&input_no) - 1);

error = device_add(&dev->dev); //使用device_add()函数将input_dev包含的device结构注册到Linux设备模型中,并可以在sysfs文件系统中表现出来。

if (error)
return error;

path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
pr_info("%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;
}

list_add_tail(&dev->node, &input_dev_list); //将设备加入到device_add中

list_for_each_entry(handler, &input_handler_list, node) //将设备和handler连接起来

input_attach_handler(dev, handler);

input_wakeup_procfs_readers();

mutex_unlock(&input_mutex);

return 0;
}

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;

/* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit);  //强制加入 EV_SYN 事件

/* KEY_RESERVED is not supposed to be transmitted to userspace. */
__clear_bit(KEY_RESERVED, dev->keybit); //用户空间不支持KEY_RESERVED

/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev);

if (!dev->hint_events_per_packet)
dev->hint_events_per_packet =
input_estimate_events_per_packet(dev);

/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*//初始化设备连击计时器,如果驱动没有填写连击参数就使用默认值
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",             //input设备的名字叫 input0 input1 input2.。。。。
(unsigned long) atomic_inc_return(&input_no) - 1);

error = device_add(&dev->dev);  //使用device_add()函数将input_dev包含的device结构注册到Linux设备模型中,并可以在sysfs文件系统中表现出来。
if (error)
return error;

path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
pr_info("%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;
}

list_add_tail(&dev->node, &input_dev_list); //将设备加入到device_add中

list_for_each_entry(handler, &input_handler_list, node) //将设备和handler连接起来
input_attach_handler(dev, handler);

input_wakeup_procfs_readers();

mutex_unlock(&input_mutex);

return 0;
}


到了这里input设备的注册已经完成了。设备注册就是生成设备文件,建立好各个目录中的设备连接,然后将handler 与之相连接

三、事件处理

在驱动中我们报告事件调用的是input_event()函数

[cpp]
view plaincopyprint?

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);
}
}

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);
}
}


主要来看input_handle_event这个函数是,上报事件的进一步传递

[cpp]
view plaincopyprint?

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);
}

disposition = INPUT_PASS_TO_HANDLERS;
}
break;

case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) {

__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;

case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX))
disposition = input_handle_abs_event(dev, code, &value);

break;

case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;

break;

case EV_MSC:
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;

break;

case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) {

__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;

case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {

if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;

case EV_REP:
if (code <= REP_MAX && value >= 0 && dev->rep
!= value) {
dev->rep[code] = value;
disposition = INPUT_PASS_TO_ALL;
}
break;

case EV_FF:
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;

case EV_PWR:
disposition = INPUT_PASS_TO_ALL;
break;
}

if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = false;

//上面是检测上报事件的有效性

if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)//如果需要设备处理参与的话

dev->event(dev, type, code, value);     //设备的事件处理函数是用户自定义的一个处理事件的函数。比如摁下caps lock键  键盘上会有一个灯打开和关闭 用的就是这个原理

if (disposition & INPUT_PASS_TO_HANDLERS)//如果需要handler参与

input_pass_event(dev, type, code, value);   //进行下一步的传递

}
我们看input_pass_event
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
struct input_handle *handle;

rcu_read_lock();

handle = rcu_dereference(dev->grab);
if (handle)
handle->handler->event(handle, type, code, value);
else {
bool filtered = false;

list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
if (!handle->open)
continue;

handler = handle->handler;
if (!handler->filter) {
if (filtered)
break;

handler->event(handle, type, code, value);

} else if (handler->filter(handle, type, code, value))
filtered = true;
}
}

rcu_read_unlock();
}

[code]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);
}

disposition = INPUT_PASS_TO_HANDLERS;
}
break;

case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) {

__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;

case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX))
disposition = input_handle_abs_event(dev, code, &value);

break;

case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;

break;

case EV_MSC:
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;

break;

case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) {

__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;

case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {

if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;

case EV_REP:
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
dev->rep[code] = value;
disposition = INPUT_PASS_TO_ALL;
}
break;

case EV_FF:
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;

case EV_PWR:
disposition = INPUT_PASS_TO_ALL;
break;
}

if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = false;

//上面是检测上报事件的有效性

if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)//如果需要设备处理参与的话
dev->event(dev, type, code, value);     //设备的事件处理函数是用户自定义的一个处理事件的函数。比如摁下caps lock键  键盘上会有一个灯打开和关闭 用的就是这个原理

if (disposition & INPUT_PASS_TO_HANDLERS)//如果需要handler参与
input_pass_event(dev, type, code, value);   //进行下一步的传递
}
我们看input_pass_event
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handler *handler;
struct input_handle *handle;

rcu_read_lock();

handle = rcu_dereference(dev->grab);
if (handle)
handle->handler->event(handle, type, code, value);
else {
bool filtered = false;

list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
if (!handle->open)
continue;

handler = handle->handler;
if (!handler->filter) {
if (filtered)
break;

handler->event(handle, type, code, value);

} else if (handler->filter(handle, type, code, value))
filtered = true;
}
}

rcu_read_unlock();
}


input_pass_event这个函数如果dev指定了handler的话就执行这个handler->event 如果没有的话就遍历所有handler_list 来查找合适handler->event

从这里可以看出如果我们要处理input_event的话,必须制定一个handler->event,事实上,我们从/dev/input目录下的设备文件读取事件也是这么做的,

我们接下来继续看。

首先我们必须找到设备 handler注册地方

我们知道读取事件都是在/dev/input/event0 ...设备上读去的,我们找到event设备的 创建函数在

android\kernel_imx\drivers\input\evdev.c中

[cpp]
view plaincopyprint?

static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
我们看到这里调用input_register_handler注册了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,
};
这里event=evdev_event,这就是处理事件的函数具体的

static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
struct timespec ts;

ktime_get_ts(&ts);
event.time.tv_sec = ts.tv_sec;
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
event.type = type;
event.code = code;
event.value = value;

rcu_read_lock();

client = rcu_dereference(evdev->grab); //得到一个client

if (client)
evdev_pass_event(client, &event); //把事件传递过去

else
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event);

rcu_read_unlock();

if (type == EV_SYN && code == SYN_REPORT)
wake_up_interruptible(&evdev->wait);
}

static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
我们看到这里调用input_register_handler注册了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,
};
这里event=evdev_event,这就是处理事件的函数具体的

static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
struct timespec ts;

ktime_get_ts(&ts);
event.time.tv_sec = ts.tv_sec;
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
event.type = type;
event.code = code;
event.value = value;

rcu_read_lock();

client = rcu_dereference(evdev->grab);  //得到一个client
if (client)
evdev_pass_event(client, &event);   //把事件传递过去
else
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event);

rcu_read_unlock();

if (type == EV_SYN && code == SYN_REPORT)
wake_up_interruptible(&evdev->wait);
}


我们继续看evdev_pass_event

[cpp]
view plaincopyprint?

static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);

client->buffer[client->head++] = *event;
client->head &= client->bufsize - 1;

if (unlikely(client->head == client->tail)) {
/*
* This effectively "drops" all unconsumed events, leaving
* EV_SYN/SYN_DROPPED plus the newest event in the queue.
*/
client->tail = (client->head - 2) & (client->bufsize - 1);

client->buffer[client->tail].time = event->time;
client->buffer[client->tail].type = EV_SYN;
client->buffer[client->tail].code = SYN_DROPPED;
client->buffer[client->tail].value = 0;

client->packet_head = client->tail;
if (client->use_wake_lock)
wake_unlock(&client->wake_lock);
}

if (event->type == EV_SYN && event->code == SYN_REPORT) {
client->packet_head = client->head;
if (client->use_wake_lock)
wake_lock(&client->wake_lock);
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}

spin_unlock(&client->buffer_lock);
}

static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);

client->buffer[client->head++] = *event;
client->head &= client->bufsize - 1;

if (unlikely(client->head == client->tail)) {
/*
* This effectively "drops" all unconsumed events, leaving
* EV_SYN/SYN_DROPPED plus the newest event in the queue.
*/
client->tail = (client->head - 2) & (client->bufsize - 1);

client->buffer[client->tail].time = event->time;
client->buffer[client->tail].type = EV_SYN;
client->buffer[client->tail].code = SYN_DROPPED;
client->buffer[client->tail].value = 0;

client->packet_head = client->tail;
if (client->use_wake_lock)
wake_unlock(&client->wake_lock);
}

if (event->type == EV_SYN && event->code == SYN_REPORT) {
client->packet_head = client->head;
if (client->use_wake_lock)
wake_lock(&client->wake_lock);
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}

spin_unlock(&client->buffer_lock);
}


这个函数就是把相应的input_event放入到 client->buffer 的队列中。到了这里,我们看到输入设备的事件处理,被放到一个队列里,那么然后呢?

我从event中读事件,是调用的 evdev的read函数,我们来看

evdev的操作集.fops = &evdev_fops,

[cpp]
view plaincopyprint?

static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync,
.flush = evdev_flush,
.llseek = no_llseek,
};

static const struct file_operations evdev_fops = {
.owner		= THIS_MODULE,
.read		= evdev_read,
.write		= evdev_write,
.poll		= evdev_poll,
.open		= evdev_open,
.release	= evdev_release,
.unlocked_ioctl	= evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl	= evdev_ioctl_compat,
#endif
.fasync		= evdev_fasync,
.flush		= evdev_flush,
.llseek		= no_llseek,
};


可以看到读取函数为evdev_read 我们继续看

[cpp]
view plaincopyprint?

static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
int retval = 0;

if (count < input_event_size())
return -EINVAL;

if (!(file->f_flags & O_NONBLOCK)) {
retval = wait_event_interruptible(evdev->wait,
client->packet_head != client->tail || !evdev->exist);
if (retval)
return retval;
}

if (!evdev->exist)
return -ENODEV;

while (retval + input_event_size() <= count && //事件不为

evdev_fetch_next_event(client, &event)) {

if (input_event_to_user(buffer + retval, &event))//把事件拷贝到 usr的buff中

return -EFAULT;

retval += input_event_size();
}

if (retval == 0 && file->f_flags & O_NONBLOCK)
retval = -EAGAIN;
return retval;
}

static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
int retval = 0;

if (count < input_event_size())
return -EINVAL;

if (!(file->f_flags & O_NONBLOCK)) {
retval = wait_event_interruptible(evdev->wait,
client->packet_head != client->tail || !evdev->exist);
if (retval)
return retval;
}

if (!evdev->exist)
return -ENODEV;

while (retval + input_event_size() <= count &&  //事件不为
evdev_fetch_next_event(client, &event)) {

if (input_event_to_user(buffer + retval, &event))//把事件拷贝到 usr的buff中
return -EFAULT;

retval += input_event_size();
}

if (retval == 0 && file->f_flags & O_NONBLOCK)
retval = -EAGAIN;
return retval;
}


到了这里所有的事件处理已经完成了。总结一下,事件读取设备文件evdev 是独立于input_device的一个内核模块,两者通过input_handler联系起来

当input_device收到驱动发送的event以后,会回调evdev的处理函数,把event复制到一个缓存中,当我们从evdev读取数据时,相应的处理函数会把

event复制到buff中,因此我们就读取到了事件。android读取到事件以后,就会进行android层面的input_event处理
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: