os-k/kaleid/kernel/ke/terminal.c

237 lines
5.4 KiB
C

//----------------------------------------------------------------------------//
// GNU GPL OS/K //
// //
// Authors: spectral` //
// NeoX //
// //
// Desc: Early terminal functions //
//----------------------------------------------------------------------------//
#include <kaleid.h>
static Terminal_t vgaTerm;
//
// Initialize standard output
//
void InitTerms(void)
{
KalAssert(!GetStdOut() && vgaTerm.initDone != INITOK);
vgaTerm.initDone = INITOK;
SetStdDbg(&vgaTerm);
SetStdOut(&vgaTerm);
ClearTerm(GetStdOut());
}
//
// Fill terminal with spaces
//
error_t ClearTerm(Terminal_t *term)
{
error_t retcode;
if (term == NULL) return EINVAL;
KalAssert(term->initDone == INITOK);
AquireLock(&term->lock);
retcode = term->ClearTermUnlocked(term);
ReleaseLock(&term->lock);
return retcode;
}
//
// Change the color code
//
error_t ChTermColor(Terminal_t *term, TermColor_t fgColor, TermColor_t bgColor)
{
if (fgColor > KTERM_COLOR_WHITE || bgColor > KTERM_COLOR_WHITE)
return EINVAL;
if (term == NULL)
return EINVAL;
AquireLock(&term->lock);
term->fgColor = fgColor;
term->bgColor = bgColor;
ReleaseLock(&term->lock);
return EOK;
}
//
// Write a single character on the terminal
//
error_t PutOnTerm(Terminal_t *term, char ch)
{
error_t retcode;
if (term == NULL) return EINVAL;
KalAssert(term->initDone == INITOK);
AquireLock(&term->lock);
retcode = term->PutOnTermUnlocked(term, ch);
ReleaseLock(&term->lock);
return retcode;
}
//
// Print string on terminal
//
error_t PrintOnTerm(Terminal_t *term, const char *str)
{
error_t retcode = EOK;
if (term == NULL) return EINVAL;
KalAssert(term->initDone == INITOK);
AquireLock(&term->lock);
while (*str && retcode == EOK) {
retcode = term->PutOnTermUnlocked(term, *str++);
}
ReleaseLock(&term->lock);
return retcode;
}
//----------------------------------------------------------//
// Internal functions for VGA terminals //
// These DO NOT check input correctness //
//----------------------------------------------------------//
//
// VGA-related macros
//
#define VGA_ComputeColorCode(fg, bg) ((fg) | (bg) << 4)
#define VGA_ComputeOffset(term, x, y) ((y) * (term)->width + (x))
#define VGA_ComputeEntry(ch, cl) (((ushort)(ch)) | (ushort)(cl) << 8)
//
// Fill terminal with '\0'
//
error_t VGA_ClearTermUnlocked(Terminal_t *term)
{
const uchar color = VGA_ComputeColorCode(term->fgColor, term->bgColor);
const ushort filler = VGA_ComputeEntry('\0', color);
const size_t bufsize = term->width * term->height;
// Fill the buffer
memsetw((ushort *)term->data, filler, bufsize);
// XXX update cursor too
term->currentX = term->currentY = 0;
return EOK;
}
//
// Write a single character on the terminal
//
error_t VGA_PutOnTermUnlocked(Terminal_t *term, char ch)
{
uint i;
size_t prevY;
if (ch == '\r') {
term->currentX = 0;
return EOK;
}
//
// 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') {
term->currentY = term->width - 1;
}
//
// Tabulations account for "term->tabSize" spaces
//
else if (ch == '\t') {
prevY = term->currentY;
for (i = 0; i < term->tabSize; i++) {
//
// Make sure tabulations can't spread over two lines
//
if (term->currentY == prevY) {
VGA_PutOnTermUnlocked(term, ' ');
}
}
}
else {
ushort *buffer = (ushort *)term->data;
const size_t offset = VGA_ComputeOffset(term, term->currentY, term->currentY);
buffer[offset] = VGA_ComputeEntry(ch, VGA_ComputeColorCode(term->fgColor, term->bgColor));
}
//
// Did we reach the end of line?
//
if (++term->currentX == term->width) {
term->currentX = 0;
//
// Did we reach the buffer's end?
//
if (++term->currentY == term->height) {
//
// XXX scroll up
//
term->currentY = 0;
}
}
//
// Nothing can go wrong
//
return EOK;
}
//
// Print string on terminal
//
error_t VGA_PrintOnTermUnlocked(Terminal_t *term, const char *str)
{
error_t retcode = EOK;
while (*str && retcode == EOK) {
retcode = term->PutOnTermUnlocked(term, *str++);
}
return retcode;
}
//
// VGA output
//
static Terminal_t vgaTerm = {
.initDone = FALSE,
.lock = INITLOCK(KLOCK_MUTEX),
.name = "VGA Output Terminal",
.type = "VGA",
.data = (void *)0xB8000,
.width = 80,
.height = 25,
.currentX = 0,
.currentY = 0,
.tabSize = KTABSIZE,
.fgColor = KTERM_COLOR_LGREY,
.bgColor = KTERM_COLOR_BLACK,
.ClearTermUnlocked = VGA_ClearTermUnlocked,
.PutOnTermUnlocked = VGA_PutOnTermUnlocked,
.PrintOnTermUnlocked = VGA_PrintOnTermUnlocked,
};