/contrib/ntp/kernel/tty_clk.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 317 lines · 179 code · 34 blank · 104 comment · 41 complexity · 05111714387d8f2888974820da9dd0ad MD5 · raw file

  1. /* tty_clk.c,v 3.1 1993/07/06 01:07:33 jbj Exp
  2. * tty_clk.c - Generic line driver for receiving radio clock timecodes
  3. */
  4. #include "clk.h"
  5. #if NCLK > 0
  6. #include "../h/param.h"
  7. #include "../h/types.h"
  8. #include "../h/systm.h"
  9. #include "../h/dir.h"
  10. #include "../h/user.h"
  11. #include "../h/ioctl.h"
  12. #include "../h/tty.h"
  13. #include "../h/proc.h"
  14. #include "../h/file.h"
  15. #include "../h/conf.h"
  16. #include "../h/buf.h"
  17. #include "../h/uio.h"
  18. #include "../h/clist.h"
  19. /*
  20. * This line discipline is intended to provide well performing
  21. * generic support for the reception and time stamping of radio clock
  22. * timecodes. Most radio clock devices return a string where a
  23. * particular character in the code (usually a \r) is on-time
  24. * synchronized with the clock. The idea here is to collect characters
  25. * until (one of) the synchronization character(s) (we allow two) is seen.
  26. * When the magic character arrives we take a timestamp by calling
  27. * microtime() and insert the eight bytes of struct timeval into the
  28. * buffer after the magic character. We then wake up anyone waiting
  29. * for the buffer and return the whole mess on the next read.
  30. *
  31. * To use this the calling program is expected to first open the
  32. * port, and then to set the port into raw mode with the speed
  33. * set appropriately with a TIOCSETP ioctl(), with the erase and kill
  34. * characters set to those to be considered magic (yes, I know this
  35. * is gross, but they were so convenient). If only one character is
  36. * magic you can set then both the same, or perhaps to the alternate
  37. * parity versions of said character. After getting all this set,
  38. * change the line discipline to CLKLDISC and you are on your way.
  39. *
  40. * The only other bit of magic we do in here is to flush the receive
  41. * buffers on writes if the CRMOD flag is set (hack, hack).
  42. */
  43. /*
  44. * We run this very much like a raw mode terminal, with the exception
  45. * that we store up characters locally until we hit one of the
  46. * magic ones and then dump it into the rawq all at once. We keep
  47. * the buffered data in clists since we can then often move it to
  48. * the rawq without copying. For sanity we limit the number of
  49. * characters between specials, and the total number of characters
  50. * before we flush the rawq, as follows.
  51. */
  52. #define CLKLINESIZE (256)
  53. #define NCLKCHARS (CLKLINESIZE*4)
  54. struct clkdata {
  55. int inuse;
  56. struct clist clkbuf;
  57. };
  58. #define clk_cc clkbuf.c_cc
  59. #define clk_cf clkbuf.c_cf
  60. #define clk_cl clkbuf.c_cl
  61. struct clkdata clk_data[NCLK];
  62. /*
  63. * Routine for flushing the internal clist
  64. */
  65. #define clk_bflush(clk) (ndflush(&((clk)->clkbuf), (clk)->clk_cc))
  66. int clk_debug = 0;
  67. /*ARGSUSED*/
  68. clkopen(dev, tp)
  69. dev_t dev;
  70. register struct tty *tp;
  71. {
  72. register struct clkdata *clk;
  73. /*
  74. * Don't allow multiple opens. This will also protect us
  75. * from someone opening /dev/tty
  76. */
  77. if (tp->t_line == CLKLDISC)
  78. return (EBUSY);
  79. ttywflush(tp);
  80. for (clk = clk_data; clk < &clk_data[NCLK]; clk++)
  81. if (!clk->inuse)
  82. break;
  83. if (clk >= &clk_data[NCLK])
  84. return (EBUSY);
  85. clk->inuse++;
  86. clk->clk_cc = 0;
  87. clk->clk_cf = clk->clk_cl = NULL;
  88. tp->T_LINEP = (caddr_t) clk;
  89. return (0);
  90. }
  91. /*
  92. * Break down... called when discipline changed or from device
  93. * close routine.
  94. */
  95. clkclose(tp)
  96. register struct tty *tp;
  97. {
  98. register struct clkdata *clk;
  99. register int s = spltty();
  100. clk = (struct clkdata *)tp->T_LINEP;
  101. if (clk->clk_cc > 0)
  102. clk_bflush(clk);
  103. clk->inuse = 0;
  104. tp->t_line = 0; /* paranoid: avoid races */
  105. splx(s);
  106. }
  107. /*
  108. * Receive a write request. We pass these requests on to the terminal
  109. * driver, except that if the CRMOD bit is set in the flags we
  110. * first flush the input queues.
  111. */
  112. clkwrite(tp, uio)
  113. register struct tty *tp;
  114. struct uio *uio;
  115. {
  116. if (tp->t_flags & CRMOD) {
  117. register struct clkdata *clk;
  118. int s;
  119. s = spltty();
  120. if (tp->t_rawq.c_cc > 0)
  121. ndflush(&tp->t_rawq, tp->t_rawq.c_cc);
  122. clk = (struct clkdata *) tp->T_LINEP;
  123. if (clk->clk_cc > 0)
  124. clk_bflush(clk);
  125. (void)splx(s);
  126. }
  127. ttwrite(tp, uio);
  128. }
  129. /*
  130. * Low level character input routine.
  131. * If the character looks okay, grab a time stamp. If the stuff in
  132. * the buffer is too old, dump it and start fresh. If the character is
  133. * non-BCDish, everything in the buffer too.
  134. */
  135. clkinput(c, tp)
  136. register int c;
  137. register struct tty *tp;
  138. {
  139. register struct clkdata *clk;
  140. register int i;
  141. register long s;
  142. struct timeval tv;
  143. /*
  144. * Check to see whether this isn't the magic character. If not,
  145. * save the character and return.
  146. */
  147. #ifdef ultrix
  148. if (c != tp->t_cc[VERASE] && c != tp->t_cc[VKILL]) {
  149. #else
  150. if (c != tp->t_erase && c != tp->t_kill) {
  151. #endif
  152. clk = (struct clkdata *) tp->T_LINEP;
  153. if (clk->clk_cc >= CLKLINESIZE)
  154. clk_bflush(clk);
  155. if (putc(c, &clk->clkbuf) == -1) {
  156. /*
  157. * Hopeless, no clists. Flush what we have
  158. * and hope things improve.
  159. */
  160. clk_bflush(clk);
  161. }
  162. return;
  163. }
  164. /*
  165. * Here we have a magic character. Get a timestamp and store
  166. * everything.
  167. */
  168. microtime(&tv);
  169. clk = (struct clkdata *) tp->T_LINEP;
  170. if (putc(c, &clk->clkbuf) == -1)
  171. goto flushout;
  172. #ifdef CLKLDISC
  173. /*
  174. * STREAMS people started writing timestamps this way.
  175. * It's not my fault, I am just going along with the flow...
  176. */
  177. for (i = 0; i < sizeof(struct timeval); i++)
  178. if (putc(*( ((char*)&tv) + i ), &clk->clkbuf) == -1)
  179. goto flushout;
  180. #else
  181. /*
  182. * This is a machine independant way of puting longs into
  183. * the datastream. It has fallen into disuse...
  184. */
  185. s = tv.tv_sec;
  186. for (i = 0; i < sizeof(long); i++) {
  187. if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
  188. goto flushout;
  189. s <<= 8;
  190. }
  191. s = tv.tv_usec;
  192. for (i = 0; i < sizeof(long); i++) {
  193. if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
  194. goto flushout;
  195. s <<= 8;
  196. }
  197. #endif
  198. /*
  199. * If the length of the rawq exceeds our sanity limit, dump
  200. * all the old crap in there before copying this in.
  201. */
  202. if (tp->t_rawq.c_cc > NCLKCHARS)
  203. ndflush(&tp->t_rawq, tp->t_rawq.c_cc);
  204. /*
  205. * Now copy the buffer in. There is a special case optimization
  206. * here. If there is nothing on the rawq at present we can
  207. * just copy the clists we own over. Otherwise we must concatenate
  208. * the present data on the end.
  209. */
  210. s = (long)spltty();
  211. if (tp->t_rawq.c_cc <= 0) {
  212. tp->t_rawq = clk->clkbuf;
  213. clk->clk_cc = 0;
  214. clk->clk_cl = clk->clk_cf = NULL;
  215. (void) splx((int)s);
  216. } else {
  217. (void) splx((int)s);
  218. catq(&clk->clkbuf, &tp->t_rawq);
  219. clk_bflush(clk);
  220. }
  221. /*
  222. * Tell the world
  223. */
  224. ttwakeup(tp);
  225. return;
  226. flushout:
  227. /*
  228. * It would be nice if this never happened. Flush the
  229. * internal clists and hope someone else frees some of them
  230. */
  231. clk_bflush(clk);
  232. return;
  233. }
  234. /*
  235. * Handle ioctls. We reject most tty-style except those that
  236. * change the line discipline and a couple of others..
  237. */
  238. clkioctl(tp, cmd, data, flag)
  239. struct tty *tp;
  240. int cmd;
  241. caddr_t data;
  242. int flag;
  243. {
  244. int flags;
  245. struct sgttyb *sg;
  246. if ((cmd>>8) != 't')
  247. return (-1);
  248. switch (cmd) {
  249. case TIOCSETD:
  250. case TIOCGETD:
  251. case TIOCGETP:
  252. case TIOCGETC:
  253. case TIOCOUTQ:
  254. return (-1);
  255. case TIOCSETP:
  256. /*
  257. * He likely wants to set new magic characters in.
  258. * Do this part.
  259. */
  260. sg = (struct sgttyb *)data;
  261. #ifdef ultrix
  262. tp->t_cc[VERASE] = sg->sg_erase;
  263. tp->t_cc[VKILL] = sg->sg_kill;
  264. #else
  265. tp->t_erase = sg->sg_erase;
  266. tp->t_kill = sg->sg_kill;
  267. #endif
  268. return (0);
  269. case TIOCFLUSH:
  270. flags = *(int *)data;
  271. if (flags == 0 || (flags & FREAD)) {
  272. register struct clkdata *clk;
  273. clk = (struct clkdata *) tp->T_LINEP;
  274. if (clk->clk_cc > 0)
  275. clk_bflush(clk);
  276. }
  277. return (-1);
  278. default:
  279. break;
  280. }
  281. return (ENOTTY); /* not quite appropriate */
  282. }
  283. #endif NCLK