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 * 995f0f58cSPoul-Henning Kamp * $Id: pps.c,v 1.2 1998/02/13 17:35:33 phk Exp $ 10507e2e44SPoul-Henning Kamp * 11507e2e44SPoul-Henning Kamp */ 12507e2e44SPoul-Henning Kamp 1395f0f58cSPoul-Henning Kamp #include "opt_devfs.h" 1495f0f58cSPoul-Henning Kamp 15507e2e44SPoul-Henning Kamp #include <sys/param.h> 16507e2e44SPoul-Henning Kamp #include <sys/kernel.h> 17507e2e44SPoul-Henning Kamp #include <sys/systm.h> 18507e2e44SPoul-Henning Kamp #include <sys/conf.h> 19507e2e44SPoul-Henning Kamp #include <sys/uio.h> 20507e2e44SPoul-Henning Kamp #ifdef DEVFS 21507e2e44SPoul-Henning Kamp #include <sys/devfsext.h> 2295f0f58cSPoul-Henning Kamp #endif 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 28cc732491SPoul-Henning Kamp #define PPS_NAME "pps" /* our official name */ 29507e2e44SPoul-Henning Kamp 3095f0f58cSPoul-Henning Kamp static struct pps_data { 3195f0f58cSPoul-Henning Kamp int pps_unit; 3295f0f58cSPoul-Henning Kamp struct ppb_device pps_dev; 33507e2e44SPoul-Henning Kamp struct ppsclockev { 34507e2e44SPoul-Henning Kamp struct timespec timestamp; 35507e2e44SPoul-Henning Kamp u_int serial; 36507e2e44SPoul-Henning Kamp } ev; 37507e2e44SPoul-Henning Kamp int sawtooth; 38cc732491SPoul-Henning Kamp } *softc[NPPS]; 39507e2e44SPoul-Henning Kamp 4095f0f58cSPoul-Henning Kamp static int npps; 41507e2e44SPoul-Henning Kamp 42507e2e44SPoul-Henning Kamp /* 43507e2e44SPoul-Henning Kamp * Make ourselves visible as a ppbus driver 44507e2e44SPoul-Henning Kamp */ 45507e2e44SPoul-Henning Kamp 4695f0f58cSPoul-Henning Kamp static struct ppb_device *ppsprobe(struct ppb_data *ppb); 4795f0f58cSPoul-Henning Kamp static int ppsattach(struct ppb_device *dev); 4895f0f58cSPoul-Henning Kamp static void ppsintr(int unit); 4995f0f58cSPoul-Henning Kamp static void pps_drvinit(void *unused); 50507e2e44SPoul-Henning Kamp 5195f0f58cSPoul-Henning Kamp static struct ppb_driver ppsdriver = { 5295f0f58cSPoul-Henning Kamp ppsprobe, ppsattach, PPS_NAME 53507e2e44SPoul-Henning Kamp }; 54507e2e44SPoul-Henning Kamp 5595f0f58cSPoul-Henning Kamp DATA_SET(ppbdriver_set, ppsdriver); 56507e2e44SPoul-Henning Kamp 5795f0f58cSPoul-Henning Kamp static d_open_t ppsopen; 5895f0f58cSPoul-Henning Kamp static d_close_t ppsclose; 5995f0f58cSPoul-Henning Kamp static d_read_t ppsread; 6095f0f58cSPoul-Henning Kamp static d_write_t ppswrite; 61507e2e44SPoul-Henning Kamp 62507e2e44SPoul-Henning Kamp #define CDEV_MAJOR 89 6395f0f58cSPoul-Henning Kamp static struct cdevsw pps_cdevsw = 6495f0f58cSPoul-Henning Kamp { ppsopen, ppsclose, ppsread, ppswrite, 65507e2e44SPoul-Henning Kamp noioctl, nullstop, nullreset, nodevtotty, 66cc732491SPoul-Henning Kamp seltrue, nommap, nostrat, PPS_NAME, 67507e2e44SPoul-Henning Kamp NULL, -1 }; 68507e2e44SPoul-Henning Kamp 69507e2e44SPoul-Henning Kamp static struct ppb_device * 7095f0f58cSPoul-Henning Kamp ppsprobe(struct ppb_data *ppb) 71507e2e44SPoul-Henning Kamp { 7295f0f58cSPoul-Henning Kamp struct pps_data *sc; 73507e2e44SPoul-Henning Kamp 7495f0f58cSPoul-Henning Kamp sc = (struct pps_data *) malloc(sizeof(struct pps_data), 75507e2e44SPoul-Henning Kamp M_TEMP, M_NOWAIT); 76507e2e44SPoul-Henning Kamp if (!sc) { 77cc732491SPoul-Henning Kamp printf(PPS_NAME ": cannot malloc!\n"); 78507e2e44SPoul-Henning Kamp return (0); 79507e2e44SPoul-Henning Kamp } 8095f0f58cSPoul-Henning Kamp bzero(sc, sizeof(struct pps_data)); 81507e2e44SPoul-Henning Kamp 8295f0f58cSPoul-Henning Kamp softc[npps] = sc; 83507e2e44SPoul-Henning Kamp 8495f0f58cSPoul-Henning Kamp sc->pps_unit = npps++; 85507e2e44SPoul-Henning Kamp 8695f0f58cSPoul-Henning Kamp sc->pps_dev.id_unit = sc->pps_unit; 8795f0f58cSPoul-Henning Kamp sc->pps_dev.ppb = ppb; 8895f0f58cSPoul-Henning Kamp sc->pps_dev.intr = ppsintr; 89507e2e44SPoul-Henning Kamp 9095f0f58cSPoul-Henning Kamp return (&sc->pps_dev); 91507e2e44SPoul-Henning Kamp } 92507e2e44SPoul-Henning Kamp 93507e2e44SPoul-Henning Kamp static int 9495f0f58cSPoul-Henning Kamp ppsattach(struct ppb_device *dev) 95507e2e44SPoul-Henning Kamp { 96507e2e44SPoul-Henning Kamp /* 97507e2e44SPoul-Henning Kamp * Report ourselves 98507e2e44SPoul-Henning Kamp */ 99cc732491SPoul-Henning Kamp printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 100507e2e44SPoul-Henning Kamp dev->id_unit, dev->ppb->ppb_link->adapter_unit); 101507e2e44SPoul-Henning Kamp 102507e2e44SPoul-Henning Kamp #ifdef DEVFS 10395f0f58cSPoul-Henning Kamp devfs_add_devswf(&pps_cdevsw, 104507e2e44SPoul-Henning Kamp dev->id_unit, DV_CHR, 105cc732491SPoul-Henning Kamp UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit); 10695f0f58cSPoul-Henning Kamp devfs_add_devswf(&pps_cdevsw, 107507e2e44SPoul-Henning Kamp dev->id_unit | LP_BYPASS, DV_CHR, 108cc732491SPoul-Henning Kamp UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d.ctl", dev->id_unit); 109507e2e44SPoul-Henning Kamp #endif 110507e2e44SPoul-Henning Kamp 111507e2e44SPoul-Henning Kamp return (1); 112507e2e44SPoul-Henning Kamp } 113507e2e44SPoul-Henning Kamp 114507e2e44SPoul-Henning Kamp static int 11595f0f58cSPoul-Henning Kamp ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 116507e2e44SPoul-Henning Kamp { 11795f0f58cSPoul-Henning Kamp struct pps_data *sc; 118507e2e44SPoul-Henning Kamp u_int unit = minor(dev); 119507e2e44SPoul-Henning Kamp 12095f0f58cSPoul-Henning Kamp if ((unit >= npps)) 121507e2e44SPoul-Henning Kamp return (ENXIO); 122507e2e44SPoul-Henning Kamp 123507e2e44SPoul-Henning Kamp sc = softc[unit]; 124507e2e44SPoul-Henning Kamp 12595f0f58cSPoul-Henning Kamp if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 126507e2e44SPoul-Henning Kamp return (EINTR); 127507e2e44SPoul-Henning Kamp 12895f0f58cSPoul-Henning Kamp ppb_wctr(&sc->pps_dev, 0x10); 129507e2e44SPoul-Henning Kamp 130507e2e44SPoul-Henning Kamp return(0); 131507e2e44SPoul-Henning Kamp } 132507e2e44SPoul-Henning Kamp 133507e2e44SPoul-Henning Kamp static int 13495f0f58cSPoul-Henning Kamp ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 135507e2e44SPoul-Henning Kamp { 13695f0f58cSPoul-Henning Kamp struct pps_data *sc = softc[minor(dev)]; 137507e2e44SPoul-Henning Kamp 13895f0f58cSPoul-Henning Kamp ppb_release_bus(&sc->pps_dev); 139507e2e44SPoul-Henning Kamp return(0); 140507e2e44SPoul-Henning Kamp } 141507e2e44SPoul-Henning Kamp 142507e2e44SPoul-Henning Kamp static void 14395f0f58cSPoul-Henning Kamp ppsintr(int unit) 144507e2e44SPoul-Henning Kamp { 145507e2e44SPoul-Henning Kamp /* 146507e2e44SPoul-Henning Kamp * XXX: You want to thing carefully about what you actually want to do 147507e2e44SPoul-Henning Kamp * here. 148507e2e44SPoul-Henning Kamp */ 14995f0f58cSPoul-Henning Kamp #if 1 15095f0f58cSPoul-Henning Kamp struct pps_data *sc = softc[unit]; 151507e2e44SPoul-Henning Kamp struct timespec tc; 152507e2e44SPoul-Henning Kamp #if 1 153507e2e44SPoul-Henning Kamp struct timeval tv; 154507e2e44SPoul-Henning Kamp #endif 155507e2e44SPoul-Henning Kamp 156507e2e44SPoul-Henning Kamp nanotime(&tc); 15795f0f58cSPoul-Henning Kamp if (!(ppb_rstr(&sc->pps_dev) & nACK)) 158507e2e44SPoul-Henning Kamp return; 159507e2e44SPoul-Henning Kamp tc.tv_nsec -= sc->sawtooth; 160507e2e44SPoul-Henning Kamp sc->sawtooth = 0; 161507e2e44SPoul-Henning Kamp if (tc.tv_nsec > 1000000000) { 162507e2e44SPoul-Henning Kamp tc.tv_sec++; 163507e2e44SPoul-Henning Kamp tc.tv_nsec -= 1000000000; 164507e2e44SPoul-Henning Kamp } else if (tc.tv_nsec < 0) { 165507e2e44SPoul-Henning Kamp tc.tv_sec--; 166507e2e44SPoul-Henning Kamp tc.tv_nsec += 1000000000; 167507e2e44SPoul-Henning Kamp } 168507e2e44SPoul-Henning Kamp sc->ev.timestamp = tc; 169507e2e44SPoul-Henning Kamp sc->ev.serial++; 170507e2e44SPoul-Henning Kamp #if 1 171507e2e44SPoul-Henning Kamp tv.tv_sec = tc.tv_sec; 172507e2e44SPoul-Henning Kamp tv.tv_usec = tc.tv_nsec / 1000; 173507e2e44SPoul-Henning Kamp hardpps(&tv, tv.tv_usec); 174507e2e44SPoul-Henning Kamp #endif 175507e2e44SPoul-Henning Kamp #endif 176507e2e44SPoul-Henning Kamp } 177507e2e44SPoul-Henning Kamp 178507e2e44SPoul-Henning Kamp static int 17995f0f58cSPoul-Henning Kamp ppsread(dev_t dev, struct uio *uio, int ioflag) 180507e2e44SPoul-Henning Kamp { 18195f0f58cSPoul-Henning Kamp struct pps_data *sc = softc[minor(dev)]; 182507e2e44SPoul-Henning Kamp int err, c; 183507e2e44SPoul-Henning Kamp 18495f0f58cSPoul-Henning Kamp c = imin(uio->uio_resid, (int)sizeof sc->ev); 18595f0f58cSPoul-Henning Kamp err = uiomove((caddr_t)&sc->ev, c, uio); 186507e2e44SPoul-Henning Kamp return(err); 187507e2e44SPoul-Henning Kamp } 188507e2e44SPoul-Henning Kamp 189507e2e44SPoul-Henning Kamp static int 19095f0f58cSPoul-Henning Kamp ppswrite(dev_t dev, struct uio *uio, int ioflag) 191507e2e44SPoul-Henning Kamp { 19295f0f58cSPoul-Henning Kamp struct pps_data *sc = softc[minor(dev)]; 193507e2e44SPoul-Henning Kamp int err, c; 194507e2e44SPoul-Henning Kamp 19595f0f58cSPoul-Henning Kamp c = imin(uio->uio_resid, (int)sizeof sc->sawtooth); 19695f0f58cSPoul-Henning Kamp err = uiomove((caddr_t)&sc->sawtooth, c, uio); 197507e2e44SPoul-Henning Kamp return(err); 198507e2e44SPoul-Henning Kamp } 199507e2e44SPoul-Henning Kamp 20095f0f58cSPoul-Henning Kamp static pps_devsw_installed = 0; 201507e2e44SPoul-Henning Kamp 202507e2e44SPoul-Henning Kamp static void 20395f0f58cSPoul-Henning Kamp pps_drvinit(void *unused) 204507e2e44SPoul-Henning Kamp { 205507e2e44SPoul-Henning Kamp dev_t dev; 206507e2e44SPoul-Henning Kamp 20795f0f58cSPoul-Henning Kamp if( ! pps_devsw_installed ) { 208507e2e44SPoul-Henning Kamp dev = makedev(CDEV_MAJOR, 0); 20995f0f58cSPoul-Henning Kamp cdevsw_add(&dev, &pps_cdevsw, NULL); 21095f0f58cSPoul-Henning Kamp pps_devsw_installed = 1; 211507e2e44SPoul-Henning Kamp } 212507e2e44SPoul-Henning Kamp } 213507e2e44SPoul-Henning Kamp 21495f0f58cSPoul-Henning Kamp SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL) 215