diff options
Diffstat (limited to 'drivers/usb/input/hid-input.c')
| -rw-r--r-- | drivers/usb/input/hid-input.c | 179 |
1 files changed, 176 insertions, 3 deletions
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 192a03b28971..cb0d80f49252 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c | |||
| @@ -73,6 +73,160 @@ static const struct { | |||
| 73 | #define map_key_clear(c) do { map_key(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) | 74 | #define map_ff_effect(c) do { set_bit(c, input->ffbit); } while (0) |
| 75 | 75 | ||
| 76 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK | ||
| 77 | |||
| 78 | struct hidinput_key_translation { | ||
| 79 | u16 from; | ||
| 80 | u16 to; | ||
| 81 | u8 flags; | ||
| 82 | }; | ||
| 83 | |||
| 84 | #define POWERBOOK_FLAG_FKEY 0x01 | ||
| 85 | |||
| 86 | static 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 | |||
| 105 | static 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 | |||
| 128 | static int usbhid_pb_fnmode = 1; | ||
| 129 | module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); | ||
| 130 | MODULE_PARM_DESC(pb_fnmode, | ||
| 131 | "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); | ||
| 132 | |||
| 133 | static 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 | |||
| 145 | static 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 | |||
| 205 | static 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 | ||
| 219 | static 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 | |||
| 225 | static inline void hidinput_pb_setup(struct input_dev *input) | ||
| 226 | { | ||
| 227 | } | ||
| 228 | #endif | ||
| 229 | |||
| 76 | static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, | 230 | static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, |
| 77 | struct hid_usage *usage) | 231 | struct hid_usage *usage) |
| 78 | { | 232 | { |
| @@ -135,8 +289,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
| 135 | case HID_UP_SIMULATION: | 289 | case HID_UP_SIMULATION: |
| 136 | 290 | ||
| 137 | switch (usage->hid & 0xffff) { | 291 | switch (usage->hid & 0xffff) { |
| 138 | case 0xba: map_abs(ABS_RUDDER); break; | 292 | case 0xba: map_abs(ABS_RUDDER); break; |
| 139 | case 0xbb: map_abs(ABS_THROTTLE); break; | 293 | case 0xbb: map_abs(ABS_THROTTLE); break; |
| 294 | case 0xc4: map_abs(ABS_GAS); break; | ||
| 295 | case 0xc5: map_abs(ABS_BRAKE); break; | ||
| 296 | case 0xc8: map_abs(ABS_WHEEL); break; | ||
| 140 | default: goto ignore; | 297 | default: goto ignore; |
| 141 | } | 298 | } |
| 142 | break; | 299 | break; |
| @@ -289,11 +446,19 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
| 289 | case 0x226: map_key_clear(KEY_STOP); break; | 446 | case 0x226: map_key_clear(KEY_STOP); break; |
| 290 | case 0x227: map_key_clear(KEY_REFRESH); break; | 447 | case 0x227: map_key_clear(KEY_REFRESH); break; |
| 291 | case 0x22a: map_key_clear(KEY_BOOKMARKS); break; | 448 | case 0x22a: map_key_clear(KEY_BOOKMARKS); break; |
| 449 | case 0x233: map_key_clear(KEY_SCROLLUP); break; | ||
| 450 | case 0x234: map_key_clear(KEY_SCROLLDOWN); break; | ||
| 292 | case 0x238: map_rel(REL_HWHEEL); break; | 451 | case 0x238: map_rel(REL_HWHEEL); break; |
| 293 | case 0x279: map_key_clear(KEY_REDO); break; | 452 | case 0x279: map_key_clear(KEY_REDO); break; |
| 294 | case 0x289: map_key_clear(KEY_REPLY); break; | 453 | case 0x289: map_key_clear(KEY_REPLY); break; |
| 295 | case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; | 454 | case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; |
| 296 | case 0x28c: map_key_clear(KEY_SEND); break; | 455 | case 0x28c: map_key_clear(KEY_SEND); break; |
| 456 | |||
| 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 | |||
| 297 | default: goto ignore; | 462 | default: goto ignore; |
| 298 | } | 463 | } |
| 299 | break; | 464 | break; |
| @@ -325,7 +490,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
| 325 | 490 | ||
| 326 | set_bit(EV_REP, input->evbit); | 491 | set_bit(EV_REP, input->evbit); |
| 327 | switch(usage->hid & HID_USAGE) { | 492 | switch(usage->hid & HID_USAGE) { |
| 328 | case 0x003: map_key_clear(KEY_FN); break; | 493 | case 0x003: |
| 494 | /* The fn key on Apple PowerBooks */ | ||
| 495 | map_key_clear(KEY_FN); | ||
| 496 | hidinput_pb_setup(input); | ||
| 497 | break; | ||
| 498 | |||
| 329 | default: goto ignore; | 499 | default: goto ignore; |
| 330 | } | 500 | } |
| 331 | break; | 501 | break; |
| @@ -482,6 +652,9 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
| 482 | return; | 652 | return; |
| 483 | } | 653 | } |
| 484 | 654 | ||
| 655 | if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value)) | ||
| 656 | return; | ||
| 657 | |||
| 485 | if (usage->hat_min < usage->hat_max || usage->hat_dir) { | 658 | if (usage->hat_min < usage->hat_max || usage->hat_dir) { |
| 486 | int hat_dir = usage->hat_dir; | 659 | int hat_dir = usage->hat_dir; |
| 487 | if (!hat_dir) | 660 | if (!hat_dir) |
| @@ -524,7 +697,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
| 524 | return; | 697 | return; |
| 525 | } | 698 | } |
| 526 | 699 | ||
| 527 | if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ | 700 | if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ |
| 528 | return; | 701 | return; |
| 529 | 702 | ||
| 530 | input_event(input, usage->type, usage->code, value); | 703 | input_event(input, usage->type, usage->code, value); |
