diff options
Diffstat (limited to 'kernel/tty_clk_STREAMS.c')
-rw-r--r-- | kernel/tty_clk_STREAMS.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/kernel/tty_clk_STREAMS.c b/kernel/tty_clk_STREAMS.c new file mode 100644 index 0000000..13b0a25 --- /dev/null +++ b/kernel/tty_clk_STREAMS.c @@ -0,0 +1,266 @@ +/* tty_clk_STREAMS.c,v 3.1 1993/07/06 01:07:34 jbj Exp + * Timestamp STREAMS module for SunOS 4.1 + * + * Copyright 1991, Nick Sayer + * + * Special thanks to Greg Onufer for his debug assists. + * + * Should be PUSHed directly on top of a serial I/O channel. + * For any character in a user-designated set, adds a kernel + * timestamp to that character. + * + * BUGS: + * + * Only so many characters can be timestamped. This number, however, + * is adjustable. + * + * The null character ($00) cannot be timestamped. + * + * The M_DATA messages passed upstream will not be the same + * size as when they arrive from downstream, even if no + * timestamp character is in the message. This, however, + * should not affect anything. + * + */ + +#include "clk.h" +#if NCLK > 0 +/* + * How big should the messages we pass upstream be? + */ +#define MESSAGE_SIZE 128 + +#include <string.h> +#include <sys/types.h> +#include <sys/stream.h> +#include <sys/param.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/user.h> +#include <sys/errno.h> +#include <sys/syslog.h> + +#include <sys/clkdefs.h> + +static struct module_info rminfo = { 0, "clk", 0, INFPSZ, 0, 0 }; +static struct module_info wminfo = { 0, "clk", 0, INFPSZ, 0, 0 }; +static int clkopen(), clkrput(), clkwput(), clkclose(); + +static struct qinit rinit = { clkrput, NULL, clkopen, clkclose, NULL, + &rminfo, NULL }; + +static struct qinit winit = { clkwput, NULL, NULL, NULL, NULL, + &wminfo, NULL }; + +struct streamtab clkinfo = { &rinit, &winit, NULL, NULL }; + +struct priv_data_type +{ + char in_use; + char string[CLK_MAXSTRSIZE]; +} priv_data[NCLK]; + +char first_open=1; + +/* + * God only knows why, but linking with strchr() fails + * on my system, so here's a renamed copy. + */ + +u_char *str_chr(s,c) +u_char *s; +int c; +{ + while (*s) + if(*s++ == c) + return (s-1); + return NULL; +} + +/*ARGSUSED*/ +static int clkopen(q, dev, flag, sflag) +queue_t *q; +dev_t dev; +int flag; +int sflag; +{ + int i; + +/* Damn it! We can't even have the global data struct properly + initialized! So we have a mark to tell us to init the global + data on the first open */ + + if (first_open) + { + first_open=0; + + for(i=0;i<NCLK;i++) + priv_data[i].in_use=0; + } + + for(i=0;i<NCLK;i++) + if(!priv_data[i].in_use) + { + priv_data[i].in_use++; + ((struct priv_data_type *) (q->q_ptr))=priv_data+i; + priv_data[i].string[0]=0; + return (0); + } + u.u_error = EBUSY; + return (OPENFAIL); +} + +/*ARGSUSED*/ +static int clkclose(q, flag) +queue_t *q; +int flag; +{ + ((struct priv_data_type *) (q->q_ptr))->in_use=0; + + return (0); +} + +/* + * Now the crux of the biscuit. + * + * If it's an M_DATA package, we take each character and pass + * it to clkchar. + */ + +void clkchar(); + +static int clkrput(q, mp) +queue_t *q; +mblk_t *mp; +{ + mblk_t *bp; + + switch(mp->b_datap->db_type) + { + case M_DATA: + clkchar(0,q,2); + for(bp=mp; bp!=NULL; bp=bp->b_cont) + { + while(bp->b_rptr < bp->b_wptr) + clkchar( ((u_char)*(bp->b_rptr++)) , q , 0 ); + } + clkchar(0,q,1); + freemsg(mp); + break; + default: + putnext(q,mp); + break; + } + +} + +/* + * If it's a matching M_IOCTL, handle it. + */ + +static int clkwput(q, mp) +queue_t *q; +mblk_t *mp; +{ + struct iocblk *iocp; + + switch(mp->b_datap->db_type) + { + case M_IOCTL: + iocp=(struct iocblk*) mp->b_rptr; + if (iocp->ioc_cmd==CLK_SETSTR) + { + strncpy( ((struct priv_data_type *) (RD(q)->q_ptr))->string, + (char *) mp->b_cont->b_rptr,CLK_MAXSTRSIZE); + /* make sure it's null terminated */ + ((struct priv_data_type *) (RD(q)->q_ptr))->string[CLK_MAXSTRSIZE-1]=0; + mp->b_datap->db_type = M_IOCACK; + qreply(q,mp); + } + else + putnext(q,mp); + break; + default: + putnext(q,mp); + break; + } +} + +/* + * Now clkchar. It takes a character, a queue pointer and an action + * flag and depending on the flag either: + * + * 0 - adds the character to the current message. If there's a + * timestamp to be done, do that too. If the message is less than + * 8 chars from being full, link in a new one, and set it up for + * the next call. + * + * 1 - sends the whole mess to Valhala. + * + * 2 - set things up. + * + * Yeah, it's an ugly hack. Complaints may be filed with /dev/null. + */ + + +void clkchar(c,q,f) + register u_char c; + queue_t *q; + char f; +{ + static char error; + static mblk_t *message,*mp; + struct timeval tv; + +/* Get a timestamp ASAP! */ + uniqtime(&tv); + + switch(f) + { + case 1: + if (!error) + putnext(q,message); + break; + case 2: + mp=message= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO); + error=(message==NULL); + if (error) + log(LOG_ERR,"clk: cannot allocate message - data lost"); + break; + case 0: + if (error) /* If we had an error, forget it. */ + return; + + *mp->b_wptr++=c; /* Put the char away first. + + /* If it's in the special string, append a struct timeval */ + + if (str_chr( ((struct priv_data_type *) (q->q_ptr))->string , + c )!=NULL) + { + int i; + + for (i=0;i<sizeof(struct timeval);i++) + *mp->b_wptr++= *( ((char*)&tv) + i ); + } + + /* If we don't have space for a complete struct timeval, and a + char, it's time for a new mp block */ + + if (((mp->b_wptr-mp->b_rptr)+sizeof(struct timeval)+2)>MESSAGE_SIZE) + { + mp->b_cont= (mblk_t*) allocb(MESSAGE_SIZE,BPRI_LO); + error=(mp->b_cont==NULL); + if (error) + { + log(LOG_ERR,"clk: cannot allocate message - data lost"); + freemsg(message); + } + mp=mp->b_cont; + } + + break; + } +} + +#endif |