/** * @file vga.c * @brief Basic functions for interacting with the CRTC controller in VGA text-mode. * @author rami * @version 0.1 * @date 2024-02-03 */ #include #include #include #include enum VGA_COLOR vga_color = VGA_COLOR_WHITE; uint16_t get_cursor_pos() { uint16_t pos = 0; /* Tell CRTC controller we want the low cursor position */ outb(CRTC_ADDR_PORT, CRTC_CURSOR_LO_REGISTER); /* Read it through the data port */ pos = inb(CRTC_DATA_PORT); /* Repeat with high position */ outb(CRTC_ADDR_PORT, CRTC_CURSOR_HI_REGISTER); uint16_t hi_pos = 0; hi_pos = inb(CRTC_DATA_PORT); pos |= hi_pos << 8; return pos; } void set_cursor_pos(uint16_t pos) { /* Tell CRTC controller we want the low cursor position */ outb(CRTC_ADDR_PORT, CRTC_CURSOR_LO_REGISTER); outb(CRTC_DATA_PORT, (uint8_t)(pos & 0xFF)); /* Repeat with high position */ outb(CRTC_ADDR_PORT, CRTC_CURSOR_HI_REGISTER); outb(CRTC_DATA_PORT, (uint8_t)((pos >> 8) & 0xFF)); } void clear_screen(void) { char *video_memory = (char *)VGA_MEMORY_ADDR; for (int i = 0; i < VGA_MAX_COLS * VGA_MAX_ROWS; i++) { video_memory[i * 2] = 0; } set_cursor_pos(0); } void vga_putc(char character) { uint16_t pos = get_cursor_pos(); if (pos == VGA_MAX_COLS * VGA_MAX_ROWS) { if (character != '\n') { // Move video memory up one row memcpy((char*)VGA_MEMORY_ADDR, (char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*2), VGA_MAX_COLS * (VGA_MAX_ROWS - 1) * 2); // Clear last row for (int i = 0; i < VGA_MAX_COLS*2; i+=2) { ((char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*(VGA_MAX_ROWS - 1)*2))[i] = 0; ((char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*(VGA_MAX_ROWS - 1)*2))[i+1] = 0x0f; } pos = VGA_MAX_COLS * (VGA_MAX_ROWS - 1); } else { // Move video memory up two rows memcpy((char*)VGA_MEMORY_ADDR, (char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*2*2), VGA_MAX_COLS * (VGA_MAX_ROWS - 2) * 2); // Clear last 2 rows for (int i = 0; i < VGA_MAX_COLS*2*2; i+=2) { ((char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*(VGA_MAX_ROWS - 2)*2))[i] = 0; ((char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*(VGA_MAX_ROWS - 2)*2))[i+1] = 0x0f; } pos = VGA_MAX_COLS * (VGA_MAX_ROWS - 2); } } char *video_memory = (char *)VGA_MEMORY_ADDR + pos * 2; if (character == '\n') { uint16_t next_line = VGA_MAX_COLS * (pos / VGA_MAX_COLS + 1); set_cursor_pos(next_line); } else { video_memory[0] = character; video_memory[1] = vga_color; set_cursor_pos(pos + 1); } } void popchar() { uint16_t pos = get_cursor_pos(); if (pos == 0) return; char *video_memory = (char *)(VGA_MEMORY_ADDR + (pos - 1) * 2); video_memory[0] = 0; set_cursor_pos(pos - 1); } void set_color(enum VGA_COLOR col) { vga_color = col; }