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