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.18 1999/05/30 16:51:36 phk 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 35 static 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 42 static int npps; 43 44 /* 45 * Make ourselves visible as a ppbus driver 46 */ 47 48 static struct ppb_device *ppsprobe(struct ppb_data *ppb); 49 static int ppsattach(struct ppb_device *dev); 50 static void ppsintr(int unit); 51 52 static struct ppb_driver ppsdriver = { 53 ppsprobe, ppsattach, PPS_NAME 54 }; 55 56 DATA_SET(ppbdriver_set, ppsdriver); 57 58 static d_open_t ppsopen; 59 static d_close_t ppsclose; 60 static d_ioctl_t ppsioctl; 61 62 #define CDEV_MAJOR 89 63 static 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 86 static struct ppb_device * 87 ppsprobe(struct ppb_data *ppb) 88 { 89 struct pps_data *sc; 90 static int once; 91 92 if (!once++) 93 cdevsw_add(&pps_cdevsw); 94 95 sc = (struct pps_data *) malloc(sizeof(struct pps_data), 96 M_TEMP, M_NOWAIT); 97 if (!sc) { 98 printf(PPS_NAME ": cannot malloc!\n"); 99 return (0); 100 } 101 bzero(sc, sizeof(struct pps_data)); 102 103 softc[npps] = sc; 104 105 sc->pps_unit = npps++; 106 107 sc->pps_dev.id_unit = sc->pps_unit; 108 sc->pps_dev.ppb = ppb; 109 sc->pps_dev.name = ppsdriver.name; 110 sc->pps_dev.intr = ppsintr; 111 112 sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 113 pps_init(&sc->pps); 114 return (&sc->pps_dev); 115 } 116 117 static int 118 ppsattach(struct ppb_device *dev) 119 { 120 121 /* 122 * Report ourselves 123 */ 124 printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 125 dev->id_unit, dev->ppb->ppb_link->adapter_unit); 126 127 #ifdef DEVFS 128 devfs_add_devswf(&pps_cdevsw, 129 dev->id_unit, DV_CHR, 130 UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit); 131 #endif 132 return (1); 133 } 134 135 static int 136 ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 137 { 138 struct pps_data *sc; 139 u_int unit = minor(dev); 140 141 if ((unit >= npps)) 142 return (ENXIO); 143 144 sc = softc[unit]; 145 146 if (!sc->pps_open) { 147 if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 148 return (EINTR); 149 150 ppb_wctr(&sc->pps_dev, 0); 151 ppb_wctr(&sc->pps_dev, IRQENABLE); 152 sc->pps_open = 1; 153 } 154 155 return(0); 156 } 157 158 static int 159 ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 160 { 161 struct pps_data *sc = softc[minor(dev)]; 162 163 sc->pps.ppsparam.mode = 0; /* PHK ??? */ 164 165 ppb_wdtr(&sc->pps_dev, 0); 166 ppb_wctr(&sc->pps_dev, 0); 167 168 ppb_release_bus(&sc->pps_dev); 169 sc->pps_open = 0; 170 return(0); 171 } 172 173 static void 174 ppsintr(int unit) 175 { 176 struct pps_data *sc = softc[unit]; 177 struct timecounter *tc; 178 unsigned count; 179 180 tc = timecounter; 181 count = timecounter->tc_get_timecount(tc); 182 if (!(ppb_rstr(&sc->pps_dev) & nACK)) 183 return; 184 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 185 ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); 186 pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 187 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 188 ppb_wctr(&sc->pps_dev, IRQENABLE); 189 } 190 191 static int 192 ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 193 { 194 struct pps_data *sc = softc[minor(dev)]; 195 196 return (pps_ioctl(cmd, data, &sc->pps)); 197 } 198 199