xref: /freebsd/sys/dev/ppbus/pps.c (revision 95f0f58cc3b9e21dd86bcd4a090874c3760ddd08)
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  *
995f0f58cSPoul-Henning Kamp  * $Id: pps.c,v 1.2 1998/02/13 17:35:33 phk Exp $
10507e2e44SPoul-Henning Kamp  *
11507e2e44SPoul-Henning Kamp  */
12507e2e44SPoul-Henning Kamp 
1395f0f58cSPoul-Henning Kamp #include "opt_devfs.h"
1495f0f58cSPoul-Henning Kamp 
15507e2e44SPoul-Henning Kamp #include <sys/param.h>
16507e2e44SPoul-Henning Kamp #include <sys/kernel.h>
17507e2e44SPoul-Henning Kamp #include <sys/systm.h>
18507e2e44SPoul-Henning Kamp #include <sys/conf.h>
19507e2e44SPoul-Henning Kamp #include <sys/uio.h>
20507e2e44SPoul-Henning Kamp #ifdef DEVFS
21507e2e44SPoul-Henning Kamp #include <sys/devfsext.h>
2295f0f58cSPoul-Henning Kamp #endif
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 
28cc732491SPoul-Henning Kamp #define PPS_NAME	"pps"		/* our official name */
29507e2e44SPoul-Henning Kamp 
3095f0f58cSPoul-Henning Kamp static struct pps_data {
3195f0f58cSPoul-Henning Kamp 	int	pps_unit;
3295f0f58cSPoul-Henning Kamp 	struct	ppb_device pps_dev;
33507e2e44SPoul-Henning Kamp 	struct  ppsclockev {
34507e2e44SPoul-Henning Kamp 		struct	timespec timestamp;
35507e2e44SPoul-Henning Kamp 		u_int	serial;
36507e2e44SPoul-Henning Kamp 	} ev;
37507e2e44SPoul-Henning Kamp 	int	sawtooth;
38cc732491SPoul-Henning Kamp } *softc[NPPS];
39507e2e44SPoul-Henning Kamp 
4095f0f58cSPoul-Henning Kamp static int npps;
41507e2e44SPoul-Henning Kamp 
42507e2e44SPoul-Henning Kamp /*
43507e2e44SPoul-Henning Kamp  * Make ourselves visible as a ppbus driver
44507e2e44SPoul-Henning Kamp  */
45507e2e44SPoul-Henning Kamp 
4695f0f58cSPoul-Henning Kamp static struct ppb_device	*ppsprobe(struct ppb_data *ppb);
4795f0f58cSPoul-Henning Kamp static int			ppsattach(struct ppb_device *dev);
4895f0f58cSPoul-Henning Kamp static void			ppsintr(int unit);
4995f0f58cSPoul-Henning Kamp static void			pps_drvinit(void *unused);
50507e2e44SPoul-Henning Kamp 
5195f0f58cSPoul-Henning Kamp static struct ppb_driver ppsdriver = {
5295f0f58cSPoul-Henning Kamp     ppsprobe, ppsattach, PPS_NAME
53507e2e44SPoul-Henning Kamp };
54507e2e44SPoul-Henning Kamp 
5595f0f58cSPoul-Henning Kamp DATA_SET(ppbdriver_set, ppsdriver);
56507e2e44SPoul-Henning Kamp 
5795f0f58cSPoul-Henning Kamp static	d_open_t	ppsopen;
5895f0f58cSPoul-Henning Kamp static	d_close_t	ppsclose;
5995f0f58cSPoul-Henning Kamp static	d_read_t	ppsread;
6095f0f58cSPoul-Henning Kamp static	d_write_t	ppswrite;
61507e2e44SPoul-Henning Kamp 
62507e2e44SPoul-Henning Kamp #define CDEV_MAJOR 89
6395f0f58cSPoul-Henning Kamp static struct cdevsw pps_cdevsw =
6495f0f58cSPoul-Henning Kamp 	{ ppsopen,	ppsclose,	ppsread,	ppswrite,
65507e2e44SPoul-Henning Kamp 	  noioctl,	nullstop,	nullreset,	nodevtotty,
66cc732491SPoul-Henning Kamp 	  seltrue,	nommap,		nostrat,	PPS_NAME,
67507e2e44SPoul-Henning Kamp 	  NULL,		-1 };
68507e2e44SPoul-Henning Kamp 
69507e2e44SPoul-Henning Kamp static struct ppb_device *
7095f0f58cSPoul-Henning Kamp ppsprobe(struct ppb_data *ppb)
71507e2e44SPoul-Henning Kamp {
7295f0f58cSPoul-Henning Kamp 	struct pps_data *sc;
73507e2e44SPoul-Henning Kamp 
7495f0f58cSPoul-Henning Kamp 	sc = (struct pps_data *) malloc(sizeof(struct pps_data),
75507e2e44SPoul-Henning Kamp 							M_TEMP, M_NOWAIT);
76507e2e44SPoul-Henning Kamp 	if (!sc) {
77cc732491SPoul-Henning Kamp 		printf(PPS_NAME ": cannot malloc!\n");
78507e2e44SPoul-Henning Kamp 		return (0);
79507e2e44SPoul-Henning Kamp 	}
8095f0f58cSPoul-Henning Kamp 	bzero(sc, sizeof(struct pps_data));
81507e2e44SPoul-Henning Kamp 
8295f0f58cSPoul-Henning Kamp 	softc[npps] = sc;
83507e2e44SPoul-Henning Kamp 
8495f0f58cSPoul-Henning Kamp 	sc->pps_unit = npps++;
85507e2e44SPoul-Henning Kamp 
8695f0f58cSPoul-Henning Kamp 	sc->pps_dev.id_unit = sc->pps_unit;
8795f0f58cSPoul-Henning Kamp 	sc->pps_dev.ppb = ppb;
8895f0f58cSPoul-Henning Kamp 	sc->pps_dev.intr = ppsintr;
89507e2e44SPoul-Henning Kamp 
9095f0f58cSPoul-Henning Kamp 	return (&sc->pps_dev);
91507e2e44SPoul-Henning Kamp }
92507e2e44SPoul-Henning Kamp 
93507e2e44SPoul-Henning Kamp static int
9495f0f58cSPoul-Henning Kamp ppsattach(struct ppb_device *dev)
95507e2e44SPoul-Henning Kamp {
96507e2e44SPoul-Henning Kamp 	/*
97507e2e44SPoul-Henning Kamp 	 * Report ourselves
98507e2e44SPoul-Henning Kamp 	 */
99cc732491SPoul-Henning Kamp 	printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n",
100507e2e44SPoul-Henning Kamp 	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
101507e2e44SPoul-Henning Kamp 
102507e2e44SPoul-Henning Kamp #ifdef DEVFS
10395f0f58cSPoul-Henning Kamp 	devfs_add_devswf(&pps_cdevsw,
104507e2e44SPoul-Henning Kamp 		dev->id_unit, DV_CHR,
105cc732491SPoul-Henning Kamp 		UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit);
10695f0f58cSPoul-Henning Kamp 	devfs_add_devswf(&pps_cdevsw,
107507e2e44SPoul-Henning Kamp 		dev->id_unit | LP_BYPASS, DV_CHR,
108cc732491SPoul-Henning Kamp 		UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d.ctl", dev->id_unit);
109507e2e44SPoul-Henning Kamp #endif
110507e2e44SPoul-Henning Kamp 
111507e2e44SPoul-Henning Kamp 	return (1);
112507e2e44SPoul-Henning Kamp }
113507e2e44SPoul-Henning Kamp 
114507e2e44SPoul-Henning Kamp static	int
11595f0f58cSPoul-Henning Kamp ppsopen(dev_t dev, int flags, int fmt, struct proc *p)
116507e2e44SPoul-Henning Kamp {
11795f0f58cSPoul-Henning Kamp 	struct pps_data *sc;
118507e2e44SPoul-Henning Kamp 	u_int unit = minor(dev);
119507e2e44SPoul-Henning Kamp 
12095f0f58cSPoul-Henning Kamp 	if ((unit >= npps))
121507e2e44SPoul-Henning Kamp 		return (ENXIO);
122507e2e44SPoul-Henning Kamp 
123507e2e44SPoul-Henning Kamp 	sc = softc[unit];
124507e2e44SPoul-Henning Kamp 
12595f0f58cSPoul-Henning Kamp 	if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
126507e2e44SPoul-Henning Kamp 		return (EINTR);
127507e2e44SPoul-Henning Kamp 
12895f0f58cSPoul-Henning Kamp 	ppb_wctr(&sc->pps_dev, 0x10);
129507e2e44SPoul-Henning Kamp 
130507e2e44SPoul-Henning Kamp 	return(0);
131507e2e44SPoul-Henning Kamp }
132507e2e44SPoul-Henning Kamp 
133507e2e44SPoul-Henning Kamp static	int
13495f0f58cSPoul-Henning Kamp ppsclose(dev_t dev, int flags, int fmt, struct proc *p)
135507e2e44SPoul-Henning Kamp {
13695f0f58cSPoul-Henning Kamp 	struct pps_data *sc = softc[minor(dev)];
137507e2e44SPoul-Henning Kamp 
13895f0f58cSPoul-Henning Kamp 	ppb_release_bus(&sc->pps_dev);
139507e2e44SPoul-Henning Kamp 	return(0);
140507e2e44SPoul-Henning Kamp }
141507e2e44SPoul-Henning Kamp 
142507e2e44SPoul-Henning Kamp static void
14395f0f58cSPoul-Henning Kamp ppsintr(int unit)
144507e2e44SPoul-Henning Kamp {
145507e2e44SPoul-Henning Kamp /*
146507e2e44SPoul-Henning Kamp  * XXX: You want to thing carefully about what you actually want to do
147507e2e44SPoul-Henning Kamp  * here.
148507e2e44SPoul-Henning Kamp  */
14995f0f58cSPoul-Henning Kamp #if 1
15095f0f58cSPoul-Henning Kamp 	struct pps_data *sc = softc[unit];
151507e2e44SPoul-Henning Kamp 	struct timespec tc;
152507e2e44SPoul-Henning Kamp #if 1
153507e2e44SPoul-Henning Kamp 	struct timeval tv;
154507e2e44SPoul-Henning Kamp #endif
155507e2e44SPoul-Henning Kamp 
156507e2e44SPoul-Henning Kamp 	nanotime(&tc);
15795f0f58cSPoul-Henning Kamp 	if (!(ppb_rstr(&sc->pps_dev) & nACK))
158507e2e44SPoul-Henning Kamp 		return;
159507e2e44SPoul-Henning Kamp 	tc.tv_nsec -= sc->sawtooth;
160507e2e44SPoul-Henning Kamp 	sc->sawtooth = 0;
161507e2e44SPoul-Henning Kamp 	if (tc.tv_nsec > 1000000000) {
162507e2e44SPoul-Henning Kamp 		tc.tv_sec++;
163507e2e44SPoul-Henning Kamp 		tc.tv_nsec -= 1000000000;
164507e2e44SPoul-Henning Kamp 	} else if (tc.tv_nsec < 0) {
165507e2e44SPoul-Henning Kamp 		tc.tv_sec--;
166507e2e44SPoul-Henning Kamp 		tc.tv_nsec += 1000000000;
167507e2e44SPoul-Henning Kamp 	}
168507e2e44SPoul-Henning Kamp 	sc->ev.timestamp = tc;
169507e2e44SPoul-Henning Kamp 	sc->ev.serial++;
170507e2e44SPoul-Henning Kamp #if 1
171507e2e44SPoul-Henning Kamp 	tv.tv_sec = tc.tv_sec;
172507e2e44SPoul-Henning Kamp 	tv.tv_usec = tc.tv_nsec / 1000;
173507e2e44SPoul-Henning Kamp 	hardpps(&tv, tv.tv_usec);
174507e2e44SPoul-Henning Kamp #endif
175507e2e44SPoul-Henning Kamp #endif
176507e2e44SPoul-Henning Kamp }
177507e2e44SPoul-Henning Kamp 
178507e2e44SPoul-Henning Kamp static	int
17995f0f58cSPoul-Henning Kamp ppsread(dev_t dev, struct uio *uio, int ioflag)
180507e2e44SPoul-Henning Kamp {
18195f0f58cSPoul-Henning Kamp 	struct pps_data *sc = softc[minor(dev)];
182507e2e44SPoul-Henning Kamp 	int err, c;
183507e2e44SPoul-Henning Kamp 
18495f0f58cSPoul-Henning Kamp 	c = imin(uio->uio_resid, (int)sizeof sc->ev);
18595f0f58cSPoul-Henning Kamp 	err = uiomove((caddr_t)&sc->ev, c, uio);
186507e2e44SPoul-Henning Kamp 	return(err);
187507e2e44SPoul-Henning Kamp }
188507e2e44SPoul-Henning Kamp 
189507e2e44SPoul-Henning Kamp static	int
19095f0f58cSPoul-Henning Kamp ppswrite(dev_t dev, struct uio *uio, int ioflag)
191507e2e44SPoul-Henning Kamp {
19295f0f58cSPoul-Henning Kamp 	struct pps_data *sc = softc[minor(dev)];
193507e2e44SPoul-Henning Kamp 	int err, c;
194507e2e44SPoul-Henning Kamp 
19595f0f58cSPoul-Henning Kamp 	c = imin(uio->uio_resid, (int)sizeof sc->sawtooth);
19695f0f58cSPoul-Henning Kamp 	err = uiomove((caddr_t)&sc->sawtooth, c, uio);
197507e2e44SPoul-Henning Kamp 	return(err);
198507e2e44SPoul-Henning Kamp }
199507e2e44SPoul-Henning Kamp 
20095f0f58cSPoul-Henning Kamp static pps_devsw_installed = 0;
201507e2e44SPoul-Henning Kamp 
202507e2e44SPoul-Henning Kamp static void
20395f0f58cSPoul-Henning Kamp pps_drvinit(void *unused)
204507e2e44SPoul-Henning Kamp {
205507e2e44SPoul-Henning Kamp 	dev_t dev;
206507e2e44SPoul-Henning Kamp 
20795f0f58cSPoul-Henning Kamp 	if( ! pps_devsw_installed ) {
208507e2e44SPoul-Henning Kamp 		dev = makedev(CDEV_MAJOR, 0);
20995f0f58cSPoul-Henning Kamp 		cdevsw_add(&dev, &pps_cdevsw, NULL);
21095f0f58cSPoul-Henning Kamp 		pps_devsw_installed = 1;
211507e2e44SPoul-Henning Kamp     	}
212507e2e44SPoul-Henning Kamp }
213507e2e44SPoul-Henning Kamp 
21495f0f58cSPoul-Henning Kamp SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL)
215