Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID subsystem updates from Jiri Kosina: "HID subsystem and drivers update. Highlights: - new support of a group of Win7/Win8 multitouch devices, from Benjamin Tissoires - fix for compat interface brokenness in uhid, from Dmitry Torokhov - conversion of drivers to use hid_driver helper, by H Hartley Sweeten - HID over I2C transport received ACPI enumeration support, written by Mika Westerberg - there is an ongoing effort to make HID sensor hubs independent of USB transport. The first self-contained part of this work is provided here, done by Mika Westerberg - a few smaller fixes here and there, support for a couple new devices added" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (43 commits) HID: Correct Logitech order in hid-ids.h HID: LG4FF: Remove unnecessary deadzone code HID: LG: Prevent the Logitech Gaming Wheels deadzone HID: LG: Fix detection of Logitech Speed Force Wireless (WiiWheel) HID: LG: Add support for Logitech Momo Force (Red) Wheel HID: hidraw: print message when succesfully initialized HID: logitech: split accel, brake for Driving Force wheel HID: logitech: add report descriptor for Driving Force wheel HID: add ThingM blink(1) USB RGB LED support HID: uhid: make creating devices work on 64/32 systems HID: wiimote: fix nunchuck button parser HID: blacklist Velleman data acquisition boards HID: sensor-hub: don't limit the driver only to USB bus HID: sensor-hub: get rid of unused sensor_hub_grabbed_usages[] table HID: extend autodetect to handle I2C sensors as well HID: ntrig: use input_configured() callback to set the name HID: multitouch: do not use pointers towards hid-core HID: add missing GENERIC_HARDIRQ dependency HID: multitouch: make MT_CLS_ALWAYS_TRUE the new default class HID: multitouch: fix protocol for Elo panels ...
This commit is contained in:
commit
48a732dfaa
21
Documentation/ABI/testing/sysfs-driver-hid-srws1
Normal file
21
Documentation/ABI/testing/sysfs-driver-hid-srws1
Normal file
@ -0,0 +1,21 @@
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM1
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM2
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM3
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM4
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM5
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM6
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM7
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM8
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM9
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM10
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM11
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM12
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM13
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM14
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPM15
|
||||
What: /sys/class/leds/SRWS1::<serial>::RPMALL
|
||||
Date: Jan 2013
|
||||
KernelVersion: 3.9
|
||||
Contact: Simon Wood <simon@mungewell.org>
|
||||
Description: Provides a control for turning on/off the LEDs which form
|
||||
an RPM meter on the front of the controller
|
23
Documentation/ABI/testing/sysfs-driver-hid-thingm
Normal file
23
Documentation/ABI/testing/sysfs-driver-hid-thingm
Normal file
@ -0,0 +1,23 @@
|
||||
What: /sys/class/leds/blink1::<serial>/rgb
|
||||
Date: January 2013
|
||||
Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
|
||||
Description: The ThingM blink1 is an USB RGB LED. The color notation is
|
||||
3-byte hexadecimal. Read this attribute to get the last set
|
||||
color. Write the 24-bit hexadecimal color to change the current
|
||||
LED color. The default color is full white (0xFFFFFF).
|
||||
For instance, set the color to green with: echo 00FF00 > rgb
|
||||
|
||||
What: /sys/class/leds/blink1::<serial>/fade
|
||||
Date: January 2013
|
||||
Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
|
||||
Description: This attribute allows to set a fade time in milliseconds for
|
||||
the next color change. Read the attribute to know the current
|
||||
fade time. The default value is set to 0 (no fade time). For
|
||||
instance, set a fade time of 2 seconds with: echo 2000 > fade
|
||||
|
||||
What: /sys/class/leds/blink1::<serial>/play
|
||||
Date: January 2013
|
||||
Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
|
||||
Description: This attribute is used to play/pause the light patterns. Write 1
|
||||
to start playing, 0 to stop. Reading this attribute returns the
|
||||
current playing status.
|
@ -7611,6 +7611,11 @@ S: Supported
|
||||
F: drivers/thermal/
|
||||
F: include/linux/thermal.h
|
||||
|
||||
THINGM BLINK(1) USB RGB LED DRIVER
|
||||
M: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
|
||||
S: Maintained
|
||||
F: drivers/hid/hid-thingm.c
|
||||
|
||||
THINKPAD ACPI EXTRAS DRIVER
|
||||
M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
|
||||
L: ibm-acpi-devel@lists.sourceforge.net
|
||||
|
@ -596,6 +596,12 @@ config HID_SPEEDLINK
|
||||
---help---
|
||||
Support for Speedlink Vicious and Divine Cezanne mouse.
|
||||
|
||||
config HID_STEELSERIES
|
||||
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
|
||||
@ -655,6 +661,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
|
||||
@ -719,7 +735,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---
|
||||
|
@ -101,8 +101,10 @@ 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) += hid-steelseries.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
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
@ -1599,6 +1603,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) },
|
||||
@ -1697,7 +1702,9 @@ 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_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) },
|
||||
@ -2228,6 +2235,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 &&
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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 <hadess@hadess.net>");
|
||||
MODULE_DESCRIPTION("ION iCade input driver");
|
||||
|
@ -445,6 +445,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
|
||||
|
||||
@ -525,8 +528,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
|
||||
@ -597,6 +600,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
|
||||
|
||||
@ -709,6 +715,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
|
||||
@ -726,6 +733,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
|
||||
|
||||
@ -747,6 +757,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
|
||||
@ -794,6 +807,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
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -21,8 +21,10 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include "usbhid/usbhid.h"
|
||||
#include "hid-ids.h"
|
||||
#include "hid-lg.h"
|
||||
|
||||
@ -40,17 +42,86 @@
|
||||
#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
|
||||
#define MOMO_RDESC_ORIG_SIZE 87
|
||||
|
||||
/* 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), */
|
||||
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), */
|
||||
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, 0x31, /* Usage (Y), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x09, 0x35, /* Usage (Rz), */
|
||||
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,6 +170,51 @@ 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
|
||||
@ -109,6 +225,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) {
|
||||
@ -124,17 +242,39 @@ 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) {
|
||||
|
||||
/* 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_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,
|
||||
@ -143,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;
|
||||
@ -328,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;
|
||||
}
|
||||
|
||||
@ -465,7 +636,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),
|
||||
@ -503,17 +674,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");
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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,8 +84,11 @@ struct mt_device {
|
||||
struct mt_class mtclass; /* our mt device class */
|
||||
struct mt_fields *fields; /* temporary placeholder for storing the
|
||||
multitouch fields */
|
||||
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 */
|
||||
__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,
|
||||
@ -111,6 +115,9 @@ 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_NSMU 0x000a
|
||||
#define MT_CLS_DUAL_CONTACT_NUMBER 0x0010
|
||||
#define MT_CLS_DUAL_CONTACT_ID 0x0011
|
||||
|
||||
/* vendor specific classes */
|
||||
#define MT_CLS_3M 0x0101
|
||||
@ -144,6 +151,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},
|
||||
@ -170,6 +180,16 @@ 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_DUAL_CONTACT_NUMBER,
|
||||
.quirks = MT_QUIRK_ALWAYS_VALID |
|
||||
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
|
||||
@ -250,6 +270,9 @@ static ssize_t mt_set_quirks(struct device *dev,
|
||||
|
||||
td->mtclass.quirks = val;
|
||||
|
||||
if (td->cc_index < 0)
|
||||
td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -301,6 +324,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;
|
||||
@ -428,6 +452,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,
|
||||
@ -459,6 +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->cc_index = field->index;
|
||||
td->cc_value_index = usage->usage_index;
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_DG_CONTACTMAX:
|
||||
@ -523,6 +550,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;
|
||||
@ -577,6 +608,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;
|
||||
@ -623,20 +664,13 @@ static int 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 */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* fallback to the generic hidinput handling */
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (usage->usage_index + 1 == field->report_count) {
|
||||
@ -650,12 +684,43 @@ 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;
|
||||
|
||||
/*
|
||||
* Includes multi-packet support where subsequent
|
||||
* packets are sent with zero 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];
|
||||
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)
|
||||
@ -711,6 +776,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;
|
||||
@ -719,11 +785,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->cc_index < 0)
|
||||
cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
|
||||
}
|
||||
|
||||
static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
@ -781,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);
|
||||
@ -875,7 +946,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) },
|
||||
|
||||
@ -888,14 +959,14 @@ 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 */
|
||||
{ .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,
|
||||
@ -906,12 +977,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) },
|
||||
|
||||
@ -982,7 +1053,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) },
|
||||
|
||||
@ -1000,12 +1071,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) },
|
||||
|
||||
@ -1023,7 +1094,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) },
|
||||
|
||||
@ -1056,6 +1127,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_DEFAULT,
|
||||
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,
|
||||
@ -1065,7 +1141,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) },
|
||||
|
||||
@ -1111,7 +1187,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_DEFAULT,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
|
||||
USB_DEVICE_ID_MTP_SITRONIX)},
|
||||
|
||||
@ -1121,48 +1197,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) },
|
||||
|
||||
@ -1193,21 +1269,10 @@ 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,
|
||||
#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);
|
||||
|
@ -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,20 +1022,10 @@ 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,
|
||||
};
|
||||
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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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 <anssi.hannula@gmail.com>
|
||||
*/
|
||||
|
||||
@ -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);
|
||||
@ -216,17 +225,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");
|
||||
|
@ -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 <tlambert@google.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -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");
|
||||
|
@ -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 <dave@thedillows.org>, Antonio Ospite <ospite@studenti.unina.it>");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -605,16 +605,12 @@ 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);
|
||||
|
||||
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,
|
||||
@ -627,19 +623,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 <srinivas.pandruvada@intel.com>");
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
@ -43,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) {
|
||||
hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n");
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@ -56,6 +88,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;
|
||||
}
|
||||
@ -217,6 +255,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);
|
||||
@ -229,17 +269,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");
|
||||
|
@ -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");
|
||||
|
393
drivers/hid/hid-steelseries.c
Normal file
393
drivers/hid/hid-steelseries.c
Normal file
@ -0,0 +1,393 @@
|
||||
/*
|
||||
* 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 <linux/device.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#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;
|
||||
/* the last element is used for setting all leds simultaneously */
|
||||
struct led_classdev *led[SRWS1_NUMBER_LEDS + 1];
|
||||
};
|
||||
#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");
|
@ -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");
|
||||
|
272
drivers/hid/hid-thingm.c
Normal file
272
drivers/hid/hid-thingm.c
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* ThingM blink(1) USB RGB LED driver
|
||||
*
|
||||
* Copyright 2013 Savoir-faire Linux Inc.
|
||||
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
|
||||
*
|
||||
* 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 <linux/hid.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#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 <vivien.didelot@savoirfairelinux.com>");
|
||||
MODULE_DESCRIPTION("ThingM blink(1) USB RGB LED driver");
|
@ -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 <jarod@redhat.com>");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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 <dh.herrmann@gmail.com>");
|
||||
MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <linux/i2c/i2c-hid.h>
|
||||
|
||||
@ -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,
|
||||
@ -821,6 +824,70 @@ static int 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 i2c_hid_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
@ -832,11 +899,6 @@ static int 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");
|
||||
@ -847,11 +909,22 @@ static int 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);
|
||||
@ -884,6 +957,7 @@ static int 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);
|
||||
@ -975,6 +1049,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,
|
||||
|
@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/hid.h>
|
||||
@ -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:
|
||||
|
@ -589,6 +589,7 @@ struct hid_usage_id {
|
||||
* @raw_event: if report in report_table, this hook is called (NULL means nop)
|
||||
* @usage_table: on which events to call event (NULL means all)
|
||||
* @event: if usage in usage_table, this hook is called (NULL means nop)
|
||||
* @report: this hook is called after parsing a report (NULL means nop)
|
||||
* @report_fixup: called before report descriptor parsing (NULL means nop)
|
||||
* @input_mapping: invoked on input registering before mapping an usage
|
||||
* @input_mapped: invoked on input registering after mapping an usage
|
||||
@ -627,6 +628,7 @@ struct hid_driver {
|
||||
const struct hid_usage_id *usage_table;
|
||||
int (*event)(struct hid_device *hdev, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value);
|
||||
void (*report)(struct hid_device *hdev, struct hid_report *report);
|
||||
|
||||
__u8 *(*report_fixup)(struct hid_device *hdev, __u8 *buf,
|
||||
unsigned int *size);
|
||||
@ -700,6 +702,18 @@ extern int __must_check __hid_register_driver(struct hid_driver *,
|
||||
|
||||
extern void hid_unregister_driver(struct hid_driver *);
|
||||
|
||||
/**
|
||||
* module_hid_driver() - Helper macro for registering a HID driver
|
||||
* @__hid_driver: hid_driver struct
|
||||
*
|
||||
* Helper macro for HID drivers which do not do anything special in module
|
||||
* init/exit. This eliminates a lot of boilerplate. Each module may only
|
||||
* use this macro once, and calling it replaces module_init() and module_exit()
|
||||
*/
|
||||
#define module_hid_driver(__hid_driver) \
|
||||
module_driver(__hid_driver, hid_register_driver, \
|
||||
hid_unregister_driver)
|
||||
|
||||
extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
|
||||
extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
|
||||
extern int hidinput_connect(struct hid_device *hid, unsigned int force);
|
||||
@ -872,9 +886,6 @@ static inline int hid_hw_power(struct hid_device *hdev, int level)
|
||||
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||||
int interrupt);
|
||||
|
||||
extern int hid_generic_init(void);
|
||||
extern void hid_generic_exit(void);
|
||||
|
||||
/* HID quirks API */
|
||||
u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
|
||||
int usbhid_quirks_init(char **quirks_param);
|
||||
|
@ -86,7 +86,7 @@ struct uhid_feature_answer_req {
|
||||
__u16 err;
|
||||
__u16 size;
|
||||
__u8 data[UHID_DATA_MAX];
|
||||
};
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uhid_event {
|
||||
__u32 type;
|
||||
|
Loading…
Reference in New Issue
Block a user