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