我对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);
    }
}

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


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

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 学校移动4g网卡怎么办 没上专科线怎么办福建 联考没过本科线怎么办 拍婚纱拍的脸歪怎么办? 老婆彻底寒心要离婚怎么办 手机被同学偷了怎么办 钱被同学偷了怎么办 上班穿皮鞋脚疼怎么办 高跟靴子买大了怎么办 我怀了第三个小孩怎么办? 离婚前把钱花了怎么办 对谈对象有压力怎么办 和对象感情淡了怎么办 孩子处对象学习下降怎么办 孩子高三成绩差怎么办 老妈怨气太重怎么办 广东小高考有d怎么办 高考考生档案袋有个小洞怎么办 江苏省考生出省后小高考成绩怎么办 江苏小高考三D怎么办 小高考补考没过怎么办 理科高考200多分怎么办 高考没考过200分怎么办 电子手表指针不走了怎么办 家长说你教的不好怎么办 小升初分班考试考砸了怎么办 老公不给老婆看病怎么办 孕妈妈涨奶严重怎么办 90岁老头尿不下尿怎么办 妻子要离婚丈夫不离怎么办 弟媳妇天天在家吵架怎么办 弟媳妇不和我说话怎么办 我想和弟媳妇做一次怎么办 老公对弟媳妇有非分之想怎么办 跟弟媳妇有矛盾怎么办 学生考试前不认真怎么办 有人雇凶要杀我怎么办 高考理综数学英语都没考好怎么办 母亲判刑孩子未成年无人监管怎么办 高三了数学30分怎么办 母猪发烧耳朵放血止不住了怎么办?