pps.c revision 44666
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 *
944666Sphk * $Id: pps.c,v 1.13 1999/01/30 15:35:39 nsouch Exp $
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
1833396Sphk#include "opt_devfs.h"
1933396Sphk
2033323Sphk#include <sys/param.h>
2133323Sphk#include <sys/kernel.h>
2233323Sphk#include <sys/systm.h>
2333323Sphk#include <sys/conf.h>
2436739Sphk#include <sys/timepps.h>
2533323Sphk#ifdef DEVFS
2633323Sphk#include <sys/devfsext.h>
2733396Sphk#endif
2833323Sphk#include <sys/malloc.h>
2933323Sphk
3033323Sphk#include <dev/ppbus/ppbconf.h>
3133326Sphk#include "pps.h"
3233323Sphk
3336739Sphk#define PPS_NAME	"lppps"		/* our official name */
3433323Sphk
3533396Sphkstatic struct pps_data {
3633396Sphk	int	pps_unit;
3733396Sphk	struct	ppb_device pps_dev;
3844666Sphk	struct	pps_state pps;
3933326Sphk} *softc[NPPS];
4033323Sphk
4133396Sphkstatic int npps;
4244666Sphkstatic pps_devsw_installed = 0;
4333323Sphk
4433323Sphk/*
4533323Sphk * Make ourselves visible as a ppbus driver
4633323Sphk */
4733323Sphk
4833396Sphkstatic struct ppb_device	*ppsprobe(struct ppb_data *ppb);
4933396Sphkstatic int			ppsattach(struct ppb_device *dev);
5033396Sphkstatic void			ppsintr(int unit);
5133396Sphkstatic void			pps_drvinit(void *unused);
5233323Sphk
5333396Sphkstatic struct ppb_driver ppsdriver = {
5433396Sphk    ppsprobe, ppsattach, PPS_NAME
5533323Sphk};
5633323Sphk
5733396SphkDATA_SET(ppbdriver_set, ppsdriver);
5833323Sphk
5933396Sphkstatic	d_open_t	ppsopen;
6033396Sphkstatic	d_close_t	ppsclose;
6136739Sphkstatic	d_ioctl_t	ppsioctl;
6233323Sphk
6333323Sphk#define CDEV_MAJOR 89
6433396Sphkstatic struct cdevsw pps_cdevsw =
6536739Sphk	{ ppsopen,	ppsclose,	noread,		nowrite,
6636739Sphk	  ppsioctl,	nullstop,	nullreset,	nodevtotty,
6733326Sphk	  seltrue,	nommap,		nostrat,	PPS_NAME,
6833323Sphk	  NULL,		-1 };
6933323Sphk
7044666Sphk
7133323Sphkstatic struct ppb_device *
7233396Sphkppsprobe(struct ppb_data *ppb)
7333323Sphk{
7433396Sphk	struct pps_data *sc;
7533323Sphk
7633396Sphk	sc = (struct pps_data *) malloc(sizeof(struct pps_data),
7733323Sphk							M_TEMP, M_NOWAIT);
7833323Sphk	if (!sc) {
7933326Sphk		printf(PPS_NAME ": cannot malloc!\n");
8033323Sphk		return (0);
8133323Sphk	}
8233396Sphk	bzero(sc, sizeof(struct pps_data));
8333323Sphk
8433396Sphk	softc[npps] = sc;
8533323Sphk
8633396Sphk	sc->pps_unit = npps++;
8733323Sphk
8833396Sphk	sc->pps_dev.id_unit = sc->pps_unit;
8933396Sphk	sc->pps_dev.ppb = ppb;
9038061Smsmith	sc->pps_dev.name = ppsdriver.name;
9133396Sphk	sc->pps_dev.intr = ppsintr;
9233323Sphk
9344666Sphk	sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
9444666Sphk	pps_init(&sc->pps);
9533396Sphk	return (&sc->pps_dev);
9633323Sphk}
9733323Sphk
9833323Sphkstatic int
9933396Sphkppsattach(struct ppb_device *dev)
10033323Sphk{
10144666Sphk	dev_t devt;
10244666Sphk
10333323Sphk	/*
10433323Sphk	 * Report ourselves
10533323Sphk	 */
10633326Sphk	printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n",
10733323Sphk	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
10833323Sphk
10933323Sphk#ifdef DEVFS
11033396Sphk	devfs_add_devswf(&pps_cdevsw,
11133323Sphk		dev->id_unit, DV_CHR,
11233326Sphk		UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit);
11333323Sphk#endif
11444666Sphk	if( ! pps_devsw_installed ) {
11544666Sphk		devt = makedev(CDEV_MAJOR, 0);
11644666Sphk		cdevsw_add(&devt, &pps_cdevsw, NULL);
11744666Sphk		pps_devsw_installed = 1;
11844666Sphk    	}
11933323Sphk	return (1);
12033323Sphk}
12133323Sphk
12233323Sphkstatic	int
12333396Sphkppsopen(dev_t dev, int flags, int fmt, struct proc *p)
12433323Sphk{
12533396Sphk	struct pps_data *sc;
12633323Sphk	u_int unit = minor(dev);
12733323Sphk
12833396Sphk	if ((unit >= npps))
12933323Sphk		return (ENXIO);
13033323Sphk
13133323Sphk	sc = softc[unit];
13233323Sphk
13333396Sphk	if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
13433323Sphk		return (EINTR);
13533323Sphk
13643433Snsouch	ppb_wctr(&sc->pps_dev, 0);
13736739Sphk	ppb_wctr(&sc->pps_dev, IRQENABLE);
13833323Sphk
13933323Sphk	return(0);
14033323Sphk}
14133323Sphk
14233323Sphkstatic	int
14333396Sphkppsclose(dev_t dev, int flags, int fmt, struct proc *p)
14433323Sphk{
14533396Sphk	struct pps_data *sc = softc[minor(dev)];
14633323Sphk
14744666Sphk	sc->pps.ppsparam.mode = 0;	/* PHK ??? */
14843433Snsouch
14943433Snsouch	ppb_wdtr(&sc->pps_dev, 0);
15043433Snsouch	ppb_wctr(&sc->pps_dev, 0);
15143433Snsouch
15233396Sphk	ppb_release_bus(&sc->pps_dev);
15333323Sphk	return(0);
15433323Sphk}
15533323Sphk
15633323Sphkstatic void
15733396Sphkppsintr(int unit)
15833323Sphk{
15933396Sphk	struct pps_data *sc = softc[unit];
16044666Sphk	struct timecounter *tc;
16144666Sphk	unsigned count;
16233323Sphk
16344666Sphk	tc = timecounter;
16444666Sphk	count = timecounter->tc_get_timecount(tc);
16533396Sphk	if (!(ppb_rstr(&sc->pps_dev) & nACK))
16633323Sphk		return;
16744666Sphk	if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
16836739Sphk		ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED);
16944666Sphk	pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT);
17044666Sphk	if (sc->pps.ppsparam.mode & PPS_ECHOASSERT)
17136739Sphk		ppb_wctr(&sc->pps_dev, IRQENABLE);
17233323Sphk}
17333323Sphk
17436739Sphkstatic int
17536748Sbdeppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
17633323Sphk{
17733396Sphk	struct pps_data *sc = softc[minor(dev)];
17833323Sphk
17944666Sphk	return (pps_ioctl(cmd, data, &sc->pps));
18033323Sphk}
18133323Sphk
182