xref: /linux/drivers/input/serio/i8042.c (revision 7eb61cc674ee0f597e7954d38e4e08fe8c5b19ba)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  i8042 keyboard and mouse controller driver for Linux
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (c) 1999-2004 Vojtech Pavlik
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds 
94eb3c30bSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
104eb3c30bSJoe Perches 
117e044e05SDmitry Torokhov #include <linux/types.h>
121da177e4SLinus Torvalds #include <linux/delay.h>
131da177e4SLinus Torvalds #include <linux/module.h>
141da177e4SLinus Torvalds #include <linux/interrupt.h>
151da177e4SLinus Torvalds #include <linux/ioport.h>
161da177e4SLinus Torvalds #include <linux/init.h>
171da177e4SLinus Torvalds #include <linux/serio.h>
181da177e4SLinus Torvalds #include <linux/err.h>
191da177e4SLinus Torvalds #include <linux/rcupdate.h>
20d052d1beSRussell King #include <linux/platform_device.h>
21553a05b8SMárton Németh #include <linux/i8042.h>
225a0e3ad6STejun Heo #include <linux/slab.h>
231c5dd134SRafael J. Wysocki #include <linux/suspend.h>
246052abf8SRajat Jain #include <linux/property.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include <asm/io.h>
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
291da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
301da177e4SLinus Torvalds MODULE_LICENSE("GPL");
311da177e4SLinus Torvalds 
32386b3849SDmitry Torokhov static bool i8042_nokbd;
33945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0);
34945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
35945ef0d4SDmitry Torokhov 
36386b3849SDmitry Torokhov static bool i8042_noaux;
371da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0);
381da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
391da177e4SLinus Torvalds 
40e55a3366SDmitry Torokhov static bool i8042_nomux;
411da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0);
422c860a11SDominik Brodowski MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing controller is present.");
431da177e4SLinus Torvalds 
44386b3849SDmitry Torokhov static bool i8042_unlock;
451da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0);
461da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
471da177e4SLinus Torvalds 
489222ba68STakashi Iwai static bool i8042_probe_defer;
499222ba68STakashi Iwai module_param_named(probe_defer, i8042_probe_defer, bool, 0);
509222ba68STakashi Iwai MODULE_PARM_DESC(probe_defer, "Allow deferred probing.");
519222ba68STakashi Iwai 
52930e1924SMarcos Paulo de Souza enum i8042_controller_reset_mode {
53930e1924SMarcos Paulo de Souza 	I8042_RESET_NEVER,
54930e1924SMarcos Paulo de Souza 	I8042_RESET_ALWAYS,
55930e1924SMarcos Paulo de Souza 	I8042_RESET_ON_S2RAM,
56930e1924SMarcos Paulo de Souza #define I8042_RESET_DEFAULT	I8042_RESET_ON_S2RAM
57930e1924SMarcos Paulo de Souza };
58930e1924SMarcos Paulo de Souza static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
i8042_set_reset(const char * val,const struct kernel_param * kp)59930e1924SMarcos Paulo de Souza static int i8042_set_reset(const char *val, const struct kernel_param *kp)
60930e1924SMarcos Paulo de Souza {
61930e1924SMarcos Paulo de Souza 	enum i8042_controller_reset_mode *arg = kp->arg;
62930e1924SMarcos Paulo de Souza 	int error;
63930e1924SMarcos Paulo de Souza 	bool reset;
64930e1924SMarcos Paulo de Souza 
65930e1924SMarcos Paulo de Souza 	if (val) {
66930e1924SMarcos Paulo de Souza 		error = kstrtobool(val, &reset);
67930e1924SMarcos Paulo de Souza 		if (error)
68930e1924SMarcos Paulo de Souza 			return error;
69930e1924SMarcos Paulo de Souza 	} else {
70930e1924SMarcos Paulo de Souza 		reset = true;
71930e1924SMarcos Paulo de Souza 	}
72930e1924SMarcos Paulo de Souza 
73930e1924SMarcos Paulo de Souza 	*arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
74930e1924SMarcos Paulo de Souza 	return 0;
75930e1924SMarcos Paulo de Souza }
76930e1924SMarcos Paulo de Souza 
77930e1924SMarcos Paulo de Souza static const struct kernel_param_ops param_ops_reset_param = {
78930e1924SMarcos Paulo de Souza 	.flags = KERNEL_PARAM_OPS_FL_NOARG,
79930e1924SMarcos Paulo de Souza 	.set = i8042_set_reset,
80930e1924SMarcos Paulo de Souza };
81930e1924SMarcos Paulo de Souza #define param_check_reset_param(name, p)	\
82930e1924SMarcos Paulo de Souza 	__param_check(name, p, enum i8042_controller_reset_mode)
83930e1924SMarcos Paulo de Souza module_param_named(reset, i8042_reset, reset_param, 0);
84930e1924SMarcos Paulo de Souza MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both");
851da177e4SLinus Torvalds 
86386b3849SDmitry Torokhov static bool i8042_direct;
871da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0);
881da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode.");
891da177e4SLinus Torvalds 
90386b3849SDmitry Torokhov static bool i8042_dumbkbd;
911da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
921da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
931da177e4SLinus Torvalds 
94386b3849SDmitry Torokhov static bool i8042_noloop;
951da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0);
961da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
971da177e4SLinus Torvalds 
98f8313ef1SJiri Kosina static bool i8042_notimeout;
99f8313ef1SJiri Kosina module_param_named(notimeout, i8042_notimeout, bool, 0);
100f8313ef1SJiri Kosina MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042");
101f8313ef1SJiri Kosina 
102148e9a71SSrihari Vijayaraghavan static bool i8042_kbdreset;
103148e9a71SSrihari Vijayaraghavan module_param_named(kbdreset, i8042_kbdreset, bool, 0);
104148e9a71SSrihari Vijayaraghavan MODULE_PARM_DESC(kbdreset, "Reset device connected to KBD port");
105148e9a71SSrihari Vijayaraghavan 
1068987fec0SCarlos Corbacho #ifdef CONFIG_X86
107386b3849SDmitry Torokhov static bool i8042_dritek;
1088987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0);
1098987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension");
1108987fec0SCarlos Corbacho #endif
1118987fec0SCarlos Corbacho 
1121da177e4SLinus Torvalds #ifdef CONFIG_PNP
113386b3849SDmitry Torokhov static bool i8042_nopnp;
1141da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0);
1151da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
1161da177e4SLinus Torvalds #endif
1171da177e4SLinus Torvalds 
118*3d765ae2SWerner Sembach static bool i8042_forcenorestore;
119*3d765ae2SWerner Sembach module_param_named(forcenorestore, i8042_forcenorestore, bool, 0);
120*3d765ae2SWerner Sembach MODULE_PARM_DESC(forcenorestore, "Force no restore on s3 resume, copying s2idle behaviour");
121*3d765ae2SWerner Sembach 
1221da177e4SLinus Torvalds #define DEBUG
1231da177e4SLinus Torvalds #ifdef DEBUG
124386b3849SDmitry Torokhov static bool i8042_debug;
1251da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600);
1261da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
127e1443d28SStephen Chandler Paul 
128e1443d28SStephen Chandler Paul static bool i8042_unmask_kbd_data;
129e1443d28SStephen Chandler Paul module_param_named(unmask_kbd_data, i8042_unmask_kbd_data, bool, 0600);
130e1443d28SStephen Chandler Paul MODULE_PARM_DESC(unmask_kbd_data, "Unconditional enable (may reveal sensitive data) of normally sanitize-filtered kbd data traffic debug log [pre-condition: i8042.debug=1 enabled]");
1311da177e4SLinus Torvalds #endif
1321da177e4SLinus Torvalds 
133b1884583SHans de Goede static bool i8042_present;
1341c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test;
135a7c5868cSHans de Goede static char i8042_kbd_firmware_id[128];
136a7c5868cSHans de Goede static char i8042_aux_firmware_id[128];
1376052abf8SRajat Jain static struct fwnode_handle *i8042_kbd_fwnode;
1381c7827aeSDmitry Torokhov 
1391da177e4SLinus Torvalds #include "i8042.h"
1401da177e4SLinus Torvalds 
141181d683dSDmitry Torokhov /*
142181d683dSDmitry Torokhov  * i8042_lock protects serialization between i8042_command and
143181d683dSDmitry Torokhov  * the interrupt handler.
144181d683dSDmitry Torokhov  */
1451da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock);
1461da177e4SLinus Torvalds 
147181d683dSDmitry Torokhov /*
148181d683dSDmitry Torokhov  * Writers to AUX and KBD ports as well as users issuing i8042_command
149181d683dSDmitry Torokhov  * directly should acquire i8042_mutex (by means of calling
150c2d7ed9dSTyson Moore  * i8042_lock_chip() and i8042_unlock_chip() helpers) to ensure that
151181d683dSDmitry Torokhov  * they do not disturb each other (unfortunately in many i8042
152181d683dSDmitry Torokhov  * implementations write to one of the ports will immediately abort
153181d683dSDmitry Torokhov  * command that is being processed by another port).
154181d683dSDmitry Torokhov  */
155181d683dSDmitry Torokhov static DEFINE_MUTEX(i8042_mutex);
156181d683dSDmitry Torokhov 
1571da177e4SLinus Torvalds struct i8042_port {
1581da177e4SLinus Torvalds 	struct serio *serio;
1591da177e4SLinus Torvalds 	int irq;
160386b3849SDmitry Torokhov 	bool exists;
161e1443d28SStephen Chandler Paul 	bool driver_bound;
1621da177e4SLinus Torvalds 	signed char mux;
1631da177e4SLinus Torvalds };
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds #define I8042_KBD_PORT_NO	0
1661da177e4SLinus Torvalds #define I8042_AUX_PORT_NO	1
1671da177e4SLinus Torvalds #define I8042_MUX_PORT_NO	2
1681da177e4SLinus Torvalds #define I8042_NUM_PORTS		(I8042_NUM_MUX_PORTS + 2)
169de9ce703SDmitry Torokhov 
170de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS];
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds static unsigned char i8042_initial_ctr;
1731da177e4SLinus Torvalds static unsigned char i8042_ctr;
174386b3849SDmitry Torokhov static bool i8042_mux_present;
175386b3849SDmitry Torokhov static bool i8042_kbd_irq_registered;
176386b3849SDmitry Torokhov static bool i8042_aux_irq_registered;
177817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack;
1781da177e4SLinus Torvalds static struct platform_device *i8042_platform_device;
179e1443d28SStephen Chandler Paul static struct notifier_block i8042_kbd_bind_notifier_block;
1801da177e4SLinus Torvalds 
1817d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id);
182967c9ef9SMatthew Garrett static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
183967c9ef9SMatthew Garrett 				     struct serio *serio);
1841da177e4SLinus Torvalds 
i8042_lock_chip(void)185181d683dSDmitry Torokhov void i8042_lock_chip(void)
186181d683dSDmitry Torokhov {
187181d683dSDmitry Torokhov 	mutex_lock(&i8042_mutex);
188181d683dSDmitry Torokhov }
189181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip);
190181d683dSDmitry Torokhov 
i8042_unlock_chip(void)191181d683dSDmitry Torokhov void i8042_unlock_chip(void)
192181d683dSDmitry Torokhov {
193181d683dSDmitry Torokhov 	mutex_unlock(&i8042_mutex);
194181d683dSDmitry Torokhov }
195181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip);
196181d683dSDmitry Torokhov 
i8042_install_filter(bool (* filter)(unsigned char data,unsigned char str,struct serio * serio))197967c9ef9SMatthew Garrett int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
198967c9ef9SMatthew Garrett 					struct serio *serio))
199967c9ef9SMatthew Garrett {
200967c9ef9SMatthew Garrett 	unsigned long flags;
201967c9ef9SMatthew Garrett 	int ret = 0;
202967c9ef9SMatthew Garrett 
203967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
204967c9ef9SMatthew Garrett 
205967c9ef9SMatthew Garrett 	if (i8042_platform_filter) {
206967c9ef9SMatthew Garrett 		ret = -EBUSY;
207967c9ef9SMatthew Garrett 		goto out;
208967c9ef9SMatthew Garrett 	}
209967c9ef9SMatthew Garrett 
210967c9ef9SMatthew Garrett 	i8042_platform_filter = filter;
211967c9ef9SMatthew Garrett 
212967c9ef9SMatthew Garrett out:
213967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
214967c9ef9SMatthew Garrett 	return ret;
215967c9ef9SMatthew Garrett }
216967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_install_filter);
217967c9ef9SMatthew Garrett 
i8042_remove_filter(bool (* filter)(unsigned char data,unsigned char str,struct serio * port))218967c9ef9SMatthew Garrett int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
219967c9ef9SMatthew Garrett 				       struct serio *port))
220967c9ef9SMatthew Garrett {
221967c9ef9SMatthew Garrett 	unsigned long flags;
222967c9ef9SMatthew Garrett 	int ret = 0;
223967c9ef9SMatthew Garrett 
224967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
225967c9ef9SMatthew Garrett 
226967c9ef9SMatthew Garrett 	if (i8042_platform_filter != filter) {
227967c9ef9SMatthew Garrett 		ret = -EINVAL;
228967c9ef9SMatthew Garrett 		goto out;
229967c9ef9SMatthew Garrett 	}
230967c9ef9SMatthew Garrett 
231967c9ef9SMatthew Garrett 	i8042_platform_filter = NULL;
232967c9ef9SMatthew Garrett 
233967c9ef9SMatthew Garrett out:
234967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
235967c9ef9SMatthew Garrett 	return ret;
236967c9ef9SMatthew Garrett }
237967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_remove_filter);
238967c9ef9SMatthew Garrett 
2391da177e4SLinus Torvalds /*
2401da177e4SLinus Torvalds  * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
2411da177e4SLinus Torvalds  * be ready for reading values from it / writing values to it.
2421da177e4SLinus Torvalds  * Called always with i8042_lock held.
2431da177e4SLinus Torvalds  */
2441da177e4SLinus Torvalds 
i8042_wait_read(void)2451da177e4SLinus Torvalds static int i8042_wait_read(void)
2461da177e4SLinus Torvalds {
2471da177e4SLinus Torvalds 	int i = 0;
248de9ce703SDmitry Torokhov 
2491da177e4SLinus Torvalds 	while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
2501da177e4SLinus Torvalds 		udelay(50);
2511da177e4SLinus Torvalds 		i++;
2521da177e4SLinus Torvalds 	}
2531da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
2541da177e4SLinus Torvalds }
2551da177e4SLinus Torvalds 
i8042_wait_write(void)2561da177e4SLinus Torvalds static int i8042_wait_write(void)
2571da177e4SLinus Torvalds {
2581da177e4SLinus Torvalds 	int i = 0;
259de9ce703SDmitry Torokhov 
2601da177e4SLinus Torvalds 	while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
2611da177e4SLinus Torvalds 		udelay(50);
2621da177e4SLinus Torvalds 		i++;
2631da177e4SLinus Torvalds 	}
2641da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds /*
2681da177e4SLinus Torvalds  * i8042_flush() flushes all data that may be in the keyboard and mouse buffers
2691da177e4SLinus Torvalds  * of the i8042 down the toilet.
2701da177e4SLinus Torvalds  */
2711da177e4SLinus Torvalds 
i8042_flush(void)2721da177e4SLinus Torvalds static int i8042_flush(void)
2731da177e4SLinus Torvalds {
2741da177e4SLinus Torvalds 	unsigned long flags;
2751da177e4SLinus Torvalds 	unsigned char data, str;
2762f0d2604SAndrey Moiseev 	int count = 0;
2772f0d2604SAndrey Moiseev 	int retval = 0;
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
2801da177e4SLinus Torvalds 
2812f0d2604SAndrey Moiseev 	while ((str = i8042_read_status()) & I8042_STR_OBF) {
2822f0d2604SAndrey Moiseev 		if (count++ < I8042_BUFFER_SIZE) {
2831da177e4SLinus Torvalds 			udelay(50);
2841da177e4SLinus Torvalds 			data = i8042_read_data();
2854eb3c30bSJoe Perches 			dbg("%02x <- i8042 (flush, %s)\n",
2864eb3c30bSJoe Perches 			    data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
2872f0d2604SAndrey Moiseev 		} else {
2882f0d2604SAndrey Moiseev 			retval = -EIO;
2892f0d2604SAndrey Moiseev 			break;
2902f0d2604SAndrey Moiseev 		}
2911da177e4SLinus Torvalds 	}
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
2941da177e4SLinus Torvalds 
2952f0d2604SAndrey Moiseev 	return retval;
2961da177e4SLinus Torvalds }
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds /*
2991da177e4SLinus Torvalds  * i8042_command() executes a command on the i8042. It also sends the input
3001da177e4SLinus Torvalds  * parameter(s) of the commands to it, and receives the output value(s). The
3011da177e4SLinus Torvalds  * parameters are to be stored in the param array, and the output is placed
3021da177e4SLinus Torvalds  * into the same array. The number of the parameters and output values is
3031da177e4SLinus Torvalds  * encoded in bits 8-11 of the command number.
3041da177e4SLinus Torvalds  */
3051da177e4SLinus Torvalds 
__i8042_command(unsigned char * param,int command)306de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command)
3071da177e4SLinus Torvalds {
308de9ce703SDmitry Torokhov 	int i, error;
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
3111da177e4SLinus Torvalds 		return -1;
3121da177e4SLinus Torvalds 
313de9ce703SDmitry Torokhov 	error = i8042_wait_write();
314de9ce703SDmitry Torokhov 	if (error)
315de9ce703SDmitry Torokhov 		return error;
316463a4f76SDmitry Torokhov 
3174eb3c30bSJoe Perches 	dbg("%02x -> i8042 (command)\n", command & 0xff);
3181da177e4SLinus Torvalds 	i8042_write_command(command & 0xff);
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 12) & 0xf); i++) {
321de9ce703SDmitry Torokhov 		error = i8042_wait_write();
3222ea9c236SMarcos Paulo de Souza 		if (error) {
3232ea9c236SMarcos Paulo de Souza 			dbg("     -- i8042 (wait write timeout)\n");
324de9ce703SDmitry Torokhov 			return error;
3252ea9c236SMarcos Paulo de Souza 		}
3264eb3c30bSJoe Perches 		dbg("%02x -> i8042 (parameter)\n", param[i]);
3271da177e4SLinus Torvalds 		i8042_write_data(param[i]);
3281da177e4SLinus Torvalds 	}
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 8) & 0xf); i++) {
331de9ce703SDmitry Torokhov 		error = i8042_wait_read();
332de9ce703SDmitry Torokhov 		if (error) {
3332ea9c236SMarcos Paulo de Souza 			dbg("     -- i8042 (wait read timeout)\n");
334de9ce703SDmitry Torokhov 			return error;
335de9ce703SDmitry Torokhov 		}
336463a4f76SDmitry Torokhov 
337463a4f76SDmitry Torokhov 		if (command == I8042_CMD_AUX_LOOP &&
338463a4f76SDmitry Torokhov 		    !(i8042_read_status() & I8042_STR_AUXDATA)) {
3394eb3c30bSJoe Perches 			dbg("     -- i8042 (auxerr)\n");
340de9ce703SDmitry Torokhov 			return -1;
341463a4f76SDmitry Torokhov 		}
342463a4f76SDmitry Torokhov 
3431da177e4SLinus Torvalds 		param[i] = i8042_read_data();
3444eb3c30bSJoe Perches 		dbg("%02x <- i8042 (return)\n", param[i]);
3451da177e4SLinus Torvalds 	}
3461da177e4SLinus Torvalds 
347de9ce703SDmitry Torokhov 	return 0;
348de9ce703SDmitry Torokhov }
3491da177e4SLinus Torvalds 
i8042_command(unsigned char * param,int command)350553a05b8SMárton Németh int i8042_command(unsigned char *param, int command)
351de9ce703SDmitry Torokhov {
352de9ce703SDmitry Torokhov 	unsigned long flags;
353de9ce703SDmitry Torokhov 	int retval;
354de9ce703SDmitry Torokhov 
355b1884583SHans de Goede 	if (!i8042_present)
356b1884583SHans de Goede 		return -1;
357b1884583SHans de Goede 
358de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
359de9ce703SDmitry Torokhov 	retval = __i8042_command(param, command);
360463a4f76SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
361de9ce703SDmitry Torokhov 
3621da177e4SLinus Torvalds 	return retval;
3631da177e4SLinus Torvalds }
364553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command);
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds /*
3671da177e4SLinus Torvalds  * i8042_kbd_write() sends a byte out through the keyboard interface.
3681da177e4SLinus Torvalds  */
3691da177e4SLinus Torvalds 
i8042_kbd_write(struct serio * port,unsigned char c)3701da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c)
3711da177e4SLinus Torvalds {
3721da177e4SLinus Torvalds 	unsigned long flags;
3731da177e4SLinus Torvalds 	int retval = 0;
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	if (!(retval = i8042_wait_write())) {
3784eb3c30bSJoe Perches 		dbg("%02x -> i8042 (kbd-data)\n", c);
3791da177e4SLinus Torvalds 		i8042_write_data(c);
3801da177e4SLinus Torvalds 	}
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds 	return retval;
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds /*
3881da177e4SLinus Torvalds  * i8042_aux_write() sends a byte out through the aux interface.
3891da177e4SLinus Torvalds  */
3901da177e4SLinus Torvalds 
i8042_aux_write(struct serio * serio,unsigned char c)3911da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c)
3921da177e4SLinus Torvalds {
3931da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3941da177e4SLinus Torvalds 
395f4e3c711SDmitry Torokhov 	return i8042_command(&c, port->mux == -1 ?
396f4e3c711SDmitry Torokhov 					I8042_CMD_AUX_SEND :
397f4e3c711SDmitry Torokhov 					I8042_CMD_MUX_SEND + port->mux);
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds 
4005ddbc77cSDmitry Torokhov 
4015ddbc77cSDmitry Torokhov /*
4020e2b4458SMarcos Paulo de Souza  * i8042_port_close attempts to clear AUX or KBD port state by disabling
4035ddbc77cSDmitry Torokhov  * and then re-enabling it.
4045ddbc77cSDmitry Torokhov  */
4055ddbc77cSDmitry Torokhov 
i8042_port_close(struct serio * serio)4065ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio)
4075ddbc77cSDmitry Torokhov {
4085ddbc77cSDmitry Torokhov 	int irq_bit;
4095ddbc77cSDmitry Torokhov 	int disable_bit;
4105ddbc77cSDmitry Torokhov 	const char *port_name;
4115ddbc77cSDmitry Torokhov 
4125ddbc77cSDmitry Torokhov 	if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) {
4135ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_AUXINT;
4145ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_AUXDIS;
4155ddbc77cSDmitry Torokhov 		port_name = "AUX";
4165ddbc77cSDmitry Torokhov 	} else {
4175ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_KBDINT;
4185ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_KBDDIS;
4195ddbc77cSDmitry Torokhov 		port_name = "KBD";
4205ddbc77cSDmitry Torokhov 	}
4215ddbc77cSDmitry Torokhov 
4225ddbc77cSDmitry Torokhov 	i8042_ctr &= ~irq_bit;
4235ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
4244eb3c30bSJoe Perches 		pr_warn("Can't write CTR while closing %s port\n", port_name);
4255ddbc77cSDmitry Torokhov 
4265ddbc77cSDmitry Torokhov 	udelay(50);
4275ddbc77cSDmitry Torokhov 
4285ddbc77cSDmitry Torokhov 	i8042_ctr &= ~disable_bit;
4295ddbc77cSDmitry Torokhov 	i8042_ctr |= irq_bit;
4305ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
4314eb3c30bSJoe Perches 		pr_err("Can't reactivate %s port\n", port_name);
4325ddbc77cSDmitry Torokhov 
4335ddbc77cSDmitry Torokhov 	/*
4345ddbc77cSDmitry Torokhov 	 * See if there is any data appeared while we were messing with
4355ddbc77cSDmitry Torokhov 	 * port state.
4365ddbc77cSDmitry Torokhov 	 */
4375ddbc77cSDmitry Torokhov 	i8042_interrupt(0, NULL);
4385ddbc77cSDmitry Torokhov }
4395ddbc77cSDmitry Torokhov 
4401da177e4SLinus Torvalds /*
4411da177e4SLinus Torvalds  * i8042_start() is called by serio core when port is about to finish
4421da177e4SLinus Torvalds  * registering. It will mark port as existing so i8042_interrupt can
4431da177e4SLinus Torvalds  * start sending data through it.
4441da177e4SLinus Torvalds  */
i8042_start(struct serio * serio)4451da177e4SLinus Torvalds static int i8042_start(struct serio *serio)
4461da177e4SLinus Torvalds {
4471da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
4481da177e4SLinus Torvalds 
449c8a144b2SStephen Boyd 	device_set_wakeup_capable(&serio->dev, true);
450c8a144b2SStephen Boyd 
451c8a144b2SStephen Boyd 	/*
452c8a144b2SStephen Boyd 	 * On platforms using suspend-to-idle, allow the keyboard to
453c8a144b2SStephen Boyd 	 * wake up the system from sleep by enabling keyboard wakeups
454c8a144b2SStephen Boyd 	 * by default.  This is consistent with keyboard wakeup
455c8a144b2SStephen Boyd 	 * behavior on many platforms using suspend-to-RAM (ACPI S3)
456c8a144b2SStephen Boyd 	 * by default.
457c8a144b2SStephen Boyd 	 */
458c8a144b2SStephen Boyd 	if (pm_suspend_default_s2idle() &&
459c8a144b2SStephen Boyd 	    serio == i8042_ports[I8042_KBD_PORT_NO].serio) {
460c8a144b2SStephen Boyd 		device_set_wakeup_enable(&serio->dev, true);
461c8a144b2SStephen Boyd 	}
462c8a144b2SStephen Boyd 
463340d394aSChen Hong 	spin_lock_irq(&i8042_lock);
464386b3849SDmitry Torokhov 	port->exists = true;
465340d394aSChen Hong 	spin_unlock_irq(&i8042_lock);
466340d394aSChen Hong 
4671da177e4SLinus Torvalds 	return 0;
4681da177e4SLinus Torvalds }
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds /*
4711da177e4SLinus Torvalds  * i8042_stop() marks serio port as non-existing so i8042_interrupt
4721da177e4SLinus Torvalds  * will not try to send data to the port that is about to go away.
4731da177e4SLinus Torvalds  * The function is called by serio core as part of unregister procedure.
4741da177e4SLinus Torvalds  */
i8042_stop(struct serio * serio)4751da177e4SLinus Torvalds static void i8042_stop(struct serio *serio)
4761da177e4SLinus Torvalds {
4771da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
4781da177e4SLinus Torvalds 
479340d394aSChen Hong 	spin_lock_irq(&i8042_lock);
480386b3849SDmitry Torokhov 	port->exists = false;
481340d394aSChen Hong 	port->serio = NULL;
482340d394aSChen Hong 	spin_unlock_irq(&i8042_lock);
483a8399c51SDmitry Torokhov 
484a8399c51SDmitry Torokhov 	/*
485340d394aSChen Hong 	 * We need to make sure that interrupt handler finishes using
486340d394aSChen Hong 	 * our serio port before we return from this function.
487a8399c51SDmitry Torokhov 	 * We synchronize with both AUX and KBD IRQs because there is
488a8399c51SDmitry Torokhov 	 * a (very unlikely) chance that AUX IRQ is raised for KBD port
489a8399c51SDmitry Torokhov 	 * and vice versa.
490a8399c51SDmitry Torokhov 	 */
491a8399c51SDmitry Torokhov 	synchronize_irq(I8042_AUX_IRQ);
492a8399c51SDmitry Torokhov 	synchronize_irq(I8042_KBD_IRQ);
4931da177e4SLinus Torvalds }
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds /*
4964e8d340dSDmitry Torokhov  * i8042_filter() filters out unwanted bytes from the input data stream.
4974e8d340dSDmitry Torokhov  * It is called from i8042_interrupt and thus is running with interrupts
4984e8d340dSDmitry Torokhov  * off and i8042_lock held.
4994e8d340dSDmitry Torokhov  */
i8042_filter(unsigned char data,unsigned char str,struct serio * serio)500967c9ef9SMatthew Garrett static bool i8042_filter(unsigned char data, unsigned char str,
501967c9ef9SMatthew Garrett 			 struct serio *serio)
5024e8d340dSDmitry Torokhov {
5034e8d340dSDmitry Torokhov 	if (unlikely(i8042_suppress_kbd_ack)) {
5044e8d340dSDmitry Torokhov 		if ((~str & I8042_STR_AUXDATA) &&
5054e8d340dSDmitry Torokhov 		    (data == 0xfa || data == 0xfe)) {
5064e8d340dSDmitry Torokhov 			i8042_suppress_kbd_ack--;
5074e8d340dSDmitry Torokhov 			dbg("Extra keyboard ACK - filtered out\n");
5084e8d340dSDmitry Torokhov 			return true;
5094e8d340dSDmitry Torokhov 		}
5104e8d340dSDmitry Torokhov 	}
5114e8d340dSDmitry Torokhov 
512967c9ef9SMatthew Garrett 	if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
5130747e3bcSStefan Weil 		dbg("Filtered out by platform filter\n");
514967c9ef9SMatthew Garrett 		return true;
515967c9ef9SMatthew Garrett 	}
516967c9ef9SMatthew Garrett 
5174e8d340dSDmitry Torokhov 	return false;
5184e8d340dSDmitry Torokhov }
5194e8d340dSDmitry Torokhov 
5204e8d340dSDmitry Torokhov /*
5211da177e4SLinus Torvalds  * i8042_interrupt() is the most important function in this driver -
5221da177e4SLinus Torvalds  * it handles the interrupts from the i8042, and sends incoming bytes
5231da177e4SLinus Torvalds  * to the upper layers.
5241da177e4SLinus Torvalds  */
5251da177e4SLinus Torvalds 
i8042_interrupt(int irq,void * dev_id)5267d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id)
5271da177e4SLinus Torvalds {
5281da177e4SLinus Torvalds 	struct i8042_port *port;
529967c9ef9SMatthew Garrett 	struct serio *serio;
5301da177e4SLinus Torvalds 	unsigned long flags;
5311da177e4SLinus Torvalds 	unsigned char str, data;
5321da177e4SLinus Torvalds 	unsigned int dfl;
5331da177e4SLinus Torvalds 	unsigned int port_no;
5344e8d340dSDmitry Torokhov 	bool filtered;
535817e6ba3SDmitry Torokhov 	int ret = 1;
5361da177e4SLinus Torvalds 
5371da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
5384e8d340dSDmitry Torokhov 
5391da177e4SLinus Torvalds 	str = i8042_read_status();
5401da177e4SLinus Torvalds 	if (unlikely(~str & I8042_STR_OBF)) {
5411da177e4SLinus Torvalds 		spin_unlock_irqrestore(&i8042_lock, flags);
5424eb3c30bSJoe Perches 		if (irq)
5434eb3c30bSJoe Perches 			dbg("Interrupt %d, without any data\n", irq);
5441da177e4SLinus Torvalds 		ret = 0;
5451da177e4SLinus Torvalds 		goto out;
5461da177e4SLinus Torvalds 	}
5474e8d340dSDmitry Torokhov 
5481da177e4SLinus Torvalds 	data = i8042_read_data();
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
5511da177e4SLinus Torvalds 		static unsigned long last_transmit;
5521da177e4SLinus Torvalds 		static unsigned char last_str;
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds 		dfl = 0;
5551da177e4SLinus Torvalds 		if (str & I8042_STR_MUXERR) {
5564eb3c30bSJoe Perches 			dbg("MUX error, status is %02x, data is %02x\n",
5574eb3c30bSJoe Perches 			    str, data);
5581da177e4SLinus Torvalds /*
5591da177e4SLinus Torvalds  * When MUXERR condition is signalled the data register can only contain
5601da177e4SLinus Torvalds  * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
561a216a4b6SDmitry Torokhov  * it is not always the case. Some KBCs also report 0xfc when there is
562a216a4b6SDmitry Torokhov  * nothing connected to the port while others sometimes get confused which
563a216a4b6SDmitry Torokhov  * port the data came from and signal error leaving the data intact. They
564a216a4b6SDmitry Torokhov  * _do not_ revert to legacy mode (actually I've never seen KBC reverting
565a216a4b6SDmitry Torokhov  * to legacy mode yet, when we see one we'll add proper handling).
566a216a4b6SDmitry Torokhov  * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the
567a216a4b6SDmitry Torokhov  * rest assume that the data came from the same serio last byte
5681da177e4SLinus Torvalds  * was transmitted (if transmission happened not too long ago).
5691da177e4SLinus Torvalds  */
570a216a4b6SDmitry Torokhov 
571a216a4b6SDmitry Torokhov 			switch (data) {
572a216a4b6SDmitry Torokhov 				default:
5731da177e4SLinus Torvalds 					if (time_before(jiffies, last_transmit + HZ/10)) {
5741da177e4SLinus Torvalds 						str = last_str;
5751da177e4SLinus Torvalds 						break;
5761da177e4SLinus Torvalds 					}
5776f49c4f5SGustavo A. R. Silva 					fallthrough;	/* report timeout */
578a216a4b6SDmitry Torokhov 				case 0xfc:
5791da177e4SLinus Torvalds 				case 0xfd:
5801da177e4SLinus Torvalds 				case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
5811da177e4SLinus Torvalds 				case 0xff: dfl = SERIO_PARITY;  data = 0xfe; break;
5821da177e4SLinus Torvalds 			}
5831da177e4SLinus Torvalds 		}
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 		port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
5861da177e4SLinus Torvalds 		last_str = str;
5871da177e4SLinus Torvalds 		last_transmit = jiffies;
5881da177e4SLinus Torvalds 	} else {
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds 		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
591f8313ef1SJiri Kosina 		      ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0);
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 		port_no = (str & I8042_STR_AUXDATA) ?
5941da177e4SLinus Torvalds 				I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
5951da177e4SLinus Torvalds 	}
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds 	port = &i8042_ports[port_no];
598967c9ef9SMatthew Garrett 	serio = port->exists ? port->serio : NULL;
5991da177e4SLinus Torvalds 
600e1443d28SStephen Chandler Paul 	filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n",
601e1443d28SStephen Chandler Paul 		   port_no, irq,
6021da177e4SLinus Torvalds 		   dfl & SERIO_PARITY ? ", bad parity" : "",
6031da177e4SLinus Torvalds 		   dfl & SERIO_TIMEOUT ? ", timeout" : "");
6041da177e4SLinus Torvalds 
605967c9ef9SMatthew Garrett 	filtered = i8042_filter(data, str, serio);
606817e6ba3SDmitry Torokhov 
6074e8d340dSDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
6084e8d340dSDmitry Torokhov 
609340d394aSChen Hong 	if (likely(serio && !filtered))
610967c9ef9SMatthew Garrett 		serio_interrupt(serio, data, dfl);
6111da177e4SLinus Torvalds 
6121da177e4SLinus Torvalds  out:
6131da177e4SLinus Torvalds 	return IRQ_RETVAL(ret);
6141da177e4SLinus Torvalds }
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds /*
6175ddbc77cSDmitry Torokhov  * i8042_enable_kbd_port enables keyboard port on chip
618de9ce703SDmitry Torokhov  */
619de9ce703SDmitry Torokhov 
i8042_enable_kbd_port(void)620de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void)
621de9ce703SDmitry Torokhov {
622de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_KBDDIS;
623de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDINT;
624de9ce703SDmitry Torokhov 
625de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
626018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_KBDINT;
627018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_KBDDIS;
6284eb3c30bSJoe Perches 		pr_err("Failed to enable KBD port\n");
629de9ce703SDmitry Torokhov 		return -EIO;
630de9ce703SDmitry Torokhov 	}
631de9ce703SDmitry Torokhov 
632de9ce703SDmitry Torokhov 	return 0;
633de9ce703SDmitry Torokhov }
634de9ce703SDmitry Torokhov 
635de9ce703SDmitry Torokhov /*
636de9ce703SDmitry Torokhov  * i8042_enable_aux_port enables AUX (mouse) port on chip
637de9ce703SDmitry Torokhov  */
638de9ce703SDmitry Torokhov 
i8042_enable_aux_port(void)639de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void)
640de9ce703SDmitry Torokhov {
641de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXDIS;
642de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXINT;
643de9ce703SDmitry Torokhov 
644de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
645018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_AUXINT;
646018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_AUXDIS;
6474eb3c30bSJoe Perches 		pr_err("Failed to enable AUX port\n");
648de9ce703SDmitry Torokhov 		return -EIO;
649de9ce703SDmitry Torokhov 	}
650de9ce703SDmitry Torokhov 
651de9ce703SDmitry Torokhov 	return 0;
652de9ce703SDmitry Torokhov }
653de9ce703SDmitry Torokhov 
654de9ce703SDmitry Torokhov /*
655de9ce703SDmitry Torokhov  * i8042_enable_mux_ports enables 4 individual AUX ports after
656de9ce703SDmitry Torokhov  * the controller has been switched into Multiplexed mode
657de9ce703SDmitry Torokhov  */
658de9ce703SDmitry Torokhov 
i8042_enable_mux_ports(void)659de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void)
660de9ce703SDmitry Torokhov {
661de9ce703SDmitry Torokhov 	unsigned char param;
662de9ce703SDmitry Torokhov 	int i;
663de9ce703SDmitry Torokhov 
664de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
665de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_MUX_PFX + i);
666de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_AUX_ENABLE);
667de9ce703SDmitry Torokhov 	}
668de9ce703SDmitry Torokhov 
669de9ce703SDmitry Torokhov 	return i8042_enable_aux_port();
670de9ce703SDmitry Torokhov }
671de9ce703SDmitry Torokhov 
672de9ce703SDmitry Torokhov /*
673386b3849SDmitry Torokhov  * i8042_set_mux_mode checks whether the controller has an
674386b3849SDmitry Torokhov  * active multiplexor and puts the chip into Multiplexed (true)
675386b3849SDmitry Torokhov  * or Legacy (false) mode.
6761da177e4SLinus Torvalds  */
6771da177e4SLinus Torvalds 
i8042_set_mux_mode(bool multiplex,unsigned char * mux_version)678386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version)
6791da177e4SLinus Torvalds {
6801da177e4SLinus Torvalds 
681386b3849SDmitry Torokhov 	unsigned char param, val;
6821da177e4SLinus Torvalds /*
6831da177e4SLinus Torvalds  * Get rid of bytes in the queue.
6841da177e4SLinus Torvalds  */
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	i8042_flush();
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds /*
6891da177e4SLinus Torvalds  * Internal loopback test - send three bytes, they should come back from the
690de9ce703SDmitry Torokhov  * mouse interface, the last should be version.
6911da177e4SLinus Torvalds  */
6921da177e4SLinus Torvalds 
693386b3849SDmitry Torokhov 	param = val = 0xf0;
694386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6951da177e4SLinus Torvalds 		return -1;
696386b3849SDmitry Torokhov 	param = val = multiplex ? 0x56 : 0xf6;
697386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6981da177e4SLinus Torvalds 		return -1;
699386b3849SDmitry Torokhov 	param = val = multiplex ? 0xa4 : 0xa5;
700386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == val)
701386b3849SDmitry Torokhov 		return -1;
702386b3849SDmitry Torokhov 
703386b3849SDmitry Torokhov /*
704386b3849SDmitry Torokhov  * Workaround for interference with USB Legacy emulation
705386b3849SDmitry Torokhov  * that causes a v10.12 MUX to be found.
706386b3849SDmitry Torokhov  */
707386b3849SDmitry Torokhov 	if (param == 0xac)
7081da177e4SLinus Torvalds 		return -1;
7091da177e4SLinus Torvalds 
7101da177e4SLinus Torvalds 	if (mux_version)
711463a4f76SDmitry Torokhov 		*mux_version = param;
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds 	return 0;
7141da177e4SLinus Torvalds }
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds /*
7171da177e4SLinus Torvalds  * i8042_check_mux() checks whether the controller supports the PS/2 Active
7181da177e4SLinus Torvalds  * Multiplexing specification by Synaptics, Phoenix, Insyde and
7191da177e4SLinus Torvalds  * LCS/Telegraphics.
7201da177e4SLinus Torvalds  */
7211da177e4SLinus Torvalds 
i8042_check_mux(void)7229222ba68STakashi Iwai static int i8042_check_mux(void)
7231da177e4SLinus Torvalds {
7241da177e4SLinus Torvalds 	unsigned char mux_version;
7251da177e4SLinus Torvalds 
726386b3849SDmitry Torokhov 	if (i8042_set_mux_mode(true, &mux_version))
7271da177e4SLinus Torvalds 		return -1;
7281da177e4SLinus Torvalds 
7294eb3c30bSJoe Perches 	pr_info("Detected active multiplexing controller, rev %d.%d\n",
7301da177e4SLinus Torvalds 		(mux_version >> 4) & 0xf, mux_version & 0xf);
7311da177e4SLinus Torvalds 
732de9ce703SDmitry Torokhov /*
733de9ce703SDmitry Torokhov  * Disable all muxed ports by disabling AUX.
734de9ce703SDmitry Torokhov  */
735de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS;
736de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXINT;
737de9ce703SDmitry Torokhov 
738de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
7394eb3c30bSJoe Perches 		pr_err("Failed to disable AUX port, can't use MUX\n");
740de9ce703SDmitry Torokhov 		return -EIO;
741de9ce703SDmitry Torokhov 	}
7421da177e4SLinus Torvalds 
743386b3849SDmitry Torokhov 	i8042_mux_present = true;
744de9ce703SDmitry Torokhov 
7451da177e4SLinus Torvalds 	return 0;
7461da177e4SLinus Torvalds }
7471da177e4SLinus Torvalds 
748de9ce703SDmitry Torokhov /*
749de9ce703SDmitry Torokhov  * The following is used to test AUX IRQ delivery.
750de9ce703SDmitry Torokhov  */
7519222ba68STakashi Iwai static struct completion i8042_aux_irq_delivered;
7529222ba68STakashi Iwai static bool i8042_irq_being_tested;
753de9ce703SDmitry Torokhov 
i8042_aux_test_irq(int irq,void * dev_id)7549222ba68STakashi Iwai static irqreturn_t i8042_aux_test_irq(int irq, void *dev_id)
755de9ce703SDmitry Torokhov {
756de9ce703SDmitry Torokhov 	unsigned long flags;
757de9ce703SDmitry Torokhov 	unsigned char str, data;
758e3758b2aSFernando Luis Vázquez Cao 	int ret = 0;
759de9ce703SDmitry Torokhov 
760de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
761de9ce703SDmitry Torokhov 	str = i8042_read_status();
762de9ce703SDmitry Torokhov 	if (str & I8042_STR_OBF) {
763de9ce703SDmitry Torokhov 		data = i8042_read_data();
7644eb3c30bSJoe Perches 		dbg("%02x <- i8042 (aux_test_irq, %s)\n",
765d3d2dfe2SDmitry Torokhov 		    data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
766de9ce703SDmitry Torokhov 		if (i8042_irq_being_tested &&
767de9ce703SDmitry Torokhov 		    data == 0xa5 && (str & I8042_STR_AUXDATA))
768de9ce703SDmitry Torokhov 			complete(&i8042_aux_irq_delivered);
769e3758b2aSFernando Luis Vázquez Cao 		ret = 1;
770de9ce703SDmitry Torokhov 	}
771de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
772de9ce703SDmitry Torokhov 
773e3758b2aSFernando Luis Vázquez Cao 	return IRQ_RETVAL(ret);
774de9ce703SDmitry Torokhov }
775de9ce703SDmitry Torokhov 
776d2ada559SRoland Scheidegger /*
777d2ada559SRoland Scheidegger  * i8042_toggle_aux - enables or disables AUX port on i8042 via command and
778d2ada559SRoland Scheidegger  * verifies success by readinng CTR. Used when testing for presence of AUX
779d2ada559SRoland Scheidegger  * port.
780d2ada559SRoland Scheidegger  */
i8042_toggle_aux(bool on)7819222ba68STakashi Iwai static int i8042_toggle_aux(bool on)
782d2ada559SRoland Scheidegger {
783d2ada559SRoland Scheidegger 	unsigned char param;
784d2ada559SRoland Scheidegger 	int i;
785d2ada559SRoland Scheidegger 
786d2ada559SRoland Scheidegger 	if (i8042_command(&param,
787d2ada559SRoland Scheidegger 			on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE))
788d2ada559SRoland Scheidegger 		return -1;
789d2ada559SRoland Scheidegger 
790d2ada559SRoland Scheidegger 	/* some chips need some time to set the I8042_CTR_AUXDIS bit */
791d2ada559SRoland Scheidegger 	for (i = 0; i < 100; i++) {
792d2ada559SRoland Scheidegger 		udelay(50);
793d2ada559SRoland Scheidegger 
794d2ada559SRoland Scheidegger 		if (i8042_command(&param, I8042_CMD_CTL_RCTR))
795d2ada559SRoland Scheidegger 			return -1;
796d2ada559SRoland Scheidegger 
797d2ada559SRoland Scheidegger 		if (!(param & I8042_CTR_AUXDIS) == on)
798d2ada559SRoland Scheidegger 			return 0;
799d2ada559SRoland Scheidegger 	}
800d2ada559SRoland Scheidegger 
801d2ada559SRoland Scheidegger 	return -1;
802d2ada559SRoland Scheidegger }
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds /*
8051da177e4SLinus Torvalds  * i8042_check_aux() applies as much paranoia as it can at detecting
8061da177e4SLinus Torvalds  * the presence of an AUX interface.
8071da177e4SLinus Torvalds  */
8081da177e4SLinus Torvalds 
i8042_check_aux(void)8099222ba68STakashi Iwai static int i8042_check_aux(void)
8101da177e4SLinus Torvalds {
811de9ce703SDmitry Torokhov 	int retval = -1;
812386b3849SDmitry Torokhov 	bool irq_registered = false;
813386b3849SDmitry Torokhov 	bool aux_loop_broken = false;
814de9ce703SDmitry Torokhov 	unsigned long flags;
8151da177e4SLinus Torvalds 	unsigned char param;
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds /*
8181da177e4SLinus Torvalds  * Get rid of bytes in the queue.
8191da177e4SLinus Torvalds  */
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 	i8042_flush();
8221da177e4SLinus Torvalds 
8231da177e4SLinus Torvalds /*
8241da177e4SLinus Torvalds  * Internal loopback test - filters out AT-type i8042's. Unfortunately
8251da177e4SLinus Torvalds  * SiS screwed up and their 5597 doesn't support the LOOP command even
8261da177e4SLinus Torvalds  * though it has an AUX port.
8271da177e4SLinus Torvalds  */
8281da177e4SLinus Torvalds 
8291da177e4SLinus Torvalds 	param = 0x5a;
8303ca5de6dSDmitry Torokhov 	retval = i8042_command(&param, I8042_CMD_AUX_LOOP);
8313ca5de6dSDmitry Torokhov 	if (retval || param != 0x5a) {
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds /*
8341da177e4SLinus Torvalds  * External connection test - filters out AT-soldered PS/2 i8042's
8351da177e4SLinus Torvalds  * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error
8361da177e4SLinus Torvalds  * 0xfa - no error on some notebooks which ignore the spec
8371da177e4SLinus Torvalds  * Because it's common for chipsets to return error on perfectly functioning
8381da177e4SLinus Torvalds  * AUX ports, we test for this only when the LOOP command failed.
8391da177e4SLinus Torvalds  */
8401da177e4SLinus Torvalds 
841de9ce703SDmitry Torokhov 		if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
842de9ce703SDmitry Torokhov 		    (param && param != 0xfa && param != 0xff))
8431da177e4SLinus Torvalds 			return -1;
8441e4865f8SDmitry Torokhov 
8453ca5de6dSDmitry Torokhov /*
8463ca5de6dSDmitry Torokhov  * If AUX_LOOP completed without error but returned unexpected data
8473ca5de6dSDmitry Torokhov  * mark it as broken
8483ca5de6dSDmitry Torokhov  */
8493ca5de6dSDmitry Torokhov 		if (!retval)
850386b3849SDmitry Torokhov 			aux_loop_broken = true;
8511da177e4SLinus Torvalds 	}
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds /*
8541da177e4SLinus Torvalds  * Bit assignment test - filters out PS/2 i8042's in AT mode
8551da177e4SLinus Torvalds  */
8561da177e4SLinus Torvalds 
857386b3849SDmitry Torokhov 	if (i8042_toggle_aux(false)) {
8584eb3c30bSJoe Perches 		pr_warn("Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
8594eb3c30bSJoe Perches 		pr_warn("If AUX port is really absent please use the 'i8042.noaux' option\n");
8601da177e4SLinus Torvalds 	}
8611da177e4SLinus Torvalds 
862386b3849SDmitry Torokhov 	if (i8042_toggle_aux(true))
8631da177e4SLinus Torvalds 		return -1;
8641da177e4SLinus Torvalds 
8651da177e4SLinus Torvalds /*
866148e9a71SSrihari Vijayaraghavan  * Reset keyboard (needed on some laptops to successfully detect
867148e9a71SSrihari Vijayaraghavan  * touchpad, e.g., some Gigabyte laptop models with Elantech
868148e9a71SSrihari Vijayaraghavan  * touchpads).
869148e9a71SSrihari Vijayaraghavan  */
870148e9a71SSrihari Vijayaraghavan 	if (i8042_kbdreset) {
871148e9a71SSrihari Vijayaraghavan 		pr_warn("Attempting to reset device connected to KBD port\n");
872148e9a71SSrihari Vijayaraghavan 		i8042_kbd_write(NULL, (unsigned char) 0xff);
873148e9a71SSrihari Vijayaraghavan 	}
874148e9a71SSrihari Vijayaraghavan 
875148e9a71SSrihari Vijayaraghavan /*
876de9ce703SDmitry Torokhov  * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and
877de9ce703SDmitry Torokhov  * used it for a PCI card or somethig else.
878de9ce703SDmitry Torokhov  */
879de9ce703SDmitry Torokhov 
8801c7827aeSDmitry Torokhov 	if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) {
881de9ce703SDmitry Torokhov /*
882de9ce703SDmitry Torokhov  * Without LOOP command we can't test AUX IRQ delivery. Assume the port
883de9ce703SDmitry Torokhov  * is working and hope we are right.
884de9ce703SDmitry Torokhov  */
885de9ce703SDmitry Torokhov 		retval = 0;
886de9ce703SDmitry Torokhov 		goto out;
887de9ce703SDmitry Torokhov 	}
888de9ce703SDmitry Torokhov 
889de9ce703SDmitry Torokhov 	if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED,
890de9ce703SDmitry Torokhov 			"i8042", i8042_platform_device))
891de9ce703SDmitry Torokhov 		goto out;
892de9ce703SDmitry Torokhov 
893386b3849SDmitry Torokhov 	irq_registered = true;
894de9ce703SDmitry Torokhov 
895de9ce703SDmitry Torokhov 	if (i8042_enable_aux_port())
896de9ce703SDmitry Torokhov 		goto out;
897de9ce703SDmitry Torokhov 
898de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
899de9ce703SDmitry Torokhov 
900de9ce703SDmitry Torokhov 	init_completion(&i8042_aux_irq_delivered);
901386b3849SDmitry Torokhov 	i8042_irq_being_tested = true;
902de9ce703SDmitry Torokhov 
903de9ce703SDmitry Torokhov 	param = 0xa5;
904de9ce703SDmitry Torokhov 	retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);
905de9ce703SDmitry Torokhov 
906de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
907de9ce703SDmitry Torokhov 
908de9ce703SDmitry Torokhov 	if (retval)
909de9ce703SDmitry Torokhov 		goto out;
910de9ce703SDmitry Torokhov 
911de9ce703SDmitry Torokhov 	if (wait_for_completion_timeout(&i8042_aux_irq_delivered,
912de9ce703SDmitry Torokhov 					msecs_to_jiffies(250)) == 0) {
913de9ce703SDmitry Torokhov /*
914de9ce703SDmitry Torokhov  * AUX IRQ was never delivered so we need to flush the controller to
915de9ce703SDmitry Torokhov  * get rid of the byte we put there; otherwise keyboard may not work.
916de9ce703SDmitry Torokhov  */
9174eb3c30bSJoe Perches 		dbg("     -- i8042 (aux irq test timeout)\n");
918de9ce703SDmitry Torokhov 		i8042_flush();
919de9ce703SDmitry Torokhov 		retval = -1;
920de9ce703SDmitry Torokhov 	}
921de9ce703SDmitry Torokhov 
922de9ce703SDmitry Torokhov  out:
923de9ce703SDmitry Torokhov 
924de9ce703SDmitry Torokhov /*
9251da177e4SLinus Torvalds  * Disable the interface.
9261da177e4SLinus Torvalds  */
9271da177e4SLinus Torvalds 
9281da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_AUXDIS;
9291da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_AUXINT;
9301da177e4SLinus Torvalds 
9311da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
932de9ce703SDmitry Torokhov 		retval = -1;
933de9ce703SDmitry Torokhov 
934de9ce703SDmitry Torokhov 	if (irq_registered)
935de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
936de9ce703SDmitry Torokhov 
937de9ce703SDmitry Torokhov 	return retval;
938de9ce703SDmitry Torokhov }
939de9ce703SDmitry Torokhov 
i8042_controller_check(void)940de9ce703SDmitry Torokhov static int i8042_controller_check(void)
941de9ce703SDmitry Torokhov {
9422f0d2604SAndrey Moiseev 	if (i8042_flush()) {
943f5d75341STakashi Iwai 		pr_info("No controller found\n");
944de9ce703SDmitry Torokhov 		return -ENODEV;
945de9ce703SDmitry Torokhov 	}
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds 	return 0;
9481da177e4SLinus Torvalds }
9491da177e4SLinus Torvalds 
i8042_controller_selftest(void)950de9ce703SDmitry Torokhov static int i8042_controller_selftest(void)
9512673c836SVojtech Pavlik {
9522673c836SVojtech Pavlik 	unsigned char param;
9535ea2fc64SArjan van de Ven 	int i = 0;
9542673c836SVojtech Pavlik 
9555ea2fc64SArjan van de Ven 	/*
9565ea2fc64SArjan van de Ven 	 * We try this 5 times; on some really fragile systems this does not
9575ea2fc64SArjan van de Ven 	 * take the first time...
9585ea2fc64SArjan van de Ven 	 */
9595ea2fc64SArjan van de Ven 	do {
9605ea2fc64SArjan van de Ven 
9612673c836SVojtech Pavlik 		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
9624eb3c30bSJoe Perches 			pr_err("i8042 controller selftest timeout\n");
963de9ce703SDmitry Torokhov 			return -ENODEV;
9642673c836SVojtech Pavlik 		}
9652673c836SVojtech Pavlik 
9665ea2fc64SArjan van de Ven 		if (param == I8042_RET_CTL_TEST)
9675ea2fc64SArjan van de Ven 			return 0;
9685ea2fc64SArjan van de Ven 
969a2a94e73SPaul Bolle 		dbg("i8042 controller selftest: %#x != %#x\n",
9702673c836SVojtech Pavlik 		    param, I8042_RET_CTL_TEST);
9715ea2fc64SArjan van de Ven 		msleep(50);
9725ea2fc64SArjan van de Ven 	} while (i++ < 5);
9732673c836SVojtech Pavlik 
9745ea2fc64SArjan van de Ven #ifdef CONFIG_X86
9755ea2fc64SArjan van de Ven 	/*
9765ea2fc64SArjan van de Ven 	 * On x86, we don't fail entire i8042 initialization if controller
9775ea2fc64SArjan van de Ven 	 * reset fails in hopes that keyboard port will still be functional
9785ea2fc64SArjan van de Ven 	 * and user will still get a working keyboard. This is especially
9795ea2fc64SArjan van de Ven 	 * important on netbooks. On other arches we trust hardware more.
9805ea2fc64SArjan van de Ven 	 */
9814eb3c30bSJoe Perches 	pr_info("giving up on controller selftest, continuing anyway...\n");
9822673c836SVojtech Pavlik 	return 0;
9835ea2fc64SArjan van de Ven #else
984a2a94e73SPaul Bolle 	pr_err("i8042 controller selftest failed\n");
9855ea2fc64SArjan van de Ven 	return -EIO;
9865ea2fc64SArjan van de Ven #endif
9872673c836SVojtech Pavlik }
9881da177e4SLinus Torvalds 
9891da177e4SLinus Torvalds /*
990c2d7ed9dSTyson Moore  * i8042_controller_init initializes the i8042 controller, and,
9911da177e4SLinus Torvalds  * most importantly, sets it into non-xlated mode if that's
9921da177e4SLinus Torvalds  * desired.
9931da177e4SLinus Torvalds  */
9941da177e4SLinus Torvalds 
i8042_controller_init(void)9951da177e4SLinus Torvalds static int i8042_controller_init(void)
9961da177e4SLinus Torvalds {
9971da177e4SLinus Torvalds 	unsigned long flags;
998ee1e82ceSDmitry Torokhov 	int n = 0;
999ee1e82ceSDmitry Torokhov 	unsigned char ctr[2];
10001da177e4SLinus Torvalds 
10011da177e4SLinus Torvalds /*
1002ee1e82ceSDmitry Torokhov  * Save the CTR for restore on unload / reboot.
10031da177e4SLinus Torvalds  */
10041da177e4SLinus Torvalds 
1005ee1e82ceSDmitry Torokhov 	do {
1006ee1e82ceSDmitry Torokhov 		if (n >= 10) {
10074eb3c30bSJoe Perches 			pr_err("Unable to get stable CTR read\n");
1008de9ce703SDmitry Torokhov 			return -EIO;
10091da177e4SLinus Torvalds 		}
10101da177e4SLinus Torvalds 
1011ee1e82ceSDmitry Torokhov 		if (n != 0)
1012ee1e82ceSDmitry Torokhov 			udelay(50);
1013ee1e82ceSDmitry Torokhov 
1014ee1e82ceSDmitry Torokhov 		if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
10154eb3c30bSJoe Perches 			pr_err("Can't read CTR while initializing i8042\n");
10169222ba68STakashi Iwai 			return i8042_probe_defer ? -EPROBE_DEFER : -EIO;
1017ee1e82ceSDmitry Torokhov 		}
1018ee1e82ceSDmitry Torokhov 
1019ee1e82ceSDmitry Torokhov 	} while (n < 2 || ctr[0] != ctr[1]);
1020ee1e82ceSDmitry Torokhov 
1021ee1e82ceSDmitry Torokhov 	i8042_initial_ctr = i8042_ctr = ctr[0];
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds /*
10241da177e4SLinus Torvalds  * Disable the keyboard interface and interrupt.
10251da177e4SLinus Torvalds  */
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_KBDDIS;
10281da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_KBDINT;
10291da177e4SLinus Torvalds 
10301da177e4SLinus Torvalds /*
10311da177e4SLinus Torvalds  * Handle keylock.
10321da177e4SLinus Torvalds  */
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
10351da177e4SLinus Torvalds 	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
10361da177e4SLinus Torvalds 		if (i8042_unlock)
10371da177e4SLinus Torvalds 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
10381da177e4SLinus Torvalds 		else
10394eb3c30bSJoe Perches 			pr_warn("Warning: Keylock active\n");
10401da177e4SLinus Torvalds 	}
10411da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
10421da177e4SLinus Torvalds 
10431da177e4SLinus Torvalds /*
10441da177e4SLinus Torvalds  * If the chip is configured into nontranslated mode by the BIOS, don't
10451da177e4SLinus Torvalds  * bother enabling translating and be happy.
10461da177e4SLinus Torvalds  */
10471da177e4SLinus Torvalds 
10481da177e4SLinus Torvalds 	if (~i8042_ctr & I8042_CTR_XLATE)
1049386b3849SDmitry Torokhov 		i8042_direct = true;
10501da177e4SLinus Torvalds 
10511da177e4SLinus Torvalds /*
10521da177e4SLinus Torvalds  * Set nontranslated mode for the kbd interface if requested by an option.
10531da177e4SLinus Torvalds  * After this the kbd interface becomes a simple serial in/out, like the aux
10541da177e4SLinus Torvalds  * interface is. We don't do this by default, since it can confuse notebook
10551da177e4SLinus Torvalds  * BIOSes.
10561da177e4SLinus Torvalds  */
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds 	if (i8042_direct)
10591da177e4SLinus Torvalds 		i8042_ctr &= ~I8042_CTR_XLATE;
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds /*
10621da177e4SLinus Torvalds  * Write CTR back.
10631da177e4SLinus Torvalds  */
10641da177e4SLinus Torvalds 
10651da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
10664eb3c30bSJoe Perches 		pr_err("Can't write CTR while initializing i8042\n");
1067de9ce703SDmitry Torokhov 		return -EIO;
10681da177e4SLinus Torvalds 	}
10691da177e4SLinus Torvalds 
1070ee1e82ceSDmitry Torokhov /*
1071ee1e82ceSDmitry Torokhov  * Flush whatever accumulated while we were disabling keyboard port.
1072ee1e82ceSDmitry Torokhov  */
1073ee1e82ceSDmitry Torokhov 
1074ee1e82ceSDmitry Torokhov 	i8042_flush();
1075ee1e82ceSDmitry Torokhov 
10761da177e4SLinus Torvalds 	return 0;
10771da177e4SLinus Torvalds }
10781da177e4SLinus Torvalds 
10791da177e4SLinus Torvalds 
10801da177e4SLinus Torvalds /*
1081de9ce703SDmitry Torokhov  * Reset the controller and reset CRT to the original value set by BIOS.
10821da177e4SLinus Torvalds  */
10831da177e4SLinus Torvalds 
i8042_controller_reset(bool s2r_wants_reset)1084930e1924SMarcos Paulo de Souza static void i8042_controller_reset(bool s2r_wants_reset)
1085de9ce703SDmitry Torokhov {
1086de9ce703SDmitry Torokhov 	i8042_flush();
10871da177e4SLinus Torvalds 
10881da177e4SLinus Torvalds /*
10898d04ddb6SDmitry Torokhov  * Disable both KBD and AUX interfaces so they don't get in the way
10908d04ddb6SDmitry Torokhov  */
10918d04ddb6SDmitry Torokhov 
10928d04ddb6SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
10938d04ddb6SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
10948d04ddb6SDmitry Torokhov 
1095ee1e82ceSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
10964eb3c30bSJoe Perches 		pr_warn("Can't write CTR while resetting\n");
10975ddbc77cSDmitry Torokhov 
10988d04ddb6SDmitry Torokhov /*
10991da177e4SLinus Torvalds  * Disable MUX mode if present.
11001da177e4SLinus Torvalds  */
11011da177e4SLinus Torvalds 
11021da177e4SLinus Torvalds 	if (i8042_mux_present)
1103386b3849SDmitry Torokhov 		i8042_set_mux_mode(false, NULL);
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds /*
1106de9ce703SDmitry Torokhov  * Reset the controller if requested.
1107de9ce703SDmitry Torokhov  */
1108de9ce703SDmitry Torokhov 
1109930e1924SMarcos Paulo de Souza 	if (i8042_reset == I8042_RESET_ALWAYS ||
1110930e1924SMarcos Paulo de Souza 	    (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
1111de9ce703SDmitry Torokhov 		i8042_controller_selftest();
1112930e1924SMarcos Paulo de Souza 	}
1113de9ce703SDmitry Torokhov 
1114de9ce703SDmitry Torokhov /*
11151da177e4SLinus Torvalds  * Restore the original control register setting.
11161da177e4SLinus Torvalds  */
11171da177e4SLinus Torvalds 
1118de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
11194eb3c30bSJoe Perches 		pr_warn("Can't restore CTR\n");
11201da177e4SLinus Torvalds }
11211da177e4SLinus Torvalds 
11221da177e4SLinus Torvalds 
11231da177e4SLinus Torvalds /*
1124c7ff0d9cSTAMUKI Shoichi  * i8042_panic_blink() will turn the keyboard LEDs on or off and is called
1125c7ff0d9cSTAMUKI Shoichi  * when kernel panics. Flashing LEDs is useful for users running X who may
1126aa5e5dc2SMichael Opdenacker  * not see the console and will help distinguishing panics from "real"
11271da177e4SLinus Torvalds  * lockups.
11281da177e4SLinus Torvalds  *
11291da177e4SLinus Torvalds  * Note that DELAY has a limit of 10ms so we will not get stuck here
11301da177e4SLinus Torvalds  * waiting for KBC to free up even if KBD interrupt is off
11311da177e4SLinus Torvalds  */
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
11341da177e4SLinus Torvalds 
i8042_panic_blink(int state)1135c7ff0d9cSTAMUKI Shoichi static long i8042_panic_blink(int state)
11361da177e4SLinus Torvalds {
11371da177e4SLinus Torvalds 	long delay = 0;
1138c7ff0d9cSTAMUKI Shoichi 	char led;
11391da177e4SLinus Torvalds 
1140c7ff0d9cSTAMUKI Shoichi 	led = (state) ? 0x01 | 0x04 : 0;
11411da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
11421da177e4SLinus Torvalds 		DELAY;
11434eb3c30bSJoe Perches 	dbg("%02x -> i8042 (panic blink)\n", 0xed);
114419f3c3e3SDmitry Torokhov 	i8042_suppress_kbd_ack = 2;
11451da177e4SLinus Torvalds 	i8042_write_data(0xed); /* set leds */
11461da177e4SLinus Torvalds 	DELAY;
11471da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
11481da177e4SLinus Torvalds 		DELAY;
11491da177e4SLinus Torvalds 	DELAY;
11504eb3c30bSJoe Perches 	dbg("%02x -> i8042 (panic blink)\n", led);
11511da177e4SLinus Torvalds 	i8042_write_data(led);
11521da177e4SLinus Torvalds 	DELAY;
11531da177e4SLinus Torvalds 	return delay;
11541da177e4SLinus Torvalds }
11551da177e4SLinus Torvalds 
11561da177e4SLinus Torvalds #undef DELAY
11571da177e4SLinus Torvalds 
1158d35895dbSBruno Prémont #ifdef CONFIG_X86
i8042_dritek_enable(void)1159d35895dbSBruno Prémont static void i8042_dritek_enable(void)
1160d35895dbSBruno Prémont {
1161594d6363SChristoph Fritz 	unsigned char param = 0x90;
1162d35895dbSBruno Prémont 	int error;
1163d35895dbSBruno Prémont 
1164d35895dbSBruno Prémont 	error = i8042_command(&param, 0x1059);
1165d35895dbSBruno Prémont 	if (error)
11664eb3c30bSJoe Perches 		pr_warn("Failed to enable DRITEK extension: %d\n", error);
1167d35895dbSBruno Prémont }
1168d35895dbSBruno Prémont #endif
1169d35895dbSBruno Prémont 
117082dd9effSDmitry Torokhov #ifdef CONFIG_PM
11717e044e05SDmitry Torokhov 
11721da177e4SLinus Torvalds /*
1173ebd7768dSDmitry Torokhov  * Here we try to reset everything back to a state we had
1174ebd7768dSDmitry Torokhov  * before suspending.
11751da177e4SLinus Torvalds  */
11761da177e4SLinus Torvalds 
i8042_controller_resume(bool s2r_wants_reset)1177930e1924SMarcos Paulo de Souza static int i8042_controller_resume(bool s2r_wants_reset)
11781da177e4SLinus Torvalds {
1179de9ce703SDmitry Torokhov 	int error;
11801da177e4SLinus Torvalds 
1181de9ce703SDmitry Torokhov 	error = i8042_controller_check();
1182de9ce703SDmitry Torokhov 	if (error)
1183de9ce703SDmitry Torokhov 		return error;
11842673c836SVojtech Pavlik 
1185930e1924SMarcos Paulo de Souza 	if (i8042_reset == I8042_RESET_ALWAYS ||
1186930e1924SMarcos Paulo de Souza 	    (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
1187de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1188de9ce703SDmitry Torokhov 		if (error)
1189de9ce703SDmitry Torokhov 			return error;
11901ca56e51SDmitry Torokhov 	}
1191de9ce703SDmitry Torokhov 
1192de9ce703SDmitry Torokhov /*
119382dd9effSDmitry Torokhov  * Restore original CTR value and disable all ports
1194de9ce703SDmitry Torokhov  */
1195de9ce703SDmitry Torokhov 
119682dd9effSDmitry Torokhov 	i8042_ctr = i8042_initial_ctr;
119782dd9effSDmitry Torokhov 	if (i8042_direct)
119882dd9effSDmitry Torokhov 		i8042_ctr &= ~I8042_CTR_XLATE;
1199de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
1200de9ce703SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
12012673c836SVojtech Pavlik 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
12024eb3c30bSJoe Perches 		pr_warn("Can't write CTR to resume, retrying...\n");
12032f6a77d5SJiri Kosina 		msleep(50);
12042f6a77d5SJiri Kosina 		if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
12054eb3c30bSJoe Perches 			pr_err("CTR write retry failed\n");
1206de9ce703SDmitry Torokhov 			return -EIO;
12071da177e4SLinus Torvalds 		}
12082f6a77d5SJiri Kosina 	}
12091da177e4SLinus Torvalds 
1210d35895dbSBruno Prémont 
1211d35895dbSBruno Prémont #ifdef CONFIG_X86
1212d35895dbSBruno Prémont 	if (i8042_dritek)
1213d35895dbSBruno Prémont 		i8042_dritek_enable();
1214d35895dbSBruno Prémont #endif
1215d35895dbSBruno Prémont 
1216de9ce703SDmitry Torokhov 	if (i8042_mux_present) {
1217386b3849SDmitry Torokhov 		if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
12184eb3c30bSJoe Perches 			pr_warn("failed to resume active multiplexor, mouse won't work\n");
1219de9ce703SDmitry Torokhov 	} else if (i8042_ports[I8042_AUX_PORT_NO].serio)
1220de9ce703SDmitry Torokhov 		i8042_enable_aux_port();
12211da177e4SLinus Torvalds 
1222de9ce703SDmitry Torokhov 	if (i8042_ports[I8042_KBD_PORT_NO].serio)
1223de9ce703SDmitry Torokhov 		i8042_enable_kbd_port();
12241da177e4SLinus Torvalds 
12257d12e780SDavid Howells 	i8042_interrupt(0, NULL);
12261da177e4SLinus Torvalds 
12271da177e4SLinus Torvalds 	return 0;
12281da177e4SLinus Torvalds }
1229ebd7768dSDmitry Torokhov 
12301ca56e51SDmitry Torokhov /*
12311ca56e51SDmitry Torokhov  * Here we try to restore the original BIOS settings to avoid
12321ca56e51SDmitry Torokhov  * upsetting it.
12331ca56e51SDmitry Torokhov  */
12341ca56e51SDmitry Torokhov 
i8042_pm_suspend(struct device * dev)12351729ad1fSDmitry Torokhov static int i8042_pm_suspend(struct device *dev)
12361ca56e51SDmitry Torokhov {
1237f13b2065SRafael J. Wysocki 	int i;
1238f13b2065SRafael J. Wysocki 
1239*3d765ae2SWerner Sembach 	if (!i8042_forcenorestore && pm_suspend_via_firmware())
12401729ad1fSDmitry Torokhov 		i8042_controller_reset(true);
12411ca56e51SDmitry Torokhov 
1242f13b2065SRafael J. Wysocki 	/* Set up serio interrupts for system wakeup. */
1243f13b2065SRafael J. Wysocki 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1244f13b2065SRafael J. Wysocki 		struct serio *serio = i8042_ports[i].serio;
1245f13b2065SRafael J. Wysocki 
1246f13b2065SRafael J. Wysocki 		if (serio && device_may_wakeup(&serio->dev))
1247f13b2065SRafael J. Wysocki 			enable_irq_wake(i8042_ports[i].irq);
1248f13b2065SRafael J. Wysocki 	}
1249f13b2065SRafael J. Wysocki 
12501ca56e51SDmitry Torokhov 	return 0;
12511ca56e51SDmitry Torokhov }
12521ca56e51SDmitry Torokhov 
i8042_pm_resume_noirq(struct device * dev)12531c5dd134SRafael J. Wysocki static int i8042_pm_resume_noirq(struct device *dev)
12541c5dd134SRafael J. Wysocki {
1255*3d765ae2SWerner Sembach 	if (i8042_forcenorestore || !pm_resume_via_firmware())
12561c5dd134SRafael J. Wysocki 		i8042_interrupt(0, NULL);
12571c5dd134SRafael J. Wysocki 
12581c5dd134SRafael J. Wysocki 	return 0;
12591c5dd134SRafael J. Wysocki }
12601c5dd134SRafael J. Wysocki 
i8042_pm_resume(struct device * dev)12611ca56e51SDmitry Torokhov static int i8042_pm_resume(struct device *dev)
12621ca56e51SDmitry Torokhov {
1263930e1924SMarcos Paulo de Souza 	bool want_reset;
1264f13b2065SRafael J. Wysocki 	int i;
1265f13b2065SRafael J. Wysocki 
1266f13b2065SRafael J. Wysocki 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1267f13b2065SRafael J. Wysocki 		struct serio *serio = i8042_ports[i].serio;
1268f13b2065SRafael J. Wysocki 
1269f13b2065SRafael J. Wysocki 		if (serio && device_may_wakeup(&serio->dev))
1270f13b2065SRafael J. Wysocki 			disable_irq_wake(i8042_ports[i].irq);
1271f13b2065SRafael J. Wysocki 	}
1272f13b2065SRafael J. Wysocki 
12731ca56e51SDmitry Torokhov 	/*
12741c5dd134SRafael J. Wysocki 	 * If platform firmware was not going to be involved in suspend, we did
12751c5dd134SRafael J. Wysocki 	 * not restore the controller state to whatever it had been at boot
12761c5dd134SRafael J. Wysocki 	 * time, so we do not need to do anything.
12771ca56e51SDmitry Torokhov 	 */
1278*3d765ae2SWerner Sembach 	if (i8042_forcenorestore || !pm_suspend_via_firmware())
12791c5dd134SRafael J. Wysocki 		return 0;
12801c5dd134SRafael J. Wysocki 
12811c5dd134SRafael J. Wysocki 	/*
12821c5dd134SRafael J. Wysocki 	 * We only need to reset the controller if we are resuming after handing
12831c5dd134SRafael J. Wysocki 	 * off control to the platform firmware, otherwise we can simply restore
12841c5dd134SRafael J. Wysocki 	 * the mode.
12851c5dd134SRafael J. Wysocki 	 */
1286930e1924SMarcos Paulo de Souza 	want_reset = pm_resume_via_firmware();
12871c5dd134SRafael J. Wysocki 
1288930e1924SMarcos Paulo de Souza 	return i8042_controller_resume(want_reset);
12891ca56e51SDmitry Torokhov }
12901ca56e51SDmitry Torokhov 
i8042_pm_thaw(struct device * dev)1291c2d1a2a1SAlan Jenkins static int i8042_pm_thaw(struct device *dev)
1292c2d1a2a1SAlan Jenkins {
1293c2d1a2a1SAlan Jenkins 	i8042_interrupt(0, NULL);
1294c2d1a2a1SAlan Jenkins 
1295c2d1a2a1SAlan Jenkins 	return 0;
1296c2d1a2a1SAlan Jenkins }
1297c2d1a2a1SAlan Jenkins 
i8042_pm_reset(struct device * dev)12981729ad1fSDmitry Torokhov static int i8042_pm_reset(struct device *dev)
12991729ad1fSDmitry Torokhov {
13001729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
13011729ad1fSDmitry Torokhov 
13021729ad1fSDmitry Torokhov 	return 0;
13031729ad1fSDmitry Torokhov }
13041729ad1fSDmitry Torokhov 
i8042_pm_restore(struct device * dev)13051ca56e51SDmitry Torokhov static int i8042_pm_restore(struct device *dev)
13061ca56e51SDmitry Torokhov {
13071ca56e51SDmitry Torokhov 	return i8042_controller_resume(false);
13081ca56e51SDmitry Torokhov }
13091ca56e51SDmitry Torokhov 
1310ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = {
13111729ad1fSDmitry Torokhov 	.suspend	= i8042_pm_suspend,
13121c5dd134SRafael J. Wysocki 	.resume_noirq	= i8042_pm_resume_noirq,
13131ca56e51SDmitry Torokhov 	.resume		= i8042_pm_resume,
1314c2d1a2a1SAlan Jenkins 	.thaw		= i8042_pm_thaw,
1315ebd7768dSDmitry Torokhov 	.poweroff	= i8042_pm_reset,
1316ebd7768dSDmitry Torokhov 	.restore	= i8042_pm_restore,
1317ebd7768dSDmitry Torokhov };
1318ebd7768dSDmitry Torokhov 
131982dd9effSDmitry Torokhov #endif /* CONFIG_PM */
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds /*
13221da177e4SLinus Torvalds  * We need to reset the 8042 back to original mode on system shutdown,
13231da177e4SLinus Torvalds  * because otherwise BIOSes will be confused.
13241da177e4SLinus Torvalds  */
13251da177e4SLinus Torvalds 
i8042_shutdown(struct platform_device * dev)13263ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev)
13271da177e4SLinus Torvalds {
13281729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
13291da177e4SLinus Torvalds }
13301da177e4SLinus Torvalds 
i8042_create_kbd_port(void)13319222ba68STakashi Iwai static int i8042_create_kbd_port(void)
13321da177e4SLinus Torvalds {
13331da177e4SLinus Torvalds 	struct serio *serio;
13341da177e4SLinus Torvalds 	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
13351da177e4SLinus Torvalds 
133606b449d7SErick Archer 	serio = kzalloc(sizeof(*serio), GFP_KERNEL);
13370854e52dSDmitry Torokhov 	if (!serio)
13380854e52dSDmitry Torokhov 		return -ENOMEM;
13390854e52dSDmitry Torokhov 
13401da177e4SLinus Torvalds 	serio->id.type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL;
13411da177e4SLinus Torvalds 	serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write;
13421da177e4SLinus Torvalds 	serio->start		= i8042_start;
13431da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
13445ddbc77cSDmitry Torokhov 	serio->close		= i8042_port_close;
134540974618SDmitry Torokhov 	serio->ps2_cmd_mutex	= &i8042_mutex;
13461da177e4SLinus Torvalds 	serio->port_data	= port;
13471da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1348a9f08ad7SWolfram Sang 	strscpy(serio->name, "i8042 KBD port", sizeof(serio->name));
1349a9f08ad7SWolfram Sang 	strscpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
1350a9f08ad7SWolfram Sang 	strscpy(serio->firmware_id, i8042_kbd_firmware_id,
1351a7c5868cSHans de Goede 		sizeof(serio->firmware_id));
13526052abf8SRajat Jain 	set_primary_fwnode(&serio->dev, i8042_kbd_fwnode);
13531da177e4SLinus Torvalds 
13541da177e4SLinus Torvalds 	port->serio = serio;
1355de9ce703SDmitry Torokhov 	port->irq = I8042_KBD_IRQ;
13560854e52dSDmitry Torokhov 
1357de9ce703SDmitry Torokhov 	return 0;
13581da177e4SLinus Torvalds }
13591da177e4SLinus Torvalds 
i8042_create_aux_port(int idx)13609222ba68STakashi Iwai static int i8042_create_aux_port(int idx)
13611da177e4SLinus Torvalds {
13621da177e4SLinus Torvalds 	struct serio *serio;
1363de9ce703SDmitry Torokhov 	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
1364de9ce703SDmitry Torokhov 	struct i8042_port *port = &i8042_ports[port_no];
13651da177e4SLinus Torvalds 
136606b449d7SErick Archer 	serio = kzalloc(sizeof(*serio), GFP_KERNEL);
13670854e52dSDmitry Torokhov 	if (!serio)
13680854e52dSDmitry Torokhov 		return -ENOMEM;
13690854e52dSDmitry Torokhov 
13701da177e4SLinus Torvalds 	serio->id.type		= SERIO_8042;
13711da177e4SLinus Torvalds 	serio->write		= i8042_aux_write;
13721da177e4SLinus Torvalds 	serio->start		= i8042_start;
13731da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
137447af45d6SDmitry Torokhov 	serio->ps2_cmd_mutex	= &i8042_mutex;
13751da177e4SLinus Torvalds 	serio->port_data	= port;
13761da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1377de9ce703SDmitry Torokhov 	if (idx < 0) {
1378a9f08ad7SWolfram Sang 		strscpy(serio->name, "i8042 AUX port", sizeof(serio->name));
1379a9f08ad7SWolfram Sang 		strscpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
1380a9f08ad7SWolfram Sang 		strscpy(serio->firmware_id, i8042_aux_firmware_id,
1381a7c5868cSHans de Goede 			sizeof(serio->firmware_id));
13825ddbc77cSDmitry Torokhov 		serio->close = i8042_port_close;
1383de9ce703SDmitry Torokhov 	} else {
1384de9ce703SDmitry Torokhov 		snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
1385de9ce703SDmitry Torokhov 		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
1386a9f08ad7SWolfram Sang 		strscpy(serio->firmware_id, i8042_aux_firmware_id,
1387266e43c4SHans de Goede 			sizeof(serio->firmware_id));
13881da177e4SLinus Torvalds 	}
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds 	port->serio = serio;
1391de9ce703SDmitry Torokhov 	port->mux = idx;
1392de9ce703SDmitry Torokhov 	port->irq = I8042_AUX_IRQ;
13930854e52dSDmitry Torokhov 
1394de9ce703SDmitry Torokhov 	return 0;
1395de9ce703SDmitry Torokhov }
1396de9ce703SDmitry Torokhov 
i8042_free_kbd_port(void)13979222ba68STakashi Iwai static void i8042_free_kbd_port(void)
1398de9ce703SDmitry Torokhov {
1399de9ce703SDmitry Torokhov 	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
1400de9ce703SDmitry Torokhov 	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
1401de9ce703SDmitry Torokhov }
1402de9ce703SDmitry Torokhov 
i8042_free_aux_ports(void)14039222ba68STakashi Iwai static void i8042_free_aux_ports(void)
1404de9ce703SDmitry Torokhov {
1405de9ce703SDmitry Torokhov 	int i;
1406de9ce703SDmitry Torokhov 
1407de9ce703SDmitry Torokhov 	for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) {
1408de9ce703SDmitry Torokhov 		kfree(i8042_ports[i].serio);
1409de9ce703SDmitry Torokhov 		i8042_ports[i].serio = NULL;
1410de9ce703SDmitry Torokhov 	}
1411de9ce703SDmitry Torokhov }
1412de9ce703SDmitry Torokhov 
i8042_register_ports(void)14139222ba68STakashi Iwai static void i8042_register_ports(void)
1414de9ce703SDmitry Torokhov {
1415de9ce703SDmitry Torokhov 	int i;
1416de9ce703SDmitry Torokhov 
1417de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1418f13b2065SRafael J. Wysocki 		struct serio *serio = i8042_ports[i].serio;
1419f13b2065SRafael J. Wysocki 
1420684bec10SDaniel Drake 		if (!serio)
1421684bec10SDaniel Drake 			continue;
1422684bec10SDaniel Drake 
1423de9ce703SDmitry Torokhov 		printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
1424f13b2065SRafael J. Wysocki 			serio->name,
1425de9ce703SDmitry Torokhov 			(unsigned long) I8042_DATA_REG,
1426de9ce703SDmitry Torokhov 			(unsigned long) I8042_COMMAND_REG,
1427de9ce703SDmitry Torokhov 			i8042_ports[i].irq);
1428f13b2065SRafael J. Wysocki 		serio_register_port(serio);
1429de9ce703SDmitry Torokhov 	}
1430de9ce703SDmitry Torokhov }
1431de9ce703SDmitry Torokhov 
i8042_unregister_ports(void)1432e2619cf7SBill Pemberton static void i8042_unregister_ports(void)
1433de9ce703SDmitry Torokhov {
1434de9ce703SDmitry Torokhov 	int i;
1435de9ce703SDmitry Torokhov 
1436de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1437de9ce703SDmitry Torokhov 		if (i8042_ports[i].serio) {
1438de9ce703SDmitry Torokhov 			serio_unregister_port(i8042_ports[i].serio);
1439de9ce703SDmitry Torokhov 			i8042_ports[i].serio = NULL;
1440de9ce703SDmitry Torokhov 		}
1441de9ce703SDmitry Torokhov 	}
1442de9ce703SDmitry Torokhov }
1443de9ce703SDmitry Torokhov 
i8042_free_irqs(void)1444de9ce703SDmitry Torokhov static void i8042_free_irqs(void)
1445de9ce703SDmitry Torokhov {
1446de9ce703SDmitry Torokhov 	if (i8042_aux_irq_registered)
1447de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
1448de9ce703SDmitry Torokhov 	if (i8042_kbd_irq_registered)
1449de9ce703SDmitry Torokhov 		free_irq(I8042_KBD_IRQ, i8042_platform_device);
1450de9ce703SDmitry Torokhov 
1451386b3849SDmitry Torokhov 	i8042_aux_irq_registered = i8042_kbd_irq_registered = false;
1452de9ce703SDmitry Torokhov }
1453de9ce703SDmitry Torokhov 
i8042_setup_aux(void)14549222ba68STakashi Iwai static int i8042_setup_aux(void)
1455de9ce703SDmitry Torokhov {
1456de9ce703SDmitry Torokhov 	int (*aux_enable)(void);
1457de9ce703SDmitry Torokhov 	int error;
1458de9ce703SDmitry Torokhov 	int i;
1459de9ce703SDmitry Torokhov 
1460de9ce703SDmitry Torokhov 	if (i8042_check_aux())
1461de9ce703SDmitry Torokhov 		return -ENODEV;
1462de9ce703SDmitry Torokhov 
1463de9ce703SDmitry Torokhov 	if (i8042_nomux || i8042_check_mux()) {
1464de9ce703SDmitry Torokhov 		error = i8042_create_aux_port(-1);
1465de9ce703SDmitry Torokhov 		if (error)
1466de9ce703SDmitry Torokhov 			goto err_free_ports;
1467de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_aux_port;
1468de9ce703SDmitry Torokhov 	} else {
1469de9ce703SDmitry Torokhov 		for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
1470de9ce703SDmitry Torokhov 			error = i8042_create_aux_port(i);
1471de9ce703SDmitry Torokhov 			if (error)
1472de9ce703SDmitry Torokhov 				goto err_free_ports;
1473de9ce703SDmitry Torokhov 		}
1474de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_mux_ports;
1475de9ce703SDmitry Torokhov 	}
1476de9ce703SDmitry Torokhov 
1477de9ce703SDmitry Torokhov 	error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED,
1478de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1479de9ce703SDmitry Torokhov 	if (error)
1480de9ce703SDmitry Torokhov 		goto err_free_ports;
1481de9ce703SDmitry Torokhov 
1482855b6985SLuo Meng 	error = aux_enable();
1483855b6985SLuo Meng 	if (error)
1484de9ce703SDmitry Torokhov 		goto err_free_irq;
1485de9ce703SDmitry Torokhov 
1486386b3849SDmitry Torokhov 	i8042_aux_irq_registered = true;
1487de9ce703SDmitry Torokhov 	return 0;
1488de9ce703SDmitry Torokhov 
1489de9ce703SDmitry Torokhov  err_free_irq:
1490de9ce703SDmitry Torokhov 	free_irq(I8042_AUX_IRQ, i8042_platform_device);
1491de9ce703SDmitry Torokhov  err_free_ports:
1492de9ce703SDmitry Torokhov 	i8042_free_aux_ports();
1493de9ce703SDmitry Torokhov 	return error;
1494de9ce703SDmitry Torokhov }
1495de9ce703SDmitry Torokhov 
i8042_setup_kbd(void)14969222ba68STakashi Iwai static int i8042_setup_kbd(void)
1497de9ce703SDmitry Torokhov {
1498de9ce703SDmitry Torokhov 	int error;
1499de9ce703SDmitry Torokhov 
1500de9ce703SDmitry Torokhov 	error = i8042_create_kbd_port();
1501de9ce703SDmitry Torokhov 	if (error)
1502de9ce703SDmitry Torokhov 		return error;
1503de9ce703SDmitry Torokhov 
1504de9ce703SDmitry Torokhov 	error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
1505de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1506de9ce703SDmitry Torokhov 	if (error)
1507de9ce703SDmitry Torokhov 		goto err_free_port;
1508de9ce703SDmitry Torokhov 
1509de9ce703SDmitry Torokhov 	error = i8042_enable_kbd_port();
1510de9ce703SDmitry Torokhov 	if (error)
1511de9ce703SDmitry Torokhov 		goto err_free_irq;
1512de9ce703SDmitry Torokhov 
1513386b3849SDmitry Torokhov 	i8042_kbd_irq_registered = true;
1514de9ce703SDmitry Torokhov 	return 0;
1515de9ce703SDmitry Torokhov 
1516de9ce703SDmitry Torokhov  err_free_irq:
1517de9ce703SDmitry Torokhov 	free_irq(I8042_KBD_IRQ, i8042_platform_device);
1518de9ce703SDmitry Torokhov  err_free_port:
1519de9ce703SDmitry Torokhov 	i8042_free_kbd_port();
1520de9ce703SDmitry Torokhov 	return error;
15211da177e4SLinus Torvalds }
15221da177e4SLinus Torvalds 
i8042_kbd_bind_notifier(struct notifier_block * nb,unsigned long action,void * data)1523e1443d28SStephen Chandler Paul static int i8042_kbd_bind_notifier(struct notifier_block *nb,
1524e1443d28SStephen Chandler Paul 				   unsigned long action, void *data)
1525e1443d28SStephen Chandler Paul {
1526e1443d28SStephen Chandler Paul 	struct device *dev = data;
1527e1443d28SStephen Chandler Paul 	struct serio *serio = to_serio_port(dev);
1528e1443d28SStephen Chandler Paul 	struct i8042_port *port = serio->port_data;
1529e1443d28SStephen Chandler Paul 
1530e1443d28SStephen Chandler Paul 	if (serio != i8042_ports[I8042_KBD_PORT_NO].serio)
1531e1443d28SStephen Chandler Paul 		return 0;
1532e1443d28SStephen Chandler Paul 
1533e1443d28SStephen Chandler Paul 	switch (action) {
1534e1443d28SStephen Chandler Paul 	case BUS_NOTIFY_BOUND_DRIVER:
1535e1443d28SStephen Chandler Paul 		port->driver_bound = true;
1536e1443d28SStephen Chandler Paul 		break;
1537e1443d28SStephen Chandler Paul 
1538e1443d28SStephen Chandler Paul 	case BUS_NOTIFY_UNBIND_DRIVER:
1539e1443d28SStephen Chandler Paul 		port->driver_bound = false;
1540e1443d28SStephen Chandler Paul 		break;
1541e1443d28SStephen Chandler Paul 	}
1542e1443d28SStephen Chandler Paul 
1543e1443d28SStephen Chandler Paul 	return 0;
1544e1443d28SStephen Chandler Paul }
1545e1443d28SStephen Chandler Paul 
i8042_probe(struct platform_device * dev)15469222ba68STakashi Iwai static int i8042_probe(struct platform_device *dev)
15471da177e4SLinus Torvalds {
1548de9ce703SDmitry Torokhov 	int error;
15491da177e4SLinus Torvalds 
1550930e1924SMarcos Paulo de Souza 	if (i8042_reset == I8042_RESET_ALWAYS) {
1551de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1552de9ce703SDmitry Torokhov 		if (error)
1553de9ce703SDmitry Torokhov 			return error;
15541ca56e51SDmitry Torokhov 	}
15551da177e4SLinus Torvalds 
1556de9ce703SDmitry Torokhov 	error = i8042_controller_init();
1557de9ce703SDmitry Torokhov 	if (error)
1558de9ce703SDmitry Torokhov 		return error;
15591da177e4SLinus Torvalds 
1560d35895dbSBruno Prémont #ifdef CONFIG_X86
1561d35895dbSBruno Prémont 	if (i8042_dritek)
1562d35895dbSBruno Prémont 		i8042_dritek_enable();
1563d35895dbSBruno Prémont #endif
1564d35895dbSBruno Prémont 
1565de9ce703SDmitry Torokhov 	if (!i8042_noaux) {
1566de9ce703SDmitry Torokhov 		error = i8042_setup_aux();
1567de9ce703SDmitry Torokhov 		if (error && error != -ENODEV && error != -EBUSY)
1568de9ce703SDmitry Torokhov 			goto out_fail;
15691da177e4SLinus Torvalds 	}
15701da177e4SLinus Torvalds 
1571945ef0d4SDmitry Torokhov 	if (!i8042_nokbd) {
1572de9ce703SDmitry Torokhov 		error = i8042_setup_kbd();
1573de9ce703SDmitry Torokhov 		if (error)
1574de9ce703SDmitry Torokhov 			goto out_fail;
1575945ef0d4SDmitry Torokhov 	}
1576de9ce703SDmitry Torokhov /*
1577de9ce703SDmitry Torokhov  * Ok, everything is ready, let's register all serio ports
1578de9ce703SDmitry Torokhov  */
1579de9ce703SDmitry Torokhov 	i8042_register_ports();
15801da177e4SLinus Torvalds 
15811da177e4SLinus Torvalds 	return 0;
15820854e52dSDmitry Torokhov 
1583de9ce703SDmitry Torokhov  out_fail:
1584de9ce703SDmitry Torokhov 	i8042_free_aux_ports();	/* in case KBD failed but AUX not */
1585de9ce703SDmitry Torokhov 	i8042_free_irqs();
15861729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
15870854e52dSDmitry Torokhov 
1588de9ce703SDmitry Torokhov 	return error;
15891da177e4SLinus Torvalds }
15901da177e4SLinus Torvalds 
i8042_remove(struct platform_device * dev)15912e760e9bSUwe Kleine-König static void i8042_remove(struct platform_device *dev)
15921da177e4SLinus Torvalds {
1593de9ce703SDmitry Torokhov 	i8042_unregister_ports();
1594de9ce703SDmitry Torokhov 	i8042_free_irqs();
15951729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
159687fd6318SDmitry Torokhov }
159787fd6318SDmitry Torokhov 
159887fd6318SDmitry Torokhov static struct platform_driver i8042_driver = {
159987fd6318SDmitry Torokhov 	.driver		= {
160087fd6318SDmitry Torokhov 		.name	= "i8042",
1601ebd7768dSDmitry Torokhov #ifdef CONFIG_PM
1602ebd7768dSDmitry Torokhov 		.pm	= &i8042_pm_ops,
1603ebd7768dSDmitry Torokhov #endif
160487fd6318SDmitry Torokhov 	},
16059222ba68STakashi Iwai 	.probe		= i8042_probe,
16062e760e9bSUwe Kleine-König 	.remove_new	= i8042_remove,
160782dd9effSDmitry Torokhov 	.shutdown	= i8042_shutdown,
160887fd6318SDmitry Torokhov };
160987fd6318SDmitry Torokhov 
1610e1443d28SStephen Chandler Paul static struct notifier_block i8042_kbd_bind_notifier_block = {
1611e1443d28SStephen Chandler Paul 	.notifier_call = i8042_kbd_bind_notifier,
1612e1443d28SStephen Chandler Paul };
1613e1443d28SStephen Chandler Paul 
i8042_init(void)161487fd6318SDmitry Torokhov static int __init i8042_init(void)
161587fd6318SDmitry Torokhov {
161687fd6318SDmitry Torokhov 	int err;
161787fd6318SDmitry Torokhov 
161887fd6318SDmitry Torokhov 	dbg_init();
161987fd6318SDmitry Torokhov 
162087fd6318SDmitry Torokhov 	err = i8042_platform_init();
162187fd6318SDmitry Torokhov 	if (err)
1622b1884583SHans de Goede 		return (err == -ENODEV) ? 0 : err;
162387fd6318SDmitry Torokhov 
1624de9ce703SDmitry Torokhov 	err = i8042_controller_check();
1625de9ce703SDmitry Torokhov 	if (err)
1626de9ce703SDmitry Torokhov 		goto err_platform_exit;
162787fd6318SDmitry Torokhov 
1628b1884583SHans de Goede 	/* Set this before creating the dev to allow i8042_command to work right away */
1629b1884583SHans de Goede 	i8042_present = true;
1630b1884583SHans de Goede 
16319222ba68STakashi Iwai 	err = platform_driver_register(&i8042_driver);
16329222ba68STakashi Iwai 	if (err)
1633f8113416SDmitry Torokhov 		goto err_platform_exit;
16349222ba68STakashi Iwai 
16359222ba68STakashi Iwai 	i8042_platform_device = platform_device_alloc("i8042", -1);
16369222ba68STakashi Iwai 	if (!i8042_platform_device) {
16379222ba68STakashi Iwai 		err = -ENOMEM;
16389222ba68STakashi Iwai 		goto err_unregister_driver;
163987fd6318SDmitry Torokhov 	}
164087fd6318SDmitry Torokhov 
16419222ba68STakashi Iwai 	err = platform_device_add(i8042_platform_device);
16429222ba68STakashi Iwai 	if (err)
16439222ba68STakashi Iwai 		goto err_free_device;
16449222ba68STakashi Iwai 
1645e1443d28SStephen Chandler Paul 	bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block);
1646de9ce703SDmitry Torokhov 	panic_blink = i8042_panic_blink;
1647de9ce703SDmitry Torokhov 
164887fd6318SDmitry Torokhov 	return 0;
164987fd6318SDmitry Torokhov 
16509222ba68STakashi Iwai err_free_device:
16519222ba68STakashi Iwai 	platform_device_put(i8042_platform_device);
16529222ba68STakashi Iwai err_unregister_driver:
16539222ba68STakashi Iwai 	platform_driver_unregister(&i8042_driver);
165487fd6318SDmitry Torokhov  err_platform_exit:
165587fd6318SDmitry Torokhov 	i8042_platform_exit();
165687fd6318SDmitry Torokhov 	return err;
165787fd6318SDmitry Torokhov }
165887fd6318SDmitry Torokhov 
i8042_exit(void)165987fd6318SDmitry Torokhov static void __exit i8042_exit(void)
166087fd6318SDmitry Torokhov {
1661b1884583SHans de Goede 	if (!i8042_present)
1662b1884583SHans de Goede 		return;
1663b1884583SHans de Goede 
1664f8113416SDmitry Torokhov 	platform_device_unregister(i8042_platform_device);
1665af045b86SDmitry Torokhov 	platform_driver_unregister(&i8042_driver);
16661da177e4SLinus Torvalds 	i8042_platform_exit();
16671da177e4SLinus Torvalds 
1668e1443d28SStephen Chandler Paul 	bus_unregister_notifier(&serio_bus, &i8042_kbd_bind_notifier_block);
16691da177e4SLinus Torvalds 	panic_blink = NULL;
16701da177e4SLinus Torvalds }
16711da177e4SLinus Torvalds 
16721da177e4SLinus Torvalds module_init(i8042_init);
16731da177e4SLinus Torvalds module_exit(i8042_exit);
1674