summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/ppcn_60x/console/i8042.c
blob: 93ca26aced460d92b45fb3137bc1d16b24463e80 (plain) (tree)

























                                                                           
                           
                          
























































                                                                        
                          






















                                                              

                               























                                                             
                        

 

                         

                          
                             





































                                                                         
                          

 
                         
















                                                                 
                          







































                                                                     

                          





                                            
                           

 

                         

















                                                                           
      



















                                                          
                         

























































































































                                                      
                         


















































                                                                    
                              




                             
                                      





























































































































































                                                                              
                        




































































































                                                                            
                          





































































































































                                                                                

                                               















































                                                                      
                                































                                                        
                               

































                                                                  

                               




















































































                                                                                
/*
 *  This file contains the PS2 keyboard driver for the i8042
 *
 *  Note that this driver will only handle a single i8042 device
 *
 *  COPYRIGHT (c) 1998 by Radstone Technology
 *
 *
 * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
 * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
 *
 * You are hereby granted permission to use, copy, modify, and distribute
 * this file, provided that this notice, plus the above copyright notice
 * and disclaimer, appears in all copies. Radstone Technology will provide
 * no support for this code.
 *
 *  This driver uses the termios pseudo driver.
 *
 *  $Id$
 */

#include <rtems.h>
#include <bsp.h>
#include <rtems/libio.h>
#include <libchip/serial.h>
#include <rtems/ringbuf.h>

#include "console.h"
#include "i8042_p.h"
#include "vga_p.h"

/*
 * UK style keyboard
 */
char pcUKNormalLookup[] = "1234567890-=\b\tqwertyuiop[]\n\0asdfghjkl;\'"
			  "`\0#zxcvbnm,./\0*\0 \0\0\0\0\0\0\0\0\0\0\0\0"
			  "\000789-456+1230.\0\0\\";
char pcUKShiftedLookup[]= "!\"£$%^&*()_+\b\tQWERTYUIOP{}\n\0ASDFGHJKL:"
			  "@\0\0~ZXCVBNM<>?\0*\0 \0\0\0\0\0\0\0\0\0\0\0"
			  "\0\000789-456+1230.\0\0|";
/*
 * US style keyboard
 */
char pcUSNormalLookup[] = "1234567890-=\b\tqwertyuiop[]\n\0asdfghjkl;\'"
			  "`\0\\zxcvbnm,./\0*\0 \0\0\0\0\0\0\0\0\0\0\0"
			  "\0\000789-456+1230.\0\0\\";
char pcUSShiftedLookup[]= "!@#$%^&*()_+\b\tQWERTYUIOP{}\n\0ASDFGHJKL:@~"
			  "\0|ZXCVBNM<>?\0*\0 \0\0\0\0\0\0\0\0\0\0\0\0"
			  "\000789-456+1230.\0\0|";

static char *pcNormalLookup;
static char *pcShiftedLookup;

/*
 * This is exported to vga.c to provide flow control
 */
volatile boolean bScrollLock=FALSE;

/*
 * If multiple devices are to be supported then a private copy of
 * the following will be required for each instance
 */
static boolean bCtrlPressed=FALSE;
static boolean bAltPressed=FALSE;
static boolean bAltGrPressed=FALSE;
static boolean bLShiftPressed=FALSE;
static boolean bRShiftPressed=FALSE;
static boolean bCapsLock=FALSE;
static boolean bNumLock=FALSE;
static boolean bTwoCode=FALSE;

#if CONSOLE_USE_INTERRUPTS
static volatile Ring_buffer_t KbdOutputBuffer;
static volatile boolean bProcessInterruptInput=FALSE;
static boolean bInterruptsEnabled=FALSE;
static volatile boolean bReceivedAck=TRUE;

static void i8042_process(
	int minor
);

static void i8042_scan_code(
	int minor,
	uint8_t     ucScan
);
#endif

static volatile Ring_buffer_t KbdInputBuffer;

/*
 * The following routines enable an interrupt driver to switch
 * to polled mode as required for command processing
 */
void i8042_polled_on(
	int minor 
)
{
#if CONSOLE_USE_INTERRUPTS
	bProcessInterruptInput=FALSE;
#endif
}

