File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_bancomm.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:37 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>