aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/input/Kconfig10
-rw-r--r--drivers/usb/input/hid-core.c8
-rw-r--r--drivers/usb/input/hid-input.c166
-rw-r--r--drivers/usb/input/hid.h31
4 files changed, 201 insertions, 14 deletions
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index 509dd0a04c54..5246b35301de 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -37,6 +37,16 @@ config USB_HIDINPUT
37 37
38 If unsure, say Y. 38 If unsure, say Y.
39 39
40config USB_HIDINPUT_POWERBOOK
41 bool "Enable support for iBook/PowerBook special keys"
42 default n
43 depends on USB_HIDINPUT
44 help
45 Say Y here if you want support for the special keys (Fn, Numlock) on
46 Apple iBooks and PowerBooks.
47
48 If unsure, say N.
49
40config HID_FF 50config HID_FF
41 bool "Force feedback support (EXPERIMENTAL)" 51 bool "Force feedback support (EXPERIMENTAL)"
42 depends on USB_HIDINPUT && EXPERIMENTAL 52 depends on USB_HIDINPUT && EXPERIMENTAL
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 1a2d20303ed8..a91e72c41415 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1585,6 +1585,14 @@ static const struct hid_blacklist {
1585 1585
1586 { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION }, 1586 { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
1587 1587
1588 { USB_VENDOR_ID_APPLE, 0x020E, HID_QUIRK_POWERBOOK_HAS_FN },
1589 { USB_VENDOR_ID_APPLE, 0x020F, HID_QUIRK_POWERBOOK_HAS_FN },
1590 { USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN },
1591 { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN },
1592 { USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN },
1593 { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN },
1594 { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN },
1595
1588 { 0, 0 } 1596 { 0, 0 }
1589}; 1597};
1590 1598
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
index 36a08c04c460..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
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
76static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, 230static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
77 struct hid_usage *usage) 231 struct hid_usage *usage)
78{ 232{
@@ -336,7 +490,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
336 490
337 set_bit(EV_REP, input->evbit); 491 set_bit(EV_REP, input->evbit);
338 switch(usage->hid & HID_USAGE) { 492 switch(usage->hid & HID_USAGE) {
339 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
340 default: goto ignore; 499 default: goto ignore;
341 } 500 }
342 break; 501 break;
@@ -493,6 +652,9 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
493 return; 652 return;
494 } 653 }
495 654
655 if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
656 return;
657
496 if (usage->hat_min < usage->hat_max || usage->hat_dir) { 658 if (usage->hat_min < usage->hat_max || usage->hat_dir) {
497 int hat_dir = usage->hat_dir; 659 int hat_dir = usage->hat_dir;
498 if (!hat_dir) 660 if (!hat_dir)
@@ -535,7 +697,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
535 return; 697 return;
536 } 698 }
537 699
538 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 */
539 return; 701 return;
540 702
541 input_event(input, usage->type, usage->code, value); 703 input_event(input, usage->type, usage->code, value);
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
index 335316c7233b..8b0d4346ce9c 100644
--- a/drivers/usb/input/hid.h
+++ b/drivers/usb/input/hid.h
@@ -235,18 +235,20 @@ struct hid_item {
235 * HID device quirks. 235 * HID device quirks.
236 */ 236 */
237 237
238#define HID_QUIRK_INVERT 0x001 238#define HID_QUIRK_INVERT 0x00000001
239#define HID_QUIRK_NOTOUCH 0x002 239#define HID_QUIRK_NOTOUCH 0x00000002
240#define HID_QUIRK_IGNORE 0x004 240#define HID_QUIRK_IGNORE 0x00000004
241#define HID_QUIRK_NOGET 0x008 241#define HID_QUIRK_NOGET 0x00000008
242#define HID_QUIRK_HIDDEV 0x010 242#define HID_QUIRK_HIDDEV 0x00000010
243#define HID_QUIRK_BADPAD 0x020 243#define HID_QUIRK_BADPAD 0x00000020
244#define HID_QUIRK_MULTI_INPUT 0x040 244#define HID_QUIRK_MULTI_INPUT 0x00000040
245#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x080 245#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080
246#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x100 246#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100
247#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x200 247#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200
248#define HID_QUIRK_2WHEEL_POWERMOUSE 0x400 248#define HID_QUIRK_2WHEEL_POWERMOUSE 0x00000400
249#define HID_QUIRK_CYMOTION 0x800 249#define HID_QUIRK_CYMOTION 0x00000800
250#define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000
251#define HID_QUIRK_POWERBOOK_FN_ON 0x00002000
250 252
251/* 253/*
252 * This is the global environment of the parser. This information is 254 * This is the global environment of the parser. This information is
@@ -432,6 +434,11 @@ struct hid_device { /* device report descriptor */
432 void (*ff_exit)(struct hid_device*); /* Called by hid_exit_ff(hid) */ 434 void (*ff_exit)(struct hid_device*); /* Called by hid_exit_ff(hid) */
433 int (*ff_event)(struct hid_device *hid, struct input_dev *input, 435 int (*ff_event)(struct hid_device *hid, struct input_dev *input,
434 unsigned int type, unsigned int code, int value); 436 unsigned int type, unsigned int code, int value);
437
438#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
439 unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
440 unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
441#endif
435}; 442};
436 443
437#define HID_GLOBAL_STACK_SIZE 4 444#define HID_GLOBAL_STACK_SIZE 4