//----------------------------------------------------------------------------// // GNU GPL OS/K // // // // Desc: VGA terminal functions // // // // // // Copyright © 2018-2019 The OS/K Team // // // // This file is part of OS/K. // // // // OS/K is free software: you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation, either version 3 of the License, or // // any later version. // // // // OS/K is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY//without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License for more details. // // // // You should have received a copy of the GNU General Public License // // along with OS/K. If not, see . // //----------------------------------------------------------------------------// #include //----------------------------------------------------------// // 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) // // Clear terminal // error_t VGA_ClearTermUnlocked(Terminal_t *term) { const uchar color = VGA_ComputeColorCode(term->fgColor, term->bgColor); const ushort filler = VGA_ComputeEntry(' ', 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->currentX = term->width - 1; } // Tabulations account for "term->tabSize" spaces else if (ch == '\t') { prevY = term->currentX; for (i = 0; i < term->tabSize; i++) { // Make sure tabulations can't spread over two lines if (term->currentX == prevY) { VGA_PutOnTermUnlocked(term, ' '); } } } else { ushort *buffer = (ushort *)term->data; const size_t offset = VGA_ComputeOffset(term, term->currentX, 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 // XXX custom sizes // Terminal_t VGA_Terminal = { .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, }; // // Initialize VGA output // void VGA_Init(void) { KalAssert(VGA_Terminal.initDone != INITOK); VGA_Terminal.initDone = INITOK; }