summaryrefslogtreecommitdiff
path: root/ports/winnt/include/timepps.h
diff options
context:
space:
mode:
Diffstat (limited to 'ports/winnt/include/timepps.h')
-rw-r--r--ports/winnt/include/timepps.h811
1 files changed, 811 insertions, 0 deletions
diff --git a/ports/winnt/include/timepps.h b/ports/winnt/include/timepps.h
new file mode 100644
index 000000000000..76b1bfada1ab
--- /dev/null
+++ b/ports/winnt/include/timepps.h
@@ -0,0 +1,811 @@
+/***********************************************************************
+ * *
+ * 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 Windows with one or more backend provider DLLs *
+ * implementing the provider interfaces defined herein. *
+ * *
+ * This Windows version was derived by Dave Hart *
+ * <davehart@davehart.com> from Mills' timepps-Solaris.h *
+ * *
+ ***********************************************************************
+ * *
+ * 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 *
+ * *
+ **********************************************************************/
+
+#ifndef TIMEPPS_H
+#define TIMEPPS_H
+
+#include "sys/time.h" /* in ntp ref source declares struct timespec */
+
+/*
+ * 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_HECTONANOSECONDS 10000000 /* 100ns units in a second */
+#define PPS_FILETIME_1970 0x019db1ded53e8000 /* unix epoch to Windows */
+
+#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 ntp_fp */ \
+ do { \
+ double d_frac; \
+ \
+ d_frac = ((struct timespec)&(x))->tv_nsec \
+ * PPS_FRAC / PPS_NANOSECOND; \
+ (x).integral = ((struct timespec)&(x))->tv_sec \
+ + PPS_JAN_1970; \
+ (x).fractional = (unsigned int)d_frac; \
+ if (d_frac >= PPS_FRAC) \
+ (x).integral++; \
+ } while (0)
+
+#define PPS_NTPTOTSPEC(x) /* convert ntp_fp to timespec */ \
+ do { \
+ double d_frac; \
+ \
+ /* careful, doing in place and tv_sec may be 64bit */ \
+ d_frac = (double)((ntp_fp_t *)&(x))->fractional \
+ * PPS_NANOSECOND / PPS_FRAC; \
+ (x).tv_sec = ((ntp_fp_t *)&(x))->integral \
+ - (time_t)PPS_JAN_1970; \
+ (x).tv_nsec = (long)d_frac; \
+ } 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 */
+#define PPS_TSFMT_BOTH (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
+
+/*
+ * Kernel discipline actions (not used in Windows yet)
+ */
+
+#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 */
+
+#pragma warning(push)
+#pragma warning(disable: 201) /* nonstd extension nameless union */
+
+typedef struct ntp_fp {
+ union ntp_fp_sec {
+ unsigned int integral;
+ int s_integral;
+ };
+ unsigned int fractional;
+} ntp_fp_t; /* NTP-compatible time stamp */
+
+#pragma warning(pop)
+
+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 */
+
+/* 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, \
+ (a)->s_integral, (a)->fractional)
+
+
+/*
+ * 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
+
+/*
+ *------ Here begins the implementation-specific part! ------
+ */
+
+#include <windows.h>
+#include <errno.h>
+#include <stddef.h> /* offsetof() */
+#include <io.h> /* _get_osfhandle() */
+
+#ifndef EOPNOTSUPP
+#define EOPNOTSUPP 45
+#endif
+
+typedef UINT_PTR pps_handle_t; /* pps handlebars */
+
+#ifndef inline
+#define inline __inline
+#endif
+
+/*
+ * ntpd on Windows is typically distributed as a binary as few users
+ * have the tools needed to build from source. Rather than build
+ * a single timepps.h for Windows which knows how to talk to all
+ * PPS implementations frozen in time as of compiling, this timepps.h
+ * allows one or more backend providers to be used by naming a DLL
+ * which exports the provider interfaces defined here.
+ */
+typedef enum ppsapi_magic_tag {
+ PPSAPI_MAGIC_UNIT = 0x70707355, /* ppsU */
+} ppsapi_magic;
+
+typedef struct {
+ struct pps_provider_tag *provider;
+ void * context;/* provider's unit pointer */
+ ppsapi_magic magic; /* to detect invalid handles */
+ pps_params_t params; /* PPS parameters set by user */
+} pps_unit_t;
+
+typedef void (*ppps_ntp_timestamp_from_counter)(
+ ntp_fp_t *result,
+ ULONGLONG Timestamp,
+ ULONGLONG Counterstamp
+ );
+
+typedef pps_handle_t (*pcreate_pps_handle)(
+ void * prov_context
+ );
+
+/*
+ * ppsapi_prov_init() - exported by backend DLLs
+ *
+ * Return value is pps capabilities available to PPSAPI consumers
+ * via time_pps_getcaps().
+ */
+#define PPSAPI_TIMEPPS_PROV_VER 2
+
+typedef int (WINAPI *pppsapi_prov_init)(
+ int ppsapi_timepps_prov_ver,
+ pcreate_pps_handle create_pps_handle,
+ ppps_ntp_timestamp_from_counter ntp_timestamp_from_counter,
+ char * short_name_buf,
+ size_t short_name_size,
+ char * full_name_buf,
+ size_t full_name_size
+ );
+
+typedef int (WINAPI *provtime_pps_create)(
+ HANDLE winhandle, /* user device handle */
+ pps_handle_t *phandle /* returned handle */
+ );
+
+typedef int (WINAPI *provtime_pps_destroy)(
+ pps_unit_t * unit,
+ void * context
+ );
+
+typedef int (WINAPI *provtime_pps_setparams)(
+ pps_unit_t * unit,
+ void * context,
+ const pps_params_t * params
+ );
+
+typedef int (WINAPI *provtime_pps_fetch)(
+ pps_unit_t * unit,
+ void * context,
+ const int tsformat,
+ pps_info_t * pinfo,
+ const struct timespec * timeout
+ );
+
+typedef int (WINAPI *provtime_pps_kcbind)(
+ pps_unit_t * unit,
+ void * context,
+ const int kernel_consumer,
+ const int edge,
+ const int tsformat
+ );
+
+typedef struct pps_provider_tag {
+ struct pps_provider_tag *next;
+ int caps;
+ char * short_name;
+ char * full_name;
+ provtime_pps_create ptime_pps_create;
+ provtime_pps_destroy ptime_pps_destroy;
+ provtime_pps_setparams ptime_pps_setparams;
+ provtime_pps_fetch ptime_pps_fetch;
+ provtime_pps_kcbind ptime_pps_kcbind;
+} ppsapi_provider;
+
+static ppsapi_provider * g_provider_list;
+static ppsapi_provider * g_curr_provider;
+
+
+static inline pps_handle_t
+internal_create_pps_handle(
+ void * prov_context
+ )
+{
+ pps_unit_t * punit;
+
+ if (NULL == g_curr_provider) {
+ fprintf(stderr, "create_pps_handle: provider backend called me outside time_pps_create\n");
+ punit = NULL;
+ } else
+ punit = malloc(sizeof(*punit));
+ if (punit != NULL) {
+ punit->provider = g_curr_provider;
+ punit->context = prov_context;
+ punit->magic = PPSAPI_MAGIC_UNIT;
+ memset(&punit->params, 0, sizeof(punit->params));
+ }
+ return (pps_handle_t)punit;
+}
+
+static inline pps_unit_t *
+unit_from_ppsapi_handle(
+ pps_handle_t handle
+ )
+{
+ pps_unit_t *punit;
+
+ punit = (pps_unit_t *)handle;
+ if (PPSAPI_MAGIC_UNIT != punit->magic)
+ punit = NULL;
+ return punit;
+}
+
+/*
+ * ntpd on Windows only looks to errno after finding
+ * GetLastError returns NO_ERROR. To accomodate its
+ * use of msyslog in portable code such as refclock_atom.c,
+ * this implementation always clears the Windows
+ * error code using SetLastError(NO_ERROR) when
+ * returning an errno. This is also a good idea
+ * for any non-ntpd clients as they should rely only
+ * the errno for PPSAPI functions.
+ */
+#define RETURN_PPS_ERRNO(e) \
+do { \
+ SetLastError(NO_ERROR); \
+ errno = (e); \
+ return -1; \
+} while (0)
+
+
+#ifdef OWN_PPS_NTP_TIMESTAMP_FROM_COUNTER
+extern void pps_ntp_timestamp_from_counter(ntp_fp_t *, ULONGLONG, ULONGLONG);
+#else
+/*
+ * helper routine for serialpps.sys ioctl which returns
+ * performance counter "timestamp" as well as a system
+ * FILETIME timestamp. Converts one of the inputs to
+ * NTP fixed-point format.
+ *
+ * You will probably want to supply your own and #define
+ * OWN_PPS_NTP_TIMESTAMP_FROM_COUNTER, as this stub
+ * converts only the low-resolution system timestamp.
+ *
+ * When implementing a provider, use the pointer to this
+ * conversion function supplied to your prov_init(), as
+ * the copy in your DLL will likely be the stub below,
+ * where you want the one provided by the PPSAPI client
+ * such as ntpd.
+ */
+static inline void
+pps_ntp_timestamp_from_counter(
+ ntp_fp_t *result,
+ ULONGLONG Timestamp,
+ ULONGLONG Counterstamp)
+{
+ ULONGLONG BiasedTimestamp;
+
+ /* convert from 100ns units to NTP fixed point format */
+
+ BiasedTimestamp = Timestamp - PPS_FILETIME_1970;
+ result->integral = PPS_JAN_1970 +
+ (unsigned)(BiasedTimestamp / PPS_HECTONANOSECONDS);
+ result->fractional =
+ (unsigned) ((BiasedTimestamp % PPS_HECTONANOSECONDS) *
+ (PPS_FRAC / PPS_HECTONANOSECONDS));
+}
+#endif
+
+
+static inline int
+load_pps_provider(
+ char * dllpath
+ )
+{
+ char short_name[16];
+ char full_name[64];
+ ppsapi_provider * prov;
+ HMODULE hmod;
+ pppsapi_prov_init pprov_init;
+
+ prov = malloc(sizeof(*prov));
+ if (NULL == prov)
+ return ENOMEM;
+
+ hmod = LoadLibrary(dllpath);
+ if (NULL == hmod) {
+ fprintf(stderr, "load_pps_provider: LoadLibrary(%s) error %u\n", dllpath, GetLastError());
+ free(prov);
+ return ENOENT;
+ }
+
+ pprov_init = (pppsapi_prov_init)GetProcAddress(hmod, "ppsapi_prov_init");
+ if (NULL == pprov_init) {
+ fprintf(stderr, "load_pps_provider: entrypoint ppsapi_prov_init not found in %s\n", dllpath);
+ free(prov);
+ FreeLibrary(hmod);
+ return EFAULT;
+ }
+
+ prov->caps = (*pprov_init)(PPSAPI_TIMEPPS_PROV_VER,
+ &internal_create_pps_handle,
+ &pps_ntp_timestamp_from_counter,
+ short_name, sizeof(short_name),
+ full_name, sizeof(full_name));
+
+ if (!prov->caps) {
+ free(prov);
+ FreeLibrary(hmod);
+ return EACCES;
+ }
+
+ prov->short_name = _strdup(short_name);
+ prov->full_name = _strdup(full_name);
+
+ if (NULL == prov->short_name || !prov->short_name[0]
+ || NULL == prov->full_name || !prov->full_name[0]) {
+
+ if (prov->short_name)
+ free(prov->short_name);
+ if (prov->full_name)
+ free(prov->full_name);
+ free(prov);
+ FreeLibrary(hmod);
+ return EINVAL;
+ }
+
+ prov->ptime_pps_create = (provtime_pps_create)
+ GetProcAddress(hmod, "prov_time_pps_create");
+ prov->ptime_pps_destroy = (provtime_pps_destroy)
+ GetProcAddress(hmod, "prov_time_pps_destroy");
+ prov->ptime_pps_setparams = (provtime_pps_setparams)
+ GetProcAddress(hmod, "prov_time_pps_setparams");
+ prov->ptime_pps_fetch = (provtime_pps_fetch)
+ GetProcAddress(hmod, "prov_time_pps_fetch");
+ prov->ptime_pps_kcbind = (provtime_pps_kcbind)
+ GetProcAddress(hmod, "prov_time_pps_kcbind");
+
+ if (NULL == prov->ptime_pps_create
+ || NULL == prov->ptime_pps_destroy
+ || NULL == prov->ptime_pps_setparams
+ || NULL == prov->ptime_pps_fetch
+ || NULL == prov->ptime_pps_kcbind) {
+
+ fprintf(stderr, "PPSAPI provider %s missing entrypoint\n",
+ prov->short_name);
+ free(prov->short_name);
+ free(prov->full_name);
+ free(prov);
+ FreeLibrary(hmod);
+ return EINVAL;
+ }
+
+ fprintf(stderr, "loaded PPSAPI provider %s caps 0x%x provider %p\n",
+ prov->full_name, prov->caps, prov);
+
+ prov->next = g_provider_list;
+ g_provider_list = prov;
+
+ return 0;
+}
+
+
+/*
+ * time_pps_create - create PPS handle from file descriptor
+ *
+ * This is the initial entrypoint of PPSAPI from the client. Note
+ * to maintain source compatibility with Unix, the input file
+ * descriptor really is a descriptor from the C runtime low-numbered
+ * descriptor namespace, though it may have been converted from a
+ * native Windows HANDLE using _open_osfhandle().
+ */
+static inline int
+time_pps_create(
+ int filedes,/* device file descriptor */
+ pps_handle_t * phandle /* returned handle */
+ )
+{
+ HANDLE winhandle;
+ char * dlls;
+ char * dll;
+ char * pch;
+ ppsapi_provider * prov;
+ pps_handle_t ppshandle;
+ int err;
+
+ if (NULL == phandle)
+ RETURN_PPS_ERRNO(EFAULT);
+
+ winhandle = (HANDLE)_get_osfhandle(filedes);
+ fprintf(stderr, "time_pps_create(%d) got winhandle %p\n", filedes, winhandle);
+ if (INVALID_HANDLE_VALUE == winhandle)
+ RETURN_PPS_ERRNO(EBADF);
+
+ /*
+ * For initial testing the list of PPSAPI backend
+ * providers is provided by the environment variable
+ * PPSAPI_DLLS, separated by semicolons such as
+ * PPSAPI_DLLS=c:\ntp\serial_ppsapi.dll;..\parport_ppsapi.dll
+ * There are a million better ways, such as a well-known
+ * registry key under which a value is created for each
+ * provider DLL installed, or even a platform-specific
+ * ntp.conf directive or command-line switch.
+ */
+ dlls = getenv("PPSAPI_DLLS");
+ if (dlls != NULL && NULL == g_provider_list) {
+ dlls = dll = _strdup(dlls);
+ fprintf(stderr, "getenv(PPSAPI_DLLS) gives %s\n", dlls);
+ } else
+ dlls = dll = NULL;
+
+ while (dll != NULL && dll[0]) {
+ pch = strchr(dll, ';');
+ if (pch != NULL)
+ *pch = 0;
+ err = load_pps_provider(dll);
+ if (err) {
+ fprintf(stderr, "load_pps_provider(%s) got errno %d\n", dll, err);
+ RETURN_PPS_ERRNO(err);
+ }
+ dll = (NULL == pch)
+ ? NULL
+ : pch + 1;
+ }
+
+ if (NULL != dlls)
+ free(dlls);
+ dlls = dll = NULL;
+
+ /*
+ * Hand off to each provider in turn until one returns a PPS
+ * handle or they've all declined.
+ */
+ for (prov = g_provider_list; prov != NULL; prov = prov->next) {
+ ppshandle = 0;
+ g_curr_provider = prov;
+ err = (*prov->ptime_pps_create)(winhandle, &ppshandle);
+ g_curr_provider = NULL;
+ fprintf(stderr, "%s prov_time_pps_create(%p) returned %d\n",
+ prov->short_name, winhandle, err);
+ if (!err && ppshandle) {
+ *phandle = ppshandle;
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "PPSAPI provider list %p\n", g_provider_list);
+
+ RETURN_PPS_ERRNO(ENOEXEC);
+}
+
+
+/*
+ * release PPS handle
+ */
+
+static inline int
+time_pps_destroy(
+ pps_handle_t handle
+ )
+{
+ pps_unit_t * punit;
+ int err;
+
+ if (!handle)
+ RETURN_PPS_ERRNO(EBADF);
+
+ punit = unit_from_ppsapi_handle(handle);
+
+ if (NULL == punit)
+ RETURN_PPS_ERRNO(EBADF);
+
+ err = (*punit->provider->ptime_pps_destroy)(punit, punit->context);
+
+ free(punit);
+
+ if (err)
+ RETURN_PPS_ERRNO(err);
+ else
+ 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 err;
+
+ /*
+ * Check for valid arguments and set parameters.
+ */
+ if (!handle)
+ RETURN_PPS_ERRNO(EBADF);
+
+ punit = unit_from_ppsapi_handle(handle);
+
+ if (NULL == punit)
+ RETURN_PPS_ERRNO(EBADF);
+
+ if (NULL == params)
+ RETURN_PPS_ERRNO(EFAULT);
+
+ err = (*punit->provider->ptime_pps_setparams)(punit, punit->context, params);
+
+ if (err)
+ RETURN_PPS_ERRNO(err);
+ else
+ return 0;
+}
+
+/*
+ * get parameters for handle
+ */
+
+static inline int
+time_pps_getparams(
+ pps_handle_t handle,
+ pps_params_t *params_buf
+ )
+{
+ pps_unit_t * punit;
+
+ /*
+ * Check for valid arguments and get parameters.
+ */
+ if (!handle)
+ RETURN_PPS_ERRNO(EBADF);
+
+ punit = unit_from_ppsapi_handle(handle);
+
+ if (NULL == punit)
+ RETURN_PPS_ERRNO(EBADF);
+
+ if (NULL == params_buf)
+ RETURN_PPS_ERRNO(EFAULT);
+
+ *params_buf = punit->params;
+ return 0;
+}
+
+
+/*
+ * time_pps_getcap - get capabilities for handle
+ */
+static inline int
+time_pps_getcap(
+ pps_handle_t handle,
+ int *pmode
+ )
+{
+ pps_unit_t * punit;
+
+ /*
+ * Check for valid arguments and get capabilities.
+ */
+ if (!handle)
+ RETURN_PPS_ERRNO(EBADF);
+
+ punit = unit_from_ppsapi_handle(handle);
+
+ if (NULL == punit)
+ RETURN_PPS_ERRNO(EBADF);
+
+ if (NULL == pmode)
+ RETURN_PPS_ERRNO(EFAULT);
+
+ *pmode = punit->provider->caps;
+ return 0;
+}
+
+/*
+ * Fetch timestamps
+ */
+
+static inline int
+time_pps_fetch(
+ pps_handle_t handle,
+ const int tsformat,
+ pps_info_t * pinfo,
+ const struct timespec * ptimeout
+ )
+{
+ pps_unit_t * punit;
+ int err;
+
+ /*
+ * Check for valid arguments and fetch timestamps
+ */
+ if (!handle)
+ RETURN_PPS_ERRNO(EBADF);
+
+ if (NULL == pinfo)
+ RETURN_PPS_ERRNO(EFAULT);
+
+ punit = unit_from_ppsapi_handle(handle);
+
+ if (NULL == punit)
+ RETURN_PPS_ERRNO(EBADF);
+
+ err = (*punit->provider->ptime_pps_fetch)(punit,
+ punit->context,
+ tsformat,
+ pinfo,
+ ptimeout);
+
+ if (err)
+ RETURN_PPS_ERRNO(err);
+ else
+ return 0;
+}
+
+/*
+ * time_pps_kcbind - specify kernel consumer
+ *
+ * Not supported so far by Windows.
+ */
+
+static inline int
+time_pps_kcbind(
+ pps_handle_t handle,
+ const int kernel_consumer,
+ const int edge, const int tsformat
+ )
+{
+ pps_unit_t * punit;
+ int err;
+
+ if (!handle)
+ RETURN_PPS_ERRNO(EBADF);
+
+ punit = unit_from_ppsapi_handle(handle);
+
+ if (NULL == punit)
+ RETURN_PPS_ERRNO(EBADF);
+
+ err = (*punit->provider->ptime_pps_kcbind)(
+ punit,
+ punit->context,
+ kernel_consumer,
+ edge,
+ tsformat);
+
+ if (err)
+ RETURN_PPS_ERRNO(err);
+ else
+ return 0;
+}
+
+
+#endif /* TIMEPPS_H */