1/*
2 * Copyright 2021, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <boot/stage2.h>
7#include <boot/platform/generic/text_console.h>
8#include <boot/platform/generic/video.h>
9
10#include <frame_buffer_console.h>
11
12
13extern console_module_info gFrameBufferConsoleModule;
14
15
16class VideoTextConsole : public ConsoleNode {
17	public:
18		VideoTextConsole(addr_t framebuffer);
19
20		virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
21			size_t bufferSize);
22		virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer,
23			size_t bufferSize);
24
25		virtual void	ClearScreen();
26		virtual int32	Width();
27		virtual int32	Height();
28		virtual void	SetCursor(int32 x, int32 y);
29		virtual void	SetCursorVisible(bool visible);
30		virtual void	SetColors(int32 foreground, int32 background);
31
32	private:
33		uint16 fColor = 0x0f00;
34		bool fShowCursor;
35		int32 fCursorX, fCursorY;
36		int32 fScreenWidth, fScreenHeight;
37};
38
39
40//	#pragma mark -
41
42
43VideoTextConsole::VideoTextConsole(addr_t framebuffer)
44	: ConsoleNode()
45{
46	frame_buffer_update(framebuffer, gKernelArgs.frame_buffer.width,
47		gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth,
48		gKernelArgs.frame_buffer.bytes_per_row);
49	gFrameBufferConsoleModule.get_size(&fScreenWidth, &fScreenHeight);
50
51	SetCursorVisible(false);
52	ClearScreen();
53}
54
55
56ssize_t
57VideoTextConsole::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
58{
59	return B_ERROR;
60}
61
62
63ssize_t
64VideoTextConsole::WriteAt(void *cookie, off_t /*pos*/, const void *buffer,
65	size_t bufferSize)
66{
67	const char *string = (const char *)buffer;
68	for (size_t i = 0; i < bufferSize; i++) {
69		const char c = string[i];
70		if (c == '\n' || fCursorX >= fScreenWidth) {
71			fCursorX = 0;
72			if (fCursorY == (fScreenHeight - 1)) {
73				// Move the screen up and clear the bottom line.
74				gFrameBufferConsoleModule.blit(0, 1, fScreenWidth, 0,
75					0, fScreenHeight - 1);
76				gFrameBufferConsoleModule.fill_glyph(0, fCursorY, fScreenWidth,
77					1, ' ', fColor);
78			} else {
79				fCursorY++;
80			}
81		}
82
83		switch (c) {
84			case '\n':
85				// already handled above
86				break;
87
88			default:
89				gFrameBufferConsoleModule.put_glyph(fCursorX, fCursorY, c, fColor);
90				break;
91		}
92		fCursorX++;
93	}
94	return bufferSize;
95}
96
97
98void
99VideoTextConsole::ClearScreen()
100{
101	gFrameBufferConsoleModule.clear(fColor);
102}
103
104
105int32
106VideoTextConsole::Width()
107{
108	return fScreenWidth;
109}
110
111
112int32
113VideoTextConsole::Height()
114{
115	return fScreenHeight;
116}
117
118
119void
120VideoTextConsole::SetCursor(int32 x, int32 y)
121{
122	fCursorX = x;
123	fCursorY = y;
124	if (fShowCursor)
125		SetCursorVisible(true);
126}
127
128
129void
130VideoTextConsole::SetCursorVisible(bool visible)
131{
132	fShowCursor = visible;
133	if (fShowCursor)
134		gFrameBufferConsoleModule.move_cursor(fCursorX, fCursorY);
135	else
136		gFrameBufferConsoleModule.move_cursor(-1, -1);
137}
138
139
140void
141VideoTextConsole::SetColors(int32 foreground, int32 background)
142{
143	fColor = (background & 0xf) << 4 | (foreground & 0xf);
144}
145
146
147ConsoleNode*
148video_text_console_init(addr_t frameBuffer)
149{
150	return new VideoTextConsole(frameBuffer);
151}
152