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