void i8042_polled_off(
	int minor 
)
{
#if CONSOLE_USE_INTERRUPTS
	uint32_t  	Irql;
	uint8_t  	ucScan;

	/*
	 * Make sure we have processed everything outstanding
	 */
	rtems_interrupt_disable(Irql);
	while(!Ring_buffer_Is_empty(&KbdInputBuffer))
	{
		rtems_interrupt_enable(Irql);
		Ring_buffer_Remove_character(&KbdInputBuffer,
					     ucScan);
		i8042_scan_code(minor, ucScan);
		rtems_interrupt_disable(Irql);
	}
	bProcessInterruptInput=TRUE;
	rtems_interrupt_enable(Irql);
#endif
}

/*
 * Send data to the keyboard
 */
static rtems_status_code
i8042_outbyte_raw(
	int minor,
	uint8_t   ucData
)
{
	uint32_t   i;
	uint8_t   Status;

#if CONSOLE_USE_INTERRUPTS
	uint32_t  	Irql;

	if(bInterruptsEnabled)
	{
		Ring_buffer_Add_character(&KbdOutputBuffer,
					  ucData);
		if(!Console_Port_Data[minor].bActive)
		{
			/*
			 * Wake up the device
			 */
			rtems_interrupt_disable(Irql);
			Console_Port_Data[minor].bActive=TRUE;
			i8042_process(minor);
			rtems_interrupt_enable(Irql);

		}
		return RTEMS_SUCCESSFUL;
	}
#endif
	for (i=0; i<KBD_TIMEOUT; i++)
	{
		inport_byte(Console_Port_Tbl[minor].ulCtrlPort1, Status);
		if((Status & KBD_IBF_MASK)==0)
		{
			outport_byte(Console_Port_Tbl[minor].ulDataPort,
				     ucData);
			return RTEMS_SUCCESSFUL;
		}
	}
	return RTEMS_TIMEOUT;
}

/*
 * Read data from the keyboard
 */
static rtems_status_code
i8042_inbyte_polled(
	int minor,
	uint8_t   *pucData
)
{
	uint8_t   Status;

	inport_byte(Console_Port_Tbl[minor].ulCtrlPort1, Status);
	if(Status & KBD_OBF_MASK)
	{
		inport_byte(Console_Port_Tbl[minor].ulDataPort,
			    *pucData);
		return RTEMS_SUCCESSFUL;
	}
	return RTEMS_TIMEOUT;
}

/*
 * Blocking read data from the keyboard
 */
static rtems_status_code
i8042_inbyte_raw(
	int minor,
	uint8_t   *pucData
)
{
	int i;

#if CONSOLE_USE_INTERRUPTS
	if(bInterruptsEnabled)
	{
		i=0;
		while(Ring_buffer_Is_empty(&KbdInputBuffer))
		{
			rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
			if(i++==KBD_TIMEOUT)
			{
				return RTEMS_TIMEOUT;
			}
		}
		Ring_buffer_Remove_character(&KbdInputBuffer,
					     *pucData);
	}
	else
#endif
	{
		for (i=0; i<KBD_TIMEOUT; i++)
		{
			if(i8042_inbyte_polled(minor, pucData)==
			      RTEMS_SUCCESSFUL)
			{
				return RTEMS_SUCCESSFUL;
			}
			/*
			 * Wait for a character to be recieved
			 */
		}

		return RTEMS_TIMEOUT;
	}

	return RTEMS_SUCCESSFUL;
}

#if CONSOLE_USE_INTERRUPTS

/*
 * Send a command to the keyboard controller
 */
static rtems_status_code
i8042_outbyte_cmd_polled(
	int minor,
	uint8_t   ucCommand
)
{
	uint32_t   i;
	uint8_t   Status;

	/*
	 * This routine may be called when no clock driver is available
	 * so the timeout is dependant on the ISA bus timing used to access
	 * the i8042 which will not vary (much) across platforms.
	 */
	for (i=0; i<KBD_TIMEOUT; i++)
	{
		inport_byte(Console_Port_Tbl[minor].ulCtrlPort1, Status);
		if((Status & KBD_IBF_MASK)==0)
		{
			outport_byte(Console_Port_Tbl[minor].ulCtrlPort1,
				     ucCommand);
			return RTEMS_SUCCESSFUL;
		}
	}
	return RTEMS_TIMEOUT;
}
#endif

