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 "keyboard.h"
10#include "video.h"
11
12#include <SupportDefs.h>
13#include <util/kernel_cpp.h>
14#include <boot/stage2.h>
15
16#include <string.h>
17
18
19class Console : public ConsoleNode {
20	public:
21		Console();
22
23		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
24		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
25
26		virtual void	ClearScreen();
27		virtual int32	Width();
28		virtual int32	Height();
29		virtual void	SetCursor(int32 x, int32 y);
30		virtual void	SetCursorVisible(bool visible);
31		virtual void	SetColors(int32 foreground, int32 background);
32};
33
34static uint16 *sScreenBase = (uint16 *)0xb8000;
35static uint32 sScreenWidth = 80;
36static uint32 sScreenHeight = 25;
37static uint32 sScreenOffset = 0;
38static uint16 sColor = 0x0f00;
39
40extern ConsoleNode* gConsoleNode;
41static Console sConsole;
42FILE *stdin, *stdout, *stderr;
43
44
45static void
46scroll_up()
47{
48	memcpy(sScreenBase, sScreenBase + sScreenWidth,
49		sScreenWidth * sScreenHeight * 2 - sScreenWidth * 2);
50	sScreenOffset = (sScreenHeight - 1) * sScreenWidth;
51
52	for (uint32 i = 0; i < sScreenWidth; i++)
53		sScreenBase[sScreenOffset + i] = sColor | ' ';
54}
55
56
57//	#pragma mark -
58
59
60Console::Console()
61	: ConsoleNode()
62{
63}
64
65
66ssize_t
67Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
68{
69	// don't seek in character devices
70	// not implemented (and not yet? needed)
71	return B_ERROR;
72}
73
74
75ssize_t
76Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, size_t bufferSize)
77{
78	const char *string = (const char *)buffer;
79
80	if (gKernelArgs.frame_buffer.enabled)
81		return bufferSize;
82
83	for (uint32 i = 0; i < bufferSize; i++) {
84		if (string[0] == '\n')
85			sScreenOffset += sScreenWidth - (sScreenOffset % sScreenWidth);
86		else
87			sScreenBase[sScreenOffset++] = sColor | string[0];
88
89		if (sScreenOffset >= sScreenWidth * sScreenHeight)
90			scroll_up();
91
92		string++;
93	}
94	return bufferSize;
95}
96
97
98void
99Console::ClearScreen()
100{
101	if (gKernelArgs.frame_buffer.enabled)
102		return;
103
104	for (uint32 i = 0; i < sScreenWidth * sScreenHeight; i++)
105		sScreenBase[i] = sColor;
106
107	// reset cursor position as well
108	sScreenOffset = 0;
109}
110
111
112int32
113Console::Width()
114{
115	return sScreenWidth;
116}
117
118
119int32
120Console::Height()
121{
122	return sScreenHeight;
123}
124
125
126void
127Console::SetCursor(int32 x, int32 y)
128{
129	if (y >= (int32)sScreenHeight)
130		y = sScreenHeight - 1;
131	else if (y < 0)
132		y = 0;
133	if (x >= (int32)sScreenWidth)
134		x = sScreenWidth - 1;
135	else if (x < 0)
136		x = 0;
137
138	sScreenOffset = x + y * sScreenWidth;
139	video_move_text_cursor(x, y);
140}
141
142
143void
144Console::SetCursorVisible(bool visible)
145{
146	if (visible)
147		video_show_text_cursor();
148	else
149		video_hide_text_cursor();
150}
151
152
153void
154Console::SetColors(int32 foreground, int32 background)
155{
156	sColor = (background & 0xf) << 12 | (foreground & 0xf) << 8;
157}
158
159
160int
161console_wait_for_key(void)
162{
163	union key key = wait_for_key();
164
165	if (key.code.ascii == 0) {
166		switch (key.code.bios) {
167			case BIOS_KEY_UP:
168				return TEXT_CONSOLE_KEY_UP;
169			case BIOS_KEY_DOWN:
170				return TEXT_CONSOLE_KEY_DOWN;
171			case BIOS_KEY_LEFT:
172				return TEXT_CONSOLE_KEY_LEFT;
173			case BIOS_KEY_RIGHT:
174				return TEXT_CONSOLE_KEY_RIGHT;
175			case BIOS_KEY_PAGE_UP:
176				return TEXT_CONSOLE_KEY_PAGE_UP;
177			case BIOS_KEY_PAGE_DOWN:
178				return TEXT_CONSOLE_KEY_PAGE_DOWN;
179			case BIOS_KEY_HOME:
180				return TEXT_CONSOLE_KEY_HOME;
181			case BIOS_KEY_END:
182				return TEXT_CONSOLE_KEY_END;
183			default:
184				return 0;
185		}
186	} else
187		return key.code.ascii;
188}
189
190
191status_t
192console_init(void)
193{
194	// ToDo: make screen size changeable via stage2_args
195
196	gConsoleNode = &sConsole;
197
198	console_clear_screen();
199
200	// enable stdio functionality
201	stdin = (FILE *)&sConsole;
202	stdout = stderr = (FILE *)&sConsole;
203
204	return B_OK;
205}
206
207