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