99 lines
3.0 KiB
C
99 lines
3.0 KiB
C
|
/**
|
||
|
* @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;
|
||
|
}
|