From 68aabb6d21045bea3a05259cec1e5caacd4b2cd8 Mon Sep 17 00:00:00 2001 From: drochner Date: Sat, 20 Jun 1998 19:17:47 +0000 Subject: [PATCH] First cut on a VT100 emulation. It should be able to parse escape sequences up to VT300, but not everything is implemented. Most notably, there is no font handling - all displayable characters are handed to the graphics driver. To solve this, a serious interface change to the graphics driver is needed (Unicode?). --- sys/dev/wscons/files.wscons | 6 +- sys/dev/wscons/wsemul_vt100.c | 1148 ++++++++++++++++++++++++++++ sys/dev/wscons/wsemul_vt100_keys.c | 203 +++++ sys/dev/wscons/wsemul_vt100_subr.c | 740 ++++++++++++++++++ sys/dev/wscons/wsemul_vt100var.h | 116 +++ 5 files changed, 2212 insertions(+), 1 deletion(-) create mode 100644 sys/dev/wscons/wsemul_vt100.c create mode 100644 sys/dev/wscons/wsemul_vt100_keys.c create mode 100644 sys/dev/wscons/wsemul_vt100_subr.c create mode 100644 sys/dev/wscons/wsemul_vt100var.h diff --git a/sys/dev/wscons/files.wscons b/sys/dev/wscons/files.wscons index 85386caa85af..95606b5bb59c 100644 --- a/sys/dev/wscons/files.wscons +++ b/sys/dev/wscons/files.wscons @@ -1,4 +1,4 @@ -# $NetBSD: files.wscons,v 1.7 1998/06/15 17:51:56 drochner Exp $ +# $NetBSD: files.wscons,v 1.8 1998/06/20 19:17:47 drochner Exp $ # # "Workstation Console" glue; attaches frame buffer to emulator & keyboard, @@ -44,6 +44,10 @@ file dev/wscons/wsemul_sun.c (wsdisplaydev | wsemuldisplaydev | wskbddev) & wsemul_sun file dev/wscons/wsemul_vt100.c (wsdisplaydev | wsemuldisplaydev | wskbddev) & wsemul_vt100 +file dev/wscons/wsemul_vt100_subr.c + (wsdisplaydev | wsemuldisplaydev | wskbddev) & wsemul_vt100 +file dev/wscons/wsemul_vt100_keys.c + (wsdisplaydev | wsemuldisplaydev | wskbddev) & wsemul_vt100 file dev/wscons/wsevent.c wskbddev | wsmousedev file dev/wscons/wskbd.c diff --git a/sys/dev/wscons/wsemul_vt100.c b/sys/dev/wscons/wsemul_vt100.c new file mode 100644 index 000000000000..9f1dc201172a --- /dev/null +++ b/sys/dev/wscons/wsemul_vt100.c @@ -0,0 +1,1148 @@ +/* $NetBSD: wsemul_vt100.c,v 1.1 1998/06/20 19:17:47 drochner Exp $ */ + +/* + * Copyright (c) 1998 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "opt_wskernattr.h" + +void *wsemul_vt100_cnattach __P((const struct wsscreen_descr *, void *, + int, int, long)); +void *wsemul_vt100_attach __P((int console, const struct wsscreen_descr *, + void *, int, int, void *, long)); +void wsemul_vt100_output __P((void *cookie, const u_char *data, u_int count, + int)); +void wsemul_vt100_detach __P((void *cookie, u_int *crowp, u_int *ccolp)); + +const struct wsemul_ops wsemul_vt100_ops = { + "vt100", + wsemul_vt100_cnattach, + wsemul_vt100_attach, + wsemul_vt100_output, + wsemul_vt100_translate, + wsemul_vt100_detach, +}; + +struct wsemul_vt100_emuldata wsemul_vt100_console_emuldata; + +static void wsemul_vt100_init __P((struct wsemul_vt100_emuldata *, + const struct wsscreen_descr *, + void *, int, int, long)); + +static u_int wsemul_vt100_output_normal __P((struct wsemul_vt100_emuldata *, + u_char, int)); +typedef u_int vt100_handler __P((struct wsemul_vt100_emuldata *, u_char)); +static vt100_handler +wsemul_vt100_output_esc, +wsemul_vt100_output_csi, +wsemul_vt100_output_csi_qm, +wsemul_vt100_output_scs94, +wsemul_vt100_output_scs94_percent, +wsemul_vt100_output_scs96, +wsemul_vt100_output_scs96_percent, +wsemul_vt100_output_hash, +wsemul_vt100_output_esc_spc, +wsemul_vt100_output_csi_gt, +wsemul_vt100_output_string, +wsemul_vt100_output_string_esc, +wsemul_vt100_output_csi_dq, +wsemul_vt100_output_dcs, +wsemul_vt100_output_csi_dollar, +wsemul_vt100_output_csi_qm_dollar, +wsemul_vt100_output_csi_amp, +wsemul_vt100_output_csi_em, +wsemul_vt100_output_dcs_dollar; + +#define VT100_EMUL_STATE_NORMAL 0 /* normal processing */ +#define VT100_EMUL_STATE_ESC 1 /* got ESC */ +#define VT100_EMUL_STATE_CSI 2 /* got CSI (ESC[) */ +#define VT100_EMUL_STATE_CSI_QM 3 /* got CSI? */ +#define VT100_EMUL_STATE_SCS94 4 /* got ESC{()*+} */ +#define VT100_EMUL_STATE_SCS94_PERCENT 5 /* got ESC{()*+}% */ +#define VT100_EMUL_STATE_SCS96 6 /* got ESC{-./} */ +#define VT100_EMUL_STATE_SCS96_PERCENT 7 /* got ESC{-./}% */ +#define VT100_EMUL_STATE_HASH 8 /* got ESC# */ +#define VT100_EMUL_STATE_ESC_SPC 9 /* got ESC */ +#define VT100_EMUL_STATE_CSI_GT 10 /* got CSI> */ +#define VT100_EMUL_STATE_STRING 11 /* waiting for ST (ESC\) */ +#define VT100_EMUL_STATE_STRING_ESC 12 /* waiting for ST, got ESC */ +#define VT100_EMUL_STATE_CSI_DQ 13 /* got CSI

" */ +#define VT100_EMUL_STATE_DCS 14 /* got DCS (ESC P) */ +#define VT100_EMUL_STATE_CSI_DOLLAR 15 /* got CSI

$ */ +#define VT100_EMUL_STATE_CSI_QM_DOLLAR 16 /* got CSI?

$ */ +#define VT100_EMUL_STATE_CSI_AMP 17 /* got CSI& */ +#define VT100_EMUL_STATE_CSI_EM 18 /* got CSI! */ +#define VT100_EMUL_STATE_DCS_DOLLAR 19 /* got DCS

