目录
在Linux内核中,input设备用input_dev结构体描述,使用input子系统实现输入设备驱动的时候,驱动的核心工作是向系统报告按键、触摸屏、键盘、鼠标等输入事件(event,通过input_event结构体描述),不再需要关心文件操作接口,因为input子系统已经完成了文件操作接口。驱动报告的事件经过InputCore和 Eventhandler最终到达用户空间。下面给出一个使用input子系统的例子,通过这个例子来解析input子系统的方方面面。
(1)键盘驱动
static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1);
input_sync(&button_dev);
}
static int __init button_init(void)
{
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
printk(KERN_ERR "button.c: Can''t allocate irq %d\n", button_irq);
return -EBUSY;
}
button_dev.evbit[0] = BIT(EV_KEY);
button_dev.keybit[LONG(BTN_0)] = BIT(BTN_0);
input_register_device(&button_dev);
}
static void __exit button_exit(void)
{
input_unregister_device(&button_dev);
free_irq(BUTTON_IRQ, button_interrupt);
}
module_init(button_init);
module_exit(button_exit);
这是个最简单使用input子系统的例子,权且引出这input子系统,这个驱动中主要涉及input子系统的函数下面一一列出,后面会有详细的介绍:
1)set_bit(EV_KEY, button_dev.evbit);
set_bit(BTN_0, button_dev.keybit);
分别用来设置设备所产生的事件以及上报的按键值。Struct iput_dev中有两个成员,一个是evbit.一个是keybit,分别用表示设备所支持的动作和按键类型。
2)input_register_device(&button_dev);
用来注册一个input device.
2.1)request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)
申请中断的函数是request_irq()
3) input_report_key()
用于给上层上报一个按键动作
4)input_sync()
用来告诉上层,本次的事件已经完成了.
5) input_unregister_device()
用来注销一个input_dev设备
input 子系统也是作为内核的一个字符设备模块存在的,所以他也是字符设备自然也会有字符设备的文件接口.input子系统的注册过程主要分为两步,先注册了一个input class然后再注册一个字符设备 input。

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;
}
//proc 文件接口创建
err = input_proc_init();
if (err)
goto fail1;
//申请input设备号 主设备号13 最多1024个此类子设备
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;
}

注意这里仅仅创建了input 类并未在这个类下创建设备,同时申请了主设备号为13,次设备号为0-1024的设备号。input子系统和platform_bus 的思想很相同,分为核心层、input_dev(类似设备) 和input_handler(类似drivers)。当一个input_dev添加到内核时如果设备的id和handler的ids相匹配则会执行handler的connet接口将设备和具体handler 链接。整个input子系统实现了输入设备的共性部分,而差异性的部分由具体的设备实现。具体来看其数据结构:
输入设备(dev)

struct input_dev {
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
unsigned int hint_events_per_packet;
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode);
int (*getkeycode)(struct input_dev *dev,
struct input_keymap_entry *ke);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int rep[REP_CNT];
struct input_mt *mt;
struct input_absinfo *absinfo;
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle __rcu *grab;
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
struct device dev;
struct list_head h_list;
struct list_head node;
unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;
bool devres_managed;
};

输入事件处理结构(handler)

//handler
struct input_handler {
void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
void (*events)(struct input_handle *handle,
const struct input_value *vals, unsigned int count);
bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
bool (*match)(struct input_handler *handler, struct input_dev *dev);
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);
bool legacy_minors;
int minor;
const char *name;
const struct input_device_id *id_table;
struct list_head h_list;
struct list_head node;
};

我这里不打算一开始就从驱动框架开始学习,因为直接上框架比较抽象所以我先从一个突破口一步一步探索,这里的突破口我选择的是输入设备注册开始的地方。
输入设备注册

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 (dev->devres_managed) {
devres = devres_alloc(devm_input_device_unregister,
sizeof(struct input_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]) {
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;
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;
}

将设备加入到设备链表然后遍历input_handler_list(这是一个handler 的链表在handler注册的过程中加入)依次执行匹配,调用过程如下
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)————>>input_match_device(struct input_dev *dev, struct input_handler *handler)
实际是由 input_match_device 检查匹配过程的如下:

