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