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