1: /* 2: * Copyright (c) 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 1.2 (2.11BSD GTE) 11/29/94 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 "user.h" 19: #include "tablet.h" 20: #include "tty.h" 21: #include "proc.h" 22: #include "inode.h" 23: #include "file.h" 24: #include "buf.h" 25: #include "uio.h" 26: 27: /* 28: * Tablet configuration table. 29: */ 30: struct tbconf { 31: short tbc_recsize; /* input record size in bytes */ 32: short tbc_uiosize; /* size of data record returned user */ 33: int tbc_sync; /* mask for finding sync byte/bit */ 34: int (*tbc_decode)();/* decoding routine */ 35: char *tbc_run; /* enter run mode sequence */ 36: char *tbc_point; /* enter point mode sequence */ 37: char *tbc_stop; /* stop sequence */ 38: char *tbc_start; /* start/restart sequence */ 39: int tbc_flags; 40: #define TBF_POL 0x1 /* polhemus hack */ 41: }; 42: 43: static int tbdecode(), gtcodecode(), poldecode(); 44: static int tblresdecode(), tbhresdecode(); 45: 46: struct tbconf tbconf[TBTYPE] = { 47: { 0 }, 48: { 5, sizeof (struct tbpos), 0200, tbdecode, "6", "4" }, 49: { 5, sizeof (struct tbpos), 0200, tbdecode, "\1CN", "\1RT", "\2", "\4" }, 50: { 8, sizeof (struct gtcopos), 0200, gtcodecode }, 51: {17, sizeof (struct polpos), 0200, poldecode, 0, 0, "\21", "\5\22\2\23", 52: TBF_POL }, 53: { 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CN", "\1PT", "\2", "\4"}, 54: { 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CN", "\1PT", "\2", "\4"}, 55: }; 56: 57: /* 58: * Tablet state 59: */ 60: struct tb { 61: int tbflags; /* mode & type bits */ 62: #define TBMAXREC 17 /* max input record size */ 63: char cbuf[TBMAXREC]; /* input buffer */ 64: union { 65: struct tbpos tbpos; 66: struct gtcopos gtcopos; 67: struct polpos polpos; 68: } rets; /* processed state */ 69: #define NTBS 16 70: } tb[NTBS]; 71: 72: /* 73: * Open as tablet discipline; called on discipline change. 74: */ 75: /*ARGSUSED*/ 76: tbopen(dev, tp) 77: dev_t dev; 78: register struct tty *tp; 79: { 80: register struct tb *tbp; 81: 82: if (tp->t_line == TABLDISC) 83: return (ENODEV); 84: ttywflush(tp); 85: for (tbp = tb; tbp < &tb[NTBS]; tbp++) 86: if (tbp->tbflags == 0) 87: break; 88: if (tbp >= &tb[NTBS]) 89: return (EBUSY); 90: tbp->tbflags = TBTIGER|TBPOINT; /* default */ 91: tp->t_cp = tbp->cbuf; 92: tp->t_inbuf = 0; 93: bzero((caddr_t)&tbp->rets, sizeof (tbp->rets)); 94: tp->T_LINEP = (caddr_t)tbp; 95: tp->t_flags |= LITOUT; 96: return (0); 97: } 98: 99: /* 100: * Line discipline change or last device close. 101: */ 102: tbclose(tp, flag) 103: register struct tty *tp; 104: int flag; 105: { 106: register int s; 107: int modebits = TBPOINT|TBSTOP; 108: 109: tbioctl(tp, (u_int)(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, flag) 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); 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: u_int cmd; 281: caddr_t data; 282: { 283: register struct tb *tbp = (struct tb *)tp->T_LINEP; 284: 285: switch (cmd) { 286: 287: case BIOGMODE: 288: *(int *)data = tbp->tbflags & TBMODE; 289: break; 290: 291: case BIOSTYPE: 292: if (tbconf[*(int *)data & TBTYPE].tbc_recsize == 0 || 293: tbconf[*(int *)data & TBTYPE].tbc_decode == 0) 294: return (EINVAL); 295: tbp->tbflags &= ~TBTYPE; 296: tbp->tbflags |= *(int *)data & TBTYPE; 297: /* fall thru... to set mode bits */ 298: 299: case BIOSMODE: { 300: register struct tbconf *tc; 301: 302: tbp->tbflags &= ~TBMODE; 303: tbp->tbflags |= *(int *)data & TBMODE; 304: tc = &tbconf[tbp->tbflags & TBTYPE]; 305: if (tbp->tbflags&TBSTOP) { 306: if (tc->tbc_stop) 307: ttyout(tc->tbc_stop, tp); 308: } else if (tc->tbc_start) 309: ttyout(tc->tbc_start, tp); 310: if (tbp->tbflags&TBPOINT) { 311: if (tc->tbc_point) 312: ttyout(tc->tbc_point, tp); 313: } else if (tc->tbc_run) 314: ttyout(tc->tbc_run, tp); 315: ttstart(tp); 316: break; 317: } 318: 319: case BIOGTYPE: 320: *(int *)data = tbp->tbflags & TBTYPE; 321: break; 322: 323: case TIOCSETD: 324: case TIOCGETD: 325: case TIOCGETP: 326: case TIOCGETC: 327: return (-1); /* pass thru... */ 328: 329: default: 330: return (ENOTTY); 331: } 332: return (0); 333: } 334: #endif