/* * inch.c -- keyboard minimal driver * * Copyright (C) 1999 Eric Valette. valette@crf.canon.fr * * This code is based on the pc386 BSP inch.c so the following * copyright also applies : * * (C) Copyright 1997 - * - NavIST Group - Real-Time Distributed Systems and Industrial Automation * * http://pandora.ist.utl.pt * * Instituto Superior Tecnico * Lisboa * PORTUGAL * The license and distribution terms for this file may be * found in found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Id$ */ #include #ifdef BSP_KBD_IOBASE #include #include "console.inl" /*-------------------------------------------------------------------------+ | Constants +--------------------------------------------------------------------------*/ #define KBD_CTL 0x1 /* -------------------------------- */ #define KBD_DATA 0x0 /* Port offsets for PC keyboard controller */ #define KBD_STATUS 0x4 /* -------------------------------- */ #define KBD_BUF_SIZE 256 /*-------------------------------------------------------------------------+ | Global Variables +--------------------------------------------------------------------------*/ static char key_map[] = { 0,033,'1','2','3','4','5','6','7','8','9','0','-','=','\b','\t', 'q','w','e','r','t','y','u','i','o','p','[',']',015,0x80, 'a','s','d','f','g','h','j','k','l',';',047,0140,0x80, 0134,'z','x','c','v','b','n','m',',','.','/',0x80, '*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,'0',0177 }; /* Keyboard scancode -> character map with no modifiers. */ static char shift_map[] = { 0,033,'!','@','#','$','%','^','&','*','(',')','_','+','\b','\t', 'Q','W','E','R','T','Y','U','I','O','P','{','}',015,0x80, 'A','S','D','F','G','H','J','K','L',':',042,'~',0x80, '|','Z','X','C','V','B','N','M','<','>','?',0x80, '*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, 0x80,0x80,0x80,0x80,'7','8','9',0x80,'4','5','6',0x80, '1','2','3','0',177 }; /* Keyboard scancode -> character map with SHIFT key modifier. */ static char kbd_buffer[KBD_BUF_SIZE]; static uint16_t kbd_first = 0; static uint16_t kbd_last = 0; static uint16_t kbd_end = KBD_BUF_SIZE - 1; /*-------------------------------------------------------------------------+ | Function: _IBMPC_scankey | Description: This function can be called during a poll for input, or by | an ISR. Basically any time you want to process a keypress. | Global Variables: key_map, shift_map. | Arguments: outChar - character read in case of a valid reading, | otherwise unchanged. | Returns: TRUE in case a valid character has been read, | FALSE otherwise. +--------------------------------------------------------------------------*/ rtems_boolean _IBMPC_scankey(char *outChar) { unsigned char inChar; static int alt_pressed = 0; static int ctrl_pressed = 0; static int shift_pressed = 0; static int caps_pressed = 0; static int extended = 0; *outChar = 0; /* default value if we return FALSE */ /* Read keyboard controller, toggle enable */ inChar=kbd_inb(KBD_CTL); kbd_outb(KBD_CTL, inChar & ~0x80); kbd_outb(KBD_CTL, inChar | 0x80); kbd_outb(KBD_CTL, inChar & ~0x80); /* See if it has data */ inChar=kbd_inb(KBD_STATUS); if ((inChar & 0x01) == 0) return FALSE; /* Read the data. Handle nonsense with shift, control, etc. */ inChar=kbd_inb(KBD_DATA); if (extended) extended--; switch (inChar) { case 0xe0: extended = 2; return FALSE; break; case 0x38: alt_pressed = 1; return FALSE; break; case 0xb8: alt_pressed = 0; return FALSE; break; case 0x1d: ctrl_pressed = 1; return FALSE; break; case 0x9d: ctrl_pressed = 0; return FALSE; break; case 0x2a: if (extended) return FALSE; case 0x36: shift_pressed = 1; return FALSE; break; case 0xaa: if (extended) return FALSE; case 0xb6: shift_pressed = 0; return FALSE; break; case 0x3a: caps_pressed = 1; return FALSE; break; case 0xba: caps_pressed = 0; return FALSE; break; case 0x53: if (ctrl_pressed && alt_pressed) rtemsReboot(); /* ctrl+alt+del -> reboot */ break; /* * Ignore unrecognized keys--usually arrow and such */ default: if ((inChar & 0x80) || (inChar > 0x39)) /* High-bit on means key is being released, not pressed */ return FALSE; break; } /* switch */ /* Strip high bit, look up in our map */ inChar &= 0x7f; if (ctrl_pressed) { *outChar = key_map[inChar]; *outChar &= 037; } else { *outChar = shift_pressed ? shift_map[inChar] : key_map[inChar]; if (caps_pressed) { if (*outChar >= 'A' && *outChar <= 'Z') *outChar += 'a' - 'A'; else if (*outChar >= 'a' && *outChar <= 'z') *outChar -= 'a' - 'A'; } } return TRUE; } /* _IBMPC_scankey */ /*-------------------------------------------------------------------------+ | Function: _IBMPC_keyboard_isr | Description: Interrupt Service Routine for keyboard (0x01) IRQ. | Global Variables: kbd_buffer, kbd_first, kbd_last. | Arguments: vector - standard RTEMS argument - see documentation. | Returns: standard return value - see documentation. +--------------------------------------------------------------------------*/ void _IBMPC_keyboard_isr() { if (_IBMPC_scankey(&kbd_buffer[kbd_last])) { /* Got one; save it if there is enough room in buffer. */ unsigned int next = (kbd_last == kbd_end) ? 0 : kbd_last + 1; if (next != kbd_first) { kbd_last = next; } } } /* _IBMPC_keyboard_isr */ /*-------------------------------------------------------------------------+ | Function: _IBMPC_chrdy | Description: Check keyboard ISR buffer and return character if not empty. | Global Variables: kbd_buffer, kbd_first, kbd_last. | Arguments: c - character read if keyboard buffer not empty, otherwise | unchanged. | Returns: TRUE if keyboard buffer not empty, FALSE otherwise. +--------------------------------------------------------------------------*/ rtems_boolean _IBMPC_chrdy(char *c) { /* Check buffer our ISR builds */ if (kbd_first != kbd_last) { *c = kbd_buffer[kbd_first]; kbd_first = (kbd_first + 1) % KBD_BUF_SIZE; return TRUE; } else return FALSE; } /* _IBMPC_chrdy */ /*-------------------------------------------------------------------------+ | Function: _IBMPC_inch | Description: Poll keyboard until a character is ready and return it. | Global Variables: None. | Arguments: None. | Returns: character read from keyboard. +--------------------------------------------------------------------------*/ char _IBMPC_inch(void) { char c; while (!_IBMPC_chrdy(&c)) continue; return c; } /* _IBMPC_inch */ /* * Routine that can be used before interrupt management is initialized. */ char BSP_wait_polled_input(void) { char c; while (!_IBMPC_scankey(&c)) continue; return c; } /*-------------------------------------------------------------------------+ | Function: _IBMPC_inch_sleep | Description: If charcter is ready return it, otherwise sleep until | it is ready | Global Variables: None. | Arguments: None. | Returns: character read from keyboard. +--------------------------------------------------------------------------*/ char _IBMPC_inch_sleep(void) { char c; rtems_interval ticks_per_second; ticks_per_second = 0; for(;;) { if(_IBMPC_chrdy(&c)) { return c; } if(ticks_per_second == 0) { rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); } rtems_task_wake_after((ticks_per_second+24)/25); } return c; } /* _IBMPC_inch */ #endif