$ */ + +vt100_handler *vt100_output[] = { + wsemul_vt100_output_esc, + wsemul_vt100_output_csi, + wsemul_vt100_output_csi_qm, + wsemul_vt100_output_scs94, + wsemul_vt100_output_scs94_percent, + wsemul_vt100_output_scs96, + wsemul_vt100_output_scs96_percent, + wsemul_vt100_output_hash, + wsemul_vt100_output_esc_spc, + wsemul_vt100_output_csi_gt, + wsemul_vt100_output_string, + wsemul_vt100_output_string_esc, + wsemul_vt100_output_csi_dq, + wsemul_vt100_output_dcs, + wsemul_vt100_output_csi_dollar, + wsemul_vt100_output_csi_qm_dollar, + wsemul_vt100_output_csi_amp, + wsemul_vt100_output_csi_em, + wsemul_vt100_output_dcs_dollar, +}; + +static void +wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr) + struct wsemul_vt100_emuldata *edp; + const struct wsscreen_descr *type; + void *cookie; + int ccol, crow; + long defattr; +{ + edp->emulops = type->textops; + edp->emulcookie = cookie; + edp->scrcapabilities = type->capabilities; + edp->nrows = type->nrows; + edp->ncols = type->ncols; + edp->crow = crow; + edp->ccol = ccol; + edp->defattr = defattr; +} + +void * +wsemul_vt100_cnattach(type, cookie, ccol, crow, defattr) + const struct wsscreen_descr *type; + void *cookie; + int ccol, crow; + long defattr; +{ + struct wsemul_vt100_emuldata *edp; + int res; + + edp = &wsemul_vt100_console_emuldata; + wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr); +#ifdef DIAGNOSTIC + edp->console = 1; +#endif + edp->cbcookie = NULL; + +#if defined(WS_KERNEL_FG) || defined(WS_KERNEL_BG) || \ + defined(WS_KERNEL_COLATTR) || defined(WS_KERNEL_MONOATTR) +#ifndef WS_KERNEL_FG +#define WS_KERNEL_FG WSCOL_WHITE +#endif +#ifndef WS_KERNEL_BG +#define WS_KERNEL_BG WSCOL_BLACK +#endif +#ifndef WS_KERNEL_COLATTR +#define WS_KERNEL_COLATTR 0 +#endif +#ifndef WS_KERNEL_MONOATTR +#define WS_KERNEL_MONOATTR 0 +#endif + if (type->capabilities & WSSCREEN_WSCOLORS) + res = (*edp->emulops->alloc_attr)(cookie, + WS_KERNEL_FG, WS_KERNEL_BG, + WS_KERNEL_COLATTR | WSATTR_WSCOLORS, + &edp->kernattr); + else + res = (*edp->emulops->alloc_attr)(cookie, 0, 0, + WS_KERNEL_MONOATTR, + &edp->kernattr); + if (res) +#endif + edp->kernattr = defattr; + + edp->tabs = 0; + edp->dcsarg = 0; + wsemul_vt100_reset(edp); + return (edp); +} + +void * +wsemul_vt100_attach(console, type, cookie, ccol, crow, cbcookie, defattr) + int console; + const struct wsscreen_descr *type; + void *cookie; + int ccol, crow; + void *cbcookie; + long defattr; +{ + struct wsemul_vt100_emuldata *edp; + + if (console) { + edp = &wsemul_vt100_console_emuldata; +#ifdef DIAGNOSTIC + KASSERT(edp->console == 1); +#endif + } else { + edp = malloc(sizeof *edp, M_DEVBUF, M_WAITOK); + wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr); +#ifdef DIAGNOSTIC + edp->console = 0; +#endif + } + edp->cbcookie = cbcookie; + + edp->tabs = malloc(type->ncols, M_DEVBUF, M_NOWAIT); + edp->dcsarg = malloc(DCS_MAXLEN, M_DEVBUF, M_NOWAIT); + wsemul_vt100_reset(edp); + return (edp); +} + +void +wsemul_vt100_detach(cookie, crowp, ccolp) + void *cookie; + u_int *crowp, *ccolp; +{ + struct wsemul_vt100_emuldata *edp = cookie; + + *crowp = edp->crow; + *ccolp = edp->ccol; + if (edp->tabs) { + free(edp->tabs, M_DEVBUF); + edp->tabs = 0; + } + if (edp->dcsarg) { + free(edp->dcsarg, M_DEVBUF); + edp->dcsarg = 0; + } + if (edp != &wsemul_vt100_console_emuldata) + free(edp, M_DEVBUF); +} + +void +wsemul_vt100_reset(edp) + struct wsemul_vt100_emuldata *edp; +{ + int i; + + edp->state = VT100_EMUL_STATE_NORMAL; + edp->flags = VTFL_DECAWM | VTFL_CURSORON; + edp->curattr = edp->defattr; + edp->attrflags = 0; + edp->fgcol = WSCOL_WHITE; + edp->bgcol = WSCOL_BLACK; + edp->scrreg_startrow = 0; + edp->scrreg_nrows = edp->nrows; + if (edp->tabs) { + bzero(edp->tabs, edp->ncols); + for (i = 1; i < edp->ncols; i += 8 - (i & 7)) + edp->tabs[i] = 1; + } + edp->dcspos = 0; + edp->dcstype = 0; +} + +/* + * now all the state machine bits + */ + +static u_int +wsemul_vt100_output_normal(edp, c, kernel) + struct wsemul_vt100_emuldata *edp; + u_char c; + int kernel; +{ + u_int newstate = VT100_EMUL_STATE_NORMAL; + u_int n; + + switch (c) { + case ASCII_NUL: + /* ignore */ + break; + case ASCII_BEL: + wsdisplay_emulbell(edp->cbcookie); + break; + case ASCII_BS: + if (edp->ccol > 0) { + edp->ccol--; + edp->flags &= ~VTFL_LASTCHAR; + } + break; + case ASCII_CR: + edp->ccol = 0; + edp->flags &= ~VTFL_LASTCHAR; + break; + case ASCII_HT: + if (edp->tabs) { + if (edp->ccol >= edp->ncols - 1) + break; + for (n = edp->ccol + 1; n < edp->ncols - 1; n++) + if (edp->tabs[n]) + break; + } else { + n = edp->ccol + min(8 - (edp->ccol & 7), COLS_LEFT); + } + (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, + edp->ccol, n - edp->ccol, + kernel ? edp->kernattr : edp->curattr); + edp->ccol = n; + break; + case ASCII_SI: /* LS0 */ +#ifdef VT100_PRINTNOTIMPL + printf("SI ignored\n"); +#endif + break; + case ASCII_SO: /* LS1 */ +#ifdef VT100_PRINTNOTIMPL + printf("SO ignored\n"); +#endif + break; + case ASCII_ESC: +#ifdef DIAGNOSTIC + if (kernel) + panic("ESC in kernel output"); +#endif + newstate = VT100_EMUL_STATE_ESC; + break; +#if 0 + case CSI: /* 8-bit */ + edp->nargs = 0; + bzero(edp->args, sizeof (edp->args)); + newstate = VT100_EMUL_STATE_CSI; + break; + case DCS: /* 8-bit */ + edp->nargs = 0; + bzero(edp->args, sizeof (edp->args)); + newstate = VT100_EMUL_STATE_DCS; + break; +#endif + default: /* normal character */ + if ((edp->flags & (VTFL_LASTCHAR | VTFL_DECAWM)) == + (VTFL_LASTCHAR | VTFL_DECAWM)) { + if (ROWS_BELOW > 0) + edp->crow++; + else + wsemul_vt100_scrollup(edp, 1); + edp->ccol = 0; + edp->flags &= ~VTFL_LASTCHAR; + } + + if ((edp->flags & VTFL_INSERTMODE) && + edp->ccol < edp->ncols - 1) { + (*edp->emulops->copycols)(edp->emulcookie, edp->crow, + edp->ccol, edp->ccol + 1, + edp->ncols - edp->ccol - 1); + } + + (*edp->emulops->putstr)(edp->emulcookie, edp->crow, edp->ccol, + &c, 1, + kernel ? edp->kernattr : edp->curattr); + + if (edp->ccol < edp->ncols - 1) + edp->ccol++; + else + edp->flags |= VTFL_LASTCHAR; + break; + case ASCII_LF: + case ASCII_VT: + case ASCII_FF: + if (ROWS_BELOW > 0) + edp->crow++; + else + wsemul_vt100_scrollup(edp, 1); + break; + } + + return (newstate); +} + +static u_int +wsemul_vt100_output_esc(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + u_int newstate = VT100_EMUL_STATE_NORMAL; + + switch (c) { + case '[': /* CSI */ + edp->nargs = 0; + bzero(edp->args, sizeof (edp->args)); + newstate = VT100_EMUL_STATE_CSI; + break; + case '7': /* DECSC */ + edp->savedcursor_row = edp->crow; + edp->savedcursor_col = edp->ccol; + /* save attributes! */ + break; + case '8': /* DECRC */ + edp->crow = edp->savedcursor_row; + edp->ccol = edp->savedcursor_col; + /* restore attributes! */ + break; + case '=': /* DECKPAM application mode */ + edp->flags |= VTFL_APPLKEYPAD; + break; + case '>': /* DECKPNM numeric mode */ + edp->flags &= ~VTFL_APPLKEYPAD; + break; + case 'E': /* NEL */ + edp->ccol = 0; + /* FALLTHRU */ + case 'D': /* IND */ + if (ROWS_BELOW > 0) { + edp->crow++; + break; + } + wsemul_vt100_scrollup(edp, 1); + break; + case 'H': /* HTS */ + KASSERT(edp->tabs != 0); + edp->tabs[edp->ccol] = 1; + break; + case '~': /* LS1R */ + case 'n': /* LS2 */ + case '}': /* LS2R */ + case 'o': /* LS3 */ + case '|': /* LS3R */ +#ifdef VT100_PRINTNOTIMPL + printf("ESC %c ignored\n", c); +#endif + break; + case 'N': /* SS2 */ + case 'O': /* SS3 */ +#ifdef VT100_PRINTNOTIMPL + printf("ESC %c ignored\n", c); +#endif + break; + case 'M': /* RI */ + if (ROWS_ABOVE > 0) { + edp->crow--; + break; + } + wsemul_vt100_scrolldown(edp, 1); + break; + case 'P': /* DCS */ + edp->nargs = 0; + bzero(edp->args, sizeof (edp->args)); + newstate = VT100_EMUL_STATE_DCS; + break; + case 'c': /* RIS */ + wsemul_vt100_reset(edp); + edp->ccol = edp->crow = 0; + break; + case '(': case ')': case '*': case '+': /* SCS */ + edp->designating = c; + newstate = VT100_EMUL_STATE_SCS94; + break; + case '-': case '.': case '/': /* SCS */ + edp->designating = c; + newstate = VT100_EMUL_STATE_SCS96; + break; + case '#': + newstate = VT100_EMUL_STATE_HASH; + break; + case ' ': /* 7/8 bit */ + newstate = VT100_EMUL_STATE_ESC_SPC; + break; + case ']': /* OSC operating system command */ + case '^': /* PM privacy message */ + case '_': /* APC application program command */ + /* ignored */ + newstate = VT100_EMUL_STATE_STRING; + break; + case '<': /* exit VT52 mode - ignored */ + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ESC%c unknown\n", c); +#endif + break; + } + + return (newstate); +} + +static u_int +wsemul_vt100_output_csi_qm(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + u_int newstate = VT100_EMUL_STATE_CSI_QM; + + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* argument digit */ + if (edp->nargs > VT100_EMUL_NARGS - 1) + break; + edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) + + (c - '0'); + break; + case ';': /* argument terminator */ + edp->nargs++; + break; + case '$': /* request mode */ + newstate = VT100_EMUL_STATE_CSI_QM_DOLLAR; + break; + default: /* end of escape sequence */ + edp->nargs++; + if (edp->nargs > VT100_EMUL_NARGS) { +#ifdef VT100_DEBUG + printf("vt100: too many arguments\n"); +#endif + edp->nargs = VT100_EMUL_NARGS; + } + wsemul_vt100_handle_csi_qm(edp, c); + newstate = VT100_EMUL_STATE_NORMAL; + break; + } + return (newstate); +} + +static u_int +wsemul_vt100_output_csi_qm_dollar(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + u_int newstate = VT100_EMUL_STATE_NORMAL; + + switch (c) { + case 'p': /* DECRQM request DEC private mode */ + vt100_reportmode(edp, ARG(0), 1); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI?%c unknown\n", c); +#endif + break; + } + + return (newstate); +} + +static u_int +wsemul_vt100_output_csi_amp(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + u_int newstate = VT100_EMUL_STATE_NORMAL; + + switch (c) { + case 'u': /* DECRQUPSS request user preferred supplemental set */ + wsdisplay_emulinput(edp->emulcookie, "\033P0!u%5\033\\", 9); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI&%c unknown\n", c); +#endif + break; + } + + return (newstate); +} + +static u_int +wsemul_vt100_output_scs94(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + u_int newstate = VT100_EMUL_STATE_NORMAL; + + switch (c) { + case '%': /* probably DEC supplemental graphic */ + newstate = VT100_EMUL_STATE_SCS94_PERCENT; + break; + case 'B': /* ASCII */ + case 'A': /* ISO-latin-1 supplemental */ + case '<': /* user preferred supplemental */ + case '0': /* DEC special graphic */ +#ifdef VT100_PRINTNOTIMPL + printf("ESC%c%c ignored\n", edp->designating, c); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ESC%c%c unknown\n", edp->designating, c); +#endif + break; + } + return (newstate); +} + +static u_int +wsemul_vt100_output_scs94_percent(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case '5': /* DEC supplemental graphic */ +#ifdef VT100_PRINTNOTIMPL + printf("ESC%c%%5 ignored\n", edp->designating); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ESC%c%%%c unknown\n", edp->designating, c); +#endif + break; + } + return (VT100_EMUL_STATE_NORMAL); +} + +static u_int +wsemul_vt100_output_scs96(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + u_int newstate = VT100_EMUL_STATE_NORMAL; + + switch (c) { + case '%': /* probably portugese */ + newstate = VT100_EMUL_STATE_SCS96_PERCENT; + break; + case 'A': /* british */ + case '4': /* dutch */ + case '5': case 'C': /* finnish */ + case 'R': /* french */ + case 'Q': /* french canadian */ + case 'K': /* german */ + case 'Y': /* italian */ + case 'E': case '6': /* norwegian / danish */ + case 'Z': /* spanish */ + case '7': case 'H': /* swedish */ + case '=': /* swiss */ +#ifdef VT100_PRINTNOTIMPL + printf("ESC%c%c ignored\n", edp->designating, c); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ESC%c%c unknown\n", edp->designating, c); +#endif + break; + } + return (newstate); +} + +static u_int +wsemul_vt100_output_scs96_percent(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case '6': /* portugese */ +#ifdef VT100_PRINTNOTIMPL + printf("ESC%c%%6 ignored\n", edp->designating); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ESC%c%%%c unknown\n", edp->designating, c); +#endif + break; + } + return (VT100_EMUL_STATE_NORMAL); +} + +static u_int +wsemul_vt100_output_esc_spc(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case 'F': /* 7-bit controls */ + case 'G': /* 8-bit controls */ +#ifdef VT100_PRINTNOTIMPL + printf("ESC%c ignored\n", c); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ESC%c unknown\n", c); +#endif + break; + } + return (VT100_EMUL_STATE_NORMAL); +} + +static u_int +wsemul_vt100_output_string(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case ASCII_ESC: /* might be a string end */ + return (VT100_EMUL_STATE_STRING_ESC); +#if 0 + case ST: /* string end 8-bit */ + wsemul_vt100_handle_dcs(edp); + return (VT100_EMUL_STATE_NORMAL); +#endif + default: + if (edp->dcstype && edp->dcspos < DCS_MAXLEN) + edp->dcsarg[edp->dcspos++] = c; + } + return (VT100_EMUL_STATE_STRING); +} + +static u_int +wsemul_vt100_output_string_esc(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + if (c == '\\') { /* ST complete */ + wsemul_vt100_handle_dcs(edp); + return (VT100_EMUL_STATE_NORMAL); + } else + return (VT100_EMUL_STATE_STRING); +} + +static u_int +wsemul_vt100_output_csi_em(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case 'p': /* DECSTR soft reset VT300 only */ + wsemul_vt100_reset(edp); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ESC!%c unknown\n", c); +#endif + break; + } + return (VT100_EMUL_STATE_NORMAL); +} + +static u_int +wsemul_vt100_output_dcs(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + u_int newstate = VT100_EMUL_STATE_DCS; + + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* argument digit */ + if (edp->nargs > VT100_EMUL_NARGS - 1) + break; + edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) + + (c - '0'); + break; + case ';': /* argument terminator */ + edp->nargs++; + break; + default: + edp->nargs++; + if (edp->nargs > VT100_EMUL_NARGS) { +#ifdef VT100_DEBUG + printf("vt100: too many arguments\n"); +#endif + edp->nargs = VT100_EMUL_NARGS; + } + newstate = VT100_EMUL_STATE_STRING; + switch (c) { + case '$': + newstate = VT100_EMUL_STATE_DCS_DOLLAR; + break; + case '{': /* DECDLD soft charset */ + case '!': /* DECRQUPSS user preferred supplemental set */ + /* 'u' must follow - need another state */ + case '|': /* DECUDK program F6..F20 */ +#ifdef VT100_PRINTNOTIMPL + printf("DCS%c ignored\n", c); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("DCS%c (%d, %d) unknown\n", c, ARG(0), ARG(1)); +#endif + break; + } + } + + return (newstate); +} + +static u_int +wsemul_vt100_output_dcs_dollar(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case 'p': /* DECRSTS terminal state restore */ + case 'q': /* DECRQSS control function request */ +#ifdef VT100_PRINTNOTIMPL + printf("DCS$%c ignored\n", c); +#endif + break; + case 't': /* DECRSPS restore presentation state */ + switch (ARG(0)) { + case 0: /* error */ + break; + case 1: /* cursor information restore */ +#ifdef VT100_PRINTNOTIMPL + printf("DCS1$t ignored\n"); +#endif + break; + case 2: /* tab stop restore */ + edp->dcspos = 0; + edp->dcstype = DCSTYPE_TABRESTORE; + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("DCS%d$t unknown\n", ARG(0)); +#endif + break; + } + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("DCS$%c (%d, %d) unknown\n", c, ARG(0), ARG(1)); +#endif + break; + } + return (VT100_EMUL_STATE_STRING); +} + +static u_int +wsemul_vt100_output_csi_gt(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case 'c': /* DA secondary */ + wsdisplay_emulinput(edp->cbcookie, WSEMUL_VT_ID2, + sizeof(WSEMUL_VT_ID2)); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI>%c unknown\n", c); +#endif + break; + } + return (VT100_EMUL_STATE_NORMAL); +} + +static u_int +wsemul_vt100_output_csi_dollar(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + u_int newstate = VT100_EMUL_STATE_NORMAL; + + switch (c) { + case '}': /* DECSASD */ + /* select active status display */ + switch (ARG(0)) { + case 0: /* main display */ + case 1: /* status line */ +#ifdef VT100_PRINTNOTIMPL + printf("CSI%d$} ignored\n", ARG(0)); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%d$} unknown\n", ARG(0)); +#endif + break; + } + break; + case '~': /* DECSSDD */ + /* select status line type */ + switch (ARG(0)) { + case 0: /* none */ + case 1: /* indicator */ + case 2: /* host-writable */ +#ifdef VT100_PRINTNOTIMPL + printf("CSI%d$~ ignored\n", ARG(0)); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%d$~ unknown\n", ARG(0)); +#endif + break; + } + break; + case 'p': /* DECRQM request mode ANSI */ + vt100_reportmode(edp, ARG(0), 0); + break; + case 'u': /* DECRQTSR request terminal status report */ + switch (ARG(0)) { + case 0: /* ignored */ + break; + case 1: /* terminal state report */ +#ifdef VT100_PRINTNOTIMPL + printf("CSI1$u ignored\n"); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%d$u unknown\n", ARG(0)); +#endif + break; + } + break; + case 'w': /* DECRQPSR request presentation status report + (VT300 only) */ + switch (ARG(0)) { + case 0: /* error */ + break; + case 1: /* cursor information report */ +#ifdef VT100_PRINTNOTIMPL + printf("CSI1$w ignored\n"); +#endif + break; + case 2: /* tab stop report */ + { + int i, n; + char buf[20]; + KASSERT(edp->tabs != 0); + wsdisplay_emulinput(edp->cbcookie, "\033P2$u", 5); + for (i = 0; i < edp->ncols; i++) + if (edp->tabs[i]) { + n = sprintf(buf, "%s%d", + (i ? "/" : ""), i + 1); + wsdisplay_emulinput(edp->cbcookie, + buf, n); + } + } + wsdisplay_emulinput(edp->cbcookie, "\033\\", 2); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%d$w unknown\n", ARG(0)); +#endif + break; + } + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI$%c unknown\n", c); +#endif + break; + } + return (newstate); +} + +static u_int +wsemul_vt100_output_hash(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case '5': /* DECSWL single width, single height */ + break; + case '6': /* DECDWL double width, single height */ + case '3': /* DECDHL double width, double height, top half */ + case '4': /* DECDHL double width, double height, bottom half */ +#ifdef VT100_PRINTNOTIMPL + printf("ESC#%c ignored\n", c); +#endif + break; + case '8': { /* DECALN */ + int i, j; + for (i = 0; i < edp->nrows; i++) + for (j = 0; j < edp->ncols; j++) + (*edp->emulops->putstr)(edp->emulcookie, i, j, + "E", 1, edp->curattr); + } + edp->ccol = 0; + edp->crow = 0; + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ESC#%c unknown\n", c); +#endif + break; + } + return (VT100_EMUL_STATE_NORMAL); +} + +static u_int +wsemul_vt100_output_csi(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + u_int newstate = VT100_EMUL_STATE_CSI; + + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* argument digit */ + if (edp->nargs > VT100_EMUL_NARGS - 1) + break; + edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) + + (c - '0'); + break; + case ';': /* argument terminator */ + edp->nargs++; + break; + case '?': /* DEC specific */ + edp->nargs = 0; + bzero(edp->args, sizeof (edp->args)); + newstate = VT100_EMUL_STATE_CSI_QM; + break; + case '>': /* DA query */ + newstate = VT100_EMUL_STATE_CSI_GT; + break; + case '"': + newstate = VT100_EMUL_STATE_CSI_DQ; + break; + case '$': + newstate = VT100_EMUL_STATE_CSI_DOLLAR; + break; + case '&': + newstate = VT100_EMUL_STATE_CSI_AMP; + break; + case '!': + newstate = VT100_EMUL_STATE_CSI_EM; + break; + default: /* end of escape sequence */ + edp->nargs++; + if (edp->nargs > VT100_EMUL_NARGS) { +#ifdef VT100_DEBUG + printf("vt100: too many arguments\n"); +#endif + edp->nargs = VT100_EMUL_NARGS; + } + wsemul_vt100_handle_csi(edp, c); + newstate = VT100_EMUL_STATE_NORMAL; + break; + } + return (newstate); +} + +static u_int +wsemul_vt100_output_csi_dq(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case 'p': /* DECSCL */ + switch (ARG(0)) { + case 61: /* VT100 mode (no further arguments!) */ + break; + case 62: + case 63: /* VT300 mode */ + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%d\"p unknown\n", ARG(0)); +#endif + break; + } + switch (ARG(1)) { + case 0: + case 2: /* 8-bit controls */ +#ifdef VT100_PRINTNOTIMPL + printf("CSI%d;%d\"p ignored\n", ARG(0), ARG(1)); +#endif + break; + case 1: /* 7-bit controls */ + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%d;%d\"p unknown\n", ARG(0), ARG(1)); +#endif + break; + } + break; + case 'q': /* DECSCA select character attribute VT300 only */ + switch (ARG(0)) { + case 0: + case 1: /* erasable */ + break; + case 2: /* not erasable */ +#ifdef VT100_PRINTNOTIMPL + printf("CSI2\"q ignored\n"); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%d\"q unknown\n", ARG(0)); +#endif + break; + } + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI\"%c unknown (%d, %d)\n", c, ARG(0), ARG(1)); +#endif + break; + } + return (VT100_EMUL_STATE_NORMAL); +} + +void +wsemul_vt100_output(cookie, data, count, kernel) + void *cookie; + const u_char *data; + u_int count; + int kernel; +{ + struct wsemul_vt100_emuldata *edp = cookie; + +#ifdef DIAGNOSTIC + if (kernel && !edp->console) + panic("wsemul_vt100_output: kernel output, not console"); +#endif + + /* XXX */ + (*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, edp->ccol); + for (; count > 0; data++, count--) { + if (edp->state == VT100_EMUL_STATE_NORMAL || kernel) { + edp->state = wsemul_vt100_output_normal(edp, *data, + kernel); + continue; + } +#ifdef DIAGNOSTIC + if (edp->state > sizeof(vt100_output) / sizeof(vt100_output[0])) + panic("wsemul_vt100: invalid state %d\n", edp->state); +#endif + edp->state = vt100_output[edp->state - 1](edp, *data); + } + /* XXX */ + (*edp->emulops->cursor)(edp->emulcookie, edp->flags & VTFL_CURSORON, + edp->crow, edp->ccol); +} diff --git a/sys/dev/wscons/wsemul_vt100_keys.c b/sys/dev/wscons/wsemul_vt100_keys.c new file mode 100644 index 000000000000..0707043f2216 --- /dev/null +++ b/sys/dev/wscons/wsemul_vt100_keys.c @@ -0,0 +1,203 @@ +/* $NetBSD: wsemul_vt100_keys.c,v 1.1 1998/06/20 19:17:47 drochner Exp $ */ + +/* + * Copyright (c) 1998 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include +#include +#include +#include + +static char *vt100_fkeys[] = { + "\033[11~", /* F1 */ + "\033[12~", + "\033[13~", /* F1-F5 normally don't send codes */ + "\033[14~", + "\033[15~", /* F5 */ + "\033[17~", /* F6 */ + "\033[18~", + "\033[19~", + "\033[20~", + "\033[21~", + "\033[23~", /* VT100: ESC */ + "\033[24~", /* VT100: BS */ + "\033[25~", /* VT100: LF */ + "\033[26~", + "\033[28~", /* help */ + "\033[29~", /* do */ + "\033[31~", + "\033[32~", + "\033[33~", + "\033[34~", /* F20 */ +}; + +static char *vt100_pfkeys[] = { + "\033OP", /* PF1 */ + "\033OQ", + "\033OR", + "\033OS", /* PF4 */ +}; + +static char *vt100_numpad[] = { + "\033Op", /* KP 0 */ + "\033Oq", /* KP 1 */ + "\033Or", /* KP 2 */ + "\033Os", /* KP 3 */ + "\033Ot", /* KP 4 */ + "\033Ou", /* KP 5 */ + "\033Ov", /* KP 6 */ + "\033Ow", /* KP 7 */ + "\033Ox", /* KP 8 */ + "\033Oy", /* KP 9 */ +}; + +int +wsemul_vt100_translate(cookie, in, out) + void *cookie; + keysym_t in; + char **out; +{ + struct wsemul_vt100_emuldata *edp = cookie; + static char c; + + if (in >= KS_f1 && in <= KS_f20) { + *out = vt100_fkeys[in - KS_f1]; + return (5); + } + if (in >= KS_F1 && in <= KS_F20) { + *out = vt100_fkeys[in - KS_F1]; + return (5); + } + if (in >= KS_KP_F1 && in <= KS_KP_F4) { + *out = vt100_pfkeys[in - KS_KP_F1]; + return (3); + } + if (edp->flags & VTFL_APPLKEYPAD) { + if (in >= KS_KP_0 && in <= KS_KP_9) { + *out = vt100_numpad[in - KS_KP_0]; + return (3); + } + switch (in) { + case KS_KP_Tab: + *out = "\033OI"; + return (3); + case KS_KP_Enter: + *out = "\033OM"; + return (3); + case KS_KP_Multiply: + *out = "\033Oj"; + return (3); + case KS_KP_Add: + *out = "\033Ok"; + return (3); + case KS_KP_Separator: + *out = "\033Ol"; + return (3); + case KS_KP_Subtract: + *out = "\033Om"; + return (3); + case KS_KP_Decimal: + *out = "\033On"; + return (3); + case KS_KP_Divide: + *out = "\033Oo"; + return (3); + } + } else { + if (!(in & 0x80)) { + c = in & 0xff; /* turn into ASCII */ + *out = &c; + return (1); + } + } + switch (in) { + case KS_Help: + *out = vt100_fkeys[15]; + return (5); + case KS_Execute: /* "Do" */ + *out = vt100_fkeys[16]; + return (5); + case KS_Find: + *out = "\033[1~"; + return (4); + case KS_Insert: + case KS_KP_Insert: + *out = "\033[2~"; + return (4); + case KS_KP_Delete: + *out = "\033[3~"; + return (4); + case KS_Select: + *out = "\033[4~"; + return (4); + case KS_Prior: + case KS_KP_Prior: + *out = "\033[5~"; + return (4); + case KS_Next: + case KS_KP_Next: + *out = "\033[6~"; + return (4); + case KS_Up: + case KS_KP_Up: + if (edp->flags & VTFL_APPLCURSOR) + *out = "\033OA"; + else + *out = "\033[A"; + return (3); + case KS_Down: + case KS_KP_Down: + if (edp->flags & VTFL_APPLCURSOR) + *out = "\033OB"; + else + *out = "\033[B"; + return (3); + case KS_Left: + case KS_KP_Left: + if (edp->flags & VTFL_APPLCURSOR) + *out = "\033OD"; + else + *out = "\033[D"; + return (3); + case KS_Right: + case KS_KP_Right: + if (edp->flags & VTFL_APPLCURSOR) + *out = "\033OC"; + else + *out = "\033[C"; + return (3); + } + return (0); +} diff --git a/sys/dev/wscons/wsemul_vt100_subr.c b/sys/dev/wscons/wsemul_vt100_subr.c new file mode 100644 index 000000000000..f6491f98f8ba --- /dev/null +++ b/sys/dev/wscons/wsemul_vt100_subr.c @@ -0,0 +1,740 @@ +/* $NetBSD: wsemul_vt100_subr.c,v 1.1 1998/06/20 19:17:47 drochner Exp $ */ + +/* + * Copyright (c) 1998 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include +#include +#include +#include + +static int vt100_selectattribute __P((struct wsemul_vt100_emuldata *, + int, int, int, long *)); +static int vt100_ansimode __P((struct wsemul_vt100_emuldata *, int, int)); +static int vt100_decmode __P((struct wsemul_vt100_emuldata *, int, int)); +#define MODE_SET 33 +#define MODE_RESET 44 +#define MODE_REPORT 55 + +/* + * scroll up within scrolling region + */ +void +wsemul_vt100_scrollup(edp, n) + struct wsemul_vt100_emuldata *edp; + int n; +{ + int help; + + if (n > edp->scrreg_nrows) + n = edp->scrreg_nrows; + + help = edp->scrreg_nrows - n; + if (help > 0) + (*edp->emulops->copyrows)(edp->emulcookie, + edp->scrreg_startrow + n, + edp->scrreg_startrow, + help); + (*edp->emulops->eraserows)(edp->emulcookie, + edp->scrreg_startrow + help, n, + edp->curattr); +} + +/* + * scroll down within scrolling region + */ +void +wsemul_vt100_scrolldown(edp, n) + struct wsemul_vt100_emuldata *edp; + int n; +{ + int help; + + if (n > edp->scrreg_nrows) + n = edp->scrreg_nrows; + + help = edp->scrreg_nrows - n; + if (help > 0) + (*edp->emulops->copyrows)(edp->emulcookie, + edp->scrreg_startrow, + edp->scrreg_startrow + n, + help); + (*edp->emulops->eraserows)(edp->emulcookie, + edp->scrreg_startrow, n, + edp->curattr); +} + +/* + * erase in display + */ +void +wsemul_vt100_ed(edp, arg) + struct wsemul_vt100_emuldata *edp; + int arg; +{ + int n; + + switch (arg) { + case 0: /* cursor to end */ + (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, + edp->ccol, COLS_LEFT + 1, + edp->curattr); + n = edp->nrows - edp->crow - 1; + if (n > 0) { + (*edp->emulops->eraserows)(edp->emulcookie, + edp->crow + 1, n, + edp->curattr); + } + break; + case 1: /* beginning to cursor */ + if (edp->crow > 0) { + (*edp->emulops->eraserows)(edp->emulcookie, + 0, edp->crow, + edp->curattr); + } + (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, + 0, edp->ccol + 1, + edp->curattr); + break; + case 2: /* complete display */ + (*edp->emulops->eraserows)(edp->emulcookie, + 0, edp->nrows, + edp->curattr); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ed(%d) unknown\n", arg); +#endif + break; + } +} + +/* + * erase in line + */ +void +wsemul_vt100_el(edp, arg) + struct wsemul_vt100_emuldata *edp; + int arg; +{ + switch (arg) { + case 0: /* cursor to end */ + (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, + edp->ccol, COLS_LEFT + 1, + edp->curattr); + break; + case 1: /* beginning to cursor */ + (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, + 0, edp->ccol + 1, + edp->curattr); + break; + case 2: /* complete line */ + (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, + 0, edp->ncols, + edp->curattr); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("el(%d) unknown\n", arg); +#endif + break; + } +} + +/* + * handle commands after CSI (ESC[) + */ +void +wsemul_vt100_handle_csi(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + int n, help, flags, fgcol, bgcol; + long attr; + + switch (c) { + case '@': /* ICH insert character VT300 only */ + n = min(DEF1_ARG(0), COLS_LEFT + 1); + help = edp->ncols - (edp->ccol + n); + if (help > 0) + (*edp->emulops->copycols)(edp->emulcookie, edp->crow, + edp->ccol, edp->ccol + n, + help); + (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, + edp->ccol, n, edp->curattr); + break; + case 'A': /* CUU */ + edp->crow -= min(DEF1_ARG(0), ROWS_ABOVE); + break; + case 'B': /* CUD */ + edp->crow += min(DEF1_ARG(0), ROWS_BELOW); + break; + case 'C': /* CUF */ + edp->ccol += min(DEF1_ARG(0), COLS_LEFT); + break; + case 'D': /* CUB */ + edp->ccol -= min(DEF1_ARG(0), edp->ccol); + edp->flags &= ~VTFL_LASTCHAR; + break; + case 'H': /* CUP */ + case 'f': /* HVP */ + if (edp->flags & VTFL_DECOM) + edp->crow = edp->scrreg_startrow + + min(DEF1_ARG(0), edp->scrreg_nrows) - 1; + else + edp->crow = min(DEF1_ARG(0), edp->nrows) - 1; + edp->ccol = min(DEF1_ARG(1), edp->ncols) - 1; + edp->flags &= ~VTFL_LASTCHAR; + break; + case 'J': /* ED erase in display */ + wsemul_vt100_ed(edp, ARG(0)); + break; + case 'K': /* EL erase in line */ + wsemul_vt100_el(edp, ARG(0)); + break; + case 'L': /* IL insert line */ + case 'M': /* DL delete line */ + n = min(DEF1_ARG(0), ROWS_BELOW + 1); + { + int savscrstartrow, savscrnrows; + savscrstartrow = edp->scrreg_startrow; + savscrnrows = edp->scrreg_nrows; + edp->scrreg_nrows -= ROWS_ABOVE; + edp->scrreg_startrow = edp->crow; + if (c == 'L') + wsemul_vt100_scrolldown(edp, n); + else + wsemul_vt100_scrollup(edp, n); + edp->scrreg_startrow = savscrstartrow; + edp->scrreg_nrows = savscrnrows; + } + break; + case 'P': /* DCH delete character */ + n = min(DEF1_ARG(0), COLS_LEFT + 1); + help = edp->ncols - (edp->ccol + n); + if (help > 0) + (*edp->emulops->copycols)(edp->emulcookie, edp->crow, + edp->ccol + n, edp->ccol, + help); + (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, + edp->ncols - n, n, edp->curattr); + break; + case 'X': /* ECH erase character */ + n = min(DEF1_ARG(0), COLS_LEFT + 1); + (*edp->emulops->erasecols)(edp->emulcookie, edp->crow, + edp->ccol, n, + edp->curattr); + break; + case 'c': /* DA primary */ + if (ARG(0) == 0) + wsdisplay_emulinput(edp->cbcookie, WSEMUL_VT_ID1, + sizeof(WSEMUL_VT_ID1)); + break; + case 'g': /* TBC */ + KASSERT(edp->tabs != 0); + switch (ARG(0)) { + case 0: + edp->tabs[edp->ccol] = 0; + break; + case 3: + bzero(edp->tabs, edp->ncols); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%dg unknown\n", ARG(0)); +#endif + break; + } + break; + case 'h': /* SM */ + vt100_setmode(edp, ARG(0), 0); + break; + case 'i': /* MC printer controller mode */ + switch (ARG(0)) { + case 0: /* print screen */ + break; + case 4: /* off */ + case 5: /* on */ + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%di unknown\n", ARG(0)); +#endif + break; + } + break; + case 'l': /* RM */ + vt100_resetmode(edp, ARG(0), 0); + break; + case 'm': /* SGR select graphic rendition */ + flags = edp->attrflags; + fgcol = edp->fgcol; + bgcol = edp->bgcol; + for (n = 0; n < edp->nargs; n++) { + switch (ARG(n)) { + case 0: /* reset */ + edp->attrflags = 0; + edp->fgcol = WSCOL_WHITE; + edp->bgcol = WSCOL_BLACK; + if (n == edp->nargs - 1) { + edp->curattr = edp->defattr; + return; + } + break; + case 1: /* bold */ + flags |= WSATTR_HILIT; + break; + case 4: /* underline */ + flags |= WSATTR_UNDERLINE; + break; + case 5: /* blink */ + flags |= WSATTR_BLINK; + break; + case 7: /* reverse */ + flags |= WSATTR_REVERSE; + break; + case 22: /* ~bold VT300 only */ + flags &= ~WSATTR_HILIT; + break; + case 24: /* ~underline VT300 only */ + flags &= ~WSATTR_UNDERLINE; + break; + case 25: /* ~blink VT300 only */ + flags &= ~WSATTR_BLINK; + break; + case 27: /* ~reverse VT300 only */ + flags &= ~WSATTR_REVERSE; + break; + case 30: case 31: case 32: case 33: + case 34: case 35: case 36: case 37: + /* fg color */ + flags |= WSATTR_WSCOLORS; + fgcol = ARG(n) - 30; + break; + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + /* bg color */ + flags |= WSATTR_WSCOLORS; + bgcol = ARG(n) - 40; + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%dm unknown\n", ARG(n)); +#endif + } + } + if (vt100_selectattribute(edp, flags, fgcol, bgcol, &attr)) { +#ifdef VT100_DEBUG + printf("error allocating attr %d/%d/%x\n", + fgcol, bgcol, flags); +#endif + } else { + edp->curattr = attr; + edp->attrflags = flags; + edp->fgcol = fgcol; + edp->bgcol = bgcol; + } + break; + case 'n': /* reports */ + switch (ARG(0)) { + case 5: /* DSR operating status */ + /* 0 = OK, 3 = malfunction */ + wsdisplay_emulinput(edp->cbcookie, "\033[0n", 4); + break; + case 6: { /* DSR cursor position report */ + char buf[20]; + int row; + if (edp->flags & VTFL_DECOM) + row = ROWS_ABOVE; + else + row = edp->crow; + n = sprintf(buf, "\033[%d;%dR", + row + 1, edp->ccol + 1); + wsdisplay_emulinput(edp->cbcookie, buf, n); + } + break; + case 15: /* DSR printer status */ + /* 13 = no printer, 10 = ready, 11 = not ready */ + wsdisplay_emulinput(edp->cbcookie, "\033[?13n", 6); + break; + case 25: /* UDK status - VT300 only */ + /* 20 = locked, 21 = unlocked */ + wsdisplay_emulinput(edp->cbcookie, "\033[?21n", 6); + break; + case 26: /* keyboard dialect */ + /* 1 = north american , 7 = german */ + wsdisplay_emulinput(edp->cbcookie, "\033[?27;1n", 8); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%dn unknown\n", ARG(0)); +#endif + break; + } + break; + case 'r': /* DECSTBM set top/bottom margins */ + if (ARG(0) == 0 && ARG(1) == 0) { + edp->scrreg_startrow = 0; + edp->scrreg_nrows = edp->nrows; + } else { + edp->scrreg_startrow = min(DEF1_ARG(0), + edp->nrows) - 1; + edp->scrreg_nrows = min(DEF1_ARG(1), edp->nrows) - + edp->scrreg_startrow; + } + edp->crow = ((edp->flags & VTFL_DECOM) ? + edp->scrreg_startrow : 0); + edp->ccol = 0; + break; + case 'y': + switch (ARG(0)) { + case 4: /* DECTST invoke confidence test */ + /* ignore */ + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%dy unknown\n", ARG(0)); +#endif + break; + } + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI%c (%d, %d) unknown\n", c, ARG(0), ARG(1)); +#endif + } +} + +/* + * handle commands after CSI? + */ +void +wsemul_vt100_handle_csi_qm(edp, c) + struct wsemul_vt100_emuldata *edp; + u_char c; +{ + switch (c) { + case 'J': /* DECSED selective erase in display */ + wsemul_vt100_ed(edp, ARG(0)); + break; + case 'K': /* DECSEL selective erase in line */ + wsemul_vt100_el(edp, ARG(0)); + break; + case 'h': /* SM, DEC private */ + vt100_setmode(edp, ARG(0), 1); + break; + case 'i': /* MC printer controller mode */ + switch (ARG(0)) { + case 1: /* print cursor line */ + case 4: /* off */ + case 5: /* on */ +#ifdef VT100_PRINTNOTIMPL + printf("CSI?%di ignored\n", ARG(0)); +#endif + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI?%di unknown\n", ARG(0)); +#endif + break; + } + break; + case 'l': /* RM, DEC private */ + vt100_resetmode(edp, ARG(0), 1); + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("CSI?%c (%d, %d) unknown\n", c, ARG(0), ARG(1)); +#endif + break; + } +} + +/* + * get an attribute from the graphics driver, + * try to find replacements if the desired appearance + * is not supported + */ +static int +vt100_selectattribute(edp, flags, fgcol, bgcol, attr) + struct wsemul_vt100_emuldata *edp; + int flags, fgcol, bgcol; + long *attr; +{ + if ((flags & WSATTR_HILIT) && + !(edp->scrcapabilities & WSSCREEN_HILIT)) { + flags &= ~WSATTR_HILIT; + if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { + fgcol = WSCOL_RED; + flags |= WSATTR_WSCOLORS; + } else { +#ifdef VT100_DEBUG + printf("bold ignored (impossible)\n"); +#endif + } + } + if ((flags & WSATTR_UNDERLINE) && + !(edp->scrcapabilities & WSSCREEN_UNDERLINE)) { + flags &= ~WSATTR_UNDERLINE; + if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { + bgcol = WSCOL_BROWN; + flags &= ~WSATTR_UNDERLINE; + flags |= WSATTR_WSCOLORS; + } else { +#ifdef VT100_DEBUG + printf("underline ignored (impossible)\n"); +#endif + } + } + if ((flags & WSATTR_BLINK) && + !(edp->scrcapabilities & WSSCREEN_BLINK)) { + flags &= ~WSATTR_BLINK; +#ifdef VT100_DEBUG + printf("blink ignored (impossible)\n"); +#endif + } + if ((flags & WSATTR_REVERSE) && + !(edp->scrcapabilities & WSSCREEN_REVERSE)) { + flags &= ~WSATTR_REVERSE; + if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { + int help; + help = bgcol; + bgcol = fgcol; + fgcol = help; + flags |= WSATTR_WSCOLORS; + } else { +#ifdef VT100_DEBUG + printf("reverse ignored (impossible)\n"); +#endif + } + } + if ((flags & WSATTR_WSCOLORS) && + !(edp->scrcapabilities & WSSCREEN_WSCOLORS)) { + flags &= ~WSATTR_WSCOLORS; +#ifdef VT100_DEBUG + printf("colors ignored (impossible)\n"); +#endif + } + return ((*edp->emulops->alloc_attr)(edp->emulcookie, + fgcol, bgcol, flags, + attr)); +} + +/* + * handle device control sequences if the main state machine + * told so by setting edp->dcstype to a nonzero value + */ +void +wsemul_vt100_handle_dcs(edp) + struct wsemul_vt100_emuldata *edp; +{ + int i, pos; + + switch (edp->dcstype) { + case 0: /* not handled */ + return; + case DCSTYPE_TABRESTORE: + KASSERT(edp->tabs != 0); + bzero(edp->tabs, edp->ncols); + pos = 0; + for (i = 0; i < edp->dcspos; i++) { + char c = edp->dcsarg[i]; + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + pos = pos * 10 + (edp->dcsarg[i] - '0'); + break; + case '/': + if (pos > 0) + edp->tabs[pos - 1] = 1; + pos = 0; + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("unknown char %c in DCS\n", c); +#endif + } + } + if (pos > 0) + edp->tabs[pos - 1] = 1; + break; + default: + panic("wsemul_vt100_handle_dcs: bad type %d", edp->dcstype); + } + edp->dcstype = 0; +} + +static int +vt100_ansimode(edp, nr, op) + struct wsemul_vt100_emuldata *edp; + int nr, op; +{ + int res = 0; /* default: unknown */ + + switch (nr) { + case 2: /* KAM keyboard locked/unlocked */ + break; + case 3: /* CRM control representation */ + break; + case 4: /* IRM insert/replace characters */ + if (op == MODE_SET) + edp->flags |= VTFL_INSERTMODE; + else if (op == MODE_RESET) + edp->flags &= ~VTFL_INSERTMODE; + res = ((edp->flags & VTFL_INSERTMODE) ? 1 : 2); + break; + case 10: /* HEM horizontal editing (permanently reset) */ + res = 4; + break; + case 12: /* SRM local echo off/on */ + res = 4; /* permanently reset ??? */ + break; + case 20: /* LNM newline = newline/linefeed */ + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("ANSI mode %d unknown\n", nr); +#endif + } + return (res); +} + +static int +vt100_decmode(edp, nr, op) + struct wsemul_vt100_emuldata *edp; + int nr, op; +{ + int res = 0; /* default: unknown */ + + switch (nr) { + case 1: /* DECCKM application/nomal cursor keys */ + if (op == MODE_SET) + edp->flags |= VTFL_APPLCURSOR; + else if (op == MODE_RESET) + edp->flags &= ~VTFL_APPLCURSOR; + res = ((edp->flags & VTFL_APPLCURSOR) ? 1 : 2); + break; + case 2: /* DECANM ANSI vt100/vt52 */ + res = 3; /* permanently set ??? */ + break; + case 3: /* DECCOLM 132/80 cols */ + case 4: /* DECSCLM smooth/jump scroll */ + case 5: /* DECSCNM light/dark background */ + res = 4; /* all permanently reset ??? */ + break; + case 6: /* DECOM move within/outside margins */ + if (op == MODE_SET) + edp->flags |= VTFL_DECOM; + else if (op == MODE_RESET) + edp->flags &= ~VTFL_DECOM; + res = ((edp->flags & VTFL_DECOM) ? 1 : 2); + break; + case 7: /* DECAWM autowrap */ + if (op == MODE_SET) + edp->flags |= VTFL_DECAWM; + else if (op == MODE_RESET) + edp->flags &= ~VTFL_DECAWM; + res = ((edp->flags & VTFL_DECAWM) ? 1 : 2); + break; + case 8: /* DECARM keyboard autorepeat */ + break; + case 18: /* DECPFF print form feed */ + break; + case 19: /* DECPEX printer extent: screen/scrolling region */ + break; + case 25: /* DECTCEM text cursor on/off */ + if (op == MODE_SET || op == MODE_RESET) { + edp->flags = (edp->flags & ~VTFL_CURSORON) | + ((op == MODE_SET) ? VTFL_CURSORON : 0); + (*edp->emulops->cursor)(edp->emulcookie, + (op == MODE_SET), + edp->crow, edp->ccol); + } + res = ((edp->flags & VTFL_CURSORON) ? 1 : 2); + break; + case 42: /* DECNRCM use 7-bit NRC / + 7/8 bit from DEC multilingual or ISO-latin-1*/ + break; + case 66: /* DECNKM numeric keypad */ + break; + case 68: /* DECKBUM keyboard usage data processing/typewriter */ + break; + default: +#ifdef VT100_PRINTUNKNOWN + printf("DEC mode %d unknown\n", nr); +#endif + break; + } + return (res); +} + +void +vt100_setmode(edp, nr, decmode) + struct wsemul_vt100_emuldata *edp; + int nr, decmode; +{ + if (decmode) + vt100_decmode(edp, nr, MODE_SET); + else + vt100_ansimode(edp, nr, MODE_SET); +} + +void +vt100_resetmode(edp, nr, decmode) + struct wsemul_vt100_emuldata *edp; + int nr, decmode; +{ + if (decmode) + vt100_decmode(edp, nr, MODE_RESET); + else + vt100_ansimode(edp, nr, MODE_RESET); +} + +void +vt100_reportmode(edp, nr, decmode) + struct wsemul_vt100_emuldata *edp; + int nr, decmode; +{ + char buf[20]; + int res, n; + + if (decmode) + res = vt100_decmode(edp, nr, MODE_REPORT); + else + res = vt100_ansimode(edp, nr, MODE_REPORT); + + n = sprintf(buf, "\033[%s%d;%d$y", (decmode ? "?" : ""), nr, res); + wsdisplay_emulinput(edp->cbcookie, buf, n); +} diff --git a/sys/dev/wscons/wsemul_vt100var.h b/sys/dev/wscons/wsemul_vt100var.h new file mode 100644 index 000000000000..8a9b40c30852 --- /dev/null +++ b/sys/dev/wscons/wsemul_vt100var.h @@ -0,0 +1,116 @@ +/* $NetBSD: wsemul_vt100var.h,v 1.1 1998/06/20 19:17:47 drochner Exp $ */ + +/* + * Copyright (c) 1998 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define VT100_EMUL_NARGS 10 /* max # of args to a command */ + +struct wsemul_vt100_emuldata { + const struct wsdisplay_emulops *emulops; + void *emulcookie; + int scrcapabilities; + u_int nrows, ncols, crow, ccol; + long defattr; /* default attribute */ + + long kernattr; /* attribute for kernel output */ + void *cbcookie; +#ifdef DIAGNOSTIC + int console; +#endif + + u_int state; /* processing state */ + int flags; +#define VTFL_LASTCHAR 1 /* printed last char on line (below cursor) */ +#define VTFL_INSERTMODE 2 +#define VTFL_APPLKEYPAD 4 +#define VTFL_APPLCURSOR 8 +#define VTFL_DECOM 16 /* origin mode */ +#define VTFL_DECAWM 32 /* auto wrap */ +#define VTFL_CURSORON 64 + long curattr; /* currently used attribute */ + int attrflags, fgcol, bgcol; /* properties of curattr */ + int scrreg_startrow; + int scrreg_nrows; + char *tabs; + + int nargs; + u_int args[VT100_EMUL_NARGS]; /* command args */ + + char designating; /* substate in VT100_EMUL_STATE_DESIGNATE */ + + int dcstype; /* substate in VT100_EMUL_STATE_STRING */ + char *dcsarg; + int dcspos; +#define DCS_MAXLEN 256 /* ??? */ +#define DCSTYPE_TABRESTORE 1 /* DCS2$t */ + + int savedcursor_row, savedcursor_col; +}; + +/* some useful utility macros */ +#define ARG(n) (edp->args[(n)]) +#define DEF1_ARG(n) (ARG(n) ? ARG(n) : 1) +#define COLS_LEFT (edp->ncols - edp->ccol - 1) +#define ROWS_ABOVE (edp->crow - edp->scrreg_startrow) +#define ROWS_BELOW (edp->scrreg_startrow + edp->scrreg_nrows \ + - edp->crow - 1) + +/* + * response to primary DA request + * operating level: 61 = VT100, 62 = VT200, 63 = VT300 + * extensions: 1 = 132 cols, 2 = printer port, 6 = selective erase, + * 7 = soft charset, 8 = UDKs, 9 = NRC sets + * VT100 = "033[?1;2c" + */ +#define WSEMUL_VT_ID1 "\033[?62;6c" +/* + * response to secondary DA request + * ident code: 24 = VT320 + * firmware version + * hardware options: 0 = no options + */ +#define WSEMUL_VT_ID2 "\033[>24;20;0c" + +void wsemul_vt100_reset __P((struct wsemul_vt100_emuldata *)); +void wsemul_vt100_scrollup __P((struct wsemul_vt100_emuldata *, int)); +void wsemul_vt100_scrolldown __P((struct wsemul_vt100_emuldata *, int)); +void wsemul_vt100_ed __P((struct wsemul_vt100_emuldata *, int)); +void wsemul_vt100_el __P((struct wsemul_vt100_emuldata *, int)); +void wsemul_vt100_handle_csi __P((struct wsemul_vt100_emuldata *, u_char)); +void wsemul_vt100_handle_csi_qm __P((struct wsemul_vt100_emuldata *, + u_char)); +void wsemul_vt100_handle_dcs __P((struct wsemul_vt100_emuldata *)); +void vt100_setmode __P((struct wsemul_vt100_emuldata *, int, int)); +void vt100_resetmode __P((struct wsemul_vt100_emuldata *, int, int)); +void vt100_reportmode __P((struct wsemul_vt100_emuldata *, int, int)); + +int wsemul_vt100_translate __P((void *cookie, keysym_t, char **));