123392Smckusick /* 229111Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323392Smckusick * All rights reserved. The Berkeley software License Agreement 423392Smckusick * specifies the terms and conditions for redistribution. 523392Smckusick * 6*29947Skarels * @(#)tty_tb.c 7.2 (Berkeley) 11/03/86 723392Smckusick */ 87297Ssam 97297Ssam #include "tb.h" 107297Ssam #if NTB > 0 117297Ssam 1225412Ssam /* 1325412Ssam * Line discipline for RS232 tablets; 1425412Ssam * supplies binary coordinate data. 1525412Ssam */ 1617097Sbloom #include "param.h" 1717097Sbloom #include "systm.h" 1817097Sbloom #include "dir.h" 1917097Sbloom #include "user.h" 2025412Ssam #include "tablet.h" 2117097Sbloom #include "tty.h" 2217097Sbloom #include "proc.h" 2317097Sbloom #include "inode.h" 2417097Sbloom #include "file.h" 2517097Sbloom #include "buf.h" 2617097Sbloom #include "uio.h" 277297Ssam 287297Ssam /* 2925412Ssam * Tablet configuration table. 307297Ssam */ 3125412Ssam struct tbconf { 3225412Ssam short tbc_recsize; /* input record size in bytes */ 3325412Ssam short tbc_uiosize; /* size of data record returned user */ 3425412Ssam int tbc_sync; /* mask for finding sync byte/bit */ 3525412Ssam int (*tbc_decode)();/* decoding routine */ 3625412Ssam char *tbc_run; /* enter run mode sequence */ 3725412Ssam char *tbc_point; /* enter point mode sequence */ 3825412Ssam char *tbc_stop; /* stop sequence */ 3925412Ssam char *tbc_start; /* start/restart sequence */ 4025412Ssam int tbc_flags; 4125412Ssam #define TBF_POL 0x1 /* polhemus hack */ 4225412Ssam }; 437297Ssam 4425412Ssam static int tbdecode(), gtcodecode(), poldecode(); 4525412Ssam static int tblresdecode(), tbhresdecode(); 468522Sroot 4725412Ssam struct tbconf tbconf[TBTYPE] = { 4825412Ssam { 0 }, 4925412Ssam { 5, sizeof (struct tbpos), 0200, tbdecode, "6", "4" }, 5025412Ssam { 5, sizeof (struct tbpos), 0200, tbdecode, "\1CN", "\1RT", "\2", "\4" }, 5125412Ssam { 8, sizeof (struct gtcopos), 0200, gtcodecode }, 5225412Ssam {17, sizeof (struct polpos), 0200, poldecode, 0, 0, "\21", "\5\22\2\23", 5325412Ssam TBF_POL }, 5425412Ssam { 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CN", "\1PT", "\2", "\4"}, 5525412Ssam { 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CN", "\1PT", "\2", "\4"}, 5625412Ssam }; 5725412Ssam 5825412Ssam /* 5925412Ssam * Tablet state 6025412Ssam */ 6114596Ssam struct tb { 6225412Ssam int tbflags; /* mode & type bits */ 6325412Ssam #define TBMAXREC 17 /* max input record size */ 6425412Ssam char cbuf[TBMAXREC]; /* input buffer */ 6525412Ssam union { 6625412Ssam struct tbpos tbpos; 6725412Ssam struct gtcopos gtcopos; 6825412Ssam struct polpos polpos; 6925412Ssam } rets; /* processed state */ 7025412Ssam #define NTBS 16 7114596Ssam } tb[NTBS]; 727297Ssam 737297Ssam /* 7425412Ssam * Open as tablet discipline; called on discipline change. 757297Ssam */ 767297Ssam /*ARGSUSED*/ 777297Ssam tbopen(dev, tp) 787632Ssam dev_t dev; 797632Ssam register struct tty *tp; 807297Ssam { 8114596Ssam register struct tb *tbp; 827297Ssam 8325412Ssam if (tp->t_line == TABLDISC) 8414596Ssam return (ENODEV); 8514596Ssam ttywflush(tp); 8614596Ssam for (tbp = tb; tbp < &tb[NTBS]; tbp++) 8725412Ssam if (tbp->tbflags == 0) 8814596Ssam break; 8914596Ssam if (tbp >= &tb[NTBS]) 908557Sroot return (EBUSY); 9125412Ssam tbp->tbflags = TBTIGER|TBPOINT; /* default */ 9214596Ssam tp->t_cp = tbp->cbuf; 937297Ssam tp->t_inbuf = 0; 9425412Ssam bzero((caddr_t)&tbp->rets, sizeof (tbp->rets)); 9525412Ssam tp->T_LINEP = (caddr_t)tbp; 9625412Ssam tp->t_flags |= LITOUT; 978557Sroot return (0); 987297Ssam } 997297Ssam 1007297Ssam /* 10125412Ssam * Line discipline change or last device close. 1027297Ssam */ 1037297Ssam tbclose(tp) 1048557Sroot register struct tty *tp; 1057297Ssam { 10625412Ssam register int s; 10725412Ssam int modebits = TBPOINT|TBSTOP; 1087297Ssam 10925412Ssam tbioctl(tp, BIOSMODE, &modebits, 0); 110*29947Skarels s = spltty(); 11125412Ssam ((struct tb *)tp->T_LINEP)->tbflags = 0; 1127297Ssam tp->t_cp = 0; 1137297Ssam tp->t_inbuf = 0; 1147297Ssam tp->t_rawq.c_cc = 0; /* clear queues -- paranoid */ 1157297Ssam tp->t_canq.c_cc = 0; 11615044Smckusick tp->t_line = 0; /* paranoid: avoid races */ 1177297Ssam splx(s); 1187297Ssam } 1197297Ssam 1207297Ssam /* 1217297Ssam * Read from a tablet line. 12225412Ssam * Characters have been buffered in a buffer and decoded. 1237297Ssam */ 1247732Sroot tbread(tp, uio) 1257732Sroot register struct tty *tp; 1267732Sroot struct uio *uio; 1277297Ssam { 12825412Ssam register struct tb *tbp = (struct tb *)tp->T_LINEP; 12925412Ssam register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE]; 13025412Ssam int ret; 1317297Ssam 13225412Ssam if ((tp->t_state&TS_CARR_ON) == 0) 1338522Sroot return (EIO); 13425412Ssam ret = uiomove(&tbp->rets, tc->tbc_uiosize, UIO_READ, uio); 13525412Ssam if (tc->tbc_flags&TBF_POL) 13625412Ssam tbp->rets.polpos.p_key = ' '; 13725412Ssam return (ret); 1387297Ssam } 1397297Ssam 1407297Ssam /* 1417297Ssam * Low level character input routine. 14225412Ssam * Stuff the character in the buffer, and decode 1437297Ssam * if all the chars are there. 1447297Ssam * 1457297Ssam * This routine could be expanded in-line in the receiver 14625412Ssam * interrupt routine to make it run as fast as possible. 1477297Ssam */ 1487297Ssam tbinput(c, tp) 1498522Sroot register int c; 1508522Sroot register struct tty *tp; 1517297Ssam { 15225412Ssam register struct tb *tbp = (struct tb *)tp->T_LINEP; 15325412Ssam register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE]; 1547297Ssam 15525412Ssam if (tc->tbc_recsize == 0 || tc->tbc_decode == 0) /* paranoid? */ 15625412Ssam return; 15725412Ssam /* 15825412Ssam * Locate sync bit/byte or reset input buffer. 15925412Ssam */ 16025412Ssam if (c&tc->tbc_sync || tp->t_inbuf == tc->tbc_recsize) { 16125412Ssam tp->t_cp = tbp->cbuf; 16225412Ssam tp->t_inbuf = 0; 1637297Ssam } 16425412Ssam *tp->t_cp++ = c&0177; 16525412Ssam /* 16625412Ssam * Call decode routine only if a full record has been collected. 16725412Ssam */ 16825412Ssam if (++tp->t_inbuf == tc->tbc_recsize) 16925412Ssam (*tc->tbc_decode)(tbp->cbuf, &tbp->rets); 1707297Ssam } 1717297Ssam 1727297Ssam /* 17325412Ssam * Decode GTCO 8 byte format (high res, tilt, and pressure). 1747297Ssam */ 17525412Ssam static 17625412Ssam gtcodecode(cp, tbpos) 1777297Ssam register char *cp; 17825412Ssam register struct gtcopos *tbpos; 1797297Ssam { 1807297Ssam 18125412Ssam tbpos->pressure = *cp >> 2; 18225412Ssam tbpos->status = (tbpos->pressure > 16) | TBINPROX; /* half way down */ 18325412Ssam tbpos->xpos = (*cp++ & 03) << 14; 18425412Ssam tbpos->xpos |= *cp++ << 7; 18525412Ssam tbpos->xpos |= *cp++; 18625412Ssam tbpos->ypos = (*cp++ & 03) << 14; 18725412Ssam tbpos->ypos |= *cp++ << 7; 18825412Ssam tbpos->ypos |= *cp++; 18925412Ssam tbpos->xtilt = *cp++; 19025412Ssam tbpos->ytilt = *cp++; 19114596Ssam tbpos->scount++; 1927297Ssam } 1937297Ssam 1947297Ssam /* 19525412Ssam * Decode old Hitachi 5 byte format (low res). 1967297Ssam */ 19725412Ssam static 19814596Ssam tbdecode(cp, tbpos) 1997297Ssam register char *cp; 20014596Ssam register struct tbpos *tbpos; 2017297Ssam { 2027297Ssam register char byte; 2037297Ssam 2047297Ssam byte = *cp++; 20525412Ssam tbpos->status = (byte&0100) ? TBINPROX : 0; 2067297Ssam byte &= ~0100; 2078522Sroot if (byte > 036) 20825412Ssam tbpos->status |= 1 << ((byte-040)/2); 20925412Ssam tbpos->xpos = *cp++ << 7; 21025412Ssam tbpos->xpos |= *cp++; 21125412Ssam if (tbpos->xpos < 256) /* tablet wraps around at 256 */ 21225412Ssam tbpos->status &= ~TBINPROX; /* make it out of proximity */ 21325412Ssam tbpos->ypos = *cp++ << 7; 21425412Ssam tbpos->ypos |= *cp++; 21514596Ssam tbpos->scount++; 2167297Ssam } 2177297Ssam 2187297Ssam /* 21925412Ssam * Decode new Hitach 5-byte format (low res). 2207297Ssam */ 22125412Ssam static 22225412Ssam tblresdecode(cp, tbpos) 22325412Ssam register char *cp; 22425412Ssam register struct tbpos *tbpos; 22525412Ssam { 22625412Ssam 22725412Ssam *cp &= ~0100; /* mask sync bit */ 22825412Ssam tbpos->status = (*cp++ >> 2) | TBINPROX; 22925412Ssam tbpos->xpos = *cp++; 23025412Ssam tbpos->xpos |= *cp++ << 6; 23125412Ssam tbpos->ypos = *cp++; 23225412Ssam tbpos->ypos |= *cp++ << 6; 23325412Ssam tbpos->scount++; 23425412Ssam } 23525412Ssam 23625412Ssam /* 23725412Ssam * Decode new Hitach 6-byte format (high res). 23825412Ssam */ 23925412Ssam static 24025412Ssam tbhresdecode(cp, tbpos) 24125412Ssam register char *cp; 24225412Ssam register struct tbpos *tbpos; 24325412Ssam { 24425412Ssam char byte; 24525412Ssam 24625412Ssam byte = *cp++; 24725412Ssam tbpos->xpos = (byte & 03) << 14; 24825412Ssam tbpos->xpos |= *cp++ << 7; 24925412Ssam tbpos->xpos |= *cp++; 25025412Ssam tbpos->ypos = *cp++ << 14; 25125412Ssam tbpos->ypos |= *cp++ << 7; 25225412Ssam tbpos->ypos |= *cp++; 25325412Ssam tbpos->status = (byte >> 2) | TBINPROX; 25425412Ssam tbpos->scount++; 25525412Ssam } 25625412Ssam 25725412Ssam /* 25825412Ssam * Polhemus decode. 25925412Ssam */ 26025412Ssam static 26125412Ssam poldecode(cp, polpos) 26225412Ssam register char *cp; 26325412Ssam register struct polpos *polpos; 26425412Ssam { 26525412Ssam 26625412Ssam polpos->p_x = cp[4] | cp[3]<<7 | (cp[9] & 0x03) << 14; 26725412Ssam polpos->p_y = cp[6] | cp[5]<<7 | (cp[9] & 0x0c) << 12; 26825412Ssam polpos->p_z = cp[8] | cp[7]<<7 | (cp[9] & 0x30) << 10; 26925412Ssam polpos->p_azi = cp[11] | cp[10]<<7 | (cp[16] & 0x03) << 14; 27025412Ssam polpos->p_pit = cp[13] | cp[12]<<7 | (cp[16] & 0x0c) << 12; 27125412Ssam polpos->p_rol = cp[15] | cp[14]<<7 | (cp[16] & 0x30) << 10; 27225412Ssam polpos->p_stat = cp[1] | cp[0]<<7; 27325412Ssam if (cp[2] != ' ') 27425412Ssam polpos->p_key = cp[2]; 27525412Ssam } 27625412Ssam 2777297Ssam /*ARGSUSED*/ 2787632Ssam tbioctl(tp, cmd, data, flag) 2797632Ssam struct tty *tp; 2807632Ssam caddr_t data; 2817297Ssam { 28225412Ssam register struct tb *tbp = (struct tb *)tp->T_LINEP; 2837297Ssam 2847297Ssam switch (cmd) { 2857297Ssam 28625412Ssam case BIOGMODE: 28725412Ssam *(int *)data = tbp->tbflags & TBMODE; 28825412Ssam break; 28925412Ssam 29025412Ssam case BIOSTYPE: 29125412Ssam if (tbconf[*(int *)data & TBTYPE].tbc_recsize == 0 || 29225412Ssam tbconf[*(int *)data & TBTYPE].tbc_decode == 0) 29325412Ssam return (EINVAL); 29425412Ssam tbp->tbflags &= ~TBTYPE; 29525412Ssam tbp->tbflags |= *(int *)data & TBTYPE; 29625412Ssam /* fall thru... to set mode bits */ 29725412Ssam 29825412Ssam case BIOSMODE: { 29925412Ssam register struct tbconf *tc; 30025412Ssam 30125412Ssam tbp->tbflags &= ~TBMODE; 30225412Ssam tbp->tbflags |= *(int *)data & TBMODE; 30325412Ssam tc = &tbconf[tbp->tbflags & TBTYPE]; 30425412Ssam if (tbp->tbflags&TBSTOP) { 30525412Ssam if (tc->tbc_stop) 30625412Ssam ttyout(tc->tbc_stop, tp); 30725412Ssam } else if (tc->tbc_start) 30825412Ssam ttyout(tc->tbc_start, tp); 30925412Ssam if (tbp->tbflags&TBPOINT) { 31025412Ssam if (tc->tbc_point) 31125412Ssam ttyout(tc->tbc_point, tp); 31225412Ssam } else if (tc->tbc_run) 31325412Ssam ttyout(tc->tbc_run, tp); 31425412Ssam ttstart(tp); 31525412Ssam break; 31625412Ssam } 31725412Ssam 31825412Ssam case BIOGTYPE: 31925412Ssam *(int *)data = tbp->tbflags & TBTYPE; 32025412Ssam break; 32125412Ssam 3227297Ssam case TIOCSETD: 3237297Ssam case TIOCGETD: 3247297Ssam case TIOCGETP: 3257297Ssam case TIOCGETC: 32625412Ssam return (-1); /* pass thru... */ 32725412Ssam 32825412Ssam default: 32925412Ssam return (ENOTTY); 3307297Ssam } 3317297Ssam return (0); 3327297Ssam } 3337297Ssam #endif 334