xref: /freebsd/sys/dev/ppbus/pps.c (revision 20240fa3ad284d37c77b569550834ff75be7e589)
1507e2e44SPoul-Henning Kamp /*
2507e2e44SPoul-Henning Kamp  * ----------------------------------------------------------------------------
3507e2e44SPoul-Henning Kamp  * "THE BEER-WARE LICENSE" (Revision 42):
4507e2e44SPoul-Henning Kamp  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5507e2e44SPoul-Henning Kamp  * can do whatever you want with this stuff. If we meet some day, and you think
6507e2e44SPoul-Henning Kamp  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7507e2e44SPoul-Henning Kamp  * ----------------------------------------------------------------------------
8507e2e44SPoul-Henning Kamp  *
920240fa3SNicolas Souchu  * $Id: pps.c,v 1.12 1998/12/07 21:58:16 archie Exp $
10389825d5SPoul-Henning Kamp  *
11389825d5SPoul-Henning Kamp  * This driver implements a draft-mogul-pps-api-02.txt PPS source.
12389825d5SPoul-Henning Kamp  *
13389825d5SPoul-Henning Kamp  * The input pin is pin#10
14389825d5SPoul-Henning Kamp  * The echo output pin is pin#14
15507e2e44SPoul-Henning Kamp  *
16507e2e44SPoul-Henning Kamp  */
17507e2e44SPoul-Henning Kamp 
1895f0f58cSPoul-Henning Kamp #include "opt_devfs.h"
1920240fa3SNicolas Souchu #include "opt_ntp.h"
2095f0f58cSPoul-Henning Kamp 
21507e2e44SPoul-Henning Kamp #include <sys/param.h>
22507e2e44SPoul-Henning Kamp #include <sys/kernel.h>
23507e2e44SPoul-Henning Kamp #include <sys/systm.h>
24507e2e44SPoul-Henning Kamp #include <sys/conf.h>
258afeddf0SPoul-Henning Kamp #include <sys/timepps.h>
26507e2e44SPoul-Henning Kamp #ifdef DEVFS
27507e2e44SPoul-Henning Kamp #include <sys/devfsext.h>
2895f0f58cSPoul-Henning Kamp #endif
29507e2e44SPoul-Henning Kamp #include <sys/malloc.h>
30507e2e44SPoul-Henning Kamp 
31507e2e44SPoul-Henning Kamp #include <dev/ppbus/ppbconf.h>
32cc732491SPoul-Henning Kamp #include "pps.h"
33507e2e44SPoul-Henning Kamp 
348afeddf0SPoul-Henning Kamp #define PPS_NAME	"lppps"		/* our official name */
35507e2e44SPoul-Henning Kamp 
3695f0f58cSPoul-Henning Kamp static struct pps_data {
3795f0f58cSPoul-Henning Kamp 	int	pps_unit;
3895f0f58cSPoul-Henning Kamp 	struct	ppb_device pps_dev;
398afeddf0SPoul-Henning Kamp 	pps_params_t	ppsparam;
408afeddf0SPoul-Henning Kamp 	pps_info_t	ppsinfo;
41cc732491SPoul-Henning Kamp } *softc[NPPS];
42507e2e44SPoul-Henning Kamp 
438afeddf0SPoul-Henning Kamp static int ppscap =
448afeddf0SPoul-Henning Kamp 	PPS_CAPTUREASSERT |
45399144d9SPoul-Henning Kamp #ifdef PPS_SYNC
468afeddf0SPoul-Henning Kamp 	PPS_HARDPPSONASSERT |
47399144d9SPoul-Henning Kamp #endif /* PPS_SYNC */
488afeddf0SPoul-Henning Kamp 	PPS_OFFSETASSERT |
49389825d5SPoul-Henning Kamp 	PPS_ECHOASSERT |
50389825d5SPoul-Henning Kamp 	PPS_TSFMT_TSPEC;
518afeddf0SPoul-Henning Kamp 
5295f0f58cSPoul-Henning Kamp static int npps;
53507e2e44SPoul-Henning Kamp 
54507e2e44SPoul-Henning Kamp /*
55507e2e44SPoul-Henning Kamp  * Make ourselves visible as a ppbus driver
56507e2e44SPoul-Henning Kamp  */
57507e2e44SPoul-Henning Kamp 
5895f0f58cSPoul-Henning Kamp static struct ppb_device	*ppsprobe(struct ppb_data *ppb);
5995f0f58cSPoul-Henning Kamp static int			ppsattach(struct ppb_device *dev);
6095f0f58cSPoul-Henning Kamp static void			ppsintr(int unit);
6195f0f58cSPoul-Henning Kamp static void			pps_drvinit(void *unused);
62507e2e44SPoul-Henning Kamp 
6395f0f58cSPoul-Henning Kamp static struct ppb_driver ppsdriver = {
6495f0f58cSPoul-Henning Kamp     ppsprobe, ppsattach, PPS_NAME
65507e2e44SPoul-Henning Kamp };
66507e2e44SPoul-Henning Kamp 
6795f0f58cSPoul-Henning Kamp DATA_SET(ppbdriver_set, ppsdriver);
68507e2e44SPoul-Henning Kamp 
6995f0f58cSPoul-Henning Kamp static	d_open_t	ppsopen;
7095f0f58cSPoul-Henning Kamp static	d_close_t	ppsclose;
718afeddf0SPoul-Henning Kamp static	d_ioctl_t	ppsioctl;
72507e2e44SPoul-Henning Kamp 
73507e2e44SPoul-Henning Kamp #define CDEV_MAJOR 89
7495f0f58cSPoul-Henning Kamp static struct cdevsw pps_cdevsw =
758afeddf0SPoul-Henning Kamp 	{ ppsopen,	ppsclose,	noread,		nowrite,
768afeddf0SPoul-Henning Kamp 	  ppsioctl,	nullstop,	nullreset,	nodevtotty,
77cc732491SPoul-Henning Kamp 	  seltrue,	nommap,		nostrat,	PPS_NAME,
78507e2e44SPoul-Henning Kamp 	  NULL,		-1 };
79507e2e44SPoul-Henning Kamp 
80507e2e44SPoul-Henning Kamp static struct ppb_device *
8195f0f58cSPoul-Henning Kamp ppsprobe(struct ppb_data *ppb)
82507e2e44SPoul-Henning Kamp {
8395f0f58cSPoul-Henning Kamp 	struct pps_data *sc;
84507e2e44SPoul-Henning Kamp 
8595f0f58cSPoul-Henning Kamp 	sc = (struct pps_data *) malloc(sizeof(struct pps_data),
86507e2e44SPoul-Henning Kamp 							M_TEMP, M_NOWAIT);
87507e2e44SPoul-Henning Kamp 	if (!sc) {
88cc732491SPoul-Henning Kamp 		printf(PPS_NAME ": cannot malloc!\n");
89507e2e44SPoul-Henning Kamp 		return (0);
90507e2e44SPoul-Henning Kamp 	}
9195f0f58cSPoul-Henning Kamp 	bzero(sc, sizeof(struct pps_data));
92507e2e44SPoul-Henning Kamp 
9395f0f58cSPoul-Henning Kamp 	softc[npps] = sc;
94507e2e44SPoul-Henning Kamp 
9595f0f58cSPoul-Henning Kamp 	sc->pps_unit = npps++;
96507e2e44SPoul-Henning Kamp 
9795f0f58cSPoul-Henning Kamp 	sc->pps_dev.id_unit = sc->pps_unit;
9895f0f58cSPoul-Henning Kamp 	sc->pps_dev.ppb = ppb;
9946f3ff79SMike Smith 	sc->pps_dev.name = ppsdriver.name;
10095f0f58cSPoul-Henning Kamp 	sc->pps_dev.intr = ppsintr;
101507e2e44SPoul-Henning Kamp 
10295f0f58cSPoul-Henning Kamp 	return (&sc->pps_dev);
103507e2e44SPoul-Henning Kamp }
104507e2e44SPoul-Henning Kamp 
105507e2e44SPoul-Henning Kamp static int
10695f0f58cSPoul-Henning Kamp ppsattach(struct ppb_device *dev)
107507e2e44SPoul-Henning Kamp {
108507e2e44SPoul-Henning Kamp 	/*
109507e2e44SPoul-Henning Kamp 	 * Report ourselves
110507e2e44SPoul-Henning Kamp 	 */
111cc732491SPoul-Henning Kamp 	printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n",
112507e2e44SPoul-Henning Kamp 	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
113507e2e44SPoul-Henning Kamp 
114507e2e44SPoul-Henning Kamp #ifdef DEVFS
11595f0f58cSPoul-Henning Kamp 	devfs_add_devswf(&pps_cdevsw,
116507e2e44SPoul-Henning Kamp 		dev->id_unit, DV_CHR,
117cc732491SPoul-Henning Kamp 		UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit);
118507e2e44SPoul-Henning Kamp #endif
119507e2e44SPoul-Henning Kamp 
120507e2e44SPoul-Henning Kamp 	return (1);
121507e2e44SPoul-Henning Kamp }
122507e2e44SPoul-Henning Kamp 
123507e2e44SPoul-Henning Kamp static	int
12495f0f58cSPoul-Henning Kamp ppsopen(dev_t dev, int flags, int fmt, struct proc *p)
125507e2e44SPoul-Henning Kamp {
12695f0f58cSPoul-Henning Kamp 	struct pps_data *sc;
127507e2e44SPoul-Henning Kamp 	u_int unit = minor(dev);
128507e2e44SPoul-Henning Kamp 
12995f0f58cSPoul-Henning Kamp 	if ((unit >= npps))
130507e2e44SPoul-Henning Kamp 		return (ENXIO);
131507e2e44SPoul-Henning Kamp 
132507e2e44SPoul-Henning Kamp 	sc = softc[unit];
133507e2e44SPoul-Henning Kamp 
13495f0f58cSPoul-Henning Kamp 	if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
135507e2e44SPoul-Henning Kamp 		return (EINTR);
136507e2e44SPoul-Henning Kamp 
13720240fa3SNicolas Souchu 	ppb_wctr(&sc->pps_dev, 0);
1388afeddf0SPoul-Henning Kamp 	ppb_wctr(&sc->pps_dev, IRQENABLE);
139507e2e44SPoul-Henning Kamp 
140507e2e44SPoul-Henning Kamp 	return(0);
141507e2e44SPoul-Henning Kamp }
142507e2e44SPoul-Henning Kamp 
143507e2e44SPoul-Henning Kamp static	int
14495f0f58cSPoul-Henning Kamp ppsclose(dev_t dev, int flags, int fmt, struct proc *p)
145507e2e44SPoul-Henning Kamp {
14695f0f58cSPoul-Henning Kamp 	struct pps_data *sc = softc[minor(dev)];
147507e2e44SPoul-Henning Kamp 
1488afeddf0SPoul-Henning Kamp 	sc->ppsparam.mode = 0;
14920240fa3SNicolas Souchu 
15020240fa3SNicolas Souchu 	ppb_wdtr(&sc->pps_dev, 0);
15120240fa3SNicolas Souchu 	ppb_wctr(&sc->pps_dev, 0);
15220240fa3SNicolas Souchu 
15395f0f58cSPoul-Henning Kamp 	ppb_release_bus(&sc->pps_dev);
154507e2e44SPoul-Henning Kamp 	return(0);
155507e2e44SPoul-Henning Kamp }
156507e2e44SPoul-Henning Kamp 
157507e2e44SPoul-Henning Kamp static void
15895f0f58cSPoul-Henning Kamp ppsintr(int unit)
159507e2e44SPoul-Henning Kamp {
16095f0f58cSPoul-Henning Kamp 	struct pps_data *sc = softc[unit];
161507e2e44SPoul-Henning Kamp 	struct timespec tc;
162507e2e44SPoul-Henning Kamp 
163507e2e44SPoul-Henning Kamp 	nanotime(&tc);
16495f0f58cSPoul-Henning Kamp 	if (!(ppb_rstr(&sc->pps_dev) & nACK))
165507e2e44SPoul-Henning Kamp 		return;
1668afeddf0SPoul-Henning Kamp 	if (sc->ppsparam.mode & PPS_ECHOASSERT)
1678afeddf0SPoul-Henning Kamp 		ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED);
168389825d5SPoul-Henning Kamp 	if (sc->ppsparam.mode & PPS_OFFSETASSERT) {
1698afeddf0SPoul-Henning Kamp 		timespecadd(&tc, &sc->ppsparam.assert_offset);
1708afeddf0SPoul-Henning Kamp 		if (tc.tv_nsec < 0) {
171507e2e44SPoul-Henning Kamp 			tc.tv_sec--;
172507e2e44SPoul-Henning Kamp 			tc.tv_nsec += 1000000000;
173507e2e44SPoul-Henning Kamp 		}
174389825d5SPoul-Henning Kamp 	}
1758afeddf0SPoul-Henning Kamp 	sc->ppsinfo.assert_timestamp = tc;
1768afeddf0SPoul-Henning Kamp 	sc->ppsinfo.assert_sequence++;
177399144d9SPoul-Henning Kamp #ifdef PPS_SYNC
1788afeddf0SPoul-Henning Kamp 	if (sc->ppsparam.mode & PPS_HARDPPSONASSERT) {
179f1d19042SArchie Cobbs 		struct timeval tv;
180f1d19042SArchie Cobbs 
181507e2e44SPoul-Henning Kamp 		tv.tv_sec = tc.tv_sec;
182507e2e44SPoul-Henning Kamp 		tv.tv_usec = tc.tv_nsec / 1000;
183507e2e44SPoul-Henning Kamp 		hardpps(&tv, tv.tv_usec);
1848afeddf0SPoul-Henning Kamp 	}
185399144d9SPoul-Henning Kamp #endif /* PPS_SYNC */
1868afeddf0SPoul-Henning Kamp 	if (sc->ppsparam.mode & PPS_ECHOASSERT)
1878afeddf0SPoul-Henning Kamp 		ppb_wctr(&sc->pps_dev, IRQENABLE);
188507e2e44SPoul-Henning Kamp }
189507e2e44SPoul-Henning Kamp 
190507e2e44SPoul-Henning Kamp static int
191ceeea6b9SBruce Evans ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
192507e2e44SPoul-Henning Kamp {
19395f0f58cSPoul-Henning Kamp 	struct pps_data *sc = softc[minor(dev)];
194507e2e44SPoul-Henning Kamp 
195938ee3ceSPoul-Henning Kamp 	return (std_pps_ioctl(cmd, data, &sc->ppsparam, &sc->ppsinfo, ppscap));
1968afeddf0SPoul-Henning Kamp }
197507e2e44SPoul-Henning Kamp 
19895f0f58cSPoul-Henning Kamp static pps_devsw_installed = 0;
199507e2e44SPoul-Henning Kamp 
200507e2e44SPoul-Henning Kamp static void
20195f0f58cSPoul-Henning Kamp pps_drvinit(void *unused)
202507e2e44SPoul-Henning Kamp {
203507e2e44SPoul-Henning Kamp 	dev_t dev;
204507e2e44SPoul-Henning Kamp 
20595f0f58cSPoul-Henning Kamp 	if( ! pps_devsw_installed ) {
206507e2e44SPoul-Henning Kamp 		dev = makedev(CDEV_MAJOR, 0);
20795f0f58cSPoul-Henning Kamp 		cdevsw_add(&dev, &pps_cdevsw, NULL);
20895f0f58cSPoul-Henning Kamp 		pps_devsw_installed = 1;
209507e2e44SPoul-Henning Kamp     	}
210507e2e44SPoul-Henning Kamp }
211507e2e44SPoul-Henning Kamp 
21295f0f58cSPoul-Henning Kamp SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL)
213