1 /* $OpenBSD: wsemul_sun.c,v 1.28 2009/09/05 16:51:19 miod Exp $ */ 2 /* $NetBSD: wsemul_sun.c,v 1.11 2000/01/05 11:19:36 drochner Exp $ */ 3 4 /* 5 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christopher G. Demetriou 18 * for the NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * This file implements a sun terminal personality for wscons. 36 * 37 * Derived from old rcons code. 38 * Color support from NetBSD's rcons color code, and wsemul_vt100. 39 */ 40 41 #ifndef SMALL_KERNEL 42 #define JUMP_SCROLL 43 #endif 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/time.h> 48 #include <sys/malloc.h> 49 #include <sys/fcntl.h> 50 51 #include <dev/wscons/wsconsio.h> 52 #include <dev/wscons/wsdisplayvar.h> 53 #include <dev/wscons/wsemulvar.h> 54 #include <dev/wscons/wsksymdef.h> 55 #include <dev/wscons/ascii.h> 56 57 void *wsemul_sun_cnattach(const struct wsscreen_descr *, void *, 58 int, int, long); 59 void *wsemul_sun_attach(int, const struct wsscreen_descr *, 60 void *, int, int, void *, long); 61 u_int wsemul_sun_output(void *, const u_char *, u_int, int); 62 int wsemul_sun_translate(void *, keysym_t, const char **); 63 void wsemul_sun_detach(void *, u_int *, u_int *); 64 void wsemul_sun_resetop(void *, enum wsemul_resetops); 65 66 const struct wsemul_ops wsemul_sun_ops = { 67 "sun", 68 wsemul_sun_cnattach, 69 wsemul_sun_attach, 70 wsemul_sun_output, 71 wsemul_sun_translate, 72 wsemul_sun_detach, 73 wsemul_sun_resetop 74 }; 75 76 #define SUN_EMUL_STATE_NORMAL 0 /* normal processing */ 77 #define SUN_EMUL_STATE_HAVEESC 1 /* seen start of ctl seq */ 78 #define SUN_EMUL_STATE_CONTROL 2 /* processing ctl seq */ 79 80 #define SUN_EMUL_NARGS 2 /* max # of args to a command */ 81 82 struct wsemul_sun_emuldata { 83 const struct wsdisplay_emulops *emulops; 84 struct wsemul_abortstate abortstate; 85 void *emulcookie; 86 void *cbcookie; 87 int scrcapabilities; 88 u_int nrows, ncols, crow, ccol; 89 long defattr; /* default attribute (rendition) */ 90 91 u_int state; /* processing state */ 92 u_int args[SUN_EMUL_NARGS]; /* command args, if CONTROL */ 93 int nargs; /* number of args */ 94 95 u_int scrolldist; /* distance to scroll */ 96 long curattr, bkgdattr; /* currently used attribute */ 97 long kernattr; /* attribute for kernel output */ 98 int attrflags, fgcol, bgcol; /* properties of curattr */ 99 100 #ifdef DIAGNOSTIC 101 int console; 102 #endif 103 }; 104 105 void wsemul_sun_init(struct wsemul_sun_emuldata *, 106 const struct wsscreen_descr *, void *, int, int, long); 107 int wsemul_sun_jump_scroll(struct wsemul_sun_emuldata *, const u_char *, 108 u_int, int); 109 void wsemul_sun_reset(struct wsemul_sun_emuldata *); 110 int wsemul_sun_output_lowchars(struct wsemul_sun_emuldata *, u_char, int); 111 int wsemul_sun_output_normal(struct wsemul_sun_emuldata *, u_char, int); 112 void wsemul_sun_output_haveesc(struct wsemul_sun_emuldata *, u_char); 113 int wsemul_sun_output_control(struct wsemul_sun_emuldata *, u_char); 114 int wsemul_sun_control(struct wsemul_sun_emuldata *, u_char); 115 int wsemul_sun_selectattribute(struct wsemul_sun_emuldata *, int, int, int, 116 long *, long *); 117 int wsemul_sun_scrollup(struct wsemul_sun_emuldata *, u_int); 118 119 struct wsemul_sun_emuldata wsemul_sun_console_emuldata; 120 121 /* some useful utility macros */ 122 #define ARG(n,c) \ 123 ((n) >= edp->nargs ? 0 : edp->args[(n) + MAX(0, edp->nargs - (c))]) 124 #define NORMALIZE(arg) ((arg) != 0 ? (arg) : 1) 125 #define COLS_LEFT (edp->ncols - 1 - edp->ccol) 126 #define ROWS_LEFT (edp->nrows - 1 - edp->crow) 127 128 void 129 wsemul_sun_init(struct wsemul_sun_emuldata *edp, 130 const struct wsscreen_descr *type, void *cookie, int ccol, int crow, 131 long defattr) 132 { 133 edp->emulops = type->textops; 134 edp->emulcookie = cookie; 135 edp->scrcapabilities = type->capabilities; 136 edp->nrows = type->nrows; 137 edp->ncols = type->ncols; 138 edp->crow = crow; 139 edp->ccol = ccol; 140 edp->defattr = defattr; 141 wsemul_reset_abortstate(&edp->abortstate); 142 } 143 144 void 145 wsemul_sun_reset(struct wsemul_sun_emuldata *edp) 146 { 147 edp->state = SUN_EMUL_STATE_NORMAL; 148 edp->bkgdattr = edp->curattr = edp->defattr; 149 edp->attrflags = 0; 150 edp->fgcol = WSCOL_BLACK; 151 edp->bgcol = WSCOL_WHITE; 152 edp->scrolldist = 1; 153 } 154 155 void * 156 wsemul_sun_cnattach(const struct wsscreen_descr *type, void *cookie, int ccol, 157 int crow, long defattr) 158 { 159 struct wsemul_sun_emuldata *edp; 160 int res; 161 162 edp = &wsemul_sun_console_emuldata; 163 wsemul_sun_init(edp, type, cookie, ccol, crow, defattr); 164 165 #ifndef WS_KERNEL_FG 166 #define WS_KERNEL_FG WSCOL_BLACK 167 #endif 168 #ifndef WS_KERNEL_BG 169 #define WS_KERNEL_BG WSCOL_WHITE 170 #endif 171 #ifndef WS_KERNEL_COLATTR 172 #define WS_KERNEL_COLATTR 0 173 #endif 174 #ifndef WS_KERNEL_MONOATTR 175 #define WS_KERNEL_MONOATTR 0 176 #endif 177 if (type->capabilities & WSSCREEN_WSCOLORS) 178 res = (*edp->emulops->alloc_attr)(cookie, 179 WS_KERNEL_FG, WS_KERNEL_BG, 180 WS_KERNEL_COLATTR | WSATTR_WSCOLORS, 181 &edp->kernattr); 182 else 183 res = (*edp->emulops->alloc_attr)(cookie, 0, 0, 184 WS_KERNEL_MONOATTR, 185 &edp->kernattr); 186 if (res) 187 edp->kernattr = defattr; 188 189 edp->cbcookie = NULL; 190 191 #ifdef DIAGNOSTIC 192 edp->console = 1; 193 #endif 194 195 wsemul_sun_reset(edp); 196 return (edp); 197 } 198 199 void * 200 wsemul_sun_attach(int console, const struct wsscreen_descr *type, void *cookie, 201 int ccol, int crow, void *cbcookie, long defattr) 202 { 203 struct wsemul_sun_emuldata *edp; 204 205 if (console) { 206 edp = &wsemul_sun_console_emuldata; 207 #ifdef DIAGNOSTIC 208 KASSERT(edp->console == 1); 209 #endif 210 } else { 211 edp = malloc(sizeof *edp, M_DEVBUF, M_NOWAIT); 212 if (edp == NULL) 213 return (NULL); 214 wsemul_sun_init(edp, type, cookie, ccol, crow, defattr); 215 216 #ifdef DIAGNOSTIC 217 edp->console = 0; 218 #endif 219 } 220 221 edp->cbcookie = cbcookie; 222 223 wsemul_sun_reset(edp); 224 return (edp); 225 } 226 227 int 228 wsemul_sun_output_lowchars(struct wsemul_sun_emuldata *edp, u_char c, 229 int kernel) 230 { 231 u_int n; 232 int rc = 0; 233 234 switch (c) { 235 case ASCII_NUL: 236 default: 237 /* ignore */ 238 break; 239 240 case ASCII_BEL: /* "Bell (BEL)" */ 241 wsdisplay_emulbell(edp->cbcookie); 242 break; 243 244 case ASCII_BS: /* "Backspace (BS)" */ 245 if (edp->ccol > 0) 246 edp->ccol--; 247 break; 248 249 case ASCII_CR: /* "Return (CR)" */ 250 edp->ccol = 0; 251 break; 252 253 case ASCII_HT: /* "Tab (TAB)" */ 254 n = min(8 - (edp->ccol & 7), COLS_LEFT); 255 if (n != 0) { 256 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 257 (edp->emulcookie, edp->crow, edp->ccol, n, 258 kernel ? edp->kernattr : edp->bkgdattr)); 259 if (rc != 0) 260 break; 261 edp->ccol += n; 262 } 263 break; 264 265 case ASCII_FF: /* "Form Feed (FF)" */ 266 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 267 (edp->emulcookie, 0, edp->nrows, edp->bkgdattr)); 268 if (rc != 0) 269 break; 270 edp->ccol = edp->crow = 0; 271 break; 272 273 case ASCII_VT: /* "Reverse Line Feed" */ 274 if (edp->crow > 0) 275 edp->crow--; 276 break; 277 278 case ASCII_ESC: /* "Escape (ESC)" */ 279 if (kernel) { 280 printf("wsemul_sun_output_lowchars: ESC in kernel " 281 "output ignored\n"); 282 break; /* ignore the ESC */ 283 } 284 285 edp->state = SUN_EMUL_STATE_HAVEESC; 286 break; 287 288 case ASCII_LF: /* "Line Feed (LF)" */ 289 /* if the cur line isn't the last, incr and leave. */ 290 if (ROWS_LEFT > 0) 291 edp->crow++; 292 else { 293 rc = wsemul_sun_scrollup(edp, edp->scrolldist); 294 if (rc != 0) 295 break; 296 } 297 break; 298 } 299 300 return rc; 301 } 302 303 int 304 wsemul_sun_output_normal(struct wsemul_sun_emuldata *edp, u_char c, int kernel) 305 { 306 int rc; 307 308 WSEMULOP(rc, edp, &edp->abortstate, putchar, 309 (edp->emulcookie, edp->crow, edp->ccol, 310 c, kernel ? edp->kernattr : edp->curattr)); 311 if (rc != 0) 312 return rc; 313 314 if (++edp->ccol >= edp->ncols) { 315 /* if the cur line isn't the last, incr and leave. */ 316 if (ROWS_LEFT > 0) 317 edp->crow++; 318 else { 319 rc = wsemul_sun_scrollup(edp, edp->scrolldist); 320 if (rc != 0) { 321 /* undo line wrap */ 322 edp->ccol--; 323 324 return rc; 325 } 326 } 327 edp->ccol = 0; 328 } 329 330 return 0; 331 } 332 333 void 334 wsemul_sun_output_haveesc(struct wsemul_sun_emuldata *edp, u_char c) 335 { 336 switch (c) { 337 case '[': /* continuation of multi-char sequence */ 338 edp->nargs = 0; 339 bzero(edp->args, sizeof (edp->args)); 340 edp->state = SUN_EMUL_STATE_CONTROL; 341 break; 342 343 default: 344 #ifdef DEBUG 345 printf("ESC%c unknown\n", c); 346 #endif 347 edp->state = SUN_EMUL_STATE_NORMAL; /* XXX is this wise? */ 348 break; 349 } 350 } 351 352 int 353 wsemul_sun_control(struct wsemul_sun_emuldata *edp, u_char c) 354 { 355 u_int n, src, dst; 356 int flags, fgcol, bgcol; 357 long attr, bkgdattr; 358 int rc = 0; 359 360 switch (c) { 361 case '@': /* "Insert Character (ICH)" */ 362 n = min(NORMALIZE(ARG(0,1)), COLS_LEFT + 1); 363 src = edp->ccol; 364 dst = edp->ccol + n; 365 if (dst < edp->ncols) { 366 WSEMULOP(rc, edp, &edp->abortstate, copycols, 367 (edp->emulcookie, edp->crow, src, dst, 368 edp->ncols - dst)); 369 if (rc != 0) 370 break; 371 } 372 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 373 (edp->emulcookie, edp->crow, src, n, edp->bkgdattr)); 374 break; 375 376 case 'A': /* "Cursor Up (CUU)" */ 377 edp->crow -= min(NORMALIZE(ARG(0,1)), edp->crow); 378 break; 379 380 case 'E': /* "Cursor Next Line (CNL)" */ 381 edp->ccol = 0; 382 /* FALLTHROUGH */ 383 case 'B': /* "Cursor Down (CUD)" */ 384 edp->crow += min(NORMALIZE(ARG(0,1)), ROWS_LEFT); 385 break; 386 387 case 'C': /* "Cursor Forward (CUF)" */ 388 edp->ccol += min(NORMALIZE(ARG(0,1)), COLS_LEFT); 389 break; 390 391 case 'D': /* "Cursor Backward (CUB)" */ 392 edp->ccol -= min(NORMALIZE(ARG(0,1)), edp->ccol); 393 break; 394 395 case 'f': /* "Horizontal And Vertical Position (HVP)" */ 396 case 'H': /* "Cursor Position (CUP)" */ 397 edp->crow = min(NORMALIZE(ARG(0,2)), edp->nrows) - 1; 398 edp->ccol = min(NORMALIZE(ARG(1,2)), edp->ncols) - 1; 399 break; 400 401 case 'J': /* "Erase in Display (ED)" */ 402 if (ROWS_LEFT > 0) { 403 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 404 (edp->emulcookie, edp->crow + 1, ROWS_LEFT, 405 edp->bkgdattr)); 406 if (rc != 0) 407 break; 408 } 409 /* FALLTHROUGH */ 410 case 'K': /* "Erase in Line (EL)" */ 411 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 412 (edp->emulcookie, edp->crow, edp->ccol, COLS_LEFT + 1, 413 edp->bkgdattr)); 414 break; 415 416 case 'L': /* "Insert Line (IL)" */ 417 n = min(NORMALIZE(ARG(0,1)), ROWS_LEFT + 1); 418 src = edp->crow; 419 dst = edp->crow + n; 420 if (dst < edp->nrows) { 421 WSEMULOP(rc, edp, &edp->abortstate, copyrows, 422 (edp->emulcookie, src, dst, edp->nrows - dst)); 423 if (rc != 0) 424 break; 425 } 426 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 427 (edp->emulcookie, src, n, edp->bkgdattr)); 428 break; 429 430 case 'M': /* "Delete Line (DL)" */ 431 n = min(NORMALIZE(ARG(0,1)), ROWS_LEFT + 1); 432 src = edp->crow + n; 433 dst = edp->crow; 434 if (src < edp->nrows) { 435 WSEMULOP(rc, edp, &edp->abortstate, copyrows, 436 (edp->emulcookie, src, dst, edp->nrows - src)); 437 if (rc != 0) 438 break; 439 } 440 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 441 (edp->emulcookie, dst + edp->nrows - src, n, 442 edp->bkgdattr)); 443 break; 444 445 case 'P': /* "Delete Character (DCH)" */ 446 n = min(NORMALIZE(ARG(0,1)), COLS_LEFT + 1); 447 src = edp->ccol + n; 448 dst = edp->ccol; 449 if (src < edp->ncols) { 450 WSEMULOP(rc, edp, &edp->abortstate, copycols, 451 (edp->emulcookie, edp->crow, src, dst, 452 edp->ncols - src)); 453 if (rc != 0) 454 break; 455 } 456 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 457 (edp->emulcookie, edp->crow, edp->ncols - n, n, 458 edp->bkgdattr)); 459 break; 460 461 case 'm': /* "Select Graphic Rendition (SGR)" */ 462 flags = edp->attrflags; 463 fgcol = edp->fgcol; 464 bgcol = edp->bgcol; 465 466 for (n = 0; n < edp->nargs; n++) { 467 switch (ARG(n,edp->nargs)) { 468 /* Clear all attributes || End underline */ 469 case 0: 470 if (n == edp->nargs - 1) { 471 edp->bkgdattr = 472 edp->curattr = edp->defattr; 473 edp->attrflags = 0; 474 edp->fgcol = WSCOL_BLACK; 475 edp->bgcol = WSCOL_WHITE; 476 return 0; 477 } 478 flags = 0; 479 fgcol = WSCOL_BLACK; 480 bgcol = WSCOL_WHITE; 481 break; 482 /* Begin bold */ 483 case 1: 484 flags |= WSATTR_HILIT; 485 break; 486 /* Begin underline */ 487 case 4: 488 flags |= WSATTR_UNDERLINE; 489 break; 490 /* Begin reverse */ 491 case 7: 492 flags |= WSATTR_REVERSE; 493 break; 494 /* ANSI foreground color */ 495 case 30: case 31: case 32: case 33: 496 case 34: case 35: case 36: case 37: 497 fgcol = ARG(n,edp->nargs) - 30; 498 break; 499 /* ANSI background color */ 500 case 40: case 41: case 42: case 43: 501 case 44: case 45: case 46: case 47: 502 bgcol = ARG(n,edp->nargs) - 40; 503 break; 504 } 505 } 506 setattr: 507 if (wsemul_sun_selectattribute(edp, flags, fgcol, bgcol, &attr, 508 &bkgdattr)) { 509 #ifdef DEBUG 510 printf("error allocating attr %d/%d/%x\n", 511 fgcol, bgcol, flags); 512 #endif 513 } else { 514 edp->curattr = attr; 515 edp->bkgdattr = bkgdattr; 516 edp->attrflags = flags; 517 edp->fgcol = fgcol; 518 edp->bgcol = bgcol; 519 } 520 break; 521 522 case 'p': /* "Black On White (SUNBOW)" */ 523 flags = 0; 524 fgcol = WSCOL_BLACK; 525 bgcol = WSCOL_WHITE; 526 goto setattr; 527 528 case 'q': /* "White On Black (SUNWOB)" */ 529 flags = 0; 530 fgcol = WSCOL_WHITE; 531 bgcol = WSCOL_BLACK; 532 goto setattr; 533 534 case 'r': /* "Set Scrolling (SUNSCRL)" */ 535 edp->scrolldist = min(ARG(0,1), edp->nrows); 536 break; 537 538 case 's': /* "Reset Terminal Emulator (SUNRESET)" */ 539 wsemul_sun_reset(edp); 540 break; 541 } 542 543 return rc; 544 } 545 546 int 547 wsemul_sun_output_control(struct wsemul_sun_emuldata *edp, u_char c) 548 { 549 int oargs; 550 int rc; 551 552 switch (c) { 553 case '0': case '1': case '2': case '3': case '4': /* argument digit */ 554 case '5': case '6': case '7': case '8': case '9': 555 /* 556 * If we receive more arguments than we are expecting, 557 * discard the earliest arguments. 558 */ 559 if (edp->nargs > SUN_EMUL_NARGS - 1) { 560 bcopy(edp->args + 1, edp->args, 561 (SUN_EMUL_NARGS - 1) * sizeof(edp->args[0])); 562 edp->args[edp->nargs = SUN_EMUL_NARGS - 1] = 0; 563 } 564 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) + 565 (c - '0'); 566 break; 567 568 case ';': /* argument terminator */ 569 edp->nargs++; 570 break; 571 572 default: /* end of escape sequence */ 573 oargs = edp->nargs++; 574 if (edp->nargs > SUN_EMUL_NARGS) 575 edp->nargs = SUN_EMUL_NARGS; 576 rc = wsemul_sun_control(edp, c); 577 if (rc != 0) { 578 /* undo nargs progress */ 579 edp->nargs = oargs; 580 581 return rc; 582 } 583 edp->state = SUN_EMUL_STATE_NORMAL; 584 break; 585 } 586 587 return 0; 588 } 589 590 u_int 591 wsemul_sun_output(void *cookie, const u_char *data, u_int count, int kernel) 592 { 593 struct wsemul_sun_emuldata *edp = cookie; 594 u_int processed = 0; 595 u_char c; 596 #ifdef JUMP_SCROLL 597 int lines; 598 #endif 599 int rc = 0; 600 601 #ifdef DIAGNOSTIC 602 if (kernel && !edp->console) 603 panic("wsemul_sun_output: kernel output, not console"); 604 #endif 605 606 switch (edp->abortstate.state) { 607 case ABORT_FAILED_CURSOR: 608 /* 609 * If we could not display the cursor back, we pretended not 610 * having been able to display the last character. But this 611 * is a lie, so compensate here. 612 */ 613 data++, count--; 614 processed++; 615 wsemul_reset_abortstate(&edp->abortstate); 616 break; 617 case ABORT_OK: 618 /* remove cursor image */ 619 rc = (*edp->emulops->cursor) 620 (edp->emulcookie, 0, edp->crow, edp->ccol); 621 if (rc != 0) 622 return 0; 623 break; 624 default: 625 break; 626 } 627 628 for (; count > 0; data++, count--) { 629 #ifdef JUMP_SCROLL 630 switch (edp->abortstate.state) { 631 case ABORT_FAILED_JUMP_SCROLL: 632 /* 633 * If we failed a previous jump scroll attempt, we 634 * need to try to resume it with the same distance. 635 * We can not recompute it since there might be more 636 * bytes in the tty ring, causing a different result. 637 */ 638 lines = edp->abortstate.lines; 639 break; 640 case ABORT_OK: 641 /* 642 * If scrolling is not disabled and we are the bottom of 643 * the screen, count newlines until an escape sequence 644 * appears. 645 */ 646 if ((edp->state == SUN_EMUL_STATE_NORMAL || kernel) && 647 ROWS_LEFT == 0 && edp->scrolldist != 0) 648 lines = wsemul_sun_jump_scroll(edp, data, 649 count, kernel); 650 else 651 lines = 0; 652 break; 653 default: 654 /* 655 * If we are recovering a non-scrolling failure, 656 * do not try to scroll yet. 657 */ 658 lines = 0; 659 break; 660 } 661 662 if (lines > 1) { 663 wsemul_resume_abort(&edp->abortstate); 664 rc = wsemul_sun_scrollup(edp, lines); 665 if (rc != 0) { 666 wsemul_abort_jump_scroll(&edp->abortstate, 667 lines); 668 return processed; 669 } 670 wsemul_reset_abortstate(&edp->abortstate); 671 edp->crow--; 672 } 673 #endif 674 675 wsemul_resume_abort(&edp->abortstate); 676 677 c = *data; 678 if (c < ' ') { 679 rc = wsemul_sun_output_lowchars(edp, c, kernel); 680 if (rc != 0) 681 break; 682 processed++; 683 continue; 684 } 685 686 if (kernel) { 687 rc = wsemul_sun_output_normal(edp, c, 1); 688 if (rc != 0) 689 break; 690 processed++; 691 continue; 692 } 693 694 switch (edp->state) { 695 case SUN_EMUL_STATE_NORMAL: 696 rc = wsemul_sun_output_normal(edp, c, 0); 697 break; 698 case SUN_EMUL_STATE_HAVEESC: 699 wsemul_sun_output_haveesc(edp, c); 700 break; 701 case SUN_EMUL_STATE_CONTROL: 702 rc = wsemul_sun_output_control(edp, c); 703 break; 704 default: 705 #ifdef DIAGNOSTIC 706 panic("wsemul_sun: invalid state %d", edp->state); 707 #else 708 /* try to recover, if things get screwed up... */ 709 edp->state = SUN_EMUL_STATE_NORMAL; 710 rc = wsemul_sun_output_normal(edp, c, 0); 711 #endif 712 break; 713 } 714 if (rc != 0) 715 break; 716 processed++; 717 } 718 719 if (rc != 0) 720 wsemul_abort_other(&edp->abortstate); 721 else { 722 /* put cursor image back */ 723 rc = (*edp->emulops->cursor) 724 (edp->emulcookie, 1, edp->crow, edp->ccol); 725 if (rc != 0) { 726 /* 727 * Fail the last character output, remembering that 728 * only the cursor operation really needs to be done. 729 */ 730 wsemul_abort_cursor(&edp->abortstate); 731 processed--; 732 } 733 } 734 735 if (rc == 0) 736 wsemul_reset_abortstate(&edp->abortstate); 737 738 return processed; 739 } 740 741 #ifdef JUMP_SCROLL 742 int 743 wsemul_sun_jump_scroll(struct wsemul_sun_emuldata *edp, const u_char *data, 744 u_int count, int kernel) 745 { 746 u_char curchar; 747 u_int pos, lines; 748 749 lines = 0; 750 pos = edp->ccol; 751 for (; count != 0; data++, count--) { 752 curchar = *data; 753 if (curchar == ASCII_FF || 754 curchar == ASCII_VT || curchar == ASCII_ESC) 755 break; 756 757 switch (curchar) { 758 case ASCII_BS: 759 if (pos > 0) 760 pos--; 761 break; 762 case ASCII_CR: 763 pos = 0; 764 break; 765 case ASCII_HT: 766 pos = (pos + 7) & ~7; 767 if (pos >= edp->ncols) 768 pos = edp->ncols - 1; 769 break; 770 case ASCII_LF: 771 break; 772 default: 773 if (++pos >= edp->ncols) { 774 pos = 0; 775 curchar = ASCII_LF; 776 } 777 break; 778 } 779 if (curchar == ASCII_LF) { 780 if (++lines >= edp->nrows - 1) 781 break; 782 } 783 } 784 785 return lines; 786 } 787 #endif 788 789 /* 790 * Get an attribute from the graphics driver. 791 * Try to find replacements if the desired appearance is not supported. 792 */ 793 int 794 wsemul_sun_selectattribute(struct wsemul_sun_emuldata *edp, int flags, 795 int fgcol, int bgcol, long *attr, long *bkgdattr) 796 { 797 int error; 798 799 /* 800 * Rasops will force white on black as normal output colors, unless 801 * WSATTR_WSCOLORS is specified. Since Sun console is black on white, 802 * always use WSATTR_WSCOLORS and our colors, as we know better. 803 */ 804 if (!(edp->scrcapabilities & WSSCREEN_WSCOLORS)) { 805 flags &= ~WSATTR_WSCOLORS; 806 } else { 807 flags |= WSATTR_WSCOLORS; 808 } 809 810 error = (*edp->emulops->alloc_attr)(edp->emulcookie, fgcol, bgcol, 811 flags & WSATTR_WSCOLORS, bkgdattr); 812 if (error) 813 return (error); 814 815 if ((flags & WSATTR_HILIT) && 816 !(edp->scrcapabilities & WSSCREEN_HILIT)) { 817 flags &= ~WSATTR_HILIT; 818 if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { 819 fgcol = WSCOL_RED; 820 flags |= WSATTR_WSCOLORS; 821 } 822 } 823 if ((flags & WSATTR_UNDERLINE) && 824 !(edp->scrcapabilities & WSSCREEN_UNDERLINE)) { 825 flags &= ~WSATTR_UNDERLINE; 826 if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { 827 fgcol = WSCOL_CYAN; 828 flags &= ~WSATTR_UNDERLINE; 829 flags |= WSATTR_WSCOLORS; 830 } 831 } 832 if ((flags & WSATTR_BLINK) && 833 !(edp->scrcapabilities & WSSCREEN_BLINK)) { 834 flags &= ~WSATTR_BLINK; 835 } 836 if ((flags & WSATTR_REVERSE) && 837 !(edp->scrcapabilities & WSSCREEN_REVERSE)) { 838 flags &= ~WSATTR_REVERSE; 839 if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { 840 int help; 841 help = bgcol; 842 bgcol = fgcol; 843 fgcol = help; 844 flags |= WSATTR_WSCOLORS; 845 } 846 } 847 error = (*edp->emulops->alloc_attr)(edp->emulcookie, fgcol, bgcol, 848 flags, attr); 849 if (error) 850 return (error); 851 852 return (0); 853 } 854 855 static const char *sun_fkeys[] = { 856 "\033[224z", /* F1 */ 857 "\033[225z", 858 "\033[226z", 859 "\033[227z", 860 "\033[228z", 861 "\033[229z", 862 "\033[230z", 863 "\033[231z", 864 "\033[232z", 865 "\033[233z", 866 "\033[234z", 867 "\033[235z", /* F12 */ 868 }; 869 870 static const char *sun_lkeys[] = { 871 "\033[207z", /* KS_Help */ 872 NULL, /* KS_Execute */ 873 "\033[200z", /* KS_Find */ 874 NULL, /* KS_Select */ 875 "\033[193z", /* KS_Again */ 876 "\033[194z", /* KS_Props */ 877 "\033[195z", /* KS_Undo */ 878 "\033[196z", /* KS_Front */ 879 "\033[197z", /* KS_Copy */ 880 "\033[198z", /* KS_Open */ 881 "\033[199z", /* KS_Paste */ 882 "\033[201z", /* KS_Cut */ 883 }; 884 885 int 886 wsemul_sun_translate(void *cookie, keysym_t in, const char **out) 887 { 888 static char c; 889 890 if (KS_GROUP(in) == KS_GROUP_Keypad && (in & 0x80) == 0) { 891 c = in & 0xff; /* turn into ASCII */ 892 *out = &c; 893 return (1); 894 } 895 896 if (in >= KS_f1 && in <= KS_f12) { 897 *out = sun_fkeys[in - KS_f1]; 898 return (6); 899 } 900 if (in >= KS_F1 && in <= KS_F12) { 901 *out = sun_fkeys[in - KS_F1]; 902 return (6); 903 } 904 if (in >= KS_KP_F1 && in <= KS_KP_F4) { 905 *out = sun_fkeys[in - KS_KP_F1]; 906 return (6); 907 } 908 if (in >= KS_Help && in <= KS_Cut && sun_lkeys[in - KS_Help] != NULL) { 909 *out = sun_lkeys[in - KS_Help]; 910 return (6); 911 } 912 913 switch (in) { 914 case KS_Home: 915 case KS_KP_Home: 916 case KS_KP_Begin: 917 *out = "\033[214z"; 918 return (6); 919 case KS_End: 920 case KS_KP_End: 921 *out = "\033[220z"; 922 return (6); 923 case KS_Insert: 924 case KS_KP_Insert: 925 *out = "\033[247z"; 926 return (6); 927 case KS_Prior: 928 case KS_KP_Prior: 929 *out = "\033[216z"; 930 return (6); 931 case KS_Next: 932 case KS_KP_Next: 933 *out = "\033[222z"; 934 return (6); 935 case KS_Up: 936 case KS_KP_Up: 937 *out = "\033[A"; 938 return (3); 939 case KS_Down: 940 case KS_KP_Down: 941 *out = "\033[B"; 942 return (3); 943 case KS_Left: 944 case KS_KP_Left: 945 *out = "\033[D"; 946 return (3); 947 case KS_Right: 948 case KS_KP_Right: 949 *out = "\033[C"; 950 return (3); 951 case KS_KP_Delete: 952 *out = "\177"; 953 return (1); 954 } 955 return (0); 956 } 957 958 void 959 wsemul_sun_detach(void *cookie, u_int *crowp, u_int *ccolp) 960 { 961 struct wsemul_sun_emuldata *edp = cookie; 962 963 *crowp = edp->crow; 964 *ccolp = edp->ccol; 965 if (edp != &wsemul_sun_console_emuldata) 966 free(edp, M_DEVBUF); 967 } 968 969 void 970 wsemul_sun_resetop(void *cookie, enum wsemul_resetops op) 971 { 972 struct wsemul_sun_emuldata *edp = cookie; 973 974 switch (op) { 975 case WSEMUL_RESET: 976 wsemul_sun_reset(edp); 977 break; 978 case WSEMUL_CLEARSCREEN: 979 (*edp->emulops->eraserows)(edp->emulcookie, 0, edp->nrows, 980 edp->bkgdattr); 981 edp->ccol = edp->crow = 0; 982 (*edp->emulops->cursor)(edp->emulcookie, 1, 0, 0); 983 break; 984 case WSEMUL_CLEARCURSOR: 985 (*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, 986 edp->ccol); 987 break; 988 default: 989 break; 990 } 991 } 992 993 int 994 wsemul_sun_scrollup(struct wsemul_sun_emuldata *edp, u_int lines) 995 { 996 int rc; 997 998 /* 999 * if we're in wrap-around mode, go to the first 1000 * line and clear it. 1001 */ 1002 if (lines == 0) { 1003 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 1004 (edp->emulcookie, 0, 1, edp->bkgdattr)); 1005 if (rc != 0) 1006 return rc; 1007 1008 edp->crow = 0; 1009 return 0; 1010 } 1011 1012 /* 1013 * If the scrolling distance is equal to the screen height 1014 * (usually 34), clear the screen; otherwise, scroll by the 1015 * scrolling distance. 1016 */ 1017 if (lines < edp->nrows) { 1018 WSEMULOP(rc, edp, &edp->abortstate, copyrows, 1019 (edp->emulcookie, lines, 0, edp->nrows - lines)); 1020 if (rc != 0) 1021 return rc; 1022 } 1023 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 1024 (edp->emulcookie, edp->nrows - lines, lines, edp->bkgdattr)); 1025 if (rc != 0) 1026 return rc; 1027 1028 edp->crow -= lines - 1; 1029 1030 return 0; 1031 } 1032