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.14 1999/03/11 15:09:51 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 struct ppb_device pps_dev; 38 struct pps_state pps; 39 } *softc[NPPS]; 40 41 static int npps; 42 43 /* 44 * Make ourselves visible as a ppbus driver 45 */ 46 47 static struct ppb_device *ppsprobe(struct ppb_data *ppb); 48 static int ppsattach(struct ppb_device *dev); 49 static void ppsintr(int unit); 50 static void pps_drvinit(void *unused); 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 { ppsopen, ppsclose, noread, nowrite, 65 ppsioctl, nullstop, nullreset, nodevtotty, 66 seltrue, nommap, nostrat, PPS_NAME, 67 NULL, -1 }; 68 69 70 static struct ppb_device * 71 ppsprobe(struct ppb_data *ppb) 72 { 73 struct pps_data *sc; 74 75 sc = (struct pps_data *) malloc(sizeof(struct pps_data), 76 M_TEMP, M_NOWAIT); 77 if (!sc) { 78 printf(PPS_NAME ": cannot malloc!\n"); 79 return (0); 80 } 81 bzero(sc, sizeof(struct pps_data)); 82 83 softc[npps] = sc; 84 85 sc->pps_unit = npps++; 86 87 sc->pps_dev.id_unit = sc->pps_unit; 88 sc->pps_dev.ppb = ppb; 89 sc->pps_dev.name = ppsdriver.name; 90 sc->pps_dev.intr = ppsintr; 91 92 sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 93 pps_init(&sc->pps); 94 return (&sc->pps_dev); 95 } 96 97 static int 98 ppsattach(struct ppb_device *dev) 99 { 100 dev_t devt; 101 102 /* 103 * Report ourselves 104 */ 105 printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 106 dev->id_unit, dev->ppb->ppb_link->adapter_unit); 107 108 #ifdef DEVFS 109 devfs_add_devswf(&pps_cdevsw, 110 dev->id_unit, DV_CHR, 111 UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit); 112 #endif 113 devt = makedev(CDEV_MAJOR, 0); 114 cdevsw_add(&devt, &pps_cdevsw, NULL); 115 return (1); 116 } 117 118 static int 119 ppsopen(dev_t dev, int flags, int fmt, struct proc *p) 120 { 121 struct pps_data *sc; 122 u_int unit = minor(dev); 123 124 if ((unit >= npps)) 125 return (ENXIO); 126 127 sc = softc[unit]; 128 129 if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 130 return (EINTR); 131 132 ppb_wctr(&sc->pps_dev, 0); 133 ppb_wctr(&sc->pps_dev, IRQENABLE); 134 135 return(0); 136 } 137 138 static int 139 ppsclose(dev_t dev, int flags, int fmt, struct proc *p) 140 { 141 struct pps_data *sc = softc[minor(dev)]; 142 143 sc->pps.ppsparam.mode = 0; /* PHK ??? */ 144 145 ppb_wdtr(&sc->pps_dev, 0); 146 ppb_wctr(&sc->pps_dev, 0); 147 148 ppb_release_bus(&sc->pps_dev); 149 return(0); 150 } 151 152 static void 153 ppsintr(int unit) 154 { 155 struct pps_data *sc = softc[unit]; 156 struct timecounter *tc; 157 unsigned count; 158 159 tc = timecounter; 160 count = timecounter->tc_get_timecount(tc); 161 if (!(ppb_rstr(&sc->pps_dev) & nACK)) 162 return; 163 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 164 ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); 165 pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 166 if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 167 ppb_wctr(&sc->pps_dev, IRQENABLE); 168 } 169 170 static int 171 ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 172 { 173 struct pps_data *sc = softc[minor(dev)]; 174 175 return (pps_ioctl(cmd, data, &sc->pps)); 176 } 177 178