pps.c revision 33442
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.3 1998/02/15 14:54:09 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#endif 107 108 return (1); 109} 110 111static int 112ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 113{ 114 struct pps_data *sc; 115 u_int unit = minor(dev); 116 117 if ((unit >= npps)) 118 return (ENXIO); 119 120 sc = softc[unit]; 121 122 if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 123 return (EINTR); 124 125 ppb_wctr(&sc->pps_dev, 0x10); 126 127 return(0); 128} 129 130static int 131ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 132{ 133 struct pps_data *sc = softc[minor(dev)]; 134 135 ppb_release_bus(&sc->pps_dev); 136 return(0); 137} 138 139static void 140ppsintr(int unit) 141{ 142/* 143 * XXX: You want to thing carefully about what you actually want to do 144 * here. 145 */ 146#if 1 147 struct pps_data *sc = softc[unit]; 148 struct timespec tc; 149#if 1 150 struct timeval tv; 151#endif 152 153 nanotime(&tc); 154 if (!(ppb_rstr(&sc->pps_dev) & nACK)) 155 return; 156 tc.tv_nsec -= sc->sawtooth; 157 sc->sawtooth = 0; 158 if (tc.tv_nsec > 1000000000) { 159 tc.tv_sec++; 160 tc.tv_nsec -= 1000000000; 161 } else if (tc.tv_nsec < 0) { 162 tc.tv_sec--; 163 tc.tv_nsec += 1000000000; 164 } 165 sc->ev.timestamp = tc; 166 sc->ev.serial++; 167#if 1 168 tv.tv_sec = tc.tv_sec; 169 tv.tv_usec = tc.tv_nsec / 1000; 170 hardpps(&tv, tv.tv_usec); 171#endif 172#endif 173} 174 175static int 176ppsread(dev_t dev, struct uio *uio, int ioflag) 177{ 178 struct pps_data *sc = softc[minor(dev)]; 179 int err, c; 180 181 c = imin(uio->uio_resid, (int)sizeof sc->ev); 182 err = uiomove((caddr_t)&sc->ev, c, uio); 183 return(err); 184} 185 186static int 187ppswrite(dev_t dev, struct uio *uio, int ioflag) 188{ 189 struct pps_data *sc = softc[minor(dev)]; 190 int err, c; 191 192 c = imin(uio->uio_resid, (int)sizeof sc->sawtooth); 193 err = uiomove((caddr_t)&sc->sawtooth, c, uio); 194 return(err); 195} 196 197static pps_devsw_installed = 0; 198 199static void 200pps_drvinit(void *unused) 201{ 202 dev_t dev; 203 204 if( ! pps_devsw_installed ) { 205 dev = makedev(CDEV_MAJOR, 0); 206 cdevsw_add(&dev, &pps_cdevsw, NULL); 207 pps_devsw_installed = 1; 208 } 209} 210 211SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL) 212