PageRenderTime 24ms CodeModel.GetById 1ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/ntp/include/timepps-SunOS.h

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