No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / prep / stand / boot / vga.c
blobc1d1b88228b08c63c2360d4ae4f0f3c4d42204b1
1 /* $NetBSD: vga.c,v 1.5 2006/04/10 18:40:06 garbled Exp $ */
3 /*-
4 * Copyright (C) 1995-1997 Gary Thomas (gdt@linuxppc.org)
5 * All rights reserved.
7 * VGA 'glass TTY' emulator
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Gary Thomas.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #ifdef CONS_VGA
36 #include <lib/libsa/stand.h>
37 #include <lib/libkern/libkern.h>
38 #include "boot.h"
40 #define COL 80
41 #define ROW 25
42 #define CHR 2
43 #define MONO_BASE 0x3B4
44 #define MONO_BUF 0xB0000
45 #define CGA_BASE 0x3D4
46 #define CGA_BUF 0xB8000
48 u_char background = 0; /* Black */
49 u_char foreground = 7; /* White */
51 u_int addr_6845;
52 u_short *Crtat;
53 int lastpos;
54 int scroll;
57 * The current state of virtual displays
59 struct screen {
60 u_short *cp; /* the current character address */
61 enum state {
62 NORMAL, /* no pending escape */
63 ESC, /* saw ESC */
64 EBRAC, /* saw ESC[ */
65 EBRACEQ /* saw ESC[= */
66 } state; /* command parser state */
67 int cx; /* the first escape seq argument */
68 int cy; /* the second escap seq argument */
69 int *accp; /* pointer to the current processed argument */
70 int row; /* current column */
71 int so; /* standout mode */
72 u_short color; /* normal character color */
73 u_short color_so; /* standout color */
74 u_short save_color; /* saved normal color */
75 u_short save_color_so; /* saved standout color */
76 } screen;
79 * Color and attributes for normal, standout and kernel output
80 * are stored in the least-significant byte of a u_short
81 * so they don't have to be shifted for use.
82 * This is all byte-order dependent.
84 #define CATTR(x) (x) /* store color/attributes un-shifted */
85 #define ATTR_ADDR(which) (((u_char *)&(which))+1) /* address of attributes */
87 u_short pccolor; /* color/attributes for tty output */
88 u_short pccolor_so; /* color/attributes, standout mode */
90 static void cursor(void);
91 static void initscreen(void);
92 void fillw(u_short, u_short *, int);
93 void video_on(void);
94 void video_off(void);
97 * cursor() sets an offset (0-1999) into the 80x25 text area
99 static void
100 cursor(void)
102 int pos = screen.cp - Crtat;
104 if (lastpos != pos) {
105 outb(addr_6845, 14);
106 outb(addr_6845+1, pos >> 8);
107 outb(addr_6845, 15);
108 outb(addr_6845+1, pos);
109 lastpos = pos;
113 static void
114 initscreen(void)
116 struct screen *d = &screen;
118 pccolor = CATTR((background<<4)|foreground);
119 pccolor_so = CATTR((foreground<<4)|background);
120 d->color = pccolor;
121 d->save_color = pccolor;
122 d->color_so = pccolor_so;
123 d->save_color_so = pccolor_so;
127 #define wrtchar(c, d) { \
128 *(d->cp) = c; \
129 d->cp++; \
130 d->row++; \
133 void
134 fillw(u_short val, u_short *buf, int num)
136 /* Need to byte swap value */
137 u_short tmp;
139 tmp = val;
140 while (num-- > 0)
141 *buf++ = tmp;
145 * vga_putc (nee sput) has support for emulation of the 'ibmpc' termcap entry.
146 * This is a bare-bones implementation of a bare-bones entry
147 * One modification: Change li#24 to li#25 to reflect 25 lines
148 * "ca" is the color/attributes value (left-shifted by 8)
149 * or 0 if the current regular color for that screen is to be used.
151 void
152 vga_putc(int c)
154 struct screen *d = &screen;
155 u_short *base;
156 int i, j;
157 u_short *pp;
159 base = Crtat;
161 switch (d->state) {
162 case NORMAL:
163 switch (c) {
164 case 0x0: /* Ignore pad characters */
165 return;
167 case 0x1B:
168 d->state = ESC;
169 break;
171 case '\t':
172 do {
173 wrtchar(d->color | ' ', d);
174 } while (d->row % 8);
175 break;
177 case '\b': /* non-destructive backspace */
178 if (d->cp > base) {
179 d->cp--;
180 d->row--;
181 if (d->row < 0)
182 d->row += COL; /* prev column */
184 break;
186 case '\n':
187 d->cp += COL;
188 case '\r':
189 d->cp -= d->row;
190 d->row = 0;
191 break;
193 case '\007':
194 break;
196 default:
197 if (d->so) {
198 wrtchar(d->color_so|(c<<8), d);
199 } else {
200 wrtchar(d->color | (c<<8), d);
202 if (d->row >= COL)
203 d->row = 0;
204 break;
206 break;
208 case EBRAC:
210 * In this state, the action at the end of the switch
211 * on the character type is to go to NORMAL state,
212 * and intermediate states do a return rather than break.
214 switch (c) {
215 case 'm':
216 d->so = d->cx;
217 break;
219 case 'A': /* back one row */
220 if (d->cp >= base + COL)
221 d->cp -= COL;
222 break;
224 case 'B': /* down one row */
225 d->cp += COL;
226 break;
228 case 'C': /* right cursor */
229 d->cp++;
230 d->row++;
231 break;
233 case 'D': /* left cursor */
234 if (d->cp > base) {
235 d->cp--;
236 d->row--;
237 if (d->row < 0)
238 d->row += COL; /* prev column ??? */
240 break;
242 case 'J': /* Clear to end of display */
243 fillw(d->color|(' '<<8), d->cp, base + COL * ROW - d->cp);
244 break;
246 case 'K': /* Clear to EOL */
247 fillw(d->color|(' '<<8), d->cp, COL - (d->cp - base) % COL);
248 break;
250 case 'H': /* Cursor move */
251 if (d->cx > ROW)
252 d->cx = ROW;
253 if (d->cy > COL)
254 d->cy = COL;
255 if (d->cx == 0 || d->cy == 0) {
256 d->cp = base;
257 d->row = 0;
258 } else {
259 d->cp = base + (d->cx - 1) * COL + d->cy - 1;
260 d->row = d->cy - 1;
262 break;
264 case '_': /* set cursor */
265 if (d->cx)
266 d->cx = 1; /* block */
267 else
268 d->cx = 12; /* underline */
269 outb(addr_6845, 10);
270 outb(addr_6845+1, d->cx);
271 outb(addr_6845, 11);
272 outb(addr_6845+1, 13);
273 break;
275 case ';': /* Switch params in cursor def */
276 d->accp = &d->cy;
277 return;
279 case '=': /* ESC[= color change */
280 d->state = EBRACEQ;
281 return;
283 case 'L': /* Insert line */
284 i = (d->cp - base) / COL;
285 /* avoid deficiency of bcopy implementation */
286 /* XXX: comment and hack relevant? */
287 pp = base + COL * (ROW-2);
288 for (j = ROW - 1 - i; j--; pp -= COL)
289 memmove(pp + COL, pp, COL * CHR);
290 fillw(d->color|(' '<<8), base + i * COL, COL);
291 break;
293 case 'M': /* Delete line */
294 i = (d->cp - base) / COL;
295 pp = base + i * COL;
296 memmove(pp, pp + COL, (ROW-1 - i)*COL*CHR);
297 fillw(d->color|(' '<<8), base + COL * (ROW - 1), COL);
298 break;
300 default: /* Only numbers valid here */
301 if ((c >= '0') && (c <= '9')) {
302 *(d->accp) *= 10;
303 *(d->accp) += c - '0';
304 return;
305 } else
306 break;
308 d->state = NORMAL;
309 break;
311 case EBRACEQ: {
313 * In this state, the action at the end of the switch
314 * on the character type is to go to NORMAL state,
315 * and intermediate states do a return rather than break.
317 u_char *colp;
320 * Set foreground/background color
321 * for normal mode, standout mode
322 * or kernel output.
323 * Based on code from kentp@svmp03.
325 switch (c) {
326 case 'F':
327 colp = ATTR_ADDR(d->color);
328 do_fg:
329 *colp = (*colp & 0xf0) | (d->cx);
330 break;
332 case 'G':
333 colp = ATTR_ADDR(d->color);
334 do_bg:
335 *colp = (*colp & 0xf) | (d->cx << 4);
336 break;
338 case 'H':
339 colp = ATTR_ADDR(d->color_so);
340 goto do_fg;
342 case 'I':
343 colp = ATTR_ADDR(d->color_so);
344 goto do_bg;
346 case 'S':
347 d->save_color = d->color;
348 d->save_color_so = d->color_so;
349 break;
351 case 'R':
352 d->color = d->save_color;
353 d->color_so = d->save_color_so;
354 break;
356 default: /* Only numbers valid here */
357 if ((c >= '0') && (c <= '9')) {
358 d->cx *= 10;
359 d->cx += c - '0';
360 return;
361 } else
362 break;
364 d->state = NORMAL;
366 break;
368 case ESC:
369 switch (c) {
370 case 'c': /* Clear screen & home */
371 fillw(d->color|(' '<<8), base, COL * ROW);
372 d->cp = base;
373 d->row = 0;
374 d->state = NORMAL;
375 break;
376 case '[': /* Start ESC [ sequence */
377 d->state = EBRAC;
378 d->cx = 0;
379 d->cy = 0;
380 d->accp = &d->cx;
381 break;
382 default: /* Invalid, clear state */
383 d->state = NORMAL;
384 break;
386 break;
388 if (d->cp >= base + (COL * ROW)) { /* scroll check */
389 memmove(base, base + COL, COL * (ROW - 1) * CHR);
390 fillw(d->color|(' '<<8), base + COL * (ROW - 1), COL);
391 d->cp -= COL;
393 cursor();
396 void
397 vga_puts(char *s)
399 char c;
400 while ((c = *s++)) {
401 vga_putc(c);
405 void
406 video_on(void)
409 /* Enable video */
410 outb(0x3C4, 0x01);
411 outb(0x3C5, inb(0x3C5) & ~0x20);
414 void
415 video_off(void)
418 /* Disable video */
419 outb(0x3C4, 0x01);
420 outb(0x3C5, inb(0x3C5) | 0x20);
423 void
424 vga_init(u_char *ISA_mem)
426 struct screen *d = &screen;
428 memset(d, 0, sizeof (screen));
429 video_on();
431 d->cp = Crtat = (u_short *)&ISA_mem[0x0B8000];
432 addr_6845 = CGA_BASE;
433 initscreen();
434 fillw(pccolor|(' '<<8), d->cp, COL * ROW);
436 #endif /* CONS_VGA */