xref: /freebsd/sys/dev/ppbus/pps.c (revision 1a03ce6c6310315885f9a2da485dae956ae22146)
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  *
91a03ce6cSPoul-Henning Kamp  * $Id: pps.c,v 1.19 1999/05/31 11:25:00 phk 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 
18507e2e44SPoul-Henning Kamp #include <sys/param.h>
19507e2e44SPoul-Henning Kamp #include <sys/kernel.h>
20507e2e44SPoul-Henning Kamp #include <sys/systm.h>
21507e2e44SPoul-Henning Kamp #include <sys/conf.h>
228afeddf0SPoul-Henning Kamp #include <sys/timepps.h>
23507e2e44SPoul-Henning Kamp #include <sys/malloc.h>
24507e2e44SPoul-Henning Kamp 
25507e2e44SPoul-Henning Kamp #include <dev/ppbus/ppbconf.h>
26cc732491SPoul-Henning Kamp #include "pps.h"
27507e2e44SPoul-Henning Kamp 
281a03ce6cSPoul-Henning Kamp #define PPS_NAME	"pps"		/* our official name */
29507e2e44SPoul-Henning Kamp 
301a03ce6cSPoul-Henning Kamp struct pps_data {
31477f9db3SPoul-Henning Kamp 	int	pps_open;
3295f0f58cSPoul-Henning Kamp 	struct	ppb_device pps_dev;
3332c20357SPoul-Henning Kamp 	struct	pps_state pps;
341a03ce6cSPoul-Henning Kamp };
35507e2e44SPoul-Henning Kamp 
3695f0f58cSPoul-Henning Kamp static int npps;
37507e2e44SPoul-Henning Kamp 
38507e2e44SPoul-Henning Kamp /*
39507e2e44SPoul-Henning Kamp  * Make ourselves visible as a ppbus driver
40507e2e44SPoul-Henning Kamp  */
41507e2e44SPoul-Henning Kamp 
4295f0f58cSPoul-Henning Kamp static struct ppb_device	*ppsprobe(struct ppb_data *ppb);
4395f0f58cSPoul-Henning Kamp static int			ppsattach(struct ppb_device *dev);
441a03ce6cSPoul-Henning Kamp static void			ppsintr(struct ppb_device *ppd);
45507e2e44SPoul-Henning Kamp 
4695f0f58cSPoul-Henning Kamp static struct ppb_driver ppsdriver = {
4795f0f58cSPoul-Henning Kamp     ppsprobe, ppsattach, PPS_NAME
48507e2e44SPoul-Henning Kamp };
49507e2e44SPoul-Henning Kamp 
5095f0f58cSPoul-Henning Kamp DATA_SET(ppbdriver_set, ppsdriver);
51507e2e44SPoul-Henning Kamp 
5295f0f58cSPoul-Henning Kamp static	d_open_t	ppsopen;
5395f0f58cSPoul-Henning Kamp static	d_close_t	ppsclose;
548afeddf0SPoul-Henning Kamp static	d_ioctl_t	ppsioctl;
55507e2e44SPoul-Henning Kamp 
56507e2e44SPoul-Henning Kamp #define CDEV_MAJOR 89
574e2f199eSPoul-Henning Kamp static struct cdevsw pps_cdevsw = {
584e2f199eSPoul-Henning Kamp 	/* open */	ppsopen,
594e2f199eSPoul-Henning Kamp 	/* close */	ppsclose,
604e2f199eSPoul-Henning Kamp 	/* read */	noread,
614e2f199eSPoul-Henning Kamp 	/* write */	nowrite,
624e2f199eSPoul-Henning Kamp 	/* ioctl */	ppsioctl,
634e2f199eSPoul-Henning Kamp 	/* stop */	nostop,
644e2f199eSPoul-Henning Kamp 	/* reset */	noreset,
654e2f199eSPoul-Henning Kamp 	/* devtotty */	nodevtotty,
664e2f199eSPoul-Henning Kamp 	/* poll */	nopoll,
674e2f199eSPoul-Henning Kamp 	/* mmap */	nommap,
684e2f199eSPoul-Henning Kamp 	/* strategy */	nostrategy,
694e2f199eSPoul-Henning Kamp 	/* name */	PPS_NAME,
704e2f199eSPoul-Henning Kamp 	/* parms */	noparms,
714e2f199eSPoul-Henning Kamp 	/* maj */	CDEV_MAJOR,
724e2f199eSPoul-Henning Kamp 	/* dump */	nodump,
734e2f199eSPoul-Henning Kamp 	/* psize */	nopsize,
744e2f199eSPoul-Henning Kamp 	/* flags */	0,
754e2f199eSPoul-Henning Kamp 	/* maxio */	0,
764e2f199eSPoul-Henning Kamp 	/* bmaj */	-1
774e2f199eSPoul-Henning Kamp };
78507e2e44SPoul-Henning Kamp 
7932c20357SPoul-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;
842447bec8SPoul-Henning Kamp 	static int once;
851a03ce6cSPoul-Henning Kamp 	dev_t dev;
862447bec8SPoul-Henning Kamp 
872447bec8SPoul-Henning Kamp 	if (!once++)
882447bec8SPoul-Henning Kamp 		cdevsw_add(&pps_cdevsw);
89507e2e44SPoul-Henning Kamp 
9095f0f58cSPoul-Henning Kamp 	sc = (struct pps_data *) malloc(sizeof(struct pps_data),
91507e2e44SPoul-Henning Kamp 							M_TEMP, M_NOWAIT);
92507e2e44SPoul-Henning Kamp 	if (!sc) {
93cc732491SPoul-Henning Kamp 		printf(PPS_NAME ": cannot malloc!\n");
94507e2e44SPoul-Henning Kamp 		return (0);
95507e2e44SPoul-Henning Kamp 	}
9695f0f58cSPoul-Henning Kamp 	bzero(sc, sizeof(struct pps_data));
97507e2e44SPoul-Henning Kamp 
981a03ce6cSPoul-Henning Kamp 	dev = make_dev(&pps_cdevsw, npps,
991a03ce6cSPoul-Henning Kamp 	    UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", npps);
100507e2e44SPoul-Henning Kamp 
1011a03ce6cSPoul-Henning Kamp 	dev->si_drv1 = sc;
102507e2e44SPoul-Henning Kamp 
1031a03ce6cSPoul-Henning Kamp 	sc->pps_dev.id_unit = npps++;
10495f0f58cSPoul-Henning Kamp 	sc->pps_dev.ppb = ppb;
10546f3ff79SMike Smith 	sc->pps_dev.name = ppsdriver.name;
1061a03ce6cSPoul-Henning Kamp 	sc->pps_dev.bintr = ppsintr;
1071a03ce6cSPoul-Henning Kamp 	sc->pps_dev.drv1 = sc;
108507e2e44SPoul-Henning Kamp 
10932c20357SPoul-Henning Kamp 	sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
11032c20357SPoul-Henning Kamp 	pps_init(&sc->pps);
11195f0f58cSPoul-Henning Kamp 	return (&sc->pps_dev);
112507e2e44SPoul-Henning Kamp }
113507e2e44SPoul-Henning Kamp 
114507e2e44SPoul-Henning Kamp static int
11595f0f58cSPoul-Henning Kamp ppsattach(struct ppb_device *dev)
116507e2e44SPoul-Henning Kamp {
11732c20357SPoul-Henning Kamp 
118507e2e44SPoul-Henning Kamp 	/*
119507e2e44SPoul-Henning Kamp 	 * Report ourselves
120507e2e44SPoul-Henning Kamp 	 */
121cc732491SPoul-Henning Kamp 	printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n",
122507e2e44SPoul-Henning Kamp 	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
123507e2e44SPoul-Henning Kamp 
124507e2e44SPoul-Henning Kamp 	return (1);
125507e2e44SPoul-Henning Kamp }
126507e2e44SPoul-Henning Kamp 
127507e2e44SPoul-Henning Kamp static	int
12895f0f58cSPoul-Henning Kamp ppsopen(dev_t dev, int flags, int fmt, struct proc *p)
129507e2e44SPoul-Henning Kamp {
13095f0f58cSPoul-Henning Kamp 	struct pps_data *sc;
131507e2e44SPoul-Henning Kamp 	u_int unit = minor(dev);
132507e2e44SPoul-Henning Kamp 
13395f0f58cSPoul-Henning Kamp 	if ((unit >= npps))
134507e2e44SPoul-Henning Kamp 		return (ENXIO);
135507e2e44SPoul-Henning Kamp 
1361a03ce6cSPoul-Henning Kamp 	sc = dev->si_drv1;
137507e2e44SPoul-Henning Kamp 
138477f9db3SPoul-Henning Kamp 	if (!sc->pps_open) {
13995f0f58cSPoul-Henning Kamp 		if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
140507e2e44SPoul-Henning Kamp 			return (EINTR);
141507e2e44SPoul-Henning Kamp 
14220240fa3SNicolas Souchu 		ppb_wctr(&sc->pps_dev, 0);
1438afeddf0SPoul-Henning Kamp 		ppb_wctr(&sc->pps_dev, IRQENABLE);
144477f9db3SPoul-Henning Kamp 		sc->pps_open = 1;
145477f9db3SPoul-Henning Kamp 	}
146507e2e44SPoul-Henning Kamp 
147507e2e44SPoul-Henning Kamp 	return(0);
148507e2e44SPoul-Henning Kamp }
149507e2e44SPoul-Henning Kamp 
150507e2e44SPoul-Henning Kamp static	int
15195f0f58cSPoul-Henning Kamp ppsclose(dev_t dev, int flags, int fmt, struct proc *p)
152507e2e44SPoul-Henning Kamp {
1531a03ce6cSPoul-Henning Kamp 	struct pps_data *sc = dev->si_drv1;
154507e2e44SPoul-Henning Kamp 
15532c20357SPoul-Henning Kamp 	sc->pps.ppsparam.mode = 0;	/* PHK ??? */
15620240fa3SNicolas Souchu 
15720240fa3SNicolas Souchu 	ppb_wdtr(&sc->pps_dev, 0);
15820240fa3SNicolas Souchu 	ppb_wctr(&sc->pps_dev, 0);
15920240fa3SNicolas Souchu 
16095f0f58cSPoul-Henning Kamp 	ppb_release_bus(&sc->pps_dev);
161477f9db3SPoul-Henning Kamp 	sc->pps_open = 0;
162507e2e44SPoul-Henning Kamp 	return(0);
163507e2e44SPoul-Henning Kamp }
164507e2e44SPoul-Henning Kamp 
165507e2e44SPoul-Henning Kamp static void
1661a03ce6cSPoul-Henning Kamp ppsintr(struct ppb_device *ppd)
167507e2e44SPoul-Henning Kamp {
1681a03ce6cSPoul-Henning Kamp 	struct pps_data *sc = ppd->drv1;
16932c20357SPoul-Henning Kamp 	struct timecounter *tc;
17032c20357SPoul-Henning Kamp 	unsigned count;
171507e2e44SPoul-Henning Kamp 
17232c20357SPoul-Henning Kamp 	tc = timecounter;
17332c20357SPoul-Henning Kamp 	count = timecounter->tc_get_timecount(tc);
17495f0f58cSPoul-Henning Kamp 	if (!(ppb_rstr(&sc->pps_dev) & nACK))
175507e2e44SPoul-Henning Kamp 		return;
17632c20357SPoul-Henning Kamp 	if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
1778afeddf0SPoul-Henning Kamp 		ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED);
17832c20357SPoul-Henning Kamp 	pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT);
17932c20357SPoul-Henning Kamp 	if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
1808afeddf0SPoul-Henning Kamp 		ppb_wctr(&sc->pps_dev, IRQENABLE);
181507e2e44SPoul-Henning Kamp }
182507e2e44SPoul-Henning Kamp 
183507e2e44SPoul-Henning Kamp static int
184ceeea6b9SBruce Evans ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
185507e2e44SPoul-Henning Kamp {
1861a03ce6cSPoul-Henning Kamp 	struct pps_data *sc = dev->si_drv1;
187507e2e44SPoul-Henning Kamp 
18832c20357SPoul-Henning Kamp 	return (pps_ioctl(cmd, data, &sc->pps));
1898afeddf0SPoul-Henning Kamp }
190507e2e44SPoul-Henning Kamp 
191