vidconsole.c revision 259065
1/*- 2 * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) 3 * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: releng/10.0/sys/boot/pc98/libpc98/vidconsole.c 226746 2011-10-25 19:45:12Z jhb $"); 32 33#include <stand.h> 34#include <bootstrap.h> 35#include <btxv86.h> 36#include <machine/cpufunc.h> 37#include "libi386.h" 38 39#if KEYBOARD_PROBE 40#include <machine/cpufunc.h> 41 42static int probe_keyboard(void); 43#endif 44static void vidc_probe(struct console *cp); 45static int vidc_init(int arg); 46static void vidc_putchar(int c); 47static int vidc_getchar(void); 48static int vidc_ischar(void); 49 50static int vidc_started; 51 52#ifdef TERM_EMU 53#define MAXARGS 8 54#define DEFAULT_FGCOLOR 7 55#define DEFAULT_BGCOLOR 0 56 57void end_term(void); 58void bail_out(int c); 59void vidc_term_emu(int c); 60void get_pos(void); 61void curs_move(int x, int y); 62void write_char(int c, int fg, int bg); 63void scroll_up(int rows, int fg, int bg); 64void CD(void); 65void CM(void); 66void HO(void); 67 68static int args[MAXARGS], argc; 69static int fg_c, bg_c, curx, cury; 70static int esc; 71#endif 72 73static unsigned short *crtat, *Crtat; 74static int row = 25, col = 80; 75#ifdef TERM_EMU 76static u_int8_t ibmpc_to_pc98[256] = { 77 0x01, 0x21, 0x81, 0xa1, 0x41, 0x61, 0xc1, 0xe1, 78 0x09, 0x29, 0x89, 0xa9, 0x49, 0x69, 0xc9, 0xe9, 79 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 80 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 81 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 82 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 83 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 84 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 85 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 86 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 87 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 88 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 89 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 90 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 91 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 92 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 93 94 0x03, 0x23, 0x83, 0xa3, 0x43, 0x63, 0xc3, 0xe3, 95 0x0b, 0x2b, 0x8b, 0xab, 0x4b, 0x6b, 0xcb, 0xeb, 96 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 97 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 98 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 99 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 100 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 101 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 102 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 103 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 104 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 105 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 106 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 107 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 108 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 109 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 110}; 111#define at2pc98(fg_at, bg_at) ibmpc_to_pc98[((bg_at) << 4) | (fg_at)] 112#endif /* TERM_EMU */ 113 114struct console vidconsole = { 115 "vidconsole", 116 "internal video/keyboard", 117 0, 118 vidc_probe, 119 vidc_init, 120 vidc_putchar, 121 vidc_getchar, 122 vidc_ischar 123}; 124 125static void 126vidc_probe(struct console *cp) 127{ 128 129 /* look for a keyboard */ 130#if KEYBOARD_PROBE 131 if (probe_keyboard()) 132#endif 133 { 134 135 cp->c_flags |= C_PRESENTIN; 136 } 137 138 /* XXX for now, always assume we can do BIOS screen output */ 139 cp->c_flags |= C_PRESENTOUT; 140} 141 142static int 143vidc_init(int arg) 144{ 145 int i, hw_cursor; 146 147 if (vidc_started && arg == 0) 148 return (0); 149 vidc_started = 1; 150 Crtat = (unsigned short *)PTOV(0xA0000); 151 while ((inb(0x60) & 0x04) == 0) 152 ; 153 outb(0x62, 0xe0); 154 while ((inb(0x60) & 0x01) == 0) 155 ; 156 hw_cursor = inb(0x62); 157 hw_cursor |= (inb(0x62) << 8); 158 inb(0x62); 159 inb(0x62); 160 inb(0x62); 161 crtat = Crtat + hw_cursor; 162#ifdef TERM_EMU 163 /* Init terminal emulator */ 164 end_term(); 165 get_pos(); 166 curs_move(curx, cury); 167 fg_c = DEFAULT_FGCOLOR; 168 bg_c = DEFAULT_BGCOLOR; 169#endif 170 for (i = 0; i < 10 && vidc_ischar(); i++) 171 (void)vidc_getchar(); 172 return (0); /* XXX reinit? */ 173} 174 175static void 176beep(void) 177{ 178 179 outb(0x37, 6); 180 delay(40000); 181 outb(0x37, 7); 182} 183 184#if 0 185static void 186vidc_biosputchar(int c) 187{ 188 unsigned short *cp; 189 int i, pos; 190 191#ifdef TERM_EMU 192 *crtat = (c == 0x5c ? 0xfc : c); 193 *(crtat + 0x1000) = at2pc98(fg, bg); 194#else 195 switch(c) { 196 case '\b': 197 crtat--; 198 break; 199 case '\r': 200 crtat -= (crtat - Crtat) % col; 201 break; 202 case '\n': 203 crtat += col; 204 break; 205 default: 206 *crtat = (c == 0x5c ? 0xfc : c); 207 *(crtat++ + 0x1000) = 0xe1; 208 break; 209 } 210 211 if (crtat >= Crtat + col * row) { 212 cp = Crtat; 213 for (i = 1; i < row; i++) { 214 bcopy((void *)(cp + col), (void *)cp, col * 2); 215 cp += col; 216 } 217 for (i = 0; i < col; i++) { 218 *cp++ = ' '; 219 } 220 crtat -= col; 221 } 222 pos = crtat - Crtat; 223 while ((inb(0x60) & 0x04) == 0) {} 224 outb(0x62, 0x49); 225 outb(0x60, pos & 0xff); 226 outb(0x60, pos >> 8); 227#endif 228} 229#endif 230 231static void 232vidc_rawputchar(int c) 233{ 234 int i; 235 236 if (c == '\t') 237 /* lame tab expansion */ 238 for (i = 0; i < 8; i++) 239 vidc_rawputchar(' '); 240 else { 241 /* Emulate AH=0eh (teletype output) */ 242 switch(c) { 243 case '\a': 244 beep(); 245 return; 246 case '\r': 247 curx = 0; 248 curs_move(curx, cury); 249 return; 250 case '\n': 251 cury++; 252 if (cury > 24) { 253 scroll_up(1, fg_c, bg_c); 254 cury--; 255 } else { 256 curs_move(curx, cury); 257 } 258 return; 259 case '\b': 260 if (curx > 0) { 261 curx--; 262 curs_move(curx, cury); 263 /* write_char(' ', fg_c, bg_c); XXX destructive(!) */ 264 return; 265 } 266 return; 267 default: 268 write_char(c, fg_c, bg_c); 269 curx++; 270 if (curx > 79) { 271 curx = 0; 272 cury++; 273 } 274 if (cury > 24) { 275 curx = 0; 276 scroll_up(1, fg_c, bg_c); 277 cury--; 278 } 279 } 280 curs_move(curx, cury); 281 } 282} 283 284#ifdef TERM_EMU 285 286/* Get cursor position on the screen. Result is in edx. Sets 287 * curx and cury appropriately. 288 */ 289void 290get_pos(void) 291{ 292 int pos = crtat - Crtat; 293 294 curx = pos % col; 295 cury = pos / col; 296} 297 298/* Move cursor to x rows and y cols (0-based). */ 299void 300curs_move(int x, int y) 301{ 302 int pos; 303 304 pos = x + y * col; 305 crtat = Crtat + pos; 306 pos = crtat - Crtat; 307 while((inb(0x60) & 0x04) == 0) {} 308 outb(0x62, 0x49); 309 outb(0x60, pos & 0xff); 310 outb(0x60, pos >> 8); 311 curx = x; 312 cury = y; 313#define isvisible(c) (((c) >= 32) && ((c) < 255)) 314 if (!isvisible(*crtat & 0x00ff)) { 315 write_char(' ', fg_c, bg_c); 316 } 317} 318 319/* Scroll up the whole window by a number of rows. If rows==0, 320 * clear the window. fg and bg are attributes for the new lines 321 * inserted in the window. 322 */ 323void 324scroll_up(int rows, int fgcol, int bgcol) 325{ 326 unsigned short *cp; 327 int i; 328 329 if (rows == 0) 330 rows = 25; 331 cp = Crtat; 332 for (i = rows; i < row; i++) { 333 bcopy((void *)(cp + col), (void *)cp, col * 2); 334 cp += col; 335 } 336 for (i = 0; i < col; i++) { 337 *(cp + 0x1000) = at2pc98(fgcol, bgcol); 338 *cp++ = ' '; 339 } 340} 341 342/* Write character and attribute at cursor position. */ 343void 344write_char(int c, int fgcol, int bgcol) 345{ 346 347 *crtat = (c == 0x5c ? 0xfc : (c & 0xff)); 348 *(crtat + 0x1000) = at2pc98(fgcol, bgcol); 349} 350 351/**************************************************************/ 352/* 353 * Screen manipulation functions. They use accumulated data in 354 * args[] and argc variables. 355 * 356 */ 357 358/* Clear display from current position to end of screen */ 359void 360CD(void) 361{ 362 int pos; 363 364 get_pos(); 365 for (pos = 0; crtat + pos <= Crtat + col * row; pos++) { 366 *(crtat + pos) = ' '; 367 *(crtat + pos + 0x1000) = at2pc98(fg_c, bg_c); 368 } 369 end_term(); 370} 371 372/* Absolute cursor move to args[0] rows and args[1] columns 373 * (the coordinates are 1-based). 374 */ 375void 376CM(void) 377{ 378 379 if (args[0] > 0) 380 args[0]--; 381 if (args[1] > 0) 382 args[1]--; 383 curs_move(args[1], args[0]); 384 end_term(); 385} 386 387/* Home cursor (left top corner) */ 388void 389HO(void) 390{ 391 392 argc = 1; 393 args[0] = args[1] = 1; 394 CM(); 395} 396 397/* Clear internal state of the terminal emulation code */ 398void 399end_term(void) 400{ 401 402 esc = 0; 403 argc = -1; 404} 405 406/* Gracefully exit ESC-sequence processing in case of misunderstanding */ 407void 408bail_out(int c) 409{ 410 char buf[16], *ch; 411 int i; 412 413 if (esc) { 414 vidc_rawputchar('\033'); 415 if (esc != '\033') 416 vidc_rawputchar(esc); 417 for (i = 0; i <= argc; ++i) { 418 sprintf(buf, "%d", args[i]); 419 ch = buf; 420 while (*ch) 421 vidc_rawputchar(*ch++); 422 } 423 } 424 vidc_rawputchar(c); 425 end_term(); 426} 427 428static void 429get_arg(int c) 430{ 431 432 if (argc < 0) 433 argc = 0; 434 args[argc] *= 10; 435 args[argc] += c - '0'; 436} 437 438/* Emulate basic capabilities of cons25 terminal */ 439void 440vidc_term_emu(int c) 441{ 442 static int ansi_col[] = { 443 0, 4, 2, 6, 1, 5, 3, 7, 444 }; 445 int t; 446 int i; 447 448 switch (esc) { 449 case 0: 450 switch (c) { 451 case '\033': 452 esc = c; 453 break; 454 default: 455 vidc_rawputchar(c); 456 break; 457 } 458 break; 459 460 case '\033': 461 switch (c) { 462 case '[': 463 esc = c; 464 args[0] = 0; 465 argc = -1; 466 break; 467 default: 468 bail_out(c); 469 break; 470 } 471 break; 472 473 case '[': 474 switch (c) { 475 case ';': 476 if (argc < 0) /* XXX */ 477 argc = 0; 478 else if (argc + 1 >= MAXARGS) 479 bail_out(c); 480 else 481 args[++argc] = 0; 482 break; 483 case 'H': 484 if (argc < 0) 485 HO(); 486 else if (argc == 1) 487 CM(); 488 else 489 bail_out(c); 490 break; 491 case 'J': 492 if (argc < 0) 493 CD(); 494 else 495 bail_out(c); 496 break; 497 case 'm': 498 if (argc < 0) { 499 fg_c = DEFAULT_FGCOLOR; 500 bg_c = DEFAULT_BGCOLOR; 501 } 502 for (i = 0; i <= argc; ++i) { 503 switch (args[i]) { 504 case 0: /* back to normal */ 505 fg_c = DEFAULT_FGCOLOR; 506 bg_c = DEFAULT_BGCOLOR; 507 break; 508 case 1: /* bold */ 509 fg_c |= 0x8; 510 break; 511 case 4: /* underline */ 512 case 5: /* blink */ 513 bg_c |= 0x8; 514 break; 515 case 7: /* reverse */ 516 t = fg_c; 517 fg_c = bg_c; 518 bg_c = t; 519 break; 520 case 30: case 31: case 32: case 33: 521 case 34: case 35: case 36: case 37: 522 fg_c = ansi_col[args[i] - 30]; 523 break; 524 case 39: /* normal */ 525 fg_c = DEFAULT_FGCOLOR; 526 break; 527 case 40: case 41: case 42: case 43: 528 case 44: case 45: case 46: case 47: 529 bg_c = ansi_col[args[i] - 40]; 530 break; 531 case 49: /* normal */ 532 bg_c = DEFAULT_BGCOLOR; 533 break; 534 } 535 } 536 end_term(); 537 break; 538 default: 539 if (isdigit(c)) 540 get_arg(c); 541 else 542 bail_out(c); 543 break; 544 } 545 break; 546 547 default: 548 bail_out(c); 549 break; 550 } 551} 552#endif 553 554static void 555vidc_putchar(int c) 556{ 557#ifdef TERM_EMU 558 vidc_term_emu(c); 559#else 560 vidc_rawputchar(c); 561#endif 562} 563 564static int 565vidc_getchar(void) 566{ 567 568 if (vidc_ischar()) { 569 v86.ctl = 0; 570 v86.addr = 0x18; 571 v86.eax = 0x0; 572 v86int(); 573 return (v86.eax & 0xff); 574 } else { 575 return (-1); 576 } 577} 578 579static int 580vidc_ischar(void) 581{ 582 583 v86.ctl = 0; 584 v86.addr = 0x18; 585 v86.eax = 0x100; 586 v86int(); 587 return ((v86.ebx >> 8) & 0x1); 588} 589 590#if KEYBOARD_PROBE 591static int 592probe_keyboard(void) 593{ 594 return (*(u_char *)PTOV(0xA1481) & 0x48); 595} 596#endif /* KEYBOARD_PROBE */ 597