X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pintos-anon;a=blobdiff_plain;f=src%2Fdevices%2Fvga.c;h=f421b617bd3706858d2536eb21866531b1fd9b85;hp=28235af6141a0fd7ed6a57298ede87471ec4e542;hb=f1f2dc8de9e336d83383692d4478bb14a3dafc11;hpb=9b16dc8bd3273cb0f88e5410e42eb886b8da992a diff --git a/src/devices/vga.c b/src/devices/vga.c index 28235af..f421b61 100644 --- a/src/devices/vga.c +++ b/src/devices/vga.c @@ -1,90 +1,172 @@ -#include "vga.h" +#include "devices/vga.h" +#include #include #include -#include "io.h" -#include "lib.h" -#include "mmu.h" +#include +#include "devices/speaker.h" +#include "threads/io.h" +#include "threads/interrupt.h" +#include "threads/vaddr.h" -static size_t vga_cols, vga_rows; -static size_t vga_x, vga_y; -static uint16_t *vga_base; +/* VGA text screen support. See [FREEVGA] for more information. */ -void -vga_init (void) -{ - vga_cols = 80; - vga_rows = 25; - vga_base = (uint16_t *) ptov (0xb8000); - vga_cls (); -} +/* Number of columns and rows on the text display. */ +#define COL_CNT 80 +#define ROW_CNT 25 -void -vga_cls (void) -{ - size_t i; - for (i = 0; i < vga_cols * vga_rows; i++) - vga_base[i] = 0x0700; - vga_x = vga_y = 0; -} +/* Current cursor position. (0,0) is in the upper left corner of + the display. */ +static size_t cx, cy; + +/* Attribute value for gray text on a black background. */ +#define GRAY_ON_BLACK 0x07 +/* Framebuffer. See [FREEVGA] under "VGA Text Mode Operation". + The character at (x,y) is fb[y][x][0]. + The attribute at (x,y) is fb[y][x][1]. */ +static uint8_t (*fb)[COL_CNT][2]; + +static void clear_row (size_t y); +static void cls (void); +static void newline (void); +static void move_cursor (void); +static void find_cursor (size_t *x, size_t *y); + +/* Initializes the VGA text display. */ static void -vga_newline (void) +init (void) { - vga_x = 0; - vga_y++; - if (vga_y >= vga_rows) + /* Already initialized? */ + static bool inited; + if (!inited) { - vga_y = vga_rows - 1; - memmove (vga_base, vga_base + vga_cols, - vga_cols * (vga_rows - 1) * 2); - memset (vga_base + vga_cols * (vga_rows - 1), - 0, vga_cols * 2); + fb = ptov (0xb8000); + find_cursor (&cx, &cy); + inited = true; } } -static void -move_cursor (void) -{ - uint16_t cp = (vga_x + vga_cols * vga_y); - outw (0x3d4, 0x0e | (cp & 0xff00)); - outw (0x3d4, 0x0f | (cp << 8)); -} - +/* Writes C to the VGA text display, interpreting control + characters in the conventional ways. */ void vga_putc (int c) { + /* Disable interrupts to lock out interrupt handlers + that might write to the console. */ + enum intr_level old_level = intr_disable (); + + init (); + switch (c) { case '\n': - vga_newline (); + newline (); break; case '\f': - vga_cls (); + cls (); break; case '\b': - if (vga_x > 0) - vga_x--; + if (cx > 0) + cx--; break; case '\r': - vga_x = 0; + cx = 0; break; case '\t': - vga_x = (vga_x + 8) / 8 * 8; - if (vga_x >= vga_cols) - vga_newline (); + cx = ROUND_UP (cx + 1, 8); + if (cx >= COL_CNT) + newline (); + break; + + case '\a': + intr_set_level (old_level); + speaker_beep (); + intr_disable (); break; default: - vga_base[vga_x + vga_y * vga_cols] = 0x0700 | c; - vga_x++; - if (vga_x >= vga_cols) - vga_newline (); + fb[cy][cx][0] = c; + fb[cy][cx][1] = GRAY_ON_BLACK; + if (++cx >= COL_CNT) + newline (); break; } + /* Update cursor position. */ move_cursor (); + + intr_set_level (old_level); +} + +/* Clears the screen and moves the cursor to the upper left. */ +static void +cls (void) +{ + size_t y; + + for (y = 0; y < ROW_CNT; y++) + clear_row (y); + + cx = cy = 0; + move_cursor (); +} + +/* Clears row Y to spaces. */ +static void +clear_row (size_t y) +{ + size_t x; + + for (x = 0; x < COL_CNT; x++) + { + fb[y][x][0] = ' '; + fb[y][x][1] = GRAY_ON_BLACK; + } +} + +/* Advances the cursor to the first column in the next line on + the screen. If the cursor is already on the last line on the + screen, scrolls the screen upward one line. */ +static void +newline (void) +{ + cx = 0; + cy++; + if (cy >= ROW_CNT) + { + cy = ROW_CNT - 1; + memmove (&fb[0], &fb[1], sizeof fb[0] * (ROW_CNT - 1)); + clear_row (ROW_CNT - 1); + } +} + +/* Moves the hardware cursor to (cx,cy). */ +static void +move_cursor (void) +{ + /* See [FREEVGA] under "Manipulating the Text-mode Cursor". */ + uint16_t cp = cx + COL_CNT * cy; + outw (0x3d4, 0x0e | (cp & 0xff00)); + outw (0x3d4, 0x0f | (cp << 8)); +} + +/* Reads the current hardware cursor position into (*X,*Y). */ +static void +find_cursor (size_t *x, size_t *y) +{ + /* See [FREEVGA] under "Manipulating the Text-mode Cursor". */ + uint16_t cp; + + outb (0x3d4, 0x0e); + cp = inb (0x3d5) << 8; + + outb (0x3d4, 0x0f); + cp |= inb (0x3d5); + + *x = cp % COL_CNT; + *y = cp / COL_CNT; }