1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)tty_tb.c 7.1 (Berkeley) 6/5/86 7: */ 8: 9: #include "tb.h" 10: #if NTB > 0 11: 12: /* 13: * Line discipline for RS232 tablets; 14: * supplies binary coordinate data. 15: */ 16: #include "param.h" 17: #include "systm.h" 18: #include "dir.h" 19: #include "user.h" 20: #include "tablet.h" 21: #include "tty.h" 22: #include "proc.h" 23: #include "inode.h" 24: #include "file.h" 25: #include "buf.h" 26: #include "uio.h" 27: 28: /* 29: * Tablet configuration table. 30: */ 31: struct tbconf { 32: short tbc_recsize; /* input record size in bytes */ 33: short tbc_uiosize; /* size of data record returned user */ 34: int tbc_sync; /* mask for finding sync byte/bit */ 35: int (*tbc_decode)();/* decoding routine */ 36: char *tbc_run; /* enter run mode sequence */ 37: char *tbc_point; /* enter point mode sequence */ 38: char *tbc_stop; /* stop sequence */ 39: char *tbc_start; /* start/restart sequence */ 40: int tbc_flags; 41: #define TBF_POL 0x1 /* polhemus hack */ 42: }; 43: 44: static int tbdecode(), gtcodecode(), poldecode(); 45: static int tblresdecode(), tbhresdecode(); 46: 47: struct tbconf tbconf[TBTYPE] = { 48: { 0 }, 49: { 5, sizeof (struct tbpos), 0200, tbdecode, "6", "4" }, 50: { 5, sizeof (struct tbpos), 0200, tbdecode, "\1CN", "\1RT", "\2", "\4" }, 51: { 8, sizeof (struct gtcopos), 0200, gtcodecode }, 52: {17, sizeof (struct polpos), 0200, poldecode, 0, 0, "\21", "\5\22\2\23", 53: TBF_POL }, 54: { 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CN", "\1PT", "\2", "\4"}, 55: { 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CN", "\1PT", "\2", "\4"}, 56: }; 57: 58: /* 59: * Tablet state 60: */ 61: struct tb { 62: int tbflags; /* mode & type bits */ 63: #define TBMAXREC 17 /* max input record size */ 64: char cbuf[TBMAXREC]; /* input buffer */ 65: union { 66: struct tbpos tbpos; 67: struct gtcopos gtcopos; 68: struct polpos polpos; 69: } rets; /* processed state */ 70: #define NTBS 16 71: } tb[NTBS]; 72: 73: /* 74: * Open as tablet discipline; called on discipline change. 75: */ 76: /*ARGSUSED*/ 77: tbopen(dev, tp) 78: dev_t dev; 79: register struct tty *tp; 80: { 81: register struct tb *tbp; 82: 83: if (tp->t_line == TABLDISC) 84: return (ENODEV); 85: ttywflush(tp); 86: for (tbp = tb; tbp < &tb[NTBS]; tbp++) 87: if (tbp->tbflags == 0) 88: break; 89: if (tbp >= &tb[NTBS]) 90: return (EBUSY); 91: tbp->tbflags = TBTIGER|TBPOINT; /* default */ 92: tp->t_cp = tbp->cbuf; 93: tp->t_inbuf = 0; 94: bzero((caddr_t)&tbp->rets, sizeof (tbp->rets)); 95: tp->T_LINEP = (caddr_t)tbp; 96: tp->t_flags |= LITOUT; 97: return (0); 98: } 99: 100: /* 101: * Line discipline change or last device close. 102: */ 103: tbclose(tp) 104: register struct tty *tp; 105: { 106: register int s; 107: int modebits = TBPOINT|TBSTOP; 108: 109: tbioctl(tp, BIOSMODE, &modebits, 0); 110: s = spl5(); 111: ((struct tb *)tp->T_LINEP)->tbflags = 0; 112: tp->t_cp = 0; 113: tp->t_inbuf = 0; 114: tp->t_rawq.c_cc = 0; /* clear queues -- paranoid */ 115: tp->t_canq.c_cc = 0; 116: tp->t_line = 0; /* paranoid: avoid races */ 117: splx(s); 118: } 119: 120: /* 121: * Read from a tablet line. 122: * Characters have been buffered in a buffer and decoded. 123: */ 124: tbread(tp, uio) 125: register struct tty *tp; 126: struct uio *uio; 127: { 128: register struct tb *tbp = (struct tb *)tp->T_LINEP; 129: register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE]; 130: int ret; 131: 132: if ((tp->t_state&TS_CARR_ON) == 0) 133: return (EIO); 134: ret = uiomove(&tbp->rets, tc->tbc_uiosize, UIO_READ, uio); 135: if (tc->tbc_flags&TBF_POL) 136: tbp->rets.polpos.p_key = ' '; 137: return (ret); 138: } 139: 140: /* 141: * Low level character input routine. 142: * Stuff the character in the buffer, and decode 143: * if all the chars are there. 144: * 145: * This routine could be expanded in-line in the receiver 146: * interrupt routine to make it run as fast as possible. 147: */ 148: tbinput(c, tp) 149: register int c; 150: register struct tty *tp; 151: { 152: register struct tb *tbp = (struct tb *)tp->T_LINEP; 153: register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE]; 154: 155: if (tc->tbc_recsize == 0 || tc->tbc_decode == 0) /* paranoid? */ 156: return; 157: /* 158: * Locate sync bit/byte or reset input buffer. 159: */ 160: if (c&tc->tbc_sync || tp->t_inbuf == tc->tbc_recsize) { 161: tp->t_cp = tbp->cbuf; 162: tp->t_inbuf = 0; 163: } 164: *tp->t_cp++ = c&0177; 165: /* 166: * Call decode routine only if a full record has been collected. 167: */ 168: if (++tp->t_inbuf == tc->tbc_recsize) 169: (*tc->tbc_decode)(tbp->cbuf, &tbp->rets); 170: } 171: 172: /* 173: * Decode GTCO 8 byte format (high res, tilt, and pressure). 174: */ 175: static 176: gtcodecode(cp, tbpos) 177: register char *cp; 178: register struct gtcopos *tbpos; 179: { 180: 181: tbpos->pressure = *cp >> 2; 182: tbpos->status = (tbpos->pressure > 16) | TBINPROX; /* half way down */ 183: tbpos->xpos = (*cp++ & 03) << 14; 184: tbpos->xpos |= *cp++ << 7; 185: tbpos->xpos |= *cp++; 186: tbpos->ypos = (*cp++ & 03) << 14; 187: tbpos->ypos |= *cp++ << 7; 188: tbpos->ypos |= *cp++; 189: tbpos->xtilt = *cp++; 190: tbpos->ytilt = *cp++; 191: tbpos->scount++; 192: } 193: 194: /* 195: * Decode old Hitachi 5 byte format (low res). 196: */ 197: static 198: tbdecode(cp, tbpos) 199: register char *cp; 200: register struct tbpos *tbpos; 201: { 202: register char byte; 203: 204: byte = *cp++; 205: tbpos->status = (byte&0100) ? TBINPROX : 0; 206: byte &= ~0100; 207: if (byte > 036) 208: tbpos->status |= 1 << ((byte-040)/2); 209: tbpos->xpos = *cp++ << 7; 210: tbpos->xpos |= *cp++; 211: if (tbpos->xpos < 256) /* tablet wraps around at 256 */ 212: tbpos->status &= ~TBINPROX; /* make it out of proximity */ 213: tbpos->ypos = *cp++ << 7; 214: tbpos->ypos |= *cp++; 215: tbpos->scount++; 216: } 217: 218: /* 219: * Decode new Hitach 5-byte format (low res). 220: */ 221: static 222: tblresdecode(cp, tbpos) 223: register char *cp; 224: register struct tbpos *tbpos; 225: { 226: 227: *cp &= ~0100; /* mask sync bit */ 228: tbpos->status = (*cp++ >> 2) | TBINPROX; 229: tbpos->xpos = *cp++; 230: tbpos->xpos |= *cp++ << 6; 231: tbpos->ypos = *cp++; 232: tbpos->ypos |= *cp++ << 6; 233: tbpos->scount++; 234: } 235: 236: /* 237: * Decode new Hitach 6-byte format (high res). 238: */ 239: static 240: tbhresdecode(cp, tbpos) 241: register char *cp; 242: register struct tbpos *tbpos; 243: { 244: char byte; 245: 246: byte = *cp++; 247: tbpos->xpos = (byte & 03) << 14; 248: tbpos->xpos |= *cp++ << 7; 249: tbpos->xpos |= *cp++; 250: tbpos->ypos = *cp++ << 14; 251: tbpos->ypos |= *cp++ << 7; 252: tbpos->ypos |= *cp++; 253: tbpos->status = (byte >> 2) | TBINPROX; 254: tbpos->scount++; 255: } 256: 257: /* 258: * Polhemus decode. 259: */ 260: static 261: poldecode(cp, polpos) 262: register char *cp; 263: register struct polpos *polpos; 264: { 265: 266: polpos->p_x = cp[4] | cp[3]<<7 | (cp[9] & 0x03) << 14; 267: polpos->p_y = cp[6] | cp[5]<<7 | (cp[9] & 0x0c) << 12; 268: polpos->p_z = cp[8] | cp[7]<<7 | (cp[9] & 0x30) << 10; 269: polpos->p_azi = cp[11] | cp[10]<<7 | (cp[16] & 0x03) << 14; 270: polpos->p_pit = cp[13] | cp[12]<<7 | (cp[16] & 0x0c) << 12; 271: polpos->p_rol = cp[15] | cp[14]<<7 | (cp[16] & 0x30) << 10; 272: polpos->p_stat = cp[1] | cp[0]<<7; 273: if (cp[2] != ' ') 274: polpos->p_key = cp[2]; 275: } 276: 277: /*ARGSUSED*/ 278: tbioctl(tp, cmd, data, flag) 279: struct tty *tp; 280: caddr_t data; 281: { 282: register struct tb *tbp = (struct tb *)tp->T_LINEP; 283: 284: switch (cmd) { 285: 286: case BIOGMODE: 287: *(int *)data = tbp->tbflags & TBMODE; 288: break; 289: 290: case BIOSTYPE: 291: if (tbconf[*(int *)data & TBTYPE].tbc_recsize == 0 || 292: tbconf[*(int *)data & TBTYPE].tbc_decode == 0) 293: return (EINVAL); 294: tbp->tbflags &= ~TBTYPE; 295: tbp->tbflags |= *(int *)data & TBTYPE; 296: /* fall thru... to set mode bits */ 297: 298: case BIOSMODE: { 299: register struct tbconf *tc; 300: 301: tbp->tbflags &= ~TBMODE; 302: tbp->tbflags |= *(int *)data & TBMODE; 303: tc = &tbconf[tbp->tbflags & TBTYPE]; 304: if (tbp->tbflags&TBSTOP) { 305: if (tc->tbc_stop) 306: ttyout(tc->tbc_stop, tp); 307: } else if (tc->tbc_start) 308: ttyout(tc->tbc_start, tp); 309: if (tbp->tbflags&TBPOINT) { 310: if (tc->tbc_point) 311: ttyout(tc->tbc_point, tp); 312: } else if (tc->tbc_run) 313: ttyout(tc->tbc_run, tp); 314: ttstart(tp); 315: break; 316: } 317: 318: case BIOGTYPE: 319: *(int *)data = tbp->tbflags & TBTYPE; 320: break; 321: 322: case TIOCSETD: 323: case TIOCGETD: 324: case TIOCGETP: 325: case TIOCGETC: 326: return (-1); /* pass thru... */ 327: 328: default: 329: return (ENOTTY); 330: } 331: return (0); 332: } 333: #endif