xref: /linux/drivers/input/keyboard/atkbd.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * AT and PS/2 keyboard driver
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (c) 1999-2002 Vojtech Pavlik
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds /*
101da177e4SLinus Torvalds  * This driver can handle standard AT keyboards and PS/2 keyboards in
111da177e4SLinus Torvalds  * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb
121da177e4SLinus Torvalds  * input-only controllers and AT keyboards connected over a one way RS232
131da177e4SLinus Torvalds  * converter.
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds #include <linux/delay.h>
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds #include <linux/slab.h>
191da177e4SLinus Torvalds #include <linux/interrupt.h>
201da177e4SLinus Torvalds #include <linux/init.h>
211da177e4SLinus Torvalds #include <linux/input.h>
2245ceaf14SStephen Boyd #include <linux/input/vivaldi-fmap.h>
231da177e4SLinus Torvalds #include <linux/serio.h>
241da177e4SLinus Torvalds #include <linux/workqueue.h>
251da177e4SLinus Torvalds #include <linux/libps2.h>
2633d3f07aSIngo Molnar #include <linux/mutex.h>
27554101e3SGiel de Nijs #include <linux/dmi.h>
288f7b057aSRajat Jain #include <linux/property.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #define DRIVER_DESC	"AT and PS/2 keyboard driver"
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
331da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
341da177e4SLinus Torvalds MODULE_LICENSE("GPL");
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds static int atkbd_set = 2;
371da177e4SLinus Torvalds module_param_named(set, atkbd_set, int, 0);
381da177e4SLinus Torvalds MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds #if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
41a9a1f9c3SDmitry Torokhov static bool atkbd_reset;
421da177e4SLinus Torvalds #else
43a9a1f9c3SDmitry Torokhov static bool atkbd_reset = true;
441da177e4SLinus Torvalds #endif
451da177e4SLinus Torvalds module_param_named(reset, atkbd_reset, bool, 0);
461da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
471da177e4SLinus Torvalds 
48a9a1f9c3SDmitry Torokhov static bool atkbd_softrepeat;
491da177e4SLinus Torvalds module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
501da177e4SLinus Torvalds MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
511da177e4SLinus Torvalds 
52a9a1f9c3SDmitry Torokhov static bool atkbd_softraw = true;
531da177e4SLinus Torvalds module_param_named(softraw, atkbd_softraw, bool, 0);
541da177e4SLinus Torvalds MODULE_PARM_DESC(softraw, "Use software generated rawmode");
551da177e4SLinus Torvalds 
56a9a1f9c3SDmitry Torokhov static bool atkbd_scroll;
571da177e4SLinus Torvalds module_param_named(scroll, atkbd_scroll, bool, 0);
581da177e4SLinus Torvalds MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
591da177e4SLinus Torvalds 
60a9a1f9c3SDmitry Torokhov static bool atkbd_extra;
611da177e4SLinus Torvalds module_param_named(extra, atkbd_extra, bool, 0);
621da177e4SLinus Torvalds MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
631da177e4SLinus Torvalds 
648c5188b6SBenjamin LaHaise static bool atkbd_terminal;
658c5188b6SBenjamin LaHaise module_param_named(terminal, atkbd_terminal, bool, 0);
668c5188b6SBenjamin LaHaise MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
678c5188b6SBenjamin LaHaise 
689d17ad23SRajat Jain #define SCANCODE(keymap)	((keymap >> 16) & 0xFFFF)
699d17ad23SRajat Jain #define KEYCODE(keymap)		(keymap & 0xFFFF)
709d17ad23SRajat Jain 
711da177e4SLinus Torvalds /*
721da177e4SLinus Torvalds  * Scancode to keycode tables. These are just the default setting, and
730211a9c8SFrederik Schwarzer  * are loadable via a userland utility.
741da177e4SLinus Torvalds  */
751da177e4SLinus Torvalds 
761ba36e11SDmitry Torokhov #define ATKBD_KEYMAP_SIZE	512
771ba36e11SDmitry Torokhov 
781ba36e11SDmitry Torokhov static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds /* XXX: need a more general approach */
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds #include "hpps2atkbd.h"	/* include the keyboard scancodes */
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds #else
871da177e4SLinus Torvalds 	  0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
881da177e4SLinus Torvalds 	  0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
891da177e4SLinus Torvalds 	  0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
901da177e4SLinus Torvalds 	  0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
911da177e4SLinus Torvalds 	  0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
921da177e4SLinus Torvalds 	  0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
931da177e4SLinus Torvalds 	  0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
941da177e4SLinus Torvalds 	 82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
971da177e4SLinus Torvalds 	217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
981da177e4SLinus Torvalds 	173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
9972a42f24SHans de Goede 	159,  0,115,  0,164,  0,  0,116,158,  0,172,166,  0,  0,  0,142,
1001da177e4SLinus Torvalds 	157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
1011da177e4SLinus Torvalds 	226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
1021da177e4SLinus Torvalds 	  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
1031da177e4SLinus Torvalds 	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	  0,  0,  0, 65, 99,
1061da177e4SLinus Torvalds #endif
1071da177e4SLinus Torvalds };
1081da177e4SLinus Torvalds 
1091ba36e11SDmitry Torokhov static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = {
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 	  0,  0,  0,  0,  0,  0,  0, 59,  1,138,128,129,130, 15, 41, 60,
1121da177e4SLinus Torvalds 	131, 29, 42, 86, 58, 16,  2, 61,133, 56, 44, 31, 30, 17,  3, 62,
1131da177e4SLinus Torvalds 	134, 46, 45, 32, 18,  5,  4, 63,135, 57, 47, 33, 20, 19,  6, 64,
1141da177e4SLinus Torvalds 	136, 49, 48, 35, 34, 21,  7, 65,137,100, 50, 36, 22,  8,  9, 66,
1151da177e4SLinus Torvalds 	125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68,
1161da177e4SLinus Torvalds 	113,114, 40, 43, 26, 13, 87, 99, 97, 54, 28, 27, 43, 43, 88, 70,
1171da177e4SLinus Torvalds 	108,105,119,103,111,107, 14,110,  0, 79,106, 75, 71,109,102,104,
1181da177e4SLinus Torvalds 	 82, 83, 80, 76, 77, 72, 69, 98,  0, 96, 81,  0, 78, 73, 55,183,
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 	184,185,186,187, 74, 94, 92, 93,  0,  0,  0,125,126,127,112,  0,
12172a42f24SHans de Goede 	  0,139,172,163,165,115,152,172,166,140,160,154,113,114,167,168,
1221da177e4SLinus Torvalds 	148,149,147,140
1231da177e4SLinus Torvalds };
1241da177e4SLinus Torvalds 
125f6d65610SDmitry Torokhov static const unsigned short atkbd_unxlate_table[128] = {
1261da177e4SLinus Torvalds           0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
1271da177e4SLinus Torvalds          21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
1281da177e4SLinus Torvalds          35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
1291da177e4SLinus Torvalds          50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
1301da177e4SLinus Torvalds          11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
1311da177e4SLinus Torvalds         114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
1321da177e4SLinus Torvalds          71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
1331da177e4SLinus Torvalds          19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
1341da177e4SLinus Torvalds };
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds #define ATKBD_CMD_SETLEDS	0x10ed
1371da177e4SLinus Torvalds #define ATKBD_CMD_GSCANSET	0x11f0
1381da177e4SLinus Torvalds #define ATKBD_CMD_SSCANSET	0x10f0
1391da177e4SLinus Torvalds #define ATKBD_CMD_GETID		0x02f2
1401da177e4SLinus Torvalds #define ATKBD_CMD_SETREP	0x10f3
1411da177e4SLinus Torvalds #define ATKBD_CMD_ENABLE	0x00f4
1424a299bf5SDmitry Torokhov #define ATKBD_CMD_RESET_DIS	0x00f5	/* Reset to defaults and disable */
1434a299bf5SDmitry Torokhov #define ATKBD_CMD_RESET_DEF	0x00f6	/* Reset to defaults */
1448c5188b6SBenjamin LaHaise #define ATKBD_CMD_SETALL_MB	0x00f8	/* Set all keys to give break codes */
1458c5188b6SBenjamin LaHaise #define ATKBD_CMD_SETALL_MBR	0x00fa  /* ... and repeat */
1461da177e4SLinus Torvalds #define ATKBD_CMD_RESET_BAT	0x02ff
1471da177e4SLinus Torvalds #define ATKBD_CMD_RESEND	0x00fe
1481da177e4SLinus Torvalds #define ATKBD_CMD_EX_ENABLE	0x10ea
1491da177e4SLinus Torvalds #define ATKBD_CMD_EX_SETLEDS	0x20eb
1501da177e4SLinus Torvalds #define ATKBD_CMD_OK_GETID	0x02e8
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds #define ATKBD_RET_ACK		0xfa
1531da177e4SLinus Torvalds #define ATKBD_RET_NAK		0xfe
1541da177e4SLinus Torvalds #define ATKBD_RET_BAT		0xaa
1551da177e4SLinus Torvalds #define ATKBD_RET_EMUL0		0xe0
1561da177e4SLinus Torvalds #define ATKBD_RET_EMUL1		0xe1
1571da177e4SLinus Torvalds #define ATKBD_RET_RELEASE	0xf0
1580ae051a1SDmitry Torokhov #define ATKBD_RET_HANJA		0xf1
1590ae051a1SDmitry Torokhov #define ATKBD_RET_HANGEUL	0xf2
1601da177e4SLinus Torvalds #define ATKBD_RET_ERR		0xff
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds #define ATKBD_KEY_UNKNOWN	0
1631da177e4SLinus Torvalds #define ATKBD_KEY_NULL		255
1641da177e4SLinus Torvalds 
1654b70858bSDmitry Torokhov #define ATKBD_SCR_1		0xfffe
1664b70858bSDmitry Torokhov #define ATKBD_SCR_2		0xfffd
1674b70858bSDmitry Torokhov #define ATKBD_SCR_4		0xfffc
1684b70858bSDmitry Torokhov #define ATKBD_SCR_8		0xfffb
1694b70858bSDmitry Torokhov #define ATKBD_SCR_CLICK		0xfffa
1704b70858bSDmitry Torokhov #define ATKBD_SCR_LEFT		0xfff9
1714b70858bSDmitry Torokhov #define ATKBD_SCR_RIGHT		0xfff8
1721da177e4SLinus Torvalds 
173f6d65610SDmitry Torokhov #define ATKBD_SPECIAL		ATKBD_SCR_RIGHT
1741da177e4SLinus Torvalds 
1750d4c8597SDmitry Torokhov #define ATKBD_LED_EVENT_BIT	0
1760d4c8597SDmitry Torokhov #define ATKBD_REP_EVENT_BIT	1
1770d4c8597SDmitry Torokhov 
1780ae051a1SDmitry Torokhov #define ATKBD_XL_ERR		0x01
1790ae051a1SDmitry Torokhov #define ATKBD_XL_BAT		0x02
1800ae051a1SDmitry Torokhov #define ATKBD_XL_ACK		0x04
1810ae051a1SDmitry Torokhov #define ATKBD_XL_NAK		0x08
1820ae051a1SDmitry Torokhov #define ATKBD_XL_HANGEUL	0x10
1830ae051a1SDmitry Torokhov #define ATKBD_XL_HANJA		0x20
1840ae051a1SDmitry Torokhov 
185f6d65610SDmitry Torokhov static const struct {
1864b70858bSDmitry Torokhov 	unsigned short keycode;
1871da177e4SLinus Torvalds 	unsigned char set2;
1881da177e4SLinus Torvalds } atkbd_scroll_keys[] = {
1891da177e4SLinus Torvalds 	{ ATKBD_SCR_1,     0xc5 },
1905212dd58SVojtech Pavlik 	{ ATKBD_SCR_2,     0x9d },
1915212dd58SVojtech Pavlik 	{ ATKBD_SCR_4,     0xa4 },
1925212dd58SVojtech Pavlik 	{ ATKBD_SCR_8,     0x9b },
1931da177e4SLinus Torvalds 	{ ATKBD_SCR_CLICK, 0xe0 },
1941da177e4SLinus Torvalds 	{ ATKBD_SCR_LEFT,  0xcb },
1951da177e4SLinus Torvalds 	{ ATKBD_SCR_RIGHT, 0xd2 },
1961da177e4SLinus Torvalds };
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds /*
1991da177e4SLinus Torvalds  * The atkbd control structure
2001da177e4SLinus Torvalds  */
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds struct atkbd {
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	struct ps2dev ps2dev;
2053c42f0c3SDmitry Torokhov 	struct input_dev *dev;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	/* Written only during init */
2081da177e4SLinus Torvalds 	char name[64];
2091da177e4SLinus Torvalds 	char phys[32];
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 	unsigned short id;
2121ba36e11SDmitry Torokhov 	unsigned short keycode[ATKBD_KEYMAP_SIZE];
2131ba36e11SDmitry Torokhov 	DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
2141da177e4SLinus Torvalds 	unsigned char set;
215a9a1f9c3SDmitry Torokhov 	bool translated;
216a9a1f9c3SDmitry Torokhov 	bool extra;
217a9a1f9c3SDmitry Torokhov 	bool write;
218a9a1f9c3SDmitry Torokhov 	bool softrepeat;
219a9a1f9c3SDmitry Torokhov 	bool softraw;
220a9a1f9c3SDmitry Torokhov 	bool scroll;
221a9a1f9c3SDmitry Torokhov 	bool enabled;
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 	/* Accessed only from interrupt */
2241da177e4SLinus Torvalds 	unsigned char emul;
225a9a1f9c3SDmitry Torokhov 	bool resend;
226a9a1f9c3SDmitry Torokhov 	bool release;
2270ae051a1SDmitry Torokhov 	unsigned long xl_bit;
2281da177e4SLinus Torvalds 	unsigned int last;
2291da177e4SLinus Torvalds 	unsigned long time;
23086255d9dSDmitry Torokhov 	unsigned long err_count;
2310d4c8597SDmitry Torokhov 
232da4249c9SDmitry Torokhov 	struct delayed_work event_work;
233da4249c9SDmitry Torokhov 	unsigned long event_jiffies;
2340d4c8597SDmitry Torokhov 	unsigned long event_mask;
23559b01513SEric W. Biederman 
23659b01513SEric W. Biederman 	/* Serializes reconnect(), attr->set() and event work */
23759b01513SEric W. Biederman 	struct mutex mutex;
2388f7b057aSRajat Jain 
23945ceaf14SStephen Boyd 	struct vivaldi_data vdata;
2401da177e4SLinus Torvalds };
2411da177e4SLinus Torvalds 
242554101e3SGiel de Nijs /*
24336726dd9SThadeu Lima de Souza Cascardo  * System-specific keymap fixup routine
244554101e3SGiel de Nijs  */
24539191698SDaniel Mierswa static void (*atkbd_platform_fixup)(struct atkbd *, const void *data);
24639191698SDaniel Mierswa static void *atkbd_platform_fixup_data;
247e5713069SJamie Lentin static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int);
248554101e3SGiel de Nijs 
2493d725caaSSheng-Liang Song /*
2503d725caaSSheng-Liang Song  * Certain keyboards to not like ATKBD_CMD_RESET_DIS and stop responding
2513d725caaSSheng-Liang Song  * to many commands until full reset (ATKBD_CMD_RESET_BAT) is performed.
2523d725caaSSheng-Liang Song  */
2533d725caaSSheng-Liang Song static bool atkbd_skip_deactivate;
2543d725caaSSheng-Liang Song 
2551da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
2561da177e4SLinus Torvalds 				ssize_t (*handler)(struct atkbd *, char *));
2571da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
2581da177e4SLinus Torvalds 				ssize_t (*handler)(struct atkbd *, const char *, size_t));
2591da177e4SLinus Torvalds #define ATKBD_DEFINE_ATTR(_name)						\
2601da177e4SLinus Torvalds static ssize_t atkbd_show_##_name(struct atkbd *, char *);			\
2611da177e4SLinus Torvalds static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t);		\
26286255d9dSDmitry Torokhov static ssize_t atkbd_do_show_##_name(struct device *d,				\
26386255d9dSDmitry Torokhov 				struct device_attribute *attr, char *b)		\
2641da177e4SLinus Torvalds {										\
2651da177e4SLinus Torvalds 	return atkbd_attr_show_helper(d, b, atkbd_show_##_name);		\
2661da177e4SLinus Torvalds }										\
26786255d9dSDmitry Torokhov static ssize_t atkbd_do_set_##_name(struct device *d,				\
26886255d9dSDmitry Torokhov 			struct device_attribute *attr, const char *b, size_t s)	\
2691da177e4SLinus Torvalds {										\
2701da177e4SLinus Torvalds 	return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name);		\
2711da177e4SLinus Torvalds }										\
2721da177e4SLinus Torvalds static struct device_attribute atkbd_attr_##_name =				\
2731da177e4SLinus Torvalds 	__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(extra);
2761ba36e11SDmitry Torokhov ATKBD_DEFINE_ATTR(force_release);
2771da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(scroll);
2781da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(set);
2791da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(softrepeat);
2801da177e4SLinus Torvalds ATKBD_DEFINE_ATTR(softraw);
2811da177e4SLinus Torvalds 
28286255d9dSDmitry Torokhov #define ATKBD_DEFINE_RO_ATTR(_name)						\
28386255d9dSDmitry Torokhov static ssize_t atkbd_show_##_name(struct atkbd *, char *);			\
28486255d9dSDmitry Torokhov static ssize_t atkbd_do_show_##_name(struct device *d,				\
28586255d9dSDmitry Torokhov 				struct device_attribute *attr, char *b)		\
28686255d9dSDmitry Torokhov {										\
28786255d9dSDmitry Torokhov 	return atkbd_attr_show_helper(d, b, atkbd_show_##_name);		\
28886255d9dSDmitry Torokhov }										\
28986255d9dSDmitry Torokhov static struct device_attribute atkbd_attr_##_name =				\
29086255d9dSDmitry Torokhov 	__ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);
29186255d9dSDmitry Torokhov 
29286255d9dSDmitry Torokhov ATKBD_DEFINE_RO_ATTR(err_count);
2938f7b057aSRajat Jain ATKBD_DEFINE_RO_ATTR(function_row_physmap);
29486255d9dSDmitry Torokhov 
29586255d9dSDmitry Torokhov static struct attribute *atkbd_attributes[] = {
29686255d9dSDmitry Torokhov 	&atkbd_attr_extra.attr,
2971ba36e11SDmitry Torokhov 	&atkbd_attr_force_release.attr,
29886255d9dSDmitry Torokhov 	&atkbd_attr_scroll.attr,
29986255d9dSDmitry Torokhov 	&atkbd_attr_set.attr,
30086255d9dSDmitry Torokhov 	&atkbd_attr_softrepeat.attr,
30186255d9dSDmitry Torokhov 	&atkbd_attr_softraw.attr,
30286255d9dSDmitry Torokhov 	&atkbd_attr_err_count.attr,
3038f7b057aSRajat Jain 	&atkbd_attr_function_row_physmap.attr,
30486255d9dSDmitry Torokhov 	NULL
30586255d9dSDmitry Torokhov };
30686255d9dSDmitry Torokhov 
atkbd_show_function_row_physmap(struct atkbd * atkbd,char * buf)3078f7b057aSRajat Jain static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf)
3088f7b057aSRajat Jain {
30945ceaf14SStephen Boyd 	return vivaldi_function_row_physmap_show(&atkbd->vdata, buf);
3108f7b057aSRajat Jain }
3118f7b057aSRajat Jain 
atkbd_from_serio(struct serio * serio)312100e1695SDmitry Torokhov static struct atkbd *atkbd_from_serio(struct serio *serio)
313100e1695SDmitry Torokhov {
314100e1695SDmitry Torokhov 	struct ps2dev *ps2dev = serio_get_drvdata(serio);
315100e1695SDmitry Torokhov 
316100e1695SDmitry Torokhov 	return container_of(ps2dev, struct atkbd, ps2dev);
317100e1695SDmitry Torokhov }
318100e1695SDmitry Torokhov 
atkbd_attr_is_visible(struct kobject * kobj,struct attribute * attr,int i)3198f7b057aSRajat Jain static umode_t atkbd_attr_is_visible(struct kobject *kobj,
3208f7b057aSRajat Jain 				struct attribute *attr, int i)
3218f7b057aSRajat Jain {
32250221b0bSYueHaibing 	struct device *dev = kobj_to_dev(kobj);
3238f7b057aSRajat Jain 	struct serio *serio = to_serio_port(dev);
324100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
3258f7b057aSRajat Jain 
3268f7b057aSRajat Jain 	if (attr == &atkbd_attr_function_row_physmap.attr &&
32745ceaf14SStephen Boyd 	    !atkbd->vdata.num_function_row_keys)
3288f7b057aSRajat Jain 		return 0;
3298f7b057aSRajat Jain 
3308f7b057aSRajat Jain 	return attr->mode;
3318f7b057aSRajat Jain }
3328f7b057aSRajat Jain 
333c99e3ac6SDmitry Torokhov static const struct attribute_group atkbd_attribute_group = {
33486255d9dSDmitry Torokhov 	.attrs	= atkbd_attributes,
3358f7b057aSRajat Jain 	.is_visible = atkbd_attr_is_visible,
33686255d9dSDmitry Torokhov };
33786255d9dSDmitry Torokhov 
338c99e3ac6SDmitry Torokhov __ATTRIBUTE_GROUPS(atkbd_attribute);
339c99e3ac6SDmitry Torokhov 
3400ae051a1SDmitry Torokhov static const unsigned int xl_table[] = {
3410ae051a1SDmitry Torokhov 	ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
3420ae051a1SDmitry Torokhov 	ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
3430ae051a1SDmitry Torokhov };
3441da177e4SLinus Torvalds 
3450ae051a1SDmitry Torokhov /*
3460ae051a1SDmitry Torokhov  * Checks if we should mangle the scancode to extract 'release' bit
3470ae051a1SDmitry Torokhov  * in translated mode.
3480ae051a1SDmitry Torokhov  */
atkbd_need_xlate(unsigned long xl_bit,unsigned char code)349a9a1f9c3SDmitry Torokhov static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
3501da177e4SLinus Torvalds {
3510ae051a1SDmitry Torokhov 	int i;
3520ae051a1SDmitry Torokhov 
3530ae051a1SDmitry Torokhov 	if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
354a9a1f9c3SDmitry Torokhov 		return false;
3550ae051a1SDmitry Torokhov 
3560ae051a1SDmitry Torokhov 	for (i = 0; i < ARRAY_SIZE(xl_table); i++)
3570ae051a1SDmitry Torokhov 		if (code == xl_table[i])
3580ae051a1SDmitry Torokhov 			return test_bit(i, &xl_bit);
3590ae051a1SDmitry Torokhov 
360a9a1f9c3SDmitry Torokhov 	return true;
3610ae051a1SDmitry Torokhov }
3620ae051a1SDmitry Torokhov 
3630ae051a1SDmitry Torokhov /*
3640ae051a1SDmitry Torokhov  * Calculates new value of xl_bit so the driver can distinguish
3650ae051a1SDmitry Torokhov  * between make/break pair of scancodes for select keys and PS/2
3660ae051a1SDmitry Torokhov  * protocol responses.
3670ae051a1SDmitry Torokhov  */
atkbd_calculate_xl_bit(struct atkbd * atkbd,unsigned char code)3680ae051a1SDmitry Torokhov static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code)
3690ae051a1SDmitry Torokhov {
3700ae051a1SDmitry Torokhov 	int i;
3710ae051a1SDmitry Torokhov 
3720ae051a1SDmitry Torokhov 	for (i = 0; i < ARRAY_SIZE(xl_table); i++) {
3730ae051a1SDmitry Torokhov 		if (!((code ^ xl_table[i]) & 0x7f)) {
3740ae051a1SDmitry Torokhov 			if (code & 0x80)
3750ae051a1SDmitry Torokhov 				__clear_bit(i, &atkbd->xl_bit);
3760ae051a1SDmitry Torokhov 			else
3770ae051a1SDmitry Torokhov 				__set_bit(i, &atkbd->xl_bit);
3780ae051a1SDmitry Torokhov 			break;
3790ae051a1SDmitry Torokhov 		}
3800ae051a1SDmitry Torokhov 	}
3810ae051a1SDmitry Torokhov }
3820ae051a1SDmitry Torokhov 
3830ae051a1SDmitry Torokhov /*
3840ae051a1SDmitry Torokhov  * Encode the scancode, 0xe0 prefix, and high bit into a single integer,
3850ae051a1SDmitry Torokhov  * keeping kernel 2.4 compatibility for set 2
3860ae051a1SDmitry Torokhov  */
atkbd_compat_scancode(struct atkbd * atkbd,unsigned int code)3870ae051a1SDmitry Torokhov static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code)
3880ae051a1SDmitry Torokhov {
3890ae051a1SDmitry Torokhov 	if (atkbd->set == 3) {
3900ae051a1SDmitry Torokhov 		if (atkbd->emul == 1)
3910ae051a1SDmitry Torokhov 			code |= 0x100;
3920ae051a1SDmitry Torokhov         } else {
3930ae051a1SDmitry Torokhov 		code = (code & 0x7f) | ((code & 0x80) << 1);
3940ae051a1SDmitry Torokhov 		if (atkbd->emul == 1)
3950ae051a1SDmitry Torokhov 			code |= 0x80;
3960ae051a1SDmitry Torokhov 	}
3970ae051a1SDmitry Torokhov 
3980ae051a1SDmitry Torokhov 	return code;
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds /*
402c4c7eac8SDmitry Torokhov  * Tries to handle frame or parity error by requesting the keyboard controller
403c4c7eac8SDmitry Torokhov  * to resend the last byte. This historically not done on x86 as controllers
404c4c7eac8SDmitry Torokhov  * there typically do not implement this command.
4051da177e4SLinus Torvalds  */
atkbd_handle_frame_error(struct ps2dev * ps2dev,u8 data,unsigned int flags)406c4c7eac8SDmitry Torokhov static bool __maybe_unused atkbd_handle_frame_error(struct ps2dev *ps2dev,
407c4c7eac8SDmitry Torokhov 						    u8 data, unsigned int flags)
4081da177e4SLinus Torvalds {
409c4c7eac8SDmitry Torokhov 	struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev);
410c4c7eac8SDmitry Torokhov 	struct serio *serio = ps2dev->serio;
411c4c7eac8SDmitry Torokhov 
412c4c7eac8SDmitry Torokhov 	if ((flags & (SERIO_FRAME | SERIO_PARITY)) &&
413c4c7eac8SDmitry Torokhov 	    (~flags & SERIO_TIMEOUT) &&
414c4c7eac8SDmitry Torokhov 	    !atkbd->resend && atkbd->write) {
415c4c7eac8SDmitry Torokhov 		dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
416c4c7eac8SDmitry Torokhov 		serio_write(serio, ATKBD_CMD_RESEND);
417c4c7eac8SDmitry Torokhov 		atkbd->resend = true;
418c4c7eac8SDmitry Torokhov 		return true;
419c4c7eac8SDmitry Torokhov 	}
420c4c7eac8SDmitry Torokhov 
421c4c7eac8SDmitry Torokhov 	if (!flags && data == ATKBD_RET_ACK)
422c4c7eac8SDmitry Torokhov 		atkbd->resend = false;
423c4c7eac8SDmitry Torokhov 
424c4c7eac8SDmitry Torokhov 	return false;
425c4c7eac8SDmitry Torokhov }
426c4c7eac8SDmitry Torokhov 
atkbd_pre_receive_byte(struct ps2dev * ps2dev,u8 data,unsigned int flags)427c4c7eac8SDmitry Torokhov static enum ps2_disposition atkbd_pre_receive_byte(struct ps2dev *ps2dev,
428c4c7eac8SDmitry Torokhov 						   u8 data, unsigned int flags)
429c4c7eac8SDmitry Torokhov {
430c4c7eac8SDmitry Torokhov 	struct serio *serio = ps2dev->serio;
431c4c7eac8SDmitry Torokhov 
432c4c7eac8SDmitry Torokhov 	dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
433c4c7eac8SDmitry Torokhov 
434c4c7eac8SDmitry Torokhov #if !defined(__i386__) && !defined (__x86_64__)
435c4c7eac8SDmitry Torokhov 	if (atkbd_handle_frame_error(ps2dev, data, flags))
436c4c7eac8SDmitry Torokhov 		return PS2_IGNORE;
437c4c7eac8SDmitry Torokhov #endif
438c4c7eac8SDmitry Torokhov 
439c4c7eac8SDmitry Torokhov 	return PS2_PROCESS;
440c4c7eac8SDmitry Torokhov }
441c4c7eac8SDmitry Torokhov 
atkbd_receive_byte(struct ps2dev * ps2dev,u8 data)442c4c7eac8SDmitry Torokhov static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data)
443c4c7eac8SDmitry Torokhov {
444c4c7eac8SDmitry Torokhov 	struct serio *serio = ps2dev->serio;
445c4c7eac8SDmitry Torokhov 	struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev);
4460ae051a1SDmitry Torokhov 	struct input_dev *dev = atkbd->dev;
4471da177e4SLinus Torvalds 	unsigned int code = data;
448554101e3SGiel de Nijs 	int scroll = 0, hscroll = 0, click = -1;
4491da177e4SLinus Torvalds 	int value;
450f6d65610SDmitry Torokhov 	unsigned short keycode;
4511da177e4SLinus Torvalds 
452aaca981eSDmitry Torokhov 	pm_wakeup_event(&serio->dev, 0);
453aaca981eSDmitry Torokhov 
4541da177e4SLinus Torvalds 	if (!atkbd->enabled)
455c4c7eac8SDmitry Torokhov 		return;
4561da177e4SLinus Torvalds 
4570ae051a1SDmitry Torokhov 	input_event(dev, EV_MSC, MSC_RAW, code);
4581da177e4SLinus Torvalds 
459e5713069SJamie Lentin 	if (atkbd_platform_scancode_fixup)
460e5713069SJamie Lentin 		code = atkbd_platform_scancode_fixup(atkbd, code);
461e5713069SJamie Lentin 
4621da177e4SLinus Torvalds 	if (atkbd->translated) {
4631da177e4SLinus Torvalds 
4640ae051a1SDmitry Torokhov 		if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
4651da177e4SLinus Torvalds 			atkbd->release = code >> 7;
4661da177e4SLinus Torvalds 			code &= 0x7f;
4671da177e4SLinus Torvalds 		}
4681da177e4SLinus Torvalds 
4690ae051a1SDmitry Torokhov 		if (!atkbd->emul)
4700ae051a1SDmitry Torokhov 			atkbd_calculate_xl_bit(atkbd, data);
4711da177e4SLinus Torvalds 	}
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds 	switch (code) {
4741da177e4SLinus Torvalds 	case ATKBD_RET_BAT:
475a9a1f9c3SDmitry Torokhov 		atkbd->enabled = false;
476dbc26344SDmitry Torokhov 		serio_reconnect(atkbd->ps2dev.serio);
477c4c7eac8SDmitry Torokhov 		return;
4781da177e4SLinus Torvalds 	case ATKBD_RET_EMUL0:
4791da177e4SLinus Torvalds 		atkbd->emul = 1;
480c4c7eac8SDmitry Torokhov 		return;
4811da177e4SLinus Torvalds 	case ATKBD_RET_EMUL1:
4821da177e4SLinus Torvalds 		atkbd->emul = 2;
483c4c7eac8SDmitry Torokhov 		return;
4841da177e4SLinus Torvalds 	case ATKBD_RET_RELEASE:
485a9a1f9c3SDmitry Torokhov 		atkbd->release = true;
486c4c7eac8SDmitry Torokhov 		return;
4870ae051a1SDmitry Torokhov 	case ATKBD_RET_ACK:
4880ae051a1SDmitry Torokhov 	case ATKBD_RET_NAK:
4899f7a60d6SQi Yong 		if (printk_ratelimit())
490a9a1f9c3SDmitry Torokhov 			dev_warn(&serio->dev,
491a9a1f9c3SDmitry Torokhov 				 "Spurious %s on %s. "
492f57fe78eSJesper Juhl 				 "Some program might be trying to access hardware directly.\n",
4930ae051a1SDmitry Torokhov 				 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
494c4c7eac8SDmitry Torokhov 		return;
4951da177e4SLinus Torvalds 	case ATKBD_RET_ERR:
49686255d9dSDmitry Torokhov 		atkbd->err_count++;
497a9a1f9c3SDmitry Torokhov 		dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
498a9a1f9c3SDmitry Torokhov 			serio->phys);
499c4c7eac8SDmitry Torokhov 		return;
5001da177e4SLinus Torvalds 	}
5011da177e4SLinus Torvalds 
5020ae051a1SDmitry Torokhov 	code = atkbd_compat_scancode(atkbd, code);
5030ae051a1SDmitry Torokhov 
5040ae051a1SDmitry Torokhov 	if (atkbd->emul && --atkbd->emul)
505c4c7eac8SDmitry Torokhov 		return;
5061da177e4SLinus Torvalds 
5070ae051a1SDmitry Torokhov 	keycode = atkbd->keycode[code];
5081da177e4SLinus Torvalds 
5095447326fSStefan Brüns 	if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
5100ae051a1SDmitry Torokhov 		if (keycode != ATKBD_KEY_NULL)
5110ae051a1SDmitry Torokhov 			input_event(dev, EV_MSC, MSC_SCAN, code);
5120ae051a1SDmitry Torokhov 
5130ae051a1SDmitry Torokhov 	switch (keycode) {
5141da177e4SLinus Torvalds 	case ATKBD_KEY_NULL:
5151da177e4SLinus Torvalds 		break;
5161da177e4SLinus Torvalds 	case ATKBD_KEY_UNKNOWN:
517a9a1f9c3SDmitry Torokhov 		dev_warn(&serio->dev,
518a9a1f9c3SDmitry Torokhov 			 "Unknown key %s (%s set %d, code %#x on %s).\n",
5191da177e4SLinus Torvalds 			 atkbd->release ? "released" : "pressed",
5201da177e4SLinus Torvalds 			 atkbd->translated ? "translated" : "raw",
5211da177e4SLinus Torvalds 			 atkbd->set, code, serio->phys);
522a9a1f9c3SDmitry Torokhov 		dev_warn(&serio->dev,
523a9a1f9c3SDmitry Torokhov 			 "Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
5241da177e4SLinus Torvalds 			 code & 0x80 ? "e0" : "", code & 0x7f);
5250ae051a1SDmitry Torokhov 		input_sync(dev);
5261da177e4SLinus Torvalds 		break;
5271da177e4SLinus Torvalds 	case ATKBD_SCR_1:
528a9a1f9c3SDmitry Torokhov 		scroll = 1;
5291da177e4SLinus Torvalds 		break;
5301da177e4SLinus Torvalds 	case ATKBD_SCR_2:
531a9a1f9c3SDmitry Torokhov 		scroll = 2;
5321da177e4SLinus Torvalds 		break;
5331da177e4SLinus Torvalds 	case ATKBD_SCR_4:
534a9a1f9c3SDmitry Torokhov 		scroll = 4;
5351da177e4SLinus Torvalds 		break;
5361da177e4SLinus Torvalds 	case ATKBD_SCR_8:
537a9a1f9c3SDmitry Torokhov 		scroll = 8;
5381da177e4SLinus Torvalds 		break;
5391da177e4SLinus Torvalds 	case ATKBD_SCR_CLICK:
5401da177e4SLinus Torvalds 		click = !atkbd->release;
5411da177e4SLinus Torvalds 		break;
5421da177e4SLinus Torvalds 	case ATKBD_SCR_LEFT:
5431da177e4SLinus Torvalds 		hscroll = -1;
5441da177e4SLinus Torvalds 		break;
5451da177e4SLinus Torvalds 	case ATKBD_SCR_RIGHT:
5461da177e4SLinus Torvalds 		hscroll = 1;
5471da177e4SLinus Torvalds 		break;
5481da177e4SLinus Torvalds 	default:
5490ae051a1SDmitry Torokhov 		if (atkbd->release) {
5500ae051a1SDmitry Torokhov 			value = 0;
5511da177e4SLinus Torvalds 			atkbd->last = 0;
5520ae051a1SDmitry Torokhov 		} else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
5530ae051a1SDmitry Torokhov 			/* Workaround Toshiba laptop multiple keypress */
5540ae051a1SDmitry Torokhov 			value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
5550ae051a1SDmitry Torokhov 		} else {
5561da177e4SLinus Torvalds 			value = 1;
5570ae051a1SDmitry Torokhov 			atkbd->last = code;
5580ae051a1SDmitry Torokhov 			atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
5591da177e4SLinus Torvalds 		}
5601da177e4SLinus Torvalds 
561f8b4c46cSDmitry Torokhov 		input_event(dev, EV_KEY, keycode, value);
5620ae051a1SDmitry Torokhov 		input_sync(dev);
5630ae051a1SDmitry Torokhov 
564554101e3SGiel de Nijs 		if (value && test_bit(code, atkbd->force_release_mask)) {
5655447326fSStefan Brüns 			input_event(dev, EV_MSC, MSC_SCAN, code);
5660ae051a1SDmitry Torokhov 			input_report_key(dev, keycode, 0);
5670ae051a1SDmitry Torokhov 			input_sync(dev);
5680ae051a1SDmitry Torokhov 		}
5691da177e4SLinus Torvalds 	}
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds 	if (atkbd->scroll) {
5721da177e4SLinus Torvalds 		if (click != -1)
5730ae051a1SDmitry Torokhov 			input_report_key(dev, BTN_MIDDLE, click);
574a9a1f9c3SDmitry Torokhov 		input_report_rel(dev, REL_WHEEL,
575a9a1f9c3SDmitry Torokhov 				 atkbd->release ? -scroll : scroll);
5760ae051a1SDmitry Torokhov 		input_report_rel(dev, REL_HWHEEL, hscroll);
5770ae051a1SDmitry Torokhov 		input_sync(dev);
5781da177e4SLinus Torvalds 	}
5791da177e4SLinus Torvalds 
580a9a1f9c3SDmitry Torokhov 	atkbd->release = false;
5811da177e4SLinus Torvalds }
5821da177e4SLinus Torvalds 
atkbd_set_repeat_rate(struct atkbd * atkbd)5833d0f0fa0SDmitry Torokhov static int atkbd_set_repeat_rate(struct atkbd *atkbd)
5841da177e4SLinus Torvalds {
5851da177e4SLinus Torvalds 	const short period[32] =
5861da177e4SLinus Torvalds 		{ 33,  37,  42,  46,  50,  54,  58,  63,  67,  75,  83,  92, 100, 109, 116, 125,
5871da177e4SLinus Torvalds 		 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
5881da177e4SLinus Torvalds 	const short delay[4] =
5891da177e4SLinus Torvalds 		{ 250, 500, 750, 1000 };
5900d4c8597SDmitry Torokhov 
5913d0f0fa0SDmitry Torokhov 	struct input_dev *dev = atkbd->dev;
5923d0f0fa0SDmitry Torokhov 	unsigned char param;
5933d0f0fa0SDmitry Torokhov 	int i = 0, j = 0;
5943d0f0fa0SDmitry Torokhov 
5953d0f0fa0SDmitry Torokhov 	while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
5963d0f0fa0SDmitry Torokhov 		i++;
5973d0f0fa0SDmitry Torokhov 	dev->rep[REP_PERIOD] = period[i];
5983d0f0fa0SDmitry Torokhov 
5998ea371fbSFlorin Malita 	while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY])
6003d0f0fa0SDmitry Torokhov 		j++;
6013d0f0fa0SDmitry Torokhov 	dev->rep[REP_DELAY] = delay[j];
6023d0f0fa0SDmitry Torokhov 
6033d0f0fa0SDmitry Torokhov 	param = i | (j << 5);
6043d0f0fa0SDmitry Torokhov 	return ps2_command(&atkbd->ps2dev, &param, ATKBD_CMD_SETREP);
6053d0f0fa0SDmitry Torokhov }
6063d0f0fa0SDmitry Torokhov 
atkbd_set_leds(struct atkbd * atkbd)6073d0f0fa0SDmitry Torokhov static int atkbd_set_leds(struct atkbd *atkbd)
6083d0f0fa0SDmitry Torokhov {
6090d4c8597SDmitry Torokhov 	struct input_dev *dev = atkbd->dev;
6101da177e4SLinus Torvalds 	unsigned char param[2];
6111da177e4SLinus Torvalds 
6121da177e4SLinus Torvalds 	param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
6131da177e4SLinus Torvalds 		 | (test_bit(LED_NUML,    dev->led) ? 2 : 0)
6141da177e4SLinus Torvalds 		 | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);
6153d0f0fa0SDmitry Torokhov 	if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
6163d0f0fa0SDmitry Torokhov 		return -1;
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds 	if (atkbd->extra) {
6191da177e4SLinus Torvalds 		param[0] = 0;
6201da177e4SLinus Torvalds 		param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
6211da177e4SLinus Torvalds 			 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
6221da177e4SLinus Torvalds 			 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
6231da177e4SLinus Torvalds 			 | (test_bit(LED_MISC,    dev->led) ? 0x10 : 0)
6241da177e4SLinus Torvalds 			 | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);
6253d0f0fa0SDmitry Torokhov 		if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS))
6263d0f0fa0SDmitry Torokhov 			return -1;
6271da177e4SLinus Torvalds 	}
6281da177e4SLinus Torvalds 
6293d0f0fa0SDmitry Torokhov 	return 0;
6300d4c8597SDmitry Torokhov }
6310d4c8597SDmitry Torokhov 
6323d0f0fa0SDmitry Torokhov /*
6333d0f0fa0SDmitry Torokhov  * atkbd_event_work() is used to complete processing of events that
6343d0f0fa0SDmitry Torokhov  * can not be processed by input_event() which is often called from
6353d0f0fa0SDmitry Torokhov  * interrupt context.
6363d0f0fa0SDmitry Torokhov  */
6373d0f0fa0SDmitry Torokhov 
atkbd_event_work(struct work_struct * work)63865f27f38SDavid Howells static void atkbd_event_work(struct work_struct *work)
6393d0f0fa0SDmitry Torokhov {
640da4249c9SDmitry Torokhov 	struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);
6413d0f0fa0SDmitry Torokhov 
64259b01513SEric W. Biederman 	mutex_lock(&atkbd->mutex);
6433d0f0fa0SDmitry Torokhov 
64494dfb0d6SDmitry Torokhov 	if (!atkbd->enabled) {
64594dfb0d6SDmitry Torokhov 		/*
64694dfb0d6SDmitry Torokhov 		 * Serio ports are resumed asynchronously so while driver core
64794dfb0d6SDmitry Torokhov 		 * thinks that device is already fully operational in reality
64894dfb0d6SDmitry Torokhov 		 * it may not be ready yet. In this case we need to keep
64994dfb0d6SDmitry Torokhov 		 * rescheduling till reconnect completes.
65094dfb0d6SDmitry Torokhov 		 */
65194dfb0d6SDmitry Torokhov 		schedule_delayed_work(&atkbd->event_work,
65294dfb0d6SDmitry Torokhov 					msecs_to_jiffies(100));
65394dfb0d6SDmitry Torokhov 	} else {
6543d0f0fa0SDmitry Torokhov 		if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
6553d0f0fa0SDmitry Torokhov 			atkbd_set_leds(atkbd);
6563d0f0fa0SDmitry Torokhov 
6573d0f0fa0SDmitry Torokhov 		if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
6583d0f0fa0SDmitry Torokhov 			atkbd_set_repeat_rate(atkbd);
65994dfb0d6SDmitry Torokhov 	}
6603d0f0fa0SDmitry Torokhov 
66159b01513SEric W. Biederman 	mutex_unlock(&atkbd->mutex);
6620d4c8597SDmitry Torokhov }
6630d4c8597SDmitry Torokhov 
6640d4c8597SDmitry Torokhov /*
665da4249c9SDmitry Torokhov  * Schedule switch for execution. We need to throttle requests,
666da4249c9SDmitry Torokhov  * otherwise keyboard may become unresponsive.
667da4249c9SDmitry Torokhov  */
atkbd_schedule_event_work(struct atkbd * atkbd,int event_bit)668da4249c9SDmitry Torokhov static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
669da4249c9SDmitry Torokhov {
670da4249c9SDmitry Torokhov 	unsigned long delay = msecs_to_jiffies(50);
671da4249c9SDmitry Torokhov 
672da4249c9SDmitry Torokhov 	if (time_after(jiffies, atkbd->event_jiffies + delay))
673da4249c9SDmitry Torokhov 		delay = 0;
674da4249c9SDmitry Torokhov 
675da4249c9SDmitry Torokhov 	atkbd->event_jiffies = jiffies;
676da4249c9SDmitry Torokhov 	set_bit(event_bit, &atkbd->event_mask);
67759b01513SEric W. Biederman 	mb();
678da4249c9SDmitry Torokhov 	schedule_delayed_work(&atkbd->event_work, delay);
679da4249c9SDmitry Torokhov }
680da4249c9SDmitry Torokhov 
681da4249c9SDmitry Torokhov /*
6820d4c8597SDmitry Torokhov  * Event callback from the input module. Events that change the state of
6830d4c8597SDmitry Torokhov  * the hardware are processed here. If action can not be performed in
6840d4c8597SDmitry Torokhov  * interrupt context it is offloaded to atkbd_event_work.
6850d4c8597SDmitry Torokhov  */
6860d4c8597SDmitry Torokhov 
atkbd_event(struct input_dev * dev,unsigned int type,unsigned int code,int value)687da4249c9SDmitry Torokhov static int atkbd_event(struct input_dev *dev,
688da4249c9SDmitry Torokhov 			unsigned int type, unsigned int code, int value)
6890d4c8597SDmitry Torokhov {
690b356872fSDmitry Torokhov 	struct atkbd *atkbd = input_get_drvdata(dev);
6910d4c8597SDmitry Torokhov 
6920d4c8597SDmitry Torokhov 	if (!atkbd->write)
6930d4c8597SDmitry Torokhov 		return -1;
6940d4c8597SDmitry Torokhov 
6950d4c8597SDmitry Torokhov 	switch (type) {
6960d4c8597SDmitry Torokhov 
6970d4c8597SDmitry Torokhov 	case EV_LED:
698da4249c9SDmitry Torokhov 		atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
6990d4c8597SDmitry Torokhov 		return 0;
7000d4c8597SDmitry Torokhov 
7010d4c8597SDmitry Torokhov 	case EV_REP:
702da4249c9SDmitry Torokhov 		if (!atkbd->softrepeat)
703da4249c9SDmitry Torokhov 			atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
7041da177e4SLinus Torvalds 		return 0;
7051da177e4SLinus Torvalds 
706a9a1f9c3SDmitry Torokhov 	default:
7071da177e4SLinus Torvalds 		return -1;
7081da177e4SLinus Torvalds 	}
709a9a1f9c3SDmitry Torokhov }
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds /*
7121da177e4SLinus Torvalds  * atkbd_enable() signals that interrupt handler is allowed to
7131da177e4SLinus Torvalds  * generate input events.
7141da177e4SLinus Torvalds  */
7151da177e4SLinus Torvalds 
atkbd_enable(struct atkbd * atkbd)7161da177e4SLinus Torvalds static inline void atkbd_enable(struct atkbd *atkbd)
7171da177e4SLinus Torvalds {
7181da177e4SLinus Torvalds 	serio_pause_rx(atkbd->ps2dev.serio);
719a9a1f9c3SDmitry Torokhov 	atkbd->enabled = true;
7201da177e4SLinus Torvalds 	serio_continue_rx(atkbd->ps2dev.serio);
7211da177e4SLinus Torvalds }
7221da177e4SLinus Torvalds 
7231da177e4SLinus Torvalds /*
7241da177e4SLinus Torvalds  * atkbd_disable() tells input handler that all incoming data except
7251da177e4SLinus Torvalds  * for ACKs and command response should be dropped.
7261da177e4SLinus Torvalds  */
7271da177e4SLinus Torvalds 
atkbd_disable(struct atkbd * atkbd)7281da177e4SLinus Torvalds static inline void atkbd_disable(struct atkbd *atkbd)
7291da177e4SLinus Torvalds {
7301da177e4SLinus Torvalds 	serio_pause_rx(atkbd->ps2dev.serio);
731a9a1f9c3SDmitry Torokhov 	atkbd->enabled = false;
7321da177e4SLinus Torvalds 	serio_continue_rx(atkbd->ps2dev.serio);
7331da177e4SLinus Torvalds }
7341da177e4SLinus Torvalds 
atkbd_activate(struct atkbd * atkbd)735be2d7e42SShawn Nematbakhsh static int atkbd_activate(struct atkbd *atkbd)
736be2d7e42SShawn Nematbakhsh {
737be2d7e42SShawn Nematbakhsh 	struct ps2dev *ps2dev = &atkbd->ps2dev;
738be2d7e42SShawn Nematbakhsh 
739be2d7e42SShawn Nematbakhsh /*
740be2d7e42SShawn Nematbakhsh  * Enable the keyboard to receive keystrokes.
741be2d7e42SShawn Nematbakhsh  */
742be2d7e42SShawn Nematbakhsh 
743be2d7e42SShawn Nematbakhsh 	if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
744be2d7e42SShawn Nematbakhsh 		dev_err(&ps2dev->serio->dev,
745be2d7e42SShawn Nematbakhsh 			"Failed to enable keyboard on %s\n",
746be2d7e42SShawn Nematbakhsh 			ps2dev->serio->phys);
747be2d7e42SShawn Nematbakhsh 		return -1;
748be2d7e42SShawn Nematbakhsh 	}
749be2d7e42SShawn Nematbakhsh 
750be2d7e42SShawn Nematbakhsh 	return 0;
751be2d7e42SShawn Nematbakhsh }
752be2d7e42SShawn Nematbakhsh 
753be2d7e42SShawn Nematbakhsh /*
754be2d7e42SShawn Nematbakhsh  * atkbd_deactivate() resets and disables the keyboard from sending
755be2d7e42SShawn Nematbakhsh  * keystrokes.
756be2d7e42SShawn Nematbakhsh  */
757be2d7e42SShawn Nematbakhsh 
atkbd_deactivate(struct atkbd * atkbd)758be2d7e42SShawn Nematbakhsh static void atkbd_deactivate(struct atkbd *atkbd)
759be2d7e42SShawn Nematbakhsh {
760be2d7e42SShawn Nematbakhsh 	struct ps2dev *ps2dev = &atkbd->ps2dev;
761be2d7e42SShawn Nematbakhsh 
762be2d7e42SShawn Nematbakhsh 	if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS))
763be2d7e42SShawn Nematbakhsh 		dev_err(&ps2dev->serio->dev,
764be2d7e42SShawn Nematbakhsh 			"Failed to deactivate keyboard on %s\n",
765be2d7e42SShawn Nematbakhsh 			ps2dev->serio->phys);
766be2d7e42SShawn Nematbakhsh }
767be2d7e42SShawn Nematbakhsh 
768936e4d49SHans de Goede #ifdef CONFIG_X86
atkbd_is_portable_device(void)769936e4d49SHans de Goede static bool atkbd_is_portable_device(void)
770936e4d49SHans de Goede {
771936e4d49SHans de Goede 	static const char * const chassis_types[] = {
772936e4d49SHans de Goede 		"8",	/* Portable */
773936e4d49SHans de Goede 		"9",	/* Laptop */
774936e4d49SHans de Goede 		"10",	/* Notebook */
775936e4d49SHans de Goede 		"14",	/* Sub-Notebook */
776936e4d49SHans de Goede 		"31",	/* Convertible */
777936e4d49SHans de Goede 		"32",	/* Detachable */
778936e4d49SHans de Goede 	};
779936e4d49SHans de Goede 	int i;
780936e4d49SHans de Goede 
781936e4d49SHans de Goede 	for (i = 0; i < ARRAY_SIZE(chassis_types); i++)
782936e4d49SHans de Goede 		if (dmi_match(DMI_CHASSIS_TYPE, chassis_types[i]))
783936e4d49SHans de Goede 			return true;
784936e4d49SHans de Goede 
785936e4d49SHans de Goede 	return false;
786936e4d49SHans de Goede }
787936e4d49SHans de Goede 
788936e4d49SHans de Goede /*
789936e4d49SHans de Goede  * On many modern laptops ATKBD_CMD_GETID may cause problems, on these laptops
790936e4d49SHans de Goede  * the controller is always in translated mode. In this mode mice/touchpads will
791936e4d49SHans de Goede  * not work. So in this case simply assume a keyboard is connected to avoid
792936e4d49SHans de Goede  * confusing some laptop keyboards.
793936e4d49SHans de Goede  *
79458f65f9dSHans de Goede  * Skipping ATKBD_CMD_GETID ends up using a fake keyboard id. Using the standard
79558f65f9dSHans de Goede  * 0xab83 id is ok in translated mode, only atkbd_select_set() checks atkbd->id
79658f65f9dSHans de Goede  * and in translated mode that is a no-op.
797936e4d49SHans de Goede  */
atkbd_skip_getid(struct atkbd * atkbd)798936e4d49SHans de Goede static bool atkbd_skip_getid(struct atkbd *atkbd)
799936e4d49SHans de Goede {
800936e4d49SHans de Goede 	return atkbd->translated && atkbd_is_portable_device();
801936e4d49SHans de Goede }
802936e4d49SHans de Goede #else
atkbd_skip_getid(struct atkbd * atkbd)803936e4d49SHans de Goede static inline bool atkbd_skip_getid(struct atkbd *atkbd) { return false; }
804936e4d49SHans de Goede #endif
805936e4d49SHans de Goede 
8061da177e4SLinus Torvalds /*
8071da177e4SLinus Torvalds  * atkbd_probe() probes for an AT keyboard on a serio port.
8081da177e4SLinus Torvalds  */
8091da177e4SLinus Torvalds 
atkbd_probe(struct atkbd * atkbd)8101da177e4SLinus Torvalds static int atkbd_probe(struct atkbd *atkbd)
8111da177e4SLinus Torvalds {
8121da177e4SLinus Torvalds 	struct ps2dev *ps2dev = &atkbd->ps2dev;
8131da177e4SLinus Torvalds 	unsigned char param[2];
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds /*
8161da177e4SLinus Torvalds  * Some systems, where the bit-twiddling when testing the io-lines of the
8171da177e4SLinus Torvalds  * controller may confuse the keyboard need a full reset of the keyboard. On
8181da177e4SLinus Torvalds  * these systems the BIOS also usually doesn't do it for us.
8191da177e4SLinus Torvalds  */
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 	if (atkbd_reset)
8221da177e4SLinus Torvalds 		if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
823a9a1f9c3SDmitry Torokhov 			dev_warn(&ps2dev->serio->dev,
824a9a1f9c3SDmitry Torokhov 				 "keyboard reset failed on %s\n",
825a9a1f9c3SDmitry Torokhov 				 ps2dev->serio->phys);
8261da177e4SLinus Torvalds 
827683cd825SHans de Goede 	if (atkbd_skip_getid(atkbd)) {
828683cd825SHans de Goede 		atkbd->id = 0xab83;
8299cf6e24cSHans de Goede 		goto deactivate_kbd;
830683cd825SHans de Goede 	}
831683cd825SHans de Goede 
8321da177e4SLinus Torvalds /*
8331da177e4SLinus Torvalds  * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
8341da177e4SLinus Torvalds  * Some keyboards report different values, but the first byte is always 0xab or
8351da177e4SLinus Torvalds  * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this
8361da177e4SLinus Torvalds  * should make sure we don't try to set the LEDs on it.
8371da177e4SLinus Torvalds  */
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	param[0] = param[1] = 0xa5;	/* initialize with invalid values */
840683cd825SHans de Goede 	if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds /*
843683cd825SHans de Goede  * If the get ID command failed, we check if we can at least set
844936e4d49SHans de Goede  * the LEDs on the keyboard. This should work on every keyboard out there.
845936e4d49SHans de Goede  * It also turns the LEDs off, which we want anyway.
8461da177e4SLinus Torvalds  */
8471da177e4SLinus Torvalds 		param[0] = 0;
8481da177e4SLinus Torvalds 		if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
8491da177e4SLinus Torvalds 			return -1;
850683cd825SHans de Goede 		atkbd->id = 0xabba;
8511da177e4SLinus Torvalds 		return 0;
8521da177e4SLinus Torvalds 	}
8531da177e4SLinus Torvalds 
8549807879bSDmitry Torokhov 	if (!ps2_is_keyboard_id(param[0]))
8551da177e4SLinus Torvalds 		return -1;
8561da177e4SLinus Torvalds 
8571da177e4SLinus Torvalds 	atkbd->id = (param[0] << 8) | param[1];
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds 	if (atkbd->id == 0xaca1 && atkbd->translated) {
860a9a1f9c3SDmitry Torokhov 		dev_err(&ps2dev->serio->dev,
861236d6a77SDmitry Torokhov 			"NCD terminal keyboards are only supported on non-translating controllers. "
862a9a1f9c3SDmitry Torokhov 			"Use i8042.direct=1 to disable translation.\n");
8631da177e4SLinus Torvalds 		return -1;
8641da177e4SLinus Torvalds 	}
8651da177e4SLinus Torvalds 
8669cf6e24cSHans de Goede deactivate_kbd:
867be2d7e42SShawn Nematbakhsh /*
868be2d7e42SShawn Nematbakhsh  * Make sure nothing is coming from the keyboard and disturbs our
869be2d7e42SShawn Nematbakhsh  * internal state.
870be2d7e42SShawn Nematbakhsh  */
8713d725caaSSheng-Liang Song 	if (!atkbd_skip_deactivate)
872be2d7e42SShawn Nematbakhsh 		atkbd_deactivate(atkbd);
873be2d7e42SShawn Nematbakhsh 
8741da177e4SLinus Torvalds 	return 0;
8751da177e4SLinus Torvalds }
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds /*
8781da177e4SLinus Torvalds  * atkbd_select_set checks if a keyboard has a working Set 3 support, and
8791da177e4SLinus Torvalds  * sets it into that. Unfortunately there are keyboards that can be switched
8801da177e4SLinus Torvalds  * to Set 3, but don't work well in that (BTC Multimedia ...)
8811da177e4SLinus Torvalds  */
8821da177e4SLinus Torvalds 
atkbd_select_set(struct atkbd * atkbd,int target_set,int allow_extra)8831da177e4SLinus Torvalds static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
8841da177e4SLinus Torvalds {
8851da177e4SLinus Torvalds 	struct ps2dev *ps2dev = &atkbd->ps2dev;
8861da177e4SLinus Torvalds 	unsigned char param[2];
8871da177e4SLinus Torvalds 
888a9a1f9c3SDmitry Torokhov 	atkbd->extra = false;
8891da177e4SLinus Torvalds /*
8901da177e4SLinus Torvalds  * For known special keyboards we can go ahead and set the correct set.
8911da177e4SLinus Torvalds  * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
8921da177e4SLinus Torvalds  * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards.
8931da177e4SLinus Torvalds  */
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds 	if (atkbd->translated)
8961da177e4SLinus Torvalds 		return 2;
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds 	if (atkbd->id == 0xaca1) {
8991da177e4SLinus Torvalds 		param[0] = 3;
9001da177e4SLinus Torvalds 		ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
9011da177e4SLinus Torvalds 		return 3;
9021da177e4SLinus Torvalds 	}
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds 	if (allow_extra) {
9051da177e4SLinus Torvalds 		param[0] = 0x71;
9061da177e4SLinus Torvalds 		if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
907a9a1f9c3SDmitry Torokhov 			atkbd->extra = true;
9081da177e4SLinus Torvalds 			return 2;
9091da177e4SLinus Torvalds 		}
9101da177e4SLinus Torvalds 	}
9111da177e4SLinus Torvalds 
9128c5188b6SBenjamin LaHaise 	if (atkbd_terminal) {
9138c5188b6SBenjamin LaHaise 		ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB);
9148c5188b6SBenjamin LaHaise 		return 3;
9158c5188b6SBenjamin LaHaise 	}
9168c5188b6SBenjamin LaHaise 
9171da177e4SLinus Torvalds 	if (target_set != 3)
9181da177e4SLinus Torvalds 		return 2;
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 	if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {
9211da177e4SLinus Torvalds 		atkbd->id = param[0] << 8 | param[1];
9221da177e4SLinus Torvalds 		return 2;
9231da177e4SLinus Torvalds 	}
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds 	param[0] = 3;
9261da177e4SLinus Torvalds 	if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
9271da177e4SLinus Torvalds 		return 2;
9281da177e4SLinus Torvalds 
9291da177e4SLinus Torvalds 	param[0] = 0;
9301da177e4SLinus Torvalds 	if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
9311da177e4SLinus Torvalds 		return 2;
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds 	if (param[0] != 3) {
9341da177e4SLinus Torvalds 		param[0] = 2;
9351da177e4SLinus Torvalds 		if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
9361da177e4SLinus Torvalds 			return 2;
9371da177e4SLinus Torvalds 	}
9381da177e4SLinus Torvalds 
9391da177e4SLinus Torvalds 	ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 	return 3;
9421da177e4SLinus Torvalds }
9431da177e4SLinus Torvalds 
atkbd_reset_state(struct atkbd * atkbd)944fc0eb28cSDmitry Torokhov static int atkbd_reset_state(struct atkbd *atkbd)
945fc0eb28cSDmitry Torokhov {
946fc0eb28cSDmitry Torokhov         struct ps2dev *ps2dev = &atkbd->ps2dev;
947fc0eb28cSDmitry Torokhov 	unsigned char param[1];
948fc0eb28cSDmitry Torokhov 
949fc0eb28cSDmitry Torokhov /*
950fc0eb28cSDmitry Torokhov  * Set the LEDs to a predefined state (all off).
951fc0eb28cSDmitry Torokhov  */
952fc0eb28cSDmitry Torokhov 
953fc0eb28cSDmitry Torokhov 	param[0] = 0;
954fc0eb28cSDmitry Torokhov 	if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
955fc0eb28cSDmitry Torokhov 		return -1;
956fc0eb28cSDmitry Torokhov 
957fc0eb28cSDmitry Torokhov /*
958fc0eb28cSDmitry Torokhov  * Set autorepeat to fastest possible.
959fc0eb28cSDmitry Torokhov  */
960fc0eb28cSDmitry Torokhov 
961fc0eb28cSDmitry Torokhov 	param[0] = 0;
962fc0eb28cSDmitry Torokhov 	if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
963fc0eb28cSDmitry Torokhov 		return -1;
964fc0eb28cSDmitry Torokhov 
965fc0eb28cSDmitry Torokhov 	return 0;
966fc0eb28cSDmitry Torokhov }
967fc0eb28cSDmitry Torokhov 
9681da177e4SLinus Torvalds /*
9691da177e4SLinus Torvalds  * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
9701da177e4SLinus Torvalds  * reboot.
9711da177e4SLinus Torvalds  */
9721da177e4SLinus Torvalds 
atkbd_cleanup(struct serio * serio)9731da177e4SLinus Torvalds static void atkbd_cleanup(struct serio *serio)
9741da177e4SLinus Torvalds {
975100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
97657f5b159SDmitry Torokhov 
97757f5b159SDmitry Torokhov 	atkbd_disable(atkbd);
9784a299bf5SDmitry Torokhov 	ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF);
9791da177e4SLinus Torvalds }
9801da177e4SLinus Torvalds 
9811da177e4SLinus Torvalds 
9821da177e4SLinus Torvalds /*
9831da177e4SLinus Torvalds  * atkbd_disconnect() closes and frees.
9841da177e4SLinus Torvalds  */
9851da177e4SLinus Torvalds 
atkbd_disconnect(struct serio * serio)9861da177e4SLinus Torvalds static void atkbd_disconnect(struct serio *serio)
9871da177e4SLinus Torvalds {
988100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
9891da177e4SLinus Torvalds 
9901da177e4SLinus Torvalds 	atkbd_disable(atkbd);
9911da177e4SLinus Torvalds 
9920ef7a26aSDmitry Torokhov 	input_unregister_device(atkbd->dev);
9930ef7a26aSDmitry Torokhov 
9940ef7a26aSDmitry Torokhov 	/*
9950ef7a26aSDmitry Torokhov 	 * Make sure we don't have a command in flight.
9960ef7a26aSDmitry Torokhov 	 * Note that since atkbd->enabled is false event work will keep
9970ef7a26aSDmitry Torokhov 	 * rescheduling itself until it gets canceled and will not try
9980ef7a26aSDmitry Torokhov 	 * accessing freed input device or serio port.
9990ef7a26aSDmitry Torokhov 	 */
1000d6d79a78SJiri Pirko 	cancel_delayed_work_sync(&atkbd->event_work);
10011da177e4SLinus Torvalds 
10021da177e4SLinus Torvalds 	serio_close(serio);
10031da177e4SLinus Torvalds 	serio_set_drvdata(serio, NULL);
10041da177e4SLinus Torvalds 	kfree(atkbd);
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds 
1007554101e3SGiel de Nijs /*
100839191698SDaniel Mierswa  * generate release events for the keycodes given in data
100939191698SDaniel Mierswa  */
atkbd_apply_forced_release_keylist(struct atkbd * atkbd,const void * data)101039191698SDaniel Mierswa static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd,
101139191698SDaniel Mierswa 						const void *data)
101239191698SDaniel Mierswa {
101339191698SDaniel Mierswa 	const unsigned int *keys = data;
101439191698SDaniel Mierswa 	unsigned int i;
101539191698SDaniel Mierswa 
101639191698SDaniel Mierswa 	if (atkbd->set == 2)
101739191698SDaniel Mierswa 		for (i = 0; keys[i] != -1U; i++)
101839191698SDaniel Mierswa 			__set_bit(keys[i], atkbd->force_release_mask);
101939191698SDaniel Mierswa }
102039191698SDaniel Mierswa 
102139191698SDaniel Mierswa /*
102261579ba8SMatthew Garrett  * Most special keys (Fn+F?) on Dell laptops do not generate release
1023554101e3SGiel de Nijs  * events so we have to do it ourselves.
1024554101e3SGiel de Nijs  */
102539191698SDaniel Mierswa static unsigned int atkbd_dell_laptop_forced_release_keys[] = {
102639191698SDaniel Mierswa 	0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U
1027554101e3SGiel de Nijs };
10281da177e4SLinus Torvalds 
10291da177e4SLinus Torvalds /*
10305a54c011SJiri Kosina  * Perform fixup for HP system that doesn't generate release
10315a54c011SJiri Kosina  * for its video switch
10325a54c011SJiri Kosina  */
103339191698SDaniel Mierswa static unsigned int atkbd_hp_forced_release_keys[] = {
103439191698SDaniel Mierswa 	0x94, -1U
10355a54c011SJiri Kosina };
10365a54c011SJiri Kosina 
10375a54c011SJiri Kosina /*
1038e04126c7SBarry Carroll  * Samsung NC10,NC20 with Fn+F? key release not working
10394200844bSStuart Hopkins  */
104039191698SDaniel Mierswa static unsigned int atkbd_samsung_forced_release_keys[] = {
104139191698SDaniel Mierswa 	0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U
10424200844bSStuart Hopkins };
10434200844bSStuart Hopkins 
10444200844bSStuart Hopkins /*
1045f0a14de2SSimon Davie  * Amilo Pi 3525 key release for Fn+Volume keys not working
1046f0a14de2SSimon Davie  */
1047f0a14de2SSimon Davie static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = {
1048f0a14de2SSimon Davie 	0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U
1049f0a14de2SSimon Davie };
1050f0a14de2SSimon Davie 
1051f0a14de2SSimon Davie /*
10529166d0f6SAdrian Batzill  * Amilo Xi 3650 key release for light touch bar not working
10539166d0f6SAdrian Batzill  */
10549166d0f6SAdrian Batzill static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = {
10559166d0f6SAdrian Batzill 	0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U
10569166d0f6SAdrian Batzill };
10579166d0f6SAdrian Batzill 
10589166d0f6SAdrian Batzill /*
1059032e46cbSJerone Young  * Soltech TA12 system with broken key release on volume keys and mute key
1060032e46cbSJerone Young  */
1061032e46cbSJerone Young static unsigned int atkdb_soltech_ta12_forced_release_keys[] = {
1062032e46cbSJerone Young 	0xa0, 0xae, 0xb0, -1U
1063032e46cbSJerone Young };
1064032e46cbSJerone Young 
1065032e46cbSJerone Young /*
1066000c2a35SHerton Ronaldo Krzesinski  * Many notebooks don't send key release event for volume up/down
1067000c2a35SHerton Ronaldo Krzesinski  * keys, with key list below common among them
1068000c2a35SHerton Ronaldo Krzesinski  */
1069000c2a35SHerton Ronaldo Krzesinski static unsigned int atkbd_volume_forced_release_keys[] = {
1070000c2a35SHerton Ronaldo Krzesinski 	0xae, 0xb0, -1U
1071000c2a35SHerton Ronaldo Krzesinski };
1072000c2a35SHerton Ronaldo Krzesinski 
1073000c2a35SHerton Ronaldo Krzesinski /*
1074e5713069SJamie Lentin  * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas
1075e5713069SJamie Lentin  * they should be generating e4-e6 (0x80 | code).
1076e5713069SJamie Lentin  */
atkbd_oqo_01plus_scancode_fixup(struct atkbd * atkbd,unsigned int code)1077e5713069SJamie Lentin static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
1078e5713069SJamie Lentin 						    unsigned int code)
1079e5713069SJamie Lentin {
1080e5713069SJamie Lentin 	if (atkbd->translated && atkbd->emul == 1 &&
1081e5713069SJamie Lentin 	    (code == 0x64 || code == 0x65 || code == 0x66)) {
1082e5713069SJamie Lentin 		atkbd->emul = 0;
1083e5713069SJamie Lentin 		code |= 0x80;
1084e5713069SJamie Lentin 	}
1085e5713069SJamie Lentin 
1086e5713069SJamie Lentin 	return code;
1087e5713069SJamie Lentin }
1088e5713069SJamie Lentin 
atkbd_get_keymap_from_fwnode(struct atkbd * atkbd)10899d17ad23SRajat Jain static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
10909d17ad23SRajat Jain {
10919d17ad23SRajat Jain 	struct device *dev = &atkbd->ps2dev.serio->dev;
10929d17ad23SRajat Jain 	int i, n;
10939d17ad23SRajat Jain 	u32 *ptr;
10949d17ad23SRajat Jain 	u16 scancode, keycode;
10959d17ad23SRajat Jain 
10969d17ad23SRajat Jain 	/* Parse "linux,keymap" property */
10979d17ad23SRajat Jain 	n = device_property_count_u32(dev, "linux,keymap");
10989d17ad23SRajat Jain 	if (n <= 0 || n > ATKBD_KEYMAP_SIZE)
10999d17ad23SRajat Jain 		return -ENXIO;
11009d17ad23SRajat Jain 
11019d17ad23SRajat Jain 	ptr = kcalloc(n, sizeof(u32), GFP_KERNEL);
11029d17ad23SRajat Jain 	if (!ptr)
11039d17ad23SRajat Jain 		return -ENOMEM;
11049d17ad23SRajat Jain 
11059d17ad23SRajat Jain 	if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) {
11069d17ad23SRajat Jain 		dev_err(dev, "problem parsing FW keymap property\n");
11079d17ad23SRajat Jain 		kfree(ptr);
11089d17ad23SRajat Jain 		return -EINVAL;
11099d17ad23SRajat Jain 	}
11109d17ad23SRajat Jain 
11119d17ad23SRajat Jain 	memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
11129d17ad23SRajat Jain 	for (i = 0; i < n; i++) {
11139d17ad23SRajat Jain 		scancode = SCANCODE(ptr[i]);
11149d17ad23SRajat Jain 		keycode = KEYCODE(ptr[i]);
11159d17ad23SRajat Jain 		atkbd->keycode[scancode] = keycode;
11169d17ad23SRajat Jain 	}
11179d17ad23SRajat Jain 
11189d17ad23SRajat Jain 	kfree(ptr);
11199d17ad23SRajat Jain 	return 0;
11209d17ad23SRajat Jain }
11219d17ad23SRajat Jain 
1122e5713069SJamie Lentin /*
11233c42f0c3SDmitry Torokhov  * atkbd_set_keycode_table() initializes keyboard's keycode table
11241da177e4SLinus Torvalds  * according to the selected scancode set
11251da177e4SLinus Torvalds  */
11261da177e4SLinus Torvalds 
atkbd_set_keycode_table(struct atkbd * atkbd)11271da177e4SLinus Torvalds static void atkbd_set_keycode_table(struct atkbd *atkbd)
11281da177e4SLinus Torvalds {
11299d17ad23SRajat Jain 	struct device *dev = &atkbd->ps2dev.serio->dev;
1130554101e3SGiel de Nijs 	unsigned int scancode;
11311da177e4SLinus Torvalds 	int i, j;
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 	memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
11341ba36e11SDmitry Torokhov 	bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
11351da177e4SLinus Torvalds 
11369d17ad23SRajat Jain 	if (!atkbd_get_keymap_from_fwnode(atkbd)) {
11379d17ad23SRajat Jain 		dev_dbg(dev, "Using FW keymap\n");
11389d17ad23SRajat Jain 	} else if (atkbd->translated) {
11391da177e4SLinus Torvalds 		for (i = 0; i < 128; i++) {
1140554101e3SGiel de Nijs 			scancode = atkbd_unxlate_table[i];
1141554101e3SGiel de Nijs 			atkbd->keycode[i] = atkbd_set2_keycode[scancode];
1142554101e3SGiel de Nijs 			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80];
11431da177e4SLinus Torvalds 			if (atkbd->scroll)
11441da177e4SLinus Torvalds 				for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
1145554101e3SGiel de Nijs 					if ((scancode | 0x80) == atkbd_scroll_keys[j].set2)
11461da177e4SLinus Torvalds 						atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
11471da177e4SLinus Torvalds 		}
11481da177e4SLinus Torvalds 	} else if (atkbd->set == 3) {
11491da177e4SLinus Torvalds 		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
11501da177e4SLinus Torvalds 	} else {
11511da177e4SLinus Torvalds 		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
11521da177e4SLinus Torvalds 
11531da177e4SLinus Torvalds 		if (atkbd->scroll)
1154554101e3SGiel de Nijs 			for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) {
1155554101e3SGiel de Nijs 				scancode = atkbd_scroll_keys[i].set2;
1156554101e3SGiel de Nijs 				atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode;
1157554101e3SGiel de Nijs 		}
11581da177e4SLinus Torvalds 	}
11590ae051a1SDmitry Torokhov 
1160554101e3SGiel de Nijs /*
1161554101e3SGiel de Nijs  * HANGEUL and HANJA keys do not send release events so we need to
1162554101e3SGiel de Nijs  * generate such events ourselves
1163554101e3SGiel de Nijs  */
1164554101e3SGiel de Nijs 	scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL);
1165554101e3SGiel de Nijs 	atkbd->keycode[scancode] = KEY_HANGEUL;
1166554101e3SGiel de Nijs 	__set_bit(scancode, atkbd->force_release_mask);
1167554101e3SGiel de Nijs 
1168554101e3SGiel de Nijs 	scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA);
1169554101e3SGiel de Nijs 	atkbd->keycode[scancode] = KEY_HANJA;
1170554101e3SGiel de Nijs 	__set_bit(scancode, atkbd->force_release_mask);
1171554101e3SGiel de Nijs 
1172554101e3SGiel de Nijs /*
1173554101e3SGiel de Nijs  * Perform additional fixups
1174554101e3SGiel de Nijs  */
1175554101e3SGiel de Nijs 	if (atkbd_platform_fixup)
117639191698SDaniel Mierswa 		atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data);
11771da177e4SLinus Torvalds }
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds /*
11801da177e4SLinus Torvalds  * atkbd_set_device_attrs() sets up keyboard's input device structure
11811da177e4SLinus Torvalds  */
11821da177e4SLinus Torvalds 
atkbd_set_device_attrs(struct atkbd * atkbd)11831da177e4SLinus Torvalds static void atkbd_set_device_attrs(struct atkbd *atkbd)
11841da177e4SLinus Torvalds {
11853c42f0c3SDmitry Torokhov 	struct input_dev *input_dev = atkbd->dev;
11861da177e4SLinus Torvalds 	int i;
11871da177e4SLinus Torvalds 
11883c42f0c3SDmitry Torokhov 	if (atkbd->extra)
1189ea08c6faSDmitry Torokhov 		snprintf(atkbd->name, sizeof(atkbd->name),
1190ea08c6faSDmitry Torokhov 			 "AT Set 2 Extra keyboard");
11913c42f0c3SDmitry Torokhov 	else
1192ea08c6faSDmitry Torokhov 		snprintf(atkbd->name, sizeof(atkbd->name),
1193ea08c6faSDmitry Torokhov 			 "AT %s Set %d keyboard",
11943c42f0c3SDmitry Torokhov 			 atkbd->translated ? "Translated" : "Raw", atkbd->set);
11951da177e4SLinus Torvalds 
1196ea08c6faSDmitry Torokhov 	snprintf(atkbd->phys, sizeof(atkbd->phys),
1197ea08c6faSDmitry Torokhov 		 "%s/input0", atkbd->ps2dev.serio->phys);
11981da177e4SLinus Torvalds 
11993c42f0c3SDmitry Torokhov 	input_dev->name = atkbd->name;
12003c42f0c3SDmitry Torokhov 	input_dev->phys = atkbd->phys;
12013c42f0c3SDmitry Torokhov 	input_dev->id.bustype = BUS_I8042;
12023c42f0c3SDmitry Torokhov 	input_dev->id.vendor = 0x0001;
12033c42f0c3SDmitry Torokhov 	input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
12043c42f0c3SDmitry Torokhov 	input_dev->id.version = atkbd->id;
12053c42f0c3SDmitry Torokhov 	input_dev->event = atkbd_event;
1206469ba4dfSDmitry Torokhov 	input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
12071da177e4SLinus Torvalds 
1208b356872fSDmitry Torokhov 	input_set_drvdata(input_dev, atkbd);
1209b356872fSDmitry Torokhov 
12107b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
12117b19ada2SJiri Slaby 		BIT_MASK(EV_MSC);
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds 	if (atkbd->write) {
12147b19ada2SJiri Slaby 		input_dev->evbit[0] |= BIT_MASK(EV_LED);
12157b19ada2SJiri Slaby 		input_dev->ledbit[0] = BIT_MASK(LED_NUML) |
12167b19ada2SJiri Slaby 			BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL);
12171da177e4SLinus Torvalds 	}
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 	if (atkbd->extra)
12207b19ada2SJiri Slaby 		input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) |
12217b19ada2SJiri Slaby 			BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) |
12227b19ada2SJiri Slaby 			BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC);
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds 	if (!atkbd->softrepeat) {
12253c42f0c3SDmitry Torokhov 		input_dev->rep[REP_DELAY] = 250;
12263c42f0c3SDmitry Torokhov 		input_dev->rep[REP_PERIOD] = 33;
12271da177e4SLinus Torvalds 	}
12281da177e4SLinus Torvalds 
12297b19ada2SJiri Slaby 	input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) :
12307b19ada2SJiri Slaby 		BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);
12311da177e4SLinus Torvalds 
12321da177e4SLinus Torvalds 	if (atkbd->scroll) {
12337b19ada2SJiri Slaby 		input_dev->evbit[0] |= BIT_MASK(EV_REL);
12347b19ada2SJiri Slaby 		input_dev->relbit[0] = BIT_MASK(REL_WHEEL) |
12357b19ada2SJiri Slaby 			BIT_MASK(REL_HWHEEL);
1236f6d65610SDmitry Torokhov 		__set_bit(BTN_MIDDLE, input_dev->keybit);
12371da177e4SLinus Torvalds 	}
12381da177e4SLinus Torvalds 
12393c42f0c3SDmitry Torokhov 	input_dev->keycode = atkbd->keycode;
1240f6d65610SDmitry Torokhov 	input_dev->keycodesize = sizeof(unsigned short);
12413c42f0c3SDmitry Torokhov 	input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
12421da177e4SLinus Torvalds 
12434b70858bSDmitry Torokhov 	for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
12444b70858bSDmitry Torokhov 		if (atkbd->keycode[i] != KEY_RESERVED &&
12454b70858bSDmitry Torokhov 		    atkbd->keycode[i] != ATKBD_KEY_NULL &&
12464b70858bSDmitry Torokhov 		    atkbd->keycode[i] < ATKBD_SPECIAL) {
1247f6d65610SDmitry Torokhov 			__set_bit(atkbd->keycode[i], input_dev->keybit);
12481da177e4SLinus Torvalds 		}
12494b70858bSDmitry Torokhov 	}
12504b70858bSDmitry Torokhov }
12511da177e4SLinus Torvalds 
atkbd_parse_fwnode_data(struct serio * serio)12528f7b057aSRajat Jain static void atkbd_parse_fwnode_data(struct serio *serio)
12538f7b057aSRajat Jain {
1254100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
12558f7b057aSRajat Jain 	struct device *dev = &serio->dev;
12568f7b057aSRajat Jain 	int n;
12578f7b057aSRajat Jain 
12588f7b057aSRajat Jain 	/* Parse "function-row-physmap" property */
12598f7b057aSRajat Jain 	n = device_property_count_u32(dev, "function-row-physmap");
126045ceaf14SStephen Boyd 	if (n > 0 && n <= VIVALDI_MAX_FUNCTION_ROW_KEYS &&
12618f7b057aSRajat Jain 	    !device_property_read_u32_array(dev, "function-row-physmap",
126245ceaf14SStephen Boyd 					    atkbd->vdata.function_row_physmap,
126345ceaf14SStephen Boyd 					    n)) {
126445ceaf14SStephen Boyd 		atkbd->vdata.num_function_row_keys = n;
12658f7b057aSRajat Jain 		dev_dbg(dev, "FW reported %d function-row key locations\n", n);
12668f7b057aSRajat Jain 	}
12678f7b057aSRajat Jain }
12688f7b057aSRajat Jain 
12691da177e4SLinus Torvalds /*
12701da177e4SLinus Torvalds  * atkbd_connect() is called when the serio module finds an interface
12711da177e4SLinus Torvalds  * that isn't handled yet by an appropriate device driver. We check if
12721da177e4SLinus Torvalds  * there is an AT keyboard out there and if yes, we register ourselves
12731da177e4SLinus Torvalds  * to the input module.
12741da177e4SLinus Torvalds  */
12751da177e4SLinus Torvalds 
atkbd_connect(struct serio * serio,struct serio_driver * drv)12761da177e4SLinus Torvalds static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
12771da177e4SLinus Torvalds {
12781da177e4SLinus Torvalds 	struct atkbd *atkbd;
12793c42f0c3SDmitry Torokhov 	struct input_dev *dev;
12803c42f0c3SDmitry Torokhov 	int err = -ENOMEM;
12811da177e4SLinus Torvalds 
1282*bb8706a4SErick Archer 	atkbd = kzalloc(sizeof(*atkbd), GFP_KERNEL);
12833c42f0c3SDmitry Torokhov 	dev = input_allocate_device();
12843c42f0c3SDmitry Torokhov 	if (!atkbd || !dev)
12852b03b60eSDmitry Torokhov 		goto fail1;
12861da177e4SLinus Torvalds 
12873c42f0c3SDmitry Torokhov 	atkbd->dev = dev;
1288c4c7eac8SDmitry Torokhov 	ps2_init(&atkbd->ps2dev, serio,
1289c4c7eac8SDmitry Torokhov 		 atkbd_pre_receive_byte, atkbd_receive_byte);
1290da4249c9SDmitry Torokhov 	INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
129159b01513SEric W. Biederman 	mutex_init(&atkbd->mutex);
12921da177e4SLinus Torvalds 
12931da177e4SLinus Torvalds 	switch (serio->id.type) {
12941da177e4SLinus Torvalds 
12951da177e4SLinus Torvalds 	case SERIO_8042_XL:
1296a9a1f9c3SDmitry Torokhov 		atkbd->translated = true;
12976f49c4f5SGustavo A. R. Silva 		fallthrough;
1298a9a1f9c3SDmitry Torokhov 
12991da177e4SLinus Torvalds 	case SERIO_8042:
13001da177e4SLinus Torvalds 		if (serio->write)
1301a9a1f9c3SDmitry Torokhov 			atkbd->write = true;
13021da177e4SLinus Torvalds 		break;
13031da177e4SLinus Torvalds 	}
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds 	atkbd->softraw = atkbd_softraw;
13061da177e4SLinus Torvalds 	atkbd->softrepeat = atkbd_softrepeat;
13071da177e4SLinus Torvalds 	atkbd->scroll = atkbd_scroll;
13081da177e4SLinus Torvalds 
13091da177e4SLinus Torvalds 	if (atkbd->softrepeat)
1310a9a1f9c3SDmitry Torokhov 		atkbd->softraw = true;
13111da177e4SLinus Torvalds 
13121da177e4SLinus Torvalds 	serio_set_drvdata(serio, atkbd);
13131da177e4SLinus Torvalds 
13141da177e4SLinus Torvalds 	err = serio_open(serio, drv);
13153c42f0c3SDmitry Torokhov 	if (err)
13162b03b60eSDmitry Torokhov 		goto fail2;
13171da177e4SLinus Torvalds 
13181da177e4SLinus Torvalds 	if (atkbd->write) {
13191da177e4SLinus Torvalds 
13201da177e4SLinus Torvalds 		if (atkbd_probe(atkbd)) {
13213c42f0c3SDmitry Torokhov 			err = -ENODEV;
13222b03b60eSDmitry Torokhov 			goto fail3;
13231da177e4SLinus Torvalds 		}
13241da177e4SLinus Torvalds 
13251da177e4SLinus Torvalds 		atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
1326fc0eb28cSDmitry Torokhov 		atkbd_reset_state(atkbd);
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds 	} else {
13291da177e4SLinus Torvalds 		atkbd->set = 2;
13301da177e4SLinus Torvalds 		atkbd->id = 0xab00;
13311da177e4SLinus Torvalds 	}
13321da177e4SLinus Torvalds 
13338f7b057aSRajat Jain 	atkbd_parse_fwnode_data(serio);
13348f7b057aSRajat Jain 
13351da177e4SLinus Torvalds 	atkbd_set_keycode_table(atkbd);
13361da177e4SLinus Torvalds 	atkbd_set_device_attrs(atkbd);
13371da177e4SLinus Torvalds 
13381da177e4SLinus Torvalds 	atkbd_enable(atkbd);
1339be2d7e42SShawn Nematbakhsh 	if (serio->write)
1340be2d7e42SShawn Nematbakhsh 		atkbd_activate(atkbd);
13411da177e4SLinus Torvalds 
13422b03b60eSDmitry Torokhov 	err = input_register_device(atkbd->dev);
13432b03b60eSDmitry Torokhov 	if (err)
1344c99e3ac6SDmitry Torokhov 		goto fail3;
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	return 0;
13473c42f0c3SDmitry Torokhov 
13482b03b60eSDmitry Torokhov  fail3:	serio_close(serio);
13492b03b60eSDmitry Torokhov  fail2:	serio_set_drvdata(serio, NULL);
13502b03b60eSDmitry Torokhov  fail1:	input_free_device(dev);
13513c42f0c3SDmitry Torokhov 	kfree(atkbd);
13523c42f0c3SDmitry Torokhov 	return err;
13531da177e4SLinus Torvalds }
13541da177e4SLinus Torvalds 
13551da177e4SLinus Torvalds /*
13561da177e4SLinus Torvalds  * atkbd_reconnect() tries to restore keyboard into a sane state and is
13571da177e4SLinus Torvalds  * most likely called on resume.
13581da177e4SLinus Torvalds  */
13591da177e4SLinus Torvalds 
atkbd_reconnect(struct serio * serio)13601da177e4SLinus Torvalds static int atkbd_reconnect(struct serio *serio)
13611da177e4SLinus Torvalds {
1362100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
13631da177e4SLinus Torvalds 	struct serio_driver *drv = serio->drv;
136459b01513SEric W. Biederman 	int retval = -1;
13651da177e4SLinus Torvalds 
13661da177e4SLinus Torvalds 	if (!atkbd || !drv) {
1367a9a1f9c3SDmitry Torokhov 		dev_dbg(&serio->dev,
1368a9a1f9c3SDmitry Torokhov 			"reconnect request, but serio is disconnected, ignoring...\n");
13691da177e4SLinus Torvalds 		return -1;
13701da177e4SLinus Torvalds 	}
13711da177e4SLinus Torvalds 
137259b01513SEric W. Biederman 	mutex_lock(&atkbd->mutex);
137359b01513SEric W. Biederman 
13741da177e4SLinus Torvalds 	atkbd_disable(atkbd);
13751da177e4SLinus Torvalds 
13761da177e4SLinus Torvalds 	if (atkbd->write) {
13771da177e4SLinus Torvalds 		if (atkbd_probe(atkbd))
137859b01513SEric W. Biederman 			goto out;
137959b01513SEric W. Biederman 
13801da177e4SLinus Torvalds 		if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
138159b01513SEric W. Biederman 			goto out;
13821da177e4SLinus Torvalds 
1383d4119bdaSDmitry Torokhov 		/*
1384d4119bdaSDmitry Torokhov 		 * Restore LED state and repeat rate. While input core
1385d4119bdaSDmitry Torokhov 		 * will do this for us at resume time reconnect may happen
1386d4119bdaSDmitry Torokhov 		 * because user requested it via sysfs or simply because
1387d4119bdaSDmitry Torokhov 		 * keyboard was unplugged and plugged in again so we need
1388d4119bdaSDmitry Torokhov 		 * to do it ourselves here.
1389d4119bdaSDmitry Torokhov 		 */
1390d4119bdaSDmitry Torokhov 		atkbd_set_leds(atkbd);
1391d4119bdaSDmitry Torokhov 		if (!atkbd->softrepeat)
1392d4119bdaSDmitry Torokhov 			atkbd_set_repeat_rate(atkbd);
1393d4119bdaSDmitry Torokhov 
13941da177e4SLinus Torvalds 	}
13951da177e4SLinus Torvalds 
1396be2d7e42SShawn Nematbakhsh 	/*
1397be2d7e42SShawn Nematbakhsh 	 * Reset our state machine in case reconnect happened in the middle
1398be2d7e42SShawn Nematbakhsh 	 * of multi-byte scancode.
1399be2d7e42SShawn Nematbakhsh 	 */
1400be2d7e42SShawn Nematbakhsh 	atkbd->xl_bit = 0;
1401be2d7e42SShawn Nematbakhsh 	atkbd->emul = 0;
1402be2d7e42SShawn Nematbakhsh 
14031da177e4SLinus Torvalds 	atkbd_enable(atkbd);
1404be2d7e42SShawn Nematbakhsh 	if (atkbd->write)
1405be2d7e42SShawn Nematbakhsh 		atkbd_activate(atkbd);
1406be2d7e42SShawn Nematbakhsh 
140759b01513SEric W. Biederman 	retval = 0;
14081da177e4SLinus Torvalds 
140959b01513SEric W. Biederman  out:
141059b01513SEric W. Biederman 	mutex_unlock(&atkbd->mutex);
141159b01513SEric W. Biederman 	return retval;
14121da177e4SLinus Torvalds }
14131da177e4SLinus Torvalds 
1414af2e7d77SArvind Yadav static const struct serio_device_id atkbd_serio_ids[] = {
14151da177e4SLinus Torvalds 	{
14161da177e4SLinus Torvalds 		.type	= SERIO_8042,
14171da177e4SLinus Torvalds 		.proto	= SERIO_ANY,
14181da177e4SLinus Torvalds 		.id	= SERIO_ANY,
14191da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
14201da177e4SLinus Torvalds 	},
14211da177e4SLinus Torvalds 	{
14221da177e4SLinus Torvalds 		.type	= SERIO_8042_XL,
14231da177e4SLinus Torvalds 		.proto	= SERIO_ANY,
14241da177e4SLinus Torvalds 		.id	= SERIO_ANY,
14251da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
14261da177e4SLinus Torvalds 	},
14271da177e4SLinus Torvalds 	{
14281da177e4SLinus Torvalds 		.type	= SERIO_RS232,
14291da177e4SLinus Torvalds 		.proto	= SERIO_PS2SER,
14301da177e4SLinus Torvalds 		.id	= SERIO_ANY,
14311da177e4SLinus Torvalds 		.extra	= SERIO_ANY,
14321da177e4SLinus Torvalds 	},
14331da177e4SLinus Torvalds 	{ 0 }
14341da177e4SLinus Torvalds };
14351da177e4SLinus Torvalds 
14361da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, atkbd_serio_ids);
14371da177e4SLinus Torvalds 
14381da177e4SLinus Torvalds static struct serio_driver atkbd_drv = {
14391da177e4SLinus Torvalds 	.driver		= {
14401da177e4SLinus Torvalds 		.name		= "atkbd",
1441c99e3ac6SDmitry Torokhov 		.dev_groups	= atkbd_attribute_groups,
14421da177e4SLinus Torvalds 	},
14431da177e4SLinus Torvalds 	.description	= DRIVER_DESC,
14441da177e4SLinus Torvalds 	.id_table	= atkbd_serio_ids,
1445c4c7eac8SDmitry Torokhov 	.interrupt	= ps2_interrupt,
14461da177e4SLinus Torvalds 	.connect	= atkbd_connect,
14471da177e4SLinus Torvalds 	.reconnect	= atkbd_reconnect,
14481da177e4SLinus Torvalds 	.disconnect	= atkbd_disconnect,
14491da177e4SLinus Torvalds 	.cleanup	= atkbd_cleanup,
14501da177e4SLinus Torvalds };
14511da177e4SLinus Torvalds 
atkbd_attr_show_helper(struct device * dev,char * buf,ssize_t (* handler)(struct atkbd *,char *))14521da177e4SLinus Torvalds static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
14531da177e4SLinus Torvalds 				ssize_t (*handler)(struct atkbd *, char *))
14541da177e4SLinus Torvalds {
14551da177e4SLinus Torvalds 	struct serio *serio = to_serio_port(dev);
1456100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
14571da177e4SLinus Torvalds 
145859b01513SEric W. Biederman 	return handler(atkbd, buf);
14591da177e4SLinus Torvalds }
14601da177e4SLinus Torvalds 
atkbd_attr_set_helper(struct device * dev,const char * buf,size_t count,ssize_t (* handler)(struct atkbd *,const char *,size_t))14611da177e4SLinus Torvalds static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
14621da177e4SLinus Torvalds 				ssize_t (*handler)(struct atkbd *, const char *, size_t))
14631da177e4SLinus Torvalds {
14641da177e4SLinus Torvalds 	struct serio *serio = to_serio_port(dev);
1465100e1695SDmitry Torokhov 	struct atkbd *atkbd = atkbd_from_serio(serio);
14661da177e4SLinus Torvalds 	int retval;
14671da177e4SLinus Torvalds 
146859b01513SEric W. Biederman 	retval = mutex_lock_interruptible(&atkbd->mutex);
14691da177e4SLinus Torvalds 	if (retval)
14701da177e4SLinus Torvalds 		return retval;
14711da177e4SLinus Torvalds 
14721da177e4SLinus Torvalds 	atkbd_disable(atkbd);
14731da177e4SLinus Torvalds 	retval = handler(atkbd, buf, count);
14741da177e4SLinus Torvalds 	atkbd_enable(atkbd);
14751da177e4SLinus Torvalds 
147659b01513SEric W. Biederman 	mutex_unlock(&atkbd->mutex);
147759b01513SEric W. Biederman 
14781da177e4SLinus Torvalds 	return retval;
14791da177e4SLinus Torvalds }
14801da177e4SLinus Torvalds 
atkbd_show_extra(struct atkbd * atkbd,char * buf)14811da177e4SLinus Torvalds static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
14821da177e4SLinus Torvalds {
14831da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0);
14841da177e4SLinus Torvalds }
14851da177e4SLinus Torvalds 
atkbd_set_extra(struct atkbd * atkbd,const char * buf,size_t count)14861da177e4SLinus Torvalds static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
14871da177e4SLinus Torvalds {
14882b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
148976496e7aSJJ Ding 	unsigned int value;
14902b03b60eSDmitry Torokhov 	int err;
1491a9a1f9c3SDmitry Torokhov 	bool old_extra;
1492a9a1f9c3SDmitry Torokhov 	unsigned char old_set;
14931da177e4SLinus Torvalds 
14941da177e4SLinus Torvalds 	if (!atkbd->write)
14951da177e4SLinus Torvalds 		return -EIO;
14961da177e4SLinus Torvalds 
149776496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
149876496e7aSJJ Ding 	if (err)
149976496e7aSJJ Ding 		return err;
150076496e7aSJJ Ding 
150176496e7aSJJ Ding 	if (value > 1)
15021da177e4SLinus Torvalds 		return -EINVAL;
15031da177e4SLinus Torvalds 
15041da177e4SLinus Torvalds 	if (atkbd->extra != value) {
15053c42f0c3SDmitry Torokhov 		/*
15063c42f0c3SDmitry Torokhov 		 * Since device's properties will change we need to
15072b03b60eSDmitry Torokhov 		 * unregister old device. But allocate and register
15082b03b60eSDmitry Torokhov 		 * new one first to make sure we have it.
15093c42f0c3SDmitry Torokhov 		 */
15102b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
15112b03b60eSDmitry Torokhov 		old_extra = atkbd->extra;
15122b03b60eSDmitry Torokhov 		old_set = atkbd->set;
15132b03b60eSDmitry Torokhov 
15142b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
15152b03b60eSDmitry Torokhov 		if (!new_dev)
15163c42f0c3SDmitry Torokhov 			return -ENOMEM;
15172b03b60eSDmitry Torokhov 
15183c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
15191da177e4SLinus Torvalds 		atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
1520fc0eb28cSDmitry Torokhov 		atkbd_reset_state(atkbd);
15211da177e4SLinus Torvalds 		atkbd_activate(atkbd);
15222b03b60eSDmitry Torokhov 		atkbd_set_keycode_table(atkbd);
15231da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
15242b03b60eSDmitry Torokhov 
15252b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
15262b03b60eSDmitry Torokhov 		if (err) {
15272b03b60eSDmitry Torokhov 			input_free_device(new_dev);
15282b03b60eSDmitry Torokhov 
15292b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
15302b03b60eSDmitry Torokhov 			atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
15312b03b60eSDmitry Torokhov 			atkbd_set_keycode_table(atkbd);
15322b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
15332b03b60eSDmitry Torokhov 
15342b03b60eSDmitry Torokhov 			return err;
15352b03b60eSDmitry Torokhov 		}
15362b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
15372b03b60eSDmitry Torokhov 
15381da177e4SLinus Torvalds 	}
15391da177e4SLinus Torvalds 	return count;
15401da177e4SLinus Torvalds }
15411da177e4SLinus Torvalds 
atkbd_show_force_release(struct atkbd * atkbd,char * buf)15421ba36e11SDmitry Torokhov static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
15431ba36e11SDmitry Torokhov {
15440b480037STejun Heo 	size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
15450b480037STejun Heo 			       ATKBD_KEYMAP_SIZE, atkbd->force_release_mask);
15461ba36e11SDmitry Torokhov 
15471ba36e11SDmitry Torokhov 	buf[len++] = '\n';
15481ba36e11SDmitry Torokhov 	buf[len] = '\0';
15491ba36e11SDmitry Torokhov 
15501ba36e11SDmitry Torokhov 	return len;
15511ba36e11SDmitry Torokhov }
15521ba36e11SDmitry Torokhov 
atkbd_set_force_release(struct atkbd * atkbd,const char * buf,size_t count)15531ba36e11SDmitry Torokhov static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
15541ba36e11SDmitry Torokhov 					const char *buf, size_t count)
15551ba36e11SDmitry Torokhov {
15561ba36e11SDmitry Torokhov 	/* 64 bytes on stack should be acceptable */
15571ba36e11SDmitry Torokhov 	DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
15581ba36e11SDmitry Torokhov 	int err;
15591ba36e11SDmitry Torokhov 
15601ba36e11SDmitry Torokhov 	err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
15611ba36e11SDmitry Torokhov 	if (err)
15621ba36e11SDmitry Torokhov 		return err;
15631ba36e11SDmitry Torokhov 
15641ba36e11SDmitry Torokhov 	memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
15651ba36e11SDmitry Torokhov 	return count;
15661ba36e11SDmitry Torokhov }
15671ba36e11SDmitry Torokhov 
15681ba36e11SDmitry Torokhov 
atkbd_show_scroll(struct atkbd * atkbd,char * buf)15691da177e4SLinus Torvalds static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
15701da177e4SLinus Torvalds {
15711da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
15721da177e4SLinus Torvalds }
15731da177e4SLinus Torvalds 
atkbd_set_scroll(struct atkbd * atkbd,const char * buf,size_t count)15741da177e4SLinus Torvalds static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
15751da177e4SLinus Torvalds {
15762b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
157776496e7aSJJ Ding 	unsigned int value;
15782b03b60eSDmitry Torokhov 	int err;
1579a9a1f9c3SDmitry Torokhov 	bool old_scroll;
15801da177e4SLinus Torvalds 
158176496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
158276496e7aSJJ Ding 	if (err)
158376496e7aSJJ Ding 		return err;
158476496e7aSJJ Ding 
158576496e7aSJJ Ding 	if (value > 1)
15861da177e4SLinus Torvalds 		return -EINVAL;
15871da177e4SLinus Torvalds 
15881da177e4SLinus Torvalds 	if (atkbd->scroll != value) {
15892b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
15902b03b60eSDmitry Torokhov 		old_scroll = atkbd->scroll;
15912b03b60eSDmitry Torokhov 
15922b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
15932b03b60eSDmitry Torokhov 		if (!new_dev)
15943c42f0c3SDmitry Torokhov 			return -ENOMEM;
15952b03b60eSDmitry Torokhov 
15963c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
15971da177e4SLinus Torvalds 		atkbd->scroll = value;
15981da177e4SLinus Torvalds 		atkbd_set_keycode_table(atkbd);
15991da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
16002b03b60eSDmitry Torokhov 
16012b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
16022b03b60eSDmitry Torokhov 		if (err) {
16032b03b60eSDmitry Torokhov 			input_free_device(new_dev);
16042b03b60eSDmitry Torokhov 
16052b03b60eSDmitry Torokhov 			atkbd->scroll = old_scroll;
16062b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
16072b03b60eSDmitry Torokhov 			atkbd_set_keycode_table(atkbd);
16082b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
16092b03b60eSDmitry Torokhov 
16102b03b60eSDmitry Torokhov 			return err;
16112b03b60eSDmitry Torokhov 		}
16122b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
16131da177e4SLinus Torvalds 	}
16141da177e4SLinus Torvalds 	return count;
16151da177e4SLinus Torvalds }
16161da177e4SLinus Torvalds 
atkbd_show_set(struct atkbd * atkbd,char * buf)16171da177e4SLinus Torvalds static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
16181da177e4SLinus Torvalds {
16191da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->set);
16201da177e4SLinus Torvalds }
16211da177e4SLinus Torvalds 
atkbd_set_set(struct atkbd * atkbd,const char * buf,size_t count)16221da177e4SLinus Torvalds static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
16231da177e4SLinus Torvalds {
16242b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
162576496e7aSJJ Ding 	unsigned int value;
16262b03b60eSDmitry Torokhov 	int err;
1627a9a1f9c3SDmitry Torokhov 	unsigned char old_set;
1628a9a1f9c3SDmitry Torokhov 	bool old_extra;
16291da177e4SLinus Torvalds 
16301da177e4SLinus Torvalds 	if (!atkbd->write)
16311da177e4SLinus Torvalds 		return -EIO;
16321da177e4SLinus Torvalds 
163376496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
163476496e7aSJJ Ding 	if (err)
163576496e7aSJJ Ding 		return err;
163676496e7aSJJ Ding 
163776496e7aSJJ Ding 	if (value != 2 && value != 3)
16381da177e4SLinus Torvalds 		return -EINVAL;
16391da177e4SLinus Torvalds 
16401da177e4SLinus Torvalds 	if (atkbd->set != value) {
16412b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
16422b03b60eSDmitry Torokhov 		old_extra = atkbd->extra;
16432b03b60eSDmitry Torokhov 		old_set = atkbd->set;
16442b03b60eSDmitry Torokhov 
16452b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
16462b03b60eSDmitry Torokhov 		if (!new_dev)
16473c42f0c3SDmitry Torokhov 			return -ENOMEM;
16482b03b60eSDmitry Torokhov 
16493c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
16501da177e4SLinus Torvalds 		atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
1651d4119bdaSDmitry Torokhov 		atkbd_reset_state(atkbd);
16521da177e4SLinus Torvalds 		atkbd_activate(atkbd);
16531da177e4SLinus Torvalds 		atkbd_set_keycode_table(atkbd);
16541da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
16552b03b60eSDmitry Torokhov 
16562b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
16572b03b60eSDmitry Torokhov 		if (err) {
16582b03b60eSDmitry Torokhov 			input_free_device(new_dev);
16592b03b60eSDmitry Torokhov 
16602b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
16612b03b60eSDmitry Torokhov 			atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
16622b03b60eSDmitry Torokhov 			atkbd_set_keycode_table(atkbd);
16632b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
16642b03b60eSDmitry Torokhov 
16652b03b60eSDmitry Torokhov 			return err;
16662b03b60eSDmitry Torokhov 		}
16672b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
16681da177e4SLinus Torvalds 	}
16691da177e4SLinus Torvalds 	return count;
16701da177e4SLinus Torvalds }
16711da177e4SLinus Torvalds 
atkbd_show_softrepeat(struct atkbd * atkbd,char * buf)16721da177e4SLinus Torvalds static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
16731da177e4SLinus Torvalds {
16741da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0);
16751da177e4SLinus Torvalds }
16761da177e4SLinus Torvalds 
atkbd_set_softrepeat(struct atkbd * atkbd,const char * buf,size_t count)16771da177e4SLinus Torvalds static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
16781da177e4SLinus Torvalds {
16792b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
168076496e7aSJJ Ding 	unsigned int value;
16812b03b60eSDmitry Torokhov 	int err;
1682a9a1f9c3SDmitry Torokhov 	bool old_softrepeat, old_softraw;
16831da177e4SLinus Torvalds 
16841da177e4SLinus Torvalds 	if (!atkbd->write)
16851da177e4SLinus Torvalds 		return -EIO;
16861da177e4SLinus Torvalds 
168776496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
168876496e7aSJJ Ding 	if (err)
168976496e7aSJJ Ding 		return err;
169076496e7aSJJ Ding 
169176496e7aSJJ Ding 	if (value > 1)
16921da177e4SLinus Torvalds 		return -EINVAL;
16931da177e4SLinus Torvalds 
16941da177e4SLinus Torvalds 	if (atkbd->softrepeat != value) {
16952b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
16962b03b60eSDmitry Torokhov 		old_softrepeat = atkbd->softrepeat;
16972b03b60eSDmitry Torokhov 		old_softraw = atkbd->softraw;
16982b03b60eSDmitry Torokhov 
16992b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
17002b03b60eSDmitry Torokhov 		if (!new_dev)
17013c42f0c3SDmitry Torokhov 			return -ENOMEM;
17022b03b60eSDmitry Torokhov 
17033c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
17041da177e4SLinus Torvalds 		atkbd->softrepeat = value;
17051da177e4SLinus Torvalds 		if (atkbd->softrepeat)
1706a9a1f9c3SDmitry Torokhov 			atkbd->softraw = true;
17071da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
17082b03b60eSDmitry Torokhov 
17092b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
17102b03b60eSDmitry Torokhov 		if (err) {
17112b03b60eSDmitry Torokhov 			input_free_device(new_dev);
17122b03b60eSDmitry Torokhov 
17132b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
17142b03b60eSDmitry Torokhov 			atkbd->softrepeat = old_softrepeat;
17152b03b60eSDmitry Torokhov 			atkbd->softraw = old_softraw;
17162b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
17172b03b60eSDmitry Torokhov 
17182b03b60eSDmitry Torokhov 			return err;
17192b03b60eSDmitry Torokhov 		}
17202b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
17211da177e4SLinus Torvalds 	}
17221da177e4SLinus Torvalds 	return count;
17231da177e4SLinus Torvalds }
17241da177e4SLinus Torvalds 
17251da177e4SLinus Torvalds 
atkbd_show_softraw(struct atkbd * atkbd,char * buf)17261da177e4SLinus Torvalds static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
17271da177e4SLinus Torvalds {
17281da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0);
17291da177e4SLinus Torvalds }
17301da177e4SLinus Torvalds 
atkbd_set_softraw(struct atkbd * atkbd,const char * buf,size_t count)17311da177e4SLinus Torvalds static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
17321da177e4SLinus Torvalds {
17332b03b60eSDmitry Torokhov 	struct input_dev *old_dev, *new_dev;
173476496e7aSJJ Ding 	unsigned int value;
17352b03b60eSDmitry Torokhov 	int err;
1736a9a1f9c3SDmitry Torokhov 	bool old_softraw;
17371da177e4SLinus Torvalds 
173876496e7aSJJ Ding 	err = kstrtouint(buf, 10, &value);
173976496e7aSJJ Ding 	if (err)
174076496e7aSJJ Ding 		return err;
174176496e7aSJJ Ding 
174276496e7aSJJ Ding 	if (value > 1)
17431da177e4SLinus Torvalds 		return -EINVAL;
17441da177e4SLinus Torvalds 
17451da177e4SLinus Torvalds 	if (atkbd->softraw != value) {
17462b03b60eSDmitry Torokhov 		old_dev = atkbd->dev;
17472b03b60eSDmitry Torokhov 		old_softraw = atkbd->softraw;
17482b03b60eSDmitry Torokhov 
17492b03b60eSDmitry Torokhov 		new_dev = input_allocate_device();
17502b03b60eSDmitry Torokhov 		if (!new_dev)
17513c42f0c3SDmitry Torokhov 			return -ENOMEM;
17522b03b60eSDmitry Torokhov 
17533c42f0c3SDmitry Torokhov 		atkbd->dev = new_dev;
17541da177e4SLinus Torvalds 		atkbd->softraw = value;
17551da177e4SLinus Torvalds 		atkbd_set_device_attrs(atkbd);
17562b03b60eSDmitry Torokhov 
17572b03b60eSDmitry Torokhov 		err = input_register_device(atkbd->dev);
17582b03b60eSDmitry Torokhov 		if (err) {
17592b03b60eSDmitry Torokhov 			input_free_device(new_dev);
17602b03b60eSDmitry Torokhov 
17612b03b60eSDmitry Torokhov 			atkbd->dev = old_dev;
17622b03b60eSDmitry Torokhov 			atkbd->softraw = old_softraw;
17632b03b60eSDmitry Torokhov 			atkbd_set_device_attrs(atkbd);
17642b03b60eSDmitry Torokhov 
17652b03b60eSDmitry Torokhov 			return err;
17662b03b60eSDmitry Torokhov 		}
17672b03b60eSDmitry Torokhov 		input_unregister_device(old_dev);
17681da177e4SLinus Torvalds 	}
17691da177e4SLinus Torvalds 	return count;
17701da177e4SLinus Torvalds }
17711da177e4SLinus Torvalds 
atkbd_show_err_count(struct atkbd * atkbd,char * buf)177286255d9dSDmitry Torokhov static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
177386255d9dSDmitry Torokhov {
177486255d9dSDmitry Torokhov 	return sprintf(buf, "%lu\n", atkbd->err_count);
177586255d9dSDmitry Torokhov }
177686255d9dSDmitry Torokhov 
atkbd_setup_forced_release(const struct dmi_system_id * id)177739191698SDaniel Mierswa static int __init atkbd_setup_forced_release(const struct dmi_system_id *id)
1778554101e3SGiel de Nijs {
177939191698SDaniel Mierswa 	atkbd_platform_fixup = atkbd_apply_forced_release_keylist;
178039191698SDaniel Mierswa 	atkbd_platform_fixup_data = id->driver_data;
178139191698SDaniel Mierswa 
1782c388b2c6SAxel Lin 	return 1;
1783554101e3SGiel de Nijs }
1784554101e3SGiel de Nijs 
atkbd_setup_scancode_fixup(const struct dmi_system_id * id)1785e5713069SJamie Lentin static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
1786e5713069SJamie Lentin {
1787e5713069SJamie Lentin 	atkbd_platform_scancode_fixup = id->driver_data;
1788e5713069SJamie Lentin 
1789c388b2c6SAxel Lin 	return 1;
1790e5713069SJamie Lentin }
1791e5713069SJamie Lentin 
atkbd_deactivate_fixup(const struct dmi_system_id * id)17923d725caaSSheng-Liang Song static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id)
17933d725caaSSheng-Liang Song {
17943d725caaSSheng-Liang Song 	atkbd_skip_deactivate = true;
17953d725caaSSheng-Liang Song 	return 1;
17963d725caaSSheng-Liang Song }
17973d725caaSSheng-Liang Song 
17988b8a518eSDmitry Torokhov /*
17998b8a518eSDmitry Torokhov  * NOTE: do not add any more "force release" quirks to this table.  The
18008b8a518eSDmitry Torokhov  * task of adjusting list of keys that should be "released" automatically
18018b8a518eSDmitry Torokhov  * by the driver is now delegated to userspace tools, such as udev, so
18028b8a518eSDmitry Torokhov  * submit such quirks there.
18038b8a518eSDmitry Torokhov  */
1804c45fc81eSDmitry Torokhov static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
1805554101e3SGiel de Nijs 	{
1806554101e3SGiel de Nijs 		.matches = {
1807554101e3SGiel de Nijs 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
180861579ba8SMatthew Garrett 			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
1809554101e3SGiel de Nijs 		},
181039191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
181139191698SDaniel Mierswa 		.driver_data = atkbd_dell_laptop_forced_release_keys,
1812554101e3SGiel de Nijs 	},
18135a54c011SJiri Kosina 	{
18142a3ec326SMatthew Garrett 		.matches = {
18152a3ec326SMatthew Garrett 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
18162a3ec326SMatthew Garrett 			DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
18172a3ec326SMatthew Garrett 		},
181839191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
181939191698SDaniel Mierswa 		.driver_data = atkbd_dell_laptop_forced_release_keys,
18202a3ec326SMatthew Garrett 	},
18212a3ec326SMatthew Garrett 	{
18225a54c011SJiri Kosina 		.matches = {
18235a54c011SJiri Kosina 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18245a54c011SJiri Kosina 			DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"),
18255a54c011SJiri Kosina 		},
182639191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
182739191698SDaniel Mierswa 		.driver_data = atkbd_hp_forced_release_keys,
18285a54c011SJiri Kosina 	},
1829a8215b81SMatthew Garrett 	{
1830181f6382SRikard Ljungstrand 		.matches = {
1831181f6382SRikard Ljungstrand 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1832181f6382SRikard Ljungstrand 			DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
1833181f6382SRikard Ljungstrand 		},
183439191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
1835000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
1836181f6382SRikard Ljungstrand 	},
1837181f6382SRikard Ljungstrand 	{
18382bcaa6a4SDave Andrews 		.matches = {
18392bcaa6a4SDave Andrews 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18402bcaa6a4SDave Andrews 			DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
18412bcaa6a4SDave Andrews 		},
18422bcaa6a4SDave Andrews 		.callback = atkbd_setup_forced_release,
1843000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
18442bcaa6a4SDave Andrews 	},
18452bcaa6a4SDave Andrews 	{
18462bcaa6a4SDave Andrews 		.matches = {
18472bcaa6a4SDave Andrews 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18482bcaa6a4SDave Andrews 			DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
18492bcaa6a4SDave Andrews 		},
18502bcaa6a4SDave Andrews 		.callback = atkbd_setup_forced_release,
1851000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
18522bcaa6a4SDave Andrews 	},
18532bcaa6a4SDave Andrews 	{
18542bcaa6a4SDave Andrews 		.matches = {
18552bcaa6a4SDave Andrews 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
18562bcaa6a4SDave Andrews 			DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
18572bcaa6a4SDave Andrews 		},
18582bcaa6a4SDave Andrews 		.callback = atkbd_setup_forced_release,
1859000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
18602bcaa6a4SDave Andrews 	},
18612bcaa6a4SDave Andrews 	{
1862c45fc81eSDmitry Torokhov 		/* Inventec Symphony */
1863a8215b81SMatthew Garrett 		.matches = {
1864a8215b81SMatthew Garrett 			DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"),
1865a8215b81SMatthew Garrett 			DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
1866a8215b81SMatthew Garrett 		},
186739191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
1868000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
1869a8215b81SMatthew Garrett 	},
18704200844bSStuart Hopkins 	{
1871c45fc81eSDmitry Torokhov 		/* Samsung NC10 */
18724200844bSStuart Hopkins 		.matches = {
18734200844bSStuart Hopkins 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
18744200844bSStuart Hopkins 			DMI_MATCH(DMI_PRODUCT_NAME, "NC10"),
18754200844bSStuart Hopkins 		},
187639191698SDaniel Mierswa 		.callback = atkbd_setup_forced_release,
187739191698SDaniel Mierswa 		.driver_data = atkbd_samsung_forced_release_keys,
18784200844bSStuart Hopkins 	},
1879adcb523eSDaniel Mierswa 	{
1880c45fc81eSDmitry Torokhov 		/* Samsung NC20 */
1881e04126c7SBarry Carroll 		.matches = {
1882e04126c7SBarry Carroll 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1883e04126c7SBarry Carroll 			DMI_MATCH(DMI_PRODUCT_NAME, "NC20"),
1884e04126c7SBarry Carroll 		},
1885e04126c7SBarry Carroll 		.callback = atkbd_setup_forced_release,
1886e04126c7SBarry Carroll 		.driver_data = atkbd_samsung_forced_release_keys,
1887e04126c7SBarry Carroll 	},
1888e04126c7SBarry Carroll 	{
1889c45fc81eSDmitry Torokhov 		/* Samsung SQ45S70S */
1890157f3a3eSDmitry Torokhov 		.matches = {
1891157f3a3eSDmitry Torokhov 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1892157f3a3eSDmitry Torokhov 			DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"),
1893157f3a3eSDmitry Torokhov 		},
1894157f3a3eSDmitry Torokhov 		.callback = atkbd_setup_forced_release,
1895157f3a3eSDmitry Torokhov 		.driver_data = atkbd_samsung_forced_release_keys,
1896157f3a3eSDmitry Torokhov 	},
1897157f3a3eSDmitry Torokhov 	{
1898c45fc81eSDmitry Torokhov 		/* Fujitsu Amilo PA 1510 */
1899adcb523eSDaniel Mierswa 		.matches = {
1900adcb523eSDaniel Mierswa 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1901adcb523eSDaniel Mierswa 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
1902adcb523eSDaniel Mierswa 		},
1903adcb523eSDaniel Mierswa 		.callback = atkbd_setup_forced_release,
1904000c2a35SHerton Ronaldo Krzesinski 		.driver_data = atkbd_volume_forced_release_keys,
1905adcb523eSDaniel Mierswa 	},
19069166d0f6SAdrian Batzill 	{
1907c45fc81eSDmitry Torokhov 		/* Fujitsu Amilo Pi 3525 */
1908f0a14de2SSimon Davie 		.matches = {
1909f0a14de2SSimon Davie 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1910f0a14de2SSimon Davie 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"),
1911f0a14de2SSimon Davie 		},
1912f0a14de2SSimon Davie 		.callback = atkbd_setup_forced_release,
1913f0a14de2SSimon Davie 		.driver_data = atkbd_amilo_pi3525_forced_release_keys,
1914f0a14de2SSimon Davie 	},
1915f0a14de2SSimon Davie 	{
1916c45fc81eSDmitry Torokhov 		/* Fujitsu Amilo Xi 3650 */
19179166d0f6SAdrian Batzill 		.matches = {
19189166d0f6SAdrian Batzill 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
19199166d0f6SAdrian Batzill 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"),
19209166d0f6SAdrian Batzill 		},
19219166d0f6SAdrian Batzill 		.callback = atkbd_setup_forced_release,
19229166d0f6SAdrian Batzill 		.driver_data = atkbd_amilo_xi3650_forced_release_keys,
19239166d0f6SAdrian Batzill 	},
1924032e46cbSJerone Young 	{
1925032e46cbSJerone Young 		.matches = {
1926032e46cbSJerone Young 			DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"),
1927032e46cbSJerone Young 			DMI_MATCH(DMI_PRODUCT_NAME, "TA12"),
1928032e46cbSJerone Young 		},
1929032e46cbSJerone Young 		.callback = atkbd_setup_forced_release,
1930032e46cbSJerone Young 		.driver_data = atkdb_soltech_ta12_forced_release_keys,
1931032e46cbSJerone Young 	},
1932e5713069SJamie Lentin 	{
1933c45fc81eSDmitry Torokhov 		/* OQO Model 01+ */
1934e5713069SJamie Lentin 		.matches = {
1935e5713069SJamie Lentin 			DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
1936e5713069SJamie Lentin 			DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
1937e5713069SJamie Lentin 		},
1938e5713069SJamie Lentin 		.callback = atkbd_setup_scancode_fixup,
1939e5713069SJamie Lentin 		.driver_data = atkbd_oqo_01plus_scancode_fixup,
1940e5713069SJamie Lentin 	},
19413d725caaSSheng-Liang Song 	{
19423d725caaSSheng-Liang Song 		.matches = {
19433d725caaSSheng-Liang Song 			DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
19443d725caaSSheng-Liang Song 		},
19453d725caaSSheng-Liang Song 		.callback = atkbd_deactivate_fixup,
19463d725caaSSheng-Liang Song 	},
1947554101e3SGiel de Nijs 	{ }
1948554101e3SGiel de Nijs };
19491da177e4SLinus Torvalds 
atkbd_init(void)19501da177e4SLinus Torvalds static int __init atkbd_init(void)
19511da177e4SLinus Torvalds {
1952554101e3SGiel de Nijs 	dmi_check_system(atkbd_dmi_quirk_table);
1953554101e3SGiel de Nijs 
1954153a9df0SAkinobu Mita 	return serio_register_driver(&atkbd_drv);
19551da177e4SLinus Torvalds }
19561da177e4SLinus Torvalds 
atkbd_exit(void)19571da177e4SLinus Torvalds static void __exit atkbd_exit(void)
19581da177e4SLinus Torvalds {
19591da177e4SLinus Torvalds 	serio_unregister_driver(&atkbd_drv);
19601da177e4SLinus Torvalds }
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds module_init(atkbd_init);
19631da177e4SLinus Torvalds module_exit(atkbd_exit);
1964