2005-04-16 15:20:36 -07:00
/*
* i8042 keyboard and mouse controller driver for Linux
*
* Copyright ( c ) 1999 - 2004 Vojtech Pavlik
*/
/*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*/
# include <linux/delay.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <linux/config.h>
# include <linux/init.h>
# include <linux/serio.h>
# include <linux/err.h>
# include <linux/rcupdate.h>
# include <asm/io.h>
MODULE_AUTHOR ( " Vojtech Pavlik <vojtech@suse.cz> " ) ;
MODULE_DESCRIPTION ( " i8042 keyboard and mouse controller driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
static unsigned int i8042_noaux ;
module_param_named ( noaux , i8042_noaux , bool , 0 ) ;
MODULE_PARM_DESC ( noaux , " Do not probe or use AUX (mouse) port. " ) ;
static unsigned int i8042_nomux ;
module_param_named ( nomux , i8042_nomux , bool , 0 ) ;
MODULE_PARM_DESC ( nomux , " Do not check whether an active multiplexing conrtoller is present. " ) ;
static unsigned int i8042_unlock ;
module_param_named ( unlock , i8042_unlock , bool , 0 ) ;
MODULE_PARM_DESC ( unlock , " Ignore keyboard lock. " ) ;
static unsigned int i8042_reset ;
module_param_named ( reset , i8042_reset , bool , 0 ) ;
MODULE_PARM_DESC ( reset , " Reset controller during init and cleanup. " ) ;
static unsigned int i8042_direct ;
module_param_named ( direct , i8042_direct , bool , 0 ) ;
MODULE_PARM_DESC ( direct , " Put keyboard port into non-translated mode. " ) ;
static unsigned int i8042_dumbkbd ;
module_param_named ( dumbkbd , i8042_dumbkbd , bool , 0 ) ;
MODULE_PARM_DESC ( dumbkbd , " Pretend that controller can only read data from keyboard " ) ;
static unsigned int i8042_noloop ;
module_param_named ( noloop , i8042_noloop , bool , 0 ) ;
MODULE_PARM_DESC ( noloop , " Disable the AUX Loopback command while probing for the AUX port " ) ;
static unsigned int i8042_blink_frequency = 500 ;
module_param_named ( panicblink , i8042_blink_frequency , uint , 0600 ) ;
MODULE_PARM_DESC ( panicblink , " Frequency with which keyboard LEDs should blink when kernel panics " ) ;
# ifdef CONFIG_PNP
static int i8042_nopnp ;
module_param_named ( nopnp , i8042_nopnp , bool , 0 ) ;
MODULE_PARM_DESC ( nopnp , " Do not use PNP to detect controller settings " ) ;
# endif
# define DEBUG
# ifdef DEBUG
static int i8042_debug ;
module_param_named ( debug , i8042_debug , bool , 0600 ) ;
MODULE_PARM_DESC ( debug , " Turn i8042 debugging mode on and off " ) ;
# endif
__obsolete_setup ( " i8042_noaux " ) ;
__obsolete_setup ( " i8042_nomux " ) ;
__obsolete_setup ( " i8042_unlock " ) ;
__obsolete_setup ( " i8042_reset " ) ;
__obsolete_setup ( " i8042_direct " ) ;
__obsolete_setup ( " i8042_dumbkbd " ) ;
# include "i8042.h"
static DEFINE_SPINLOCK ( i8042_lock ) ;
struct i8042_port {
struct serio * serio ;
int irq ;
unsigned char disable ;
unsigned char irqen ;
unsigned char exists ;
signed char mux ;
char name [ 8 ] ;
} ;
# define I8042_KBD_PORT_NO 0
# define I8042_AUX_PORT_NO 1
# define I8042_MUX_PORT_NO 2
# define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2)
static struct i8042_port i8042_ports [ I8042_NUM_PORTS ] = {
{
. disable = I8042_CTR_KBDDIS ,
. irqen = I8042_CTR_KBDINT ,
. mux = - 1 ,
. name = " KBD " ,
} ,
{
. disable = I8042_CTR_AUXDIS ,
. irqen = I8042_CTR_AUXINT ,
. mux = - 1 ,
. name = " AUX " ,
}
} ;
static unsigned char i8042_initial_ctr ;
static unsigned char i8042_ctr ;
static unsigned char i8042_mux_open ;
static unsigned char i8042_mux_present ;
static struct timer_list i8042_timer ;
static struct platform_device * i8042_platform_device ;
/*
* Shared IRQ ' s require a device pointer , but this driver doesn ' t support
* multiple devices
*/
# define i8042_request_irq_cookie (&i8042_timer)
static irqreturn_t i8042_interrupt ( int irq , void * dev_id , struct pt_regs * regs ) ;
/*
* The i8042_wait_read ( ) and i8042_wait_write functions wait for the i8042 to
* be ready for reading values from it / writing values to it .
* Called always with i8042_lock held .
*/
static int i8042_wait_read ( void )
{
int i = 0 ;
while ( ( ~ i8042_read_status ( ) & I8042_STR_OBF ) & & ( i < I8042_CTL_TIMEOUT ) ) {
udelay ( 50 ) ;
i + + ;
}
return - ( i = = I8042_CTL_TIMEOUT ) ;
}
static int i8042_wait_write ( void )
{
int i = 0 ;
while ( ( i8042_read_status ( ) & I8042_STR_IBF ) & & ( i < I8042_CTL_TIMEOUT ) ) {
udelay ( 50 ) ;
i + + ;
}
return - ( i = = I8042_CTL_TIMEOUT ) ;
}
/*
* i8042_flush ( ) flushes all data that may be in the keyboard and mouse buffers
* of the i8042 down the toilet .
*/
static int i8042_flush ( void )
{
unsigned long flags ;
unsigned char data , str ;
int i = 0 ;
spin_lock_irqsave ( & i8042_lock , flags ) ;
while ( ( ( str = i8042_read_status ( ) ) & I8042_STR_OBF ) & & ( i < I8042_BUFFER_SIZE ) ) {
udelay ( 50 ) ;
data = i8042_read_data ( ) ;
i + + ;
dbg ( " %02x <- i8042 (flush, %s) " , data ,
str & I8042_STR_AUXDATA ? " aux " : " kbd " ) ;
}
spin_unlock_irqrestore ( & i8042_lock , flags ) ;
return i ;
}
/*
* i8042_command ( ) executes a command on the i8042 . It also sends the input
* parameter ( s ) of the commands to it , and receives the output value ( s ) . The
* parameters are to be stored in the param array , and the output is placed
* into the same array . The number of the parameters and output values is
* encoded in bits 8 - 11 of the command number .
*/
static int i8042_command ( unsigned char * param , int command )
{
unsigned long flags ;
int retval = 0 , i = 0 ;
if ( i8042_noloop & & command = = I8042_CMD_AUX_LOOP )
return - 1 ;
spin_lock_irqsave ( & i8042_lock , flags ) ;
retval = i8042_wait_write ( ) ;
if ( ! retval ) {
dbg ( " %02x -> i8042 (command) " , command & 0xff ) ;
i8042_write_command ( command & 0xff ) ;
}
if ( ! retval )
for ( i = 0 ; i < ( ( command > > 12 ) & 0xf ) ; i + + ) {
if ( ( retval = i8042_wait_write ( ) ) ) break ;
dbg ( " %02x -> i8042 (parameter) " , param [ i ] ) ;
i8042_write_data ( param [ i ] ) ;
}
if ( ! retval )
for ( i = 0 ; i < ( ( command > > 8 ) & 0xf ) ; i + + ) {
if ( ( retval = i8042_wait_read ( ) ) ) break ;
if ( i8042_read_status ( ) & I8042_STR_AUXDATA )
param [ i ] = ~ i8042_read_data ( ) ;
else
param [ i ] = i8042_read_data ( ) ;
dbg ( " %02x <- i8042 (return) " , param [ i ] ) ;
}
spin_unlock_irqrestore ( & i8042_lock , flags ) ;
if ( retval )
dbg ( " -- i8042 (timeout) " ) ;
return retval ;
}
/*
* i8042_kbd_write ( ) sends a byte out through the keyboard interface .
*/
static int i8042_kbd_write ( struct serio * port , unsigned char c )
{
unsigned long flags ;
int retval = 0 ;
spin_lock_irqsave ( & i8042_lock , flags ) ;
if ( ! ( retval = i8042_wait_write ( ) ) ) {
dbg ( " %02x -> i8042 (kbd-data) " , c ) ;
i8042_write_data ( c ) ;
}
spin_unlock_irqrestore ( & i8042_lock , flags ) ;
return retval ;
}
/*
* i8042_aux_write ( ) sends a byte out through the aux interface .
*/
static int i8042_aux_write ( struct serio * serio , unsigned char c )
{
struct i8042_port * port = serio - > port_data ;
int retval ;
/*
* Send the byte out .
*/
if ( port - > mux = = - 1 )
retval = i8042_command ( & c , I8042_CMD_AUX_SEND ) ;
else
retval = i8042_command ( & c , I8042_CMD_MUX_SEND + port - > mux ) ;
/*
* Make sure the interrupt happens and the character is received even
* in the case the IRQ isn ' t wired , so that we can receive further
* characters later .
*/
i8042_interrupt ( 0 , NULL , NULL ) ;
return retval ;
}
/*
* i8042_activate_port ( ) enables port on a chip .
*/
static int i8042_activate_port ( struct i8042_port * port )
{
if ( ! port - > serio )
return - 1 ;
i8042_flush ( ) ;
/*
* Enable port again here because it is disabled if we are
* resuming ( normally it is enabled already ) .
*/
i8042_ctr & = ~ port - > disable ;
i8042_ctr | = port - > irqen ;
if ( i8042_command ( & i8042_ctr , I8042_CMD_CTL_WCTR ) ) {
i8042_ctr & = ~ port - > irqen ;
return - 1 ;
}
return 0 ;
}
/*
* i8042_open ( ) is called when a port is open by the higher layer .
* It allocates the interrupt and calls i8042_enable_port .
*/
static int i8042_open ( struct serio * serio )
{
struct i8042_port * port = serio - > port_data ;
if ( port - > mux ! = - 1 )
if ( i8042_mux_open + + )
return 0 ;
if ( request_irq ( port - > irq , i8042_interrupt ,
SA_SHIRQ , " i8042 " , i8042_request_irq_cookie ) ) {
printk ( KERN_ERR " i8042.c: Can't get irq %d for %s, unregistering the port. \n " , port - > irq , port - > name ) ;
goto irq_fail ;
}
if ( i8042_activate_port ( port ) ) {
printk ( KERN_ERR " i8042.c: Can't activate %s, unregistering the port \n " , port - > name ) ;
goto activate_fail ;
}
i8042_interrupt ( 0 , NULL , NULL ) ;
return 0 ;
activate_fail :
free_irq ( port - > irq , i8042_request_irq_cookie ) ;
irq_fail :
serio_unregister_port_delayed ( serio ) ;
return - 1 ;
}
/*
* i8042_close ( ) frees the interrupt , so that it can possibly be used
* by another driver . We never know - if the user doesn ' t have a mouse ,
* the BIOS could have used the AUX interrupt for PCI .
*/
static void i8042_close ( struct serio * serio )
{
struct i8042_port * port = serio - > port_data ;
if ( port - > mux ! = - 1 )
if ( - - i8042_mux_open )
return ;
i8042_ctr & = ~ port - > irqen ;
if ( i8042_command ( & i8042_ctr , I8042_CMD_CTL_WCTR ) ) {
printk ( KERN_WARNING " i8042.c: Can't write CTR while closing %s. \n " , port - > name ) ;
/*
* We still want to continue and free IRQ so if more data keeps coming in
* kernel will just ignore the irq .
*/
}
free_irq ( port - > irq , i8042_request_irq_cookie ) ;
i8042_flush ( ) ;
}
/*
* i8042_start ( ) is called by serio core when port is about to finish
* registering . It will mark port as existing so i8042_interrupt can
* start sending data through it .
*/
static int i8042_start ( struct serio * serio )
{
struct i8042_port * port = serio - > port_data ;
port - > exists = 1 ;
mb ( ) ;
return 0 ;
}
/*
* i8042_stop ( ) marks serio port as non - existing so i8042_interrupt
* will not try to send data to the port that is about to go away .
* The function is called by serio core as part of unregister procedure .
*/
static void i8042_stop ( struct serio * serio )
{
struct i8042_port * port = serio - > port_data ;
port - > exists = 0 ;
2005-06-25 14:55:38 -07:00
synchronize_sched ( ) ;
2005-04-16 15:20:36 -07:00
port - > serio = NULL ;
}
/*
* i8042_interrupt ( ) is the most important function in this driver -
* it handles the interrupts from the i8042 , and sends incoming bytes
* to the upper layers .
*/
static irqreturn_t i8042_interrupt ( int irq , void * dev_id , struct pt_regs * regs )
{
struct i8042_port * port ;
unsigned long flags ;
unsigned char str , data ;
unsigned int dfl ;
unsigned int port_no ;
int ret ;
mod_timer ( & i8042_timer , jiffies + I8042_POLL_PERIOD ) ;
spin_lock_irqsave ( & i8042_lock , flags ) ;
str = i8042_read_status ( ) ;
if ( unlikely ( ~ str & I8042_STR_OBF ) ) {
spin_unlock_irqrestore ( & i8042_lock , flags ) ;
if ( irq ) dbg ( " Interrupt %d, without any data " , irq ) ;
ret = 0 ;
goto out ;
}
data = i8042_read_data ( ) ;
spin_unlock_irqrestore ( & i8042_lock , flags ) ;
if ( i8042_mux_present & & ( str & I8042_STR_AUXDATA ) ) {
static unsigned long last_transmit ;
static unsigned char last_str ;
dfl = 0 ;
if ( str & I8042_STR_MUXERR ) {
dbg ( " MUX error, status is %02x, data is %02x " , str , data ) ;
switch ( data ) {
default :
/*
* When MUXERR condition is signalled the data register can only contain
* 0xfd , 0xfe or 0xff if implementation follows the spec . Unfortunately
* it is not always the case . Some KBC just get confused which port the
* data came from and signal error leaving the data intact . They _do not_
* revert to legacy mode ( actually I ' ve never seen KBC reverting to legacy
* mode yet , when we see one we ' ll add proper handling ) .
* Anyway , we will assume that the data came from the same serio last byte
* was transmitted ( if transmission happened not too long ago ) .
*/
if ( time_before ( jiffies , last_transmit + HZ / 10 ) ) {
str = last_str ;
break ;
}
/* fall through - report timeout */
case 0xfd :
case 0xfe : dfl = SERIO_TIMEOUT ; data = 0xfe ; break ;
case 0xff : dfl = SERIO_PARITY ; data = 0xfe ; break ;
}
}
port_no = I8042_MUX_PORT_NO + ( ( str > > 6 ) & 3 ) ;
last_str = str ;
last_transmit = jiffies ;
} else {
dfl = ( ( str & I8042_STR_PARITY ) ? SERIO_PARITY : 0 ) |
( ( str & I8042_STR_TIMEOUT ) ? SERIO_TIMEOUT : 0 ) ;
port_no = ( str & I8042_STR_AUXDATA ) ?
I8042_AUX_PORT_NO : I8042_KBD_PORT_NO ;
}
port = & i8042_ports [ port_no ] ;
dbg ( " %02x <- i8042 (interrupt, %s, %d%s%s) " ,
data , port - > name , irq ,
dfl & SERIO_PARITY ? " , bad parity " : " " ,
dfl & SERIO_TIMEOUT ? " , timeout " : " " ) ;
if ( likely ( port - > exists ) )
serio_interrupt ( port - > serio , data , dfl , regs ) ;
ret = 1 ;
out :
return IRQ_RETVAL ( ret ) ;
}
/*
* i8042_set_mux_mode checks whether the controller has an active
* multiplexor and puts the chip into Multiplexed ( 1 ) or Legacy ( 0 ) mode .
*/
static int i8042_set_mux_mode ( unsigned int mode , unsigned char * mux_version )
{
unsigned char param ;
/*
* Get rid of bytes in the queue .
*/
i8042_flush ( ) ;
/*
* Internal loopback test - send three bytes , they should come back from the
* mouse interface , the last should be version . Note that we negate mouseport
* command responses for the i8042_check_aux ( ) routine .
*/
param = 0xf0 ;
if ( i8042_command ( & param , I8042_CMD_AUX_LOOP ) | | param ! = 0x0f )
return - 1 ;
param = mode ? 0x56 : 0xf6 ;
if ( i8042_command ( & param , I8042_CMD_AUX_LOOP ) | | param ! = ( mode ? 0xa9 : 0x09 ) )
return - 1 ;
param = mode ? 0xa4 : 0xa5 ;
if ( i8042_command ( & param , I8042_CMD_AUX_LOOP ) | | param = = ( mode ? 0x5b : 0x5a ) )
return - 1 ;
if ( mux_version )
* mux_version = ~ param ;
return 0 ;
}
/*
* i8042_enable_mux_ports enables 4 individual AUX ports after
* the controller has been switched into Multiplexed mode
*/
static int i8042_enable_mux_ports ( void )
{
unsigned char param ;
int i ;
/*
* Disable all muxed ports by disabling AUX .
*/
i8042_ctr | = I8042_CTR_AUXDIS ;
i8042_ctr & = ~ I8042_CTR_AUXINT ;
if ( i8042_command ( & i8042_ctr , I8042_CMD_CTL_WCTR ) ) {
printk ( KERN_ERR " i8042.c: Failed to disable AUX port, can't use MUX. \n " ) ;
return - 1 ;
}
/*
* Enable all muxed ports .
*/
for ( i = 0 ; i < 4 ; i + + ) {
i8042_command ( & param , I8042_CMD_MUX_PFX + i ) ;
i8042_command ( & param , I8042_CMD_AUX_ENABLE ) ;
}
return 0 ;
}
/*
* i8042_check_mux ( ) checks whether the controller supports the PS / 2 Active
* Multiplexing specification by Synaptics , Phoenix , Insyde and
* LCS / Telegraphics .
*/
static int __init i8042_check_mux ( void )
{
unsigned char mux_version ;
if ( i8042_set_mux_mode ( 1 , & mux_version ) )
return - 1 ;
/* Workaround for interference with USB Legacy emulation */
/* that causes a v10.12 MUX to be found. */
if ( mux_version = = 0xAC )
return - 1 ;
printk ( KERN_INFO " i8042.c: Detected active multiplexing controller, rev %d.%d. \n " ,
( mux_version > > 4 ) & 0xf , mux_version & 0xf ) ;
if ( i8042_enable_mux_ports ( ) )
return - 1 ;
i8042_mux_present = 1 ;
return 0 ;
}
/*
* i8042_check_aux ( ) applies as much paranoia as it can at detecting
* the presence of an AUX interface .
*/
static int __init i8042_check_aux ( void )
{
unsigned char param ;
static int i8042_check_aux_cookie ;
/*
* Check if AUX irq is available . If it isn ' t , then there is no point
* in trying to detect AUX presence .
*/
if ( request_irq ( i8042_ports [ I8042_AUX_PORT_NO ] . irq , i8042_interrupt ,
SA_SHIRQ , " i8042 " , & i8042_check_aux_cookie ) )
return - 1 ;
free_irq ( i8042_ports [ I8042_AUX_PORT_NO ] . irq , & i8042_check_aux_cookie ) ;
/*
* Get rid of bytes in the queue .
*/
i8042_flush ( ) ;
/*
* Internal loopback test - filters out AT - type i8042 ' s . Unfortunately
* SiS screwed up and their 5597 doesn ' t support the LOOP command even
* though it has an AUX port .
*/
param = 0x5a ;
if ( i8042_command ( & param , I8042_CMD_AUX_LOOP ) | | param ! = 0xa5 ) {
/*
* External connection test - filters out AT - soldered PS / 2 i8042 ' s
* 0x00 - no error , 0x01 - 0x03 - clock / data stuck , 0xff - general error
* 0xfa - no error on some notebooks which ignore the spec
* Because it ' s common for chipsets to return error on perfectly functioning
* AUX ports , we test for this only when the LOOP command failed .
*/
if ( i8042_command ( & param , I8042_CMD_AUX_TEST )
| | ( param & & param ! = 0xfa & & param ! = 0xff ) )
return - 1 ;
}
/*
* Bit assignment test - filters out PS / 2 i8042 ' s in AT mode
*/
if ( i8042_command ( & param , I8042_CMD_AUX_DISABLE ) )
return - 1 ;
if ( i8042_command ( & param , I8042_CMD_CTL_RCTR ) | | ( ~ param & I8042_CTR_AUXDIS ) ) {
printk ( KERN_WARNING " Failed to disable AUX port, but continuing anyway... Is this a SiS? \n " ) ;
printk ( KERN_WARNING " If AUX port is really absent please use the 'i8042.noaux' option. \n " ) ;
}
if ( i8042_command ( & param , I8042_CMD_AUX_ENABLE ) )
return - 1 ;
if ( i8042_command ( & param , I8042_CMD_CTL_RCTR ) | | ( param & I8042_CTR_AUXDIS ) )
return - 1 ;
/*
* Disable the interface .
*/
i8042_ctr | = I8042_CTR_AUXDIS ;
i8042_ctr & = ~ I8042_CTR_AUXINT ;
if ( i8042_command ( & i8042_ctr , I8042_CMD_CTL_WCTR ) )
return - 1 ;
return 0 ;
}
/*
* i8042_port_register ( ) marks the device as existing ,
* registers it , and reports to the user .
*/
static int __init i8042_port_register ( struct i8042_port * port )
{
i8042_ctr & = ~ port - > disable ;
if ( i8042_command ( & i8042_ctr , I8042_CMD_CTL_WCTR ) ) {
printk ( KERN_WARNING " i8042.c: Can't write CTR while registering. \n " ) ;
kfree ( port - > serio ) ;
port - > serio = NULL ;
i8042_ctr | = port - > disable ;
return - 1 ;
}
printk ( KERN_INFO " serio: i8042 %s port at %#lx,%#lx irq %d \n " ,
port - > name ,
( unsigned long ) I8042_DATA_REG ,
( unsigned long ) I8042_COMMAND_REG ,
port - > irq ) ;
serio_register_port ( port - > serio ) ;
return 0 ;
}
static void i8042_timer_func ( unsigned long data )
{
i8042_interrupt ( 0 , NULL , NULL ) ;
}
2005-05-28 02:11:27 -05:00
static int i8042_ctl_test ( void )
{
unsigned char param ;
if ( ! i8042_reset )
return 0 ;
if ( i8042_command ( & param , I8042_CMD_CTL_TEST ) ) {
printk ( KERN_ERR " i8042.c: i8042 controller self test timeout. \n " ) ;
return - 1 ;
}
if ( param ! = I8042_RET_CTL_TEST ) {
printk ( KERN_ERR " i8042.c: i8042 controller selftest failed. (%#x != %#x) \n " ,
param , I8042_RET_CTL_TEST ) ;
return - 1 ;
}
return 0 ;
}
2005-04-16 15:20:36 -07:00
/*
* i8042_controller init initializes the i8042 controller , and ,
* most importantly , sets it into non - xlated mode if that ' s
* desired .
*/
static int i8042_controller_init ( void )
{
unsigned long flags ;
/*
* Test the i8042 . We need to know if it thinks it ' s working correctly
* before doing anything else .
*/
if ( i8042_flush ( ) = = I8042_BUFFER_SIZE ) {
printk ( KERN_ERR " i8042.c: No controller found. \n " ) ;
return - 1 ;
}
2005-05-28 02:11:27 -05:00
if ( i8042_ctl_test ( ) )
return - 1 ;
2005-04-16 15:20:36 -07:00
/*
* Save the CTR for restoral on unload / reboot .
*/
if ( i8042_command ( & i8042_ctr , I8042_CMD_CTL_RCTR ) ) {
printk ( KERN_ERR " i8042.c: Can't read CTR while initializing i8042. \n " ) ;
return - 1 ;
}
i8042_initial_ctr = i8042_ctr ;
/*
* Disable the keyboard interface and interrupt .
*/
i8042_ctr | = I8042_CTR_KBDDIS ;
i8042_ctr & = ~ I8042_CTR_KBDINT ;
/*
* Handle keylock .
*/
spin_lock_irqsave ( & i8042_lock , flags ) ;
if ( ~ i8042_read_status ( ) & I8042_STR_KEYLOCK ) {
if ( i8042_unlock )
i8042_ctr | = I8042_CTR_IGNKEYLOCK ;
else
printk ( KERN_WARNING " i8042.c: Warning: Keylock active. \n " ) ;
}
spin_unlock_irqrestore ( & i8042_lock , flags ) ;
/*
* If the chip is configured into nontranslated mode by the BIOS , don ' t
* bother enabling translating and be happy .
*/
if ( ~ i8042_ctr & I8042_CTR_XLATE )
i8042_direct = 1 ;
/*
* Set nontranslated mode for the kbd interface if requested by an option .
* After this the kbd interface becomes a simple serial in / out , like the aux
* interface is . We don ' t do this by default , since it can confuse notebook
* BIOSes .
*/
if ( i8042_direct )
i8042_ctr & = ~ I8042_CTR_XLATE ;
/*
* Write CTR back .
*/
if ( i8042_command ( & i8042_ctr , I8042_CMD_CTL_WCTR ) ) {
printk ( KERN_ERR " i8042.c: Can't write CTR while initializing i8042. \n " ) ;
return - 1 ;
}
return 0 ;
}
/*
* Reset the controller .
*/
static void i8042_controller_reset ( void )
{
/*
* Reset the controller if requested .
*/
2005-05-28 02:11:27 -05:00
i8042_ctl_test ( ) ;
2005-04-16 15:20:36 -07:00
/*
* Disable MUX mode if present .
*/
if ( i8042_mux_present )
i8042_set_mux_mode ( 0 , NULL ) ;
/*
* Restore the original control register setting .
*/
i8042_ctr = i8042_initial_ctr ;
if ( i8042_command ( & i8042_ctr , I8042_CMD_CTL_WCTR ) )
printk ( KERN_WARNING " i8042.c: Can't restore CTR. \n " ) ;
}
/*
* Here we try to reset everything back to a state in which the BIOS will be
* able to talk to the hardware when rebooting .
*/
static void i8042_controller_cleanup ( void )
{
int i ;
i8042_flush ( ) ;
/*
* Reset anything that is connected to the ports .
*/
for ( i = 0 ; i < I8042_NUM_PORTS ; i + + )
if ( i8042_ports [ i ] . exists )
serio_cleanup ( i8042_ports [ i ] . serio ) ;
i8042_controller_reset ( ) ;
}
/*
* i8042_panic_blink ( ) will flash the keyboard LEDs and is called when
* kernel panics . Flashing LEDs is useful for users running X who may
* not see the console and will help distingushing panics from " real "
* lockups .
*
* Note that DELAY has a limit of 10 ms so we will not get stuck here
* waiting for KBC to free up even if KBD interrupt is off
*/
# define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
static long i8042_panic_blink ( long count )
{
long delay = 0 ;
static long last_blink ;
static char led ;
/*
* We expect frequency to be about 1 / 2 s . KDB uses about 1 s .
* Make sure they are different .
*/
if ( ! i8042_blink_frequency )
return 0 ;
if ( count - last_blink < i8042_blink_frequency )
return 0 ;
led ^ = 0x01 | 0x04 ;
while ( i8042_read_status ( ) & I8042_STR_IBF )
DELAY ;
i8042_write_data ( 0xed ) ; /* set leds */
DELAY ;
while ( i8042_read_status ( ) & I8042_STR_IBF )
DELAY ;
DELAY ;
i8042_write_data ( led ) ;
DELAY ;
last_blink = count ;
return delay ;
}
# undef DELAY
/*
* Here we try to restore the original BIOS settings
*/
static int i8042_suspend ( struct device * dev , pm_message_t state , u32 level )
{
if ( level = = SUSPEND_DISABLE ) {
del_timer_sync ( & i8042_timer ) ;
i8042_controller_reset ( ) ;
}
return 0 ;
}
/*
* Here we try to reset everything back to a state in which suspended
*/
static int i8042_resume ( struct device * dev , u32 level )
{
int i ;
if ( level ! = RESUME_ENABLE )
return 0 ;
2005-05-28 02:11:27 -05:00
if ( i8042_ctl_test ( ) )
return - 1 ;
if ( i8042_command ( & i8042_ctr , I8042_CMD_CTL_WCTR ) ) {
printk ( KERN_ERR " i8042: Can't write CTR \n " ) ;
2005-04-16 15:20:36 -07:00
return - 1 ;
}
if ( i8042_mux_present )
if ( i8042_set_mux_mode ( 1 , NULL ) | | i8042_enable_mux_ports ( ) )
printk ( KERN_WARNING " i8042: failed to resume active multiplexor, mouse won't work. \n " ) ;
/*
* Activate all ports .
*/
for ( i = 0 ; i < I8042_NUM_PORTS ; i + + )
i8042_activate_port ( & i8042_ports [ i ] ) ;
/*
* Restart timer ( for polling " stuck " data )
*/
mod_timer ( & i8042_timer , jiffies + I8042_POLL_PERIOD ) ;
panic_blink = i8042_panic_blink ;
return 0 ;
}
/*
* We need to reset the 8042 back to original mode on system shutdown ,
* because otherwise BIOSes will be confused .
*/
static void i8042_shutdown ( struct device * dev )
{
i8042_controller_cleanup ( ) ;
}
static struct device_driver i8042_driver = {
. name = " i8042 " ,
. bus = & platform_bus_type ,
. suspend = i8042_suspend ,
. resume = i8042_resume ,
. shutdown = i8042_shutdown ,
} ;
static void __init i8042_create_kbd_port ( void )
{
struct serio * serio ;
struct i8042_port * port = & i8042_ports [ I8042_KBD_PORT_NO ] ;
serio = kmalloc ( sizeof ( struct serio ) , GFP_KERNEL ) ;
if ( serio ) {
memset ( serio , 0 , sizeof ( struct serio ) ) ;
serio - > id . type = i8042_direct ? SERIO_8042 : SERIO_8042_XL ;
serio - > write = i8042_dumbkbd ? NULL : i8042_kbd_write ;
serio - > open = i8042_open ;
serio - > close = i8042_close ;
serio - > start = i8042_start ;
serio - > stop = i8042_stop ;
serio - > port_data = port ;
serio - > dev . parent = & i8042_platform_device - > dev ;
strlcpy ( serio - > name , " i8042 Kbd Port " , sizeof ( serio - > name ) ) ;
strlcpy ( serio - > phys , I8042_KBD_PHYS_DESC , sizeof ( serio - > phys ) ) ;
port - > serio = serio ;
i8042_port_register ( port ) ;
}
}
static void __init i8042_create_aux_port ( void )
{
struct serio * serio ;
struct i8042_port * port = & i8042_ports [ I8042_AUX_PORT_NO ] ;
serio = kmalloc ( sizeof ( struct serio ) , GFP_KERNEL ) ;
if ( serio ) {
memset ( serio , 0 , sizeof ( struct serio ) ) ;
serio - > id . type = SERIO_8042 ;
serio - > write = i8042_aux_write ;
serio - > open = i8042_open ;
serio - > close = i8042_close ;
serio - > start = i8042_start ;
serio - > stop = i8042_stop ;
serio - > port_data = port ;
serio - > dev . parent = & i8042_platform_device - > dev ;
strlcpy ( serio - > name , " i8042 Aux Port " , sizeof ( serio - > name ) ) ;
strlcpy ( serio - > phys , I8042_AUX_PHYS_DESC , sizeof ( serio - > phys ) ) ;
port - > serio = serio ;
i8042_port_register ( port ) ;
}
}
static void __init i8042_create_mux_port ( int index )
{
struct serio * serio ;
struct i8042_port * port = & i8042_ports [ I8042_MUX_PORT_NO + index ] ;
serio = kmalloc ( sizeof ( struct serio ) , GFP_KERNEL ) ;
if ( serio ) {
memset ( serio , 0 , sizeof ( struct serio ) ) ;
serio - > id . type = SERIO_8042 ;
serio - > write = i8042_aux_write ;
serio - > open = i8042_open ;
serio - > close = i8042_close ;
serio - > start = i8042_start ;
serio - > stop = i8042_stop ;
serio - > port_data = port ;
serio - > dev . parent = & i8042_platform_device - > dev ;
snprintf ( serio - > name , sizeof ( serio - > name ) , " i8042 Aux-%d Port " , index ) ;
snprintf ( serio - > phys , sizeof ( serio - > phys ) , I8042_MUX_PHYS_DESC , index + 1 ) ;
* port = i8042_ports [ I8042_AUX_PORT_NO ] ;
port - > exists = 0 ;
snprintf ( port - > name , sizeof ( port - > name ) , " AUX%d " , index ) ;
port - > mux = index ;
port - > serio = serio ;
i8042_port_register ( port ) ;
}
}
static int __init i8042_init ( void )
{
int i ;
int err ;
dbg_init ( ) ;
init_timer ( & i8042_timer ) ;
i8042_timer . function = i8042_timer_func ;
if ( i8042_platform_init ( ) )
return - EBUSY ;
i8042_ports [ I8042_AUX_PORT_NO ] . irq = I8042_AUX_IRQ ;
i8042_ports [ I8042_KBD_PORT_NO ] . irq = I8042_KBD_IRQ ;
if ( i8042_controller_init ( ) ) {
i8042_platform_exit ( ) ;
return - ENODEV ;
}
err = driver_register ( & i8042_driver ) ;
if ( err ) {
i8042_platform_exit ( ) ;
return err ;
}
i8042_platform_device = platform_device_register_simple ( " i8042 " , - 1 , NULL , 0 ) ;
if ( IS_ERR ( i8042_platform_device ) ) {
driver_unregister ( & i8042_driver ) ;
i8042_platform_exit ( ) ;
return PTR_ERR ( i8042_platform_device ) ;
}
if ( ! i8042_noaux & & ! i8042_check_aux ( ) ) {
if ( ! i8042_nomux & & ! i8042_check_mux ( ) )
for ( i = 0 ; i < I8042_NUM_MUX_PORTS ; i + + )
i8042_create_mux_port ( i ) ;
else
i8042_create_aux_port ( ) ;
}
i8042_create_kbd_port ( ) ;
mod_timer ( & i8042_timer , jiffies + I8042_POLL_PERIOD ) ;
return 0 ;
}
static void __exit i8042_exit ( void )
{
int i ;
i8042_controller_cleanup ( ) ;
for ( i = 0 ; i < I8042_NUM_PORTS ; i + + )
if ( i8042_ports [ i ] . exists )
serio_unregister_port ( i8042_ports [ i ] . serio ) ;
del_timer_sync ( & i8042_timer ) ;
platform_device_unregister ( i8042_platform_device ) ;
driver_unregister ( & i8042_driver ) ;
i8042_platform_exit ( ) ;
panic_blink = NULL ;
}
module_init ( i8042_init ) ;
module_exit ( i8042_exit ) ;