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