Home | History | Annotate | Line # | Download | only in wscons
wsemul_vt100.c revision 1.1
      1 /* $NetBSD: wsemul_vt100.c,v 1.1 1998/06/20 19:17:47 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  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed for the NetBSD Project
     18  *	by Matthias Drochner.
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  *
     33  */
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/time.h>
     38 #include <sys/malloc.h>
     39 #include <sys/fcntl.h>
     40 
     41 #include <dev/wscons/wsconsio.h>
     42 #include <dev/wscons/wsdisplayvar.h>
     43 #include <dev/wscons/wsemulvar.h>
     44 #include <dev/wscons/wsemul_vt100var.h>
     45 #include <dev/wscons/ascii.h>
     46 
     47 #include "opt_wskernattr.h"
     48 
     49 void	*wsemul_vt100_cnattach __P((const struct wsscreen_descr *, void *,
     50 				  int, int, long));
     51 void	*wsemul_vt100_attach __P((int console, const struct wsscreen_descr *,
     52 				  void *, int, int, void *, long));
     53 void	wsemul_vt100_output __P((void *cookie, const u_char *data, u_int count,
     54 				 int));
     55 void	wsemul_vt100_detach __P((void *cookie, u_int *crowp, u_int *ccolp));
     56 
     57 const struct wsemul_ops wsemul_vt100_ops = {
     58 	"vt100",
     59 	wsemul_vt100_cnattach,
     60 	wsemul_vt100_attach,
     61 	wsemul_vt100_output,
     62 	wsemul_vt100_translate,
     63 	wsemul_vt100_detach,
     64 };
     65 
     66 struct wsemul_vt100_emuldata wsemul_vt100_console_emuldata;
     67 
     68 static void wsemul_vt100_init __P((struct wsemul_vt100_emuldata *,
     69 				   const struct wsscreen_descr *,
     70 				   void *, int, int, long));
     71 
     72 static u_int wsemul_vt100_output_normal __P((struct wsemul_vt100_emuldata *,
     73 					     u_char, int));
     74 typedef u_int vt100_handler __P((struct wsemul_vt100_emuldata *, u_char));
     75 static vt100_handler
     76 wsemul_vt100_output_esc,
     77 wsemul_vt100_output_csi,
     78 wsemul_vt100_output_csi_qm,
     79 wsemul_vt100_output_scs94,
     80 wsemul_vt100_output_scs94_percent,
     81 wsemul_vt100_output_scs96,
     82 wsemul_vt100_output_scs96_percent,
     83 wsemul_vt100_output_hash,
     84 wsemul_vt100_output_esc_spc,
     85 wsemul_vt100_output_csi_gt,
     86 wsemul_vt100_output_string,
     87 wsemul_vt100_output_string_esc,
     88 wsemul_vt100_output_csi_dq,
     89 wsemul_vt100_output_dcs,
     90 wsemul_vt100_output_csi_dollar,
     91 wsemul_vt100_output_csi_qm_dollar,
     92 wsemul_vt100_output_csi_amp,
     93 wsemul_vt100_output_csi_em,
     94 wsemul_vt100_output_dcs_dollar;
     95 
     96 #define	VT100_EMUL_STATE_NORMAL		0	/* normal processing */
     97 #define	VT100_EMUL_STATE_ESC		1	/* got ESC */
     98 #define	VT100_EMUL_STATE_CSI		2	/* got CSI (ESC[) */
     99 #define	VT100_EMUL_STATE_CSI_QM		3	/* got CSI? */
    100 #define	VT100_EMUL_STATE_SCS94		4	/* got ESC{()*+} */
    101 #define	VT100_EMUL_STATE_SCS94_PERCENT	5	/* got ESC{()*+}% */
    102 #define	VT100_EMUL_STATE_SCS96		6	/* got ESC{-./} */
    103 #define	VT100_EMUL_STATE_SCS96_PERCENT	7	/* got ESC{-./}% */
    104 #define	VT100_EMUL_STATE_HASH		8	/* got ESC# */
    105 #define	VT100_EMUL_STATE_ESC_SPC	9	/* got ESC<SPC> */
    106 #define	VT100_EMUL_STATE_CSI_GT		10	/* got CSI> */
    107 #define	VT100_EMUL_STATE_STRING		11	/* waiting for ST (ESC\) */
    108 #define	VT100_EMUL_STATE_STRING_ESC	12	/* waiting for ST, got ESC */
    109 #define	VT100_EMUL_STATE_CSI_DQ		13	/* got CSI<p>" */
    110 #define	VT100_EMUL_STATE_DCS		14	/* got DCS (ESC P) */
    111 #define	VT100_EMUL_STATE_CSI_DOLLAR	15	/* got CSI<p>$ */
    112 #define	VT100_EMUL_STATE_CSI_QM_DOLLAR	16	/* got CSI?<p>$ */
    113 #define	VT100_EMUL_STATE_CSI_AMP	17	/* got CSI& */
    114 #define	VT100_EMUL_STATE_CSI_EM		18	/* got CSI! */
    115 #define	VT100_EMUL_STATE_DCS_DOLLAR	19	/* got DCS<p>$ */
    116 
    117 vt100_handler *vt100_output[] = {
    118 	wsemul_vt100_output_esc,
    119 	wsemul_vt100_output_csi,
    120 	wsemul_vt100_output_csi_qm,
    121 	wsemul_vt100_output_scs94,
    122 	wsemul_vt100_output_scs94_percent,
    123 	wsemul_vt100_output_scs96,
    124 	wsemul_vt100_output_scs96_percent,
    125 	wsemul_vt100_output_hash,
    126 	wsemul_vt100_output_esc_spc,
    127 	wsemul_vt100_output_csi_gt,
    128 	wsemul_vt100_output_string,
    129 	wsemul_vt100_output_string_esc,
    130 	wsemul_vt100_output_csi_dq,
    131 	wsemul_vt100_output_dcs,
    132 	wsemul_vt100_output_csi_dollar,
    133 	wsemul_vt100_output_csi_qm_dollar,
    134 	wsemul_vt100_output_csi_amp,
    135 	wsemul_vt100_output_csi_em,
    136 	wsemul_vt100_output_dcs_dollar,
    137 };
    138 
    139 static void
    140 wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr)
    141 	struct wsemul_vt100_emuldata *edp;
    142 	const struct wsscreen_descr *type;
    143 	void *cookie;
    144 	int ccol, crow;
    145 	long defattr;
    146 {
    147 	edp->emulops = type->textops;
    148 	edp->emulcookie = cookie;
    149 	edp->scrcapabilities = type->capabilities;
    150 	edp->nrows = type->nrows;
    151 	edp->ncols = type->ncols;
    152 	edp->crow = crow;
    153 	edp->ccol = ccol;
    154 	edp->defattr = defattr;
    155 }
    156 
    157 void *
    158 wsemul_vt100_cnattach(type, cookie, ccol, crow, defattr)
    159 	const struct wsscreen_descr *type;
    160 	void *cookie;
    161 	int ccol, crow;
    162 	long defattr;
    163 {
    164 	struct wsemul_vt100_emuldata *edp;
    165 	int res;
    166 
    167 	edp = &wsemul_vt100_console_emuldata;
    168 	wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr);
    169 #ifdef DIAGNOSTIC
    170 	edp->console = 1;
    171 #endif
    172 	edp->cbcookie = NULL;
    173 
    174 #if defined(WS_KERNEL_FG) || defined(WS_KERNEL_BG) || \
    175   defined(WS_KERNEL_COLATTR) || defined(WS_KERNEL_MONOATTR)
    176 #ifndef WS_KERNEL_FG
    177 #define WS_KERNEL_FG WSCOL_WHITE
    178 #endif
    179 #ifndef WS_KERNEL_BG
    180 #define WS_KERNEL_BG WSCOL_BLACK
    181 #endif
    182 #ifndef WS_KERNEL_COLATTR
    183 #define WS_KERNEL_COLATTR 0
    184 #endif
    185 #ifndef WS_KERNEL_MONOATTR
    186 #define WS_KERNEL_MONOATTR 0
    187 #endif
    188 	if (type->capabilities & WSSCREEN_WSCOLORS)
    189 		res = (*edp->emulops->alloc_attr)(cookie,
    190 					    WS_KERNEL_FG, WS_KERNEL_BG,
    191 					    WS_KERNEL_COLATTR | WSATTR_WSCOLORS,
    192 					    &edp->kernattr);
    193 	else
    194 		res = (*edp->emulops->alloc_attr)(cookie, 0, 0,
    195 					    WS_KERNEL_MONOATTR,
    196 					    &edp->kernattr);
    197 	if (res)
    198 #endif
    199 	edp->kernattr = defattr;
    200 
    201 	edp->tabs = 0;
    202 	edp->dcsarg = 0;
    203 	wsemul_vt100_reset(edp);
    204 	return (edp);
    205 }
    206 
    207 void *
    208 wsemul_vt100_attach(console, type, cookie, ccol, crow, cbcookie, defattr)
    209 	int console;
    210 	const struct wsscreen_descr *type;
    211 	void *cookie;
    212 	int ccol, crow;
    213 	void *cbcookie;
    214 	long defattr;
    215 {
    216 	struct wsemul_vt100_emuldata *edp;
    217 
    218 	if (console) {
    219 		edp = &wsemul_vt100_console_emuldata;
    220 #ifdef DIAGNOSTIC
    221 		KASSERT(edp->console == 1);
    222 #endif
    223 	} else {
    224 		edp = malloc(sizeof *edp, M_DEVBUF, M_WAITOK);
    225 		wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr);
    226 #ifdef DIAGNOSTIC
    227 		edp->console = 0;
    228 #endif
    229 	}
    230 	edp->cbcookie = cbcookie;
    231 
    232 	edp->tabs = malloc(type->ncols, M_DEVBUF, M_NOWAIT);
    233 	edp->dcsarg = malloc(DCS_MAXLEN, M_DEVBUF, M_NOWAIT);
    234 	wsemul_vt100_reset(edp);
    235 	return (edp);
    236 }
    237 
    238 void
    239 wsemul_vt100_detach(cookie, crowp, ccolp)
    240 	void *cookie;
    241 	u_int *crowp, *ccolp;
    242 {
    243 	struct wsemul_vt100_emuldata *edp = cookie;
    244 
    245 	*crowp = edp->crow;
    246 	*ccolp = edp->ccol;
    247 	if (edp->tabs) {
    248 		free(edp->tabs, M_DEVBUF);
    249 		edp->tabs = 0;
    250 	}
    251 	if (edp->dcsarg) {
    252 		free(edp->dcsarg, M_DEVBUF);
    253 		edp->dcsarg = 0;
    254 	}
    255 	if (edp != &wsemul_vt100_console_emuldata)
    256 		free(edp, M_DEVBUF);
    257 }
    258 
    259 void
    260 wsemul_vt100_reset(edp)
    261 	struct wsemul_vt100_emuldata *edp;
    262 {
    263 	int i;
    264 
    265 	edp->state = VT100_EMUL_STATE_NORMAL;
    266 	edp->flags = VTFL_DECAWM | VTFL_CURSORON;
    267 	edp->curattr = edp->defattr;
    268 	edp->attrflags = 0;
    269 	edp->fgcol = WSCOL_WHITE;
    270 	edp->bgcol = WSCOL_BLACK;
    271 	edp->scrreg_startrow = 0;
    272 	edp->scrreg_nrows = edp->nrows;
    273 	if (edp->tabs) {
    274 		bzero(edp->tabs, edp->ncols);
    275 		for (i = 1; i < edp->ncols; i += 8 - (i & 7))
    276 			edp->tabs[i] = 1;
    277 	}
    278 	edp->dcspos = 0;
    279 	edp->dcstype = 0;
    280 }
    281 
    282 /*
    283  * now all the state machine bits
    284  */
    285 
    286 static u_int
    287 wsemul_vt100_output_normal(edp, c, kernel)
    288 	struct wsemul_vt100_emuldata *edp;
    289 	u_char c;
    290 	int kernel;
    291 {
    292 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    293 	u_int n;
    294 
    295 	switch (c) {
    296 	    case ASCII_NUL:
    297 		/* ignore */
    298 		break;
    299 	    case ASCII_BEL:
    300 		wsdisplay_emulbell(edp->cbcookie);
    301 		break;
    302 	    case ASCII_BS:
    303 		if (edp->ccol > 0) {
    304 			edp->ccol--;
    305 			edp->flags &= ~VTFL_LASTCHAR;
    306 		}
    307 		break;
    308 	    case ASCII_CR:
    309 		edp->ccol = 0;
    310 		edp->flags &= ~VTFL_LASTCHAR;
    311 		break;
    312 	    case ASCII_HT:
    313 		if (edp->tabs) {
    314 			if (edp->ccol >= edp->ncols - 1)
    315 				break;
    316 			for (n = edp->ccol + 1; n < edp->ncols - 1; n++)
    317 				if (edp->tabs[n])
    318 					break;
    319 		} else {
    320 			n = edp->ccol + min(8 - (edp->ccol & 7), COLS_LEFT);
    321 		}
    322 		(*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
    323 					   edp->ccol, n - edp->ccol,
    324 				     kernel ? edp->kernattr : edp->curattr);
    325 		edp->ccol = n;
    326 		break;
    327 	    case ASCII_SI: /* LS0 */
    328 #ifdef VT100_PRINTNOTIMPL
    329 		printf("SI ignored\n");
    330 #endif
    331 		break;
    332 	    case ASCII_SO: /* LS1 */
    333 #ifdef VT100_PRINTNOTIMPL
    334 		printf("SO ignored\n");
    335 #endif
    336 		break;
    337 	    case ASCII_ESC:
    338 #ifdef DIAGNOSTIC
    339 		if (kernel)
    340 			panic("ESC in kernel output");
    341 #endif
    342 		newstate = VT100_EMUL_STATE_ESC;
    343 		break;
    344 #if 0
    345 	    case CSI: /* 8-bit */
    346 		edp->nargs = 0;
    347 		bzero(edp->args, sizeof (edp->args));
    348 		newstate = VT100_EMUL_STATE_CSI;
    349 		break;
    350 	    case DCS: /* 8-bit */
    351 		edp->nargs = 0;
    352 		bzero(edp->args, sizeof (edp->args));
    353 		newstate = VT100_EMUL_STATE_DCS;
    354 		break;
    355 #endif
    356 	    default: /* normal character */
    357 		if ((edp->flags & (VTFL_LASTCHAR | VTFL_DECAWM)) ==
    358 		    (VTFL_LASTCHAR | VTFL_DECAWM)) {
    359 			if (ROWS_BELOW > 0)
    360 				edp->crow++;
    361 			else
    362 				wsemul_vt100_scrollup(edp, 1);
    363 			edp->ccol = 0;
    364 			edp->flags &= ~VTFL_LASTCHAR;
    365 		}
    366 
    367 		if ((edp->flags & VTFL_INSERTMODE) &&
    368 		    edp->ccol < edp->ncols - 1) {
    369 			(*edp->emulops->copycols)(edp->emulcookie, edp->crow,
    370 						  edp->ccol, edp->ccol + 1,
    371 						  edp->ncols - edp->ccol - 1);
    372 		}
    373 
    374 		(*edp->emulops->putstr)(edp->emulcookie, edp->crow, edp->ccol,
    375 					&c, 1,
    376 				    kernel ? edp->kernattr : edp->curattr);
    377 
    378 		if (edp->ccol < edp->ncols - 1)
    379 			edp->ccol++;
    380 		else
    381 			edp->flags |= VTFL_LASTCHAR;
    382 		break;
    383 	    case ASCII_LF:
    384 	    case ASCII_VT:
    385 	    case ASCII_FF:
    386 		if (ROWS_BELOW > 0)
    387 			edp->crow++;
    388 		else
    389 			wsemul_vt100_scrollup(edp, 1);
    390 		break;
    391 	}
    392 
    393 	return (newstate);
    394 }
    395 
    396 static u_int
    397 wsemul_vt100_output_esc(edp, c)
    398 	struct wsemul_vt100_emuldata *edp;
    399 	u_char c;
    400 {
    401 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    402 
    403 	switch (c) {
    404 	    case '[': /* CSI */
    405 		edp->nargs = 0;
    406 		bzero(edp->args, sizeof (edp->args));
    407 		newstate = VT100_EMUL_STATE_CSI;
    408 		break;
    409 	    case '7': /* DECSC */
    410 		edp->savedcursor_row = edp->crow;
    411 		edp->savedcursor_col = edp->ccol;
    412 		/* save attributes! */
    413 		break;
    414 	    case '8': /* DECRC */
    415 		edp->crow = edp->savedcursor_row;
    416 		edp->ccol = edp->savedcursor_col;
    417 		/* restore attributes! */
    418 		break;
    419 	    case '=': /* DECKPAM application mode */
    420 		edp->flags |= VTFL_APPLKEYPAD;
    421 		break;
    422 	    case '>': /* DECKPNM numeric mode */
    423 		edp->flags &= ~VTFL_APPLKEYPAD;
    424 		break;
    425 	    case 'E': /* NEL */
    426 		edp->ccol = 0;
    427 		/* FALLTHRU */
    428 	    case 'D': /* IND */
    429 		if (ROWS_BELOW > 0) {
    430 			edp->crow++;
    431 			break;
    432 		}
    433 		wsemul_vt100_scrollup(edp, 1);
    434 		break;
    435 	    case 'H': /* HTS */
    436 		KASSERT(edp->tabs != 0);
    437 		edp->tabs[edp->ccol] = 1;
    438 		break;
    439 	    case '~': /* LS1R */
    440 	    case 'n': /* LS2 */
    441 	    case '}': /* LS2R */
    442 	    case 'o': /* LS3 */
    443 	    case '|': /* LS3R */
    444 #ifdef VT100_PRINTNOTIMPL
    445 		printf("ESC %c ignored\n", c);
    446 #endif
    447 		break;
    448 	    case 'N': /* SS2 */
    449 	    case 'O': /* SS3 */
    450 #ifdef VT100_PRINTNOTIMPL
    451 		printf("ESC %c ignored\n", c);
    452 #endif
    453 		break;
    454 	    case 'M': /* RI */
    455 		if (ROWS_ABOVE > 0) {
    456 			edp->crow--;
    457 			break;
    458 		}
    459 		wsemul_vt100_scrolldown(edp, 1);
    460 		break;
    461 	    case 'P': /* DCS */
    462 		edp->nargs = 0;
    463 		bzero(edp->args, sizeof (edp->args));
    464 		newstate = VT100_EMUL_STATE_DCS;
    465 		break;
    466 	    case 'c': /* RIS */
    467 		wsemul_vt100_reset(edp);
    468 		edp->ccol = edp->crow = 0;
    469 		break;
    470 	    case '(': case ')': case '*': case '+': /* SCS */
    471 		edp->designating = c;
    472 		newstate = VT100_EMUL_STATE_SCS94;
    473 		break;
    474 	    case '-': case '.': case '/': /* SCS */
    475 		edp->designating = c;
    476 		newstate = VT100_EMUL_STATE_SCS96;
    477 		break;
    478 	    case '#':
    479 		newstate = VT100_EMUL_STATE_HASH;
    480 		break;
    481 	    case ' ': /* 7/8 bit */
    482 		newstate = VT100_EMUL_STATE_ESC_SPC;
    483 		break;
    484 	    case ']': /* OSC operating system command */
    485 	    case '^': /* PM privacy message */
    486 	    case '_': /* APC application program command */
    487 		/* ignored */
    488 		newstate = VT100_EMUL_STATE_STRING;
    489 		break;
    490 	    case '<': /* exit VT52 mode - ignored */
    491 		break;
    492 	    default:
    493 #ifdef VT100_PRINTUNKNOWN
    494 		printf("ESC%c unknown\n", c);
    495 #endif
    496 		break;
    497 	}
    498 
    499 	return (newstate);
    500 }
    501 
    502 static u_int
    503 wsemul_vt100_output_csi_qm(edp, c)
    504 	struct wsemul_vt100_emuldata *edp;
    505 	u_char c;
    506 {
    507 	u_int newstate = VT100_EMUL_STATE_CSI_QM;
    508 
    509 	switch (c) {
    510 	    case '0': case '1': case '2': case '3': case '4':
    511 	    case '5': case '6': case '7': case '8': case '9':
    512 		/* argument digit */
    513 		if (edp->nargs > VT100_EMUL_NARGS - 1)
    514 			break;
    515 		edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
    516 		    (c - '0');
    517 		break;
    518 	    case ';': /* argument terminator */
    519 		edp->nargs++;
    520 		break;
    521 	    case '$': /* request mode */
    522 		newstate = VT100_EMUL_STATE_CSI_QM_DOLLAR;
    523 		break;
    524 	    default: /* end of escape sequence */
    525 		edp->nargs++;
    526 		if (edp->nargs > VT100_EMUL_NARGS) {
    527 #ifdef VT100_DEBUG
    528 			printf("vt100: too many arguments\n");
    529 #endif
    530 			edp->nargs = VT100_EMUL_NARGS;
    531 		}
    532 		wsemul_vt100_handle_csi_qm(edp, c);
    533 		newstate = VT100_EMUL_STATE_NORMAL;
    534 		break;
    535 	}
    536 	return (newstate);
    537 }
    538 
    539 static u_int
    540 wsemul_vt100_output_csi_qm_dollar(edp, c)
    541 	struct wsemul_vt100_emuldata *edp;
    542 	u_char c;
    543 {
    544 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    545 
    546 	switch (c) {
    547 	    case 'p': /* DECRQM request DEC private mode */
    548 		vt100_reportmode(edp, ARG(0), 1);
    549 		break;
    550 	    default:
    551 #ifdef VT100_PRINTUNKNOWN
    552 		printf("CSI?%c unknown\n", c);
    553 #endif
    554 		break;
    555 	}
    556 
    557 	return (newstate);
    558 }
    559 
    560 static u_int
    561 wsemul_vt100_output_csi_amp(edp, c)
    562 	struct wsemul_vt100_emuldata *edp;
    563 	u_char c;
    564 {
    565 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    566 
    567 	switch (c) {
    568 	    case 'u': /* DECRQUPSS request user preferred supplemental set */
    569 		wsdisplay_emulinput(edp->emulcookie, "\033P0!u%5\033\\", 9);
    570 		break;
    571 	    default:
    572 #ifdef VT100_PRINTUNKNOWN
    573 		printf("CSI&%c unknown\n", c);
    574 #endif
    575 		break;
    576 	}
    577 
    578 	return (newstate);
    579 }
    580 
    581 static u_int
    582 wsemul_vt100_output_scs94(edp, c)
    583 	struct wsemul_vt100_emuldata *edp;
    584 	u_char c;
    585 {
    586 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    587 
    588 	switch (c) {
    589 	    case '%': /* probably DEC supplemental graphic */
    590 		newstate = VT100_EMUL_STATE_SCS94_PERCENT;
    591 		break;
    592 	    case 'B': /* ASCII */
    593 	    case 'A': /* ISO-latin-1 supplemental */
    594 	    case '<': /* user preferred supplemental */
    595 	    case '0': /* DEC special graphic */
    596 #ifdef VT100_PRINTNOTIMPL
    597 		printf("ESC%c%c ignored\n", edp->designating, c);
    598 #endif
    599 		break;
    600 	    default:
    601 #ifdef VT100_PRINTUNKNOWN
    602 		printf("ESC%c%c unknown\n", edp->designating, c);
    603 #endif
    604 		break;
    605 	}
    606 	return (newstate);
    607 }
    608 
    609 static u_int
    610 wsemul_vt100_output_scs94_percent(edp, c)
    611 	struct wsemul_vt100_emuldata *edp;
    612 	u_char c;
    613 {
    614 	switch (c) {
    615 	    case '5': /* DEC supplemental graphic */
    616 #ifdef VT100_PRINTNOTIMPL
    617 		printf("ESC%c%%5 ignored\n", edp->designating);
    618 #endif
    619 		break;
    620 	    default:
    621 #ifdef VT100_PRINTUNKNOWN
    622 		printf("ESC%c%%%c unknown\n", edp->designating, c);
    623 #endif
    624 		break;
    625 	}
    626 	return (VT100_EMUL_STATE_NORMAL);
    627 }
    628 
    629 static u_int
    630 wsemul_vt100_output_scs96(edp, c)
    631 	struct wsemul_vt100_emuldata *edp;
    632 	u_char c;
    633 {
    634 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    635 
    636 	switch (c) {
    637 	    case '%': /* probably portugese */
    638 		newstate = VT100_EMUL_STATE_SCS96_PERCENT;
    639 		break;
    640 	    case 'A': /* british */
    641 	    case '4': /* dutch */
    642 	    case '5': case 'C': /* finnish */
    643 	    case 'R': /* french */
    644 	    case 'Q': /* french canadian */
    645 	    case 'K': /* german */
    646 	    case 'Y': /* italian */
    647 	    case 'E': case '6': /* norwegian / danish */
    648 	    case 'Z': /* spanish */
    649 	    case '7': case 'H': /* swedish */
    650 	    case '=': /* swiss */
    651 #ifdef VT100_PRINTNOTIMPL
    652 		printf("ESC%c%c ignored\n", edp->designating, c);
    653 #endif
    654 		break;
    655 	    default:
    656 #ifdef VT100_PRINTUNKNOWN
    657 		printf("ESC%c%c unknown\n", edp->designating, c);
    658 #endif
    659 		break;
    660 	}
    661 	return (newstate);
    662 }
    663 
    664 static u_int
    665 wsemul_vt100_output_scs96_percent(edp, c)
    666 	struct wsemul_vt100_emuldata *edp;
    667 	u_char c;
    668 {
    669 	switch (c) {
    670 	    case '6': /* portugese */
    671 #ifdef VT100_PRINTNOTIMPL
    672 		printf("ESC%c%%6 ignored\n", edp->designating);
    673 #endif
    674 		break;
    675 	    default:
    676 #ifdef VT100_PRINTUNKNOWN
    677 		printf("ESC%c%%%c unknown\n", edp->designating, c);
    678 #endif
    679 		break;
    680 	}
    681 	return (VT100_EMUL_STATE_NORMAL);
    682 }
    683 
    684 static u_int
    685 wsemul_vt100_output_esc_spc(edp, c)
    686 	struct wsemul_vt100_emuldata *edp;
    687 	u_char c;
    688 {
    689 	switch (c) {
    690 	    case 'F': /* 7-bit controls */
    691 	    case 'G': /* 8-bit controls */
    692 #ifdef VT100_PRINTNOTIMPL
    693 		printf("ESC<SPC>%c ignored\n", c);
    694 #endif
    695 		break;
    696 	    default:
    697 #ifdef VT100_PRINTUNKNOWN
    698 		printf("ESC<SPC>%c unknown\n", c);
    699 #endif
    700 		break;
    701 	}
    702 	return (VT100_EMUL_STATE_NORMAL);
    703 }
    704 
    705 static u_int
    706 wsemul_vt100_output_string(edp, c)
    707 	struct wsemul_vt100_emuldata *edp;
    708 	u_char c;
    709 {
    710 	switch (c) {
    711 	    case ASCII_ESC: /* might be a string end */
    712 		return (VT100_EMUL_STATE_STRING_ESC);
    713 #if 0
    714 	    case ST: /* string end 8-bit */
    715 		wsemul_vt100_handle_dcs(edp);
    716 		return (VT100_EMUL_STATE_NORMAL);
    717 #endif
    718 	    default:
    719 		if (edp->dcstype && edp->dcspos < DCS_MAXLEN)
    720 			edp->dcsarg[edp->dcspos++] = c;
    721 	}
    722 	return (VT100_EMUL_STATE_STRING);
    723 }
    724 
    725 static u_int
    726 wsemul_vt100_output_string_esc(edp, c)
    727 	struct wsemul_vt100_emuldata *edp;
    728 	u_char c;
    729 {
    730 	if (c == '\\') { /* ST complete */
    731 		wsemul_vt100_handle_dcs(edp);
    732 		return (VT100_EMUL_STATE_NORMAL);
    733 	} else
    734 		return (VT100_EMUL_STATE_STRING);
    735 }
    736 
    737 static u_int
    738 wsemul_vt100_output_csi_em(edp, c)
    739 	struct wsemul_vt100_emuldata *edp;
    740 	u_char c;
    741 {
    742 	switch (c) {
    743 	    case 'p': /* DECSTR soft reset VT300 only */
    744 		wsemul_vt100_reset(edp);
    745 		break;
    746 	    default:
    747 #ifdef VT100_PRINTUNKNOWN
    748 		printf("ESC!%c unknown\n", c);
    749 #endif
    750 		break;
    751 	}
    752 	return (VT100_EMUL_STATE_NORMAL);
    753 }
    754 
    755 static u_int
    756 wsemul_vt100_output_dcs(edp, c)
    757 	struct wsemul_vt100_emuldata *edp;
    758 	u_char c;
    759 {
    760 	u_int newstate = VT100_EMUL_STATE_DCS;
    761 
    762 	switch (c) {
    763 	    case '0': case '1': case '2': case '3': case '4':
    764 	    case '5': case '6': case '7': case '8': case '9':
    765 		/* argument digit */
    766 		if (edp->nargs > VT100_EMUL_NARGS - 1)
    767 			break;
    768 		edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
    769 		    (c - '0');
    770 		break;
    771 	    case ';': /* argument terminator */
    772 		edp->nargs++;
    773 		break;
    774 	    default:
    775 		edp->nargs++;
    776 		if (edp->nargs > VT100_EMUL_NARGS) {
    777 #ifdef VT100_DEBUG
    778 			printf("vt100: too many arguments\n");
    779 #endif
    780 			edp->nargs = VT100_EMUL_NARGS;
    781 		}
    782 		newstate = VT100_EMUL_STATE_STRING;
    783 		switch (c) {
    784 		    case '$':
    785 			newstate = VT100_EMUL_STATE_DCS_DOLLAR;
    786 			break;
    787 		    case '{': /* DECDLD soft charset */
    788 		    case '!': /* DECRQUPSS user preferred supplemental set */
    789 			/* 'u' must follow - need another state */
    790 		    case '|': /* DECUDK program F6..F20 */
    791 #ifdef VT100_PRINTNOTIMPL
    792 			printf("DCS%c ignored\n", c);
    793 #endif
    794 			break;
    795 		    default:
    796 #ifdef VT100_PRINTUNKNOWN
    797 			printf("DCS%c (%d, %d) unknown\n", c, ARG(0), ARG(1));
    798 #endif
    799 			break;
    800 		}
    801 	}
    802 
    803 	return (newstate);
    804 }
    805 
    806 static u_int
    807 wsemul_vt100_output_dcs_dollar(edp, c)
    808 	struct wsemul_vt100_emuldata *edp;
    809 	u_char c;
    810 {
    811 	switch (c) {
    812 	    case 'p': /* DECRSTS terminal state restore */
    813 	    case 'q': /* DECRQSS control function request */
    814 #ifdef VT100_PRINTNOTIMPL
    815 		printf("DCS$%c ignored\n", c);
    816 #endif
    817 		break;
    818 	    case 't': /* DECRSPS restore presentation state */
    819 		switch (ARG(0)) {
    820 		    case 0: /* error */
    821 			break;
    822 		    case 1: /* cursor information restore */
    823 #ifdef VT100_PRINTNOTIMPL
    824 			printf("DCS1$t ignored\n");
    825 #endif
    826 			break;
    827 		    case 2: /* tab stop restore */
    828 			edp->dcspos = 0;
    829 			edp->dcstype = DCSTYPE_TABRESTORE;
    830 			break;
    831 		    default:
    832 #ifdef VT100_PRINTUNKNOWN
    833 			printf("DCS%d$t unknown\n", ARG(0));
    834 #endif
    835 			break;
    836 		}
    837 		break;
    838 	    default:
    839 #ifdef VT100_PRINTUNKNOWN
    840 		printf("DCS$%c (%d, %d) unknown\n", c, ARG(0), ARG(1));
    841 #endif
    842 		break;
    843 	}
    844 	return (VT100_EMUL_STATE_STRING);
    845 }
    846 
    847 static u_int
    848 wsemul_vt100_output_csi_gt(edp, c)
    849 	struct wsemul_vt100_emuldata *edp;
    850 	u_char c;
    851 {
    852 	switch (c) {
    853 	    case 'c': /* DA secondary */
    854 		wsdisplay_emulinput(edp->cbcookie, WSEMUL_VT_ID2,
    855 				    sizeof(WSEMUL_VT_ID2));
    856 		break;
    857 	    default:
    858 #ifdef VT100_PRINTUNKNOWN
    859 		printf("CSI>%c unknown\n", c);
    860 #endif
    861 		break;
    862 	}
    863 	return (VT100_EMUL_STATE_NORMAL);
    864 }
    865 
    866 static u_int
    867 wsemul_vt100_output_csi_dollar(edp, c)
    868 	struct wsemul_vt100_emuldata *edp;
    869 	u_char c;
    870 {
    871 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    872 
    873 	switch (c) {
    874 	    case '}': /* DECSASD */
    875 		/* select active status display */
    876 		switch (ARG(0)) {
    877 		    case 0: /* main display */
    878 		    case 1: /* status line */
    879 #ifdef VT100_PRINTNOTIMPL
    880 			printf("CSI%d$} ignored\n", ARG(0));
    881 #endif
    882 			break;
    883 		    default:
    884 #ifdef VT100_PRINTUNKNOWN
    885 			printf("CSI%d$} unknown\n", ARG(0));
    886 #endif
    887 			break;
    888 		}
    889 		break;
    890 	    case '~': /* DECSSDD */
    891 		/* select status line type */
    892 		switch (ARG(0)) {
    893 		    case 0: /* none */
    894 		    case 1: /* indicator */
    895 		    case 2: /* host-writable */
    896 #ifdef VT100_PRINTNOTIMPL
    897 			printf("CSI%d$~ ignored\n", ARG(0));
    898 #endif
    899 			break;
    900 		    default:
    901 #ifdef VT100_PRINTUNKNOWN
    902 			printf("CSI%d$~ unknown\n", ARG(0));
    903 #endif
    904 			break;
    905 		}
    906 		break;
    907 	    case 'p': /* DECRQM request mode ANSI */
    908 		vt100_reportmode(edp, ARG(0), 0);
    909 		break;
    910 	    case 'u': /* DECRQTSR request terminal status report */
    911 		switch (ARG(0)) {
    912 		    case 0: /* ignored */
    913 			break;
    914 		    case 1: /* terminal state report */
    915 #ifdef VT100_PRINTNOTIMPL
    916 			printf("CSI1$u ignored\n");
    917 #endif
    918 			break;
    919 		    default:
    920 #ifdef VT100_PRINTUNKNOWN
    921 			printf("CSI%d$u unknown\n", ARG(0));
    922 #endif
    923 			break;
    924 		}
    925 		break;
    926 	    case 'w': /* DECRQPSR request presentation status report
    927 			 (VT300 only) */
    928 		switch (ARG(0)) {
    929 		    case 0: /* error */
    930 			break;
    931 		    case 1: /* cursor information report */
    932 #ifdef VT100_PRINTNOTIMPL
    933 			printf("CSI1$w ignored\n");
    934 #endif
    935 			break;
    936 		    case 2: /* tab stop report */
    937 			{
    938 			int i, n;
    939 			char buf[20];
    940 			KASSERT(edp->tabs != 0);
    941 			wsdisplay_emulinput(edp->cbcookie, "\033P2$u", 5);
    942 			for (i = 0; i < edp->ncols; i++)
    943 				if (edp->tabs[i]) {
    944 					n = sprintf(buf, "%s%d",
    945 						    (i ? "/" : ""), i + 1);
    946 					wsdisplay_emulinput(edp->cbcookie,
    947 							    buf, n);
    948 				}
    949 			}
    950 			wsdisplay_emulinput(edp->cbcookie, "\033\\", 2);
    951 			break;
    952 		    default:
    953 #ifdef VT100_PRINTUNKNOWN
    954 			printf("CSI%d$w unknown\n", ARG(0));
    955 #endif
    956 			break;
    957 		}
    958 		break;
    959 	    default:
    960 #ifdef VT100_PRINTUNKNOWN
    961 		printf("CSI$%c unknown\n", c);
    962 #endif
    963 		break;
    964 	}
    965 	return (newstate);
    966 }
    967 
    968 static u_int
    969 wsemul_vt100_output_hash(edp, c)
    970 	struct wsemul_vt100_emuldata *edp;
    971 	u_char c;
    972 {
    973 	switch (c) {
    974 	    case '5': /*  DECSWL single width, single height */
    975 		break;
    976 	    case '6': /*  DECDWL double width, single height */
    977 	    case '3': /*  DECDHL double width, double height, top half */
    978 	    case '4': /*  DECDHL double width, double height, bottom half */
    979 #ifdef VT100_PRINTNOTIMPL
    980 		printf("ESC#%c ignored\n", c);
    981 #endif
    982 		break;
    983 	    case '8': { /* DECALN */
    984 		int i, j;
    985 		for (i = 0; i < edp->nrows; i++)
    986 			for (j = 0; j < edp->ncols; j++)
    987 				(*edp->emulops->putstr)(edp->emulcookie, i, j,
    988 							"E", 1, edp->curattr);
    989 		}
    990 		edp->ccol = 0;
    991 		edp->crow = 0;
    992 		break;
    993 	    default:
    994 #ifdef VT100_PRINTUNKNOWN
    995 		printf("ESC#%c unknown\n", c);
    996 #endif
    997 		break;
    998 	}
    999 	return (VT100_EMUL_STATE_NORMAL);
   1000 }
   1001 
   1002 static u_int
   1003 wsemul_vt100_output_csi(edp, c)
   1004 	struct wsemul_vt100_emuldata *edp;
   1005 	u_char c;
   1006 {
   1007 	u_int newstate = VT100_EMUL_STATE_CSI;
   1008 
   1009 	switch (c) {
   1010 	    case '0': case '1': case '2': case '3': case '4':
   1011 	    case '5': case '6': case '7': case '8': case '9':
   1012 		/* argument digit */
   1013 		if (edp->nargs > VT100_EMUL_NARGS - 1)
   1014 			break;
   1015 		edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
   1016 		    (c - '0');
   1017 		break;
   1018 	    case ';': /* argument terminator */
   1019 		edp->nargs++;
   1020 		break;
   1021 	    case '?': /* DEC specific */
   1022 		edp->nargs = 0;
   1023 		bzero(edp->args, sizeof (edp->args));
   1024 		newstate = VT100_EMUL_STATE_CSI_QM;
   1025 		break;
   1026 	    case '>': /* DA query */
   1027 		newstate = VT100_EMUL_STATE_CSI_GT;
   1028 		break;
   1029 	    case '"':
   1030 		newstate = VT100_EMUL_STATE_CSI_DQ;
   1031 		break;
   1032 	    case '$':
   1033 		newstate = VT100_EMUL_STATE_CSI_DOLLAR;
   1034 		break;
   1035 	    case '&':
   1036 		newstate = VT100_EMUL_STATE_CSI_AMP;
   1037 		break;
   1038 	    case '!':
   1039 		newstate = VT100_EMUL_STATE_CSI_EM;
   1040 		break;
   1041 	    default: /* end of escape sequence */
   1042 		edp->nargs++;
   1043 		if (edp->nargs > VT100_EMUL_NARGS) {
   1044 #ifdef VT100_DEBUG
   1045 			printf("vt100: too many arguments\n");
   1046 #endif
   1047 			edp->nargs = VT100_EMUL_NARGS;
   1048 		}
   1049 		wsemul_vt100_handle_csi(edp, c);
   1050 		newstate = VT100_EMUL_STATE_NORMAL;
   1051 		break;
   1052 	}
   1053 	return (newstate);
   1054 }
   1055 
   1056 static u_int
   1057 wsemul_vt100_output_csi_dq(edp, c)
   1058 	struct wsemul_vt100_emuldata *edp;
   1059 	u_char c;
   1060 {
   1061 	switch (c) {
   1062 	    case 'p': /* DECSCL */
   1063 		switch (ARG(0)) {
   1064 		    case 61: /* VT100 mode (no further arguments!) */
   1065 			break;
   1066 		    case 62:
   1067 		    case 63: /* VT300 mode */
   1068 			break;
   1069 		    default:
   1070 #ifdef VT100_PRINTUNKNOWN
   1071 			printf("CSI%d\"p unknown\n", ARG(0));
   1072 #endif
   1073 			break;
   1074 		}
   1075 		switch (ARG(1)) {
   1076 		    case 0:
   1077 		    case 2: /* 8-bit controls */
   1078 #ifdef VT100_PRINTNOTIMPL
   1079 			printf("CSI%d;%d\"p ignored\n", ARG(0), ARG(1));
   1080 #endif
   1081 			break;
   1082 		    case 1: /* 7-bit controls */
   1083 			break;
   1084 		    default:
   1085 #ifdef VT100_PRINTUNKNOWN
   1086 			printf("CSI%d;%d\"p unknown\n", ARG(0), ARG(1));
   1087 #endif
   1088 			break;
   1089 		}
   1090 		break;
   1091 	    case 'q': /* DECSCA select character attribute VT300 only */
   1092 		switch (ARG(0)) {
   1093 		    case 0:
   1094 		    case 1: /* erasable */
   1095 			break;
   1096 		    case 2: /* not erasable */
   1097 #ifdef VT100_PRINTNOTIMPL
   1098 			printf("CSI2\"q ignored\n");
   1099 #endif
   1100 			break;
   1101 		    default:
   1102 #ifdef VT100_PRINTUNKNOWN
   1103 			printf("CSI%d\"q unknown\n", ARG(0));
   1104 #endif
   1105 			break;
   1106 		}
   1107 		break;
   1108 	    default:
   1109 #ifdef VT100_PRINTUNKNOWN
   1110 		printf("CSI\"%c unknown (%d, %d)\n", c, ARG(0), ARG(1));
   1111 #endif
   1112 		break;
   1113 	}
   1114 	return (VT100_EMUL_STATE_NORMAL);
   1115 }
   1116 
   1117 void
   1118 wsemul_vt100_output(cookie, data, count, kernel)
   1119 	void *cookie;
   1120 	const u_char *data;
   1121 	u_int count;
   1122 	int kernel;
   1123 {
   1124 	struct wsemul_vt100_emuldata *edp = cookie;
   1125 
   1126 #ifdef DIAGNOSTIC
   1127 	if (kernel && !edp->console)
   1128 		panic("wsemul_vt100_output: kernel output, not console");
   1129 #endif
   1130 
   1131 	/* XXX */
   1132 	(*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, edp->ccol);
   1133 	for (; count > 0; data++, count--) {
   1134 		if (edp->state == VT100_EMUL_STATE_NORMAL || kernel) {
   1135 			edp->state = wsemul_vt100_output_normal(edp, *data,
   1136 								kernel);
   1137 			continue;
   1138 		}
   1139 #ifdef DIAGNOSTIC
   1140 		if (edp->state > sizeof(vt100_output) / sizeof(vt100_output[0]))
   1141 			panic("wsemul_vt100: invalid state %d\n", edp->state);
   1142 #endif
   1143 		edp->state = vt100_output[edp->state - 1](edp, *data);
   1144 	}
   1145 	/* XXX */
   1146 	(*edp->emulops->cursor)(edp->emulcookie, edp->flags & VTFL_CURSORON,
   1147 				edp->crow, edp->ccol);
   1148 }
   1149