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