pps.c revision 51658
1171802Sdelphij/*
2170808Sdelphij * ----------------------------------------------------------------------------
3182739Sdelphij * "THE BEER-WARE LICENSE" (Revision 42):
4171802Sdelphij * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5170808Sdelphij * can do whatever you want with this stuff. If we meet some day, and you think
6170808Sdelphij * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7170808Sdelphij * ----------------------------------------------------------------------------
8170808Sdelphij *
9170808Sdelphij * $FreeBSD: head/sys/dev/ppbus/pps.c 51658 1999-09-25 18:24:47Z phk $
10170808Sdelphij *
11170808Sdelphij * This driver implements a draft-mogul-pps-api-02.txt PPS source.
12170808Sdelphij *
13170808Sdelphij * The input pin is pin#10
14170808Sdelphij * The echo output pin is pin#14
15170808Sdelphij *
16170808Sdelphij */
17170808Sdelphij
18170808Sdelphij#include <sys/param.h>
19170808Sdelphij#include <sys/kernel.h>
20170808Sdelphij#include <sys/systm.h>
21170808Sdelphij#include <sys/conf.h>
22170808Sdelphij#include <sys/timepps.h>
23170808Sdelphij#include <sys/malloc.h>
24170808Sdelphij
25170808Sdelphij#include <dev/ppbus/ppbconf.h>
26170808Sdelphij#include "pps.h"
27170808Sdelphij
28170808Sdelphij#define PPS_NAME	"pps"		/* our official name */
29170808Sdelphij
30170808Sdelphijstruct pps_data {
31170808Sdelphij	int	pps_open;
32170808Sdelphij	struct	ppb_device pps_dev;
33170808Sdelphij	struct	pps_state pps;
34170808Sdelphij};
35170808Sdelphij
36170808Sdelphijstatic int npps;
37170808Sdelphij
38170808Sdelphij/*
39170808Sdelphij * Make ourselves visible as a ppbus driver
40170808Sdelphij */
41170808Sdelphij
42170808Sdelphijstatic struct ppb_device	*ppsprobe(struct ppb_data *ppb);
43170808Sdelphijstatic int			ppsattach(struct ppb_device *dev);
44170808Sdelphijstatic void			ppsintr(struct ppb_device *ppd);
45197850Sdelphij
46197850Sdelphijstatic struct ppb_driver ppsdriver = {
47170808Sdelphij    ppsprobe, ppsattach, PPS_NAME
48170808Sdelphij};
49170808Sdelphij
50170808SdelphijDATA_SET(ppbdriver_set, ppsdriver);
51170808Sdelphij
52170808Sdelphijstatic	d_open_t	ppsopen;
53170808Sdelphijstatic	d_close_t	ppsclose;
54170808Sdelphijstatic	d_ioctl_t	ppsioctl;
55170808Sdelphij
56188929Salc#define CDEV_MAJOR 89
57170808Sdelphijstatic struct cdevsw pps_cdevsw = {
58170808Sdelphij	/* open */	ppsopen,
59170808Sdelphij	/* close */	ppsclose,
60170808Sdelphij	/* read */	noread,
61170808Sdelphij	/* write */	nowrite,
62170808Sdelphij	/* ioctl */	ppsioctl,
63170808Sdelphij	/* poll */	nopoll,
64170808Sdelphij	/* mmap */	nommap,
65171069Sdelphij	/* strategy */	nostrategy,
66170808Sdelphij	/* name */	PPS_NAME,
67170808Sdelphij	/* maj */	CDEV_MAJOR,
68170808Sdelphij	/* dump */	nodump,
69170808Sdelphij	/* psize */	nopsize,
70170808Sdelphij	/* flags */	0,
71170808Sdelphij	/* bmaj */	-1
72170808Sdelphij};
73170808Sdelphij
74170808Sdelphij
75170808Sdelphijstatic struct ppb_device *
76170808Sdelphijppsprobe(struct ppb_data *ppb)
77170808Sdelphij{
78170808Sdelphij	struct pps_data *sc;
79170808Sdelphij	static int once;
80191990Sattilio	dev_t dev;
81170808Sdelphij
82170808Sdelphij	if (!once++)
83170808Sdelphij		cdevsw_add(&pps_cdevsw);
84170808Sdelphij
85170808Sdelphij	sc = (struct pps_data *) malloc(sizeof(struct pps_data),
86170808Sdelphij							M_TEMP, M_NOWAIT);
87170808Sdelphij	if (!sc) {
88170808Sdelphij		printf(PPS_NAME ": cannot malloc!\n");
89197953Sdelphij		return (0);
90197953Sdelphij	}
91197953Sdelphij	bzero(sc, sizeof(struct pps_data));
92197953Sdelphij
93197953Sdelphij	dev = make_dev(&pps_cdevsw, npps,
94170808Sdelphij	    UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", npps);
95171799Sdelphij
96171799Sdelphij	dev->si_drv1 = sc;
97176559Sattilio
98171802Sdelphij	sc->pps_dev.id_unit = npps++;
99175294Sattilio	sc->pps_dev.ppb = ppb;
100170808Sdelphij	sc->pps_dev.name = ppsdriver.name;
101171799Sdelphij	sc->pps_dev.bintr = ppsintr;
102191990Sattilio	sc->pps_dev.drv1 = sc;
103170808Sdelphij
104175202Sattilio	sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
105171802Sdelphij	pps_init(&sc->pps);
106170808Sdelphij	return (&sc->pps_dev);
107170808Sdelphij}
108170808Sdelphij
109170808Sdelphijstatic int
110170808Sdelphijppsattach(struct ppb_device *dev)
111188318Skib{
112211598Sed
113211598Sed	/*
114211598Sed	 * Report ourselves
115170808Sdelphij	 */
116170808Sdelphij	printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n",
117170808Sdelphij	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
118170808Sdelphij
119170808Sdelphij	return (1);
120170808Sdelphij}
121211598Sed
122211598Sedstatic	int
123211598Sedppsopen(dev_t dev, int flags, int fmt, struct proc *p)
124211598Sed{
125170808Sdelphij	struct pps_data *sc;
126170808Sdelphij	u_int unit = minor(dev);
127170808Sdelphij
128170808Sdelphij	if ((unit >= npps))
129170808Sdelphij		return (ENXIO);
130170808Sdelphij
131170808Sdelphij	sc = dev->si_drv1;
132170808Sdelphij
133170808Sdelphij	if (!sc->pps_open) {
134170808Sdelphij		if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
135170808Sdelphij			return (EINTR);
136170808Sdelphij
137170808Sdelphij		ppb_wctr(&sc->pps_dev, 0);
138170808Sdelphij		ppb_wctr(&sc->pps_dev, IRQENABLE);
139170808Sdelphij		sc->pps_open = 1;
140170808Sdelphij	}
141170808Sdelphij
142170808Sdelphij	return(0);
143170808Sdelphij}
144170808Sdelphij
145170808Sdelphijstatic	int
146170808Sdelphijppsclose(dev_t dev, int flags, int fmt, struct proc *p)
147170808Sdelphij{
148170808Sdelphij	struct pps_data *sc = dev->si_drv1;
149170808Sdelphij
150170808Sdelphij	sc->pps.ppsparam.mode = 0;	/* PHK ??? */
151170808Sdelphij
152170808Sdelphij	ppb_wdtr(&sc->pps_dev, 0);
153170808Sdelphij	ppb_wctr(&sc->pps_dev, 0);
154170808Sdelphij
155170808Sdelphij	ppb_release_bus(&sc->pps_dev);
156170808Sdelphij	sc->pps_open = 0;
157170808Sdelphij	return(0);
158170808Sdelphij}
159170808Sdelphij
160170808Sdelphijstatic void
161170808Sdelphijppsintr(struct ppb_device *ppd)
162170808Sdelphij{
163170808Sdelphij	struct pps_data *sc = ppd->drv1;
164170808Sdelphij	struct timecounter *tc;
165171070Sdelphij	unsigned count;
166170808Sdelphij
167171799Sdelphij	tc = timecounter;
168191990Sattilio	count = timecounter->tc_get_timecount(tc);
169170808Sdelphij	if (!(ppb_rstr(&sc->pps_dev) & nACK))
170170808Sdelphij		return;
171170808Sdelphij	if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
172170808Sdelphij		ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED);
173170808Sdelphij	pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT);
174170808Sdelphij	if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
175170808Sdelphij		ppb_wctr(&sc->pps_dev, IRQENABLE);
176170808Sdelphij}
177170808Sdelphij
178170808Sdelphijstatic int
179171070Sdelphijppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
180170808Sdelphij{
181171799Sdelphij	struct pps_data *sc = dev->si_drv1;
182171799Sdelphij
183191990Sattilio	return (pps_ioctl(cmd, data, &sc->pps));
184170808Sdelphij}
185170808Sdelphij
186170808Sdelphij