wsemul_vt100.c revision 1.47
1/* $OpenBSD: wsemul_vt100.c,v 1.28 2011/08/04 04:18:42 miod 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.47 2021/06/07 15:52:08 christos 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_WAITOK); 257 vd->dblwid = malloc(1024, M_DEVBUF, M_WAITOK|M_ZERO); 258 vd->dw = 0; 259 vd->dcsarg = malloc(DCS_MAXLEN, M_DEVBUF, M_WAITOK); 260 edp->isolatin1tab = malloc(128 * sizeof(int), M_DEVBUF, M_WAITOK); 261 edp->decgraphtab = malloc(128 * sizeof(int), M_DEVBUF, M_WAITOK); 262 edp->dectechtab = malloc(128 * sizeof(int), M_DEVBUF, M_WAITOK); 263 edp->nrctab = malloc(128 * sizeof(int), M_DEVBUF, M_WAITOK); 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 if (edp->state == VT100_EMUL_STATE_STRING) { 433 /* acts as an equivalent to the ``ESC \'' string end */ 434 wsemul_vt100_handle_dcs(vd); 435 edp->state = VT100_EMUL_STATE_NORMAL; 436 } else { 437 wsdisplay_emulbell(vd->cbcookie); 438 } 439 break; 440 case ASCII_BS: 441 if (vd->ccol > 0) { 442 vd->ccol--; 443 vd->flags &= ~VTFL_LASTCHAR; 444 } 445 break; 446 case ASCII_CR: 447 vd->ccol = 0; 448 vd->flags &= ~VTFL_LASTCHAR; 449 break; 450 case ASCII_HT: 451 if (vd->tabs) { 452 if (!COLS_LEFT(vd)) 453 break; 454 for (n = vd->ccol + 1; n < NCOLS(vd) - 1; n++) 455 if (vd->tabs[n]) 456 break; 457 } else { 458 n = vd->ccol + uimin(8 - (vd->ccol & 7), COLS_LEFT(vd)); 459 } 460 vd->ccol = n; 461 break; 462 case ASCII_SO: /* LS1 */ 463 edp->chartab0 = 1; 464 break; 465 case ASCII_SI: /* LS0 */ 466 edp->chartab0 = 0; 467 break; 468 case ASCII_ESC: 469 if (kernel) { 470 printf("%s: ESC in kernel output ignored\n", __func__); 471 break; /* ignore the ESC */ 472 } 473 474 if (edp->state == VT100_EMUL_STATE_STRING) { 475 /* might be a string end */ 476 edp->state = VT100_EMUL_STATE_STRING_ESC; 477 } else { 478 /* XXX cancel current escape sequence */ 479 edp->state = VT100_EMUL_STATE_ESC; 480 } 481 break; 482#if 0 483 case CSI: /* 8-bit */ 484 /* XXX cancel current escape sequence */ 485 edp->nargs = 0; 486 memset(edp->args, 0, sizeof (edp->args)); 487 edp->modif1 = edp->modif2 = '\0'; 488 edp->state = VT100_EMUL_STATE_CSI; 489 break; 490 case DCS: /* 8-bit */ 491 /* XXX cancel current escape sequence */ 492 edp->nargs = 0; 493 memset(edp->args, 0, sizeof (edp->args)); 494 edp->state = VT100_EMUL_STATE_DCS; 495 break; 496 case ST: /* string end 8-bit */ 497 /* XXX only in VT100_EMUL_STATE_STRING */ 498 wsemul_vt100_handle_dcs(vd); 499 edp->state = VT100_EMUL_STATE_NORMAL; 500 break; 501#endif 502 case ASCII_LF: 503 case ASCII_VT: 504 case ASCII_FF: 505 wsemul_vt100_nextline(edp); 506 break; 507 } 508} 509 510static u_int 511wsemul_vt100_output_esc(struct wsemul_vt100_emuldata *edp, u_char c) 512{ 513 struct vt100base_data *vd = &edp->bd; 514 int i; 515 516 switch (c) { 517 case '[': /* CSI */ 518 vd->nargs = 0; 519 memset(vd->args, 0, sizeof (vd->args)); 520 vd->modif1 = vd->modif2 = '\0'; 521 return VT100_EMUL_STATE_CSI; 522 case '7': /* DECSC */ 523 vd->flags |= VTFL_SAVEDCURS; 524 edp->savedcursor_row = vd->crow; 525 edp->savedcursor_col = vd->ccol; 526 edp->savedattr = vd->curattr; 527 edp->savedbkgdattr = vd->bkgdattr; 528 edp->savedattrflags = vd->attrflags; 529 edp->savedfgcol = vd->fgcol; 530 edp->savedbgcol = vd->bgcol; 531 for (i = 0; i < 4; i++) 532 edp->savedchartab_G[i] = edp->chartab_G[i]; 533 edp->savedchartab0 = edp->chartab0; 534 edp->savedchartab1 = edp->chartab1; 535 break; 536 case '8': /* DECRC */ 537 if ((vd->flags & VTFL_SAVEDCURS) == 0) 538 break; 539 vd->crow = edp->savedcursor_row; 540 vd->ccol = edp->savedcursor_col; 541 vd->curattr = edp->savedattr; 542 vd->bkgdattr = edp->savedbkgdattr; 543 vd->attrflags = edp->savedattrflags; 544 vd->fgcol = edp->savedfgcol; 545 vd->bgcol = edp->savedbgcol; 546 for (i = 0; i < 4; i++) 547 edp->chartab_G[i] = edp->savedchartab_G[i]; 548 edp->chartab0 = edp->savedchartab0; 549 edp->chartab1 = edp->savedchartab1; 550 break; 551 case '=': /* DECKPAM application mode */ 552 vd->flags |= VTFL_APPLKEYPAD; 553 break; 554 case '>': /* DECKPNM numeric mode */ 555 vd->flags &= ~VTFL_APPLKEYPAD; 556 break; 557 case 'E': /* NEL */ 558 vd->ccol = 0; 559 /* FALLTHRU */ 560 case 'D': /* IND */ 561 wsemul_vt100_nextline(edp); 562 break; 563 case 'H': /* HTS */ 564 KASSERT(vd->tabs != 0); 565 vd->tabs[vd->ccol] = 1; 566 break; 567 case '~': /* LS1R */ 568 edp->chartab1 = 1; 569 break; 570 case 'n': /* LS2 */ 571 edp->chartab0 = 2; 572 break; 573 case '}': /* LS2R */ 574 edp->chartab1 = 2; 575 break; 576 case 'o': /* LS3 */ 577 edp->chartab0 = 3; 578 break; 579 case '|': /* LS3R */ 580 edp->chartab1 = 3; 581 break; 582 case 'N': /* SS2 */ 583 edp->sschartab = 2; 584 break; 585 case 'O': /* SS3 */ 586 edp->sschartab = 3; 587 break; 588 case 'M': /* RI */ 589 if (ROWS_ABOVE(vd) > 0) { 590 vd->crow--; 591 CHECK_DW(vd); 592 break; 593 } 594 wsemul_vt100_scrolldown(vd, 1); 595 break; 596 case 'P': /* DCS */ 597 vd->nargs = 0; 598 memset(vd->args, 0, sizeof (vd->args)); 599 return VT100_EMUL_STATE_DCS; 600 case 'c': /* RIS */ 601 wsemul_vt100_reset(edp); 602 wsemul_vt100_ed(vd, 2); 603 vd->ccol = vd->crow = 0; 604 break; 605 case '(': case ')': case '*': case '+': /* SCS */ 606 edp->designating = c - '('; 607 return VT100_EMUL_STATE_SCS94; 608 case '-': case '.': case '/': /* SCS */ 609 edp->designating = c - '-' + 1; 610 return VT100_EMUL_STATE_SCS96; 611 case '#': 612 return VT100_EMUL_STATE_ESC_HASH; 613 case ' ': /* 7/8 bit */ 614 return VT100_EMUL_STATE_ESC_SPC; 615 case ']': /* OSC operating system command */ 616 case '^': /* PM privacy message */ 617 case '_': /* APC application program command */ 618 /* ignored */ 619 return VT100_EMUL_STATE_STRING; 620 case '<': /* exit VT52 mode - ignored */ 621 break; 622 default: 623#ifdef VT100_PRINTUNKNOWN 624 printf("ESC%c unknown\n", c); 625#endif 626 break; 627 } 628 return VT100_EMUL_STATE_NORMAL; 629} 630 631static u_int 632wsemul_vt100_output_scs94(struct wsemul_vt100_emuldata *edp, u_char c) 633{ 634 switch (c) { 635 case '%': /* probably DEC supplemental graphic */ 636 return VT100_EMUL_STATE_SCS94_PERCENT; 637 case 'A': /* british / national */ 638 edp->chartab_G[edp->designating] = edp->nrctab; 639 break; 640 case 'B': /* ASCII */ 641 edp->chartab_G[edp->designating] = 0; 642 break; 643 case '<': /* user preferred supplemental */ 644 /* XXX not really "user" preferred */ 645 edp->chartab_G[edp->designating] = edp->isolatin1tab; 646 break; 647 case '0': /* DEC special graphic */ 648 edp->chartab_G[edp->designating] = edp->decgraphtab; 649 break; 650 case '>': /* DEC tech */ 651 edp->chartab_G[edp->designating] = edp->dectechtab; 652 break; 653 default: 654#ifdef VT100_PRINTUNKNOWN 655 printf("ESC%c%c unknown\n", edp->designating + '(', c); 656#endif 657 break; 658 } 659 return VT100_EMUL_STATE_NORMAL; 660} 661 662static u_int 663wsemul_vt100_output_scs94_percent(struct wsemul_vt100_emuldata *edp, u_char c) 664{ 665 switch (c) { 666 case '5': /* DEC supplemental graphic */ 667 /* XXX there are differences */ 668 edp->chartab_G[edp->designating] = edp->isolatin1tab; 669 break; 670 default: 671#ifdef VT100_PRINTUNKNOWN 672 printf("ESC%c%%%c unknown\n", edp->designating + '(', c); 673#endif 674 break; 675 } 676 return VT100_EMUL_STATE_NORMAL; 677} 678 679static u_int 680wsemul_vt100_output_scs96(struct wsemul_vt100_emuldata *edp, u_char c) 681{ 682 int nrc; 683 684 switch (c) { 685 case '%': /* probably portuguese */ 686 return VT100_EMUL_STATE_SCS96_PERCENT; 687 case 'A': /* ISO-latin-1 supplemental */ 688 edp->chartab_G[edp->designating] = edp->isolatin1tab; 689 break; 690 case '4': /* dutch */ 691 nrc = 1; 692 goto setnrc; 693 case '5': case 'C': /* finnish */ 694 nrc = 2; 695 goto setnrc; 696 case 'R': /* french */ 697 nrc = 3; 698 goto setnrc; 699 case 'Q': /* french canadian */ 700 nrc = 4; 701 goto setnrc; 702 case 'K': /* german */ 703 nrc = 5; 704 goto setnrc; 705 case 'Y': /* italian */ 706 nrc = 6; 707 goto setnrc; 708 case 'E': case '6': /* norwegian / danish */ 709 nrc = 7; 710 goto setnrc; 711 case 'Z': /* spanish */ 712 nrc = 9; 713 goto setnrc; 714 case '7': case 'H': /* swedish */ 715 nrc = 10; 716 goto setnrc; 717 case '=': /* swiss */ 718 nrc = 11; 719setnrc: 720 vt100_setnrc(edp, nrc); /* what table ??? */ 721 break; 722 default: 723#ifdef VT100_PRINTUNKNOWN 724 printf("ESC%c%c unknown\n", edp->designating + '-' - 1, c); 725#endif 726 break; 727 } 728 return VT100_EMUL_STATE_NORMAL; 729} 730 731static u_int 732wsemul_vt100_output_scs96_percent(struct wsemul_vt100_emuldata *edp, u_char c) 733{ 734 switch (c) { 735 case '6': /* portuguese */ 736 vt100_setnrc(edp, 8); 737 break; 738 default: 739#ifdef VT100_PRINTUNKNOWN 740 printf("ESC%c%%%c unknown\n", edp->designating + '-', c); 741#endif 742 break; 743 } 744 return VT100_EMUL_STATE_NORMAL; 745} 746 747static u_int 748wsemul_vt100_output_esc_spc(struct wsemul_vt100_emuldata *edp, 749 u_char c) 750{ 751 switch (c) { 752 case 'F': /* 7-bit controls */ 753 case 'G': /* 8-bit controls */ 754#ifdef VT100_PRINTNOTIMPL 755 printf("ESC<SPC>%c ignored\n", c); 756#endif 757 break; 758 default: 759#ifdef VT100_PRINTUNKNOWN 760 printf("ESC<SPC>%c unknown\n", c); 761#endif 762 break; 763 } 764 return VT100_EMUL_STATE_NORMAL; 765} 766 767static u_int 768wsemul_vt100_output_string(struct wsemul_vt100_emuldata *edp, u_char c) 769{ 770 struct vt100base_data *vd = &edp->bd; 771 772 if (vd->dcstype && vd->dcspos < DCS_MAXLEN) 773 vd->dcsarg[vd->dcspos++] = c; 774 return VT100_EMUL_STATE_STRING; 775} 776 777static u_int 778wsemul_vt100_output_string_esc(struct wsemul_vt100_emuldata *edp, u_char c) 779{ 780 struct vt100base_data *vd = &edp->bd; 781 782 if (c == '\\') { /* ST complete */ 783 wsemul_vt100_handle_dcs(vd); 784 return VT100_EMUL_STATE_NORMAL; 785 } else 786 return VT100_EMUL_STATE_STRING; 787} 788 789static u_int 790wsemul_vt100_output_dcs(struct wsemul_vt100_emuldata *edp, u_char c) 791{ 792 struct vt100base_data *vd = &edp->bd; 793 794 switch (c) { 795 case '0': case '1': case '2': case '3': case '4': 796 case '5': case '6': case '7': case '8': case '9': 797 /* argument digit */ 798 if (vd->nargs > VT100_EMUL_NARGS - 1) 799 break; 800 vd->args[vd->nargs] = (vd->args[vd->nargs] * 10) + 801 (c - '0'); 802 break; 803 case ';': /* argument terminator */ 804 vd->nargs++; 805 break; 806 default: 807 vd->nargs++; 808 if (vd->nargs > VT100_EMUL_NARGS) { 809#ifdef VT100_DEBUG 810 printf("vt100: too many arguments\n"); 811#endif 812 vd->nargs = VT100_EMUL_NARGS; 813 } 814 switch (c) { 815 case '$': 816 return VT100_EMUL_STATE_DCS_DOLLAR; 817 case '{': /* DECDLD soft charset */ 818 case '!': /* DECRQUPSS user preferred supplemental set */ 819 /* 'u' must follow - need another state */ 820 case '|': /* DECUDK program F6..F20 */ 821#ifdef VT100_PRINTNOTIMPL 822 printf("DCS%c ignored\n", c); 823#endif 824 break; 825 default: 826#ifdef VT100_PRINTUNKNOWN 827 printf("DCS%c (%d, %d) unknown\n", c, ARG(vd, 0), ARG(vd, 1)); 828#endif 829 break; 830 } 831 return VT100_EMUL_STATE_STRING; 832 } 833 834 return VT100_EMUL_STATE_DCS; 835} 836 837static u_int 838wsemul_vt100_output_dcs_dollar(struct wsemul_vt100_emuldata *edp, u_char c) 839{ 840 struct vt100base_data *vd = &edp->bd; 841 842 switch (c) { 843 case 'p': /* DECRSTS terminal state restore */ 844 case 'q': /* DECRQSS control function request */ 845#ifdef VT100_PRINTNOTIMPL 846 printf("DCS$%c ignored\n", c); 847#endif 848 break; 849 case 't': /* DECRSPS restore presentation state */ 850 switch (ARG(vd, 0)) { 851 case 0: /* error */ 852 break; 853 case 1: /* cursor information restore */ 854#ifdef VT100_PRINTNOTIMPL 855 printf("DCS1$t ignored\n"); 856#endif 857 break; 858 case 2: /* tab stop restore */ 859 vd->dcspos = 0; 860 vd->dcstype = DCSTYPE_TABRESTORE; 861 break; 862 default: 863#ifdef VT100_PRINTUNKNOWN 864 printf("DCS%d$t unknown\n", ARG(vd, 0)); 865#endif 866 break; 867 } 868 break; 869 default: 870#ifdef VT100_PRINTUNKNOWN 871 printf("DCS$%c (%d, %d) unknown\n", c, ARG(vd, 0), ARG(vd, 1)); 872#endif 873 break; 874 } 875 return VT100_EMUL_STATE_STRING; 876} 877 878static u_int 879wsemul_vt100_output_esc_hash(struct wsemul_vt100_emuldata *edp, u_char c) 880{ 881 struct vt100base_data *vd = &edp->bd; 882 int i, j; 883 884 switch (c) { 885 case '5': /* DECSWL single width, single height */ 886 if (vd->dw) { 887 for (i = 0; i < vd->ncols / 2; i++) 888 (*vd->emulops->copycols)(vd->emulcookie, 889 vd->crow, 890 2 * i, i, 1); 891 (*vd->emulops->erasecols)(vd->emulcookie, vd->crow, 892 i, vd->ncols - i, 893 vd->bkgdattr); 894 vd->dblwid[vd->crow] = 0; 895 vd->dw = 0; 896 } 897 break; 898 case '6': /* DECDWL double width, single height */ 899 case '3': /* DECDHL double width, double height, top half */ 900 case '4': /* DECDHL double width, double height, bottom half */ 901 if (!vd->dw) { 902 for (i = vd->ncols / 2 - 1; i >= 0; i--) 903 (*vd->emulops->copycols)(vd->emulcookie, 904 vd->crow, 905 i, 2 * i, 1); 906 for (i = 0; i < vd->ncols / 2; i++) 907 (*vd->emulops->erasecols)(vd->emulcookie, 908 vd->crow, 909 2 * i + 1, 1, 910 vd->bkgdattr); 911 vd->dblwid[vd->crow] = 1; 912 vd->dw = 1; 913 if (vd->ccol > (vd->ncols >> 1) - 1) 914 vd->ccol = (vd->ncols >> 1) - 1; 915 } 916 break; 917 case '8': /* DECALN */ 918 for (i = 0; i < vd->nrows; i++) 919 for (j = 0; j < vd->ncols; j++) 920 (*vd->emulops->putchar)(vd->emulcookie, i, j, 921 'E', vd->curattr); 922 vd->ccol = 0; 923 vd->crow = 0; 924 break; 925 default: 926#ifdef VT100_PRINTUNKNOWN 927 printf("ESC#%c unknown\n", c); 928#endif 929 break; 930 } 931 return VT100_EMUL_STATE_NORMAL; 932} 933 934static u_int 935wsemul_vt100_output_csi(struct wsemul_vt100_emuldata *edp, u_char c) 936{ 937 struct vt100base_data *vd = &edp->bd; 938 939 switch (c) { 940 case '0': case '1': case '2': case '3': case '4': 941 case '5': case '6': case '7': case '8': case '9': 942 /* argument digit */ 943 if (vd->nargs > VT100_EMUL_NARGS - 1) 944 break; 945 vd->args[vd->nargs] = (vd->args[vd->nargs] * 10) + 946 (c - '0'); 947 break; 948 case ';': /* argument terminator */ 949 vd->nargs++; 950 break; 951 case '?': /* DEC specific */ 952 case '>': /* DA query */ 953 vd->modif1 = c; 954 break; 955 case '!': 956 case '"': 957 case '$': 958 case '&': 959 vd->modif2 = c; 960 break; 961 default: /* end of escape sequence */ 962 vd->nargs++; 963 if (vd->nargs > VT100_EMUL_NARGS) { 964#ifdef VT100_DEBUG 965 printf("vt100: too many arguments\n"); 966#endif 967 vd->nargs = VT100_EMUL_NARGS; 968 } 969 wsemul_vt100_handle_csi(vd, c); 970 return VT100_EMUL_STATE_NORMAL; 971 } 972 return VT100_EMUL_STATE_CSI; 973} 974 975void 976wsemul_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("%s: kernel output, not console", __func__); 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 int state = edp->state - 1; 999 KASSERT(state < __arraycount(vt100_output)); 1000 edp->state = vt100_output[state](edp, *data); 1001 } 1002 if (vd->flags & VTFL_CURSORON) 1003 (*vd->emulops->cursor)(vd->emulcookie, 1, 1004 vd->crow, vd->ccol << vd->dw); 1005} 1006 1007#ifdef WSDISPLAY_CUSTOM_OUTPUT 1008static void 1009wsemul_vt100_getmsgattrs(void *cookie, struct wsdisplay_msgattrs *ma) 1010{ 1011 struct wsemul_vt100_emuldata *edp = cookie; 1012 struct vt100base_data *vd = &edp->bd; 1013 1014 *ma = vd->msgattrs; 1015} 1016 1017static void 1018wsemul_vt100_setmsgattrs(void *cookie, const struct wsscreen_descr *type, 1019 const struct wsdisplay_msgattrs *ma) 1020{ 1021 int error; 1022 long tmp; 1023 struct wsemul_vt100_emuldata *edp = cookie; 1024 struct vt100base_data *vd = &edp->bd; 1025 1026 vd->msgattrs = *ma; 1027 if (type->capabilities & WSSCREEN_WSCOLORS) { 1028 vd->msgattrs.default_attrs |= WSATTR_WSCOLORS; 1029 vd->msgattrs.kernel_attrs |= WSATTR_WSCOLORS; 1030 } else { 1031 vd->msgattrs.default_bg = vd->msgattrs.kernel_bg = 0; 1032 vd->msgattrs.default_fg = vd->msgattrs.kernel_fg = 0; 1033 } 1034 1035 error = (*vd->emulops->allocattr)(vd->emulcookie, 1036 vd->msgattrs.default_fg, 1037 vd->msgattrs.default_bg, 1038 vd->msgattrs.default_attrs, 1039 &tmp); 1040#ifndef VT100_DEBUG 1041 __USE(error); 1042#else 1043 if (error) 1044 printf("vt100: failed to allocate attribute for default " 1045 "messages\n"); 1046 else 1047#endif 1048 { 1049 if (vd->curattr == vd->defattr) { 1050 vd->bkgdattr = vd->curattr = tmp; 1051 vd->attrflags = vd->msgattrs.default_attrs; 1052 vd->bgcol = vd->msgattrs.default_bg; 1053 vd->fgcol = vd->msgattrs.default_fg; 1054 } else { 1055 edp->savedbkgdattr = edp->savedattr = tmp; 1056 edp->savedattrflags = vd->msgattrs.default_attrs; 1057 edp->savedbgcol = vd->msgattrs.default_bg; 1058 edp->savedfgcol = vd->msgattrs.default_fg; 1059 } 1060 if (vd->emulops->replaceattr != NULL) 1061 (*vd->emulops->replaceattr)(vd->emulcookie, 1062 vd->defattr, tmp); 1063 vd->defattr = tmp; 1064 } 1065 1066 error = (*vd->emulops->allocattr)(vd->emulcookie, 1067 vd->msgattrs.kernel_fg, 1068 vd->msgattrs.kernel_bg, 1069 vd->msgattrs.kernel_attrs, 1070 &tmp); 1071#ifdef VT100_DEBUG 1072 if (error) 1073 printf("vt100: failed to allocate attribute for kernel " 1074 "messages\n"); 1075 else 1076#endif 1077 { 1078 if (vd->emulops->replaceattr != NULL) 1079 (*vd->emulops->replaceattr)(vd->emulcookie, 1080 edp->kernattr, tmp); 1081 edp->kernattr = tmp; 1082 } 1083} 1084#endif /* WSDISPLAY_CUSTOM_OUTPUT */ 1085