1: /* Code and data for the IBM console driver. 2: * 3: * The 6845 video controller used by the IBM PC shares its video memory with 4: * the CPU somewhere in the 0xB0000 memory bank. To the 6845 this memory 5: * consists of 16-bit words. Each word has a character code in the low byte 6: * and a so-called attribute byte in the high byte. The CPU directly modifies 7: * video memory to display characters, and sets two registers on the 6845 that 8: * specify the video origin and the cursor position. The video origin is the 9: * place in video memory where the first character (upper left corner) can 10: * be found. Moving the origin is a fast way to scroll the screen. Some 11: * video adapters wrap around the top of video memory, so the origin can 12: * move without bounds. For other adapters screen memory must sometimes be 13: * moved to reset the origin. All computations on video memory use character 14: * (word) addresses for simplicity and assume there is no wrapping. The 15: * assembly support functions translate the word addresses to byte addresses 16: * and the scrolling function worries about wrapping. 17: */ 18: 19: #include "kernel.h" 20: #include <termios.h> 21: #include <minix/callnr.h> 22: #include <minix/com.h> 23: #include "protect.h" 24: #include "tty.h" 25: #include "proc.h" 26: 27: /* Definitions used by the console driver. */ 28: #define MONO_BASE 0xB0000L /* base of mono video memory */ 29: #define COLOR_BASE 0xB8000L /* base of color video memory */ 30: #define MONO_SIZE 0x1000 /* 4K mono video memory */ 31: #define COLOR_SIZE 0x4000 /* 16K color video memory */ 32: #define EGA_SIZE 0x8000 /* EGA & VGA have at least 32K */ 33: #define BLANK_COLOR 0x0700 /* determines cursor color on blank screen */ 34: #define SCROLL_UP 0 /* scroll forward */ 35: #define SCROLL_DOWN 1 /* scroll backward */ 36: #define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */ 37: #define CONS_RAM_WORDS 80 /* video ram buffer size */ 38: #define MAX_ESC_PARMS 4 /* number of escape sequence params allowed */ 39: 40: /* Constants relating to the controller chips. */ 41: #define M_6845 0x3B4 /* port for 6845 mono */ 42: #define C_6845 0x3D4 /* port for 6845 color */ 43: #define INDEX 0 /* 6845's index register */ 44: #define DATA 1 /* 6845's data register */ 45: #define VID_ORG 12 /* 6845's origin register */ 46: #define CURSOR 14 /* 6845's cursor register */ 47: 48: /* Beeper. */ 49: #define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */ 50: #define B_TIME 3 /* length of CTRL-G beep is ticks */ 51: 52: /* definitions used for font management */ 53: #define GA_SEQUENCER_INDEX 0x3C4 54: #define GA_SEQUENCER_DATA 0x3C5 55: #define GA_GRAPHICS_INDEX 0x3CE 56: #define GA_GRAPHICS_DATA 0x3CF 57: #define GA_VIDEO_ADDRESS 0xA0000L 58: #define GA_FONT_SIZE 8192 59: 60: /* Global variables used by the console driver and assembly support. */ 61: PUBLIC u16_t vid_seg; 62: PUBLIC vir_bytes vid_off; /* video ram is found at vid_seg:vid_off */ 63: PUBLIC unsigned vid_size; /* 0x2000 for color or 0x0800 for mono */ 64: PUBLIC unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */ 65: PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */ 66: 67: /* Private variables used by the console driver. */ 68: PRIVATE int vid_port; /* I/O port for accessing 6845 */ 69: PRIVATE int wrap; /* hardware can wrap? */ 70: PRIVATE int softscroll; /* 1 = software scrolling, 0 = hardware */ 71: PRIVATE int beeping; /* speaker is beeping? */ 72: PRIVATE unsigned font_lines; /* font lines per character */ 73: PRIVATE unsigned scr_width; /* # characters on a line */ 74: PRIVATE unsigned scr_lines; /* # lines on the screen */ 75: PRIVATE unsigned scr_size; /* # characters on the screen */ 76: 77: /* Per console data. */ 78: typedef struct console { 79: tty_t *c_tty; /* associated TTY struct */ 80: int c_column; /* current column number (0-origin) */ 81: int c_row; /* current row (0 at top of screen) */ 82: int c_rwords; /* number of WORDS (not bytes) in outqueue */ 83: unsigned c_start; /* start of video memory of this console */ 84: unsigned c_limit; /* limit of this console's video memory */ 85: unsigned c_org; /* location in RAM where 6845 base points */ 86: unsigned c_cur; /* current position of cursor in video RAM */ 87: unsigned c_attr; /* character attribute */ 88: unsigned c_blank; /* blank attribute */ 89: char c_reverse; /* reverse video */ 90: char c_esc_state; /* 0=normal, 1=ESC, 2=ESC[ */ 91: char c_esc_intro; /* Distinguishing character following ESC */ 92: int *c_esc_parmp; /* pointer to current escape parameter */ 93: int c_esc_parmv[MAX_ESC_PARMS]; /* list of escape parameters */ 94: u16_t c_ramqueue[CONS_RAM_WORDS]; /* buffer for video RAM */ 95: } console_t; 96: 97: PRIVATE int nr_cons= 1; /* actual number of consoles */ 98: PRIVATE console_t cons_table[NR_CONS]; 99: PRIVATE console_t *curcons; /* currently visible */ 100: 101: /* Color if using a color controller. */ 102: #define color (vid_port == C_6845) 103: 104: /* Map from ANSI colors to the attributes used by the PC */ 105: PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7}; 106: 107: /* Structure used for font management */ 108: struct sequence { 109: unsigned short index; 110: unsigned char port; 111: unsigned char value; 112: }; 113: 114: FORWARD _PROTOTYPE( void cons_write, (struct tty *tp) ); 115: FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c) ); 116: FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c) ); 117: FORWARD _PROTOTYPE( void beep, (void) ); 118: FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c) ); 119: FORWARD _PROTOTYPE( void flush, (console_t *cons) ); 120: FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c) ); 121: FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir) ); 122: FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val) ); 123: FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp) ); 124: FORWARD _PROTOTYPE( void cons_org0, (void) ); 125: FORWARD _PROTOTYPE( void ga_program, (struct sequence *seq) ); 126: FORWARD _PROTOTYPE( void cons_ioctl, (tty_t *tp) ); 127: 128: 129: /*===========================================================================* 130: * cons_write * 131: *===========================================================================*/ 132: PRIVATE void cons_write(tp) 133: register struct tty *tp; /* tells which terminal is to be used */ 134: { 135: /* Copy as much data as possible to the output queue, then start I/O. On 136: * memory-mapped terminals, such as the IBM console, the I/O will also be 137: * finished, and the counts updated. Keep repeating until all I/O done. 138: */ 139: 140: int count; 141: register char *tbuf; 142: char buf[64]; 143: phys_bytes user_phys; 144: console_t *cons = tp->tty_priv; 145: 146: /* Check quickly for nothing to do, so this can be called often without 147: * unmodular tests elsewhere. 148: */ 149: if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return; 150: 151: /* Copy the user bytes to buf[] for decent addressing. Loop over the 152: * copies, since the user buffer may be much larger than buf[]. 153: */ 154: do { 155: if (count > sizeof(buf)) count = sizeof(buf); 156: user_phys = proc_vir2phys(proc_addr(tp->tty_outproc), tp->tty_out_vir); 157: phys_copy(user_phys, vir2phys(buf), (phys_bytes) count); 158: tbuf = buf; 159: 160: /* Update terminal data structure. */ 161: tp->tty_out_vir += count; 162: tp->tty_outcum += count; 163: tp->tty_outleft -= count; 164: 165: /* Output each byte of the copy to the screen. Avoid calling 166: * out_char() for the "easy" characters, put them into the buffer 167: * directly. 168: */ 169: do { 170: if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0 171: || cons->c_column >= scr_width 172: || cons->c_rwords >= buflen(cons->c_ramqueue)) 173: { 174: out_char(cons, *tbuf++); 175: } else { 176: cons->c_ramqueue[cons->c_rwords++] = 177: cons->c_attr | (*tbuf++ & BYTE); 178: cons->c_column++; 179: } 180: } while (--count != 0); 181: } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited); 182: 183: flush(cons); /* transfer anything buffered to the screen */ 184: 185: /* Reply to the writer if all output is finished. */ 186: if (tp->tty_outleft == 0) { 187: tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc, 188: tp->tty_outcum); 189: tp->tty_outcum = 0; 190: } 191: } 192: 193: 194: /*===========================================================================* 195: * cons_echo * 196: *===========================================================================*/ 197: PRIVATE void cons_echo(tp, c) 198: register tty_t *tp; /* pointer to tty struct */ 199: int c; /* character to be echoed */ 200: { 201: /* Echo keyboard input (print & flush). */ 202: console_t *cons = tp->tty_priv; 203: 204: out_char(cons, c); 205: flush(cons); 206: } 207: 208: 209: /*===========================================================================* 210: * out_char * 211: *===========================================================================*/ 212: PRIVATE void out_char(cons, c) 213: register console_t *cons; /* pointer to console struct */ 214: int c; /* character to be output */ 215: { 216: /* Output a character on the console. Check for escape sequences first. */ 217: if (cons->c_esc_state > 0) { 218: parse_escape(cons, c); 219: return; 220: } 221: 222: switch(c) { 223: case 000: /* null is typically used for padding */ 224: return; /* better not do anything */ 225: 226: case 007: /* ring the bell */ 227: flush(cons); /* print any chars queued for output */ 228: beep(); 229: return; 230: 231: case '\b': /* backspace */ 232: if (--cons->c_column < 0) { 233: if (--cons->c_row >= 0) cons->c_column += scr_width; 234: } 235: flush(cons); 236: return; 237: 238: case '\n': /* line feed */ 239: if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR)) 240: == (OPOST|ONLCR)) { 241: cons->c_column = 0; 242: } 243: /*FALL THROUGH*/ 244: case 013: /* CTRL-K */ 245: case 014: /* CTRL-L */ 246: if (cons->c_row == scr_lines-1) { 247: scroll_screen(cons, SCROLL_UP); 248: } else { 249: cons->c_row++; 250: } 251: flush(cons); 252: return; 253: 254: case '\r': /* carriage return */ 255: cons->c_column = 0; 256: flush(cons); 257: return; 258: 259: case '\t': /* tab */ 260: cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK; 261: if (cons->c_column > scr_width) { 262: cons->c_column -= scr_width; 263: if (cons->c_row == scr_lines-1) { 264: scroll_screen(cons, SCROLL_UP); 265: } else { 266: cons->c_row++; 267: } 268: } 269: flush(cons); 270: return; 271: 272: case 033: /* ESC - start of an escape sequence */ 273: flush(cons); /* print any chars queued for output */ 274: cons->c_esc_state = 1; /* mark ESC as seen */ 275: return; 276: 277: default: /* printable chars are stored in ramqueue */ 278: if (cons->c_column >= scr_width) { 279: if (!LINEWRAP) return; 280: if (cons->c_row == scr_lines-1) { 281: scroll_screen(cons, SCROLL_UP); 282: } else { 283: cons->c_row++; 284: } 285: cons->c_column = 0; 286: flush(cons); 287: } 288: if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons); 289: cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE); 290: cons->c_column++; /* next column */ 291: return; 292: } 293: } 294: 295: 296: /*===========================================================================* 297: * scroll_screen * 298: *===========================================================================*/ 299: PRIVATE void scroll_screen(cons, dir) 300: register console_t *cons; /* pointer to console struct */ 301: int dir; /* SCROLL_UP or SCROLL_DOWN */ 302: { 303: unsigned new_line, new_org, chars; 304: 305: flush(cons); 306: chars = scr_size - scr_width; /* one screen minus one line */ 307: 308: /* Scrolling the screen is a real nuisance due to the various incompatible 309: * video cards. This driver supports software scrolling (Hercules?), 310: * hardware scrolling (mono and CGA cards) and hardware scrolling without 311: * wrapping (EGA cards). In the latter case we must make sure that 312: * c_start <= c_org && c_org + scr_size <= c_limit 313: * holds, because EGA doesn't wrap around the end of video memory. 314: */ 315: if (dir == SCROLL_UP) { 316: /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */ 317: if (softscroll) { 318: vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars); 319: } else 320: if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) { 321: vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars); 322: cons->c_org = cons->c_start; 323: } else { 324: cons->c_org = (cons->c_org + scr_width) & vid_mask; 325: } 326: new_line = (cons->c_org + chars) & vid_mask; 327: } else { 328: /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */ 329: if (softscroll) { 330: vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars); 331: } else 332: if (!wrap && cons->c_org < cons->c_start + scr_width) { 333: new_org = cons->c_limit - scr_size; 334: vid_vid_copy(cons->c_org, new_org + scr_width, chars); 335: cons->c_org = new_org; 336: } else { 337: cons->c_org = (cons->c_org - scr_width) & vid_mask; 338: } 339: new_line = cons->c_org; 340: } 341: /* Blank the new line at top or bottom. */ 342: blank_color = cons->c_blank; 343: mem_vid_copy(BLANK_MEM, new_line, scr_width); 344: 345: /* Set the new video origin. */ 346: if (cons == curcons) set_6845(VID_ORG, cons->c_org); 347: flush(cons); 348: } 349: 350: 351: /*===========================================================================* 352: * flush * 353: *===========================================================================*/ 354: PRIVATE void flush(cons) 355: register console_t *cons; /* pointer to console struct */ 356: { 357: /* Send characters buffered in 'ramqueue' to screen memory, check the new 358: * cursor position, compute the new hardware cursor position and set it. 359: */ 360: unsigned cur; 361: tty_t *tp = cons->c_tty; 362: 363: /* Have the characters in 'ramqueue' transferred to the screen. */ 364: if (cons->c_rwords > 0) { 365: mem_vid_copy(cons->c_ramqueue, cons->c_cur, cons->c_rwords); 366: cons->c_rwords = 0; 367: 368: /* TTY likes to know the current column and if echoing messed up. */ 369: tp->tty_position = cons->c_column; 370: tp->tty_reprint = TRUE; 371: } 372: 373: /* Check and update the cursor position. */ 374: if (cons->c_column < 0) cons->c_column = 0; 375: if (cons->c_column > scr_width) cons->c_column = scr_width; 376: if (cons->c_row < 0) cons->c_row = 0; 377: if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1; 378: cur = cons->c_org + cons->c_row * scr_width + cons->c_column; 379: if (cur != cons->c_cur) { 380: if (cons == curcons) set_6845(CURSOR, cur); 381: cons->c_cur = cur; 382: } 383: } 384: 385: 386: /*===========================================================================* 387: * parse_escape * 388: *===========================================================================*/ 389: PRIVATE void parse_escape(cons, c) 390: register console_t *cons; /* pointer to console struct */ 391: char c; /* next character in escape sequence */ 392: { 393: /* The following ANSI escape sequences are currently supported. 394: * If n and/or m are omitted, they default to 1. 395: * ESC [nA moves up n lines 396: * ESC [nB moves down n lines 397: * ESC [nC moves right n spaces 398: * ESC [nD moves left n spaces 399: * ESC [m;nH" moves cursor to (m,n) 400: * ESC [J clears screen from cursor 401: * ESC [K clears line from cursor 402: * ESC [nL inserts n lines ar cursor 403: * ESC [nM deletes n lines at cursor 404: * ESC [nP deletes n chars at cursor 405: * ESC [n@ inserts n chars at cursor 406: * ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse) 407: * ESC M scrolls the screen backwards if the cursor is on the top line 408: */ 409: 410: switch (cons->c_esc_state) { 411: case 1: /* ESC seen */ 412: cons->c_esc_intro = '\0'; 413: cons->c_esc_parmp = bufend(cons->c_esc_parmv); 414: do { 415: *--cons->c_esc_parmp = 0; 416: } while (cons->c_esc_parmp > cons->c_esc_parmv); 417: switch (c) { 418: case '[': /* Control Sequence Introducer */ 419: cons->c_esc_intro = c; 420: cons->c_esc_state = 2; 421: break; 422: case 'M': /* Reverse Index */ 423: do_escape(cons, c); 424: break; 425: default: 426: cons->c_esc_state = 0; 427: } 428: break; 429: 430: case 2: /* ESC [ seen */ 431: if (c >= '0' && c <= '9') { 432: if (cons->c_esc_parmp < bufend(cons->c_esc_parmv)) 433: *cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'0'); 434: } else 435: if (c == ';') { 436: if (cons->c_esc_parmp < bufend(cons->c_esc_parmv)) 437: cons->c_esc_parmp++; 438: } else { 439: do_escape(cons, c); 440: } 441: break; 442: } 443: } 444: 445: 446: /*===========================================================================* 447: * do_escape * 448: *===========================================================================*/ 449: PRIVATE void do_escape(cons, c) 450: register console_t *cons; /* pointer to console struct */ 451: char c; /* next character in escape sequence */ 452: { 453: int value, n; 454: unsigned src, dst, count; 455: int *parmp; 456: 457: /* Some of these things hack on screen RAM, so it had better be up to date */ 458: flush(cons); 459: 460: if (cons->c_esc_intro == '\0') { 461: /* Handle a sequence beginning with just ESC */ 462: switch (c) { 463: case 'M': /* Reverse Index */ 464: if (cons->c_row == 0) { 465: scroll_screen(cons, SCROLL_DOWN); 466: } else { 467: cons->c_row--; 468: } 469: flush(cons); 470: break; 471: 472: default: break; 473: } 474: } else 475: if (cons->c_esc_intro == '[') { 476: /* Handle a sequence beginning with ESC [ and parameters */ 477: value = cons->c_esc_parmv[0]; 478: switch (c) { 479: case 'A': /* ESC [nA moves up n lines */ 480: n = (value == 0 ? 1 : value); 481: cons->c_row -= n; 482: flush(cons); 483: break; 484: 485: case 'B': /* ESC [nB moves down n lines */ 486: n = (value == 0 ? 1 : value); 487: cons->c_row += n; 488: flush(cons); 489: break; 490: 491: case 'C': /* ESC [nC moves right n spaces */ 492: n = (value == 0 ? 1 : value); 493: cons->c_column += n; 494: flush(cons); 495: break; 496: 497: case 'D': /* ESC [nD moves left n spaces */ 498: n = (value == 0 ? 1 : value); 499: cons->c_column -= n; 500: flush(cons); 501: break; 502: 503: case 'H': /* ESC [m;nH" moves cursor to (m,n) */ 504: cons->c_row = cons->c_esc_parmv[0] - 1; 505: cons->c_column = cons->c_esc_parmv[1] - 1; 506: flush(cons); 507: break; 508: 509: case 'J': /* ESC [sJ clears in display */ 510: switch (value) { 511: case 0: /* Clear from cursor to end of screen */ 512: count = scr_size - (cons->c_cur - cons->c_org); 513: dst = cons->c_cur; 514: break; 515: case 1: /* Clear from start of screen to cursor */ 516: count = cons->c_cur - cons->c_org; 517: dst = cons->c_org; 518: break; 519: case 2: /* Clear entire screen */ 520: count = scr_size; 521: dst = cons->c_org; 522: break; 523: default: /* Do nothing */ 524: count = 0; 525: dst = cons->c_org; 526: } 527: blank_color = cons->c_blank; 528: mem_vid_copy(BLANK_MEM, dst, count); 529: break; 530: 531: case 'K': /* ESC [sK clears line from cursor */ 532: switch (value) { 533: case 0: /* Clear from cursor to end of line */ 534: count = scr_width - cons->c_column; 535: dst = cons->c_cur; 536: break; 537: case 1: /* Clear from beginning of line to cursor */ 538: count = cons->c_column; 539: dst = cons->c_cur - cons->c_column; 540: break; 541: case 2: /* Clear entire line */ 542: count = scr_width; 543: dst = cons->c_cur - cons->c_column; 544: break; 545: default: /* Do nothing */ 546: count = 0; 547: dst = cons->c_cur; 548: } 549: blank_color = cons->c_blank; 550: mem_vid_copy(BLANK_MEM, dst, count); 551: break; 552: 553: case 'L': /* ESC [nL inserts n lines at cursor */ 554: n = value; 555: if (n < 1) n = 1; 556: if (n > (scr_lines - cons->c_row)) 557: n = scr_lines - cons->c_row; 558: 559: src = cons->c_org + cons->c_row * scr_width; 560: dst = src + n * scr_width; 561: count = (scr_lines - cons->c_row - n) * scr_width; 562: vid_vid_copy(src, dst, count); 563: blank_color = cons->c_blank; 564: mem_vid_copy(BLANK_MEM, src, n * scr_width); 565: break; 566: 567: case 'M': /* ESC [nM deletes n lines at cursor */ 568: n = value; 569: if (n < 1) n = 1; 570: if (n > (scr_lines - cons->c_row)) 571: n = scr_lines - cons->c_row; 572: 573: dst = cons->c_org + cons->c_row * scr_width; 574: src = dst + n * scr_width; 575: count = (scr_lines - cons->c_row - n) * scr_width; 576: vid_vid_copy(src, dst, count); 577: blank_color = cons->c_blank; 578: mem_vid_copy(BLANK_MEM, dst + count, n * scr_width); 579: break; 580: 581: case '@': /* ESC [n@ inserts n chars at cursor */ 582: n = value; 583: if (n < 1) n = 1; 584: if (n > (scr_width - cons->c_column)) 585: n = scr_width - cons->c_column; 586: 587: src = cons->c_cur; 588: dst = src + n; 589: count = scr_width - cons->c_column - n; 590: vid_vid_copy(src, dst, count); 591: blank_color = cons->c_blank; 592: mem_vid_copy(BLANK_MEM, src, n); 593: break; 594: 595: case 'P': /* ESC [nP deletes n chars at cursor */ 596: n = value; 597: if (n < 1) n = 1; 598: if (n > (scr_width - cons->c_column)) 599: n = scr_width - cons->c_column; 600: 601: dst = cons->c_cur; 602: src = dst + n; 603: count = scr_width - cons->c_column - n; 604: vid_vid_copy(src, dst, count); 605: blank_color = cons->c_blank; 606: mem_vid_copy(BLANK_MEM, dst + count, n); 607: break; 608: 609: case 'm': /* ESC [nm enables rendition n */ 610: for (parmp = cons->c_esc_parmv; parmp <= cons->c_esc_parmp 611: && parmp < bufend(cons->c_esc_parmv); parmp++) { 612: if (cons->c_reverse) { 613: /* Unswap fg and bg colors */ 614: cons->c_attr = ((cons->c_attr & 0x7000) >> 4) | 615: ((cons->c_attr & 0x0700) << 4) | 616: ((cons->c_attr & 0x8800)); 617: } 618: switch (n = *parmp) { 619: case 0: /* NORMAL */ 620: cons->c_attr = cons->c_blank = BLANK_COLOR; 621: cons->c_reverse = FALSE; 622: break; 623: 624: case 1: /* BOLD */ 625: /* Set intensity bit */ 626: cons->c_attr |= 0x0800; 627: break; 628: 629: case 4: /* UNDERLINE */ 630: if (color) { 631: /* Change white to cyan, i.e. lose red 632: */ 633: cons->c_attr = (cons->c_attr & 0xBBFF); 634: } else { 635: /* Set underline attribute */ 636: cons->c_attr = (cons->c_attr & 0x99FF); 637: } 638: break; 639: 640: case 5: /* BLINKING */ 641: /* Set the blink bit */ 642: cons->c_attr |= 0x8000; 643: break; 644: 645: case 7: /* REVERSE */ 646: cons->c_reverse = TRUE; 647: break; 648: 649: default: /* COLOR */ 650: if (n == 39) n = 37; /* set default color */ 651: if (n == 49) n = 40; 652: 653: if (!color) { 654: /* Don't mess up a monochrome screen */ 655: } else 656: if (30 <= n && n <= 37) { 657: /* Foreground color */ 658: cons->c_attr = 659: (cons->c_attr & 0xF8FF) | 660: (ansi_colors[(n - 30)] << 8); 661: cons->c_blank = 662: (cons->c_blank & 0xF8FF) | 663: (ansi_colors[(n - 30)] << 8); 664: } else 665: if (40 <= n && n <= 47) { 666: /* Background color */ 667: cons->c_attr = 668: (cons->c_attr & 0x8FFF) | 669: (ansi_colors[(n - 40)] << 12); 670: cons->c_blank = 671: (cons->c_blank & 0x8FFF) | 672: (ansi_colors[(n - 40)] << 12); 673: } 674: } 675: if (cons->c_reverse) { 676: /* Swap fg and bg colors */ 677: cons->c_attr = ((cons->c_attr & 0x7000) >> 4) | 678: ((cons->c_attr & 0x0700) << 4) | 679: ((cons->c_attr & 0x8800)); 680: } 681: } 682: break; 683: } 684: } 685: cons->c_esc_state = 0; 686: } 687: 688: 689: /*===========================================================================* 690: * set_6845 * 691: *===========================================================================*/ 692: PRIVATE void set_6845(reg, val) 693: int reg; /* which register pair to set */ 694: unsigned val; /* 16-bit value to set it to */ 695: { 696: /* Set a register pair inside the 6845. 697: * Registers 12-13 tell the 6845 where in video ram to start 698: * Registers 14-15 tell the 6845 where to put the cursor 699: */ 700: lock(); /* try to stop h/w loading in-between value */ 701: outb(vid_port + INDEX, reg); /* set the index register */ 702: outb(vid_port + DATA, (val>>8) & BYTE); /* output high byte */ 703: outb(vid_port + INDEX, reg + 1); /* again */ 704: outb(vid_port + DATA, val&BYTE); /* output low byte */ 705: unlock(); 706: } 707: 708: 709: /*===========================================================================* 710: * beep * 711: *===========================================================================*/ 712: PRIVATE void beep() 713: { 714: /* Making a beeping sound on the speaker (output for CRTL-G). 715: * This routine works by turning on the bits 0 and 1 in port B of the 8255 716: * chip that drive the speaker. 717: */ 718: 719: static timer_t tmr_stop_beep; 720: 721: if (!beeping) { 722: outb(TIMER_MODE, 0xB6); /* timer channel 2, square wave */ 723: outb(TIMER2, (BEEP_FREQ >> 0) & BYTE); /* low freq byte */ 724: outb(TIMER2, (BEEP_FREQ >> 8) & BYTE); /* high freq byte */ 725: lock(); /* guard PORT_B from keyboard intr handler */ 726: outb(PORT_B, inb(PORT_B) | 3); /* turn on beep bits */ 727: unlock(); 728: beeping = TRUE; 729: } 730: tmr_settimer(&tmr_stop_beep, TTY, get_uptime()+B_TIME, stop_beep); 731: } 732: 733: 734: /*===========================================================================* 735: * stop_beep * 736: *===========================================================================*/ 737: PRIVATE void stop_beep(tmrp) 738: timer_t *tmrp; 739: { 740: /* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */ 741: 742: lock(); /* guard PORT_B from keyboard intr handler */ 743: outb(PORT_B, inb(PORT_B) & ~3); 744: beeping = FALSE; 745: unlock(); 746: } 747: 748: 749: /*===========================================================================* 750: * scr_init * 751: *===========================================================================*/ 752: PUBLIC void scr_init(tp) 753: tty_t *tp; 754: { 755: /* Initialize the screen driver. */ 756: console_t *cons; 757: phys_bytes vid_base; 758: u16_t bios_columns, bios_crtbase, bios_fontlines; 759: u8_t bios_rows; 760: int line; 761: unsigned page_size; 762: 763: /* Associate console and TTY. */ 764: line = tp - &tty_table[0]; 765: if (line >= nr_cons) return; 766: cons = &cons_table[line]; 767: cons->c_tty = tp; 768: tp->tty_priv = cons; 769: 770: /* Initialize the keyboard driver. */ 771: kb_init(tp); 772: 773: /* Fill in TTY function hooks. */ 774: tp->tty_devwrite = cons_write; 775: tp->tty_echo = cons_echo; 776: tp->tty_ioctl = cons_ioctl; 777: 778: /* Get the BIOS parameters that describe the VDU. */ 779: phys_copy(0x44AL, vir2phys(&bios_columns), 2L); 780: phys_copy(0x463L, vir2phys(&bios_crtbase), 2L); 781: phys_copy(0x484L, vir2phys(&bios_rows), 1L); 782: phys_copy(0x485L, vir2phys(&bios_fontlines), 2L); 783: 784: vid_port = bios_crtbase; 785: scr_width = bios_columns; 786: font_lines = bios_fontlines; 787: scr_lines = ega ? bios_rows+1 : 25; 788: 789: if (color) { 790: vid_base = COLOR_BASE; 791: vid_size = COLOR_SIZE; 792: } else { 793: vid_base = MONO_BASE; 794: vid_size = MONO_SIZE; 795: } 796: if (ega) vid_size = EGA_SIZE; 797: wrap = !ega; 798: 799: phys2seg(&vid_seg, &vid_off, vid_base); 800: 801: vid_size >>= 1; /* word count */ 802: vid_mask = vid_size - 1; 803: 804: /* Size of the screen (number of displayed characters.) */ 805: scr_size = scr_lines * scr_width; 806: 807: /* There can be as many consoles as video memory allows. */ 808: nr_cons = vid_size / scr_size; 809: if (nr_cons > NR_CONS) nr_cons = NR_CONS; 810: if (nr_cons > 1) wrap = 0; 811: page_size = vid_size / nr_cons; 812: cons->c_start = line * page_size; 813: cons->c_limit = cons->c_start + page_size; 814: cons->c_cur = cons->c_org = cons->c_start; 815: cons->c_attr = cons->c_blank = BLANK_COLOR; 816: 817: /* Clear the screen. */ 818: blank_color = BLANK_COLOR; 819: mem_vid_copy(BLANK_MEM, cons->c_start, scr_size); 820: select_console(0); 821: cons_ioctl(tp); 822: } 823: 824: 825: /*===========================================================================* 826: * putk * 827: *===========================================================================*/ 828: PUBLIC void putk(c) 829: int c; /* character to print */ 830: { 831: /* This procedure is used by the version of printf() that is linked with 832: * the kernel itself. The one in the library sends a message to FS, which is 833: * not what is needed for printing within the kernel. This version just queues 834: * the character and starts the output. 835: */ 836: 837: if (c != 0) { 838: if (c == '\n') putk('\r'); 839: out_char(&cons_table[0], (int) c); 840: } else { 841: flush(&cons_table[0]); 842: } 843: } 844: 845: 846: /*===========================================================================* 847: * toggle_scroll * 848: *===========================================================================*/ 849: PUBLIC void toggle_scroll() 850: { 851: /* Toggle between hardware and software scroll. */ 852: 853: cons_org0(); 854: softscroll = !softscroll; 855: printf("%sware scrolling enabled.\n", softscroll ? "Soft" : "Hard"); 856: } 857: 858: 859: /*===========================================================================* 860: * cons_stop * 861: *===========================================================================*/ 862: PUBLIC void cons_stop() 863: { 864: /* Prepare for halt or reboot. */ 865: cons_org0(); 866: softscroll = 1; 867: select_console(0); 868: cons_table[0].c_attr = cons_table[0].c_blank = BLANK_COLOR; 869: } 870: 871: 872: /*===========================================================================* 873: * cons_org0 * 874: *===========================================================================*/ 875: PRIVATE void cons_org0() 876: { 877: /* Scroll video memory back to put the origin at 0. */ 878: int cons_line; 879: console_t *cons; 880: unsigned n; 881: 882: for (cons_line = 0; cons_line < nr_cons; cons_line++) { 883: cons = &cons_table[cons_line]; 884: while (cons->c_org > cons->c_start) { 885: n = vid_size - scr_size; /* amount of unused memory */ 886: if (n > cons->c_org - cons->c_start) 887: n = cons->c_org - cons->c_start; 888: vid_vid_copy(cons->c_org, cons->c_org - n, scr_size); 889: cons->c_org -= n; 890: } 891: flush(cons); 892: } 893: select_console(current); 894: } 895: 896: 897: /*===========================================================================* 898: * select_console * 899: *===========================================================================*/ 900: PUBLIC void select_console(int cons_line) 901: { 902: /* Set the current console to console number 'cons_line'. */ 903: 904: if (cons_line < 0 || cons_line >= nr_cons) return; 905: current = cons_line; 906: curcons = &cons_table[cons_line]; 907: set_6845(VID_ORG, curcons->c_org); 908: set_6845(CURSOR, curcons->c_cur); 909: } 910: 911: 912: /*===========================================================================* 913: * con_loadfont * 914: *===========================================================================*/ 915: PUBLIC int con_loadfont(user_phys) 916: phys_bytes user_phys; 917: { 918: /* Load a font into the EGA or VGA adapter. */ 919: static struct sequence seq1[7] = { 920: { GA_SEQUENCER_INDEX, 0x00, 0x01 }, 921: { GA_SEQUENCER_INDEX, 0x02, 0x04 }, 922: { GA_SEQUENCER_INDEX, 0x04, 0x07 }, 923: { GA_SEQUENCER_INDEX, 0x00, 0x03 }, 924: { GA_GRAPHICS_INDEX, 0x04, 0x02 }, 925: { GA_GRAPHICS_INDEX, 0x05, 0x00 }, 926: { GA_GRAPHICS_INDEX, 0x06, 0x00 }, 927: }; 928: static struct sequence seq2[7] = { 929: { GA_SEQUENCER_INDEX, 0x00, 0x01 }, 930: { GA_SEQUENCER_INDEX, 0x02, 0x03 }, 931: { GA_SEQUENCER_INDEX, 0x04, 0x03 }, 932: { GA_SEQUENCER_INDEX, 0x00, 0x03 }, 933: { GA_GRAPHICS_INDEX, 0x04, 0x00 }, 934: { GA_GRAPHICS_INDEX, 0x05, 0x10 }, 935: { GA_GRAPHICS_INDEX, 0x06, 0 }, 936: }; 937: 938: seq2[6].value= color ? 0x0E : 0x0A; 939: 940: if (!ega) return(ENOTTY); 941: 942: lock(); 943: ga_program(seq1); /* bring font memory into view */ 944: 945: phys_copy(user_phys, (phys_bytes)GA_VIDEO_ADDRESS, (phys_bytes)GA_FONT_SIZE); 946: 947: ga_program(seq2); /* restore */ 948: unlock(); 949: 950: return(OK); 951: } 952: 953: 954: /*===========================================================================* 955: * ga_program * 956: *===========================================================================*/ 957: PRIVATE void ga_program(seq) 958: struct sequence *seq; 959: { 960: int len= 7; 961: do { 962: outb(seq->index, seq->port); 963: outb(seq->index+1, seq->value); 964: seq++; 965: } while (--len > 0); 966: } 967: 968: 969: /*===========================================================================* 970: * cons_ioctl * 971: *===========================================================================*/ 972: PRIVATE void cons_ioctl(tp) 973: tty_t *tp; 974: { 975: /* Set the screen dimensions. */ 976: 977: tp->tty_winsize.ws_row= scr_lines; 978: tp->tty_winsize.ws_col= scr_width; 979: tp->tty_winsize.ws_xpixel= scr_width * 8; 980: tp->tty_winsize.ws_ypixel= scr_lines * font_lines; 981: }