/contrib/ntp/kernel/tty_clk_STREAMS.c
C | 266 lines | 162 code | 38 blank | 66 comment | 16 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 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 45static struct module_info rminfo = { 0, "clk", 0, INFPSZ, 0, 0 }; 46static struct module_info wminfo = { 0, "clk", 0, INFPSZ, 0, 0 }; 47static int clkopen(), clkrput(), clkwput(), clkclose(); 48 49static struct qinit rinit = { clkrput, NULL, clkopen, clkclose, NULL, 50 &rminfo, NULL }; 51 52static struct qinit winit = { clkwput, NULL, NULL, NULL, NULL, 53 &wminfo, NULL }; 54 55struct streamtab clkinfo = { &rinit, &winit, NULL, NULL }; 56 57struct priv_data_type 58{ 59 char in_use; 60 char string[CLK_MAXSTRSIZE]; 61} priv_data[NCLK]; 62 63char 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 70u_char *str_chr(s,c) 71u_char *s; 72int c; 73{ 74 while (*s) 75 if(*s++ == c) 76 return (s-1); 77 return NULL; 78} 79 80/*ARGSUSED*/ 81static int clkopen(q, dev, flag, sflag) 82queue_t *q; 83dev_t dev; 84int flag; 85int 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*/ 114static int clkclose(q, flag) 115queue_t *q; 116int 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 130void clkchar(); 131 132static int clkrput(q, mp) 133queue_t *q; 134mblk_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 161static int clkwput(q, mp) 162queue_t *q; 163mblk_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 206void 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