Annotation of embedaddon/ntp/ntpd/refclock_bancomm.c, revision 1.1.1.1

1.1       misho       1: /* refclock_bancomm.c - clock driver for the  Datum/Bancomm bc635VME 
                      2:  * Time and Frequency Processor. It requires the BANCOMM bc635VME/
                      3:  * bc350VXI Time and Frequency Processor Module Driver for SunOS4.x 
                      4:  * and SunOS5.x UNIX Systems. It has been tested on a UltraSparc 
                      5:  * IIi-cEngine running Solaris 2.6.
                      6:  * 
                      7:  * Author(s):  Ganesh Ramasivan & Gary Cliff, Computing Devices Canada,
                      8:  *             Ottawa, Canada
                      9:  *
                     10:  * Date:       July 1999
                     11:  *
                     12:  * Note(s):    The refclock type has been defined as 16.
                     13:  *
                     14:  *             This program has been modelled after the Bancomm driver
                     15:  *             originally written by R. Schmidt of Time Service, U.S. 
                     16:  *             Naval Observatory for a HP-UX machine. Since the original
                     17:  *             authors no longer plan to maintain this code, all 
                     18:  *             references to the HP-UX vme2 driver subsystem bave been
                     19:  *             removed. Functions vme_report_event(), vme_receive(), 
                     20:  *             vme_control() and vme_buginfo() have been deleted because
                     21:  *             they are no longer being used.
                     22:  *
                     23:  *     04/28/2005 Rob Neal 
                     24:  *             Modified to add support for Symmetricom bc637PCI-U Time & 
                     25:  *             Frequency Processor. 
                     26:  *     2/21/2007 Ali Ghorashi
                     27:  *             Modified to add support for Symmetricom bc637PCI-U Time & 
                     28:  *             Frequency Processor on Solaris.
                     29:  *             Tested on Solaris 10 with a bc635 card.
                     30:  *
                     31:  *             Card bus type (VME/VXI or PCI) and environment are specified via the
                     32:  *             "mode" keyword on the server command in ntp.conf.
                     33:  *             server 127.127.16.u prefer mode M
                     34:  *             where u is the id (usually 0) of the entry in /dev (/dev/stfp0)
                     35:  *     
                     36:  *             and M is one of the following modes: 
                     37:  *             1               : FreeBSD PCI 635/637.
                     38:  *             2               : Linux or Windows PCI 635/637.
                     39:  *             3               : Solaris PCI 635/637
                     40:  *             not specified, or other number: 
                     41:  *                             : Assumed to be VME/VXI legacy Bancomm card on Solaris.
                     42:  *             Linux and Windows platforms require Symmetricoms' proprietary driver
                     43:  *             for the TFP card.
                     44:  *             Solaris requires Symmetricom's driver and its header file (freely distributed) to 
                     45:  *             be installed and running.
                     46:  */
                     47: 
                     48: #ifdef HAVE_CONFIG_H
                     49: #include <config.h>
                     50: #endif
                     51: 
                     52: #if defined(REFCLOCK) && defined(CLOCK_BANC) 
                     53: 
                     54: #include "ntpd.h"
                     55: #include "ntp_io.h"
                     56: #include "ntp_refclock.h"
                     57: #include "ntp_unixtime.h"
                     58: #include "ntp_stdlib.h"
                     59: 
                     60: #include <stdio.h>
                     61: #include <syslog.h>
                     62: #include <ctype.h>
                     63: 
                     64: struct btfp_time                /* Structure for reading 5 time words   */
                     65:                                 /* in one ioctl(2) operation.           */
                     66: {
                     67:        unsigned short btfp_time[5];  /* Time words 0,1,2,3, and 4. (16bit)*/
                     68: };
                     69: /* SunOS5 ioctl commands definitions.*/
                     70: #define BTFPIOC            ( 'b'<< 8 )
                     71: #define IOCIO( l, n )      ( BTFPIOC | n )
                     72: #define IOCIOR( l, n, s )  ( BTFPIOC | n )
                     73: #define IOCIORN( l, n, s ) ( BTFPIOC | n )
                     74: #define IOCIOWN( l, n, s ) ( BTFPIOC | n )
                     75: 
                     76: /***** Simple ioctl commands *****/
                     77: #define RUNLOCK        IOCIOR(b, 19, int )  /* Release Capture Lockout */
                     78: #define RCR0           IOCIOR(b, 22, int )  /* Read control register zero.*/
                     79: #define        WCR0            IOCIOWN(b, 23, int)          /* Write control register zero*/
                     80: /***** Compound ioctl commands *****/
                     81: 
                     82: /* Read all 5 time words in one call.   */
                     83: #define READTIME       IOCIORN(b, 32, sizeof( struct btfp_time ))
                     84: 
                     85: #if defined(__FreeBSD__) 
                     86: #undef  READTIME
                     87: #define READTIME       _IOR('u', 5, struct btfp_time )
                     88: #endif 
                     89: 
                     90: /* Solaris specific section */
                     91: struct stfp_tm {
                     92:        int32_t tm_sec; 
                     93:        int32_t tm_min;
                     94:        int32_t tm_hour;
                     95:        int32_t tm_mday;
                     96:        int32_t tm_mon;
                     97:        int32_t tm_year;
                     98:        int32_t tm_wday;
                     99:        int32_t tm_yday;
                    100:        int32_t tm_isdst;
                    101: };
                    102: 
                    103: struct stfp_time {
                    104:        struct stfp_tm  tm;
                    105:        int32_t         usec;                   /* usec 0 - 999999 */
                    106:        int32_t         hnsec;                  /* hnsec 0 - 9 (hundreds of nsecs) */
                    107:        int32_t         status;
                    108: };
                    109: 
                    110: #define SELTIMEFORMAT  2       
                    111: #      define TIME_DECIMAL 0
                    112: #      define TIME_BINARY      1
                    113: 
                    114: #if defined(__sun__)
                    115: #undef READTIME
                    116: #define READTIME               9
                    117: #endif /** __sun___ **/
                    118: /* end solaris specific section */
                    119: 
                    120: struct vmedate {                          /* structure returned by get_vmetime.c */
                    121:        unsigned short year;
                    122:        unsigned short day;
                    123:        unsigned short hr;
                    124:        unsigned short mn;
                    125:        unsigned short sec;
                    126:        long frac;
                    127:        unsigned short status;
                    128: };
                    129: 
                    130: typedef void *SYMMT_PCI_HANDLE;
                    131: 
                    132: /*
                    133:  * VME interface parameters. 
                    134:  */
                    135: #define VMEPRECISION    (-21)   /* precision assumed (1 us) */
                    136: #define USNOREFID       "BTFP"  /* or whatever */
                    137: #define VMEREFID        "BTFP"  /* reference id */
                    138: #define VMEDESCRIPTION  "Bancomm bc635 TFP" /* who we are */
                    139: #define VMEHSREFID      0x7f7f1000 /* 127.127.16.00 refid hi strata */
                    140: /* clock type 16 is used here  */
                    141: #define GMT            0       /* hour offset from Greenwich */
                    142: 
                    143: /*
                    144:  * Imported from ntp_timer module
                    145:  */
                    146: extern u_long current_time;     /* current time(s) */
                    147: 
                    148: /*
                    149:  * Imported from ntpd module
                    150:  */
                    151: extern volatile int debug;               /* global debug flag */
                    152: 
                    153: /*
                    154:  * VME unit control structure.
                    155:  * Changes made to vmeunit structure. Most members are now available in the 
                    156:  * new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan
                    157:  */
                    158: struct vmeunit {
                    159:        struct vmedate vmedata; /* data returned from vme read */
                    160:        u_long lasttime;        /* last time clock heard from */
                    161: };
                    162: 
                    163: /*
                    164:  * Function prototypes
                    165:  */
                    166: static  int     vme_start       (int, struct peer *);
                    167: static  void    vme_shutdown    (int, struct peer *);
                    168: static  void    vme_receive     (struct recvbuf *);
                    169: static  void    vme_poll        (int unit, struct peer *);
                    170: struct vmedate *get_datumtime(struct vmedate *);       
                    171: void   tvme_fill(struct vmedate *, uint32_t btm[2]);
                    172: void   stfp_time2tvme(struct vmedate *time_vme, struct stfp_time *stfp);
                    173: inline const char *DEVICE_NAME(int n);
                    174: 
                    175: 
                    176: /*
                    177:  * Define the bc*() functions as weak so we can compile/link without them.
                    178:  * Only clients with the card will have the proprietary vendor device driver
                    179:  * and interface library needed for use on Linux/Windows platforms.
                    180:  */
                    181: extern uint32_t __attribute__ ((weak)) bcReadBinTime(SYMMT_PCI_HANDLE, uint32_t *, uint32_t*, uint8_t*);
                    182: extern SYMMT_PCI_HANDLE __attribute__ ((weak)) bcStartPci(void);
                    183: extern void __attribute__ ((weak)) bcStopPci(SYMMT_PCI_HANDLE);
                    184: 
                    185: /*
                    186:  * Transfer vector
                    187:  */
                    188: struct  refclock refclock_bancomm = {
                    189:        vme_start,              /* start up driver */
                    190:        vme_shutdown,           /* shut down driver */
                    191:        vme_poll,               /* transmit poll message */
                    192:        noentry,                /* not used (old vme_control) */
                    193:        noentry,                /* initialize driver */ 
                    194:        noentry,                /* not used (old vme_buginfo) */ 
                    195:        NOFLAGS                 /* not used */
                    196: };
                    197: 
                    198: int fd_vme;  /* file descriptor for ioctls */
                    199: int regvalue;
                    200: int tfp_type;  /* mode selector, indicate platform and driver interface */
                    201: SYMMT_PCI_HANDLE stfp_handle;
                    202: 
                    203: /** 
                    204:  * this macro returns the device name based on
                    205:  * the platform we are running on and the device number
                    206:  */
                    207: #if defined(__sun__)
                    208: inline const char *DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/stfp%d",n);return s;}
                    209: #else
                    210: inline const char* DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/btfp%d",n);return s;}
                    211: #endif /**__sun__**/
                    212: 
                    213: /*
                    214:  * vme_start - open the VME device and initialize data for processing
                    215:  */
                    216: static int
                    217: vme_start(
                    218:        int unit,
                    219:        struct peer *peer
                    220:        )
                    221: {
                    222:        register struct vmeunit *vme;
                    223:        struct refclockproc *pp;
                    224:        int dummy;
                    225:        char vmedev[20];
                    226:        
                    227:        tfp_type = (int)(peer->ttl);
                    228:        switch (tfp_type) {             
                    229:                case 1:
                    230:                case 3:
                    231:                        break;
                    232:                case 2:
                    233:                        stfp_handle = bcStartPci();     /* init the card in lin/win */
                    234:                        break;
                    235:                default:
                    236:                        break;
                    237:        }
                    238:        /*
                    239:         * Open VME device
                    240:         */
                    241: #ifdef DEBUG
                    242: 
                    243:        printf("Opening DATUM DEVICE %s\n",DEVICE_NAME(peer->refclkunit));
                    244: #endif
                    245:        if ( (fd_vme = open(DEVICE_NAME(peer->refclkunit), O_RDWR)) < 0) {
                    246:                msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
                    247:                return (0);
                    248:        }
                    249:        else  { 
                    250:                switch (tfp_type) {
                    251:                        case 1: break;
                    252:                        case 2: break;
                    253:                        case 3:break;
                    254:                        default: 
                    255:                                /* Release capture lockout in case it was set before. */
                    256:                                if( ioctl( fd_vme, RUNLOCK, &dummy ) )
                    257:                                msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m");
                    258: 
                    259:                                regvalue = 0; /* More esoteric stuff to do... */
                    260:                                if( ioctl( fd_vme, WCR0, &regvalue ) )
                    261:                                msyslog(LOG_ERR, "vme_start: WCR0 failed %m");
                    262:                                break;
                    263:                }
                    264:        }
                    265: 
                    266:        /*
                    267:         * Allocate unit structure
                    268:         */
                    269:        vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit));
                    270:        bzero((char *)vme, sizeof(struct vmeunit));
                    271: 
                    272: 
                    273:        /*
                    274:         * Set up the structures
                    275:         */
                    276:        pp = peer->procptr;
                    277:        pp->unitptr = (caddr_t) vme;
                    278:        pp->timestarted = current_time;
                    279: 
                    280:        pp->io.clock_recv = vme_receive;
                    281:        pp->io.srcclock = (caddr_t)peer;
                    282:        pp->io.datalen = 0;
                    283:        pp->io.fd = fd_vme;
                    284: 
                    285:        /*
                    286:         * All done.  Initialize a few random peer variables, then
                    287:         * return success. Note that root delay and root dispersion are
                    288:         * always zero for this clock.
                    289:         */
                    290:        peer->precision = VMEPRECISION;
                    291:        memcpy(&pp->refid, USNOREFID,4);
                    292:        return (1);
                    293: }
                    294: 
                    295: 
                    296: /*
                    297:  * vme_shutdown - shut down a VME clock
                    298:  */
                    299: static void
                    300: vme_shutdown(
                    301:        int unit, 
                    302:        struct peer *peer
                    303:        )
                    304: {
                    305:        register struct vmeunit *vme;
                    306:        struct refclockproc *pp;
                    307: 
                    308:        /*
                    309:         * Tell the I/O module to turn us off.  We're history.
                    310:         */
                    311:        pp = peer->procptr;
                    312:        vme = (struct vmeunit *)pp->unitptr;
                    313:        io_closeclock(&pp->io);
                    314:        pp->unitptr = NULL;
                    315:        if (NULL != vme)
                    316:                free(vme);
                    317:        if (tfp_type == 2)
                    318:                bcStopPci(stfp_handle); 
                    319: }
                    320: 
                    321: 
                    322: /*
                    323:  * vme_receive - receive data from the VME device.
                    324:  *
                    325:  * Note: This interface would be interrupt-driven. We don't use that
                    326:  * now, but include a dummy routine for possible future adventures.
                    327:  */
                    328: static void
                    329: vme_receive(
                    330:        struct recvbuf *rbufp
                    331:        )
                    332: {
                    333: }
                    334: 
                    335: 
                    336: /*
                    337:  * vme_poll - called by the transmit procedure
                    338:  */
                    339: static void
                    340: vme_poll(
                    341:        int unit,
                    342:        struct peer *peer
                    343:        )
                    344: {
                    345:        struct vmedate *tptr; 
                    346:        struct vmeunit *vme;
                    347:        struct refclockproc *pp;
                    348:        time_t tloc;
                    349:        struct tm *tadr;
                    350:         
                    351:        pp = peer->procptr;      
                    352:        vme = (struct vmeunit *)pp->unitptr;        /* Here is the structure */
                    353: 
                    354:        tptr = &vme->vmedata; 
                    355:        if ((tptr = get_datumtime(tptr)) == NULL ) {
                    356:                refclock_report(peer, CEVNT_BADREPLY);
                    357:                return;
                    358:        }
                    359: 
                    360:        get_systime(&pp->lastrec);
                    361:        pp->polls++;
                    362:        vme->lasttime = current_time;
                    363: 
                    364:        /*
                    365:         * Get VME time and convert to timestamp format. 
                    366:         * The year must come from the system clock.
                    367:         */
                    368:        
                    369:          time(&tloc);
                    370:          tadr = gmtime(&tloc);
                    371:          tptr->year = (unsigned short)(tadr->tm_year + 1900);
                    372: 
                    373:        snprintf(pp->a_lastcode,
                    374:                 sizeof(pp->a_lastcode),
                    375:                 "%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d",
                    376:                 tptr->day, 
                    377:                 tptr->hr, 
                    378:                 tptr->mn,
                    379:                 tptr->sec, 
                    380:                 tptr->frac, 
                    381:                 tptr->status);
                    382: 
                    383:        pp->lencode = (u_short) strlen(pp->a_lastcode);
                    384: 
                    385:        pp->day =  tptr->day;
                    386:        pp->hour =   tptr->hr;
                    387:        pp->minute =  tptr->mn;
                    388:        pp->second =  tptr->sec;
                    389:        pp->nsec =   tptr->frac;        
                    390: 
                    391: #ifdef DEBUG
                    392:        if (debug)
                    393:            printf("pp: %3d %02d:%02d:%02d.%06ld %1x\n",
                    394:                   pp->day, pp->hour, pp->minute, pp->second,
                    395:                   pp->nsec, tptr->status);
                    396: #endif
                    397:        if (tptr->status ) {       /*  Status 0 is locked to ref., 1 is not */
                    398:                refclock_report(peer, CEVNT_BADREPLY);
                    399:                return;
                    400:        }
                    401: 
                    402:        /*
                    403:         * Now, compute the reference time value. Use the heavy
                    404:         * machinery for the seconds and the millisecond field for the
                    405:         * fraction when present. If an error in conversion to internal
                    406:         * format is found, the program declares bad data and exits.
                    407:         * Note that this code does not yet know how to do the years and
                    408:         * relies on the clock-calendar chip for sanity.
                    409:         */
                    410:        if (!refclock_process(pp)) {
                    411:                refclock_report(peer, CEVNT_BADTIME);
                    412:                return;
                    413:        }
                    414:        pp->lastref = pp->lastrec;
                    415:        refclock_receive(peer);
                    416:        record_clock_stats(&peer->srcadr, pp->a_lastcode);
                    417: }
                    418: 
                    419: struct vmedate *
                    420: get_datumtime(struct vmedate *time_vme)
                    421: {
                    422:        char cbuf[7];
                    423:        struct btfp_time vts;
                    424:        uint32_t btm[2];
                    425:        uint8_t dmy;
                    426:        struct stfp_time stfpm;
                    427:        
                    428:        if (time_vme == NULL)
                    429:                time_vme = emalloc(sizeof(*time_vme));
                    430: 
                    431:        switch (tfp_type) {
                    432:                case 1:                         /* BSD, PCI, 2 32bit time words */
                    433:                        if (ioctl(fd_vme, READTIME, &btm)) {
                    434:                        msyslog(LOG_ERR, "get_bc63x error: %m");
                    435:                                return(NULL);
                    436:                        }
                    437:                        tvme_fill(time_vme, btm);
                    438:                        break;
                    439: 
                    440:                case 2:                         /* Linux/Windows, PCI, 2 32bit time words */
                    441:                        if (bcReadBinTime(stfp_handle, &btm[1], &btm[0], &dmy) == 0) {
                    442:                        msyslog(LOG_ERR, "get_datumtime error: %m"); 
                    443:                                return(NULL);
                    444:                        }
                    445:                        tvme_fill(time_vme, btm);
                    446:                        break;
                    447:                        
                    448:                case 3: /** solaris **/
                    449:                        memset(&stfpm,0,sizeof(stfpm));
                    450:                        
                    451:                        /* we need the time in decimal format */
                    452:                        /* Here we rudely assume that we are the only user of the driver.
                    453:                         * Other programs will have to set their own time format before reading 
                    454:                         * the time.
                    455:                         */
                    456:                        if(ioctl (fd_vme, SELTIMEFORMAT, TIME_DECIMAL)){        
                    457:                                        msyslog(LOG_ERR, "Could not set time format\n");
                    458:                                        return (NULL);  
                    459:                        }
                    460:                        /* read the time */
                    461:                        if (ioctl(fd_vme, READTIME, &stfpm)) {
                    462:                                msyslog(LOG_ERR, "ioctl error: %m");
                    463:                                return(NULL);
                    464:                        }
                    465:                        stfp_time2tvme(time_vme,  &stfpm);
                    466:                        break;                  
                    467: 
                    468:                default:                        /* legacy bancomm card */
                    469: 
                    470:                        if (ioctl(fd_vme, READTIME, &vts)) {
                    471:                                msyslog(LOG_ERR,
                    472:                                        "get_datumtime error: %m");
                    473:                                return(NULL);
                    474:                        }
                    475:                        /* Get day */
                    476:                        snprintf(cbuf, sizeof(cbuf), "%3.3x",
                    477:                                 ((vts.btfp_time[ 0 ] & 0x000f) << 8) +
                    478:                                  ((vts.btfp_time[ 1 ] & 0xff00) >> 8));  
                    479:                        time_vme->day = (unsigned short)atoi(cbuf);
                    480: 
                    481:                        /* Get hour */
                    482:                        snprintf(cbuf, sizeof(cbuf), "%2.2x",
                    483:                                 vts.btfp_time[ 1 ] & 0x00ff);
                    484:                        time_vme->hr = (unsigned short)atoi(cbuf);
                    485: 
                    486:                        /* Get minutes */
                    487:                        snprintf(cbuf, sizeof(cbuf), "%2.2x",
                    488:                                 (vts.btfp_time[ 2 ] & 0xff00) >> 8);
                    489:                        time_vme->mn = (unsigned short)atoi(cbuf);
                    490: 
                    491:                        /* Get seconds */
                    492:                        snprintf(cbuf, sizeof(cbuf), "%2.2x",
                    493:                                 vts.btfp_time[ 2 ] & 0x00ff);
                    494:                        time_vme->sec = (unsigned short)atoi(cbuf);
                    495: 
                    496:                        /* Get microseconds.  Yes, we ignore the 0.1 microsecond digit so
                    497:                                 we can use the TVTOTSF function  later on...*/
                    498: 
                    499:                        snprintf(cbuf, sizeof(cbuf), "%4.4x%2.2x",
                    500:                                 vts.btfp_time[ 3 ],
                    501:                                 vts.btfp_time[ 4 ] >> 8);
                    502:                        time_vme->frac = (u_long) atoi(cbuf);
                    503: 
                    504:                        /* Get status bit */
                    505:                        time_vme->status = (vts.btfp_time[0] & 0x0010) >> 4;
                    506: 
                    507:                        break;
                    508:        }
                    509: 
                    510:        if (time_vme->status) 
                    511:                return ((void *)NULL);
                    512:        else
                    513:            return (time_vme);
                    514: }
                    515: /* Assign values to time_vme struct. Mostly for readability */
                    516: void
                    517: tvme_fill(struct vmedate *time_vme, uint32_t btm[2])
                    518: {
                    519:        struct tm maj;
                    520:        uint32_t dmaj, dmin;
                    521: 
                    522:        dmaj = btm[1];                  /* syntax sugar */
                    523:        dmin = btm[0];
                    524: 
                    525:        gmtime_r(&dmaj, &maj);
                    526:        time_vme->day  = maj.tm_yday+1;
                    527:        time_vme->hr   = maj.tm_hour;
                    528:        time_vme->mn   = maj.tm_min;
                    529:        time_vme->sec  = maj.tm_sec;
                    530:        time_vme->frac = (dmin & 0x000fffff) * 1000; 
                    531:        time_vme->frac += ((dmin & 0x00f00000) >> 20) * 100;
                    532:        time_vme->status = (dmin & 0x01000000) >> 24;
                    533:        return;
                    534: }
                    535: 
                    536: 
                    537: /* Assign values to time_vme struct. Mostly for readability */
                    538: void
                    539: stfp_time2tvme(struct vmedate *time_vme, struct stfp_time *stfp)
                    540: {
                    541: 
                    542:        time_vme->day  = stfp->tm.tm_yday+1;
                    543:        time_vme->hr   = stfp->tm.tm_hour;
                    544:        time_vme->mn   = stfp->tm.tm_min;
                    545:        time_vme->sec  = stfp->tm.tm_sec;
                    546:        time_vme->frac = stfp->usec*1000;  
                    547:        time_vme->frac += stfp->hnsec * 100;
                    548:        time_vme->status = stfp->status;
                    549:        return;
                    550: }
                    551: #else
                    552: int refclock_bancomm_bs;
                    553: #endif /* REFCLOCK */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>