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 * ----------------------------------------------------------------------------
9 * $FreeBSD: src/sys/dev/ppbus/pps.c,v 1.24.2.1 2000/05/24 00:20:57 n_hibma Exp $
10 * $DragonFly: src/sys/dev/misc/pps/pps.c,v 1.17 2006/10/25 20:55:55 dillon Exp $
12 * This driver implements a draft-mogul-pps-api-02.txt PPS source.
14 * The input pin is pin#10
15 * The echo output pin is pin#14
21 #include <sys/param.h>
22 #include <sys/kernel.h>
23 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/module.h>
28 #include <sys/timepps.h>
31 #include <bus/ppbus/ppbconf.h>
32 #include <bus/ppbus/ppbio.h>
36 #define PPS_NAME "pps" /* our official name */
40 struct ppb_device pps_dev
;
43 struct resource
*intr_resource
; /* interrupt resource */
44 void *intr_cookie
; /* interrupt registration cookie */
47 static void ppsintr(void *arg
);
49 #define DEVTOSOFTC(dev) \
50 ((struct pps_data *)device_get_softc(dev))
51 #define UNITOSOFTC(unit) \
52 ((struct pps_data *)devclass_get_softc(pps_devclass, (unit)))
53 #define UNITODEVICE(unit) \
54 (devclass_get_device(pps_devclass, (unit)))
56 static devclass_t pps_devclass
;
58 static d_open_t ppsopen
;
59 static d_close_t ppsclose
;
60 static d_ioctl_t ppsioctl
;
63 static struct dev_ops pps_ops
= {
64 { PPS_NAME
, CDEV_MAJOR
, 0 },
71 ppsprobe(device_t ppsdev
)
75 sc
= DEVTOSOFTC(ppsdev
);
76 bzero(sc
, sizeof(struct pps_data
));
78 device_set_desc(ppsdev
, "Pulse per second Timing Interface");
80 sc
->pps
.ppscap
= PPS_CAPTUREASSERT
| PPS_ECHOASSERT
;
86 ppsattach(device_t ppsdev
)
88 struct pps_data
*sc
= DEVTOSOFTC(ppsdev
);
89 device_t ppbus
= device_get_parent(ppsdev
);
94 /* retrieve the ppbus irq */
95 BUS_READ_IVAR(ppbus
, ppsdev
, PPBUS_IVAR_IRQ
, &irq
);
98 /* declare our interrupt handler */
99 sc
->intr_resource
= bus_alloc_resource(ppsdev
, SYS_RES_IRQ
,
100 &zero
, irq
, irq
, 1, RF_SHAREABLE
);
102 /* interrupts seem mandatory */
103 if (sc
->intr_resource
== 0)
106 unit
= device_get_unit(ppsdev
);
107 dev_ops_add(&pps_ops
, -1, unit
);
108 make_dev(&pps_ops
, unit
, UID_ROOT
, GID_WHEEL
, 0644,
109 PPS_NAME
"%d", unit
);
114 ppsopen(struct dev_open_args
*ap
)
116 cdev_t dev
= ap
->a_head
.a_dev
;
117 u_int unit
= minor(dev
);
118 struct pps_data
*sc
= UNITOSOFTC(unit
);
119 device_t ppsdev
= UNITODEVICE(unit
);
120 device_t ppbus
= device_get_parent(ppsdev
);
124 if (ppb_request_bus(ppbus
, ppsdev
, PPB_WAIT
|PPB_INTR
))
127 /* attach the interrupt handler */
128 if ((error
= BUS_SETUP_INTR(ppbus
, ppsdev
, sc
->intr_resource
,
130 &sc
->intr_cookie
, NULL
))) {
131 ppb_release_bus(ppbus
, ppsdev
);
136 ppb_wctr(ppbus
, IRQENABLE
);
144 ppsclose(struct dev_close_args
*ap
)
146 cdev_t dev
= ap
->a_head
.a_dev
;
147 u_int unit
= minor(dev
);
148 struct pps_data
*sc
= UNITOSOFTC(unit
);
149 device_t ppsdev
= UNITODEVICE(unit
);
150 device_t ppbus
= device_get_parent(ppsdev
);
152 sc
->pps
.ppsparam
.mode
= 0; /* PHK ??? */
157 /* Note: the interrupt handler is automatically detached */
158 ppb_release_bus(ppbus
, ppsdev
);
166 device_t ppsdev
= (device_t
)arg
;
167 device_t ppbus
= device_get_parent(ppsdev
);
168 struct pps_data
*sc
= DEVTOSOFTC(ppsdev
);
171 count
= sys_cputimer
->count();
172 if (!(ppb_rstr(ppbus
) & nACK
))
174 if (sc
->pps
.ppsparam
.mode
& PPS_ECHOASSERT
)
175 ppb_wctr(ppbus
, IRQENABLE
| AUTOFEED
);
176 pps_event(&sc
->pps
, count
, PPS_CAPTUREASSERT
);
177 if (sc
->pps
.ppsparam
.mode
& PPS_ECHOASSERT
)
178 ppb_wctr(ppbus
, IRQENABLE
);
182 ppsioctl(struct dev_ioctl_args
*ap
)
184 cdev_t dev
= ap
->a_head
.a_dev
;
185 u_int unit
= minor(dev
);
186 struct pps_data
*sc
= UNITOSOFTC(unit
);
188 return (pps_ioctl(ap
->a_cmd
, ap
->a_data
, &sc
->pps
));
192 * Becuase pps is a static device under any attached ppbus, and not scanned
193 * by the ppbus, we need an identify function to create the device.
195 static device_method_t pps_methods
[] = {
196 /* device interface */
197 DEVMETHOD(device_identify
, bus_generic_identify
),
198 DEVMETHOD(device_probe
, ppsprobe
),
199 DEVMETHOD(device_attach
, ppsattach
),
204 static driver_t pps_driver
= {
207 sizeof(struct pps_data
),
209 DRIVER_MODULE(pps
, ppbus
, pps_driver
, pps_devclass
, 0, 0);