X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=blobdiff_plain;f=drivers%2Fmacintosh%2Fadbhid.c;h=5396c67ba0a45c9b7cc1196590d1cffe18b49f60;hp=48d17bf6c927d6e8b528c48758b7c309d4c2773f;hb=908cf4b925e419bc74f3297b2f0e51d6f8a81da2;hpb=dcf397f037f52add9945eced57ca300ab6a4413c diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 48d17bf6c927..5396c67ba0a4 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -52,6 +52,11 @@ MODULE_AUTHOR("Franz Sirl "); +static int restore_capslock_events; +module_param(restore_capslock_events, int, 0644); +MODULE_PARM_DESC(restore_capslock_events, + "Produce keypress events for capslock on both keyup and keydown."); + #define KEYB_KEYREG 0 /* register # for key up/down data */ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ @@ -70,7 +75,7 @@ static struct notifier_block adbhid_adb_notifier = { #define ADB_KEY_POWER_OLD 0x7e #define ADB_KEY_POWER 0x7f -u16 adb_to_linux_keycodes[128] = { +static const u16 adb_to_linux_keycodes[128] = { /* 0x00 */ KEY_A, /* 30 */ /* 0x01 */ KEY_S, /* 31 */ /* 0x02 */ KEY_D, /* 32 */ @@ -214,9 +219,13 @@ struct adbhid { int flags; }; -#define FLAG_FN_KEY_PRESSED 0x00000001 -#define FLAG_POWER_FROM_FN 0x00000002 -#define FLAG_EMU_FWDEL_DOWN 0x00000004 +#define FLAG_FN_KEY_PRESSED 0x00000001 +#define FLAG_POWER_FROM_FN 0x00000002 +#define FLAG_EMU_FWDEL_DOWN 0x00000004 +#define FLAG_CAPSLOCK_TRANSLATE 0x00000008 +#define FLAG_CAPSLOCK_DOWN 0x00000010 +#define FLAG_CAPSLOCK_IGNORE_NEXT 0x00000020 +#define FLAG_POWER_KEY_PRESSED 0x00000040 static struct adbhid *adbhid[16]; @@ -272,20 +281,61 @@ adbhid_keyboard_input(unsigned char *data, int nb, int apoll) } static void -adbhid_input_keycode(int id, int keycode, int repeat) +adbhid_input_keycode(int id, int scancode, int repeat) { struct adbhid *ahid = adbhid[id]; - int up_flag, key; - - up_flag = (keycode & 0x80); - keycode &= 0x7f; + int keycode, up_flag, key; + + keycode = scancode & 0x7f; + up_flag = scancode & 0x80; + + if (restore_capslock_events) { + if (keycode == ADB_KEY_CAPSLOCK && !up_flag) { + /* Key pressed, turning on the CapsLock LED. + * The next 0xff will be interpreted as a release. */ + if (ahid->flags & FLAG_CAPSLOCK_IGNORE_NEXT) { + /* Throw away this key event if it happens + * just after resume. */ + ahid->flags &= ~FLAG_CAPSLOCK_IGNORE_NEXT; + return; + } else { + ahid->flags |= FLAG_CAPSLOCK_TRANSLATE + | FLAG_CAPSLOCK_DOWN; + } + } else if (scancode == 0xff && + !(ahid->flags & FLAG_POWER_KEY_PRESSED)) { + /* Scancode 0xff usually signifies that the capslock + * key was either pressed or released, or that the + * power button was released. */ + if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) { + keycode = ADB_KEY_CAPSLOCK; + if (ahid->flags & FLAG_CAPSLOCK_DOWN) { + /* Key released */ + up_flag = 1; + ahid->flags &= ~FLAG_CAPSLOCK_DOWN; + } else { + /* Key pressed */ + up_flag = 0; + ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE; + } + } else { + printk(KERN_INFO "Spurious caps lock event " + "(scancode 0xff).\n"); + } + } + } switch (keycode) { - case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */ - input_report_key(ahid->input, KEY_CAPSLOCK, 1); - input_report_key(ahid->input, KEY_CAPSLOCK, 0); - input_sync(ahid->input); - return; + case ADB_KEY_CAPSLOCK: + if (!restore_capslock_events) { + /* Generate down/up events for CapsLock everytime. */ + input_report_key(ahid->input, KEY_CAPSLOCK, 1); + input_sync(ahid->input); + input_report_key(ahid->input, KEY_CAPSLOCK, 0); + input_sync(ahid->input); + return; + } + break; #ifdef CONFIG_PPC_PMAC case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */ switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO, @@ -296,7 +346,13 @@ adbhid_input_keycode(int id, int keycode, int repeat) keycode = ADB_KEY_POWER; } break; - case ADB_KEY_POWER: + case ADB_KEY_POWER: + /* Keep track of the power key state */ + if (up_flag) + ahid->flags &= ~FLAG_POWER_KEY_PRESSED; + else + ahid->flags |= FLAG_POWER_KEY_PRESSED; + /* Fn + Command will produce a bogus "power" keycode */ if (ahid->flags & FLAG_FN_KEY_PRESSED) { keycode = ADB_KEY_CMD; @@ -642,6 +698,21 @@ static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned i return -1; } +static void +adbhid_kbd_capslock_remember(void) +{ + struct adbhid *ahid; + int i; + + for (i = 1; i < 16; i++) { + ahid = adbhid[i]; + + if (ahid && ahid->id == ADB_KEYBOARD) + if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) + ahid->flags |= FLAG_CAPSLOCK_IGNORE_NEXT; + } +} + static int adb_message_handler(struct notifier_block *this, unsigned long code, void *x) { @@ -658,8 +729,17 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x) } /* Stop pending led requests */ - while(leds_req_pending) + while (leds_req_pending) adb_poll(); + + /* After resume, and if the capslock LED is on, the PMU will + * send a "capslock down" key event. This confuses the + * restore_capslock_events logic. Remember if the capslock + * LED was on before suspend so the unwanted key event can + * be ignored after resume. */ + if (restore_capslock_events) + adbhid_kbd_capslock_remember(); + break; case ADB_MSG_POST_RESET: @@ -753,8 +833,10 @@ adbhid_input_register(int id, int default_id, int original_handler_id, if (hid->keycode[i]) set_bit(hid->keycode[i], input_dev->keybit); - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); - input_dev->ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | + BIT_MASK(EV_REP); + input_dev->ledbit[0] = BIT_MASK(LED_SCROLLL) | + BIT_MASK(LED_CAPSL) | BIT_MASK(LED_NUML); input_dev->event = adbhid_kbd_event; input_dev->keycodemax = KEY_FN; input_dev->keycodesize = sizeof(hid->keycode[0]); @@ -763,16 +845,18 @@ adbhid_input_register(int id, int default_id, int original_handler_id, case ADB_MOUSE: sprintf(hid->name, "ADB mouse"); - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); - input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); + input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | + BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); + input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); break; case ADB_MISC: switch (original_handler_id) { case 0x02: /* Adjustable keyboard button device */ sprintf(hid->name, "ADB adjustable keyboard buttons"); - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->evbit[0] = BIT_MASK(EV_KEY) | + BIT_MASK(EV_REP); set_bit(KEY_SOUND, input_dev->keybit); set_bit(KEY_MUTE, input_dev->keybit); set_bit(KEY_VOLUMEUP, input_dev->keybit); @@ -780,7 +864,8 @@ adbhid_input_register(int id, int default_id, int original_handler_id, break; case 0x1f: /* Powerbook button device */ sprintf(hid->name, "ADB Powerbook buttons"); - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->evbit[0] = BIT_MASK(EV_KEY) | + BIT_MASK(EV_REP); set_bit(KEY_MUTE, input_dev->keybit); set_bit(KEY_VOLUMEUP, input_dev->keybit); set_bit(KEY_VOLUMEDOWN, input_dev->keybit);