/* Minimal polling PC keyboard driver
* - No interrupt
* - No LED
* - No special keys
*
* still Enough For Me to type a filename.
*
* 2003-07 by SONE Takesh
* 2004-04 moved by LYH From filo to Etherboot
* yhlu@tyan.com
*/
#include <gpxe/io.h>
#include "console.h"
static char key_map[][128] = {
{
"\0\x1b""1234567890-=\b\t"
"qwertyuiop[]\r\0as"
"dfghjkl;'`\0\\zxcv"
"bnm,./\0*\0 \0\0\0\0\0\0"
"\0\0\0\0\0\0\0""789-456+1"
"230."
},{
"\0\x1b""!@#$%^&*()_+\b\t"
"QWERTYUIOP{}\r\0AS"
"DFGHJKL:\"~\0|ZXCV"
"BNM<>?\0\0\0 \0\0\0\0\0\0"
"\0\0\0\0\0\0\0""789-456+1"
"230."
}
};
static int cur_scan;
static unsigned int shift_state;
#define SHIFT 1
#define CONTROL 2
#define CAPS 4
static int get_scancode(void)
{
int scan;
if ((inb(0x64) & 1) == 0)
return 0;
scan = inb(0x60);
switch (scan) {
case 0x2a:
case 0x36:
shift_state |= SHIFT;
break;
case 0xaa:
case 0xb6:
shift_state &= ~SHIFT;
break;
case 0x1d:
shift_state |= CONTROL;
break;
case 0x9d:
shift_state &= ~CONTROL;
break;
case 0x3a:
shift_state ^= CAPS;
break;
}
if (scan & 0x80)
return 0; /* ignore break code or 0xe0 etc! */
return scan;
}
static int kbd_havekey(void)
{
if (!cur_scan)
cur_scan = get_scancode();
return cur_scan != 0;
}
static int kbd_ischar(void)
{
if (!kbd_havekey())
return 0;
if (!key_map[shift_state & SHIFT][cur_scan]) {
cur_scan = 0;
return 0;
}
return 1;
}
static int kbd_getc(void)
{
int c;
while (!kbd_ischar())
;
c = key_map[shift_state & SHIFT][cur_scan];
if (shift_state & (CONTROL | CAPS)) {
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
if (shift_state & CONTROL)
c &= 0x1f;
else if (shift_state & CAPS)
c ^= ('A' ^ 'a');
}
}
cur_scan = 0;
return c;
}
struct console_driver pc_kbd_console __console_driver = {
.getchar = kbd_getc,
};