pps.c revision 33396
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 *
9 * $Id: pps.c,v 1.2 1998/02/13 17:35:33 phk Exp $
10 *
11 */
12
13#include "opt_devfs.h"
14
15#include <sys/param.h>
16#include <sys/kernel.h>
17#include <sys/systm.h>
18#include <sys/conf.h>
19#include <sys/uio.h>
20#ifdef DEVFS
21#include <sys/devfsext.h>
22#endif
23#include <sys/malloc.h>
24
25#include <dev/ppbus/ppbconf.h>
26#include "pps.h"
27
28#define PPS_NAME	"pps"		/* our official name */
29
30static struct pps_data {
31	int	pps_unit;
32	struct	ppb_device pps_dev;
33	struct  ppsclockev {
34		struct	timespec timestamp;
35		u_int	serial;
36	} ev;
37	int	sawtooth;
38} *softc[NPPS];
39
40static int npps;
41
42/*
43 * Make ourselves visible as a ppbus driver
44 */
45
46static struct ppb_device	*ppsprobe(struct ppb_data *ppb);
47static int			ppsattach(struct ppb_device *dev);
48static void			ppsintr(int unit);
49static void			pps_drvinit(void *unused);
50
51static struct ppb_driver ppsdriver = {
52    ppsprobe, ppsattach, PPS_NAME
53};
54
55DATA_SET(ppbdriver_set, ppsdriver);
56
57static	d_open_t	ppsopen;
58static	d_close_t	ppsclose;
59static	d_read_t	ppsread;
60static	d_write_t	ppswrite;
61
62#define CDEV_MAJOR 89
63static struct cdevsw pps_cdevsw =
64	{ ppsopen,	ppsclose,	ppsread,	ppswrite,
65	  noioctl,	nullstop,	nullreset,	nodevtotty,
66	  seltrue,	nommap,		nostrat,	PPS_NAME,
67	  NULL,		-1 };
68
69static struct ppb_device *
70ppsprobe(struct ppb_data *ppb)
71{
72	struct pps_data *sc;
73
74	sc = (struct pps_data *) malloc(sizeof(struct pps_data),
75							M_TEMP, M_NOWAIT);
76	if (!sc) {
77		printf(PPS_NAME ": cannot malloc!\n");
78		return (0);
79	}
80	bzero(sc, sizeof(struct pps_data));
81
82	softc[npps] = sc;
83
84	sc->pps_unit = npps++;
85
86	sc->pps_dev.id_unit = sc->pps_unit;
87	sc->pps_dev.ppb = ppb;
88	sc->pps_dev.intr = ppsintr;
89
90	return (&sc->pps_dev);
91}
92
93static int
94ppsattach(struct ppb_device *dev)
95{
96	/*
97	 * Report ourselves
98	 */
99	printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n",
100	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
101
102#ifdef DEVFS
103	devfs_add_devswf(&pps_cdevsw,
104		dev->id_unit, DV_CHR,
105		UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit);
106	devfs_add_devswf(&pps_cdevsw,
107		dev->id_unit | LP_BYPASS, DV_CHR,
108		UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d.ctl", dev->id_unit);
109#endif
110
111	return (1);
112}
113
114static	int
115ppsopen(dev_t dev, int flags, int fmt, struct proc *p)
116{
117	struct pps_data *sc;
118	u_int unit = minor(dev);
119
120	if ((unit >= npps))
121		return (ENXIO);
122
123	sc = softc[unit];
124
125	if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
126		return (EINTR);
127
128	ppb_wctr(&sc->pps_dev, 0x10);
129
130	return(0);
131}
132
133static	int
134ppsclose(dev_t dev, int flags, int fmt, struct proc *p)
135{
136	struct pps_data *sc = softc[minor(dev)];
137
138	ppb_release_bus(&sc->pps_dev);
139	return(0);
140}
141
142static void
143ppsintr(int unit)
144{
145/*
146 * XXX: You want to thing carefully about what you actually want to do
147 * here.
148 */
149#if 1
150	struct pps_data *sc = softc[unit];
151	struct timespec tc;
152#if 1
153	struct timeval tv;
154#endif
155
156	nanotime(&tc);
157	if (!(ppb_rstr(&sc->pps_dev) & nACK))
158		return;
159	tc.tv_nsec -= sc->sawtooth;
160	sc->sawtooth = 0;
161	if (tc.tv_nsec > 1000000000) {
162		tc.tv_sec++;
163		tc.tv_nsec -= 1000000000;
164	} else if (tc.tv_nsec < 0) {
165		tc.tv_sec--;
166		tc.tv_nsec += 1000000000;
167	}
168	sc->ev.timestamp = tc;
169	sc->ev.serial++;
170#if 1
171	tv.tv_sec = tc.tv_sec;
172	tv.tv_usec = tc.tv_nsec / 1000;
173	hardpps(&tv, tv.tv_usec);
174#endif
175#endif
176}
177
178static	int
179ppsread(dev_t dev, struct uio *uio, int ioflag)
180{
181	struct pps_data *sc = softc[minor(dev)];
182	int err, c;
183
184	c = imin(uio->uio_resid, (int)sizeof sc->ev);
185	err = uiomove((caddr_t)&sc->ev, c, uio);
186	return(err);
187}
188
189static	int
190ppswrite(dev_t dev, struct uio *uio, int ioflag)
191{
192	struct pps_data *sc = softc[minor(dev)];
193	int err, c;
194
195	c = imin(uio->uio_resid, (int)sizeof sc->sawtooth);
196	err = uiomove((caddr_t)&sc->sawtooth, c, uio);
197	return(err);
198}
199
200static pps_devsw_installed = 0;
201
202static void
203pps_drvinit(void *unused)
204{
205	dev_t dev;
206
207	if( ! pps_devsw_installed ) {
208		dev = makedev(CDEV_MAJOR, 0);
209		cdevsw_add(&dev, &pps_cdevsw, NULL);
210		pps_devsw_installed = 1;
211    	}
212}
213
214SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL)
215