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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>