void EnqueueKbdChar(
	int minor,
	char cChar
)
{
#if CONSOLE_USE_INTERRUPTS
	rtems_termios_enqueue_raw_characters(
		Console_Port_Data[minor].termios_data,
		&cChar,
		1);
#else
	Ring_buffer_Add_character(&KbdInputBuffer, cChar);
#endif
}
/*
 * Process second code in a two code sequence
 */
static void i8042_process_two_code(
	int minor,
	uint8_t   ucScan,
	boolean bMakenBreak
)
{
	char cASCIICtrlCode;
	char cASCIICode;

	cASCIICtrlCode='\0';
	cASCIICode='\0';

	switch(ucScan)
	{
		case KEY_ALT:
		{
			bAltGrPressed=bMakenBreak;
			break;
		}

		case KEY_CONTROL:
		{
			bCtrlPressed=bMakenBreak;
			break;
		}

		case KEY_INSERT:
		{
			cASCIICtrlCode='@';
			break;
		}

		case KEY_DELETE:
		{
			cASCIICode=ASCII_DEL;
			break;
		}

		case KEY_LEFT_ARROW:
		{
			cASCIICtrlCode='D';
			break;
		}

		case KEY_HOME:
		{
			cASCIICtrlCode='H';
			break;
		}

		case KEY_END:
		{
			cASCIICtrlCode='K';
			break;
		}

		case KEY_UP_ARROW:
		{
			cASCIICtrlCode='A';
			break;
		}

		case KEY_DOWN_ARROW:
		{
			cASCIICtrlCode='B';
			break;
		}

		case KEY_PAGE_UP:
		{
			cASCIICtrlCode='?';
			break;
		}

		case KEY_PAGE_DOWN:
		{
			cASCIICtrlCode='/';
			break;
		}

		case KEY_RIGHT_ARROW:
		{
			cASCIICtrlCode='C';
			break;
		}

		case KEY_KEYPAD_SLASH:
		{
			cASCIICode='/';
			break;
		}

		case KEY_KEYPAD_ENTER:
		{
			cASCIICode=ASCII_CR;
			break;
		}

		case KEY_PRINT_SCREEN:
		{
			cASCIICode=ASCII_SYSRQ;
			break;
		}

		default:
		{
			/*
			 * Ignore this code
			 */
			break;
		}
	}

	if(bMakenBreak && cASCIICode)
	{
		EnqueueKbdChar(minor, cASCIICode);
	}
	else if(bMakenBreak && cASCIICtrlCode)
	{
		EnqueueKbdChar(minor, ASCII_CSI);
		EnqueueKbdChar(minor, cASCIICtrlCode);
	}
}

static boolean i8042_process_qualifiers(
	uint8_t   ucScan,
	boolean	bMakenBreak
)
{
	boolean	bProcessed;

	/*
	 * Check for scan codes for shift, control, or alt keys.
	 */
	bProcessed=TRUE;

	switch (ucScan)
	{
		case KEY_LEFT_SHIFT:
		{
			bLShiftPressed=bMakenBreak;
			break;
		}

		case KEY_RIGHT_SHIFT:
		{
			bRShiftPressed=bMakenBreak;
			break;
		}

		case KEY_CONTROL:
		{
			bCtrlPressed=bMakenBreak;
			break;
		}

		case KEY_ALT:
		{
			bAltPressed=bMakenBreak;
			break;
		}

		default:
		{
			/*
			 * Something else needs to process this code
			 */
			bProcessed=FALSE;
			break;
		}
	}

	return(bProcessed);
}

