xref: /haiku/src/system/kernel/debug/blue_screen.cpp (revision a39bfc19fd44e3c9cc853b718e9186fa082e190b)
1f33c8020SAxel Dörfler /*
2855ab2b3SAxel Dörfler  * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3f33c8020SAxel Dörfler  * Distributed under the terms of the MIT License.
4f33c8020SAxel Dörfler  */
5f33c8020SAxel Dörfler 
6f33c8020SAxel Dörfler 
7f33c8020SAxel Dörfler #include "blue_screen.h"
8f33c8020SAxel Dörfler 
967f20716SAxel Dörfler #include <KernelExport.h>
10f33c8020SAxel Dörfler #include <frame_buffer_console.h>
11f33c8020SAxel Dörfler #include <console.h>
12f33c8020SAxel Dörfler #include <arch/debug_console.h>
13f33c8020SAxel Dörfler 
14f33c8020SAxel Dörfler #include <string.h>
15f33c8020SAxel Dörfler #include <stdio.h>
16f33c8020SAxel Dörfler 
17855ab2b3SAxel Dörfler #include "debug_commands.h"
18855ab2b3SAxel Dörfler 
19f33c8020SAxel Dörfler 
20f33c8020SAxel Dörfler #define USE_SCROLLING 0
21f33c8020SAxel Dörfler #define NO_CLEAR 1
22f33c8020SAxel Dörfler 
2367f20716SAxel Dörfler #define MAX_ARGS 8
2467f20716SAxel Dörfler 
2567f20716SAxel Dörfler #define FMASK 0x0f
2667f20716SAxel Dörfler #define BMASK 0x70
2767f20716SAxel Dörfler 
2867f20716SAxel Dörfler typedef enum {
2967f20716SAxel Dörfler 	CONSOLE_STATE_NORMAL = 0,
3067f20716SAxel Dörfler 	CONSOLE_STATE_GOT_ESCAPE,
3167f20716SAxel Dörfler 	CONSOLE_STATE_SEEN_BRACKET,
3267f20716SAxel Dörfler 	CONSOLE_STATE_NEW_ARG,
3367f20716SAxel Dörfler 	CONSOLE_STATE_PARSING_ARG,
3467f20716SAxel Dörfler } console_state;
3567f20716SAxel Dörfler 
3670c3e1a4SAxel Dörfler typedef enum {
3770c3e1a4SAxel Dörfler 	LINE_ERASE_WHOLE,
3870c3e1a4SAxel Dörfler 	LINE_ERASE_LEFT,
3970c3e1a4SAxel Dörfler 	LINE_ERASE_RIGHT
4070c3e1a4SAxel Dörfler } erase_line_mode;
4170c3e1a4SAxel Dörfler 
42f33c8020SAxel Dörfler struct screen_info {
43f33c8020SAxel Dörfler 	int32	columns;
44f33c8020SAxel Dörfler 	int32	rows;
45f33c8020SAxel Dörfler 	int32	x, y;
46f33c8020SAxel Dörfler 	uint8	attr;
4767f20716SAxel Dörfler 	bool	bright_attr;
4867f20716SAxel Dörfler 	bool	reverse_attr;
49855ab2b3SAxel Dörfler 	int32	in_command_rows;
50855ab2b3SAxel Dörfler 	bool	paging;
5133965e02SAxel Dörfler 	bool	boot_debug_output;
52855ab2b3SAxel Dörfler 	bool	ignore_output;
5367f20716SAxel Dörfler 
5467f20716SAxel Dörfler 	// state machine
5567f20716SAxel Dörfler 	console_state state;
5667f20716SAxel Dörfler 	int32	arg_count;
5767f20716SAxel Dörfler 	int32	args[MAX_ARGS];
58f33c8020SAxel Dörfler } sScreen;
59f33c8020SAxel Dörfler 
60f33c8020SAxel Dörfler console_module_info *sModule;
61f33c8020SAxel Dörfler 
62f33c8020SAxel Dörfler 
63f33c8020SAxel Dörfler static inline void
64f33c8020SAxel Dörfler hide_cursor(void)
65f33c8020SAxel Dörfler {
66f33c8020SAxel Dörfler 	sModule->move_cursor(-1, -1);
67f33c8020SAxel Dörfler }
68f33c8020SAxel Dörfler 
69f33c8020SAxel Dörfler 
70f33c8020SAxel Dörfler static inline void
71f33c8020SAxel Dörfler update_cursor(int32 x, int32 y)
72f33c8020SAxel Dörfler {
73f33c8020SAxel Dörfler 	sModule->move_cursor(x, y);
74f33c8020SAxel Dörfler }
75f33c8020SAxel Dörfler 
76f33c8020SAxel Dörfler 
7767f20716SAxel Dörfler static inline void
7867f20716SAxel Dörfler move_cursor(int32 x, int32 y)
7967f20716SAxel Dörfler {
8067f20716SAxel Dörfler 	sScreen.x = x;
8167f20716SAxel Dörfler 	sScreen.y = y;
8267f20716SAxel Dörfler 	update_cursor(x, y);
8367f20716SAxel Dörfler }
8467f20716SAxel Dörfler 
8567f20716SAxel Dörfler 
86f33c8020SAxel Dörfler #if USE_SCROLLING
87f33c8020SAxel Dörfler 
88855ab2b3SAxel Dörfler /*!	Scroll from the cursor line up to the top of the scroll region up one
89855ab2b3SAxel Dörfler 	line.
90855ab2b3SAxel Dörfler */
91f33c8020SAxel Dörfler static void
92f33c8020SAxel Dörfler scroll_up(void)
93f33c8020SAxel Dörfler {
94f33c8020SAxel Dörfler 	// move the screen up one
95f33c8020SAxel Dörfler 	sModule->blit(0, 1, sScreen.columns, sScreen.rows - 1, 0, 0);
96f33c8020SAxel Dörfler 
97f33c8020SAxel Dörfler 	// clear the bottom line
98f33c8020SAxel Dörfler 	sModule->fill_glyph(0, 0, sScreen.columns, 1, ' ', sScreen.attr);
99f33c8020SAxel Dörfler }
100f33c8020SAxel Dörfler #endif
101f33c8020SAxel Dörfler 
102f33c8020SAxel Dörfler 
103f33c8020SAxel Dörfler static void
104f33c8020SAxel Dörfler next_line(void)
105f33c8020SAxel Dörfler {
106*a39bfc19SAxel Dörfler #if USE_SCROLLING
107*a39bfc19SAxel Dörfler 	// TODO: scrolling is usually too slow; we could probably just remove it
108*a39bfc19SAxel Dörfler 	if (sScreen.y == sScreen.rows - 1)
109*a39bfc19SAxel Dörfler  		scroll_up();
110*a39bfc19SAxel Dörfler  	else
111*a39bfc19SAxel Dörfler  		sScreen.y++;
112*a39bfc19SAxel Dörfler #else
113855ab2b3SAxel Dörfler 	if (in_command_invocation())
114855ab2b3SAxel Dörfler 		sScreen.in_command_rows++;
115855ab2b3SAxel Dörfler 	else
116855ab2b3SAxel Dörfler 		sScreen.in_command_rows = 0;
117855ab2b3SAxel Dörfler 
118*a39bfc19SAxel Dörfler 	if (sScreen.paging && ((sScreen.in_command_rows > 0
119*a39bfc19SAxel Dörfler 			&& ((sScreen.in_command_rows + 3) % sScreen.rows) == 0)
120*a39bfc19SAxel Dörfler 		|| (sScreen.boot_debug_output && sScreen.y == sScreen.rows - 1))) {
121*a39bfc19SAxel Dörfler 		// Use the paging mechanism: either, we're in the debugger, and a
122*a39bfc19SAxel Dörfler 		// command is being executed, or we're currently showing boot debug
123*a39bfc19SAxel Dörfler 		// output
124855ab2b3SAxel Dörfler 		const char *text = "Press key to continue, Q to quit";
125855ab2b3SAxel Dörfler 		int32 length = strlen(text);
126855ab2b3SAxel Dörfler 		if (sScreen.x + length > sScreen.columns) {
127855ab2b3SAxel Dörfler 			// make sure we don't overwrite too much
128855ab2b3SAxel Dörfler 			text = "P";
129855ab2b3SAxel Dörfler 			length = 1;
130855ab2b3SAxel Dörfler 		}
131855ab2b3SAxel Dörfler 
132855ab2b3SAxel Dörfler 		for (int32 i = 0; i < length; i++) {
133*a39bfc19SAxel Dörfler 			// yellow on black (or reverse, during boot)
134855ab2b3SAxel Dörfler 			sModule->put_glyph(sScreen.columns - length + i, sScreen.y,
135*a39bfc19SAxel Dörfler 				text[i], sScreen.boot_debug_output ? 0x6f : 0xf6);
136855ab2b3SAxel Dörfler 		}
137855ab2b3SAxel Dörfler 
138855ab2b3SAxel Dörfler 		char c = blue_screen_getchar();
139855ab2b3SAxel Dörfler 		if (c == 'q')
140855ab2b3SAxel Dörfler 			sScreen.ignore_output = true;
141855ab2b3SAxel Dörfler 
142855ab2b3SAxel Dörfler 		// remove on screen text again
143855ab2b3SAxel Dörfler 		sModule->fill_glyph(sScreen.columns - length, sScreen.y, length,
144855ab2b3SAxel Dörfler 			1, ' ', sScreen.attr);
145855ab2b3SAxel Dörfler 	}
146*a39bfc19SAxel Dörfler 	if (sScreen.y == sScreen.rows - 1) {
147f33c8020SAxel Dörfler 		sScreen.y = 0;
148855ab2b3SAxel Dörfler 		sModule->fill_glyph(0, 0, sScreen.columns, 2, ' ', sScreen.attr);
149*a39bfc19SAxel Dörfler 	} else
150f33c8020SAxel Dörfler 		sScreen.y++;
151*a39bfc19SAxel Dörfler #endif
152f33c8020SAxel Dörfler 
153f33c8020SAxel Dörfler #if NO_CLEAR
154855ab2b3SAxel Dörfler 	if (sScreen.y + 2 < sScreen.rows) {
155855ab2b3SAxel Dörfler 		sModule->fill_glyph(0, (sScreen.y + 2) % sScreen.rows, sScreen.columns,
156855ab2b3SAxel Dörfler 			1, ' ', sScreen.attr);
157855ab2b3SAxel Dörfler 	}
158f33c8020SAxel Dörfler #endif
159f33c8020SAxel Dörfler 	sScreen.x = 0;
160f33c8020SAxel Dörfler }
161f33c8020SAxel Dörfler 
162f33c8020SAxel Dörfler 
163f33c8020SAxel Dörfler static void
16470c3e1a4SAxel Dörfler erase_line(erase_line_mode mode)
16570c3e1a4SAxel Dörfler {
16670c3e1a4SAxel Dörfler 	switch (mode) {
16770c3e1a4SAxel Dörfler 		case LINE_ERASE_WHOLE:
168855ab2b3SAxel Dörfler 			sModule->fill_glyph(0, sScreen.y, sScreen.columns, 1, ' ',
169855ab2b3SAxel Dörfler 				sScreen.attr);
17070c3e1a4SAxel Dörfler 			break;
17170c3e1a4SAxel Dörfler 		case LINE_ERASE_LEFT:
172855ab2b3SAxel Dörfler 			sModule->fill_glyph(0, sScreen.y, sScreen.x + 1, 1, ' ',
173855ab2b3SAxel Dörfler 				sScreen.attr);
17470c3e1a4SAxel Dörfler 			break;
17570c3e1a4SAxel Dörfler 		case LINE_ERASE_RIGHT:
176855ab2b3SAxel Dörfler 			sModule->fill_glyph(sScreen.x, sScreen.y, sScreen.columns
177855ab2b3SAxel Dörfler 				- sScreen.x, 1, ' ', sScreen.attr);
17870c3e1a4SAxel Dörfler 			break;
17970c3e1a4SAxel Dörfler 	}
18070c3e1a4SAxel Dörfler }
18170c3e1a4SAxel Dörfler 
18270c3e1a4SAxel Dörfler 
18370c3e1a4SAxel Dörfler static void
184f33c8020SAxel Dörfler back_space(void)
185f33c8020SAxel Dörfler {
186f33c8020SAxel Dörfler 	if (sScreen.x <= 0)
187f33c8020SAxel Dörfler 		return;
188f33c8020SAxel Dörfler 
189f33c8020SAxel Dörfler 	sScreen.x--;
190f33c8020SAxel Dörfler 	sModule->put_glyph(sScreen.x, sScreen.y, ' ', sScreen.attr);
191f33c8020SAxel Dörfler }
192f33c8020SAxel Dörfler 
193f33c8020SAxel Dörfler 
194f33c8020SAxel Dörfler static void
195f33c8020SAxel Dörfler put_character(char c)
196f33c8020SAxel Dörfler {
197f33c8020SAxel Dörfler 	if (++sScreen.x >= sScreen.columns) {
198f33c8020SAxel Dörfler 		next_line();
199f33c8020SAxel Dörfler 		sScreen.x++;
200f33c8020SAxel Dörfler 	}
201f33c8020SAxel Dörfler 
202f33c8020SAxel Dörfler 	sModule->put_glyph(sScreen.x - 1, sScreen.y, c, sScreen.attr);
203f33c8020SAxel Dörfler }
204f33c8020SAxel Dörfler 
205f33c8020SAxel Dörfler 
206f33c8020SAxel Dörfler static void
20767f20716SAxel Dörfler set_vt100_attributes(int32 *args, int32 argCount)
20867f20716SAxel Dörfler {
20967f20716SAxel Dörfler 	if (argCount == 0) {
21067f20716SAxel Dörfler 		// that's the default (attributes off)
21167f20716SAxel Dörfler 		argCount++;
21267f20716SAxel Dörfler 		args[0] = 0;
21367f20716SAxel Dörfler 	}
21467f20716SAxel Dörfler 
21567f20716SAxel Dörfler 	for (int32 i = 0; i < argCount; i++) {
21667f20716SAxel Dörfler 		switch (args[i]) {
21767f20716SAxel Dörfler 			case 0: // reset
21833965e02SAxel Dörfler 				sScreen.attr = sScreen.boot_debug_output ? 0xf0 : 0x0f;
21967f20716SAxel Dörfler 				sScreen.bright_attr = true;
22067f20716SAxel Dörfler 				sScreen.reverse_attr = false;
22167f20716SAxel Dörfler 				break;
22267f20716SAxel Dörfler 			case 1: // bright
22367f20716SAxel Dörfler 				sScreen.bright_attr = true;
22467f20716SAxel Dörfler 				sScreen.attr |= 0x08; // set the bright bit
22567f20716SAxel Dörfler 				break;
22667f20716SAxel Dörfler 			case 2: // dim
22767f20716SAxel Dörfler 				sScreen.bright_attr = false;
22867f20716SAxel Dörfler 				sScreen.attr &= ~0x08; // unset the bright bit
22967f20716SAxel Dörfler 				break;
23067f20716SAxel Dörfler 			case 4: // underscore we can't do
23167f20716SAxel Dörfler 				break;
23267f20716SAxel Dörfler 			case 5: // blink
23367f20716SAxel Dörfler 				sScreen.attr |= 0x80; // set the blink bit
23467f20716SAxel Dörfler 				break;
23567f20716SAxel Dörfler 			case 7: // reverse
23667f20716SAxel Dörfler 				sScreen.reverse_attr = true;
237855ab2b3SAxel Dörfler 				sScreen.attr = ((sScreen.attr & BMASK) >> 4)
238855ab2b3SAxel Dörfler 					| ((sScreen.attr & FMASK) << 4);
23967f20716SAxel Dörfler 				if (sScreen.bright_attr)
24067f20716SAxel Dörfler 					sScreen.attr |= 0x08;
24167f20716SAxel Dörfler 				break;
24267f20716SAxel Dörfler 			case 8: // hidden?
24367f20716SAxel Dörfler 				break;
24467f20716SAxel Dörfler 
24567f20716SAxel Dörfler 			/* foreground colors */
246855ab2b3SAxel Dörfler 			case 30: // black
247855ab2b3SAxel Dörfler 			case 31: // red
248855ab2b3SAxel Dörfler 			case 32: // green
249855ab2b3SAxel Dörfler 			case 33: // yellow
250855ab2b3SAxel Dörfler 			case 34: // blue
251855ab2b3SAxel Dörfler 			case 35: // magenta
252855ab2b3SAxel Dörfler 			case 36: // cyan
253855ab2b3SAxel Dörfler 			case 37: // white
254855ab2b3SAxel Dörfler 			{
255855ab2b3SAxel Dörfler 				const uint8 colors[] = {0, 4, 2, 6, 1, 5, 3, 7};
256855ab2b3SAxel Dörfler 				sScreen.attr = (sScreen.attr & ~FMASK) | colors[args[i] - 30]
257855ab2b3SAxel Dörfler 					| (sScreen.bright_attr ? 0x08 : 0);
258855ab2b3SAxel Dörfler 				break;
259855ab2b3SAxel Dörfler 			}
26067f20716SAxel Dörfler 
26167f20716SAxel Dörfler 			/* background colors */
26267f20716SAxel Dörfler 			case 40: sScreen.attr = (sScreen.attr & ~BMASK) | (0 << 4); break; // black
26367f20716SAxel Dörfler 			case 41: sScreen.attr = (sScreen.attr & ~BMASK) | (4 << 4); break; // red
26467f20716SAxel Dörfler 			case 42: sScreen.attr = (sScreen.attr & ~BMASK) | (2 << 4); break; // green
26567f20716SAxel Dörfler 			case 43: sScreen.attr = (sScreen.attr & ~BMASK) | (6 << 4); break; // yellow
26667f20716SAxel Dörfler 			case 44: sScreen.attr = (sScreen.attr & ~BMASK) | (1 << 4); break; // blue
26767f20716SAxel Dörfler 			case 45: sScreen.attr = (sScreen.attr & ~BMASK) | (5 << 4); break; // magenta
26867f20716SAxel Dörfler 			case 46: sScreen.attr = (sScreen.attr & ~BMASK) | (3 << 4); break; // cyan
26967f20716SAxel Dörfler 			case 47: sScreen.attr = (sScreen.attr & ~BMASK) | (7 << 4); break; // white
27067f20716SAxel Dörfler 		}
27167f20716SAxel Dörfler 	}
27267f20716SAxel Dörfler }
27367f20716SAxel Dörfler 
27467f20716SAxel Dörfler 
27567f20716SAxel Dörfler static bool
27667f20716SAxel Dörfler process_vt100_command(const char c, bool seenBracket, int32 *args, int32 argCount)
27767f20716SAxel Dörfler {
27867f20716SAxel Dörfler 	bool ret = true;
27967f20716SAxel Dörfler 
28067f20716SAxel Dörfler //	kprintf("process_vt100_command: c '%c', argCount %ld, arg[0] %ld, arg[1] %ld, seenBracket %d\n",
28167f20716SAxel Dörfler //		c, argCount, args[0], args[1], seenBracket);
28267f20716SAxel Dörfler 
28367f20716SAxel Dörfler 	if (seenBracket) {
28467f20716SAxel Dörfler 		switch (c) {
28567f20716SAxel Dörfler 			case 'H': /* set cursor position */
28667f20716SAxel Dörfler 			case 'f': {
28767f20716SAxel Dörfler 				int32 row = argCount > 0 ? args[0] : 1;
28867f20716SAxel Dörfler 				int32 col = argCount > 1 ? args[1] : 1;
28967f20716SAxel Dörfler 				if (row > 0)
29067f20716SAxel Dörfler 					row--;
29167f20716SAxel Dörfler 				if (col > 0)
29267f20716SAxel Dörfler 					col--;
29367f20716SAxel Dörfler 				move_cursor(col, row);
29467f20716SAxel Dörfler 				break;
29567f20716SAxel Dörfler 			}
29667f20716SAxel Dörfler 			case 'A': { /* move up */
29767f20716SAxel Dörfler 				int32 deltay = argCount > 0 ? -args[0] : -1;
29867f20716SAxel Dörfler 				if (deltay == 0)
29967f20716SAxel Dörfler 					deltay = -1;
30067f20716SAxel Dörfler 				move_cursor(sScreen.x, sScreen.y + deltay);
30167f20716SAxel Dörfler 				break;
30267f20716SAxel Dörfler 			}
30367f20716SAxel Dörfler 			case 'e':
30467f20716SAxel Dörfler 			case 'B': { /* move down */
30567f20716SAxel Dörfler 				int32 deltay = argCount > 0 ? args[0] : 1;
30667f20716SAxel Dörfler 				if (deltay == 0)
30767f20716SAxel Dörfler 					deltay = 1;
30867f20716SAxel Dörfler 				move_cursor(sScreen.x, sScreen.y + deltay);
30967f20716SAxel Dörfler 				break;
31067f20716SAxel Dörfler 			}
31167f20716SAxel Dörfler 			case 'D': { /* move left */
31267f20716SAxel Dörfler 				int32 deltax = argCount > 0 ? -args[0] : -1;
31367f20716SAxel Dörfler 				if (deltax == 0)
31467f20716SAxel Dörfler 					deltax = -1;
31567f20716SAxel Dörfler 				move_cursor(sScreen.x + deltax, sScreen.y);
31667f20716SAxel Dörfler 				break;
31767f20716SAxel Dörfler 			}
31867f20716SAxel Dörfler 			case 'a':
31967f20716SAxel Dörfler 			case 'C': { /* move right */
32067f20716SAxel Dörfler 				int32 deltax = argCount > 0 ? args[0] : 1;
32167f20716SAxel Dörfler 				if (deltax == 0)
32267f20716SAxel Dörfler 					deltax = 1;
32367f20716SAxel Dörfler 				move_cursor(sScreen.x + deltax, sScreen.y);
32467f20716SAxel Dörfler 				break;
32567f20716SAxel Dörfler 			}
32667f20716SAxel Dörfler 			case '`':
32767f20716SAxel Dörfler 			case 'G': { /* set X position */
32867f20716SAxel Dörfler 				int32 newx = argCount > 0 ? args[0] : 1;
32967f20716SAxel Dörfler 				if (newx > 0)
33067f20716SAxel Dörfler 					newx--;
33167f20716SAxel Dörfler 				move_cursor(newx, sScreen.y);
33267f20716SAxel Dörfler 				break;
33367f20716SAxel Dörfler 			}
33467f20716SAxel Dörfler 			case 'd': { /* set y position */
33567f20716SAxel Dörfler 				int32 newy = argCount > 0 ? args[0] : 1;
33667f20716SAxel Dörfler 				if (newy > 0)
33767f20716SAxel Dörfler 					newy--;
33867f20716SAxel Dörfler 				move_cursor(sScreen.x, newy);
33967f20716SAxel Dörfler 				break;
34067f20716SAxel Dörfler 			}
34167f20716SAxel Dörfler #if 0
34267f20716SAxel Dörfler 			case 's': /* save current cursor */
34367f20716SAxel Dörfler 				save_cur(console, false);
34467f20716SAxel Dörfler 				break;
34567f20716SAxel Dörfler 			case 'u': /* restore cursor */
34667f20716SAxel Dörfler 				restore_cur(console, false);
34767f20716SAxel Dörfler 				break;
34867f20716SAxel Dörfler 			case 'r': { /* set scroll region */
34967f20716SAxel Dörfler 				int32 low = argCount > 0 ? args[0] : 1;
35067f20716SAxel Dörfler 				int32 high = argCount > 1 ? args[1] : sScreen.lines;
35167f20716SAxel Dörfler 				if (low <= high)
35267f20716SAxel Dörfler 					set_scroll_region(console, low - 1, high - 1);
35367f20716SAxel Dörfler 				break;
35467f20716SAxel Dörfler 			}
35567f20716SAxel Dörfler 			case 'L': { /* scroll virtual down at cursor */
35667f20716SAxel Dörfler 				int32 lines = argCount > 0 ? args[0] : 1;
35767f20716SAxel Dörfler 				while (lines > 0) {
35867f20716SAxel Dörfler 					scrdown(console);
35967f20716SAxel Dörfler 					lines--;
36067f20716SAxel Dörfler 				}
36167f20716SAxel Dörfler 				break;
36267f20716SAxel Dörfler 			}
36367f20716SAxel Dörfler 			case 'M': { /* scroll virtual up at cursor */
36467f20716SAxel Dörfler 				int32 lines = argCount > 0 ? args[0] : 1;
36567f20716SAxel Dörfler 				while (lines > 0) {
36667f20716SAxel Dörfler 					scrup(console);
36767f20716SAxel Dörfler 					lines--;
36867f20716SAxel Dörfler 				}
36967f20716SAxel Dörfler 				break;
37067f20716SAxel Dörfler 			}
37170c3e1a4SAxel Dörfler #endif
37267f20716SAxel Dörfler 			case 'K':
37367f20716SAxel Dörfler 				if (argCount == 0 || args[0] == 0) {
37467f20716SAxel Dörfler 					// erase to end of line
37570c3e1a4SAxel Dörfler 					erase_line(LINE_ERASE_RIGHT);
37667f20716SAxel Dörfler 				} else if (argCount > 0) {
37767f20716SAxel Dörfler 					if (args[0] == 1)
37870c3e1a4SAxel Dörfler 						erase_line(LINE_ERASE_LEFT);
37967f20716SAxel Dörfler 					else if (args[0] == 2)
38070c3e1a4SAxel Dörfler 						erase_line(LINE_ERASE_WHOLE);
38167f20716SAxel Dörfler 				}
38267f20716SAxel Dörfler 				break;
38370c3e1a4SAxel Dörfler #if 0
38467f20716SAxel Dörfler 			case 'J':
38567f20716SAxel Dörfler 				if (argCount == 0 || args[0] == 0) {
38667f20716SAxel Dörfler 					// erase to end of screen
38767f20716SAxel Dörfler 					erase_screen(console, SCREEN_ERASE_DOWN);
38867f20716SAxel Dörfler 				} else {
38967f20716SAxel Dörfler 					if (args[0] == 1)
39067f20716SAxel Dörfler 						erase_screen(console, SCREEN_ERASE_UP);
39167f20716SAxel Dörfler 					else if (args[0] == 2)
39267f20716SAxel Dörfler 						erase_screen(console, SCREEN_ERASE_WHOLE);
39367f20716SAxel Dörfler 				}
39467f20716SAxel Dörfler 				break;
39567f20716SAxel Dörfler #endif
39667f20716SAxel Dörfler 			case 'm':
39767f20716SAxel Dörfler 				if (argCount >= 0)
39867f20716SAxel Dörfler 					set_vt100_attributes(args, argCount);
39967f20716SAxel Dörfler 				break;
40067f20716SAxel Dörfler 			default:
40167f20716SAxel Dörfler 				ret = false;
40267f20716SAxel Dörfler 		}
40367f20716SAxel Dörfler 	} else {
40467f20716SAxel Dörfler 		switch (c) {
40567f20716SAxel Dörfler #if 0
40667f20716SAxel Dörfler 			case 'c':
40767f20716SAxel Dörfler 				reset_console(console);
40867f20716SAxel Dörfler 				break;
40967f20716SAxel Dörfler 			case 'D':
41067f20716SAxel Dörfler 				rlf(console);
41167f20716SAxel Dörfler 				break;
41267f20716SAxel Dörfler 			case 'M':
41367f20716SAxel Dörfler 				lf(console);
41467f20716SAxel Dörfler 				break;
41567f20716SAxel Dörfler 			case '7':
41667f20716SAxel Dörfler 				save_cur(console, true);
41767f20716SAxel Dörfler 				break;
41867f20716SAxel Dörfler 			case '8':
41967f20716SAxel Dörfler 				restore_cur(console, true);
42067f20716SAxel Dörfler 				break;
42167f20716SAxel Dörfler #endif
42267f20716SAxel Dörfler 			default:
42367f20716SAxel Dörfler 				ret = false;
42467f20716SAxel Dörfler 		}
42567f20716SAxel Dörfler 	}
42667f20716SAxel Dörfler 
42767f20716SAxel Dörfler 	return ret;
42867f20716SAxel Dörfler }
42967f20716SAxel Dörfler 
43067f20716SAxel Dörfler 
43167f20716SAxel Dörfler static void
432f33c8020SAxel Dörfler parse_character(char c)
433f33c8020SAxel Dörfler {
43467f20716SAxel Dörfler 	switch (sScreen.state) {
43567f20716SAxel Dörfler 		case CONSOLE_STATE_NORMAL:
436f33c8020SAxel Dörfler 			// just output the stuff
437f33c8020SAxel Dörfler 			switch (c) {
438f33c8020SAxel Dörfler 				case '\n':
439f33c8020SAxel Dörfler 					next_line();
440f33c8020SAxel Dörfler 					break;
441f33c8020SAxel Dörfler 				case 0x8:
442f33c8020SAxel Dörfler 					back_space();
443f33c8020SAxel Dörfler 					break;
444f33c8020SAxel Dörfler 				case '\t':
44567f20716SAxel Dörfler 					// ToDo: real tab...
446f31dc4ddSAxel Dörfler 					sScreen.x = (sScreen.x + 8) & ~7;
447f31dc4ddSAxel Dörfler 					if (sScreen.x >= sScreen.columns)
448f31dc4ddSAxel Dörfler 						next_line();
449f33c8020SAxel Dörfler 					break;
450f33c8020SAxel Dörfler 
451f33c8020SAxel Dörfler 				case '\r':
452f33c8020SAxel Dörfler 				case '\0':
45367f20716SAxel Dörfler 				case '\a': // beep
454f33c8020SAxel Dörfler 					break;
455f33c8020SAxel Dörfler 
45667f20716SAxel Dörfler 				case 0x1b:
45767f20716SAxel Dörfler 					// escape character
45867f20716SAxel Dörfler 					sScreen.arg_count = -1;
45967f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_GOT_ESCAPE;
46067f20716SAxel Dörfler 					break;
461f33c8020SAxel Dörfler 				default:
462f33c8020SAxel Dörfler 					put_character(c);
463f33c8020SAxel Dörfler 			}
46467f20716SAxel Dörfler 			break;
46567f20716SAxel Dörfler 		case CONSOLE_STATE_GOT_ESCAPE:
46667f20716SAxel Dörfler 			// look for either commands with no argument, or the '[' character
46767f20716SAxel Dörfler 			switch (c) {
46867f20716SAxel Dörfler 				case '[':
46967f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_SEEN_BRACKET;
47067f20716SAxel Dörfler 					break;
47167f20716SAxel Dörfler 				default:
47267f20716SAxel Dörfler 					sScreen.args[sScreen.arg_count] = 0;
473855ab2b3SAxel Dörfler 					process_vt100_command(c, false, sScreen.args,
474855ab2b3SAxel Dörfler 						sScreen.arg_count + 1);
47567f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NORMAL;
47667f20716SAxel Dörfler 			}
47767f20716SAxel Dörfler 			break;
47867f20716SAxel Dörfler 		case CONSOLE_STATE_SEEN_BRACKET:
47967f20716SAxel Dörfler 			switch (c) {
48067f20716SAxel Dörfler 				case '0'...'9':
48167f20716SAxel Dörfler 					sScreen.arg_count = 0;
48267f20716SAxel Dörfler 					sScreen.args[sScreen.arg_count] = c - '0';
48367f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_PARSING_ARG;
48467f20716SAxel Dörfler 					break;
48567f20716SAxel Dörfler 				case '?':
486855ab2b3SAxel Dörfler 					// private DEC mode parameter follows - we ignore those
487855ab2b3SAxel Dörfler 					// anyway
48867f20716SAxel Dörfler 					break;
48967f20716SAxel Dörfler 				default:
490855ab2b3SAxel Dörfler 					process_vt100_command(c, true, sScreen.args,
491855ab2b3SAxel Dörfler 						sScreen.arg_count + 1);
49267f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NORMAL;
49367f20716SAxel Dörfler 			}
49467f20716SAxel Dörfler 			break;
49567f20716SAxel Dörfler 		case CONSOLE_STATE_NEW_ARG:
49667f20716SAxel Dörfler 			switch (c) {
49767f20716SAxel Dörfler 				case '0'...'9':
49867f20716SAxel Dörfler 					sScreen.arg_count++;
49967f20716SAxel Dörfler 					if (sScreen.arg_count == MAX_ARGS) {
50067f20716SAxel Dörfler 						sScreen.state = CONSOLE_STATE_NORMAL;
50167f20716SAxel Dörfler 						break;
50267f20716SAxel Dörfler 					}
50367f20716SAxel Dörfler 					sScreen.args[sScreen.arg_count] = c - '0';
50467f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_PARSING_ARG;
50567f20716SAxel Dörfler 					break;
50667f20716SAxel Dörfler 				default:
507855ab2b3SAxel Dörfler 					process_vt100_command(c, true, sScreen.args,
508855ab2b3SAxel Dörfler 						sScreen.arg_count + 1);
50967f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NORMAL;
51067f20716SAxel Dörfler 			}
51167f20716SAxel Dörfler 			break;
51267f20716SAxel Dörfler 		case CONSOLE_STATE_PARSING_ARG:
51367f20716SAxel Dörfler 			// parse args
51467f20716SAxel Dörfler 			switch (c) {
51567f20716SAxel Dörfler 				case '0'...'9':
51667f20716SAxel Dörfler 					sScreen.args[sScreen.arg_count] *= 10;
51767f20716SAxel Dörfler 					sScreen.args[sScreen.arg_count] += c - '0';
51867f20716SAxel Dörfler 					break;
51967f20716SAxel Dörfler 				case ';':
52067f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NEW_ARG;
52167f20716SAxel Dörfler 					break;
52267f20716SAxel Dörfler 				default:
523855ab2b3SAxel Dörfler 					process_vt100_command(c, true, sScreen.args,
524855ab2b3SAxel Dörfler 						sScreen.arg_count + 1);
52567f20716SAxel Dörfler 					sScreen.state = CONSOLE_STATE_NORMAL;
52667f20716SAxel Dörfler 			}
52767f20716SAxel Dörfler 	}
528f33c8020SAxel Dörfler }
529f33c8020SAxel Dörfler 
530f33c8020SAxel Dörfler 
531855ab2b3SAxel Dörfler static int
532855ab2b3SAxel Dörfler set_paging(int argc, char **argv)
533855ab2b3SAxel Dörfler {
534855ab2b3SAxel Dörfler 	if (argc > 1 && !strcmp(argv[1], "--help")) {
535855ab2b3SAxel Dörfler 		kprintf("usage: %s [on|off]\n", argv[0]);
536855ab2b3SAxel Dörfler 		return 0;
537855ab2b3SAxel Dörfler 	}
538855ab2b3SAxel Dörfler 
539855ab2b3SAxel Dörfler 	if (argc == 1)
540855ab2b3SAxel Dörfler 		sScreen.paging = !sScreen.paging;
541855ab2b3SAxel Dörfler 	else if (!strcmp(argv[1], "on"))
542855ab2b3SAxel Dörfler 		sScreen.paging = true;
543855ab2b3SAxel Dörfler 	else if (!strcmp(argv[1], "off"))
544855ab2b3SAxel Dörfler 		sScreen.paging = false;
545855ab2b3SAxel Dörfler 	else
546855ab2b3SAxel Dörfler 		sScreen.paging = parse_expression(argv[1]) != 0;
547855ab2b3SAxel Dörfler 
548855ab2b3SAxel Dörfler 	kprintf("paging is turned %s now.\n", sScreen.paging ? "on" : "off");
549855ab2b3SAxel Dörfler 	return 0;
550855ab2b3SAxel Dörfler }
551855ab2b3SAxel Dörfler 
552855ab2b3SAxel Dörfler 
553f33c8020SAxel Dörfler //	#pragma mark -
554f33c8020SAxel Dörfler 
555f33c8020SAxel Dörfler 
556f33c8020SAxel Dörfler status_t
557f33c8020SAxel Dörfler blue_screen_init(void)
558f33c8020SAxel Dörfler {
559f33c8020SAxel Dörfler 	extern console_module_info gFrameBufferConsoleModule;
560f33c8020SAxel Dörfler 
561f33c8020SAxel Dörfler 	// we can't use get_module() here, since it's too early in the boot process
562f33c8020SAxel Dörfler 
563f33c8020SAxel Dörfler 	if (!frame_buffer_console_available())
564f33c8020SAxel Dörfler 		return B_ERROR;
565f33c8020SAxel Dörfler 
566f33c8020SAxel Dörfler 	sModule = &gFrameBufferConsoleModule;
567855ab2b3SAxel Dörfler 	sScreen.paging = true;
568855ab2b3SAxel Dörfler 
569855ab2b3SAxel Dörfler 	add_debugger_command("paging", set_paging, "Enable or disable paging");
570f33c8020SAxel Dörfler 	return B_OK;
571f33c8020SAxel Dörfler }
572f33c8020SAxel Dörfler 
573f33c8020SAxel Dörfler 
574173d0b2fSAxel Dörfler status_t
57592447917SAxel Dörfler blue_screen_enter(bool debugOutput)
576f33c8020SAxel Dörfler {
57792447917SAxel Dörfler 	sScreen.attr = debugOutput ? 0xf0 : 0x0f;
57892447917SAxel Dörfler 		// black on white for KDL, white on black for debug output
57933965e02SAxel Dörfler 	sScreen.boot_debug_output = debugOutput;
58033965e02SAxel Dörfler 	sScreen.ignore_output = false;
58133965e02SAxel Dörfler 
582f33c8020SAxel Dörfler 	sScreen.x = sScreen.y = 0;
58367f20716SAxel Dörfler 	sScreen.state = CONSOLE_STATE_NORMAL;
584f33c8020SAxel Dörfler 
585173d0b2fSAxel Dörfler 	if (sModule == NULL)
586173d0b2fSAxel Dörfler 		return B_NO_INIT;
587173d0b2fSAxel Dörfler 
588f33c8020SAxel Dörfler 	sModule->get_size(&sScreen.columns, &sScreen.rows);
589f33c8020SAxel Dörfler #if !NO_CLEAR
590f33c8020SAxel Dörfler 	sModule->clear(sScreen.attr);
591f33c8020SAxel Dörfler #else
592f33c8020SAxel Dörfler 	sModule->fill_glyph(0, sScreen.y, sScreen.columns, 3, ' ', sScreen.attr);
593f33c8020SAxel Dörfler #endif
594173d0b2fSAxel Dörfler 	return B_OK;
595f33c8020SAxel Dörfler }
596f33c8020SAxel Dörfler 
597f33c8020SAxel Dörfler 
598f33c8020SAxel Dörfler char
599f33c8020SAxel Dörfler blue_screen_getchar(void)
600f33c8020SAxel Dörfler {
601f33c8020SAxel Dörfler 	return arch_debug_blue_screen_getchar();
602f33c8020SAxel Dörfler }
603f33c8020SAxel Dörfler 
604f33c8020SAxel Dörfler 
605f33c8020SAxel Dörfler void
606f33c8020SAxel Dörfler blue_screen_putchar(char c)
607f33c8020SAxel Dörfler {
60833965e02SAxel Dörfler 	if (sScreen.ignore_output
60933965e02SAxel Dörfler 		&& (in_command_invocation() || sScreen.boot_debug_output))
610855ab2b3SAxel Dörfler 		return;
611855ab2b3SAxel Dörfler 
612855ab2b3SAxel Dörfler 	sScreen.ignore_output = false;
613f33c8020SAxel Dörfler 	hide_cursor();
614f33c8020SAxel Dörfler 
615f33c8020SAxel Dörfler 	parse_character(c);
616f33c8020SAxel Dörfler 
617f33c8020SAxel Dörfler 	update_cursor(sScreen.x, sScreen.y);
618f33c8020SAxel Dörfler }
619f33c8020SAxel Dörfler 
620f33c8020SAxel Dörfler 
621f33c8020SAxel Dörfler void
622f33c8020SAxel Dörfler blue_screen_puts(const char *text)
623f33c8020SAxel Dörfler {
62433965e02SAxel Dörfler 	if (sScreen.ignore_output
62533965e02SAxel Dörfler 		&& (in_command_invocation() || sScreen.boot_debug_output))
626855ab2b3SAxel Dörfler 		return;
627855ab2b3SAxel Dörfler 
628855ab2b3SAxel Dörfler 	sScreen.ignore_output = false;
629f33c8020SAxel Dörfler 	hide_cursor();
630f33c8020SAxel Dörfler 
631f33c8020SAxel Dörfler 	while (text[0] != '\0') {
632f33c8020SAxel Dörfler 		parse_character(text[0]);
633f33c8020SAxel Dörfler 		text++;
634f33c8020SAxel Dörfler 	}
635f33c8020SAxel Dörfler 
636f33c8020SAxel Dörfler 	update_cursor(sScreen.x, sScreen.y);
637f33c8020SAxel Dörfler }
638