static const struct input_device_id *input_match_device(struct input_handler *handler,
struct input_dev *dev)
{
const struct input_device_id *id;
for (id = handler->id_table; id->flags || id->driver_info; id++) {
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;
if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX))
continue;
if (!bitmap_subset(id->keybit, dev->keybit, KEY_MAX))
continue;
if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX))
continue;
if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX))
continue;
if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX))
continue;
if (!bitmap_subset(id->ledbit, dev->ledbit, LED_MAX))
continue;
if (!bitmap_subset(id->sndbit, dev->sndbit, SND_MAX))
continue;
if (!bitmap_subset(id->ffbit, dev->ffbit, FF_MAX))
continue;
if (!bitmap_subset(id->swbit, dev->swbit, SW_MAX))
continue;
if (!handler->match || handler->match(handler, dev))
return id;
}
return NULL;
}

先看一下一个数据结构struct input_device_id即
struct input_id {
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;
};
遍历handler 的id表,依次进行和当前设备id的匹配,匹配规则基本如下:
1、检查handler是否要求匹配总线类型,如果需要则进行匹配,匹配成功或不需要匹配则下一步,失败则下一个匹配项。
2、检查handler是否要求匹配厂商id,结果同上。
3、检查handler是否要求匹配产品id,同上。
4、检查handler是否要求匹配版本id,同上。
5、设备支持的所以输入事件类型是否都是当前的handler的子集,如果是则算匹配第一步符合继续下一步,否则下一个。
6、检查handler有无match接口函数,有则执行返回非0则算匹配成功返回handler 发生匹配的ID (struct input_device_id*),无则直接返回第一阶段匹配的Id。
再回到input_attach_handler 接口:

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)
pr_err("failed to attach handler %s to device %s, error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}

可以看到如果前面的前面的input_match_device如果匹配了设备则返回id,然后则执行handler的connect 接口定义是int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);由这个接口完成dev和handler的链接。拿事件设备(evdev.c)作为例子来分析其具体接口的实现 。
事件设备的connect 接口:

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct evdev *evdev;
int minor;
int dev_no;
int error;
minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
if (minor < 0) {
error = minor;
pr_err("failed to reserve new minor: %d\n", error);
return error;
}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
if (!evdev) {
error = -ENOMEM;
goto err_free_minor;
}
INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);
evdev->exist = true;
dev_no = minor;
/* Normalize device number if it falls into legacy range */
if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
dev_no -= EVDEV_MINOR_BASE;
dev_set_name(&evdev->dev, "event%d", dev_no);
evdev->handle.dev = input_get_device(dev);
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler;
evdev->handle.private = evdev;
evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
error = input_register_handle(&evdev->handle);
if (error)
goto err_free_evdev;
cdev_init(&evdev->cdev, &evdev_fops);
evdev->cdev.kobj.parent = &evdev->dev.kobj;
error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
if (error)
goto err_unregister_handle;
error = device_add(&evdev->dev);
if (error)
goto err_cleanup_evdev;
return 0;
err_cleanup_evdev:
evdev_cleanup(evdev);
err_unregister_handle:
input_unregister_handle(&evdev->handle);
err_free_evdev:
put_device(&evdev->dev);
err_free_minor:
input_free_minor(minor);
return error;
}

执行过程是分配一个事件设备子设备号在创建文件接口event%d 时需要,分配一个事件设备结构体,这个结构体如下:

struct evdev {
int open;
struct input_handle handle;
wait_queue_head_t wait;
struct evdev_client __rcu *grab;
struct list_head client_list;
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
struct cdev cdev;
bool exist;
};

