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 * 920240fa3SNicolas Souchu * $Id: pps.c,v 1.12 1998/12/07 21:58:16 archie 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 1895f0f58cSPoul-Henning Kamp #include "opt_devfs.h" 1920240fa3SNicolas Souchu #include "opt_ntp.h" 2095f0f58cSPoul-Henning Kamp 21507e2e44SPoul-Henning Kamp #include <sys/param.h> 22507e2e44SPoul-Henning Kamp #include <sys/kernel.h> 23507e2e44SPoul-Henning Kamp #include <sys/systm.h> 24507e2e44SPoul-Henning Kamp #include <sys/conf.h> 258afeddf0SPoul-Henning Kamp #include <sys/timepps.h> 26507e2e44SPoul-Henning Kamp #ifdef DEVFS 27507e2e44SPoul-Henning Kamp #include <sys/devfsext.h> 2895f0f58cSPoul-Henning Kamp #endif 29507e2e44SPoul-Henning Kamp #include <sys/malloc.h> 30507e2e44SPoul-Henning Kamp 31507e2e44SPoul-Henning Kamp #include <dev/ppbus/ppbconf.h> 32cc732491SPoul-Henning Kamp #include "pps.h" 33507e2e44SPoul-Henning Kamp 348afeddf0SPoul-Henning Kamp #define PPS_NAME "lppps" /* our official name */ 35507e2e44SPoul-Henning Kamp 3695f0f58cSPoul-Henning Kamp static struct pps_data { 3795f0f58cSPoul-Henning Kamp int pps_unit; 3895f0f58cSPoul-Henning Kamp struct ppb_device pps_dev; 398afeddf0SPoul-Henning Kamp pps_params_t ppsparam; 408afeddf0SPoul-Henning Kamp pps_info_t ppsinfo; 41cc732491SPoul-Henning Kamp } *softc[NPPS]; 42507e2e44SPoul-Henning Kamp 438afeddf0SPoul-Henning Kamp static int ppscap = 448afeddf0SPoul-Henning Kamp PPS_CAPTUREASSERT | 45399144d9SPoul-Henning Kamp #ifdef PPS_SYNC 468afeddf0SPoul-Henning Kamp PPS_HARDPPSONASSERT | 47399144d9SPoul-Henning Kamp #endif /* PPS_SYNC */ 488afeddf0SPoul-Henning Kamp PPS_OFFSETASSERT | 49389825d5SPoul-Henning Kamp PPS_ECHOASSERT | 50389825d5SPoul-Henning Kamp PPS_TSFMT_TSPEC; 518afeddf0SPoul-Henning Kamp 5295f0f58cSPoul-Henning Kamp static int npps; 53507e2e44SPoul-Henning Kamp 54507e2e44SPoul-Henning Kamp /* 55507e2e44SPoul-Henning Kamp * Make ourselves visible as a ppbus driver 56507e2e44SPoul-Henning Kamp */ 57507e2e44SPoul-Henning Kamp 5895f0f58cSPoul-Henning Kamp static struct ppb_device *ppsprobe(struct ppb_data *ppb); 5995f0f58cSPoul-Henning Kamp static int ppsattach(struct ppb_device *dev); 6095f0f58cSPoul-Henning Kamp static void ppsintr(int unit); 6195f0f58cSPoul-Henning Kamp static void pps_drvinit(void *unused); 62507e2e44SPoul-Henning Kamp 6395f0f58cSPoul-Henning Kamp static struct ppb_driver ppsdriver = { 6495f0f58cSPoul-Henning Kamp ppsprobe, ppsattach, PPS_NAME 65507e2e44SPoul-Henning Kamp }; 66507e2e44SPoul-Henning Kamp 6795f0f58cSPoul-Henning Kamp DATA_SET(ppbdriver_set, ppsdriver); 68507e2e44SPoul-Henning Kamp 6995f0f58cSPoul-Henning Kamp static d_open_t ppsopen; 7095f0f58cSPoul-Henning Kamp static d_close_t ppsclose; 718afeddf0SPoul-Henning Kamp static d_ioctl_t ppsioctl; 72507e2e44SPoul-Henning Kamp 73507e2e44SPoul-Henning Kamp #define CDEV_MAJOR 89 7495f0f58cSPoul-Henning Kamp static struct cdevsw pps_cdevsw = 758afeddf0SPoul-Henning Kamp { ppsopen, ppsclose, noread, nowrite, 768afeddf0SPoul-Henning Kamp ppsioctl, nullstop, nullreset, nodevtotty, 77cc732491SPoul-Henning Kamp seltrue, nommap, nostrat, PPS_NAME, 78507e2e44SPoul-Henning Kamp NULL, -1 }; 79507e2e44SPoul-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; 84507e2e44SPoul-Henning Kamp 8595f0f58cSPoul-Henning Kamp sc = (struct pps_data *) malloc(sizeof(struct pps_data), 86507e2e44SPoul-Henning Kamp M_TEMP, M_NOWAIT); 87507e2e44SPoul-Henning Kamp if (!sc) { 88cc732491SPoul-Henning Kamp printf(PPS_NAME ": cannot malloc!\n"); 89507e2e44SPoul-Henning Kamp return (0); 90507e2e44SPoul-Henning Kamp } 9195f0f58cSPoul-Henning Kamp bzero(sc, sizeof(struct pps_data)); 92507e2e44SPoul-Henning Kamp 9395f0f58cSPoul-Henning Kamp softc[npps] = sc; 94507e2e44SPoul-Henning Kamp 9595f0f58cSPoul-Henning Kamp sc->pps_unit = npps++; 96507e2e44SPoul-Henning Kamp 9795f0f58cSPoul-Henning Kamp sc->pps_dev.id_unit = sc->pps_unit; 9895f0f58cSPoul-Henning Kamp sc->pps_dev.ppb = ppb; 9946f3ff79SMike Smith sc->pps_dev.name = ppsdriver.name; 10095f0f58cSPoul-Henning Kamp sc->pps_dev.intr = ppsintr; 101507e2e44SPoul-Henning Kamp 10295f0f58cSPoul-Henning Kamp return (&sc->pps_dev); 103507e2e44SPoul-Henning Kamp } 104507e2e44SPoul-Henning Kamp 105507e2e44SPoul-Henning Kamp static int 10695f0f58cSPoul-Henning Kamp ppsattach(struct ppb_device *dev) 107507e2e44SPoul-Henning Kamp { 108507e2e44SPoul-Henning Kamp /* 109507e2e44SPoul-Henning Kamp * Report ourselves 110507e2e44SPoul-Henning Kamp */ 111cc732491SPoul-Henning Kamp printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 112507e2e44SPoul-Henning Kamp dev->id_unit, dev->ppb->ppb_link->adapter_unit); 113507e2e44SPoul-Henning Kamp 114507e2e44SPoul-Henning Kamp #ifdef DEVFS 11595f0f58cSPoul-Henning Kamp devfs_add_devswf(&pps_cdevsw, 116507e2e44SPoul-Henning Kamp dev->id_unit, DV_CHR, 117cc732491SPoul-Henning Kamp UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit); 118507e2e44SPoul-Henning Kamp #endif 119507e2e44SPoul-Henning Kamp 120507e2e44SPoul-Henning Kamp return (1); 121507e2e44SPoul-Henning Kamp } 122507e2e44SPoul-Henning Kamp 123507e2e44SPoul-Henning Kamp static int 12495f0f58cSPoul-Henning Kamp ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 125507e2e44SPoul-Henning Kamp { 12695f0f58cSPoul-Henning Kamp struct pps_data *sc; 127507e2e44SPoul-Henning Kamp u_int unit = minor(dev); 128507e2e44SPoul-Henning Kamp 12995f0f58cSPoul-Henning Kamp if ((unit >= npps)) 130507e2e44SPoul-Henning Kamp return (ENXIO); 131507e2e44SPoul-Henning Kamp 132507e2e44SPoul-Henning Kamp sc = softc[unit]; 133507e2e44SPoul-Henning Kamp 13495f0f58cSPoul-Henning Kamp if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 135507e2e44SPoul-Henning Kamp return (EINTR); 136507e2e44SPoul-Henning Kamp 13720240fa3SNicolas Souchu ppb_wctr(&sc->pps_dev, 0); 1388afeddf0SPoul-Henning Kamp ppb_wctr(&sc->pps_dev, IRQENABLE); 139507e2e44SPoul-Henning Kamp 140507e2e44SPoul-Henning Kamp return(0); 141507e2e44SPoul-Henning Kamp } 142507e2e44SPoul-Henning Kamp 143507e2e44SPoul-Henning Kamp static int 14495f0f58cSPoul-Henning Kamp ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 145507e2e44SPoul-Henning Kamp { 14695f0f58cSPoul-Henning Kamp struct pps_data *sc = softc[minor(dev)]; 147507e2e44SPoul-Henning Kamp 1488afeddf0SPoul-Henning Kamp sc->ppsparam.mode = 0; 14920240fa3SNicolas Souchu 15020240fa3SNicolas Souchu ppb_wdtr(&sc->pps_dev, 0); 15120240fa3SNicolas Souchu ppb_wctr(&sc->pps_dev, 0); 15220240fa3SNicolas Souchu 15395f0f58cSPoul-Henning Kamp ppb_release_bus(&sc->pps_dev); 154507e2e44SPoul-Henning Kamp return(0); 155507e2e44SPoul-Henning Kamp } 156507e2e44SPoul-Henning Kamp 157507e2e44SPoul-Henning Kamp static void 15895f0f58cSPoul-Henning Kamp ppsintr(int unit) 159507e2e44SPoul-Henning Kamp { 16095f0f58cSPoul-Henning Kamp struct pps_data *sc = softc[unit]; 161507e2e44SPoul-Henning Kamp struct timespec tc; 162507e2e44SPoul-Henning Kamp 163507e2e44SPoul-Henning Kamp nanotime(&tc); 16495f0f58cSPoul-Henning Kamp if (!(ppb_rstr(&sc->pps_dev) & nACK)) 165507e2e44SPoul-Henning Kamp return; 1668afeddf0SPoul-Henning Kamp if (sc->ppsparam.mode & PPS_ECHOASSERT) 1678afeddf0SPoul-Henning Kamp ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); 168389825d5SPoul-Henning Kamp if (sc->ppsparam.mode & PPS_OFFSETASSERT) { 1698afeddf0SPoul-Henning Kamp timespecadd(&tc, &sc->ppsparam.assert_offset); 1708afeddf0SPoul-Henning Kamp if (tc.tv_nsec < 0) { 171507e2e44SPoul-Henning Kamp tc.tv_sec--; 172507e2e44SPoul-Henning Kamp tc.tv_nsec += 1000000000; 173507e2e44SPoul-Henning Kamp } 174389825d5SPoul-Henning Kamp } 1758afeddf0SPoul-Henning Kamp sc->ppsinfo.assert_timestamp = tc; 1768afeddf0SPoul-Henning Kamp sc->ppsinfo.assert_sequence++; 177399144d9SPoul-Henning Kamp #ifdef PPS_SYNC 1788afeddf0SPoul-Henning Kamp if (sc->ppsparam.mode & PPS_HARDPPSONASSERT) { 179f1d19042SArchie Cobbs struct timeval tv; 180f1d19042SArchie Cobbs 181507e2e44SPoul-Henning Kamp tv.tv_sec = tc.tv_sec; 182507e2e44SPoul-Henning Kamp tv.tv_usec = tc.tv_nsec / 1000; 183507e2e44SPoul-Henning Kamp hardpps(&tv, tv.tv_usec); 1848afeddf0SPoul-Henning Kamp } 185399144d9SPoul-Henning Kamp #endif /* PPS_SYNC */ 1868afeddf0SPoul-Henning Kamp if (sc->ppsparam.mode & PPS_ECHOASSERT) 1878afeddf0SPoul-Henning Kamp ppb_wctr(&sc->pps_dev, IRQENABLE); 188507e2e44SPoul-Henning Kamp } 189507e2e44SPoul-Henning Kamp 190507e2e44SPoul-Henning Kamp static int 191ceeea6b9SBruce Evans ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 192507e2e44SPoul-Henning Kamp { 19395f0f58cSPoul-Henning Kamp struct pps_data *sc = softc[minor(dev)]; 194507e2e44SPoul-Henning Kamp 195938ee3ceSPoul-Henning Kamp return (std_pps_ioctl(cmd, data, &sc->ppsparam, &sc->ppsinfo, ppscap)); 1968afeddf0SPoul-Henning Kamp } 197507e2e44SPoul-Henning Kamp 19895f0f58cSPoul-Henning Kamp static pps_devsw_installed = 0; 199507e2e44SPoul-Henning Kamp 200507e2e44SPoul-Henning Kamp static void 20195f0f58cSPoul-Henning Kamp pps_drvinit(void *unused) 202507e2e44SPoul-Henning Kamp { 203507e2e44SPoul-Henning Kamp dev_t dev; 204507e2e44SPoul-Henning Kamp 20595f0f58cSPoul-Henning Kamp if( ! pps_devsw_installed ) { 206507e2e44SPoul-Henning Kamp dev = makedev(CDEV_MAJOR, 0); 20795f0f58cSPoul-Henning Kamp cdevsw_add(&dev, &pps_cdevsw, NULL); 20895f0f58cSPoul-Henning Kamp pps_devsw_installed = 1; 209507e2e44SPoul-Henning Kamp } 210507e2e44SPoul-Henning Kamp } 211507e2e44SPoul-Henning Kamp 21295f0f58cSPoul-Henning Kamp SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL) 213