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.
整個邏輯大致這樣。

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