summaryrefslogtreecommitdiff
path: root/sys/dev/wscons/wscons.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/wscons/wscons.c')
-rw-r--r--sys/dev/wscons/wscons.c495
1 files changed, 495 insertions, 0 deletions
diff --git a/sys/dev/wscons/wscons.c b/sys/dev/wscons/wscons.c
new file mode 100644
index 00000000000..2845895227d
--- /dev/null
+++ b/sys/dev/wscons/wscons.c
@@ -0,0 +1,495 @@
+/* $NetBSD: wscons.c,v 1.3.4.1 1996/06/03 18:54:35 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/termios.h>
+
+#include <dev/cons.h>
+#include <alpha/wscons/wsconsvar.h>
+#include <alpha/wscons/wscons_emul.h>
+#include <machine/wsconsio.h>
+
+cdev_decl(wscons);
+
+/* Macros to clear/set/test flags. */
+#define SET(t, f) (t) |= (f)
+#define CLR(t, f) (t) &= ~(f)
+#define ISSET(t, f) ((t) & (f))
+
+/*
+ * Autoconfiguration glue.
+ */
+struct wscons_softc {
+ struct device sc_dev;
+
+ struct wscons_emul_data *sc_emul_data;
+ struct tty *sc_tty;
+
+ wscons_ioctl_t sc_ioctl;
+ wscons_mmap_t sc_mmap;
+};
+
+int wsconsmatch __P((struct device *, void *, void *));
+void wsconsattach __P((struct device *, struct device *, void *));
+
+struct cfattach wscons_ca = {
+ sizeof (struct wscons_softc), wsconsmatch, wsconsattach,
+};
+
+struct cfdriver wscons_cd = {
+ NULL, "wscons", DV_TTY,
+};
+
+/*
+ * Console handing functions and variables.
+ */
+int wscons_console_attached; /* polled console fns attached */
+int wscons_console_unit = -1;
+struct wscons_emul_data wscons_console_emul_data;
+
+int wscons_cngetc __P((dev_t));
+void wscons_cnputc __P((dev_t, int));
+void wscons_cnpollc __P((dev_t, int));
+
+struct consdev wscons_consdev =
+ { NULL, NULL, wscons_cngetc, wscons_cnputc, wscons_cnpollc, NODEV, 1 };
+
+/*
+ * Input focus handling: where characters from the keyboard are sent.
+ */
+int wscons_input_focus = -1;
+
+/*
+ * TTY interface helpers.
+ */
+
+#define WSCUNIT(dev) minor(dev)
+
+void wsconsstart __P((struct tty *));
+int wsconsparam __P((struct tty *, struct termios *));
+
+
+/*
+ * Output device selection and attachment.
+ */
+
+int
+wsconsmatch(parent, cfdata, aux)
+ struct device *parent;
+ void *cfdata;
+ void *aux;
+{
+ struct wscons_attach_args *waa = aux;
+ struct cfdata *cf = cfdata;
+
+ if (waa->waa_isconsole && wscons_console_unit != -1)
+ panic("wsconsmatch: multiple consoles?");
+
+ /* If console-ness specified... */
+ if (cf->wsconscf_console != -1) {
+ /*
+ * If exact match, return match with high priority,
+ * else return don't match.
+ */
+ if ((cf->wsconscf_console && waa->waa_isconsole) ||
+ (!cf->wsconscf_console && !waa->waa_isconsole))
+ return (10);
+ else
+ return (0);
+ }
+
+ /* Otherwise match with low priority. */
+ return (1);
+}
+
+void
+wsconsattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct wscons_attach_args *waa = aux;
+ struct wscons_softc *sc = (struct wscons_softc *)self;
+ int console;
+
+ console = waa->waa_isconsole;
+ if (console)
+ printf(": console");
+
+ /*
+ * If output has already been set up, record it now. Otherwise,
+ * do the setup.
+ */
+ if (console) {
+ sc->sc_emul_data = &wscons_console_emul_data;
+ wscons_console_unit = sc->sc_dev.dv_unit;
+ wscons_consdev.cn_dev =
+ makedev(25, wscons_console_unit); /* XXX */
+ } else {
+ sc->sc_emul_data = malloc(sizeof(*sc->sc_emul_data), M_DEVBUF,
+ M_WAITOK);
+ wscons_emul_attach(sc->sc_emul_data, &waa->waa_odev_spec);
+ }
+
+ /*
+ * Set wscons input focus if this is the console device,
+ * or if we've not yet set the input focus.
+ */
+ if (console || wscons_input_focus == -1)
+ wscons_input_focus = sc->sc_dev.dv_unit;
+
+ /*
+ * Set up the device's tty structure.
+ */
+ sc->sc_tty = ttymalloc();
+ tty_attach(sc->sc_tty);
+
+ /*
+ * Record other relevant information: ioctl and mmap functions.
+ */
+ sc->sc_ioctl = waa->waa_odev_spec.wo_ioctl;
+ sc->sc_mmap = waa->waa_odev_spec.wo_mmap;
+
+ printf("\n");
+}
+
+
+/*
+ * Keyboard input handling.
+ */
+
+void
+wscons_input(cp)
+ char *cp;
+{
+ struct wscons_softc *sc;
+ struct tty *tp;
+
+ if (wscons_input_focus == -1)
+ return;
+
+#ifdef DIAGNOSTIC
+ if (wscons_input_focus >= wscons_cd.cd_ndevs)
+ panic("wscons_input: bogus input focus");
+ sc = wscons_cd.cd_devs[wscons_input_focus];
+ if (sc == NULL)
+ panic("wscons_input: null input device");
+ tp = sc->sc_tty;
+ if (tp == NULL)
+ panic("wscons_input: no tty");
+#else
+ sc = wscons_cd.cd_devs[wscons_input_focus];
+ tp = sc->sc_tty;
+#endif
+
+ while (*cp)
+ (*linesw[tp->t_line].l_rint)(*cp++, tp);
+}
+
+
+/*
+ * Console (output) tty-handling functions.
+ */
+
+int
+wsconsopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct wscons_softc *sc;
+ int unit = WSCUNIT(dev), newopen, rv;
+ struct tty *tp;
+
+ if (unit >= wscons_cd.cd_ndevs)
+ return ENXIO;
+ sc = wscons_cd.cd_devs[unit];
+ if (sc == NULL)
+ return ENXIO;
+
+#ifdef DIAGNOSTIC
+ if (!sc->sc_tty)
+ panic("wscopen: no tty!");
+#endif
+ tp = sc->sc_tty;
+
+ tp->t_oproc = wsconsstart;
+ tp->t_param = wsconsparam;
+ tp->t_dev = dev;
+ newopen = (tp->t_state & TS_ISOPEN) == 0;
+ if (newopen) {
+ tp->t_state |= TS_WOPEN;
+ 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;
+ wsconsparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+ } else if ((tp->t_state & TS_XCLUDE) != 0 && p->p_ucred->cr_uid != 0)
+ return EBUSY;
+ tp->t_state |= TS_CARR_ON;
+
+ rv = ((*linesw[tp->t_line].l_open)(dev, tp));
+ if (newopen && (rv == 0)) {
+ /* set window sizes to be correct */
+ tp->t_winsize.ws_row = sc->sc_emul_data->ac_nrow;
+ tp->t_winsize.ws_col = sc->sc_emul_data->ac_ncol;
+ }
+ return (rv);
+}
+
+int
+wsconsclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct wscons_softc *sc = wscons_cd.cd_devs[WSCUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+ return(0);
+}
+
+int
+wsconsread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct wscons_softc *sc = wscons_cd.cd_devs[WSCUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+wsconswrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct wscons_softc *sc = wscons_cd.cd_devs[WSCUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+struct tty *
+wsconstty(dev)
+ dev_t dev;
+{
+ struct wscons_softc *sc = wscons_cd.cd_devs[WSCUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return (tp);
+}
+
+int
+wsconsioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct wscons_softc *sc = wscons_cd.cd_devs[WSCUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+ int error;
+
+ /* do the line discipline ioctls first */
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+
+ /* then the tty ioctls */
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+
+ /* then the underlying frame buffer device ioctls */
+ if (sc->sc_ioctl != NULL)
+ error = (*sc->sc_ioctl)(sc->sc_dev.dv_parent, cmd, data,
+ flag, p);
+ if (error >= 0)
+ return error;
+
+ /*
+ * then the keyboard ioctls, if we have input focus.
+ * This is done last because it's a special case: it will
+ * return ENOTTY (not -1) if it can't figure out what
+ * to do with the request.
+ */
+ if (WSCUNIT(dev) == wscons_input_focus)
+ error = kbdioctl(0, cmd, data, flag, p); /* XXX dev */
+ else
+ error = ENOTTY;
+
+ return (error);
+}
+
+int
+wsconsmmap(dev, offset, prot)
+ dev_t dev;
+ int offset; /* XXX */
+ int prot;
+{
+ struct wscons_softc *sc = wscons_cd.cd_devs[WSCUNIT(dev)];
+
+ if (sc->sc_ioctl != NULL)
+ return (*sc->sc_mmap)(sc->sc_dev.dv_parent, offset, prot);
+ else
+ return -1;
+}
+
+void
+wsconsstart(tp)
+ register struct tty *tp;
+{
+ struct wscons_softc *sc;
+ register int s, n, i;
+ char buf[OBUFSIZ];
+
+ s = spltty();
+ if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
+ splx(s);
+ return;
+ }
+ tp->t_state |= TS_BUSY;
+ splx(s);
+
+ n = q_to_b(&tp->t_outq, buf, sizeof(buf));
+ for (i = 0; i < n; ++i)
+ buf[i] &= 0177; /* strip parity (argh) */
+
+ sc = wscons_cd.cd_devs[WSCUNIT(tp->t_dev)];
+ wscons_emul_input(sc->sc_emul_data, buf, n);
+
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ /* Come back if there's more to do */
+ if (tp->t_outq.c_cc) {
+ tp->t_state |= TS_TIMEOUT;
+ timeout(ttrstrt, tp, 1);
+ }
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (tp->t_state&TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ splx(s);
+}
+
+int
+wsconsstop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ /* XXX ??? */
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY))
+ if (!ISSET(tp->t_state, TS_TTSTOP))
+ SET(tp->t_state, TS_FLUSH);
+ splx(s);
+}
+
+/*
+ * Set line parameters.
+ */
+int
+wsconsparam(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;
+}
+
+
+/*
+ * Polled-console handing setup and manipulation.
+ */
+
+void
+wscons_attach_console(wo)
+ const struct wscons_odev_spec *wo;
+{
+
+ if (wscons_console_attached)
+ panic("wscons_attach_console: multiple times");
+
+ wscons_emul_attach(&wscons_console_emul_data, wo);
+ cn_tab = &wscons_consdev;
+ wscons_console_attached = 1;
+}
+
+void
+wscons_cnputc(dev, ic)
+ dev_t dev;
+ int ic;
+{
+ char c = ic;
+
+ if (wscons_console_attached)
+ wscons_emul_input(&wscons_console_emul_data, &c, 1);
+}
+
+int
+wscons_cngetc(dev)
+ dev_t dev;
+{
+
+ return kbd_cngetc(dev); /* XXX XXX */
+}
+
+void
+wscons_cnpollc(dev, i)
+ dev_t dev;
+ int i;
+{
+
+ kbd_cngetc(dev, i); /* XXX XXX */
+}