diff options
Diffstat (limited to 'ports/winnt/ppsapi/loopback/monolithic-serialpps-timepps.h')
-rw-r--r-- | ports/winnt/ppsapi/loopback/monolithic-serialpps-timepps.h | 714 |
1 files changed, 0 insertions, 714 deletions
diff --git a/ports/winnt/ppsapi/loopback/monolithic-serialpps-timepps.h b/ports/winnt/ppsapi/loopback/monolithic-serialpps-timepps.h deleted file mode 100644 index 1007ccdd90c3..000000000000 --- a/ports/winnt/ppsapi/loopback/monolithic-serialpps-timepps.h +++ /dev/null @@ -1,714 +0,0 @@ -/*********************************************************************** - * * - * Copyright (c) David L. Mills 1999-2000 * - * * - * 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 a suitably modified * - * serialpps.sys being used in place of serial.sys. It can * - * be extended to support a modified parallel port driver once * - * available. * - * * - * 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 _SYS_TIMEPPS_H_ -#define _SYS_TIMEPPS_H_ - -/* 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_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_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) - -#define PPS_NTPTOTSPEC(x) /* convert ntp_fp to timespec */ \ - do { \ - double d_temp; \ - \ - (x).tv_sec -= (time_t)PPS_JAN_1970; \ - d_temp = (double)((x).tv_nsec); \ - d_temp *= PPS_NANOSECOND; \ - d_temp /= PPS_FRAC; \ - (x).tv_nsec = (long)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 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 - -/* - * 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 */ - OVERLAPPED ol; /* caches ol.hEvent for DeviceIoControl */ - pps_params_t params; /* PPS parameters set by user */ -} pps_unit_t; - -typedef pps_unit_t* pps_handle_t; /* pps handlebars */ - -/* - *------ Here begins the implementation-specific part! ------ - */ - -#include <windows.h> -#include <errno.h> - -#ifndef EOPNOTSUPP -#define EOPNOTSUPP 45 -#endif - -typedef struct _OLD_SERIAL_PPS_STAMPS { - LARGE_INTEGER Timestamp; - LARGE_INTEGER Counterstamp; -} OLD_SERIAL_PPS_STAMPS, *POLDSERIAL_PPS_STAMPS; - -typedef struct _SERIAL_PPS_STAMPS { - LARGE_INTEGER Timestamp; - LARGE_INTEGER Counterstamp; - DWORD SeqNum; -} SERIAL_PPS_STAMPS, *PSERIAL_PPS_STAMPS; - -#define IOCTL_SERIAL_GET_PPS_STAMPS CTL_CODE(FILE_DEVICE_SERIAL_PORT,114,METHOD_BUFFERED,FILE_ANY_ACCESS) - -/* byte offset of member m in struct typedef s */ -#define PPS_OFFSETOF(m,s) (size_t)(&((s *)0)->m) - -/* - * 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 use 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. - */ -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 - - -/* - * create PPS handle from file descriptor - */ - -static inline int -time_pps_create( - int filedes, /* file descriptor */ - pps_handle_t *handle /* returned handle */ - ) -{ - OLD_SERIAL_PPS_STAMPS old_pps_stamps; - DWORD bytes; - OVERLAPPED ol; - - /* - * Check for valid arguments and attach PPS signal. - */ - - if (!handle) - RETURN_PPS_ERRNO(EFAULT); - - if (PPS_OFFSETOF(tspec.tv_nsec, pps_timeu_t) != - PPS_OFFSETOF(ntpfp.fractional, pps_timeu_t)) { - fprintf(stderr, - "timepps.h needs work, union of \n" - "unsigned int ntp_fp.integral and\n" - "time_t timespec.tv_sec accessed\n" - "interchangeably.\n"); - RETURN_PPS_ERRNO(EFAULT); - } - - /* - * For this ioctl which will never block, we don't want to go - * through the overhead of a completion port, so we use an - * event handle in the overlapped structure with its 1 bit set. - * - * From GetQueuedCompletionStatus docs: - * Even if you have passed the function a file handle associated - * with a completion port and a valid OVERLAPPED structure, an - * application can prevent completion port notification. This is - * done by specifying a valid event handle for the hEvent member - * of the OVERLAPPED structure, and setting its low-order bit. A - * valid event handle whose low-order bit is set keeps I/O - * completion from being queued to the completion port. - */ - - ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - ol.hEvent = (HANDLE) ((ULONG_PTR)ol.hEvent | 1); - - if (FALSE == DeviceIoControl( - (HANDLE)_get_osfhandle(filedes), - IOCTL_SERIAL_GET_PPS_STAMPS, - NULL, - 0, - &old_pps_stamps, - sizeof(old_pps_stamps), - &bytes, - &ol) - || sizeof(old_pps_stamps) != bytes) { - - /* - * If you want to write some dead code this could detect the - * IOCTL being pended, but the driver always has the info - * instantly, so ERROR_IO_PENDING isn't a concern. - */ - - CloseHandle(ol.hEvent); - fprintf(stderr, - "time_pps_create: IOCTL_SERIAL_GET_PPS_STAMPS: %d %d\n", - bytes, - GetLastError()); - RETURN_PPS_ERRNO(ENXIO); - } - - /* - * Allocate and initialize default unit structure. - */ - - *handle = malloc(sizeof(pps_unit_t)); - if (!(*handle)) - RETURN_PPS_ERRNO(ENOMEM); - - memset(*handle, 0, sizeof(pps_unit_t)); - (*handle)->filedes = filedes; - (*handle)->ol.hEvent = ol.hEvent; - (*handle)->params.api_version = PPS_API_VERS_1; - (*handle)->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC; - return (0); -} - -/* - * release PPS handle - */ - -static inline int -time_pps_destroy( - pps_handle_t handle - ) -{ - /* - * Check for valid arguments and detach PPS signal. - */ - - if (!handle) - RETURN_PPS_ERRNO(EBADF); - - CloseHandle(handle->ol.hEvent); - free(handle); - return (0); -} - -/* - * set parameters for handle - */ - -static inline int -time_pps_setparams( - pps_handle_t handle, - const pps_params_t *params - ) -{ - int mode, mode_in; - /* - * Check for valid arguments and set parameters. - */ - - if (!handle) - RETURN_PPS_ERRNO(EBADF); - - if (!params) - RETURN_PPS_ERRNO(EFAULT); - - /* - * 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) - RETURN_PPS_ERRNO(EINVAL); - - /* - * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT - */ - - mode_in = params->mode; - - /* - * 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 (handle->params.assert_offset.tv_sec || - handle->params.assert_offset.tv_nsec) - - RETURN_PPS_ERRNO(EINVAL); - - /* - * 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)) - RETURN_PPS_ERRNO(EOPNOTSUPP); - - /* - * ok, ready to go. - */ - - mode = handle->params.mode; - handle->params = *params; - handle->params.mode = mode | mode_in; - handle->params.api_version = PPS_API_VERS_1; - return (0); -} - -/* - * get parameters for handle - */ - -static inline int -time_pps_getparams( - pps_handle_t handle, - pps_params_t *params - ) -{ - /* - * Check for valid arguments and get parameters. - */ - - if (!handle) - RETURN_PPS_ERRNO(EBADF); - - if (!params) - RETURN_PPS_ERRNO(EFAULT); - - *params = handle->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) - RETURN_PPS_ERRNO(EBADF); - - if (!mode) - RETURN_PPS_ERRNO(EFAULT); - - *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 - ) -{ - SERIAL_PPS_STAMPS pps_stamps; - pps_info_t infobuf; - BOOL rc; - DWORD bytes; - DWORD lasterr; - - /* - * Check for valid arguments and fetch timestamps - */ - - if (!handle) - RETURN_PPS_ERRNO(EBADF); - - if (!ppsinfo) - RETURN_PPS_ERRNO(EFAULT); - - /* - * nb. PPS_CANWAIT is NOT set by the implementation, we can totally - * ignore the timeout variable. - */ - - memset(&infobuf, 0, sizeof(infobuf)); - - /* - * if not captureassert, nothing to return. - */ - - if (!handle->params.mode & PPS_CAPTUREASSERT) { - *ppsinfo = infobuf; - return (0); - } - - /* - * First rev of serialpps.sys didn't support the SeqNum field, - * support it by simply returning constant 0 for serial in that case. - */ - pps_stamps.SeqNum = 0; - - /* - * interrogate (hopefully) serialpps.sys - * if it's the standard serial.sys or another driver, - * IOCTL_SERIAL_GET_PPS_STAMPS is most likely unknown - * and will result in ERROR_INVALID_PARAMETER. - */ - bytes = 0; - - rc = DeviceIoControl( - (HANDLE)_get_osfhandle(handle->filedes), - IOCTL_SERIAL_GET_PPS_STAMPS, - NULL, - 0, - &pps_stamps, - sizeof(pps_stamps), - &bytes, - &handle->ol); - - if (!rc) { - - lasterr = GetLastError(); - if (ERROR_INVALID_PARAMETER != lasterr) - fprintf(stderr, "time_pps_fetch: ioctl err %d\n", - lasterr); - RETURN_PPS_ERRNO(EOPNOTSUPP); - - } else if (bytes != sizeof(pps_stamps) && - bytes != sizeof(OLD_SERIAL_PPS_STAMPS)) { - - fprintf(stderr, - "time_pps_fetch: wanted %d or %d bytes got %d from " - "IOCTL_SERIAL_GET_PPS_STAMPS 0x%x\n" , - sizeof(OLD_SERIAL_PPS_STAMPS), - sizeof(SERIAL_PPS_STAMPS), - bytes, - IOCTL_SERIAL_GET_PPS_STAMPS); - RETURN_PPS_ERRNO(ENXIO); - } - - /* - * pps_ntp_timestamp_from_counter takes the two flavors - * of timestamp we have (counter and system time) and - * uses whichever it can to give the best NTP fixed-point - * conversion. In ntpd the Counterstamp is typically - * used. A stub implementation in this file simply - * converts from Windows Timestamp to NTP fixed-point. - */ - pps_ntp_timestamp_from_counter( - &infobuf.assert_timestamp_ntpfp, - pps_stamps.Timestamp.QuadPart, - pps_stamps.Counterstamp.QuadPart); - - /* - * Note that only assert timestamps - * are captured by this interface. - */ - - infobuf.assert_sequence = pps_stamps.SeqNum; - - /* - * Apply offset and translate to specified format - */ - - switch (tsformat) { - case PPS_TSFMT_NTPFP: /* NTP format requires no translation */ - if (handle->params.mode & PPS_OFFSETASSERT) { - NTPFP_L_ADDS(&infobuf.assert_timestamp_ntpfp, - &handle->params.assert_offset_ntpfp); - } - break; - - case PPS_TSFMT_TSPEC: /* timespec format requires conversion to nsecs form */ - PPS_NTPTOTSPEC(infobuf.assert_timestamp); - if (handle->params.mode & PPS_OFFSETASSERT) { - infobuf.assert_timestamp.tv_sec += - handle->params.assert_offset.tv_sec; - infobuf.assert_timestamp.tv_nsec += - handle->params.assert_offset.tv_nsec; - PPS_NORMALIZE(infobuf.assert_timestamp); - } - break; - - default: - RETURN_PPS_ERRNO(EINVAL); - } - - infobuf.current_mode = handle->params.mode; - *ppsinfo = infobuf; - 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 - ) -{ - /* - * Check for valid arguments before revealing the ugly truth - */ - if (!handle) - RETURN_PPS_ERRNO(EBADF); - - RETURN_PPS_ERRNO(EOPNOTSUPP); -} - - - -#endif /* _SYS_TIMEPPS_H_ */ |