summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2015-08-23 17:07:23 +0000
committerian <ian@FreeBSD.org>2015-08-23 17:07:23 +0000
commitf1738f73c5c88085ceaa97f5fad5bf8510f0db50 (patch)
tree98b72b049e6d37963890a41ec707fade2ce20f48
parent50ce2fd7fcc4d5ce45d566f92ae3fb982d519ddb (diff)
downloadFreeBSD-src-f1738f73c5c88085ceaa97f5fad5bf8510f0db50.zip
FreeBSD-src-f1738f73c5c88085ceaa97f5fad5bf8510f0db50.tar.gz
MFC r286469, r286591, r286595, r286596, r286613:
Provide the tty-layer mutex when initializing the pps api. This allows time_pps_fetch() to be used in blocking mode. Allow the choice of PPS signal captured by uart(4) to be runtime-configured, eliminating the need to build a custom kernel to use the CTS signal. Correct the polarity of the PPS assert and clear events with respect to the electrical signals on the serial port. Document the change in polarity of the uart(4) PPS capture. Style fix -- do the braces for switches correctly. Relnotes: yes
-rw-r--r--UPDATING14
-rw-r--r--share/man/man4/uart.435
-rw-r--r--sys/dev/uart/uart_bus.h10
-rw-r--r--sys/dev/uart/uart_core.c133
-rw-r--r--sys/dev/uart/uart_tty.c10
5 files changed, 182 insertions, 20 deletions
diff --git a/UPDATING b/UPDATING
index 3263818..5f0b398 100644
--- a/UPDATING
+++ b/UPDATING
@@ -16,6 +16,20 @@ from older versions of FreeBSD, try WITHOUT_CLANG to bootstrap to the tip of
stable/10, and then rebuild without this option. The bootstrap process from
older version of current is a bit fragile.
+20150823:
+ The polarity of Pulse Per Second (PPS) capture events with the
+ uart(4) driver has been corrected. Prior to this change the PPS
+ "assert" event corresponded to the trailing edge of a positive PPS
+ pulse and the "clear" event was the leading edge of the next pulse.
+
+ As the width of a PPS pulse in a typical GPS receiver is on the
+ order of 1 millisecond, most users will not notice any significant
+ difference with this change.
+
+ Anyone who has compensated for the historical polarity reversal by
+ configuring a negative offset equal to the pulse width will need to
+ remove that workaround.
+
20150822:
From legacy ata(4) driver was removed support for SATA controllers
supported by more functional drivers ahci(4), siis(4) and mvs(4).
diff --git a/share/man/man4/uart.4 b/share/man/man4/uart.4
index 644c37d..d520409 100644
--- a/share/man/man4/uart.4
+++ b/share/man/man4/uart.4
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 12, 2008
+.Dd August 10, 2015
.Dt UART 4
.Os
.Sh NAME
@@ -151,6 +151,39 @@ SCC: serial communications controllers supported by the
device driver.
.El
.\"
+.Sh Pulse Per Second (PPS) Timing Interface
+The
+.Nm
+driver can capture PPS timing information as defined in RFC 2783.
+The API, accessed via
+.Xr ioctl 8 ,
+is available on the tty device.
+To use the PPS capture feature with
+.Xr ntpd 8 ,
+symlink the tty device to
+.Va /dev/pps0.
+.Pp
+The
+.Va hw.uart.pps_mode
+tunable configures the PPS capture mode for all uart devices;
+it can be set in
+.Xr loader.conf 5 .
+The
+.Va dev.uart.0.pps_mode
+sysctl configures the PPS capture mode for a specific uart device;
+it can be set in
+.Xr loader.conf 5
+or
+.Xr sysctl.conf 5 .
+The following capture modes are available:
+.Bl -tag -compact -offset "mmmm" -width "mmmm"
+.It 0
+Capture disabled.
+.It 1
+Capture pulses on the CTS line.
+.It 2
+Capture pulses on the DCD line (default).
+.El
.Sh FILES
.Bl -tag -width ".Pa /dev/ttyu?.init" -compact
.It Pa /dev/ttyu?
diff --git a/sys/dev/uart/uart_bus.h b/sys/dev/uart/uart_bus.h
index c455bb9..4a2ab91 100644
--- a/sys/dev/uart/uart_bus.h
+++ b/sys/dev/uart/uart_bus.h
@@ -48,14 +48,6 @@
#define UART_STAT_OVERRUN 0x0400
#define UART_STAT_PARERR 0x0800
-#ifdef UART_PPS_ON_CTS
-#define UART_SIG_DPPS SER_DCTS
-#define UART_SIG_PPS SER_CTS
-#else
-#define UART_SIG_DPPS SER_DDCD
-#define UART_SIG_PPS SER_DCD
-#endif
-
/* UART_IOCTL() requests */
#define UART_IOCTL_BREAK 1
#define UART_IOCTL_IFLOW 2
@@ -119,6 +111,7 @@ struct uart_softc {
/* Pulse capturing support (PPS). */
struct pps_state sc_pps;
+ int sc_pps_mode;
/* Upper layer data. */
void *sc_softih;
@@ -149,6 +142,7 @@ void uart_sched_softih(struct uart_softc *, uint32_t);
int uart_tty_attach(struct uart_softc *);
int uart_tty_detach(struct uart_softc *);
+struct mtx *uart_tty_getlock(struct uart_softc *);
void uart_tty_intr(void *arg);
/*
diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c
index 76b6a78..3da37e0 100644
--- a/sys/dev/uart/uart_core.c
+++ b/sys/dev/uart/uart_core.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/reboot.h>
+#include <sys/sysctl.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
@@ -64,6 +65,108 @@ static MALLOC_DEFINE(M_UART, "UART", "UART driver");
static int uart_poll_freq = UART_POLL_FREQ;
TUNABLE_INT("debug.uart_poll_freq", &uart_poll_freq);
+#define PPS_MODE_DISABLED 0
+#define PPS_MODE_CTS 1
+#define PPS_MODE_DCD 2
+
+static inline int
+uart_pps_signal(int pps_mode)
+{
+
+ switch(pps_mode) {
+ case PPS_MODE_CTS:
+ return (SER_CTS);
+ case PPS_MODE_DCD:
+ return (SER_DCD);
+ }
+ return (0);
+}
+static inline int
+uart_pps_mode_valid(int pps_mode)
+{
+
+ switch(pps_mode) {
+ case PPS_MODE_DISABLED:
+ case PPS_MODE_CTS:
+ case PPS_MODE_DCD:
+ return (true);
+ }
+ return (false);
+}
+
+static const char *
+uart_pps_mode_name(int pps_mode)
+{
+ switch(pps_mode) {
+ case PPS_MODE_DISABLED:
+ return ("disabled");
+ case PPS_MODE_CTS:
+ return ("CTS");
+ case PPS_MODE_DCD:
+ return ("DCD");
+ }
+ return ("invalid");
+}
+
+static int
+uart_pps_mode_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct uart_softc *sc;
+ int err, tmp;
+
+ sc = arg1;
+ tmp = sc->sc_pps_mode;
+ err = sysctl_handle_int(oidp, &tmp, 0, req);
+ if (err != 0 || req->newptr == NULL)
+ return (err);
+ if (!uart_pps_mode_valid(tmp))
+ return (EINVAL);
+ sc->sc_pps_mode = tmp;
+ return(0);
+}
+
+static void
+uart_pps_init(struct uart_softc *sc)
+{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree;
+
+ ctx = device_get_sysctl_ctx(sc->sc_dev);
+ tree = device_get_sysctl_tree(sc->sc_dev);
+
+ /*
+ * The historical default for pps capture mode is either DCD or CTS,
+ * depending on the UART_PPS_ON_CTS kernel option. Start with that,
+ * then try to fetch the tunable that overrides the mode for all uart
+ * devices, then try to fetch the sysctl-tunable that overrides the mode
+ * for one specific device.
+ */
+#ifdef UART_PPS_ON_CTS
+ sc->sc_pps_mode = PPS_MODE_CTS;
+#else
+ sc->sc_pps_mode = PPS_MODE_DCD;
+#endif
+ TUNABLE_INT_FETCH("hw.uart.pps_mode", &sc->sc_pps_mode);
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "pps_mode",
+ CTLTYPE_INT | CTLFLAG_RWTUN, sc, 0, uart_pps_mode_sysctl, "I",
+ "pulse capturing mode - 0/1/2 - disabled/CTS/DCD");
+
+ if (!uart_pps_mode_valid(sc->sc_pps_mode)) {
+ device_printf(sc->sc_dev,
+ "Invalid pps_mode %d configured; disabling PPS capture\n",
+ sc->sc_pps_mode);
+ sc->sc_pps_mode = PPS_MODE_DISABLED;
+ } else if (bootverbose) {
+ device_printf(sc->sc_dev, "PPS capture mode %d (%s)\n",
+ sc->sc_pps_mode, uart_pps_mode_name(sc->sc_pps_mode));
+ }
+
+ sc->sc_pps.ppscap = PPS_CAPTUREBOTH;
+ sc->sc_pps.driver_mtx = uart_tty_getlock(sc);
+ sc->sc_pps.driver_abi = PPS_ABI_VERSION;
+ pps_init_abi(&sc->sc_pps);
+}
+
void
uart_add_sysdev(struct uart_devinfo *di)
{
@@ -199,15 +302,22 @@ static __inline int
uart_intr_sigchg(void *arg)
{
struct uart_softc *sc = arg;
- int new, old, sig;
+ int new, old, pps_sig, sig;
sig = UART_GETSIG(sc);
+ /*
+ * Time pulse counting support. Note that both CTS and DCD are
+ * active-low signals. The status bit is high to indicate that
+ * the signal on the line is low, which corresponds to a PPS
+ * clear event.
+ */
if (sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) {
- if (sig & UART_SIG_DPPS) {
+ pps_sig = uart_pps_signal(sc->sc_pps_mode);
+ if (sig & SER_DELTA(pps_sig)) {
pps_capture(&sc->sc_pps);
- pps_event(&sc->sc_pps, (sig & UART_SIG_PPS) ?
- PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
+ pps_event(&sc->sc_pps, (sig & pps_sig) ?
+ PPS_CAPTURECLEAR : PPS_CAPTUREASSERT);
}
}
@@ -499,9 +609,6 @@ uart_bus_attach(device_t dev)
sc->sc_sysdev->stopbits);
}
- sc->sc_pps.ppscap = PPS_CAPTUREBOTH;
- pps_init(&sc->sc_pps);
-
sc->sc_leaving = 0;
sc->sc_testintr = 1;
filt = uart_intr(sc);
@@ -554,10 +661,14 @@ uart_bus_attach(device_t dev)
printf("\n");
}
- error = (sc->sc_sysdev != NULL && sc->sc_sysdev->attach != NULL)
- ? (*sc->sc_sysdev->attach)(sc) : uart_tty_attach(sc);
- if (error)
- goto fail;
+ if (sc->sc_sysdev != NULL && sc->sc_sysdev->attach != NULL) {
+ if ((error = sc->sc_sysdev->attach(sc)) != 0)
+ goto fail;
+ } else {
+ if ((error = uart_tty_attach(sc)) != 0)
+ goto fail;
+ uart_pps_init(sc);
+ }
if (sc->sc_sysdev != NULL)
sc->sc_sysdev->hwmtx = sc->sc_hwmtx;
diff --git a/sys/dev/uart/uart_tty.c b/sys/dev/uart/uart_tty.c
index 56f879b..e676d50 100644
--- a/sys/dev/uart/uart_tty.c
+++ b/sys/dev/uart/uart_tty.c
@@ -410,3 +410,13 @@ uart_tty_detach(struct uart_softc *sc)
return (0);
}
+
+struct mtx *
+uart_tty_getlock(struct uart_softc *sc)
+{
+
+ if (sc->sc_u.u_tty.tp != NULL)
+ return (tty_getlock(sc->sc_u.u_tty.tp));
+ else
+ return (NULL);
+}
OpenPOWER on IntegriCloud