(文章写得比较早,当时自己也是一知半解,描述的不好,后来我参考了网上的大量资料,重新写了一篇:嵌入式Linux驱动笔记(二十五)------Input子系统框架)
基于设备驱动分层的思想,其实理解了platform总线,输入子系统也是可以很好理解的。
以kernel 4.8.17为例:
input.c文件:
static char *input_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
}
struct class input_class = {
.name = "input",
.devnode = input_devnode,
};
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;
}
初始化的工作主要做了:
创建一个input_class类.
在/proc下创建入口项.即/proc/bus/input目录产生设备信息.
注册字符设备input,主设备号为13(#define INPUT_MAJOR13)
至于input_class结构体下的input_devnode,我也不知道干什么的......
值得注意的是注册input设备的时候都是在这个input下,即/dev/input/event0等等......
好吧,input注册后,基于设备驱动分层的思想,总要有设备文件和驱动文件吧,下面可以看下evdev.c文件,(为什么看这个文件?其实我想看gpio_key.c这个文件的,但是这个驱动文件里的probe涉及到设备树,目前还不会搞,脑阔疼......)
evdev.c:
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,
};
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
向输入子系统注册驱动handler,注意哦,这里是handler,译为:处理者,
之后还会看到一个词:handle,译为:手柄,这两个不要搞混了。
接下来进入input_register_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;
}
初始化h_list链表.
14、15行,重头戏,遍历链表,寻找handler匹配的设备.
跟踪进入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;
}
这里面有一个匹配函数,就像platform总线一样,会把设备和驱动两两匹配起来。
如果匹配成功,这会执行connect函数进行连接(就好比probe函数一样).
设备和驱动是怎么匹配的:
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;
}
很遗憾,这个match函数我也看不懂他们是怎么具体匹配的..........伤心啊 。
不过据我了解,evdev.c的handler可以适应任何的dev设备,即分配一个input_dev结构体,即使什么都不做,也能和evdev.c的handler匹配成功。而且这个match的时候,即使匹配成功了也没用break跳出,所以会出现一个dev对应多个handler的情况......
当它们匹配成功后,就会调用connect函数.这个connect函数是什么呢,就是之前input_register_handler传入的结构体里的成员,函数如下:
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;
/*比较长,省略了一部分代码*/
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);
/*比较长,省略了一部分代码*/
return 0;
}
注意第10行,注册input的时候,就是这样会在/dev/input下生成event0、1、2...n.
还有注意handle(不是handler哦) ,之前说过,这里会把dev、name、handler、private通过evdev->handle记录下来,并注册handle(23行,即把dev和handler添加到h_list链表中),这样通过handle就可以找到dev与handler,实现设备和驱动的连接了。
最后,通过device_add就实现设备的注册了("关于正真设备文件的创建(不是指sys下的文件), 最终是由device_add函数里头的kobject_uevent(&dev->kobj, KOBJ_ADD)完成的对hotplug_helper的调用的。
如果想了解uevent的详情,可以阅读 《Linux设备模型浅析之uevent篇》或者他的一系列文章。
")
上面讲的是驱动部分,接下来就是设备部分,原理是一样的:
就在input.c文件里的input_register_device函数,方法是一模一样的,
调用:
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
所以说,不管事设备先注册还是驱动先注册,他们都会去寻找、等待自己的另一半(好好的码着代码,突然就虐狗了............)
驱动和设备建立好连接后,怎么用呢?
当然是通过event上报event(事件)到Handler层进行处理,然后提交给用户了。
input_event->input_handle_event->input_pass_values->input_to_handler->handler->events(handle, vals, count);
所以看下evdev.c文件里的evdev_event函数:
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct input_value vals[] = { { type, code, value } };
evdev_events(handle, vals, 1);
}
它会调用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 ev_time[EV_CLK_MAX];
ev_time[EV_CLK_MONO] = ktime_get();
ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]);
ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO],
TK_OFFS_BOOT);
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_values(client, vals, count, ev_time);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_values(client, vals, count, ev_time);
rcu_read_unlock();
}
可以看出,刚开始对读操作上锁,防止被干扰,之后进行填充数据,完成之后再解锁。
填充数据由evdev_pass_values函数完成。
evdev_pass_values函数:
static void evdev_pass_values(struct evdev_client *client,
const struct input_value *vals, unsigned int count,
ktime_t *ev_time)
{
struct evdev *evdev = client->evdev;
const struct input_value *v;
struct input_event event;
bool wakeup = false;
if (client->revoked)
return;
event.time = ktime_to_timeval(ev_time[client->clk_type]);
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
for (v = vals; v != vals + count; v++) {
if (__evdev_is_filtered(client, v->type, v->code))
continue;
if (v->type == EV_SYN && v->code == SYN_REPORT) {
/* drop empty SYN_REPORT */
if (client->packet_head == client->head)
continue;
wakeup = true;
}
event.type = v->type;
event.code = v->code;
event.value = v->value;
__pass_event(client, &event);
}
spin_unlock(&client->buffer_lock);
if (wakeup)
wake_up_interruptible(&evdev->wait);
}
值得注意的是,当事件的类型为EV_SYN、事件代码为SYN_REPORT,并且client->packet_head != client->head(buffer采用的是环形方式存储,即当设备的信息包的头!=设备的头?不知道怎么理解)时,会唤醒 指定的注册在等待队列上的进程.
即通过input_sync函数产生:
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
当然,这个不是我们现在关心的,先码住,心理默念:会唤醒某个东西,会唤醒某个东西,会唤醒某个东西,,,,,,,我们比较关心__pass_event函数,就是在这个函数里填充消息。
__pass_event函数:
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);
}
}
就这样,将消息填充到了buffer中......
那用户应用程序又怎么操作的?
还记得之前说的evdev_connect函数吗?
里面有一句:cdev_init(&evdev->cdev, &evdev_fops);
chardevice的初始化,evdev_fops如下:
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,
};
终于又回到了我们最熟悉的字符设备的file_operations啊,真是 这里的山路十八弯~不容易啊......
进入read函数看一看,evdev_read:
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)) {
if (input_event_to_user(buffer + read, &event))
return -EFAULT;
read += input_event_size();
}
if (read)
break;
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;
}
有点长,但是为了最后的胜利,忍了..........
分析下这个函数:
第10行:如果读取的消息不为0且长度小于消息buffer里的长度
第17行:又见环形缓存存储,当信息包的头等于设备的尾时?不知道,估计想描述buffer是否为空时吧,当消息为空并且文件是非阻塞方式打开时,立即返回.......
第31行:最重要的一行了,input_event_to_user这个函数里面会调用copy_to_user函数,把buffer里的数据传输到应用空间,这样,即实现了应用程序的数据读取。
第40行:如果文件不是以非阻塞方式打开,则会执行wait_event_interruptible休眠等待。嘿嘿,还记得之前默念的东西吗,就是这里!!!!别慌,好好睡觉,当input_sync函数调用时,我就来叫你起床,嘿嘿嘿......
好了,写到这里好像写了挺多的了,累了,,,剩下的write、open之类的懒得分析了,套路都是一样的,剩下的自己练练手咯,祝你们成功!