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