vmware-svga/lib/metalkit/console_vga.c

270 lines
5.9 KiB
C
Raw Permalink Normal View History

2009-04-13 02:05:42 -05:00
/* -*- Mode: C; c-basic-offset: 3 -*-
*
* console_vga.c - Console driver for VGA text mode.
*
* This file is part of Metalkit, a simple collection of modules for
* writing software that runs on the bare metal. Get the latest code
* at http://svn.navi.cx/misc/trunk/metalkit/
*
* Copyright (c) 2008-2009 Micah Dowty
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "types.h"
#include "console_vga.h"
#include "io.h"
#include "intr.h"
#define VGA_TEXT_FRAMEBUFFER ((uint8*)0xB8000)
#define VGA_CRTCREG_CURSOR_LOC_HIGH 0x0E
#define VGA_CRTCREG_CURSOR_LOC_LOW 0x0F
typedef struct {
uint16 crtc_iobase;
struct {
int8 x, y;
} cursor;
int8 attr;
} ConsoleVGAObject;
ConsoleVGAObject gConsoleVGA[1];
/*
* ConsoleVGAWriteCRTC --
*
* Write to a VGA CRT Control register.
*/
static fastcall void
ConsoleVGAWriteCRTC(uint8 addr, uint8 value)
{
ConsoleVGAObject *self = gConsoleVGA;
IO_Out8(self->crtc_iobase, addr);
IO_Out8(self->crtc_iobase + 1, value);
}
/*
* ConsoleVGAMoveHardwareCursor --
*
* Set the hardware cursor to the current cursor position.
*/
static fastcall void
ConsoleVGAMoveHardwareCursor(void)
{
ConsoleVGAObject *self = gConsoleVGA;
uint16 loc = self->cursor.x + self->cursor.y * VGA_TEXT_WIDTH;
ConsoleVGAWriteCRTC(VGA_CRTCREG_CURSOR_LOC_LOW, loc & 0xFF);
ConsoleVGAWriteCRTC(VGA_CRTCREG_CURSOR_LOC_HIGH, loc >> 8);
}
/*
* ConsoleVGAMoveTo --
*
* Set the text insertion point. This will move the hardware cursor
* at the next Console_Flush().
*/
static fastcall void
ConsoleVGAMoveTo(int x, int y)
{
ConsoleVGAObject *self = gConsoleVGA;
self->cursor.x = x;
self->cursor.y = y;
}
/*
* ConsoleVGA_Clear --
*
* Clear the screen and move the cursor to the home position.
*/
static fastcall void
ConsoleVGAClear(void)
{
ConsoleVGAObject *self = gConsoleVGA;
uint8 *fb = VGA_TEXT_FRAMEBUFFER;
int i, j;
ConsoleVGAMoveTo(0, 0);
for (j = 0; j < VGA_TEXT_HEIGHT; j++) {
for (i = 0; i < VGA_TEXT_WIDTH; i++) {
fb[0] = ' ';
fb[1] = self->attr;
fb += 2;
}
}
}
/*
* ConsoleVGA_SetColor --
*
* Set the text foreground color.
*/
fastcall void
ConsoleVGA_SetColor(int8 fgColor)
{
ConsoleVGAObject *self = gConsoleVGA;
self->attr &= 0xF0;
self->attr |= fgColor;
}
/*
* ConsoleVGA_SetColor --
*
* Set the text background color.
*/
fastcall void
ConsoleVGA_SetBgColor(int8 bgColor)
{
ConsoleVGAObject *self = gConsoleVGA;
self->attr &= 0x0F;
self->attr |= bgColor << 4;
}
/*
* ConsoleVGAWriteChar --
*
* Write one character, TTY-style. Interprets \n characters.
*/
static fastcall void
ConsoleVGAWriteChar(char c)
{
ConsoleVGAObject *self = gConsoleVGA;
uint8 *fb = VGA_TEXT_FRAMEBUFFER;
if (c == '\n') {
self->cursor.y++;
self->cursor.x = 0;
} else if (c == '\t') {
while (self->cursor.x & 7) {
ConsoleVGAWriteChar(' ');
}
} else if (c == '\b') {
if (self->cursor.x > 0) {
self->cursor.x--;
ConsoleVGAWriteChar(' ');
self->cursor.x--;
}
} else {
fb += self->cursor.x * 2 + self->cursor.y * VGA_TEXT_WIDTH * 2;
fb[0] = c;
fb[1] = self->attr;
self->cursor.x++;
}
if (self->cursor.x >= VGA_TEXT_WIDTH) {
self->cursor.x = 0;
self->cursor.y++;
}
if (self->cursor.y >= VGA_TEXT_HEIGHT) {
int i;
uint8 *fb = VGA_TEXT_FRAMEBUFFER;
const uint32 scrollSize = VGA_TEXT_WIDTH * 2 * (VGA_TEXT_HEIGHT - 1);
self->cursor.y = VGA_TEXT_HEIGHT - 1;
memcpy(fb, fb + VGA_TEXT_WIDTH * 2, scrollSize);
fb += scrollSize;
for (i = 0; i < VGA_TEXT_WIDTH; i++) {
fb[0] = ' ';
fb[1] = self->attr;
fb += 2;
}
}
}
/*
* ConsoleVGABeginPanic --
*
* Prepare for a panic in VGA mode: Set up the panic colors,
* and clear the screen.
*/
static fastcall void
ConsoleVGABeginPanic(void)
{
ConsoleVGA_SetColor(VGA_COLOR_WHITE);
ConsoleVGA_SetBgColor(VGA_COLOR_RED);
ConsoleVGAClear();
ConsoleVGAMoveHardwareCursor();
}
/*
* ConsoleVGA_Init --
*
* Perform first-time initialization for VGA text mode,
* set VGA as the current console driver, and clear the
* screen with a default color.
*/
fastcall void
ConsoleVGA_Init(void)
{
ConsoleVGAObject *self = gConsoleVGA;
/*
* Read the I/O address select bit, to determine where the CRTC
* registers are.
*/
if (IO_In8(0x3CC) & 1) {
self->crtc_iobase = 0x3D4;
} else {
self->crtc_iobase = 0x3B4;
}
gConsole.beginPanic = ConsoleVGABeginPanic;
gConsole.clear = ConsoleVGAClear;
gConsole.moveTo = ConsoleVGAMoveTo;
gConsole.writeChar = ConsoleVGAWriteChar;
gConsole.flush = ConsoleVGAMoveHardwareCursor;
ConsoleVGA_SetColor(VGA_COLOR_WHITE);
ConsoleVGA_SetBgColor(VGA_COLOR_BLUE);
ConsoleVGAClear();
ConsoleVGAMoveHardwareCursor();
}