pps.c revision 33442
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.3 1998/02/15 14:54:09 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#endif
107
108	return (1);
109}
110
111static	int
112ppsopen(dev_t dev, int flags, int fmt, struct proc *p)
113{
114	struct pps_data *sc;
115	u_int unit = minor(dev);
116
117	if ((unit >= npps))
118		return (ENXIO);
119
120	sc = softc[unit];
121
122	if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
123		return (EINTR);
124
125	ppb_wctr(&sc->pps_dev, 0x10);
126
127	return(0);
128}
129
130static	int
131ppsclose(dev_t dev, int flags, int fmt, struct proc *p)
132{
133	struct pps_data *sc = softc[minor(dev)];
134
135	ppb_release_bus(&sc->pps_dev);
136	return(0);
137}
138
139static void
140ppsintr(int unit)
141{
142/*
143 * XXX: You want to thing carefully about what you actually want to do
144 * here.
145 */
146#if 1
147	struct pps_data *sc = softc[unit];
148	struct timespec tc;
149#if 1
150	struct timeval tv;
151#endif
152
153	nanotime(&tc);
154	if (!(ppb_rstr(&sc->pps_dev) & nACK))
155		return;
156	tc.tv_nsec -= sc->sawtooth;
157	sc->sawtooth = 0;
158	if (tc.tv_nsec > 1000000000) {
159		tc.tv_sec++;
160		tc.tv_nsec -= 1000000000;
161	} else if (tc.tv_nsec < 0) {
162		tc.tv_sec--;
163		tc.tv_nsec += 1000000000;
164	}
165	sc->ev.timestamp = tc;
166	sc->ev.serial++;
167#if 1
168	tv.tv_sec = tc.tv_sec;
169	tv.tv_usec = tc.tv_nsec / 1000;
170	hardpps(&tv, tv.tv_usec);
171#endif
172#endif
173}
174
175static	int
176ppsread(dev_t dev, struct uio *uio, int ioflag)
177{
178	struct pps_data *sc = softc[minor(dev)];
179	int err, c;
180
181	c = imin(uio->uio_resid, (int)sizeof sc->ev);
182	err = uiomove((caddr_t)&sc->ev, c, uio);
183	return(err);
184}
185
186static	int
187ppswrite(dev_t dev, struct uio *uio, int ioflag)
188{
189	struct pps_data *sc = softc[minor(dev)];
190	int err, c;
191
192	c = imin(uio->uio_resid, (int)sizeof sc->sawtooth);
193	err = uiomove((caddr_t)&sc->sawtooth, c, uio);
194	return(err);
195}
196
197static pps_devsw_installed = 0;
198
199static void
200pps_drvinit(void *unused)
201{
202	dev_t dev;
203
204	if( ! pps_devsw_installed ) {
205		dev = makedev(CDEV_MAJOR, 0);
206		cdevsw_add(&dev, &pps_cdevsw, NULL);
207		pps_devsw_installed = 1;
208    	}
209}
210
211SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL)
212