]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/include/timepps-Solaris.h
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / include / timepps-Solaris.h
1 /***********************************************************************
2  *                                                                     *
3  * Copyright (c) David L. Mills 1999-2009                              *
4  *                                                                     *
5  * Permission to use, copy, modify, and distribute this software and   *
6  * its documentation for any purpose and with or 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 /* addition of NTP fixed-point format */
182
183 #define NTPFP_M_ADD(r_i, r_f, a_i, a_f)         /* r += a */ \
184         do { \
185                 register u_int32 lo_tmp; \
186                 register u_int32 hi_tmp; \
187                 \
188                 lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \
189                 hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & 0xffff); \
190                 if (lo_tmp & 0x10000) \
191                         hi_tmp++; \
192                 (r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \
193                 \
194                 (r_i) += (a_i); \
195                 if (hi_tmp & 0x10000) \
196                         (r_i)++; \
197         } while (0)
198
199 #define NTPFP_L_ADDS(r, a)      NTPFP_M_ADD((r)->integral, (r)->fractional, \
200                                             (int)(a)->integral, (a)->fractional)
201
202 /*
203  * The following definitions are architecture-dependent
204  */
205
206 #define PPS_CAP (PPS_CAPTUREASSERT | PPS_OFFSETASSERT | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
207 #define PPS_RO  (PPS_CANWAIT | PPS_CANPOLL)
208
209 typedef struct {
210         int filedes;            /* file descriptor */
211         pps_params_t params;    /* PPS parameters set by user */
212 } pps_unit_t;
213
214 /*
215  *------ Here begins the implementation-specific part! ------
216  */
217
218 #include <errno.h>
219
220 /*
221  * pps handlebars, which are required to be an opaque scalar.  This
222  * implementation uses the handle as a pointer so it must be large
223  * enough.  uintptr_t is as large as a pointer.
224  */
225 typedef uintptr_t pps_handle_t; 
226
227 /*
228  * create PPS handle from file descriptor
229  */
230
231 static inline int
232 time_pps_create(
233         int filedes,            /* file descriptor */
234         pps_handle_t *handle    /* returned handle */
235         )
236 {
237         pps_unit_t *punit;
238         int one = 1;
239
240         /*
241          * Check for valid arguments and attach PPS signal.
242          */
243
244         if (!handle) {
245                 errno = EFAULT;
246                 return (-1);    /* null pointer */
247         }
248
249         if (ioctl(filedes, TIOCSPPS, &one) < 0) {
250                 perror("refclock_ioctl: TIOCSPPS failed:");
251                 return (-1);
252         }
253
254         /*
255          * Allocate and initialize default unit structure.
256          */
257
258         punit = malloc(sizeof(*punit));
259         if (NULL == punit) {
260                 errno = ENOMEM;
261                 return (-1);    /* what, no memory? */
262         }
263
264         memset(punit, 0, sizeof(*punit));
265         punit->filedes = filedes;
266         punit->params.api_version = PPS_API_VERS_1;
267         punit->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC;
268
269         *handle = (pps_handle_t)punit;
270         return (0);
271 }
272
273 /*
274  * release PPS handle
275  */
276
277 static inline int
278 time_pps_destroy(
279         pps_handle_t handle
280         )
281 {
282         pps_unit_t *punit;
283
284         /*
285          * Check for valid arguments and detach PPS signal.
286          */
287
288         if (!handle) {
289                 errno = EBADF;
290                 return (-1);    /* bad handle */
291         }
292         punit = (pps_unit_t *)handle;
293         free(punit);
294         return (0);
295 }
296
297 /*
298  * set parameters for handle
299  */
300
301 static inline int
302 time_pps_setparams(
303         pps_handle_t handle,
304         const pps_params_t *params
305         )
306 {
307         pps_unit_t *    punit;
308         int             mode, mode_in;
309         /*
310          * Check for valid arguments and set parameters.
311          */
312
313         if (!handle) {
314                 errno = EBADF;
315                 return (-1);    /* bad handle */
316         }
317
318         if (!params) {
319                 errno = EFAULT;
320                 return (-1);    /* bad argument */
321         }
322
323         /*
324          * There was no reasonable consensu in the API working group.
325          * I require `api_version' to be set!
326          */
327
328         if (params->api_version != PPS_API_VERS_1) {
329                 errno = EINVAL;
330                 return(-1);
331         }
332
333         /*
334          * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT
335          */
336
337         mode_in = params->mode;
338         punit = (pps_unit_t *)handle;
339
340         /*
341          * Only one of the time formats may be selected
342          * if a nonzero assert offset is supplied.
343          */
344         if ((mode_in & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) ==
345             (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) {
346
347                 if (punit->params.assert_offset.tv_sec ||
348                         punit->params.assert_offset.tv_nsec) {
349
350                         errno = EINVAL;
351                         return(-1);
352                 }
353
354                 /*
355                  * If no offset was specified but both time
356                  * format flags are used consider it harmless
357                  * but turn off PPS_TSFMT_NTPFP so getparams
358                  * will not show both formats lit.
359                  */
360                 mode_in &= ~PPS_TSFMT_NTPFP;
361         }
362
363         /* turn off read-only bits */
364
365         mode_in &= ~PPS_RO;
366
367         /*
368          * test remaining bits, should only have captureassert, 
369          * offsetassert, and/or timestamp format bits.
370          */
371
372         if (mode_in & ~(PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
373                         PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) {
374                 errno = EOPNOTSUPP;
375                 return(-1);
376         }
377
378         /*
379          * ok, ready to go.
380          */
381
382         mode = punit->params.mode;
383         memcpy(&punit->params, params, sizeof(punit->params));
384         punit->params.api_version = PPS_API_VERS_1;
385         punit->params.mode = mode | mode_in;
386         return (0);
387 }
388
389 /*
390  * get parameters for handle
391  */
392
393 static inline int
394 time_pps_getparams(
395         pps_handle_t handle,
396         pps_params_t *params
397         )
398 {
399         pps_unit_t *    punit;
400
401         /*
402          * Check for valid arguments and get parameters.
403          */
404
405         if (!handle) {
406                 errno = EBADF;
407                 return (-1);    /* bad handle */
408         }
409
410         if (!params) {
411                 errno = EFAULT;
412                 return (-1);    /* bad argument */
413         }
414
415         punit = (pps_unit_t *)handle;
416         memcpy(params, &punit->params, sizeof(*params));
417         return (0);
418 }
419
420 /*
421  * get capabilities for handle
422  */
423
424 static inline int
425 time_pps_getcap(
426         pps_handle_t handle,
427         int *mode
428         )
429 {
430         /*
431          * Check for valid arguments and get capabilities.
432          */
433
434         if (!handle) {
435                 errno = EBADF;
436                 return (-1);    /* bad handle */
437         }
438
439         if (!mode) {
440                 errno = EFAULT;
441                 return (-1);    /* bad argument */
442         }
443         *mode = PPS_CAP;
444         return (0);
445 }
446
447 /*
448  * Fetch timestamps
449  */
450
451 static inline int
452 time_pps_fetch(
453         pps_handle_t handle,
454         const int tsformat,
455         pps_info_t *ppsinfo,
456         const struct timespec *timeout
457         )
458 {
459         struct ppsclockev {
460                 struct timeval tv;
461                 u_int serial;
462         } ev;
463
464         pps_info_t      infobuf;
465         pps_unit_t *    punit;
466
467         /*
468          * Check for valid arguments and fetch timestamps
469          */
470
471         if (!handle) {
472                 errno = EBADF;
473                 return (-1);    /* bad handle */
474         }
475
476         if (!ppsinfo) {
477                 errno = EFAULT;
478                 return (-1);    /* bad argument */
479         }
480
481         /*
482          * nb. PPS_CANWAIT is NOT set by the implementation, we can totally
483          * ignore the timeout variable.
484          */
485
486         memset(&infobuf, 0, sizeof(infobuf));
487         punit = (pps_unit_t *)handle;
488
489         /*
490          * if not captureassert, nothing to return.
491          */
492
493         if (!punit->params.mode & PPS_CAPTUREASSERT) {
494                 memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
495                 return (0);
496         }
497
498         if (ioctl(punit->filedes, TIOCGPPSEV, (caddr_t) &ev) < 0) {
499                 perror("time_pps_fetch:");
500                 errno = EOPNOTSUPP;
501                 return(-1);
502         }
503
504         infobuf.assert_sequence = ev.serial;
505         infobuf.assert_timestamp.tv_sec = ev.tv.tv_sec;
506         infobuf.assert_timestamp.tv_nsec = ev.tv.tv_usec * 1000;
507
508         /*
509          * Translate to specified format then apply offset
510          */
511
512         switch (tsformat) {
513         case PPS_TSFMT_TSPEC:
514                 /* timespec format requires no conversion */
515                 if (punit->params.mode & PPS_OFFSETASSERT) {
516                         infobuf.assert_timestamp.tv_sec  += 
517                                 punit->params.assert_offset.tv_sec;
518                         infobuf.assert_timestamp.tv_nsec += 
519                                 punit->params.assert_offset.tv_nsec;
520                         PPS_NORMALIZE(infobuf.assert_timestamp);
521                 }
522                 break;
523
524         case PPS_TSFMT_NTPFP:
525                 /* NTP format requires conversion to fraction form */
526                 PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp);
527                 if (punit->params.mode & PPS_OFFSETASSERT)
528                         NTPFP_L_ADDS(&infobuf.assert_timestamp_ntpfp, 
529                                      &punit->params.assert_offset_ntpfp);
530                 break;          
531
532         default:
533                 errno = EINVAL;
534                 return (-1);
535         }
536
537         infobuf.current_mode = punit->params.mode;
538         memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
539         return (0);
540 }
541
542 /*
543  * specify kernel consumer
544  */
545
546 static inline int
547 time_pps_kcbind(
548         pps_handle_t handle,
549         const int kernel_consumer,
550         const int edge,
551         const int tsformat
552         )
553 {
554         /*
555          * Check for valid arguments and bind kernel consumer
556          */
557         if (!handle) {
558                 errno = EBADF;
559                 return (-1);    /* bad handle */
560         }
561         if (geteuid() != 0) {
562                 errno = EPERM;
563                 return (-1);    /* must be superuser */
564         }
565         errno = EOPNOTSUPP;
566         return(-1);
567 }
568
569 #endif /* _SYS_TIMEPPS_H_ */