]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/include/timepps-Solaris.h
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ntp / include / timepps-Solaris.h
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 Solaris (2.6 and above).                       *
25  *                                                                     *
26  ***********************************************************************
27  *                                                                     *
28  * A full PPSAPI interface to the Solaris 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 /* Solaris version, TIOCGPPSEV and TIOCSPPS assumed to exist. */
50
51 #ifndef _SYS_TIMEPPS_H_
52 #define _SYS_TIMEPPS_H_
53
54 #include <termios.h>    /* to get TOCGPPSEV and TIOCSPPS */
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 Solaris)
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
133 typedef unsigned long pps_seq_t;        /* sequence number */
134
135 typedef struct ntp_fp {
136         unsigned int    integral;
137         unsigned int    fractional;
138 } ntp_fp_t;                             /* NTP-compatible time stamp */
139
140 typedef 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
150 typedef 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
168 typedef 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
188 typedef struct {
189         int filedes;            /* file descriptor */
190         pps_params_t params;    /* PPS parameters set by user */
191 } pps_unit_t;
192
193 typedef 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
205 static inline int
206 time_pps_create(
207         int filedes,            /* file descriptor */
208         pps_handle_t *handle    /* returned handle */
209         )
210 {
211         int one = 1;
212
213         /*
214          * Check for valid arguments and attach PPS signal.
215          */
216
217         if (!handle) {
218                 errno = EFAULT;
219                 return (-1);    /* null pointer */
220         }
221
222         if (ioctl(filedes, TIOCSPPS, &one) < 0) {
223                 perror("refclock_ioctl: TIOCSPPS failed:");
224                 return (-1);
225         }
226
227         /*
228          * Allocate and initialize default unit structure.
229          */
230
231         *handle = malloc(sizeof(pps_unit_t));
232         if (!(*handle)) {
233                 errno = EBADF;
234                 return (-1);    /* what, no memory? */
235         }
236
237         memset(*handle, 0, sizeof(pps_unit_t));
238         (*handle)->filedes = filedes;
239         (*handle)->params.api_version = PPS_API_VERS_1;
240         (*handle)->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC;
241         return (0);
242 }
243
244 /*
245  * release PPS handle
246  */
247
248 static inline int
249 time_pps_destroy(
250         pps_handle_t handle
251         )
252 {
253         /*
254          * Check for valid arguments and detach PPS signal.
255          */
256
257         if (!handle) {
258                 errno = EBADF;
259                 return (-1);    /* bad handle */
260         }
261         free(handle);
262         return (0);
263 }
264
265 /*
266  * set parameters for handle
267  */
268
269 static inline int
270 time_pps_setparams(
271         pps_handle_t handle,
272         const pps_params_t *params
273         )
274 {
275         int     mode, mode_in;
276         /*
277          * Check for valid arguments and set parameters.
278          */
279
280         if (!handle) {
281                 errno = EBADF;
282                 return (-1);    /* bad handle */
283         }
284
285         if (!params) {
286                 errno = EFAULT;
287                 return (-1);    /* bad argument */
288         }
289
290         /*
291          * There was no reasonable consensu in the API working group.
292          * I require `api_version' to be set!
293          */
294
295         if (params->api_version != PPS_API_VERS_1) {
296                 errno = EINVAL;
297                 return(-1);
298         }
299
300         /*
301          * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT
302          */
303
304         mode_in = params->mode;
305
306         /* turn off read-only bits */
307
308         mode_in &= ~PPS_RO;
309
310         /* test remaining bits, should only have captureassert and/or offsetassert */
311
312         if (mode_in & ~(PPS_CAPTUREASSERT | PPS_OFFSETASSERT)) {
313                 errno = EOPNOTSUPP;
314                 return(-1);
315         }
316
317         /*
318          * ok, ready to go.
319          */
320
321         mode = handle->params.mode;
322         memcpy(&handle->params, params, sizeof(pps_params_t));
323         handle->params.api_version = PPS_API_VERS_1;
324         handle->params.mode = mode | mode_in;
325         return (0);
326 }
327
328 /*
329  * get parameters for handle
330  */
331
332 static inline int
333 time_pps_getparams(
334         pps_handle_t handle,
335         pps_params_t *params
336         )
337 {
338         /*
339          * Check for valid arguments and get parameters.
340          */
341
342         if (!handle) {
343                 errno = EBADF;
344                 return (-1);    /* bad handle */
345         }
346
347         if (!params) {
348                 errno = EFAULT;
349                 return (-1);    /* bad argument */
350         }
351
352         memcpy(params, &handle->params, sizeof(pps_params_t));
353         return (0);
354 }
355
356 /* (
357  * get capabilities for handle
358  */
359
360 static inline int
361 time_pps_getcap(
362         pps_handle_t handle,
363         int *mode
364         )
365 {
366         /*
367          * Check for valid arguments and get capabilities.
368          */
369
370         if (!handle) {
371                 errno = EBADF;
372                 return (-1);    /* bad handle */
373         }
374
375         if (!mode) {
376                 errno = EFAULT;
377                 return (-1);    /* bad argument */
378         }
379         *mode = PPS_CAP;
380         return (0);
381 }
382
383 /*
384  * Fetch timestamps
385  */
386
387 static inline int
388 time_pps_fetch(
389         pps_handle_t handle,
390         const int tsformat,
391         pps_info_t *ppsinfo,
392         const struct timespec *timeout
393         )
394 {
395         struct ppsclockev {
396                 struct timeval tv;
397                 u_int serial;
398         } ev;
399
400         pps_info_t infobuf;
401
402         /*
403          * Check for valid arguments and fetch timestamps
404          */
405
406         if (!handle) {
407                 errno = EBADF;
408                 return (-1);    /* bad handle */
409         }
410
411         if (!ppsinfo) {
412                 errno = EFAULT;
413                 return (-1);    /* bad argument */
414         }
415
416         /*
417          * nb. PPS_CANWAIT is NOT set by the implementation, we can totally
418          * ignore the timeout variable.
419          */
420
421         memset(&infobuf, 0, sizeof(infobuf));
422
423         /*
424          * if not captureassert, nothing to return.
425          */
426
427         if (!handle->params.mode & PPS_CAPTUREASSERT) {
428                 memcpy(ppsinfo, &infobuf, sizeof(pps_info_t));
429                 return (0);
430         }
431
432         if (ioctl(handle->filedes, TIOCGPPSEV, (caddr_t) &ev) < 0) {
433                 perror("time_pps_fetch:");
434                 errno = EOPNOTSUPP;
435                 return(-1);
436         }
437
438         /*
439          * Apply offsets as specified. Note that only assert timestamps
440          * are captured by this interface.
441          */
442
443         infobuf.assert_sequence = ev.serial;
444         infobuf.assert_timestamp.tv_sec = ev.tv.tv_sec;
445         infobuf.assert_timestamp.tv_nsec = ev.tv.tv_usec * 1000;
446
447         if (handle->params.mode & PPS_OFFSETASSERT) {
448                 infobuf.assert_timestamp.tv_sec  += handle->params.assert_offset.tv_sec;
449                 infobuf.assert_timestamp.tv_nsec += handle->params.assert_offset.tv_nsec;
450                 PPS_NORMALIZE(infobuf.assert_timestamp);
451         }
452
453         /*
454          * Translate to specified format
455          */
456
457         switch (tsformat) {
458         case PPS_TSFMT_TSPEC:
459                 break;           /* timespec format requires no translation */
460
461         case PPS_TSFMT_NTPFP:   /* NTP format requires conversion to fraction form */
462                 PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp);
463                 break;
464
465         default:
466                 errno = EINVAL;
467                 return (-1);
468         }
469
470         infobuf.current_mode = handle->params.mode;
471         memcpy(ppsinfo, &infobuf, sizeof(pps_info_t));
472         return (0);
473 }
474
475 /*
476  * specify kernel consumer
477  */
478
479 static inline int
480 time_pps_kcbind(
481         pps_handle_t handle,
482         const int kernel_consumer,
483         const int edge, const int tsformat
484         )
485 {
486         /*
487          * Check for valid arguments and bind kernel consumer
488          */
489         if (!handle) {
490                 errno = EBADF;
491                 return (-1);    /* bad handle */
492         }
493         if (geteuid() != 0) {
494                 errno = EPERM;
495                 return (-1);    /* must be superuser */
496         }
497         errno = EOPNOTSUPP;
498         return(-1);
499 }
500
501 #endif /* _SYS_TIMEPPS_H_ */