Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / ntpd / refclock_bancomm.c
blobade90b484eb86b3a60c7f83c5833a5358dff6904
1 /* $NetBSD: refclock_bancomm.c,v 1.2 2003/12/04 16:23:37 drochner Exp $ */
3 /* refclock_bancomm.c - clock driver for the Datum/Bancomm bc635VME
4 * Time and Frequency Processor. It requires the BANCOMM bc635VME/
5 * bc350VXI Time and Frequency Processor Module Driver for SunOS4.x
6 * and SunOS5.x UNIX Systems. It has been tested on a UltraSparc
7 * IIi-cEngine running Solaris 2.6.
8 *
9 * Author(s): Ganesh Ramasivan & Gary Cliff, Computing Devices Canada,
10 * Ottawa, Canada
12 * Date: July 1999
14 * Note(s): The refclock type has been defined as 16.
16 * This program has been modelled after the Bancomm driver
17 * originally written by R. Schmidt of Time Service, U.S.
18 * Naval Observatory for a HP-UX machine. Since the original
19 * authors no longer plan to maintain this code, all
20 * references to the HP-UX vme2 driver subsystem bave been
21 * removed. Functions vme_report_event(), vme_receive(),
22 * vme_control() and vme_buginfo() have been deleted because
23 * they are no longer being used.
25 * The time on the bc635 TFP must be set to GMT due to the
26 * fact that NTP makes use of GMT for all its calculations.
28 * Installation of the Datum/Bancomm driver creates the
29 * device file /dev/btfp0
31 * 04/28/2005 Rob Neal
32 * Modified to add support for Symmetricom bc637PCI-U Time &
33 * Frequency Processor.
34 * Card bus type (VME/VXI or PCI) and environment are specified via the
35 * "mode" keyword on the server command in ntp.conf.
36 * server 127.127.16.u prefer mode m (...)
37 * Modes currently supported are
38 * 1 : FreeBSD PCI 635/637.
39 * 2 : Linux or Windows 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 * Tested on FreeBSD 5.3 with a 637 card.
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif
51 #if defined(REFCLOCK) && defined(CLOCK_BANC)
53 #include "ntpd.h"
54 #include "ntp_io.h"
55 #include "ntp_refclock.h"
56 #include "ntp_unixtime.h"
57 #include "ntp_stdlib.h"
59 #include <stdio.h>
60 #include <syslog.h>
61 #include <ctype.h>
63 /* STUFF BY RES */
64 struct btfp_time /* Structure for reading 5 time words */
65 /* in one ioctl(2) operation. */
67 unsigned short btfp_time[5]; /* Time words 0,1,2,3, and 4. (16bit)*/
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 )
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 *****/
82 /* Read all 5 time words in one call. */
83 #define READTIME IOCIORN(b, 32, sizeof( struct btfp_time ))
85 #if defined(__FreeBSD__)
86 #undef READTIME
87 #define READTIME _IOR('u', 5, struct btfp_time )
88 #endif
90 #define VMEFD "/dev/btfp0"
92 struct vmedate { /* structure returned by get_vmetime.c */
93 unsigned short year;
94 unsigned short day;
95 unsigned short hr;
96 unsigned short mn;
97 unsigned short sec;
98 long frac;
99 unsigned short status;
102 /* END OF STUFF FROM RES */
103 typedef void *SYMMT_PCI_HANDLE;
106 * VME interface parameters.
108 #define VMEPRECISION (-21) /* precision assumed (1 us) */
109 #define USNOREFID "BTFP" /* or whatever */
110 #define VMEREFID "BTFP" /* reference id */
111 #define VMEDESCRIPTION "Bancomm bc635 TFP" /* who we are */
112 #define VMEHSREFID 0x7f7f1000 /* 127.127.16.00 refid hi strata */
113 /* clock type 16 is used here */
114 #define GMT 0 /* hour offset from Greenwich */
117 * Imported from ntp_timer module
119 extern u_long current_time; /* current time(s) */
122 * Imported from ntpd module
124 extern volatile int debug; /* global debug flag */
127 * VME unit control structure.
128 * Changes made to vmeunit structure. Most members are now available in the
129 * new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan
131 struct vmeunit {
132 struct vmedate vmedata; /* data returned from vme read */
133 u_long lasttime; /* last time clock heard from */
137 * Function prototypes
139 static int vme_start (int, struct peer *);
140 static void vme_shutdown (int, struct peer *);
141 static void vme_receive (struct recvbuf *);
142 static void vme_poll (int unit, struct peer *);
143 struct vmedate *get_datumtime(struct vmedate *);
144 void tvme_fill(struct vmedate *, uint32_t btm[2]);
146 * Define the bc*() functions as weak so we can compile/link without them.
147 * Only clients with the card will have the proprietary vendor device driver
148 * and interface library needed for use on Linux/Windows platforms.
150 extern uint32_t __attribute__ ((weak)) bcReadBinTime(SYMMT_PCI_HANDLE, uint32_t *, uint32_t*, uint8_t*);
151 extern SYMMT_PCI_HANDLE __attribute__ ((weak)) bcStartPci(void);
152 extern void __attribute__ ((weak)) bcStopPci(SYMMT_PCI_HANDLE);
155 * Transfer vector
157 struct refclock refclock_bancomm = {
158 vme_start, /* start up driver */
159 vme_shutdown, /* shut down driver */
160 vme_poll, /* transmit poll message */
161 noentry, /* not used (old vme_control) */
162 noentry, /* initialize driver */
163 noentry, /* not used (old vme_buginfo) */
164 NOFLAGS /* not used */
167 int fd_vme; /* file descriptor for ioctls */
168 int regvalue;
169 int tfp_type; /* mode selector, indicate platform and driver interface */
170 SYMMT_PCI_HANDLE stfp_handle;
174 * vme_start - open the VME device and initialize data for processing
176 static int
177 vme_start(
178 int unit,
179 struct peer *peer
182 register struct vmeunit *vme;
183 struct refclockproc *pp;
184 int dummy;
185 char vmedev[20];
187 tfp_type = (int)(peer->ttl);
188 switch (tfp_type) {
189 case 1:
190 break;
191 case 2:
192 stfp_handle = bcStartPci(); /* init the card in lin/win */
193 break;
194 default:
195 break;
198 * Open VME device
200 #ifdef DEBUG
202 printf("Opening DATUM VME DEVICE \n");
203 #endif
204 if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) {
205 msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
206 return (0);
208 else {
209 switch (tfp_type) {
210 case 1: break;
211 case 2: break;
212 default:
213 /* Release capture lockout in case it was set before. */
214 if( ioctl( fd_vme, RUNLOCK, &dummy ) )
215 msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m");
217 regvalue = 0; /* More esoteric stuff to do... */
218 if( ioctl( fd_vme, WCR0, &regvalue ) )
219 msyslog(LOG_ERR, "vme_start: WCR0 failed %m");
220 break;
225 * Allocate unit structure
227 vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit));
228 bzero((char *)vme, sizeof(struct vmeunit));
232 * Set up the structures
234 pp = peer->procptr;
235 pp->unitptr = (caddr_t) vme;
236 pp->timestarted = current_time;
238 pp->io.clock_recv = vme_receive;
239 pp->io.srcclock = (caddr_t)peer;
240 pp->io.datalen = 0;
241 pp->io.fd = fd_vme;
244 * All done. Initialize a few random peer variables, then
245 * return success. Note that root delay and root dispersion are
246 * always zero for this clock.
248 peer->precision = VMEPRECISION;
249 memcpy(&pp->refid, USNOREFID,4);
250 return (1);
255 * vme_shutdown - shut down a VME clock
257 static void
258 vme_shutdown(
259 int unit,
260 struct peer *peer
263 register struct vmeunit *vme;
264 struct refclockproc *pp;
267 * Tell the I/O module to turn us off. We're history.
269 pp = peer->procptr;
270 vme = (struct vmeunit *)pp->unitptr;
271 io_closeclock(&pp->io);
272 pp->unitptr = NULL;
273 free(vme);
274 if (tfp_type == 2) bcStopPci(stfp_handle);
279 * vme_receive - receive data from the VME device.
281 * Note: This interface would be interrupt-driven. We don't use that
282 * now, but include a dummy routine for possible future adventures.
284 static void
285 vme_receive(
286 struct recvbuf *rbufp
293 * vme_poll - called by the transmit procedure
295 static void
296 vme_poll(
297 int unit,
298 struct peer *peer
301 struct vmedate *tptr;
302 struct vmeunit *vme;
303 struct refclockproc *pp;
304 time_t tloc;
305 struct tm *tadr;
307 pp = peer->procptr;
308 vme = (struct vmeunit *)pp->unitptr; /* Here is the structure */
310 tptr = &vme->vmedata;
311 if ((tptr = get_datumtime(tptr)) == NULL ) {
312 refclock_report(peer, CEVNT_BADREPLY);
313 return;
316 get_systime(&pp->lastrec);
317 pp->polls++;
318 vme->lasttime = current_time;
321 * Get VME time and convert to timestamp format.
322 * The year must come from the system clock.
325 time(&tloc);
326 tadr = gmtime(&tloc);
327 tptr->year = (unsigned short)(tadr->tm_year + 1900);
329 sprintf(pp->a_lastcode,
330 "%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d",
331 tptr->day,
332 tptr->hr,
333 tptr->mn,
334 tptr->sec,
335 tptr->frac,
336 tptr->status);
338 pp->lencode = (u_short) strlen(pp->a_lastcode);
340 pp->day = tptr->day;
341 pp->hour = tptr->hr;
342 pp->minute = tptr->mn;
343 pp->second = tptr->sec;
344 pp->nsec = tptr->frac;
346 #ifdef DEBUG
347 if (debug)
348 printf("pp: %3d %02d:%02d:%02d.%06ld %1x\n",
349 pp->day, pp->hour, pp->minute, pp->second,
350 pp->nsec, tptr->status);
351 #endif
352 if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */
353 refclock_report(peer, CEVNT_BADREPLY);
354 return;
358 * Now, compute the reference time value. Use the heavy
359 * machinery for the seconds and the millisecond field for the
360 * fraction when present. If an error in conversion to internal
361 * format is found, the program declares bad data and exits.
362 * Note that this code does not yet know how to do the years and
363 * relies on the clock-calendar chip for sanity.
365 if (!refclock_process(pp)) {
366 refclock_report(peer, CEVNT_BADTIME);
367 return;
369 pp->lastref = pp->lastrec;
370 refclock_receive(peer);
371 record_clock_stats(&peer->srcadr, pp->a_lastcode);
374 struct vmedate *
375 get_datumtime(struct vmedate *time_vme)
377 char cbuf[7];
378 struct btfp_time vts;
379 uint32_t btm[2];
380 uint8_t dmy;
382 if ( time_vme == (struct vmedate *)NULL) {
383 time_vme = (struct vmedate *)malloc(sizeof(struct vmedate ));
386 switch (tfp_type) {
387 case 1: /* BSD, PCI, 2 32bit time words */
388 if (ioctl(fd_vme, READTIME, &btm)) {
389 msyslog(LOG_ERR, "get_bc63x error: %m");
390 return(NULL);
392 tvme_fill(time_vme, btm);
393 break;
395 case 2: /* Linux/Windows, PCI, 2 32bit time words */
396 if (bcReadBinTime(stfp_handle, &btm[1], &btm[0], &dmy) == 0) {
397 msyslog(LOG_ERR, "get_datumtime error: %m");
398 return(NULL);
400 tvme_fill(time_vme, btm);
401 break;
403 default: /* legacy bancomm card */
405 if (ioctl(fd_vme, READTIME, &vts)) {
406 msyslog(LOG_ERR, "get_datumtime error: %m");
407 return(NULL);
409 /* Get day */
410 sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
411 ((vts.btfp_time[ 1 ] & 0xff00) >> 8));
412 time_vme->day = (unsigned short)atoi(cbuf);
414 /* Get hour */
415 sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff);
417 time_vme->hr = (unsigned short)atoi(cbuf);
419 /* Get minutes */
420 sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8);
421 time_vme->mn = (unsigned short)atoi(cbuf);
423 /* Get seconds */
424 sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff);
425 time_vme->sec = (unsigned short)atoi(cbuf);
427 /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so
428 we can use the TVTOTSF function later on...*/
430 sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ],
431 vts.btfp_time[ 4 ]>>8);
433 time_vme->frac = (u_long) atoi(cbuf);
435 /* Get status bit */
436 time_vme->status = (vts.btfp_time[0] & 0x0010) >>4;
438 break;
441 if (time_vme->status)
442 return ((void *)NULL);
443 else
444 return (time_vme);
446 /* Assign values to time_vme struct. Mostly for readability */
447 void
448 tvme_fill(struct vmedate *time_vme, uint32_t btm[2])
450 struct tm maj;
451 uint32_t dmaj, dmin;
453 dmaj = btm[1]; /* syntax sugar */
454 dmin = btm[0];
456 gmtime_r(&dmaj, &maj);
457 time_vme->day = maj.tm_yday+1;
458 time_vme->hr = maj.tm_hour;
459 time_vme->mn = maj.tm_min;
460 time_vme->sec = maj.tm_sec;
461 time_vme->frac = (dmin & 0x000fffff) * 1000;
462 time_vme->frac += ((dmin & 0x00f00000) >> 20) * 100;
463 time_vme->status = (dmin & 0x01000000) >> 24;
464 return;
467 #else
468 int refclock_bancomm_bs;
469 #endif /* REFCLOCK */