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