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 * 10 * This driver implements a draft-mogul-pps-api-02.txt PPS source. 11 * 12 * The input pin is pin#10 13 * The echo output pin is pin#14 14 * 15 */ 16 17 #include <sys/cdefs.h> 18 __FBSDID("$FreeBSD$"); 19 20 #include <sys/param.h> 21 #include <sys/kernel.h> 22 #include <sys/systm.h> 23 #include <sys/module.h> 24 #include <sys/bus.h> 25 #include <sys/conf.h> 26 #include <sys/timepps.h> 27 #include <machine/bus.h> 28 #include <machine/resource.h> 29 #include <sys/rman.h> 30 31 #include <dev/ppbus/ppbconf.h> 32 #include "ppbus_if.h" 33 #include <dev/ppbus/ppbio.h> 34 35 #define PPS_NAME "pps" /* our official name */ 36 37 #define PRVERBOSE(fmt, arg...) if (bootverbose) printf(fmt, ##arg); 38 39 struct pps_data { 40 struct ppb_device pps_dev; 41 struct pps_state pps[9]; 42 struct cdev *devs[9]; 43 device_t ppsdev; 44 device_t ppbus; 45 int busy; 46 struct callout_handle timeout; 47 int lastdata; 48 49 struct mtx mtx; 50 struct resource *intr_resource; /* interrupt resource */ 51 void *intr_cookie; /* interrupt registration cookie */ 52 }; 53 54 static int ppsintr(void *arg); 55 static void ppshcpoll(void *arg); 56 57 #define DEVTOSOFTC(dev) \ 58 ((struct pps_data *)device_get_softc(dev)) 59 60 static devclass_t pps_devclass; 61 62 static d_open_t ppsopen; 63 static d_close_t ppsclose; 64 static d_ioctl_t ppsioctl; 65 66 static struct cdevsw pps_cdevsw = { 67 .d_version = D_VERSION, 68 .d_open = ppsopen, 69 .d_close = ppsclose, 70 .d_ioctl = ppsioctl, 71 .d_name = PPS_NAME, 72 }; 73 74 static void 75 ppsidentify(driver_t *driver, device_t parent) 76 { 77 78 device_t dev; 79 80 dev = device_find_child(parent, PPS_NAME, 0); 81 if (!dev) 82 BUS_ADD_CHILD(parent, 0, PPS_NAME, -1); 83 } 84 85 static int 86 ppstry(device_t ppbus, int send, int expect) 87 { 88 int i; 89 90 ppb_wdtr(ppbus, send); 91 i = ppb_rdtr(ppbus); 92 PRVERBOSE("S: %02x E: %02x G: %02x\n", send, expect, i); 93 return (i != expect); 94 } 95 96 static int 97 ppsprobe(device_t ppsdev) 98 { 99 device_set_desc(ppsdev, "Pulse per second Timing Interface"); 100 101 return (0); 102 } 103 104 static int 105 ppsattach(device_t dev) 106 { 107 struct pps_data *sc = DEVTOSOFTC(dev); 108 device_t ppbus = device_get_parent(dev); 109 struct cdev *d; 110 intptr_t irq; 111 int i, unit, zero = 0; 112 113 mtx_init(&sc->mtx, device_get_nameunit(dev), "pps", MTX_SPIN); 114 /* retrieve the ppbus irq */ 115 BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); 116 117 if (irq > 0) { 118 /* declare our interrupt handler */ 119 sc->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, 120 &zero, irq, irq, 1, RF_SHAREABLE); 121 } 122 /* interrupts seem mandatory */ 123 if (sc->intr_resource == NULL) 124 return (ENXIO); 125 126 sc->ppsdev = dev; 127 sc->ppbus = ppbus; 128 unit = device_get_unit(ppbus); 129 d = make_dev(&pps_cdevsw, unit, 130 UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", unit); 131 sc->devs[0] = d; 132 sc->pps[0].ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 133 d->si_drv1 = sc; 134 d->si_drv2 = (void*)0; 135 pps_init(&sc->pps[0]); 136 137 if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) 138 return (0); 139 140 do { 141 i = ppb_set_mode(sc->ppbus, PPB_EPP); 142 PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus)); 143 if (i == -1) 144 break; 145 i = 0; 146 ppb_wctr(ppbus, i); 147 if (ppstry(ppbus, 0x00, 0x00)) 148 break; 149 if (ppstry(ppbus, 0x55, 0x55)) 150 break; 151 if (ppstry(ppbus, 0xaa, 0xaa)) 152 break; 153 if (ppstry(ppbus, 0xff, 0xff)) 154 break; 155 156 i = IRQENABLE | PCD | STROBE | nINIT | SELECTIN; 157 ppb_wctr(ppbus, i); 158 PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i); 159 if (ppstry(ppbus, 0x00, 0x00)) 160 break; 161 if (ppstry(ppbus, 0x55, 0x00)) 162 break; 163 if (ppstry(ppbus, 0xaa, 0x00)) 164 break; 165 if (ppstry(ppbus, 0xff, 0x00)) 166 break; 167 168 i = IRQENABLE | PCD | nINIT | SELECTIN; 169 ppb_wctr(ppbus, i); 170 PRVERBOSE("CTR = %02x (%02x)\n", ppb_rctr(ppbus), i); 171 ppstry(ppbus, 0x00, 0xff); 172 ppstry(ppbus, 0x55, 0xff); 173 ppstry(ppbus, 0xaa, 0xff); 174 ppstry(ppbus, 0xff, 0xff); 175 176 for (i = 1; i < 9; i++) { 177 d = make_dev(&pps_cdevsw, unit + 0x10000 * i, 178 UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%db%d", unit, i - 1); 179 sc->devs[i] = d; 180 sc->pps[i].ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; 181 d->si_drv1 = sc; 182 d->si_drv2 = (void *)(intptr_t)i; 183 pps_init(&sc->pps[i]); 184 } 185 } while (0); 186 i = ppb_set_mode(sc->ppbus, PPB_COMPATIBLE); 187 ppb_release_bus(ppbus, dev); 188 189 return (0); 190 } 191 192 static int 193 ppsopen(struct cdev *dev, int flags, int fmt, struct thread *td) 194 { 195 struct pps_data *sc = dev->si_drv1; 196 int subdev = (intptr_t)dev->si_drv2; 197 int error, i; 198 199 if (!sc->busy) { 200 device_t ppsdev = sc->ppsdev; 201 device_t ppbus = sc->ppbus; 202 203 if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) 204 return (EINTR); 205 206 /* attach the interrupt handler */ 207 if ((error = bus_setup_intr(ppsdev, sc->intr_resource, 208 (INTR_TYPE_TTY | INTR_MPSAFE), ppsintr, NULL, 209 sc, &sc->intr_cookie))) { 210 ppb_release_bus(ppbus, ppsdev); 211 return (error); 212 } 213 214 i = ppb_set_mode(sc->ppbus, PPB_PS2); 215 PRVERBOSE("EPP: %d %d\n", i, PPB_IN_EPP_MODE(sc->ppbus)); 216 217 i = IRQENABLE | PCD | nINIT | SELECTIN; 218 ppb_wctr(ppbus, i); 219 } 220 if (subdev > 0 && !(sc->busy & ~1)) { 221 sc->timeout = timeout(ppshcpoll, sc, 1); 222 sc->lastdata = ppb_rdtr(sc->ppbus); 223 } 224 sc->busy |= (1 << subdev); 225 return(0); 226 } 227 228 static int 229 ppsclose(struct cdev *dev, int flags, int fmt, struct thread *td) 230 { 231 struct pps_data *sc = dev->si_drv1; 232 int subdev = (intptr_t)dev->si_drv2; 233 234 sc->pps[subdev].ppsparam.mode = 0; /* PHK ??? */ 235 sc->busy &= ~(1 << subdev); 236 if (subdev > 0 && !(sc->busy & ~1)) 237 untimeout(ppshcpoll, sc, sc->timeout); 238 if (!sc->busy) { 239 device_t ppsdev = sc->ppsdev; 240 device_t ppbus = sc->ppbus; 241 242 ppb_wdtr(ppbus, 0); 243 ppb_wctr(ppbus, 0); 244 245 /* Note: the interrupt handler is automatically detached */ 246 ppb_set_mode(ppbus, PPB_COMPATIBLE); 247 ppb_release_bus(ppbus, ppsdev); 248 } 249 return(0); 250 } 251 252 static void 253 ppshcpoll(void *arg) 254 { 255 struct pps_data *sc = arg; 256 int i, j, k, l; 257 258 if (!(sc->busy & ~1)) 259 return; 260 mtx_lock_spin(&sc->mtx); 261 sc->timeout = timeout(ppshcpoll, sc, 1); 262 i = ppb_rdtr(sc->ppbus); 263 if (i == sc->lastdata) 264 return; 265 l = sc->lastdata ^ i; 266 k = 1; 267 for (j = 1; j < 9; j ++) { 268 if (l & k) { 269 pps_capture(&sc->pps[j]); 270 pps_event(&sc->pps[j], 271 i & k ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); 272 } 273 k += k; 274 } 275 sc->lastdata = i; 276 mtx_unlock_spin(&sc->mtx); 277 } 278 279 static int 280 ppsintr(void *arg) 281 { 282 struct pps_data *sc = (struct pps_data *)arg; 283 284 pps_capture(&sc->pps[0]); 285 if (!(ppb_rstr(sc->ppbus) & nACK)) 286 return (FILTER_STRAY); 287 if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) 288 ppb_wctr(sc->ppbus, IRQENABLE | AUTOFEED); 289 mtx_lock_spin(&sc->mtx); 290 pps_event(&sc->pps[0], PPS_CAPTUREASSERT); 291 mtx_unlock_spin(&sc->mtx); 292 if (sc->pps[0].ppsparam.mode & PPS_ECHOASSERT) 293 ppb_wctr(sc->ppbus, IRQENABLE); 294 return (FILTER_HANDLED); 295 } 296 297 static int 298 ppsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) 299 { 300 struct pps_data *sc = dev->si_drv1; 301 int subdev = (intptr_t)dev->si_drv2; 302 int err; 303 304 mtx_lock_spin(&sc->mtx); 305 err = pps_ioctl(cmd, data, &sc->pps[subdev]); 306 mtx_unlock_spin(&sc->mtx); 307 return (err); 308 } 309 310 static device_method_t pps_methods[] = { 311 /* device interface */ 312 DEVMETHOD(device_identify, ppsidentify), 313 DEVMETHOD(device_probe, ppsprobe), 314 DEVMETHOD(device_attach, ppsattach), 315 316 { 0, 0 } 317 }; 318 319 static driver_t pps_driver = { 320 PPS_NAME, 321 pps_methods, 322 sizeof(struct pps_data), 323 }; 324 DRIVER_MODULE(pps, ppbus, pps_driver, pps_devclass, 0, 0); 325 MODULE_DEPEND(pps, ppbus, 1, 1, 1); 326