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