1 /* $NetBSD: pps_ppbus.c,v 1.13 2008/04/21 12:56:31 ad Exp $ */
4 * ported to timecounters by Frank Kardel 2006
7 * Matthias Drochner. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions, and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: pps_ppbus.c,v 1.13 2008/04/21 12:56:31 ad Exp $");
36 #include <sys/param.h>
37 #include <sys/systm.h>
40 #include <sys/ioctl.h>
41 #include <sys/timepps.h>
43 #include <dev/ppbus/ppbus_base.h>
44 #include <dev/ppbus/ppbus_device.h>
45 #include <dev/ppbus/ppbus_io.h>
46 #include <dev/ppbus/ppbus_var.h>
49 struct ppbus_device_softc pps_dev
;
52 struct pps_state pps_state
; /* pps state */
55 static int pps_probe(device_t
, cfdata_t
, void *);
56 static void pps_attach(device_t
, device_t
, void *);
57 CFATTACH_DECL_NEW(pps
, sizeof(struct pps_softc
), pps_probe
, pps_attach
,
59 extern struct cfdriver pps_cd
;
61 static dev_type_open(ppsopen
);
62 static dev_type_close(ppsclose
);
63 static dev_type_ioctl(ppsioctl
);
64 const struct cdevsw pps_cdevsw
= {
65 ppsopen
, ppsclose
, noread
, nowrite
, ppsioctl
,
66 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
69 static void ppsintr(void *arg
);
72 pps_probe(device_t parent
, cfdata_t match
, void *aux
)
74 struct ppbus_attach_args
*args
= aux
;
76 /* we need an interrupt */
77 if (!(args
->capabilities
& PPBUS_HAS_INTR
))
84 pps_attach(device_t parent
, device_t self
, void *aux
)
86 struct pps_softc
*sc
= device_private(self
);
89 sc
->pps_dev
.sc_dev
= self
;
95 ppsopen(dev_t dev
, int flags
, int fmt
, struct lwp
*l
)
100 sc
= device_lookup_private(&pps_cd
, minor(dev
));
107 if (ppbus_request_bus(sc
->ppbus
, sc
->pps_dev
.sc_dev
,
108 PPBUS_WAIT
|PPBUS_INTR
, 0))
111 ppbus_write_ivar(sc
->ppbus
, PPBUS_IVAR_IEEE
, &weg
);
113 /* attach the interrupt handler */
114 /* XXX priority should be set here */
115 res
= ppbus_add_handler(sc
->ppbus
, ppsintr
, sc
);
117 ppbus_release_bus(sc
->ppbus
, sc
->pps_dev
.sc_dev
,
122 ppbus_set_mode(sc
->ppbus
, PPBUS_PS2
, 0);
123 ppbus_wctr(sc
->ppbus
, IRQENABLE
| PCD
| nINIT
| SELECTIN
);
125 mutex_spin_enter(&timecounter_lock
);
126 memset((void *)&sc
->pps_state
, 0, sizeof(sc
->pps_state
));
127 sc
->pps_state
.ppscap
= PPS_CAPTUREASSERT
;
128 pps_init(&sc
->pps_state
);
129 mutex_spin_exit(&timecounter_lock
);
137 ppsclose(dev_t dev
, int flags
, int fmt
, struct lwp
*l
)
139 struct pps_softc
*sc
= device_lookup_private(&pps_cd
, minor(dev
));
140 device_t ppbus
= sc
->ppbus
;
143 mutex_spin_enter(&timecounter_lock
);
144 sc
->pps_state
.ppsparam
.mode
= 0;
145 mutex_spin_exit(&timecounter_lock
);
147 ppbus_wdtr(ppbus
, 0);
148 ppbus_wctr(ppbus
, 0);
150 ppbus_remove_handler(ppbus
, ppsintr
);
151 ppbus_set_mode(ppbus
, PPBUS_COMPATIBLE
, 0);
152 ppbus_release_bus(ppbus
, sc
->pps_dev
.sc_dev
, PPBUS_WAIT
, 0);
159 struct pps_softc
*sc
= arg
;
160 device_t ppbus
= sc
->ppbus
;
162 mutex_spin_enter(&timecounter_lock
);
163 pps_capture(&sc
->pps_state
);
164 if (!(ppbus_rstr(ppbus
) & nACK
)) {
165 mutex_spin_exit(&timecounter_lock
);
168 if (sc
->pps_state
.ppsparam
.mode
& PPS_ECHOASSERT
)
169 ppbus_wctr(ppbus
, IRQENABLE
| AUTOFEED
);
170 pps_event(&sc
->pps_state
, PPS_CAPTUREASSERT
);
171 if (sc
->pps_state
.ppsparam
.mode
& PPS_ECHOASSERT
)
172 ppbus_wctr(ppbus
, IRQENABLE
);
173 mutex_spin_exit(&timecounter_lock
);
177 ppsioctl(dev_t dev
, u_long cmd
, void *data
, int flags
, struct lwp
*l
)
179 struct pps_softc
*sc
= device_lookup_private(&pps_cd
, minor(dev
));
184 case PPS_IOC_DESTROY
:
185 case PPS_IOC_GETPARAMS
:
186 case PPS_IOC_SETPARAMS
:
192 mutex_spin_enter(&timecounter_lock
);
193 error
= pps_ioctl(cmd
, data
, &sc
->pps_state
);
194 mutex_spin_exit(&timecounter_lock
);
198 error
= EPASSTHROUGH
;