diff options
Diffstat (limited to 'sys/dev/uart')
-rw-r--r-- | sys/dev/uart/uart_bus.h | 10 | ||||
-rw-r--r-- | sys/dev/uart/uart_bus_pci.c | 2 | ||||
-rw-r--r-- | sys/dev/uart/uart_core.c | 145 | ||||
-rw-r--r-- | sys/dev/uart/uart_cpu_fdt.c | 28 | ||||
-rw-r--r-- | sys/dev/uart/uart_tty.c | 10 |
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); +} |