1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 *  ION iCade input driver
4 *
5 *  Copyright (c) 2012 Bastien Nocera <hadess@hadess.net>
6 *  Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
7 */
8
9/*
10 */
11
12#include <linux/device.h>
13#include <linux/hid.h>
14#include <linux/module.h>
15
16#include "hid-ids.h"
17
18/*
19 *   ���      A C Y L
20 *  ��� ���
21 *   ���      B X Z R
22 *
23 *
24 *  UP ON,OFF  = w,e
25 *  RT ON,OFF  = d,c
26 *  DN ON,OFF  = x,z
27 *  LT ON,OFF  = a,q
28 *  A  ON,OFF  = y,t
29 *  B  ON,OFF  = h,r
30 *  C  ON,OFF  = u,f
31 *  X  ON,OFF  = j,n
32 *  Y  ON,OFF  = i,m
33 *  Z  ON,OFF  = k,p
34 *  L  ON,OFF  = o,g
35 *  R  ON,OFF  = l,v
36 */
37
38/* The translation code uses HID usage instead of input layer
39 * keys. This code generates a lookup table that makes
40 * translation quick.
41 *
42 * #include <linux/input.h>
43 * #include <stdio.h>
44 * #include <assert.h>
45 *
46 * #define unk     KEY_UNKNOWN
47 *
48 * < copy of hid_keyboard[] from hid-input.c >
49 *
50 * struct icade_key_translation {
51 *     int         from;
52 *     const char *to;
53 *     int         press;
54 * };
55 *
56 * static const struct icade_key_translation icade_keys[] = {
57 *    { KEY_W,        "KEY_UP",         1 },
58 *    { KEY_E,        "KEY_UP",         0 },
59 *    { KEY_D,        "KEY_RIGHT",      1 },
60 *    { KEY_C,        "KEY_RIGHT",      0 },
61 *    { KEY_X,        "KEY_DOWN",       1 },
62 *    { KEY_Z,        "KEY_DOWN",       0 },
63 *    { KEY_A,        "KEY_LEFT",       1 },
64 *    { KEY_Q,        "KEY_LEFT",       0 },
65 *    { KEY_Y,        "BTN_A",          1 },
66 *    { KEY_T,        "BTN_A",          0 },
67 *    { KEY_H,        "BTN_B",          1 },
68 *    { KEY_R,        "BTN_B",          0 },
69 *    { KEY_U,        "BTN_C",          1 },
70 *    { KEY_F,        "BTN_C",          0 },
71 *    { KEY_J,        "BTN_X",          1 },
72 *    { KEY_N,        "BTN_X",          0 },
73 *    { KEY_I,        "BTN_Y",          1 },
74 *    { KEY_M,        "BTN_Y",          0 },
75 *    { KEY_K,        "BTN_Z",          1 },
76 *    { KEY_P,        "BTN_Z",          0 },
77 *    { KEY_O,        "BTN_THUMBL",     1 },
78 *    { KEY_G,        "BTN_THUMBL",     0 },
79 *    { KEY_L,        "BTN_THUMBR",     1 },
80 *    { KEY_V,        "BTN_THUMBR",     0 },
81 *
82 *    { }
83 * };
84 *
85 * static int
86 * usage_for_key (int key)
87 * {
88 *     int i;
89 *     for (i = 0; i < 256; i++) {
90 *     if (hid_keyboard[i] == key)
91 *         return i;
92 *     }
93 *     assert(0);
94 * }
95 *
96 * int main (int argc, char **argv)
97 * {
98 *     const struct icade_key_translation *trans;
99 *     int max_usage = 0;
100 *
101 *     for (trans = icade_keys; trans->from; trans++) {
102 *         int usage = usage_for_key (trans->from);
103 *         max_usage = usage > max_usage ? usage : max_usage;
104 *     }
105 *
106 *     printf ("#define ICADE_MAX_USAGE %d\n\n", max_usage);
107 *     printf ("struct icade_key {\n");
108 *     printf ("\tu16 to;\n");
109 *     printf ("\tu8 press:1;\n");
110 *     printf ("};\n\n");
111 *     printf ("static const struct icade_key "
112 *             "icade_usage_table[%d] = {\n", max_usage + 1);
113 *     for (trans = icade_keys; trans->from; trans++) {
114 *         printf ("\t[%d] = { %s, %d },\n",
115 *                 usage_for_key (trans->from), trans->to, trans->press);
116 *     }
117 *     printf ("};\n");
118 *
119 *     return 0;
120 * }
121 */
122
123#define ICADE_MAX_USAGE 29
124
125struct icade_key {
126	u16 to;
127	u8 press:1;
128};
129
130static const struct icade_key icade_usage_table[30] = {
131	[26] = { KEY_UP, 1 },
132	[8] = { KEY_UP, 0 },
133	[7] = { KEY_RIGHT, 1 },
134	[6] = { KEY_RIGHT, 0 },
135	[27] = { KEY_DOWN, 1 },
136	[29] = { KEY_DOWN, 0 },
137	[4] = { KEY_LEFT, 1 },
138	[20] = { KEY_LEFT, 0 },
139	[28] = { BTN_A, 1 },
140	[23] = { BTN_A, 0 },
141	[11] = { BTN_B, 1 },
142	[21] = { BTN_B, 0 },
143	[24] = { BTN_C, 1 },
144	[9] = { BTN_C, 0 },
145	[13] = { BTN_X, 1 },
146	[17] = { BTN_X, 0 },
147	[12] = { BTN_Y, 1 },
148	[16] = { BTN_Y, 0 },
149	[14] = { BTN_Z, 1 },
150	[19] = { BTN_Z, 0 },
151	[18] = { BTN_THUMBL, 1 },
152	[10] = { BTN_THUMBL, 0 },
153	[15] = { BTN_THUMBR, 1 },
154	[25] = { BTN_THUMBR, 0 },
155};
156
157static const struct icade_key *icade_find_translation(u16 from)
158{
159	if (from > ICADE_MAX_USAGE)
160		return NULL;
161	return &icade_usage_table[from];
162}
163
164static int icade_event(struct hid_device *hdev, struct hid_field *field,
165		struct hid_usage *usage, __s32 value)
166{
167	const struct icade_key *trans;
168
169	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
170			!usage->type)
171		return 0;
172
173	/* We ignore the fake key up, and act only on key down */
174	if (!value)
175		return 1;
176
177	trans = icade_find_translation(usage->hid & HID_USAGE);
178
179	if (!trans)
180		return 1;
181
182	input_event(field->hidinput->input, usage->type,
183			trans->to, trans->press);
184
185	return 1;
186}
187
188static int icade_input_mapping(struct hid_device *hdev, struct hid_input *hi,
189		struct hid_field *field, struct hid_usage *usage,
190		unsigned long **bit, int *max)
191{
192	const struct icade_key *trans;
193
194	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) {
195		trans = icade_find_translation(usage->hid & HID_USAGE);
196
197		if (!trans)
198			return -1;
199
200		hid_map_usage(hi, usage, bit, max, EV_KEY, trans->to);
201		set_bit(trans->to, hi->input->keybit);
202
203		return 1;
204	}
205
206	/* ignore others */
207	return -1;
208
209}
210
211static int icade_input_mapped(struct hid_device *hdev, struct hid_input *hi,
212		struct hid_field *field, struct hid_usage *usage,
213		unsigned long **bit, int *max)
214{
215	if (usage->type == EV_KEY)
216		set_bit(usage->type, hi->input->evbit);
217
218	return -1;
219}
220
221static const struct hid_device_id icade_devices[] = {
222	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
223
224	{ }
225};
226MODULE_DEVICE_TABLE(hid, icade_devices);
227
228static struct hid_driver icade_driver = {
229	.name = "icade",
230	.id_table = icade_devices,
231	.event = icade_event,
232	.input_mapped = icade_input_mapped,
233	.input_mapping = icade_input_mapping,
234};
235module_hid_driver(icade_driver);
236
237MODULE_LICENSE("GPL");
238MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
239MODULE_DESCRIPTION("ION iCade input driver");
240