1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * AT and PS/2 keyboard driver
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (c) 1999-2002 Vojtech Pavlik
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds /*
101da177e4SLinus Torvalds * This driver can handle standard AT keyboards and PS/2 keyboards in
111da177e4SLinus Torvalds * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb
121da177e4SLinus Torvalds * input-only controllers and AT keyboards connected over a one way RS232
131da177e4SLinus Torvalds * converter.
141da177e4SLinus Torvalds */
151da177e4SLinus Torvalds
161da177e4SLinus Torvalds #include <linux/delay.h>
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds #include <linux/slab.h>
191da177e4SLinus Torvalds #include <linux/interrupt.h>
201da177e4SLinus Torvalds #include <linux/init.h>
211da177e4SLinus Torvalds #include <linux/input.h>
2245ceaf14SStephen Boyd #include <linux/input/vivaldi-fmap.h>
231da177e4SLinus Torvalds #include <linux/serio.h>
241da177e4SLinus Torvalds #include <linux/workqueue.h>
251da177e4SLinus Torvalds #include <linux/libps2.h>
2633d3f07aSIngo Molnar #include <linux/mutex.h>
27554101e3SGiel de Nijs #include <linux/dmi.h>
288f7b057aSRajat Jain #include <linux/property.h>
291da177e4SLinus Torvalds
301da177e4SLinus Torvalds #define DRIVER_DESC "AT and PS/2 keyboard driver"
311da177e4SLinus Torvalds
321da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
331da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
341da177e4SLinus Torvalds MODULE_LICENSE("GPL");
351da177e4SLinus Torvalds
361da177e4SLinus Torvalds static int atkbd_set = 2;
371da177e4SLinus Torvalds module_param_named(set, atkbd_set, int, 0);
381da177e4SLinus Torvalds MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
41a9a1f9c3SDmitry Torokhov static bool atkbd_reset;
421da177e4SLinus Torvalds #else
43a9a1f9c3SDmitry Torokhov static bool atkbd_reset = true;
441da177e4SLinus Torvalds #endif
451da177e4SLinus Torvalds module_param_named(reset, atkbd_reset, bool, 0);
461da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
471da177e4SLinus Torvalds
48a9a1f9c3SDmitry Torokhov static bool atkbd_softrepeat;
491da177e4SLinus Torvalds module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
501da177e4SLinus Torvalds MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
511da177e4SLinus Torvalds
52a9a1f9c3SDmitry Torokhov static bool atkbd_softraw = true;
531da177e4SLinus Torvalds module_param_named(softraw, atkbd_softraw, bool, 0);
541da177e4SLinus Torvalds MODULE_PARM_DESC(softraw, "Use software generated rawmode");
551da177e4SLinus Torvalds
56a9a1f9c3SDmitry Torokhov static bool atkbd_scroll;
571da177e4SLinus Torvalds module_param_named(scroll, atkbd_scroll, bool, 0);
581da177e4SLinus Torvalds MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
591da177e4SLinus Torvalds
60a9a1f9c3SDmitry Torokhov static bool atkbd_extra;
611da177e4SLinus Torvalds module_param_named(extra, atkbd_extra, bool, 0);
621da177e4SLinus Torvalds MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
631da177e4SLinus Torvalds
648c5188b6SBenjamin LaHaise static bool atkbd_terminal;
658c5188b6SBenjamin LaHaise module_param_named(terminal, atkbd_terminal, bool, 0);
668c5188b6SBenjamin LaHaise MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
678c5188b6SBenjamin LaHaise
689d17ad23SRajat Jain #define SCANCODE(keymap) ((keymap >> 16) & 0xFFFF)
699d17ad23SRajat Jain #define KEYCODE(keymap) (keymap & 0xFFFF)
709d17ad23SRajat Jain
711da177e4SLinus Torvalds /*
721da177e4SLinus Torvalds * Scancode to keycode tables. These are just the default setting, and
730211a9c8SFrederik Schwarzer * are loadable via a userland utility.
741da177e4SLinus Torvalds */
751da177e4SLinus Torvalds
761ba36e11SDmitry Torokhov #define ATKBD_KEYMAP_SIZE 512
771ba36e11SDmitry Torokhov
781ba36e11SDmitry Torokhov static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds /* XXX: need a more general approach */
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds #include "hpps2atkbd.h" /* include the keyboard scancodes */
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds #else
871da177e4SLinus Torvalds 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
881da177e4SLinus Torvalds 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
891da177e4SLinus Torvalds 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
901da177e4SLinus Torvalds 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
911da177e4SLinus Torvalds 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
92*dc8c9c17SMark Pearson 0, 89, 40, 0, 26, 13, 0,193, 58, 54, 28, 27, 0, 43, 0, 85,
931da177e4SLinus Torvalds 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
941da177e4SLinus Torvalds 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
951da177e4SLinus Torvalds
961da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
971da177e4SLinus Torvalds 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
981da177e4SLinus Torvalds 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
9972a42f24SHans de Goede 159, 0,115, 0,164, 0, 0,116,158, 0,172,166, 0, 0, 0,142,
1001da177e4SLinus Torvalds 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
1011da177e4SLinus Torvalds 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
1021da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
1031da177e4SLinus Torvalds 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
1041da177e4SLinus Torvalds
1051da177e4SLinus Torvalds 0, 0, 0, 65, 99,
1061da177e4SLinus Torvalds #endif
1071da177e4SLinus Torvalds };
1081da177e4SLinus Torvalds
1091ba36e11SDmitry Torokhov static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = {
1101da177e4SLinus Torvalds
1111da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
1121da177e4SLinus Torvalds 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
1131da177e4SLinus Torvalds 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64,
1141da177e4SLinus Torvalds 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66,
1151da177e4SLinus Torvalds 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68,
1161da177e4SLinus Torvalds 113,114, 40, 43, 26, 13, 87, 99, 97, 54, 28, 27, 43, 43, 88, 70,
1171da177e4SLinus Torvalds 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104,
1181da177e4SLinus Torvalds 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55,183,
1191da177e4SLinus Torvalds
1201da177e4SLinus Torvalds 184,185,186,187, 74, 94, 92, 93, 0, 0, 0,125,126,127,112, 0,
12172a42f24SHans de Goede 0,139,172,163,165,115,152,172,166,140,160,154,113,114,167,168,
1221da177e4SLinus Torvalds 148,149,147,140
1231da177e4SLinus Torvalds };
1241da177e4SLinus Torvalds
125f6d65610SDmitry Torokhov static const unsigned short atkbd_unxlate_table[128] = {
1261da177e4SLinus Torvalds 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
1271da177e4SLinus Torvalds 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
1281da177e4SLinus Torvalds 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
1291da177e4SLinus Torvalds 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
1301da177e4SLinus Torvalds 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
1311da177e4SLinus Torvalds 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
1321da177e4SLinus Torvalds 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
1331da177e4SLinus Torvalds 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
1341da177e4SLinus Torvalds };
1351da177e4SLinus Torvalds
1361da177e4SLinus Torvalds #define ATKBD_CMD_SETLEDS 0x10ed
1371da177e4SLinus Torvalds #define ATKBD_CMD_GSCANSET 0x11f0
1381da177e4SLinus Torvalds #define ATKBD_CMD_SSCANSET 0x10f0
1391da177e4SLinus Torvalds #define ATKBD_CMD_GETID 0x02f2
1401da177e4SLinus Torvalds #define ATKBD_CMD_SETREP 0x10f3
1411da177e4SLinus Torvalds #define ATKBD_CMD_ENABLE 0x00f4
1424a299bf5SDmitry Torokhov #define ATKBD_CMD_RESET_DIS 0x00f5 /* Reset to defaults and disable */
1434a299bf5SDmitry Torokhov #define ATKBD_CMD_RESET_DEF 0x00f6 /* Reset to defaults */
1448c5188b6SBenjamin LaHaise #define ATKBD_CMD_SETALL_MB 0x00f8 /* Set all keys to give break codes */
1458c5188b6SBenjamin LaHaise #define ATKBD_CMD_SETALL_MBR 0x00fa /* ... and repeat */
1461da177e4SLinus Torvalds #define ATKBD_CMD_RESET_BAT 0x02ff
1471da177e4SLinus Torvalds #define ATKBD_CMD_RESEND 0x00fe
1481da177e4SLinus Torvalds #define ATKBD_CMD_EX_ENABLE 0x10ea
1491da177e4SLinus Torvalds #define ATKBD_CMD_EX_SETLEDS 0x20eb
1501da177e4SLinus Torvalds #define ATKBD_CMD_OK_GETID 0x02e8
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds #define ATKBD_RET_ACK 0xfa
1531da177e4SLinus Torvalds #define ATKBD_RET_NAK 0xfe
1541da177e4SLinus Torvalds #define ATKBD_RET_BAT 0xaa
1551da177e4SLinus Torvalds #define ATKBD_RET_EMUL0 0xe0
1561da177e4SLinus Torvalds #define ATKBD_RET_EMUL1 0xe1
1571da177e4SLinus Torvalds #define ATKBD_RET_RELEASE 0xf0
1580ae051a1SDmitry Torokhov #define ATKBD_RET_HANJA 0xf1
1590ae051a1SDmitry Torokhov #define ATKBD_RET_HANGEUL 0xf2
1601da177e4SLinus Torvalds #define ATKBD_RET_ERR 0xff
1611da177e4SLinus Torvalds
1621da177e4SLinus Torvalds #define ATKBD_KEY_UNKNOWN 0
1631da177e4SLinus Torvalds #define ATKBD_KEY_NULL 255
1641da177e4SLinus Torvalds
1654b70858bSDmitry Torokhov #define ATKBD_SCR_1 0xfffe
1664b70858bSDmitry Torokhov #define ATKBD_SCR_2 0xfffd
1674b70858bSDmitry Torokhov #define ATKBD_SCR_4 0xfffc
1684b70858bSDmitry Torokhov #define ATKBD_SCR_8 0xfffb
1694b70858bSDmitry Torokhov #define ATKBD_SCR_CLICK 0xfffa
1704b70858bSDmitry Torokhov #define ATKBD_SCR_LEFT 0xfff9
1714b70858bSDmitry Torokhov #define ATKBD_SCR_RIGHT 0xfff8
1721da177e4SLinus Torvalds
173f6d65610SDmitry Torokhov #define ATKBD_SPECIAL ATKBD_SCR_RIGHT
1741da177e4SLinus Torvalds
1750d4c8597SDmitry Torokhov #define ATKBD_LED_EVENT_BIT 0
1760d4c8597SDmitry Torokhov #define ATKBD_REP_EVENT_BIT 1
1770d4c8597SDmitry Torokhov
1780ae051a1SDmitry Torokhov #define ATKBD_XL_ERR 0x01
1790ae051a1SDmitry Torokhov #define ATKBD_XL_BAT 0x02
1800ae051a1SDmitry Torokhov #define ATKBD_XL_ACK 0x04
1810ae051a1SDmitry Torokhov #define ATKBD_XL_NAK 0x08
1820ae051a1SDmitry Torokhov #define ATKBD_XL_HANGEUL 0x10
1830ae051a1SDmitry Torokhov #define ATKBD_XL_HANJA 0x20
1840ae051a1SDmitry Torokhov
185f6d65610SDmitry Torokhov static const struct {
1864b70858bSDmitry Torokhov unsigned short keycode;
1871da177e4SLinus Torvalds unsigned char set2;
1881da177e4SLinus Torvalds } atkbd_scroll_keys[] = {
1891da177e4SLinus Torvalds { ATKBD_SCR_1, 0xc5 },
1905212dd58SVojtech Pavlik { ATKBD_SCR_2, 0x9d },
1915212dd58SVojtech Pavlik { ATKBD_SCR_4, 0xa4 },
1925212dd58SVojtech Pavlik { ATKBD_SCR_8, 0x9b },
1931da177e4SLinus Torvalds { ATKBD_SCR_CLICK, 0xe0 },
1941da177e4SLinus Torvalds { ATKBD_SCR_LEFT, 0xcb },
1951da177e4SLinus Torvalds { ATKBD_SCR_RIGHT, 0xd2 },
1961da177e4SLinus Torvalds };
1971da177e4SLinus Torvalds
1981da177e4SLinus Torvalds /*
1991da177e4SLinus Torvalds * The atkbd control structure
2001da177e4SLinus Torvalds */
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds struct atkbd {
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds struct ps2dev ps2dev;
2053c42f0c3SDmitry Torokhov struct input_dev *dev;
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds /* Written only during init */
2081da177e4SLinus Torvalds char name[64];
2091da177e4SLinus Torvalds char phys[32];
2101da177e4SLinus Torvalds
2111da177e4SLinus Torvalds unsigned short id;
2121ba36e11SDmitry Torokhov unsigned short keycode[ATKBD_KEYMAP_SIZE];
2131ba36e11SDmitry Torokhov DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
2141da177e4SLinus Torvalds unsigned char set;
215a9a1f9c3SDmitry Torokhov bool translated;
216a9a1f9c3SDmitry Torokhov bool extra;
217a9a1f9c3SDmitry Torokhov bool write;
218a9a1f9c3SDmitry Torokhov bool softrepeat;
219a9a1f9c3SDmitry Torokhov bool softraw;
220a9a1f9c3SDmitry Torokhov bool scroll;
221a9a1f9c3SDmitry Torokhov bool enabled;
2221da177e4SLinus Torvalds
2231da177e4SLinus Torvalds /* Accessed only from interrupt */
2241da177e4SLinus Torvalds unsigned char emul;
225a9a1f9c3SDmitry Torokhov bool resend;
226a9a1f9c3SDmitry Torokhov bool release;
2270ae051a1SDmitry Torokhov unsigned long xl_bit;
2281da177e4SLinus Torvalds unsigned int last;
2291da177e4SLinus Torvalds unsigned long time;
23086255d9dSDmitry Torokhov unsigned long err_count;
2310d4c8597SDmitry Torokhov
232da4249c9SDmitry Torokhov struct delayed_work event_work;
233da4249c9SDmitry Torokhov unsigned long event_jiffies;
2340d4c8597SDmitry Torokhov unsigned long event_mask;
23559b01513SEric W. Biederman
23659b01513SEric W. Biederman /* Serializes reconnect(), attr->set() and event work */
23759b01513SEric W. Biederman struct mutex mutex;
2388f7b057aSRajat Jain
23945ceaf14SStephen Boyd struct vivaldi_data vdata;
2401da177e4SLinus Torvalds };
2411da177e4SLinus Torvalds
242554101e3SGiel de Nijs /*
24336726dd9SThadeu Lima de Souza Cascardo * System-specific keymap fixup routine
244554101e3SGiel de Nijs */
24539191698SDaniel Mierswa static void (*atkbd_platform_fixup)(struct atkbd *, const void *data);
24639191698SDaniel Mierswa static void *atkbd_platform_fixup_data;
247e5713069SJamie Lentin static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int);
248554101e3SGiel de Nijs
2493d725caaSSheng-Liang Song /*
2503d725caaSSheng-Liang Song * Certain keyboards to not like ATKBD_CMD_RESET_DIS and stop responding
2513d725caaSSheng-Liang Song * to many commands until full reset (ATKBD_CMD_RESET_BAT) is performed.
2523d725caaSSheng-Liang Song */
2533d725caaSSheng-Liang Song static bool atkbd_skip_deactivate;
2543d725caaSSheng-Liang Song
2551da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
2561da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, char *));
2571da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
2581da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, const char *, size_t));
2591da177e4SLinus Torvalds #define ATKBD_DEFINE_ATTR(_name) \
2601da177e4SLinus Torvalds static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
2611da177e4SLinus Torvalds static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \
26286255d9dSDmitry Torokhov static ssize_t atkbd_do_show_##_name(struct device *d, \
26386255d9dSDmitry Torokhov struct device_attribute *attr, char *b) \
2641da177e4SLinus Torvalds { \
2651da177e4SLinus Torvalds return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
2661da177e4SLinus Torvalds } \
26786255d9dSDmitry Torokhov static ssize_t atkbd_do_set_##_name(struct device *d, \
26886255d9dSDmitry Torokhov struct device_attribute *attr, const char *b, size_t s) \
2691da177e4SLinus Torvalds { \
2701da177e4SLinus Torvalds return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
2711da177e4SLinus Torvalds } \
2721da177e4SLinus Torvalds static struct device_attribute atkbd_attr_##_name = \
2731da177e4SLinus Torvalds __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
2741da177e4SLinus Torvalds
2751da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(extra);
2761ba36e11SDmitry Torokhov ATKBD_DEFINE_ATTR(force_release);
2771da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(scroll);
2781da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(set);
2791da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(softrepeat);
2801da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(softraw);
2811da177e4SLinus Torvalds
28286255d9dSDmitry Torokhov #define ATKBD_DEFINE_RO_ATTR(_name) \
28386255d9dSDmitry Torokhov static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
28486255d9dSDmitry Torokhov static ssize_t atkbd_do_show_##_name(struct device *d, \
28586255d9dSDmitry Torokhov struct device_attribute *attr, char *b) \
28686255d9dSDmitry Torokhov { \
28786255d9dSDmitry Torokhov return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
28886255d9dSDmitry Torokhov } \
28986255d9dSDmitry Torokhov static struct device_attribute atkbd_attr_##_name = \
29086255d9dSDmitry Torokhov __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);
29186255d9dSDmitry Torokhov
29286255d9dSDmitry Torokhov ATKBD_DEFINE_RO_ATTR(err_count);
2938f7b057aSRajat Jain ATKBD_DEFINE_RO_ATTR(function_row_physmap);
29486255d9dSDmitry Torokhov
29586255d9dSDmitry Torokhov static struct attribute *atkbd_attributes[] = {
29686255d9dSDmitry Torokhov &atkbd_attr_extra.attr,
2971ba36e11SDmitry Torokhov &atkbd_attr_force_release.attr,
29886255d9dSDmitry Torokhov &atkbd_attr_scroll.attr,
29986255d9dSDmitry Torokhov &atkbd_attr_set.attr,
30086255d9dSDmitry Torokhov &atkbd_attr_softrepeat.attr,
30186255d9dSDmitry Torokhov &atkbd_attr_softraw.attr,
30286255d9dSDmitry Torokhov &atkbd_attr_err_count.attr,
3038f7b057aSRajat Jain &atkbd_attr_function_row_physmap.attr,
30486255d9dSDmitry Torokhov NULL
30586255d9dSDmitry Torokhov };
30686255d9dSDmitry Torokhov
atkbd_show_function_row_physmap(struct atkbd * atkbd,char * buf)3078f7b057aSRajat Jain static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf)
3088f7b057aSRajat Jain {
30945ceaf14SStephen Boyd return vivaldi_function_row_physmap_show(&atkbd->vdata, buf);
3108f7b057aSRajat Jain }
3118f7b057aSRajat Jain
atkbd_from_serio(struct serio * serio)312100e1695SDmitry Torokhov static struct atkbd *atkbd_from_serio(struct serio *serio)
313100e1695SDmitry Torokhov {
314100e1695SDmitry Torokhov struct ps2dev *ps2dev = serio_get_drvdata(serio);
315100e1695SDmitry Torokhov
316100e1695SDmitry Torokhov return container_of(ps2dev, struct atkbd, ps2dev);
317100e1695SDmitry Torokhov }
318100e1695SDmitry Torokhov
atkbd_attr_is_visible(struct kobject * kobj,struct attribute * attr,int i)3198f7b057aSRajat Jain static umode_t atkbd_attr_is_visible(struct kobject *kobj,
3208f7b057aSRajat Jain struct attribute *attr, int i)
3218f7b057aSRajat Jain {
32250221b0bSYueHaibing struct device *dev = kobj_to_dev(kobj);
3238f7b057aSRajat Jain struct serio *serio = to_serio_port(dev);
324100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
3258f7b057aSRajat Jain
3268f7b057aSRajat Jain if (attr == &atkbd_attr_function_row_physmap.attr &&
32745ceaf14SStephen Boyd !atkbd->vdata.num_function_row_keys)
3288f7b057aSRajat Jain return 0;
3298f7b057aSRajat Jain
3308f7b057aSRajat Jain return attr->mode;
3318f7b057aSRajat Jain }
3328f7b057aSRajat Jain
333c99e3ac6SDmitry Torokhov static const struct attribute_group atkbd_attribute_group = {
33486255d9dSDmitry Torokhov .attrs = atkbd_attributes,
3358f7b057aSRajat Jain .is_visible = atkbd_attr_is_visible,
33686255d9dSDmitry Torokhov };
33786255d9dSDmitry Torokhov
338c99e3ac6SDmitry Torokhov __ATTRIBUTE_GROUPS(atkbd_attribute);
339c99e3ac6SDmitry Torokhov
3400ae051a1SDmitry Torokhov static const unsigned int xl_table[] = {
3410ae051a1SDmitry Torokhov ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
3420ae051a1SDmitry Torokhov ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
3430ae051a1SDmitry Torokhov };
3441da177e4SLinus Torvalds
3450ae051a1SDmitry Torokhov /*
3460ae051a1SDmitry Torokhov * Checks if we should mangle the scancode to extract 'release' bit
3470ae051a1SDmitry Torokhov * in translated mode.
3480ae051a1SDmitry Torokhov */
atkbd_need_xlate(unsigned long xl_bit,unsigned char code)349a9a1f9c3SDmitry Torokhov static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
3501da177e4SLinus Torvalds {
3510ae051a1SDmitry Torokhov int i;
3520ae051a1SDmitry Torokhov
3530ae051a1SDmitry Torokhov if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
354a9a1f9c3SDmitry Torokhov return false;
3550ae051a1SDmitry Torokhov
3560ae051a1SDmitry Torokhov for (i = 0; i < ARRAY_SIZE(xl_table); i++)
3570ae051a1SDmitry Torokhov if (code == xl_table[i])
3580ae051a1SDmitry Torokhov return test_bit(i, &xl_bit);
3590ae051a1SDmitry Torokhov
360a9a1f9c3SDmitry Torokhov return true;
3610ae051a1SDmitry Torokhov }
3620ae051a1SDmitry Torokhov
3630ae051a1SDmitry Torokhov /*
3640ae051a1SDmitry Torokhov * Calculates new value of xl_bit so the driver can distinguish
3650ae051a1SDmitry Torokhov * between make/break pair of scancodes for select keys and PS/2
3660ae051a1SDmitry Torokhov * protocol responses.
3670ae051a1SDmitry Torokhov */
atkbd_calculate_xl_bit(struct atkbd * atkbd,unsigned char code)3680ae051a1SDmitry Torokhov static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code)
3690ae051a1SDmitry Torokhov {
3700ae051a1SDmitry Torokhov int i;
3710ae051a1SDmitry Torokhov
3720ae051a1SDmitry Torokhov for (i = 0; i < ARRAY_SIZE(xl_table); i++) {
3730ae051a1SDmitry Torokhov if (!((code ^ xl_table[i]) & 0x7f)) {
3740ae051a1SDmitry Torokhov if (code & 0x80)
3750ae051a1SDmitry Torokhov __clear_bit(i, &atkbd->xl_bit);
3760ae051a1SDmitry Torokhov else
3770ae051a1SDmitry Torokhov __set_bit(i, &atkbd->xl_bit);
3780ae051a1SDmitry Torokhov break;
3790ae051a1SDmitry Torokhov }
3800ae051a1SDmitry Torokhov }
3810ae051a1SDmitry Torokhov }
3820ae051a1SDmitry Torokhov
3830ae051a1SDmitry Torokhov /*
3840ae051a1SDmitry Torokhov * Encode the scancode, 0xe0 prefix, and high bit into a single integer,
3850ae051a1SDmitry Torokhov * keeping kernel 2.4 compatibility for set 2
3860ae051a1SDmitry Torokhov */
atkbd_compat_scancode(struct atkbd * atkbd,unsigned int code)3870ae051a1SDmitry Torokhov static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code)
3880ae051a1SDmitry Torokhov {
3890ae051a1SDmitry Torokhov if (atkbd->set == 3) {
3900ae051a1SDmitry Torokhov if (atkbd->emul == 1)
3910ae051a1SDmitry Torokhov code |= 0x100;
3920ae051a1SDmitry Torokhov } else {
3930ae051a1SDmitry Torokhov code = (code & 0x7f) | ((code & 0x80) << 1);
3940ae051a1SDmitry Torokhov if (atkbd->emul == 1)
3950ae051a1SDmitry Torokhov code |= 0x80;
3960ae051a1SDmitry Torokhov }
3970ae051a1SDmitry Torokhov
3980ae051a1SDmitry Torokhov return code;
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds
4011da177e4SLinus Torvalds /*
402c4c7eac8SDmitry Torokhov * Tries to handle frame or parity error by requesting the keyboard controller
403c4c7eac8SDmitry Torokhov * to resend the last byte. This historically not done on x86 as controllers
404c4c7eac8SDmitry Torokhov * there typically do not implement this command.
4051da177e4SLinus Torvalds */
atkbd_handle_frame_error(struct ps2dev * ps2dev,u8 data,unsigned int flags)406c4c7eac8SDmitry Torokhov static bool __maybe_unused atkbd_handle_frame_error(struct ps2dev *ps2dev,
407c4c7eac8SDmitry Torokhov u8 data, unsigned int flags)
4081da177e4SLinus Torvalds {
409c4c7eac8SDmitry Torokhov struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev);
410c4c7eac8SDmitry Torokhov struct serio *serio = ps2dev->serio;
411c4c7eac8SDmitry Torokhov
412c4c7eac8SDmitry Torokhov if ((flags & (SERIO_FRAME | SERIO_PARITY)) &&
413c4c7eac8SDmitry Torokhov (~flags & SERIO_TIMEOUT) &&
414c4c7eac8SDmitry Torokhov !atkbd->resend && atkbd->write) {
415c4c7eac8SDmitry Torokhov dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
416c4c7eac8SDmitry Torokhov serio_write(serio, ATKBD_CMD_RESEND);
417c4c7eac8SDmitry Torokhov atkbd->resend = true;
418c4c7eac8SDmitry Torokhov return true;
419c4c7eac8SDmitry Torokhov }
420c4c7eac8SDmitry Torokhov
421c4c7eac8SDmitry Torokhov if (!flags && data == ATKBD_RET_ACK)
422c4c7eac8SDmitry Torokhov atkbd->resend = false;
423c4c7eac8SDmitry Torokhov
424c4c7eac8SDmitry Torokhov return false;
425c4c7eac8SDmitry Torokhov }
426c4c7eac8SDmitry Torokhov
atkbd_pre_receive_byte(struct ps2dev * ps2dev,u8 data,unsigned int flags)427c4c7eac8SDmitry Torokhov static enum ps2_disposition atkbd_pre_receive_byte(struct ps2dev *ps2dev,
428c4c7eac8SDmitry Torokhov u8 data, unsigned int flags)
429c4c7eac8SDmitry Torokhov {
430c4c7eac8SDmitry Torokhov struct serio *serio = ps2dev->serio;
431c4c7eac8SDmitry Torokhov
432c4c7eac8SDmitry Torokhov dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
433c4c7eac8SDmitry Torokhov
434c4c7eac8SDmitry Torokhov #if !defined(__i386__) && !defined (__x86_64__)
435c4c7eac8SDmitry Torokhov if (atkbd_handle_frame_error(ps2dev, data, flags))
436c4c7eac8SDmitry Torokhov return PS2_IGNORE;
437c4c7eac8SDmitry Torokhov #endif
438c4c7eac8SDmitry Torokhov
439c4c7eac8SDmitry Torokhov return PS2_PROCESS;
440c4c7eac8SDmitry Torokhov }
441c4c7eac8SDmitry Torokhov
atkbd_receive_byte(struct ps2dev * ps2dev,u8 data)442c4c7eac8SDmitry Torokhov static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data)
443c4c7eac8SDmitry Torokhov {
444c4c7eac8SDmitry Torokhov struct serio *serio = ps2dev->serio;
445c4c7eac8SDmitry Torokhov struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev);
4460ae051a1SDmitry Torokhov struct input_dev *dev = atkbd->dev;
4471da177e4SLinus Torvalds unsigned int code = data;
448554101e3SGiel de Nijs int scroll = 0, hscroll = 0, click = -1;
4491da177e4SLinus Torvalds int value;
450f6d65610SDmitry Torokhov unsigned short keycode;
4511da177e4SLinus Torvalds
452aaca981eSDmitry Torokhov pm_wakeup_event(&serio->dev, 0);
453aaca981eSDmitry Torokhov
4541da177e4SLinus Torvalds if (!atkbd->enabled)
455c4c7eac8SDmitry Torokhov return;
4561da177e4SLinus Torvalds
4570ae051a1SDmitry Torokhov input_event(dev, EV_MSC, MSC_RAW, code);
4581da177e4SLinus Torvalds
459e5713069SJamie Lentin if (atkbd_platform_scancode_fixup)
460e5713069SJamie Lentin code = atkbd_platform_scancode_fixup(atkbd, code);
461e5713069SJamie Lentin
4621da177e4SLinus Torvalds if (atkbd->translated) {
4631da177e4SLinus Torvalds
4640ae051a1SDmitry Torokhov if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
4651da177e4SLinus Torvalds atkbd->release = code >> 7;
4661da177e4SLinus Torvalds code &= 0x7f;
4671da177e4SLinus Torvalds }
4681da177e4SLinus Torvalds
4690ae051a1SDmitry Torokhov if (!atkbd->emul)
4700ae051a1SDmitry Torokhov atkbd_calculate_xl_bit(atkbd, data);
4711da177e4SLinus Torvalds }
4721da177e4SLinus Torvalds
4731da177e4SLinus Torvalds switch (code) {
4741da177e4SLinus Torvalds case ATKBD_RET_BAT:
475a9a1f9c3SDmitry Torokhov atkbd->enabled = false;
476dbc26344SDmitry Torokhov serio_reconnect(atkbd->ps2dev.serio);
477c4c7eac8SDmitry Torokhov return;
4781da177e4SLinus Torvalds case ATKBD_RET_EMUL0:
4791da177e4SLinus Torvalds atkbd->emul = 1;
480c4c7eac8SDmitry Torokhov return;
4811da177e4SLinus Torvalds case ATKBD_RET_EMUL1:
4821da177e4SLinus Torvalds atkbd->emul = 2;
483c4c7eac8SDmitry Torokhov return;
4841da177e4SLinus Torvalds case ATKBD_RET_RELEASE:
485a9a1f9c3SDmitry Torokhov atkbd->release = true;
486c4c7eac8SDmitry Torokhov return;
4870ae051a1SDmitry Torokhov case ATKBD_RET_ACK:
4880ae051a1SDmitry Torokhov case ATKBD_RET_NAK:
4899f7a60d6SQi Yong if (printk_ratelimit())
490a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev,
491a9a1f9c3SDmitry Torokhov "Spurious %s on %s. "
492f57fe78eSJesper Juhl "Some program might be trying to access hardware directly.\n",
4930ae051a1SDmitry Torokhov data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
494c4c7eac8SDmitry Torokhov return;
4951da177e4SLinus Torvalds case ATKBD_RET_ERR:
49686255d9dSDmitry Torokhov atkbd->err_count++;
497a9a1f9c3SDmitry Torokhov dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
498a9a1f9c3SDmitry Torokhov serio->phys);
499c4c7eac8SDmitry Torokhov return;
5001da177e4SLinus Torvalds }
5011da177e4SLinus Torvalds
5020ae051a1SDmitry Torokhov code = atkbd_compat_scancode(atkbd, code);
5030ae051a1SDmitry Torokhov
5040ae051a1SDmitry Torokhov if (atkbd->emul && --atkbd->emul)
505c4c7eac8SDmitry Torokhov return;
5061da177e4SLinus Torvalds
5070ae051a1SDmitry Torokhov keycode = atkbd->keycode[code];
5081da177e4SLinus Torvalds
5095447326fSStefan Brüns if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
5100ae051a1SDmitry Torokhov if (keycode != ATKBD_KEY_NULL)
5110ae051a1SDmitry Torokhov input_event(dev, EV_MSC, MSC_SCAN, code);
5120ae051a1SDmitry Torokhov
5130ae051a1SDmitry Torokhov switch (keycode) {
5141da177e4SLinus Torvalds case ATKBD_KEY_NULL:
5151da177e4SLinus Torvalds break;
5161da177e4SLinus Torvalds case ATKBD_KEY_UNKNOWN:
517a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev,
518a9a1f9c3SDmitry Torokhov "Unknown key %s (%s set %d, code %#x on %s).\n",
5191da177e4SLinus Torvalds atkbd->release ? "released" : "pressed",
5201da177e4SLinus Torvalds atkbd->translated ? "translated" : "raw",
5211da177e4SLinus Torvalds atkbd->set, code, serio->phys);
522a9a1f9c3SDmitry Torokhov dev_warn(&serio->dev,
523a9a1f9c3SDmitry Torokhov "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
5241da177e4SLinus Torvalds code & 0x80 ? "e0" : "", code & 0x7f);
5250ae051a1SDmitry Torokhov input_sync(dev);
5261da177e4SLinus Torvalds break;
5271da177e4SLinus Torvalds case ATKBD_SCR_1:
528a9a1f9c3SDmitry Torokhov scroll = 1;
5291da177e4SLinus Torvalds break;
5301da177e4SLinus Torvalds case ATKBD_SCR_2:
531a9a1f9c3SDmitry Torokhov scroll = 2;
5321da177e4SLinus Torvalds break;
5331da177e4SLinus Torvalds case ATKBD_SCR_4:
534a9a1f9c3SDmitry Torokhov scroll = 4;
5351da177e4SLinus Torvalds break;
5361da177e4SLinus Torvalds case ATKBD_SCR_8:
537a9a1f9c3SDmitry Torokhov scroll = 8;
5381da177e4SLinus Torvalds break;
5391da177e4SLinus Torvalds case ATKBD_SCR_CLICK:
5401da177e4SLinus Torvalds click = !atkbd->release;
5411da177e4SLinus Torvalds break;
5421da177e4SLinus Torvalds case ATKBD_SCR_LEFT:
5431da177e4SLinus Torvalds hscroll = -1;
5441da177e4SLinus Torvalds break;
5451da177e4SLinus Torvalds case ATKBD_SCR_RIGHT:
5461da177e4SLinus Torvalds hscroll = 1;
5471da177e4SLinus Torvalds break;
5481da177e4SLinus Torvalds default:
5490ae051a1SDmitry Torokhov if (atkbd->release) {
5500ae051a1SDmitry Torokhov value = 0;
5511da177e4SLinus Torvalds atkbd->last = 0;
5520ae051a1SDmitry Torokhov } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
5530ae051a1SDmitry Torokhov /* Workaround Toshiba laptop multiple keypress */
5540ae051a1SDmitry Torokhov value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
5550ae051a1SDmitry Torokhov } else {
5561da177e4SLinus Torvalds value = 1;
5570ae051a1SDmitry Torokhov atkbd->last = code;
5580ae051a1SDmitry Torokhov atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
5591da177e4SLinus Torvalds }
5601da177e4SLinus Torvalds
561f8b4c46cSDmitry Torokhov input_event(dev, EV_KEY, keycode, value);
5620ae051a1SDmitry Torokhov input_sync(dev);
5630ae051a1SDmitry Torokhov
564554101e3SGiel de Nijs if (value && test_bit(code, atkbd->force_release_mask)) {
5655447326fSStefan Brüns input_event(dev, EV_MSC, MSC_SCAN, code);
5660ae051a1SDmitry Torokhov input_report_key(dev, keycode, 0);
5670ae051a1SDmitry Torokhov input_sync(dev);
5680ae051a1SDmitry Torokhov }
5691da177e4SLinus Torvalds }
5701da177e4SLinus Torvalds
5711da177e4SLinus Torvalds if (atkbd->scroll) {
5721da177e4SLinus Torvalds if (click != -1)
5730ae051a1SDmitry Torokhov input_report_key(dev, BTN_MIDDLE, click);
574a9a1f9c3SDmitry Torokhov input_report_rel(dev, REL_WHEEL,
575a9a1f9c3SDmitry Torokhov atkbd->release ? -scroll : scroll);
5760ae051a1SDmitry Torokhov input_report_rel(dev, REL_HWHEEL, hscroll);
5770ae051a1SDmitry Torokhov input_sync(dev);
5781da177e4SLinus Torvalds }
5791da177e4SLinus Torvalds
580a9a1f9c3SDmitry Torokhov atkbd->release = false;
5811da177e4SLinus Torvalds }
5821da177e4SLinus Torvalds
atkbd_set_repeat_rate(struct atkbd * atkbd)5833d0f0fa0SDmitry Torokhov static int atkbd_set_repeat_rate(struct atkbd *atkbd)
5841da177e4SLinus Torvalds {
5851da177e4SLinus Torvalds const short period[32] =
5861da177e4SLinus Torvalds { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
5871da177e4SLinus Torvalds 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
5881da177e4SLinus Torvalds const short delay[4] =
5891da177e4SLinus Torvalds { 250, 500, 750, 1000 };
5900d4c8597SDmitry Torokhov
5913d0f0fa0SDmitry Torokhov struct input_dev *dev = atkbd->dev;
5923d0f0fa0SDmitry Torokhov unsigned char param;
5933d0f0fa0SDmitry Torokhov int i = 0, j = 0;
5943d0f0fa0SDmitry Torokhov
5953d0f0fa0SDmitry Torokhov while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
5963d0f0fa0SDmitry Torokhov i++;
5973d0f0fa0SDmitry Torokhov dev->rep[REP_PERIOD] = period[i];
5983d0f0fa0SDmitry Torokhov
5998ea371fbSFlorin Malita while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY])
6003d0f0fa0SDmitry Torokhov j++;
6013d0f0fa0SDmitry Torokhov dev->rep[REP_DELAY] = delay[j];
6023d0f0fa0SDmitry Torokhov
6033d0f0fa0SDmitry Torokhov param = i | (j << 5);
6043d0f0fa0SDmitry Torokhov return ps2_command(&atkbd->ps2dev, ¶m, ATKBD_CMD_SETREP);
6053d0f0fa0SDmitry Torokhov }
6063d0f0fa0SDmitry Torokhov
atkbd_set_leds(struct atkbd * atkbd)6073d0f0fa0SDmitry Torokhov static int atkbd_set_leds(struct atkbd *atkbd)
6083d0f0fa0SDmitry Torokhov {
6090d4c8597SDmitry Torokhov struct input_dev *dev = atkbd->dev;
6101da177e4SLinus Torvalds unsigned char param[2];
6111da177e4SLinus Torvalds
6121da177e4SLinus Torvalds param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
6131da177e4SLinus Torvalds | (test_bit(LED_NUML, dev->led) ? 2 : 0)
6141da177e4SLinus Torvalds | (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
6153d0f0fa0SDmitry Torokhov if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
6163d0f0fa0SDmitry Torokhov return -1;
6171da177e4SLinus Torvalds
6181da177e4SLinus Torvalds if (atkbd->extra) {
6191da177e4SLinus Torvalds param[0] = 0;
6201da177e4SLinus Torvalds param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
6211da177e4SLinus Torvalds | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
6221da177e4SLinus Torvalds | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
6231da177e4SLinus Torvalds | (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
6241da177e4SLinus Torvalds | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
6253d0f0fa0SDmitry Torokhov if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS))
6263d0f0fa0SDmitry Torokhov return -1;
6271da177e4SLinus Torvalds }
6281da177e4SLinus Torvalds
6293d0f0fa0SDmitry Torokhov return 0;
6300d4c8597SDmitry Torokhov }
6310d4c8597SDmitry Torokhov
6323d0f0fa0SDmitry Torokhov /*
6333d0f0fa0SDmitry Torokhov * atkbd_event_work() is used to complete processing of events that
6343d0f0fa0SDmitry Torokhov * can not be processed by input_event() which is often called from
6353d0f0fa0SDmitry Torokhov * interrupt context.
6363d0f0fa0SDmitry Torokhov */
6373d0f0fa0SDmitry Torokhov
atkbd_event_work(struct work_struct * work)63865f27f38SDavid Howells static void atkbd_event_work(struct work_struct *work)
6393d0f0fa0SDmitry Torokhov {
640da4249c9SDmitry Torokhov struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);
6413d0f0fa0SDmitry Torokhov
64259b01513SEric W. Biederman mutex_lock(&atkbd->mutex);
6433d0f0fa0SDmitry Torokhov
64494dfb0d6SDmitry Torokhov if (!atkbd->enabled) {
64594dfb0d6SDmitry Torokhov /*
64694dfb0d6SDmitry Torokhov * Serio ports are resumed asynchronously so while driver core
64794dfb0d6SDmitry Torokhov * thinks that device is already fully operational in reality
64894dfb0d6SDmitry Torokhov * it may not be ready yet. In this case we need to keep
64994dfb0d6SDmitry Torokhov * rescheduling till reconnect completes.
65094dfb0d6SDmitry Torokhov */
65194dfb0d6SDmitry Torokhov schedule_delayed_work(&atkbd->event_work,
65294dfb0d6SDmitry Torokhov msecs_to_jiffies(100));
65394dfb0d6SDmitry Torokhov } else {
6543d0f0fa0SDmitry Torokhov if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
6553d0f0fa0SDmitry Torokhov atkbd_set_leds(atkbd);
6563d0f0fa0SDmitry Torokhov
6573d0f0fa0SDmitry Torokhov if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
6583d0f0fa0SDmitry Torokhov atkbd_set_repeat_rate(atkbd);
65994dfb0d6SDmitry Torokhov }
6603d0f0fa0SDmitry Torokhov
66159b01513SEric W. Biederman mutex_unlock(&atkbd->mutex);
6620d4c8597SDmitry Torokhov }
6630d4c8597SDmitry Torokhov
6640d4c8597SDmitry Torokhov /*
665da4249c9SDmitry Torokhov * Schedule switch for execution. We need to throttle requests,
666da4249c9SDmitry Torokhov * otherwise keyboard may become unresponsive.
667da4249c9SDmitry Torokhov */
atkbd_schedule_event_work(struct atkbd * atkbd,int event_bit)668da4249c9SDmitry Torokhov static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
669da4249c9SDmitry Torokhov {
670da4249c9SDmitry Torokhov unsigned long delay = msecs_to_jiffies(50);
671da4249c9SDmitry Torokhov
672da4249c9SDmitry Torokhov if (time_after(jiffies, atkbd->event_jiffies + delay))
673da4249c9SDmitry Torokhov delay = 0;
674da4249c9SDmitry Torokhov
675da4249c9SDmitry Torokhov atkbd->event_jiffies = jiffies;
676da4249c9SDmitry Torokhov set_bit(event_bit, &atkbd->event_mask);
67759b01513SEric W. Biederman mb();
678da4249c9SDmitry Torokhov schedule_delayed_work(&atkbd->event_work, delay);
679da4249c9SDmitry Torokhov }
680da4249c9SDmitry Torokhov
681da4249c9SDmitry Torokhov /*
6820d4c8597SDmitry Torokhov * Event callback from the input module. Events that change the state of
6830d4c8597SDmitry Torokhov * the hardware are processed here. If action can not be performed in
6840d4c8597SDmitry Torokhov * interrupt context it is offloaded to atkbd_event_work.
6850d4c8597SDmitry Torokhov */
6860d4c8597SDmitry Torokhov
atkbd_event(struct input_dev * dev,unsigned int type,unsigned int code,int value)687da4249c9SDmitry Torokhov static int atkbd_event(struct input_dev *dev,
688da4249c9SDmitry Torokhov unsigned int type, unsigned int code, int value)
6890d4c8597SDmitry Torokhov {
690b356872fSDmitry Torokhov struct atkbd *atkbd = input_get_drvdata(dev);
6910d4c8597SDmitry Torokhov
6920d4c8597SDmitry Torokhov if (!atkbd->write)
6930d4c8597SDmitry Torokhov return -1;
6940d4c8597SDmitry Torokhov
6950d4c8597SDmitry Torokhov switch (type) {
6960d4c8597SDmitry Torokhov
6970d4c8597SDmitry Torokhov case EV_LED:
698da4249c9SDmitry Torokhov atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
6990d4c8597SDmitry Torokhov return 0;
7000d4c8597SDmitry Torokhov
7010d4c8597SDmitry Torokhov case EV_REP:
702da4249c9SDmitry Torokhov if (!atkbd->softrepeat)
703da4249c9SDmitry Torokhov atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
7041da177e4SLinus Torvalds return 0;
7051da177e4SLinus Torvalds
706a9a1f9c3SDmitry Torokhov default:
7071da177e4SLinus Torvalds return -1;
7081da177e4SLinus Torvalds }
709a9a1f9c3SDmitry Torokhov }
7101da177e4SLinus Torvalds
7111da177e4SLinus Torvalds /*
7121da177e4SLinus Torvalds * atkbd_enable() signals that interrupt handler is allowed to
7131da177e4SLinus Torvalds * generate input events.
7141da177e4SLinus Torvalds */
7151da177e4SLinus Torvalds
atkbd_enable(struct atkbd * atkbd)7161da177e4SLinus Torvalds static inline void atkbd_enable(struct atkbd *atkbd)
7171da177e4SLinus Torvalds {
7181da177e4SLinus Torvalds serio_pause_rx(atkbd->ps2dev.serio);
719a9a1f9c3SDmitry Torokhov atkbd->enabled = true;
7201da177e4SLinus Torvalds serio_continue_rx(atkbd->ps2dev.serio);
7211da177e4SLinus Torvalds }
7221da177e4SLinus Torvalds
7231da177e4SLinus Torvalds /*
7241da177e4SLinus Torvalds * atkbd_disable() tells input handler that all incoming data except
7251da177e4SLinus Torvalds * for ACKs and command response should be dropped.
7261da177e4SLinus Torvalds */
7271da177e4SLinus Torvalds
atkbd_disable(struct atkbd * atkbd)7281da177e4SLinus Torvalds static inline void atkbd_disable(struct atkbd *atkbd)
7291da177e4SLinus Torvalds {
7301da177e4SLinus Torvalds serio_pause_rx(atkbd->ps2dev.serio);
731a9a1f9c3SDmitry Torokhov atkbd->enabled = false;
7321da177e4SLinus Torvalds serio_continue_rx(atkbd->ps2dev.serio);
7331da177e4SLinus Torvalds }
7341da177e4SLinus Torvalds
atkbd_activate(struct atkbd * atkbd)735be2d7e42SShawn Nematbakhsh static int atkbd_activate(struct atkbd *atkbd)
736be2d7e42SShawn Nematbakhsh {
737be2d7e42SShawn Nematbakhsh struct ps2dev *ps2dev = &atkbd->ps2dev;
738be2d7e42SShawn Nematbakhsh
739be2d7e42SShawn Nematbakhsh /*
740be2d7e42SShawn Nematbakhsh * Enable the keyboard to receive keystrokes.
741be2d7e42SShawn Nematbakhsh */
742be2d7e42SShawn Nematbakhsh
743be2d7e42SShawn Nematbakhsh if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
744be2d7e42SShawn Nematbakhsh dev_err(&ps2dev->serio->dev,
745be2d7e42SShawn Nematbakhsh "Failed to enable keyboard on %s\n",
746be2d7e42SShawn Nematbakhsh ps2dev->serio->phys);
747be2d7e42SShawn Nematbakhsh return -1;
748be2d7e42SShawn Nematbakhsh }
749be2d7e42SShawn Nematbakhsh
750be2d7e42SShawn Nematbakhsh return 0;
751be2d7e42SShawn Nematbakhsh }
752be2d7e42SShawn Nematbakhsh
753be2d7e42SShawn Nematbakhsh /*
754be2d7e42SShawn Nematbakhsh * atkbd_deactivate() resets and disables the keyboard from sending
755be2d7e42SShawn Nematbakhsh * keystrokes.
756be2d7e42SShawn Nematbakhsh */
757be2d7e42SShawn Nematbakhsh
atkbd_deactivate(struct atkbd * atkbd)758be2d7e42SShawn Nematbakhsh static void atkbd_deactivate(struct atkbd *atkbd)
759be2d7e42SShawn Nematbakhsh {
760be2d7e42SShawn Nematbakhsh struct ps2dev *ps2dev = &atkbd->ps2dev;
761be2d7e42SShawn Nematbakhsh
762be2d7e42SShawn Nematbakhsh if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS))
763be2d7e42SShawn Nematbakhsh dev_err(&ps2dev->serio->dev,
764be2d7e42SShawn Nematbakhsh "Failed to deactivate keyboard on %s\n",
765be2d7e42SShawn Nematbakhsh ps2dev->serio->phys);
766be2d7e42SShawn Nematbakhsh }
767be2d7e42SShawn Nematbakhsh
768274333f8SHans de Goede #ifdef CONFIG_X86
atkbd_is_portable_device(void)769274333f8SHans de Goede static bool atkbd_is_portable_device(void)
770274333f8SHans de Goede {
771274333f8SHans de Goede static const char * const chassis_types[] = {
772274333f8SHans de Goede "8", /* Portable */
773274333f8SHans de Goede "9", /* Laptop */
774274333f8SHans de Goede "10", /* Notebook */
775274333f8SHans de Goede "14", /* Sub-Notebook */
776274333f8SHans de Goede "31", /* Convertible */
777274333f8SHans de Goede "32", /* Detachable */
778274333f8SHans de Goede };
779274333f8SHans de Goede int i;
780274333f8SHans de Goede
781274333f8SHans de Goede for (i = 0; i < ARRAY_SIZE(chassis_types); i++)
782274333f8SHans de Goede if (dmi_match(DMI_CHASSIS_TYPE, chassis_types[i]))
783274333f8SHans de Goede return true;
784274333f8SHans de Goede
785274333f8SHans de Goede return false;
786274333f8SHans de Goede }
787274333f8SHans de Goede
788274333f8SHans de Goede /*
789274333f8SHans de Goede * On many modern laptops ATKBD_CMD_GETID may cause problems, on these laptops
790274333f8SHans de Goede * the controller is always in translated mode. In this mode mice/touchpads will
791274333f8SHans de Goede * not work. So in this case simply assume a keyboard is connected to avoid
792274333f8SHans de Goede * confusing some laptop keyboards.
793274333f8SHans de Goede *
794881720dcSHans de Goede * Skipping ATKBD_CMD_GETID ends up using a fake keyboard id. Using the standard
795881720dcSHans de Goede * 0xab83 id is ok in translated mode, only atkbd_select_set() checks atkbd->id
796881720dcSHans de Goede * and in translated mode that is a no-op.
797274333f8SHans de Goede */
atkbd_skip_getid(struct atkbd * atkbd)798274333f8SHans de Goede static bool atkbd_skip_getid(struct atkbd *atkbd)
799274333f8SHans de Goede {
800274333f8SHans de Goede return atkbd->translated && atkbd_is_portable_device();
801274333f8SHans de Goede }
802274333f8SHans de Goede #else
atkbd_skip_getid(struct atkbd * atkbd)803274333f8SHans de Goede static inline bool atkbd_skip_getid(struct atkbd *atkbd) { return false; }
804274333f8SHans de Goede #endif
805274333f8SHans de Goede
8061da177e4SLinus Torvalds /*
8071da177e4SLinus Torvalds * atkbd_probe() probes for an AT keyboard on a serio port.
8081da177e4SLinus Torvalds */
8091da177e4SLinus Torvalds
atkbd_probe(struct atkbd * atkbd)8101da177e4SLinus Torvalds static int atkbd_probe(struct atkbd *atkbd)
8111da177e4SLinus Torvalds {
8121da177e4SLinus Torvalds struct ps2dev *ps2dev = &atkbd->ps2dev;
8131da177e4SLinus Torvalds unsigned char param[2];
8141da177e4SLinus Torvalds
8151da177e4SLinus Torvalds /*
8161da177e4SLinus Torvalds * Some systems, where the bit-twiddling when testing the io-lines of the
8171da177e4SLinus Torvalds * controller may confuse the keyboard need a full reset of the keyboard. On
8181da177e4SLinus Torvalds * these systems the BIOS also usually doesn't do it for us.
8191da177e4SLinus Torvalds */
8201da177e4SLinus Torvalds
8211da177e4SLinus Torvalds if (atkbd_reset)
8221da177e4SLinus Torvalds if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
823a9a1f9c3SDmitry Torokhov dev_warn(&ps2dev->serio->dev,
824a9a1f9c3SDmitry Torokhov "keyboard reset failed on %s\n",
825a9a1f9c3SDmitry Torokhov ps2dev->serio->phys);
8261da177e4SLinus Torvalds
827ac589a37SHans de Goede if (atkbd_skip_getid(atkbd)) {
828ac589a37SHans de Goede atkbd->id = 0xab83;
829ac589a37SHans de Goede return 0;
830ac589a37SHans de Goede }
831ac589a37SHans de Goede
8321da177e4SLinus Torvalds /*
8331da177e4SLinus Torvalds * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
8341da177e4SLinus Torvalds * Some keyboards report different values, but the first byte is always 0xab or
8351da177e4SLinus Torvalds * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this
8361da177e4SLinus Torvalds * should make sure we don't try to set the LEDs on it.
8371da177e4SLinus Torvalds */
8381da177e4SLinus Torvalds
8391da177e4SLinus Torvalds param[0] = param[1] = 0xa5; /* initialize with invalid values */
840ac589a37SHans de Goede if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
8411da177e4SLinus Torvalds
8421da177e4SLinus Torvalds /*
843ac589a37SHans de Goede * If the get ID command failed, we check if we can at least set
844274333f8SHans de Goede * the LEDs on the keyboard. This should work on every keyboard out there.
845274333f8SHans de Goede * It also turns the LEDs off, which we want anyway.
8461da177e4SLinus Torvalds */
8471da177e4SLinus Torvalds param[0] = 0;
8481da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
8491da177e4SLinus Torvalds return -1;
850ac589a37SHans de Goede atkbd->id = 0xabba;
8511da177e4SLinus Torvalds return 0;
8521da177e4SLinus Torvalds }
8531da177e4SLinus Torvalds
8549807879bSDmitry Torokhov if (!ps2_is_keyboard_id(param[0]))
8551da177e4SLinus Torvalds return -1;
8561da177e4SLinus Torvalds
8571da177e4SLinus Torvalds atkbd->id = (param[0] << 8) | param[1];
8581da177e4SLinus Torvalds
8591da177e4SLinus Torvalds if (atkbd->id == 0xaca1 && atkbd->translated) {
860a9a1f9c3SDmitry Torokhov dev_err(&ps2dev->serio->dev,
861236d6a77SDmitry Torokhov "NCD terminal keyboards are only supported on non-translating controllers. "
862a9a1f9c3SDmitry Torokhov "Use i8042.direct=1 to disable translation.\n");
8631da177e4SLinus Torvalds return -1;
8641da177e4SLinus Torvalds }
8651da177e4SLinus Torvalds
866be2d7e42SShawn Nematbakhsh /*
867be2d7e42SShawn Nematbakhsh * Make sure nothing is coming from the keyboard and disturbs our
868be2d7e42SShawn Nematbakhsh * internal state.
869be2d7e42SShawn Nematbakhsh */
8703d725caaSSheng-Liang Song if (!atkbd_skip_deactivate)
871be2d7e42SShawn Nematbakhsh atkbd_deactivate(atkbd);
872be2d7e42SShawn Nematbakhsh
8731da177e4SLinus Torvalds return 0;
8741da177e4SLinus Torvalds }
8751da177e4SLinus Torvalds
8761da177e4SLinus Torvalds /*
8771da177e4SLinus Torvalds * atkbd_select_set checks if a keyboard has a working Set 3 support, and
8781da177e4SLinus Torvalds * sets it into that. Unfortunately there are keyboards that can be switched
8791da177e4SLinus Torvalds * to Set 3, but don't work well in that (BTC Multimedia ...)
8801da177e4SLinus Torvalds */
8811da177e4SLinus Torvalds
atkbd_select_set(struct atkbd * atkbd,int target_set,int allow_extra)8821da177e4SLinus Torvalds static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
8831da177e4SLinus Torvalds {
8841da177e4SLinus Torvalds struct ps2dev *ps2dev = &atkbd->ps2dev;
8851da177e4SLinus Torvalds unsigned char param[2];
8861da177e4SLinus Torvalds
887a9a1f9c3SDmitry Torokhov atkbd->extra = false;
8881da177e4SLinus Torvalds /*
8891da177e4SLinus Torvalds * For known special keyboards we can go ahead and set the correct set.
8901da177e4SLinus Torvalds * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
8911da177e4SLinus Torvalds * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards.
8921da177e4SLinus Torvalds */
8931da177e4SLinus Torvalds
8941da177e4SLinus Torvalds if (atkbd->translated)
8951da177e4SLinus Torvalds return 2;
8961da177e4SLinus Torvalds
8971da177e4SLinus Torvalds if (atkbd->id == 0xaca1) {
8981da177e4SLinus Torvalds param[0] = 3;
8991da177e4SLinus Torvalds ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
9001da177e4SLinus Torvalds return 3;
9011da177e4SLinus Torvalds }
9021da177e4SLinus Torvalds
9031da177e4SLinus Torvalds if (allow_extra) {
9041da177e4SLinus Torvalds param[0] = 0x71;
9051da177e4SLinus Torvalds if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
906a9a1f9c3SDmitry Torokhov atkbd->extra = true;
9071da177e4SLinus Torvalds return 2;
9081da177e4SLinus Torvalds }
9091da177e4SLinus Torvalds }
9101da177e4SLinus Torvalds
9118c5188b6SBenjamin LaHaise if (atkbd_terminal) {
9128c5188b6SBenjamin LaHaise ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB);
9138c5188b6SBenjamin LaHaise return 3;
9148c5188b6SBenjamin LaHaise }
9158c5188b6SBenjamin LaHaise
9161da177e4SLinus Torvalds if (target_set != 3)
9171da177e4SLinus Torvalds return 2;
9181da177e4SLinus Torvalds
9191da177e4SLinus Torvalds if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {
9201da177e4SLinus Torvalds atkbd->id = param[0] << 8 | param[1];
9211da177e4SLinus Torvalds return 2;
9221da177e4SLinus Torvalds }
9231da177e4SLinus Torvalds
9241da177e4SLinus Torvalds param[0] = 3;
9251da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
9261da177e4SLinus Torvalds return 2;
9271da177e4SLinus Torvalds
9281da177e4SLinus Torvalds param[0] = 0;
9291da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
9301da177e4SLinus Torvalds return 2;
9311da177e4SLinus Torvalds
9321da177e4SLinus Torvalds if (param[0] != 3) {
9331da177e4SLinus Torvalds param[0] = 2;
9341da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
9351da177e4SLinus Torvalds return 2;
9361da177e4SLinus Torvalds }
9371da177e4SLinus Torvalds
9381da177e4SLinus Torvalds ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
9391da177e4SLinus Torvalds
9401da177e4SLinus Torvalds return 3;
9411da177e4SLinus Torvalds }
9421da177e4SLinus Torvalds
atkbd_reset_state(struct atkbd * atkbd)943fc0eb28cSDmitry Torokhov static int atkbd_reset_state(struct atkbd *atkbd)
944fc0eb28cSDmitry Torokhov {
945fc0eb28cSDmitry Torokhov struct ps2dev *ps2dev = &atkbd->ps2dev;
946fc0eb28cSDmitry Torokhov unsigned char param[1];
947fc0eb28cSDmitry Torokhov
948fc0eb28cSDmitry Torokhov /*
949fc0eb28cSDmitry Torokhov * Set the LEDs to a predefined state (all off).
950fc0eb28cSDmitry Torokhov */
951fc0eb28cSDmitry Torokhov
952fc0eb28cSDmitry Torokhov param[0] = 0;
953fc0eb28cSDmitry Torokhov if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
954fc0eb28cSDmitry Torokhov return -1;
955fc0eb28cSDmitry Torokhov
956fc0eb28cSDmitry Torokhov /*
957fc0eb28cSDmitry Torokhov * Set autorepeat to fastest possible.
958fc0eb28cSDmitry Torokhov */
959fc0eb28cSDmitry Torokhov
960fc0eb28cSDmitry Torokhov param[0] = 0;
961fc0eb28cSDmitry Torokhov if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
962fc0eb28cSDmitry Torokhov return -1;
963fc0eb28cSDmitry Torokhov
964fc0eb28cSDmitry Torokhov return 0;
965fc0eb28cSDmitry Torokhov }
966fc0eb28cSDmitry Torokhov
9671da177e4SLinus Torvalds /*
9681da177e4SLinus Torvalds * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
9691da177e4SLinus Torvalds * reboot.
9701da177e4SLinus Torvalds */
9711da177e4SLinus Torvalds
atkbd_cleanup(struct serio * serio)9721da177e4SLinus Torvalds static void atkbd_cleanup(struct serio *serio)
9731da177e4SLinus Torvalds {
974100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
97557f5b159SDmitry Torokhov
97657f5b159SDmitry Torokhov atkbd_disable(atkbd);
9774a299bf5SDmitry Torokhov ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF);
9781da177e4SLinus Torvalds }
9791da177e4SLinus Torvalds
9801da177e4SLinus Torvalds
9811da177e4SLinus Torvalds /*
9821da177e4SLinus Torvalds * atkbd_disconnect() closes and frees.
9831da177e4SLinus Torvalds */
9841da177e4SLinus Torvalds
atkbd_disconnect(struct serio * serio)9851da177e4SLinus Torvalds static void atkbd_disconnect(struct serio *serio)
9861da177e4SLinus Torvalds {
987100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
9881da177e4SLinus Torvalds
9891da177e4SLinus Torvalds atkbd_disable(atkbd);
9901da177e4SLinus Torvalds
9910ef7a26aSDmitry Torokhov input_unregister_device(atkbd->dev);
9920ef7a26aSDmitry Torokhov
9930ef7a26aSDmitry Torokhov /*
9940ef7a26aSDmitry Torokhov * Make sure we don't have a command in flight.
9950ef7a26aSDmitry Torokhov * Note that since atkbd->enabled is false event work will keep
9960ef7a26aSDmitry Torokhov * rescheduling itself until it gets canceled and will not try
9970ef7a26aSDmitry Torokhov * accessing freed input device or serio port.
9980ef7a26aSDmitry Torokhov */
999d6d79a78SJiri Pirko cancel_delayed_work_sync(&atkbd->event_work);
10001da177e4SLinus Torvalds
10011da177e4SLinus Torvalds serio_close(serio);
10021da177e4SLinus Torvalds serio_set_drvdata(serio, NULL);
10031da177e4SLinus Torvalds kfree(atkbd);
10041da177e4SLinus Torvalds }
10051da177e4SLinus Torvalds
1006554101e3SGiel de Nijs /*
100739191698SDaniel Mierswa * generate release events for the keycodes given in data
100839191698SDaniel Mierswa */
atkbd_apply_forced_release_keylist(struct atkbd * atkbd,const void * data)100939191698SDaniel Mierswa static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd,
101039191698SDaniel Mierswa const void *data)
101139191698SDaniel Mierswa {
101239191698SDaniel Mierswa const unsigned int *keys = data;
101339191698SDaniel Mierswa unsigned int i;
101439191698SDaniel Mierswa
101539191698SDaniel Mierswa if (atkbd->set == 2)
101639191698SDaniel Mierswa for (i = 0; keys[i] != -1U; i++)
101739191698SDaniel Mierswa __set_bit(keys[i], atkbd->force_release_mask);
101839191698SDaniel Mierswa }
101939191698SDaniel Mierswa
102039191698SDaniel Mierswa /*
102161579ba8SMatthew Garrett * Most special keys (Fn+F?) on Dell laptops do not generate release
1022554101e3SGiel de Nijs * events so we have to do it ourselves.
1023554101e3SGiel de Nijs */
102439191698SDaniel Mierswa static unsigned int atkbd_dell_laptop_forced_release_keys[] = {
102539191698SDaniel Mierswa 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U
1026554101e3SGiel de Nijs };
10271da177e4SLinus Torvalds
10281da177e4SLinus Torvalds /*
10295a54c011SJiri Kosina * Perform fixup for HP system that doesn't generate release
10305a54c011SJiri Kosina * for its video switch
10315a54c011SJiri Kosina */
103239191698SDaniel Mierswa static unsigned int atkbd_hp_forced_release_keys[] = {
103339191698SDaniel Mierswa 0x94, -1U
10345a54c011SJiri Kosina };
10355a54c011SJiri Kosina
10365a54c011SJiri Kosina /*
1037e04126c7SBarry Carroll * Samsung NC10,NC20 with Fn+F? key release not working
10384200844bSStuart Hopkins */
103939191698SDaniel Mierswa static unsigned int atkbd_samsung_forced_release_keys[] = {
104039191698SDaniel Mierswa 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U
10414200844bSStuart Hopkins };
10424200844bSStuart Hopkins
10434200844bSStuart Hopkins /*
1044f0a14de2SSimon Davie * Amilo Pi 3525 key release for Fn+Volume keys not working
1045f0a14de2SSimon Davie */
1046f0a14de2SSimon Davie static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = {
1047f0a14de2SSimon Davie 0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U
1048f0a14de2SSimon Davie };
1049f0a14de2SSimon Davie
1050f0a14de2SSimon Davie /*
10519166d0f6SAdrian Batzill * Amilo Xi 3650 key release for light touch bar not working
10529166d0f6SAdrian Batzill */
10539166d0f6SAdrian Batzill static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = {
10549166d0f6SAdrian Batzill 0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U
10559166d0f6SAdrian Batzill };
10569166d0f6SAdrian Batzill
10579166d0f6SAdrian Batzill /*
1058032e46cbSJerone Young * Soltech TA12 system with broken key release on volume keys and mute key
1059032e46cbSJerone Young */
1060032e46cbSJerone Young static unsigned int atkdb_soltech_ta12_forced_release_keys[] = {
1061032e46cbSJerone Young 0xa0, 0xae, 0xb0, -1U
1062032e46cbSJerone Young };
1063032e46cbSJerone Young
1064032e46cbSJerone Young /*
1065000c2a35SHerton Ronaldo Krzesinski * Many notebooks don't send key release event for volume up/down
1066000c2a35SHerton Ronaldo Krzesinski * keys, with key list below common among them
1067000c2a35SHerton Ronaldo Krzesinski */
1068000c2a35SHerton Ronaldo Krzesinski static unsigned int atkbd_volume_forced_release_keys[] = {
1069000c2a35SHerton Ronaldo Krzesinski 0xae, 0xb0, -1U
1070000c2a35SHerton Ronaldo Krzesinski };
1071000c2a35SHerton Ronaldo Krzesinski
1072000c2a35SHerton Ronaldo Krzesinski /*
1073e5713069SJamie Lentin * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas
1074e5713069SJamie Lentin * they should be generating e4-e6 (0x80 | code).
1075e5713069SJamie Lentin */
atkbd_oqo_01plus_scancode_fixup(struct atkbd * atkbd,unsigned int code)1076e5713069SJamie Lentin static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
1077e5713069SJamie Lentin unsigned int code)
1078e5713069SJamie Lentin {
1079e5713069SJamie Lentin if (atkbd->translated && atkbd->emul == 1 &&
1080e5713069SJamie Lentin (code == 0x64 || code == 0x65 || code == 0x66)) {
1081e5713069SJamie Lentin atkbd->emul = 0;
1082e5713069SJamie Lentin code |= 0x80;
1083e5713069SJamie Lentin }
1084e5713069SJamie Lentin
1085e5713069SJamie Lentin return code;
1086e5713069SJamie Lentin }
1087e5713069SJamie Lentin
atkbd_get_keymap_from_fwnode(struct atkbd * atkbd)10889d17ad23SRajat Jain static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
10899d17ad23SRajat Jain {
10909d17ad23SRajat Jain struct device *dev = &atkbd->ps2dev.serio->dev;
10919d17ad23SRajat Jain int i, n;
10929d17ad23SRajat Jain u32 *ptr;
10939d17ad23SRajat Jain u16 scancode, keycode;
10949d17ad23SRajat Jain
10959d17ad23SRajat Jain /* Parse "linux,keymap" property */
10969d17ad23SRajat Jain n = device_property_count_u32(dev, "linux,keymap");
10979d17ad23SRajat Jain if (n <= 0 || n > ATKBD_KEYMAP_SIZE)
10989d17ad23SRajat Jain return -ENXIO;
10999d17ad23SRajat Jain
11009d17ad23SRajat Jain ptr = kcalloc(n, sizeof(u32), GFP_KERNEL);
11019d17ad23SRajat Jain if (!ptr)
11029d17ad23SRajat Jain return -ENOMEM;
11039d17ad23SRajat Jain
11049d17ad23SRajat Jain if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) {
11059d17ad23SRajat Jain dev_err(dev, "problem parsing FW keymap property\n");
11069d17ad23SRajat Jain kfree(ptr);
11079d17ad23SRajat Jain return -EINVAL;
11089d17ad23SRajat Jain }
11099d17ad23SRajat Jain
11109d17ad23SRajat Jain memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
11119d17ad23SRajat Jain for (i = 0; i < n; i++) {
11129d17ad23SRajat Jain scancode = SCANCODE(ptr[i]);
11139d17ad23SRajat Jain keycode = KEYCODE(ptr[i]);
11149d17ad23SRajat Jain atkbd->keycode[scancode] = keycode;
11159d17ad23SRajat Jain }
11169d17ad23SRajat Jain
11179d17ad23SRajat Jain kfree(ptr);
11189d17ad23SRajat Jain return 0;
11199d17ad23SRajat Jain }
11209d17ad23SRajat Jain
1121e5713069SJamie Lentin /*
11223c42f0c3SDmitry Torokhov * atkbd_set_keycode_table() initializes keyboard's keycode table
11231da177e4SLinus Torvalds * according to the selected scancode set
11241da177e4SLinus Torvalds */
11251da177e4SLinus Torvalds
atkbd_set_keycode_table(struct atkbd * atkbd)11261da177e4SLinus Torvalds static void atkbd_set_keycode_table(struct atkbd *atkbd)
11271da177e4SLinus Torvalds {
11289d17ad23SRajat Jain struct device *dev = &atkbd->ps2dev.serio->dev;
1129554101e3SGiel de Nijs unsigned int scancode;
11301da177e4SLinus Torvalds int i, j;
11311da177e4SLinus Torvalds
11321da177e4SLinus Torvalds memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
11331ba36e11SDmitry Torokhov bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
11341da177e4SLinus Torvalds
11359d17ad23SRajat Jain if (!atkbd_get_keymap_from_fwnode(atkbd)) {
11369d17ad23SRajat Jain dev_dbg(dev, "Using FW keymap\n");
11379d17ad23SRajat Jain } else if (atkbd->translated) {
11381da177e4SLinus Torvalds for (i = 0; i < 128; i++) {
1139554101e3SGiel de Nijs scancode = atkbd_unxlate_table[i];
1140554101e3SGiel de Nijs atkbd->keycode[i] = atkbd_set2_keycode[scancode];
1141554101e3SGiel de Nijs atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80];
11421da177e4SLinus Torvalds if (atkbd->scroll)
11431da177e4SLinus Torvalds for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
1144554101e3SGiel de Nijs if ((scancode | 0x80) == atkbd_scroll_keys[j].set2)
11451da177e4SLinus Torvalds atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
11461da177e4SLinus Torvalds }
11471da177e4SLinus Torvalds } else if (atkbd->set == 3) {
11481da177e4SLinus Torvalds memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
11491da177e4SLinus Torvalds } else {
11501da177e4SLinus Torvalds memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
11511da177e4SLinus Torvalds
11521da177e4SLinus Torvalds if (atkbd->scroll)
1153554101e3SGiel de Nijs for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) {
1154554101e3SGiel de Nijs scancode = atkbd_scroll_keys[i].set2;
1155554101e3SGiel de Nijs atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode;
1156554101e3SGiel de Nijs }
11571da177e4SLinus Torvalds }
11580ae051a1SDmitry Torokhov
1159554101e3SGiel de Nijs /*
1160554101e3SGiel de Nijs * HANGEUL and HANJA keys do not send release events so we need to
1161554101e3SGiel de Nijs * generate such events ourselves
1162554101e3SGiel de Nijs */
1163554101e3SGiel de Nijs scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL);
1164554101e3SGiel de Nijs atkbd->keycode[scancode] = KEY_HANGEUL;
1165554101e3SGiel de Nijs __set_bit(scancode, atkbd->force_release_mask);
1166554101e3SGiel de Nijs
1167554101e3SGiel de Nijs scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA);
1168554101e3SGiel de Nijs atkbd->keycode[scancode] = KEY_HANJA;
1169554101e3SGiel de Nijs __set_bit(scancode, atkbd->force_release_mask);
1170554101e3SGiel de Nijs
1171554101e3SGiel de Nijs /*
1172554101e3SGiel de Nijs * Perform additional fixups
1173554101e3SGiel de Nijs */
1174554101e3SGiel de Nijs if (atkbd_platform_fixup)
117539191698SDaniel Mierswa atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data);
11761da177e4SLinus Torvalds }
11771da177e4SLinus Torvalds
11781da177e4SLinus Torvalds /*
11791da177e4SLinus Torvalds * atkbd_set_device_attrs() sets up keyboard's input device structure
11801da177e4SLinus Torvalds */
11811da177e4SLinus Torvalds
atkbd_set_device_attrs(struct atkbd * atkbd)11821da177e4SLinus Torvalds static void atkbd_set_device_attrs(struct atkbd *atkbd)
11831da177e4SLinus Torvalds {
11843c42f0c3SDmitry Torokhov struct input_dev *input_dev = atkbd->dev;
11851da177e4SLinus Torvalds int i;
11861da177e4SLinus Torvalds
11873c42f0c3SDmitry Torokhov if (atkbd->extra)
1188ea08c6faSDmitry Torokhov snprintf(atkbd->name, sizeof(atkbd->name),
1189ea08c6faSDmitry Torokhov "AT Set 2 Extra keyboard");
11903c42f0c3SDmitry Torokhov else
1191ea08c6faSDmitry Torokhov snprintf(atkbd->name, sizeof(atkbd->name),
1192ea08c6faSDmitry Torokhov "AT %s Set %d keyboard",
11933c42f0c3SDmitry Torokhov atkbd->translated ? "Translated" : "Raw", atkbd->set);
11941da177e4SLinus Torvalds
1195ea08c6faSDmitry Torokhov snprintf(atkbd->phys, sizeof(atkbd->phys),
1196ea08c6faSDmitry Torokhov "%s/input0", atkbd->ps2dev.serio->phys);
11971da177e4SLinus Torvalds
11983c42f0c3SDmitry Torokhov input_dev->name = atkbd->name;
11993c42f0c3SDmitry Torokhov input_dev->phys = atkbd->phys;
12003c42f0c3SDmitry Torokhov input_dev->id.bustype = BUS_I8042;
12013c42f0c3SDmitry Torokhov input_dev->id.vendor = 0x0001;
12023c42f0c3SDmitry Torokhov input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
12033c42f0c3SDmitry Torokhov input_dev->id.version = atkbd->id;
12043c42f0c3SDmitry Torokhov input_dev->event = atkbd_event;
1205469ba4dfSDmitry Torokhov input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
12061da177e4SLinus Torvalds
1207b356872fSDmitry Torokhov input_set_drvdata(input_dev, atkbd);
1208b356872fSDmitry Torokhov
12097b19ada2SJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
12107b19ada2SJiri Slaby BIT_MASK(EV_MSC);
12111da177e4SLinus Torvalds
12121da177e4SLinus Torvalds if (atkbd->write) {
12137b19ada2SJiri Slaby input_dev->evbit[0] |= BIT_MASK(EV_LED);
12147b19ada2SJiri Slaby input_dev->ledbit[0] = BIT_MASK(LED_NUML) |
12157b19ada2SJiri Slaby BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL);
12161da177e4SLinus Torvalds }
12171da177e4SLinus Torvalds
12181da177e4SLinus Torvalds if (atkbd->extra)
12197b19ada2SJiri Slaby input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) |
12207b19ada2SJiri Slaby BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) |
12217b19ada2SJiri Slaby BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC);
12221da177e4SLinus Torvalds
12231da177e4SLinus Torvalds if (!atkbd->softrepeat) {
12243c42f0c3SDmitry Torokhov input_dev->rep[REP_DELAY] = 250;
12253c42f0c3SDmitry Torokhov input_dev->rep[REP_PERIOD] = 33;
12261da177e4SLinus Torvalds }
12271da177e4SLinus Torvalds
12287b19ada2SJiri Slaby input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) :
12297b19ada2SJiri Slaby BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);
12301da177e4SLinus Torvalds
12311da177e4SLinus Torvalds if (atkbd->scroll) {
12327b19ada2SJiri Slaby input_dev->evbit[0] |= BIT_MASK(EV_REL);
12337b19ada2SJiri Slaby input_dev->relbit[0] = BIT_MASK(REL_WHEEL) |
12347b19ada2SJiri Slaby BIT_MASK(REL_HWHEEL);
1235f6d65610SDmitry Torokhov __set_bit(BTN_MIDDLE, input_dev->keybit);
12361da177e4SLinus Torvalds }
12371da177e4SLinus Torvalds
12383c42f0c3SDmitry Torokhov input_dev->keycode = atkbd->keycode;
1239f6d65610SDmitry Torokhov input_dev->keycodesize = sizeof(unsigned short);
12403c42f0c3SDmitry Torokhov input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
12411da177e4SLinus Torvalds
12424b70858bSDmitry Torokhov for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
12434b70858bSDmitry Torokhov if (atkbd->keycode[i] != KEY_RESERVED &&
12444b70858bSDmitry Torokhov atkbd->keycode[i] != ATKBD_KEY_NULL &&
12454b70858bSDmitry Torokhov atkbd->keycode[i] < ATKBD_SPECIAL) {
1246f6d65610SDmitry Torokhov __set_bit(atkbd->keycode[i], input_dev->keybit);
12471da177e4SLinus Torvalds }
12484b70858bSDmitry Torokhov }
12494b70858bSDmitry Torokhov }
12501da177e4SLinus Torvalds
atkbd_parse_fwnode_data(struct serio * serio)12518f7b057aSRajat Jain static void atkbd_parse_fwnode_data(struct serio *serio)
12528f7b057aSRajat Jain {
1253100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
12548f7b057aSRajat Jain struct device *dev = &serio->dev;
12558f7b057aSRajat Jain int n;
12568f7b057aSRajat Jain
12578f7b057aSRajat Jain /* Parse "function-row-physmap" property */
12588f7b057aSRajat Jain n = device_property_count_u32(dev, "function-row-physmap");
125945ceaf14SStephen Boyd if (n > 0 && n <= VIVALDI_MAX_FUNCTION_ROW_KEYS &&
12608f7b057aSRajat Jain !device_property_read_u32_array(dev, "function-row-physmap",
126145ceaf14SStephen Boyd atkbd->vdata.function_row_physmap,
126245ceaf14SStephen Boyd n)) {
126345ceaf14SStephen Boyd atkbd->vdata.num_function_row_keys = n;
12648f7b057aSRajat Jain dev_dbg(dev, "FW reported %d function-row key locations\n", n);
12658f7b057aSRajat Jain }
12668f7b057aSRajat Jain }
12678f7b057aSRajat Jain
12681da177e4SLinus Torvalds /*
12691da177e4SLinus Torvalds * atkbd_connect() is called when the serio module finds an interface
12701da177e4SLinus Torvalds * that isn't handled yet by an appropriate device driver. We check if
12711da177e4SLinus Torvalds * there is an AT keyboard out there and if yes, we register ourselves
12721da177e4SLinus Torvalds * to the input module.
12731da177e4SLinus Torvalds */
12741da177e4SLinus Torvalds
atkbd_connect(struct serio * serio,struct serio_driver * drv)12751da177e4SLinus Torvalds static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
12761da177e4SLinus Torvalds {
12771da177e4SLinus Torvalds struct atkbd *atkbd;
12783c42f0c3SDmitry Torokhov struct input_dev *dev;
12793c42f0c3SDmitry Torokhov int err = -ENOMEM;
12801da177e4SLinus Torvalds
12813c42f0c3SDmitry Torokhov atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL);
12823c42f0c3SDmitry Torokhov dev = input_allocate_device();
12833c42f0c3SDmitry Torokhov if (!atkbd || !dev)
12842b03b60eSDmitry Torokhov goto fail1;
12851da177e4SLinus Torvalds
12863c42f0c3SDmitry Torokhov atkbd->dev = dev;
1287c4c7eac8SDmitry Torokhov ps2_init(&atkbd->ps2dev, serio,
1288c4c7eac8SDmitry Torokhov atkbd_pre_receive_byte, atkbd_receive_byte);
1289da4249c9SDmitry Torokhov INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
129059b01513SEric W. Biederman mutex_init(&atkbd->mutex);
12911da177e4SLinus Torvalds
12921da177e4SLinus Torvalds switch (serio->id.type) {
12931da177e4SLinus Torvalds
12941da177e4SLinus Torvalds case SERIO_8042_XL:
1295a9a1f9c3SDmitry Torokhov atkbd->translated = true;
12966f49c4f5SGustavo A. R. Silva fallthrough;
1297a9a1f9c3SDmitry Torokhov
12981da177e4SLinus Torvalds case SERIO_8042:
12991da177e4SLinus Torvalds if (serio->write)
1300a9a1f9c3SDmitry Torokhov atkbd->write = true;
13011da177e4SLinus Torvalds break;
13021da177e4SLinus Torvalds }
13031da177e4SLinus Torvalds
13041da177e4SLinus Torvalds atkbd->softraw = atkbd_softraw;
13051da177e4SLinus Torvalds atkbd->softrepeat = atkbd_softrepeat;
13061da177e4SLinus Torvalds atkbd->scroll = atkbd_scroll;
13071da177e4SLinus Torvalds
13081da177e4SLinus Torvalds if (atkbd->softrepeat)
1309a9a1f9c3SDmitry Torokhov atkbd->softraw = true;
13101da177e4SLinus Torvalds
13111da177e4SLinus Torvalds serio_set_drvdata(serio, atkbd);
13121da177e4SLinus Torvalds
13131da177e4SLinus Torvalds err = serio_open(serio, drv);
13143c42f0c3SDmitry Torokhov if (err)
13152b03b60eSDmitry Torokhov goto fail2;
13161da177e4SLinus Torvalds
13171da177e4SLinus Torvalds if (atkbd->write) {
13181da177e4SLinus Torvalds
13191da177e4SLinus Torvalds if (atkbd_probe(atkbd)) {
13203c42f0c3SDmitry Torokhov err = -ENODEV;
13212b03b60eSDmitry Torokhov goto fail3;
13221da177e4SLinus Torvalds }
13231da177e4SLinus Torvalds
13241da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
1325fc0eb28cSDmitry Torokhov atkbd_reset_state(atkbd);
13261da177e4SLinus Torvalds
13271da177e4SLinus Torvalds } else {
13281da177e4SLinus Torvalds atkbd->set = 2;
13291da177e4SLinus Torvalds atkbd->id = 0xab00;
13301da177e4SLinus Torvalds }
13311da177e4SLinus Torvalds
13328f7b057aSRajat Jain atkbd_parse_fwnode_data(serio);
13338f7b057aSRajat Jain
13341da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd);
13351da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
13361da177e4SLinus Torvalds
13371da177e4SLinus Torvalds atkbd_enable(atkbd);
1338be2d7e42SShawn Nematbakhsh if (serio->write)
1339be2d7e42SShawn Nematbakhsh atkbd_activate(atkbd);
13401da177e4SLinus Torvalds
13412b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
13422b03b60eSDmitry Torokhov if (err)
1343c99e3ac6SDmitry Torokhov goto fail3;
13441da177e4SLinus Torvalds
13451da177e4SLinus Torvalds return 0;
13463c42f0c3SDmitry Torokhov
13472b03b60eSDmitry Torokhov fail3: serio_close(serio);
13482b03b60eSDmitry Torokhov fail2: serio_set_drvdata(serio, NULL);
13492b03b60eSDmitry Torokhov fail1: input_free_device(dev);
13503c42f0c3SDmitry Torokhov kfree(atkbd);
13513c42f0c3SDmitry Torokhov return err;
13521da177e4SLinus Torvalds }
13531da177e4SLinus Torvalds
13541da177e4SLinus Torvalds /*
13551da177e4SLinus Torvalds * atkbd_reconnect() tries to restore keyboard into a sane state and is
13561da177e4SLinus Torvalds * most likely called on resume.
13571da177e4SLinus Torvalds */
13581da177e4SLinus Torvalds
atkbd_reconnect(struct serio * serio)13591da177e4SLinus Torvalds static int atkbd_reconnect(struct serio *serio)
13601da177e4SLinus Torvalds {
1361100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
13621da177e4SLinus Torvalds struct serio_driver *drv = serio->drv;
136359b01513SEric W. Biederman int retval = -1;
13641da177e4SLinus Torvalds
13651da177e4SLinus Torvalds if (!atkbd || !drv) {
1366a9a1f9c3SDmitry Torokhov dev_dbg(&serio->dev,
1367a9a1f9c3SDmitry Torokhov "reconnect request, but serio is disconnected, ignoring...\n");
13681da177e4SLinus Torvalds return -1;
13691da177e4SLinus Torvalds }
13701da177e4SLinus Torvalds
137159b01513SEric W. Biederman mutex_lock(&atkbd->mutex);
137259b01513SEric W. Biederman
13731da177e4SLinus Torvalds atkbd_disable(atkbd);
13741da177e4SLinus Torvalds
13751da177e4SLinus Torvalds if (atkbd->write) {
13761da177e4SLinus Torvalds if (atkbd_probe(atkbd))
137759b01513SEric W. Biederman goto out;
137859b01513SEric W. Biederman
13791da177e4SLinus Torvalds if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
138059b01513SEric W. Biederman goto out;
13811da177e4SLinus Torvalds
1382d4119bdaSDmitry Torokhov /*
1383d4119bdaSDmitry Torokhov * Restore LED state and repeat rate. While input core
1384d4119bdaSDmitry Torokhov * will do this for us at resume time reconnect may happen
1385d4119bdaSDmitry Torokhov * because user requested it via sysfs or simply because
1386d4119bdaSDmitry Torokhov * keyboard was unplugged and plugged in again so we need
1387d4119bdaSDmitry Torokhov * to do it ourselves here.
1388d4119bdaSDmitry Torokhov */
1389d4119bdaSDmitry Torokhov atkbd_set_leds(atkbd);
1390d4119bdaSDmitry Torokhov if (!atkbd->softrepeat)
1391d4119bdaSDmitry Torokhov atkbd_set_repeat_rate(atkbd);
1392d4119bdaSDmitry Torokhov
13931da177e4SLinus Torvalds }
13941da177e4SLinus Torvalds
1395be2d7e42SShawn Nematbakhsh /*
1396be2d7e42SShawn Nematbakhsh * Reset our state machine in case reconnect happened in the middle
1397be2d7e42SShawn Nematbakhsh * of multi-byte scancode.
1398be2d7e42SShawn Nematbakhsh */
1399be2d7e42SShawn Nematbakhsh atkbd->xl_bit = 0;
1400be2d7e42SShawn Nematbakhsh atkbd->emul = 0;
1401be2d7e42SShawn Nematbakhsh
14021da177e4SLinus Torvalds atkbd_enable(atkbd);
1403be2d7e42SShawn Nematbakhsh if (atkbd->write)
1404be2d7e42SShawn Nematbakhsh atkbd_activate(atkbd);
1405be2d7e42SShawn Nematbakhsh
140659b01513SEric W. Biederman retval = 0;
14071da177e4SLinus Torvalds
140859b01513SEric W. Biederman out:
140959b01513SEric W. Biederman mutex_unlock(&atkbd->mutex);
141059b01513SEric W. Biederman return retval;
14111da177e4SLinus Torvalds }
14121da177e4SLinus Torvalds
1413af2e7d77SArvind Yadav static const struct serio_device_id atkbd_serio_ids[] = {
14141da177e4SLinus Torvalds {
14151da177e4SLinus Torvalds .type = SERIO_8042,
14161da177e4SLinus Torvalds .proto = SERIO_ANY,
14171da177e4SLinus Torvalds .id = SERIO_ANY,
14181da177e4SLinus Torvalds .extra = SERIO_ANY,
14191da177e4SLinus Torvalds },
14201da177e4SLinus Torvalds {
14211da177e4SLinus Torvalds .type = SERIO_8042_XL,
14221da177e4SLinus Torvalds .proto = SERIO_ANY,
14231da177e4SLinus Torvalds .id = SERIO_ANY,
14241da177e4SLinus Torvalds .extra = SERIO_ANY,
14251da177e4SLinus Torvalds },
14261da177e4SLinus Torvalds {
14271da177e4SLinus Torvalds .type = SERIO_RS232,
14281da177e4SLinus Torvalds .proto = SERIO_PS2SER,
14291da177e4SLinus Torvalds .id = SERIO_ANY,
14301da177e4SLinus Torvalds .extra = SERIO_ANY,
14311da177e4SLinus Torvalds },
14321da177e4SLinus Torvalds { 0 }
14331da177e4SLinus Torvalds };
14341da177e4SLinus Torvalds
14351da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
14361da177e4SLinus Torvalds
14371da177e4SLinus Torvalds static struct serio_driver atkbd_drv = {
14381da177e4SLinus Torvalds .driver = {
14391da177e4SLinus Torvalds .name = "atkbd",
1440c99e3ac6SDmitry Torokhov .dev_groups = atkbd_attribute_groups,
14411da177e4SLinus Torvalds },
14421da177e4SLinus Torvalds .description = DRIVER_DESC,
14431da177e4SLinus Torvalds .id_table = atkbd_serio_ids,
1444c4c7eac8SDmitry Torokhov .interrupt = ps2_interrupt,
14451da177e4SLinus Torvalds .connect = atkbd_connect,
14461da177e4SLinus Torvalds .reconnect = atkbd_reconnect,
14471da177e4SLinus Torvalds .disconnect = atkbd_disconnect,
14481da177e4SLinus Torvalds .cleanup = atkbd_cleanup,
14491da177e4SLinus Torvalds };
14501da177e4SLinus Torvalds
atkbd_attr_show_helper(struct device * dev,char * buf,ssize_t (* handler)(struct atkbd *,char *))14511da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
14521da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, char *))
14531da177e4SLinus Torvalds {
14541da177e4SLinus Torvalds struct serio *serio = to_serio_port(dev);
1455100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
14561da177e4SLinus Torvalds
145759b01513SEric W. Biederman return handler(atkbd, buf);
14581da177e4SLinus Torvalds }
14591da177e4SLinus Torvalds
atkbd_attr_set_helper(struct device * dev,const char * buf,size_t count,ssize_t (* handler)(struct atkbd *,const char *,size_t))14601da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
14611da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, const char *, size_t))
14621da177e4SLinus Torvalds {
14631da177e4SLinus Torvalds struct serio *serio = to_serio_port(dev);
1464100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
14651da177e4SLinus Torvalds int retval;
14661da177e4SLinus Torvalds
146759b01513SEric W. Biederman retval = mutex_lock_interruptible(&atkbd->mutex);
14681da177e4SLinus Torvalds if (retval)
14691da177e4SLinus Torvalds return retval;
14701da177e4SLinus Torvalds
14711da177e4SLinus Torvalds atkbd_disable(atkbd);
14721da177e4SLinus Torvalds retval = handler(atkbd, buf, count);
14731da177e4SLinus Torvalds atkbd_enable(atkbd);
14741da177e4SLinus Torvalds
147559b01513SEric W. Biederman mutex_unlock(&atkbd->mutex);
147659b01513SEric W. Biederman
14771da177e4SLinus Torvalds return retval;
14781da177e4SLinus Torvalds }
14791da177e4SLinus Torvalds
atkbd_show_extra(struct atkbd * atkbd,char * buf)14801da177e4SLinus Torvalds static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
14811da177e4SLinus Torvalds {
14821da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0);
14831da177e4SLinus Torvalds }
14841da177e4SLinus Torvalds
atkbd_set_extra(struct atkbd * atkbd,const char * buf,size_t count)14851da177e4SLinus Torvalds static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
14861da177e4SLinus Torvalds {
14872b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
148876496e7aSJJ Ding unsigned int value;
14892b03b60eSDmitry Torokhov int err;
1490a9a1f9c3SDmitry Torokhov bool old_extra;
1491a9a1f9c3SDmitry Torokhov unsigned char old_set;
14921da177e4SLinus Torvalds
14931da177e4SLinus Torvalds if (!atkbd->write)
14941da177e4SLinus Torvalds return -EIO;
14951da177e4SLinus Torvalds
149676496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
149776496e7aSJJ Ding if (err)
149876496e7aSJJ Ding return err;
149976496e7aSJJ Ding
150076496e7aSJJ Ding if (value > 1)
15011da177e4SLinus Torvalds return -EINVAL;
15021da177e4SLinus Torvalds
15031da177e4SLinus Torvalds if (atkbd->extra != value) {
15043c42f0c3SDmitry Torokhov /*
15053c42f0c3SDmitry Torokhov * Since device's properties will change we need to
15062b03b60eSDmitry Torokhov * unregister old device. But allocate and register
15072b03b60eSDmitry Torokhov * new one first to make sure we have it.
15083c42f0c3SDmitry Torokhov */
15092b03b60eSDmitry Torokhov old_dev = atkbd->dev;
15102b03b60eSDmitry Torokhov old_extra = atkbd->extra;
15112b03b60eSDmitry Torokhov old_set = atkbd->set;
15122b03b60eSDmitry Torokhov
15132b03b60eSDmitry Torokhov new_dev = input_allocate_device();
15142b03b60eSDmitry Torokhov if (!new_dev)
15153c42f0c3SDmitry Torokhov return -ENOMEM;
15162b03b60eSDmitry Torokhov
15173c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
15181da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
1519fc0eb28cSDmitry Torokhov atkbd_reset_state(atkbd);
15201da177e4SLinus Torvalds atkbd_activate(atkbd);
15212b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd);
15221da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
15232b03b60eSDmitry Torokhov
15242b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
15252b03b60eSDmitry Torokhov if (err) {
15262b03b60eSDmitry Torokhov input_free_device(new_dev);
15272b03b60eSDmitry Torokhov
15282b03b60eSDmitry Torokhov atkbd->dev = old_dev;
15292b03b60eSDmitry Torokhov atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
15302b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd);
15312b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
15322b03b60eSDmitry Torokhov
15332b03b60eSDmitry Torokhov return err;
15342b03b60eSDmitry Torokhov }
15352b03b60eSDmitry Torokhov input_unregister_device(old_dev);
15362b03b60eSDmitry Torokhov
15371da177e4SLinus Torvalds }
15381da177e4SLinus Torvalds return count;
15391da177e4SLinus Torvalds }
15401da177e4SLinus Torvalds
atkbd_show_force_release(struct atkbd * atkbd,char * buf)15411ba36e11SDmitry Torokhov static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
15421ba36e11SDmitry Torokhov {
15430b480037STejun Heo size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
15440b480037STejun Heo ATKBD_KEYMAP_SIZE, atkbd->force_release_mask);
15451ba36e11SDmitry Torokhov
15461ba36e11SDmitry Torokhov buf[len++] = '\n';
15471ba36e11SDmitry Torokhov buf[len] = '\0';
15481ba36e11SDmitry Torokhov
15491ba36e11SDmitry Torokhov return len;
15501ba36e11SDmitry Torokhov }
15511ba36e11SDmitry Torokhov
atkbd_set_force_release(struct atkbd * atkbd,const char * buf,size_t count)15521ba36e11SDmitry Torokhov static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
15531ba36e11SDmitry Torokhov const char *buf, size_t count)
15541ba36e11SDmitry Torokhov {
15551ba36e11SDmitry Torokhov /* 64 bytes on stack should be acceptable */
15561ba36e11SDmitry Torokhov DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
15571ba36e11SDmitry Torokhov int err;
15581ba36e11SDmitry Torokhov
15591ba36e11SDmitry Torokhov err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
15601ba36e11SDmitry Torokhov if (err)
15611ba36e11SDmitry Torokhov return err;
15621ba36e11SDmitry Torokhov
15631ba36e11SDmitry Torokhov memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
15641ba36e11SDmitry Torokhov return count;
15651ba36e11SDmitry Torokhov }
15661ba36e11SDmitry Torokhov
15671ba36e11SDmitry Torokhov
atkbd_show_scroll(struct atkbd * atkbd,char * buf)15681da177e4SLinus Torvalds static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
15691da177e4SLinus Torvalds {
15701da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
15711da177e4SLinus Torvalds }
15721da177e4SLinus Torvalds
atkbd_set_scroll(struct atkbd * atkbd,const char * buf,size_t count)15731da177e4SLinus Torvalds static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
15741da177e4SLinus Torvalds {
15752b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
157676496e7aSJJ Ding unsigned int value;
15772b03b60eSDmitry Torokhov int err;
1578a9a1f9c3SDmitry Torokhov bool old_scroll;
15791da177e4SLinus Torvalds
158076496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
158176496e7aSJJ Ding if (err)
158276496e7aSJJ Ding return err;
158376496e7aSJJ Ding
158476496e7aSJJ Ding if (value > 1)
15851da177e4SLinus Torvalds return -EINVAL;
15861da177e4SLinus Torvalds
15871da177e4SLinus Torvalds if (atkbd->scroll != value) {
15882b03b60eSDmitry Torokhov old_dev = atkbd->dev;
15892b03b60eSDmitry Torokhov old_scroll = atkbd->scroll;
15902b03b60eSDmitry Torokhov
15912b03b60eSDmitry Torokhov new_dev = input_allocate_device();
15922b03b60eSDmitry Torokhov if (!new_dev)
15933c42f0c3SDmitry Torokhov return -ENOMEM;
15942b03b60eSDmitry Torokhov
15953c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
15961da177e4SLinus Torvalds atkbd->scroll = value;
15971da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd);
15981da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
15992b03b60eSDmitry Torokhov
16002b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
16012b03b60eSDmitry Torokhov if (err) {
16022b03b60eSDmitry Torokhov input_free_device(new_dev);
16032b03b60eSDmitry Torokhov
16042b03b60eSDmitry Torokhov atkbd->scroll = old_scroll;
16052b03b60eSDmitry Torokhov atkbd->dev = old_dev;
16062b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd);
16072b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
16082b03b60eSDmitry Torokhov
16092b03b60eSDmitry Torokhov return err;
16102b03b60eSDmitry Torokhov }
16112b03b60eSDmitry Torokhov input_unregister_device(old_dev);
16121da177e4SLinus Torvalds }
16131da177e4SLinus Torvalds return count;
16141da177e4SLinus Torvalds }
16151da177e4SLinus Torvalds
atkbd_show_set(struct atkbd * atkbd,char * buf)16161da177e4SLinus Torvalds static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
16171da177e4SLinus Torvalds {
16181da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->set);
16191da177e4SLinus Torvalds }
16201da177e4SLinus Torvalds
atkbd_set_set(struct atkbd * atkbd,const char * buf,size_t count)16211da177e4SLinus Torvalds static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
16221da177e4SLinus Torvalds {
16232b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
162476496e7aSJJ Ding unsigned int value;
16252b03b60eSDmitry Torokhov int err;
1626a9a1f9c3SDmitry Torokhov unsigned char old_set;
1627a9a1f9c3SDmitry Torokhov bool old_extra;
16281da177e4SLinus Torvalds
16291da177e4SLinus Torvalds if (!atkbd->write)
16301da177e4SLinus Torvalds return -EIO;
16311da177e4SLinus Torvalds
163276496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
163376496e7aSJJ Ding if (err)
163476496e7aSJJ Ding return err;
163576496e7aSJJ Ding
163676496e7aSJJ Ding if (value != 2 && value != 3)
16371da177e4SLinus Torvalds return -EINVAL;
16381da177e4SLinus Torvalds
16391da177e4SLinus Torvalds if (atkbd->set != value) {
16402b03b60eSDmitry Torokhov old_dev = atkbd->dev;
16412b03b60eSDmitry Torokhov old_extra = atkbd->extra;
16422b03b60eSDmitry Torokhov old_set = atkbd->set;
16432b03b60eSDmitry Torokhov
16442b03b60eSDmitry Torokhov new_dev = input_allocate_device();
16452b03b60eSDmitry Torokhov if (!new_dev)
16463c42f0c3SDmitry Torokhov return -ENOMEM;
16472b03b60eSDmitry Torokhov
16483c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
16491da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
1650d4119bdaSDmitry Torokhov atkbd_reset_state(atkbd);
16511da177e4SLinus Torvalds atkbd_activate(atkbd);
16521da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd);
16531da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
16542b03b60eSDmitry Torokhov
16552b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
16562b03b60eSDmitry Torokhov if (err) {
16572b03b60eSDmitry Torokhov input_free_device(new_dev);
16582b03b60eSDmitry Torokhov
16592b03b60eSDmitry Torokhov atkbd->dev = old_dev;
16602b03b60eSDmitry Torokhov atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
16612b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd);
16622b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
16632b03b60eSDmitry Torokhov
16642b03b60eSDmitry Torokhov return err;
16652b03b60eSDmitry Torokhov }
16662b03b60eSDmitry Torokhov input_unregister_device(old_dev);
16671da177e4SLinus Torvalds }
16681da177e4SLinus Torvalds return count;
16691da177e4SLinus Torvalds }
16701da177e4SLinus Torvalds
atkbd_show_softrepeat(struct atkbd * atkbd,char * buf)16711da177e4SLinus Torvalds static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
16721da177e4SLinus Torvalds {
16731da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0);
16741da177e4SLinus Torvalds }
16751da177e4SLinus Torvalds
atkbd_set_softrepeat(struct atkbd * atkbd,const char * buf,size_t count)16761da177e4SLinus Torvalds static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
16771da177e4SLinus Torvalds {
16782b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
167976496e7aSJJ Ding unsigned int value;
16802b03b60eSDmitry Torokhov int err;
1681a9a1f9c3SDmitry Torokhov bool old_softrepeat, old_softraw;
16821da177e4SLinus Torvalds
16831da177e4SLinus Torvalds if (!atkbd->write)
16841da177e4SLinus Torvalds return -EIO;
16851da177e4SLinus Torvalds
168676496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
168776496e7aSJJ Ding if (err)
168876496e7aSJJ Ding return err;
168976496e7aSJJ Ding
169076496e7aSJJ Ding if (value > 1)
16911da177e4SLinus Torvalds return -EINVAL;
16921da177e4SLinus Torvalds
16931da177e4SLinus Torvalds if (atkbd->softrepeat != value) {
16942b03b60eSDmitry Torokhov old_dev = atkbd->dev;
16952b03b60eSDmitry Torokhov old_softrepeat = atkbd->softrepeat;
16962b03b60eSDmitry Torokhov old_softraw = atkbd->softraw;
16972b03b60eSDmitry Torokhov
16982b03b60eSDmitry Torokhov new_dev = input_allocate_device();
16992b03b60eSDmitry Torokhov if (!new_dev)
17003c42f0c3SDmitry Torokhov return -ENOMEM;
17012b03b60eSDmitry Torokhov
17023c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
17031da177e4SLinus Torvalds atkbd->softrepeat = value;
17041da177e4SLinus Torvalds if (atkbd->softrepeat)
1705a9a1f9c3SDmitry Torokhov atkbd->softraw = true;
17061da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
17072b03b60eSDmitry Torokhov
17082b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
17092b03b60eSDmitry Torokhov if (err) {
17102b03b60eSDmitry Torokhov input_free_device(new_dev);
17112b03b60eSDmitry Torokhov
17122b03b60eSDmitry Torokhov atkbd->dev = old_dev;
17132b03b60eSDmitry Torokhov atkbd->softrepeat = old_softrepeat;
17142b03b60eSDmitry Torokhov atkbd->softraw = old_softraw;
17152b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
17162b03b60eSDmitry Torokhov
17172b03b60eSDmitry Torokhov return err;
17182b03b60eSDmitry Torokhov }
17192b03b60eSDmitry Torokhov input_unregister_device(old_dev);
17201da177e4SLinus Torvalds }
17211da177e4SLinus Torvalds return count;
17221da177e4SLinus Torvalds }
17231da177e4SLinus Torvalds
17241da177e4SLinus Torvalds
atkbd_show_softraw(struct atkbd * atkbd,char * buf)17251da177e4SLinus Torvalds static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
17261da177e4SLinus Torvalds {
17271da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0);
17281da177e4SLinus Torvalds }
17291da177e4SLinus Torvalds
atkbd_set_softraw(struct atkbd * atkbd,const char * buf,size_t count)17301da177e4SLinus Torvalds static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
17311da177e4SLinus Torvalds {
17322b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
173376496e7aSJJ Ding unsigned int value;
17342b03b60eSDmitry Torokhov int err;
1735a9a1f9c3SDmitry Torokhov bool old_softraw;
17361da177e4SLinus Torvalds
173776496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
173876496e7aSJJ Ding if (err)
173976496e7aSJJ Ding return err;
174076496e7aSJJ Ding
174176496e7aSJJ Ding if (value > 1)
17421da177e4SLinus Torvalds return -EINVAL;
17431da177e4SLinus Torvalds
17441da177e4SLinus Torvalds if (atkbd->softraw != value) {
17452b03b60eSDmitry Torokhov old_dev = atkbd->dev;
17462b03b60eSDmitry Torokhov old_softraw = atkbd->softraw;
17472b03b60eSDmitry Torokhov
17482b03b60eSDmitry Torokhov new_dev = input_allocate_device();
17492b03b60eSDmitry Torokhov if (!new_dev)
17503c42f0c3SDmitry Torokhov return -ENOMEM;
17512b03b60eSDmitry Torokhov
17523c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
17531da177e4SLinus Torvalds atkbd->softraw = value;
17541da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
17552b03b60eSDmitry Torokhov
17562b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
17572b03b60eSDmitry Torokhov if (err) {
17582b03b60eSDmitry Torokhov input_free_device(new_dev);
17592b03b60eSDmitry Torokhov
17602b03b60eSDmitry Torokhov atkbd->dev = old_dev;
17612b03b60eSDmitry Torokhov atkbd->softraw = old_softraw;
17622b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
17632b03b60eSDmitry Torokhov
17642b03b60eSDmitry Torokhov return err;
17652b03b60eSDmitry Torokhov }
17662b03b60eSDmitry Torokhov input_unregister_device(old_dev);
17671da177e4SLinus Torvalds }
17681da177e4SLinus Torvalds return count;
17691da177e4SLinus Torvalds }
17701da177e4SLinus Torvalds
atkbd_show_err_count(struct atkbd * atkbd,char * buf)177186255d9dSDmitry Torokhov static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
177286255d9dSDmitry Torokhov {
177386255d9dSDmitry Torokhov return sprintf(buf, "%lu\n", atkbd->err_count);
177486255d9dSDmitry Torokhov }
177586255d9dSDmitry Torokhov
atkbd_setup_forced_release(const struct dmi_system_id * id)177639191698SDaniel Mierswa static int __init atkbd_setup_forced_release(const struct dmi_system_id *id)
1777554101e3SGiel de Nijs {
177839191698SDaniel Mierswa atkbd_platform_fixup = atkbd_apply_forced_release_keylist;
177939191698SDaniel Mierswa atkbd_platform_fixup_data = id->driver_data;
178039191698SDaniel Mierswa
1781c388b2c6SAxel Lin return 1;
1782554101e3SGiel de Nijs }
1783554101e3SGiel de Nijs
atkbd_setup_scancode_fixup(const struct dmi_system_id * id)1784e5713069SJamie Lentin static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
1785e5713069SJamie Lentin {
1786e5713069SJamie Lentin atkbd_platform_scancode_fixup = id->driver_data;
1787e5713069SJamie Lentin
1788c388b2c6SAxel Lin return 1;
1789e5713069SJamie Lentin }
1790e5713069SJamie Lentin
atkbd_deactivate_fixup(const struct dmi_system_id * id)17913d725caaSSheng-Liang Song static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id)
17923d725caaSSheng-Liang Song {
17933d725caaSSheng-Liang Song atkbd_skip_deactivate = true;
17943d725caaSSheng-Liang Song return 1;
17953d725caaSSheng-Liang Song }
17963d725caaSSheng-Liang Song
17978b8a518eSDmitry Torokhov /*
17988b8a518eSDmitry Torokhov * NOTE: do not add any more "force release" quirks to this table. The
17998b8a518eSDmitry Torokhov * task of adjusting list of keys that should be "released" automatically
18008b8a518eSDmitry Torokhov * by the driver is now delegated to userspace tools, such as udev, so
18018b8a518eSDmitry Torokhov * submit such quirks there.
18028b8a518eSDmitry Torokhov */
1803c45fc81eSDmitry Torokhov static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
1804554101e3SGiel de Nijs {
1805554101e3SGiel de Nijs .matches = {
1806554101e3SGiel de Nijs DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
180761579ba8SMatthew Garrett DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
1808554101e3SGiel de Nijs },
180939191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
181039191698SDaniel Mierswa .driver_data = atkbd_dell_laptop_forced_release_keys,
1811554101e3SGiel de Nijs },
18125a54c011SJiri Kosina {
18132a3ec326SMatthew Garrett .matches = {
18142a3ec326SMatthew Garrett DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
18152a3ec326SMatthew Garrett DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
18162a3ec326SMatthew Garrett },
181739191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
181839191698SDaniel Mierswa .driver_data = atkbd_dell_laptop_forced_release_keys,
18192a3ec326SMatthew Garrett },
18202a3ec326SMatthew Garrett {
18215a54c011SJiri Kosina .matches = {
18225a54c011SJiri Kosina DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18235a54c011SJiri Kosina DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"),
18245a54c011SJiri Kosina },
182539191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
182639191698SDaniel Mierswa .driver_data = atkbd_hp_forced_release_keys,
18275a54c011SJiri Kosina },
1828a8215b81SMatthew Garrett {
1829181f6382SRikard Ljungstrand .matches = {
1830181f6382SRikard Ljungstrand DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1831181f6382SRikard Ljungstrand DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
1832181f6382SRikard Ljungstrand },
183339191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
1834000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
1835181f6382SRikard Ljungstrand },
1836181f6382SRikard Ljungstrand {
18372bcaa6a4SDave Andrews .matches = {
18382bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18392bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
18402bcaa6a4SDave Andrews },
18412bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release,
1842000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
18432bcaa6a4SDave Andrews },
18442bcaa6a4SDave Andrews {
18452bcaa6a4SDave Andrews .matches = {
18462bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18472bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
18482bcaa6a4SDave Andrews },
18492bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release,
1850000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
18512bcaa6a4SDave Andrews },
18522bcaa6a4SDave Andrews {
18532bcaa6a4SDave Andrews .matches = {
18542bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18552bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
18562bcaa6a4SDave Andrews },
18572bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release,
1858000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
18592bcaa6a4SDave Andrews },
18602bcaa6a4SDave Andrews {
1861c45fc81eSDmitry Torokhov /* Inventec Symphony */
1862a8215b81SMatthew Garrett .matches = {
1863a8215b81SMatthew Garrett DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"),
1864a8215b81SMatthew Garrett DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
1865a8215b81SMatthew Garrett },
186639191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
1867000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
1868a8215b81SMatthew Garrett },
18694200844bSStuart Hopkins {
1870c45fc81eSDmitry Torokhov /* Samsung NC10 */
18714200844bSStuart Hopkins .matches = {
18724200844bSStuart Hopkins DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
18734200844bSStuart Hopkins DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
18744200844bSStuart Hopkins },
187539191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
187639191698SDaniel Mierswa .driver_data = atkbd_samsung_forced_release_keys,
18774200844bSStuart Hopkins },
1878adcb523eSDaniel Mierswa {
1879c45fc81eSDmitry Torokhov /* Samsung NC20 */
1880e04126c7SBarry Carroll .matches = {
1881e04126c7SBarry Carroll DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1882e04126c7SBarry Carroll DMI_MATCH(DMI_PRODUCT_NAME, "NC20"),
1883e04126c7SBarry Carroll },
1884e04126c7SBarry Carroll .callback = atkbd_setup_forced_release,
1885e04126c7SBarry Carroll .driver_data = atkbd_samsung_forced_release_keys,
1886e04126c7SBarry Carroll },
1887e04126c7SBarry Carroll {
1888c45fc81eSDmitry Torokhov /* Samsung SQ45S70S */
1889157f3a3eSDmitry Torokhov .matches = {
1890157f3a3eSDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1891157f3a3eSDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
1892157f3a3eSDmitry Torokhov },
1893157f3a3eSDmitry Torokhov .callback = atkbd_setup_forced_release,
1894157f3a3eSDmitry Torokhov .driver_data = atkbd_samsung_forced_release_keys,
1895157f3a3eSDmitry Torokhov },
1896157f3a3eSDmitry Torokhov {
1897c45fc81eSDmitry Torokhov /* Fujitsu Amilo PA 1510 */
1898adcb523eSDaniel Mierswa .matches = {
1899adcb523eSDaniel Mierswa DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1900adcb523eSDaniel Mierswa DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
1901adcb523eSDaniel Mierswa },
1902adcb523eSDaniel Mierswa .callback = atkbd_setup_forced_release,
1903000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
1904adcb523eSDaniel Mierswa },
19059166d0f6SAdrian Batzill {
1906c45fc81eSDmitry Torokhov /* Fujitsu Amilo Pi 3525 */
1907f0a14de2SSimon Davie .matches = {
1908f0a14de2SSimon Davie DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1909f0a14de2SSimon Davie DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"),
1910f0a14de2SSimon Davie },
1911f0a14de2SSimon Davie .callback = atkbd_setup_forced_release,
1912f0a14de2SSimon Davie .driver_data = atkbd_amilo_pi3525_forced_release_keys,
1913f0a14de2SSimon Davie },
1914f0a14de2SSimon Davie {
1915c45fc81eSDmitry Torokhov /* Fujitsu Amilo Xi 3650 */
19169166d0f6SAdrian Batzill .matches = {
19179166d0f6SAdrian Batzill DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
19189166d0f6SAdrian Batzill DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"),
19199166d0f6SAdrian Batzill },
19209166d0f6SAdrian Batzill .callback = atkbd_setup_forced_release,
19219166d0f6SAdrian Batzill .driver_data = atkbd_amilo_xi3650_forced_release_keys,
19229166d0f6SAdrian Batzill },
1923032e46cbSJerone Young {
1924032e46cbSJerone Young .matches = {
1925032e46cbSJerone Young DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"),
1926032e46cbSJerone Young DMI_MATCH(DMI_PRODUCT_NAME, "TA12"),
1927032e46cbSJerone Young },
1928032e46cbSJerone Young .callback = atkbd_setup_forced_release,
1929032e46cbSJerone Young .driver_data = atkdb_soltech_ta12_forced_release_keys,
1930032e46cbSJerone Young },
1931e5713069SJamie Lentin {
1932c45fc81eSDmitry Torokhov /* OQO Model 01+ */
1933e5713069SJamie Lentin .matches = {
1934e5713069SJamie Lentin DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
1935e5713069SJamie Lentin DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
1936e5713069SJamie Lentin },
1937e5713069SJamie Lentin .callback = atkbd_setup_scancode_fixup,
1938e5713069SJamie Lentin .driver_data = atkbd_oqo_01plus_scancode_fixup,
1939e5713069SJamie Lentin },
19403d725caaSSheng-Liang Song {
19413d725caaSSheng-Liang Song .matches = {
19423d725caaSSheng-Liang Song DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
19433d725caaSSheng-Liang Song },
19443d725caaSSheng-Liang Song .callback = atkbd_deactivate_fixup,
19453d725caaSSheng-Liang Song },
1946554101e3SGiel de Nijs { }
1947554101e3SGiel de Nijs };
19481da177e4SLinus Torvalds
atkbd_init(void)19491da177e4SLinus Torvalds static int __init atkbd_init(void)
19501da177e4SLinus Torvalds {
1951554101e3SGiel de Nijs dmi_check_system(atkbd_dmi_quirk_table);
1952554101e3SGiel de Nijs
1953153a9df0SAkinobu Mita return serio_register_driver(&atkbd_drv);
19541da177e4SLinus Torvalds }
19551da177e4SLinus Torvalds
atkbd_exit(void)19561da177e4SLinus Torvalds static void __exit atkbd_exit(void)
19571da177e4SLinus Torvalds {
19581da177e4SLinus Torvalds serio_unregister_driver(&atkbd_drv);
19591da177e4SLinus Torvalds }
19601da177e4SLinus Torvalds
19611da177e4SLinus Torvalds module_init(atkbd_init);
19621da177e4SLinus Torvalds module_exit(atkbd_exit);
1963