我对linux理解之input一

来源:互联网 发布:国产复合弓 知乎 编辑:程序博客网 时间:2024/05/22 14:23
我们先看下input的注册过程:
input_register_device(input_dev):
int input_register_device(struct input_dev *dev)
{
    static atomic_t input_no = ATOMIC_INIT(0);
    struct input_handler *handler;
    const char *path;
    int error;

    __set_bit(EV_SYN, dev->evbit);//支持同步事件

    /*
     * If delay and period are pre-set by the driver, then autorepeating
     * is handled by the driver itself and we don't do it in input.c.
     */

    init_timer(&dev->timer);//为重复按键做准备
    if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
        dev->timer.data = (long) dev;
        dev->timer.function = input_repeat_key;
        dev->rep[REP_DELAY] = 250;
        dev->rep[REP_PERIOD] = 33;
    }

    if (!dev->getkeycode)//如果没设置,则设置成默认的
        dev->getkeycode = input_default_getkeycode;

    if (!dev->setkeycode)
        dev->setkeycode = input_default_setkeycode;

    dev_set_name(&dev->dev, "input%ld",
                 (unsigned long) atomic_inc_return(&input_no) - 1);//按顺序地去定义input序号

    error = device_add(&dev->dev);//将input dev添加到sys系统中,包括创建一些input的属性文件
    if (error)
        return error;

    path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);//这里路径是上面device_add产生的
    printk(KERN_INFO "input: %s as %s\n",
        dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
    kfree(path);

    error = mutex_lock_interruptible(&input_mutex);
    if (error) {
        device_del(&dev->dev);
        return error;
    }

    list_add_tail(&dev->node, &input_dev_list);//添加到input设备列表里面

    list_for_each_entry(handler, &input_handler_list, node)//对input handler列表中的每个handler都进行匹配,这里input_handler_list怎么来的呢?我们在 input_register_handler找到它的形成过程
        input_attach_handler(dev, handler);//匹配dev和handler

    input_wakeup_procfs_readers();

    mutex_unlock(&input_mutex);

    return 0;
}
我们看下input_attach_handler(dev, handler):
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
    const struct input_device_id *id;
    int error;

    if (handler->blacklist && input_match_device(handler->blacklist, dev))//如果在黑名单里面就返回
        return -ENODEV;

    id = input_match_device(handler->id_table, dev);//匹配handler->id_table和dev
    if (!id)
        return -ENODEV;

    error = handler->connect(handler, dev, id);//调用handler的connect连接handler、 dev,这个函数很重要,起到了承上启下的作用。
    if (error && error != -ENODEV)
        printk(KERN_ERR
            "input: failed to attach handler %s to device %s, "
            "error: %d\n",
            handler->name, kobject_name(&dev->dev.kobj), error);

    return error;
}
input_match_device(handler->id_table, dev):
static const struct input_device_id *input_match_device(const struct input_device_id *id,
                            struct input_dev *dev)
{
    int i;

    for (; id->flags || id->driver_info; id++) {//对handler中的每个id都进行查询

        if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
            if (id->bustype != dev->id.bustype)
                continue;

        if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
            if (id->vendor != dev->id.vendor)
                continue;

        if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
            if (id->product != dev->id.product)
                continue;

        if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
            if (id->version != dev->id.version)
                continue;

        MATCH_BIT(evbit,  EV_MAX);
        MATCH_BIT(keybit, KEY_MAX);
        MATCH_BIT(relbit, REL_MAX);
        MATCH_BIT(absbit, ABS_MAX);
        MATCH_BIT(mscbit, MSC_MAX);
        MATCH_BIT(ledbit, LED_MAX);
        MATCH_BIT(sndbit, SND_MAX);
        MATCH_BIT(ffbit,  FF_MAX);
        MATCH_BIT(swbit,  SW_MAX);

        return id;
    }

    return NULL;
}
该函数会对handler中的每个id都进行查询,先根据id->flags设置去比较,然后比较具体的位,MATCH_BIT定义如下:
#define MATCH_BIT(bit, max) \
        for (i = 0; i < BITS_TO_LONGS(max); i++) \
            if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
                break; \
        if (i != BITS_TO_LONGS(max)) \
            continue;
