211 lines
4.9 KiB
C
211 lines
4.9 KiB
C
//----------------------------------------------------------------------------//
|
|
// GNU GPL OS/K //
|
|
// //
|
|
// Authors: spectral` //
|
|
// NeoX //
|
|
// //
|
|
// Desc: Early terminal functions //
|
|
//----------------------------------------------------------------------------//
|
|
|
|
#define _UNLOCKED_IO
|
|
#include <kalkern/io/terminal.h>
|
|
|
|
//
|
|
// VGA-related macros
|
|
//
|
|
#define ComputeColorCode(fg, bg) ((fg) | (bg) << 4)
|
|
#define ComputeOffset(kt, x, y) ((y) * kt->kt_width + (x))
|
|
#define ComputeEntry(ch, cl) (((ushort)(ch)) | (ushort)(cl) << 8)
|
|
|
|
//
|
|
// VGA output
|
|
//
|
|
static terminal_t _vga_term = {
|
|
.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 = INITLOCK(KLOCK_MUTEX),
|
|
.kt_init = FALSE,
|
|
};
|
|
|
|
//
|
|
// Standard output terminal
|
|
//
|
|
terminal_t *stdout;
|
|
|
|
//
|
|
// Debugging terminal
|
|
//
|
|
terminal_t *stddbg;
|
|
|
|
//
|
|
// Initialize standard output
|
|
//
|
|
void InitTerms(void)
|
|
{
|
|
Assert(!stdout && _vga_term.kt_init != INITOK);
|
|
|
|
_vga_term.kt_init = INITOK;
|
|
stddbg = &_vga_term;
|
|
|
|
// to be switched to VESA
|
|
stdout = &_vga_term;
|
|
ClearTerm(stdout);
|
|
}
|
|
|
|
//
|
|
// Fill terminal with spaces
|
|
//
|
|
status_t ClearTerm(terminal_t *kt)
|
|
{
|
|
if (kt == NULL)
|
|
return BAD_ARG_NULL;
|
|
|
|
Assert(kt->kt_init == INITOK);
|
|
|
|
LockTerm(kt);
|
|
ClearTermUnlocked(kt);
|
|
UnlockTerm(kt);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Change the color code
|
|
//
|
|
status_t ChTermColor(terminal_t *kt, uchar color)
|
|
{
|
|
if (color > KTERM_COLOR_WHITE)
|
|
return BAD_ARG_RANGE;
|
|
|
|
if (kt == NULL)
|
|
return BAD_ARG_NULL;
|
|
|
|
LockTerm(kt);
|
|
kt->kt_color = color;
|
|
UnlockTerm(kt);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Write a single character on the terminal
|
|
//
|
|
status_t PutOnTerm(terminal_t *kt, char ch)
|
|
{
|
|
if (kt == NULL)
|
|
return BAD_ARG_NULL;
|
|
|
|
Assert(kt->kt_init == INITOK);
|
|
|
|
LockTerm(kt);
|
|
PutOnTermUnlocked(kt, ch);
|
|
UnlockTerm(kt);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Print string on terminal
|
|
//
|
|
status_t PrintOnTerm(terminal_t *kt, const char *str)
|
|
{
|
|
if (kt == NULL)
|
|
return BAD_ARG_NULL;
|
|
|
|
Assert(kt->kt_init == INITOK);
|
|
|
|
LockTerm(kt);
|
|
while (*str) {
|
|
PutOnTermUnlocked(kt, *str++);
|
|
}
|
|
UnlockTerm(kt);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
//----------------------------------------------------------//
|
|
// UNLOCKED VERSIONS //
|
|
// //
|
|
// Direct use is highly deprecated //
|
|
// Useful in rare instances //
|
|
//----------------------------------------------------------//
|
|
|
|
//
|
|
// Fill terminal with spaces (UNLOCKED version)
|
|
// XXX would '\0' work too?
|
|
//
|
|
void ClearTermUnlocked(terminal_t *kt)
|
|
{
|
|
size_t i;
|
|
|
|
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 memsetw()
|
|
kt->kt_buffer[i] = filler;
|
|
}
|
|
|
|
kt->kt_curr_x = kt->kt_curr_y = 0;
|
|
}
|
|
|
|
//
|
|
// Write a single character on the terminal (UNLOCKED version)
|
|
//
|
|
void PutOnTermUnlocked(terminal_t *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 "TABSIZE" 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) {
|
|
PutOnTermUnlocked(kt, ' ');
|
|
}
|
|
}
|
|
}
|
|
|
|
else {
|
|
// actually write on the buffer
|
|
const size_t offset = ComputeOffset(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;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print string on terminal (UNLOCKED version)
|
|
//
|
|
void PrintOnTermUnlocked(terminal_t *kt, const char *str)
|
|
{
|
|
while (*str) {
|
|
PutOnTermUnlocked(kt, *str++);
|
|
}
|
|
}
|
|
|