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