xref: /linux/drivers/input/serio/i8042.c (revision f13b2065de8147a1652b830ea5db961cf80c09df)
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>
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #include <asm/io.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
311da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
321da177e4SLinus Torvalds MODULE_LICENSE("GPL");
331da177e4SLinus Torvalds 
34386b3849SDmitry Torokhov static bool i8042_nokbd;
35945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0);
36945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
37945ef0d4SDmitry Torokhov 
38386b3849SDmitry Torokhov static bool i8042_noaux;
391da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0);
401da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
411da177e4SLinus Torvalds 
42e55a3366SDmitry Torokhov static bool i8042_nomux;
431da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0);
442c860a11SDominik Brodowski MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing controller is present.");
451da177e4SLinus Torvalds 
46386b3849SDmitry Torokhov static bool i8042_unlock;
471da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0);
481da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
491da177e4SLinus Torvalds 
50386b3849SDmitry Torokhov static bool i8042_reset;
511da177e4SLinus Torvalds module_param_named(reset, i8042_reset, bool, 0);
521da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
531da177e4SLinus Torvalds 
54386b3849SDmitry Torokhov static bool i8042_direct;
551da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0);
561da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode.");
571da177e4SLinus Torvalds 
58386b3849SDmitry Torokhov static bool i8042_dumbkbd;
591da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
601da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
611da177e4SLinus Torvalds 
62386b3849SDmitry Torokhov static bool i8042_noloop;
631da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0);
641da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
651da177e4SLinus Torvalds 
66f8313ef1SJiri Kosina static bool i8042_notimeout;
67f8313ef1SJiri Kosina module_param_named(notimeout, i8042_notimeout, bool, 0);
68f8313ef1SJiri Kosina MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042");
69f8313ef1SJiri Kosina 
70148e9a71SSrihari Vijayaraghavan static bool i8042_kbdreset;
71148e9a71SSrihari Vijayaraghavan module_param_named(kbdreset, i8042_kbdreset, bool, 0);
72148e9a71SSrihari Vijayaraghavan MODULE_PARM_DESC(kbdreset, "Reset device connected to KBD port");
73148e9a71SSrihari Vijayaraghavan 
748987fec0SCarlos Corbacho #ifdef CONFIG_X86
75386b3849SDmitry Torokhov static bool i8042_dritek;
768987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0);
778987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension");
788987fec0SCarlos Corbacho #endif
798987fec0SCarlos Corbacho 
801da177e4SLinus Torvalds #ifdef CONFIG_PNP
81386b3849SDmitry Torokhov static bool i8042_nopnp;
821da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0);
831da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
841da177e4SLinus Torvalds #endif
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds #define DEBUG
871da177e4SLinus Torvalds #ifdef DEBUG
88386b3849SDmitry Torokhov static bool i8042_debug;
891da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600);
901da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
911da177e4SLinus Torvalds #endif
921da177e4SLinus Torvalds 
931c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test;
94a7c5868cSHans de Goede static char i8042_kbd_firmware_id[128];
95a7c5868cSHans de Goede static char i8042_aux_firmware_id[128];
961c7827aeSDmitry Torokhov 
971da177e4SLinus Torvalds #include "i8042.h"
981da177e4SLinus Torvalds 
99181d683dSDmitry Torokhov /*
100181d683dSDmitry Torokhov  * i8042_lock protects serialization between i8042_command and
101181d683dSDmitry Torokhov  * the interrupt handler.
102181d683dSDmitry Torokhov  */
1031da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock);
1041da177e4SLinus Torvalds 
105181d683dSDmitry Torokhov /*
106181d683dSDmitry Torokhov  * Writers to AUX and KBD ports as well as users issuing i8042_command
107181d683dSDmitry Torokhov  * directly should acquire i8042_mutex (by means of calling
108181d683dSDmitry Torokhov  * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that
109181d683dSDmitry Torokhov  * they do not disturb each other (unfortunately in many i8042
110181d683dSDmitry Torokhov  * implementations write to one of the ports will immediately abort
111181d683dSDmitry Torokhov  * command that is being processed by another port).
112181d683dSDmitry Torokhov  */
113181d683dSDmitry Torokhov static DEFINE_MUTEX(i8042_mutex);
114181d683dSDmitry Torokhov 
1151da177e4SLinus Torvalds struct i8042_port {
1161da177e4SLinus Torvalds 	struct serio *serio;
1171da177e4SLinus Torvalds 	int irq;
118386b3849SDmitry Torokhov 	bool exists;
1191da177e4SLinus Torvalds 	signed char mux;
1201da177e4SLinus Torvalds };
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds #define I8042_KBD_PORT_NO	0
1231da177e4SLinus Torvalds #define I8042_AUX_PORT_NO	1
1241da177e4SLinus Torvalds #define I8042_MUX_PORT_NO	2
1251da177e4SLinus Torvalds #define I8042_NUM_PORTS		(I8042_NUM_MUX_PORTS + 2)
126de9ce703SDmitry Torokhov 
127de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS];
1281da177e4SLinus Torvalds 
1291da177e4SLinus Torvalds static unsigned char i8042_initial_ctr;
1301da177e4SLinus Torvalds static unsigned char i8042_ctr;
131386b3849SDmitry Torokhov static bool i8042_mux_present;
132386b3849SDmitry Torokhov static bool i8042_kbd_irq_registered;
133386b3849SDmitry Torokhov static bool i8042_aux_irq_registered;
134817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack;
1351da177e4SLinus Torvalds static struct platform_device *i8042_platform_device;
1361da177e4SLinus Torvalds 
1377d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id);
138967c9ef9SMatthew Garrett static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
139967c9ef9SMatthew Garrett 				     struct serio *serio);
1401da177e4SLinus Torvalds 
141181d683dSDmitry Torokhov void i8042_lock_chip(void)
142181d683dSDmitry Torokhov {
143181d683dSDmitry Torokhov 	mutex_lock(&i8042_mutex);
144181d683dSDmitry Torokhov }
145181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip);
146181d683dSDmitry Torokhov 
147181d683dSDmitry Torokhov void i8042_unlock_chip(void)
148181d683dSDmitry Torokhov {
149181d683dSDmitry Torokhov 	mutex_unlock(&i8042_mutex);
150181d683dSDmitry Torokhov }
151181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip);
152181d683dSDmitry Torokhov 
153967c9ef9SMatthew Garrett int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
154967c9ef9SMatthew Garrett 					struct serio *serio))
155967c9ef9SMatthew Garrett {
156967c9ef9SMatthew Garrett 	unsigned long flags;
157967c9ef9SMatthew Garrett 	int ret = 0;
158967c9ef9SMatthew Garrett 
159967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
160967c9ef9SMatthew Garrett 
161967c9ef9SMatthew Garrett 	if (i8042_platform_filter) {
162967c9ef9SMatthew Garrett 		ret = -EBUSY;
163967c9ef9SMatthew Garrett 		goto out;
164967c9ef9SMatthew Garrett 	}
165967c9ef9SMatthew Garrett 
166967c9ef9SMatthew Garrett 	i8042_platform_filter = filter;
167967c9ef9SMatthew Garrett 
168967c9ef9SMatthew Garrett out:
169967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
170967c9ef9SMatthew Garrett 	return ret;
171967c9ef9SMatthew Garrett }
172967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_install_filter);
173967c9ef9SMatthew Garrett 
174967c9ef9SMatthew Garrett int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
175967c9ef9SMatthew Garrett 				       struct serio *port))
176967c9ef9SMatthew Garrett {
177967c9ef9SMatthew Garrett 	unsigned long flags;
178967c9ef9SMatthew Garrett 	int ret = 0;
179967c9ef9SMatthew Garrett 
180967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
181967c9ef9SMatthew Garrett 
182967c9ef9SMatthew Garrett 	if (i8042_platform_filter != filter) {
183967c9ef9SMatthew Garrett 		ret = -EINVAL;
184967c9ef9SMatthew Garrett 		goto out;
185967c9ef9SMatthew Garrett 	}
186967c9ef9SMatthew Garrett 
187967c9ef9SMatthew Garrett 	i8042_platform_filter = NULL;
188967c9ef9SMatthew Garrett 
189967c9ef9SMatthew Garrett out:
190967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
191967c9ef9SMatthew Garrett 	return ret;
192967c9ef9SMatthew Garrett }
193967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_remove_filter);
194967c9ef9SMatthew Garrett 
1951da177e4SLinus Torvalds /*
1961da177e4SLinus Torvalds  * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
1971da177e4SLinus Torvalds  * be ready for reading values from it / writing values to it.
1981da177e4SLinus Torvalds  * Called always with i8042_lock held.
1991da177e4SLinus Torvalds  */
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds static int i8042_wait_read(void)
2021da177e4SLinus Torvalds {
2031da177e4SLinus Torvalds 	int i = 0;
204de9ce703SDmitry Torokhov 
2051da177e4SLinus Torvalds 	while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
2061da177e4SLinus Torvalds 		udelay(50);
2071da177e4SLinus Torvalds 		i++;
2081da177e4SLinus Torvalds 	}
2091da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds static int i8042_wait_write(void)
2131da177e4SLinus Torvalds {
2141da177e4SLinus Torvalds 	int i = 0;
215de9ce703SDmitry Torokhov 
2161da177e4SLinus Torvalds 	while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
2171da177e4SLinus Torvalds 		udelay(50);
2181da177e4SLinus Torvalds 		i++;
2191da177e4SLinus Torvalds 	}
2201da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds /*
2241da177e4SLinus Torvalds  * i8042_flush() flushes all data that may be in the keyboard and mouse buffers
2251da177e4SLinus Torvalds  * of the i8042 down the toilet.
2261da177e4SLinus Torvalds  */
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds static int i8042_flush(void)
2291da177e4SLinus Torvalds {
2301da177e4SLinus Torvalds 	unsigned long flags;
2311da177e4SLinus Torvalds 	unsigned char data, str;
2322f0d2604SAndrey Moiseev 	int count = 0;
2332f0d2604SAndrey Moiseev 	int retval = 0;
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
2361da177e4SLinus Torvalds 
2372f0d2604SAndrey Moiseev 	while ((str = i8042_read_status()) & I8042_STR_OBF) {
2382f0d2604SAndrey Moiseev 		if (count++ < I8042_BUFFER_SIZE) {
2391da177e4SLinus Torvalds 			udelay(50);
2401da177e4SLinus Torvalds 			data = i8042_read_data();
2414eb3c30bSJoe Perches 			dbg("%02x <- i8042 (flush, %s)\n",
2424eb3c30bSJoe Perches 			    data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
2432f0d2604SAndrey Moiseev 		} else {
2442f0d2604SAndrey Moiseev 			retval = -EIO;
2452f0d2604SAndrey Moiseev 			break;
2462f0d2604SAndrey Moiseev 		}
2471da177e4SLinus Torvalds 	}
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
2501da177e4SLinus Torvalds 
2512f0d2604SAndrey Moiseev 	return retval;
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds /*
2551da177e4SLinus Torvalds  * i8042_command() executes a command on the i8042. It also sends the input
2561da177e4SLinus Torvalds  * parameter(s) of the commands to it, and receives the output value(s). The
2571da177e4SLinus Torvalds  * parameters are to be stored in the param array, and the output is placed
2581da177e4SLinus Torvalds  * into the same array. The number of the parameters and output values is
2591da177e4SLinus Torvalds  * encoded in bits 8-11 of the command number.
2601da177e4SLinus Torvalds  */
2611da177e4SLinus Torvalds 
262de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command)
2631da177e4SLinus Torvalds {
264de9ce703SDmitry Torokhov 	int i, error;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
2671da177e4SLinus Torvalds 		return -1;
2681da177e4SLinus Torvalds 
269de9ce703SDmitry Torokhov 	error = i8042_wait_write();
270de9ce703SDmitry Torokhov 	if (error)
271de9ce703SDmitry Torokhov 		return error;
272463a4f76SDmitry Torokhov 
2734eb3c30bSJoe Perches 	dbg("%02x -> i8042 (command)\n", command & 0xff);
2741da177e4SLinus Torvalds 	i8042_write_command(command & 0xff);
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 12) & 0xf); i++) {
277de9ce703SDmitry Torokhov 		error = i8042_wait_write();
278de9ce703SDmitry Torokhov 		if (error)
279de9ce703SDmitry Torokhov 			return error;
2804eb3c30bSJoe Perches 		dbg("%02x -> i8042 (parameter)\n", param[i]);
2811da177e4SLinus Torvalds 		i8042_write_data(param[i]);
2821da177e4SLinus Torvalds 	}
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 8) & 0xf); i++) {
285de9ce703SDmitry Torokhov 		error = i8042_wait_read();
286de9ce703SDmitry Torokhov 		if (error) {
2874eb3c30bSJoe Perches 			dbg("     -- i8042 (timeout)\n");
288de9ce703SDmitry Torokhov 			return error;
289de9ce703SDmitry Torokhov 		}
290463a4f76SDmitry Torokhov 
291463a4f76SDmitry Torokhov 		if (command == I8042_CMD_AUX_LOOP &&
292463a4f76SDmitry Torokhov 		    !(i8042_read_status() & I8042_STR_AUXDATA)) {
2934eb3c30bSJoe Perches 			dbg("     -- i8042 (auxerr)\n");
294de9ce703SDmitry Torokhov 			return -1;
295463a4f76SDmitry Torokhov 		}
296463a4f76SDmitry Torokhov 
2971da177e4SLinus Torvalds 		param[i] = i8042_read_data();
2984eb3c30bSJoe Perches 		dbg("%02x <- i8042 (return)\n", param[i]);
2991da177e4SLinus Torvalds 	}
3001da177e4SLinus Torvalds 
301de9ce703SDmitry Torokhov 	return 0;
302de9ce703SDmitry Torokhov }
3031da177e4SLinus Torvalds 
304553a05b8SMárton Németh int i8042_command(unsigned char *param, int command)
305de9ce703SDmitry Torokhov {
306de9ce703SDmitry Torokhov 	unsigned long flags;
307de9ce703SDmitry Torokhov 	int retval;
308de9ce703SDmitry Torokhov 
309de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
310de9ce703SDmitry Torokhov 	retval = __i8042_command(param, command);
311463a4f76SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
312de9ce703SDmitry Torokhov 
3131da177e4SLinus Torvalds 	return retval;
3141da177e4SLinus Torvalds }
315553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command);
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds /*
3181da177e4SLinus Torvalds  * i8042_kbd_write() sends a byte out through the keyboard interface.
3191da177e4SLinus Torvalds  */
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds 	unsigned long flags;
3241da177e4SLinus Torvalds 	int retval = 0;
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 	if (!(retval = i8042_wait_write())) {
3294eb3c30bSJoe Perches 		dbg("%02x -> i8042 (kbd-data)\n", c);
3301da177e4SLinus Torvalds 		i8042_write_data(c);
3311da177e4SLinus Torvalds 	}
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	return retval;
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds /*
3391da177e4SLinus Torvalds  * i8042_aux_write() sends a byte out through the aux interface.
3401da177e4SLinus Torvalds  */
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c)
3431da177e4SLinus Torvalds {
3441da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3451da177e4SLinus Torvalds 
346f4e3c711SDmitry Torokhov 	return i8042_command(&c, port->mux == -1 ?
347f4e3c711SDmitry Torokhov 					I8042_CMD_AUX_SEND :
348f4e3c711SDmitry Torokhov 					I8042_CMD_MUX_SEND + port->mux);
3491da177e4SLinus Torvalds }
3501da177e4SLinus Torvalds 
3515ddbc77cSDmitry Torokhov 
3525ddbc77cSDmitry Torokhov /*
3535ddbc77cSDmitry Torokhov  * i8042_aux_close attempts to clear AUX or KBD port state by disabling
3545ddbc77cSDmitry Torokhov  * and then re-enabling it.
3555ddbc77cSDmitry Torokhov  */
3565ddbc77cSDmitry Torokhov 
3575ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio)
3585ddbc77cSDmitry Torokhov {
3595ddbc77cSDmitry Torokhov 	int irq_bit;
3605ddbc77cSDmitry Torokhov 	int disable_bit;
3615ddbc77cSDmitry Torokhov 	const char *port_name;
3625ddbc77cSDmitry Torokhov 
3635ddbc77cSDmitry Torokhov 	if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) {
3645ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_AUXINT;
3655ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_AUXDIS;
3665ddbc77cSDmitry Torokhov 		port_name = "AUX";
3675ddbc77cSDmitry Torokhov 	} else {
3685ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_KBDINT;
3695ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_KBDDIS;
3705ddbc77cSDmitry Torokhov 		port_name = "KBD";
3715ddbc77cSDmitry Torokhov 	}
3725ddbc77cSDmitry Torokhov 
3735ddbc77cSDmitry Torokhov 	i8042_ctr &= ~irq_bit;
3745ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
3754eb3c30bSJoe Perches 		pr_warn("Can't write CTR while closing %s port\n", port_name);
3765ddbc77cSDmitry Torokhov 
3775ddbc77cSDmitry Torokhov 	udelay(50);
3785ddbc77cSDmitry Torokhov 
3795ddbc77cSDmitry Torokhov 	i8042_ctr &= ~disable_bit;
3805ddbc77cSDmitry Torokhov 	i8042_ctr |= irq_bit;
3815ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
3824eb3c30bSJoe Perches 		pr_err("Can't reactivate %s port\n", port_name);
3835ddbc77cSDmitry Torokhov 
3845ddbc77cSDmitry Torokhov 	/*
3855ddbc77cSDmitry Torokhov 	 * See if there is any data appeared while we were messing with
3865ddbc77cSDmitry Torokhov 	 * port state.
3875ddbc77cSDmitry Torokhov 	 */
3885ddbc77cSDmitry Torokhov 	i8042_interrupt(0, NULL);
3895ddbc77cSDmitry Torokhov }
3905ddbc77cSDmitry Torokhov 
3911da177e4SLinus Torvalds /*
3921da177e4SLinus Torvalds  * i8042_start() is called by serio core when port is about to finish
3931da177e4SLinus Torvalds  * registering. It will mark port as existing so i8042_interrupt can
3941da177e4SLinus Torvalds  * start sending data through it.
3951da177e4SLinus Torvalds  */
3961da177e4SLinus Torvalds static int i8042_start(struct serio *serio)
3971da177e4SLinus Torvalds {
3981da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3991da177e4SLinus Torvalds 
400386b3849SDmitry Torokhov 	port->exists = true;
4011da177e4SLinus Torvalds 	mb();
4021da177e4SLinus Torvalds 	return 0;
4031da177e4SLinus Torvalds }
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds /*
4061da177e4SLinus Torvalds  * i8042_stop() marks serio port as non-existing so i8042_interrupt
4071da177e4SLinus Torvalds  * will not try to send data to the port that is about to go away.
4081da177e4SLinus Torvalds  * The function is called by serio core as part of unregister procedure.
4091da177e4SLinus Torvalds  */
4101da177e4SLinus Torvalds static void i8042_stop(struct serio *serio)
4111da177e4SLinus Torvalds {
4121da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
4131da177e4SLinus Torvalds 
414386b3849SDmitry Torokhov 	port->exists = false;
415a8399c51SDmitry Torokhov 
416a8399c51SDmitry Torokhov 	/*
417a8399c51SDmitry Torokhov 	 * We synchronize with both AUX and KBD IRQs because there is
418a8399c51SDmitry Torokhov 	 * a (very unlikely) chance that AUX IRQ is raised for KBD port
419a8399c51SDmitry Torokhov 	 * and vice versa.
420a8399c51SDmitry Torokhov 	 */
421a8399c51SDmitry Torokhov 	synchronize_irq(I8042_AUX_IRQ);
422a8399c51SDmitry Torokhov 	synchronize_irq(I8042_KBD_IRQ);
4231da177e4SLinus Torvalds 	port->serio = NULL;
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds /*
4274e8d340dSDmitry Torokhov  * i8042_filter() filters out unwanted bytes from the input data stream.
4284e8d340dSDmitry Torokhov  * It is called from i8042_interrupt and thus is running with interrupts
4294e8d340dSDmitry Torokhov  * off and i8042_lock held.
4304e8d340dSDmitry Torokhov  */
431967c9ef9SMatthew Garrett static bool i8042_filter(unsigned char data, unsigned char str,
432967c9ef9SMatthew Garrett 			 struct serio *serio)
4334e8d340dSDmitry Torokhov {
4344e8d340dSDmitry Torokhov 	if (unlikely(i8042_suppress_kbd_ack)) {
4354e8d340dSDmitry Torokhov 		if ((~str & I8042_STR_AUXDATA) &&
4364e8d340dSDmitry Torokhov 		    (data == 0xfa || data == 0xfe)) {
4374e8d340dSDmitry Torokhov 			i8042_suppress_kbd_ack--;
4384e8d340dSDmitry Torokhov 			dbg("Extra keyboard ACK - filtered out\n");
4394e8d340dSDmitry Torokhov 			return true;
4404e8d340dSDmitry Torokhov 		}
4414e8d340dSDmitry Torokhov 	}
4424e8d340dSDmitry Torokhov 
443967c9ef9SMatthew Garrett 	if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
4440747e3bcSStefan Weil 		dbg("Filtered out by platform filter\n");
445967c9ef9SMatthew Garrett 		return true;
446967c9ef9SMatthew Garrett 	}
447967c9ef9SMatthew Garrett 
4484e8d340dSDmitry Torokhov 	return false;
4494e8d340dSDmitry Torokhov }
4504e8d340dSDmitry Torokhov 
4514e8d340dSDmitry Torokhov /*
4521da177e4SLinus Torvalds  * i8042_interrupt() is the most important function in this driver -
4531da177e4SLinus Torvalds  * it handles the interrupts from the i8042, and sends incoming bytes
4541da177e4SLinus Torvalds  * to the upper layers.
4551da177e4SLinus Torvalds  */
4561da177e4SLinus Torvalds 
4577d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id)
4581da177e4SLinus Torvalds {
4591da177e4SLinus Torvalds 	struct i8042_port *port;
460967c9ef9SMatthew Garrett 	struct serio *serio;
4611da177e4SLinus Torvalds 	unsigned long flags;
4621da177e4SLinus Torvalds 	unsigned char str, data;
4631da177e4SLinus Torvalds 	unsigned int dfl;
4641da177e4SLinus Torvalds 	unsigned int port_no;
4654e8d340dSDmitry Torokhov 	bool filtered;
466817e6ba3SDmitry Torokhov 	int ret = 1;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
4694e8d340dSDmitry Torokhov 
4701da177e4SLinus Torvalds 	str = i8042_read_status();
4711da177e4SLinus Torvalds 	if (unlikely(~str & I8042_STR_OBF)) {
4721da177e4SLinus Torvalds 		spin_unlock_irqrestore(&i8042_lock, flags);
4734eb3c30bSJoe Perches 		if (irq)
4744eb3c30bSJoe Perches 			dbg("Interrupt %d, without any data\n", irq);
4751da177e4SLinus Torvalds 		ret = 0;
4761da177e4SLinus Torvalds 		goto out;
4771da177e4SLinus Torvalds 	}
4784e8d340dSDmitry Torokhov 
4791da177e4SLinus Torvalds 	data = i8042_read_data();
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 	if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
4821da177e4SLinus Torvalds 		static unsigned long last_transmit;
4831da177e4SLinus Torvalds 		static unsigned char last_str;
4841da177e4SLinus Torvalds 
4851da177e4SLinus Torvalds 		dfl = 0;
4861da177e4SLinus Torvalds 		if (str & I8042_STR_MUXERR) {
4874eb3c30bSJoe Perches 			dbg("MUX error, status is %02x, data is %02x\n",
4884eb3c30bSJoe Perches 			    str, data);
4891da177e4SLinus Torvalds /*
4901da177e4SLinus Torvalds  * When MUXERR condition is signalled the data register can only contain
4911da177e4SLinus Torvalds  * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
492a216a4b6SDmitry Torokhov  * it is not always the case. Some KBCs also report 0xfc when there is
493a216a4b6SDmitry Torokhov  * nothing connected to the port while others sometimes get confused which
494a216a4b6SDmitry Torokhov  * port the data came from and signal error leaving the data intact. They
495a216a4b6SDmitry Torokhov  * _do not_ revert to legacy mode (actually I've never seen KBC reverting
496a216a4b6SDmitry Torokhov  * to legacy mode yet, when we see one we'll add proper handling).
497a216a4b6SDmitry Torokhov  * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the
498a216a4b6SDmitry Torokhov  * rest assume that the data came from the same serio last byte
4991da177e4SLinus Torvalds  * was transmitted (if transmission happened not too long ago).
5001da177e4SLinus Torvalds  */
501a216a4b6SDmitry Torokhov 
502a216a4b6SDmitry Torokhov 			switch (data) {
503a216a4b6SDmitry Torokhov 				default:
5041da177e4SLinus Torvalds 					if (time_before(jiffies, last_transmit + HZ/10)) {
5051da177e4SLinus Torvalds 						str = last_str;
5061da177e4SLinus Torvalds 						break;
5071da177e4SLinus Torvalds 					}
5081da177e4SLinus Torvalds 					/* fall through - report timeout */
509a216a4b6SDmitry Torokhov 				case 0xfc:
5101da177e4SLinus Torvalds 				case 0xfd:
5111da177e4SLinus Torvalds 				case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
5121da177e4SLinus Torvalds 				case 0xff: dfl = SERIO_PARITY;  data = 0xfe; break;
5131da177e4SLinus Torvalds 			}
5141da177e4SLinus Torvalds 		}
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds 		port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
5171da177e4SLinus Torvalds 		last_str = str;
5181da177e4SLinus Torvalds 		last_transmit = jiffies;
5191da177e4SLinus Torvalds 	} else {
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
522f8313ef1SJiri Kosina 		      ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0);
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 		port_no = (str & I8042_STR_AUXDATA) ?
5251da177e4SLinus Torvalds 				I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
5261da177e4SLinus Torvalds 	}
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 	port = &i8042_ports[port_no];
529967c9ef9SMatthew Garrett 	serio = port->exists ? port->serio : NULL;
5301da177e4SLinus Torvalds 
5314eb3c30bSJoe Perches 	dbg("%02x <- i8042 (interrupt, %d, %d%s%s)\n",
532de9ce703SDmitry Torokhov 	    data, port_no, irq,
5331da177e4SLinus Torvalds 	    dfl & SERIO_PARITY ? ", bad parity" : "",
5341da177e4SLinus Torvalds 	    dfl & SERIO_TIMEOUT ? ", timeout" : "");
5351da177e4SLinus Torvalds 
536967c9ef9SMatthew Garrett 	filtered = i8042_filter(data, str, serio);
537817e6ba3SDmitry Torokhov 
5384e8d340dSDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
5394e8d340dSDmitry Torokhov 
5404e8d340dSDmitry Torokhov 	if (likely(port->exists && !filtered))
541967c9ef9SMatthew Garrett 		serio_interrupt(serio, data, dfl);
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds  out:
5441da177e4SLinus Torvalds 	return IRQ_RETVAL(ret);
5451da177e4SLinus Torvalds }
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds /*
5485ddbc77cSDmitry Torokhov  * i8042_enable_kbd_port enables keyboard port on chip
549de9ce703SDmitry Torokhov  */
550de9ce703SDmitry Torokhov 
551de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void)
552de9ce703SDmitry Torokhov {
553de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_KBDDIS;
554de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDINT;
555de9ce703SDmitry Torokhov 
556de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
557018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_KBDINT;
558018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_KBDDIS;
5594eb3c30bSJoe Perches 		pr_err("Failed to enable KBD port\n");
560de9ce703SDmitry Torokhov 		return -EIO;
561de9ce703SDmitry Torokhov 	}
562de9ce703SDmitry Torokhov 
563de9ce703SDmitry Torokhov 	return 0;
564de9ce703SDmitry Torokhov }
565de9ce703SDmitry Torokhov 
566de9ce703SDmitry Torokhov /*
567de9ce703SDmitry Torokhov  * i8042_enable_aux_port enables AUX (mouse) port on chip
568de9ce703SDmitry Torokhov  */
569de9ce703SDmitry Torokhov 
570de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void)
571de9ce703SDmitry Torokhov {
572de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXDIS;
573de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXINT;
574de9ce703SDmitry Torokhov 
575de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
576018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_AUXINT;
577018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_AUXDIS;
5784eb3c30bSJoe Perches 		pr_err("Failed to enable AUX port\n");
579de9ce703SDmitry Torokhov 		return -EIO;
580de9ce703SDmitry Torokhov 	}
581de9ce703SDmitry Torokhov 
582de9ce703SDmitry Torokhov 	return 0;
583de9ce703SDmitry Torokhov }
584de9ce703SDmitry Torokhov 
585de9ce703SDmitry Torokhov /*
586de9ce703SDmitry Torokhov  * i8042_enable_mux_ports enables 4 individual AUX ports after
587de9ce703SDmitry Torokhov  * the controller has been switched into Multiplexed mode
588de9ce703SDmitry Torokhov  */
589de9ce703SDmitry Torokhov 
590de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void)
591de9ce703SDmitry Torokhov {
592de9ce703SDmitry Torokhov 	unsigned char param;
593de9ce703SDmitry Torokhov 	int i;
594de9ce703SDmitry Torokhov 
595de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
596de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_MUX_PFX + i);
597de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_AUX_ENABLE);
598de9ce703SDmitry Torokhov 	}
599de9ce703SDmitry Torokhov 
600de9ce703SDmitry Torokhov 	return i8042_enable_aux_port();
601de9ce703SDmitry Torokhov }
602de9ce703SDmitry Torokhov 
603de9ce703SDmitry Torokhov /*
604386b3849SDmitry Torokhov  * i8042_set_mux_mode checks whether the controller has an
605386b3849SDmitry Torokhov  * active multiplexor and puts the chip into Multiplexed (true)
606386b3849SDmitry Torokhov  * or Legacy (false) mode.
6071da177e4SLinus Torvalds  */
6081da177e4SLinus Torvalds 
609386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version)
6101da177e4SLinus Torvalds {
6111da177e4SLinus Torvalds 
612386b3849SDmitry Torokhov 	unsigned char param, val;
6131da177e4SLinus Torvalds /*
6141da177e4SLinus Torvalds  * Get rid of bytes in the queue.
6151da177e4SLinus Torvalds  */
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds 	i8042_flush();
6181da177e4SLinus Torvalds 
6191da177e4SLinus Torvalds /*
6201da177e4SLinus Torvalds  * Internal loopback test - send three bytes, they should come back from the
621de9ce703SDmitry Torokhov  * mouse interface, the last should be version.
6221da177e4SLinus Torvalds  */
6231da177e4SLinus Torvalds 
624386b3849SDmitry Torokhov 	param = val = 0xf0;
625386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6261da177e4SLinus Torvalds 		return -1;
627386b3849SDmitry Torokhov 	param = val = multiplex ? 0x56 : 0xf6;
628386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6291da177e4SLinus Torvalds 		return -1;
630386b3849SDmitry Torokhov 	param = val = multiplex ? 0xa4 : 0xa5;
631386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == val)
632386b3849SDmitry Torokhov 		return -1;
633386b3849SDmitry Torokhov 
634386b3849SDmitry Torokhov /*
635386b3849SDmitry Torokhov  * Workaround for interference with USB Legacy emulation
636386b3849SDmitry Torokhov  * that causes a v10.12 MUX to be found.
637386b3849SDmitry Torokhov  */
638386b3849SDmitry Torokhov 	if (param == 0xac)
6391da177e4SLinus Torvalds 		return -1;
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds 	if (mux_version)
642463a4f76SDmitry Torokhov 		*mux_version = param;
6431da177e4SLinus Torvalds 
6441da177e4SLinus Torvalds 	return 0;
6451da177e4SLinus Torvalds }
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds /*
6481da177e4SLinus Torvalds  * i8042_check_mux() checks whether the controller supports the PS/2 Active
6491da177e4SLinus Torvalds  * Multiplexing specification by Synaptics, Phoenix, Insyde and
6501da177e4SLinus Torvalds  * LCS/Telegraphics.
6511da177e4SLinus Torvalds  */
6521da177e4SLinus Torvalds 
653f8113416SDmitry Torokhov static int __init i8042_check_mux(void)
6541da177e4SLinus Torvalds {
6551da177e4SLinus Torvalds 	unsigned char mux_version;
6561da177e4SLinus Torvalds 
657386b3849SDmitry Torokhov 	if (i8042_set_mux_mode(true, &mux_version))
6581da177e4SLinus Torvalds 		return -1;
6591da177e4SLinus Torvalds 
6604eb3c30bSJoe Perches 	pr_info("Detected active multiplexing controller, rev %d.%d\n",
6611da177e4SLinus Torvalds 		(mux_version >> 4) & 0xf, mux_version & 0xf);
6621da177e4SLinus Torvalds 
663de9ce703SDmitry Torokhov /*
664de9ce703SDmitry Torokhov  * Disable all muxed ports by disabling AUX.
665de9ce703SDmitry Torokhov  */
666de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS;
667de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXINT;
668de9ce703SDmitry Torokhov 
669de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
6704eb3c30bSJoe Perches 		pr_err("Failed to disable AUX port, can't use MUX\n");
671de9ce703SDmitry Torokhov 		return -EIO;
672de9ce703SDmitry Torokhov 	}
6731da177e4SLinus Torvalds 
674386b3849SDmitry Torokhov 	i8042_mux_present = true;
675de9ce703SDmitry Torokhov 
6761da177e4SLinus Torvalds 	return 0;
6771da177e4SLinus Torvalds }
6781da177e4SLinus Torvalds 
679de9ce703SDmitry Torokhov /*
680de9ce703SDmitry Torokhov  * The following is used to test AUX IRQ delivery.
681de9ce703SDmitry Torokhov  */
682f8113416SDmitry Torokhov static struct completion i8042_aux_irq_delivered __initdata;
683f8113416SDmitry Torokhov static bool i8042_irq_being_tested __initdata;
684de9ce703SDmitry Torokhov 
685f8113416SDmitry Torokhov static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
686de9ce703SDmitry Torokhov {
687de9ce703SDmitry Torokhov 	unsigned long flags;
688de9ce703SDmitry Torokhov 	unsigned char str, data;
689e3758b2aSFernando Luis Vázquez Cao 	int ret = 0;
690de9ce703SDmitry Torokhov 
691de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
692de9ce703SDmitry Torokhov 	str = i8042_read_status();
693de9ce703SDmitry Torokhov 	if (str & I8042_STR_OBF) {
694de9ce703SDmitry Torokhov 		data = i8042_read_data();
6954eb3c30bSJoe Perches 		dbg("%02x <- i8042 (aux_test_irq, %s)\n",
696d3d2dfe2SDmitry Torokhov 		    data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
697de9ce703SDmitry Torokhov 		if (i8042_irq_being_tested &&
698de9ce703SDmitry Torokhov 		    data == 0xa5 && (str & I8042_STR_AUXDATA))
699de9ce703SDmitry Torokhov 			complete(&i8042_aux_irq_delivered);
700e3758b2aSFernando Luis Vázquez Cao 		ret = 1;
701de9ce703SDmitry Torokhov 	}
702de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
703de9ce703SDmitry Torokhov 
704e3758b2aSFernando Luis Vázquez Cao 	return IRQ_RETVAL(ret);
705de9ce703SDmitry Torokhov }
706de9ce703SDmitry Torokhov 
707d2ada559SRoland Scheidegger /*
708d2ada559SRoland Scheidegger  * i8042_toggle_aux - enables or disables AUX port on i8042 via command and
709d2ada559SRoland Scheidegger  * verifies success by readinng CTR. Used when testing for presence of AUX
710d2ada559SRoland Scheidegger  * port.
711d2ada559SRoland Scheidegger  */
712f8113416SDmitry Torokhov static int __init i8042_toggle_aux(bool on)
713d2ada559SRoland Scheidegger {
714d2ada559SRoland Scheidegger 	unsigned char param;
715d2ada559SRoland Scheidegger 	int i;
716d2ada559SRoland Scheidegger 
717d2ada559SRoland Scheidegger 	if (i8042_command(&param,
718d2ada559SRoland Scheidegger 			on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE))
719d2ada559SRoland Scheidegger 		return -1;
720d2ada559SRoland Scheidegger 
721d2ada559SRoland Scheidegger 	/* some chips need some time to set the I8042_CTR_AUXDIS bit */
722d2ada559SRoland Scheidegger 	for (i = 0; i < 100; i++) {
723d2ada559SRoland Scheidegger 		udelay(50);
724d2ada559SRoland Scheidegger 
725d2ada559SRoland Scheidegger 		if (i8042_command(&param, I8042_CMD_CTL_RCTR))
726d2ada559SRoland Scheidegger 			return -1;
727d2ada559SRoland Scheidegger 
728d2ada559SRoland Scheidegger 		if (!(param & I8042_CTR_AUXDIS) == on)
729d2ada559SRoland Scheidegger 			return 0;
730d2ada559SRoland Scheidegger 	}
731d2ada559SRoland Scheidegger 
732d2ada559SRoland Scheidegger 	return -1;
733d2ada559SRoland Scheidegger }
7341da177e4SLinus Torvalds 
7351da177e4SLinus Torvalds /*
7361da177e4SLinus Torvalds  * i8042_check_aux() applies as much paranoia as it can at detecting
7371da177e4SLinus Torvalds  * the presence of an AUX interface.
7381da177e4SLinus Torvalds  */
7391da177e4SLinus Torvalds 
740f8113416SDmitry Torokhov static int __init i8042_check_aux(void)
7411da177e4SLinus Torvalds {
742de9ce703SDmitry Torokhov 	int retval = -1;
743386b3849SDmitry Torokhov 	bool irq_registered = false;
744386b3849SDmitry Torokhov 	bool aux_loop_broken = false;
745de9ce703SDmitry Torokhov 	unsigned long flags;
7461da177e4SLinus Torvalds 	unsigned char param;
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds /*
7491da177e4SLinus Torvalds  * Get rid of bytes in the queue.
7501da177e4SLinus Torvalds  */
7511da177e4SLinus Torvalds 
7521da177e4SLinus Torvalds 	i8042_flush();
7531da177e4SLinus Torvalds 
7541da177e4SLinus Torvalds /*
7551da177e4SLinus Torvalds  * Internal loopback test - filters out AT-type i8042's. Unfortunately
7561da177e4SLinus Torvalds  * SiS screwed up and their 5597 doesn't support the LOOP command even
7571da177e4SLinus Torvalds  * though it has an AUX port.
7581da177e4SLinus Torvalds  */
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds 	param = 0x5a;
7613ca5de6dSDmitry Torokhov 	retval = i8042_command(&param, I8042_CMD_AUX_LOOP);
7623ca5de6dSDmitry Torokhov 	if (retval || param != 0x5a) {
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds /*
7651da177e4SLinus Torvalds  * External connection test - filters out AT-soldered PS/2 i8042's
7661da177e4SLinus Torvalds  * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error
7671da177e4SLinus Torvalds  * 0xfa - no error on some notebooks which ignore the spec
7681da177e4SLinus Torvalds  * Because it's common for chipsets to return error on perfectly functioning
7691da177e4SLinus Torvalds  * AUX ports, we test for this only when the LOOP command failed.
7701da177e4SLinus Torvalds  */
7711da177e4SLinus Torvalds 
772de9ce703SDmitry Torokhov 		if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
773de9ce703SDmitry Torokhov 		    (param && param != 0xfa && param != 0xff))
7741da177e4SLinus Torvalds 			return -1;
7751e4865f8SDmitry Torokhov 
7763ca5de6dSDmitry Torokhov /*
7773ca5de6dSDmitry Torokhov  * If AUX_LOOP completed without error but returned unexpected data
7783ca5de6dSDmitry Torokhov  * mark it as broken
7793ca5de6dSDmitry Torokhov  */
7803ca5de6dSDmitry Torokhov 		if (!retval)
781386b3849SDmitry Torokhov 			aux_loop_broken = true;
7821da177e4SLinus Torvalds 	}
7831da177e4SLinus Torvalds 
7841da177e4SLinus Torvalds /*
7851da177e4SLinus Torvalds  * Bit assignment test - filters out PS/2 i8042's in AT mode
7861da177e4SLinus Torvalds  */
7871da177e4SLinus Torvalds 
788386b3849SDmitry Torokhov 	if (i8042_toggle_aux(false)) {
7894eb3c30bSJoe Perches 		pr_warn("Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
7904eb3c30bSJoe Perches 		pr_warn("If AUX port is really absent please use the 'i8042.noaux' option\n");
7911da177e4SLinus Torvalds 	}
7921da177e4SLinus Torvalds 
793386b3849SDmitry Torokhov 	if (i8042_toggle_aux(true))
7941da177e4SLinus Torvalds 		return -1;
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds /*
797148e9a71SSrihari Vijayaraghavan  * Reset keyboard (needed on some laptops to successfully detect
798148e9a71SSrihari Vijayaraghavan  * touchpad, e.g., some Gigabyte laptop models with Elantech
799148e9a71SSrihari Vijayaraghavan  * touchpads).
800148e9a71SSrihari Vijayaraghavan  */
801148e9a71SSrihari Vijayaraghavan 	if (i8042_kbdreset) {
802148e9a71SSrihari Vijayaraghavan 		pr_warn("Attempting to reset device connected to KBD port\n");
803148e9a71SSrihari Vijayaraghavan 		i8042_kbd_write(NULL, (unsigned char) 0xff);
804148e9a71SSrihari Vijayaraghavan 	}
805148e9a71SSrihari Vijayaraghavan 
806148e9a71SSrihari Vijayaraghavan /*
807de9ce703SDmitry Torokhov  * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and
808de9ce703SDmitry Torokhov  * used it for a PCI card or somethig else.
809de9ce703SDmitry Torokhov  */
810de9ce703SDmitry Torokhov 
8111c7827aeSDmitry Torokhov 	if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) {
812de9ce703SDmitry Torokhov /*
813de9ce703SDmitry Torokhov  * Without LOOP command we can't test AUX IRQ delivery. Assume the port
814de9ce703SDmitry Torokhov  * is working and hope we are right.
815de9ce703SDmitry Torokhov  */
816de9ce703SDmitry Torokhov 		retval = 0;
817de9ce703SDmitry Torokhov 		goto out;
818de9ce703SDmitry Torokhov 	}
819de9ce703SDmitry Torokhov 
820de9ce703SDmitry Torokhov 	if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED,
821de9ce703SDmitry Torokhov 			"i8042", i8042_platform_device))
822de9ce703SDmitry Torokhov 		goto out;
823de9ce703SDmitry Torokhov 
824386b3849SDmitry Torokhov 	irq_registered = true;
825de9ce703SDmitry Torokhov 
826de9ce703SDmitry Torokhov 	if (i8042_enable_aux_port())
827de9ce703SDmitry Torokhov 		goto out;
828de9ce703SDmitry Torokhov 
829de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
830de9ce703SDmitry Torokhov 
831de9ce703SDmitry Torokhov 	init_completion(&i8042_aux_irq_delivered);
832386b3849SDmitry Torokhov 	i8042_irq_being_tested = true;
833de9ce703SDmitry Torokhov 
834de9ce703SDmitry Torokhov 	param = 0xa5;
835de9ce703SDmitry Torokhov 	retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);
836de9ce703SDmitry Torokhov 
837de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
838de9ce703SDmitry Torokhov 
839de9ce703SDmitry Torokhov 	if (retval)
840de9ce703SDmitry Torokhov 		goto out;
841de9ce703SDmitry Torokhov 
842de9ce703SDmitry Torokhov 	if (wait_for_completion_timeout(&i8042_aux_irq_delivered,
843de9ce703SDmitry Torokhov 					msecs_to_jiffies(250)) == 0) {
844de9ce703SDmitry Torokhov /*
845de9ce703SDmitry Torokhov  * AUX IRQ was never delivered so we need to flush the controller to
846de9ce703SDmitry Torokhov  * get rid of the byte we put there; otherwise keyboard may not work.
847de9ce703SDmitry Torokhov  */
8484eb3c30bSJoe Perches 		dbg("     -- i8042 (aux irq test timeout)\n");
849de9ce703SDmitry Torokhov 		i8042_flush();
850de9ce703SDmitry Torokhov 		retval = -1;
851de9ce703SDmitry Torokhov 	}
852de9ce703SDmitry Torokhov 
853de9ce703SDmitry Torokhov  out:
854de9ce703SDmitry Torokhov 
855de9ce703SDmitry Torokhov /*
8561da177e4SLinus Torvalds  * Disable the interface.
8571da177e4SLinus Torvalds  */
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_AUXDIS;
8601da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_AUXINT;
8611da177e4SLinus Torvalds 
8621da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
863de9ce703SDmitry Torokhov 		retval = -1;
864de9ce703SDmitry Torokhov 
865de9ce703SDmitry Torokhov 	if (irq_registered)
866de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
867de9ce703SDmitry Torokhov 
868de9ce703SDmitry Torokhov 	return retval;
869de9ce703SDmitry Torokhov }
870de9ce703SDmitry Torokhov 
871de9ce703SDmitry Torokhov static int i8042_controller_check(void)
872de9ce703SDmitry Torokhov {
8732f0d2604SAndrey Moiseev 	if (i8042_flush()) {
8744eb3c30bSJoe Perches 		pr_err("No controller found\n");
875de9ce703SDmitry Torokhov 		return -ENODEV;
876de9ce703SDmitry Torokhov 	}
8771da177e4SLinus Torvalds 
8781da177e4SLinus Torvalds 	return 0;
8791da177e4SLinus Torvalds }
8801da177e4SLinus Torvalds 
881de9ce703SDmitry Torokhov static int i8042_controller_selftest(void)
8822673c836SVojtech Pavlik {
8832673c836SVojtech Pavlik 	unsigned char param;
8845ea2fc64SArjan van de Ven 	int i = 0;
8852673c836SVojtech Pavlik 
8865ea2fc64SArjan van de Ven 	/*
8875ea2fc64SArjan van de Ven 	 * We try this 5 times; on some really fragile systems this does not
8885ea2fc64SArjan van de Ven 	 * take the first time...
8895ea2fc64SArjan van de Ven 	 */
8905ea2fc64SArjan van de Ven 	do {
8915ea2fc64SArjan van de Ven 
8922673c836SVojtech Pavlik 		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
8934eb3c30bSJoe Perches 			pr_err("i8042 controller selftest timeout\n");
894de9ce703SDmitry Torokhov 			return -ENODEV;
8952673c836SVojtech Pavlik 		}
8962673c836SVojtech Pavlik 
8975ea2fc64SArjan van de Ven 		if (param == I8042_RET_CTL_TEST)
8985ea2fc64SArjan van de Ven 			return 0;
8995ea2fc64SArjan van de Ven 
900a2a94e73SPaul Bolle 		dbg("i8042 controller selftest: %#x != %#x\n",
9012673c836SVojtech Pavlik 		    param, I8042_RET_CTL_TEST);
9025ea2fc64SArjan van de Ven 		msleep(50);
9035ea2fc64SArjan van de Ven 	} while (i++ < 5);
9042673c836SVojtech Pavlik 
9055ea2fc64SArjan van de Ven #ifdef CONFIG_X86
9065ea2fc64SArjan van de Ven 	/*
9075ea2fc64SArjan van de Ven 	 * On x86, we don't fail entire i8042 initialization if controller
9085ea2fc64SArjan van de Ven 	 * reset fails in hopes that keyboard port will still be functional
9095ea2fc64SArjan van de Ven 	 * and user will still get a working keyboard. This is especially
9105ea2fc64SArjan van de Ven 	 * important on netbooks. On other arches we trust hardware more.
9115ea2fc64SArjan van de Ven 	 */
9124eb3c30bSJoe Perches 	pr_info("giving up on controller selftest, continuing anyway...\n");
9132673c836SVojtech Pavlik 	return 0;
9145ea2fc64SArjan van de Ven #else
915a2a94e73SPaul Bolle 	pr_err("i8042 controller selftest failed\n");
9165ea2fc64SArjan van de Ven 	return -EIO;
9175ea2fc64SArjan van de Ven #endif
9182673c836SVojtech Pavlik }
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds /*
9211da177e4SLinus Torvalds  * i8042_controller init initializes the i8042 controller, and,
9221da177e4SLinus Torvalds  * most importantly, sets it into non-xlated mode if that's
9231da177e4SLinus Torvalds  * desired.
9241da177e4SLinus Torvalds  */
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds static int i8042_controller_init(void)
9271da177e4SLinus Torvalds {
9281da177e4SLinus Torvalds 	unsigned long flags;
929ee1e82ceSDmitry Torokhov 	int n = 0;
930ee1e82ceSDmitry Torokhov 	unsigned char ctr[2];
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds /*
933ee1e82ceSDmitry Torokhov  * Save the CTR for restore on unload / reboot.
9341da177e4SLinus Torvalds  */
9351da177e4SLinus Torvalds 
936ee1e82ceSDmitry Torokhov 	do {
937ee1e82ceSDmitry Torokhov 		if (n >= 10) {
9384eb3c30bSJoe Perches 			pr_err("Unable to get stable CTR read\n");
939de9ce703SDmitry Torokhov 			return -EIO;
9401da177e4SLinus Torvalds 		}
9411da177e4SLinus Torvalds 
942ee1e82ceSDmitry Torokhov 		if (n != 0)
943ee1e82ceSDmitry Torokhov 			udelay(50);
944ee1e82ceSDmitry Torokhov 
945ee1e82ceSDmitry Torokhov 		if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
9464eb3c30bSJoe Perches 			pr_err("Can't read CTR while initializing i8042\n");
947ee1e82ceSDmitry Torokhov 			return -EIO;
948ee1e82ceSDmitry Torokhov 		}
949ee1e82ceSDmitry Torokhov 
950ee1e82ceSDmitry Torokhov 	} while (n < 2 || ctr[0] != ctr[1]);
951ee1e82ceSDmitry Torokhov 
952ee1e82ceSDmitry Torokhov 	i8042_initial_ctr = i8042_ctr = ctr[0];
9531da177e4SLinus Torvalds 
9541da177e4SLinus Torvalds /*
9551da177e4SLinus Torvalds  * Disable the keyboard interface and interrupt.
9561da177e4SLinus Torvalds  */
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_KBDDIS;
9591da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_KBDINT;
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds /*
9621da177e4SLinus Torvalds  * Handle keylock.
9631da177e4SLinus Torvalds  */
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
9661da177e4SLinus Torvalds 	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
9671da177e4SLinus Torvalds 		if (i8042_unlock)
9681da177e4SLinus Torvalds 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
9691da177e4SLinus Torvalds 		else
9704eb3c30bSJoe Perches 			pr_warn("Warning: Keylock active\n");
9711da177e4SLinus Torvalds 	}
9721da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
9731da177e4SLinus Torvalds 
9741da177e4SLinus Torvalds /*
9751da177e4SLinus Torvalds  * If the chip is configured into nontranslated mode by the BIOS, don't
9761da177e4SLinus Torvalds  * bother enabling translating and be happy.
9771da177e4SLinus Torvalds  */
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds 	if (~i8042_ctr & I8042_CTR_XLATE)
980386b3849SDmitry Torokhov 		i8042_direct = true;
9811da177e4SLinus Torvalds 
9821da177e4SLinus Torvalds /*
9831da177e4SLinus Torvalds  * Set nontranslated mode for the kbd interface if requested by an option.
9841da177e4SLinus Torvalds  * After this the kbd interface becomes a simple serial in/out, like the aux
9851da177e4SLinus Torvalds  * interface is. We don't do this by default, since it can confuse notebook
9861da177e4SLinus Torvalds  * BIOSes.
9871da177e4SLinus Torvalds  */
9881da177e4SLinus Torvalds 
9891da177e4SLinus Torvalds 	if (i8042_direct)
9901da177e4SLinus Torvalds 		i8042_ctr &= ~I8042_CTR_XLATE;
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds /*
9931da177e4SLinus Torvalds  * Write CTR back.
9941da177e4SLinus Torvalds  */
9951da177e4SLinus Torvalds 
9961da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
9974eb3c30bSJoe Perches 		pr_err("Can't write CTR while initializing i8042\n");
998de9ce703SDmitry Torokhov 		return -EIO;
9991da177e4SLinus Torvalds 	}
10001da177e4SLinus Torvalds 
1001ee1e82ceSDmitry Torokhov /*
1002ee1e82ceSDmitry Torokhov  * Flush whatever accumulated while we were disabling keyboard port.
1003ee1e82ceSDmitry Torokhov  */
1004ee1e82ceSDmitry Torokhov 
1005ee1e82ceSDmitry Torokhov 	i8042_flush();
1006ee1e82ceSDmitry Torokhov 
10071da177e4SLinus Torvalds 	return 0;
10081da177e4SLinus Torvalds }
10091da177e4SLinus Torvalds 
10101da177e4SLinus Torvalds 
10111da177e4SLinus Torvalds /*
1012de9ce703SDmitry Torokhov  * Reset the controller and reset CRT to the original value set by BIOS.
10131da177e4SLinus Torvalds  */
10141da177e4SLinus Torvalds 
10151729ad1fSDmitry Torokhov static void i8042_controller_reset(bool force_reset)
1016de9ce703SDmitry Torokhov {
1017de9ce703SDmitry Torokhov 	i8042_flush();
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds /*
10208d04ddb6SDmitry Torokhov  * Disable both KBD and AUX interfaces so they don't get in the way
10218d04ddb6SDmitry Torokhov  */
10228d04ddb6SDmitry Torokhov 
10238d04ddb6SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
10248d04ddb6SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
10258d04ddb6SDmitry Torokhov 
1026ee1e82ceSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
10274eb3c30bSJoe Perches 		pr_warn("Can't write CTR while resetting\n");
10285ddbc77cSDmitry Torokhov 
10298d04ddb6SDmitry Torokhov /*
10301da177e4SLinus Torvalds  * Disable MUX mode if present.
10311da177e4SLinus Torvalds  */
10321da177e4SLinus Torvalds 
10331da177e4SLinus Torvalds 	if (i8042_mux_present)
1034386b3849SDmitry Torokhov 		i8042_set_mux_mode(false, NULL);
10351da177e4SLinus Torvalds 
10361da177e4SLinus Torvalds /*
1037de9ce703SDmitry Torokhov  * Reset the controller if requested.
1038de9ce703SDmitry Torokhov  */
1039de9ce703SDmitry Torokhov 
10401729ad1fSDmitry Torokhov 	if (i8042_reset || force_reset)
1041de9ce703SDmitry Torokhov 		i8042_controller_selftest();
1042de9ce703SDmitry Torokhov 
1043de9ce703SDmitry Torokhov /*
10441da177e4SLinus Torvalds  * Restore the original control register setting.
10451da177e4SLinus Torvalds  */
10461da177e4SLinus Torvalds 
1047de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
10484eb3c30bSJoe Perches 		pr_warn("Can't restore CTR\n");
10491da177e4SLinus Torvalds }
10501da177e4SLinus Torvalds 
10511da177e4SLinus Torvalds 
10521da177e4SLinus Torvalds /*
1053c7ff0d9cSTAMUKI Shoichi  * i8042_panic_blink() will turn the keyboard LEDs on or off and is called
1054c7ff0d9cSTAMUKI Shoichi  * when kernel panics. Flashing LEDs is useful for users running X who may
1055aa5e5dc2SMichael Opdenacker  * not see the console and will help distinguishing panics from "real"
10561da177e4SLinus Torvalds  * lockups.
10571da177e4SLinus Torvalds  *
10581da177e4SLinus Torvalds  * Note that DELAY has a limit of 10ms so we will not get stuck here
10591da177e4SLinus Torvalds  * waiting for KBC to free up even if KBD interrupt is off
10601da177e4SLinus Torvalds  */
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
10631da177e4SLinus Torvalds 
1064c7ff0d9cSTAMUKI Shoichi static long i8042_panic_blink(int state)
10651da177e4SLinus Torvalds {
10661da177e4SLinus Torvalds 	long delay = 0;
1067c7ff0d9cSTAMUKI Shoichi 	char led;
10681da177e4SLinus Torvalds 
1069c7ff0d9cSTAMUKI Shoichi 	led = (state) ? 0x01 | 0x04 : 0;
10701da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
10711da177e4SLinus Torvalds 		DELAY;
10724eb3c30bSJoe Perches 	dbg("%02x -> i8042 (panic blink)\n", 0xed);
107319f3c3e3SDmitry Torokhov 	i8042_suppress_kbd_ack = 2;
10741da177e4SLinus Torvalds 	i8042_write_data(0xed); /* set leds */
10751da177e4SLinus Torvalds 	DELAY;
10761da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
10771da177e4SLinus Torvalds 		DELAY;
10781da177e4SLinus Torvalds 	DELAY;
10794eb3c30bSJoe Perches 	dbg("%02x -> i8042 (panic blink)\n", led);
10801da177e4SLinus Torvalds 	i8042_write_data(led);
10811da177e4SLinus Torvalds 	DELAY;
10821da177e4SLinus Torvalds 	return delay;
10831da177e4SLinus Torvalds }
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds #undef DELAY
10861da177e4SLinus Torvalds 
1087d35895dbSBruno Prémont #ifdef CONFIG_X86
1088d35895dbSBruno Prémont static void i8042_dritek_enable(void)
1089d35895dbSBruno Prémont {
1090594d6363SChristoph Fritz 	unsigned char param = 0x90;
1091d35895dbSBruno Prémont 	int error;
1092d35895dbSBruno Prémont 
1093d35895dbSBruno Prémont 	error = i8042_command(&param, 0x1059);
1094d35895dbSBruno Prémont 	if (error)
10954eb3c30bSJoe Perches 		pr_warn("Failed to enable DRITEK extension: %d\n", error);
1096d35895dbSBruno Prémont }
1097d35895dbSBruno Prémont #endif
1098d35895dbSBruno Prémont 
109982dd9effSDmitry Torokhov #ifdef CONFIG_PM
11007e044e05SDmitry Torokhov 
11011da177e4SLinus Torvalds /*
1102ebd7768dSDmitry Torokhov  * Here we try to reset everything back to a state we had
1103ebd7768dSDmitry Torokhov  * before suspending.
11041da177e4SLinus Torvalds  */
11051da177e4SLinus Torvalds 
11061ca56e51SDmitry Torokhov static int i8042_controller_resume(bool force_reset)
11071da177e4SLinus Torvalds {
1108de9ce703SDmitry Torokhov 	int error;
11091da177e4SLinus Torvalds 
1110de9ce703SDmitry Torokhov 	error = i8042_controller_check();
1111de9ce703SDmitry Torokhov 	if (error)
1112de9ce703SDmitry Torokhov 		return error;
11132673c836SVojtech Pavlik 
11141ca56e51SDmitry Torokhov 	if (i8042_reset || force_reset) {
1115de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1116de9ce703SDmitry Torokhov 		if (error)
1117de9ce703SDmitry Torokhov 			return error;
11181ca56e51SDmitry Torokhov 	}
1119de9ce703SDmitry Torokhov 
1120de9ce703SDmitry Torokhov /*
112182dd9effSDmitry Torokhov  * Restore original CTR value and disable all ports
1122de9ce703SDmitry Torokhov  */
1123de9ce703SDmitry Torokhov 
112482dd9effSDmitry Torokhov 	i8042_ctr = i8042_initial_ctr;
112582dd9effSDmitry Torokhov 	if (i8042_direct)
112682dd9effSDmitry Torokhov 		i8042_ctr &= ~I8042_CTR_XLATE;
1127de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
1128de9ce703SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
11292673c836SVojtech Pavlik 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
11304eb3c30bSJoe Perches 		pr_warn("Can't write CTR to resume, retrying...\n");
11312f6a77d5SJiri Kosina 		msleep(50);
11322f6a77d5SJiri Kosina 		if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
11334eb3c30bSJoe Perches 			pr_err("CTR write retry failed\n");
1134de9ce703SDmitry Torokhov 			return -EIO;
11351da177e4SLinus Torvalds 		}
11362f6a77d5SJiri Kosina 	}
11371da177e4SLinus Torvalds 
1138d35895dbSBruno Prémont 
1139d35895dbSBruno Prémont #ifdef CONFIG_X86
1140d35895dbSBruno Prémont 	if (i8042_dritek)
1141d35895dbSBruno Prémont 		i8042_dritek_enable();
1142d35895dbSBruno Prémont #endif
1143d35895dbSBruno Prémont 
1144de9ce703SDmitry Torokhov 	if (i8042_mux_present) {
1145386b3849SDmitry Torokhov 		if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
11464eb3c30bSJoe Perches 			pr_warn("failed to resume active multiplexor, mouse won't work\n");
1147de9ce703SDmitry Torokhov 	} else if (i8042_ports[I8042_AUX_PORT_NO].serio)
1148de9ce703SDmitry Torokhov 		i8042_enable_aux_port();
11491da177e4SLinus Torvalds 
1150de9ce703SDmitry Torokhov 	if (i8042_ports[I8042_KBD_PORT_NO].serio)
1151de9ce703SDmitry Torokhov 		i8042_enable_kbd_port();
11521da177e4SLinus Torvalds 
11537d12e780SDavid Howells 	i8042_interrupt(0, NULL);
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds 	return 0;
11561da177e4SLinus Torvalds }
1157ebd7768dSDmitry Torokhov 
11581ca56e51SDmitry Torokhov /*
11591ca56e51SDmitry Torokhov  * Here we try to restore the original BIOS settings to avoid
11601ca56e51SDmitry Torokhov  * upsetting it.
11611ca56e51SDmitry Torokhov  */
11621ca56e51SDmitry Torokhov 
11631729ad1fSDmitry Torokhov static int i8042_pm_suspend(struct device *dev)
11641ca56e51SDmitry Torokhov {
1165*f13b2065SRafael J. Wysocki 	int i;
1166*f13b2065SRafael J. Wysocki 
11671729ad1fSDmitry Torokhov 	i8042_controller_reset(true);
11681ca56e51SDmitry Torokhov 
1169*f13b2065SRafael J. Wysocki 	/* Set up serio interrupts for system wakeup. */
1170*f13b2065SRafael J. Wysocki 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1171*f13b2065SRafael J. Wysocki 		struct serio *serio = i8042_ports[i].serio;
1172*f13b2065SRafael J. Wysocki 
1173*f13b2065SRafael J. Wysocki 		if (serio && device_may_wakeup(&serio->dev))
1174*f13b2065SRafael J. Wysocki 			enable_irq_wake(i8042_ports[i].irq);
1175*f13b2065SRafael J. Wysocki 	}
1176*f13b2065SRafael J. Wysocki 
11771ca56e51SDmitry Torokhov 	return 0;
11781ca56e51SDmitry Torokhov }
11791ca56e51SDmitry Torokhov 
11801ca56e51SDmitry Torokhov static int i8042_pm_resume(struct device *dev)
11811ca56e51SDmitry Torokhov {
1182*f13b2065SRafael J. Wysocki 	int i;
1183*f13b2065SRafael J. Wysocki 
1184*f13b2065SRafael J. Wysocki 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1185*f13b2065SRafael J. Wysocki 		struct serio *serio = i8042_ports[i].serio;
1186*f13b2065SRafael J. Wysocki 
1187*f13b2065SRafael J. Wysocki 		if (serio && device_may_wakeup(&serio->dev))
1188*f13b2065SRafael J. Wysocki 			disable_irq_wake(i8042_ports[i].irq);
1189*f13b2065SRafael J. Wysocki 	}
1190*f13b2065SRafael J. Wysocki 
11911ca56e51SDmitry Torokhov 	/*
11921ca56e51SDmitry Torokhov 	 * On resume from S2R we always try to reset the controller
11931ca56e51SDmitry Torokhov 	 * to bring it in a sane state. (In case of S2D we expect
11941ca56e51SDmitry Torokhov 	 * BIOS to reset the controller for us.)
11951ca56e51SDmitry Torokhov 	 */
11961ca56e51SDmitry Torokhov 	return i8042_controller_resume(true);
11971ca56e51SDmitry Torokhov }
11981ca56e51SDmitry Torokhov 
1199c2d1a2a1SAlan Jenkins static int i8042_pm_thaw(struct device *dev)
1200c2d1a2a1SAlan Jenkins {
1201c2d1a2a1SAlan Jenkins 	i8042_interrupt(0, NULL);
1202c2d1a2a1SAlan Jenkins 
1203c2d1a2a1SAlan Jenkins 	return 0;
1204c2d1a2a1SAlan Jenkins }
1205c2d1a2a1SAlan Jenkins 
12061729ad1fSDmitry Torokhov static int i8042_pm_reset(struct device *dev)
12071729ad1fSDmitry Torokhov {
12081729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
12091729ad1fSDmitry Torokhov 
12101729ad1fSDmitry Torokhov 	return 0;
12111729ad1fSDmitry Torokhov }
12121729ad1fSDmitry Torokhov 
12131ca56e51SDmitry Torokhov static int i8042_pm_restore(struct device *dev)
12141ca56e51SDmitry Torokhov {
12151ca56e51SDmitry Torokhov 	return i8042_controller_resume(false);
12161ca56e51SDmitry Torokhov }
12171ca56e51SDmitry Torokhov 
1218ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = {
12191729ad1fSDmitry Torokhov 	.suspend	= i8042_pm_suspend,
12201ca56e51SDmitry Torokhov 	.resume		= i8042_pm_resume,
1221c2d1a2a1SAlan Jenkins 	.thaw		= i8042_pm_thaw,
1222ebd7768dSDmitry Torokhov 	.poweroff	= i8042_pm_reset,
1223ebd7768dSDmitry Torokhov 	.restore	= i8042_pm_restore,
1224ebd7768dSDmitry Torokhov };
1225ebd7768dSDmitry Torokhov 
122682dd9effSDmitry Torokhov #endif /* CONFIG_PM */
12271da177e4SLinus Torvalds 
12281da177e4SLinus Torvalds /*
12291da177e4SLinus Torvalds  * We need to reset the 8042 back to original mode on system shutdown,
12301da177e4SLinus Torvalds  * because otherwise BIOSes will be confused.
12311da177e4SLinus Torvalds  */
12321da177e4SLinus Torvalds 
12333ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev)
12341da177e4SLinus Torvalds {
12351729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
12361da177e4SLinus Torvalds }
12371da177e4SLinus Torvalds 
1238f8113416SDmitry Torokhov static int __init i8042_create_kbd_port(void)
12391da177e4SLinus Torvalds {
12401da177e4SLinus Torvalds 	struct serio *serio;
12411da177e4SLinus Torvalds 	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
12421da177e4SLinus Torvalds 
1243d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
12440854e52dSDmitry Torokhov 	if (!serio)
12450854e52dSDmitry Torokhov 		return -ENOMEM;
12460854e52dSDmitry Torokhov 
12471da177e4SLinus Torvalds 	serio->id.type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL;
12481da177e4SLinus Torvalds 	serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write;
12491da177e4SLinus Torvalds 	serio->start		= i8042_start;
12501da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
12515ddbc77cSDmitry Torokhov 	serio->close		= i8042_port_close;
12521da177e4SLinus Torvalds 	serio->port_data	= port;
12531da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1254de9ce703SDmitry Torokhov 	strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
12551da177e4SLinus Torvalds 	strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
1256a7c5868cSHans de Goede 	strlcpy(serio->firmware_id, i8042_kbd_firmware_id,
1257a7c5868cSHans de Goede 		sizeof(serio->firmware_id));
12581da177e4SLinus Torvalds 
12591da177e4SLinus Torvalds 	port->serio = serio;
1260de9ce703SDmitry Torokhov 	port->irq = I8042_KBD_IRQ;
12610854e52dSDmitry Torokhov 
1262de9ce703SDmitry Torokhov 	return 0;
12631da177e4SLinus Torvalds }
12641da177e4SLinus Torvalds 
1265f8113416SDmitry Torokhov static int __init i8042_create_aux_port(int idx)
12661da177e4SLinus Torvalds {
12671da177e4SLinus Torvalds 	struct serio *serio;
1268de9ce703SDmitry Torokhov 	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
1269de9ce703SDmitry Torokhov 	struct i8042_port *port = &i8042_ports[port_no];
12701da177e4SLinus Torvalds 
1271d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
12720854e52dSDmitry Torokhov 	if (!serio)
12730854e52dSDmitry Torokhov 		return -ENOMEM;
12740854e52dSDmitry Torokhov 
12751da177e4SLinus Torvalds 	serio->id.type		= SERIO_8042;
12761da177e4SLinus Torvalds 	serio->write		= i8042_aux_write;
12771da177e4SLinus Torvalds 	serio->start		= i8042_start;
12781da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
12791da177e4SLinus Torvalds 	serio->port_data	= port;
12801da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1281de9ce703SDmitry Torokhov 	if (idx < 0) {
1282de9ce703SDmitry Torokhov 		strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));
12831da177e4SLinus Torvalds 		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
1284a7c5868cSHans de Goede 		strlcpy(serio->firmware_id, i8042_aux_firmware_id,
1285a7c5868cSHans de Goede 			sizeof(serio->firmware_id));
12865ddbc77cSDmitry Torokhov 		serio->close = i8042_port_close;
1287de9ce703SDmitry Torokhov 	} else {
1288de9ce703SDmitry Torokhov 		snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
1289de9ce703SDmitry Torokhov 		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
1290266e43c4SHans de Goede 		strlcpy(serio->firmware_id, i8042_aux_firmware_id,
1291266e43c4SHans de Goede 			sizeof(serio->firmware_id));
12921da177e4SLinus Torvalds 	}
12931da177e4SLinus Torvalds 
12941da177e4SLinus Torvalds 	port->serio = serio;
1295de9ce703SDmitry Torokhov 	port->mux = idx;
1296de9ce703SDmitry Torokhov 	port->irq = I8042_AUX_IRQ;
12970854e52dSDmitry Torokhov 
1298de9ce703SDmitry Torokhov 	return 0;
1299de9ce703SDmitry Torokhov }
1300de9ce703SDmitry Torokhov 
1301f8113416SDmitry Torokhov static void __init i8042_free_kbd_port(void)
1302de9ce703SDmitry Torokhov {
1303de9ce703SDmitry Torokhov 	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
1304de9ce703SDmitry Torokhov 	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
1305de9ce703SDmitry Torokhov }
1306de9ce703SDmitry Torokhov 
1307f8113416SDmitry Torokhov static void __init i8042_free_aux_ports(void)
1308de9ce703SDmitry Torokhov {
1309de9ce703SDmitry Torokhov 	int i;
1310de9ce703SDmitry Torokhov 
1311de9ce703SDmitry Torokhov 	for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) {
1312de9ce703SDmitry Torokhov 		kfree(i8042_ports[i].serio);
1313de9ce703SDmitry Torokhov 		i8042_ports[i].serio = NULL;
1314de9ce703SDmitry Torokhov 	}
1315de9ce703SDmitry Torokhov }
1316de9ce703SDmitry Torokhov 
1317f8113416SDmitry Torokhov static void __init i8042_register_ports(void)
1318de9ce703SDmitry Torokhov {
1319de9ce703SDmitry Torokhov 	int i;
1320de9ce703SDmitry Torokhov 
1321de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1322*f13b2065SRafael J. Wysocki 		struct serio *serio = i8042_ports[i].serio;
1323*f13b2065SRafael J. Wysocki 
1324*f13b2065SRafael J. Wysocki 		if (serio) {
1325de9ce703SDmitry Torokhov 			printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
1326*f13b2065SRafael J. Wysocki 				serio->name,
1327de9ce703SDmitry Torokhov 				(unsigned long) I8042_DATA_REG,
1328de9ce703SDmitry Torokhov 				(unsigned long) I8042_COMMAND_REG,
1329de9ce703SDmitry Torokhov 				i8042_ports[i].irq);
1330*f13b2065SRafael J. Wysocki 			serio_register_port(serio);
1331*f13b2065SRafael J. Wysocki 			device_set_wakeup_capable(&serio->dev, true);
1332de9ce703SDmitry Torokhov 		}
1333de9ce703SDmitry Torokhov 	}
1334de9ce703SDmitry Torokhov }
1335de9ce703SDmitry Torokhov 
1336e2619cf7SBill Pemberton static void i8042_unregister_ports(void)
1337de9ce703SDmitry Torokhov {
1338de9ce703SDmitry Torokhov 	int i;
1339de9ce703SDmitry Torokhov 
1340de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1341de9ce703SDmitry Torokhov 		if (i8042_ports[i].serio) {
1342de9ce703SDmitry Torokhov 			serio_unregister_port(i8042_ports[i].serio);
1343de9ce703SDmitry Torokhov 			i8042_ports[i].serio = NULL;
1344de9ce703SDmitry Torokhov 		}
1345de9ce703SDmitry Torokhov 	}
1346de9ce703SDmitry Torokhov }
1347de9ce703SDmitry Torokhov 
1348181d683dSDmitry Torokhov /*
1349181d683dSDmitry Torokhov  * Checks whether port belongs to i8042 controller.
1350181d683dSDmitry Torokhov  */
1351181d683dSDmitry Torokhov bool i8042_check_port_owner(const struct serio *port)
1352181d683dSDmitry Torokhov {
1353181d683dSDmitry Torokhov 	int i;
1354181d683dSDmitry Torokhov 
1355181d683dSDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++)
1356181d683dSDmitry Torokhov 		if (i8042_ports[i].serio == port)
1357181d683dSDmitry Torokhov 			return true;
1358181d683dSDmitry Torokhov 
1359181d683dSDmitry Torokhov 	return false;
1360181d683dSDmitry Torokhov }
1361181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_check_port_owner);
1362181d683dSDmitry Torokhov 
1363de9ce703SDmitry Torokhov static void i8042_free_irqs(void)
1364de9ce703SDmitry Torokhov {
1365de9ce703SDmitry Torokhov 	if (i8042_aux_irq_registered)
1366de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
1367de9ce703SDmitry Torokhov 	if (i8042_kbd_irq_registered)
1368de9ce703SDmitry Torokhov 		free_irq(I8042_KBD_IRQ, i8042_platform_device);
1369de9ce703SDmitry Torokhov 
1370386b3849SDmitry Torokhov 	i8042_aux_irq_registered = i8042_kbd_irq_registered = false;
1371de9ce703SDmitry Torokhov }
1372de9ce703SDmitry Torokhov 
1373f8113416SDmitry Torokhov static int __init i8042_setup_aux(void)
1374de9ce703SDmitry Torokhov {
1375de9ce703SDmitry Torokhov 	int (*aux_enable)(void);
1376de9ce703SDmitry Torokhov 	int error;
1377de9ce703SDmitry Torokhov 	int i;
1378de9ce703SDmitry Torokhov 
1379de9ce703SDmitry Torokhov 	if (i8042_check_aux())
1380de9ce703SDmitry Torokhov 		return -ENODEV;
1381de9ce703SDmitry Torokhov 
1382de9ce703SDmitry Torokhov 	if (i8042_nomux || i8042_check_mux()) {
1383de9ce703SDmitry Torokhov 		error = i8042_create_aux_port(-1);
1384de9ce703SDmitry Torokhov 		if (error)
1385de9ce703SDmitry Torokhov 			goto err_free_ports;
1386de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_aux_port;
1387de9ce703SDmitry Torokhov 	} else {
1388de9ce703SDmitry Torokhov 		for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
1389de9ce703SDmitry Torokhov 			error = i8042_create_aux_port(i);
1390de9ce703SDmitry Torokhov 			if (error)
1391de9ce703SDmitry Torokhov 				goto err_free_ports;
1392de9ce703SDmitry Torokhov 		}
1393de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_mux_ports;
1394de9ce703SDmitry Torokhov 	}
1395de9ce703SDmitry Torokhov 
1396de9ce703SDmitry Torokhov 	error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED,
1397de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1398de9ce703SDmitry Torokhov 	if (error)
1399de9ce703SDmitry Torokhov 		goto err_free_ports;
1400de9ce703SDmitry Torokhov 
1401de9ce703SDmitry Torokhov 	if (aux_enable())
1402de9ce703SDmitry Torokhov 		goto err_free_irq;
1403de9ce703SDmitry Torokhov 
1404386b3849SDmitry Torokhov 	i8042_aux_irq_registered = true;
1405de9ce703SDmitry Torokhov 	return 0;
1406de9ce703SDmitry Torokhov 
1407de9ce703SDmitry Torokhov  err_free_irq:
1408de9ce703SDmitry Torokhov 	free_irq(I8042_AUX_IRQ, i8042_platform_device);
1409de9ce703SDmitry Torokhov  err_free_ports:
1410de9ce703SDmitry Torokhov 	i8042_free_aux_ports();
1411de9ce703SDmitry Torokhov 	return error;
1412de9ce703SDmitry Torokhov }
1413de9ce703SDmitry Torokhov 
1414f8113416SDmitry Torokhov static int __init i8042_setup_kbd(void)
1415de9ce703SDmitry Torokhov {
1416de9ce703SDmitry Torokhov 	int error;
1417de9ce703SDmitry Torokhov 
1418de9ce703SDmitry Torokhov 	error = i8042_create_kbd_port();
1419de9ce703SDmitry Torokhov 	if (error)
1420de9ce703SDmitry Torokhov 		return error;
1421de9ce703SDmitry Torokhov 
1422de9ce703SDmitry Torokhov 	error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
1423de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1424de9ce703SDmitry Torokhov 	if (error)
1425de9ce703SDmitry Torokhov 		goto err_free_port;
1426de9ce703SDmitry Torokhov 
1427de9ce703SDmitry Torokhov 	error = i8042_enable_kbd_port();
1428de9ce703SDmitry Torokhov 	if (error)
1429de9ce703SDmitry Torokhov 		goto err_free_irq;
1430de9ce703SDmitry Torokhov 
1431386b3849SDmitry Torokhov 	i8042_kbd_irq_registered = true;
1432de9ce703SDmitry Torokhov 	return 0;
1433de9ce703SDmitry Torokhov 
1434de9ce703SDmitry Torokhov  err_free_irq:
1435de9ce703SDmitry Torokhov 	free_irq(I8042_KBD_IRQ, i8042_platform_device);
1436de9ce703SDmitry Torokhov  err_free_port:
1437de9ce703SDmitry Torokhov 	i8042_free_kbd_port();
1438de9ce703SDmitry Torokhov 	return error;
14391da177e4SLinus Torvalds }
14401da177e4SLinus Torvalds 
1441f8113416SDmitry Torokhov static int __init i8042_probe(struct platform_device *dev)
14421da177e4SLinus Torvalds {
1443de9ce703SDmitry Torokhov 	int error;
14441da177e4SLinus Torvalds 
1445ec62e1c8SDmitry Torokhov 	i8042_platform_device = dev;
1446ec62e1c8SDmitry Torokhov 
14471ca56e51SDmitry Torokhov 	if (i8042_reset) {
1448de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1449de9ce703SDmitry Torokhov 		if (error)
1450de9ce703SDmitry Torokhov 			return error;
14511ca56e51SDmitry Torokhov 	}
14521da177e4SLinus Torvalds 
1453de9ce703SDmitry Torokhov 	error = i8042_controller_init();
1454de9ce703SDmitry Torokhov 	if (error)
1455de9ce703SDmitry Torokhov 		return error;
14561da177e4SLinus Torvalds 
1457d35895dbSBruno Prémont #ifdef CONFIG_X86
1458d35895dbSBruno Prémont 	if (i8042_dritek)
1459d35895dbSBruno Prémont 		i8042_dritek_enable();
1460d35895dbSBruno Prémont #endif
1461d35895dbSBruno Prémont 
1462de9ce703SDmitry Torokhov 	if (!i8042_noaux) {
1463de9ce703SDmitry Torokhov 		error = i8042_setup_aux();
1464de9ce703SDmitry Torokhov 		if (error && error != -ENODEV && error != -EBUSY)
1465de9ce703SDmitry Torokhov 			goto out_fail;
14661da177e4SLinus Torvalds 	}
14671da177e4SLinus Torvalds 
1468945ef0d4SDmitry Torokhov 	if (!i8042_nokbd) {
1469de9ce703SDmitry Torokhov 		error = i8042_setup_kbd();
1470de9ce703SDmitry Torokhov 		if (error)
1471de9ce703SDmitry Torokhov 			goto out_fail;
1472945ef0d4SDmitry Torokhov 	}
1473de9ce703SDmitry Torokhov /*
1474de9ce703SDmitry Torokhov  * Ok, everything is ready, let's register all serio ports
1475de9ce703SDmitry Torokhov  */
1476de9ce703SDmitry Torokhov 	i8042_register_ports();
14771da177e4SLinus Torvalds 
14781da177e4SLinus Torvalds 	return 0;
14790854e52dSDmitry Torokhov 
1480de9ce703SDmitry Torokhov  out_fail:
1481de9ce703SDmitry Torokhov 	i8042_free_aux_ports();	/* in case KBD failed but AUX not */
1482de9ce703SDmitry Torokhov 	i8042_free_irqs();
14831729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
1484ec62e1c8SDmitry Torokhov 	i8042_platform_device = NULL;
14850854e52dSDmitry Torokhov 
1486de9ce703SDmitry Torokhov 	return error;
14871da177e4SLinus Torvalds }
14881da177e4SLinus Torvalds 
1489e2619cf7SBill Pemberton static int i8042_remove(struct platform_device *dev)
14901da177e4SLinus Torvalds {
1491de9ce703SDmitry Torokhov 	i8042_unregister_ports();
1492de9ce703SDmitry Torokhov 	i8042_free_irqs();
14931729ad1fSDmitry Torokhov 	i8042_controller_reset(false);
1494ec62e1c8SDmitry Torokhov 	i8042_platform_device = NULL;
14951da177e4SLinus Torvalds 
149687fd6318SDmitry Torokhov 	return 0;
149787fd6318SDmitry Torokhov }
149887fd6318SDmitry Torokhov 
149987fd6318SDmitry Torokhov static struct platform_driver i8042_driver = {
150087fd6318SDmitry Torokhov 	.driver		= {
150187fd6318SDmitry Torokhov 		.name	= "i8042",
1502ebd7768dSDmitry Torokhov #ifdef CONFIG_PM
1503ebd7768dSDmitry Torokhov 		.pm	= &i8042_pm_ops,
1504ebd7768dSDmitry Torokhov #endif
150587fd6318SDmitry Torokhov 	},
15061cb0aa88SBill Pemberton 	.remove		= i8042_remove,
150782dd9effSDmitry Torokhov 	.shutdown	= i8042_shutdown,
150887fd6318SDmitry Torokhov };
150987fd6318SDmitry Torokhov 
151087fd6318SDmitry Torokhov static int __init i8042_init(void)
151187fd6318SDmitry Torokhov {
1512ec62e1c8SDmitry Torokhov 	struct platform_device *pdev;
151387fd6318SDmitry Torokhov 	int err;
151487fd6318SDmitry Torokhov 
151587fd6318SDmitry Torokhov 	dbg_init();
151687fd6318SDmitry Torokhov 
151787fd6318SDmitry Torokhov 	err = i8042_platform_init();
151887fd6318SDmitry Torokhov 	if (err)
151987fd6318SDmitry Torokhov 		return err;
152087fd6318SDmitry Torokhov 
1521de9ce703SDmitry Torokhov 	err = i8042_controller_check();
1522de9ce703SDmitry Torokhov 	if (err)
1523de9ce703SDmitry Torokhov 		goto err_platform_exit;
152487fd6318SDmitry Torokhov 
1525ec62e1c8SDmitry Torokhov 	pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
1526ec62e1c8SDmitry Torokhov 	if (IS_ERR(pdev)) {
1527ec62e1c8SDmitry Torokhov 		err = PTR_ERR(pdev);
1528f8113416SDmitry Torokhov 		goto err_platform_exit;
152987fd6318SDmitry Torokhov 	}
153087fd6318SDmitry Torokhov 
1531de9ce703SDmitry Torokhov 	panic_blink = i8042_panic_blink;
1532de9ce703SDmitry Torokhov 
153387fd6318SDmitry Torokhov 	return 0;
153487fd6318SDmitry Torokhov 
153587fd6318SDmitry Torokhov  err_platform_exit:
153687fd6318SDmitry Torokhov 	i8042_platform_exit();
153787fd6318SDmitry Torokhov 	return err;
153887fd6318SDmitry Torokhov }
153987fd6318SDmitry Torokhov 
154087fd6318SDmitry Torokhov static void __exit i8042_exit(void)
154187fd6318SDmitry Torokhov {
1542f8113416SDmitry Torokhov 	platform_device_unregister(i8042_platform_device);
1543af045b86SDmitry Torokhov 	platform_driver_unregister(&i8042_driver);
15441da177e4SLinus Torvalds 	i8042_platform_exit();
15451da177e4SLinus Torvalds 
15461da177e4SLinus Torvalds 	panic_blink = NULL;
15471da177e4SLinus Torvalds }
15481da177e4SLinus Torvalds 
15491da177e4SLinus Torvalds module_init(i8042_init);
15501da177e4SLinus Torvalds module_exit(i8042_exit);
1551