他带出来了input子系统的另外一个重要数据类型struct input_handle,他是负责链接handler和dev的数据结构如下:

struct input_handle {
void *private;
int open;
const char *name;
struct input_dev *dev;
struct input_handler *handler;
struct list_head d_node;
struct list_head h_node;
};

这里暂时不继续深究,继续上面connect的过程分析,分配好对应的数据块后就是初始化,然后就是设置数据块中的设备名称这是为了sys文件系统的显示(event%d)然后就是handle发挥作用的时候如下这部分在connect中:
evdev->handle.dev = input_get_device(dev); evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev;
然后接着初始化新设备的相关内容,后面将要进行注册这个过程和platform设备的处理过程相似。
evdev->dev.devt = MKDEV(INPUT_MAJOR, minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; evdev->dev.release = evdev_free; device_initialize(&evdev->dev);
然后就是input自系统的API,input_register_handle(struct input_handle* )注意区分handle 和 handler 接下来就是“偷梁换柱”的准备工作了--->注意绑定了一个文件操作接口。

cdev_init(&evdev->cdev, &evdev_fops);
evdev->cdev.kobj.parent = &evdev->dev.kobj;
error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
if (error)
goto err_unregister_handle;
error = device_add(&evdev->dev);

这里的evdev_fops 就是中间件用来“偷梁换柱”的关键,通过上面的操作这时候就会在/dev目录下看到对应的event%s设备了。到这里input子系统的三个成员已经出现了有input_dev、input_handler、input_handle,最后其实还有input_event 和 input_client。Linux内核对于input子系统的处理过程,除此之外上面描述的是设备的注册过程外同样的在handler的注册过程应该也是有一个类似的处理过程,思想和linux设备驱动的整个思想统一源码如下:

/**
* 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 error;
error = mutex_lock_interruptible(&input_mutex);
if (error)
return error;
INIT_LIST_HEAD(&handler->h_list);
list_add_tail(&handler->node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return 0;
}

后面我将分析一个常见input驱动evdev.c(事件设备)实例来分析学习下,其实上面的connect接口已经是事件设备的事件处理部分的接口了,所以可以看到在输入设备注册时符合匹配规则时就已经完成了事件处理接口的绑定,到这里驱动在内核中的加载的部分已经完成了接下来分析输入设备和用户空间是如何交互的。
事件设备实例
切入点从上面注册的字符设备的evdev_fops中的open接口开始作为切入点。

static int evdev_open(struct inode *inode, struct file *file)
{
//这里使用了一个架构知识盲区,即字符设备的inode中的i_cdev是记录字符设备的地址的
struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
//按照这个输入事件的具体实现了一个策略确定事件buf的个数
unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
unsigned int size = sizeof(struct evdev_client) +
bufsize * sizeof(struct input_event);
struct evdev_client *client;
int error;
client = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (!client)
client = vzalloc(size);
if (!client)
return -ENOMEM;
client->bufsize = bufsize;
spin_lock_init(&client->buffer_lock);
client->evdev = evdev;
//关联起来 将client的挂接到evdev事件设备上
evdev_attach_client(evdev, client);
//evdev其中的 handle->open ++
error = evdev_open_device(evdev);
if (error)
goto err_free_client;
//将这个client 绑定到文件节点的私有数据上,私有数据太重要了
file->private_data = client;
//以不可以执行lseek的方式执行打开操作
nonseekable_open(inode, file);
return 0;
err_free_client:
evdev_detach_client(evdev, client);
kvfree(client);
return error;
}

每一个打开输入设备的的进程都会由内核open接口分配一个client,这个client都会和用户空间的struct file *file的私有数据关联起来,具体参考代码注释。然后就是读取接口了。

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;
size_t read = 0;
int error;
if (count != 0 && count < input_event_size())
return -EINVAL;
for (;;) {
if (!evdev->exist || client->revoked)
return -ENODEV;
if (client->packet_head == client->tail &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
/*
* count == 0 is special - no IO is done but we check
* for error conditions (see above).
*/
if (count == 0)
break;
while (read + input_event_size() <= count &&
evdev_fetch_next_event(client, &event)) {
//拷贝一个input_event 到buff
if (input_event_to_user(buffer + read, &event))
return -EFAULT;
//增加读取到的字节数以便读取结束后返回
read += input_event_size();
}
//读到了数据不需要后续的阻塞处理
if (read)
break;
//什么也没读到则需要处理阻塞的逻辑,这里是直接使调用进程在当前的wait list上睡眠
if (!(file->f_flags & O_NONBLOCK)) {
error = wait_event_interruptible(evdev->wait,
client->packet_head != client->tail ||
!evdev->exist || client->revoked);
if (error)
return error;
//执行到这里就是因为有数据可以读而唤醒或者信号中断的
}
}
return read;
}

