123392Smckusick /* 223392Smckusick * Copyright (c) 1982 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*25412Ssam * @(#)tty_tb.c 6.6 (Berkeley) 11/06/85 723392Smckusick */ 87297Ssam 97297Ssam #include "tb.h" 107297Ssam #if NTB > 0 117297Ssam 12*25412Ssam /* 13*25412Ssam * Line discipline for RS232 tablets; 14*25412Ssam * supplies binary coordinate data. 15*25412Ssam */ 1617097Sbloom #include "param.h" 1717097Sbloom #include "systm.h" 1817097Sbloom #include "dir.h" 1917097Sbloom #include "user.h" 20*25412Ssam #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 /* 29*25412Ssam * Tablet configuration table. 307297Ssam */ 31*25412Ssam struct tbconf { 32*25412Ssam short tbc_recsize; /* input record size in bytes */ 33*25412Ssam short tbc_uiosize; /* size of data record returned user */ 34*25412Ssam int tbc_sync; /* mask for finding sync byte/bit */ 35*25412Ssam int (*tbc_decode)();/* decoding routine */ 36*25412Ssam char *tbc_run; /* enter run mode sequence */ 37*25412Ssam char *tbc_point; /* enter point mode sequence */ 38*25412Ssam char *tbc_stop; /* stop sequence */ 39*25412Ssam char *tbc_start; /* start/restart sequence */ 40*25412Ssam int tbc_flags; 41*25412Ssam #define TBF_POL 0x1 /* polhemus hack */ 42*25412Ssam }; 437297Ssam 44*25412Ssam static int tbdecode(), gtcodecode(), poldecode(); 45*25412Ssam static int tblresdecode(), tbhresdecode(); 468522Sroot 47*25412Ssam struct tbconf tbconf[TBTYPE] = { 48*25412Ssam { 0 }, 49*25412Ssam { 5, sizeof (struct tbpos), 0200, tbdecode, "6", "4" }, 50*25412Ssam { 5, sizeof (struct tbpos), 0200, tbdecode, "\1CN", "\1RT", "\2", "\4" }, 51*25412Ssam { 8, sizeof (struct gtcopos), 0200, gtcodecode }, 52*25412Ssam {17, sizeof (struct polpos), 0200, poldecode, 0, 0, "\21", "\5\22\2\23", 53*25412Ssam TBF_POL }, 54*25412Ssam { 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CN", "\1PT", "\2", "\4"}, 55*25412Ssam { 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CN", "\1PT", "\2", "\4"}, 56*25412Ssam }; 57*25412Ssam 58*25412Ssam /* 59*25412Ssam * Tablet state 60*25412Ssam */ 6114596Ssam struct tb { 62*25412Ssam int tbflags; /* mode & type bits */ 63*25412Ssam #define TBMAXREC 17 /* max input record size */ 64*25412Ssam char cbuf[TBMAXREC]; /* input buffer */ 65*25412Ssam union { 66*25412Ssam struct tbpos tbpos; 67*25412Ssam struct gtcopos gtcopos; 68*25412Ssam struct polpos polpos; 69*25412Ssam } rets; /* processed state */ 70*25412Ssam #define NTBS 16 7114596Ssam } tb[NTBS]; 727297Ssam 737297Ssam /* 74*25412Ssam * 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 83*25412Ssam if (tp->t_line == TABLDISC) 8414596Ssam return (ENODEV); 8514596Ssam ttywflush(tp); 8614596Ssam for (tbp = tb; tbp < &tb[NTBS]; tbp++) 87*25412Ssam if (tbp->tbflags == 0) 8814596Ssam break; 8914596Ssam if (tbp >= &tb[NTBS]) 908557Sroot return (EBUSY); 91*25412Ssam tbp->tbflags = TBTIGER|TBPOINT; /* default */ 9214596Ssam tp->t_cp = tbp->cbuf; 937297Ssam tp->t_inbuf = 0; 94*25412Ssam bzero((caddr_t)&tbp->rets, sizeof (tbp->rets)); 95*25412Ssam tp->T_LINEP = (caddr_t)tbp; 96*25412Ssam tp->t_flags |= LITOUT; 978557Sroot return (0); 987297Ssam } 997297Ssam 1007297Ssam /* 101*25412Ssam * Line discipline change or last device close. 1027297Ssam */ 1037297Ssam tbclose(tp) 1048557Sroot register struct tty *tp; 1057297Ssam { 106*25412Ssam register int s; 107*25412Ssam int modebits = TBPOINT|TBSTOP; 1087297Ssam 109*25412Ssam tbioctl(tp, BIOSMODE, &modebits, 0); 110*25412Ssam s = spl5(); 111*25412Ssam ((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. 122*25412Ssam * Characters have been buffered in a buffer and decoded. 1237297Ssam */ 1247732Sroot tbread(tp, uio) 1257732Sroot register struct tty *tp; 1267732Sroot struct uio *uio; 1277297Ssam { 128*25412Ssam register struct tb *tbp = (struct tb *)tp->T_LINEP; 129*25412Ssam register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE]; 130*25412Ssam int ret; 1317297Ssam 132*25412Ssam if ((tp->t_state&TS_CARR_ON) == 0) 1338522Sroot return (EIO); 134*25412Ssam ret = uiomove(&tbp->rets, tc->tbc_uiosize, UIO_READ, uio); 135*25412Ssam if (tc->tbc_flags&TBF_POL) 136*25412Ssam tbp->rets.polpos.p_key = ' '; 137*25412Ssam return (ret); 1387297Ssam } 1397297Ssam 1407297Ssam /* 1417297Ssam * Low level character input routine. 142*25412Ssam * 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 146*25412Ssam * 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 { 152*25412Ssam register struct tb *tbp = (struct tb *)tp->T_LINEP; 153*25412Ssam register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE]; 1547297Ssam 155*25412Ssam if (tc->tbc_recsize == 0 || tc->tbc_decode == 0) /* paranoid? */ 156*25412Ssam return; 157*25412Ssam /* 158*25412Ssam * Locate sync bit/byte or reset input buffer. 159*25412Ssam */ 160*25412Ssam if (c&tc->tbc_sync || tp->t_inbuf == tc->tbc_recsize) { 161*25412Ssam tp->t_cp = tbp->cbuf; 162*25412Ssam tp->t_inbuf = 0; 1637297Ssam } 164*25412Ssam *tp->t_cp++ = c&0177; 165*25412Ssam /* 166*25412Ssam * Call decode routine only if a full record has been collected. 167*25412Ssam */ 168*25412Ssam if (++tp->t_inbuf == tc->tbc_recsize) 169*25412Ssam (*tc->tbc_decode)(tbp->cbuf, &tbp->rets); 1707297Ssam } 1717297Ssam 1727297Ssam /* 173*25412Ssam * Decode GTCO 8 byte format (high res, tilt, and pressure). 1747297Ssam */ 175*25412Ssam static 176*25412Ssam gtcodecode(cp, tbpos) 1777297Ssam register char *cp; 178*25412Ssam register struct gtcopos *tbpos; 1797297Ssam { 1807297Ssam 181*25412Ssam tbpos->pressure = *cp >> 2; 182*25412Ssam tbpos->status = (tbpos->pressure > 16) | TBINPROX; /* half way down */ 183*25412Ssam tbpos->xpos = (*cp++ & 03) << 14; 184*25412Ssam tbpos->xpos |= *cp++ << 7; 185*25412Ssam tbpos->xpos |= *cp++; 186*25412Ssam tbpos->ypos = (*cp++ & 03) << 14; 187*25412Ssam tbpos->ypos |= *cp++ << 7; 188*25412Ssam tbpos->ypos |= *cp++; 189*25412Ssam tbpos->xtilt = *cp++; 190*25412Ssam tbpos->ytilt = *cp++; 19114596Ssam tbpos->scount++; 1927297Ssam } 1937297Ssam 1947297Ssam /* 195*25412Ssam * Decode old Hitachi 5 byte format (low res). 1967297Ssam */ 197*25412Ssam static 19814596Ssam tbdecode(cp, tbpos) 1997297Ssam register char *cp; 20014596Ssam register struct tbpos *tbpos; 2017297Ssam { 2027297Ssam register char byte; 2037297Ssam 2047297Ssam byte = *cp++; 205*25412Ssam tbpos->status = (byte&0100) ? TBINPROX : 0; 2067297Ssam byte &= ~0100; 2078522Sroot if (byte > 036) 208*25412Ssam tbpos->status |= 1 << ((byte-040)/2); 209*25412Ssam tbpos->xpos = *cp++ << 7; 210*25412Ssam tbpos->xpos |= *cp++; 211*25412Ssam if (tbpos->xpos < 256) /* tablet wraps around at 256 */ 212*25412Ssam tbpos->status &= ~TBINPROX; /* make it out of proximity */ 213*25412Ssam tbpos->ypos = *cp++ << 7; 214*25412Ssam tbpos->ypos |= *cp++; 21514596Ssam tbpos->scount++; 2167297Ssam } 2177297Ssam 2187297Ssam /* 219*25412Ssam * Decode new Hitach 5-byte format (low res). 2207297Ssam */ 221*25412Ssam static 222*25412Ssam tblresdecode(cp, tbpos) 223*25412Ssam register char *cp; 224*25412Ssam register struct tbpos *tbpos; 225*25412Ssam { 226*25412Ssam 227*25412Ssam *cp &= ~0100; /* mask sync bit */ 228*25412Ssam tbpos->status = (*cp++ >> 2) | TBINPROX; 229*25412Ssam tbpos->xpos = *cp++; 230*25412Ssam tbpos->xpos |= *cp++ << 6; 231*25412Ssam tbpos->ypos = *cp++; 232*25412Ssam tbpos->ypos |= *cp++ << 6; 233*25412Ssam tbpos->scount++; 234*25412Ssam } 235*25412Ssam 236*25412Ssam /* 237*25412Ssam * Decode new Hitach 6-byte format (high res). 238*25412Ssam */ 239*25412Ssam static 240*25412Ssam tbhresdecode(cp, tbpos) 241*25412Ssam register char *cp; 242*25412Ssam register struct tbpos *tbpos; 243*25412Ssam { 244*25412Ssam char byte; 245*25412Ssam 246*25412Ssam byte = *cp++; 247*25412Ssam tbpos->xpos = (byte & 03) << 14; 248*25412Ssam tbpos->xpos |= *cp++ << 7; 249*25412Ssam tbpos->xpos |= *cp++; 250*25412Ssam tbpos->ypos = *cp++ << 14; 251*25412Ssam tbpos->ypos |= *cp++ << 7; 252*25412Ssam tbpos->ypos |= *cp++; 253*25412Ssam tbpos->status = (byte >> 2) | TBINPROX; 254*25412Ssam tbpos->scount++; 255*25412Ssam } 256*25412Ssam 257*25412Ssam /* 258*25412Ssam * Polhemus decode. 259*25412Ssam */ 260*25412Ssam static 261*25412Ssam poldecode(cp, polpos) 262*25412Ssam register char *cp; 263*25412Ssam register struct polpos *polpos; 264*25412Ssam { 265*25412Ssam 266*25412Ssam polpos->p_x = cp[4] | cp[3]<<7 | (cp[9] & 0x03) << 14; 267*25412Ssam polpos->p_y = cp[6] | cp[5]<<7 | (cp[9] & 0x0c) << 12; 268*25412Ssam polpos->p_z = cp[8] | cp[7]<<7 | (cp[9] & 0x30) << 10; 269*25412Ssam polpos->p_azi = cp[11] | cp[10]<<7 | (cp[16] & 0x03) << 14; 270*25412Ssam polpos->p_pit = cp[13] | cp[12]<<7 | (cp[16] & 0x0c) << 12; 271*25412Ssam polpos->p_rol = cp[15] | cp[14]<<7 | (cp[16] & 0x30) << 10; 272*25412Ssam polpos->p_stat = cp[1] | cp[0]<<7; 273*25412Ssam if (cp[2] != ' ') 274*25412Ssam polpos->p_key = cp[2]; 275*25412Ssam } 276*25412Ssam 2777297Ssam /*ARGSUSED*/ 2787632Ssam tbioctl(tp, cmd, data, flag) 2797632Ssam struct tty *tp; 2807632Ssam caddr_t data; 2817297Ssam { 282*25412Ssam register struct tb *tbp = (struct tb *)tp->T_LINEP; 2837297Ssam 2847297Ssam switch (cmd) { 2857297Ssam 286*25412Ssam case BIOGMODE: 287*25412Ssam *(int *)data = tbp->tbflags & TBMODE; 288*25412Ssam break; 289*25412Ssam 290*25412Ssam case BIOSTYPE: 291*25412Ssam if (tbconf[*(int *)data & TBTYPE].tbc_recsize == 0 || 292*25412Ssam tbconf[*(int *)data & TBTYPE].tbc_decode == 0) 293*25412Ssam return (EINVAL); 294*25412Ssam tbp->tbflags &= ~TBTYPE; 295*25412Ssam tbp->tbflags |= *(int *)data & TBTYPE; 296*25412Ssam /* fall thru... to set mode bits */ 297*25412Ssam 298*25412Ssam case BIOSMODE: { 299*25412Ssam register struct tbconf *tc; 300*25412Ssam 301*25412Ssam tbp->tbflags &= ~TBMODE; 302*25412Ssam tbp->tbflags |= *(int *)data & TBMODE; 303*25412Ssam tc = &tbconf[tbp->tbflags & TBTYPE]; 304*25412Ssam if (tbp->tbflags&TBSTOP) { 305*25412Ssam if (tc->tbc_stop) 306*25412Ssam ttyout(tc->tbc_stop, tp); 307*25412Ssam } else if (tc->tbc_start) 308*25412Ssam ttyout(tc->tbc_start, tp); 309*25412Ssam if (tbp->tbflags&TBPOINT) { 310*25412Ssam if (tc->tbc_point) 311*25412Ssam ttyout(tc->tbc_point, tp); 312*25412Ssam } else if (tc->tbc_run) 313*25412Ssam ttyout(tc->tbc_run, tp); 314*25412Ssam ttstart(tp); 315*25412Ssam break; 316*25412Ssam } 317*25412Ssam 318*25412Ssam case BIOGTYPE: 319*25412Ssam *(int *)data = tbp->tbflags & TBTYPE; 320*25412Ssam break; 321*25412Ssam 3227297Ssam case TIOCSETD: 3237297Ssam case TIOCGETD: 3247297Ssam case TIOCGETP: 3257297Ssam case TIOCGETC: 326*25412Ssam return (-1); /* pass thru... */ 327*25412Ssam 328*25412Ssam default: 329*25412Ssam return (ENOTTY); 3307297Ssam } 3317297Ssam return (0); 3327297Ssam } 3337297Ssam #endif 334