static boolean i8042_process_top_row(
	int		minor,
	uint8_t  	ucScan
)
{
	boolean	bProcessed;
	char	cASCIIFnCode;
#if CONSOLE_USE_INTERRUPTS==0
	uint8_t  	ucKeyboardAck;
#endif

	/*
	 * Check for keys on the top row
	 */
	bProcessed=TRUE;
	cASCIIFnCode='\0';

	switch (ucScan)
	{
		case KEY_ESC:
		{
			EnqueueKbdChar(minor, ASCII_ESC);
			break;
		}

		case KEY_F1:
		{
			cASCIIFnCode='P';
			break;
		}

		case KEY_F2:
		{
			cASCIIFnCode='Q';
			break;
		}

		case KEY_F3:
		{
			cASCIIFnCode='w';
			break;
		}

		case KEY_F4:
		{
			cASCIIFnCode='x';
			break;
		}

		case KEY_F5:
		{
			cASCIIFnCode='t';
			break;
		}

		case KEY_F6:
		{
			cASCIIFnCode='u';
			break;
		}

		case KEY_F7:
		{
			cASCIIFnCode='q';
			break;
		}

		case KEY_F8:
		{
			cASCIIFnCode='r';
			break;
		}

		case KEY_F9:
		{
			cASCIIFnCode='p';
			break;
		}

		case KEY_F10:
		{
			cASCIIFnCode='M';
			break;
		}

		case KEY_F11:
		{
			cASCIIFnCode='A';
			break;
		}

		case KEY_F12:
		{
			cASCIIFnCode='B';
			break;
		}

		case KEY_SYS_REQUEST:
		{
			EnqueueKbdChar(minor, ASCII_SYSRQ);
			break;
		}

		case KEY_CAPS_LOCK:
		case KEY_NUM_LOCK:
		case KEY_SCROLL_LOCK:
		{
			switch(ucScan)
			{
				case KEY_CAPS_LOCK:
				{
					bCapsLock=!bCapsLock;
					break;
				}

				case KEY_NUM_LOCK:
				{
					bNumLock=!bNumLock;
					break;
				}

				case KEY_SCROLL_LOCK:
				{
#if CONSOLE_USE_INTERRUPTS
					bScrollLock=!bScrollLock;
#endif
					break;
				}
			}

			i8042_outbyte_raw(minor, KBD_CMD_SET_LEDS);
#if CONSOLE_USE_INTERRUPTS==0
			i8042_inbyte_raw(minor, &ucKeyboardAck);
#endif
			i8042_outbyte_raw(minor,
					  (bCapsLock ? KBD_LED_CAPS : 0) |
					  (bNumLock ? KBD_LED_NUM : 0) |
					  (bScrollLock ? KBD_LED_SCROLL : 0));
#if CONSOLE_USE_INTERRUPTS==0
			i8042_inbyte_raw(minor, &ucKeyboardAck);
#endif

			break;
		}

		default:
		{
			/*
			 * Something else needs to process this code
			 */
			bProcessed=FALSE;
			break;
		}
	}

	if(cASCIIFnCode)
	{
		EnqueueKbdChar(minor, ASCII_CSI);
		EnqueueKbdChar(minor, 'O');
		EnqueueKbdChar(minor, cASCIIFnCode);
	}

	return(bProcessed);
}

static boolean i8042_process_keypad(
	int	minor,
	uint8_t   ucScan
)
{
	char cASCIICtrlCode;

	/*
	 * Process keys on the keypad
	 */
	cASCIICtrlCode='\0';

	switch(ucScan)
	{
		case KEY_UP_ARROW:
		{
			cASCIICtrlCode='A';
			break;
		}

		case KEY_DOWN_ARROW:
		{
			cASCIICtrlCode='B';
			break;
		}

		case KEY_RIGHT_ARROW:
		{
			cASCIICtrlCode='C';
			break;
		}

		case KEY_LEFT_ARROW:
		{
			cASCIICtrlCode='D';
			break;
		}

		case KEY_HOME:
		{
			cASCIICtrlCode='H';
			break;
		}

		case KEY_END:
		{
			cASCIICtrlCode='K';
			break;
		}

		case KEY_PAGE_UP:
		{
			cASCIICtrlCode='?';
			break;
		}

		case KEY_PAGE_DOWN:
		{
			cASCIICtrlCode='/';
			break;
		}

		case KEY_INSERT:
		{
			cASCIICtrlCode='@';
			break;
		}

		case KEY_DELETE:
		{
			/*
			 * This is a special case not requiring an ASCII_CSI
			 */
			EnqueueKbdChar(minor, ASCII_DEL);
			return(TRUE);
		}

		default:
		{
			/*
			 * Something else needs to process this code
			 */
			break;
		}
	}

	if(cASCIICtrlCode)
	{
		EnqueueKbdChar(minor, ASCII_CSI);
		EnqueueKbdChar(minor, cASCIICtrlCode);
		return(TRUE);
	}
	else
	{
		return(FALSE);
	}
}

