input子系统分为了input device drivers和input event drivers,看图
可以看到,在kernel space中,input -core 管理着 input device drivers 以及input event drivers,其中在 input device drivers中,当遇到有按键或者是TP触摸时甚至我们假定的sensor的中断时,调用一个函数即在input-core中的input_event的函数(input.c中定义,但是一般不直接调用,还有一层函数的封装),在input-core中input_event函数中,假如是正确的
事件的话,会通过input-core层之前注册的input event drivers 定义的event函数,将键值或者是坐标值写到已经定义的buffer中,当底层的input device drivers 进行input_sync时,作为一组数据保存,上层函数通过read 函数 ,函数中input_event_to_user将数据拷贝到用户空间。接下来我会一一分析。
最典型的input event drivers 是evdev的事件驱动 的drivers,基本管理着大部分的input device drivers。
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */ //能够匹配到所有的已经注册在input子系统上dev
{ }, /* Terminating zero entry */
};
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
.event = evdev_event, //dev 进行input_event 时实际上调用的函数。
.connect = evdev_connect, //注册匹配成功后,调用connect函数
.disconnect = evdev_disconnect, //注册不成功时,调用disconnect函数
.fops = &evdev_fops, //进行读写等操作
.minor = EVDEV_MINOR_BASE, //次版本号是从64开始
.name = "evdev",
.id_table = evdev_ids, //和dev匹配时用到了id_table
};
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);
接下来讲一下evdev.c中定义的几个比较重要的函数。
static int
evdev_connect
(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
这个函数在input_attach_handler(input.c中定义的),当match函数成功时,即进行connect函数,就是调用的这个connect函数(evdev为例,当然joydev,moucedev也有自己的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 error;
for (minor = 0; minor < EVDEV_MINORS; minor++) //一个handler只能支持32个设备
if (!evdev_table[minor]) //直到检查到evdev_table是否有空闲的,空闲时此时获得了minor
break;
if (minor == EVDEV_MINORS) { //检查是否已经等于了最大的32,等于32就没有空间了
pr_err("no more free evdev devices\n");
return -ENFILE;
}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //申请evdev空间
if (!evdev)
return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list); //初始化client_list链表
spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait); //初始化等待队列
dev_set_name(&evdev->dev, "event%d", minor); //在/dev/input/生成event0,event1...的文件,当然这个是设置name
evdev->exist = true;
evdev->minor = minor;
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, EVDEV_MINOR_BASE + minor); //此版本是evdev的起始次版本64+minor,所以就是64,65..95
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); //注册handle,这个将handler以及dev产生更亲密的关系。
if (error)
goto err_free_evdev;
error = evdev_install_chrdev(evdev); //vdev_table[evdev->minor] = evdev; vdev_table赋值
if (error)
goto err_unregister_handle;
error = device_add(&evdev->dev); //在/dev/input/生成event0,event1等
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);
return error;
}
这里面还有一个函数需要来看一下
int input_register_handle(struct input_handle *handle)
handle是存放一对匹配好的handler以及dev的。这个函数的作用是利于handler访问dev,也有利于dev访问handler的
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); //将handle->d_node添加到dev->h_list中
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); //将handle->d_node添加到handler->h_list中
if (handler->start)
handler->start(handle);
return 0;
}
用一个图很直观的体现一下(注:摘抄的)
还有一个函数是
static void evdev_event(struct input_handle *handle,unsigned int type, unsigned int code, int value)
当底层传入event事件时,都会进入这个函数(异常除外,以evdev为例)
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
ktime_t time_mono, time_real;
time_mono = ktime_get();
time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
event.type = type; //将传入的type等赋值给event
event.code = code;
event.value = value;
rcu_read_lock();
client = rcu_dereference(evdev->grab); //前面的evdev->grab并没有动,所以没有
if (client)
evdev_pass_event(client, &event, time_mono, time_real);
else
list_for_each_entry_rcu(client, &evdev->client_list, node) //evdev->client_list 是在用户空间打开input系统时
evdev_pass_event(client, &event, time_mono, time_real); //将evdev与evdev->client_list发生关系的
rcu_read_unlock();
if (type == EV_SYN && code == SYN_REPORT) //在设备进行input_sync时就会调用这个
wake_up_interruptible(&evdev->wait); //唤醒等待队列
}
看一下
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event,
ktime_t mono, ktime_t real)
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event,
ktime_t mono, ktime_t real)
{
event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
mono : real);
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);
client->buffer[client->head++] = *event; //将event赋值给buffer,这个buffer是给用户来读的
client->head &= client->bufsize - 1;
if (unlikely(client->head == client->tail)) { //不太可能发生的,就是head == 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 (client->use_wake_lock)
wake_unlock(&client->wake_lock);
}
if (event->type == EV_SYN && event->code == SYN_REPORT) { //检测是否是input_sync同步事件
client->packet_head = client->head; //重新认为是新的一组数据
if (client->use_wake_lock)
wake_lock(&client->wake_lock);
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
spin_unlock(&client->buffer_lock);
}
将数据存储到所谓的buffer中后,上层通过read函数读取走已存的数据,具体函数名是
static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
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;
int retval = 0;
if (count < input_event_size())
return -EINVAL;
if (!(file->f_flags & O_NONBLOCK)) {
retval = wait_event_interruptible(evdev->wait,
client->packet_head != client->tail ||
!evdev->exist);
if (retval)
return retval;
}
if (!evdev->exist)
return -ENODEV;
while (retval + input_event_size() <= count &&
evdev_fetch_next_event(client, &event)) {
if (input_event_to_user(buffer + retval, &event))
return -EFAULT;
retval += input_event_size();
}
if (retval == 0 && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
return retval;
}