154359Sroberto/* refclock_bancomm.c - clock driver for the  Datum/Bancomm bc635VME
254359Sroberto * Time and Frequency Processor. It requires the BANCOMM bc635VME/
354359Sroberto * bc350VXI Time and Frequency Processor Module Driver for SunOS4.x
454359Sroberto * and SunOS5.x UNIX Systems. It has been tested on a UltraSparc
554359Sroberto * IIi-cEngine running Solaris 2.6.
654359Sroberto *
754359Sroberto * Author(s): 	Ganesh Ramasivan & Gary Cliff, Computing Devices Canada,
854359Sroberto *		Ottawa, Canada
954359Sroberto *
1054359Sroberto * Date: 	July 1999
1154359Sroberto *
1254359Sroberto * Note(s):	The refclock type has been defined as 16.
1354359Sroberto *
1454359Sroberto *		This program has been modelled after the Bancomm driver
1554359Sroberto *		originally written by R. Schmidt of Time Service, U.S.
1654359Sroberto *		Naval Observatory for a HP-UX machine. Since the original
1754359Sroberto *		authors no longer plan to maintain this code, all
1854359Sroberto *		references to the HP-UX vme2 driver subsystem bave been
1954359Sroberto *		removed. Functions vme_report_event(), vme_receive(),
2054359Sroberto *		vme_control() and vme_buginfo() have been deleted because
2154359Sroberto *		they are no longer being used.
2254359Sroberto *
23182007Sroberto *	04/28/2005 Rob Neal
24182007Sroberto *		Modified to add support for Symmetricom bc637PCI-U Time &
25182007Sroberto *		Frequency Processor.
26290001Sglebius *	2/21/2007 Ali Ghorashi
27290001Sglebius *	        Modified to add support for Symmetricom bc637PCI-U Time &
28290001Sglebius *		Frequency Processor on Solaris.
29290001Sglebius *		Tested on Solaris 10 with a bc635 card.
30290001Sglebius *
31182007Sroberto *		Card bus type (VME/VXI or PCI) and environment are specified via the
32182007Sroberto *		"mode" keyword on the server command in ntp.conf.
33290001Sglebius *		server 127.127.16.u prefer mode M
34290001Sglebius *		where u is the id (usually 0) of the entry in /dev (/dev/stfp0)
35290001Sglebius *
36290001Sglebius *		and M is one of the following modes:
37182007Sroberto *		1		: FreeBSD PCI 635/637.
38182007Sroberto *		2		: Linux or Windows PCI 635/637.
39290001Sglebius *		3		: Solaris PCI 635/637
40182007Sroberto *		not specified, or other number:
41182007Sroberto *				: Assumed to be VME/VXI legacy Bancomm card on Solaris.
42182007Sroberto *		Linux and Windows platforms require Symmetricoms' proprietary driver
43290001Sglebius *		for the TFP card.
44290001Sglebius *		Solaris requires Symmetricom's driver and its header file (freely distributed) to
45290001Sglebius *		be installed and running.
4654359Sroberto */
4754359Sroberto
4854359Sroberto#ifdef HAVE_CONFIG_H
4954359Sroberto#include <config.h>
5054359Sroberto#endif
5154359Sroberto
5254359Sroberto#if defined(REFCLOCK) && defined(CLOCK_BANC)
5354359Sroberto
5454359Sroberto#include "ntpd.h"
5554359Sroberto#include "ntp_io.h"
5654359Sroberto#include "ntp_refclock.h"
5754359Sroberto#include "ntp_unixtime.h"
5854359Sroberto#include "ntp_stdlib.h"
5954359Sroberto
6082498Sroberto#include <stdio.h>
6182498Sroberto#include <syslog.h>
6282498Sroberto#include <ctype.h>
6382498Sroberto
6454359Srobertostruct btfp_time                /* Structure for reading 5 time words   */
6554359Sroberto                                /* in one ioctl(2) operation.           */
6654359Sroberto{
6754359Sroberto	unsigned short btfp_time[5];  /* Time words 0,1,2,3, and 4. (16bit)*/
6854359Sroberto};
6954359Sroberto/* SunOS5 ioctl commands definitions.*/
7054359Sroberto#define BTFPIOC            ( 'b'<< 8 )
7154359Sroberto#define IOCIO( l, n )      ( BTFPIOC | n )
7254359Sroberto#define IOCIOR( l, n, s )  ( BTFPIOC | n )
7354359Sroberto#define IOCIORN( l, n, s ) ( BTFPIOC | n )
7454359Sroberto#define IOCIOWN( l, n, s ) ( BTFPIOC | n )
7554359Sroberto
7654359Sroberto/***** Simple ioctl commands *****/
7754359Sroberto#define RUNLOCK     	IOCIOR(b, 19, int )  /* Release Capture Lockout */
7854359Sroberto#define RCR0      	IOCIOR(b, 22, int )  /* Read control register zero.*/
7954359Sroberto#define	WCR0		IOCIOWN(b, 23, int)	     /* Write control register zero*/
8054359Sroberto/***** Compound ioctl commands *****/
8154359Sroberto
8254359Sroberto/* Read all 5 time words in one call.   */
8354359Sroberto#define READTIME	IOCIORN(b, 32, sizeof( struct btfp_time ))
84182007Sroberto
85182007Sroberto#if defined(__FreeBSD__)
86182007Sroberto#undef  READTIME
87182007Sroberto#define READTIME	_IOR('u', 5, struct btfp_time )
88182007Sroberto#endif
89182007Sroberto
90290001Sglebius/* Solaris specific section */
91290001Sglebiusstruct	stfp_tm {
92290001Sglebius	int32_t tm_sec;
93290001Sglebius	int32_t tm_min;
94290001Sglebius	int32_t tm_hour;
95290001Sglebius	int32_t tm_mday;
96290001Sglebius	int32_t tm_mon;
97290001Sglebius	int32_t tm_year;
98290001Sglebius	int32_t tm_wday;
99290001Sglebius	int32_t tm_yday;
100290001Sglebius	int32_t tm_isdst;
101290001Sglebius};
10254359Sroberto
103290001Sglebiusstruct stfp_time {
104290001Sglebius	struct stfp_tm	tm;
105290001Sglebius	int32_t 	usec;			/* usec 0 - 999999 */
106290001Sglebius	int32_t 	hnsec;			/* hnsec 0 - 9 (hundreds of nsecs) */
107290001Sglebius	int32_t 	status;
108290001Sglebius};
109290001Sglebius
110290001Sglebius#define SELTIMEFORMAT	2
111290001Sglebius#	define TIME_DECIMAL 0
112290001Sglebius#	define TIME_BINARY	1
113290001Sglebius
114290001Sglebius#if defined(__sun__)
115290001Sglebius#undef	READTIME
116290001Sglebius#define READTIME		9
117290001Sglebius#endif /** __sun___ **/
118290001Sglebius/* end solaris specific section */
119290001Sglebius
120290001Sglebiusstruct vmedate {			   /* structure returned by get_vmetime.c */
12154359Sroberto	unsigned short year;
12254359Sroberto	unsigned short day;
12354359Sroberto	unsigned short hr;
12454359Sroberto	unsigned short mn;
12554359Sroberto	unsigned short sec;
126182007Sroberto	long frac;
12754359Sroberto	unsigned short status;
12854359Sroberto};
12954359Sroberto
130182007Srobertotypedef void *SYMMT_PCI_HANDLE;
13154359Sroberto
13254359Sroberto/*
13354359Sroberto * VME interface parameters.
13454359Sroberto */
13554359Sroberto#define VMEPRECISION    (-21)   /* precision assumed (1 us) */
13654359Sroberto#define USNOREFID       "BTFP"  /* or whatever */
13754359Sroberto#define VMEREFID        "BTFP"  /* reference id */
13854359Sroberto#define VMEDESCRIPTION  "Bancomm bc635 TFP" /* who we are */
13954359Sroberto#define VMEHSREFID      0x7f7f1000 /* 127.127.16.00 refid hi strata */
14054359Sroberto/* clock type 16 is used here  */
14154359Sroberto#define GMT           	0       /* hour offset from Greenwich */
14254359Sroberto
14354359Sroberto/*
14454359Sroberto * Imported from ntp_timer module
14554359Sroberto */
14654359Srobertoextern u_long current_time;     /* current time(s) */
14754359Sroberto
14854359Sroberto/*
14954359Sroberto * VME unit control structure.
15054359Sroberto * Changes made to vmeunit structure. Most members are now available in the
15154359Sroberto * new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan
15254359Sroberto */
15354359Srobertostruct vmeunit {
15454359Sroberto	struct vmedate vmedata; /* data returned from vme read */
15554359Sroberto	u_long lasttime;        /* last time clock heard from */
15654359Sroberto};
15754359Sroberto
15854359Sroberto/*
15954359Sroberto * Function prototypes
16054359Sroberto */
16154359Srobertostatic  int     vme_start       (int, struct peer *);
16254359Srobertostatic  void    vme_shutdown    (int, struct peer *);
16354359Srobertostatic  void    vme_receive     (struct recvbuf *);
16454359Srobertostatic  void    vme_poll        (int unit, struct peer *);
165182007Srobertostruct vmedate *get_datumtime(struct vmedate *);
166290001Sglebiusvoid	tvme_fill(struct vmedate *, uint32_t btm[2]);
167290001Sglebiusvoid	stfp_time2tvme(struct vmedate *time_vme, struct stfp_time *stfp);
168290001Sglebiusinline const char *DEVICE_NAME(int n);
169290001Sglebius
170290001Sglebius
171182007Sroberto/*
172182007Sroberto * Define the bc*() functions as weak so we can compile/link without them.
173182007Sroberto * Only clients with the card will have the proprietary vendor device driver
174182007Sroberto * and interface library needed for use on Linux/Windows platforms.
175182007Sroberto */
176182007Srobertoextern uint32_t __attribute__ ((weak)) bcReadBinTime(SYMMT_PCI_HANDLE, uint32_t *, uint32_t*, uint8_t*);
177182007Srobertoextern SYMMT_PCI_HANDLE __attribute__ ((weak)) bcStartPci(void);
178182007Srobertoextern void __attribute__ ((weak)) bcStopPci(SYMMT_PCI_HANDLE);
17954359Sroberto
18054359Sroberto/*
18154359Sroberto * Transfer vector
18254359Sroberto */
18354359Srobertostruct  refclock refclock_bancomm = {
18482498Sroberto	vme_start, 		/* start up driver */
18582498Sroberto	vme_shutdown,		/* shut down driver */
18682498Sroberto	vme_poll,		/* transmit poll message */
18782498Sroberto	noentry,		/* not used (old vme_control) */
18882498Sroberto	noentry,		/* initialize driver */
18982498Sroberto	noentry,		/* not used (old vme_buginfo) */
19082498Sroberto	NOFLAGS			/* not used */
19154359Sroberto};
19254359Sroberto
19354359Srobertoint fd_vme;  /* file descriptor for ioctls */
19454359Srobertoint regvalue;
195182007Srobertoint tfp_type;	/* mode selector, indicate platform and driver interface */
196182007SrobertoSYMMT_PCI_HANDLE stfp_handle;
19754359Sroberto
198290001Sglebius/**
199290001Sglebius * this macro returns the device name based on
200290001Sglebius * the platform we are running on and the device number
201290001Sglebius */
202290001Sglebius#if defined(__sun__)
203290001Sglebiusinline const char *DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/stfp%d",n);return s;}
204290001Sglebius#else
205290001Sglebiusinline const char* DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/btfp%d",n);return s;}
206290001Sglebius#endif /**__sun__**/
20754359Sroberto
20854359Sroberto/*
20954359Sroberto * vme_start - open the VME device and initialize data for processing
21054359Sroberto */
21154359Srobertostatic int
21254359Srobertovme_start(
21354359Sroberto	int unit,
21454359Sroberto	struct peer *peer
21554359Sroberto	)
21654359Sroberto{
21754359Sroberto	register struct vmeunit *vme;
21854359Sroberto	struct refclockproc *pp;
21954359Sroberto	int dummy;
22054359Sroberto	char vmedev[20];
221182007Sroberto
222182007Sroberto	tfp_type = (int)(peer->ttl);
223182007Sroberto	switch (tfp_type) {
224182007Sroberto		case 1:
225290001Sglebius		case 3:
226182007Sroberto			break;
227182007Sroberto		case 2:
228182007Sroberto			stfp_handle = bcStartPci(); 	/* init the card in lin/win */
229182007Sroberto			break;
230182007Sroberto		default:
231182007Sroberto			break;
232182007Sroberto	}
23354359Sroberto	/*
23454359Sroberto	 * Open VME device
23554359Sroberto	 */
23654359Sroberto#ifdef DEBUG
23754359Sroberto
238290001Sglebius	printf("Opening DATUM DEVICE %s\n",DEVICE_NAME(peer->refclkunit));
23954359Sroberto#endif
240290001Sglebius	if ( (fd_vme = open(DEVICE_NAME(peer->refclkunit), O_RDWR)) < 0) {
24154359Sroberto		msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
24254359Sroberto		return (0);
24354359Sroberto	}
244182007Sroberto	else  {
245182007Sroberto		switch (tfp_type) {
246182007Sroberto		  	case 1:	break;
247182007Sroberto			case 2: break;
248290001Sglebius			case 3:break;
249182007Sroberto			default:
250182007Sroberto				/* Release capture lockout in case it was set before. */
251182007Sroberto				if( ioctl( fd_vme, RUNLOCK, &dummy ) )
252182007Sroberto		    		msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m");
25354359Sroberto
254182007Sroberto				regvalue = 0; /* More esoteric stuff to do... */
255182007Sroberto				if( ioctl( fd_vme, WCR0, &regvalue ) )
256182007Sroberto		    		msyslog(LOG_ERR, "vme_start: WCR0 failed %m");
257182007Sroberto				break;
258182007Sroberto		}
25954359Sroberto	}
26054359Sroberto
26154359Sroberto	/*
26254359Sroberto	 * Allocate unit structure
26354359Sroberto	 */
264290001Sglebius	vme = emalloc_zero(sizeof(struct vmeunit));
26554359Sroberto
26654359Sroberto
26754359Sroberto	/*
26854359Sroberto	 * Set up the structures
26954359Sroberto	 */
27054359Sroberto	pp = peer->procptr;
271290001Sglebius	pp->unitptr = vme;
27254359Sroberto	pp->timestarted = current_time;
27354359Sroberto
27454359Sroberto	pp->io.clock_recv = vme_receive;
275290001Sglebius	pp->io.srcclock = peer;
27654359Sroberto	pp->io.datalen = 0;
27754359Sroberto	pp->io.fd = fd_vme;
278290001Sglebius	/* shouldn't there be an io_addclock() call? */
27954359Sroberto
28054359Sroberto	/*
28154359Sroberto	 * All done.  Initialize a few random peer variables, then
28254359Sroberto 	 * return success. Note that root delay and root dispersion are
28354359Sroberto	 * always zero for this clock.
28454359Sroberto	 */
28554359Sroberto	peer->precision = VMEPRECISION;
28682498Sroberto	memcpy(&pp->refid, USNOREFID,4);
28754359Sroberto	return (1);
28854359Sroberto}
28954359Sroberto
29054359Sroberto
29154359Sroberto/*
29254359Sroberto * vme_shutdown - shut down a VME clock
29354359Sroberto */
29454359Srobertostatic void
29554359Srobertovme_shutdown(
29654359Sroberto	int unit,
29754359Sroberto	struct peer *peer
29854359Sroberto	)
29954359Sroberto{
30054359Sroberto	register struct vmeunit *vme;
30154359Sroberto	struct refclockproc *pp;
30254359Sroberto
30354359Sroberto	/*
30454359Sroberto	 * Tell the I/O module to turn us off.  We're history.
30554359Sroberto	 */
30682498Sroberto	pp = peer->procptr;
307290001Sglebius	vme = pp->unitptr;
30854359Sroberto	io_closeclock(&pp->io);
30954359Sroberto	pp->unitptr = NULL;
310290001Sglebius	if (NULL != vme)
311290001Sglebius		free(vme);
312290001Sglebius	if (tfp_type == 2)
313290001Sglebius		bcStopPci(stfp_handle);
31454359Sroberto}
31554359Sroberto
31654359Sroberto
31754359Sroberto/*
31854359Sroberto * vme_receive - receive data from the VME device.
31954359Sroberto *
32054359Sroberto * Note: This interface would be interrupt-driven. We don't use that
32154359Sroberto * now, but include a dummy routine for possible future adventures.
32254359Sroberto */
32354359Srobertostatic void
32454359Srobertovme_receive(
32554359Sroberto	struct recvbuf *rbufp
32654359Sroberto	)
32754359Sroberto{
32854359Sroberto}
32954359Sroberto
33054359Sroberto
33154359Sroberto/*
33254359Sroberto * vme_poll - called by the transmit procedure
33354359Sroberto */
33454359Srobertostatic void
33554359Srobertovme_poll(
33654359Sroberto	int unit,
33754359Sroberto	struct peer *peer
33854359Sroberto	)
33954359Sroberto{
34054359Sroberto	struct vmedate *tptr;
34154359Sroberto	struct vmeunit *vme;
34254359Sroberto	struct refclockproc *pp;
34354359Sroberto	time_t tloc;
34454359Sroberto	struct tm *tadr;
34554359Sroberto
34654359Sroberto	pp = peer->procptr;
347290001Sglebius	vme = pp->unitptr;        /* Here is the structure */
34854359Sroberto
34954359Sroberto	tptr = &vme->vmedata;
35054359Sroberto	if ((tptr = get_datumtime(tptr)) == NULL ) {
35154359Sroberto		refclock_report(peer, CEVNT_BADREPLY);
35254359Sroberto		return;
35354359Sroberto	}
35454359Sroberto
35554359Sroberto	get_systime(&pp->lastrec);
35654359Sroberto	pp->polls++;
35754359Sroberto	vme->lasttime = current_time;
35854359Sroberto
35954359Sroberto	/*
36054359Sroberto	 * Get VME time and convert to timestamp format.
36154359Sroberto	 * The year must come from the system clock.
36254359Sroberto	 */
36354359Sroberto
36454359Sroberto	  time(&tloc);
36554359Sroberto	  tadr = gmtime(&tloc);
36654359Sroberto	  tptr->year = (unsigned short)(tadr->tm_year + 1900);
36754359Sroberto
368290001Sglebius	snprintf(pp->a_lastcode,
369290001Sglebius		 sizeof(pp->a_lastcode),
370290001Sglebius		 "%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d",
371290001Sglebius		 tptr->day,
372290001Sglebius		 tptr->hr,
373290001Sglebius		 tptr->mn,
374290001Sglebius		 tptr->sec,
375290001Sglebius		 tptr->frac,
376290001Sglebius		 tptr->status);
37754359Sroberto
37854359Sroberto	pp->lencode = (u_short) strlen(pp->a_lastcode);
37954359Sroberto
38054359Sroberto	pp->day =  tptr->day;
38154359Sroberto	pp->hour =   tptr->hr;
38254359Sroberto	pp->minute =  tptr->mn;
38354359Sroberto	pp->second =  tptr->sec;
384182007Sroberto	pp->nsec =   tptr->frac;
38554359Sroberto
38654359Sroberto#ifdef DEBUG
38754359Sroberto	if (debug)
38854359Sroberto	    printf("pp: %3d %02d:%02d:%02d.%06ld %1x\n",
38954359Sroberto		   pp->day, pp->hour, pp->minute, pp->second,
390182007Sroberto		   pp->nsec, tptr->status);
39154359Sroberto#endif
39254359Sroberto	if (tptr->status ) {       /*  Status 0 is locked to ref., 1 is not */
39354359Sroberto		refclock_report(peer, CEVNT_BADREPLY);
39454359Sroberto		return;
39554359Sroberto	}
39654359Sroberto
39754359Sroberto	/*
39854359Sroberto	 * Now, compute the reference time value. Use the heavy
39954359Sroberto	 * machinery for the seconds and the millisecond field for the
40054359Sroberto	 * fraction when present. If an error in conversion to internal
40154359Sroberto	 * format is found, the program declares bad data and exits.
40254359Sroberto	 * Note that this code does not yet know how to do the years and
40354359Sroberto	 * relies on the clock-calendar chip for sanity.
40454359Sroberto	 */
40554359Sroberto	if (!refclock_process(pp)) {
40654359Sroberto		refclock_report(peer, CEVNT_BADTIME);
40754359Sroberto		return;
40854359Sroberto	}
409132451Sroberto	pp->lastref = pp->lastrec;
410132451Sroberto	refclock_receive(peer);
41154359Sroberto	record_clock_stats(&peer->srcadr, pp->a_lastcode);
41254359Sroberto}
41354359Sroberto
41454359Srobertostruct vmedate *
41554359Srobertoget_datumtime(struct vmedate *time_vme)
41654359Sroberto{
41754359Sroberto	char cbuf[7];
41854359Sroberto	struct btfp_time vts;
419182007Sroberto	uint32_t btm[2];
420182007Sroberto	uint8_t dmy;
421290001Sglebius	struct stfp_time stfpm;
42254359Sroberto
423290001Sglebius	if (time_vme == NULL)
424290001Sglebius  		time_vme = emalloc(sizeof(*time_vme));
42554359Sroberto
426182007Sroberto	switch (tfp_type) {
427182007Sroberto		case 1:				/* BSD, PCI, 2 32bit time words */
428182007Sroberto			if (ioctl(fd_vme, READTIME, &btm)) {
429182007Sroberto	    		msyslog(LOG_ERR, "get_bc63x error: %m");
430182007Sroberto				return(NULL);
431182007Sroberto			}
432182007Sroberto			tvme_fill(time_vme, btm);
433182007Sroberto			break;
43454359Sroberto
435182007Sroberto		case 2:				/* Linux/Windows, PCI, 2 32bit time words */
436182007Sroberto			if (bcReadBinTime(stfp_handle, &btm[1], &btm[0], &dmy) == 0) {
437182007Sroberto	    		msyslog(LOG_ERR, "get_datumtime error: %m");
438182007Sroberto				return(NULL);
439182007Sroberto			}
440182007Sroberto			tvme_fill(time_vme, btm);
441182007Sroberto			break;
442290001Sglebius
443290001Sglebius		case 3: /** solaris **/
444290001Sglebius			memset(&stfpm,0,sizeof(stfpm));
445290001Sglebius
446290001Sglebius			/* we need the time in decimal format */
447290001Sglebius			/* Here we rudely assume that we are the only user of the driver.
448290001Sglebius			 * Other programs will have to set their own time format before reading
449290001Sglebius			 * the time.
450290001Sglebius			 */
451290001Sglebius			if(ioctl (fd_vme, SELTIMEFORMAT, TIME_DECIMAL)){
452290001Sglebius					msyslog(LOG_ERR, "Could not set time format");
453290001Sglebius					return (NULL);
454290001Sglebius			}
455290001Sglebius			/* read the time */
456290001Sglebius			if (ioctl(fd_vme, READTIME, &stfpm)) {
457290001Sglebius				msyslog(LOG_ERR, "ioctl error: %m");
458290001Sglebius				return(NULL);
459290001Sglebius			}
460290001Sglebius			stfp_time2tvme(time_vme,  &stfpm);
461290001Sglebius			break;
46254359Sroberto
463182007Sroberto		default:			/* legacy bancomm card */
46454359Sroberto
465182007Sroberto			if (ioctl(fd_vme, READTIME, &vts)) {
466290001Sglebius				msyslog(LOG_ERR,
467290001Sglebius					"get_datumtime error: %m");
468182007Sroberto				return(NULL);
469182007Sroberto			}
470182007Sroberto			/* Get day */
471290001Sglebius			snprintf(cbuf, sizeof(cbuf), "%3.3x",
472290001Sglebius				 ((vts.btfp_time[ 0 ] & 0x000f) << 8) +
473290001Sglebius				  ((vts.btfp_time[ 1 ] & 0xff00) >> 8));
474182007Sroberto			time_vme->day = (unsigned short)atoi(cbuf);
47554359Sroberto
476182007Sroberto			/* Get hour */
477290001Sglebius			snprintf(cbuf, sizeof(cbuf), "%2.2x",
478290001Sglebius				 vts.btfp_time[ 1 ] & 0x00ff);
479182007Sroberto			time_vme->hr = (unsigned short)atoi(cbuf);
48054359Sroberto
481182007Sroberto			/* Get minutes */
482290001Sglebius			snprintf(cbuf, sizeof(cbuf), "%2.2x",
483290001Sglebius				 (vts.btfp_time[ 2 ] & 0xff00) >> 8);
484182007Sroberto			time_vme->mn = (unsigned short)atoi(cbuf);
48554359Sroberto
486182007Sroberto			/* Get seconds */
487290001Sglebius			snprintf(cbuf, sizeof(cbuf), "%2.2x",
488290001Sglebius				 vts.btfp_time[ 2 ] & 0x00ff);
489182007Sroberto			time_vme->sec = (unsigned short)atoi(cbuf);
49054359Sroberto
491182007Sroberto			/* Get microseconds.  Yes, we ignore the 0.1 microsecond digit so
492182007Sroberto				 we can use the TVTOTSF function  later on...*/
49354359Sroberto
494290001Sglebius			snprintf(cbuf, sizeof(cbuf), "%4.4x%2.2x",
495290001Sglebius				 vts.btfp_time[ 3 ],
496290001Sglebius				 vts.btfp_time[ 4 ] >> 8);
497182007Sroberto			time_vme->frac = (u_long) atoi(cbuf);
49854359Sroberto
499182007Sroberto			/* Get status bit */
500290001Sglebius			time_vme->status = (vts.btfp_time[0] & 0x0010) >> 4;
50154359Sroberto
502182007Sroberto			break;
503182007Sroberto	}
50454359Sroberto
505182007Sroberto	if (time_vme->status)
50654359Sroberto		return ((void *)NULL);
50754359Sroberto	else
50854359Sroberto	    return (time_vme);
50954359Sroberto}
510182007Sroberto/* Assign values to time_vme struct. Mostly for readability */
511182007Srobertovoid
512182007Srobertotvme_fill(struct vmedate *time_vme, uint32_t btm[2])
513182007Sroberto{
514182007Sroberto	struct tm maj;
515182007Sroberto	uint32_t dmaj, dmin;
51654359Sroberto
517182007Sroberto	dmaj = btm[1];			/* syntax sugar */
518182007Sroberto	dmin = btm[0];
519182007Sroberto
520182007Sroberto	gmtime_r(&dmaj, &maj);
521182007Sroberto	time_vme->day  = maj.tm_yday+1;
522182007Sroberto	time_vme->hr   = maj.tm_hour;
523182007Sroberto	time_vme->mn   = maj.tm_min;
524182007Sroberto	time_vme->sec  = maj.tm_sec;
525182007Sroberto	time_vme->frac = (dmin & 0x000fffff) * 1000;
526182007Sroberto	time_vme->frac += ((dmin & 0x00f00000) >> 20) * 100;
527182007Sroberto	time_vme->status = (dmin & 0x01000000) >> 24;
528182007Sroberto	return;
529182007Sroberto}
530182007Sroberto
531290001Sglebius
532290001Sglebius/* Assign values to time_vme struct. Mostly for readability */
533290001Sglebiusvoid
534290001Sglebiusstfp_time2tvme(struct vmedate *time_vme, struct stfp_time *stfp)
535290001Sglebius{
536290001Sglebius
537290001Sglebius	time_vme->day  = stfp->tm.tm_yday+1;
538290001Sglebius	time_vme->hr   = stfp->tm.tm_hour;
539290001Sglebius	time_vme->mn   = stfp->tm.tm_min;
540290001Sglebius	time_vme->sec  = stfp->tm.tm_sec;
541290001Sglebius	time_vme->frac = stfp->usec*1000;
542290001Sglebius	time_vme->frac += stfp->hnsec * 100;
543290001Sglebius	time_vme->status = stfp->status;
544290001Sglebius	return;
545290001Sglebius}
54654359Sroberto#else
54754359Srobertoint refclock_bancomm_bs;
54854359Sroberto#endif /* REFCLOCK */
549