/*
 * This routine translates the keyboard scan code into an
 * ASCII character (or sequence) and queues it
 */
static void i8042_scan_code(
	int minor,
	uint8_t     ucScan
)
{
	char cChar;
	boolean	bMakenBreak;

	/*
	 * Check for code 0xe0, which introduces a two key sequence.
	 */

	if(ucScan==KEY_TWO_KEY)
	{
		bTwoCode=TRUE;
		return;
	}

	/*
	 * Bit 7 of scan code indicates make or break
	 */
	if(ucScan & 0x80)
	{
		bMakenBreak=FALSE;
		ucScan&=0x7f;
	}
	else
	{
		bMakenBreak=TRUE;
	}

	/*
	 * If we are in a multikey sequence then process the second keypress
	 */
	if(bTwoCode)
	{
		i8042_process_two_code(minor, ucScan, bMakenBreak);

		/*
		 * Revert to prcessing single key sequences
		 */
		bTwoCode=FALSE;
		return;
	}

	if(i8042_process_qualifiers(ucScan, bMakenBreak))
	{
		/*
		 * We are all done
		 */
		return;
	}

	/*
	 * The remaining keys are only processed for make
	 */
	if(!bMakenBreak)
	{
		return;
	}

	if(i8042_process_top_row(minor, ucScan))
	{
		/*
		 * We are all done
		 */
		return;
	}

	if(!bNumLock && i8042_process_keypad(minor, ucScan))
	{
		/*
		 * We are all done
		 */
		return;
	}

	/*
	 * Process "normal" keys
	 */

	cChar=0;

	/*
	 * Check to see if the scan code corresponds to an ASCII
	 * character.
	 */
	if(((ucScan >= 16) && (ucScan <= 25)) ||
	   ((ucScan >= 30) && (ucScan <= 38)) ||
	   ((ucScan >= 44) && (ucScan <= 50)))
	{
		if(bCtrlPressed)
		{
			cChar=pcNormalLookup[ucScan - 2]-'a'+1;
		}
		else
		{
			if(((bLShiftPressed || bRShiftPressed) && !bCapsLock) ||
			   (!(bLShiftPressed || bRShiftPressed) && bCapsLock))
			{
				cChar=pcShiftedLookup[ucScan - 2];
			}
			else
			{
				cChar=pcNormalLookup[ucScan - 2];
			}
		}
	}
	else if((ucScan > 1) && (ucScan <= 0x56))
	{
		/*
		 * Its ASCII but not alpha, so don't shift on CapsLock.
		 */
		if(bLShiftPressed || bRShiftPressed)
		{
			cChar=pcShiftedLookup[ucScan - 2];
		}
		else
		{
			cChar=pcNormalLookup[ucScan - 2];
		}
	}

	/* 
	 * If we got a character then queue it
	 */
	if(cChar)
	{
		EnqueueKbdChar(minor, cChar);
	}
}

/*
 *  Console Device Driver Entry Points
 */
boolean i8042_probe(int minor)
{
	uint8_t   ucKeyboardAck;
	uint8_t   ucKeyboardID1, ucKeyboardID2;

	if(!vga_probe(minor))
	{
		/*
		 * There is no VGA adaptor so fail probe
		 */
		return(FALSE);
	}

	Ring_buffer_Initialize(&KbdInputBuffer);
#if CONSOLE_USE_INTERRUPTS
	Ring_buffer_Initialize(&KbdOutputBuffer);
#endif

	i8042_polled_on(minor);
	/*
	 * Determine keyboard type
	 */
	i8042_outbyte_raw(minor, KBD_CMD_READ_ID);
	ucKeyboardAck=0;
	if((i8042_inbyte_raw(minor, &ucKeyboardAck)==RTEMS_TIMEOUT) ||
	   (ucKeyboardAck==KBD_CMD_RESEND))
	{
		/*
		 * No or incorrect keyboard response so fail probe
		 */
		return(FALSE);
	}

	i8042_inbyte_raw(minor, &ucKeyboardID1);
	i8042_inbyte_raw(minor, &ucKeyboardID2);
	if((ucKeyboardID1==0xab) && (ucKeyboardID2==0x41))
	{
		pcNormalLookup=&pcUKNormalLookup[0];
		pcShiftedLookup=&pcUKShiftedLookup[0];
	}
	else
	{
		pcNormalLookup=&pcUSNormalLookup[0];
		pcShiftedLookup=&pcUSShiftedLookup[0];
	}
	i8042_polled_off(minor);

	return(TRUE);
}

