Annotation of embedaddon/ntp/include/timepps-Solaris.h, revision 1.1.1.1
1.1 misho 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 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_ */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>