『Linuxバス、設備と駆動』USBHID設備駆動
10290 ワード
説明:本分析はmstar 801プラットフォームLinux 2に基づく.6.35.11カーネル、その他のカーネルバージョンは参照用のみです.
一、HID仮想バス駆動ロード
drivers/hid/hid-core.c
二、USBHID駆動ロード
USBHIDドライバは、USBバスデバイスドライバとHIDバスデバイスドライバを同時に含む.
drivers/hid/usbhid/hid-core.c
三、USBHID設備探知
1.USBバスのデバイスがHIDデバイスを探知して登録する
USBデバイス発見メカニズムは以下のリンクを参照してください.
『Linuxバス、設備と駆動』USB設備発見メカニズム
drivers/hid/usbhid/hid-core.c
drivers/hid/hid-core.c
HIDデバイスの登録:
drivers/hid/hid-core.c
2.HIDバスの設備探知
参考USBバス探知:http://blog.csdn.net/tankai19880619/article/details/11639185
drivers/hid/hid-core.c
四、具体的な設備駆動
1.HIDINPUTデバイス、例えば2.4 Gのリモコンを歩く
drivers/hid/hid-input.c
2.HIDDEV設備
drivers/hid/usbhid/hiddev.c
3.HIDRAWデバイス、デバイスと元の通信を行う
このドライバでは、データは解析されず、デバイスが生成したデータをアプリケーション層に簡単に伝えるだけです.
drivers/hid/hidraw.c
五、設備除去部分
1.USBバス装置除去トリガUSBHIDにおけるUSB駆動部呼び出し
drivers/hid/usbhid/hid-core.c
drivers/hid/hid-core.c
一、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.4 Gのリモコンを歩く
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
}