1139825Simp/*-
236739Sphk * ----------------------------------------------------------------------------
336739Sphk * "THE BEER-WARE LICENSE" (Revision 42):
436739Sphk * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
536739Sphk * can do whatever you want with this stuff. If we meet some day, and you think
636739Sphk * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
736739Sphk * ----------------------------------------------------------------------------
836739Sphk *
9227789Slstewart * Copyright (c) 2011 The FreeBSD Foundation
10227789Slstewart * All rights reserved.
11227789Slstewart *
12227789Slstewart * Portions of this software were developed by Julien Ridoux at the University
13227789Slstewart * of Melbourne under sponsorship from the FreeBSD Foundation.
14227789Slstewart *
1550477Speter * $FreeBSD$
1636739Sphk *
17122967Sphk * The is a FreeBSD version of the RFC 2783 API for Pulse Per Second
18122967Sphk * timing interfaces.
1936739Sphk */
2036739Sphk
2136739Sphk#ifndef _SYS_TIMEPPS_H_
2236739Sphk#define _SYS_TIMEPPS_H_
2336739Sphk
24227789Slstewart#include <sys/_ffcounter.h>
2536739Sphk#include <sys/ioccom.h>
2695817Sphk#include <sys/time.h>
2736739Sphk
2852061Sjhay#define PPS_API_VERS_1	1
2952061Sjhay
3036739Sphktypedef int pps_handle_t;
3136739Sphk
3236739Sphktypedef unsigned pps_seq_t;
3336739Sphk
3436938Sphktypedef struct ntp_fp {
3536938Sphk	unsigned int	integral;
3636938Sphk	unsigned int	fractional;
3736938Sphk} ntp_fp_t;
3836938Sphk
3936938Sphktypedef union pps_timeu {
4036938Sphk	struct timespec	tspec;
4136938Sphk	ntp_fp_t	ntpfp;
4252061Sjhay	unsigned long	longpad[3];
4336938Sphk} pps_timeu_t;
4436938Sphk
4536739Sphktypedef struct {
4636938Sphk	pps_seq_t	assert_sequence;	/* assert event seq # */
4736938Sphk	pps_seq_t	clear_sequence;		/* clear event seq # */
4836938Sphk	pps_timeu_t	assert_tu;
4936938Sphk	pps_timeu_t	clear_tu;
5036938Sphk	int		current_mode;		/* current mode bits */
5136739Sphk} pps_info_t;
5236739Sphk
53227789Slstewarttypedef struct {
54227789Slstewart	pps_seq_t	assert_sequence;	/* assert event seq # */
55227789Slstewart	pps_seq_t	clear_sequence;		/* clear event seq # */
56227789Slstewart	pps_timeu_t	assert_tu;
57227789Slstewart	pps_timeu_t	clear_tu;
58227789Slstewart	ffcounter	assert_ffcount;		/* ffcounter on assert event */
59227789Slstewart	ffcounter	clear_ffcount;		/* ffcounter on clear event */
60227789Slstewart	int		current_mode;		/* current mode bits */
61227789Slstewart} pps_info_ffc_t;
62227789Slstewart
6336938Sphk#define assert_timestamp        assert_tu.tspec
6436938Sphk#define clear_timestamp         clear_tu.tspec
6536938Sphk
6636938Sphk#define assert_timestamp_ntpfp  assert_tu.ntpfp
6736938Sphk#define clear_timestamp_ntpfp   clear_tu.ntpfp
6836938Sphk
6936739Sphktypedef struct {
7052061Sjhay	int api_version;			/* API version # */
7136938Sphk	int mode;				/* mode bits */
7236938Sphk	pps_timeu_t assert_off_tu;
7336938Sphk	pps_timeu_t clear_off_tu;
7436739Sphk} pps_params_t;
7536739Sphk
7636938Sphk#define assert_offset   assert_off_tu.tspec
7736938Sphk#define clear_offset    clear_off_tu.tspec
7836938Sphk
7936938Sphk#define assert_offset_ntpfp     assert_off_tu.ntpfp
8036938Sphk#define clear_offset_ntpfp      clear_off_tu.ntpfp
8136938Sphk
8236938Sphk
8336739Sphk#define PPS_CAPTUREASSERT	0x01
8437110Sphk#define PPS_CAPTURECLEAR	0x02
8536739Sphk#define PPS_CAPTUREBOTH		0x03
8636739Sphk
8736938Sphk#define PPS_OFFSETASSERT	0x10
8836938Sphk#define PPS_OFFSETCLEAR		0x20
8936938Sphk
9036739Sphk#define PPS_ECHOASSERT		0x40
9136739Sphk#define PPS_ECHOCLEAR		0x80
9236739Sphk
9336739Sphk#define PPS_CANWAIT		0x100
9452061Sjhay#define PPS_CANPOLL		0x200
9536739Sphk
9636938Sphk#define PPS_TSFMT_TSPEC		0x1000
9736938Sphk#define PPS_TSFMT_NTPFP		0x2000
9836938Sphk
99227789Slstewart#define	PPS_TSCLK_FBCK		0x10000
100227789Slstewart#define	PPS_TSCLK_FFWD		0x20000
101227789Slstewart#define	PPS_TSCLK_MASK		0x30000
102227789Slstewart
10352061Sjhay#define PPS_KC_HARDPPS		0
10452061Sjhay#define PPS_KC_HARDPPS_PLL	1
10552061Sjhay#define PPS_KC_HARDPPS_FLL	2
10652061Sjhay
10752061Sjhaystruct pps_fetch_args {
10852061Sjhay	int tsformat;
10952061Sjhay	pps_info_t	pps_info_buf;
11036739Sphk	struct timespec	timeout;
11136739Sphk};
11236739Sphk
113227789Slstewartstruct pps_fetch_ffc_args {
114227789Slstewart	int		tsformat;
115227789Slstewart	pps_info_ffc_t	pps_info_buf_ffc;
116227789Slstewart	struct timespec	timeout;
117227789Slstewart};
118227789Slstewart
11952061Sjhaystruct pps_kcbind_args {
12052061Sjhay	int kernel_consumer;
12152061Sjhay	int edge;
12252061Sjhay	int tsformat;
12352061Sjhay};
12452061Sjhay
12536739Sphk#define PPS_IOC_CREATE		_IO('1', 1)
12636739Sphk#define PPS_IOC_DESTROY		_IO('1', 2)
12736739Sphk#define PPS_IOC_SETPARAMS	_IOW('1', 3, pps_params_t)
12836739Sphk#define PPS_IOC_GETPARAMS	_IOR('1', 4, pps_params_t)
12936739Sphk#define PPS_IOC_GETCAP		_IOR('1', 5, int)
13052061Sjhay#define PPS_IOC_FETCH		_IOWR('1', 6, struct pps_fetch_args)
13152061Sjhay#define PPS_IOC_KCBIND		_IOW('1', 7, struct pps_kcbind_args)
132227789Slstewart#define	PPS_IOC_FETCH_FFCOUNTER	_IOWR('1', 8, struct pps_fetch_ffc_args)
13336739Sphk
13455205Speter#ifdef _KERNEL
13595817Sphk
136283341Sianstruct mtx;
137283341Sian
138283341Sian#define	KCMODE_EDGEMASK		0x03
139283341Sian#define	KCMODE_ABIFLAG		0x80000000 /* Internal use: abi-aware driver. */
140283341Sian
141283341Sian#define	PPS_ABI_VERSION		1
142283341Sian
143283341Sian#define	PPSFLAG_MTX_SPIN	0x01	/* Driver mtx is MTX_SPIN type. */
144283341Sian
14544666Sphkstruct pps_state {
14695817Sphk	/* Capture information. */
14795817Sphk	struct timehands *capth;
148227789Slstewart	struct fftimehands *capffth;
14995817Sphk	unsigned	capgen;
15095817Sphk	unsigned	capcount;
15195817Sphk
15295817Sphk	/* State information. */
15395817Sphk	pps_params_t	ppsparam;
15495817Sphk	pps_info_t	ppsinfo;
155227789Slstewart	pps_info_ffc_t	ppsinfo_ffc;
15695817Sphk	int		kcmode;
15795817Sphk	int		ppscap;
15895817Sphk	struct timecounter *ppstc;
15995817Sphk	unsigned	ppscount[3];
160283341Sian	/*
161283341Sian	 * The following fields are valid if the driver calls pps_init_abi().
162283341Sian	 */
163283341Sian	uint16_t	driver_abi;	/* Driver sets before pps_init_abi(). */
164283341Sian	uint16_t	kernel_abi;	/* Kernel sets during pps_init_abi(). */
165283341Sian	struct mtx	*driver_mtx;	/* Optional, valid if non-NULL. */
166283341Sian	uint32_t	flags;
16744666Sphk};
16836941Sphk
16995523Sphkvoid pps_capture(struct pps_state *pps);
17095523Sphkvoid pps_event(struct pps_state *pps, int event);
17192719Salfredvoid pps_init(struct pps_state *pps);
172283341Sianvoid pps_init_abi(struct pps_state *pps);
17395817Sphkint pps_ioctl(unsigned long cmd, caddr_t data, struct pps_state *pps);
17492719Salfredvoid hardpps(struct timespec *tsp, long nsec);
17544666Sphk
17655205Speter#else /* !_KERNEL */
17744666Sphk
17844666Sphkstatic __inline int
17944666Sphktime_pps_create(int filedes, pps_handle_t *handle)
18044666Sphk{
18144666Sphk	int error;
18244666Sphk
18344666Sphk	*handle = -1;
18444666Sphk	error = ioctl(filedes, PPS_IOC_CREATE, 0);
18544666Sphk	if (error < 0)
18644666Sphk		return (-1);
18744666Sphk	*handle = filedes;
18844666Sphk	return (0);
18944666Sphk}
19044666Sphk
19144666Sphkstatic __inline int
19244666Sphktime_pps_destroy(pps_handle_t handle)
19344666Sphk{
19444666Sphk	return (ioctl(handle, PPS_IOC_DESTROY, 0));
19544666Sphk}
19644666Sphk
19744666Sphkstatic __inline int
19844666Sphktime_pps_setparams(pps_handle_t handle, const pps_params_t *ppsparams)
19944666Sphk{
20044666Sphk	return (ioctl(handle, PPS_IOC_SETPARAMS, ppsparams));
20144666Sphk}
20244666Sphk
20344666Sphkstatic __inline int
20444666Sphktime_pps_getparams(pps_handle_t handle, pps_params_t *ppsparams)
20544666Sphk{
20644666Sphk	return (ioctl(handle, PPS_IOC_GETPARAMS, ppsparams));
20744666Sphk}
20844666Sphk
20944666Sphkstatic __inline int
21044666Sphktime_pps_getcap(pps_handle_t handle, int *mode)
21144666Sphk{
21244666Sphk	return (ioctl(handle, PPS_IOC_GETCAP, mode));
21344666Sphk}
21444666Sphk
21544666Sphkstatic __inline int
21652061Sjhaytime_pps_fetch(pps_handle_t handle, const int tsformat,
21752061Sjhay	pps_info_t *ppsinfobuf, const struct timespec *timeout)
21844666Sphk{
21952061Sjhay	int error;
22052061Sjhay	struct pps_fetch_args arg;
22152061Sjhay
22252061Sjhay	arg.tsformat = tsformat;
22352061Sjhay	if (timeout == NULL) {
22452061Sjhay		arg.timeout.tv_sec = -1;
22552061Sjhay		arg.timeout.tv_nsec = -1;
22652061Sjhay	} else
22752061Sjhay		arg.timeout = *timeout;
22852061Sjhay	error = ioctl(handle, PPS_IOC_FETCH, &arg);
22952061Sjhay	*ppsinfobuf = arg.pps_info_buf;
23052061Sjhay	return (error);
23144666Sphk}
23244666Sphk
23344666Sphkstatic __inline int
234227789Slstewarttime_pps_fetch_ffc(pps_handle_t handle, const int tsformat,
235227789Slstewart	pps_info_ffc_t *ppsinfobuf, const struct timespec *timeout)
236227789Slstewart{
237227789Slstewart	struct pps_fetch_ffc_args arg;
238227789Slstewart	int error;
239227789Slstewart
240227789Slstewart	arg.tsformat = tsformat;
241227789Slstewart	if (timeout == NULL) {
242227789Slstewart		arg.timeout.tv_sec = -1;
243227789Slstewart		arg.timeout.tv_nsec = -1;
244227789Slstewart	} else {
245227789Slstewart		arg.timeout = *timeout;
246227789Slstewart	}
247227789Slstewart	error = ioctl(handle, PPS_IOC_FETCH_FFCOUNTER, &arg);
248227789Slstewart	*ppsinfobuf = arg.pps_info_buf_ffc;
249227789Slstewart	return (error);
250227789Slstewart}
251227789Slstewart
252227789Slstewartstatic __inline int
25352061Sjhaytime_pps_kcbind(pps_handle_t handle, const int kernel_consumer,
25452061Sjhay	const int edge, const int tsformat)
25544666Sphk{
25652061Sjhay	struct pps_kcbind_args arg;
25744666Sphk
25852061Sjhay	arg.kernel_consumer = kernel_consumer;
25952061Sjhay	arg.edge = edge;
26052061Sjhay	arg.tsformat = tsformat;
26152061Sjhay	return (ioctl(handle, PPS_IOC_KCBIND, &arg));
26244666Sphk}
26344666Sphk
26495817Sphk#endif /* KERNEL */
26595817Sphk
26695817Sphk#endif /* !_SYS_TIMEPPS_H_ */
267