1 /* $NetBSD: timepps-SCO.h,v 1.4 2016/01/08 21:35:35 christos Exp $ */ 2 3 /*********************************************************************** 4 * * 5 * Copyright (c) David L. Mills 1999-2000 * 6 * * 7 * Permission to use, copy, modify, and distribute this software and * 8 * its documentation for any purpose and with or without fee is hereby * 9 * granted, provided that the above copyright notice appears in all * 10 * copies and that both the copyright notice and this permission * 11 * notice appear in supporting documentation, and that the name * 12 * University of Delaware not be used in advertising or publicity * 13 * pertaining to distribution of the software without specific, * 14 * written prior permission. The University of Delaware makes no * 15 * representations about the suitability this software for any * 16 * purpose. It is provided "as is" without express or implied * 17 * warranty. * 18 * * 19 *********************************************************************** 20 * * 21 * This header file complies with "Pulse-Per-Second API for UNIX-like * 22 * Operating Systems, Version 1.0", rfc2783. Credit is due Jeff Mogul * 23 * and Marc Brett, from whom much of this code was shamelessly stolen. * 24 * * 25 * this modified timepps.h can be used to provide a PPSAPI interface * 26 * to a machine running SCO Unix. * 27 * * 28 *********************************************************************** 29 * * 30 * A full PPSAPI interface to the SCO Unix kernel would be better, but * 31 * this at least removes the necessity for special coding from the NTP * 32 * NTP drivers. * 33 * * 34 *********************************************************************** 35 * * 36 * Some of this include file * 37 * Copyright (c) 1999 by Ulrich Windl, * 38 * based on code by Reg Clemens <reg@dwf.com> * 39 * based on code by Poul-Henning Kamp <phk@FreeBSD.org> * 40 * * 41 *********************************************************************** 42 * * 43 * "THE BEER-WARE LICENSE" (Revision 42): * 44 * <phk@FreeBSD.org> wrote this file. As long as you retain this * 45 * notice you can do whatever you want with this stuff. If we meet some* 46 * day, and you think this stuff is worth it, you can buy me a beer * 47 * in return. Poul-Henning Kamp * 48 * * 49 **********************************************************************/ 50 51 /*SCO UNIX version, TIOCDCDTIMESTAMP assumed to exist. */ 52 53 #ifndef _SYS_TIMEPPS_H_ 54 #define _SYS_TIMEPPS_H_ 55 56 #include <termios.h> /* to get TIOCDCDTIMESTAMP */ 57 58 /* Implementation note: the logical states ``assert'' and ``clear'' 59 * are implemented in terms of the UART register, i.e. ``assert'' 60 * means the bit is set. 61 */ 62 63 /* 64 * The following definitions are architecture independent 65 */ 66 67 #define PPS_API_VERS_1 1 /* API version number */ 68 #define PPS_JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ 69 #define PPS_NANOSECOND 1000000000L /* one nanosecond in decimal */ 70 #define PPS_FRAC 4294967296. /* 2^32 as a double */ 71 72 #define PPS_NORMALIZE(x) /* normalize timespec */ \ 73 do { \ 74 if ((x).tv_nsec >= PPS_NANOSECOND) { \ 75 (x).tv_nsec -= PPS_NANOSECOND; \ 76 (x).tv_sec++; \ 77 } else if ((x).tv_nsec < 0) { \ 78 (x).tv_nsec += PPS_NANOSECOND; \ 79 (x).tv_sec--; \ 80 } \ 81 } while (0) 82 83 #define PPS_TSPECTONTP(x) /* convert timespec to l_fp */ \ 84 do { \ 85 double d_temp; \ 86 \ 87 (x).integral += (unsigned int)PPS_JAN_1970; \ 88 d_temp = (x).fractional * PPS_FRAC / PPS_NANOSECOND; \ 89 if (d_temp >= PPS_FRAC) \ 90 (x).integral++; \ 91 (x).fractional = (unsigned int)d_temp; \ 92 } while (0) 93 94 /* 95 * Device/implementation parameters (mode) 96 */ 97 98 #define PPS_CAPTUREASSERT 0x01 /* capture assert events */ 99 #define PPS_CAPTURECLEAR 0x02 /* capture clear events */ 100 #define PPS_CAPTUREBOTH 0x03 /* capture assert and clear events */ 101 102 #define PPS_OFFSETASSERT 0x10 /* apply compensation for assert ev. */ 103 #define PPS_OFFSETCLEAR 0x20 /* apply compensation for clear ev. */ 104 #define PPS_OFFSETBOTH 0x30 /* apply compensation for both */ 105 106 #define PPS_CANWAIT 0x100 /* Can we wait for an event? */ 107 #define PPS_CANPOLL 0x200 /* "This bit is reserved for */ 108 109 /* 110 * Kernel actions (mode) 111 */ 112 113 #define PPS_ECHOASSERT 0x40 /* feed back assert event to output */ 114 #define PPS_ECHOCLEAR 0x80 /* feed back clear event to output */ 115 116 /* 117 * Timestamp formats (tsformat) 118 */ 119 120 #define PPS_TSFMT_TSPEC 0x1000 /* select timespec format */ 121 #define PPS_TSFMT_NTPFP 0x2000 /* select NTP format */ 122 123 /* 124 * Kernel discipline actions (not used in Solaris) 125 */ 126 127 #define PPS_KC_HARDPPS 0 /* enable kernel consumer */ 128 #define PPS_KC_HARDPPS_PLL 1 /* phase-lock mode */ 129 #define PPS_KC_HARDPPS_FLL 2 /* frequency-lock mode */ 130 131 /* 132 * Type definitions 133 */ 134 135 typedef unsigned long pps_seq_t; /* sequence number */ 136 137 typedef struct ntp_fp { 138 unsigned int integral; 139 unsigned int fractional; 140 } ntp_fp_t; /* NTP-compatible time stamp */ 141 142 typedef union pps_timeu { /* timestamp format */ 143 struct timespec tspec; 144 ntp_fp_t ntpfp; 145 unsigned long longpad[3]; 146 } pps_timeu_t; /* generic data type to represent time stamps */ 147 148 /* 149 * Timestamp information structure 150 */ 151 152 typedef struct pps_info { 153 pps_seq_t assert_sequence; /* seq. num. of assert event */ 154 pps_seq_t clear_sequence; /* seq. num. of clear event */ 155 pps_timeu_t assert_tu; /* time of assert event */ 156 pps_timeu_t clear_tu; /* time of clear event */ 157 int current_mode; /* current mode bits */ 158 } pps_info_t; 159 160 #define assert_timestamp assert_tu.tspec 161 #define clear_timestamp clear_tu.tspec 162 163 #define assert_timestamp_ntpfp assert_tu.ntpfp 164 #define clear_timestamp_ntpfp clear_tu.ntpfp 165 166 /* 167 * Parameter structure 168 */ 169 170 typedef struct pps_params { 171 int api_version; /* API version # */ 172 int mode; /* mode bits */ 173 pps_timeu_t assert_off_tu; /* offset compensation for assert */ 174 pps_timeu_t clear_off_tu; /* offset compensation for clear */ 175 } pps_params_t; 176 177 #define assert_offset assert_off_tu.tspec 178 #define clear_offset clear_off_tu.tspec 179 180 #define assert_offset_ntpfp assert_off_tu.ntpfp 181 #define clear_offset_ntpfp clear_off_tu.ntpfp 182 183 /* 184 * The following definitions are architecture-dependent 185 */ 186 187 #define PPS_CAP (PPS_CAPTUREASSERT | PPS_OFFSETASSERT | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP) 188 #define PPS_RO (PPS_CANWAIT | PPS_CANPOLL | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP) 189 190 typedef struct { 191 int filedes; /* file descriptor */ 192 pps_params_t params; /* PPS parameters set by user */ 193 struct timeval tv_save; 194 pps_seq_t serial; 195 } pps_unit_t; 196 197 typedef pps_unit_t* pps_handle_t; /* pps handlebars */ 198 199 /* 200 *------ Here begins the implementation-specific part! ------ 201 */ 202 203 #include <errno.h> 204 205 /* 206 * create PPS handle from file descriptor 207 */ 208 209 static inline int 210 time_pps_create( 211 int filedes, /* file descriptor */ 212 pps_handle_t *handle /* returned handle */ 213 ) 214 { 215 int one = 1; 216 217 /* 218 * Check for valid arguments and attach PPS signal. 219 */ 220 221 if (!handle) { 222 errno = EFAULT; 223 return (-1); /* null pointer */ 224 } 225 226 /* 227 * Allocate and initialize default unit structure. 228 */ 229 230 *handle = malloc(sizeof(pps_unit_t)); 231 if (!(*handle)) { 232 errno = EBADF; 233 return (-1); /* what, no memory? */ 234 } 235 236 memset(*handle, 0, sizeof(pps_unit_t)); 237 (*handle)->filedes = filedes; 238 (*handle)->params.api_version = PPS_API_VERS_1; 239 (*handle)->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC; 240 return (0); 241 } 242 243 /* 244 * release PPS handle 245 */ 246 247 static inline int 248 time_pps_destroy( 249 pps_handle_t handle 250 ) 251 { 252 /* 253 * Check for valid arguments and detach PPS signal. 254 */ 255 256 if (!handle) { 257 errno = EBADF; 258 return (-1); /* bad handle */ 259 } 260 free(handle); 261 return (0); 262 } 263 264 /* 265 * set parameters for handle 266 */ 267 268 static inline int 269 time_pps_setparams( 270 pps_handle_t handle, 271 const pps_params_t *params 272 ) 273 { 274 int mode, mode_in; 275 /* 276 * Check for valid arguments and set parameters. 277 */ 278 279 if (!handle) { 280 errno = EBADF; 281 return (-1); /* bad handle */ 282 } 283 284 if (!params) { 285 errno = EFAULT; 286 return (-1); /* bad argument */ 287 } 288 289 /* 290 * There was no reasonable consensu in the API working group. 291 * I require `api_version' to be set! 292 */ 293 294 if (params->api_version != PPS_API_VERS_1) { 295 errno = EINVAL; 296 return(-1); 297 } 298 299 /* 300 * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT 301 */ 302 303 mode_in = params->mode; 304 305 /* turn off read-only bits */ 306 307 mode_in &= ~PPS_RO; 308 309 /* test remaining bits, should only have captureassert and/or offsetassert */ 310 311 if (mode_in & ~(PPS_CAPTUREASSERT | PPS_OFFSETASSERT)) { 312 errno = EOPNOTSUPP; 313 return(-1); 314 } 315 316 /* 317 * ok, ready to go. 318 */ 319 320 mode = handle->params.mode; 321 memcpy(&handle->params, params, sizeof(pps_params_t)); 322 handle->params.api_version = PPS_API_VERS_1; 323 handle->params.mode = mode | mode_in; 324 return (0); 325 } 326 327 /* 328 * get parameters for handle 329 */ 330 331 static inline int 332 time_pps_getparams( 333 pps_handle_t handle, 334 pps_params_t *params 335 ) 336 { 337 /* 338 * Check for valid arguments and get parameters. 339 */ 340 341 if (!handle) { 342 errno = EBADF; 343 return (-1); /* bad handle */ 344 } 345 346 if (!params) { 347 errno = EFAULT; 348 return (-1); /* bad argument */ 349 } 350 351 memcpy(params, &handle->params, sizeof(pps_params_t)); 352 return (0); 353 } 354 355 /* ( 356 * get capabilities for handle 357 */ 358 359 static inline int 360 time_pps_getcap( 361 pps_handle_t handle, 362 int *mode 363 ) 364 { 365 /* 366 * Check for valid arguments and get capabilities. 367 */ 368 369 if (!handle) { 370 errno = EBADF; 371 return (-1); /* bad handle */ 372 } 373 374 if (!mode) { 375 errno = EFAULT; 376 return (-1); /* bad argument */ 377 } 378 *mode = PPS_CAP; 379 return (0); 380 } 381 382 /* 383 * Fetch timestamps 384 */ 385 386 static inline int 387 time_pps_fetch( 388 pps_handle_t handle, 389 const int tsformat, 390 pps_info_t *ppsinfo, 391 const struct timespec *timeout 392 ) 393 { 394 struct timeval tv; 395 pps_info_t infobuf; 396 397 /* 398 * Check for valid arguments and fetch timestamps 399 */ 400 401 if (!handle) { 402 errno = EBADF; 403 return (-1); /* bad handle */ 404 } 405 406 if (!ppsinfo) { 407 errno = EFAULT; 408 return (-1); /* bad argument */ 409 } 410 411 /* 412 * nb. PPS_CANWAIT is NOT set by the implementation, we can totally 413 * ignore the timeout variable. 414 */ 415 416 memset(&infobuf, 0, sizeof(infobuf)); 417 418 /* 419 * if not captureassert, nothing to return. 420 */ 421 422 if (!handle->params.mode & PPS_CAPTUREASSERT) { 423 memcpy(ppsinfo, &infobuf, sizeof(pps_info_t)); 424 return (0); 425 } 426 427 if (ioctl(instance->filedes, TIOCDCDTIMESTAMP, &tv) < 0) { 428 perror("time_pps_fetch:"); 429 errno = EOPNOTSUPP; 430 return(-1); 431 } 432 433 /* 434 * fake serial here 435 */ 436 437 if (tv.tv_sec != handle->tv_save.tv_sec || tv.tv_usec != handle->tv_save.tv_usec) { 438 handle->tv_save = tv; 439 handle->serial++; 440 } 441 442 /* 443 * Apply offsets as specified. Note that only assert timestamps 444 * are captured by this interface. 445 */ 446 447 infobuf.assert_sequence = handle->serial; 448 infobuf.assert_timestamp.tv_sec = tv.tv_sec; 449 infobuf.assert_timestamp.tv_nsec = tv.tv_usec * 1000; 450 451 if (handle->params.mode & PPS_OFFSETASSERT) { 452 infobuf.assert_timestamp.tv_sec += handle->params.assert_offset.tv_sec; 453 infobuf.assert_timestamp.tv_nsec += handle->params.assert_offset.tv_nsec; 454 PPS_NORMALIZE(infobuf.assert_timestamp); 455 } 456 457 /* 458 * Translate to specified format 459 */ 460 461 switch (tsformat) { 462 case PPS_TSFMT_TSPEC: 463 break; /* timespec format requires no translation */ 464 465 case PPS_TSFMT_NTPFP: /* NTP format requires conversion to fraction form */ 466 PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp); 467 break; 468 469 default: 470 errno = EINVAL; 471 return (-1); 472 } 473 474 infobuf.current_mode = handle->params.mode; 475 memcpy(ppsinfo, &infobuf, sizeof(pps_info_t)); 476 return (0); 477 } 478 479 /* 480 * specify kernel consumer 481 */ 482 483 static inline int 484 time_pps_kcbind( 485 pps_handle_t handle, 486 const int kernel_consumer, 487 const int edge, const int tsformat 488 ) 489 { 490 /* 491 * Check for valid arguments and bind kernel consumer 492 */ 493 if (!handle) { 494 errno = EBADF; 495 return (-1); /* bad handle */ 496 } 497 if (geteuid() != 0) { 498 errno = EPERM; 499 return (-1); /* must be superuser */ 500 } 501 errno = EOPNOTSUPP; 502 return(-1); 503 } 504 505 #endif /* _SYS_TIMEPPS_H_ */ 506