keyboard.c revision c58f1213e628a545081c70e26c6b67a841cff880
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
* --------------------------------------------------------------------
*
* This code is based on:
*
*
* Copyright (C) 2002 MandrakeSoft S.A.
*
* MandrakeSoft S.A.
* 43, rue d'Aboukir
* 75002 Paris - France
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
#include "inlines.h"
#include "biosint.h"
#if DEBUG_INT16
#else
# define BX_DEBUG_INT16(...)
#endif
extern void post(void);
void jmp_post(void);
#define none 0
#define MAX_SCAN_CODE 0x58
struct {
{ 0x1071, 0x1051, 0x1011, 0x1000, 0x40 }, /* Q */
{ 0x1177, 0x1157, 0x1117, 0x1100, 0x40 }, /* W */
{ 0x1265, 0x1245, 0x1205, 0x1200, 0x40 }, /* E */
{ 0x1372, 0x1352, 0x1312, 0x1300, 0x40 }, /* R */
{ 0x1474, 0x1454, 0x1414, 0x1400, 0x40 }, /* T */
{ 0x1579, 0x1559, 0x1519, 0x1500, 0x40 }, /* Y */
{ 0x1675, 0x1655, 0x1615, 0x1600, 0x40 }, /* U */
{ 0x1769, 0x1749, 0x1709, 0x1700, 0x40 }, /* I */
{ 0x186f, 0x184f, 0x180f, 0x1800, 0x40 }, /* O */
{ 0x1970, 0x1950, 0x1910, 0x1900, 0x40 }, /* P */
{ 0x1e61, 0x1e41, 0x1e01, 0x1e00, 0x40 }, /* A */
{ 0x1f73, 0x1f53, 0x1f13, 0x1f00, 0x40 }, /* S */
{ 0x2064, 0x2044, 0x2004, 0x2000, 0x40 }, /* D */
{ 0x2166, 0x2146, 0x2106, 0x2100, 0x40 }, /* F */
{ 0x2267, 0x2247, 0x2207, 0x2200, 0x40 }, /* G */
{ 0x2368, 0x2348, 0x2308, 0x2300, 0x40 }, /* H */
{ 0x246a, 0x244a, 0x240a, 0x2400, 0x40 }, /* J */
{ 0x256b, 0x254b, 0x250b, 0x2500, 0x40 }, /* K */
{ 0x266c, 0x264c, 0x260c, 0x2600, 0x40 }, /* L */
{ 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, 0x40 }, /* Z */
{ 0x2d78, 0x2d58, 0x2d18, 0x2d00, 0x40 }, /* X */
{ 0x2e63, 0x2e43, 0x2e03, 0x2e00, 0x40 }, /* C */
{ 0x2f76, 0x2f56, 0x2f16, 0x2f00, 0x40 }, /* V */
{ 0x3062, 0x3042, 0x3002, 0x3000, 0x40 }, /* B */
{ 0x316e, 0x314e, 0x310e, 0x3100, 0x40 }, /* N */
{ 0x326d, 0x324d, 0x320d, 0x3200, 0x40 }, /* M */
};
/* Keyboard initialization. */
//--------------------------------------------------------------------------
// keyboard_panic
//--------------------------------------------------------------------------
{
// If you're getting a 993 keyboard panic here,
// please see the comment in keyboard_init
}
//--------------------------------------------------------------------------
// keyboard_init
//--------------------------------------------------------------------------
// this file is based on LinuxBIOS implementation of keyboard.c
// could convert to #asm to gain space
void BIOSCALL keyboard_init(void)
{
/* ------------------- controller side ----------------------*/
/* send cmd = 0xAA, self test 8042 */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* read self-test result, 0x55 should be returned from 0x60 */
keyboard_panic(991);
}
/* send cmd = 0xAB, keyboard interface test */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* read keyboard interface test result, */
/* 0x00 should be returned form 0x60 */
keyboard_panic(992);
}
/* ------------------- keyboard side ------------------------*/
/* reset keyboard and self test (keyboard side) */
/* also enables the keyboard interface */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* keyboard should return ACK */
keyboard_panic(993);
}
/* Wait for data */
max=0xffff;
keyboard_panic(994);
}
/* Disable keyboard */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* keyboard should return ACK */
keyboard_panic(995);
}
/* Write Keyboard Mode */
/* Wait until buffer is empty */
max=0xffff;
/* send cmd: scan code convert, disable mouse, enable IRQ 1 */
/* Wait until buffer is empty */
max=0xffff;
/* Enable keyboard */
/* Wait until buffer is empty */
max=0xffff;
/* Wait for data */
max=0xffff;
/* keyboard should return ACK */
keyboard_panic(996);
}
/* Enable aux interface */
/* While we're here, disable the A20 gate. Required for
* compatibility with the IBM PC and DOS.
*/
set_enable_a20(0);
}
{
#if BX_CPU < 2
buffer_start = 0x001E;
buffer_end = 0x003E;
#else
#endif
buffer_tail += 2;
if (buffer_tail >= buffer_end)
if (buffer_tail == buffer_head)
return(0);
return(1);
}
/* Keyboard hardware interrupt handler. */
//@todo: should this be declared as taking arguments at all?
{
//
// DS has been set to F000 before call
//
if (scancode == 0) {
BX_INFO("KBD: int09 handler: AL=0\n");
return;
}
asciicode = 0;
switch (scancode) {
case 0x3a: /* Caps Lock press */
shift_flags ^= 0x40;
mf2_flags |= 0x40;
break;
case 0xba: /* Caps Lock release */
mf2_flags &= ~0x40;
break;
case 0x2a: /* L Shift press */
case 0xaa: /* L Shift release */
case 0x36: /* R Shift press */
case 0xb6: /* R Shift release */
/* If this was an extended (i.e. faked) key, leave flags alone. */
if (!(mf2_state & 0x02)) {
if (scancode & 0x80)
shift_flags &= ~flag;
else
shift_flags |= flag;
}
break;
case 0x1d: /* Ctrl press */
if ((mf2_state & 0x01) == 0) {
shift_flags |= 0x04;
if (mf2_state & 0x02) {
mf2_state |= 0x04;
} else {
mf2_flags |= 0x01;
}
}
break;
case 0x9d: /* Ctrl release */
if ((mf2_state & 0x01) == 0) {
shift_flags &= ~0x04;
if (mf2_state & 0x02) {
mf2_state &= ~0x04;
} else {
mf2_flags &= ~0x01;
}
}
break;
case 0x38: /* Alt press */
shift_flags |= 0x08;
if (mf2_state & 0x02) {
mf2_state |= 0x08;
} else {
mf2_flags |= 0x02;
}
break;
case 0xb8: /* Alt release */
shift_flags &= ~0x08;
if (mf2_state & 0x02) {
mf2_state &= ~0x08;
} else {
mf2_flags &= ~0x02;
}
break;
case 0x45: /* Num Lock press */
if ((mf2_state & 0x03) == 0) {
mf2_flags |= 0x20;
shift_flags ^= 0x20;
}
break;
case 0xc5: /* Num Lock release */
if ((mf2_state & 0x03) == 0) {
mf2_flags &= ~0x20;
}
break;
case 0x46: /* Scroll Lock press */
mf2_flags |= 0x10;
shift_flags ^= 0x10;
break;
case 0xc6: /* Scroll Lock release */
mf2_flags &= ~0x10;
break;
case 0x53: /* Del press */
jmp_post();
/* fall through */
default:
if (scancode & 0x80) {
break; /* toss key releases ... */
}
if (scancode > MAX_SCAN_CODE) {
return;
}
/* extended keys handling */
asciicode = 0xe0;
/* check if lock state should be ignored
* because a SHIFT key are pressed */
} else {
}
} else {
/* check if lock is on */
} else {
}
}
BX_INFO("KBD: int09h_handler(): scancode & asciicode are zero?\n");
}
break;
}
mf2_state &= ~0x01;
}
mf2_state &= ~0x02;
}
{
#if BX_CPU < 2
buffer_start = 0x001E;
buffer_end = 0x003E;
#else
#endif
if (buffer_head != buffer_tail) {
*ascii_code = acode;
if (incr) {
buffer_head += 2;
if (buffer_head >= buffer_end)
}
return(1);
}
else {
return(0);
}
}
//@todo: move somewhere else?
/* Interrupt 16h service implementation. */
{
int_disable(); //@todo: interrupts should be disabled already??
led_flags &= 0xf8;
inb(0x60);
}
int_enable();
}
switch (GET_AH()) {
case 0x00: /* read keyboard input */
BX_PANIC("KBD: int16h: out of keyboard input\n");
}
ascii_code = 0;
else if (ascii_code == 0xE0)
ascii_code = 0;
break;
case 0x01: /* check keyboard status */
SET_IF(); /* Enable interrupts. Some callers depend on that! */
SET_ZF();
return;
}
ascii_code = 0;
else if (ascii_code == 0xE0)
ascii_code = 0;
CLEAR_ZF();
break;
case 0x02: /* get shift flag status */
break;
case 0x05: /* store key-stroke into buffer */
SET_AL(1);
}
else {
SET_AL(0);
}
break;
case 0x09: /* GET KEYBOARD FUNCTIONALITY */
// bit Bochs Description
// 7 0 reserved
// 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
// 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
// 4 1 INT 16/AH=0Ah supported
// 3 0 INT 16/AX=0306h supported
// 2 0 INT 16/AX=0305h supported
// 1 0 INT 16/AX=0304h supported
// 0 0 INT 16/AX=0300h supported
//
SET_AL(0x30);
break;
case 0x0A: /* GET KEYBOARD ID */
count = 2;
kbd_code = 0x0;
//@todo: Might be better to just mask the KB interrupt
int_disable();
/* Wait for data */
max=0xffff;
inb(0x80);
if (max>0x0) {
do {
max=0xffff;
inb(0x80);
if (max>0x0) {
kbd_code >>= 8;
}
} while (--count>0);
}
}
break;
case 0x10: /* read MF-II keyboard input */
BX_PANIC("KBD: int16h: out of keyboard input\n");
}
ascii_code = 0;
break;
case 0x11: /* check MF-II keyboard status */
SET_IF();
SET_ZF();
return;
}
ascii_code = 0;
CLEAR_ZF();
break;
case 0x12: /* get extended keyboard status */
break;
case 0x92: /* keyboard capability check called by DOS 5.0+ keyb */
break;
case 0xA2: /* 122 keys capability check called by DOS 5.0+ keyb */
// don't change AH : function int16 ah=0x20-0x22 NOT supported
break;
//@todo: what's the point of handling this??
#if 0
case 0x6F:
if (GET_AL() == 0x08)
#endif
default:
}
}