先从文件的私有数据中取出clients然后进行必要的参数检查,读取大小不能是0并且不能小于一个事件sizeof(struct input_event) 大小,然后遍历循环读取事件知道读到指定数量的数据或无事件可读,关键的就是其中的evdev_fetch_next_event接口处理,他会返回是否有事件可以读取,当有事件可以读取时事件地址保存在event指针,然后再将事件拷贝到用户提供的buf中。

static int evdev_fetch_next_event(struct evdev_client *client,
struct input_event *event)
{
int have_event;
spin_lock_irq(&client->buffer_lock);
have_event = client->packet_head != client->tail;
if (have_event) {
*event = client->buffer[client->tail++];
client->tail &= client->bufsize - 1;
}
spin_unlock_irq(&client->buffer_lock);
return have_event;
}

从处理逻辑可以判断事件在发生后都是保存在client下的一个链表中,实际的数据保存在起初为这个client分配的空间中。循环读取事件知道满足待读取的大小或读完事件然后返回实际读取到的字节数。既然这里可以读,那么是在什么时候输入事件被挂接并保存到这个client上的呢?继续找,这肯定是要找到handler的添加过程了。找到定义如下:

static struct input_handler evdev_handler = {
.event = evdev_event,
.events = evdev_events,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.legacy_minors = true,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};

事件的上报肯定从这里某一个接口实现的,猜测是设备调用的handler的接口来完成事件的上报,这里就直接看evdev_events接口,因为要想真的搞清楚还需要一个事件输入设备的代码来验证。

static void evdev_events(struct input_handle *handle,
const struct input_value *vals, unsigned int count)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
ktime_t time_mono, time_real;
time_mono = ktime_get();
time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
rcu_read_lock();
//这一部分代码不知道什么分支会运行到这里所以暂时不看,正常是执行地下else的分支
client = rcu_dereference(evdev->grab);
//上面特殊情况执行,所以下面的判断一般不成立
if (client)
evdev_pass_values(client, vals, count, time_mono, time_real);
else
//遍历这个事件上的所有clients 依次将事件放到对应的client上
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_values(client, vals, count,
time_mono, time_real);
rcu_read_unlock();
}

这个接口中主要就是获取系统时间,通过接口evdev_pass_values接口将事件绑定并保存到到每个client上如下:

static void evdev_pass_values(struct evdev_client *client,
const struct input_value *vals, unsigned int count,
ktime_t mono, ktime_t real)
{
struct evdev *evdev = client->evdev;
const struct input_value *v;
struct input_event event;
bool wakeup = false;
//这个标志意味着这个client不接收事件
if (client->revoked)
return;
//构造事件
event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
mono : real);
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
for (v = vals; v != vals + count; v++) {
event.type = v->type;
event.code = v->code;
event.value = v->value;
//发送事件到client
__pass_event(client, &event);
if (v->type == EV_SYN && v->code == SYN_REPORT)
wakeup = true;
}
spin_unlock(&client->buffer_lock);
//唤醒逻辑
if (wakeup)
wake_up_interruptible(&evdev->wait);
}

