--- /dev/null
+/* cs410.c
+ * Entry points for 15-410 extensions
+ * NetWatch system management mode administration console
+ *
+ * Copyright (c) 2008 Jacob Potter and Joshua Wise. All rights reserved.
+ * This program is free software; you can redistribute and/or modify it under
+ * the terms found in the file LICENSE in the root of this source tree.
+ *
+ */
+
+#include <io.h>
+#include <smi.h>
+#include <smram.h>
+#include <video_defines.h>
+#include <output.h>
+#include <minilib.h>
+
+#define CONSCOLOR 0x1F
+
+unsigned char oldcons[80 * 25 * 2];
+
+static unsigned char vga_read(unsigned char idx)
+{
+ outb(CRTC_IDX_REG, idx);
+ return inb(CRTC_DATA_REG);
+}
+
+static char * vga_base()
+{
+ return (char *) (
+ 0xB8000
+ + (((unsigned int) vga_read(CRTC_START_ADDR_MSB_IDX)) << 9)
+ + (((unsigned int) vga_read(CRTC_START_ADDR_LSB_IDX)) << 1)
+ );
+}
+
+static void grey_console()
+{
+ int i;
+ char *p = vga_base();
+
+ for (i = 0; i < 80*25; i++, p+=2)
+ p[1] &= ~0xF8; /* Clear the background and any brightness. */
+}
+
+#define CHAR(x, y) (base[((y)*80+(x))*2])
+#define COLOR(x, y) (base[((y)*80+(x))*2+1])
+
+static void ui_frame(int xp, int yp, int xs, int ys, char *title)
+{
+ int x, y;
+ char *base = vga_base();
+
+ /* Blank and fill the region. */
+ for (y = yp; y <= (yp + ys); y++)
+ for (x = xp; x <= (xp + xs); x++)
+ {
+ CHAR(x, y) = ' ';
+ COLOR(x, y) = CONSCOLOR;
+ }
+
+ /* Draw the top and the bottom (and the bar if need be). */
+ for (x = xp; x <= (xp + xs); x++)
+ {
+ CHAR(x, yp) = 0xCD /* double line horizontal */;
+ CHAR(x, yp+ys) = 0xCD /* double line horizontal */;
+ if (title)
+ CHAR(x, yp+2) = 0xC4 /* single line horizontal */;
+ }
+
+ /* Draw the left and right. */
+ for (y = yp; y <= (yp + ys); y++)
+ {
+ CHAR(xp, y) = 0xBA /* double line vertical */;
+ CHAR(xp+xs, y) = 0xBA /* double line vertical */;
+ }
+
+ /* Drop in the corners. */
+ CHAR(xp, yp) = 0xC9;
+ CHAR(xp+xs, yp) = 0xBB;
+ CHAR(xp, yp+ys) = 0xC8;
+ CHAR(xp+xs, yp+ys) = 0xBC;
+ if (title)
+ {
+ CHAR(xp, yp+2) = 0xC7;
+ CHAR(xp+xs, yp+2) = 0xB6;
+ }
+
+ /* Drop in the text. */
+ if (title)
+ for (x = (xs - strlen(title)) / 2 + xp; *title; x++, title++)
+ CHAR(x, yp+1) = *title;
+}
+
+static void ui_label(int xp, int yp, char *s)
+{
+ int x;
+ char *base = vga_base();
+
+ for (x = xp; *s; x++, s++)
+ CHAR(x, yp) = *s;
+}
+
+typedef enum ui_element_type {
+ UI_FRAME = 0,
+ UI_LABEL = 1,
+ UI_END = -1
+} ui_element_type_t;
+
+typedef union ui_element {
+ ui_element_type_t type;
+ struct {
+ ui_element_type_t type;
+ int xp, yp;
+ int xs, ys;
+ char *title;
+ } frame;
+ struct {
+ ui_element_type_t type;
+ int xp, yp;
+ char *text;
+ } label;
+} ui_element_t;
+
+static ui_element_t mainmenu[] = {
+ { .frame = {
+ .type = UI_FRAME,
+ .xp = 10, .yp = 5,
+ .xs = 60, .ys = 15,
+ .title = "NetWatch main menu" } },
+ { .label = {
+ .type = UI_LABEL,
+ .xp = 12, .yp = 8,
+ .text = "Options:" } },
+ { .label = {
+ .type = UI_LABEL,
+ .xp = 12, .yp = 10,
+ .text = "q - Return to system" } },
+ { .type = UI_END }
+};
+
+static void ui_render(ui_element_t *ui)
+{
+ for (; ui->type != UI_END; ui++)
+ switch (ui->type)
+ {
+ case UI_FRAME:
+ ui_frame(ui->frame.xp, ui->frame.yp,
+ ui->frame.xs, ui->frame.ys,
+ ui->frame.title);
+ break;
+ case UI_LABEL:
+ ui_label(ui->label.xp, ui->label.yp,
+ ui->label.text);
+ break;
+ case UI_END:
+ default:
+ return; /* ??? */
+ }
+}
+
+void cs410_pwrbtn_handler(smi_event_t ev)
+{
+ smram_state_t old_state;
+
+ outputf("410watch: Power button event");
+
+ /* Save off the console. */
+ old_state = smram_save_state();
+ smram_aseg_set_state(SMRAM_ASEG_SMMCODE);
+ memcpy(oldcons, vga_base(), 80*25*2);
+
+ /* Pull a Simics, and grey out the console -- why not? */
+ grey_console();
+
+ /* Show the main menu. */
+ ui_render(mainmenu);
+
+ /* Allow access to data in ASEG. */
+ smram_restore_state(old_state);
+
+ /* Now just sit for a while to show off our newly greyed console. */
+ char c;
+ char *p = vga_base() + (11*80+12)*2;
+ extern int getchar();
+ while ((c = getchar()) != 'q')
+ {
+ smram_aseg_set_state(SMRAM_ASEG_SMMCODE);
+ *p = c;
+ p += 2;
+ smram_restore_state(old_state);
+ }
+
+ /* Put the console back. */
+ smram_aseg_set_state(SMRAM_ASEG_SMMCODE);
+ memcpy(vga_base(), oldcons, 80*25*2);
+ smram_restore_state(old_state);
+
+}
--- /dev/null
+/**
+ * The 15-410 reference kernel keyboard handling code.
+ *
+ * @author Steve Muckle <smuckle@andrew.cmu.edu>
+ *
+ * @author Edited by zra for the 2003-2004 season.
+ *
+ * @author Edited by mpa for spring 2004
+ *
+ * @author Rewritten by nwf for spring 2007.
+ *
+ * Functions for turning keyboard scancodes
+ * into chars.
+ *
+ * Notice that we use Scancode Set 1
+ */
+/*@{*/
+
+#include "keyhelp.h"
+
+/**
+ * This is returned as the upper bits of the result of
+ * process_scancode and may be interrogated more readily by
+ * the KH_ macros in keyhelp.h
+ *
+ * WARNING:
+ * The bottom bits overlap with the KH_RESULT_ codes in the
+ * return value.
+ */
+static short key_state = 0;
+
+ /** Currently processing a PRINT SCREEN BREAK sequence */
+#define KH_PRSCR_UP_SCAN 0x0008
+ /** Currently processing a PRINT SCREEN MAKE sequence */
+#define KH_PRSCR_DOWN_SCAN 0x0004
+ /** Currently processing a PAUSE/BREAK (MAKE) sequence */
+#define KH_PAUSE_SCAN 0x0002
+ /** Currently processing an extended sequence (E0 prefix) */
+#define KH_EXTENDED_SCAN 0x0001
+static short key_internal_state = 0;
+
+static int key_sequence = 0;
+
+#define KHS_SHIFT_CORE (key_state & (KH_LSHIFT_KEY | KH_RSHIFT_KEY))
+#define KHS_CTL_CORE (key_state & (KH_LCONTROL_KEY | KH_RCONTROL_KEY))
+
+#define KHS_SHIFT(c,r,s,u) \
+ { c = KHS_SHIFT_CORE ? s : u; r = u; }
+#define KHS_SHIFTCTL(c,r,cc,s,u) \
+ { c = KHS_CTL_CORE ? cc : (KHS_SHIFT_CORE ? s : u); r = u; }
+#define KHS_SHIFTCAPSCTL(c,r,cc,s,u) \
+ { c = KHS_CTL_CORE ? cc : (((KHS_SHIFT_CORE || (key_state & KH_CAPS_LOCK)) && \
+ !(KHS_SHIFT_CORE && (key_state & KH_CAPS_LOCK))) ? s : u) ; r = u; }
+
+/**
+ * This function performs the mapping
+ * from simple scancodes to chars.
+ *
+ * @param scancode a simple scancode.
+ * @param pressed 0 if released, nonzero if pressed.
+ *
+ * @return A partially constructed kh_type.
+ */
+static kh_type
+process_simple_scan(int scancode, int pressed)
+{
+ unsigned char code = 0x80;
+ unsigned char rcode = 0x80;
+ kh_type res = 0;
+
+ switch(scancode & 0x7F)
+ {
+ case 0x1:
+ /* Escape key. */
+ rcode = code = 0x1B;
+ break;
+ case 0x2:
+ /* 1 or ! */
+ KHS_SHIFT(code, rcode, '!', '1');
+ break;
+ case 0x3:
+ /* 2 or @ */
+ KHS_SHIFTCTL(code, rcode, 0x00, '@', '2');
+ break;
+ case 0x4:
+ /* 3 or # */
+ KHS_SHIFT(code, rcode, '#', '3');
+ break;
+ case 0x5:
+ /* 4 or $ */
+ KHS_SHIFT(code, rcode, '$', '4');
+ break;
+ case 0x6:
+ /* 5 or % */
+ KHS_SHIFT(code, rcode, '%', '5');
+ break;
+ case 0x7:
+ /* 6 or ^ */
+ KHS_SHIFTCTL(code, rcode, 0x1E, '^', '6');
+ break;
+ case 0x8:
+ /* 7 or & */
+ KHS_SHIFT(code, rcode, '&', '7');
+ break;
+ case 0x9:
+ /* 8 or * */
+ KHS_SHIFT(code, rcode, '*', '8');
+ break;
+ case 0xA:
+ /* 9 or ( */
+ KHS_SHIFT(code, rcode, '(', '9');
+ break;
+ case 0xB:
+ /* 0 or ) */
+ KHS_SHIFT(code, rcode, ')', '0');
+ break;
+ case 0xC:
+ /* - or _ */
+ KHS_SHIFTCTL(code, rcode, 0x1F, '_', '-');
+ break;
+ case 0xD:
+ /* = or + */
+ KHS_SHIFT(code, rcode, '+', '=');
+ break;
+ case 0xE:
+ /* Backspace key. */
+ rcode = code = '\b';
+ break;
+ case 0xF:
+ /* Tab key. */
+ rcode = code = '\t';
+ break;
+ case 0x10:
+ /* q or Q. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x11, 'Q', 'q');
+ break;
+ case 0x11:
+ /* w or W. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x17, 'W', 'w');
+ break;
+ case 0x12:
+ /* e or E. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x05, 'E', 'e');
+ break;
+ case 0x13:
+ /* r or R. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x12, 'R', 'r');
+ break;
+ case 0x14:
+ /* t or T. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x14, 'T', 't');
+ break;
+ case 0x15:
+ /* y or Y. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x19, 'Y', 'y');
+ break;
+ case 0x16:
+ /* u or U. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x15, 'U', 'u');
+ break;
+ case 0x17:
+ /* i or I. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x09, 'I', 'i');
+ break;
+ case 0x18:
+ /* o or O. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x0F, 'O', 'o');
+ break;
+ case 0x19:
+ /* p or P. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x10, 'P', 'p');
+ break;
+ case 0x1A:
+ /* [ or {. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x1B, '{', '[');
+ break;
+ case 0x1B:
+ /* ] or }. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x1D, '}', ']');
+ break;
+ case 0x1C:
+ /* Enter key. */
+ rcode=code='\n';
+ break;
+ case 0x1D:
+ if((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 0))
+ {
+ /* Stage 1 of a pause sequence */
+ key_sequence++;
+ return 0;
+ } else {
+ key_internal_state &= ~KH_PAUSE_SCAN;
+ key_sequence = 0;
+ }
+ rcode=KHE_LCTL;
+ if(pressed)
+ key_state |= KH_LCONTROL_KEY;
+ else
+ key_state &= ~KH_LCONTROL_KEY;
+ break;
+ case 0x1E:
+ /* a or A. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x01, 'A', 'a');
+ break;
+ case 0x1F:
+ /* s or S. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x13, 'S', 's');
+ break;
+ case 0x20:
+ /* d or D. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x04, 'D', 'd');
+ break;
+ case 0x21:
+ /* f or F. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x06, 'F', 'f');
+ break;
+ case 0x22:
+ /* g or G. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x07, 'G', 'g');
+ break;
+ case 0x23:
+ /* h or H. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x08, 'H', 'h');
+ break;
+ case 0x24:
+ /* j or J. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x0A, 'J', 'j');
+ break;
+ case 0x25:
+ /* k or K. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x0B, 'K', 'k');
+ break;
+ case 0x26:
+ /* l or L. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x0C, 'L', 'l');
+ break;
+ case 0x27:
+ /* ; or :. */
+ KHS_SHIFT(code, rcode, ':', ';');
+ break;
+ case 0x28:
+ /* ' or " */
+ KHS_SHIFT(code, rcode, '\"', '\'');
+ break;
+ case 0x29:
+ KHS_SHIFT(code, rcode, '~', '`');
+ break;
+ case 0x2A:
+ rcode = KHE_LSHIFT;
+ if(pressed)
+ key_state |= KH_LSHIFT_KEY;
+ else
+ key_state &= ~KH_LSHIFT_KEY;
+ break;
+ case 0x2B:
+ /* \ or |. */
+ KHS_SHIFTCTL(code, rcode, 0x1C, '|', '\\');
+ break;
+ case 0x2C:
+ /* z or Z. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x1A, 'Z', 'z');
+ break;
+ case 0x2D:
+ /* x or X. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x18, 'X', 'x');
+ break;
+ case 0x2E:
+ /* c or C. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x03, 'C', 'c');
+ break;
+ case 0x2F:
+ /* v or V. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x16, 'V', 'v');
+ break;
+ case 0x30:
+ /* b or B. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x02, 'B', 'b');
+ break;
+ case 0x31:
+ /* n or N. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x0E, 'N', 'n');
+ break;
+ case 0x32:
+ /* m or M. */
+ KHS_SHIFTCAPSCTL(code, rcode, 0x0D, 'M', 'm');
+ break;
+ case 0x33:
+ /* , or <. */
+ KHS_SHIFT(code, rcode, '<', ',');
+ break;
+ case 0x34:
+ /* . or >. */
+ KHS_SHIFT(code, rcode, '>', '.');
+ break;
+ case 0x35:
+ /* / or ? */
+ KHS_SHIFT(code, rcode, '?', '/');
+ break;
+ case 0x36:
+ rcode = KHE_RSHIFT;
+ if(pressed)
+ key_state |= KH_RSHIFT_KEY;
+ else
+ key_state &= ~KH_RSHIFT_KEY;
+ break;
+ case 0x37:
+ /* NP * */
+ rcode = code = '*';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x38:
+ rcode = KHE_LALT;
+ if(pressed)
+ key_state |= KH_LALT_KEY;
+ else
+ key_state &= ~KH_LALT_KEY;
+ break;
+ case 0x39:
+ /* Space bar. */
+ rcode = code =' ';
+ break;
+ case 0x3A:
+ rcode = KHE_CAPSLOCK;
+ if(pressed)
+ {
+ if(key_state & KH_CAPS_LOCK)
+ key_state &= ~KH_CAPS_LOCK;
+ else
+ key_state |= KH_CAPS_LOCK;
+ }
+ break;
+ case 0x3B:
+ /* F1 key. */
+ rcode = code = KHE_F1;
+ break;
+ case 0x3C:
+ /* F2 key. */
+ rcode = code = KHE_F2;
+ break;
+ case 0x3D:
+ /* F3 key. */
+ rcode = code = KHE_F3;
+ break;
+ case 0x3E:
+ /* F4 key. */
+ rcode = code = KHE_F4;
+ break;
+ case 0x3F:
+ /* F5 key. */
+ rcode = code = KHE_F5;
+ break;
+ case 0x40:
+ /* F6 key. */
+ rcode = code = KHE_F6;
+ break;
+ case 0x41:
+ /* F7 key. */
+ rcode = code = KHE_F7;
+ break;
+ case 0x42:
+ /* F8 key. */
+ rcode = code = KHE_F8;
+ break;
+ case 0x43:
+ /* F9 key. */
+ rcode = code = KHE_F9;
+ break;
+ case 0x44:
+ /* F10 key. */
+ rcode = code = KHE_F10;
+ break;
+ case 0x45:
+ if((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 1))
+ {
+ /* Stage 2 of a pause sequence */
+ key_sequence++;
+ return 0;
+ } else {
+ key_internal_state &= ~KH_PAUSE_SCAN;
+ key_sequence = 0;
+ }
+ rcode = KHE_NUMLOCK;
+ if(pressed)
+ {
+ if(key_state & KH_NUM_LOCK)
+ key_state &= ~KH_NUM_LOCK;
+ else
+ key_state |= KH_NUM_LOCK;
+ }
+ break;
+ case 0x47:
+ rcode = code = '7';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x48:
+ rcode = code = '8';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x49:
+ rcode = code = '9';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x4A:
+ rcode = code = '-';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x4B:
+ rcode = code = '4';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x4C:
+ rcode = code = '5';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x4D:
+ rcode = code = '6';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x4E:
+ rcode = code = '+';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x4F:
+ rcode = code = '1';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x50:
+ rcode = code = '2';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x51:
+ rcode = code = '3';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x52:
+ rcode = code = '0';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x53:
+ rcode = code = '.';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x57:
+ /* F11 key. */
+ rcode = code = KHE_F11;
+ break;
+ case 0x58:
+ /* F12 key. */
+ rcode = code = KHE_F12;
+ break;
+ case 0xE1 & 0x7F:
+ if(!(key_internal_state & KH_PAUSE_SCAN))
+ {
+ /* Stage 0 of a pause sequence */
+ key_internal_state |= KH_PAUSE_SCAN;
+ key_sequence = 0;
+ return 0;
+ } else if ((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 2)) {
+ key_sequence++;
+ return 0;
+ } else {
+ key_internal_state &= ~KH_PAUSE_SCAN;
+ key_sequence = 0;
+ }
+ /* FALLTHROUGH */
+ default:
+ rcode = code = KHE_UNDEFINED;
+ break;
+ }
+
+ if ( rcode != KHE_UNDEFINED && code != KHE_UNDEFINED )
+ res |= (KH_RESULT_HASDATA << KH_RMODS_SHIFT);
+ else
+ code = 0x00;
+
+ return res | (code << KH_CHAR_SHIFT)
+ | (rcode << KH_RAWCHAR_SHIFT)
+ | (KH_RESULT_HASRAW << KH_RMODS_SHIFT);
+}
+
+/**
+ * Processes extended scan codes. Notably, this includes
+ * the arrow keys as well as some of the more unusual keys
+ * on the keyboard.
+ *
+ * @param keypress the extended scancode.
+ * @param 0 if released. non-zero if pressed.
+ *
+ * @return A partially constructed kh_type.
+ */
+kh_type
+process_extended_scan(int keypress, int pressed)
+{
+ unsigned char code = 0x80;
+ unsigned char rcode = 0x80;
+ kh_type res = 0;
+
+ /* Intermediate states in multiple byte scancodes should return
+ * zero from this function, rather than returning a RESULT code.
+ */
+
+ switch(keypress & 0x7F)
+ {
+ case 0x1C:
+ /* NP '\n' */
+ rcode = code = '\n';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x1D:
+ /* Right control key */
+ rcode = KHE_RCTL;
+ if(pressed)
+ key_state |= KH_RCONTROL_KEY;
+ else
+ key_state &= ~KH_RCONTROL_KEY;
+ break;
+ case 0x2A:
+ /* Stage 0 of PRINT SCREEN MAKE and Stage 1 of PRINT SCREEN BREAK */
+ if(key_internal_state & KH_PRSCR_UP_SCAN)
+ {
+ rcode = code = KHE_PRINT_SCREEN;
+ key_internal_state &= ~KH_PRSCR_UP_SCAN;
+ } else if (!(key_internal_state & KH_PRSCR_UP_SCAN)) {
+ key_internal_state |= KH_PRSCR_DOWN_SCAN;
+ key_internal_state &= ~KH_EXTENDED_SCAN;
+ return 0;
+ } else {
+ rcode = code = KHE_UNDEFINED;
+ }
+ break;
+ case 0x35:
+ /* NP / */
+ rcode = code = '/';
+ res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+ break;
+ case 0x37:
+ /* Stage 1 of PRINT SCREEN MAKE and Stage 0 of PRINT SCREEN BREAK */
+ if(key_internal_state & KH_PRSCR_DOWN_SCAN)
+ {
+ rcode = code = KHE_PRINT_SCREEN;
+ key_internal_state &= ~KH_PRSCR_DOWN_SCAN;
+ } else if (!(key_internal_state & KH_PRSCR_DOWN_SCAN)) {
+ key_internal_state |= KH_PRSCR_UP_SCAN;
+ key_internal_state &= ~KH_EXTENDED_SCAN;
+ return 0;
+ } else {
+ rcode = code = KHE_UNDEFINED;
+ }
+ break;
+ case 0x38:
+ /* Right alt key */
+ rcode = KHE_RALT;
+ if(pressed)
+ key_state |= KH_RALT_KEY;
+ else
+ key_state &= ~KH_RALT_KEY;
+ break;
+ case 0x48:
+ /* UP */
+ rcode = code=KHE_ARROW_UP;
+ break;
+ case 0x4b:
+ /* LEFT */
+ rcode = code=KHE_ARROW_LEFT;
+ break;
+ case 0x4d:
+ /* RIGHT */
+ rcode = code=KHE_ARROW_RIGHT;
+ break;
+ case 0x50:
+ /* DOWN */
+ rcode = code = KHE_ARROW_DOWN;
+ break;
+ case 0x53:
+ /* DEL */
+ rcode = code = 0x7F;
+ break;
+ default:
+ rcode = code = KHE_UNDEFINED;
+ break;
+ }
+
+ key_internal_state &= ~KH_EXTENDED_SCAN;
+
+ if ( rcode != KHE_UNDEFINED && code != KHE_UNDEFINED )
+ res |= (KH_RESULT_HASDATA << KH_RMODS_SHIFT);
+ else
+ code = 0x00;
+
+ return res | (code << KH_CHAR_SHIFT)
+ | (rcode << KH_RAWCHAR_SHIFT)
+ | (KH_RESULT_HASRAW << KH_RMODS_SHIFT);
+}
+
+ /** The entrypoint to the keyboard processing library.
+ *
+ * @param keypress A raw scancode as returned by the keyboard hardware.
+ * @return A kh_type indicating the keyboard modifier key states, result
+ * modifier bits, and potentially ASCII/410 Upper Code Plane
+ * translations.
+ */
+kh_type process_scancode(int keypress) {
+ kh_type res;
+ int pressed = !(keypress & 0x80);
+ int keycode = keypress & 0x7F;
+
+ if (key_internal_state & KH_EXTENDED_SCAN)
+ res = process_extended_scan(keycode, pressed);
+ else
+ {
+ switch(keypress & 0xFF)
+ {
+ case 0x9D:
+ if ((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 3))
+ {
+ key_sequence++;
+ return 0;
+ } else {
+ key_internal_state &= ~KH_PAUSE_SCAN;
+ key_sequence = 0;
+ }
+ goto deflt;
+ case 0xC5:
+ if ((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 4))
+ {
+ key_internal_state &= ~KH_PAUSE_SCAN;
+ /* Pause sequence completed */
+ res = (KHE_PAUSE << KH_CHAR_SHIFT)
+ | (KHE_PAUSE << KH_RAWCHAR_SHIFT)
+ | (KH_RESULT_HASDATA << KH_RMODS_SHIFT);
+ break;
+ }
+ key_internal_state &= ~KH_PAUSE_SCAN;
+ key_sequence = 0;
+ goto deflt;
+ case 0xE0:
+ key_internal_state |= KH_EXTENDED_SCAN;
+ /* Return no result for this intermediate state */
+ return key_state << KH_STATE_SHIFT;
+ default:
+deflt:
+ key_internal_state &= ~(KH_PRSCR_UP_SCAN | KH_PRSCR_DOWN_SCAN);
+ res = process_simple_scan(keycode, pressed);
+ }
+ }
+
+ if(pressed)
+ res |= KH_RESULT_MAKE << KH_RMODS_SHIFT;
+
+ res |= (key_state & KH_STATE_SMASK) << KH_STATE_SHIFT;
+
+ return res;
+}
+
+/*@}*/
--- /dev/null
+#ifndef KEYHELP_H
+#define KEYHELP_H
+
+#define KEY_IDT_ENTRY 0x21
+#define KEYBOARD_PORT 0x60
+
+/** Return type of process_scancode. Four bytes wide, which are broken down as
+ * follows:
+ *
+ * - The top two (most significant) bytes are a state field composed of the
+ * KH_*_KEY, KH_*_LOCK, and KH_RESULT_* values below.
+ * - The third byte is defined as the "raw" result and gives a cannonical,
+ * unshifted name for the key pressed, if KH_HASDATA() gives true
+ * [KH_RESULT_HASDATA on].
+ * - The fourth (least significant byte) gives a "common" value of the result.
+ * This is the representation subject to all modifier keys.
+ */
+typedef int kh_type;
+
+ /**@{ kh_type bitfield breakdown definitions */
+#define KH_STATE_SHIFT 16
+#define KH_STATE_SMASK 0x0FF00
+#define KH_RMODS_SHIFT 16
+#define KH_RMODS_SMASK 0x000F
+ /* Note that there are bits in neither of these MASKs; these are reserved for
+ * future expanson; see commentary below.
+ */
+#define KH_RAWCHAR_SHIFT 8
+#define KH_RAWCHAR_SMASK 0x0FF
+#define KH_CHAR_SHIFT 0
+#define KH_CHAR_SMASK 0x0FF
+ /**@}*/
+
+ /**@{ Utility macros for parsing the return of process_scancode() */
+ /** Extract STATE fields from return type */
+#define KH_STATE(k) ((k >> KH_STATE_SHIFT) & KH_STATE_SMASK)
+ /** Extract RMODS fields from return type */
+#define KH_RMODS(k) ((k >> KH_RMODS_SHIFT) & KH_RMODS_SMASK)
+ /** Extract RAWCHAR field from return type */
+#define KH_GETRAW(k) ((k >> KH_RAWCHAR_SHIFT) & KH_RAWCHAR_SMASK)
+ /** Extract CHARACTER field from return type */
+#define KH_GETCHAR(k) ((k >> KH_CHAR_SHIFT) & KH_CHAR_SMASK)
+
+ /** Return nonzero if the CapsLock is on in the status word k */
+#define KH_CAPSLOCK(k) (!!((k>>KH_STATE_SHIFT)&KH_CAPS_LOCK))
+ /** Return nonzero if either shift is down in the status word k */
+#define KH_SHIFT(k) (!!((k>>KH_STATE_SHIFT)&(KH_LSHIFT_KEY|KH_RSHIFT_KEY)))
+ /** Return nonzero if either ctl is down in the status word k */
+#define KH_CTL(k) (!!((k>>KH_STATE_SHIFT)&(KH_LCONTROL_KEY|KH_RCONTROL_KEY)))
+ /** Return nonzero if either alt is down in the status word k */
+#define KH_ALT(k) (!!((k>>KH_STATE_SHIFT)&(KH_LALT_KEY|KH_RALT_KEY)))
+
+ /** Return nonzero if the status word k contains a raw character value */
+#define KH_HASRAW(k) (!!((k>>KH_RMODS_SHIFT)&KH_RESULT_HASRAW))
+ /** Return nonzero if the status word k contains a character value */
+#define KH_HASDATA(k) (!!((k>>KH_RMODS_SHIFT)&KH_RESULT_HASDATA))
+ /** Return nonzero if the status word k results are from the Numeric Pad.
+ * @pre Valid only if KH_HASDATA(k) is nonzero. */
+#define KH_NUMPAD(k) (!!((k>>KH_RMODS_SHIFT)&KH_RESULT_NUMPAD))
+ /** Return nonzero if the status work k results from a key going down.
+ * @pre Valid only if KH_HASDATA(k) is nonzero. */
+#define KH_ISMAKE(k) (!!((k>>KH_RMODS_SHIFT)&KH_RESULT_MAKE))
+
+ /** Return nonzero if the status word k character is from the
+ * 410 Upper Code Plane.
+ *
+ * @pre Valid only if KH_HASDATA(k) is nonzero. */
+#define KH_ISEXTENDED(k) (!!(KH_GETCHAR(k)&0x80))
+
+ /** Return nonzero if the status word k raw result character is from
+ * the 410 Upper Code Plane.
+ *
+ * @pre Valid only if KH_HASDATA(k) is nonzero. */
+#define KH_ISRAWEXTENDED(k) (!!(KH_GETRAW(k)&0x80))
+ /**@}*/
+
+/**@{ key_state variables */
+ /** Left shift */
+#define KH_LSHIFT_KEY 0x8000
+ /** Right shift */
+#define KH_RSHIFT_KEY 0x4000
+ /** Left control */
+#define KH_LCONTROL_KEY 0x2000
+ /** Right control */
+#define KH_RCONTROL_KEY 0x1000
+ /** Left alt */
+#define KH_LALT_KEY 0x0800
+ /** Right alt */
+#define KH_RALT_KEY 0x0400
+ /** Caps lock */
+#define KH_CAPS_LOCK 0x0200
+ /** Num lock */
+#define KH_NUM_LOCK 0x0100
+/**@}*/
+
+ /* Reserved bits in range 0x00F0; these are currently NOT inside either of the
+ * MASKS above.
+ *
+ * @bug Currently the LGUI and RGUI modifiers are ignored.
+ * @bug Currently ScrollLock is not treated as a modifier.
+ */
+
+/**@{*/
+ /** Result contains a meaningful answer beyond the modifier bits. If this
+ * bit is OFF in the returned word, the calling implementation SHOULD NOT
+ * make access to either the result or the raw result.
+ *
+ * (As a debugging hint, the current implementation should be returning zeros
+ * in those fields in this case. If lots of zeros seem to be going to
+ * screen, check one's handling of this case!)
+ */
+#define KH_RESULT_HASRAW 0x08
+
+ /** Result contains a meaningful answer beyond the modifier bits and raw
+ * code. That is to say that this contains a translated code that you
+ * probably care about.
+ */
+#define KH_RESULT_HASDATA 0x04
+
+ /** Signals that the result is from the Numeric Pad. This implementation
+ * will return ASCII values regardless of NumLock status, leaving to callers
+ * to do more meaningful things for the non-ASCII meanings. */
+#define KH_RESULT_NUMPAD 0x02
+
+ /** If KH_RESULT_HASDATA, this bit is asserted for MAKE events and clear for
+ * BREAK events. Traditional parsing logic probably only wants to emit
+ * chars when KH_RESULT_MAKE is turned on.
+ */
+#define KH_RESULT_MAKE 0x01
+/**@}*/
+
+enum kh_extended_e {
+ /* Some control codes are returned within the ASCII encoding scheme, where
+ * the ASCII definition is sufficiently close to what we're after.
+ */
+ KHE_ESCAPE = 0x1B,
+ KHE_BACKSPACE = '\b',
+ KHE_TAB = '\t',
+ KHE_ENTER = '\n',
+
+ /*
+ * The remainder of ASCII, from 0x20 - 0x7F, is returned as ASCII. But then
+ * we run out of mappings and, rather than inventing a mapping to the unused
+ * control characters, we invent our own upper code plane, which we'll call
+ * the 410 Upper Code Plane.
+ */
+
+ KHE_UNDEFINED = 0x80, /**< A non-ASCII character for which we don't have an
+ escape sequence. Traditional results would have
+ been to return a '?' but this leaves the behavior
+ to the implementation */
+
+ KHE_ARROW_UP,
+ KHE_ARROW_LEFT,
+ KHE_ARROW_DOWN,
+ KHE_ARROW_RIGHT,
+
+ /* Modifiers */
+ KHE_LALT,
+ KHE_RALT,
+ KHE_LCTL,
+ KHE_RCTL,
+ KHE_LSHIFT,
+ KHE_RSHIFT,
+ /* KHE_LGUI, */
+ /* KHE_RGUI, */
+ KHE_CAPSLOCK,
+ KHE_NUMLOCK,
+
+ /* F keys */
+ KHE_F1,
+ KHE_F2,
+ KHE_F3,
+ KHE_F4,
+ KHE_F5,
+ KHE_F6,
+ KHE_F7,
+ KHE_F8,
+ KHE_F9,
+ KHE_F10,
+ KHE_F11,
+ KHE_F12,
+
+ /* Sequenced characters */
+ KHE_PAUSE,
+ KHE_PRINT_SCREEN,
+
+ /**
+ * @bug Coming soon...
+ * Well now, THIS is going to be a fun case. Since we SHOULD move to
+ * processing the Numeric Pad in the driver, we need to know what KP5 without
+ * NumLock Turned on is... it's this key, which is best defined as
+ * "KP5 without NumLock," known as "BEGIN".
+ */
+ /* KHE_BEGIN, */
+
+ /**
+ * @bug We do not handle these at the moment.
+ */
+ /* KHE_HOME, */
+ /* KHE_END, */
+ /* KHE_INSERT, */
+ /* KHE_PAGE_UP, */
+ /* KHE_PAGE_DOWN, */
+ /* KHE_APPS, */ /* The "context menu" key */
+};
+
+kh_type process_scancode(int keypress);
+
+#endif