NetBSD/sys/arch/x68k/dev/ite.c
jdolecek e0cc03a09b merge kqueue branch into -current
kqueue provides a stateful and efficient event notification framework
currently supported events include socket, file, directory, fifo,
pipe, tty and device changes, and monitoring of processes and signals

kqueue is supported by all writable filesystems in NetBSD tree
(with exception of Coda) and all device drivers supporting poll(2)

based on work done by Jonathan Lemon for FreeBSD
initial NetBSD port done by Luke Mewburn and Jason Thorpe
2002-10-23 09:10:23 +00:00

2521 lines
51 KiB
C

/* $NetBSD: ite.c,v 1.33 2002/10/23 09:12:44 jdolecek 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 "ite.h"
#if NITE > 0
#include "bell.h"
#include "kbd.h"
#include "opt_ite.h"
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/proc.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/cpu.h>
#include <machine/kbio.h>
#include <machine/bus.h>
#include <machine/grfioctl.h>
#include <machine/iteioctl.h>
#include <arch/x68k/dev/grfvar.h>
#include <arch/x68k/dev/itevar.h>
#include <arch/x68k/dev/kbdmap.h>
#include <arch/x68k/dev/mfp.h>
#if NBELL > 0
void opm_bell __P((void));
#endif
#define SUBR_CNPROBE(min) itesw[min].ite_cnprobe(min)
#define SUBR_INIT(ip) ip->isw->ite_init(ip)
#define SUBR_DEINIT(ip) ip->isw->ite_deinit(ip)
#define SUBR_PUTC(ip,c,dy,dx,m) ip->isw->ite_putc(ip,c,dy,dx,m)
#define SUBR_CURSOR(ip,flg) ip->isw->ite_cursor(ip,flg)
#define SUBR_CLEAR(ip,sy,sx,h,w) ip->isw->ite_clear(ip,sy,sx,h,w)
#define SUBR_SCROLL(ip,sy,sx,count,dir) \
ip->isw->ite_scroll(ip,sy,sx,count,dir)
struct consdev;
__inline static void itesendch __P((int));
__inline static void alignment_display __P((struct ite_softc *));
__inline static void snap_cury __P((struct ite_softc *));
__inline static void ite_dnchar __P((struct ite_softc *, int));
static void ite_inchar __P((struct ite_softc *, int));
__inline static void ite_clrtoeol __P((struct ite_softc *));
__inline static void ite_clrtobol __P((struct ite_softc *));
__inline static void ite_clrline __P((struct ite_softc *));
__inline static void ite_clrtoeos __P((struct ite_softc *));
__inline static void ite_clrtobos __P((struct ite_softc *));
__inline static void ite_clrscreen __P((struct ite_softc *));
__inline static void ite_dnline __P((struct ite_softc *, int));
__inline static void ite_inline __P((struct ite_softc *, int));
__inline static void ite_index __P((struct ite_softc *));
__inline static void ite_lf __P((struct ite_softc *));
__inline static void ite_crlf __P((struct ite_softc *));
__inline static void ite_cr __P((struct ite_softc *));
__inline static void ite_rlf __P((struct ite_softc *));
static void iteprecheckwrap __P((struct ite_softc *ip));
static void itecheckwrap __P((struct ite_softc *ip));
static int ite_argnum __P((struct ite_softc *ip));
static int ite_zargnum __P((struct ite_softc *ip));
static void ite_sendstr __P((struct ite_softc *ip, char *str));
__inline static int atoi __P((const char *cp));
__inline static char *index __P((const char *cp, char ch));
void ite_reset __P((struct ite_softc *ip));
struct ite_softc *getitesp __P((dev_t));
int iteon __P((dev_t, int));
void iteoff __P((dev_t, int));
struct itesw itesw[] = {
{0, tv_init, tv_deinit, 0,
0, 0, 0}
};
int nitesw = sizeof(itesw) / sizeof(itesw[0]);
/*
* # of chars are output in a single itestart() call.
* If this is too big, user processes will be blocked out for
* long periods of time while we are emptying the queue in itestart().
* If it is too small, console output will be very ragged.
*/
#define ITEBURST 64
int nite = NITE;
struct tty *ite_tty[NITE];
struct ite_softc *kbd_ite = NULL;
struct ite_softc con_itesoftc;
struct tty *kbd_tty = NULL;
int start_repeat_timeo = 20; /* /100: initial timeout till pressed key repeats */
int next_repeat_timeo = 3; /* /100: timeout when repeating for next char */
u_char cons_tabs[MAX_TABS];
void itestart __P((struct tty *tp));
void iteputchar __P((int c, struct ite_softc *ip));
void ite_putstr __P((const u_char * s, int len, dev_t dev));
void iteattach __P((struct device *, struct device *, void *));
int itematch __P((struct device *, struct cfdata *, void *));
CFATTACH_DECL(ite, sizeof(struct ite_softc),
itematch, iteattach, NULL, NULL);
extern struct cfdriver ite_cd;
dev_type_open(iteopen);
dev_type_close(iteclose);
dev_type_read(iteread);
dev_type_write(itewrite);
dev_type_ioctl(iteioctl);
dev_type_tty(itetty);
dev_type_poll(itepoll);
const struct cdevsw ite_cdevsw = {
iteopen, iteclose, iteread, itewrite, iteioctl,
nostop, itetty, itepoll, nommap, ttykqfilter, D_TTY
};
int
itematch(pdp, cdp, auxp)
struct device *pdp;
struct cfdata *cdp;
void *auxp;
{
struct grf_softc *gp;
#if 0
int maj;
#endif
gp = auxp;
/* ite0 should be at grf0 XXX */
if(cdp->cf_unit != gp->g_device.dv_unit)
return(0);
#if 0
/*
* 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.
*/
maj = cdevsw_lookup_major(&ite_cdevsw);
gp->g_itedev = makedev(maj, cdp->cf_unit);
#endif
return(1);
}
/*
* iteinit() is the standard entry point for initialization of
* an ite device, it is also called from ite_cninit().
*/
void
iteattach(pdp, dp, auxp)
struct device *pdp, *dp;
void *auxp;
{
struct ite_softc *ip;
struct grf_softc *gp;
gp = (struct grf_softc *)auxp;
if (dp) {
ip = (struct ite_softc *)dp;
if(con_itesoftc.grf != NULL
/*&& con_itesoftc.grf->g_unit == gp->g_unit*/) {
/*
* console reinit copy params over.
* and console always gets keyboard
*/
memcpy(&ip->grf, &con_itesoftc.grf,
(char *)&ip[1] - (char *)&ip->grf);
con_itesoftc.grf = NULL;
kbd_ite = ip;
}
ip->grf = gp;
iteinit(ip->device.dv_unit); /* XXX */
printf(": rows %d cols %d", ip->rows, ip->cols);
if (kbd_ite == NULL)
kbd_ite = ip;
printf("\n");
} else {
if (con_itesoftc.grf != NULL)
return;
con_itesoftc.grf = gp;
con_itesoftc.tabs = cons_tabs;
}
}
struct ite_softc *
getitesp(dev)
dev_t dev;
{
extern int x68k_realconfig;
if (x68k_realconfig && con_itesoftc.grf == NULL)
return(ite_cd.cd_devs[UNIT(dev)]);
if (con_itesoftc.grf == NULL)
panic("no ite_softc for console");
return(&con_itesoftc);
}
void
iteinit(dev)
dev_t dev;
{
struct ite_softc *ip;
ip = getitesp(dev);
if (ip->flags & ITE_INITED)
return;
memcpy(&kbdmap, &ascii_kbdmap, sizeof(struct kbdmap));
ip->curx = 0;
ip->cury = 0;
ip->cursorx = 0;
ip->cursory = 0;
ip->isw = &itesw[ip->device.dv_unit]; /* XXX */
SUBR_INIT(ip);
SUBR_CURSOR(ip, DRAW_CURSOR);
if (!ip->tabs)
ip->tabs = malloc(MAX_TABS*sizeof(u_char), M_DEVBUF, M_WAITOK);
ite_reset(ip);
ip->flags |= ITE_INITED;
}
/*
* Perform functions necessary to setup device as a terminal emulator.
*/
int
iteon(dev, flag)
dev_t dev;
int flag;
{
int unit = UNIT(dev);
struct ite_softc *ip;
if (unit < 0 || unit >= ite_cd.cd_ndevs ||
(ip = getitesp(unit)) == NULL || (ip->flags&ITE_ALIVE) == 0)
return(ENXIO);
/* 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);
if (flag & 2)
ite_reset(ip);
#if NKBD > 0
mfp_send_usart (0x49); /* XXX */
#endif
return(0);
}
/*
* "Shut down" device as terminal emulator.
* Note that we do not deinit the console device unless forced.
* Deinit'ing the console every time leads to a very active
* screen when processing /etc/rc.
*/
void
iteoff(dev, flag)
dev_t dev;
int flag;
{
int unit = UNIT(dev);
register struct ite_softc *ip;
/* XXX check whether when call from grf.c */
if (unit < 0 || unit >= ite_cd.cd_ndevs ||
(ip = getitesp(unit)) == NULL || (ip->flags&ITE_ALIVE) == 0)
return;
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);
/*
* XXX When the system is rebooted with "reboot", init(8)
* kills the last process to have the console open.
* If we don't revent the the ITE_ACTIVE bit from being
* cleared, we will never see messages printed during
* the process of rebooting.
*/
if ((flag & 2) == 0 && (ip->flags & ITE_ISCONS) == 0) {
ip->flags &= ~ITE_ACTIVE;
#if NKBD > 0
mfp_send_usart (0x48); /* XXX */
#endif
}
}
/*
* standard entry points to the device.
*/
/* ARGSUSED */
int
iteopen(dev, mode, devtype, p)
dev_t dev;
int mode, devtype;
struct proc *p;
{
int unit = UNIT(dev);
register struct tty *tp;
register struct ite_softc *ip;
register int error;
int first = 0;
if (unit >= ite_cd.cd_ndevs || (ip = getitesp(dev)) == NULL)
return (ENXIO);
if (!ite_tty[unit]) {
tp = ite_tty[unit] = ttymalloc();
tty_attach(tp);
} else
tp = ite_tty[unit];
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 = iteon(dev, 0);
if (error)
return (error);
first = 1;
}
tp->t_oproc = itestart;
tp->t_param = NULL;
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_ISOPEN|TS_CARR_ON;
ttsetwater(tp);
}
error = (*tp->t_linesw->l_open)(dev, tp);
if (error == 0) {
tp->t_winsize.ws_row = ip->rows;
tp->t_winsize.ws_col = ip->cols;
} else if (first)
iteoff(dev, 0);
return (error);
}
/*ARGSUSED*/
int
iteclose(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
register struct tty *tp = ite_tty[UNIT(dev)];
(*tp->t_linesw->l_close)(tp, flag);
ttyclose(tp);
iteoff(dev, 0);
#if 0
ttyfree(tp);
ite_tty[UNIT(dev)] = (struct tty *)0;
#endif
return(0);
}
int
iteread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
register struct tty *tp = ite_tty[UNIT(dev)];
return ((*tp->t_linesw->l_read)(tp, uio, flag));
}
int
itewrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
register struct tty *tp = ite_tty[UNIT(dev)];
return ((*tp->t_linesw->l_write)(tp, uio, flag));
}
int
itepoll(dev, events, p)
dev_t dev;
int events;
struct proc *p;
{
register struct tty *tp = ite_tty[UNIT(dev)];
return ((*tp->t_linesw->l_poll)(tp, events, p));
}
struct tty *
itetty(dev)
dev_t dev;
{
return (ite_tty[UNIT(dev)]);
}
int
iteioctl(dev, cmd, addr, flag, p)
dev_t dev;
u_long cmd;
caddr_t addr;
int flag;
struct proc *p;
{
struct iterepeat *irp;
register struct tty *tp = ite_tty[UNIT(dev)];
int error;
error = (*tp->t_linesw->l_ioctl)(tp, cmd, addr, flag, p);
if (error != EPASSTHROUGH)
return (error);
error = ttioctl(tp, cmd, addr, flag, p);
if (error != EPASSTHROUGH)
return (error);
switch (cmd) {
case ITEIOCSKMAP:
if (addr == 0)
return(EFAULT);
memcpy(&kbdmap, addr, sizeof(struct kbdmap));
return(0);
case ITEIOCGKMAP:
if (addr == NULL)
return(EFAULT);
memcpy(addr, &kbdmap, sizeof(struct kbdmap));
return(0);
case ITEIOCGREPT:
irp = (struct iterepeat *)addr;
irp->start = start_repeat_timeo;
irp->next = next_repeat_timeo;
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;
#if x68k
case ITELOADFONT:
if (addr) {
memcpy(kern_font, addr, 4096 /*sizeof (kernel_font)*/);
ite_set_glyph();
return 0;
} else
return EFAULT;
case ITETVCTRL:
if (addr && *(u_int8_t *)addr < 0x40) {
return mfp_send_usart (* (u_int8_t *)addr);
} else {
return EFAULT;
}
#endif
}
return (EPASSTHROUGH);
}
void
itestart(tp)
register struct tty *tp;
{
struct clist *rbp;
struct ite_softc *ip;
u_char buf[ITEBURST];
int s, len;
ip = getitesp(tp->t_dev);
/*
* (Potentially) lower priority. We only need to protect ourselves
* from keyboard interrupts since that is all that can affect the
* state of our tty (kernel printf doesn't go through this routine).
*/
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;
callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, tp);
}
/* 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);
}
/* 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;
int unit = UNIT(dev);
/* XXX check whether when call from grf.c */
if (unit < 0 || unit >= ite_cd.cd_ndevs ||
(ip = getitesp(unit)) == NULL)
return;
ip->flags &= ~ITE_INITED;
iteinit(dev);
}
void
ite_reset(ip)
struct ite_softc *ip;
{
int i;
ip->curx = 0;
ip->cury = 0;
ip->attribute = 0;
ip->save_curx = 0;
ip->save_cury = 0;
ip->save_attribute = 0;
ip->ap = ip->argbuf;
ip->emul_level = EMUL_VT300_8;
ip->eightbit_C1 = 0;
ip->top_margin = 0;
ip->bottom_margin = ip->rows - 1;
ip->inside_margins = 0; /* origin mode == absolute */
ip->linefeed_newline = 0;
ip->auto_wrap = 1;
ip->cursor_appmode = 0;
ip->keypad_appmode = 0;
ip->imode = 0;
ip->key_repeat = 1;
ip->G0 = CSET_ASCII;
ip->G1 = CSET_JIS1983;
ip->G2 = CSET_JISKANA;
ip->G3 = CSET_JIS1990;
ip->GL = &ip->G0;
ip->GR = &ip->G1;
ip->save_GL = 0;
ip->save_char = 0;
ip->fgcolor = 7;
ip->bgcolor = 0;
for (i = 0; i < ip->cols; i++)
ip->tabs[i] = ((i & 7) == 0);
/* XXX clear screen */
SUBR_CLEAR(ip, 0, 0, ip->rows, ip->cols);
attrclr(ip, 0, 0, ip->rows, ip->cols);
}
/* Used in console at startup only */
int
ite_cnfilter(c)
u_char c;
{
static u_char mod = 0;
struct key key;
u_char code, up, mask;
int s;
up = c & 0x80 ? 1 : 0;
c &= 0x7f;
code = 0;
s = spltty();
mask = 0;
if (c >= KBD_LEFT_ALT && !(c >= 0x63 && c <= 0x6c)) { /* 0x63: F1, 0x6c:F10 */
switch (c) {
case KBD_LEFT_SHIFT:
mask = KBD_MOD_SHIFT;
break;
case KBD_LEFT_ALT:
mask = KBD_MOD_LALT;
break;
case KBD_RIGHT_ALT:
mask = KBD_MOD_RALT;
break;
case KBD_LEFT_META:
mask = KBD_MOD_LMETA;
break;
case KBD_RIGHT_META:
mask = KBD_MOD_RMETA;
break;
case KBD_CAPS_LOCK:
/*
* capslock already behaves `right', don't need to
* keep track of the state in here.
*/
mask = KBD_MOD_CAPS;
break;
case KBD_CTRL:
mask = KBD_MOD_CTRL;
break;
case KBD_RECONNECT:
/* ite got 0xff */
if (up)
kbd_setLED();
break;
}
if (mask & KBD_MOD_CAPS) {
if (!up) {
mod ^= KBD_MOD_CAPS;
kbdled ^= LED_CAPS_LOCK;
kbd_setLED();
}
} else if (up)
mod &= ~mask;
else mod |= mask;
splx (s);
return -1;
}
if (up) {
splx(s);
return -1;
}
/* translate modifiers */
if (mod & KBD_MOD_SHIFT) {
if (mod & KBD_MOD_ALT)
key = kbdmap.alt_shift_keys[c];
else
key = kbdmap.shift_keys[c];
} else if (mod & KBD_MOD_ALT)
key = kbdmap.alt_keys[c];
else {
key = kbdmap.keys[c];
/* if CAPS and key is CAPable (no pun intended) */
if ((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) {
splx(s);
return -1;
}
if (mod & KBD_MOD_CTRL)
code &= 0x1f;
if (mod & KBD_MOD_META)
code |= 0x80;
/* do console mapping. */
code = code == '\r' ? '\n' : code;
splx(s);
return (code);
}
/* And now the old stuff. */
__inline static void
itesendch (ch)
int ch;
{
(*kbd_tty->t_linesw->l_rint)(ch, kbd_tty);
}
void
ite_filter(c)
u_char c;
{
static u_short mod = 0;
register unsigned char code, *str;
u_short up, mask;
struct key key;
int s, i;
if (!kbd_ite || !(kbd_tty = ite_tty[kbd_ite->device.dv_unit]))
return;
/* have to make sure we're at spltty in here */
s = spltty ();
up = c & 0x80 ? 1 : 0;
c &= 0x7f;
code = 0;
mask = 0;
if (c >= KBD_LEFT_ALT &&
!(c >= 0x63 && c <= 0x6c)) { /* 0x63: F1, 0x6c:F10 */
switch (c) {
case KBD_LEFT_SHIFT:
mask = KBD_MOD_SHIFT;
break;
case KBD_LEFT_ALT:
mask = KBD_MOD_LALT;
break;
case KBD_RIGHT_ALT:
mask = KBD_MOD_RALT;
break;
case KBD_LEFT_META:
mask = KBD_MOD_LMETA;
break;
case KBD_RIGHT_META:
mask = KBD_MOD_RMETA;
break;
case KBD_CAPS_LOCK:
/*
* capslock already behaves `right', don't need to keep
* track of the state in here.
*/
mask = KBD_MOD_CAPS;
break;
case KBD_CTRL:
mask = KBD_MOD_CTRL;
break;
case KBD_OPT1:
mask = KBD_MOD_OPT1;
break;
case KBD_OPT2:
mask = KBD_MOD_OPT2;
break;
case KBD_RECONNECT:
if (up) { /* ite got 0xff */
kbd_setLED();
}
break;
}
if (mask & KBD_MOD_CAPS) {
if (!up) {
mod ^= KBD_MOD_CAPS;
kbdled ^= LED_CAPS_LOCK;
kbd_setLED();
}
} else if (up) {
mod &= ~mask;
} else mod |= mask;
/*
* return even if it wasn't a modifier key, the other
* codes up here are either special (like reset warning),
* or not yet defined
*/
splx (s);
return;
}
if (up) {
splx (s);
return;
}
/*
* intercept LAlt-LMeta-F1 here to switch back to original ascii-keymap.
* this should probably be configurable..
*/
if (mod == (KBD_MOD_LALT|KBD_MOD_LMETA) && c == 0x63) {
memcpy(&kbdmap, &ascii_kbdmap, sizeof(struct kbdmap));
splx (s);
return;
}
/* translate modifiers */
if (mod & KBD_MOD_SHIFT) {
if (mod & KBD_MOD_ALT)
key = kbdmap.alt_shift_keys[c];
else
key = kbdmap.shift_keys[c];
} else if (mod & KBD_MOD_ALT)
key = kbdmap.alt_keys[c];
else {
key = kbdmap.keys[c];
/* if CAPS and key is CAPable (no pun intended) */
if ((mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS))
key = kbdmap.shift_keys[c];
else if ((mod & KBD_MOD_OPT2) && (key.mode & KBD_MODE_KPAD))
key = kbdmap.shift_keys[c];
}
code = key.code;
/* handle dead keys */
if (key.mode & KBD_MODE_DEAD) {
splx (s);
return;
}
/* 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 ((mod & KBD_MOD_CTRL) &&
(code == ' ' || (code >= '@' && code <= 'z')))
code &= 0x1f;
if (mod & KBD_MOD_META)
code |= 0x80;
} else if ((key.mode & KBD_MODE_KPAD) &&
(kbd_ite && kbd_ite->keypad_appmode)) {
static char *in = "0123456789-+.\r()/*";
static char *out = "pqrstuvwxymlnMPQRS";
char *cp = index (in, code);
/*
* keypad-appmode sends SS3 followed by the above
* translated character
*/
(*kbd_tty->t_linesw->l_rint) (27, kbd_tty);
(*kbd_tty->t_linesw->l_rint) ('O', kbd_tty);
(*kbd_tty->t_linesw->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 >= 0x3b && c <= 0x3e && kbd_ite->cursor_appmode
&& !memcmp(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--)
(*kbd_tty->t_linesw->l_rint) (*str++, kbd_tty);
splx(s);
return;
}
(*kbd_tty->t_linesw->l_rint)(code, kbd_tty);
splx(s);
return;
}
/* helper functions, makes the code below more readable */
__inline static void
ite_sendstr (ip, str)
struct ite_softc *ip;
char *str;
{
while (*str)
itesendch (*str++);
}
__inline 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);
}
__inline static void
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;
}
}
__inline static void
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);
}
static void
ite_inchar(ip, n)
struct ite_softc *ip;
int n;
{
int c = ip->save_char;
ip->save_char = 0;
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);
ip->save_char = c;
}
__inline static void
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);
}
}
__inline static void
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);
}
__inline static void
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);
}
__inline static void
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);
}
}
__inline static void
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);
}
}
__inline static void
ite_clrscreen(ip)
struct ite_softc *ip;
{
SUBR_CLEAR(ip, 0, 0, ip->rows, ip->cols);
attrclr(ip, 0, 0, ip->rows, ip->cols);
}
__inline static void
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);
}
__inline static void
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;
if (n <= 0)
n = 1;
else 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);
ip->curx = 0;
}
__inline static void
ite_index (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);
}
/*clr_attr(ip, ATTR_INV);*/
}
__inline static void
ite_lf (ip)
struct ite_softc *ip;
{
++ip->cury;
if (ip->cury > ip->bottom_margin) {
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);*/
/* reset character set ... thanks for mohta. */
ip->G0 = CSET_ASCII;
ip->G1 = CSET_JIS1983;
ip->G2 = CSET_JISKANA;
ip->G3 = CSET_JIS1990;
ip->GL = &ip->G0;
ip->GR = &ip->G1;
ip->save_GL = 0;
ip->save_char = 0;
}
__inline static void
ite_crlf (ip)
struct ite_softc *ip;
{
ip->curx = 0;
ite_lf (ip);
}
__inline static void
ite_cr (ip)
struct ite_softc *ip;
{
if (ip->curx) {
ip->curx = 0;
}
}
__inline static void
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);
}
clr_attr(ip, ATTR_INV);
}
__inline static int
atoi (cp)
const char *cp;
{
int n;
for (n = 0; *cp && *cp >= '0' && *cp <= '9'; cp++)
n = n * 10 + *cp - '0';
return n;
}
__inline static char *
index(cp, ch)
const char *cp;
char ch;
{
while (*cp && *cp != ch)
cp++;
return *cp ? (char *) cp : 0;
}
__inline static int
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;
}
__inline static int
ite_zargnum (ip)
struct ite_softc *ip;
{
char ch;
int n;
/* convert argument string into number */
if (ip->ap == ip->argbuf)
return 0;
ch = *ip->ap;
*ip->ap = 0; /* terminate string */
n = atoi (ip->argbuf);
*ip->ap = ch;
return n; /* don't "n ? n : 1" here, <CSI>0m != <CSI>1m ! */
}
void
ite_putstr(s, len, dev)
const u_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;
{
int n, x, y;
char *cp;
if (c >= 0x20 && ip->escape) {
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':
/* next line */
c = NEL;
ip->escape = 0;
break;
case 'H':
/* set TAB at current col */
c = HTS;
ip->escape = 0;
break;
case 'M':
/* reverse index */
c = RI;
ip->escape = 0;
break;
case 'N':
/* single shift G2 */
c = SS2;
ip->escape = 0;
break;
case 'O':
/* single shift G3 */
c = SS3;
ip->escape = 0;
break;
case 'P':
/* DCS detected */
c = DCS;
ip->escape = 0;
break;
case '[':
c = CSI;
ip->escape = 0;
break;
case '\\':
/* String Terminator */
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;
/* 94-multibyte character sets designate */
case '$':
ip->escape = '$';
return;
/* locking shift modes */
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 '~':
ip->GR = &ip->G1;
ip->escape = 0;
return;
/* font width/height control */
case '#':
ip->escape = '#';
return;
case 'c':
/* hard terminal reset .. */
ite_reset (ip);
SUBR_CURSOR(ip, MOVE_CURSOR);
ip->escape = 0;
return;
case '7':
/* save cursor */
ip->save_curx = ip->curx;
ip->save_cury = ip->cury;
ip->save_attribute = ip->attribute;
ip->sc_om = ip->inside_margins;
ip->sc_G0 = ip->G0;
ip->sc_G1 = ip->G1;
ip->sc_G2 = ip->G2;
ip->sc_G3 = ip->G3;
ip->sc_GL = ip->GL;
ip->sc_GR = ip->GR;
ip->escape = 0;
return;
case '8':
/* restore cursor */
ip->curx = ip->save_curx;
ip->cury = ip->save_cury;
ip->attribute = ip->save_attribute;
ip->inside_margins = ip->sc_om;
ip->G0 = ip->sc_G0;
ip->G1 = ip->sc_G1;
ip->G2 = ip->sc_G2;
ip->G3 = ip->sc_G3;
ip->GL = ip->sc_GL;
ip->GR = ip->sc_GR;
SUBR_CURSOR(ip, MOVE_CURSOR);
ip->escape = 0;
return;
case '=':
/* keypad application mode */
ip->keypad_appmode = 1;
ip->escape = 0;
return;
case '>':
/* keypad numeric mode */
ip->keypad_appmode = 0;
ip->escape = 0;
return;
case 'Z': /* request ID */
if (ip->emul_level == EMUL_VT100)
ite_sendstr (ip, "\033[61;0c"); /* XXX not clean */
else
ite_sendstr (ip, "\033[63;0c"); /* XXX not clean */
ip->escape = 0;
return;
/* default catch all for not recognized ESC sequences */
default:
ip->escape = 0;
return;
}
break;
case '(': /* designate G0 */
switch (c) {
case 'B': /* USASCII */
ip->G0 = CSET_ASCII;
ip->escape = 0;
return;
case 'I':
ip->G0 = CSET_JISKANA;
ip->escape = 0;
return;
case 'J':
ip->G0 = CSET_JISROMA;
ip->escape = 0;
return;
case 'A': /* British or ISO-Latin-1 */
case 'H': /* Swedish */
case 'K': /* German */
case 'R': /* French */
case 'Y': /* Italian */
case 'Z': /* Spanish */
default:
/* not supported */
ip->escape = 0;
return;
}
case ')': /* designate G1 */
ip->escape = 0;
return;
case '$': /* 94-multibyte character set */
switch (c) {
case '@':
ip->G0 = CSET_JIS1978;
ip->escape = 0;
return;
case 'B':
ip->G0 = CSET_JIS1983;
ip->escape = 0;
return;
case 'D':
ip->G0 = CSET_JIS1990;
ip->escape = 0;
return;
default:
/* not supported */
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 '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':
/* device attributes */
*ip->ap = 0;
if (ip->argbuf[0] == '>') {
ite_sendstr (ip, "\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 (ip, "\033[?1;1c");
else
ite_sendstr (ip, "\033[63;0c");
break;
}
ip->escape = 0;
return;
case 'n':
switch (ite_zargnum(ip)) {
case 5:
ite_sendstr (ip, "\033[0n"); /* no malfunction */
break;
case 6:
/* cursor position report */
sprintf (ip->argbuf, "\033[%d;%dR",
ip->cury + 1, ip->curx + 1);
ite_sendstr (ip, ip->argbuf);
break;
}
ip->escape = 0;
return;
case 'x':
switch (ite_zargnum(ip)) {
case 0:
/* Fake some terminal parameters. */
ite_sendstr (ip, "\033[2;1;1;112;112;1;0x");
break;
case 1:
ite_sendstr (ip, "\033[3;1;1;112;112;1;0x");
break;
}
ip->escape = 0;
return;
case 'g':
/* clear tabs */
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;
default:
/* ignore */
break;
}
ip->escape = 0;
return;
case 'h': /* set mode */
case 'l': /* reset mode */
n = ite_zargnum (ip);
switch (n) {
case 4:
ip->imode = (c == 'h'); /* insert/replace mode */
break;
case 20:
ip->linefeed_newline = (c == 'h');
break;
}
ip->escape = 0;
return;
case 'M':
/* delete line */
ite_dnline (ip, ite_argnum (ip));
ip->escape = 0;
return;
case 'L':
/* insert line */
ite_inline (ip, ite_argnum (ip));
ip->escape = 0;
return;
case 'P':
/* delete char */
ite_dnchar (ip, ite_argnum (ip));
ip->escape = 0;
return;
case '@':
/* insert char(s) */
ite_inchar (ip, ite_argnum (ip));
ip->escape = 0;
return;
case '!':
/* soft terminal reset */
ip->escape = 0; /* XXX */
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':
/* cursor up */
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':
/* cursor down */
n = ite_argnum (ip);
n = ip->cury + (n ? n : 1);
n = min(ip->rows - 1, n);
#if 0
if (ip->inside_margins)
#endif
n = min(ip->bottom_margin, n);
#if 0
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;
#endif
ip->cury = n;
ip->escape = 0;
SUBR_CURSOR(ip, MOVE_CURSOR);
clr_attr (ip, ATTR_INV);
return;
case 'C':
/* cursor forward */
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':
/* cursor backward */
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':
/* erase screen */
*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':
/* erase line */
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 'S':
/* scroll up */
n = ite_zargnum (ip);
if (n <= 0)
n = 1;
else if (n > ip->rows-1)
n = ip->rows-1;
SUBR_SCROLL(ip, ip->rows-1, 0, n, SCROLL_UP);
ip->escape = 0;
return;
case 'T':
/* scroll down */
n = ite_zargnum (ip);
if (n <= 0)
n = 1;
else if (n > ip->rows-1)
n = ip->rows-1;
SUBR_SCROLL(ip, 0, 0, n, SCROLL_DOWN);
ip->escape = 0;
return;
case 'X':
/* erase character */
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':
/* set scrolling region */
ip->escape = 0;
*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)
return;
x--;
y--;
ip->top_margin = min(x, ip->rows - 2);
ip->bottom_margin = min(y, ip->rows - 1);
if (ip->inside_margins) {
ip->cury = ip->top_margin;
} else
ip->cury = 0;
ip->curx = 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);
ip->fgcolor = 7;
ip->bgcolor = 0;
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 '3':
switch (cp[1]) {
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
/* foreground colors */
ip->fgcolor = cp[1] - '0';
cp += 2;
break;
default:
cp++;
break;
}
break;
case '4':
switch (cp[1]) {
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
/* background colors */
ip->bgcolor = cp[1] - '0';
cp += 2;
break;
default:
set_attr (ip, ATTR_UL);
cp++;
break;
}
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 (ip, "\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':
/* Terminal Reports */
*ip->ap = 0;
if (ip->ap == &ip->argbuf[2]) {
if (!strncmp(ip->argbuf, "15", 2))
/* printer status: no printer */
ite_sendstr (ip, "\033[13n");
else if (!strncmp(ip->argbuf, "25", 2))
/* udk status */
ite_sendstr (ip, "\033[20n");
else if (!strncmp(ip->argbuf, "26", 2))
/* keyboard dialect: US */
ite_sendstr (ip, "\033[27;1n");
}
ip->escape = 0;
return;
case 'h': /* set dec private modes */
case 'l': /* reset dec private modes */
n = ite_zargnum (ip);
switch (n) {
case 1:
/* CKM - cursor key mode */
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');
#if 0
ip->curx = 0;
ip->cury = ip->inside_margins ? ip->top_margin : 0;
SUBR_CURSOR(ip, MOVE_CURSOR);
#endif
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;
case 'K':
/* selective erase in line */
case 'J':
/* selective erase in display */
default:
ip->escape = 0;
return;
}
break;
default:
ip->escape = 0;
return;
}
}
switch (c) {
case 0x00: /* NUL */
case 0x01: /* SOH */
case 0x02: /* STX */
case 0x03: /* ETX */
case 0x04: /* EOT */
case 0x05: /* ENQ */
case 0x06: /* ACK */
break;
case BEL:
#if NBELL > 0
if (kbd_ite && ite_tty[kbd_ite->device.dv_unit])
opm_bell();
#endif
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 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 SO:
ip->GL = &ip->G1;
break;
case SI:
ip->GL = &ip->G0;
break;
case 0x10: /* DLE */
case 0x11: /* DC1/XON */
case 0x12: /* DC2 */
case 0x13: /* DC3/XOFF */
case 0x14: /* DC4 */
case 0x15: /* NAK */
case 0x16: /* SYN */
case 0x17: /* ETB */
break;
case CAN:
ip->escape = 0; /* cancel any escape sequence in progress */
break;
case 0x19: /* EM */
break;
case SUB:
ip->escape = 0; /* dito, but see below */
/* should also display a reverse question mark!! */
break;
case ESC:
ip->escape = ESC;
break;
case 0x1c: /* FS */
case 0x1d: /* GS */
case 0x1e: /* RS */
case 0x1f: /* US */
break;
/* now it gets weird.. 8bit control sequences.. */
case IND: /* index: move cursor down, scroll */
ite_index (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 */
ip->save_GL = ip->GR; /* GL XXX EUC */
ip->GR = &ip->G2; /* GL XXX */
break;
case SS3: /* go into G3 for one character */
ip->save_GL = ip->GR; /* GL XXX EUC */
ip->GR = &ip->G3; /* GL XXX */
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;
case DEL:
break;
default:
if (!ip->save_char && (*((c & 0x80) ? ip->GR : ip->GL) & CSET_MULTI)) {
ip->save_char = c;
break;
}
if (ip->imode)
ite_inchar(ip, ip->save_char ? 2 : 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);
if (ip->save_char) {
itecheckwrap(ip);
ip->save_char = 0;
}
if (ip->save_GL) {
/*
* reset single shift
*/
ip->GR = ip->save_GL;
ip->save_GL = 0;
}
break;
}
}
static void
iteprecheckwrap(ip)
struct ite_softc *ip;
{
if (ip->auto_wrap && ip->curx + (ip->save_char ? 1 : 0) == 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);*/
}
}
static void
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
}
#endif
#if NITE > 0 && NKBD > 0
/*
* Console functions
*/
#include <dev/cons.h>
extern void kbdenable __P((int));
extern int kbdcngetc __P((void));
/*
* 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;
{
int maj;
/* locate the major number */
maj = cdevsw_lookup_major(&ite_cdevsw);
/*
* return priority of the best ite (already picked from attach)
* or CN_DEAD.
*/
if (con_itesoftc.grf == NULL)
cd->cn_pri = CN_DEAD;
else {
con_itesoftc.flags = (ITE_ALIVE|ITE_CONSOLE);
/*
* hardcode the minor number.
* currently we support only one ITE, it is enough for now.
*/
con_itesoftc.isw = &itesw[0];
cd->cn_pri = CN_INTERNAL;
cd->cn_dev = makedev(maj, 0);
}
}
void
itecninit(cd)
struct consdev *cd;
{
struct ite_softc *ip;
ip = getitesp(cd->cn_dev);
iteinit(cd->cn_dev); /* init console unit */
ip->flags |= ITE_ACTIVE | ITE_ISCONS;
kbdenable(0);
mfp_send_usart(0x49);
}
/*
* itecnfinish() 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
itecnfinish(ip)
struct ite_softc *ip;
{
static int done;
if (done)
return;
done = 1;
}
/*ARGSUSED*/
int
itecngetc(dev)
dev_t dev;
{
register int c;
do {
c = kbdcngetc();
c = ite_cnfilter(c);
} while (c == -1);
return (c);
}
void
itecnputc(dev, c)
dev_t dev;
int c;
{
static int paniced = 0;
struct ite_softc *ip = getitesp(dev);
char ch = c;
#ifdef ITE_KERNEL_ATTR
short save_attribute;
#endif
if (panicstr && !paniced &&
(ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE) {
(void) iteon(dev, 3);
paniced = 1;
}
#ifdef ITE_KERNEL_ATTR
save_attribute = ip->attribute;
ip->attribute = ITE_KERNEL_ATTR;
#endif
ite_putstr(&ch, 1, dev);
#ifdef ITE_KERNEL_ATTR
ip->attribute = save_attribute;
#endif
}
#endif