Files
aster-core/drivers/display.c
T
2026-07-12 05:44:42 +02:00

191 lines
3.8 KiB
C

/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento ovladac realizuje textovou konzoli nad VGA pameti na adrese 0xB8000.
* Ridi pozici kurzoru, barvy znaku, zpracovani ridicich znaku
* a automaticky scroll, kdyz vystup presahne posledni radek obrazovky.
*/
#include "display.h"
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
#define VGA_CONTENT_HEIGHT (VGA_HEIGHT - 1)
static volatile u16 *const vga = (u16 *)0xB8000;
static u8 color = 0x0F;
static usize row = 0;
static usize col = 0;
static inline void outb(u16 port, u8 value) {
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
static void update_hw_cursor(void) {
u16 pos = (u16)(row * VGA_WIDTH + col);
outb(0x3D4, 0x0F);
outb(0x3D5, (u8)(pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (u8)((pos >> 8) & 0xFF));
}
static inline u16 vga_entry(char c, u8 clr) {
return (u16)c | ((u16)clr << 8);
}
static void scroll_if_needed(void) {
usize r;
usize c;
if (row < VGA_CONTENT_HEIGHT) {
return;
}
for (r = 1; r < VGA_CONTENT_HEIGHT; ++r) {
for (c = 0; c < VGA_WIDTH; ++c) {
vga[(r - 1) * VGA_WIDTH + c] = vga[r * VGA_WIDTH + c];
}
}
for (c = 0; c < VGA_WIDTH; ++c) {
vga[(VGA_CONTENT_HEIGHT - 1) * VGA_WIDTH + c] = vga_entry(' ', color);
}
row = VGA_CONTENT_HEIGHT - 1;
}
void display_set_color(u8 fg, u8 bg) {
color = (u8)((bg << 4) | (fg & 0x0F));
}
void display_clear(void) {
usize i;
for (i = 0; i < VGA_WIDTH * VGA_HEIGHT; ++i) {
vga[i] = vga_entry(' ', color);
}
row = 0;
col = 0;
update_hw_cursor();
}
void display_init(void) {
display_set_color(0x0F, 0x00);
display_clear();
}
void display_putc(char c) {
if (c == '\n') {
col = 0;
++row;
scroll_if_needed();
update_hw_cursor();
return;
}
if (c == '\r') {
col = 0;
update_hw_cursor();
return;
}
if (c == '\b') {
if (col > 0) {
--col;
} else if (row > 0) {
--row;
col = VGA_WIDTH - 1;
}
vga[row * VGA_WIDTH + col] = vga_entry(' ', color);
update_hw_cursor();
return;
}
if (c == '\t') {
col = (col + 4) & ~3ULL;
if (col >= VGA_WIDTH) {
col = 0;
++row;
scroll_if_needed();
}
update_hw_cursor();
return;
}
vga[row * VGA_WIDTH + col] = vga_entry(c, color);
++col;
if (col >= VGA_WIDTH) {
col = 0;
++row;
scroll_if_needed();
}
update_hw_cursor();
}
void display_write(const char *text) {
while (*text) {
display_putc(*text++);
}
}
void display_get_cursor(usize *out_row, usize *out_col) {
if (out_row) {
*out_row = row;
}
if (out_col) {
*out_col = col;
}
}
void display_set_cursor(usize new_row, usize new_col) {
if (new_row >= VGA_HEIGHT) {
new_row = VGA_HEIGHT - 1;
}
if (new_col >= VGA_WIDTH) {
new_col = VGA_WIDTH - 1;
}
row = new_row;
col = new_col;
update_hw_cursor();
}
void display_fill_row(usize target_row, char ch, u8 fg, u8 bg) {
usize c;
u8 clr;
if (target_row >= VGA_HEIGHT) {
return;
}
clr = (u8)((bg << 4) | (fg & 0x0F));
for (c = 0; c < VGA_WIDTH; ++c) {
vga[target_row * VGA_WIDTH + c] = vga_entry(ch, clr);
}
}
void display_write_at(usize target_row, usize target_col, const char *text, u8 fg, u8 bg) {
usize c = target_col;
u8 clr;
if (!text || target_row >= VGA_HEIGHT || target_col >= VGA_WIDTH) {
return;
}
clr = (u8)((bg << 4) | (fg & 0x0F));
while (*text && c < VGA_WIDTH) {
vga[target_row * VGA_WIDTH + c] = vga_entry(*text++, clr);
++c;
}
}