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>