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