Linux Input子系统3(基于Linux6.6)---输入核心层介绍
在 Linux 内核中,输入核心层(或称为输入子系统的核心)是 input 子系统 的关键组成部分,负责管理各种输入设备、处理输入事件,并提供与用户空间的接口。输入核心层是输入子系统的基础,它承载了输入设备的注册、事件的处理、以及与用户空间的交互等核心功能。
输入核心层的主要职责包括:
- 管理输入设备:处理输入设备的注册与注销,维护输入设备的生命周期。
- 事件的捕捉与传递:处理来自设备的输入事件,确保事件的正确传递到相应的用户空间应用程序。
- 输入事件类型的支持:支持多种输入事件类型(如键盘按键、鼠标移动、触摸屏坐标等)。
- 提供与用户空间的接口:通过设备文件接口(如
/dev/input/eventX
),允许用户空间应用读取输入事件。
一、input子系统的实现
注册input子系统本身很简单只需要在sysfs中注册号相应的设备类和主设备号即可。
drivers/input/input.c
static char *input_devnode(const struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
}
struct class input_class = {
.name = "input",
.devnode = input_devnode,
};
EXPORT_SYMBOL_GPL(input_class);
static int __init input_init(void)
{
int err;
err = class_register(&input_class); /* 在sysfs中的class类下注册一个input的类 */
if (err) {
printk(KERN_ERR "input: unable to register input_dev class\n");
return err;
}
err = input_proc_init(); /* 初始化proc文件系统 */
if (err)
goto fail1;
err = register_chrdev(INPUT_MAJOR, "input", &input_fops); /* 注册字符设备驱动 */
if (err) {
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
goto fail2;
}
return 0;
fail2: input_proc_exit();
fail1: class_unregister(&input_class);
return err;
}
取消注册就更简单来,和注册相反即可。
drivers/input/input.c
static void __exit input_exit(void)
{
input_proc_exit();
unregister_chrdev_region(MKDEV(INPUT_MAJOR, 0),
INPUT_MAX_CHAR_DEVICES);
class_unregister(&input_class);
}
二、设备驱动层提供的接口函数
2.1、初始化
设备描述结构体变量,同时初始化一些通用性数据。
drivers/input/input.c
/**
* input_allocate_device - allocate memory for new input device
*
* Returns prepared struct input_dev or %NULL.
*
* NOTE: Use input_free_device() to free devices that have not been
* registered; input_unregister_device() should be used for already
* registered devices.
*/
struct input_dev *input_allocate_device(void)
{
static atomic_t input_no = ATOMIC_INIT(-1);
struct input_dev *dev;
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); /* 申请内存 */
if (dev) {
dev->dev.type = &input_dev_type; /* 绑定设备信息 */
dev->dev.class = &input_class; /* 绑定在sysfs所属的类,后面的register里面的add_device后才能出现在sysfs下的input文件夹下 */
device_initialize(&dev->dev); /* 设备初始化 */
mutex_init(&dev->mutex);
spin_lock_init(&dev->event_lock);
INIT_LIST_HEAD(&dev->h_list); /* 初始化链表 */
INIT_LIST_HEAD(&dev->node);
__module_get(THIS_MODULE);
}
return dev;
}
EXPORT_SYMBOL(input_allocate_device);
2.2、设置dev设备的能力
只有注册前设置来它拥有的能力,将来该设备注册后,发送的信息才能被上报。
注意:该函数每次只能设置一个能力。
drivers/input/input.c
/* 根据type类型,设置code到相应的typebit */
/**
* input_set_capability - mark device as capable of a certain event
* @dev: device that is capable of emitting or accepting event
* @type: type of the event (EV_KEY, EV_REL, etc...)
* @code: event code
*
* In addition to setting up corresponding bit in appropriate capability
* bitmap the function also adjusts dev->evbit.
*/
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{
if (type < EV_CNT && input_max_code[type] &&
code > input_max_code[type]) {
pr_err("%s: invalid code %u for type %u\n", __func__, code,
type);
dump_stack();
return;
}
switch (type) {
case EV_KEY:
__set_bit(code, dev->keybit);
break;
case EV_REL:
__set_bit(code, dev->relbit);
break;
case EV_ABS:
input_alloc_absinfo(dev);
__set_bit(code, dev->absbit);
break;
case EV_MSC:
__set_bit(code, dev->mscbit);
break;
case EV_SW:
__set_bit(code, dev->swbit);
break;
case EV_LED:
__set_bit(code, dev->ledbit);
break;
case EV_SND:
__set_bit(code, dev->sndbit);
break;
case EV_FF:
__set_bit(code, dev->ffbit);
break;
case EV_PWR:
/* do nothing */
break;
default:
pr_err("%s: unknown type %u (code %u)\n", __func__, type, code);
dump_stack();
return;
}
__set_bit(type, dev->evbit);
}
EXPORT_SYMBOL(input_set_capability);
2.3、具体设备注册
drivers/input/input.c
int input_register_device(struct input_dev *dev)
{
struct input_devres *devres = NULL;
struct input_handler *handler;
unsigned int packet_size;
const char *path;
int error;
if (test_bit(EV_ABS, dev->evbit) && !dev->absinfo) {
dev_err(&dev->dev,
"Absolute device without dev->absinfo, refusing to register\n");
return -EINVAL;
}
if (dev->devres_managed) {
devres = devres_alloc(devm_input_device_unregister,
sizeof(*devres), GFP_KERNEL);
if (!devres)
return -ENOMEM;
devres->input = dev;
}
/* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit);
/* KEY_RESERVED is not supposed to be transmitted to userspace. */
__clear_bit(KEY_RESERVED, dev->keybit);
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev);
packet_size = input_estimate_events_per_packet(dev);
if (dev->hint_events_per_packet < packet_size)
dev->hint_events_per_packet = packet_size;
dev->max_vals = dev->hint_events_per_packet + 2;
dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
if (!dev->vals) {
error = -ENOMEM;
goto err_devres_free;
}
/*
* 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.
*/
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD])
input_enable_softrepeat(dev, 250, 33);
if (!dev->getkeycode)
dev->getkeycode = input_default_getkeycode;
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
if (dev->poller)
input_dev_poller_finalize(dev->poller);
error = device_add(&dev->dev);
if (error)
goto err_free_vals;
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)
goto err_device_del;
list_add_tail(&dev->node, &input_dev_list);
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
if (dev->devres_managed) {
dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
__func__, dev_name(&dev->dev));
devres_add(dev->dev.parent, devres);
}
return 0;
err_device_del:
device_del(&dev->dev);
err_free_vals:
kfree(dev->vals);
dev->vals = NULL;
err_devres_free:
devres_free(devres);
return error;
}
EXPORT_SYMBOL(input_register_device);
2.4、handler和dev做匹配
如果匹配上,则把两者绑定。
drivers/input/input.c
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); /* 匹配handler和dev */
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id); /* 做具体的绑定handler和dev工作,由具体的事驱动层实现 */
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;
}
2.5、匹配handler和dev
每一个事件驱动层在实现的时候都要实现一个struct input_device_id的表(数组),用来表明该事件驱动可以支持的设备。
include/linux/mod_devicetable.h
struct input_device_id {
kernel_ulong_t flags; /* flags表明下面的四个要不要匹配,已经用相关宏定义好 */
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;
kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
kernel_ulong_t driver_info;
};
如果填充时在handler里面的在flags标志里面置位了下面的某一个,则匹配时就会检查响应的(总线类型,厂商,设备号,设备版本)。如果没有置位相应位,则表明匹配时不检查响应的标志位。
include/linux/mod_devicetable.h
#define INPUT_DEVICE_ID_MATCH_BUS 1
#define INPUT_DEVICE_ID_MATCH_VENDOR 2
#define INPUT_DEVICE_ID_MATCH_PRODUCT 4
#define INPUT_DEVICE_ID_MATCH_VERSION 8
同时也可以置位需要匹配类型,
#define INPUT_DEVICE_ID_MATCH_EVBIT 0x0010
#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x0020
#define INPUT_DEVICE_ID_MATCH_RELBIT 0x0040
#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x0080
#define INPUT_DEVICE_ID_MATCH_MSCIT 0x0100
#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x0200
#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x0400
#define INPUT_DEVICE_ID_MATCH_FFBIT 0x0800
#define INPUT_DEVICE_ID_MATCH_SWBIT 0x1000
下面就是真正的通过input_device_id来匹配
drivers/input/input.c
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;
/* input_device_id是一个数组,从前向后依次遍历id_table中和dev里面的id和xxbit中完全匹配的 */
id = input_match_device(handler, dev);
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id);
if (error && error != -ENODEV)
pr_err("failed to attach handler %s to device %s, error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
bool input_match_device_id(const struct input_dev *dev,
const struct input_device_id *id)
{
/* 正如前面描述的handler中id_table置位了相应标志位才做匹配检查 */
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->bustype != dev->id.bustype)
return false;
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->vendor != dev->id.vendor)
return false;
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->product != dev->id.product)
return false;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id->version != dev->id.version)
return false;
/* 同一id_table里面的flags匹配成功,才能MATCH_BIT匹配 */
if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX) ||
!bitmap_subset(id->keybit, dev->keybit, KEY_MAX) ||
!bitmap_subset(id->relbit, dev->relbit, REL_MAX) ||
!bitmap_subset(id->absbit, dev->absbit, ABS_MAX) ||
!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX) ||
!bitmap_subset(id->ledbit, dev->ledbit, LED_MAX) ||
!bitmap_subset(id->sndbit, dev->sndbit, SND_MAX) ||
!bitmap_subset(id->ffbit, dev->ffbit, FF_MAX) ||
!bitmap_subset(id->swbit, dev->swbit, SW_MAX) ||
!bitmap_subset(id->propbit, dev->propbit, INPUT_PROP_MAX)) {
return false;
}
/* 看handler层有没有再定义macth匹配函数,如果没有,那到这里就是已经找到id了,否则,还要通过handler里面的match才能确定就是该id */
return true;
}
EXPORT_SYMBOL(input_match_device_id);
以某一个来分析MATCH_BIT宏。
#define MATCH_BIT(bit, max) \
for (i = 0; i < BITS_TO_LONGS(max); i++) \
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
break; \
if (i != BITS_TO_LONGS(max)) \
continue;
假设以keybit为例,宏替换后如下。可以发现,就是匹配handler里面的keybit值的dev里面keybit值。即每一项都要满足id_table中,该项(keybit的值)。即dev的key值可以有 1 2 3 4 5 6,handler中id_table可以只有1,2,3。这样也能匹配成功。
for (i = 0; i < BITS_TO_LONGS(KEY_MAX); i++)
if ((id->keybit[i] & dev->keybit[i]) != id->keybit[i])
break;
if (i != BITS_TO_LONGS(KEY_MAX))
continue;
以evdev的id_table分别举例,方便上面的理解。
首先看evdev的id_table:可以发现,它里面除了driver_info其他都是空的。即evdev的handler可以匹配所有的device
即空的flags:不用匹配flags
空的xxbit,不用匹配xxbit
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
2.6、unregister
它和register的顺序刚好相反,就不详细分析了
/**
* input_unregister_device - unregister previously registered device
* @dev: device to be unregistered
*
* This function unregisters an input device. Once device is unregistered
* the caller should not try to access it as it may get freed at any moment.
*/
void input_unregister_device(struct input_dev *dev)
{
if (dev->devres_managed) {
WARN_ON(devres_destroy(dev->dev.parent,
devm_input_device_unregister,
devm_input_device_match,
dev));
__input_unregister_device(dev);
/*
* We do not do input_put_device() here because it will be done
* when 2nd devres fires up.
*/
} else {
__input_unregister_device(dev);
input_put_device(dev);
}
}
EXPORT_SYMBOL(input_unregister_device);
至此,和核心层中input子系统和device相关的已经分析完毕。
三、事件驱动层提供的接口函数
接下来我们分析handler部分
3.1、handler注册
drivers/input/input.c
/**
* input_register_handler - register a new input handler
* @handler: handler to be registered
*
* This function registers a new input handler (interface) for input
* devices in the system and attaches it to all input devices that
* are compatible with the handler.
*/
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
int retval;
retval = mutex_lock_interruptible(&input_mutex);
if (retval)
return retval;
INIT_LIST_HEAD(&handler->h_list); /* 初始化自身链表 */
if (handler->fops != NULL) {
if (input_table[handler->minor >> 5]) { /* 每种handler的minor以32的倍数为base ,这里是检查当前handler类是不是已经注册过了,比如evdev的base是64,那么他就在input_table[2]中*/
retval = -EBUSY;
goto out;
}
input_table[handler->minor >> 5] = handler; /* 上面检查没被注册过,测在这里注册进input_table中 */
}
list_add_tail(&handler->node, &input_handler_list); /* 把当前handler加入到input核心增维护的两条重要链表之一的handler链表中去 */
/* 用当前的handler遍历核心层维护的两条重要链表之一的dev链表,并尝试匹配 */
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers(); /* 更新proce文件系统 */
out:
mutex_unlock(&input_mutex);
return retval;
}
匹配算法和device那边的完全一样。
这里要说明的是为什么即在注册handler的时候匹配一遍,又要在注册device的时候匹配一次。
这是因为,通常系统不能确定是handler先注册,还是dev先注册。
假设只在注册dev的时候匹配handler(注册handler去掉匹配那几句代码 ),结果,devi先执行的,因为handler还没被注册,所以dev匹配失败。当注册handler的时候,因为没有了再次匹配,所以两者无法再接续到一块了。所以要在handler和dev注册都匹配一次,当然肯定是后面注册的才能匹配成。
3.2、handler解注册
drivers/input/input.c
/**
* input_unregister_handler - unregisters an input handler
* @handler: handler to be unregistered
*
* This function disconnects a handler from its input devices and
* removes it from lists of known handlers.
*/
void input_unregister_handler(struct input_handler *handler)
{
struct input_handle *handle, *next;
mutex_lock(&input_mutex);
list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
handler->disconnect(handle);
WARN_ON(!list_empty(&handler->h_list));
list_del_init(&handler->node);
if (handler->fops != NULL)
input_table[handler->minor >> 5] = NULL;
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
}
3.3、handle注册
还有一个注册函数就是handle的注册(与其说注册,其实就是把handler和dev的链表加入到handle的数据中)
drivers/input/input.c
/**
* input_register_handle - register a new input handle
* @handle: handle to register
*
* This function puts a new input handle onto device's
* and handler's lists so that events can flow through
* it once it is opened using input_open_device().
*
* This function is supposed to be called from handler's
* connect() method.
*/
int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
int error;
/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
error = mutex_lock_interruptible(&dev->mutex);
if (error)
return error;
/*
* Filters go to the head of the list, normal handlers
* to the tail.
*/
if (handler->filter)
list_add_rcu(&handle->d_node, &dev->h_list);
else
list_add_tail_rcu(&handle->d_node, &dev->h_list); /* 把dev加入到handle */
mutex_unlock(&dev->mutex);
/*
* Since we are supposed to be called from ->connect()
* which is mutually exclusive with ->disconnect()
* we can't be racing with input_unregister_handle()
* and so separate lock is not needed here.
*/
list_add_tail_rcu(&handle->h_node, &handler->h_list); /* 把handler加入到handle */
if (handler->start)
handler->start(handle);
return 0;
}
4.handle解注册
drivers/input/input.c
/**
* input_unregister_handle - unregister an input handle
* @handle: handle to unregister
*
* This function removes input handle from device's
* and handler's lists.
*
* This function is supposed to be called from handler's
* disconnect() method.
*/
void input_unregister_handle(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
list_del_rcu(&handle->h_node);
/*
* Take dev->mutex to prevent race with input_release_device().
*/
mutex_lock(&dev->mutex);
list_del_rcu(&handle->d_node);
mutex_unlock(&dev->mutex);
synchronize_rcu();
}
RCU(Read-Copy-Update)是一种优化的数据结构更新机制,广泛用于 Linux 内核中,特别是在需要高并发读取和低开销写入的场景下。RCU 的核心思想是将读操作与写操作分离开来,允许多个读操作并行进行,而写操作则通过创建新的数据副本、替换旧数据的方式进行,从而减少锁的竞争和延迟。