xref: /openbmc/linux/drivers/input/serio/i8042.c (revision 5ddbc77c)
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 
137e044e05SDmitry Torokhov #include <linux/types.h>
141da177e4SLinus Torvalds #include <linux/delay.h>
151da177e4SLinus Torvalds #include <linux/module.h>
161da177e4SLinus Torvalds #include <linux/interrupt.h>
171da177e4SLinus Torvalds #include <linux/ioport.h>
181da177e4SLinus Torvalds #include <linux/init.h>
191da177e4SLinus Torvalds #include <linux/serio.h>
201da177e4SLinus Torvalds #include <linux/err.h>
211da177e4SLinus Torvalds #include <linux/rcupdate.h>
22d052d1beSRussell King #include <linux/platform_device.h>
23553a05b8SMárton Németh #include <linux/i8042.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <asm/io.h>
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
281da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
291da177e4SLinus Torvalds MODULE_LICENSE("GPL");
301da177e4SLinus Torvalds 
31945ef0d4SDmitry Torokhov static unsigned int i8042_nokbd;
32945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0);
33945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
34945ef0d4SDmitry Torokhov 
351da177e4SLinus Torvalds static unsigned int i8042_noaux;
361da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0);
371da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds static unsigned int i8042_nomux;
401da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0);
411da177e4SLinus Torvalds MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present.");
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds static unsigned int i8042_unlock;
441da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0);
451da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds static unsigned int i8042_reset;
481da177e4SLinus Torvalds module_param_named(reset, i8042_reset, bool, 0);
491da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds static unsigned int i8042_direct;
521da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0);
531da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode.");
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds static unsigned int i8042_dumbkbd;
561da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
571da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds static unsigned int i8042_noloop;
601da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0);
611da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds static unsigned int i8042_blink_frequency = 500;
641da177e4SLinus Torvalds module_param_named(panicblink, i8042_blink_frequency, uint, 0600);
651da177e4SLinus Torvalds MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics");
661da177e4SLinus Torvalds 
678987fec0SCarlos Corbacho #ifdef CONFIG_X86
688987fec0SCarlos Corbacho static unsigned int i8042_dritek;
698987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0);
708987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension");
718987fec0SCarlos Corbacho #endif
728987fec0SCarlos Corbacho 
731da177e4SLinus Torvalds #ifdef CONFIG_PNP
741da177e4SLinus Torvalds static int i8042_nopnp;
751da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0);
761da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
771da177e4SLinus Torvalds #endif
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds #define DEBUG
801da177e4SLinus Torvalds #ifdef DEBUG
811da177e4SLinus Torvalds static int i8042_debug;
821da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600);
831da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
841da177e4SLinus Torvalds #endif
851da177e4SLinus Torvalds 
861c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test;
871c7827aeSDmitry Torokhov 
881da177e4SLinus Torvalds #include "i8042.h"
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock);
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds struct i8042_port {
931da177e4SLinus Torvalds 	struct serio *serio;
941da177e4SLinus Torvalds 	int irq;
951da177e4SLinus Torvalds 	unsigned char exists;
961da177e4SLinus Torvalds 	signed char mux;
971da177e4SLinus Torvalds };
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds #define I8042_KBD_PORT_NO	0
1001da177e4SLinus Torvalds #define I8042_AUX_PORT_NO	1
1011da177e4SLinus Torvalds #define I8042_MUX_PORT_NO	2
1021da177e4SLinus Torvalds #define I8042_NUM_PORTS		(I8042_NUM_MUX_PORTS + 2)
103de9ce703SDmitry Torokhov 
104de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS];
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds static unsigned char i8042_initial_ctr;
1071da177e4SLinus Torvalds static unsigned char i8042_ctr;
1081da177e4SLinus Torvalds static unsigned char i8042_mux_present;
109de9ce703SDmitry Torokhov static unsigned char i8042_kbd_irq_registered;
110de9ce703SDmitry Torokhov static unsigned char i8042_aux_irq_registered;
111817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack;
1121da177e4SLinus Torvalds static struct platform_device *i8042_platform_device;
1131da177e4SLinus Torvalds 
1147d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id);
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds /*
1171da177e4SLinus Torvalds  * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
1181da177e4SLinus Torvalds  * be ready for reading values from it / writing values to it.
1191da177e4SLinus Torvalds  * Called always with i8042_lock held.
1201da177e4SLinus Torvalds  */
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds static int i8042_wait_read(void)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds 	int i = 0;
125de9ce703SDmitry Torokhov 
1261da177e4SLinus Torvalds 	while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
1271da177e4SLinus Torvalds 		udelay(50);
1281da177e4SLinus Torvalds 		i++;
1291da177e4SLinus Torvalds 	}
1301da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds static int i8042_wait_write(void)
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds 	int i = 0;
136de9ce703SDmitry Torokhov 
1371da177e4SLinus Torvalds 	while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
1381da177e4SLinus Torvalds 		udelay(50);
1391da177e4SLinus Torvalds 		i++;
1401da177e4SLinus Torvalds 	}
1411da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds /*
1451da177e4SLinus Torvalds  * i8042_flush() flushes all data that may be in the keyboard and mouse buffers
1461da177e4SLinus Torvalds  * of the i8042 down the toilet.
1471da177e4SLinus Torvalds  */
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds static int i8042_flush(void)
1501da177e4SLinus Torvalds {
1511da177e4SLinus Torvalds 	unsigned long flags;
1521da177e4SLinus Torvalds 	unsigned char data, str;
1531da177e4SLinus Torvalds 	int i = 0;
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) {
1581da177e4SLinus Torvalds 		udelay(50);
1591da177e4SLinus Torvalds 		data = i8042_read_data();
1601da177e4SLinus Torvalds 		i++;
1611da177e4SLinus Torvalds 		dbg("%02x <- i8042 (flush, %s)", data,
1621da177e4SLinus Torvalds 			str & I8042_STR_AUXDATA ? "aux" : "kbd");
1631da177e4SLinus Torvalds 	}
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds 	return i;
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds /*
1711da177e4SLinus Torvalds  * i8042_command() executes a command on the i8042. It also sends the input
1721da177e4SLinus Torvalds  * parameter(s) of the commands to it, and receives the output value(s). The
1731da177e4SLinus Torvalds  * parameters are to be stored in the param array, and the output is placed
1741da177e4SLinus Torvalds  * into the same array. The number of the parameters and output values is
1751da177e4SLinus Torvalds  * encoded in bits 8-11 of the command number.
1761da177e4SLinus Torvalds  */
1771da177e4SLinus Torvalds 
178de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command)
1791da177e4SLinus Torvalds {
180de9ce703SDmitry Torokhov 	int i, error;
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 	if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
1831da177e4SLinus Torvalds 		return -1;
1841da177e4SLinus Torvalds 
185de9ce703SDmitry Torokhov 	error = i8042_wait_write();
186de9ce703SDmitry Torokhov 	if (error)
187de9ce703SDmitry Torokhov 		return error;
188463a4f76SDmitry Torokhov 
1891da177e4SLinus Torvalds 	dbg("%02x -> i8042 (command)", command & 0xff);
1901da177e4SLinus Torvalds 	i8042_write_command(command & 0xff);
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 12) & 0xf); i++) {
193de9ce703SDmitry Torokhov 		error = i8042_wait_write();
194de9ce703SDmitry Torokhov 		if (error)
195de9ce703SDmitry Torokhov 			return error;
1961da177e4SLinus Torvalds 		dbg("%02x -> i8042 (parameter)", param[i]);
1971da177e4SLinus Torvalds 		i8042_write_data(param[i]);
1981da177e4SLinus Torvalds 	}
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 8) & 0xf); i++) {
201de9ce703SDmitry Torokhov 		error = i8042_wait_read();
202de9ce703SDmitry Torokhov 		if (error) {
203de9ce703SDmitry Torokhov 			dbg("     -- i8042 (timeout)");
204de9ce703SDmitry Torokhov 			return error;
205de9ce703SDmitry Torokhov 		}
206463a4f76SDmitry Torokhov 
207463a4f76SDmitry Torokhov 		if (command == I8042_CMD_AUX_LOOP &&
208463a4f76SDmitry Torokhov 		    !(i8042_read_status() & I8042_STR_AUXDATA)) {
209de9ce703SDmitry Torokhov 			dbg("     -- i8042 (auxerr)");
210de9ce703SDmitry Torokhov 			return -1;
211463a4f76SDmitry Torokhov 		}
212463a4f76SDmitry Torokhov 
2131da177e4SLinus Torvalds 		param[i] = i8042_read_data();
2141da177e4SLinus Torvalds 		dbg("%02x <- i8042 (return)", param[i]);
2151da177e4SLinus Torvalds 	}
2161da177e4SLinus Torvalds 
217de9ce703SDmitry Torokhov 	return 0;
218de9ce703SDmitry Torokhov }
2191da177e4SLinus Torvalds 
220553a05b8SMárton Németh int i8042_command(unsigned char *param, int command)
221de9ce703SDmitry Torokhov {
222de9ce703SDmitry Torokhov 	unsigned long flags;
223de9ce703SDmitry Torokhov 	int retval;
224de9ce703SDmitry Torokhov 
225de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
226de9ce703SDmitry Torokhov 	retval = __i8042_command(param, command);
227463a4f76SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
228de9ce703SDmitry Torokhov 
2291da177e4SLinus Torvalds 	return retval;
2301da177e4SLinus Torvalds }
231553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command);
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds /*
2341da177e4SLinus Torvalds  * i8042_kbd_write() sends a byte out through the keyboard interface.
2351da177e4SLinus Torvalds  */
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c)
2381da177e4SLinus Torvalds {
2391da177e4SLinus Torvalds 	unsigned long flags;
2401da177e4SLinus Torvalds 	int retval = 0;
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
2431da177e4SLinus Torvalds 
2441da177e4SLinus Torvalds 	if (!(retval = i8042_wait_write())) {
2451da177e4SLinus Torvalds 		dbg("%02x -> i8042 (kbd-data)", c);
2461da177e4SLinus Torvalds 		i8042_write_data(c);
2471da177e4SLinus Torvalds 	}
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	return retval;
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds /*
2551da177e4SLinus Torvalds  * i8042_aux_write() sends a byte out through the aux interface.
2561da177e4SLinus Torvalds  */
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c)
2591da177e4SLinus Torvalds {
2601da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
2611da177e4SLinus Torvalds 
262f4e3c711SDmitry Torokhov 	return i8042_command(&c, port->mux == -1 ?
263f4e3c711SDmitry Torokhov 					I8042_CMD_AUX_SEND :
264f4e3c711SDmitry Torokhov 					I8042_CMD_MUX_SEND + port->mux);
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds 
267*5ddbc77cSDmitry Torokhov 
268*5ddbc77cSDmitry Torokhov /*
269*5ddbc77cSDmitry Torokhov  * i8042_aux_close attempts to clear AUX or KBD port state by disabling
270*5ddbc77cSDmitry Torokhov  * and then re-enabling it.
271*5ddbc77cSDmitry Torokhov  */
272*5ddbc77cSDmitry Torokhov 
273*5ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio)
274*5ddbc77cSDmitry Torokhov {
275*5ddbc77cSDmitry Torokhov 	int irq_bit;
276*5ddbc77cSDmitry Torokhov 	int disable_bit;
277*5ddbc77cSDmitry Torokhov 	const char *port_name;
278*5ddbc77cSDmitry Torokhov 
279*5ddbc77cSDmitry Torokhov 	if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) {
280*5ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_AUXINT;
281*5ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_AUXDIS;
282*5ddbc77cSDmitry Torokhov 		port_name = "AUX";
283*5ddbc77cSDmitry Torokhov 	} else {
284*5ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_KBDINT;
285*5ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_KBDDIS;
286*5ddbc77cSDmitry Torokhov 		port_name = "KBD";
287*5ddbc77cSDmitry Torokhov 	}
288*5ddbc77cSDmitry Torokhov 
289*5ddbc77cSDmitry Torokhov 	i8042_ctr &= ~irq_bit;
290*5ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
291*5ddbc77cSDmitry Torokhov 		printk(KERN_WARNING
292*5ddbc77cSDmitry Torokhov 			"i8042.c: Can't write CTR while closing %s port.\n",
293*5ddbc77cSDmitry Torokhov 			port_name);
294*5ddbc77cSDmitry Torokhov 
295*5ddbc77cSDmitry Torokhov 	udelay(50);
296*5ddbc77cSDmitry Torokhov 
297*5ddbc77cSDmitry Torokhov 	i8042_ctr &= ~disable_bit;
298*5ddbc77cSDmitry Torokhov 	i8042_ctr |= irq_bit;
299*5ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
300*5ddbc77cSDmitry Torokhov 		printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n",
301*5ddbc77cSDmitry Torokhov 			port_name);
302*5ddbc77cSDmitry Torokhov 
303*5ddbc77cSDmitry Torokhov 	/*
304*5ddbc77cSDmitry Torokhov 	 * See if there is any data appeared while we were messing with
305*5ddbc77cSDmitry Torokhov 	 * port state.
306*5ddbc77cSDmitry Torokhov 	 */
307*5ddbc77cSDmitry Torokhov 	i8042_interrupt(0, NULL);
308*5ddbc77cSDmitry Torokhov }
309*5ddbc77cSDmitry Torokhov 
3101da177e4SLinus Torvalds /*
3111da177e4SLinus Torvalds  * i8042_start() is called by serio core when port is about to finish
3121da177e4SLinus Torvalds  * registering. It will mark port as existing so i8042_interrupt can
3131da177e4SLinus Torvalds  * start sending data through it.
3141da177e4SLinus Torvalds  */
3151da177e4SLinus Torvalds static int i8042_start(struct serio *serio)
3161da177e4SLinus Torvalds {
3171da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 	port->exists = 1;
3201da177e4SLinus Torvalds 	mb();
3211da177e4SLinus Torvalds 	return 0;
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds /*
3251da177e4SLinus Torvalds  * i8042_stop() marks serio port as non-existing so i8042_interrupt
3261da177e4SLinus Torvalds  * will not try to send data to the port that is about to go away.
3271da177e4SLinus Torvalds  * The function is called by serio core as part of unregister procedure.
3281da177e4SLinus Torvalds  */
3291da177e4SLinus Torvalds static void i8042_stop(struct serio *serio)
3301da177e4SLinus Torvalds {
3311da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	port->exists = 0;
334a8399c51SDmitry Torokhov 
335a8399c51SDmitry Torokhov 	/*
336a8399c51SDmitry Torokhov 	 * We synchronize with both AUX and KBD IRQs because there is
337a8399c51SDmitry Torokhov 	 * a (very unlikely) chance that AUX IRQ is raised for KBD port
338a8399c51SDmitry Torokhov 	 * and vice versa.
339a8399c51SDmitry Torokhov 	 */
340a8399c51SDmitry Torokhov 	synchronize_irq(I8042_AUX_IRQ);
341a8399c51SDmitry Torokhov 	synchronize_irq(I8042_KBD_IRQ);
3421da177e4SLinus Torvalds 	port->serio = NULL;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds /*
3461da177e4SLinus Torvalds  * i8042_interrupt() is the most important function in this driver -
3471da177e4SLinus Torvalds  * it handles the interrupts from the i8042, and sends incoming bytes
3481da177e4SLinus Torvalds  * to the upper layers.
3491da177e4SLinus Torvalds  */
3501da177e4SLinus Torvalds 
3517d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id)
3521da177e4SLinus Torvalds {
3531da177e4SLinus Torvalds 	struct i8042_port *port;
3541da177e4SLinus Torvalds 	unsigned long flags;
3551da177e4SLinus Torvalds 	unsigned char str, data;
3561da177e4SLinus Torvalds 	unsigned int dfl;
3571da177e4SLinus Torvalds 	unsigned int port_no;
358817e6ba3SDmitry Torokhov 	int ret = 1;
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
3611da177e4SLinus Torvalds 	str = i8042_read_status();
3621da177e4SLinus Torvalds 	if (unlikely(~str & I8042_STR_OBF)) {
3631da177e4SLinus Torvalds 		spin_unlock_irqrestore(&i8042_lock, flags);
3641da177e4SLinus Torvalds 		if (irq) dbg("Interrupt %d, without any data", irq);
3651da177e4SLinus Torvalds 		ret = 0;
3661da177e4SLinus Torvalds 		goto out;
3671da177e4SLinus Torvalds 	}
3681da177e4SLinus Torvalds 	data = i8042_read_data();
3691da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
3721da177e4SLinus Torvalds 		static unsigned long last_transmit;
3731da177e4SLinus Torvalds 		static unsigned char last_str;
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds 		dfl = 0;
3761da177e4SLinus Torvalds 		if (str & I8042_STR_MUXERR) {
3771da177e4SLinus Torvalds 			dbg("MUX error, status is %02x, data is %02x", str, data);
3781da177e4SLinus Torvalds /*
3791da177e4SLinus Torvalds  * When MUXERR condition is signalled the data register can only contain
3801da177e4SLinus Torvalds  * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
381a216a4b6SDmitry Torokhov  * it is not always the case. Some KBCs also report 0xfc when there is
382a216a4b6SDmitry Torokhov  * nothing connected to the port while others sometimes get confused which
383a216a4b6SDmitry Torokhov  * port the data came from and signal error leaving the data intact. They
384a216a4b6SDmitry Torokhov  * _do not_ revert to legacy mode (actually I've never seen KBC reverting
385a216a4b6SDmitry Torokhov  * to legacy mode yet, when we see one we'll add proper handling).
386a216a4b6SDmitry Torokhov  * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the
387a216a4b6SDmitry Torokhov  * rest assume that the data came from the same serio last byte
3881da177e4SLinus Torvalds  * was transmitted (if transmission happened not too long ago).
3891da177e4SLinus Torvalds  */
390a216a4b6SDmitry Torokhov 
391a216a4b6SDmitry Torokhov 			switch (data) {
392a216a4b6SDmitry Torokhov 				default:
3931da177e4SLinus Torvalds 					if (time_before(jiffies, last_transmit + HZ/10)) {
3941da177e4SLinus Torvalds 						str = last_str;
3951da177e4SLinus Torvalds 						break;
3961da177e4SLinus Torvalds 					}
3971da177e4SLinus Torvalds 					/* fall through - report timeout */
398a216a4b6SDmitry Torokhov 				case 0xfc:
3991da177e4SLinus Torvalds 				case 0xfd:
4001da177e4SLinus Torvalds 				case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
4011da177e4SLinus Torvalds 				case 0xff: dfl = SERIO_PARITY;  data = 0xfe; break;
4021da177e4SLinus Torvalds 			}
4031da177e4SLinus Torvalds 		}
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds 		port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
4061da177e4SLinus Torvalds 		last_str = str;
4071da177e4SLinus Torvalds 		last_transmit = jiffies;
4081da177e4SLinus Torvalds 	} else {
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds 		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
4111da177e4SLinus Torvalds 		      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 		port_no = (str & I8042_STR_AUXDATA) ?
4141da177e4SLinus Torvalds 				I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
4151da177e4SLinus Torvalds 	}
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 	port = &i8042_ports[port_no];
4181da177e4SLinus Torvalds 
419de9ce703SDmitry Torokhov 	dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
420de9ce703SDmitry Torokhov 	    data, port_no, irq,
4211da177e4SLinus Torvalds 	    dfl & SERIO_PARITY ? ", bad parity" : "",
4221da177e4SLinus Torvalds 	    dfl & SERIO_TIMEOUT ? ", timeout" : "");
4231da177e4SLinus Torvalds 
424817e6ba3SDmitry Torokhov 	if (unlikely(i8042_suppress_kbd_ack))
425817e6ba3SDmitry Torokhov 		if (port_no == I8042_KBD_PORT_NO &&
426817e6ba3SDmitry Torokhov 		    (data == 0xfa || data == 0xfe)) {
42719f3c3e3SDmitry Torokhov 			i8042_suppress_kbd_ack--;
428817e6ba3SDmitry Torokhov 			goto out;
429817e6ba3SDmitry Torokhov 		}
430817e6ba3SDmitry Torokhov 
4311da177e4SLinus Torvalds 	if (likely(port->exists))
4327d12e780SDavid Howells 		serio_interrupt(port->serio, data, dfl);
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds  out:
4351da177e4SLinus Torvalds 	return IRQ_RETVAL(ret);
4361da177e4SLinus Torvalds }
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds /*
439*5ddbc77cSDmitry Torokhov  * i8042_enable_kbd_port enables keyboard port on chip
440de9ce703SDmitry Torokhov  */
441de9ce703SDmitry Torokhov 
442de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void)
443de9ce703SDmitry Torokhov {
444de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_KBDDIS;
445de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDINT;
446de9ce703SDmitry Torokhov 
447de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
448018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_KBDINT;
449018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_KBDDIS;
450de9ce703SDmitry Torokhov 		printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n");
451de9ce703SDmitry Torokhov 		return -EIO;
452de9ce703SDmitry Torokhov 	}
453de9ce703SDmitry Torokhov 
454de9ce703SDmitry Torokhov 	return 0;
455de9ce703SDmitry Torokhov }
456de9ce703SDmitry Torokhov 
457de9ce703SDmitry Torokhov /*
458de9ce703SDmitry Torokhov  * i8042_enable_aux_port enables AUX (mouse) port on chip
459de9ce703SDmitry Torokhov  */
460de9ce703SDmitry Torokhov 
461de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void)
462de9ce703SDmitry Torokhov {
463de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXDIS;
464de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXINT;
465de9ce703SDmitry Torokhov 
466de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
467018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_AUXINT;
468018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_AUXDIS;
469de9ce703SDmitry Torokhov 		printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n");
470de9ce703SDmitry Torokhov 		return -EIO;
471de9ce703SDmitry Torokhov 	}
472de9ce703SDmitry Torokhov 
473de9ce703SDmitry Torokhov 	return 0;
474de9ce703SDmitry Torokhov }
475de9ce703SDmitry Torokhov 
476de9ce703SDmitry Torokhov /*
477de9ce703SDmitry Torokhov  * i8042_enable_mux_ports enables 4 individual AUX ports after
478de9ce703SDmitry Torokhov  * the controller has been switched into Multiplexed mode
479de9ce703SDmitry Torokhov  */
480de9ce703SDmitry Torokhov 
481de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void)
482de9ce703SDmitry Torokhov {
483de9ce703SDmitry Torokhov 	unsigned char param;
484de9ce703SDmitry Torokhov 	int i;
485de9ce703SDmitry Torokhov 
486de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
487de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_MUX_PFX + i);
488de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_AUX_ENABLE);
489de9ce703SDmitry Torokhov 	}
490de9ce703SDmitry Torokhov 
491de9ce703SDmitry Torokhov 	return i8042_enable_aux_port();
492de9ce703SDmitry Torokhov }
493de9ce703SDmitry Torokhov 
494de9ce703SDmitry Torokhov /*
4951da177e4SLinus Torvalds  * i8042_set_mux_mode checks whether the controller has an active
4961da177e4SLinus Torvalds  * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode.
4971da177e4SLinus Torvalds  */
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version)
5001da177e4SLinus Torvalds {
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	unsigned char param;
5031da177e4SLinus Torvalds /*
5041da177e4SLinus Torvalds  * Get rid of bytes in the queue.
5051da177e4SLinus Torvalds  */
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds 	i8042_flush();
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds /*
5101da177e4SLinus Torvalds  * Internal loopback test - send three bytes, they should come back from the
511de9ce703SDmitry Torokhov  * mouse interface, the last should be version.
5121da177e4SLinus Torvalds  */
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 	param = 0xf0;
515463a4f76SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xf0)
5161da177e4SLinus Torvalds 		return -1;
5171da177e4SLinus Torvalds 	param = mode ? 0x56 : 0xf6;
518463a4f76SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6))
5191da177e4SLinus Torvalds 		return -1;
5201da177e4SLinus Torvalds 	param = mode ? 0xa4 : 0xa5;
521463a4f76SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5))
5221da177e4SLinus Torvalds 		return -1;
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 	if (mux_version)
525463a4f76SDmitry Torokhov 		*mux_version = param;
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds 	return 0;
5281da177e4SLinus Torvalds }
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds /*
5311da177e4SLinus Torvalds  * i8042_check_mux() checks whether the controller supports the PS/2 Active
5321da177e4SLinus Torvalds  * Multiplexing specification by Synaptics, Phoenix, Insyde and
5331da177e4SLinus Torvalds  * LCS/Telegraphics.
5341da177e4SLinus Torvalds  */
5351da177e4SLinus Torvalds 
53687fd6318SDmitry Torokhov static int __devinit i8042_check_mux(void)
5371da177e4SLinus Torvalds {
5381da177e4SLinus Torvalds 	unsigned char mux_version;
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds 	if (i8042_set_mux_mode(1, &mux_version))
5411da177e4SLinus Torvalds 		return -1;
5421da177e4SLinus Torvalds 
543de9ce703SDmitry Torokhov /*
544de9ce703SDmitry Torokhov  * Workaround for interference with USB Legacy emulation
545de9ce703SDmitry Torokhov  * that causes a v10.12 MUX to be found.
546de9ce703SDmitry Torokhov  */
5471da177e4SLinus Torvalds 	if (mux_version == 0xAC)
5481da177e4SLinus Torvalds 		return -1;
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
5511da177e4SLinus Torvalds 		(mux_version >> 4) & 0xf, mux_version & 0xf);
5521da177e4SLinus Torvalds 
553de9ce703SDmitry Torokhov /*
554de9ce703SDmitry Torokhov  * Disable all muxed ports by disabling AUX.
555de9ce703SDmitry Torokhov  */
556de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS;
557de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXINT;
558de9ce703SDmitry Torokhov 
559de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
560de9ce703SDmitry Torokhov 		printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n");
561de9ce703SDmitry Torokhov 		return -EIO;
562de9ce703SDmitry Torokhov 	}
5631da177e4SLinus Torvalds 
5641da177e4SLinus Torvalds 	i8042_mux_present = 1;
565de9ce703SDmitry Torokhov 
5661da177e4SLinus Torvalds 	return 0;
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds 
569de9ce703SDmitry Torokhov /*
570de9ce703SDmitry Torokhov  * The following is used to test AUX IRQ delivery.
571de9ce703SDmitry Torokhov  */
572de9ce703SDmitry Torokhov static struct completion i8042_aux_irq_delivered __devinitdata;
573de9ce703SDmitry Torokhov static int i8042_irq_being_tested __devinitdata;
574de9ce703SDmitry Torokhov 
5757d12e780SDavid Howells static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id)
576de9ce703SDmitry Torokhov {
577de9ce703SDmitry Torokhov 	unsigned long flags;
578de9ce703SDmitry Torokhov 	unsigned char str, data;
579e3758b2aSFernando Luis Vázquez Cao 	int ret = 0;
580de9ce703SDmitry Torokhov 
581de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
582de9ce703SDmitry Torokhov 	str = i8042_read_status();
583de9ce703SDmitry Torokhov 	if (str & I8042_STR_OBF) {
584de9ce703SDmitry Torokhov 		data = i8042_read_data();
585de9ce703SDmitry Torokhov 		if (i8042_irq_being_tested &&
586de9ce703SDmitry Torokhov 		    data == 0xa5 && (str & I8042_STR_AUXDATA))
587de9ce703SDmitry Torokhov 			complete(&i8042_aux_irq_delivered);
588e3758b2aSFernando Luis Vázquez Cao 		ret = 1;
589de9ce703SDmitry Torokhov 	}
590de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
591de9ce703SDmitry Torokhov 
592e3758b2aSFernando Luis Vázquez Cao 	return IRQ_RETVAL(ret);
593de9ce703SDmitry Torokhov }
594de9ce703SDmitry Torokhov 
595d2ada559SRoland Scheidegger /*
596d2ada559SRoland Scheidegger  * i8042_toggle_aux - enables or disables AUX port on i8042 via command and
597d2ada559SRoland Scheidegger  * verifies success by readinng CTR. Used when testing for presence of AUX
598d2ada559SRoland Scheidegger  * port.
599d2ada559SRoland Scheidegger  */
600d2ada559SRoland Scheidegger static int __devinit i8042_toggle_aux(int on)
601d2ada559SRoland Scheidegger {
602d2ada559SRoland Scheidegger 	unsigned char param;
603d2ada559SRoland Scheidegger 	int i;
604d2ada559SRoland Scheidegger 
605d2ada559SRoland Scheidegger 	if (i8042_command(&param,
606d2ada559SRoland Scheidegger 			on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE))
607d2ada559SRoland Scheidegger 		return -1;
608d2ada559SRoland Scheidegger 
609d2ada559SRoland Scheidegger 	/* some chips need some time to set the I8042_CTR_AUXDIS bit */
610d2ada559SRoland Scheidegger 	for (i = 0; i < 100; i++) {
611d2ada559SRoland Scheidegger 		udelay(50);
612d2ada559SRoland Scheidegger 
613d2ada559SRoland Scheidegger 		if (i8042_command(&param, I8042_CMD_CTL_RCTR))
614d2ada559SRoland Scheidegger 			return -1;
615d2ada559SRoland Scheidegger 
616d2ada559SRoland Scheidegger 		if (!(param & I8042_CTR_AUXDIS) == on)
617d2ada559SRoland Scheidegger 			return 0;
618d2ada559SRoland Scheidegger 	}
619d2ada559SRoland Scheidegger 
620d2ada559SRoland Scheidegger 	return -1;
621d2ada559SRoland Scheidegger }
6221da177e4SLinus Torvalds 
6231da177e4SLinus Torvalds /*
6241da177e4SLinus Torvalds  * i8042_check_aux() applies as much paranoia as it can at detecting
6251da177e4SLinus Torvalds  * the presence of an AUX interface.
6261da177e4SLinus Torvalds  */
6271da177e4SLinus Torvalds 
62887fd6318SDmitry Torokhov static int __devinit i8042_check_aux(void)
6291da177e4SLinus Torvalds {
630de9ce703SDmitry Torokhov 	int retval = -1;
631de9ce703SDmitry Torokhov 	int irq_registered = 0;
6321e4865f8SDmitry Torokhov 	int aux_loop_broken = 0;
633de9ce703SDmitry Torokhov 	unsigned long flags;
6341da177e4SLinus Torvalds 	unsigned char param;
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds /*
6371da177e4SLinus Torvalds  * Get rid of bytes in the queue.
6381da177e4SLinus Torvalds  */
6391da177e4SLinus Torvalds 
6401da177e4SLinus Torvalds 	i8042_flush();
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds /*
6431da177e4SLinus Torvalds  * Internal loopback test - filters out AT-type i8042's. Unfortunately
6441da177e4SLinus Torvalds  * SiS screwed up and their 5597 doesn't support the LOOP command even
6451da177e4SLinus Torvalds  * though it has an AUX port.
6461da177e4SLinus Torvalds  */
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds 	param = 0x5a;
6493ca5de6dSDmitry Torokhov 	retval = i8042_command(&param, I8042_CMD_AUX_LOOP);
6503ca5de6dSDmitry Torokhov 	if (retval || param != 0x5a) {
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds /*
6531da177e4SLinus Torvalds  * External connection test - filters out AT-soldered PS/2 i8042's
6541da177e4SLinus Torvalds  * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error
6551da177e4SLinus Torvalds  * 0xfa - no error on some notebooks which ignore the spec
6561da177e4SLinus Torvalds  * Because it's common for chipsets to return error on perfectly functioning
6571da177e4SLinus Torvalds  * AUX ports, we test for this only when the LOOP command failed.
6581da177e4SLinus Torvalds  */
6591da177e4SLinus Torvalds 
660de9ce703SDmitry Torokhov 		if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
661de9ce703SDmitry Torokhov 		    (param && param != 0xfa && param != 0xff))
6621da177e4SLinus Torvalds 			return -1;
6631e4865f8SDmitry Torokhov 
6643ca5de6dSDmitry Torokhov /*
6653ca5de6dSDmitry Torokhov  * If AUX_LOOP completed without error but returned unexpected data
6663ca5de6dSDmitry Torokhov  * mark it as broken
6673ca5de6dSDmitry Torokhov  */
6683ca5de6dSDmitry Torokhov 		if (!retval)
6691e4865f8SDmitry Torokhov 			aux_loop_broken = 1;
6701da177e4SLinus Torvalds 	}
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds /*
6731da177e4SLinus Torvalds  * Bit assignment test - filters out PS/2 i8042's in AT mode
6741da177e4SLinus Torvalds  */
6751da177e4SLinus Torvalds 
676d2ada559SRoland Scheidegger 	if (i8042_toggle_aux(0)) {
6771da177e4SLinus Torvalds 		printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
6781da177e4SLinus Torvalds 		printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n");
6791da177e4SLinus Torvalds 	}
6801da177e4SLinus Torvalds 
681d2ada559SRoland Scheidegger 	if (i8042_toggle_aux(1))
6821da177e4SLinus Torvalds 		return -1;
6831da177e4SLinus Torvalds 
6841da177e4SLinus Torvalds /*
685de9ce703SDmitry Torokhov  * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and
686de9ce703SDmitry Torokhov  * used it for a PCI card or somethig else.
687de9ce703SDmitry Torokhov  */
688de9ce703SDmitry Torokhov 
6891c7827aeSDmitry Torokhov 	if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) {
690de9ce703SDmitry Torokhov /*
691de9ce703SDmitry Torokhov  * Without LOOP command we can't test AUX IRQ delivery. Assume the port
692de9ce703SDmitry Torokhov  * is working and hope we are right.
693de9ce703SDmitry Torokhov  */
694de9ce703SDmitry Torokhov 		retval = 0;
695de9ce703SDmitry Torokhov 		goto out;
696de9ce703SDmitry Torokhov 	}
697de9ce703SDmitry Torokhov 
698de9ce703SDmitry Torokhov 	if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED,
699de9ce703SDmitry Torokhov 			"i8042", i8042_platform_device))
700de9ce703SDmitry Torokhov 		goto out;
701de9ce703SDmitry Torokhov 
702de9ce703SDmitry Torokhov 	irq_registered = 1;
703de9ce703SDmitry Torokhov 
704de9ce703SDmitry Torokhov 	if (i8042_enable_aux_port())
705de9ce703SDmitry Torokhov 		goto out;
706de9ce703SDmitry Torokhov 
707de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
708de9ce703SDmitry Torokhov 
709de9ce703SDmitry Torokhov 	init_completion(&i8042_aux_irq_delivered);
710de9ce703SDmitry Torokhov 	i8042_irq_being_tested = 1;
711de9ce703SDmitry Torokhov 
712de9ce703SDmitry Torokhov 	param = 0xa5;
713de9ce703SDmitry Torokhov 	retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);
714de9ce703SDmitry Torokhov 
715de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
716de9ce703SDmitry Torokhov 
717de9ce703SDmitry Torokhov 	if (retval)
718de9ce703SDmitry Torokhov 		goto out;
719de9ce703SDmitry Torokhov 
720de9ce703SDmitry Torokhov 	if (wait_for_completion_timeout(&i8042_aux_irq_delivered,
721de9ce703SDmitry Torokhov 					msecs_to_jiffies(250)) == 0) {
722de9ce703SDmitry Torokhov /*
723de9ce703SDmitry Torokhov  * AUX IRQ was never delivered so we need to flush the controller to
724de9ce703SDmitry Torokhov  * get rid of the byte we put there; otherwise keyboard may not work.
725de9ce703SDmitry Torokhov  */
726de9ce703SDmitry Torokhov 		i8042_flush();
727de9ce703SDmitry Torokhov 		retval = -1;
728de9ce703SDmitry Torokhov 	}
729de9ce703SDmitry Torokhov 
730de9ce703SDmitry Torokhov  out:
731de9ce703SDmitry Torokhov 
732de9ce703SDmitry Torokhov /*
7331da177e4SLinus Torvalds  * Disable the interface.
7341da177e4SLinus Torvalds  */
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_AUXDIS;
7371da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_AUXINT;
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
740de9ce703SDmitry Torokhov 		retval = -1;
741de9ce703SDmitry Torokhov 
742de9ce703SDmitry Torokhov 	if (irq_registered)
743de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
744de9ce703SDmitry Torokhov 
745de9ce703SDmitry Torokhov 	return retval;
746de9ce703SDmitry Torokhov }
747de9ce703SDmitry Torokhov 
748de9ce703SDmitry Torokhov static int i8042_controller_check(void)
749de9ce703SDmitry Torokhov {
750de9ce703SDmitry Torokhov 	if (i8042_flush() == I8042_BUFFER_SIZE) {
751de9ce703SDmitry Torokhov 		printk(KERN_ERR "i8042.c: No controller found.\n");
752de9ce703SDmitry Torokhov 		return -ENODEV;
753de9ce703SDmitry Torokhov 	}
7541da177e4SLinus Torvalds 
7551da177e4SLinus Torvalds 	return 0;
7561da177e4SLinus Torvalds }
7571da177e4SLinus Torvalds 
758de9ce703SDmitry Torokhov static int i8042_controller_selftest(void)
7592673c836SVojtech Pavlik {
7602673c836SVojtech Pavlik 	unsigned char param;
7615ea2fc64SArjan van de Ven 	int i = 0;
7622673c836SVojtech Pavlik 
7632673c836SVojtech Pavlik 	if (!i8042_reset)
7642673c836SVojtech Pavlik 		return 0;
7652673c836SVojtech Pavlik 
7665ea2fc64SArjan van de Ven 	/*
7675ea2fc64SArjan van de Ven 	 * We try this 5 times; on some really fragile systems this does not
7685ea2fc64SArjan van de Ven 	 * take the first time...
7695ea2fc64SArjan van de Ven 	 */
7705ea2fc64SArjan van de Ven 	do {
7715ea2fc64SArjan van de Ven 
7722673c836SVojtech Pavlik 		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
7732673c836SVojtech Pavlik 			printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
774de9ce703SDmitry Torokhov 			return -ENODEV;
7752673c836SVojtech Pavlik 		}
7762673c836SVojtech Pavlik 
7775ea2fc64SArjan van de Ven 		if (param == I8042_RET_CTL_TEST)
7785ea2fc64SArjan van de Ven 			return 0;
7795ea2fc64SArjan van de Ven 
7802673c836SVojtech Pavlik 		printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
7812673c836SVojtech Pavlik 			param, I8042_RET_CTL_TEST);
7825ea2fc64SArjan van de Ven 		msleep(50);
7835ea2fc64SArjan van de Ven 	} while (i++ < 5);
7842673c836SVojtech Pavlik 
7855ea2fc64SArjan van de Ven #ifdef CONFIG_X86
7865ea2fc64SArjan van de Ven 	/*
7875ea2fc64SArjan van de Ven 	 * On x86, we don't fail entire i8042 initialization if controller
7885ea2fc64SArjan van de Ven 	 * reset fails in hopes that keyboard port will still be functional
7895ea2fc64SArjan van de Ven 	 * and user will still get a working keyboard. This is especially
7905ea2fc64SArjan van de Ven 	 * important on netbooks. On other arches we trust hardware more.
7915ea2fc64SArjan van de Ven 	 */
7925ea2fc64SArjan van de Ven 	printk(KERN_INFO
7935ea2fc64SArjan van de Ven 		"i8042: giving up on controller selftest, continuing anyway...\n");
7942673c836SVojtech Pavlik 	return 0;
7955ea2fc64SArjan van de Ven #else
7965ea2fc64SArjan van de Ven 	return -EIO;
7975ea2fc64SArjan van de Ven #endif
7982673c836SVojtech Pavlik }
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds /*
8011da177e4SLinus Torvalds  * i8042_controller init initializes the i8042 controller, and,
8021da177e4SLinus Torvalds  * most importantly, sets it into non-xlated mode if that's
8031da177e4SLinus Torvalds  * desired.
8041da177e4SLinus Torvalds  */
8051da177e4SLinus Torvalds 
8061da177e4SLinus Torvalds static int i8042_controller_init(void)
8071da177e4SLinus Torvalds {
8081da177e4SLinus Torvalds 	unsigned long flags;
8091da177e4SLinus Torvalds 
8101da177e4SLinus Torvalds /*
8111da177e4SLinus Torvalds  * Save the CTR for restoral on unload / reboot.
8121da177e4SLinus Torvalds  */
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
8151da177e4SLinus Torvalds 		printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n");
816de9ce703SDmitry Torokhov 		return -EIO;
8171da177e4SLinus Torvalds 	}
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	i8042_initial_ctr = i8042_ctr;
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds /*
8221da177e4SLinus Torvalds  * Disable the keyboard interface and interrupt.
8231da177e4SLinus Torvalds  */
8241da177e4SLinus Torvalds 
8251da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_KBDDIS;
8261da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_KBDINT;
8271da177e4SLinus Torvalds 
8281da177e4SLinus Torvalds /*
8291da177e4SLinus Torvalds  * Handle keylock.
8301da177e4SLinus Torvalds  */
8311da177e4SLinus Torvalds 
8321da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
8331da177e4SLinus Torvalds 	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
8341da177e4SLinus Torvalds 		if (i8042_unlock)
8351da177e4SLinus Torvalds 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
8361da177e4SLinus Torvalds 		else
8371da177e4SLinus Torvalds 			printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
8381da177e4SLinus Torvalds 	}
8391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
8401da177e4SLinus Torvalds 
8411da177e4SLinus Torvalds /*
8421da177e4SLinus Torvalds  * If the chip is configured into nontranslated mode by the BIOS, don't
8431da177e4SLinus Torvalds  * bother enabling translating and be happy.
8441da177e4SLinus Torvalds  */
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds 	if (~i8042_ctr & I8042_CTR_XLATE)
8471da177e4SLinus Torvalds 		i8042_direct = 1;
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds /*
8501da177e4SLinus Torvalds  * Set nontranslated mode for the kbd interface if requested by an option.
8511da177e4SLinus Torvalds  * After this the kbd interface becomes a simple serial in/out, like the aux
8521da177e4SLinus Torvalds  * interface is. We don't do this by default, since it can confuse notebook
8531da177e4SLinus Torvalds  * BIOSes.
8541da177e4SLinus Torvalds  */
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds 	if (i8042_direct)
8571da177e4SLinus Torvalds 		i8042_ctr &= ~I8042_CTR_XLATE;
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds /*
8601da177e4SLinus Torvalds  * Write CTR back.
8611da177e4SLinus Torvalds  */
8621da177e4SLinus Torvalds 
8631da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
8641da177e4SLinus Torvalds 		printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
865de9ce703SDmitry Torokhov 		return -EIO;
8661da177e4SLinus Torvalds 	}
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds 	return 0;
8691da177e4SLinus Torvalds }
8701da177e4SLinus Torvalds 
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds /*
873de9ce703SDmitry Torokhov  * Reset the controller and reset CRT to the original value set by BIOS.
8741da177e4SLinus Torvalds  */
8751da177e4SLinus Torvalds 
876de9ce703SDmitry Torokhov static void i8042_controller_reset(void)
877de9ce703SDmitry Torokhov {
878de9ce703SDmitry Torokhov 	i8042_flush();
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds /*
8818d04ddb6SDmitry Torokhov  * Disable both KBD and AUX interfaces so they don't get in the way
8828d04ddb6SDmitry Torokhov  */
8838d04ddb6SDmitry Torokhov 
8848d04ddb6SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
8858d04ddb6SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
8868d04ddb6SDmitry Torokhov 
887*5ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
888*5ddbc77cSDmitry Torokhov 		printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n");
889*5ddbc77cSDmitry Torokhov 
8908d04ddb6SDmitry Torokhov /*
8911da177e4SLinus Torvalds  * Disable MUX mode if present.
8921da177e4SLinus Torvalds  */
8931da177e4SLinus Torvalds 
8941da177e4SLinus Torvalds 	if (i8042_mux_present)
8951da177e4SLinus Torvalds 		i8042_set_mux_mode(0, NULL);
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds /*
898de9ce703SDmitry Torokhov  * Reset the controller if requested.
899de9ce703SDmitry Torokhov  */
900de9ce703SDmitry Torokhov 
901de9ce703SDmitry Torokhov 	i8042_controller_selftest();
902de9ce703SDmitry Torokhov 
903de9ce703SDmitry Torokhov /*
9041da177e4SLinus Torvalds  * Restore the original control register setting.
9051da177e4SLinus Torvalds  */
9061da177e4SLinus Torvalds 
907de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
9081da177e4SLinus Torvalds 		printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
9091da177e4SLinus Torvalds }
9101da177e4SLinus Torvalds 
9111da177e4SLinus Torvalds 
9121da177e4SLinus Torvalds /*
9131da177e4SLinus Torvalds  * i8042_panic_blink() will flash the keyboard LEDs and is called when
9141da177e4SLinus Torvalds  * kernel panics. Flashing LEDs is useful for users running X who may
9151da177e4SLinus Torvalds  * not see the console and will help distingushing panics from "real"
9161da177e4SLinus Torvalds  * lockups.
9171da177e4SLinus Torvalds  *
9181da177e4SLinus Torvalds  * Note that DELAY has a limit of 10ms so we will not get stuck here
9191da177e4SLinus Torvalds  * waiting for KBC to free up even if KBD interrupt is off
9201da177e4SLinus Torvalds  */
9211da177e4SLinus Torvalds 
9221da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
9231da177e4SLinus Torvalds 
9241da177e4SLinus Torvalds static long i8042_panic_blink(long count)
9251da177e4SLinus Torvalds {
9261da177e4SLinus Torvalds 	long delay = 0;
9271da177e4SLinus Torvalds 	static long last_blink;
9281da177e4SLinus Torvalds 	static char led;
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 	/*
9311da177e4SLinus Torvalds 	 * We expect frequency to be about 1/2s. KDB uses about 1s.
9321da177e4SLinus Torvalds 	 * Make sure they are different.
9331da177e4SLinus Torvalds 	 */
9341da177e4SLinus Torvalds 	if (!i8042_blink_frequency)
9351da177e4SLinus Torvalds 		return 0;
9361da177e4SLinus Torvalds 	if (count - last_blink < i8042_blink_frequency)
9371da177e4SLinus Torvalds 		return 0;
9381da177e4SLinus Torvalds 
9391da177e4SLinus Torvalds 	led ^= 0x01 | 0x04;
9401da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
9411da177e4SLinus Torvalds 		DELAY;
94219f3c3e3SDmitry Torokhov 	dbg("%02x -> i8042 (panic blink)", 0xed);
94319f3c3e3SDmitry Torokhov 	i8042_suppress_kbd_ack = 2;
9441da177e4SLinus Torvalds 	i8042_write_data(0xed); /* set leds */
9451da177e4SLinus Torvalds 	DELAY;
9461da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
9471da177e4SLinus Torvalds 		DELAY;
9481da177e4SLinus Torvalds 	DELAY;
94919f3c3e3SDmitry Torokhov 	dbg("%02x -> i8042 (panic blink)", led);
9501da177e4SLinus Torvalds 	i8042_write_data(led);
9511da177e4SLinus Torvalds 	DELAY;
9521da177e4SLinus Torvalds 	last_blink = count;
9531da177e4SLinus Torvalds 	return delay;
9541da177e4SLinus Torvalds }
9551da177e4SLinus Torvalds 
9561da177e4SLinus Torvalds #undef DELAY
9571da177e4SLinus Torvalds 
958d35895dbSBruno Prémont #ifdef CONFIG_X86
959d35895dbSBruno Prémont static void i8042_dritek_enable(void)
960d35895dbSBruno Prémont {
961d35895dbSBruno Prémont 	char param = 0x90;
962d35895dbSBruno Prémont 	int error;
963d35895dbSBruno Prémont 
964d35895dbSBruno Prémont 	error = i8042_command(&param, 0x1059);
965d35895dbSBruno Prémont 	if (error)
966d35895dbSBruno Prémont 		printk(KERN_WARNING
967d35895dbSBruno Prémont 			"Failed to enable DRITEK extension: %d\n",
968d35895dbSBruno Prémont 			error);
969d35895dbSBruno Prémont }
970d35895dbSBruno Prémont #endif
971d35895dbSBruno Prémont 
97282dd9effSDmitry Torokhov #ifdef CONFIG_PM
9737e044e05SDmitry Torokhov 
9741da177e4SLinus Torvalds /*
975ebd7768dSDmitry Torokhov  * Here we try to restore the original BIOS settings to avoid
976ebd7768dSDmitry Torokhov  * upsetting it.
9771da177e4SLinus Torvalds  */
9781da177e4SLinus Torvalds 
979ebd7768dSDmitry Torokhov static int i8042_pm_reset(struct device *dev)
9801da177e4SLinus Torvalds {
98182dd9effSDmitry Torokhov 	i8042_controller_reset();
982ddaa4343SThadeu Lima de Souza Cascardo 
9831da177e4SLinus Torvalds 	return 0;
9841da177e4SLinus Torvalds }
9851da177e4SLinus Torvalds 
9861da177e4SLinus Torvalds /*
987ebd7768dSDmitry Torokhov  * Here we try to reset everything back to a state we had
988ebd7768dSDmitry Torokhov  * before suspending.
9891da177e4SLinus Torvalds  */
9901da177e4SLinus Torvalds 
991ebd7768dSDmitry Torokhov static int i8042_pm_restore(struct device *dev)
9921da177e4SLinus Torvalds {
993de9ce703SDmitry Torokhov 	int error;
9941da177e4SLinus Torvalds 
995de9ce703SDmitry Torokhov 	error = i8042_controller_check();
996de9ce703SDmitry Torokhov 	if (error)
997de9ce703SDmitry Torokhov 		return error;
9982673c836SVojtech Pavlik 
999de9ce703SDmitry Torokhov 	error = i8042_controller_selftest();
1000de9ce703SDmitry Torokhov 	if (error)
1001de9ce703SDmitry Torokhov 		return error;
1002de9ce703SDmitry Torokhov 
1003de9ce703SDmitry Torokhov /*
100482dd9effSDmitry Torokhov  * Restore original CTR value and disable all ports
1005de9ce703SDmitry Torokhov  */
1006de9ce703SDmitry Torokhov 
100782dd9effSDmitry Torokhov 	i8042_ctr = i8042_initial_ctr;
100882dd9effSDmitry Torokhov 	if (i8042_direct)
100982dd9effSDmitry Torokhov 		i8042_ctr &= ~I8042_CTR_XLATE;
1010de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
1011de9ce703SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
10122673c836SVojtech Pavlik 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
10132f6a77d5SJiri Kosina 		printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n");
10142f6a77d5SJiri Kosina 		msleep(50);
10152f6a77d5SJiri Kosina 		if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
10162f6a77d5SJiri Kosina 			printk(KERN_ERR "i8042: CTR write retry failed\n");
1017de9ce703SDmitry Torokhov 			return -EIO;
10181da177e4SLinus Torvalds 		}
10192f6a77d5SJiri Kosina 	}
10201da177e4SLinus Torvalds 
1021d35895dbSBruno Prémont 
1022d35895dbSBruno Prémont #ifdef CONFIG_X86
1023d35895dbSBruno Prémont 	if (i8042_dritek)
1024d35895dbSBruno Prémont 		i8042_dritek_enable();
1025d35895dbSBruno Prémont #endif
1026d35895dbSBruno Prémont 
1027de9ce703SDmitry Torokhov 	if (i8042_mux_present) {
10281da177e4SLinus Torvalds 		if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())
1029de9ce703SDmitry Torokhov 			printk(KERN_WARNING
1030de9ce703SDmitry Torokhov 				"i8042: failed to resume active multiplexor, "
1031de9ce703SDmitry Torokhov 				"mouse won't work.\n");
1032de9ce703SDmitry Torokhov 	} else if (i8042_ports[I8042_AUX_PORT_NO].serio)
1033de9ce703SDmitry Torokhov 		i8042_enable_aux_port();
10341da177e4SLinus Torvalds 
1035de9ce703SDmitry Torokhov 	if (i8042_ports[I8042_KBD_PORT_NO].serio)
1036de9ce703SDmitry Torokhov 		i8042_enable_kbd_port();
10371da177e4SLinus Torvalds 
10387d12e780SDavid Howells 	i8042_interrupt(0, NULL);
10391da177e4SLinus Torvalds 
10401da177e4SLinus Torvalds 	return 0;
10411da177e4SLinus Torvalds }
1042ebd7768dSDmitry Torokhov 
1043ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = {
1044ebd7768dSDmitry Torokhov 	.suspend	= i8042_pm_reset,
1045ebd7768dSDmitry Torokhov 	.resume		= i8042_pm_restore,
1046ebd7768dSDmitry Torokhov 	.poweroff	= i8042_pm_reset,
1047ebd7768dSDmitry Torokhov 	.restore	= i8042_pm_restore,
1048ebd7768dSDmitry Torokhov };
1049ebd7768dSDmitry Torokhov 
105082dd9effSDmitry Torokhov #endif /* CONFIG_PM */
10511da177e4SLinus Torvalds 
10521da177e4SLinus Torvalds /*
10531da177e4SLinus Torvalds  * We need to reset the 8042 back to original mode on system shutdown,
10541da177e4SLinus Torvalds  * because otherwise BIOSes will be confused.
10551da177e4SLinus Torvalds  */
10561da177e4SLinus Torvalds 
10573ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev)
10581da177e4SLinus Torvalds {
105982dd9effSDmitry Torokhov 	i8042_controller_reset();
10601da177e4SLinus Torvalds }
10611da177e4SLinus Torvalds 
106287fd6318SDmitry Torokhov static int __devinit i8042_create_kbd_port(void)
10631da177e4SLinus Torvalds {
10641da177e4SLinus Torvalds 	struct serio *serio;
10651da177e4SLinus Torvalds 	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
10661da177e4SLinus Torvalds 
1067d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
10680854e52dSDmitry Torokhov 	if (!serio)
10690854e52dSDmitry Torokhov 		return -ENOMEM;
10700854e52dSDmitry Torokhov 
10711da177e4SLinus Torvalds 	serio->id.type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL;
10721da177e4SLinus Torvalds 	serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write;
10731da177e4SLinus Torvalds 	serio->start		= i8042_start;
10741da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
1075*5ddbc77cSDmitry Torokhov 	serio->close		= i8042_port_close;
10761da177e4SLinus Torvalds 	serio->port_data	= port;
10771da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1078de9ce703SDmitry Torokhov 	strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
10791da177e4SLinus Torvalds 	strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
10801da177e4SLinus Torvalds 
10811da177e4SLinus Torvalds 	port->serio = serio;
1082de9ce703SDmitry Torokhov 	port->irq = I8042_KBD_IRQ;
10830854e52dSDmitry Torokhov 
1084de9ce703SDmitry Torokhov 	return 0;
10851da177e4SLinus Torvalds }
10861da177e4SLinus Torvalds 
1087de9ce703SDmitry Torokhov static int __devinit i8042_create_aux_port(int idx)
10881da177e4SLinus Torvalds {
10891da177e4SLinus Torvalds 	struct serio *serio;
1090de9ce703SDmitry Torokhov 	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
1091de9ce703SDmitry Torokhov 	struct i8042_port *port = &i8042_ports[port_no];
10921da177e4SLinus Torvalds 
1093d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
10940854e52dSDmitry Torokhov 	if (!serio)
10950854e52dSDmitry Torokhov 		return -ENOMEM;
10960854e52dSDmitry Torokhov 
10971da177e4SLinus Torvalds 	serio->id.type		= SERIO_8042;
10981da177e4SLinus Torvalds 	serio->write		= i8042_aux_write;
10991da177e4SLinus Torvalds 	serio->start		= i8042_start;
11001da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
11011da177e4SLinus Torvalds 	serio->port_data	= port;
11021da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1103de9ce703SDmitry Torokhov 	if (idx < 0) {
1104de9ce703SDmitry Torokhov 		strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));
11051da177e4SLinus Torvalds 		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
1106*5ddbc77cSDmitry Torokhov 		serio->close = i8042_port_close;
1107de9ce703SDmitry Torokhov 	} else {
1108de9ce703SDmitry Torokhov 		snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
1109de9ce703SDmitry Torokhov 		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
11101da177e4SLinus Torvalds 	}
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 	port->serio = serio;
1113de9ce703SDmitry Torokhov 	port->mux = idx;
1114de9ce703SDmitry Torokhov 	port->irq = I8042_AUX_IRQ;
11150854e52dSDmitry Torokhov 
1116de9ce703SDmitry Torokhov 	return 0;
1117de9ce703SDmitry Torokhov }
1118de9ce703SDmitry Torokhov 
1119de9ce703SDmitry Torokhov static void __devinit i8042_free_kbd_port(void)
1120de9ce703SDmitry Torokhov {
1121de9ce703SDmitry Torokhov 	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
1122de9ce703SDmitry Torokhov 	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
1123de9ce703SDmitry Torokhov }
1124de9ce703SDmitry Torokhov 
1125de9ce703SDmitry Torokhov static void __devinit i8042_free_aux_ports(void)
1126de9ce703SDmitry Torokhov {
1127de9ce703SDmitry Torokhov 	int i;
1128de9ce703SDmitry Torokhov 
1129de9ce703SDmitry Torokhov 	for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) {
1130de9ce703SDmitry Torokhov 		kfree(i8042_ports[i].serio);
1131de9ce703SDmitry Torokhov 		i8042_ports[i].serio = NULL;
1132de9ce703SDmitry Torokhov 	}
1133de9ce703SDmitry Torokhov }
1134de9ce703SDmitry Torokhov 
1135de9ce703SDmitry Torokhov static void __devinit i8042_register_ports(void)
1136de9ce703SDmitry Torokhov {
1137de9ce703SDmitry Torokhov 	int i;
1138de9ce703SDmitry Torokhov 
1139de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1140de9ce703SDmitry Torokhov 		if (i8042_ports[i].serio) {
1141de9ce703SDmitry Torokhov 			printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
1142de9ce703SDmitry Torokhov 				i8042_ports[i].serio->name,
1143de9ce703SDmitry Torokhov 				(unsigned long) I8042_DATA_REG,
1144de9ce703SDmitry Torokhov 				(unsigned long) I8042_COMMAND_REG,
1145de9ce703SDmitry Torokhov 				i8042_ports[i].irq);
1146de9ce703SDmitry Torokhov 			serio_register_port(i8042_ports[i].serio);
1147de9ce703SDmitry Torokhov 		}
1148de9ce703SDmitry Torokhov 	}
1149de9ce703SDmitry Torokhov }
1150de9ce703SDmitry Torokhov 
11517a1904c3SRalf Baechle static void __devexit i8042_unregister_ports(void)
1152de9ce703SDmitry Torokhov {
1153de9ce703SDmitry Torokhov 	int i;
1154de9ce703SDmitry Torokhov 
1155de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1156de9ce703SDmitry Torokhov 		if (i8042_ports[i].serio) {
1157de9ce703SDmitry Torokhov 			serio_unregister_port(i8042_ports[i].serio);
1158de9ce703SDmitry Torokhov 			i8042_ports[i].serio = NULL;
1159de9ce703SDmitry Torokhov 		}
1160de9ce703SDmitry Torokhov 	}
1161de9ce703SDmitry Torokhov }
1162de9ce703SDmitry Torokhov 
1163de9ce703SDmitry Torokhov static void i8042_free_irqs(void)
1164de9ce703SDmitry Torokhov {
1165de9ce703SDmitry Torokhov 	if (i8042_aux_irq_registered)
1166de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
1167de9ce703SDmitry Torokhov 	if (i8042_kbd_irq_registered)
1168de9ce703SDmitry Torokhov 		free_irq(I8042_KBD_IRQ, i8042_platform_device);
1169de9ce703SDmitry Torokhov 
1170de9ce703SDmitry Torokhov 	i8042_aux_irq_registered = i8042_kbd_irq_registered = 0;
1171de9ce703SDmitry Torokhov }
1172de9ce703SDmitry Torokhov 
1173de9ce703SDmitry Torokhov static int __devinit i8042_setup_aux(void)
1174de9ce703SDmitry Torokhov {
1175de9ce703SDmitry Torokhov 	int (*aux_enable)(void);
1176de9ce703SDmitry Torokhov 	int error;
1177de9ce703SDmitry Torokhov 	int i;
1178de9ce703SDmitry Torokhov 
1179de9ce703SDmitry Torokhov 	if (i8042_check_aux())
1180de9ce703SDmitry Torokhov 		return -ENODEV;
1181de9ce703SDmitry Torokhov 
1182de9ce703SDmitry Torokhov 	if (i8042_nomux || i8042_check_mux()) {
1183de9ce703SDmitry Torokhov 		error = i8042_create_aux_port(-1);
1184de9ce703SDmitry Torokhov 		if (error)
1185de9ce703SDmitry Torokhov 			goto err_free_ports;
1186de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_aux_port;
1187de9ce703SDmitry Torokhov 	} else {
1188de9ce703SDmitry Torokhov 		for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
1189de9ce703SDmitry Torokhov 			error = i8042_create_aux_port(i);
1190de9ce703SDmitry Torokhov 			if (error)
1191de9ce703SDmitry Torokhov 				goto err_free_ports;
1192de9ce703SDmitry Torokhov 		}
1193de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_mux_ports;
1194de9ce703SDmitry Torokhov 	}
1195de9ce703SDmitry Torokhov 
1196de9ce703SDmitry Torokhov 	error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED,
1197de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1198de9ce703SDmitry Torokhov 	if (error)
1199de9ce703SDmitry Torokhov 		goto err_free_ports;
1200de9ce703SDmitry Torokhov 
1201de9ce703SDmitry Torokhov 	if (aux_enable())
1202de9ce703SDmitry Torokhov 		goto err_free_irq;
1203de9ce703SDmitry Torokhov 
1204de9ce703SDmitry Torokhov 	i8042_aux_irq_registered = 1;
1205de9ce703SDmitry Torokhov 	return 0;
1206de9ce703SDmitry Torokhov 
1207de9ce703SDmitry Torokhov  err_free_irq:
1208de9ce703SDmitry Torokhov 	free_irq(I8042_AUX_IRQ, i8042_platform_device);
1209de9ce703SDmitry Torokhov  err_free_ports:
1210de9ce703SDmitry Torokhov 	i8042_free_aux_ports();
1211de9ce703SDmitry Torokhov 	return error;
1212de9ce703SDmitry Torokhov }
1213de9ce703SDmitry Torokhov 
1214de9ce703SDmitry Torokhov static int __devinit i8042_setup_kbd(void)
1215de9ce703SDmitry Torokhov {
1216de9ce703SDmitry Torokhov 	int error;
1217de9ce703SDmitry Torokhov 
1218de9ce703SDmitry Torokhov 	error = i8042_create_kbd_port();
1219de9ce703SDmitry Torokhov 	if (error)
1220de9ce703SDmitry Torokhov 		return error;
1221de9ce703SDmitry Torokhov 
1222de9ce703SDmitry Torokhov 	error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
1223de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1224de9ce703SDmitry Torokhov 	if (error)
1225de9ce703SDmitry Torokhov 		goto err_free_port;
1226de9ce703SDmitry Torokhov 
1227de9ce703SDmitry Torokhov 	error = i8042_enable_kbd_port();
1228de9ce703SDmitry Torokhov 	if (error)
1229de9ce703SDmitry Torokhov 		goto err_free_irq;
1230de9ce703SDmitry Torokhov 
1231de9ce703SDmitry Torokhov 	i8042_kbd_irq_registered = 1;
1232de9ce703SDmitry Torokhov 	return 0;
1233de9ce703SDmitry Torokhov 
1234de9ce703SDmitry Torokhov  err_free_irq:
1235de9ce703SDmitry Torokhov 	free_irq(I8042_KBD_IRQ, i8042_platform_device);
1236de9ce703SDmitry Torokhov  err_free_port:
1237de9ce703SDmitry Torokhov 	i8042_free_kbd_port();
1238de9ce703SDmitry Torokhov 	return error;
12391da177e4SLinus Torvalds }
12401da177e4SLinus Torvalds 
124187fd6318SDmitry Torokhov static int __devinit i8042_probe(struct platform_device *dev)
12421da177e4SLinus Torvalds {
1243de9ce703SDmitry Torokhov 	int error;
12441da177e4SLinus Torvalds 
1245de9ce703SDmitry Torokhov 	error = i8042_controller_selftest();
1246de9ce703SDmitry Torokhov 	if (error)
1247de9ce703SDmitry Torokhov 		return error;
12481da177e4SLinus Torvalds 
1249de9ce703SDmitry Torokhov 	error = i8042_controller_init();
1250de9ce703SDmitry Torokhov 	if (error)
1251de9ce703SDmitry Torokhov 		return error;
12521da177e4SLinus Torvalds 
1253d35895dbSBruno Prémont #ifdef CONFIG_X86
1254d35895dbSBruno Prémont 	if (i8042_dritek)
1255d35895dbSBruno Prémont 		i8042_dritek_enable();
1256d35895dbSBruno Prémont #endif
1257d35895dbSBruno Prémont 
1258de9ce703SDmitry Torokhov 	if (!i8042_noaux) {
1259de9ce703SDmitry Torokhov 		error = i8042_setup_aux();
1260de9ce703SDmitry Torokhov 		if (error && error != -ENODEV && error != -EBUSY)
1261de9ce703SDmitry Torokhov 			goto out_fail;
12621da177e4SLinus Torvalds 	}
12631da177e4SLinus Torvalds 
1264945ef0d4SDmitry Torokhov 	if (!i8042_nokbd) {
1265de9ce703SDmitry Torokhov 		error = i8042_setup_kbd();
1266de9ce703SDmitry Torokhov 		if (error)
1267de9ce703SDmitry Torokhov 			goto out_fail;
1268945ef0d4SDmitry Torokhov 	}
1269de9ce703SDmitry Torokhov /*
1270de9ce703SDmitry Torokhov  * Ok, everything is ready, let's register all serio ports
1271de9ce703SDmitry Torokhov  */
1272de9ce703SDmitry Torokhov 	i8042_register_ports();
12731da177e4SLinus Torvalds 
12741da177e4SLinus Torvalds 	return 0;
12750854e52dSDmitry Torokhov 
1276de9ce703SDmitry Torokhov  out_fail:
1277de9ce703SDmitry Torokhov 	i8042_free_aux_ports();	/* in case KBD failed but AUX not */
1278de9ce703SDmitry Torokhov 	i8042_free_irqs();
1279de9ce703SDmitry Torokhov 	i8042_controller_reset();
12800854e52dSDmitry Torokhov 
1281de9ce703SDmitry Torokhov 	return error;
12821da177e4SLinus Torvalds }
12831da177e4SLinus Torvalds 
128487fd6318SDmitry Torokhov static int __devexit i8042_remove(struct platform_device *dev)
12851da177e4SLinus Torvalds {
1286de9ce703SDmitry Torokhov 	i8042_unregister_ports();
1287de9ce703SDmitry Torokhov 	i8042_free_irqs();
1288de9ce703SDmitry Torokhov 	i8042_controller_reset();
12891da177e4SLinus Torvalds 
129087fd6318SDmitry Torokhov 	return 0;
129187fd6318SDmitry Torokhov }
129287fd6318SDmitry Torokhov 
129387fd6318SDmitry Torokhov static struct platform_driver i8042_driver = {
129487fd6318SDmitry Torokhov 	.driver		= {
129587fd6318SDmitry Torokhov 		.name	= "i8042",
129687fd6318SDmitry Torokhov 		.owner	= THIS_MODULE,
1297ebd7768dSDmitry Torokhov #ifdef CONFIG_PM
1298ebd7768dSDmitry Torokhov 		.pm	= &i8042_pm_ops,
1299ebd7768dSDmitry Torokhov #endif
130087fd6318SDmitry Torokhov 	},
130187fd6318SDmitry Torokhov 	.probe		= i8042_probe,
130287fd6318SDmitry Torokhov 	.remove		= __devexit_p(i8042_remove),
130382dd9effSDmitry Torokhov 	.shutdown	= i8042_shutdown,
130487fd6318SDmitry Torokhov };
130587fd6318SDmitry Torokhov 
130687fd6318SDmitry Torokhov static int __init i8042_init(void)
130787fd6318SDmitry Torokhov {
130887fd6318SDmitry Torokhov 	int err;
130987fd6318SDmitry Torokhov 
131087fd6318SDmitry Torokhov 	dbg_init();
131187fd6318SDmitry Torokhov 
131287fd6318SDmitry Torokhov 	err = i8042_platform_init();
131387fd6318SDmitry Torokhov 	if (err)
131487fd6318SDmitry Torokhov 		return err;
131587fd6318SDmitry Torokhov 
1316de9ce703SDmitry Torokhov 	err = i8042_controller_check();
1317de9ce703SDmitry Torokhov 	if (err)
1318de9ce703SDmitry Torokhov 		goto err_platform_exit;
131987fd6318SDmitry Torokhov 
132087fd6318SDmitry Torokhov 	err = platform_driver_register(&i8042_driver);
132187fd6318SDmitry Torokhov 	if (err)
132287fd6318SDmitry Torokhov 		goto err_platform_exit;
132387fd6318SDmitry Torokhov 
132487fd6318SDmitry Torokhov 	i8042_platform_device = platform_device_alloc("i8042", -1);
132587fd6318SDmitry Torokhov 	if (!i8042_platform_device) {
132687fd6318SDmitry Torokhov 		err = -ENOMEM;
132787fd6318SDmitry Torokhov 		goto err_unregister_driver;
132887fd6318SDmitry Torokhov 	}
132987fd6318SDmitry Torokhov 
133087fd6318SDmitry Torokhov 	err = platform_device_add(i8042_platform_device);
133187fd6318SDmitry Torokhov 	if (err)
133287fd6318SDmitry Torokhov 		goto err_free_device;
133387fd6318SDmitry Torokhov 
1334de9ce703SDmitry Torokhov 	panic_blink = i8042_panic_blink;
1335de9ce703SDmitry Torokhov 
133687fd6318SDmitry Torokhov 	return 0;
133787fd6318SDmitry Torokhov 
133887fd6318SDmitry Torokhov  err_free_device:
133987fd6318SDmitry Torokhov 	platform_device_put(i8042_platform_device);
134087fd6318SDmitry Torokhov  err_unregister_driver:
134187fd6318SDmitry Torokhov 	platform_driver_unregister(&i8042_driver);
134287fd6318SDmitry Torokhov  err_platform_exit:
134387fd6318SDmitry Torokhov 	i8042_platform_exit();
134487fd6318SDmitry Torokhov 
134587fd6318SDmitry Torokhov 	return err;
134687fd6318SDmitry Torokhov }
134787fd6318SDmitry Torokhov 
134887fd6318SDmitry Torokhov static void __exit i8042_exit(void)
134987fd6318SDmitry Torokhov {
13501da177e4SLinus Torvalds 	platform_device_unregister(i8042_platform_device);
13513ae5eaecSRussell King 	platform_driver_unregister(&i8042_driver);
13521da177e4SLinus Torvalds 	i8042_platform_exit();
13531da177e4SLinus Torvalds 
13541da177e4SLinus Torvalds 	panic_blink = NULL;
13551da177e4SLinus Torvalds }
13561da177e4SLinus Torvalds 
13571da177e4SLinus Torvalds module_init(i8042_init);
13581da177e4SLinus Torvalds module_exit(i8042_exit);
1359