summaryrefslogtreecommitdiff
path: root/include/timepps-Solaris.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/timepps-Solaris.h')
-rw-r--r--include/timepps-Solaris.h569
1 files changed, 569 insertions, 0 deletions
diff --git a/include/timepps-Solaris.h b/include/timepps-Solaris.h
new file mode 100644
index 0000000..a2b1fbe
--- /dev/null
+++ b/include/timepps-Solaris.h
@@ -0,0 +1,569 @@
+/***********************************************************************
+ * *
+ * Copyright (c) David L. Mills 1999-2009 *
+ * *
+ * Permission to use, copy, modify, and distribute this software and *
+ * its documentation for any purpose and with or without fee is hereby *
+ * granted, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission *
+ * notice appear in supporting documentation, and that the name *
+ * University of Delaware not be used in advertising or publicity *
+ * pertaining to distribution of the software without specific, *
+ * written prior permission. The University of Delaware makes no *
+ * representations about the suitability this software for any *
+ * purpose. It is provided "as is" without express or implied *
+ * warranty. *
+ * *
+ ***********************************************************************
+ * *
+ * This header file complies with "Pulse-Per-Second API for UNIX-like *
+ * Operating Systems, Version 1.0", rfc2783. Credit is due Jeff Mogul *
+ * and Marc Brett, from whom much of this code was shamelessly stolen. *
+ * *
+ * this modified timepps.h can be used to provide a PPSAPI interface *
+ * to a machine running Solaris (2.6 and above). *
+ * *
+ ***********************************************************************
+ * *
+ * A full PPSAPI interface to the Solaris kernel would be better, but *
+ * this at least removes the necessity for special coding from the NTP *
+ * NTP drivers. *
+ * *
+ ***********************************************************************
+ * *
+ * Some of this include file *
+ * Copyright (c) 1999 by Ulrich Windl, *
+ * based on code by Reg Clemens <reg@dwf.com> *
+ * based on code by Poul-Henning Kamp <phk@FreeBSD.org> *
+ * *
+ ***********************************************************************
+ * *
+ * "THE BEER-WARE LICENSE" (Revision 42): *
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this *
+ * notice you can do whatever you want with this stuff. If we meet some*
+ * day, and you think this stuff is worth it, you can buy me a beer *
+ * in return. Poul-Henning Kamp *
+ * *
+ **********************************************************************/
+
+/* Solaris version, TIOCGPPSEV and TIOCSPPS assumed to exist. */
+
+#ifndef _SYS_TIMEPPS_H_
+#define _SYS_TIMEPPS_H_
+
+#include <termios.h> /* to get TOCGPPSEV and TIOCSPPS */
+
+/* Implementation note: the logical states ``assert'' and ``clear''
+ * are implemented in terms of the UART register, i.e. ``assert''
+ * means the bit is set.
+ */
+
+/*
+ * The following definitions are architecture independent
+ */
+
+#define PPS_API_VERS_1 1 /* API version number */
+#define PPS_JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
+#define PPS_NANOSECOND 1000000000L /* one nanosecond in decimal */
+#define PPS_FRAC 4294967296. /* 2^32 as a double */
+
+#define PPS_NORMALIZE(x) /* normalize timespec */ \
+ do { \
+ if ((x).tv_nsec >= PPS_NANOSECOND) { \
+ (x).tv_nsec -= PPS_NANOSECOND; \
+ (x).tv_sec++; \
+ } else if ((x).tv_nsec < 0) { \
+ (x).tv_nsec += PPS_NANOSECOND; \
+ (x).tv_sec--; \
+ } \
+ } while (0)
+
+#define PPS_TSPECTONTP(x) /* convert timespec to l_fp */ \
+ do { \
+ double d_temp; \
+ \
+ (x).integral += (unsigned int)PPS_JAN_1970; \
+ d_temp = (x).fractional * PPS_FRAC / PPS_NANOSECOND; \
+ if (d_temp >= PPS_FRAC) \
+ (x).integral++; \
+ (x).fractional = (unsigned int)d_temp; \
+ } while (0)
+
+/*
+ * Device/implementation parameters (mode)
+ */
+
+#define PPS_CAPTUREASSERT 0x01 /* capture assert events */
+#define PPS_CAPTURECLEAR 0x02 /* capture clear events */
+#define PPS_CAPTUREBOTH 0x03 /* capture assert and clear events */
+
+#define PPS_OFFSETASSERT 0x10 /* apply compensation for assert ev. */
+#define PPS_OFFSETCLEAR 0x20 /* apply compensation for clear ev. */
+#define PPS_OFFSETBOTH 0x30 /* apply compensation for both */
+
+#define PPS_CANWAIT 0x100 /* Can we wait for an event? */
+#define PPS_CANPOLL 0x200 /* "This bit is reserved for */
+
+/*
+ * Kernel actions (mode)
+ */
+
+#define PPS_ECHOASSERT 0x40 /* feed back assert event to output */
+#define PPS_ECHOCLEAR 0x80 /* feed back clear event to output */
+
+/*
+ * Timestamp formats (tsformat)
+ */
+
+#define PPS_TSFMT_TSPEC 0x1000 /* select timespec format */
+#define PPS_TSFMT_NTPFP 0x2000 /* select NTP format */
+
+/*
+ * Kernel discipline actions (not used in Solaris)
+ */
+
+#define PPS_KC_HARDPPS 0 /* enable kernel consumer */
+#define PPS_KC_HARDPPS_PLL 1 /* phase-lock mode */
+#define PPS_KC_HARDPPS_FLL 2 /* frequency-lock mode */
+
+/*
+ * Type definitions
+ */
+
+typedef unsigned long pps_seq_t; /* sequence number */
+
+typedef struct ntp_fp {
+ unsigned int integral;
+ unsigned int fractional;
+} ntp_fp_t; /* NTP-compatible time stamp */
+
+typedef union pps_timeu { /* timestamp format */
+ struct timespec tspec;
+ ntp_fp_t ntpfp;
+ unsigned long longpad[3];
+} pps_timeu_t; /* generic data type to represent time stamps */
+
+/*
+ * Timestamp information structure
+ */
+
+typedef struct pps_info {
+ pps_seq_t assert_sequence; /* seq. num. of assert event */
+ pps_seq_t clear_sequence; /* seq. num. of clear event */
+ pps_timeu_t assert_tu; /* time of assert event */
+ pps_timeu_t clear_tu; /* time of clear event */
+ int current_mode; /* current mode bits */
+} pps_info_t;
+
+#define assert_timestamp assert_tu.tspec
+#define clear_timestamp clear_tu.tspec
+
+#define assert_timestamp_ntpfp assert_tu.ntpfp
+#define clear_timestamp_ntpfp clear_tu.ntpfp
+
+/*
+ * Parameter structure
+ */
+
+typedef struct pps_params {
+ int api_version; /* API version # */
+ int mode; /* mode bits */
+ pps_timeu_t assert_off_tu; /* offset compensation for assert */
+ pps_timeu_t clear_off_tu; /* offset compensation for clear */
+} pps_params_t;
+
+#define assert_offset assert_off_tu.tspec
+#define clear_offset clear_off_tu.tspec
+
+#define assert_offset_ntpfp assert_off_tu.ntpfp
+#define clear_offset_ntpfp clear_off_tu.ntpfp
+
+/* addition of NTP fixed-point format */
+
+#define NTPFP_M_ADD(r_i, r_f, a_i, a_f) /* r += a */ \
+ do { \
+ register u_int32 lo_tmp; \
+ register u_int32 hi_tmp; \
+ \
+ lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \
+ hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & 0xffff); \
+ if (lo_tmp & 0x10000) \
+ hi_tmp++; \
+ (r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \
+ \
+ (r_i) += (a_i); \
+ if (hi_tmp & 0x10000) \
+ (r_i)++; \
+ } while (0)
+
+#define NTPFP_L_ADDS(r, a) NTPFP_M_ADD((r)->integral, (r)->fractional, \
+ (int)(a)->integral, (a)->fractional)
+
+/*
+ * The following definitions are architecture-dependent
+ */
+
+#define PPS_CAP (PPS_CAPTUREASSERT | PPS_OFFSETASSERT | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
+#define PPS_RO (PPS_CANWAIT | PPS_CANPOLL)
+
+typedef struct {
+ int filedes; /* file descriptor */
+ pps_params_t params; /* PPS parameters set by user */
+} pps_unit_t;
+
+/*
+ *------ Here begins the implementation-specific part! ------
+ */
+
+#include <errno.h>
+
+/*
+ * pps handlebars, which are required to be an opaque scalar. This
+ * implementation uses the handle as a pointer so it must be large
+ * enough. uintptr_t is as large as a pointer.
+ */
+typedef uintptr_t pps_handle_t;
+
+/*
+ * create PPS handle from file descriptor
+ */
+
+static inline int
+time_pps_create(
+ int filedes, /* file descriptor */
+ pps_handle_t *handle /* returned handle */
+ )
+{
+ pps_unit_t *punit;
+ int one = 1;
+
+ /*
+ * Check for valid arguments and attach PPS signal.
+ */
+
+ if (!handle) {
+ errno = EFAULT;
+ return (-1); /* null pointer */
+ }
+
+ if (ioctl(filedes, TIOCSPPS, &one) < 0) {
+ perror("refclock_ioctl: TIOCSPPS failed:");
+ return (-1);
+ }
+
+ /*
+ * Allocate and initialize default unit structure.
+ */
+
+ punit = malloc(sizeof(*punit));
+ if (NULL == punit) {
+ errno = ENOMEM;
+ return (-1); /* what, no memory? */
+ }
+
+ memset(punit, 0, sizeof(*punit));
+ punit->filedes = filedes;
+ punit->params.api_version = PPS_API_VERS_1;
+ punit->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC;
+
+ *handle = (pps_handle_t)punit;
+ return (0);
+}
+
+/*
+ * release PPS handle
+ */
+
+static inline int
+time_pps_destroy(
+ pps_handle_t handle
+ )
+{
+ pps_unit_t *punit;
+
+ /*
+ * Check for valid arguments and detach PPS signal.
+ */
+
+ if (!handle) {
+ errno = EBADF;
+ return (-1); /* bad handle */
+ }
+ punit = (pps_unit_t *)handle;
+ free(punit);
+ return (0);
+}
+
+/*
+ * set parameters for handle
+ */
+
+static inline int
+time_pps_setparams(
+ pps_handle_t handle,
+ const pps_params_t *params
+ )
+{
+ pps_unit_t * punit;
+ int mode, mode_in;
+ /*
+ * Check for valid arguments and set parameters.
+ */
+
+ if (!handle) {
+ errno = EBADF;
+ return (-1); /* bad handle */
+ }
+
+ if (!params) {
+ errno = EFAULT;
+ return (-1); /* bad argument */
+ }
+
+ /*
+ * There was no reasonable consensu in the API working group.
+ * I require `api_version' to be set!
+ */
+
+ if (params->api_version != PPS_API_VERS_1) {
+ errno = EINVAL;
+ return(-1);
+ }
+
+ /*
+ * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT
+ */
+
+ mode_in = params->mode;
+ punit = (pps_unit_t *)handle;
+
+ /*
+ * Only one of the time formats may be selected
+ * if a nonzero assert offset is supplied.
+ */
+ if ((mode_in & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) ==
+ (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) {
+
+ if (punit->params.assert_offset.tv_sec ||
+ punit->params.assert_offset.tv_nsec) {
+
+ errno = EINVAL;
+ return(-1);
+ }
+
+ /*
+ * If no offset was specified but both time
+ * format flags are used consider it harmless
+ * but turn off PPS_TSFMT_NTPFP so getparams
+ * will not show both formats lit.
+ */
+ mode_in &= ~PPS_TSFMT_NTPFP;
+ }
+
+ /* turn off read-only bits */
+
+ mode_in &= ~PPS_RO;
+
+ /*
+ * test remaining bits, should only have captureassert,
+ * offsetassert, and/or timestamp format bits.
+ */
+
+ if (mode_in & ~(PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
+ PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) {
+ errno = EOPNOTSUPP;
+ return(-1);
+ }
+
+ /*
+ * ok, ready to go.
+ */
+
+ mode = punit->params.mode;
+ memcpy(&punit->params, params, sizeof(punit->params));
+ punit->params.api_version = PPS_API_VERS_1;
+ punit->params.mode = mode | mode_in;
+ return (0);
+}
+
+/*
+ * get parameters for handle
+ */
+
+static inline int
+time_pps_getparams(
+ pps_handle_t handle,
+ pps_params_t *params
+ )
+{
+ pps_unit_t * punit;
+
+ /*
+ * Check for valid arguments and get parameters.
+ */
+
+ if (!handle) {
+ errno = EBADF;
+ return (-1); /* bad handle */
+ }
+
+ if (!params) {
+ errno = EFAULT;
+ return (-1); /* bad argument */
+ }
+
+ punit = (pps_unit_t *)handle;
+ memcpy(params, &punit->params, sizeof(params));
+ return (0);
+}
+
+/*
+ * get capabilities for handle
+ */
+
+static inline int
+time_pps_getcap(
+ pps_handle_t handle,
+ int *mode
+ )
+{
+ /*
+ * Check for valid arguments and get capabilities.
+ */
+
+ if (!handle) {
+ errno = EBADF;
+ return (-1); /* bad handle */
+ }
+
+ if (!mode) {
+ errno = EFAULT;
+ return (-1); /* bad argument */
+ }
+ *mode = PPS_CAP;
+ return (0);
+}
+
+/*
+ * Fetch timestamps
+ */
+
+static inline int
+time_pps_fetch(
+ pps_handle_t handle,
+ const int tsformat,
+ pps_info_t *ppsinfo,
+ const struct timespec *timeout
+ )
+{
+ struct ppsclockev {
+ struct timeval tv;
+ u_int serial;
+ } ev;
+
+ pps_info_t infobuf;
+ pps_unit_t * punit;
+
+ /*
+ * Check for valid arguments and fetch timestamps
+ */
+
+ if (!handle) {
+ errno = EBADF;
+ return (-1); /* bad handle */
+ }
+
+ if (!ppsinfo) {
+ errno = EFAULT;
+ return (-1); /* bad argument */
+ }
+
+ /*
+ * nb. PPS_CANWAIT is NOT set by the implementation, we can totally
+ * ignore the timeout variable.
+ */
+
+ memset(&infobuf, 0, sizeof(infobuf));
+ punit = (pps_unit_t *)handle;
+
+ /*
+ * if not captureassert, nothing to return.
+ */
+
+ if (!punit->params.mode & PPS_CAPTUREASSERT) {
+ memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
+ return (0);
+ }
+
+ if (ioctl(punit->filedes, TIOCGPPSEV, (caddr_t) &ev) < 0) {
+ perror("time_pps_fetch:");
+ errno = EOPNOTSUPP;
+ return(-1);
+ }
+
+ infobuf.assert_sequence = ev.serial;
+ infobuf.assert_timestamp.tv_sec = ev.tv.tv_sec;
+ infobuf.assert_timestamp.tv_nsec = ev.tv.tv_usec * 1000;
+
+ /*
+ * Translate to specified format then apply offset
+ */
+
+ switch (tsformat) {
+ case PPS_TSFMT_TSPEC:
+ /* timespec format requires no conversion */
+ if (punit->params.mode & PPS_OFFSETASSERT) {
+ infobuf.assert_timestamp.tv_sec +=
+ punit->params.assert_offset.tv_sec;
+ infobuf.assert_timestamp.tv_nsec +=
+ punit->params.assert_offset.tv_nsec;
+ PPS_NORMALIZE(infobuf.assert_timestamp);
+ }
+ break;
+
+ case PPS_TSFMT_NTPFP:
+ /* NTP format requires conversion to fraction form */
+ PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp);
+ if (punit->params.mode & PPS_OFFSETASSERT)
+ NTPFP_L_ADDS(&infobuf.assert_timestamp_ntpfp,
+ &punit->params.assert_offset_ntpfp);
+ break;
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ infobuf.current_mode = punit->params.mode;
+ memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
+ return (0);
+}
+
+/*
+ * specify kernel consumer
+ */
+
+static inline int
+time_pps_kcbind(
+ pps_handle_t handle,
+ const int kernel_consumer,
+ const int edge,
+ const int tsformat
+ )
+{
+ /*
+ * Check for valid arguments and bind kernel consumer
+ */
+ if (!handle) {
+ errno = EBADF;
+ return (-1); /* bad handle */
+ }
+ if (geteuid() != 0) {
+ errno = EPERM;
+ return (-1); /* must be superuser */
+ }
+ errno = EOPNOTSUPP;
+ return(-1);
+}
+
+#endif /* _SYS_TIMEPPS_H_ */