187 lines
4.3 KiB
C
187 lines
4.3 KiB
C
//----------------------------------------------------------------------------//
|
|
// GNU GPL OS/K //
|
|
// //
|
|
// Authors: spectral` //
|
|
// NeoX //
|
|
// //
|
|
// Desc: Early terminal functions //
|
|
//----------------------------------------------------------------------------//
|
|
|
|
#include "kernel/io/terminal.h"
|
|
|
|
//
|
|
// VGA-related macros
|
|
//
|
|
#define ComputeColorCode(fg, bg) ((fg) | (bg) << 4)
|
|
#define ComputeEntryOffset(kt, x, y) ((y) * kt->kt_width + (x))
|
|
#define ComputeEntry(ch, cl) (((ushort)(ch)) | (ushort)(cl) << 8)
|
|
|
|
//
|
|
// VGA output
|
|
//
|
|
static struct kterm _kt_vga = {
|
|
.kt_buffer = (ushort *)0xB8000,
|
|
.kt_width = 80,
|
|
.kt_height = 25,
|
|
.kt_curr_x = 0,
|
|
.kt_curr_y = 0,
|
|
.kt_color = ComputeColorCode(KTERM_COLOR_LGREY, KTERM_COLOR_BLACK),
|
|
.kt_lock = NULL,
|
|
#ifndef _NO_DEBUG
|
|
.kt_init = FALSE,
|
|
#endif
|
|
};
|
|
|
|
//
|
|
// Standard output terminal
|
|
//
|
|
struct kterm *kt_stdout;
|
|
|
|
//
|
|
// Initialize standard output
|
|
//
|
|
void kterm_init(void)
|
|
{
|
|
assert(!kt_stdout && !_kt_vga.kt_init && "kterm_init() called twice");
|
|
|
|
#ifndef _NO_DEBUG
|
|
_kt_vga.kt_init = TRUE;
|
|
#endif
|
|
|
|
// to be switched to VESA
|
|
kt_stdout = &_kt_vga;
|
|
ktclear();
|
|
}
|
|
|
|
//
|
|
// Fills terminal with spaces
|
|
// XXX would '\0' work too?
|
|
//
|
|
status_t kterm_clear(struct kterm *kt)
|
|
{
|
|
size_t i;
|
|
|
|
if (kt == NULL)
|
|
return BAD_ARG_NULL;
|
|
|
|
assert(kt->kt_init && "kterm_clear called before initialization");
|
|
|
|
kterm_lock(kt);
|
|
|
|
const ushort filler = ComputeEntry(' ', kt->kt_color);
|
|
const size_t bufsize = kt->kt_width * kt->kt_height;
|
|
|
|
for (i = 0; i < bufsize; i++) {
|
|
// XXX implement memset()
|
|
kt->kt_buffer[i] = filler;
|
|
}
|
|
|
|
kt->kt_curr_x = kt->kt_curr_y = 0;
|
|
|
|
kterm_unlock(kt);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Change the color code
|
|
//
|
|
status_t kterm_change_color(struct kterm *kt, uchar color)
|
|
{
|
|
if (color > KTERM_COLOR_WHITE)
|
|
return BAD_ARG_RANGE;
|
|
|
|
if (kt == NULL)
|
|
return BAD_ARG_NULL;
|
|
|
|
kterm_lock(kt);
|
|
kt->kt_color = color;
|
|
kterm_unlock(kt);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Writes a single character on the terminal (UNLOCKED version)
|
|
//
|
|
// DEPRECATED:
|
|
// - always use kterm_putch (LOCKED version)
|
|
// - doesn't check for NULL input
|
|
//
|
|
void kterm_putch_unlocked(struct kterm *kt, char ch)
|
|
{
|
|
int i;
|
|
size_t prev_row;
|
|
|
|
// carriage return takes us back to the beginning of the line
|
|
// no further test should be necessary
|
|
if (ch == '\r') { kt->kt_curr_x = 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') { kt->kt_curr_y = kt->kt_width - 1; }
|
|
|
|
// tabulations account for 4 spaces
|
|
else if (ch == '\t') {
|
|
prev_row = kt->kt_curr_y;
|
|
// compiler will optimize this away
|
|
for (i = 0; i < TABSIZE; i++) {
|
|
// tabulations can't spread over two lines
|
|
if (kt->kt_curr_y == prev_row) {
|
|
kterm_putch_unlocked(kt, ' ');
|
|
}
|
|
}
|
|
}
|
|
|
|
// XXX check whether we were given a writable character
|
|
else {
|
|
const size_t offset = ComputeEntryOffset(kt, kt->kt_curr_x, kt->kt_curr_y);
|
|
kt->kt_buffer[offset] = ComputeEntry(ch, kt->kt_color);
|
|
}
|
|
|
|
// end of line?
|
|
if (++kt->kt_curr_x == kt->kt_width) {
|
|
kt->kt_curr_x = 0;
|
|
|
|
// line feed + end of buffer?
|
|
if (++kt->kt_curr_y == kt->kt_height) {
|
|
kt->kt_curr_y = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Writes a single character on the terminal (LOCKED version)
|
|
//
|
|
status_t kterm_putch(struct kterm *kt, char ch)
|
|
{
|
|
if (kt == NULL)
|
|
return BAD_ARG_NULL;
|
|
|
|
kterm_lock(kt);
|
|
kterm_putch_unlocked(kt, ch);
|
|
kterm_unlock(kt);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// Print string on kterminal
|
|
//
|
|
status_t kterm_print(struct kterm *kt, const char *str)
|
|
{
|
|
if (kt == NULL)
|
|
return BAD_ARG_NULL;
|
|
|
|
kterm_lock(kt);
|
|
while (*str) {
|
|
kterm_putch_unlocked(kt, *str++);
|
|
}
|
|
kterm_unlock(kt);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
|