void i8042_init(int minor)
{
	uint8_t   ucKeyboardAck;

	vga_init(minor);

	i8042_polled_on(minor);
	/*
	 * Switch all LEDs off
	 */
	i8042_outbyte_raw(minor, KBD_CMD_SET_LEDS);
	i8042_inbyte_raw(minor, &ucKeyboardAck);
	i8042_outbyte_raw(minor, 0);
	i8042_inbyte_raw(minor, &ucKeyboardAck);
	/*
	 * Select scan code set 1
	 */
	i8042_outbyte_raw(minor, KBD_CMD_SEL_SCAN_CODE);
	i8042_inbyte_raw(minor, &ucKeyboardAck);
	i8042_outbyte_raw(minor, 1);
	i8042_inbyte_raw(minor, &ucKeyboardAck);
	i8042_polled_off(minor);
}

/* PAGE
 *
 *  i8042_inbyte_nonblocking_polled 
 *
 *  Console Termios polling input entry point.
 */

int i8042_inbyte_nonblocking_polled( 
	int minor 
)
{
	uint8_t  	ucScan;
	char	ucData;

	if(i8042_inbyte_polled(minor, &ucScan)==RTEMS_SUCCESSFUL)
	{
		i8042_scan_code(minor, ucScan);
	}

	if(!Ring_buffer_Is_empty(&KbdInputBuffer))
	{
		Ring_buffer_Remove_character(&KbdInputBuffer,
					     ucData);
		return(ucData);
	}

	return(-1);
}

#if CONSOLE_USE_INTERRUPTS
/*
 *  i8042_isr
 *
 *  This routine is the console interrupt handler for the keyboard
 *
 *  Input parameters:
 *    vector - vector number
 *
 *  Output parameters: NONE
 *
 *  Return values:     NONE
 */
static void i8042_process(
	int	minor
)
{
	uint8_t  	Status;
	uint8_t  	ucData;

	inport_byte(Console_Port_Tbl[minor].ulCtrlPort1, Status);

	if(Status & KBD_OBF_MASK)
	{
		inport_byte(Console_Port_Tbl[minor].ulDataPort, ucData);

		if(bProcessInterruptInput)
		{
			/*
			 * Every byte written to the keyboard should be followed
			 * by an acknowledge
			 */
			if(ucData==KBD_CMD_ACK)
			{
				bReceivedAck=TRUE;
			}
			else
			{
				i8042_scan_code(minor, ucData);
			}
		}
		else
		{
			/*
			 * Store the scan code into the ring buffer where it
			 * can be read using i8042_inbyte_raw()
			 */
			Ring_buffer_Add_character(&KbdInputBuffer, ucData);
		}
	}

	if(((Status & KBD_IBF_MASK)==0) &&
	   bReceivedAck)
	{
		if(Ring_buffer_Is_empty(&KbdOutputBuffer))
		{
			Console_Port_Data[minor].bActive=FALSE;
		}
		else
		{
			Ring_buffer_Remove_character(&KbdOutputBuffer,
						     ucData);
			outport_byte(Console_Port_Tbl[minor].ulDataPort,
				     ucData);
			bReceivedAck=FALSE;
		}
	}
}

static rtems_isr i8042_isr(
  rtems_vector_number vector
)
{
        int     minor;

        for(minor=0;minor<Console_Port_Count;minor++)
        {
                if(vector==Console_Port_Tbl[minor].ulIntVector)
                {
                        i8042_process(minor);
                }
        }
}

void i8042_initialize_interrupts(int minor)
{
	i8042_init(minor);

	Console_Port_Data[minor].bActive=FALSE;

	set_vector(i8042_isr,
		   Console_Port_Tbl[minor].ulIntVector,
		   1);

	i8042_outbyte_cmd_polled(minor, KBD_CTR_WRITE_COMMAND);
	i8042_outbyte_raw(minor, KBD_CMD_ENABLE_KBD_INT);

	/*
	 * At this point interrupts should spring into life
	 */
	bInterruptsEnabled=TRUE;
}

#endif /* CONSOLE_USE_INTERRUPTS */