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