/**
* keyboard.c
*
* Main keyboard handling routines.
*
* Exports:
* keyboard_irq();
* init_keyboard();
*
* Imports:
* video.c console_t _vc[];
* video.c select_vc();
* video.c putch();
* main.c printf();
* main.c printk();
*/
//#include <conio.h> /* key scancode definitions */
#include <keyboard.h>
#include <x86.h> /* outportb, inportb(), etc */
#include <string.h>
#include <esh/esh.h> /* shell commands */
#include "_krnl.h" /* MAX_VC */
#include "bootlog.h" /* klog() */
#define KBD_BUF_SIZE 64
/**
* Imports
*/
extern console_t _vc[];
void select_vc(unsigned which_vc);
void putch(unsigned c);
void printf(const char *fmt, ...);
void printk(int type, const char *fmt, ...);
void dumpheapk(void);
void testheap(void);
unsigned get_current_vc();
static int rawkey, keys[128];
static int numkeysbuffer;
static char szInBuf[KBD_BUF_SIZE];
/**
* 0 if not set
* 1 if make code
* 2 if break code
*/
static int makebreak;
/**
* reboot()
*
*/
static void reboot(void)
{
unsigned temp;
disable();
/**
* flush the keyboard controller
*/
do
{
temp = inportb(0x64);
if((temp & 0x01) != 0)
{
(void)inportb(0x60);
continue;
}
} while((temp & 0x02) != 0);
/**
* now pulse the cpu reset line
*/
outportb(0x64, 0xFE);
/**
* if that didn't work, just halt
*/
while(1);
}
/**
* XXX
*
* I'm not even sure if we need the following functions yet,
* however they are here just in case. Leave them alone.
*/
/**
* _write_kb()
*
*/
static void _write_kb(unsigned adr, unsigned d)
{
unsigned long t;
unsigned s;
for(t = 5000000L; t != 0; t--)
{
s = inportb(0x64);
/**
* loop until 8042 input buffer is empty
*/
if((s & 0x02) == 0)
break;
}
if(t != 0)
outportb(adr, d);
}
/**
* _kb_wait()
*
*/
static inline void _kb_wait(void)
{
int i;
for(i = 0; i < 0x1000000; i++)
if((inportb(0x64) & 0x02) == 0)
return;
printk(0, "Keyboard timeout\n");
}
/**
* _kb_send()
*
*/
static inline void _kb_send(unsigned char c)
{
_kb_wait();
outportb(c, 0x64);
}
/**
* _translate_sc()
*
* Translates a scancode from the keyboard
*/
unsigned _translate_sc(unsigned k)
{
unsigned c;
static unsigned altk;
unsigned donefirst = 0;
if(k == KEY_BKSPACE)
{
if(numkeysbuffer - 1 < 0)
{
numkeysbuffer = 0;
return 0;
}
}
switch(k)
{
case 0xE0:
altk = 1; c = 0; donefirst = 1; break;
case KEY_TILDA: /* ` or ~ */
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 126 : 126; break;
case KEY_END: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 49; break;
case KEY_1:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 33 : 49; break;
case KEY_DOWN: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 50; break;
case KEY_2:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 64 : 50; break;
case KEY_PGDOWN: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 51; break;
case KEY_3:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 35 : 51; break;
case KEY_LEFT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 52; break;
case KEY_4:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 36 : 52; break;
case KEYP_5: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 53; break;
case KEY_5:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 35 : 53; break;
case KEY_RIGHT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 54; break;
case KEY_6:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 94 : 54; break;
case KEY_HOME: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 55; break;
case KEY_7:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 38 : 55; break;
case KEY_UP: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 56; break;
case KEYP_ASTERISK: c = 42; break;
case KEY_8:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 42 : 56; break;
case KEY_PGUP: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 57; break;
case KEY_9:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 40 : 57; break;
case KEY_INSERT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 48; break;
case KEY_0:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 41 : 48; break;
case KEYP_MINUS: c = 45; break;
case KEY_MINUS:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 95 : 45; break;
case KEYP_PLUS: c = 43; break;
case KEY_PLUS:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 61 : 43; break;
case KEY_BKSLASH:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 124 : 92; break;
case KEY_Q:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 81 : 113; break;
case KEY_W:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 87 : 119; break;
case KEY_E:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 69 : 101; break;
case KEY_R:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 82 : 114; break;
case KEY_T:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 84 : 116; break;
case KEY_Y:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 89 : 121; break;
case KEY_U:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 85 : 117; break;
case KEY_I:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 73 : 105; break;
case KEY_O:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 79 : 111; break;
case KEY_P:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 80 : 112; break;
case KEY_LBRACKET:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 123 : 91; break;
case KEY_RBRACKET:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 125 : 93; break;
case KEY_ENTER:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 10 : 10; break;
case KEY_A:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 65 : 97; break;
case KEY_S:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 83 : 115; break;
case KEY_D:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 68 : 100; break;
case KEY_F:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 70 : 102; break;
case KEY_G:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 71 : 103; break;
case KEY_H:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 72 : 104; break;
case KEY_J:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 74 : 106; break;
case KEY_K:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 75 : 107; break;
case KEY_L:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 76 : 108; break;
case KEY_SEMICOLON:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 58 : 59; break;
case KEY_QUOTE:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 34 : 39; break;
case KEY_Z:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 90 : 122; break;
case KEY_X:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 88 : 120; break;
case KEY_C:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 67 : 99; break;
case KEY_V:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 86 : 118; break;
case KEY_B:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 66 : 98; break;
case KEY_N:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 78 : 110; break;
case KEY_M:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 77 : 109; break;
case KEY_COMMA:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 60 : 44; break;
case KEY_DEL: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 46; break;
case KEY_PERIOD:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 62 : 46; break;
case KEY_SLASH:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 63 : 47; break;
case KEY_SPACE:
c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 32 : 32; break;
case KEY_BKSPACE: c = '\b'; break; /* just for now */
default:
c = 0;
}
if(donefirst == 0)
altk = 0;
if(keys[KEY_CAPS])
{
if(keys[KEY_LSHIFT] || keys[KEY_RSHIFT])
{
if(c >= 'A' && c <= 'Z')
c += 32;
}
else
{
if(c >= 'a' && c <= 'z')
c -= 32;
}
}
/**
* Simple shell for now
*/
if(c != 0 && c != '\n' && c != '\b')
{
if((numkeysbuffer - 1) == KBD_BUF_SIZE)
{
numkeysbuffer = 0;
szInBuf[0] = '\0';
szInBuf[numkeysbuffer] = c;
numkeysbuffer++;
}
else
{
szInBuf[numkeysbuffer] = c;
numkeysbuffer++;
}
}
else if(c == '\n')
{
printf("\n");
/**
* Make it a real string
*/
szInBuf[numkeysbuffer] = '\0';
/**
* Process command
*/
processCommand(&szInBuf[0], numkeysbuffer - 1);
/**
* Clear buffer
*/
numkeysbuffer = 0;
szInBuf[0] = '\0';
/**
* Print "line"
*/
printf("$ ");
c = 0;
}
else if(c == '\b')
{
szInBuf[numkeysbuffer] = '\0';
numkeysbuffer--;
printf("\b \b");
c = 0;
}
return c;
}
/**
* handle_meta_key()
*
* I'll pretty this up later
*/
void handle_meta_key(unsigned k)
{
int i;
k = k; /* to shut gcc up */
/**
* Check for the infamous three finger salute
*/
if((keys[KEY_RCTRL] || keys[KEY_LCTRL]) &&
(keys[KEY_RALT] || keys[KEY_LALT]) &&
keys[KEY_DEL])
{
/**
* FIXME
*
* This should call _send_signal()
*/
reboot();
}
/**
* Check for Alt + F1-F12 for virtual terminals
*/
for(i = 0; i < 10; i++)
{
if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[i + KEY_F1])
{
select_vc(i);
return;
}
}
if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[KEY_F11])
{
select_vc(10);
return;
}
if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[KEY_F12])
{
select_vc(11);
return;
}
}
/**
* keyboard_irq()
*
* Called when a keyboard interrupt is generated.
*/
void keyboard_irq(void)
{
register char a;
unsigned c;
unsigned short kbdstat;
rawkey = inportb(0x60);
outportb(0x61, (a=inportb(0x61)|0x82));
outportb(0x61, a & 0x7F);
/**
* If it's less than 0x80 then it's definatelly
* a make code or a repeat code
*/
if(rawkey < 0x80)
{
/**
* We don't want to gunk up the numlock key
* because we will define it's state in the
* break code a bit later
*/
if((rawkey != KEYP_NUMLCK) && (rawkey != KEY_SCRLCK) && (rawkey != KEY_CAPS))
keys[rawkey] = 1;
keyDown(rawkey);
}
else /* rawkey >= 0x80 */
{
if(rawkey == 0xE0)
{
/**
* It's either a make code, break code, or repeat code
*/
rawkey = inportb(0x60);
outportb(0x61, (a=inportb(0x61)|0x82));
outportb(0x61, a & 0x7F);
if(rawkey < 0x80)
{
/**
* Ok, it's a make code or repeat code for the numeric
* keypad (gray keys)
*/
keys[rawkey] = 1;
keyDown(rawkey);
}
else /* rawkey >= 0x80 */
{
/**
* It's either a make code for the numeric keypad or
* a break code for the numeric keypad.
*/
if(rawkey == 0x2A)
{
/**
* Ok, we have a make code for the numeric keypad
* and NUMLOCK is on. The second byte is what we
* want since what we have so far is this:
*
* 0xE0 0x2A
*/
rawkey = inportb(0x60);
outportb(0x61, (a=inportb(0x61)|0x82));
outportb(0x61, a & 0x7F);
rawkey = inportb(0x60);
outportb(0x61, (a=inportb(0x61)|0x82));
outportb(0x61, a & 0x7F);
keys[rawkey] = 1;
keyDown(rawkey);
}
else
{
/**
* It's a break code from the numeric keypad.
*/
keys[rawkey] = 0;
keyUp(rawkey);
}
}
}
else /* rawkey != 0xE0 */
{
/**
* It's a break code
*
* Make sure we toggle the numlock, scroll lock, and caps lock key.
*/
if(((rawkey - 0x80) == KEYP_NUMLCK) ||
((rawkey - 0x80) == KEY_SCRLCK) ||
((rawkey - 0x80) == KEY_CAPS))
{
keys[rawkey - 0x80] = !keys[rawkey - 0x80];
kbdstat = 0;
if(keys[KEY_SCRLCK])
kbdstat |= 1;
if(keys[KEYP_NUMLCK])
kbdstat |= 2;
if(keys[KEY_CAPS])
kbdstat |= 4;
_write_kb(0x60, 0xED);
_write_kb(0x60, kbdstat);
outportb(0x20, 0x20);
keyUp(rawkey);
return;
}
keys[rawkey - 0x80] = 0;
keyUp(rawkey);
}
}
c = _translate_sc(rawkey);
if(c != 0)
printf("%c", c);
else
{
/**
* We need to check for meta-key-crap here
*/
handle_meta_key(rawkey);
}
//enable();
outportb(0x20, 0x20);
}
/**
* init_keyboard()
*
*/
void init_keyboard(void)
{
static unsigned char buffers[KBD_BUF_SIZE * MAX_VC];
int i;
//klog("init", "keyboard %2u buf, %2ub each", K_KLOG_PENDING, &_vc[0]);
for(i = 0; i < MAX_VC; i++)
{
_vc[i].keystrokes.data = buffers + KBD_BUF_SIZE * i;
_vc[i].keystrokes.size = KBD_BUF_SIZE;
}
for(i = 0; i < 128; i++)
keys[i] = 0;
makebreak = 0;
//klog(NULL, K_KLOG_SUCCESS, &_vc[0], NULL);
//kprintf("init_kbd: %u buffers, %u bytes each\n",
// MAX_VC, KBD_BUF_SIZE);
//kprintf("[ Entering Runlevel 0 ].......................................................Ok");
_vc[0].attrib = 8;
printf("[ ");
_vc[0].attrib = 15;
printf("init: keyboard %2u buf, %2ub each ", MAX_VC, KBD_BUF_SIZE);
_vc[0].attrib = 8;
printf("]...........................................");
_vc[0].attrib = 2;
printf("Ok");
_vc[0].attrib = 7;
}