aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/input/hid-input.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/input/hid-input.c')
-rw-r--r--drivers/usb/input/hid-input.c166
1 files changed, 164 insertions, 2 deletions
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
index 36a08c04c46..cb0d80f4925 100644
--- a/drivers/usb/input/hid-input.c
+++ b/drivers/usb/input/hid-input.c
@@ -73,6 +73,160 @@ static const struct {
#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
#define map_ff_effect(c) do { set_bit(c, input->ffbit); } while (0)
+#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+
+struct hidinput_key_translation {
+ u16 from;
+ u16 to;
+ u8 flags;
+};
+
+#define POWERBOOK_FLAG_FKEY 0x01
+
+static struct hidinput_key_translation powerbook_fn_keys[] = {
+ { KEY_BACKSPACE, KEY_DELETE },
+ { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY },
+ { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY },
+ { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY },
+ { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY },
+ { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY },
+ { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY },
+ { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY },
+ { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY },
+ { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY },
+ { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY },
+ { KEY_UP, KEY_PAGEUP },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_LEFT, KEY_HOME },
+ { KEY_RIGHT, KEY_END },
+ { }
+};
+
+static struct hidinput_key_translation powerbook_numlock_keys[] = {
+ { KEY_J, KEY_KP1 },
+ { KEY_K, KEY_KP2 },
+ { KEY_L, KEY_KP3 },
+ { KEY_U, KEY_KP4 },
+ { KEY_I, KEY_KP5 },
+ { KEY_O, KEY_KP6 },
+ { KEY_7, KEY_KP7 },
+ { KEY_8, KEY_KP8 },
+ { KEY_9, KEY_KP9 },
+ { KEY_M, KEY_KP0 },
+ { KEY_DOT, KEY_KPDOT },
+ { KEY_SLASH, KEY_KPPLUS },
+ { KEY_SEMICOLON, KEY_KPMINUS },
+ { KEY_P, KEY_KPASTERISK },
+ { KEY_MINUS, KEY_KPEQUAL },
+ { KEY_0, KEY_KPSLASH },
+ { KEY_F6, KEY_NUMLOCK },
+ { KEY_KPENTER, KEY_KPENTER },
+ { KEY_BACKSPACE, KEY_BACKSPACE },
+ { }
+};
+
+static int usbhid_pb_fnmode = 1;
+module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
+MODULE_PARM_DESC(pb_fnmode,
+ "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
+
+static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
+{
+ struct hidinput_key_translation *trans;
+
+ /* Look for the translation */
+ for (trans = table; trans->from; trans++)
+ if (trans->from == from)
+ return trans;
+
+ return NULL;
+}
+
+static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+ struct hid_usage *usage, __s32 value)
+{
+ struct hidinput_key_translation *trans;
+
+ if (usage->code == KEY_FN) {
+ if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON;
+ else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
+
+ input_event(input, usage->type, usage->code, value);
+
+ return 1;
+ }
+
+ if (usbhid_pb_fnmode) {
+ int do_translate;
+
+ trans = find_translation(powerbook_fn_keys, usage->code);
+ if (trans) {
+ if (test_bit(usage->code, hid->pb_pressed_fn))
+ do_translate = 1;
+ else if (trans->flags & POWERBOOK_FLAG_FKEY)
+ do_translate =
+ (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
+ (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
+ else
+ do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
+
+ if (do_translate) {
+ if (value)
+ set_bit(usage->code, hid->pb_pressed_fn);
+ else
+ clear_bit(usage->code, hid->pb_pressed_fn);
+
+ input_event(input, usage->type, trans->to, value);
+
+ return 1;
+ }
+ }
+
+ if (test_bit(usage->code, hid->pb_pressed_numlock) ||
+ test_bit(LED_NUML, input->led)) {
+ trans = find_translation(powerbook_numlock_keys, usage->code);
+
+ if (trans) {
+ if (value)
+ set_bit(usage->code, hid->pb_pressed_numlock);
+ else
+ clear_bit(usage->code, hid->pb_pressed_numlock);
+
+ input_event(input, usage->type, trans->to, value);
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void hidinput_pb_setup(struct input_dev *input)
+{
+ struct hidinput_key_translation *trans;
+
+ set_bit(KEY_NUMLOCK, input->keybit);
+
+ /* Enable all needed keys */
+ for (trans = powerbook_fn_keys; trans->from; trans++)
+ set_bit(trans->to, input->keybit);
+
+ for (trans = powerbook_numlock_keys; trans->from; trans++)
+ set_bit(trans->to, input->keybit);
+}
+#else
+static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+ struct hid_usage *usage, __s32 value)
+{
+ return 0;
+}
+
+static inline void hidinput_pb_setup(struct input_dev *input)
+{
+}
+#endif
+
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage)
{
@@ -336,7 +490,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
set_bit(EV_REP, input->evbit);
switch(usage->hid & HID_USAGE) {
- case 0x003: map_key_clear(KEY_FN); break;
+ case 0x003:
+ /* The fn key on Apple PowerBooks */
+ map_key_clear(KEY_FN);
+ hidinput_pb_setup(input);
+ break;
+
default: goto ignore;
}
break;
@@ -493,6 +652,9 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
+ if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
+ return;
+
if (usage->hat_min < usage->hat_max || usage->hat_dir) {
int hat_dir = usage->hat_dir;
if (!hat_dir)
@@ -535,7 +697,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
- if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
+ if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
return;
input_event(input, usage->type, usage->code, value);