diff options
-rw-r--r-- | share/man/man4/mbg.4 | 30 | ||||
-rw-r--r-- | sys/dev/pci/mbg.c | 123 |
2 files changed, 131 insertions, 22 deletions
diff --git a/share/man/man4/mbg.4 b/share/man/man4/mbg.4 index 6206641c3c7..847d641f587 100644 --- a/share/man/man4/mbg.4 +++ b/share/man/man4/mbg.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: mbg.4,v 1.1 2006/12/17 16:32:35 mbalmer Exp $ +.\" $OpenBSD: mbg.4,v 1.2 2006/12/29 10:55:30 mbalmer Exp $ .\" .\" Copyright (c) 2006 Marc Balmer <mbalmer@openbsd.org> .\" @@ -19,20 +19,36 @@ .Os .Sh NAME .Nm mbg -.Nd Meinberg Funkuhren time signal station receiver +.Nd Meinberg Funkuhren radio clocks .Sh SYNOPSIS .Cd "mbg* at pci?" .Sh DESCRIPTION The .Nm -driver provides support for Meinberg Funkuhren time signal station receiver -cards. +driver provides support for Meinberg Funkuhren radio clocks (time signal +station receivers and GPS devices). +.Nm +implements a timedelta sensor and the delta (in nanoseconds) between the +received time information and the local time can be accessed through the +.Xr sysctl 8 +interface. .Pp -Currently, only the DCF77 PCI32 card is supported by -.Nm . +The card type is indicated in the sensor description. +Currently, the following cards are supported by +.Nm : +.Bl -tag -width "GPS170" -offset indent +.It PCI32 +5V DCF77 time signal station receiver card +.It PCI511 +3.3V/5V DCF77 time signal station receiver card +.It GPS170 +3.3V/5V 6-channel GPS receiver card +.El .Sh SEE ALSO .Xr intro 4 , -.Xr pci 4 +.Xr pci 4 , +.Xr ntpd 8 , +.Xr sysctl 8 .Sh HISTORY The .Nm diff --git a/sys/dev/pci/mbg.c b/sys/dev/pci/mbg.c index 7b185e59401..f244e03e6d3 100644 --- a/sys/dev/pci/mbg.c +++ b/sys/dev/pci/mbg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mbg.c,v 1.7 2006/12/23 17:46:39 deraadt Exp $ */ +/* $OpenBSD: mbg.c,v 1.8 2006/12/29 10:55:30 mbalmer Exp $ */ /* * Copyright (c) 2006 Marc Balmer <mbalmer@openbsd.org> @@ -41,6 +41,10 @@ struct mbg_softc { struct sensor sc_signal; struct sensordev sc_sensordev; u_int8_t sc_status; + + int (*sc_read)(struct mbg_softc *, int cmd, + char *buf, size_t len, + struct timespec *tstamp); }; struct mbg_time { @@ -72,7 +76,16 @@ struct mbg_time { #define AMCC_IMB4 0x1c /* incoming mailbox 4 */ #define AMCC_FIFO 0x20 /* FIFO register */ #define AMCC_INTCSR 0x38 /* interrupt control/status register */ -#define AMCC_MCSR 0x3c /* master control/status register */ +#define AMCC_MCSR 0x3c /* master control/status register */ + +/* ASIC registers */ +#define ASIC_CFG 0x00 +#define ASIC_FEATURES 0x08 /* r/o */ +#define ASIC_STATUS 0x10 +#define ASIC_CTLSTATUS 0x14 +#define ASIC_DATA 0x18 +#define ASIC_RES1 0x1c +#define ASIC_ADDON 0x20 /* commands */ #define MBG_GET_TIME 0x00 @@ -85,15 +98,17 @@ struct mbg_time { /* misc. constants */ #define MBG_FIFO_LEN 16 #define MBG_ID_LEN (2 * MBG_FIFO_LEN + 1) -#define MBG_BUSY 0x01 +#define MBG_BUSY 0x01 #define MBG_SIG_BIAS 55 #define MBG_SIG_MAX 68 int mbg_probe(struct device *, void *, void *); void mbg_attach(struct device *, struct device *, void *); -int mbg_read(struct mbg_softc *, int cmd, char *buf, size_t len, - struct timespec *tstamp); void mbg_task(void *); +int mbg_read_amcc_s5933(struct mbg_softc *, int cmd, char *buf, size_t len, + struct timespec *tstamp); +int mbg_read_asic(struct mbg_softc *, int cmd, char *buf, size_t len, + struct timespec *tstamp); struct cfattach mbg_ca = { sizeof(struct mbg_softc), mbg_probe, mbg_attach @@ -104,7 +119,9 @@ struct cfdriver mbg_cd = { }; const struct pci_matchid mbg_devices[] = { - { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI32 } + { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI32 }, + { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI511 }, + { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_GPS170 } }; int @@ -132,8 +149,23 @@ mbg_attach(struct device *parent, struct device *self, void *aux) return; } - if (mbg_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) || - mbg_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN, + switch (PCI_PRODUCT(pa->pa_id)) { + case PCI_PRODUCT_MEINBERG_PCI32: + sc->sc_read = mbg_read_amcc_s5933; + break; + case PCI_PRODUCT_MEINBERG_PCI511: + /* FALLTHROUGH */ + case PCI_PRODUCT_MEINBERG_GPS170: + sc->sc_read = mbg_read_asic; + break; + default: + /* this can not normally happen, but then there is murphy */ + panic(": unsupported product 0x%04x", PCI_PRODUCT(pa->pa_id)); + break; + } + + if (sc->sc_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) || + sc->sc_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN, NULL)) printf(": firmware unknown, "); else { @@ -141,7 +173,7 @@ mbg_attach(struct device *parent, struct device *self, void *aux) printf(": firmware %s, ", fw_id); } - if (mbg_read(sc, MBG_GET_TIME, (char *)&tframe, + if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, sizeof(struct mbg_time), NULL)) { printf("unknown status\n"); sc->sc_status = 0; @@ -162,7 +194,13 @@ mbg_attach(struct device *parent, struct device *self, void *aux) sc->sc_timedelta.status = SENSOR_S_UNKNOWN; sc->sc_timedelta.value = 0LL; sc->sc_timedelta.flags = 0; - strlcpy(sc->sc_timedelta.desc, "DCF77", sizeof(sc->sc_timedelta.desc)); +#ifdef PCIVERBOSE + pci_devinfo(pa->pa_id, pa->pa_class, 0, sc->sc_timedelta.desc, + sizeof(sc->sc_timedelta.desc)); +#else + strlcpy(sc->sc_timedelta.desc, "Radio clock", + sizeof(sc->sc_timedelta.desc)); +#endif sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta); sc->sc_signal.type = SENSOR_PERCENT; @@ -174,7 +212,6 @@ mbg_attach(struct device *parent, struct device *self, void *aux) sensor_attach(&sc->sc_sensordev, &sc->sc_signal); sensor_task_register(sc, mbg_task, 10); - sensordev_install(&sc->sc_sensordev); } @@ -188,10 +225,9 @@ mbg_task(void *arg) time_t trecv; int signal; - if (mbg_read(sc, MBG_GET_TIME, (char *)&tframe, sizeof(tframe), + if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, sizeof(tframe), &tstamp)) { - log(LOG_ERR, "%s: error reading time\n", - sc->sc_dev.dv_xname); + log(LOG_ERR, "%s: error reading time\n", sc->sc_dev.dv_xname); return; } if (tframe.status & MBG_INVALID) { @@ -235,8 +271,12 @@ mbg_task(void *arg) } } +/* + * send a command and read back results to an AMCC S5933 based card + * (i.e. the PCI32 DCF77 radio clock) + */ int -mbg_read(struct mbg_softc *sc, int cmd, char *buf, size_t len, +mbg_read_amcc_s5933(struct mbg_softc *sc, int cmd, char *buf, size_t len, struct timespec *tstamp) { long timer, tmax; @@ -281,3 +321,56 @@ mbg_read(struct mbg_softc *sc, int cmd, char *buf, size_t len, } return 0; } + +/* + * send a command and read back results to an ASIC based card + * (i.e. the PCI511 DCF77 radio clock) + */ +int +mbg_read_asic(struct mbg_softc *sc, int cmd, char *buf, size_t len, + struct timespec *tstamp) +{ + long timer, tmax; + size_t n; + u_int32_t data; + char *p = buf; + u_int16_t port; + u_int8_t status; + + /* write the command, optionally taking a timestamp */ + if (tstamp) + nanotime(tstamp); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd); + + /* wait for the BUSY flag to go low */ + timer = 0; + tmax = cold ? 50 : hz / 10; + do { + if (cold) + delay(20); + else + tsleep(tstamp, 0, "mbg", 1); + status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASIC_STATUS); + } while ((status & MBG_BUSY) && timer++ < tmax); + + if (status & MBG_BUSY) + return -1; + + /* read data from the device FIFO */ + port = ASIC_ADDON; + for (n = 0; n < len / 4; n++) { + data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port); + *(u_int32_t *)p = data; + p += sizeof(data); + port += sizeof(data); + } + + if (len % 4) { + data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port); + for (n = 0; n < len % 4; n++) { + *p++ = data & 0xff; + data >>= 8; + } + } + return 0; +} |