可以看出来是id->bit[i]与dev->bit[i]比较。
从整体上看,匹配的过程还算比较简单。分析中有几个新的地方input_handler_list和handler->connect。
其实这些都是input子系统最顶层做的工作,最顶层可以有evdev,joydev,mousedev等,当然用户完全可以构建一个自己的dev。我们就挑选evdev做分析吧,也是最常用的一种。
static const struct input_device_id evdev_ids[] = {//还记得上面匹配函数里面用到的id吗?就是它哦
    { .driver_info = 1 },    /* Matches all devices */
    { },            /* Terminating zero entry */
};

MODULE_DEVICE_TABLE(input, evdev_ids);

static struct input_handler evdev_handler = {
    .event        = evdev_event,
    .connect    = evdev_connect,//看到了吧,匹配函数中的handler->connect
    .disconnect    = evdev_disconnect,
    .fops        = &evdev_fops,
    .minor        = EVDEV_MINOR_BASE,
    .name        = "evdev",
    .id_table    = evdev_ids,
};

static int __init evdev_init(void)
{
    return input_register_handler(&evdev_handler);
}
evdev初始化是注册了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;//放到input_table
    }

    list_add_tail(&handler->node, &input_handler_list);//添加到handler列表中,这样就形成了input_handler_list

    list_for_each_entry(dev, &input_dev_list, node)
        input_attach_handler(dev, handler);//这边也进行匹配了,所以无论是handler还是dev注册都会调用匹配函数

    input_wakeup_procfs_readers();

out:
    mutex_unlock(&input_mutex);
    return retval;
}

我们下面分析一下evdev_connect:
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++)//找到一个空的minor
        if (!evdev_table[minor])
            break;

    if (minor == EVDEV_MINORS) {
        printk(KERN_ERR "evdev: no more free evdev devices\n");
        return -ENFILE;
    }

    evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
    if (!evdev)
        return -ENOMEM;

    INIT_LIST_HEAD(&evdev->client_list);
    spin_lock_init(&evdev->client_lock);
    mutex_init(&evdev->mutex);
    init_waitqueue_head(&evdev->wait);

    dev_set_name(&evdev->dev, "event%d", minor);//evdev的名字,即event*
    evdev->exist = 1;
    evdev->minor = minor;

    evdev->handle.dev = input_get_device(dev);//将dev赋值给handle
    evdev->handle.name = dev_name(&evdev->dev);
    evdev->handle.handler = handler;//将handler赋值给handle
    evdev->handle.private = evdev;
    //可以看出handle将dev和handler联系到一块了
    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);

    error = input_register_handle(&evdev->handle);//注册handle,其实就是将handle再跟dev和handler分别联系起来,这样三者就真正地互相联系到一块了
    if (error)
        goto err_free_evdev;

    error = evdev_install_chrdev(evdev);//把evdev添加到evdev_table中
    if (error)
        goto err_unregister_handle;

    error = device_add(&evdev->dev);//将evdev添加到/sys/中
    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;
}
我们先解释input_register_handle(&evdev->handle):
int input_register_handle(struct input_handle *handle)
{
    struct input_handler *handler = handle->handler;
    struct input_dev *dev = handle->dev;
    int error;

    /*
     * We take dev->mutex here to prevent race with
     * input_release_device().
     */
    error = mutex_lock_interruptible(&dev->mutex);
    if (error)
        return error;
    list_add_tail_rcu(&handle->d_node, &dev->h_list);//将handle添加到dev的h_list
    mutex_unlock(&dev->mutex);

    /*
     * Since we are supposed to be called from ->connect()
     * which is mutually exclusive with ->disconnect()
     * we can't be racing with input_unregister_handle()
     * and so separate lock is not needed here.
     */
    list_add_tail(&handle->h_node, &handler->h_list);//将handle添加到handler的h_list

    if (handler->start)
        handler->start(handle);

    return 0;
}
将handle分别添加到dev和handler的h_list中,这样三者真正地联系起来了,可以互相访问。
我们可以看到evdev才是真正用户可以操作的设备,evdev中的handle把handler和dev联系到了一块,同时将evdev添加到了sys中。