一、前言
前面我们分析了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);
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中
前面我们分析了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);
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中
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