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