setgroups check int > NGROUPS, so negative would fail; minor cleanup
[unix-history] / usr / src / sys / kern / tty_tb.c
index 62f125c..2ca8584 100644 (file)
@@ -1,48 +1,75 @@
-/*     tty_tb.c        6.2     83/09/22        */
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ *     @(#)tty_tb.c    7.5 (Berkeley) %G%
+ */
 
 #include "tb.h"
 #if NTB > 0
 
 
 #include "tb.h"
 #if NTB > 0
 
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/ioctl.h"
-#include "../h/tty.h"
-#include "../h/proc.h"
-#include "../h/inode.h"
-#include "../h/file.h"
-#include "../h/conf.h"
-#include "../h/buf.h"
-#include "../h/uio.h"
+/*
+ * Line discipline for RS232 tablets;
+ * supplies binary coordinate data.
+ */
+#include "param.h"
+#include "user.h"
+#include "tablet.h"
+#include "tty.h"
 
 /*
 
 /*
- * Line discipline for RS232 tablets.
- * Supplies binary coordinate data.
- *
- * MAKE TABLET TYPE AN ioctl TO AVOID HAVING ONE DISCIPLINE PER TABLET TYPE.
+ * Tablet configuration table.
  */
  */
+struct tbconf {
+       short   tbc_recsize;    /* input record size in bytes */
+       short   tbc_uiosize;    /* size of data record returned user */
+       int     tbc_sync;       /* mask for finding sync byte/bit */
+       int     (*tbc_decode)();/* decoding routine */
+       char    *tbc_run;       /* enter run mode sequence */
+       char    *tbc_point;     /* enter point mode sequence */
+       char    *tbc_stop;      /* stop sequence */
+       char    *tbc_start;     /* start/restart sequence */
+       int     tbc_flags;
+#define        TBF_POL         0x1     /* polhemus hack */
+#define        TBF_INPROX      0x2     /* tablet has proximity info */
+};
 
 
-#define NTBS           (16)
-#define MALLTABCHAR    (8)
-#define MTABCHAR       (5)
-#define MNTABCHAR      (6)
+static int tbdecode(), gtcodecode(), poldecode();
+static int tblresdecode(), tbhresdecode();
 
 
+struct tbconf tbconf[TBTYPE] = {
+{ 0 },
+{ 5, sizeof (struct tbpos), 0200, tbdecode, "6", "4" },
+{ 5, sizeof (struct tbpos), 0200, tbdecode, "\1CN", "\1RT", "\2", "\4" },
+{ 8, sizeof (struct gtcopos), 0200, gtcodecode },
+{17, sizeof (struct polpos), 0200, poldecode, 0, 0, "\21", "\5\22\2\23",
+  TBF_POL },
+{ 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CN", "\1PT", "\2", "\4",
+  TBF_INPROX },
+{ 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CN", "\1PT", "\2", "\4",
+  TBF_INPROX },
+{ 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CL\33", "\1PT\33", 0, 0},
+{ 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CL\33", "\1PT\33", 0, 0},
+};
+
+/*
+ * Tablet state
+ */
 struct tb {
 struct tb {
-       short used;
-       char cbuf[MALLTABCHAR];
-       struct tbpos {
-               int     xpos;
-               int     ypos;
-               short   status;
-               short   scount;
-       } tbpos;
+       int     tbflags;                /* mode & type bits */
+#define        TBMAXREC        17      /* max input record size */
+       char    cbuf[TBMAXREC];         /* input buffer */
+       union {
+               struct  tbpos tbpos;
+               struct  gtcopos gtcopos;
+               struct  polpos polpos;
+       } rets;                         /* processed state */
+#define NTBS   16
 } tb[NTBS];
 
 /*
 } tb[NTBS];
 
 /*
- * Open as tablet discipline.  Called when discipline changed
- * with ioctl, and changes the interpretation of the information
- * in the tty structure.
+ * Open as tablet discipline; called on discipline change.
  */
 /*ARGSUSED*/
 tbopen(dev, tp)
  */
 /*ARGSUSED*/
 tbopen(dev, tp)
@@ -51,33 +78,35 @@ tbopen(dev, tp)
 {
        register struct tb *tbp;
 
 {
        register struct tb *tbp;
 
-       if (tp->t_line == TABLDISC || tp->t_line == NTABLDISC)
+       if (tp->t_line == TABLDISC)
                return (ENODEV);
        ttywflush(tp);
        for (tbp = tb; tbp < &tb[NTBS]; tbp++)
                return (ENODEV);
        ttywflush(tp);
        for (tbp = tb; tbp < &tb[NTBS]; tbp++)
-               if (!tbp->used)
+               if (tbp->tbflags == 0)
                        break;
        if (tbp >= &tb[NTBS])
                return (EBUSY);
                        break;
        if (tbp >= &tb[NTBS])
                return (EBUSY);
-       tbp->used++;
+       tbp->tbflags = TBTIGER|TBPOINT;         /* default */
        tp->t_cp = tbp->cbuf;
        tp->t_inbuf = 0;
        tp->t_cp = tbp->cbuf;
        tp->t_inbuf = 0;
-       tbp->tbpos.xpos = tbp->tbpos.ypos = 0;
-       tbp->tbpos.status = tbp->tbpos.scount = 0;
-       tp->T_LINEP = (caddr_t) tbp;
+       bzero((caddr_t)&tbp->rets, sizeof (tbp->rets));
+       tp->T_LINEP = (caddr_t)tbp;
+       tp->t_flags |= LITOUT;
        return (0);
 }
 
 /*
        return (0);
 }
 
 /*
- * Break down... called when discipline changed or from device
- * close routine.
+ * Line discipline change or last device close.
  */
 tbclose(tp)
        register struct tty *tp;
 {
  */
 tbclose(tp)
        register struct tty *tp;
 {
-       register int s = spl5();
+       register int s;
+       int modebits = TBPOINT|TBSTOP;
 
 
-       ((struct tb *) tp->T_LINEP)->used = 0;
+       tbioctl(tp, BIOSMODE, &modebits, 0);
+       s = spltty();
+       ((struct tb *)tp->T_LINEP)->tbflags = 0;
        tp->t_cp = 0;
        tp->t_inbuf = 0;
        tp->t_rawq.c_cc = 0;            /* clear queues -- paranoid */
        tp->t_cp = 0;
        tp->t_inbuf = 0;
        tp->t_rawq.c_cc = 0;            /* clear queues -- paranoid */
@@ -88,124 +117,224 @@ tbclose(tp)
 
 /*
  * Read from a tablet line.
 
 /*
  * Read from a tablet line.
- * Characters have been buffered in a buffer and
- * decoded. The coordinates are now sluffed back to the user.
+ * Characters have been buffered in a buffer and decoded.
  */
 tbread(tp, uio)
        register struct tty *tp;
        struct uio *uio;
 {
  */
 tbread(tp, uio)
        register struct tty *tp;
        struct uio *uio;
 {
-       struct tbpos *tbpos;
+       register struct tb *tbp = (struct tb *)tp->T_LINEP;
+       register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE];
+       int ret;
 
 
-       if ((tp->t_state&TS_CARR_ON)==0)
+       if ((tp->t_state&TS_CARR_ON) == 0)
                return (EIO);
                return (EIO);
-       tbpos = &(((struct tb *) (tp->T_LINEP))->tbpos);
-       return (uiomove(tbpos, sizeof *tbpos, UIO_READ, uio));
+       ret = uiomove(&tbp->rets, tc->tbc_uiosize, uio);
+       if (tc->tbc_flags&TBF_POL)
+               tbp->rets.polpos.p_key = ' ';
+       return (ret);
 }
 
 /*
  * Low level character input routine.
 }
 
 /*
  * Low level character input routine.
- * Stuff the character in the buffer, and decode the it
+ * Stuff the character in the buffer, and decode
  * if all the chars are there.
  *
  * This routine could be expanded in-line in the receiver
  * if all the chars are there.
  *
  * This routine could be expanded in-line in the receiver
- * interrupt routine of the dh-11 to make it run as fast as possible.
+ * interrupt routine to make it run as fast as possible.
  */
  */
-int    LASTTABC;
-
 tbinput(c, tp)
        register int c;
        register struct tty *tp;
 {
 tbinput(c, tp)
        register int c;
        register struct tty *tp;
 {
-       register struct tb *tbp = (struct tb *) tp->T_LINEP;
-
-       if (tp->t_line == TABLDISC) {
-               if ((c&0200) || (tp->t_inbuf == MTABCHAR)) {
-                       tp->t_cp = tbp->cbuf;
-                       tp->t_inbuf = 0;
-               }
-               *tp->t_cp++ = c&0177;
-               if (++tp->t_inbuf == MTABCHAR)
-                       tbdecode(tbp->cbuf, &tbp->tbpos);
-       } else if (tp->t_line == NTABLDISC) {
-               if ((c&0200) || (tp->t_inbuf == MNTABCHAR)) {
-                       tp->t_cp = tbp->cbuf;
-                       tp->t_inbuf = 0;
-               }
-               *tp->t_cp++ = c&0177;
-               if (++tp->t_inbuf == MNTABCHAR)
-                       tbndecode(tbp->cbuf, &tbp->tbpos);
+       register struct tb *tbp = (struct tb *)tp->T_LINEP;
+       register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE];
+
+       if (tc->tbc_recsize == 0 || tc->tbc_decode == 0)        /* paranoid? */
+               return;
+       /*
+        * Locate sync bit/byte or reset input buffer.
+        */
+       if (c&tc->tbc_sync || tp->t_inbuf == tc->tbc_recsize) {
+               tp->t_cp = tbp->cbuf;
+               tp->t_inbuf = 0;
        }
        }
+       *tp->t_cp++ = c&0177;
+       /*
+        * Call decode routine only if a full record has been collected.
+        */
+       if (++tp->t_inbuf == tc->tbc_recsize)
+               (*tc->tbc_decode)(tc, tbp->cbuf, &tbp->rets);
 }
 
 /*
 }
 
 /*
- * Decode tablet coordinates from ascii to binary.
- *     (gtco 6 character format)
+ * Decode GTCO 8 byte format (high res, tilt, and pressure).
  */
  */
-tbndecode(cp, tbpos)
+static
+gtcodecode(tc, cp, tbpos)
+       struct tbconf *tc;
        register char *cp;
        register char *cp;
-       register struct tbpos *tbpos;
+       register struct gtcopos *tbpos;
 {
 
 {
 
-       tbpos->status = *cp>>2; /* this needs to be decoded */
-       tbpos->xpos = ((*cp++)&03)<<14;
-       tbpos->xpos |= (*cp++)<<7;
-       tbpos->xpos |= (*cp++);
-       tbpos->ypos = ((*cp++)&03)<<14;
-       tbpos->ypos |= (*cp++)<<7;
-       tbpos->ypos |= (*cp++);
+       tbpos->pressure = *cp >> 2;
+       tbpos->status = (tbpos->pressure > 16) | TBINPROX; /* half way down */
+       tbpos->xpos = (*cp++ & 03) << 14;
+       tbpos->xpos |= *cp++ << 7;
+       tbpos->xpos |= *cp++;
+       tbpos->ypos = (*cp++ & 03) << 14;
+       tbpos->ypos |= *cp++ << 7;
+       tbpos->ypos |= *cp++;
+       tbpos->xtilt = *cp++;
+       tbpos->ytilt = *cp++;
        tbpos->scount++;
 }
 
 /*
        tbpos->scount++;
 }
 
 /*
- * Decode tablet coordinates from ascii to binary.
- *     (hitachi 5 character format)
+ * Decode old Hitachi 5 byte format (low res).
  */
  */
-tbdecode(cp, tbpos)
+static
+tbdecode(tc, cp, tbpos)
+       struct tbconf *tc;
        register char *cp;
        register struct tbpos *tbpos;
 {
        register char *cp;
        register struct tbpos *tbpos;
 {
-       register int status;
        register char byte;
 
        byte = *cp++;
        register char byte;
 
        byte = *cp++;
-       status = (byte&0100) ? 0100000 : 0;
+       tbpos->status = (byte&0100) ? TBINPROX : 0;
        byte &= ~0100;
        if (byte > 036)
        byte &= ~0100;
        if (byte > 036)
-               status |= 1<<((byte-040)/2);
-       tbpos->xpos = (*cp++)<<7;
-       tbpos->xpos |= (*cp++);
-       if (tbpos->xpos < 256)          /* tablet wraps around at 256 */
-               status &= 077777;       /* make it out of proximity */
-       tbpos->ypos = (*cp++)<<7;
-       tbpos->ypos |= (*cp++);
-       tbpos->status  = status;
+               tbpos->status |= 1 << ((byte-040)/2);
+       tbpos->xpos = *cp++ << 7;
+       tbpos->xpos |= *cp++;
+       if (tbpos->xpos < 256)                  /* tablet wraps around at 256 */
+               tbpos->status &= ~TBINPROX;     /* make it out of proximity */
+       tbpos->ypos = *cp++ << 7;
+       tbpos->ypos |= *cp++;
        tbpos->scount++;
 }
 
 /*
        tbpos->scount++;
 }
 
 /*
- * This routine is called whenever a ioctl is about to be performed
- * and gets a chance to reject the ioctl.  We reject all teletype
- * oriented ioctl's except those which set the discipline, and
- * those which get parameters (gtty and get special characters).
+ * Decode new Hitach 5-byte format (low res).
  */
  */
+static
+tblresdecode(tc, cp, tbpos)
+       struct tbconf *tc;
+       register char *cp;
+       register struct tbpos *tbpos;
+{
+
+       *cp &= ~0100;           /* mask sync bit */
+       tbpos->status = (*cp++ >> 2) | TBINPROX;
+       if (tc->tbc_flags&TBF_INPROX && tbpos->status&020)
+               tbpos->status &= ~(020|TBINPROX);
+       tbpos->xpos = *cp++;
+       tbpos->xpos |= *cp++ << 6;
+       tbpos->ypos = *cp++;
+       tbpos->ypos |= *cp++ << 6;
+       tbpos->scount++;
+}
+
+/*
+ * Decode new Hitach 6-byte format (high res).
+ */
+static
+tbhresdecode(tc, cp, tbpos)
+       struct tbconf *tc;
+       register char *cp;
+       register struct tbpos *tbpos;
+{
+       char byte;
+
+       byte = *cp++;
+       tbpos->xpos = (byte & 03) << 14;
+       tbpos->xpos |= *cp++ << 7;
+       tbpos->xpos |= *cp++;
+       tbpos->ypos = *cp++ << 14;
+       tbpos->ypos |= *cp++ << 7;
+       tbpos->ypos |= *cp++;
+       tbpos->status = (byte >> 2) | TBINPROX;
+       if (tc->tbc_flags&TBF_INPROX && tbpos->status&020)
+               tbpos->status &= ~(020|TBINPROX);
+       tbpos->scount++;
+}
+
+/*
+ * Polhemus decode.
+ */
+static
+poldecode(tc, cp, polpos)
+       struct tbconf *tc;
+       register char *cp;
+       register struct polpos *polpos;
+{
+
+       polpos->p_x = cp[4] | cp[3]<<7 | (cp[9] & 0x03) << 14;
+       polpos->p_y = cp[6] | cp[5]<<7 | (cp[9] & 0x0c) << 12;
+       polpos->p_z = cp[8] | cp[7]<<7 | (cp[9] & 0x30) << 10;
+       polpos->p_azi = cp[11] | cp[10]<<7 | (cp[16] & 0x03) << 14;
+       polpos->p_pit = cp[13] | cp[12]<<7 | (cp[16] & 0x0c) << 12;
+       polpos->p_rol = cp[15] | cp[14]<<7 | (cp[16] & 0x30) << 10;
+       polpos->p_stat = cp[1] | cp[0]<<7;
+       if (cp[2] != ' ')
+               polpos->p_key = cp[2];
+}
+
 /*ARGSUSED*/
 tbioctl(tp, cmd, data, flag)
        struct tty *tp;
        caddr_t data;
 {
 /*ARGSUSED*/
 tbioctl(tp, cmd, data, flag)
        struct tty *tp;
        caddr_t data;
 {
+       register struct tb *tbp = (struct tb *)tp->T_LINEP;
 
 
-       if ((cmd>>8) != 't')
-               return (cmd);
        switch (cmd) {
 
        switch (cmd) {
 
+       case BIOGMODE:
+               *(int *)data = tbp->tbflags & TBMODE;
+               break;
+
+       case BIOSTYPE:
+               if (tbconf[*(int *)data & TBTYPE].tbc_recsize == 0 ||
+                   tbconf[*(int *)data & TBTYPE].tbc_decode == 0)
+                       return (EINVAL);
+               tbp->tbflags &= ~TBTYPE;
+               tbp->tbflags |= *(int *)data & TBTYPE;
+               /* fall thru... to set mode bits */
+
+       case BIOSMODE: {
+               register struct tbconf *tc;
+
+               tbp->tbflags &= ~TBMODE;
+               tbp->tbflags |= *(int *)data & TBMODE;
+               tc = &tbconf[tbp->tbflags & TBTYPE];
+               if (tbp->tbflags&TBSTOP) {
+                       if (tc->tbc_stop)
+                               ttyout(tc->tbc_stop, tp);
+               } else if (tc->tbc_start)
+                       ttyout(tc->tbc_start, tp);
+               if (tbp->tbflags&TBPOINT) {
+                       if (tc->tbc_point)
+                               ttyout(tc->tbc_point, tp);
+               } else if (tc->tbc_run)
+                       ttyout(tc->tbc_run, tp);
+               ttstart(tp);
+               break;
+       }
+
+       case BIOGTYPE:
+               *(int *)data = tbp->tbflags & TBTYPE;
+               break;
+
        case TIOCSETD:
        case TIOCGETD:
        case TIOCGETP:
        case TIOCGETC:
        case TIOCSETD:
        case TIOCGETD:
        case TIOCGETP:
        case TIOCGETC:
-               return (cmd);
+               return (-1);            /* pass thru... */
+
+       default:
+               return (ENOTTY);
        }
        }
-       u.u_error = ENOTTY;
        return (0);
 }
 #endif
        return (0);
 }
 #endif