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