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