From f425458eafd51b6b5ab64f407922e1198c567cb2 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 17 Dec 2012 15:28:26 -0700 Subject: HID: Use module_hid_driver macro Use the new module_hid_driver macro in all HID drivers that have a simple register/unregister init/exit. This also converts the hid drivers that test for a failure of hid_register_driver() and report the failure. Using module_hid_driver in those drivers removes the failure message. Signed-off-by: H Hartley Sweeten Signed-off-by: Jiri Kosina --- drivers/hid/hid-a4tech.c | 13 +------------ drivers/hid/hid-apple.c | 19 +------------------ drivers/hid/hid-aureal.c | 13 +------------ drivers/hid/hid-axff.c | 14 +------------- drivers/hid/hid-belkin.c | 13 +------------ drivers/hid/hid-cherry.c | 13 +------------ drivers/hid/hid-chicony.c | 13 +------------ drivers/hid/hid-cypress.c | 13 +------------ drivers/hid/hid-dr.c | 13 +------------ drivers/hid/hid-elecom.c | 13 +------------ drivers/hid/hid-emsff.c | 13 +------------ drivers/hid/hid-ezkey.c | 13 +------------ drivers/hid/hid-gaff.c | 13 +------------ drivers/hid/hid-generic.c | 14 +------------- drivers/hid/hid-gyration.c | 13 +------------ drivers/hid/hid-holtek-kbd.c | 13 +------------ drivers/hid/hid-holtekff.c | 15 +-------------- drivers/hid/hid-icade.c | 19 +------------------ drivers/hid/hid-kensington.c | 13 +------------ drivers/hid/hid-keytouch.c | 13 +------------ drivers/hid/hid-kye.c | 13 +------------ drivers/hid/hid-lcpower.c | 13 +------------ drivers/hid/hid-lenovo-tpkbd.c | 14 +------------- drivers/hid/hid-lg.c | 13 +------------ drivers/hid/hid-magicmouse.c | 19 +------------------ drivers/hid/hid-microsoft.c | 13 +------------ drivers/hid/hid-monterey.c | 13 +------------ drivers/hid/hid-multitouch.c | 14 +------------- drivers/hid/hid-ntrig.c | 13 +------------ drivers/hid/hid-ortek.c | 13 +------------ drivers/hid/hid-petalynx.c | 13 +------------ drivers/hid/hid-picolcd_core.c | 13 +------------ drivers/hid/hid-pl.c | 13 +------------ drivers/hid/hid-primax.c | 13 +------------ drivers/hid/hid-prodikeys.c | 19 +------------------ drivers/hid/hid-ps3remote.c | 13 +------------ drivers/hid/hid-roccat-lua.c | 14 +------------- drivers/hid/hid-saitek.c | 13 +------------ drivers/hid/hid-samsung.c | 13 +------------ drivers/hid/hid-sensor-hub.c | 14 +------------- drivers/hid/hid-sjoy.c | 13 +------------ drivers/hid/hid-sony.c | 13 +------------ drivers/hid/hid-speedlink.c | 13 +------------ drivers/hid/hid-sunplus.c | 13 +------------ drivers/hid/hid-tivo.c | 13 +------------ drivers/hid/hid-tmff.c | 13 +------------ drivers/hid/hid-topseed.c | 13 +------------ drivers/hid/hid-twinhan.c | 13 +------------ drivers/hid/hid-uclogic.c | 13 +------------ drivers/hid/hid-wacom.c | 18 +----------------- drivers/hid/hid-waltop.c | 13 +------------ drivers/hid/hid-wiimote-core.c | 19 +------------------ drivers/hid/hid-zpff.c | 13 +------------ drivers/hid/hid-zydacron.c | 13 +------------ 54 files changed, 54 insertions(+), 691 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c index 0a23988..7c5507e 100644 --- a/drivers/hid/hid-a4tech.c +++ b/drivers/hid/hid-a4tech.c @@ -146,17 +146,6 @@ static struct hid_driver a4_driver = { .probe = a4_probe, .remove = a4_remove, }; +module_hid_driver(a4_driver); -static int __init a4_init(void) -{ - return hid_register_driver(&a4_driver); -} - -static void __exit a4_exit(void) -{ - hid_unregister_driver(&a4_driver); -} - -module_init(a4_init); -module_exit(a4_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index d0f7662..320a958 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -555,23 +555,6 @@ static struct hid_driver apple_driver = { .input_mapping = apple_input_mapping, .input_mapped = apple_input_mapped, }; +module_hid_driver(apple_driver); -static int __init apple_init(void) -{ - int ret; - - ret = hid_register_driver(&apple_driver); - if (ret) - pr_err("can't register apple driver\n"); - - return ret; -} - -static void __exit apple_exit(void) -{ - hid_unregister_driver(&apple_driver); -} - -module_init(apple_init); -module_exit(apple_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c index 7968187..340ba9d3 100644 --- a/drivers/hid/hid-aureal.c +++ b/drivers/hid/hid-aureal.c @@ -37,17 +37,6 @@ static struct hid_driver aureal_driver = { .id_table = aureal_devices, .report_fixup = aureal_report_fixup, }; +module_hid_driver(aureal_driver); -static int __init aureal_init(void) -{ - return hid_register_driver(&aureal_driver); -} - -static void __exit aureal_exit(void) -{ - hid_unregister_driver(&aureal_driver); -} - -module_init(aureal_init); -module_exit(aureal_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c index 5be858d..62f0cee 100644 --- a/drivers/hid/hid-axff.c +++ b/drivers/hid/hid-axff.c @@ -192,19 +192,7 @@ static struct hid_driver ax_driver = { .probe = ax_probe, .remove = ax_remove, }; - -static int __init ax_init(void) -{ - return hid_register_driver(&ax_driver); -} - -static void __exit ax_exit(void) -{ - hid_unregister_driver(&ax_driver); -} - -module_init(ax_init); -module_exit(ax_exit); +module_hid_driver(ax_driver); MODULE_AUTHOR("Sergei Kolzun"); MODULE_DESCRIPTION("Force feedback support for ACRUX game controllers"); diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c index a1a5a12..cc4cf13 100644 --- a/drivers/hid/hid-belkin.c +++ b/drivers/hid/hid-belkin.c @@ -86,17 +86,6 @@ static struct hid_driver belkin_driver = { .input_mapping = belkin_input_mapping, .probe = belkin_probe, }; +module_hid_driver(belkin_driver); -static int __init belkin_init(void) -{ - return hid_register_driver(&belkin_driver); -} - -static void __exit belkin_exit(void) -{ - hid_unregister_driver(&belkin_driver); -} - -module_init(belkin_init); -module_exit(belkin_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c index af034d3..1bdcccc 100644 --- a/drivers/hid/hid-cherry.c +++ b/drivers/hid/hid-cherry.c @@ -69,17 +69,6 @@ static struct hid_driver ch_driver = { .report_fixup = ch_report_fixup, .input_mapping = ch_input_mapping, }; +module_hid_driver(ch_driver); -static int __init ch_init(void) -{ - return hid_register_driver(&ch_driver); -} - -static void __exit ch_exit(void) -{ - hid_unregister_driver(&ch_driver); -} - -module_init(ch_init); -module_exit(ch_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index a2abb8e..b613d5a 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c @@ -70,17 +70,6 @@ static struct hid_driver ch_driver = { .id_table = ch_devices, .input_mapping = ch_input_mapping, }; +module_hid_driver(ch_driver); -static int __init ch_init(void) -{ - return hid_register_driver(&ch_driver); -} - -static void __exit ch_exit(void) -{ - hid_unregister_driver(&ch_driver); -} - -module_init(ch_init); -module_exit(ch_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index 3e159a5..c4ef3bc 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c @@ -144,17 +144,6 @@ static struct hid_driver cp_driver = { .event = cp_event, .probe = cp_probe, }; +module_hid_driver(cp_driver); -static int __init cp_init(void) -{ - return hid_register_driver(&cp_driver); -} - -static void __exit cp_exit(void) -{ - hid_unregister_driver(&cp_driver); -} - -module_init(cp_init); -module_exit(cp_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c index e832f44..0fe8f65 100644 --- a/drivers/hid/hid-dr.c +++ b/drivers/hid/hid-dr.c @@ -297,17 +297,6 @@ static struct hid_driver dr_driver = { .report_fixup = dr_report_fixup, .probe = dr_probe, }; +module_hid_driver(dr_driver); -static int __init dr_init(void) -{ - return hid_register_driver(&dr_driver); -} - -static void __exit dr_exit(void) -{ - hid_unregister_driver(&dr_driver); -} - -module_init(dr_init); -module_exit(dr_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 79d0c61..d0bd13b 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -41,17 +41,6 @@ static struct hid_driver elecom_driver = { .id_table = elecom_devices, .report_fixup = elecom_report_fixup }; +module_hid_driver(elecom_driver); -static int __init elecom_init(void) -{ - return hid_register_driver(&elecom_driver); -} - -static void __exit elecom_exit(void) -{ - hid_unregister_driver(&elecom_driver); -} - -module_init(elecom_init); -module_exit(elecom_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c index 2630d48..2e093ab 100644 --- a/drivers/hid/hid-emsff.c +++ b/drivers/hid/hid-emsff.c @@ -150,18 +150,7 @@ static struct hid_driver ems_driver = { .id_table = ems_devices, .probe = ems_probe, }; +module_hid_driver(ems_driver); -static int ems_init(void) -{ - return hid_register_driver(&ems_driver); -} - -static void ems_exit(void) -{ - hid_unregister_driver(&ems_driver); -} - -module_init(ems_init); -module_exit(ems_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c index 6540af2..212ac6b 100644 --- a/drivers/hid/hid-ezkey.c +++ b/drivers/hid/hid-ezkey.c @@ -76,17 +76,6 @@ static struct hid_driver ez_driver = { .input_mapping = ez_input_mapping, .event = ez_event, }; +module_hid_driver(ez_driver); -static int __init ez_init(void) -{ - return hid_register_driver(&ez_driver); -} - -static void __exit ez_exit(void) -{ - hid_unregister_driver(&ez_driver); -} - -module_init(ez_init); -module_exit(ez_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c index f1e1bcf..04d2e6a 100644 --- a/drivers/hid/hid-gaff.c +++ b/drivers/hid/hid-gaff.c @@ -176,17 +176,6 @@ static struct hid_driver ga_driver = { .id_table = ga_devices, .probe = ga_probe, }; +module_hid_driver(ga_driver); -static int __init ga_init(void) -{ - return hid_register_driver(&ga_driver); -} - -static void __exit ga_exit(void) -{ - hid_unregister_driver(&ga_driver); -} - -module_init(ga_init); -module_exit(ga_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c index a8b3148..e288a4a 100644 --- a/drivers/hid/hid-generic.c +++ b/drivers/hid/hid-generic.c @@ -34,19 +34,7 @@ static struct hid_driver hid_generic = { .name = "hid-generic", .id_table = hid_table, }; - -static int __init hid_init(void) -{ - return hid_register_driver(&hid_generic); -} - -static void __exit hid_exit(void) -{ - hid_unregister_driver(&hid_generic); -} - -module_init(hid_init); -module_exit(hid_exit); +module_hid_driver(hid_generic); MODULE_AUTHOR("Henrik Rydberg"); MODULE_DESCRIPTION("HID generic driver"); diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c index 4442c30..288d61c 100644 --- a/drivers/hid/hid-gyration.c +++ b/drivers/hid/hid-gyration.c @@ -88,17 +88,6 @@ static struct hid_driver gyration_driver = { .input_mapping = gyration_input_mapping, .event = gyration_event, }; +module_hid_driver(gyration_driver); -static int __init gyration_init(void) -{ - return hid_register_driver(&gyration_driver); -} - -static void __exit gyration_exit(void) -{ - hid_unregister_driver(&gyration_driver); -} - -module_init(gyration_init); -module_exit(gyration_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-holtek-kbd.c b/drivers/hid/hid-holtek-kbd.c index e0a5d17..6e1a4a4 100644 --- a/drivers/hid/hid-holtek-kbd.c +++ b/drivers/hid/hid-holtek-kbd.c @@ -167,17 +167,6 @@ static struct hid_driver holtek_kbd_driver = { .report_fixup = holtek_kbd_report_fixup, .probe = holtek_kbd_probe }; +module_hid_driver(holtek_kbd_driver); -static int __init holtek_kbd_init(void) -{ - return hid_register_driver(&holtek_kbd_driver); -} - -static void __exit holtek_kbd_exit(void) -{ - hid_unregister_driver(&holtek_kbd_driver); -} - -module_exit(holtek_kbd_exit); -module_init(holtek_kbd_init); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c index ff295e6..f34d118 100644 --- a/drivers/hid/hid-holtekff.c +++ b/drivers/hid/hid-holtekff.c @@ -224,17 +224,4 @@ static struct hid_driver holtek_driver = { .id_table = holtek_devices, .probe = holtek_probe, }; - -static int __init holtek_init(void) -{ - return hid_register_driver(&holtek_driver); -} - -static void __exit holtek_exit(void) -{ - hid_unregister_driver(&holtek_driver); -} - -module_init(holtek_init); -module_exit(holtek_exit); - +module_hid_driver(holtek_driver); diff --git a/drivers/hid/hid-icade.c b/drivers/hid/hid-icade.c index 1d6565e3..09dcc04 100644 --- a/drivers/hid/hid-icade.c +++ b/drivers/hid/hid-icade.c @@ -235,25 +235,8 @@ static struct hid_driver icade_driver = { .input_mapped = icade_input_mapped, .input_mapping = icade_input_mapping, }; +module_hid_driver(icade_driver); -static int __init icade_init(void) -{ - int ret; - - ret = hid_register_driver(&icade_driver); - if (ret) - pr_err("can't register icade driver\n"); - - return ret; -} - -static void __exit icade_exit(void) -{ - hid_unregister_driver(&icade_driver); -} - -module_init(icade_init); -module_exit(icade_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Bastien Nocera "); MODULE_DESCRIPTION("ION iCade input driver"); diff --git a/drivers/hid/hid-kensington.c b/drivers/hid/hid-kensington.c index a5b4016..fe9a99d 100644 --- a/drivers/hid/hid-kensington.c +++ b/drivers/hid/hid-kensington.c @@ -47,17 +47,6 @@ static struct hid_driver ks_driver = { .id_table = ks_devices, .input_mapping = ks_input_mapping, }; +module_hid_driver(ks_driver); -static int __init ks_init(void) -{ - return hid_register_driver(&ks_driver); -} - -static void __exit ks_exit(void) -{ - hid_unregister_driver(&ks_driver); -} - -module_init(ks_init); -module_exit(ks_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-keytouch.c b/drivers/hid/hid-keytouch.c index 07cd825..3074671 100644 --- a/drivers/hid/hid-keytouch.c +++ b/drivers/hid/hid-keytouch.c @@ -49,18 +49,7 @@ static struct hid_driver keytouch_driver = { .id_table = keytouch_devices, .report_fixup = keytouch_report_fixup, }; +module_hid_driver(keytouch_driver); -static int __init keytouch_init(void) -{ - return hid_register_driver(&keytouch_driver); -} - -static void __exit keytouch_exit(void) -{ - hid_unregister_driver(&keytouch_driver); -} - -module_init(keytouch_init); -module_exit(keytouch_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jiri Kosina"); diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index b4f0d82..ef72dae 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -419,17 +419,6 @@ static struct hid_driver kye_driver = { .probe = kye_probe, .report_fixup = kye_report_fixup, }; +module_hid_driver(kye_driver); -static int __init kye_init(void) -{ - return hid_register_driver(&kye_driver); -} - -static void __exit kye_exit(void) -{ - hid_unregister_driver(&kye_driver); -} - -module_init(kye_init); -module_exit(kye_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-lcpower.c b/drivers/hid/hid-lcpower.c index 22bc14a..6424cfd 100644 --- a/drivers/hid/hid-lcpower.c +++ b/drivers/hid/hid-lcpower.c @@ -54,17 +54,6 @@ static struct hid_driver ts_driver = { .id_table = ts_devices, .input_mapping = ts_input_mapping, }; +module_hid_driver(ts_driver); -static int __init ts_init(void) -{ - return hid_register_driver(&ts_driver); -} - -static void __exit ts_exit(void) -{ - hid_unregister_driver(&ts_driver); -} - -module_init(ts_init); -module_exit(ts_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c index cea016e..956c3b1 100644 --- a/drivers/hid/hid-lenovo-tpkbd.c +++ b/drivers/hid/hid-lenovo-tpkbd.c @@ -468,18 +468,6 @@ static struct hid_driver tpkbd_driver = { .probe = tpkbd_probe, .remove = tpkbd_remove, }; - -static int __init tpkbd_init(void) -{ - return hid_register_driver(&tpkbd_driver); -} - -static void __exit tpkbd_exit(void) -{ - hid_unregister_driver(&tpkbd_driver); -} - -module_init(tpkbd_init); -module_exit(tpkbd_exit); +module_hid_driver(tpkbd_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index a2f8e88..e3dc73b 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -503,17 +503,6 @@ static struct hid_driver lg_driver = { .probe = lg_probe, .remove = lg_remove, }; +module_hid_driver(lg_driver); -static int __init lg_init(void) -{ - return hid_register_driver(&lg_driver); -} - -static void __exit lg_exit(void) -{ - hid_unregister_driver(&lg_driver); -} - -module_init(lg_init); -module_exit(lg_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 25ddf3e..f7f113b 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -569,23 +569,6 @@ static struct hid_driver magicmouse_driver = { .raw_event = magicmouse_raw_event, .input_mapping = magicmouse_input_mapping, }; +module_hid_driver(magicmouse_driver); -static int __init magicmouse_init(void) -{ - int ret; - - ret = hid_register_driver(&magicmouse_driver); - if (ret) - pr_err("can't register magicmouse driver\n"); - - return ret; -} - -static void __exit magicmouse_exit(void) -{ - hid_unregister_driver(&magicmouse_driver); -} - -module_init(magicmouse_init); -module_exit(magicmouse_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 6fcd466d0..29d27f6 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -221,17 +221,6 @@ static struct hid_driver ms_driver = { .event = ms_event, .probe = ms_probe, }; +module_hid_driver(ms_driver); -static int __init ms_init(void) -{ - return hid_register_driver(&ms_driver); -} - -static void __exit ms_exit(void) -{ - hid_unregister_driver(&ms_driver); -} - -module_init(ms_init); -module_exit(ms_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c index cd3643e..9e14c00 100644 --- a/drivers/hid/hid-monterey.c +++ b/drivers/hid/hid-monterey.c @@ -63,17 +63,6 @@ static struct hid_driver mr_driver = { .report_fixup = mr_report_fixup, .input_mapping = mr_input_mapping, }; +module_hid_driver(mr_driver); -static int __init mr_init(void) -{ - return hid_register_driver(&mr_driver); -} - -static void __exit mr_exit(void) -{ - hid_unregister_driver(&mr_driver); -} - -module_init(mr_init); -module_exit(mr_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 61543c0..46d8136 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1198,16 +1198,4 @@ static struct hid_driver mt_driver = { .resume = mt_resume, #endif }; - -static int __init mt_init(void) -{ - return hid_register_driver(&mt_driver); -} - -static void __exit mt_exit(void) -{ - hid_unregister_driver(&mt_driver); -} - -module_init(mt_init); -module_exit(mt_exit); +module_hid_driver(mt_driver); diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 86a969f..2ffc0e3 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -1026,17 +1026,6 @@ static struct hid_driver ntrig_driver = { .usage_table = ntrig_grabbed_usages, .event = ntrig_event, }; +module_hid_driver(ntrig_driver); -static int __init ntrig_init(void) -{ - return hid_register_driver(&ntrig_driver); -} - -static void __exit ntrig_exit(void) -{ - hid_unregister_driver(&ntrig_driver); -} - -module_init(ntrig_init); -module_exit(ntrig_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c index 0ffa1d2..6620f15 100644 --- a/drivers/hid/hid-ortek.c +++ b/drivers/hid/hid-ortek.c @@ -50,17 +50,6 @@ static struct hid_driver ortek_driver = { .id_table = ortek_devices, .report_fixup = ortek_report_fixup }; +module_hid_driver(ortek_driver); -static int __init ortek_init(void) -{ - return hid_register_driver(&ortek_driver); -} - -static void __exit ortek_exit(void) -{ - hid_unregister_driver(&ortek_driver); -} - -module_init(ortek_init); -module_exit(ortek_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c index 4c521de..736b250 100644 --- a/drivers/hid/hid-petalynx.c +++ b/drivers/hid/hid-petalynx.c @@ -103,17 +103,6 @@ static struct hid_driver pl_driver = { .input_mapping = pl_input_mapping, .probe = pl_probe, }; +module_hid_driver(pl_driver); -static int __init pl_init(void) -{ - return hid_register_driver(&pl_driver); -} - -static void __exit pl_exit(void) -{ - hid_unregister_driver(&pl_driver); -} - -module_init(pl_init); -module_exit(pl_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c index 86df26e..31cd93f 100644 --- a/drivers/hid/hid-picolcd_core.c +++ b/drivers/hid/hid-picolcd_core.c @@ -672,18 +672,7 @@ static struct hid_driver picolcd_driver = { .reset_resume = picolcd_reset_resume, #endif }; +module_hid_driver(picolcd_driver); -static int __init picolcd_init(void) -{ - return hid_register_driver(&picolcd_driver); -} - -static void __exit picolcd_exit(void) -{ - hid_unregister_driver(&picolcd_driver); -} - -module_init(picolcd_init); -module_exit(picolcd_exit); MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c index 47ed74c..123977e 100644 --- a/drivers/hid/hid-pl.c +++ b/drivers/hid/hid-pl.c @@ -216,17 +216,6 @@ static struct hid_driver pl_driver = { .id_table = pl_devices, .probe = pl_probe, }; +module_hid_driver(pl_driver); -static int __init pl_init(void) -{ - return hid_register_driver(&pl_driver); -} - -static void __exit pl_exit(void) -{ - hid_unregister_driver(&pl_driver); -} - -module_init(pl_init); -module_exit(pl_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-primax.c b/drivers/hid/hid-primax.c index c15adb0..3a1c3c4 100644 --- a/drivers/hid/hid-primax.c +++ b/drivers/hid/hid-primax.c @@ -75,18 +75,7 @@ static struct hid_driver px_driver = { .id_table = px_devices, .raw_event = px_raw_event, }; +module_hid_driver(px_driver); -static int __init px_init(void) -{ - return hid_register_driver(&px_driver); -} - -static void __exit px_exit(void) -{ - hid_unregister_driver(&px_driver); -} - -module_init(px_init); -module_exit(px_exit); MODULE_AUTHOR("Terry Lambert "); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index ec8ca33..4e1c4bc 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -889,23 +889,6 @@ static struct hid_driver pk_driver = { .probe = pk_probe, .remove = pk_remove, }; +module_hid_driver(pk_driver); -static int pk_init(void) -{ - int ret; - - ret = hid_register_driver(&pk_driver); - if (ret) - pr_err("can't register prodikeys driver\n"); - - return ret; -} - -static void pk_exit(void) -{ - hid_unregister_driver(&pk_driver); -} - -module_init(pk_init); -module_exit(pk_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ps3remote.c b/drivers/hid/hid-ps3remote.c index 03811e53..f1239d3 100644 --- a/drivers/hid/hid-ps3remote.c +++ b/drivers/hid/hid-ps3remote.c @@ -198,18 +198,7 @@ static struct hid_driver ps3remote_driver = { .report_fixup = ps3remote_fixup, .input_mapping = ps3remote_mapping, }; +module_hid_driver(ps3remote_driver); -static int __init ps3remote_init(void) -{ - return hid_register_driver(&ps3remote_driver); -} - -static void __exit ps3remote_exit(void) -{ - hid_unregister_driver(&ps3remote_driver); -} - -module_init(ps3remote_init); -module_exit(ps3remote_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Dillow , Antonio Ospite "); diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c index 5084fb4..6adc0fa 100644 --- a/drivers/hid/hid-roccat-lua.c +++ b/drivers/hid/hid-roccat-lua.c @@ -208,19 +208,7 @@ static struct hid_driver lua_driver = { .probe = lua_probe, .remove = lua_remove }; - -static int __init lua_init(void) -{ - return hid_register_driver(&lua_driver); -} - -static void __exit lua_exit(void) -{ - hid_unregister_driver(&lua_driver); -} - -module_init(lua_init); -module_exit(lua_exit); +module_hid_driver(lua_driver); MODULE_AUTHOR("Stefan Achatz"); MODULE_DESCRIPTION("USB Roccat Lua driver"); diff --git a/drivers/hid/hid-saitek.c b/drivers/hid/hid-saitek.c index 45aea77..37961c7 100644 --- a/drivers/hid/hid-saitek.c +++ b/drivers/hid/hid-saitek.c @@ -54,17 +54,6 @@ static struct hid_driver saitek_driver = { .id_table = saitek_devices, .report_fixup = saitek_report_fixup }; +module_hid_driver(saitek_driver); -static int __init saitek_init(void) -{ - return hid_register_driver(&saitek_driver); -} - -static void __exit saitek_exit(void) -{ - hid_unregister_driver(&saitek_driver); -} - -module_init(saitek_init); -module_exit(saitek_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c index a5821d3..7cbb067 100644 --- a/drivers/hid/hid-samsung.c +++ b/drivers/hid/hid-samsung.c @@ -196,17 +196,6 @@ static struct hid_driver samsung_driver = { .input_mapping = samsung_input_mapping, .probe = samsung_probe, }; +module_hid_driver(samsung_driver); -static int __init samsung_init(void) -{ - return hid_register_driver(&samsung_driver); -} - -static void __exit samsung_exit(void) -{ - hid_unregister_driver(&samsung_driver); -} - -module_init(samsung_init); -module_exit(samsung_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 0bc58bd..4179f5e 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -627,19 +627,7 @@ static struct hid_driver sensor_hub_driver = { .reset_resume = sensor_hub_reset_resume, #endif }; - -static int __init sensor_hub_init(void) -{ - return hid_register_driver(&sensor_hub_driver); -} - -static void __exit sensor_hub_exit(void) -{ - hid_unregister_driver(&sensor_hub_driver); -} - -module_init(sensor_hub_init); -module_exit(sensor_hub_exit); +module_hid_driver(sensor_hub_driver); MODULE_DESCRIPTION("HID Sensor Hub driver"); MODULE_AUTHOR("Srinivas Pandruvada "); diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c index 42257ac..28f7740 100644 --- a/drivers/hid/hid-sjoy.c +++ b/drivers/hid/hid-sjoy.c @@ -177,19 +177,8 @@ static struct hid_driver sjoy_driver = { .id_table = sjoy_devices, .probe = sjoy_probe, }; +module_hid_driver(sjoy_driver); -static int __init sjoy_init(void) -{ - return hid_register_driver(&sjoy_driver); -} - -static void __exit sjoy_exit(void) -{ - hid_unregister_driver(&sjoy_driver); -} - -module_init(sjoy_init); -module_exit(sjoy_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jussi Kivilinna"); diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 7f33ebf..23fc762 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -229,17 +229,6 @@ static struct hid_driver sony_driver = { .report_fixup = sony_report_fixup, .raw_event = sony_raw_event }; +module_hid_driver(sony_driver); -static int __init sony_init(void) -{ - return hid_register_driver(&sony_driver); -} - -static void __exit sony_exit(void) -{ - hid_unregister_driver(&sony_driver); -} - -module_init(sony_init); -module_exit(sony_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-speedlink.c b/drivers/hid/hid-speedlink.c index 6020137..e94371a 100644 --- a/drivers/hid/hid-speedlink.c +++ b/drivers/hid/hid-speedlink.c @@ -73,17 +73,6 @@ static struct hid_driver speedlink_driver = { .input_mapping = speedlink_input_mapping, .event = speedlink_event, }; +module_hid_driver(speedlink_driver); -static int __init speedlink_init(void) -{ - return hid_register_driver(&speedlink_driver); -} - -static void __exit speedlink_exit(void) -{ - hid_unregister_driver(&speedlink_driver); -} - -module_init(speedlink_init); -module_exit(speedlink_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c index 45b4b06..87fc91e 100644 --- a/drivers/hid/hid-sunplus.c +++ b/drivers/hid/hid-sunplus.c @@ -63,17 +63,6 @@ static struct hid_driver sp_driver = { .report_fixup = sp_report_fixup, .input_mapping = sp_input_mapping, }; +module_hid_driver(sp_driver); -static int __init sp_init(void) -{ - return hid_register_driver(&sp_driver); -} - -static void __exit sp_exit(void) -{ - hid_unregister_driver(&sp_driver); -} - -module_init(sp_init); -module_exit(sp_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-tivo.c b/drivers/hid/hid-tivo.c index 9f85f82..d790d8d 100644 --- a/drivers/hid/hid-tivo.c +++ b/drivers/hid/hid-tivo.c @@ -73,18 +73,7 @@ static struct hid_driver tivo_driver = { .id_table = tivo_devices, .input_mapping = tivo_input_mapping, }; +module_hid_driver(tivo_driver); -static int __init tivo_init(void) -{ - return hid_register_driver(&tivo_driver); -} - -static void __exit tivo_exit(void) -{ - hid_unregister_driver(&tivo_driver); -} - -module_init(tivo_init); -module_exit(tivo_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson "); diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index 83a933b..e4fcf3f 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -261,17 +261,6 @@ static struct hid_driver tm_driver = { .id_table = tm_devices, .probe = tm_probe, }; +module_hid_driver(tm_driver); -static int __init tm_init(void) -{ - return hid_register_driver(&tm_driver); -} - -static void __exit tm_exit(void) -{ - hid_unregister_driver(&tm_driver); -} - -module_init(tm_init); -module_exit(tm_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c index 613ff7b..8a5b843 100644 --- a/drivers/hid/hid-topseed.c +++ b/drivers/hid/hid-topseed.c @@ -76,17 +76,6 @@ static struct hid_driver ts_driver = { .id_table = ts_devices, .input_mapping = ts_input_mapping, }; +module_hid_driver(ts_driver); -static int __init ts_init(void) -{ - return hid_register_driver(&ts_driver); -} - -static void __exit ts_exit(void) -{ - hid_unregister_driver(&ts_driver); -} - -module_init(ts_init); -module_exit(ts_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-twinhan.c b/drivers/hid/hid-twinhan.c index f23456b..c08c364 100644 --- a/drivers/hid/hid-twinhan.c +++ b/drivers/hid/hid-twinhan.c @@ -131,17 +131,6 @@ static struct hid_driver twinhan_driver = { .id_table = twinhan_devices, .input_mapping = twinhan_input_mapping, }; +module_hid_driver(twinhan_driver); -static int __init twinhan_init(void) -{ - return hid_register_driver(&twinhan_driver); -} - -static void __exit twinhan_exit(void) -{ - hid_unregister_driver(&twinhan_driver); -} - -module_init(twinhan_init); -module_exit(twinhan_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c index 2e56a1f..fb8b516 100644 --- a/drivers/hid/hid-uclogic.c +++ b/drivers/hid/hid-uclogic.c @@ -650,17 +650,6 @@ static struct hid_driver uclogic_driver = { .id_table = uclogic_devices, .report_fixup = uclogic_report_fixup, }; +module_hid_driver(uclogic_driver); -static int __init uclogic_init(void) -{ - return hid_register_driver(&uclogic_driver); -} - -static void __exit uclogic_exit(void) -{ - hid_unregister_driver(&uclogic_driver); -} - -module_init(uclogic_init); -module_exit(uclogic_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 2f60da9..a4a8bb0 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -953,23 +953,7 @@ static struct hid_driver wacom_driver = { .raw_event = wacom_raw_event, .input_mapped = wacom_input_mapped, }; +module_hid_driver(wacom_driver); -static int __init wacom_init(void) -{ - int ret; - - ret = hid_register_driver(&wacom_driver); - if (ret) - pr_err("can't register wacom driver\n"); - return ret; -} - -static void __exit wacom_exit(void) -{ - hid_unregister_driver(&wacom_driver); -} - -module_init(wacom_init); -module_exit(wacom_exit); MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL"); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c index bb536ab..059931d 100644 --- a/drivers/hid/hid-waltop.c +++ b/drivers/hid/hid-waltop.c @@ -779,17 +779,6 @@ static struct hid_driver waltop_driver = { .report_fixup = waltop_report_fixup, .raw_event = waltop_raw_event, }; +module_hid_driver(waltop_driver); -static int __init waltop_init(void) -{ - return hid_register_driver(&waltop_driver); -} - -static void __exit waltop_exit(void) -{ - hid_unregister_driver(&waltop_driver); -} - -module_init(waltop_init); -module_exit(waltop_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index 84e2fbe..0fb8ab9 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -1294,25 +1294,8 @@ static struct hid_driver wiimote_hid_driver = { .remove = wiimote_hid_remove, .raw_event = wiimote_hid_event, }; +module_hid_driver(wiimote_hid_driver); -static int __init wiimote_init(void) -{ - int ret; - - ret = hid_register_driver(&wiimote_hid_driver); - if (ret) - pr_err("Can't register wiimote hid driver\n"); - - return ret; -} - -static void __exit wiimote_exit(void) -{ - hid_unregister_driver(&wiimote_hid_driver); -} - -module_init(wiimote_init); -module_exit(wiimote_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Herrmann "); MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver"); diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c index f6ba81d..af66452 100644 --- a/drivers/hid/hid-zpff.c +++ b/drivers/hid/hid-zpff.c @@ -152,17 +152,6 @@ static struct hid_driver zp_driver = { .id_table = zp_devices, .probe = zp_probe, }; +module_hid_driver(zp_driver); -static int __init zp_init(void) -{ - return hid_register_driver(&zp_driver); -} - -static void __exit zp_exit(void) -{ - hid_unregister_driver(&zp_driver); -} - -module_init(zp_init); -module_exit(zp_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c index 1ad85f2..e4cddec 100644 --- a/drivers/hid/hid-zydacron.c +++ b/drivers/hid/hid-zydacron.c @@ -219,17 +219,6 @@ static struct hid_driver zc_driver = { .probe = zc_probe, .remove = zc_remove, }; +module_hid_driver(zc_driver); -static int __init zc_init(void) -{ - return hid_register_driver(&zc_driver); -} - -static void __exit zc_exit(void) -{ - hid_unregister_driver(&zc_driver); -} - -module_init(zc_init); -module_exit(zc_exit); MODULE_LICENSE("GPL"); -- cgit v1.1 From e57a67da600408c6f15c453a48c386d0f17188dd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Dec 2012 20:57:34 -0200 Subject: HID: hid-sony: fix troubles with Sony remote clones There are some Sony clone gamepads that are incompatible with PS3 since firmware 3.50, as they decided to prevent those devices to work, without any good technical reason. I was one of those 'blessed' people affected by their niceness with their customers. Marcelo also has another device with a similar problem. Perhaps due to Sony's way to block the device, damaging the device's eeprom, or perhaps because they just have a different, broken Report descriptor, there are 3 buttons that don't work on both devices (the ones equivalent to square, round and X). What it happens is that the descriptor generate weird EV_ABS events to those buttons, instead of EV_MSC/EV_KEY. A fix that seems to be enough for them is to return the original sixaxis table instead of the broken one. That's what this patch does. Yet, there are some missing entries at the used keytable. On my tests, all keys are now producing the right events, but the reported keycodes look weird: "square" key: (Button.0010 = 1) 1355524363.460835: event type EV_MSC(0x04): scancode = 0x90010 1355524363.460835: event type EV_KEY(0x01) key_up: BTN_DEAD(0x0001) "round" key: (Button.000e = 1) 1355524410.908705: event type EV_MSC(0x04): scancode = 0x9000e 1355524410.908705: event type EV_KEY(0x01) key_down: (0x0001) 1355524410.971788: event type EV_MSC(0x04): scancode = 0x9000e 1355524410.971788: event type EV_KEY(0x01) key_up: (0x0001) "X" key: (Button.000f = 1) 1355524384.880813: event type EV_MSC(0x04): scancode = 0x9000f 1355524384.880813: event type EV_KEY(0x01) key_down: (0x0001) 1355524384.979815: event type EV_MSC(0x04): scancode = 0x9000f 1355524384.979815: event type EV_KEY(0x01) key_up: (0x0001) The rationale is likely due to those entries at rdesc table, where the Kernel were not likely able to parse: Button.000d ---> Key.? Button.000e ---> Key.? Button.000f ---> Key.? Button.0010 ---> Key.BtnDead Button.0011 ---> Key.? Button.0012 ---> Key.? Button.0013 ---> Key.? As a reference, this is the rdisc used on my clone (a Mad Catz model 8846): 05 01 09 04 a1 01 a1 02 85 01 75 08 95 01 15 00 26 ff 00 81 03 75 01 95 0d 15 00 25 01 35 00 45 01 05 09 19 01 29 0d 81 02 75 01 95 03 06 00 ff 81 03 05 01 25 07 46 3b 01 75 04 95 01 65 14 09 39 81 42 65 00 75 01 95 0c 06 00 ff 81 03 15 00 26 ff 00 05 01 09 01 a1 00 75 08 95 04 15 00 15 00 15 00 35 00 35 00 46 ff 00 09 30 09 31 09 32 09 35 81 02 c0 05 01 75 08 95 27 09 01 81 02 75 08 95 30 09 01 91 02 75 08 95 30 09 01 b1 02 c0 a1 02 85 02 75 08 95 30 09 01 b1 02 c0 a1 02 85 ee 75 08 95 30 09 01 b1 02 c0 a1 02 85 ef 75 08 95 30 09 01 b1 02 c0 c0 This is what's returned on Marcelo's device (not sure what is the brand name of his device): 05 01 09 04 a1 01 a1 02 85 01 75 08 95 01 15 00 26 ff 00 81 03 75 01 95 13 15 00 25 01 35 00 45 01 05 09 19 01 29 13 81 02 75 01 95 0d 06 00 ff 81 03 15 00 26 ff 00 05 01 09 01 a1 00 75 08 95 04 35 00 46 ff 00 09 30 09 31 09 32 09 35 81 02 c0 05 01 95 13 09 01 81 02 95 0c 81 01 75 10 95 04 26 ff 03 46 ff 03 09 01 81 02 c0 a1 02 85 02 75 08 95 30 09 01 b1 02 c0 a1 02 85 ee 75 08 95 30 09 01 b1 02 c0 a1 02 85 ef 75 08 95 30 09 01 b1 02 c0 c0 Reported-by: Marcelo Leitner Signed-off-by: Mauro Carvalho Chehab Tested-by: Marcelo Leitner Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 7f33ebf..16df4d8 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -33,6 +33,28 @@ static const u8 sixaxis_rdesc_fixup[] = { 0x03, 0x46, 0xFF, 0x03, 0x09, 0x01, 0x81, 0x02 }; +static const u8 sixaxis_rdesc_fixup2[] = { + 0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0xa1, 0x02, + 0x85, 0x01, 0x75, 0x08, 0x95, 0x01, 0x15, 0x00, + 0x26, 0xff, 0x00, 0x81, 0x03, 0x75, 0x01, 0x95, + 0x13, 0x15, 0x00, 0x25, 0x01, 0x35, 0x00, 0x45, + 0x01, 0x05, 0x09, 0x19, 0x01, 0x29, 0x13, 0x81, + 0x02, 0x75, 0x01, 0x95, 0x0d, 0x06, 0x00, 0xff, + 0x81, 0x03, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05, + 0x01, 0x09, 0x01, 0xa1, 0x00, 0x75, 0x08, 0x95, + 0x04, 0x35, 0x00, 0x46, 0xff, 0x00, 0x09, 0x30, + 0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x81, 0x02, + 0xc0, 0x05, 0x01, 0x95, 0x13, 0x09, 0x01, 0x81, + 0x02, 0x95, 0x0c, 0x81, 0x01, 0x75, 0x10, 0x95, + 0x04, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x09, + 0x01, 0x81, 0x02, 0xc0, 0xa1, 0x02, 0x85, 0x02, + 0x75, 0x08, 0x95, 0x30, 0x09, 0x01, 0xb1, 0x02, + 0xc0, 0xa1, 0x02, 0x85, 0xee, 0x75, 0x08, 0x95, + 0x30, 0x09, 0x01, 0xb1, 0x02, 0xc0, 0xa1, 0x02, + 0x85, 0xef, 0x75, 0x08, 0x95, 0x30, 0x09, 0x01, + 0xb1, 0x02, 0xc0, 0xc0, +}; + struct sony_sc { unsigned long quirks; }; @@ -56,6 +78,12 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, hid_info(hdev, "Fixing up Sony Sixaxis report descriptor\n"); memcpy((void *)&rdesc[83], (void *)&sixaxis_rdesc_fixup, sizeof(sixaxis_rdesc_fixup)); + } else if (sc->quirks & SIXAXIS_CONTROLLER_USB && + *rsize > sizeof(sixaxis_rdesc_fixup2)) { + hid_info(hdev, "Sony Sixaxis clone detected. Using original report descriptor (size: %d clone; %d new)\n", + *rsize, (int)sizeof(sixaxis_rdesc_fixup2)); + *rsize = sizeof(sixaxis_rdesc_fixup2); + memcpy(rdesc, &sixaxis_rdesc_fixup2, *rsize); } return rdesc; } -- cgit v1.1 From a464918419f94a0043d2f549d6defb4c3f69f68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Luis=20V=C3=A1zquez=20Cao?= Date: Tue, 15 Jan 2013 19:40:48 +0900 Subject: HID: add support for Sony RF receiver with USB product id 0x0374 Some Vaio desktop computers, among them the VGC-LN51JGB multimedia PC, have a RF receiver, multi-interface USB device 054c:0374, that is used to connect a wireless keyboard and a wireless mouse. The keyboard works flawlessly, but the mouse (VGP-WMS3 in my case) does not seem to be generating any pointer events. The problem is that the mouse pointer is wrongly declared as a constant non-data variable in the report descriptor (see lsusb and usbhid-dump output below), with the consequence that it is ignored by the HID code. Add this device to the have-special-driver list and fix up the report descriptor in the Sony-specific driver which happens to already have a fixup for a similar firmware bug. # lsusb -vd 054C:0374 Bus 003 Device 002: ID 054c:0374 Sony Corp. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x054c Sony Corp. idProduct 0x0374 iSerial 0 [...] Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 1 Boot Interface Subclass bInterfaceProtocol 2 Mouse iInterface 2 RF Receiver [...] Report Descriptor: (length is 100) [...] Item(Global): Usage Page, data= [ 0x01 ] 1 Generic Desktop Controls Item(Local ): Usage, data= [ 0x30 ] 48 Direction-X Item(Local ): Usage, data= [ 0x31 ] 49 Direction-Y Item(Global): Report Count, data= [ 0x02 ] 2 Item(Global): Report Size, data= [ 0x08 ] 8 Item(Global): Logical Minimum, data= [ 0x81 ] 129 Item(Global): Logical Maximum, data= [ 0x7f ] 127 Item(Main ): Input, data= [ 0x07 ] 7 Constant Variable Relative No_Wrap Linear Preferred_State No_Null_Position Non_Volatile Bitfield # usbhid-dump 003:002:001:DESCRIPTOR 1357910009.758544 05 01 09 02 A1 01 05 01 09 02 A1 02 85 01 09 01 A1 00 05 09 19 01 29 05 95 05 75 01 15 00 25 01 81 02 75 03 95 01 81 01 05 01 09 30 09 31 95 02 75 08 15 81 25 7F 81 07 A1 02 85 01 09 38 35 00 45 00 15 81 25 7F 95 01 75 08 81 06 C0 A1 02 85 01 05 0C 15 81 25 7F 95 01 75 08 0A 38 02 81 06 C0 C0 C0 C0 Cc: linux-input@vger.kernel.org Cc: linux-usb@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Fernando Luis Vazquez Cao Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-sony.c | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index eb2ee11..1651728 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1697,6 +1697,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4dfa605..50ac909 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -706,6 +706,7 @@ #define USB_VENDOR_ID_SONY 0x054c #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b +#define USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE 0x0374 #define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 16df4d8..6d2d459 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -67,7 +67,7 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, if ((sc->quirks & VAIO_RDESC_CONSTANT) && *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { - hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n"); + hid_info(hdev, "Fixing up Sony RF Receiver report descriptor\n"); rdesc[55] = 0x06; } @@ -245,6 +245,8 @@ static const struct hid_device_id sony_devices[] = { .driver_data = SIXAXIS_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), .driver_data = VAIO_RDESC_CONSTANT }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE), + .driver_data = VAIO_RDESC_CONSTANT }, { } }; MODULE_DEVICE_TABLE(hid, sony_devices); -- cgit v1.1 From aaca9cc0165f06a037a1e07770f6b379ff496288 Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Thu, 17 Jan 2013 11:06:09 +0100 Subject: HID: Support Jess/Saitek Color Rumble Pad Add support for another gamepad to the hid-pl driver. The "color rumble pad P580" marketed using the "Saitek" brand in Germany, and using a USB Vendor ID attributed to "Jess" seems to be electronically identical to the 4-field variant of the "Green Asia" gamepad. The pad has been tested to support rumble strengths up to 255, not just 127. Signed-off-by: Michael Karcher Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-pl.c | 13 +++++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index eb2ee11..aad2627 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1599,6 +1599,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4dfa605..3a49334 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -442,6 +442,9 @@ #define USB_VENDOR_ID_JESS 0x0c45 #define USB_DEVICE_ID_JESS_YUREX 0x1010 +#define USB_VENDOR_ID_JESS2 0x0f30 +#define USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD 0x0111 + #define USB_VENDOR_ID_KBGEAR 0x084e #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c index 123977e..b0199d2 100644 --- a/drivers/hid/hid-pl.c +++ b/drivers/hid/hid-pl.c @@ -14,6 +14,8 @@ * 0e8f:0003 "GASIA USB Gamepad" * - another version of the König gamepad * + * 0f30:0111 "Saitek Color Rumble Pad" + * * Copyright (c) 2007, 2009 Anssi Hannula */ @@ -51,6 +53,7 @@ struct plff_device { struct hid_report *report; + s32 maxval; s32 *strong; s32 *weak; }; @@ -66,8 +69,8 @@ static int hid_plff_play(struct input_dev *dev, void *data, right = effect->u.rumble.weak_magnitude; debug("called with 0x%04x 0x%04x", left, right); - left = left * 0x7f / 0xffff; - right = right * 0x7f / 0xffff; + left = left * plff->maxval / 0xffff; + right = right * plff->maxval / 0xffff; *plff->strong = left; *plff->weak = right; @@ -87,6 +90,7 @@ static int plff_init(struct hid_device *hid) struct list_head *report_ptr = report_list; struct input_dev *dev; int error; + s32 maxval; s32 *strong; s32 *weak; @@ -123,6 +127,7 @@ static int plff_init(struct hid_device *hid) return -ENODEV; } + maxval = 0x7f; if (report->field[0]->report_count >= 4) { report->field[0]->value[0] = 0x00; report->field[0]->value[1] = 0x00; @@ -135,6 +140,8 @@ static int plff_init(struct hid_device *hid) report->field[1]->value[0] = 0x00; strong = &report->field[2]->value[0]; weak = &report->field[3]->value[0]; + if (hid->vendor == USB_VENDOR_ID_JESS2) + maxval = 0xff; debug("detected 4-field device"); } else { hid_err(hid, "not enough fields or values\n"); @@ -158,6 +165,7 @@ static int plff_init(struct hid_device *hid) plff->report = report; plff->strong = strong; plff->weak = weak; + plff->maxval = maxval; *strong = 0x00; *weak = 0x00; @@ -207,6 +215,7 @@ static const struct hid_device_id pl_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR), .driver_data = 1 }, /* Twin USB Joystick */ { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), }, + { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD), }, { } }; MODULE_DEVICE_TABLE(hid, pl_devices); -- cgit v1.1 From b77a989acca3fb4d09c2d8c3749499c663f5ab9f Mon Sep 17 00:00:00 2001 From: Simon Que Date: Thu, 17 Jan 2013 13:02:52 -0800 Subject: HID: Fix uninitialized variable "size" in hid-wiimote-debug This variable is initialized conditionally, based on whether a wiimote call succeeds. However, the logic is not obvious to the compiler so it throws a warning. Eliminate the warning by initializing "size" to 0. The warning is: files/drivers/hid/hid-wiimote-debug.c:69:18: warning: 'size' may be used uninitialized in this function [-Wmaybe-uninitialized] Signed-off-by: Simon Que Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-wiimote-debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-wiimote-debug.c b/drivers/hid/hid-wiimote-debug.c index eec3291..90124ff 100644 --- a/drivers/hid/hid-wiimote-debug.c +++ b/drivers/hid/hid-wiimote-debug.c @@ -31,7 +31,7 @@ static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s, unsigned long flags; ssize_t ret; char buf[16]; - __u16 size; + __u16 size = 0; if (s == 0) return -EINVAL; -- cgit v1.1 From 92241e67c0acf21421cda214bdf877c8c030e556 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 9 Jan 2013 16:43:08 +0200 Subject: HID: i2c-hid: add ACPI support The HID over I2C protocol specification states that when the device is enumerated from ACPI the HID descriptor address can be obtained by executing "_DSM" for the device with function 1. Enable this. Signed-off-by: Mika Westerberg Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid.c | 87 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 9ef22244..9e46e42 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -139,6 +140,8 @@ struct i2c_hid { unsigned long flags; /* device flags */ wait_queue_head_t wait; /* For waiting the interrupt */ + + struct i2c_hid_platform_data pdata; }; static int __i2c_hid_command(struct i2c_client *client, @@ -810,6 +813,70 @@ static int __devinit i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) return 0; } +#ifdef CONFIG_ACPI +static int i2c_hid_acpi_pdata(struct i2c_client *client, + struct i2c_hid_platform_data *pdata) +{ + static u8 i2c_hid_guid[] = { + 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, + 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, + }; + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object params[4], *obj; + struct acpi_object_list input; + struct acpi_device *adev; + acpi_handle handle; + + handle = ACPI_HANDLE(&client->dev); + if (!handle || acpi_bus_get_device(handle, &adev)) + return -ENODEV; + + input.count = ARRAY_SIZE(params); + input.pointer = params; + + params[0].type = ACPI_TYPE_BUFFER; + params[0].buffer.length = sizeof(i2c_hid_guid); + params[0].buffer.pointer = i2c_hid_guid; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = 1; + params[2].type = ACPI_TYPE_INTEGER; + params[2].integer.value = 1; /* HID function */ + params[3].type = ACPI_TYPE_INTEGER; + params[3].integer.value = 0; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) { + dev_err(&client->dev, "device _DSM execution failed\n"); + return -ENODEV; + } + + obj = (union acpi_object *)buf.pointer; + if (obj->type != ACPI_TYPE_INTEGER) { + dev_err(&client->dev, "device _DSM returned invalid type: %d\n", + obj->type); + kfree(buf.pointer); + return -EINVAL; + } + + pdata->hid_descriptor_address = obj->integer.value; + + kfree(buf.pointer); + return 0; +} + +static const struct acpi_device_id i2c_hid_acpi_match[] = { + {"ACPI0C50", 0 }, + {"PNP0C50", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match); +#else +static inline int i2c_hid_acpi_pdata(struct i2c_client *client, + struct i2c_hid_platform_data *pdata) +{ + return -ENODEV; +} +#endif + static int __devinit i2c_hid_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) { @@ -821,11 +888,6 @@ static int __devinit i2c_hid_probe(struct i2c_client *client, dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); - if (!platform_data) { - dev_err(&client->dev, "HID register address not provided\n"); - return -EINVAL; - } - if (!client->irq) { dev_err(&client->dev, "HID over i2c has not been provided an Int IRQ\n"); @@ -836,11 +898,22 @@ static int __devinit i2c_hid_probe(struct i2c_client *client, if (!ihid) return -ENOMEM; + if (!platform_data) { + ret = i2c_hid_acpi_pdata(client, &ihid->pdata); + if (ret) { + dev_err(&client->dev, + "HID register address not provided\n"); + goto err; + } + } else { + ihid->pdata = *platform_data; + } + i2c_set_clientdata(client, ihid); ihid->client = client; - hidRegister = platform_data->hid_descriptor_address; + hidRegister = ihid->pdata.hid_descriptor_address; ihid->wHIDDescRegister = cpu_to_le16(hidRegister); init_waitqueue_head(&ihid->wait); @@ -873,6 +946,7 @@ static int __devinit i2c_hid_probe(struct i2c_client *client, hid->hid_get_raw_report = i2c_hid_get_raw_report; hid->hid_output_raw_report = i2c_hid_output_raw_report; hid->dev.parent = &client->dev; + ACPI_HANDLE_SET(&hid->dev, ACPI_HANDLE(&client->dev)); hid->bus = BUS_I2C; hid->version = le16_to_cpu(ihid->hdesc.bcdVersion); hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID); @@ -964,6 +1038,7 @@ static struct i2c_driver i2c_hid_driver = { .name = "i2c_hid", .owner = THIS_MODULE, .pm = &i2c_hid_pm, + .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match), }, .probe = i2c_hid_probe, -- cgit v1.1 From 99d249021abd4341771523ed8dd7946276103432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Luis=20V=C3=A1zquez=20Cao?= Date: Tue, 22 Jan 2013 15:20:38 +0900 Subject: HID: clean up quirk for Sony RF receivers Document what the fix-up is does and make it more robust by ensuring that it is only applied to the USB interface that corresponds to the mouse (sony_report_fixup() is called once per interface during probing). Cc: linux-input@vger.kernel.org Cc: linux-usb@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Fernando Luis Vazquez Cao Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 6d2d459..9769c00 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -65,9 +65,19 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, { struct sony_sc *sc = hid_get_drvdata(hdev); - if ((sc->quirks & VAIO_RDESC_CONSTANT) && - *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { + /* + * Some Sony RF receivers wrongly declare the mouse pointer as a + * a constant non-data variable. + */ + if ((sc->quirks & VAIO_RDESC_CONSTANT) && *rsize >= 56 && + /* usage page: generic desktop controls */ + /* rdesc[0] == 0x05 && rdesc[1] == 0x01 && */ + /* usage: mouse */ + rdesc[2] == 0x09 && rdesc[3] == 0x02 && + /* input (usage page for x,y axes): constant, variable, relative */ + rdesc[54] == 0x81 && rdesc[55] == 0x07) { hid_info(hdev, "Fixing up Sony RF Receiver report descriptor\n"); + /* input: data, variable, relative */ rdesc[55] = 0x06; } -- cgit v1.1 From 75dbb9530f73da521b871ba3c4bd32f301a62635 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Thu, 31 Jan 2013 08:07:07 -0700 Subject: USB: HID: SRW-S1 Gaming Wheel Driver Add support the SRW-S1 by patching HID descriptor to read axis as Generic Desktop X, Y and Z (rather than Usage page being 'Simulation'). Signed-off-by: Simon Wood Tested-by: John Murphy Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 ++++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 ++ drivers/hid/hid-steelseries-srws1.c | 58 +++++++++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+) create mode 100644 drivers/hid/hid-steelseries-srws1.c (limited to 'drivers/hid') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index e7d6a13..37df92f 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -596,6 +596,12 @@ config HID_SPEEDLINK ---help--- Support for Speedlink Vicious and Divine Cezanne mouse. +config HID_STEELSERIES_SRWS1 + tristate "Steelseries SRW-S1 steering wheel support" + depends on USB_HID + ---help--- + Support for Steelseries SRW-S1 steering wheel + config HID_SUNPLUS tristate "Sunplus wireless desktop" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index b622157..bbebe0a 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o +obj-$(CONFIG_HID_STEELSERIES_SRWS1) += hid-steelseries-srws1.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index eb2ee11..65cda7f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1697,6 +1697,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4dfa605..f5976f3 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -723,6 +723,9 @@ #define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403 #define USB_DEVICE_ID_MTP_SITRONIX 0x5001 +#define USB_VENDOR_ID_STEELSERIES 0x1038 +#define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410 + #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c new file mode 100644 index 0000000..161917c --- /dev/null +++ b/drivers/hid/hid-steelseries-srws1.c @@ -0,0 +1,58 @@ +/* + * HID driver for Steelseries SRW-S1 + * + * Copyright (c) 2013 Simon Wood + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include + +#include "hid-ids.h" + +static __u8 *steelseries_srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + if (*rsize >= 115 && rdesc[11] == 0x02 && rdesc[13] == 0xc8 + && rdesc[29] == 0xbb && rdesc[40] == 0xc5) { + hid_info(hdev, "Fixing up Steelseries SRW-S1 report descriptor\n"); + rdesc[11] = 0x01; + rdesc[13] = 0x30; + rdesc[29] = 0x31; + rdesc[40] = 0x32; + } + return rdesc; +} + +static const struct hid_device_id steelseries_srws1_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, + { } +}; +MODULE_DEVICE_TABLE(hid, steelseries_srws1_devices); + +static struct hid_driver steelseries_srws1_driver = { + .name = "steelseries_srws1", + .id_table = steelseries_srws1_devices, + .report_fixup = steelseries_srws1_report_fixup +}; + +static int __init steelseries_srws1_init(void) +{ + return hid_register_driver(&steelseries_srws1_driver); +} + +static void __exit steelseries_srws1_exit(void) +{ + hid_unregister_driver(&steelseries_srws1_driver); +} + +module_init(steelseries_srws1_init); +module_exit(steelseries_srws1_exit); +MODULE_LICENSE("GPL"); -- cgit v1.1 From 5492606dc39b2f1ce67cf718f09ade373a35f4eb Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Thu, 31 Jan 2013 08:07:08 -0700 Subject: USB: HID: Steelseries SRW-S1 Add support for dials This patch to the SRW-S1 driver re-writes the HID descriptor to insert a section for the 3 dials on the device, previously these were contained within a 'Manufacturer Specific' usage page. Signed-off-by: Simon Wood Tested-by: John Murphy Signed-off-by: Jiri Kosina --- drivers/hid/hid-steelseries-srws1.c | 86 +++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c index 161917c..e95434d 100644 --- a/drivers/hid/hid-steelseries-srws1.c +++ b/drivers/hid/hid-steelseries-srws1.c @@ -17,16 +17,94 @@ #include "hid-ids.h" +/* Fixed report descriptor for Steelseries SRW-S1 wheel controller + * + * The original descriptor hides the sensitivity and assists dials + * a custom vendor usage page. This inserts a patch to make them + * appear in the 'Generic Desktop' usage. + */ + +static __u8 steelseries_srws1_rdesc_fixed[] = { +0x05, 0x01, /* Usage Page (Desktop) */ +0x09, 0x08, /* Usage (MultiAxis), Changed */ +0xA1, 0x01, /* Collection (Application), */ +0xA1, 0x02, /* Collection (Logical), */ +0x95, 0x01, /* Report Count (1), */ +0x05, 0x01, /* Changed Usage Page (Desktop), */ +0x09, 0x30, /* Changed Usage (X), */ +0x16, 0xF8, 0xF8, /* Logical Minimum (-1800), */ +0x26, 0x08, 0x07, /* Logical Maximum (1800), */ +0x65, 0x14, /* Unit (Degrees), */ +0x55, 0x0F, /* Unit Exponent (15), */ +0x75, 0x10, /* Report Size (16), */ +0x81, 0x02, /* Input (Variable), */ +0x09, 0x31, /* Changed Usage (Y), */ +0x15, 0x00, /* Logical Minimum (0), */ +0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ +0x75, 0x0C, /* Report Size (12), */ +0x81, 0x02, /* Input (Variable), */ +0x09, 0x32, /* Changed Usage (Z), */ +0x15, 0x00, /* Logical Minimum (0), */ +0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ +0x75, 0x0C, /* Report Size (12), */ +0x81, 0x02, /* Input (Variable), */ +0x05, 0x01, /* Usage Page (Desktop), */ +0x09, 0x39, /* Usage (Hat Switch), */ +0x25, 0x07, /* Logical Maximum (7), */ +0x35, 0x00, /* Physical Minimum (0), */ +0x46, 0x3B, 0x01, /* Physical Maximum (315), */ +0x65, 0x14, /* Unit (Degrees), */ +0x75, 0x04, /* Report Size (4), */ +0x95, 0x01, /* Report Count (1), */ +0x81, 0x02, /* Input (Variable), */ +0x25, 0x01, /* Logical Maximum (1), */ +0x45, 0x01, /* Physical Maximum (1), */ +0x65, 0x00, /* Unit, */ +0x75, 0x01, /* Report Size (1), */ +0x95, 0x03, /* Report Count (3), */ +0x81, 0x01, /* Input (Constant), */ +0x05, 0x09, /* Usage Page (Button), */ +0x19, 0x01, /* Usage Minimum (01h), */ +0x29, 0x11, /* Usage Maximum (11h), */ +0x95, 0x11, /* Report Count (17), */ +0x81, 0x02, /* Input (Variable), */ + /* ---- Dial patch starts here ---- */ +0x05, 0x01, /* Usage Page (Desktop), */ +0x09, 0x33, /* Usage (RX), */ +0x75, 0x04, /* Report Size (4), */ +0x95, 0x02, /* Report Count (2), */ +0x15, 0x00, /* Logical Minimum (0), */ +0x25, 0x0b, /* Logical Maximum (b), */ +0x81, 0x02, /* Input (Variable), */ +0x09, 0x35, /* Usage (RZ), */ +0x75, 0x04, /* Report Size (4), */ +0x95, 0x01, /* Report Count (1), */ +0x25, 0x03, /* Logical Maximum (3), */ +0x81, 0x02, /* Input (Variable), */ + /* ---- Dial patch ends here ---- */ +0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ +0x09, 0x01, /* Usage (01h), */ +0x75, 0x04, /* Changed Report Size (4), */ +0x95, 0x0D, /* Changed Report Count (13), */ +0x81, 0x02, /* Input (Variable), */ +0xC0, /* End Collection, */ +0xA1, 0x02, /* Collection (Logical), */ +0x09, 0x02, /* Usage (02h), */ +0x75, 0x08, /* Report Size (8), */ +0x95, 0x10, /* Report Count (16), */ +0x91, 0x02, /* Output (Variable), */ +0xC0, /* End Collection, */ +0xC0 /* End Collection */ +}; + static __u8 *steelseries_srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { if (*rsize >= 115 && rdesc[11] == 0x02 && rdesc[13] == 0xc8 && rdesc[29] == 0xbb && rdesc[40] == 0xc5) { hid_info(hdev, "Fixing up Steelseries SRW-S1 report descriptor\n"); - rdesc[11] = 0x01; - rdesc[13] = 0x30; - rdesc[29] = 0x31; - rdesc[40] = 0x32; + rdesc = steelseries_srws1_rdesc_fixed; + *rsize = sizeof(steelseries_srws1_rdesc_fixed); } return rdesc; } -- cgit v1.1 From 2e2daff3a51f2d10155b03f461f4e29eaf80dcbd Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Thu, 31 Jan 2013 08:07:09 -0700 Subject: USB: HID: Steelseries SRW-S1 Add support for LEDs This patch to the SRW-S1 driver adds support for the LED RPM meter on the front of the device. The LEDs are controlled via /sys/class/leds interface, with an individual control for each of the 15 LEDs. Signed-off-by: Simon Wood Tested-by: John Murphy Signed-off-by: Jiri Kosina --- drivers/hid/hid-steelseries-srws1.c | 199 ++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c index e95434d..a7386699 100644 --- a/drivers/hid/hid-steelseries-srws1.c +++ b/drivers/hid/hid-steelseries-srws1.c @@ -12,11 +12,21 @@ */ #include +#include #include #include +#include "usbhid/usbhid.h" #include "hid-ids.h" +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +#define SRWS1_NUMBER_LEDS 15 +struct steelseries_srws1_data { + __u16 led_state; + struct led_classdev *led[SRWS1_NUMBER_LEDS]; +}; +#endif + /* Fixed report descriptor for Steelseries SRW-S1 wheel controller * * The original descriptor hides the sensitivity and assists dials @@ -97,6 +107,191 @@ static __u8 steelseries_srws1_rdesc_fixed[] = { 0xC0 /* End Collection */ }; +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds) +{ + struct list_head *report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + __s32 *value = report->field[0]->value; + + value[0] = 0x40; + value[1] = leds & 0xFF; + value[2] = leds >> 8; + value[3] = 0x00; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; + value[7] = 0x00; + value[8] = 0x00; + value[9] = 0x00; + value[10] = 0x00; + value[11] = 0x00; + value[12] = 0x00; + value[13] = 0x00; + value[14] = 0x00; + value[15] = 0x00; + + usbhid_submit_report(hdev, report, USB_DIR_OUT); + + /* Note: LED change does not show on device until the device is read/polled */ +} + +static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid); + int i, state = 0; + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return; + } + + for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { + if (led_cdev != drv_data->led[i]) + continue; + + state = (drv_data->led_state >> i) & 1; + if (value == LED_OFF && state) { + drv_data->led_state &= ~(1 << i); + steelseries_srws1_set_leds(hid, drv_data->led_state); + } else if (value != LED_OFF && !state) { + drv_data->led_state |= 1 << i; + steelseries_srws1_set_leds(hid, drv_data->led_state); + } + break; + } +} + +static enum led_brightness steelseries_srws1_led_get_brightness(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct steelseries_srws1_data *drv_data; + int i, value = 0; + + drv_data = hid_get_drvdata(hid); + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return LED_OFF; + } + + for (i = 0; i < SRWS1_NUMBER_LEDS; i++) + if (led_cdev == drv_data->led[i]) { + value = (drv_data->led_state >> i) & 1; + break; + } + + return value ? LED_FULL : LED_OFF; +} + +static int steelseries_srws1_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret, i; + struct led_classdev *led; + size_t name_sz; + char *name; + + struct steelseries_srws1_data *drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); + + if (drv_data == NULL) { + hid_err(hdev, "can't alloc SRW-S1 memory\n"); + return -ENOMEM; + } + + hid_set_drvdata(hdev, drv_data); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto err_free; + } + + /* register led subsystem */ + drv_data->led_state = 0; + for (i = 0; i < SRWS1_NUMBER_LEDS; i++) + drv_data->led[i] = NULL; + + steelseries_srws1_set_leds(hdev, 0); + + name_sz = strlen(hdev->uniq) + 15; + + for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { + led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); + if (!led) { + hid_err(hdev, "can't allocate memory for LED %d\n", i); + goto err_led; + } + + name = (void *)(&led[1]); + snprintf(name, name_sz, "SRWS1::%s::RPM%d", hdev->uniq, i+1); + led->name = name; + led->brightness = 0; + led->max_brightness = 1; + led->brightness_get = steelseries_srws1_led_get_brightness; + led->brightness_set = steelseries_srws1_led_set_brightness; + + drv_data->led[i] = led; + ret = led_classdev_register(&hdev->dev, led); + + if (ret) { + hid_err(hdev, "failed to register LED %d. Aborting.\n", i); +err_led: + /* Deregister all LEDs (if any) */ + for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { + led = drv_data->led[i]; + drv_data->led[i] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + goto out; /* but let the driver continue without LEDs */ + } + } +out: + return 0; +err_free: + kfree(drv_data); + return ret; +} + +static void steelseries_srws1_remove(struct hid_device *hdev) +{ + int i; + struct led_classdev *led; + + struct steelseries_srws1_data *drv_data = hid_get_drvdata(hdev); + + if (drv_data) { + /* Deregister LEDs (if any) */ + for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { + led = drv_data->led[i]; + drv_data->led[i] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + + } + + hid_hw_stop(hdev); + kfree(drv_data); + return; +} +#endif + static __u8 *steelseries_srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { @@ -118,6 +313,10 @@ MODULE_DEVICE_TABLE(hid, steelseries_srws1_devices); static struct hid_driver steelseries_srws1_driver = { .name = "steelseries_srws1", .id_table = steelseries_srws1_devices, +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) + .probe = steelseries_srws1_probe, + .remove = steelseries_srws1_remove, +#endif .report_fixup = steelseries_srws1_report_fixup }; -- cgit v1.1 From e25d780581dc4d261c66e072a59c34782bd03e0a Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Thu, 31 Jan 2013 08:07:10 -0700 Subject: USB: HID: Steelseries SRW-S1 Add support controlling all LEDs simultaneously This patch to the SRW-S1 driver adds the ability to control all LEDs simultaneously as testing showed that it was slow (noticably!!) when seting or clearing all the LEDs in turn. It adds a 'RPMALL' LED, whose behavoir is asserted to all the LEDs in the bar graph, individual LEDs can subsequently be turned on/off individually. Signed-off-by: Simon Wood Tested-by: John Murphy Signed-off-by: Jiri Kosina --- drivers/hid/hid-steelseries-srws1.c | 65 ++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c index a7386699..365bc9e 100644 --- a/drivers/hid/hid-steelseries-srws1.c +++ b/drivers/hid/hid-steelseries-srws1.c @@ -136,6 +136,42 @@ static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds) /* Note: LED change does not show on device until the device is read/polled */ } +static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid); + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return; + } + + if (value == LED_OFF) + drv_data->led_state = 0; + else + drv_data->led_state = (1 << (SRWS1_NUMBER_LEDS + 1)) - 1; + + steelseries_srws1_set_leds(hid, drv_data->led_state); +} + +static enum led_brightness steelseries_srws1_led_all_get_brightness(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct steelseries_srws1_data *drv_data; + + drv_data = hid_get_drvdata(hid); + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return LED_OFF; + } + + return (drv_data->led_state >> SRWS1_NUMBER_LEDS) ? LED_FULL : LED_OFF; +} + static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness value) { @@ -219,13 +255,34 @@ static int steelseries_srws1_probe(struct hid_device *hdev, /* register led subsystem */ drv_data->led_state = 0; - for (i = 0; i < SRWS1_NUMBER_LEDS; i++) + for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) drv_data->led[i] = NULL; steelseries_srws1_set_leds(hdev, 0); - name_sz = strlen(hdev->uniq) + 15; + name_sz = strlen(hdev->uniq) + 16; + + /* 'ALL', for setting all LEDs simultaneously */ + led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); + if (!led) { + hid_err(hdev, "can't allocate memory for LED ALL\n"); + goto err_led; + } + + name = (void *)(&led[1]); + snprintf(name, name_sz, "SRWS1::%s::RPMALL", hdev->uniq); + led->name = name; + led->brightness = 0; + led->max_brightness = 1; + led->brightness_get = steelseries_srws1_led_all_get_brightness; + led->brightness_set = steelseries_srws1_led_all_set_brightness; + + drv_data->led[SRWS1_NUMBER_LEDS] = led; + ret = led_classdev_register(&hdev->dev, led); + if (ret) + goto err_led; + /* Each individual LED */ for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); if (!led) { @@ -248,7 +305,7 @@ static int steelseries_srws1_probe(struct hid_device *hdev, hid_err(hdev, "failed to register LED %d. Aborting.\n", i); err_led: /* Deregister all LEDs (if any) */ - for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { + for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { led = drv_data->led[i]; drv_data->led[i] = NULL; if (!led) @@ -275,7 +332,7 @@ static void steelseries_srws1_remove(struct hid_device *hdev) if (drv_data) { /* Deregister LEDs (if any) */ - for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { + for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { led = drv_data->led[i]; drv_data->led[i] = NULL; if (!led) -- cgit v1.1 From 090800c2a3f746572ef142e2d5404922a599e841 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 31 Jan 2013 16:50:24 +0100 Subject: HID: steelseries: rename driver to be compliant with other drivers We usually group drivers on a per-vendor basis, implementing device-specific deviations from the standard in vendor-specific driver. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 +- drivers/hid/Makefile | 2 +- drivers/hid/hid-steelseries-srws1.c | 392 ------------------------------------ drivers/hid/hid-steelseries.c | 392 ++++++++++++++++++++++++++++++++++++ 4 files changed, 394 insertions(+), 394 deletions(-) delete mode 100644 drivers/hid/hid-steelseries-srws1.c create mode 100644 drivers/hid/hid-steelseries.c (limited to 'drivers/hid') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 37df92f..6d5d266 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -596,7 +596,7 @@ config HID_SPEEDLINK ---help--- Support for Speedlink Vicious and Divine Cezanne mouse. -config HID_STEELSERIES_SRWS1 +config HID_STEELSERIES tristate "Steelseries SRW-S1 steering wheel support" depends on USB_HID ---help--- diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index bbebe0a..247f2b8 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -101,7 +101,7 @@ obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o -obj-$(CONFIG_HID_STEELSERIES_SRWS1) += hid-steelseries-srws1.o +obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c deleted file mode 100644 index 365bc9e..0000000 --- a/drivers/hid/hid-steelseries-srws1.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * HID driver for Steelseries SRW-S1 - * - * Copyright (c) 2013 Simon Wood - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#include -#include -#include -#include - -#include "usbhid/usbhid.h" -#include "hid-ids.h" - -#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) -#define SRWS1_NUMBER_LEDS 15 -struct steelseries_srws1_data { - __u16 led_state; - struct led_classdev *led[SRWS1_NUMBER_LEDS]; -}; -#endif - -/* Fixed report descriptor for Steelseries SRW-S1 wheel controller - * - * The original descriptor hides the sensitivity and assists dials - * a custom vendor usage page. This inserts a patch to make them - * appear in the 'Generic Desktop' usage. - */ - -static __u8 steelseries_srws1_rdesc_fixed[] = { -0x05, 0x01, /* Usage Page (Desktop) */ -0x09, 0x08, /* Usage (MultiAxis), Changed */ -0xA1, 0x01, /* Collection (Application), */ -0xA1, 0x02, /* Collection (Logical), */ -0x95, 0x01, /* Report Count (1), */ -0x05, 0x01, /* Changed Usage Page (Desktop), */ -0x09, 0x30, /* Changed Usage (X), */ -0x16, 0xF8, 0xF8, /* Logical Minimum (-1800), */ -0x26, 0x08, 0x07, /* Logical Maximum (1800), */ -0x65, 0x14, /* Unit (Degrees), */ -0x55, 0x0F, /* Unit Exponent (15), */ -0x75, 0x10, /* Report Size (16), */ -0x81, 0x02, /* Input (Variable), */ -0x09, 0x31, /* Changed Usage (Y), */ -0x15, 0x00, /* Logical Minimum (0), */ -0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ -0x75, 0x0C, /* Report Size (12), */ -0x81, 0x02, /* Input (Variable), */ -0x09, 0x32, /* Changed Usage (Z), */ -0x15, 0x00, /* Logical Minimum (0), */ -0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ -0x75, 0x0C, /* Report Size (12), */ -0x81, 0x02, /* Input (Variable), */ -0x05, 0x01, /* Usage Page (Desktop), */ -0x09, 0x39, /* Usage (Hat Switch), */ -0x25, 0x07, /* Logical Maximum (7), */ -0x35, 0x00, /* Physical Minimum (0), */ -0x46, 0x3B, 0x01, /* Physical Maximum (315), */ -0x65, 0x14, /* Unit (Degrees), */ -0x75, 0x04, /* Report Size (4), */ -0x95, 0x01, /* Report Count (1), */ -0x81, 0x02, /* Input (Variable), */ -0x25, 0x01, /* Logical Maximum (1), */ -0x45, 0x01, /* Physical Maximum (1), */ -0x65, 0x00, /* Unit, */ -0x75, 0x01, /* Report Size (1), */ -0x95, 0x03, /* Report Count (3), */ -0x81, 0x01, /* Input (Constant), */ -0x05, 0x09, /* Usage Page (Button), */ -0x19, 0x01, /* Usage Minimum (01h), */ -0x29, 0x11, /* Usage Maximum (11h), */ -0x95, 0x11, /* Report Count (17), */ -0x81, 0x02, /* Input (Variable), */ - /* ---- Dial patch starts here ---- */ -0x05, 0x01, /* Usage Page (Desktop), */ -0x09, 0x33, /* Usage (RX), */ -0x75, 0x04, /* Report Size (4), */ -0x95, 0x02, /* Report Count (2), */ -0x15, 0x00, /* Logical Minimum (0), */ -0x25, 0x0b, /* Logical Maximum (b), */ -0x81, 0x02, /* Input (Variable), */ -0x09, 0x35, /* Usage (RZ), */ -0x75, 0x04, /* Report Size (4), */ -0x95, 0x01, /* Report Count (1), */ -0x25, 0x03, /* Logical Maximum (3), */ -0x81, 0x02, /* Input (Variable), */ - /* ---- Dial patch ends here ---- */ -0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ -0x09, 0x01, /* Usage (01h), */ -0x75, 0x04, /* Changed Report Size (4), */ -0x95, 0x0D, /* Changed Report Count (13), */ -0x81, 0x02, /* Input (Variable), */ -0xC0, /* End Collection, */ -0xA1, 0x02, /* Collection (Logical), */ -0x09, 0x02, /* Usage (02h), */ -0x75, 0x08, /* Report Size (8), */ -0x95, 0x10, /* Report Count (16), */ -0x91, 0x02, /* Output (Variable), */ -0xC0, /* End Collection, */ -0xC0 /* End Collection */ -}; - -#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) -static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds) -{ - struct list_head *report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; - - value[0] = 0x40; - value[1] = leds & 0xFF; - value[2] = leds >> 8; - value[3] = 0x00; - value[4] = 0x00; - value[5] = 0x00; - value[6] = 0x00; - value[7] = 0x00; - value[8] = 0x00; - value[9] = 0x00; - value[10] = 0x00; - value[11] = 0x00; - value[12] = 0x00; - value[13] = 0x00; - value[14] = 0x00; - value[15] = 0x00; - - usbhid_submit_report(hdev, report, USB_DIR_OUT); - - /* Note: LED change does not show on device until the device is read/polled */ -} - -static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cdev, - enum led_brightness value) -{ - struct device *dev = led_cdev->dev->parent; - struct hid_device *hid = container_of(dev, struct hid_device, dev); - struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid); - - if (!drv_data) { - hid_err(hid, "Device data not found."); - return; - } - - if (value == LED_OFF) - drv_data->led_state = 0; - else - drv_data->led_state = (1 << (SRWS1_NUMBER_LEDS + 1)) - 1; - - steelseries_srws1_set_leds(hid, drv_data->led_state); -} - -static enum led_brightness steelseries_srws1_led_all_get_brightness(struct led_classdev *led_cdev) -{ - struct device *dev = led_cdev->dev->parent; - struct hid_device *hid = container_of(dev, struct hid_device, dev); - struct steelseries_srws1_data *drv_data; - - drv_data = hid_get_drvdata(hid); - - if (!drv_data) { - hid_err(hid, "Device data not found."); - return LED_OFF; - } - - return (drv_data->led_state >> SRWS1_NUMBER_LEDS) ? LED_FULL : LED_OFF; -} - -static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev, - enum led_brightness value) -{ - struct device *dev = led_cdev->dev->parent; - struct hid_device *hid = container_of(dev, struct hid_device, dev); - struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid); - int i, state = 0; - - if (!drv_data) { - hid_err(hid, "Device data not found."); - return; - } - - for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { - if (led_cdev != drv_data->led[i]) - continue; - - state = (drv_data->led_state >> i) & 1; - if (value == LED_OFF && state) { - drv_data->led_state &= ~(1 << i); - steelseries_srws1_set_leds(hid, drv_data->led_state); - } else if (value != LED_OFF && !state) { - drv_data->led_state |= 1 << i; - steelseries_srws1_set_leds(hid, drv_data->led_state); - } - break; - } -} - -static enum led_brightness steelseries_srws1_led_get_brightness(struct led_classdev *led_cdev) -{ - struct device *dev = led_cdev->dev->parent; - struct hid_device *hid = container_of(dev, struct hid_device, dev); - struct steelseries_srws1_data *drv_data; - int i, value = 0; - - drv_data = hid_get_drvdata(hid); - - if (!drv_data) { - hid_err(hid, "Device data not found."); - return LED_OFF; - } - - for (i = 0; i < SRWS1_NUMBER_LEDS; i++) - if (led_cdev == drv_data->led[i]) { - value = (drv_data->led_state >> i) & 1; - break; - } - - return value ? LED_FULL : LED_OFF; -} - -static int steelseries_srws1_probe(struct hid_device *hdev, - const struct hid_device_id *id) -{ - int ret, i; - struct led_classdev *led; - size_t name_sz; - char *name; - - struct steelseries_srws1_data *drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); - - if (drv_data == NULL) { - hid_err(hdev, "can't alloc SRW-S1 memory\n"); - return -ENOMEM; - } - - hid_set_drvdata(hdev, drv_data); - - ret = hid_parse(hdev); - if (ret) { - hid_err(hdev, "parse failed\n"); - goto err_free; - } - - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - if (ret) { - hid_err(hdev, "hw start failed\n"); - goto err_free; - } - - /* register led subsystem */ - drv_data->led_state = 0; - for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) - drv_data->led[i] = NULL; - - steelseries_srws1_set_leds(hdev, 0); - - name_sz = strlen(hdev->uniq) + 16; - - /* 'ALL', for setting all LEDs simultaneously */ - led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); - if (!led) { - hid_err(hdev, "can't allocate memory for LED ALL\n"); - goto err_led; - } - - name = (void *)(&led[1]); - snprintf(name, name_sz, "SRWS1::%s::RPMALL", hdev->uniq); - led->name = name; - led->brightness = 0; - led->max_brightness = 1; - led->brightness_get = steelseries_srws1_led_all_get_brightness; - led->brightness_set = steelseries_srws1_led_all_set_brightness; - - drv_data->led[SRWS1_NUMBER_LEDS] = led; - ret = led_classdev_register(&hdev->dev, led); - if (ret) - goto err_led; - - /* Each individual LED */ - for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { - led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); - if (!led) { - hid_err(hdev, "can't allocate memory for LED %d\n", i); - goto err_led; - } - - name = (void *)(&led[1]); - snprintf(name, name_sz, "SRWS1::%s::RPM%d", hdev->uniq, i+1); - led->name = name; - led->brightness = 0; - led->max_brightness = 1; - led->brightness_get = steelseries_srws1_led_get_brightness; - led->brightness_set = steelseries_srws1_led_set_brightness; - - drv_data->led[i] = led; - ret = led_classdev_register(&hdev->dev, led); - - if (ret) { - hid_err(hdev, "failed to register LED %d. Aborting.\n", i); -err_led: - /* Deregister all LEDs (if any) */ - for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { - led = drv_data->led[i]; - drv_data->led[i] = NULL; - if (!led) - continue; - led_classdev_unregister(led); - kfree(led); - } - goto out; /* but let the driver continue without LEDs */ - } - } -out: - return 0; -err_free: - kfree(drv_data); - return ret; -} - -static void steelseries_srws1_remove(struct hid_device *hdev) -{ - int i; - struct led_classdev *led; - - struct steelseries_srws1_data *drv_data = hid_get_drvdata(hdev); - - if (drv_data) { - /* Deregister LEDs (if any) */ - for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { - led = drv_data->led[i]; - drv_data->led[i] = NULL; - if (!led) - continue; - led_classdev_unregister(led); - kfree(led); - } - - } - - hid_hw_stop(hdev); - kfree(drv_data); - return; -} -#endif - -static __u8 *steelseries_srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc, - unsigned int *rsize) -{ - if (*rsize >= 115 && rdesc[11] == 0x02 && rdesc[13] == 0xc8 - && rdesc[29] == 0xbb && rdesc[40] == 0xc5) { - hid_info(hdev, "Fixing up Steelseries SRW-S1 report descriptor\n"); - rdesc = steelseries_srws1_rdesc_fixed; - *rsize = sizeof(steelseries_srws1_rdesc_fixed); - } - return rdesc; -} - -static const struct hid_device_id steelseries_srws1_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, - { } -}; -MODULE_DEVICE_TABLE(hid, steelseries_srws1_devices); - -static struct hid_driver steelseries_srws1_driver = { - .name = "steelseries_srws1", - .id_table = steelseries_srws1_devices, -#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) - .probe = steelseries_srws1_probe, - .remove = steelseries_srws1_remove, -#endif - .report_fixup = steelseries_srws1_report_fixup -}; - -static int __init steelseries_srws1_init(void) -{ - return hid_register_driver(&steelseries_srws1_driver); -} - -static void __exit steelseries_srws1_exit(void) -{ - hid_unregister_driver(&steelseries_srws1_driver); -} - -module_init(steelseries_srws1_init); -module_exit(steelseries_srws1_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c new file mode 100644 index 0000000..365bc9e --- /dev/null +++ b/drivers/hid/hid-steelseries.c @@ -0,0 +1,392 @@ +/* + * HID driver for Steelseries SRW-S1 + * + * Copyright (c) 2013 Simon Wood + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include + +#include "usbhid/usbhid.h" +#include "hid-ids.h" + +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +#define SRWS1_NUMBER_LEDS 15 +struct steelseries_srws1_data { + __u16 led_state; + struct led_classdev *led[SRWS1_NUMBER_LEDS]; +}; +#endif + +/* Fixed report descriptor for Steelseries SRW-S1 wheel controller + * + * The original descriptor hides the sensitivity and assists dials + * a custom vendor usage page. This inserts a patch to make them + * appear in the 'Generic Desktop' usage. + */ + +static __u8 steelseries_srws1_rdesc_fixed[] = { +0x05, 0x01, /* Usage Page (Desktop) */ +0x09, 0x08, /* Usage (MultiAxis), Changed */ +0xA1, 0x01, /* Collection (Application), */ +0xA1, 0x02, /* Collection (Logical), */ +0x95, 0x01, /* Report Count (1), */ +0x05, 0x01, /* Changed Usage Page (Desktop), */ +0x09, 0x30, /* Changed Usage (X), */ +0x16, 0xF8, 0xF8, /* Logical Minimum (-1800), */ +0x26, 0x08, 0x07, /* Logical Maximum (1800), */ +0x65, 0x14, /* Unit (Degrees), */ +0x55, 0x0F, /* Unit Exponent (15), */ +0x75, 0x10, /* Report Size (16), */ +0x81, 0x02, /* Input (Variable), */ +0x09, 0x31, /* Changed Usage (Y), */ +0x15, 0x00, /* Logical Minimum (0), */ +0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ +0x75, 0x0C, /* Report Size (12), */ +0x81, 0x02, /* Input (Variable), */ +0x09, 0x32, /* Changed Usage (Z), */ +0x15, 0x00, /* Logical Minimum (0), */ +0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ +0x75, 0x0C, /* Report Size (12), */ +0x81, 0x02, /* Input (Variable), */ +0x05, 0x01, /* Usage Page (Desktop), */ +0x09, 0x39, /* Usage (Hat Switch), */ +0x25, 0x07, /* Logical Maximum (7), */ +0x35, 0x00, /* Physical Minimum (0), */ +0x46, 0x3B, 0x01, /* Physical Maximum (315), */ +0x65, 0x14, /* Unit (Degrees), */ +0x75, 0x04, /* Report Size (4), */ +0x95, 0x01, /* Report Count (1), */ +0x81, 0x02, /* Input (Variable), */ +0x25, 0x01, /* Logical Maximum (1), */ +0x45, 0x01, /* Physical Maximum (1), */ +0x65, 0x00, /* Unit, */ +0x75, 0x01, /* Report Size (1), */ +0x95, 0x03, /* Report Count (3), */ +0x81, 0x01, /* Input (Constant), */ +0x05, 0x09, /* Usage Page (Button), */ +0x19, 0x01, /* Usage Minimum (01h), */ +0x29, 0x11, /* Usage Maximum (11h), */ +0x95, 0x11, /* Report Count (17), */ +0x81, 0x02, /* Input (Variable), */ + /* ---- Dial patch starts here ---- */ +0x05, 0x01, /* Usage Page (Desktop), */ +0x09, 0x33, /* Usage (RX), */ +0x75, 0x04, /* Report Size (4), */ +0x95, 0x02, /* Report Count (2), */ +0x15, 0x00, /* Logical Minimum (0), */ +0x25, 0x0b, /* Logical Maximum (b), */ +0x81, 0x02, /* Input (Variable), */ +0x09, 0x35, /* Usage (RZ), */ +0x75, 0x04, /* Report Size (4), */ +0x95, 0x01, /* Report Count (1), */ +0x25, 0x03, /* Logical Maximum (3), */ +0x81, 0x02, /* Input (Variable), */ + /* ---- Dial patch ends here ---- */ +0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ +0x09, 0x01, /* Usage (01h), */ +0x75, 0x04, /* Changed Report Size (4), */ +0x95, 0x0D, /* Changed Report Count (13), */ +0x81, 0x02, /* Input (Variable), */ +0xC0, /* End Collection, */ +0xA1, 0x02, /* Collection (Logical), */ +0x09, 0x02, /* Usage (02h), */ +0x75, 0x08, /* Report Size (8), */ +0x95, 0x10, /* Report Count (16), */ +0x91, 0x02, /* Output (Variable), */ +0xC0, /* End Collection, */ +0xC0 /* End Collection */ +}; + +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds) +{ + struct list_head *report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + __s32 *value = report->field[0]->value; + + value[0] = 0x40; + value[1] = leds & 0xFF; + value[2] = leds >> 8; + value[3] = 0x00; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; + value[7] = 0x00; + value[8] = 0x00; + value[9] = 0x00; + value[10] = 0x00; + value[11] = 0x00; + value[12] = 0x00; + value[13] = 0x00; + value[14] = 0x00; + value[15] = 0x00; + + usbhid_submit_report(hdev, report, USB_DIR_OUT); + + /* Note: LED change does not show on device until the device is read/polled */ +} + +static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid); + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return; + } + + if (value == LED_OFF) + drv_data->led_state = 0; + else + drv_data->led_state = (1 << (SRWS1_NUMBER_LEDS + 1)) - 1; + + steelseries_srws1_set_leds(hid, drv_data->led_state); +} + +static enum led_brightness steelseries_srws1_led_all_get_brightness(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct steelseries_srws1_data *drv_data; + + drv_data = hid_get_drvdata(hid); + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return LED_OFF; + } + + return (drv_data->led_state >> SRWS1_NUMBER_LEDS) ? LED_FULL : LED_OFF; +} + +static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid); + int i, state = 0; + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return; + } + + for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { + if (led_cdev != drv_data->led[i]) + continue; + + state = (drv_data->led_state >> i) & 1; + if (value == LED_OFF && state) { + drv_data->led_state &= ~(1 << i); + steelseries_srws1_set_leds(hid, drv_data->led_state); + } else if (value != LED_OFF && !state) { + drv_data->led_state |= 1 << i; + steelseries_srws1_set_leds(hid, drv_data->led_state); + } + break; + } +} + +static enum led_brightness steelseries_srws1_led_get_brightness(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct steelseries_srws1_data *drv_data; + int i, value = 0; + + drv_data = hid_get_drvdata(hid); + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return LED_OFF; + } + + for (i = 0; i < SRWS1_NUMBER_LEDS; i++) + if (led_cdev == drv_data->led[i]) { + value = (drv_data->led_state >> i) & 1; + break; + } + + return value ? LED_FULL : LED_OFF; +} + +static int steelseries_srws1_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret, i; + struct led_classdev *led; + size_t name_sz; + char *name; + + struct steelseries_srws1_data *drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); + + if (drv_data == NULL) { + hid_err(hdev, "can't alloc SRW-S1 memory\n"); + return -ENOMEM; + } + + hid_set_drvdata(hdev, drv_data); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + goto err_free; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto err_free; + } + + /* register led subsystem */ + drv_data->led_state = 0; + for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) + drv_data->led[i] = NULL; + + steelseries_srws1_set_leds(hdev, 0); + + name_sz = strlen(hdev->uniq) + 16; + + /* 'ALL', for setting all LEDs simultaneously */ + led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); + if (!led) { + hid_err(hdev, "can't allocate memory for LED ALL\n"); + goto err_led; + } + + name = (void *)(&led[1]); + snprintf(name, name_sz, "SRWS1::%s::RPMALL", hdev->uniq); + led->name = name; + led->brightness = 0; + led->max_brightness = 1; + led->brightness_get = steelseries_srws1_led_all_get_brightness; + led->brightness_set = steelseries_srws1_led_all_set_brightness; + + drv_data->led[SRWS1_NUMBER_LEDS] = led; + ret = led_classdev_register(&hdev->dev, led); + if (ret) + goto err_led; + + /* Each individual LED */ + for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { + led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); + if (!led) { + hid_err(hdev, "can't allocate memory for LED %d\n", i); + goto err_led; + } + + name = (void *)(&led[1]); + snprintf(name, name_sz, "SRWS1::%s::RPM%d", hdev->uniq, i+1); + led->name = name; + led->brightness = 0; + led->max_brightness = 1; + led->brightness_get = steelseries_srws1_led_get_brightness; + led->brightness_set = steelseries_srws1_led_set_brightness; + + drv_data->led[i] = led; + ret = led_classdev_register(&hdev->dev, led); + + if (ret) { + hid_err(hdev, "failed to register LED %d. Aborting.\n", i); +err_led: + /* Deregister all LEDs (if any) */ + for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { + led = drv_data->led[i]; + drv_data->led[i] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + goto out; /* but let the driver continue without LEDs */ + } + } +out: + return 0; +err_free: + kfree(drv_data); + return ret; +} + +static void steelseries_srws1_remove(struct hid_device *hdev) +{ + int i; + struct led_classdev *led; + + struct steelseries_srws1_data *drv_data = hid_get_drvdata(hdev); + + if (drv_data) { + /* Deregister LEDs (if any) */ + for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { + led = drv_data->led[i]; + drv_data->led[i] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + + } + + hid_hw_stop(hdev); + kfree(drv_data); + return; +} +#endif + +static __u8 *steelseries_srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + if (*rsize >= 115 && rdesc[11] == 0x02 && rdesc[13] == 0xc8 + && rdesc[29] == 0xbb && rdesc[40] == 0xc5) { + hid_info(hdev, "Fixing up Steelseries SRW-S1 report descriptor\n"); + rdesc = steelseries_srws1_rdesc_fixed; + *rsize = sizeof(steelseries_srws1_rdesc_fixed); + } + return rdesc; +} + +static const struct hid_device_id steelseries_srws1_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, + { } +}; +MODULE_DEVICE_TABLE(hid, steelseries_srws1_devices); + +static struct hid_driver steelseries_srws1_driver = { + .name = "steelseries_srws1", + .id_table = steelseries_srws1_devices, +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) + .probe = steelseries_srws1_probe, + .remove = steelseries_srws1_remove, +#endif + .report_fixup = steelseries_srws1_report_fixup +}; + +static int __init steelseries_srws1_init(void) +{ + return hid_register_driver(&steelseries_srws1_driver); +} + +static void __exit steelseries_srws1_exit(void) +{ + hid_unregister_driver(&steelseries_srws1_driver); +} + +module_init(steelseries_srws1_init); +module_exit(steelseries_srws1_exit); +MODULE_LICENSE("GPL"); -- cgit v1.1 From 7e41576247b782a21c05f7ea8a78a6db119ba789 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 31 Jan 2013 16:51:47 +0100 Subject: HID: steelseries: fix out of bound array access The last field of the driver_data->leds[] array is used to store the special toggle for setting all leds simultaneously, so we need to allocate appropriate number of led_classdev pointers. Signed-off-by: Jiri Kosina --- drivers/hid/hid-steelseries.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c index 365bc9e..2ed995c 100644 --- a/drivers/hid/hid-steelseries.c +++ b/drivers/hid/hid-steelseries.c @@ -23,7 +23,8 @@ #define SRWS1_NUMBER_LEDS 15 struct steelseries_srws1_data { __u16 led_state; - struct led_classdev *led[SRWS1_NUMBER_LEDS]; + /* the last element is used for setting all leds simultaneously */ + struct led_classdev *led[SRWS1_NUMBER_LEDS + 1]; }; #endif -- cgit v1.1 From 6d85d037d6247b06e1060b5e5ad0e4854a7d1e3b Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 31 Jan 2013 17:22:23 +0100 Subject: HID: core: add "report" hook, called once the report has been parsed This callback is called when the parsing of the report has been done by hid-core (so after the calls to .event). The hid drivers can now have access to the whole report by relying on the values stored in the different fields. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index eb2ee11..754098a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1195,6 +1195,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, { struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_report *report; + struct hid_driver *hdrv; unsigned int a; int rsize, csize = size; u8 *cdata = data; @@ -1231,6 +1232,9 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, if (hid->claimed != HID_CLAIMED_HIDRAW) { for (a = 0; a < report->maxfield; a++) hid_input_field(hid, report->field[a], cdata, interrupt); + hdrv = hid->driver; + if (hdrv && hdrv->report) + hdrv->report(hid, report); } if (hid->claimed & HID_CLAIMED_INPUT) -- cgit v1.1 From 55978fa9dc4c57f8249617c35d28c0599de850df Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 31 Jan 2013 17:22:24 +0100 Subject: HID: multitouch: use the callback "report" instead of sequential events Nexio 42" devices requires to rely on the HID field Contact Count to compute the valid values. However, this field is most of the time at the end of the report, meaning that we need to get the all report parsed before processing it. This patch does not introduce functional changes. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 61543c0..13b9461 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -85,6 +85,7 @@ struct mt_device { multitouch fields */ unsigned last_field_index; /* last field index of the report */ unsigned last_slot_field; /* the last field of a slot */ + unsigned mt_report_id; /* the report ID of the multitouch device */ __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ __s8 inputmode_index; /* InputMode HID feature index in the report */ __s8 maxcontact_report_id; /* Maximum Contact Number HID feature, @@ -428,6 +429,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, mt_store_field(usage, td, hi); td->last_field_index = field->index; td->touches_by_report++; + td->mt_report_id = field->report->id; return 1; case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, @@ -578,6 +580,16 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input) static int mt_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { + /* we will handle the hidinput part later, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ struct mt_device *td = hid_get_drvdata(hid); __s32 quirks = td->mtclass.quirks; @@ -635,8 +647,7 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, break; default: - /* fallback to the generic hidinput handling */ - return 0; + return; } if (usage->usage_index + 1 == field->report_count) { @@ -650,12 +661,32 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, } } +} - /* we have handled the hidinput part, now remains hiddev */ - if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) - hid->hiddev_hid_event(hid, field, usage, value); +static void mt_report(struct hid_device *hid, struct hid_report *report) +{ + struct mt_device *td = hid_get_drvdata(hid); + struct hid_field *field; + unsigned count; + int r, n; - return 1; + if (report->id != td->mt_report_id) + return; + + if (!(hid->claimed & HID_CLAIMED_INPUT)) + return; + + for (r = 0; r < report->maxfield; r++) { + field = report->field[r]; + count = field->report_count; + + if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) + continue; + + for (n = 0; n < count; n++) + mt_process_mt_event(hid, field, &field->usage[n], + field->value[n]); + } } static void mt_set_input_mode(struct hid_device *hdev) @@ -1193,6 +1224,7 @@ static struct hid_driver mt_driver = { .feature_mapping = mt_feature_mapping, .usage_table = mt_grabbed_usages, .event = mt_event, + .report = mt_report, #ifdef CONFIG_PM .reset_resume = mt_reset_resume, .resume = mt_resume, -- cgit v1.1 From c2517f62dac608e43b652dc6ed1e478e8447e029 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 31 Jan 2013 17:22:25 +0100 Subject: HID: multitouch: add support for Nexio 42" panel This device is the worst device I saw. It keeps TipSwitch and InRange at 1 for fingers that are not touching the panel. The solution is to rely on the field ContactCount, which is accurate as the correct information are packed at the begining of the frame. Unfortunately, CountactCount is most of the time at the end of the report. The solution is to pick it when we have the whole report in raw_event. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34e2547..8311380 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -597,6 +597,9 @@ #define USB_VENDOR_ID_NEC 0x073e #define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 +#define USB_VENDOR_ID_NEXIO 0x1870 +#define USB_DEVICE_ID_NEXIO_MULTITOUCH_420 0x010d + #define USB_VENDOR_ID_NEXTWINDOW 0x1926 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 13b9461..87690e2 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -54,6 +54,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_NO_AREA (1 << 9) #define MT_QUIRK_IGNORE_DUPLICATES (1 << 10) #define MT_QUIRK_HOVERING (1 << 11) +#define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12) struct mt_slot { __s32 x, y, cx, cy, p, w, h; @@ -83,6 +84,7 @@ struct mt_device { struct mt_class mtclass; /* our mt device class */ struct mt_fields *fields; /* temporary placeholder for storing the multitouch fields */ + __s32 *contactcount; /* contact count value in the report */ unsigned last_field_index; /* last field index of the report */ unsigned last_slot_field; /* the last field of a slot */ unsigned mt_report_id; /* the report ID of the multitouch device */ @@ -112,6 +114,7 @@ struct mt_device { #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 #define MT_CLS_DUAL_NSMU_CONTACTID 0x0008 #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 +#define MT_CLS_ALWAYS_TRUE 0x000a /* vendor specific classes */ #define MT_CLS_3M 0x0101 @@ -171,6 +174,9 @@ static struct mt_class mt_classes[] = { { .name = MT_CLS_INRANGE_CONTACTNUMBER, .quirks = MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_SLOT_IS_CONTACTNUMBER }, + { .name = MT_CLS_ALWAYS_TRUE, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE }, /* * vendor specific classes @@ -251,6 +257,9 @@ static ssize_t mt_set_quirks(struct device *dev, td->mtclass.quirks = val; + if (!td->contactcount) + td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; + return count; } @@ -461,6 +470,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, td->last_field_index = field->index; return 1; case HID_DG_CONTACTCOUNT: + td->contactcount = field->value + usage->usage_index; td->last_field_index = field->index; return 1; case HID_DG_CONTACTMAX: @@ -525,6 +535,10 @@ static int mt_compute_slot(struct mt_device *td, struct input_dev *input) */ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) { + if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) && + td->num_received >= td->num_expected) + return; + if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) { int slotnum = mt_compute_slot(td, input); struct mt_slot *s = &td->curdata; @@ -635,12 +649,6 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, td->curdata.h = value; break; case HID_DG_CONTACTCOUNT: - /* - * Includes multi-packet support where subsequent - * packets are sent with zero contactcount. - */ - if (value) - td->num_expected = value; break; case HID_DG_TOUCH: /* do nothing */ @@ -676,6 +684,13 @@ static void mt_report(struct hid_device *hid, struct hid_report *report) if (!(hid->claimed & HID_CLAIMED_INPUT)) return; + /* + * Includes multi-packet support where subsequent + * packets are sent with zero contactcount. + */ + if (td->contactcount && *td->contactcount) + td->num_expected = *td->contactcount; + for (r = 0; r < report->maxfield; r++) { field = report->field[r]; count = field->report_count; @@ -750,11 +765,15 @@ static void mt_post_parse_default_settings(struct mt_device *td) static void mt_post_parse(struct mt_device *td) { struct mt_fields *f = td->fields; + struct mt_class *cls = &td->mtclass; if (td->touches_by_report > 0) { int field_count_per_touch = f->length / td->touches_by_report; td->last_slot_field = f->usages[field_count_per_touch - 1]; } + + if (!td->contactcount) + cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) @@ -1087,6 +1106,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, + /* Nexio panels */ + { .driver_data = MT_CLS_ALWAYS_TRUE, + MT_USB_DEVICE(USB_VENDOR_ID_NEXIO, + USB_DEVICE_ID_NEXIO_MULTITOUCH_420)}, + /* Panasonic panels */ { .driver_data = MT_CLS_PANASONIC, MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, -- cgit v1.1 From c629dd7eb3b43bb09eecb035f016bdca32dc8acf Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 31 Jan 2013 17:22:26 +0100 Subject: HID: multitouch: fix Win8 protocol for Sharp like devices The Sharp LC-20FE1-W screen (04dd:9681) behaves like the Nexio 42". It may report out of ranges values that are filtered out by relying on the Contact Count HID field. Adding the quirk MT_QUIRK_CONTACT_CNT_ACCURATE makes hid-multitouch strongest against this kind of device, without breaking the current devices. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 87690e2..1cf676d9 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -311,6 +311,7 @@ static void mt_feature_mapping(struct hid_device *hdev, *quirks |= MT_QUIRK_ALWAYS_VALID; *quirks |= MT_QUIRK_IGNORE_DUPLICATES; *quirks |= MT_QUIRK_HOVERING; + *quirks |= MT_QUIRK_CONTACT_CNT_ACCURATE; *quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; *quirks &= ~MT_QUIRK_VALID_IS_INRANGE; *quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; -- cgit v1.1 From e0bb8f9adf1e11cea419c845220d1524a525823b Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 31 Jan 2013 17:22:27 +0100 Subject: HID: multitouch: ensure that serial devices make no use of contact count The serial protocol makes contact count a redondant information, and sometimes it is not reliable (TRS-Star are in this case). Disabling the use of contact count for these devices is thus safer. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 1cf676d9..2693059 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -758,6 +758,7 @@ static void mt_post_parse_default_settings(struct mt_device *td) quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP; quirks &= ~MT_QUIRK_VALID_IS_INRANGE; quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE; + quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } td->mtclass.quirks = quirks; -- cgit v1.1 From 51377fed20461ad857c020b7109efa8207200222 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 31 Jan 2013 17:22:28 +0100 Subject: HID: multitouch: fix protocol for Sitronix 1403:5001 Since the inclusion of this device in hid-multitouch, the device did not forward any events. Using the serial class makes it working again. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 2693059..4ea28de33 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1168,7 +1168,7 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_CONFIDENCE, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM)}, - { .driver_data = MT_CLS_CONFIDENCE, + { .driver_data = MT_CLS_ALWAYS_TRUE, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX)}, -- cgit v1.1 From efc16787cf92de4906adae8e451c10c6189b4ca8 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 31 Jan 2013 17:22:29 +0100 Subject: HID: multitouch: fix protocol for Cando 2087:0a02 Cando 2087:0a02 was broken, this fixes it. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 4ea28de33..e2fc121 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -115,6 +115,7 @@ struct mt_device { #define MT_CLS_DUAL_NSMU_CONTACTID 0x0008 #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 #define MT_CLS_ALWAYS_TRUE 0x000a +#define MT_CLS_DUAL_CONTACT_NUMBER 0x0010 /* vendor specific classes */ #define MT_CLS_3M 0x0101 @@ -177,6 +178,11 @@ static struct mt_class mt_classes[] = { { .name = MT_CLS_ALWAYS_TRUE, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE }, + { .name = MT_CLS_DUAL_CONTACT_NUMBER, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_SLOT_IS_CONTACTNUMBER, + .maxcontacts = 2 }, /* * vendor specific classes @@ -947,7 +953,7 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, MT_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, - { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, + { .driver_data = MT_CLS_DUAL_CONTACT_NUMBER, MT_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, -- cgit v1.1 From e325905c6c28331772dcd3218a690af744a1a564 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 31 Jan 2013 17:22:30 +0100 Subject: HID: multitouch: fix protocol for Elo panels The previous protocol was nearly working, but when several fingers were present on the sensor, those that were not moving were not updated in the next report, introducing a lot of releases. Signed-off-by: Benjamin Tissoires Conflicts: drivers/hid/hid-multitouch.c Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index e2fc121..a3d4f0f 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -116,6 +116,7 @@ struct mt_device { #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 #define MT_CLS_ALWAYS_TRUE 0x000a #define MT_CLS_DUAL_CONTACT_NUMBER 0x0010 +#define MT_CLS_DUAL_CONTACT_ID 0x0011 /* vendor specific classes */ #define MT_CLS_3M 0x0101 @@ -183,6 +184,11 @@ static struct mt_class mt_classes[] = { MT_QUIRK_CONTACT_CNT_ACCURATE | MT_QUIRK_SLOT_IS_CONTACTNUMBER, .maxcontacts = 2 }, + { .name = MT_CLS_DUAL_CONTACT_ID, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_SLOT_IS_CONTACTID, + .maxcontacts = 2 }, /* * vendor specific classes @@ -1040,7 +1046,7 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) }, /* Elo TouchSystems IntelliTouch Plus panel */ - { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, + { .driver_data = MT_CLS_DUAL_CONTACT_ID, MT_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) }, -- cgit v1.1 From dc3e1d8052548f5b46288a1d43c93684f7d64804 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 31 Jan 2013 17:22:31 +0100 Subject: HID: multitouch: make MT_CLS_ALWAYS_TRUE the new default class By running a test on all the traces of the devices I have, I noticed that the class MT_CLS_ALWAYS_TRUE could handle all the devices I've seen so far without any other quirks. I guess this is the behavior Win 7 requires in its driver. We can change the default class then and keep the existing classes for backward compatibility and performances for some of them. Two operations have been done: * replaced MT_CLS_DEFAULT by MT_CLS_NSMU * then replaced MT_CLS_ALWAYS_TRUE by MT_CLS_DEFAULT Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 54 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index a3d4f0f..28af54f 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -114,7 +114,7 @@ struct mt_device { #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 #define MT_CLS_DUAL_NSMU_CONTACTID 0x0008 #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 -#define MT_CLS_ALWAYS_TRUE 0x000a +#define MT_CLS_NSMU 0x000a #define MT_CLS_DUAL_CONTACT_NUMBER 0x0010 #define MT_CLS_DUAL_CONTACT_ID 0x0011 @@ -150,6 +150,9 @@ static int cypress_compute_slot(struct mt_device *td) static struct mt_class mt_classes[] = { { .name = MT_CLS_DEFAULT, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE }, + { .name = MT_CLS_NSMU, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, { .name = MT_CLS_SERIAL, .quirks = MT_QUIRK_ALWAYS_VALID}, @@ -176,9 +179,6 @@ static struct mt_class mt_classes[] = { { .name = MT_CLS_INRANGE_CONTACTNUMBER, .quirks = MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_SLOT_IS_CONTACTNUMBER }, - { .name = MT_CLS_ALWAYS_TRUE, - .quirks = MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE }, { .name = MT_CLS_DUAL_CONTACT_NUMBER, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE | @@ -939,7 +939,7 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_3M3266) }, /* ActionStar panels */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) }, @@ -952,7 +952,7 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, /* Baanto multitouch devices */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2) }, /* Cando panels */ @@ -970,12 +970,12 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, /* Chunghwa Telecom touch panels */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, /* CVTouch panels */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) }, @@ -1064,12 +1064,12 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) }, /* Gametel game controller */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL, USB_DEVICE_ID_GAMETEL_MT_MODE) }, /* GoodTouch panels */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, USB_DEVICE_ID_GOODTOUCH_000f) }, @@ -1087,7 +1087,7 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_IDEACOM_IDC6651) }, /* Ilitek dual touch panel */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) }, @@ -1121,7 +1121,7 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, /* Nexio panels */ - { .driver_data = MT_CLS_ALWAYS_TRUE, + { .driver_data = MT_CLS_DEFAULT, MT_USB_DEVICE(USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_420)}, @@ -1134,7 +1134,7 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_PANABOARD_UBT880) }, /* Novatek Panel */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_PCT) }, @@ -1180,7 +1180,7 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_CONFIDENCE, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM)}, - { .driver_data = MT_CLS_ALWAYS_TRUE, + { .driver_data = MT_CLS_DEFAULT, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX)}, @@ -1190,48 +1190,48 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_TOPSEED2_PERIPAD_701) }, /* Touch International panels */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, /* Unitec panels */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, /* XAT */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XAT, USB_DEVICE_ID_XAT_CSR) }, /* Xiroku */ - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX) }, - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX) }, - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR) }, - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX1) }, - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX1) }, - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR1) }, - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX2) }, - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX2) }, - { .driver_data = MT_CLS_DEFAULT, + { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, -- cgit v1.1 From e7e2b788614c453c72550264bd915ba8923218e8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 6 Feb 2013 17:23:55 +0100 Subject: HID: add missing GENERIC_HARDIRQ dependency HID Sensors framework support (CONFIG_HID_SENSOR_HUB) unconditionally selects MFD_CORE which however depends on GENERIC_HARDIRQS. So add this dependency to HID_SENSOR_HUB as well. Signed-off-by: Heiko Carstens Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index e7d6a13..bf88eca 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -719,7 +719,7 @@ config HID_ZYDACRON config HID_SENSOR_HUB tristate "HID Sensors framework support" - depends on USB_HID + depends on USB_HID && GENERIC_HARDIRQS select MFD_CORE default n -- help--- -- cgit v1.1 From 7e3cc447ff8906558619b1ecc46e4bd776a4f3a6 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 6 Feb 2013 12:10:47 +0100 Subject: HID: multitouch: do not use pointers towards hid-core The previous implementation registered a pointer towards hid-core to the value of contact count. This is not safe and may be difficult to debug if hid-core ever changes its implementation. The use of regular indexes is a better choice. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 28af54f..e22fbd3 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -84,7 +84,8 @@ struct mt_device { struct mt_class mtclass; /* our mt device class */ struct mt_fields *fields; /* temporary placeholder for storing the multitouch fields */ - __s32 *contactcount; /* contact count value in the report */ + int cc_index; /* contact count field index in the report */ + int cc_value_index; /* contact count value index in the field */ unsigned last_field_index; /* last field index of the report */ unsigned last_slot_field; /* the last field of a slot */ unsigned mt_report_id; /* the report ID of the multitouch device */ @@ -269,7 +270,7 @@ static ssize_t mt_set_quirks(struct device *dev, td->mtclass.quirks = val; - if (!td->contactcount) + if (td->cc_index < 0) td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; return count; @@ -483,7 +484,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, td->last_field_index = field->index; return 1; case HID_DG_CONTACTCOUNT: - td->contactcount = field->value + usage->usage_index; + td->cc_index = field->index; + td->cc_value_index = usage->usage_index; td->last_field_index = field->index; return 1; case HID_DG_CONTACTMAX: @@ -701,8 +703,12 @@ static void mt_report(struct hid_device *hid, struct hid_report *report) * Includes multi-packet support where subsequent * packets are sent with zero contactcount. */ - if (td->contactcount && *td->contactcount) - td->num_expected = *td->contactcount; + if (td->cc_index >= 0) { + struct hid_field *field = report->field[td->cc_index]; + int value = field->value[td->cc_value_index]; + if (value) + td->num_expected = value; + } for (r = 0; r < report->maxfield; r++) { field = report->field[r]; @@ -786,7 +792,7 @@ static void mt_post_parse(struct mt_device *td) td->last_slot_field = f->usages[field_count_per_touch - 1]; } - if (!td->contactcount) + if (td->cc_index < 0) cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE; } @@ -845,6 +851,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->mtclass = *mtclass; td->inputmode = -1; td->maxcontact_report_id = -1; + td->cc_index = -1; hid_set_drvdata(hdev, td); td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL); -- cgit v1.1 From 1b474fe82d4eed3c909f02be82586284827c1705 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 8 Feb 2013 15:51:30 +0100 Subject: HID: ntrig: use input_configured() callback to set the name The use of input_configured() allows the ntrig driver to actually change the name of the input and its bitmask before it is added to the input subsystem. Thus, the logs are coherents and udev catch the real bitmask when the device is added. Signed-off-by: Benjamin Tissoires Signed-off-by: Rafi Rubin Signed-off-by: Jiri Kosina --- drivers/hid/hid-ntrig.c | 68 ++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 86a969f..79ab3494 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -858,12 +858,43 @@ not_claimed_input: return 1; } +static void ntrig_input_configured(struct hid_device *hid, + struct hid_input *hidinput) + +{ + struct input_dev *input = hidinput->input; + + if (hidinput->report->maxfield < 1) + return; + + switch (hidinput->report->field[0]->application) { + case HID_DG_PEN: + input->name = "N-Trig Pen"; + break; + case HID_DG_TOUCHSCREEN: + /* These keys are redundant for fingers, clear them + * to prevent incorrect identification */ + __clear_bit(BTN_TOOL_PEN, input->keybit); + __clear_bit(BTN_TOOL_FINGER, input->keybit); + __clear_bit(BTN_0, input->keybit); + __set_bit(BTN_TOOL_DOUBLETAP, input->keybit); + /* + * The physical touchscreen (single touch) + * input has a value for physical, whereas + * the multitouch only has logical input + * fields. + */ + input->name = (hidinput->report->field[0]->physical) ? + "N-Trig Touchscreen" : + "N-Trig MultiTouch"; + break; + } +} + static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; struct ntrig_data *nd; - struct hid_input *hidinput; - struct input_dev *input; struct hid_report *report; if (id->driver_data) @@ -901,38 +932,6 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - - list_for_each_entry(hidinput, &hdev->inputs, list) { - if (hidinput->report->maxfield < 1) - continue; - - input = hidinput->input; - switch (hidinput->report->field[0]->application) { - case HID_DG_PEN: - input->name = "N-Trig Pen"; - break; - case HID_DG_TOUCHSCREEN: - /* These keys are redundant for fingers, clear them - * to prevent incorrect identification */ - __clear_bit(BTN_TOOL_PEN, input->keybit); - __clear_bit(BTN_TOOL_FINGER, input->keybit); - __clear_bit(BTN_0, input->keybit); - __set_bit(BTN_TOOL_DOUBLETAP, input->keybit); - /* - * The physical touchscreen (single touch) - * input has a value for physical, whereas - * the multitouch only has logical input - * fields. - */ - input->name = - (hidinput->report->field[0] - ->physical) ? - "N-Trig Touchscreen" : - "N-Trig MultiTouch"; - break; - } - } - /* This is needed for devices with more recent firmware versions */ report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0x0a]; if (report) { @@ -1023,6 +1022,7 @@ static struct hid_driver ntrig_driver = { .remove = ntrig_remove, .input_mapping = ntrig_input_mapping, .input_mapped = ntrig_input_mapped, + .input_configured = ntrig_input_configured, .usage_table = ntrig_grabbed_usages, .event = ntrig_event, }; -- cgit v1.1 From fa79f5ec534eaae59a7cb2ca208178f03f9b75ec Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 11 Feb 2013 12:31:17 +0200 Subject: HID: extend autodetect to handle I2C sensors as well Since the advent of HID over I2C protocol, it is possible to have sensor hubs behind I2C bus as well. We can autodetect this in a same way than USB sensor hubs. Signed-off-by: Mika Westerberg Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index eb2ee11..fe3a59e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -729,7 +729,7 @@ static int hid_scan_report(struct hid_device *hid) item.type == HID_ITEM_TYPE_MAIN && item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION && (item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL && - hid->bus == BUS_USB) + (hid->bus == BUS_USB || hid->bus == BUS_I2C)) hid->group = HID_GROUP_SENSOR_HUB; } -- cgit v1.1 From 9ef0c5ff0cbdb4eb1f10351091154f3a85b8e9b7 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 11 Feb 2013 12:31:18 +0200 Subject: HID: sensor-hub: get rid of unused sensor_hub_grabbed_usages[] table This table is not used anywhere in the driver so kill it. Signed-off-by: Mika Westerberg Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 0bc58bd..3c55b3d 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -610,11 +610,6 @@ static const struct hid_device_id sensor_hub_devices[] = { }; MODULE_DEVICE_TABLE(hid, sensor_hub_devices); -static const struct hid_usage_id sensor_hub_grabbed_usages[] = { - { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, - { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 } -}; - static struct hid_driver sensor_hub_driver = { .name = "hid-sensor-hub", .id_table = sensor_hub_devices, -- cgit v1.1 From 0d1e4b024f5eff6f3a8927ddfbf6a1a9d6db1a31 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 11 Feb 2013 12:31:19 +0200 Subject: HID: sensor-hub: don't limit the driver only to USB bus We now have two transport mediums: USB and I2C, where sensor hubs can exists. So instead of constraining the driver to only these two we let it to match any HID bus as long as the group is HID_GROUP_SENSOR_HUB. Signed-off-by: Mika Westerberg Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 3c55b3d..7d96db3 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -605,7 +605,8 @@ static void sensor_hub_remove(struct hid_device *hdev) } static const struct hid_device_id sensor_hub_devices[] = { - { HID_DEVICE(BUS_USB, HID_GROUP_SENSOR_HUB, HID_ANY_ID, HID_ANY_ID) }, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, + HID_ANY_ID) }, { } }; MODULE_DEVICE_TABLE(hid, sensor_hub_devices); -- cgit v1.1 From 30b6b7d8d340f41d11eb75e5238d33dbc438fde4 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 13 Feb 2013 13:22:45 +0000 Subject: HID: blacklist Velleman data acquisition boards These are simple data acquistion boards, not HID devices and are handled by the vmk80xx comedi driver. At least one of them (10cf:5500) misidentifies itself as a HID in its USB interface descriptor. Ignore all these devices. Signed-off-by: Ian Abbott Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 8 ++++++++ drivers/hid/hid-ids.h | 6 ++++++ 2 files changed, 14 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index aad2627..bf44af3 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2229,6 +2229,14 @@ bool hid_ignore(struct hid_device *hdev) hdev->type != HID_TYPE_USBMOUSE) return true; break; + case USB_VENDOR_ID_VELLEMAN: + /* These are not HID devices. They are handled by comedi. */ + if ((hdev->product >= USB_DEVICE_ID_VELLEMAN_K8055_FIRST && + hdev->product <= USB_DEVICE_ID_VELLEMAN_K8055_LAST) || + (hdev->product >= USB_DEVICE_ID_VELLEMAN_K8061_FIRST && + hdev->product <= USB_DEVICE_ID_VELLEMAN_K8061_LAST)) + return true; + break; } if (hdev->type == HID_TYPE_USBMOUSE && diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3a49334..1041052 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -794,6 +794,12 @@ #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709 #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19 0x0a19 +#define USB_VENDOR_ID_VELLEMAN 0x10cf +#define USB_DEVICE_ID_VELLEMAN_K8055_FIRST 0x5500 +#define USB_DEVICE_ID_VELLEMAN_K8055_LAST 0x5503 +#define USB_DEVICE_ID_VELLEMAN_K8061_FIRST 0x8061 +#define USB_DEVICE_ID_VELLEMAN_K8061_LAST 0x8068 + #define USB_VENDOR_ID_VERNIER 0x08f7 #define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 #define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 -- cgit v1.1 From 89bdd0c6f38ccf0de43d5a36ede384a730f3394e Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 18 Feb 2013 01:47:15 +0100 Subject: HID: wiimote: fix nunchuck button parser The buttons of the Wii Remote Nunchuck extension are actually active low. Fix the parser to forward the inverted values. The comment in the function always said "0 == pressed" but the implementation was wrong from the beginning. Cc: stable@vger.kernel.org Reported-by: Victor Quicksilver Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-wiimote-ext.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c index 38ae8777..0472191 100644 --- a/drivers/hid/hid-wiimote-ext.c +++ b/drivers/hid/hid-wiimote-ext.c @@ -403,14 +403,14 @@ static void handler_nunchuck(struct wiimote_ext *ext, const __u8 *payload) if (ext->motionp) { input_report_key(ext->input, - wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x04)); + wiiext_keymap[WIIEXT_KEY_Z], !(payload[5] & 0x04)); input_report_key(ext->input, - wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x08)); + wiiext_keymap[WIIEXT_KEY_C], !(payload[5] & 0x08)); } else { input_report_key(ext->input, - wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x01)); + wiiext_keymap[WIIEXT_KEY_Z], !(payload[5] & 0x01)); input_report_key(ext->input, - wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x02)); + wiiext_keymap[WIIEXT_KEY_C], !(payload[5] & 0x02)); } input_sync(ext->input); -- cgit v1.1 From befde0226a595d1a7854c0cbf32904b8279c4fd0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 18 Feb 2013 11:26:11 +0100 Subject: HID: uhid: make creating devices work on 64/32 systems Unfortunately UHID interface, as it was introduced, is broken with 32 bit userspace running on 64 bit kernels as it uses a pointer in its userspace facing API. Fix it by checking if we are executing compat task and munge the request appropriately. Reported-by: Kirill A. Shutemov Acked-by: Kirill A. Shutemov Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/uhid.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 714cd8c..fc307e04 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -276,6 +277,94 @@ static struct hid_ll_driver uhid_hid_driver = { .parse = uhid_hid_parse, }; +#ifdef CONFIG_COMPAT + +/* Apparently we haven't stepped on these rakes enough times yet. */ +struct uhid_create_req_compat { + __u8 name[128]; + __u8 phys[64]; + __u8 uniq[64]; + + compat_uptr_t rd_data; + __u16 rd_size; + + __u16 bus; + __u32 vendor; + __u32 product; + __u32 version; + __u32 country; +} __attribute__((__packed__)); + +static int uhid_event_from_user(const char __user *buffer, size_t len, + struct uhid_event *event) +{ + if (is_compat_task()) { + u32 type; + + if (get_user(type, buffer)) + return -EFAULT; + + if (type == UHID_CREATE) { + /* + * This is our messed up request with compat pointer. + * It is largish (more than 256 bytes) so we better + * allocate it from the heap. + */ + struct uhid_create_req_compat *compat; + + compat = kmalloc(sizeof(*compat), GFP_KERNEL); + if (!compat) + return -ENOMEM; + + buffer += sizeof(type); + len -= sizeof(type); + if (copy_from_user(compat, buffer, + min(len, sizeof(*compat)))) { + kfree(compat); + return -EFAULT; + } + + /* Shuffle the data over to proper structure */ + event->type = type; + + memcpy(event->u.create.name, compat->name, + sizeof(compat->name)); + memcpy(event->u.create.phys, compat->phys, + sizeof(compat->phys)); + memcpy(event->u.create.uniq, compat->uniq, + sizeof(compat->uniq)); + + event->u.create.rd_data = compat_ptr(compat->rd_data); + event->u.create.rd_size = compat->rd_size; + + event->u.create.bus = compat->bus; + event->u.create.vendor = compat->vendor; + event->u.create.product = compat->product; + event->u.create.version = compat->version; + event->u.create.country = compat->country; + + kfree(compat); + return 0; + } + /* All others can be copied directly */ + } + + if (copy_from_user(event, buffer, min(len, sizeof(*event)))) + return -EFAULT; + + return 0; +} +#else +static int uhid_event_from_user(const char __user *buffer, size_t len, + struct uhid_event *event) +{ + if (copy_from_user(event, buffer, min(len, sizeof(*event)))) + return -EFAULT; + + return 0; +} +#endif + static int uhid_dev_create(struct uhid_device *uhid, const struct uhid_event *ev) { @@ -498,10 +587,10 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, memset(&uhid->input_buf, 0, sizeof(uhid->input_buf)); len = min(count, sizeof(uhid->input_buf)); - if (copy_from_user(&uhid->input_buf, buffer, len)) { - ret = -EFAULT; + + ret = uhid_event_from_user(buffer, len, &uhid->input_buf); + if (ret) goto unlock; - } switch (uhid->input_buf.type) { case UHID_CREATE: -- cgit v1.1 From 30ba2fbde1840db440915491cdde235b72a11384 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 22 Jan 2013 12:01:21 -0500 Subject: HID: add ThingM blink(1) USB RGB LED support The ThingM blink(1) is an open source hardware USB RGB LED. It contains an internal EEPROM, allowing to configure up to 12 light patterns. A light pattern is a RGB color plus a fade time. This driver registers a LED class instance with additional sysfs attributes to support basic functions such as setting RGB colors, fade and playing. Other functions are still accessible through the hidraw interface. At this time, the only documentation for the device is the firmware source code from ThingM, plus a few schematics. They are available at: https://github.com/todbot/blink1 This patch is version 3. It updates the name of the source file, the driver and the led sysfs entry, according to comments from Jiri Kosina and Simon Wood. Signed-off-by: Vivien Didelot Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 10 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 + drivers/hid/hid-thingm.c | 272 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 287 insertions(+) create mode 100644 drivers/hid/hid-thingm.c (limited to 'drivers/hid') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index bf88eca..3d52945 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -655,6 +655,16 @@ config HID_TOPSEED Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic CLLRCMCE remote control. +config HID_THINGM + tristate "ThingM blink(1) USB RGB LED" + depends on USB_HID + depends on LEDS_CLASS + ---help--- + Support for the ThingM blink(1) USB RGB LED. This driver registers a + Linux LED class instance, plus additional sysfs attributes to control + RGB colors, fade time and playing. The device is exposed through hidraw + to access other functions. + config HID_THRUSTMASTER tristate "ThrustMaster devices support" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index b622157..9301704 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_HID_SONY) += hid-sony.o obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o +obj-$(CONFIG_HID_THINGM) += hid-thingm.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o obj-$(CONFIG_HID_TIVO) += hid-tivo.o obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index bf44af3..5f7115e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1699,6 +1699,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 1041052..eebbbf6 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -747,6 +747,9 @@ #define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010 #define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 +#define USB_VENDOR_ID_THINGM 0x27b8 +#define USB_DEVICE_ID_BLINK1 0x01ed + #define USB_VENDOR_ID_THRUSTMASTER 0x044f #define USB_VENDOR_ID_TIVO 0x150a diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c new file mode 100644 index 0000000..2055a52 --- /dev/null +++ b/drivers/hid/hid-thingm.c @@ -0,0 +1,272 @@ +/* + * ThingM blink(1) USB RGB LED driver + * + * Copyright 2013 Savoir-faire Linux Inc. + * Vivien Didelot + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ + +#include +#include +#include +#include + +#include "hid-ids.h" + +#define BLINK1_CMD_SIZE 9 + +#define blink1_rgb_to_r(rgb) ((rgb & 0xFF0000) >> 16) +#define blink1_rgb_to_g(rgb) ((rgb & 0x00FF00) >> 8) +#define blink1_rgb_to_b(rgb) ((rgb & 0x0000FF) >> 0) + +/** + * struct blink1_data - blink(1) device specific data + * @hdev: HID device. + * @led_cdev: LED class instance. + * @rgb: 8-bit per channel RGB notation. + * @fade: fade time in hundredths of a second. + * @brightness: brightness coefficient. + * @play: play/pause in-memory patterns. + */ +struct blink1_data { + struct hid_device *hdev; + struct led_classdev led_cdev; + u32 rgb; + u16 fade; + u8 brightness; + bool play; +}; + +static int blink1_send_command(struct blink1_data *data, + u8 buf[BLINK1_CMD_SIZE]) +{ + int ret; + + hid_dbg(data->hdev, "command: %d%c%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7], buf[8]); + + ret = data->hdev->hid_output_raw_report(data->hdev, buf, + BLINK1_CMD_SIZE, HID_FEATURE_REPORT); + + return ret < 0 ? ret : 0; +} + +static int blink1_update_color(struct blink1_data *data) +{ + u8 buf[BLINK1_CMD_SIZE] = { 1, 'n', 0, 0, 0, 0, 0, 0, 0 }; + + if (data->brightness) { + unsigned int coef = DIV_ROUND_CLOSEST(255, data->brightness); + + buf[2] = DIV_ROUND_CLOSEST(blink1_rgb_to_r(data->rgb), coef); + buf[3] = DIV_ROUND_CLOSEST(blink1_rgb_to_g(data->rgb), coef); + buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef); + } + + if (data->fade) { + buf[1] = 'c'; + buf[5] = (data->fade & 0xFF00) >> 8; + buf[6] = (data->fade & 0x00FF); + } + + return blink1_send_command(data, buf); +} + +static void blink1_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent); + + data->brightness = brightness; + if (blink1_update_color(data)) + hid_err(data->hdev, "failed to update color\n"); +} + +static enum led_brightness blink1_led_get(struct led_classdev *led_cdev) +{ + struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent); + + return data->brightness; +} + +static ssize_t blink1_show_rgb(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct blink1_data *data = dev_get_drvdata(dev->parent); + + return sprintf(buf, "%.6X\n", data->rgb); +} + +static ssize_t blink1_store_rgb(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct blink1_data *data = dev_get_drvdata(dev->parent); + long unsigned int rgb; + int ret; + + ret = kstrtoul(buf, 16, &rgb); + if (ret) + return ret; + + /* RGB triplet notation is 24-bit hexadecimal */ + if (rgb > 0xFFFFFF) + return -EINVAL; + + data->rgb = rgb; + ret = blink1_update_color(data); + + return ret ? ret : count; +} + +static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR, blink1_show_rgb, blink1_store_rgb); + +static ssize_t blink1_show_fade(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct blink1_data *data = dev_get_drvdata(dev->parent); + + return sprintf(buf, "%d\n", data->fade * 10); +} + +static ssize_t blink1_store_fade(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct blink1_data *data = dev_get_drvdata(dev->parent); + long unsigned int fade; + int ret; + + ret = kstrtoul(buf, 10, &fade); + if (ret) + return ret; + + /* blink(1) accepts 16-bit fade time, number of 10ms ticks */ + fade = DIV_ROUND_CLOSEST(fade, 10); + if (fade > 65535) + return -EINVAL; + + data->fade = fade; + + return count; +} + +static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR, + blink1_show_fade, blink1_store_fade); + +static ssize_t blink1_show_play(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct blink1_data *data = dev_get_drvdata(dev->parent); + + return sprintf(buf, "%d\n", data->play); +} + +static ssize_t blink1_store_play(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct blink1_data *data = dev_get_drvdata(dev->parent); + u8 cmd[BLINK1_CMD_SIZE] = { 1, 'p', 0, 0, 0, 0, 0, 0, 0 }; + long unsigned int play; + int ret; + + ret = kstrtoul(buf, 10, &play); + if (ret) + return ret; + + data->play = !!play; + cmd[2] = data->play; + ret = blink1_send_command(data, cmd); + + return ret ? ret : count; +} + +static DEVICE_ATTR(play, S_IRUGO | S_IWUSR, + blink1_show_play, blink1_store_play); + +static const struct attribute_group blink1_sysfs_group = { + .attrs = (struct attribute *[]) { + &dev_attr_rgb.attr, + &dev_attr_fade.attr, + &dev_attr_play.attr, + NULL + }, +}; + +static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + struct blink1_data *data; + struct led_classdev *led; + char led_name[13]; + int ret; + + data = devm_kzalloc(&hdev->dev, sizeof(struct blink1_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + hid_set_drvdata(hdev, data); + data->hdev = hdev; + data->rgb = 0xFFFFFF; /* set a default white color */ + + ret = hid_parse(hdev); + if (ret) + goto error; + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) + goto error; + + /* blink(1) serial numbers range is 0x1A001000 to 0x1A002FFF */ + led = &data->led_cdev; + snprintf(led_name, sizeof(led_name), "blink1::%s", hdev->uniq + 4); + led->name = led_name; + led->brightness_set = blink1_led_set; + led->brightness_get = blink1_led_get; + ret = led_classdev_register(&hdev->dev, led); + if (ret) + goto stop; + + ret = sysfs_create_group(&led->dev->kobj, &blink1_sysfs_group); + if (ret) + goto remove_led; + + return 0; + +remove_led: + led_classdev_unregister(led); +stop: + hid_hw_stop(hdev); +error: + return ret; +} + +static void thingm_remove(struct hid_device *hdev) +{ + struct blink1_data *data = hid_get_drvdata(hdev); + struct led_classdev *led = &data->led_cdev; + + sysfs_remove_group(&led->dev->kobj, &blink1_sysfs_group); + led_classdev_unregister(led); + hid_hw_stop(hdev); +} + +static const struct hid_device_id thingm_table[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) }, + { } +}; +MODULE_DEVICE_TABLE(hid, thingm_table); + +static struct hid_driver thingm_driver = { + .name = "thingm", + .probe = thingm_probe, + .remove = thingm_remove, + .id_table = thingm_table, +}; + +module_hid_driver(thingm_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vivien Didelot "); +MODULE_DESCRIPTION("ThingM blink(1) USB RGB LED driver"); -- cgit v1.1 From 54bfe3f0dab2b2f0ac629690f187537d95adeb4f Mon Sep 17 00:00:00 2001 From: Paul Sbarra Date: Sun, 17 Feb 2013 11:53:13 -0600 Subject: HID: logitech: add report descriptor for Driving Force wheel This is the original report descriptor as reported by lsusb -vd 046d:c294. Signed-off-by: Paul Sbarra Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 5 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index a2f8e88..6daa192 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -21,8 +21,10 @@ #include #include #include +#include #include +#include "usbhid/usbhid.h" #include "hid-ids.h" #include "hid-lg.h" @@ -40,17 +42,83 @@ #define LG_FF3 0x1000 #define LG_FF4 0x2000 -/* Size of the original descriptor of the Driving Force Pro wheel */ +/* Size of the original descriptors of the Driving Force (and Pro) wheels */ +#define DF_RDESC_ORIG_SIZE 130 #define DFP_RDESC_ORIG_SIZE 97 -/* Fixed report descriptor for Logitech Driving Force Pro wheel controller +/* Fixed report descriptors for Logitech Driving Force (and Pro) + * wheel controllers * - * The original descriptor hides the separate throttle and brake axes in + * The original descriptors hide the separate throttle and brake axes in * a custom vendor usage page, providing only a combined value as * GenericDesktop.Y. - * This descriptor removes the combined Y axis and instead reports + * These descriptors remove the combined Y axis and instead report * separate throttle (Y) and brake (RZ). */ +static __u8 df_rdesc_fixed[] = { +0x05, 0x01, /* Usage Page (Desktop), */ +0x09, 0x04, /* Usage (Joystik), */ +0xA1, 0x01, /* Collection (Application), */ +0xA1, 0x02, /* Collection (Logical), */ +0x95, 0x01, /* Report Count (1), */ +0x75, 0x0A, /* Report Size (10), */ +0x14, /* Logical Minimum (0), */ +0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ +0x34, /* Physical Minimum (0), */ +0x46, 0xFF, 0x03, /* Physical Maximum (1023), */ +0x09, 0x30, /* Usage (X), */ +0x81, 0x02, /* Input (Variable), */ +0x95, 0x0C, /* Report Count (12), */ +0x75, 0x01, /* Report Size (1), */ +0x25, 0x01, /* Logical Maximum (1), */ +0x45, 0x01, /* Physical Maximum (1), */ +0x05, 0x09, /* Usage (Buttons), */ +0x19, 0x01, /* Usage Minimum (1), */ +0x29, 0x0c, /* Usage Maximum (12), */ +0x81, 0x02, /* Input (Variable), */ +0x95, 0x02, /* Report Count (2), */ +0x06, 0x00, 0xFF, /* Usage Page (Vendor: 65280), */ +0x09, 0x01, /* Usage (?: 1), */ +0x81, 0x02, /* Input (Variable), */ +0x05, 0x01, /* Usage Page (Desktop), */ +0x09, 0x31, /* Usage (Y), */ +0x26, 0xFF, 0x00, /* Logical Maximum (255), */ +0x46, 0xFF, 0x00, /* Physical Maximum (255), */ +0x95, 0x01, /* Report Count (1), */ +0x75, 0x08, /* Report Size (8), */ +0x81, 0x02, /* Input (Variable), */ +0x25, 0x07, /* Logical Maximum (7), */ +0x46, 0x3B, 0x01, /* Physical Maximum (315), */ +0x75, 0x04, /* Report Size (4), */ +0x65, 0x14, /* Unit (Degrees), */ +0x09, 0x39, /* Usage (Hat Switch), */ +0x81, 0x42, /* Input (Variable, Null State), */ +0x75, 0x01, /* Report Size (1), */ +0x95, 0x04, /* Report Count (4), */ +0x65, 0x00, /* Unit (none), */ +0x06, 0x00, 0xFF, /* Usage Page (Vendor: 65280), */ +0x09, 0x01, /* Usage (?: 1), */ +0x25, 0x01, /* Logical Maximum (1), */ +0x45, 0x01, /* Physical Maximum (1), */ +0x81, 0x02, /* Input (Variable), */ +0x95, 0x02, /* Report Count (2), */ +0x75, 0x08, /* Report Size (8), */ +0x26, 0xFF, 0x00, /* Logical Maximum (255), */ +0x46, 0xFF, 0x00, /* Physical Maximum (255), */ +0x09, 0x02, /* Usage (?: 2), */ +0x81, 0x02, /* Input (Variable), */ +0xC0, /* End Collection, */ +0xA1, 0x02, /* Collection (Logical), */ +0x26, 0xFF, 0x00, /* Logical Maximum (255), */ +0x46, 0xFF, 0x00, /* Physical Maximum (255), */ +0x95, 0x07, /* Report Count (7), */ +0x75, 0x08, /* Report Size (8), */ +0x09, 0x03, /* Usage (?: 3), */ +0x91, 0x02, /* Output (Variable), */ +0xC0, /* End Collection, */ +0xC0 /* End Collection */ +}; + static __u8 dfp_rdesc_fixed[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x04, /* Usage (Joystik), */ @@ -99,7 +167,6 @@ static __u8 dfp_rdesc_fixed[] = { 0xC0 /* End Collection */ }; - /* * Certain Logitech keyboards send in report #3 keys which are far * above the logical maximum described in descriptor. This extends @@ -109,6 +176,8 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { struct lg_drv_data *drv_data = hid_get_drvdata(hdev); + struct usb_device_descriptor *udesc; + __u16 bcdDevice, rev_maj, rev_min; if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && rdesc[84] == 0x8c && rdesc[85] == 0x02) { @@ -135,6 +204,28 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, } switch (hdev->product) { + + /* Several wheels report as this id when operating in emulation mode. */ + case USB_DEVICE_ID_LOGITECH_WHEEL: + udesc = &(hid_to_usb_dev(hdev)->descriptor); + if (!udesc) { + hid_err(hdev, "NULL USB device descriptor\n"); + break; + } + bcdDevice = le16_to_cpu(udesc->bcdDevice); + rev_maj = bcdDevice >> 8; + rev_min = bcdDevice & 0xff; + + /* Update the report descriptor for only the Driving Force wheel */ + if (rev_maj == 1 && rev_min == 2 && + *rsize == DF_RDESC_ORIG_SIZE) { + hid_info(hdev, + "fixing up Logitech Driving Force report descriptor\n"); + rdesc = df_rdesc_fixed; + *rsize = sizeof(df_rdesc_fixed); + } + break; + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: if (*rsize == DFP_RDESC_ORIG_SIZE) { hid_info(hdev, -- cgit v1.1 From 5a9b571bacafffaff75f4f523c4479c85e83cb15 Mon Sep 17 00:00:00 2001 From: Paul Sbarra Date: Sun, 17 Feb 2013 11:53:14 -0600 Subject: HID: logitech: split accel, brake for Driving Force wheel Signed-off-by: Paul Sbarra Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 6daa192..6bb7f05 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -81,7 +81,6 @@ static __u8 df_rdesc_fixed[] = { 0x09, 0x01, /* Usage (?: 1), */ 0x81, 0x02, /* Input (Variable), */ 0x05, 0x01, /* Usage Page (Desktop), */ -0x09, 0x31, /* Usage (Y), */ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ 0x95, 0x01, /* Report Count (1), */ @@ -101,11 +100,14 @@ static __u8 df_rdesc_fixed[] = { 0x25, 0x01, /* Logical Maximum (1), */ 0x45, 0x01, /* Physical Maximum (1), */ 0x81, 0x02, /* Input (Variable), */ -0x95, 0x02, /* Report Count (2), */ +0x05, 0x01, /* Usage Page (Desktop), */ +0x95, 0x01, /* Report Count (1), */ 0x75, 0x08, /* Report Size (8), */ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ -0x09, 0x02, /* Usage (?: 2), */ +0x09, 0x31, /* Usage (Y), */ +0x81, 0x02, /* Input (Variable), */ +0x09, 0x35, /* Usage (Rz), */ 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xA1, 0x02, /* Collection (Logical), */ -- cgit v1.1 From 0f690ccf56d3166e695ad27fb0936af189250ef1 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 19 Feb 2013 14:05:34 +0100 Subject: HID: hidraw: print message when succesfully initialized Print a message when hidraw has been succesfully initialized. Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 413a731..f3bbbce 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -581,6 +581,7 @@ int __init hidraw_init(void) if (result < 0) goto error_class; + printk(KERN_INFO "hidraw: raw HID events driver (C) Jiri Kosina\n"); out: return result; -- cgit v1.1 From 270baef1fafab50410e0e395ec26834de2dcc390 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Tue, 19 Feb 2013 20:25:10 -0700 Subject: HID: LG: Add support for Logitech Momo Force (Red) Wheel This patch provides a modified report descriptor to split accelerator and brake, and adds the 'NO_GET' flag to prevent it hanging on connection. Note: for convience this patch is against the follow patch which was applied earlier this week. https://patchwork.kernel.org/patch/2153471/ Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 6bb7f05..160c489 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -45,6 +45,7 @@ /* Size of the original descriptors of the Driving Force (and Pro) wheels */ #define DF_RDESC_ORIG_SIZE 130 #define DFP_RDESC_ORIG_SIZE 97 +#define MOMO_RDESC_ORIG_SIZE 87 /* Fixed report descriptors for Logitech Driving Force (and Pro) * wheel controllers @@ -169,6 +170,52 @@ static __u8 dfp_rdesc_fixed[] = { 0xC0 /* End Collection */ }; +static __u8 momo_rdesc_fixed[] = { +0x05, 0x01, /* Usage Page (Desktop), */ +0x09, 0x04, /* Usage (Joystik), */ +0xA1, 0x01, /* Collection (Application), */ +0xA1, 0x02, /* Collection (Logical), */ +0x95, 0x01, /* Report Count (1), */ +0x75, 0x0A, /* Report Size (10), */ +0x15, 0x00, /* Logical Minimum (0), */ +0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ +0x35, 0x00, /* Physical Minimum (0), */ +0x46, 0xFF, 0x03, /* Physical Maximum (1023), */ +0x09, 0x30, /* Usage (X), */ +0x81, 0x02, /* Input (Variable), */ +0x95, 0x08, /* Report Count (8), */ +0x75, 0x01, /* Report Size (1), */ +0x25, 0x01, /* Logical Maximum (1), */ +0x45, 0x01, /* Physical Maximum (1), */ +0x05, 0x09, /* Usage Page (Button), */ +0x19, 0x01, /* Usage Minimum (01h), */ +0x29, 0x08, /* Usage Maximum (08h), */ +0x81, 0x02, /* Input (Variable), */ +0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ +0x75, 0x0E, /* Report Size (14), */ +0x95, 0x01, /* Report Count (1), */ +0x26, 0xFF, 0x00, /* Logical Maximum (255), */ +0x46, 0xFF, 0x00, /* Physical Maximum (255), */ +0x09, 0x00, /* Usage (00h), */ +0x81, 0x02, /* Input (Variable), */ +0x05, 0x01, /* Usage Page (Desktop), */ +0x75, 0x08, /* Report Size (8), */ +0x09, 0x31, /* Usage (Y), */ +0x81, 0x02, /* Input (Variable), */ +0x09, 0x32, /* Usage (Z), */ +0x81, 0x02, /* Input (Variable), */ +0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ +0x09, 0x01, /* Usage (01h), */ +0x81, 0x02, /* Input (Variable), */ +0xC0, /* End Collection, */ +0xA1, 0x02, /* Collection (Logical), */ +0x09, 0x02, /* Usage (02h), */ +0x95, 0x07, /* Report Count (7), */ +0x91, 0x02, /* Output (Variable), */ +0xC0, /* End Collection, */ +0xC0 /* End Collection */ +}; + /* * Certain Logitech keyboards send in report #3 keys which are far * above the logical maximum described in descriptor. This extends @@ -228,6 +275,15 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, } break; + case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: + if (*rsize == MOMO_RDESC_ORIG_SIZE) { + hid_info(hdev, + "fixing up Logitech Momo Force (Red) report descriptor\n"); + rdesc = momo_rdesc_fixed; + *rsize = sizeof(momo_rdesc_fixed); + } + break; + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: if (*rsize == DFP_RDESC_ORIG_SIZE) { hid_info(hdev, @@ -558,7 +614,7 @@ static const struct hid_device_id lg_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO), .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL), - .driver_data = LG_FF4 }, + .driver_data = LG_NOGET | LG_FF4 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2), .driver_data = LG_FF4 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), -- cgit v1.1 From b5836246c127ce1f0afe9790537b94c71efd2d2a Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Tue, 19 Feb 2013 20:25:11 -0700 Subject: HID: LG: Fix detection of Logitech Speed Force Wireless (WiiWheel) Previously 'LG4FF' was only used for the WiiWheel, however it is now used for all the Logitech Wheels. This patch corrects the detection mechanism for the patching the report descriptor to ensure only the WiiWheel will be patched. Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 160c489..c065598 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -242,15 +242,6 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, "fixing up rel/abs in Logitech report descriptor\n"); rdesc[33] = rdesc[50] = 0x02; } - if ((drv_data->quirks & LG_FF4) && *rsize >= 101 && - rdesc[41] == 0x95 && rdesc[42] == 0x0B && - rdesc[47] == 0x05 && rdesc[48] == 0x09) { - hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n"); - rdesc[41] = 0x05; - rdesc[42] = 0x09; - rdesc[47] = 0x95; - rdesc[48] = 0x0B; - } switch (hdev->product) { @@ -292,6 +283,17 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, *rsize = sizeof(dfp_rdesc_fixed); } break; + + case USB_DEVICE_ID_LOGITECH_WII_WHEEL: + if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B && + rdesc[47] == 0x05 && rdesc[48] == 0x09) { + hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n"); + rdesc[41] = 0x05; + rdesc[42] = 0x09; + rdesc[47] = 0x95; + rdesc[48] = 0x0B; + } + break; } return rdesc; -- cgit v1.1 From 94b3f712fe2cd5c33d57ca0ab9604d2402bc72cd Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Tue, 19 Feb 2013 20:25:12 -0700 Subject: HID: LG: Prevent the Logitech Gaming Wheels deadzone This patch ensures that the Logitech wheels are not initialised with default fuzz/flat values, by marking them as multiaxis devices (rather than joysticks). Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index c065598..5d3c861 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -479,6 +479,26 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, usage->type == EV_REL || usage->type == EV_ABS)) clear_bit(usage->code, *bit); + /* Ensure that Logitech wheels are not given a default fuzz/flat value */ + if (usage->type == EV_ABS && (usage->code == ABS_X || + usage->code == ABS_Y || usage->code == ABS_Z || + usage->code == ABS_RZ)) { + switch (hdev->product) { + case USB_DEVICE_ID_LOGITECH_WHEEL: + case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + case USB_DEVICE_ID_LOGITECH_G25_WHEEL: + case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL: + case USB_DEVICE_ID_LOGITECH_G27_WHEEL: + case USB_DEVICE_ID_LOGITECH_WII_WHEEL: + case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2: + field->application = HID_GD_MULTIAXIS; + break; + default: + break; + } + } + return 0; } -- cgit v1.1 From d50bbd008ac3ead5eb8990fac1908c4a53e7a164 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Tue, 19 Feb 2013 20:25:13 -0700 Subject: HID: LG4FF: Remove unnecessary deadzone code This patch removes code which is now unnecessary for setting the fuzz/flat characterics for the logitech DFP wheel. This is now done in the previous patch by marking the wheel as a multi-axis device. Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg4ff.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index d7947c7..65a6ec8 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -43,11 +43,6 @@ #define G27_REV_MAJ 0x12 #define G27_REV_MIN 0x38 -#define DFP_X_MIN 0 -#define DFP_X_MAX 16383 -#define DFP_PEDAL_MIN 0 -#define DFP_PEDAL_MAX 255 - #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev) static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); @@ -598,18 +593,6 @@ int lg4ff_init(struct hid_device *hid) return error; dbg_hid("sysfs interface created\n"); - /* Set default axes parameters */ - switch (lg4ff_devices[i].product_id) { - case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: - dbg_hid("Setting axes parameters for Driving Force Pro\n"); - input_set_abs_params(dev, ABS_X, DFP_X_MIN, DFP_X_MAX, 0, 0); - input_set_abs_params(dev, ABS_Y, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0); - input_set_abs_params(dev, ABS_RZ, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0); - break; - default: - break; - } - /* Set the maximum range to start with */ entry->range = entry->max_range; if (entry->set_range != NULL) -- cgit v1.1 From 483f86a54c6d89f16da2e53f2b7b6205b34756df Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Tue, 19 Feb 2013 20:25:14 -0700 Subject: HID: Correct Logitech order in hid-ids.h Reorders a couple of device IDs (Logitech controllers) to ensure that they are in hexidecimal order. Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34e2547..865492c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -525,8 +525,8 @@ #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 #define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287 -#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 #define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293 +#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299 -- cgit v1.1