// vconsole.c // Author: Josh Holtrop // Date: 08/02/04 // Modified: 08/16/04 #include "char/vconsole.h" #include "hos_defines.h" #include "fs/devices.h" #include "mm/vmm.h" #include "lang/asmfuncs.h" #include "display.h" #include "functions.h" vconsole_t *vconsoles[VCONSOLE_MAX]; // pointer to virtual console structs extern int display_activeConsole; // display subsystem active virtual console number char ansi2vgaAttr[8] = {0, 4, 2, 6, 1, 5, 3, 7}; void vconsole_put_char(minor_t id, int c); void vconsole_update_cursor(minor_t id, u16_t position); void vconsole_update_attribute(minor_t id); void vconsole_refresh(minor_t id); // initialization routine for vconsoles module int vconsole_init(major_t major) { dev_driver_t *vconsole_driver; if (( vconsole_driver = New(dev_driver_t) )) { vconsole_driver->char_write = vconsole_char_write; devices_register_major('c', major, vconsole_driver); return 0; } return -1; } // routine to create a new virtual console object minor_t vconsole_new(int width, int height) { int i; for (i = 1; i < VCONSOLE_MAX; i++) { if ( (!vconsoles[i]) && ( vconsoles[i] = kcalloc(1, sizeof(vconsole_t)))) //New(vconsole_t) ) ) { if (( vconsoles[i]->buffer = kmalloc(width * height * 2) )) { vconsoles[i]->width = width; vconsoles[i]->height = height; vconsoles[i]->attribute = vconsoles[i]->foreground = 0x07; memsetw(vconsoles[i]->buffer, 0x0720, width * height); // register the device as /dev/console%d return i; } else { kfree(vconsoles[i]); return 0; } } } return 0; } // called by display subsystem to draw a virtual console to the screen int vconsole_draw(minor_t id) { if (vconsoles[id]) return display_console_draw(id, vconsoles[id]->cursorPosition, vconsoles[id]->buffer); return -1; } // called by character device interface when a character is written to device w/ minor #id int vconsole_char_write(minor_t id, int c) { if (!vconsoles[id]) return -1; int cursorY = vconsoles[id]->cursorPosition / vconsoles[id]->width; int cursorX = vconsoles[id]->cursorPosition % vconsoles[id]->width; int evalEscapePosition = 0; switch (vconsoles[id]->escapeLevel) { case 2: if (c >= '0' && c <= '9') // c is part of an escape value { vconsoles[id]->escapeValue[vconsoles[id]->escapePosition] *= 10; vconsoles[id]->escapeValue[vconsoles[id]->escapePosition] += c - '0'; return 0; } else if (c == ';') { if (vconsoles[id]->escapePosition < 7) vconsoles[id]->escapePosition++; return 0; } switch (c) { case 'A': // move cursor up n rows cursorY -= vconsoles[id]->escapeValue[0]; if (cursorY < 0) cursorY = 0; vconsole_update_cursor(id, cursorY * vconsoles[id]->width + cursorX); break; case 'B': // move cursor down n rows cursorY += vconsoles[id]->escapeValue[0]; if (cursorY >= vconsoles[id]->height) cursorY = vconsoles[id]->height - 1; vconsole_update_cursor(id, cursorY * vconsoles[id]->width + cursorX); break; case 'C': // move cursor left n columns cursorX -= vconsoles[id]->escapeValue[0]; if (cursorX < 0) cursorX = 0; vconsole_update_cursor(id, cursorY * vconsoles[id]->width + cursorX); break; case 'D': // move cursor right n columns cursorX += vconsoles[id]->escapeValue[0]; if (cursorX >= vconsoles[id]->width) cursorX = vconsoles[id]->width - 1; vconsole_update_cursor(id, cursorY * vconsoles[id]->width + cursorX); break; case 'H': case 'f': // move cursor to position (x,y) upper left is (1,1) cursorX = vconsoles[id]->escapeValue[0] - 1; cursorY = vconsoles[id]->escapeValue[1] - 1; if (cursorY < 0) cursorY = 0; if (cursorY >= vconsoles[id]->height) cursorY = vconsoles[id]->height - 1; if (cursorX < 0) cursorX = 0; if (cursorX >= vconsoles[id]->width) cursorX = vconsoles[id]->width - 1; vconsole_update_cursor(id, cursorY * vconsoles[id]->width + cursorX); break; case 'J': // clear screen, home cursor memsetw(vconsoles[id]->buffer, 0x0720, vconsoles[id]->width * vconsoles[id]->height); vconsole_draw(id); vconsole_update_cursor(id, 0); break; case 'K': // erase line from cursor position (including char. under cursor) to end of line memsetw(vconsoles[id]->buffer + vconsoles[id]->cursorPosition, 0x0720, vconsoles[id]->width - cursorX); vconsole_draw(id); break; case 's': // push cursor position on an internal stack if (vconsoles[id]->cursorStackPosition < 16) vconsoles[id]->cursorStack[vconsoles[id]->cursorStackPosition++] = vconsoles[id]->cursorPosition; break; case 'u': // pop cursor position from stack if (vconsoles[id]->cursorStackPosition > 0) { vconsole_update_cursor(id, vconsoles[id]->cursorStack[--vconsoles[id]->cursorStackPosition]); } break; case 'm': // set text attributes for (evalEscapePosition = 0; evalEscapePosition <= vconsoles[id]->escapePosition; evalEscapePosition++) { switch (vconsoles[id]->escapeValue[evalEscapePosition]) { case 0: vconsoles[id]->foreground = 0x07; vconsoles[id]->background = 0x00; vconsoles[id]->concealed = 0; vconsoles[id]->reverse = 0; vconsoles[id]->blink = 0; vconsoles[id]->bold = 0; vconsole_update_attribute(id); break; case 1: vconsoles[id]->bold = 1; vconsole_update_attribute(id); break; case 5: vconsoles[id]->blink = 1; vconsole_update_attribute(id); break; case 7: vconsoles[id]->reverse = 1; vconsole_update_attribute(id); break; case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: vconsoles[id]->foreground = ansi2vgaAttr[vconsoles[id]->escapeValue[evalEscapePosition] - 30]; vconsole_update_attribute(id); break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: vconsoles[id]->background = ansi2vgaAttr[vconsoles[id]->escapeValue[evalEscapePosition] - 40]; vconsole_update_attribute(id); break; } } vconsoles[id]->escapePosition = 0; break; } memsetd(vconsoles[id]->escapeValue, 0, 8); vconsoles[id]->escapePosition = 0; vconsoles[id]->escapeLevel = 0; return 0; case 1: if (c == '[') vconsoles[id]->escapeLevel = 2; break; vconsoles[id]->escapeLevel = 0; return 0; // invalid escape sequence default: if (c == '\e') { vconsoles[id]->escapeLevel = 1; return 0; } vconsole_put_char(id, c); } return 0; } // write the character to the virtual console void vconsole_put_char(minor_t id, int c) { if (!vconsoles[id]->concealed) { switch (c) { case '\t': if (vconsoles[id]->cursorPosition % 8) vconsole_update_cursor(id, vconsoles[id]->cursorPosition + (8 - (vconsoles[id]->cursorPosition % 8))); else vconsole_update_cursor(id, vconsoles[id]->cursorPosition + 8); break; case '\n': if (vconsoles[id]->cursorPosition % (vconsoles[id]->width)) vconsole_update_cursor(id, vconsoles[id]->cursorPosition + (vconsoles[id]->width - (vconsoles[id]->cursorPosition % vconsoles[id]->width))); else vconsole_update_cursor(id, vconsoles[id]->cursorPosition + vconsoles[id]->width); break; default: vconsoles[id]->buffer[vconsoles[id]->cursorPosition] = c | (vconsoles[id]->attribute << 8); if (id == display_activeConsole) display_console_put_char(id, c | (vconsoles[id]->attribute << 8), vconsoles[id]->cursorPosition); vconsole_update_cursor(id, vconsoles[id]->cursorPosition + 1); } } } void vconsole_update_cursor(minor_t id, u16_t position) { vconsoles[id]->cursorPosition = position; if (position >= (vconsoles[id]->width * vconsoles[id]->height)) // time to scroll console { int i; for (i = 0; i < vconsoles[id]->cursorStackPosition; i++) { vconsoles[id]->cursorStack[i] -= vconsoles[id]->width; if (vconsoles[id]->cursorStack[i] < 0) vconsoles[id]->cursorStack[i] = 0; } vconsoles[id]->cursorPosition -= vconsoles[id]->width; memcpyw(vconsoles[id]->buffer, vconsoles[id]->buffer + vconsoles[id]->width, vconsoles[id]->width * (vconsoles[id]->height - 1)); memsetw(vconsoles[id]->buffer + (vconsoles[id]->width * (vconsoles[id]->height - 1)), 0x0720, vconsoles[id]->width); if (display_activeConsole == id) { vconsole_draw(id); return; } } if (display_activeConsole == id) display_console_update_cursor(id, position); } void vconsole_update_attribute(minor_t id) { if (vconsoles[id]->reverse) { vconsoles[id]->attribute = vconsoles[id]->blink << 7 | vconsoles[id]->foreground << 4 | vconsoles[id]->bold << 3 | vconsoles[id]->background; } else { vconsoles[id]->attribute = vconsoles[id]->blink << 7 | vconsoles[id]->background << 4 | vconsoles[id]->bold << 3 | vconsoles[id]->foreground; } }