1/*
2 * Copyright 2004-2005, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3 * Copyright 2011, Rene Gollent, rene@gollent.com. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "console.h"
9#include "video.h"
10#include "graphics.h"
11#include <Htif.h>
12#include "virtio.h"
13
14#include <SupportDefs.h>
15#include <util/kernel_cpp.h>
16#include <boot/stage2.h>
17
18#include <string.h>
19
20
21class Console : public ConsoleNode {
22public:
23		Console();
24
25		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
26			size_t bufferSize);
27		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer,
28			size_t bufferSize);
29
30		virtual void	ClearScreen();
31		virtual int32	Width();
32		virtual int32	Height();
33		virtual void	SetCursor(int32 x, int32 y);
34		virtual void	SetCursorVisible(bool visible);
35		virtual void	SetColors(int32 foreground, int32 background);
36};
37
38static uint16* sScreenBase;
39static uint32 sScreenOfsX = 0;
40static uint32 sScreenOfsY = 0;
41static uint32 sScreenWidth = 80;
42static uint32 sScreenHeight = 25;
43static uint32 sScreenOffset = 0;
44static uint16 sColor = 0x0f00;
45
46extern ConsoleNode* gConsoleNode;
47static Console sConsole;
48FILE *stdin, *stdout, *stderr;
49
50
51static const uint32 kPalette[] = {
52	0x000000,
53	0x0000aa,
54	0x00aa00,
55	0x00aaaa,
56	0xaa0000,
57	0xaa00aa,
58	0xaa5500,
59	0xaaaaaa,
60	0x555555,
61	0x5555ff,
62	0x55ff55,
63	0x55ffff,
64	0xff5555,
65	0xff55ff,
66	0xffff55,
67	0xffffff
68};
69
70
71static void
72RefreshFramebuf(int32 x0, int32 y0, int32 w, int32 h)
73{
74	for (int32 y = y0; y < y0 + h; y++)
75		for (int32 x = x0; x < x0 + w; x++) {
76			uint16 cell = sScreenBase[x + y * sScreenWidth];
77			int32 charX = sScreenOfsX + x*gFixedFont.charWidth;
78			int32 charY = sScreenOfsY + y*gFixedFont.charHeight;
79			uint32 bgColor = kPalette[cell / 0x1000 % 0x10];
80			uint32 fontColor = kPalette[cell / 0x100 % 0x10];
81			Clear(gFramebuf.Clip(charX, charY, gFixedFont.charWidth,
82				gFixedFont.charHeight), bgColor);
83			BlitMaskRgb(gFramebuf, gFixedFont.ThisGlyph(cell % 0x100),
84				charX, charY, fontColor);
85		}
86}
87
88
89static void
90scroll_up()
91{
92	memcpy(sScreenBase, sScreenBase + sScreenWidth,
93		sScreenWidth * sScreenHeight * 2 - sScreenWidth * 2);
94	sScreenOffset = (sScreenHeight - 1) * sScreenWidth;
95
96	for (uint32 i = 0; i < sScreenWidth; i++)
97		sScreenBase[sScreenOffset + i] = sColor | ' ';
98}
99
100
101//	#pragma mark -
102
103
104Console::Console()
105	: ConsoleNode()
106{
107}
108
109
110ssize_t
111Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
112{
113	// don't seek in character devices
114	// not implemented (and not yet? needed)
115	return B_ERROR;
116}
117
118
119ssize_t
120Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer,
121		size_t bufferSize)
122{
123	const char *string = (const char *)buffer;
124
125	if (gKernelArgs.frame_buffer.enabled)
126		return bufferSize;
127
128	for (uint32 i = 0; i < bufferSize; i++) {
129		if (string[0] == '\n') {
130			sScreenOffset += sScreenWidth - (sScreenOffset % sScreenWidth);
131		} else {
132			sScreenBase[sScreenOffset++] = sColor | string[0];
133			RefreshFramebuf((sScreenOffset - 1) % sScreenWidth,
134				(sScreenOffset - 1) / sScreenWidth, 1, 1);
135		}
136
137		if (sScreenOffset >= sScreenWidth * sScreenHeight) {
138			scroll_up();
139			RefreshFramebuf(0, 0, sScreenWidth, sScreenHeight);
140		}
141
142		string++;
143	}
144
145	return bufferSize;
146}
147
148
149void
150Console::ClearScreen()
151{
152	if (gKernelArgs.frame_buffer.enabled)
153		return;
154
155	for (uint32 i = 0; i < sScreenWidth * sScreenHeight; i++)
156		sScreenBase[i] = sColor;
157
158	// reset cursor position as well
159	sScreenOffset = 0;
160
161	RefreshFramebuf(0, 0, sScreenWidth, sScreenHeight);
162}
163
164
165int32
166Console::Width()
167{
168	return sScreenWidth;
169}
170
171
172int32
173Console::Height()
174{
175	return sScreenHeight;
176}
177
178
179void
180Console::SetCursor(int32 x, int32 y)
181{
182	if (y >= (int32)sScreenHeight)
183		y = sScreenHeight - 1;
184	else if (y < 0)
185		y = 0;
186	if (x >= (int32)sScreenWidth)
187		x = sScreenWidth - 1;
188	else if (x < 0)
189		x = 0;
190
191	sScreenOffset = x + y * sScreenWidth;
192}
193
194
195void
196Console::SetCursorVisible(bool)
197{
198	// TODO: implement
199}
200
201
202void
203Console::SetColors(int32 foreground, int32 background)
204{
205	sColor = (background & 0xf) << 12 | (foreground & 0xf) << 8;
206}
207
208
209int
210console_wait_for_key(void)
211{
212	int key = virtio_input_wait_for_key();
213
214	switch (key) {
215	case 71: return TEXT_CONSOLE_KEY_RETURN;
216	case 30: return TEXT_CONSOLE_KEY_BACKSPACE;
217	case  1: return TEXT_CONSOLE_KEY_ESCAPE;
218	case 94: return TEXT_CONSOLE_KEY_SPACE;
219
220	case 87: return TEXT_CONSOLE_KEY_UP;
221	case 98: return TEXT_CONSOLE_KEY_DOWN;
222	case 97: return TEXT_CONSOLE_KEY_LEFT;
223	case 99: return TEXT_CONSOLE_KEY_RIGHT;
224	case 33: return TEXT_CONSOLE_KEY_PAGE_UP;
225	case 54: return TEXT_CONSOLE_KEY_PAGE_DOWN;
226	case 32: return TEXT_CONSOLE_KEY_HOME;
227	case 53: return TEXT_CONSOLE_KEY_END;
228
229	default:
230		return TEXT_CONSOLE_NO_KEY;
231	}
232}
233
234
235status_t
236console_init(void)
237{
238	sScreenWidth = 80;
239	sScreenHeight = 25;
240	sScreenOfsX = gFramebuf.width/2 - sScreenWidth*gFixedFont.charWidth/2;
241	sScreenOfsY = gFramebuf.height/2 - sScreenHeight*gFixedFont.charHeight/2;
242
243	sScreenBase = new(std::nothrow) uint16[sScreenWidth * sScreenHeight];
244
245	sConsole.ClearScreen();
246
247	// enable stdio functionality
248	gConsoleNode = &sConsole;
249	stdin = (FILE *)&sConsole;
250	stdout = stderr = (FILE *)&sConsole;
251
252	return B_OK;
253}
254