1 /* $NetBSD: rcons_subr.c,v 1.2 1995/10/04 23:57:26 pk 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. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * @(#)rcons_subr.c 8.1 (Berkeley) 6/11/93 45 */ 46 47 #ifdef _KERNEL 48 #include <sys/param.h> 49 #include <sys/device.h> 50 #else 51 #include <sys/types.h> 52 #include "myfbdevice.h" 53 #endif 54 55 #include <dev/rcons/rcons.h> 56 #include <dev/rcons/raster.h> 57 58 #include "rcons_subr.h" 59 60 extern void rcons_bell(struct rconsole *); 61 62 #define RCONS_ISPRINT(c) ((((c) >= ' ') && ((c) <= '~')) || ((c) > 160)) 63 #define RCONS_ISDIGIT(c) ((c) >= '0' && (c) <= '9') 64 65 /* Output (or at least handle) a string sent to the console */ 66 void 67 rcons_puts(rc, str, n) 68 register struct rconsole *rc; 69 register unsigned char *str; 70 register int n; 71 { 72 register int c, i, j; 73 register unsigned char *cp; 74 75 /* Jump scroll */ 76 /* XXX maybe this should be an option? */ 77 if ((rc->rc_bits & FB_INESC) == 0) { 78 /* Count newlines up to an escape sequence */ 79 i = 0; 80 j = 0; 81 for (cp = str; j++ < n && *cp != '\033'; ++cp) { 82 if (*cp == '\n') 83 ++i; 84 else if (*cp == '\013') 85 --i; 86 } 87 88 /* Only jump scroll two or more rows */ 89 if (*rc->rc_row + i >= rc->rc_maxrow + 1) { 90 /* Erase the cursor (if necessary) */ 91 if (rc->rc_bits & FB_CURSOR) 92 rcons_cursor(rc); 93 94 rcons_scroll(rc, i); 95 } 96 } 97 98 /* Process characters */ 99 while (--n >= 0) { 100 c = *str; 101 if (c == '\033') { 102 /* Start an escape (perhaps aborting one in progress) */ 103 rc->rc_bits |= FB_INESC | FB_P0_DEFAULT | FB_P1_DEFAULT; 104 rc->rc_bits &= ~(FB_P0 | FB_P1); 105 106 /* Most parameters default to 1 */ 107 rc->rc_p0 = rc->rc_p1 = 1; 108 } else if (rc->rc_bits & FB_INESC) { 109 rcons_esc(rc, c); 110 } else { 111 /* Erase the cursor (if necessary) */ 112 if (rc->rc_bits & FB_CURSOR) 113 rcons_cursor(rc); 114 115 /* Display the character */ 116 if (RCONS_ISPRINT(c)) { 117 /* Try to output as much as possible */ 118 j = rc->rc_maxcol - (*rc->rc_col + 1); 119 if (j > n) 120 j = n; 121 for (i = 1; i < j && RCONS_ISPRINT(str[i]); ++i) 122 continue; 123 rcons_text(rc, str, i); 124 --i; 125 str += i; 126 n -= i; 127 } else 128 rcons_pctrl(rc, c); 129 } 130 ++str; 131 } 132 /* Redraw the cursor (if necessary) */ 133 if ((rc->rc_bits & FB_CURSOR) == 0) 134 rcons_cursor(rc); 135 } 136 137 /* Actually write a string to the frame buffer */ 138 void 139 rcons_text(rc, str, n) 140 register struct rconsole *rc; 141 register unsigned char *str; 142 register int n; 143 { 144 register int x, y, op; 145 146 x = *rc->rc_col * rc->rc_font->width + rc->rc_xorigin; 147 y = *rc->rc_row * rc->rc_font->height + 148 rc->rc_font->ascent + rc->rc_yorigin; 149 op = RAS_SRC; 150 if (((rc->rc_bits & FB_STANDOUT) != 0) ^ 151 ((rc->rc_bits & FB_INVERT) != 0)) 152 op = RAS_NOT(op); 153 raster_textn(rc->rc_sp, x, y, op, rc->rc_font, str, n); 154 *rc->rc_col += n; 155 if (*rc->rc_col >= rc->rc_maxcol) { 156 *rc->rc_col = 0; 157 (*rc->rc_row)++; 158 } 159 if (*rc->rc_row >= rc->rc_maxrow) 160 rcons_scroll(rc, 1); 161 } 162 163 /* Handle a control character sent to the console */ 164 void 165 rcons_pctrl(rc, c) 166 register struct rconsole *rc; 167 register int c; 168 { 169 170 switch (c) { 171 172 case '\r': /* Carriage return */ 173 *rc->rc_col = 0; 174 break; 175 176 case '\b': /* Backspace */ 177 if (*rc->rc_col > 0) 178 (*rc->rc_col)--; 179 break; 180 181 case '\013': /* Vertical tab */ 182 if (*rc->rc_row > 0) 183 (*rc->rc_row)--; 184 break; 185 186 case '\f': /* Formfeed */ 187 *rc->rc_row = *rc->rc_col = 0; 188 rcons_clear2eop(rc); 189 break; 190 191 case '\n': /* Linefeed */ 192 (*rc->rc_row)++; 193 if (*rc->rc_row >= rc->rc_maxrow) 194 rcons_scroll(rc, 1); 195 break; 196 197 case '\007': /* Bell */ 198 rcons_bell(rc); 199 break; 200 201 case '\t': /* Horizontal tab */ 202 *rc->rc_col = (*rc->rc_col + 8) & ~7; 203 if (*rc->rc_col >= rc->rc_maxcol) 204 *rc->rc_col = rc->rc_maxcol - 1; 205 break; 206 } 207 } 208 209 /* Handle the next character in an escape sequence */ 210 void 211 rcons_esc(rc, c) 212 register struct rconsole *rc; 213 register int c; 214 { 215 216 if (c == '[') { 217 /* Parameter 0 */ 218 rc->rc_bits &= ~FB_P1; 219 rc->rc_bits |= FB_P0; 220 } else if (c == ';') { 221 /* Parameter 1 */ 222 rc->rc_bits &= ~FB_P0; 223 rc->rc_bits |= FB_P1; 224 } else if (RCONS_ISDIGIT(c)) { 225 /* Add a digit to a parameter */ 226 if (rc->rc_bits & FB_P0) { 227 /* Parameter 0 */ 228 if (rc->rc_bits & FB_P0_DEFAULT) { 229 rc->rc_bits &= ~FB_P0_DEFAULT; 230 rc->rc_p0 = 0; 231 } 232 rc->rc_p0 *= 10; 233 rc->rc_p0 += c - '0'; 234 } else if (rc->rc_bits & FB_P1) { 235 /* Parameter 1 */ 236 if (rc->rc_bits & FB_P1_DEFAULT) { 237 rc->rc_bits &= ~FB_P1_DEFAULT; 238 rc->rc_p1 = 0; 239 } 240 rc->rc_p1 *= 10; 241 rc->rc_p1 += c - '0'; 242 } 243 } else { 244 /* Erase the cursor (if necessary) */ 245 if (rc->rc_bits & FB_CURSOR) 246 rcons_cursor(rc); 247 248 /* Process the completed escape sequence */ 249 rcons_doesc(rc, c); 250 rc->rc_bits &= ~FB_INESC; 251 } 252 } 253 254 /* Process a complete escape sequence */ 255 void 256 rcons_doesc(rc, c) 257 register struct rconsole *rc; 258 register int c; 259 { 260 261 #ifdef notdef 262 /* XXX add escape sequence to enable visual (and audible) bell */ 263 rc->rc_bits = FB_VISBELL; 264 #endif 265 266 switch (c) { 267 268 case '@': 269 /* Insert Character (ICH) */ 270 rcons_insertchar(rc, rc->rc_p0); 271 break; 272 273 case 'A': 274 /* Cursor Up (CUU) */ 275 *rc->rc_row -= rc->rc_p0; 276 if (*rc->rc_row < 0) 277 *rc->rc_row = 0; 278 break; 279 280 case 'B': 281 /* Cursor Down (CUD) */ 282 *rc->rc_row += rc->rc_p0; 283 if (*rc->rc_row >= rc->rc_maxrow) 284 *rc->rc_row = rc->rc_maxrow - 1; 285 break; 286 287 case 'C': 288 /* Cursor Forward (CUF) */ 289 *rc->rc_col += rc->rc_p0; 290 if (*rc->rc_col >= rc->rc_maxcol) 291 *rc->rc_col = rc->rc_maxcol - 1; 292 break; 293 294 case 'D': 295 /* Cursor Backward (CUB) */ 296 *rc->rc_col -= rc->rc_p0; 297 if (*rc->rc_col < 0) 298 *rc->rc_col = 0; 299 break; 300 301 case 'E': 302 /* Cursor Next Line (CNL) */ 303 *rc->rc_col = 0; 304 *rc->rc_row += rc->rc_p0; 305 if (*rc->rc_row >= rc->rc_maxrow) 306 *rc->rc_row = rc->rc_maxrow - 1; 307 break; 308 309 case 'f': 310 /* Horizontal And Vertical Position (HVP) */ 311 case 'H': 312 /* Cursor Position (CUP) */ 313 *rc->rc_col = rc->rc_p1 - 1; 314 if (*rc->rc_col < 0) 315 *rc->rc_col = 0; 316 else if (*rc->rc_col >= rc->rc_maxcol) 317 *rc->rc_col = rc->rc_maxcol - 1; 318 319 *rc->rc_row = rc->rc_p0 - 1; 320 if (*rc->rc_row < 0) 321 *rc->rc_row = 0; 322 else if (*rc->rc_row >= rc->rc_maxrow) 323 *rc->rc_row = rc->rc_maxrow - 1; 324 break; 325 326 case 'J': 327 /* Erase in Display (ED) */ 328 rcons_clear2eop(rc); 329 break; 330 331 case 'K': 332 /* Erase in Line (EL) */ 333 rcons_clear2eol(rc); 334 break; 335 336 case 'L': 337 /* Insert Line (IL) */ 338 rcons_insertline(rc, rc->rc_p0); 339 break; 340 341 case 'M': 342 /* Delete Line (DL) */ 343 rcons_delline(rc, rc->rc_p0); 344 break; 345 346 case 'P': 347 /* Delete Character (DCH) */ 348 rcons_delchar(rc, rc->rc_p0); 349 break; 350 351 case 'm': 352 /* Select Graphic Rendition (SGR); */ 353 /* (defaults to zero) */ 354 if (rc->rc_bits & FB_P0_DEFAULT) 355 rc->rc_p0 = 0; 356 if (rc->rc_p0) 357 rc->rc_bits |= FB_STANDOUT; 358 else 359 rc->rc_bits &= ~FB_STANDOUT; 360 break; 361 362 case 'p': 363 /* Black On White (SUNBOW) */ 364 rcons_invert(rc, 0); 365 break; 366 367 case 'q': 368 /* White On Black (SUNWOB) */ 369 rcons_invert(rc, 1); 370 break; 371 372 case 'r': 373 /* Set scrolling (SUNSCRL) */ 374 /* (defaults to zero) */ 375 if (rc->rc_bits & FB_P0_DEFAULT) 376 rc->rc_p0 = 0; 377 /* XXX not implemented yet */ 378 rc->rc_scroll = rc->rc_p0; 379 break; 380 381 case 's': 382 /* Reset terminal emulator (SUNRESET) */ 383 rc->rc_bits &= ~FB_STANDOUT; 384 rc->rc_scroll = 0; 385 if (rc->rc_bits & FB_INVERT) 386 rcons_invert(rc, 0); 387 break; 388 } 389 } 390 391 /* Paint (or unpaint) the cursor */ 392 void 393 rcons_cursor(rc) 394 register struct rconsole *rc; 395 { 396 register int x, y; 397 398 x = *rc->rc_col * rc->rc_font->width + rc->rc_xorigin; 399 y = *rc->rc_row * rc->rc_font->height + rc->rc_yorigin; 400 raster_op(rc->rc_sp, x, y, 401 #ifdef notdef 402 /* XXX This is the right way but too slow */ 403 rc->rc_font->chars[(int)' '].r->width, 404 rc->rc_font->chars[(int)' '].r->height, 405 #else 406 rc->rc_font->width, rc->rc_font->height, 407 #endif 408 RAS_INVERT, (struct raster *) 0, 0, 0); 409 rc->rc_bits ^= FB_CURSOR; 410 } 411 412 /* Possibly change to SUNWOB or SUNBOW mode */ 413 void 414 rcons_invert(rc, wob) 415 struct rconsole *rc; 416 int wob; 417 { 418 if (((rc->rc_bits & FB_INVERT) != 0) ^ wob) { 419 /* Invert the display */ 420 raster_op(rc->rc_sp, 0, 0, rc->rc_sp->width, rc->rc_sp->height, 421 RAS_INVERT, (struct raster *) 0, 0, 0); 422 423 /* Swap things around */ 424 rc->rc_ras_blank = RAS_NOT(rc->rc_ras_blank); 425 rc->rc_bits ^= FB_INVERT; 426 } 427 } 428 429 /* Clear to the end of the page */ 430 void 431 rcons_clear2eop(rc) 432 register struct rconsole *rc; 433 { 434 register int y; 435 436 if (*rc->rc_col == 0 && *rc->rc_row == 0) { 437 /* Clear the entire frame buffer */ 438 raster_op(rc->rc_sp, 0, 0, 439 rc->rc_sp->width, rc->rc_sp->height, 440 rc->rc_ras_blank, (struct raster *) 0, 0, 0); 441 } else { 442 /* Only clear what needs to be cleared */ 443 rcons_clear2eol(rc); 444 y = (*rc->rc_row + 1) * rc->rc_font->height; 445 446 raster_op(rc->rc_sp, rc->rc_xorigin, rc->rc_yorigin + y, 447 rc->rc_emuwidth, rc->rc_emuheight - y, 448 rc->rc_ras_blank, (struct raster *) 0, 0, 0); 449 } 450 } 451 452 /* Clear to the end of the line */ 453 void 454 rcons_clear2eol(rc) 455 register struct rconsole *rc; 456 { 457 register int x; 458 459 x = *rc->rc_col * rc->rc_font->width; 460 461 raster_op(rc->rc_sp, 462 rc->rc_xorigin + x, 463 *rc->rc_row * rc->rc_font->height + rc->rc_yorigin, 464 rc->rc_emuwidth - x, rc->rc_font->height, 465 rc->rc_ras_blank, (struct raster *) 0, 0, 0); 466 } 467 468 /* Scroll up one line */ 469 void 470 rcons_scroll(rc, n) 471 register struct rconsole *rc; 472 register int n; 473 { 474 register int ydiv; 475 476 /* Can't scroll more than the whole screen */ 477 if (n > rc->rc_maxrow) 478 n = rc->rc_maxrow; 479 480 /* Calculate new row */ 481 *rc->rc_row -= n; 482 if (*rc->rc_row < 0) 483 *rc->rc_row = 0; 484 485 /* Calculate number of pixels to scroll */ 486 ydiv = rc->rc_font->height * n; 487 488 raster_op(rc->rc_sp, rc->rc_xorigin, rc->rc_yorigin, 489 rc->rc_emuwidth, rc->rc_emuheight - ydiv, 490 RAS_SRC, rc->rc_sp, rc->rc_xorigin, ydiv + rc->rc_yorigin); 491 492 raster_op(rc->rc_sp, 493 rc->rc_xorigin, rc->rc_yorigin + rc->rc_emuheight - ydiv, 494 rc->rc_emuwidth, ydiv, rc->rc_ras_blank, (struct raster *) 0, 0, 0); 495 } 496 497 /* Delete characters */ 498 void 499 rcons_delchar(rc, n) 500 register struct rconsole *rc; 501 register int n; 502 { 503 register int tox, fromx, y, width; 504 505 /* Can't delete more chars than there are */ 506 if (n > rc->rc_maxcol - *rc->rc_col) 507 n = rc->rc_maxcol - *rc->rc_col; 508 509 fromx = (*rc->rc_col + n) * rc->rc_font->width; 510 tox = *rc->rc_col * rc->rc_font->width; 511 y = *rc->rc_row * rc->rc_font->height; 512 width = n * rc->rc_font->width; 513 514 raster_op(rc->rc_sp, tox + rc->rc_xorigin, y + rc->rc_yorigin, 515 rc->rc_emuwidth - fromx, rc->rc_font->height, 516 RAS_SRC, rc->rc_sp, fromx + rc->rc_xorigin, y + rc->rc_yorigin); 517 518 raster_op(rc->rc_sp, 519 rc->rc_emuwidth - width + rc->rc_xorigin, y + rc->rc_yorigin, 520 width, rc->rc_font->height, 521 rc->rc_ras_blank, (struct raster *) 0, 0, 0); 522 } 523 524 /* Delete a number of lines */ 525 void 526 rcons_delline(rc, n) 527 register struct rconsole *rc; 528 register int n; 529 { 530 register int fromy, toy, height; 531 532 /* Can't delete more lines than there are */ 533 if (n > rc->rc_maxrow - *rc->rc_row) 534 n = rc->rc_maxrow - *rc->rc_row; 535 536 fromy = (*rc->rc_row + n) * rc->rc_font->height; 537 toy = *rc->rc_row * rc->rc_font->height; 538 height = rc->rc_font->height * n; 539 540 raster_op(rc->rc_sp, rc->rc_xorigin, toy + rc->rc_yorigin, 541 rc->rc_emuwidth, rc->rc_emuheight - fromy, RAS_SRC, 542 rc->rc_sp, rc->rc_xorigin, fromy + rc->rc_yorigin); 543 544 raster_op(rc->rc_sp, 545 rc->rc_xorigin, rc->rc_emuheight - height + rc->rc_yorigin, 546 rc->rc_emuwidth, height, 547 rc->rc_ras_blank, (struct raster *) 0, 0, 0); 548 } 549 550 /* Insert some characters */ 551 void 552 rcons_insertchar(rc, n) 553 register struct rconsole *rc; 554 register int n; 555 { 556 register int tox, fromx, y; 557 558 /* Can't insert more chars than can fit */ 559 if (n > rc->rc_maxcol - *rc->rc_col) 560 n = rc->rc_maxcol - *rc->rc_col; 561 562 tox = (*rc->rc_col + n) * rc->rc_font->width; 563 fromx = *rc->rc_col * rc->rc_font->width; 564 y = *rc->rc_row * rc->rc_font->height; 565 566 raster_op(rc->rc_sp, tox + rc->rc_xorigin, y + rc->rc_yorigin, 567 rc->rc_emuwidth - tox, rc->rc_font->height, 568 RAS_SRC, rc->rc_sp, fromx + rc->rc_xorigin, y + rc->rc_yorigin); 569 570 raster_op(rc->rc_sp, fromx + rc->rc_xorigin, y + rc->rc_yorigin, 571 rc->rc_font->width * n, rc->rc_font->height, 572 rc->rc_ras_blank, (struct raster *) 0, 0, 0); 573 } 574 575 /* Insert some lines */ 576 void 577 rcons_insertline(rc, n) 578 register struct rconsole *rc; 579 register int n; 580 { 581 register int fromy, toy; 582 583 /* Can't insert more lines than can fit */ 584 if (n > rc->rc_maxrow - *rc->rc_row) 585 n = rc->rc_maxrow - *rc->rc_row; 586 587 toy = (*rc->rc_row + n) * rc->rc_font->height; 588 fromy = *rc->rc_row * rc->rc_font->height; 589 590 raster_op(rc->rc_sp, rc->rc_xorigin, toy + rc->rc_yorigin, 591 rc->rc_emuwidth, rc->rc_emuheight - toy, 592 RAS_SRC, rc->rc_sp, rc->rc_xorigin, fromy + rc->rc_yorigin); 593 594 raster_op(rc->rc_sp, rc->rc_xorigin, fromy + rc->rc_yorigin, 595 rc->rc_emuwidth, rc->rc_font->height * n, 596 rc->rc_ras_blank, (struct raster *) 0, 0, 0); 597 } 598