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