pps.c revision 50477
152284Sobrien/* 250397Sobrien * ---------------------------------------------------------------------------- 3169689Skan * "THE BEER-WARE LICENSE" (Revision 42): 490075Sobrien * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 550397Sobrien * can do whatever you want with this stuff. If we meet some day, and you think 690075Sobrien * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 750397Sobrien * ---------------------------------------------------------------------------- 890075Sobrien * 990075Sobrien * $FreeBSD: head/sys/dev/ppbus/pps.c 50477 1999-08-28 01:08:13Z peter $ 1090075Sobrien * 1190075Sobrien * This driver implements a draft-mogul-pps-api-02.txt PPS source. 1250397Sobrien * 1390075Sobrien * The input pin is pin#10 1490075Sobrien * The echo output pin is pin#14 1590075Sobrien * 1690075Sobrien */ 1750397Sobrien 1850397Sobrien#include <sys/param.h> 1990075Sobrien#include <sys/kernel.h> 20169689Skan#include <sys/systm.h> 21169689Skan#include <sys/conf.h> 2250397Sobrien#include <sys/timepps.h> 2350397Sobrien#include <sys/malloc.h> 2450397Sobrien 2550397Sobrien#include <dev/ppbus/ppbconf.h> 2650397Sobrien#include "pps.h" 2750397Sobrien 2852284Sobrien#define PPS_NAME "pps" /* our official name */ 2952284Sobrien 3052284Sobrienstruct pps_data { 3150397Sobrien int pps_open; 3250397Sobrien struct ppb_device pps_dev; 3350397Sobrien struct pps_state pps; 3450397Sobrien}; 3550397Sobrien 3650397Sobrienstatic int npps; 3750397Sobrien 3850397Sobrien/* 3950397Sobrien * Make ourselves visible as a ppbus driver 4050397Sobrien */ 4150397Sobrien 4250397Sobrienstatic struct ppb_device *ppsprobe(struct ppb_data *ppb); 4350397Sobrienstatic int ppsattach(struct ppb_device *dev); 4450397Sobrienstatic void ppsintr(struct ppb_device *ppd); 4550397Sobrien 4650397Sobrienstatic struct ppb_driver ppsdriver = { 4750397Sobrien ppsprobe, ppsattach, PPS_NAME 4850397Sobrien}; 4950397Sobrien 5050397SobrienDATA_SET(ppbdriver_set, ppsdriver); 5150397Sobrien 5250397Sobrienstatic d_open_t ppsopen; 5350397Sobrienstatic d_close_t ppsclose; 5450397Sobrienstatic d_ioctl_t ppsioctl; 5550397Sobrien 5650397Sobrien#define CDEV_MAJOR 89 5750397Sobrienstatic struct cdevsw pps_cdevsw = { 5850397Sobrien /* open */ ppsopen, 5950397Sobrien /* close */ ppsclose, 6050397Sobrien /* read */ noread, 6150397Sobrien /* write */ nowrite, 6250397Sobrien /* ioctl */ ppsioctl, 6350397Sobrien /* stop */ nostop, 6450397Sobrien /* reset */ noreset, 6550397Sobrien /* devtotty */ nodevtotty, 6650397Sobrien /* poll */ nopoll, 6750397Sobrien /* mmap */ nommap, 6850397Sobrien /* strategy */ nostrategy, 6950397Sobrien /* name */ PPS_NAME, 7050397Sobrien /* parms */ noparms, 7150397Sobrien /* maj */ CDEV_MAJOR, 7250397Sobrien /* dump */ nodump, 7350397Sobrien /* psize */ nopsize, 7450397Sobrien /* flags */ 0, 7550397Sobrien /* maxio */ 0, 7650397Sobrien /* bmaj */ -1 7750397Sobrien}; 7850397Sobrien 7950397Sobrien 8050397Sobrienstatic struct ppb_device * 8150397Sobrienppsprobe(struct ppb_data *ppb) 8250397Sobrien{ 8350397Sobrien struct pps_data *sc; 8450397Sobrien static int once; 8550397Sobrien dev_t dev; 8650397Sobrien 8750397Sobrien if (!once++) 8850397Sobrien cdevsw_add(&pps_cdevsw); 8950397Sobrien 9050397Sobrien sc = (struct pps_data *) malloc(sizeof(struct pps_data), 9150397Sobrien M_TEMP, M_NOWAIT); 9250397Sobrien if (!sc) { 9350397Sobrien printf(PPS_NAME ": cannot malloc!\n"); 9450397Sobrien return (0); 9550397Sobrien } 9650397Sobrien bzero(sc, sizeof(struct pps_data)); 9750397Sobrien 9850397Sobrien dev = make_dev(&pps_cdevsw, npps, 9950397Sobrien UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", npps); 10050397Sobrien 10150397Sobrien dev->si_drv1 = sc; 10250397Sobrien 10350397Sobrien sc->pps_dev.id_unit = npps++; 10450397Sobrien sc->pps_dev.ppb = ppb; 10550397Sobrien sc->pps_dev.name = ppsdriver.name; 10650397Sobrien sc->pps_dev.bintr = ppsintr; 10750397Sobrien sc->pps_dev.drv1 = sc; 10850397Sobrien 10950397Sobrien sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 11050397Sobrien pps_init(&sc->pps); 11150397Sobrien return (&sc->pps_dev); 11250397Sobrien} 11350397Sobrien 11450397Sobrienstatic int 11550397Sobrienppsattach(struct ppb_device *dev) 11650397Sobrien{ 11750397Sobrien 11850397Sobrien /* 11950397Sobrien * Report ourselves 12050397Sobrien */ 12150397Sobrien printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n", 12250397Sobrien dev->id_unit, dev->ppb->ppb_link->adapter_unit); 12350397Sobrien 12450397Sobrien return (1); 12552284Sobrien} 12652284Sobrien 12752284Sobrienstatic int 12852284Sobrienppsopen(dev_t dev, int flags, int fmt, struct proc *p) 12990075Sobrien{ 13090075Sobrien struct pps_data *sc; 13190075Sobrien u_int unit = minor(dev); 13290075Sobrien 13352284Sobrien if ((unit >= npps)) 13452284Sobrien return (ENXIO); 13552284Sobrien 13652284Sobrien sc = dev->si_drv1; 13752284Sobrien 13852284Sobrien if (!sc->pps_open) { 13952284Sobrien if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR)) 14052284Sobrien return (EINTR); 14152284Sobrien 14250397Sobrien ppb_wctr(&sc->pps_dev, 0); 14350397Sobrien ppb_wctr(&sc->pps_dev, IRQENABLE); 14450397Sobrien sc->pps_open = 1; 14550397Sobrien } 14650397Sobrien 14750397Sobrien return(0); 148132718Skan} 149132718Skan 15052284Sobrienstatic int 15150397Sobrienppsclose(dev_t dev, int flags, int fmt, struct proc *p) 15250397Sobrien{ 153132718Skan struct pps_data *sc = dev->si_drv1; 15490075Sobrien 15550397Sobrien sc->pps.ppsparam.mode = 0; /* PHK ??? */ 15650397Sobrien 15750397Sobrien ppb_wdtr(&sc->pps_dev, 0); 15850397Sobrien ppb_wctr(&sc->pps_dev, 0); 15950397Sobrien 16050397Sobrien ppb_release_bus(&sc->pps_dev); 16150397Sobrien sc->pps_open = 0; 16250397Sobrien return(0); 16390075Sobrien} 164117395Skan 16596263Sobrienstatic void 16690075Sobrienppsintr(struct ppb_device *ppd) 16790075Sobrien{ 168117395Skan struct pps_data *sc = ppd->drv1; 169132718Skan struct timecounter *tc; 17050397Sobrien unsigned count; 171169689Skan 172169689Skan tc = timecounter; 173169689Skan count = timecounter->tc_get_timecount(tc); 17450397Sobrien if (!(ppb_rstr(&sc->pps_dev) & nACK)) 17550397Sobrien return; 17650397Sobrien if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 17750397Sobrien ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED); 17850397Sobrien pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 17950397Sobrien if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 18050397Sobrien ppb_wctr(&sc->pps_dev, IRQENABLE); 18150397Sobrien} 18250397Sobrien 18350397Sobrienstatic int 18450397Sobrienppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 18550397Sobrien{ 18650397Sobrien struct pps_data *sc = dev->si_drv1; 18752284Sobrien 18852284Sobrien return (pps_ioctl(cmd, data, &sc->pps)); 18950397Sobrien} 19052284Sobrien 19150397Sobrien