diff options
author | aqua <aqua@iserlohn-fortress.net> | 2023-03-12 18:39:39 +0200 |
---|---|---|
committer | aqua <aqua@iserlohn-fortress.net> | 2023-03-12 18:39:39 +0200 |
commit | fbc736463f2ca2f5dbf1b7c412f408245e61df97 (patch) | |
tree | 84a66eabc5e3be2191ae0d5d1e0ff33d05515b4a /devices/vga.c | |
parent | Add unit tests for C drivers (diff) | |
download | kernel-fbc736463f2ca2f5dbf1b7c412f408245e61df97.tar.xz |
Revert VGA C driver
Diffstat (limited to 'devices/vga.c')
-rw-r--r-- | devices/vga.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/devices/vga.c b/devices/vga.c new file mode 100644 index 0000000..e4831b8 --- /dev/null +++ b/devices/vga.c @@ -0,0 +1,152 @@ +#include "vga.h" +#include <stdint.h> +#include <sys/io.h> + +#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; +}; +_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) +{ + 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 FILE *self, const char *string, int len) +{ + int written = 0; + if (len == -1) + while (*string != '\0') { + vga_putc(self, *string); + ++string; + ++written; + } + + else + for (int 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) +{ + 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; + vga_update_cursor(); +} |