应用程序如何read?
Input子系统分析之一讲过应用程序去open,那么如何read呢?
搜遍input.c 也没有提供read的函数,有一个可惜不是;那read在哪里定义的呢?想到可能在evdev.c里定义的,先看下他的初始化模块
仍以evdev.c (drivers/input/evdev.c)为基础进行说明:
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
上文说过input_register_handler 就是在这里调用的,下面来看一下传入的参数evdev_handler,定义如下
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
看到这里面有一个fops操作集合,默认用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,
...
.fasync = evdev_fasync,
...
};
看看在这个函数里面如何read的??
if (client->head == client->tail && evdev->exist &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;// wake up wait queue
retval = wait_event_interruptible(evdev->wait,
client->head != client->tail || !evdev->exist);
if (retval)
return retval;
整个就是有数据可读,就是按键按下,直接执行下面的,否则休眠
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();
}
这里面有点疑问retval+input_event_size() 没理解??而且retval是wait_event_interruptible返回的,奥明白了
只有retal=0才会跳到这里,如果休眠的话肯定返回了,那就是有数据可读,其实这个就转换为input_event_size()<=count
似乎有点多此一举,其实不是的,下面有的,利用它读剩余事件。
先看下input_event_size(),这个函数是得到sizeof(struct input_event),而input_event是什么呢?
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
就是它!没错,平时发送的事件就是它,就是用它来传送的
evdev_fetch_next_event(client, &event)是用来取出里面的event事件的,这个函数里面会指定处理的最大事件数量为64
#define EVDEV_BUFFER_SIZE 64
*event = client->buffer[client->tail++];
client->tail &= EVDEV_BUFFER_SIZE - 1;
接着就调用input_event_to_user(buffer + retval, &event)函数,发送到用户空间
这里面调用的方式不一样,处理也不一样,这个函数最终会调用copy_to_user(buffer, event, sizeof(struct input_event)),不再陈述
上面牵涉到一个问题在哪里唤醒刚才休眠的队列?
在本文家搜素这个wait队列,有两处提供唤醒,一处是evdev_hangup函数,另一处是evdev_event,而后面一处正是我们需要的
这个evdev_event如何被调用?
一般大家能猜到的就是中断服务程序,下面进入一般都是驱动提供的服务程序里,使用input_event函数,这个函数里面会调用下面的函数
input_handle_event(dev, type, code, value);
进入此函数,看一下这个函数怎么实现的?这个肯定是讲键盘有关的事件进行上传,在后面会进行陈述
自此全部完结,肯定还没有搞懂怎么回事??其实这样的,
你先讲模块放入内核编译,或者insmod此input模块后,就已经将input_dev注册进去了,而且注册了中断之类的
而handler之类的大部分框架底层已帮我们实现好了,接下来看下应用程序
int buttons_fd;
int key_value, i=0, count;struct input_event ev_key;
buttons_fd = open("/dev/event0", O_RDWR);while(1)
{
count = read(buttons_fd, &ev_key, sizeof(struct input_event));
for(i=0; i<(int)count/sizeof(struct input_event); i++)
{
//对每一个事件的处理
}}
close(buttons_fd);
1. 应用程序打开input设备,并在read处阻塞(前面有调用具体的函数),然后就等待中断的触发,
2. 当按下按钮时就触发了中断,中断里面调用input_event去上传按键事件,最终调用input_pass_event,如何处理的??敬请期待