1507e2e44SPoul-Henning Kamp /* 2507e2e44SPoul-Henning Kamp * ---------------------------------------------------------------------------- 3507e2e44SPoul-Henning Kamp * "THE BEER-WARE LICENSE" (Revision 42): 4507e2e44SPoul-Henning Kamp * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 5507e2e44SPoul-Henning Kamp * can do whatever you want with this stuff. If we meet some day, and you think 6507e2e44SPoul-Henning Kamp * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7507e2e44SPoul-Henning Kamp * ---------------------------------------------------------------------------- 8507e2e44SPoul-Henning Kamp * 91a03ce6cSPoul-Henning Kamp * $Id: pps.c,v 1.19 1999/05/31 11:25:00 phk Exp $ 10389825d5SPoul-Henning Kamp * 11389825d5SPoul-Henning Kamp * This driver implements a draft-mogul-pps-api-02.txt PPS source. 12389825d5SPoul-Henning Kamp * 13389825d5SPoul-Henning Kamp * The input pin is pin#10 14389825d5SPoul-Henning Kamp * The echo output pin is pin#14 15507e2e44SPoul-Henning Kamp * 16507e2e44SPoul-Henning Kamp */ 17507e2e44SPoul-Henning Kamp 18507e2e44SPoul-Henning Kamp #include <sys/param.h> 19507e2e44SPoul-Henning Kamp #include <sys/kernel.h> 20507e2e44SPoul-Henning Kamp #include <sys/systm.h> 21507e2e44SPoul-Henning Kamp #include <sys/conf.h> 228afeddf0SPoul-Henning Kamp #include <sys/timepps.h> 23507e2e44SPoul-Henning Kamp #include <sys/malloc.h> 24507e2e44SPoul-Henning Kamp 25507e2e44SPoul-Henning Kamp #include <dev/ppbus/ppbconf.h> 26cc732491SPoul-Henning Kamp #include "pps.h" 27507e2e44SPoul-Henning Kamp 281a03ce6cSPoul-Henning Kamp #define PPS_NAME "pps" /* our official name */ 29507e2e44SPoul-Henning Kamp 301a03ce6cSPoul-Henning Kamp struct pps_data { 31477f9db3SPoul-Henning Kamp int pps_open; 3295f0f58cSPoul-Henning Kamp struct ppb_device pps_dev; 3332c20357SPoul-Henning Kamp struct pps_state pps; 341a03ce6cSPoul-Henning Kamp }; 35507e2e44SPoul-Henning Kamp 3695f0f58cSPoul-Henning Kamp static int npps; 37507e2e44SPoul-Henning Kamp 38507e2e44SPoul-Henning Kamp /* 39507e2e44SPoul-Henning Kamp * Make ourselves visible as a ppbus driver 40507e2e44SPoul-Henning Kamp */ 41507e2e44SPoul-Henning Kamp 4295f0f58cSPoul-Henning Kamp static struct ppb_device *ppsprobe(struct ppb_data *ppb); 4395f0f58cSPoul-Henning Kamp static int ppsattach(struct ppb_device *dev); 441a03ce6cSPoul-Henning Kamp static void ppsintr(struct ppb_device *ppd); 45507e2e44SPoul-Henning Kamp 4695f0f58cSPoul-Henning Kamp static struct ppb_driver ppsdriver = { 4795f0f58cSPoul-Henning Kamp ppsprobe, ppsattach, PPS_NAME 48507e2e44SPoul-Henning Kamp }; 49507e2e44SPoul-Henning Kamp 5095f0f58cSPoul-Henning Kamp DATA_SET(ppbdriver_set, ppsdriver); 51507e2e44SPoul-Henning Kamp 5295f0f58cSPoul-Henning Kamp static d_open_t ppsopen; 5395f0f58cSPoul-Henning Kamp static d_close_t ppsclose; 548afeddf0SPoul-Henning Kamp static d_ioctl_t ppsioctl; 55507e2e44SPoul-Henning Kamp 56507e2e44SPoul-Henning Kamp #define CDEV_MAJOR 89 574e2f199eSPoul-Henning Kamp static struct cdevsw pps_cdevsw = { 584e2f199eSPoul-Henning Kamp /* open */ ppsopen, 594e2f199eSPoul-Henning Kamp /* close */ ppsclose, 604e2f199eSPoul-Henning Kamp /* read */ noread, 614e2f199eSPoul-Henning Kamp /* write */ nowrite, 624e2f199eSPoul-Henning Kamp /* ioctl */ ppsioctl, 634e2f199eSPoul-Henning Kamp /* stop */ nostop, 644e2f199eSPoul-Henning Kamp /* reset */ noreset, 654e2f199eSPoul-Henning Kamp /* devtotty */ nodevtotty, 664e2f199eSPoul-Henning Kamp /* poll */ nopoll, 674e2f199eSPoul-Henning Kamp /* mmap */ nommap, 684e2f199eSPoul-Henning Kamp /* strategy */ nostrategy, 694e2f199eSPoul-Henning Kamp /* name */ PPS_NAME, 704e2f199eSPoul-Henning Kamp /* parms */ noparms, 714e2f199eSPoul-Henning Kamp /* maj */ CDEV_MAJOR, 724e2f199eSPoul-Henning Kamp /* dump */ nodump, 734e2f199eSPoul-Henning Kamp /* psize */ nopsize, 744e2f199eSPoul-Henning Kamp /* flags */ 0, 754e2f199eSPoul-Henning Kamp /* maxio */ 0, 764e2f199eSPoul-Henning Kamp /* bmaj */ -1 774e2f199eSPoul-Henning Kamp }; 78507e2e44SPoul-Henning Kamp 7932c20357SPoul-Henning Kamp 80507e2e44SPoul-Henning Kamp static struct ppb_device * 8195f0f58cSPoul-Henning Kamp ppsprobe(struct ppb_data *ppb) 82507e2e44SPoul-Henning Kamp { 8395f0f58cSPoul-Henning Kamp struct pps_data *sc; 842447bec8SPoul-Henning Kamp static int once; 851a03ce6cSPoul-Henning Kamp dev_t dev; 862447bec8SPoul-Henning Kamp 872447bec8SPoul-Henning Kamp if (!once++) 882447bec8SPoul-Henning Kamp cdevsw_add(&pps_cdevsw); 89507e2e44SPoul-Henning Kamp 9095f0f58cSPoul-Henning Kamp sc = (struct pps_data *) malloc(sizeof(struct pps_data), 91507e2e44SPoul-Henning Kamp M_TEMP, M_NOWAIT); 92507e2e44SPoul-Henning Kamp if (!sc) { 93cc732491SPoul-Henning Kamp printf(PPS_NAME ": cannot malloc!\n"); 94507e2e44SPoul-Henning Kamp return (0); 95507e2e44SPoul-Henning Kamp } 9695f0f58cSPoul-Henning Kamp bzero(sc, sizeof(struct pps_data)); 97507e2e44SPoul-Henning Kamp 981a03ce6cSPoul-Henning Kamp dev = make_dev(&pps_cdevsw, npps, 991a03ce6cSPoul-Henning Kamp UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", npps); 100507e2e44SPoul-Henning Kamp 1011a03ce6cSPoul-Henning Kamp dev->si_drv1 = sc; 102507e2e44SPoul-Henning Kamp 1031a03ce6cSPoul-Henning Kamp sc->pps_dev.id_unit = npps++; 10495f0f58cSPoul-Henning Kamp sc->pps_dev.ppb = ppb; 10546f3ff79SMike Smith sc->pps_dev.name = ppsdriver.name; 1061a03ce6cSPoul-Henning Kamp sc->pps_dev.bintr = ppsintr; 1071a03ce6cSPoul-Henning Kamp sc->pps_dev.drv1 = sc; 108507e2e44SPoul-Henning Kamp 10932c20357SPoul-Henning Kamp sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 11032c20357SPoul-Henning Kamp pps_init(&sc->pps); 11195f0f58cSPoul-Henning Kamp return (&sc->pps_dev); 112507e2e44SPoul-Henning Kamp } 113507e2e44SPoul-Henning Kamp 114507e2e44SPoul-Henning Kamp static int 11595f0f58cSPoul-Henning Kamp ppsattach(struct ppb_device *dev) 116507e2e44SPoul-Henning Kamp { 11732c20357SPoul-Henning Kamp 118507e2e44SPoul-Henning Kamp /* 119507e2e44SPoul-Henning Kamp * Report ourselves 120507e2e44SPoul-Henning Kamp */ 121cc732491SPoul-Henning Kamp printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 122507e2e44SPoul-Henning Kamp dev->id_unit, dev->ppb->ppb_link->adapter_unit); 123507e2e44SPoul-Henning Kamp 124507e2e44SPoul-Henning Kamp return (1); 125507e2e44SPoul-Henning Kamp } 126507e2e44SPoul-Henning Kamp 127507e2e44SPoul-Henning Kamp static int 12895f0f58cSPoul-Henning Kamp ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 129507e2e44SPoul-Henning Kamp { 13095f0f58cSPoul-Henning Kamp struct pps_data *sc; 131507e2e44SPoul-Henning Kamp u_int unit = minor(dev); 132507e2e44SPoul-Henning Kamp 13395f0f58cSPoul-Henning Kamp if ((unit >= npps)) 134507e2e44SPoul-Henning Kamp return (ENXIO); 135507e2e44SPoul-Henning Kamp 1361a03ce6cSPoul-Henning Kamp sc = dev->si_drv1; 137507e2e44SPoul-Henning Kamp 138477f9db3SPoul-Henning Kamp if (!sc->pps_open) { 13995f0f58cSPoul-Henning Kamp if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 140507e2e44SPoul-Henning Kamp return (EINTR); 141507e2e44SPoul-Henning Kamp 14220240fa3SNicolas Souchu ppb_wctr(&sc->pps_dev, 0); 1438afeddf0SPoul-Henning Kamp ppb_wctr(&sc->pps_dev, IRQENABLE); 144477f9db3SPoul-Henning Kamp sc->pps_open = 1; 145477f9db3SPoul-Henning Kamp } 146507e2e44SPoul-Henning Kamp 147507e2e44SPoul-Henning Kamp return(0); 148507e2e44SPoul-Henning Kamp } 149507e2e44SPoul-Henning Kamp 150507e2e44SPoul-Henning Kamp static int 15195f0f58cSPoul-Henning Kamp ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 152507e2e44SPoul-Henning Kamp { 1531a03ce6cSPoul-Henning Kamp struct pps_data *sc = dev->si_drv1; 154507e2e44SPoul-Henning Kamp 15532c20357SPoul-Henning Kamp sc->pps.ppsparam.mode = 0; /* PHK ??? */ 15620240fa3SNicolas Souchu 15720240fa3SNicolas Souchu ppb_wdtr(&sc->pps_dev, 0); 15820240fa3SNicolas Souchu ppb_wctr(&sc->pps_dev, 0); 15920240fa3SNicolas Souchu 16095f0f58cSPoul-Henning Kamp ppb_release_bus(&sc->pps_dev); 161477f9db3SPoul-Henning Kamp sc->pps_open = 0; 162507e2e44SPoul-Henning Kamp return(0); 163507e2e44SPoul-Henning Kamp } 164507e2e44SPoul-Henning Kamp 165507e2e44SPoul-Henning Kamp static void 1661a03ce6cSPoul-Henning Kamp ppsintr(struct ppb_device *ppd) 167507e2e44SPoul-Henning Kamp { 1681a03ce6cSPoul-Henning Kamp struct pps_data *sc = ppd->drv1; 16932c20357SPoul-Henning Kamp struct timecounter *tc; 17032c20357SPoul-Henning Kamp unsigned count; 171507e2e44SPoul-Henning Kamp 17232c20357SPoul-Henning Kamp tc = timecounter; 17332c20357SPoul-Henning Kamp count = timecounter->tc_get_timecount(tc); 17495f0f58cSPoul-Henning Kamp if (!(ppb_rstr(&sc->pps_dev) & nACK)) 175507e2e44SPoul-Henning Kamp return; 17632c20357SPoul-Henning Kamp if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 1778afeddf0SPoul-Henning Kamp ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); 17832c20357SPoul-Henning Kamp pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 17932c20357SPoul-Henning Kamp if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 1808afeddf0SPoul-Henning Kamp ppb_wctr(&sc->pps_dev, IRQENABLE); 181507e2e44SPoul-Henning Kamp } 182507e2e44SPoul-Henning Kamp 183507e2e44SPoul-Henning Kamp static int 184ceeea6b9SBruce Evans ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 185507e2e44SPoul-Henning Kamp { 1861a03ce6cSPoul-Henning Kamp struct pps_data *sc = dev->si_drv1; 187507e2e44SPoul-Henning Kamp 18832c20357SPoul-Henning Kamp return (pps_ioctl(cmd, data, &sc->pps)); 1898afeddf0SPoul-Henning Kamp } 190507e2e44SPoul-Henning Kamp 191