本文共 2763 字,大约阅读时间需要 9 分钟。
应用程序如何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,如何处理的??敬请期待
转载地址:http://vbtqb.baihongyu.com/