pps.c revision 56455
133323Sphk/* 233323Sphk * ---------------------------------------------------------------------------- 333323Sphk * "THE BEER-WARE LICENSE" (Revision 42): 433323Sphk * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 533323Sphk * can do whatever you want with this stuff. If we meet some day, and you think 633323Sphk * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 733323Sphk * ---------------------------------------------------------------------------- 833323Sphk * 950477Speter * $FreeBSD: head/sys/dev/ppbus/pps.c 56455 2000-01-23 14:41:04Z peter $ 1033323Sphk * 1136938Sphk * This driver implements a draft-mogul-pps-api-02.txt PPS source. 1236938Sphk * 1336938Sphk * The input pin is pin#10 1436938Sphk * The echo output pin is pin#14 1536938Sphk * 1633323Sphk */ 1733323Sphk 1833323Sphk#include <sys/param.h> 1933323Sphk#include <sys/kernel.h> 2033323Sphk#include <sys/systm.h> 2155939Snsouch#include <sys/module.h> 2255939Snsouch#include <sys/bus.h> 2333323Sphk#include <sys/conf.h> 2436739Sphk#include <sys/timepps.h> 2533323Sphk#include <sys/malloc.h> 2655939Snsouch#include <machine/bus.h> 2755939Snsouch#include <machine/resource.h> 2855939Snsouch#include <sys/rman.h> 2933323Sphk 3033323Sphk#include <dev/ppbus/ppbconf.h> 3155939Snsouch#include "ppbus_if.h" 3255939Snsouch#include <dev/ppbus/ppbio.h> 3333326Sphk#include "pps.h" 3433323Sphk 3549550Sphk#define PPS_NAME "pps" /* our official name */ 3633323Sphk 3749550Sphkstruct pps_data { 3846053Sphk int pps_open; 3933396Sphk struct ppb_device pps_dev; 4044666Sphk struct pps_state pps; 4155939Snsouch 4255939Snsouch struct resource *intr_resource; /* interrupt resource */ 4355939Snsouch void *intr_cookie; /* interrupt registration cookie */ 4449550Sphk}; 4533323Sphk 4655939Snsouchstatic void ppsintr(void *arg); 4733323Sphk 4855939Snsouch#define DEVTOSOFTC(dev) \ 4955939Snsouch ((struct pps_data *)device_get_softc(dev)) 5055939Snsouch#define UNITOSOFTC(unit) \ 5155939Snsouch ((struct pps_data *)devclass_get_softc(pps_devclass, (unit))) 5255939Snsouch#define UNITODEVICE(unit) \ 5355939Snsouch (devclass_get_device(pps_devclass, (unit))) 5433323Sphk 5555939Snsouchstatic devclass_t pps_devclass; 5633323Sphk 5733396Sphkstatic d_open_t ppsopen; 5833396Sphkstatic d_close_t ppsclose; 5936739Sphkstatic d_ioctl_t ppsioctl; 6033323Sphk 6133323Sphk#define CDEV_MAJOR 89 6247625Sphkstatic struct cdevsw pps_cdevsw = { 6347625Sphk /* open */ ppsopen, 6447625Sphk /* close */ ppsclose, 6547625Sphk /* read */ noread, 6647625Sphk /* write */ nowrite, 6747625Sphk /* ioctl */ ppsioctl, 6847625Sphk /* poll */ nopoll, 6947625Sphk /* mmap */ nommap, 7047625Sphk /* strategy */ nostrategy, 7147625Sphk /* name */ PPS_NAME, 7247625Sphk /* maj */ CDEV_MAJOR, 7347625Sphk /* dump */ nodump, 7447625Sphk /* psize */ nopsize, 7547625Sphk /* flags */ 0, 7647625Sphk /* bmaj */ -1 7747625Sphk}; 7833323Sphk 7956455Speterstatic void 8056455Speterppsidentify(driver_t *driver, device_t parent) 8156455Speter{ 8256455Speter 8356455Speter BUS_ADD_CHILD(parent, 0, PPS_NAME, 0); 8456455Speter} 8556455Speter 8655939Snsouchstatic int 8755939Snsouchppsprobe(device_t ppsdev) 8833323Sphk{ 8933396Sphk struct pps_data *sc; 9049550Sphk dev_t dev; 9155939Snsouch int unit; 9233323Sphk 9355939Snsouch sc = DEVTOSOFTC(ppsdev); 9433396Sphk bzero(sc, sizeof(struct pps_data)); 9533323Sphk 9655939Snsouch unit = device_get_unit(ppsdev); 9755939Snsouch dev = make_dev(&pps_cdevsw, unit, 9855939Snsouch UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", unit); 9933323Sphk 10055939Snsouch device_set_desc(ppsdev, "Pulse per second Timing Interface"); 10133323Sphk 10244666Sphk sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT; 10344666Sphk pps_init(&sc->pps); 10455939Snsouch return (0); 10533323Sphk} 10633323Sphk 10733323Sphkstatic int 10855939Snsouchppsattach(device_t dev) 10933323Sphk{ 11055939Snsouch struct pps_data *sc = DEVTOSOFTC(dev); 11155939Snsouch device_t ppbus = device_get_parent(dev); 11255939Snsouch int irq, zero = 0; 11344666Sphk 11455939Snsouch /* retrieve the ppbus irq */ 11555939Snsouch BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); 11633323Sphk 11755939Snsouch if (irq > 0) { 11855939Snsouch /* declare our interrupt handler */ 11955939Snsouch sc->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, 12055939Snsouch &zero, irq, irq, 1, RF_SHAREABLE); 12155939Snsouch } 12255939Snsouch /* interrupts seem mandatory */ 12355939Snsouch if (sc->intr_resource == 0) 12455939Snsouch return (ENXIO); 12555939Snsouch 12655939Snsouch return (0); 12733323Sphk} 12833323Sphk 12933323Sphkstatic int 13033396Sphkppsopen(dev_t dev, int flags, int fmt, struct proc *p) 13133323Sphk{ 13233323Sphk u_int unit = minor(dev); 13355939Snsouch struct pps_data *sc = UNITOSOFTC(unit); 13455939Snsouch device_t ppsdev = UNITODEVICE(unit); 13555939Snsouch device_t ppbus = device_get_parent(ppsdev); 13655939Snsouch int error; 13733323Sphk 13846053Sphk if (!sc->pps_open) { 13955939Snsouch if (ppb_request_bus(ppbus, ppsdev, PPB_WAIT|PPB_INTR)) 14046053Sphk return (EINTR); 14133323Sphk 14255939Snsouch /* attach the interrupt handler */ 14355939Snsouch if ((error = BUS_SETUP_INTR(ppbus, ppsdev, sc->intr_resource, 14455939Snsouch INTR_TYPE_TTY, ppsintr, ppsdev, 14555939Snsouch &sc->intr_cookie))) { 14655939Snsouch ppb_release_bus(ppbus, ppsdev); 14755939Snsouch return (error); 14855939Snsouch } 14955939Snsouch 15055939Snsouch ppb_wctr(ppbus, 0); 15155939Snsouch ppb_wctr(ppbus, IRQENABLE); 15246053Sphk sc->pps_open = 1; 15346053Sphk } 15433323Sphk 15533323Sphk return(0); 15633323Sphk} 15733323Sphk 15833323Sphkstatic int 15933396Sphkppsclose(dev_t dev, int flags, int fmt, struct proc *p) 16033323Sphk{ 16155939Snsouch u_int unit = minor(dev); 16255939Snsouch struct pps_data *sc = UNITOSOFTC(unit); 16355939Snsouch device_t ppsdev = UNITODEVICE(unit); 16455939Snsouch device_t ppbus = device_get_parent(ppsdev); 16533323Sphk 16644666Sphk sc->pps.ppsparam.mode = 0; /* PHK ??? */ 16743433Snsouch 16855939Snsouch ppb_wdtr(ppbus, 0); 16955939Snsouch ppb_wctr(ppbus, 0); 17043433Snsouch 17155939Snsouch /* Note: the interrupt handler is automatically detached */ 17255939Snsouch ppb_release_bus(ppbus, ppsdev); 17346053Sphk sc->pps_open = 0; 17433323Sphk return(0); 17533323Sphk} 17633323Sphk 17733323Sphkstatic void 17855939Snsouchppsintr(void *arg) 17933323Sphk{ 18055939Snsouch device_t ppsdev = (device_t)arg; 18155939Snsouch device_t ppbus = device_get_parent(ppsdev); 18255939Snsouch struct pps_data *sc = DEVTOSOFTC(ppsdev); 18344666Sphk struct timecounter *tc; 18444666Sphk unsigned count; 18533323Sphk 18644666Sphk tc = timecounter; 18744666Sphk count = timecounter->tc_get_timecount(tc); 18855939Snsouch if (!(ppb_rstr(ppbus) & nACK)) 18933323Sphk return; 19044666Sphk if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 19155939Snsouch ppb_wctr(ppbus, IRQENABLE | AUTOFEED); 19244666Sphk pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT); 19344666Sphk if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 19455939Snsouch ppb_wctr(ppbus, IRQENABLE); 19533323Sphk} 19633323Sphk 19736739Sphkstatic int 19836748Sbdeppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 19933323Sphk{ 20055939Snsouch u_int unit = minor(dev); 20155939Snsouch struct pps_data *sc = UNITOSOFTC(unit); 20233323Sphk 20344666Sphk return (pps_ioctl(cmd, data, &sc->pps)); 20433323Sphk} 20533323Sphk 20656455Speterstatic device_method_t pps_methods[] = { 20756455Speter /* device interface */ 20856455Speter DEVMETHOD(device_identify, ppsidentify), 20956455Speter DEVMETHOD(device_probe, ppsprobe), 21056455Speter DEVMETHOD(device_attach, ppsattach), 21156455Speter 21256455Speter { 0, 0 } 21356455Speter}; 21456455Speter 21556455Speterstatic driver_t pps_driver = { 21656455Speter PPS_NAME, 21756455Speter pps_methods, 21856455Speter sizeof(struct pps_data), 21956455Speter}; 22055939SnsouchDRIVER_MODULE(pps, ppbus, pps_driver, pps_devclass, 0, 0); 221