整个处理过程就是将传进来的内核事件加上时间信息组合封装成一个输入事件input_event然后通过接口__pass_event 将事件添加给client,最后如果有必要还需要唤醒阻塞在这个client上的进程。来看事件添加处理:

static void __pass_event(struct evdev_client *client,
const struct input_event *event)
{
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 (event->type == EV_SYN && event->code == SYN_REPORT) {
client->packet_head = client->head;
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
}

就是数据拷贝和链表的操作流程。现在整个输入事假的输入过程越来越清晰明显了。现在就差一个最初的“引爆点”就是谁调用的handler的接口呢,继续往下找这个过程可以借助内核的一个输入设备驱动来辅助进行分析这里拿gpio_key的这个GPIO键盘驱动作为实例,但是这个驱动他是基于platform总线驱动的框架的,如果不清楚platform驱动框架的工作流程可以先去看我的前面的platform的驱动学习相关的内容。所以这里直接来看这个驱动的probe接口执行过程:

static int gpio_keys_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
struct gpio_keys_drvdata *ddata;
struct input_dev *input;
size_t size;
int i, error;
int wakeup = 0;
if (!pdata) {
pdata = gpio_keys_get_devtree_pdata(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
size = sizeof(struct gpio_keys_drvdata) +
pdata->nbuttons * sizeof(struct gpio_button_data);
ddata = devm_kzalloc(dev, size, GFP_KERNEL);
if (!ddata) {
dev_err(dev, "failed to allocate state\n");
return -ENOMEM;
}
//申请一个输入设备(input_dev),这是输入设备联系前面的设备添加过程
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "failed to allocate input device\n");
return -ENOMEM;
}
//驱动框架相关的内容
ddata->pdata = pdata;
ddata->input = input;
mutex_init(&ddata->disable_lock);
platform_set_drvdata(pdev, ddata);
//这里结合前面的输入设备的数据结构体就明白下面这部分时在初始化设备的一些信息等
input_set_drvdata(input, ddata);
input->name = pdata->name ? : pdev->name;
input->phys = "gpio-keys/input0";
input->dev.parent = &pdev->dev;
//设备的两个重要接口函数,他是属于设备的
input->open = gpio_keys_open;
input->close = gpio_keys_close;
//这里是输入设备的信息字段设置,有时后会用于匹配handler 使用。
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
/* Enable auto repeat feature of Linux input subsystem */
//设置设备支持的输入事件及特性,这一部分需要先熟悉输入设备的支持的事件的描述方法,bitmap,这些信息也是记录在设备中的,具体的面再看
//设置设备是否支持重复上报,这是按键类设备特有的,比如按键按下不松手是否需要一定间隔上报
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
for (i = 0; i < pdata->nbuttons; i++) {
const struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i];
//这是这个驱动封装的接口实际上内部执行的处理过程还混杂这Linux GPIO子系统和工作队列等的相关内容,这里大致分析下执行流程,只关心我们目前关心的内容
/*
每个按键PIN执行:申请IO,根据这个按键的平台数据配置这个IO和申请中断等,然后初始化好一个工作。重点是设置这个input设备的支持的输入事件和对应的值
这里就是EV_KEY 和按键的键值。设置好这么多最后的将每个IO的的数据绑定到每个IO的对应中断服务接口上。然后就是中断服务接口
*/
error = gpio_keys_setup_key(pdev, input, bdata, button);
if (error)
return error;
if (button->wakeup)
wakeup = 1;
}
error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
if (error) {
dev_err(dev, "Unable to export keys/switches, error: %d\n",
error);
return error;
}
error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device, error: %d\n",
error);
goto err_remove_group;
}
device_init_wakeup(&pdev->dev, wakeup);
return 0;
err_remove_group:
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
return error;
}

