]> Joshua Wise's Git repositories - netwatch.git/blob - grubload/console.c
27880baabbafce3a3d0edb1bcee9d8e6a6c98c2a
[netwatch.git] / grubload / console.c
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  */
23 struct 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  */
52 static 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. */
64 static 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  */
75 static 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
140 int 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
185 void putbytes(const char *s, int len)
186 {
187         if (!curcons->initialized)
188                 clear_console();
189         
190         while (len--)
191                 putbyte(*(s++));
192 }
193
194 int 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
203 void get_term_color(int *color)
204 {
205         if (!curcons->initialized)
206                 clear_console();
207         
208         *color = (int)curcons->attr;
209 }
210
211 int 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
223 void get_cursor(int *row, int *col)
224 {
225         if (!curcons->initialized)
226                 clear_console();
227         *row = curcons->row;
228         *col = curcons->col;
229 }
230
231 void hide_cursor()
232 {
233         if (!curcons->initialized)
234                 clear_console();
235         curcons->showcursor = 0;
236         update_cursor();
237 }
238
239 void show_cursor()
240 {
241         if (!curcons->initialized)
242                 clear_console();
243         curcons->showcursor = 1;
244         update_cursor();
245 }
246
247 void 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
261 void 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
269 char 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.033887 seconds and 2 git commands to generate.