#include "console.h"
#include "video.h"
#include "graphics.h"
#include <Htif.h>
#include "virtio.h"
#include <SupportDefs.h>
#include <util/kernel_cpp.h>
#include <boot/stage2.h>
#include <string.h>
class Console : public ConsoleNode {
public:
Console();
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
size_t bufferSize);
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer,
size_t bufferSize);
virtual void ClearScreen();
virtual int32 Width();
virtual int32 Height();
virtual void SetCursor(int32 x, int32 y);
virtual void SetCursorVisible(bool visible);
virtual void SetColors(int32 foreground, int32 background);
};
static uint16* sScreenBase;
static uint32 sScreenOfsX = 0;
static uint32 sScreenOfsY = 0;
static uint32 sScreenWidth = 80;
static uint32 sScreenHeight = 25;
static uint32 sScreenOffset = 0;
static uint16 sColor = 0x0f00;
extern ConsoleNode* gConsoleNode;
static Console sConsole;
FILE *stdin, *stdout, *stderr;
static const uint32 kPalette[] = {
0x000000,
0x0000aa,
0x00aa00,
0x00aaaa,
0xaa0000,
0xaa00aa,
0xaa5500,
0xaaaaaa,
0x555555,
0x5555ff,
0x55ff55,
0x55ffff,
0xff5555,
0xff55ff,
0xffff55,
0xffffff
};
static void
RefreshFramebuf(int32 x0, int32 y0, int32 w, int32 h)
{
for (int32 y = y0; y < y0 + h; y++)
for (int32 x = x0; x < x0 + w; x++) {
uint16 cell = sScreenBase[x + y * sScreenWidth];
int32 charX = sScreenOfsX + x*gFixedFont.charWidth;
int32 charY = sScreenOfsY + y*gFixedFont.charHeight;
uint32 bgColor = kPalette[cell / 0x1000 % 0x10];
uint32 fontColor = kPalette[cell / 0x100 % 0x10];
Clear(gFramebuf.Clip(charX, charY, gFixedFont.charWidth,
gFixedFont.charHeight), bgColor);
BlitMaskRgb(gFramebuf, gFixedFont.ThisGlyph(cell % 0x100),
charX, charY, fontColor);
}
}
static void
scroll_up()
{
memcpy(sScreenBase, sScreenBase + sScreenWidth,
sScreenWidth * sScreenHeight * 2 - sScreenWidth * 2);
sScreenOffset = (sScreenHeight - 1) * sScreenWidth;
for (uint32 i = 0; i < sScreenWidth; i++)
sScreenBase[sScreenOffset + i] = sColor | ' ';
}
Console::Console()
: ConsoleNode()
{
}
ssize_t
Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
{
return B_ERROR;
}
ssize_t
Console::WriteAt(void *cookie, off_t , const void *buffer,
size_t bufferSize)
{
const char *string = (const char *)buffer;
if (gKernelArgs.frame_buffer.enabled)
return bufferSize;
for (uint32 i = 0; i < bufferSize; i++) {
if (string[0] == '\n') {
sScreenOffset += sScreenWidth - (sScreenOffset % sScreenWidth);
} else {
sScreenBase[sScreenOffset++] = sColor | string[0];
RefreshFramebuf((sScreenOffset - 1) % sScreenWidth,
(sScreenOffset - 1) / sScreenWidth, 1, 1);
}
if (sScreenOffset >= sScreenWidth * sScreenHeight) {
scroll_up();
RefreshFramebuf(0, 0, sScreenWidth, sScreenHeight);
}
string++;
}
return bufferSize;
}
void
Console::ClearScreen()
{
if (gKernelArgs.frame_buffer.enabled)
return;
for (uint32 i = 0; i < sScreenWidth * sScreenHeight; i++)
sScreenBase[i] = sColor;
sScreenOffset = 0;
RefreshFramebuf(0, 0, sScreenWidth, sScreenHeight);
}
int32
Console::Width()
{
return sScreenWidth;
}
int32
Console::Height()
{
return sScreenHeight;
}
void
Console::SetCursor(int32 x, int32 y)
{
if (y >= (int32)sScreenHeight)
y = sScreenHeight - 1;
else if (y < 0)
y = 0;
if (x >= (int32)sScreenWidth)
x = sScreenWidth - 1;
else if (x < 0)
x = 0;
sScreenOffset = x + y * sScreenWidth;
}
void
Console::SetCursorVisible(bool)
{
}
void
Console::SetColors(int32 foreground, int32 background)
{
sColor = (background & 0xf) << 12 | (foreground & 0xf) << 8;
}
int
console_wait_for_key(void)
{
int key = virtio_input_wait_for_key();
switch (key) {
case 71: return TEXT_CONSOLE_KEY_RETURN;
case 30: return TEXT_CONSOLE_KEY_BACKSPACE;
case 1: return TEXT_CONSOLE_KEY_ESCAPE;
case 94: return TEXT_CONSOLE_KEY_SPACE;
case 87: return TEXT_CONSOLE_KEY_UP;
case 98: return TEXT_CONSOLE_KEY_DOWN;
case 97: return TEXT_CONSOLE_KEY_LEFT;
case 99: return TEXT_CONSOLE_KEY_RIGHT;
case 33: return TEXT_CONSOLE_KEY_PAGE_UP;
case 54: return TEXT_CONSOLE_KEY_PAGE_DOWN;
case 32: return TEXT_CONSOLE_KEY_HOME;
case 53: return TEXT_CONSOLE_KEY_END;
default:
return TEXT_CONSOLE_NO_KEY;
}
}
status_t
console_init(void)
{
sScreenWidth = 80;
sScreenHeight = 25;
sScreenOfsX = gFramebuf.width/2 - sScreenWidth*gFixedFont.charWidth/2;
sScreenOfsY = gFramebuf.height/2 - sScreenHeight*gFixedFont.charHeight/2;
sScreenBase = new(std::nothrow) uint16[sScreenWidth * sScreenHeight];
sConsole.ClearScreen();
gConsoleNode = &sConsole;
stdin = (FILE *)&sConsole;
stdout = stderr = (FILE *)&sConsole;
return B_OK;
}