/contrib/ntp/include/timepps-SunOS.h

https://bitbucket.org/freebsd/freebsd-head/ · C++ Header · 504 lines · 260 code · 91 blank · 153 comment · 28 complexity · c1099b10ce5bf32581ef5d628a4c928d MD5 · raw file

  1. /***********************************************************************
  2. * *
  3. * Copyright (c) David L. Mills 1999-2000 *
  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 SunOS. *
  25. * *
  26. ***********************************************************************
  27. * *
  28. * A full PPSAPI interface to the SunOS 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. /* SunOS version, CIOGETEV assumed to exist for SunOS */
  49. #ifndef _SYS_TIMEPPS_H_
  50. #define _SYS_TIMEPPS_H_
  51. #include <termios.h> /* to get CIOGETEV */
  52. /* Implementation note: the logical states ``assert'' and ``clear''
  53. * are implemented in terms of the UART register, i.e. ``assert''
  54. * means the bit is set.
  55. */
  56. /*
  57. * The following definitions are architecture independent
  58. */
  59. #define PPS_API_VERS_1 1 /* API version number */
  60. #define PPS_JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
  61. #define PPS_NANOSECOND 1000000000L /* one nanosecond in decimal */
  62. #define PPS_FRAC 4294967296. /* 2^32 as a double */
  63. #define PPS_NORMALIZE(x) /* normalize timespec */ \
  64. do { \
  65. if ((x).tv_nsec >= PPS_NANOSECOND) { \
  66. (x).tv_nsec -= PPS_NANOSECOND; \
  67. (x).tv_sec++; \
  68. } else if ((x).tv_nsec < 0) { \
  69. (x).tv_nsec += PPS_NANOSECOND; \
  70. (x).tv_sec--; \
  71. } \
  72. } while (0)
  73. #define PPS_TSPECTONTP(x) /* convert timespec to l_fp */ \
  74. do { \
  75. double d_temp; \
  76. \
  77. (x).integral += (unsigned int)PPS_JAN_1970; \
  78. d_temp = (x).fractional * PPS_FRAC / PPS_NANOSECOND; \
  79. if (d_temp >= PPS_FRAC) \
  80. (x).integral++; \
  81. (x).fractional = (unsigned int)d_temp; \
  82. } while (0)
  83. /*
  84. * Device/implementation parameters (mode)
  85. */
  86. #define PPS_CAPTUREASSERT 0x01 /* capture assert events */
  87. #define PPS_CAPTURECLEAR 0x02 /* capture clear events */
  88. #define PPS_CAPTUREBOTH 0x03 /* capture assert and clear events */
  89. #define PPS_OFFSETASSERT 0x10 /* apply compensation for assert ev. */
  90. #define PPS_OFFSETCLEAR 0x20 /* apply compensation for clear ev. */
  91. #define PPS_OFFSETBOTH 0x30 /* apply compensation for both */
  92. #define PPS_CANWAIT 0x100 /* Can we wait for an event? */
  93. #define PPS_CANPOLL 0x200 /* "This bit is reserved for */
  94. /*
  95. * Kernel actions (mode)
  96. */
  97. #define PPS_ECHOASSERT 0x40 /* feed back assert event to output */
  98. #define PPS_ECHOCLEAR 0x80 /* feed back clear event to output */
  99. /*
  100. * Timestamp formats (tsformat)
  101. */
  102. #define PPS_TSFMT_TSPEC 0x1000 /* select timespec format */
  103. #define PPS_TSFMT_NTPFP 0x2000 /* select NTP format */
  104. /*
  105. * Kernel discipline actions (not used in SunOS)
  106. */
  107. #define PPS_KC_HARDPPS 0 /* enable kernel consumer */
  108. #define PPS_KC_HARDPPS_PLL 1 /* phase-lock mode */
  109. #define PPS_KC_HARDPPS_FLL 2 /* frequency-lock mode */
  110. /*
  111. * Type definitions
  112. */
  113. typedef unsigned long pps_seq_t; /* sequence number */
  114. typedef struct ntp_fp {
  115. unsigned int integral;
  116. unsigned int fractional;
  117. } ntp_fp_t; /* NTP-compatible time stamp */
  118. typedef union pps_timeu { /* timestamp format */
  119. struct timespec tspec;
  120. ntp_fp_t ntpfp;
  121. unsigned long longpad[3];
  122. } pps_timeu_t; /* generic data type to represent time stamps */
  123. /*
  124. * Timestamp information structure
  125. */
  126. typedef struct pps_info {
  127. pps_seq_t assert_sequence; /* seq. num. of assert event */
  128. pps_seq_t clear_sequence; /* seq. num. of clear event */
  129. pps_timeu_t assert_tu; /* time of assert event */
  130. pps_timeu_t clear_tu; /* time of clear event */
  131. int current_mode; /* current mode bits */
  132. } pps_info_t;
  133. #define assert_timestamp assert_tu.tspec
  134. #define clear_timestamp clear_tu.tspec
  135. #define assert_timestamp_ntpfp assert_tu.ntpfp
  136. #define clear_timestamp_ntpfp clear_tu.ntpfp
  137. /*
  138. * Parameter structure
  139. */
  140. typedef struct pps_params {
  141. int api_version; /* API version # */
  142. int mode; /* mode bits */
  143. pps_timeu_t assert_off_tu; /* offset compensation for assert */
  144. pps_timeu_t clear_off_tu; /* offset compensation for clear */
  145. } pps_params_t;
  146. #define assert_offset assert_off_tu.tspec
  147. #define clear_offset clear_off_tu.tspec
  148. #define assert_offset_ntpfp assert_off_tu.ntpfp
  149. #define clear_offset_ntpfp clear_off_tu.ntpfp
  150. /*
  151. * The following definitions are architecture-dependent
  152. */
  153. #define PPS_CAP (PPS_CAPTUREASSERT | PPS_OFFSETASSERT | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
  154. #define PPS_RO (PPS_CANWAIT | PPS_CANPOLL | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
  155. typedef struct {
  156. int filedes; /* file descriptor */
  157. pps_params_t params; /* PPS parameters set by user */
  158. } pps_unit_t;
  159. typedef pps_unit_t* pps_handle_t; /* pps handlebars */
  160. /*
  161. *------ Here begins the implementation-specific part! ------
  162. */
  163. #include <errno.h>
  164. /*
  165. * create PPS handle from file descriptor
  166. */
  167. static inline int
  168. time_pps_create(
  169. int filedes, /* file descriptor */
  170. pps_handle_t *handle /* returned handle */
  171. )
  172. {
  173. /*
  174. * Check for valid arguments and attach PPS signal.
  175. */
  176. if (!handle) {
  177. errno = EFAULT;
  178. return (-1); /* null pointer */
  179. }
  180. if (ioctl(filedes, I_PUSH, "ppsclock") < 0) {
  181. perror("time_pps_create: I_PUSH ppsclock failed");
  182. return (-1);
  183. }
  184. /*
  185. * Allocate and initialize default unit structure.
  186. */
  187. *handle = malloc(sizeof(pps_unit_t));
  188. if (!(*handle)) {
  189. errno = EBADF;
  190. return (-1); /* what, no memory? */
  191. }
  192. memset(*handle, 0, sizeof(pps_unit_t));
  193. (*handle)->filedes = filedes;
  194. (*handle)->params.api_version = PPS_API_VERS_1;
  195. (*handle)->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC;
  196. return (0);
  197. }
  198. /*
  199. * release PPS handle
  200. */
  201. static inline int
  202. time_pps_destroy(
  203. pps_handle_t handle
  204. )
  205. {
  206. /*
  207. * Check for valid arguments and detach PPS signal.
  208. */
  209. if (!handle) {
  210. errno = EBADF;
  211. return (-1); /* bad handle */
  212. }
  213. free(handle);
  214. return (0);
  215. }
  216. /*
  217. * set parameters for handle
  218. */
  219. static inline int
  220. time_pps_setparams(
  221. pps_handle_t handle,
  222. const pps_params_t *params
  223. )
  224. {
  225. int mode, mode_in;
  226. /*
  227. * Check for valid arguments and set parameters.
  228. */
  229. if (!handle) {
  230. errno = EBADF;
  231. return (-1); /* bad handle */
  232. }
  233. if (!params) {
  234. errno = EFAULT;
  235. return (-1); /* bad argument */
  236. }
  237. /*
  238. * There was no reasonable consensu in the API working group.
  239. * I require `api_version' to be set!
  240. */
  241. if (params->api_version != PPS_API_VERS_1) {
  242. errno = EINVAL;
  243. return(-1);
  244. }
  245. /*
  246. * only settable modes are PPS_CAPTUREASSERT and PPS_OFFSETASSERT
  247. */
  248. mode_in = params->mode;
  249. /* turn off read-only bits */
  250. mode_in &= ~PPS_RO;
  251. /* test remaining bits, should only have captureassert and/or offsetassert */
  252. if (mode_in & ~(PPS_CAPTUREASSERT | PPS_OFFSETASSERT)) {
  253. errno = EOPNOTSUPP;
  254. return(-1);
  255. }
  256. /*
  257. * ok, ready to go.
  258. */
  259. mode = handle->params.mode;
  260. memcpy(&handle->params, params, sizeof(pps_params_t));
  261. handle->params.api_version = PPS_API_VERS_1;
  262. handle->params.mode = mode | mode_in;
  263. return (0);
  264. }
  265. /*
  266. * get parameters for handle
  267. */
  268. static inline int
  269. time_pps_getparams(
  270. pps_handle_t handle,
  271. pps_params_t *params
  272. )
  273. {
  274. /*
  275. * Check for valid arguments and get parameters.
  276. */
  277. if (!handle) {
  278. errno = EBADF;
  279. return (-1); /* bad handle */
  280. }
  281. if (!params) {
  282. errno = EFAULT;
  283. return (-1); /* bad argument */
  284. }
  285. memcpy(params, &handle->params, sizeof(pps_params_t));
  286. return (0);
  287. }
  288. /* (
  289. * get capabilities for handle
  290. */
  291. static inline int
  292. time_pps_getcap(
  293. pps_handle_t handle,
  294. int *mode
  295. )
  296. {
  297. /*
  298. * Check for valid arguments and get capabilities.
  299. */
  300. if (!handle) {
  301. errno = EBADF;
  302. return (-1); /* bad handle */
  303. }
  304. if (!mode) {
  305. errno = EFAULT;
  306. return (-1); /* bad argument */
  307. }
  308. *mode = PPS_CAP;
  309. return (0);
  310. }
  311. /*
  312. * Fetch timestamps
  313. */
  314. static inline int
  315. time_pps_fetch(
  316. pps_handle_t handle,
  317. const int tsformat,
  318. pps_info_t *ppsinfo,
  319. const struct timespec *timeout
  320. )
  321. {
  322. struct ppsclockev {
  323. struct timeval tv;
  324. u_int serial;
  325. } ev;
  326. pps_info_t infobuf;
  327. /*
  328. * Check for valid arguments and fetch timestamps
  329. */
  330. if (!handle) {
  331. errno = EBADF;
  332. return (-1); /* bad handle */
  333. }
  334. if (!ppsinfo) {
  335. errno = EFAULT;
  336. return (-1); /* bad argument */
  337. }
  338. /*
  339. * nb. PPS_CANWAIT is NOT set by the implementation, we can totally
  340. * ignore the timeout variable.
  341. */
  342. memset(&infobuf, 0, sizeof(infobuf));
  343. /*
  344. * if not captureassert, nothing to return.
  345. */
  346. if (!handle->params.mode & PPS_CAPTUREASSERT) {
  347. memcpy(ppsinfo, &infobuf, sizeof(pps_info_t));
  348. return (0);
  349. }
  350. #if defined(__STDC__)
  351. #define CIOGETEV _IOR('C', 0, struct ppsclockev) /* get last pps event */
  352. #else
  353. #define CIOGETEV _IOR(C, 0, struct ppsclockev) /* get last pps event */
  354. #endif
  355. if (ioctl(handle->filedes, CIOGETEV, (caddr_t) &ev) < 0) {
  356. perror("time_pps_fetch:");
  357. errno = EOPNOTSUPP;
  358. return(-1);
  359. }
  360. /*
  361. * Apply offsets as specified. Note that only assert timestamps
  362. * are captured by this interface.
  363. */
  364. infobuf.assert_sequence = ev.serial;
  365. infobuf.assert_timestamp.tv_sec = ev.tv.tv_sec;
  366. infobuf.assert_timestamp.tv_nsec = ev.tv.tv_usec * 1000;
  367. if (handle->params.mode & PPS_OFFSETASSERT) {
  368. infobuf.assert_timestamp.tv_sec += handle->params.assert_offset.tv_sec;
  369. infobuf.assert_timestamp.tv_nsec += handle->params.assert_offset.tv_nsec;
  370. PPS_NORMALIZE(infobuf.assert_timestamp);
  371. }
  372. /*
  373. * Translate to specified format
  374. */
  375. switch (tsformat) {
  376. case PPS_TSFMT_TSPEC:
  377. break; /* timespec format requires no translation */
  378. case PPS_TSFMT_NTPFP: /* NTP format requires conversion to fraction form */
  379. PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp);
  380. break;
  381. default:
  382. errno = EINVAL;
  383. return (-1);
  384. }
  385. infobuf.current_mode = handle->params.mode;
  386. memcpy(ppsinfo, &infobuf, sizeof(pps_info_t));
  387. return (0);
  388. }
  389. /*
  390. * specify kernel consumer
  391. */
  392. static inline int
  393. time_pps_kcbind(
  394. pps_handle_t handle,
  395. const int kernel_consumer,
  396. const int edge, const int tsformat
  397. )
  398. {
  399. /*
  400. * Check for valid arguments and bind kernel consumer
  401. */
  402. if (!handle) {
  403. errno = EBADF;
  404. return (-1); /* bad handle */
  405. }
  406. if (geteuid() != 0) {
  407. errno = EPERM;
  408. return (-1); /* must be superuser */
  409. }
  410. errno = EOPNOTSUPP;
  411. return(-1);
  412. }
  413. #endif /* _SYS_TIMEPPS_H_ */