3 /***********************************************************************
5 * Copyright (c) David L. Mills 1999-2009 *
7 * Permission to use, copy, modify, and distribute this software and *
8 * its documentation for any purpose and without fee is hereby *
9 * granted, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission *
11 * notice appear in supporting documentation, and that the name *
12 * University of Delaware not be used in advertising or publicity *
13 * pertaining to distribution of the software without specific, *
14 * written prior permission. The University of Delaware makes no *
15 * representations about the suitability this software for any *
16 * purpose. It is provided "as is" without express or implied *
19 ***********************************************************************
21 * This header file complies with "Pulse-Per-Second API for UNIX-like *
22 * Operating Systems, Version 1.0", rfc2783. Credit is due Jeff Mogul *
23 * and Marc Brett, from whom much of this code was shamelessly stolen. *
25 * this modified timepps.h can be used to provide a PPSAPI interface *
26 * to a machine running Solaris (2.6 and above). *
28 ***********************************************************************
30 * A full PPSAPI interface to the Solaris kernel would be better, but *
31 * this at least removes the necessity for special coding from the NTP *
34 ***********************************************************************
36 * Some of this include file *
37 * Copyright (c) 1999 by Ulrich Windl, *
38 * based on code by Reg Clemens <reg@dwf.com> *
39 * based on code by Poul-Henning Kamp <phk@FreeBSD.org> *
41 ***********************************************************************
43 * "THE BEER-WARE LICENSE" (Revision 42): *
44 * <phk@FreeBSD.org> wrote this file. As long as you retain this *
45 * notice you can do whatever you want with this stuff. If we meet some*
46 * day, and you think this stuff is worth it, you can buy me a beer *
47 * in return. Poul-Henning Kamp *
49 **********************************************************************/
51 /* Solaris version, TIOCGPPSEV and TIOCSPPS assumed to exist. */
53 #ifndef _SYS_TIMEPPS_H_
54 #define _SYS_TIMEPPS_H_
56 #include <termios.h> /* to get TOCGPPSEV and TIOCSPPS */
58 /* Implementation note: the logical states ``assert'' and ``clear''
59 * are implemented in terms of the UART register, i.e. ``assert''
60 * means the bit is set.
64 * The following definitions are architecture independent
67 #define PPS_API_VERS_1 1 /* API version number */
68 #define PPS_JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
69 #define PPS_NANOSECOND 1000000000L /* one nanosecond in decimal */
70 #define PPS_FRAC 4294967296. /* 2^32 as a double */
72 #define PPS_NORMALIZE(x) /* normalize timespec */ \
74 if ((x).tv_nsec >= PPS_NANOSECOND) { \
75 (x).tv_nsec -= PPS_NANOSECOND; \
77 } else if ((x).tv_nsec < 0) { \
78 (x).tv_nsec += PPS_NANOSECOND; \
83 #define PPS_TSPECTONTP(x) /* convert timespec to l_fp */ \
87 (x).integral += (unsigned int)PPS_JAN_1970; \
88 d_temp = (x).fractional * PPS_FRAC / PPS_NANOSECOND; \
89 if (d_temp >= PPS_FRAC) \
91 (x).fractional = (unsigned int)d_temp; \
95 * Device/implementation parameters (mode)
98 #define PPS_CAPTUREASSERT 0x01 /* capture assert events */
99 #define PPS_CAPTURECLEAR 0x02 /* capture clear events */
100 #define PPS_CAPTUREBOTH 0x03 /* capture assert and clear events */
102 #define PPS_OFFSETASSERT 0x10 /* apply compensation for assert ev. */
103 #define PPS_OFFSETCLEAR 0x20 /* apply compensation for clear ev. */
104 #define PPS_OFFSETBOTH 0x30 /* apply compensation for both */
106 #define PPS_CANWAIT 0x100 /* Can we wait for an event? */
107 #define PPS_CANPOLL 0x200 /* "This bit is reserved for */
110 * Kernel actions (mode)
113 #define PPS_ECHOASSERT 0x40 /* feed back assert event to output */
114 #define PPS_ECHOCLEAR 0x80 /* feed back clear event to output */
117 * Timestamp formats (tsformat)
120 #define PPS_TSFMT_TSPEC 0x1000 /* select timespec format */
121 #define PPS_TSFMT_NTPFP 0x2000 /* select NTP format */
124 * Kernel discipline actions (not used in Solaris)
127 #define PPS_KC_HARDPPS 0 /* enable kernel consumer */
128 #define PPS_KC_HARDPPS_PLL 1 /* phase-lock mode */
129 #define PPS_KC_HARDPPS_FLL 2 /* frequency-lock mode */
135 typedef unsigned long pps_seq_t
; /* sequence number */
137 typedef struct ntp_fp
{
138 unsigned int integral
;
139 unsigned int fractional
;
140 } ntp_fp_t
; /* NTP-compatible time stamp */
142 typedef union pps_timeu
{ /* timestamp format */
143 struct timespec tspec
;
145 unsigned long longpad
[3];
146 } pps_timeu_t
; /* generic data type to represent time stamps */
149 * Timestamp information structure
152 typedef struct pps_info
{
153 pps_seq_t assert_sequence
; /* seq. num. of assert event */
154 pps_seq_t clear_sequence
; /* seq. num. of clear event */
155 pps_timeu_t assert_tu
; /* time of assert event */
156 pps_timeu_t clear_tu
; /* time of clear event */
157 int current_mode
; /* current mode bits */
160 #define assert_timestamp assert_tu.tspec
161 #define clear_timestamp clear_tu.tspec
163 #define assert_timestamp_ntpfp assert_tu.ntpfp
164 #define clear_timestamp_ntpfp clear_tu.ntpfp
167 * Parameter structure
170 typedef struct pps_params
{
171 int api_version
; /* API version # */
172 int mode
; /* mode bits */
173 pps_timeu_t assert_off_tu
; /* offset compensation for assert */
174 pps_timeu_t clear_off_tu
; /* offset compensation for clear */
177 #define assert_offset assert_off_tu.tspec
178 #define clear_offset clear_off_tu.tspec
180 #define assert_offset_ntpfp assert_off_tu.ntpfp
181 #define clear_offset_ntpfp clear_off_tu.ntpfp
183 /* addition of NTP fixed-point format */
185 #define NTPFP_M_ADD(r_i, r_f, a_i, a_f) /* r += a */ \
187 register u_int32 lo_tmp; \
188 register u_int32 hi_tmp; \
190 lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \
191 hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & 0xffff); \
192 if (lo_tmp & 0x10000) \
194 (r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \
197 if (hi_tmp & 0x10000) \
201 #define NTPFP_L_ADDS(r, a) NTPFP_M_ADD((r)->integral, (r)->fractional, \
202 (int)(a)->integral, (a)->fractional)
205 * The following definitions are architecture-dependent
208 #define PPS_CAP (PPS_CAPTUREASSERT | PPS_OFFSETASSERT | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
209 #define PPS_RO (PPS_CANWAIT | PPS_CANPOLL)
212 int filedes
; /* file descriptor */
213 pps_params_t params
; /* PPS parameters set by user */
217 *------ Here begins the implementation-specific part! ------
223 * pps handlebars, which are required to be an opaque scalar. This
224 * implementation uses the handle as a pointer so it must be large
225 * enough. uintptr_t is as large as a pointer.
227 typedef uintptr_t pps_handle_t
;
230 * create PPS handle from file descriptor
235 int filedes
, /* file descriptor */
236 pps_handle_t
*handle
/* returned handle */
243 * Check for valid arguments and attach PPS signal.
248 return (-1); /* null pointer */
251 if (ioctl(filedes
, TIOCSPPS
, &one
) < 0) {
252 perror("refclock_ioctl: TIOCSPPS failed:");
257 * Allocate and initialize default unit structure.
260 punit
= malloc(sizeof(*punit
));
263 return (-1); /* what, no memory? */
266 memset(punit
, 0, sizeof(*punit
));
267 punit
->filedes
= filedes
;
268 punit
->params
.api_version
= PPS_API_VERS_1
;
269 punit
->params
.mode
= PPS_CAPTUREASSERT
| PPS_TSFMT_TSPEC
;
271 *handle
= (pps_handle_t
)punit
;
287 * Check for valid arguments and detach PPS signal.
292 return (-1); /* bad handle */
294 punit
= (pps_unit_t
*)handle
;
300 * set parameters for handle
306 const pps_params_t
*params
312 * Check for valid arguments and set parameters.
317 return (-1); /* bad handle */
322 return (-1); /* bad argument */
326 * There was no reasonable consensu in the API working group.
327 * I require `api_version' to be set!
330 if (params
->api_version
!= PPS_API_VERS_1
) {
336 * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT
339 mode_in
= params
->mode
;
340 punit
= (pps_unit_t
*)handle
;
343 * Only one of the time formats may be selected
344 * if a nonzero assert offset is supplied.
346 if ((mode_in
& (PPS_TSFMT_TSPEC
| PPS_TSFMT_NTPFP
)) ==
347 (PPS_TSFMT_TSPEC
| PPS_TSFMT_NTPFP
)) {
349 if (punit
->params
.assert_offset
.tv_sec
||
350 punit
->params
.assert_offset
.tv_nsec
) {
357 * If no offset was specified but both time
358 * format flags are used consider it harmless
359 * but turn off PPS_TSFMT_NTPFP so getparams
360 * will not show both formats lit.
362 mode_in
&= ~PPS_TSFMT_NTPFP
;
365 /* turn off read-only bits */
370 * test remaining bits, should only have captureassert,
371 * offsetassert, and/or timestamp format bits.
374 if (mode_in
& ~(PPS_CAPTUREASSERT
| PPS_OFFSETASSERT
|
375 PPS_TSFMT_TSPEC
| PPS_TSFMT_NTPFP
)) {
384 mode
= punit
->params
.mode
;
385 memcpy(&punit
->params
, params
, sizeof(punit
->params
));
386 punit
->params
.api_version
= PPS_API_VERS_1
;
387 punit
->params
.mode
= mode
| mode_in
;
392 * get parameters for handle
404 * Check for valid arguments and get parameters.
409 return (-1); /* bad handle */
414 return (-1); /* bad argument */
417 punit
= (pps_unit_t
*)handle
;
418 memcpy(params
, &punit
->params
, sizeof(params
));
423 * get capabilities for handle
433 * Check for valid arguments and get capabilities.
438 return (-1); /* bad handle */
443 return (-1); /* bad argument */
458 const struct timespec
*timeout
470 * Check for valid arguments and fetch timestamps
475 return (-1); /* bad handle */
480 return (-1); /* bad argument */
484 * nb. PPS_CANWAIT is NOT set by the implementation, we can totally
485 * ignore the timeout variable.
488 memset(&infobuf
, 0, sizeof(infobuf
));
489 punit
= (pps_unit_t
*)handle
;
492 * if not captureassert, nothing to return.
495 if (!punit
->params
.mode
& PPS_CAPTUREASSERT
) {
496 memcpy(ppsinfo
, &infobuf
, sizeof(*ppsinfo
));
500 if (ioctl(punit
->filedes
, TIOCGPPSEV
, (caddr_t
) &ev
) < 0) {
501 perror("time_pps_fetch:");
506 infobuf
.assert_sequence
= ev
.serial
;
507 infobuf
.assert_timestamp
.tv_sec
= ev
.tv
.tv_sec
;
508 infobuf
.assert_timestamp
.tv_nsec
= ev
.tv
.tv_usec
* 1000;
511 * Translate to specified format then apply offset
515 case PPS_TSFMT_TSPEC
:
516 /* timespec format requires no conversion */
517 if (punit
->params
.mode
& PPS_OFFSETASSERT
) {
518 infobuf
.assert_timestamp
.tv_sec
+=
519 punit
->params
.assert_offset
.tv_sec
;
520 infobuf
.assert_timestamp
.tv_nsec
+=
521 punit
->params
.assert_offset
.tv_nsec
;
522 PPS_NORMALIZE(infobuf
.assert_timestamp
);
526 case PPS_TSFMT_NTPFP
:
527 /* NTP format requires conversion to fraction form */
528 PPS_TSPECTONTP(infobuf
.assert_timestamp_ntpfp
);
529 if (punit
->params
.mode
& PPS_OFFSETASSERT
)
530 NTPFP_L_ADDS(&infobuf
.assert_timestamp_ntpfp
,
531 &punit
->params
.assert_offset_ntpfp
);
539 infobuf
.current_mode
= punit
->params
.mode
;
540 memcpy(ppsinfo
, &infobuf
, sizeof(*ppsinfo
));
545 * specify kernel consumer
551 const int kernel_consumer
,
557 * Check for valid arguments and bind kernel consumer
561 return (-1); /* bad handle */
563 if (geteuid() != 0) {
565 return (-1); /* must be superuser */
571 #endif /* _SYS_TIMEPPS_H_ */