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