xref: /linux/drivers/input/keyboard/atkbd.c (revision 45ceaf14d53a123e5955477da501bc6f26b99039)
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>
22*45ceaf14SStephen 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 
239*45ceaf14SStephen 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 {
309*45ceaf14SStephen Boyd 	return vivaldi_function_row_physmap_show(&atkbd->vdata, buf);
3108f7b057aSRajat Jain }
3118f7b057aSRajat Jain 
3128f7b057aSRajat Jain static umode_t atkbd_attr_is_visible(struct kobject *kobj,
3138f7b057aSRajat Jain 				struct attribute *attr, int i)
3148f7b057aSRajat Jain {
31550221b0bSYueHaibing 	struct device *dev = kobj_to_dev(kobj);
3168f7b057aSRajat Jain 	struct serio *serio = to_serio_port(dev);
3178f7b057aSRajat Jain 	struct atkbd *atkbd = serio_get_drvdata(serio);
3188f7b057aSRajat Jain 
3198f7b057aSRajat Jain 	if (attr == &atkbd_attr_function_row_physmap.attr &&
320*45ceaf14SStephen Boyd 	    !atkbd->vdata.num_function_row_keys)
3218f7b057aSRajat Jain 		return 0;
3228f7b057aSRajat Jain 
3238f7b057aSRajat Jain 	return attr->mode;
3248f7b057aSRajat Jain }
3258f7b057aSRajat Jain 
32686255d9dSDmitry Torokhov static struct attribute_group atkbd_attribute_group = {
32786255d9dSDmitry Torokhov 	.attrs	= atkbd_attributes,
3288f7b057aSRajat Jain 	.is_visible = atkbd_attr_is_visible,
32986255d9dSDmitry Torokhov };
33086255d9dSDmitry Torokhov 
3310ae051a1SDmitry Torokhov static const unsigned int xl_table[] = {
3320ae051a1SDmitry Torokhov 	ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
3330ae051a1SDmitry Torokhov 	ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
3340ae051a1SDmitry Torokhov };
3351da177e4SLinus Torvalds 
3360ae051a1SDmitry Torokhov /*
3370ae051a1SDmitry Torokhov  * Checks if we should mangle the scancode to extract 'release' bit
3380ae051a1SDmitry Torokhov  * in translated mode.
3390ae051a1SDmitry Torokhov  */
340a9a1f9c3SDmitry Torokhov static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
3411da177e4SLinus Torvalds {
3420ae051a1SDmitry Torokhov 	int i;
3430ae051a1SDmitry Torokhov 
3440ae051a1SDmitry Torokhov 	if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
345a9a1f9c3SDmitry Torokhov 		return false;
3460ae051a1SDmitry Torokhov 
3470ae051a1SDmitry Torokhov 	for (i = 0; i < ARRAY_SIZE(xl_table); i++)
3480ae051a1SDmitry Torokhov 		if (code == xl_table[i])
3490ae051a1SDmitry Torokhov 			return test_bit(i, &xl_bit);
3500ae051a1SDmitry Torokhov 
351a9a1f9c3SDmitry Torokhov 	return true;
3520ae051a1SDmitry Torokhov }
3530ae051a1SDmitry Torokhov 
3540ae051a1SDmitry Torokhov /*
3550ae051a1SDmitry Torokhov  * Calculates new value of xl_bit so the driver can distinguish
3560ae051a1SDmitry Torokhov  * between make/break pair of scancodes for select keys and PS/2
3570ae051a1SDmitry Torokhov  * protocol responses.
3580ae051a1SDmitry Torokhov  */
3590ae051a1SDmitry Torokhov static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code)
3600ae051a1SDmitry Torokhov {
3610ae051a1SDmitry Torokhov 	int i;
3620ae051a1SDmitry Torokhov 
3630ae051a1SDmitry Torokhov 	for (i = 0; i < ARRAY_SIZE(xl_table); i++) {
3640ae051a1SDmitry Torokhov 		if (!((code ^ xl_table[i]) & 0x7f)) {
3650ae051a1SDmitry Torokhov 			if (code & 0x80)
3660ae051a1SDmitry Torokhov 				__clear_bit(i, &atkbd->xl_bit);
3670ae051a1SDmitry Torokhov 			else
3680ae051a1SDmitry Torokhov 				__set_bit(i, &atkbd->xl_bit);
3690ae051a1SDmitry Torokhov 			break;
3700ae051a1SDmitry Torokhov 		}
3710ae051a1SDmitry Torokhov 	}
3720ae051a1SDmitry Torokhov }
3730ae051a1SDmitry Torokhov 
3740ae051a1SDmitry Torokhov /*
3750ae051a1SDmitry Torokhov  * Encode the scancode, 0xe0 prefix, and high bit into a single integer,
3760ae051a1SDmitry Torokhov  * keeping kernel 2.4 compatibility for set 2
3770ae051a1SDmitry Torokhov  */
3780ae051a1SDmitry Torokhov static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code)
3790ae051a1SDmitry Torokhov {
3800ae051a1SDmitry Torokhov 	if (atkbd->set == 3) {
3810ae051a1SDmitry Torokhov 		if (atkbd->emul == 1)
3820ae051a1SDmitry Torokhov 			code |= 0x100;
3830ae051a1SDmitry Torokhov         } else {
3840ae051a1SDmitry Torokhov 		code = (code & 0x7f) | ((code & 0x80) << 1);
3850ae051a1SDmitry Torokhov 		if (atkbd->emul == 1)
3860ae051a1SDmitry Torokhov 			code |= 0x80;
3870ae051a1SDmitry Torokhov 	}
3880ae051a1SDmitry Torokhov 
3890ae051a1SDmitry Torokhov 	return code;
3901da177e4SLinus Torvalds }
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds /*
3931da177e4SLinus Torvalds  * atkbd_interrupt(). Here takes place processing of data received from
3941da177e4SLinus Torvalds  * the keyboard into events.
3951da177e4SLinus Torvalds  */
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
3987d12e780SDavid Howells 				   unsigned int flags)
3991da177e4SLinus Torvalds {
4001da177e4SLinus Torvalds 	struct atkbd *atkbd = serio_get_drvdata(serio);
4010ae051a1SDmitry Torokhov 	struct input_dev *dev = atkbd->dev;
4021da177e4SLinus Torvalds 	unsigned int code = data;
403554101e3SGiel de Nijs 	int scroll = 0, hscroll = 0, click = -1;
4041da177e4SLinus Torvalds 	int value;
405f6d65610SDmitry Torokhov 	unsigned short keycode;
4061da177e4SLinus Torvalds 
407a9a1f9c3SDmitry Torokhov 	dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds #if !defined(__i386__) && !defined (__x86_64__)
4101da177e4SLinus Torvalds 	if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
411a9a1f9c3SDmitry Torokhov 		dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
4121da177e4SLinus Torvalds 		serio_write(serio, ATKBD_CMD_RESEND);
413a9a1f9c3SDmitry Torokhov 		atkbd->resend = true;
4141da177e4SLinus Torvalds 		goto out;
4151da177e4SLinus Torvalds 	}
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 	if (!flags && data == ATKBD_RET_ACK)
418a9a1f9c3SDmitry Torokhov 		atkbd->resend = false;
4191da177e4SLinus Torvalds #endif
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds 	if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
4221da177e4SLinus Torvalds 		if  (ps2_handle_ack(&atkbd->ps2dev, data))
4231da177e4SLinus Torvalds 			goto out;
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
4261da177e4SLinus Torvalds 		if  (ps2_handle_response(&atkbd->ps2dev, data))
4271da177e4SLinus Torvalds 			goto out;
4281da177e4SLinus Torvalds 
429aaca981eSDmitry Torokhov 	pm_wakeup_event(&serio->dev, 0);
430aaca981eSDmitry Torokhov 
4311da177e4SLinus Torvalds 	if (!atkbd->enabled)
4321da177e4SLinus Torvalds 		goto out;
4331da177e4SLinus Torvalds 
4340ae051a1SDmitry Torokhov 	input_event(dev, EV_MSC, MSC_RAW, code);
4351da177e4SLinus Torvalds 
436e5713069SJamie Lentin 	if (atkbd_platform_scancode_fixup)
437e5713069SJamie Lentin 		code = atkbd_platform_scancode_fixup(atkbd, code);
438e5713069SJamie Lentin 
4391da177e4SLinus Torvalds 	if (atkbd->translated) {
4401da177e4SLinus Torvalds 
4410ae051a1SDmitry Torokhov 		if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
4421da177e4SLinus Torvalds 			atkbd->release = code >> 7;
4431da177e4SLinus Torvalds 			code &= 0x7f;
4441da177e4SLinus Torvalds 		}
4451da177e4SLinus Torvalds 
4460ae051a1SDmitry Torokhov 		if (!atkbd->emul)
4470ae051a1SDmitry Torokhov 			atkbd_calculate_xl_bit(atkbd, data);
4481da177e4SLinus Torvalds 	}
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds 	switch (code) {
4511da177e4SLinus Torvalds 	case ATKBD_RET_BAT:
452a9a1f9c3SDmitry Torokhov 		atkbd->enabled = false;
453dbc26344SDmitry Torokhov 		serio_reconnect(atkbd->ps2dev.serio);
4541da177e4SLinus Torvalds 		goto out;
4551da177e4SLinus Torvalds 	case ATKBD_RET_EMUL0:
4561da177e4SLinus Torvalds 		atkbd->emul = 1;
4571da177e4SLinus Torvalds 		goto out;
4581da177e4SLinus Torvalds 	case ATKBD_RET_EMUL1:
4591da177e4SLinus Torvalds 		atkbd->emul = 2;
4601da177e4SLinus Torvalds 		goto out;
4611da177e4SLinus Torvalds 	case ATKBD_RET_RELEASE:
462a9a1f9c3SDmitry Torokhov 		atkbd->release = true;
4631da177e4SLinus Torvalds 		goto out;
4640ae051a1SDmitry Torokhov 	case ATKBD_RET_ACK:
4650ae051a1SDmitry Torokhov 	case ATKBD_RET_NAK:
4669f7a60d6SQi Yong 		if (printk_ratelimit())
467a9a1f9c3SDmitry Torokhov 			dev_warn(&serio->dev,
468a9a1f9c3SDmitry Torokhov 				 "Spurious %s on %s. "
469f57fe78eSJesper Juhl 				 "Some program might be trying to access hardware directly.\n",
4700ae051a1SDmitry Torokhov 				 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
4710ae051a1SDmitry Torokhov 		goto out;
4721da177e4SLinus Torvalds 	case ATKBD_RET_ERR:
47386255d9dSDmitry Torokhov 		atkbd->err_count++;
474a9a1f9c3SDmitry Torokhov 		dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
475a9a1f9c3SDmitry Torokhov 			serio->phys);
4761da177e4SLinus Torvalds 		goto out;
4771da177e4SLinus Torvalds 	}
4781da177e4SLinus Torvalds 
4790ae051a1SDmitry Torokhov 	code = atkbd_compat_scancode(atkbd, code);
4800ae051a1SDmitry Torokhov 
4810ae051a1SDmitry Torokhov 	if (atkbd->emul && --atkbd->emul)
4821da177e4SLinus Torvalds 		goto out;
4831da177e4SLinus Torvalds 
4840ae051a1SDmitry Torokhov 	keycode = atkbd->keycode[code];
4851da177e4SLinus Torvalds 
4865447326fSStefan Brüns 	if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
4870ae051a1SDmitry Torokhov 		if (keycode != ATKBD_KEY_NULL)
4880ae051a1SDmitry Torokhov 			input_event(dev, EV_MSC, MSC_SCAN, code);
4890ae051a1SDmitry Torokhov 
4900ae051a1SDmitry Torokhov 	switch (keycode) {
4911da177e4SLinus Torvalds 	case ATKBD_KEY_NULL:
4921da177e4SLinus Torvalds 		break;
4931da177e4SLinus Torvalds 	case ATKBD_KEY_UNKNOWN:
494a9a1f9c3SDmitry Torokhov 		dev_warn(&serio->dev,
495a9a1f9c3SDmitry Torokhov 			 "Unknown key %s (%s set %d, code %#x on %s).\n",
4961da177e4SLinus Torvalds 			 atkbd->release ? "released" : "pressed",
4971da177e4SLinus Torvalds 			 atkbd->translated ? "translated" : "raw",
4981da177e4SLinus Torvalds 			 atkbd->set, code, serio->phys);
499a9a1f9c3SDmitry Torokhov 		dev_warn(&serio->dev,
500a9a1f9c3SDmitry Torokhov 			 "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
5011da177e4SLinus Torvalds 			 code & 0x80 ? "e0" : "", code & 0x7f);
5020ae051a1SDmitry Torokhov 		input_sync(dev);
5031da177e4SLinus Torvalds 		break;
5041da177e4SLinus Torvalds 	case ATKBD_SCR_1:
505a9a1f9c3SDmitry Torokhov 		scroll = 1;
5061da177e4SLinus Torvalds 		break;
5071da177e4SLinus Torvalds 	case ATKBD_SCR_2:
508a9a1f9c3SDmitry Torokhov 		scroll = 2;
5091da177e4SLinus Torvalds 		break;
5101da177e4SLinus Torvalds 	case ATKBD_SCR_4:
511a9a1f9c3SDmitry Torokhov 		scroll = 4;
5121da177e4SLinus Torvalds 		break;
5131da177e4SLinus Torvalds 	case ATKBD_SCR_8:
514a9a1f9c3SDmitry Torokhov 		scroll = 8;
5151da177e4SLinus Torvalds 		break;
5161da177e4SLinus Torvalds 	case ATKBD_SCR_CLICK:
5171da177e4SLinus Torvalds 		click = !atkbd->release;
5181da177e4SLinus Torvalds 		break;
5191da177e4SLinus Torvalds 	case ATKBD_SCR_LEFT:
5201da177e4SLinus Torvalds 		hscroll = -1;
5211da177e4SLinus Torvalds 		break;
5221da177e4SLinus Torvalds 	case ATKBD_SCR_RIGHT:
5231da177e4SLinus Torvalds 		hscroll = 1;
5241da177e4SLinus Torvalds 		break;
5251da177e4SLinus Torvalds 	default:
5260ae051a1SDmitry Torokhov 		if (atkbd->release) {
5270ae051a1SDmitry Torokhov 			value = 0;
5281da177e4SLinus Torvalds 			atkbd->last = 0;
5290ae051a1SDmitry Torokhov 		} else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
5300ae051a1SDmitry Torokhov 			/* Workaround Toshiba laptop multiple keypress */
5310ae051a1SDmitry Torokhov 			value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
5320ae051a1SDmitry Torokhov 		} else {
5331da177e4SLinus Torvalds 			value = 1;
5340ae051a1SDmitry Torokhov 			atkbd->last = code;
5350ae051a1SDmitry Torokhov 			atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
5361da177e4SLinus Torvalds 		}
5371da177e4SLinus Torvalds 
538f8b4c46cSDmitry Torokhov 		input_event(dev, EV_KEY, keycode, value);
5390ae051a1SDmitry Torokhov 		input_sync(dev);
5400ae051a1SDmitry Torokhov 
541554101e3SGiel de Nijs 		if (value && test_bit(code, atkbd->force_release_mask)) {
5425447326fSStefan Brüns 			input_event(dev, EV_MSC, MSC_SCAN, code);
5430ae051a1SDmitry Torokhov 			input_report_key(dev, keycode, 0);
5440ae051a1SDmitry Torokhov 			input_sync(dev);
5450ae051a1SDmitry Torokhov 		}
5461da177e4SLinus Torvalds 	}
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	if (atkbd->scroll) {
5491da177e4SLinus Torvalds 		if (click != -1)
5500ae051a1SDmitry Torokhov 			input_report_key(dev, BTN_MIDDLE, click);
551a9a1f9c3SDmitry Torokhov 		input_report_rel(dev, REL_WHEEL,
552a9a1f9c3SDmitry Torokhov 				 atkbd->release ? -scroll : scroll);
5530ae051a1SDmitry Torokhov 		input_report_rel(dev, REL_HWHEEL, hscroll);
5540ae051a1SDmitry Torokhov 		input_sync(dev);
5551da177e4SLinus Torvalds 	}
5561da177e4SLinus Torvalds 
557a9a1f9c3SDmitry Torokhov 	atkbd->release = false;
5581da177e4SLinus Torvalds out:
5591da177e4SLinus Torvalds 	return IRQ_HANDLED;
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds 
5623d0f0fa0SDmitry Torokhov static int atkbd_set_repeat_rate(struct atkbd *atkbd)
5631da177e4SLinus Torvalds {
5641da177e4SLinus Torvalds 	const short period[32] =
5651da177e4SLinus Torvalds 		{ 33,  37,  42,  46,  50,  54,  58,  63,  67,  75,  83,  92, 100, 109, 116, 125,
5661da177e4SLinus Torvalds 		 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
5671da177e4SLinus Torvalds 	const short delay[4] =
5681da177e4SLinus Torvalds 		{ 250, 500, 750, 1000 };
5690d4c8597SDmitry Torokhov 
5703d0f0fa0SDmitry Torokhov 	struct input_dev *dev = atkbd->dev;
5713d0f0fa0SDmitry Torokhov 	unsigned char param;
5723d0f0fa0SDmitry Torokhov 	int i = 0, j = 0;
5733d0f0fa0SDmitry Torokhov 
5743d0f0fa0SDmitry Torokhov 	while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
5753d0f0fa0SDmitry Torokhov 		i++;
5763d0f0fa0SDmitry Torokhov 	dev->rep[REP_PERIOD] = period[i];
5773d0f0fa0SDmitry Torokhov 
5788ea371fbSFlorin Malita 	while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY])
5793d0f0fa0SDmitry Torokhov 		j++;
5803d0f0fa0SDmitry Torokhov 	dev->rep[REP_DELAY] = delay[j];
5813d0f0fa0SDmitry Torokhov 
5823d0f0fa0SDmitry Torokhov 	param = i | (j << 5);
5833d0f0fa0SDmitry Torokhov 	return ps2_command(&atkbd->ps2dev, &param, ATKBD_CMD_SETREP);
5843d0f0fa0SDmitry Torokhov }
5853d0f0fa0SDmitry Torokhov 
5863d0f0fa0SDmitry Torokhov static int atkbd_set_leds(struct atkbd *atkbd)
5873d0f0fa0SDmitry Torokhov {
5880d4c8597SDmitry Torokhov 	struct input_dev *dev = atkbd->dev;
5891da177e4SLinus Torvalds 	unsigned char param[2];
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 	param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
5921da177e4SLinus Torvalds 		 | (test_bit(LED_NUML,    dev->led) ? 2 : 0)
5931da177e4SLinus Torvalds 		 | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
5943d0f0fa0SDmitry Torokhov 	if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
5953d0f0fa0SDmitry Torokhov 		return -1;
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds 	if (atkbd->extra) {
5981da177e4SLinus Torvalds 		param[0] = 0;
5991da177e4SLinus Torvalds 		param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
6001da177e4SLinus Torvalds 			 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
6011da177e4SLinus Torvalds 			 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
6021da177e4SLinus Torvalds 			 | (test_bit(LED_MISC,    dev->led) ? 0x10 : 0)
6031da177e4SLinus Torvalds 			 | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);
6043d0f0fa0SDmitry Torokhov 		if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS))
6053d0f0fa0SDmitry Torokhov 			return -1;
6061da177e4SLinus Torvalds 	}
6071da177e4SLinus Torvalds 
6083d0f0fa0SDmitry Torokhov 	return 0;
6090d4c8597SDmitry Torokhov }
6100d4c8597SDmitry Torokhov 
6113d0f0fa0SDmitry Torokhov /*
6123d0f0fa0SDmitry Torokhov  * atkbd_event_work() is used to complete processing of events that
6133d0f0fa0SDmitry Torokhov  * can not be processed by input_event() which is often called from
6143d0f0fa0SDmitry Torokhov  * interrupt context.
6153d0f0fa0SDmitry Torokhov  */
6163d0f0fa0SDmitry Torokhov 
61765f27f38SDavid Howells static void atkbd_event_work(struct work_struct *work)
6183d0f0fa0SDmitry Torokhov {
619da4249c9SDmitry Torokhov 	struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);
6203d0f0fa0SDmitry Torokhov 
62159b01513SEric W. Biederman 	mutex_lock(&atkbd->mutex);
6223d0f0fa0SDmitry Torokhov 
62394dfb0d6SDmitry Torokhov 	if (!atkbd->enabled) {
62494dfb0d6SDmitry Torokhov 		/*
62594dfb0d6SDmitry Torokhov 		 * Serio ports are resumed asynchronously so while driver core
62694dfb0d6SDmitry Torokhov 		 * thinks that device is already fully operational in reality
62794dfb0d6SDmitry Torokhov 		 * it may not be ready yet. In this case we need to keep
62894dfb0d6SDmitry Torokhov 		 * rescheduling till reconnect completes.
62994dfb0d6SDmitry Torokhov 		 */
63094dfb0d6SDmitry Torokhov 		schedule_delayed_work(&atkbd->event_work,
63194dfb0d6SDmitry Torokhov 					msecs_to_jiffies(100));
63294dfb0d6SDmitry Torokhov 	} else {
6333d0f0fa0SDmitry Torokhov 		if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
6343d0f0fa0SDmitry Torokhov 			atkbd_set_leds(atkbd);
6353d0f0fa0SDmitry Torokhov 
6363d0f0fa0SDmitry Torokhov 		if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
6373d0f0fa0SDmitry Torokhov 			atkbd_set_repeat_rate(atkbd);
63894dfb0d6SDmitry Torokhov 	}
6393d0f0fa0SDmitry Torokhov 
64059b01513SEric W. Biederman 	mutex_unlock(&atkbd->mutex);
6410d4c8597SDmitry Torokhov }
6420d4c8597SDmitry Torokhov 
6430d4c8597SDmitry Torokhov /*
644da4249c9SDmitry Torokhov  * Schedule switch for execution. We need to throttle requests,
645da4249c9SDmitry Torokhov  * otherwise keyboard may become unresponsive.
646da4249c9SDmitry Torokhov  */
647da4249c9SDmitry Torokhov static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
648da4249c9SDmitry Torokhov {
649da4249c9SDmitry Torokhov 	unsigned long delay = msecs_to_jiffies(50);
650da4249c9SDmitry Torokhov 
651da4249c9SDmitry Torokhov 	if (time_after(jiffies, atkbd->event_jiffies + delay))
652da4249c9SDmitry Torokhov 		delay = 0;
653da4249c9SDmitry Torokhov 
654da4249c9SDmitry Torokhov 	atkbd->event_jiffies = jiffies;
655da4249c9SDmitry Torokhov 	set_bit(event_bit, &atkbd->event_mask);
65659b01513SEric W. Biederman 	mb();
657da4249c9SDmitry Torokhov 	schedule_delayed_work(&atkbd->event_work, delay);
658da4249c9SDmitry Torokhov }
659da4249c9SDmitry Torokhov 
660da4249c9SDmitry Torokhov /*
6610d4c8597SDmitry Torokhov  * Event callback from the input module. Events that change the state of
6620d4c8597SDmitry Torokhov  * the hardware are processed here. If action can not be performed in
6630d4c8597SDmitry Torokhov  * interrupt context it is offloaded to atkbd_event_work.
6640d4c8597SDmitry Torokhov  */
6650d4c8597SDmitry Torokhov 
666da4249c9SDmitry Torokhov static int atkbd_event(struct input_dev *dev,
667da4249c9SDmitry Torokhov 			unsigned int type, unsigned int code, int value)
6680d4c8597SDmitry Torokhov {
669b356872fSDmitry Torokhov 	struct atkbd *atkbd = input_get_drvdata(dev);
6700d4c8597SDmitry Torokhov 
6710d4c8597SDmitry Torokhov 	if (!atkbd->write)
6720d4c8597SDmitry Torokhov 		return -1;
6730d4c8597SDmitry Torokhov 
6740d4c8597SDmitry Torokhov 	switch (type) {
6750d4c8597SDmitry Torokhov 
6760d4c8597SDmitry Torokhov 	case EV_LED:
677da4249c9SDmitry Torokhov 		atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
6780d4c8597SDmitry Torokhov 		return 0;
6790d4c8597SDmitry Torokhov 
6800d4c8597SDmitry Torokhov 	case EV_REP:
681da4249c9SDmitry Torokhov 		if (!atkbd->softrepeat)
682da4249c9SDmitry Torokhov 			atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
6831da177e4SLinus Torvalds 		return 0;
6841da177e4SLinus Torvalds 
685a9a1f9c3SDmitry Torokhov 	default:
6861da177e4SLinus Torvalds 		return -1;
6871da177e4SLinus Torvalds 	}
688a9a1f9c3SDmitry Torokhov }
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds /*
6911da177e4SLinus Torvalds  * atkbd_enable() signals that interrupt handler is allowed to
6921da177e4SLinus Torvalds  * generate input events.
6931da177e4SLinus Torvalds  */
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds static inline void atkbd_enable(struct atkbd *atkbd)
6961da177e4SLinus Torvalds {
6971da177e4SLinus Torvalds 	serio_pause_rx(atkbd->ps2dev.serio);
698a9a1f9c3SDmitry Torokhov 	atkbd->enabled = true;
6991da177e4SLinus Torvalds 	serio_continue_rx(atkbd->ps2dev.serio);
7001da177e4SLinus Torvalds }
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds /*
7031da177e4SLinus Torvalds  * atkbd_disable() tells input handler that all incoming data except
7041da177e4SLinus Torvalds  * for ACKs and command response should be dropped.
7051da177e4SLinus Torvalds  */
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds static inline void atkbd_disable(struct atkbd *atkbd)
7081da177e4SLinus Torvalds {
7091da177e4SLinus Torvalds 	serio_pause_rx(atkbd->ps2dev.serio);
710a9a1f9c3SDmitry Torokhov 	atkbd->enabled = false;
7111da177e4SLinus Torvalds 	serio_continue_rx(atkbd->ps2dev.serio);
7121da177e4SLinus Torvalds }
7131da177e4SLinus Torvalds 
714be2d7e42SShawn Nematbakhsh static int atkbd_activate(struct atkbd *atkbd)
715be2d7e42SShawn Nematbakhsh {
716be2d7e42SShawn Nematbakhsh 	struct ps2dev *ps2dev = &atkbd->ps2dev;
717be2d7e42SShawn Nematbakhsh 
718be2d7e42SShawn Nematbakhsh /*
719be2d7e42SShawn Nematbakhsh  * Enable the keyboard to receive keystrokes.
720be2d7e42SShawn Nematbakhsh  */
721be2d7e42SShawn Nematbakhsh 
722be2d7e42SShawn Nematbakhsh 	if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
723be2d7e42SShawn Nematbakhsh 		dev_err(&ps2dev->serio->dev,
724be2d7e42SShawn Nematbakhsh 			"Failed to enable keyboard on %s\n",
725be2d7e42SShawn Nematbakhsh 			ps2dev->serio->phys);
726be2d7e42SShawn Nematbakhsh 		return -1;
727be2d7e42SShawn Nematbakhsh 	}
728be2d7e42SShawn Nematbakhsh 
729be2d7e42SShawn Nematbakhsh 	return 0;
730be2d7e42SShawn Nematbakhsh }
731be2d7e42SShawn Nematbakhsh 
732be2d7e42SShawn Nematbakhsh /*
733be2d7e42SShawn Nematbakhsh  * atkbd_deactivate() resets and disables the keyboard from sending
734be2d7e42SShawn Nematbakhsh  * keystrokes.
735be2d7e42SShawn Nematbakhsh  */
736be2d7e42SShawn Nematbakhsh 
737be2d7e42SShawn Nematbakhsh static void atkbd_deactivate(struct atkbd *atkbd)
738be2d7e42SShawn Nematbakhsh {
739be2d7e42SShawn Nematbakhsh 	struct ps2dev *ps2dev = &atkbd->ps2dev;
740be2d7e42SShawn Nematbakhsh 
741be2d7e42SShawn Nematbakhsh 	if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS))
742be2d7e42SShawn Nematbakhsh 		dev_err(&ps2dev->serio->dev,
743be2d7e42SShawn Nematbakhsh 			"Failed to deactivate keyboard on %s\n",
744be2d7e42SShawn Nematbakhsh 			ps2dev->serio->phys);
745be2d7e42SShawn Nematbakhsh }
746be2d7e42SShawn Nematbakhsh 
7471da177e4SLinus Torvalds /*
7481da177e4SLinus Torvalds  * atkbd_probe() probes for an AT keyboard on a serio port.
7491da177e4SLinus Torvalds  */
7501da177e4SLinus Torvalds 
7511da177e4SLinus Torvalds static int atkbd_probe(struct atkbd *atkbd)
7521da177e4SLinus Torvalds {
7531da177e4SLinus Torvalds 	struct ps2dev *ps2dev = &atkbd->ps2dev;
7541da177e4SLinus Torvalds 	unsigned char param[2];
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds /*
7571da177e4SLinus Torvalds  * Some systems, where the bit-twiddling when testing the io-lines of the
7581da177e4SLinus Torvalds  * controller may confuse the keyboard need a full reset of the keyboard. On
7591da177e4SLinus Torvalds  * these systems the BIOS also usually doesn't do it for us.
7601da177e4SLinus Torvalds  */
7611da177e4SLinus Torvalds 
7621da177e4SLinus Torvalds 	if (atkbd_reset)
7631da177e4SLinus Torvalds 		if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
764a9a1f9c3SDmitry Torokhov 			dev_warn(&ps2dev->serio->dev,
765a9a1f9c3SDmitry Torokhov 				 "keyboard reset failed on %s\n",
766a9a1f9c3SDmitry Torokhov 				 ps2dev->serio->phys);
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds /*
7691da177e4SLinus Torvalds  * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
7701da177e4SLinus Torvalds  * Some keyboards report different values, but the first byte is always 0xab or
7711da177e4SLinus Torvalds  * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this
7721da177e4SLinus Torvalds  * should make sure we don't try to set the LEDs on it.
7731da177e4SLinus Torvalds  */
7741da177e4SLinus Torvalds 
7751da177e4SLinus Torvalds 	param[0] = param[1] = 0xa5;	/* initialize with invalid values */
7761da177e4SLinus Torvalds 	if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds /*
7791da177e4SLinus Torvalds  * If the get ID command failed, we check if we can at least set the LEDs on
7801da177e4SLinus Torvalds  * the keyboard. This should work on every keyboard out there. It also turns
7811da177e4SLinus Torvalds  * the LEDs off, which we want anyway.
7821da177e4SLinus Torvalds  */
7831da177e4SLinus Torvalds 		param[0] = 0;
7841da177e4SLinus Torvalds 		if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
7851da177e4SLinus Torvalds 			return -1;
7861da177e4SLinus Torvalds 		atkbd->id = 0xabba;
7871da177e4SLinus Torvalds 		return 0;
7881da177e4SLinus Torvalds 	}
7891da177e4SLinus Torvalds 
7909807879bSDmitry Torokhov 	if (!ps2_is_keyboard_id(param[0]))
7911da177e4SLinus Torvalds 		return -1;
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds 	atkbd->id = (param[0] << 8) | param[1];
7941da177e4SLinus Torvalds 
7951da177e4SLinus Torvalds 	if (atkbd->id == 0xaca1 && atkbd->translated) {
796a9a1f9c3SDmitry Torokhov 		dev_err(&ps2dev->serio->dev,
797236d6a77SDmitry Torokhov 			"NCD terminal keyboards are only supported on non-translating controllers. "
798a9a1f9c3SDmitry Torokhov 			"Use i8042.direct=1 to disable translation.\n");
7991da177e4SLinus Torvalds 		return -1;
8001da177e4SLinus Torvalds 	}
8011da177e4SLinus Torvalds 
802be2d7e42SShawn Nematbakhsh /*
803be2d7e42SShawn Nematbakhsh  * Make sure nothing is coming from the keyboard and disturbs our
804be2d7e42SShawn Nematbakhsh  * internal state.
805be2d7e42SShawn Nematbakhsh  */
8063d725caaSSheng-Liang Song 	if (!atkbd_skip_deactivate)
807be2d7e42SShawn Nematbakhsh 		atkbd_deactivate(atkbd);
808be2d7e42SShawn Nematbakhsh 
8091da177e4SLinus Torvalds 	return 0;
8101da177e4SLinus Torvalds }
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds /*
8131da177e4SLinus Torvalds  * atkbd_select_set checks if a keyboard has a working Set 3 support, and
8141da177e4SLinus Torvalds  * sets it into that. Unfortunately there are keyboards that can be switched
8151da177e4SLinus Torvalds  * to Set 3, but don't work well in that (BTC Multimedia ...)
8161da177e4SLinus Torvalds  */
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
8191da177e4SLinus Torvalds {
8201da177e4SLinus Torvalds 	struct ps2dev *ps2dev = &atkbd->ps2dev;
8211da177e4SLinus Torvalds 	unsigned char param[2];
8221da177e4SLinus Torvalds 
823a9a1f9c3SDmitry Torokhov 	atkbd->extra = false;
8241da177e4SLinus Torvalds /*
8251da177e4SLinus Torvalds  * For known special keyboards we can go ahead and set the correct set.
8261da177e4SLinus Torvalds  * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
8271da177e4SLinus Torvalds  * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards.
8281da177e4SLinus Torvalds  */
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds 	if (atkbd->translated)
8311da177e4SLinus Torvalds 		return 2;
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 	if (atkbd->id == 0xaca1) {
8341da177e4SLinus Torvalds 		param[0] = 3;
8351da177e4SLinus Torvalds 		ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
8361da177e4SLinus Torvalds 		return 3;
8371da177e4SLinus Torvalds 	}
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	if (allow_extra) {
8401da177e4SLinus Torvalds 		param[0] = 0x71;
8411da177e4SLinus Torvalds 		if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
842a9a1f9c3SDmitry Torokhov 			atkbd->extra = true;
8431da177e4SLinus Torvalds 			return 2;
8441da177e4SLinus Torvalds 		}
8451da177e4SLinus Torvalds 	}
8461da177e4SLinus Torvalds 
8478c5188b6SBenjamin LaHaise 	if (atkbd_terminal) {
8488c5188b6SBenjamin LaHaise 		ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB);
8498c5188b6SBenjamin LaHaise 		return 3;
8508c5188b6SBenjamin LaHaise 	}
8518c5188b6SBenjamin LaHaise 
8521da177e4SLinus Torvalds 	if (target_set != 3)
8531da177e4SLinus Torvalds 		return 2;
8541da177e4SLinus Torvalds 
8551da177e4SLinus Torvalds 	if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {
8561da177e4SLinus Torvalds 		atkbd->id = param[0] << 8 | param[1];
8571da177e4SLinus Torvalds 		return 2;
8581da177e4SLinus Torvalds 	}
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds 	param[0] = 3;
8611da177e4SLinus Torvalds 	if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
8621da177e4SLinus Torvalds 		return 2;
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds 	param[0] = 0;
8651da177e4SLinus Torvalds 	if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
8661da177e4SLinus Torvalds 		return 2;
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds 	if (param[0] != 3) {
8691da177e4SLinus Torvalds 		param[0] = 2;
8701da177e4SLinus Torvalds 		if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
8711da177e4SLinus Torvalds 			return 2;
8721da177e4SLinus Torvalds 	}
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds 	ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
8751da177e4SLinus Torvalds 
8761da177e4SLinus Torvalds 	return 3;
8771da177e4SLinus Torvalds }
8781da177e4SLinus Torvalds 
879fc0eb28cSDmitry Torokhov static int atkbd_reset_state(struct atkbd *atkbd)
880fc0eb28cSDmitry Torokhov {
881fc0eb28cSDmitry Torokhov         struct ps2dev *ps2dev = &atkbd->ps2dev;
882fc0eb28cSDmitry Torokhov 	unsigned char param[1];
883fc0eb28cSDmitry Torokhov 
884fc0eb28cSDmitry Torokhov /*
885fc0eb28cSDmitry Torokhov  * Set the LEDs to a predefined state (all off).
886fc0eb28cSDmitry Torokhov  */
887fc0eb28cSDmitry Torokhov 
888fc0eb28cSDmitry Torokhov 	param[0] = 0;
889fc0eb28cSDmitry Torokhov 	if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
890fc0eb28cSDmitry Torokhov 		return -1;
891fc0eb28cSDmitry Torokhov 
892fc0eb28cSDmitry Torokhov /*
893fc0eb28cSDmitry Torokhov  * Set autorepeat to fastest possible.
894fc0eb28cSDmitry Torokhov  */
895fc0eb28cSDmitry Torokhov 
896fc0eb28cSDmitry Torokhov 	param[0] = 0;
897fc0eb28cSDmitry Torokhov 	if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
898fc0eb28cSDmitry Torokhov 		return -1;
899fc0eb28cSDmitry Torokhov 
900fc0eb28cSDmitry Torokhov 	return 0;
901fc0eb28cSDmitry Torokhov }
902fc0eb28cSDmitry Torokhov 
9031da177e4SLinus Torvalds /*
9041da177e4SLinus Torvalds  * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
9051da177e4SLinus Torvalds  * reboot.
9061da177e4SLinus Torvalds  */
9071da177e4SLinus Torvalds 
9081da177e4SLinus Torvalds static void atkbd_cleanup(struct serio *serio)
9091da177e4SLinus Torvalds {
9101da177e4SLinus Torvalds 	struct atkbd *atkbd = serio_get_drvdata(serio);
91157f5b159SDmitry Torokhov 
91257f5b159SDmitry Torokhov 	atkbd_disable(atkbd);
9134a299bf5SDmitry Torokhov 	ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF);
9141da177e4SLinus Torvalds }
9151da177e4SLinus Torvalds 
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds /*
9181da177e4SLinus Torvalds  * atkbd_disconnect() closes and frees.
9191da177e4SLinus Torvalds  */
9201da177e4SLinus Torvalds 
9211da177e4SLinus Torvalds static void atkbd_disconnect(struct serio *serio)
9221da177e4SLinus Torvalds {
9231da177e4SLinus Torvalds 	struct atkbd *atkbd = serio_get_drvdata(serio);
9241da177e4SLinus Torvalds 
92559b01513SEric W. Biederman 	sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
92659b01513SEric W. Biederman 
9271da177e4SLinus Torvalds 	atkbd_disable(atkbd);
9281da177e4SLinus Torvalds 
9290ef7a26aSDmitry Torokhov 	input_unregister_device(atkbd->dev);
9300ef7a26aSDmitry Torokhov 
9310ef7a26aSDmitry Torokhov 	/*
9320ef7a26aSDmitry Torokhov 	 * Make sure we don't have a command in flight.
9330ef7a26aSDmitry Torokhov 	 * Note that since atkbd->enabled is false event work will keep
9340ef7a26aSDmitry Torokhov 	 * rescheduling itself until it gets canceled and will not try
9350ef7a26aSDmitry Torokhov 	 * accessing freed input device or serio port.
9360ef7a26aSDmitry Torokhov 	 */
937d6d79a78SJiri Pirko 	cancel_delayed_work_sync(&atkbd->event_work);
9381da177e4SLinus Torvalds 
9391da177e4SLinus Torvalds 	serio_close(serio);
9401da177e4SLinus Torvalds 	serio_set_drvdata(serio, NULL);
9411da177e4SLinus Torvalds 	kfree(atkbd);
9421da177e4SLinus Torvalds }
9431da177e4SLinus Torvalds 
944554101e3SGiel de Nijs /*
94539191698SDaniel Mierswa  * generate release events for the keycodes given in data
94639191698SDaniel Mierswa  */
94739191698SDaniel Mierswa static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd,
94839191698SDaniel Mierswa 						const void *data)
94939191698SDaniel Mierswa {
95039191698SDaniel Mierswa 	const unsigned int *keys = data;
95139191698SDaniel Mierswa 	unsigned int i;
95239191698SDaniel Mierswa 
95339191698SDaniel Mierswa 	if (atkbd->set == 2)
95439191698SDaniel Mierswa 		for (i = 0; keys[i] != -1U; i++)
95539191698SDaniel Mierswa 			__set_bit(keys[i], atkbd->force_release_mask);
95639191698SDaniel Mierswa }
95739191698SDaniel Mierswa 
95839191698SDaniel Mierswa /*
95961579ba8SMatthew Garrett  * Most special keys (Fn+F?) on Dell laptops do not generate release
960554101e3SGiel de Nijs  * events so we have to do it ourselves.
961554101e3SGiel de Nijs  */
96239191698SDaniel Mierswa static unsigned int atkbd_dell_laptop_forced_release_keys[] = {
96339191698SDaniel Mierswa 	0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U
964554101e3SGiel de Nijs };
9651da177e4SLinus Torvalds 
9661da177e4SLinus Torvalds /*
9675a54c011SJiri Kosina  * Perform fixup for HP system that doesn't generate release
9685a54c011SJiri Kosina  * for its video switch
9695a54c011SJiri Kosina  */
97039191698SDaniel Mierswa static unsigned int atkbd_hp_forced_release_keys[] = {
97139191698SDaniel Mierswa 	0x94, -1U
9725a54c011SJiri Kosina };
9735a54c011SJiri Kosina 
9745a54c011SJiri Kosina /*
975e04126c7SBarry Carroll  * Samsung NC10,NC20 with Fn+F? key release not working
9764200844bSStuart Hopkins  */
97739191698SDaniel Mierswa static unsigned int atkbd_samsung_forced_release_keys[] = {
97839191698SDaniel Mierswa 	0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U
9794200844bSStuart Hopkins };
9804200844bSStuart Hopkins 
9814200844bSStuart Hopkins /*
982f0a14de2SSimon Davie  * Amilo Pi 3525 key release for Fn+Volume keys not working
983f0a14de2SSimon Davie  */
984f0a14de2SSimon Davie static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = {
985f0a14de2SSimon Davie 	0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U
986f0a14de2SSimon Davie };
987f0a14de2SSimon Davie 
988f0a14de2SSimon Davie /*
9899166d0f6SAdrian Batzill  * Amilo Xi 3650 key release for light touch bar not working
9909166d0f6SAdrian Batzill  */
9919166d0f6SAdrian Batzill static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = {
9929166d0f6SAdrian Batzill 	0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U
9939166d0f6SAdrian Batzill };
9949166d0f6SAdrian Batzill 
9959166d0f6SAdrian Batzill /*
996032e46cbSJerone Young  * Soltech TA12 system with broken key release on volume keys and mute key
997032e46cbSJerone Young  */
998032e46cbSJerone Young static unsigned int atkdb_soltech_ta12_forced_release_keys[] = {
999032e46cbSJerone Young 	0xa0, 0xae, 0xb0, -1U
1000032e46cbSJerone Young };
1001032e46cbSJerone Young 
1002032e46cbSJerone Young /*
1003000c2a35SHerton Ronaldo Krzesinski  * Many notebooks don't send key release event for volume up/down
1004000c2a35SHerton Ronaldo Krzesinski  * keys, with key list below common among them
1005000c2a35SHerton Ronaldo Krzesinski  */
1006000c2a35SHerton Ronaldo Krzesinski static unsigned int atkbd_volume_forced_release_keys[] = {
1007000c2a35SHerton Ronaldo Krzesinski 	0xae, 0xb0, -1U
1008000c2a35SHerton Ronaldo Krzesinski };
1009000c2a35SHerton Ronaldo Krzesinski 
1010000c2a35SHerton Ronaldo Krzesinski /*
1011e5713069SJamie Lentin  * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas
1012e5713069SJamie Lentin  * they should be generating e4-e6 (0x80 | code).
1013e5713069SJamie Lentin  */
1014e5713069SJamie Lentin static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
1015e5713069SJamie Lentin 						    unsigned int code)
1016e5713069SJamie Lentin {
1017e5713069SJamie Lentin 	if (atkbd->translated && atkbd->emul == 1 &&
1018e5713069SJamie Lentin 	    (code == 0x64 || code == 0x65 || code == 0x66)) {
1019e5713069SJamie Lentin 		atkbd->emul = 0;
1020e5713069SJamie Lentin 		code |= 0x80;
1021e5713069SJamie Lentin 	}
1022e5713069SJamie Lentin 
1023e5713069SJamie Lentin 	return code;
1024e5713069SJamie Lentin }
1025e5713069SJamie Lentin 
10269d17ad23SRajat Jain static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
10279d17ad23SRajat Jain {
10289d17ad23SRajat Jain 	struct device *dev = &atkbd->ps2dev.serio->dev;
10299d17ad23SRajat Jain 	int i, n;
10309d17ad23SRajat Jain 	u32 *ptr;
10319d17ad23SRajat Jain 	u16 scancode, keycode;
10329d17ad23SRajat Jain 
10339d17ad23SRajat Jain 	/* Parse "linux,keymap" property */
10349d17ad23SRajat Jain 	n = device_property_count_u32(dev, "linux,keymap");
10359d17ad23SRajat Jain 	if (n <= 0 || n > ATKBD_KEYMAP_SIZE)
10369d17ad23SRajat Jain 		return -ENXIO;
10379d17ad23SRajat Jain 
10389d17ad23SRajat Jain 	ptr = kcalloc(n, sizeof(u32), GFP_KERNEL);
10399d17ad23SRajat Jain 	if (!ptr)
10409d17ad23SRajat Jain 		return -ENOMEM;
10419d17ad23SRajat Jain 
10429d17ad23SRajat Jain 	if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) {
10439d17ad23SRajat Jain 		dev_err(dev, "problem parsing FW keymap property\n");
10449d17ad23SRajat Jain 		kfree(ptr);
10459d17ad23SRajat Jain 		return -EINVAL;
10469d17ad23SRajat Jain 	}
10479d17ad23SRajat Jain 
10489d17ad23SRajat Jain 	memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
10499d17ad23SRajat Jain 	for (i = 0; i < n; i++) {
10509d17ad23SRajat Jain 		scancode = SCANCODE(ptr[i]);
10519d17ad23SRajat Jain 		keycode = KEYCODE(ptr[i]);
10529d17ad23SRajat Jain 		atkbd->keycode[scancode] = keycode;
10539d17ad23SRajat Jain 	}
10549d17ad23SRajat Jain 
10559d17ad23SRajat Jain 	kfree(ptr);
10569d17ad23SRajat Jain 	return 0;
10579d17ad23SRajat Jain }
10589d17ad23SRajat Jain 
1059e5713069SJamie Lentin /*
10603c42f0c3SDmitry Torokhov  * atkbd_set_keycode_table() initializes keyboard's keycode table
10611da177e4SLinus Torvalds  * according to the selected scancode set
10621da177e4SLinus Torvalds  */
10631da177e4SLinus Torvalds 
10641da177e4SLinus Torvalds static void atkbd_set_keycode_table(struct atkbd *atkbd)
10651da177e4SLinus Torvalds {
10669d17ad23SRajat Jain 	struct device *dev = &atkbd->ps2dev.serio->dev;
1067554101e3SGiel de Nijs 	unsigned int scancode;
10681da177e4SLinus Torvalds 	int i, j;
10691da177e4SLinus Torvalds 
10701da177e4SLinus Torvalds 	memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
10711ba36e11SDmitry Torokhov 	bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
10721da177e4SLinus Torvalds 
10739d17ad23SRajat Jain 	if (!atkbd_get_keymap_from_fwnode(atkbd)) {
10749d17ad23SRajat Jain 		dev_dbg(dev, "Using FW keymap\n");
10759d17ad23SRajat Jain 	} else if (atkbd->translated) {
10761da177e4SLinus Torvalds 		for (i = 0; i < 128; i++) {
1077554101e3SGiel de Nijs 			scancode = atkbd_unxlate_table[i];
1078554101e3SGiel de Nijs 			atkbd->keycode[i] = atkbd_set2_keycode[scancode];
1079554101e3SGiel de Nijs 			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80];
10801da177e4SLinus Torvalds 			if (atkbd->scroll)
10811da177e4SLinus Torvalds 				for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
1082554101e3SGiel de Nijs 					if ((scancode | 0x80) == atkbd_scroll_keys[j].set2)
10831da177e4SLinus Torvalds 						atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
10841da177e4SLinus Torvalds 		}
10851da177e4SLinus Torvalds 	} else if (atkbd->set == 3) {
10861da177e4SLinus Torvalds 		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
10871da177e4SLinus Torvalds 	} else {
10881da177e4SLinus Torvalds 		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
10891da177e4SLinus Torvalds 
10901da177e4SLinus Torvalds 		if (atkbd->scroll)
1091554101e3SGiel de Nijs 			for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) {
1092554101e3SGiel de Nijs 				scancode = atkbd_scroll_keys[i].set2;
1093554101e3SGiel de Nijs 				atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode;
1094554101e3SGiel de Nijs 		}
10951da177e4SLinus Torvalds 	}
10960ae051a1SDmitry Torokhov 
1097554101e3SGiel de Nijs /*
1098554101e3SGiel de Nijs  * HANGEUL and HANJA keys do not send release events so we need to
1099554101e3SGiel de Nijs  * generate such events ourselves
1100554101e3SGiel de Nijs  */
1101554101e3SGiel de Nijs 	scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL);
1102554101e3SGiel de Nijs 	atkbd->keycode[scancode] = KEY_HANGEUL;
1103554101e3SGiel de Nijs 	__set_bit(scancode, atkbd->force_release_mask);
1104554101e3SGiel de Nijs 
1105554101e3SGiel de Nijs 	scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA);
1106554101e3SGiel de Nijs 	atkbd->keycode[scancode] = KEY_HANJA;
1107554101e3SGiel de Nijs 	__set_bit(scancode, atkbd->force_release_mask);
1108554101e3SGiel de Nijs 
1109554101e3SGiel de Nijs /*
1110554101e3SGiel de Nijs  * Perform additional fixups
1111554101e3SGiel de Nijs  */
1112554101e3SGiel de Nijs 	if (atkbd_platform_fixup)
111339191698SDaniel Mierswa 		atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data);
11141da177e4SLinus Torvalds }
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds /*
11171da177e4SLinus Torvalds  * atkbd_set_device_attrs() sets up keyboard's input device structure
11181da177e4SLinus Torvalds  */
11191da177e4SLinus Torvalds 
11201da177e4SLinus Torvalds static void atkbd_set_device_attrs(struct atkbd *atkbd)
11211da177e4SLinus Torvalds {
11223c42f0c3SDmitry Torokhov 	struct input_dev *input_dev = atkbd->dev;
11231da177e4SLinus Torvalds 	int i;
11241da177e4SLinus Torvalds 
11253c42f0c3SDmitry Torokhov 	if (atkbd->extra)
1126ea08c6faSDmitry Torokhov 		snprintf(atkbd->name, sizeof(atkbd->name),
1127ea08c6faSDmitry Torokhov 			 "AT Set 2 Extra keyboard");
11283c42f0c3SDmitry Torokhov 	else
1129ea08c6faSDmitry Torokhov 		snprintf(atkbd->name, sizeof(atkbd->name),
1130ea08c6faSDmitry Torokhov 			 "AT %s Set %d keyboard",
11313c42f0c3SDmitry Torokhov 			 atkbd->translated ? "Translated" : "Raw", atkbd->set);
11321da177e4SLinus Torvalds 
1133ea08c6faSDmitry Torokhov 	snprintf(atkbd->phys, sizeof(atkbd->phys),
1134ea08c6faSDmitry Torokhov 		 "%s/input0", atkbd->ps2dev.serio->phys);
11351da177e4SLinus Torvalds 
11363c42f0c3SDmitry Torokhov 	input_dev->name = atkbd->name;
11373c42f0c3SDmitry Torokhov 	input_dev->phys = atkbd->phys;
11383c42f0c3SDmitry Torokhov 	input_dev->id.bustype = BUS_I8042;
11393c42f0c3SDmitry Torokhov 	input_dev->id.vendor = 0x0001;
11403c42f0c3SDmitry Torokhov 	input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
11413c42f0c3SDmitry Torokhov 	input_dev->id.version = atkbd->id;
11423c42f0c3SDmitry Torokhov 	input_dev->event = atkbd_event;
1143469ba4dfSDmitry Torokhov 	input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
11441da177e4SLinus Torvalds 
1145b356872fSDmitry Torokhov 	input_set_drvdata(input_dev, atkbd);
1146b356872fSDmitry Torokhov 
11477b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
11487b19ada2SJiri Slaby 		BIT_MASK(EV_MSC);
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 	if (atkbd->write) {
11517b19ada2SJiri Slaby 		input_dev->evbit[0] |= BIT_MASK(EV_LED);
11527b19ada2SJiri Slaby 		input_dev->ledbit[0] = BIT_MASK(LED_NUML) |
11537b19ada2SJiri Slaby 			BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL);
11541da177e4SLinus Torvalds 	}
11551da177e4SLinus Torvalds 
11561da177e4SLinus Torvalds 	if (atkbd->extra)
11577b19ada2SJiri Slaby 		input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) |
11587b19ada2SJiri Slaby 			BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) |
11597b19ada2SJiri Slaby 			BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC);
11601da177e4SLinus Torvalds 
11611da177e4SLinus Torvalds 	if (!atkbd->softrepeat) {
11623c42f0c3SDmitry Torokhov 		input_dev->rep[REP_DELAY] = 250;
11633c42f0c3SDmitry Torokhov 		input_dev->rep[REP_PERIOD] = 33;
11641da177e4SLinus Torvalds 	}
11651da177e4SLinus Torvalds 
11667b19ada2SJiri Slaby 	input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) :
11677b19ada2SJiri Slaby 		BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);
11681da177e4SLinus Torvalds 
11691da177e4SLinus Torvalds 	if (atkbd->scroll) {
11707b19ada2SJiri Slaby 		input_dev->evbit[0] |= BIT_MASK(EV_REL);
11717b19ada2SJiri Slaby 		input_dev->relbit[0] = BIT_MASK(REL_WHEEL) |
11727b19ada2SJiri Slaby 			BIT_MASK(REL_HWHEEL);
1173f6d65610SDmitry Torokhov 		__set_bit(BTN_MIDDLE, input_dev->keybit);
11741da177e4SLinus Torvalds 	}
11751da177e4SLinus Torvalds 
11763c42f0c3SDmitry Torokhov 	input_dev->keycode = atkbd->keycode;
1177f6d65610SDmitry Torokhov 	input_dev->keycodesize = sizeof(unsigned short);
11783c42f0c3SDmitry Torokhov 	input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
11791da177e4SLinus Torvalds 
11804b70858bSDmitry Torokhov 	for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
11814b70858bSDmitry Torokhov 		if (atkbd->keycode[i] != KEY_RESERVED &&
11824b70858bSDmitry Torokhov 		    atkbd->keycode[i] != ATKBD_KEY_NULL &&
11834b70858bSDmitry Torokhov 		    atkbd->keycode[i] < ATKBD_SPECIAL) {
1184f6d65610SDmitry Torokhov 			__set_bit(atkbd->keycode[i], input_dev->keybit);
11851da177e4SLinus Torvalds 		}
11864b70858bSDmitry Torokhov 	}
11874b70858bSDmitry Torokhov }
11881da177e4SLinus Torvalds 
11898f7b057aSRajat Jain static void atkbd_parse_fwnode_data(struct serio *serio)
11908f7b057aSRajat Jain {
11918f7b057aSRajat Jain 	struct atkbd *atkbd = serio_get_drvdata(serio);
11928f7b057aSRajat Jain 	struct device *dev = &serio->dev;
11938f7b057aSRajat Jain 	int n;
11948f7b057aSRajat Jain 
11958f7b057aSRajat Jain 	/* Parse "function-row-physmap" property */
11968f7b057aSRajat Jain 	n = device_property_count_u32(dev, "function-row-physmap");
1197*45ceaf14SStephen Boyd 	if (n > 0 && n <= VIVALDI_MAX_FUNCTION_ROW_KEYS &&
11988f7b057aSRajat Jain 	    !device_property_read_u32_array(dev, "function-row-physmap",
1199*45ceaf14SStephen Boyd 					    atkbd->vdata.function_row_physmap,
1200*45ceaf14SStephen Boyd 					    n)) {
1201*45ceaf14SStephen Boyd 		atkbd->vdata.num_function_row_keys = n;
12028f7b057aSRajat Jain 		dev_dbg(dev, "FW reported %d function-row key locations\n", n);
12038f7b057aSRajat Jain 	}
12048f7b057aSRajat Jain }
12058f7b057aSRajat Jain 
12061da177e4SLinus Torvalds /*
12071da177e4SLinus Torvalds  * atkbd_connect() is called when the serio module finds an interface
12081da177e4SLinus Torvalds  * that isn't handled yet by an appropriate device driver. We check if
12091da177e4SLinus Torvalds  * there is an AT keyboard out there and if yes, we register ourselves
12101da177e4SLinus Torvalds  * to the input module.
12111da177e4SLinus Torvalds  */
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
12141da177e4SLinus Torvalds {
12151da177e4SLinus Torvalds 	struct atkbd *atkbd;
12163c42f0c3SDmitry Torokhov 	struct input_dev *dev;
12173c42f0c3SDmitry Torokhov 	int err = -ENOMEM;
12181da177e4SLinus Torvalds 
12193c42f0c3SDmitry Torokhov 	atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL);
12203c42f0c3SDmitry Torokhov 	dev = input_allocate_device();
12213c42f0c3SDmitry Torokhov 	if (!atkbd || !dev)
12222b03b60eSDmitry Torokhov 		goto fail1;
12231da177e4SLinus Torvalds 
12243c42f0c3SDmitry Torokhov 	atkbd->dev = dev;
12251da177e4SLinus Torvalds 	ps2_init(&atkbd->ps2dev, serio);
1226da4249c9SDmitry Torokhov 	INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
122759b01513SEric W. Biederman 	mutex_init(&atkbd->mutex);
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 	switch (serio->id.type) {
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds 	case SERIO_8042_XL:
1232a9a1f9c3SDmitry Torokhov 		atkbd->translated = true;
12336f49c4f5SGustavo A. R. Silva 		fallthrough;
1234a9a1f9c3SDmitry Torokhov 
12351da177e4SLinus Torvalds 	case SERIO_8042:
12361da177e4SLinus Torvalds 		if (serio->write)
1237a9a1f9c3SDmitry Torokhov 			atkbd->write = true;
12381da177e4SLinus Torvalds 		break;
12391da177e4SLinus Torvalds 	}
12401da177e4SLinus Torvalds 
12411da177e4SLinus Torvalds 	atkbd->softraw = atkbd_softraw;
12421da177e4SLinus Torvalds 	atkbd->softrepeat = atkbd_softrepeat;
12431da177e4SLinus Torvalds 	atkbd->scroll = atkbd_scroll;
12441da177e4SLinus Torvalds 
12451da177e4SLinus Torvalds 	if (atkbd->softrepeat)
1246a9a1f9c3SDmitry Torokhov 		atkbd->softraw = true;
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds 	serio_set_drvdata(serio, atkbd);
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 	err = serio_open(serio, drv);
12513c42f0c3SDmitry Torokhov 	if (err)
12522b03b60eSDmitry Torokhov 		goto fail2;
12531da177e4SLinus Torvalds 
12541da177e4SLinus Torvalds 	if (atkbd->write) {
12551da177e4SLinus Torvalds 
12561da177e4SLinus Torvalds 		if (atkbd_probe(atkbd)) {
12573c42f0c3SDmitry Torokhov 			err = -ENODEV;
12582b03b60eSDmitry Torokhov 			goto fail3;
12591da177e4SLinus Torvalds 		}
12601da177e4SLinus Torvalds 
12611da177e4SLinus Torvalds 		atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
1262fc0eb28cSDmitry Torokhov 		atkbd_reset_state(atkbd);
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 	} else {
12651da177e4SLinus Torvalds 		atkbd->set = 2;
12661da177e4SLinus Torvalds 		atkbd->id = 0xab00;
12671da177e4SLinus Torvalds 	}
12681da177e4SLinus Torvalds 
12698f7b057aSRajat Jain 	atkbd_parse_fwnode_data(serio);
12708f7b057aSRajat Jain 
12711da177e4SLinus Torvalds 	atkbd_set_keycode_table(atkbd);
12721da177e4SLinus Torvalds 	atkbd_set_device_attrs(atkbd);
12731da177e4SLinus Torvalds 
12742b03b60eSDmitry Torokhov 	err = sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group);
12752b03b60eSDmitry Torokhov 	if (err)
12762b03b60eSDmitry Torokhov 		goto fail3;
12771da177e4SLinus Torvalds 
12781da177e4SLinus Torvalds 	atkbd_enable(atkbd);
1279be2d7e42SShawn Nematbakhsh 	if (serio->write)
1280be2d7e42SShawn Nematbakhsh 		atkbd_activate(atkbd);
12811da177e4SLinus Torvalds 
12822b03b60eSDmitry Torokhov 	err = input_register_device(atkbd->dev);
12832b03b60eSDmitry Torokhov 	if (err)
12842b03b60eSDmitry Torokhov 		goto fail4;
12851da177e4SLinus Torvalds 
12861da177e4SLinus Torvalds 	return 0;
12873c42f0c3SDmitry Torokhov 
12882b03b60eSDmitry Torokhov  fail4: sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
12892b03b60eSDmitry Torokhov  fail3:	serio_close(serio);
12902b03b60eSDmitry Torokhov  fail2:	serio_set_drvdata(serio, NULL);
12912b03b60eSDmitry Torokhov  fail1:	input_free_device(dev);
12923c42f0c3SDmitry Torokhov 	kfree(atkbd);
12933c42f0c3SDmitry Torokhov 	return err;
12941da177e4SLinus Torvalds }
12951da177e4SLinus Torvalds 
12961da177e4SLinus Torvalds /*
12971da177e4SLinus Torvalds  * atkbd_reconnect() tries to restore keyboard into a sane state and is
12981da177e4SLinus Torvalds  * most likely called on resume.
12991da177e4SLinus Torvalds  */
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds static int atkbd_reconnect(struct serio *serio)
13021da177e4SLinus Torvalds {
13031da177e4SLinus Torvalds 	struct atkbd *atkbd = serio_get_drvdata(serio);
13041da177e4SLinus Torvalds 	struct serio_driver *drv = serio->drv;
130559b01513SEric W. Biederman 	int retval = -1;
13061da177e4SLinus Torvalds 
13071da177e4SLinus Torvalds 	if (!atkbd || !drv) {
1308a9a1f9c3SDmitry Torokhov 		dev_dbg(&serio->dev,
1309a9a1f9c3SDmitry Torokhov 			"reconnect request, but serio is disconnected, ignoring...\n");
13101da177e4SLinus Torvalds 		return -1;
13111da177e4SLinus Torvalds 	}
13121da177e4SLinus Torvalds 
131359b01513SEric W. Biederman 	mutex_lock(&atkbd->mutex);
131459b01513SEric W. Biederman 
13151da177e4SLinus Torvalds 	atkbd_disable(atkbd);
13161da177e4SLinus Torvalds 
13171da177e4SLinus Torvalds 	if (atkbd->write) {
13181da177e4SLinus Torvalds 		if (atkbd_probe(atkbd))
131959b01513SEric W. Biederman 			goto out;
132059b01513SEric W. Biederman 
13211da177e4SLinus Torvalds 		if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
132259b01513SEric W. Biederman 			goto out;
13231da177e4SLinus Torvalds 
1324d4119bdaSDmitry Torokhov 		/*
1325d4119bdaSDmitry Torokhov 		 * Restore LED state and repeat rate. While input core
1326d4119bdaSDmitry Torokhov 		 * will do this for us at resume time reconnect may happen
1327d4119bdaSDmitry Torokhov 		 * because user requested it via sysfs or simply because
1328d4119bdaSDmitry Torokhov 		 * keyboard was unplugged and plugged in again so we need
1329d4119bdaSDmitry Torokhov 		 * to do it ourselves here.
1330d4119bdaSDmitry Torokhov 		 */
1331d4119bdaSDmitry Torokhov 		atkbd_set_leds(atkbd);
1332d4119bdaSDmitry Torokhov 		if (!atkbd->softrepeat)
1333d4119bdaSDmitry Torokhov 			atkbd_set_repeat_rate(atkbd);
1334d4119bdaSDmitry Torokhov 
13351da177e4SLinus Torvalds 	}
13361da177e4SLinus Torvalds 
1337be2d7e42SShawn Nematbakhsh 	/*
1338be2d7e42SShawn Nematbakhsh 	 * Reset our state machine in case reconnect happened in the middle
1339be2d7e42SShawn Nematbakhsh 	 * of multi-byte scancode.
1340be2d7e42SShawn Nematbakhsh 	 */
1341be2d7e42SShawn Nematbakhsh 	atkbd->xl_bit = 0;
1342be2d7e42SShawn Nematbakhsh 	atkbd->emul = 0;
1343be2d7e42SShawn Nematbakhsh 
13441da177e4SLinus Torvalds 	atkbd_enable(atkbd);
1345be2d7e42SShawn Nematbakhsh 	if (atkbd->write)
1346be2d7e42SShawn Nematbakhsh 		atkbd_activate(atkbd);
1347be2d7e42SShawn Nematbakhsh 
134859b01513SEric W. Biederman 	retval = 0;
13491da177e4SLinus Torvalds 
135059b01513SEric W. Biederman  out:
135159b01513SEric W. Biederman 	mutex_unlock(&atkbd->mutex);
135259b01513SEric W. Biederman 	return retval;
13531da177e4SLinus Torvalds }
13541da177e4SLinus Torvalds 
1355af2e7d77SArvind Yadav static const struct serio_device_id atkbd_serio_ids[] = {
13561da177e4SLinus Torvalds 	{
13571da177e4SLinus Torvalds 		.type	= SERIO_8042,
13581da177e4SLinus Torvalds 		.proto	= SERIO_ANY,
13591da177e4SLinus Torvalds 		.id	= SERIO_ANY,
13601da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
13611da177e4SLinus Torvalds 	},
13621da177e4SLinus Torvalds 	{
13631da177e4SLinus Torvalds 		.type	= SERIO_8042_XL,
13641da177e4SLinus Torvalds 		.proto	= SERIO_ANY,
13651da177e4SLinus Torvalds 		.id	= SERIO_ANY,
13661da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
13671da177e4SLinus Torvalds 	},
13681da177e4SLinus Torvalds 	{
13691da177e4SLinus Torvalds 		.type	= SERIO_RS232,
13701da177e4SLinus Torvalds 		.proto	= SERIO_PS2SER,
13711da177e4SLinus Torvalds 		.id	= SERIO_ANY,
13721da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
13731da177e4SLinus Torvalds 	},
13741da177e4SLinus Torvalds 	{ 0 }
13751da177e4SLinus Torvalds };
13761da177e4SLinus Torvalds 
13771da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
13781da177e4SLinus Torvalds 
13791da177e4SLinus Torvalds static struct serio_driver atkbd_drv = {
13801da177e4SLinus Torvalds 	.driver		= {
13811da177e4SLinus Torvalds 		.name	= "atkbd",
13821da177e4SLinus Torvalds 	},
13831da177e4SLinus Torvalds 	.description	= DRIVER_DESC,
13841da177e4SLinus Torvalds 	.id_table	= atkbd_serio_ids,
13851da177e4SLinus Torvalds 	.interrupt	= atkbd_interrupt,
13861da177e4SLinus Torvalds 	.connect	= atkbd_connect,
13871da177e4SLinus Torvalds 	.reconnect	= atkbd_reconnect,
13881da177e4SLinus Torvalds 	.disconnect	= atkbd_disconnect,
13891da177e4SLinus Torvalds 	.cleanup	= atkbd_cleanup,
13901da177e4SLinus Torvalds };
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
13931da177e4SLinus Torvalds 				ssize_t (*handler)(struct atkbd *, char *))
13941da177e4SLinus Torvalds {
13951da177e4SLinus Torvalds 	struct serio *serio = to_serio_port(dev);
139659b01513SEric W. Biederman 	struct atkbd *atkbd = serio_get_drvdata(serio);
13971da177e4SLinus Torvalds 
139859b01513SEric W. Biederman 	return handler(atkbd, buf);
13991da177e4SLinus Torvalds }
14001da177e4SLinus Torvalds 
14011da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
14021da177e4SLinus Torvalds 				ssize_t (*handler)(struct atkbd *, const char *, size_t))
14031da177e4SLinus Torvalds {
14041da177e4SLinus Torvalds 	struct serio *serio = to_serio_port(dev);
140559b01513SEric W. Biederman 	struct atkbd *atkbd = serio_get_drvdata(serio);
14061da177e4SLinus Torvalds 	int retval;
14071da177e4SLinus Torvalds 
140859b01513SEric W. Biederman 	retval = mutex_lock_interruptible(&atkbd->mutex);
14091da177e4SLinus Torvalds 	if (retval)
14101da177e4SLinus Torvalds 		return retval;
14111da177e4SLinus Torvalds 
14121da177e4SLinus Torvalds 	atkbd_disable(atkbd);
14131da177e4SLinus Torvalds 	retval = handler(atkbd, buf, count);
14141da177e4SLinus Torvalds 	atkbd_enable(atkbd);
14151da177e4SLinus Torvalds 
141659b01513SEric W. Biederman 	mutex_unlock(&atkbd->mutex);
141759b01513SEric W. Biederman 
14181da177e4SLinus Torvalds 	return retval;
14191da177e4SLinus Torvalds }
14201da177e4SLinus Torvalds 
14211da177e4SLinus Torvalds static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
14221da177e4SLinus Torvalds {
14231da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0);
14241da177e4SLinus Torvalds }
14251da177e4SLinus Torvalds 
14261da177e4SLinus Torvalds static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
14271da177e4SLinus Torvalds {
14282b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
142976496e7aSJJ Ding 	unsigned int value;
14302b03b60eSDmitry Torokhov 	int err;
1431a9a1f9c3SDmitry Torokhov 	bool old_extra;
1432a9a1f9c3SDmitry Torokhov 	unsigned char old_set;
14331da177e4SLinus Torvalds 
14341da177e4SLinus Torvalds 	if (!atkbd->write)
14351da177e4SLinus Torvalds 		return -EIO;
14361da177e4SLinus Torvalds 
143776496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
143876496e7aSJJ Ding 	if (err)
143976496e7aSJJ Ding 		return err;
144076496e7aSJJ Ding 
144176496e7aSJJ Ding 	if (value > 1)
14421da177e4SLinus Torvalds 		return -EINVAL;
14431da177e4SLinus Torvalds 
14441da177e4SLinus Torvalds 	if (atkbd->extra != value) {
14453c42f0c3SDmitry Torokhov 		/*
14463c42f0c3SDmitry Torokhov 		 * Since device's properties will change we need to
14472b03b60eSDmitry Torokhov 		 * unregister old device. But allocate and register
14482b03b60eSDmitry Torokhov 		 * new one first to make sure we have it.
14493c42f0c3SDmitry Torokhov 		 */
14502b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
14512b03b60eSDmitry Torokhov 		old_extra = atkbd->extra;
14522b03b60eSDmitry Torokhov 		old_set = atkbd->set;
14532b03b60eSDmitry Torokhov 
14542b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
14552b03b60eSDmitry Torokhov 		if (!new_dev)
14563c42f0c3SDmitry Torokhov 			return -ENOMEM;
14572b03b60eSDmitry Torokhov 
14583c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
14591da177e4SLinus Torvalds 		atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
1460fc0eb28cSDmitry Torokhov 		atkbd_reset_state(atkbd);
14611da177e4SLinus Torvalds 		atkbd_activate(atkbd);
14622b03b60eSDmitry Torokhov 		atkbd_set_keycode_table(atkbd);
14631da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
14642b03b60eSDmitry Torokhov 
14652b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
14662b03b60eSDmitry Torokhov 		if (err) {
14672b03b60eSDmitry Torokhov 			input_free_device(new_dev);
14682b03b60eSDmitry Torokhov 
14692b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
14702b03b60eSDmitry Torokhov 			atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
14712b03b60eSDmitry Torokhov 			atkbd_set_keycode_table(atkbd);
14722b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
14732b03b60eSDmitry Torokhov 
14742b03b60eSDmitry Torokhov 			return err;
14752b03b60eSDmitry Torokhov 		}
14762b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
14772b03b60eSDmitry Torokhov 
14781da177e4SLinus Torvalds 	}
14791da177e4SLinus Torvalds 	return count;
14801da177e4SLinus Torvalds }
14811da177e4SLinus Torvalds 
14821ba36e11SDmitry Torokhov static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
14831ba36e11SDmitry Torokhov {
14840b480037STejun Heo 	size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
14850b480037STejun Heo 			       ATKBD_KEYMAP_SIZE, atkbd->force_release_mask);
14861ba36e11SDmitry Torokhov 
14871ba36e11SDmitry Torokhov 	buf[len++] = '\n';
14881ba36e11SDmitry Torokhov 	buf[len] = '\0';
14891ba36e11SDmitry Torokhov 
14901ba36e11SDmitry Torokhov 	return len;
14911ba36e11SDmitry Torokhov }
14921ba36e11SDmitry Torokhov 
14931ba36e11SDmitry Torokhov static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
14941ba36e11SDmitry Torokhov 					const char *buf, size_t count)
14951ba36e11SDmitry Torokhov {
14961ba36e11SDmitry Torokhov 	/* 64 bytes on stack should be acceptable */
14971ba36e11SDmitry Torokhov 	DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
14981ba36e11SDmitry Torokhov 	int err;
14991ba36e11SDmitry Torokhov 
15001ba36e11SDmitry Torokhov 	err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
15011ba36e11SDmitry Torokhov 	if (err)
15021ba36e11SDmitry Torokhov 		return err;
15031ba36e11SDmitry Torokhov 
15041ba36e11SDmitry Torokhov 	memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
15051ba36e11SDmitry Torokhov 	return count;
15061ba36e11SDmitry Torokhov }
15071ba36e11SDmitry Torokhov 
15081ba36e11SDmitry Torokhov 
15091da177e4SLinus Torvalds static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
15101da177e4SLinus Torvalds {
15111da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
15121da177e4SLinus Torvalds }
15131da177e4SLinus Torvalds 
15141da177e4SLinus Torvalds static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
15151da177e4SLinus Torvalds {
15162b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
151776496e7aSJJ Ding 	unsigned int value;
15182b03b60eSDmitry Torokhov 	int err;
1519a9a1f9c3SDmitry Torokhov 	bool old_scroll;
15201da177e4SLinus Torvalds 
152176496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
152276496e7aSJJ Ding 	if (err)
152376496e7aSJJ Ding 		return err;
152476496e7aSJJ Ding 
152576496e7aSJJ Ding 	if (value > 1)
15261da177e4SLinus Torvalds 		return -EINVAL;
15271da177e4SLinus Torvalds 
15281da177e4SLinus Torvalds 	if (atkbd->scroll != value) {
15292b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
15302b03b60eSDmitry Torokhov 		old_scroll = atkbd->scroll;
15312b03b60eSDmitry Torokhov 
15322b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
15332b03b60eSDmitry Torokhov 		if (!new_dev)
15343c42f0c3SDmitry Torokhov 			return -ENOMEM;
15352b03b60eSDmitry Torokhov 
15363c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
15371da177e4SLinus Torvalds 		atkbd->scroll = value;
15381da177e4SLinus Torvalds 		atkbd_set_keycode_table(atkbd);
15391da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
15402b03b60eSDmitry Torokhov 
15412b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
15422b03b60eSDmitry Torokhov 		if (err) {
15432b03b60eSDmitry Torokhov 			input_free_device(new_dev);
15442b03b60eSDmitry Torokhov 
15452b03b60eSDmitry Torokhov 			atkbd->scroll = old_scroll;
15462b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
15472b03b60eSDmitry Torokhov 			atkbd_set_keycode_table(atkbd);
15482b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
15492b03b60eSDmitry Torokhov 
15502b03b60eSDmitry Torokhov 			return err;
15512b03b60eSDmitry Torokhov 		}
15522b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
15531da177e4SLinus Torvalds 	}
15541da177e4SLinus Torvalds 	return count;
15551da177e4SLinus Torvalds }
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
15581da177e4SLinus Torvalds {
15591da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->set);
15601da177e4SLinus Torvalds }
15611da177e4SLinus Torvalds 
15621da177e4SLinus Torvalds static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
15631da177e4SLinus Torvalds {
15642b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
156576496e7aSJJ Ding 	unsigned int value;
15662b03b60eSDmitry Torokhov 	int err;
1567a9a1f9c3SDmitry Torokhov 	unsigned char old_set;
1568a9a1f9c3SDmitry Torokhov 	bool old_extra;
15691da177e4SLinus Torvalds 
15701da177e4SLinus Torvalds 	if (!atkbd->write)
15711da177e4SLinus Torvalds 		return -EIO;
15721da177e4SLinus Torvalds 
157376496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
157476496e7aSJJ Ding 	if (err)
157576496e7aSJJ Ding 		return err;
157676496e7aSJJ Ding 
157776496e7aSJJ Ding 	if (value != 2 && value != 3)
15781da177e4SLinus Torvalds 		return -EINVAL;
15791da177e4SLinus Torvalds 
15801da177e4SLinus Torvalds 	if (atkbd->set != value) {
15812b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
15822b03b60eSDmitry Torokhov 		old_extra = atkbd->extra;
15832b03b60eSDmitry Torokhov 		old_set = atkbd->set;
15842b03b60eSDmitry Torokhov 
15852b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
15862b03b60eSDmitry Torokhov 		if (!new_dev)
15873c42f0c3SDmitry Torokhov 			return -ENOMEM;
15882b03b60eSDmitry Torokhov 
15893c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
15901da177e4SLinus Torvalds 		atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
1591d4119bdaSDmitry Torokhov 		atkbd_reset_state(atkbd);
15921da177e4SLinus Torvalds 		atkbd_activate(atkbd);
15931da177e4SLinus Torvalds 		atkbd_set_keycode_table(atkbd);
15941da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
15952b03b60eSDmitry Torokhov 
15962b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
15972b03b60eSDmitry Torokhov 		if (err) {
15982b03b60eSDmitry Torokhov 			input_free_device(new_dev);
15992b03b60eSDmitry Torokhov 
16002b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
16012b03b60eSDmitry Torokhov 			atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
16022b03b60eSDmitry Torokhov 			atkbd_set_keycode_table(atkbd);
16032b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
16042b03b60eSDmitry Torokhov 
16052b03b60eSDmitry Torokhov 			return err;
16062b03b60eSDmitry Torokhov 		}
16072b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
16081da177e4SLinus Torvalds 	}
16091da177e4SLinus Torvalds 	return count;
16101da177e4SLinus Torvalds }
16111da177e4SLinus Torvalds 
16121da177e4SLinus Torvalds static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
16131da177e4SLinus Torvalds {
16141da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0);
16151da177e4SLinus Torvalds }
16161da177e4SLinus Torvalds 
16171da177e4SLinus Torvalds static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
16181da177e4SLinus Torvalds {
16192b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
162076496e7aSJJ Ding 	unsigned int value;
16212b03b60eSDmitry Torokhov 	int err;
1622a9a1f9c3SDmitry Torokhov 	bool old_softrepeat, old_softraw;
16231da177e4SLinus Torvalds 
16241da177e4SLinus Torvalds 	if (!atkbd->write)
16251da177e4SLinus Torvalds 		return -EIO;
16261da177e4SLinus Torvalds 
162776496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
162876496e7aSJJ Ding 	if (err)
162976496e7aSJJ Ding 		return err;
163076496e7aSJJ Ding 
163176496e7aSJJ Ding 	if (value > 1)
16321da177e4SLinus Torvalds 		return -EINVAL;
16331da177e4SLinus Torvalds 
16341da177e4SLinus Torvalds 	if (atkbd->softrepeat != value) {
16352b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
16362b03b60eSDmitry Torokhov 		old_softrepeat = atkbd->softrepeat;
16372b03b60eSDmitry Torokhov 		old_softraw = atkbd->softraw;
16382b03b60eSDmitry Torokhov 
16392b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
16402b03b60eSDmitry Torokhov 		if (!new_dev)
16413c42f0c3SDmitry Torokhov 			return -ENOMEM;
16422b03b60eSDmitry Torokhov 
16433c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
16441da177e4SLinus Torvalds 		atkbd->softrepeat = value;
16451da177e4SLinus Torvalds 		if (atkbd->softrepeat)
1646a9a1f9c3SDmitry Torokhov 			atkbd->softraw = true;
16471da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
16482b03b60eSDmitry Torokhov 
16492b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
16502b03b60eSDmitry Torokhov 		if (err) {
16512b03b60eSDmitry Torokhov 			input_free_device(new_dev);
16522b03b60eSDmitry Torokhov 
16532b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
16542b03b60eSDmitry Torokhov 			atkbd->softrepeat = old_softrepeat;
16552b03b60eSDmitry Torokhov 			atkbd->softraw = old_softraw;
16562b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
16572b03b60eSDmitry Torokhov 
16582b03b60eSDmitry Torokhov 			return err;
16592b03b60eSDmitry Torokhov 		}
16602b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
16611da177e4SLinus Torvalds 	}
16621da177e4SLinus Torvalds 	return count;
16631da177e4SLinus Torvalds }
16641da177e4SLinus Torvalds 
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
16671da177e4SLinus Torvalds {
16681da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0);
16691da177e4SLinus Torvalds }
16701da177e4SLinus Torvalds 
16711da177e4SLinus Torvalds static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
16721da177e4SLinus Torvalds {
16732b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
167476496e7aSJJ Ding 	unsigned int value;
16752b03b60eSDmitry Torokhov 	int err;
1676a9a1f9c3SDmitry Torokhov 	bool old_softraw;
16771da177e4SLinus Torvalds 
167876496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
167976496e7aSJJ Ding 	if (err)
168076496e7aSJJ Ding 		return err;
168176496e7aSJJ Ding 
168276496e7aSJJ Ding 	if (value > 1)
16831da177e4SLinus Torvalds 		return -EINVAL;
16841da177e4SLinus Torvalds 
16851da177e4SLinus Torvalds 	if (atkbd->softraw != value) {
16862b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
16872b03b60eSDmitry Torokhov 		old_softraw = atkbd->softraw;
16882b03b60eSDmitry Torokhov 
16892b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
16902b03b60eSDmitry Torokhov 		if (!new_dev)
16913c42f0c3SDmitry Torokhov 			return -ENOMEM;
16922b03b60eSDmitry Torokhov 
16933c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
16941da177e4SLinus Torvalds 		atkbd->softraw = value;
16951da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
16962b03b60eSDmitry Torokhov 
16972b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
16982b03b60eSDmitry Torokhov 		if (err) {
16992b03b60eSDmitry Torokhov 			input_free_device(new_dev);
17002b03b60eSDmitry Torokhov 
17012b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
17022b03b60eSDmitry Torokhov 			atkbd->softraw = old_softraw;
17032b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
17042b03b60eSDmitry Torokhov 
17052b03b60eSDmitry Torokhov 			return err;
17062b03b60eSDmitry Torokhov 		}
17072b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
17081da177e4SLinus Torvalds 	}
17091da177e4SLinus Torvalds 	return count;
17101da177e4SLinus Torvalds }
17111da177e4SLinus Torvalds 
171286255d9dSDmitry Torokhov static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
171386255d9dSDmitry Torokhov {
171486255d9dSDmitry Torokhov 	return sprintf(buf, "%lu\n", atkbd->err_count);
171586255d9dSDmitry Torokhov }
171686255d9dSDmitry Torokhov 
171739191698SDaniel Mierswa static int __init atkbd_setup_forced_release(const struct dmi_system_id *id)
1718554101e3SGiel de Nijs {
171939191698SDaniel Mierswa 	atkbd_platform_fixup = atkbd_apply_forced_release_keylist;
172039191698SDaniel Mierswa 	atkbd_platform_fixup_data = id->driver_data;
172139191698SDaniel Mierswa 
1722c388b2c6SAxel Lin 	return 1;
1723554101e3SGiel de Nijs }
1724554101e3SGiel de Nijs 
1725e5713069SJamie Lentin static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
1726e5713069SJamie Lentin {
1727e5713069SJamie Lentin 	atkbd_platform_scancode_fixup = id->driver_data;
1728e5713069SJamie Lentin 
1729c388b2c6SAxel Lin 	return 1;
1730e5713069SJamie Lentin }
1731e5713069SJamie Lentin 
17323d725caaSSheng-Liang Song static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id)
17333d725caaSSheng-Liang Song {
17343d725caaSSheng-Liang Song 	atkbd_skip_deactivate = true;
17353d725caaSSheng-Liang Song 	return 1;
17363d725caaSSheng-Liang Song }
17373d725caaSSheng-Liang Song 
17388b8a518eSDmitry Torokhov /*
17398b8a518eSDmitry Torokhov  * NOTE: do not add any more "force release" quirks to this table.  The
17408b8a518eSDmitry Torokhov  * task of adjusting list of keys that should be "released" automatically
17418b8a518eSDmitry Torokhov  * by the driver is now delegated to userspace tools, such as udev, so
17428b8a518eSDmitry Torokhov  * submit such quirks there.
17438b8a518eSDmitry Torokhov  */
1744c45fc81eSDmitry Torokhov static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
1745554101e3SGiel de Nijs 	{
1746554101e3SGiel de Nijs 		.matches = {
1747554101e3SGiel de Nijs 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
174861579ba8SMatthew Garrett 			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
1749554101e3SGiel de Nijs 		},
175039191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
175139191698SDaniel Mierswa 		.driver_data = atkbd_dell_laptop_forced_release_keys,
1752554101e3SGiel de Nijs 	},
17535a54c011SJiri Kosina 	{
17542a3ec326SMatthew Garrett 		.matches = {
17552a3ec326SMatthew Garrett 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
17562a3ec326SMatthew Garrett 			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
17572a3ec326SMatthew Garrett 		},
175839191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
175939191698SDaniel Mierswa 		.driver_data = atkbd_dell_laptop_forced_release_keys,
17602a3ec326SMatthew Garrett 	},
17612a3ec326SMatthew Garrett 	{
17625a54c011SJiri Kosina 		.matches = {
17635a54c011SJiri Kosina 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
17645a54c011SJiri Kosina 			DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"),
17655a54c011SJiri Kosina 		},
176639191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
176739191698SDaniel Mierswa 		.driver_data = atkbd_hp_forced_release_keys,
17685a54c011SJiri Kosina 	},
1769a8215b81SMatthew Garrett 	{
1770181f6382SRikard Ljungstrand 		.matches = {
1771181f6382SRikard Ljungstrand 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1772181f6382SRikard Ljungstrand 			DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
1773181f6382SRikard Ljungstrand 		},
177439191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
1775000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
1776181f6382SRikard Ljungstrand 	},
1777181f6382SRikard Ljungstrand 	{
17782bcaa6a4SDave Andrews 		.matches = {
17792bcaa6a4SDave Andrews 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
17802bcaa6a4SDave Andrews 			DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
17812bcaa6a4SDave Andrews 		},
17822bcaa6a4SDave Andrews 		.callback = atkbd_setup_forced_release,
1783000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
17842bcaa6a4SDave Andrews 	},
17852bcaa6a4SDave Andrews 	{
17862bcaa6a4SDave Andrews 		.matches = {
17872bcaa6a4SDave Andrews 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
17882bcaa6a4SDave Andrews 			DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
17892bcaa6a4SDave Andrews 		},
17902bcaa6a4SDave Andrews 		.callback = atkbd_setup_forced_release,
1791000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
17922bcaa6a4SDave Andrews 	},
17932bcaa6a4SDave Andrews 	{
17942bcaa6a4SDave Andrews 		.matches = {
17952bcaa6a4SDave Andrews 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
17962bcaa6a4SDave Andrews 			DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
17972bcaa6a4SDave Andrews 		},
17982bcaa6a4SDave Andrews 		.callback = atkbd_setup_forced_release,
1799000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
18002bcaa6a4SDave Andrews 	},
18012bcaa6a4SDave Andrews 	{
1802c45fc81eSDmitry Torokhov 		/* Inventec Symphony */
1803a8215b81SMatthew Garrett 		.matches = {
1804a8215b81SMatthew Garrett 			DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"),
1805a8215b81SMatthew Garrett 			DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
1806a8215b81SMatthew Garrett 		},
180739191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
1808000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
1809a8215b81SMatthew Garrett 	},
18104200844bSStuart Hopkins 	{
1811c45fc81eSDmitry Torokhov 		/* Samsung NC10 */
18124200844bSStuart Hopkins 		.matches = {
18134200844bSStuart Hopkins 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
18144200844bSStuart Hopkins 			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
18154200844bSStuart Hopkins 		},
181639191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
181739191698SDaniel Mierswa 		.driver_data = atkbd_samsung_forced_release_keys,
18184200844bSStuart Hopkins 	},
1819adcb523eSDaniel Mierswa 	{
1820c45fc81eSDmitry Torokhov 		/* Samsung NC20 */
1821e04126c7SBarry Carroll 		.matches = {
1822e04126c7SBarry Carroll 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1823e04126c7SBarry Carroll 			DMI_MATCH(DMI_PRODUCT_NAME, "NC20"),
1824e04126c7SBarry Carroll 		},
1825e04126c7SBarry Carroll 		.callback = atkbd_setup_forced_release,
1826e04126c7SBarry Carroll 		.driver_data = atkbd_samsung_forced_release_keys,
1827e04126c7SBarry Carroll 	},
1828e04126c7SBarry Carroll 	{
1829c45fc81eSDmitry Torokhov 		/* Samsung SQ45S70S */
1830157f3a3eSDmitry Torokhov 		.matches = {
1831157f3a3eSDmitry Torokhov 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1832157f3a3eSDmitry Torokhov 			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
1833157f3a3eSDmitry Torokhov 		},
1834157f3a3eSDmitry Torokhov 		.callback = atkbd_setup_forced_release,
1835157f3a3eSDmitry Torokhov 		.driver_data = atkbd_samsung_forced_release_keys,
1836157f3a3eSDmitry Torokhov 	},
1837157f3a3eSDmitry Torokhov 	{
1838c45fc81eSDmitry Torokhov 		/* Fujitsu Amilo PA 1510 */
1839adcb523eSDaniel Mierswa 		.matches = {
1840adcb523eSDaniel Mierswa 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1841adcb523eSDaniel Mierswa 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
1842adcb523eSDaniel Mierswa 		},
1843adcb523eSDaniel Mierswa 		.callback = atkbd_setup_forced_release,
1844000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
1845adcb523eSDaniel Mierswa 	},
18469166d0f6SAdrian Batzill 	{
1847c45fc81eSDmitry Torokhov 		/* Fujitsu Amilo Pi 3525 */
1848f0a14de2SSimon Davie 		.matches = {
1849f0a14de2SSimon Davie 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1850f0a14de2SSimon Davie 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"),
1851f0a14de2SSimon Davie 		},
1852f0a14de2SSimon Davie 		.callback = atkbd_setup_forced_release,
1853f0a14de2SSimon Davie 		.driver_data = atkbd_amilo_pi3525_forced_release_keys,
1854f0a14de2SSimon Davie 	},
1855f0a14de2SSimon Davie 	{
1856c45fc81eSDmitry Torokhov 		/* Fujitsu Amilo Xi 3650 */
18579166d0f6SAdrian Batzill 		.matches = {
18589166d0f6SAdrian Batzill 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
18599166d0f6SAdrian Batzill 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"),
18609166d0f6SAdrian Batzill 		},
18619166d0f6SAdrian Batzill 		.callback = atkbd_setup_forced_release,
18629166d0f6SAdrian Batzill 		.driver_data = atkbd_amilo_xi3650_forced_release_keys,
18639166d0f6SAdrian Batzill 	},
1864032e46cbSJerone Young 	{
1865032e46cbSJerone Young 		.matches = {
1866032e46cbSJerone Young 			DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"),
1867032e46cbSJerone Young 			DMI_MATCH(DMI_PRODUCT_NAME, "TA12"),
1868032e46cbSJerone Young 		},
1869032e46cbSJerone Young 		.callback = atkbd_setup_forced_release,
1870032e46cbSJerone Young 		.driver_data = atkdb_soltech_ta12_forced_release_keys,
1871032e46cbSJerone Young 	},
1872e5713069SJamie Lentin 	{
1873c45fc81eSDmitry Torokhov 		/* OQO Model 01+ */
1874e5713069SJamie Lentin 		.matches = {
1875e5713069SJamie Lentin 			DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
1876e5713069SJamie Lentin 			DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
1877e5713069SJamie Lentin 		},
1878e5713069SJamie Lentin 		.callback = atkbd_setup_scancode_fixup,
1879e5713069SJamie Lentin 		.driver_data = atkbd_oqo_01plus_scancode_fixup,
1880e5713069SJamie Lentin 	},
18813d725caaSSheng-Liang Song 	{
18823d725caaSSheng-Liang Song 		.matches = {
18833d725caaSSheng-Liang Song 			DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
18843d725caaSSheng-Liang Song 		},
18853d725caaSSheng-Liang Song 		.callback = atkbd_deactivate_fixup,
18863d725caaSSheng-Liang Song 	},
1887554101e3SGiel de Nijs 	{ }
1888554101e3SGiel de Nijs };
18891da177e4SLinus Torvalds 
18901da177e4SLinus Torvalds static int __init atkbd_init(void)
18911da177e4SLinus Torvalds {
1892554101e3SGiel de Nijs 	dmi_check_system(atkbd_dmi_quirk_table);
1893554101e3SGiel de Nijs 
1894153a9df0SAkinobu Mita 	return serio_register_driver(&atkbd_drv);
18951da177e4SLinus Torvalds }
18961da177e4SLinus Torvalds 
18971da177e4SLinus Torvalds static void __exit atkbd_exit(void)
18981da177e4SLinus Torvalds {
18991da177e4SLinus Torvalds 	serio_unregister_driver(&atkbd_drv);
19001da177e4SLinus Torvalds }
19011da177e4SLinus Torvalds 
19021da177e4SLinus Torvalds module_init(atkbd_init);
19031da177e4SLinus Torvalds module_exit(atkbd_exit);
1904