Annotation of embedaddon/ntp/include/timepps-Solaris.h, revision 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>