date and time created 92/07/13 00:41:28 by torek
authorChris Torek <torek@ucbvax.Berkeley.EDU>
Mon, 13 Jul 1992 15:41:28 +0000 (07:41 -0800)
committerChris Torek <torek@ucbvax.Berkeley.EDU>
Mon, 13 Jul 1992 15:41:28 +0000 (07:41 -0800)
SCCS-vsn: sys/sparc/dev/cons.c 7.1
SCCS-vsn: sys/sparc/dev/event.c 7.1
SCCS-vsn: sys/sparc/dev/event_var.h 7.1

usr/src/sys/sparc/dev/cons.c [new file with mode: 0644]
usr/src/sys/sparc/dev/event.c [new file with mode: 0644]
usr/src/sys/sparc/dev/event_var.h [new file with mode: 0644]

diff --git a/usr/src/sys/sparc/dev/cons.c b/usr/src/sys/sparc/dev/cons.c
new file mode 100644 (file)
index 0000000..d64ba57
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)cons.c      7.1 (Berkeley) %G%
+ *
+ * from: $Header: cons.c,v 1.10 92/07/10 00:02:42 torek Exp $
+ */
+
+/*
+ * Console (indirect) driver.
+ */
+
+#include "sys/param.h"
+#include "sys/proc.h"
+#include "sys/systm.h"
+#include "sys/ioctl.h"
+#include "sys/tty.h"
+#include "sys/file.h"
+#include "sys/conf.h"
+
+#include "machine/bsd_openprom.h"
+#include "machine/psl.h"
+
+#include "zs.h"
+
+struct tty *constty = 0;       /* virtual console output device */
+struct tty *fbconstty = 0;     /* tty structure for frame buffer console */
+int    rom_console_input;      /* when set, hardclock calls cnrom() */
+
+int    cons_ocount;            /* output byte count */
+
+extern struct promvec *promvec;
+
+/*
+ * The output driver may munge the minor number in cons.t_dev.
+ */
+struct tty cons;               /* rom console tty device */
+static void cnstart __P((struct tty *));
+static void cnfbstart __P((struct tty *));
+static void cnfbstop __P((struct tty *, int));
+static void cnfbdma __P((void *));
+
+extern char partab[];
+
+consinit()
+{
+       register struct tty *tp = &cons;
+       register int in, out;
+       void zsconsole(), bwtwoconsole();
+
+       tp->t_dev = makedev(0, 0);      /* /dev/console */
+       tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+       tp->t_param = (int (*)(struct tty *, struct termios *))nullop;
+       in = *promvec->pv_stdin;
+       out = *promvec->pv_stdout;
+       switch (in) {
+
+#if NZS > 0
+       case PROMDEV_TTYA:
+               zsconsole(tp, 0, 0);
+               break;
+
+       case PROMDEV_TTYB:
+               zsconsole(tp, 1, 0);
+               break;
+#endif
+
+       case PROMDEV_KBD:
+               /*
+                * Tell the keyboard driver to direct ASCII input here.
+                */
+               kbd_ascii(tp);
+               break;
+
+       default:
+               rom_console_input = 1;
+               printf("unknown console input source %d; using rom\n", in);
+               break;
+       }
+       switch (out) {
+
+#if NZS > 0
+       case PROMDEV_TTYA:
+               zsconsole(tp, 0, 1);
+               break;
+
+       case PROMDEV_TTYB:
+               zsconsole(tp, 1, 1);
+               break;
+#endif
+
+       case PROMDEV_SCREEN:
+               fbconstty = tp;
+               tp->t_oproc = cnfbstart;
+               tp->t_stop = cnfbstop;
+               break;
+
+       default:
+               printf("unknown console output sink %d; using rom\n", out);
+               tp->t_oproc = cnstart;
+               tp->t_stop = (void (*)(struct tty *, int))nullop;
+               break;
+       }
+}
+
+/* ARGSUSED */
+cnopen(dev, flag, mode, p)
+       dev_t dev;
+       int flag, mode;
+       struct proc *p;
+{
+       register struct tty *tp = &cons;
+
+       if ((tp->t_state & TS_ISOPEN) == 0) {
+               /*
+                * Leave baud rate alone!
+                */
+               ttychars(tp);
+               tp->t_iflag = TTYDEF_IFLAG;
+               tp->t_oflag = TTYDEF_OFLAG;
+               tp->t_lflag = TTYDEF_LFLAG;
+               tp->t_cflag = TTYDEF_CFLAG;
+               tp->t_state = TS_ISOPEN | TS_CARR_ON;
+               ttsetwater(tp);
+       } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
+               return (EBUSY);
+       return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+/* ARGSUSED */
+cnclose(dev, flag, mode, p)
+       dev_t dev;
+       int flag, mode;
+       struct proc *p;
+{
+       register struct tty *tp = &cons;
+
+       (*linesw[tp->t_line].l_close)(tp, flag);
+       ttyclose(tp);
+       return (0);
+}
+
+/* ARGSUSED */
+cnread(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+       int flag;
+{
+       register struct tty *tp = &cons;
+
+       return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+/* ARGSUSED */
+cnwrite(dev, uio, flag)
+       dev_t dev;
+       struct uio *uio;
+       int flag;
+{
+       register struct tty *tp;
+       
+       if ((tp = constty) == NULL ||
+           (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN))
+               tp = &cons;
+       return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+cnioctl(dev, cmd, data, flag, p)
+       dev_t dev;
+       int cmd;
+       caddr_t data;
+       int flag;
+       struct proc *p;
+{
+       register struct tty *tp;
+       int error;
+
+       /*
+        * Superuser can always use this to wrest control of console
+        * output from the "virtual" console.
+        */
+       if (cmd == TIOCCONS && constty) {
+               error = suser(p->p_ucred, (u_short *)NULL);
+               if (error)
+                       return (error);
+               constty = NULL;
+               return (0);
+       }
+       tp = &cons;
+       if ((error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p)) >= 0)
+               return (error);
+       if ((error = ttioctl(tp, cmd, data, flag)) >= 0)
+               return (error);
+       return (ENOTTY);
+}
+
+cnselect(dev, which, p)
+       dev_t dev;
+       int which;
+       struct proc *p;
+{
+
+       return (ttselect(makedev(major(dev), 0), which, p));
+}
+
+/*
+ * The rest of this code is run only when we are using the ROM vectors.
+ */
+
+/*
+ * Generic output.  We just call putchar.  (Very bad for performance.)
+ */
+static void
+cnstart(tp)
+       register struct tty *tp;
+{
+       register int c, s;
+       register void (*putc)(int);
+
+       s = spltty();
+       if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
+               splx(s);
+               return;
+       }
+       putc = promvec->pv_putchar;
+       while (tp->t_outq.c_cc) {
+               c = getc(&tp->t_outq);
+               /*
+                * *%&!*& ROM monitor console putchar is not reentrant!
+                * splhigh/tty around it so as not to run so long with
+                * clock interrupts blocked.
+                */
+               (void) splhigh();
+               (*putc)(c & 0177);
+               (void) spltty();
+       }
+       if (tp->t_state & TS_ASLEEP) {          /* can't happen? */
+               tp->t_state &= ~TS_ASLEEP;
+               wakeup((caddr_t)&tp->t_outq);
+       }
+       selwakeup(&tp->t_wsel);
+       splx(s);
+}
+
+/*
+ * Frame buffer output.
+ * We use pseudo-DMA, via the ROM `write string' function, called from
+ * software clock interrupts.
+ */
+static void
+cnfbstart(tp)
+       register struct tty *tp;
+{
+       register int s;
+
+       s = spltty();           /* paranoid: splsoftclock should suffice */
+       if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
+               splx(s);
+               return;
+       }
+       /*
+        * If there are sleepers, and output has drained below low
+        * water mark, awaken.
+        */
+       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);
+       }
+       if (tp->t_outq.c_cc) {
+               tp->t_state |= TS_BUSY;
+               if (s == 0) {
+                       (void) splsoftclock();
+                       cnfbdma((void *)tp);
+               } else
+                       timeout(cnfbdma, tp, 1);
+       }
+       splx(s);
+}
+
+/*
+ * Stop frame buffer output: just assert TS_FLUSH if necessary.
+ */
+static void
+cnfbstop(tp, flag)
+       register struct tty *tp;
+       int flag;
+{
+       register int s = spltty();      /* paranoid */
+
+       if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY)
+               tp->t_state |= TS_FLUSH;
+       splx(s);
+}
+
+/*
+ * Do pseudo-dma (called from software interrupt).
+ */
+static void
+cnfbdma(tpaddr)
+       void *tpaddr;
+{
+       register struct tty *tp = tpaddr;
+       register char *p, *q;
+       register int n, c, s;
+
+       s = spltty();                   /* paranoid */
+       if (tp->t_state & TS_FLUSH) {
+               tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+               splx(s);
+       } else {
+               tp->t_state &= ~TS_BUSY;
+               splx(s);
+               p = tp->t_outq.c_cf;
+               n = ndqb(&tp->t_outq, 0);
+               for (q = p, c = n; --c >= 0; q++)
+                       if (*q & 0200)  /* high bits seem to be bad */
+                               *q &= ~0200;
+               (*promvec->pv_putstr)(p, n);
+               ndflush(&tp->t_outq, n);
+       }
+       if (tp->t_line)
+               (*linesw[tp->t_line].l_start)(tp);
+       else
+               cnfbstart(tp);
+}
+
+/*
+ * The following is for rom console input.  The rom will not call
+ * an `interrupt' routine on console input ready, so we must poll.
+ * This is all rather sad.
+ */
+volatile int   cn_rxc;                 /* XXX receive `silo' */
+
+/* called from hardclock, which is above spltty, so no tty calls! */
+cnrom()
+{
+       register int c;
+
+       if (cn_rxc >= 0)
+               return (1);
+       if ((c = (*promvec->pv_nbgetchar)()) < 0)
+               return (0);
+       cn_rxc = c;
+       return (1);
+}
+
+/* pseudo console software interrupt scheduled when cnrom() returns 1 */
+cnrint()
+{
+       register struct tty *tp;
+       register int c, s;
+
+       s = splclock();
+       c = cn_rxc;
+       cn_rxc = -1;
+       splx(s);
+       if (c < 0)
+               return;
+       tp = &cons;
+       if ((tp->t_cflag & CSIZE) == CS7) {
+               /* XXX this should be done elsewhere, if at all */
+               if (tp->t_cflag & PARENB)
+                       if (tp->t_cflag & PARODD ?
+                           (partab[c & 0177] & 0200) == (c & 0200) :
+                           (partab[c & 0177] & 0200) != (c & 0200))
+                               c |= TTY_PE;
+               c &= ~0200;
+       }
+       (*linesw[tp->t_line].l_rint)(c, tp);
+}
+
+cngetc()
+{
+       register int s, c;
+
+       s = splhigh();
+       c = (*promvec->pv_getchar)();
+       splx(s);
+       if (c == '\r')
+               c = '\n';
+       return (c);
+}
+
+cnputc(c)
+       register int c;
+{
+       register int s = splhigh();
+
+       if (c == '\n')
+               (*promvec->pv_putchar)('\r');
+       (*promvec->pv_putchar)(c);
+       splx(s);
+}
diff --git a/usr/src/sys/sparc/dev/event.c b/usr/src/sys/sparc/dev/event.c
new file mode 100644 (file)
index 0000000..05b2d6a
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)event.c     7.1 (Berkeley) %G%
+ *
+ * from: $Header: event.c,v 1.4 92/06/17 05:35:45 torek Exp $ (LBL)
+ */
+
+/*
+ * Internal `Firm_event' interface for the keyboard and mouse drivers.
+ */
+
+#include "sys/param.h"
+#include "sys/fcntl.h"
+#include "sys/malloc.h"
+#include "sys/proc.h"
+#include "sys/systm.h"
+#include "sys/vnode.h"
+
+#include "vuid_event.h"
+#include "event_var.h"
+
+/*
+ * Initialize a firm_event queue.
+ */
+void
+ev_init(ev)
+       register struct evvar *ev;
+{
+
+       ev->ev_get = ev->ev_put = 0;
+       ev->ev_q = malloc((u_long)EV_QSIZE * sizeof(struct firm_event),
+           M_DEVBUF, M_WAITOK);
+       bzero((caddr_t)ev->ev_q, EV_QSIZE * sizeof(struct firm_event));
+}
+
+/*
+ * Tear down a firm_event queue.
+ */
+void
+ev_fini(ev)
+       register struct evvar *ev;
+{
+
+       free(ev->ev_q, M_DEVBUF);
+}
+
+/*
+ * User-level interface: read, select.
+ * (User cannot write an event queue.)
+ */
+int
+ev_read(ev, uio, flags)
+       register struct evvar *ev;
+       struct uio *uio;
+       int flags;
+{
+       int s, n, cnt, error;
+
+       /*
+        * Make sure we can return at least 1.
+        */
+       if (uio->uio_resid < sizeof(struct firm_event))
+               return (EMSGSIZE);      /* ??? */
+       s = splev();
+       while (ev->ev_get == ev->ev_put) {
+               if (flags & IO_NDELAY) {
+                       splx(s);
+                       return (EWOULDBLOCK);
+               }
+               ev->ev_wanted = 1;
+               error = tsleep((caddr_t)ev, PEVENT | PCATCH, "firm_event", 0);
+               if (error) {
+                       splx(s);
+                       return (error);
+               }
+       }
+       /*
+        * Move firm_events from tail end of queue (there is at least one
+        * there).
+        */
+       if (ev->ev_put < ev->ev_get)
+               cnt = EV_QSIZE - ev->ev_get;    /* events in [get..QSIZE) */
+       else
+               cnt = ev->ev_put - ev->ev_get;  /* events in [get..put) */
+       splx(s);
+       n = howmany(uio->uio_resid, sizeof(struct firm_event));
+       if (cnt > n)
+               cnt = n;
+       error = uiomove((caddr_t)&ev->ev_q[ev->ev_get],
+           cnt * sizeof(struct firm_event), uio);
+       n -= cnt;
+       /*
+        * If we do not wrap to 0, used up all our space, or had an error,
+        * stop.  Otherwise move from front of queue to put index, if there
+        * is anything there to move.
+        */
+       if ((ev->ev_get = (ev->ev_get + cnt) % EV_QSIZE) != 0 ||
+           n == 0 || error || (cnt = ev->ev_put) == 0)
+               return (error);
+       if (cnt > n)
+               cnt = n;
+       error = uiomove((caddr_t)&ev->ev_q[0],
+           cnt * sizeof(struct firm_event), uio);
+       ev->ev_get = cnt;
+       return (error);
+}
+
+int
+ev_select(ev, rw, p)
+       register struct evvar *ev;
+       int rw;
+       struct proc *p;
+{
+       int s = splev();
+
+       switch (rw) {
+
+       case FREAD:
+               /* succeed if there is something to read */
+               if (ev->ev_get != ev->ev_put) {
+                       splx(s);
+                       return (1);
+               }
+               selrecord(p, &ev->ev_sel);
+               break;
+
+       case FWRITE:
+               return (1);     /* always fails => never blocks */
+       }
+       splx(s);
+       return (0);
+}
diff --git a/usr/src/sys/sparc/dev/event_var.h b/usr/src/sys/sparc/dev/event_var.h
new file mode 100644 (file)
index 0000000..e0e326e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)event_var.h 7.1 (Berkeley) %G%
+ *
+ * from: $Header: event_var.h,v 1.4 92/06/17 05:35:45 torek Exp $ (LBL)
+ */
+
+/*
+ * Internal `Firm_event' interface for the keyboard and mouse drivers.
+ * The drivers are expected not to place events in the queue above spltty(),
+ * i.e., are expected to run off serial ports.
+ */
+
+/* EV_QSIZE should be a power of two so that `%' is fast */
+#define        EV_QSIZE        256     /* may need tuning; this uses 2k */
+
+struct evvar {
+       u_int   ev_get;         /* get (read) index (modified synchronously) */
+       volatile u_int ev_put;  /* put (write) index (modified by interrupt) */
+       struct  selinfo ev_sel; /* process selecting */
+       struct  proc *ev_io;    /* process that opened queue (can get SIGIO) */
+       char    ev_wanted;      /* wake up on input ready */
+       char    ev_async;       /* send SIGIO on input ready */
+       struct  firm_event *ev_q;/* circular buffer (queue) of events */
+};
+
+#define        splev() spltty()
+
+#define        EV_WAKEUP(ev) { \
+       selwakeup(&(ev)->ev_sel); \
+       if ((ev)->ev_wanted) { \
+               (ev)->ev_wanted = 0; \
+               wakeup((caddr_t)(ev)); \
+       } \
+       if ((ev)->ev_async) \
+               psignal((ev)->ev_io, SIGIO); \
+}
+
+void   ev_init __P((struct evvar *));
+void   ev_fini __P((struct evvar *));
+int    ev_read __P((struct evvar *, struct uio *, int));
+int    ev_select __P((struct evvar *, int, struct proc *));
+
+/*
+ * PEVENT is set just above PSOCK, which is just above TTIPRI, on the
+ * theory that mouse and keyboard `user' input should be quick.
+ */
+#define        PEVENT  23