输入子系统(二)

来源:互联网 发布:虚拟社交网络弊大于利 编辑:程序博客网 时间:2024/06/06 11:36

一、输入子系统初始化过程:
kernel/drivers/input/input.c
1.1、input_init( )初始化

static int __init input_init(void){    int err;    err = class_register(&input_class);    if (err) {        pr_err("unable to register input_dev class\n");        return err;    }    /* 注册input_class类,所有input_device均为此类    struct class input_class = {    .name       = "input",    .devnode    = input_devnode,    }; */    /* 在/proc下建立相关交互文件 */    err = input_proc_init();    if (err)        goto fail1;    /* 注册主设备号为INPUT_MAJOR,此设备好为0~255的字符设备     * 操作指针为input_fops。     */    err = register_chrdev(INPUT_MAJOR, "input", &input_fops);    if (err) {        pr_err("unable to register char major %d", INPUT_MAJOR);        goto fail2;    }    return 0; fail2: input_proc_exit(); fail1: class_unregister(&input_class);    return err;}

1.2、input_open_file( )文件打开函数

static const struct file_operations input_fops = {    .owner = THIS_MODULE,    .open = input_open_file,    .llseek = noop_llseek,};/* 此处将控制转到input_handler中定义的fops文件指针的open()函数, * 该函数在input_handler中实现, 因此不同的handler处理器对应不同的文件打开方法. */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;    err = mutex_lock_interruptible(&input_mutex);    if (err)        return err;    /* 将设备节点的次设备号右移5位作为索引值到input_table中去对应项,     * 一个handler代表32(1<<5)个设备节点, 即一个handler最多可以处理32个设备节点.     * 因为在input_table中的取值是以次设备号右移5位为索引的, 即第5位相同的次设备号对应的是同一个索引.     */    handler = input_table[iminor(inode) >> 5];    if (handler)        new_fops = fops_get(handler->fops);    mutex_unlock(&input_mutex);    /* 在input_handler中找到对应的handler后,就会检验该handler否存在,     * 判断new_fops->open函数是否定义, 如未定义则表示设备不存在.     * 在存在的情况下, 从handler->fops中获得新的文件操作指针file_operation,     * 并增加引用. 此后, 对设备的操作都通过新的文件操作指针new_fops来完成.     */    if (!new_fops || !new_fops->open) {        fops_put(new_fops);        err = -ENODEV;        goto out;    }    old_fops = file->f_op;    file->f_op = new_fops;    /* 使用新的open函数,重新打开设备 */    err = new_fops->open(inode, file);    if (err) {        fops_put(file->f_op);        file->f_op = fops_get(old_fops);    }    fops_put(old_fops);out:    return err;}

1.3、input_register_handler( )

int input_register_handler(struct input_handler *handler){    struct input_dev *dev;    int retval;    retval = mutex_lock_interruptible(&input_mutex);    if (retval)        return retval;    INIT_LIST_HEAD(&handler->h_list);    if (handler->fops != NULL) {        if (input_table[handler->minor >> 5]) {            retval = -EBUSY;            goto out;        }        input_table[handler->minor >> 5] = handler; /* 将handler赋给input_table数组(右移5位作为索引) */    }    list_add_tail(&handler->node, &input_handler_list);    list_for_each_entry(dev, &input_dev_list, node)        input_attach_handler(dev, handler);    input_wakeup_procfs_readers(); out:    mutex_unlock(&input_mutex);    return retval;}

二、evdev输入事件:

kernel/drivers/input/evdev.c

2.1、evdev_init( )初始化函数

/* evdev_ids中没有定义id->flags, 也没有配置属性值, * 表明所有input_dev发出的事件均可以由evdev_handler来处理. * 并且此处匹配成功后回调用handler->connect()即evdev_connect()函数. */static const struct input_device_id evdev_ids[] = {    { .driver_info = 1 },   /* Matches all devices */    { },                    /* Terminating zero entry */};static struct input_handler evdev_handler = {    .event      = evdev_event,    .connect    = evdev_connect,    .disconnect = evdev_disconnect,    .fops       = &evdev_fops,    .minor      = EVDEV_MINOR_BASE,     /* evdev_handler的设备文件索引范围为(13, 64)~(13, 64+32) */    .name       = "evdev",    .id_table   = evdev_ids,            /* 此处只定义了id_table */};static int __init evdev_init(void){    return input_register_handler(&evdev_handler);  /* handler注册 */}/* 在input_attach_handler( )的input_match_device( )函数中 * input_dev与handler匹配的关键在于, handler中的blacklist和id_table. * */

2.2、evdev_connect( )

