aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorMartin Rusko <martin.rusko@gmail.com>2013-05-28 08:25:15 -0400
committerJiri Kosina <jkosina@suse.cz>2013-05-28 08:29:38 -0400
commit68e353fe476e7dab4644b9e7b4979b72726397ae (patch)
tree0b90c036dfd75be84b8c24cd37d985702cf027e1 /drivers/hid
parent31b9779cb292e2ea3312b15c5eda96b69edbb4da (diff)
HID: add support for Huion 580 tablet
Add hid-huion.c with support for Huion 580 tablet, which is simple 8x5" tablet with 4000LPI resolution and 2048 levels pressure-sensitive pen manufactured by the Chinese company Huion. The driver fixes incorrect report descriptor sent by the device, performs custom initialization required to switch the tablet into its native resolution mode and inverts the in-range bit. Signed-off-by: Martin Rusko <martin.rusko@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Kconfig6
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-core.c1
-rw-r--r--drivers/hid/hid-huion.c177
-rw-r--r--drivers/hid/hid-ids.h3
5 files changed, 188 insertions, 0 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index fb52f3f6de80..015e6156caaf 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -240,6 +240,12 @@ config HOLTEK_FF
240 Say Y here if you have a Holtek On Line Grip based game controller 240 Say Y here if you have a Holtek On Line Grip based game controller
241 and want to have force feedback support for it. 241 and want to have force feedback support for it.
242 242
243config HID_HUION
244 tristate "Huion tablets"
245 depends on USB_HID
246 ---help---
247 Support for Huion 580 tablet.
248
243config HID_KEYTOUCH 249config HID_KEYTOUCH
244 tristate "Keytouch HID devices" 250 tristate "Keytouch HID devices"
245 depends on HID 251 depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 2065694f57ab..b15602bfaccf 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
52obj-$(CONFIG_HID_GYRATION) += hid-gyration.o 52obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
53obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o 53obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o
54obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o 54obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
55obj-$(CONFIG_HID_HUION) += hid-huion.o
55obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o 56obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o
56obj-$(CONFIG_HID_ICADE) += hid-icade.o 57obj-$(CONFIG_HID_ICADE) += hid-icade.o
57obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o 58obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 5d2ef6626615..c27207860dfb 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1584,6 +1584,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1584 { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, 1584 { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
1585 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, 1585 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
1586 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, 1586 { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
1587 { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
1587 { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) }, 1588 { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
1588 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) }, 1589 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
1589 { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, 1590 { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
diff --git a/drivers/hid/hid-huion.c b/drivers/hid/hid-huion.c
new file mode 100644
index 000000000000..cbf4da4689ba
--- /dev/null
+++ b/drivers/hid/hid-huion.c
@@ -0,0 +1,177 @@
1/*
2 * HID driver for Huion devices not fully compliant with HID standard
3 *
4 * Copyright (c) 2013 Martin Rusko
5 */
6
7/*
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 */
13
14#include <linux/device.h>
15#include <linux/hid.h>
16#include <linux/module.h>
17#include <linux/usb.h>
18#include "usbhid/usbhid.h"
19
20#include "hid-ids.h"
21
22/* Original Huion 580 report descriptor size */
23#define HUION_580_RDESC_ORIG_SIZE 177
24
25/* Fixed Huion 580 report descriptor */
26static __u8 huion_580_rdesc_fixed[] = {
27 0x05, 0x0D, /* Usage Page (Digitizer), */
28 0x09, 0x02, /* Usage (Pen), */
29 0xA1, 0x01, /* Collection (Application), */
30 0x85, 0x07, /* Report ID (7), */
31 0x09, 0x20, /* Usage (Stylus), */
32 0xA0, /* Collection (Physical), */
33 0x14, /* Logical Minimum (0), */
34 0x25, 0x01, /* Logical Maximum (1), */
35 0x75, 0x01, /* Report Size (1), */
36 0x09, 0x42, /* Usage (Tip Switch), */
37 0x09, 0x44, /* Usage (Barrel Switch), */
38 0x09, 0x46, /* Usage (Tablet Pick), */
39 0x95, 0x03, /* Report Count (3), */
40 0x81, 0x02, /* Input (Variable), */
41 0x95, 0x03, /* Report Count (3), */
42 0x81, 0x03, /* Input (Constant, Variable), */
43 0x09, 0x32, /* Usage (In Range), */
44 0x95, 0x01, /* Report Count (1), */
45 0x81, 0x02, /* Input (Variable), */
46 0x95, 0x01, /* Report Count (1), */
47 0x81, 0x03, /* Input (Constant, Variable), */
48 0x75, 0x10, /* Report Size (16), */
49 0x95, 0x01, /* Report Count (1), */
50 0xA4, /* Push, */
51 0x05, 0x01, /* Usage Page (Desktop), */
52 0x65, 0x13, /* Unit (Inch), */
53 0x55, 0xFD, /* Unit Exponent (-3), */
54 0x34, /* Physical Minimum (0), */
55 0x09, 0x30, /* Usage (X), */
56 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
57 0x26, 0x00, 0x7D, /* Logical Maximum (32000), */
58 0x81, 0x02, /* Input (Variable), */
59 0x09, 0x31, /* Usage (Y), */
60 0x46, 0x88, 0x13, /* Physical Maximum (5000), */
61 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
62 0x81, 0x02, /* Input (Variable), */
63 0xB4, /* Pop, */
64 0x09, 0x30, /* Usage (Tip Pressure), */
65 0x26, 0xFF, 0x07, /* Logical Maximum (2047), */
66 0x81, 0x02, /* Input (Variable), */
67 0xC0, /* End Collection, */
68 0xC0 /* End Collection */
69};
70
71static __u8 *huion_report_fixup(struct hid_device *hdev, __u8 *rdesc,
72 unsigned int *rsize)
73{
74 switch (hdev->product) {
75 case USB_DEVICE_ID_HUION_580:
76 if (*rsize == HUION_580_RDESC_ORIG_SIZE) {
77 rdesc = huion_580_rdesc_fixed;
78 *rsize = sizeof(huion_580_rdesc_fixed);
79 }
80 break;
81 }
82 return rdesc;
83}
84
85/**
86 * Enable fully-functional tablet mode by reading special string
87 * descriptor.
88 *
89 * @hdev: HID device
90 *
91 * The specific string descriptor and data were discovered by sniffing
92 * the Windows driver traffic.
93 */
94static int huion_tablet_enable(struct hid_device *hdev)
95{
96 int rc;
97 char buf[22];
98
99 rc = usb_string(hid_to_usb_dev(hdev), 0x64, buf, sizeof(buf));
100 if (rc < 0)
101 return rc;
102
103 return 0;
104}
105
106static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
107{
108 int ret;
109 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
110
111 /* Ignore interfaces 1 (mouse) and 2 (keyboard) for Huion 580 tablet,
112 * as they are not used
113 */
114 switch (id->product) {
115 case USB_DEVICE_ID_HUION_580:
116 if (intf->cur_altsetting->desc.bInterfaceNumber != 0x00)
117 return -ENODEV;
118 break;
119 }
120
121 ret = hid_parse(hdev);
122 if (ret) {
123 hid_err(hdev, "parse failed\n");
124 goto err;
125 }
126
127 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
128 if (ret) {
129 hid_err(hdev, "hw start failed\n");
130 goto err;
131 }
132
133 switch (id->product) {
134 case USB_DEVICE_ID_HUION_580:
135 ret = huion_tablet_enable(hdev);
136 if (ret) {
137 hid_err(hdev, "tablet enabling failed\n");
138 goto enabling_err;
139 }
140 break;
141 }
142
143 return 0;
144enabling_err:
145 hid_hw_stop(hdev);
146err:
147 return ret;
148}
149
150static int huion_raw_event(struct hid_device *hdev, struct hid_report *report,
151 u8 *data, int size)
152{
153 /* If this is a pen input report then invert the in-range bit */
154 if (report->type == HID_INPUT_REPORT && report->id == 0x07 && size >= 2)
155 data[1] ^= 0x40;
156
157 return 0;
158}
159
160static const struct hid_device_id huion_devices[] = {
161 { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
162 { }
163};
164MODULE_DEVICE_TABLE(hid, huion_devices);
165
166static struct hid_driver huion_driver = {
167 .name = "huion",
168 .id_table = huion_devices,
169 .probe = huion_probe,
170 .report_fixup = huion_report_fixup,
171 .raw_event = huion_raw_event,
172};
173module_hid_driver(huion_driver);
174
175MODULE_AUTHOR("Martin Rusko");
176MODULE_DESCRIPTION("Huion HID driver");
177MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 533815b12ebc..3da75dd4c323 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -425,6 +425,9 @@
425#define USB_DEVICE_ID_UGCI_FLYING 0x0020 425#define USB_DEVICE_ID_UGCI_FLYING 0x0020
426#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030 426#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
427 427
428#define USB_VENDOR_ID_HUION 0x256c
429#define USB_DEVICE_ID_HUION_580 0x006e
430
428#define USB_VENDOR_ID_IDEACOM 0x1cb6 431#define USB_VENDOR_ID_IDEACOM 0x1cb6
429#define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650 432#define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650
430#define USB_DEVICE_ID_IDEACOM_IDC6651 0x6651 433#define USB_DEVICE_ID_IDEACOM_IDC6651 0x6651