Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15531109
  • 博文数量: 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-20 11:16:15

我们来看看hidinput_connect是如何被引用上的,下面是一个引用流程.
hid_init
hid_probe
hidinput_connect
input_register_device
input_attach_handler
mousedev_connect
mousedev_open_device
input_open_device
hidinput_open
usbhid_open

/*
 * Register the input device; print a message.
 * Configure the input layer interface
 * Read all reports and initialize the absolute field values.
 */
int hidinput_connect(struct hid_device *hid)
{
    struct hid_report *report;
    struct hid_input *hidinput = NULL;
    struct input_dev *input_dev;
    int i, j, k;
    int max_report_type = HID_OUTPUT_REPORT;

    if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
        return -1;

    INIT_LIST_HEAD(&hid->inputs);
// unsigned char mouse_report[] = {
//     0x05, 0x01, // USAGE_PAGE (Generic Desktop) //
//     0x09, 0x02, // USAGE (Mouse)
//     0xa1, 0x01, // COLLECTION (Application)     // hid->collection[0].usage = 0x10002 hid->maxcollection = 1;
//     0x09, 0x01, //   USAGE (Pointer)
//     0xa1, 0x00, //   COLLECTION (Physical)      // hid->collection[1].usage = 0x10001 hid->maxcollection = 2;
    for (i = 0; i < hid->maxcollection; i++)
        if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
            hid->collection[i].type == HID_COLLECTION_PHYSICAL)
            if (IS_INPUT_APPLICATION(hid->collection[i].usage)) // 因为具有0x10002而成立[luther.gliethttp]
                break;

    if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDINPUT) == 0)
        return -1;                                              // 没有input类型的collection收集集[luther.gliethttp]

    if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
        max_report_type = HID_INPUT_REPORT;                     // #define HID_INPUT_REPORT        0
                                                                // #define HID_OUTPUT_REPORT    1
                                                                // #define HID_FEATURE_REPORT    2
    for (k = HID_INPUT_REPORT; k <= max_report_type; k++)
        list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
                                                                // k=0时,遍历所有input类型的report,最多255个report,每个report用id区分[luther.gliethttp]
            if (!report->maxfield)                              // 没有对数据域,continue.
                continue;

            if (!hidinput) {
                hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);// 还没有为该hid设备申请input_dev,那么先申请用来包装input_dev的hidinput.
                input_dev = input_allocate_device();
                if (!hidinput || !input_dev) {                  // 均正常才可.
                    kfree(hidinput);
                    input_free_device(input_dev);
                    err_hid("Out of memory during hid input probe");
                    goto out_unwind;
                }

                input_set_drvdata(input_dev, hid);              // 设置input_dev的private为hid物理设备
                input_dev->event = hid->hidinput_input_event;   // 该input_dev因为被hid设备包装,所以使用hid设备的hidinput_input_event方法
                input_dev->open = hidinput_open;                // 该方法在hid_probe==>usb_hid_configure中赋值
                input_dev->close = hidinput_close;              // hid->hidinput_input_event = usb_hidinput_input_event;
                input_dev->setkeycode = hidinput_setkeycode;    // hid->hid_open = usbhid_open;
                input_dev->getkeycode = hidinput_getkeycode;    // 有hid自己键盘数据解析合成函数[luther.gliethttp]

                input_dev->name = hid->name;                    // 复制hid属性到input_dev,这样才能表征出input_dev对应该hid物理设备
                input_dev->phys = hid->phys;
                input_dev->uniq = hid->uniq;
                input_dev->id.bustype = hid->bus;
                input_dev->id.vendor  = hid->vendor;
                input_dev->id.product = hid->product;
                input_dev->id.version = hid->version;
                input_dev->dev.parent = hid->dev;
                hidinput->input = input_dev;                    // hidinput是一个将hid数据转为input格式的协议转换者,转换完毕之后,将数据发送
                                                                // 给hidinput->input 这个真正的连接到mousedev_handler驱动上input_dev设备.
                list_add_tail(&hidinput->list, &hid->inputs);   // 将hidinput添加到hid->inputs链表上,以表示本hidinput需要hid物理设备的数据,
                                                                // 这样当hid设备上传数据,引发irq中断
                                                                // 处理函数执行hid_irq_in==>hid_input_report==>hidinput_report_event
                                                                // list_for_each_entry(hidinput, &hid->inputs, list)
                                                                //   input_sync(hidinput->input); // 将hid物理设备上发的数据分发给
                                                                //   挂接到hid物理设备hid->inputs链表上的所有hidinput->input对象[luther.gliehttp]
                                                                // 最后usb_hidinput_input_event将处理该event数据,主要是3种event,
                                                                // 鼠标左键按下和抬起,鼠标右键按下和抬起,鼠标中键按下和抬起[luther.gliethttp]
                                                                // 代码流程为:
                                                                // hid_irq_in
                                                                // hid_input_report
                                                                // hid_input_field         // 数据域
                                                                // hid_process_event
                                                                // hidinput_hid_event
                                                                // input_event
                                                                // input_handle_event      // dev->event(dev, type, code, value);
                                                                // 在usb_hid_configure ==> hid->hidinput_input_event = usb_hidinput_input_event;
                                                                // hidinput_connect ==> input_dev->event = hid->hidinput_input_event;
                                                                // usb_hidinput_input_event
            }

            for (i = 0; i < report->maxfield; i++)
                for (j = 0; j < report->field[i]->maxusage; j++)// 报告描述符中可能描述了很多个有意义的数据段,每个数据段用field表示,
                    hidinput_configure_usage(hidinput, report->field[i],// 每个filed又由若干个usage来进一步约束数据最大小值,Const,
                                 report->field[i]->usage + j);  // bits如何组合等特有规则来描述该filed数据该如何被翻译解释[luther.gliethttp]
                                                                // 对于hidinput_configure_usage细节分析,需要单开一个话题《浅析usbhid驱动hidinput_configure_usage细则》.[luther.gliethttp]

            if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
                /* This will leave hidinput NULL, so that it
                 * allocates another one if we have more inputs on
                 * the same interface. Some devices (e.g. Happ's
                 * UGCI) cram a lot of unrelated inputs into the
                 * same interface. */
                hidinput->report = report;                      // 比如k=0时,那么每组用report_id标识的report数据都作为一个独立的input设备输入
                if (input_register_device(hidinput->input))     // 所以这里注册该report_id对应的report数据对应的一个hidinput->input设备[luther.gliethttp]
                    goto out_cleanup;
                hidinput = NULL;    // hidinput置空,以便下一个reprot_id对应的report执行上面的hidinput申请填充工作[luther.gliethttp]
            }
        }

    if (hidinput && input_register_device(hidinput->input))
        goto out_cleanup;

    return 0;

out_cleanup:
    input_free_device(hidinput->input);
    kfree(hidinput);
out_unwind:
    /* unwind the ones we already registered */
    hidinput_disconnect(hid);

    return -1;
}

阅读(5228) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

gliethttp2010-12-13 13:20:50

是通过input_attach_handler函数中的handler->id_table这个id_table来将设备与driver做匹配的,而input_handler_list上的driver是通过input_register_handler来完成注册登记的,可以参考 kernel/drivers/input/mousedev.c:1073: error = input_register_handler(&mousedev_handler); kernel/drivers/input/evdev.c:896: return input_register_handler(&evdev_handler);

chinaunix网友2010-12-06 16:57:37

你好啊,我想请教一下,在input子系统中,是通过什么信息来知道,设备要用的是Evdev,还是Mousedev,或者Keybdev? 恩,举个例子,我如果需要写一个红外遥控驱动,那么怎么才能让系统知道这是一个键盘驱动,要用Keybdev?