1 /* $NetBSD: wsemul_vt100.c,v 1.30 2006/11/16 01:33:31 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1998 5 * Matthias Drochner. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: wsemul_vt100.c,v 1.30 2006/11/16 01:33:31 christos Exp $"); 31 32 #include "opt_wsmsgattrs.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/time.h> 37 #include <sys/malloc.h> 38 #include <sys/fcntl.h> 39 40 #include <dev/wscons/wsconsio.h> 41 #include <dev/wscons/wsdisplayvar.h> 42 #include <dev/wscons/wsemulvar.h> 43 #include <dev/wscons/wsemul_vt100var.h> 44 #include <dev/wscons/ascii.h> 45 46 void *wsemul_vt100_cnattach(const struct wsscreen_descr *, void *, 47 int, int, long); 48 void *wsemul_vt100_attach(int console, const struct wsscreen_descr *, 49 void *, int, int, void *, long); 50 void wsemul_vt100_output(void *cookie, const u_char *data, u_int count, int); 51 void wsemul_vt100_detach(void *cookie, u_int *crowp, u_int *ccolp); 52 void wsemul_vt100_resetop(void *, enum wsemul_resetops); 53 #ifdef WSDISPLAY_CUSTOM_OUTPUT 54 static void wsemul_vt100_getmsgattrs(void *, struct wsdisplay_msgattrs *); 55 static void wsemul_vt100_setmsgattrs(void *, const struct wsscreen_descr *, 56 const struct wsdisplay_msgattrs *); 57 #endif /* WSDISPLAY_CUSTOM_OUTPUT */ 58 59 const struct wsemul_ops wsemul_vt100_ops = { 60 "vt100", 61 wsemul_vt100_cnattach, 62 wsemul_vt100_attach, 63 wsemul_vt100_output, 64 wsemul_vt100_translate, 65 wsemul_vt100_detach, 66 wsemul_vt100_resetop, 67 #ifdef WSDISPLAY_CUSTOM_OUTPUT 68 wsemul_vt100_getmsgattrs, 69 wsemul_vt100_setmsgattrs, 70 #else 71 NULL, 72 NULL, 73 #endif 74 }; 75 76 struct wsemul_vt100_emuldata wsemul_vt100_console_emuldata; 77 78 static void wsemul_vt100_init(struct wsemul_vt100_emuldata *, 79 const struct wsscreen_descr *, 80 void *, int, int, long); 81 82 static void wsemul_vt100_output_normal(struct wsemul_vt100_emuldata *, 83 u_char, int); 84 static void wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata *, 85 u_char, int); 86 static void wsemul_vt100_nextline(struct wsemul_vt100_emuldata *); 87 typedef u_int vt100_handler(struct wsemul_vt100_emuldata *, u_char); 88 89 static vt100_handler 90 wsemul_vt100_output_esc, 91 wsemul_vt100_output_csi, 92 wsemul_vt100_output_scs94, 93 wsemul_vt100_output_scs94_percent, 94 wsemul_vt100_output_scs96, 95 wsemul_vt100_output_scs96_percent, 96 wsemul_vt100_output_esc_hash, 97 wsemul_vt100_output_esc_spc, 98 wsemul_vt100_output_string, 99 wsemul_vt100_output_string_esc, 100 wsemul_vt100_output_dcs, 101 wsemul_vt100_output_dcs_dollar; 102 103 #define VT100_EMUL_STATE_NORMAL 0 /* normal processing */ 104 #define VT100_EMUL_STATE_ESC 1 /* got ESC */ 105 #define VT100_EMUL_STATE_CSI 2 /* got CSI (ESC[) */ 106 #define VT100_EMUL_STATE_SCS94 3 /* got ESC{()*+} */ 107 #define VT100_EMUL_STATE_SCS94_PERCENT 4 /* got ESC{()*+}% */ 108 #define VT100_EMUL_STATE_SCS96 5 /* got ESC{-./} */ 109 #define VT100_EMUL_STATE_SCS96_PERCENT 6 /* got ESC{-./}% */ 110 #define VT100_EMUL_STATE_ESC_HASH 7 /* got ESC# */ 111 #define VT100_EMUL_STATE_ESC_SPC 8 /* got ESC<SPC> */ 112 #define VT100_EMUL_STATE_STRING 9 /* waiting for ST (ESC\) */ 113 #define VT100_EMUL_STATE_STRING_ESC 10 /* waiting for ST, got ESC */ 114 #define VT100_EMUL_STATE_DCS 11 /* got DCS (ESC P) */ 115 #define VT100_EMUL_STATE_DCS_DOLLAR 12 /* got DCS<p>$ */ 116 117 vt100_handler *vt100_output[] = { 118 wsemul_vt100_output_esc, 119 wsemul_vt100_output_csi, 120 wsemul_vt100_output_scs94, 121 wsemul_vt100_output_scs94_percent, 122 wsemul_vt100_output_scs96, 123 wsemul_vt100_output_scs96_percent, 124 wsemul_vt100_output_esc_hash, 125 wsemul_vt100_output_esc_spc, 126 wsemul_vt100_output_string, 127 wsemul_vt100_output_string_esc, 128 wsemul_vt100_output_dcs, 129 wsemul_vt100_output_dcs_dollar, 130 }; 131 132 static void 133 wsemul_vt100_init(struct wsemul_vt100_emuldata *edp, 134 const struct wsscreen_descr *type, void *cookie, int ccol, int crow, 135 long defattr) 136 { 137 int error; 138 139 edp->emulops = type->textops; 140 edp->emulcookie = cookie; 141 edp->scrcapabilities = type->capabilities; 142 edp->nrows = type->nrows; 143 edp->ncols = type->ncols; 144 edp->crow = crow; 145 edp->ccol = ccol; 146 147 /* The underlying driver has already allocated a default and simple 148 * attribute for us, which is stored in defattr. We try to set the 149 * values specified by the kernel options below, but in case of 150 * failure we fallback to the value given by the driver. */ 151 152 if (type->capabilities & WSSCREEN_WSCOLORS) { 153 edp->msgattrs.default_attrs = WS_DEFAULT_COLATTR | 154 WSATTR_WSCOLORS; 155 edp->msgattrs.default_bg = WS_DEFAULT_BG; 156 edp->msgattrs.default_fg = WS_DEFAULT_FG; 157 158 edp->msgattrs.kernel_attrs = WS_KERNEL_COLATTR | 159 WSATTR_WSCOLORS; 160 edp->msgattrs.kernel_bg = WS_KERNEL_BG; 161 edp->msgattrs.kernel_fg = WS_KERNEL_FG; 162 } else { 163 edp->msgattrs.default_attrs = WS_DEFAULT_MONOATTR; 164 edp->msgattrs.default_bg = edp->msgattrs.default_fg = 0; 165 166 edp->msgattrs.kernel_attrs = WS_KERNEL_MONOATTR; 167 edp->msgattrs.kernel_bg = edp->msgattrs.kernel_fg = 0; 168 } 169 170 error = (*edp->emulops->allocattr)(cookie, 171 edp->msgattrs.default_fg, 172 edp->msgattrs.default_bg, 173 edp->msgattrs.default_attrs, 174 &edp->defattr); 175 if (error) { 176 edp->defattr = defattr; 177 /* XXX This assumes the driver has allocated white on black 178 * XXX as the default attribute, which is not always true. 179 * XXX Maybe we need an emulop that, given an attribute, 180 * XXX (defattr) returns its flags and colors? */ 181 edp->msgattrs.default_attrs = 0; 182 edp->msgattrs.default_bg = WSCOL_BLACK; 183 edp->msgattrs.default_fg = WSCOL_WHITE; 184 } else { 185 if (edp->emulops->replaceattr != NULL) 186 (*edp->emulops->replaceattr)(cookie, defattr, 187 edp->defattr); 188 } 189 190 #if defined(WS_KERNEL_CUSTOMIZED) 191 /* Set up kernel colors, in case they were customized by the user; 192 * otherwise default to the colors specified for the console. 193 * In case of failure, we use console colors too; we can assume 194 * they are good as they have been previously allocated and 195 * verified. */ 196 error = (*edp->emulops->allocattr)(cookie, 197 edp->msgattrs.kernel_fg, 198 edp->msgattrs.kernel_bg, 199 edp->msgattrs.kernel_attrs, 200 &edp->kernattr); 201 if (error) 202 #endif 203 edp->kernattr = edp->defattr; 204 } 205 206 void * 207 wsemul_vt100_cnattach(const struct wsscreen_descr *type, void *cookie, 208 int ccol, int crow, long defattr) 209 { 210 struct wsemul_vt100_emuldata *edp; 211 212 edp = &wsemul_vt100_console_emuldata; 213 wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr); 214 #ifdef DIAGNOSTIC 215 edp->console = 1; 216 #endif 217 edp->cbcookie = NULL; 218 219 edp->tabs = 0; 220 edp->dblwid = 0; 221 edp->dw = 0; 222 edp->dcsarg = 0; 223 edp->isolatin1tab = edp->decgraphtab = edp->dectechtab = 0; 224 edp->nrctab = 0; 225 wsemul_vt100_reset(edp); 226 return (edp); 227 } 228 229 void * 230 wsemul_vt100_attach(int console, const struct wsscreen_descr *type, 231 void *cookie, int ccol, int crow, void *cbcookie, long defattr) 232 { 233 struct wsemul_vt100_emuldata *edp; 234 235 if (console) { 236 edp = &wsemul_vt100_console_emuldata; 237 #ifdef DIAGNOSTIC 238 KASSERT(edp->console == 1); 239 #endif 240 } else { 241 edp = malloc(sizeof *edp, M_DEVBUF, M_WAITOK); 242 wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr); 243 #ifdef DIAGNOSTIC 244 edp->console = 0; 245 #endif 246 } 247 edp->cbcookie = cbcookie; 248 249 edp->tabs = malloc(edp->ncols, M_DEVBUF, M_NOWAIT); 250 edp->dblwid = malloc(edp->nrows, M_DEVBUF, M_NOWAIT|M_ZERO); 251 edp->dw = 0; 252 edp->dcsarg = malloc(DCS_MAXLEN, M_DEVBUF, M_NOWAIT); 253 edp->isolatin1tab = malloc(128 * sizeof(int), M_DEVBUF, M_NOWAIT); 254 edp->decgraphtab = malloc(128 * sizeof(int), M_DEVBUF, M_NOWAIT); 255 edp->dectechtab = malloc(128 * sizeof(int), M_DEVBUF, M_NOWAIT); 256 edp->nrctab = malloc(128 * sizeof(int), M_DEVBUF, M_NOWAIT); 257 vt100_initchartables(edp); 258 wsemul_vt100_reset(edp); 259 return (edp); 260 } 261 262 void 263 wsemul_vt100_detach(void *cookie, u_int *crowp, u_int *ccolp) 264 { 265 struct wsemul_vt100_emuldata *edp = cookie; 266 267 *crowp = edp->crow; 268 *ccolp = edp->ccol; 269 #define f(ptr) if (ptr) {free(ptr, M_DEVBUF); ptr = 0;} 270 f(edp->tabs) 271 f(edp->dblwid) 272 f(edp->dcsarg) 273 f(edp->isolatin1tab) 274 f(edp->decgraphtab) 275 f(edp->dectechtab) 276 f(edp->nrctab) 277 #undef f 278 if (edp != &wsemul_vt100_console_emuldata) 279 free(edp, M_DEVBUF); 280 } 281 282 void 283 wsemul_vt100_resetop(void *cookie, enum wsemul_resetops op) 284 { 285 struct wsemul_vt100_emuldata *edp = cookie; 286 287 switch (op) { 288 case WSEMUL_RESET: 289 wsemul_vt100_reset(edp); 290 break; 291 case WSEMUL_SYNCFONT: 292 vt100_initchartables(edp); 293 break; 294 case WSEMUL_CLEARSCREEN: 295 wsemul_vt100_ed(edp, 2); 296 edp->ccol = edp->crow = 0; 297 (*edp->emulops->cursor)(edp->emulcookie, 298 edp->flags & VTFL_CURSORON, 0, 0); 299 break; 300 default: 301 break; 302 } 303 } 304 305 void 306 wsemul_vt100_reset(struct wsemul_vt100_emuldata *edp) 307 { 308 int i; 309 310 edp->state = VT100_EMUL_STATE_NORMAL; 311 edp->flags = VTFL_DECAWM | VTFL_CURSORON; 312 edp->bkgdattr = edp->curattr = edp->defattr; 313 edp->attrflags = edp->msgattrs.default_attrs; 314 edp->fgcol = edp->msgattrs.default_fg; 315 edp->bgcol = edp->msgattrs.default_bg; 316 edp->scrreg_startrow = 0; 317 edp->scrreg_nrows = edp->nrows; 318 if (edp->tabs) { 319 memset(edp->tabs, 0, edp->ncols); 320 for (i = 8; i < edp->ncols; i += 8) 321 edp->tabs[i] = 1; 322 } 323 edp->dcspos = 0; 324 edp->dcstype = 0; 325 edp->chartab_G[0] = 0; 326 edp->chartab_G[1] = edp->nrctab; /* ??? */ 327 edp->chartab_G[2] = edp->isolatin1tab; 328 edp->chartab_G[3] = edp->isolatin1tab; 329 edp->chartab0 = 0; 330 edp->chartab1 = 2; 331 edp->sschartab = 0; 332 } 333 334 /* 335 * now all the state machine bits 336 */ 337 338 /* 339 * Move the cursor to the next line if possible. If the cursor is at 340 * the bottom of the scroll area, then scroll it up. If the cursor is 341 * at the bottom of the screen then don't move it down. 342 */ 343 static void 344 wsemul_vt100_nextline(struct wsemul_vt100_emuldata *edp) 345 { 346 if (ROWS_BELOW == 0) { 347 /* Bottom of the scroll region. */ 348 wsemul_vt100_scrollup(edp, 1); 349 } else { 350 if ((edp->crow+1) < edp->nrows) 351 /* Cursor not at the bottom of the screen. */ 352 edp->crow++; 353 CHECK_DW; 354 } 355 } 356 357 static void 358 wsemul_vt100_output_normal(struct wsemul_vt100_emuldata *edp, u_char c, 359 int kernel) 360 { 361 u_int *ct, dc; 362 363 if ((edp->flags & (VTFL_LASTCHAR | VTFL_DECAWM)) == 364 (VTFL_LASTCHAR | VTFL_DECAWM)) { 365 wsemul_vt100_nextline(edp); 366 edp->ccol = 0; 367 edp->flags &= ~VTFL_LASTCHAR; 368 } 369 370 if (c & 0x80) { 371 c &= 0x7f; 372 ct = edp->chartab_G[edp->chartab1]; 373 } else { 374 if (edp->sschartab) { 375 ct = edp->chartab_G[edp->sschartab]; 376 edp->sschartab = 0; 377 } else 378 ct = edp->chartab_G[edp->chartab0]; 379 } 380 dc = (ct ? ct[c] : c); 381 382 if ((edp->flags & VTFL_INSERTMODE) && COLS_LEFT) 383 COPYCOLS(edp->ccol, edp->ccol + 1, COLS_LEFT); 384 385 (*edp->emulops->putchar)(edp->emulcookie, edp->crow, 386 edp->ccol << edp->dw, dc, 387 kernel ? edp->kernattr : edp->curattr); 388 389 if (COLS_LEFT) 390 edp->ccol++; 391 else 392 edp->flags |= VTFL_LASTCHAR; 393 } 394 395 static void 396 wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata *edp, u_char c, 397 int kernel) 398 { 399 u_int n; 400 401 switch (c) { 402 case ASCII_NUL: 403 default: 404 /* ignore */ 405 break; 406 case ASCII_BEL: 407 wsdisplay_emulbell(edp->cbcookie); 408 break; 409 case ASCII_BS: 410 if (edp->ccol > 0) { 411 edp->ccol--; 412 edp->flags &= ~VTFL_LASTCHAR; 413 } 414 break; 415 case ASCII_CR: 416 edp->ccol = 0; 417 edp->flags &= ~VTFL_LASTCHAR; 418 break; 419 case ASCII_HT: 420 if (edp->tabs) { 421 if (!COLS_LEFT) 422 break; 423 for (n = edp->ccol + 1; n < NCOLS - 1; n++) 424 if (edp->tabs[n]) 425 break; 426 } else { 427 n = edp->ccol + min(8 - (edp->ccol & 7), COLS_LEFT); 428 } 429 edp->ccol = n; 430 break; 431 case ASCII_SO: /* LS1 */ 432 edp->chartab0 = 1; 433 break; 434 case ASCII_SI: /* LS0 */ 435 edp->chartab0 = 0; 436 break; 437 case ASCII_ESC: 438 if (kernel) { 439 printf("wsemul_vt100_output_c0c1: ESC in kernel output ignored\n"); 440 break; /* ignore the ESC */ 441 } 442 443 if (edp->state == VT100_EMUL_STATE_STRING) { 444 /* might be a string end */ 445 edp->state = VT100_EMUL_STATE_STRING_ESC; 446 } else { 447 /* XXX cancel current escape sequence */ 448 edp->state = VT100_EMUL_STATE_ESC; 449 } 450 break; 451 #if 0 452 case CSI: /* 8-bit */ 453 /* XXX cancel current escape sequence */ 454 edp->nargs = 0; 455 memset(edp->args, 0, sizeof (edp->args)); 456 edp->modif1 = edp->modif2 = '\0'; 457 edp->state = VT100_EMUL_STATE_CSI; 458 break; 459 case DCS: /* 8-bit */ 460 /* XXX cancel current escape sequence */ 461 edp->nargs = 0; 462 memset(edp->args, 0, sizeof (edp->args)); 463 edp->state = VT100_EMUL_STATE_DCS; 464 break; 465 case ST: /* string end 8-bit */ 466 /* XXX only in VT100_EMUL_STATE_STRING */ 467 wsemul_vt100_handle_dcs(edp); 468 return (VT100_EMUL_STATE_NORMAL); 469 #endif 470 case ASCII_LF: 471 case ASCII_VT: 472 case ASCII_FF: 473 wsemul_vt100_nextline(edp); 474 break; 475 } 476 } 477 478 static u_int 479 wsemul_vt100_output_esc(struct wsemul_vt100_emuldata *edp, u_char c) 480 { 481 u_int newstate = VT100_EMUL_STATE_NORMAL; 482 int i; 483 484 switch (c) { 485 case '[': /* CSI */ 486 edp->nargs = 0; 487 memset(edp->args, 0, sizeof (edp->args)); 488 edp->modif1 = edp->modif2 = '\0'; 489 newstate = VT100_EMUL_STATE_CSI; 490 break; 491 case '7': /* DECSC */ 492 edp->flags |= VTFL_SAVEDCURS; 493 edp->savedcursor_row = edp->crow; 494 edp->savedcursor_col = edp->ccol; 495 edp->savedattr = edp->curattr; 496 edp->savedbkgdattr = edp->bkgdattr; 497 edp->savedattrflags = edp->attrflags; 498 edp->savedfgcol = edp->fgcol; 499 edp->savedbgcol = edp->bgcol; 500 for (i = 0; i < 4; i++) 501 edp->savedchartab_G[i] = edp->chartab_G[i]; 502 edp->savedchartab0 = edp->chartab0; 503 edp->savedchartab1 = edp->chartab1; 504 break; 505 case '8': /* DECRC */ 506 if ((edp->flags & VTFL_SAVEDCURS) == 0) 507 break; 508 edp->crow = edp->savedcursor_row; 509 edp->ccol = edp->savedcursor_col; 510 edp->curattr = edp->savedattr; 511 edp->bkgdattr = edp->savedbkgdattr; 512 edp->attrflags = edp->savedattrflags; 513 edp->fgcol = edp->savedfgcol; 514 edp->bgcol = edp->savedbgcol; 515 for (i = 0; i < 4; i++) 516 edp->chartab_G[i] = edp->savedchartab_G[i]; 517 edp->chartab0 = edp->savedchartab0; 518 edp->chartab1 = edp->savedchartab1; 519 break; 520 case '=': /* DECKPAM application mode */ 521 edp->flags |= VTFL_APPLKEYPAD; 522 break; 523 case '>': /* DECKPNM numeric mode */ 524 edp->flags &= ~VTFL_APPLKEYPAD; 525 break; 526 case 'E': /* NEL */ 527 edp->ccol = 0; 528 /* FALLTHRU */ 529 case 'D': /* IND */ 530 wsemul_vt100_nextline(edp); 531 break; 532 case 'H': /* HTS */ 533 KASSERT(edp->tabs != 0); 534 edp->tabs[edp->ccol] = 1; 535 break; 536 case '~': /* LS1R */ 537 edp->chartab1 = 1; 538 break; 539 case 'n': /* LS2 */ 540 edp->chartab0 = 2; 541 break; 542 case '}': /* LS2R */ 543 edp->chartab1 = 2; 544 break; 545 case 'o': /* LS3 */ 546 edp->chartab0 = 3; 547 break; 548 case '|': /* LS3R */ 549 edp->chartab1 = 3; 550 break; 551 case 'N': /* SS2 */ 552 edp->sschartab = 2; 553 break; 554 case 'O': /* SS3 */ 555 edp->sschartab = 3; 556 break; 557 case 'M': /* RI */ 558 if (ROWS_ABOVE > 0) { 559 edp->crow--; 560 CHECK_DW; 561 break; 562 } 563 wsemul_vt100_scrolldown(edp, 1); 564 break; 565 case 'P': /* DCS */ 566 edp->nargs = 0; 567 memset(edp->args, 0, sizeof (edp->args)); 568 newstate = VT100_EMUL_STATE_DCS; 569 break; 570 case 'c': /* RIS */ 571 wsemul_vt100_reset(edp); 572 wsemul_vt100_ed(edp, 2); 573 edp->ccol = edp->crow = 0; 574 break; 575 case '(': case ')': case '*': case '+': /* SCS */ 576 edp->designating = c - '('; 577 newstate = VT100_EMUL_STATE_SCS94; 578 break; 579 case '-': case '.': case '/': /* SCS */ 580 edp->designating = c - '-' + 1; 581 newstate = VT100_EMUL_STATE_SCS96; 582 break; 583 case '#': 584 newstate = VT100_EMUL_STATE_ESC_HASH; 585 break; 586 case ' ': /* 7/8 bit */ 587 newstate = VT100_EMUL_STATE_ESC_SPC; 588 break; 589 case ']': /* OSC operating system command */ 590 case '^': /* PM privacy message */ 591 case '_': /* APC application program command */ 592 /* ignored */ 593 newstate = VT100_EMUL_STATE_STRING; 594 break; 595 case '<': /* exit VT52 mode - ignored */ 596 break; 597 default: 598 #ifdef VT100_PRINTUNKNOWN 599 printf("ESC%c unknown\n", c); 600 #endif 601 break; 602 } 603 604 return (newstate); 605 } 606 607 static u_int 608 wsemul_vt100_output_scs94(struct wsemul_vt100_emuldata *edp, u_char c) 609 { 610 u_int newstate = VT100_EMUL_STATE_NORMAL; 611 612 switch (c) { 613 case '%': /* probably DEC supplemental graphic */ 614 newstate = VT100_EMUL_STATE_SCS94_PERCENT; 615 break; 616 case 'A': /* british / national */ 617 edp->chartab_G[edp->designating] = edp->nrctab; 618 break; 619 case 'B': /* ASCII */ 620 edp->chartab_G[edp->designating] = 0; 621 break; 622 case '<': /* user preferred supplemental */ 623 /* XXX not really "user" preferred */ 624 edp->chartab_G[edp->designating] = edp->isolatin1tab; 625 break; 626 case '0': /* DEC special graphic */ 627 edp->chartab_G[edp->designating] = edp->decgraphtab; 628 break; 629 case '>': /* DEC tech */ 630 edp->chartab_G[edp->designating] = edp->dectechtab; 631 break; 632 default: 633 #ifdef VT100_PRINTUNKNOWN 634 printf("ESC%c%c unknown\n", edp->designating + '(', c); 635 #endif 636 break; 637 } 638 return (newstate); 639 } 640 641 static u_int 642 wsemul_vt100_output_scs94_percent(struct wsemul_vt100_emuldata *edp, u_char c) 643 { 644 switch (c) { 645 case '5': /* DEC supplemental graphic */ 646 /* XXX there are differences */ 647 edp->chartab_G[edp->designating] = edp->isolatin1tab; 648 break; 649 default: 650 #ifdef VT100_PRINTUNKNOWN 651 printf("ESC%c%%%c unknown\n", edp->designating + '(', c); 652 #endif 653 break; 654 } 655 return (VT100_EMUL_STATE_NORMAL); 656 } 657 658 static u_int 659 wsemul_vt100_output_scs96(struct wsemul_vt100_emuldata *edp, u_char c) 660 { 661 u_int newstate = VT100_EMUL_STATE_NORMAL; 662 int nrc; 663 664 switch (c) { 665 case '%': /* probably portugese */ 666 newstate = VT100_EMUL_STATE_SCS96_PERCENT; 667 break; 668 case 'A': /* ISO-latin-1 supplemental */ 669 edp->chartab_G[edp->designating] = edp->isolatin1tab; 670 break; 671 case '4': /* dutch */ 672 nrc = 1; 673 goto setnrc; 674 case '5': case 'C': /* finnish */ 675 nrc = 2; 676 goto setnrc; 677 case 'R': /* french */ 678 nrc = 3; 679 goto setnrc; 680 case 'Q': /* french canadian */ 681 nrc = 4; 682 goto setnrc; 683 case 'K': /* german */ 684 nrc = 5; 685 goto setnrc; 686 case 'Y': /* italian */ 687 nrc = 6; 688 goto setnrc; 689 case 'E': case '6': /* norwegian / danish */ 690 nrc = 7; 691 goto setnrc; 692 case 'Z': /* spanish */ 693 nrc = 9; 694 goto setnrc; 695 case '7': case 'H': /* swedish */ 696 nrc = 10; 697 goto setnrc; 698 case '=': /* swiss */ 699 nrc = 11; 700 setnrc: 701 vt100_setnrc(edp, nrc); /* what table ??? */ 702 break; 703 default: 704 #ifdef VT100_PRINTUNKNOWN 705 printf("ESC%c%c unknown\n", edp->designating + '-' - 1, c); 706 #endif 707 break; 708 } 709 return (newstate); 710 } 711 712 static u_int 713 wsemul_vt100_output_scs96_percent(struct wsemul_vt100_emuldata *edp, u_char c) 714 { 715 switch (c) { 716 case '6': /* portugese */ 717 vt100_setnrc(edp, 8); 718 break; 719 default: 720 #ifdef VT100_PRINTUNKNOWN 721 printf("ESC%c%%%c unknown\n", edp->designating + '-', c); 722 #endif 723 break; 724 } 725 return (VT100_EMUL_STATE_NORMAL); 726 } 727 728 static u_int 729 wsemul_vt100_output_esc_spc(struct wsemul_vt100_emuldata *edp, 730 u_char c) 731 { 732 switch (c) { 733 case 'F': /* 7-bit controls */ 734 case 'G': /* 8-bit controls */ 735 #ifdef VT100_PRINTNOTIMPL 736 printf("ESC<SPC>%c ignored\n", c); 737 #endif 738 break; 739 default: 740 #ifdef VT100_PRINTUNKNOWN 741 printf("ESC<SPC>%c unknown\n", c); 742 #endif 743 break; 744 } 745 return (VT100_EMUL_STATE_NORMAL); 746 } 747 748 static u_int 749 wsemul_vt100_output_string(struct wsemul_vt100_emuldata *edp, u_char c) 750 { 751 if (edp->dcstype && edp->dcspos < DCS_MAXLEN) 752 edp->dcsarg[edp->dcspos++] = c; 753 return (VT100_EMUL_STATE_STRING); 754 } 755 756 static u_int 757 wsemul_vt100_output_string_esc(struct wsemul_vt100_emuldata *edp, u_char c) 758 { 759 if (c == '\\') { /* ST complete */ 760 wsemul_vt100_handle_dcs(edp); 761 return (VT100_EMUL_STATE_NORMAL); 762 } else 763 return (VT100_EMUL_STATE_STRING); 764 } 765 766 static u_int 767 wsemul_vt100_output_dcs(struct wsemul_vt100_emuldata *edp, u_char c) 768 { 769 u_int newstate = VT100_EMUL_STATE_DCS; 770 771 switch (c) { 772 case '0': case '1': case '2': case '3': case '4': 773 case '5': case '6': case '7': case '8': case '9': 774 /* argument digit */ 775 if (edp->nargs > VT100_EMUL_NARGS - 1) 776 break; 777 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) + 778 (c - '0'); 779 break; 780 case ';': /* argument terminator */ 781 edp->nargs++; 782 break; 783 default: 784 edp->nargs++; 785 if (edp->nargs > VT100_EMUL_NARGS) { 786 #ifdef VT100_DEBUG 787 printf("vt100: too many arguments\n"); 788 #endif 789 edp->nargs = VT100_EMUL_NARGS; 790 } 791 newstate = VT100_EMUL_STATE_STRING; 792 switch (c) { 793 case '$': 794 newstate = VT100_EMUL_STATE_DCS_DOLLAR; 795 break; 796 case '{': /* DECDLD soft charset */ 797 case '!': /* DECRQUPSS user preferred supplemental set */ 798 /* 'u' must follow - need another state */ 799 case '|': /* DECUDK program F6..F20 */ 800 #ifdef VT100_PRINTNOTIMPL 801 printf("DCS%c ignored\n", c); 802 #endif 803 break; 804 default: 805 #ifdef VT100_PRINTUNKNOWN 806 printf("DCS%c (%d, %d) unknown\n", c, ARG(0), ARG(1)); 807 #endif 808 break; 809 } 810 } 811 812 return (newstate); 813 } 814 815 static u_int 816 wsemul_vt100_output_dcs_dollar(struct wsemul_vt100_emuldata *edp, u_char c) 817 { 818 switch (c) { 819 case 'p': /* DECRSTS terminal state restore */ 820 case 'q': /* DECRQSS control function request */ 821 #ifdef VT100_PRINTNOTIMPL 822 printf("DCS$%c ignored\n", c); 823 #endif 824 break; 825 case 't': /* DECRSPS restore presentation state */ 826 switch (ARG(0)) { 827 case 0: /* error */ 828 break; 829 case 1: /* cursor information restore */ 830 #ifdef VT100_PRINTNOTIMPL 831 printf("DCS1$t ignored\n"); 832 #endif 833 break; 834 case 2: /* tab stop restore */ 835 edp->dcspos = 0; 836 edp->dcstype = DCSTYPE_TABRESTORE; 837 break; 838 default: 839 #ifdef VT100_PRINTUNKNOWN 840 printf("DCS%d$t unknown\n", ARG(0)); 841 #endif 842 break; 843 } 844 break; 845 default: 846 #ifdef VT100_PRINTUNKNOWN 847 printf("DCS$%c (%d, %d) unknown\n", c, ARG(0), ARG(1)); 848 #endif 849 break; 850 } 851 return (VT100_EMUL_STATE_STRING); 852 } 853 854 static u_int 855 wsemul_vt100_output_esc_hash(struct wsemul_vt100_emuldata *edp, u_char c) 856 { 857 int i, j; 858 859 switch (c) { 860 case '5': /* DECSWL single width, single height */ 861 if (edp->dw) { 862 for (i = 0; i < edp->ncols / 2; i++) 863 (*edp->emulops->copycols)(edp->emulcookie, 864 edp->crow, 865 2 * i, i, 1); 866 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, 867 i, edp->ncols - i, 868 edp->bkgdattr); 869 edp->dblwid[edp->crow] = 0; 870 edp->dw = 0; 871 } 872 break; 873 case '6': /* DECDWL double width, single height */ 874 case '3': /* DECDHL double width, double height, top half */ 875 case '4': /* DECDHL double width, double height, bottom half */ 876 if (!edp->dw) { 877 for (i = edp->ncols / 2 - 1; i >= 0; i--) 878 (*edp->emulops->copycols)(edp->emulcookie, 879 edp->crow, 880 i, 2 * i, 1); 881 for (i = 0; i < edp->ncols / 2; i++) 882 (*edp->emulops->erasecols)(edp->emulcookie, 883 edp->crow, 884 2 * i + 1, 1, 885 edp->bkgdattr); 886 edp->dblwid[edp->crow] = 1; 887 edp->dw = 1; 888 if (edp->ccol > (edp->ncols >> 1) - 1) 889 edp->ccol = (edp->ncols >> 1) - 1; 890 } 891 break; 892 case '8': /* DECALN */ 893 for (i = 0; i < edp->nrows; i++) 894 for (j = 0; j < edp->ncols; j++) 895 (*edp->emulops->putchar)(edp->emulcookie, i, j, 896 'E', edp->curattr); 897 edp->ccol = 0; 898 edp->crow = 0; 899 break; 900 default: 901 #ifdef VT100_PRINTUNKNOWN 902 printf("ESC#%c unknown\n", c); 903 #endif 904 break; 905 } 906 return (VT100_EMUL_STATE_NORMAL); 907 } 908 909 static u_int 910 wsemul_vt100_output_csi(struct wsemul_vt100_emuldata *edp, u_char c) 911 { 912 u_int newstate = VT100_EMUL_STATE_CSI; 913 914 switch (c) { 915 case '0': case '1': case '2': case '3': case '4': 916 case '5': case '6': case '7': case '8': case '9': 917 /* argument digit */ 918 if (edp->nargs > VT100_EMUL_NARGS - 1) 919 break; 920 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) + 921 (c - '0'); 922 break; 923 case ';': /* argument terminator */ 924 edp->nargs++; 925 break; 926 case '?': /* DEC specific */ 927 case '>': /* DA query */ 928 edp->modif1 = c; 929 break; 930 case '!': 931 case '"': 932 case '$': 933 case '&': 934 edp->modif2 = c; 935 break; 936 default: /* end of escape sequence */ 937 edp->nargs++; 938 if (edp->nargs > VT100_EMUL_NARGS) { 939 #ifdef VT100_DEBUG 940 printf("vt100: too many arguments\n"); 941 #endif 942 edp->nargs = VT100_EMUL_NARGS; 943 } 944 wsemul_vt100_handle_csi(edp, c); 945 newstate = VT100_EMUL_STATE_NORMAL; 946 break; 947 } 948 return (newstate); 949 } 950 951 void 952 wsemul_vt100_output(void *cookie, const u_char *data, u_int count, int kernel) 953 { 954 struct wsemul_vt100_emuldata *edp = cookie; 955 956 #ifdef DIAGNOSTIC 957 if (kernel && !edp->console) 958 panic("wsemul_vt100_output: kernel output, not console"); 959 #endif 960 961 if (edp->flags & VTFL_CURSORON) 962 (*edp->emulops->cursor)(edp->emulcookie, 0, 963 edp->crow, edp->ccol << edp->dw); 964 for (; count > 0; data++, count--) { 965 if ((*data & 0x7f) < 0x20) { 966 wsemul_vt100_output_c0c1(edp, *data, kernel); 967 continue; 968 } 969 if (edp->state == VT100_EMUL_STATE_NORMAL || kernel) { 970 wsemul_vt100_output_normal(edp, *data, kernel); 971 continue; 972 } 973 #ifdef DIAGNOSTIC 974 if (edp->state > sizeof(vt100_output) / sizeof(vt100_output[0])) 975 panic("wsemul_vt100: invalid state %d", edp->state); 976 #endif 977 edp->state = vt100_output[edp->state - 1](edp, *data); 978 } 979 if (edp->flags & VTFL_CURSORON) 980 (*edp->emulops->cursor)(edp->emulcookie, 1, 981 edp->crow, edp->ccol << edp->dw); 982 } 983 984 #ifdef WSDISPLAY_CUSTOM_OUTPUT 985 static void 986 wsemul_vt100_getmsgattrs(void *cookie, struct wsdisplay_msgattrs *ma) 987 { 988 struct wsemul_vt100_emuldata *edp = cookie; 989 990 *ma = edp->msgattrs; 991 } 992 993 static void 994 wsemul_vt100_setmsgattrs(void *cookie, const struct wsscreen_descr *type, 995 const struct wsdisplay_msgattrs *ma) 996 { 997 int error; 998 long tmp; 999 struct wsemul_vt100_emuldata *edp = cookie; 1000 1001 edp->msgattrs = *ma; 1002 if (type->capabilities & WSSCREEN_WSCOLORS) { 1003 edp->msgattrs.default_attrs |= WSATTR_WSCOLORS; 1004 edp->msgattrs.kernel_attrs |= WSATTR_WSCOLORS; 1005 } else { 1006 edp->msgattrs.default_bg = edp->msgattrs.kernel_bg = 0; 1007 edp->msgattrs.default_fg = edp->msgattrs.kernel_fg = 0; 1008 } 1009 1010 error = (*edp->emulops->allocattr)(edp->emulcookie, 1011 edp->msgattrs.default_fg, 1012 edp->msgattrs.default_bg, 1013 edp->msgattrs.default_attrs, 1014 &tmp); 1015 #ifdef VT100_DEBUG 1016 if (error) 1017 printf("vt100: failed to allocate attribute for default " 1018 "messages\n"); 1019 else 1020 #endif 1021 { 1022 if (edp->curattr == edp->defattr) { 1023 edp->bkgdattr = edp->curattr = tmp; 1024 edp->attrflags = edp->msgattrs.default_attrs; 1025 edp->bgcol = edp->msgattrs.default_bg; 1026 edp->fgcol = edp->msgattrs.default_fg; 1027 } else { 1028 edp->savedbkgdattr = edp->savedattr = tmp; 1029 edp->savedattrflags = edp->msgattrs.default_attrs; 1030 edp->savedbgcol = edp->msgattrs.default_bg; 1031 edp->savedfgcol = edp->msgattrs.default_fg; 1032 } 1033 if (edp->emulops->replaceattr != NULL) 1034 (*edp->emulops->replaceattr)(edp->emulcookie, 1035 edp->defattr, tmp); 1036 edp->defattr = tmp; 1037 } 1038 1039 error = (*edp->emulops->allocattr)(edp->emulcookie, 1040 edp->msgattrs.kernel_fg, 1041 edp->msgattrs.kernel_bg, 1042 edp->msgattrs.kernel_attrs, 1043 &tmp); 1044 #ifdef VT100_DEBUG 1045 if (error) 1046 printf("vt100: failed to allocate attribute for kernel " 1047 "messages\n"); 1048 else 1049 #endif 1050 { 1051 if (edp->emulops->replaceattr != NULL) 1052 (*edp->emulops->replaceattr)(edp->emulcookie, 1053 edp->kernattr, tmp); 1054 edp->kernattr = tmp; 1055 } 1056 } 1057 #endif /* WSDISPLAY_CUSTOM_OUTPUT */ 1058