xref: /netbsd-src/external/bsd/ntp/dist/include/timepps-SCO.h (revision cdfa2a7ef92791ba9db70a584a1d904730e6fb46)
1 /*	$NetBSD: timepps-SCO.h,v 1.5 2020/05/25 20:47:20 christos Exp $	*/
2 
3 /***********************************************************************
4  *								       *
5  * Copyright (c) David L. Mills 1999-2000			       *
6  *								       *
7  * Permission to use, copy, modify, and distribute this software and   *
8  * its documentation for any purpose and with or 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          *
17  * warranty.							       *
18  *								       *
19  ***********************************************************************
20  *								       *
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. *
24  *								       *
25  * this modified timepps.h can be used to provide a PPSAPI interface   *
26  * to a machine running SCO Unix.				       *
27  *								       *
28  ***********************************************************************
29  *								       *
30  * A full PPSAPI interface to the SCO Unix kernel would be better, but *
31  * this at least removes the necessity for special coding from the NTP *
32  * NTP drivers. 						       *
33  *								       *
34  ***********************************************************************
35  *								       *
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>   *
40  *								       *
41  ***********************************************************************
42  *								       *
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				       *
48  *								       *
49  **********************************************************************/
50 
51 /*SCO UNIX version, TIOCDCDTIMESTAMP assumed to exist. */
52 
53 #ifndef _SYS_TIMEPPS_H_
54 #define _SYS_TIMEPPS_H_
55 
56 #include <termios.h>	/* to get TIOCDCDTIMESTAMP */
57 
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.
61  */
62 
63 /*
64  * The following definitions are architecture independent
65  */
66 
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 */
71 
72 #define PPS_NORMALIZE(x)	/* normalize timespec */ \
73 	do { \
74 		if ((x).tv_nsec >= PPS_NANOSECOND) { \
75 			(x).tv_nsec -= PPS_NANOSECOND; \
76 			(x).tv_sec++; \
77 		} else if ((x).tv_nsec < 0) { \
78 			(x).tv_nsec += PPS_NANOSECOND; \
79 			(x).tv_sec--; \
80 		} \
81 	} while (0)
82 
83 #define PPS_TSPECTONTP(x)	/* convert timespec to l_fp */ \
84 	do { \
85 		double d_temp; \
86 	\
87 		(x).integral += (unsigned int)PPS_JAN_1970; \
88 		d_temp = (x).fractional * PPS_FRAC / PPS_NANOSECOND; \
89 		if (d_temp >= PPS_FRAC) \
90 			(x).integral++; \
91 		(x).fractional = (unsigned int)d_temp; \
92 	} while (0)
93 
94 /*
95  * Device/implementation parameters (mode)
96  */
97 
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 */
101 
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 */
105 
106 #define PPS_CANWAIT		0x100	/* Can we wait for an event? */
107 #define PPS_CANPOLL		0x200	/* "This bit is reserved for */
108 
109 /*
110  * Kernel actions (mode)
111  */
112 
113 #define PPS_ECHOASSERT		0x40	/* feed back assert event to output */
114 #define PPS_ECHOCLEAR		0x80	/* feed back clear event to output */
115 
116 /*
117  * Timestamp formats (tsformat)
118  */
119 
120 #define PPS_TSFMT_TSPEC 	0x1000	/* select timespec format */
121 #define PPS_TSFMT_NTPFP 	0x2000	/* select NTP format */
122 
123 /*
124  * Kernel discipline actions (not used in Solaris)
125  */
126 
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 */
130 
131 /*
132  * Type definitions
133  */
134 
135 typedef unsigned long pps_seq_t;	/* sequence number */
136 
137 typedef struct ntp_fp {
138 	unsigned int	integral;
139 	unsigned int	fractional;
140 } ntp_fp_t;				/* NTP-compatible time stamp */
141 
142 typedef union pps_timeu {		/* timestamp format */
143 	struct timespec tspec;
144 	ntp_fp_t	ntpfp;
145 	unsigned long	longpad[3];
146 } pps_timeu_t;				/* generic data type to represent time stamps */
147 
148 /*
149  * Timestamp information structure
150  */
151 
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 */
158 } pps_info_t;
159 
160 #define assert_timestamp	assert_tu.tspec
161 #define clear_timestamp 	clear_tu.tspec
162 
163 #define assert_timestamp_ntpfp	assert_tu.ntpfp
164 #define clear_timestamp_ntpfp	clear_tu.ntpfp
165 
166 /*
167  * Parameter structure
168  */
169 
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 */
175 } pps_params_t;
176 
177 #define assert_offset		assert_off_tu.tspec
178 #define clear_offset		clear_off_tu.tspec
179 
180 #define assert_offset_ntpfp	assert_off_tu.ntpfp
181 #define clear_offset_ntpfp	clear_off_tu.ntpfp
182 
183 /*
184  * The following definitions are architecture-dependent
185  */
186 
187 #define PPS_CAP (PPS_CAPTUREASSERT | PPS_OFFSETASSERT | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
188 #define PPS_RO	(PPS_CANWAIT | PPS_CANPOLL | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
189 
190 typedef struct {
191 	int filedes;		/* file descriptor */
192 	pps_params_t params;	/* PPS parameters set by user */
193 	struct timeval	tv_save;
194 	pps_seq_t serial;
195 } pps_unit_t;
196 
197 typedef pps_unit_t* pps_handle_t; /* pps handlebars */
198 
199 /*
200  *------ Here begins the implementation-specific part! ------
201  */
202 
203 #include <errno.h>
204 
205 /*
206  * create PPS handle from file descriptor
207  */
208 
209 static inline int
time_pps_create(int filedes,pps_handle_t * handle)210 time_pps_create(
211 	int filedes,		/* file descriptor */
212 	pps_handle_t *handle	/* returned handle */
213 	)
214 {
215 	int one = 1;
216 
217 	/*
218 	 * Check for valid arguments and attach PPS signal.
219 	 */
220 
221 	if (!handle) {
222 		errno = EFAULT;
223 		return (-1);	/* null pointer */
224 	}
225 
226 	/*
227 	 * Allocate and initialize default unit structure.
228 	 */
229 
230 	*handle = malloc(sizeof(pps_unit_t));
231 	if (!(*handle)) {
232 		errno = EBADF;
233 		return (-1);	/* what, no memory? */
234 	}
235 
236 	memset(*handle, 0, sizeof(pps_unit_t));
237 	(*handle)->filedes = filedes;
238 	(*handle)->params.api_version = PPS_API_VERS_1;
239 	(*handle)->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC;
240 	return (0);
241 }
242 
243 /*
244  * release PPS handle
245  */
246 
247 static inline int
time_pps_destroy(pps_handle_t handle)248 time_pps_destroy(
249 	pps_handle_t handle
250 	)
251 {
252 	/*
253 	 * Check for valid arguments and detach PPS signal.
254 	 */
255 
256 	if (!handle) {
257 		errno = EBADF;
258 		return (-1);	/* bad handle */
259 	}
260 	free(handle);
261 	return (0);
262 }
263 
264 /*
265  * set parameters for handle
266  */
267 
268 static inline int
time_pps_setparams(pps_handle_t handle,const pps_params_t * params)269 time_pps_setparams(
270 	pps_handle_t handle,
271 	const pps_params_t *params
272 	)
273 {
274 	int	mode, mode_in;
275 	/*
276 	 * Check for valid arguments and set parameters.
277 	 */
278 
279 	if (!handle) {
280 		errno = EBADF;
281 		return (-1);	/* bad handle */
282 	}
283 
284 	if (!params) {
285 		errno = EFAULT;
286 		return (-1);	/* bad argument */
287 	}
288 
289 	/*
290 	 * There was no reasonable consensu in the API working group.
291 	 * I require `api_version' to be set!
292 	 */
293 
294 	if (params->api_version != PPS_API_VERS_1) {
295 		errno = EINVAL;
296 		return(-1);
297 	}
298 
299 	/*
300 	 * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT
301 	 */
302 
303 	mode_in = params->mode;
304 
305 	/* turn off read-only bits */
306 
307 	mode_in &= ~PPS_RO;
308 
309 	/* test remaining bits, should only have captureassert and/or offsetassert */
310 
311 	if (mode_in & ~(PPS_CAPTUREASSERT | PPS_OFFSETASSERT)) {
312 		errno = EOPNOTSUPP;
313 		return(-1);
314 	}
315 
316 	/*
317 	 * ok, ready to go.
318 	 */
319 
320 	mode = handle->params.mode;
321 	memcpy(&handle->params, params, sizeof(pps_params_t));
322 	handle->params.api_version = PPS_API_VERS_1;
323 	handle->params.mode = mode | mode_in;
324 	return (0);
325 }
326 
327 /*
328  * get parameters for handle
329  */
330 
331 static inline int
time_pps_getparams(pps_handle_t handle,pps_params_t * params)332 time_pps_getparams(
333 	pps_handle_t handle,
334 	pps_params_t *params
335 	)
336 {
337 	/*
338 	 * Check for valid arguments and get parameters.
339 	 */
340 
341 	if (!handle) {
342 		errno = EBADF;
343 		return (-1);	/* bad handle */
344 	}
345 
346 	if (!params) {
347 		errno = EFAULT;
348 		return (-1);	/* bad argument */
349 	}
350 
351 	memcpy(params, &handle->params, sizeof(pps_params_t));
352 	return (0);
353 }
354 
355 /* (
356  * get capabilities for handle
357  */
358 
359 static inline int
time_pps_getcap(pps_handle_t handle,int * mode)360 time_pps_getcap(
361 	pps_handle_t handle,
362 	int *mode
363 	)
364 {
365 	/*
366 	 * Check for valid arguments and get capabilities.
367 	 */
368 
369 	if (!handle) {
370 		errno = EBADF;
371 		return (-1);	/* bad handle */
372 	}
373 
374 	if (!mode) {
375 		errno = EFAULT;
376 		return (-1);	/* bad argument */
377 	}
378 	*mode = PPS_CAP;
379 	return (0);
380 }
381 
382 /*
383  * Fetch timestamps
384  */
385 
386 static inline int
time_pps_fetch(pps_handle_t handle,const int tsformat,pps_info_t * ppsinfo,const struct timespec * timeout)387 time_pps_fetch(
388 	pps_handle_t handle,
389 	const int tsformat,
390 	pps_info_t *ppsinfo,
391 	const struct timespec *timeout
392 	)
393 {
394 	struct timeval tv;
395 	pps_info_t infobuf;
396 
397 	/*
398 	 * Check for valid arguments and fetch timestamps
399 	 */
400 
401 	if (!handle) {
402 		errno = EBADF;
403 		return (-1);	/* bad handle */
404 	}
405 
406 	if (!ppsinfo) {
407 		errno = EFAULT;
408 		return (-1);	/* bad argument */
409 	}
410 
411 	/*
412 	 * nb. PPS_CANWAIT is NOT set by the implementation, we can totally
413 	 * ignore the timeout variable.
414 	 */
415 
416 	memset(&infobuf, 0, sizeof(infobuf));
417 
418 	/*
419 	 * if not captureassert, nothing to return.
420 	 */
421 
422 	if (!handle->params.mode & PPS_CAPTUREASSERT) {
423 		memcpy(ppsinfo, &infobuf, sizeof(pps_info_t));
424 		return (0);
425 	}
426 
427 	if (ioctl(instance->filedes, TIOCDCDTIMESTAMP, &tv) < 0) {
428 		perror("time_pps_fetch:");
429 		errno = EOPNOTSUPP;
430 		return(-1);
431 	}
432 
433 	/*
434 	 * fake serial here
435 	 */
436 
437 	if (tv.tv_sec != handle->tv_save.tv_sec || tv.tv_usec != handle->tv_save.tv_usec) {
438 		handle->tv_save = tv;
439 		handle->serial++;
440 	}
441 
442 	/*
443 	 * Apply offsets as specified. Note that only assert timestamps
444 	 * are captured by this interface.
445 	 */
446 
447 	infobuf.assert_sequence = handle->serial;
448 	infobuf.assert_timestamp.tv_sec = tv.tv_sec;
449 	infobuf.assert_timestamp.tv_nsec = tv.tv_usec * 1000;
450 
451 	if (handle->params.mode & PPS_OFFSETASSERT) {
452 		infobuf.assert_timestamp.tv_sec  += handle->params.assert_offset.tv_sec;
453 		infobuf.assert_timestamp.tv_nsec += handle->params.assert_offset.tv_nsec;
454 		PPS_NORMALIZE(infobuf.assert_timestamp);
455 	}
456 
457 	/*
458 	 * Translate to specified format
459 	 */
460 
461 	switch (tsformat) {
462 	case PPS_TSFMT_TSPEC:
463 		break;		 /* timespec format requires no translation */
464 
465 	case PPS_TSFMT_NTPFP:	/* NTP format requires conversion to fraction form */
466 		PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp);
467 		break;
468 
469 	default:
470 		errno = EINVAL;
471 		return (-1);
472 	}
473 
474 	infobuf.current_mode = handle->params.mode;
475 	memcpy(ppsinfo, &infobuf, sizeof(pps_info_t));
476 	return (0);
477 }
478 
479 /*
480  * specify kernel consumer
481  */
482 
483 static inline int
time_pps_kcbind(pps_handle_t handle,const int kernel_consumer,const int edge,const int tsformat)484 time_pps_kcbind(
485 	pps_handle_t handle,
486 	const int kernel_consumer,
487 	const int edge, const int tsformat
488 	)
489 {
490 	/*
491 	 * Check for valid arguments and bind kernel consumer
492 	 */
493 	if (!handle) {
494 		errno = EBADF;
495 		return (-1);	/* bad handle */
496 	}
497 	if (geteuid() != 0) {
498 		errno = EPERM;
499 		return (-1);	/* must be superuser */
500 	}
501 	errno = EOPNOTSUPP;
502 	return(-1);
503 }
504 
505 #endif /* _SYS_TIMEPPS_H_ */
506