File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / include / timepps-Solaris.h
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 5 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /***********************************************************************
    2:  *								       *
    3:  * Copyright (c) David L. Mills 1999-2009			       *
    4:  *								       *
    5:  * Permission to use, copy, modify, and distribute this software and   *
    6:  * its documentation for any purpose and without fee is hereby	       *
    7:  * granted, provided that the above copyright notice appears in all    *
    8:  * copies and that both the copyright notice and this permission       *
    9:  * notice appear in supporting documentation, and that the name        *
   10:  * University of Delaware not be used in advertising or publicity      *
   11:  * pertaining to distribution of the software without specific,        *
   12:  * written prior permission. The University of Delaware makes no       *
   13:  * representations about the suitability this software for any	       *
   14:  * purpose. It is provided "as is" without express or implied          *
   15:  * warranty.							       *
   16:  *								       *
   17:  ***********************************************************************
   18:  *								       *
   19:  * This header file complies with "Pulse-Per-Second API for UNIX-like  *
   20:  * Operating Systems, Version 1.0", rfc2783. Credit is due Jeff Mogul  *
   21:  * and Marc Brett, from whom much of this code was shamelessly stolen. *
   22:  *								       *
   23:  * this modified timepps.h can be used to provide a PPSAPI interface   *
   24:  * to a machine running Solaris (2.6 and above).		       *
   25:  *								       *
   26:  ***********************************************************************
   27:  *								       *
   28:  * A full PPSAPI interface to the Solaris kernel would be better, but  *
   29:  * this at least removes the necessity for special coding from the NTP *
   30:  * NTP drivers. 						       *
   31:  *								       *
   32:  ***********************************************************************
   33:  *								       *
   34:  * Some of this include file					       *
   35:  * Copyright (c) 1999 by Ulrich Windl,				       *
   36:  *	based on code by Reg Clemens <reg@dwf.com>		       *
   37:  *		based on code by Poul-Henning Kamp <phk@FreeBSD.org>   *
   38:  *								       *
   39:  ***********************************************************************
   40:  *								       *
   41:  * "THE BEER-WARE LICENSE" (Revision 42):                              *
   42:  * <phk@FreeBSD.org> wrote this file.  As long as you retain this      *
   43:  * notice you can do whatever you want with this stuff. If we meet some*
   44:  * day, and you think this stuff is worth it, you can buy me a beer    *
   45:  * in return.	Poul-Henning Kamp				       *
   46:  *								       *
   47:  **********************************************************************/
   48: 
   49: /* Solaris version, TIOCGPPSEV and TIOCSPPS assumed to exist. */
   50: 
   51: #ifndef _SYS_TIMEPPS_H_
   52: #define _SYS_TIMEPPS_H_
   53: 
   54: #include <termios.h>	/* to get TOCGPPSEV and TIOCSPPS */
   55: 
   56: /* Implementation note: the logical states ``assert'' and ``clear''
   57:  * are implemented in terms of the UART register, i.e. ``assert''
   58:  * means the bit is set.
   59:  */
   60: 
   61: /*
   62:  * The following definitions are architecture independent
   63:  */
   64: 
   65: #define PPS_API_VERS_1	1		/* API version number */
   66: #define PPS_JAN_1970	2208988800UL	/* 1970 - 1900 in seconds */
   67: #define PPS_NANOSECOND	1000000000L	/* one nanosecond in decimal */
   68: #define PPS_FRAC	4294967296.	/* 2^32 as a double */
   69: 
   70: #define PPS_NORMALIZE(x)	/* normalize timespec */ \
   71: 	do { \
   72: 		if ((x).tv_nsec >= PPS_NANOSECOND) { \
   73: 			(x).tv_nsec -= PPS_NANOSECOND; \
   74: 			(x).tv_sec++; \
   75: 		} else if ((x).tv_nsec < 0) { \
   76: 			(x).tv_nsec += PPS_NANOSECOND; \
   77: 			(x).tv_sec--; \
   78: 		} \
   79: 	} while (0)
   80: 
   81: #define PPS_TSPECTONTP(x)	/* convert timespec to l_fp */ \
   82: 	do { \
   83: 		double d_temp; \
   84: 	\
   85: 		(x).integral += (unsigned int)PPS_JAN_1970; \
   86: 		d_temp = (x).fractional * PPS_FRAC / PPS_NANOSECOND; \
   87: 		if (d_temp >= PPS_FRAC) \
   88: 			(x).integral++; \
   89: 		(x).fractional = (unsigned int)d_temp; \
   90: 	} while (0)
   91: 
   92: /*
   93:  * Device/implementation parameters (mode)
   94:  */
   95: 
   96: #define PPS_CAPTUREASSERT	0x01	/* capture assert events */
   97: #define PPS_CAPTURECLEAR	0x02	/* capture clear events */
   98: #define PPS_CAPTUREBOTH 	0x03	/* capture assert and clear events */
   99: 
  100: #define PPS_OFFSETASSERT	0x10	/* apply compensation for assert ev. */
  101: #define PPS_OFFSETCLEAR 	0x20	/* apply compensation for clear ev. */
  102: #define PPS_OFFSETBOTH		0x30	/* apply compensation for both */
  103: 
  104: #define PPS_CANWAIT		0x100	/* Can we wait for an event? */
  105: #define PPS_CANPOLL		0x200	/* "This bit is reserved for */
  106: 
  107: /*
  108:  * Kernel actions (mode)
  109:  */
  110: 
  111: #define PPS_ECHOASSERT		0x40	/* feed back assert event to output */
  112: #define PPS_ECHOCLEAR		0x80	/* feed back clear event to output */
  113: 
  114: /*
  115:  * Timestamp formats (tsformat)
  116:  */
  117: 
  118: #define PPS_TSFMT_TSPEC 	0x1000	/* select timespec format */
  119: #define PPS_TSFMT_NTPFP 	0x2000	/* select NTP format */
  120: 
  121: /*
  122:  * Kernel discipline actions (not used in Solaris)
  123:  */
  124: 
  125: #define PPS_KC_HARDPPS		0	/* enable kernel consumer */
  126: #define PPS_KC_HARDPPS_PLL	1	/* phase-lock mode */
  127: #define PPS_KC_HARDPPS_FLL	2	/* frequency-lock mode */
  128: 
  129: /*
  130:  * Type definitions
  131:  */
  132: 
  133: typedef unsigned long pps_seq_t;	/* sequence number */
  134: 
  135: typedef struct ntp_fp {
  136: 	unsigned int	integral;
  137: 	unsigned int	fractional;
  138: } ntp_fp_t;				/* NTP-compatible time stamp */
  139: 
  140: typedef union pps_timeu {		/* timestamp format */
  141: 	struct timespec tspec;
  142: 	ntp_fp_t	ntpfp;
  143: 	unsigned long	longpad[3];
  144: } pps_timeu_t;				/* generic data type to represent time stamps */
  145: 
  146: /*
  147:  * Timestamp information structure
  148:  */
  149: 
  150: typedef struct pps_info {
  151: 	pps_seq_t	assert_sequence;	/* seq. num. of assert event */
  152: 	pps_seq_t	clear_sequence; 	/* seq. num. of clear event */
  153: 	pps_timeu_t	assert_tu;		/* time of assert event */
  154: 	pps_timeu_t	clear_tu;		/* time of clear event */
  155: 	int		current_mode;		/* current mode bits */
  156: } pps_info_t;
  157: 
  158: #define assert_timestamp	assert_tu.tspec
  159: #define clear_timestamp 	clear_tu.tspec
  160: 
  161: #define assert_timestamp_ntpfp	assert_tu.ntpfp
  162: #define clear_timestamp_ntpfp	clear_tu.ntpfp
  163: 
  164: /*
  165:  * Parameter structure
  166:  */
  167: 
  168: typedef struct pps_params {
  169: 	int		api_version;	/* API version # */
  170: 	int		mode;		/* mode bits */
  171: 	pps_timeu_t assert_off_tu;	/* offset compensation for assert */
  172: 	pps_timeu_t clear_off_tu;	/* offset compensation for clear */
  173: } pps_params_t;
  174: 
  175: #define assert_offset		assert_off_tu.tspec
  176: #define clear_offset		clear_off_tu.tspec
  177: 
  178: #define assert_offset_ntpfp	assert_off_tu.ntpfp
  179: #define clear_offset_ntpfp	clear_off_tu.ntpfp
  180: 
  181: /* addition of NTP fixed-point format */
  182: 
  183: #define NTPFP_M_ADD(r_i, r_f, a_i, a_f) 	/* r += a */ \
  184: 	do { \
  185: 		register u_int32 lo_tmp; \
  186: 		register u_int32 hi_tmp; \
  187: 		\
  188: 		lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \
  189: 		hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & 0xffff); \
  190: 		if (lo_tmp & 0x10000) \
  191: 			hi_tmp++; \
  192: 		(r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \
  193: 		\
  194: 		(r_i) += (a_i); \
  195: 		if (hi_tmp & 0x10000) \
  196: 			(r_i)++; \
  197: 	} while (0)
  198: 
  199: #define	NTPFP_L_ADDS(r, a)	NTPFP_M_ADD((r)->integral, (r)->fractional, \
  200: 					    (int)(a)->integral, (a)->fractional)
  201: 
  202: /*
  203:  * The following definitions are architecture-dependent
  204:  */
  205: 
  206: #define PPS_CAP (PPS_CAPTUREASSERT | PPS_OFFSETASSERT | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
  207: #define PPS_RO	(PPS_CANWAIT | PPS_CANPOLL)
  208: 
  209: typedef struct {
  210: 	int filedes;		/* file descriptor */
  211: 	pps_params_t params;	/* PPS parameters set by user */
  212: } pps_unit_t;
  213: 
  214: /*
  215:  *------ Here begins the implementation-specific part! ------
  216:  */
  217: 
  218: #include <errno.h>
  219: 
  220: /*
  221:  * pps handlebars, which are required to be an opaque scalar.  This
  222:  * implementation uses the handle as a pointer so it must be large
  223:  * enough.  uintptr_t is as large as a pointer.
  224:  */
  225: typedef uintptr_t pps_handle_t; 
  226: 
  227: /*
  228:  * create PPS handle from file descriptor
  229:  */
  230: 
  231: static inline int
  232: time_pps_create(
  233: 	int filedes,		/* file descriptor */
  234: 	pps_handle_t *handle	/* returned handle */
  235: 	)
  236: {
  237: 	pps_unit_t *punit;
  238: 	int one = 1;
  239: 
  240: 	/*
  241: 	 * Check for valid arguments and attach PPS signal.
  242: 	 */
  243: 
  244: 	if (!handle) {
  245: 		errno = EFAULT;
  246: 		return (-1);	/* null pointer */
  247: 	}
  248: 
  249: 	if (ioctl(filedes, TIOCSPPS, &one) < 0) {
  250: 		perror("refclock_ioctl: TIOCSPPS failed:");
  251: 		return (-1);
  252: 	}
  253: 
  254: 	/*
  255: 	 * Allocate and initialize default unit structure.
  256: 	 */
  257: 
  258: 	punit = malloc(sizeof(*punit));
  259: 	if (NULL == punit) {
  260: 		errno = ENOMEM;
  261: 		return (-1);	/* what, no memory? */
  262: 	}
  263: 
  264: 	memset(punit, 0, sizeof(*punit));
  265: 	punit->filedes = filedes;
  266: 	punit->params.api_version = PPS_API_VERS_1;
  267: 	punit->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC;
  268: 
  269: 	*handle = (pps_handle_t)punit;
  270: 	return (0);
  271: }
  272: 
  273: /*
  274:  * release PPS handle
  275:  */
  276: 
  277: static inline int
  278: time_pps_destroy(
  279: 	pps_handle_t handle
  280: 	)
  281: {
  282: 	pps_unit_t *punit;
  283: 
  284: 	/*
  285: 	 * Check for valid arguments and detach PPS signal.
  286: 	 */
  287: 
  288: 	if (!handle) {
  289: 		errno = EBADF;
  290: 		return (-1);	/* bad handle */
  291: 	}
  292: 	punit = (pps_unit_t *)handle;
  293: 	free(punit);
  294: 	return (0);
  295: }
  296: 
  297: /*
  298:  * set parameters for handle
  299:  */
  300: 
  301: static inline int
  302: time_pps_setparams(
  303: 	pps_handle_t handle,
  304: 	const pps_params_t *params
  305: 	)
  306: {
  307: 	pps_unit_t *	punit;
  308: 	int		mode, mode_in;
  309: 	/*
  310: 	 * Check for valid arguments and set parameters.
  311: 	 */
  312: 
  313: 	if (!handle) {
  314: 		errno = EBADF;
  315: 		return (-1);	/* bad handle */
  316: 	}
  317: 
  318: 	if (!params) {
  319: 		errno = EFAULT;
  320: 		return (-1);	/* bad argument */
  321: 	}
  322: 
  323: 	/*
  324: 	 * There was no reasonable consensu in the API working group.
  325: 	 * I require `api_version' to be set!
  326: 	 */
  327: 
  328: 	if (params->api_version != PPS_API_VERS_1) {
  329: 		errno = EINVAL;
  330: 		return(-1);
  331: 	}
  332: 
  333: 	/*
  334: 	 * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT
  335: 	 */
  336: 
  337: 	mode_in = params->mode;
  338: 	punit = (pps_unit_t *)handle;
  339: 
  340: 	/*
  341: 	 * Only one of the time formats may be selected
  342: 	 * if a nonzero assert offset is supplied.
  343: 	 */
  344: 	if ((mode_in & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) ==
  345: 	    (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) {
  346: 
  347: 		if (punit->params.assert_offset.tv_sec ||
  348: 			punit->params.assert_offset.tv_nsec) {
  349: 
  350: 			errno = EINVAL;
  351: 			return(-1);
  352: 		}
  353: 
  354: 		/*
  355: 		 * If no offset was specified but both time
  356: 		 * format flags are used consider it harmless
  357: 		 * but turn off PPS_TSFMT_NTPFP so getparams
  358: 		 * will not show both formats lit.
  359: 		 */
  360: 		mode_in &= ~PPS_TSFMT_NTPFP;
  361: 	}
  362: 
  363: 	/* turn off read-only bits */
  364: 
  365: 	mode_in &= ~PPS_RO;
  366: 
  367: 	/*
  368: 	 * test remaining bits, should only have captureassert, 
  369: 	 * offsetassert, and/or timestamp format bits.
  370: 	 */
  371: 
  372: 	if (mode_in & ~(PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
  373: 			PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) {
  374: 		errno = EOPNOTSUPP;
  375: 		return(-1);
  376: 	}
  377: 
  378: 	/*
  379: 	 * ok, ready to go.
  380: 	 */
  381: 
  382: 	mode = punit->params.mode;
  383: 	memcpy(&punit->params, params, sizeof(punit->params));
  384: 	punit->params.api_version = PPS_API_VERS_1;
  385: 	punit->params.mode = mode | mode_in;
  386: 	return (0);
  387: }
  388: 
  389: /*
  390:  * get parameters for handle
  391:  */
  392: 
  393: static inline int
  394: time_pps_getparams(
  395: 	pps_handle_t handle,
  396: 	pps_params_t *params
  397: 	)
  398: {
  399: 	pps_unit_t *	punit;
  400: 
  401: 	/*
  402: 	 * Check for valid arguments and get parameters.
  403: 	 */
  404: 
  405: 	if (!handle) {
  406: 		errno = EBADF;
  407: 		return (-1);	/* bad handle */
  408: 	}
  409: 
  410: 	if (!params) {
  411: 		errno = EFAULT;
  412: 		return (-1);	/* bad argument */
  413: 	}
  414: 
  415: 	punit = (pps_unit_t *)handle;
  416: 	memcpy(params, &punit->params, sizeof(params));
  417: 	return (0);
  418: }
  419: 
  420: /*
  421:  * get capabilities for handle
  422:  */
  423: 
  424: static inline int
  425: time_pps_getcap(
  426: 	pps_handle_t handle,
  427: 	int *mode
  428: 	)
  429: {
  430: 	/*
  431: 	 * Check for valid arguments and get capabilities.
  432: 	 */
  433: 
  434: 	if (!handle) {
  435: 		errno = EBADF;
  436: 		return (-1);	/* bad handle */
  437: 	}
  438: 
  439: 	if (!mode) {
  440: 		errno = EFAULT;
  441: 		return (-1);	/* bad argument */
  442: 	}
  443: 	*mode = PPS_CAP;
  444: 	return (0);
  445: }
  446: 
  447: /*
  448:  * Fetch timestamps
  449:  */
  450: 
  451: static inline int
  452: time_pps_fetch(
  453: 	pps_handle_t handle,
  454: 	const int tsformat,
  455: 	pps_info_t *ppsinfo,
  456: 	const struct timespec *timeout
  457: 	)
  458: {
  459: 	struct ppsclockev {
  460: 		struct timeval tv;
  461: 		u_int serial;
  462: 	} ev;
  463: 
  464: 	pps_info_t	infobuf;
  465: 	pps_unit_t *	punit;
  466: 
  467: 	/*
  468: 	 * Check for valid arguments and fetch timestamps
  469: 	 */
  470: 
  471: 	if (!handle) {
  472: 		errno = EBADF;
  473: 		return (-1);	/* bad handle */
  474: 	}
  475: 
  476: 	if (!ppsinfo) {
  477: 		errno = EFAULT;
  478: 		return (-1);	/* bad argument */
  479: 	}
  480: 
  481: 	/*
  482: 	 * nb. PPS_CANWAIT is NOT set by the implementation, we can totally
  483: 	 * ignore the timeout variable.
  484: 	 */
  485: 
  486: 	memset(&infobuf, 0, sizeof(infobuf));
  487: 	punit = (pps_unit_t *)handle;
  488: 
  489: 	/*
  490: 	 * if not captureassert, nothing to return.
  491: 	 */
  492: 
  493: 	if (!punit->params.mode & PPS_CAPTUREASSERT) {
  494: 		memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
  495: 		return (0);
  496: 	}
  497: 
  498: 	if (ioctl(punit->filedes, TIOCGPPSEV, (caddr_t) &ev) < 0) {
  499: 		perror("time_pps_fetch:");
  500: 		errno = EOPNOTSUPP;
  501: 		return(-1);
  502: 	}
  503: 
  504: 	infobuf.assert_sequence = ev.serial;
  505: 	infobuf.assert_timestamp.tv_sec = ev.tv.tv_sec;
  506: 	infobuf.assert_timestamp.tv_nsec = ev.tv.tv_usec * 1000;
  507: 
  508: 	/*
  509: 	 * Translate to specified format then apply offset
  510: 	 */
  511: 
  512: 	switch (tsformat) {
  513: 	case PPS_TSFMT_TSPEC:
  514: 		/* timespec format requires no conversion */
  515: 		if (punit->params.mode & PPS_OFFSETASSERT) {
  516: 			infobuf.assert_timestamp.tv_sec  += 
  517: 				punit->params.assert_offset.tv_sec;
  518: 			infobuf.assert_timestamp.tv_nsec += 
  519: 				punit->params.assert_offset.tv_nsec;
  520: 			PPS_NORMALIZE(infobuf.assert_timestamp);
  521: 		}
  522: 		break;
  523: 
  524: 	case PPS_TSFMT_NTPFP:
  525: 		/* NTP format requires conversion to fraction form */
  526: 		PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp);
  527: 		if (punit->params.mode & PPS_OFFSETASSERT)
  528: 			NTPFP_L_ADDS(&infobuf.assert_timestamp_ntpfp, 
  529: 				     &punit->params.assert_offset_ntpfp);
  530: 		break;		
  531: 
  532: 	default:
  533: 		errno = EINVAL;
  534: 		return (-1);
  535: 	}
  536: 
  537: 	infobuf.current_mode = punit->params.mode;
  538: 	memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
  539: 	return (0);
  540: }
  541: 
  542: /*
  543:  * specify kernel consumer
  544:  */
  545: 
  546: static inline int
  547: time_pps_kcbind(
  548: 	pps_handle_t handle,
  549: 	const int kernel_consumer,
  550: 	const int edge,
  551: 	const int tsformat
  552: 	)
  553: {
  554: 	/*
  555: 	 * Check for valid arguments and bind kernel consumer
  556: 	 */
  557: 	if (!handle) {
  558: 		errno = EBADF;
  559: 		return (-1);	/* bad handle */
  560: 	}
  561: 	if (geteuid() != 0) {
  562: 		errno = EPERM;
  563: 		return (-1);	/* must be superuser */
  564: 	}
  565: 	errno = EOPNOTSUPP;
  566: 	return(-1);
  567: }
  568: 
  569: #endif /* _SYS_TIMEPPS_H_ */

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