pps.c revision 47625
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.17 1999/05/06 22:03:14 peter Exp $ 10 * 11 * This driver implements a draft-mogul-pps-api-02.txt PPS source. 12 * 13 * The input pin is pin#10 14 * The echo output pin is pin#14 15 * 16 */ 17 18#include "opt_devfs.h" 19 20#include <sys/param.h> 21#include <sys/kernel.h> 22#include <sys/systm.h> 23#include <sys/conf.h> 24#include <sys/timepps.h> 25#ifdef DEVFS 26#include <sys/devfsext.h> 27#endif 28#include <sys/malloc.h> 29 30#include <dev/ppbus/ppbconf.h> 31#include "pps.h" 32 33#define PPS_NAME "lppps" /* our official name */ 34 35static struct pps_data { 36 int pps_unit; 37 int pps_open; 38 struct ppb_device pps_dev; 39 struct pps_state pps; 40} *softc[NPPS]; 41 42static int npps; 43 44/* 45 * Make ourselves visible as a ppbus driver 46 */ 47 48static struct ppb_device *ppsprobe(struct ppb_data *ppb); 49static int ppsattach(struct ppb_device *dev); 50static void ppsintr(int unit); 51 52static struct ppb_driver ppsdriver = { 53 ppsprobe, ppsattach, PPS_NAME 54}; 55 56DATA_SET(ppbdriver_set, ppsdriver); 57 58static d_open_t ppsopen; 59static d_close_t ppsclose; 60static d_ioctl_t ppsioctl; 61 62#define CDEV_MAJOR 89 63static struct cdevsw pps_cdevsw = { 64 /* open */ ppsopen, 65 /* close */ ppsclose, 66 /* read */ noread, 67 /* write */ nowrite, 68 /* ioctl */ ppsioctl, 69 /* stop */ nostop, 70 /* reset */ noreset, 71 /* devtotty */ nodevtotty, 72 /* poll */ nopoll, 73 /* mmap */ nommap, 74 /* strategy */ nostrategy, 75 /* name */ PPS_NAME, 76 /* parms */ noparms, 77 /* maj */ CDEV_MAJOR, 78 /* dump */ nodump, 79 /* psize */ nopsize, 80 /* flags */ 0, 81 /* maxio */ 0, 82 /* bmaj */ -1 83}; 84 85 86static struct ppb_device * 87ppsprobe(struct ppb_data *ppb) 88{ 89 struct pps_data *sc; 90 91 sc = (struct pps_data *) malloc(sizeof(struct pps_data), 92 M_TEMP, M_NOWAIT); 93 if (!sc) { 94 printf(PPS_NAME ": cannot malloc!\n"); 95 return (0); 96 } 97 bzero(sc, sizeof(struct pps_data)); 98 99 softc[npps] = sc; 100 101 sc->pps_unit = npps++; 102 103 sc->pps_dev.id_unit = sc->pps_unit; 104 sc->pps_dev.ppb = ppb; 105 sc->pps_dev.name = ppsdriver.name; 106 sc->pps_dev.intr = ppsintr; 107 108 sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 109 pps_init(&sc->pps); 110 return (&sc->pps_dev); 111} 112 113static int 114ppsattach(struct ppb_device *dev) 115{ 116 dev_t devt; 117 118 /* 119 * Report ourselves 120 */ 121 printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 122 dev->id_unit, dev->ppb->ppb_link->adapter_unit); 123 124#ifdef DEVFS 125 devfs_add_devswf(&pps_cdevsw, 126 dev->id_unit, DV_CHR, 127 UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit); 128#endif 129 devt = makedev(CDEV_MAJOR, 0); 130 cdevsw_add(&devt, &pps_cdevsw, NULL); 131 return (1); 132} 133 134static int 135ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 136{ 137 struct pps_data *sc; 138 u_int unit = minor(dev); 139 140 if ((unit >= npps)) 141 return (ENXIO); 142 143 sc = softc[unit]; 144 145 if (!sc->pps_open) { 146 if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 147 return (EINTR); 148 149 ppb_wctr(&sc->pps_dev, 0); 150 ppb_wctr(&sc->pps_dev, IRQENABLE); 151 sc->pps_open = 1; 152 } 153 154 return(0); 155} 156 157static int 158ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 159{ 160 struct pps_data *sc = softc[minor(dev)]; 161 162 sc->pps.ppsparam.mode = 0; /* PHK ??? */ 163 164 ppb_wdtr(&sc->pps_dev, 0); 165 ppb_wctr(&sc->pps_dev, 0); 166 167 ppb_release_bus(&sc->pps_dev); 168 sc->pps_open = 0; 169 return(0); 170} 171 172static void 173ppsintr(int unit) 174{ 175 struct pps_data *sc = softc[unit]; 176 struct timecounter *tc; 177 unsigned count; 178 179 tc = timecounter; 180 count = timecounter->tc_get_timecount(tc); 181 if (!(ppb_rstr(&sc->pps_dev) & nACK)) 182 return; 183 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 184 ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); 185 pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 186 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 187 ppb_wctr(&sc->pps_dev, IRQENABLE); 188} 189 190static int 191ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 192{ 193 struct pps_data *sc = softc[minor(dev)]; 194 195 return (pps_ioctl(cmd, data, &sc->pps)); 196} 197 198