1 /* $NetBSD: rcons_subr.c,v 1.15 2005/12/11 12:23:44 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratory. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)rcons_subr.c 8.1 (Berkeley) 6/11/93 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: rcons_subr.c,v 1.15 2005/12/11 12:23:44 christos Exp $"); 45 46 #include <sys/param.h> 47 #ifdef _KERNEL 48 #include <sys/device.h> 49 #include <sys/systm.h> 50 #else 51 #include "myfbdevice.h" 52 #endif 53 54 #include <dev/rcons/rcons.h> 55 #include <dev/wscons/wsdisplayvar.h> 56 57 extern void rcons_bell(struct rconsole *); 58 59 #if 0 60 #define RCONS_ISPRINT(c) ((((c) >= ' ') && ((c) <= '~')) || ((c) > 160)) 61 #else 62 #define RCONS_ISPRINT(c) (((((c) >= ' ') && ((c) <= '~'))) || ((c) > 127)) 63 #endif 64 #define RCONS_ISDIGIT(c) ((c) >= '0' && (c) <= '9') 65 66 /* Initialize our operations set */ 67 void 68 rcons_init_ops(rc) 69 struct rconsole *rc; 70 { 71 long tmp; 72 int i, m; 73 74 m = sizeof(rc->rc_charmap) / sizeof(rc->rc_charmap[0]); 75 76 for (i = 0; i < m; i++) 77 rc->rc_ops->mapchar(rc->rc_cookie, i, rc->rc_charmap + i); 78 79 /* Determine which attributes the device supports. */ 80 #ifdef RASTERCONSOLE_FGCOL 81 rc->rc_deffgcolor = RASTERCONSOLE_FGCOL; 82 #endif 83 #ifdef RASTERCONSOLE_BGCOL 84 rc->rc_defbgcolor = RASTERCONSOLE_BGCOL; 85 #endif 86 rc->rc_fgcolor = rc->rc_deffgcolor; 87 rc->rc_bgcolor = rc->rc_defbgcolor; 88 rc->rc_supwsflg = 0; 89 90 for (i = 1; i < 256; i <<= 1) 91 if (rc->rc_ops->allocattr(rc->rc_cookie, 0, 0, i, &tmp) == 0) 92 rc->rc_supwsflg |= i; 93 94 /* Allocate kernel output attribute */ 95 rc->rc_wsflg = WSATTR_HILIT; 96 rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor); 97 rc->rc_kern_attr = rc->rc_attr; 98 99 rc->rc_wsflg = 0; 100 rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor); 101 rc->rc_defattr = rc->rc_attr; 102 } 103 104 /* Output (or at least handle) a string sent to the console */ 105 void 106 rcons_puts(rc, str, n) 107 struct rconsole *rc; 108 const unsigned char *str; 109 int n; 110 { 111 int c, i, j; 112 const unsigned char *cp; 113 114 /* Jump scroll */ 115 /* XXX maybe this should be an option? */ 116 if ((rc->rc_bits & FB_INESC) == 0) { 117 /* Count newlines up to an escape sequence */ 118 i = 0; 119 j = 0; 120 for (cp = str; j++ < n && *cp != '\033'; ++cp) { 121 if (*cp == '\n') 122 ++i; 123 else if (*cp == '\013') 124 --i; 125 } 126 127 /* Only jump scroll two or more rows */ 128 if (rc->rc_row + i > rc->rc_maxrow + 1) { 129 /* Erase the cursor (if necessary) */ 130 if (rc->rc_bits & FB_CURSOR) 131 rcons_cursor(rc); 132 133 rcons_scroll(rc, i); 134 } 135 } 136 137 /* Process characters */ 138 while (--n >= 0) { 139 c = *str; 140 if (c == '\033') { 141 /* Start an escape (perhaps aborting one in progress) */ 142 rc->rc_bits |= FB_INESC | FB_P0_DEFAULT | FB_P1_DEFAULT; 143 rc->rc_bits &= ~(FB_P0 | FB_P1); 144 145 /* Most parameters default to 1 */ 146 rc->rc_p0 = rc->rc_p1 = 1; 147 } else if (rc->rc_bits & FB_INESC) { 148 rcons_esc(rc, c); 149 } else { 150 /* Erase the cursor (if necessary) */ 151 if (rc->rc_bits & FB_CURSOR) 152 rcons_cursor(rc); 153 154 /* Display the character */ 155 if (RCONS_ISPRINT(c)) { 156 /* Try to output as much as possible */ 157 j = rc->rc_maxcol - rc->rc_col; 158 if (j > n) 159 j = n; 160 for (i = 1; i < j && RCONS_ISPRINT(str[i]); ++i) 161 continue; 162 rcons_text(rc, str, i); 163 --i; 164 str += i; 165 n -= i; 166 } else 167 rcons_pctrl(rc, c); 168 } 169 ++str; 170 } 171 /* Redraw the cursor (if necessary) */ 172 if ((rc->rc_bits & FB_CURSOR) == 0) 173 rcons_cursor(rc); 174 } 175 176 177 /* Handle a control character sent to the console */ 178 void 179 rcons_pctrl(rc, c) 180 struct rconsole *rc; 181 int c; 182 { 183 184 switch (c) { 185 case '\r': /* Carriage return */ 186 rc->rc_col = 0; 187 break; 188 189 case '\b': /* Backspace */ 190 if (rc->rc_col > 0) 191 (rc->rc_col)--; 192 break; 193 194 case '\v': /* Vertical tab */ 195 if (rc->rc_row > 0) 196 (rc->rc_row)--; 197 break; 198 199 case '\f': /* Formfeed */ 200 rc->rc_row = rc->rc_col = 0; 201 rcons_clear2eop(rc); 202 break; 203 204 case '\n': /* Linefeed */ 205 (rc->rc_row)++; 206 if (rc->rc_row >= rc->rc_maxrow) 207 rcons_scroll(rc, 1); 208 break; 209 210 case '\a': /* Bell */ 211 rcons_bell(rc); 212 break; 213 214 case '\t': /* Horizontal tab */ 215 rc->rc_col = (rc->rc_col + 8) & ~7; 216 if (rc->rc_col >= rc->rc_maxcol) 217 rc->rc_col = rc->rc_maxcol; 218 break; 219 } 220 } 221 222 /* Handle the next character in an escape sequence */ 223 void 224 rcons_esc(rc, c) 225 struct rconsole *rc; 226 int c; 227 { 228 229 if (c == '[') { 230 /* Parameter 0 */ 231 rc->rc_bits &= ~FB_P1; 232 rc->rc_bits |= FB_P0; 233 } else if (c == ';') { 234 /* Parameter 1 */ 235 rc->rc_bits &= ~FB_P0; 236 rc->rc_bits |= FB_P1; 237 } else if (RCONS_ISDIGIT(c)) { 238 /* Add a digit to a parameter */ 239 if (rc->rc_bits & FB_P0) { 240 /* Parameter 0 */ 241 if (rc->rc_bits & FB_P0_DEFAULT) { 242 rc->rc_bits &= ~FB_P0_DEFAULT; 243 rc->rc_p0 = 0; 244 } 245 rc->rc_p0 *= 10; 246 rc->rc_p0 += c - '0'; 247 } else if (rc->rc_bits & FB_P1) { 248 /* Parameter 1 */ 249 if (rc->rc_bits & FB_P1_DEFAULT) { 250 rc->rc_bits &= ~FB_P1_DEFAULT; 251 rc->rc_p1 = 0; 252 } 253 rc->rc_p1 *= 10; 254 rc->rc_p1 += c - '0'; 255 } 256 } else { 257 /* Erase the cursor (if necessary) */ 258 if (rc->rc_bits & FB_CURSOR) 259 rcons_cursor(rc); 260 261 /* Process the completed escape sequence */ 262 rcons_doesc(rc, c); 263 rc->rc_bits &= ~FB_INESC; 264 } 265 } 266 267 268 /* Handle an SGR (Select Graphic Rendition) escape */ 269 void 270 rcons_sgresc(rc, c) 271 struct rconsole *rc; 272 int c; 273 { 274 275 switch (c) { 276 /* Clear all attributes || End underline */ 277 case 0: 278 rc->rc_wsflg = 0; 279 rc->rc_fgcolor = rc->rc_deffgcolor; 280 rc->rc_bgcolor = rc->rc_defbgcolor; 281 rc->rc_attr = rc->rc_defattr; 282 break; 283 284 /* ANSI foreground color */ 285 case 30: case 31: case 32: case 33: 286 case 34: case 35: case 36: case 37: 287 rcons_setcolor(rc, c - 30, rc->rc_bgcolor); 288 break; 289 290 /* ANSI background color */ 291 case 40: case 41: case 42: case 43: 292 case 44: case 45: case 46: case 47: 293 rcons_setcolor(rc, rc->rc_fgcolor, c - 40); 294 break; 295 296 /* Begin reverse */ 297 case 7: 298 rc->rc_wsflg |= WSATTR_REVERSE; 299 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor); 300 break; 301 302 /* Begin bold */ 303 case 1: 304 rc->rc_wsflg |= WSATTR_HILIT; 305 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor); 306 break; 307 308 /* Begin underline */ 309 case 4: 310 rc->rc_wsflg |= WSATTR_UNDERLINE; 311 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor); 312 break; 313 } 314 } 315 316 317 /* Process a complete escape sequence */ 318 void 319 rcons_doesc(rc, c) 320 struct rconsole *rc; 321 int c; 322 { 323 324 #ifdef notdef 325 /* XXX add escape sequence to enable visual (and audible) bell */ 326 rc->rc_bits = FB_VISBELL; 327 #endif 328 329 switch (c) { 330 331 case '@': 332 /* Insert Character (ICH) */ 333 rcons_insertchar(rc, rc->rc_p0); 334 break; 335 336 case 'A': 337 /* Cursor Up (CUU) */ 338 rc->rc_row -= rc->rc_p0; 339 if (rc->rc_row < 0) 340 rc->rc_row = 0; 341 break; 342 343 case 'B': 344 /* Cursor Down (CUD) */ 345 rc->rc_row += rc->rc_p0; 346 if (rc->rc_row >= rc->rc_maxrow) 347 rc->rc_row = rc->rc_maxrow - 1; 348 break; 349 350 case 'C': 351 /* Cursor Forward (CUF) */ 352 rc->rc_col += rc->rc_p0; 353 if (rc->rc_col >= rc->rc_maxcol) 354 rc->rc_col = rc->rc_maxcol - 1; 355 break; 356 357 case 'D': 358 /* Cursor Backward (CUB) */ 359 rc->rc_col -= rc->rc_p0; 360 if (rc->rc_col < 0) 361 rc->rc_col = 0; 362 break; 363 364 case 'E': 365 /* Cursor Next Line (CNL) */ 366 rc->rc_col = 0; 367 rc->rc_row += rc->rc_p0; 368 if (rc->rc_row >= rc->rc_maxrow) 369 rc->rc_row = rc->rc_maxrow - 1; 370 break; 371 372 case 'f': 373 /* Horizontal And Vertical Position (HVP) */ 374 case 'H': 375 /* Cursor Position (CUP) */ 376 rc->rc_col = rc->rc_p1 - 1; 377 if (rc->rc_col < 0) 378 rc->rc_col = 0; 379 else if (rc->rc_col >= rc->rc_maxcol) 380 rc->rc_col = rc->rc_maxcol - 1; 381 382 rc->rc_row = rc->rc_p0 - 1; 383 if (rc->rc_row < 0) 384 rc->rc_row = 0; 385 else if (rc->rc_row >= rc->rc_maxrow) 386 rc->rc_row = rc->rc_maxrow - 1; 387 break; 388 389 case 'J': 390 /* Erase in Display (ED) */ 391 rcons_clear2eop(rc); 392 break; 393 394 case 'K': 395 /* Erase in Line (EL) */ 396 rcons_clear2eol(rc); 397 break; 398 399 case 'L': 400 /* Insert Line (IL) */ 401 rcons_insertline(rc, rc->rc_p0); 402 break; 403 404 case 'M': 405 /* Delete Line (DL) */ 406 rcons_delline(rc, rc->rc_p0); 407 break; 408 409 case 'P': 410 /* Delete Character (DCH) */ 411 rcons_delchar(rc, rc->rc_p0); 412 break; 413 414 case 'm': 415 /* Select Graphic Rendition (SGR) */ 416 /* (defaults to zero) */ 417 if (rc->rc_bits & FB_P0_DEFAULT) 418 rc->rc_p0 = 0; 419 420 if (rc->rc_bits & FB_P1_DEFAULT) 421 rc->rc_p1 = 0; 422 423 rcons_sgresc(rc, rc->rc_p0); 424 425 if (rc->rc_bits & FB_P1) 426 rcons_sgresc(rc, rc->rc_p1); 427 428 break; 429 430 /* 431 * XXX: setting SUNBOW and SUNWOB should probably affect 432 * deffgcolor, defbgcolor and defattr too. 433 */ 434 case 'p': 435 /* Black On White (SUNBOW) */ 436 rcons_setcolor(rc, WSCOL_BLACK, WSCOL_WHITE); 437 break; 438 439 case 'q': 440 /* White On Black (SUNWOB) */ 441 rcons_setcolor(rc, WSCOL_WHITE, WSCOL_BLACK); 442 break; 443 444 case 'r': 445 /* Set scrolling (SUNSCRL) */ 446 /* (defaults to zero) */ 447 if (rc->rc_bits & FB_P0_DEFAULT) 448 rc->rc_p0 = 0; 449 /* XXX not implemented yet */ 450 rc->rc_scroll = rc->rc_p0; 451 break; 452 453 case 's': 454 /* Reset terminal emulator (SUNRESET) */ 455 rc->rc_wsflg = 0; 456 rc->rc_scroll = 0; 457 rc->rc_bits &= ~FB_NO_CURSOR; 458 rc->rc_fgcolor = rc->rc_deffgcolor; 459 rc->rc_bgcolor = rc->rc_defbgcolor; 460 rc->rc_attr = rc->rc_defattr; 461 462 if (rc->rc_bits & FB_INVERT) 463 rcons_invert(rc, 0); 464 break; 465 #ifdef notyet 466 /* 467 * XXX following two read \E[?25h and \E[?25l. rcons 468 * can't currently handle the '?'. 469 */ 470 case 'h': 471 /* Normal/very visible cursor */ 472 if (rc->rc_p0 == 25) { 473 rc->rc_bits &= ~FB_NO_CURSOR; 474 475 if (rc->rc_bits & FB_CURSOR) { 476 rc->rc_bits ^= FB_CURSOR; 477 rcons_cursor(rc); 478 } 479 } 480 break; 481 482 case 'l': 483 /* Invisible cursor */ 484 if (rc->rc_p0 == 25 && (rc->rc_bits & FB_NO_CURSOR) == 0) { 485 if (rc->rc_bits & FB_CURSOR) 486 rcons_cursor(rc); 487 488 rc->rc_bits |= FB_NO_CURSOR; 489 } 490 break; 491 #endif 492 } 493 } 494 495 /* Set ANSI colors */ 496 void 497 rcons_setcolor(rc, fg, bg) 498 struct rconsole *rc; 499 int fg, bg; 500 { 501 int flg; 502 503 if (fg > WSCOL_WHITE || fg < 0) 504 return; 505 506 if (bg > WSCOL_WHITE || bg < 0) 507 return; 508 509 #ifdef RASTERCONS_WONB 510 flg = bg; 511 bg = fg; 512 fg = flg; 513 #endif 514 515 /* Emulate WSATTR_REVERSE attribute if it's not supported */ 516 if ((rc->rc_wsflg & WSATTR_REVERSE) && 517 !(rc->rc_supwsflg & WSATTR_REVERSE)) { 518 flg = bg; 519 bg = fg; 520 fg = flg; 521 } 522 523 /* 524 * Mask out unsupported flags and get attribute 525 * XXX - always ask for WSCOLORS if supported (why shouldn't we?) 526 */ 527 flg = (rc->rc_wsflg | WSATTR_WSCOLORS) & rc->rc_supwsflg; 528 rc->rc_bgcolor = bg; 529 rc->rc_fgcolor = fg; 530 rc->rc_ops->allocattr(rc->rc_cookie, fg, bg, flg, &rc->rc_attr); 531 } 532 533 534 /* Actually write a string to the frame buffer */ 535 void 536 rcons_text(rc, str, n) 537 struct rconsole *rc; 538 const unsigned char *str; 539 int n; 540 { 541 u_int uc; 542 543 while (n--) { 544 uc = rc->rc_charmap[*str++ & 255]; 545 rc->rc_ops->putchar(rc->rc_cookie, rc->rc_row, rc->rc_col++, 546 uc, rc->rc_attr); 547 } 548 549 if (rc->rc_col >= rc->rc_maxcol) { 550 rc->rc_col = 0; 551 rc->rc_row++; 552 } 553 554 if (rc->rc_row >= rc->rc_maxrow) 555 rcons_scroll(rc, 1); 556 } 557 558 /* Paint (or unpaint) the cursor */ 559 void 560 rcons_cursor(rc) 561 struct rconsole *rc; 562 { 563 rc->rc_bits ^= FB_CURSOR; 564 565 if (rc->rc_bits & FB_NO_CURSOR) 566 return; 567 568 rc->rc_ops->cursor(rc->rc_cookie, rc->rc_bits & FB_CURSOR, 569 rc->rc_row, rc->rc_col); 570 } 571 572 /* Possibly change to SUNWOB or SUNBOW mode */ 573 void 574 rcons_invert(rc, wob) 575 struct rconsole *rc; 576 int wob; 577 { 578 579 rc->rc_bits ^= FB_INVERT; 580 /* XXX how do we do we invert the framebuffer?? */ 581 } 582 583 /* Clear to the end of the page */ 584 void 585 rcons_clear2eop(rc) 586 struct rconsole *rc; 587 { 588 if (rc->rc_col || rc->rc_row) { 589 rcons_clear2eol(rc); 590 591 if (rc->rc_row < (rc->rc_maxrow - 1)) 592 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row + 1, 593 rc->rc_maxrow, rc->rc_attr); 594 } else 595 rc->rc_ops->eraserows(rc->rc_cookie, 0, rc->rc_maxrow, 596 rc->rc_attr); 597 } 598 599 /* Clear to the end of the line */ 600 void 601 rcons_clear2eol(rc) 602 struct rconsole *rc; 603 { 604 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col, 605 rc->rc_maxcol - rc->rc_col, rc->rc_attr); 606 } 607 608 609 /* Scroll up */ 610 void 611 rcons_scroll(rc, n) 612 struct rconsole *rc; 613 int n; 614 { 615 /* Can't scroll more than the whole screen */ 616 if (n > rc->rc_maxrow) 617 n = rc->rc_maxrow; 618 619 /* Calculate new row */ 620 rc->rc_row -= n; 621 622 if (rc->rc_row < 0) 623 rc->rc_row = 0; 624 625 rc->rc_ops->copyrows(rc->rc_cookie, n, 0, rc->rc_maxrow - n); 626 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n, rc->rc_attr); 627 } 628 629 /* Delete characters */ 630 void 631 rcons_delchar(rc, n) 632 struct rconsole *rc; 633 int n; 634 { 635 /* Can't delete more chars than there are */ 636 if (n > rc->rc_maxcol - rc->rc_col) 637 n = rc->rc_maxcol - rc->rc_col; 638 639 rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col + n, 640 rc->rc_col, rc->rc_maxcol - rc->rc_col - n); 641 642 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, 643 rc->rc_maxcol - n, n, rc->rc_attr); 644 } 645 646 /* Delete a number of lines */ 647 void 648 rcons_delline(rc, n) 649 struct rconsole *rc; 650 int n; 651 { 652 /* Can't delete more lines than there are */ 653 if (n > rc->rc_maxrow - rc->rc_row) 654 n = rc->rc_maxrow - rc->rc_row; 655 656 rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row + n, rc->rc_row, 657 rc->rc_maxrow - rc->rc_row - n); 658 659 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n, 660 rc->rc_attr); 661 } 662 663 /* Insert some characters */ 664 void 665 rcons_insertchar(rc, n) 666 struct rconsole *rc; 667 int n; 668 { 669 /* Can't insert more chars than can fit */ 670 if (n > rc->rc_maxcol - rc->rc_col) 671 n = rc->rc_maxcol - rc->rc_col - 1; 672 673 rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col, 674 rc->rc_col + n, rc->rc_maxcol - rc->rc_col - n - 1); 675 676 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col, 677 n, rc->rc_attr); 678 } 679 680 /* Insert some lines */ 681 void 682 rcons_insertline(rc, n) 683 struct rconsole *rc; 684 int n; 685 { 686 /* Can't insert more lines than can fit */ 687 if (n > rc->rc_maxrow - rc->rc_row) 688 n = rc->rc_maxrow - rc->rc_row; 689 690 rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row, rc->rc_row + n, 691 rc->rc_maxrow - rc->rc_row - n); 692 693 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row, n, 694 rc->rc_attr); 695 } 696 697 /* end of rcons_subr.c */ 698