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