Android Input子系统浅谈
本文主要讲解[Android Input 子系统][6],我会从一下几个方面讲解:
- linux kernel的input子系统框架
- 以触摸屏驱动为例讲解内核input子系统
- Android framework层Input子系统的框架
- Input子系统的应用程序接口
linux kernel里面input子系统框架
- **主要作用是维护两个重要的链表input_dev_list和input_handler_list
- 下面这段代码便是内核里面Input子系统的框架层部分代码
代码位置:/kernel/driver/input/input.c
可以看到input的内核框架层也是以类似于driver的方式注册的
这段代码便是Input子系统在内核中的核心框架;大家可能会疑惑怎么这
么简单,看着什么也没有做,其实却是这样,这这段code里面主要建立
了一些用于debug的节点,主要有如下节点:
class节点/sys/class/input :调用class_register生成
proc节点/proc/bus/input/devices和handles:调用input_proc_init生成
dev节点:/dev/input:调用register_chrdev_region
以上三种节点在后面会讲解分别用作什么
static int __init input_init(void)
{
int err;
err = class_register(&input_class);
if (err) {
pr_err("unable to register input_dev class\n");
return err;
}
err = input_proc_init();
if (err)
goto fail1;
err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),
INPUT_MAX_CHAR_DEVICES, "input");
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 void __exit input_exit(void)
{
input_proc_exit();
unregister_chrdev_region(MKDEV(INPUT_MAJOR, 0),
INPUT_MAX_CHAR_DEVICES);
class_unregister(&input_class);
}
subsys_initcall(input_init);
两个重要的链表
-
两个重要的链表 input_register_device():
- 向input_dev_list里面添加input device
-
调用input_attach_handler去匹配input_handler
input_register_handler(): - 向input_handler_list天剑input handler
- 调用input_attach_handler去匹配input_handler
注意上面这两个函数都提到了input_attach_handler()这意味着我们在注册我们的input device的时候会去匹配我们的input handler同时当我们去注册input handler的时候会去匹配input device
通常这两个函数是在我们的driver里面调用的
以触摸屏驱动为例讲解内核input子系统
input_dev = input_allocate_device();
if (!input_dev) {
err = -ENOMEM;
dev_err(&client->dev, "[Focal][Touch] %s: failed to allocate input device\n", __func__);
goto exit_input_dev_alloc_failed;
}
ftxxxx_ts->input_dev = input_dev;
set_bit(KEY_BACK, input_dev->keybit);
set_bit(KEY_HOME, input_dev->keybit);
set_bit(KEY_APPSELECT, input_dev->keybit);
//set_bit(KEY_POWER, input_dev->keybit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
// printk("maxx=%d,maxy=%d\n",ftxxxx_ts->x_max,ftxxxx_ts->y_max);
input_mt_init_slots(input_dev, CFG_MAX_TOUCH_POINTS, 0);
// input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, CFG_MAX_TOUCH_POINTS, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 31, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, ftxxxx_ts->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, ftxxxx_ts->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, PRESS_MAX, 0, 0);
input_dev->name = Focal_input_dev_name;
err = input_register_device(input_dev);
上面这段代码便是我摘抄的触摸屏驱动的部分代码,主要是input device的注册过程,重点函数是input_register_device()正如我们上面所说的他会去input_handler_list里面去寻找匹配input handler,对于向触摸屏和鼠标等我们的内核已经为我们注册好了input handler代码位于:/kernel/driver/input/evdev.c:
这段代码主要注册了一个input handler,我们的触摸屏驱动匹配到的就是这个handler
/kernel/driver/input/evdev.c:
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
static void __exit evdev_exit(void)
{
input_unregister_handler(&evdev_handler);
}
module_init(evdev_init);
module_exit(evdev_exit);
在touch driver里面调用input_register_device()会有如下关键的一段代码:
将input device添加进input_dev_list,并且对于每一个注册好的input handler调用input_attach_handler()去匹配device(在这里使我们的触摸屏)
list_add_tail(&dev->node, &input_dev_list);
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
。。。
下面便是匹配的代码:对于我们的touch 这里匹配到的就是我们在evdev.c里面注册好的handler,紧接着调用handler->connect(handler, dev, id);
会到evdev.c里面会知道这里的connect是evdev_connect()
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 (!