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