//----------------------------------------------------------------------------// // GNU GPL OS/K // // // // Authors: spectral` // // NeoX // // // // Desc: Early terminal functions // //----------------------------------------------------------------------------// #include 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, };