]> Joshua Wise's Git repositories - netwatch.git/blob - lib/console.c
db95d7dcbdc8c12f13b87b7cd57a7143e2f824aa
[netwatch.git] / lib / console.c
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  */
26 struct 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  */
55 static 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. */
67 static 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  */
78 static 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
143 int 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
188 void putbytes(const char *s, int len)
189 {
190         if (!curcons->initialized)
191                 clear_console();
192         
193         while (len--)
194                 putbyte(*(s++));
195 }
196
197 int 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
206 void get_term_color(int *color)
207 {
208         if (!curcons->initialized)
209                 clear_console();
210         
211         *color = (int)curcons->attr;
212 }
213
214 int 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
226 void get_cursor(int *row, int *col)
227 {
228         if (!curcons->initialized)
229                 clear_console();
230         *row = curcons->row;
231         *col = curcons->col;
232 }
233
234 void hide_cursor()
235 {
236         if (!curcons->initialized)
237                 clear_console();
238         curcons->showcursor = 0;
239         update_cursor();
240 }
241
242 void show_cursor()
243 {
244         if (!curcons->initialized)
245                 clear_console();
246         curcons->showcursor = 1;
247         update_cursor();
248 }
249
250 void 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
264 void 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
272 char 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.095308 seconds and 4 git commands to generate.