Annotation of embedaddon/ntp/ntpd/refclock_gpsvme.c, revision 1.1.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, ®p[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>