blob: 028e1ad89f5d96471f08bbb36a96c6d3ee33e121 [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
610 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
611 int i;
612 for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
613 input_set_abs_params(input, i, -1, 1, 0, 0);
614 set_bit(i, input->absbit);
615 }
616 if (usage->hat_dir && !field->dpad)
617 field->dpad = usage->code;
618 }
619
620#ifdef DEBUG
621 resolv_event(usage->type, usage->code);
622 printk("\n");
623#endif
624 return;
625
626ignore:
627#ifdef DEBUG
628 printk("IGNORED\n");
629#endif
630 return;
631}
632
633void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs)
634{
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700635 struct input_dev *input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 int *quirks = &hid->quirks;
637
Pete Zaitceva9b2e912005-07-29 12:18:34 -0700638 if (!field->hidinput)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500640
641 input = field->hidinput->input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643 input_regs(input, regs);
644
645 if (!usage->type)
646 return;
647
648 if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
649 || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
650 if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
651 else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
652 return;
653 }
654
Bart Masseya82e49b2006-05-08 14:40:13 -0700655 if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
656 input_event(input, usage->type, usage->code, -value);
657 return;
658 }
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
661 input_event(input, usage->type, REL_HWHEEL, value);
662 return;
663 }
664
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500665 if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
666 return;
667
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500668 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 int hat_dir = usage->hat_dir;
670 if (!hat_dir)
671 hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
672 if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
673 input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x);
674 input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
675 return;
676 }
677
678 if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
679 *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
680 return;
681 }
682
683 if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
684 if (value) {
685 input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
686 return;
687 }
688 input_event(input, usage->type, usage->code, 0);
689 input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
690 return;
691 }
692
693 if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
694 int a = field->logical_minimum;
695 int b = field->logical_maximum;
696 input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
697 }
698
699 if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
700 input->ff_effects_max = value;
701 dbg("Maximum Effects - %d",input->ff_effects_max);
702 return;
703 }
704
705 if (usage->hid == (HID_UP_PID | 0x7fUL)) {
706 dbg("PID Pool Report\n");
707 return;
708 }
709
Michael Hanselmanneab9edd2006-01-14 10:08:06 -0500710 if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return;
712
713 input_event(input, usage->type, usage->code, value);
714
715 if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
716 input_event(input, usage->type, usage->code, 0);
717}
718
719void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
720{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 struct hid_input *hidinput;
722
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500723 list_for_each_entry(hidinput, &hid->inputs, list)
724 input_sync(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725}
726
727static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
728{
729 struct hid_report *report;
730 int i, j;
731
732 list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
733 for (i = 0; i < report->maxfield; i++) {
734 *field = report->field[i];
735 for (j = 0; j < (*field)->maxusage; j++)
736 if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
737 return j;
738 }
739 }
740 return -1;
741}
742
743static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
744{
745 struct hid_device *hid = dev->private;
746 struct hid_field *field;
747 int offset;
748
749 if (type == EV_FF)
750 return hid_ff_event(hid, dev, type, code, value);
751
752 if (type != EV_LED)
753 return -1;
754
755 if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
756 warn("event field not found");
757 return -1;
758 }
759
760 hid_set_field(field, offset, value);
761 hid_submit_report(hid, field->report, USB_DIR_OUT);
762
763 return 0;
764}
765
766static int hidinput_open(struct input_dev *dev)
767{
768 struct hid_device *hid = dev->private;
769 return hid_open(hid);
770}
771
772static void hidinput_close(struct input_dev *dev)
773{
774 struct hid_device *hid = dev->private;
775 hid_close(hid);
776}
777
778/*
779 * Register the input device; print a message.
780 * Configure the input layer interface
781 * Read all reports and initialize the absolute field values.
782 */
783
784int hidinput_connect(struct hid_device *hid)
785{
786 struct usb_device *dev = hid->dev;
787 struct hid_report *report;
788 struct hid_input *hidinput = NULL;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500789 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 int i, j, k;
791
792 INIT_LIST_HEAD(&hid->inputs);
793
794 for (i = 0; i < hid->maxcollection; i++)
795 if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
796 hid->collection[i].type == HID_COLLECTION_PHYSICAL)
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500797 if (IS_INPUT_APPLICATION(hid->collection[i].usage))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 break;
799
800 if (i == hid->maxcollection)
801 return -1;
802
803 for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
804 list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
805
806 if (!report->maxfield)
807 continue;
808
809 if (!hidinput) {
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500810 hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
811 input_dev = input_allocate_device();
812 if (!hidinput || !input_dev) {
813 kfree(hidinput);
814 input_free_device(input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 err("Out of memory during hid input probe");
816 return -1;
817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500819 input_dev->private = hid;
820 input_dev->event = hidinput_input_event;
821 input_dev->open = hidinput_open;
822 input_dev->close = hidinput_close;
823
824 input_dev->name = hid->name;
825 input_dev->phys = hid->phys;
826 input_dev->uniq = hid->uniq;
827 usb_to_input_id(dev, &input_dev->id);
828 input_dev->cdev.dev = &hid->intf->dev;
829
830 hidinput->input = input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 list_add_tail(&hidinput->list, &hid->inputs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 }
833
834 for (i = 0; i < report->maxfield; i++)
835 for (j = 0; j < report->field[i]->maxusage; j++)
836 hidinput_configure_usage(hidinput, report->field[i],
837 report->field[i]->usage + j);
Dmitry Torokhov05f091a2005-05-29 02:29:01 -0500838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
840 /* This will leave hidinput NULL, so that it
841 * allocates another one if we have more inputs on
842 * the same interface. Some devices (e.g. Happ's
843 * UGCI) cram a lot of unrelated inputs into the
844 * same interface. */
845 hidinput->report = report;
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500846 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 hidinput = NULL;
848 }
849 }
850
851 /* This only gets called when we are a single-input (most of the
852 * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
853 * only useful in this case, and not for multi-input quirks. */
854 if (hidinput) {
855 hid_ff_init(hid);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500856 input_register_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 }
858
859 return 0;
860}
861
862void hidinput_disconnect(struct hid_device *hid)
863{
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500864 struct hid_input *hidinput, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500866 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 list_del(&hidinput->list);
Dmitry Torokhovc5b7c7c2005-09-15 02:01:47 -0500868 input_unregister_device(hidinput->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 kfree(hidinput);
870 }
871}