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