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