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