说明:本分析基于mstar801平台Linux2.6.35.11内核,其他内核版本仅供参考。
一、HID虚拟总线驱动加载
drivers/hid/hid-core.c
module_init(hid_init); static int __init hid_init(void){ ret = bus_register(&hid_bus_type); //注册HID虚拟总线 ret = hidraw_init(); } static struct bus_type hid_bus_type = { .name = "hid", .match = hid_bus_match, .probe = hid_device_probe, .remove = hid_device_remove, .uevent = hid_uevent, };
二、USBHID驱动加载
USBHID驱动同时包含USB总线设备驱动和HID总线设备驱动。
drivers/hid/usbhid/hid-core.c
static int __init hid_init(void){ retval = hid_register_driver(&hid_usb_driver); //注册HID总线设备驱动 retval = usb_register(&hid_driver); //注册USB总线设备驱动 } module_init(hid_init); static struct hid_driver hid_usb_driver = { //一般HID驱动都不实现probe方法 .name = "generic-usb", .id_table = hid_usb_table, }; static struct usb_driver hid_driver = { //USB设备驱动方法 .name = "usbhid", .probe = usbhid_probe, .disconnect = usbhid_disconnect, #ifdef CONFIG_PM .suspend = hid_suspend, .resume = hid_resume, .reset_resume = hid_reset_resume, #endif .pre_reset = hid_pre_reset, .post_reset = hid_post_reset, .id_table = hid_usb_ids, .supports_autosuspend = 1, };
三、USBHID设备探测
1.USB总线的设备探测并注册HID设备
USB设备发现机制看如下链接:
《Linux总线、设备与驱动》USB设备发现机制
drivers/hid/usbhid/hid-core.c
static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id){ hid = hid_allocate_device(); //申请HID设备 hid->ll_driver = &usb_hid_driver; //重要! /* static struct hid_ll_driver usb_hid_driver = { .parse = usbhid_parse, .start = usbhid_start, .stop = usbhid_stop, .open = usbhid_open, .close = usbhid_close, .power = usbhid_power, .hidinput_input_event = usb_hidinput_input_event, }; */ hid->hiddev_connect = hiddev_connect; hid->hiddev_disconnect = hiddev_disconnect; hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; usb_make_path(dev, hid->phys, sizeof(hid->phys)); strlcat(hid->phys, "/input", sizeof(hid->phys)); if (len < sizeof(hid->phys) - 1) snprintf(hid->phys + len, sizeof(hid->phys) - len, "%d", intf->altsetting[0].desc.bInterfaceNumber); ret = hid_add_device(hid); //注册HID设备 }申请HID设备:
drivers/hid/hid-core.c
struct hid_device *hid_allocate_device(void){ struct hid_device *hdev; device_initialize(&hdev->dev); hdev->dev.release = hid_device_release; hdev->dev.bus = &hid_bus_type; } static struct bus_type hid_bus_type = { .name = "hid", .match = hid_bus_match, .probe = hid_device_probe, .remove = hid_device_remove, .uevent = hid_uevent, };
注册HID设备:
drivers/hid/hid-core.c
int hid_add_device(struct hid_device *hdev){ ret = device_add(&hdev->dev); //该函数的调用将导致总线对应match和probe的调用 }
2.HID总线的设备探测
参考USB总线探测:http://blog.csdn.net/tankai19880619/article/details/11639185
drivers/hid/hid-core.c
//HID总线match函数 static int hid_bus_match(struct device *dev, struct device_driver *drv){ if (!hid_match_device(hdev, hdrv)) //匹配VID和PID return 0; if (!strncmp(hdrv->name, "generic-", 8)) //名字为generic-都匹配 return !hid_match_id(hdev, hid_have_special_driver); } //HID总线的probe函数 static int hid_device_probe(struct device *dev){ if (hdrv->probe) { //一般HID驱动都没有实现probe方法 ret = hdrv->probe(hdev, id); } else { /* default probe */ ret = hid_parse(hdev); /* include/linux/hid.h static inline int __must_check hid_parse(struct hid_device *hdev){ ret = hdev->ll_driver->parse(hdev); if (!ret) hdev->status |= HID_STAT_PARSED; return ret; } drivers/hid/usbhid/hid-core.c static int usbhid_parse(struct hid_device *hid){ ret = hid_parse_report(hid, rdesc, rsize); } */ if (!ret) ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); /* include/linux/hid.h static inline int __must_check hid_hw_start(struct hid_device *hdev, unsigned int connect_mask){ int ret = hdev->ll_driver->start(hdev); ret = hid_connect(hdev, connect_mask); if (ret) hdev->ll_driver->stop(hdev); } drivers/hid/usbhid/hid-core.c static int usbhid_start(struct hid_device *hid){ } */ } } int hid_connect(struct hid_device *hdev, unsigned int connect_mask){ static const char *types[] = { "Device", "Pointer", "Mouse", "Device", "Joystick", "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller" }; //HIDINPUT设备 if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,connect_mask & HID_CONNECT_HIDINPUT_FORCE)) hdev->claimed |= HID_CLAIMED_INPUT; //HIDDEV设备 if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect && !hdev->hiddev_connect(hdev,connect_mask & HID_CONNECT_HIDDEV_FORCE)) hdev->claimed |= HID_CLAIMED_HIDDEV; //HIDRAW设备 if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev)) hdev->claimed |= HID_CLAIMED_HIDRAW; }
四、具体设备驱动
1.HIDINPUT设备,如走2.4G的遥控器
drivers/hid/hid-input.c
int hidinput_connect(struct hid_device *hid, unsigned int force){ //申请设备 input_dev = input_allocate_device(); input_dev->event = hid->ll_driver->hidinput_input_event; input_dev->open = hidinput_open; input_dev->close = hidinput_close; input_dev->setkeycode = hidinput_setkeycode; input_dev->getkeycode = hidinput_getkeycode; input_dev->name = hid->name; for (i = 0; i < report->maxfield; i++) for (j = 0; j < report->field[i]->maxusage; j++) hidinput_configure_usage(hidinput, report->field[i],report->field[i]->usage + j); /* static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, struct hid_usage *usage){ switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_KEYBOARD: set_bit(EV_REP, input->evbit); if ((usage->hid & HID_USAGE) < 256) { if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore; map_key_clear(hid_keyboard[usage->hid & HID_USAGE]); /* static const unsigned char hid_keyboard[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 115,114,unk,172,194,121,229, 89, 93,124, 92, 94, 95,unk,unk,unk, 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk, 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk }; */ } else map_key(KEY_UNKNOWN); break; } } } */ //注册设备 if (hidinput && input_register_device(hidinput->input)) goto out_cleanup; }
2.HIDDEV设备
drivers/hid/usbhid/hiddev.c
int hiddev_connect(struct hid_device *hid, unsigned int force){ retval = usb_register_dev(usbhid->intf, &hiddev_class); }
3.HIDRAW设备,用来与设备做原始的通讯
这个驱动中不会解析任何数据,只是简单的将设备产生的数据传给应用层。
drivers/hid/hidraw.c
int hidraw_connect(struct hid_device *hid){ dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor), NULL, "%s%d", "hidraw", minor); }
五、设备移除部分
1.USB总线设备移除触发USBHID中USB驱动部分调用
drivers/hid/usbhid/hid-core.c
retval = usb_register(&hid_driver); static struct usb_driver hid_driver = { .disconnect = usbhid_disconnect, } static void usbhid_disconnect(struct usb_interface *intf){ hid_destroy_device(hid); //调用HID总线的设备注销函数 }2.HID总线驱动
drivers/hid/hid-core.c
void hid_destroy_device(struct hid_device *hdev){ hid_remove_device(hdev); } static void hid_remove_device(struct hid_device *hdev){ device_del(&hdev->dev); } //总线设备注销触发总线函数调用: static struct bus_type hid_bus_type = { .remove = hid_device_remove, } static int hid_device_remove(struct device *dev){ if (hdrv) { if (hdrv->remove) hdrv->remove(hdev); else /* default remove */ hid_hw_stop(hdev); /* include/linux/hid.h static inline void hid_hw_stop(struct hid_device *hdev){ hid_disconnect(hdev); } */ hdev->driver = NULL; } } void hid_disconnect(struct hid_device *hdev){ device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc); if (hdev->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hdev); //HIDINPUT设备 if (hdev->claimed & HID_CLAIMED_HIDDEV) hdev->hiddev_disconnect(hdev); //HIDDEV设备 if (hdev->claimed & HID_CLAIMED_HIDRAW) hidraw_disconnect(hdev); //HIDRAW设备 }