]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/include/timepps-SunOS.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-SunOS.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 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
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         /*
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
246 static inline int
247 time_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
267 static inline int
268 time_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
330 static inline int
331 time_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
358 static inline int
359 time_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
385 static inline int
386 time_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
482 static inline int
483 time_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_ */