pps.c revision 44666
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.13 1999/01/30 15:35:39 nsouch 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 struct ppb_device pps_dev; 38 struct pps_state pps; 39} *softc[NPPS]; 40 41static int npps; 42static pps_devsw_installed = 0; 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); 51static void pps_drvinit(void *unused); 52 53static struct ppb_driver ppsdriver = { 54 ppsprobe, ppsattach, PPS_NAME 55}; 56 57DATA_SET(ppbdriver_set, ppsdriver); 58 59static d_open_t ppsopen; 60static d_close_t ppsclose; 61static d_ioctl_t ppsioctl; 62 63#define CDEV_MAJOR 89 64static struct cdevsw pps_cdevsw = 65 { ppsopen, ppsclose, noread, nowrite, 66 ppsioctl, nullstop, nullreset, nodevtotty, 67 seltrue, nommap, nostrat, PPS_NAME, 68 NULL, -1 }; 69 70 71static struct ppb_device * 72ppsprobe(struct ppb_data *ppb) 73{ 74 struct pps_data *sc; 75 76 sc = (struct pps_data *) malloc(sizeof(struct pps_data), 77 M_TEMP, M_NOWAIT); 78 if (!sc) { 79 printf(PPS_NAME ": cannot malloc!\n"); 80 return (0); 81 } 82 bzero(sc, sizeof(struct pps_data)); 83 84 softc[npps] = sc; 85 86 sc->pps_unit = npps++; 87 88 sc->pps_dev.id_unit = sc->pps_unit; 89 sc->pps_dev.ppb = ppb; 90 sc->pps_dev.name = ppsdriver.name; 91 sc->pps_dev.intr = ppsintr; 92 93 sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 94 pps_init(&sc->pps); 95 return (&sc->pps_dev); 96} 97 98static int 99ppsattach(struct ppb_device *dev) 100{ 101 dev_t devt; 102 103 /* 104 * Report ourselves 105 */ 106 printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 107 dev->id_unit, dev->ppb->ppb_link->adapter_unit); 108 109#ifdef DEVFS 110 devfs_add_devswf(&pps_cdevsw, 111 dev->id_unit, DV_CHR, 112 UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit); 113#endif 114 if( ! pps_devsw_installed ) { 115 devt = makedev(CDEV_MAJOR, 0); 116 cdevsw_add(&devt, &pps_cdevsw, NULL); 117 pps_devsw_installed = 1; 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 = softc[unit]; 132 133 if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 134 return (EINTR); 135 136 ppb_wctr(&sc->pps_dev, 0); 137 ppb_wctr(&sc->pps_dev, IRQENABLE); 138 139 return(0); 140} 141 142static int 143ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 144{ 145 struct pps_data *sc = softc[minor(dev)]; 146 147 sc->pps.ppsparam.mode = 0; /* PHK ??? */ 148 149 ppb_wdtr(&sc->pps_dev, 0); 150 ppb_wctr(&sc->pps_dev, 0); 151 152 ppb_release_bus(&sc->pps_dev); 153 return(0); 154} 155 156static void 157ppsintr(int unit) 158{ 159 struct pps_data *sc = softc[unit]; 160 struct timecounter *tc; 161 unsigned count; 162 163 tc = timecounter; 164 count = timecounter->tc_get_timecount(tc); 165 if (!(ppb_rstr(&sc->pps_dev) & nACK)) 166 return; 167 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 168 ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); 169 pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 170 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 171 ppb_wctr(&sc->pps_dev, IRQENABLE); 172} 173 174static int 175ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 176{ 177 struct pps_data *sc = softc[minor(dev)]; 178 179 return (pps_ioctl(cmd, data, &sc->pps)); 180} 181 182