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