建议是直接到内核源码中找到这一段学习,因为他同时综合了平台设备驱动的相关内容,这里暂时就不提了,直接挑重点的内容注释。其中重要的中断服务接口,这部分又使用了Linux内核的工作队列机制工作队列是在上面的设置过程中设置的,当按键按下时就会执行下面的中断接口函数这个函数操作也很简单直接调度工作队列由工作队列处理具体的事务,这是一个共享中断传入不同的按键对象作为区分。

static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
{
struct gpio_button_data *bdata = dev_id;
BUG_ON(irq != bdata->irq);
//唤醒电源相关的,暂时不看
if (bdata->button->wakeup)
pm_stay_awake(bdata->input->dev.parent);
//按键驱动的逻辑相关
if (bdata->timer_debounce)
mod_timer(&bdata->timer,
jiffies + msecs_to_jiffies(bdata->timer_debounce));
else
schedule_work(&bdata->work);//调度工作队列(中断低半部机制)
return IRQ_HANDLED;
}

最后重点来看一下,前面绑定的工作队列处理接口。

static void gpio_keys_gpio_work_func(struct work_struct *work)
{
struct gpio_button_data *bdata =
container_of(work, struct gpio_button_data, work);
//得到当前按键的参数信息
gpio_keys_gpio_report_event(bdata);
//电源管理相关的
if (bdata->button->wakeup)
pm_relax(bdata->input->dev.parent);
}

gpio_keys_gpio_report_event分析如下:

static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
{
const struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY;
//读取IO的状态(会睡眠因为在工作队列中)
int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
//根据按键的类型进行不同的处理
if (type == EV_ABS) {
if (state)
input_event(input, type, button->code, button->value);
} else {
input_event(input, type, button->code, !!state);
}
input_sync(input);
}

这里就是input子系统的相关内容了,从按键参数中获取当前按键的绑定的input_dev,根据按键类型的不同进行事件的上报,下面就是input子系统的API接口函数了。

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);
//真正的上报接口 这里的code和value 分别为前面设置能力和获取的IO状态
input_handle_event(dev, type, code, value);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}

继续看下一个接口 input_handle_event

static void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition;
disposition = input_get_disposition(dev, type, code, &value);
//检查是否通过设备自己的接口上报事件
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
//猜测是上面接口执行的返回值,检查是否执行成功,成功则返回不需要继续上报流程
if (!dev->vals)
return;
//通过handle 上报
if (disposition & INPUT_PASS_TO_HANDLERS) {
struct input_value *v;
if (disposition & INPUT_SLOT) {
v = &dev->vals[dev->num_vals++];
v->type = EV_ABS;
v->code = ABS_MT_SLOT;
v->value = dev->mt->slot;
}
//打包事件的值
v = &dev->vals[dev->num_vals++];
v->type = type;
v->code = code;
v->value = value;
}
//检查是否需要立刻上报事件
if (disposition & INPUT_FLUSH) {
if (dev->num_vals >= 2)
//上报事件
input_pass_values(dev, dev->vals, dev->num_vals);
dev->num_vals = 0;
} else if (dev->num_vals >= dev->max_vals - 2) {
dev->vals[dev->num_vals++] = input_value_sync;
input_pass_values(dev, dev->vals, dev->num_vals);
dev->num_vals = 0;
}
}

继续深入 input_pass_values

