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