1181834Sroberto/*********************************************************************** 2181834Sroberto * * 3181834Sroberto * Copyright (c) David L. Mills 1999-2000 * 4181834Sroberto * * 5181834Sroberto * Permission to use, copy, modify, and distribute this software and * 6181834Sroberto * its documentation for any purpose and without fee is hereby * 7181834Sroberto * granted, provided that the above copyright notice appears in all * 8181834Sroberto * copies and that both the copyright notice and this permission * 9181834Sroberto * notice appear in supporting documentation, and that the name * 10181834Sroberto * University of Delaware not be used in advertising or publicity * 11181834Sroberto * pertaining to distribution of the software without specific, * 12181834Sroberto * written prior permission. The University of Delaware makes no * 13181834Sroberto * representations about the suitability this software for any * 14181834Sroberto * purpose. It is provided "as is" without express or implied * 15181834Sroberto * warranty. * 16181834Sroberto * * 17181834Sroberto *********************************************************************** 18181834Sroberto * * 19181834Sroberto * This header file complies with "Pulse-Per-Second API for UNIX-like * 20181834Sroberto * Operating Systems, Version 1.0", rfc2783. Credit is due Jeff Mogul * 21181834Sroberto * and Marc Brett, from whom much of this code was shamelessly stolen. * 22181834Sroberto * * 23181834Sroberto * this modified timepps.h can be used to provide a PPSAPI interface * 24181834Sroberto * to a machine running SunOS. * 25181834Sroberto * * 26181834Sroberto *********************************************************************** 27181834Sroberto * * 28181834Sroberto * A full PPSAPI interface to the SunOS kernel would be better, but * 29181834Sroberto * this at least removes the necessity for special coding from the NTP * 30181834Sroberto * NTP drivers. * 31181834Sroberto * * 32181834Sroberto *********************************************************************** 33181834Sroberto * * 34181834Sroberto * Some of this include file * 35181834Sroberto * Copyright (c) 1999 by Ulrich Windl, * 36181834Sroberto * based on code by Reg Clemens <reg@dwf.com> * 37181834Sroberto * based on code by Poul-Henning Kamp <phk@FreeBSD.org> * 38181834Sroberto * * 39181834Sroberto *********************************************************************** 40181834Sroberto * * 41181834Sroberto * "THE BEER-WARE LICENSE" (Revision 42): * 42181834Sroberto * <phk@FreeBSD.org> wrote this file. As long as you retain this * 43181834Sroberto * notice you can do whatever you want with this stuff. If we meet some* 44181834Sroberto * day, and you think this stuff is worth it, you can buy me a beer * 45181834Sroberto * in return. Poul-Henning Kamp * 46181834Sroberto * * 47181834Sroberto **********************************************************************/ 48181834Sroberto 49181834Sroberto/* SunOS version, CIOGETEV assumed to exist for SunOS */ 50181834Sroberto 51181834Sroberto#ifndef _SYS_TIMEPPS_H_ 52181834Sroberto#define _SYS_TIMEPPS_H_ 53181834Sroberto 54181834Sroberto#include <termios.h> /* to get CIOGETEV */ 55181834Sroberto 56181834Sroberto/* Implementation note: the logical states ``assert'' and ``clear'' 57181834Sroberto * are implemented in terms of the UART register, i.e. ``assert'' 58181834Sroberto * means the bit is set. 59181834Sroberto */ 60181834Sroberto 61181834Sroberto/* 62181834Sroberto * The following definitions are architecture independent 63181834Sroberto */ 64181834Sroberto 65181834Sroberto#define PPS_API_VERS_1 1 /* API version number */ 66181834Sroberto#define PPS_JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ 67181834Sroberto#define PPS_NANOSECOND 1000000000L /* one nanosecond in decimal */ 68181834Sroberto#define PPS_FRAC 4294967296. /* 2^32 as a double */ 69181834Sroberto 70181834Sroberto#define PPS_NORMALIZE(x) /* normalize timespec */ \ 71181834Sroberto do { \ 72181834Sroberto if ((x).tv_nsec >= PPS_NANOSECOND) { \ 73181834Sroberto (x).tv_nsec -= PPS_NANOSECOND; \ 74181834Sroberto (x).tv_sec++; \ 75181834Sroberto } else if ((x).tv_nsec < 0) { \ 76181834Sroberto (x).tv_nsec += PPS_NANOSECOND; \ 77181834Sroberto (x).tv_sec--; \ 78181834Sroberto } \ 79181834Sroberto } while (0) 80181834Sroberto 81181834Sroberto#define PPS_TSPECTONTP(x) /* convert timespec to l_fp */ \ 82181834Sroberto do { \ 83181834Sroberto double d_temp; \ 84181834Sroberto \ 85181834Sroberto (x).integral += (unsigned int)PPS_JAN_1970; \ 86181834Sroberto d_temp = (x).fractional * PPS_FRAC / PPS_NANOSECOND; \ 87181834Sroberto if (d_temp >= PPS_FRAC) \ 88181834Sroberto (x).integral++; \ 89181834Sroberto (x).fractional = (unsigned int)d_temp; \ 90181834Sroberto } while (0) 91181834Sroberto 92181834Sroberto/* 93181834Sroberto * Device/implementation parameters (mode) 94181834Sroberto */ 95181834Sroberto 96181834Sroberto#define PPS_CAPTUREASSERT 0x01 /* capture assert events */ 97181834Sroberto#define PPS_CAPTURECLEAR 0x02 /* capture clear events */ 98181834Sroberto#define PPS_CAPTUREBOTH 0x03 /* capture assert and clear events */ 99181834Sroberto 100181834Sroberto#define PPS_OFFSETASSERT 0x10 /* apply compensation for assert ev. */ 101181834Sroberto#define PPS_OFFSETCLEAR 0x20 /* apply compensation for clear ev. */ 102181834Sroberto#define PPS_OFFSETBOTH 0x30 /* apply compensation for both */ 103181834Sroberto 104181834Sroberto#define PPS_CANWAIT 0x100 /* Can we wait for an event? */ 105181834Sroberto#define PPS_CANPOLL 0x200 /* "This bit is reserved for */ 106181834Sroberto 107181834Sroberto/* 108181834Sroberto * Kernel actions (mode) 109181834Sroberto */ 110181834Sroberto 111181834Sroberto#define PPS_ECHOASSERT 0x40 /* feed back assert event to output */ 112181834Sroberto#define PPS_ECHOCLEAR 0x80 /* feed back clear event to output */ 113181834Sroberto 114181834Sroberto/* 115181834Sroberto * Timestamp formats (tsformat) 116181834Sroberto */ 117181834Sroberto 118181834Sroberto#define PPS_TSFMT_TSPEC 0x1000 /* select timespec format */ 119181834Sroberto#define PPS_TSFMT_NTPFP 0x2000 /* select NTP format */ 120181834Sroberto 121181834Sroberto/* 122181834Sroberto * Kernel discipline actions (not used in SunOS) 123181834Sroberto */ 124181834Sroberto 125181834Sroberto#define PPS_KC_HARDPPS 0 /* enable kernel consumer */ 126181834Sroberto#define PPS_KC_HARDPPS_PLL 1 /* phase-lock mode */ 127181834Sroberto#define PPS_KC_HARDPPS_FLL 2 /* frequency-lock mode */ 128181834Sroberto 129181834Sroberto/* 130181834Sroberto * Type definitions 131181834Sroberto */ 132181834Sroberto 133181834Srobertotypedef unsigned long pps_seq_t; /* sequence number */ 134181834Sroberto 135181834Srobertotypedef struct ntp_fp { 136181834Sroberto unsigned int integral; 137181834Sroberto unsigned int fractional; 138181834Sroberto} ntp_fp_t; /* NTP-compatible time stamp */ 139181834Sroberto 140181834Srobertotypedef union pps_timeu { /* timestamp format */ 141181834Sroberto struct timespec tspec; 142181834Sroberto ntp_fp_t ntpfp; 143181834Sroberto unsigned long longpad[3]; 144181834Sroberto} pps_timeu_t; /* generic data type to represent time stamps */ 145181834Sroberto 146181834Sroberto/* 147181834Sroberto * Timestamp information structure 148181834Sroberto */ 149181834Sroberto 150181834Srobertotypedef struct pps_info { 151181834Sroberto pps_seq_t assert_sequence; /* seq. num. of assert event */ 152181834Sroberto pps_seq_t clear_sequence; /* seq. num. of clear event */ 153181834Sroberto pps_timeu_t assert_tu; /* time of assert event */ 154181834Sroberto pps_timeu_t clear_tu; /* time of clear event */ 155181834Sroberto int current_mode; /* current mode bits */ 156181834Sroberto} pps_info_t; 157181834Sroberto 158181834Sroberto#define assert_timestamp assert_tu.tspec 159181834Sroberto#define clear_timestamp clear_tu.tspec 160181834Sroberto 161181834Sroberto#define assert_timestamp_ntpfp assert_tu.ntpfp 162181834Sroberto#define clear_timestamp_ntpfp clear_tu.ntpfp 163181834Sroberto 164181834Sroberto/* 165181834Sroberto * Parameter structure 166181834Sroberto */ 167181834Sroberto 168181834Srobertotypedef struct pps_params { 169181834Sroberto int api_version; /* API version # */ 170181834Sroberto int mode; /* mode bits */ 171181834Sroberto pps_timeu_t assert_off_tu; /* offset compensation for assert */ 172181834Sroberto pps_timeu_t clear_off_tu; /* offset compensation for clear */ 173181834Sroberto} pps_params_t; 174181834Sroberto 175181834Sroberto#define assert_offset assert_off_tu.tspec 176181834Sroberto#define clear_offset clear_off_tu.tspec 177181834Sroberto 178181834Sroberto#define assert_offset_ntpfp assert_off_tu.ntpfp 179181834Sroberto#define clear_offset_ntpfp clear_off_tu.ntpfp 180181834Sroberto 181181834Sroberto/* 182181834Sroberto * The following definitions are architecture-dependent 183181834Sroberto */ 184181834Sroberto 185181834Sroberto#define PPS_CAP (PPS_CAPTUREASSERT | PPS_OFFSETASSERT | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP) 186181834Sroberto#define PPS_RO (PPS_CANWAIT | PPS_CANPOLL | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP) 187181834Sroberto 188181834Srobertotypedef struct { 189181834Sroberto int filedes; /* file descriptor */ 190181834Sroberto pps_params_t params; /* PPS parameters set by user */ 191181834Sroberto} pps_unit_t; 192181834Sroberto 193181834Srobertotypedef pps_unit_t* pps_handle_t; /* pps handlebars */ 194181834Sroberto 195181834Sroberto/* 196181834Sroberto *------ Here begins the implementation-specific part! ------ 197181834Sroberto */ 198181834Sroberto 199181834Sroberto#include <errno.h> 200181834Sroberto 201181834Sroberto/* 202181834Sroberto * create PPS handle from file descriptor 203181834Sroberto */ 204181834Sroberto 205181834Srobertostatic inline int 206181834Srobertotime_pps_create( 207181834Sroberto int filedes, /* file descriptor */ 208181834Sroberto pps_handle_t *handle /* returned handle */ 209181834Sroberto ) 210181834Sroberto{ 211181834Sroberto /* 212181834Sroberto * Check for valid arguments and attach PPS signal. 213181834Sroberto */ 214181834Sroberto 215181834Sroberto if (!handle) { 216181834Sroberto errno = EFAULT; 217181834Sroberto return (-1); /* null pointer */ 218181834Sroberto } 219181834Sroberto 220181834Sroberto if (ioctl(filedes, I_PUSH, "ppsclock") < 0) { 221181834Sroberto perror("time_pps_create: I_PUSH ppsclock failed"); 222181834Sroberto return (-1); 223181834Sroberto } 224181834Sroberto 225181834Sroberto /* 226181834Sroberto * Allocate and initialize default unit structure. 227181834Sroberto */ 228181834Sroberto 229181834Sroberto *handle = malloc(sizeof(pps_unit_t)); 230181834Sroberto if (!(*handle)) { 231181834Sroberto errno = EBADF; 232181834Sroberto return (-1); /* what, no memory? */ 233181834Sroberto } 234181834Sroberto 235181834Sroberto memset(*handle, 0, sizeof(pps_unit_t)); 236181834Sroberto (*handle)->filedes = filedes; 237181834Sroberto (*handle)->params.api_version = PPS_API_VERS_1; 238181834Sroberto (*handle)->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC; 239181834Sroberto return (0); 240181834Sroberto} 241181834Sroberto 242181834Sroberto/* 243181834Sroberto * release PPS handle 244181834Sroberto */ 245181834Sroberto 246181834Srobertostatic inline int 247181834Srobertotime_pps_destroy( 248181834Sroberto pps_handle_t handle 249181834Sroberto ) 250181834Sroberto{ 251181834Sroberto /* 252181834Sroberto * Check for valid arguments and detach PPS signal. 253181834Sroberto */ 254181834Sroberto 255181834Sroberto if (!handle) { 256181834Sroberto errno = EBADF; 257181834Sroberto return (-1); /* bad handle */ 258181834Sroberto } 259181834Sroberto free(handle); 260181834Sroberto return (0); 261181834Sroberto} 262181834Sroberto 263181834Sroberto/* 264181834Sroberto * set parameters for handle 265181834Sroberto */ 266181834Sroberto 267181834Srobertostatic inline int 268181834Srobertotime_pps_setparams( 269181834Sroberto pps_handle_t handle, 270181834Sroberto const pps_params_t *params 271181834Sroberto ) 272181834Sroberto{ 273181834Sroberto int mode, mode_in; 274181834Sroberto /* 275181834Sroberto * Check for valid arguments and set parameters. 276181834Sroberto */ 277181834Sroberto 278181834Sroberto if (!handle) { 279181834Sroberto errno = EBADF; 280181834Sroberto return (-1); /* bad handle */ 281181834Sroberto } 282181834Sroberto 283181834Sroberto if (!params) { 284181834Sroberto errno = EFAULT; 285181834Sroberto return (-1); /* bad argument */ 286181834Sroberto } 287181834Sroberto 288181834Sroberto /* 289181834Sroberto * There was no reasonable consensu in the API working group. 290181834Sroberto * I require `api_version' to be set! 291181834Sroberto */ 292181834Sroberto 293181834Sroberto if (params->api_version != PPS_API_VERS_1) { 294181834Sroberto errno = EINVAL; 295181834Sroberto return(-1); 296181834Sroberto } 297181834Sroberto 298181834Sroberto /* 299181834Sroberto * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT 300181834Sroberto */ 301181834Sroberto 302181834Sroberto mode_in = params->mode; 303181834Sroberto 304181834Sroberto /* turn off read-only bits */ 305181834Sroberto 306181834Sroberto mode_in &= ~PPS_RO; 307181834Sroberto 308181834Sroberto /* test remaining bits, should only have captureassert and/or offsetassert */ 309181834Sroberto 310181834Sroberto if (mode_in & ~(PPS_CAPTUREASSERT | PPS_OFFSETASSERT)) { 311181834Sroberto errno = EOPNOTSUPP; 312181834Sroberto return(-1); 313181834Sroberto } 314181834Sroberto 315181834Sroberto /* 316181834Sroberto * ok, ready to go. 317181834Sroberto */ 318181834Sroberto 319181834Sroberto mode = handle->params.mode; 320181834Sroberto memcpy(&handle->params, params, sizeof(pps_params_t)); 321181834Sroberto handle->params.api_version = PPS_API_VERS_1; 322181834Sroberto handle->params.mode = mode | mode_in; 323181834Sroberto return (0); 324181834Sroberto} 325181834Sroberto 326181834Sroberto/* 327181834Sroberto * get parameters for handle 328181834Sroberto */ 329181834Sroberto 330181834Srobertostatic inline int 331181834Srobertotime_pps_getparams( 332181834Sroberto pps_handle_t handle, 333181834Sroberto pps_params_t *params 334181834Sroberto ) 335181834Sroberto{ 336181834Sroberto /* 337181834Sroberto * Check for valid arguments and get parameters. 338181834Sroberto */ 339181834Sroberto 340181834Sroberto if (!handle) { 341181834Sroberto errno = EBADF; 342181834Sroberto return (-1); /* bad handle */ 343181834Sroberto } 344181834Sroberto 345181834Sroberto if (!params) { 346181834Sroberto errno = EFAULT; 347181834Sroberto return (-1); /* bad argument */ 348181834Sroberto } 349181834Sroberto 350181834Sroberto memcpy(params, &handle->params, sizeof(pps_params_t)); 351181834Sroberto return (0); 352181834Sroberto} 353181834Sroberto 354181834Sroberto/* ( 355181834Sroberto * get capabilities for handle 356181834Sroberto */ 357181834Sroberto 358181834Srobertostatic inline int 359181834Srobertotime_pps_getcap( 360181834Sroberto pps_handle_t handle, 361181834Sroberto int *mode 362181834Sroberto ) 363181834Sroberto{ 364181834Sroberto /* 365181834Sroberto * Check for valid arguments and get capabilities. 366181834Sroberto */ 367181834Sroberto 368181834Sroberto if (!handle) { 369181834Sroberto errno = EBADF; 370181834Sroberto return (-1); /* bad handle */ 371181834Sroberto } 372181834Sroberto 373181834Sroberto if (!mode) { 374181834Sroberto errno = EFAULT; 375181834Sroberto return (-1); /* bad argument */ 376181834Sroberto } 377181834Sroberto *mode = PPS_CAP; 378181834Sroberto return (0); 379181834Sroberto} 380181834Sroberto 381181834Sroberto/* 382181834Sroberto * Fetch timestamps 383181834Sroberto */ 384181834Sroberto 385181834Srobertostatic inline int 386181834Srobertotime_pps_fetch( 387181834Sroberto pps_handle_t handle, 388181834Sroberto const int tsformat, 389181834Sroberto pps_info_t *ppsinfo, 390181834Sroberto const struct timespec *timeout 391181834Sroberto ) 392181834Sroberto{ 393181834Sroberto struct ppsclockev { 394181834Sroberto struct timeval tv; 395181834Sroberto u_int serial; 396181834Sroberto } ev; 397181834Sroberto pps_info_t infobuf; 398181834Sroberto 399181834Sroberto /* 400181834Sroberto * Check for valid arguments and fetch timestamps 401181834Sroberto */ 402181834Sroberto 403181834Sroberto if (!handle) { 404181834Sroberto errno = EBADF; 405181834Sroberto return (-1); /* bad handle */ 406181834Sroberto } 407181834Sroberto 408181834Sroberto if (!ppsinfo) { 409181834Sroberto errno = EFAULT; 410181834Sroberto return (-1); /* bad argument */ 411181834Sroberto } 412181834Sroberto 413181834Sroberto /* 414181834Sroberto * nb. PPS_CANWAIT is NOT set by the implementation, we can totally 415181834Sroberto * ignore the timeout variable. 416181834Sroberto */ 417181834Sroberto 418181834Sroberto memset(&infobuf, 0, sizeof(infobuf)); 419181834Sroberto 420181834Sroberto /* 421181834Sroberto * if not captureassert, nothing to return. 422181834Sroberto */ 423181834Sroberto 424181834Sroberto if (!handle->params.mode & PPS_CAPTUREASSERT) { 425181834Sroberto memcpy(ppsinfo, &infobuf, sizeof(pps_info_t)); 426181834Sroberto return (0); 427181834Sroberto } 428181834Sroberto 429181834Sroberto#if defined(__STDC__) 430181834Sroberto#define CIOGETEV _IOR('C', 0, struct ppsclockev) /* get last pps event */ 431181834Sroberto#else 432181834Sroberto#define CIOGETEV _IOR(C, 0, struct ppsclockev) /* get last pps event */ 433181834Sroberto#endif 434181834Sroberto 435181834Sroberto if (ioctl(handle->filedes, CIOGETEV, (caddr_t) &ev) < 0) { 436181834Sroberto perror("time_pps_fetch:"); 437181834Sroberto errno = EOPNOTSUPP; 438181834Sroberto return(-1); 439181834Sroberto } 440181834Sroberto 441181834Sroberto /* 442181834Sroberto * Apply offsets as specified. Note that only assert timestamps 443181834Sroberto * are captured by this interface. 444181834Sroberto */ 445181834Sroberto 446181834Sroberto infobuf.assert_sequence = ev.serial; 447181834Sroberto infobuf.assert_timestamp.tv_sec = ev.tv.tv_sec; 448181834Sroberto infobuf.assert_timestamp.tv_nsec = ev.tv.tv_usec * 1000; 449181834Sroberto 450181834Sroberto if (handle->params.mode & PPS_OFFSETASSERT) { 451181834Sroberto infobuf.assert_timestamp.tv_sec += handle->params.assert_offset.tv_sec; 452181834Sroberto infobuf.assert_timestamp.tv_nsec += handle->params.assert_offset.tv_nsec; 453181834Sroberto PPS_NORMALIZE(infobuf.assert_timestamp); 454181834Sroberto } 455181834Sroberto 456181834Sroberto /* 457181834Sroberto * Translate to specified format 458181834Sroberto */ 459181834Sroberto 460181834Sroberto switch (tsformat) { 461181834Sroberto case PPS_TSFMT_TSPEC: 462181834Sroberto break; /* timespec format requires no translation */ 463181834Sroberto 464181834Sroberto case PPS_TSFMT_NTPFP: /* NTP format requires conversion to fraction form */ 465181834Sroberto PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp); 466181834Sroberto break; 467181834Sroberto 468181834Sroberto default: 469181834Sroberto errno = EINVAL; 470181834Sroberto return (-1); 471181834Sroberto } 472181834Sroberto 473181834Sroberto infobuf.current_mode = handle->params.mode; 474181834Sroberto memcpy(ppsinfo, &infobuf, sizeof(pps_info_t)); 475181834Sroberto return (0); 476181834Sroberto} 477181834Sroberto 478181834Sroberto/* 479181834Sroberto * specify kernel consumer 480181834Sroberto */ 481181834Sroberto 482181834Srobertostatic inline int 483181834Srobertotime_pps_kcbind( 484181834Sroberto pps_handle_t handle, 485181834Sroberto const int kernel_consumer, 486181834Sroberto const int edge, const int tsformat 487181834Sroberto ) 488181834Sroberto{ 489181834Sroberto /* 490181834Sroberto * Check for valid arguments and bind kernel consumer 491181834Sroberto */ 492181834Sroberto if (!handle) { 493181834Sroberto errno = EBADF; 494181834Sroberto return (-1); /* bad handle */ 495181834Sroberto } 496181834Sroberto if (geteuid() != 0) { 497181834Sroberto errno = EPERM; 498181834Sroberto return (-1); /* must be superuser */ 499181834Sroberto } 500181834Sroberto errno = EOPNOTSUPP; 501181834Sroberto return(-1); 502181834Sroberto} 503181834Sroberto 504181834Sroberto#endif /* _SYS_TIMEPPS_H_ */ 505