blob: 9a808a3b4d3750e1a6e4a93a3c9cac1b98c1a667 [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
124static int usbhid_pb_fnmode = 1;
125module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
126MODULE_PARM_DESC(pb_fnmode,
127 "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
128
129static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
130{
131 struct hidinput_key_translation *trans;
132
133 /* Look for the translation */
134 for (trans = table; trans->from; trans++)
135 if (trans->from == from)
136 return trans;
137
138 return NULL;
139}
140
141static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
142 struct hid_usage *usage, __s32 value)
143{
144 struct hidinput_key_translation *trans;
145
146 if (usage->code == KEY_FN) {
147 if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON;
148 else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
149
150 input_event(input, usage->type, usage->code, value);
151
152 return 1;
153 }
154
155 if (usbhid_pb_fnmode) {
156 int do_translate;
157
158 trans = find_translation(powerbook_fn_keys, usage->code);
159 if (trans) {
160 if (test_bit(usage->code, hid->pb_pressed_fn))
161 do_translate = 1;
162 else if (trans->flags & POWERBOOK_FLAG_FKEY)
163 do_translate =
164 (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
165 (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
166 else
167 do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
168
169 if (do_translate) {
170 if (value)
171 set_bit(usage->code, hid->pb_pressed_fn);
172 else
173 clear_bit(usage->code, hid->pb_pressed_fn);
174
175 input_event(input, usage->type, trans->to, value);
176
177 return 1;
178 }
179 }
180
181 if (test_bit(usage->code, hid->pb_pressed_numlock) ||
182 test_bit(LED_NUML, input->led)) {
183 trans = find_translation(powerbook_numlock_keys, usage->code);
184
185 if (trans) {
186 if (value)
187 set_bit(usage->code, hid->pb_pressed_numlock);
188 else
189 clear_bit(usage->code, hid->pb_pressed_numlock);
190
191 input_event(input, usage->type, trans->to, value);
192 }
193
194 return 1;
195 }
196 }
197
198 return 0;
199}
200
201static void hidinput_pb_setup(struct input_dev *input)
202{
203 struct hidinput_key_translation *trans;
204
205 set_bit(KEY_NUMLOCK, input->keybit);
206
207 /* Enable all needed keys */
208 for (trans = powerbook_fn_keys; trans->from; trans++)
209 set_bit(trans->to, input->keybit);
210
211 for (trans = powerbook_numlock_keys; trans->from; trans++)
212 set_bit(trans->to, input->keybit);
213}
214#else
215static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
216 struct hid_usage *usage, __s32 value)
217{
218 return 0;
219}
220
221static inline void hidinput_pb_setup(struct input_dev *input)
222{
223}
224#endif
225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
227 struct hid_usage *usage)
228{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500229 struct input_dev *input = hidinput->input;
230 struct hid_device *device = input->private;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500231 int max = 0, code;
232 unsigned long *bit = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 field->hidinput = hidinput;
235
236#ifdef DEBUG
237 printk(KERN_DEBUG "Mapping: ");
238 resolv_usage(usage->hid);
239 printk(" ---> ");
240#endif
241
242 if (field->flags & HID_MAIN_ITEM_CONSTANT)
243 goto ignore;
244
245 switch (usage->hid & HID_USAGE_PAGE) {
246
247 case HID_UP_UNDEFINED:
248 goto ignore;
249
250 case HID_UP_KEYBOARD:
251
252 set_bit(EV_REP, input->evbit);
253
254 if ((usage->hid & HID_USAGE) < 256) {
255 if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
256 map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
257 } else
258 map_key(KEY_UNKNOWN);
259
260 break;
261
262 case HID_UP_BUTTON:
263
264 code = ((usage->hid - 1) & 0xf);
265
266 switch (field->application) {
267 case HID_GD_MOUSE:
268 case HID_GD_POINTER: code += 0x110; break;
269 case HID_GD_JOYSTICK: code += 0x120; break;
270 case HID_GD_GAMEPAD: code += 0x130; break;
271 default:
272 switch (field->physical) {
273 case HID_GD_MOUSE:
274 case HID_GD_POINTER: code += 0x110; break;
275 case HID_GD_JOYSTICK: code += 0x120; break;
276 case HID_GD_GAMEPAD: code += 0x130; break;
277 default: code += 0x100;
278 }
279 }
280
281 map_key(code);
282 break;
283
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500284
285 case HID_UP_SIMULATION:
286
287 switch (usage->hid & 0xffff) {
Dmitry Torokhov5fce9d7b2006-01-14 00:27:51 -0500288 case 0xba: map_abs(ABS_RUDDER); break;
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500289 case 0xbb: map_abs(ABS_THROTTLE); break;
Dmitry Torokhov5fce9d7b2006-01-14 00:27:51 -0500290 case 0xc4: map_abs(ABS_GAS); break;
291 case 0xc5: map_abs(ABS_BRAKE); break;
292 case 0xc8: map_abs(ABS_WHEEL); break;
Dmitry Torokhovff60dde2005-12-17 11:42:54 -0500293 default: goto ignore;
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500294 }
295 break;
296
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 case HID_UP_GENDESK:
298
299 if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
300 switch (usage->hid & 0xf) {
301 case 0x1: map_key_clear(KEY_POWER); break;
302 case 0x2: map_key_clear(KEY_SLEEP); break;
303 case 0x3: map_key_clear(KEY_WAKEUP); break;
304 default: goto unknown;
305 }
306 break;
307 }
308
309 if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
310 switch (usage->hid) {
311 case HID_GD_UP: usage->hat_dir = 1; break;
312 case HID_GD_DOWN: usage->hat_dir = 5; break;
313 case HID_GD_RIGHT: usage->hat_dir = 3; break;
314 case HID_GD_LEFT: usage->hat_dir = 7; break;
315 default: goto unknown;
316 }
317 if (field->dpad) {
318 map_abs(field->dpad);
319 goto ignore;
320 }
321 map_abs(ABS_HAT0X);
322 break;
323 }
324
325 switch (usage->hid) {
326
327 /* These usage IDs map directly to the usage codes. */
328 case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
329 case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
330 case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500331 if (field->flags & HID_MAIN_ITEM_RELATIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 map_rel(usage->hid & 0xf);
333 else
334 map_abs(usage->hid & 0xf);
335 break;
336
337 case HID_GD_HATSWITCH:
338 usage->hat_min = field->logical_minimum;
339 usage->hat_max = field->logical_maximum;
340 map_abs(ABS_HAT0X);
341 break;
342
343 case HID_GD_START: map_key_clear(BTN_START); break;
344 case HID_GD_SELECT: map_key_clear(BTN_SELECT); break;
345
346 default: goto unknown;
347 }
348
349 break;
350
351 case HID_UP_LED:
352 if (((usage->hid - 1) & 0xffff) >= LED_MAX)
353 goto ignore;
354 map_led((usage->hid - 1) & 0xffff);
355 break;
356
357 case HID_UP_DIGITIZER:
358
359 switch (usage->hid & 0xff) {
360
361 case 0x30: /* TipPressure */
362 if (!test_bit(BTN_TOUCH, input->keybit)) {
363 device->quirks |= HID_QUIRK_NOTOUCH;
364 set_bit(EV_KEY, input->evbit);
365 set_bit(BTN_TOUCH, input->keybit);
366 }
367
368 map_abs_clear(ABS_PRESSURE);
369 break;
370
371 case 0x32: /* InRange */
372 switch (field->physical & 0xff) {
373 case 0x21: map_key(BTN_TOOL_MOUSE); break;
374 case 0x22: map_key(BTN_TOOL_FINGER); break;
375 default: map_key(BTN_TOOL_PEN); break;
376 }
377 break;
378
379 case 0x3c: /* Invert */
380 map_key_clear(BTN_TOOL_RUBBER);
381 break;
382
383 case 0x33: /* Touch */
384 case 0x42: /* TipSwitch */
385 case 0x43: /* TipSwitch2 */
386 device->quirks &= ~HID_QUIRK_NOTOUCH;
387 map_key_clear(BTN_TOUCH);
388 break;
389
390 case 0x44: /* BarrelSwitch */
391 map_key_clear(BTN_STYLUS);
392 break;
393
394 default: goto unknown;
395 }
396 break;
397
398 case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
399
400 switch (usage->hid & HID_USAGE) {
401 case 0x000: goto ignore;
402 case 0x034: map_key_clear(KEY_SLEEP); break;
403 case 0x036: map_key_clear(BTN_MISC); break;
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500404 case 0x045: map_key_clear(KEY_RADIO); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 case 0x08a: map_key_clear(KEY_WWW); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500406 case 0x08d: map_key_clear(KEY_PROGRAM); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 case 0x095: map_key_clear(KEY_HELP); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500408 case 0x09c: map_key_clear(KEY_CHANNELUP); break;
409 case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 case 0x0b0: map_key_clear(KEY_PLAY); break;
411 case 0x0b1: map_key_clear(KEY_PAUSE); break;
412 case 0x0b2: map_key_clear(KEY_RECORD); break;
413 case 0x0b3: map_key_clear(KEY_FASTFORWARD); break;
414 case 0x0b4: map_key_clear(KEY_REWIND); break;
415 case 0x0b5: map_key_clear(KEY_NEXTSONG); break;
416 case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break;
417 case 0x0b7: map_key_clear(KEY_STOPCD); break;
418 case 0x0b8: map_key_clear(KEY_EJECTCD); break;
419 case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
420 case 0x0e0: map_abs_clear(ABS_VOLUME); break;
421 case 0x0e2: map_key_clear(KEY_MUTE); break;
422 case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
423 case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
424 case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
425 case 0x183: map_key_clear(KEY_CONFIG); break;
426 case 0x18a: map_key_clear(KEY_MAIL); break;
427 case 0x192: map_key_clear(KEY_CALC); break;
428 case 0x194: map_key_clear(KEY_FILE); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500429 case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
430 case 0x201: map_key_clear(KEY_NEW); break;
431 case 0x207: map_key_clear(KEY_SAVE); break;
432 case 0x208: map_key_clear(KEY_PRINT); break;
433 case 0x209: map_key_clear(KEY_PROPS); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 case 0x21a: map_key_clear(KEY_UNDO); break;
435 case 0x21b: map_key_clear(KEY_COPY); break;
436 case 0x21c: map_key_clear(KEY_CUT); break;
437 case 0x21d: map_key_clear(KEY_PASTE); break;
438 case 0x221: map_key_clear(KEY_FIND); break;
439 case 0x223: map_key_clear(KEY_HOMEPAGE); break;
440 case 0x224: map_key_clear(KEY_BACK); break;
441 case 0x225: map_key_clear(KEY_FORWARD); break;
442 case 0x226: map_key_clear(KEY_STOP); break;
443 case 0x227: map_key_clear(KEY_REFRESH); break;
444 case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500445 case 0x233: map_key_clear(KEY_SCROLLUP); break;
446 case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 case 0x238: map_rel(REL_HWHEEL); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500448 case 0x279: map_key_clear(KEY_REDO); break;
449 case 0x289: map_key_clear(KEY_REPLY); break;
450 case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
451 case 0x28c: map_key_clear(KEY_SEND); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500452
453 /* Reported on a Cherry Cymotion keyboard */
454 case 0x301: map_key_clear(KEY_PROG1); break;
455 case 0x302: map_key_clear(KEY_PROG2); break;
456 case 0x303: map_key_clear(KEY_PROG3); break;
457
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500458 default: goto ignore;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 }
460 break;
461
462 case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
463
464 set_bit(EV_REP, input->evbit);
465 switch (usage->hid & HID_USAGE) {
466 case 0x021: map_key_clear(KEY_PRINT); break;
467 case 0x070: map_key_clear(KEY_HP); break;
468 case 0x071: map_key_clear(KEY_CAMERA); break;
469 case 0x072: map_key_clear(KEY_SOUND); break;
470 case 0x073: map_key_clear(KEY_QUESTION); break;
471 case 0x080: map_key_clear(KEY_EMAIL); break;
472 case 0x081: map_key_clear(KEY_CHAT); break;
473 case 0x082: map_key_clear(KEY_SEARCH); break;
474 case 0x083: map_key_clear(KEY_CONNECT); break;
475 case 0x084: map_key_clear(KEY_FINANCE); break;
476 case 0x085: map_key_clear(KEY_SPORT); break;
477 case 0x086: map_key_clear(KEY_SHOP); break;
478 default: goto ignore;
479 }
480 break;
481
482 case HID_UP_MSVENDOR:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 goto ignore;
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500484
Stelian Pope875ce32005-09-05 01:57:33 -0500485 case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
486
487 set_bit(EV_REP, input->evbit);
488 switch(usage->hid & HID_USAGE) {
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500489 case 0x003:
490 /* The fn key on Apple PowerBooks */
491 map_key_clear(KEY_FN);
492 hidinput_pb_setup(input);
493 break;
494
Stelian Pope875ce32005-09-05 01:57:33 -0500495 default: goto ignore;
496 }
497 break;
498
499 case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500500
501 set_bit(EV_REP, input->evbit);
502 switch(usage->hid & HID_USAGE) {
503 case 0x004: map_key_clear(KEY_AGAIN); break;
504 case 0x00d: map_key_clear(KEY_HOME); break;
505 case 0x024: map_key_clear(KEY_SHUFFLE); break;
506 case 0x025: map_key_clear(KEY_TV); break;
507 case 0x026: map_key_clear(KEY_MENU); break;
508 case 0x031: map_key_clear(KEY_AUDIO); break;
Micah F. Galizia50a598d2006-03-14 00:09:34 -0500509 case 0x032: map_key_clear(KEY_TEXT); break;
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500510 case 0x033: map_key_clear(KEY_LAST); break;
511 case 0x047: map_key_clear(KEY_MP3); break;
512 case 0x048: map_key_clear(KEY_DVD); break;
513 case 0x049: map_key_clear(KEY_MEDIA); break;
514 case 0x04a: map_key_clear(KEY_VIDEO); break;
515 case 0x04b: map_key_clear(KEY_ANGLE); break;
516 case 0x04c: map_key_clear(KEY_LANGUAGE); break;
517 case 0x04d: map_key_clear(KEY_SUBTITLE); break;
518 case 0x051: map_key_clear(KEY_RED); break;
519 case 0x052: map_key_clear(KEY_CLOSE); break;
520 default: goto ignore;
521 }
522 break;
523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 case HID_UP_PID:
525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 switch(usage->hid & HID_USAGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 case 0xa4: map_key_clear(BTN_DEAD); break;
528 default: goto ignore;
529 }
530 break;
531
532 default:
533 unknown:
534 if (field->report_size == 1) {
535 if (field->report->type == HID_OUTPUT_REPORT) {
536 map_led(LED_MISC);
537 break;
538 }
539 map_key(BTN_MISC);
540 break;
541 }
542 if (field->flags & HID_MAIN_ITEM_RELATIVE) {
543 map_rel(REL_MISC);
544 break;
545 }
546 map_abs(ABS_MISC);
547 break;
548 }
549
Bart Masseya82e49b2006-05-08 14:40:13 -0700550 if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
551 if (usage->hid == HID_GD_Z)
552 map_rel(REL_HWHEEL);
553 else if (usage->code == BTN_1)
554 map_key(BTN_2);
555 else if (usage->code == BTN_2)
556 map_key(BTN_1);
557 }
Vojtech Pavlikc58de6d2005-09-05 00:13:15 -0500558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500560 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 set_bit(REL_HWHEEL, bit);
562
563 if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
564 || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
565 goto ignore;
566
Bart Masseya82e49b2006-05-08 14:40:13 -0700567 set_bit(usage->type, input->evbit);
568
569 while (usage->code <= max && test_and_set_bit(usage->code, bit))
570 usage->code = find_next_zero_bit(bit, max + 1, usage->code);
571
572 if (usage->code > max)
573 goto ignore;
574
575
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 if (usage->type == EV_ABS) {
577
578 int a = field->logical_minimum;
579 int b = field->logical_maximum;
580
581 if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) {
582 a = field->logical_minimum = 0;
583 b = field->logical_maximum = 255;
584 }
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
587 input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
588 else input_set_abs_params(input, usage->code, a, b, 0, 0);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
591
Dmitry Torokhovcb786232006-07-15 01:17:54 -0400592 if (usage->type == EV_ABS &&
593 (usage->hat_min < usage->hat_max || usage->hat_dir)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 int i;
595 for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
596 input_set_abs_params(input, i, -1, 1, 0, 0);
597 set_bit(i, input->absbit);
598 }
599 if (usage->hat_dir && !field->dpad)
600 field->dpad = usage->code;
601 }
602
603#ifdef DEBUG
604 resolv_event(usage->type, usage->code);
605 printk("\n");
606#endif
607 return;
608
609ignore:
610#ifdef DEBUG
611 printk("IGNORED\n");
612#endif
613 return;
614}
615
David Howells7d12e782006-10-05 14:55:46 +0100616void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700618 struct input_dev *input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 int *quirks = &hid->quirks;
620
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700621 if (!field->hidinput)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500623
624 input = field->hidinput->input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 if (!usage->type)
627 return;
628
629 if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
630 || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
631 if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
632 else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
633 return;
634 }
635
Bart Masseya82e49b2006-05-08 14:40:13 -0700636 if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
637 input_event(input, usage->type, usage->code, -value);
638 return;
639 }
640
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
642 input_event(input, usage->type, REL_HWHEEL, value);
643 return;
644 }
645
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500646 if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
647 return;
648
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500649 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 int hat_dir = usage->hat_dir;
651 if (!hat_dir)
652 hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
653 if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
654 input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x);
655 input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
656 return;
657 }
658
659 if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
660 *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
661 return;
662 }
663
664 if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
665 if (value) {
666 input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
667 return;
668 }
669 input_event(input, usage->type, usage->code, 0);
670 input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
671 return;
672 }
673
674 if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
675 int a = field->logical_minimum;
676 int b = field->logical_maximum;
677 input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
678 }
679
680 if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
Anssi Hannula224ee882006-07-19 01:40:47 -0400681 dbg("Maximum Effects - %d",value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 return;
683 }
684
685 if (usage->hid == (HID_UP_PID | 0x7fUL)) {
686 dbg("PID Pool Report\n");
687 return;
688 }
689
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500690 if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return;
692
693 input_event(input, usage->type, usage->code, value);
694
695 if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
696 input_event(input, usage->type, usage->code, 0);
697}
698
699void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
700{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 struct hid_input *hidinput;
702
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500703 list_for_each_entry(hidinput, &hid->inputs, list)
704 input_sync(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705}
706
707static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
708{
709 struct hid_report *report;
710 int i, j;
711
712 list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
713 for (i = 0; i < report->maxfield; i++) {
714 *field = report->field[i];
715 for (j = 0; j < (*field)->maxusage; j++)
716 if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
717 return j;
718 }
719 }
720 return -1;
721}
722
723static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
724{
725 struct hid_device *hid = dev->private;
726 struct hid_field *field;
727 int offset;
728
729 if (type == EV_FF)
Anssi Hannuladc76c912006-07-19 01:40:55 -0400730 return input_ff_event(dev, type, code, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
732 if (type != EV_LED)
733 return -1;
734
735 if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
736 warn("event field not found");
737 return -1;
738 }
739
740 hid_set_field(field, offset, value);
741 hid_submit_report(hid, field->report, USB_DIR_OUT);
742
743 return 0;
744}
745
746static int hidinput_open(struct input_dev *dev)
747{
748 struct hid_device *hid = dev->private;
749 return hid_open(hid);
750}
751
752static void hidinput_close(struct input_dev *dev)
753{
754 struct hid_device *hid = dev->private;
755 hid_close(hid);
756}
757
758/*
759 * Register the input device; print a message.
760 * Configure the input layer interface
761 * Read all reports and initialize the absolute field values.
762 */
763
764int hidinput_connect(struct hid_device *hid)
765{
766 struct usb_device *dev = hid->dev;
767 struct hid_report *report;
768 struct hid_input *hidinput = NULL;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500769 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 int i, j, k;
771
772 INIT_LIST_HEAD(&hid->inputs);
773
774 for (i = 0; i < hid->maxcollection; i++)
775 if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
776 hid->collection[i].type == HID_COLLECTION_PHYSICAL)
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500777 if (IS_INPUT_APPLICATION(hid->collection[i].usage))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 break;
779
780 if (i == hid->maxcollection)
781 return -1;
782
783 for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
784 list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
785
786 if (!report->maxfield)
787 continue;
788
789 if (!hidinput) {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500790 hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
791 input_dev = input_allocate_device();
792 if (!hidinput || !input_dev) {
793 kfree(hidinput);
794 input_free_device(input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 err("Out of memory during hid input probe");
796 return -1;
797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500799 input_dev->private = hid;
800 input_dev->event = hidinput_input_event;
801 input_dev->open = hidinput_open;
802 input_dev->close = hidinput_close;
803
804 input_dev->name = hid->name;
805 input_dev->phys = hid->phys;
806 input_dev->uniq = hid->uniq;
807 usb_to_input_id(dev, &input_dev->id);
808 input_dev->cdev.dev = &hid->intf->dev;
809
810 hidinput->input = input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 list_add_tail(&hidinput->list, &hid->inputs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 }
813
814 for (i = 0; i < report->maxfield; i++)
815 for (j = 0; j < report->field[i]->maxusage; j++)
816 hidinput_configure_usage(hidinput, report->field[i],
817 report->field[i]->usage + j);
Dmitry Torokhov05f091ab2005-05-29 02:29:01 -0500818
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
820 /* This will leave hidinput NULL, so that it
821 * allocates another one if we have more inputs on
822 * the same interface. Some devices (e.g. Happ's
823 * UGCI) cram a lot of unrelated inputs into the
824 * same interface. */
825 hidinput->report = report;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500826 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 hidinput = NULL;
828 }
829 }
830
831 /* This only gets called when we are a single-input (most of the
832 * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
833 * only useful in this case, and not for multi-input quirks. */
834 if (hidinput) {
835 hid_ff_init(hid);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500836 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
838
839 return 0;
840}
841
842void hidinput_disconnect(struct hid_device *hid)
843{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500844 struct hid_input *hidinput, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500846 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 list_del(&hidinput->list);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500848 input_unregister_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 kfree(hidinput);
850 }
851}