/contrib/ntp/kernel/tty_clk_STREAMS.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 266 lines · 162 code · 38 blank · 66 comment · 20 complexity · 3b74ab8bee09244d3a96dcac4d85fdc1 MD5 · raw file

  1. /* tty_clk_STREAMS.c,v 3.1 1993/07/06 01:07:34 jbj Exp
  2. * Timestamp STREAMS module for SunOS 4.1
  3. *
  4. * Copyright 1991, Nick Sayer
  5. *
  6. * Special thanks to Greg Onufer for his debug assists.
  7. *
  8. * Should be PUSHed directly on top of a serial I/O channel.
  9. * For any character in a user-designated set, adds a kernel
  10. * timestamp to that character.
  11. *
  12. * BUGS:
  13. *
  14. * Only so many characters can be timestamped. This number, however,
  15. * is adjustable.
  16. *
  17. * The null character ($00) cannot be timestamped.
  18. *
  19. * The M_DATA messages passed upstream will not be the same
  20. * size as when they arrive from downstream, even if no
  21. * timestamp character is in the message. This, however,
  22. * should not affect anything.
  23. *
  24. */
  25. #include "clk.h"
  26. #if NCLK > 0
  27. /*
  28. * How big should the messages we pass upstream be?
  29. */
  30. #define MESSAGE_SIZE 128
  31. #include <string.h>
  32. #include <sys/types.h>
  33. #include <sys/stream.h>
  34. #include <sys/param.h>
  35. #include <sys/time.h>
  36. #include <sys/kernel.h>
  37. #include <sys/user.h>
  38. #include <sys/errno.h>
  39. #include <sys/syslog.h>
  40. #include <sys/clkdefs.h>
  41. static struct module_info rminfo = { 0, "clk", 0, INFPSZ, 0, 0 };
  42. static struct module_info wminfo = { 0, "clk", 0, INFPSZ, 0, 0 };
  43. static int clkopen(), clkrput(), clkwput(), clkclose();
  44. static struct qinit rinit = { clkrput, NULL, clkopen, clkclose, NULL,
  45. &rminfo, NULL };
  46. static struct qinit winit = { clkwput, NULL, NULL, NULL, NULL,
  47. &wminfo, NULL };
  48. struct streamtab clkinfo = { &rinit, &winit, NULL, NULL };
  49. struct priv_data_type
  50. {
  51. char in_use;
  52. char string[CLK_MAXSTRSIZE];
  53. } priv_data[NCLK];
  54. char first_open=1;
  55. /*
  56. * God only knows why, but linking with strchr() fails
  57. * on my system, so here's a renamed copy.
  58. */
  59. u_char *str_chr(s,c)
  60. u_char *s;
  61. int c;
  62. {
  63. while (*s)
  64. if(*s++ == c)
  65. return (s-1);
  66. return NULL;
  67. }
  68. /*ARGSUSED*/
  69. static int clkopen(q, dev, flag, sflag)
  70. queue_t *q;
  71. dev_t dev;
  72. int flag;
  73. int sflag;
  74. {
  75. int i;
  76. /* Damn it! We can't even have the global data struct properly
  77. initialized! So we have a mark to tell us to init the global
  78. data on the first open */
  79. if (first_open)
  80. {
  81. first_open=0;
  82. for(i=0;i<NCLK;i++)
  83. priv_data[i].in_use=0;
  84. }
  85. for(i=0;i<NCLK;i++)
  86. if(!priv_data[i].in_use)
  87. {
  88. priv_data[i].in_use++;
  89. ((struct priv_data_type *) (q->q_ptr))=priv_data+i;
  90. priv_data[i].string[0]=0;
  91. return (0);
  92. }
  93. u.u_error = EBUSY;
  94. return (OPENFAIL);
  95. }
  96. /*ARGSUSED*/
  97. static int clkclose(q, flag)
  98. queue_t *q;
  99. int flag;
  100. {
  101. ((struct priv_data_type *) (q->q_ptr))->in_use=0;
  102. return (0);
  103. }
  104. /*
  105. * Now the crux of the biscuit.
  106. *
  107. * If it's an M_DATA package, we take each character and pass
  108. * it to clkchar.
  109. */
  110. void clkchar();
  111. static int clkrput(q, mp)
  112. queue_t *q;
  113. mblk_t *mp;
  114. {
  115. mblk_t *bp;
  116. switch(mp->b_datap->db_type)
  117. {
  118. case M_DATA:
  119. clkchar(0,q,2);
  120. for(bp=mp; bp!=NULL; bp=bp->b_cont)
  121. {
  122. while(bp->b_rptr < bp->b_wptr)
  123. clkchar( ((u_char)*(bp->b_rptr++)) , q , 0 );
  124. }
  125. clkchar(0,q,1);
  126. freemsg(mp);
  127. break;
  128. default:
  129. putnext(q,mp);
  130. break;
  131. }
  132. }
  133. /*
  134. * If it's a matching M_IOCTL, handle it.
  135. */
  136. static int clkwput(q, mp)
  137. queue_t *q;
  138. mblk_t *mp;
  139. {
  140. struct iocblk *iocp;
  141. switch(mp->b_datap->db_type)
  142. {
  143. case M_IOCTL:
  144. iocp=(struct iocblk*) mp->b_rptr;
  145. if (iocp->ioc_cmd==CLK_SETSTR)
  146. {
  147. strncpy( ((struct priv_data_type *) (RD(q)->q_ptr))->string,
  148. (char *) mp->b_cont->b_rptr,CLK_MAXSTRSIZE);
  149. /* make sure it's null terminated */
  150. ((struct priv_data_type *) (RD(q)->q_ptr))->string[CLK_MAXSTRSIZE-1]=0;
  151. mp->b_datap->db_type = M_IOCACK;
  152. qreply(q,mp);
  153. }
  154. else
  155. putnext(q,mp);
  156. break;
  157. default:
  158. putnext(q,mp);
  159. break;
  160. }
  161. }
  162. /*
  163. * Now clkchar. It takes a character, a queue pointer and an action
  164. * flag and depending on the flag either:
  165. *
  166. * 0 - adds the character to the current message. If there's a
  167. * timestamp to be done, do that too. If the message is less than
  168. * 8 chars from being full, link in a new one, and set it up for
  169. * the next call.
  170. *
  171. * 1 - sends the whole mess to Valhala.
  172. *
  173. * 2 - set things up.
  174. *
  175. * Yeah, it's an ugly hack. Complaints may be filed with /dev/null.
  176. */
  177. void clkchar(c,q,f)
  178. register u_char c;
  179. queue_t *q;
  180. char f;
  181. {
  182. static char error;
  183. static mblk_t *message,*mp;
  184. struct timeval tv;
  185. /* Get a timestamp ASAP! */
  186. uniqtime(&tv);
  187. switch(f)
  188. {
  189. case 1:
  190. if (!error)
  191. putnext(q,message);
  192. break;
  193. case 2:
  194. mp=message= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO);
  195. error=(message==NULL);
  196. if (error)
  197. log(LOG_ERR,"clk: cannot allocate message - data lost");
  198. break;
  199. case 0:
  200. if (error) /* If we had an error, forget it. */
  201. return;
  202. *mp->b_wptr++=c; /* Put the char away first.
  203. /* If it's in the special string, append a struct timeval */
  204. if (str_chr( ((struct priv_data_type *) (q->q_ptr))->string ,
  205. c )!=NULL)
  206. {
  207. int i;
  208. for (i=0;i<sizeof(struct timeval);i++)
  209. *mp->b_wptr++= *( ((char*)&tv) + i );
  210. }
  211. /* If we don't have space for a complete struct timeval, and a
  212. char, it's time for a new mp block */
  213. if (((mp->b_wptr-mp->b_rptr)+sizeof(struct timeval)+2)>MESSAGE_SIZE)
  214. {
  215. mp->b_cont= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO);
  216. error=(mp->b_cont==NULL);
  217. if (error)
  218. {
  219. log(LOG_ERR,"clk: cannot allocate message - data lost");
  220. freemsg(message);
  221. }
  222. mp=mp->b_cont;
  223. }
  224. break;
  225. }
  226. }
  227. #endif