Annotation of embedaddon/ntp/ntpd/refclock_gpsvme.c, revision 1.1

1.1     ! misho       1: /* refclock_psc.c:  clock driver for Brandywine PCI-SyncClock32/HP-UX 11.X */
        !             2: 
        !             3: #ifdef HAVE_CONFIG_H
        !             4: #include       <config.h>
        !             5: #endif /* HAVE_CONFIG_H        */
        !             6: 
        !             7: #if defined(REFCLOCK) && defined(CLOCK_GPSVME)
        !             8: 
        !             9: #include       "ntpd.h"
        !            10: #include       "ntp_io.h"
        !            11: #include       "ntp_refclock.h"
        !            12: #include       "ntp_unixtime.h"
        !            13: #include       "ntp_stdlib.h"
        !            14: 
        !            15: #ifdef __hpux
        !            16: #include       <sys/rtprio.h>  /* may already be included above        */
        !            17: #include       <sys/lock.h>    /* NEEDED for PROCLOCK                  */
        !            18: #endif /* __hpux       */
        !            19: 
        !            20: #ifdef __linux__
        !            21: #include       <sys/ioctl.h>   /* for _IOR, ioctl                      */
        !            22: #endif /* __linux__    */
        !            23: 
        !            24: enum {                         /* constants    */
        !            25:     BUFSIZE                    =       32,
        !            26:     PSC_SYNC_OK                        =       0x40,   /* Sync status bit      */
        !            27:     DP_LEAPSEC_DAY10DAY1       =       0x82,   /* DP RAM address       */
        !            28:     DP_LEAPSEC_DAY1000DAY100   =       0x83,
        !            29:     DELAY                      =       1,
        !            30:     NUNIT                      =       2       /* max UNITS            */
        !            31: };
        !            32: 
        !            33: /*     clock card registers    */
        !            34: struct psc_regs {
        !            35:     uint32_t           low_time;       /* card base + 0x00     */
        !            36:     uint32_t           high_time;      /* card base + 0x04     */
        !            37:     uint32_t           ext_low_time;   /* card base + 0x08     */
        !            38:     uint32_t           ext_high_time;  /* card base + 0x0C     */
        !            39:     uint8_t            device_status;  /* card base + 0x10     */
        !            40:     uint8_t            device_control; /* card base + 0x11     */
        !            41:     uint8_t            reserved0;      /* card base + 0x12     */
        !            42:     uint8_t            ext_100ns;      /* card base + 0x13     */
        !            43:     uint8_t            match_usec;     /* card base + 0x14     */
        !            44:     uint8_t            match_msec;     /* card base + 0x15     */
        !            45:     uint8_t            reserved1;      /* card base + 0x16     */
        !            46:     uint8_t            reserved2;      /* card base + 0x17     */
        !            47:     uint8_t            reserved3;      /* card base + 0x18     */
        !            48:     uint8_t            reserved4;      /* card base + 0x19     */
        !            49:     uint8_t            dp_ram_addr;    /* card base + 0x1A     */
        !            50:     uint8_t            reserved5;      /* card base + 0x1B     */
        !            51:     uint8_t            reserved6;      /* card base + 0x1C     */
        !            52:     uint8_t            reserved7;      /* card base + 0x1D     */
        !            53:     uint8_t            dp_ram_data;    /* card base + 0x1E     */
        !            54:     uint8_t            reserved8;      /* card base + 0x1F     */
        !            55: } *volatile regp[NUNIT];
        !            56: 
        !            57: #define        PSC_REGS        _IOR('K', 0, long)      /* ioctl argument       */
        !            58: 
        !            59: /* Macros to swap byte order and convert BCD to binary */
        !            60: #define SWAP(val) ( ((val) >> 24) | (((val) & 0x00ff0000) >> 8) | \
        !            61: (((val) & 0x0000ff00) << 8) | (((val) & 0x000000ff) << 24) )
        !            62: #define BCD2INT2(val)  ( ((val) >> 4 & 0x0f)*10 + ((val) & 0x0f) )
        !            63: #define BCD2INT3(val)  ( ((val) >> 8 & 0x0f)*100 + ((val) >> 4 & 0x0f)*10 + \
        !            64: ((val) & 0x0f) )
        !            65: 
        !            66: /* PSC interface definitions */
        !            67: #define PRECISION      (-20)   /* precision assumed (1 us)     */
        !            68: #define REFID          "USNO"  /* reference ID */
        !            69: #define DESCRIPTION    "Brandywine PCI-SyncClock32"
        !            70: #define DEVICE         "/dev/refclock%1d"      /* device file  */
        !            71: 
        !            72: /* clock unit control structure */
        !            73: struct psc_unit {
        !            74:     short      unit;           /* NTP refclock unit number     */
        !            75:     short      last_hour;      /* last hour (monitor leap sec) */
        !            76:     int                msg_flag[2];    /* count error messages         */
        !            77: };
        !            78: int    fd[NUNIT];              /* file descriptor      */
        !            79: 
        !            80: /* Local function prototypes */
        !            81: static int             psc_start(int, struct peer *);
        !            82: static void            psc_shutdown(int, struct peer *);
        !            83: static void            psc_poll(int, struct peer *);
        !            84: static void            check_leap_sec(struct refclockproc *, int);
        !            85: 
        !            86: /* Transfer vector     */
        !            87: struct refclock        refclock_gpsvme = {
        !            88:     psc_start, psc_shutdown, psc_poll, noentry, noentry, noentry, NOFLAGS
        !            89: };
        !            90: 
        !            91: /* psc_start:  open device and initialize data for processing */
        !            92: static int
        !            93: psc_start(
        !            94:     int                unit,
        !            95:     struct peer        *peer
        !            96:     )
        !            97: {
        !            98:     char                       buf[BUFSIZE];
        !            99:     struct refclockproc                *pp;
        !           100:     struct psc_unit            *up = emalloc(sizeof *up);
        !           101: 
        !           102:     if (unit < 0 || unit > 1) {                /* support units 0 and 1        */
        !           103:        msyslog(LOG_ERR, "psc_start: bad unit: %d", unit);
        !           104:        return 0;
        !           105:     }
        !           106: 
        !           107:     memset(up, '\0', sizeof *up);
        !           108: 
        !           109:     snprintf(buf, sizeof(buf), DEVICE, unit);  /* dev file name        */
        !           110:     fd[unit] = open(buf, O_RDONLY);    /* open device file     */
        !           111:     if (fd[unit] < 0) {
        !           112:        msyslog(LOG_ERR, "psc_start: unit: %d, open failed.  %m", unit);
        !           113:        return 0;
        !           114:     }
        !           115:      
        !           116:     /* get the address of the mapped regs      */
        !           117:     if (ioctl(fd[unit], PSC_REGS, &regp[unit]) < 0) {
        !           118:        msyslog(LOG_ERR, "psc_start: unit: %d, ioctl failed.  %m", unit);
        !           119:        return 0;
        !           120:     }
        !           121: 
        !           122:     /* initialize peer variables       */
        !           123:     pp = peer->procptr;
        !           124:     pp->io.clock_recv = noentry;
        !           125:     pp->io.srcclock = (caddr_t) peer;
        !           126:     pp->io.datalen = 0;
        !           127:     pp->io.fd = -1;
        !           128:     pp->unitptr = (caddr_t) up;
        !           129:     get_systime(&pp->lastrec);
        !           130:     memcpy(&pp->refid, REFID, 4);
        !           131:     peer->precision = PRECISION;
        !           132:     pp->clockdesc = DESCRIPTION;
        !           133:     up->unit = unit;
        !           134: #ifdef __hpux     
        !           135:     rtprio(0,120);             /* set real time priority       */
        !           136:     plock(PROCLOCK);           /* lock process in memory       */
        !           137: #endif /* __hpux       */     
        !           138:     return 1;
        !           139: }
        !           140: 
        !           141: /* psc_shutdown:  shut down the clock */
        !           142: static void
        !           143: psc_shutdown(
        !           144:     int                unit,
        !           145:     struct peer        *peer
        !           146:     )
        !           147: {
        !           148:     if (NULL != peer->procptr->unitptr)
        !           149:        free(peer->procptr->unitptr);
        !           150:     if (fd[unit] > 0)
        !           151:        close(fd[unit]);
        !           152: }
        !           153: 
        !           154: /* psc_poll:  read, decode, and record device time */
        !           155: static void
        !           156: psc_poll(
        !           157:     int                unit,
        !           158:     struct peer        *peer
        !           159:     )
        !           160: {
        !           161:     struct refclockproc        *pp = peer->procptr;
        !           162:     struct psc_unit            *up;
        !           163:     unsigned                   tlo, thi;
        !           164:     unsigned char              status;
        !           165: 
        !           166:     up = (struct psc_unit *) pp->unitptr;
        !           167:     tlo = regp[unit]->low_time;                /* latch and read first 4 bytes */
        !           168:     thi = regp[unit]->high_time;       /* read 4 higher order bytes    */
        !           169:     status = regp[unit]->device_status;        /* read device status byte      */
        !           170: 
        !           171:     if (!(status & PSC_SYNC_OK)) {
        !           172:        refclock_report(peer, CEVNT_BADTIME);
        !           173:        if (!up->msg_flag[unit]) {      /* write once to system log     */
        !           174:            msyslog(LOG_WARNING,
        !           175:                "SYNCHRONIZATION LOST on unit %1d, status %02x\n",
        !           176:                status, unit);
        !           177:            up->msg_flag[unit] = 1;
        !           178:        }
        !           179:        return;
        !           180:     }
        !           181: 
        !           182:     get_systime(&pp->lastrec);
        !           183:     pp->polls++;
        !           184:      
        !           185:     tlo = SWAP(tlo);                   /* little to big endian swap on */
        !           186:     thi = SWAP(thi);                   /* copy of data                 */
        !           187:     /* convert the BCD time to broken down time used by refclockproc   */
        !           188:     pp->day    = BCD2INT3((thi & 0x0FFF0000) >> 16);
        !           189:     pp->hour   = BCD2INT2((thi & 0x0000FF00) >> 8);
        !           190:     pp->minute = BCD2INT2(thi & 0x000000FF);
        !           191:     pp->second = BCD2INT2(tlo >> 24);
        !           192:     /* ntp_process() in ntp_refclock.c appears to use usec as fraction of
        !           193:        second in microseconds if usec is nonzero. */
        !           194:     pp->nsec   = 1000000*BCD2INT3((tlo & 0x00FFF000) >> 12) +
        !           195:        BCD2INT3(tlo & 0x00000FFF);
        !           196: 
        !           197:     snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
        !           198:             "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x", pp->day,
        !           199:             pp->hour, pp->minute, pp->second, pp->nsec, status, thi,
        !           200:             tlo);
        !           201:     pp->lencode = strlen(pp->a_lastcode);
        !           202: 
        !           203:     /* compute the timecode timestamp  */
        !           204:     if (!refclock_process(pp)) {
        !           205:        refclock_report(peer, CEVNT_BADTIME);
        !           206:        return;
        !           207:     }
        !           208:     /* simulate the NTP receive and packet procedures  */
        !           209:     refclock_receive(peer);
        !           210:     /* write clock statistics to file  */
        !           211:     record_clock_stats(&peer->srcadr, pp->a_lastcode); 
        !           212: 
        !           213:     /* With the first timecode beginning the day, check for a GPS
        !           214:        leap second notification.      */
        !           215:     if (pp->hour < up->last_hour) {
        !           216:        check_leap_sec(pp, unit);
        !           217:        up->msg_flag[0] = up->msg_flag[1] = 0;  /* reset flags  */
        !           218:     }
        !           219:     up->last_hour = pp->hour;
        !           220: }
        !           221: 
        !           222: /* check_leap_sec:  read the Dual Port RAM leap second day registers.  The
        !           223:    onboard GPS receiver should write the hundreds digit of day of year in
        !           224:    DP_LeapSec_Day1000Day100 and the tens and ones digits in
        !           225:    DP_LeapSec_Day10Day1.  If these values are nonzero and today, we have
        !           226:    a leap second pending, so we set the pp->leap flag to LEAP_ADDSECOND.
        !           227:    If the BCD data are zero or a date other than today, set pp->leap to
        !           228:    LEAP_NOWARNING.  */
        !           229: static void
        !           230: check_leap_sec(struct refclockproc *pp, int unit)
        !           231: {
        !           232:     unsigned char      dhi, dlo;
        !           233:     int                        leap_day;
        !           234:      
        !           235:     regp[unit]->dp_ram_addr = DP_LEAPSEC_DAY10DAY1;
        !           236:     usleep(DELAY);
        !           237:     dlo = regp[unit]->dp_ram_data;
        !           238:     regp[unit]->dp_ram_addr = DP_LEAPSEC_DAY1000DAY100;
        !           239:     usleep(DELAY);
        !           240:     dhi = regp[unit]->dp_ram_data;
        !           241:     leap_day = BCD2INT2(dlo) + 100*(dhi & 0x0F);
        !           242: 
        !           243:     pp->leap = LEAP_NOWARNING;                 /* default      */
        !           244:     if (leap_day && leap_day == pp->day) {
        !           245:        pp->leap = LEAP_ADDSECOND;              /* leap second today    */
        !           246:        msyslog(LOG_ERR, "LEAP_ADDSECOND flag set, day %d (%x %x).",
        !           247:            leap_day, dhi, dlo);
        !           248:     }
        !           249: }
        !           250: 
        !           251: #else
        !           252: int    refclock_gpsvme_bs;
        !           253: #endif /* REFCLOCK     */

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