Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15531266
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: 嵌入式

2009-07-30 11:41:42

浅析usb鼠标input_register_device注册input_dev设备全过程

hid_probe
==>  usb_hid_configure
==*> hid->hidinput_input_event = usb_hidinput_input_event;
==*> hid->hid_open = usbhid_open;
==*> hid->hid_close = usbhid_close;

==>  hidinput_connect
==*> input_dev = input_allocate_device();
==*> input_dev->event = hid->hidinput_input_event;      // usb_hidinput_input_event
==*> input_dev->open = hidinput_open;
==*> input_dev->close = hidinput_close;
==*> input_dev->setkeycode = hidinput_setkeycode;
==*> input_dev->getkeycode = hidinput_getkeycode;
==*> hidinput->input = input_dev;
==*> list_add_tail(&hidinput->list, &hid->inputs);      // 添加到hid->inputs链表上,以便hid_irq_in收到hid硬件设备数据后遍历分发数据[luther.gliethttp]
==*> input_register_device(hidinput->input)
int input_register_device(struct input_dev *dev)
{
    list_add_tail(&dev->node, &input_dev_list);         // 添加到input_dev_list输入设备链表上,以便input_register_handler注册新handler时遍历.
    list_for_each_entry(handler, &input_handler_list, node) // 遍历驱动链表,尝试给我们的hid设备变身成的普通input设备匹配一个驱动
        input_attach_handler(dev, handler);             // attach一个驱动给我们变身为普通input设备的hid设备[luther.gliethttp]
}

drivers/input/evdev.c|995| return input_register_handler(&evdev_handler);
drivers/input/mousedev.c|1072| error = input_register_handler(&mousedev_handler);
drivers/char/keyboard.c|1416| error = input_register_handler(&kbd_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);    // mousedev_handler
    if (!id)
        return -ENODEV;

    error = handler->connect(handler, dev, id);         // mousedev_connect为该dev建立一个连接到mousedev_handler的handle
    if (error && error != -ENODEV)                      // 每个input_dev可以对应n多个handle,他们都挂接在input_dev的h_list链表上
        printk(KERN_ERR                                 // 每个handle唯一对应一个handler,用来处理由input_dev设备发送过来的数据[luther.gliethttp]
            "input: failed to attach handler %s to device %s, "
            "error: %d\n",
            handler->name, kobject_name(&dev->dev.kobj), error);

    return error;
}

static int mousedev_connect(struct input_handler *handler,
                struct input_dev *dev,
                const struct input_device_id *id)
{
    struct mousedev *mousedev;
    int minor;
    int error;

    for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
        if (!mousedev_table[minor])                     // 从mousedev_handler驱动管理的最多32个设备槽中申请一个空槽[luther.gliethttp]
            break;

    if (minor == MOUSEDEV_MINORS) {                     // 没有空槽了
        printk(KERN_ERR "mousedev: no more free mousedev devices\n");
        return -ENFILE;
    }

    mousedev = mousedev_create(dev, handler, minor);    // 创建包装了dev的mousedev设备,同时uevent出去,创建/dev/input/mousex节点
    if (IS_ERR(mousedev))
        return PTR_ERR(mousedev);

    error = mixdev_add_device(mousedev);                // 见后将mousedev添加到mousedev_mix_list管理链表
    if (error) {
        mousedev_destroy(mousedev);
        return error;
    }

    return 0;
}

