]> Joshua Wise's Git repositories - netwatch.git/blame - lib/console.c
Add port tool
[netwatch.git] / lib / console.c
CommitLineData
9b8c947b
JW
1/** @file console.c
2 * @brief A console driver.
3 *
4 * @author Joshua Wise (jwise) <joshua@joshuawise.com>
5 * @bug None known
6 */
7
8#include <console.h>
9#include "console-ext.h"
10#include <io.h>
11
12#define POS_IS_VALID(row, col) ((row) >= 0 && (row) < CONSOLE_HEIGHT && (col) >= 0 && (col) < CONSOLE_WIDTH)
13
14/** @brief A structure describing a console that is backed by memory.
15 *
16 * In the mode of designing for extensibility, all of the console driver's
17 * state is encapsulated in a 'struct console', which would ostensibly make
18 * it easier to create virtual consoles later. All of the console driver's
19 * workings touch this struct; ideally, there are no references to
20 * CONSOLE_MEM_BASE or other hardware outside of this. In practice, this
21 * isn't quite the case (see update_cursor()).... but we're close.
22 */
23struct console {
24 int row; /**< The current row. */
25 int col; /**< The current column. */
26 unsigned char attr; /**< The current color/attribute. */
27 unsigned char *base; /**< The current base to write data to.
28 * Might not be equal to physbase if we're
29 * in a different virtual console right
30 * now or we have requested a backbuffer!
31 */
32 unsigned char *physbase; /**< The physical memory base for
33 * this console.
34 */
35 int showcursor; /**< Whether the cursor should be shown
36 * by update_cursor().
37 */
38 int initialized; /**< Whether the console has been
39 * initialized. Functions should check
40 * this and call clear_console() before
41 * running if this is zero.
42 */
43 int backbuffer; /**< Whether we're currently writing to a
44 * backbuffer instead of the physical
45 * video memory.
46 */
47};
48
49/** @brief The structure describing the one console on the system. Should
50 * not be touched by anyone but the initializer for curcons!
51 */
52static struct console cons = {
53 .row = 0,
54 .col = 0,
55 .attr = FGND_LGRAY,
56 .base = (unsigned char *)CONSOLE_MEM_BASE,
57 .physbase = (unsigned char *)CONSOLE_MEM_BASE,
58 .showcursor = 1,
59 .initialized = 0,
60 .backbuffer = 0,
61};
62
63/** @brief The current console that all console.c operations work on. */
64static struct console *curcons = &cons;
65
66/** @brief Makes sure that the VGA cursor matches with the console.c's idea
67 * of where the cursor should be.
68 *
69 * update_cursor would be trivial, but for a few important checks. In
70 * particular, it won't touch the cursor at all if we're backbuffered
71 * (since that would make the cursor fly around a screen that isn't
72 * actually being updated), and if the cursor is hidden, it sets it to an
73 * out-of-bounds segment to make sure that it's actually hidden.
74 */
75static void update_cursor()
76{
77 if (curcons->backbuffer)
78 return;
79 if (curcons->showcursor)
80 {
81 unsigned short addr = (curcons->row * CONSOLE_WIDTH + curcons->col);
82 outb(CRTC_IDX_REG, CRTC_CURSOR_MSB_IDX);
83 outb(CRTC_DATA_REG, (addr >> 8));
84 outb(CRTC_IDX_REG, CRTC_CURSOR_LSB_IDX);
85 outb(CRTC_DATA_REG, addr & 0xFF);
86 } else {
87 outb(CRTC_IDX_REG, CRTC_CURSOR_MSB_IDX);
88 outb(CRTC_DATA_REG, 255 /* invalid */);
89 outb(CRTC_IDX_REG, CRTC_CURSOR_LSB_IDX);
90 outb(CRTC_DATA_REG, 255 /* invalid */);
91 }
92}
93
94/** @brief Redirects console writes to a backbuffer.
95 *
96 * Verifies that the console is not already backbuffered. If it's not, it
97 * allocates a backbuffer, copies the current console into the backbuffer,
98 * and sets the backbuffered flag.
99 *
100 * This isn't just theoretical, by the way. The game screen's timer causes
101 * it to repaint every frame (for lack of a better way to do it), which is
102 * fine in qemu (which is fast), but causes severe flicker in simics. This
103 * backbuffering logic seems to have alleviated the flicker.
104 *
105 * @see cons_debackbuffer
106 */
107/*void cons_backbuffer()
108{
109 if (!curcons->initialized)
110 clear_console();
111 if (curcons->backbuffer)
112 return;
113 curcons->base = malloc(CONSOLE_WIDTH * CONSOLE_HEIGHT * 2);
114 memcpy(curcons->base, curcons->physbase, CONSOLE_WIDTH * CONSOLE_HEIGHT * 2);
115 curcons->backbuffer = 1;
116}*/
117
118/** @brief Turns off the backbuffer.
119 *
120 * Verifies that we are currently backbuffered. If so, copies the
121 * backbuffer into video memory, frees the backbuffer, sets the pointer
122 * back to video memory, clears the backbuffered flag, and updates the
123 * hardware cursor.
124 *
125 * @see cons_backbuffer
126 */
127/*void cons_debackbuffer()
128{
129 if (!curcons->initialized)
130 clear_console();
131 if (!curcons->backbuffer)
132 return;
133 memcpy(curcons->physbase, curcons->base, CONSOLE_WIDTH * CONSOLE_HEIGHT * 2);
134 free(curcons->base);
135 curcons->base = curcons->physbase;
136 curcons->backbuffer = 0;
137 update_cursor();
138}*/
139
140int putbyte(char ch)
141{
142 if (!curcons->initialized)
143 clear_console();
144
145 /* Make sure to handle special cases nicely.*/
146 switch(ch)
147 {
148 case '\n':
149 curcons->row++;
150 if (curcons->row >= CONSOLE_HEIGHT) /* Moving off the end? Scroll. */
151 {
152 int c;
153 memmove(curcons->base, curcons->base + 2*CONSOLE_WIDTH, 2*CONSOLE_WIDTH*(CONSOLE_HEIGHT-1));
154 curcons->row--;
155 for (c=0; c<CONSOLE_WIDTH; c++) /* Clear the newly blank bottom line. */
156 {
157 curcons->base[(curcons->row * CONSOLE_WIDTH + c) * 2] = ' ';
158 curcons->base[(curcons->row * CONSOLE_WIDTH + c) * 2 + 1] = curcons->attr;
159 }
160 }
161 // fall through
162 case '\r':
163 curcons->col = 0;
164 update_cursor();
165 break;
166 case '\b':
167 if (curcons->col)
168 {
169 curcons->col--;
170 curcons->base[(curcons->row*CONSOLE_WIDTH + curcons->col) * 2] = ' ';
171 }
172 update_cursor();
173 break;
174 default:
175 curcons->base[(curcons->row*CONSOLE_WIDTH + curcons->col) * 2] = ch;
176 curcons->base[(curcons->row*CONSOLE_WIDTH + curcons->col) * 2 + 1] = curcons->attr;
177 curcons->col++;
178 if (curcons->col >= CONSOLE_WIDTH)
179 putbyte('\n');
180 update_cursor();
181 }
182 return ch;
183}
184
185void putbytes(const char *s, int len)
186{
187 if (!curcons->initialized)
188 clear_console();
189
190 while (len--)
191 putbyte(*(s++));
192}
193
194int set_term_color(int color)
195{
196 if (!curcons->initialized)
197 clear_console();
198
199 curcons->attr = (unsigned char)color;
200 return 0;
201}
202
203void get_term_color(int *color)
204{
205 if (!curcons->initialized)
206 clear_console();
207
208 *color = (int)curcons->attr;
209}
210
211int set_cursor(int row, int col)
212{
213 if (!curcons->initialized)
214 clear_console();
215 if (!POS_IS_VALID(row, col))
216 return -1;
217 curcons->row = row;
218 curcons->col = col;
219 update_cursor();
220 return 0;
221}
222
223void get_cursor(int *row, int *col)
224{
225 if (!curcons->initialized)
226 clear_console();
227 *row = curcons->row;
228 *col = curcons->col;
229}
230
231void hide_cursor()
232{
233 if (!curcons->initialized)
234 clear_console();
235 curcons->showcursor = 0;
236 update_cursor();
237}
238
239void show_cursor()
240{
241 if (!curcons->initialized)
242 clear_console();
243 curcons->showcursor = 1;
244 update_cursor();
245}
246
247void clear_console()
248{
249 int i;
250 curcons->initialized = 1;
251 curcons->row = 0;
252 curcons->col = 0;
253 for (i = 0; i < CONSOLE_WIDTH * CONSOLE_HEIGHT; i++)
254 {
255 curcons->base[i*2] = ' ';
256 curcons->base[i*2+1] = FGND_LGRAY;
257 }
258 update_cursor();
259}
260
261void draw_char(int row, int col, int ch, int color)
262{
263 if (!POS_IS_VALID(row, col))
264 return;
265 curcons->base[2 * (CONSOLE_WIDTH * row + col)] = (unsigned char)ch;
266 curcons->base[2 * (CONSOLE_WIDTH * row + col)+1] = (unsigned char)color;
267}
268
269char get_char(int row, int col)
270{
271 if (!POS_IS_VALID(row, col))
272 return 0;
273 return curcons->base[2 * (CONSOLE_WIDTH * row + col)];
274}
This page took 0.045536 seconds and 4 git commands to generate.