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,
921da177e4SLinus Torvalds 0, 89, 40, 0, 26, 13, 0, 0, 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
768936e4d49SHans de Goede #ifdef CONFIG_X86
atkbd_is_portable_device(void)769936e4d49SHans de Goede static bool atkbd_is_portable_device(void)
770936e4d49SHans de Goede {
771936e4d49SHans de Goede static const char * const chassis_types[] = {
772936e4d49SHans de Goede "8", /* Portable */
773936e4d49SHans de Goede "9", /* Laptop */
774936e4d49SHans de Goede "10", /* Notebook */
775936e4d49SHans de Goede "14", /* Sub-Notebook */
776936e4d49SHans de Goede "31", /* Convertible */
777936e4d49SHans de Goede "32", /* Detachable */
778936e4d49SHans de Goede };
779936e4d49SHans de Goede int i;
780936e4d49SHans de Goede
781936e4d49SHans de Goede for (i = 0; i < ARRAY_SIZE(chassis_types); i++)
782936e4d49SHans de Goede if (dmi_match(DMI_CHASSIS_TYPE, chassis_types[i]))
783936e4d49SHans de Goede return true;
784936e4d49SHans de Goede
785936e4d49SHans de Goede return false;
786936e4d49SHans de Goede }
787936e4d49SHans de Goede
788936e4d49SHans de Goede /*
789936e4d49SHans de Goede * On many modern laptops ATKBD_CMD_GETID may cause problems, on these laptops
790936e4d49SHans de Goede * the controller is always in translated mode. In this mode mice/touchpads will
791936e4d49SHans de Goede * not work. So in this case simply assume a keyboard is connected to avoid
792936e4d49SHans de Goede * confusing some laptop keyboards.
793936e4d49SHans de Goede *
79458f65f9dSHans de Goede * Skipping ATKBD_CMD_GETID ends up using a fake keyboard id. Using the standard
79558f65f9dSHans de Goede * 0xab83 id is ok in translated mode, only atkbd_select_set() checks atkbd->id
79658f65f9dSHans de Goede * and in translated mode that is a no-op.
797936e4d49SHans de Goede */
atkbd_skip_getid(struct atkbd * atkbd)798936e4d49SHans de Goede static bool atkbd_skip_getid(struct atkbd *atkbd)
799936e4d49SHans de Goede {
800936e4d49SHans de Goede return atkbd->translated && atkbd_is_portable_device();
801936e4d49SHans de Goede }
802936e4d49SHans de Goede #else
atkbd_skip_getid(struct atkbd * atkbd)803936e4d49SHans de Goede static inline bool atkbd_skip_getid(struct atkbd *atkbd) { return false; }
804936e4d49SHans de Goede #endif
805936e4d49SHans 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
827683cd825SHans de Goede if (atkbd_skip_getid(atkbd)) {
828683cd825SHans de Goede atkbd->id = 0xab83;
8299cf6e24cSHans de Goede goto deactivate_kbd;
830683cd825SHans de Goede }
831683cd825SHans 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 */
840683cd825SHans de Goede if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
8411da177e4SLinus Torvalds
8421da177e4SLinus Torvalds /*
843683cd825SHans de Goede * If the get ID command failed, we check if we can at least set
844936e4d49SHans de Goede * the LEDs on the keyboard. This should work on every keyboard out there.
845936e4d49SHans 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;
850683cd825SHans 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
8669cf6e24cSHans de Goede deactivate_kbd:
867be2d7e42SShawn Nematbakhsh /*
868be2d7e42SShawn Nematbakhsh * Make sure nothing is coming from the keyboard and disturbs our
869be2d7e42SShawn Nematbakhsh * internal state.
870be2d7e42SShawn Nematbakhsh */
8713d725caaSSheng-Liang Song if (!atkbd_skip_deactivate)
872be2d7e42SShawn Nematbakhsh atkbd_deactivate(atkbd);
873be2d7e42SShawn Nematbakhsh
8741da177e4SLinus Torvalds return 0;
8751da177e4SLinus Torvalds }
8761da177e4SLinus Torvalds
8771da177e4SLinus Torvalds /*
8781da177e4SLinus Torvalds * atkbd_select_set checks if a keyboard has a working Set 3 support, and
8791da177e4SLinus Torvalds * sets it into that. Unfortunately there are keyboards that can be switched
8801da177e4SLinus Torvalds * to Set 3, but don't work well in that (BTC Multimedia ...)
8811da177e4SLinus Torvalds */
8821da177e4SLinus Torvalds
atkbd_select_set(struct atkbd * atkbd,int target_set,int allow_extra)8831da177e4SLinus Torvalds static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
8841da177e4SLinus Torvalds {
8851da177e4SLinus Torvalds struct ps2dev *ps2dev = &atkbd->ps2dev;
8861da177e4SLinus Torvalds unsigned char param[2];
8871da177e4SLinus Torvalds
888a9a1f9c3SDmitry Torokhov atkbd->extra = false;
8891da177e4SLinus Torvalds /*
8901da177e4SLinus Torvalds * For known special keyboards we can go ahead and set the correct set.
8911da177e4SLinus Torvalds * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
8921da177e4SLinus Torvalds * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards.
8931da177e4SLinus Torvalds */
8941da177e4SLinus Torvalds
8951da177e4SLinus Torvalds if (atkbd->translated)
8961da177e4SLinus Torvalds return 2;
8971da177e4SLinus Torvalds
8981da177e4SLinus Torvalds if (atkbd->id == 0xaca1) {
8991da177e4SLinus Torvalds param[0] = 3;
9001da177e4SLinus Torvalds ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
9011da177e4SLinus Torvalds return 3;
9021da177e4SLinus Torvalds }
9031da177e4SLinus Torvalds
9041da177e4SLinus Torvalds if (allow_extra) {
9051da177e4SLinus Torvalds param[0] = 0x71;
9061da177e4SLinus Torvalds if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
907a9a1f9c3SDmitry Torokhov atkbd->extra = true;
9081da177e4SLinus Torvalds return 2;
9091da177e4SLinus Torvalds }
9101da177e4SLinus Torvalds }
9111da177e4SLinus Torvalds
9128c5188b6SBenjamin LaHaise if (atkbd_terminal) {
9138c5188b6SBenjamin LaHaise ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB);
9148c5188b6SBenjamin LaHaise return 3;
9158c5188b6SBenjamin LaHaise }
9168c5188b6SBenjamin LaHaise
9171da177e4SLinus Torvalds if (target_set != 3)
9181da177e4SLinus Torvalds return 2;
9191da177e4SLinus Torvalds
9201da177e4SLinus Torvalds if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {
9211da177e4SLinus Torvalds atkbd->id = param[0] << 8 | param[1];
9221da177e4SLinus Torvalds return 2;
9231da177e4SLinus Torvalds }
9241da177e4SLinus Torvalds
9251da177e4SLinus Torvalds param[0] = 3;
9261da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
9271da177e4SLinus Torvalds return 2;
9281da177e4SLinus Torvalds
9291da177e4SLinus Torvalds param[0] = 0;
9301da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
9311da177e4SLinus Torvalds return 2;
9321da177e4SLinus Torvalds
9331da177e4SLinus Torvalds if (param[0] != 3) {
9341da177e4SLinus Torvalds param[0] = 2;
9351da177e4SLinus Torvalds if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
9361da177e4SLinus Torvalds return 2;
9371da177e4SLinus Torvalds }
9381da177e4SLinus Torvalds
9391da177e4SLinus Torvalds ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
9401da177e4SLinus Torvalds
9411da177e4SLinus Torvalds return 3;
9421da177e4SLinus Torvalds }
9431da177e4SLinus Torvalds
atkbd_reset_state(struct atkbd * atkbd)944fc0eb28cSDmitry Torokhov static int atkbd_reset_state(struct atkbd *atkbd)
945fc0eb28cSDmitry Torokhov {
946fc0eb28cSDmitry Torokhov struct ps2dev *ps2dev = &atkbd->ps2dev;
947fc0eb28cSDmitry Torokhov unsigned char param[1];
948fc0eb28cSDmitry Torokhov
949fc0eb28cSDmitry Torokhov /*
950fc0eb28cSDmitry Torokhov * Set the LEDs to a predefined state (all off).
951fc0eb28cSDmitry Torokhov */
952fc0eb28cSDmitry Torokhov
953fc0eb28cSDmitry Torokhov param[0] = 0;
954fc0eb28cSDmitry Torokhov if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
955fc0eb28cSDmitry Torokhov return -1;
956fc0eb28cSDmitry Torokhov
957fc0eb28cSDmitry Torokhov /*
958fc0eb28cSDmitry Torokhov * Set autorepeat to fastest possible.
959fc0eb28cSDmitry Torokhov */
960fc0eb28cSDmitry Torokhov
961fc0eb28cSDmitry Torokhov param[0] = 0;
962fc0eb28cSDmitry Torokhov if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
963fc0eb28cSDmitry Torokhov return -1;
964fc0eb28cSDmitry Torokhov
965fc0eb28cSDmitry Torokhov return 0;
966fc0eb28cSDmitry Torokhov }
967fc0eb28cSDmitry Torokhov
9681da177e4SLinus Torvalds /*
9691da177e4SLinus Torvalds * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
9701da177e4SLinus Torvalds * reboot.
9711da177e4SLinus Torvalds */
9721da177e4SLinus Torvalds
atkbd_cleanup(struct serio * serio)9731da177e4SLinus Torvalds static void atkbd_cleanup(struct serio *serio)
9741da177e4SLinus Torvalds {
975100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
97657f5b159SDmitry Torokhov
97757f5b159SDmitry Torokhov atkbd_disable(atkbd);
9784a299bf5SDmitry Torokhov ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF);
9791da177e4SLinus Torvalds }
9801da177e4SLinus Torvalds
9811da177e4SLinus Torvalds
9821da177e4SLinus Torvalds /*
9831da177e4SLinus Torvalds * atkbd_disconnect() closes and frees.
9841da177e4SLinus Torvalds */
9851da177e4SLinus Torvalds
atkbd_disconnect(struct serio * serio)9861da177e4SLinus Torvalds static void atkbd_disconnect(struct serio *serio)
9871da177e4SLinus Torvalds {
988100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
9891da177e4SLinus Torvalds
9901da177e4SLinus Torvalds atkbd_disable(atkbd);
9911da177e4SLinus Torvalds
9920ef7a26aSDmitry Torokhov input_unregister_device(atkbd->dev);
9930ef7a26aSDmitry Torokhov
9940ef7a26aSDmitry Torokhov /*
9950ef7a26aSDmitry Torokhov * Make sure we don't have a command in flight.
9960ef7a26aSDmitry Torokhov * Note that since atkbd->enabled is false event work will keep
9970ef7a26aSDmitry Torokhov * rescheduling itself until it gets canceled and will not try
9980ef7a26aSDmitry Torokhov * accessing freed input device or serio port.
9990ef7a26aSDmitry Torokhov */
1000d6d79a78SJiri Pirko cancel_delayed_work_sync(&atkbd->event_work);
10011da177e4SLinus Torvalds
10021da177e4SLinus Torvalds serio_close(serio);
10031da177e4SLinus Torvalds serio_set_drvdata(serio, NULL);
10041da177e4SLinus Torvalds kfree(atkbd);
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds
1007554101e3SGiel de Nijs /*
100839191698SDaniel Mierswa * generate release events for the keycodes given in data
100939191698SDaniel Mierswa */
atkbd_apply_forced_release_keylist(struct atkbd * atkbd,const void * data)101039191698SDaniel Mierswa static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd,
101139191698SDaniel Mierswa const void *data)
101239191698SDaniel Mierswa {
101339191698SDaniel Mierswa const unsigned int *keys = data;
101439191698SDaniel Mierswa unsigned int i;
101539191698SDaniel Mierswa
101639191698SDaniel Mierswa if (atkbd->set == 2)
101739191698SDaniel Mierswa for (i = 0; keys[i] != -1U; i++)
101839191698SDaniel Mierswa __set_bit(keys[i], atkbd->force_release_mask);
101939191698SDaniel Mierswa }
102039191698SDaniel Mierswa
102139191698SDaniel Mierswa /*
102261579ba8SMatthew Garrett * Most special keys (Fn+F?) on Dell laptops do not generate release
1023554101e3SGiel de Nijs * events so we have to do it ourselves.
1024554101e3SGiel de Nijs */
102539191698SDaniel Mierswa static unsigned int atkbd_dell_laptop_forced_release_keys[] = {
102639191698SDaniel Mierswa 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U
1027554101e3SGiel de Nijs };
10281da177e4SLinus Torvalds
10291da177e4SLinus Torvalds /*
10305a54c011SJiri Kosina * Perform fixup for HP system that doesn't generate release
10315a54c011SJiri Kosina * for its video switch
10325a54c011SJiri Kosina */
103339191698SDaniel Mierswa static unsigned int atkbd_hp_forced_release_keys[] = {
103439191698SDaniel Mierswa 0x94, -1U
10355a54c011SJiri Kosina };
10365a54c011SJiri Kosina
10375a54c011SJiri Kosina /*
1038e04126c7SBarry Carroll * Samsung NC10,NC20 with Fn+F? key release not working
10394200844bSStuart Hopkins */
104039191698SDaniel Mierswa static unsigned int atkbd_samsung_forced_release_keys[] = {
104139191698SDaniel Mierswa 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U
10424200844bSStuart Hopkins };
10434200844bSStuart Hopkins
10444200844bSStuart Hopkins /*
1045f0a14de2SSimon Davie * Amilo Pi 3525 key release for Fn+Volume keys not working
1046f0a14de2SSimon Davie */
1047f0a14de2SSimon Davie static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = {
1048f0a14de2SSimon Davie 0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U
1049f0a14de2SSimon Davie };
1050f0a14de2SSimon Davie
1051f0a14de2SSimon Davie /*
10529166d0f6SAdrian Batzill * Amilo Xi 3650 key release for light touch bar not working
10539166d0f6SAdrian Batzill */
10549166d0f6SAdrian Batzill static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = {
10559166d0f6SAdrian Batzill 0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U
10569166d0f6SAdrian Batzill };
10579166d0f6SAdrian Batzill
10589166d0f6SAdrian Batzill /*
1059032e46cbSJerone Young * Soltech TA12 system with broken key release on volume keys and mute key
1060032e46cbSJerone Young */
1061032e46cbSJerone Young static unsigned int atkdb_soltech_ta12_forced_release_keys[] = {
1062032e46cbSJerone Young 0xa0, 0xae, 0xb0, -1U
1063032e46cbSJerone Young };
1064032e46cbSJerone Young
1065032e46cbSJerone Young /*
1066000c2a35SHerton Ronaldo Krzesinski * Many notebooks don't send key release event for volume up/down
1067000c2a35SHerton Ronaldo Krzesinski * keys, with key list below common among them
1068000c2a35SHerton Ronaldo Krzesinski */
1069000c2a35SHerton Ronaldo Krzesinski static unsigned int atkbd_volume_forced_release_keys[] = {
1070000c2a35SHerton Ronaldo Krzesinski 0xae, 0xb0, -1U
1071000c2a35SHerton Ronaldo Krzesinski };
1072000c2a35SHerton Ronaldo Krzesinski
1073000c2a35SHerton Ronaldo Krzesinski /*
1074e5713069SJamie Lentin * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas
1075e5713069SJamie Lentin * they should be generating e4-e6 (0x80 | code).
1076e5713069SJamie Lentin */
atkbd_oqo_01plus_scancode_fixup(struct atkbd * atkbd,unsigned int code)1077e5713069SJamie Lentin static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
1078e5713069SJamie Lentin unsigned int code)
1079e5713069SJamie Lentin {
1080e5713069SJamie Lentin if (atkbd->translated && atkbd->emul == 1 &&
1081e5713069SJamie Lentin (code == 0x64 || code == 0x65 || code == 0x66)) {
1082e5713069SJamie Lentin atkbd->emul = 0;
1083e5713069SJamie Lentin code |= 0x80;
1084e5713069SJamie Lentin }
1085e5713069SJamie Lentin
1086e5713069SJamie Lentin return code;
1087e5713069SJamie Lentin }
1088e5713069SJamie Lentin
atkbd_get_keymap_from_fwnode(struct atkbd * atkbd)10899d17ad23SRajat Jain static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
10909d17ad23SRajat Jain {
10919d17ad23SRajat Jain struct device *dev = &atkbd->ps2dev.serio->dev;
10929d17ad23SRajat Jain int i, n;
10939d17ad23SRajat Jain u32 *ptr;
10949d17ad23SRajat Jain u16 scancode, keycode;
10959d17ad23SRajat Jain
10969d17ad23SRajat Jain /* Parse "linux,keymap" property */
10979d17ad23SRajat Jain n = device_property_count_u32(dev, "linux,keymap");
10989d17ad23SRajat Jain if (n <= 0 || n > ATKBD_KEYMAP_SIZE)
10999d17ad23SRajat Jain return -ENXIO;
11009d17ad23SRajat Jain
11019d17ad23SRajat Jain ptr = kcalloc(n, sizeof(u32), GFP_KERNEL);
11029d17ad23SRajat Jain if (!ptr)
11039d17ad23SRajat Jain return -ENOMEM;
11049d17ad23SRajat Jain
11059d17ad23SRajat Jain if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) {
11069d17ad23SRajat Jain dev_err(dev, "problem parsing FW keymap property\n");
11079d17ad23SRajat Jain kfree(ptr);
11089d17ad23SRajat Jain return -EINVAL;
11099d17ad23SRajat Jain }
11109d17ad23SRajat Jain
11119d17ad23SRajat Jain memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
11129d17ad23SRajat Jain for (i = 0; i < n; i++) {
11139d17ad23SRajat Jain scancode = SCANCODE(ptr[i]);
11149d17ad23SRajat Jain keycode = KEYCODE(ptr[i]);
11159d17ad23SRajat Jain atkbd->keycode[scancode] = keycode;
11169d17ad23SRajat Jain }
11179d17ad23SRajat Jain
11189d17ad23SRajat Jain kfree(ptr);
11199d17ad23SRajat Jain return 0;
11209d17ad23SRajat Jain }
11219d17ad23SRajat Jain
1122e5713069SJamie Lentin /*
11233c42f0c3SDmitry Torokhov * atkbd_set_keycode_table() initializes keyboard's keycode table
11241da177e4SLinus Torvalds * according to the selected scancode set
11251da177e4SLinus Torvalds */
11261da177e4SLinus Torvalds
atkbd_set_keycode_table(struct atkbd * atkbd)11271da177e4SLinus Torvalds static void atkbd_set_keycode_table(struct atkbd *atkbd)
11281da177e4SLinus Torvalds {
11299d17ad23SRajat Jain struct device *dev = &atkbd->ps2dev.serio->dev;
1130554101e3SGiel de Nijs unsigned int scancode;
11311da177e4SLinus Torvalds int i, j;
11321da177e4SLinus Torvalds
11331da177e4SLinus Torvalds memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
11341ba36e11SDmitry Torokhov bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
11351da177e4SLinus Torvalds
11369d17ad23SRajat Jain if (!atkbd_get_keymap_from_fwnode(atkbd)) {
11379d17ad23SRajat Jain dev_dbg(dev, "Using FW keymap\n");
11389d17ad23SRajat Jain } else if (atkbd->translated) {
11391da177e4SLinus Torvalds for (i = 0; i < 128; i++) {
1140554101e3SGiel de Nijs scancode = atkbd_unxlate_table[i];
1141554101e3SGiel de Nijs atkbd->keycode[i] = atkbd_set2_keycode[scancode];
1142554101e3SGiel de Nijs atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80];
11431da177e4SLinus Torvalds if (atkbd->scroll)
11441da177e4SLinus Torvalds for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
1145554101e3SGiel de Nijs if ((scancode | 0x80) == atkbd_scroll_keys[j].set2)
11461da177e4SLinus Torvalds atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
11471da177e4SLinus Torvalds }
11481da177e4SLinus Torvalds } else if (atkbd->set == 3) {
11491da177e4SLinus Torvalds memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
11501da177e4SLinus Torvalds } else {
11511da177e4SLinus Torvalds memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
11521da177e4SLinus Torvalds
11531da177e4SLinus Torvalds if (atkbd->scroll)
1154554101e3SGiel de Nijs for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) {
1155554101e3SGiel de Nijs scancode = atkbd_scroll_keys[i].set2;
1156554101e3SGiel de Nijs atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode;
1157554101e3SGiel de Nijs }
11581da177e4SLinus Torvalds }
11590ae051a1SDmitry Torokhov
1160554101e3SGiel de Nijs /*
1161554101e3SGiel de Nijs * HANGEUL and HANJA keys do not send release events so we need to
1162554101e3SGiel de Nijs * generate such events ourselves
1163554101e3SGiel de Nijs */
1164554101e3SGiel de Nijs scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL);
1165554101e3SGiel de Nijs atkbd->keycode[scancode] = KEY_HANGEUL;
1166554101e3SGiel de Nijs __set_bit(scancode, atkbd->force_release_mask);
1167554101e3SGiel de Nijs
1168554101e3SGiel de Nijs scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA);
1169554101e3SGiel de Nijs atkbd->keycode[scancode] = KEY_HANJA;
1170554101e3SGiel de Nijs __set_bit(scancode, atkbd->force_release_mask);
1171554101e3SGiel de Nijs
1172554101e3SGiel de Nijs /*
1173554101e3SGiel de Nijs * Perform additional fixups
1174554101e3SGiel de Nijs */
1175554101e3SGiel de Nijs if (atkbd_platform_fixup)
117639191698SDaniel Mierswa atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data);
11771da177e4SLinus Torvalds }
11781da177e4SLinus Torvalds
11791da177e4SLinus Torvalds /*
11801da177e4SLinus Torvalds * atkbd_set_device_attrs() sets up keyboard's input device structure
11811da177e4SLinus Torvalds */
11821da177e4SLinus Torvalds
atkbd_set_device_attrs(struct atkbd * atkbd)11831da177e4SLinus Torvalds static void atkbd_set_device_attrs(struct atkbd *atkbd)
11841da177e4SLinus Torvalds {
11853c42f0c3SDmitry Torokhov struct input_dev *input_dev = atkbd->dev;
11861da177e4SLinus Torvalds int i;
11871da177e4SLinus Torvalds
11883c42f0c3SDmitry Torokhov if (atkbd->extra)
1189ea08c6faSDmitry Torokhov snprintf(atkbd->name, sizeof(atkbd->name),
1190ea08c6faSDmitry Torokhov "AT Set 2 Extra keyboard");
11913c42f0c3SDmitry Torokhov else
1192ea08c6faSDmitry Torokhov snprintf(atkbd->name, sizeof(atkbd->name),
1193ea08c6faSDmitry Torokhov "AT %s Set %d keyboard",
11943c42f0c3SDmitry Torokhov atkbd->translated ? "Translated" : "Raw", atkbd->set);
11951da177e4SLinus Torvalds
1196ea08c6faSDmitry Torokhov snprintf(atkbd->phys, sizeof(atkbd->phys),
1197ea08c6faSDmitry Torokhov "%s/input0", atkbd->ps2dev.serio->phys);
11981da177e4SLinus Torvalds
11993c42f0c3SDmitry Torokhov input_dev->name = atkbd->name;
12003c42f0c3SDmitry Torokhov input_dev->phys = atkbd->phys;
12013c42f0c3SDmitry Torokhov input_dev->id.bustype = BUS_I8042;
12023c42f0c3SDmitry Torokhov input_dev->id.vendor = 0x0001;
12033c42f0c3SDmitry Torokhov input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
12043c42f0c3SDmitry Torokhov input_dev->id.version = atkbd->id;
12053c42f0c3SDmitry Torokhov input_dev->event = atkbd_event;
1206469ba4dfSDmitry Torokhov input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
12071da177e4SLinus Torvalds
1208b356872fSDmitry Torokhov input_set_drvdata(input_dev, atkbd);
1209b356872fSDmitry Torokhov
12107b19ada2SJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
12117b19ada2SJiri Slaby BIT_MASK(EV_MSC);
12121da177e4SLinus Torvalds
12131da177e4SLinus Torvalds if (atkbd->write) {
12147b19ada2SJiri Slaby input_dev->evbit[0] |= BIT_MASK(EV_LED);
12157b19ada2SJiri Slaby input_dev->ledbit[0] = BIT_MASK(LED_NUML) |
12167b19ada2SJiri Slaby BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL);
12171da177e4SLinus Torvalds }
12181da177e4SLinus Torvalds
12191da177e4SLinus Torvalds if (atkbd->extra)
12207b19ada2SJiri Slaby input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) |
12217b19ada2SJiri Slaby BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) |
12227b19ada2SJiri Slaby BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC);
12231da177e4SLinus Torvalds
12241da177e4SLinus Torvalds if (!atkbd->softrepeat) {
12253c42f0c3SDmitry Torokhov input_dev->rep[REP_DELAY] = 250;
12263c42f0c3SDmitry Torokhov input_dev->rep[REP_PERIOD] = 33;
12271da177e4SLinus Torvalds }
12281da177e4SLinus Torvalds
12297b19ada2SJiri Slaby input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) :
12307b19ada2SJiri Slaby BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);
12311da177e4SLinus Torvalds
12321da177e4SLinus Torvalds if (atkbd->scroll) {
12337b19ada2SJiri Slaby input_dev->evbit[0] |= BIT_MASK(EV_REL);
12347b19ada2SJiri Slaby input_dev->relbit[0] = BIT_MASK(REL_WHEEL) |
12357b19ada2SJiri Slaby BIT_MASK(REL_HWHEEL);
1236f6d65610SDmitry Torokhov __set_bit(BTN_MIDDLE, input_dev->keybit);
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds
12393c42f0c3SDmitry Torokhov input_dev->keycode = atkbd->keycode;
1240f6d65610SDmitry Torokhov input_dev->keycodesize = sizeof(unsigned short);
12413c42f0c3SDmitry Torokhov input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
12421da177e4SLinus Torvalds
12434b70858bSDmitry Torokhov for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
12444b70858bSDmitry Torokhov if (atkbd->keycode[i] != KEY_RESERVED &&
12454b70858bSDmitry Torokhov atkbd->keycode[i] != ATKBD_KEY_NULL &&
12464b70858bSDmitry Torokhov atkbd->keycode[i] < ATKBD_SPECIAL) {
1247f6d65610SDmitry Torokhov __set_bit(atkbd->keycode[i], input_dev->keybit);
12481da177e4SLinus Torvalds }
12494b70858bSDmitry Torokhov }
12504b70858bSDmitry Torokhov }
12511da177e4SLinus Torvalds
atkbd_parse_fwnode_data(struct serio * serio)12528f7b057aSRajat Jain static void atkbd_parse_fwnode_data(struct serio *serio)
12538f7b057aSRajat Jain {
1254100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
12558f7b057aSRajat Jain struct device *dev = &serio->dev;
12568f7b057aSRajat Jain int n;
12578f7b057aSRajat Jain
12588f7b057aSRajat Jain /* Parse "function-row-physmap" property */
12598f7b057aSRajat Jain n = device_property_count_u32(dev, "function-row-physmap");
126045ceaf14SStephen Boyd if (n > 0 && n <= VIVALDI_MAX_FUNCTION_ROW_KEYS &&
12618f7b057aSRajat Jain !device_property_read_u32_array(dev, "function-row-physmap",
126245ceaf14SStephen Boyd atkbd->vdata.function_row_physmap,
126345ceaf14SStephen Boyd n)) {
126445ceaf14SStephen Boyd atkbd->vdata.num_function_row_keys = n;
12658f7b057aSRajat Jain dev_dbg(dev, "FW reported %d function-row key locations\n", n);
12668f7b057aSRajat Jain }
12678f7b057aSRajat Jain }
12688f7b057aSRajat Jain
12691da177e4SLinus Torvalds /*
12701da177e4SLinus Torvalds * atkbd_connect() is called when the serio module finds an interface
12711da177e4SLinus Torvalds * that isn't handled yet by an appropriate device driver. We check if
12721da177e4SLinus Torvalds * there is an AT keyboard out there and if yes, we register ourselves
12731da177e4SLinus Torvalds * to the input module.
12741da177e4SLinus Torvalds */
12751da177e4SLinus Torvalds
atkbd_connect(struct serio * serio,struct serio_driver * drv)12761da177e4SLinus Torvalds static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
12771da177e4SLinus Torvalds {
12781da177e4SLinus Torvalds struct atkbd *atkbd;
12793c42f0c3SDmitry Torokhov struct input_dev *dev;
12803c42f0c3SDmitry Torokhov int err = -ENOMEM;
12811da177e4SLinus Torvalds
1282*bb8706a4SErick Archer atkbd = kzalloc(sizeof(*atkbd), GFP_KERNEL);
12833c42f0c3SDmitry Torokhov dev = input_allocate_device();
12843c42f0c3SDmitry Torokhov if (!atkbd || !dev)
12852b03b60eSDmitry Torokhov goto fail1;
12861da177e4SLinus Torvalds
12873c42f0c3SDmitry Torokhov atkbd->dev = dev;
1288c4c7eac8SDmitry Torokhov ps2_init(&atkbd->ps2dev, serio,
1289c4c7eac8SDmitry Torokhov atkbd_pre_receive_byte, atkbd_receive_byte);
1290da4249c9SDmitry Torokhov INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
129159b01513SEric W. Biederman mutex_init(&atkbd->mutex);
12921da177e4SLinus Torvalds
12931da177e4SLinus Torvalds switch (serio->id.type) {
12941da177e4SLinus Torvalds
12951da177e4SLinus Torvalds case SERIO_8042_XL:
1296a9a1f9c3SDmitry Torokhov atkbd->translated = true;
12976f49c4f5SGustavo A. R. Silva fallthrough;
1298a9a1f9c3SDmitry Torokhov
12991da177e4SLinus Torvalds case SERIO_8042:
13001da177e4SLinus Torvalds if (serio->write)
1301a9a1f9c3SDmitry Torokhov atkbd->write = true;
13021da177e4SLinus Torvalds break;
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds
13051da177e4SLinus Torvalds atkbd->softraw = atkbd_softraw;
13061da177e4SLinus Torvalds atkbd->softrepeat = atkbd_softrepeat;
13071da177e4SLinus Torvalds atkbd->scroll = atkbd_scroll;
13081da177e4SLinus Torvalds
13091da177e4SLinus Torvalds if (atkbd->softrepeat)
1310a9a1f9c3SDmitry Torokhov atkbd->softraw = true;
13111da177e4SLinus Torvalds
13121da177e4SLinus Torvalds serio_set_drvdata(serio, atkbd);
13131da177e4SLinus Torvalds
13141da177e4SLinus Torvalds err = serio_open(serio, drv);
13153c42f0c3SDmitry Torokhov if (err)
13162b03b60eSDmitry Torokhov goto fail2;
13171da177e4SLinus Torvalds
13181da177e4SLinus Torvalds if (atkbd->write) {
13191da177e4SLinus Torvalds
13201da177e4SLinus Torvalds if (atkbd_probe(atkbd)) {
13213c42f0c3SDmitry Torokhov err = -ENODEV;
13222b03b60eSDmitry Torokhov goto fail3;
13231da177e4SLinus Torvalds }
13241da177e4SLinus Torvalds
13251da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
1326fc0eb28cSDmitry Torokhov atkbd_reset_state(atkbd);
13271da177e4SLinus Torvalds
13281da177e4SLinus Torvalds } else {
13291da177e4SLinus Torvalds atkbd->set = 2;
13301da177e4SLinus Torvalds atkbd->id = 0xab00;
13311da177e4SLinus Torvalds }
13321da177e4SLinus Torvalds
13338f7b057aSRajat Jain atkbd_parse_fwnode_data(serio);
13348f7b057aSRajat Jain
13351da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd);
13361da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
13371da177e4SLinus Torvalds
13381da177e4SLinus Torvalds atkbd_enable(atkbd);
1339be2d7e42SShawn Nematbakhsh if (serio->write)
1340be2d7e42SShawn Nematbakhsh atkbd_activate(atkbd);
13411da177e4SLinus Torvalds
13422b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
13432b03b60eSDmitry Torokhov if (err)
1344c99e3ac6SDmitry Torokhov goto fail3;
13451da177e4SLinus Torvalds
13461da177e4SLinus Torvalds return 0;
13473c42f0c3SDmitry Torokhov
13482b03b60eSDmitry Torokhov fail3: serio_close(serio);
13492b03b60eSDmitry Torokhov fail2: serio_set_drvdata(serio, NULL);
13502b03b60eSDmitry Torokhov fail1: input_free_device(dev);
13513c42f0c3SDmitry Torokhov kfree(atkbd);
13523c42f0c3SDmitry Torokhov return err;
13531da177e4SLinus Torvalds }
13541da177e4SLinus Torvalds
13551da177e4SLinus Torvalds /*
13561da177e4SLinus Torvalds * atkbd_reconnect() tries to restore keyboard into a sane state and is
13571da177e4SLinus Torvalds * most likely called on resume.
13581da177e4SLinus Torvalds */
13591da177e4SLinus Torvalds
atkbd_reconnect(struct serio * serio)13601da177e4SLinus Torvalds static int atkbd_reconnect(struct serio *serio)
13611da177e4SLinus Torvalds {
1362100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
13631da177e4SLinus Torvalds struct serio_driver *drv = serio->drv;
136459b01513SEric W. Biederman int retval = -1;
13651da177e4SLinus Torvalds
13661da177e4SLinus Torvalds if (!atkbd || !drv) {
1367a9a1f9c3SDmitry Torokhov dev_dbg(&serio->dev,
1368a9a1f9c3SDmitry Torokhov "reconnect request, but serio is disconnected, ignoring...\n");
13691da177e4SLinus Torvalds return -1;
13701da177e4SLinus Torvalds }
13711da177e4SLinus Torvalds
137259b01513SEric W. Biederman mutex_lock(&atkbd->mutex);
137359b01513SEric W. Biederman
13741da177e4SLinus Torvalds atkbd_disable(atkbd);
13751da177e4SLinus Torvalds
13761da177e4SLinus Torvalds if (atkbd->write) {
13771da177e4SLinus Torvalds if (atkbd_probe(atkbd))
137859b01513SEric W. Biederman goto out;
137959b01513SEric W. Biederman
13801da177e4SLinus Torvalds if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
138159b01513SEric W. Biederman goto out;
13821da177e4SLinus Torvalds
1383d4119bdaSDmitry Torokhov /*
1384d4119bdaSDmitry Torokhov * Restore LED state and repeat rate. While input core
1385d4119bdaSDmitry Torokhov * will do this for us at resume time reconnect may happen
1386d4119bdaSDmitry Torokhov * because user requested it via sysfs or simply because
1387d4119bdaSDmitry Torokhov * keyboard was unplugged and plugged in again so we need
1388d4119bdaSDmitry Torokhov * to do it ourselves here.
1389d4119bdaSDmitry Torokhov */
1390d4119bdaSDmitry Torokhov atkbd_set_leds(atkbd);
1391d4119bdaSDmitry Torokhov if (!atkbd->softrepeat)
1392d4119bdaSDmitry Torokhov atkbd_set_repeat_rate(atkbd);
1393d4119bdaSDmitry Torokhov
13941da177e4SLinus Torvalds }
13951da177e4SLinus Torvalds
1396be2d7e42SShawn Nematbakhsh /*
1397be2d7e42SShawn Nematbakhsh * Reset our state machine in case reconnect happened in the middle
1398be2d7e42SShawn Nematbakhsh * of multi-byte scancode.
1399be2d7e42SShawn Nematbakhsh */
1400be2d7e42SShawn Nematbakhsh atkbd->xl_bit = 0;
1401be2d7e42SShawn Nematbakhsh atkbd->emul = 0;
1402be2d7e42SShawn Nematbakhsh
14031da177e4SLinus Torvalds atkbd_enable(atkbd);
1404be2d7e42SShawn Nematbakhsh if (atkbd->write)
1405be2d7e42SShawn Nematbakhsh atkbd_activate(atkbd);
1406be2d7e42SShawn Nematbakhsh
140759b01513SEric W. Biederman retval = 0;
14081da177e4SLinus Torvalds
140959b01513SEric W. Biederman out:
141059b01513SEric W. Biederman mutex_unlock(&atkbd->mutex);
141159b01513SEric W. Biederman return retval;
14121da177e4SLinus Torvalds }
14131da177e4SLinus Torvalds
1414af2e7d77SArvind Yadav static const struct serio_device_id atkbd_serio_ids[] = {
14151da177e4SLinus Torvalds {
14161da177e4SLinus Torvalds .type = SERIO_8042,
14171da177e4SLinus Torvalds .proto = SERIO_ANY,
14181da177e4SLinus Torvalds .id = SERIO_ANY,
14191da177e4SLinus Torvalds .extra = SERIO_ANY,
14201da177e4SLinus Torvalds },
14211da177e4SLinus Torvalds {
14221da177e4SLinus Torvalds .type = SERIO_8042_XL,
14231da177e4SLinus Torvalds .proto = SERIO_ANY,
14241da177e4SLinus Torvalds .id = SERIO_ANY,
14251da177e4SLinus Torvalds .extra = SERIO_ANY,
14261da177e4SLinus Torvalds },
14271da177e4SLinus Torvalds {
14281da177e4SLinus Torvalds .type = SERIO_RS232,
14291da177e4SLinus Torvalds .proto = SERIO_PS2SER,
14301da177e4SLinus Torvalds .id = SERIO_ANY,
14311da177e4SLinus Torvalds .extra = SERIO_ANY,
14321da177e4SLinus Torvalds },
14331da177e4SLinus Torvalds { 0 }
14341da177e4SLinus Torvalds };
14351da177e4SLinus Torvalds
14361da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
14371da177e4SLinus Torvalds
14381da177e4SLinus Torvalds static struct serio_driver atkbd_drv = {
14391da177e4SLinus Torvalds .driver = {
14401da177e4SLinus Torvalds .name = "atkbd",
1441c99e3ac6SDmitry Torokhov .dev_groups = atkbd_attribute_groups,
14421da177e4SLinus Torvalds },
14431da177e4SLinus Torvalds .description = DRIVER_DESC,
14441da177e4SLinus Torvalds .id_table = atkbd_serio_ids,
1445c4c7eac8SDmitry Torokhov .interrupt = ps2_interrupt,
14461da177e4SLinus Torvalds .connect = atkbd_connect,
14471da177e4SLinus Torvalds .reconnect = atkbd_reconnect,
14481da177e4SLinus Torvalds .disconnect = atkbd_disconnect,
14491da177e4SLinus Torvalds .cleanup = atkbd_cleanup,
14501da177e4SLinus Torvalds };
14511da177e4SLinus Torvalds
atkbd_attr_show_helper(struct device * dev,char * buf,ssize_t (* handler)(struct atkbd *,char *))14521da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
14531da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, char *))
14541da177e4SLinus Torvalds {
14551da177e4SLinus Torvalds struct serio *serio = to_serio_port(dev);
1456100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
14571da177e4SLinus Torvalds
145859b01513SEric W. Biederman return handler(atkbd, buf);
14591da177e4SLinus Torvalds }
14601da177e4SLinus Torvalds
atkbd_attr_set_helper(struct device * dev,const char * buf,size_t count,ssize_t (* handler)(struct atkbd *,const char *,size_t))14611da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
14621da177e4SLinus Torvalds ssize_t (*handler)(struct atkbd *, const char *, size_t))
14631da177e4SLinus Torvalds {
14641da177e4SLinus Torvalds struct serio *serio = to_serio_port(dev);
1465100e1695SDmitry Torokhov struct atkbd *atkbd = atkbd_from_serio(serio);
14661da177e4SLinus Torvalds int retval;
14671da177e4SLinus Torvalds
146859b01513SEric W. Biederman retval = mutex_lock_interruptible(&atkbd->mutex);
14691da177e4SLinus Torvalds if (retval)
14701da177e4SLinus Torvalds return retval;
14711da177e4SLinus Torvalds
14721da177e4SLinus Torvalds atkbd_disable(atkbd);
14731da177e4SLinus Torvalds retval = handler(atkbd, buf, count);
14741da177e4SLinus Torvalds atkbd_enable(atkbd);
14751da177e4SLinus Torvalds
147659b01513SEric W. Biederman mutex_unlock(&atkbd->mutex);
147759b01513SEric W. Biederman
14781da177e4SLinus Torvalds return retval;
14791da177e4SLinus Torvalds }
14801da177e4SLinus Torvalds
atkbd_show_extra(struct atkbd * atkbd,char * buf)14811da177e4SLinus Torvalds static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
14821da177e4SLinus Torvalds {
14831da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0);
14841da177e4SLinus Torvalds }
14851da177e4SLinus Torvalds
atkbd_set_extra(struct atkbd * atkbd,const char * buf,size_t count)14861da177e4SLinus Torvalds static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
14871da177e4SLinus Torvalds {
14882b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
148976496e7aSJJ Ding unsigned int value;
14902b03b60eSDmitry Torokhov int err;
1491a9a1f9c3SDmitry Torokhov bool old_extra;
1492a9a1f9c3SDmitry Torokhov unsigned char old_set;
14931da177e4SLinus Torvalds
14941da177e4SLinus Torvalds if (!atkbd->write)
14951da177e4SLinus Torvalds return -EIO;
14961da177e4SLinus Torvalds
149776496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
149876496e7aSJJ Ding if (err)
149976496e7aSJJ Ding return err;
150076496e7aSJJ Ding
150176496e7aSJJ Ding if (value > 1)
15021da177e4SLinus Torvalds return -EINVAL;
15031da177e4SLinus Torvalds
15041da177e4SLinus Torvalds if (atkbd->extra != value) {
15053c42f0c3SDmitry Torokhov /*
15063c42f0c3SDmitry Torokhov * Since device's properties will change we need to
15072b03b60eSDmitry Torokhov * unregister old device. But allocate and register
15082b03b60eSDmitry Torokhov * new one first to make sure we have it.
15093c42f0c3SDmitry Torokhov */
15102b03b60eSDmitry Torokhov old_dev = atkbd->dev;
15112b03b60eSDmitry Torokhov old_extra = atkbd->extra;
15122b03b60eSDmitry Torokhov old_set = atkbd->set;
15132b03b60eSDmitry Torokhov
15142b03b60eSDmitry Torokhov new_dev = input_allocate_device();
15152b03b60eSDmitry Torokhov if (!new_dev)
15163c42f0c3SDmitry Torokhov return -ENOMEM;
15172b03b60eSDmitry Torokhov
15183c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
15191da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
1520fc0eb28cSDmitry Torokhov atkbd_reset_state(atkbd);
15211da177e4SLinus Torvalds atkbd_activate(atkbd);
15222b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd);
15231da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
15242b03b60eSDmitry Torokhov
15252b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
15262b03b60eSDmitry Torokhov if (err) {
15272b03b60eSDmitry Torokhov input_free_device(new_dev);
15282b03b60eSDmitry Torokhov
15292b03b60eSDmitry Torokhov atkbd->dev = old_dev;
15302b03b60eSDmitry Torokhov atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
15312b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd);
15322b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
15332b03b60eSDmitry Torokhov
15342b03b60eSDmitry Torokhov return err;
15352b03b60eSDmitry Torokhov }
15362b03b60eSDmitry Torokhov input_unregister_device(old_dev);
15372b03b60eSDmitry Torokhov
15381da177e4SLinus Torvalds }
15391da177e4SLinus Torvalds return count;
15401da177e4SLinus Torvalds }
15411da177e4SLinus Torvalds
atkbd_show_force_release(struct atkbd * atkbd,char * buf)15421ba36e11SDmitry Torokhov static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
15431ba36e11SDmitry Torokhov {
15440b480037STejun Heo size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
15450b480037STejun Heo ATKBD_KEYMAP_SIZE, atkbd->force_release_mask);
15461ba36e11SDmitry Torokhov
15471ba36e11SDmitry Torokhov buf[len++] = '\n';
15481ba36e11SDmitry Torokhov buf[len] = '\0';
15491ba36e11SDmitry Torokhov
15501ba36e11SDmitry Torokhov return len;
15511ba36e11SDmitry Torokhov }
15521ba36e11SDmitry Torokhov
atkbd_set_force_release(struct atkbd * atkbd,const char * buf,size_t count)15531ba36e11SDmitry Torokhov static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
15541ba36e11SDmitry Torokhov const char *buf, size_t count)
15551ba36e11SDmitry Torokhov {
15561ba36e11SDmitry Torokhov /* 64 bytes on stack should be acceptable */
15571ba36e11SDmitry Torokhov DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
15581ba36e11SDmitry Torokhov int err;
15591ba36e11SDmitry Torokhov
15601ba36e11SDmitry Torokhov err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
15611ba36e11SDmitry Torokhov if (err)
15621ba36e11SDmitry Torokhov return err;
15631ba36e11SDmitry Torokhov
15641ba36e11SDmitry Torokhov memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
15651ba36e11SDmitry Torokhov return count;
15661ba36e11SDmitry Torokhov }
15671ba36e11SDmitry Torokhov
15681ba36e11SDmitry Torokhov
atkbd_show_scroll(struct atkbd * atkbd,char * buf)15691da177e4SLinus Torvalds static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
15701da177e4SLinus Torvalds {
15711da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
15721da177e4SLinus Torvalds }
15731da177e4SLinus Torvalds
atkbd_set_scroll(struct atkbd * atkbd,const char * buf,size_t count)15741da177e4SLinus Torvalds static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
15751da177e4SLinus Torvalds {
15762b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
157776496e7aSJJ Ding unsigned int value;
15782b03b60eSDmitry Torokhov int err;
1579a9a1f9c3SDmitry Torokhov bool old_scroll;
15801da177e4SLinus Torvalds
158176496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
158276496e7aSJJ Ding if (err)
158376496e7aSJJ Ding return err;
158476496e7aSJJ Ding
158576496e7aSJJ Ding if (value > 1)
15861da177e4SLinus Torvalds return -EINVAL;
15871da177e4SLinus Torvalds
15881da177e4SLinus Torvalds if (atkbd->scroll != value) {
15892b03b60eSDmitry Torokhov old_dev = atkbd->dev;
15902b03b60eSDmitry Torokhov old_scroll = atkbd->scroll;
15912b03b60eSDmitry Torokhov
15922b03b60eSDmitry Torokhov new_dev = input_allocate_device();
15932b03b60eSDmitry Torokhov if (!new_dev)
15943c42f0c3SDmitry Torokhov return -ENOMEM;
15952b03b60eSDmitry Torokhov
15963c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
15971da177e4SLinus Torvalds atkbd->scroll = value;
15981da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd);
15991da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
16002b03b60eSDmitry Torokhov
16012b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
16022b03b60eSDmitry Torokhov if (err) {
16032b03b60eSDmitry Torokhov input_free_device(new_dev);
16042b03b60eSDmitry Torokhov
16052b03b60eSDmitry Torokhov atkbd->scroll = old_scroll;
16062b03b60eSDmitry Torokhov atkbd->dev = old_dev;
16072b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd);
16082b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
16092b03b60eSDmitry Torokhov
16102b03b60eSDmitry Torokhov return err;
16112b03b60eSDmitry Torokhov }
16122b03b60eSDmitry Torokhov input_unregister_device(old_dev);
16131da177e4SLinus Torvalds }
16141da177e4SLinus Torvalds return count;
16151da177e4SLinus Torvalds }
16161da177e4SLinus Torvalds
atkbd_show_set(struct atkbd * atkbd,char * buf)16171da177e4SLinus Torvalds static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
16181da177e4SLinus Torvalds {
16191da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->set);
16201da177e4SLinus Torvalds }
16211da177e4SLinus Torvalds
atkbd_set_set(struct atkbd * atkbd,const char * buf,size_t count)16221da177e4SLinus Torvalds static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
16231da177e4SLinus Torvalds {
16242b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
162576496e7aSJJ Ding unsigned int value;
16262b03b60eSDmitry Torokhov int err;
1627a9a1f9c3SDmitry Torokhov unsigned char old_set;
1628a9a1f9c3SDmitry Torokhov bool old_extra;
16291da177e4SLinus Torvalds
16301da177e4SLinus Torvalds if (!atkbd->write)
16311da177e4SLinus Torvalds return -EIO;
16321da177e4SLinus Torvalds
163376496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
163476496e7aSJJ Ding if (err)
163576496e7aSJJ Ding return err;
163676496e7aSJJ Ding
163776496e7aSJJ Ding if (value != 2 && value != 3)
16381da177e4SLinus Torvalds return -EINVAL;
16391da177e4SLinus Torvalds
16401da177e4SLinus Torvalds if (atkbd->set != value) {
16412b03b60eSDmitry Torokhov old_dev = atkbd->dev;
16422b03b60eSDmitry Torokhov old_extra = atkbd->extra;
16432b03b60eSDmitry Torokhov old_set = atkbd->set;
16442b03b60eSDmitry Torokhov
16452b03b60eSDmitry Torokhov new_dev = input_allocate_device();
16462b03b60eSDmitry Torokhov if (!new_dev)
16473c42f0c3SDmitry Torokhov return -ENOMEM;
16482b03b60eSDmitry Torokhov
16493c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
16501da177e4SLinus Torvalds atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
1651d4119bdaSDmitry Torokhov atkbd_reset_state(atkbd);
16521da177e4SLinus Torvalds atkbd_activate(atkbd);
16531da177e4SLinus Torvalds atkbd_set_keycode_table(atkbd);
16541da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
16552b03b60eSDmitry Torokhov
16562b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
16572b03b60eSDmitry Torokhov if (err) {
16582b03b60eSDmitry Torokhov input_free_device(new_dev);
16592b03b60eSDmitry Torokhov
16602b03b60eSDmitry Torokhov atkbd->dev = old_dev;
16612b03b60eSDmitry Torokhov atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
16622b03b60eSDmitry Torokhov atkbd_set_keycode_table(atkbd);
16632b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
16642b03b60eSDmitry Torokhov
16652b03b60eSDmitry Torokhov return err;
16662b03b60eSDmitry Torokhov }
16672b03b60eSDmitry Torokhov input_unregister_device(old_dev);
16681da177e4SLinus Torvalds }
16691da177e4SLinus Torvalds return count;
16701da177e4SLinus Torvalds }
16711da177e4SLinus Torvalds
atkbd_show_softrepeat(struct atkbd * atkbd,char * buf)16721da177e4SLinus Torvalds static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
16731da177e4SLinus Torvalds {
16741da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0);
16751da177e4SLinus Torvalds }
16761da177e4SLinus Torvalds
atkbd_set_softrepeat(struct atkbd * atkbd,const char * buf,size_t count)16771da177e4SLinus Torvalds static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
16781da177e4SLinus Torvalds {
16792b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
168076496e7aSJJ Ding unsigned int value;
16812b03b60eSDmitry Torokhov int err;
1682a9a1f9c3SDmitry Torokhov bool old_softrepeat, old_softraw;
16831da177e4SLinus Torvalds
16841da177e4SLinus Torvalds if (!atkbd->write)
16851da177e4SLinus Torvalds return -EIO;
16861da177e4SLinus Torvalds
168776496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
168876496e7aSJJ Ding if (err)
168976496e7aSJJ Ding return err;
169076496e7aSJJ Ding
169176496e7aSJJ Ding if (value > 1)
16921da177e4SLinus Torvalds return -EINVAL;
16931da177e4SLinus Torvalds
16941da177e4SLinus Torvalds if (atkbd->softrepeat != value) {
16952b03b60eSDmitry Torokhov old_dev = atkbd->dev;
16962b03b60eSDmitry Torokhov old_softrepeat = atkbd->softrepeat;
16972b03b60eSDmitry Torokhov old_softraw = atkbd->softraw;
16982b03b60eSDmitry Torokhov
16992b03b60eSDmitry Torokhov new_dev = input_allocate_device();
17002b03b60eSDmitry Torokhov if (!new_dev)
17013c42f0c3SDmitry Torokhov return -ENOMEM;
17022b03b60eSDmitry Torokhov
17033c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
17041da177e4SLinus Torvalds atkbd->softrepeat = value;
17051da177e4SLinus Torvalds if (atkbd->softrepeat)
1706a9a1f9c3SDmitry Torokhov atkbd->softraw = true;
17071da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
17082b03b60eSDmitry Torokhov
17092b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
17102b03b60eSDmitry Torokhov if (err) {
17112b03b60eSDmitry Torokhov input_free_device(new_dev);
17122b03b60eSDmitry Torokhov
17132b03b60eSDmitry Torokhov atkbd->dev = old_dev;
17142b03b60eSDmitry Torokhov atkbd->softrepeat = old_softrepeat;
17152b03b60eSDmitry Torokhov atkbd->softraw = old_softraw;
17162b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
17172b03b60eSDmitry Torokhov
17182b03b60eSDmitry Torokhov return err;
17192b03b60eSDmitry Torokhov }
17202b03b60eSDmitry Torokhov input_unregister_device(old_dev);
17211da177e4SLinus Torvalds }
17221da177e4SLinus Torvalds return count;
17231da177e4SLinus Torvalds }
17241da177e4SLinus Torvalds
17251da177e4SLinus Torvalds
atkbd_show_softraw(struct atkbd * atkbd,char * buf)17261da177e4SLinus Torvalds static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
17271da177e4SLinus Torvalds {
17281da177e4SLinus Torvalds return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0);
17291da177e4SLinus Torvalds }
17301da177e4SLinus Torvalds
atkbd_set_softraw(struct atkbd * atkbd,const char * buf,size_t count)17311da177e4SLinus Torvalds static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
17321da177e4SLinus Torvalds {
17332b03b60eSDmitry Torokhov struct input_dev *old_dev, *new_dev;
173476496e7aSJJ Ding unsigned int value;
17352b03b60eSDmitry Torokhov int err;
1736a9a1f9c3SDmitry Torokhov bool old_softraw;
17371da177e4SLinus Torvalds
173876496e7aSJJ Ding err = kstrtouint(buf, 10, &value);
173976496e7aSJJ Ding if (err)
174076496e7aSJJ Ding return err;
174176496e7aSJJ Ding
174276496e7aSJJ Ding if (value > 1)
17431da177e4SLinus Torvalds return -EINVAL;
17441da177e4SLinus Torvalds
17451da177e4SLinus Torvalds if (atkbd->softraw != value) {
17462b03b60eSDmitry Torokhov old_dev = atkbd->dev;
17472b03b60eSDmitry Torokhov old_softraw = atkbd->softraw;
17482b03b60eSDmitry Torokhov
17492b03b60eSDmitry Torokhov new_dev = input_allocate_device();
17502b03b60eSDmitry Torokhov if (!new_dev)
17513c42f0c3SDmitry Torokhov return -ENOMEM;
17522b03b60eSDmitry Torokhov
17533c42f0c3SDmitry Torokhov atkbd->dev = new_dev;
17541da177e4SLinus Torvalds atkbd->softraw = value;
17551da177e4SLinus Torvalds atkbd_set_device_attrs(atkbd);
17562b03b60eSDmitry Torokhov
17572b03b60eSDmitry Torokhov err = input_register_device(atkbd->dev);
17582b03b60eSDmitry Torokhov if (err) {
17592b03b60eSDmitry Torokhov input_free_device(new_dev);
17602b03b60eSDmitry Torokhov
17612b03b60eSDmitry Torokhov atkbd->dev = old_dev;
17622b03b60eSDmitry Torokhov atkbd->softraw = old_softraw;
17632b03b60eSDmitry Torokhov atkbd_set_device_attrs(atkbd);
17642b03b60eSDmitry Torokhov
17652b03b60eSDmitry Torokhov return err;
17662b03b60eSDmitry Torokhov }
17672b03b60eSDmitry Torokhov input_unregister_device(old_dev);
17681da177e4SLinus Torvalds }
17691da177e4SLinus Torvalds return count;
17701da177e4SLinus Torvalds }
17711da177e4SLinus Torvalds
atkbd_show_err_count(struct atkbd * atkbd,char * buf)177286255d9dSDmitry Torokhov static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
177386255d9dSDmitry Torokhov {
177486255d9dSDmitry Torokhov return sprintf(buf, "%lu\n", atkbd->err_count);
177586255d9dSDmitry Torokhov }
177686255d9dSDmitry Torokhov
atkbd_setup_forced_release(const struct dmi_system_id * id)177739191698SDaniel Mierswa static int __init atkbd_setup_forced_release(const struct dmi_system_id *id)
1778554101e3SGiel de Nijs {
177939191698SDaniel Mierswa atkbd_platform_fixup = atkbd_apply_forced_release_keylist;
178039191698SDaniel Mierswa atkbd_platform_fixup_data = id->driver_data;
178139191698SDaniel Mierswa
1782c388b2c6SAxel Lin return 1;
1783554101e3SGiel de Nijs }
1784554101e3SGiel de Nijs
atkbd_setup_scancode_fixup(const struct dmi_system_id * id)1785e5713069SJamie Lentin static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
1786e5713069SJamie Lentin {
1787e5713069SJamie Lentin atkbd_platform_scancode_fixup = id->driver_data;
1788e5713069SJamie Lentin
1789c388b2c6SAxel Lin return 1;
1790e5713069SJamie Lentin }
1791e5713069SJamie Lentin
atkbd_deactivate_fixup(const struct dmi_system_id * id)17923d725caaSSheng-Liang Song static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id)
17933d725caaSSheng-Liang Song {
17943d725caaSSheng-Liang Song atkbd_skip_deactivate = true;
17953d725caaSSheng-Liang Song return 1;
17963d725caaSSheng-Liang Song }
17973d725caaSSheng-Liang Song
17988b8a518eSDmitry Torokhov /*
17998b8a518eSDmitry Torokhov * NOTE: do not add any more "force release" quirks to this table. The
18008b8a518eSDmitry Torokhov * task of adjusting list of keys that should be "released" automatically
18018b8a518eSDmitry Torokhov * by the driver is now delegated to userspace tools, such as udev, so
18028b8a518eSDmitry Torokhov * submit such quirks there.
18038b8a518eSDmitry Torokhov */
1804c45fc81eSDmitry Torokhov static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
1805554101e3SGiel de Nijs {
1806554101e3SGiel de Nijs .matches = {
1807554101e3SGiel de Nijs DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
180861579ba8SMatthew Garrett DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
1809554101e3SGiel de Nijs },
181039191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
181139191698SDaniel Mierswa .driver_data = atkbd_dell_laptop_forced_release_keys,
1812554101e3SGiel de Nijs },
18135a54c011SJiri Kosina {
18142a3ec326SMatthew Garrett .matches = {
18152a3ec326SMatthew Garrett DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
18162a3ec326SMatthew Garrett DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
18172a3ec326SMatthew Garrett },
181839191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
181939191698SDaniel Mierswa .driver_data = atkbd_dell_laptop_forced_release_keys,
18202a3ec326SMatthew Garrett },
18212a3ec326SMatthew Garrett {
18225a54c011SJiri Kosina .matches = {
18235a54c011SJiri Kosina DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18245a54c011SJiri Kosina DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"),
18255a54c011SJiri Kosina },
182639191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
182739191698SDaniel Mierswa .driver_data = atkbd_hp_forced_release_keys,
18285a54c011SJiri Kosina },
1829a8215b81SMatthew Garrett {
1830181f6382SRikard Ljungstrand .matches = {
1831181f6382SRikard Ljungstrand DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1832181f6382SRikard Ljungstrand DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
1833181f6382SRikard Ljungstrand },
183439191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
1835000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
1836181f6382SRikard Ljungstrand },
1837181f6382SRikard Ljungstrand {
18382bcaa6a4SDave Andrews .matches = {
18392bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18402bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
18412bcaa6a4SDave Andrews },
18422bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release,
1843000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
18442bcaa6a4SDave Andrews },
18452bcaa6a4SDave Andrews {
18462bcaa6a4SDave Andrews .matches = {
18472bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18482bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
18492bcaa6a4SDave Andrews },
18502bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release,
1851000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
18522bcaa6a4SDave Andrews },
18532bcaa6a4SDave Andrews {
18542bcaa6a4SDave Andrews .matches = {
18552bcaa6a4SDave Andrews DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18562bcaa6a4SDave Andrews DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
18572bcaa6a4SDave Andrews },
18582bcaa6a4SDave Andrews .callback = atkbd_setup_forced_release,
1859000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
18602bcaa6a4SDave Andrews },
18612bcaa6a4SDave Andrews {
1862c45fc81eSDmitry Torokhov /* Inventec Symphony */
1863a8215b81SMatthew Garrett .matches = {
1864a8215b81SMatthew Garrett DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"),
1865a8215b81SMatthew Garrett DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
1866a8215b81SMatthew Garrett },
186739191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
1868000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
1869a8215b81SMatthew Garrett },
18704200844bSStuart Hopkins {
1871c45fc81eSDmitry Torokhov /* Samsung NC10 */
18724200844bSStuart Hopkins .matches = {
18734200844bSStuart Hopkins DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
18744200844bSStuart Hopkins DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
18754200844bSStuart Hopkins },
187639191698SDaniel Mierswa .callback = atkbd_setup_forced_release,
187739191698SDaniel Mierswa .driver_data = atkbd_samsung_forced_release_keys,
18784200844bSStuart Hopkins },
1879adcb523eSDaniel Mierswa {
1880c45fc81eSDmitry Torokhov /* Samsung NC20 */
1881e04126c7SBarry Carroll .matches = {
1882e04126c7SBarry Carroll DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1883e04126c7SBarry Carroll DMI_MATCH(DMI_PRODUCT_NAME, "NC20"),
1884e04126c7SBarry Carroll },
1885e04126c7SBarry Carroll .callback = atkbd_setup_forced_release,
1886e04126c7SBarry Carroll .driver_data = atkbd_samsung_forced_release_keys,
1887e04126c7SBarry Carroll },
1888e04126c7SBarry Carroll {
1889c45fc81eSDmitry Torokhov /* Samsung SQ45S70S */
1890157f3a3eSDmitry Torokhov .matches = {
1891157f3a3eSDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1892157f3a3eSDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
1893157f3a3eSDmitry Torokhov },
1894157f3a3eSDmitry Torokhov .callback = atkbd_setup_forced_release,
1895157f3a3eSDmitry Torokhov .driver_data = atkbd_samsung_forced_release_keys,
1896157f3a3eSDmitry Torokhov },
1897157f3a3eSDmitry Torokhov {
1898c45fc81eSDmitry Torokhov /* Fujitsu Amilo PA 1510 */
1899adcb523eSDaniel Mierswa .matches = {
1900adcb523eSDaniel Mierswa DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1901adcb523eSDaniel Mierswa DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
1902adcb523eSDaniel Mierswa },
1903adcb523eSDaniel Mierswa .callback = atkbd_setup_forced_release,
1904000c2a35SHerton Ronaldo Krzesinski .driver_data = atkbd_volume_forced_release_keys,
1905adcb523eSDaniel Mierswa },
19069166d0f6SAdrian Batzill {
1907c45fc81eSDmitry Torokhov /* Fujitsu Amilo Pi 3525 */
1908f0a14de2SSimon Davie .matches = {
1909f0a14de2SSimon Davie DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1910f0a14de2SSimon Davie DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"),
1911f0a14de2SSimon Davie },
1912f0a14de2SSimon Davie .callback = atkbd_setup_forced_release,
1913f0a14de2SSimon Davie .driver_data = atkbd_amilo_pi3525_forced_release_keys,
1914f0a14de2SSimon Davie },
1915f0a14de2SSimon Davie {
1916c45fc81eSDmitry Torokhov /* Fujitsu Amilo Xi 3650 */
19179166d0f6SAdrian Batzill .matches = {
19189166d0f6SAdrian Batzill DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
19199166d0f6SAdrian Batzill DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"),
19209166d0f6SAdrian Batzill },
19219166d0f6SAdrian Batzill .callback = atkbd_setup_forced_release,
19229166d0f6SAdrian Batzill .driver_data = atkbd_amilo_xi3650_forced_release_keys,
19239166d0f6SAdrian Batzill },
1924032e46cbSJerone Young {
1925032e46cbSJerone Young .matches = {
1926032e46cbSJerone Young DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"),
1927032e46cbSJerone Young DMI_MATCH(DMI_PRODUCT_NAME, "TA12"),
1928032e46cbSJerone Young },
1929032e46cbSJerone Young .callback = atkbd_setup_forced_release,
1930032e46cbSJerone Young .driver_data = atkdb_soltech_ta12_forced_release_keys,
1931032e46cbSJerone Young },
1932e5713069SJamie Lentin {
1933c45fc81eSDmitry Torokhov /* OQO Model 01+ */
1934e5713069SJamie Lentin .matches = {
1935e5713069SJamie Lentin DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
1936e5713069SJamie Lentin DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
1937e5713069SJamie Lentin },
1938e5713069SJamie Lentin .callback = atkbd_setup_scancode_fixup,
1939e5713069SJamie Lentin .driver_data = atkbd_oqo_01plus_scancode_fixup,
1940e5713069SJamie Lentin },
19413d725caaSSheng-Liang Song {
19423d725caaSSheng-Liang Song .matches = {
19433d725caaSSheng-Liang Song DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
19443d725caaSSheng-Liang Song },
19453d725caaSSheng-Liang Song .callback = atkbd_deactivate_fixup,
19463d725caaSSheng-Liang Song },
1947554101e3SGiel de Nijs { }
1948554101e3SGiel de Nijs };
19491da177e4SLinus Torvalds
atkbd_init(void)19501da177e4SLinus Torvalds static int __init atkbd_init(void)
19511da177e4SLinus Torvalds {
1952554101e3SGiel de Nijs dmi_check_system(atkbd_dmi_quirk_table);
1953554101e3SGiel de Nijs
1954153a9df0SAkinobu Mita return serio_register_driver(&atkbd_drv);
19551da177e4SLinus Torvalds }
19561da177e4SLinus Torvalds
atkbd_exit(void)19571da177e4SLinus Torvalds static void __exit atkbd_exit(void)
19581da177e4SLinus Torvalds {
19591da177e4SLinus Torvalds serio_unregister_driver(&atkbd_drv);
19601da177e4SLinus Torvalds }
19611da177e4SLinus Torvalds
19621da177e4SLinus Torvalds module_init(atkbd_init);
19631da177e4SLinus Torvalds module_exit(atkbd_exit);
1964