linux驱动开发:input子系统三

linux输入设备的总结:
上一篇文章中,用户空间可以open 我们的event1设备文件,也可以read我们的设备文件。可是我们的代码里面并没有实现read 和 open函数。但是依旧可以抓到数据。这也就是说内核帮我们做好了很多input设备公共的操作函数。我们只要按照特定的框架去开发就可以了。

具体的一些相关的代码和structure有贴出来,以防止以后忘记。在这里做个备份.

1) evdev  handler
static struct input_handler evdev_handler = {
    .event      = evdev_event,
    .events     = evdev_events,
    .connect    = evdev_connect,
    .disconnect = evdev_disconnect,
    .legacy_minors  = true,
    .minor      = EVDEV_MINOR_BASE,
    .name       = "evdev",
    .id_table   = evdev_ids,
};

2) 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,
    .llseek     = no_llseek,
};

3)read the event* ,how we get the data stand for?

int input_event_to_user(char __user *buffer,
            const struct input_event *event)
{
    if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
        struct input_event_compat compat_event;

        compat_event.time.tv_sec = event->time.tv_sec;
        compat_event.time.tv_usec = event->time.tv_usec;
        compat_event.type = event->type;
        compat_event.code = event->code;
        compat_event.value = event->value;

        if (copy_to_user(buffer, &compat_event,
                 sizeof(struct input_event_compat)))
            return -EFAULT;

    } else {
        if (copy_to_user(buffer, event, sizeof(struct input_event)))
            return -EFAULT;
    }

    return 0;
}

4)  user space: read 

static const struct file_operations input_devices_fileops = {
    .owner      = THIS_MODULE,
    .open       = input_proc_devices_open,
    .poll       = input_proc_devices_poll,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = seq_release,
};

static const struct seq_operations input_devices_seq_ops = {
    .start  = input_devices_seq_start,
    .next   = input_devices_seq_next,
    .stop   = input_seq_stop,
    .show   = input_devices_seq_show,
};

static int input_proc_devices_open(struct inode *inode, struct file *file)
{
    return seq_open(file, &input_devices_seq_ops);
}

struct seq_file {
    char *buf;
    size_t size;
    size_t from;
    size_t count;
    loff_t index;
    loff_t read_pos;
    u64 version;
    struct mutex lock;
    const struct seq_operations *op;
    int poll_event;
#ifdef CONFIG_USER_NS
    struct user_namespace *user_ns;
#endif
    void *private;
};

int seq_open(struct file *file, const struct seq_operations *op)
{
    struct seq_file *p = file->private_data;

    if (!p) {
        p = kmalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
            return -ENOMEM;
        file->private_data = p;
    }
    memset(p, 0, sizeof(*p));
    mutex_init(&p->lock);
    p->op = op;
#ifdef CONFIG_USER_NS
    p->user_ns = file->f_cred->user_ns;
#endif

    /*
     * Wrappers around seq_open(e.g. swaps_open) need to be
     * aware of this. If they set f_version themselves, they
     * should call seq_open first and then set f_version.
     */
    file->f_version = 0;

    /*
     * seq_files support lseek() and pread().  They do not implement
     * write() at all, but we clear FMODE_PWRITE here for historical
     * reasons.
     *
     * If a client of seq_files a) implements file.write() and b) wishes to
     * support pwrite() then that client will need to implement its own
     * file.open() which calls seq_open() and then sets FMODE_PWRITE.
     */
    file->f_mode &= ~FMODE_PWRITE;
    return 0;
}

    input.c ---> input_fops.open()    //input_proc_devices_open

    ---->seq_open()    //open函数主要就是调用seq_open()函数将一个struct seq_operations结构和struct file链接起来

    ----> evdev.open

    read_write.c:

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    struct fd f = fdget(fd);
    ssize_t ret = -EBADF;

    if (f.file) {
        loff_t pos = file_pos_read(f.file);
        ret = vfs_read(f.file, buf, count, &pos);
        file_pos_write(f.file, pos);
        fdput(f);
    }
    return ret;
}

ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
    ssize_t ret;

    if (!(file->f_mode & FMODE_READ))
        return -EBADF;
    if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
        return -EINVAL;
    if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
        return -EFAULT;

    ret = rw_verify_area(READ, file, pos, count);
    if (ret >= 0) {
        count = ret;
        if (file->f_op->read)
            ret = file->f_op->read(file, buf, count, pos);
        else
            ret = do_sync_read(file, buf, count, pos);
        if (ret > 0) {
            fsnotify_access(file);
            add_rchar(current, ret);
        }
        inc_syscr(current);
    }

    return ret;
}


    read()---> sys_read() // system call

    ----->vfs_read()

    ----->file->f_op->read 

    ----->evdev.read


5)  input_register_device()


        ---->list_add_tail(&dev->node, &input_dev_list);
            |
            |
        ---->list_for_each_entry(handler, &input_handler_list, node)
            |
            |
        ---->input_attach_handler(dev, handler); // each match input_dev_list with input_handler_list

        ---->handler->connect(handler, dev, id) //connect

        ----> //set up the minor device num, set up the device node file 






100) fun remark

    register_chrdev(unsigned int major,const char * name,const struct file_operations * fops);
    register_chrdev_region(dev_t,unsigned,const char *);

这里写图片描述
整个input的框架大致如上图。
1.input dev通过 input_register_device 向 input core 模块注册设备,注册成功则在对应的 input_dev_list上添加一个设备节点
2.event handler通过 input_register_handler向input core模块注册 handlers,注册成功则在对应的input_handler_list上添加一个节点.
3.注册的设备通过 input_match_device 来遍历 input_handler_list上的节点,如果match到,则调用对应的handler的connect函数
4.connect函数会获得次设备号,创建设备节点文件.
5.用户空间进行系统调用时的 open,read操作,实际上操作的是 input dev match到的evdev的fops.open 和 fops.read.
整个逻辑大致这样。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章