pps.c revision 33396
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 * $Id: pps.c,v 1.2 1998/02/13 17:35:33 phk Exp $ 10 * 11 */ 12 13#include "opt_devfs.h" 14 15#include <sys/param.h> 16#include <sys/kernel.h> 17#include <sys/systm.h> 18#include <sys/conf.h> 19#include <sys/uio.h> 20#ifdef DEVFS 21#include <sys/devfsext.h> 22#endif 23#include <sys/malloc.h> 24 25#include <dev/ppbus/ppbconf.h> 26#include "pps.h" 27 28#define PPS_NAME "pps" /* our official name */ 29 30static struct pps_data { 31 int pps_unit; 32 struct ppb_device pps_dev; 33 struct ppsclockev { 34 struct timespec timestamp; 35 u_int serial; 36 } ev; 37 int sawtooth; 38} *softc[NPPS]; 39 40static int npps; 41 42/* 43 * Make ourselves visible as a ppbus driver 44 */ 45 46static struct ppb_device *ppsprobe(struct ppb_data *ppb); 47static int ppsattach(struct ppb_device *dev); 48static void ppsintr(int unit); 49static void pps_drvinit(void *unused); 50 51static struct ppb_driver ppsdriver = { 52 ppsprobe, ppsattach, PPS_NAME 53}; 54 55DATA_SET(ppbdriver_set, ppsdriver); 56 57static d_open_t ppsopen; 58static d_close_t ppsclose; 59static d_read_t ppsread; 60static d_write_t ppswrite; 61 62#define CDEV_MAJOR 89 63static struct cdevsw pps_cdevsw = 64 { ppsopen, ppsclose, ppsread, ppswrite, 65 noioctl, nullstop, nullreset, nodevtotty, 66 seltrue, nommap, nostrat, PPS_NAME, 67 NULL, -1 }; 68 69static struct ppb_device * 70ppsprobe(struct ppb_data *ppb) 71{ 72 struct pps_data *sc; 73 74 sc = (struct pps_data *) malloc(sizeof(struct pps_data), 75 M_TEMP, M_NOWAIT); 76 if (!sc) { 77 printf(PPS_NAME ": cannot malloc!\n"); 78 return (0); 79 } 80 bzero(sc, sizeof(struct pps_data)); 81 82 softc[npps] = sc; 83 84 sc->pps_unit = npps++; 85 86 sc->pps_dev.id_unit = sc->pps_unit; 87 sc->pps_dev.ppb = ppb; 88 sc->pps_dev.intr = ppsintr; 89 90 return (&sc->pps_dev); 91} 92 93static int 94ppsattach(struct ppb_device *dev) 95{ 96 /* 97 * Report ourselves 98 */ 99 printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 100 dev->id_unit, dev->ppb->ppb_link->adapter_unit); 101 102#ifdef DEVFS 103 devfs_add_devswf(&pps_cdevsw, 104 dev->id_unit, DV_CHR, 105 UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit); 106 devfs_add_devswf(&pps_cdevsw, 107 dev->id_unit | LP_BYPASS, DV_CHR, 108 UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d.ctl", dev->id_unit); 109#endif 110 111 return (1); 112} 113 114static int 115ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 116{ 117 struct pps_data *sc; 118 u_int unit = minor(dev); 119 120 if ((unit >= npps)) 121 return (ENXIO); 122 123 sc = softc[unit]; 124 125 if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 126 return (EINTR); 127 128 ppb_wctr(&sc->pps_dev, 0x10); 129 130 return(0); 131} 132 133static int 134ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 135{ 136 struct pps_data *sc = softc[minor(dev)]; 137 138 ppb_release_bus(&sc->pps_dev); 139 return(0); 140} 141 142static void 143ppsintr(int unit) 144{ 145/* 146 * XXX: You want to thing carefully about what you actually want to do 147 * here. 148 */ 149#if 1 150 struct pps_data *sc = softc[unit]; 151 struct timespec tc; 152#if 1 153 struct timeval tv; 154#endif 155 156 nanotime(&tc); 157 if (!(ppb_rstr(&sc->pps_dev) & nACK)) 158 return; 159 tc.tv_nsec -= sc->sawtooth; 160 sc->sawtooth = 0; 161 if (tc.tv_nsec > 1000000000) { 162 tc.tv_sec++; 163 tc.tv_nsec -= 1000000000; 164 } else if (tc.tv_nsec < 0) { 165 tc.tv_sec--; 166 tc.tv_nsec += 1000000000; 167 } 168 sc->ev.timestamp = tc; 169 sc->ev.serial++; 170#if 1 171 tv.tv_sec = tc.tv_sec; 172 tv.tv_usec = tc.tv_nsec / 1000; 173 hardpps(&tv, tv.tv_usec); 174#endif 175#endif 176} 177 178static int 179ppsread(dev_t dev, struct uio *uio, int ioflag) 180{ 181 struct pps_data *sc = softc[minor(dev)]; 182 int err, c; 183 184 c = imin(uio->uio_resid, (int)sizeof sc->ev); 185 err = uiomove((caddr_t)&sc->ev, c, uio); 186 return(err); 187} 188 189static int 190ppswrite(dev_t dev, struct uio *uio, int ioflag) 191{ 192 struct pps_data *sc = softc[minor(dev)]; 193 int err, c; 194 195 c = imin(uio->uio_resid, (int)sizeof sc->sawtooth); 196 err = uiomove((caddr_t)&sc->sawtooth, c, uio); 197 return(err); 198} 199 200static pps_devsw_installed = 0; 201 202static void 203pps_drvinit(void *unused) 204{ 205 dev_t dev; 206 207 if( ! pps_devsw_installed ) { 208 dev = makedev(CDEV_MAJOR, 0); 209 cdevsw_add(&dev, &pps_cdevsw, NULL); 210 pps_devsw_installed = 1; 211 } 212} 213 214SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL) 215