/* * evdev_connect()函数用于连接input_dev和input_handler,这样事件的流通链才算建立。 * 流通链建立后,事件才知道被谁处理,或者处理后将向谁返回结果。 */static int evdev_connect(struct input_handler *handler, struct input_dev *dev,             const struct input_device_id *id){    struct evdev *evdev;    int minor;    int error;    for (minor = 0; minor < EVDEV_MINORS; minor++)        if (!evdev_table[minor])    /* 找到evdev_table为空的那一项 */            break;    if (minor == EVDEV_MINORS) {        pr_err("no more free evdev devices\n");        return -ENFILE;    }    evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);    if (!evdev)        return -ENOMEM;    /* 对分配的evdev结构进行初始化,包括链表、互斥锁和等待队列 */    INIT_LIST_HEAD(&evdev->client_list);    spin_lock_init(&evdev->client_lock);    mutex_init(&evdev->mutex);    init_waitqueue_head(&evdev->wait);    /* 对evdev设备进行命名,在/dev/input目录下显示 */    dev_set_name(&evdev->dev, "event%d", minor);    evdev->exist = true;    evdev->minor = minor;    evdev->handle.dev = input_get_device(dev);    evdev->handle.name = dev_name(&evdev->dev);    evdev->handle.handler = handler;    evdev->handle.private = evdev;    evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);    evdev->dev.class = &input_class;    evdev->dev.parent = &dev->dev;    evdev->dev.release = evdev_free;    device_initialize(&evdev->dev);    /* 注册handler结构体 */    error = input_register_handle(&evdev->handle);    if (error)        goto err_free_evdev;    /* 注册成功,则调用evdev_install_chrdev将evdev_table的minor项指向evdev */    error = evdev_install_chrdev(evdev);    if (error)        goto err_unregister_handle;    /* 将evdev->device注册到sysfs文件系统中 */    error = device_add(&evdev->dev);    if (error)        goto err_cleanup_evdev;    return 0; err_cleanup_evdev:    evdev_cleanup(evdev); err_unregister_handle:    input_unregister_handle(&evdev->handle); err_free_evdev:    put_device(&evdev->dev);    return error;}

2.3、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,};

2.3.1、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;   /* 得到在evdev_table[]中序列号 */    unsigned int bufsize;    int error;    if (i >= EVDEV_MINORS)        return -ENODEV;    error = mutex_lock_interruptible(&evdev_table_mutex);    if (error)        return error;    evdev = evdev_table[i];    if (evdev)                      /* 调用get_device()增加引用计数 */        get_device(&evdev->dev);    mutex_unlock(&evdev_table_mutex);    if (!evdev)        return -ENODEV;    bufsize = evdev_compute_buffer_size(evdev->handle.dev);    client = kzalloc(sizeof(struct evdev_client) +                bufsize * sizeof(struct input_event),             GFP_KERNEL);    if (!client) {        error = -ENOMEM;        goto err_put_evdev;    }    client->bufsize = bufsize;    spin_lock_init(&client->buffer_lock);    snprintf(client->name, sizeof(client->name), "%s-%d",            dev_name(&evdev->dev), task_tgid_vnr(current));    client->evdev = evdev;    evdev_attach_client(evdev, client);/* 将client挂到evdev->client_list上 */    error = evdev_open_device(evdev);    if (error)        goto err_free_client;    file->private_data = client;    nonseekable_open(inode, file);    return 0; err_free_client:    evdev_detach_client(evdev, client);    kfree(client); err_put_evdev:    put_device(&evdev->dev);    return error;}

2.3.2、evdev_open_device( )

/* 打开相应的输入设备,使设备准备好接收或者发送数据。 * 线获取互斥锁,然后检查设备是否存在,并判断设备是否已经被打开。 */static int evdev_open_device(struct evdev *evdev){    int retval;    retval = mutex_lock_interruptible(&evdev->mutex);    if (retval)        return retval;    if (!evdev->exist)        retval = -ENODEV;    else if (!evdev->open++) {  /* 第一次打开evdev */        retval = input_open_device(&evdev->handle);        if (retval)            evdev->open--;    }    mutex_unlock(&evdev->mutex);    return retval;}

2.3.3、input_open_device( )

/* 递增handler的打开计数, 如果是第一次打开, 则调用input_dev的open()函数 */int input_open_device(struct input_handle *handle){    struct input_dev *dev = handle->dev;    int retval;    retval = mutex_lock_interruptible(&dev->mutex);    if (retval)        return retval;    if (dev->going_away) {        retval = -ENODEV;        goto out;    }    handle->open++;    if (!dev->users++ && dev->open)        retval = dev->open(dev);    if (retval) {        dev->users--;        if (!--handle->open) {            /*             * Make sure we are not delivering any more events             * through this handle             */            synchronize_rcu();        }    } out:    mutex_unlock(&dev->mutex);    return retval;}
0 0
原创粉丝点击