Home | History | Annotate | Line # | Download | only in wscons
wsemul_vt100.c revision 1.2
      1 /* $NetBSD: wsemul_vt100.c,v 1.2 1998/06/20 21:52:50 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->putchar)(edp->emulcookie, edp->crow, edp->ccol,
    375 					 c, kernel ? edp->kernattr : edp->curattr);
    376 
    377 		if (edp->ccol < edp->ncols - 1)
    378 			edp->ccol++;
    379 		else
    380 			edp->flags |= VTFL_LASTCHAR;
    381 		break;
    382 	    case ASCII_LF:
    383 	    case ASCII_VT:
    384 	    case ASCII_FF:
    385 		if (ROWS_BELOW > 0)
    386 			edp->crow++;
    387 		else
    388 			wsemul_vt100_scrollup(edp, 1);
    389 		break;
    390 	}
    391 
    392 	return (newstate);
    393 }
    394 
    395 static u_int
    396 wsemul_vt100_output_esc(edp, c)
    397 	struct wsemul_vt100_emuldata *edp;
    398 	u_char c;
    399 {
    400 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    401 
    402 	switch (c) {
    403 	    case '[': /* CSI */
    404 		edp->nargs = 0;
    405 		bzero(edp->args, sizeof (edp->args));
    406 		newstate = VT100_EMUL_STATE_CSI;
    407 		break;
    408 	    case '7': /* DECSC */
    409 		edp->savedcursor_row = edp->crow;
    410 		edp->savedcursor_col = edp->ccol;
    411 		/* save attributes! */
    412 		break;
    413 	    case '8': /* DECRC */
    414 		edp->crow = edp->savedcursor_row;
    415 		edp->ccol = edp->savedcursor_col;
    416 		/* restore attributes! */
    417 		break;
    418 	    case '=': /* DECKPAM application mode */
    419 		edp->flags |= VTFL_APPLKEYPAD;
    420 		break;
    421 	    case '>': /* DECKPNM numeric mode */
    422 		edp->flags &= ~VTFL_APPLKEYPAD;
    423 		break;
    424 	    case 'E': /* NEL */
    425 		edp->ccol = 0;
    426 		/* FALLTHRU */
    427 	    case 'D': /* IND */
    428 		if (ROWS_BELOW > 0) {
    429 			edp->crow++;
    430 			break;
    431 		}
    432 		wsemul_vt100_scrollup(edp, 1);
    433 		break;
    434 	    case 'H': /* HTS */
    435 		KASSERT(edp->tabs != 0);
    436 		edp->tabs[edp->ccol] = 1;
    437 		break;
    438 	    case '~': /* LS1R */
    439 	    case 'n': /* LS2 */
    440 	    case '}': /* LS2R */
    441 	    case 'o': /* LS3 */
    442 	    case '|': /* LS3R */
    443 #ifdef VT100_PRINTNOTIMPL
    444 		printf("ESC %c ignored\n", c);
    445 #endif
    446 		break;
    447 	    case 'N': /* SS2 */
    448 	    case 'O': /* SS3 */
    449 #ifdef VT100_PRINTNOTIMPL
    450 		printf("ESC %c ignored\n", c);
    451 #endif
    452 		break;
    453 	    case 'M': /* RI */
    454 		if (ROWS_ABOVE > 0) {
    455 			edp->crow--;
    456 			break;
    457 		}
    458 		wsemul_vt100_scrolldown(edp, 1);
    459 		break;
    460 	    case 'P': /* DCS */
    461 		edp->nargs = 0;
    462 		bzero(edp->args, sizeof (edp->args));
    463 		newstate = VT100_EMUL_STATE_DCS;
    464 		break;
    465 	    case 'c': /* RIS */
    466 		wsemul_vt100_reset(edp);
    467 		edp->ccol = edp->crow = 0;
    468 		break;
    469 	    case '(': case ')': case '*': case '+': /* SCS */
    470 		edp->designating = c;
    471 		newstate = VT100_EMUL_STATE_SCS94;
    472 		break;
    473 	    case '-': case '.': case '/': /* SCS */
    474 		edp->designating = c;
    475 		newstate = VT100_EMUL_STATE_SCS96;
    476 		break;
    477 	    case '#':
    478 		newstate = VT100_EMUL_STATE_HASH;
    479 		break;
    480 	    case ' ': /* 7/8 bit */
    481 		newstate = VT100_EMUL_STATE_ESC_SPC;
    482 		break;
    483 	    case ']': /* OSC operating system command */
    484 	    case '^': /* PM privacy message */
    485 	    case '_': /* APC application program command */
    486 		/* ignored */
    487 		newstate = VT100_EMUL_STATE_STRING;
    488 		break;
    489 	    case '<': /* exit VT52 mode - ignored */
    490 		break;
    491 	    default:
    492 #ifdef VT100_PRINTUNKNOWN
    493 		printf("ESC%c unknown\n", c);
    494 #endif
    495 		break;
    496 	}
    497 
    498 	return (newstate);
    499 }
    500 
    501 static u_int
    502 wsemul_vt100_output_csi_qm(edp, c)
    503 	struct wsemul_vt100_emuldata *edp;
    504 	u_char c;
    505 {
    506 	u_int newstate = VT100_EMUL_STATE_CSI_QM;
    507 
    508 	switch (c) {
    509 	    case '0': case '1': case '2': case '3': case '4':
    510 	    case '5': case '6': case '7': case '8': case '9':
    511 		/* argument digit */
    512 		if (edp->nargs > VT100_EMUL_NARGS - 1)
    513 			break;
    514 		edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
    515 		    (c - '0');
    516 		break;
    517 	    case ';': /* argument terminator */
    518 		edp->nargs++;
    519 		break;
    520 	    case '$': /* request mode */
    521 		newstate = VT100_EMUL_STATE_CSI_QM_DOLLAR;
    522 		break;
    523 	    default: /* end of escape sequence */
    524 		edp->nargs++;
    525 		if (edp->nargs > VT100_EMUL_NARGS) {
    526 #ifdef VT100_DEBUG
    527 			printf("vt100: too many arguments\n");
    528 #endif
    529 			edp->nargs = VT100_EMUL_NARGS;
    530 		}
    531 		wsemul_vt100_handle_csi_qm(edp, c);
    532 		newstate = VT100_EMUL_STATE_NORMAL;
    533 		break;
    534 	}
    535 	return (newstate);
    536 }
    537 
    538 static u_int
    539 wsemul_vt100_output_csi_qm_dollar(edp, c)
    540 	struct wsemul_vt100_emuldata *edp;
    541 	u_char c;
    542 {
    543 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    544 
    545 	switch (c) {
    546 	    case 'p': /* DECRQM request DEC private mode */
    547 		vt100_reportmode(edp, ARG(0), 1);
    548 		break;
    549 	    default:
    550 #ifdef VT100_PRINTUNKNOWN
    551 		printf("CSI?%c unknown\n", c);
    552 #endif
    553 		break;
    554 	}
    555 
    556 	return (newstate);
    557 }
    558 
    559 static u_int
    560 wsemul_vt100_output_csi_amp(edp, c)
    561 	struct wsemul_vt100_emuldata *edp;
    562 	u_char c;
    563 {
    564 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    565 
    566 	switch (c) {
    567 	    case 'u': /* DECRQUPSS request user preferred supplemental set */
    568 		wsdisplay_emulinput(edp->emulcookie, "\033P0!u%5\033\\", 9);
    569 		break;
    570 	    default:
    571 #ifdef VT100_PRINTUNKNOWN
    572 		printf("CSI&%c unknown\n", c);
    573 #endif
    574 		break;
    575 	}
    576 
    577 	return (newstate);
    578 }
    579 
    580 static u_int
    581 wsemul_vt100_output_scs94(edp, c)
    582 	struct wsemul_vt100_emuldata *edp;
    583 	u_char c;
    584 {
    585 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    586 
    587 	switch (c) {
    588 	    case '%': /* probably DEC supplemental graphic */
    589 		newstate = VT100_EMUL_STATE_SCS94_PERCENT;
    590 		break;
    591 	    case 'B': /* ASCII */
    592 	    case 'A': /* ISO-latin-1 supplemental */
    593 	    case '<': /* user preferred supplemental */
    594 	    case '0': /* DEC special graphic */
    595 #ifdef VT100_PRINTNOTIMPL
    596 		printf("ESC%c%c ignored\n", edp->designating, c);
    597 #endif
    598 		break;
    599 	    default:
    600 #ifdef VT100_PRINTUNKNOWN
    601 		printf("ESC%c%c unknown\n", edp->designating, c);
    602 #endif
    603 		break;
    604 	}
    605 	return (newstate);
    606 }
    607 
    608 static u_int
    609 wsemul_vt100_output_scs94_percent(edp, c)
    610 	struct wsemul_vt100_emuldata *edp;
    611 	u_char c;
    612 {
    613 	switch (c) {
    614 	    case '5': /* DEC supplemental graphic */
    615 #ifdef VT100_PRINTNOTIMPL
    616 		printf("ESC%c%%5 ignored\n", edp->designating);
    617 #endif
    618 		break;
    619 	    default:
    620 #ifdef VT100_PRINTUNKNOWN
    621 		printf("ESC%c%%%c unknown\n", edp->designating, c);
    622 #endif
    623 		break;
    624 	}
    625 	return (VT100_EMUL_STATE_NORMAL);
    626 }
    627 
    628 static u_int
    629 wsemul_vt100_output_scs96(edp, c)
    630 	struct wsemul_vt100_emuldata *edp;
    631 	u_char c;
    632 {
    633 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    634 
    635 	switch (c) {
    636 	    case '%': /* probably portugese */
    637 		newstate = VT100_EMUL_STATE_SCS96_PERCENT;
    638 		break;
    639 	    case 'A': /* british */
    640 	    case '4': /* dutch */
    641 	    case '5': case 'C': /* finnish */
    642 	    case 'R': /* french */
    643 	    case 'Q': /* french canadian */
    644 	    case 'K': /* german */
    645 	    case 'Y': /* italian */
    646 	    case 'E': case '6': /* norwegian / danish */
    647 	    case 'Z': /* spanish */
    648 	    case '7': case 'H': /* swedish */
    649 	    case '=': /* swiss */
    650 #ifdef VT100_PRINTNOTIMPL
    651 		printf("ESC%c%c ignored\n", edp->designating, c);
    652 #endif
    653 		break;
    654 	    default:
    655 #ifdef VT100_PRINTUNKNOWN
    656 		printf("ESC%c%c unknown\n", edp->designating, c);
    657 #endif
    658 		break;
    659 	}
    660 	return (newstate);
    661 }
    662 
    663 static u_int
    664 wsemul_vt100_output_scs96_percent(edp, c)
    665 	struct wsemul_vt100_emuldata *edp;
    666 	u_char c;
    667 {
    668 	switch (c) {
    669 	    case '6': /* portugese */
    670 #ifdef VT100_PRINTNOTIMPL
    671 		printf("ESC%c%%6 ignored\n", edp->designating);
    672 #endif
    673 		break;
    674 	    default:
    675 #ifdef VT100_PRINTUNKNOWN
    676 		printf("ESC%c%%%c unknown\n", edp->designating, c);
    677 #endif
    678 		break;
    679 	}
    680 	return (VT100_EMUL_STATE_NORMAL);
    681 }
    682 
    683 static u_int
    684 wsemul_vt100_output_esc_spc(edp, c)
    685 	struct wsemul_vt100_emuldata *edp;
    686 	u_char c;
    687 {
    688 	switch (c) {
    689 	    case 'F': /* 7-bit controls */
    690 	    case 'G': /* 8-bit controls */
    691 #ifdef VT100_PRINTNOTIMPL
    692 		printf("ESC<SPC>%c ignored\n", c);
    693 #endif
    694 		break;
    695 	    default:
    696 #ifdef VT100_PRINTUNKNOWN
    697 		printf("ESC<SPC>%c unknown\n", c);
    698 #endif
    699 		break;
    700 	}
    701 	return (VT100_EMUL_STATE_NORMAL);
    702 }
    703 
    704 static u_int
    705 wsemul_vt100_output_string(edp, c)
    706 	struct wsemul_vt100_emuldata *edp;
    707 	u_char c;
    708 {
    709 	switch (c) {
    710 	    case ASCII_ESC: /* might be a string end */
    711 		return (VT100_EMUL_STATE_STRING_ESC);
    712 #if 0
    713 	    case ST: /* string end 8-bit */
    714 		wsemul_vt100_handle_dcs(edp);
    715 		return (VT100_EMUL_STATE_NORMAL);
    716 #endif
    717 	    default:
    718 		if (edp->dcstype && edp->dcspos < DCS_MAXLEN)
    719 			edp->dcsarg[edp->dcspos++] = c;
    720 	}
    721 	return (VT100_EMUL_STATE_STRING);
    722 }
    723 
    724 static u_int
    725 wsemul_vt100_output_string_esc(edp, c)
    726 	struct wsemul_vt100_emuldata *edp;
    727 	u_char c;
    728 {
    729 	if (c == '\\') { /* ST complete */
    730 		wsemul_vt100_handle_dcs(edp);
    731 		return (VT100_EMUL_STATE_NORMAL);
    732 	} else
    733 		return (VT100_EMUL_STATE_STRING);
    734 }
    735 
    736 static u_int
    737 wsemul_vt100_output_csi_em(edp, c)
    738 	struct wsemul_vt100_emuldata *edp;
    739 	u_char c;
    740 {
    741 	switch (c) {
    742 	    case 'p': /* DECSTR soft reset VT300 only */
    743 		wsemul_vt100_reset(edp);
    744 		break;
    745 	    default:
    746 #ifdef VT100_PRINTUNKNOWN
    747 		printf("ESC!%c unknown\n", c);
    748 #endif
    749 		break;
    750 	}
    751 	return (VT100_EMUL_STATE_NORMAL);
    752 }
    753 
    754 static u_int
    755 wsemul_vt100_output_dcs(edp, c)
    756 	struct wsemul_vt100_emuldata *edp;
    757 	u_char c;
    758 {
    759 	u_int newstate = VT100_EMUL_STATE_DCS;
    760 
    761 	switch (c) {
    762 	    case '0': case '1': case '2': case '3': case '4':
    763 	    case '5': case '6': case '7': case '8': case '9':
    764 		/* argument digit */
    765 		if (edp->nargs > VT100_EMUL_NARGS - 1)
    766 			break;
    767 		edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
    768 		    (c - '0');
    769 		break;
    770 	    case ';': /* argument terminator */
    771 		edp->nargs++;
    772 		break;
    773 	    default:
    774 		edp->nargs++;
    775 		if (edp->nargs > VT100_EMUL_NARGS) {
    776 #ifdef VT100_DEBUG
    777 			printf("vt100: too many arguments\n");
    778 #endif
    779 			edp->nargs = VT100_EMUL_NARGS;
    780 		}
    781 		newstate = VT100_EMUL_STATE_STRING;
    782 		switch (c) {
    783 		    case '$':
    784 			newstate = VT100_EMUL_STATE_DCS_DOLLAR;
    785 			break;
    786 		    case '{': /* DECDLD soft charset */
    787 		    case '!': /* DECRQUPSS user preferred supplemental set */
    788 			/* 'u' must follow - need another state */
    789 		    case '|': /* DECUDK program F6..F20 */
    790 #ifdef VT100_PRINTNOTIMPL
    791 			printf("DCS%c ignored\n", c);
    792 #endif
    793 			break;
    794 		    default:
    795 #ifdef VT100_PRINTUNKNOWN
    796 			printf("DCS%c (%d, %d) unknown\n", c, ARG(0), ARG(1));
    797 #endif
    798 			break;
    799 		}
    800 	}
    801 
    802 	return (newstate);
    803 }
    804 
    805 static u_int
    806 wsemul_vt100_output_dcs_dollar(edp, c)
    807 	struct wsemul_vt100_emuldata *edp;
    808 	u_char c;
    809 {
    810 	switch (c) {
    811 	    case 'p': /* DECRSTS terminal state restore */
    812 	    case 'q': /* DECRQSS control function request */
    813 #ifdef VT100_PRINTNOTIMPL
    814 		printf("DCS$%c ignored\n", c);
    815 #endif
    816 		break;
    817 	    case 't': /* DECRSPS restore presentation state */
    818 		switch (ARG(0)) {
    819 		    case 0: /* error */
    820 			break;
    821 		    case 1: /* cursor information restore */
    822 #ifdef VT100_PRINTNOTIMPL
    823 			printf("DCS1$t ignored\n");
    824 #endif
    825 			break;
    826 		    case 2: /* tab stop restore */
    827 			edp->dcspos = 0;
    828 			edp->dcstype = DCSTYPE_TABRESTORE;
    829 			break;
    830 		    default:
    831 #ifdef VT100_PRINTUNKNOWN
    832 			printf("DCS%d$t unknown\n", ARG(0));
    833 #endif
    834 			break;
    835 		}
    836 		break;
    837 	    default:
    838 #ifdef VT100_PRINTUNKNOWN
    839 		printf("DCS$%c (%d, %d) unknown\n", c, ARG(0), ARG(1));
    840 #endif
    841 		break;
    842 	}
    843 	return (VT100_EMUL_STATE_STRING);
    844 }
    845 
    846 static u_int
    847 wsemul_vt100_output_csi_gt(edp, c)
    848 	struct wsemul_vt100_emuldata *edp;
    849 	u_char c;
    850 {
    851 	switch (c) {
    852 	    case 'c': /* DA secondary */
    853 		wsdisplay_emulinput(edp->cbcookie, WSEMUL_VT_ID2,
    854 				    sizeof(WSEMUL_VT_ID2));
    855 		break;
    856 	    default:
    857 #ifdef VT100_PRINTUNKNOWN
    858 		printf("CSI>%c unknown\n", c);
    859 #endif
    860 		break;
    861 	}
    862 	return (VT100_EMUL_STATE_NORMAL);
    863 }
    864 
    865 static u_int
    866 wsemul_vt100_output_csi_dollar(edp, c)
    867 	struct wsemul_vt100_emuldata *edp;
    868 	u_char c;
    869 {
    870 	u_int newstate = VT100_EMUL_STATE_NORMAL;
    871 
    872 	switch (c) {
    873 	    case '}': /* DECSASD */
    874 		/* select active status display */
    875 		switch (ARG(0)) {
    876 		    case 0: /* main display */
    877 		    case 1: /* status line */
    878 #ifdef VT100_PRINTNOTIMPL
    879 			printf("CSI%d$} ignored\n", ARG(0));
    880 #endif
    881 			break;
    882 		    default:
    883 #ifdef VT100_PRINTUNKNOWN
    884 			printf("CSI%d$} unknown\n", ARG(0));
    885 #endif
    886 			break;
    887 		}
    888 		break;
    889 	    case '~': /* DECSSDD */
    890 		/* select status line type */
    891 		switch (ARG(0)) {
    892 		    case 0: /* none */
    893 		    case 1: /* indicator */
    894 		    case 2: /* host-writable */
    895 #ifdef VT100_PRINTNOTIMPL
    896 			printf("CSI%d$~ ignored\n", ARG(0));
    897 #endif
    898 			break;
    899 		    default:
    900 #ifdef VT100_PRINTUNKNOWN
    901 			printf("CSI%d$~ unknown\n", ARG(0));
    902 #endif
    903 			break;
    904 		}
    905 		break;
    906 	    case 'p': /* DECRQM request mode ANSI */
    907 		vt100_reportmode(edp, ARG(0), 0);
    908 		break;
    909 	    case 'u': /* DECRQTSR request terminal status report */
    910 		switch (ARG(0)) {
    911 		    case 0: /* ignored */
    912 			break;
    913 		    case 1: /* terminal state report */
    914 #ifdef VT100_PRINTNOTIMPL
    915 			printf("CSI1$u ignored\n");
    916 #endif
    917 			break;
    918 		    default:
    919 #ifdef VT100_PRINTUNKNOWN
    920 			printf("CSI%d$u unknown\n", ARG(0));
    921 #endif
    922 			break;
    923 		}
    924 		break;
    925 	    case 'w': /* DECRQPSR request presentation status report
    926 			 (VT300 only) */
    927 		switch (ARG(0)) {
    928 		    case 0: /* error */
    929 			break;
    930 		    case 1: /* cursor information report */
    931 #ifdef VT100_PRINTNOTIMPL
    932 			printf("CSI1$w ignored\n");
    933 #endif
    934 			break;
    935 		    case 2: /* tab stop report */
    936 			{
    937 			int i, n;
    938 			char buf[20];
    939 			KASSERT(edp->tabs != 0);
    940 			wsdisplay_emulinput(edp->cbcookie, "\033P2$u", 5);
    941 			for (i = 0; i < edp->ncols; i++)
    942 				if (edp->tabs[i]) {
    943 					n = sprintf(buf, "%s%d",
    944 						    (i ? "/" : ""), i + 1);
    945 					wsdisplay_emulinput(edp->cbcookie,
    946 							    buf, n);
    947 				}
    948 			}
    949 			wsdisplay_emulinput(edp->cbcookie, "\033\\", 2);
    950 			break;
    951 		    default:
    952 #ifdef VT100_PRINTUNKNOWN
    953 			printf("CSI%d$w unknown\n", ARG(0));
    954 #endif
    955 			break;
    956 		}
    957 		break;
    958 	    default:
    959 #ifdef VT100_PRINTUNKNOWN
    960 		printf("CSI$%c unknown\n", c);
    961 #endif
    962 		break;
    963 	}
    964 	return (newstate);
    965 }
    966 
    967 static u_int
    968 wsemul_vt100_output_hash(edp, c)
    969 	struct wsemul_vt100_emuldata *edp;
    970 	u_char c;
    971 {
    972 	switch (c) {
    973 	    case '5': /*  DECSWL single width, single height */
    974 		break;
    975 	    case '6': /*  DECDWL double width, single height */
    976 	    case '3': /*  DECDHL double width, double height, top half */
    977 	    case '4': /*  DECDHL double width, double height, bottom half */
    978 #ifdef VT100_PRINTNOTIMPL
    979 		printf("ESC#%c ignored\n", c);
    980 #endif
    981 		break;
    982 	    case '8': { /* DECALN */
    983 		int i, j;
    984 		for (i = 0; i < edp->nrows; i++)
    985 			for (j = 0; j < edp->ncols; j++)
    986 				(*edp->emulops->putchar)(edp->emulcookie, i, j,
    987 							 'E', edp->curattr);
    988 		}
    989 		edp->ccol = 0;
    990 		edp->crow = 0;
    991 		break;
    992 	    default:
    993 #ifdef VT100_PRINTUNKNOWN
    994 		printf("ESC#%c unknown\n", c);
    995 #endif
    996 		break;
    997 	}
    998 	return (VT100_EMUL_STATE_NORMAL);
    999 }
   1000 
   1001 static u_int
   1002 wsemul_vt100_output_csi(edp, c)
   1003 	struct wsemul_vt100_emuldata *edp;
   1004 	u_char c;
   1005 {
   1006 	u_int newstate = VT100_EMUL_STATE_CSI;
   1007 
   1008 	switch (c) {
   1009 	    case '0': case '1': case '2': case '3': case '4':
   1010 	    case '5': case '6': case '7': case '8': case '9':
   1011 		/* argument digit */
   1012 		if (edp->nargs > VT100_EMUL_NARGS - 1)
   1013 			break;
   1014 		edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
   1015 		    (c - '0');
   1016 		break;
   1017 	    case ';': /* argument terminator */
   1018 		edp->nargs++;
   1019 		break;
   1020 	    case '?': /* DEC specific */
   1021 		edp->nargs = 0;
   1022 		bzero(edp->args, sizeof (edp->args));
   1023 		newstate = VT100_EMUL_STATE_CSI_QM;
   1024 		break;
   1025 	    case '>': /* DA query */
   1026 		newstate = VT100_EMUL_STATE_CSI_GT;
   1027 		break;
   1028 	    case '"':
   1029 		newstate = VT100_EMUL_STATE_CSI_DQ;
   1030 		break;
   1031 	    case '$':
   1032 		newstate = VT100_EMUL_STATE_CSI_DOLLAR;
   1033 		break;
   1034 	    case '&':
   1035 		newstate = VT100_EMUL_STATE_CSI_AMP;
   1036 		break;
   1037 	    case '!':
   1038 		newstate = VT100_EMUL_STATE_CSI_EM;
   1039 		break;
   1040 	    default: /* end of escape sequence */
   1041 		edp->nargs++;
   1042 		if (edp->nargs > VT100_EMUL_NARGS) {
   1043 #ifdef VT100_DEBUG
   1044 			printf("vt100: too many arguments\n");
   1045 #endif
   1046 			edp->nargs = VT100_EMUL_NARGS;
   1047 		}
   1048 		wsemul_vt100_handle_csi(edp, c);
   1049 		newstate = VT100_EMUL_STATE_NORMAL;
   1050 		break;
   1051 	}
   1052 	return (newstate);
   1053 }
   1054 
   1055 static u_int
   1056 wsemul_vt100_output_csi_dq(edp, c)
   1057 	struct wsemul_vt100_emuldata *edp;
   1058 	u_char c;
   1059 {
   1060 	switch (c) {
   1061 	    case 'p': /* DECSCL */
   1062 		switch (ARG(0)) {
   1063 		    case 61: /* VT100 mode (no further arguments!) */
   1064 			break;
   1065 		    case 62:
   1066 		    case 63: /* VT300 mode */
   1067 			break;
   1068 		    default:
   1069 #ifdef VT100_PRINTUNKNOWN
   1070 			printf("CSI%d\"p unknown\n", ARG(0));
   1071 #endif
   1072 			break;
   1073 		}
   1074 		switch (ARG(1)) {
   1075 		    case 0:
   1076 		    case 2: /* 8-bit controls */
   1077 #ifdef VT100_PRINTNOTIMPL
   1078 			printf("CSI%d;%d\"p ignored\n", ARG(0), ARG(1));
   1079 #endif
   1080 			break;
   1081 		    case 1: /* 7-bit controls */
   1082 			break;
   1083 		    default:
   1084 #ifdef VT100_PRINTUNKNOWN
   1085 			printf("CSI%d;%d\"p unknown\n", ARG(0), ARG(1));
   1086 #endif
   1087 			break;
   1088 		}
   1089 		break;
   1090 	    case 'q': /* DECSCA select character attribute VT300 only */
   1091 		switch (ARG(0)) {
   1092 		    case 0:
   1093 		    case 1: /* erasable */
   1094 			break;
   1095 		    case 2: /* not erasable */
   1096 #ifdef VT100_PRINTNOTIMPL
   1097 			printf("CSI2\"q ignored\n");
   1098 #endif
   1099 			break;
   1100 		    default:
   1101 #ifdef VT100_PRINTUNKNOWN
   1102 			printf("CSI%d\"q unknown\n", ARG(0));
   1103 #endif
   1104 			break;
   1105 		}
   1106 		break;
   1107 	    default:
   1108 #ifdef VT100_PRINTUNKNOWN
   1109 		printf("CSI\"%c unknown (%d, %d)\n", c, ARG(0), ARG(1));
   1110 #endif
   1111 		break;
   1112 	}
   1113 	return (VT100_EMUL_STATE_NORMAL);
   1114 }
   1115 
   1116 void
   1117 wsemul_vt100_output(cookie, data, count, kernel)
   1118 	void *cookie;
   1119 	const u_char *data;
   1120 	u_int count;
   1121 	int kernel;
   1122 {
   1123 	struct wsemul_vt100_emuldata *edp = cookie;
   1124 
   1125 #ifdef DIAGNOSTIC
   1126 	if (kernel && !edp->console)
   1127 		panic("wsemul_vt100_output: kernel output, not console");
   1128 #endif
   1129 
   1130 	/* XXX */
   1131 	(*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, edp->ccol);
   1132 	for (; count > 0; data++, count--) {
   1133 		if (edp->state == VT100_EMUL_STATE_NORMAL || kernel) {
   1134 			edp->state = wsemul_vt100_output_normal(edp, *data,
   1135 								kernel);
   1136 			continue;
   1137 		}
   1138 #ifdef DIAGNOSTIC
   1139 		if (edp->state > sizeof(vt100_output) / sizeof(vt100_output[0]))
   1140 			panic("wsemul_vt100: invalid state %d\n", edp->state);
   1141 #endif
   1142 		edp->state = vt100_output[edp->state - 1](edp, *data);
   1143 	}
   1144 	/* XXX */
   1145 	(*edp->emulops->cursor)(edp->emulcookie, edp->flags & VTFL_CURSORON,
   1146 				edp->crow, edp->ccol);
   1147 }
   1148