diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /sys/arch/amiga/dev/ite.c |
initial import of NetBSD tree
Diffstat (limited to 'sys/arch/amiga/dev/ite.c')
-rw-r--r-- | sys/arch/amiga/dev/ite.c | 2262 |
1 files changed, 2262 insertions, 0 deletions
diff --git a/sys/arch/amiga/dev/ite.c b/sys/arch/amiga/dev/ite.c new file mode 100644 index 00000000000..a85b3864cc8 --- /dev/null +++ b/sys/arch/amiga/dev/ite.c @@ -0,0 +1,2262 @@ +/* $NetBSD: ite.c,v 1.32 1995/10/09 15:20:30 chopps Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * 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 by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * from: Utah Hdr: ite.c 1.1 90/07/09 + * @(#)ite.c 7.6 (Berkeley) 5/16/91 + */ + +/* + * ite - bitmaped terminal. + * Supports VT200, a few terminal features will be unavailable until + * the system actually probes the device (i.e. not after consinit()) + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/termios.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <dev/cons.h> +#include <amiga/amiga/cc.h> +#include <amiga/amiga/kdassert.h> +#include <amiga/amiga/color.h> /* DEBUG */ +#include <amiga/amiga/device.h> +#include <amiga/amiga/isr.h> +#include <amiga/dev/iteioctl.h> +#include <amiga/dev/itevar.h> +#include <amiga/dev/kbdmap.h> +#include <amiga/dev/grfioctl.h> +#include <amiga/dev/grfvar.h> + +#include "grfcc.h" + +/* + * XXX go ask sys/kern/tty.c:ttselect() + */ +#include "grf.h" +struct tty *ite_tty[NGRF]; + +#define ITEUNIT(dev) (minor(dev)) + +#define SUBR_INIT(ip) (ip)->grf->g_iteinit(ip) +#define SUBR_DEINIT(ip) (ip)->grf->g_itedeinit(ip) +#define SUBR_PUTC(ip,c,dy,dx,m) (ip)->grf->g_iteputc(ip,c,dy,dx,m) +#define SUBR_CURSOR(ip,flg) (ip)->grf->g_itecursor(ip,flg) +#define SUBR_CLEAR(ip,sy,sx,h,w) (ip)->grf->g_iteclear(ip,sy,sx,h,w) +#define SUBR_SCROLL(ip,sy,sx,count,dir) \ + (ip)->grf->g_itescroll(ip,sy,sx,count,dir) + +u_int ite_confunits; /* configured units */ + +int start_repeat_timeo = 30; /* first repeat after x s/100 */ +int next_repeat_timeo = 10; /* next repeat after x s/100 */ + +int ite_default_wrap = 1; /* you want vtxxx-nam, binpatch */ + +struct ite_softc con_itesoftc; +u_char cons_tabs[MAX_TABS]; + +struct ite_softc *kbd_ite; +int kbd_init; + +/* audio bell stuff */ +u_int bvolume = 10; +u_int bpitch = 660; +u_int bmsec = 75; + +static char *bsamplep; +static char sample[20] = { + 0,39,75,103,121,127,121,103,75,39,0, + -39,-75,-103,-121,-127,-121,-103,-75,-39 +}; + +static char *index __P((const char *, char)); +static int inline atoi __P((const char *)); +static void ite_sifilter __P((void *, void *)); +void iteputchar __P((int c, struct ite_softc *ip)); +void ite_putstr __P((const char * s, int len, dev_t dev)); +void iteattach __P((struct device *, struct device *, void *)); +int itematch __P((struct device *, struct cfdata *, void *)); + +struct cfdriver itecd = { + NULL, "ite", (cfmatch_t)itematch, iteattach, DV_DULL, + sizeof(struct ite_softc), NULL, 0 }; + +int +itematch(pdp, cdp, auxp) + struct device *pdp; + struct cfdata *cdp; + void *auxp; +{ + struct grf_softc *gp; + int maj; + + gp = auxp; + /* + * all that our mask allows (more than enough no one + * has > 32 monitors for text consoles on one machine) + */ + if (cdp->cf_unit >= sizeof(ite_confunits) * NBBY) + return(0); + /* + * XXX + * normally this would be done in attach, however + * during early init we do not have a device pointer + * and thus no unit number. + */ + for(maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == iteopen) + break; + gp->g_itedev = makedev(maj, cdp->cf_unit); + return(1); +} + +void +iteattach(pdp, dp, auxp) + struct device *pdp, *dp; + void *auxp; +{ + extern int hz; + struct grf_softc *gp; + struct ite_softc *ip; + int s; + + gp = (struct grf_softc *)auxp; + + /* + * mark unit as attached (XXX see itematch) + */ + ite_confunits |= 1 << ITEUNIT(gp->g_itedev); + + if (dp) { + ip = (struct ite_softc *)dp; + + s = spltty(); + if (con_itesoftc.grf != NULL && + con_itesoftc.grf->g_unit == gp->g_unit) { + /* + * console reinit copy params over. + * and console always gets keyboard + */ + bcopy(&con_itesoftc.grf, &ip->grf, + (char *)&ip[1] - (char *)&ip->grf); + con_itesoftc.grf = NULL; + kbd_ite = ip; + } + ip->grf = gp; + splx(s); + + alloc_sicallback(); + iteinit(gp->g_itedev); + printf(": rows %d cols %d", ip->rows, ip->cols); + printf(" repeat at (%d/100)s next at (%d/100)s", + start_repeat_timeo, next_repeat_timeo); + + if (kbd_ite == NULL) + kbd_ite = ip; + if (kbd_ite == ip) + printf(" has keyboard"); + printf("\n"); + } else { + if (con_itesoftc.grf != NULL && + con_itesoftc.grf->g_conpri > gp->g_conpri) + return; + con_itesoftc.grf = gp; + con_itesoftc.tabs = cons_tabs; + } +} + +struct ite_softc * +getitesp(dev) + dev_t dev; +{ + if (amiga_realconfig && con_itesoftc.grf == NULL) + return(itecd.cd_devs[ITEUNIT(dev)]); + + if (con_itesoftc.grf == NULL) + panic("no ite_softc for console"); + return(&con_itesoftc); +} + +/* + * cons.c entry points into ite device. + */ + +/* + * Return a priority in consdev->cn_pri field highest wins. This function + * is called before any devices have been probed. + */ +void +itecnprobe(cd) + struct consdev *cd; +{ + /* + * bring graphics layer up. + */ + config_console(); + + /* + * return priority of the best ite (already picked from attach) + * or CN_DEAD. + */ + if (con_itesoftc.grf == NULL) + cd->cn_pri = CN_DEAD; + else { + cd->cn_pri = con_itesoftc.grf->g_conpri; + cd->cn_dev = con_itesoftc.grf->g_itedev; + } +} + +/* audio bell stuff */ +void +init_bell() +{ + short i; + + if (bsamplep != NULL) + return; + bsamplep = alloc_chipmem(20); + if (bsamplep == NULL) + panic("no chipmem for ite_bell"); + + bcopy(sample, bsamplep, 20); +} + +void +ite_bell() +{ + u_int clock; + u_int period; + u_int count; + + clock = 3579545; /* PAL 3546895 */ + + /* + * the number of clock ticks per sample byte must be > 124 + * ergo bpitch must be < clock / 124*20 + * i.e. ~1443, 1300 to be safe (PAL etc.). also not zero obviously + */ + period = clock / (bpitch * 20); + count = bmsec * bpitch / 1000; + + play_sample(10, PREP_DMA_MEM(bsamplep), period, bvolume, 0x3, count); +} + +void +itecninit(cd) + struct consdev *cd; +{ + struct ite_softc *ip; + + ip = getitesp(cd->cn_dev); + iteinit(cd->cn_dev); + ip->flags |= ITE_ACTIVE | ITE_ISCONS; + + init_bell(); +} + +/* + * ite_cnfinish() is called in ite_init() when the device is + * being probed in the normal fasion, thus we can finish setting + * up this ite now that the system is more functional. + */ +void +ite_cnfinish(ip) + struct ite_softc *ip; +{ + static int done; + + if (done) + return; + done = 1; +} + +int +itecngetc(dev) + dev_t dev; +{ + int c; + + /* XXX this should be moved */ + if (!kbd_init) { + kbd_init = 1; + kbdenable(); + } + do { + c = kbdgetcn(); + c = ite_cnfilter(c, ITEFILT_CONSOLE); + } while (c == -1); + return (c); +} + +void +itecnputc(dev, c) + dev_t dev; + int c; +{ + static int paniced; + struct ite_softc *ip; + char ch; + + ip = getitesp(dev); + ch = c; + + if (panicstr && !paniced && + (ip->flags & (ITE_ACTIVE | ITE_INGRF)) != ITE_ACTIVE) { + (void)ite_on(dev, 3); + paniced = 1; + } + iteputchar(ch, ip); +} + +void +itecnpollc(dev, on) + dev_t dev; + int on; +{ + +} + +/* + * standard entry points to the device. + */ + +/* + * iteinit() is the standard entry point for initialization of + * an ite device, it is also called from ite_cninit(). + * + */ +void +iteinit(dev) + dev_t dev; +{ + struct ite_softc *ip; + + ip = getitesp(dev); + if (ip->flags & ITE_INITED) + return; + bcopy(&ascii_kbdmap, &kbdmap, sizeof(struct kbdmap)); + + ip->cursorx = 0; + ip->cursory = 0; + SUBR_INIT(ip); + SUBR_CURSOR(ip, DRAW_CURSOR); + if (ip->tabs == NULL) + ip->tabs = malloc(MAX_TABS * sizeof(u_char),M_DEVBUF,M_WAITOK); + ite_reset(ip); + ip->flags |= ITE_INITED; +} + +int +iteopen(dev, mode, devtype, p) + dev_t dev; + int mode, devtype; + struct proc *p; +{ + struct ite_softc *ip; + struct tty *tp; + int error, first, unit; + + unit = ITEUNIT(dev); + first = 0; + + if (((1 << unit) & ite_confunits) == 0) + return (ENXIO); + + ip = getitesp(dev); + + if (ip->tp == NULL) + tp = ite_tty[unit] = ip->tp = ttymalloc(); + else + tp = ip->tp; + if ((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) == (TS_ISOPEN | TS_XCLUDE) + && p->p_ucred->cr_uid != 0) + return (EBUSY); + if ((ip->flags & ITE_ACTIVE) == 0) { + error = ite_on(dev, 0); + if (error) + return (error); + first = 1; + } + tp->t_oproc = itestart; + tp->t_param = ite_param; + tp->t_dev = dev; + if ((tp->t_state & TS_ISOPEN) == 0) { + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; + tp->t_state = TS_WOPEN | TS_CARR_ON; + ttsetwater(tp); + } + error = (*linesw[tp->t_line].l_open) (dev, tp); + if (error == 0) { + tp->t_winsize.ws_row = ip->rows; + tp->t_winsize.ws_col = ip->cols; + if (!kbd_init) { + kbd_init = 1; + kbdenable(); + } + } else if (first) + ite_off(dev, 0); + return (error); +} + +int +iteclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + struct tty *tp; + + tp = getitesp(dev)->tp; + + KDASSERT(tp); + (*linesw[tp->t_line].l_close) (tp, flag); + ttyclose(tp); + ite_off(dev, 0); + return (0); +} + +int +iteread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct tty *tp; + + tp = getitesp(dev)->tp; + + KDASSERT(tp); + return ((*linesw[tp->t_line].l_read) (tp, uio, flag)); +} + +int +itewrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct tty *tp; + + tp = getitesp(dev)->tp; + + KDASSERT(tp); + return ((*linesw[tp->t_line].l_write) (tp, uio, flag)); +} + +struct tty * +itetty(dev) + dev_t dev; +{ + return (ite_tty[ITEUNIT(dev)]); +} + +int +itestop(tp, flag) + struct tty *tp; + int flag; +{ + +} + +int +iteioctl(dev, cmd, addr, flag, p) + dev_t dev; + u_long cmd; + caddr_t addr; + int flag; + struct proc *p; +{ + struct iterepeat *irp; + struct ite_softc *ip; + struct itebell *ib; + struct tty *tp; + int error; + + ip = getitesp(dev); + tp = ip->tp; + + KDASSERT(tp); + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr, flag, p); + if (error >= 0) + return (error); + error = ttioctl(tp, cmd, addr, flag, p); + if (error >= 0) + return (error); + + switch (cmd) { + case ITEIOCGBELL: + ib = (struct itebell *)addr; + ib->volume = bvolume; + ib->pitch = bpitch; + ib->msec = bmsec; + return (0); + case ITEIOCSBELL: + ib = (struct itebell *)addr; + + if (ib->pitch > MAXBPITCH || ib->pitch < MINBPITCH || + ib->volume > MAXBVOLUME || ib->msec > MAXBTIME) + return (EINVAL); + bvolume = ib->volume; + bpitch = ib->pitch; + bmsec = ib->msec; + return (0); + case ITEIOCSKMAP: + if (addr == 0) + return(EFAULT); + bcopy(addr, &kbdmap, sizeof(struct kbdmap)); + return(0); + case ITEIOCGKMAP: + if (addr == NULL) + return(EFAULT); + bcopy(&kbdmap, addr, sizeof(struct kbdmap)); + return(0); + case ITEIOCGREPT: + irp = (struct iterepeat *)addr; + irp->start = start_repeat_timeo; + irp->next = next_repeat_timeo; + return (0); + case ITEIOCSREPT: + irp = (struct iterepeat *)addr; + if (irp->start < ITEMINREPEAT && irp->next < ITEMINREPEAT) + return(EINVAL); + start_repeat_timeo = irp->start; + next_repeat_timeo = irp->next; + return(0); + } +#if NGRFCC > 0 + /* XXX */ + if (minor(dev) == 0) { + error = ite_grf_ioctl(ip, cmd, addr, flag, p); + if (error >= 0) + return (error); + } +#endif + return (ENOTTY); +} + +void +itestart(tp) + struct tty *tp; +{ + struct clist *rbp; + struct ite_softc *ip; + u_char buf[ITEBURST]; + int s, len, n; + + ip = getitesp(tp->t_dev); + + KDASSERT(tp); + + s = spltty(); { + if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) + goto out; + + tp->t_state |= TS_BUSY; + rbp = &tp->t_outq; + + len = q_to_b(rbp, buf, ITEBURST); + } splx(s); + + /* Here is a really good place to implement pre/jumpscroll() */ + ite_putstr(buf, len, tp->t_dev); + + s = spltty(); { + tp->t_state &= ~TS_BUSY; + /* we have characters remaining. */ + if (rbp->c_cc) { + tp->t_state |= TS_TIMEOUT; + timeout(ttrstrt, tp, 1); + } + /* wakeup we are below */ + if (rbp->c_cc <= tp->t_lowat) { + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t) rbp); + } + selwakeup(&tp->t_wsel); + } + out: + } splx(s); +} + +int +ite_on(dev, flag) + dev_t dev; + int flag; +{ + struct ite_softc *ip; + int unit; + + unit = ITEUNIT(dev); + if (((1 << unit) & ite_confunits) == 0) + return (ENXIO); + + ip = getitesp(dev); + + /* force ite active, overriding graphics mode */ + if (flag & 1) { + ip->flags |= ITE_ACTIVE; + ip->flags &= ~(ITE_INGRF | ITE_INITED); + } + /* leave graphics mode */ + if (flag & 2) { + ip->flags &= ~ITE_INGRF; + if ((ip->flags & ITE_ACTIVE) == 0) + return (0); + } + ip->flags |= ITE_ACTIVE; + if (ip->flags & ITE_INGRF) + return (0); + iteinit(dev); + return (0); +} + +int +ite_off(dev, flag) + dev_t dev; + int flag; +{ + struct ite_softc *ip; + + ip = getitesp(dev); + if (flag & 2) + ip->flags |= ITE_INGRF; + if ((ip->flags & ITE_ACTIVE) == 0) + return; + if ((flag & 1) || + (ip->flags & (ITE_INGRF | ITE_ISCONS | ITE_INITED)) == ITE_INITED) + SUBR_DEINIT(ip); + if ((flag & 2) == 0) /* XXX hmm grfon() I think wants this to go inactive. */ + ip->flags &= ~ITE_ACTIVE; +} + +/* XXX called after changes made in underlying grf layer. */ +/* I want to nuke this */ +void +ite_reinit(dev) + dev_t dev; +{ + struct ite_softc *ip; + + ip = getitesp(dev); + ip->flags &= ~ITE_INITED; + iteinit(dev); +} + +int +ite_param(tp, t) + struct tty *tp; + struct termios *t; +{ + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + return (0); +} + +void +ite_reset(ip) + struct ite_softc *ip; +{ + int i; + + ip->curx = 0; + ip->cury = 0; + ip->attribute = ATTR_NOR; + ip->save_curx = 0; + ip->save_cury = 0; + ip->save_attribute = ATTR_NOR; + ip->ap = ip->argbuf; + ip->emul_level = 0; + ip->eightbit_C1 = 0; + ip->top_margin = 0; + ip->bottom_margin = ip->rows - 1; + ip->inside_margins = 0; + ip->linefeed_newline = 0; + ip->auto_wrap = ite_default_wrap; + ip->cursor_appmode = 0; + ip->keypad_appmode = 0; + ip->imode = 0; + ip->key_repeat = 1; + bzero(ip->tabs, ip->cols); + for (i = 0; i < ip->cols; i++) + ip->tabs[i] = ((i & 7) == 0); +} + +/* + * has to be global becuase of the shared filters. + */ +static u_char key_mod; +static u_char last_dead; + +/* Used in console at startup only */ +int +ite_cnfilter(c, caller) + u_char c; + enum caller caller; +{ + struct key key; + u_char code, up, mask; + int s, i; + + up = c & 0x80 ? 1 : 0; + c &= 0x7f; + code = 0; + + s = spltty(); + + i = (int)c - KBD_LEFT_SHIFT; + if (i >= 0 && i <= (KBD_RIGHT_META - KBD_LEFT_SHIFT)) { + mask = 1 << i; + if (up) + key_mod &= ~mask; + else + key_mod |= mask; + splx(s); + return -1; + } + + if (up) { + splx(s); + return -1; + } + + /* translate modifiers */ + if (key_mod & KBD_MOD_SHIFT) { + if (key_mod & KBD_MOD_ALT) + key = kbdmap.alt_shift_keys[c]; + else + key = kbdmap.shift_keys[c]; + } else if (key_mod & KBD_MOD_ALT) + key = kbdmap.alt_keys[c]; + else { + key = kbdmap.keys[c]; + /* if CAPS and key is CAPable (no pun intended) */ + if ((key_mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS)) + key = kbdmap.shift_keys[c]; + } + code = key.code; + + /* if string return */ + if (key.mode & (KBD_MODE_STRING | KBD_MODE_KPAD)) { + splx(s); + return -1; + } + /* handle dead keys */ + if (key.mode & KBD_MODE_DEAD) { + /* if entered twice, send accent itself */ + if (last_dead == key.mode & KBD_MODE_ACCMASK) + last_dead = 0; + else { + last_dead = key.mode & KBD_MODE_ACCMASK; + splx(s); + return -1; + } + } + if (last_dead) { + /* can't apply dead flag to string-keys */ + if (code >= '@' && code < 0x7f) + code = + acctable[KBD_MODE_ACCENT(last_dead)][code - '@']; + last_dead = 0; + } + if (key_mod & KBD_MOD_CTRL) + code &= 0x1f; + if (key_mod & KBD_MOD_META) + code |= 0x80; + + /* do console mapping. */ + code = code == '\r' ? '\n' : code; + + splx(s); + return (code); +} + +/* And now the old stuff. */ + +/* these are used to implement repeating keys.. */ +static u_char last_char; +static u_char tout_pending; + + +static void +ite_sifilter(void *arg1, void *arg2) +{ + ite_filter((u_char)arg1, (enum caller)arg2); +} + + +/*ARGSUSED*/ +static void +repeat_handler(arg) + void *arg; +{ + tout_pending = 0; + if (last_char) + add_sicallback(ite_sifilter, (void *)last_char, + (void *)ITEFILT_REPEATER); +} + +void +ite_filter(c, caller) + u_char c; + enum caller caller; +{ + struct tty *kbd_tty; + u_char code, *str, up, mask; + struct key key; + int s, i; + + if (kbd_ite == NULL || kbd_ite->tp == NULL) + return; + + kbd_tty = kbd_ite->tp; + + /* have to make sure we're at spltty in here */ + s = spltty(); + + /* + * keyboard interrupts come at priority 2, while softint + * generated keyboard-repeat interrupts come at level 1. So, + * to not allow a key-up event to get thru before a repeat for + * the key-down, we remove any outstanding callout requests.. + */ + rem_sicallback(ite_filter); + + up = c & 0x80 ? 1 : 0; + c &= 0x7f; + code = 0; + + i = (int)c - KBD_LEFT_SHIFT; + if (i >= 0 && i <= (KBD_RIGHT_META - KBD_LEFT_SHIFT)) { + mask = 1 << i; + if (up) + key_mod &= ~mask; + else + key_mod |= mask; + splx(s); + return; + } + /* stop repeating on up event */ + if (up) { + if (tout_pending) { + untimeout(repeat_handler, 0); + tout_pending = 0; + last_char = 0; + } + splx(s); + return; + } else if (tout_pending && last_char != c) { + /* different character, stop also */ + untimeout(repeat_handler, 0); + tout_pending = 0; + last_char = 0; + } + /* Safety button, switch back to ascii keymap. */ + if (key_mod == (KBD_MOD_LALT | KBD_MOD_LMETA) && c == 0x50) { + bcopy(&ascii_kbdmap, &kbdmap, sizeof(struct kbdmap)); + + splx(s); + return; +#ifdef DDB + } else if (key_mod == (KBD_MOD_LALT | KBD_MOD_LMETA) && c == 0x59) { + extern int Debugger(); + Debugger(); + splx(s); + return; +#endif + } + /* translate modifiers */ + if (key_mod & KBD_MOD_SHIFT) { + if (key_mod & KBD_MOD_ALT) + key = kbdmap.alt_shift_keys[c]; + else + key = kbdmap.shift_keys[c]; + } else if (key_mod & KBD_MOD_ALT) + key = kbdmap.alt_keys[c]; + else { + key = kbdmap.keys[c]; + /* if CAPS and key is CAPable (no pun intended) */ + if ((key_mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS)) + key = kbdmap.shift_keys[c]; + } + code = key.code; + + /* + * arrange to repeat the keystroke. By doing this at the level + * of scan-codes, we can have function keys, and keys that + * send strings, repeat too. This also entitles an additional + * overhead, since we have to do the conversion each time, but + * I guess that's ok. + */ + if (!tout_pending && caller == ITEFILT_TTY && kbd_ite->key_repeat) { + tout_pending = 1; + last_char = c; + timeout(repeat_handler, 0, start_repeat_timeo * hz / 100); + } else if (!tout_pending && caller == ITEFILT_REPEATER && + kbd_ite->key_repeat) { + tout_pending = 1; + last_char = c; + timeout(repeat_handler, 0, next_repeat_timeo * hz / 100); + } + /* handle dead keys */ + if (key.mode & KBD_MODE_DEAD) { + /* if entered twice, send accent itself */ + if (last_dead == key.mode & KBD_MODE_ACCMASK) + last_dead = 0; + else { + last_dead = key.mode & KBD_MODE_ACCMASK; + splx(s); + return; + } + } + if (last_dead) { + /* can't apply dead flag to string-keys */ + if (!(key.mode & KBD_MODE_STRING) && code >= '@' && + code < 0x7f) + code = acctable[KBD_MODE_ACCENT(last_dead)][code - '@']; + last_dead = 0; + } + /* if not string, apply META and CTRL modifiers */ + if (!(key.mode & KBD_MODE_STRING) + && (!(key.mode & KBD_MODE_KPAD) || + (kbd_ite && !kbd_ite->keypad_appmode))) { + if (key_mod & KBD_MOD_CTRL) + code &= 0x1f; + if (key_mod & KBD_MOD_META) + code |= 0x80; + } else if ((key.mode & KBD_MODE_KPAD) && + (kbd_ite && kbd_ite->keypad_appmode)) { + static char in[] = { + 0x0f /* 0 */, 0x1d /* 1 */, 0x1e /* 2 */, 0x1f /* 3 */, + 0x2d /* 4 */, 0x2e /* 5 */, 0x2f /* 6 */, 0x3d /* 7 */, + 0x3e /* 8 */, 0x3f /* 9 */, 0x4a /* - */, 0x5e /* + */, + 0x3c /* . */, 0x43 /* e */, 0x5a /* ( */, 0x5b /* ) */, + 0x5c /* / */, 0x5d /* * */ + }; + static char *out = "pqrstuvwxymlnMPQRS"; + char *cp = index (in, c); + + /* + * keypad-appmode sends SS3 followed by the above + * translated character + */ + (*linesw[kbd_tty->t_line].l_rint) (27, kbd_tty); + (*linesw[kbd_tty->t_line].l_rint) ('O', kbd_tty); + (*linesw[kbd_tty->t_line].l_rint) (out[cp - in], kbd_tty); + splx(s); + return; + } else { + /* *NO* I don't like this.... */ + static u_char app_cursor[] = + { + 3, 27, 'O', 'A', + 3, 27, 'O', 'B', + 3, 27, 'O', 'C', + 3, 27, 'O', 'D'}; + + str = kbdmap.strings + code; + /* + * if this is a cursor key, AND it has the default + * keymap setting, AND we're in app-cursor mode, switch + * to the above table. This is *nasty* ! + */ + if (c >= 0x4c && c <= 0x4f && kbd_ite->cursor_appmode + && !bcmp(str, "\x03\x1b[", 3) && + index("ABCD", str[3])) + str = app_cursor + 4 * (str[3] - 'A'); + + /* + * using a length-byte instead of 0-termination allows + * to embed \0 into strings, although this is not used + * in the default keymap + */ + for (i = *str++; i; i--) + (*linesw[kbd_tty->t_line].l_rint) (*str++, kbd_tty); + splx(s); + return; + } + (*linesw[kbd_tty->t_line].l_rint) (code, kbd_tty); + + splx(s); + return; +} + +/* helper functions, makes the code below more readable */ +static void inline +ite_sendstr(str) + char *str; +{ + struct tty *kbd_tty; + + kbd_tty = kbd_ite->tp; + KDASSERT(kbd_tty); + while (*str) + (*linesw[kbd_tty->t_line].l_rint) (*str++, kbd_tty); +} + +static void +alignment_display(ip) + struct ite_softc *ip; +{ + int i, j; + + for (j = 0; j < ip->rows; j++) + for (i = 0; i < ip->cols; i++) + SUBR_PUTC(ip, 'E', j, i, ATTR_NOR); + attrclr(ip, 0, 0, ip->rows, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +snap_cury(ip) + struct ite_softc *ip; +{ + if (ip->inside_margins) + { + if (ip->cury < ip->top_margin) + ip->cury = ip->top_margin; + if (ip->cury > ip->bottom_margin) + ip->cury = ip->bottom_margin; + } +} + +static void inline +ite_dnchar(ip, n) + struct ite_softc *ip; + int n; +{ + n = min(n, ip->cols - ip->curx); + if (n < ip->cols - ip->curx) + { + SUBR_SCROLL(ip, ip->cury, ip->curx + n, n, SCROLL_LEFT); + attrmov(ip, ip->cury, ip->curx + n, ip->cury, ip->curx, + 1, ip->cols - ip->curx - n); + attrclr(ip, ip->cury, ip->cols - n, 1, n); + } + while (n-- > 0) + SUBR_PUTC(ip, ' ', ip->cury, ip->cols - n - 1, ATTR_NOR); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_inchar(ip, n) + struct ite_softc *ip; + int n; +{ + n = min(n, ip->cols - ip->curx); + if (n < ip->cols - ip->curx) + { + SUBR_SCROLL(ip, ip->cury, ip->curx, n, SCROLL_RIGHT); + attrmov(ip, ip->cury, ip->curx, ip->cury, ip->curx + n, + 1, ip->cols - ip->curx - n); + attrclr(ip, ip->cury, ip->curx, 1, n); + } + while (n--) + SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_clrtoeol(ip) + struct ite_softc *ip; +{ + int y = ip->cury, x = ip->curx; + if (ip->cols - x > 0) + { + SUBR_CLEAR(ip, y, x, 1, ip->cols - x); + attrclr(ip, y, x, 1, ip->cols - x); + SUBR_CURSOR(ip, DRAW_CURSOR); + } +} + +static void inline +ite_clrtobol(ip) + struct ite_softc *ip; +{ + int y = ip->cury, x = min(ip->curx + 1, ip->cols); + SUBR_CLEAR(ip, y, 0, 1, x); + attrclr(ip, y, 0, 1, x); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_clrline(ip) + struct ite_softc *ip; +{ + int y = ip->cury; + SUBR_CLEAR(ip, y, 0, 1, ip->cols); + attrclr(ip, y, 0, 1, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + + + +static void inline +ite_clrtoeos(ip) + struct ite_softc *ip; +{ + ite_clrtoeol(ip); + if (ip->cury < ip->rows - 1) + { + SUBR_CLEAR(ip, ip->cury + 1, 0, ip->rows - 1 - ip->cury, ip->cols); + attrclr(ip, ip->cury, 0, ip->rows - ip->cury, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); + } +} + +static void inline +ite_clrtobos(ip) + struct ite_softc *ip; +{ + ite_clrtobol(ip); + if (ip->cury > 0) + { + SUBR_CLEAR(ip, 0, 0, ip->cury, ip->cols); + attrclr(ip, 0, 0, ip->cury, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); + } +} + +static void inline +ite_clrscreen(ip) + struct ite_softc *ip; +{ + SUBR_CLEAR(ip, 0, 0, ip->rows, ip->cols); + attrclr(ip, 0, 0, ip->rows, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + + + +static void inline +ite_dnline(ip, n) + struct ite_softc *ip; + int n; +{ + /* interesting.. if the cursor is outside the scrolling + region, this command is simply ignored.. */ + if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin) + return; + + n = min(n, ip->bottom_margin + 1 - ip->cury); + if (n <= ip->bottom_margin - ip->cury) + { + SUBR_SCROLL(ip, ip->cury + n, 0, n, SCROLL_UP); + attrmov(ip, ip->cury + n, 0, ip->cury, 0, + ip->bottom_margin + 1 - ip->cury - n, ip->cols); + } + SUBR_CLEAR(ip, ip->bottom_margin - n + 1, 0, n, ip->cols); + attrclr(ip, ip->bottom_margin - n + 1, 0, n, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_inline(ip, n) + struct ite_softc *ip; + int n; +{ + /* interesting.. if the cursor is outside the scrolling + region, this command is simply ignored.. */ + if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin) + return; + + n = min(n, ip->bottom_margin + 1 - ip->cury); + if (n <= ip->bottom_margin - ip->cury) + { + SUBR_SCROLL(ip, ip->cury, 0, n, SCROLL_DOWN); + attrmov(ip, ip->cury, 0, ip->cury + n, 0, + ip->bottom_margin + 1 - ip->cury - n, ip->cols); + } + SUBR_CLEAR(ip, ip->cury, 0, n, ip->cols); + attrclr(ip, ip->cury, 0, n, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_lf (ip) + struct ite_softc *ip; +{ + ++ip->cury; + if ((ip->cury == ip->bottom_margin+1) || (ip->cury == ip->rows)) + { + ip->cury--; + SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); + ite_clrline(ip); + } + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); +} + +static void inline +ite_crlf (ip) + struct ite_softc *ip; +{ + ip->curx = 0; + ite_lf (ip); +} + +static void inline +ite_cr (ip) + struct ite_softc *ip; +{ + if (ip->curx) + { + ip->curx = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + } +} + +static void inline +ite_rlf (ip) + struct ite_softc *ip; +{ + ip->cury--; + if ((ip->cury < 0) || (ip->cury == ip->top_margin - 1)) + { + ip->cury++; + SUBR_SCROLL(ip, ip->top_margin, 0, 1, SCROLL_DOWN); + ite_clrline(ip); + } + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); +} + +static int inline +atoi (cp) + const char *cp; +{ + int n; + + for (n = 0; *cp && *cp >= '0' && *cp <= '9'; cp++) + n = n * 10 + *cp - '0'; + + return n; +} + +static char * +index (cp, ch) + const char *cp; + char ch; +{ + while (*cp && *cp != ch) cp++; + return *cp ? (char *) cp : 0; +} + + + +static int inline +ite_argnum (ip) + struct ite_softc *ip; +{ + char ch; + int n; + + /* convert argument string into number */ + if (ip->ap == ip->argbuf) + return 1; + ch = *ip->ap; + *ip->ap = 0; + n = atoi (ip->argbuf); + *ip->ap = ch; + + return n; +} + +static int inline +ite_zargnum (ip) + struct ite_softc *ip; +{ + char ch, *cp; + int n; + + /* convert argument string into number */ + if (ip->ap == ip->argbuf) + return 0; + ch = *ip->ap; + *ip->ap = 0; + n = atoi (ip->argbuf); + *ip->ap = ch; + + return n; /* don't "n ? n : 1" here, <CSI>0m != <CSI>1m ! */ +} + +static int inline +strncmp (a, b, l) + const char *a, *b; + int l; +{ + for (;l--; a++, b++) + if (*a != *b) + return *a - *b; + return 0; +} + +void +ite_putstr(s, len, dev) + const char *s; + int len; + dev_t dev; +{ + struct ite_softc *ip; + int i; + + ip = getitesp(dev); + + /* XXX avoid problems */ + if ((ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE) + return; + + SUBR_CURSOR(ip, START_CURSOROPT); + for (i = 0; i < len; i++) + if (s[i]) + iteputchar(s[i], ip); + SUBR_CURSOR(ip, END_CURSOROPT); +} + +void +iteputchar(c, ip) + register int c; + struct ite_softc *ip; +{ + struct tty *kbd_tty; + int n, x, y; + char *cp; + + if (kbd_ite == NULL) + kbd_tty = NULL; + else + kbd_tty = kbd_ite->tp; + + if (ip->escape) { +doesc: + switch (ip->escape) { + case ESC: + switch (c) { + /* + * first 7bit equivalents for the + * 8bit control characters + */ + case 'D': + c = IND; + ip->escape = 0; + break; + /* + * and fall into the next + * switch below (same for all `break') + */ + case 'E': + c = NEL; + ip->escape = 0; + break; + case 'H': + c = HTS; + ip->escape = 0; + break; + case 'M': + c = RI; + ip->escape = 0; + break; + case 'N': + c = SS2; + ip->escape = 0; + break; + case 'O': + c = SS3; + ip->escape = 0; + break; + case 'P': + c = DCS; + ip->escape = 0; + break; + case '[': + c = CSI; + ip->escape = 0; + break; + case '\\': + c = ST; + ip->escape = 0; + break; + case ']': + c = OSC; + ip->escape = 0; + break; + case '^': + c = PM; + ip->escape = 0; + break; + case '_': + c = APC; + ip->escape = 0; + break; + /* introduces 7/8bit control */ + case ' ': + /* can be followed by either F or G */ + ip->escape = ' '; + break; + /* + * a lot of character set selections, not yet + * used... 94-character sets: + */ + case '(': /* G0 */ + case ')': /* G1 */ + ip->escape = c; + return; + case '*': /* G2 */ + case '+': /* G3 */ + case 'B': /* ASCII */ + case 'A': /* ISO latin 1 */ + case '<': /* user preferred suplemental */ + case '0': /* dec special graphics */ + /* + * 96-character sets: + */ + case '-': /* G1 */ + case '.': /* G2 */ + case '/': /* G3 */ + /* + * national character sets: + */ + case '4': /* dutch */ + case '5': + case 'C': /* finnish */ + case 'R': /* french */ + case 'Q': /* french canadian */ + case 'K': /* german */ + case 'Y': /* italian */ + case '6': /* norwegian/danish */ + /* + * note: %5 and %6 are not supported (two + * chars..) + */ + ip->escape = 0; + /* just ignore for now */ + return; + /* + * locking shift modes (as you might guess, not + * yet supported..) + */ + case '`': + ip->GR = ip->G1; + ip->escape = 0; + return; + case 'n': + ip->GL = ip->G2; + ip->escape = 0; + return; + case '}': + ip->GR = ip->G2; + ip->escape = 0; + return; + case 'o': + ip->GL = ip->G3; + ip->escape = 0; + return; + case '|': + ip->GR = ip->G3; + ip->escape = 0; + return; + case '#': + /* font width/height control */ + ip->escape = '#'; + return; + case 'c': + /* hard terminal reset .. */ + ite_reset(ip); + SUBR_CURSOR(ip, MOVE_CURSOR); + ip->escape = 0; + return; + case '7': + ip->save_curx = ip->curx; + ip->save_cury = ip->cury; + ip->save_attribute = ip->attribute; + ip->escape = 0; + return; + case '8': + ip->curx = ip->save_curx; + ip->cury = ip->save_cury; + ip->attribute = ip->save_attribute; + SUBR_CURSOR(ip, MOVE_CURSOR); + ip->escape = 0; + return; + case '=': + ip->keypad_appmode = 1; + ip->escape = 0; + return; + case '>': + ip->keypad_appmode = 0; + ip->escape = 0; + return; + case 'Z': /* request ID */ + /* XXX not clean */ + if (ip->emul_level == EMUL_VT100) + ite_sendstr("\033[?61;0c"); + else + ite_sendstr("\033[?63;0c"); + ip->escape = 0; + return; + default: + /* + * default catch all for not recognized ESC + * sequences + */ + ip->escape = 0; + return; + } + break; + case '(': + case ')': + ip->escape = 0; + return; + case ' ': + switch (c) { + case 'F': + ip->eightbit_C1 = 0; + ip->escape = 0; + return; + case 'G': + ip->eightbit_C1 = 1; + ip->escape = 0; + return; + default: + /* not supported */ + ip->escape = 0; + return; + } + break; + case '#': + switch (c) { + case '5': + /* single height, single width */ + ip->escape = 0; + return; + case '6': + /* double width, single height */ + ip->escape = 0; + return; + case '3': + /* top half */ + ip->escape = 0; + return; + case '4': + /* bottom half */ + ip->escape = 0; + return; + case '8': + /* screen alignment pattern... */ + alignment_display(ip); + ip->escape = 0; + return; + default: + ip->escape = 0; + return; + } + break; + case CSI: + /* the biggie... */ + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case ';': + case '\"': + case '$': + case '>': + if (ip->ap < ip->argbuf + MAX_ARGSIZE) + *ip->ap++ = c; + return; + case BS: + /* + * you wouldn't believe such perversion is + * possible? it is.. BS is allowed in between + * cursor sequences (at least), according to + * vttest.. + */ + if (--ip->curx < 0) + ip->curx = 0; + else + SUBR_CURSOR(ip, MOVE_CURSOR); + break; + case 'p': + *ip->ap = 0; + if (!strncmp(ip->argbuf, "61\"", 3)) + ip->emul_level = EMUL_VT100; + else if (!strncmp(ip->argbuf, "63;1\"", 5) + || !strncmp(ip->argbuf, "62;1\"", 5)) + ip->emul_level = EMUL_VT300_7; + else + ip->emul_level = EMUL_VT300_8; + ip->escape = 0; + return; + case '?': + *ip->ap = 0; + ip->escape = '?'; + ip->ap = ip->argbuf; + return; + case 'c': + *ip->ap = 0; + if (ip->argbuf[0] == '>') { + ite_sendstr("\033[>24;0;0;0c"); + } else + switch (ite_zargnum(ip)) { + case 0: + /* + * primary DA request, send + * primary DA response + */ + if (ip->emul_level + == EMUL_VT100) + ite_sendstr( + "\033[?1;1c"); + else + ite_sendstr( + "\033[?63;1c"); + break; + } + ip->escape = 0; + return; + case 'n': + switch (ite_zargnum(ip)) { + case 5: + /* no malfunction */ + ite_sendstr("\033[0n"); + break; + case 6: + /* cursor position report */ + sprintf(ip->argbuf, "\033[%d;%dR", + ip->cury + 1, ip->curx + 1); + ite_sendstr(ip->argbuf); + break; + } + ip->escape = 0; + return; + case 'x': + switch (ite_zargnum(ip)) { + case 0: + /* Fake some terminal parameters. */ + ite_sendstr("\033[2;1;1;112;112;1;0x"); + break; + case 1: + ite_sendstr("\033[3;1;1;112;112;1;0x"); + break; + } + ip->escape = 0; + return; + case 'g': + switch (ite_zargnum(ip)) { + case 0: + if (ip->curx < ip->cols) + ip->tabs[ip->curx] = 0; + break; + case 3: + for (n = 0; n < ip->cols; n++) + ip->tabs[n] = 0; + break; + } + ip->escape = 0; + return; + case 'h': + case 'l': + n = ite_zargnum(ip); + switch (n) { + case 4: + /* insert/replace mode */ + ip->imode = (c == 'h'); + break; + case 20: + ip->linefeed_newline = (c == 'h'); + break; + } + ip->escape = 0; + return; + case 'M': + ite_dnline(ip, ite_argnum(ip)); + ip->escape = 0; + return; + case 'L': + ite_inline(ip, ite_argnum(ip)); + ip->escape = 0; + return; + case 'P': + ite_dnchar(ip, ite_argnum(ip)); + ip->escape = 0; + return; + case '@': + ite_inchar(ip, ite_argnum(ip)); + ip->escape = 0; + return; + case 'G': + /* + * this one was *not* in my vt320 manual but in + * a vt320 termcap entry.. who is right? It's + * supposed to set the horizontal cursor + * position. + */ + *ip->ap = 0; + x = atoi(ip->argbuf); + if (x) + x--; + ip->curx = min(x, ip->cols - 1); + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); + return; + case 'd': + /* + * same thing here, this one's for setting the + * absolute vertical cursor position. Not + * documented... + */ + *ip->ap = 0; + y = atoi(ip->argbuf); + if (y) + y--; + if (ip->inside_margins) + y += ip->top_margin; + ip->cury = min(y, ip->rows - 1); + ip->escape = 0; + snap_cury(ip); + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); + return; + case 'H': + case 'f': + *ip->ap = 0; + y = atoi(ip->argbuf); + x = 0; + cp = index(ip->argbuf, ';'); + if (cp) + x = atoi(cp + 1); + if (x) + x--; + if (y) + y--; + if (ip->inside_margins) + y += ip->top_margin; + ip->cury = min(y, ip->rows - 1); + ip->curx = min(x, ip->cols - 1); + ip->escape = 0; + snap_cury(ip); + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); + return; + case 'A': + n = ite_argnum(ip); + n = ip->cury - (n ? n : 1); + if (n < 0) + n = 0; + if (ip->inside_margins) + n = max(ip->top_margin, n); + else if (n == ip->top_margin - 1) + /* + * allow scrolling outside region, but + * don't scroll out of active region + * without explicit CUP + */ + n = ip->top_margin; + ip->cury = n; + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); + return; + case 'B': + n = ite_argnum(ip); + n = ip->cury + (n ? n : 1); + n = min(ip->rows - 1, n); + if (ip->inside_margins) + n = min(ip->bottom_margin, n); + else if (n == ip->bottom_margin + 1) + /* + * allow scrolling outside region, but + * don't scroll out of active region + * without explicit CUP + */ + n = ip->bottom_margin; + ip->cury = n; + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); + return; + case 'C': + n = ite_argnum(ip); + n = n ? n : 1; + ip->curx = min(ip->curx + n, ip->cols - 1); + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); + return; + case 'D': + n = ite_argnum(ip); + n = n ? n : 1; + n = ip->curx - n; + ip->curx = n >= 0 ? n : 0; + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); + return; + case 'J': + *ip->ap = 0; + n = ite_zargnum(ip); + if (n == 0) + ite_clrtoeos(ip); + else if (n == 1) + ite_clrtobos(ip); + else if (n == 2) + ite_clrscreen(ip); + ip->escape = 0; + return; + case 'K': + n = ite_zargnum(ip); + if (n == 0) + ite_clrtoeol(ip); + else if (n == 1) + ite_clrtobol(ip); + else if (n == 2) + ite_clrline(ip); + ip->escape = 0; + return; + case 'X': + n = ite_argnum(ip) - 1; + n = min(n, ip->cols - 1 - ip->curx); + for (; n >= 0; n--) { + attrclr(ip, ip->cury, ip->curx + n, 1, 1); + SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR); + } + ip->escape = 0; + return; + case '}': + case '`': + /* status line control */ + ip->escape = 0; + return; + case 'r': + *ip->ap = 0; + x = atoi(ip->argbuf); + x = x ? x : 1; + y = ip->rows; + cp = index(ip->argbuf, ';'); + if (cp) { + y = atoi(cp + 1); + y = y ? y : ip->rows; + } + if (y - x < 2) { + /* + * if illegal scrolling region, reset + * to defaults + */ + x = 1; + y = ip->rows; + } + x--; + y--; + ip->top_margin = min(x, ip->rows - 1); + ip->bottom_margin = min(y, ip->rows - 1); + if (ip->inside_margins) { + ip->cury = ip->top_margin; + ip->curx = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + } + ip->escape = 0; + return; + case 'm': + /* big attribute setter/resetter */ + { char *cp; + *ip->ap = 0; + /* kludge to make CSIm work (== CSI0m) */ + if (ip->ap == ip->argbuf) + ip->ap++; + for (cp = ip->argbuf; cp < ip->ap;) { + switch (*cp) { + case 0: + case '0': + clr_attr(ip, ATTR_ALL); + cp++; + break; + + case '1': + set_attr(ip, ATTR_BOLD); + cp++; + break; + + case '2': + switch (cp[1]) { + case '2': + clr_attr(ip, ATTR_BOLD); + cp += 2; + break; + + case '4': + clr_attr(ip, ATTR_UL); + cp += 2; + break; + + case '5': + clr_attr(ip, ATTR_BLINK); + cp += 2; + break; + + case '7': + clr_attr(ip, ATTR_INV); + cp += 2; + break; + + default: + cp++; + break; + } + break; + + case '4': + set_attr(ip, ATTR_UL); + cp++; + break; + + case '5': + set_attr(ip, ATTR_BLINK); + cp++; + break; + + case '7': + set_attr(ip, ATTR_INV); + cp++; + break; + + default: + cp++; + break; + } + } + ip->escape = 0; + return; } + case 'u': + /* DECRQTSR */ + ite_sendstr("\033P\033\\"); + ip->escape = 0; + return; + default: + ip->escape = 0; + return; + } + break; + case '?': /* CSI ? */ + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case ';': + case '\"': + case '$': + /* + * Don't fill the last character; + * it's needed. + * XXX yeah, where ?? + */ + if (ip->ap < ip->argbuf + MAX_ARGSIZE - 1) + *ip->ap++ = c; + return; + case 'n': + *ip->ap = 0; + if (ip->ap == &ip->argbuf[2]) { + if (!strncmp(ip->argbuf, "15", 2)) + /* printer status: no printer */ + ite_sendstr("\033[13n"); + + else if (!strncmp(ip->argbuf, "25", 2)) + /* udk status */ + ite_sendstr("\033[20n"); + + else if (!strncmp(ip->argbuf, "26", 2)) + /* keyboard dialect: US */ + ite_sendstr("\033[27;1n"); + } + ip->escape = 0; + return; + case 'h': + case 'l': + n = ite_zargnum(ip); + switch (n) { + case 1: + ip->cursor_appmode = (c == 'h'); + break; + case 3: + /* 132/80 columns (132 == 'h') */ + break; + case 4: /* smooth scroll */ + break; + case 5: + /* + * light background (=='h') /dark + * background(=='l') + */ + break; + case 6: /* origin mode */ + ip->inside_margins = (c == 'h'); + ip->curx = 0; + ip->cury = ip->inside_margins ? + ip->top_margin : 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + break; + case 7: /* auto wraparound */ + ip->auto_wrap = (c == 'h'); + break; + case 8: /* keyboard repeat */ + ip->key_repeat = (c == 'h'); + break; + case 20: /* newline mode */ + ip->linefeed_newline = (c == 'h'); + break; + case 25: /* cursor on/off */ + SUBR_CURSOR(ip, (c == 'h') ? + DRAW_CURSOR : ERASE_CURSOR); + break; + } + ip->escape = 0; + return; + default: + ip->escape = 0; + return; + } + break; + default: + ip->escape = 0; + return; + } + } + switch (c) { + case VT: /* VT is treated like LF */ + case FF: /* so is FF */ + case LF: + /* + * cr->crlf distinction is done here, on output, not on input! + */ + if (ip->linefeed_newline) + ite_crlf(ip); + else + ite_lf(ip); + break; + case CR: + ite_cr(ip); + break; + case BS: + if (--ip->curx < 0) + ip->curx = 0; + else + SUBR_CURSOR(ip, MOVE_CURSOR); + break; + case HT: + for (n = ip->curx + 1; n < ip->cols; n++) { + if (ip->tabs[n]) { + ip->curx = n; + SUBR_CURSOR(ip, MOVE_CURSOR); + break; + } + } + break; + case BEL: + if (kbd_tty && kbd_ite && kbd_ite->tp == kbd_tty) + ite_bell(); + break; + case SO: + ip->GL = ip->G1; + break; + case SI: + ip->GL = ip->G0; + break; + case ENQ: + /* send answer-back message !! */ + break; + case CAN: + ip->escape = 0; /* cancel any escape sequence in progress */ + break; + case SUB: + ip->escape = 0; /* dito, but see below */ + /* should also display a reverse question mark!! */ + break; + case ESC: + ip->escape = ESC; + break; + /* + * now it gets weird.. 8bit control sequences.. + */ + case IND: + /* index: move cursor down, scroll */ + ite_lf(ip); + break; + case NEL: + /* next line. next line, first pos. */ + ite_crlf(ip); + break; + case HTS: + /* set horizontal tab */ + if (ip->curx < ip->cols) + ip->tabs[ip->curx] = 1; + break; + case RI: + /* reverse index */ + ite_rlf(ip); + break; + case SS2: + /* go into G2 for one character */ + /* not yet supported */ + break; + case SS3: + /* go into G3 for one character */ + break; + case DCS: + /* device control string introducer */ + ip->escape = DCS; + ip->ap = ip->argbuf; + break; + case CSI: + /* control sequence introducer */ + ip->escape = CSI; + ip->ap = ip->argbuf; + break; + case ST: + /* string terminator */ + /* ignore, if not used as terminator */ + break; + case OSC: + /* + * introduces OS command. Ignore everything + * upto ST + */ + ip->escape = OSC; + break; + case PM: + /* privacy message, ignore everything upto ST */ + ip->escape = PM; + break; + case APC: + /* + * application program command, ignore * everything upto ST + */ + ip->escape = APC; + break; + default: + if ((c & 0x7f) < ' ' || c == DEL) + break; + if (ip->imode) + ite_inchar(ip, 1); + iteprecheckwrap(ip); +#ifdef DO_WEIRD_ATTRIBUTES + if ((ip->attribute & ATTR_INV) || attrtest(ip, ATTR_INV)) { + attrset(ip, ATTR_INV); + SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_INV); + } else + SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_NOR); +#else + SUBR_PUTC(ip, c, ip->cury, ip->curx, ip->attribute); +#endif + SUBR_CURSOR(ip, DRAW_CURSOR); + itecheckwrap(ip); + break; + } +} + +int +iteprecheckwrap(ip) + struct ite_softc *ip; +{ + if (ip->auto_wrap && ip->curx == ip->cols) { + ip->curx = 0; + clr_attr(ip, ATTR_INV); + if (++ip->cury >= ip->bottom_margin + 1) { + ip->cury = ip->bottom_margin; + SUBR_CURSOR(ip, MOVE_CURSOR); + SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); + ite_clrtoeol(ip); + } else + SUBR_CURSOR(ip, MOVE_CURSOR); + } +} + +int +itecheckwrap(ip) + struct ite_softc *ip; +{ +#if 0 + if (++ip->curx == ip->cols) { + if (ip->auto_wrap) { + ip->curx = 0; + clr_attr(ip, ATTR_INV); + if (++ip->cury >= ip->bottom_margin + 1) { + ip->cury = ip->bottom_margin; + SUBR_CURSOR(ip, MOVE_CURSOR); + SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); + ite_clrtoeol(ip); + return; + } + } else + /* stay there if no autowrap.. */ + ip->curx--; + } +#else + if (ip->curx < ip->cols) { + ip->curx++; + SUBR_CURSOR(ip, MOVE_CURSOR); + } +#endif +} |