1 /* $NetBSD: wsemul_vt100.c,v 1.35 2010/02/11 10:07:14 drochner 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.35 2010/02/11 10:07:14 drochner 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 46 void *wsemul_vt100_cnattach(const struct wsscreen_descr *, void *, 47 int, int, long); 48 void *wsemul_vt100_attach(int console, const struct wsscreen_descr *, 49 void *, int, int, void *, long); 50 void wsemul_vt100_output(void *cookie, const u_char *data, u_int count, int); 51 void wsemul_vt100_detach(void *cookie, u_int *crowp, u_int *ccolp); 52 void wsemul_vt100_resetop(void *, enum wsemul_resetops); 53 #ifdef WSDISPLAY_CUSTOM_OUTPUT 54 static void wsemul_vt100_getmsgattrs(void *, struct wsdisplay_msgattrs *); 55 static void wsemul_vt100_setmsgattrs(void *, const struct wsscreen_descr *, 56 const struct wsdisplay_msgattrs *); 57 #endif /* WSDISPLAY_CUSTOM_OUTPUT */ 58 59 const 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 76 struct wsemul_vt100_emuldata wsemul_vt100_console_emuldata; 77 78 static void wsemul_vt100_init(struct wsemul_vt100_emuldata *, 79 const struct wsscreen_descr *, 80 void *, int, int, long); 81 82 static void wsemul_vt100_output_normal(struct wsemul_vt100_emuldata *, 83 u_char, int); 84 static void wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata *, 85 u_char, int); 86 static void wsemul_vt100_nextline(struct wsemul_vt100_emuldata *); 87 typedef u_int vt100_handler(struct wsemul_vt100_emuldata *, u_char); 88 89 static vt100_handler 90 wsemul_vt100_output_esc, 91 wsemul_vt100_output_csi, 92 wsemul_vt100_output_scs94, 93 wsemul_vt100_output_scs94_percent, 94 wsemul_vt100_output_scs96, 95 wsemul_vt100_output_scs96_percent, 96 wsemul_vt100_output_esc_hash, 97 wsemul_vt100_output_esc_spc, 98 wsemul_vt100_output_string, 99 wsemul_vt100_output_string_esc, 100 wsemul_vt100_output_dcs, 101 wsemul_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 117 vt100_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 132 static void 133 wsemul_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 207 void * 208 wsemul_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 232 void * 233 wsemul_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 267 void 268 wsemul_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 288 void 289 wsemul_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 312 void 313 wsemul_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 */ 351 static void 352 wsemul_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 367 static void 368 wsemul_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 406 static void 407 wsemul_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 490 static u_int 491 wsemul_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 620 static u_int 621 wsemul_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 654 static u_int 655 wsemul_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 671 static u_int 672 wsemul_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; 713 setnrc: 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 725 static u_int 726 wsemul_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 741 static u_int 742 wsemul_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 761 static u_int 762 wsemul_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 771 static u_int 772 wsemul_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 783 static u_int 784 wsemul_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 833 static u_int 834 wsemul_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 874 static u_int 875 wsemul_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 930 static u_int 931 wsemul_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 973 void 974 wsemul_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 1008 static void 1009 wsemul_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 1017 static void 1018 wsemul_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