1f33c8020SAxel Dörfler /*
246af4e77SAxel Dörfler * Copyright 2005-2010, Axel Dörfler, axeld@pinc-software.de.
3f33c8020SAxel Dörfler * Distributed under the terms of the MIT License.
446af4e77SAxel Dörfler *
546af4e77SAxel Dörfler * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
646af4e77SAxel Dörfler * Distributed under the terms of the NewOS License.
7f33c8020SAxel Dörfler */
8f33c8020SAxel Dörfler
9f33c8020SAxel Dörfler
10f33c8020SAxel Dörfler #include "blue_screen.h"
11f33c8020SAxel Dörfler
1267f20716SAxel Dörfler #include <KernelExport.h>
13f33c8020SAxel Dörfler #include <console.h>
146eba0636SMichael Lotz #include <debug.h>
15f33c8020SAxel Dörfler #include <arch/debug_console.h>
16e7d7b1e2SRene Gollent #include <safemode.h>
17f33c8020SAxel Dörfler
18f33c8020SAxel Dörfler #include <string.h>
19f33c8020SAxel Dörfler #include <stdio.h>
20f33c8020SAxel Dörfler
21855ab2b3SAxel Dörfler #include "debug_commands.h"
22855ab2b3SAxel Dörfler
23f33c8020SAxel Dörfler
24f33c8020SAxel Dörfler #define USE_SCROLLING 0
25f33c8020SAxel Dörfler #define NO_CLEAR 1
26f33c8020SAxel Dörfler
2767f20716SAxel Dörfler #define MAX_ARGS 8
2867f20716SAxel Dörfler
2967f20716SAxel Dörfler #define FMASK 0x0f
3067f20716SAxel Dörfler #define BMASK 0x70
3167f20716SAxel Dörfler
3267f20716SAxel Dörfler typedef enum {
3367f20716SAxel Dörfler CONSOLE_STATE_NORMAL = 0,
3467f20716SAxel Dörfler CONSOLE_STATE_GOT_ESCAPE,
3567f20716SAxel Dörfler CONSOLE_STATE_SEEN_BRACKET,
3667f20716SAxel Dörfler CONSOLE_STATE_NEW_ARG,
3767f20716SAxel Dörfler CONSOLE_STATE_PARSING_ARG,
3867f20716SAxel Dörfler } console_state;
3967f20716SAxel Dörfler
4070c3e1a4SAxel Dörfler typedef enum {
4170c3e1a4SAxel Dörfler LINE_ERASE_WHOLE,
4270c3e1a4SAxel Dörfler LINE_ERASE_LEFT,
4370c3e1a4SAxel Dörfler LINE_ERASE_RIGHT
4470c3e1a4SAxel Dörfler } erase_line_mode;
4570c3e1a4SAxel Dörfler
46f33c8020SAxel Dörfler struct screen_info {
47f33c8020SAxel Dörfler int32 columns;
48f33c8020SAxel Dörfler int32 rows;
49f33c8020SAxel Dörfler int32 x, y;
50f33c8020SAxel Dörfler uint8 attr;
5167f20716SAxel Dörfler bool bright_attr;
5267f20716SAxel Dörfler bool reverse_attr;
53855ab2b3SAxel Dörfler int32 in_command_rows;
54855ab2b3SAxel Dörfler bool paging;
55fec23a53SMichael Lotz bool paging_timeout;
5633965e02SAxel Dörfler bool boot_debug_output;
57855ab2b3SAxel Dörfler bool ignore_output;
5867f20716SAxel Dörfler
5967f20716SAxel Dörfler // state machine
6067f20716SAxel Dörfler console_state state;
6167f20716SAxel Dörfler int32 arg_count;
6267f20716SAxel Dörfler int32 args[MAX_ARGS];
63f33c8020SAxel Dörfler } sScreen;
64f33c8020SAxel Dörfler
65*f72d1684SAugustin Cavalier console_module_info *sModule = NULL;
66f33c8020SAxel Dörfler
67f33c8020SAxel Dörfler
68f33c8020SAxel Dörfler static inline void
hide_cursor(void)69f33c8020SAxel Dörfler hide_cursor(void)
70f33c8020SAxel Dörfler {
71f33c8020SAxel Dörfler sModule->move_cursor(-1, -1);
72f33c8020SAxel Dörfler }
73f33c8020SAxel Dörfler
74f33c8020SAxel Dörfler
75f33c8020SAxel Dörfler static inline void
update_cursor(int32 x,int32 y)76f33c8020SAxel Dörfler update_cursor(int32 x, int32 y)
77f33c8020SAxel Dörfler {
78f33c8020SAxel Dörfler sModule->move_cursor(x, y);
79f33c8020SAxel Dörfler }
80f33c8020SAxel Dörfler
81f33c8020SAxel Dörfler
8267f20716SAxel Dörfler static inline void
move_cursor(int32 x,int32 y)8367f20716SAxel Dörfler move_cursor(int32 x, int32 y)
8467f20716SAxel Dörfler {
8567f20716SAxel Dörfler sScreen.x = x;
8667f20716SAxel Dörfler sScreen.y = y;
8767f20716SAxel Dörfler update_cursor(x, y);
8867f20716SAxel Dörfler }
8967f20716SAxel Dörfler
9067f20716SAxel Dörfler
91f33c8020SAxel Dörfler #if USE_SCROLLING
92f33c8020SAxel Dörfler
93855ab2b3SAxel Dörfler /*! Scroll from the cursor line up to the top of the scroll region up one
94855ab2b3SAxel Dörfler line.
95855ab2b3SAxel Dörfler */
96f33c8020SAxel Dörfler static void
scroll_up(void)97f33c8020SAxel Dörfler scroll_up(void)
98f33c8020SAxel Dörfler {
99f33c8020SAxel Dörfler // move the screen up one
100f33c8020SAxel Dörfler sModule->blit(0, 1, sScreen.columns, sScreen.rows - 1, 0, 0);
101f33c8020SAxel Dörfler
102f33c8020SAxel Dörfler // clear the bottom line
103f33c8020SAxel Dörfler sModule->fill_glyph(0, 0, sScreen.columns, 1, ' ', sScreen.attr);
104f33c8020SAxel Dörfler }
105f33c8020SAxel Dörfler #endif
106f33c8020SAxel Dörfler
107f33c8020SAxel Dörfler
108f33c8020SAxel Dörfler static void
next_line(void)109f33c8020SAxel Dörfler next_line(void)
110f33c8020SAxel Dörfler {
111f937627dSIngo Weinhold bool abortCommand = false;
112f937627dSIngo Weinhold
113a39bfc19SAxel Dörfler #if USE_SCROLLING
114a39bfc19SAxel Dörfler // TODO: scrolling is usually too slow; we could probably just remove it
115a39bfc19SAxel Dörfler if (sScreen.y == sScreen.rows - 1)
116a39bfc19SAxel Dörfler scroll_up();
117a39bfc19SAxel Dörfler else
118a39bfc19SAxel Dörfler sScreen.y++;
119a39bfc19SAxel Dörfler #else
120855ab2b3SAxel Dörfler if (in_command_invocation())
121855ab2b3SAxel Dörfler sScreen.in_command_rows++;
122855ab2b3SAxel Dörfler else
123855ab2b3SAxel Dörfler sScreen.in_command_rows = 0;
124855ab2b3SAxel Dörfler
125a39bfc19SAxel Dörfler if (sScreen.paging && ((sScreen.in_command_rows > 0
126a39bfc19SAxel Dörfler && ((sScreen.in_command_rows + 3) % sScreen.rows) == 0)
127a39bfc19SAxel Dörfler || (sScreen.boot_debug_output && sScreen.y == sScreen.rows - 1))) {
128fec23a53SMichael Lotz if (sScreen.paging_timeout)
129fec23a53SMichael Lotz spin(1000 * 1000 * 3);
130fec23a53SMichael Lotz else {
131a39bfc19SAxel Dörfler // Use the paging mechanism: either, we're in the debugger, and a
132a39bfc19SAxel Dörfler // command is being executed, or we're currently showing boot debug
133a39bfc19SAxel Dörfler // output
134f937627dSIngo Weinhold const char *text = in_command_invocation()
135f937627dSIngo Weinhold ? "Press key to continue, Q to quit, S to skip output"
136bc2836bbSMichael Lotz : "Press key to continue, S to skip output, P to disable paging";
137855ab2b3SAxel Dörfler int32 length = strlen(text);
138855ab2b3SAxel Dörfler if (sScreen.x + length > sScreen.columns) {
139855ab2b3SAxel Dörfler // make sure we don't overwrite too much
140855ab2b3SAxel Dörfler text = "P";
141855ab2b3SAxel Dörfler length = 1;
142855ab2b3SAxel Dörfler }
143855ab2b3SAxel Dörfler
144855ab2b3SAxel Dörfler for (int32 i = 0; i < length; i++) {
145a39bfc19SAxel Dörfler // yellow on black (or reverse, during boot)
146855ab2b3SAxel Dörfler sModule->put_glyph(sScreen.columns - length + i, sScreen.y,
147a39bfc19SAxel Dörfler text[i], sScreen.boot_debug_output ? 0x6f : 0xf6);
148855ab2b3SAxel Dörfler }
149855ab2b3SAxel Dörfler
1506eba0636SMichael Lotz char c = kgetc();
151f937627dSIngo Weinhold if (c == 's') {
152855ab2b3SAxel Dörfler sScreen.ignore_output = true;
153bc2836bbSMichael Lotz } else if (c == 'q' && in_command_invocation()) {
154bc2836bbSMichael Lotz abortCommand = true;
15573aa393dSIngo Weinhold sScreen.ignore_output = true;
156bc2836bbSMichael Lotz } else if (c == 'p' && !in_command_invocation())
157bc2836bbSMichael Lotz sScreen.paging = false;
158fec23a53SMichael Lotz else if (c == 't' && !in_command_invocation())
159fec23a53SMichael Lotz sScreen.paging_timeout = true;
160855ab2b3SAxel Dörfler
161855ab2b3SAxel Dörfler // remove on screen text again
162855ab2b3SAxel Dörfler sModule->fill_glyph(sScreen.columns - length, sScreen.y, length,
163855ab2b3SAxel Dörfler 1, ' ', sScreen.attr);
164855ab2b3SAxel Dörfler }
165ab542128SMichael Lotz
166ab542128SMichael Lotz if (sScreen.in_command_rows > 0)
167ab542128SMichael Lotz sScreen.in_command_rows += 2;
168fec23a53SMichael Lotz }
169a39bfc19SAxel Dörfler if (sScreen.y == sScreen.rows - 1) {
170f33c8020SAxel Dörfler sScreen.y = 0;
171855ab2b3SAxel Dörfler sModule->fill_glyph(0, 0, sScreen.columns, 2, ' ', sScreen.attr);
172a39bfc19SAxel Dörfler } else
173f33c8020SAxel Dörfler sScreen.y++;
174a39bfc19SAxel Dörfler #endif
175f33c8020SAxel Dörfler
176f33c8020SAxel Dörfler #if NO_CLEAR
177855ab2b3SAxel Dörfler if (sScreen.y + 2 < sScreen.rows) {
178855ab2b3SAxel Dörfler sModule->fill_glyph(0, (sScreen.y + 2) % sScreen.rows, sScreen.columns,
179855ab2b3SAxel Dörfler 1, ' ', sScreen.attr);
180855ab2b3SAxel Dörfler }
181f33c8020SAxel Dörfler #endif
182f33c8020SAxel Dörfler sScreen.x = 0;
183f937627dSIngo Weinhold
184f937627dSIngo Weinhold if (abortCommand) {
185f937627dSIngo Weinhold abort_debugger_command();
186f937627dSIngo Weinhold // should not return
187f937627dSIngo Weinhold }
188f33c8020SAxel Dörfler }
189f33c8020SAxel Dörfler
190f33c8020SAxel Dörfler
191f33c8020SAxel Dörfler static void
erase_line(erase_line_mode mode)19270c3e1a4SAxel Dörfler erase_line(erase_line_mode mode)
19370c3e1a4SAxel Dörfler {
19470c3e1a4SAxel Dörfler switch (mode) {
19570c3e1a4SAxel Dörfler case LINE_ERASE_WHOLE:
196855ab2b3SAxel Dörfler sModule->fill_glyph(0, sScreen.y, sScreen.columns, 1, ' ',
197855ab2b3SAxel Dörfler sScreen.attr);
19870c3e1a4SAxel Dörfler break;
19970c3e1a4SAxel Dörfler case LINE_ERASE_LEFT:
200855ab2b3SAxel Dörfler sModule->fill_glyph(0, sScreen.y, sScreen.x + 1, 1, ' ',
201855ab2b3SAxel Dörfler sScreen.attr);
20270c3e1a4SAxel Dörfler break;
20370c3e1a4SAxel Dörfler case LINE_ERASE_RIGHT:
204855ab2b3SAxel Dörfler sModule->fill_glyph(sScreen.x, sScreen.y, sScreen.columns
205855ab2b3SAxel Dörfler - sScreen.x, 1, ' ', sScreen.attr);
20670c3e1a4SAxel Dörfler break;
20770c3e1a4SAxel Dörfler }
20870c3e1a4SAxel Dörfler }
20970c3e1a4SAxel Dörfler
21070c3e1a4SAxel Dörfler
21170c3e1a4SAxel Dörfler static void
back_space(void)212f33c8020SAxel Dörfler back_space(void)
213f33c8020SAxel Dörfler {
214f33c8020SAxel Dörfler if (sScreen.x <= 0)
215f33c8020SAxel Dörfler return;
216f33c8020SAxel Dörfler
217f33c8020SAxel Dörfler sScreen.x--;
218f33c8020SAxel Dörfler sModule->put_glyph(sScreen.x, sScreen.y, ' ', sScreen.attr);
219f33c8020SAxel Dörfler }
220f33c8020SAxel Dörfler
221f33c8020SAxel Dörfler
222f33c8020SAxel Dörfler static void
put_character(char c)223f33c8020SAxel Dörfler put_character(char c)
224f33c8020SAxel Dörfler {
225f33c8020SAxel Dörfler if (++sScreen.x >= sScreen.columns) {
226f33c8020SAxel Dörfler next_line();
227f33c8020SAxel Dörfler sScreen.x++;
228f33c8020SAxel Dörfler }
229f33c8020SAxel Dörfler
230f33c8020SAxel Dörfler sModule->put_glyph(sScreen.x - 1, sScreen.y, c, sScreen.attr);
231f33c8020SAxel Dörfler }
232f33c8020SAxel Dörfler
233f33c8020SAxel Dörfler
234f33c8020SAxel Dörfler static void
set_vt100_attributes(int32 * args,int32 argCount)23567f20716SAxel Dörfler set_vt100_attributes(int32 *args, int32 argCount)
23667f20716SAxel Dörfler {
23767f20716SAxel Dörfler if (argCount == 0) {
23867f20716SAxel Dörfler // that's the default (attributes off)
23967f20716SAxel Dörfler argCount++;
24067f20716SAxel Dörfler args[0] = 0;
24167f20716SAxel Dörfler }
24267f20716SAxel Dörfler
24367f20716SAxel Dörfler for (int32 i = 0; i < argCount; i++) {
24467f20716SAxel Dörfler switch (args[i]) {
24567f20716SAxel Dörfler case 0: // reset
24633965e02SAxel Dörfler sScreen.attr = sScreen.boot_debug_output ? 0xf0 : 0x0f;
24767f20716SAxel Dörfler sScreen.bright_attr = true;
24867f20716SAxel Dörfler sScreen.reverse_attr = false;
24967f20716SAxel Dörfler break;
25067f20716SAxel Dörfler case 1: // bright
25167f20716SAxel Dörfler sScreen.bright_attr = true;
25267f20716SAxel Dörfler sScreen.attr |= 0x08; // set the bright bit
25367f20716SAxel Dörfler break;
25467f20716SAxel Dörfler case 2: // dim
25567f20716SAxel Dörfler sScreen.bright_attr = false;
25667f20716SAxel Dörfler sScreen.attr &= ~0x08; // unset the bright bit
25767f20716SAxel Dörfler break;
25867f20716SAxel Dörfler case 4: // underscore we can't do
25967f20716SAxel Dörfler break;
26067f20716SAxel Dörfler case 5: // blink
26167f20716SAxel Dörfler sScreen.attr |= 0x80; // set the blink bit
26267f20716SAxel Dörfler break;
26367f20716SAxel Dörfler case 7: // reverse
26467f20716SAxel Dörfler sScreen.reverse_attr = true;
265855ab2b3SAxel Dörfler sScreen.attr = ((sScreen.attr & BMASK) >> 4)
266855ab2b3SAxel Dörfler | ((sScreen.attr & FMASK) << 4);
26767f20716SAxel Dörfler if (sScreen.bright_attr)
26867f20716SAxel Dörfler sScreen.attr |= 0x08;
26967f20716SAxel Dörfler break;
27067f20716SAxel Dörfler case 8: // hidden?
27167f20716SAxel Dörfler break;
27267f20716SAxel Dörfler
27367f20716SAxel Dörfler /* foreground colors */
274855ab2b3SAxel Dörfler case 30: // black
275855ab2b3SAxel Dörfler case 31: // red
276855ab2b3SAxel Dörfler case 32: // green
277855ab2b3SAxel Dörfler case 33: // yellow
278855ab2b3SAxel Dörfler case 34: // blue
279855ab2b3SAxel Dörfler case 35: // magenta
280855ab2b3SAxel Dörfler case 36: // cyan
281855ab2b3SAxel Dörfler case 37: // white
282855ab2b3SAxel Dörfler {
283855ab2b3SAxel Dörfler const uint8 colors[] = {0, 4, 2, 6, 1, 5, 3, 7};
284855ab2b3SAxel Dörfler sScreen.attr = (sScreen.attr & ~FMASK) | colors[args[i] - 30]
285855ab2b3SAxel Dörfler | (sScreen.bright_attr ? 0x08 : 0);
286855ab2b3SAxel Dörfler break;
287855ab2b3SAxel Dörfler }
28867f20716SAxel Dörfler
28967f20716SAxel Dörfler /* background colors */
29067f20716SAxel Dörfler case 40: sScreen.attr = (sScreen.attr & ~BMASK) | (0 << 4); break; // black
29167f20716SAxel Dörfler case 41: sScreen.attr = (sScreen.attr & ~BMASK) | (4 << 4); break; // red
29267f20716SAxel Dörfler case 42: sScreen.attr = (sScreen.attr & ~BMASK) | (2 << 4); break; // green
29367f20716SAxel Dörfler case 43: sScreen.attr = (sScreen.attr & ~BMASK) | (6 << 4); break; // yellow
29467f20716SAxel Dörfler case 44: sScreen.attr = (sScreen.attr & ~BMASK) | (1 << 4); break; // blue
29567f20716SAxel Dörfler case 45: sScreen.attr = (sScreen.attr & ~BMASK) | (5 << 4); break; // magenta
29667f20716SAxel Dörfler case 46: sScreen.attr = (sScreen.attr & ~BMASK) | (3 << 4); break; // cyan
29767f20716SAxel Dörfler case 47: sScreen.attr = (sScreen.attr & ~BMASK) | (7 << 4); break; // white
29867f20716SAxel Dörfler }
29967f20716SAxel Dörfler }
30067f20716SAxel Dörfler }
30167f20716SAxel Dörfler
30267f20716SAxel Dörfler
30367f20716SAxel Dörfler static bool
process_vt100_command(const char c,bool seenBracket,int32 * args,int32 argCount)30446af4e77SAxel Dörfler process_vt100_command(const char c, bool seenBracket, int32 *args,
30546af4e77SAxel Dörfler int32 argCount)
30667f20716SAxel Dörfler {
30767f20716SAxel Dörfler bool ret = true;
30867f20716SAxel Dörfler
30967f20716SAxel Dörfler // kprintf("process_vt100_command: c '%c', argCount %ld, arg[0] %ld, arg[1] %ld, seenBracket %d\n",
31067f20716SAxel Dörfler // c, argCount, args[0], args[1], seenBracket);
31167f20716SAxel Dörfler
31267f20716SAxel Dörfler if (seenBracket) {
31367f20716SAxel Dörfler switch (c) {
31446af4e77SAxel Dörfler case 'H': // set cursor position
31546af4e77SAxel Dörfler case 'f':
31646af4e77SAxel Dörfler {
31767f20716SAxel Dörfler int32 row = argCount > 0 ? args[0] : 1;
31867f20716SAxel Dörfler int32 col = argCount > 1 ? args[1] : 1;
31967f20716SAxel Dörfler if (row > 0)
32067f20716SAxel Dörfler row--;
32167f20716SAxel Dörfler if (col > 0)
32267f20716SAxel Dörfler col--;
32367f20716SAxel Dörfler move_cursor(col, row);
32467f20716SAxel Dörfler break;
32567f20716SAxel Dörfler }
32646af4e77SAxel Dörfler case 'A': // move up
32746af4e77SAxel Dörfler {
32846af4e77SAxel Dörfler int32 deltaY = argCount > 0 ? -args[0] : -1;
32946af4e77SAxel Dörfler if (deltaY == 0)
33046af4e77SAxel Dörfler deltaY = -1;
33146af4e77SAxel Dörfler move_cursor(sScreen.x, sScreen.y + deltaY);
33267f20716SAxel Dörfler break;
33367f20716SAxel Dörfler }
33467f20716SAxel Dörfler case 'e':
33546af4e77SAxel Dörfler case 'B': // move down
33646af4e77SAxel Dörfler {
33746af4e77SAxel Dörfler int32 deltaY = argCount > 0 ? args[0] : 1;
33846af4e77SAxel Dörfler if (deltaY == 0)
33946af4e77SAxel Dörfler deltaY = 1;
34046af4e77SAxel Dörfler move_cursor(sScreen.x, sScreen.y + deltaY);
34167f20716SAxel Dörfler break;
34267f20716SAxel Dörfler }
34346af4e77SAxel Dörfler case 'D': // move left
34446af4e77SAxel Dörfler {
34546af4e77SAxel Dörfler int32 deltaX = argCount > 0 ? -args[0] : -1;
34646af4e77SAxel Dörfler if (deltaX == 0)
34746af4e77SAxel Dörfler deltaX = -1;
34846af4e77SAxel Dörfler move_cursor(sScreen.x + deltaX, sScreen.y);
34967f20716SAxel Dörfler break;
35067f20716SAxel Dörfler }
35167f20716SAxel Dörfler case 'a':
35246af4e77SAxel Dörfler case 'C': // move right
35346af4e77SAxel Dörfler {
35446af4e77SAxel Dörfler int32 deltaX = argCount > 0 ? args[0] : 1;
35546af4e77SAxel Dörfler if (deltaX == 0)
35646af4e77SAxel Dörfler deltaX = 1;
35746af4e77SAxel Dörfler move_cursor(sScreen.x + deltaX, sScreen.y);
35867f20716SAxel Dörfler break;
35967f20716SAxel Dörfler }
36067f20716SAxel Dörfler case '`':
36146af4e77SAxel Dörfler case 'G': // set X position
36246af4e77SAxel Dörfler {
36346af4e77SAxel Dörfler int32 newX = argCount > 0 ? args[0] : 1;
36446af4e77SAxel Dörfler if (newX > 0)
36546af4e77SAxel Dörfler newX--;
36646af4e77SAxel Dörfler move_cursor(newX, sScreen.y);
36767f20716SAxel Dörfler break;
36867f20716SAxel Dörfler }
36946af4e77SAxel Dörfler case 'd': // set y position
37046af4e77SAxel Dörfler {
37146af4e77SAxel Dörfler int32 newY = argCount > 0 ? args[0] : 1;
37246af4e77SAxel Dörfler if (newY > 0)
37346af4e77SAxel Dörfler newY--;
37446af4e77SAxel Dörfler move_cursor(sScreen.x, newY);
37567f20716SAxel Dörfler break;
37667f20716SAxel Dörfler }
37767f20716SAxel Dörfler #if 0
37846af4e77SAxel Dörfler case 's': // save current cursor
37967f20716SAxel Dörfler save_cur(console, false);
38067f20716SAxel Dörfler break;
38146af4e77SAxel Dörfler case 'u': // restore cursor
38267f20716SAxel Dörfler restore_cur(console, false);
38367f20716SAxel Dörfler break;
38446af4e77SAxel Dörfler case 'r': // set scroll region
38546af4e77SAxel Dörfler {
38667f20716SAxel Dörfler int32 low = argCount > 0 ? args[0] : 1;
38767f20716SAxel Dörfler int32 high = argCount > 1 ? args[1] : sScreen.lines;
38867f20716SAxel Dörfler if (low <= high)
38967f20716SAxel Dörfler set_scroll_region(console, low - 1, high - 1);
39067f20716SAxel Dörfler break;
39167f20716SAxel Dörfler }
39246af4e77SAxel Dörfler case 'L': // scroll virtual down at cursor
39346af4e77SAxel Dörfler {
39467f20716SAxel Dörfler int32 lines = argCount > 0 ? args[0] : 1;
39567f20716SAxel Dörfler while (lines > 0) {
39667f20716SAxel Dörfler scrdown(console);
39767f20716SAxel Dörfler lines--;
39867f20716SAxel Dörfler }
39967f20716SAxel Dörfler break;
40067f20716SAxel Dörfler }
40146af4e77SAxel Dörfler case 'M': // scroll virtual up at cursor
40246af4e77SAxel Dörfler {
40367f20716SAxel Dörfler int32 lines = argCount > 0 ? args[0] : 1;
40467f20716SAxel Dörfler while (lines > 0) {
40567f20716SAxel Dörfler scrup(console);
40667f20716SAxel Dörfler lines--;
40767f20716SAxel Dörfler }
40867f20716SAxel Dörfler break;
40967f20716SAxel Dörfler }
41070c3e1a4SAxel Dörfler #endif
41167f20716SAxel Dörfler case 'K':
41267f20716SAxel Dörfler if (argCount == 0 || args[0] == 0) {
41367f20716SAxel Dörfler // erase to end of line
41470c3e1a4SAxel Dörfler erase_line(LINE_ERASE_RIGHT);
41567f20716SAxel Dörfler } else if (argCount > 0) {
41667f20716SAxel Dörfler if (args[0] == 1)
41770c3e1a4SAxel Dörfler erase_line(LINE_ERASE_LEFT);
41867f20716SAxel Dörfler else if (args[0] == 2)
41970c3e1a4SAxel Dörfler erase_line(LINE_ERASE_WHOLE);
42067f20716SAxel Dörfler }
42167f20716SAxel Dörfler break;
42270c3e1a4SAxel Dörfler #if 0
42367f20716SAxel Dörfler case 'J':
42467f20716SAxel Dörfler if (argCount == 0 || args[0] == 0) {
42567f20716SAxel Dörfler // erase to end of screen
42667f20716SAxel Dörfler erase_screen(console, SCREEN_ERASE_DOWN);
42767f20716SAxel Dörfler } else {
42867f20716SAxel Dörfler if (args[0] == 1)
42967f20716SAxel Dörfler erase_screen(console, SCREEN_ERASE_UP);
43067f20716SAxel Dörfler else if (args[0] == 2)
43167f20716SAxel Dörfler erase_screen(console, SCREEN_ERASE_WHOLE);
43267f20716SAxel Dörfler }
43367f20716SAxel Dörfler break;
43467f20716SAxel Dörfler #endif
43567f20716SAxel Dörfler case 'm':
43667f20716SAxel Dörfler if (argCount >= 0)
43767f20716SAxel Dörfler set_vt100_attributes(args, argCount);
43867f20716SAxel Dörfler break;
43967f20716SAxel Dörfler default:
44067f20716SAxel Dörfler ret = false;
44167f20716SAxel Dörfler }
44267f20716SAxel Dörfler } else {
44367f20716SAxel Dörfler switch (c) {
44467f20716SAxel Dörfler #if 0
44567f20716SAxel Dörfler case 'c':
44667f20716SAxel Dörfler reset_console(console);
44767f20716SAxel Dörfler break;
44867f20716SAxel Dörfler case 'D':
44967f20716SAxel Dörfler rlf(console);
45067f20716SAxel Dörfler break;
45167f20716SAxel Dörfler case 'M':
45267f20716SAxel Dörfler lf(console);
45367f20716SAxel Dörfler break;
45467f20716SAxel Dörfler case '7':
45567f20716SAxel Dörfler save_cur(console, true);
45667f20716SAxel Dörfler break;
45767f20716SAxel Dörfler case '8':
45867f20716SAxel Dörfler restore_cur(console, true);
45967f20716SAxel Dörfler break;
46067f20716SAxel Dörfler #endif
46167f20716SAxel Dörfler default:
46267f20716SAxel Dörfler ret = false;
46367f20716SAxel Dörfler }
46467f20716SAxel Dörfler }
46567f20716SAxel Dörfler
46667f20716SAxel Dörfler return ret;
46767f20716SAxel Dörfler }
46867f20716SAxel Dörfler
46967f20716SAxel Dörfler
47067f20716SAxel Dörfler static void
parse_character(char c)471f33c8020SAxel Dörfler parse_character(char c)
472f33c8020SAxel Dörfler {
47367f20716SAxel Dörfler switch (sScreen.state) {
47467f20716SAxel Dörfler case CONSOLE_STATE_NORMAL:
475f33c8020SAxel Dörfler // just output the stuff
476f33c8020SAxel Dörfler switch (c) {
477f33c8020SAxel Dörfler case '\n':
478f33c8020SAxel Dörfler next_line();
479f33c8020SAxel Dörfler break;
480f33c8020SAxel Dörfler case 0x8:
481f33c8020SAxel Dörfler back_space();
482f33c8020SAxel Dörfler break;
483f33c8020SAxel Dörfler case '\t':
48446af4e77SAxel Dörfler // TODO: real tab...
485f31dc4ddSAxel Dörfler sScreen.x = (sScreen.x + 8) & ~7;
486f31dc4ddSAxel Dörfler if (sScreen.x >= sScreen.columns)
487f31dc4ddSAxel Dörfler next_line();
488f33c8020SAxel Dörfler break;
489f33c8020SAxel Dörfler
490f33c8020SAxel Dörfler case '\r':
491f33c8020SAxel Dörfler case '\0':
49267f20716SAxel Dörfler case '\a': // beep
493f33c8020SAxel Dörfler break;
494f33c8020SAxel Dörfler
49567f20716SAxel Dörfler case 0x1b:
49667f20716SAxel Dörfler // escape character
49746af4e77SAxel Dörfler sScreen.arg_count = 0;
49867f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_GOT_ESCAPE;
49967f20716SAxel Dörfler break;
500f33c8020SAxel Dörfler default:
501f33c8020SAxel Dörfler put_character(c);
502f33c8020SAxel Dörfler }
50367f20716SAxel Dörfler break;
50467f20716SAxel Dörfler case CONSOLE_STATE_GOT_ESCAPE:
50567f20716SAxel Dörfler // look for either commands with no argument, or the '[' character
50667f20716SAxel Dörfler switch (c) {
50767f20716SAxel Dörfler case '[':
50867f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_SEEN_BRACKET;
50967f20716SAxel Dörfler break;
51067f20716SAxel Dörfler default:
51146af4e77SAxel Dörfler sScreen.args[0] = 0;
51246af4e77SAxel Dörfler process_vt100_command(c, false, sScreen.args, 0);
51367f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_NORMAL;
51467f20716SAxel Dörfler }
51567f20716SAxel Dörfler break;
51667f20716SAxel Dörfler case CONSOLE_STATE_SEEN_BRACKET:
51767f20716SAxel Dörfler switch (c) {
51867f20716SAxel Dörfler case '0'...'9':
51967f20716SAxel Dörfler sScreen.arg_count = 0;
52046af4e77SAxel Dörfler sScreen.args[0] = c - '0';
52167f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_PARSING_ARG;
52267f20716SAxel Dörfler break;
52367f20716SAxel Dörfler case '?':
524855ab2b3SAxel Dörfler // private DEC mode parameter follows - we ignore those
525855ab2b3SAxel Dörfler // anyway
52667f20716SAxel Dörfler break;
52767f20716SAxel Dörfler default:
52838eb09a3SIngo Weinhold process_vt100_command(c, true, sScreen.args, 0);
52967f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_NORMAL;
53046af4e77SAxel Dörfler break;
53167f20716SAxel Dörfler }
53267f20716SAxel Dörfler break;
53367f20716SAxel Dörfler case CONSOLE_STATE_NEW_ARG:
53467f20716SAxel Dörfler switch (c) {
53567f20716SAxel Dörfler case '0'...'9':
53646af4e77SAxel Dörfler if (++sScreen.arg_count == MAX_ARGS) {
53767f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_NORMAL;
53867f20716SAxel Dörfler break;
53967f20716SAxel Dörfler }
54067f20716SAxel Dörfler sScreen.args[sScreen.arg_count] = c - '0';
54167f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_PARSING_ARG;
54267f20716SAxel Dörfler break;
54367f20716SAxel Dörfler default:
544855ab2b3SAxel Dörfler process_vt100_command(c, true, sScreen.args,
545855ab2b3SAxel Dörfler sScreen.arg_count + 1);
54667f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_NORMAL;
54746af4e77SAxel Dörfler break;
54867f20716SAxel Dörfler }
54967f20716SAxel Dörfler break;
55067f20716SAxel Dörfler case CONSOLE_STATE_PARSING_ARG:
55167f20716SAxel Dörfler // parse args
55267f20716SAxel Dörfler switch (c) {
55367f20716SAxel Dörfler case '0'...'9':
55467f20716SAxel Dörfler sScreen.args[sScreen.arg_count] *= 10;
55567f20716SAxel Dörfler sScreen.args[sScreen.arg_count] += c - '0';
55667f20716SAxel Dörfler break;
55767f20716SAxel Dörfler case ';':
55867f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_NEW_ARG;
55967f20716SAxel Dörfler break;
56067f20716SAxel Dörfler default:
561855ab2b3SAxel Dörfler process_vt100_command(c, true, sScreen.args,
562855ab2b3SAxel Dörfler sScreen.arg_count + 1);
56367f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_NORMAL;
56446af4e77SAxel Dörfler break;
56567f20716SAxel Dörfler }
56667f20716SAxel Dörfler }
567f33c8020SAxel Dörfler }
568f33c8020SAxel Dörfler
569f33c8020SAxel Dörfler
570855ab2b3SAxel Dörfler static int
set_paging(int argc,char ** argv)571855ab2b3SAxel Dörfler set_paging(int argc, char **argv)
572855ab2b3SAxel Dörfler {
573855ab2b3SAxel Dörfler if (argc > 1 && !strcmp(argv[1], "--help")) {
574855ab2b3SAxel Dörfler kprintf("usage: %s [on|off]\n", argv[0]);
575855ab2b3SAxel Dörfler return 0;
576855ab2b3SAxel Dörfler }
577855ab2b3SAxel Dörfler
578855ab2b3SAxel Dörfler if (argc == 1)
579855ab2b3SAxel Dörfler sScreen.paging = !sScreen.paging;
580855ab2b3SAxel Dörfler else if (!strcmp(argv[1], "on"))
581855ab2b3SAxel Dörfler sScreen.paging = true;
582855ab2b3SAxel Dörfler else if (!strcmp(argv[1], "off"))
583855ab2b3SAxel Dörfler sScreen.paging = false;
584855ab2b3SAxel Dörfler else
585855ab2b3SAxel Dörfler sScreen.paging = parse_expression(argv[1]) != 0;
586855ab2b3SAxel Dörfler
587855ab2b3SAxel Dörfler kprintf("paging is turned %s now.\n", sScreen.paging ? "on" : "off");
588855ab2b3SAxel Dörfler return 0;
589855ab2b3SAxel Dörfler }
590855ab2b3SAxel Dörfler
591855ab2b3SAxel Dörfler
592f33c8020SAxel Dörfler // #pragma mark -
593f33c8020SAxel Dörfler
594f33c8020SAxel Dörfler
595f33c8020SAxel Dörfler status_t
blue_screen_init_early()596*f72d1684SAugustin Cavalier blue_screen_init_early()
597f33c8020SAxel Dörfler {
598f33c8020SAxel Dörfler // we can't use get_module() here, since it's too early in the boot process
599*f72d1684SAugustin Cavalier extern console_module_info gFrameBufferConsoleModule;
600f33c8020SAxel Dörfler sModule = &gFrameBufferConsoleModule;
601*f72d1684SAugustin Cavalier
602*f72d1684SAugustin Cavalier if (sModule->info.std_ops(B_MODULE_INIT) != B_OK) {
603*f72d1684SAugustin Cavalier sModule = NULL;
604*f72d1684SAugustin Cavalier return B_ERROR;
605*f72d1684SAugustin Cavalier }
606*f72d1684SAugustin Cavalier
607*f72d1684SAugustin Cavalier sScreen.paging = sScreen.paging_timeout = false;
608*f72d1684SAugustin Cavalier return B_OK;
609*f72d1684SAugustin Cavalier }
610*f72d1684SAugustin Cavalier
611*f72d1684SAugustin Cavalier
612*f72d1684SAugustin Cavalier status_t
blue_screen_init()613*f72d1684SAugustin Cavalier blue_screen_init()
614*f72d1684SAugustin Cavalier {
615*f72d1684SAugustin Cavalier if (sModule == NULL) {
616*f72d1684SAugustin Cavalier // Early initialization must have previously failed, or never run.
617*f72d1684SAugustin Cavalier if (blue_screen_init_early() != B_OK)
618*f72d1684SAugustin Cavalier return B_ERROR;
619*f72d1684SAugustin Cavalier }
620*f72d1684SAugustin Cavalier
621e7d7b1e2SRene Gollent sScreen.paging = !get_safemode_boolean(
622e7d7b1e2SRene Gollent "disable_onscreen_paging", false);
623fec23a53SMichael Lotz sScreen.paging_timeout = false;
624855ab2b3SAxel Dörfler
625855ab2b3SAxel Dörfler add_debugger_command("paging", set_paging, "Enable or disable paging");
626f33c8020SAxel Dörfler return B_OK;
627f33c8020SAxel Dörfler }
628f33c8020SAxel Dörfler
629f33c8020SAxel Dörfler
630173d0b2fSAxel Dörfler status_t
blue_screen_enter(bool debugOutput)63192447917SAxel Dörfler blue_screen_enter(bool debugOutput)
632f33c8020SAxel Dörfler {
63392447917SAxel Dörfler sScreen.attr = debugOutput ? 0xf0 : 0x0f;
63492447917SAxel Dörfler // black on white for KDL, white on black for debug output
63533965e02SAxel Dörfler sScreen.boot_debug_output = debugOutput;
63633965e02SAxel Dörfler sScreen.ignore_output = false;
63733965e02SAxel Dörfler
638f33c8020SAxel Dörfler sScreen.x = sScreen.y = 0;
63967f20716SAxel Dörfler sScreen.state = CONSOLE_STATE_NORMAL;
640f33c8020SAxel Dörfler
641173d0b2fSAxel Dörfler if (sModule == NULL)
642173d0b2fSAxel Dörfler return B_NO_INIT;
643173d0b2fSAxel Dörfler
644f33c8020SAxel Dörfler sModule->get_size(&sScreen.columns, &sScreen.rows);
645f33c8020SAxel Dörfler #if !NO_CLEAR
646f33c8020SAxel Dörfler sModule->clear(sScreen.attr);
647f33c8020SAxel Dörfler #else
648f33c8020SAxel Dörfler sModule->fill_glyph(0, sScreen.y, sScreen.columns, 3, ' ', sScreen.attr);
649f33c8020SAxel Dörfler #endif
650173d0b2fSAxel Dörfler return B_OK;
651f33c8020SAxel Dörfler }
652f33c8020SAxel Dörfler
653f33c8020SAxel Dörfler
654976e5259SIngo Weinhold bool
blue_screen_paging_enabled(void)655976e5259SIngo Weinhold blue_screen_paging_enabled(void)
656976e5259SIngo Weinhold {
657976e5259SIngo Weinhold return sScreen.paging;
658976e5259SIngo Weinhold }
659976e5259SIngo Weinhold
660976e5259SIngo Weinhold
661976e5259SIngo Weinhold void
blue_screen_set_paging(bool enabled)662976e5259SIngo Weinhold blue_screen_set_paging(bool enabled)
663976e5259SIngo Weinhold {
664976e5259SIngo Weinhold sScreen.paging = enabled;
665976e5259SIngo Weinhold }
666976e5259SIngo Weinhold
667976e5259SIngo Weinhold
668a1587d16SIngo Weinhold void
blue_screen_clear_screen(void)669a1587d16SIngo Weinhold blue_screen_clear_screen(void)
670a1587d16SIngo Weinhold {
671a1587d16SIngo Weinhold sModule->clear(sScreen.attr);
672a1587d16SIngo Weinhold move_cursor(0, 0);
673a1587d16SIngo Weinhold }
674a1587d16SIngo Weinhold
675a1587d16SIngo Weinhold
6768bcc50c3SIngo Weinhold int
blue_screen_try_getchar(void)6778bcc50c3SIngo Weinhold blue_screen_try_getchar(void)
6788bcc50c3SIngo Weinhold {
6798bcc50c3SIngo Weinhold return arch_debug_blue_screen_try_getchar();
6808bcc50c3SIngo Weinhold }
6818bcc50c3SIngo Weinhold
6828bcc50c3SIngo Weinhold
683f33c8020SAxel Dörfler char
blue_screen_getchar(void)684f33c8020SAxel Dörfler blue_screen_getchar(void)
685f33c8020SAxel Dörfler {
686f33c8020SAxel Dörfler return arch_debug_blue_screen_getchar();
687f33c8020SAxel Dörfler }
688f33c8020SAxel Dörfler
689f33c8020SAxel Dörfler
690f33c8020SAxel Dörfler void
blue_screen_putchar(char c)691f33c8020SAxel Dörfler blue_screen_putchar(char c)
692f33c8020SAxel Dörfler {
69333965e02SAxel Dörfler if (sScreen.ignore_output
69433965e02SAxel Dörfler && (in_command_invocation() || sScreen.boot_debug_output))
695855ab2b3SAxel Dörfler return;
696855ab2b3SAxel Dörfler
697855ab2b3SAxel Dörfler sScreen.ignore_output = false;
698f33c8020SAxel Dörfler hide_cursor();
699f33c8020SAxel Dörfler
700f33c8020SAxel Dörfler parse_character(c);
701f33c8020SAxel Dörfler
702f33c8020SAxel Dörfler update_cursor(sScreen.x, sScreen.y);
703f33c8020SAxel Dörfler }
704f33c8020SAxel Dörfler
705f33c8020SAxel Dörfler
706f33c8020SAxel Dörfler void
blue_screen_puts(const char * text)707f33c8020SAxel Dörfler blue_screen_puts(const char *text)
708f33c8020SAxel Dörfler {
70933965e02SAxel Dörfler if (sScreen.ignore_output
71033965e02SAxel Dörfler && (in_command_invocation() || sScreen.boot_debug_output))
711855ab2b3SAxel Dörfler return;
712855ab2b3SAxel Dörfler
713855ab2b3SAxel Dörfler sScreen.ignore_output = false;
714f33c8020SAxel Dörfler hide_cursor();
715f33c8020SAxel Dörfler
716f33c8020SAxel Dörfler while (text[0] != '\0') {
717f33c8020SAxel Dörfler parse_character(text[0]);
718f33c8020SAxel Dörfler text++;
719f33c8020SAxel Dörfler }
720f33c8020SAxel Dörfler
721f33c8020SAxel Dörfler update_cursor(sScreen.x, sScreen.y);
722f33c8020SAxel Dörfler }
723