Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / kernel / tty_chu_STREAMS.c
blob0dbb54de8da052f92f383e02723e712e87c4d1b5
1 /* $NetBSD$ */
3 /*
4 * CHU STREAMS module for SunOS
6 * Version 2.6
8 * Copyright 1991-1994, Nick Sayer
10 * Special thanks to Greg Onufer for his debug assists.
11 * Special thanks to Matthias Urlichs for the 4.1.x loadable driver support
12 * code.
13 * Special wet-noodle whippings to Sun for not properly documenting
14 * ANYTHING that makes this stuff at all possible.
16 * Should be PUSHed directly on top of a serial I/O channel.
17 * Provides complete chucode structures to user space.
19 * COMPILATION:
22 * To make a SunOS 4.1.x compatable loadable module (from the ntp kernel
23 * directory):
25 * % cc -c -I../include -DLOADABLE tty_chu_STREAMS.c
27 * The resulting .o file is the loadable module. Modload it
28 * thusly:
30 * % modload tty_chu_STREAMS.o -entry _chuinit
32 * When none of the instances are pushed in a STREAM, you can
33 * modunload the driver in the usual manner if you wish.
35 * As an alternative to loading it dynamically you can compile it
36 * directly into the kernel by hacking str_conf.c. See the README
37 * file for more details on doing it the old fashioned way.
40 * To make a Solaris 2.x compatable module (from the ntp kernel
41 * directory):
43 * % {gcc,cc} -c -I../include -DSOLARIS2 tty_chu_STREAMS.c
44 * % ld -r -o /usr/kernel/strmod/chu tty_chu_STREAMS.o
45 * % chmod 755 /usr/kernel/strmod/chu
47 * The OS will load it for you automagically when it is first pushed.
49 * If you get syntax errors from <sys/timer.h> (really references
50 * to types that weren't typedef'd in gcc's version of types.h),
51 * add -D_SYS_TIMER_H to blot out the miscreants.
53 * Under Solaris 2.2 and previous, do not attempt to modunload the
54 * module unless you're SURE it's not in use. I haven't tried it, but
55 * I've been told it won't do the right thing. Under Solaris 2.3 (and
56 * presumably future revs) an attempt to unload the module when it's in
57 * use will properly refuse with a "busy" message.
60 * HISTORY:
62 * v2.6 - Mutexed the per-instance chucode just to be safe.
63 * v2.5 - Fixed show-stopper bug in Solaris 2.x - qprocson().
64 * v2.4 - Added dynamic allocation support for Solaris 2.x.
65 * v2.3 - Added support for Solaris 2.x.
66 * v2.2 - Added SERVICE IMMEDIATE hack.
67 * v2.1 - Added 'sixth byte' heuristics.
68 * v2.0 - first version with an actual version number.
69 * Added support for new CHU 'second 31' data format.
70 * Deleted PEDANTIC and ANAL_RETENTIVE.
74 #ifdef SOLARIS2
75 # ifndef NCHU
76 # define NCHU 1
77 # endif
78 # define _KERNEL
79 #elif defined(LOADABLE)
80 # ifndef NCHU
81 # define NCHU 3
82 # define KERNEL
83 # endif
84 #else
85 # include "chu.h"
86 #endif
88 #if NCHU > 0
91 * Number of microseconds we allow between
92 * character arrivals. The speed is 300 baud
93 * so this should be somewhat more than 30 msec
95 #define CHUMAXUSEC (60*1000) /* 60 msec */
97 #include <sys/types.h>
98 #include <sys/stream.h>
99 #include <sys/param.h>
100 #include <sys/time.h>
101 #include <sys/errno.h>
102 #include <sys/user.h>
103 #include <syslog.h>
104 #include <sys/tty.h>
106 #include <sys/chudefs.h>
108 #ifdef SOLARIS2
110 #include <sys/ksynch.h>
111 #include <sys/kmem.h>
112 #include <sys/cmn_err.h>
113 #include <sys/conf.h>
114 #include <sys/strtty.h>
115 #include <sys/modctl.h>
116 #include <sys/ddi.h>
117 #include <sys/sunddi.h>
119 #endif
121 #ifdef LOADABLE
123 #include <sys/kernel.h>
124 #include <sys/conf.h>
125 #include <sys/buf.h>
126 #include <sundev/mbvar.h>
127 #include <sun/autoconf.h>
128 #include <sun/vddrv.h>
130 #endif
133 static struct module_info rminfo = { 0, "chu", 0, INFPSZ, 0, 0 };
134 static struct module_info wminfo = { 0, "chu", 0, INFPSZ, 0, 0 };
135 static int chuopen(), churput(), chuwput(), chuclose();
137 static struct qinit rinit = { churput, NULL, chuopen, chuclose, NULL,
138 &rminfo, NULL };
140 static struct qinit winit = { chuwput, NULL, NULL, NULL, NULL,
141 &wminfo, NULL };
143 struct streamtab chuinfo = { &rinit, &winit, NULL, NULL };
146 * Here's our private data type and structs
148 struct priv_data
150 #ifdef SOLARIS2
151 kmutex_t chucode_mutex;
152 #else
153 char in_use;
154 #endif
155 struct chucode chu_struct;
158 #ifndef SOLARIS2
159 struct priv_data our_priv_data[NCHU];
160 #endif
162 #ifdef SOLARIS2
164 static struct fmodsw fsw =
166 "chu",
167 &chuinfo,
168 D_NEW | D_MP
171 extern struct mod_ops mod_strmodops;
173 static struct modlstrmod modlstrmod =
175 &mod_strmodops,
176 "CHU timecode decoder v2.6",
177 &fsw
180 static struct modlinkage modlinkage =
182 MODREV_1,
183 (void*) &modlstrmod,
184 NULL
187 int _init()
189 return mod_install(&modlinkage);
192 int _info(foo)
193 struct modinfo *foo;
195 return mod_info(&modlinkage,foo);
198 int _fini()
200 return mod_remove(&modlinkage);
203 #endif /* SOLARIS2 */
205 #ifdef LOADABLE
207 # ifdef sun
209 static struct vdldrv vd =
211 VDMAGIC_PSEUDO,
212 "chu",
213 NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0,
216 static struct fmodsw *chu_fmod;
218 /*ARGSUSED*/
219 chuinit (fc, vdp, vdi, vds)
220 unsigned int fc;
221 struct vddrv *vdp;
222 addr_t vdi;
223 struct vdstat *vds;
225 switch (fc) {
226 case VDLOAD:
228 int dev, i;
230 /* Find free entry in fmodsw */
231 for (dev = 0; dev < fmodcnt; dev++) {
232 if (fmodsw[dev].f_str == NULL)
233 break;
235 if (dev == fmodcnt)
236 return (ENODEV);
237 chu_fmod = &fmodsw[dev];
239 /* If you think a kernel would have strcpy() you're mistaken. */
240 for (i = 0; i <= FMNAMESZ; i++)
241 chu_fmod->f_name[i] = wminfo.mi_idname[i];
243 chu_fmod->f_str = &chuinfo;
245 vdp->vdd_vdtab = (struct vdlinkage *) & vd;
248 int i;
250 for (i=0; i<NCHU; i++)
251 our_priv_data[i].in_use=0;
254 return 0;
255 case VDUNLOAD:
257 int dev;
259 for (dev = 0; dev < NCHU; dev++)
260 if (our_priv_data[dev].in_use) {
261 /* One of the modules is still open */
262 return (EBUSY);
265 chu_fmod->f_name[0] = '\0';
266 chu_fmod->f_str = NULL;
267 return 0;
268 case VDSTAT:
269 return 0;
270 default:
271 return EIO;
275 # endif /* sun */
277 #endif /* LOADABLE */
279 #if !defined(LOADABLE) && !defined(SOLARIS2)
281 char chu_first_open=1;
283 #endif
285 /*ARGSUSED*/
286 static int chuopen(q, dev, flag, sflag)
287 queue_t *q;
288 dev_t dev;
289 int flag;
290 int sflag;
292 int i;
294 #if !defined(LOADABLE) && !defined(SOLARIS2)
295 if (chu_first_open)
297 chu_first_open=0;
299 for(i=0;i<NCHU;i++)
300 our_priv_data[i].in_use=0;
302 #endif
304 #ifdef SOLARIS2
305 /* According to the docs, calling with KM_SLEEP can never
306 fail */
308 q->q_ptr = kmem_alloc( sizeof(struct priv_data), KM_SLEEP );
309 ((struct priv_data *) q->q_ptr)->chu_struct.ncodechars = 0;
311 mutex_init(&((struct priv_data *) q->q_ptr)->chucode_mutex,"Chucode Mutex",MUTEX_DRIVER,NULL);
312 qprocson(q);
314 if (!putnextctl1(WR(q), M_CTL, MC_SERVICEIMM))
316 qprocsoff(q);
317 mutex_destroy(&((struct priv_data *)q->q_ptr)->chucode_mutex);
318 kmem_free(q->q_ptr, sizeof(struct chucode) );
319 return (EFAULT);
322 return 0;
324 #else
325 for(i=0;i<NCHU;i++)
326 if (!our_priv_data[i].in_use)
328 ((struct priv_data *) (q->q_ptr))=&(our_priv_data[i]);
329 our_priv_data[i].in_use++;
330 our_priv_data[i].chu_struct.ncodechars = 0;
331 if (!putctl1(WR(q)->q_next, M_CTL, MC_SERVICEIMM))
333 our_priv_data[i].in_use=0;
334 u.u_error = EFAULT;
335 return (OPENFAIL);
337 return 0;
340 u.u_error = EBUSY;
341 return (OPENFAIL);
342 #endif
346 /*ARGSUSED*/
347 static int chuclose(q, flag)
348 queue_t *q;
349 int flag;
351 #ifdef SOLARIS2
352 qprocsoff(q);
353 mutex_destroy(&((struct priv_data *)q->q_ptr)->chucode_mutex);
354 kmem_free(q->q_ptr, sizeof(struct chucode) );
355 #else
356 ((struct priv_data *) (q->q_ptr))->in_use=0;
357 #endif
358 return (0);
362 * Now the crux of the biscuit.
364 * We will be passed data from the man downstairs. If it's not a data
365 * packet, it must be important, so pass it along unmunged. If, however,
366 * it is a data packet, we're gonna do special stuff to it. We're going
367 * to pass each character we get to the old line discipline code we
368 * include below for just such an occasion. When the old ldisc code
369 * gets a full chucode struct, we'll hand it back upstairs.
371 * chuinput takes a single character and q (as quickly as possible).
372 * passback takes a pointer to a chucode struct and q and sends it upstream.
375 void chuinput();
376 void passback();
378 static int churput(q, mp)
379 queue_t *q;
380 mblk_t *mp;
382 mblk_t *bp;
384 switch(mp->b_datap->db_type)
386 case M_DATA:
387 for(bp=mp; bp!=NULL; bp=bp->b_cont)
389 while(bp->b_rptr < bp->b_wptr)
390 chuinput( ((u_char)*(bp->b_rptr++)) , q );
392 freemsg(mp);
393 break;
394 default:
395 putnext(q,mp);
396 break;
402 * Writing to a chu device doesn't make sense, but we'll pass them
403 * through in case they're important.
406 static int chuwput(q, mp)
407 queue_t *q;
408 mblk_t *mp;
410 putnext(q,mp);
414 * Take a pointer to a filled chucode struct and a queue and
415 * send the chucode stuff upstream
418 void passback(outdata,q)
419 struct chucode *outdata;
420 queue_t *q;
422 mblk_t *mp;
423 int j;
425 mp=(mblk_t*) allocb(sizeof(struct chucode),BPRI_LO);
427 if (mp==NULL)
429 #ifdef SOLARIS2
430 cmn_err(CE_WARN,"chu module couldn't allocate message block");
431 #else
432 log(LOG_ERR,"chu: cannot allocate message");
433 #endif
434 return;
437 for(j=0;j<sizeof(struct chucode); j++)
438 *mp->b_wptr++ = *( ((char*)outdata) + j );
440 putnext(q,mp);
444 * This routine was copied nearly verbatim from the old line discipline.
446 void chuinput(c,q)
447 register u_char c;
448 queue_t *q;
450 register struct chucode *chuc;
451 register int i;
452 long sec, usec;
453 struct timeval tv;
456 * Quick, Batman, get a timestamp! We need to do this
457 * right away. The time between the end of the stop bit
458 * and this point is critical, and should be as nearly
459 * constant and as short as possible. (Un)fortunately,
460 * the Sun's clock granularity is so big this isn't a
461 * major problem.
463 * uniqtime() is totally undocumented, but there you are.
465 uniqtime(&tv);
467 #ifdef SOLARIS2
468 mutex_enter(&((struct priv_data *)q->q_ptr)->chucode_mutex);
469 #endif
472 * Now, locate the chu struct once so we don't have to do it
473 * over and over.
475 chuc=&(((struct priv_data *) (q->q_ptr))->chu_struct);
478 * Compute the difference in this character's time stamp
479 * and the last. If it exceeds the margin, blow away all
480 * the characters currently in the buffer.
482 i = (int)chuc->ncodechars;
483 if (i > 0)
485 sec = tv.tv_sec - chuc->codetimes[i-1].tv_sec;
486 usec = tv.tv_usec - chuc->codetimes[i-1].tv_usec;
487 if (usec < 0)
489 sec -= 1;
490 usec += 1000000;
492 if (sec != 0 || usec > CHUMAXUSEC)
494 i = 0;
495 chuc->ncodechars = 0;
500 * Store the character.
502 chuc->codechars[i] = (u_char)c;
503 chuc->codetimes[i] = tv;
506 * Now we perform the 'sixth byte' heuristics.
508 * This is a long story.
510 * We used to be able to count on the first byte of the code
511 * having a '6' in the LSD. This prevented most code framing
512 * errors (garbage before the first byte wouldn't typically
513 * have a 6 in the LSD). That's no longer the case.
515 * We can get around this, however, by noting that the 6th byte
516 * must be either equal to or one's complement of the first.
517 * If we get a sixth byte that ISN'T like that, then it may
518 * well be that the first byte is garbage. The right thing
519 * to do is to left-shift the whole buffer one count and
520 * continue to wait for the sixth byte.
522 if (i == NCHUCHARS/2)
524 register u_char temp_byte;
526 temp_byte=chuc->codechars[i] ^ chuc->codechars[0];
528 if ( (temp_byte) && (temp_byte!=0xff) )
530 register int t;
532 * No match. Left-shift the buffer and try again
534 for(t=0;t<=NCHUCHARS/2;t++)
536 chuc->codechars[t]=chuc->codechars[t+1];
537 chuc->codetimes[t]=chuc->codetimes[t+1];
540 i--; /* This is because of the ++i immediately following */
545 * We done yet?
547 if (++i < NCHUCHARS)
550 * We're not done. Not much to do here. Save the count and wait
551 * for another character.
553 chuc->ncodechars = (u_char)i;
555 else
558 * We are done. Mark this buffer full and pass it along.
560 chuc->ncodechars = NCHUCHARS;
563 * Now we have a choice. Either the front half and back half
564 * have to match, or be one's complement of each other.
566 * So let's try the first byte and see
569 if(chuc->codechars[0] == chuc->codechars[NCHUCHARS/2])
571 chuc->chutype = CHU_TIME;
572 for( i=0; i<(NCHUCHARS/2); i++)
573 if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)])
575 chuc->ncodechars = 0;
576 #ifdef SOLARIS2
577 mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);
578 #endif
579 return;
582 else
584 chuc->chutype = CHU_YEAR;
585 for( i=0; i<(NCHUCHARS/2); i++)
586 if (((chuc->codechars[i] ^ chuc->codechars[i+(NCHUCHARS/2)]) & 0xff)
587 != 0xff )
589 chuc->ncodechars = 0;
590 #ifdef SOLARIS2
591 mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);
592 #endif
593 return;
597 passback(chuc,q); /* We're done! */
598 chuc->ncodechars = 0; /* Start all over again! */
600 #ifdef SOLARIS2
601 mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);
602 #endif
605 #endif /* NCHU > 0 */