/* tty_chu_STREAMS.c,v 3.1 1993/07/06 01:07:32 jbj Exp
* CHU STREAMS module for SunOS 4.1.x
* Copyright 1991-1993, Nick Sayer
* Special thanks to Greg Onufer for his debug assists.
* Special thanks to Matthias Urlichs for the loadable driver support
* Should be PUSHed directly on top of a serial I/O channel.
* Provides complete chucode structures to user space.
* To make a SunOS 4.1.x compatable loadable module (from the ntp kernel
* % cc -c -I../include -DLOADABLE tty_chu_STREAMS.c
* The resulting .o file is the loadable module. Modload it
* You can also add it into the kernel by hacking it into the streams
* table in the kernel, then adding it to config:
* where N is the maximum number of concurent chu sessions you expect
* v2.1 - Added 'sixth byte' heuristics.
* v2.0 - first version with an actual version number.
* Added support for new CHU 'second 31' data format.
* Deleted PEDANTIC and ANAL_RETENTIVE.
* Number of microseconds we allow between
* character arrivals. The speed is 300 baud
* so this should be somewhat more than 30 msec
#define CHUMAXUSEC (60*1000) /* 60 msec */
static struct module_info rminfo
= { 0, "chu", 0, INFPSZ
, 0, 0 };
static struct module_info wminfo
= { 0, "chu", 0, INFPSZ
, 0, 0 };
static int chuopen(), churput(), chuwput(), chuclose();
static struct qinit rinit
= { churput
, NULL
, chuopen
, chuclose
, NULL
,
static struct qinit winit
= { chuwput
, NULL
, NULL
, NULL
, NULL
,
struct streamtab chuinfo
= { &rinit
, &winit
, NULL
, NULL
};
* Here's our private data type and structs
struct chucode chu_struct
;
#include <sundev/mbvar.h>
#include <sun/autoconf.h>
static struct vdldrv vd
=
NULL
, NULL
, NULL
, 0, 0, NULL
, NULL
, 0, 0,
static struct fmodsw
*chu_fmod
;
chuinit (fc
, vdp
, vdi
, vds
)
/* Find free entry in fmodsw */
for (dev
= 0; dev
< fmodcnt
; dev
++) {
if (fmodsw
[dev
].f_str
== NULL
)
/* If you think a kernel would have strcpy() you're mistaken. */
for (i
= 0; i
<= FMNAMESZ
; i
++)
chu_fmod
->f_name
[i
] = wminfo
.mi_idname
[i
];
chu_fmod
->f_str
= &chuinfo
;
vdp
->vdd_vdtab
= (struct vdlinkage
*) & vd
;
our_priv_data
[i
].in_use
=0;
for (dev
= 0; dev
< NCHU
; dev
++)
if (our_priv_data
[dev
].in_use
) {
/* One of the modules is still open */
chu_fmod
->f_name
[0] = '\0';
static int chuopen(q
, dev
, flag
, sflag
)
our_priv_data
[i
].in_use
=0;
if (!our_priv_data
[i
].in_use
)
((struct priv_data
*) (q
->q_ptr
))=&(our_priv_data
[i
]);
our_priv_data
[i
].in_use
++;
our_priv_data
[i
].chu_struct
.ncodechars
= 0;
static int chuclose(q
, flag
)
((struct priv_data
*) (q
->q_ptr
))->in_use
=0;
* Now the crux of the biscuit.
* We will be passed data from the man downstairs. If it's not a data
* packet, it must be important, so pass it along unmunged. If, however,
* it is a data packet, we're gonna do special stuff to it. We're going
* to pass each character we get to the old line discipline code we
* include below for just such an occasion. When the old ldisc code
* gets a full chucode struct, we'll hand it back upstairs.
* chuinput takes a single character and q (as quickly as possible).
* passback takes a pointer to a chucode struct and q and sends it upstream.
static int churput(q
, mp
)
switch(mp
->b_datap
->db_type
)
for(bp
=mp
; bp
!=NULL
; bp
=bp
->b_cont
)
while(bp
->b_rptr
< bp
->b_wptr
)
chuinput( ((u_char
)*(bp
->b_rptr
++)) , q
);
* Writing to a chu device doesn't make sense, but we'll pass them
* through in case they're important.
static int chuwput(q
, mp
)
* Take a pointer to a filled chucode struct and a queue and
* send the chucode stuff upstream
mp
=(mblk_t
*) allocb(sizeof(struct chucode
),BPRI_LO
);
log(LOG_ERR
,"chu: cannot allocate message");
for(j
=0;j
<sizeof(struct chucode
); j
++)
*mp
->b_wptr
++ = *( ((char*)outdata
) + j
);
* This routine was copied nearly verbatim from the old line discipline.
register struct chucode
*chuc
;
* Quick, Batman, get a timestamp! We need to do this
* right away. The time between the end of the stop bit
* and this point is critical, and should be as nearly
* constant and as short as possible. (Un)fortunately,
* the Sun's clock granularity is so big this isn't a
* uniqtime() is totally undocumented, but there you are.
* Now, locate the chu struct once so we don't have to do it
chuc
=&(((struct priv_data
*) (q
->q_ptr
))->chu_struct
);
* Compute the difference in this character's time stamp
* and the last. If it exceeds the margin, blow away all
* the characters currently in the buffer.
i
= (int)chuc
->ncodechars
;
sec
= tv
.tv_sec
- chuc
->codetimes
[i
-1].tv_sec
;
usec
= tv
.tv_usec
- chuc
->codetimes
[i
-1].tv_usec
;
if (sec
!= 0 || usec
> CHUMAXUSEC
)
chuc
->codechars
[i
] = (u_char
)c
;
* Now we perform the 'sixth byte' heuristics.
* We used to be able to count on the first byte of the code
* having a '6' in the LSD. This prevented most code framing
* errors (garbage before the first byte wouldn't typically
* have a 6 in the LSD). That's no longer the case.
* We can get around this, however, by noting that the 6th byte
* must be either equal to or one's complement of the first.
* If we get a sixth byte that ISN'T like that, then it may
* well be that the first byte is garbage. The right thing
* to do is to left-shift the whole buffer one count and
* continue to wait for the sixth byte.
register u_char temp_byte
;
temp_byte
=chuc
->codechars
[i
] ^ chuc
->codechars
[0];
if ( (temp_byte
) && (temp_byte
!=0xff) )
* No match. Left-shift the buffer and try again
for(t
=0;t
<=NCHUCHARS
/2;t
++)
chuc
->codechars
[t
]=chuc
->codechars
[t
+1];
chuc
->codetimes
[t
]=chuc
->codetimes
[t
+1];
i
--; /* This is because of the ++i immediately following */
* We're not done. Not much to do here. Save the count and wait
chuc
->ncodechars
= (u_char
)i
;
* We are done. Mark this buffer full and pass it along.
chuc
->ncodechars
= NCHUCHARS
;
* Now we have a choice. Either the front half and back half
* have to match, or be one's complement of each other.
* So let's try the first byte and see
if(chuc
->codechars
[0] == chuc
->codechars
[NCHUCHARS
/2])
chuc
->chutype
= CHU_TIME
;
for( i
=0; i
<(NCHUCHARS
/2); i
++)
if (chuc
->codechars
[i
] != chuc
->codechars
[i
+(NCHUCHARS
/2)])
chuc
->chutype
= CHU_YEAR
;
for( i
=0; i
<(NCHUCHARS
/2); i
++)
if (((chuc
->codechars
[i
] ^ chuc
->codechars
[i
+(NCHUCHARS
/2)]) & 0xff)
passback(chuc
,q
); /* We're done! */
chuc
->ncodechars
= 0; /* Start all over again! */