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
This commit is contained in:
parent
9138b6e04a
commit
196d3019a8
@ -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?
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user