1 /* $NetBSD: vga.c,v 1.6 2009/03/18 10:22:34 cegger 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 <lib/libkern/libkern.h> 38 #include "boot.h" 39 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 47 48 u_char background = 0; /* Black */ 49 u_char foreground = 7; /* White */ 50 51 u_int addr_6845; 52 u_short *Crtat; 53 int lastpos; 54 int scroll; 55 56 /* 57 * The current state of virtual displays 58 */ 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; 77 78 /* 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. 83 */ 84 #define CATTR(x) (x) /* store color/attributes un-shifted */ 85 #define ATTR_ADDR(which) (((u_char *)&(which))+1) /* address of attributes */ 86 87 u_short pccolor; /* color/attributes for tty output */ 88 u_short pccolor_so; /* color/attributes, standout mode */ 89 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); 95 96 /* 97 * cursor() sets an offset (0-1999) into the 80x25 text area 98 */ 99 static void 100 cursor(void) 101 { 102 int pos = screen.cp - Crtat; 103 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; 110 } 111 } 112 113 static void 114 initscreen(void) 115 { 116 struct screen *d = &screen; 117 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; 124 } 125 126 127 #define wrtchar(c, d) { \ 128 *(d->cp) = c; \ 129 d->cp++; \ 130 d->row++; \ 131 } 132 133 void 134 fillw(u_short val, u_short *buf, int num) 135 { 136 /* Need to byte swap value */ 137 u_short tmp; 138 139 tmp = val; 140 while (num-- > 0) 141 *buf++ = tmp; 142 } 143 144 /* 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. 150 */ 151 void 152 vga_putc(int c) 153 { 154 struct screen *d = &screen; 155 u_short *base; 156 int i, j; 157 u_short *pp; 158 159 base = Crtat; 160 161 switch (d->state) { 162 case NORMAL: 163 switch (c) { 164 case 0x0: /* Ignore pad characters */ 165 return; 166 167 case 0x1B: 168 d->state = ESC; 169 break; 170 171 case '\t': 172 do { 173 wrtchar(d->color | ' ', d); 174 } while (d->row % 8); 175 break; 176 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 */ 183 } 184 break; 185 186 case '\n': 187 d->cp += COL; 188 case '\r': 189 d->cp -= d->row; 190 d->row = 0; 191 break; 192 193 case '\007': 194 break; 195 196 default: 197 if (d->so) { 198 wrtchar(d->color_so|(c<<8), d); 199 } else { 200 wrtchar(d->color | (c<<8), d); 201 } 202 if (d->row >= COL) 203 d->row = 0; 204 break; 205 } 206 break; 207 208 case EBRAC: 209 /* 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. 213 */ 214 switch (c) { 215 case 'm': 216 d->so = d->cx; 217 break; 218 219 case 'A': /* back one row */ 220 if (d->cp >= base + COL) 221 d->cp -= COL; 222 break; 223 224 case 'B': /* down one row */ 225 d->cp += COL; 226 break; 227 228 case 'C': /* right cursor */ 229 d->cp++; 230 d->row++; 231 break; 232 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 ??? */ 239 } 240 break; 241 242 case 'J': /* Clear to end of display */ 243 fillw(d->color|(' '<<8), d->cp, base + COL * ROW - d->cp); 244 break; 245 246 case 'K': /* Clear to EOL */ 247 fillw(d->color|(' '<<8), d->cp, COL - (d->cp - base) % COL); 248 break; 249 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; 261 } 262 break; 263 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; 274 275 case ';': /* Switch params in cursor def */ 276 d->accp = &d->cy; 277 return; 278 279 case '=': /* ESC[= color change */ 280 d->state = EBRACEQ; 281 return; 282 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; 292 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; 299 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; 307 } 308 d->state = NORMAL; 309 break; 310 311 case EBRACEQ: { 312 /* 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. 316 */ 317 u_char *colp; 318 319 /* 320 * Set foreground/background color 321 * for normal mode, standout mode 322 * or kernel output. 323 * Based on code from kentp@svmp03. 324 */ 325 switch (c) { 326 case 'F': 327 colp = ATTR_ADDR(d->color); 328 do_fg: 329 *colp = (*colp & 0xf0) | (d->cx); 330 break; 331 332 case 'G': 333 colp = ATTR_ADDR(d->color); 334 do_bg: 335 *colp = (*colp & 0xf) | (d->cx << 4); 336 break; 337 338 case 'H': 339 colp = ATTR_ADDR(d->color_so); 340 goto do_fg; 341 342 case 'I': 343 colp = ATTR_ADDR(d->color_so); 344 goto do_bg; 345 346 case 'S': 347 d->save_color = d->color; 348 d->save_color_so = d->color_so; 349 break; 350 351 case 'R': 352 d->color = d->save_color; 353 d->color_so = d->save_color_so; 354 break; 355 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; 363 } 364 d->state = NORMAL; 365 } 366 break; 367 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; 385 } 386 break; 387 } 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; 392 } 393 cursor(); 394 } 395 396 void 397 vga_puts(char *s) 398 { 399 char c; 400 while ((c = *s++)) { 401 vga_putc(c); 402 } 403 } 404 405 void 406 video_on(void) 407 { 408 409 /* Enable video */ 410 outb(0x3C4, 0x01); 411 outb(0x3C5, inb(0x3C5) & ~0x20); 412 } 413 414 void 415 video_off(void) 416 { 417 418 /* Disable video */ 419 outb(0x3C4, 0x01); 420 outb(0x3C5, inb(0x3C5) | 0x20); 421 } 422 423 void 424 vga_init(u_char *ISA_mem) 425 { 426 struct screen *d = &screen; 427 428 memset(d, 0, sizeof (screen)); 429 video_on(); 430 431 d->cp = Crtat = (u_short *)&ISA_mem[0x0B8000]; 432 addr_6845 = CGA_BASE; 433 initscreen(); 434 fillw(pccolor|(' '<<8), d->cp, COL * ROW); 435 } 436 #endif /* CONS_VGA */ 437