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