]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/kernel/tty_clk_STREAMS.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / kernel / tty_clk_STREAMS.c
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
26 #include "clk.h"
27 #if NCLK > 0
28 /*
29  * How big should the messages we pass upstream be?
30  */
31 #define MESSAGE_SIZE 128
32
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/stream.h>
36 #include <sys/param.h>
37 #include <sys/time.h>
38 #include <sys/kernel.h>
39 #include <sys/user.h>
40 #include <sys/errno.h>
41 #include <sys/syslog.h>
42
43 #include <sys/clkdefs.h>
44
45 static struct module_info rminfo = { 0, "clk", 0, INFPSZ, 0, 0 };
46 static struct module_info wminfo = { 0, "clk", 0, INFPSZ, 0, 0 };
47 static int clkopen(), clkrput(), clkwput(), clkclose();
48
49 static struct qinit rinit = { clkrput, NULL, clkopen, clkclose, NULL,
50         &rminfo, NULL };
51
52 static struct qinit winit = { clkwput, NULL, NULL, NULL, NULL,
53         &wminfo, NULL };
54
55 struct streamtab clkinfo = { &rinit, &winit, NULL, NULL };
56
57 struct priv_data_type
58 {
59   char in_use;
60   char string[CLK_MAXSTRSIZE];
61 } priv_data[NCLK];
62
63 char first_open=1;
64
65 /*
66  * God only knows why, but linking with strchr() fails
67  * on my system, so here's a renamed copy.
68  */
69
70 u_char *str_chr(s,c)
71 u_char *s;
72 int c;
73 {
74   while (*s)
75     if(*s++ == c)
76       return (s-1);
77   return NULL;
78 }
79
80 /*ARGSUSED*/
81 static int clkopen(q, dev, flag, sflag)
82 queue_t *q;
83 dev_t dev;
84 int flag;
85 int sflag;
86 {
87   int i;
88
89 /* Damn it! We can't even have the global data struct properly
90    initialized! So we have a mark to tell us to init the global
91    data on the first open */
92
93   if (first_open)
94   {
95     first_open=0;
96
97     for(i=0;i<NCLK;i++)
98       priv_data[i].in_use=0;
99   }
100
101   for(i=0;i<NCLK;i++)
102     if(!priv_data[i].in_use)
103     {
104       priv_data[i].in_use++;
105       ((struct priv_data_type *) (q->q_ptr))=priv_data+i;
106       priv_data[i].string[0]=0;
107       return (0);
108     }
109   u.u_error = EBUSY;
110   return (OPENFAIL);
111 }
112
113 /*ARGSUSED*/
114 static int clkclose(q, flag)
115 queue_t *q;
116 int flag;
117 {
118   ((struct priv_data_type *) (q->q_ptr))->in_use=0;
119
120   return (0);
121 }
122
123 /*
124  * Now the crux of the biscuit.
125  *
126  * If it's an M_DATA package, we take each character and pass
127  * it to clkchar.
128  */
129
130 void clkchar();
131
132 static int clkrput(q, mp)
133 queue_t *q;
134 mblk_t *mp;
135 {
136   mblk_t *bp;
137
138   switch(mp->b_datap->db_type)
139   {
140     case M_DATA:
141       clkchar(0,q,2);
142       for(bp=mp; bp!=NULL; bp=bp->b_cont)
143       {
144         while(bp->b_rptr < bp->b_wptr)
145           clkchar( ((u_char)*(bp->b_rptr++)) , q , 0 );
146       }
147       clkchar(0,q,1);
148       freemsg(mp);
149     break;
150     default:
151       putnext(q,mp);
152     break;
153   }
154
155 }
156
157 /*
158  * If it's a matching M_IOCTL, handle it.
159  */
160
161 static int clkwput(q, mp)
162 queue_t *q;
163 mblk_t *mp;
164 {
165   struct iocblk *iocp;
166
167   switch(mp->b_datap->db_type)
168   {
169     case M_IOCTL:
170       iocp=(struct iocblk*) mp->b_rptr;
171       if (iocp->ioc_cmd==CLK_SETSTR)
172       {
173         strncpy( ((struct priv_data_type *) (RD(q)->q_ptr))->string,
174           (char *) mp->b_cont->b_rptr,CLK_MAXSTRSIZE);
175         /* make sure it's null terminated */
176         ((struct priv_data_type *) (RD(q)->q_ptr))->string[CLK_MAXSTRSIZE-1]=0;
177         mp->b_datap->db_type = M_IOCACK;
178         qreply(q,mp);
179       }
180       else
181         putnext(q,mp);
182     break;
183     default:
184       putnext(q,mp);
185     break;
186   }
187 }
188
189 /*
190  * Now clkchar. It takes a character, a queue pointer and an action
191  * flag and depending on the flag either:
192  *
193  * 0 - adds the character to the current message. If there's a
194  * timestamp to be done, do that too. If the message is less than
195  * 8 chars from being full, link in a new one, and set it up for
196  * the next call.
197  *
198  * 1 - sends the whole mess to Valhala.
199  *
200  * 2 - set things up.
201  *
202  * Yeah, it's an ugly hack. Complaints may be filed with /dev/null.
203  */
204
205
206 void clkchar(c,q,f)
207         register u_char c;
208         queue_t *q;
209         char f;
210 {
211   static char error;
212   static mblk_t *message,*mp;
213   struct timeval tv;
214
215 /* Get a timestamp ASAP! */
216   uniqtime(&tv);
217
218   switch(f)
219   {
220     case 1:
221       if (!error)
222         putnext(q,message);
223     break;
224     case 2:
225       mp=message= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO);
226       error=(message==NULL);
227       if (error)
228         log(LOG_ERR,"clk: cannot allocate message - data lost");
229     break;
230     case 0:
231       if (error) /* If we had an error, forget it. */
232         return;
233
234       *mp->b_wptr++=c; /* Put the char away first.
235
236       /* If it's in the special string, append a struct timeval */
237
238       if (str_chr( ((struct priv_data_type *) (q->q_ptr))->string ,
239         c )!=NULL)
240       {
241           int i;
242
243           for (i=0;i<sizeof(struct timeval);i++)
244             *mp->b_wptr++= *( ((char*)&tv) + i );
245       }
246
247       /* If we don't have space for a complete struct timeval, and a
248          char, it's time for a new mp block */
249
250       if (((mp->b_wptr-mp->b_rptr)+sizeof(struct timeval)+2)>MESSAGE_SIZE)
251       {
252           mp->b_cont= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO);
253           error=(mp->b_cont==NULL);
254           if (error)
255           {
256             log(LOG_ERR,"clk: cannot allocate message - data lost");
257             freemsg(message);
258           }
259           mp=mp->b_cont;
260       }
261
262     break;
263   }
264 }
265
266 #endif