我对linux理解之input 二

我们看下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);
    }
}

最终回到了之前分析过的input_handle_event。


http://www.qrsdev.com/forum.php?mod=viewthread&tid=404&extra=page%3D1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值