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