os-k/src/kaleid/kernel/io/terminal.c

148 lines
3.4 KiB
C
Raw Normal View History

//----------------------------------------------------------------------------//
// GNU GPL OS/K //
// //
// Authors: spectral` //
// NeoX //
// //
// Desc: Early terminal functions //
//----------------------------------------------------------------------------//
#include "kernel/io/terminal.h"
// VGA buffer size
static const size_t kterm_width = 80;
static const size_t kterm_height = 25;
// position in the buffer
static size_t current_row;
static size_t current_col;
static uchar current_color;
// each buffer entry is composed of two bytes
// one is the color code, the other the character
static ushort *const buffer = (ushort *)0xB8000;
#define ComputeColorCode(fg, bg) ((fg) | (bg) << 4)
#define ComputeEntryOffset(x, y) ((y) * kterm_width + (x))
#define ComputeEntry(ch, cl) (((ushort)(ch)) | (ushort)(cl) << 8)
void kterm_init(void)
{
assert_never_used(kterm_init);
kterm_change_color(ComputeColorCode(KTERM_COLOR_LIGHT_GREY, KTERM_COLOR_BLACK));
kterm_clear();
}
void kterm_clear(void)
{
size_t x, y;
assert_used_once(kterm_init);
for (x = 0; x < kterm_width; x++) {
for (y = 0; y < kterm_height; y++) {
const size_t offset = ComputeEntryOffset(x,y);
buffer[offset] = ComputeEntry(' ', current_color);
}
}
// go back to beginning
current_row = current_col = 0;
// XXX cursor update
}
status_t kterm_change_color(uchar color)
{
if (color > KTERM_COLOR_WHITE)
return BAD_ARG_RANGE;
current_color = color;
return SUCCESS;
}
void kterm_putchar(char ch)
{
int i;
size_t prev;
assert_used_once(kterm_init);
// carriage return takes us back to the beginning of the line
// no further test should be necessary
if (ch == '\r') { current_col = 0; return; }
// line feed first takes us to the very end of the line
// later in this function we actually do the line feed
else if (ch == '\n') { current_col = kterm_width - 1; }
// tabulations account for 4 spaces
else if (ch == '\t') {
prev = current_row;
// compiler will optimize this away
for (i = 0; i < 4; i++) {
// tabulations can't spread over two lines
if (current_row != prev) return;
kterm_putchar(' ');
}
}
// XXX check whether we were given a writable character
else {
const size_t offset = ComputeEntryOffset(current_col, current_row);
buffer[offset] = ComputeEntry(ch, current_color);
}
// end of line?
if (++current_col == kterm_width) {
current_col = 0;
// end of buffer?
if (++current_row == kterm_height) {
current_row = 0;
// XXX save previous buffer(?) and clear
}
}
}
void kterm_print(const char *s)
{
while (*s) {
kterm_putchar(*s);
s++;
}
}
void panic(const char *s)
{
cli();
panicstr = s;
kterm_clear();
kterm_print("panic! - ");
kterm_print(s);
while (1) hlt();
__builtin_unreachable();
}