1 /* $NetBSD: vga.c,v 1.2 2001/07/22 14:57:51 wiz Exp $ */ 2 3 /*- 4 * Copyright (C) 1995-1997 Gary Thomas (gdt@linuxppc.org) 5 * All rights reserved. 6 * 7 * VGA 'glass TTY' emulator 8 * 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. 22 * 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. 33 */ 34 35 #ifdef CONS_VGA 36 #include <lib/libsa/stand.h> 37 #include "boot.h" 38 39 #define COL 80 40 #define ROW 25 41 #define CHR 2 42 #define MONO_BASE 0x3B4 43 #define MONO_BUF 0xB0000 44 #define CGA_BASE 0x3D4 45 #define CGA_BUF 0xB8000 46 47 u_char background = 0; /* Black */ 48 u_char foreground = 7; /* White */ 49 50 u_int addr_6845; 51 u_short *Crtat; 52 int lastpos; 53 int scroll; 54 55 /* 56 * The current state of virtual displays 57 */ 58 struct screen { 59 u_short *cp; /* the current character address */ 60 enum state { 61 NORMAL, /* no pending escape */ 62 ESC, /* saw ESC */ 63 EBRAC, /* saw ESC[ */ 64 EBRACEQ /* saw ESC[= */ 65 } state; /* command parser state */ 66 int cx; /* the first escape seq argument */ 67 int cy; /* the second escap seq argument */ 68 int *accp; /* pointer to the current processed argument */ 69 int row; /* current column */ 70 int so; /* standout mode */ 71 u_short color; /* normal character color */ 72 u_short color_so; /* standout color */ 73 u_short save_color; /* saved normal color */ 74 u_short save_color_so; /* saved standout color */ 75 } screen; 76 77 /* 78 * Color and attributes for normal, standout and kernel output 79 * are stored in the least-significant byte of a u_short 80 * so they don't have to be shifted for use. 81 * This is all byte-order dependent. 82 */ 83 #define CATTR(x) (x) /* store color/attributes un-shifted */ 84 #define ATTR_ADDR(which) (((u_char *)&(which))+1) /* address of attributes */ 85 86 u_short pccolor; /* color/attributes for tty output */ 87 u_short pccolor_so; /* color/attributes, standout mode */ 88 89 static void cursor __P((void)); 90 static void initscreen __P((void)); 91 void fillw __P((u_short, u_short *, int)); 92 void video_on __P((void)); 93 void video_off __P((void)); 94 95 /* 96 * cursor() sets an offset (0-1999) into the 80x25 text area 97 */ 98 static void 99 cursor() 100 { 101 int pos = screen.cp - Crtat; 102 103 if (lastpos != pos) { 104 outb(addr_6845, 14); 105 outb(addr_6845+1, pos >> 8); 106 outb(addr_6845, 15); 107 outb(addr_6845+1, pos); 108 lastpos = pos; 109 } 110 } 111 112 static void 113 initscreen() 114 { 115 struct screen *d = &screen; 116 117 pccolor = CATTR((background<<4)|foreground); 118 pccolor_so = CATTR((foreground<<4)|background); 119 d->color = pccolor; 120 d->save_color = pccolor; 121 d->color_so = pccolor_so; 122 d->save_color_so = pccolor_so; 123 } 124 125 126 #define wrtchar(c, d) { \ 127 *(d->cp) = c; \ 128 d->cp++; \ 129 d->row++; \ 130 } 131 132 void 133 fillw(val, buf, num) 134 u_short val; 135 u_short *buf; 136 int num; 137 { 138 /* Need to byte swap value */ 139 u_short tmp; 140 141 tmp = val; 142 while (num-- > 0) 143 *buf++ = tmp; 144 } 145 146 /* 147 * vga_putc (nee sput) has support for emulation of the 'ibmpc' termcap entry. 148 * This is a bare-bones implementation of a bare-bones entry 149 * One modification: Change li#24 to li#25 to reflect 25 lines 150 * "ca" is the color/attributes value (left-shifted by 8) 151 * or 0 if the current regular color for that screen is to be used. 152 */ 153 void 154 vga_putc(int c) 155 { 156 struct screen *d = &screen; 157 u_short *base; 158 int i, j; 159 u_short *pp; 160 161 base = Crtat; 162 163 switch (d->state) { 164 case NORMAL: 165 switch (c) { 166 case 0x0: /* Ignore pad characters */ 167 return; 168 169 case 0x1B: 170 d->state = ESC; 171 break; 172 173 case '\t': 174 do { 175 wrtchar(d->color | ' ', d); 176 } while (d->row % 8); 177 break; 178 179 case '\b': /* non-destructive backspace */ 180 if (d->cp > base) { 181 d->cp--; 182 d->row--; 183 if (d->row < 0) 184 d->row += COL; /* prev column */ 185 } 186 break; 187 188 case '\n': 189 d->cp += COL; 190 case '\r': 191 d->cp -= d->row; 192 d->row = 0; 193 break; 194 195 case '\007': 196 break; 197 198 default: 199 if (d->so) { 200 wrtchar(d->color_so|(c<<8), d); 201 } else { 202 wrtchar(d->color | (c<<8), d); 203 } 204 if (d->row >= COL) 205 d->row = 0; 206 break; 207 } 208 break; 209 210 case EBRAC: 211 /* 212 * In this state, the action at the end of the switch 213 * on the character type is to go to NORMAL state, 214 * and intermediate states do a return rather than break. 215 */ 216 switch (c) { 217 case 'm': 218 d->so = d->cx; 219 break; 220 221 case 'A': /* back one row */ 222 if (d->cp >= base + COL) 223 d->cp -= COL; 224 break; 225 226 case 'B': /* down one row */ 227 d->cp += COL; 228 break; 229 230 case 'C': /* right cursor */ 231 d->cp++; 232 d->row++; 233 break; 234 235 case 'D': /* left cursor */ 236 if (d->cp > base) { 237 d->cp--; 238 d->row--; 239 if (d->row < 0) 240 d->row += COL; /* prev column ??? */ 241 } 242 break; 243 244 case 'J': /* Clear to end of display */ 245 fillw(d->color|(' '<<8), d->cp, base + COL * ROW - d->cp); 246 break; 247 248 case 'K': /* Clear to EOL */ 249 fillw(d->color|(' '<<8), d->cp, COL - (d->cp - base) % COL); 250 break; 251 252 case 'H': /* Cursor move */ 253 if (d->cx > ROW) 254 d->cx = ROW; 255 if (d->cy > COL) 256 d->cy = COL; 257 if (d->cx == 0 || d->cy == 0) { 258 d->cp = base; 259 d->row = 0; 260 } else { 261 d->cp = base + (d->cx - 1) * COL + d->cy - 1; 262 d->row = d->cy - 1; 263 } 264 break; 265 266 case '_': /* set cursor */ 267 if (d->cx) 268 d->cx = 1; /* block */ 269 else 270 d->cx = 12; /* underline */ 271 outb(addr_6845, 10); 272 outb(addr_6845+1, d->cx); 273 outb(addr_6845, 11); 274 outb(addr_6845+1, 13); 275 break; 276 277 case ';': /* Switch params in cursor def */ 278 d->accp = &d->cy; 279 return; 280 281 case '=': /* ESC[= color change */ 282 d->state = EBRACEQ; 283 return; 284 285 case 'L': /* Insert line */ 286 i = (d->cp - base) / COL; 287 /* avoid deficiency of bcopy implementation */ 288 /* XXX: comment and hack relevant? */ 289 pp = base + COL * (ROW-2); 290 for (j = ROW - 1 - i; j--; pp -= COL) 291 memmove(pp + COL, pp, COL * CHR); 292 fillw(d->color|(' '<<8), base + i * COL, COL); 293 break; 294 295 case 'M': /* Delete line */ 296 i = (d->cp - base) / COL; 297 pp = base + i * COL; 298 memmove(pp, pp + COL, (ROW-1 - i)*COL*CHR); 299 fillw(d->color|(' '<<8), base + COL * (ROW - 1), COL); 300 break; 301 302 default: /* Only numbers valid here */ 303 if ((c >= '0') && (c <= '9')) { 304 *(d->accp) *= 10; 305 *(d->accp) += c - '0'; 306 return; 307 } else 308 break; 309 } 310 d->state = NORMAL; 311 break; 312 313 case EBRACEQ: { 314 /* 315 * In this state, the action at the end of the switch 316 * on the character type is to go to NORMAL state, 317 * and intermediate states do a return rather than break. 318 */ 319 u_char *colp; 320 321 /* 322 * Set foreground/background color 323 * for normal mode, standout mode 324 * or kernel output. 325 * Based on code from kentp@svmp03. 326 */ 327 switch (c) { 328 case 'F': 329 colp = ATTR_ADDR(d->color); 330 do_fg: 331 *colp = (*colp & 0xf0) | (d->cx); 332 break; 333 334 case 'G': 335 colp = ATTR_ADDR(d->color); 336 do_bg: 337 *colp = (*colp & 0xf) | (d->cx << 4); 338 break; 339 340 case 'H': 341 colp = ATTR_ADDR(d->color_so); 342 goto do_fg; 343 344 case 'I': 345 colp = ATTR_ADDR(d->color_so); 346 goto do_bg; 347 348 case 'S': 349 d->save_color = d->color; 350 d->save_color_so = d->color_so; 351 break; 352 353 case 'R': 354 d->color = d->save_color; 355 d->color_so = d->save_color_so; 356 break; 357 358 default: /* Only numbers valid here */ 359 if ((c >= '0') && (c <= '9')) { 360 d->cx *= 10; 361 d->cx += c - '0'; 362 return; 363 } else 364 break; 365 } 366 d->state = NORMAL; 367 } 368 break; 369 370 case ESC: 371 switch (c) { 372 case 'c': /* Clear screen & home */ 373 fillw(d->color|(' '<<8), base, COL * ROW); 374 d->cp = base; 375 d->row = 0; 376 d->state = NORMAL; 377 break; 378 case '[': /* Start ESC [ sequence */ 379 d->state = EBRAC; 380 d->cx = 0; 381 d->cy = 0; 382 d->accp = &d->cx; 383 break; 384 default: /* Invalid, clear state */ 385 d->state = NORMAL; 386 break; 387 } 388 break; 389 } 390 if (d->cp >= base + (COL * ROW)) { /* scroll check */ 391 memmove(base, base + COL, COL * (ROW - 1) * CHR); 392 fillw(d->color|(' '<<8), base + COL * (ROW - 1), COL); 393 d->cp -= COL; 394 } 395 cursor(); 396 } 397 398 void 399 vga_puts(s) 400 char *s; 401 { 402 char c; 403 while ((c = *s++)) { 404 vga_putc(c); 405 } 406 } 407 408 void 409 video_on() 410 { 411 412 /* Enable video */ 413 outb(0x3C4, 0x01); 414 outb(0x3C5, inb(0x3C5) & ~0x20); 415 } 416 417 void 418 video_off() 419 { 420 421 /* Disable video */ 422 outb(0x3C4, 0x01); 423 outb(0x3C5, inb(0x3C5) | 0x20); 424 } 425 426 void 427 vga_init(ISA_mem) 428 u_char *ISA_mem; 429 { 430 struct screen *d = &screen; 431 432 memset(d, 0, sizeof (screen)); 433 video_on(); 434 435 d->cp = Crtat = (u_short *)&ISA_mem[0x0B8000]; 436 addr_6845 = CGA_BASE; 437 initscreen(); 438 fillw(pccolor|(' '<<8), d->cp, COL * ROW); 439 } 440 #endif /* CONS_VGA */ 441