diff options
Diffstat (limited to 'drivers/input/keyboard/atkbd.c')
-rw-r--r-- | drivers/input/keyboard/atkbd.c | 145 |
1 files changed, 104 insertions, 41 deletions
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 4709e15af607..28e6110d1ff8 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c | |||
@@ -233,6 +233,7 @@ struct atkbd { | |||
233 | */ | 233 | */ |
234 | static void (*atkbd_platform_fixup)(struct atkbd *, const void *data); | 234 | static void (*atkbd_platform_fixup)(struct atkbd *, const void *data); |
235 | static void *atkbd_platform_fixup_data; | 235 | static void *atkbd_platform_fixup_data; |
236 | static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int); | ||
236 | 237 | ||
237 | static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, | 238 | static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, |
238 | ssize_t (*handler)(struct atkbd *, char *)); | 239 | ssize_t (*handler)(struct atkbd *, char *)); |
@@ -393,6 +394,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, | |||
393 | 394 | ||
394 | input_event(dev, EV_MSC, MSC_RAW, code); | 395 | input_event(dev, EV_MSC, MSC_RAW, code); |
395 | 396 | ||
397 | if (atkbd_platform_scancode_fixup) | ||
398 | code = atkbd_platform_scancode_fixup(atkbd, code); | ||
399 | |||
396 | if (atkbd->translated) { | 400 | if (atkbd->translated) { |
397 | 401 | ||
398 | if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) { | 402 | if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) { |
@@ -574,11 +578,22 @@ static void atkbd_event_work(struct work_struct *work) | |||
574 | 578 | ||
575 | mutex_lock(&atkbd->event_mutex); | 579 | mutex_lock(&atkbd->event_mutex); |
576 | 580 | ||
577 | if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) | 581 | if (!atkbd->enabled) { |
578 | atkbd_set_leds(atkbd); | 582 | /* |
583 | * Serio ports are resumed asynchronously so while driver core | ||
584 | * thinks that device is already fully operational in reality | ||
585 | * it may not be ready yet. In this case we need to keep | ||
586 | * rescheduling till reconnect completes. | ||
587 | */ | ||
588 | schedule_delayed_work(&atkbd->event_work, | ||
589 | msecs_to_jiffies(100)); | ||
590 | } else { | ||
591 | if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) | ||
592 | atkbd_set_leds(atkbd); | ||
579 | 593 | ||
580 | if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) | 594 | if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) |
581 | atkbd_set_repeat_rate(atkbd); | 595 | atkbd_set_repeat_rate(atkbd); |
596 | } | ||
582 | 597 | ||
583 | mutex_unlock(&atkbd->event_mutex); | 598 | mutex_unlock(&atkbd->event_mutex); |
584 | } | 599 | } |
@@ -770,6 +785,30 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra | |||
770 | return 3; | 785 | return 3; |
771 | } | 786 | } |
772 | 787 | ||
788 | static int atkbd_reset_state(struct atkbd *atkbd) | ||
789 | { | ||
790 | struct ps2dev *ps2dev = &atkbd->ps2dev; | ||
791 | unsigned char param[1]; | ||
792 | |||
793 | /* | ||
794 | * Set the LEDs to a predefined state (all off). | ||
795 | */ | ||
796 | |||
797 | param[0] = 0; | ||
798 | if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) | ||
799 | return -1; | ||
800 | |||
801 | /* | ||
802 | * Set autorepeat to fastest possible. | ||
803 | */ | ||
804 | |||
805 | param[0] = 0; | ||
806 | if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP)) | ||
807 | return -1; | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
773 | static int atkbd_activate(struct atkbd *atkbd) | 812 | static int atkbd_activate(struct atkbd *atkbd) |
774 | { | 813 | { |
775 | struct ps2dev *ps2dev = &atkbd->ps2dev; | 814 | struct ps2dev *ps2dev = &atkbd->ps2dev; |
@@ -852,29 +891,6 @@ static unsigned int atkbd_hp_forced_release_keys[] = { | |||
852 | }; | 891 | }; |
853 | 892 | ||
854 | /* | 893 | /* |
855 | * Inventec system with broken key release on volume keys | ||
856 | */ | ||
857 | static unsigned int atkbd_inventec_forced_release_keys[] = { | ||
858 | 0xae, 0xb0, -1U | ||
859 | }; | ||
860 | |||
861 | /* | ||
862 | * Perform fixup for HP Pavilion ZV6100 laptop that doesn't generate release | ||
863 | * for its volume buttons | ||
864 | */ | ||
865 | static unsigned int atkbd_hp_zv6100_forced_release_keys[] = { | ||
866 | 0xae, 0xb0, -1U | ||
867 | }; | ||
868 | |||
869 | /* | ||
870 | * Perform fixup for HP (Compaq) Presario R4000 R4100 R4200 that don't generate | ||
871 | * release for their volume buttons | ||
872 | */ | ||
873 | static unsigned int atkbd_hp_r4000_forced_release_keys[] = { | ||
874 | 0xae, 0xb0, -1U | ||
875 | }; | ||
876 | |||
877 | /* | ||
878 | * Samsung NC10,NC20 with Fn+F? key release not working | 894 | * Samsung NC10,NC20 with Fn+F? key release not working |
879 | */ | 895 | */ |
880 | static unsigned int atkbd_samsung_forced_release_keys[] = { | 896 | static unsigned int atkbd_samsung_forced_release_keys[] = { |
@@ -882,14 +898,6 @@ static unsigned int atkbd_samsung_forced_release_keys[] = { | |||
882 | }; | 898 | }; |
883 | 899 | ||
884 | /* | 900 | /* |
885 | * The volume up and volume down special keys on a Fujitsu Amilo PA 1510 laptop | ||
886 | * do not generate release events so we have to do it ourselves. | ||
887 | */ | ||
888 | static unsigned int atkbd_amilo_pa1510_forced_release_keys[] = { | ||
889 | 0xb0, 0xae, -1U | ||
890 | }; | ||
891 | |||
892 | /* | ||
893 | * Amilo Pi 3525 key release for Fn+Volume keys not working | 901 | * Amilo Pi 3525 key release for Fn+Volume keys not working |
894 | */ | 902 | */ |
895 | static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = { | 903 | static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = { |
@@ -911,6 +919,30 @@ static unsigned int atkdb_soltech_ta12_forced_release_keys[] = { | |||
911 | }; | 919 | }; |
912 | 920 | ||
913 | /* | 921 | /* |
922 | * Many notebooks don't send key release event for volume up/down | ||
923 | * keys, with key list below common among them | ||
924 | */ | ||
925 | static unsigned int atkbd_volume_forced_release_keys[] = { | ||
926 | 0xae, 0xb0, -1U | ||
927 | }; | ||
928 | |||
929 | /* | ||
930 | * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas | ||
931 | * they should be generating e4-e6 (0x80 | code). | ||
932 | */ | ||
933 | static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd, | ||
934 | unsigned int code) | ||
935 | { | ||
936 | if (atkbd->translated && atkbd->emul == 1 && | ||
937 | (code == 0x64 || code == 0x65 || code == 0x66)) { | ||
938 | atkbd->emul = 0; | ||
939 | code |= 0x80; | ||
940 | } | ||
941 | |||
942 | return code; | ||
943 | } | ||
944 | |||
945 | /* | ||
914 | * atkbd_set_keycode_table() initializes keyboard's keycode table | 946 | * atkbd_set_keycode_table() initializes keyboard's keycode table |
915 | * according to the selected scancode set | 947 | * according to the selected scancode set |
916 | */ | 948 | */ |
@@ -1087,6 +1119,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) | |||
1087 | } | 1119 | } |
1088 | 1120 | ||
1089 | atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); | 1121 | atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); |
1122 | atkbd_reset_state(atkbd); | ||
1090 | atkbd_activate(atkbd); | 1123 | atkbd_activate(atkbd); |
1091 | 1124 | ||
1092 | } else { | 1125 | } else { |
@@ -1141,6 +1174,18 @@ static int atkbd_reconnect(struct serio *serio) | |||
1141 | return -1; | 1174 | return -1; |
1142 | 1175 | ||
1143 | atkbd_activate(atkbd); | 1176 | atkbd_activate(atkbd); |
1177 | |||
1178 | /* | ||
1179 | * Restore LED state and repeat rate. While input core | ||
1180 | * will do this for us at resume time reconnect may happen | ||
1181 | * because user requested it via sysfs or simply because | ||
1182 | * keyboard was unplugged and plugged in again so we need | ||
1183 | * to do it ourselves here. | ||
1184 | */ | ||
1185 | atkbd_set_leds(atkbd); | ||
1186 | if (!atkbd->softrepeat) | ||
1187 | atkbd_set_repeat_rate(atkbd); | ||
1188 | |||
1144 | } | 1189 | } |
1145 | 1190 | ||
1146 | atkbd_enable(atkbd); | 1191 | atkbd_enable(atkbd); |
@@ -1267,6 +1312,7 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun | |||
1267 | 1312 | ||
1268 | atkbd->dev = new_dev; | 1313 | atkbd->dev = new_dev; |
1269 | atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); | 1314 | atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); |
1315 | atkbd_reset_state(atkbd); | ||
1270 | atkbd_activate(atkbd); | 1316 | atkbd_activate(atkbd); |
1271 | atkbd_set_keycode_table(atkbd); | 1317 | atkbd_set_keycode_table(atkbd); |
1272 | atkbd_set_device_attrs(atkbd); | 1318 | atkbd_set_device_attrs(atkbd); |
@@ -1388,6 +1434,7 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) | |||
1388 | 1434 | ||
1389 | atkbd->dev = new_dev; | 1435 | atkbd->dev = new_dev; |
1390 | atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); | 1436 | atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); |
1437 | atkbd_reset_state(atkbd); | ||
1391 | atkbd_activate(atkbd); | 1438 | atkbd_activate(atkbd); |
1392 | atkbd_set_keycode_table(atkbd); | 1439 | atkbd_set_keycode_table(atkbd); |
1393 | atkbd_set_device_attrs(atkbd); | 1440 | atkbd_set_device_attrs(atkbd); |
@@ -1513,6 +1560,13 @@ static int __init atkbd_setup_forced_release(const struct dmi_system_id *id) | |||
1513 | return 0; | 1560 | return 0; |
1514 | } | 1561 | } |
1515 | 1562 | ||
1563 | static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id) | ||
1564 | { | ||
1565 | atkbd_platform_scancode_fixup = id->driver_data; | ||
1566 | |||
1567 | return 0; | ||
1568 | } | ||
1569 | |||
1516 | static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { | 1570 | static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { |
1517 | { | 1571 | { |
1518 | .ident = "Dell Laptop", | 1572 | .ident = "Dell Laptop", |
@@ -1548,7 +1602,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { | |||
1548 | DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), | 1602 | DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), |
1549 | }, | 1603 | }, |
1550 | .callback = atkbd_setup_forced_release, | 1604 | .callback = atkbd_setup_forced_release, |
1551 | .driver_data = atkbd_hp_zv6100_forced_release_keys, | 1605 | .driver_data = atkbd_volume_forced_release_keys, |
1552 | }, | 1606 | }, |
1553 | { | 1607 | { |
1554 | .ident = "HP Presario R4000", | 1608 | .ident = "HP Presario R4000", |
@@ -1557,7 +1611,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { | |||
1557 | DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"), | 1611 | DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"), |
1558 | }, | 1612 | }, |
1559 | .callback = atkbd_setup_forced_release, | 1613 | .callback = atkbd_setup_forced_release, |
1560 | .driver_data = atkbd_hp_r4000_forced_release_keys, | 1614 | .driver_data = atkbd_volume_forced_release_keys, |
1561 | }, | 1615 | }, |
1562 | { | 1616 | { |
1563 | .ident = "HP Presario R4100", | 1617 | .ident = "HP Presario R4100", |
@@ -1566,7 +1620,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { | |||
1566 | DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"), | 1620 | DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"), |
1567 | }, | 1621 | }, |
1568 | .callback = atkbd_setup_forced_release, | 1622 | .callback = atkbd_setup_forced_release, |
1569 | .driver_data = atkbd_hp_r4000_forced_release_keys, | 1623 | .driver_data = atkbd_volume_forced_release_keys, |
1570 | }, | 1624 | }, |
1571 | { | 1625 | { |
1572 | .ident = "HP Presario R4200", | 1626 | .ident = "HP Presario R4200", |
@@ -1575,7 +1629,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { | |||
1575 | DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"), | 1629 | DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"), |
1576 | }, | 1630 | }, |
1577 | .callback = atkbd_setup_forced_release, | 1631 | .callback = atkbd_setup_forced_release, |
1578 | .driver_data = atkbd_hp_r4000_forced_release_keys, | 1632 | .driver_data = atkbd_volume_forced_release_keys, |
1579 | }, | 1633 | }, |
1580 | { | 1634 | { |
1581 | .ident = "Inventec Symphony", | 1635 | .ident = "Inventec Symphony", |
@@ -1584,7 +1638,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { | |||
1584 | DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), | 1638 | DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), |
1585 | }, | 1639 | }, |
1586 | .callback = atkbd_setup_forced_release, | 1640 | .callback = atkbd_setup_forced_release, |
1587 | .driver_data = atkbd_inventec_forced_release_keys, | 1641 | .driver_data = atkbd_volume_forced_release_keys, |
1588 | }, | 1642 | }, |
1589 | { | 1643 | { |
1590 | .ident = "Samsung NC10", | 1644 | .ident = "Samsung NC10", |
@@ -1620,7 +1674,7 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { | |||
1620 | DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"), | 1674 | DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"), |
1621 | }, | 1675 | }, |
1622 | .callback = atkbd_setup_forced_release, | 1676 | .callback = atkbd_setup_forced_release, |
1623 | .driver_data = atkbd_amilo_pa1510_forced_release_keys, | 1677 | .driver_data = atkbd_volume_forced_release_keys, |
1624 | }, | 1678 | }, |
1625 | { | 1679 | { |
1626 | .ident = "Fujitsu Amilo Pi 3525", | 1680 | .ident = "Fujitsu Amilo Pi 3525", |
@@ -1649,6 +1703,15 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { | |||
1649 | .callback = atkbd_setup_forced_release, | 1703 | .callback = atkbd_setup_forced_release, |
1650 | .driver_data = atkdb_soltech_ta12_forced_release_keys, | 1704 | .driver_data = atkdb_soltech_ta12_forced_release_keys, |
1651 | }, | 1705 | }, |
1706 | { | ||
1707 | .ident = "OQO Model 01+", | ||
1708 | .matches = { | ||
1709 | DMI_MATCH(DMI_SYS_VENDOR, "OQO"), | ||
1710 | DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), | ||
1711 | }, | ||
1712 | .callback = atkbd_setup_scancode_fixup, | ||
1713 | .driver_data = atkbd_oqo_01plus_scancode_fixup, | ||
1714 | }, | ||
1652 | { } | 1715 | { } |
1653 | }; | 1716 | }; |
1654 | 1717 | ||