Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: adbhid - fix capslock key state after suspend

If the adbhid module parameter restore_capslock_events is used,
sometimes capslock will get stuck down after resuming.

My fix is to remember the capslock state before suspend and then
ignore the first 'caps lock key down' message after resume if the
capslock LED was on before suspending.

Signed-off-by: Rodney Lorrimar <rodney@rodney.id.au>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Rodney Lorrimar and committed by
Dmitry Torokhov
2e75f044 d2fc60d6

+39 -7
+39 -7
drivers/macintosh/adbhid.c
··· 219 219 int flags; 220 220 }; 221 221 222 - #define FLAG_FN_KEY_PRESSED 0x00000001 223 - #define FLAG_POWER_FROM_FN 0x00000002 224 - #define FLAG_EMU_FWDEL_DOWN 0x00000004 225 - #define FLAG_CAPSLOCK_TRANSLATE 0x00000008 226 - #define FLAG_CAPSLOCK_DOWN 0x00000010 222 + #define FLAG_FN_KEY_PRESSED 0x00000001 223 + #define FLAG_POWER_FROM_FN 0x00000002 224 + #define FLAG_EMU_FWDEL_DOWN 0x00000004 225 + #define FLAG_CAPSLOCK_TRANSLATE 0x00000008 226 + #define FLAG_CAPSLOCK_DOWN 0x00000010 227 + #define FLAG_CAPSLOCK_IGNORE_NEXT 0x00000020 227 228 228 229 static struct adbhid *adbhid[16]; 229 230 ··· 292 291 if (keycode == ADB_KEY_CAPSLOCK && !up_flag) { 293 292 /* Key pressed, turning on the CapsLock LED. 294 293 * The next 0xff will be interpreted as a release. */ 295 - ahid->flags |= FLAG_CAPSLOCK_TRANSLATE 294 + if (ahid->flags & FLAG_CAPSLOCK_IGNORE_NEXT) { 295 + /* Throw away this key event if it happens 296 + * just after resume. */ 297 + ahid->flags &= ~FLAG_CAPSLOCK_IGNORE_NEXT; 298 + return; 299 + } else { 300 + ahid->flags |= FLAG_CAPSLOCK_TRANSLATE 296 301 | FLAG_CAPSLOCK_DOWN; 302 + } 297 303 } else if (scancode == 0xff) { 298 304 /* Scancode 0xff usually signifies that the capslock 299 305 * key was either pressed or released. */ ··· 689 681 return -1; 690 682 } 691 683 684 + static void 685 + adbhid_kbd_capslock_remember(void) 686 + { 687 + struct adbhid *ahid; 688 + int i; 689 + 690 + for (i = 1; i < 16; i++) { 691 + ahid = adbhid[i]; 692 + 693 + if (ahid && ahid->id == ADB_KEYBOARD) 694 + if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) 695 + ahid->flags |= FLAG_CAPSLOCK_IGNORE_NEXT; 696 + } 697 + } 698 + 692 699 static int 693 700 adb_message_handler(struct notifier_block *this, unsigned long code, void *x) 694 701 { ··· 720 697 } 721 698 722 699 /* Stop pending led requests */ 723 - while(leds_req_pending) 700 + while (leds_req_pending) 724 701 adb_poll(); 702 + 703 + /* After resume, and if the capslock LED is on, the PMU will 704 + * send a "capslock down" key event. This confuses the 705 + * restore_capslock_events logic. Remember if the capslock 706 + * LED was on before suspend so the unwanted key event can 707 + * be ignored after resume. */ 708 + if (restore_capslock_events) 709 + adbhid_kbd_capslock_remember(); 710 + 725 711 break; 726 712 727 713 case ADB_MSG_POST_RESET: