hazel/kernel/vga.c

99 lines
3.0 KiB
C
Raw Normal View History

/**
* @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 <kernel/vga.h>
#include <kernel/io.h>
#include <kernel/log.h>
#include <kernel/mem.h>
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;
}