xref: /openbmc/linux/drivers/input/serio/i8042.c (revision 340d394a)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  i8042 keyboard and mouse controller driver for Linux
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (c) 1999-2004 Vojtech Pavlik
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds /*
81da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify it
91da177e4SLinus Torvalds  * under the terms of the GNU General Public License version 2 as published by
101da177e4SLinus Torvalds  * the Free Software Foundation.
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
134eb3c30bSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
144eb3c30bSJoe Perches 
157e044e05SDmitry Torokhov #include <linux/types.h>
161da177e4SLinus Torvalds #include <linux/delay.h>
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds #include <linux/interrupt.h>
191da177e4SLinus Torvalds #include <linux/ioport.h>
201da177e4SLinus Torvalds #include <linux/init.h>
211da177e4SLinus Torvalds #include <linux/serio.h>
221da177e4SLinus Torvalds #include <linux/err.h>
231da177e4SLinus Torvalds #include <linux/rcupdate.h>
24d052d1beSRussell King #include <linux/platform_device.h>
25553a05b8SMárton Németh #include <linux/i8042.h>
265a0e3ad6STejun Heo #include <linux/slab.h>
271c5dd134SRafael J. Wysocki #include <linux/suspend.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #include <asm/io.h>
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
321da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
331da177e4SLinus Torvalds MODULE_LICENSE("GPL");
341da177e4SLinus Torvalds 
35386b3849SDmitry Torokhov static bool i8042_nokbd;
36945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0);
37945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
38945ef0d4SDmitry Torokhov 
39386b3849SDmitry Torokhov static bool i8042_noaux;
401da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0);
411da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
421da177e4SLinus Torvalds 
43e55a3366SDmitry Torokhov static bool i8042_nomux;
441da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0);
452c860a11SDominik Brodowski MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing controller is present.");
461da177e4SLinus Torvalds 
47386b3849SDmitry Torokhov static bool i8042_unlock;
481da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0);
491da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
501da177e4SLinus Torvalds 
51930e1924SMarcos Paulo de Souza enum i8042_controller_reset_mode {
52930e1924SMarcos Paulo de Souza 	I8042_RESET_NEVER,
53930e1924SMarcos Paulo de Souza 	I8042_RESET_ALWAYS,
54930e1924SMarcos Paulo de Souza 	I8042_RESET_ON_S2RAM,
55930e1924SMarcos Paulo de Souza #define I8042_RESET_DEFAULT	I8042_RESET_ON_S2RAM
56930e1924SMarcos Paulo de Souza };
57930e1924SMarcos Paulo de Souza static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
58930e1924SMarcos Paulo de Souza static int i8042_set_reset(const char *val, const struct kernel_param *kp)
59930e1924SMarcos Paulo de Souza {
60930e1924SMarcos Paulo de Souza 	enum i8042_controller_reset_mode *arg = kp->arg;
61930e1924SMarcos Paulo de Souza 	int error;
62930e1924SMarcos Paulo de Souza 	bool reset;
63930e1924SMarcos Paulo de Souza 
64930e1924SMarcos Paulo de Souza 	if (val) {
65930e1924SMarcos Paulo de Souza 		error = kstrtobool(val, &reset);
66930e1924SMarcos Paulo de Souza 		if (error)
67930e1924SMarcos Paulo de Souza 			return error;
68930e1924SMarcos Paulo de Souza 	} else {
69930e1924SMarcos Paulo de Souza 		reset = true;
70930e1924SMarcos Paulo de Souza 	}
71930e1924SMarcos Paulo de Souza 
72930e1924SMarcos Paulo de Souza 	*arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
73930e1924SMarcos Paulo de Souza 	return 0;
74930e1924SMarcos Paulo de Souza }
75930e1924SMarcos Paulo de Souza 
76930e1924SMarcos Paulo de Souza static const struct kernel_param_ops param_ops_reset_param = {
77930e1924SMarcos Paulo de Souza 	.flags = KERNEL_PARAM_OPS_FL_NOARG,
78930e1924SMarcos Paulo de Souza 	.set = i8042_set_reset,
79930e1924SMarcos Paulo de Souza };
80930e1924SMarcos Paulo de Souza #define param_check_reset_param(name, p)	\
81930e1924SMarcos Paulo de Souza 	__param_check(name, p, enum i8042_controller_reset_mode)
82930e1924SMarcos Paulo de Souza module_param_named(reset, i8042_reset, reset_param, 0);
83930e1924SMarcos Paulo de Souza MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both");
841da177e4SLinus Torvalds 
85386b3849SDmitry Torokhov static bool i8042_direct;
861da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0);
871da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode.");
881da177e4SLinus Torvalds 
89386b3849SDmitry Torokhov static bool i8042_dumbkbd;
901da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
911da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
921da177e4SLinus Torvalds 
93386b3849SDmitry Torokhov static bool i8042_noloop;
941da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0);
951da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
961da177e4SLinus Torvalds 
97f8313ef1SJiri Kosina static bool i8042_notimeout;
98f8313ef1SJiri Kosina module_param_named(notimeout, i8042_notimeout, bool, 0);
99f8313ef1SJiri Kosina MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042");
100f8313ef1SJiri Kosina 
101148e9a71SSrihari Vijayaraghavan static bool i8042_kbdreset;
102148e9a71SSrihari Vijayaraghavan module_param_named(kbdreset, i8042_kbdreset, bool, 0);
103148e9a71SSrihari Vijayaraghavan MODULE_PARM_DESC(kbdreset, "Reset device connected to KBD port");
104148e9a71SSrihari Vijayaraghavan 
1058987fec0SCarlos Corbacho #ifdef CONFIG_X86
106386b3849SDmitry Torokhov static bool i8042_dritek;
1078987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0);
1088987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension");
1098987fec0SCarlos Corbacho #endif
1108987fec0SCarlos Corbacho 
1111da177e4SLinus Torvalds #ifdef CONFIG_PNP
112386b3849SDmitry Torokhov static bool i8042_nopnp;
1131da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0);
1141da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
1151da177e4SLinus Torvalds #endif
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds #define DEBUG
1181da177e4SLinus Torvalds #ifdef DEBUG
119386b3849SDmitry Torokhov static bool i8042_debug;
1201da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600);
1211da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
122e1443d28SStephen Chandler Paul 
123e1443d28SStephen Chandler Paul static bool i8042_unmask_kbd_data;
124e1443d28SStephen Chandler Paul module_param_named(unmask_kbd_data, i8042_unmask_kbd_data, bool, 0600);
125e1443d28SStephen 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]");
1261da177e4SLinus Torvalds #endif
1271da177e4SLinus Torvalds 
1281c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test;
129a7c5868cSHans de Goede static char i8042_kbd_firmware_id[128];
130a7c5868cSHans de Goede static char i8042_aux_firmware_id[128];
1311c7827aeSDmitry Torokhov 
1321da177e4SLinus Torvalds #include "i8042.h"
1331da177e4SLinus Torvalds 
134181d683dSDmitry Torokhov /*
135181d683dSDmitry Torokhov  * i8042_lock protects serialization between i8042_command and
136181d683dSDmitry Torokhov  * the interrupt handler.
137181d683dSDmitry Torokhov  */
1381da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock);
1391da177e4SLinus Torvalds 
140181d683dSDmitry Torokhov /*
141181d683dSDmitry Torokhov  * Writers to AUX and KBD ports as well as users issuing i8042_command
142181d683dSDmitry Torokhov  * directly should acquire i8042_mutex (by means of calling
143181d683dSDmitry Torokhov  * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that
144181d683dSDmitry Torokhov  * they do not disturb each other (unfortunately in many i8042
145181d683dSDmitry Torokhov  * implementations write to one of the ports will immediately abort
146181d683dSDmitry Torokhov  * command that is being processed by another port).
147181d683dSDmitry Torokhov  */
148181d683dSDmitry Torokhov static DEFINE_MUTEX(i8042_mutex);
149181d683dSDmitry Torokhov 
1501da177e4SLinus Torvalds struct i8042_port {
1511da177e4SLinus Torvalds 	struct serio *serio;
1521da177e4SLinus Torvalds 	int irq;
153386b3849SDmitry Torokhov 	bool exists;
154e1443d28SStephen Chandler Paul 	bool driver_bound;
1551da177e4SLinus Torvalds 	signed char mux;
1561da177e4SLinus Torvalds };
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds #define I8042_KBD_PORT_NO	0
1591da177e4SLinus Torvalds #define I8042_AUX_PORT_NO	1
1601da177e4SLinus Torvalds #define I8042_MUX_PORT_NO	2
1611da177e4SLinus Torvalds #define I8042_NUM_PORTS		(I8042_NUM_MUX_PORTS + 2)
162de9ce703SDmitry Torokhov 
163de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS];
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds static unsigned char i8042_initial_ctr;
1661da177e4SLinus Torvalds static unsigned char i8042_ctr;
167386b3849SDmitry Torokhov static bool i8042_mux_present;
168386b3849SDmitry Torokhov static bool i8042_kbd_irq_registered;
169386b3849SDmitry Torokhov static bool i8042_aux_irq_registered;
170817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack;
1711da177e4SLinus Torvalds static struct platform_device *i8042_platform_device;
172e1443d28SStephen Chandler Paul static struct notifier_block i8042_kbd_bind_notifier_block;
1731da177e4SLinus Torvalds 
1747d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id);
175967c9ef9SMatthew Garrett static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
176967c9ef9SMatthew Garrett 				     struct serio *serio);
1771da177e4SLinus Torvalds 
178181d683dSDmitry Torokhov void i8042_lock_chip(void)
179181d683dSDmitry Torokhov {
180181d683dSDmitry Torokhov 	mutex_lock(&i8042_mutex);
181181d683dSDmitry Torokhov }
182181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip);
183181d683dSDmitry Torokhov 
184181d683dSDmitry Torokhov void i8042_unlock_chip(void)
185181d683dSDmitry Torokhov {
186181d683dSDmitry Torokhov 	mutex_unlock(&i8042_mutex);
187181d683dSDmitry Torokhov }
188181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip);
189181d683dSDmitry Torokhov 
190967c9ef9SMatthew Garrett int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
191967c9ef9SMatthew Garrett 					struct serio *serio))
192967c9ef9SMatthew Garrett {
193967c9ef9SMatthew Garrett 	unsigned long flags;
194967c9ef9SMatthew Garrett 	int ret = 0;
195967c9ef9SMatthew Garrett 
196967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
197967c9ef9SMatthew Garrett 
198967c9ef9SMatthew Garrett 	if (i8042_platform_filter) {
199967c9ef9SMatthew Garrett 		ret = -EBUSY;
200967c9ef9SMatthew Garrett 		goto out;
201967c9ef9SMatthew Garrett 	}
202967c9ef9SMatthew Garrett 
203967c9ef9SMatthew Garrett 	i8042_platform_filter = filter;
204967c9ef9SMatthew Garrett 
205967c9ef9SMatthew Garrett out:
206967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
207967c9ef9SMatthew Garrett 	return ret;
208967c9ef9SMatthew Garrett }
209967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_install_filter);
210967c9ef9SMatthew Garrett 
211967c9ef9SMatthew Garrett int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
212967c9ef9SMatthew Garrett 				       struct serio *port))
213967c9ef9SMatthew Garrett {
214967c9ef9SMatthew Garrett 	unsigned long flags;
215967c9ef9SMatthew Garrett 	int ret = 0;
216967c9ef9SMatthew Garrett 
217967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
218967c9ef9SMatthew Garrett 
219967c9ef9SMatthew Garrett 	if (i8042_platform_filter != filter) {
220967c9ef9SMatthew Garrett 		ret = -EINVAL;
221967c9ef9SMatthew Garrett 		goto out;
222967c9ef9SMatthew Garrett 	}
223967c9ef9SMatthew Garrett 
224967c9ef9SMatthew Garrett 	i8042_platform_filter = NULL;
225967c9ef9SMatthew Garrett 
226967c9ef9SMatthew Garrett out:
227967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
228967c9ef9SMatthew Garrett 	return ret;
229967c9ef9SMatthew Garrett }
230967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_remove_filter);
231967c9ef9SMatthew Garrett 
2321da177e4SLinus Torvalds /*
2331da177e4SLinus Torvalds  * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
2341da177e4SLinus Torvalds  * be ready for reading values from it / writing values to it.
2351da177e4SLinus Torvalds  * Called always with i8042_lock held.
2361da177e4SLinus Torvalds  */
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds static int i8042_wait_read(void)
2391da177e4SLinus Torvalds {
2401da177e4SLinus Torvalds 	int i = 0;
241de9ce703SDmitry Torokhov 
2421da177e4SLinus Torvalds 	while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
2431da177e4SLinus Torvalds 		udelay(50);
2441da177e4SLinus Torvalds 		i++;
2451da177e4SLinus Torvalds 	}
2461da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds static int i8042_wait_write(void)
2501da177e4SLinus Torvalds {
2511da177e4SLinus Torvalds 	int i = 0;
252de9ce703SDmitry Torokhov 
2531da177e4SLinus Torvalds 	while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
2541da177e4SLinus Torvalds 		udelay(50);
2551da177e4SLinus Torvalds 		i++;
2561da177e4SLinus Torvalds 	}
2571da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
2581da177e4SLinus Torvalds }
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds /*
2611da177e4SLinus Torvalds  * i8042_flush() flushes all data that may be in the keyboard and mouse buffers
2621da177e4SLinus Torvalds  * of the i8042 down the toilet.
2631da177e4SLinus Torvalds  */
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds static int i8042_flush(void)
2661da177e4SLinus Torvalds {
2671da177e4SLinus Torvalds 	unsigned long flags;
2681da177e4SLinus Torvalds 	unsigned char data, str;
2692f0d2604SAndrey Moiseev 	int count = 0;
2702f0d2604SAndrey Moiseev 	int retval = 0;
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
2731da177e4SLinus Torvalds 
2742f0d2604SAndrey Moiseev 	while ((str = i8042_read_status()) & I8042_STR_OBF) {
2752f0d2604SAndrey Moiseev 		if (count++ < I8042_BUFFER_SIZE) {
2761da177e4SLinus Torvalds 			udelay(50);
2771da177e4SLinus Torvalds 			data = i8042_read_data();
2784eb3c30bSJoe Perches 			dbg("%02x <- i8042 (flush, %s)\n",
2794eb3c30bSJoe Perches 			    data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
2802f0d2604SAndrey Moiseev 		} else {
2812f0d2604SAndrey Moiseev 			retval = -EIO;
2822f0d2604SAndrey Moiseev 			break;
2832f0d2604SAndrey Moiseev 		}
2841da177e4SLinus Torvalds 	}
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
2871da177e4SLinus Torvalds 
2882f0d2604SAndrey Moiseev 	return retval;
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds /*
2921da177e4SLinus Torvalds  * i8042_command() executes a command on the i8042. It also sends the input
2931da177e4SLinus Torvalds  * parameter(s) of the commands to it, and receives the output value(s). The
2941da177e4SLinus Torvalds  * parameters are to be stored in the param array, and the output is placed
2951da177e4SLinus Torvalds  * into the same array. The number of the parameters and output values is
2961da177e4SLinus Torvalds  * encoded in bits 8-11 of the command number.
2971da177e4SLinus Torvalds  */
2981da177e4SLinus Torvalds 
299de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command)
3001da177e4SLinus Torvalds {
301de9ce703SDmitry Torokhov 	int i, error;
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
3041da177e4SLinus Torvalds 		return -1;
3051da177e4SLinus Torvalds 
306de9ce703SDmitry Torokhov 	error = i8042_wait_write();
307de9ce703SDmitry Torokhov 	if (error)
308de9ce703SDmitry Torokhov 		return error;
309463a4f76SDmitry Torokhov 
3104eb3c30bSJoe Perches 	dbg("%02x -> i8042 (command)\n", command & 0xff);
3111da177e4SLinus Torvalds 	i8042_write_command(command & 0xff);
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 12) & 0xf); i++) {
314de9ce703SDmitry Torokhov 		error = i8042_wait_write();
3152ea9c236SMarcos Paulo de Souza 		if (error) {
3162ea9c236SMarcos Paulo de Souza 			dbg("     -- i8042 (wait write timeout)\n");
317de9ce703SDmitry Torokhov 			return error;
3182ea9c236SMarcos Paulo de Souza 		}
3194eb3c30bSJoe Perches 		dbg("%02x -> i8042 (parameter)\n", param[i]);
3201da177e4SLinus Torvalds 		i8042_write_data(param[i]);
3211da177e4SLinus Torvalds 	}
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 8) & 0xf); i++) {
324de9ce703SDmitry Torokhov 		error = i8042_wait_read();
325de9ce703SDmitry Torokhov 		if (error) {
3262ea9c236SMarcos Paulo de Souza 			dbg("     -- i8042 (wait read timeout)\n");
327de9ce703SDmitry Torokhov 			return error;
328de9ce703SDmitry Torokhov 		}
329463a4f76SDmitry Torokhov 
330463a4f76SDmitry Torokhov 		if (command == I8042_CMD_AUX_LOOP &&
331463a4f76SDmitry Torokhov 		    !(i8042_read_status() & I8042_STR_AUXDATA)) {
3324eb3c30bSJoe Perches 			dbg("     -- i8042 (auxerr)\n");
333de9ce703SDmitry Torokhov 			return -1;
334463a4f76SDmitry Torokhov 		}
335463a4f76SDmitry Torokhov 
3361da177e4SLinus Torvalds 		param[i] = i8042_read_data();
3374eb3c30bSJoe Perches 		dbg("%02x <- i8042 (return)\n", param[i]);
3381da177e4SLinus Torvalds 	}
3391da177e4SLinus Torvalds 
340de9ce703SDmitry Torokhov 	return 0;
341de9ce703SDmitry Torokhov }
3421da177e4SLinus Torvalds 
343553a05b8SMárton Németh int i8042_command(unsigned char *param, int command)
344de9ce703SDmitry Torokhov {
345de9ce703SDmitry Torokhov 	unsigned long flags;
346de9ce703SDmitry Torokhov 	int retval;
347de9ce703SDmitry Torokhov 
348de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
349de9ce703SDmitry Torokhov 	retval = __i8042_command(param, command);
350463a4f76SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
351de9ce703SDmitry Torokhov 
3521da177e4SLinus Torvalds 	return retval;
3531da177e4SLinus Torvalds }
354553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command);
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds /*
3571da177e4SLinus Torvalds  * i8042_kbd_write() sends a byte out through the keyboard interface.
3581da177e4SLinus Torvalds  */
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c)
3611da177e4SLinus Torvalds {
3621da177e4SLinus Torvalds 	unsigned long flags;
3631da177e4SLinus Torvalds 	int retval = 0;
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds 	if (!(retval = i8042_wait_write())) {
3684eb3c30bSJoe Perches 		dbg("%02x -> i8042 (kbd-data)\n", c);
3691da177e4SLinus Torvalds 		i8042_write_data(c);
3701da177e4SLinus Torvalds 	}
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 	return retval;
3751da177e4SLinus Torvalds }
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds /*
3781da177e4SLinus Torvalds  * i8042_aux_write() sends a byte out through the aux interface.
3791da177e4SLinus Torvalds  */
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c)
3821da177e4SLinus Torvalds {
3831da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3841da177e4SLinus Torvalds 
385f4e3c711SDmitry Torokhov 	return i8042_command(&c, port->mux == -1 ?
386f4e3c711SDmitry Torokhov 					I8042_CMD_AUX_SEND :
387f4e3c711SDmitry Torokhov 					I8042_CMD_MUX_SEND + port->mux);
3881da177e4SLinus Torvalds }
3891da177e4SLinus Torvalds 
3905ddbc77cSDmitry Torokhov 
3915ddbc77cSDmitry Torokhov /*
3920e2b4458SMarcos Paulo de Souza  * i8042_port_close attempts to clear AUX or KBD port state by disabling
3935ddbc77cSDmitry Torokhov  * and then re-enabling it.
3945ddbc77cSDmitry Torokhov  */
3955ddbc77cSDmitry Torokhov 
3965ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio)
3975ddbc77cSDmitry Torokhov {
3985ddbc77cSDmitry Torokhov 	int irq_bit;
3995ddbc77cSDmitry Torokhov 	int disable_bit;
4005ddbc77cSDmitry Torokhov 	const char *port_name;
4015ddbc77cSDmitry Torokhov 
4025ddbc77cSDmitry Torokhov 	if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) {
4035ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_AUXINT;
4045ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_AUXDIS;
4055ddbc77cSDmitry Torokhov 		port_name = "AUX";
4065ddbc77cSDmitry Torokhov 	} else {
4075ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_KBDINT;
4085ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_KBDDIS;
4095ddbc77cSDmitry Torokhov 		port_name = "KBD";
4105ddbc77cSDmitry Torokhov 	}
4115ddbc77cSDmitry Torokhov 
4125ddbc77cSDmitry Torokhov 	i8042_ctr &= ~irq_bit;
4135ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
4144eb3c30bSJoe Perches 		pr_warn("Can't write CTR while closing %s port\n", port_name);
4155ddbc77cSDmitry Torokhov 
4165ddbc77cSDmitry Torokhov 	udelay(50);
4175ddbc77cSDmitry Torokhov 
4185ddbc77cSDmitry Torokhov 	i8042_ctr &= ~disable_bit;
4195ddbc77cSDmitry Torokhov 	i8042_ctr |= irq_bit;
4205ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
4214eb3c30bSJoe Perches 		pr_err("Can't reactivate %s port\n", port_name);
4225ddbc77cSDmitry Torokhov 
4235ddbc77cSDmitry Torokhov 	/*
4245ddbc77cSDmitry Torokhov 	 * See if there is any data appeared while we were messing with
4255ddbc77cSDmitry Torokhov 	 * port state.
4265ddbc77cSDmitry Torokhov 	 */
4275ddbc77cSDmitry Torokhov 	i8042_interrupt(0, NULL);
4285ddbc77cSDmitry Torokhov }
4295ddbc77cSDmitry Torokhov 
4301da177e4SLinus Torvalds /*
4311da177e4SLinus Torvalds  * i8042_start() is called by serio core when port is about to finish
4321da177e4SLinus Torvalds  * registering. It will mark port as existing so i8042_interrupt can
4331da177e4SLinus Torvalds  * start sending data through it.
4341da177e4SLinus Torvalds  */
4351da177e4SLinus Torvalds static int i8042_start(struct serio *serio)
4361da177e4SLinus Torvalds {
4371da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
4381da177e4SLinus Torvalds 
439*340d394aSChen Hong 	spin_lock_irq(&i8042_lock);
440386b3849SDmitry Torokhov 	port->exists = true;
441*340d394aSChen Hong 	spin_unlock_irq(&i8042_lock);
442*340d394aSChen Hong 
4431da177e4SLinus Torvalds 	return 0;
4441da177e4SLinus Torvalds }
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds /*
4471da177e4SLinus Torvalds  * i8042_stop() marks serio port as non-existing so i8042_interrupt
4481da177e4SLinus Torvalds  * will not try to send data to the port that is about to go away.
4491da177e4SLinus Torvalds  * The function is called by serio core as part of unregister procedure.
4501da177e4SLinus Torvalds  */
4511da177e4SLinus Torvalds static void i8042_stop(struct serio *serio)
4521da177e4SLinus Torvalds {
4531da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
4541da177e4SLinus Torvalds 
455*340d394aSChen Hong 	spin_lock_irq(&i8042_lock);
456386b3849SDmitry Torokhov 	port->exists = false;
457*340d394aSChen Hong 	port->serio = NULL;
458*340d394aSChen Hong 	spin_unlock_irq(&i8042_lock);
459a8399c51SDmitry Torokhov 
460a8399c51SDmitry Torokhov 	/*
461*340d394aSChen Hong 	 * We need to make sure that interrupt handler finishes using
462*340d394aSChen Hong 	 * our serio port before we return from this function.
463a8399c51SDmitry Torokhov 	 * We synchronize with both AUX and KBD IRQs because there is
464a8399c51SDmitry Torokhov 	 * a (very unlikely) chance that AUX IRQ is raised for KBD port
465a8399c51SDmitry Torokhov 	 * and vice versa.
466a8399c51SDmitry Torokhov 	 */
467a8399c51SDmitry Torokhov 	synchronize_irq(I8042_AUX_IRQ);
468a8399c51SDmitry Torokhov 	synchronize_irq(I8042_KBD_IRQ);
4691da177e4SLinus Torvalds }
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds /*
4724e8d340dSDmitry Torokhov  * i8042_filter() filters out unwanted bytes from the input data stream.
4734e8d340dSDmitry Torokhov  * It is called from i8042_interrupt and thus is running with interrupts
4744e8d340dSDmitry Torokhov  * off and i8042_lock held.
4754e8d340dSDmitry Torokhov  */
476967c9ef9SMatthew Garrett static bool i8042_filter(unsigned char data, unsigned char str,
477967c9ef9SMatthew Garrett 			 struct serio *serio)
4784e8d340dSDmitry Torokhov {
4794e8d340dSDmitry Torokhov 	if (unlikely(i8042_suppress_kbd_ack)) {
4804e8d340dSDmitry Torokhov 		if ((~str & I8042_STR_AUXDATA) &&
4814e8d340dSDmitry Torokhov 		    (data == 0xfa || data == 0xfe)) {
4824e8d340dSDmitry Torokhov 			i8042_suppress_kbd_ack--;
4834e8d340dSDmitry Torokhov 			dbg("Extra keyboard ACK - filtered out\n");
4844e8d340dSDmitry Torokhov 			return true;
4854e8d340dSDmitry Torokhov 		}
4864e8d340dSDmitry Torokhov 	}
4874e8d340dSDmitry Torokhov 
488967c9ef9SMatthew Garrett 	if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
4890747e3bcSStefan Weil 		dbg("Filtered out by platform filter\n");
490967c9ef9SMatthew Garrett 		return true;
491967c9ef9SMatthew Garrett 	}
492967c9ef9SMatthew Garrett 
4934e8d340dSDmitry Torokhov 	return false;
4944e8d340dSDmitry Torokhov }
4954e8d340dSDmitry Torokhov 
4964e8d340dSDmitry Torokhov /*
4971da177e4SLinus Torvalds  * i8042_interrupt() is the most important function in this driver -
4981da177e4SLinus Torvalds  * it handles the interrupts from the i8042, and sends incoming bytes
4991da177e4SLinus Torvalds  * to the upper layers.
5001da177e4SLinus Torvalds  */
5011da177e4SLinus Torvalds 
5027d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id)
5031da177e4SLinus Torvalds {
5041da177e4SLinus Torvalds 	struct i8042_port *port;
505967c9ef9SMatthew Garrett 	struct serio *serio;
5061da177e4SLinus Torvalds 	unsigned long flags;
5071da177e4SLinus Torvalds 	unsigned char str, data;
5081da177e4SLinus Torvalds 	unsigned int dfl;
5091da177e4SLinus Torvalds 	unsigned int port_no;
5104e8d340dSDmitry Torokhov 	bool filtered;
511817e6ba3SDmitry Torokhov 	int ret = 1;
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
5144e8d340dSDmitry Torokhov 
5151da177e4SLinus Torvalds 	str = i8042_read_status();
5161da177e4SLinus Torvalds 	if (unlikely(~str & I8042_STR_OBF)) {
5171da177e4SLinus Torvalds 		spin_unlock_irqrestore(&i8042_lock, flags);
5184eb3c30bSJoe Perches 		if (irq)
5194eb3c30bSJoe Perches 			dbg("Interrupt %d, without any data\n", irq);
5201da177e4SLinus Torvalds 		ret = 0;
5211da177e4SLinus Torvalds 		goto out;
5221da177e4SLinus Torvalds 	}
5234e8d340dSDmitry Torokhov 
5241da177e4SLinus Torvalds 	data = i8042_read_data();
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 	if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
5271da177e4SLinus Torvalds 		static unsigned long last_transmit;
5281da177e4SLinus Torvalds 		static unsigned char last_str;
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 		dfl = 0;
5311da177e4SLinus Torvalds 		if (str & I8042_STR_MUXERR) {
5324eb3c30bSJoe Perches 			dbg("MUX error, status is %02x, data is %02x\n",
5334eb3c30bSJoe Perches 			    str, data);
5341da177e4SLinus Torvalds /*
5351da177e4SLinus Torvalds  * When MUXERR condition is signalled the data register can only contain
5361da177e4SLinus Torvalds  * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
537a216a4b6SDmitry Torokhov  * it is not always the case. Some KBCs also report 0xfc when there is
538a216a4b6SDmitry Torokhov  * nothing connected to the port while others sometimes get confused which
539a216a4b6SDmitry Torokhov  * port the data came from and signal error leaving the data intact. They
540a216a4b6SDmitry Torokhov  * _do not_ revert to legacy mode (actually I've never seen KBC reverting
541a216a4b6SDmitry Torokhov  * to legacy mode yet, when we see one we'll add proper handling).
542a216a4b6SDmitry Torokhov  * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the
543a216a4b6SDmitry Torokhov  * rest assume that the data came from the same serio last byte
5441da177e4SLinus Torvalds  * was transmitted (if transmission happened not too long ago).
5451da177e4SLinus Torvalds  */
546a216a4b6SDmitry Torokhov 
547a216a4b6SDmitry Torokhov 			switch (data) {
548a216a4b6SDmitry Torokhov 				default:
5491da177e4SLinus Torvalds 					if (time_before(jiffies, last_transmit + HZ/10)) {
5501da177e4SLinus Torvalds 						str = last_str;
5511da177e4SLinus Torvalds 						break;
5521da177e4SLinus Torvalds 					}
5531da177e4SLinus Torvalds 					/* fall through - report timeout */
554a216a4b6SDmitry Torokhov 				case 0xfc:
5551da177e4SLinus Torvalds 				case 0xfd:
5561da177e4SLinus Torvalds 				case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
5571da177e4SLinus Torvalds 				case 0xff: dfl = SERIO_PARITY;  data = 0xfe; break;
5581da177e4SLinus Torvalds 			}
5591da177e4SLinus Torvalds 		}
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds 		port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
5621da177e4SLinus Torvalds 		last_str = str;
5631da177e4SLinus Torvalds 		last_transmit = jiffies;
5641da177e4SLinus Torvalds 	} else {
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds 		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
567f8313ef1SJiri Kosina 		      ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0);
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 		port_no = (str & I8042_STR_AUXDATA) ?
5701da177e4SLinus Torvalds 				I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
5711da177e4SLinus Torvalds 	}
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds 	port = &i8042_ports[port_no];
574967c9ef9SMatthew Garrett 	serio = port->exists ? port->serio : NULL;
5751da177e4SLinus Torvalds 
576e1443d28SStephen Chandler Paul 	filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n",
577e1443d28SStephen Chandler Paul 		   port_no, irq,
5781da177e4SLinus Torvalds 		   dfl & SERIO_PARITY ? ", bad parity" : "",
5791da177e4SLinus Torvalds 		   dfl & SERIO_TIMEOUT ? ", timeout" : "");
5801da177e4SLinus Torvalds 
581967c9ef9SMatthew Garrett 	filtered = i8042_filter(data, str, serio);
582817e6ba3SDmitry Torokhov 
5834e8d340dSDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
5844e8d340dSDmitry Torokhov 
585*340d394aSChen Hong 	if (likely(serio && !filtered))
586967c9ef9SMatthew Garrett 		serio_interrupt(serio, data, dfl);
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds  out:
5891da177e4SLinus Torvalds 	return IRQ_RETVAL(ret);
5901da177e4SLinus Torvalds }
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds /*
5935ddbc77cSDmitry Torokhov  * i8042_enable_kbd_port enables keyboard port on chip
594de9ce703SDmitry Torokhov  */
595de9ce703SDmitry Torokhov 
596de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void)
597de9ce703SDmitry Torokhov {
598de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_KBDDIS;
599de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDINT;
600de9ce703SDmitry Torokhov 
601de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
602018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_KBDINT;
603018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_KBDDIS;
6044eb3c30bSJoe Perches 		pr_err("Failed to enable KBD port\n");
605de9ce703SDmitry Torokhov 		return -EIO;
606de9ce703SDmitry Torokhov 	}
607de9ce703SDmitry Torokhov 
608de9ce703SDmitry Torokhov 	return 0;
609de9ce703SDmitry Torokhov }
610de9ce703SDmitry Torokhov 
611de9ce703SDmitry Torokhov /*
612de9ce703SDmitry Torokhov  * i8042_enable_aux_port enables AUX (mouse) port on chip
613de9ce703SDmitry Torokhov  */
614de9ce703SDmitry Torokhov 
615de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void)
616de9ce703SDmitry Torokhov {
617de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXDIS;
618de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXINT;
619de9ce703SDmitry Torokhov 
620de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
621018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_AUXINT;
622018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_AUXDIS;
6234eb3c30bSJoe Perches 		pr_err("Failed to enable AUX port\n");
624de9ce703SDmitry Torokhov 		return -EIO;
625de9ce703SDmitry Torokhov 	}
626de9ce703SDmitry Torokhov 
627de9ce703SDmitry Torokhov 	return 0;
628de9ce703SDmitry Torokhov }
629de9ce703SDmitry Torokhov 
630de9ce703SDmitry Torokhov /*
631de9ce703SDmitry Torokhov  * i8042_enable_mux_ports enables 4 individual AUX ports after
632de9ce703SDmitry Torokhov  * the controller has been switched into Multiplexed mode
633de9ce703SDmitry Torokhov  */
634de9ce703SDmitry Torokhov 
635de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void)
636de9ce703SDmitry Torokhov {
637de9ce703SDmitry Torokhov 	unsigned char param;
638de9ce703SDmitry Torokhov 	int i;
639de9ce703SDmitry Torokhov 
640de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
641de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_MUX_PFX + i);
642de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_AUX_ENABLE);
643de9ce703SDmitry Torokhov 	}
644de9ce703SDmitry Torokhov 
645de9ce703SDmitry Torokhov 	return i8042_enable_aux_port();
646de9ce703SDmitry Torokhov }
647de9ce703SDmitry Torokhov 
648de9ce703SDmitry Torokhov /*
649386b3849SDmitry Torokhov  * i8042_set_mux_mode checks whether the controller has an
650386b3849SDmitry Torokhov  * active multiplexor and puts the chip into Multiplexed (true)
651386b3849SDmitry Torokhov  * or Legacy (false) mode.
6521da177e4SLinus Torvalds  */
6531da177e4SLinus Torvalds 
654386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version)
6551da177e4SLinus Torvalds {
6561da177e4SLinus Torvalds 
657386b3849SDmitry Torokhov 	unsigned char param, val;
6581da177e4SLinus Torvalds /*
6591da177e4SLinus Torvalds  * Get rid of bytes in the queue.
6601da177e4SLinus Torvalds  */
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds 	i8042_flush();
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds /*
6651da177e4SLinus Torvalds  * Internal loopback test - send three bytes, they should come back from the
666de9ce703SDmitry Torokhov  * mouse interface, the last should be version.
6671da177e4SLinus Torvalds  */
6681da177e4SLinus Torvalds 
669386b3849SDmitry Torokhov 	param = val = 0xf0;
670386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6711da177e4SLinus Torvalds 		return -1;
672386b3849SDmitry Torokhov 	param = val = multiplex ? 0x56 : 0xf6;
673386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6741da177e4SLinus Torvalds 		return -1;
675386b3849SDmitry Torokhov 	param = val = multiplex ? 0xa4 : 0xa5;
676386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == val)
677386b3849SDmitry Torokhov 		return -1;
678386b3849SDmitry Torokhov 
679386b3849SDmitry Torokhov /*
680386b3849SDmitry Torokhov  * Workaround for interference with USB Legacy emulation
681386b3849SDmitry Torokhov  * that causes a v10.12 MUX to be found.
682386b3849SDmitry Torokhov  */
683386b3849SDmitry Torokhov 	if (param == 0xac)
6841da177e4SLinus Torvalds 		return -1;
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	if (mux_version)
687463a4f76SDmitry Torokhov 		*mux_version = param;
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds 	return 0;
6901da177e4SLinus Torvalds }
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds /*
6931da177e4SLinus Torvalds  * i8042_check_mux() checks whether the controller supports the PS/2 Active
6941da177e4SLinus Torvalds  * Multiplexing specification by Synaptics, Phoenix, Insyde and
6951da177e4SLinus Torvalds  * LCS/Telegraphics.
6961da177e4SLinus Torvalds  */
6971da177e4SLinus Torvalds 
698f8113416SDmitry Torokhov static int __init i8042_check_mux(void)
6991da177e4SLinus Torvalds {
7001da177e4SLinus Torvalds 	unsigned char mux_version;
7011da177e4SLinus Torvalds 
702386b3849SDmitry Torokhov 	if (i8042_set_mux_mode(true, &mux_version))
7031da177e4SLinus Torvalds 		return -1;
7041da177e4SLinus Torvalds 
7054eb3c30bSJoe Perches 	pr_info("Detected active multiplexing controller, rev %d.%d\n",
7061da177e4SLinus Torvalds 		(mux_version >> 4) & 0xf, mux_version & 0xf);
7071da177e4SLinus Torvalds 
708de9ce703SDmitry Torokhov /*
709de9ce703SDmitry Torokhov  * Disable all muxed ports by disabling AUX.
710de9ce703SDmitry Torokhov  */
711de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS;
712de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXINT;
713de9ce703SDmitry Torokhov 
714de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
7154eb3c30bSJoe Perches 		pr_err("Failed to disable AUX port, can't use MUX\n");
716de9ce703SDmitry Torokhov 		return -EIO;
717de9ce703SDmitry Torokhov 	}
7181da177e4SLinus Torvalds 
719386b3849SDmitry Torokhov 	i8042_mux_present = true;
720de9ce703SDmitry Torokhov 
7211da177e4SLinus Torvalds 	return 0;
7221da177e4SLinus Torvalds }
7231da177e4SLinus Torvalds 
724de9ce703SDmitry Torokhov /*
725de9ce703SDmitry Torokhov  * The following is used to test AUX IRQ delivery.
726de9ce703SDmitry Torokhov  */
727f8113416SDmitry Torokhov static struct completion i8042_aux_irq_delivered __initdata;
728f8113416SDmitry Torokhov static bool i8042_irq_being_tested __initdata;
729de9ce703SDmitry Torokhov 
730f8113416SDmitry Torokhov static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
731de9ce703SDmitry Torokhov {
732de9ce703SDmitry Torokhov 	unsigned long flags;
733de9ce703SDmitry Torokhov 	unsigned char str, data;
734e3758b2aSFernando Luis Vázquez Cao 	int ret = 0;
735de9ce703SDmitry Torokhov 
736de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
737de9ce703SDmitry Torokhov 	str = i8042_read_status();
738de9ce703SDmitry Torokhov 	if (str & I8042_STR_OBF) {
739de9ce703SDmitry Torokhov 		data = i8042_read_data();
7404eb3c30bSJoe Perches 		dbg("%02x <- i8042 (aux_test_irq, %s)\n",
741d3d2dfe2SDmitry Torokhov 		    data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
742de9ce703SDmitry Torokhov 		if (i8042_irq_being_tested &&
743de9ce703SDmitry Torokhov 		    data == 0xa5 && (str & I8042_STR_AUXDATA))
744de9ce703SDmitry Torokhov 			complete(&i8042_aux_irq_delivered);
745e3758b2aSFernando Luis Vázquez Cao 		ret = 1;
746de9ce703SDmitry Torokhov 	}
747de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
748de9ce703SDmitry Torokhov 
749e3758b2aSFernando Luis Vázquez Cao 	return IRQ_RETVAL(ret);
750de9ce703SDmitry Torokhov }
751de9ce703SDmitry Torokhov 
752d2ada559SRoland Scheidegger /*
753d2ada559SRoland Scheidegger  * i8042_toggle_aux - enables or disables AUX port on i8042 via command and
754d2ada559SRoland Scheidegger  * verifies success by readinng CTR. Used when testing for presence of AUX
755d2ada559SRoland Scheidegger  * port.
756d2ada559SRoland Scheidegger  */
757f8113416SDmitry Torokhov static int __init i8042_toggle_aux(bool on)
758d2ada559SRoland Scheidegger {
759d2ada559SRoland Scheidegger 	unsigned char param;
760d2ada559SRoland Scheidegger 	int i;
761d2ada559SRoland Scheidegger 
762d2ada559SRoland Scheidegger 	if (i8042_command(&param,
763d2ada559SRoland Scheidegger 			on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE))
764d2ada559SRoland Scheidegger 		return -1;
765d2ada559SRoland Scheidegger 
766d2ada559SRoland Scheidegger 	/* some chips need some time to set the I8042_CTR_AUXDIS bit */
767d2ada559SRoland Scheidegger 	for (i = 0; i < 100; i++) {
768d2ada559SRoland Scheidegger 		udelay(50);
769d2ada559SRoland Scheidegger 
770d2ada559SRoland Scheidegger 		if (i8042_command(&param, I8042_CMD_CTL_RCTR))
771d2ada559SRoland Scheidegger 			return -1;
772d2ada559SRoland Scheidegger 
773d2ada559SRoland Scheidegger 		if (!(param & I8042_CTR_AUXDIS) == on)
774d2ada559SRoland Scheidegger 			return 0;
775d2ada559SRoland Scheidegger 	}
776d2ada559SRoland Scheidegger 
777d2ada559SRoland Scheidegger 	return -1;
778d2ada559SRoland Scheidegger }
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds /*
7811da177e4SLinus Torvalds  * i8042_check_aux() applies as much paranoia as it can at detecting
7821da177e4SLinus Torvalds  * the presence of an AUX interface.
7831da177e4SLinus Torvalds  */
7841da177e4SLinus Torvalds 
785f8113416SDmitry Torokhov static int __init i8042_check_aux(void)
7861da177e4SLinus Torvalds {
787de9ce703SDmitry Torokhov 	int retval = -1;
788386b3849SDmitry Torokhov 	bool irq_registered = false;
789386b3849SDmitry Torokhov 	bool aux_loop_broken = false;
790de9ce703SDmitry Torokhov 	unsigned long flags;
7911da177e4SLinus Torvalds 	unsigned char param;
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds /*
7941da177e4SLinus Torvalds  * Get rid of bytes in the queue.
7951da177e4SLinus Torvalds  */
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds 	i8042_flush();
7981da177e4SLinus Torvalds 
7991da177e4SLinus Torvalds /*
8001da177e4SLinus Torvalds  * Internal loopback test - filters out AT-type i8042's. Unfortunately
8011da177e4SLinus Torvalds  * SiS screwed up and their 5597 doesn't support the LOOP command even
8021da177e4SLinus Torvalds  * though it has an AUX port.
8031da177e4SLinus Torvalds  */
8041da177e4SLinus Torvalds 
8051da177e4SLinus Torvalds 	param = 0x5a;
8063ca5de6dSDmitry Torokhov 	retval = i8042_command(&param, I8042_CMD_AUX_LOOP);
8073ca5de6dSDmitry Torokhov 	if (retval || param != 0x5a) {
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds /*
8101da177e4SLinus Torvalds  * External connection test - filters out AT-soldered PS/2 i8042's
8111da177e4SLinus Torvalds  * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error
8121da177e4SLinus Torvalds  * 0xfa - no error on some notebooks which ignore the spec
8131da177e4SLinus Torvalds  * Because it's common for chipsets to return error on perfectly functioning
8141da177e4SLinus Torvalds  * AUX ports, we test for this only when the LOOP command failed.
8151da177e4SLinus Torvalds  */
8161da177e4SLinus Torvalds 
817de9ce703SDmitry Torokhov 		if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
818de9ce703SDmitry Torokhov 		    (param && param != 0xfa && param != 0xff))
8191da177e4SLinus Torvalds 			return -1;
8201e4865f8SDmitry Torokhov 
8213ca5de6dSDmitry Torokhov /*
8223ca5de6dSDmitry Torokhov  * If AUX_LOOP completed without error but returned unexpected data
8233ca5de6dSDmitry Torokhov  * mark it as broken
8243ca5de6dSDmitry Torokhov  */
8253ca5de6dSDmitry Torokhov 		if (!retval)
826386b3849SDmitry Torokhov 			aux_loop_broken = true;
8271da177e4SLinus Torvalds 	}
8281da177e4SLinus Torvalds 
8291da177e4SLinus Torvalds /*
8301da177e4SLinus Torvalds  * Bit assignment test - filters out PS/2 i8042's in AT mode
8311da177e4SLinus Torvalds  */
8321da177e4SLinus Torvalds 
833386b3849SDmitry Torokhov 	if (i8042_toggle_aux(false)) {
8344eb3c30bSJoe Perches 		pr_warn("Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
8354eb3c30bSJoe Perches 		pr_warn("If AUX port is really absent please use the 'i8042.noaux' option\n");
8361da177e4SLinus Torvalds 	}
8371da177e4SLinus Torvalds 
838386b3849SDmitry Torokhov 	if (i8042_toggle_aux(true))
8391da177e4SLinus Torvalds 		return -1;
8401da177e4SLinus Torvalds 
8411da177e4SLinus Torvalds /*
842148e9a71SSrihari Vijayaraghavan  * Reset keyboard (needed on some laptops to successfully detect
843148e9a71SSrihari Vijayaraghavan  * touchpad, e.g., some Gigabyte laptop models with Elantech
844148e9a71SSrihari Vijayaraghavan  * touchpads).
845148e9a71SSrihari Vijayaraghavan  */
846148e9a71SSrihari Vijayaraghavan 	if (i8042_kbdreset) {
847148e9a71SSrihari Vijayaraghavan 		pr_warn("Attempting to reset device connected to KBD port\n");
848148e9a71SSrihari Vijayaraghavan 		i8042_kbd_write(NULL, (unsigned char) 0xff);
849148e9a71SSrihari Vijayaraghavan 	}
850148e9a71SSrihari Vijayaraghavan 
851148e9a71SSrihari Vijayaraghavan /*
852de9ce703SDmitry Torokhov  * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and
853de9ce703SDmitry Torokhov  * used it for a PCI card or somethig else.
854de9ce703SDmitry Torokhov  */
855de9ce703SDmitry Torokhov 
8561c7827aeSDmitry Torokhov 	if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) {
857de9ce703SDmitry Torokhov /*
858de9ce703SDmitry Torokhov  * Without LOOP command we can't test AUX IRQ delivery. Assume the port
859de9ce703SDmitry Torokhov  * is working and hope we are right.
860de9ce703SDmitry Torokhov  */
861de9ce703SDmitry Torokhov 		retval = 0;
862de9ce703SDmitry Torokhov 		goto out;
863de9ce703SDmitry Torokhov 	}
864de9ce703SDmitry Torokhov 
865de9ce703SDmitry Torokhov 	if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED,
866de9ce703SDmitry Torokhov 			"i8042", i8042_platform_device))
867de9ce703SDmitry Torokhov 		goto out;
868de9ce703SDmitry Torokhov 
869386b3849SDmitry Torokhov 	irq_registered = true;
870de9ce703SDmitry Torokhov 
871de9ce703SDmitry Torokhov 	if (i8042_enable_aux_port())
872de9ce703SDmitry Torokhov 		goto out;
873de9ce703SDmitry Torokhov 
874de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
875de9ce703SDmitry Torokhov 
876de9ce703SDmitry Torokhov 	init_completion(&i8042_aux_irq_delivered);
877386b3849SDmitry Torokhov 	i8042_irq_being_tested = true;
878de9ce703SDmitry Torokhov 
879de9ce703SDmitry Torokhov 	param = 0xa5;
880de9ce703SDmitry Torokhov 	retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);
881de9ce703SDmitry Torokhov 
882de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
883de9ce703SDmitry Torokhov 
884de9ce703SDmitry Torokhov 	if (retval)
885de9ce703SDmitry Torokhov 		goto out;
886de9ce703SDmitry Torokhov 
887de9ce703SDmitry Torokhov 	if (wait_for_completion_timeout(&i8042_aux_irq_delivered,
888de9ce703SDmitry Torokhov 					msecs_to_jiffies(250)) == 0) {
889de9ce703SDmitry Torokhov /*
890de9ce703SDmitry Torokhov  * AUX IRQ was never delivered so we need to flush the controller to
891de9ce703SDmitry Torokhov  * get rid of the byte we put there; otherwise keyboard may not work.
892de9ce703SDmitry Torokhov  */
8934eb3c30bSJoe Perches 		dbg("     -- i8042 (aux irq test timeout)\n");
894de9ce703SDmitry Torokhov 		i8042_flush();
895de9ce703SDmitry Torokhov 		retval = -1;
896de9ce703SDmitry Torokhov 	}
897de9ce703SDmitry Torokhov 
898de9ce703SDmitry Torokhov  out:
899de9ce703SDmitry Torokhov 
900de9ce703SDmitry Torokhov /*
9011da177e4SLinus Torvalds  * Disable the interface.
9021da177e4SLinus Torvalds  */
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_AUXDIS;
9051da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_AUXINT;
9061da177e4SLinus Torvalds 
9071da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
908de9ce703SDmitry Torokhov 		retval = -1;
909de9ce703SDmitry Torokhov 
910de9ce703SDmitry Torokhov 	if (irq_registered)
911de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
912de9ce703SDmitry Torokhov 
913de9ce703SDmitry Torokhov 	return retval;
914de9ce703SDmitry Torokhov }
915de9ce703SDmitry Torokhov 
916de9ce703SDmitry Torokhov static int i8042_controller_check(void)
917de9ce703SDmitry Torokhov {
9182f0d2604SAndrey Moiseev 	if (i8042_flush()) {
919f5d75341STakashi Iwai 		pr_info("No controller found\n");
920de9ce703SDmitry Torokhov 		return -ENODEV;
921de9ce703SDmitry Torokhov 	}
9221da177e4SLinus Torvalds 
9231da177e4SLinus Torvalds 	return 0;
9241da177e4SLinus Torvalds }
9251da177e4SLinus Torvalds 
926de9ce703SDmitry Torokhov static int i8042_controller_selftest(void)
9272673c836SVojtech Pavlik {
9282673c836SVojtech Pavlik 	unsigned char param;
9295ea2fc64SArjan van de Ven 	int i = 0;
9302673c836SVojtech Pavlik 
9315ea2fc64SArjan van de Ven 	/*
9325ea2fc64SArjan van de Ven 	 * We try this 5 times; on some really fragile systems this does not
9335ea2fc64SArjan van de Ven 	 * take the first time...
9345ea2fc64SArjan van de Ven 	 */
9355ea2fc64SArjan van de Ven 	do {
9365ea2fc64SArjan van de Ven 
9372673c836SVojtech Pavlik 		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
9384eb3c30bSJoe Perches 			pr_err("i8042 controller selftest timeout\n");
939de9ce703SDmitry Torokhov 			return -ENODEV;
9402673c836SVojtech Pavlik 		}
9412673c836SVojtech Pavlik 
9425ea2fc64SArjan van de Ven 		if (param == I8042_RET_CTL_TEST)
9435ea2fc64SArjan van de Ven 			return 0;
9445ea2fc64SArjan van de Ven 
945a2a94e73SPaul Bolle 		dbg("i8042 controller selftest: %#x != %#x\n",
9462673c836SVojtech Pavlik 		    param, I8042_RET_CTL_TEST);
9475ea2fc64SArjan van de Ven 		msleep(50);
9485ea2fc64SArjan van de Ven 	} while (i++ < 5);
9492673c836SVojtech Pavlik 
9505ea2fc64SArjan van de Ven #ifdef CONFIG_X86
9515ea2fc64SArjan van de Ven 	/*
9525ea2fc64SArjan van de Ven 	 * On x86, we don't fail entire i8042 initialization if controller
9535ea2fc64SArjan van de Ven 	 * reset fails in hopes that keyboard port will still be functional
9545ea2fc64SArjan van de Ven 	 * and user will still get a working keyboard. This is especially
9555ea2fc64SArjan van de Ven 	 * important on netbooks. On other arches we trust hardware more.
9565ea2fc64SArjan van de Ven 	 */
9574eb3c30bSJoe Perches 	pr_info("giving up on controller selftest, continuing anyway...\n");
9582673c836SVojtech Pavlik 	return 0;
9595ea2fc64SArjan van de Ven #else
960a2a94e73SPaul Bolle 	pr_err("i8042 controller selftest failed\n");
9615ea2fc64SArjan van de Ven 	return -EIO;
9625ea2fc64SArjan van de Ven #endif
9632673c836SVojtech Pavlik }
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds /*
9661da177e4SLinus Torvalds  * i8042_controller init initializes the i8042 controller, and,
9671da177e4SLinus Torvalds  * most importantly, sets it into non-xlated mode if that's
9681da177e4SLinus Torvalds  * desired.
9691da177e4SLinus Torvalds  */
9701da177e4SLinus Torvalds 
9711da177e4SLinus Torvalds static int i8042_controller_init(void)
9721da177e4SLinus Torvalds {
9731da177e4SLinus Torvalds 	unsigned long flags;
974ee1e82ceSDmitry Torokhov 	int n = 0;
975ee1e82ceSDmitry Torokhov 	unsigned char ctr[2];
9761da177e4SLinus Torvalds 
9771da177e4SLinus Torvalds /*
978ee1e82ceSDmitry Torokhov  * Save the CTR for restore on unload / reboot.
9791da177e4SLinus Torvalds  */
9801da177e4SLinus Torvalds 
981ee1e82ceSDmitry Torokhov 	do {
982ee1e82ceSDmitry Torokhov 		if (n >= 10) {
9834eb3c30bSJoe Perches 			pr_err("Unable to get stable CTR read\n");
984de9ce703SDmitry Torokhov 			return -EIO;
9851da177e4SLinus Torvalds 		}
9861da177e4SLinus Torvalds 
987ee1e82ceSDmitry Torokhov 		if (n != 0)
988ee1e82ceSDmitry Torokhov 			udelay(50);
989ee1e82ceSDmitry Torokhov 
990ee1e82ceSDmitry Torokhov 		if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
9914eb3c30bSJoe Perches 			pr_err("Can't read CTR while initializing i8042\n");
992ee1e82ceSDmitry Torokhov 			return -EIO;
993ee1e82ceSDmitry Torokhov 		}
994ee1e82ceSDmitry Torokhov 
995ee1e82ceSDmitry Torokhov 	} while (n < 2 || ctr[0] != ctr[1]);
996ee1e82ceSDmitry Torokhov 
997ee1e82ceSDmitry Torokhov 	i8042_initial_ctr = i8042_ctr = ctr[0];
9981da177e4SLinus Torvalds 
9991da177e4SLinus Torvalds /*
10001da177e4SLinus Torvalds  * Disable the keyboard interface and interrupt.
10011da177e4SLinus Torvalds  */
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_KBDDIS;
10041da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_KBDINT;
10051da177e4SLinus Torvalds 
10061da177e4SLinus Torvalds /*
10071da177e4SLinus Torvalds  * Handle keylock.
10081da177e4SLinus Torvalds  */
10091da177e4SLinus Torvalds 
10101da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
10111da177e4SLinus Torvalds 	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
10121da177e4SLinus Torvalds 		if (i8042_unlock)
10131da177e4SLinus Torvalds 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
10141da177e4SLinus Torvalds 		else
10154eb3c30bSJoe Perches 			pr_warn("Warning: Keylock active\n");
10161da177e4SLinus Torvalds 	}
10171da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds /*
10201da177e4SLinus Torvalds  * If the chip is configured into nontranslated mode by the BIOS, don't
10211da177e4SLinus Torvalds  * bother enabling translating and be happy.
10221da177e4SLinus Torvalds  */
10231da177e4SLinus Torvalds 
10241da177e4SLinus Torvalds 	if (~i8042_ctr & I8042_CTR_XLATE)
1025386b3849SDmitry Torokhov 		i8042_direct = true;
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds /*
10281da177e4SLinus Torvalds  * Set nontranslated mode for the kbd interface if requested by an option.
10291da177e4SLinus Torvalds  * After this the kbd interface becomes a simple serial in/out, like the aux
10301da177e4SLinus Torvalds  * interface is. We don't do this by default, since it can confuse notebook
10311da177e4SLinus Torvalds  * BIOSes.
10321da177e4SLinus Torvalds  */
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds 	if (i8042_direct)
10351da177e4SLinus Torvalds 		i8042_ctr &= ~I8042_CTR_XLATE;
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds /*
10381da177e4SLinus Torvalds  * Write CTR back.
10391da177e4SLinus Torvalds  */
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
10424eb3c30bSJoe Perches 		pr_err("Can't write CTR while initializing i8042\n");
1043de9ce703SDmitry Torokhov 		return -EIO;
10441da177e4SLinus Torvalds 	}
10451da177e4SLinus Torvalds 
1046ee1e82ceSDmitry Torokhov /*
1047ee1e82ceSDmitry Torokhov  * Flush whatever accumulated while we were disabling keyboard port.
1048ee1e82ceSDmitry Torokhov  */
1049ee1e82ceSDmitry Torokhov 
1050ee1e82ceSDmitry Torokhov 	i8042_flush();
1051ee1e82ceSDmitry Torokhov 
10521da177e4SLinus Torvalds 	return 0;
10531da177e4SLinus Torvalds }
10541da177e4SLinus Torvalds 
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds /*
1057de9ce703SDmitry Torokhov  * Reset the controller and reset CRT to the original value set by BIOS.
10581da177e4SLinus Torvalds  */
10591da177e4SLinus Torvalds 
1060930e1924SMarcos Paulo de Souza static void i8042_controller_reset(bool s2r_wants_reset)
1061de9ce703SDmitry Torokhov {
1062de9ce703SDmitry Torokhov 	i8042_flush();
10631da177e4SLinus Torvalds 
10641da177e4SLinus Torvalds /*
10658d04ddb6SDmitry Torokhov  * Disable both KBD and AUX interfaces so they don't get in the way
10668d04ddb6SDmitry Torokhov  */
10678d04ddb6SDmitry Torokhov 
10688d04ddb6SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
10698d04ddb6SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
10708d04ddb6SDmitry Torokhov 
1071ee1e82ceSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
10724eb3c30bSJoe Perches 		pr_warn("Can't write CTR while resetting\n");
10735ddbc77cSDmitry Torokhov 
10748d04ddb6SDmitry Torokhov /*
10751da177e4SLinus Torvalds  * Disable MUX mode if present.
10761da177e4SLinus Torvalds  */
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 	if (i8042_mux_present)
1079386b3849SDmitry Torokhov 		i8042_set_mux_mode(false, NULL);
10801da177e4SLinus Torvalds 
10811da177e4SLinus Torvalds /*
1082de9ce703SDmitry Torokhov  * Reset the controller if requested.
1083de9ce703SDmitry Torokhov  */
1084de9ce703SDmitry Torokhov 
1085930e1924SMarcos Paulo de Souza 	if (i8042_reset == I8042_RESET_ALWAYS ||
1086930e1924SMarcos Paulo de Souza 	    (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
1087de9ce703SDmitry Torokhov 		i8042_controller_selftest();
1088930e1924SMarcos Paulo de Souza 	}
1089de9ce703SDmitry Torokhov 
1090de9ce703SDmitry Torokhov /*
10911da177e4SLinus Torvalds  * Restore the original control register setting.
10921da177e4SLinus Torvalds  */
10931da177e4SLinus Torvalds 
1094de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
10954eb3c30bSJoe Perches 		pr_warn("Can't restore CTR\n");
10961da177e4SLinus Torvalds }
10971da177e4SLinus Torvalds 
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds /*
1100c7ff0d9cSTAMUKI Shoichi  * i8042_panic_blink() will turn the keyboard LEDs on or off and is called
1101c7ff0d9cSTAMUKI Shoichi  * when kernel panics. Flashing LEDs is useful for users running X who may
1102aa5e5dc2SMichael Opdenacker  * not see the console and will help distinguishing panics from "real"
11031da177e4SLinus Torvalds  * lockups.
11041da177e4SLinus Torvalds  *
11051da177e4SLinus Torvalds  * Note that DELAY has a limit of 10ms so we will not get stuck here
11061da177e4SLinus Torvalds  * waiting for KBC to free up even if KBD interrupt is off
11071da177e4SLinus Torvalds  */
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
11101da177e4SLinus Torvalds 
1111c7ff0d9cSTAMUKI Shoichi static long i8042_panic_blink(int state)
11121da177e4SLinus Torvalds {
11131da177e4SLinus Torvalds 	long delay = 0;
1114c7ff0d9cSTAMUKI Shoichi 	char led;
11151da177e4SLinus Torvalds 
1116c7ff0d9cSTAMUKI Shoichi 	led = (state) ? 0x01 | 0x04 : 0;
11171da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
11181da177e4SLinus Torvalds 		DELAY;
11194eb3c30bSJoe Perches 	dbg("%02x -> i8042 (panic blink)\n", 0xed);
112019f3c3e3SDmitry Torokhov 	i8042_suppress_kbd_ack = 2;
11211da177e4SLinus Torvalds 	i8042_write_data(0xed); /* set leds */
11221da177e4SLinus Torvalds 	DELAY;
11231da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
11241da177e4SLinus Torvalds 		DELAY;
11251da177e4SLinus Torvalds 	DELAY;
11264eb3c30bSJoe Perches 	dbg("%02x -> i8042 (panic blink)\n", led);
11271da177e4SLinus Torvalds 	i8042_write_data(led);
11281da177e4SLinus Torvalds 	DELAY;
11291da177e4SLinus Torvalds 	return delay;
11301da177e4SLinus Torvalds }
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds #undef DELAY
11331da177e4SLinus Torvalds 
1134d35895dbSBruno Prémont #ifdef CONFIG_X86
1135d35895dbSBruno Prémont static void i8042_dritek_enable(void)
1136d35895dbSBruno Prémont {
1137594d6363SChristoph Fritz 	unsigned char param = 0x90;
1138d35895dbSBruno Prémont 	int error;
1139d35895dbSBruno Prémont 
1140d35895dbSBruno Prémont 	error = i8042_command(&param, 0x1059);
1141d35895dbSBruno Prémont 	if (error)
11424eb3c30bSJoe Perches 		pr_warn("Failed to enable DRITEK extension: %d\n", error);
1143d35895dbSBruno Prémont }
1144d35895dbSBruno Prémont #endif
1145d35895dbSBruno Prémont 
114682dd9effSDmitry Torokhov #ifdef CONFIG_PM
11477e044e05SDmitry Torokhov 
11481da177e4SLinus Torvalds /*
1149ebd7768dSDmitry Torokhov  * Here we try to reset everything back to a state we had
1150ebd7768dSDmitry Torokhov  * before suspending.
11511da177e4SLinus Torvalds  */
11521da177e4SLinus Torvalds 
1153930e1924SMarcos Paulo de Souza static int i8042_controller_resume(bool s2r_wants_reset)
11541da177e4SLinus Torvalds {
1155de9ce703SDmitry Torokhov 	int error;
11561da177e4SLinus Torvalds 
1157de9ce703SDmitry Torokhov 	error = i8042_controller_check();
1158de9ce703SDmitry Torokhov 	if (error)
1159de9ce703SDmitry Torokhov 		return error;
11602673c836SVojtech Pavlik 
1161930e1924SMarcos Paulo de Souza 	if (i8042_reset == I8042_RESET_ALWAYS ||
1162930e1924SMarcos Paulo de Souza 	    (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
1163de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1164de9ce703SDmitry Torokhov 		if (error)
1165de9ce703SDmitry Torokhov 			return error;
11661ca56e51SDmitry Torokhov 	}
1167de9ce703SDmitry Torokhov 
1168de9ce703SDmitry Torokhov /*
116982dd9effSDmitry Torokhov  * Restore original CTR value and disable all ports
1170de9ce703SDmitry Torokhov  */
1171de9ce703SDmitry Torokhov 
117282dd9effSDmitry Torokhov 	i8042_ctr = i8042_initial_ctr;
117382dd9effSDmitry Torokhov 	if (i8042_direct)
117482dd9effSDmitry Torokhov 		i8042_ctr &= ~I8042_CTR_XLATE;
1175de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
1176de9ce703SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
11772673c836SVojtech Pavlik 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
11784eb3c30bSJoe Perches 		pr_warn("Can't write CTR to resume, retrying...\n");
11792f6a77d5SJiri Kosina 		msleep(50);
11802f6a77d5SJiri Kosina 		if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
11814eb3c30bSJoe Perches 			pr_err("CTR write retry failed\n");
1182de9ce703SDmitry Torokhov 			return -EIO;
11831da177e4SLinus Torvalds 		}
11842f6a77d5SJiri Kosina 	}
11851da177e4SLinus Torvalds 
1186d35895dbSBruno Prémont 
1187d35895dbSBruno Prémont #ifdef CONFIG_X86
1188d35895dbSBruno Prémont 	if (i8042_dritek)
1189d35895dbSBruno Prémont 		i8042_dritek_enable();
1190d35895dbSBruno Prémont #endif
1191d35895dbSBruno Prémont 
1192de9ce703SDmitry Torokhov 	if (i8042_mux_present) {
1193386b3849SDmitry Torokhov 		if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
11944eb3c30bSJoe Perches 			pr_warn("failed to resume active multiplexor, mouse won't work\n");
1195de9ce703SDmitry Torokhov 	} else if (i8042_ports[I8042_AUX_PORT_NO].serio)
1196de9ce703SDmitry Torokhov 		i8042_enable_aux_port();
11971da177e4SLinus Torvalds 
1198de9ce703SDmitry Torokhov 	if (i8042_ports[I8042_KBD_PORT_NO].serio)
1199de9ce703SDmitry Torokhov 		i8042_enable_kbd_port();
12001da177e4SLinus Torvalds 
12017d12e780SDavid Howells 	i8042_interrupt(0, NULL);
12021da177e4SLinus Torvalds 
12031da177e4SLinus Torvalds 	return 0;
12041da177e4SLinus Torvalds }
1205ebd7768dSDmitry Torokhov 
12061ca56e51SDmitry Torokhov /*
12071ca56e51SDmitry Torokhov  * Here we try to restore the original BIOS settings to avoid
12081ca56e51SDmitry Torokhov  * upsetting it.
12091ca56e51SDmitry Torokhov  */
12101ca56e51SDmitry Torokhov 
12111729ad1fSDmitry Torokhov static int i8042_pm_suspend(struct device *dev)
12121ca56e51SDmitry Torokhov {
1213f13b2065SRafael J. Wysocki 	int i;
1214f13b2065SRafael J. Wysocki 
12151c5dd134SRafael J. Wysocki 	if (pm_suspend_via_firmware())
12161729ad1fSDmitry Torokhov 		i8042_controller_reset(true);
12171ca56e51SDmitry Torokhov 
1218f13b2065SRafael J. Wysocki 	/* Set up serio interrupts for system wakeup. */
1219f13b2065SRafael J. Wysocki 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1220f13b2065SRafael J. Wysocki 		struct serio *serio = i8042_ports[i].serio;
1221f13b2065SRafael J. Wysocki 
1222f13b2065SRafael J. Wysocki 		if (serio && device_may_wakeup(&serio->dev))
1223f13b2065SRafael J. Wysocki 			enable_irq_wake(i8042_ports[i].irq);
1224f13b2065SRafael J. Wysocki 	}
1225f13b2065SRafael J. Wysocki 
12261ca56e51SDmitry Torokhov 	return 0;
12271ca56e51SDmitry Torokhov }
12281ca56e51SDmitry Torokhov 
12291c5dd134SRafael J. Wysocki static int i8042_pm_resume_noirq(struct device *dev)
12301c5dd134SRafael J. Wysocki {
12311c5dd134SRafael J. Wysocki 	if (!pm_resume_via_firmware())
12321c5dd134SRafael J. Wysocki 		i8042_interrupt(0, NULL);
12331c5dd134SRafael J. Wysocki 
12341c5dd134SRafael J. Wysocki 	return 0;
12351c5dd134SRafael J. Wysocki }
12361c5dd134SRafael J. Wysocki 
12371ca56e51SDmitry Torokhov static int i8042_pm_resume(struct device *dev)
12381ca56e51SDmitry Torokhov {
1239930e1924SMarcos Paulo de Souza 	bool want_reset;
1240f13b2065SRafael J. Wysocki 	int i;
1241f13b2065SRafael J. Wysocki 
1242f13b2065SRafael J. Wysocki 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1243f13b2065SRafael J. Wysocki 		struct serio *serio = i8042_ports[i].serio;
1244f13b2065SRafael J. Wysocki 
1245f13b2065SRafael J. Wysocki 		if (serio && device_may_wakeup(&serio->dev))
1246f13b2065SRafael J. Wysocki 			disable_irq_wake(i8042_ports[i].irq);
1247f13b2065SRafael J. Wysocki 	}
1248f13b2065SRafael J. Wysocki 
12491ca56e51SDmitry Torokhov 	/*
12501c5dd134SRafael J. Wysocki 	 * If platform firmware was not going to be involved in suspend, we did
12511c5dd134SRafael J. Wysocki 	 * not restore the controller state to whatever it had been at boot
12521c5dd134SRafael J. Wysocki 	 * time, so we do not need to do anything.
12531ca56e51SDmitry Torokhov 	 */
12541c5dd134SRafael J. Wysocki 	if (!pm_suspend_via_firmware())
12551c5dd134SRafael J. Wysocki 		return 0;
12561c5dd134SRafael J. Wysocki 
12571c5dd134SRafael J. Wysocki 	/*
12581c5dd134SRafael J. Wysocki 	 * We only need to reset the controller if we are resuming after handing
12591c5dd134SRafael J. Wysocki 	 * off control to the platform firmware, otherwise we can simply restore
12601c5dd134SRafael J. Wysocki 	 * the mode.
12611c5dd134SRafael J. Wysocki 	 */
1262930e1924SMarcos Paulo de Souza 	want_reset = pm_resume_via_firmware();
12631c5dd134SRafael J. Wysocki 
1264930e1924SMarcos Paulo de Souza 	return i8042_controller_resume(want_reset);
12651ca56e51SDmitry Torokhov }
12661ca56e51SDmitry Torokhov 
1267c2d1a2a1SAlan Jenkins static int i8042_pm_thaw(struct device *dev)
1268c2d1a2a1SAlan Jenkins {
1269c2d1a2a1SAlan Jenkins 	i8042_interrupt(0, NULL);
1270c2d1a2a1SAlan Jenkins 
1271c2d1a2a1SAlan Jenkins 	return 0;
1272c2d1a2a1SAlan Jenkins }
1273c2d1a2a1SAlan Jenkins 
12741729ad1fSDmitry Torokhov static int i8042_pm_reset(struct device *dev)
12751729ad1fSDmitry Torokhov {
12761729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
12771729ad1fSDmitry Torokhov 
12781729ad1fSDmitry Torokhov 	return 0;
12791729ad1fSDmitry Torokhov }
12801729ad1fSDmitry Torokhov 
12811ca56e51SDmitry Torokhov static int i8042_pm_restore(struct device *dev)
12821ca56e51SDmitry Torokhov {
12831ca56e51SDmitry Torokhov 	return i8042_controller_resume(false);
12841ca56e51SDmitry Torokhov }
12851ca56e51SDmitry Torokhov 
1286ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = {
12871729ad1fSDmitry Torokhov 	.suspend	= i8042_pm_suspend,
12881c5dd134SRafael J. Wysocki 	.resume_noirq	= i8042_pm_resume_noirq,
12891ca56e51SDmitry Torokhov 	.resume		= i8042_pm_resume,
1290c2d1a2a1SAlan Jenkins 	.thaw		= i8042_pm_thaw,
1291ebd7768dSDmitry Torokhov 	.poweroff	= i8042_pm_reset,
1292ebd7768dSDmitry Torokhov 	.restore	= i8042_pm_restore,
1293ebd7768dSDmitry Torokhov };
1294ebd7768dSDmitry Torokhov 
129582dd9effSDmitry Torokhov #endif /* CONFIG_PM */
12961da177e4SLinus Torvalds 
12971da177e4SLinus Torvalds /*
12981da177e4SLinus Torvalds  * We need to reset the 8042 back to original mode on system shutdown,
12991da177e4SLinus Torvalds  * because otherwise BIOSes will be confused.
13001da177e4SLinus Torvalds  */
13011da177e4SLinus Torvalds 
13023ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev)
13031da177e4SLinus Torvalds {
13041729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
13051da177e4SLinus Torvalds }
13061da177e4SLinus Torvalds 
1307f8113416SDmitry Torokhov static int __init i8042_create_kbd_port(void)
13081da177e4SLinus Torvalds {
13091da177e4SLinus Torvalds 	struct serio *serio;
13101da177e4SLinus Torvalds 	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
13111da177e4SLinus Torvalds 
1312d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
13130854e52dSDmitry Torokhov 	if (!serio)
13140854e52dSDmitry Torokhov 		return -ENOMEM;
13150854e52dSDmitry Torokhov 
13161da177e4SLinus Torvalds 	serio->id.type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL;
13171da177e4SLinus Torvalds 	serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write;
13181da177e4SLinus Torvalds 	serio->start		= i8042_start;
13191da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
13205ddbc77cSDmitry Torokhov 	serio->close		= i8042_port_close;
132140974618SDmitry Torokhov 	serio->ps2_cmd_mutex	= &i8042_mutex;
13221da177e4SLinus Torvalds 	serio->port_data	= port;
13231da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1324de9ce703SDmitry Torokhov 	strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
13251da177e4SLinus Torvalds 	strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
1326a7c5868cSHans de Goede 	strlcpy(serio->firmware_id, i8042_kbd_firmware_id,
1327a7c5868cSHans de Goede 		sizeof(serio->firmware_id));
13281da177e4SLinus Torvalds 
13291da177e4SLinus Torvalds 	port->serio = serio;
1330de9ce703SDmitry Torokhov 	port->irq = I8042_KBD_IRQ;
13310854e52dSDmitry Torokhov 
1332de9ce703SDmitry Torokhov 	return 0;
13331da177e4SLinus Torvalds }
13341da177e4SLinus Torvalds 
1335f8113416SDmitry Torokhov static int __init i8042_create_aux_port(int idx)
13361da177e4SLinus Torvalds {
13371da177e4SLinus Torvalds 	struct serio *serio;
1338de9ce703SDmitry Torokhov 	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
1339de9ce703SDmitry Torokhov 	struct i8042_port *port = &i8042_ports[port_no];
13401da177e4SLinus Torvalds 
1341d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
13420854e52dSDmitry Torokhov 	if (!serio)
13430854e52dSDmitry Torokhov 		return -ENOMEM;
13440854e52dSDmitry Torokhov 
13451da177e4SLinus Torvalds 	serio->id.type		= SERIO_8042;
13461da177e4SLinus Torvalds 	serio->write		= i8042_aux_write;
13471da177e4SLinus Torvalds 	serio->start		= i8042_start;
13481da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
134947af45d6SDmitry Torokhov 	serio->ps2_cmd_mutex	= &i8042_mutex;
13501da177e4SLinus Torvalds 	serio->port_data	= port;
13511da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1352de9ce703SDmitry Torokhov 	if (idx < 0) {
1353de9ce703SDmitry Torokhov 		strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));
13541da177e4SLinus Torvalds 		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
1355a7c5868cSHans de Goede 		strlcpy(serio->firmware_id, i8042_aux_firmware_id,
1356a7c5868cSHans de Goede 			sizeof(serio->firmware_id));
13575ddbc77cSDmitry Torokhov 		serio->close = i8042_port_close;
1358de9ce703SDmitry Torokhov 	} else {
1359de9ce703SDmitry Torokhov 		snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
1360de9ce703SDmitry Torokhov 		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
1361266e43c4SHans de Goede 		strlcpy(serio->firmware_id, i8042_aux_firmware_id,
1362266e43c4SHans de Goede 			sizeof(serio->firmware_id));
13631da177e4SLinus Torvalds 	}
13641da177e4SLinus Torvalds 
13651da177e4SLinus Torvalds 	port->serio = serio;
1366de9ce703SDmitry Torokhov 	port->mux = idx;
1367de9ce703SDmitry Torokhov 	port->irq = I8042_AUX_IRQ;
13680854e52dSDmitry Torokhov 
1369de9ce703SDmitry Torokhov 	return 0;
1370de9ce703SDmitry Torokhov }
1371de9ce703SDmitry Torokhov 
1372f8113416SDmitry Torokhov static void __init i8042_free_kbd_port(void)
1373de9ce703SDmitry Torokhov {
1374de9ce703SDmitry Torokhov 	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
1375de9ce703SDmitry Torokhov 	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
1376de9ce703SDmitry Torokhov }
1377de9ce703SDmitry Torokhov 
1378f8113416SDmitry Torokhov static void __init i8042_free_aux_ports(void)
1379de9ce703SDmitry Torokhov {
1380de9ce703SDmitry Torokhov 	int i;
1381de9ce703SDmitry Torokhov 
1382de9ce703SDmitry Torokhov 	for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) {
1383de9ce703SDmitry Torokhov 		kfree(i8042_ports[i].serio);
1384de9ce703SDmitry Torokhov 		i8042_ports[i].serio = NULL;
1385de9ce703SDmitry Torokhov 	}
1386de9ce703SDmitry Torokhov }
1387de9ce703SDmitry Torokhov 
1388f8113416SDmitry Torokhov static void __init i8042_register_ports(void)
1389de9ce703SDmitry Torokhov {
1390de9ce703SDmitry Torokhov 	int i;
1391de9ce703SDmitry Torokhov 
1392de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1393f13b2065SRafael J. Wysocki 		struct serio *serio = i8042_ports[i].serio;
1394f13b2065SRafael J. Wysocki 
1395f13b2065SRafael J. Wysocki 		if (serio) {
1396de9ce703SDmitry Torokhov 			printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
1397f13b2065SRafael J. Wysocki 				serio->name,
1398de9ce703SDmitry Torokhov 				(unsigned long) I8042_DATA_REG,
1399de9ce703SDmitry Torokhov 				(unsigned long) I8042_COMMAND_REG,
1400de9ce703SDmitry Torokhov 				i8042_ports[i].irq);
1401f13b2065SRafael J. Wysocki 			serio_register_port(serio);
1402f13b2065SRafael J. Wysocki 			device_set_wakeup_capable(&serio->dev, true);
1403de9ce703SDmitry Torokhov 		}
1404de9ce703SDmitry Torokhov 	}
1405de9ce703SDmitry Torokhov }
1406de9ce703SDmitry Torokhov 
1407e2619cf7SBill Pemberton static void i8042_unregister_ports(void)
1408de9ce703SDmitry Torokhov {
1409de9ce703SDmitry Torokhov 	int i;
1410de9ce703SDmitry Torokhov 
1411de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1412de9ce703SDmitry Torokhov 		if (i8042_ports[i].serio) {
1413de9ce703SDmitry Torokhov 			serio_unregister_port(i8042_ports[i].serio);
1414de9ce703SDmitry Torokhov 			i8042_ports[i].serio = NULL;
1415de9ce703SDmitry Torokhov 		}
1416de9ce703SDmitry Torokhov 	}
1417de9ce703SDmitry Torokhov }
1418de9ce703SDmitry Torokhov 
1419de9ce703SDmitry Torokhov static void i8042_free_irqs(void)
1420de9ce703SDmitry Torokhov {
1421de9ce703SDmitry Torokhov 	if (i8042_aux_irq_registered)
1422de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
1423de9ce703SDmitry Torokhov 	if (i8042_kbd_irq_registered)
1424de9ce703SDmitry Torokhov 		free_irq(I8042_KBD_IRQ, i8042_platform_device);
1425de9ce703SDmitry Torokhov 
1426386b3849SDmitry Torokhov 	i8042_aux_irq_registered = i8042_kbd_irq_registered = false;
1427de9ce703SDmitry Torokhov }
1428de9ce703SDmitry Torokhov 
1429f8113416SDmitry Torokhov static int __init i8042_setup_aux(void)
1430de9ce703SDmitry Torokhov {
1431de9ce703SDmitry Torokhov 	int (*aux_enable)(void);
1432de9ce703SDmitry Torokhov 	int error;
1433de9ce703SDmitry Torokhov 	int i;
1434de9ce703SDmitry Torokhov 
1435de9ce703SDmitry Torokhov 	if (i8042_check_aux())
1436de9ce703SDmitry Torokhov 		return -ENODEV;
1437de9ce703SDmitry Torokhov 
1438de9ce703SDmitry Torokhov 	if (i8042_nomux || i8042_check_mux()) {
1439de9ce703SDmitry Torokhov 		error = i8042_create_aux_port(-1);
1440de9ce703SDmitry Torokhov 		if (error)
1441de9ce703SDmitry Torokhov 			goto err_free_ports;
1442de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_aux_port;
1443de9ce703SDmitry Torokhov 	} else {
1444de9ce703SDmitry Torokhov 		for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
1445de9ce703SDmitry Torokhov 			error = i8042_create_aux_port(i);
1446de9ce703SDmitry Torokhov 			if (error)
1447de9ce703SDmitry Torokhov 				goto err_free_ports;
1448de9ce703SDmitry Torokhov 		}
1449de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_mux_ports;
1450de9ce703SDmitry Torokhov 	}
1451de9ce703SDmitry Torokhov 
1452de9ce703SDmitry Torokhov 	error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED,
1453de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1454de9ce703SDmitry Torokhov 	if (error)
1455de9ce703SDmitry Torokhov 		goto err_free_ports;
1456de9ce703SDmitry Torokhov 
1457de9ce703SDmitry Torokhov 	if (aux_enable())
1458de9ce703SDmitry Torokhov 		goto err_free_irq;
1459de9ce703SDmitry Torokhov 
1460386b3849SDmitry Torokhov 	i8042_aux_irq_registered = true;
1461de9ce703SDmitry Torokhov 	return 0;
1462de9ce703SDmitry Torokhov 
1463de9ce703SDmitry Torokhov  err_free_irq:
1464de9ce703SDmitry Torokhov 	free_irq(I8042_AUX_IRQ, i8042_platform_device);
1465de9ce703SDmitry Torokhov  err_free_ports:
1466de9ce703SDmitry Torokhov 	i8042_free_aux_ports();
1467de9ce703SDmitry Torokhov 	return error;
1468de9ce703SDmitry Torokhov }
1469de9ce703SDmitry Torokhov 
1470f8113416SDmitry Torokhov static int __init i8042_setup_kbd(void)
1471de9ce703SDmitry Torokhov {
1472de9ce703SDmitry Torokhov 	int error;
1473de9ce703SDmitry Torokhov 
1474de9ce703SDmitry Torokhov 	error = i8042_create_kbd_port();
1475de9ce703SDmitry Torokhov 	if (error)
1476de9ce703SDmitry Torokhov 		return error;
1477de9ce703SDmitry Torokhov 
1478de9ce703SDmitry Torokhov 	error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
1479de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1480de9ce703SDmitry Torokhov 	if (error)
1481de9ce703SDmitry Torokhov 		goto err_free_port;
1482de9ce703SDmitry Torokhov 
1483de9ce703SDmitry Torokhov 	error = i8042_enable_kbd_port();
1484de9ce703SDmitry Torokhov 	if (error)
1485de9ce703SDmitry Torokhov 		goto err_free_irq;
1486de9ce703SDmitry Torokhov 
1487386b3849SDmitry Torokhov 	i8042_kbd_irq_registered = true;
1488de9ce703SDmitry Torokhov 	return 0;
1489de9ce703SDmitry Torokhov 
1490de9ce703SDmitry Torokhov  err_free_irq:
1491de9ce703SDmitry Torokhov 	free_irq(I8042_KBD_IRQ, i8042_platform_device);
1492de9ce703SDmitry Torokhov  err_free_port:
1493de9ce703SDmitry Torokhov 	i8042_free_kbd_port();
1494de9ce703SDmitry Torokhov 	return error;
14951da177e4SLinus Torvalds }
14961da177e4SLinus Torvalds 
1497e1443d28SStephen Chandler Paul static int i8042_kbd_bind_notifier(struct notifier_block *nb,
1498e1443d28SStephen Chandler Paul 				   unsigned long action, void *data)
1499e1443d28SStephen Chandler Paul {
1500e1443d28SStephen Chandler Paul 	struct device *dev = data;
1501e1443d28SStephen Chandler Paul 	struct serio *serio = to_serio_port(dev);
1502e1443d28SStephen Chandler Paul 	struct i8042_port *port = serio->port_data;
1503e1443d28SStephen Chandler Paul 
1504e1443d28SStephen Chandler Paul 	if (serio != i8042_ports[I8042_KBD_PORT_NO].serio)
1505e1443d28SStephen Chandler Paul 		return 0;
1506e1443d28SStephen Chandler Paul 
1507e1443d28SStephen Chandler Paul 	switch (action) {
1508e1443d28SStephen Chandler Paul 	case BUS_NOTIFY_BOUND_DRIVER:
1509e1443d28SStephen Chandler Paul 		port->driver_bound = true;
1510e1443d28SStephen Chandler Paul 		break;
1511e1443d28SStephen Chandler Paul 
1512e1443d28SStephen Chandler Paul 	case BUS_NOTIFY_UNBIND_DRIVER:
1513e1443d28SStephen Chandler Paul 		port->driver_bound = false;
1514e1443d28SStephen Chandler Paul 		break;
1515e1443d28SStephen Chandler Paul 	}
1516e1443d28SStephen Chandler Paul 
1517e1443d28SStephen Chandler Paul 	return 0;
1518e1443d28SStephen Chandler Paul }
1519e1443d28SStephen Chandler Paul 
1520f8113416SDmitry Torokhov static int __init i8042_probe(struct platform_device *dev)
15211da177e4SLinus Torvalds {
1522de9ce703SDmitry Torokhov 	int error;
15231da177e4SLinus Torvalds 
1524ec62e1c8SDmitry Torokhov 	i8042_platform_device = dev;
1525ec62e1c8SDmitry Torokhov 
1526930e1924SMarcos Paulo de Souza 	if (i8042_reset == I8042_RESET_ALWAYS) {
1527de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1528de9ce703SDmitry Torokhov 		if (error)
1529de9ce703SDmitry Torokhov 			return error;
15301ca56e51SDmitry Torokhov 	}
15311da177e4SLinus Torvalds 
1532de9ce703SDmitry Torokhov 	error = i8042_controller_init();
1533de9ce703SDmitry Torokhov 	if (error)
1534de9ce703SDmitry Torokhov 		return error;
15351da177e4SLinus Torvalds 
1536d35895dbSBruno Prémont #ifdef CONFIG_X86
1537d35895dbSBruno Prémont 	if (i8042_dritek)
1538d35895dbSBruno Prémont 		i8042_dritek_enable();
1539d35895dbSBruno Prémont #endif
1540d35895dbSBruno Prémont 
1541de9ce703SDmitry Torokhov 	if (!i8042_noaux) {
1542de9ce703SDmitry Torokhov 		error = i8042_setup_aux();
1543de9ce703SDmitry Torokhov 		if (error && error != -ENODEV && error != -EBUSY)
1544de9ce703SDmitry Torokhov 			goto out_fail;
15451da177e4SLinus Torvalds 	}
15461da177e4SLinus Torvalds 
1547945ef0d4SDmitry Torokhov 	if (!i8042_nokbd) {
1548de9ce703SDmitry Torokhov 		error = i8042_setup_kbd();
1549de9ce703SDmitry Torokhov 		if (error)
1550de9ce703SDmitry Torokhov 			goto out_fail;
1551945ef0d4SDmitry Torokhov 	}
1552de9ce703SDmitry Torokhov /*
1553de9ce703SDmitry Torokhov  * Ok, everything is ready, let's register all serio ports
1554de9ce703SDmitry Torokhov  */
1555de9ce703SDmitry Torokhov 	i8042_register_ports();
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds 	return 0;
15580854e52dSDmitry Torokhov 
1559de9ce703SDmitry Torokhov  out_fail:
1560de9ce703SDmitry Torokhov 	i8042_free_aux_ports();	/* in case KBD failed but AUX not */
1561de9ce703SDmitry Torokhov 	i8042_free_irqs();
15621729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
1563ec62e1c8SDmitry Torokhov 	i8042_platform_device = NULL;
15640854e52dSDmitry Torokhov 
1565de9ce703SDmitry Torokhov 	return error;
15661da177e4SLinus Torvalds }
15671da177e4SLinus Torvalds 
1568e2619cf7SBill Pemberton static int i8042_remove(struct platform_device *dev)
15691da177e4SLinus Torvalds {
1570de9ce703SDmitry Torokhov 	i8042_unregister_ports();
1571de9ce703SDmitry Torokhov 	i8042_free_irqs();
15721729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
1573ec62e1c8SDmitry Torokhov 	i8042_platform_device = NULL;
15741da177e4SLinus Torvalds 
157587fd6318SDmitry Torokhov 	return 0;
157687fd6318SDmitry Torokhov }
157787fd6318SDmitry Torokhov 
157887fd6318SDmitry Torokhov static struct platform_driver i8042_driver = {
157987fd6318SDmitry Torokhov 	.driver		= {
158087fd6318SDmitry Torokhov 		.name	= "i8042",
1581ebd7768dSDmitry Torokhov #ifdef CONFIG_PM
1582ebd7768dSDmitry Torokhov 		.pm	= &i8042_pm_ops,
1583ebd7768dSDmitry Torokhov #endif
158487fd6318SDmitry Torokhov 	},
15851cb0aa88SBill Pemberton 	.remove		= i8042_remove,
158682dd9effSDmitry Torokhov 	.shutdown	= i8042_shutdown,
158787fd6318SDmitry Torokhov };
158887fd6318SDmitry Torokhov 
1589e1443d28SStephen Chandler Paul static struct notifier_block i8042_kbd_bind_notifier_block = {
1590e1443d28SStephen Chandler Paul 	.notifier_call = i8042_kbd_bind_notifier,
1591e1443d28SStephen Chandler Paul };
1592e1443d28SStephen Chandler Paul 
159387fd6318SDmitry Torokhov static int __init i8042_init(void)
159487fd6318SDmitry Torokhov {
1595ec62e1c8SDmitry Torokhov 	struct platform_device *pdev;
159687fd6318SDmitry Torokhov 	int err;
159787fd6318SDmitry Torokhov 
159887fd6318SDmitry Torokhov 	dbg_init();
159987fd6318SDmitry Torokhov 
160087fd6318SDmitry Torokhov 	err = i8042_platform_init();
160187fd6318SDmitry Torokhov 	if (err)
160287fd6318SDmitry Torokhov 		return err;
160387fd6318SDmitry Torokhov 
1604de9ce703SDmitry Torokhov 	err = i8042_controller_check();
1605de9ce703SDmitry Torokhov 	if (err)
1606de9ce703SDmitry Torokhov 		goto err_platform_exit;
160787fd6318SDmitry Torokhov 
1608ec62e1c8SDmitry Torokhov 	pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
1609ec62e1c8SDmitry Torokhov 	if (IS_ERR(pdev)) {
1610ec62e1c8SDmitry Torokhov 		err = PTR_ERR(pdev);
1611f8113416SDmitry Torokhov 		goto err_platform_exit;
161287fd6318SDmitry Torokhov 	}
161387fd6318SDmitry Torokhov 
1614e1443d28SStephen Chandler Paul 	bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block);
1615de9ce703SDmitry Torokhov 	panic_blink = i8042_panic_blink;
1616de9ce703SDmitry Torokhov 
161787fd6318SDmitry Torokhov 	return 0;
161887fd6318SDmitry Torokhov 
161987fd6318SDmitry Torokhov  err_platform_exit:
162087fd6318SDmitry Torokhov 	i8042_platform_exit();
162187fd6318SDmitry Torokhov 	return err;
162287fd6318SDmitry Torokhov }
162387fd6318SDmitry Torokhov 
162487fd6318SDmitry Torokhov static void __exit i8042_exit(void)
162587fd6318SDmitry Torokhov {
1626f8113416SDmitry Torokhov 	platform_device_unregister(i8042_platform_device);
1627af045b86SDmitry Torokhov 	platform_driver_unregister(&i8042_driver);
16281da177e4SLinus Torvalds 	i8042_platform_exit();
16291da177e4SLinus Torvalds 
1630e1443d28SStephen Chandler Paul 	bus_unregister_notifier(&serio_bus, &i8042_kbd_bind_notifier_block);
16311da177e4SLinus Torvalds 	panic_blink = NULL;
16321da177e4SLinus Torvalds }
16331da177e4SLinus Torvalds 
16341da177e4SLinus Torvalds module_init(i8042_init);
16351da177e4SLinus Torvalds module_exit(i8042_exit);
1636