aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorMichael Hanselmann <linux-kernel@hansmi.ch>2006-01-14 10:08:06 -0500
committerDmitry Torokhov <dtor_core@ameritech.net>2006-01-14 10:08:06 -0500
commiteab9edd27f7ceaad6b57085817d63287bda15190 (patch)
tree8ba37791bfeb95e660caf6192c8dcecd9ba2aa6e /drivers/usb
parent1e27ffd4d7d39783c5196daa2584cca5785d1f95 (diff)
Input: HID - add support for fn key on Apple PowerBooks
This patch implements support for the fn key on Apple PowerBooks using USB based keyboards and makes them behave like their ADB counterparts. Signed-off-by: Michael Hanselmann <linux-kernel@hansmi.ch> Acked-by: Rene Nussbaumer <linux-kernel@killerfox.forkbomb.ch> Acked-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/usb')
-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