summaryrefslogtreecommitdiffstats
path: root/sys/dev/uart
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/uart')
-rw-r--r--sys/dev/uart/uart_bus.h10
-rw-r--r--sys/dev/uart/uart_bus_pci.c2
-rw-r--r--sys/dev/uart/uart_core.c145
-rw-r--r--sys/dev/uart/uart_cpu_fdt.c28
-rw-r--r--sys/dev/uart/uart_tty.c10
5 files changed, 159 insertions, 36 deletions
diff --git a/sys/dev/uart/uart_bus.h b/sys/dev/uart/uart_bus.h
index e78d769..11d599e67 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
@@ -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;
@@ -150,6 +143,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_bus_pci.c b/sys/dev/uart/uart_bus_pci.c
index 7bcac95..48954a5 100644
--- a/sys/dev/uart/uart_bus_pci.c
+++ b/sys/dev/uart/uart_bus_pci.c
@@ -115,6 +115,8 @@ static const struct pci_id pci_ns8250_ids[] = {
0x10, 16384000 },
{ 0x1415, 0xc120, 0xffff, 0, "Oxford Semiconductor OXPCIe952 PCIe 16950 UART",
0x10 },
+{ 0x14e4, 0x160a, 0xffff, 0, "Broadcom TruManage UART", 0x10,
+ 128 * DEFAULT_RCLK, 2},
{ 0x14e4, 0x4344, 0xffff, 0, "Sony Ericsson GC89 PC Card", 0x10},
{ 0x151f, 0x0000, 0xffff, 0, "TOPIC Semiconductor TP560 56k modem", 0x10 },
{ 0x1fd4, 0x1999, 0x1fd4, 0x0001, "Sunix SER5xxxx Serial Port", 0x10,
diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c
index 191244a..96b4529 100644
--- a/sys/dev/uart/uart_core.c
+++ b/sys/dev/uart/uart_core.c
@@ -70,6 +70,108 @@ 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,15 +313,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);
}
}
@@ -365,14 +474,13 @@ uart_bus_probe(device_t dev, int regshft, int rclk, int rid, int chan)
*/
sc->sc_rrid = rid;
sc->sc_rtype = SYS_RES_IOPORT;
- sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
- 0, ~0, uart_getrange(sc->sc_class), RF_ACTIVE);
+ sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
+ RF_ACTIVE);
if (sc->sc_rres == NULL) {
sc->sc_rrid = rid;
sc->sc_rtype = SYS_RES_MEMORY;
- sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype,
- &sc->sc_rrid, 0, ~0, uart_getrange(sc->sc_class),
- RF_ACTIVE);
+ sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype,
+ &sc->sc_rrid, RF_ACTIVE);
if (sc->sc_rres == NULL)
return (ENXIO);
}
@@ -447,8 +555,8 @@ uart_bus_attach(device_t dev)
* Re-allocate. We expect that the softc contains the information
* collected by uart_bus_probe() intact.
*/
- sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
- 0, ~0, uart_getrange(sc->sc_class), RF_ACTIVE);
+ sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
+ RF_ACTIVE);
if (sc->sc_rres == NULL) {
mtx_destroy(&sc->sc_hwmtx_s);
return (ENXIO);
@@ -511,9 +619,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);
@@ -568,10 +673,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_cpu_fdt.c b/sys/dev/uart/uart_cpu_fdt.c
index 344aad5..c70b4ca 100644
--- a/sys/dev/uart/uart_cpu_fdt.c
+++ b/sys/dev/uart/uart_cpu_fdt.c
@@ -134,6 +134,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
phandle_t node, chosen;
pcell_t shift, br, rclk;
u_long start, size, pbase, psize;
+ char *cp;
int err;
uart_bus_space_mem = fdtbus_bs_tag;
@@ -148,18 +149,25 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
if (devtype != UART_DEV_CONSOLE)
return (ENXIO);
- /*
- * Retrieve /chosen/std{in,out}.
- */
- node = -1;
- if ((chosen = OF_finddevice("/chosen")) != -1) {
- for (name = propnames; *name != NULL; name++) {
- if (phandle_chosen_propdev(chosen, *name, &node) == 0)
- break;
+ /* Has the user forced a specific device node? */
+ cp = kern_getenv("hw.fdt.console");
+ if (cp == NULL) {
+ /*
+ * Retrieve /chosen/std{in,out}.
+ */
+ node = -1;
+ if ((chosen = OF_finddevice("/chosen")) != -1) {
+ for (name = propnames; *name != NULL; name++) {
+ if (phandle_chosen_propdev(chosen, *name,
+ &node) == 0)
+ break;
+ }
}
+ if (chosen == -1 || *name == NULL)
+ node = OF_finddevice("serial0"); /* Last ditch */
+ } else {
+ node = OF_finddevice(cp);
}
- if (chosen == -1 || *name == NULL)
- node = OF_finddevice("serial0"); /* Last ditch */
if (node == -1) /* Can't find anything */
return (ENXIO);
diff --git a/sys/dev/uart/uart_tty.c b/sys/dev/uart/uart_tty.c
index c31b542..ada4927 100644
--- a/sys/dev/uart/uart_tty.c
+++ b/sys/dev/uart/uart_tty.c
@@ -404,3 +404,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