我对linux理解之input 二
来源:互联网 发布:国产复合弓 知乎 编辑:程序博客网 时间:2024/06/07 21:46
我们看下input从打开,到读写的过程:
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
static int __init input_init(void)
{
......
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);//所有input共同的一个操作,所有对主设备号为INPUT_MAJOR设备操作,都将转换为这个fops
......
}
所有对主设备号为INPUT_MAJOR设备操作,都将转换为input_fops,比如对/dev/input/event*的操作。那假如用户空间程序打开一个input节点,那么将会调用input_open_file:
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler;
const struct file_operations *old_fops, *new_fops = NULL;
int err;
lock_kernel();
/* No load-on-demand here? */
handler = input_table[iminor(inode) >> 5];
if (!handler || !(new_fops = fops_get(handler->fops))) {
err = -ENODEV;
goto out;
}
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
if (!new_fops->open) {
fops_put(new_fops);
err = -ENODEV;
goto out;
}
old_fops = file->f_op;//此时的file的ops是该函数所属的ops,即input_fops
file->f_op = new_fops;//偷梁换柱!把file的ops换成了handler的ops,那后面对file的读写等操作就都变成了handler的操作
err = new_fops->open(inode, file);//handler的open
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);//如果发生错误,不能忘了换回来,否则就永远打不开了
}
fops_put(old_fops);
out:
unlock_kernel();
return err;
}
这里有个地方设计的很绝妙,它竟然来了一招偷梁换柱,把file的ops给换掉了,换成handler的ops了,这就意味着后面的file操作直接对应到handler的ops。为什么这么设计呢?
可能是为了架构之间的清晰,互不影响吧。你想假如把evdev的操作直接放到input_ops里面,那像joydev、mousedev怎么办呢?所以索性就分开。那下面我们就看下handler的ops:
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,
};
我们看到handler的ops对应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
};
那对应的open就是evdev_open:
static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;
int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
return error;
evdev = evdev_table;//根据minor相对位置找到evdev,在evdev_install_chrdev中有定义
if (evdev)
get_device(&evdev->dev);
mutex_unlock(&evdev_table_mutex);
if (!evdev)
return -ENODEV;
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);//注意这里的client,虽然刚出现,但却很重要
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
spin_lock_init(&client->buffer_lock);
#ifdef CONFIG_WAKELOCK
snprintf(client->name, sizeof(client->name), "%s-%d", dev_name(&evdev->dev),
task_tgid_vnr(current));
wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
#endif
client->evdev = evdev;
evdev_attach_client(evdev, client);//其实就是将client添加到evdev中的lient_list里
error = evdev_open_device(evdev);
if (error)
goto err_free_client;
file->private_data = client;//赋值给file的私有数据
return 0;
err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
err_put_evdev:
put_device(&evdev->dev);
return error;
}
这里最重要的是client的出现。它是input系统的数据的中转站,好像也不是很贴切。
我们下面看下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;
int retval;
if (count < input_event_size())//不能小于一个input event事件的大小
return -EINVAL;
if (client->head == client->tail && evdev->exist &&//确保有效性
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(evdev->wait,
client->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)) {//一个一个事件地去拷贝到user空间
if (input_event_to_user(buffer + retval, &event))//拷贝函数
return -EFAULT;
retval += input_event_size();
}
return retval;
}
我们看下evdev_fetch_next_event(client, &event):
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->head != client->tail;//它是将后面判断的结果赋值给have_event
if (have_event) {
*event = client->buffer[client->tail++];//event指向client的buffer,从tail开始,这里的buffer数据怎么来的呢?
client->tail &= EVDEV_BUFFER_SIZE - 1;
#ifdef CONFIG_WAKELOCK
if (client->head == client->tail)
wake_unlock(&client->wake_lock);
#endif
}
spin_unlock_irq(&client->buffer_lock);
return have_event;
}
我们看到用户空间的的数据是client的buffer,那这个buffer是怎么来的呢?input上报数据使用input_report_abs等类似的函数。下面以input_report_abs为例分析数据上报流程:
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}
转到input_event:
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)) {//检查该dev是否支持该event的类型
spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);//添加到随机数熵池
input_handle_event(dev, type, code, value);//处理event
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 = INPUT_IGNORE_EVENT;
switch (type) {
case EV_SYN:
switch (code) {
case SYN_CONFIG:
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT:
if (!dev->sync) {
dev->sync = 1;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case SYN_MT_REPORT:
dev->sync = 0;
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
break;
case EV_KEY:
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
!!test_bit(code, dev->key) != value) {
if (value != 2) {
__change_bit(code, dev->key);
if (value)
input_start_autorepeat(dev, code);
else
input_stop_autorepeat(dev);
}
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) {
__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX)) {
if (test_bit(code, input_abs_bypass)) {
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
value = input_defuzz_abs_event(value,
dev->abs[code], dev->absfuzz[code]);
if (dev->abs[code] != value) {
dev->abs[code] = value;
disposition = INPUT_PASS_TO_HANDLERS;
}
}
break;
case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;
break;
case EV_MSC:
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;
break;
case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) {
__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_REP:
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
dev->rep[code] = value;
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_FF:
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;
case EV_PWR:
disposition = INPUT_PASS_TO_ALL;
break;
}
//上面根据type决定disposition的值,下面根据disposition的值去做不同的处理
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)//不是同步事件就不设置同步标记
dev->sync = 0;
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)//将事件传送给设备去处理
dev->event(dev, type, code, value);
if (disposition & INPUT_PASS_TO_HANDLERS)//将事件传送给上层handler处理
input_pass_event(dev, type, code, value);//一般都将转换成改函数处理
}
我们看下input_pass_event:
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
if (handle)
handle->handler->event(handle, type, code, value);//引用handler的event函数,如果是evdev,则对应evdev_event
else
list_for_each_entry_rcu(handle, &dev->h_list, d_node)//通过dev中的h_list查找handle
if (handle->open)
handle->handler->event(handle,
type, code, value);
rcu_read_unlock();
}
该函数将转换成handle->handler->event去处理,我们在handler注册的时候知道event对应evdev_event:
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;
#ifdef CONFIG_WAKELOCK//默认是定义的
struct timespec ts;
ktime_get_ts(&ts);
event.time.tv_sec = ts.tv_sec;
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
#else
do_gettimeofday(&event.time);
#endif
event.type = type;
event.code = code;
event.value = value;//我们看到event中包含了time,type,code,value
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)//如果有多个client
evdev_pass_event(client, &event);//传送event
rcu_read_unlock();
wake_up_interruptible(&evdev->wait);
}
我们看到到这里已经将数据集合到event结构中了,然后通过evdev_pass_event去传送:
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/*
* Interrupts are disabled, just acquire the lock
*/
spin_lock(&client->buffer_lock);
#ifdef CONFIG_WAKELOCK
wake_lock_timeout(&client->wake_lock, 5 * HZ);//保证5s之类不能睡眠,否则可能导致数据fill错误
#endif
client->buffer[client->head++] = *event;//添加到client的buffer里面
client->head &= EVDEV_BUFFER_SIZE - 1;////保证存储的事件不能超过规定的大小,超过以后将又从0开始,覆盖原来的event
spin_unlock(&client->buffer_lock);
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
看到了吧,最终是将event放到了client的buffer里面了,这就是上面evdev_read要读的数据那个client->buffer。是不是有点很爽的感觉呢?:)
下面我们再看下write吧:
static ssize_t evdev_write(struct file *file, const 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;
retval = mutex_lock_interruptible(&evdev->mutex);
if (retval)
return retval;
if (!evdev->exist) {
retval = -ENODEV;
goto out;
}
while (retval < count) {
if (input_event_from_user(buffer + retval, &event)) {//从用户空间拷贝到event结构中
retval = -EFAULT;
goto out;
}
input_inject_event(&evdev->handle,//执行注入event函数
event.type, event.code, event.value);
retval += input_event_size();
}
out:
mutex_unlock(&evdev->mutex);
return retval;
}
拷贝完了后就执行注入事件函数:
void input_inject_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct input_dev *dev = handle->dev;
struct input_handle *grab;
unsigned long flags;
if (is_event_supported(type, dev->evbit, EV_MAX)) {//判断是否支持这个type
spin_lock_irqsave(&dev->event_lock, flags);
rcu_read_lock();
grab = rcu_dereference(dev->grab);
if (!grab || grab == handle)
input_handle_event(dev, type, code, value);//处理event事件,在数据上报过程中已经分析过了
rcu_read_unlock();
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
static int __init input_init(void)
{
......
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);//所有input共同的一个操作,所有对主设备号为INPUT_MAJOR设备操作,都将转换为这个fops
......
}
所有对主设备号为INPUT_MAJOR设备操作,都将转换为input_fops,比如对/dev/input/event*的操作。那假如用户空间程序打开一个input节点,那么将会调用input_open_file:
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler;
const struct file_operations *old_fops, *new_fops = NULL;
int err;
lock_kernel();
/* No load-on-demand here? */
handler = input_table[iminor(inode) >> 5];
if (!handler || !(new_fops = fops_get(handler->fops))) {
err = -ENODEV;
goto out;
}
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
* not "no device". Oh, well...
*/
if (!new_fops->open) {
fops_put(new_fops);
err = -ENODEV;
goto out;
}
old_fops = file->f_op;//此时的file的ops是该函数所属的ops,即input_fops
file->f_op = new_fops;//偷梁换柱!把file的ops换成了handler的ops,那后面对file的读写等操作就都变成了handler的操作
err = new_fops->open(inode, file);//handler的open
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);//如果发生错误,不能忘了换回来,否则就永远打不开了
}
fops_put(old_fops);
out:
unlock_kernel();
return err;
}
这里有个地方设计的很绝妙,它竟然来了一招偷梁换柱,把file的ops给换掉了,换成handler的ops了,这就意味着后面的file操作直接对应到handler的ops。为什么这么设计呢?
可能是为了架构之间的清晰,互不影响吧。你想假如把evdev的操作直接放到input_ops里面,那像joydev、mousedev怎么办呢?所以索性就分开。那下面我们就看下handler的ops:
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,
};
我们看到handler的ops对应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
};
那对应的open就是evdev_open:
static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;
int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
return error;
evdev = evdev_table;//根据minor相对位置找到evdev,在evdev_install_chrdev中有定义
if (evdev)
get_device(&evdev->dev);
mutex_unlock(&evdev_table_mutex);
if (!evdev)
return -ENODEV;
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);//注意这里的client,虽然刚出现,但却很重要
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
spin_lock_init(&client->buffer_lock);
#ifdef CONFIG_WAKELOCK
snprintf(client->name, sizeof(client->name), "%s-%d", dev_name(&evdev->dev),
task_tgid_vnr(current));
wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
#endif
client->evdev = evdev;
evdev_attach_client(evdev, client);//其实就是将client添加到evdev中的lient_list里
error = evdev_open_device(evdev);
if (error)
goto err_free_client;
file->private_data = client;//赋值给file的私有数据
return 0;
err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
err_put_evdev:
put_device(&evdev->dev);
return error;
}
这里最重要的是client的出现。它是input系统的数据的中转站,好像也不是很贴切。
我们下面看下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;
int retval;
if (count < input_event_size())//不能小于一个input event事件的大小
return -EINVAL;
if (client->head == client->tail && evdev->exist &&//确保有效性
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(evdev->wait,
client->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)) {//一个一个事件地去拷贝到user空间
if (input_event_to_user(buffer + retval, &event))//拷贝函数
return -EFAULT;
retval += input_event_size();
}
return retval;
}
我们看下evdev_fetch_next_event(client, &event):
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->head != client->tail;//它是将后面判断的结果赋值给have_event
if (have_event) {
*event = client->buffer[client->tail++];//event指向client的buffer,从tail开始,这里的buffer数据怎么来的呢?
client->tail &= EVDEV_BUFFER_SIZE - 1;
#ifdef CONFIG_WAKELOCK
if (client->head == client->tail)
wake_unlock(&client->wake_lock);
#endif
}
spin_unlock_irq(&client->buffer_lock);
return have_event;
}
我们看到用户空间的的数据是client的buffer,那这个buffer是怎么来的呢?input上报数据使用input_report_abs等类似的函数。下面以input_report_abs为例分析数据上报流程:
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}
转到input_event:
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)) {//检查该dev是否支持该event的类型
spin_lock_irqsave(&dev->event_lock, flags);
add_input_randomness(type, code, value);//添加到随机数熵池
input_handle_event(dev, type, code, value);//处理event
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 = INPUT_IGNORE_EVENT;
switch (type) {
case EV_SYN:
switch (code) {
case SYN_CONFIG:
disposition = INPUT_PASS_TO_ALL;
break;
case SYN_REPORT:
if (!dev->sync) {
dev->sync = 1;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case SYN_MT_REPORT:
dev->sync = 0;
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
break;
case EV_KEY:
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
!!test_bit(code, dev->key) != value) {
if (value != 2) {
__change_bit(code, dev->key);
if (value)
input_start_autorepeat(dev, code);
else
input_stop_autorepeat(dev);
}
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
!!test_bit(code, dev->sw) != value) {
__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case EV_ABS:
if (is_event_supported(code, dev->absbit, ABS_MAX)) {
if (test_bit(code, input_abs_bypass)) {
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
value = input_defuzz_abs_event(value,
dev->abs[code], dev->absfuzz[code]);
if (dev->abs[code] != value) {
dev->abs[code] = value;
disposition = INPUT_PASS_TO_HANDLERS;
}
}
break;
case EV_REL:
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
disposition = INPUT_PASS_TO_HANDLERS;
break;
case EV_MSC:
if (is_event_supported(code, dev->mscbit, MSC_MAX))
disposition = INPUT_PASS_TO_ALL;
break;
case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
!!test_bit(code, dev->led) != value) {
__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_SND:
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd) != !!value)
__change_bit(code, dev->snd);
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_REP:
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
dev->rep[code] = value;
disposition = INPUT_PASS_TO_ALL;
}
break;
case EV_FF:
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;
case EV_PWR:
disposition = INPUT_PASS_TO_ALL;
break;
}
//上面根据type决定disposition的值,下面根据disposition的值去做不同的处理
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)//不是同步事件就不设置同步标记
dev->sync = 0;
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)//将事件传送给设备去处理
dev->event(dev, type, code, value);
if (disposition & INPUT_PASS_TO_HANDLERS)//将事件传送给上层handler处理
input_pass_event(dev, type, code, value);//一般都将转换成改函数处理
}
我们看下input_pass_event:
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
if (handle)
handle->handler->event(handle, type, code, value);//引用handler的event函数,如果是evdev,则对应evdev_event
else
list_for_each_entry_rcu(handle, &dev->h_list, d_node)//通过dev中的h_list查找handle
if (handle->open)
handle->handler->event(handle,
type, code, value);
rcu_read_unlock();
}
该函数将转换成handle->handler->event去处理,我们在handler注册的时候知道event对应evdev_event:
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;
#ifdef CONFIG_WAKELOCK//默认是定义的
struct timespec ts;
ktime_get_ts(&ts);
event.time.tv_sec = ts.tv_sec;
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
#else
do_gettimeofday(&event.time);
#endif
event.type = type;
event.code = code;
event.value = value;//我们看到event中包含了time,type,code,value
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)//如果有多个client
evdev_pass_event(client, &event);//传送event
rcu_read_unlock();
wake_up_interruptible(&evdev->wait);
}
我们看到到这里已经将数据集合到event结构中了,然后通过evdev_pass_event去传送:
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/*
* Interrupts are disabled, just acquire the lock
*/
spin_lock(&client->buffer_lock);
#ifdef CONFIG_WAKELOCK
wake_lock_timeout(&client->wake_lock, 5 * HZ);//保证5s之类不能睡眠,否则可能导致数据fill错误
#endif
client->buffer[client->head++] = *event;//添加到client的buffer里面
client->head &= EVDEV_BUFFER_SIZE - 1;////保证存储的事件不能超过规定的大小,超过以后将又从0开始,覆盖原来的event
spin_unlock(&client->buffer_lock);
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
看到了吧,最终是将event放到了client的buffer里面了,这就是上面evdev_read要读的数据那个client->buffer。是不是有点很爽的感觉呢?:)
下面我们再看下write吧:
static ssize_t evdev_write(struct file *file, const 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;
retval = mutex_lock_interruptible(&evdev->mutex);
if (retval)
return retval;
if (!evdev->exist) {
retval = -ENODEV;
goto out;
}
while (retval < count) {
if (input_event_from_user(buffer + retval, &event)) {//从用户空间拷贝到event结构中
retval = -EFAULT;
goto out;
}
input_inject_event(&evdev->handle,//执行注入event函数
event.type, event.code, event.value);
retval += input_event_size();
}
out:
mutex_unlock(&evdev->mutex);
return retval;
}
拷贝完了后就执行注入事件函数:
void input_inject_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct input_dev *dev = handle->dev;
struct input_handle *grab;
unsigned long flags;
if (is_event_supported(type, dev->evbit, EV_MAX)) {//判断是否支持这个type
spin_lock_irqsave(&dev->event_lock, flags);
rcu_read_lock();
grab = rcu_dereference(dev->grab);
if (!grab || grab == handle)
input_handle_event(dev, type, code, value);//处理event事件,在数据上报过程中已经分析过了
rcu_read_unlock();
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
最终回到了之前分析过的input_handle_event。
http://www.qrsdev.com/forum.php?mod=viewthread&tid=404&extra=page%3D1
- 我对linux理解之input 二
- 我对linux理解之input 二
- 我对linux理解之input一
- 我对linux理解之input一
- 我对linux理解之alsa二
- 我对linux理解之tty二
- 我对linux理解之i2c 二
- 我对linux理解之alsa二
- 我对linux理解之i2c 二
- 我对linux理解之i2c 二
- 我对linux理解之tty二
- 我对linux理解之i2c 二
- 我对linux理解之alsa二
- 我对linux理解之alsa一
- 我对linux理解之spi
- 我对linux理解之driver_register
- 我对linux的理解之device_register
- 我对linux理解之tty一
- java基础 -- Preferences操作注册表
- POJ 1743 (后缀数组)
- poj1141 动态规划
- JAVA中SERIALVERSIONUID的解释
- vi/vim多行注释和取消注释
- 我对linux理解之input 二
- 提示:找不到 org/springframework/dao/support/PersistenceExceptionTranslator
- C#操作Access之创建mdb库浅析
- 【TCP通信】多客户端连接一个服务器端总结
- C#中怎么判断字符串为空的几种方法
- 我对linux理解之v4l2
- C#操作Access之按列读取mdb浅析
- 使用XMLReader、XMLDocument和DataSet读取xml文件及效率
- java中的“堆“和'栈”