日期:2014-05-16  浏览次数:20636 次

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