xref: /freebsd/sys/dev/ppbus/pps.c (revision 601752d5a7bef087e755da5a2b158fa35cb51ccb)
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.14 1999/03/11 15:09:51 phk Exp $
10  *
11  * This driver implements a draft-mogul-pps-api-02.txt PPS source.
12  *
13  * The input pin is pin#10
14  * The echo output pin is pin#14
15  *
16  */
17 
18 #include "opt_devfs.h"
19 
20 #include <sys/param.h>
21 #include <sys/kernel.h>
22 #include <sys/systm.h>
23 #include <sys/conf.h>
24 #include <sys/timepps.h>
25 #ifdef DEVFS
26 #include <sys/devfsext.h>
27 #endif
28 #include <sys/malloc.h>
29 
30 #include <dev/ppbus/ppbconf.h>
31 #include "pps.h"
32 
33 #define PPS_NAME	"lppps"		/* our official name */
34 
35 static struct pps_data {
36 	int	pps_unit;
37 	struct	ppb_device pps_dev;
38 	struct	pps_state pps;
39 } *softc[NPPS];
40 
41 static int npps;
42 
43 /*
44  * Make ourselves visible as a ppbus driver
45  */
46 
47 static struct ppb_device	*ppsprobe(struct ppb_data *ppb);
48 static int			ppsattach(struct ppb_device *dev);
49 static void			ppsintr(int unit);
50 static void			pps_drvinit(void *unused);
51 
52 static struct ppb_driver ppsdriver = {
53     ppsprobe, ppsattach, PPS_NAME
54 };
55 
56 DATA_SET(ppbdriver_set, ppsdriver);
57 
58 static	d_open_t	ppsopen;
59 static	d_close_t	ppsclose;
60 static	d_ioctl_t	ppsioctl;
61 
62 #define CDEV_MAJOR 89
63 static struct cdevsw pps_cdevsw =
64 	{ ppsopen,	ppsclose,	noread,		nowrite,
65 	  ppsioctl,	nullstop,	nullreset,	nodevtotty,
66 	  seltrue,	nommap,		nostrat,	PPS_NAME,
67 	  NULL,		-1 };
68 
69 
70 static struct ppb_device *
71 ppsprobe(struct ppb_data *ppb)
72 {
73 	struct pps_data *sc;
74 
75 	sc = (struct pps_data *) malloc(sizeof(struct pps_data),
76 							M_TEMP, M_NOWAIT);
77 	if (!sc) {
78 		printf(PPS_NAME ": cannot malloc!\n");
79 		return (0);
80 	}
81 	bzero(sc, sizeof(struct pps_data));
82 
83 	softc[npps] = sc;
84 
85 	sc->pps_unit = npps++;
86 
87 	sc->pps_dev.id_unit = sc->pps_unit;
88 	sc->pps_dev.ppb = ppb;
89 	sc->pps_dev.name = ppsdriver.name;
90 	sc->pps_dev.intr = ppsintr;
91 
92 	sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
93 	pps_init(&sc->pps);
94 	return (&sc->pps_dev);
95 }
96 
97 static int
98 ppsattach(struct ppb_device *dev)
99 {
100 	dev_t devt;
101 
102 	/*
103 	 * Report ourselves
104 	 */
105 	printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n",
106 	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
107 
108 #ifdef DEVFS
109 	devfs_add_devswf(&pps_cdevsw,
110 		dev->id_unit, DV_CHR,
111 		UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit);
112 #endif
113 	devt = makedev(CDEV_MAJOR, 0);
114 	cdevsw_add(&devt, &pps_cdevsw, NULL);
115 	return (1);
116 }
117 
118 static	int
119 ppsopen(dev_t dev, int flags, int fmt, struct proc *p)
120 {
121 	struct pps_data *sc;
122 	u_int unit = minor(dev);
123 
124 	if ((unit >= npps))
125 		return (ENXIO);
126 
127 	sc = softc[unit];
128 
129 	if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
130 		return (EINTR);
131 
132 	ppb_wctr(&sc->pps_dev, 0);
133 	ppb_wctr(&sc->pps_dev, IRQENABLE);
134 
135 	return(0);
136 }
137 
138 static	int
139 ppsclose(dev_t dev, int flags, int fmt, struct proc *p)
140 {
141 	struct pps_data *sc = softc[minor(dev)];
142 
143 	sc->pps.ppsparam.mode = 0;	/* PHK ??? */
144 
145 	ppb_wdtr(&sc->pps_dev, 0);
146 	ppb_wctr(&sc->pps_dev, 0);
147 
148 	ppb_release_bus(&sc->pps_dev);
149 	return(0);
150 }
151 
152 static void
153 ppsintr(int unit)
154 {
155 	struct pps_data *sc = softc[unit];
156 	struct timecounter *tc;
157 	unsigned count;
158 
159 	tc = timecounter;
160 	count = timecounter->tc_get_timecount(tc);
161 	if (!(ppb_rstr(&sc->pps_dev) & nACK))
162 		return;
163 	if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
164 		ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED);
165 	pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT);
166 	if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
167 		ppb_wctr(&sc->pps_dev, IRQENABLE);
168 }
169 
170 static int
171 ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
172 {
173 	struct pps_data *sc = softc[minor(dev)];
174 
175 	return (pps_ioctl(cmd, data, &sc->pps));
176 }
177 
178