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