diff options
author | Dmitry Torokhov <dtor@insightbb.com> | 2006-08-04 22:52:46 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2006-08-04 22:52:46 -0400 |
commit | 3d0f0fa0cb554541e10cb8cb84104e4b10828468 (patch) | |
tree | 5753ba0c43657fc66a5b502b5be5eb95819f7b04 /drivers/input/keyboard/atkbd.c | |
parent | 184dd2751c653a572c79c1fff969000b8880da40 (diff) |
Input: atkbd - restore repeat rate when resuming
Make the AT keyboard driver restore previously set repeat rate
when resuming. Noticed by Linus Torvalds.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/keyboard/atkbd.c')
-rw-r--r-- | drivers/input/keyboard/atkbd.c | 103 |
1 files changed, 60 insertions, 43 deletions
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index ce1f10e8984b..6bfa0cf4b1d2 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c | |||
@@ -482,13 +482,7 @@ out: | |||
482 | return IRQ_HANDLED; | 482 | return IRQ_HANDLED; |
483 | } | 483 | } |
484 | 484 | ||
485 | /* | 485 | static int atkbd_set_repeat_rate(struct atkbd *atkbd) |
486 | * atkbd_event_work() is used to complete processing of events that | ||
487 | * can not be processed by input_event() which is often called from | ||
488 | * interrupt context. | ||
489 | */ | ||
490 | |||
491 | static void atkbd_event_work(void *data) | ||
492 | { | 486 | { |
493 | const short period[32] = | 487 | const short period[32] = |
494 | { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, | 488 | { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, |
@@ -496,41 +490,64 @@ static void atkbd_event_work(void *data) | |||
496 | const short delay[4] = | 490 | const short delay[4] = |
497 | { 250, 500, 750, 1000 }; | 491 | { 250, 500, 750, 1000 }; |
498 | 492 | ||
499 | struct atkbd *atkbd = data; | 493 | struct input_dev *dev = atkbd->dev; |
494 | unsigned char param; | ||
495 | int i = 0, j = 0; | ||
496 | |||
497 | while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD]) | ||
498 | i++; | ||
499 | dev->rep[REP_PERIOD] = period[i]; | ||
500 | |||
501 | while (j < ARRAY_SIZE(period) - 1 && delay[j] < dev->rep[REP_DELAY]) | ||
502 | j++; | ||
503 | dev->rep[REP_DELAY] = delay[j]; | ||
504 | |||
505 | param = i | (j << 5); | ||
506 | return ps2_command(&atkbd->ps2dev, ¶m, ATKBD_CMD_SETREP); | ||
507 | } | ||
508 | |||
509 | static int atkbd_set_leds(struct atkbd *atkbd) | ||
510 | { | ||
500 | struct input_dev *dev = atkbd->dev; | 511 | struct input_dev *dev = atkbd->dev; |
501 | unsigned char param[2]; | 512 | unsigned char param[2]; |
502 | int i, j; | ||
503 | 513 | ||
504 | mutex_lock(&atkbd->event_mutex); | 514 | param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) |
515 | | (test_bit(LED_NUML, dev->led) ? 2 : 0) | ||
516 | | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); | ||
517 | if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) | ||
518 | return -1; | ||
505 | 519 | ||
506 | if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) { | 520 | if (atkbd->extra) { |
507 | param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) | 521 | param[0] = 0; |
508 | | (test_bit(LED_NUML, dev->led) ? 2 : 0) | 522 | param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) |
509 | | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); | 523 | | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) |
510 | ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS); | 524 | | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) |
511 | 525 | | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) | |
512 | if (atkbd->extra) { | 526 | | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); |
513 | param[0] = 0; | 527 | if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS)) |
514 | param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) | 528 | return -1; |
515 | | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) | ||
516 | | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) | ||
517 | | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) | ||
518 | | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); | ||
519 | ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS); | ||
520 | } | ||
521 | } | 529 | } |
522 | 530 | ||
523 | if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) { | 531 | return 0; |
524 | i = j = 0; | 532 | } |
525 | while (i < 31 && period[i] < dev->rep[REP_PERIOD]) | 533 | |
526 | i++; | 534 | /* |
527 | while (j < 3 && delay[j] < dev->rep[REP_DELAY]) | 535 | * atkbd_event_work() is used to complete processing of events that |
528 | j++; | 536 | * can not be processed by input_event() which is often called from |
529 | dev->rep[REP_PERIOD] = period[i]; | 537 | * interrupt context. |
530 | dev->rep[REP_DELAY] = delay[j]; | 538 | */ |
531 | param[0] = i | (j << 5); | 539 | |
532 | ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP); | 540 | static void atkbd_event_work(void *data) |
533 | } | 541 | { |
542 | struct atkbd *atkbd = data; | ||
543 | |||
544 | mutex_lock(&atkbd->event_mutex); | ||
545 | |||
546 | if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) | ||
547 | atkbd_set_leds(atkbd); | ||
548 | |||
549 | if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) | ||
550 | atkbd_set_repeat_rate(atkbd); | ||
534 | 551 | ||
535 | mutex_unlock(&atkbd->event_mutex); | 552 | mutex_unlock(&atkbd->event_mutex); |
536 | } | 553 | } |
@@ -975,7 +992,6 @@ static int atkbd_reconnect(struct serio *serio) | |||
975 | { | 992 | { |
976 | struct atkbd *atkbd = serio_get_drvdata(serio); | 993 | struct atkbd *atkbd = serio_get_drvdata(serio); |
977 | struct serio_driver *drv = serio->drv; | 994 | struct serio_driver *drv = serio->drv; |
978 | unsigned char param[1]; | ||
979 | 995 | ||
980 | if (!atkbd || !drv) { | 996 | if (!atkbd || !drv) { |
981 | printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); | 997 | printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); |
@@ -985,10 +1001,6 @@ static int atkbd_reconnect(struct serio *serio) | |||
985 | atkbd_disable(atkbd); | 1001 | atkbd_disable(atkbd); |
986 | 1002 | ||
987 | if (atkbd->write) { | 1003 | if (atkbd->write) { |
988 | param[0] = (test_bit(LED_SCROLLL, atkbd->dev->led) ? 1 : 0) | ||
989 | | (test_bit(LED_NUML, atkbd->dev->led) ? 2 : 0) | ||
990 | | (test_bit(LED_CAPSL, atkbd->dev->led) ? 4 : 0); | ||
991 | |||
992 | if (atkbd_probe(atkbd)) | 1004 | if (atkbd_probe(atkbd)) |
993 | return -1; | 1005 | return -1; |
994 | if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) | 1006 | if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) |
@@ -996,8 +1008,13 @@ static int atkbd_reconnect(struct serio *serio) | |||
996 | 1008 | ||
997 | atkbd_activate(atkbd); | 1009 | atkbd_activate(atkbd); |
998 | 1010 | ||
999 | if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) | 1011 | /* |
1000 | return -1; | 1012 | * Restore repeat rate and LEDs (that were reset by atkbd_activate) |
1013 | * to pre-resume state | ||
1014 | */ | ||
1015 | if (!atkbd->softrepeat) | ||
1016 | atkbd_set_repeat_rate(atkbd); | ||
1017 | atkbd_set_leds(atkbd); | ||
1001 | } | 1018 | } |
1002 | 1019 | ||
1003 | atkbd_enable(atkbd); | 1020 | atkbd_enable(atkbd); |