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); |