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>