static struct mousedev *mousedev_create(struct input_dev *dev,
                    struct input_handler *handler,
                    int minor)
{
    mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
    if (minor == MOUSEDEV_MIX)
        strlcpy(mousedev->name, "mice", sizeof(mousedev->name)); // minor等于MOUSEDEV_MIX那么创建/dev/input/mice节点
    else
        snprintf(mousedev->name, sizeof(mousedev->name),
             "mouse%d", minor);                     // 创建/dev/input/mousex节点,节点函数操作集fops为
                                                    // input_init==>register_chrdev(INPUT_MAJOR, "input", &input_fops);
                                                    // 创建的input_fops,当应用程序调用open时,执行input_open_file
                                                    // input_open_file
                                                    // ==> struct input_handler *handler = input_table[iminor(inode) >> 5];
                                                    // 每32个minor对应一个handler,
                                                    // ==> new_fops = fops_get(handler->fops))
                                                    // ==> file->f_op = new_fops;即mousedev_fops
                                                    // ==> new_fops->open(inode, file);即mousedev_open
                                                    // mousedev_init
                                                    // ==> #define MOUSEDEV_MINOR_BASE    32
                                                    // ==> static struct input_handler mousedev_handler = {
                                                    //      .event =    mousedev_event,
                                                    //      .connect =    mousedev_connect,
                                                    //      .disconnect =    mousedev_disconnect,
                                                    //      .fops =        &mousedev_fops,
                                                    //      .minor =    MOUSEDEV_MINOR_BASE,
                                                    //      .name =        "mousedev",
                                                    //      .id_table =    mousedev_ids,
                                                    //  };
                                                    // ==> input_register_handler(&mousedev_handler);
                                                    // ==*> input_table[handler->minor >> 5] = handler;即mousedev_handler

    mousedev->handle.dev = input_get_device(dev);
    mousedev->handle.name = mousedev->name;
    mousedev->handle.handler = handler;             // mousedev_handler
    mousedev->handle.private = mousedev;
    strlcpy(mousedev->dev.bus_id, mousedev->name,
        sizeof(mousedev->dev.bus_id));
    mousedev->dev.class = &input_class;
    mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor); // 创建节点号
    mousedev->dev.release = mousedev_free;
    device_initialize(&mousedev->dev);
    if (minor != MOUSEDEV_MIX) {
        error = input_register_handle(&mousedev->handle); // 见下,将handle添加的input_dev的h_list链表上,以便硬件设备数据到达之后遍历handle,
        if (error)                                        // 将硬件传上来的数据分发给每个handle对应的handler分别处理.[luther.gliethttp]
            goto err_free_mousedev;
    }

    error = mousedev_install_chrdev(mousedev);      // 记录登记到32个设备表中mousedev_table[mousedev->minor] = mousedev;
    if (error)                                      // 这个mousedev由mousedev_handler驱动使用唯一对应硬件设备,设备节点为/dev/input/mouse_[minor-32]
        goto err_unregister_handle;

    error = device_add(&mousedev->dev);             // uevent然后作为daemon的应用程序生成/dev/input/mousex节点,函数操作集为input_fops
}

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注册登记到input_dev设备的h_list链表上,这样当dev设备产生数据之后,
    mutex_unlock(&dev->mutex);                      // 才能通过遍历h_list链表,一一向handle发送产生的物理数据[luther.gliethttp]
    synchronize_rcu();                              // 比如
                                                    // input_event
                                                    // ==>input_handle_event
                                                    // ==>input_pass_event
                                                    // ==>list_for_each_entry_rcu(handle, &dev->h_list, d_node)
                                                    //      if (handle->open) 如果应用程序打开了/dev/input/mice或mousex节点,那么
                                                    //            handle->handler->event(handle,type, code, value);
                                                    // mousedev_event
    /*
     * 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添加到mousedev_handler的h_list链表上,在input_unregister_handler
                                                    // 函数中将遍历handler->h_list上的所有handle,然后一一断开它们[luther.gliethttp]
                                                    // input_unregister_handler
                                                    // list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
                                                    //    handler->disconnect(handle);
    if (handler->start)
        handler->start(handle);                     // mousedev_handler没有start函数

    return 0;
}

static int mixdev_add_device(struct mousedev *mousedev)
{
    int retval;

    retval = mutex_lock_interruptible(&mousedev_mix->mutex);
    if (retval)
        return retval;

    if (mousedev_mix->open) {                                   // 如果/dev/input/mice节点已经有应用程序打开了
        retval = mousedev_open_device(mousedev);                // 那么尝试打开mousedev,增加mousedev->open++引用[luther.gliethttp]
        if (retval)                                             // 如果mousedev->open等于0,那么说明没有应用程序打开/dev/input/mousex节点
            goto out;                                           // 所以将直接执行input_open_device(&mousedev->handle);操作.

        mousedev->mixdev_open = 1;                              // 标识mousedev_mix驱动也在引用该mousedev设备,
                                                                // 当然该mousedev设备也可能已经由其他应用程序调用/dev/input/mousex打开
    }

    get_device(&mousedev->dev);
    list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);  // 添加到mousedev_mix_list管理链表

 out:
    mutex_unlock(&mousedev_mix->mutex);
    return retval;
}

static int mousedev_open_device(struct mousedev *mousedev)
{
    int retval;

    retval = mutex_lock_interruptible(&mousedev->mutex);
    if (retval)
        return retval;

    if (mousedev->minor == MOUSEDEV_MIX)
        mixdev_open_devices();                      // 打开mousedev_mix_list链表上的所有mousedev设备[luther.gliethttp]
    else if (!mousedev->exist)
        retval = -ENODEV;
    else if (!mousedev->open++) {                   // mousedev->open还等于0,那么执行下面打开操作[luther.gliethttp]
        retval = input_open_device(&mousedev->handle);
        if (retval)
            mousedev->open--;
    }

    mutex_unlock(&mousedev->mutex);
    return retval;
}

static void mixdev_open_devices(void)
{
    struct mousedev *mousedev;

    if (mousedev_mix->open++)
        return;

    list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
        if (!mousedev->mixdev_open) {
            if (mousedev_open_device(mousedev))
                continue;

            mousedev->mixdev_open = 1;
        }
    }
}

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++;                                 // 引用计数加1.

    if (!dev->users++ && dev->open)                 // dev->users为0,说明我们是第一个引用dev的用户,所以需要执行dev->open函数
        retval = dev->open(dev);                    // hidinput_connect==> input_dev->open = hidinput_open;
                                                    // hidinput_open ==> hid->hid_open(hid);
                                                    // usb_hid_configure
                                                    // hid->hid_open = usbhid_open;
                                                    // 所以最后调用usbhid_open
                                                    // usb_submit_urb(usbhid->urbin, GFP_ATOMIC); 提交一个in读取urb.[luther.gliethttp]
    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;
}
阅读(3873) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~