pps.c revision 51658
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 * $FreeBSD: head/sys/dev/ppbus/pps.c 51658 1999-09-25 18:24:47Z phk $ 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 <sys/param.h> 19#include <sys/kernel.h> 20#include <sys/systm.h> 21#include <sys/conf.h> 22#include <sys/timepps.h> 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 30struct pps_data { 31 int pps_open; 32 struct ppb_device pps_dev; 33 struct pps_state pps; 34}; 35 36static int npps; 37 38/* 39 * Make ourselves visible as a ppbus driver 40 */ 41 42static struct ppb_device *ppsprobe(struct ppb_data *ppb); 43static int ppsattach(struct ppb_device *dev); 44static void ppsintr(struct ppb_device *ppd); 45 46static struct ppb_driver ppsdriver = { 47 ppsprobe, ppsattach, PPS_NAME 48}; 49 50DATA_SET(ppbdriver_set, ppsdriver); 51 52static d_open_t ppsopen; 53static d_close_t ppsclose; 54static d_ioctl_t ppsioctl; 55 56#define CDEV_MAJOR 89 57static struct cdevsw pps_cdevsw = { 58 /* open */ ppsopen, 59 /* close */ ppsclose, 60 /* read */ noread, 61 /* write */ nowrite, 62 /* ioctl */ ppsioctl, 63 /* poll */ nopoll, 64 /* mmap */ nommap, 65 /* strategy */ nostrategy, 66 /* name */ PPS_NAME, 67 /* maj */ CDEV_MAJOR, 68 /* dump */ nodump, 69 /* psize */ nopsize, 70 /* flags */ 0, 71 /* bmaj */ -1 72}; 73 74 75static struct ppb_device * 76ppsprobe(struct ppb_data *ppb) 77{ 78 struct pps_data *sc; 79 static int once; 80 dev_t dev; 81 82 if (!once++) 83 cdevsw_add(&pps_cdevsw); 84 85 sc = (struct pps_data *) malloc(sizeof(struct pps_data), 86 M_TEMP, M_NOWAIT); 87 if (!sc) { 88 printf(PPS_NAME ": cannot malloc!\n"); 89 return (0); 90 } 91 bzero(sc, sizeof(struct pps_data)); 92 93 dev = make_dev(&pps_cdevsw, npps, 94 UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", npps); 95 96 dev->si_drv1 = sc; 97 98 sc->pps_dev.id_unit = npps++; 99 sc->pps_dev.ppb = ppb; 100 sc->pps_dev.name = ppsdriver.name; 101 sc->pps_dev.bintr = ppsintr; 102 sc->pps_dev.drv1 = sc; 103 104 sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 105 pps_init(&sc->pps); 106 return (&sc->pps_dev); 107} 108 109static int 110ppsattach(struct ppb_device *dev) 111{ 112 113 /* 114 * Report ourselves 115 */ 116 printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 117 dev->id_unit, dev->ppb->ppb_link->adapter_unit); 118 119 return (1); 120} 121 122static int 123ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 124{ 125 struct pps_data *sc; 126 u_int unit = minor(dev); 127 128 if ((unit >= npps)) 129 return (ENXIO); 130 131 sc = dev->si_drv1; 132 133 if (!sc->pps_open) { 134 if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 135 return (EINTR); 136 137 ppb_wctr(&sc->pps_dev, 0); 138 ppb_wctr(&sc->pps_dev, IRQENABLE); 139 sc->pps_open = 1; 140 } 141 142 return(0); 143} 144 145static int 146ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 147{ 148 struct pps_data *sc = dev->si_drv1; 149 150 sc->pps.ppsparam.mode = 0; /* PHK ??? */ 151 152 ppb_wdtr(&sc->pps_dev, 0); 153 ppb_wctr(&sc->pps_dev, 0); 154 155 ppb_release_bus(&sc->pps_dev); 156 sc->pps_open = 0; 157 return(0); 158} 159 160static void 161ppsintr(struct ppb_device *ppd) 162{ 163 struct pps_data *sc = ppd->drv1; 164 struct timecounter *tc; 165 unsigned count; 166 167 tc = timecounter; 168 count = timecounter->tc_get_timecount(tc); 169 if (!(ppb_rstr(&sc->pps_dev) & nACK)) 170 return; 171 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 172 ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); 173 pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 174 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 175 ppb_wctr(&sc->pps_dev, IRQENABLE); 176} 177 178static int 179ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 180{ 181 struct pps_data *sc = dev->si_drv1; 182 183 return (pps_ioctl(cmd, data, &sc->pps)); 184} 185 186