aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2012-10-31 07:10:10 -0400
committerJiri Kosina <jkosina@suse.cz>2012-10-31 10:52:59 -0400
commit4ddfe0289bd4622a2a84747ab90c0614da4673e0 (patch)
treedc07b281d5aaf9af229db90da9909f35c5d0fa60
parentdef7cb8cd4e3258db88050eaaca5438bcc3dafca (diff)
HID: Add driver for ION iCade
Add a driver for the ION iCade mini arcade cabinet [1]. The device generates a key press and release for each joystick movement or button press or release. For example, moving the stick to the left will generate the "A" key being pressed and then released. A list of all the combinations is available in the iCade developer guide [2]. This driver hides all this and makes the device work as a generic joystick. [1]: http://www.ionaudio.com/products/details/icade [2]: http://www.ionaudio.com/downloads/iCade_Dev_Resource_v1.3.pdf Signed-off-by: Bastien Nocera <hadess@hadess.net> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/Kconfig9
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-core.c1
-rw-r--r--drivers/hid/hid-icade.c259
-rw-r--r--drivers/hid/hid-ids.h3
5 files changed, 273 insertions, 0 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 1630150ad2b1..813f0fe7711d 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -265,6 +265,15 @@ config HID_GYRATION
265 ---help--- 265 ---help---
266 Support for Gyration remote control. 266 Support for Gyration remote control.
267 267
268config HID_ICADE
269 tristate "ION iCade arcade controller"
270 depends on (BT_HIDP)
271 ---help---
272 Support for the ION iCade arcade controller to work as a joystick.
273
274 To compile this driver as a module, choose M here: the
275 module will be called hid-icade.
276
268config HID_TWINHAN 277config HID_TWINHAN
269 tristate "Twinhan IR remote control" 278 tristate "Twinhan IR remote control"
270 depends on USB_HID 279 depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index cef68ca859d3..85c910c6d9d2 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
52obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o 52obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o
53obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o 53obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
54obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o 54obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o
55obj-$(CONFIG_HID_ICADE) += hid-icade.o
55obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o 56obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
56obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o 57obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
57obj-$(CONFIG_HID_KYE) += hid-kye.o 58obj-$(CONFIG_HID_KYE) += hid-kye.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index bd3971bf31bf..0a6b36fbb4ce 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1572,6 +1572,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1572 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_09FA) }, 1572 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_09FA) },
1573 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_1020) }, 1573 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_1020) },
1574 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_09FA) }, 1574 { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_09FA) },
1575 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
1575 { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, 1576 { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
1576 { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, 1577 { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
1577 { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, 1578 { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
diff --git a/drivers/hid/hid-icade.c b/drivers/hid/hid-icade.c
new file mode 100644
index 000000000000..1d6565e37ba3
--- /dev/null
+++ b/drivers/hid/hid-icade.c
@@ -0,0 +1,259 @@
1/*
2 * ION iCade input driver
3 *
4 * Copyright (c) 2012 Bastien Nocera <hadess@hadess.net>
5 * Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
6 */
7
8/*
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 */
14
15#include <linux/device.h>
16#include <linux/hid.h>
17#include <linux/module.h>
18
19#include "hid-ids.h"
20
21/*
22 * ↑ A C Y L
23 * ← →
24 * ↓ B X Z R
25 *
26 *
27 * UP ON,OFF = w,e
28 * RT ON,OFF = d,c
29 * DN ON,OFF = x,z
30 * LT ON,OFF = a,q
31 * A ON,OFF = y,t
32 * B ON,OFF = h,r
33 * C ON,OFF = u,f
34 * X ON,OFF = j,n
35 * Y ON,OFF = i,m
36 * Z ON,OFF = k,p
37 * L ON,OFF = o,g
38 * R ON,OFF = l,v
39 */
40
41/* The translation code uses HID usage instead of input layer
42 * keys. This code generates a lookup table that makes
43 * translation quick.
44 *
45 * #include <linux/input.h>
46 * #include <stdio.h>
47 * #include <assert.h>
48 *
49 * #define unk KEY_UNKNOWN
50 *
51 * < copy of hid_keyboard[] from hid-input.c >
52 *
53 * struct icade_key_translation {
54 * int from;
55 * const char *to;
56 * int press;
57 * };
58 *
59 * static const struct icade_key_translation icade_keys[] = {
60 * { KEY_W, "KEY_UP", 1 },
61 * { KEY_E, "KEY_UP", 0 },
62 * { KEY_D, "KEY_RIGHT", 1 },
63 * { KEY_C, "KEY_RIGHT", 0 },
64 * { KEY_X, "KEY_DOWN", 1 },
65 * { KEY_Z, "KEY_DOWN", 0 },
66 * { KEY_A, "KEY_LEFT", 1 },
67 * { KEY_Q, "KEY_LEFT", 0 },
68 * { KEY_Y, "BTN_A", 1 },
69 * { KEY_T, "BTN_A", 0 },
70 * { KEY_H, "BTN_B", 1 },
71 * { KEY_R, "BTN_B", 0 },
72 * { KEY_U, "BTN_C", 1 },
73 * { KEY_F, "BTN_C", 0 },
74 * { KEY_J, "BTN_X", 1 },
75 * { KEY_N, "BTN_X", 0 },
76 * { KEY_I, "BTN_Y", 1 },
77 * { KEY_M, "BTN_Y", 0 },
78 * { KEY_K, "BTN_Z", 1 },
79 * { KEY_P, "BTN_Z", 0 },
80 * { KEY_O, "BTN_THUMBL", 1 },
81 * { KEY_G, "BTN_THUMBL", 0 },
82 * { KEY_L, "BTN_THUMBR", 1 },
83 * { KEY_V, "BTN_THUMBR", 0 },
84 *
85 * { }
86 * };
87 *
88 * static int
89 * usage_for_key (int key)
90 * {
91 * int i;
92 * for (i = 0; i < 256; i++) {
93 * if (hid_keyboard[i] == key)
94 * return i;
95 * }
96 * assert(0);
97 * }
98 *
99 * int main (int argc, char **argv)
100 * {
101 * const struct icade_key_translation *trans;
102 * int max_usage = 0;
103 *
104 * for (trans = icade_keys; trans->from; trans++) {
105 * int usage = usage_for_key (trans->from);
106 * max_usage = usage > max_usage ? usage : max_usage;
107 * }
108 *
109 * printf ("#define ICADE_MAX_USAGE %d\n\n", max_usage);
110 * printf ("struct icade_key {\n");
111 * printf ("\tu16 to;\n");
112 * printf ("\tu8 press:1;\n");
113 * printf ("};\n\n");
114 * printf ("static const struct icade_key "
115 * "icade_usage_table[%d] = {\n", max_usage + 1);
116 * for (trans = icade_keys; trans->from; trans++) {
117 * printf ("\t[%d] = { %s, %d },\n",
118 * usage_for_key (trans->from), trans->to, trans->press);
119 * }
120 * printf ("};\n");
121 *
122 * return 0;
123 * }
124 */
125
126#define ICADE_MAX_USAGE 29
127
128struct icade_key {
129 u16 to;
130 u8 press:1;
131};
132
133static const struct icade_key icade_usage_table[30] = {
134 [26] = { KEY_UP, 1 },
135 [8] = { KEY_UP, 0 },
136 [7] = { KEY_RIGHT, 1 },
137 [6] = { KEY_RIGHT, 0 },
138 [27] = { KEY_DOWN, 1 },
139 [29] = { KEY_DOWN, 0 },
140 [4] = { KEY_LEFT, 1 },
141 [20] = { KEY_LEFT, 0 },
142 [28] = { BTN_A, 1 },
143 [23] = { BTN_A, 0 },
144 [11] = { BTN_B, 1 },
145 [21] = { BTN_B, 0 },
146 [24] = { BTN_C, 1 },
147 [9] = { BTN_C, 0 },
148 [13] = { BTN_X, 1 },
149 [17] = { BTN_X, 0 },
150 [12] = { BTN_Y, 1 },
151 [16] = { BTN_Y, 0 },
152 [14] = { BTN_Z, 1 },
153 [19] = { BTN_Z, 0 },
154 [18] = { BTN_THUMBL, 1 },
155 [10] = { BTN_THUMBL, 0 },
156 [15] = { BTN_THUMBR, 1 },
157 [25] = { BTN_THUMBR, 0 },
158};
159
160static const struct icade_key *icade_find_translation(u16 from)
161{
162 if (from < 0 || from > ICADE_MAX_USAGE)
163 return NULL;
164 return &icade_usage_table[from];
165}
166
167static int icade_event(struct hid_device *hdev, struct hid_field *field,
168 struct hid_usage *usage, __s32 value)
169{
170 const struct icade_key *trans;
171
172 if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
173 !usage->type)
174 return 0;
175
176 /* We ignore the fake key up, and act only on key down */
177 if (!value)
178 return 1;
179
180 trans = icade_find_translation(usage->hid & HID_USAGE);
181
182 if (!trans)
183 return 1;
184
185 input_event(field->hidinput->input, usage->type,
186 trans->to, trans->press);
187
188 return 1;
189}
190
191static int icade_input_mapping(struct hid_device *hdev, struct hid_input *hi,
192 struct hid_field *field, struct hid_usage *usage,
193 unsigned long **bit, int *max)
194{
195 const struct icade_key *trans;
196
197 if ((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) {
198 trans = icade_find_translation(usage->hid & HID_USAGE);
199
200 if (!trans)
201 return -1;
202
203 hid_map_usage(hi, usage, bit, max, EV_KEY, trans->to);
204 set_bit(trans->to, hi->input->keybit);
205
206 return 1;
207 }
208
209 /* ignore others */
210 return -1;
211
212}
213
214static int icade_input_mapped(struct hid_device *hdev, struct hid_input *hi,
215 struct hid_field *field, struct hid_usage *usage,
216 unsigned long **bit, int *max)
217{
218 if (usage->type == EV_KEY)
219 set_bit(usage->type, hi->input->evbit);
220
221 return -1;
222}
223
224static const struct hid_device_id icade_devices[] = {
225 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
226
227 { }
228};
229MODULE_DEVICE_TABLE(hid, icade_devices);
230
231static struct hid_driver icade_driver = {
232 .name = "icade",
233 .id_table = icade_devices,
234 .event = icade_event,
235 .input_mapped = icade_input_mapped,
236 .input_mapping = icade_input_mapping,
237};
238
239static int __init icade_init(void)
240{
241 int ret;
242
243 ret = hid_register_driver(&icade_driver);
244 if (ret)
245 pr_err("can't register icade driver\n");
246
247 return ret;
248}
249
250static void __exit icade_exit(void)
251{
252 hid_unregister_driver(&icade_driver);
253}
254
255module_init(icade_init);
256module_exit(icade_exit);
257MODULE_LICENSE("GPL");
258MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
259MODULE_DESCRIPTION("ION iCade input driver");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 269b50912a4a..9bc8d570777a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -420,6 +420,9 @@
420#define USB_VENDOR_ID_ILITEK 0x222a 420#define USB_VENDOR_ID_ILITEK 0x222a
421#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001 421#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
422 422
423#define USB_VENDOR_ID_ION 0x15e4
424#define USB_DEVICE_ID_ICADE 0x0132
425
423#define USB_VENDOR_ID_HOLTEK 0x1241 426#define USB_VENDOR_ID_HOLTEK 0x1241
424#define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015 427#define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015
425 428