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