#include "vga.h" #include #include #define cga_idx_port 0x3d4 #define cga_dat_port 0x3d5 #define cursor_start 0x0a #define cursor_end 0x0b #define cursor_addr_h 0x0e #define cursor_addr_l 0x0f #define cursor_hide 0x20 struct __attribute__((packed)) VGAEntry { unsigned char text; uint8_t foreground : 4; uint8_t background : 4; }; /* TODO _Static_assert(sizeof(struct VGAEntry) == 2, "sizeof VGAEntry"); */ const int width = 80; const int height = 25; struct VGAEntry *buffer; int col = 0; int row = 0; /* *** Cursor *** */ 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(void) { 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(__attribute__((unused)) const FILE *self, char a) { int i, x, y; 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 (y = 1; y < height; ++y) for (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 (i = (height - 1) * width; i < height * width; ++i) buffer[i].text = ' '; --row; } } int vga_puts(const FILE *self, const char *string, int len) { int i; int written = 0; if (len == -1) while (*string != '\0') { vga_putc(self, *string); ++string; ++written; } else for (i = 0; i < len; ++i) { vga_putc(self, string[i]); ++written; } return written; } void vga_flush(__attribute__((unused)) const FILE *self) { vga_update_cursor(); } /* *** Text Mode *** */ FILE vga_stream; FILE * vga_init(void *addr) { buffer = (struct VGAEntry *)addr; vga_enable_cursor(14, 15); vga_clear(VGA_COLOR_LIGHT_BLUE, VGA_COLOR_LIGHT_GREY); vga_stream.id = 0; vga_stream.putc = &vga_putc; vga_stream.puts = &vga_puts; vga_stream.flush = &vga_flush; return &vga_stream; } void vga_clear(enum vga_color foreground, enum vga_color background) { int x, y; for (y = 0; y < height; ++y) for (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; vga_update_cursor(); }