1/* $NetBSD: rcons_subr.c,v 1.17 2009/03/14 15:36:20 dsl 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.17 2009/03/14 15:36:20 dsl 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 57extern 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 */ 67void 68rcons_init_ops(struct rconsole *rc) 69{ 70 long tmp; 71 int i, m; 72 73 m = sizeof(rc->rc_charmap) / sizeof(rc->rc_charmap[0]); 74 75 for (i = 0; i < m; i++) 76 rc->rc_ops->mapchar(rc->rc_cookie, i, rc->rc_charmap + i); 77 78 /* Determine which attributes the device supports. */ 79#ifdef RASTERCONSOLE_FGCOL 80 rc->rc_deffgcolor = RASTERCONSOLE_FGCOL; 81#endif 82#ifdef RASTERCONSOLE_BGCOL 83 rc->rc_defbgcolor = RASTERCONSOLE_BGCOL; 84#endif 85 rc->rc_fgcolor = rc->rc_deffgcolor; 86 rc->rc_bgcolor = rc->rc_defbgcolor; 87 rc->rc_supwsflg = 0; 88 89 for (i = 1; i < 256; i <<= 1) 90 if (rc->rc_ops->allocattr(rc->rc_cookie, 0, 0, i, &tmp) == 0) 91 rc->rc_supwsflg |= i; 92 93 /* Allocate kernel output attribute */ 94 rc->rc_wsflg = WSATTR_HILIT; 95 rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor); 96 rc->rc_kern_attr = rc->rc_attr; 97 98 rc->rc_wsflg = 0; 99 rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor); 100 rc->rc_defattr = rc->rc_attr; 101} 102 103/* Output (or at least handle) a string sent to the console */ 104void 105rcons_puts(struct rconsole *rc, const unsigned char *str, int n) 106{ 107 int c, i, j; 108 const unsigned char *cp; 109 110 /* Jump scroll */ 111 /* XXX maybe this should be an option? */ 112 if ((rc->rc_bits & FB_INESC) == 0) { 113 /* Count newlines up to an escape sequence */ 114 i = 0; 115 j = 0; 116 for (cp = str; j++ < n && *cp != '\033'; ++cp) { 117 if (*cp == '\n') 118 ++i; 119 else if (*cp == '\013') 120 --i; 121 } 122 123 /* Only jump scroll two or more rows */ 124 if (rc->rc_row + i > rc->rc_maxrow + 1) { 125 /* Erase the cursor (if necessary) */ 126 if (rc->rc_bits & FB_CURSOR) 127 rcons_cursor(rc); 128 129 rcons_scroll(rc, i); 130 } 131 } 132 133 /* Process characters */ 134 while (--n >= 0) { 135 c = *str; 136 if (c == '\033') { 137 /* Start an escape (perhaps aborting one in progress) */ 138 rc->rc_bits |= FB_INESC | FB_P0_DEFAULT | FB_P1_DEFAULT; 139 rc->rc_bits &= ~(FB_P0 | FB_P1); 140 141 /* Most parameters default to 1 */ 142 rc->rc_p0 = rc->rc_p1 = 1; 143 } else if (rc->rc_bits & FB_INESC) { 144 rcons_esc(rc, c); 145 } else { 146 /* Erase the cursor (if necessary) */ 147 if (rc->rc_bits & FB_CURSOR) 148 rcons_cursor(rc); 149 150 /* Display the character */ 151 if (RCONS_ISPRINT(c)) { 152 /* Try to output as much as possible */ 153 j = rc->rc_maxcol - rc->rc_col; 154 if (j > n) 155 j = n; 156 for (i = 1; i < j && RCONS_ISPRINT(str[i]); ++i) 157 continue; 158 rcons_text(rc, str, i); 159 --i; 160 str += i; 161 n -= i; 162 } else 163 rcons_pctrl(rc, c); 164 } 165 ++str; 166 } 167 /* Redraw the cursor (if necessary) */ 168 if ((rc->rc_bits & FB_CURSOR) == 0) 169 rcons_cursor(rc); 170} 171 172 173/* Handle a control character sent to the console */ 174void 175rcons_pctrl(struct rconsole *rc, int c) 176{ 177 178 switch (c) { 179 case '\r': /* Carriage return */ 180 rc->rc_col = 0; 181 break; 182 183 case '\b': /* Backspace */ 184 if (rc->rc_col > 0) 185 (rc->rc_col)--; 186 break; 187 188 case '\v': /* Vertical tab */ 189 if (rc->rc_row > 0) 190 (rc->rc_row)--; 191 break; 192 193 case '\f': /* Formfeed */ 194 rc->rc_row = rc->rc_col = 0; 195 rcons_clear2eop(rc); 196 break; 197 198 case '\n': /* Linefeed */ 199 (rc->rc_row)++; 200 if (rc->rc_row >= rc->rc_maxrow) 201 rcons_scroll(rc, 1); 202 break; 203 204 case '\a': /* Bell */ 205 rcons_bell(rc); 206 break; 207 208 case '\t': /* Horizontal tab */ 209 rc->rc_col = (rc->rc_col + 8) & ~7; 210 if (rc->rc_col >= rc->rc_maxcol) 211 rc->rc_col = rc->rc_maxcol; 212 break; 213 } 214} 215 216/* Handle the next character in an escape sequence */ 217void 218rcons_esc(struct rconsole *rc, int c) 219{ 220 221 if (c == '[') { 222 /* Parameter 0 */ 223 rc->rc_bits &= ~FB_P1; 224 rc->rc_bits |= FB_P0; 225 } else if (c == ';') { 226 /* Parameter 1 */ 227 rc->rc_bits &= ~FB_P0; 228 rc->rc_bits |= FB_P1; 229 } else if (RCONS_ISDIGIT(c)) { 230 /* Add a digit to a parameter */ 231 if (rc->rc_bits & FB_P0) { 232 /* Parameter 0 */ 233 if (rc->rc_bits & FB_P0_DEFAULT) { 234 rc->rc_bits &= ~FB_P0_DEFAULT; 235 rc->rc_p0 = 0; 236 } 237 rc->rc_p0 *= 10; 238 rc->rc_p0 += c - '0'; 239 } else if (rc->rc_bits & FB_P1) { 240 /* Parameter 1 */ 241 if (rc->rc_bits & FB_P1_DEFAULT) { 242 rc->rc_bits &= ~FB_P1_DEFAULT; 243 rc->rc_p1 = 0; 244 } 245 rc->rc_p1 *= 10; 246 rc->rc_p1 += c - '0'; 247 } 248 } else { 249 /* Erase the cursor (if necessary) */ 250 if (rc->rc_bits & FB_CURSOR) 251 rcons_cursor(rc); 252 253 /* Process the completed escape sequence */ 254 rcons_doesc(rc, c); 255 rc->rc_bits &= ~FB_INESC; 256 } 257} 258 259 260/* Handle an SGR (Select Graphic Rendition) escape */ 261void 262rcons_sgresc(struct rconsole *rc, int c) 263{ 264 265 switch (c) { 266 /* Clear all attributes || End underline */ 267 case 0: 268 rc->rc_wsflg = 0; 269 rc->rc_fgcolor = rc->rc_deffgcolor; 270 rc->rc_bgcolor = rc->rc_defbgcolor; 271 rc->rc_attr = rc->rc_defattr; 272 break; 273 274 /* ANSI foreground color */ 275 case 30: case 31: case 32: case 33: 276 case 34: case 35: case 36: case 37: 277 rcons_setcolor(rc, c - 30, rc->rc_bgcolor); 278 break; 279 280 /* ANSI background color */ 281 case 40: case 41: case 42: case 43: 282 case 44: case 45: case 46: case 47: 283 rcons_setcolor(rc, rc->rc_fgcolor, c - 40); 284 break; 285 286 /* Begin reverse */ 287 case 7: 288 rc->rc_wsflg |= WSATTR_REVERSE; 289 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor); 290 break; 291 292 /* Begin bold */ 293 case 1: 294 rc->rc_wsflg |= WSATTR_HILIT; 295 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor); 296 break; 297 298 /* Begin underline */ 299 case 4: 300 rc->rc_wsflg |= WSATTR_UNDERLINE; 301 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor); 302 break; 303 } 304} 305 306 307/* Process a complete escape sequence */ 308void 309rcons_doesc(struct rconsole *rc, int c) 310{ 311 312#ifdef notdef 313 /* XXX add escape sequence to enable visual (and audible) bell */ 314 rc->rc_bits = FB_VISBELL; 315#endif 316 317 switch (c) { 318 319 case '@': 320 /* Insert Character (ICH) */ 321 rcons_insertchar(rc, rc->rc_p0); 322 break; 323 324 case 'A': 325 /* Cursor Up (CUU) */ 326 if (rc->rc_row >= rc->rc_p0) 327 rc->rc_row -= rc->rc_p0; 328 else 329 rc->rc_row = 0; 330 break; 331 332 case 'B': 333 /* Cursor Down (CUD) */ 334 rc->rc_row += rc->rc_p0; 335 if (rc->rc_row >= rc->rc_maxrow) 336 rc->rc_row = rc->rc_maxrow - 1; 337 break; 338 339 case 'C': 340 /* Cursor Forward (CUF) */ 341 rc->rc_col += rc->rc_p0; 342 if (rc->rc_col >= rc->rc_maxcol) 343 rc->rc_col = rc->rc_maxcol - 1; 344 break; 345 346 case 'D': 347 /* Cursor Backward (CUB) */ 348 if (rc->rc_col >= rc->rc_p0) 349 rc->rc_col -= rc->rc_p0; 350 else 351 rc->rc_col = 0; 352 break; 353 354 case 'E': 355 /* Cursor Next Line (CNL) */ 356 rc->rc_col = 0; 357 rc->rc_row += rc->rc_p0; 358 if (rc->rc_row >= rc->rc_maxrow) 359 rc->rc_row = rc->rc_maxrow - 1; 360 break; 361 362 case 'f': 363 /* Horizontal And Vertical Position (HVP) */ 364 case 'H': 365 /* Cursor Position (CUP) */ 366 rc->rc_col = MIN(MAX(rc->rc_p1, 1), rc->rc_maxcol) - 1; 367 rc->rc_row = MIN(MAX(rc->rc_p0, 1), rc->rc_maxrow) - 1; 368 break; 369 370 case 'J': 371 /* Erase in Display (ED) */ 372 rcons_clear2eop(rc); 373 break; 374 375 case 'K': 376 /* Erase in Line (EL) */ 377 rcons_clear2eol(rc); 378 break; 379 380 case 'L': 381 /* Insert Line (IL) */ 382 rcons_insertline(rc, rc->rc_p0); 383 break; 384 385 case 'M': 386 /* Delete Line (DL) */ 387 rcons_delline(rc, rc->rc_p0); 388 break; 389 390 case 'P': 391 /* Delete Character (DCH) */ 392 rcons_delchar(rc, rc->rc_p0); 393 break; 394 395 case 'm': 396 /* Select Graphic Rendition (SGR) */ 397 /* (defaults to zero) */ 398 if (rc->rc_bits & FB_P0_DEFAULT) 399 rc->rc_p0 = 0; 400 401 if (rc->rc_bits & FB_P1_DEFAULT) 402 rc->rc_p1 = 0; 403 404 rcons_sgresc(rc, rc->rc_p0); 405 406 if (rc->rc_bits & FB_P1) 407 rcons_sgresc(rc, rc->rc_p1); 408 409 break; 410 411 /* 412 * XXX: setting SUNBOW and SUNWOB should probably affect 413 * deffgcolor, defbgcolor and defattr too. 414 */ 415 case 'p': 416 /* Black On White (SUNBOW) */ 417 rcons_setcolor(rc, WSCOL_BLACK, WSCOL_WHITE); 418 break; 419 420 case 'q': 421 /* White On Black (SUNWOB) */ 422 rcons_setcolor(rc, WSCOL_WHITE, WSCOL_BLACK); 423 break; 424 425 case 'r': 426 /* Set scrolling (SUNSCRL) */ 427 /* (defaults to zero) */ 428 if (rc->rc_bits & FB_P0_DEFAULT) 429 rc->rc_p0 = 0; 430 /* XXX not implemented yet */ 431 rc->rc_scroll = rc->rc_p0; 432 break; 433 434 case 's': 435 /* Reset terminal emulator (SUNRESET) */ 436 rc->rc_wsflg = 0; 437 rc->rc_scroll = 0; 438 rc->rc_bits &= ~FB_NO_CURSOR; 439 rc->rc_fgcolor = rc->rc_deffgcolor; 440 rc->rc_bgcolor = rc->rc_defbgcolor; 441 rc->rc_attr = rc->rc_defattr; 442 443 if (rc->rc_bits & FB_INVERT) 444 rcons_invert(rc, 0); 445 break; 446#ifdef notyet 447 /* 448 * XXX following two read \E[?25h and \E[?25l. rcons 449 * can't currently handle the '?'. 450 */ 451 case 'h': 452 /* Normal/very visible cursor */ 453 if (rc->rc_p0 == 25) { 454 rc->rc_bits &= ~FB_NO_CURSOR; 455 456 if (rc->rc_bits & FB_CURSOR) { 457 rc->rc_bits ^= FB_CURSOR; 458 rcons_cursor(rc); 459 } 460 } 461 break; 462 463 case 'l': 464 /* Invisible cursor */ 465 if (rc->rc_p0 == 25 && (rc->rc_bits & FB_NO_CURSOR) == 0) { 466 if (rc->rc_bits & FB_CURSOR) 467 rcons_cursor(rc); 468 469 rc->rc_bits |= FB_NO_CURSOR; 470 } 471 break; 472#endif 473 } 474} 475 476/* Set ANSI colors */ 477void 478rcons_setcolor(struct rconsole *rc, int fg, int bg) 479{ 480 int flg; 481 482 if (fg > WSCOL_WHITE || fg < 0) 483 return; 484 485 if (bg > WSCOL_WHITE || bg < 0) 486 return; 487 488#ifdef RASTERCONS_WONB 489 flg = bg; 490 bg = fg; 491 fg = flg; 492#endif 493 494 /* Emulate WSATTR_REVERSE attribute if it's not supported */ 495 if ((rc->rc_wsflg & WSATTR_REVERSE) && 496 !(rc->rc_supwsflg & WSATTR_REVERSE)) { 497 flg = bg; 498 bg = fg; 499 fg = flg; 500 } 501 502 /* 503 * Mask out unsupported flags and get attribute 504 * XXX - always ask for WSCOLORS if supported (why shouldn't we?) 505 */ 506 flg = (rc->rc_wsflg | WSATTR_WSCOLORS) & rc->rc_supwsflg; 507 rc->rc_bgcolor = bg; 508 rc->rc_fgcolor = fg; 509 rc->rc_ops->allocattr(rc->rc_cookie, fg, bg, flg, &rc->rc_attr); 510} 511 512 513/* Actually write a string to the frame buffer */ 514void 515rcons_text(struct rconsole *rc, const unsigned char *str, int n) 516{ 517 u_int uc; 518 519 while (n--) { 520 uc = rc->rc_charmap[*str++ & 255]; 521 rc->rc_ops->putchar(rc->rc_cookie, rc->rc_row, rc->rc_col++, 522 uc, rc->rc_attr); 523 } 524 525 if (rc->rc_col >= rc->rc_maxcol) { 526 rc->rc_col = 0; 527 rc->rc_row++; 528 } 529 530 if (rc->rc_row >= rc->rc_maxrow) 531 rcons_scroll(rc, 1); 532} 533 534/* Paint (or unpaint) the cursor */ 535void 536rcons_cursor(struct rconsole *rc) 537{ 538 rc->rc_bits ^= FB_CURSOR; 539 540 if (rc->rc_bits & FB_NO_CURSOR) 541 return; 542 543 rc->rc_ops->cursor(rc->rc_cookie, rc->rc_bits & FB_CURSOR, 544 rc->rc_row, rc->rc_col); 545} 546 547/* Possibly change to SUNWOB or SUNBOW mode */ 548void 549rcons_invert(struct rconsole *rc, int wob) 550{ 551 552 rc->rc_bits ^= FB_INVERT; 553 /* XXX how do we do we invert the framebuffer?? */ 554} 555 556/* Clear to the end of the page */ 557void 558rcons_clear2eop(struct rconsole *rc) 559{ 560 if (rc->rc_col || rc->rc_row) { 561 rcons_clear2eol(rc); 562 563 if (rc->rc_row < (rc->rc_maxrow - 1)) 564 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row + 1, 565 rc->rc_maxrow, rc->rc_attr); 566 } else 567 rc->rc_ops->eraserows(rc->rc_cookie, 0, rc->rc_maxrow, 568 rc->rc_attr); 569} 570 571/* Clear to the end of the line */ 572void 573rcons_clear2eol(struct rconsole *rc) 574{ 575 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col, 576 rc->rc_maxcol - rc->rc_col, rc->rc_attr); 577} 578 579 580/* Scroll up */ 581void 582rcons_scroll(struct rconsole *rc, int n) 583{ 584 /* Can't scroll more than the whole screen */ 585 if (n > rc->rc_maxrow) 586 n = rc->rc_maxrow; 587 588 /* Calculate new row */ 589 if (rc->rc_row >= n) 590 rc->rc_row -= n; 591 else 592 rc->rc_row = 0; 593 594 rc->rc_ops->copyrows(rc->rc_cookie, n, 0, rc->rc_maxrow - n); 595 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n, rc->rc_attr); 596} 597 598/* Delete characters */ 599void 600rcons_delchar(struct rconsole *rc, int n) 601{ 602 /* Can't delete more chars than there are */ 603 if (n > rc->rc_maxcol - rc->rc_col) 604 n = rc->rc_maxcol - rc->rc_col; 605 606 rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col + n, 607 rc->rc_col, rc->rc_maxcol - rc->rc_col - n); 608 609 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, 610 rc->rc_maxcol - n, n, rc->rc_attr); 611} 612 613/* Delete a number of lines */ 614void 615rcons_delline(struct rconsole *rc, int n) 616{ 617 /* Can't delete more lines than there are */ 618 if (n > rc->rc_maxrow - rc->rc_row) 619 n = rc->rc_maxrow - rc->rc_row; 620 621 rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row + n, rc->rc_row, 622 rc->rc_maxrow - rc->rc_row - n); 623 624 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n, 625 rc->rc_attr); 626} 627 628/* Insert some characters */ 629void 630rcons_insertchar(struct rconsole *rc, int n) 631{ 632 /* Can't insert more chars than can fit */ 633 if (n > rc->rc_maxcol - rc->rc_col) 634 n = rc->rc_maxcol - rc->rc_col - 1; 635 636 rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col, 637 rc->rc_col + n, rc->rc_maxcol - rc->rc_col - n - 1); 638 639 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col, 640 n, rc->rc_attr); 641} 642 643/* Insert some lines */ 644void 645rcons_insertline(struct rconsole *rc, int n) 646{ 647 /* Can't insert more lines than can fit */ 648 if (n > rc->rc_maxrow - rc->rc_row) 649 n = rc->rc_maxrow - rc->rc_row; 650 651 rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row, rc->rc_row + n, 652 rc->rc_maxrow - rc->rc_row - n); 653 654 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row, n, 655 rc->rc_attr); 656} 657 658/* end of rcons_subr.c */ 659