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