10ef2b8422
Change microseq offsets. Previously, offsets of the program counter where added to the index of the current microinstruction. Make them rely on the index of the next executed microinstruction. Suggested by: Luigi Rizzo <luigi@labinfo.iet.unipi.it>
213 lines
4.5 KiB
C
213 lines
4.5 KiB
C
/*
|
|
* ----------------------------------------------------------------------------
|
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
|
* <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
|
|
* can do whatever you want with this stuff. If we meet some day, and you think
|
|
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* $Id: pps.c,v 1.12 1998/12/07 21:58:16 archie Exp $
|
|
*
|
|
* This driver implements a draft-mogul-pps-api-02.txt PPS source.
|
|
*
|
|
* The input pin is pin#10
|
|
* The echo output pin is pin#14
|
|
*
|
|
*/
|
|
|
|
#include "opt_devfs.h"
|
|
#include "opt_ntp.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/timepps.h>
|
|
#ifdef DEVFS
|
|
#include <sys/devfsext.h>
|
|
#endif
|
|
#include <sys/malloc.h>
|
|
|
|
#include <dev/ppbus/ppbconf.h>
|
|
#include "pps.h"
|
|
|
|
#define PPS_NAME "lppps" /* our official name */
|
|
|
|
static struct pps_data {
|
|
int pps_unit;
|
|
struct ppb_device pps_dev;
|
|
pps_params_t ppsparam;
|
|
pps_info_t ppsinfo;
|
|
} *softc[NPPS];
|
|
|
|
static int ppscap =
|
|
PPS_CAPTUREASSERT |
|
|
#ifdef PPS_SYNC
|
|
PPS_HARDPPSONASSERT |
|
|
#endif /* PPS_SYNC */
|
|
PPS_OFFSETASSERT |
|
|
PPS_ECHOASSERT |
|
|
PPS_TSFMT_TSPEC;
|
|
|
|
static int npps;
|
|
|
|
/*
|
|
* Make ourselves visible as a ppbus driver
|
|
*/
|
|
|
|
static struct ppb_device *ppsprobe(struct ppb_data *ppb);
|
|
static int ppsattach(struct ppb_device *dev);
|
|
static void ppsintr(int unit);
|
|
static void pps_drvinit(void *unused);
|
|
|
|
static struct ppb_driver ppsdriver = {
|
|
ppsprobe, ppsattach, PPS_NAME
|
|
};
|
|
|
|
DATA_SET(ppbdriver_set, ppsdriver);
|
|
|
|
static d_open_t ppsopen;
|
|
static d_close_t ppsclose;
|
|
static d_ioctl_t ppsioctl;
|
|
|
|
#define CDEV_MAJOR 89
|
|
static struct cdevsw pps_cdevsw =
|
|
{ ppsopen, ppsclose, noread, nowrite,
|
|
ppsioctl, nullstop, nullreset, nodevtotty,
|
|
seltrue, nommap, nostrat, PPS_NAME,
|
|
NULL, -1 };
|
|
|
|
static struct ppb_device *
|
|
ppsprobe(struct ppb_data *ppb)
|
|
{
|
|
struct pps_data *sc;
|
|
|
|
sc = (struct pps_data *) malloc(sizeof(struct pps_data),
|
|
M_TEMP, M_NOWAIT);
|
|
if (!sc) {
|
|
printf(PPS_NAME ": cannot malloc!\n");
|
|
return (0);
|
|
}
|
|
bzero(sc, sizeof(struct pps_data));
|
|
|
|
softc[npps] = sc;
|
|
|
|
sc->pps_unit = npps++;
|
|
|
|
sc->pps_dev.id_unit = sc->pps_unit;
|
|
sc->pps_dev.ppb = ppb;
|
|
sc->pps_dev.name = ppsdriver.name;
|
|
sc->pps_dev.intr = ppsintr;
|
|
|
|
return (&sc->pps_dev);
|
|
}
|
|
|
|
static int
|
|
ppsattach(struct ppb_device *dev)
|
|
{
|
|
/*
|
|
* Report ourselves
|
|
*/
|
|
printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n",
|
|
dev->id_unit, dev->ppb->ppb_link->adapter_unit);
|
|
|
|
#ifdef DEVFS
|
|
devfs_add_devswf(&pps_cdevsw,
|
|
dev->id_unit, DV_CHR,
|
|
UID_ROOT, GID_WHEEL, 0600, PPS_NAME "%d", dev->id_unit);
|
|
#endif
|
|
|
|
return (1);
|
|
}
|
|
|
|
static int
|
|
ppsopen(dev_t dev, int flags, int fmt, struct proc *p)
|
|
{
|
|
struct pps_data *sc;
|
|
u_int unit = minor(dev);
|
|
|
|
if ((unit >= npps))
|
|
return (ENXIO);
|
|
|
|
sc = softc[unit];
|
|
|
|
if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
|
|
return (EINTR);
|
|
|
|
ppb_wctr(&sc->pps_dev, 0);
|
|
ppb_wctr(&sc->pps_dev, IRQENABLE);
|
|
|
|
return(0);
|
|
}
|
|
|
|
static int
|
|
ppsclose(dev_t dev, int flags, int fmt, struct proc *p)
|
|
{
|
|
struct pps_data *sc = softc[minor(dev)];
|
|
|
|
sc->ppsparam.mode = 0;
|
|
|
|
ppb_wdtr(&sc->pps_dev, 0);
|
|
ppb_wctr(&sc->pps_dev, 0);
|
|
|
|
ppb_release_bus(&sc->pps_dev);
|
|
return(0);
|
|
}
|
|
|
|
static void
|
|
ppsintr(int unit)
|
|
{
|
|
struct pps_data *sc = softc[unit];
|
|
struct timespec tc;
|
|
|
|
nanotime(&tc);
|
|
if (!(ppb_rstr(&sc->pps_dev) & nACK))
|
|
return;
|
|
if (sc->ppsparam.mode & PPS_ECHOASSERT)
|
|
ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED);
|
|
if (sc->ppsparam.mode & PPS_OFFSETASSERT) {
|
|
timespecadd(&tc, &sc->ppsparam.assert_offset);
|
|
if (tc.tv_nsec < 0) {
|
|
tc.tv_sec--;
|
|
tc.tv_nsec += 1000000000;
|
|
}
|
|
}
|
|
sc->ppsinfo.assert_timestamp = tc;
|
|
sc->ppsinfo.assert_sequence++;
|
|
#ifdef PPS_SYNC
|
|
if (sc->ppsparam.mode & PPS_HARDPPSONASSERT) {
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec = tc.tv_sec;
|
|
tv.tv_usec = tc.tv_nsec / 1000;
|
|
hardpps(&tv, tv.tv_usec);
|
|
}
|
|
#endif /* PPS_SYNC */
|
|
if (sc->ppsparam.mode & PPS_ECHOASSERT)
|
|
ppb_wctr(&sc->pps_dev, IRQENABLE);
|
|
}
|
|
|
|
static int
|
|
ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
|
|
{
|
|
struct pps_data *sc = softc[minor(dev)];
|
|
|
|
return (std_pps_ioctl(cmd, data, &sc->ppsparam, &sc->ppsinfo, ppscap));
|
|
}
|
|
|
|
static pps_devsw_installed = 0;
|
|
|
|
static void
|
|
pps_drvinit(void *unused)
|
|
{
|
|
dev_t dev;
|
|
|
|
if( ! pps_devsw_installed ) {
|
|
dev = makedev(CDEV_MAJOR, 0);
|
|
cdevsw_add(&dev, &pps_cdevsw, NULL);
|
|
pps_devsw_installed = 1;
|
|
}
|
|
}
|
|
|
|
SYSINIT(ppsdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pps_drvinit,NULL)
|