1/* tty_chu.c,v 3.1 1993/07/06 01:07:30 jbj Exp 2 * tty_chu.c - CHU line driver 3 */ 4 5#include "chu.h" 6#if NCHU > 0 7 8#include "../h/param.h" 9#include "../h/types.h" 10#include "../h/systm.h" 11#include "../h/dir.h" 12#include "../h/user.h" 13#include "../h/ioctl.h" 14#include "../h/tty.h" 15#include "../h/proc.h" 16#include "../h/file.h" 17#include "../h/conf.h" 18#include "../h/buf.h" 19#include "../h/uio.h" 20 21#include "../h/chudefs.h" 22 23/* 24 * Line discipline for receiving CHU time codes. 25 * Does elementary noise elimination, takes time stamps after 26 * the arrival of each character, returns a buffer full of the 27 * received 10 character code and the associated time stamps. 28 */ 29#define NUMCHUBUFS 3 30 31struct chudata { 32 u_char used; /* Set to 1 when structure in use */ 33 u_char lastindex; /* least recently used buffer */ 34 u_char curindex; /* buffer to use */ 35 u_char sleeping; /* set to 1 when we're sleeping on a buffer */ 36 struct chucode chubuf[NUMCHUBUFS]; 37} chu_data[NCHU]; 38 39/* 40 * Number of microseconds we allow between 41 * character arrivals. The speed is 300 baud 42 * so this should be somewhat more than 30 msec 43 */ 44#define CHUMAXUSEC (50*1000) /* 50 msec */ 45 46int chu_debug = 0; 47 48/* 49 * Open as CHU time discipline. Called when discipline changed 50 * with ioctl, and changes the interpretation of the information 51 * in the tty structure. 52 */ 53/*ARGSUSED*/ 54chuopen(dev, tp) 55 dev_t dev; 56 register struct tty *tp; 57{ 58 register struct chudata *chu; 59 60 /* 61 * Don't allow multiple opens. This will also protect us 62 * from someone opening /dev/tty 63 */ 64 if (tp->t_line == CHULDISC) 65 return (EBUSY); 66 ttywflush(tp); 67 for (chu = chu_data; chu < &chu_data[NCHU]; chu++) 68 if (!chu->used) 69 break; 70 if (chu >= &chu[NCHU]) 71 return (EBUSY); 72 chu->used++; 73 chu->lastindex = chu->curindex = 0; 74 chu->sleeping = 0; 75 chu->chubuf[0].ncodechars = 0; 76 tp->T_LINEP = (caddr_t) chu; 77 return (0); 78} 79 80/* 81 * Break down... called when discipline changed or from device 82 * close routine. 83 */ 84chuclose(tp) 85 register struct tty *tp; 86{ 87 register int s = spl5(); 88 89 ((struct chudata *) tp->T_LINEP)->used = 0; 90 tp->t_cp = 0; 91 tp->t_inbuf = 0; 92 tp->t_rawq.c_cc = 0; /* clear queues -- paranoid */ 93 tp->t_canq.c_cc = 0; 94 tp->t_line = 0; /* paranoid: avoid races */ 95 splx(s); 96} 97 98/* 99 * Read a CHU buffer. Sleep on the current buffer 100 */ 101churead(tp, uio) 102 register struct tty *tp; 103 struct uio *uio; 104{ 105 register struct chudata *chu; 106 register struct chucode *chucode; 107 register int s; 108 109 if ((tp->t_state&TS_CARR_ON)==0) 110 return (EIO); 111 112 chu = (struct chudata *) (tp->T_LINEP); 113 114 s = spl5(); 115 chucode = &(chu->chubuf[chu->lastindex]); 116 while (chu->curindex == chu->lastindex) { 117 chu->sleeping = 1; 118 sleep((caddr_t)chucode, TTIPRI); 119 } 120 chu->sleeping = 0; 121 if (++(chu->lastindex) >= NUMCHUBUFS) 122 chu->lastindex = 0; 123 splx(s); 124 125 return (uiomove((caddr_t)chucode, sizeof(*chucode), UIO_READ, uio)); 126} 127 128/* 129 * Low level character input routine. 130 * If the character looks okay, grab a time stamp. If the stuff in 131 * the buffer is too old, dump it and start fresh. If the character is 132 * non-BCDish, everything in the buffer too. 133 */ 134chuinput(c, tp) 135 register int c; 136 register struct tty *tp; 137{ 138 register struct chudata *chu = (struct chudata *) tp->T_LINEP; 139 register struct chucode *chuc; 140 register int i; 141 long sec, usec; 142 struct timeval tv; 143 144 /* 145 * Do a check on the BSDness of the character. This delays 146 * the time stamp a bit but saves a fair amount of overhead 147 * when the static is bad. 148 */ 149 if (((c) & 0xf) > 9 || (((c)>>4) & 0xf) > 9) { 150 chuc = &(chu->chubuf[chu->curindex]); 151 chuc->ncodechars = 0; /* blow all previous away */ 152 return; 153 } 154 155 /* 156 * Call microtime() to get the current time of day 157 */ 158 microtime(&tv); 159 160 /* 161 * Compute the difference in this character's time stamp 162 * and the last. If it exceeds the margin, blow away all 163 * the characters currently in the buffer. 164 */ 165 chuc = &(chu->chubuf[chu->curindex]); 166 i = (int)chuc->ncodechars; 167 if (i > 0) { 168 sec = tv.tv_sec - chuc->codetimes[i-1].tv_sec; 169 usec = tv.tv_usec - chuc->codetimes[i-1].tv_usec; 170 if (usec < 0) { 171 sec -= 1; 172 usec += 1000000; 173 } 174 if (sec != 0 || usec > CHUMAXUSEC) { 175 i = 0; 176 chuc->ncodechars = 0; 177 } 178 } 179 180 /* 181 * Store the character. If we're done, have to tell someone 182 */ 183 chuc->codechars[i] = (u_char)c; 184 chuc->codetimes[i] = tv; 185 186 if (++i < NCHUCHARS) { 187 /* 188 * Not much to do here. Save the count and wait 189 * for another character. 190 */ 191 chuc->ncodechars = (u_char)i; 192 } else { 193 /* 194 * Mark this buffer full and point at next. If the 195 * next buffer is full we overwrite it by bumping the 196 * next pointer. 197 */ 198 chuc->ncodechars = NCHUCHARS; 199 if (++(chu->curindex) >= NUMCHUBUFS) 200 chu->curindex = 0; 201 if (chu->curindex == chu->lastindex) 202 if (++(chu->lastindex) >= NUMCHUBUFS) 203 chu->lastindex = 0; 204 chu->chubuf[chu->curindex].ncodechars = 0; 205 206 /* 207 * Wake up anyone sleeping on this. Also wake up 208 * selectors and/or deliver a SIGIO as required. 209 */ 210 if (tp->t_rsel) { 211 selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 212 tp->t_state &= ~TS_RCOLL; 213 tp->t_rsel = 0; 214 } 215 if (tp->t_state & TS_ASYNC) 216 gsignal(tp->t_pgrp, SIGIO); 217 if (chu->sleeping) 218 (void) wakeup((caddr_t)chuc); 219 } 220} 221 222/* 223 * Handle ioctls. We reject all tty-style except those that 224 * change the line discipline. 225 */ 226chuioctl(tp, cmd, data, flag) 227 struct tty *tp; 228 int cmd; 229 caddr_t data; 230 int flag; 231{ 232 233 if ((cmd>>8) != 't') 234 return (-1); 235 switch (cmd) { 236 case TIOCSETD: 237 case TIOCGETD: 238 case TIOCGETP: 239 case TIOCGETC: 240 return (-1); 241 } 242 return (ENOTTY); /* not quite appropriate */ 243} 244 245 246chuselect(dev, rw) 247 dev_t dev; 248 int rw; 249{ 250 register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 251 struct chudata *chu; 252 int s = spl5(); 253 254 chu = (struct chudata *) (tp->T_LINEP); 255 256 switch (rw) { 257 258 case FREAD: 259 if (chu->curindex != chu->lastindex) 260 goto win; 261 if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 262 tp->t_state |= TS_RCOLL; 263 else 264 tp->t_rsel = u.u_procp; 265 break; 266 267 case FWRITE: 268 goto win; 269 } 270 splx(s); 271 return (0); 272win: 273 splx(s); 274 return (1); 275} 276#endif NCHU 277