blob: 68e7ebb978a9721c0eb13ce6d0d4710c00d78c42 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
3 *
4 * Copyright (c) 2000-2001 Vojtech Pavlik
5 *
6 * USB HID to Linux Input mapping
7 */
8
9/*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Should you need to contact me, the author, you can do so either by
25 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
26 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
27 */
28
29#include <linux/module.h>
30#include <linux/slab.h>
31#include <linux/kernel.h>
David Brownellae0dadc2006-06-13 10:04:34 -070032#include <linux/usb/input.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34#undef DEBUG
35
36#include "hid.h"
37
38#define unk KEY_UNKNOWN
39
Arjan van de Ven4c4c9432005-11-29 09:43:42 +010040static const unsigned char hid_keyboard[256] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
42 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
43 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
44 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
45 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
46 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
47 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
48 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
49 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
50 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
51 unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
52 unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
53 unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
54 unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
55 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
56 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
57};
58
Arjan van de Ven4c4c9432005-11-29 09:43:42 +010059static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 __s32 x;
61 __s32 y;
62} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
63
64#define map_abs(c) do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0)
65#define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
66#define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
67#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
70#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Michael Hanselmanneab9edd2006-01-14 10:08:06 -050072#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
73
74struct hidinput_key_translation {
75 u16 from;
76 u16 to;
77 u8 flags;
78};
79
80#define POWERBOOK_FLAG_FKEY 0x01
81
82static struct hidinput_key_translation powerbook_fn_keys[] = {
83 { KEY_BACKSPACE, KEY_DELETE },
84 { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY },
85 { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY },
86 { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY },
87 { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY },
88 { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY },
89 { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY },
90 { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY },
91 { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY },
92 { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY },
93 { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY },
94 { KEY_UP, KEY_PAGEUP },
95 { KEY_DOWN, KEY_PAGEDOWN },
96 { KEY_LEFT, KEY_HOME },
97 { KEY_RIGHT, KEY_END },
98 { }
99};
100
101static struct hidinput_key_translation powerbook_numlock_keys[] = {
102 { KEY_J, KEY_KP1 },
103 { KEY_K, KEY_KP2 },
104 { KEY_L, KEY_KP3 },
105 { KEY_U, KEY_KP4 },
106 { KEY_I, KEY_KP5 },
107 { KEY_O, KEY_KP6 },
108 { KEY_7, KEY_KP7 },
109 { KEY_8, KEY_KP8 },
110 { KEY_9, KEY_KP9 },
111 { KEY_M, KEY_KP0 },
112 { KEY_DOT, KEY_KPDOT },
113 { KEY_SLASH, KEY_KPPLUS },
114 { KEY_SEMICOLON, KEY_KPMINUS },
115 { KEY_P, KEY_KPASTERISK },
116 { KEY_MINUS, KEY_KPEQUAL },
117 { KEY_0, KEY_KPSLASH },
118 { KEY_F6, KEY_NUMLOCK },
119 { KEY_KPENTER, KEY_KPENTER },
120 { KEY_BACKSPACE, KEY_BACKSPACE },
121 { }
122};
123
Olaf Heringbb7eef62006-11-08 19:58:07 -0800124static struct hidinput_key_translation powerbook_iso_keyboard[] = {
125 { KEY_GRAVE, KEY_102ND },
126 { KEY_102ND, KEY_GRAVE },
127 { }
128};
129
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500130static int usbhid_pb_fnmode = 1;
131module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
132MODULE_PARM_DESC(pb_fnmode,
133 "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
134
135static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
136{
137 struct hidinput_key_translation *trans;
138
139 /* Look for the translation */
140 for (trans = table; trans->from; trans++)
141 if (trans->from == from)
142 return trans;
143
144 return NULL;
145}
146
147static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
148 struct hid_usage *usage, __s32 value)
149{
150 struct hidinput_key_translation *trans;
151
152 if (usage->code == KEY_FN) {
153 if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON;
154 else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
155
156 input_event(input, usage->type, usage->code, value);
157
158 return 1;
159 }
160
161 if (usbhid_pb_fnmode) {
162 int do_translate;
163
164 trans = find_translation(powerbook_fn_keys, usage->code);
165 if (trans) {
166 if (test_bit(usage->code, hid->pb_pressed_fn))
167 do_translate = 1;
168 else if (trans->flags & POWERBOOK_FLAG_FKEY)
169 do_translate =
170 (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
171 (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
172 else
173 do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
174
175 if (do_translate) {
176 if (value)
177 set_bit(usage->code, hid->pb_pressed_fn);
178 else
179 clear_bit(usage->code, hid->pb_pressed_fn);
180
181 input_event(input, usage->type, trans->to, value);
182
183 return 1;
184 }
185 }
186
187 if (test_bit(usage->code, hid->pb_pressed_numlock) ||
188 test_bit(LED_NUML, input->led)) {
189 trans = find_translation(powerbook_numlock_keys, usage->code);
190
191 if (trans) {
192 if (value)
193 set_bit(usage->code, hid->pb_pressed_numlock);
194 else
195 clear_bit(usage->code, hid->pb_pressed_numlock);
196
197 input_event(input, usage->type, trans->to, value);
198 }
199
200 return 1;
201 }
202 }
203
Olaf Heringbb7eef62006-11-08 19:58:07 -0800204 if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) {
205 trans = find_translation(powerbook_iso_keyboard, usage->code);
206 if (trans) {
207 input_event(input, usage->type, trans->to, value);
208 return 1;
209 }
210 }
211
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500212 return 0;
213}
214
215static void hidinput_pb_setup(struct input_dev *input)
216{
217 struct hidinput_key_translation *trans;
218
219 set_bit(KEY_NUMLOCK, input->keybit);
220
221 /* Enable all needed keys */
222 for (trans = powerbook_fn_keys; trans->from; trans++)
223 set_bit(trans->to, input->keybit);
224
225 for (trans = powerbook_numlock_keys; trans->from; trans++)
226 set_bit(trans->to, input->keybit);
Olaf Heringbb7eef62006-11-08 19:58:07 -0800227
228 for (trans = powerbook_iso_keyboard; trans->from; trans++)
229 set_bit(trans->to, input->keybit);
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500230}
231#else
232static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
233 struct hid_usage *usage, __s32 value)
234{
235 return 0;
236}
237
238static inline void hidinput_pb_setup(struct input_dev *input)
239{
240}
241#endif
242
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
244 struct hid_usage *usage)
245{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500246 struct input_dev *input = hidinput->input;
247 struct hid_device *device = input->private;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500248 int max = 0, code;
249 unsigned long *bit = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251 field->hidinput = hidinput;
252
253#ifdef DEBUG
254 printk(KERN_DEBUG "Mapping: ");
255 resolv_usage(usage->hid);
256 printk(" ---> ");
257#endif
258
259 if (field->flags & HID_MAIN_ITEM_CONSTANT)
260 goto ignore;
261
262 switch (usage->hid & HID_USAGE_PAGE) {
263
264 case HID_UP_UNDEFINED:
265 goto ignore;
266
267 case HID_UP_KEYBOARD:
268
269 set_bit(EV_REP, input->evbit);
270
271 if ((usage->hid & HID_USAGE) < 256) {
272 if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
273 map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
274 } else
275 map_key(KEY_UNKNOWN);
276
277 break;
278
279 case HID_UP_BUTTON:
280
281 code = ((usage->hid - 1) & 0xf);
282
283 switch (field->application) {
284 case HID_GD_MOUSE:
285 case HID_GD_POINTER: code += 0x110; break;
286 case HID_GD_JOYSTICK: code += 0x120; break;
287 case HID_GD_GAMEPAD: code += 0x130; break;
288 default:
289 switch (field->physical) {
290 case HID_GD_MOUSE:
291 case HID_GD_POINTER: code += 0x110; break;
292 case HID_GD_JOYSTICK: code += 0x120; break;
293 case HID_GD_GAMEPAD: code += 0x130; break;
294 default: code += 0x100;
295 }
296 }
297
298 map_key(code);
299 break;
300
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500301
302 case HID_UP_SIMULATION:
303
304 switch (usage->hid & 0xffff) {
Dmitry Torokhov5fce9d7b2006-01-14 00:27:51 -0500305 case 0xba: map_abs(ABS_RUDDER); break;
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500306 case 0xbb: map_abs(ABS_THROTTLE); break;
Dmitry Torokhov5fce9d7b2006-01-14 00:27:51 -0500307 case 0xc4: map_abs(ABS_GAS); break;
308 case 0xc5: map_abs(ABS_BRAKE); break;
309 case 0xc8: map_abs(ABS_WHEEL); break;
Dmitry Torokhovff60dde2005-12-17 11:42:54 -0500310 default: goto ignore;
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500311 }
312 break;
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 case HID_UP_GENDESK:
315
316 if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
317 switch (usage->hid & 0xf) {
318 case 0x1: map_key_clear(KEY_POWER); break;
319 case 0x2: map_key_clear(KEY_SLEEP); break;
320 case 0x3: map_key_clear(KEY_WAKEUP); break;
321 default: goto unknown;
322 }
323 break;
324 }
325
326 if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
327 switch (usage->hid) {
328 case HID_GD_UP: usage->hat_dir = 1; break;
329 case HID_GD_DOWN: usage->hat_dir = 5; break;
330 case HID_GD_RIGHT: usage->hat_dir = 3; break;
331 case HID_GD_LEFT: usage->hat_dir = 7; break;
332 default: goto unknown;
333 }
334 if (field->dpad) {
335 map_abs(field->dpad);
336 goto ignore;
337 }
338 map_abs(ABS_HAT0X);
339 break;
340 }
341
342 switch (usage->hid) {
343
344 /* These usage IDs map directly to the usage codes. */
345 case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
346 case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
347 case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500348 if (field->flags & HID_MAIN_ITEM_RELATIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 map_rel(usage->hid & 0xf);
350 else
351 map_abs(usage->hid & 0xf);
352 break;
353
354 case HID_GD_HATSWITCH:
355 usage->hat_min = field->logical_minimum;
356 usage->hat_max = field->logical_maximum;
357 map_abs(ABS_HAT0X);
358 break;
359
360 case HID_GD_START: map_key_clear(BTN_START); break;
361 case HID_GD_SELECT: map_key_clear(BTN_SELECT); break;
362
363 default: goto unknown;
364 }
365
366 break;
367
368 case HID_UP_LED:
369 if (((usage->hid - 1) & 0xffff) >= LED_MAX)
370 goto ignore;
371 map_led((usage->hid - 1) & 0xffff);
372 break;
373
374 case HID_UP_DIGITIZER:
375
376 switch (usage->hid & 0xff) {
377
378 case 0x30: /* TipPressure */
379 if (!test_bit(BTN_TOUCH, input->keybit)) {
380 device->quirks |= HID_QUIRK_NOTOUCH;
381 set_bit(EV_KEY, input->evbit);
382 set_bit(BTN_TOUCH, input->keybit);
383 }
384
385 map_abs_clear(ABS_PRESSURE);
386 break;
387
388 case 0x32: /* InRange */
389 switch (field->physical & 0xff) {
390 case 0x21: map_key(BTN_TOOL_MOUSE); break;
391 case 0x22: map_key(BTN_TOOL_FINGER); break;
392 default: map_key(BTN_TOOL_PEN); break;
393 }
394 break;
395
396 case 0x3c: /* Invert */
397 map_key_clear(BTN_TOOL_RUBBER);
398 break;
399
400 case 0x33: /* Touch */
401 case 0x42: /* TipSwitch */
402 case 0x43: /* TipSwitch2 */
403 device->quirks &= ~HID_QUIRK_NOTOUCH;
404 map_key_clear(BTN_TOUCH);
405 break;
406
407 case 0x44: /* BarrelSwitch */
408 map_key_clear(BTN_STYLUS);
409 break;
410
411 default: goto unknown;
412 }
413 break;
414
415 case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
416
417 switch (usage->hid & HID_USAGE) {
418 case 0x000: goto ignore;
419 case 0x034: map_key_clear(KEY_SLEEP); break;
420 case 0x036: map_key_clear(BTN_MISC); break;
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500421 case 0x045: map_key_clear(KEY_RADIO); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 case 0x08a: map_key_clear(KEY_WWW); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500423 case 0x08d: map_key_clear(KEY_PROGRAM); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 case 0x095: map_key_clear(KEY_HELP); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500425 case 0x09c: map_key_clear(KEY_CHANNELUP); break;
426 case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 case 0x0b0: map_key_clear(KEY_PLAY); break;
428 case 0x0b1: map_key_clear(KEY_PAUSE); break;
429 case 0x0b2: map_key_clear(KEY_RECORD); break;
430 case 0x0b3: map_key_clear(KEY_FASTFORWARD); break;
431 case 0x0b4: map_key_clear(KEY_REWIND); break;
432 case 0x0b5: map_key_clear(KEY_NEXTSONG); break;
433 case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break;
434 case 0x0b7: map_key_clear(KEY_STOPCD); break;
435 case 0x0b8: map_key_clear(KEY_EJECTCD); break;
436 case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
437 case 0x0e0: map_abs_clear(ABS_VOLUME); break;
438 case 0x0e2: map_key_clear(KEY_MUTE); break;
439 case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
440 case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
441 case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
442 case 0x183: map_key_clear(KEY_CONFIG); break;
443 case 0x18a: map_key_clear(KEY_MAIL); break;
444 case 0x192: map_key_clear(KEY_CALC); break;
445 case 0x194: map_key_clear(KEY_FILE); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500446 case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
447 case 0x201: map_key_clear(KEY_NEW); break;
448 case 0x207: map_key_clear(KEY_SAVE); break;
449 case 0x208: map_key_clear(KEY_PRINT); break;
450 case 0x209: map_key_clear(KEY_PROPS); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 case 0x21a: map_key_clear(KEY_UNDO); break;
452 case 0x21b: map_key_clear(KEY_COPY); break;
453 case 0x21c: map_key_clear(KEY_CUT); break;
454 case 0x21d: map_key_clear(KEY_PASTE); break;
455 case 0x221: map_key_clear(KEY_FIND); break;
456 case 0x223: map_key_clear(KEY_HOMEPAGE); break;
457 case 0x224: map_key_clear(KEY_BACK); break;
458 case 0x225: map_key_clear(KEY_FORWARD); break;
459 case 0x226: map_key_clear(KEY_STOP); break;
460 case 0x227: map_key_clear(KEY_REFRESH); break;
461 case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500462 case 0x233: map_key_clear(KEY_SCROLLUP); break;
463 case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 case 0x238: map_rel(REL_HWHEEL); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500465 case 0x279: map_key_clear(KEY_REDO); break;
466 case 0x289: map_key_clear(KEY_REPLY); break;
467 case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
468 case 0x28c: map_key_clear(KEY_SEND); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500469
470 /* Reported on a Cherry Cymotion keyboard */
471 case 0x301: map_key_clear(KEY_PROG1); break;
472 case 0x302: map_key_clear(KEY_PROG2); break;
473 case 0x303: map_key_clear(KEY_PROG3); break;
474
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500475 default: goto ignore;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 }
477 break;
478
479 case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
480
481 set_bit(EV_REP, input->evbit);
482 switch (usage->hid & HID_USAGE) {
483 case 0x021: map_key_clear(KEY_PRINT); break;
484 case 0x070: map_key_clear(KEY_HP); break;
485 case 0x071: map_key_clear(KEY_CAMERA); break;
486 case 0x072: map_key_clear(KEY_SOUND); break;
487 case 0x073: map_key_clear(KEY_QUESTION); break;
488 case 0x080: map_key_clear(KEY_EMAIL); break;
489 case 0x081: map_key_clear(KEY_CHAT); break;
490 case 0x082: map_key_clear(KEY_SEARCH); break;
491 case 0x083: map_key_clear(KEY_CONNECT); break;
492 case 0x084: map_key_clear(KEY_FINANCE); break;
493 case 0x085: map_key_clear(KEY_SPORT); break;
494 case 0x086: map_key_clear(KEY_SHOP); break;
495 default: goto ignore;
496 }
497 break;
498
499 case HID_UP_MSVENDOR:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 goto ignore;
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500501
Stelian Pope875ce32005-09-05 01:57:33 -0500502 case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
503
504 set_bit(EV_REP, input->evbit);
505 switch(usage->hid & HID_USAGE) {
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500506 case 0x003:
507 /* The fn key on Apple PowerBooks */
508 map_key_clear(KEY_FN);
509 hidinput_pb_setup(input);
510 break;
511
Stelian Pope875ce32005-09-05 01:57:33 -0500512 default: goto ignore;
513 }
514 break;
515
516 case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500517
518 set_bit(EV_REP, input->evbit);
519 switch(usage->hid & HID_USAGE) {
520 case 0x004: map_key_clear(KEY_AGAIN); break;
521 case 0x00d: map_key_clear(KEY_HOME); break;
522 case 0x024: map_key_clear(KEY_SHUFFLE); break;
523 case 0x025: map_key_clear(KEY_TV); break;
524 case 0x026: map_key_clear(KEY_MENU); break;
525 case 0x031: map_key_clear(KEY_AUDIO); break;
Micah F. Galizia50a598d2006-03-14 00:09:34 -0500526 case 0x032: map_key_clear(KEY_TEXT); break;
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500527 case 0x033: map_key_clear(KEY_LAST); break;
528 case 0x047: map_key_clear(KEY_MP3); break;
529 case 0x048: map_key_clear(KEY_DVD); break;
530 case 0x049: map_key_clear(KEY_MEDIA); break;
531 case 0x04a: map_key_clear(KEY_VIDEO); break;
532 case 0x04b: map_key_clear(KEY_ANGLE); break;
533 case 0x04c: map_key_clear(KEY_LANGUAGE); break;
534 case 0x04d: map_key_clear(KEY_SUBTITLE); break;
535 case 0x051: map_key_clear(KEY_RED); break;
536 case 0x052: map_key_clear(KEY_CLOSE); break;
537 default: goto ignore;
538 }
539 break;
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 case HID_UP_PID:
542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 switch(usage->hid & HID_USAGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 case 0xa4: map_key_clear(BTN_DEAD); break;
545 default: goto ignore;
546 }
547 break;
548
549 default:
550 unknown:
551 if (field->report_size == 1) {
552 if (field->report->type == HID_OUTPUT_REPORT) {
553 map_led(LED_MISC);
554 break;
555 }
556 map_key(BTN_MISC);
557 break;
558 }
559 if (field->flags & HID_MAIN_ITEM_RELATIVE) {
560 map_rel(REL_MISC);
561 break;
562 }
563 map_abs(ABS_MISC);
564 break;
565 }
566
Bart Masseya82e49b2006-05-08 14:40:13 -0700567 if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
568 if (usage->hid == HID_GD_Z)
569 map_rel(REL_HWHEEL);
570 else if (usage->code == BTN_1)
571 map_key(BTN_2);
572 else if (usage->code == BTN_2)
573 map_key(BTN_1);
574 }
Vojtech Pavlikc58de6d2005-09-05 00:13:15 -0500575
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500577 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 set_bit(REL_HWHEEL, bit);
579
580 if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
581 || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
582 goto ignore;
583
Bart Masseya82e49b2006-05-08 14:40:13 -0700584 set_bit(usage->type, input->evbit);
585
586 while (usage->code <= max && test_and_set_bit(usage->code, bit))
587 usage->code = find_next_zero_bit(bit, max + 1, usage->code);
588
589 if (usage->code > max)
590 goto ignore;
591
592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 if (usage->type == EV_ABS) {
594
595 int a = field->logical_minimum;
596 int b = field->logical_maximum;
597
598 if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) {
599 a = field->logical_minimum = 0;
600 b = field->logical_maximum = 255;
601 }
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500602
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
604 input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
605 else input_set_abs_params(input, usage->code, a, b, 0, 0);
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 }
608
Dmitry Torokhovcb786232006-07-15 01:17:54 -0400609 if (usage->type == EV_ABS &&
610 (usage->hat_min < usage->hat_max || usage->hat_dir)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 int i;
612 for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
613 input_set_abs_params(input, i, -1, 1, 0, 0);
614 set_bit(i, input->absbit);
615 }
616 if (usage->hat_dir && !field->dpad)
617 field->dpad = usage->code;
618 }
619
620#ifdef DEBUG
621 resolv_event(usage->type, usage->code);
622 printk("\n");
623#endif
624 return;
625
626ignore:
627#ifdef DEBUG
628 printk("IGNORED\n");
629#endif
630 return;
631}
632
David Howells7d12e782006-10-05 14:55:46 +0100633void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700635 struct input_dev *input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 int *quirks = &hid->quirks;
637
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700638 if (!field->hidinput)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500640
641 input = field->hidinput->input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 if (!usage->type)
644 return;
645
646 if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
647 || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
648 if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
649 else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
650 return;
651 }
652
Bart Masseya82e49b2006-05-08 14:40:13 -0700653 if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
654 input_event(input, usage->type, usage->code, -value);
655 return;
656 }
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
659 input_event(input, usage->type, REL_HWHEEL, value);
660 return;
661 }
662
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500663 if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
664 return;
665
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500666 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 int hat_dir = usage->hat_dir;
668 if (!hat_dir)
669 hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
670 if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
671 input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x);
672 input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
673 return;
674 }
675
676 if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
677 *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
678 return;
679 }
680
681 if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
682 if (value) {
683 input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
684 return;
685 }
686 input_event(input, usage->type, usage->code, 0);
687 input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
688 return;
689 }
690
691 if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
692 int a = field->logical_minimum;
693 int b = field->logical_maximum;
694 input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
695 }
696
697 if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
Anssi Hannula224ee882006-07-19 01:40:47 -0400698 dbg("Maximum Effects - %d",value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 return;
700 }
701
702 if (usage->hid == (HID_UP_PID | 0x7fUL)) {
703 dbg("PID Pool Report\n");
704 return;
705 }
706
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500707 if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return;
709
710 input_event(input, usage->type, usage->code, value);
711
712 if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
713 input_event(input, usage->type, usage->code, 0);
714}
715
716void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
717{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 struct hid_input *hidinput;
719
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500720 list_for_each_entry(hidinput, &hid->inputs, list)
721 input_sync(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722}
723
724static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
725{
726 struct hid_report *report;
727 int i, j;
728
729 list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
730 for (i = 0; i < report->maxfield; i++) {
731 *field = report->field[i];
732 for (j = 0; j < (*field)->maxusage; j++)
733 if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
734 return j;
735 }
736 }
737 return -1;
738}
739
740static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
741{
742 struct hid_device *hid = dev->private;
743 struct hid_field *field;
744 int offset;
745
746 if (type == EV_FF)
Anssi Hannuladc76c912006-07-19 01:40:55 -0400747 return input_ff_event(dev, type, code, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 if (type != EV_LED)
750 return -1;
751
752 if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
753 warn("event field not found");
754 return -1;
755 }
756
757 hid_set_field(field, offset, value);
758 hid_submit_report(hid, field->report, USB_DIR_OUT);
759
760 return 0;
761}
762
763static int hidinput_open(struct input_dev *dev)
764{
765 struct hid_device *hid = dev->private;
766 return hid_open(hid);
767}
768
769static void hidinput_close(struct input_dev *dev)
770{
771 struct hid_device *hid = dev->private;
772 hid_close(hid);
773}
774
775/*
776 * Register the input device; print a message.
777 * Configure the input layer interface
778 * Read all reports and initialize the absolute field values.
779 */
780
781int hidinput_connect(struct hid_device *hid)
782{
783 struct usb_device *dev = hid->dev;
784 struct hid_report *report;
785 struct hid_input *hidinput = NULL;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500786 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 int i, j, k;
788
789 INIT_LIST_HEAD(&hid->inputs);
790
791 for (i = 0; i < hid->maxcollection; i++)
792 if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
793 hid->collection[i].type == HID_COLLECTION_PHYSICAL)
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500794 if (IS_INPUT_APPLICATION(hid->collection[i].usage))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 break;
796
797 if (i == hid->maxcollection)
798 return -1;
799
800 for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
801 list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
802
803 if (!report->maxfield)
804 continue;
805
806 if (!hidinput) {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500807 hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
808 input_dev = input_allocate_device();
809 if (!hidinput || !input_dev) {
810 kfree(hidinput);
811 input_free_device(input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 err("Out of memory during hid input probe");
813 return -1;
814 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500816 input_dev->private = hid;
817 input_dev->event = hidinput_input_event;
818 input_dev->open = hidinput_open;
819 input_dev->close = hidinput_close;
820
821 input_dev->name = hid->name;
822 input_dev->phys = hid->phys;
823 input_dev->uniq = hid->uniq;
824 usb_to_input_id(dev, &input_dev->id);
825 input_dev->cdev.dev = &hid->intf->dev;
826
827 hidinput->input = input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 list_add_tail(&hidinput->list, &hid->inputs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 }
830
831 for (i = 0; i < report->maxfield; i++)
832 for (j = 0; j < report->field[i]->maxusage; j++)
833 hidinput_configure_usage(hidinput, report->field[i],
834 report->field[i]->usage + j);
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
837 /* This will leave hidinput NULL, so that it
838 * allocates another one if we have more inputs on
839 * the same interface. Some devices (e.g. Happ's
840 * UGCI) cram a lot of unrelated inputs into the
841 * same interface. */
842 hidinput->report = report;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500843 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 hidinput = NULL;
845 }
846 }
847
848 /* This only gets called when we are a single-input (most of the
849 * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
850 * only useful in this case, and not for multi-input quirks. */
851 if (hidinput) {
852 hid_ff_init(hid);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500853 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
855
856 return 0;
857}
858
859void hidinput_disconnect(struct hid_device *hid)
860{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500861 struct hid_input *hidinput, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500863 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 list_del(&hidinput->list);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500865 input_unregister_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 kfree(hidinput);
867 }
868}