Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Aug 2015 20:08:09 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r286591 - in head: share/man/man4 sys/dev/uart
Message-ID:  <201508102008.t7AK89xT012339@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Mon Aug 10 20:08:09 2015
New Revision: 286591
URL: https://svnweb.freebsd.org/changeset/base/286591

Log:
  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.
  
  The historical UART_PPS_ON_CTS kernel option is still honored, but now it
  can be overridden at runtime using a tunable to configure all uart devices
  (hw.uart.pps_mode) or specific devices (dev.uart.#.pps_mode).  The per-
  device config is both a tunable and a writable sysctl.
  
  This syncs the PPS capabilities of uart(4) with the enhancements recently
  recently added to ucom(4) for capturing from USB serial devices.
  
  Relnotes:	yes

Modified:
  head/share/man/man4/uart.4
  head/sys/dev/uart/uart_bus.h
  head/sys/dev/uart/uart_core.c

Modified: head/share/man/man4/uart.4
==============================================================================
--- head/share/man/man4/uart.4	Mon Aug 10 19:41:31 2015	(r286590)
+++ head/share/man/man4/uart.4	Mon Aug 10 20:08:09 2015	(r286591)
@@ -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 s
 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?

Modified: head/sys/dev/uart/uart_bus.h
==============================================================================
--- head/sys/dev/uart/uart_bus.h	Mon Aug 10 19:41:31 2015	(r286590)
+++ head/sys/dev/uart/uart_bus.h	Mon Aug 10 20:08:09 2015	(r286591)
@@ -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
@@ -120,6 +112,7 @@ struct uart_softc {
 
 	/* Pulse capturing support (PPS). */
 	struct pps_state sc_pps;
+	int		 sc_pps_mode;
 
 	/* Upper layer data. */
 	void		*sc_softih;

Modified: head/sys/dev/uart/uart_core.c
==============================================================================
--- head/sys/dev/uart/uart_core.c	Mon Aug 10 19:41:31 2015	(r286590)
+++ head/sys/dev/uart/uart_core.c	Mon Aug 10 20:08:09 2015	(r286591)
@@ -70,6 +70,111 @@ static int uart_force_poll;
 SYSCTL_INT(_debug, OID_AUTO, uart_force_poll, CTLFLAG_RDTUN, &uart_force_poll,
     0, "Force UART polling");
 
+#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)
 {
@@ -211,14 +316,15 @@ 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);
 
 	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_event(&sc->sc_pps, (sig & pps_sig) ?
 			    PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
 		}
 	}
@@ -571,10 +677,7 @@ uart_bus_attach(device_t dev)
 	} else {
 		if ((error = uart_tty_attach(sc)) != 0)
 			goto fail;
-		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);
+		uart_pps_init(sc);
 	}
 
 	if (sc->sc_sysdev != NULL)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201508102008.t7AK89xT012339>