blob: 7208839f2dbf24d50c15516b7d99971980f8160d [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)
68#define map_ff(c) do { usage->code = c; usage->type = EV_FF; bit = input->ffbit; max = FF_MAX; } while (0)
69
70#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
71#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
72#define map_ff_effect(c) do { set_bit(c, input->ffbit); } while (0)
73
Michael Hanselmanneab9edd2006-01-14 10:08:06 -050074#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
75
76struct hidinput_key_translation {
77 u16 from;
78 u16 to;
79 u8 flags;
80};
81
82#define POWERBOOK_FLAG_FKEY 0x01
83
84static struct hidinput_key_translation powerbook_fn_keys[] = {
85 { KEY_BACKSPACE, KEY_DELETE },
86 { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY },
87 { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY },
88 { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY },
89 { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY },
90 { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY },
91 { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY },
92 { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY },
93 { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY },
94 { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY },
95 { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY },
96 { KEY_UP, KEY_PAGEUP },
97 { KEY_DOWN, KEY_PAGEDOWN },
98 { KEY_LEFT, KEY_HOME },
99 { KEY_RIGHT, KEY_END },
100 { }
101};
102
103static struct hidinput_key_translation powerbook_numlock_keys[] = {
104 { KEY_J, KEY_KP1 },
105 { KEY_K, KEY_KP2 },
106 { KEY_L, KEY_KP3 },
107 { KEY_U, KEY_KP4 },
108 { KEY_I, KEY_KP5 },
109 { KEY_O, KEY_KP6 },
110 { KEY_7, KEY_KP7 },
111 { KEY_8, KEY_KP8 },
112 { KEY_9, KEY_KP9 },
113 { KEY_M, KEY_KP0 },
114 { KEY_DOT, KEY_KPDOT },
115 { KEY_SLASH, KEY_KPPLUS },
116 { KEY_SEMICOLON, KEY_KPMINUS },
117 { KEY_P, KEY_KPASTERISK },
118 { KEY_MINUS, KEY_KPEQUAL },
119 { KEY_0, KEY_KPSLASH },
120 { KEY_F6, KEY_NUMLOCK },
121 { KEY_KPENTER, KEY_KPENTER },
122 { KEY_BACKSPACE, KEY_BACKSPACE },
123 { }
124};
125
126static int usbhid_pb_fnmode = 1;
127module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
128MODULE_PARM_DESC(pb_fnmode,
129 "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
130
131static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
132{
133 struct hidinput_key_translation *trans;
134
135 /* Look for the translation */
136 for (trans = table; trans->from; trans++)
137 if (trans->from == from)
138 return trans;
139
140 return NULL;
141}
142
143static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
144 struct hid_usage *usage, __s32 value)
145{
146 struct hidinput_key_translation *trans;
147
148 if (usage->code == KEY_FN) {
149 if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON;
150 else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
151
152 input_event(input, usage->type, usage->code, value);
153
154 return 1;
155 }
156
157 if (usbhid_pb_fnmode) {
158 int do_translate;
159
160 trans = find_translation(powerbook_fn_keys, usage->code);
161 if (trans) {
162 if (test_bit(usage->code, hid->pb_pressed_fn))
163 do_translate = 1;
164 else if (trans->flags & POWERBOOK_FLAG_FKEY)
165 do_translate =
166 (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
167 (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
168 else
169 do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
170
171 if (do_translate) {
172 if (value)
173 set_bit(usage->code, hid->pb_pressed_fn);
174 else
175 clear_bit(usage->code, hid->pb_pressed_fn);
176
177 input_event(input, usage->type, trans->to, value);
178
179 return 1;
180 }
181 }
182
183 if (test_bit(usage->code, hid->pb_pressed_numlock) ||
184 test_bit(LED_NUML, input->led)) {
185 trans = find_translation(powerbook_numlock_keys, usage->code);
186
187 if (trans) {
188 if (value)
189 set_bit(usage->code, hid->pb_pressed_numlock);
190 else
191 clear_bit(usage->code, hid->pb_pressed_numlock);
192
193 input_event(input, usage->type, trans->to, value);
194 }
195
196 return 1;
197 }
198 }
199
200 return 0;
201}
202
203static void hidinput_pb_setup(struct input_dev *input)
204{
205 struct hidinput_key_translation *trans;
206
207 set_bit(KEY_NUMLOCK, input->keybit);
208
209 /* Enable all needed keys */
210 for (trans = powerbook_fn_keys; trans->from; trans++)
211 set_bit(trans->to, input->keybit);
212
213 for (trans = powerbook_numlock_keys; trans->from; trans++)
214 set_bit(trans->to, input->keybit);
215}
216#else
217static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
218 struct hid_usage *usage, __s32 value)
219{
220 return 0;
221}
222
223static inline void hidinput_pb_setup(struct input_dev *input)
224{
225}
226#endif
227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
229 struct hid_usage *usage)
230{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500231 struct input_dev *input = hidinput->input;
232 struct hid_device *device = input->private;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500233 int max = 0, code;
234 unsigned long *bit = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
236 field->hidinput = hidinput;
237
238#ifdef DEBUG
239 printk(KERN_DEBUG "Mapping: ");
240 resolv_usage(usage->hid);
241 printk(" ---> ");
242#endif
243
244 if (field->flags & HID_MAIN_ITEM_CONSTANT)
245 goto ignore;
246
247 switch (usage->hid & HID_USAGE_PAGE) {
248
249 case HID_UP_UNDEFINED:
250 goto ignore;
251
252 case HID_UP_KEYBOARD:
253
254 set_bit(EV_REP, input->evbit);
255
256 if ((usage->hid & HID_USAGE) < 256) {
257 if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
258 map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
259 } else
260 map_key(KEY_UNKNOWN);
261
262 break;
263
264 case HID_UP_BUTTON:
265
266 code = ((usage->hid - 1) & 0xf);
267
268 switch (field->application) {
269 case HID_GD_MOUSE:
270 case HID_GD_POINTER: code += 0x110; break;
271 case HID_GD_JOYSTICK: code += 0x120; break;
272 case HID_GD_GAMEPAD: code += 0x130; break;
273 default:
274 switch (field->physical) {
275 case HID_GD_MOUSE:
276 case HID_GD_POINTER: code += 0x110; break;
277 case HID_GD_JOYSTICK: code += 0x120; break;
278 case HID_GD_GAMEPAD: code += 0x130; break;
279 default: code += 0x100;
280 }
281 }
282
283 map_key(code);
284 break;
285
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500286
287 case HID_UP_SIMULATION:
288
289 switch (usage->hid & 0xffff) {
Dmitry Torokhov5fce9d7b2006-01-14 00:27:51 -0500290 case 0xba: map_abs(ABS_RUDDER); break;
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500291 case 0xbb: map_abs(ABS_THROTTLE); break;
Dmitry Torokhov5fce9d7b2006-01-14 00:27:51 -0500292 case 0xc4: map_abs(ABS_GAS); break;
293 case 0xc5: map_abs(ABS_BRAKE); break;
294 case 0xc8: map_abs(ABS_WHEEL); break;
Dmitry Torokhovff60dde2005-12-17 11:42:54 -0500295 default: goto ignore;
Vojtech Pavlik0aebfda2005-09-05 00:07:59 -0500296 }
297 break;
298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 case HID_UP_GENDESK:
300
301 if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
302 switch (usage->hid & 0xf) {
303 case 0x1: map_key_clear(KEY_POWER); break;
304 case 0x2: map_key_clear(KEY_SLEEP); break;
305 case 0x3: map_key_clear(KEY_WAKEUP); break;
306 default: goto unknown;
307 }
308 break;
309 }
310
311 if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
312 switch (usage->hid) {
313 case HID_GD_UP: usage->hat_dir = 1; break;
314 case HID_GD_DOWN: usage->hat_dir = 5; break;
315 case HID_GD_RIGHT: usage->hat_dir = 3; break;
316 case HID_GD_LEFT: usage->hat_dir = 7; break;
317 default: goto unknown;
318 }
319 if (field->dpad) {
320 map_abs(field->dpad);
321 goto ignore;
322 }
323 map_abs(ABS_HAT0X);
324 break;
325 }
326
327 switch (usage->hid) {
328
329 /* These usage IDs map directly to the usage codes. */
330 case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
331 case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
332 case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500333 if (field->flags & HID_MAIN_ITEM_RELATIVE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 map_rel(usage->hid & 0xf);
335 else
336 map_abs(usage->hid & 0xf);
337 break;
338
339 case HID_GD_HATSWITCH:
340 usage->hat_min = field->logical_minimum;
341 usage->hat_max = field->logical_maximum;
342 map_abs(ABS_HAT0X);
343 break;
344
345 case HID_GD_START: map_key_clear(BTN_START); break;
346 case HID_GD_SELECT: map_key_clear(BTN_SELECT); break;
347
348 default: goto unknown;
349 }
350
351 break;
352
353 case HID_UP_LED:
354 if (((usage->hid - 1) & 0xffff) >= LED_MAX)
355 goto ignore;
356 map_led((usage->hid - 1) & 0xffff);
357 break;
358
359 case HID_UP_DIGITIZER:
360
361 switch (usage->hid & 0xff) {
362
363 case 0x30: /* TipPressure */
364 if (!test_bit(BTN_TOUCH, input->keybit)) {
365 device->quirks |= HID_QUIRK_NOTOUCH;
366 set_bit(EV_KEY, input->evbit);
367 set_bit(BTN_TOUCH, input->keybit);
368 }
369
370 map_abs_clear(ABS_PRESSURE);
371 break;
372
373 case 0x32: /* InRange */
374 switch (field->physical & 0xff) {
375 case 0x21: map_key(BTN_TOOL_MOUSE); break;
376 case 0x22: map_key(BTN_TOOL_FINGER); break;
377 default: map_key(BTN_TOOL_PEN); break;
378 }
379 break;
380
381 case 0x3c: /* Invert */
382 map_key_clear(BTN_TOOL_RUBBER);
383 break;
384
385 case 0x33: /* Touch */
386 case 0x42: /* TipSwitch */
387 case 0x43: /* TipSwitch2 */
388 device->quirks &= ~HID_QUIRK_NOTOUCH;
389 map_key_clear(BTN_TOUCH);
390 break;
391
392 case 0x44: /* BarrelSwitch */
393 map_key_clear(BTN_STYLUS);
394 break;
395
396 default: goto unknown;
397 }
398 break;
399
400 case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
401
402 switch (usage->hid & HID_USAGE) {
403 case 0x000: goto ignore;
404 case 0x034: map_key_clear(KEY_SLEEP); break;
405 case 0x036: map_key_clear(BTN_MISC); break;
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500406 case 0x045: map_key_clear(KEY_RADIO); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 case 0x08a: map_key_clear(KEY_WWW); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500408 case 0x08d: map_key_clear(KEY_PROGRAM); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 case 0x095: map_key_clear(KEY_HELP); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500410 case 0x09c: map_key_clear(KEY_CHANNELUP); break;
411 case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 case 0x0b0: map_key_clear(KEY_PLAY); break;
413 case 0x0b1: map_key_clear(KEY_PAUSE); break;
414 case 0x0b2: map_key_clear(KEY_RECORD); break;
415 case 0x0b3: map_key_clear(KEY_FASTFORWARD); break;
416 case 0x0b4: map_key_clear(KEY_REWIND); break;
417 case 0x0b5: map_key_clear(KEY_NEXTSONG); break;
418 case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break;
419 case 0x0b7: map_key_clear(KEY_STOPCD); break;
420 case 0x0b8: map_key_clear(KEY_EJECTCD); break;
421 case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
422 case 0x0e0: map_abs_clear(ABS_VOLUME); break;
423 case 0x0e2: map_key_clear(KEY_MUTE); break;
424 case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
425 case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
426 case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
427 case 0x183: map_key_clear(KEY_CONFIG); break;
428 case 0x18a: map_key_clear(KEY_MAIL); break;
429 case 0x192: map_key_clear(KEY_CALC); break;
430 case 0x194: map_key_clear(KEY_FILE); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500431 case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
432 case 0x201: map_key_clear(KEY_NEW); break;
433 case 0x207: map_key_clear(KEY_SAVE); break;
434 case 0x208: map_key_clear(KEY_PRINT); break;
435 case 0x209: map_key_clear(KEY_PROPS); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 case 0x21a: map_key_clear(KEY_UNDO); break;
437 case 0x21b: map_key_clear(KEY_COPY); break;
438 case 0x21c: map_key_clear(KEY_CUT); break;
439 case 0x21d: map_key_clear(KEY_PASTE); break;
440 case 0x221: map_key_clear(KEY_FIND); break;
441 case 0x223: map_key_clear(KEY_HOMEPAGE); break;
442 case 0x224: map_key_clear(KEY_BACK); break;
443 case 0x225: map_key_clear(KEY_FORWARD); break;
444 case 0x226: map_key_clear(KEY_STOP); break;
445 case 0x227: map_key_clear(KEY_REFRESH); break;
446 case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500447 case 0x233: map_key_clear(KEY_SCROLLUP); break;
448 case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 case 0x238: map_rel(REL_HWHEEL); break;
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500450 case 0x279: map_key_clear(KEY_REDO); break;
451 case 0x289: map_key_clear(KEY_REPLY); break;
452 case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
453 case 0x28c: map_key_clear(KEY_SEND); break;
Vojtech Pavlik940824b2006-01-14 00:25:39 -0500454
455 /* Reported on a Cherry Cymotion keyboard */
456 case 0x301: map_key_clear(KEY_PROG1); break;
457 case 0x302: map_key_clear(KEY_PROG2); break;
458 case 0x303: map_key_clear(KEY_PROG3); break;
459
Vojtech Pavlik8a409b02005-09-05 00:08:08 -0500460 default: goto ignore;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
462 break;
463
464 case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
465
466 set_bit(EV_REP, input->evbit);
467 switch (usage->hid & HID_USAGE) {
468 case 0x021: map_key_clear(KEY_PRINT); break;
469 case 0x070: map_key_clear(KEY_HP); break;
470 case 0x071: map_key_clear(KEY_CAMERA); break;
471 case 0x072: map_key_clear(KEY_SOUND); break;
472 case 0x073: map_key_clear(KEY_QUESTION); break;
473 case 0x080: map_key_clear(KEY_EMAIL); break;
474 case 0x081: map_key_clear(KEY_CHAT); break;
475 case 0x082: map_key_clear(KEY_SEARCH); break;
476 case 0x083: map_key_clear(KEY_CONNECT); break;
477 case 0x084: map_key_clear(KEY_FINANCE); break;
478 case 0x085: map_key_clear(KEY_SPORT); break;
479 case 0x086: map_key_clear(KEY_SHOP); break;
480 default: goto ignore;
481 }
482 break;
483
484 case HID_UP_MSVENDOR:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 goto ignore;
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500486
Stelian Pope875ce32005-09-05 01:57:33 -0500487 case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
488
489 set_bit(EV_REP, input->evbit);
490 switch(usage->hid & HID_USAGE) {
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500491 case 0x003:
492 /* The fn key on Apple PowerBooks */
493 map_key_clear(KEY_FN);
494 hidinput_pb_setup(input);
495 break;
496
Stelian Pope875ce32005-09-05 01:57:33 -0500497 default: goto ignore;
498 }
499 break;
500
501 case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500502
503 set_bit(EV_REP, input->evbit);
504 switch(usage->hid & HID_USAGE) {
505 case 0x004: map_key_clear(KEY_AGAIN); break;
506 case 0x00d: map_key_clear(KEY_HOME); break;
507 case 0x024: map_key_clear(KEY_SHUFFLE); break;
508 case 0x025: map_key_clear(KEY_TV); break;
509 case 0x026: map_key_clear(KEY_MENU); break;
510 case 0x031: map_key_clear(KEY_AUDIO); break;
Micah F. Galizia50a598d2006-03-14 00:09:34 -0500511 case 0x032: map_key_clear(KEY_TEXT); break;
Micah F. Galizia39fd7482005-09-05 00:12:15 -0500512 case 0x033: map_key_clear(KEY_LAST); break;
513 case 0x047: map_key_clear(KEY_MP3); break;
514 case 0x048: map_key_clear(KEY_DVD); break;
515 case 0x049: map_key_clear(KEY_MEDIA); break;
516 case 0x04a: map_key_clear(KEY_VIDEO); break;
517 case 0x04b: map_key_clear(KEY_ANGLE); break;
518 case 0x04c: map_key_clear(KEY_LANGUAGE); break;
519 case 0x04d: map_key_clear(KEY_SUBTITLE); break;
520 case 0x051: map_key_clear(KEY_RED); break;
521 case 0x052: map_key_clear(KEY_CLOSE); break;
522 default: goto ignore;
523 }
524 break;
525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 case HID_UP_PID:
527
528 set_bit(EV_FF, input->evbit);
529 switch(usage->hid & HID_USAGE) {
530 case 0x26: map_ff_effect(FF_CONSTANT); goto ignore;
531 case 0x27: map_ff_effect(FF_RAMP); goto ignore;
532 case 0x28: map_ff_effect(FF_CUSTOM); goto ignore;
533 case 0x30: map_ff_effect(FF_SQUARE); map_ff_effect(FF_PERIODIC); goto ignore;
534 case 0x31: map_ff_effect(FF_SINE); map_ff_effect(FF_PERIODIC); goto ignore;
535 case 0x32: map_ff_effect(FF_TRIANGLE); map_ff_effect(FF_PERIODIC); goto ignore;
536 case 0x33: map_ff_effect(FF_SAW_UP); map_ff_effect(FF_PERIODIC); goto ignore;
537 case 0x34: map_ff_effect(FF_SAW_DOWN); map_ff_effect(FF_PERIODIC); goto ignore;
538 case 0x40: map_ff_effect(FF_SPRING); goto ignore;
539 case 0x41: map_ff_effect(FF_DAMPER); goto ignore;
540 case 0x42: map_ff_effect(FF_INERTIA); goto ignore;
541 case 0x43: map_ff_effect(FF_FRICTION); goto ignore;
542 case 0x7e: map_ff(FF_GAIN); break;
543 case 0x83: input->ff_effects_max = field->value[0]; goto ignore;
544 case 0x98: map_ff(FF_AUTOCENTER); break;
545 case 0xa4: map_key_clear(BTN_DEAD); break;
546 default: goto ignore;
547 }
548 break;
549
550 default:
551 unknown:
552 if (field->report_size == 1) {
553 if (field->report->type == HID_OUTPUT_REPORT) {
554 map_led(LED_MISC);
555 break;
556 }
557 map_key(BTN_MISC);
558 break;
559 }
560 if (field->flags & HID_MAIN_ITEM_RELATIVE) {
561 map_rel(REL_MISC);
562 break;
563 }
564 map_abs(ABS_MISC);
565 break;
566 }
567
Bart Masseya82e49b2006-05-08 14:40:13 -0700568 if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
569 if (usage->hid == HID_GD_Z)
570 map_rel(REL_HWHEEL);
571 else if (usage->code == BTN_1)
572 map_key(BTN_2);
573 else if (usage->code == BTN_2)
574 map_key(BTN_1);
575 }
Vojtech Pavlikc58de6d2005-09-05 00:13:15 -0500576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500578 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 set_bit(REL_HWHEEL, bit);
580
581 if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
582 || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
583 goto ignore;
584
Bart Masseya82e49b2006-05-08 14:40:13 -0700585 set_bit(usage->type, input->evbit);
586
587 while (usage->code <= max && test_and_set_bit(usage->code, bit))
588 usage->code = find_next_zero_bit(bit, max + 1, usage->code);
589
590 if (usage->code > max)
591 goto ignore;
592
593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 if (usage->type == EV_ABS) {
595
596 int a = field->logical_minimum;
597 int b = field->logical_maximum;
598
599 if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) {
600 a = field->logical_minimum = 0;
601 b = field->logical_maximum = 255;
602 }
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
605 input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
606 else input_set_abs_params(input, usage->code, a, b, 0, 0);
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
609
Dmitry Torokhovcb786232006-07-15 01:17:54 -0400610 if (usage->type == EV_ABS &&
611 (usage->hat_min < usage->hat_max || usage->hat_dir)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 int i;
613 for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
614 input_set_abs_params(input, i, -1, 1, 0, 0);
615 set_bit(i, input->absbit);
616 }
617 if (usage->hat_dir && !field->dpad)
618 field->dpad = usage->code;
619 }
620
621#ifdef DEBUG
622 resolv_event(usage->type, usage->code);
623 printk("\n");
624#endif
625 return;
626
627ignore:
628#ifdef DEBUG
629 printk("IGNORED\n");
630#endif
631 return;
632}
633
634void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs)
635{
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700636 struct input_dev *input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 int *quirks = &hid->quirks;
638
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700639 if (!field->hidinput)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 return;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500641
642 input = field->hidinput->input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 input_regs(input, regs);
645
646 if (!usage->type)
647 return;
648
649 if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
650 || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
651 if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
652 else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
653 return;
654 }
655
Bart Masseya82e49b2006-05-08 14:40:13 -0700656 if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
657 input_event(input, usage->type, usage->code, -value);
658 return;
659 }
660
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
662 input_event(input, usage->type, REL_HWHEEL, value);
663 return;
664 }
665
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500666 if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
667 return;
668
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500669 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 int hat_dir = usage->hat_dir;
671 if (!hat_dir)
672 hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
673 if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
674 input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x);
675 input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
676 return;
677 }
678
679 if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
680 *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
681 return;
682 }
683
684 if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
685 if (value) {
686 input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
687 return;
688 }
689 input_event(input, usage->type, usage->code, 0);
690 input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
691 return;
692 }
693
694 if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
695 int a = field->logical_minimum;
696 int b = field->logical_maximum;
697 input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
698 }
699
700 if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
701 input->ff_effects_max = value;
702 dbg("Maximum Effects - %d",input->ff_effects_max);
703 return;
704 }
705
706 if (usage->hid == (HID_UP_PID | 0x7fUL)) {
707 dbg("PID Pool Report\n");
708 return;
709 }
710
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500711 if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 return;
713
714 input_event(input, usage->type, usage->code, value);
715
716 if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
717 input_event(input, usage->type, usage->code, 0);
718}
719
720void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
721{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 struct hid_input *hidinput;
723
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500724 list_for_each_entry(hidinput, &hid->inputs, list)
725 input_sync(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726}
727
728static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
729{
730 struct hid_report *report;
731 int i, j;
732
733 list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
734 for (i = 0; i < report->maxfield; i++) {
735 *field = report->field[i];
736 for (j = 0; j < (*field)->maxusage; j++)
737 if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
738 return j;
739 }
740 }
741 return -1;
742}
743
744static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
745{
746 struct hid_device *hid = dev->private;
747 struct hid_field *field;
748 int offset;
749
750 if (type == EV_FF)
751 return hid_ff_event(hid, dev, type, code, value);
752
753 if (type != EV_LED)
754 return -1;
755
756 if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
757 warn("event field not found");
758 return -1;
759 }
760
761 hid_set_field(field, offset, value);
762 hid_submit_report(hid, field->report, USB_DIR_OUT);
763
764 return 0;
765}
766
767static int hidinput_open(struct input_dev *dev)
768{
769 struct hid_device *hid = dev->private;
770 return hid_open(hid);
771}
772
773static void hidinput_close(struct input_dev *dev)
774{
775 struct hid_device *hid = dev->private;
776 hid_close(hid);
777}
778
779/*
780 * Register the input device; print a message.
781 * Configure the input layer interface
782 * Read all reports and initialize the absolute field values.
783 */
784
785int hidinput_connect(struct hid_device *hid)
786{
787 struct usb_device *dev = hid->dev;
788 struct hid_report *report;
789 struct hid_input *hidinput = NULL;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500790 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 int i, j, k;
792
793 INIT_LIST_HEAD(&hid->inputs);
794
795 for (i = 0; i < hid->maxcollection; i++)
796 if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
797 hid->collection[i].type == HID_COLLECTION_PHYSICAL)
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500798 if (IS_INPUT_APPLICATION(hid->collection[i].usage))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 break;
800
801 if (i == hid->maxcollection)
802 return -1;
803
804 for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
805 list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
806
807 if (!report->maxfield)
808 continue;
809
810 if (!hidinput) {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500811 hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
812 input_dev = input_allocate_device();
813 if (!hidinput || !input_dev) {
814 kfree(hidinput);
815 input_free_device(input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 err("Out of memory during hid input probe");
817 return -1;
818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500820 input_dev->private = hid;
821 input_dev->event = hidinput_input_event;
822 input_dev->open = hidinput_open;
823 input_dev->close = hidinput_close;
824
825 input_dev->name = hid->name;
826 input_dev->phys = hid->phys;
827 input_dev->uniq = hid->uniq;
828 usb_to_input_id(dev, &input_dev->id);
829 input_dev->cdev.dev = &hid->intf->dev;
830
831 hidinput->input = input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 list_add_tail(&hidinput->list, &hid->inputs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 }
834
835 for (i = 0; i < report->maxfield; i++)
836 for (j = 0; j < report->field[i]->maxusage; j++)
837 hidinput_configure_usage(hidinput, report->field[i],
838 report->field[i]->usage + j);
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
841 /* This will leave hidinput NULL, so that it
842 * allocates another one if we have more inputs on
843 * the same interface. Some devices (e.g. Happ's
844 * UGCI) cram a lot of unrelated inputs into the
845 * same interface. */
846 hidinput->report = report;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500847 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 hidinput = NULL;
849 }
850 }
851
852 /* This only gets called when we are a single-input (most of the
853 * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
854 * only useful in this case, and not for multi-input quirks. */
855 if (hidinput) {
856 hid_ff_init(hid);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500857 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 }
859
860 return 0;
861}
862
863void hidinput_disconnect(struct hid_device *hid)
864{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500865 struct hid_input *hidinput, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500867 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 list_del(&hidinput->list);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500869 input_unregister_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 kfree(hidinput);
871 }
872}