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