static void input_pass_values(struct input_dev *dev,
struct input_value *vals, unsigned int count)
{
//看到这个指针顿时很开心,因为前面的猜测要证实了
struct input_handle *handle;
struct input_value *v;
if (!count)
return;
rcu_read_lock();
//不止一种从input设备找到他关联的handle的方式,下面是一种
handle = rcu_dereference(dev->grab);
//上面方式未找到handle
if (handle) {
//进行事件过滤,这是handler的接口定义的,并执行handler的event接口进行事件的上报
count = input_to_handler(handle, vals, count);
} else {
//从设备的handle list上挨个找到handler
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
if (handle->open)
count = input_to_handler(handle, vals, count);
}
rcu_read_unlock();
//
add_input_randomness(vals->type, vals->code, vals->value);
//重复上报的的处理过程
/* trigger auto repeat for key events */
for (v = vals; v != vals + count; v++) {
if (v->type == EV_KEY && v->value != 2) {
if (v->value)
input_start_autorepeat(dev, v->code);
else
input_stop_autorepeat(dev);
}
}
}

看其中的上报接口input_to_handler的具体处理过程

static unsigned int input_to_handler(struct input_handle *handle,
struct input_value *vals, unsigned int count)
{
struct input_handler *handler = handle->handler;
struct input_value *end = vals;
struct input_value *v;
for (v = vals; v != vals + count; v++) {
//时间过滤
if (handler->filter &&
handler->filter(handle, v->type, v->code, v->value))
continue;
if (end != v)
*end = *v;
end++;
}
count = end - vals;
if (!count)
return 0;
//找到事件处理接口的上报接口,分为一次多个或单个事件上报
if (handler->events)
handler->events(handle, vals, count);
else if (handler->event)
for (v = vals; v != end; v++)
handler->event(handle, v->type, v->code, v->value);
return count;
}

分析到这里对于Linux系统的基本工作过程有了大致的了解,这个过程充分说明了Linux的驱动很少是使用一点点的架构的知识就能了解全部的,往往一个驱动是对各方面的内容的综合运用,这里暂时分析到这里,后面还要对整个input系统进行更加宏观的架构层次进行总结分析学习。不过还有一个疑问就是这个input设备是在什么时候加入的,回头去详细找找看,其实就是在probe 接口的后面部分,创建完文件系统的内容后就调用了input子系统的接口函数input_register_device 完成了input设备的添加注册,这个接口前面分析过了其中就会涉及到handler的匹配和绑定操作。到此一个input子系统的微观线条已经出来了,后面又总结了有一个简单的系统框架性的
学习了Linux的input子系统相关的架构知识,但是前面的学习比较实际缺少总结,所以今天就来总结一下输入子系统的架构分层,站到远处来看输入子系统。总得来说输入子系统由设备驱动层(input_dev的注册),输入子系统核心层(input core),事件处理层(handler),和用户空间四部分。这一部分类别platform驱动框架的内容来学习。
设备驱动层(类似于platform_device)
就是前面描述的gpio_keys.c 中的probe接口中的处理过程主要负责不同硬件的底层相关的中断,IO等具体硬件相关的配置和对应接口的开发,并负责将不同硬件设备的数据转换为统一的事件,
通过子系统提供的API接口向输入核心汇报。
输入核心参(类似platform_bus)
承上启下的作用上到用户空间的lient,同时提供设备注册和事件层注册并负责设备和事件层的匹配,同时负责通知事件层处理事件,并在、proc等目录下产生相应的信息文件接口。
事件层(platform_drivers)
负责对设备上报的事件进行处理,中间还引入了input_client的概念,input设备的时间层负责上对接用户空间下对接输入核心层,一个输入设备每次被打开依次设备驱动驱动层就会创建一个client,
事件处理层就负责将设备上报的事件放到每个client然后由用户读写。
中间链接件
输入子系统的几个部分其中的input_dev(输入设备)和input_handler(事件处理层),当他们俩任何一个新注册进子系统时由子系统核心进行匹配,如果匹配成功将创建一个handle用来绑定dev和handler
这里要注意区分handler和handle 这两个太像了。
总体用一个图片来表示就是:

参考:Linux输入子系统详解
再来看一点输入子系统core的相关内容----事件和事件map等相关的宏的含义及设置方法。
事件省略了一些内容:

struct input_dev {
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
。
。
。
};

具体是怎么描述的设备的的可以从如下接口“可见一斑”:

