269 lines
5.5 KiB
C
269 lines
5.5 KiB
C
/* $NetBSD: tty_clk_STREAMS.c,v 1.1.1.1 2000/03/29 12:38:49 simonb Exp $ */
|
|
|
|
/* 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
|