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>