xref: /linux/drivers/input/keyboard/atkbd.c (revision 100e16959c3ca8cb7be788ed3e2c5867481f35f6)
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 
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 
312*100e1695SDmitry Torokhov static struct atkbd *atkbd_from_serio(struct serio *serio)
313*100e1695SDmitry Torokhov {
314*100e1695SDmitry Torokhov 	struct ps2dev *ps2dev = serio_get_drvdata(serio);
315*100e1695SDmitry Torokhov 
316*100e1695SDmitry Torokhov 	return container_of(ps2dev, struct atkbd, ps2dev);
317*100e1695SDmitry Torokhov }
318*100e1695SDmitry Torokhov 
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);
324*100e1695SDmitry 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  */
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  */
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  */
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 /*
4021da177e4SLinus Torvalds  * atkbd_interrupt(). Here takes place processing of data received from
4031da177e4SLinus Torvalds  * the keyboard into events.
4041da177e4SLinus Torvalds  */
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
4077d12e780SDavid Howells 				   unsigned int flags)
4081da177e4SLinus Torvalds {
409*100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
4100ae051a1SDmitry Torokhov 	struct input_dev *dev = atkbd->dev;
4111da177e4SLinus Torvalds 	unsigned int code = data;
412554101e3SGiel de Nijs 	int scroll = 0, hscroll = 0, click = -1;
4131da177e4SLinus Torvalds 	int value;
414f6d65610SDmitry Torokhov 	unsigned short keycode;
4151da177e4SLinus Torvalds 
416a9a1f9c3SDmitry Torokhov 	dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds #if !defined(__i386__) && !defined (__x86_64__)
4191da177e4SLinus Torvalds 	if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
420a9a1f9c3SDmitry Torokhov 		dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
4211da177e4SLinus Torvalds 		serio_write(serio, ATKBD_CMD_RESEND);
422a9a1f9c3SDmitry Torokhov 		atkbd->resend = true;
4231da177e4SLinus Torvalds 		goto out;
4241da177e4SLinus Torvalds 	}
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 	if (!flags && data == ATKBD_RET_ACK)
427a9a1f9c3SDmitry Torokhov 		atkbd->resend = false;
4281da177e4SLinus Torvalds #endif
4291da177e4SLinus Torvalds 
4301da177e4SLinus Torvalds 	if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
4311da177e4SLinus Torvalds 		if  (ps2_handle_ack(&atkbd->ps2dev, data))
4321da177e4SLinus Torvalds 			goto out;
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 	if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
4351da177e4SLinus Torvalds 		if  (ps2_handle_response(&atkbd->ps2dev, data))
4361da177e4SLinus Torvalds 			goto out;
4371da177e4SLinus Torvalds 
438aaca981eSDmitry Torokhov 	pm_wakeup_event(&serio->dev, 0);
439aaca981eSDmitry Torokhov 
4401da177e4SLinus Torvalds 	if (!atkbd->enabled)
4411da177e4SLinus Torvalds 		goto out;
4421da177e4SLinus Torvalds 
4430ae051a1SDmitry Torokhov 	input_event(dev, EV_MSC, MSC_RAW, code);
4441da177e4SLinus Torvalds 
445e5713069SJamie Lentin 	if (atkbd_platform_scancode_fixup)
446e5713069SJamie Lentin 		code = atkbd_platform_scancode_fixup(atkbd, code);
447e5713069SJamie Lentin 
4481da177e4SLinus Torvalds 	if (atkbd->translated) {
4491da177e4SLinus Torvalds 
4500ae051a1SDmitry Torokhov 		if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
4511da177e4SLinus Torvalds 			atkbd->release = code >> 7;
4521da177e4SLinus Torvalds 			code &= 0x7f;
4531da177e4SLinus Torvalds 		}
4541da177e4SLinus Torvalds 
4550ae051a1SDmitry Torokhov 		if (!atkbd->emul)
4560ae051a1SDmitry Torokhov 			atkbd_calculate_xl_bit(atkbd, data);
4571da177e4SLinus Torvalds 	}
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 	switch (code) {
4601da177e4SLinus Torvalds 	case ATKBD_RET_BAT:
461a9a1f9c3SDmitry Torokhov 		atkbd->enabled = false;
462dbc26344SDmitry Torokhov 		serio_reconnect(atkbd->ps2dev.serio);
4631da177e4SLinus Torvalds 		goto out;
4641da177e4SLinus Torvalds 	case ATKBD_RET_EMUL0:
4651da177e4SLinus Torvalds 		atkbd->emul = 1;
4661da177e4SLinus Torvalds 		goto out;
4671da177e4SLinus Torvalds 	case ATKBD_RET_EMUL1:
4681da177e4SLinus Torvalds 		atkbd->emul = 2;
4691da177e4SLinus Torvalds 		goto out;
4701da177e4SLinus Torvalds 	case ATKBD_RET_RELEASE:
471a9a1f9c3SDmitry Torokhov 		atkbd->release = true;
4721da177e4SLinus Torvalds 		goto out;
4730ae051a1SDmitry Torokhov 	case ATKBD_RET_ACK:
4740ae051a1SDmitry Torokhov 	case ATKBD_RET_NAK:
4759f7a60d6SQi Yong 		if (printk_ratelimit())
476a9a1f9c3SDmitry Torokhov 			dev_warn(&serio->dev,
477a9a1f9c3SDmitry Torokhov 				 "Spurious %s on %s. "
478f57fe78eSJesper Juhl 				 "Some program might be trying to access hardware directly.\n",
4790ae051a1SDmitry Torokhov 				 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
4800ae051a1SDmitry Torokhov 		goto out;
4811da177e4SLinus Torvalds 	case ATKBD_RET_ERR:
48286255d9dSDmitry Torokhov 		atkbd->err_count++;
483a9a1f9c3SDmitry Torokhov 		dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
484a9a1f9c3SDmitry Torokhov 			serio->phys);
4851da177e4SLinus Torvalds 		goto out;
4861da177e4SLinus Torvalds 	}
4871da177e4SLinus Torvalds 
4880ae051a1SDmitry Torokhov 	code = atkbd_compat_scancode(atkbd, code);
4890ae051a1SDmitry Torokhov 
4900ae051a1SDmitry Torokhov 	if (atkbd->emul && --atkbd->emul)
4911da177e4SLinus Torvalds 		goto out;
4921da177e4SLinus Torvalds 
4930ae051a1SDmitry Torokhov 	keycode = atkbd->keycode[code];
4941da177e4SLinus Torvalds 
4955447326fSStefan Brüns 	if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
4960ae051a1SDmitry Torokhov 		if (keycode != ATKBD_KEY_NULL)
4970ae051a1SDmitry Torokhov 			input_event(dev, EV_MSC, MSC_SCAN, code);
4980ae051a1SDmitry Torokhov 
4990ae051a1SDmitry Torokhov 	switch (keycode) {
5001da177e4SLinus Torvalds 	case ATKBD_KEY_NULL:
5011da177e4SLinus Torvalds 		break;
5021da177e4SLinus Torvalds 	case ATKBD_KEY_UNKNOWN:
503a9a1f9c3SDmitry Torokhov 		dev_warn(&serio->dev,
504a9a1f9c3SDmitry Torokhov 			 "Unknown key %s (%s set %d, code %#x on %s).\n",
5051da177e4SLinus Torvalds 			 atkbd->release ? "released" : "pressed",
5061da177e4SLinus Torvalds 			 atkbd->translated ? "translated" : "raw",
5071da177e4SLinus Torvalds 			 atkbd->set, code, serio->phys);
508a9a1f9c3SDmitry Torokhov 		dev_warn(&serio->dev,
509a9a1f9c3SDmitry Torokhov 			 "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
5101da177e4SLinus Torvalds 			 code & 0x80 ? "e0" : "", code & 0x7f);
5110ae051a1SDmitry Torokhov 		input_sync(dev);
5121da177e4SLinus Torvalds 		break;
5131da177e4SLinus Torvalds 	case ATKBD_SCR_1:
514a9a1f9c3SDmitry Torokhov 		scroll = 1;
5151da177e4SLinus Torvalds 		break;
5161da177e4SLinus Torvalds 	case ATKBD_SCR_2:
517a9a1f9c3SDmitry Torokhov 		scroll = 2;
5181da177e4SLinus Torvalds 		break;
5191da177e4SLinus Torvalds 	case ATKBD_SCR_4:
520a9a1f9c3SDmitry Torokhov 		scroll = 4;
5211da177e4SLinus Torvalds 		break;
5221da177e4SLinus Torvalds 	case ATKBD_SCR_8:
523a9a1f9c3SDmitry Torokhov 		scroll = 8;
5241da177e4SLinus Torvalds 		break;
5251da177e4SLinus Torvalds 	case ATKBD_SCR_CLICK:
5261da177e4SLinus Torvalds 		click = !atkbd->release;
5271da177e4SLinus Torvalds 		break;
5281da177e4SLinus Torvalds 	case ATKBD_SCR_LEFT:
5291da177e4SLinus Torvalds 		hscroll = -1;
5301da177e4SLinus Torvalds 		break;
5311da177e4SLinus Torvalds 	case ATKBD_SCR_RIGHT:
5321da177e4SLinus Torvalds 		hscroll = 1;
5331da177e4SLinus Torvalds 		break;
5341da177e4SLinus Torvalds 	default:
5350ae051a1SDmitry Torokhov 		if (atkbd->release) {
5360ae051a1SDmitry Torokhov 			value = 0;
5371da177e4SLinus Torvalds 			atkbd->last = 0;
5380ae051a1SDmitry Torokhov 		} else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
5390ae051a1SDmitry Torokhov 			/* Workaround Toshiba laptop multiple keypress */
5400ae051a1SDmitry Torokhov 			value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
5410ae051a1SDmitry Torokhov 		} else {
5421da177e4SLinus Torvalds 			value = 1;
5430ae051a1SDmitry Torokhov 			atkbd->last = code;
5440ae051a1SDmitry Torokhov 			atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
5451da177e4SLinus Torvalds 		}
5461da177e4SLinus Torvalds 
547f8b4c46cSDmitry Torokhov 		input_event(dev, EV_KEY, keycode, value);
5480ae051a1SDmitry Torokhov 		input_sync(dev);
5490ae051a1SDmitry Torokhov 
550554101e3SGiel de Nijs 		if (value && test_bit(code, atkbd->force_release_mask)) {
5515447326fSStefan Brüns 			input_event(dev, EV_MSC, MSC_SCAN, code);
5520ae051a1SDmitry Torokhov 			input_report_key(dev, keycode, 0);
5530ae051a1SDmitry Torokhov 			input_sync(dev);
5540ae051a1SDmitry Torokhov 		}
5551da177e4SLinus Torvalds 	}
5561da177e4SLinus Torvalds 
5571da177e4SLinus Torvalds 	if (atkbd->scroll) {
5581da177e4SLinus Torvalds 		if (click != -1)
5590ae051a1SDmitry Torokhov 			input_report_key(dev, BTN_MIDDLE, click);
560a9a1f9c3SDmitry Torokhov 		input_report_rel(dev, REL_WHEEL,
561a9a1f9c3SDmitry Torokhov 				 atkbd->release ? -scroll : scroll);
5620ae051a1SDmitry Torokhov 		input_report_rel(dev, REL_HWHEEL, hscroll);
5630ae051a1SDmitry Torokhov 		input_sync(dev);
5641da177e4SLinus Torvalds 	}
5651da177e4SLinus Torvalds 
566a9a1f9c3SDmitry Torokhov 	atkbd->release = false;
5671da177e4SLinus Torvalds out:
5681da177e4SLinus Torvalds 	return IRQ_HANDLED;
5691da177e4SLinus Torvalds }
5701da177e4SLinus Torvalds 
5713d0f0fa0SDmitry Torokhov static int atkbd_set_repeat_rate(struct atkbd *atkbd)
5721da177e4SLinus Torvalds {
5731da177e4SLinus Torvalds 	const short period[32] =
5741da177e4SLinus Torvalds 		{ 33,  37,  42,  46,  50,  54,  58,  63,  67,  75,  83,  92, 100, 109, 116, 125,
5751da177e4SLinus Torvalds 		 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
5761da177e4SLinus Torvalds 	const short delay[4] =
5771da177e4SLinus Torvalds 		{ 250, 500, 750, 1000 };
5780d4c8597SDmitry Torokhov 
5793d0f0fa0SDmitry Torokhov 	struct input_dev *dev = atkbd->dev;
5803d0f0fa0SDmitry Torokhov 	unsigned char param;
5813d0f0fa0SDmitry Torokhov 	int i = 0, j = 0;
5823d0f0fa0SDmitry Torokhov 
5833d0f0fa0SDmitry Torokhov 	while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
5843d0f0fa0SDmitry Torokhov 		i++;
5853d0f0fa0SDmitry Torokhov 	dev->rep[REP_PERIOD] = period[i];
5863d0f0fa0SDmitry Torokhov 
5878ea371fbSFlorin Malita 	while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY])
5883d0f0fa0SDmitry Torokhov 		j++;
5893d0f0fa0SDmitry Torokhov 	dev->rep[REP_DELAY] = delay[j];
5903d0f0fa0SDmitry Torokhov 
5913d0f0fa0SDmitry Torokhov 	param = i | (j << 5);
5923d0f0fa0SDmitry Torokhov 	return ps2_command(&atkbd->ps2dev, &param, ATKBD_CMD_SETREP);
5933d0f0fa0SDmitry Torokhov }
5943d0f0fa0SDmitry Torokhov 
5953d0f0fa0SDmitry Torokhov static int atkbd_set_leds(struct atkbd *atkbd)
5963d0f0fa0SDmitry Torokhov {
5970d4c8597SDmitry Torokhov 	struct input_dev *dev = atkbd->dev;
5981da177e4SLinus Torvalds 	unsigned char param[2];
5991da177e4SLinus Torvalds 
6001da177e4SLinus Torvalds 	param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
6011da177e4SLinus Torvalds 		 | (test_bit(LED_NUML,    dev->led) ? 2 : 0)
6021da177e4SLinus Torvalds 		 | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
6033d0f0fa0SDmitry Torokhov 	if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
6043d0f0fa0SDmitry Torokhov 		return -1;
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds 	if (atkbd->extra) {
6071da177e4SLinus Torvalds 		param[0] = 0;
6081da177e4SLinus Torvalds 		param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
6091da177e4SLinus Torvalds 			 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
6101da177e4SLinus Torvalds 			 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
6111da177e4SLinus Torvalds 			 | (test_bit(LED_MISC,    dev->led) ? 0x10 : 0)
6121da177e4SLinus Torvalds 			 | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);
6133d0f0fa0SDmitry Torokhov 		if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS))
6143d0f0fa0SDmitry Torokhov 			return -1;
6151da177e4SLinus Torvalds 	}
6161da177e4SLinus Torvalds 
6173d0f0fa0SDmitry Torokhov 	return 0;
6180d4c8597SDmitry Torokhov }
6190d4c8597SDmitry Torokhov 
6203d0f0fa0SDmitry Torokhov /*
6213d0f0fa0SDmitry Torokhov  * atkbd_event_work() is used to complete processing of events that
6223d0f0fa0SDmitry Torokhov  * can not be processed by input_event() which is often called from
6233d0f0fa0SDmitry Torokhov  * interrupt context.
6243d0f0fa0SDmitry Torokhov  */
6253d0f0fa0SDmitry Torokhov 
62665f27f38SDavid Howells static void atkbd_event_work(struct work_struct *work)
6273d0f0fa0SDmitry Torokhov {
628da4249c9SDmitry Torokhov 	struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);
6293d0f0fa0SDmitry Torokhov 
63059b01513SEric W. Biederman 	mutex_lock(&atkbd->mutex);
6313d0f0fa0SDmitry Torokhov 
63294dfb0d6SDmitry Torokhov 	if (!atkbd->enabled) {
63394dfb0d6SDmitry Torokhov 		/*
63494dfb0d6SDmitry Torokhov 		 * Serio ports are resumed asynchronously so while driver core
63594dfb0d6SDmitry Torokhov 		 * thinks that device is already fully operational in reality
63694dfb0d6SDmitry Torokhov 		 * it may not be ready yet. In this case we need to keep
63794dfb0d6SDmitry Torokhov 		 * rescheduling till reconnect completes.
63894dfb0d6SDmitry Torokhov 		 */
63994dfb0d6SDmitry Torokhov 		schedule_delayed_work(&atkbd->event_work,
64094dfb0d6SDmitry Torokhov 					msecs_to_jiffies(100));
64194dfb0d6SDmitry Torokhov 	} else {
6423d0f0fa0SDmitry Torokhov 		if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
6433d0f0fa0SDmitry Torokhov 			atkbd_set_leds(atkbd);
6443d0f0fa0SDmitry Torokhov 
6453d0f0fa0SDmitry Torokhov 		if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
6463d0f0fa0SDmitry Torokhov 			atkbd_set_repeat_rate(atkbd);
64794dfb0d6SDmitry Torokhov 	}
6483d0f0fa0SDmitry Torokhov 
64959b01513SEric W. Biederman 	mutex_unlock(&atkbd->mutex);
6500d4c8597SDmitry Torokhov }
6510d4c8597SDmitry Torokhov 
6520d4c8597SDmitry Torokhov /*
653da4249c9SDmitry Torokhov  * Schedule switch for execution. We need to throttle requests,
654da4249c9SDmitry Torokhov  * otherwise keyboard may become unresponsive.
655da4249c9SDmitry Torokhov  */
656da4249c9SDmitry Torokhov static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
657da4249c9SDmitry Torokhov {
658da4249c9SDmitry Torokhov 	unsigned long delay = msecs_to_jiffies(50);
659da4249c9SDmitry Torokhov 
660da4249c9SDmitry Torokhov 	if (time_after(jiffies, atkbd->event_jiffies + delay))
661da4249c9SDmitry Torokhov 		delay = 0;
662da4249c9SDmitry Torokhov 
663da4249c9SDmitry Torokhov 	atkbd->event_jiffies = jiffies;
664da4249c9SDmitry Torokhov 	set_bit(event_bit, &atkbd->event_mask);
66559b01513SEric W. Biederman 	mb();
666da4249c9SDmitry Torokhov 	schedule_delayed_work(&atkbd->event_work, delay);
667da4249c9SDmitry Torokhov }
668da4249c9SDmitry Torokhov 
669da4249c9SDmitry Torokhov /*
6700d4c8597SDmitry Torokhov  * Event callback from the input module. Events that change the state of
6710d4c8597SDmitry Torokhov  * the hardware are processed here. If action can not be performed in
6720d4c8597SDmitry Torokhov  * interrupt context it is offloaded to atkbd_event_work.
6730d4c8597SDmitry Torokhov  */
6740d4c8597SDmitry Torokhov 
675da4249c9SDmitry Torokhov static int atkbd_event(struct input_dev *dev,
676da4249c9SDmitry Torokhov 			unsigned int type, unsigned int code, int value)
6770d4c8597SDmitry Torokhov {
678b356872fSDmitry Torokhov 	struct atkbd *atkbd = input_get_drvdata(dev);
6790d4c8597SDmitry Torokhov 
6800d4c8597SDmitry Torokhov 	if (!atkbd->write)
6810d4c8597SDmitry Torokhov 		return -1;
6820d4c8597SDmitry Torokhov 
6830d4c8597SDmitry Torokhov 	switch (type) {
6840d4c8597SDmitry Torokhov 
6850d4c8597SDmitry Torokhov 	case EV_LED:
686da4249c9SDmitry Torokhov 		atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
6870d4c8597SDmitry Torokhov 		return 0;
6880d4c8597SDmitry Torokhov 
6890d4c8597SDmitry Torokhov 	case EV_REP:
690da4249c9SDmitry Torokhov 		if (!atkbd->softrepeat)
691da4249c9SDmitry Torokhov 			atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
6921da177e4SLinus Torvalds 		return 0;
6931da177e4SLinus Torvalds 
694a9a1f9c3SDmitry Torokhov 	default:
6951da177e4SLinus Torvalds 		return -1;
6961da177e4SLinus Torvalds 	}
697a9a1f9c3SDmitry Torokhov }
6981da177e4SLinus Torvalds 
6991da177e4SLinus Torvalds /*
7001da177e4SLinus Torvalds  * atkbd_enable() signals that interrupt handler is allowed to
7011da177e4SLinus Torvalds  * generate input events.
7021da177e4SLinus Torvalds  */
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds static inline void atkbd_enable(struct atkbd *atkbd)
7051da177e4SLinus Torvalds {
7061da177e4SLinus Torvalds 	serio_pause_rx(atkbd->ps2dev.serio);
707a9a1f9c3SDmitry Torokhov 	atkbd->enabled = true;
7081da177e4SLinus Torvalds 	serio_continue_rx(atkbd->ps2dev.serio);
7091da177e4SLinus Torvalds }
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds /*
7121da177e4SLinus Torvalds  * atkbd_disable() tells input handler that all incoming data except
7131da177e4SLinus Torvalds  * for ACKs and command response should be dropped.
7141da177e4SLinus Torvalds  */
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds static inline void atkbd_disable(struct atkbd *atkbd)
7171da177e4SLinus Torvalds {
7181da177e4SLinus Torvalds 	serio_pause_rx(atkbd->ps2dev.serio);
719a9a1f9c3SDmitry Torokhov 	atkbd->enabled = false;
7201da177e4SLinus Torvalds 	serio_continue_rx(atkbd->ps2dev.serio);
7211da177e4SLinus Torvalds }
7221da177e4SLinus Torvalds 
723be2d7e42SShawn Nematbakhsh static int atkbd_activate(struct atkbd *atkbd)
724be2d7e42SShawn Nematbakhsh {
725be2d7e42SShawn Nematbakhsh 	struct ps2dev *ps2dev = &atkbd->ps2dev;
726be2d7e42SShawn Nematbakhsh 
727be2d7e42SShawn Nematbakhsh /*
728be2d7e42SShawn Nematbakhsh  * Enable the keyboard to receive keystrokes.
729be2d7e42SShawn Nematbakhsh  */
730be2d7e42SShawn Nematbakhsh 
731be2d7e42SShawn Nematbakhsh 	if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
732be2d7e42SShawn Nematbakhsh 		dev_err(&ps2dev->serio->dev,
733be2d7e42SShawn Nematbakhsh 			"Failed to enable keyboard on %s\n",
734be2d7e42SShawn Nematbakhsh 			ps2dev->serio->phys);
735be2d7e42SShawn Nematbakhsh 		return -1;
736be2d7e42SShawn Nematbakhsh 	}
737be2d7e42SShawn Nematbakhsh 
738be2d7e42SShawn Nematbakhsh 	return 0;
739be2d7e42SShawn Nematbakhsh }
740be2d7e42SShawn Nematbakhsh 
741be2d7e42SShawn Nematbakhsh /*
742be2d7e42SShawn Nematbakhsh  * atkbd_deactivate() resets and disables the keyboard from sending
743be2d7e42SShawn Nematbakhsh  * keystrokes.
744be2d7e42SShawn Nematbakhsh  */
745be2d7e42SShawn Nematbakhsh 
746be2d7e42SShawn Nematbakhsh static void atkbd_deactivate(struct atkbd *atkbd)
747be2d7e42SShawn Nematbakhsh {
748be2d7e42SShawn Nematbakhsh 	struct ps2dev *ps2dev = &atkbd->ps2dev;
749be2d7e42SShawn Nematbakhsh 
750be2d7e42SShawn Nematbakhsh 	if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS))
751be2d7e42SShawn Nematbakhsh 		dev_err(&ps2dev->serio->dev,
752be2d7e42SShawn Nematbakhsh 			"Failed to deactivate keyboard on %s\n",
753be2d7e42SShawn Nematbakhsh 			ps2dev->serio->phys);
754be2d7e42SShawn Nematbakhsh }
755be2d7e42SShawn Nematbakhsh 
7561da177e4SLinus Torvalds /*
7571da177e4SLinus Torvalds  * atkbd_probe() probes for an AT keyboard on a serio port.
7581da177e4SLinus Torvalds  */
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds static int atkbd_probe(struct atkbd *atkbd)
7611da177e4SLinus Torvalds {
7621da177e4SLinus Torvalds 	struct ps2dev *ps2dev = &atkbd->ps2dev;
7631da177e4SLinus Torvalds 	unsigned char param[2];
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds /*
7661da177e4SLinus Torvalds  * Some systems, where the bit-twiddling when testing the io-lines of the
7671da177e4SLinus Torvalds  * controller may confuse the keyboard need a full reset of the keyboard. On
7681da177e4SLinus Torvalds  * these systems the BIOS also usually doesn't do it for us.
7691da177e4SLinus Torvalds  */
7701da177e4SLinus Torvalds 
7711da177e4SLinus Torvalds 	if (atkbd_reset)
7721da177e4SLinus Torvalds 		if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
773a9a1f9c3SDmitry Torokhov 			dev_warn(&ps2dev->serio->dev,
774a9a1f9c3SDmitry Torokhov 				 "keyboard reset failed on %s\n",
775a9a1f9c3SDmitry Torokhov 				 ps2dev->serio->phys);
7761da177e4SLinus Torvalds 
7771da177e4SLinus Torvalds /*
7781da177e4SLinus Torvalds  * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
7791da177e4SLinus Torvalds  * Some keyboards report different values, but the first byte is always 0xab or
7801da177e4SLinus Torvalds  * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this
7811da177e4SLinus Torvalds  * should make sure we don't try to set the LEDs on it.
7821da177e4SLinus Torvalds  */
7831da177e4SLinus Torvalds 
7841da177e4SLinus Torvalds 	param[0] = param[1] = 0xa5;	/* initialize with invalid values */
7851da177e4SLinus Torvalds 	if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
7861da177e4SLinus Torvalds 
7871da177e4SLinus Torvalds /*
7881da177e4SLinus Torvalds  * If the get ID command failed, we check if we can at least set the LEDs on
7891da177e4SLinus Torvalds  * the keyboard. This should work on every keyboard out there. It also turns
7901da177e4SLinus Torvalds  * the LEDs off, which we want anyway.
7911da177e4SLinus Torvalds  */
7921da177e4SLinus Torvalds 		param[0] = 0;
7931da177e4SLinus Torvalds 		if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
7941da177e4SLinus Torvalds 			return -1;
7951da177e4SLinus Torvalds 		atkbd->id = 0xabba;
7961da177e4SLinus Torvalds 		return 0;
7971da177e4SLinus Torvalds 	}
7981da177e4SLinus Torvalds 
7999807879bSDmitry Torokhov 	if (!ps2_is_keyboard_id(param[0]))
8001da177e4SLinus Torvalds 		return -1;
8011da177e4SLinus Torvalds 
8021da177e4SLinus Torvalds 	atkbd->id = (param[0] << 8) | param[1];
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds 	if (atkbd->id == 0xaca1 && atkbd->translated) {
805a9a1f9c3SDmitry Torokhov 		dev_err(&ps2dev->serio->dev,
806236d6a77SDmitry Torokhov 			"NCD terminal keyboards are only supported on non-translating controllers. "
807a9a1f9c3SDmitry Torokhov 			"Use i8042.direct=1 to disable translation.\n");
8081da177e4SLinus Torvalds 		return -1;
8091da177e4SLinus Torvalds 	}
8101da177e4SLinus Torvalds 
811be2d7e42SShawn Nematbakhsh /*
812be2d7e42SShawn Nematbakhsh  * Make sure nothing is coming from the keyboard and disturbs our
813be2d7e42SShawn Nematbakhsh  * internal state.
814be2d7e42SShawn Nematbakhsh  */
8153d725caaSSheng-Liang Song 	if (!atkbd_skip_deactivate)
816be2d7e42SShawn Nematbakhsh 		atkbd_deactivate(atkbd);
817be2d7e42SShawn Nematbakhsh 
8181da177e4SLinus Torvalds 	return 0;
8191da177e4SLinus Torvalds }
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds /*
8221da177e4SLinus Torvalds  * atkbd_select_set checks if a keyboard has a working Set 3 support, and
8231da177e4SLinus Torvalds  * sets it into that. Unfortunately there are keyboards that can be switched
8241da177e4SLinus Torvalds  * to Set 3, but don't work well in that (BTC Multimedia ...)
8251da177e4SLinus Torvalds  */
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
8281da177e4SLinus Torvalds {
8291da177e4SLinus Torvalds 	struct ps2dev *ps2dev = &atkbd->ps2dev;
8301da177e4SLinus Torvalds 	unsigned char param[2];
8311da177e4SLinus Torvalds 
832a9a1f9c3SDmitry Torokhov 	atkbd->extra = false;
8331da177e4SLinus Torvalds /*
8341da177e4SLinus Torvalds  * For known special keyboards we can go ahead and set the correct set.
8351da177e4SLinus Torvalds  * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
8361da177e4SLinus Torvalds  * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards.
8371da177e4SLinus Torvalds  */
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	if (atkbd->translated)
8401da177e4SLinus Torvalds 		return 2;
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	if (atkbd->id == 0xaca1) {
8431da177e4SLinus Torvalds 		param[0] = 3;
8441da177e4SLinus Torvalds 		ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
8451da177e4SLinus Torvalds 		return 3;
8461da177e4SLinus Torvalds 	}
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	if (allow_extra) {
8491da177e4SLinus Torvalds 		param[0] = 0x71;
8501da177e4SLinus Torvalds 		if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
851a9a1f9c3SDmitry Torokhov 			atkbd->extra = true;
8521da177e4SLinus Torvalds 			return 2;
8531da177e4SLinus Torvalds 		}
8541da177e4SLinus Torvalds 	}
8551da177e4SLinus Torvalds 
8568c5188b6SBenjamin LaHaise 	if (atkbd_terminal) {
8578c5188b6SBenjamin LaHaise 		ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB);
8588c5188b6SBenjamin LaHaise 		return 3;
8598c5188b6SBenjamin LaHaise 	}
8608c5188b6SBenjamin LaHaise 
8611da177e4SLinus Torvalds 	if (target_set != 3)
8621da177e4SLinus Torvalds 		return 2;
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds 	if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {
8651da177e4SLinus Torvalds 		atkbd->id = param[0] << 8 | param[1];
8661da177e4SLinus Torvalds 		return 2;
8671da177e4SLinus Torvalds 	}
8681da177e4SLinus Torvalds 
8691da177e4SLinus Torvalds 	param[0] = 3;
8701da177e4SLinus Torvalds 	if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
8711da177e4SLinus Torvalds 		return 2;
8721da177e4SLinus Torvalds 
8731da177e4SLinus Torvalds 	param[0] = 0;
8741da177e4SLinus Torvalds 	if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
8751da177e4SLinus Torvalds 		return 2;
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds 	if (param[0] != 3) {
8781da177e4SLinus Torvalds 		param[0] = 2;
8791da177e4SLinus Torvalds 		if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
8801da177e4SLinus Torvalds 			return 2;
8811da177e4SLinus Torvalds 	}
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds 	ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds 	return 3;
8861da177e4SLinus Torvalds }
8871da177e4SLinus Torvalds 
888fc0eb28cSDmitry Torokhov static int atkbd_reset_state(struct atkbd *atkbd)
889fc0eb28cSDmitry Torokhov {
890fc0eb28cSDmitry Torokhov         struct ps2dev *ps2dev = &atkbd->ps2dev;
891fc0eb28cSDmitry Torokhov 	unsigned char param[1];
892fc0eb28cSDmitry Torokhov 
893fc0eb28cSDmitry Torokhov /*
894fc0eb28cSDmitry Torokhov  * Set the LEDs to a predefined state (all off).
895fc0eb28cSDmitry Torokhov  */
896fc0eb28cSDmitry Torokhov 
897fc0eb28cSDmitry Torokhov 	param[0] = 0;
898fc0eb28cSDmitry Torokhov 	if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
899fc0eb28cSDmitry Torokhov 		return -1;
900fc0eb28cSDmitry Torokhov 
901fc0eb28cSDmitry Torokhov /*
902fc0eb28cSDmitry Torokhov  * Set autorepeat to fastest possible.
903fc0eb28cSDmitry Torokhov  */
904fc0eb28cSDmitry Torokhov 
905fc0eb28cSDmitry Torokhov 	param[0] = 0;
906fc0eb28cSDmitry Torokhov 	if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
907fc0eb28cSDmitry Torokhov 		return -1;
908fc0eb28cSDmitry Torokhov 
909fc0eb28cSDmitry Torokhov 	return 0;
910fc0eb28cSDmitry Torokhov }
911fc0eb28cSDmitry Torokhov 
9121da177e4SLinus Torvalds /*
9131da177e4SLinus Torvalds  * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
9141da177e4SLinus Torvalds  * reboot.
9151da177e4SLinus Torvalds  */
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds static void atkbd_cleanup(struct serio *serio)
9181da177e4SLinus Torvalds {
919*100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
92057f5b159SDmitry Torokhov 
92157f5b159SDmitry Torokhov 	atkbd_disable(atkbd);
9224a299bf5SDmitry Torokhov 	ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF);
9231da177e4SLinus Torvalds }
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds /*
9271da177e4SLinus Torvalds  * atkbd_disconnect() closes and frees.
9281da177e4SLinus Torvalds  */
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds static void atkbd_disconnect(struct serio *serio)
9311da177e4SLinus Torvalds {
932*100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
9331da177e4SLinus Torvalds 
9341da177e4SLinus Torvalds 	atkbd_disable(atkbd);
9351da177e4SLinus Torvalds 
9360ef7a26aSDmitry Torokhov 	input_unregister_device(atkbd->dev);
9370ef7a26aSDmitry Torokhov 
9380ef7a26aSDmitry Torokhov 	/*
9390ef7a26aSDmitry Torokhov 	 * Make sure we don't have a command in flight.
9400ef7a26aSDmitry Torokhov 	 * Note that since atkbd->enabled is false event work will keep
9410ef7a26aSDmitry Torokhov 	 * rescheduling itself until it gets canceled and will not try
9420ef7a26aSDmitry Torokhov 	 * accessing freed input device or serio port.
9430ef7a26aSDmitry Torokhov 	 */
944d6d79a78SJiri Pirko 	cancel_delayed_work_sync(&atkbd->event_work);
9451da177e4SLinus Torvalds 
9461da177e4SLinus Torvalds 	serio_close(serio);
9471da177e4SLinus Torvalds 	serio_set_drvdata(serio, NULL);
9481da177e4SLinus Torvalds 	kfree(atkbd);
9491da177e4SLinus Torvalds }
9501da177e4SLinus Torvalds 
951554101e3SGiel de Nijs /*
95239191698SDaniel Mierswa  * generate release events for the keycodes given in data
95339191698SDaniel Mierswa  */
95439191698SDaniel Mierswa static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd,
95539191698SDaniel Mierswa 						const void *data)
95639191698SDaniel Mierswa {
95739191698SDaniel Mierswa 	const unsigned int *keys = data;
95839191698SDaniel Mierswa 	unsigned int i;
95939191698SDaniel Mierswa 
96039191698SDaniel Mierswa 	if (atkbd->set == 2)
96139191698SDaniel Mierswa 		for (i = 0; keys[i] != -1U; i++)
96239191698SDaniel Mierswa 			__set_bit(keys[i], atkbd->force_release_mask);
96339191698SDaniel Mierswa }
96439191698SDaniel Mierswa 
96539191698SDaniel Mierswa /*
96661579ba8SMatthew Garrett  * Most special keys (Fn+F?) on Dell laptops do not generate release
967554101e3SGiel de Nijs  * events so we have to do it ourselves.
968554101e3SGiel de Nijs  */
96939191698SDaniel Mierswa static unsigned int atkbd_dell_laptop_forced_release_keys[] = {
97039191698SDaniel Mierswa 	0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U
971554101e3SGiel de Nijs };
9721da177e4SLinus Torvalds 
9731da177e4SLinus Torvalds /*
9745a54c011SJiri Kosina  * Perform fixup for HP system that doesn't generate release
9755a54c011SJiri Kosina  * for its video switch
9765a54c011SJiri Kosina  */
97739191698SDaniel Mierswa static unsigned int atkbd_hp_forced_release_keys[] = {
97839191698SDaniel Mierswa 	0x94, -1U
9795a54c011SJiri Kosina };
9805a54c011SJiri Kosina 
9815a54c011SJiri Kosina /*
982e04126c7SBarry Carroll  * Samsung NC10,NC20 with Fn+F? key release not working
9834200844bSStuart Hopkins  */
98439191698SDaniel Mierswa static unsigned int atkbd_samsung_forced_release_keys[] = {
98539191698SDaniel Mierswa 	0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U
9864200844bSStuart Hopkins };
9874200844bSStuart Hopkins 
9884200844bSStuart Hopkins /*
989f0a14de2SSimon Davie  * Amilo Pi 3525 key release for Fn+Volume keys not working
990f0a14de2SSimon Davie  */
991f0a14de2SSimon Davie static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = {
992f0a14de2SSimon Davie 	0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U
993f0a14de2SSimon Davie };
994f0a14de2SSimon Davie 
995f0a14de2SSimon Davie /*
9969166d0f6SAdrian Batzill  * Amilo Xi 3650 key release for light touch bar not working
9979166d0f6SAdrian Batzill  */
9989166d0f6SAdrian Batzill static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = {
9999166d0f6SAdrian Batzill 	0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U
10009166d0f6SAdrian Batzill };
10019166d0f6SAdrian Batzill 
10029166d0f6SAdrian Batzill /*
1003032e46cbSJerone Young  * Soltech TA12 system with broken key release on volume keys and mute key
1004032e46cbSJerone Young  */
1005032e46cbSJerone Young static unsigned int atkdb_soltech_ta12_forced_release_keys[] = {
1006032e46cbSJerone Young 	0xa0, 0xae, 0xb0, -1U
1007032e46cbSJerone Young };
1008032e46cbSJerone Young 
1009032e46cbSJerone Young /*
1010000c2a35SHerton Ronaldo Krzesinski  * Many notebooks don't send key release event for volume up/down
1011000c2a35SHerton Ronaldo Krzesinski  * keys, with key list below common among them
1012000c2a35SHerton Ronaldo Krzesinski  */
1013000c2a35SHerton Ronaldo Krzesinski static unsigned int atkbd_volume_forced_release_keys[] = {
1014000c2a35SHerton Ronaldo Krzesinski 	0xae, 0xb0, -1U
1015000c2a35SHerton Ronaldo Krzesinski };
1016000c2a35SHerton Ronaldo Krzesinski 
1017000c2a35SHerton Ronaldo Krzesinski /*
1018e5713069SJamie Lentin  * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas
1019e5713069SJamie Lentin  * they should be generating e4-e6 (0x80 | code).
1020e5713069SJamie Lentin  */
1021e5713069SJamie Lentin static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
1022e5713069SJamie Lentin 						    unsigned int code)
1023e5713069SJamie Lentin {
1024e5713069SJamie Lentin 	if (atkbd->translated && atkbd->emul == 1 &&
1025e5713069SJamie Lentin 	    (code == 0x64 || code == 0x65 || code == 0x66)) {
1026e5713069SJamie Lentin 		atkbd->emul = 0;
1027e5713069SJamie Lentin 		code |= 0x80;
1028e5713069SJamie Lentin 	}
1029e5713069SJamie Lentin 
1030e5713069SJamie Lentin 	return code;
1031e5713069SJamie Lentin }
1032e5713069SJamie Lentin 
10339d17ad23SRajat Jain static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
10349d17ad23SRajat Jain {
10359d17ad23SRajat Jain 	struct device *dev = &atkbd->ps2dev.serio->dev;
10369d17ad23SRajat Jain 	int i, n;
10379d17ad23SRajat Jain 	u32 *ptr;
10389d17ad23SRajat Jain 	u16 scancode, keycode;
10399d17ad23SRajat Jain 
10409d17ad23SRajat Jain 	/* Parse "linux,keymap" property */
10419d17ad23SRajat Jain 	n = device_property_count_u32(dev, "linux,keymap");
10429d17ad23SRajat Jain 	if (n <= 0 || n > ATKBD_KEYMAP_SIZE)
10439d17ad23SRajat Jain 		return -ENXIO;
10449d17ad23SRajat Jain 
10459d17ad23SRajat Jain 	ptr = kcalloc(n, sizeof(u32), GFP_KERNEL);
10469d17ad23SRajat Jain 	if (!ptr)
10479d17ad23SRajat Jain 		return -ENOMEM;
10489d17ad23SRajat Jain 
10499d17ad23SRajat Jain 	if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) {
10509d17ad23SRajat Jain 		dev_err(dev, "problem parsing FW keymap property\n");
10519d17ad23SRajat Jain 		kfree(ptr);
10529d17ad23SRajat Jain 		return -EINVAL;
10539d17ad23SRajat Jain 	}
10549d17ad23SRajat Jain 
10559d17ad23SRajat Jain 	memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
10569d17ad23SRajat Jain 	for (i = 0; i < n; i++) {
10579d17ad23SRajat Jain 		scancode = SCANCODE(ptr[i]);
10589d17ad23SRajat Jain 		keycode = KEYCODE(ptr[i]);
10599d17ad23SRajat Jain 		atkbd->keycode[scancode] = keycode;
10609d17ad23SRajat Jain 	}
10619d17ad23SRajat Jain 
10629d17ad23SRajat Jain 	kfree(ptr);
10639d17ad23SRajat Jain 	return 0;
10649d17ad23SRajat Jain }
10659d17ad23SRajat Jain 
1066e5713069SJamie Lentin /*
10673c42f0c3SDmitry Torokhov  * atkbd_set_keycode_table() initializes keyboard's keycode table
10681da177e4SLinus Torvalds  * according to the selected scancode set
10691da177e4SLinus Torvalds  */
10701da177e4SLinus Torvalds 
10711da177e4SLinus Torvalds static void atkbd_set_keycode_table(struct atkbd *atkbd)
10721da177e4SLinus Torvalds {
10739d17ad23SRajat Jain 	struct device *dev = &atkbd->ps2dev.serio->dev;
1074554101e3SGiel de Nijs 	unsigned int scancode;
10751da177e4SLinus Torvalds 	int i, j;
10761da177e4SLinus Torvalds 
10771da177e4SLinus Torvalds 	memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
10781ba36e11SDmitry Torokhov 	bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
10791da177e4SLinus Torvalds 
10809d17ad23SRajat Jain 	if (!atkbd_get_keymap_from_fwnode(atkbd)) {
10819d17ad23SRajat Jain 		dev_dbg(dev, "Using FW keymap\n");
10829d17ad23SRajat Jain 	} else if (atkbd->translated) {
10831da177e4SLinus Torvalds 		for (i = 0; i < 128; i++) {
1084554101e3SGiel de Nijs 			scancode = atkbd_unxlate_table[i];
1085554101e3SGiel de Nijs 			atkbd->keycode[i] = atkbd_set2_keycode[scancode];
1086554101e3SGiel de Nijs 			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80];
10871da177e4SLinus Torvalds 			if (atkbd->scroll)
10881da177e4SLinus Torvalds 				for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
1089554101e3SGiel de Nijs 					if ((scancode | 0x80) == atkbd_scroll_keys[j].set2)
10901da177e4SLinus Torvalds 						atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
10911da177e4SLinus Torvalds 		}
10921da177e4SLinus Torvalds 	} else if (atkbd->set == 3) {
10931da177e4SLinus Torvalds 		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
10941da177e4SLinus Torvalds 	} else {
10951da177e4SLinus Torvalds 		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
10961da177e4SLinus Torvalds 
10971da177e4SLinus Torvalds 		if (atkbd->scroll)
1098554101e3SGiel de Nijs 			for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) {
1099554101e3SGiel de Nijs 				scancode = atkbd_scroll_keys[i].set2;
1100554101e3SGiel de Nijs 				atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode;
1101554101e3SGiel de Nijs 		}
11021da177e4SLinus Torvalds 	}
11030ae051a1SDmitry Torokhov 
1104554101e3SGiel de Nijs /*
1105554101e3SGiel de Nijs  * HANGEUL and HANJA keys do not send release events so we need to
1106554101e3SGiel de Nijs  * generate such events ourselves
1107554101e3SGiel de Nijs  */
1108554101e3SGiel de Nijs 	scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL);
1109554101e3SGiel de Nijs 	atkbd->keycode[scancode] = KEY_HANGEUL;
1110554101e3SGiel de Nijs 	__set_bit(scancode, atkbd->force_release_mask);
1111554101e3SGiel de Nijs 
1112554101e3SGiel de Nijs 	scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA);
1113554101e3SGiel de Nijs 	atkbd->keycode[scancode] = KEY_HANJA;
1114554101e3SGiel de Nijs 	__set_bit(scancode, atkbd->force_release_mask);
1115554101e3SGiel de Nijs 
1116554101e3SGiel de Nijs /*
1117554101e3SGiel de Nijs  * Perform additional fixups
1118554101e3SGiel de Nijs  */
1119554101e3SGiel de Nijs 	if (atkbd_platform_fixup)
112039191698SDaniel Mierswa 		atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data);
11211da177e4SLinus Torvalds }
11221da177e4SLinus Torvalds 
11231da177e4SLinus Torvalds /*
11241da177e4SLinus Torvalds  * atkbd_set_device_attrs() sets up keyboard's input device structure
11251da177e4SLinus Torvalds  */
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds static void atkbd_set_device_attrs(struct atkbd *atkbd)
11281da177e4SLinus Torvalds {
11293c42f0c3SDmitry Torokhov 	struct input_dev *input_dev = atkbd->dev;
11301da177e4SLinus Torvalds 	int i;
11311da177e4SLinus Torvalds 
11323c42f0c3SDmitry Torokhov 	if (atkbd->extra)
1133ea08c6faSDmitry Torokhov 		snprintf(atkbd->name, sizeof(atkbd->name),
1134ea08c6faSDmitry Torokhov 			 "AT Set 2 Extra keyboard");
11353c42f0c3SDmitry Torokhov 	else
1136ea08c6faSDmitry Torokhov 		snprintf(atkbd->name, sizeof(atkbd->name),
1137ea08c6faSDmitry Torokhov 			 "AT %s Set %d keyboard",
11383c42f0c3SDmitry Torokhov 			 atkbd->translated ? "Translated" : "Raw", atkbd->set);
11391da177e4SLinus Torvalds 
1140ea08c6faSDmitry Torokhov 	snprintf(atkbd->phys, sizeof(atkbd->phys),
1141ea08c6faSDmitry Torokhov 		 "%s/input0", atkbd->ps2dev.serio->phys);
11421da177e4SLinus Torvalds 
11433c42f0c3SDmitry Torokhov 	input_dev->name = atkbd->name;
11443c42f0c3SDmitry Torokhov 	input_dev->phys = atkbd->phys;
11453c42f0c3SDmitry Torokhov 	input_dev->id.bustype = BUS_I8042;
11463c42f0c3SDmitry Torokhov 	input_dev->id.vendor = 0x0001;
11473c42f0c3SDmitry Torokhov 	input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
11483c42f0c3SDmitry Torokhov 	input_dev->id.version = atkbd->id;
11493c42f0c3SDmitry Torokhov 	input_dev->event = atkbd_event;
1150469ba4dfSDmitry Torokhov 	input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
11511da177e4SLinus Torvalds 
1152b356872fSDmitry Torokhov 	input_set_drvdata(input_dev, atkbd);
1153b356872fSDmitry Torokhov 
11547b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
11557b19ada2SJiri Slaby 		BIT_MASK(EV_MSC);
11561da177e4SLinus Torvalds 
11571da177e4SLinus Torvalds 	if (atkbd->write) {
11587b19ada2SJiri Slaby 		input_dev->evbit[0] |= BIT_MASK(EV_LED);
11597b19ada2SJiri Slaby 		input_dev->ledbit[0] = BIT_MASK(LED_NUML) |
11607b19ada2SJiri Slaby 			BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL);
11611da177e4SLinus Torvalds 	}
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds 	if (atkbd->extra)
11647b19ada2SJiri Slaby 		input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) |
11657b19ada2SJiri Slaby 			BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) |
11667b19ada2SJiri Slaby 			BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC);
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds 	if (!atkbd->softrepeat) {
11693c42f0c3SDmitry Torokhov 		input_dev->rep[REP_DELAY] = 250;
11703c42f0c3SDmitry Torokhov 		input_dev->rep[REP_PERIOD] = 33;
11711da177e4SLinus Torvalds 	}
11721da177e4SLinus Torvalds 
11737b19ada2SJiri Slaby 	input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) :
11747b19ada2SJiri Slaby 		BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);
11751da177e4SLinus Torvalds 
11761da177e4SLinus Torvalds 	if (atkbd->scroll) {
11777b19ada2SJiri Slaby 		input_dev->evbit[0] |= BIT_MASK(EV_REL);
11787b19ada2SJiri Slaby 		input_dev->relbit[0] = BIT_MASK(REL_WHEEL) |
11797b19ada2SJiri Slaby 			BIT_MASK(REL_HWHEEL);
1180f6d65610SDmitry Torokhov 		__set_bit(BTN_MIDDLE, input_dev->keybit);
11811da177e4SLinus Torvalds 	}
11821da177e4SLinus Torvalds 
11833c42f0c3SDmitry Torokhov 	input_dev->keycode = atkbd->keycode;
1184f6d65610SDmitry Torokhov 	input_dev->keycodesize = sizeof(unsigned short);
11853c42f0c3SDmitry Torokhov 	input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
11861da177e4SLinus Torvalds 
11874b70858bSDmitry Torokhov 	for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
11884b70858bSDmitry Torokhov 		if (atkbd->keycode[i] != KEY_RESERVED &&
11894b70858bSDmitry Torokhov 		    atkbd->keycode[i] != ATKBD_KEY_NULL &&
11904b70858bSDmitry Torokhov 		    atkbd->keycode[i] < ATKBD_SPECIAL) {
1191f6d65610SDmitry Torokhov 			__set_bit(atkbd->keycode[i], input_dev->keybit);
11921da177e4SLinus Torvalds 		}
11934b70858bSDmitry Torokhov 	}
11944b70858bSDmitry Torokhov }
11951da177e4SLinus Torvalds 
11968f7b057aSRajat Jain static void atkbd_parse_fwnode_data(struct serio *serio)
11978f7b057aSRajat Jain {
1198*100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
11998f7b057aSRajat Jain 	struct device *dev = &serio->dev;
12008f7b057aSRajat Jain 	int n;
12018f7b057aSRajat Jain 
12028f7b057aSRajat Jain 	/* Parse "function-row-physmap" property */
12038f7b057aSRajat Jain 	n = device_property_count_u32(dev, "function-row-physmap");
120445ceaf14SStephen Boyd 	if (n > 0 && n <= VIVALDI_MAX_FUNCTION_ROW_KEYS &&
12058f7b057aSRajat Jain 	    !device_property_read_u32_array(dev, "function-row-physmap",
120645ceaf14SStephen Boyd 					    atkbd->vdata.function_row_physmap,
120745ceaf14SStephen Boyd 					    n)) {
120845ceaf14SStephen Boyd 		atkbd->vdata.num_function_row_keys = n;
12098f7b057aSRajat Jain 		dev_dbg(dev, "FW reported %d function-row key locations\n", n);
12108f7b057aSRajat Jain 	}
12118f7b057aSRajat Jain }
12128f7b057aSRajat Jain 
12131da177e4SLinus Torvalds /*
12141da177e4SLinus Torvalds  * atkbd_connect() is called when the serio module finds an interface
12151da177e4SLinus Torvalds  * that isn't handled yet by an appropriate device driver. We check if
12161da177e4SLinus Torvalds  * there is an AT keyboard out there and if yes, we register ourselves
12171da177e4SLinus Torvalds  * to the input module.
12181da177e4SLinus Torvalds  */
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
12211da177e4SLinus Torvalds {
12221da177e4SLinus Torvalds 	struct atkbd *atkbd;
12233c42f0c3SDmitry Torokhov 	struct input_dev *dev;
12243c42f0c3SDmitry Torokhov 	int err = -ENOMEM;
12251da177e4SLinus Torvalds 
12263c42f0c3SDmitry Torokhov 	atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL);
12273c42f0c3SDmitry Torokhov 	dev = input_allocate_device();
12283c42f0c3SDmitry Torokhov 	if (!atkbd || !dev)
12292b03b60eSDmitry Torokhov 		goto fail1;
12301da177e4SLinus Torvalds 
12313c42f0c3SDmitry Torokhov 	atkbd->dev = dev;
12321da177e4SLinus Torvalds 	ps2_init(&atkbd->ps2dev, serio);
1233da4249c9SDmitry Torokhov 	INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
123459b01513SEric W. Biederman 	mutex_init(&atkbd->mutex);
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds 	switch (serio->id.type) {
12371da177e4SLinus Torvalds 
12381da177e4SLinus Torvalds 	case SERIO_8042_XL:
1239a9a1f9c3SDmitry Torokhov 		atkbd->translated = true;
12406f49c4f5SGustavo A. R. Silva 		fallthrough;
1241a9a1f9c3SDmitry Torokhov 
12421da177e4SLinus Torvalds 	case SERIO_8042:
12431da177e4SLinus Torvalds 		if (serio->write)
1244a9a1f9c3SDmitry Torokhov 			atkbd->write = true;
12451da177e4SLinus Torvalds 		break;
12461da177e4SLinus Torvalds 	}
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds 	atkbd->softraw = atkbd_softraw;
12491da177e4SLinus Torvalds 	atkbd->softrepeat = atkbd_softrepeat;
12501da177e4SLinus Torvalds 	atkbd->scroll = atkbd_scroll;
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds 	if (atkbd->softrepeat)
1253a9a1f9c3SDmitry Torokhov 		atkbd->softraw = true;
12541da177e4SLinus Torvalds 
12551da177e4SLinus Torvalds 	serio_set_drvdata(serio, atkbd);
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	err = serio_open(serio, drv);
12583c42f0c3SDmitry Torokhov 	if (err)
12592b03b60eSDmitry Torokhov 		goto fail2;
12601da177e4SLinus Torvalds 
12611da177e4SLinus Torvalds 	if (atkbd->write) {
12621da177e4SLinus Torvalds 
12631da177e4SLinus Torvalds 		if (atkbd_probe(atkbd)) {
12643c42f0c3SDmitry Torokhov 			err = -ENODEV;
12652b03b60eSDmitry Torokhov 			goto fail3;
12661da177e4SLinus Torvalds 		}
12671da177e4SLinus Torvalds 
12681da177e4SLinus Torvalds 		atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
1269fc0eb28cSDmitry Torokhov 		atkbd_reset_state(atkbd);
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds 	} else {
12721da177e4SLinus Torvalds 		atkbd->set = 2;
12731da177e4SLinus Torvalds 		atkbd->id = 0xab00;
12741da177e4SLinus Torvalds 	}
12751da177e4SLinus Torvalds 
12768f7b057aSRajat Jain 	atkbd_parse_fwnode_data(serio);
12778f7b057aSRajat Jain 
12781da177e4SLinus Torvalds 	atkbd_set_keycode_table(atkbd);
12791da177e4SLinus Torvalds 	atkbd_set_device_attrs(atkbd);
12801da177e4SLinus Torvalds 
12811da177e4SLinus Torvalds 	atkbd_enable(atkbd);
1282be2d7e42SShawn Nematbakhsh 	if (serio->write)
1283be2d7e42SShawn Nematbakhsh 		atkbd_activate(atkbd);
12841da177e4SLinus Torvalds 
12852b03b60eSDmitry Torokhov 	err = input_register_device(atkbd->dev);
12862b03b60eSDmitry Torokhov 	if (err)
1287c99e3ac6SDmitry Torokhov 		goto fail3;
12881da177e4SLinus Torvalds 
12891da177e4SLinus Torvalds 	return 0;
12903c42f0c3SDmitry Torokhov 
12912b03b60eSDmitry Torokhov  fail3:	serio_close(serio);
12922b03b60eSDmitry Torokhov  fail2:	serio_set_drvdata(serio, NULL);
12932b03b60eSDmitry Torokhov  fail1:	input_free_device(dev);
12943c42f0c3SDmitry Torokhov 	kfree(atkbd);
12953c42f0c3SDmitry Torokhov 	return err;
12961da177e4SLinus Torvalds }
12971da177e4SLinus Torvalds 
12981da177e4SLinus Torvalds /*
12991da177e4SLinus Torvalds  * atkbd_reconnect() tries to restore keyboard into a sane state and is
13001da177e4SLinus Torvalds  * most likely called on resume.
13011da177e4SLinus Torvalds  */
13021da177e4SLinus Torvalds 
13031da177e4SLinus Torvalds static int atkbd_reconnect(struct serio *serio)
13041da177e4SLinus Torvalds {
1305*100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
13061da177e4SLinus Torvalds 	struct serio_driver *drv = serio->drv;
130759b01513SEric W. Biederman 	int retval = -1;
13081da177e4SLinus Torvalds 
13091da177e4SLinus Torvalds 	if (!atkbd || !drv) {
1310a9a1f9c3SDmitry Torokhov 		dev_dbg(&serio->dev,
1311a9a1f9c3SDmitry Torokhov 			"reconnect request, but serio is disconnected, ignoring...\n");
13121da177e4SLinus Torvalds 		return -1;
13131da177e4SLinus Torvalds 	}
13141da177e4SLinus Torvalds 
131559b01513SEric W. Biederman 	mutex_lock(&atkbd->mutex);
131659b01513SEric W. Biederman 
13171da177e4SLinus Torvalds 	atkbd_disable(atkbd);
13181da177e4SLinus Torvalds 
13191da177e4SLinus Torvalds 	if (atkbd->write) {
13201da177e4SLinus Torvalds 		if (atkbd_probe(atkbd))
132159b01513SEric W. Biederman 			goto out;
132259b01513SEric W. Biederman 
13231da177e4SLinus Torvalds 		if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
132459b01513SEric W. Biederman 			goto out;
13251da177e4SLinus Torvalds 
1326d4119bdaSDmitry Torokhov 		/*
1327d4119bdaSDmitry Torokhov 		 * Restore LED state and repeat rate. While input core
1328d4119bdaSDmitry Torokhov 		 * will do this for us at resume time reconnect may happen
1329d4119bdaSDmitry Torokhov 		 * because user requested it via sysfs or simply because
1330d4119bdaSDmitry Torokhov 		 * keyboard was unplugged and plugged in again so we need
1331d4119bdaSDmitry Torokhov 		 * to do it ourselves here.
1332d4119bdaSDmitry Torokhov 		 */
1333d4119bdaSDmitry Torokhov 		atkbd_set_leds(atkbd);
1334d4119bdaSDmitry Torokhov 		if (!atkbd->softrepeat)
1335d4119bdaSDmitry Torokhov 			atkbd_set_repeat_rate(atkbd);
1336d4119bdaSDmitry Torokhov 
13371da177e4SLinus Torvalds 	}
13381da177e4SLinus Torvalds 
1339be2d7e42SShawn Nematbakhsh 	/*
1340be2d7e42SShawn Nematbakhsh 	 * Reset our state machine in case reconnect happened in the middle
1341be2d7e42SShawn Nematbakhsh 	 * of multi-byte scancode.
1342be2d7e42SShawn Nematbakhsh 	 */
1343be2d7e42SShawn Nematbakhsh 	atkbd->xl_bit = 0;
1344be2d7e42SShawn Nematbakhsh 	atkbd->emul = 0;
1345be2d7e42SShawn Nematbakhsh 
13461da177e4SLinus Torvalds 	atkbd_enable(atkbd);
1347be2d7e42SShawn Nematbakhsh 	if (atkbd->write)
1348be2d7e42SShawn Nematbakhsh 		atkbd_activate(atkbd);
1349be2d7e42SShawn Nematbakhsh 
135059b01513SEric W. Biederman 	retval = 0;
13511da177e4SLinus Torvalds 
135259b01513SEric W. Biederman  out:
135359b01513SEric W. Biederman 	mutex_unlock(&atkbd->mutex);
135459b01513SEric W. Biederman 	return retval;
13551da177e4SLinus Torvalds }
13561da177e4SLinus Torvalds 
1357af2e7d77SArvind Yadav static const struct serio_device_id atkbd_serio_ids[] = {
13581da177e4SLinus Torvalds 	{
13591da177e4SLinus Torvalds 		.type	= SERIO_8042,
13601da177e4SLinus Torvalds 		.proto	= SERIO_ANY,
13611da177e4SLinus Torvalds 		.id	= SERIO_ANY,
13621da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
13631da177e4SLinus Torvalds 	},
13641da177e4SLinus Torvalds 	{
13651da177e4SLinus Torvalds 		.type	= SERIO_8042_XL,
13661da177e4SLinus Torvalds 		.proto	= SERIO_ANY,
13671da177e4SLinus Torvalds 		.id	= SERIO_ANY,
13681da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
13691da177e4SLinus Torvalds 	},
13701da177e4SLinus Torvalds 	{
13711da177e4SLinus Torvalds 		.type	= SERIO_RS232,
13721da177e4SLinus Torvalds 		.proto	= SERIO_PS2SER,
13731da177e4SLinus Torvalds 		.id	= SERIO_ANY,
13741da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
13751da177e4SLinus Torvalds 	},
13761da177e4SLinus Torvalds 	{ 0 }
13771da177e4SLinus Torvalds };
13781da177e4SLinus Torvalds 
13791da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
13801da177e4SLinus Torvalds 
13811da177e4SLinus Torvalds static struct serio_driver atkbd_drv = {
13821da177e4SLinus Torvalds 	.driver		= {
13831da177e4SLinus Torvalds 		.name		= "atkbd",
1384c99e3ac6SDmitry Torokhov 		.dev_groups	= atkbd_attribute_groups,
13851da177e4SLinus Torvalds 	},
13861da177e4SLinus Torvalds 	.description	= DRIVER_DESC,
13871da177e4SLinus Torvalds 	.id_table	= atkbd_serio_ids,
13881da177e4SLinus Torvalds 	.interrupt	= atkbd_interrupt,
13891da177e4SLinus Torvalds 	.connect	= atkbd_connect,
13901da177e4SLinus Torvalds 	.reconnect	= atkbd_reconnect,
13911da177e4SLinus Torvalds 	.disconnect	= atkbd_disconnect,
13921da177e4SLinus Torvalds 	.cleanup	= atkbd_cleanup,
13931da177e4SLinus Torvalds };
13941da177e4SLinus Torvalds 
13951da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
13961da177e4SLinus Torvalds 				ssize_t (*handler)(struct atkbd *, char *))
13971da177e4SLinus Torvalds {
13981da177e4SLinus Torvalds 	struct serio *serio = to_serio_port(dev);
1399*100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
14001da177e4SLinus Torvalds 
140159b01513SEric W. Biederman 	return handler(atkbd, buf);
14021da177e4SLinus Torvalds }
14031da177e4SLinus Torvalds 
14041da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
14051da177e4SLinus Torvalds 				ssize_t (*handler)(struct atkbd *, const char *, size_t))
14061da177e4SLinus Torvalds {
14071da177e4SLinus Torvalds 	struct serio *serio = to_serio_port(dev);
1408*100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
14091da177e4SLinus Torvalds 	int retval;
14101da177e4SLinus Torvalds 
141159b01513SEric W. Biederman 	retval = mutex_lock_interruptible(&atkbd->mutex);
14121da177e4SLinus Torvalds 	if (retval)
14131da177e4SLinus Torvalds 		return retval;
14141da177e4SLinus Torvalds 
14151da177e4SLinus Torvalds 	atkbd_disable(atkbd);
14161da177e4SLinus Torvalds 	retval = handler(atkbd, buf, count);
14171da177e4SLinus Torvalds 	atkbd_enable(atkbd);
14181da177e4SLinus Torvalds 
141959b01513SEric W. Biederman 	mutex_unlock(&atkbd->mutex);
142059b01513SEric W. Biederman 
14211da177e4SLinus Torvalds 	return retval;
14221da177e4SLinus Torvalds }
14231da177e4SLinus Torvalds 
14241da177e4SLinus Torvalds static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
14251da177e4SLinus Torvalds {
14261da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0);
14271da177e4SLinus Torvalds }
14281da177e4SLinus Torvalds 
14291da177e4SLinus Torvalds static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
14301da177e4SLinus Torvalds {
14312b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
143276496e7aSJJ Ding 	unsigned int value;
14332b03b60eSDmitry Torokhov 	int err;
1434a9a1f9c3SDmitry Torokhov 	bool old_extra;
1435a9a1f9c3SDmitry Torokhov 	unsigned char old_set;
14361da177e4SLinus Torvalds 
14371da177e4SLinus Torvalds 	if (!atkbd->write)
14381da177e4SLinus Torvalds 		return -EIO;
14391da177e4SLinus Torvalds 
144076496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
144176496e7aSJJ Ding 	if (err)
144276496e7aSJJ Ding 		return err;
144376496e7aSJJ Ding 
144476496e7aSJJ Ding 	if (value > 1)
14451da177e4SLinus Torvalds 		return -EINVAL;
14461da177e4SLinus Torvalds 
14471da177e4SLinus Torvalds 	if (atkbd->extra != value) {
14483c42f0c3SDmitry Torokhov 		/*
14493c42f0c3SDmitry Torokhov 		 * Since device's properties will change we need to
14502b03b60eSDmitry Torokhov 		 * unregister old device. But allocate and register
14512b03b60eSDmitry Torokhov 		 * new one first to make sure we have it.
14523c42f0c3SDmitry Torokhov 		 */
14532b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
14542b03b60eSDmitry Torokhov 		old_extra = atkbd->extra;
14552b03b60eSDmitry Torokhov 		old_set = atkbd->set;
14562b03b60eSDmitry Torokhov 
14572b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
14582b03b60eSDmitry Torokhov 		if (!new_dev)
14593c42f0c3SDmitry Torokhov 			return -ENOMEM;
14602b03b60eSDmitry Torokhov 
14613c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
14621da177e4SLinus Torvalds 		atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
1463fc0eb28cSDmitry Torokhov 		atkbd_reset_state(atkbd);
14641da177e4SLinus Torvalds 		atkbd_activate(atkbd);
14652b03b60eSDmitry Torokhov 		atkbd_set_keycode_table(atkbd);
14661da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
14672b03b60eSDmitry Torokhov 
14682b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
14692b03b60eSDmitry Torokhov 		if (err) {
14702b03b60eSDmitry Torokhov 			input_free_device(new_dev);
14712b03b60eSDmitry Torokhov 
14722b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
14732b03b60eSDmitry Torokhov 			atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
14742b03b60eSDmitry Torokhov 			atkbd_set_keycode_table(atkbd);
14752b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
14762b03b60eSDmitry Torokhov 
14772b03b60eSDmitry Torokhov 			return err;
14782b03b60eSDmitry Torokhov 		}
14792b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
14802b03b60eSDmitry Torokhov 
14811da177e4SLinus Torvalds 	}
14821da177e4SLinus Torvalds 	return count;
14831da177e4SLinus Torvalds }
14841da177e4SLinus Torvalds 
14851ba36e11SDmitry Torokhov static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
14861ba36e11SDmitry Torokhov {
14870b480037STejun Heo 	size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
14880b480037STejun Heo 			       ATKBD_KEYMAP_SIZE, atkbd->force_release_mask);
14891ba36e11SDmitry Torokhov 
14901ba36e11SDmitry Torokhov 	buf[len++] = '\n';
14911ba36e11SDmitry Torokhov 	buf[len] = '\0';
14921ba36e11SDmitry Torokhov 
14931ba36e11SDmitry Torokhov 	return len;
14941ba36e11SDmitry Torokhov }
14951ba36e11SDmitry Torokhov 
14961ba36e11SDmitry Torokhov static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
14971ba36e11SDmitry Torokhov 					const char *buf, size_t count)
14981ba36e11SDmitry Torokhov {
14991ba36e11SDmitry Torokhov 	/* 64 bytes on stack should be acceptable */
15001ba36e11SDmitry Torokhov 	DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
15011ba36e11SDmitry Torokhov 	int err;
15021ba36e11SDmitry Torokhov 
15031ba36e11SDmitry Torokhov 	err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
15041ba36e11SDmitry Torokhov 	if (err)
15051ba36e11SDmitry Torokhov 		return err;
15061ba36e11SDmitry Torokhov 
15071ba36e11SDmitry Torokhov 	memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
15081ba36e11SDmitry Torokhov 	return count;
15091ba36e11SDmitry Torokhov }
15101ba36e11SDmitry Torokhov 
15111ba36e11SDmitry Torokhov 
15121da177e4SLinus Torvalds static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
15131da177e4SLinus Torvalds {
15141da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
15151da177e4SLinus Torvalds }
15161da177e4SLinus Torvalds 
15171da177e4SLinus Torvalds static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
15181da177e4SLinus Torvalds {
15192b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
152076496e7aSJJ Ding 	unsigned int value;
15212b03b60eSDmitry Torokhov 	int err;
1522a9a1f9c3SDmitry Torokhov 	bool old_scroll;
15231da177e4SLinus Torvalds 
152476496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
152576496e7aSJJ Ding 	if (err)
152676496e7aSJJ Ding 		return err;
152776496e7aSJJ Ding 
152876496e7aSJJ Ding 	if (value > 1)
15291da177e4SLinus Torvalds 		return -EINVAL;
15301da177e4SLinus Torvalds 
15311da177e4SLinus Torvalds 	if (atkbd->scroll != value) {
15322b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
15332b03b60eSDmitry Torokhov 		old_scroll = atkbd->scroll;
15342b03b60eSDmitry Torokhov 
15352b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
15362b03b60eSDmitry Torokhov 		if (!new_dev)
15373c42f0c3SDmitry Torokhov 			return -ENOMEM;
15382b03b60eSDmitry Torokhov 
15393c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
15401da177e4SLinus Torvalds 		atkbd->scroll = value;
15411da177e4SLinus Torvalds 		atkbd_set_keycode_table(atkbd);
15421da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
15432b03b60eSDmitry Torokhov 
15442b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
15452b03b60eSDmitry Torokhov 		if (err) {
15462b03b60eSDmitry Torokhov 			input_free_device(new_dev);
15472b03b60eSDmitry Torokhov 
15482b03b60eSDmitry Torokhov 			atkbd->scroll = old_scroll;
15492b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
15502b03b60eSDmitry Torokhov 			atkbd_set_keycode_table(atkbd);
15512b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
15522b03b60eSDmitry Torokhov 
15532b03b60eSDmitry Torokhov 			return err;
15542b03b60eSDmitry Torokhov 		}
15552b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
15561da177e4SLinus Torvalds 	}
15571da177e4SLinus Torvalds 	return count;
15581da177e4SLinus Torvalds }
15591da177e4SLinus Torvalds 
15601da177e4SLinus Torvalds static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
15611da177e4SLinus Torvalds {
15621da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->set);
15631da177e4SLinus Torvalds }
15641da177e4SLinus Torvalds 
15651da177e4SLinus Torvalds static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
15661da177e4SLinus Torvalds {
15672b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
156876496e7aSJJ Ding 	unsigned int value;
15692b03b60eSDmitry Torokhov 	int err;
1570a9a1f9c3SDmitry Torokhov 	unsigned char old_set;
1571a9a1f9c3SDmitry Torokhov 	bool old_extra;
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds 	if (!atkbd->write)
15741da177e4SLinus Torvalds 		return -EIO;
15751da177e4SLinus Torvalds 
157676496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
157776496e7aSJJ Ding 	if (err)
157876496e7aSJJ Ding 		return err;
157976496e7aSJJ Ding 
158076496e7aSJJ Ding 	if (value != 2 && value != 3)
15811da177e4SLinus Torvalds 		return -EINVAL;
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds 	if (atkbd->set != value) {
15842b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
15852b03b60eSDmitry Torokhov 		old_extra = atkbd->extra;
15862b03b60eSDmitry Torokhov 		old_set = atkbd->set;
15872b03b60eSDmitry Torokhov 
15882b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
15892b03b60eSDmitry Torokhov 		if (!new_dev)
15903c42f0c3SDmitry Torokhov 			return -ENOMEM;
15912b03b60eSDmitry Torokhov 
15923c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
15931da177e4SLinus Torvalds 		atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
1594d4119bdaSDmitry Torokhov 		atkbd_reset_state(atkbd);
15951da177e4SLinus Torvalds 		atkbd_activate(atkbd);
15961da177e4SLinus Torvalds 		atkbd_set_keycode_table(atkbd);
15971da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
15982b03b60eSDmitry Torokhov 
15992b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
16002b03b60eSDmitry Torokhov 		if (err) {
16012b03b60eSDmitry Torokhov 			input_free_device(new_dev);
16022b03b60eSDmitry Torokhov 
16032b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
16042b03b60eSDmitry Torokhov 			atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
16052b03b60eSDmitry Torokhov 			atkbd_set_keycode_table(atkbd);
16062b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
16072b03b60eSDmitry Torokhov 
16082b03b60eSDmitry Torokhov 			return err;
16092b03b60eSDmitry Torokhov 		}
16102b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
16111da177e4SLinus Torvalds 	}
16121da177e4SLinus Torvalds 	return count;
16131da177e4SLinus Torvalds }
16141da177e4SLinus Torvalds 
16151da177e4SLinus Torvalds static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
16161da177e4SLinus Torvalds {
16171da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0);
16181da177e4SLinus Torvalds }
16191da177e4SLinus Torvalds 
16201da177e4SLinus Torvalds static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
16211da177e4SLinus Torvalds {
16222b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
162376496e7aSJJ Ding 	unsigned int value;
16242b03b60eSDmitry Torokhov 	int err;
1625a9a1f9c3SDmitry Torokhov 	bool old_softrepeat, old_softraw;
16261da177e4SLinus Torvalds 
16271da177e4SLinus Torvalds 	if (!atkbd->write)
16281da177e4SLinus Torvalds 		return -EIO;
16291da177e4SLinus Torvalds 
163076496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
163176496e7aSJJ Ding 	if (err)
163276496e7aSJJ Ding 		return err;
163376496e7aSJJ Ding 
163476496e7aSJJ Ding 	if (value > 1)
16351da177e4SLinus Torvalds 		return -EINVAL;
16361da177e4SLinus Torvalds 
16371da177e4SLinus Torvalds 	if (atkbd->softrepeat != value) {
16382b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
16392b03b60eSDmitry Torokhov 		old_softrepeat = atkbd->softrepeat;
16402b03b60eSDmitry Torokhov 		old_softraw = atkbd->softraw;
16412b03b60eSDmitry Torokhov 
16422b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
16432b03b60eSDmitry Torokhov 		if (!new_dev)
16443c42f0c3SDmitry Torokhov 			return -ENOMEM;
16452b03b60eSDmitry Torokhov 
16463c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
16471da177e4SLinus Torvalds 		atkbd->softrepeat = value;
16481da177e4SLinus Torvalds 		if (atkbd->softrepeat)
1649a9a1f9c3SDmitry Torokhov 			atkbd->softraw = true;
16501da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
16512b03b60eSDmitry Torokhov 
16522b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
16532b03b60eSDmitry Torokhov 		if (err) {
16542b03b60eSDmitry Torokhov 			input_free_device(new_dev);
16552b03b60eSDmitry Torokhov 
16562b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
16572b03b60eSDmitry Torokhov 			atkbd->softrepeat = old_softrepeat;
16582b03b60eSDmitry Torokhov 			atkbd->softraw = old_softraw;
16592b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
16602b03b60eSDmitry Torokhov 
16612b03b60eSDmitry Torokhov 			return err;
16622b03b60eSDmitry Torokhov 		}
16632b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
16641da177e4SLinus Torvalds 	}
16651da177e4SLinus Torvalds 	return count;
16661da177e4SLinus Torvalds }
16671da177e4SLinus Torvalds 
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
16701da177e4SLinus Torvalds {
16711da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0);
16721da177e4SLinus Torvalds }
16731da177e4SLinus Torvalds 
16741da177e4SLinus Torvalds static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
16751da177e4SLinus Torvalds {
16762b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
167776496e7aSJJ Ding 	unsigned int value;
16782b03b60eSDmitry Torokhov 	int err;
1679a9a1f9c3SDmitry Torokhov 	bool old_softraw;
16801da177e4SLinus Torvalds 
168176496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
168276496e7aSJJ Ding 	if (err)
168376496e7aSJJ Ding 		return err;
168476496e7aSJJ Ding 
168576496e7aSJJ Ding 	if (value > 1)
16861da177e4SLinus Torvalds 		return -EINVAL;
16871da177e4SLinus Torvalds 
16881da177e4SLinus Torvalds 	if (atkbd->softraw != value) {
16892b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
16902b03b60eSDmitry Torokhov 		old_softraw = atkbd->softraw;
16912b03b60eSDmitry Torokhov 
16922b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
16932b03b60eSDmitry Torokhov 		if (!new_dev)
16943c42f0c3SDmitry Torokhov 			return -ENOMEM;
16952b03b60eSDmitry Torokhov 
16963c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
16971da177e4SLinus Torvalds 		atkbd->softraw = value;
16981da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
16992b03b60eSDmitry Torokhov 
17002b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
17012b03b60eSDmitry Torokhov 		if (err) {
17022b03b60eSDmitry Torokhov 			input_free_device(new_dev);
17032b03b60eSDmitry Torokhov 
17042b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
17052b03b60eSDmitry Torokhov 			atkbd->softraw = old_softraw;
17062b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
17072b03b60eSDmitry Torokhov 
17082b03b60eSDmitry Torokhov 			return err;
17092b03b60eSDmitry Torokhov 		}
17102b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
17111da177e4SLinus Torvalds 	}
17121da177e4SLinus Torvalds 	return count;
17131da177e4SLinus Torvalds }
17141da177e4SLinus Torvalds 
171586255d9dSDmitry Torokhov static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
171686255d9dSDmitry Torokhov {
171786255d9dSDmitry Torokhov 	return sprintf(buf, "%lu\n", atkbd->err_count);
171886255d9dSDmitry Torokhov }
171986255d9dSDmitry Torokhov 
172039191698SDaniel Mierswa static int __init atkbd_setup_forced_release(const struct dmi_system_id *id)
1721554101e3SGiel de Nijs {
172239191698SDaniel Mierswa 	atkbd_platform_fixup = atkbd_apply_forced_release_keylist;
172339191698SDaniel Mierswa 	atkbd_platform_fixup_data = id->driver_data;
172439191698SDaniel Mierswa 
1725c388b2c6SAxel Lin 	return 1;
1726554101e3SGiel de Nijs }
1727554101e3SGiel de Nijs 
1728e5713069SJamie Lentin static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
1729e5713069SJamie Lentin {
1730e5713069SJamie Lentin 	atkbd_platform_scancode_fixup = id->driver_data;
1731e5713069SJamie Lentin 
1732c388b2c6SAxel Lin 	return 1;
1733e5713069SJamie Lentin }
1734e5713069SJamie Lentin 
17353d725caaSSheng-Liang Song static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id)
17363d725caaSSheng-Liang Song {
17373d725caaSSheng-Liang Song 	atkbd_skip_deactivate = true;
17383d725caaSSheng-Liang Song 	return 1;
17393d725caaSSheng-Liang Song }
17403d725caaSSheng-Liang Song 
17418b8a518eSDmitry Torokhov /*
17428b8a518eSDmitry Torokhov  * NOTE: do not add any more "force release" quirks to this table.  The
17438b8a518eSDmitry Torokhov  * task of adjusting list of keys that should be "released" automatically
17448b8a518eSDmitry Torokhov  * by the driver is now delegated to userspace tools, such as udev, so
17458b8a518eSDmitry Torokhov  * submit such quirks there.
17468b8a518eSDmitry Torokhov  */
1747c45fc81eSDmitry Torokhov static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
1748554101e3SGiel de Nijs 	{
1749554101e3SGiel de Nijs 		.matches = {
1750554101e3SGiel de Nijs 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
175161579ba8SMatthew Garrett 			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
1752554101e3SGiel de Nijs 		},
175339191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
175439191698SDaniel Mierswa 		.driver_data = atkbd_dell_laptop_forced_release_keys,
1755554101e3SGiel de Nijs 	},
17565a54c011SJiri Kosina 	{
17572a3ec326SMatthew Garrett 		.matches = {
17582a3ec326SMatthew Garrett 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
17592a3ec326SMatthew Garrett 			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
17602a3ec326SMatthew Garrett 		},
176139191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
176239191698SDaniel Mierswa 		.driver_data = atkbd_dell_laptop_forced_release_keys,
17632a3ec326SMatthew Garrett 	},
17642a3ec326SMatthew Garrett 	{
17655a54c011SJiri Kosina 		.matches = {
17665a54c011SJiri Kosina 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
17675a54c011SJiri Kosina 			DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"),
17685a54c011SJiri Kosina 		},
176939191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
177039191698SDaniel Mierswa 		.driver_data = atkbd_hp_forced_release_keys,
17715a54c011SJiri Kosina 	},
1772a8215b81SMatthew Garrett 	{
1773181f6382SRikard Ljungstrand 		.matches = {
1774181f6382SRikard Ljungstrand 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1775181f6382SRikard Ljungstrand 			DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
1776181f6382SRikard Ljungstrand 		},
177739191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
1778000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
1779181f6382SRikard Ljungstrand 	},
1780181f6382SRikard Ljungstrand 	{
17812bcaa6a4SDave Andrews 		.matches = {
17822bcaa6a4SDave Andrews 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
17832bcaa6a4SDave Andrews 			DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
17842bcaa6a4SDave Andrews 		},
17852bcaa6a4SDave Andrews 		.callback = atkbd_setup_forced_release,
1786000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
17872bcaa6a4SDave Andrews 	},
17882bcaa6a4SDave Andrews 	{
17892bcaa6a4SDave Andrews 		.matches = {
17902bcaa6a4SDave Andrews 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
17912bcaa6a4SDave Andrews 			DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
17922bcaa6a4SDave Andrews 		},
17932bcaa6a4SDave Andrews 		.callback = atkbd_setup_forced_release,
1794000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
17952bcaa6a4SDave Andrews 	},
17962bcaa6a4SDave Andrews 	{
17972bcaa6a4SDave Andrews 		.matches = {
17982bcaa6a4SDave Andrews 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
17992bcaa6a4SDave Andrews 			DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
18002bcaa6a4SDave Andrews 		},
18012bcaa6a4SDave Andrews 		.callback = atkbd_setup_forced_release,
1802000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
18032bcaa6a4SDave Andrews 	},
18042bcaa6a4SDave Andrews 	{
1805c45fc81eSDmitry Torokhov 		/* Inventec Symphony */
1806a8215b81SMatthew Garrett 		.matches = {
1807a8215b81SMatthew Garrett 			DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"),
1808a8215b81SMatthew Garrett 			DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
1809a8215b81SMatthew Garrett 		},
181039191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
1811000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
1812a8215b81SMatthew Garrett 	},
18134200844bSStuart Hopkins 	{
1814c45fc81eSDmitry Torokhov 		/* Samsung NC10 */
18154200844bSStuart Hopkins 		.matches = {
18164200844bSStuart Hopkins 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
18174200844bSStuart Hopkins 			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
18184200844bSStuart Hopkins 		},
181939191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
182039191698SDaniel Mierswa 		.driver_data = atkbd_samsung_forced_release_keys,
18214200844bSStuart Hopkins 	},
1822adcb523eSDaniel Mierswa 	{
1823c45fc81eSDmitry Torokhov 		/* Samsung NC20 */
1824e04126c7SBarry Carroll 		.matches = {
1825e04126c7SBarry Carroll 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1826e04126c7SBarry Carroll 			DMI_MATCH(DMI_PRODUCT_NAME, "NC20"),
1827e04126c7SBarry Carroll 		},
1828e04126c7SBarry Carroll 		.callback = atkbd_setup_forced_release,
1829e04126c7SBarry Carroll 		.driver_data = atkbd_samsung_forced_release_keys,
1830e04126c7SBarry Carroll 	},
1831e04126c7SBarry Carroll 	{
1832c45fc81eSDmitry Torokhov 		/* Samsung SQ45S70S */
1833157f3a3eSDmitry Torokhov 		.matches = {
1834157f3a3eSDmitry Torokhov 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1835157f3a3eSDmitry Torokhov 			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
1836157f3a3eSDmitry Torokhov 		},
1837157f3a3eSDmitry Torokhov 		.callback = atkbd_setup_forced_release,
1838157f3a3eSDmitry Torokhov 		.driver_data = atkbd_samsung_forced_release_keys,
1839157f3a3eSDmitry Torokhov 	},
1840157f3a3eSDmitry Torokhov 	{
1841c45fc81eSDmitry Torokhov 		/* Fujitsu Amilo PA 1510 */
1842adcb523eSDaniel Mierswa 		.matches = {
1843adcb523eSDaniel Mierswa 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1844adcb523eSDaniel Mierswa 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
1845adcb523eSDaniel Mierswa 		},
1846adcb523eSDaniel Mierswa 		.callback = atkbd_setup_forced_release,
1847000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
1848adcb523eSDaniel Mierswa 	},
18499166d0f6SAdrian Batzill 	{
1850c45fc81eSDmitry Torokhov 		/* Fujitsu Amilo Pi 3525 */
1851f0a14de2SSimon Davie 		.matches = {
1852f0a14de2SSimon Davie 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1853f0a14de2SSimon Davie 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"),
1854f0a14de2SSimon Davie 		},
1855f0a14de2SSimon Davie 		.callback = atkbd_setup_forced_release,
1856f0a14de2SSimon Davie 		.driver_data = atkbd_amilo_pi3525_forced_release_keys,
1857f0a14de2SSimon Davie 	},
1858f0a14de2SSimon Davie 	{
1859c45fc81eSDmitry Torokhov 		/* Fujitsu Amilo Xi 3650 */
18609166d0f6SAdrian Batzill 		.matches = {
18619166d0f6SAdrian Batzill 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
18629166d0f6SAdrian Batzill 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"),
18639166d0f6SAdrian Batzill 		},
18649166d0f6SAdrian Batzill 		.callback = atkbd_setup_forced_release,
18659166d0f6SAdrian Batzill 		.driver_data = atkbd_amilo_xi3650_forced_release_keys,
18669166d0f6SAdrian Batzill 	},
1867032e46cbSJerone Young 	{
1868032e46cbSJerone Young 		.matches = {
1869032e46cbSJerone Young 			DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"),
1870032e46cbSJerone Young 			DMI_MATCH(DMI_PRODUCT_NAME, "TA12"),
1871032e46cbSJerone Young 		},
1872032e46cbSJerone Young 		.callback = atkbd_setup_forced_release,
1873032e46cbSJerone Young 		.driver_data = atkdb_soltech_ta12_forced_release_keys,
1874032e46cbSJerone Young 	},
1875e5713069SJamie Lentin 	{
1876c45fc81eSDmitry Torokhov 		/* OQO Model 01+ */
1877e5713069SJamie Lentin 		.matches = {
1878e5713069SJamie Lentin 			DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
1879e5713069SJamie Lentin 			DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
1880e5713069SJamie Lentin 		},
1881e5713069SJamie Lentin 		.callback = atkbd_setup_scancode_fixup,
1882e5713069SJamie Lentin 		.driver_data = atkbd_oqo_01plus_scancode_fixup,
1883e5713069SJamie Lentin 	},
18843d725caaSSheng-Liang Song 	{
18853d725caaSSheng-Liang Song 		.matches = {
18863d725caaSSheng-Liang Song 			DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
18873d725caaSSheng-Liang Song 		},
18883d725caaSSheng-Liang Song 		.callback = atkbd_deactivate_fixup,
18893d725caaSSheng-Liang Song 	},
1890554101e3SGiel de Nijs 	{ }
1891554101e3SGiel de Nijs };
18921da177e4SLinus Torvalds 
18931da177e4SLinus Torvalds static int __init atkbd_init(void)
18941da177e4SLinus Torvalds {
1895554101e3SGiel de Nijs 	dmi_check_system(atkbd_dmi_quirk_table);
1896554101e3SGiel de Nijs 
1897153a9df0SAkinobu Mita 	return serio_register_driver(&atkbd_drv);
18981da177e4SLinus Torvalds }
18991da177e4SLinus Torvalds 
19001da177e4SLinus Torvalds static void __exit atkbd_exit(void)
19011da177e4SLinus Torvalds {
19021da177e4SLinus Torvalds 	serio_unregister_driver(&atkbd_drv);
19031da177e4SLinus Torvalds }
19041da177e4SLinus Torvalds 
19051da177e4SLinus Torvalds module_init(atkbd_init);
19061da177e4SLinus Torvalds module_exit(atkbd_exit);
1907