#include "vga.hpp" #include #include // FIXME user a Port #define cga_idx_port 0x3d4 #define cga_dat_port 0x3d5 // FIXME make constexpr #define cursor_start 0x0a #define cursor_end 0x0b #define cursor_addr_h 0x0e #define cursor_addr_l 0x0f #define cursor_hide 0x20 static_assert(sizeof(struct VGA::VGAEntry) == 2, "sizeof VGAEntry"); // FIXME make constexpr const int width = 80; const int height = 25; // *** Cursor *** // FIXME make VGA members void vga_enable_cursor(unsigned char start, unsigned char end) { outb(cursor_start, cga_idx_port); outb((inb(cga_dat_port) & 0xc0) | start, cga_dat_port); outb(cursor_end, cga_idx_port); outb((inb(cga_dat_port) & 0xe0) | end, cga_dat_port); } void vga_disable_cursor() { outb(cursor_start, cga_idx_port); outb(cursor_hide, cga_dat_port); } void VGA::update_cursor() { const uint16_t pos = row * width + col; outb(cursor_addr_l, cga_idx_port); outb(pos & 0xff, cga_dat_port); outb(cursor_addr_h, cga_idx_port); outb((pos >> 8) & 0xff, cga_dat_port); } // *** Text Mode Output *** void VGA::putc(char a) { switch (a) { case '\n': col = 0; ++row; break; case '\r': col = 0; break; case '\b': --col; if (col < 0) col = 0; break; default: buffer[row * width + col].text = a; ++col; } if (col == width) { col = 0; ++row; } if (row == height) { // scroll up for (int y = 1; y < height; ++y) for (int x = 0; x < width; ++x) { const int prev = (y - 1) * width + x; const int curr = y * width + x; buffer[prev] = buffer[curr]; } // blank out last row for (int i = (height - 1) * width; i < height * width; ++i) buffer[i].text = ' '; --row; } } int VGA::puts(const char *string, int len) { int written = 0; if (len == -1) while (*string != '\0') { putc(*string); ++string; ++written; } else for (int i = 0; i < len; ++i) { putc(string[i]); ++written; } return written; } // *** Text Mode *** VGA::VGA(void *addr) { buffer = (struct VGAEntry *)addr; vga_enable_cursor(14, 15); clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); } FILE * vga_init(void *buffer) { static VGA device(buffer); return &device; } void VGA::clear(enum vga_color foreground, enum vga_color background) { for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) { const int index = y * width + x; buffer[index].text = ' '; buffer[index].foreground = foreground; buffer[index].background = background; } col = row = 0; update_cursor(); }