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