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