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