void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{
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);
if (!dev->absinfo)
return;
__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("input_set_capability: unknown type %u (code %u)\n",
type, code);
dump_stack();
return;
}
__set_bit(type, dev->evbit);
}

可以从输入设备的结构体定义内容看到,输入系统共支持的输入类型有事件设备,按键设备,相对坐标,,,,声音控制,,开关等类型事件。也可以从头文件中的定义看到

#define EV_SYN 0x00 //同步事件 #define EV_KEY 0x01 //按键事件 #define EV_REL 0x02 //相对坐标 #define EV_ABS 0x03 //绝对坐标 #define EV_MSC 0x04 //杂项事件 #define EV_SW 0x05 //开关类型事件 #define EV_LED 0x11 //led展示事件(如键盘状态灯) #define EV_SND 0x12 //声音事件 #define EV_REP 0x14 //重复事件 #define EV_FF 0x15 //力反馈事件 #define EV_PWR 0x16 //电源事件 好像从接口看暂时不支持 #define EV_FF_STATUS 0x17 #define EV_MAX 0x1f #define EV_CNT (EV_MAX+1) /*所以通过上面的接口我盟知道设备支持的时间类型是由evbit位图来标记的,对于具体设备的code则有具体的设备类型的位图来记录。比如前面的gpio_key调用传入的事件类型是按键,而code就是具体按键的键值这个有设备平台信息携带。接下来看一下常见类型的code首先是容易理解的按键当然code就是键值如下不完全列出也不详细解释具体含义。*/ #define KEY_ESC 1 #define KEY_1 2 #define KEY_2 3 #define KEY_3 4 #define KEY_4 5 #define KEY_5 6 。 。 。 //相对坐标 #define REL_X 0x00 //这个代表x轴位移 #define REL_Y 0x01 //这个代表y轴位移 #define REL_Z 0x02 //代表z轴位移 #define REL_RX 0x03 //也是一种轴吧 #define REL_RY 0x04 #define REL_RZ 0x05 #define REL_HWHEEL 0x06 #define REL_DIAL 0x07 #define REL_WHEEL 0x08 #define REL_MISC 0x09 //绝对坐标,具体含义基本可以通过名字看出来也不完全列出来 #define ABS_X 0x00 #define ABS_Y 0x01 #define ABS_Z 0x02 #define ABS_RX 0x03 #define ABS_RY 0x04 #define ABS_RZ 0x05 #define ABS_THROTTLE 0x06 #define ABS_RUDDER 0x07 #define ABS_WHEEL 0x08 #define ABS_GAS 0x09 #define ABS_BRAKE 0x0a #define ABS_HAT0X 0x10 //其余的还有开关类的,杂项类,LED的等,同时设备的总线输入子系统也定义了就如下几种类型 #define BUS_PCI 0x01 #define BUS_ISAPNP 0x02 #define BUS_USB 0x03 #define BUS_HIL 0x04 #define BUS_BLUETOOTH 0x05 #define BUS_VIRTUAL 0x06 #define BUS_ISA 0x10 #define BUS_I8042 0x11 #define BUS_XTKBD 0x12 #define BUS_RS232 0x13 #define BUS_GAMEPORT 0x14 #define BUS_PARPORT 0x15 #define BUS_AMIGA 0x16 #define BUS_ADB 0x17 #define BUS_I2C 0x18 #define BUS_HOST 0x19 #define BUS_GSC 0x1A #define BUS_ATARI 0x1B #define BUS_SPI 0x1C

最后再来看一下输入子系统上报的事件的封装结构体,这结构体定义在\include\uapi\linux\input.h 说明用户也是可以使用上面这些内容和定义的如事件
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
其中type和code就是前面提及的时间类型和code最后的value就是事件的具体值,到这里输入子系统的相关内容就算基本结束了,很多细节没有去仔细的看还是我自己的习惯