From: Joshua Wise Date: Sat, 10 Oct 2009 08:36:53 +0000 (-0400) Subject: First pass of 410watch UI code. X-Git-Url: http://git.joshuawise.com/netwatch.git/commitdiff_plain/6093edb55a1c35ac1163e244f02023345e3e3aca First pass of 410watch UI code. --- diff --git a/cs410/cs410.c b/cs410/cs410.c new file mode 100644 index 0000000..6cc1763 --- /dev/null +++ b/cs410/cs410.c @@ -0,0 +1,199 @@ +/* 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 +#include +#include +#include +#include +#include + +#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); + +} diff --git a/cs410/keyb.c b/cs410/keyb.c new file mode 100644 index 0000000..8fd4c98 --- /dev/null +++ b/cs410/keyb.c @@ -0,0 +1,39 @@ +#include +#include "keyhelp.h" +#include "../net/net.h" +#include + +/* Takes over the i8042... oh well. If we ever fully emulate the i8042, + * then we'll patch into that. + */ + +#define KEYBOARD_PORT 0x60 +#define KEYB_STATUS_PORT 0x64 +#define KEYB_OBF 0x1 + +int getchar() +{ + kh_type key; + unsigned char scancode; + + /* Ignore accesses -- XXX hack */ + outl(0x840, 0x0); + outl(0x848, 0x0); + + do + { + while (!(inb(KEYB_STATUS_PORT) & KEYB_OBF)) + eth_poll(); + + scancode = inb(KEYBOARD_PORT); + outputf("scancode: %02x", scancode); + key = process_scancode(scancode); + } while (!KH_HASDATA(key) || !KH_ISMAKE(key)); + + /* XXX */ + outl(0x840, 0x0); + outl(0x844, 0x1000); + outl(0x848, 0x1000); + + return KH_GETCHAR(key); +} diff --git a/cs410/keyhelp.c b/cs410/keyhelp.c new file mode 100644 index 0000000..98748de --- /dev/null +++ b/cs410/keyhelp.c @@ -0,0 +1,655 @@ +/** + * The 15-410 reference kernel keyboard handling code. + * + * @author Steve Muckle + * + * @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; +} + +/*@}*/ diff --git a/cs410/keyhelp.h b/cs410/keyhelp.h new file mode 100644 index 0000000..4644b86 --- /dev/null +++ b/cs410/keyhelp.h @@ -0,0 +1,210 @@ +#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 diff --git a/netwatch/Makefile b/netwatch/Makefile index 9609e03..1b31484 100644 --- a/netwatch/Makefile +++ b/netwatch/Makefile @@ -59,6 +59,9 @@ OBJS = ../ich2/smi.o \ ../lib/demap.o \ ../lib/state.o \ ../lib/cpuid.o \ + ../cs410/cs410.o \ + ../cs410/keyb.o \ + ../cs410/keyhelp.o \ keyboard.o \ packet.o \ $(LWIP_OBJS) \ diff --git a/netwatch/firstrun.c b/netwatch/firstrun.c index 66b08d4..e561c4f 100644 --- a/netwatch/firstrun.c +++ b/netwatch/firstrun.c @@ -24,6 +24,7 @@ extern int _bss, _bssend; extern void timer_handler(smi_event_t ev); extern void kbc_handler(smi_event_t ev); extern void gbl_rls_handler(smi_event_t ev); +extern void cs410_pwrbtn_handler(smi_event_t ev); extern pci_driver_t *drivers[]; @@ -69,6 +70,9 @@ void smi_init() { smi_register_handler(SMI_EVENT_GBL_RLS, gbl_rls_handler); smi_enable_event(SMI_EVENT_GBL_RLS); + + smi_register_handler(SMI_EVENT_PWRBTN, cs410_pwrbtn_handler); + smi_enable_event(SMI_EVENT_PWRBTN); smi_enable(); diff --git a/netwatch/smi.c b/netwatch/smi.c index e551ac4..296d613 100644 --- a/netwatch/smi.c +++ b/netwatch/smi.c @@ -73,6 +73,7 @@ void smi_entry(void) extern void timer_handler(smi_event_t ev); extern void kbc_handler(smi_event_t ev); extern void gbl_rls_handler(smi_event_t ev); +extern void cs410_pwrbtn_handler(smi_event_t ev); void __firstrun_stub() { @@ -93,6 +94,9 @@ void __firstrun_stub() { smi_register_handler(SMI_EVENT_GBL_RLS, gbl_rls_handler); smi_enable_event(SMI_EVENT_GBL_RLS); + + smi_register_handler(SMI_EVENT_PWRBTN, cs410_pwrbtn_handler); + smi_enable_event(SMI_EVENT_PWRBTN); smi_enable(); }