1 /* $OpenBSD: wsemul_sun.c,v 1.3 2001/04/14 04:48:00 aaron 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 /* XXX DESCRIPTION/SOURCE OF INFORMATION */ 35 36 #include <sys/cdefs.h> 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/time.h> 41 #include <sys/malloc.h> 42 #include <sys/fcntl.h> 43 44 #include <dev/wscons/wsconsio.h> 45 #include <dev/wscons/wsdisplayvar.h> 46 #include <dev/wscons/wsemulvar.h> 47 #include <dev/wscons/wsksymdef.h> 48 #include <dev/wscons/ascii.h> 49 50 void *wsemul_sun_cnattach __P((const struct wsscreen_descr *, void *, 51 int, int, long)); 52 void *wsemul_sun_attach __P((int console, const struct wsscreen_descr *, 53 void *, int, int, void *, long)); 54 void wsemul_sun_output __P((void *cookie, const u_char *data, u_int count, 55 int)); 56 int wsemul_sun_translate __P((void *cookie, keysym_t, char **)); 57 void wsemul_sun_detach __P((void *cookie, u_int *crowp, u_int *ccolp)); 58 void wsemul_sun_resetop __P((void *, enum wsemul_resetops)); 59 60 const struct wsemul_ops wsemul_sun_ops = { 61 "sun", 62 wsemul_sun_cnattach, 63 wsemul_sun_attach, 64 wsemul_sun_output, 65 wsemul_sun_translate, 66 wsemul_sun_detach, 67 wsemul_sun_resetop 68 }; 69 70 #define SUN_EMUL_STATE_NORMAL 0 /* normal processing */ 71 #define SUN_EMUL_STATE_HAVEESC 1 /* seen start of ctl seq */ 72 #define SUN_EMUL_STATE_CONTROL 2 /* processing ctl seq */ 73 74 #define SUN_EMUL_NARGS 2 /* max # of args to a command */ 75 76 struct wsemul_sun_emuldata { 77 const struct wsdisplay_emulops *emulops; 78 void *emulcookie; 79 void *cbcookie; 80 int scrcapabilities; 81 u_int nrows, ncols, crow, ccol; 82 83 u_int state; /* processing state */ 84 u_int args[SUN_EMUL_NARGS]; /* command args, if CONTROL */ 85 u_int scrolldist; /* distance to scroll */ 86 long defattr; /* default attribute (rendition) */ 87 long bowattr; /* attribute for reversed mode */ 88 int rendflags; 89 #define REND_BOW 1 90 #define REND_SO 2 91 long curattr; /* currently used attribute */ 92 long kernattr; /* attribute for kernel output */ 93 #ifdef DIAGNOSTIC 94 int console; 95 #endif 96 }; 97 98 u_int wsemul_sun_output_normal __P((struct wsemul_sun_emuldata *, u_char, 99 int)); 100 u_int wsemul_sun_output_haveesc __P((struct wsemul_sun_emuldata *, u_char)); 101 u_int wsemul_sun_output_control __P((struct wsemul_sun_emuldata *, u_char)); 102 void wsemul_sun_control __P((struct wsemul_sun_emuldata *, u_char)); 103 104 struct wsemul_sun_emuldata wsemul_sun_console_emuldata; 105 106 /* some useful utility macros */ 107 #define ARG(n) (edp->args[(n)]) 108 #define NORMALIZE_ARG(n) (ARG(n) ? ARG(n) : 1) 109 #define COLS_LEFT (edp->ncols - edp->ccol - 1) 110 #define ROWS_LEFT (edp->nrows - edp->crow - 1) 111 112 void * 113 wsemul_sun_cnattach(type, cookie, ccol, crow, defattr) 114 const struct wsscreen_descr *type; 115 void *cookie; 116 int ccol, crow; 117 long defattr; 118 { 119 struct wsemul_sun_emuldata *edp; 120 int res; 121 122 edp = &wsemul_sun_console_emuldata; 123 124 edp->emulops = type->textops; 125 edp->emulcookie = cookie; 126 edp->scrcapabilities = type->capabilities; 127 edp->nrows = type->nrows; 128 edp->ncols = type->ncols; 129 edp->crow = crow; 130 edp->ccol = ccol; 131 edp->curattr = edp->defattr = defattr; 132 #if defined(WS_KERNEL_FG) || defined(WS_KERNEL_BG) || \ 133 defined(WS_KERNEL_COLATTR) || defined(WS_KERNEL_MONOATTR) 134 #ifndef WS_KERNEL_FG 135 #define WS_KERNEL_FG WSCOL_WHITE 136 #endif 137 #ifndef WS_KERNEL_BG 138 #define WS_KERNEL_BG WSCOL_BLACK 139 #endif 140 #ifndef WS_KERNEL_COLATTR 141 #define WS_KERNEL_COLATTR 0 142 #endif 143 #ifndef WS_KERNEL_MONOATTR 144 #define WS_KERNEL_MONOATTR 0 145 #endif 146 if (type->capabilities & WSSCREEN_WSCOLORS) 147 res = (*edp->emulops->alloc_attr)(cookie, 148 WS_KERNEL_FG, WS_KERNEL_BG, 149 WS_KERNEL_COLATTR | WSATTR_WSCOLORS, 150 &edp->kernattr); 151 else 152 res = (*edp->emulops->alloc_attr)(cookie, 0, 0, 153 WS_KERNEL_MONOATTR, 154 &edp->kernattr); 155 if (res) 156 #else 157 res = 0; /* XXX gcc */ 158 #endif 159 edp->kernattr = defattr; 160 161 edp->cbcookie = NULL; 162 163 edp->state = SUN_EMUL_STATE_NORMAL; 164 edp->scrolldist = 1; 165 #ifdef DIAGNOSTIC 166 edp->console = 1; 167 #endif 168 return (edp); 169 } 170 171 void * 172 wsemul_sun_attach(console, type, cookie, ccol, crow, cbcookie, defattr) 173 int console; 174 const struct wsscreen_descr *type; 175 void *cookie; 176 int ccol, crow; 177 void *cbcookie; 178 long defattr; 179 { 180 struct wsemul_sun_emuldata *edp; 181 182 if (console) { 183 edp = &wsemul_sun_console_emuldata; 184 #ifdef DIAGNOSTIC 185 KASSERT(edp->console == 1); 186 #endif 187 } else { 188 edp = malloc(sizeof *edp, M_DEVBUF, M_WAITOK); 189 190 edp->emulops = type->textops; 191 edp->emulcookie = cookie; 192 edp->scrcapabilities = type->capabilities; 193 edp->nrows = type->nrows; 194 edp->ncols = type->ncols; 195 edp->crow = crow; 196 edp->ccol = ccol; 197 edp->defattr = defattr; 198 199 edp->state = SUN_EMUL_STATE_NORMAL; 200 edp->scrolldist = 1; 201 #ifdef DIAGNOSTIC 202 edp->console = 0; 203 #endif 204 } 205 206 edp->cbcookie = cbcookie; 207 208 /* XXX This assumes that the default attribute is wob. */ 209 if ((!(edp->scrcapabilities & WSSCREEN_WSCOLORS) || 210 (*edp->emulops->alloc_attr)(edp->emulcookie, 211 WSCOL_BLACK, WSCOL_WHITE, 212 WSATTR_WSCOLORS, 213 &edp->bowattr)) && 214 (!(edp->scrcapabilities & WSSCREEN_REVERSE) || 215 (*edp->emulops->alloc_attr)(edp->emulcookie, 0, 0, 216 WSATTR_REVERSE, 217 &edp->bowattr))) 218 edp->bowattr = edp->defattr; 219 220 edp->curattr = edp->defattr; 221 edp->rendflags = 0; 222 223 return (edp); 224 } 225 226 inline u_int 227 wsemul_sun_output_normal(edp, c, kernel) 228 struct wsemul_sun_emuldata *edp; 229 u_char c; 230 int kernel; 231 { 232 u_int newstate = SUN_EMUL_STATE_NORMAL; 233 u_int n; 234 235 switch (c) { 236 case ASCII_BEL: /* "Bell (BEL)" */ 237 wsdisplay_emulbell(edp->cbcookie); 238 break; 239 240 case ASCII_BS: /* "Backspace (BS)" */ 241 if (edp->ccol > 0) 242 edp->ccol--; 243 break; 244 245 case ASCII_CR: /* "Return (CR)" */ 246 edp->ccol = 0; 247 break; 248 249 case ASCII_HT: /* "Tab (TAB)" */ 250 n = min(8 - (edp->ccol & 7), COLS_LEFT); 251 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, 252 edp->ccol, n, 253 kernel ? edp->kernattr : edp->curattr); 254 edp->ccol += n; 255 break; 256 257 case ASCII_FF: /* "Form Feed (FF)" */ 258 (*edp->emulops->eraserows)(edp->emulcookie, 0, edp->nrows, 259 kernel ? edp->kernattr : edp->curattr); 260 /* XXX possible in kernel output? */ 261 edp->ccol = 0; 262 edp->crow = 0; 263 break; 264 265 case ASCII_VT: /* "Reverse Line Feed" */ 266 if (edp->crow > 0) 267 edp->crow--; 268 break; 269 270 case ASCII_ESC: /* "Escape (ESC)" */ 271 if (kernel) { 272 printf("wsemul_sun_output_normal: ESC in kernel " 273 "output ignored\n"); 274 break; /* ignore the ESC */ 275 } 276 277 if (edp->state == SUN_EMUL_STATE_NORMAL) { 278 newstate = SUN_EMUL_STATE_HAVEESC; 279 break; 280 } 281 /* special case: fall through, we're printing one out */ 282 /* FALLTHRU */ 283 284 default: /* normal character */ 285 (*edp->emulops->putchar)(edp->emulcookie, edp->crow, edp->ccol, 286 c, kernel ? edp->kernattr : edp->curattr); 287 edp->ccol++; 288 289 /* if cur col is still on cur line, done. */ 290 if (edp->ccol < edp->ncols) 291 break; 292 293 /* wrap the column around. */ 294 edp->ccol = 0; 295 296 /* FALLTHRU */ 297 298 case ASCII_LF: /* "Line Feed (LF)" */ 299 /* if the cur line isn't the last, incr and leave. */ 300 if (edp->crow < edp->nrows - 1) { 301 edp->crow++; 302 break; 303 } 304 305 /* 306 * if we're in wrap-around mode, go to the first 307 * line and clear it. 308 */ 309 if (edp->scrolldist == 0) { 310 edp->crow = 0; 311 (*edp->emulops->eraserows)(edp->emulcookie, 0, 1, 312 edp->curattr); 313 break; 314 } 315 316 /* scroll by the scrolling distance. */ 317 (*edp->emulops->copyrows)(edp->emulcookie, edp->scrolldist, 0, 318 edp->nrows - edp->scrolldist); 319 (*edp->emulops->eraserows)(edp->emulcookie, 320 edp->nrows - edp->scrolldist, edp->scrolldist, 321 edp->curattr); 322 edp->crow -= edp->scrolldist - 1; 323 break; 324 } 325 326 return (newstate); 327 } 328 329 inline u_int 330 wsemul_sun_output_haveesc(edp, c) 331 struct wsemul_sun_emuldata *edp; 332 u_char c; 333 { 334 u_int newstate; 335 336 switch (c) { 337 case '[': /* continuation of multi-char sequence */ 338 bzero(edp->args, sizeof (edp->args)); 339 newstate = SUN_EMUL_STATE_CONTROL; 340 break; 341 342 default: 343 /* spit out the escape char (???), then the new character */ 344 wsemul_sun_output_normal(edp, ASCII_ESC, 0); /* ??? */ 345 newstate = wsemul_sun_output_normal(edp, c, 0); 346 break; 347 } 348 349 return (newstate); 350 } 351 352 inline void 353 wsemul_sun_control(edp, c) 354 struct wsemul_sun_emuldata *edp; 355 u_char c; 356 { 357 u_int n, src, dst; 358 359 switch (c) { 360 case '@': /* "Insert Character (ICH)" */ 361 n = min(NORMALIZE_ARG(0), COLS_LEFT + 1); 362 src = edp->ccol; 363 dst = edp->ccol + n; 364 if (dst < edp->ncols) { 365 (*edp->emulops->copycols)(edp->emulcookie, edp->crow, 366 src, dst, edp->ncols - dst); 367 } 368 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, 369 src, dst - src, edp->curattr); 370 break; 371 372 case 'A': /* "Cursor Up (CUU)" */ 373 edp->crow -= min(NORMALIZE_ARG(0), edp->crow); 374 break; 375 376 case 'E': /* "Cursor Next Line (CNL)" */ 377 edp->ccol = 0; 378 /* FALLTHRU */ 379 case 'B': /* "Cursor Down (CUD)" */ 380 edp->crow += min(NORMALIZE_ARG(0), ROWS_LEFT); 381 break; 382 383 case 'C': /* "Cursor Forward (CUF)" */ 384 edp->ccol += min(NORMALIZE_ARG(0), COLS_LEFT); 385 break; 386 387 case 'D': /* "Cursor Backward (CUB)" */ 388 edp->ccol -= min(NORMALIZE_ARG(0), edp->ccol); 389 break; 390 391 case 'f': /* "Horizontal And Vertical Position (HVP)" */ 392 case 'H': /* "Cursor Position (CUP)" */ 393 edp->crow = min(NORMALIZE_ARG(1), edp->nrows) - 1; 394 edp->ccol = min(NORMALIZE_ARG(0), edp->ncols) - 1; 395 break; 396 397 case 'J': /* "Erase in Display (ED)" */ 398 if (ROWS_LEFT > 0) { 399 (*edp->emulops->eraserows)(edp->emulcookie, 400 edp->crow + 1, ROWS_LEFT, edp->curattr); 401 } 402 /* FALLTHRU */ 403 case 'K': /* "Erase in Line (EL)" */ 404 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, 405 edp->ccol, COLS_LEFT + 1, edp->curattr); 406 break; 407 408 case 'L': /* "Insert Line (IL)" */ 409 n = min(NORMALIZE_ARG(0), ROWS_LEFT + 1); 410 src = edp->crow; 411 dst = edp->crow + n; 412 if (dst < edp->nrows) { 413 (*edp->emulops->copyrows)(edp->emulcookie, 414 src, dst, edp->nrows - dst); 415 } 416 (*edp->emulops->eraserows)(edp->emulcookie, 417 src, dst - src, edp->curattr); 418 break; 419 420 case 'M': /* "Delete Line (DL)" */ 421 n = min(NORMALIZE_ARG(0), ROWS_LEFT + 1); 422 src = edp->crow + n; 423 dst = edp->crow; 424 if (src < edp->nrows) { 425 (*edp->emulops->copyrows)(edp->emulcookie, 426 src, dst, edp->nrows - src); 427 } 428 (*edp->emulops->eraserows)(edp->emulcookie, 429 dst + edp->nrows - src, src - dst, edp->curattr); 430 break; 431 432 case 'P': /* "Delete Character (DCH)" */ 433 n = min(NORMALIZE_ARG(0), COLS_LEFT + 1); 434 src = edp->ccol + n; 435 dst = edp->ccol; 436 if (src < edp->ncols) { 437 (*edp->emulops->copycols)(edp->emulcookie, edp->crow, 438 src, dst, edp->ncols - src); 439 } 440 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, 441 dst + edp->ncols - src, src - dst, edp->curattr); 442 break; 443 444 case 'm': /* "Select Graphic Rendition (SGR)" */ 445 if (ARG(0)) 446 edp->rendflags |= REND_SO; 447 else 448 edp->rendflags &= ~REND_SO; 449 goto setattr; 450 451 case 'p': /* "Black On White (SUNBOW)" */ 452 edp->rendflags |= REND_BOW; 453 goto setattr; 454 455 case 'q': /* "White On Black (SUNWOB)" */ 456 edp->rendflags &= ~REND_BOW; 457 goto setattr; 458 459 case 'r': /* "Set Scrolling (SUNSCRL)" */ 460 edp->scrolldist = min(ARG(0), edp->nrows); 461 break; 462 463 case 's': /* "Reset Terminal Emulator (SUNRESET)" */ 464 edp->scrolldist = 1; 465 edp->rendflags = 0; 466 setattr: 467 if (((edp->rendflags & REND_BOW) != 0) ^ 468 ((edp->rendflags & REND_SO) != 0)) 469 edp->curattr = edp->bowattr; 470 else 471 edp->curattr = edp->defattr; 472 break; 473 } 474 } 475 476 inline u_int 477 wsemul_sun_output_control(edp, c) 478 struct wsemul_sun_emuldata *edp; 479 u_char c; 480 { 481 u_int newstate = SUN_EMUL_STATE_CONTROL; 482 u_int i; 483 484 switch (c) { 485 case '0': case '1': case '2': case '3': case '4': /* argument digit */ 486 case '5': case '6': case '7': case '8': case '9': 487 edp->args[0] = (edp->args[0] * 10) + (c - '0'); 488 break; 489 490 case ';': /* argument terminator */ 491 for (i = 1; i < SUN_EMUL_NARGS; i++) 492 edp->args[i] = edp->args[i - 1]; 493 edp->args[0] = 0; 494 break; 495 496 default: /* end of escape sequence */ 497 wsemul_sun_control(edp, c); 498 newstate = SUN_EMUL_STATE_NORMAL; 499 break; 500 } 501 return (newstate); 502 } 503 504 void 505 wsemul_sun_output(cookie, data, count, kernel) 506 void *cookie; 507 const u_char *data; 508 u_int count; 509 int kernel; 510 { 511 struct wsemul_sun_emuldata *edp = cookie; 512 u_int newstate; 513 514 #ifdef DIAGNOSTIC 515 if (kernel && !edp->console) 516 panic("wsemul_sun_output: kernel output, not console"); 517 #endif 518 519 /* XXX */ 520 (*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, edp->ccol); 521 for (; count > 0; data++, count--) { 522 if (kernel) { 523 wsemul_sun_output_normal(edp, *data, 1); 524 continue; 525 } 526 switch (edp->state) { 527 case SUN_EMUL_STATE_NORMAL: 528 /* XXX SCAN INPUT FOR NEWLINES, DO PRESCROLLING */ 529 newstate = wsemul_sun_output_normal(edp, *data, 0); 530 break; 531 case SUN_EMUL_STATE_HAVEESC: 532 newstate = wsemul_sun_output_haveesc(edp, *data); 533 break; 534 case SUN_EMUL_STATE_CONTROL: 535 newstate = wsemul_sun_output_control(edp, *data); 536 break; 537 default: 538 #ifdef DIAGNOSTIC 539 panic("wsemul_sun: invalid state %d\n", edp->state); 540 #endif 541 /* try to recover, if things get screwed up... */ 542 newstate = wsemul_sun_output_normal(edp, *data, 0); 543 break; 544 } 545 edp->state = newstate; 546 } 547 /* XXX */ 548 (*edp->emulops->cursor)(edp->emulcookie, 1, edp->crow, edp->ccol); 549 } 550 551 static char *sun_fkeys[] = { 552 "\033[224z", /* F1 */ 553 "\033[225z", 554 "\033[226z", 555 "\033[227z", 556 "\033[228z", 557 "\033[229z", 558 "\033[230z", 559 "\033[231z", 560 "\033[232z", 561 "\033[233z", /* F10 */ 562 }; 563 564 int 565 wsemul_sun_translate(cookie, in, out) 566 void *cookie; 567 keysym_t in; 568 char **out; 569 { 570 static char c; 571 572 if (KS_GROUP(in) == KS_GROUP_Keypad && (in & 0x80) == 0) { 573 c = in & 0xff; /* turn into ASCII */ 574 *out = &c; 575 return (1); 576 } 577 578 if (in >= KS_f1 && in <= KS_f10) { 579 *out = sun_fkeys[in - KS_f1]; 580 return (6); 581 } 582 if (in >= KS_F1 && in <= KS_F10) { 583 *out = sun_fkeys[in - KS_F1]; 584 return (6); 585 } 586 if (in >= KS_KP_F1 && in <= KS_KP_F4) { 587 *out = sun_fkeys[in - KS_KP_F1]; 588 return (6); 589 } 590 591 switch (in) { 592 case KS_Home: 593 case KS_KP_Home: 594 case KS_KP_Begin: 595 *out = "\033[214z"; 596 return (6); 597 case KS_Prior: 598 case KS_KP_Prior: 599 *out = "\033[216z"; 600 return (6); 601 case KS_Next: 602 case KS_KP_Next: 603 *out = "\033[222z"; 604 return (6); 605 case KS_Up: 606 case KS_KP_Up: 607 *out = "\033[A"; 608 return (3); 609 case KS_Down: 610 case KS_KP_Down: 611 *out = "\033[B"; 612 return (3); 613 case KS_Left: 614 case KS_KP_Left: 615 *out = "\033[D"; 616 return (3); 617 case KS_Right: 618 case KS_KP_Right: 619 *out = "\033[C"; 620 return (3); 621 case KS_KP_Delete: 622 *out = "\177"; 623 return (1); 624 } 625 return (0); 626 } 627 628 void 629 wsemul_sun_detach(cookie, crowp, ccolp) 630 void *cookie; 631 u_int *crowp, *ccolp; 632 { 633 struct wsemul_sun_emuldata *edp = cookie; 634 635 *crowp = edp->crow; 636 *ccolp = edp->ccol; 637 if (edp != &wsemul_sun_console_emuldata) 638 free(edp, M_DEVBUF); 639 } 640 641 void 642 wsemul_sun_resetop(cookie, op) 643 void *cookie; 644 enum wsemul_resetops op; 645 { 646 struct wsemul_sun_emuldata *edp = cookie; 647 648 switch (op) { 649 case WSEMUL_RESET: 650 edp->state = SUN_EMUL_STATE_NORMAL; 651 edp->scrolldist = 1; 652 edp->rendflags = 0; 653 edp->curattr = edp->defattr; 654 break; 655 case WSEMUL_CLEARSCREEN: 656 (*edp->emulops->eraserows)(edp->emulcookie, 0, edp->nrows, 657 edp->defattr); 658 edp->ccol = edp->crow = 0; 659 (*edp->emulops->cursor)(edp->emulcookie, 1, 0, 0); 660 break; 661 default: 662 break; 663 } 664 } 665