aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-04 11:39:00 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-04 11:39:00 -0700
commit3366dd9fa887ebbda4872e9554f853eaeda764be (patch)
treed1bb553325b276e9d2a1bce99f3e64834b46866b /drivers
parent697a067f1ec67f2f8dfafd0a1b95a46997a11f32 (diff)
parent21796b39c9e876a46a353a4a9ff9881766a7c176 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina: - HID battery handling cleanup by David Herrmann - ELO 4000/4500 driver, which has been finally ported to be proper HID driver by Jiri Slaby - ps3remote driver functionality is now provided by generic sony driver, by Jiri Kosina - PS2/3 Buzz controllers support, by Colin Leitner - rework of wiimote driver including full extensions hotpluggin support, sub-device modularization and speaker support by David Herrmann * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (55 commits) HID: wacom: Intuos4 battery charging changes HID: i2c-hid: support sending HID output reports using the output register HID: kye: Add report fixup for Genius Gila Gaming mouse HID: wiimote: support Nintendo Wii U Pro Controller Input: make gamepad API keycodes more clear input: document gamepad API and add extra keycodes HID: explain out-of-range check better HID: fix false positive out of range values HID: wiimote: fix coccinelle warnings HID: roccat: check cdev_add return value HID: fold ps3remote driver into generic Sony driver HID: hyperv: convert alloc+memcpy to memdup HID: core: fix reporting of raw events HID: wiimote: discard invalid EXT data reports HID: wiimote: fix classic controller parsing HID: wiimote: init EXT/MP during device detection HID: wiimote: fix DRM debug-attr to correctly parse input HID: wiimote: add MP quirks HID: wiimote: remove old static extension support HID: wiimote: add "bboard_calib" attribute ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hid/Kconfig63
-rw-r--r--drivers/hid/Makefile9
-rw-r--r--drivers/hid/hid-core.c12
-rw-r--r--drivers/hid/hid-elo.c273
-rw-r--r--drivers/hid/hid-holtek-mouse.c77
-rw-r--r--drivers/hid/hid-huion.c177
-rw-r--r--drivers/hid/hid-hyperv.c4
-rw-r--r--drivers/hid/hid-ids.h22
-rw-r--r--drivers/hid/hid-input.c11
-rw-r--r--drivers/hid/hid-kye.c21
-rw-r--r--drivers/hid/hid-multitouch.c34
-rw-r--r--drivers/hid/hid-ps3remote.c204
-rw-r--r--drivers/hid/hid-roccat.c16
-rw-r--r--drivers/hid/hid-sony.c473
-rw-r--r--drivers/hid/hid-wacom.c14
-rw-r--r--drivers/hid/hid-wiimote-core.c1658
-rw-r--r--drivers/hid/hid-wiimote-debug.c14
-rw-r--r--drivers/hid/hid-wiimote-ext.c849
-rw-r--r--drivers/hid/hid-wiimote-modules.c2086
-rw-r--r--drivers/hid/hid-wiimote.h217
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c20
21 files changed, 4540 insertions, 1714 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index fb52f3f6de8..14ef6ab6979 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -217,6 +217,13 @@ config HID_ELECOM
---help---
Support for the ELECOM BM084 (bluetooth mouse).
+config HID_ELO
+ tristate "ELO USB 4000/4500 touchscreen"
+ depends on USB_HID
+ ---help---
+ Support for the ELO USB 4000/4500 touchscreens. Note that this is for
+ different devices than those handled by CONFIG_TOUCHSCREEN_USB_ELO.
+
config HID_EZKEY
tristate "Ezkey BTC 8193 keyboard" if EXPERT
depends on HID
@@ -231,6 +238,9 @@ config HID_HOLTEK
Support for Holtek based devices:
- Holtek On Line Grip based game controller
- Trust GXT 18 Gaming Keyboard
+ - Sharkoon Drakonia / Perixx MX-2000 gaming mice
+ - Tracer Sniper TRM-503 / NOVA Gaming Slider X200 /
+ Zalman ZM-GM1
config HOLTEK_FF
bool "Holtek On Line Grip force feedback support"
@@ -240,6 +250,12 @@ config HOLTEK_FF
Say Y here if you have a Holtek On Line Grip based game controller
and want to have force feedback support for it.
+config HID_HUION
+ tristate "Huion tablets"
+ depends on USB_HID
+ ---help---
+ Support for Huion 580 tablet.
+
config HID_KEYTOUCH
tristate "Keytouch HID devices"
depends on HID
@@ -561,15 +577,6 @@ config HID_PRIMAX
Support for Primax devices that are not fully compliant with the
HID standard.
-config HID_PS3REMOTE
- tristate "Sony PS3 BD Remote Control"
- depends on HID
- ---help---
- Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
- Harmony Adapter for PS3, which connect over Bluetooth.
-
- Support for the 6-axis controllers is provided by HID_SONY.
-
config HID_ROCCAT
tristate "Roccat device support"
depends on USB_HID
@@ -594,12 +601,17 @@ config HID_SAMSUNG
Support for Samsung InfraRed remote control or keyboards.
config HID_SONY
- tristate "Sony PS3 controller"
+ tristate "Sony PS2/3 accessories"
depends on USB_HID
+ depends on NEW_LEDS
+ depends on LEDS_CLASS
---help---
- Support for Sony PS3 6-axis controllers.
+ Support for
- Support for the Sony PS3 BD Remote is provided by HID_PS3REMOTE.
+ * Sony PS3 6-axis controllers
+ * Buzz controllers
+ * Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
+ * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support"
@@ -707,22 +719,29 @@ config HID_WACOM
Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
config HID_WIIMOTE
- tristate "Nintendo Wii Remote support"
+ tristate "Nintendo Wii / Wii U peripherals"
depends on HID
depends on LEDS_CLASS
select POWER_SUPPLY
select INPUT_FF_MEMLESS
---help---
- Support for the Nintendo Wii Remote bluetooth device.
+ Support for Nintendo Wii and Wii U Bluetooth peripherals. Supported
+ devices are the Wii Remote and its extension devices, but also devices
+ based on the Wii Remote like the Wii U Pro Controller or the
+ Wii Balance Board.
-config HID_WIIMOTE_EXT
- bool "Nintendo Wii Remote Extension support"
- depends on HID_WIIMOTE
- default HID_WIIMOTE
- ---help---
- Support for extension controllers of the Nintendo Wii Remote. Say yes
- here if you want to use the Nintendo Motion+, Nunchuck or Classic
- extension controllers with your Wii Remote.
+ Support for all official Nintendo extensions is available, however, 3rd
+ party extensions might not be supported. Please report these devices to:
+ http://github.com/dvdhrm/xwiimote/issues
+
+ Other Nintendo Wii U peripherals that are IEEE 802.11 based (including
+ the Wii U Gamepad) might be supported in the future. But currently
+ support is limited to Bluetooth based devices.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hid-wiimote.
config HID_ZEROPLUS
tristate "Zeroplus based game controller support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 2065694f57a..6f687287e21 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -28,10 +28,7 @@ ifdef CONFIG_LOGIWHEELS_FF
hid-logitech-y += hid-lg4ff.o
endif
-hid-wiimote-y := hid-wiimote-core.o
-ifdef CONFIG_HID_WIIMOTE_EXT
- hid-wiimote-y += hid-wiimote-ext.o
-endif
+hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
ifdef CONFIG_DEBUG_FS
hid-wiimote-y += hid-wiimote-debug.o
endif
@@ -48,10 +45,13 @@ obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
+obj-$(CONFIG_HID_ELO) += hid-elo.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o
+obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
+obj-$(CONFIG_HID_HUION) += hid-huion.o
obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o
obj-$(CONFIG_HID_ICADE) += hid-icade.o
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
@@ -92,7 +92,6 @@ hid-picolcd-y += hid-picolcd_debugfs.o
endif
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
-obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 264f5509994..e39dac68063 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1293,7 +1293,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
ret = hdrv->raw_event(hid, report, data, size);
- if (ret != 0) {
+ if (ret < 0) {
ret = ret < 0 ? ret : 0;
goto unlock;
}
@@ -1573,6 +1573,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
@@ -1584,10 +1586,14 @@ 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_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
{ 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) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
@@ -1680,6 +1686,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
@@ -2042,6 +2050,8 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
{ HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_410) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_510) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c
new file mode 100644
index 00000000000..f042a6cf8b1
--- /dev/null
+++ b/drivers/hid/hid-elo.c
@@ -0,0 +1,273 @@
+/*
+ * HID driver for ELO usb touchscreen 4000/4500
+ *
+ * Copyright (c) 2013 Jiri Slaby
+ *
+ * Data parsing taken from elousb driver by Vojtech Pavlik.
+ *
+ * This driver is licensed under the terms of GPLv2.
+ */
+
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+
+#include "hid-ids.h"
+
+#define ELO_PERIODIC_READ_INTERVAL HZ
+#define ELO_SMARTSET_CMD_TIMEOUT 2000 /* msec */
+
+/* Elo SmartSet commands */
+#define ELO_FLUSH_SMARTSET_RESPONSES 0x02 /* Flush all pending smartset responses */
+#define ELO_SEND_SMARTSET_COMMAND 0x05 /* Send a smartset command */
+#define ELO_GET_SMARTSET_RESPONSE 0x06 /* Get a smartset response */
+#define ELO_DIAG 0x64 /* Diagnostics command */
+#define ELO_SMARTSET_PACKET_SIZE 8
+
+struct elo_priv {
+ struct usb_device *usbdev;
+ struct delayed_work work;
+ unsigned char buffer[ELO_SMARTSET_PACKET_SIZE];
+};
+
+static struct workqueue_struct *wq;
+static bool use_fw_quirk = true;
+module_param(use_fw_quirk, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fw_quirk, "Do periodic pokes for broken M firmwares (default = true)");
+
+static void elo_input_configured(struct hid_device *hdev,
+ struct hid_input *hidinput)
+{
+ struct input_dev *input = hidinput->input;
+
+ set_bit(BTN_TOUCH, input->keybit);
+ set_bit(ABS_PRESSURE, input->absbit);
+ input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);
+}
+
+static void elo_process_data(struct input_dev *input, const u8 *data, int size)
+{
+ int press;
+
+ input_report_abs(input, ABS_X, (data[3] << 8) | data[2]);
+ input_report_abs(input, ABS_Y, (data[5] << 8) | data[4]);
+
+ press = 0;
+ if (data[1] & 0x80)
+ press = (data[7] << 8) | data[6];
+ input_report_abs(input, ABS_PRESSURE, press);
+
+ if (data[1] & 0x03) {
+ input_report_key(input, BTN_TOUCH, 1);
+ input_sync(input);
+ }
+
+ if (data[1] & 0x04)
+ input_report_key(input, BTN_TOUCH, 0);
+
+ input_sync(input);
+}
+
+static int elo_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size)
+{
+ struct hid_input *hidinput;
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || list_empty(&hdev->inputs))
+ return 0;
+
+ hidinput = list_first_entry(&hdev->inputs, struct hid_input, list);
+
+ switch (report->id) {
+ case 0:
+ if (data[0] == 'T') { /* Mandatory ELO packet marker */
+ elo_process_data(hidinput->input, data, size);
+ return 1;
+ }
+ break;
+ default: /* unknown report */
+ /* Unknown report type; pass upstream */
+ hid_info(hdev, "unknown report type %d\n", report->id);
+ break;
+ }
+
+ return 0;
+}
+
+static int elo_smartset_send_get(struct usb_device *dev, u8 command,
+ void *data)
+{
+ unsigned int pipe;
+ u8 dir;
+
+ if (command == ELO_SEND_SMARTSET_COMMAND) {
+ pipe = usb_sndctrlpipe(dev, 0);
+ dir = USB_DIR_OUT;
+ } else if (command == ELO_GET_SMARTSET_RESPONSE) {
+ pipe = usb_rcvctrlpipe(dev, 0);
+ dir = USB_DIR_IN;
+ } else
+ return -EINVAL;
+
+ return usb_control_msg(dev, pipe, command,
+ dir | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, data, ELO_SMARTSET_PACKET_SIZE,
+ ELO_SMARTSET_CMD_TIMEOUT);
+}
+
+static int elo_flush_smartset_responses(struct usb_device *dev)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ ELO_FLUSH_SMARTSET_RESPONSES,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static void elo_work(struct work_struct *work)
+{
+ struct elo_priv *priv = container_of(work, struct elo_priv, work.work);
+ struct usb_device *dev = priv->usbdev;
+ unsigned char *buffer = priv->buffer;
+ int ret;
+
+ ret = elo_flush_smartset_responses(dev);
+ if (ret < 0) {
+ dev_err(&dev->dev, "initial FLUSH_SMARTSET_RESPONSES failed, error %d\n",
+ ret);
+ goto fail;
+ }
+
+ /* send Diagnostics command */
+ *buffer = ELO_DIAG;
+ ret = elo_smartset_send_get(dev, ELO_SEND_SMARTSET_COMMAND, buffer);
+ if (ret < 0) {
+ dev_err(&dev->dev, "send Diagnostics Command failed, error %d\n",
+ ret);
+ goto fail;
+ }
+
+ /* get the result */
+ ret = elo_smartset_send_get(dev, ELO_GET_SMARTSET_RESPONSE, buffer);
+ if (ret < 0) {
+ dev_err(&dev->dev, "get Diagnostics Command response failed, error %d\n",
+ ret);
+ goto fail;
+ }
+
+ /* read the ack */
+ if (*buffer != 'A') {
+ ret = elo_smartset_send_get(dev, ELO_GET_SMARTSET_RESPONSE,
+ buffer);
+ if (ret < 0) {
+ dev_err(&dev->dev, "get acknowledge response failed, error %d\n",
+ ret);
+ goto fail;
+ }
+ }
+
+fail:
+ ret = elo_flush_smartset_responses(dev);
+ if (ret < 0)
+ dev_err(&dev->dev, "final FLUSH_SMARTSET_RESPONSES failed, error %d\n",
+ ret);
+ queue_delayed_work(wq, &priv->work, ELO_PERIODIC_READ_INTERVAL);
+}
+
+/*
+ * Not all Elo devices need the periodic HID descriptor reads.
+ * Only firmware version M needs this.
+ */
+static bool elo_broken_firmware(struct usb_device *dev)
+{
+ return use_fw_quirk && le16_to_cpu(dev->descriptor.bcdDevice) == 0x10d;
+}
+
+static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct elo_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&priv->work, elo_work);
+ priv->usbdev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));
+
+ hid_set_drvdata(hdev, priv);
+
+ 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;
+ }
+
+ if (elo_broken_firmware(priv->usbdev)) {
+ hid_info(hdev, "broken firmware found, installing workaround\n");
+ queue_delayed_work(wq, &priv->work, ELO_PERIODIC_READ_INTERVAL);
+ }
+
+ return 0;
+err_free:
+ kfree(priv);
+ return ret;
+}
+
+static void elo_remove(struct hid_device *hdev)
+{
+ struct elo_priv *priv = hid_get_drvdata(hdev);
+
+ hid_hw_stop(hdev);
+ flush_workqueue(wq);
+ kfree(priv);
+}
+
+static const struct hid_device_id elo_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009), },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030), },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, elo_devices);
+
+static struct hid_driver elo_driver = {
+ .name = "elo",
+ .id_table = elo_devices,
+ .probe = elo_probe,
+ .remove = elo_remove,
+ .raw_event = elo_raw_event,
+ .input_configured = elo_input_configured,
+};
+
+static int __init elo_driver_init(void)
+{
+ int ret;
+
+ wq = create_singlethread_workqueue("elousb");
+ if (!wq)
+ return -ENOMEM;
+
+ ret = hid_register_driver(&elo_driver);
+ if (ret)
+ destroy_workqueue(wq);
+
+ return ret;
+}
+module_init(elo_driver_init);
+
+static void __exit elo_driver_exit(void)
+{
+ hid_unregister_driver(&elo_driver);
+ destroy_workqueue(wq);
+}
+module_exit(elo_driver_exit);
+
+MODULE_AUTHOR("Jiri Slaby <jslaby@suse.cz>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-holtek-mouse.c b/drivers/hid/hid-holtek-mouse.c
new file mode 100644
index 00000000000..7e6db3cf46f
--- /dev/null
+++ b/drivers/hid/hid-holtek-mouse.c
@@ -0,0 +1,77 @@
+/*
+ * HID driver for Holtek gaming mice
+ * Copyright (c) 2013 Christian Ohm
+ * Heavily inspired by various other HID drivers that adjust the report
+ * descriptor.
+*/
+
+/*
+ * 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/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+/*
+ * The report descriptor of some Holtek based gaming mice specifies an
+ * excessively large number of consumer usages (2^15), which is more than
+ * HID_MAX_USAGES. This prevents proper parsing of the report descriptor.
+ *
+ * This driver fixes the report descriptor for:
+ * - USB ID 04d9:a067, sold as Sharkoon Drakonia and Perixx MX-2000
+ * - USB ID 04d9:a04a, sold as Tracer Sniper TRM-503, NOVA Gaming Slider X200
+ * and Zalman ZM-GM1
+ */
+
+static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+
+ if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+ /* Change usage maximum and logical maximum from 0x7fff to
+ * 0x2fff, so they don't exceed HID_MAX_USAGES */
+ switch (hdev->product) {
+ case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067:
+ if (*rsize >= 122 && rdesc[115] == 0xff && rdesc[116] == 0x7f
+ && rdesc[120] == 0xff && rdesc[121] == 0x7f) {
+ hid_info(hdev, "Fixing up report descriptor\n");
+ rdesc[116] = rdesc[121] = 0x2f;
+ }
+ break;
+ case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A:
+ if (*rsize >= 113 && rdesc[106] == 0xff && rdesc[107] == 0x7f
+ && rdesc[111] == 0xff && rdesc[112] == 0x7f) {
+ hid_info(hdev, "Fixing up report descriptor\n");
+ rdesc[107] = rdesc[112] = 0x2f;
+ }
+ break;
+ }
+
+ }
+ return rdesc;
+}
+
+static const struct hid_device_id holtek_mouse_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
+ USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
+ USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, holtek_mouse_devices);
+
+static struct hid_driver holtek_mouse_driver = {
+ .name = "holtek_mouse",
+ .id_table = holtek_mouse_devices,
+ .report_fixup = holtek_mouse_report_fixup,
+};
+
+module_hid_driver(holtek_mouse_driver);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-huion.c b/drivers/hid/hid-huion.c
new file mode 100644
index 00000000000..cbf4da4689b
--- /dev/null
+++ b/drivers/hid/hid-huion.c
@@ -0,0 +1,177 @@
+/*
+ * HID driver for Huion devices not fully compliant with HID standard
+ *
+ * Copyright (c) 2013 Martin Rusko
+ */
+
+/*
+ * 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/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+
+#include "hid-ids.h"
+
+/* Original Huion 580 report descriptor size */
+#define HUION_580_RDESC_ORIG_SIZE 177
+
+/* Fixed Huion 580 report descriptor */
+static __u8 huion_580_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x07, /* Report ID (7), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
+ 0x26, 0x00, 0x7D, /* Logical Maximum (32000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x88, 0x13, /* Physical Maximum (5000), */
+ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x07, /* Logical Maximum (2047), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+static __u8 *huion_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ switch (hdev->product) {
+ case USB_DEVICE_ID_HUION_580:
+ if (*rsize == HUION_580_RDESC_ORIG_SIZE) {
+ rdesc = huion_580_rdesc_fixed;
+ *rsize = sizeof(huion_580_rdesc_fixed);
+ }
+ break;
+ }
+ return rdesc;
+}
+
+/**
+ * Enable fully-functional tablet mode by reading special string
+ * descriptor.
+ *
+ * @hdev: HID device
+ *
+ * The specific string descriptor and data were discovered by sniffing
+ * the Windows driver traffic.
+ */
+static int huion_tablet_enable(struct hid_device *hdev)
+{
+ int rc;
+ char buf[22];
+
+ rc = usb_string(hid_to_usb_dev(hdev), 0x64, buf, sizeof(buf));
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+
+ /* Ignore interfaces 1 (mouse) and 2 (keyboard) for Huion 580 tablet,
+ * as they are not used
+ */
+ switch (id->product) {
+ case USB_DEVICE_ID_HUION_580:
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0x00)
+ return -ENODEV;
+ break;
+ }
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err;
+ }
+
+ switch (id->product) {
+ case USB_DEVICE_ID_HUION_580:
+ ret = huion_tablet_enable(hdev);
+ if (ret) {
+ hid_err(hdev, "tablet enabling failed\n");
+ goto enabling_err;
+ }
+ break;
+ }
+
+ return 0;
+enabling_err:
+ hid_hw_stop(hdev);
+err:
+ return ret;
+}
+
+static int huion_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size)
+{
+ /* If this is a pen input report then invert the in-range bit */
+ if (report->type == HID_INPUT_REPORT && report->id == 0x07 && size >= 2)
+ data[1] ^= 0x40;
+
+ return 0;
+}
+
+static const struct hid_device_id huion_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, huion_devices);
+
+static struct hid_driver huion_driver = {
+ .name = "huion",
+ .id_table = huion_devices,
+ .probe = huion_probe,
+ .report_fixup = huion_report_fixup,
+ .raw_event = huion_raw_event,
+};
+module_hid_driver(huion_driver);
+
+MODULE_AUTHOR("Martin Rusko");
+MODULE_DESCRIPTION("Huion HID driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index aa3fec0d9dc..713217380b4 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -199,13 +199,11 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
if (desc->bLength == 0)
goto cleanup;
- input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
+ input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
if (!input_device->hid_desc)
goto cleanup;
- memcpy(input_device->hid_desc, desc, desc->bLength);
-
input_device->report_desc_size = desc->desc[0].wDescriptorLength;
if (input_device->report_desc_size == 0) {
input_device->dev_info_status = -EINVAL;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 38535c9243d..c5aea29f164 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -248,6 +248,9 @@
#define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81
#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001
+#define USB_VENDOR_ID_DATA_MODUL 0x7374
+#define USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH 0x1201
+
#define USB_VENDOR_ID_DEALEXTREAME 0x10c5
#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
@@ -272,16 +275,15 @@
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E 0x725e
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262 0x7262
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B 0x726b
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA 0x72aa
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1 0x72a1
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA 0x72aa
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4 0x72c4
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0 0x72d0
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA 0x72fa
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302 0x7302
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349 0x7349
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224 0x7224
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0 0x72d0
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4 0x72c4
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
@@ -425,6 +427,9 @@
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
+#define USB_VENDOR_ID_HUION 0x256c
+#define USB_DEVICE_ID_HUION_580 0x006e
+
#define USB_VENDOR_ID_IDEACOM 0x1cb6
#define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650
#define USB_DEVICE_ID_IDEACOM_IDC6651 0x6651
@@ -440,6 +445,8 @@
#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9
#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055
+#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067 0xa067
+#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A 0xa04a
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
@@ -447,6 +454,10 @@
#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
+#define USB_VENDOR_ID_JABRA 0x0b0e
+#define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412
+#define USB_DEVICE_ID_JABRA_SPEAK_510 0x0420
+
#define USB_VENDOR_ID_JESS 0x0c45
#define USB_DEVICE_ID_JESS_YUREX 0x1010
@@ -467,6 +478,7 @@
#define USB_VENDOR_ID_KYE 0x0458
#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
+#define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE 0x0138
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
#define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010
#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011
@@ -734,6 +746,8 @@
#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
+#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002
+#define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000
#define USB_VENDOR_ID_