pps.c (51658) | pps.c (55939) |
---|---|
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 * | 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 * $FreeBSD: head/sys/dev/ppbus/pps.c 51658 1999-09-25 18:24:47Z phk $ | 9 * $FreeBSD: head/sys/dev/ppbus/pps.c 55939 2000-01-14 00:18:06Z nsouch $ |
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 <sys/param.h> 19#include <sys/kernel.h> 20#include <sys/systm.h> | 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 <sys/param.h> 19#include <sys/kernel.h> 20#include <sys/systm.h> |
21#include <sys/module.h> 22#include <sys/bus.h> |
|
21#include <sys/conf.h> 22#include <sys/timepps.h> 23#include <sys/malloc.h> | 23#include <sys/conf.h> 24#include <sys/timepps.h> 25#include <sys/malloc.h> |
26#include <machine/bus.h> 27#include <machine/resource.h> 28#include <sys/rman.h> |
|
24 25#include <dev/ppbus/ppbconf.h> | 29 30#include <dev/ppbus/ppbconf.h> |
31#include "ppbus_if.h" 32#include <dev/ppbus/ppbio.h> |
|
26#include "pps.h" 27 28#define PPS_NAME "pps" /* our official name */ 29 30struct pps_data { 31 int pps_open; 32 struct ppb_device pps_dev; 33 struct pps_state pps; | 33#include "pps.h" 34 35#define PPS_NAME "pps" /* our official name */ 36 37struct pps_data { 38 int pps_open; 39 struct ppb_device pps_dev; 40 struct pps_state pps; |
41 42 struct resource *intr_resource; /* interrupt resource */ 43 void *intr_cookie; /* interrupt registration cookie */ |
|
34}; 35 | 44}; 45 |
36static int npps; | 46static int ppsprobe(device_t dev); 47static int ppsattach(device_t dev); 48static void ppsintr(void *arg); |
37 | 49 |
38/* 39 * Make ourselves visible as a ppbus driver 40 */ | 50#define DEVTOSOFTC(dev) \ 51 ((struct pps_data *)device_get_softc(dev)) 52#define UNITOSOFTC(unit) \ 53 ((struct pps_data *)devclass_get_softc(pps_devclass, (unit))) 54#define UNITODEVICE(unit) \ 55 (devclass_get_device(pps_devclass, (unit))) |
41 | 56 |
42static struct ppb_device *ppsprobe(struct ppb_data *ppb); 43static int ppsattach(struct ppb_device *dev); 44static void ppsintr(struct ppb_device *ppd); | 57static devclass_t pps_devclass; |
45 | 58 |
46static struct ppb_driver ppsdriver = { 47 ppsprobe, ppsattach, PPS_NAME | 59static device_method_t pps_methods[] = { 60 /* device interface */ 61 DEVMETHOD(device_probe, ppsprobe), 62 DEVMETHOD(device_attach, ppsattach), 63 64 { 0, 0 } |
48}; 49 | 65}; 66 |
50DATA_SET(ppbdriver_set, ppsdriver); | 67static driver_t pps_driver = { 68 PPS_NAME, 69 pps_methods, 70 sizeof(struct pps_data), 71}; |
51 52static d_open_t ppsopen; 53static d_close_t ppsclose; 54static d_ioctl_t ppsioctl; 55 56#define CDEV_MAJOR 89 57static struct cdevsw pps_cdevsw = { 58 /* open */ ppsopen, --- 7 unchanged lines hidden (view full) --- 66 /* name */ PPS_NAME, 67 /* maj */ CDEV_MAJOR, 68 /* dump */ nodump, 69 /* psize */ nopsize, 70 /* flags */ 0, 71 /* bmaj */ -1 72}; 73 | 72 73static d_open_t ppsopen; 74static d_close_t ppsclose; 75static d_ioctl_t ppsioctl; 76 77#define CDEV_MAJOR 89 78static struct cdevsw pps_cdevsw = { 79 /* open */ ppsopen, --- 7 unchanged lines hidden (view full) --- 87 /* name */ PPS_NAME, 88 /* maj */ CDEV_MAJOR, 89 /* dump */ nodump, 90 /* psize */ nopsize, 91 /* flags */ 0, 92 /* bmaj */ -1 93}; 94 |
74 75static struct ppb_device * 76ppsprobe(struct ppb_data *ppb) | 95static int 96ppsprobe(device_t ppsdev) |
77{ 78 struct pps_data *sc; 79 static int once; 80 dev_t dev; | 97{ 98 struct pps_data *sc; 99 static int once; 100 dev_t dev; |
101 int unit; |
|
81 82 if (!once++) 83 cdevsw_add(&pps_cdevsw); 84 | 102 103 if (!once++) 104 cdevsw_add(&pps_cdevsw); 105 |
85 sc = (struct pps_data *) malloc(sizeof(struct pps_data), 86 M_TEMP, M_NOWAIT); 87 if (!sc) { 88 printf(PPS_NAME ": cannot malloc!\n"); 89 return (0); 90 } | 106 sc = DEVTOSOFTC(ppsdev); |
91 bzero(sc, sizeof(struct pps_data)); 92 | 107 bzero(sc, sizeof(struct pps_data)); 108 |
93 dev = make_dev(&pps_cdevsw, npps, 94 UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", npps); | 109 unit = device_get_unit(ppsdev); 110 dev = make_dev(&pps_cdevsw, unit, 111 UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", unit); |
95 | 112 |
96 dev->si_drv1 = sc; | 113 device_set_desc(ppsdev, "Pulse per second Timing Interface"); |
97 | 114 |
98 sc->pps_dev.id_unit = npps++; 99 sc->pps_dev.ppb = ppb; 100 sc->pps_dev.name = ppsdriver.name; 101 sc->pps_dev.bintr = ppsintr; 102 sc->pps_dev.drv1 = sc; 103 | |
104 sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 105 pps_init(&sc->pps); | 115 sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 116 pps_init(&sc->pps); |
106 return (&sc->pps_dev); | 117 return (0); |
107} 108 109static int | 118} 119 120static int |
110ppsattach(struct ppb_device *dev) | 121ppsattach(device_t dev) |
111{ | 122{ |
123 struct pps_data *sc = DEVTOSOFTC(dev); 124 device_t ppbus = device_get_parent(dev); 125 int irq, zero = 0; |
|
112 | 126 |
113 /* 114 * Report ourselves 115 */ 116 printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 117 dev->id_unit, dev->ppb->ppb_link->adapter_unit); | 127 /* retrieve the ppbus irq */ 128 BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); |
118 | 129 |
119 return (1); | 130 if (irq > 0) { 131 /* declare our interrupt handler */ 132 sc->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, 133 &zero, irq, irq, 1, RF_SHAREABLE); 134 } 135 /* interrupts seem mandatory */ 136 if (sc->intr_resource == 0) 137 return (ENXIO); 138 139 return (0); |
120} 121 122static int 123ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 124{ | 140} 141 142static int 143ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 144{ |
125 struct pps_data *sc; | |
126 u_int unit = minor(dev); | 145 u_int unit = minor(dev); |
146 struct pps_data *sc = UNITOSOFTC(unit); 147 device_t ppsdev = UNITODEVICE(unit); 148 device_t ppbus = device_get_parent(ppsdev); 149 int error; |
|
127 | 150 |
128 if ((unit >= npps)) 129 return (ENXIO); 130 131 sc = dev->si_drv1; 132 | |
133 if (!sc->pps_open) { | 151 if (!sc->pps_open) { |
134 if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) | 152 if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) |
135 return (EINTR); 136 | 153 return (EINTR); 154 |
137 ppb_wctr(&sc->pps_dev, 0); 138 ppb_wctr(&sc->pps_dev, IRQENABLE); | 155 /* attach the interrupt handler */ 156 if ((error = BUS_SETUP_INTR(ppbus, ppsdev, sc->intr_resource, 157 INTR_TYPE_TTY, ppsintr, ppsdev, 158 &sc->intr_cookie))) { 159 ppb_release_bus(ppbus, ppsdev); 160 return (error); 161 } 162 163 ppb_wctr(ppbus, 0); 164 ppb_wctr(ppbus, IRQENABLE); |
139 sc->pps_open = 1; 140 } 141 142 return(0); 143} 144 145static int 146ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 147{ | 165 sc->pps_open = 1; 166 } 167 168 return(0); 169} 170 171static int 172ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 173{ |
148 struct pps_data *sc = dev->si_drv1; | 174 u_int unit = minor(dev); 175 struct pps_data *sc = UNITOSOFTC(unit); 176 device_t ppsdev = UNITODEVICE(unit); 177 device_t ppbus = device_get_parent(ppsdev); |
149 150 sc->pps.ppsparam.mode = 0; /* PHK ??? */ 151 | 178 179 sc->pps.ppsparam.mode = 0; /* PHK ??? */ 180 |
152 ppb_wdtr(&sc->pps_dev, 0); 153 ppb_wctr(&sc->pps_dev, 0); | 181 ppb_wdtr(ppbus, 0); 182 ppb_wctr(ppbus, 0); |
154 | 183 |
155 ppb_release_bus(&sc->pps_dev); | 184 /* Note: the interrupt handler is automatically detached */ 185 ppb_release_bus(ppbus, ppsdev); |
156 sc->pps_open = 0; 157 return(0); 158} 159 160static void | 186 sc->pps_open = 0; 187 return(0); 188} 189 190static void |
161ppsintr(struct ppb_device *ppd) | 191ppsintr(void *arg) |
162{ | 192{ |
163 struct pps_data *sc = ppd->drv1; | 193 device_t ppsdev = (device_t)arg; 194 device_t ppbus = device_get_parent(ppsdev); 195 struct pps_data *sc = DEVTOSOFTC(ppsdev); |
164 struct timecounter *tc; 165 unsigned count; 166 167 tc = timecounter; 168 count = timecounter->tc_get_timecount(tc); | 196 struct timecounter *tc; 197 unsigned count; 198 199 tc = timecounter; 200 count = timecounter->tc_get_timecount(tc); |
169 if (!(ppb_rstr(&sc->pps_dev) & nACK)) | 201 if (!(ppb_rstr(ppbus) & nACK)) |
170 return; 171 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) | 202 return; 203 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) |
172 ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); | 204 ppb_wctr(ppbus, IRQENABLE | AUTOFEED); |
173 pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 174 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) | 205 pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 206 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) |
175 ppb_wctr(&sc->pps_dev, IRQENABLE); | 207 ppb_wctr(ppbus, IRQENABLE); |
176} 177 178static int 179ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 180{ | 208} 209 210static int 211ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 212{ |
181 struct pps_data *sc = dev->si_drv1; | 213 u_int unit = minor(dev); 214 struct pps_data *sc = UNITOSOFTC(unit); |
182 183 return (pps_ioctl(cmd, data, &sc->pps)); 184} 185 | 215 216 return (pps_ioctl(cmd, data, &sc->pps)); 217} 218 |
219DRIVER_MODULE(pps, ppbus, pps_driver, pps_devclass, 0, 0); |
|