xref: /linux/drivers/input/serio/i8042.c (revision af045b86662f17bf130239a65995c61a34f00a6b)
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>
245a0e3ad6STejun Heo #include <linux/slab.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include <asm/io.h>
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
291da177e4SLinus Torvalds MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
301da177e4SLinus Torvalds MODULE_LICENSE("GPL");
311da177e4SLinus Torvalds 
32386b3849SDmitry Torokhov static bool i8042_nokbd;
33945ef0d4SDmitry Torokhov module_param_named(nokbd, i8042_nokbd, bool, 0);
34945ef0d4SDmitry Torokhov MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
35945ef0d4SDmitry Torokhov 
36386b3849SDmitry Torokhov static bool i8042_noaux;
371da177e4SLinus Torvalds module_param_named(noaux, i8042_noaux, bool, 0);
381da177e4SLinus Torvalds MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
391da177e4SLinus Torvalds 
40386b3849SDmitry Torokhov static bool i8042_nomux;
411da177e4SLinus Torvalds module_param_named(nomux, i8042_nomux, bool, 0);
422c860a11SDominik Brodowski MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing controller is present.");
431da177e4SLinus Torvalds 
44386b3849SDmitry Torokhov static bool i8042_unlock;
451da177e4SLinus Torvalds module_param_named(unlock, i8042_unlock, bool, 0);
461da177e4SLinus Torvalds MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
471da177e4SLinus Torvalds 
48386b3849SDmitry Torokhov static bool i8042_reset;
491da177e4SLinus Torvalds module_param_named(reset, i8042_reset, bool, 0);
501da177e4SLinus Torvalds MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
511da177e4SLinus Torvalds 
52386b3849SDmitry Torokhov static bool i8042_direct;
531da177e4SLinus Torvalds module_param_named(direct, i8042_direct, bool, 0);
541da177e4SLinus Torvalds MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode.");
551da177e4SLinus Torvalds 
56386b3849SDmitry Torokhov static bool i8042_dumbkbd;
571da177e4SLinus Torvalds module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
581da177e4SLinus Torvalds MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
591da177e4SLinus Torvalds 
60386b3849SDmitry Torokhov static bool i8042_noloop;
611da177e4SLinus Torvalds module_param_named(noloop, i8042_noloop, bool, 0);
621da177e4SLinus Torvalds MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
631da177e4SLinus Torvalds 
648987fec0SCarlos Corbacho #ifdef CONFIG_X86
65386b3849SDmitry Torokhov static bool i8042_dritek;
668987fec0SCarlos Corbacho module_param_named(dritek, i8042_dritek, bool, 0);
678987fec0SCarlos Corbacho MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension");
688987fec0SCarlos Corbacho #endif
698987fec0SCarlos Corbacho 
701da177e4SLinus Torvalds #ifdef CONFIG_PNP
71386b3849SDmitry Torokhov static bool i8042_nopnp;
721da177e4SLinus Torvalds module_param_named(nopnp, i8042_nopnp, bool, 0);
731da177e4SLinus Torvalds MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
741da177e4SLinus Torvalds #endif
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds #define DEBUG
771da177e4SLinus Torvalds #ifdef DEBUG
78386b3849SDmitry Torokhov static bool i8042_debug;
791da177e4SLinus Torvalds module_param_named(debug, i8042_debug, bool, 0600);
801da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
811da177e4SLinus Torvalds #endif
821da177e4SLinus Torvalds 
831c7827aeSDmitry Torokhov static bool i8042_bypass_aux_irq_test;
841c7827aeSDmitry Torokhov 
851da177e4SLinus Torvalds #include "i8042.h"
861da177e4SLinus Torvalds 
87181d683dSDmitry Torokhov /*
88181d683dSDmitry Torokhov  * i8042_lock protects serialization between i8042_command and
89181d683dSDmitry Torokhov  * the interrupt handler.
90181d683dSDmitry Torokhov  */
911da177e4SLinus Torvalds static DEFINE_SPINLOCK(i8042_lock);
921da177e4SLinus Torvalds 
93181d683dSDmitry Torokhov /*
94181d683dSDmitry Torokhov  * Writers to AUX and KBD ports as well as users issuing i8042_command
95181d683dSDmitry Torokhov  * directly should acquire i8042_mutex (by means of calling
96181d683dSDmitry Torokhov  * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that
97181d683dSDmitry Torokhov  * they do not disturb each other (unfortunately in many i8042
98181d683dSDmitry Torokhov  * implementations write to one of the ports will immediately abort
99181d683dSDmitry Torokhov  * command that is being processed by another port).
100181d683dSDmitry Torokhov  */
101181d683dSDmitry Torokhov static DEFINE_MUTEX(i8042_mutex);
102181d683dSDmitry Torokhov 
1031da177e4SLinus Torvalds struct i8042_port {
1041da177e4SLinus Torvalds 	struct serio *serio;
1051da177e4SLinus Torvalds 	int irq;
106386b3849SDmitry Torokhov 	bool exists;
1071da177e4SLinus Torvalds 	signed char mux;
1081da177e4SLinus Torvalds };
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds #define I8042_KBD_PORT_NO	0
1111da177e4SLinus Torvalds #define I8042_AUX_PORT_NO	1
1121da177e4SLinus Torvalds #define I8042_MUX_PORT_NO	2
1131da177e4SLinus Torvalds #define I8042_NUM_PORTS		(I8042_NUM_MUX_PORTS + 2)
114de9ce703SDmitry Torokhov 
115de9ce703SDmitry Torokhov static struct i8042_port i8042_ports[I8042_NUM_PORTS];
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds static unsigned char i8042_initial_ctr;
1181da177e4SLinus Torvalds static unsigned char i8042_ctr;
119386b3849SDmitry Torokhov static bool i8042_mux_present;
120386b3849SDmitry Torokhov static bool i8042_kbd_irq_registered;
121386b3849SDmitry Torokhov static bool i8042_aux_irq_registered;
122817e6ba3SDmitry Torokhov static unsigned char i8042_suppress_kbd_ack;
1231da177e4SLinus Torvalds static struct platform_device *i8042_platform_device;
1241da177e4SLinus Torvalds 
1257d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id);
126967c9ef9SMatthew Garrett static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
127967c9ef9SMatthew Garrett 				     struct serio *serio);
1281da177e4SLinus Torvalds 
129181d683dSDmitry Torokhov void i8042_lock_chip(void)
130181d683dSDmitry Torokhov {
131181d683dSDmitry Torokhov 	mutex_lock(&i8042_mutex);
132181d683dSDmitry Torokhov }
133181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_lock_chip);
134181d683dSDmitry Torokhov 
135181d683dSDmitry Torokhov void i8042_unlock_chip(void)
136181d683dSDmitry Torokhov {
137181d683dSDmitry Torokhov 	mutex_unlock(&i8042_mutex);
138181d683dSDmitry Torokhov }
139181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_unlock_chip);
140181d683dSDmitry Torokhov 
141967c9ef9SMatthew Garrett int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
142967c9ef9SMatthew Garrett 					struct serio *serio))
143967c9ef9SMatthew Garrett {
144967c9ef9SMatthew Garrett 	unsigned long flags;
145967c9ef9SMatthew Garrett 	int ret = 0;
146967c9ef9SMatthew Garrett 
147967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
148967c9ef9SMatthew Garrett 
149967c9ef9SMatthew Garrett 	if (i8042_platform_filter) {
150967c9ef9SMatthew Garrett 		ret = -EBUSY;
151967c9ef9SMatthew Garrett 		goto out;
152967c9ef9SMatthew Garrett 	}
153967c9ef9SMatthew Garrett 
154967c9ef9SMatthew Garrett 	i8042_platform_filter = filter;
155967c9ef9SMatthew Garrett 
156967c9ef9SMatthew Garrett out:
157967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
158967c9ef9SMatthew Garrett 	return ret;
159967c9ef9SMatthew Garrett }
160967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_install_filter);
161967c9ef9SMatthew Garrett 
162967c9ef9SMatthew Garrett int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
163967c9ef9SMatthew Garrett 				       struct serio *port))
164967c9ef9SMatthew Garrett {
165967c9ef9SMatthew Garrett 	unsigned long flags;
166967c9ef9SMatthew Garrett 	int ret = 0;
167967c9ef9SMatthew Garrett 
168967c9ef9SMatthew Garrett 	spin_lock_irqsave(&i8042_lock, flags);
169967c9ef9SMatthew Garrett 
170967c9ef9SMatthew Garrett 	if (i8042_platform_filter != filter) {
171967c9ef9SMatthew Garrett 		ret = -EINVAL;
172967c9ef9SMatthew Garrett 		goto out;
173967c9ef9SMatthew Garrett 	}
174967c9ef9SMatthew Garrett 
175967c9ef9SMatthew Garrett 	i8042_platform_filter = NULL;
176967c9ef9SMatthew Garrett 
177967c9ef9SMatthew Garrett out:
178967c9ef9SMatthew Garrett 	spin_unlock_irqrestore(&i8042_lock, flags);
179967c9ef9SMatthew Garrett 	return ret;
180967c9ef9SMatthew Garrett }
181967c9ef9SMatthew Garrett EXPORT_SYMBOL(i8042_remove_filter);
182967c9ef9SMatthew Garrett 
1831da177e4SLinus Torvalds /*
1841da177e4SLinus Torvalds  * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
1851da177e4SLinus Torvalds  * be ready for reading values from it / writing values to it.
1861da177e4SLinus Torvalds  * Called always with i8042_lock held.
1871da177e4SLinus Torvalds  */
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds static int i8042_wait_read(void)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds 	int i = 0;
192de9ce703SDmitry Torokhov 
1931da177e4SLinus Torvalds 	while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
1941da177e4SLinus Torvalds 		udelay(50);
1951da177e4SLinus Torvalds 		i++;
1961da177e4SLinus Torvalds 	}
1971da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
1981da177e4SLinus Torvalds }
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds static int i8042_wait_write(void)
2011da177e4SLinus Torvalds {
2021da177e4SLinus Torvalds 	int i = 0;
203de9ce703SDmitry Torokhov 
2041da177e4SLinus Torvalds 	while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
2051da177e4SLinus Torvalds 		udelay(50);
2061da177e4SLinus Torvalds 		i++;
2071da177e4SLinus Torvalds 	}
2081da177e4SLinus Torvalds 	return -(i == I8042_CTL_TIMEOUT);
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds /*
2121da177e4SLinus Torvalds  * i8042_flush() flushes all data that may be in the keyboard and mouse buffers
2131da177e4SLinus Torvalds  * of the i8042 down the toilet.
2141da177e4SLinus Torvalds  */
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds static int i8042_flush(void)
2171da177e4SLinus Torvalds {
2181da177e4SLinus Torvalds 	unsigned long flags;
2191da177e4SLinus Torvalds 	unsigned char data, str;
2201da177e4SLinus Torvalds 	int i = 0;
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds 	while (((str = i8042_read_status()) & I8042_STR_OBF) && (i < I8042_BUFFER_SIZE)) {
2251da177e4SLinus Torvalds 		udelay(50);
2261da177e4SLinus Torvalds 		data = i8042_read_data();
2271da177e4SLinus Torvalds 		i++;
2281da177e4SLinus Torvalds 		dbg("%02x <- i8042 (flush, %s)", data,
2291da177e4SLinus Torvalds 			str & I8042_STR_AUXDATA ? "aux" : "kbd");
2301da177e4SLinus Torvalds 	}
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 	return i;
2351da177e4SLinus Torvalds }
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds /*
2381da177e4SLinus Torvalds  * i8042_command() executes a command on the i8042. It also sends the input
2391da177e4SLinus Torvalds  * parameter(s) of the commands to it, and receives the output value(s). The
2401da177e4SLinus Torvalds  * parameters are to be stored in the param array, and the output is placed
2411da177e4SLinus Torvalds  * into the same array. The number of the parameters and output values is
2421da177e4SLinus Torvalds  * encoded in bits 8-11 of the command number.
2431da177e4SLinus Torvalds  */
2441da177e4SLinus Torvalds 
245de9ce703SDmitry Torokhov static int __i8042_command(unsigned char *param, int command)
2461da177e4SLinus Torvalds {
247de9ce703SDmitry Torokhov 	int i, error;
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
2501da177e4SLinus Torvalds 		return -1;
2511da177e4SLinus Torvalds 
252de9ce703SDmitry Torokhov 	error = i8042_wait_write();
253de9ce703SDmitry Torokhov 	if (error)
254de9ce703SDmitry Torokhov 		return error;
255463a4f76SDmitry Torokhov 
2561da177e4SLinus Torvalds 	dbg("%02x -> i8042 (command)", command & 0xff);
2571da177e4SLinus Torvalds 	i8042_write_command(command & 0xff);
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 12) & 0xf); i++) {
260de9ce703SDmitry Torokhov 		error = i8042_wait_write();
261de9ce703SDmitry Torokhov 		if (error)
262de9ce703SDmitry Torokhov 			return error;
2631da177e4SLinus Torvalds 		dbg("%02x -> i8042 (parameter)", param[i]);
2641da177e4SLinus Torvalds 		i8042_write_data(param[i]);
2651da177e4SLinus Torvalds 	}
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	for (i = 0; i < ((command >> 8) & 0xf); i++) {
268de9ce703SDmitry Torokhov 		error = i8042_wait_read();
269de9ce703SDmitry Torokhov 		if (error) {
270de9ce703SDmitry Torokhov 			dbg("     -- i8042 (timeout)");
271de9ce703SDmitry Torokhov 			return error;
272de9ce703SDmitry Torokhov 		}
273463a4f76SDmitry Torokhov 
274463a4f76SDmitry Torokhov 		if (command == I8042_CMD_AUX_LOOP &&
275463a4f76SDmitry Torokhov 		    !(i8042_read_status() & I8042_STR_AUXDATA)) {
276de9ce703SDmitry Torokhov 			dbg("     -- i8042 (auxerr)");
277de9ce703SDmitry Torokhov 			return -1;
278463a4f76SDmitry Torokhov 		}
279463a4f76SDmitry Torokhov 
2801da177e4SLinus Torvalds 		param[i] = i8042_read_data();
2811da177e4SLinus Torvalds 		dbg("%02x <- i8042 (return)", param[i]);
2821da177e4SLinus Torvalds 	}
2831da177e4SLinus Torvalds 
284de9ce703SDmitry Torokhov 	return 0;
285de9ce703SDmitry Torokhov }
2861da177e4SLinus Torvalds 
287553a05b8SMárton Németh int i8042_command(unsigned char *param, int command)
288de9ce703SDmitry Torokhov {
289de9ce703SDmitry Torokhov 	unsigned long flags;
290de9ce703SDmitry Torokhov 	int retval;
291de9ce703SDmitry Torokhov 
292de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
293de9ce703SDmitry Torokhov 	retval = __i8042_command(param, command);
294463a4f76SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
295de9ce703SDmitry Torokhov 
2961da177e4SLinus Torvalds 	return retval;
2971da177e4SLinus Torvalds }
298553a05b8SMárton Németh EXPORT_SYMBOL(i8042_command);
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds /*
3011da177e4SLinus Torvalds  * i8042_kbd_write() sends a byte out through the keyboard interface.
3021da177e4SLinus Torvalds  */
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds static int i8042_kbd_write(struct serio *port, unsigned char c)
3051da177e4SLinus Torvalds {
3061da177e4SLinus Torvalds 	unsigned long flags;
3071da177e4SLinus Torvalds 	int retval = 0;
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 	if (!(retval = i8042_wait_write())) {
3121da177e4SLinus Torvalds 		dbg("%02x -> i8042 (kbd-data)", c);
3131da177e4SLinus Torvalds 		i8042_write_data(c);
3141da177e4SLinus Torvalds 	}
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	return retval;
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds /*
3221da177e4SLinus Torvalds  * i8042_aux_write() sends a byte out through the aux interface.
3231da177e4SLinus Torvalds  */
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds static int i8042_aux_write(struct serio *serio, unsigned char c)
3261da177e4SLinus Torvalds {
3271da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3281da177e4SLinus Torvalds 
329f4e3c711SDmitry Torokhov 	return i8042_command(&c, port->mux == -1 ?
330f4e3c711SDmitry Torokhov 					I8042_CMD_AUX_SEND :
331f4e3c711SDmitry Torokhov 					I8042_CMD_MUX_SEND + port->mux);
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds 
3345ddbc77cSDmitry Torokhov 
3355ddbc77cSDmitry Torokhov /*
3365ddbc77cSDmitry Torokhov  * i8042_aux_close attempts to clear AUX or KBD port state by disabling
3375ddbc77cSDmitry Torokhov  * and then re-enabling it.
3385ddbc77cSDmitry Torokhov  */
3395ddbc77cSDmitry Torokhov 
3405ddbc77cSDmitry Torokhov static void i8042_port_close(struct serio *serio)
3415ddbc77cSDmitry Torokhov {
3425ddbc77cSDmitry Torokhov 	int irq_bit;
3435ddbc77cSDmitry Torokhov 	int disable_bit;
3445ddbc77cSDmitry Torokhov 	const char *port_name;
3455ddbc77cSDmitry Torokhov 
3465ddbc77cSDmitry Torokhov 	if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) {
3475ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_AUXINT;
3485ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_AUXDIS;
3495ddbc77cSDmitry Torokhov 		port_name = "AUX";
3505ddbc77cSDmitry Torokhov 	} else {
3515ddbc77cSDmitry Torokhov 		irq_bit = I8042_CTR_KBDINT;
3525ddbc77cSDmitry Torokhov 		disable_bit = I8042_CTR_KBDDIS;
3535ddbc77cSDmitry Torokhov 		port_name = "KBD";
3545ddbc77cSDmitry Torokhov 	}
3555ddbc77cSDmitry Torokhov 
3565ddbc77cSDmitry Torokhov 	i8042_ctr &= ~irq_bit;
3575ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
3585ddbc77cSDmitry Torokhov 		printk(KERN_WARNING
3595ddbc77cSDmitry Torokhov 			"i8042.c: Can't write CTR while closing %s port.\n",
3605ddbc77cSDmitry Torokhov 			port_name);
3615ddbc77cSDmitry Torokhov 
3625ddbc77cSDmitry Torokhov 	udelay(50);
3635ddbc77cSDmitry Torokhov 
3645ddbc77cSDmitry Torokhov 	i8042_ctr &= ~disable_bit;
3655ddbc77cSDmitry Torokhov 	i8042_ctr |= irq_bit;
3665ddbc77cSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
3675ddbc77cSDmitry Torokhov 		printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n",
3685ddbc77cSDmitry Torokhov 			port_name);
3695ddbc77cSDmitry Torokhov 
3705ddbc77cSDmitry Torokhov 	/*
3715ddbc77cSDmitry Torokhov 	 * See if there is any data appeared while we were messing with
3725ddbc77cSDmitry Torokhov 	 * port state.
3735ddbc77cSDmitry Torokhov 	 */
3745ddbc77cSDmitry Torokhov 	i8042_interrupt(0, NULL);
3755ddbc77cSDmitry Torokhov }
3765ddbc77cSDmitry Torokhov 
3771da177e4SLinus Torvalds /*
3781da177e4SLinus Torvalds  * i8042_start() is called by serio core when port is about to finish
3791da177e4SLinus Torvalds  * registering. It will mark port as existing so i8042_interrupt can
3801da177e4SLinus Torvalds  * start sending data through it.
3811da177e4SLinus Torvalds  */
3821da177e4SLinus Torvalds static int i8042_start(struct serio *serio)
3831da177e4SLinus Torvalds {
3841da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3851da177e4SLinus Torvalds 
386386b3849SDmitry Torokhov 	port->exists = true;
3871da177e4SLinus Torvalds 	mb();
3881da177e4SLinus Torvalds 	return 0;
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds /*
3921da177e4SLinus Torvalds  * i8042_stop() marks serio port as non-existing so i8042_interrupt
3931da177e4SLinus Torvalds  * will not try to send data to the port that is about to go away.
3941da177e4SLinus Torvalds  * The function is called by serio core as part of unregister procedure.
3951da177e4SLinus Torvalds  */
3961da177e4SLinus Torvalds static void i8042_stop(struct serio *serio)
3971da177e4SLinus Torvalds {
3981da177e4SLinus Torvalds 	struct i8042_port *port = serio->port_data;
3991da177e4SLinus Torvalds 
400386b3849SDmitry Torokhov 	port->exists = false;
401a8399c51SDmitry Torokhov 
402a8399c51SDmitry Torokhov 	/*
403a8399c51SDmitry Torokhov 	 * We synchronize with both AUX and KBD IRQs because there is
404a8399c51SDmitry Torokhov 	 * a (very unlikely) chance that AUX IRQ is raised for KBD port
405a8399c51SDmitry Torokhov 	 * and vice versa.
406a8399c51SDmitry Torokhov 	 */
407a8399c51SDmitry Torokhov 	synchronize_irq(I8042_AUX_IRQ);
408a8399c51SDmitry Torokhov 	synchronize_irq(I8042_KBD_IRQ);
4091da177e4SLinus Torvalds 	port->serio = NULL;
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds /*
4134e8d340dSDmitry Torokhov  * i8042_filter() filters out unwanted bytes from the input data stream.
4144e8d340dSDmitry Torokhov  * It is called from i8042_interrupt and thus is running with interrupts
4154e8d340dSDmitry Torokhov  * off and i8042_lock held.
4164e8d340dSDmitry Torokhov  */
417967c9ef9SMatthew Garrett static bool i8042_filter(unsigned char data, unsigned char str,
418967c9ef9SMatthew Garrett 			 struct serio *serio)
4194e8d340dSDmitry Torokhov {
4204e8d340dSDmitry Torokhov 	if (unlikely(i8042_suppress_kbd_ack)) {
4214e8d340dSDmitry Torokhov 		if ((~str & I8042_STR_AUXDATA) &&
4224e8d340dSDmitry Torokhov 		    (data == 0xfa || data == 0xfe)) {
4234e8d340dSDmitry Torokhov 			i8042_suppress_kbd_ack--;
4244e8d340dSDmitry Torokhov 			dbg("Extra keyboard ACK - filtered out\n");
4254e8d340dSDmitry Torokhov 			return true;
4264e8d340dSDmitry Torokhov 		}
4274e8d340dSDmitry Torokhov 	}
4284e8d340dSDmitry Torokhov 
429967c9ef9SMatthew Garrett 	if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
4300747e3bcSStefan Weil 		dbg("Filtered out by platform filter\n");
431967c9ef9SMatthew Garrett 		return true;
432967c9ef9SMatthew Garrett 	}
433967c9ef9SMatthew Garrett 
4344e8d340dSDmitry Torokhov 	return false;
4354e8d340dSDmitry Torokhov }
4364e8d340dSDmitry Torokhov 
4374e8d340dSDmitry Torokhov /*
4381da177e4SLinus Torvalds  * i8042_interrupt() is the most important function in this driver -
4391da177e4SLinus Torvalds  * it handles the interrupts from the i8042, and sends incoming bytes
4401da177e4SLinus Torvalds  * to the upper layers.
4411da177e4SLinus Torvalds  */
4421da177e4SLinus Torvalds 
4437d12e780SDavid Howells static irqreturn_t i8042_interrupt(int irq, void *dev_id)
4441da177e4SLinus Torvalds {
4451da177e4SLinus Torvalds 	struct i8042_port *port;
446967c9ef9SMatthew Garrett 	struct serio *serio;
4471da177e4SLinus Torvalds 	unsigned long flags;
4481da177e4SLinus Torvalds 	unsigned char str, data;
4491da177e4SLinus Torvalds 	unsigned int dfl;
4501da177e4SLinus Torvalds 	unsigned int port_no;
4514e8d340dSDmitry Torokhov 	bool filtered;
452817e6ba3SDmitry Torokhov 	int ret = 1;
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
4554e8d340dSDmitry Torokhov 
4561da177e4SLinus Torvalds 	str = i8042_read_status();
4571da177e4SLinus Torvalds 	if (unlikely(~str & I8042_STR_OBF)) {
4581da177e4SLinus Torvalds 		spin_unlock_irqrestore(&i8042_lock, flags);
4591da177e4SLinus Torvalds 		if (irq) dbg("Interrupt %d, without any data", irq);
4601da177e4SLinus Torvalds 		ret = 0;
4611da177e4SLinus Torvalds 		goto out;
4621da177e4SLinus Torvalds 	}
4634e8d340dSDmitry Torokhov 
4641da177e4SLinus Torvalds 	data = i8042_read_data();
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds 	if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
4671da177e4SLinus Torvalds 		static unsigned long last_transmit;
4681da177e4SLinus Torvalds 		static unsigned char last_str;
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds 		dfl = 0;
4711da177e4SLinus Torvalds 		if (str & I8042_STR_MUXERR) {
4721da177e4SLinus Torvalds 			dbg("MUX error, status is %02x, data is %02x", str, data);
4731da177e4SLinus Torvalds /*
4741da177e4SLinus Torvalds  * When MUXERR condition is signalled the data register can only contain
4751da177e4SLinus Torvalds  * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
476a216a4b6SDmitry Torokhov  * it is not always the case. Some KBCs also report 0xfc when there is
477a216a4b6SDmitry Torokhov  * nothing connected to the port while others sometimes get confused which
478a216a4b6SDmitry Torokhov  * port the data came from and signal error leaving the data intact. They
479a216a4b6SDmitry Torokhov  * _do not_ revert to legacy mode (actually I've never seen KBC reverting
480a216a4b6SDmitry Torokhov  * to legacy mode yet, when we see one we'll add proper handling).
481a216a4b6SDmitry Torokhov  * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the
482a216a4b6SDmitry Torokhov  * rest assume that the data came from the same serio last byte
4831da177e4SLinus Torvalds  * was transmitted (if transmission happened not too long ago).
4841da177e4SLinus Torvalds  */
485a216a4b6SDmitry Torokhov 
486a216a4b6SDmitry Torokhov 			switch (data) {
487a216a4b6SDmitry Torokhov 				default:
4881da177e4SLinus Torvalds 					if (time_before(jiffies, last_transmit + HZ/10)) {
4891da177e4SLinus Torvalds 						str = last_str;
4901da177e4SLinus Torvalds 						break;
4911da177e4SLinus Torvalds 					}
4921da177e4SLinus Torvalds 					/* fall through - report timeout */
493a216a4b6SDmitry Torokhov 				case 0xfc:
4941da177e4SLinus Torvalds 				case 0xfd:
4951da177e4SLinus Torvalds 				case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
4961da177e4SLinus Torvalds 				case 0xff: dfl = SERIO_PARITY;  data = 0xfe; break;
4971da177e4SLinus Torvalds 			}
4981da177e4SLinus Torvalds 		}
4991da177e4SLinus Torvalds 
5001da177e4SLinus Torvalds 		port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
5011da177e4SLinus Torvalds 		last_str = str;
5021da177e4SLinus Torvalds 		last_transmit = jiffies;
5031da177e4SLinus Torvalds 	} else {
5041da177e4SLinus Torvalds 
5051da177e4SLinus Torvalds 		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
5061da177e4SLinus Torvalds 		      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 		port_no = (str & I8042_STR_AUXDATA) ?
5091da177e4SLinus Torvalds 				I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
5101da177e4SLinus Torvalds 	}
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 	port = &i8042_ports[port_no];
513967c9ef9SMatthew Garrett 	serio = port->exists ? port->serio : NULL;
5141da177e4SLinus Torvalds 
515de9ce703SDmitry Torokhov 	dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
516de9ce703SDmitry Torokhov 	    data, port_no, irq,
5171da177e4SLinus Torvalds 	    dfl & SERIO_PARITY ? ", bad parity" : "",
5181da177e4SLinus Torvalds 	    dfl & SERIO_TIMEOUT ? ", timeout" : "");
5191da177e4SLinus Torvalds 
520967c9ef9SMatthew Garrett 	filtered = i8042_filter(data, str, serio);
521817e6ba3SDmitry Torokhov 
5224e8d340dSDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
5234e8d340dSDmitry Torokhov 
5244e8d340dSDmitry Torokhov 	if (likely(port->exists && !filtered))
525967c9ef9SMatthew Garrett 		serio_interrupt(serio, data, dfl);
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds  out:
5281da177e4SLinus Torvalds 	return IRQ_RETVAL(ret);
5291da177e4SLinus Torvalds }
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds /*
5325ddbc77cSDmitry Torokhov  * i8042_enable_kbd_port enables keyboard port on chip
533de9ce703SDmitry Torokhov  */
534de9ce703SDmitry Torokhov 
535de9ce703SDmitry Torokhov static int i8042_enable_kbd_port(void)
536de9ce703SDmitry Torokhov {
537de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_KBDDIS;
538de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDINT;
539de9ce703SDmitry Torokhov 
540de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
541018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_KBDINT;
542018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_KBDDIS;
543de9ce703SDmitry Torokhov 		printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n");
544de9ce703SDmitry Torokhov 		return -EIO;
545de9ce703SDmitry Torokhov 	}
546de9ce703SDmitry Torokhov 
547de9ce703SDmitry Torokhov 	return 0;
548de9ce703SDmitry Torokhov }
549de9ce703SDmitry Torokhov 
550de9ce703SDmitry Torokhov /*
551de9ce703SDmitry Torokhov  * i8042_enable_aux_port enables AUX (mouse) port on chip
552de9ce703SDmitry Torokhov  */
553de9ce703SDmitry Torokhov 
554de9ce703SDmitry Torokhov static int i8042_enable_aux_port(void)
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)) {
560018db6bbSMarkus Armbruster 		i8042_ctr &= ~I8042_CTR_AUXINT;
561018db6bbSMarkus Armbruster 		i8042_ctr |= I8042_CTR_AUXDIS;
562de9ce703SDmitry Torokhov 		printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n");
563de9ce703SDmitry Torokhov 		return -EIO;
564de9ce703SDmitry Torokhov 	}
565de9ce703SDmitry Torokhov 
566de9ce703SDmitry Torokhov 	return 0;
567de9ce703SDmitry Torokhov }
568de9ce703SDmitry Torokhov 
569de9ce703SDmitry Torokhov /*
570de9ce703SDmitry Torokhov  * i8042_enable_mux_ports enables 4 individual AUX ports after
571de9ce703SDmitry Torokhov  * the controller has been switched into Multiplexed mode
572de9ce703SDmitry Torokhov  */
573de9ce703SDmitry Torokhov 
574de9ce703SDmitry Torokhov static int i8042_enable_mux_ports(void)
575de9ce703SDmitry Torokhov {
576de9ce703SDmitry Torokhov 	unsigned char param;
577de9ce703SDmitry Torokhov 	int i;
578de9ce703SDmitry Torokhov 
579de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
580de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_MUX_PFX + i);
581de9ce703SDmitry Torokhov 		i8042_command(&param, I8042_CMD_AUX_ENABLE);
582de9ce703SDmitry Torokhov 	}
583de9ce703SDmitry Torokhov 
584de9ce703SDmitry Torokhov 	return i8042_enable_aux_port();
585de9ce703SDmitry Torokhov }
586de9ce703SDmitry Torokhov 
587de9ce703SDmitry Torokhov /*
588386b3849SDmitry Torokhov  * i8042_set_mux_mode checks whether the controller has an
589386b3849SDmitry Torokhov  * active multiplexor and puts the chip into Multiplexed (true)
590386b3849SDmitry Torokhov  * or Legacy (false) mode.
5911da177e4SLinus Torvalds  */
5921da177e4SLinus Torvalds 
593386b3849SDmitry Torokhov static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version)
5941da177e4SLinus Torvalds {
5951da177e4SLinus Torvalds 
596386b3849SDmitry Torokhov 	unsigned char param, val;
5971da177e4SLinus Torvalds /*
5981da177e4SLinus Torvalds  * Get rid of bytes in the queue.
5991da177e4SLinus Torvalds  */
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds 	i8042_flush();
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds /*
6041da177e4SLinus Torvalds  * Internal loopback test - send three bytes, they should come back from the
605de9ce703SDmitry Torokhov  * mouse interface, the last should be version.
6061da177e4SLinus Torvalds  */
6071da177e4SLinus Torvalds 
608386b3849SDmitry Torokhov 	param = val = 0xf0;
609386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6101da177e4SLinus Torvalds 		return -1;
611386b3849SDmitry Torokhov 	param = val = multiplex ? 0x56 : 0xf6;
612386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
6131da177e4SLinus Torvalds 		return -1;
614386b3849SDmitry Torokhov 	param = val = multiplex ? 0xa4 : 0xa5;
615386b3849SDmitry Torokhov 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == val)
616386b3849SDmitry Torokhov 		return -1;
617386b3849SDmitry Torokhov 
618386b3849SDmitry Torokhov /*
619386b3849SDmitry Torokhov  * Workaround for interference with USB Legacy emulation
620386b3849SDmitry Torokhov  * that causes a v10.12 MUX to be found.
621386b3849SDmitry Torokhov  */
622386b3849SDmitry Torokhov 	if (param == 0xac)
6231da177e4SLinus Torvalds 		return -1;
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds 	if (mux_version)
626463a4f76SDmitry Torokhov 		*mux_version = param;
6271da177e4SLinus Torvalds 
6281da177e4SLinus Torvalds 	return 0;
6291da177e4SLinus Torvalds }
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds /*
6321da177e4SLinus Torvalds  * i8042_check_mux() checks whether the controller supports the PS/2 Active
6331da177e4SLinus Torvalds  * Multiplexing specification by Synaptics, Phoenix, Insyde and
6341da177e4SLinus Torvalds  * LCS/Telegraphics.
6351da177e4SLinus Torvalds  */
6361da177e4SLinus Torvalds 
637f8113416SDmitry Torokhov static int __init i8042_check_mux(void)
6381da177e4SLinus Torvalds {
6391da177e4SLinus Torvalds 	unsigned char mux_version;
6401da177e4SLinus Torvalds 
641386b3849SDmitry Torokhov 	if (i8042_set_mux_mode(true, &mux_version))
6421da177e4SLinus Torvalds 		return -1;
6431da177e4SLinus Torvalds 
6441da177e4SLinus Torvalds 	printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
6451da177e4SLinus Torvalds 		(mux_version >> 4) & 0xf, mux_version & 0xf);
6461da177e4SLinus Torvalds 
647de9ce703SDmitry Torokhov /*
648de9ce703SDmitry Torokhov  * Disable all muxed ports by disabling AUX.
649de9ce703SDmitry Torokhov  */
650de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS;
651de9ce703SDmitry Torokhov 	i8042_ctr &= ~I8042_CTR_AUXINT;
652de9ce703SDmitry Torokhov 
653de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
654de9ce703SDmitry Torokhov 		printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n");
655de9ce703SDmitry Torokhov 		return -EIO;
656de9ce703SDmitry Torokhov 	}
6571da177e4SLinus Torvalds 
658386b3849SDmitry Torokhov 	i8042_mux_present = true;
659de9ce703SDmitry Torokhov 
6601da177e4SLinus Torvalds 	return 0;
6611da177e4SLinus Torvalds }
6621da177e4SLinus Torvalds 
663de9ce703SDmitry Torokhov /*
664de9ce703SDmitry Torokhov  * The following is used to test AUX IRQ delivery.
665de9ce703SDmitry Torokhov  */
666f8113416SDmitry Torokhov static struct completion i8042_aux_irq_delivered __initdata;
667f8113416SDmitry Torokhov static bool i8042_irq_being_tested __initdata;
668de9ce703SDmitry Torokhov 
669f8113416SDmitry Torokhov static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
670de9ce703SDmitry Torokhov {
671de9ce703SDmitry Torokhov 	unsigned long flags;
672de9ce703SDmitry Torokhov 	unsigned char str, data;
673e3758b2aSFernando Luis Vázquez Cao 	int ret = 0;
674de9ce703SDmitry Torokhov 
675de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
676de9ce703SDmitry Torokhov 	str = i8042_read_status();
677de9ce703SDmitry Torokhov 	if (str & I8042_STR_OBF) {
678de9ce703SDmitry Torokhov 		data = i8042_read_data();
679d3d2dfe2SDmitry Torokhov 		dbg("%02x <- i8042 (aux_test_irq, %s)",
680d3d2dfe2SDmitry Torokhov 			data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
681de9ce703SDmitry Torokhov 		if (i8042_irq_being_tested &&
682de9ce703SDmitry Torokhov 		    data == 0xa5 && (str & I8042_STR_AUXDATA))
683de9ce703SDmitry Torokhov 			complete(&i8042_aux_irq_delivered);
684e3758b2aSFernando Luis Vázquez Cao 		ret = 1;
685de9ce703SDmitry Torokhov 	}
686de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
687de9ce703SDmitry Torokhov 
688e3758b2aSFernando Luis Vázquez Cao 	return IRQ_RETVAL(ret);
689de9ce703SDmitry Torokhov }
690de9ce703SDmitry Torokhov 
691d2ada559SRoland Scheidegger /*
692d2ada559SRoland Scheidegger  * i8042_toggle_aux - enables or disables AUX port on i8042 via command and
693d2ada559SRoland Scheidegger  * verifies success by readinng CTR. Used when testing for presence of AUX
694d2ada559SRoland Scheidegger  * port.
695d2ada559SRoland Scheidegger  */
696f8113416SDmitry Torokhov static int __init i8042_toggle_aux(bool on)
697d2ada559SRoland Scheidegger {
698d2ada559SRoland Scheidegger 	unsigned char param;
699d2ada559SRoland Scheidegger 	int i;
700d2ada559SRoland Scheidegger 
701d2ada559SRoland Scheidegger 	if (i8042_command(&param,
702d2ada559SRoland Scheidegger 			on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE))
703d2ada559SRoland Scheidegger 		return -1;
704d2ada559SRoland Scheidegger 
705d2ada559SRoland Scheidegger 	/* some chips need some time to set the I8042_CTR_AUXDIS bit */
706d2ada559SRoland Scheidegger 	for (i = 0; i < 100; i++) {
707d2ada559SRoland Scheidegger 		udelay(50);
708d2ada559SRoland Scheidegger 
709d2ada559SRoland Scheidegger 		if (i8042_command(&param, I8042_CMD_CTL_RCTR))
710d2ada559SRoland Scheidegger 			return -1;
711d2ada559SRoland Scheidegger 
712d2ada559SRoland Scheidegger 		if (!(param & I8042_CTR_AUXDIS) == on)
713d2ada559SRoland Scheidegger 			return 0;
714d2ada559SRoland Scheidegger 	}
715d2ada559SRoland Scheidegger 
716d2ada559SRoland Scheidegger 	return -1;
717d2ada559SRoland Scheidegger }
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds /*
7201da177e4SLinus Torvalds  * i8042_check_aux() applies as much paranoia as it can at detecting
7211da177e4SLinus Torvalds  * the presence of an AUX interface.
7221da177e4SLinus Torvalds  */
7231da177e4SLinus Torvalds 
724f8113416SDmitry Torokhov static int __init i8042_check_aux(void)
7251da177e4SLinus Torvalds {
726de9ce703SDmitry Torokhov 	int retval = -1;
727386b3849SDmitry Torokhov 	bool irq_registered = false;
728386b3849SDmitry Torokhov 	bool aux_loop_broken = false;
729de9ce703SDmitry Torokhov 	unsigned long flags;
7301da177e4SLinus Torvalds 	unsigned char param;
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds /*
7331da177e4SLinus Torvalds  * Get rid of bytes in the queue.
7341da177e4SLinus Torvalds  */
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds 	i8042_flush();
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds /*
7391da177e4SLinus Torvalds  * Internal loopback test - filters out AT-type i8042's. Unfortunately
7401da177e4SLinus Torvalds  * SiS screwed up and their 5597 doesn't support the LOOP command even
7411da177e4SLinus Torvalds  * though it has an AUX port.
7421da177e4SLinus Torvalds  */
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds 	param = 0x5a;
7453ca5de6dSDmitry Torokhov 	retval = i8042_command(&param, I8042_CMD_AUX_LOOP);
7463ca5de6dSDmitry Torokhov 	if (retval || param != 0x5a) {
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds /*
7491da177e4SLinus Torvalds  * External connection test - filters out AT-soldered PS/2 i8042's
7501da177e4SLinus Torvalds  * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error
7511da177e4SLinus Torvalds  * 0xfa - no error on some notebooks which ignore the spec
7521da177e4SLinus Torvalds  * Because it's common for chipsets to return error on perfectly functioning
7531da177e4SLinus Torvalds  * AUX ports, we test for this only when the LOOP command failed.
7541da177e4SLinus Torvalds  */
7551da177e4SLinus Torvalds 
756de9ce703SDmitry Torokhov 		if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
757de9ce703SDmitry Torokhov 		    (param && param != 0xfa && param != 0xff))
7581da177e4SLinus Torvalds 			return -1;
7591e4865f8SDmitry Torokhov 
7603ca5de6dSDmitry Torokhov /*
7613ca5de6dSDmitry Torokhov  * If AUX_LOOP completed without error but returned unexpected data
7623ca5de6dSDmitry Torokhov  * mark it as broken
7633ca5de6dSDmitry Torokhov  */
7643ca5de6dSDmitry Torokhov 		if (!retval)
765386b3849SDmitry Torokhov 			aux_loop_broken = true;
7661da177e4SLinus Torvalds 	}
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds /*
7691da177e4SLinus Torvalds  * Bit assignment test - filters out PS/2 i8042's in AT mode
7701da177e4SLinus Torvalds  */
7711da177e4SLinus Torvalds 
772386b3849SDmitry Torokhov 	if (i8042_toggle_aux(false)) {
7731da177e4SLinus Torvalds 		printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
7741da177e4SLinus Torvalds 		printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n");
7751da177e4SLinus Torvalds 	}
7761da177e4SLinus Torvalds 
777386b3849SDmitry Torokhov 	if (i8042_toggle_aux(true))
7781da177e4SLinus Torvalds 		return -1;
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds /*
781de9ce703SDmitry Torokhov  * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and
782de9ce703SDmitry Torokhov  * used it for a PCI card or somethig else.
783de9ce703SDmitry Torokhov  */
784de9ce703SDmitry Torokhov 
7851c7827aeSDmitry Torokhov 	if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) {
786de9ce703SDmitry Torokhov /*
787de9ce703SDmitry Torokhov  * Without LOOP command we can't test AUX IRQ delivery. Assume the port
788de9ce703SDmitry Torokhov  * is working and hope we are right.
789de9ce703SDmitry Torokhov  */
790de9ce703SDmitry Torokhov 		retval = 0;
791de9ce703SDmitry Torokhov 		goto out;
792de9ce703SDmitry Torokhov 	}
793de9ce703SDmitry Torokhov 
794de9ce703SDmitry Torokhov 	if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED,
795de9ce703SDmitry Torokhov 			"i8042", i8042_platform_device))
796de9ce703SDmitry Torokhov 		goto out;
797de9ce703SDmitry Torokhov 
798386b3849SDmitry Torokhov 	irq_registered = true;
799de9ce703SDmitry Torokhov 
800de9ce703SDmitry Torokhov 	if (i8042_enable_aux_port())
801de9ce703SDmitry Torokhov 		goto out;
802de9ce703SDmitry Torokhov 
803de9ce703SDmitry Torokhov 	spin_lock_irqsave(&i8042_lock, flags);
804de9ce703SDmitry Torokhov 
805de9ce703SDmitry Torokhov 	init_completion(&i8042_aux_irq_delivered);
806386b3849SDmitry Torokhov 	i8042_irq_being_tested = true;
807de9ce703SDmitry Torokhov 
808de9ce703SDmitry Torokhov 	param = 0xa5;
809de9ce703SDmitry Torokhov 	retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);
810de9ce703SDmitry Torokhov 
811de9ce703SDmitry Torokhov 	spin_unlock_irqrestore(&i8042_lock, flags);
812de9ce703SDmitry Torokhov 
813de9ce703SDmitry Torokhov 	if (retval)
814de9ce703SDmitry Torokhov 		goto out;
815de9ce703SDmitry Torokhov 
816de9ce703SDmitry Torokhov 	if (wait_for_completion_timeout(&i8042_aux_irq_delivered,
817de9ce703SDmitry Torokhov 					msecs_to_jiffies(250)) == 0) {
818de9ce703SDmitry Torokhov /*
819de9ce703SDmitry Torokhov  * AUX IRQ was never delivered so we need to flush the controller to
820de9ce703SDmitry Torokhov  * get rid of the byte we put there; otherwise keyboard may not work.
821de9ce703SDmitry Torokhov  */
822d3d2dfe2SDmitry Torokhov 		dbg("     -- i8042 (aux irq test timeout)");
823de9ce703SDmitry Torokhov 		i8042_flush();
824de9ce703SDmitry Torokhov 		retval = -1;
825de9ce703SDmitry Torokhov 	}
826de9ce703SDmitry Torokhov 
827de9ce703SDmitry Torokhov  out:
828de9ce703SDmitry Torokhov 
829de9ce703SDmitry Torokhov /*
8301da177e4SLinus Torvalds  * Disable the interface.
8311da177e4SLinus Torvalds  */
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_AUXDIS;
8341da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_AUXINT;
8351da177e4SLinus Torvalds 
8361da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
837de9ce703SDmitry Torokhov 		retval = -1;
838de9ce703SDmitry Torokhov 
839de9ce703SDmitry Torokhov 	if (irq_registered)
840de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
841de9ce703SDmitry Torokhov 
842de9ce703SDmitry Torokhov 	return retval;
843de9ce703SDmitry Torokhov }
844de9ce703SDmitry Torokhov 
845de9ce703SDmitry Torokhov static int i8042_controller_check(void)
846de9ce703SDmitry Torokhov {
847de9ce703SDmitry Torokhov 	if (i8042_flush() == I8042_BUFFER_SIZE) {
848de9ce703SDmitry Torokhov 		printk(KERN_ERR "i8042.c: No controller found.\n");
849de9ce703SDmitry Torokhov 		return -ENODEV;
850de9ce703SDmitry Torokhov 	}
8511da177e4SLinus Torvalds 
8521da177e4SLinus Torvalds 	return 0;
8531da177e4SLinus Torvalds }
8541da177e4SLinus Torvalds 
855de9ce703SDmitry Torokhov static int i8042_controller_selftest(void)
8562673c836SVojtech Pavlik {
8572673c836SVojtech Pavlik 	unsigned char param;
8585ea2fc64SArjan van de Ven 	int i = 0;
8592673c836SVojtech Pavlik 
8605ea2fc64SArjan van de Ven 	/*
8615ea2fc64SArjan van de Ven 	 * We try this 5 times; on some really fragile systems this does not
8625ea2fc64SArjan van de Ven 	 * take the first time...
8635ea2fc64SArjan van de Ven 	 */
8645ea2fc64SArjan van de Ven 	do {
8655ea2fc64SArjan van de Ven 
8662673c836SVojtech Pavlik 		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
8672673c836SVojtech Pavlik 			printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
868de9ce703SDmitry Torokhov 			return -ENODEV;
8692673c836SVojtech Pavlik 		}
8702673c836SVojtech Pavlik 
8715ea2fc64SArjan van de Ven 		if (param == I8042_RET_CTL_TEST)
8725ea2fc64SArjan van de Ven 			return 0;
8735ea2fc64SArjan van de Ven 
8742673c836SVojtech Pavlik 		printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
8752673c836SVojtech Pavlik 			param, I8042_RET_CTL_TEST);
8765ea2fc64SArjan van de Ven 		msleep(50);
8775ea2fc64SArjan van de Ven 	} while (i++ < 5);
8782673c836SVojtech Pavlik 
8795ea2fc64SArjan van de Ven #ifdef CONFIG_X86
8805ea2fc64SArjan van de Ven 	/*
8815ea2fc64SArjan van de Ven 	 * On x86, we don't fail entire i8042 initialization if controller
8825ea2fc64SArjan van de Ven 	 * reset fails in hopes that keyboard port will still be functional
8835ea2fc64SArjan van de Ven 	 * and user will still get a working keyboard. This is especially
8845ea2fc64SArjan van de Ven 	 * important on netbooks. On other arches we trust hardware more.
8855ea2fc64SArjan van de Ven 	 */
8865ea2fc64SArjan van de Ven 	printk(KERN_INFO
8875ea2fc64SArjan van de Ven 		"i8042: giving up on controller selftest, continuing anyway...\n");
8882673c836SVojtech Pavlik 	return 0;
8895ea2fc64SArjan van de Ven #else
8905ea2fc64SArjan van de Ven 	return -EIO;
8915ea2fc64SArjan van de Ven #endif
8922673c836SVojtech Pavlik }
8931da177e4SLinus Torvalds 
8941da177e4SLinus Torvalds /*
8951da177e4SLinus Torvalds  * i8042_controller init initializes the i8042 controller, and,
8961da177e4SLinus Torvalds  * most importantly, sets it into non-xlated mode if that's
8971da177e4SLinus Torvalds  * desired.
8981da177e4SLinus Torvalds  */
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds static int i8042_controller_init(void)
9011da177e4SLinus Torvalds {
9021da177e4SLinus Torvalds 	unsigned long flags;
903ee1e82ceSDmitry Torokhov 	int n = 0;
904ee1e82ceSDmitry Torokhov 	unsigned char ctr[2];
9051da177e4SLinus Torvalds 
9061da177e4SLinus Torvalds /*
907ee1e82ceSDmitry Torokhov  * Save the CTR for restore on unload / reboot.
9081da177e4SLinus Torvalds  */
9091da177e4SLinus Torvalds 
910ee1e82ceSDmitry Torokhov 	do {
911ee1e82ceSDmitry Torokhov 		if (n >= 10) {
912ee1e82ceSDmitry Torokhov 			printk(KERN_ERR
913ee1e82ceSDmitry Torokhov 				"i8042.c: Unable to get stable CTR read.\n");
914de9ce703SDmitry Torokhov 			return -EIO;
9151da177e4SLinus Torvalds 		}
9161da177e4SLinus Torvalds 
917ee1e82ceSDmitry Torokhov 		if (n != 0)
918ee1e82ceSDmitry Torokhov 			udelay(50);
919ee1e82ceSDmitry Torokhov 
920ee1e82ceSDmitry Torokhov 		if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
921ee1e82ceSDmitry Torokhov 			printk(KERN_ERR
922ee1e82ceSDmitry Torokhov 				"i8042.c: Can't read CTR while initializing i8042.\n");
923ee1e82ceSDmitry Torokhov 			return -EIO;
924ee1e82ceSDmitry Torokhov 		}
925ee1e82ceSDmitry Torokhov 
926ee1e82ceSDmitry Torokhov 	} while (n < 2 || ctr[0] != ctr[1]);
927ee1e82ceSDmitry Torokhov 
928ee1e82ceSDmitry Torokhov 	i8042_initial_ctr = i8042_ctr = ctr[0];
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds /*
9311da177e4SLinus Torvalds  * Disable the keyboard interface and interrupt.
9321da177e4SLinus Torvalds  */
9331da177e4SLinus Torvalds 
9341da177e4SLinus Torvalds 	i8042_ctr |= I8042_CTR_KBDDIS;
9351da177e4SLinus Torvalds 	i8042_ctr &= ~I8042_CTR_KBDINT;
9361da177e4SLinus Torvalds 
9371da177e4SLinus Torvalds /*
9381da177e4SLinus Torvalds  * Handle keylock.
9391da177e4SLinus Torvalds  */
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 	spin_lock_irqsave(&i8042_lock, flags);
9421da177e4SLinus Torvalds 	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
9431da177e4SLinus Torvalds 		if (i8042_unlock)
9441da177e4SLinus Torvalds 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
9451da177e4SLinus Torvalds 		else
9461da177e4SLinus Torvalds 			printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
9471da177e4SLinus Torvalds 	}
9481da177e4SLinus Torvalds 	spin_unlock_irqrestore(&i8042_lock, flags);
9491da177e4SLinus Torvalds 
9501da177e4SLinus Torvalds /*
9511da177e4SLinus Torvalds  * If the chip is configured into nontranslated mode by the BIOS, don't
9521da177e4SLinus Torvalds  * bother enabling translating and be happy.
9531da177e4SLinus Torvalds  */
9541da177e4SLinus Torvalds 
9551da177e4SLinus Torvalds 	if (~i8042_ctr & I8042_CTR_XLATE)
956386b3849SDmitry Torokhov 		i8042_direct = true;
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds /*
9591da177e4SLinus Torvalds  * Set nontranslated mode for the kbd interface if requested by an option.
9601da177e4SLinus Torvalds  * After this the kbd interface becomes a simple serial in/out, like the aux
9611da177e4SLinus Torvalds  * interface is. We don't do this by default, since it can confuse notebook
9621da177e4SLinus Torvalds  * BIOSes.
9631da177e4SLinus Torvalds  */
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 	if (i8042_direct)
9661da177e4SLinus Torvalds 		i8042_ctr &= ~I8042_CTR_XLATE;
9671da177e4SLinus Torvalds 
9681da177e4SLinus Torvalds /*
9691da177e4SLinus Torvalds  * Write CTR back.
9701da177e4SLinus Torvalds  */
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
9731da177e4SLinus Torvalds 		printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
974de9ce703SDmitry Torokhov 		return -EIO;
9751da177e4SLinus Torvalds 	}
9761da177e4SLinus Torvalds 
977ee1e82ceSDmitry Torokhov /*
978ee1e82ceSDmitry Torokhov  * Flush whatever accumulated while we were disabling keyboard port.
979ee1e82ceSDmitry Torokhov  */
980ee1e82ceSDmitry Torokhov 
981ee1e82ceSDmitry Torokhov 	i8042_flush();
982ee1e82ceSDmitry Torokhov 
9831da177e4SLinus Torvalds 	return 0;
9841da177e4SLinus Torvalds }
9851da177e4SLinus Torvalds 
9861da177e4SLinus Torvalds 
9871da177e4SLinus Torvalds /*
988de9ce703SDmitry Torokhov  * Reset the controller and reset CRT to the original value set by BIOS.
9891da177e4SLinus Torvalds  */
9901da177e4SLinus Torvalds 
991de9ce703SDmitry Torokhov static void i8042_controller_reset(void)
992de9ce703SDmitry Torokhov {
993de9ce703SDmitry Torokhov 	i8042_flush();
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds /*
9968d04ddb6SDmitry Torokhov  * Disable both KBD and AUX interfaces so they don't get in the way
9978d04ddb6SDmitry Torokhov  */
9988d04ddb6SDmitry Torokhov 
9998d04ddb6SDmitry Torokhov 	i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
10008d04ddb6SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
10018d04ddb6SDmitry Torokhov 
1002ee1e82ceSDmitry Torokhov 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
10035ddbc77cSDmitry Torokhov 		printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n");
10045ddbc77cSDmitry Torokhov 
10058d04ddb6SDmitry Torokhov /*
10061da177e4SLinus Torvalds  * Disable MUX mode if present.
10071da177e4SLinus Torvalds  */
10081da177e4SLinus Torvalds 
10091da177e4SLinus Torvalds 	if (i8042_mux_present)
1010386b3849SDmitry Torokhov 		i8042_set_mux_mode(false, NULL);
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds /*
1013de9ce703SDmitry Torokhov  * Reset the controller if requested.
1014de9ce703SDmitry Torokhov  */
1015de9ce703SDmitry Torokhov 
10161ca56e51SDmitry Torokhov 	if (i8042_reset)
1017de9ce703SDmitry Torokhov 		i8042_controller_selftest();
1018de9ce703SDmitry Torokhov 
1019de9ce703SDmitry Torokhov /*
10201da177e4SLinus Torvalds  * Restore the original control register setting.
10211da177e4SLinus Torvalds  */
10221da177e4SLinus Torvalds 
1023de9ce703SDmitry Torokhov 	if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
10241da177e4SLinus Torvalds 		printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
10251da177e4SLinus Torvalds }
10261da177e4SLinus Torvalds 
10271da177e4SLinus Torvalds 
10281da177e4SLinus Torvalds /*
1029c7ff0d9cSTAMUKI Shoichi  * i8042_panic_blink() will turn the keyboard LEDs on or off and is called
1030c7ff0d9cSTAMUKI Shoichi  * when kernel panics. Flashing LEDs is useful for users running X who may
10311da177e4SLinus Torvalds  * not see the console and will help distingushing panics from "real"
10321da177e4SLinus Torvalds  * lockups.
10331da177e4SLinus Torvalds  *
10341da177e4SLinus Torvalds  * Note that DELAY has a limit of 10ms so we will not get stuck here
10351da177e4SLinus Torvalds  * waiting for KBC to free up even if KBD interrupt is off
10361da177e4SLinus Torvalds  */
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
10391da177e4SLinus Torvalds 
1040c7ff0d9cSTAMUKI Shoichi static long i8042_panic_blink(int state)
10411da177e4SLinus Torvalds {
10421da177e4SLinus Torvalds 	long delay = 0;
1043c7ff0d9cSTAMUKI Shoichi 	char led;
10441da177e4SLinus Torvalds 
1045c7ff0d9cSTAMUKI Shoichi 	led = (state) ? 0x01 | 0x04 : 0;
10461da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
10471da177e4SLinus Torvalds 		DELAY;
104819f3c3e3SDmitry Torokhov 	dbg("%02x -> i8042 (panic blink)", 0xed);
104919f3c3e3SDmitry Torokhov 	i8042_suppress_kbd_ack = 2;
10501da177e4SLinus Torvalds 	i8042_write_data(0xed); /* set leds */
10511da177e4SLinus Torvalds 	DELAY;
10521da177e4SLinus Torvalds 	while (i8042_read_status() & I8042_STR_IBF)
10531da177e4SLinus Torvalds 		DELAY;
10541da177e4SLinus Torvalds 	DELAY;
105519f3c3e3SDmitry Torokhov 	dbg("%02x -> i8042 (panic blink)", led);
10561da177e4SLinus Torvalds 	i8042_write_data(led);
10571da177e4SLinus Torvalds 	DELAY;
10581da177e4SLinus Torvalds 	return delay;
10591da177e4SLinus Torvalds }
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds #undef DELAY
10621da177e4SLinus Torvalds 
1063d35895dbSBruno Prémont #ifdef CONFIG_X86
1064d35895dbSBruno Prémont static void i8042_dritek_enable(void)
1065d35895dbSBruno Prémont {
1066d35895dbSBruno Prémont 	char param = 0x90;
1067d35895dbSBruno Prémont 	int error;
1068d35895dbSBruno Prémont 
1069d35895dbSBruno Prémont 	error = i8042_command(&param, 0x1059);
1070d35895dbSBruno Prémont 	if (error)
1071d35895dbSBruno Prémont 		printk(KERN_WARNING
1072d35895dbSBruno Prémont 			"Failed to enable DRITEK extension: %d\n",
1073d35895dbSBruno Prémont 			error);
1074d35895dbSBruno Prémont }
1075d35895dbSBruno Prémont #endif
1076d35895dbSBruno Prémont 
107782dd9effSDmitry Torokhov #ifdef CONFIG_PM
10787e044e05SDmitry Torokhov 
10791da177e4SLinus Torvalds /*
1080ebd7768dSDmitry Torokhov  * Here we try to reset everything back to a state we had
1081ebd7768dSDmitry Torokhov  * before suspending.
10821da177e4SLinus Torvalds  */
10831da177e4SLinus Torvalds 
10841ca56e51SDmitry Torokhov static int i8042_controller_resume(bool force_reset)
10851da177e4SLinus Torvalds {
1086de9ce703SDmitry Torokhov 	int error;
10871da177e4SLinus Torvalds 
1088de9ce703SDmitry Torokhov 	error = i8042_controller_check();
1089de9ce703SDmitry Torokhov 	if (error)
1090de9ce703SDmitry Torokhov 		return error;
10912673c836SVojtech Pavlik 
10921ca56e51SDmitry Torokhov 	if (i8042_reset || force_reset) {
1093de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1094de9ce703SDmitry Torokhov 		if (error)
1095de9ce703SDmitry Torokhov 			return error;
10961ca56e51SDmitry Torokhov 	}
1097de9ce703SDmitry Torokhov 
1098de9ce703SDmitry Torokhov /*
109982dd9effSDmitry Torokhov  * Restore original CTR value and disable all ports
1100de9ce703SDmitry Torokhov  */
1101de9ce703SDmitry Torokhov 
110282dd9effSDmitry Torokhov 	i8042_ctr = i8042_initial_ctr;
110382dd9effSDmitry Torokhov 	if (i8042_direct)
110482dd9effSDmitry Torokhov 		i8042_ctr &= ~I8042_CTR_XLATE;
1105de9ce703SDmitry Torokhov 	i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
1106de9ce703SDmitry Torokhov 	i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
11072673c836SVojtech Pavlik 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
11082f6a77d5SJiri Kosina 		printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n");
11092f6a77d5SJiri Kosina 		msleep(50);
11102f6a77d5SJiri Kosina 		if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
11112f6a77d5SJiri Kosina 			printk(KERN_ERR "i8042: CTR write retry failed\n");
1112de9ce703SDmitry Torokhov 			return -EIO;
11131da177e4SLinus Torvalds 		}
11142f6a77d5SJiri Kosina 	}
11151da177e4SLinus Torvalds 
1116d35895dbSBruno Prémont 
1117d35895dbSBruno Prémont #ifdef CONFIG_X86
1118d35895dbSBruno Prémont 	if (i8042_dritek)
1119d35895dbSBruno Prémont 		i8042_dritek_enable();
1120d35895dbSBruno Prémont #endif
1121d35895dbSBruno Prémont 
1122de9ce703SDmitry Torokhov 	if (i8042_mux_present) {
1123386b3849SDmitry Torokhov 		if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
1124de9ce703SDmitry Torokhov 			printk(KERN_WARNING
1125de9ce703SDmitry Torokhov 				"i8042: failed to resume active multiplexor, "
1126de9ce703SDmitry Torokhov 				"mouse won't work.\n");
1127de9ce703SDmitry Torokhov 	} else if (i8042_ports[I8042_AUX_PORT_NO].serio)
1128de9ce703SDmitry Torokhov 		i8042_enable_aux_port();
11291da177e4SLinus Torvalds 
1130de9ce703SDmitry Torokhov 	if (i8042_ports[I8042_KBD_PORT_NO].serio)
1131de9ce703SDmitry Torokhov 		i8042_enable_kbd_port();
11321da177e4SLinus Torvalds 
11337d12e780SDavid Howells 	i8042_interrupt(0, NULL);
11341da177e4SLinus Torvalds 
11351da177e4SLinus Torvalds 	return 0;
11361da177e4SLinus Torvalds }
1137ebd7768dSDmitry Torokhov 
11381ca56e51SDmitry Torokhov /*
11391ca56e51SDmitry Torokhov  * Here we try to restore the original BIOS settings to avoid
11401ca56e51SDmitry Torokhov  * upsetting it.
11411ca56e51SDmitry Torokhov  */
11421ca56e51SDmitry Torokhov 
11431ca56e51SDmitry Torokhov static int i8042_pm_reset(struct device *dev)
11441ca56e51SDmitry Torokhov {
11451ca56e51SDmitry Torokhov 	i8042_controller_reset();
11461ca56e51SDmitry Torokhov 
11471ca56e51SDmitry Torokhov 	return 0;
11481ca56e51SDmitry Torokhov }
11491ca56e51SDmitry Torokhov 
11501ca56e51SDmitry Torokhov static int i8042_pm_resume(struct device *dev)
11511ca56e51SDmitry Torokhov {
11521ca56e51SDmitry Torokhov 	/*
11531ca56e51SDmitry Torokhov 	 * On resume from S2R we always try to reset the controller
11541ca56e51SDmitry Torokhov 	 * to bring it in a sane state. (In case of S2D we expect
11551ca56e51SDmitry Torokhov 	 * BIOS to reset the controller for us.)
11561ca56e51SDmitry Torokhov 	 */
11571ca56e51SDmitry Torokhov 	return i8042_controller_resume(true);
11581ca56e51SDmitry Torokhov }
11591ca56e51SDmitry Torokhov 
1160c2d1a2a1SAlan Jenkins static int i8042_pm_thaw(struct device *dev)
1161c2d1a2a1SAlan Jenkins {
1162c2d1a2a1SAlan Jenkins 	i8042_interrupt(0, NULL);
1163c2d1a2a1SAlan Jenkins 
1164c2d1a2a1SAlan Jenkins 	return 0;
1165c2d1a2a1SAlan Jenkins }
1166c2d1a2a1SAlan Jenkins 
11671ca56e51SDmitry Torokhov static int i8042_pm_restore(struct device *dev)
11681ca56e51SDmitry Torokhov {
11691ca56e51SDmitry Torokhov 	return i8042_controller_resume(false);
11701ca56e51SDmitry Torokhov }
11711ca56e51SDmitry Torokhov 
1172ebd7768dSDmitry Torokhov static const struct dev_pm_ops i8042_pm_ops = {
1173ebd7768dSDmitry Torokhov 	.suspend	= i8042_pm_reset,
11741ca56e51SDmitry Torokhov 	.resume		= i8042_pm_resume,
1175c2d1a2a1SAlan Jenkins 	.thaw		= i8042_pm_thaw,
1176ebd7768dSDmitry Torokhov 	.poweroff	= i8042_pm_reset,
1177ebd7768dSDmitry Torokhov 	.restore	= i8042_pm_restore,
1178ebd7768dSDmitry Torokhov };
1179ebd7768dSDmitry Torokhov 
118082dd9effSDmitry Torokhov #endif /* CONFIG_PM */
11811da177e4SLinus Torvalds 
11821da177e4SLinus Torvalds /*
11831da177e4SLinus Torvalds  * We need to reset the 8042 back to original mode on system shutdown,
11841da177e4SLinus Torvalds  * because otherwise BIOSes will be confused.
11851da177e4SLinus Torvalds  */
11861da177e4SLinus Torvalds 
11873ae5eaecSRussell King static void i8042_shutdown(struct platform_device *dev)
11881da177e4SLinus Torvalds {
118982dd9effSDmitry Torokhov 	i8042_controller_reset();
11901da177e4SLinus Torvalds }
11911da177e4SLinus Torvalds 
1192f8113416SDmitry Torokhov static int __init i8042_create_kbd_port(void)
11931da177e4SLinus Torvalds {
11941da177e4SLinus Torvalds 	struct serio *serio;
11951da177e4SLinus Torvalds 	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
11961da177e4SLinus Torvalds 
1197d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
11980854e52dSDmitry Torokhov 	if (!serio)
11990854e52dSDmitry Torokhov 		return -ENOMEM;
12000854e52dSDmitry Torokhov 
12011da177e4SLinus Torvalds 	serio->id.type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL;
12021da177e4SLinus Torvalds 	serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write;
12031da177e4SLinus Torvalds 	serio->start		= i8042_start;
12041da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
12055ddbc77cSDmitry Torokhov 	serio->close		= i8042_port_close;
12061da177e4SLinus Torvalds 	serio->port_data	= port;
12071da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1208de9ce703SDmitry Torokhov 	strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
12091da177e4SLinus Torvalds 	strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds 	port->serio = serio;
1212de9ce703SDmitry Torokhov 	port->irq = I8042_KBD_IRQ;
12130854e52dSDmitry Torokhov 
1214de9ce703SDmitry Torokhov 	return 0;
12151da177e4SLinus Torvalds }
12161da177e4SLinus Torvalds 
1217f8113416SDmitry Torokhov static int __init i8042_create_aux_port(int idx)
12181da177e4SLinus Torvalds {
12191da177e4SLinus Torvalds 	struct serio *serio;
1220de9ce703SDmitry Torokhov 	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
1221de9ce703SDmitry Torokhov 	struct i8042_port *port = &i8042_ports[port_no];
12221da177e4SLinus Torvalds 
1223d39969deSDmitry Torokhov 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
12240854e52dSDmitry Torokhov 	if (!serio)
12250854e52dSDmitry Torokhov 		return -ENOMEM;
12260854e52dSDmitry Torokhov 
12271da177e4SLinus Torvalds 	serio->id.type		= SERIO_8042;
12281da177e4SLinus Torvalds 	serio->write		= i8042_aux_write;
12291da177e4SLinus Torvalds 	serio->start		= i8042_start;
12301da177e4SLinus Torvalds 	serio->stop		= i8042_stop;
12311da177e4SLinus Torvalds 	serio->port_data	= port;
12321da177e4SLinus Torvalds 	serio->dev.parent	= &i8042_platform_device->dev;
1233de9ce703SDmitry Torokhov 	if (idx < 0) {
1234de9ce703SDmitry Torokhov 		strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));
12351da177e4SLinus Torvalds 		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
12365ddbc77cSDmitry Torokhov 		serio->close = i8042_port_close;
1237de9ce703SDmitry Torokhov 	} else {
1238de9ce703SDmitry Torokhov 		snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
1239de9ce703SDmitry Torokhov 		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
12401da177e4SLinus Torvalds 	}
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds 	port->serio = serio;
1243de9ce703SDmitry Torokhov 	port->mux = idx;
1244de9ce703SDmitry Torokhov 	port->irq = I8042_AUX_IRQ;
12450854e52dSDmitry Torokhov 
1246de9ce703SDmitry Torokhov 	return 0;
1247de9ce703SDmitry Torokhov }
1248de9ce703SDmitry Torokhov 
1249f8113416SDmitry Torokhov static void __init i8042_free_kbd_port(void)
1250de9ce703SDmitry Torokhov {
1251de9ce703SDmitry Torokhov 	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
1252de9ce703SDmitry Torokhov 	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
1253de9ce703SDmitry Torokhov }
1254de9ce703SDmitry Torokhov 
1255f8113416SDmitry Torokhov static void __init i8042_free_aux_ports(void)
1256de9ce703SDmitry Torokhov {
1257de9ce703SDmitry Torokhov 	int i;
1258de9ce703SDmitry Torokhov 
1259de9ce703SDmitry Torokhov 	for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) {
1260de9ce703SDmitry Torokhov 		kfree(i8042_ports[i].serio);
1261de9ce703SDmitry Torokhov 		i8042_ports[i].serio = NULL;
1262de9ce703SDmitry Torokhov 	}
1263de9ce703SDmitry Torokhov }
1264de9ce703SDmitry Torokhov 
1265f8113416SDmitry Torokhov static void __init i8042_register_ports(void)
1266de9ce703SDmitry Torokhov {
1267de9ce703SDmitry Torokhov 	int i;
1268de9ce703SDmitry Torokhov 
1269de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1270de9ce703SDmitry Torokhov 		if (i8042_ports[i].serio) {
1271de9ce703SDmitry Torokhov 			printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
1272de9ce703SDmitry Torokhov 				i8042_ports[i].serio->name,
1273de9ce703SDmitry Torokhov 				(unsigned long) I8042_DATA_REG,
1274de9ce703SDmitry Torokhov 				(unsigned long) I8042_COMMAND_REG,
1275de9ce703SDmitry Torokhov 				i8042_ports[i].irq);
1276de9ce703SDmitry Torokhov 			serio_register_port(i8042_ports[i].serio);
1277de9ce703SDmitry Torokhov 		}
1278de9ce703SDmitry Torokhov 	}
1279de9ce703SDmitry Torokhov }
1280de9ce703SDmitry Torokhov 
12817a1904c3SRalf Baechle static void __devexit i8042_unregister_ports(void)
1282de9ce703SDmitry Torokhov {
1283de9ce703SDmitry Torokhov 	int i;
1284de9ce703SDmitry Torokhov 
1285de9ce703SDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++) {
1286de9ce703SDmitry Torokhov 		if (i8042_ports[i].serio) {
1287de9ce703SDmitry Torokhov 			serio_unregister_port(i8042_ports[i].serio);
1288de9ce703SDmitry Torokhov 			i8042_ports[i].serio = NULL;
1289de9ce703SDmitry Torokhov 		}
1290de9ce703SDmitry Torokhov 	}
1291de9ce703SDmitry Torokhov }
1292de9ce703SDmitry Torokhov 
1293181d683dSDmitry Torokhov /*
1294181d683dSDmitry Torokhov  * Checks whether port belongs to i8042 controller.
1295181d683dSDmitry Torokhov  */
1296181d683dSDmitry Torokhov bool i8042_check_port_owner(const struct serio *port)
1297181d683dSDmitry Torokhov {
1298181d683dSDmitry Torokhov 	int i;
1299181d683dSDmitry Torokhov 
1300181d683dSDmitry Torokhov 	for (i = 0; i < I8042_NUM_PORTS; i++)
1301181d683dSDmitry Torokhov 		if (i8042_ports[i].serio == port)
1302181d683dSDmitry Torokhov 			return true;
1303181d683dSDmitry Torokhov 
1304181d683dSDmitry Torokhov 	return false;
1305181d683dSDmitry Torokhov }
1306181d683dSDmitry Torokhov EXPORT_SYMBOL(i8042_check_port_owner);
1307181d683dSDmitry Torokhov 
1308de9ce703SDmitry Torokhov static void i8042_free_irqs(void)
1309de9ce703SDmitry Torokhov {
1310de9ce703SDmitry Torokhov 	if (i8042_aux_irq_registered)
1311de9ce703SDmitry Torokhov 		free_irq(I8042_AUX_IRQ, i8042_platform_device);
1312de9ce703SDmitry Torokhov 	if (i8042_kbd_irq_registered)
1313de9ce703SDmitry Torokhov 		free_irq(I8042_KBD_IRQ, i8042_platform_device);
1314de9ce703SDmitry Torokhov 
1315386b3849SDmitry Torokhov 	i8042_aux_irq_registered = i8042_kbd_irq_registered = false;
1316de9ce703SDmitry Torokhov }
1317de9ce703SDmitry Torokhov 
1318f8113416SDmitry Torokhov static int __init i8042_setup_aux(void)
1319de9ce703SDmitry Torokhov {
1320de9ce703SDmitry Torokhov 	int (*aux_enable)(void);
1321de9ce703SDmitry Torokhov 	int error;
1322de9ce703SDmitry Torokhov 	int i;
1323de9ce703SDmitry Torokhov 
1324de9ce703SDmitry Torokhov 	if (i8042_check_aux())
1325de9ce703SDmitry Torokhov 		return -ENODEV;
1326de9ce703SDmitry Torokhov 
1327de9ce703SDmitry Torokhov 	if (i8042_nomux || i8042_check_mux()) {
1328de9ce703SDmitry Torokhov 		error = i8042_create_aux_port(-1);
1329de9ce703SDmitry Torokhov 		if (error)
1330de9ce703SDmitry Torokhov 			goto err_free_ports;
1331de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_aux_port;
1332de9ce703SDmitry Torokhov 	} else {
1333de9ce703SDmitry Torokhov 		for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
1334de9ce703SDmitry Torokhov 			error = i8042_create_aux_port(i);
1335de9ce703SDmitry Torokhov 			if (error)
1336de9ce703SDmitry Torokhov 				goto err_free_ports;
1337de9ce703SDmitry Torokhov 		}
1338de9ce703SDmitry Torokhov 		aux_enable = i8042_enable_mux_ports;
1339de9ce703SDmitry Torokhov 	}
1340de9ce703SDmitry Torokhov 
1341de9ce703SDmitry Torokhov 	error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED,
1342de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1343de9ce703SDmitry Torokhov 	if (error)
1344de9ce703SDmitry Torokhov 		goto err_free_ports;
1345de9ce703SDmitry Torokhov 
1346de9ce703SDmitry Torokhov 	if (aux_enable())
1347de9ce703SDmitry Torokhov 		goto err_free_irq;
1348de9ce703SDmitry Torokhov 
1349386b3849SDmitry Torokhov 	i8042_aux_irq_registered = true;
1350de9ce703SDmitry Torokhov 	return 0;
1351de9ce703SDmitry Torokhov 
1352de9ce703SDmitry Torokhov  err_free_irq:
1353de9ce703SDmitry Torokhov 	free_irq(I8042_AUX_IRQ, i8042_platform_device);
1354de9ce703SDmitry Torokhov  err_free_ports:
1355de9ce703SDmitry Torokhov 	i8042_free_aux_ports();
1356de9ce703SDmitry Torokhov 	return error;
1357de9ce703SDmitry Torokhov }
1358de9ce703SDmitry Torokhov 
1359f8113416SDmitry Torokhov static int __init i8042_setup_kbd(void)
1360de9ce703SDmitry Torokhov {
1361de9ce703SDmitry Torokhov 	int error;
1362de9ce703SDmitry Torokhov 
1363de9ce703SDmitry Torokhov 	error = i8042_create_kbd_port();
1364de9ce703SDmitry Torokhov 	if (error)
1365de9ce703SDmitry Torokhov 		return error;
1366de9ce703SDmitry Torokhov 
1367de9ce703SDmitry Torokhov 	error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
1368de9ce703SDmitry Torokhov 			    "i8042", i8042_platform_device);
1369de9ce703SDmitry Torokhov 	if (error)
1370de9ce703SDmitry Torokhov 		goto err_free_port;
1371de9ce703SDmitry Torokhov 
1372de9ce703SDmitry Torokhov 	error = i8042_enable_kbd_port();
1373de9ce703SDmitry Torokhov 	if (error)
1374de9ce703SDmitry Torokhov 		goto err_free_irq;
1375de9ce703SDmitry Torokhov 
1376386b3849SDmitry Torokhov 	i8042_kbd_irq_registered = true;
1377de9ce703SDmitry Torokhov 	return 0;
1378de9ce703SDmitry Torokhov 
1379de9ce703SDmitry Torokhov  err_free_irq:
1380de9ce703SDmitry Torokhov 	free_irq(I8042_KBD_IRQ, i8042_platform_device);
1381de9ce703SDmitry Torokhov  err_free_port:
1382de9ce703SDmitry Torokhov 	i8042_free_kbd_port();
1383de9ce703SDmitry Torokhov 	return error;
13841da177e4SLinus Torvalds }
13851da177e4SLinus Torvalds 
1386f8113416SDmitry Torokhov static int __init i8042_probe(struct platform_device *dev)
13871da177e4SLinus Torvalds {
1388de9ce703SDmitry Torokhov 	int error;
13891da177e4SLinus Torvalds 
1390ec62e1c8SDmitry Torokhov 	i8042_platform_device = dev;
1391ec62e1c8SDmitry Torokhov 
13921ca56e51SDmitry Torokhov 	if (i8042_reset) {
1393de9ce703SDmitry Torokhov 		error = i8042_controller_selftest();
1394de9ce703SDmitry Torokhov 		if (error)
1395de9ce703SDmitry Torokhov 			return error;
13961ca56e51SDmitry Torokhov 	}
13971da177e4SLinus Torvalds 
1398de9ce703SDmitry Torokhov 	error = i8042_controller_init();
1399de9ce703SDmitry Torokhov 	if (error)
1400de9ce703SDmitry Torokhov 		return error;
14011da177e4SLinus Torvalds 
1402d35895dbSBruno Prémont #ifdef CONFIG_X86
1403d35895dbSBruno Prémont 	if (i8042_dritek)
1404d35895dbSBruno Prémont 		i8042_dritek_enable();
1405d35895dbSBruno Prémont #endif
1406d35895dbSBruno Prémont 
1407de9ce703SDmitry Torokhov 	if (!i8042_noaux) {
1408de9ce703SDmitry Torokhov 		error = i8042_setup_aux();
1409de9ce703SDmitry Torokhov 		if (error && error != -ENODEV && error != -EBUSY)
1410de9ce703SDmitry Torokhov 			goto out_fail;
14111da177e4SLinus Torvalds 	}
14121da177e4SLinus Torvalds 
1413945ef0d4SDmitry Torokhov 	if (!i8042_nokbd) {
1414de9ce703SDmitry Torokhov 		error = i8042_setup_kbd();
1415de9ce703SDmitry Torokhov 		if (error)
1416de9ce703SDmitry Torokhov 			goto out_fail;
1417945ef0d4SDmitry Torokhov 	}
1418de9ce703SDmitry Torokhov /*
1419de9ce703SDmitry Torokhov  * Ok, everything is ready, let's register all serio ports
1420de9ce703SDmitry Torokhov  */
1421de9ce703SDmitry Torokhov 	i8042_register_ports();
14221da177e4SLinus Torvalds 
14231da177e4SLinus Torvalds 	return 0;
14240854e52dSDmitry Torokhov 
1425de9ce703SDmitry Torokhov  out_fail:
1426de9ce703SDmitry Torokhov 	i8042_free_aux_ports();	/* in case KBD failed but AUX not */
1427de9ce703SDmitry Torokhov 	i8042_free_irqs();
1428de9ce703SDmitry Torokhov 	i8042_controller_reset();
1429ec62e1c8SDmitry Torokhov 	i8042_platform_device = NULL;
14300854e52dSDmitry Torokhov 
1431de9ce703SDmitry Torokhov 	return error;
14321da177e4SLinus Torvalds }
14331da177e4SLinus Torvalds 
143487fd6318SDmitry Torokhov static int __devexit i8042_remove(struct platform_device *dev)
14351da177e4SLinus Torvalds {
1436de9ce703SDmitry Torokhov 	i8042_unregister_ports();
1437de9ce703SDmitry Torokhov 	i8042_free_irqs();
1438de9ce703SDmitry Torokhov 	i8042_controller_reset();
1439ec62e1c8SDmitry Torokhov 	i8042_platform_device = NULL;
14401da177e4SLinus Torvalds 
144187fd6318SDmitry Torokhov 	return 0;
144287fd6318SDmitry Torokhov }
144387fd6318SDmitry Torokhov 
144487fd6318SDmitry Torokhov static struct platform_driver i8042_driver = {
144587fd6318SDmitry Torokhov 	.driver		= {
144687fd6318SDmitry Torokhov 		.name	= "i8042",
144787fd6318SDmitry Torokhov 		.owner	= THIS_MODULE,
1448ebd7768dSDmitry Torokhov #ifdef CONFIG_PM
1449ebd7768dSDmitry Torokhov 		.pm	= &i8042_pm_ops,
1450ebd7768dSDmitry Torokhov #endif
145187fd6318SDmitry Torokhov 	},
145287fd6318SDmitry Torokhov 	.remove		= __devexit_p(i8042_remove),
145382dd9effSDmitry Torokhov 	.shutdown	= i8042_shutdown,
145487fd6318SDmitry Torokhov };
145587fd6318SDmitry Torokhov 
145687fd6318SDmitry Torokhov static int __init i8042_init(void)
145787fd6318SDmitry Torokhov {
1458ec62e1c8SDmitry Torokhov 	struct platform_device *pdev;
145987fd6318SDmitry Torokhov 	int err;
146087fd6318SDmitry Torokhov 
146187fd6318SDmitry Torokhov 	dbg_init();
146287fd6318SDmitry Torokhov 
146387fd6318SDmitry Torokhov 	err = i8042_platform_init();
146487fd6318SDmitry Torokhov 	if (err)
146587fd6318SDmitry Torokhov 		return err;
146687fd6318SDmitry Torokhov 
1467de9ce703SDmitry Torokhov 	err = i8042_controller_check();
1468de9ce703SDmitry Torokhov 	if (err)
1469de9ce703SDmitry Torokhov 		goto err_platform_exit;
147087fd6318SDmitry Torokhov 
1471ec62e1c8SDmitry Torokhov 	pdev = platform_create_bundle(&i8042_driver, i8042_probe, NULL, 0, NULL, 0);
1472ec62e1c8SDmitry Torokhov 	if (IS_ERR(pdev)) {
1473ec62e1c8SDmitry Torokhov 		err = PTR_ERR(pdev);
1474f8113416SDmitry Torokhov 		goto err_platform_exit;
147587fd6318SDmitry Torokhov 	}
147687fd6318SDmitry Torokhov 
1477de9ce703SDmitry Torokhov 	panic_blink = i8042_panic_blink;
1478de9ce703SDmitry Torokhov 
147987fd6318SDmitry Torokhov 	return 0;
148087fd6318SDmitry Torokhov 
148187fd6318SDmitry Torokhov  err_platform_exit:
148287fd6318SDmitry Torokhov 	i8042_platform_exit();
148387fd6318SDmitry Torokhov 	return err;
148487fd6318SDmitry Torokhov }
148587fd6318SDmitry Torokhov 
148687fd6318SDmitry Torokhov static void __exit i8042_exit(void)
148787fd6318SDmitry Torokhov {
1488f8113416SDmitry Torokhov 	platform_device_unregister(i8042_platform_device);
1489*af045b86SDmitry Torokhov 	platform_driver_unregister(&i8042_driver);
14901da177e4SLinus Torvalds 	i8042_platform_exit();
14911da177e4SLinus Torvalds 
14921da177e4SLinus Torvalds 	panic_blink = NULL;
14931da177e4SLinus Torvalds }
14941da177e4SLinus Torvalds 
14951da177e4SLinus Torvalds module_init(i8042_init);
14961da177e4SLinus Torvalds module_exit(i8042_exit);
1497