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