我们来看看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;
}