summaryrefslogtreecommitdiffstats
path: root/sys/dev/uart
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2003-09-06 23:13:47 +0000
committermarcel <marcel@FreeBSD.org>2003-09-06 23:13:47 +0000
commit6efc7b093dec3e8eb3e8318116ca5338ed95ba31 (patch)
tree51fa06a66d34e172ca272cc08f5768214c3f81ef /sys/dev/uart
parentde27193cae74efc68618f3709bde0e09ae6db4df (diff)
downloadFreeBSD-src-6efc7b093dec3e8eb3e8318116ca5338ed95ba31.zip
FreeBSD-src-6efc7b093dec3e8eb3e8318116ca5338ed95ba31.tar.gz
The uart(4) driver is an universal driver for various UART hardware.
It improves on sio(4) in the following areas: o Fully newbusified to allow for memory mapped I/O. This is a must for ia64 and sparc64, o Machine dependent code to take full advantage of machine and firm- ware specific ways to define serial consoles and/or debug ports. o Hardware abstraction layer to allow the driver to be used with various UARTs, such as the well-known ns8250 family of UARTs, the Siemens sab82532 or the Zilog Z8530. This is especially important for pc98 and sparc64 where it's common to have different UARTs, o The notion of system devices to unkludge low-level consoles and remote gdb ports and provides the mechanics necessary to support the keyboard on sparc64 (which is UART based). o The notion of a kernel interface so that a UART can be tied to something other than the well-known TTY interface. This is needed on sparc64 to present the user with a device and ioctl handling suitable for a keyboard, but also allows us to cleanly hide an UART when used as a debug port. Following is a list of features and bugs/flaws specific to the ns8250 family of UARTs as compared to their support in sio(4): o The uart(4) driver determines the FIFO size and automaticly takes advantages of larger FIFOs and/or additional features. Note that since I don't have sufficient access to 16[679]5x UARTs, hardware flow control has not been enabled. This is almost trivial to do, provided one can test. The downside of this is that broken UARTs are more likely to not work correctly with uart(4). The need for tunables or knobs may be large enough to warrant their creation. o The uart(4) driver does not share the same bumpy history as sio(4) and will therefore not provide the necessary hooks, tweaks, quirks or work-arounds to deal with once common hardware. To that extend, uart(4) supports a subset of the UARTs that sio(4) supports. The question before us is whether the subset is sufficient for current hardware. o There is no support for multiport UARTs in uart(4). The decision behind this is that uart(4) deals with one EIA RS232-C interface. Packaging of multiple interfaces in a single chip or on a single expansion board is beyond the scope of uart(4) and is now mostly left for puc(4) to deal with. Lack of hardware made it impossible to actually implement such a dependency other than is present for the dual channel SAB82532 and Z8350 SCCs. The current list of missing features is: o No configuration capabilities. A set of tunables and sysctls is being worked out. There are likely not going to be any or much compile-time knobs. Such configuration does not fit well with current hardware. o No support for the PPS API. This is partly dependent on the ability to configure uart(4) and partly dependent on having sufficient information to implement it properly. As usual, the manpage is present but lacks the attention the software has gotten.
Diffstat (limited to 'sys/dev/uart')
-rw-r--r--sys/dev/uart/uart.h82
-rw-r--r--sys/dev/uart/uart_bus.h204
-rw-r--r--sys/dev/uart/uart_bus_acpi.c83
-rw-r--r--sys/dev/uart/uart_bus_ebus.c85
-rw-r--r--sys/dev/uart/uart_bus_isa.c167
-rw-r--r--sys/dev/uart/uart_bus_pci.c118
-rw-r--r--sys/dev/uart/uart_bus_puc.c94
-rw-r--r--sys/dev/uart/uart_core.c452
-rw-r--r--sys/dev/uart/uart_cpu.h115
-rw-r--r--sys/dev/uart/uart_cpu_alpha.c111
-rw-r--r--sys/dev/uart/uart_cpu_amd64.c92
-rw-r--r--sys/dev/uart/uart_cpu_i386.c92
-rw-r--r--sys/dev/uart/uart_cpu_ia64.c139
-rw-r--r--sys/dev/uart/uart_cpu_sparc64.c156
-rw-r--r--sys/dev/uart/uart_dev_ns8250.c726
-rw-r--r--sys/dev/uart/uart_dev_ns8250.h153
-rw-r--r--sys/dev/uart/uart_dev_sab82532.c670
-rw-r--r--sys/dev/uart/uart_dev_sab82532.h320
-rw-r--r--sys/dev/uart/uart_dev_z8530.c512
-rw-r--r--sys/dev/uart/uart_dev_z8530.h252
-rw-r--r--sys/dev/uart/uart_if.m138
-rw-r--r--sys/dev/uart/uart_tty.c569
22 files changed, 5330 insertions, 0 deletions
diff --git a/sys/dev/uart/uart.h b/sys/dev/uart/uart.h
new file mode 100644
index 0000000..1ea90c0
--- /dev/null
+++ b/sys/dev/uart/uart.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_UART_H_
+#define _DEV_UART_H_
+
+/*
+ * Bus access structure. This structure holds the minimum information needed
+ * to access the UART. The rclk field, although not important to actually
+ * access the UART, is important for baudrate programming, delay loops and
+ * other timing related computations.
+ */
+struct uart_bas {
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ u_int regshft;
+ u_int rclk;
+};
+
+#define uart_regofs(bas, reg) ((reg) << (bas)->regshft)
+
+#define uart_getreg(bas, reg) \
+ bus_space_read_1((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
+#define uart_setreg(bas, reg, value) \
+ bus_space_write_1((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
+
+/* 16-bit I/O (e.g. to divisor latch) */
+#define uart_getdreg(bas, reg) \
+ bus_space_read_2((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
+#define uart_setdreg(bas, reg, value) \
+ bus_space_write_2((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
+
+/*
+ * XXX we don't know the length of the bus space address range in use by
+ * the UART. Since barriers don't use the length field currently, we put
+ * a zero there for now.
+ */
+#define uart_barrier(bas) \
+ bus_space_barrier((bas)->bst, (bas)->bsh, 0, 0, \
+ BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
+
+/*
+ * Device flags.
+ */
+#define UART_FLAGS_CONSOLE(f) ((f) & 0x10)
+#define UART_FLAGS_DBGPORT(f) ((f) & 0x80)
+
+/*
+ * Data parity values (magical numbers related to ns8250).
+ */
+#define UART_PARITY_NONE 0
+#define UART_PARITY_ODD 1
+#define UART_PARITY_EVEN 3
+#define UART_PARITY_MARK 5
+#define UART_PARITY_SPACE 7
+
+#endif /* _DEV_UART_H_ */
diff --git a/sys/dev/uart/uart_bus.h b/sys/dev/uart/uart_bus.h
new file mode 100644
index 0000000..71aa1be
--- /dev/null
+++ b/sys/dev/uart/uart_bus.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_UART_BUS_H_
+#define _DEV_UART_BUS_H_
+
+/* Drain and flush targets. */
+#define UART_DRAIN_RECEIVER 0x0001
+#define UART_DRAIN_TRANSMITTER 0x0002
+#define UART_FLUSH_RECEIVER UART_DRAIN_RECEIVER
+#define UART_FLUSH_TRANSMITTER UART_DRAIN_TRANSMITTER
+
+/*
+ * Interrupt sources (in priority order). See also uart_core.c
+ * Note that the low order 16 bits are used to pass modem signals
+ * from the hardware interrupt handler to the software interrupt
+ * handler. See UART_SIG_* and UART_SIGMASK_* below.
+ */
+#define UART_IPEND_OVERRUN 0x010000
+#define UART_IPEND_BREAK 0x020000
+#define UART_IPEND_RXREADY 0x040000
+#define UART_IPEND_SIGCHG 0x080000
+#define UART_IPEND_TXIDLE 0x100000
+
+#define UART_IPEND_MASK 0x1f0000
+#define UART_IPEND_SIGMASK 0x00ffff
+
+/* Received character status bits. */
+#define UART_STAT_BREAK 0x0100
+#define UART_STAT_FRAMERR 0x0200
+#define UART_STAT_OVERRUN 0x0400
+#define UART_STAT_PARERR 0x0800
+
+/* Modem and line signals. */
+#define UART_SIG_DTR 0x0001
+#define UART_SIG_RTS 0x0002
+#define UART_SIG_DSR 0x0004
+#define UART_SIG_CTS 0x0008
+#define UART_SIG_DCD 0x0010
+#define UART_SIG_RI 0x0020
+#define UART_SIG_DDTR 0x0100
+#define UART_SIG_DRTS 0x0200
+#define UART_SIG_DDSR 0x0400
+#define UART_SIG_DCTS 0x0800
+#define UART_SIG_DDCD 0x1000
+#define UART_SIG_DRI 0x2000
+
+#define UART_SIGMASK_DTE 0x0003
+#define UART_SIGMASK_DCE 0x003c
+#define UART_SIGMASK_STATE 0x003f
+#define UART_SIGMASK_DELTA 0x3f00
+
+/* UART_IOCTL() requests */
+#define UART_IOCTL_BREAK 1
+#define UART_IOCTL_IFLOW 2
+#define UART_IOCTL_OFLOW 3
+
+/*
+ * UART class & instance (=softc)
+ */
+struct uart_class {
+ KOBJ_CLASS_FIELDS;
+ u_int uc_range; /* Bus space address range. */
+ u_int uc_rclk; /* Default rclk for this device. */
+};
+
+extern struct uart_class uart_ns8250_class;
+extern struct uart_class uart_sab82532_class;
+extern struct uart_class uart_z8530_class;
+
+struct uart_softc {
+ KOBJ_FIELDS;
+ struct uart_class *sc_class;
+ struct uart_bas sc_bas;
+ device_t sc_dev;
+
+ struct resource *sc_rres; /* Register resource. */
+ int sc_rrid;
+ int sc_rtype; /* SYS_RES_{IOPORT|MEMORY}. */
+ struct resource *sc_ires; /* Interrupt resource. */
+ void *sc_icookie;
+ int sc_irid;
+
+ int sc_callout:1; /* This UART is opened for callout. */
+ int sc_fastintr:1; /* This UART uses fast interrupts. */
+ int sc_hasfifo:1; /* This UART has FIFOs. */
+ int sc_hwiflow:1; /* This UART has HW input flow ctl. */
+ int sc_hwoflow:1; /* This UART has HW output flow ctl. */
+ int sc_leaving:1; /* This UART is going away. */
+ int sc_opened:1; /* This UART is open for business. */
+ int sc_polled:1; /* This UART has no interrupts. */
+ int sc_txbusy:1; /* This UART is transmitting. */
+
+ struct uart_devinfo *sc_sysdev; /* System device (or NULL). */
+
+ int sc_altbrk; /* State for alt break sequence. */
+ uint32_t sc_hwsig; /* Signal state. Used by HW driver. */
+
+ /* Receiver data. */
+ uint16_t *sc_rxbuf;
+ int sc_rxbufsz;
+ int sc_rxput;
+ int sc_rxget;
+ int sc_rxfifosz; /* Size of RX FIFO. */
+
+ /* Transmitter data. */
+ uint8_t *sc_txbuf;
+ int sc_txdatasz;
+ int sc_txfifosz; /* Size of TX FIFO and buffer. */
+
+ /* Upper layer data. */
+ void *sc_softih;
+ uint32_t sc_ttypend;
+ union {
+ /* TTY specific data. */
+ struct {
+ dev_t si[2]; /* We have 2 device special files. */
+ struct tty *tp;
+ } u_tty;
+ /* Keyboard specific data. */
+ struct {
+ } u_kbd;
+ } sc_u;
+};
+
+extern devclass_t uart_devclass;
+extern char uart_driver_name[];
+
+int uart_bus_attach(device_t dev);
+int uart_bus_detach(device_t dev);
+int uart_bus_probe(device_t dev, int regshft, int rclk, int rid);
+
+int uart_tty_attach(struct uart_softc *);
+int uart_tty_detach(struct uart_softc *);
+void uart_tty_intr(void *arg);
+
+/*
+ * Receive buffer operations.
+ */
+static __inline int
+uart_rx_empty(struct uart_softc *sc)
+{
+ return ((sc->sc_rxget == sc->sc_rxput) ? 1 : 0);
+}
+
+static __inline int
+uart_rx_full(struct uart_softc *sc)
+{
+ return ((sc->sc_rxput + 1 < sc->sc_rxbufsz)
+ ? (sc->sc_rxput + 1 == sc->sc_rxget) : (sc->sc_rxget == 0));
+}
+
+static __inline int
+uart_rx_get(struct uart_softc *sc)
+{
+ int ptr, xc;
+
+ ptr = sc->sc_rxget;
+ if (ptr == sc->sc_rxput)
+ return (-1);
+ xc = sc->sc_rxbuf[ptr++];
+ sc->sc_rxget = (ptr < sc->sc_rxbufsz) ? ptr : 0;
+ return (xc);
+}
+
+static __inline int
+uart_rx_put(struct uart_softc *sc, int xc)
+{
+ int ptr;
+
+ ptr = (sc->sc_rxput + 1 < sc->sc_rxbufsz) ? sc->sc_rxput + 1 : 0;
+ if (ptr == sc->sc_rxget)
+ return (ENOSPC);
+ sc->sc_rxbuf[sc->sc_rxput] = xc;
+ sc->sc_rxput = ptr;
+ return (0);
+}
+
+#endif /* _DEV_UART_BUS_H_ */
diff --git a/sys/dev/uart/uart_bus_acpi.c b/sys/dev/uart/uart_bus_acpi.c
new file mode 100644
index 0000000..ac75f0c
--- /dev/null
+++ b/sys/dev/uart/uart_bus_acpi.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2001 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <isa/isavar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+
+static int uart_acpi_probe(device_t dev);
+
+static device_method_t uart_acpi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_acpi_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_acpi_driver = {
+ uart_driver_name,
+ uart_acpi_methods,
+ sizeof(struct uart_softc),
+};
+
+static struct isa_pnp_id acpi_ns8250_ids[] = {
+ {0x0005d041, "Standard PC COM port"}, /* PNP0500 */
+ {0x0105d041, "16550A-compatible COM port"}, /* PNP0501 */
+ {0}
+};
+
+static int
+uart_acpi_probe(device_t dev)
+{
+ struct uart_softc *sc;
+ device_t parent;
+
+ parent = device_get_parent(dev);
+ sc = device_get_softc(dev);
+
+ if (!ISA_PNP_PROBE(parent, dev, acpi_ns8250_ids)) {
+ sc->sc_class = &uart_ns8250_class;
+ return (uart_bus_probe(dev, 0, 0, 0));
+ }
+
+ /* Add checks for non-ns8250 IDs here. */
+ return (ENXIO);
+}
+
+DRIVER_MODULE(uart, acpi, uart_acpi_driver, uart_devclass, 0, 0);
diff --git a/sys/dev/uart/uart_bus_ebus.c b/sys/dev/uart/uart_bus_ebus.c
new file mode 100644
index 0000000..0eab11f
--- /dev/null
+++ b/sys/dev/uart/uart_bus_ebus.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/ofw/openfirm.h>
+#include <sparc64/ebus/ebusvar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+static int uart_ebus_probe(device_t dev);
+
+static device_method_t uart_ebus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_ebus_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_ebus_driver = {
+ uart_driver_name,
+ uart_ebus_methods,
+ sizeof(struct uart_softc),
+};
+
+static int
+uart_ebus_probe(device_t dev)
+{
+ const char *nm;
+ struct uart_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ sc->sc_class = NULL;
+
+ nm = ebus_get_name(dev);
+ if (!strcmp(nm, "su")) {
+ sc->sc_class = &uart_ns8250_class;
+ return (uart_bus_probe(dev, 0, 0, 0));
+ }
+ if (!strcmp(nm, "se")) {
+ sc->sc_class = &uart_sab82532_class;
+ error = uart_bus_probe(dev, 0, 0, 0);
+ return ((error) ? error : -1);
+ }
+
+ return (ENXIO);
+}
+
+DRIVER_MODULE(uart, ebus, uart_ebus_driver, uart_devclass, 0, 0);
diff --git a/sys/dev/uart/uart_bus_isa.c b/sys/dev/uart/uart_bus_isa.c
new file mode 100644
index 0000000..784d7f9
--- /dev/null
+++ b/sys/dev/uart/uart_bus_isa.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2001 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <isa/isavar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+
+static int uart_isa_probe(device_t dev);
+
+static device_method_t uart_isa_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_isa_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_isa_driver = {
+ uart_driver_name,
+ uart_isa_methods,
+ sizeof(struct uart_softc),
+};
+
+static struct isa_pnp_id isa_ns8250_ids[] = {
+ {0x0005d041, "Standard PC COM port"}, /* PNP0500 */
+ {0x0105d041, "16550A-compatible COM port"}, /* PNP0501 */
+ {0x0205d041, "Multiport serial device (non-intelligent 16550)"}, /* PNP0502 */
+ {0x1005d041, "Generic IRDA-compatible device"}, /* PNP0510 */
+ {0x1105d041, "Generic IRDA-compatible device"}, /* PNP0511 */
+ /* Devices that do not have a compatid */
+ {0x12206804, NULL}, /* ACH2012 - 5634BTS 56K Video Ready Modem */
+ {0x7602a904, NULL}, /* AEI0276 - 56K v.90 Fax Modem (LKT) */
+ {0x00007905, NULL}, /* AKY0000 - 56K Plug&Play Modem */
+ {0x21107905, NULL}, /* AKY1021 - 56K Plug&Play Modem */
+ {0x01405407, NULL}, /* AZT4001 - AZT3000 PnP SOUND DEVICE, MODEM */
+ {0x56039008, NULL}, /* BDP0356 - Best Data 56x2 */
+ {0x56159008, NULL}, /* BDP1556 - B.D. Smart One 56SPS,Voice Modem*/
+ {0x36339008, NULL}, /* BDP3336 - Best Data Prods. 336F */
+ {0x0014490a, NULL}, /* BRI1400 - Boca 33.6 PnP */
+ {0x0015490a, NULL}, /* BRI1500 - Internal Fax Data */
+ {0x0034490a, NULL}, /* BRI3400 - Internal ACF Modem */
+ {0x0094490a, NULL}, /* BRI9400 - Boca K56Flex PnP */
+ {0x00b4490a, NULL}, /* BRIB400 - Boca 56k PnP */
+ {0x0030320d, NULL}, /* CIR3000 - Cirrus Logic V43 */
+ {0x0100440e, NULL}, /* CRD0001 - Cardinal MVP288IV ? */
+ {0x01308c0e, NULL}, /* CTL3001 - Creative Labs Phoneblaster */
+ {0x36033610, NULL}, /* DAV0336 - DAVICOM 336PNP MODEM */
+ {0x01009416, NULL}, /* ETT0001 - E-Tech Bullet 33k6 PnP */
+ {0x0000aa1a, NULL}, /* FUJ0000 - FUJITSU Modem 33600 PNP/I2 */
+ {0x1200c31e, NULL}, /* GVC0012 - VF1128HV-R9 (win modem?) */
+ {0x0303c31e, NULL}, /* GVC0303 - MaxTech 33.6 PnP D/F/V */
+ {0x0505c31e, NULL}, /* GVC0505 - GVC 56k Faxmodem */
+ {0x0116c31e, NULL}, /* GVC1601 - Rockwell V.34 Plug & Play Modem */
+ {0x0050c31e, NULL}, /* GVC5000 - some GVC modem */
+ {0x3800f91e, NULL}, /* GWY0038 - Telepath with v.90 */
+ {0x9062f91e, NULL}, /* GWY6290 - Telepath with x2 Technology */
+ {0x8100e425, NULL}, /* IOD0081 - I-O DATA DEVICE,INC. IFML-560 */
+ {0x71004d24, NULL}, /* IBM0071 - IBM ThinkPad 240 IrDA controller*/
+ {0x21002534, NULL}, /* MAE0021 - Jetstream Int V.90 56k Voice Series 2*/
+ {0x0000f435, NULL}, /* MOT0000 - Motorola ModemSURFR 33.6 Intern */
+ {0x5015f435, NULL}, /* MOT1550 - Motorola ModemSURFR 56K Modem */
+ {0xf015f435, NULL}, /* MOT15F0 - Motorola VoiceSURFR 56K Modem */
+ {0x6045f435, NULL}, /* MOT4560 - Motorola ? */
+ {0x61e7a338, NULL}, /* NECE761 - 33.6Modem */
+ {0x0160633a, NULL}, /* NSC6001 - National Semi's IrDA Controller*/
+ {0x08804f3f, NULL}, /* OZO8008 - Zoom (33.6k Modem) */
+ {0x0f804f3f, NULL}, /* OZO800f - Zoom 2812 (56k Modem) */
+ {0x39804f3f, NULL}, /* OZO8039 - Zoom 56k flex */
+ {0x00914f3f, NULL}, /* OZO9100 - Zoom 2919 (K56 Faxmodem) */
+ {0x3024a341, NULL}, /* PMC2430 - Pace 56 Voice Internal Modem */
+ {0x1000eb49, NULL}, /* ROK0010 - Rockwell ? */
+ {0x1200b23d, NULL}, /* RSS0012 - OMRON ME5614ISA */
+ {0x5002734a, NULL}, /* RSS0250 - 5614Jx3(G) Internal Modem */
+ {0x6202734a, NULL}, /* RSS0262 - 5614Jx3[G] V90+K56Flex Modem */
+ {0x1010104d, NULL}, /* SHP1010 - Rockwell 33600bps Modem */
+ {0x10f0a34d, NULL}, /* SMCF010 - SMC IrCC*/
+ {0xc100ad4d, NULL}, /* SMM00C1 - Leopard 56k PnP */
+ {0x9012b04e, NULL}, /* SUP1290 - Supra ? */
+ {0x1013b04e, NULL}, /* SUP1310 - SupraExpress 336i PnP */
+ {0x8013b04e, NULL}, /* SUP1380 - SupraExpress 288i PnP Voice */
+ {0x8113b04e, NULL}, /* SUP1381 - SupraExpress 336i PnP Voice */
+ {0x5016b04e, NULL}, /* SUP1650 - Supra 336i Sp Intl */
+ {0x7016b04e, NULL}, /* SUP1670 - Supra 336i V+ Intl */
+ {0x7420b04e, NULL}, /* SUP2070 - Supra ? */
+ {0x8020b04e, NULL}, /* SUP2080 - Supra ? */
+ {0x8420b04e, NULL}, /* SUP2084 - SupraExpress 56i PnP */
+ {0x7121b04e, NULL}, /* SUP2171 - SupraExpress 56i Sp? */
+ {0x8024b04e, NULL}, /* SUP2480 - Supra ? */
+ {0x01007256, NULL}, /* USR0001 - U.S. Robotics Inc., Sportster W */
+ {0x02007256, NULL}, /* USR0002 - U.S. Robotics Inc. Sportster 33. */
+ {0x04007256, NULL}, /* USR0004 - USR Sportster 14.4k */
+ {0x06007256, NULL}, /* USR0006 - USR Sportster 33.6k */
+ {0x11007256, NULL}, /* USR0011 - USR ? */
+ {0x01017256, NULL}, /* USR0101 - USR ? */
+ {0x30207256, NULL}, /* USR2030 - U.S.Robotics Inc. Sportster 560 */
+ {0x50207256, NULL}, /* USR2050 - U.S.Robotics Inc. Sportster 33. */
+ {0x70207256, NULL}, /* USR2070 - U.S.Robotics Inc. Sportster 560 */
+ {0x30307256, NULL}, /* USR3030 - U.S. Robotics 56K FAX INT */
+ {0x31307256, NULL}, /* USR3031 - U.S. Robotics 56K FAX INT */
+ {0x50307256, NULL}, /* USR3050 - U.S. Robotics 56K FAX INT */
+ {0x70307256, NULL}, /* USR3070 - U.S. Robotics 56K Voice INT */
+ {0x90307256, NULL}, /* USR3090 - USR ? */
+ {0x70917256, NULL}, /* USR9170 - U.S. Robotics 56K FAX INT */
+ {0x90917256, NULL}, /* USR9190 - USR 56k Voice INT */
+ {0x04f0235c, NULL}, /* WACF004 - Wacom Tablet PC Screen*/
+ {0x0300695c, NULL}, /* WCI0003 - Fax/Voice/Modem/Speakphone/Asvd */
+ {0x01a0896a, NULL}, /* ZTIA001 - Zoom Internal V90 Faxmodem */
+ {0x61f7896a, NULL}, /* ZTIF761 - Zoom ComStar 33.6 */
+ {0}
+};
+
+static int
+uart_isa_probe(device_t dev)
+{
+ struct uart_softc *sc;
+ device_t parent;
+
+ parent = device_get_parent(dev);
+ sc = device_get_softc(dev);
+
+ if (!ISA_PNP_PROBE(parent, dev, isa_ns8250_ids)) {
+ sc->sc_class = &uart_ns8250_class;
+ return (uart_bus_probe(dev, 0, 0, 0));
+ }
+
+ /* Add checks for non-ns8250 IDs here. */
+
+ sc->sc_class = &uart_ns8250_class;
+ return (uart_bus_probe(dev, 0, 0, 0));
+}
+
+DRIVER_MODULE(uart, isa, uart_isa_driver, uart_devclass, 0, 0);
diff --git a/sys/dev/uart/uart_bus_pci.c b/sys/dev/uart/uart_bus_pci.c
new file mode 100644
index 0000000..3555e5f
--- /dev/null
+++ b/sys/dev/uart/uart_bus_pci.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2001 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+
+static int uart_pci_probe(device_t dev);
+
+static device_method_t uart_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_pci_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_pci_driver = {
+ uart_driver_name,
+ uart_pci_methods,
+ sizeof(struct uart_softc),
+};
+
+struct pci_id {
+ uint32_t type;
+ const char *desc;
+ int rid;
+};
+
+static struct pci_id pci_ns8250_ids[] = {
+ { 0x100812b9, "3COM PCI FaxModem", 0x10 },
+ { 0x2000131f, "CyberSerial (1-port) 16550", 0x10 },
+ { 0x01101407, "Koutech IOFLEX-2S PCI Dual Port Serial", 0x10 },
+ { 0x01111407, "Koutech IOFLEX-2S PCI Dual Port Serial", 0x10 },
+ { 0x048011c1, "Lucent kermit based PCI Modem", 0x14 },
+ { 0x95211415, "Oxford Semiconductor PCI Dual Port Serial", 0x10 },
+ { 0x7101135e, "SeaLevel Ultra 530.PCI Single Port Serial", 0x18 },
+ { 0x0000151f, "SmartLink 5634PCV SurfRider", 0x10 },
+ { 0x0103115d, "Xircom Cardbus modem", 0x10 },
+ { 0x98459710, "Netmos Nm9845 PCI Bridge with Dual UART", 0x10 },
+ { 0x01c0135c, "Quatech SSCLP-200/300", 0x18
+ /*
+ * NB: You must mount the "SPAD" jumper to correctly detect
+ * the FIFO on the UART. Set the options on the jumpers,
+ * we do not support the extra registers on the Quatech.
+ */
+ },
+ { 0x00000000, NULL, 0 }
+};
+
+static struct pci_id *
+uart_pci_match(uint32_t type, struct pci_id *id)
+{
+
+ while (id->type && id->type != type)
+ id++;
+ return ((id->type) ? id : NULL);
+}
+
+static int
+uart_pci_probe(device_t dev)
+{
+ struct uart_softc *sc;
+ struct pci_id *id;
+
+ sc = device_get_softc(dev);
+
+ id = uart_pci_match(pci_get_devid(dev), pci_ns8250_ids);
+ if (id != NULL) {
+ sc->sc_class = &uart_ns8250_class;
+ goto match;
+ }
+ /* Add checks for non-ns8250 IDs here. */
+ return (ENXIO);
+
+ match:
+ if (id->desc)
+ device_set_desc(dev, id->desc);
+ return (uart_bus_probe(dev, 0, 0, id->rid));
+}
+
+DRIVER_MODULE(uart, pci, uart_pci_driver, uart_devclass, 0, 0);
+DRIVER_MODULE(uart, cardbus, uart_pci_driver, uart_devclass, 0, 0);
diff --git a/sys/dev/uart/uart_bus_puc.c b/sys/dev/uart/uart_bus_puc.c
new file mode 100644
index 0000000..94b042e
--- /dev/null
+++ b/sys/dev/uart/uart_bus_puc.c
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2002 JF Hay. All rights reserved.
+ * Copyright (c) 2001 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/puc/pucvar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+
+static int uart_puc_probe(device_t dev);
+
+static device_method_t uart_puc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_puc_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_puc_driver = {
+ uart_driver_name,
+ uart_puc_methods,
+ sizeof(struct uart_softc),
+};
+
+static int
+uart_puc_probe(device_t dev)
+{
+ device_t parent;
+ struct uart_softc *sc;
+ uintptr_t rclk, regshft, type;
+
+ parent = device_get_parent(dev);
+ sc = device_get_softc(dev);
+
+ if (BUS_READ_IVAR(parent, dev, PUC_IVAR_SUBTYPE, &type))
+ return (ENXIO);
+ switch (type) {
+ case PUC_PORT_UART_NS8250:
+ sc->sc_class = &uart_ns8250_class;
+ break;
+ case PUC_PORT_UART_SAB82532:
+ sc->sc_class = &uart_sab82532_class;
+ break;
+ case PUC_PORT_UART_Z8530:
+ sc->sc_class = &uart_z8530_class;
+ break;
+ default:
+ return (ENXIO);
+ }
+
+ if (BUS_READ_IVAR(parent, dev, PUC_IVAR_FREQ, &rclk))
+ rclk = 0;
+ if (BUS_READ_IVAR(parent, dev, PUC_IVAR_REGSHFT, &regshft))
+ regshft = 0;
+ return (uart_bus_probe(dev, regshft, rclk, 0));
+}
+
+DRIVER_MODULE(uart, puc, uart_puc_driver, uart_devclass, 0, 0);
diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c
new file mode 100644
index 0000000..450313a
--- /dev/null
+++ b/sys/dev/uart/uart_core.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef KLD_MODULE
+#include "opt_comconsole.h"
+#include "opt_ddb.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/cons.h>
+#include <sys/fcntl.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/reboot.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <sys/termios.h>
+#include <sys/tty.h>
+#include <machine/resource.h>
+#include <machine/stdarg.h>
+
+#include <ddb/ddb.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include "uart_if.h"
+
+devclass_t uart_devclass;
+char uart_driver_name[] = "uart";
+
+SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs =
+ SLIST_HEAD_INITIALIZER(uart_sysdevs);
+
+MALLOC_DEFINE(M_UART, "UART", "UART driver");
+
+void
+uart_add_sysdev(struct uart_devinfo *di)
+{
+ SLIST_INSERT_HEAD(&uart_sysdevs, di, next);
+}
+
+/*
+ * A break condition has been detected. We treat the break condition as
+ * a special case that should not happen during normal operation. When
+ * the break condition is to be passed to higher levels in the form of
+ * a NUL character, we really want the break to be in the right place in
+ * the input stream. The overhead to achieve that is not in relation to
+ * the exceptional nature of the break condition, so we permit ourselves
+ * to be sloppy.
+ */
+static void
+uart_intr_break(struct uart_softc *sc)
+{
+
+#if defined(DDB) && defined(BREAK_TO_DEBUGGER)
+ if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
+ breakpoint();
+ return;
+ }
+#endif
+ if (sc->sc_opened)
+ atomic_set_32(&sc->sc_ttypend, UART_IPEND_BREAK);
+}
+
+/*
+ * Handle a receiver overrun situation. We lost at least 1 byte in the
+ * input stream and it's our job to contain the situation. We grab as
+ * much of the data we can, but otherwise flush the receiver FIFO to
+ * create some breathing room. The net effect is that we avoid the
+ * overrun condition to happen for the next X characters, where X is
+ * related to the FIFO size at the cost of loosing data right away.
+ * So, instead of having multiple overrun interrupts in close proximity
+ * to each other and possibly pessimizing UART interrupt latency for
+ * other UARTs in a multiport configuration, we create a longer segment
+ * of missing characters by freeing up the FIFO.
+ * Each overrun condition is marked in the input buffer by a token. The
+ * token represents the loss of at least one, but possible more bytes in
+ * the input stream.
+ */
+static void
+uart_intr_overrun(struct uart_softc *sc)
+{
+
+ if (sc->sc_opened) {
+ UART_RECEIVE(sc);
+ if (uart_rx_put(sc, UART_STAT_OVERRUN))
+ sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
+ atomic_set_32(&sc->sc_ttypend, UART_IPEND_RXREADY);
+ }
+ UART_FLUSH(sc, UART_FLUSH_RECEIVER);
+}
+
+/*
+ * Received data ready.
+ */
+static void
+uart_intr_rxready(struct uart_softc *sc)
+{
+ int rxp;
+
+ rxp = sc->sc_rxput;
+ UART_RECEIVE(sc);
+#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
+ if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
+ while (rxp != sc->sc_rxput) {
+ if (db_alt_break(sc->sc_rxbuf[rxp++], &sc->sc_altbrk))
+ breakpoint();
+ if (rxp == sc->sc_rxbufsz)
+ rxp = 0;
+ }
+ }
+#endif
+ if (sc->sc_opened)
+ atomic_set_32(&sc->sc_ttypend, UART_IPEND_RXREADY);
+ else
+ sc->sc_rxput = sc->sc_rxget; /* Ignore received data. */
+}
+
+/*
+ * Line or modem status change (OOB signalling).
+ * We pass the signals to the software interrupt handler for further
+ * processing. Note that we merge the delta bits, but set the state
+ * bits. This is to avoid loosing state transitions due to having more
+ * than 1 hardware interrupt between software interrupts.
+ */
+static void
+uart_intr_sigchg(struct uart_softc *sc)
+{
+ int new, old, sig;
+
+ sig = UART_GETSIG(sc);
+ do {
+ old = sc->sc_ttypend;
+ new = old & ~UART_SIGMASK_STATE;
+ new |= sig & UART_IPEND_SIGMASK;
+ new |= UART_IPEND_SIGCHG;
+ } while (!atomic_cmpset_32(&sc->sc_ttypend, old, new));
+}
+
+/*
+ * The transmitter can accept more data.
+ */
+static void
+uart_intr_txidle(struct uart_softc *sc)
+{
+ if (sc->sc_txbusy) {
+ sc->sc_txbusy = 0;
+ atomic_set_32(&sc->sc_ttypend, UART_IPEND_TXIDLE);
+ }
+}
+
+static void
+uart_intr(void *arg)
+{
+ struct uart_softc *sc = arg;
+ int ipend;
+
+ if (sc->sc_leaving)
+ return;
+
+ ipend = UART_IPEND(sc);
+ if (ipend & UART_IPEND_OVERRUN)
+ uart_intr_overrun(sc);
+ if (ipend & UART_IPEND_BREAK)
+ uart_intr_break(sc);
+ if (ipend & UART_IPEND_RXREADY)
+ uart_intr_rxready(sc);
+ if (ipend & UART_IPEND_SIGCHG)
+ uart_intr_sigchg(sc);
+ if (ipend & UART_IPEND_TXIDLE)
+ uart_intr_txidle(sc);
+
+ if (sc->sc_opened && sc->sc_ttypend != 0)
+ swi_sched(sc->sc_softih, 0);
+}
+
+int
+uart_bus_probe(device_t dev, int regshft, int rclk, int rid)
+{
+ struct uart_softc *sc;
+ struct uart_devinfo *sysdev;
+ int error;
+
+ /*
+ * Initialize the instance. Note that the instance (=softc) does
+ * not necessarily match the hardware specific softc. We can't do
+ * anything about it now, because we may not attach to the device.
+ * Hardware drivers cannot use any of the class specific fields
+ * while probing.
+ */
+ sc = device_get_softc(dev);
+ kobj_init((kobj_t)sc, (kobj_class_t)sc->sc_class);
+ sc->sc_dev = dev;
+ if (device_get_desc(dev) == NULL)
+ device_set_desc(dev, sc->sc_class->name);
+
+ /*
+ * Allocate the register resource. We assume that all UARTs have
+ * a single register window in either I/O port space or memory
+ * mapped I/O space. Any UART that needs multiple windows will
+ * consequently not be supported by this driver as-is. We try I/O
+ * port space first because that's the common case.
+ */
+ 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, sc->sc_class->uc_range, 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, sc->sc_class->uc_range, RF_ACTIVE);
+ if (sc->sc_rres == NULL)
+ return (ENXIO);
+ }
+
+ /*
+ * Fill in the bus access structure and compare this device with
+ * a possible console device and/or a debug port. We set the flags
+ * in the softc so that the hardware dependent probe can adjust
+ * accordingly. In general, you don't want to permanently disrupt
+ * console I/O.
+ */
+ sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
+ sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
+ sc->sc_bas.regshft = regshft;
+ sc->sc_bas.rclk = (rclk == 0) ? sc->sc_class->uc_rclk : rclk;
+
+ SLIST_FOREACH(sysdev, &uart_sysdevs, next) {
+ if (uart_cpu_eqres(&sc->sc_bas, &sysdev->bas)) {
+ /* XXX check if ops matches class. */
+ sc->sc_sysdev = sysdev;
+ break;
+ }
+ }
+
+ error = UART_PROBE(sc);
+ bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
+ return (error);
+}
+
+int
+uart_bus_attach(device_t dev)
+{
+ struct uart_softc *sc, *sc0;
+ const char *sep;
+ int error;
+
+ /*
+ * The sc_class field defines the type of UART we're going to work
+ * with and thus the size of the softc. Replace the generic softc
+ * with one that matches the UART now that we're certain we handle
+ * the device.
+ */
+ sc0 = device_get_softc(dev);
+ if (sc0->sc_class->size > sizeof(*sc)) {
+ sc = malloc(sc0->sc_class->size, M_UART, M_WAITOK|M_ZERO);
+ bcopy(sc0, sc, sizeof(*sc));
+ device_set_softc(dev, sc);
+ } else
+ sc = sc0;
+
+ /*
+ * Protect ourselves against interrupts while we're not completely
+ * finished attaching and initializing. We don't expect interrupts
+ * until after UART_ATTACH() though.
+ */
+ sc->sc_leaving = 1;
+
+ /*
+ * 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, sc->sc_class->uc_range, RF_ACTIVE);
+ if (sc->sc_rres == NULL)
+ return (ENXIO);
+
+ sc->sc_irid = 0;
+ sc->sc_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_irid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (sc->sc_ires != NULL) {
+ error = BUS_SETUP_INTR(device_get_parent(dev), dev,
+ sc->sc_ires, INTR_TYPE_TTY | INTR_FAST, uart_intr,
+ sc, &sc->sc_icookie);
+ if (error)
+ error = BUS_SETUP_INTR(device_get_parent(dev), dev,
+ sc->sc_ires, INTR_TYPE_TTY, uart_intr, sc,
+ &sc->sc_icookie);
+ else
+ sc->sc_fastintr = 1;
+
+ if (error) {
+ device_printf(dev, "could not activate interrupt\n");
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
+ sc->sc_ires);
+ sc->sc_ires = NULL;
+ }
+ }
+ if (sc->sc_ires == NULL) {
+ /* XXX no interrupt resource. Force polled mode. */
+ sc->sc_polled = 1;
+ }
+
+ sc->sc_rxbufsz = IBUFSIZ;
+ sc->sc_rxbuf = malloc(sc->sc_rxbufsz * sizeof(*sc->sc_rxbuf),
+ M_UART, M_WAITOK);
+ sc->sc_txbuf = malloc(sc->sc_txfifosz * sizeof(*sc->sc_txbuf),
+ M_UART, M_WAITOK);
+
+ error = UART_ATTACH(sc);
+ if (error)
+ goto fail;
+
+ if (sc->sc_hwiflow || sc->sc_hwoflow) {
+ sep = "";
+ device_print_prettyname(dev);
+ if (sc->sc_hwiflow) {
+ printf("%sRTS iflow", sep);
+ sep = ", ";
+ }
+ if (sc->sc_hwoflow) {
+ printf("%sCTS oflow", sep);
+ sep = ", ";
+ }
+ printf("\n");
+ }
+
+ if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
+ sep = "";
+ device_print_prettyname(dev);
+ if (sc->sc_fastintr) {
+ printf("%sfast interrupt", sep);
+ sep = ", ";
+ }
+ if (sc->sc_polled) {
+ printf("%spolled mode", sep);
+ sep = ", ";
+ }
+ printf("\n");
+ }
+
+ if (sc->sc_sysdev != NULL) {
+ switch (sc->sc_sysdev->type) {
+ case UART_DEV_CONSOLE:
+ device_printf(dev, "console");
+ break;
+ case UART_DEV_DBGPORT:
+ device_printf(dev, "debug port");
+ break;
+ case UART_DEV_KEYBOARD:
+ device_printf(dev, "keyboard");
+ break;
+ default:
+ device_printf(dev, "unknown system device");
+ break;
+ }
+ printf(" (%d,%c,%d,%d)\n", sc->sc_sysdev->baudrate,
+ "noems"[sc->sc_sysdev->parity], sc->sc_sysdev->databits,
+ sc->sc_sysdev->stopbits);
+ }
+
+ error = (sc->sc_sysdev != NULL && sc->sc_sysdev->attach != NULL)
+ ? (*sc->sc_sysdev->attach)(sc) : uart_tty_attach(sc);
+ if (error)
+ goto fail;
+
+ sc->sc_leaving = 0;
+ uart_intr(sc);
+ return (0);
+
+ fail:
+ free(sc->sc_txbuf, M_UART);
+ free(sc->sc_rxbuf, M_UART);
+
+ if (sc->sc_ires != NULL) {
+ bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
+ sc->sc_ires);
+ }
+ bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
+
+ return (error);
+}
+
+int
+uart_bus_detach(device_t dev)
+{
+ struct uart_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ sc->sc_leaving = 1;
+
+ UART_DETACH(sc);
+
+ if (sc->sc_sysdev != NULL && sc->sc_sysdev->detach != NULL)
+ (*sc->sc_sysdev->detach)(sc);
+ else
+ uart_tty_detach(sc);
+
+ free(sc->sc_txbuf, M_UART);
+ free(sc->sc_rxbuf, M_UART);
+
+ if (sc->sc_ires != NULL) {
+ bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
+ sc->sc_ires);
+ }
+ bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
+
+ if (sc->sc_class->size > sizeof(*sc)) {
+ device_set_softc(dev, NULL);
+ free(sc, M_UART);
+ } else
+ device_set_softc(dev, NULL);
+
+ return (0);
+}
diff --git a/sys/dev/uart/uart_cpu.h b/sys/dev/uart/uart_cpu.h
new file mode 100644
index 0000000..bd1bd5f
--- /dev/null
+++ b/sys/dev/uart/uart_cpu.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_UART_CPU_H_
+#define _DEV_UART_CPU_H_
+
+/*
+ * Low-level operations for use by console and/or debug port support.
+ */
+struct uart_ops {
+ int (*probe)(struct uart_bas *);
+ void (*init)(struct uart_bas *, int, int, int, int);
+ void (*term)(struct uart_bas *);
+ void (*putc)(struct uart_bas *, int);
+ int (*poll)(struct uart_bas *);
+ int (*getc)(struct uart_bas *);
+};
+
+extern struct uart_ops uart_ns8250_ops;
+extern struct uart_ops uart_sab82532_ops;
+extern struct uart_ops uart_z8530_ops;
+
+/*
+ * Console and debug port device info.
+ */
+struct uart_softc;
+struct uart_devinfo {
+ SLIST_ENTRY(uart_devinfo) next;
+ struct uart_ops ops;
+ struct uart_bas bas;
+ int baudrate;
+ int databits;
+ int stopbits;
+ int parity;
+ int type;
+#define UART_DEV_CONSOLE 0
+#define UART_DEV_DBGPORT 1
+#define UART_DEV_KEYBOARD 2
+ int (*attach)(struct uart_softc*);
+ int (*detach)(struct uart_softc*);
+ void *cookie; /* Type dependent use. */
+};
+
+int uart_cpu_getdev(int devtype, struct uart_devinfo *di);
+int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2);
+
+void uart_add_sysdev(struct uart_devinfo*);
+
+/*
+ * Operations for low-level access to the UART. Primarily for use
+ * by console and debug port logic.
+ */
+static __inline int
+uart_probe(struct uart_devinfo *di)
+{
+ return (di->ops.probe(&di->bas));
+}
+
+static __inline void
+uart_init(struct uart_devinfo *di)
+{
+ di->ops.init(&di->bas, di->baudrate, di->databits, di->stopbits,
+ di->parity);
+}
+
+static __inline void
+uart_term(struct uart_devinfo *di)
+{
+ di->ops.term(&di->bas);
+}
+
+static __inline void
+uart_putc(struct uart_devinfo *di, int c)
+{
+ di->ops.putc(&di->bas, c);
+}
+
+static __inline int
+uart_poll(struct uart_devinfo *di)
+{
+ return (di->ops.poll(&di->bas));
+}
+
+static __inline int
+uart_getc(struct uart_devinfo *di)
+{
+ return (di->ops.getc(&di->bas));
+}
+
+#endif /* _DEV_UART_CPU_H_ */
diff --git a/sys/dev/uart/uart_cpu_alpha.c b/sys/dev/uart/uart_cpu_alpha.c
new file mode 100644
index 0000000..95ee2ff
--- /dev/null
+++ b/sys/dev/uart/uart_cpu_alpha.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/reboot.h>
+
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/rpb.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ struct ctb *ctb;
+ unsigned int i, ivar;
+
+ if (devtype == UART_DEV_CONSOLE) {
+ ctb = (struct ctb *)(((caddr_t)hwrpb) + hwrpb->rpb_ctb_off);
+ if (ctb->ctb_term_type != CTB_PRINTERPORT)
+ return (ENXIO);
+ boothowto |= RB_SERIAL;
+ di->ops = uart_ns8250_ops;
+ di->bas.bst = busspace_isa_io;
+ di->bas.bsh = 0x3f8;
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ di->baudrate = 9600;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ return (0);
+ }
+
+ /*
+ * Scan the hints. We only try units 0 to 3 (inclusive). This
+ * covers the ISA legacy where 4 UARTs had their resources
+ * predefined.
+ */
+ for (i = 0; i < 4; i++) {
+ if (resource_int_value("uart", i, "flags", &ivar))
+ continue;
+ if (devtype == UART_DEV_DBGPORT && !UART_FLAGS_DBGPORT(ivar))
+ continue;
+ /*
+ * We have a possible device. Make sure it's enabled and
+ * that we have an I/O port.
+ */
+ if (resource_int_value("uart", i, "disabled", &ivar) == 0 &&
+ ivar != 0)
+ continue;
+ if (resource_int_value("uart", i, "port", &ivar) != 0 ||
+ ivar == 0)
+ continue;
+ /*
+ * Got it. Fill in the instance and return it. We assume we
+ * only have ns8250 and successors on alpha.
+ */
+ di->ops = uart_ns8250_ops;
+ di->bas.bst = busspace_isa_io;
+ di->bas.bsh = ivar;
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ if (resource_int_value("uart", i, "baud", &ivar) != 0)
+ ivar = 0;
+ di->baudrate = ivar;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ return (0);
+ }
+
+ return (ENXIO);
+}
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
diff --git a/sys/dev/uart/uart_cpu_amd64.c b/sys/dev/uart/uart_cpu_amd64.c
new file mode 100644
index 0000000..a186216
--- /dev/null
+++ b/sys/dev/uart/uart_cpu_amd64.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ unsigned int i, ivar;
+
+ /*
+ * Scan the hints. We only try units 0 to 3 (inclusive). This
+ * covers the ISA legacy where 4 UARTs had their resources
+ * predefined.
+ */
+ for (i = 0; i < 4; i++) {
+ if (resource_int_value("uart", i, "flags", &ivar))
+ continue;
+ if (devtype == UART_DEV_CONSOLE && !UART_FLAGS_CONSOLE(ivar))
+ continue;
+ if (devtype == UART_DEV_DBGPORT && !UART_FLAGS_DBGPORT(ivar))
+ continue;
+ /*
+ * We have a possible device. Make sure it's enabled and
+ * that we have an I/O port.
+ */
+ if (resource_int_value("uart", i, "disabled", &ivar) == 0 &&
+ ivar != 0)
+ continue;
+ if (resource_int_value("uart", i, "port", &ivar) != 0 ||
+ ivar == 0)
+ continue;
+ /*
+ * Got it. Fill in the instance and return it. We only have
+ * ns8250 and successors on i386.
+ */
+ di->ops = uart_ns8250_ops;
+ di->bas.bst = AMD64_BUS_SPACE_IO;
+ di->bas.bsh = ivar;
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ if (resource_int_value("uart", i, "baud", &ivar) != 0)
+ ivar = 0;
+ di->baudrate = ivar;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ return (0);
+ }
+
+ return (ENXIO);
+}
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
diff --git a/sys/dev/uart/uart_cpu_i386.c b/sys/dev/uart/uart_cpu_i386.c
new file mode 100644
index 0000000..04de73a
--- /dev/null
+++ b/sys/dev/uart/uart_cpu_i386.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ unsigned int i, ivar;
+
+ /*
+ * Scan the hints. We only try units 0 to 3 (inclusive). This
+ * covers the ISA legacy where 4 UARTs had their resources
+ * predefined.
+ */
+ for (i = 0; i < 4; i++) {
+ if (resource_int_value("uart", i, "flags", &ivar))
+ continue;
+ if (devtype == UART_DEV_CONSOLE && !UART_FLAGS_CONSOLE(ivar))
+ continue;
+ if (devtype == UART_DEV_DBGPORT && !UART_FLAGS_DBGPORT(ivar))
+ continue;
+ /*
+ * We have a possible device. Make sure it's enabled and
+ * that we have an I/O port.
+ */
+ if (resource_int_value("uart", i, "disabled", &ivar) == 0 &&
+ ivar != 0)
+ continue;
+ if (resource_int_value("uart", i, "port", &ivar) != 0 ||
+ ivar == 0)
+ continue;
+ /*
+ * Got it. Fill in the instance and return it. We only have
+ * ns8250 and successors on i386.
+ */
+ di->ops = uart_ns8250_ops;
+ di->bas.bst = I386_BUS_SPACE_IO;
+ di->bas.bsh = ivar;
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ if (resource_int_value("uart", i, "baud", &ivar) != 0)
+ ivar = 0;
+ di->baudrate = ivar;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ return (0);
+ }
+
+ return (ENXIO);
+}
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
diff --git a/sys/dev/uart/uart_cpu_ia64.c b/sys/dev/uart/uart_cpu_ia64.c
new file mode 100644
index 0000000..f3523fb
--- /dev/null
+++ b/sys/dev/uart/uart_cpu_ia64.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bootinfo.h>
+#include <machine/bus.h>
+#include <machine/dig64.h>
+#include <machine/vmparam.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+static int dig64_to_uart_parity[] = {
+ UART_PARITY_NONE, UART_PARITY_NONE, UART_PARITY_EVEN,
+ UART_PARITY_ODD, UART_PARITY_MARK, UART_PARITY_SPACE
+};
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ struct dig64_hcdp_table *tbl;
+ struct dig64_hcdp_entry *ent;
+ unsigned int i, ivar;
+
+ /*
+ * Use the DIG64 HCDP table if present.
+ */
+ if (bootinfo.bi_hcdp != 0) {
+ tbl = (void*)IA64_PHYS_TO_RR7(bootinfo.bi_hcdp);
+ for (i = 0; i < tbl->entries; i++) {
+ ent = tbl->entry + i;
+
+ if (devtype == UART_DEV_CONSOLE &&
+ ent->type != DIG64_HCDP_CONSOLE)
+ continue;
+
+ if (devtype == UART_DEV_DBGPORT &&
+ ent->type != DIG64_HCDP_DBGPORT)
+ continue;
+
+ di->ops = uart_ns8250_ops;
+ di->bas.bst = IA64_BUS_SPACE_IO;
+ di->bas.bst = (ent->address.addr_space == 0)
+ ? IA64_BUS_SPACE_MEM : IA64_BUS_SPACE_IO;
+ di->bas.bsh = ent->address.addr_high;
+ di->bas.bsh = (di->bas.bsh << 32) +
+ ent->address.addr_low;
+ di->bas.regshft = 0;
+ di->bas.rclk = ent->pclock << 4;
+ /* We don't deal with 64-bit baud rates. */
+ di->baudrate = ent->baud_low;
+ di->databits = ent->databits;
+ di->stopbits = ent->stopbits;
+ di->parity = (ent->parity >= 6) ? UART_PARITY_NONE
+ : dig64_to_uart_parity[ent->parity];
+ return (0);
+ }
+
+ /* FALLTHROUGH */
+ }
+
+ /*
+ * Scan the hints for backward compatibility. We only try units
+ * 0 to 3 (inclusive). This covers the ISA legacy where 4 UARTs
+ * had their resources predefined.
+ */
+ for (i = 0; i < 4; i++) {
+ if (resource_int_value("uart", i, "flags", &ivar))
+ continue;
+ if (devtype == UART_DEV_CONSOLE && !UART_FLAGS_CONSOLE(ivar))
+ continue;
+ if (devtype == UART_DEV_DBGPORT && !UART_FLAGS_DBGPORT(ivar))
+ continue;
+ /*
+ * We have a possible device. Make sure it's enabled and
+ * that we have an I/O port.
+ */
+ if (resource_int_value("uart", i, "disabled", &ivar) == 0 &&
+ ivar != 0)
+ continue;
+ if (resource_int_value("uart", i, "port", &ivar) != 0 ||
+ ivar == 0)
+ continue;
+ /*
+ * Got it. Fill in the instance and return it. We only have
+ * ns8250 and successors on i386.
+ */
+ di->ops = uart_ns8250_ops;
+ di->bas.bst = IA64_BUS_SPACE_IO;
+ di->bas.bsh = ivar;
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ if (resource_int_value("uart", i, "baud", &ivar) != 0)
+ ivar = 0;
+ di->baudrate = ivar;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ return (0);
+ }
+
+ return (ENXIO);
+}
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
diff --git a/sys/dev/uart/uart_cpu_sparc64.c b/sys/dev/uart/uart_cpu_sparc64.c
new file mode 100644
index 0000000..fed26a8
--- /dev/null
+++ b/sys/dev/uart/uart_cpu_sparc64.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+#include <machine/bus_private.h>
+
+#include <dev/ofw/openfirm.h>
+#include <machine/ofw_machdep.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+static struct bus_space_tag bst_store[3];
+
+static int
+uart_cpu_channel(char *dev)
+{
+ char alias[64];
+ phandle_t aliases;
+ int len;
+
+ strcpy(alias, dev);
+ if ((aliases = OF_finddevice("/aliases")) != -1)
+ OF_getprop(aliases, dev, alias, sizeof(alias));
+ len = strlen(alias);
+ if (len < 2 || alias[len - 2] != ':' || alias[len - 1] < 'a' ||
+ alias[len - 1] > 'b')
+ return (0);
+ return (alias[len - 1] - 'a');
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ char buf[32], dev[32];
+ phandle_t input, options, output;
+ bus_addr_t addr;
+ int baud, bits, ch, error, space, stop;
+ char flag, par;
+
+ /*
+ * Get the address of the UART that is selected as the console, if
+ * the console is an UART of course. Note that we enforce that both
+ * stdin and stdout are selected. For weird configurations, use
+ * ofw_console(4).
+ * Note that the currently active console (ie /chosen/stdout and
+ * /chosen/stdin) may not be the same as the device selected in the
+ * environment (ie /options/output-device and /options/input-device)
+ * because the user may have changed the environment. In that case
+ * I would assume that the user expects that FreeBSD uses the new
+ * console setting. There's choice choice, really.
+ */
+ if ((options = OF_finddevice("/options")) == -1)
+ return (ENXIO);
+ if (OF_getprop(options, "input-device", dev, sizeof(dev)) == -1)
+ return (ENXIO);
+ if ((input = OF_finddevice(dev)) == -1)
+ return (ENXIO);
+ if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1)
+ return (ENXIO);
+ if (strcmp(buf, "serial"))
+ return (ENODEV);
+ if (devtype == UART_DEV_KEYBOARD) {
+ if (OF_getprop(input, "keyboard", buf, sizeof(buf)) == -1)
+ return (ENXIO);
+ } else if (devtype == UART_DEV_CONSOLE) {
+ if (OF_getprop(options, "output-device", buf, sizeof(buf))
+ == -1)
+ return (ENXIO);
+ if ((output = OF_finddevice(buf)) == -1)
+ return (ENXIO);
+ if (input != output)
+ return (ENXIO);
+ } else
+ return (ENODEV);
+
+ error = OF_decode_addr(input, &space, &addr);
+ if (error)
+ return (error);
+
+ /* Get the device class. */
+ if (OF_getprop(input, "name", buf, sizeof(buf)) == -1)
+ return (ENXIO);
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ if (!strcmp(buf, "se")) {
+ di->ops = uart_sab82532_ops;
+ addr += 64 * uart_cpu_channel(dev);
+ } else if (!strcmp(buf, "zs")) {
+ di->ops = uart_z8530_ops;
+ di->bas.regshft = 1;
+ ch = uart_cpu_channel(dev);
+ addr += 4 - 4 * ch;
+ } else if (!strcmp(buf, "su") || !strcmp(buf, "su_pnp"))
+ di->ops = uart_ns8250_ops;
+ else
+ return (ENXIO);
+
+ /* Fill in the device info. */
+ di->bas.bst = &bst_store[devtype];
+ di->bas.bsh = sparc64_fake_bustag(space, addr, di->bas.bst);
+
+ /* Get the line settings. */
+ di->baudrate = 9600;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ snprintf(buf, sizeof(buf), "%s-mode", dev);
+ if (OF_getprop(options, buf, buf, sizeof(buf)) == -1)
+ return (0);
+ if (sscanf(buf, "%d,%d,%c,%d,%c", &baud, &bits, &par, &stop, &flag)
+ != 5)
+ return (0);
+ di->baudrate = baud;
+ di->databits = bits;
+ di->stopbits = stop;
+ di->parity = (par == 'n') ? UART_PARITY_NONE :
+ (par == 'o') ? UART_PARITY_ODD : UART_PARITY_EVEN;
+ return (0);
+}
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+
+ return ((b1->bsh == b2->bsh) ? 1 : 0);
+}
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
new file mode 100644
index 0000000..d09371d
--- /dev/null
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_dev_ns8250.h>
+
+#include "uart_if.h"
+
+#define DEFAULT_RCLK 1843200
+
+/*
+ * Clear pending interrupts. THRE is cleared by reading IIR. Data
+ * that may have been received gets lost here.
+ */
+static void
+ns8250_clrint(struct uart_bas *bas)
+{
+ uint8_t iir;
+
+ iir = uart_getreg(bas, REG_IIR);
+ while ((iir & IIR_NOPEND) == 0) {
+ iir &= IIR_IMASK;
+ if (iir == IIR_RLS)
+ (void)uart_getreg(bas, REG_LSR);
+ else if (iir == IIR_RXRDY || iir == IIR_RXTOUT)
+ (void)uart_getreg(bas, REG_DATA);
+ else if (iir == IIR_MLSC)
+ (void)uart_getreg(bas, REG_MSR);
+ uart_barrier(bas);
+ iir = uart_getreg(bas, REG_IIR);
+ }
+}
+
+static int
+ns8250_delay(struct uart_bas *bas)
+{
+ int divisor;
+ u_char lcr;
+
+ lcr = uart_getreg(bas, REG_LCR);
+ uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
+ uart_barrier(bas);
+ divisor = uart_getdreg(bas, REG_DL);
+ uart_barrier(bas);
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+
+ /* 1/10th the time to transmit 1 character (estimate). */
+ return (16000000 * divisor / bas->rclk);
+}
+
+static int
+ns8250_divisor(int rclk, int baudrate)
+{
+ int actual_baud, divisor;
+ int error;
+
+ if (baudrate == 0)
+ return (0);
+
+ divisor = (rclk / (baudrate << 3) + 1) >> 1;
+ if (divisor == 0 || divisor >= 65536)
+ return (0);
+ actual_baud = rclk / (divisor << 4);
+
+ /* 10 times error in percent: */
+ error = ((actual_baud - baudrate) * 2000 / baudrate + 1) >> 1;
+
+ /* 3.0% maximum error tolerance: */
+ if (error < -30 || error > 30)
+ return (0);
+
+ return (divisor);
+}
+
+static int
+ns8250_drain(struct uart_bas *bas, int what)
+{
+ int delay, limit;
+
+ delay = ns8250_delay(bas);
+
+ if (what & UART_DRAIN_TRANSMITTER) {
+ /*
+ * Pick an arbitrary high limit to avoid getting stuck in
+ * an infinite loop when the hardware is broken. Make the
+ * limit high enough to handle large FIFOs.
+ */
+ limit = 10*1024;
+ while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit)
+ DELAY(delay);
+ if (limit == 0) {
+ /* printf("ns8250: transmitter appears stuck... "); */
+ return (EIO);
+ }
+ }
+
+ if (what & UART_DRAIN_RECEIVER) {
+ /*
+ * Pick an arbitrary high limit to avoid getting stuck in
+ * an infinite loop when the hardware is broken. Make the
+ * limit high enough to handle large FIFOs and integrated
+ * UARTs. The HP rx2600 for example has 3 UARTs on the
+ * management board that tend to get a lot of data send
+ * to it when the UART is first activated.
+ */
+ limit=10*4096;
+ while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) && --limit) {
+ (void)uart_getreg(bas, REG_DATA);
+ uart_barrier(bas);
+ DELAY(delay << 2);
+ }
+ if (limit == 0) {
+ /* printf("ns8250: receiver appears broken... "); */
+ return (EIO);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * We can only flush UARTs with FIFOs. UARTs without FIFOs should be
+ * drained. WARNING: this function clobbers the FIFO setting!
+ */
+static void
+ns8250_flush(struct uart_bas *bas, int what)
+{
+ uint8_t fcr;
+
+ fcr = FCR_ENABLE;
+ if (what & UART_FLUSH_TRANSMITTER)
+ fcr |= FCR_XMT_RST;
+ if (what & UART_FLUSH_RECEIVER)
+ fcr |= FCR_RCV_RST;
+ uart_setreg(bas, REG_FCR, fcr);
+ uart_barrier(bas);
+}
+
+static int
+ns8250_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+ int divisor;
+ uint8_t lcr;
+
+ lcr = 0;
+ if (databits >= 8)
+ lcr |= LCR_8BITS;
+ else if (databits == 7)
+ lcr |= LCR_7BITS;
+ else if (databits == 6)
+ lcr |= LCR_6BITS;
+ else
+ lcr |= LCR_5BITS;
+ if (stopbits > 1)
+ lcr |= LCR_STOPB;
+ lcr |= parity << 3;
+
+ /* Set baudrate. */
+ if (baudrate > 0) {
+ uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
+ uart_barrier(bas);
+ divisor = ns8250_divisor(bas->rclk, baudrate);
+ if (divisor == 0)
+ return (EINVAL);
+ uart_setdreg(bas, REG_DL, divisor);
+ uart_barrier(bas);
+ }
+
+ /* Set LCR and clear DLAB. */
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+ return (0);
+}
+
+/*
+ * Low-level UART interface.
+ */
+static int ns8250_probe(struct uart_bas *bas);
+static void ns8250_init(struct uart_bas *bas, int, int, int, int);
+static void ns8250_term(struct uart_bas *bas);
+static void ns8250_putc(struct uart_bas *bas, int);
+static int ns8250_poll(struct uart_bas *bas);
+static int ns8250_getc(struct uart_bas *bas);
+
+struct uart_ops uart_ns8250_ops = {
+ .probe = ns8250_probe,
+ .init = ns8250_init,
+ .term = ns8250_term,
+ .putc = ns8250_putc,
+ .poll = ns8250_poll,
+ .getc = ns8250_getc,
+};
+
+static int
+ns8250_probe(struct uart_bas *bas)
+{
+ u_char lcr, val;
+
+ /* Check known 0 bits that don't depend on DLAB. */
+ val = uart_getreg(bas, REG_IIR);
+ if (val & 0x30)
+ return (ENXIO);
+ val = uart_getreg(bas, REG_MCR);
+ if (val & 0xe0)
+ return (ENXIO);
+
+ lcr = uart_getreg(bas, REG_LCR);
+ uart_setreg(bas, REG_LCR, lcr & ~LCR_DLAB);
+ uart_barrier(bas);
+
+ /* Check known 0 bits that depend on !DLAB. */
+ val = uart_getreg(bas, REG_IER);
+ if (val & 0xf0)
+ goto fail;
+
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+ return (0);
+
+ fail:
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+ return (ENXIO);
+}
+
+static void
+ns8250_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+
+ if (bas->rclk == 0)
+ bas->rclk = DEFAULT_RCLK;
+ ns8250_param(bas, baudrate, databits, stopbits, parity);
+
+ /* Disable all interrupt sources. */
+ uart_setreg(bas, REG_IER, 0);
+ uart_barrier(bas);
+
+ /* Disable the FIFO (if present). */
+ uart_setreg(bas, REG_FCR, 0);
+ uart_barrier(bas);
+
+ /* Set RTS & DTR. */
+ uart_setreg(bas, REG_MCR, MCR_IE | MCR_RTS | MCR_DTR);
+ uart_barrier(bas);
+
+ ns8250_clrint(bas);
+}
+
+static void
+ns8250_term(struct uart_bas *bas)
+{
+
+ /* Clear RTS & DTR. */
+ uart_setreg(bas, REG_MCR, MCR_IE);
+ uart_barrier(bas);
+}
+
+static void
+ns8250_putc(struct uart_bas *bas, int c)
+{
+ int delay, limit;
+
+ /* 1/10th the time to transmit 1 character (estimate). */
+ delay = ns8250_delay(bas);
+
+ limit = 20;
+ while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0 && --limit)
+ DELAY(delay);
+ uart_setreg(bas, REG_DATA, c);
+ limit = 40;
+ while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit)
+ DELAY(delay);
+}
+
+static int
+ns8250_poll(struct uart_bas *bas)
+{
+
+ if (uart_getreg(bas, REG_LSR) & LSR_RXRDY)
+ return (uart_getreg(bas, REG_DATA));
+ return (-1);
+}
+
+static int
+ns8250_getc(struct uart_bas *bas)
+{
+ int delay;
+
+ /* 1/10th the time to transmit 1 character (estimate). */
+ delay = ns8250_delay(bas);
+
+ while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) == 0)
+ DELAY(delay);
+ return (uart_getreg(bas, REG_DATA));
+}
+
+/*
+ * High-level UART interface.
+ */
+struct ns8250_softc {
+ struct uart_softc base;
+ uint8_t fcr;
+ uint8_t ier;
+ uint8_t mcr;
+};
+
+static int ns8250_bus_attach(struct uart_softc *);
+static int ns8250_bus_detach(struct uart_softc *);
+static int ns8250_bus_flush(struct uart_softc *, int);
+static int ns8250_bus_getsig(struct uart_softc *);
+static int ns8250_bus_ioctl(struct uart_softc *, int, intptr_t);
+static int ns8250_bus_ipend(struct uart_softc *);
+static int ns8250_bus_param(struct uart_softc *, int, int, int, int);
+static int ns8250_bus_probe(struct uart_softc *);
+static int ns8250_bus_receive(struct uart_softc *);
+static int ns8250_bus_setsig(struct uart_softc *, int);
+static int ns8250_bus_transmit(struct uart_softc *);
+
+static kobj_method_t ns8250_methods[] = {
+ KOBJMETHOD(uart_attach, ns8250_bus_attach),
+ KOBJMETHOD(uart_detach, ns8250_bus_detach),
+ KOBJMETHOD(uart_flush, ns8250_bus_flush),
+ KOBJMETHOD(uart_getsig, ns8250_bus_getsig),
+ KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl),
+ KOBJMETHOD(uart_ipend, ns8250_bus_ipend),
+ KOBJMETHOD(uart_param, ns8250_bus_param),
+ KOBJMETHOD(uart_probe, ns8250_bus_probe),
+ KOBJMETHOD(uart_receive, ns8250_bus_receive),
+ KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
+ KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ { 0, 0 }
+};
+
+struct uart_class uart_ns8250_class = {
+ "ns8250 class",
+ ns8250_methods,
+ sizeof(struct ns8250_softc),
+ .uc_range = 8,
+ .uc_rclk = DEFAULT_RCLK
+};
+
+#define SIGCHG(c, i, s, d) \
+ if (c) { \
+ i |= (i & s) ? s : s | d; \
+ } else { \
+ i = (i & s) ? (i & ~s) | d : i; \
+ }
+
+static int
+ns8250_bus_attach(struct uart_softc *sc)
+{
+ struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
+ struct uart_bas *bas;
+
+ bas = &sc->sc_bas;
+
+ ns8250->mcr = uart_getreg(bas, REG_MCR);
+ ns8250->fcr = FCR_ENABLE | FCR_RX_MEDH;
+ uart_setreg(bas, REG_FCR, ns8250->fcr);
+ uart_barrier(bas);
+ ns8250_bus_flush(sc, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);
+
+ if (ns8250->mcr & MCR_DTR)
+ sc->sc_hwsig |= UART_SIG_DTR;
+ if (ns8250->mcr & MCR_RTS)
+ sc->sc_hwsig |= UART_SIG_RTS;
+ ns8250_bus_getsig(sc);
+
+ ns8250_clrint(bas);
+ ns8250->ier = IER_EMSC | IER_ERLS | IER_ERXRDY;
+ uart_setreg(bas, REG_IER, ns8250->ier);
+ uart_barrier(bas);
+ return (0);
+}
+
+static int
+ns8250_bus_detach(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+
+ bas = &sc->sc_bas;
+ uart_setreg(bas, REG_IER, 0);
+ uart_barrier(bas);
+ ns8250_clrint(bas);
+ return (0);
+}
+
+static int
+ns8250_bus_flush(struct uart_softc *sc, int what)
+{
+ struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
+ struct uart_bas *bas;
+
+ bas = &sc->sc_bas;
+ if (sc->sc_hasfifo) {
+ ns8250_flush(bas, what);
+ uart_setreg(bas, REG_FCR, ns8250->fcr);
+ uart_barrier(bas);
+ return (0);
+ }
+ return (ns8250_drain(bas, what));
+}
+
+static int
+ns8250_bus_getsig(struct uart_softc *sc)
+{
+ uint32_t new, old, sig;
+ uint8_t msr;
+
+ do {
+ old = sc->sc_hwsig;
+ sig = old;
+ msr = uart_getreg(&sc->sc_bas, REG_MSR);
+ SIGCHG(msr & MSR_DSR, sig, UART_SIG_DSR, UART_SIG_DDSR);
+ SIGCHG(msr & MSR_CTS, sig, UART_SIG_CTS, UART_SIG_DCTS);
+ SIGCHG(msr & MSR_DCD, sig, UART_SIG_DCD, UART_SIG_DDCD);
+ SIGCHG(msr & MSR_RI, sig, UART_SIG_RI, UART_SIG_DRI);
+ new = sig & ~UART_SIGMASK_DELTA;
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+ return (sig);
+}
+
+static int
+ns8250_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
+{
+ struct uart_bas *bas;
+ uint8_t lcr;
+
+ bas = &sc->sc_bas;
+ switch (request) {
+ case UART_IOCTL_BREAK:
+ lcr = uart_getreg(bas, REG_LCR);
+ if (data)
+ lcr |= LCR_SBREAK;
+ else
+ lcr &= ~LCR_SBREAK;
+ uart_setreg(bas, REG_LCR, lcr);
+ uart_barrier(bas);
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+ns8250_bus_ipend(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int ipend;
+ uint8_t iir, lsr;
+
+ bas = &sc->sc_bas;
+ iir = uart_getreg(bas, REG_IIR);
+ if (iir & IIR_NOPEND)
+ return (0);
+
+ ipend = 0;
+ if (iir & IIR_RXRDY) {
+ lsr = uart_getreg(bas, REG_LSR);
+ if (lsr & LSR_OE)
+ ipend |= UART_IPEND_OVERRUN;
+ if (lsr & LSR_BI)
+ ipend |= UART_IPEND_BREAK;
+ if (lsr & LSR_RXRDY)
+ ipend |= UART_IPEND_RXREADY;
+ } else {
+ if (iir & IIR_TXRDY)
+ ipend |= UART_IPEND_TXIDLE;
+ else
+ ipend |= UART_IPEND_SIGCHG;
+ }
+
+ return ((sc->sc_leaving) ? 0 : ipend);
+}
+
+static int
+ns8250_bus_param(struct uart_softc *sc, int baudrate, int databits,
+ int stopbits, int parity)
+{
+ struct uart_bas *bas;
+
+ bas = &sc->sc_bas;
+ return (ns8250_param(bas, baudrate, databits, stopbits, parity));
+}
+
+static int
+ns8250_bus_probe(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int count, delay, error, limit;
+ uint8_t mcr;
+
+ bas = &sc->sc_bas;
+
+ error = ns8250_probe(bas);
+ if (error)
+ return (error);
+
+ mcr = MCR_IE;
+ if (sc->sc_sysdev == NULL) {
+ /* By using ns8250_init() we also set DTR and RTS. */
+ ns8250_init(bas, 9600, 8, 1, UART_PARITY_NONE);
+ } else
+ mcr |= MCR_DTR | MCR_RTS;
+
+ error = ns8250_drain(bas, UART_DRAIN_TRANSMITTER);
+ if (error)
+ return (error);
+
+ /*
+ * Set loopback mode. This avoids having garbage on the wire and
+ * also allows us send and receive data. We set DTR and RTS to
+ * avoid the possibility that automatic flow-control prevents
+ * any data from being sent. We clear IE to avoid raising interrupts.
+ */
+ uart_setreg(bas, REG_MCR, MCR_LOOPBACK | MCR_DTR | MCR_RTS);
+ uart_barrier(bas);
+
+ /*
+ * Enable FIFOs. And check that the UART has them. If not, we're
+ * done. Otherwise we set DMA mode with the highest trigger level
+ * so that we can determine the FIFO size. Since this is the first
+ * time we enable the FIFOs, we reset them.
+ */
+ uart_setreg(bas, REG_FCR, FCR_ENABLE);
+ uart_barrier(bas);
+ sc->sc_hasfifo = (uart_getreg(bas, REG_IIR) & IIR_FIFO_MASK) ? 1 : 0;
+ if (!sc->sc_hasfifo) {
+ /*
+ * NS16450 or INS8250. We don't bother to differentiate
+ * between them. They're too old to be interesting.
+ */
+ uart_setreg(bas, REG_MCR, mcr);
+ uart_barrier(bas);
+ device_set_desc(sc->sc_dev, "8250 or 16450 or compatible");
+ return (0);
+ }
+
+ uart_setreg(bas, REG_FCR, FCR_ENABLE | FCR_DMA | FCR_RX_HIGH |
+ FCR_XMT_RST | FCR_RCV_RST);
+ uart_barrier(bas);
+
+ count = 0;
+ delay = ns8250_delay(bas);
+
+ /* We have FIFOs. Drain the transmitter and receiver. */
+ error = ns8250_drain(bas, UART_DRAIN_RECEIVER|UART_DRAIN_TRANSMITTER);
+ if (error) {
+ uart_setreg(bas, REG_MCR, mcr);
+ uart_setreg(bas, REG_FCR, 0);
+ uart_barrier(bas);
+ goto describe;
+ }
+
+ uart_setreg(bas, REG_IER, IER_ERXRDY);
+ uart_barrier(bas);
+
+ /*
+ * We should have a sufficiently clean "pipe" to determine the
+ * size of the FIFOs. We send as much characters as is reasonable
+ * and wait for the the RX interrupt to be asserted, counting the
+ * characters as we send them. Based on that count we know the
+ * FIFO size.
+ */
+ while ((uart_getreg(bas, REG_IIR) & IIR_RXRDY) == 0 && count < 1030) {
+ uart_setreg(bas, REG_DATA, 0);
+ uart_barrier(bas);
+ count++;
+
+ limit = 30;
+ while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit)
+ DELAY(delay);
+ if (limit == 0) {
+ uart_setreg(bas, REG_IER, 0);
+ uart_setreg(bas, REG_MCR, mcr);
+ uart_setreg(bas, REG_FCR, 0);
+ uart_barrier(bas);
+ count = 0;
+ goto describe;
+ }
+ }
+
+ uart_setreg(bas, REG_IER, 0);
+ uart_setreg(bas, REG_MCR, mcr);
+
+ /* Reset FIFOs. */
+ ns8250_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);
+
+ describe:
+ if (count >= 14 && count < 16) {
+ sc->sc_rxfifosz = 16;
+ device_set_desc(sc->sc_dev, "16550 or compatible");
+ } else if (count >= 28 && count < 32) {
+ sc->sc_rxfifosz = 32;
+ device_set_desc(sc->sc_dev, "16650 or compatible");
+ } else if (count >= 56 && count < 64) {
+ sc->sc_rxfifosz = 64;
+ device_set_desc(sc->sc_dev, "16750 or compatible");
+ } else if (count >= 112 && count < 128) {
+ sc->sc_rxfifosz = 128;
+ device_set_desc(sc->sc_dev, "16950 or compatible");
+ } else {
+ sc->sc_rxfifosz = 1;
+ device_set_desc(sc->sc_dev,
+ "Non-standard ns8250 class UART with FIFOs");
+ }
+
+ /*
+ * Force the Tx FIFO size to 16 bytes for now. We don't program the
+ * Tx trigger. Also, we assume that all data has been sent when the
+ * interrupt happens.
+ */
+ sc->sc_txfifosz = 16;
+
+ return (0);
+}
+
+static int
+ns8250_bus_receive(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int xc;
+ uint8_t lsr;
+
+ bas = &sc->sc_bas;
+ while (!uart_rx_full(sc)) {
+ lsr = uart_getreg(bas, REG_LSR);
+ if ((lsr & LSR_RXRDY) == 0)
+ break;
+ xc = uart_getreg(bas, REG_DATA);
+ if (lsr & LSR_FE)
+ xc |= UART_STAT_FRAMERR;
+ if (lsr & LSR_PE)
+ xc |= UART_STAT_PARERR;
+ uart_rx_put(sc, xc);
+ }
+ return (0);
+}
+
+static int
+ns8250_bus_setsig(struct uart_softc *sc, int sig)
+{
+ struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
+ struct uart_bas *bas;
+ uint32_t new, old;
+
+ bas = &sc->sc_bas;
+ do {
+ old = sc->sc_hwsig;
+ new = old;
+ if (sig & UART_SIG_DDTR) {
+ SIGCHG(sig & UART_SIG_DTR, new, UART_SIG_DTR,
+ UART_SIG_DDTR);
+ }
+ if (sig & UART_SIG_DRTS) {
+ SIGCHG(sig & UART_SIG_RTS, new, UART_SIG_RTS,
+ UART_SIG_DRTS);
+ }
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+ ns8250->mcr &= ~(MCR_DTR|MCR_RTS);
+ if (new & UART_SIG_DTR)
+ ns8250->mcr |= MCR_DTR;
+ if (new & UART_SIG_RTS)
+ ns8250->mcr |= MCR_RTS;
+ uart_setreg(bas, REG_MCR, ns8250->mcr);
+ uart_barrier(bas);
+ return (0);
+}
+
+static int
+ns8250_bus_transmit(struct uart_softc *sc)
+{
+ struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
+ struct uart_bas *bas;
+ int i;
+
+ bas = &sc->sc_bas;
+ while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0)
+ ;
+ uart_setreg(bas, REG_IER, ns8250->ier | IER_ETXRDY);
+ uart_barrier(bas);
+ for (i = 0; i < sc->sc_txdatasz; i++) {
+ uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]);
+ uart_barrier(bas);
+ }
+ sc->sc_txbusy = 1;
+ return (0);
+}
diff --git a/sys/dev/uart/uart_dev_ns8250.h b/sys/dev/uart/uart_dev_ns8250.h
new file mode 100644
index 0000000..85c4722
--- /dev/null
+++ b/sys/dev/uart/uart_dev_ns8250.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_UART_DEV_NS8250_H_
+#define _DEV_UART_DEV_NS8250_H_
+
+/* Enhanced Feature Register. */
+#define EFR_CTS 0x80
+#define EFR_RTS 0x40
+#define EFR_SCD 0x20 /* Special Character Detect. */
+#define EFR_EFC 0x10 /* Enhanced Function Control. */
+#define EFR_SFC_MASK 0x0f /* Software Flow Control. */
+#define EFR_SFC_TX12 0x0c /* BIT: Transmit XON1+2/XOFF1+2. */
+#define EFR_SFC_TX1 0x08 /* BIT: Transmit XON1/XOFF1. */
+#define EFR_SFC_TX2 0x04 /* BIT: Transmit XON2/XOFF2. */
+#define EFR_SFC_RX1 0x02 /* BIT: Receive XON1/XOFF1. */
+#define EFR_SFC_RX2 0x01 /* BIT: Receive XON2/XOFF2. */
+#define EFR_SFC_T12R12 0x0f /* VAL: TX 1+2, RX 1+2. */
+#define EFR_SFC_T1R12 0x0b /* VAL: TX 1, RX 1+2. */
+#define EFR_SFC_T2R12 0x07 /* VAL: TX 2, RX 1+2. */
+
+/* FIFO Control Register. */
+#define FCR_RX_HIGH 0xc0
+#define FCR_RX_MEDH 0x80
+#define FCR_RX_MEDL 0x40
+#define FCR_RX_LOW 0x00
+#define FCR_TX_HIGH 0x30
+#define FCR_TX_MEDH 0x20
+#define FCR_TX_LOW 0x10
+#define FCR_TX_MEDL 0x00
+#define FCR_DMA 0x08
+#define FCR_XMT_RST 0x04
+#define FCR_RCV_RST 0x02
+#define FCR_ENABLE 0x01
+
+/* Interrupt Enable Register. */
+#define IER_CTS 0x80
+#define IER_RTS 0x40
+#define IER_XOFF 0x20
+#define IER_SLEEP 0x10
+#define IER_EMSC 0x08
+#define IER_ERLS 0x04
+#define IER_ETXRDY 0x02
+#define IER_ERXRDY 0x01
+
+/* Interrupt Identification Register. */
+#define IIR_FIFO_MASK 0xc0
+#define IIR_RTSCTS 0x20
+#define IIR_XOFF 0x10
+#define IIR_IMASK 0x0f
+#define IIR_RXTOUT 0x0c
+#define IIR_RLS 0x06
+#define IIR_RXRDY 0x04
+#define IIR_TXRDY 0x02
+#define IIR_MLSC 0x00
+#define IIR_NOPEND 0x01
+
+/* Line Control Register. */
+#define LCR_DLAB 0x80
+#define LCR_SBREAK 0x40
+#define LCR_PZERO 0x30
+#define LCR_PONE 0x20
+#define LCR_PEVEN 0x10
+#define LCR_PODD 0x00
+#define LCR_PENAB 0x08
+#define LCR_STOPB 0x04
+#define LCR_8BITS 0x03
+#define LCR_7BITS 0x02
+#define LCR_6BITS 0x01
+#define LCR_5BITS 0x00
+
+/* Line Status Register. */
+#define LSR_DERR 0x80
+#define LSR_TEMT 0x40 /* Transmitter Empty. */
+#define LSR_THRE 0x20 /* Transmitter Holding Register Empty. */
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+
+/* Modem Control Register. */
+#define MCR_CS 0x80
+#define MCR_IRE 0x40
+#define MCR_ISEL 0x20
+#define MCR_LOOPBACK 0x10
+#define MCR_IE 0x08
+#define MCR_LBDCD MCR_IE
+#define MCR_LBRI 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* Modem Status Register. */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+/* General registers. */
+#define REG_DATA 0 /* Data Register. */
+#define REG_RBR REG_DATA /* Receiver Buffer Register (R). */
+#define REG_THR REG_DATA /* Transmitter Holding Register (W). */
+#define REG_IER 1 /* Interrupt Enable Register */
+#define REG_IIR 2 /* Interrupt Ident. Register (R). */
+#define REG_FCR 2 /* FIFO Control Register (W). */
+#define REG_LCR 3 /* Line Control Register. */
+#define REG_MCR 4 /* Modem Control Register. */
+#define REG_LSR 5 /* Line Status Register. */
+#define REG_MSR 6 /* Modem Status Register. */
+#define REG_SPR 7 /* Scratch Pad Register. */
+
+/* Baudrate registers (LCR[7] = 1). */
+#define REG_DLBL 0 /* Divisor Latch (LSB). */
+#define REG_DLBH 1 /* Divisor Latch (MSB). */
+#define REG_DL REG_DLBL /* Divisor Latch (16-bit I/O). */
+
+/* Enhanced registers (LCR = 0xBF). */
+#define REG_EFR 2 /* Enhanced Feature Register. */
+#define REG_XON1 4 /* XON character 1. */
+#define REG_XON2 5 /* XON character 2. */
+#define REG_XOFF1 6 /* XOFF character 1. */
+#define REG_XOFF2 7 /* XOFF character 2. */
+
+#endif /* _DEV_UART_DEV_NS8250_H_ */
diff --git a/sys/dev/uart/uart_dev_sab82532.c b/sys/dev/uart/uart_dev_sab82532.c
new file mode 100644
index 0000000..b7ca2e4
--- /dev/null
+++ b/sys/dev/uart/uart_dev_sab82532.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_dev_sab82532.h>
+
+#include "uart_if.h"
+
+#define DEFAULT_RCLK 29491200
+
+#define IS_CHANNEL_A(bas) (((bas)->bsh & 0x40) == 0x00)
+#define IS_CHANNEL_B(bas) (((bas)->bsh & 0x40) == 0x40)
+
+/*
+ * NOTE: To allow us to read the baudrate divisor from the chip, we
+ * copy the value written to the write-only BGR register to an unused
+ * read-write register. We use TCR for that.
+ */
+
+static int
+sab82532_delay(struct uart_bas *bas)
+{
+ int divisor, m, n;
+ uint8_t bgr, ccr2;
+
+ bgr = uart_getreg(bas, SAB_TCR);
+ ccr2 = uart_getreg(bas, SAB_CCR2);
+ n = (bgr & 0x3f) + 1;
+ m = (bgr >> 6) | ((ccr2 >> 4) & 0xC);
+ divisor = n * (1<<m);
+
+ /* 1/10th the time to transmit 1 character (estimate). */
+ return (16000000 * divisor / bas->rclk);
+}
+
+static int
+sab82532_divisor(int rclk, int baudrate)
+{
+ int act_baud, act_div, divisor;
+ int error, m, n;
+
+ if (baudrate == 0)
+ return (0);
+
+ divisor = (rclk / (baudrate << 3) + 1) >> 1;
+ if (divisor < 2 || divisor >= 1048576)
+ return (0);
+
+ /* Find the best (N+1,M) pair. */
+ for (m = 1; m < 15; m++) {
+ n = divisor / (1<<m);
+ if (n < 1 || n > 63)
+ continue;
+ act_div = n * (1<<m);
+ act_baud = rclk / (act_div << 4);
+
+ /* 10 times error in percent: */
+ error = ((act_baud - baudrate) * 2000 / baudrate + 1) >> 1;
+
+ /* 3.0% maximum error tolerance: */
+ if (error < -30 || error > 30)
+ continue;
+
+ /* Got it. */
+ return ((n - 1) | (m << 6));
+ }
+
+ return (0);
+}
+
+static void
+sab82532_flush(struct uart_bas *bas, int what)
+{
+
+ if (what & UART_FLUSH_TRANSMITTER) {
+ while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
+ ;
+ uart_setreg(bas, SAB_CMDR, SAB_CMDR_XRES);
+ uart_barrier(bas);
+ }
+ if (what & UART_FLUSH_RECEIVER) {
+ while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
+ ;
+ uart_setreg(bas, SAB_CMDR, SAB_CMDR_RRES);
+ uart_barrier(bas);
+ }
+}
+
+static int
+sab82532_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+ int divisor;
+ uint8_t ccr2, dafo;
+
+ if (databits >= 8)
+ dafo = SAB_DAFO_CHL_CS8;
+ else if (databits == 7)
+ dafo = SAB_DAFO_CHL_CS7;
+ else if (databits == 6)
+ dafo = SAB_DAFO_CHL_CS6;
+ else
+ dafo = SAB_DAFO_CHL_CS5;
+ if (stopbits > 1)
+ dafo |= SAB_DAFO_STOP;
+ switch (parity) {
+ case UART_PARITY_EVEN: dafo |= SAB_DAFO_PAR_EVEN; break;
+ case UART_PARITY_MARK: dafo |= SAB_DAFO_PAR_MARK; break;
+ case UART_PARITY_NONE: dafo |= SAB_DAFO_PAR_NONE; break;
+ case UART_PARITY_ODD: dafo |= SAB_DAFO_PAR_ODD; break;
+ case UART_PARITY_SPACE: dafo |= SAB_DAFO_PAR_SPACE; break;
+ default: return (EINVAL);
+ }
+
+ /* Set baudrate. */
+ if (baudrate > 0) {
+ divisor = sab82532_divisor(bas->rclk, baudrate);
+ if (divisor == 0)
+ return (EINVAL);
+ uart_setreg(bas, SAB_BGR, divisor & 0xff);
+ uart_barrier(bas);
+ /* Allow reading the (n-1,m) tuple from the chip. */
+ uart_setreg(bas, SAB_TCR, divisor & 0xff);
+ uart_barrier(bas);
+ ccr2 = uart_getreg(bas, SAB_CCR2);
+ ccr2 &= ~(SAB_CCR2_BR9 | SAB_CCR2_BR8);
+ ccr2 |= (divisor >> 2) & (SAB_CCR2_BR9 | SAB_CCR2_BR8);
+ uart_setreg(bas, SAB_CCR2, ccr2);
+ uart_barrier(bas);
+ }
+
+ uart_setreg(bas, SAB_DAFO, dafo);
+ uart_barrier(bas);
+ return (0);
+}
+
+/*
+ * Low-level UART interface.
+ */
+static int sab82532_probe(struct uart_bas *bas);
+static void sab82532_init(struct uart_bas *bas, int, int, int, int);
+static void sab82532_term(struct uart_bas *bas);
+static void sab82532_putc(struct uart_bas *bas, int);
+static int sab82532_poll(struct uart_bas *bas);
+static int sab82532_getc(struct uart_bas *bas);
+
+struct uart_ops uart_sab82532_ops = {
+ .probe = sab82532_probe,
+ .init = sab82532_init,
+ .term = sab82532_term,
+ .putc = sab82532_putc,
+ .poll = sab82532_poll,
+ .getc = sab82532_getc,
+};
+
+static int
+sab82532_probe(struct uart_bas *bas)
+{
+
+ return (0);
+}
+
+static void
+sab82532_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+ uint8_t ccr0, pvr;
+
+ if (bas->rclk == 0)
+ bas->rclk = DEFAULT_RCLK;
+
+ /*
+ * Set all pins, except the DTR pins (pin 1 and 2) to be inputs.
+ * Pin 4 is magical, meaning that I don't know what it does, but
+ * it too has to be set to output.
+ */
+ uart_setreg(bas, SAB_PCR,
+ ~(SAB_PVR_DTR_A|SAB_PVR_DTR_B|SAB_PVR_MAGIC));
+ uart_barrier(bas);
+ /* Disable port interrupts. */
+ uart_setreg(bas, SAB_PIM, 0xff);
+ uart_barrier(bas);
+ /* Interrupts are active low. */
+ uart_setreg(bas, SAB_IPC, SAB_IPC_ICPL);
+ uart_barrier(bas);
+ /* Set DTR. */
+ pvr = uart_getreg(bas, SAB_PVR);
+ pvr &= IS_CHANNEL_A(bas) ? ~SAB_PVR_DTR_A : ~SAB_PVR_DTR_B;
+ uart_setreg(bas, SAB_PVR, pvr | SAB_PVR_MAGIC);
+ uart_barrier(bas);
+
+ /* power down */
+ uart_setreg(bas, SAB_CCR0, 0);
+ uart_barrier(bas);
+
+ /* set basic configuration */
+ ccr0 = SAB_CCR0_MCE|SAB_CCR0_SC_NRZ|SAB_CCR0_SM_ASYNC;
+ uart_setreg(bas, SAB_CCR0, ccr0);
+ uart_barrier(bas);
+ uart_setreg(bas, SAB_CCR1, SAB_CCR1_ODS|SAB_CCR1_BCR|SAB_CCR1_CM_7);
+ uart_barrier(bas);
+ uart_setreg(bas, SAB_CCR2, SAB_CCR2_BDF|SAB_CCR2_SSEL|SAB_CCR2_TOE);
+ uart_barrier(bas);
+ uart_setreg(bas, SAB_CCR3, 0);
+ uart_barrier(bas);
+ uart_setreg(bas, SAB_CCR4, SAB_CCR4_MCK4|SAB_CCR4_EBRG|SAB_CCR4_ICD);
+ uart_barrier(bas);
+ uart_setreg(bas, SAB_MODE, SAB_MODE_FCTS|SAB_MODE_RTS|SAB_MODE_RAC);
+ uart_barrier(bas);
+ uart_setreg(bas, SAB_RFC, SAB_RFC_DPS|SAB_RFC_RFDF|
+ SAB_RFC_RFTH_32CHAR);
+ uart_barrier(bas);
+
+ sab82532_param(bas, baudrate, databits, stopbits, parity);
+
+ /* Clear interrupts. */
+ uart_setreg(bas, SAB_IMR0, 0xff);
+ uart_setreg(bas, SAB_IMR1, 0xff);
+ uart_barrier(bas);
+ uart_getreg(bas, SAB_ISR0);
+ uart_getreg(bas, SAB_ISR1);
+ uart_barrier(bas);
+
+ sab82532_flush(bas, UART_FLUSH_TRANSMITTER|UART_FLUSH_RECEIVER);
+
+ /* Power up. */
+ uart_setreg(bas, SAB_CCR0, ccr0|SAB_CCR0_PU);
+ uart_barrier(bas);
+}
+
+static void
+sab82532_term(struct uart_bas *bas)
+{
+ uint8_t pvr;
+
+ pvr = uart_getreg(bas, SAB_PVR);
+ pvr |= IS_CHANNEL_A(bas) ? SAB_PVR_DTR_A : SAB_PVR_DTR_B;
+ uart_setreg(bas, SAB_PVR, pvr);
+ uart_barrier(bas);
+}
+
+static void
+sab82532_putc(struct uart_bas *bas, int c)
+{
+ int delay, limit;
+
+ /* 1/10th the time to transmit 1 character (estimate). */
+ delay = sab82532_delay(bas);
+
+ limit = 20;
+ while ((uart_getreg(bas, SAB_STAR) & SAB_STAR_TEC) && --limit)
+ DELAY(delay);
+ uart_setreg(bas, SAB_TIC, c);
+ limit = 20;
+ while ((uart_getreg(bas, SAB_STAR) & SAB_STAR_TEC) && --limit)
+ DELAY(delay);
+}
+
+static int
+sab82532_poll(struct uart_bas *bas)
+{
+
+ if (uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE)
+ return (sab82532_getc(bas));
+ return (-1);
+}
+
+static int
+sab82532_getc(struct uart_bas *bas)
+{
+ int c, delay;
+
+ /* 1/10th the time to transmit 1 character (estimate). */
+ delay = sab82532_delay(bas);
+
+ while (!(uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE))
+ DELAY(delay);
+
+ while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
+ ;
+ uart_setreg(bas, SAB_CMDR, SAB_CMDR_RFRD);
+ uart_barrier(bas);
+
+ while (!(uart_getreg(bas, SAB_ISR0) & SAB_ISR0_TCD))
+ DELAY(delay);
+
+ c = uart_getreg(bas, SAB_RFIFO);
+ uart_barrier(bas);
+
+ /* Blow away everything left in the FIFO... */
+ while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
+ ;
+ uart_setreg(bas, SAB_CMDR, SAB_CMDR_RMC);
+ uart_barrier(bas);
+ return (c);
+}
+
+/*
+ * High-level UART interface.
+ */
+struct sab82532_softc {
+ struct uart_softc base;
+};
+
+static int sab82532_bus_attach(struct uart_softc *);
+static int sab82532_bus_detach(struct uart_softc *);
+static int sab82532_bus_flush(struct uart_softc *, int);
+static int sab82532_bus_getsig(struct uart_softc *);
+static int sab82532_bus_ioctl(struct uart_softc *, int, intptr_t);
+static int sab82532_bus_ipend(struct uart_softc *);
+static int sab82532_bus_param(struct uart_softc *, int, int, int, int);
+static int sab82532_bus_probe(struct uart_softc *);
+static int sab82532_bus_receive(struct uart_softc *);
+static int sab82532_bus_setsig(struct uart_softc *, int);
+static int sab82532_bus_transmit(struct uart_softc *);
+
+static kobj_method_t sab82532_methods[] = {
+ KOBJMETHOD(uart_attach, sab82532_bus_attach),
+ KOBJMETHOD(uart_detach, sab82532_bus_detach),
+ KOBJMETHOD(uart_flush, sab82532_bus_flush),
+ KOBJMETHOD(uart_getsig, sab82532_bus_getsig),
+ KOBJMETHOD(uart_ioctl, sab82532_bus_ioctl),
+ KOBJMETHOD(uart_ipend, sab82532_bus_ipend),
+ KOBJMETHOD(uart_param, sab82532_bus_param),
+ KOBJMETHOD(uart_probe, sab82532_bus_probe),
+ KOBJMETHOD(uart_receive, sab82532_bus_receive),
+ KOBJMETHOD(uart_setsig, sab82532_bus_setsig),
+ KOBJMETHOD(uart_transmit, sab82532_bus_transmit),
+ { 0, 0 }
+};
+
+struct uart_class uart_sab82532_class = {
+ "sab82532 class",
+ sab82532_methods,
+ sizeof(struct sab82532_softc),
+ .uc_range = 64,
+ .uc_rclk = DEFAULT_RCLK
+};
+
+#define SIGCHG(c, i, s, d) \
+ if (c) { \
+ i |= (i & s) ? s : s | d; \
+ } else { \
+ i = (i & s) ? (i & ~s) | d : i; \
+ }
+
+static int
+sab82532_bus_attach(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ uint8_t imr0, imr1;
+
+ bas = &sc->sc_bas;
+ if (sc->sc_sysdev == NULL)
+ sab82532_init(bas, 9600, 8, 1, UART_PARITY_NONE);
+
+ sc->sc_rxfifosz = 32;
+ sc->sc_txfifosz = 32;
+
+ imr0 = SAB_IMR0_TCD|SAB_IMR0_TIME|SAB_IMR0_CDSC|SAB_IMR0_RFO|
+ SAB_IMR0_RPF;
+ uart_setreg(bas, SAB_IMR0, 0xff & ~imr0);
+ imr1 = SAB_IMR1_BRKT|SAB_IMR1_ALLS|SAB_IMR1_CSC;
+ uart_setreg(bas, SAB_IMR1, 0xff & ~imr1);
+ uart_barrier(bas);
+
+ if (sc->sc_sysdev == NULL)
+ sab82532_bus_setsig(sc, UART_SIG_DDTR|UART_SIG_DRTS);
+ (void)sab82532_bus_getsig(sc);
+ return (0);
+}
+
+static int
+sab82532_bus_detach(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+
+ bas = &sc->sc_bas;
+ uart_setreg(bas, SAB_IMR0, 0xff);
+ uart_setreg(bas, SAB_IMR1, 0xff);
+ uart_barrier(bas);
+ uart_getreg(bas, SAB_ISR0);
+ uart_getreg(bas, SAB_ISR1);
+ uart_barrier(bas);
+ uart_setreg(bas, SAB_CCR0, 0);
+ uart_barrier(bas);
+ return (0);
+}
+
+static int
+sab82532_bus_flush(struct uart_softc *sc, int what)
+{
+
+ sab82532_flush(&sc->sc_bas, what);
+ return (0);
+}
+
+static int
+sab82532_bus_getsig(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ uint32_t new, old, sig;
+ uint8_t pvr, star, vstr;
+
+ bas = &sc->sc_bas;
+ do {
+ old = sc->sc_hwsig;
+ sig = old;
+ star = uart_getreg(bas, SAB_STAR);
+ SIGCHG(star & SAB_STAR_CTS, sig, UART_SIG_CTS, UART_SIG_DCTS);
+ vstr = uart_getreg(bas, SAB_VSTR);
+ SIGCHG(vstr & SAB_VSTR_CD, sig, UART_SIG_DCD, UART_SIG_DDCD);
+ pvr = uart_getreg(bas, SAB_PVR);
+ pvr &= (IS_CHANNEL_A(bas)) ? SAB_PVR_DSR_A : SAB_PVR_DSR_B;
+ SIGCHG(~pvr, sig, UART_SIG_DSR, UART_SIG_DDSR);
+ new = sig & ~UART_SIGMASK_DELTA;
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+ return (sig);
+}
+
+static int
+sab82532_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
+{
+ struct uart_bas *bas;
+ uint8_t dafo, mode;
+
+ bas = &sc->sc_bas;
+ switch (request) {
+ case UART_IOCTL_BREAK:
+ dafo = uart_getreg(bas, SAB_DAFO);
+ if (data)
+ dafo |= SAB_DAFO_XBRK;
+ else
+ dafo &= ~SAB_DAFO_XBRK;
+ uart_setreg(bas, SAB_DAFO, dafo);
+ uart_barrier(bas);
+ break;
+ case UART_IOCTL_IFLOW:
+ mode = uart_getreg(bas, SAB_MODE);
+ if (data) {
+ mode &= ~SAB_MODE_RTS;
+ mode |= SAB_MODE_FRTS;
+ } else {
+ mode |= SAB_MODE_RTS;
+ mode &= ~SAB_MODE_FRTS;
+ }
+ uart_setreg(bas, SAB_MODE, mode);
+ uart_barrier(bas);
+ break;
+ case UART_IOCTL_OFLOW:
+ mode = uart_getreg(bas, SAB_MODE);
+ if (data)
+ mode &= ~SAB_MODE_FCTS;
+ else
+ mode |= SAB_MODE_FCTS;
+ uart_setreg(bas, SAB_MODE, mode);
+ uart_barrier(bas);
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+sab82532_bus_ipend(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int ipend;
+ uint8_t isr0, isr1;
+
+ bas = &sc->sc_bas;
+ isr0 = uart_getreg(bas, SAB_ISR0);
+ isr1 = uart_getreg(bas, SAB_ISR1);
+ uart_barrier(bas);
+
+ if (isr0 & SAB_ISR0_TIME) {
+ while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
+ ;
+ uart_setreg(bas, SAB_CMDR, SAB_CMDR_RFRD);
+ uart_barrier(bas);
+ }
+
+ ipend = 0;
+ if (isr1 & SAB_ISR1_BRKT)
+ ipend |= UART_IPEND_BREAK;
+ if (isr0 & SAB_ISR0_RFO)
+ ipend |= UART_IPEND_OVERRUN;
+ if (isr0 & (SAB_ISR0_TCD|SAB_ISR0_RPF))
+ ipend |= UART_IPEND_RXREADY;
+ if ((isr0 & SAB_ISR0_CDSC) || (isr1 & SAB_ISR1_CSC))
+ ipend |= UART_IPEND_SIGCHG;
+ if (isr1 & SAB_ISR1_ALLS)
+ ipend |= UART_IPEND_TXIDLE;
+
+ return (ipend);
+}
+
+static int
+sab82532_bus_param(struct uart_softc *sc, int baudrate, int databits,
+ int stopbits, int parity)
+{
+ struct uart_bas *bas;
+
+ bas = &sc->sc_bas;
+ return (sab82532_param(bas, baudrate, databits, stopbits, parity));
+}
+
+static int
+sab82532_bus_probe(struct uart_softc *sc)
+{
+ char buf[80];
+ const char *ch, *vstr;
+ int error;
+
+ error = sab82532_probe(&sc->sc_bas);
+ if (error)
+ return (error);
+
+ /* Assume the address range is naturally aligned. */
+ ch = IS_CHANNEL_A(&sc->sc_bas) ? "A" : "B";
+
+ switch (uart_getreg(&sc->sc_bas, SAB_VSTR) & SAB_VSTR_VMASK) {
+ case SAB_VSTR_V_1:
+ vstr = "v1";
+ break;
+ case SAB_VSTR_V_2:
+ vstr = "v2";
+ break;
+ case SAB_VSTR_V_32:
+ vstr = "v3.2";
+ sc->sc_hwiflow = 0; /* CTS doesn't work with RFC:RFDF. */
+ sc->sc_hwoflow = 1;
+ break;
+ default:
+ vstr = "v4?";
+ break;
+ }
+
+ snprintf(buf, sizeof(buf), "SAB 82532 %s, channel %s", vstr, ch);
+ device_set_desc_copy(sc->sc_dev, buf);
+ return (0);
+}
+
+static int
+sab82532_bus_receive(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int i, rbcl, xc;
+ uint8_t s;
+
+ bas = &sc->sc_bas;
+ if (uart_getreg(bas, SAB_STAR) & SAB_STAR_RFNE) {
+ rbcl = uart_getreg(bas, SAB_RBCL) & 31;
+ if (rbcl == 0)
+ rbcl = 32;
+ for (i = 0; i < rbcl; i += 2) {
+ if (uart_rx_full(sc)) {
+ sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
+ break;
+ }
+ xc = uart_getreg(bas, SAB_RFIFO);
+ s = uart_getreg(bas, SAB_RFIFO + 1);
+ if (s & SAB_RSTAT_FE)
+ xc |= UART_STAT_FRAMERR;
+ if (s & SAB_RSTAT_PE)
+ xc |= UART_STAT_PARERR;
+ uart_rx_put(sc, xc);
+ }
+ }
+
+ while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
+ ;
+ uart_setreg(bas, SAB_CMDR, SAB_CMDR_RMC);
+ uart_barrier(bas);
+ return (0);
+}
+
+static int
+sab82532_bus_setsig(struct uart_softc *sc, int sig)
+{
+ struct uart_bas *bas;
+ uint32_t new, old;
+ uint8_t mode, pvr;
+
+ bas = &sc->sc_bas;
+ do {
+ old = sc->sc_hwsig;
+ new = old;
+ if (sig & UART_SIG_DDTR) {
+ SIGCHG(sig & UART_SIG_DTR, new, UART_SIG_DTR,
+ UART_SIG_DDTR);
+ }
+ if (sig & UART_SIG_DRTS) {
+ SIGCHG(sig & UART_SIG_RTS, new, UART_SIG_RTS,
+ UART_SIG_DRTS);
+ }
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+
+ /* Set DTR pin. */
+ pvr = uart_getreg(bas, SAB_PVR);
+ if (new & UART_SIG_DTR)
+ pvr &= (IS_CHANNEL_A(bas)) ? ~SAB_PVR_DTR_A : ~SAB_PVR_DTR_B;
+ else
+ pvr |= (IS_CHANNEL_A(bas)) ? SAB_PVR_DTR_A : SAB_PVR_DTR_B;
+ uart_setreg(bas, SAB_PVR, pvr);
+
+ /* Set RTS pin. */
+ mode = uart_getreg(bas, SAB_MODE);
+ if (new & UART_SIG_RTS)
+ mode &= ~SAB_MODE_FRTS;
+ else
+ mode |= SAB_MODE_FRTS;
+ uart_setreg(bas, SAB_MODE, mode);
+ uart_barrier(bas);
+ return (0);
+}
+
+static int
+sab82532_bus_transmit(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int i;
+
+ bas = &sc->sc_bas;
+ while (!(uart_getreg(bas, SAB_STAR) & SAB_STAR_XFW))
+ ;
+ for (i = 0; i < sc->sc_txdatasz; i++)
+ uart_setreg(bas, SAB_XFIFO + i, sc->sc_txbuf[i]);
+ uart_barrier(bas);
+ while (uart_getreg(bas, SAB_STAR) & SAB_STAR_CEC)
+ ;
+ uart_setreg(bas, SAB_CMDR, SAB_CMDR_XF);
+ sc->sc_txbusy = 1;
+ return (0);
+}
diff --git a/sys/dev/uart/uart_dev_sab82532.h b/sys/dev/uart/uart_dev_sab82532.h
new file mode 100644
index 0000000..8b53371
--- /dev/null
+++ b/sys/dev/uart/uart_dev_sab82532.h
@@ -0,0 +1,320 @@
+/* $OpenBSD: sab82532reg.h,v 1.2 2002/04/08 17:49:42 jason Exp $ */
+
+/*
+ * Copyright (c) 2001 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Register definitions for SAB82532 based on "Enhanced Serial Communication
+ * Controller ESCC2 Version 3.2 User's Manual 07.96" from:
+ * http://www.infineon.com
+ */
+
+#define SAB_NCHAN 2 /* number of channels */
+#define SAB_CHANLEN 0x40 /* length of channel register set */
+
+#define SAB_CHAN_A 0x00 /* channel A register offset */
+#define SAB_CHAN_B 0x40 /* channel B register offset */
+
+#define SAB_RFIFO 0x00 /* r: rx fifo */
+#define SAB_XFIFO 0x00 /* w: tx fifo */
+#define SAB_STAR 0x20 /* r: status register */
+#define SAB_CMDR 0x20 /* w: command register */
+#define SAB_MODE 0x22 /* rw: mode register */
+#define SAB_TIMR 0x23 /* rw: timer register */
+#define SAB_XON 0x24 /* rw: xon character */
+#define SAB_XOFF 0x25 /* rw: xoff character */
+#define SAB_TCR 0x26 /* rw: termination character */
+#define SAB_DAFO 0x27 /* rw: data format */
+#define SAB_RFC 0x28 /* rw: rfifo control register */
+#define SAB_RBCL 0x2a /* r: rx byte count low */
+#define SAB_TBCL 0x2a /* w: tx byte count low */
+#define SAB_RBCH 0x2b /* r: rx byte count high */
+#define SAB_XBCH 0x2b /* w: tx byte count high */
+#define SAB_CCR0 0x2c /* rw: channel configuration register 0 */
+#define SAB_CCR1 0x2d /* rw: channel configuration register 1 */
+#define SAB_CCR2 0x2e /* rw: channel configuration register 2 */
+#define SAB_CCR3 0x2f /* rw: channel configuration register 3 */
+#define SAB_TSAX 0x30 /* w: time-slot assignment register tx */
+#define SAB_TSAR 0x31 /* w: time-slot assignment register rx */
+#define SAB_XCCR 0x32 /* w: tx channel capacity register */
+#define SAB_RCCR 0x33 /* w: receive channel capacity register */
+#define SAB_VSTR 0x34 /* r: version status */
+#define SAB_BGR 0x34 /* w: baud rate generator */
+#define SAB_TIC 0x35 /* w: transmit immediate character */
+#define SAB_MXN 0x36 /* w: mask xon character */
+#define SAB_MXF 0x37 /* w: mask xoff character */
+#define SAB_GIS 0x38 /* r: global interrupt status */
+#define SAB_IVA 0x38 /* w: interrupt vector address */
+#define SAB_IPC 0x39 /* rw: interrupt port configuration */
+#define SAB_ISR0 0x3a /* r: interrupt status 0 */
+#define SAB_IMR0 0x3a /* w: interrupt mask 0 */
+#define SAB_ISR1 0x3b /* r: interrupt status 1 */
+#define SAB_IMR1 0x3b /* w: interrupt mask 1 */
+#define SAB_PVR 0x3c /* rw: port value register */
+#define SAB_PIS 0x3d /* r: port interrupt status */
+#define SAB_PIM 0x3d /* w: port interrupt mask */
+#define SAB_PCR 0x3e /* w: port configuration register */
+#define SAB_CCR4 0x3f /* rw: channel configuration register 4 */
+
+/* SAB_STAR: status register */
+#define SAB_STAR_XDOV 0x80 /* transmit data overflow */
+#define SAB_STAR_XFW 0x40 /* transmit fifo write enable */
+#define SAB_STAR_RFNE 0x20 /* rfifo not empty */
+#define SAB_STAR_FCS 0x10 /* flow control status */
+#define SAB_STAR_TEC 0x08 /* tx immediate char is executing */
+#define SAB_STAR_CEC 0x04 /* command is executing */
+#define SAB_STAR_CTS 0x02 /* cts status: 0:inactive/high,1:active/low */
+
+/* SAB_CMDR: command register */
+#define SAB_CMDR_RMC 0x80 /* receive message complete */
+#define SAB_CMDR_RRES 0x40 /* receiver reset */
+#define SAB_CMDR_RFRD 0x20 /* receive fifo read enable */
+#define SAB_CMDR_STI 0x10 /* start timer */
+#define SAB_CMDR_XF 0x08 /* transmit frame */
+#define SAB_CMDR_XRES 0x01 /* transmit reset */
+
+/* SAB_MODE: mode register */
+#define SAB_MODE_FRTS 0x40 /* flow control using rts */
+#define SAB_MODE_FCTS 0x20 /* flow control using cts */
+#define SAB_MODE_FLON 0x10 /* flow control on */
+#define SAB_MODE_RAC 0x08 /* receiver active */
+#define SAB_MODE_RTS 0x04 /* request to send */
+#define SAB_MODE_TRS 0x02 /* timer resolution */
+#define SAB_MODE_TLP 0x01 /* test loop */
+
+/* SAB_TIMR: timer register */
+#define SAB_TIMR_CNT 0xe0 /* count mask */
+#define SAB_TIMR_VAL 0x1f /* value mask */
+
+/* SAB_DAFO: data format */
+#define SAB_DAFO_XBRK 0x40 /* transmit break */
+#define SAB_DAFO_STOP 0x20 /* stop bit: 0:1 bit, 1:2 bits */
+#define SAB_DAFO_PAR1 0x10 /* parity 1, see below */
+#define SAB_DAFO_PAR0 0x08 /* parity 0, see below */
+#define SAB_DAFO_PARE 0x04 /* parity enable */
+#define SAB_DAFO_CHL1 0x02 /* character length 1, see below */
+#define SAB_DAFO_CHL0 0x01 /* character length 0, see below */
+
+#define SAB_DAFO_CHL_CSIZE (SAB_DAFO_CHL1|SAB_DAFO_CHL0)
+#define SAB_DAFO_CHL_CS5 (SAB_DAFO_CHL1|SAB_DAFO_CHL0)
+#define SAB_DAFO_CHL_CS6 (SAB_DAFO_CHL1)
+#define SAB_DAFO_CHL_CS7 (SAB_DAFO_CHL0)
+#define SAB_DAFO_CHL_CS8 (0)
+
+#define SAB_DAFO_PARMASK (SAB_DAFO_PAR1|SAB_DAFO_PAR0|SAB_DAFO_PARE)
+#define SAB_DAFO_PAR_MARK (SAB_DAFO_PAR1|SAB_DAFO_PAR0|SAB_DAFO_PARE)
+#define SAB_DAFO_PAR_EVEN (SAB_DAFO_PAR1|SAB_DAFO_PARE)
+#define SAB_DAFO_PAR_ODD (SAB_DAFO_PAR0|SAB_DAFO_PARE)
+#define SAB_DAFO_PAR_SPACE (SAB_DAFO_PARE)
+#define SAB_DAFO_PAR_NONE (0)
+
+/* SAB_RFC: rfifo control register */
+#define SAB_RFC_DPS 0x40 /* disable parity storage */
+#define SAB_RFC_DXS 0x20 /* disable storage of xon/xoff characters */
+#define SAB_RFC_RFDF 0x10 /* rfifo data format: 0 data,1 data+stat */
+#define SAB_RFC_RFTH1 0x08 /* rfifo threshold level 1, see below */
+#define SAB_RFC_RFTH0 0x04 /* rfifo threshold level 0, see below */
+#define SAB_RFC_TCDE 0x01 /* termination character detection enable */
+
+#define SAB_RFC_RFTH_MASK (SAB_RFC_RFTH1|SAB_RFC_RFTH0)
+#define SAB_RFC_RFTH_32CHAR (SAB_RFC_RFTH1|SAB_RFC_RFTH0)
+#define SAB_RFC_RFTH_16CHAR (SAB_RFC_RFTH1)
+#define SAB_RFC_RFTH_4CHAR (SAB_RFC_RFTH0)
+#define SAB_RFC_RFTH_1CHAR (0)
+
+/* SAB_RBCH: received byte count high */
+#define SAB_RBCH_DMA 0x80 /* read back of XBCH DMA bit */
+#define SAB_RBCH_CAS 0x20 /* read back of XBCH CAS bit */
+#define SAB_RBCH_CNT 0x0f /* ms 4 bits of rx byte count (not used) */
+
+/* SAB_XBCH: transmit byte count high */
+#define SAB_XBCH_DMA 0x80 /* dma mode: 1:dma, 0:interrupt */
+#define SAB_XBCH_CAS 0x20 /* carrier detect auto-start */
+#define SAB_XBCH_XC 0x10 /* transmit continuously */
+#define SAB_XBCH_CNT 0x0f /* ms 4 bits of tx byte count */
+
+/* SAB_CCR0: channel configuration register 0 */
+#define SAB_CCR0_PU 0x80 /* 0:power-down, 1:power-up */
+#define SAB_CCR0_MCE 0x40 /* master clock enable */
+#define SAB_CCR0_SC2 0x10 /* serial port config 2, see below */
+#define SAB_CCR0_SC1 0x08 /* serial port config 1, see below */
+#define SAB_CCR0_SC0 0x04 /* serial port config 0, see below */
+#define SAB_CCR0_SM1 0x02 /* serial mode 1, see below */
+#define SAB_CCR0_SM0 0x01 /* serial mode 0, see below */
+
+#define SAB_CCR0_SC_MASK (SAB_CCR0_SC2|SAB_CCR0_SC1|SAB_CCR0_SC0)
+#define SAB_CCR0_SC_NRZ (0)
+#define SAB_CCR0_SC_NRZI (SAB_CCR0_SC1)
+#define SAB_CCR0_SC_FM0 (SAB_CCR0_SC2)
+#define SAB_CCR0_SC_FM1 (SAB_CCR0_SC2|SAB_CCR0_SC0)
+#define SAB_CCR0_SC_MANCHESTER (SAB_CCR0_SC2|SAB_CCR0_SC1)
+
+#define SAB_CCR0_SM_MASK (SAB_CCR0_SM1|SAB_CCR0_SM0)
+#define SAB_CCR0_SM_DLC (0)
+#define SAB_CCR0_SM_DLCLOOP (SAB_CCR0_SM0)
+#define SAB_CCR0_SM_BISYNC (SAB_CCR0_SM1)
+#define SAB_CCR0_SM_ASYNC (SAB_CCR0_SM1|SAB_CCR0_SM0)
+
+/* SAB_CCR1: channel configuration register 1 */
+#define SAB_CCR1_ODS 0x10 /* Output driver select:1:pushpull,0:odrain */
+#define SAB_CCR1_BCR 0x08 /* bit clock rate: 1:async, 0:isochronous */
+#define SAB_CCR1_CM2 0x04 /* clock mode 2, see below */
+#define SAB_CCR1_CM1 0x02 /* clock mode 1, see below */
+#define SAB_CCR1_CM0 0x01 /* clock mode 0, see below */
+
+#define SAB_CCR1_CM_MASK (SAB_CCR1_CM2|SAB_CCR1_CM1|SAB_CCR1_CM0)
+#define SAB_CCR1_CM_7 (SAB_CCR1_CM2|SAB_CCR1_CM1|SAB_CCR1_CM0)
+
+/* SAB_CCR2: channel configuration register 2, depends on clock mode above */
+/* clock mode 0a, 1, 4, 5 */
+#define SAB_CCR2_SOC1 0x80 /* special output 1, below */
+#define SAB_CCR2_SOC0 0x40 /* special output 0, below */
+#define SAB_CCR2_SOC_MASK (SAB_CCR2_SOC1|SAB_CCR2_SOC0)
+#define SAB_CCR2_SOC_RTSHIGH (SAB_CCR2_SOC1)
+#define SAB_CCR2_SOC_RTSNORM (0)
+#define SAB_CCR2_SOC_RTSRX (SAB_CCR2_SOC1|SAB_CCR2_SOC0)
+/* clock mode 0b, 2, 3, 6, 7 */
+#define SAB_CCR2_BR9 0x80 /* baud rate bit 9 */
+#define SAB_CCR2_BR8 0x40 /* baud rate bit 8 */
+#define SAB_CCR2_BDF 0x20 /* baud rate division factor: 0:1: 1:BRG */
+#define SAB_CCR2_SSEL 0x10 /* clock source select */
+/* clock mode 5 */
+#define SAB_CCR2_XCS0 0x20 /* tx clock shift, bit 0 */
+#define SAB_CCR2_RCS0 0x10 /* rx clock shift, bit 0 */
+/* clock mode 0b, 2, 3, 4, 5, 6, 7 */
+#define SAB_CCR2_TOE 0x08 /* tx clock output enable */
+/* clock mode 0a, 0b, 1, 2, 3, 4, 5, 6, 7 */
+#define SAB_CCR2_RWX 0x04 /* read/write exchange (dma mode only) */
+#define SAB_CCR2_DIV 0x01 /* data inversion (nrz) */
+
+/* SAB_CCR3: channel configuration register 3 (v2 or greater) */
+#define SAB_CCR3_PSD 0x01 /* dpll phase shift disable (nrz/nrzi) */
+
+/* SAB_TSAX: time-slot assignment register transmit (clock mode 5 only) */
+#define SAB_TSAX_TSNX 0xfc /* time-slot number transmit */
+#define SAB_TSAX_XCS2 0x02 /* transmit clock shift bit 2 */
+#define SAB_TSAX_XCS1 0x01 /* transmit clock shift bit 1 */
+
+/* SAB_TSAR: time-slot assignment register receive (clock mode 5 only) */
+#define SAB_TSAR_TSNR 0xfc /* time-slot number receive */
+#define SAB_TSAR_RCS2 0x02 /* receive clock shift bit 2 */
+#define SAB_TSAR_RCS1 0x01 /* receive clock shift bit 1 */
+
+/* SAB_VSTR: version status register */
+#define SAB_VSTR_CD 0x80 /* carrier detect status */
+#define SAB_VSTR_DPLA 0x40 /* dpll asynchronous */
+#define SAB_VSTR_VMASK 0x0f /* chip version mask: */
+#define SAB_VSTR_V_1 0x00 /* version 1 */
+#define SAB_VSTR_V_2 0x01 /* version 2 */
+#define SAB_VSTR_V_32 0x02 /* version 3.2 */
+
+/* SAB_GIS: global interrupt status register */
+#define SAB_GIS_PI 0x80 /* universal port interrupt */
+#define SAB_GIS_ISA1 0x08 /* interrupt status a1 */
+#define SAB_GIS_ISA0 0x04 /* interrupt status a0 */
+#define SAB_GIS_ISB1 0x02 /* interrupt status b1 */
+#define SAB_GIS_ISB0 0x01 /* interrupt status b0 */
+
+/* SAB_IVA: interrupt vector address */
+#define SAB_IVA_MASK 0xf8 /* interrupt vector address mask */
+
+/* SAB_IPC: interrupt port configuration */
+#define SAB_IPC_VIS 0x80 /* masked interrupt bits visible */
+#define SAB_IPC_SLAMASK 0x18 /* slave address mask */
+#define SAB_IPC_CASM 0x04 /* cascading mode */
+#define SAB_IPC_ICMASK 0x03 /* port config mask: */
+#define SAB_IPC_ICOD 0x00 /* open drain output */
+#define SAB_IPC_ICPL 0x01 /* push/pull active low output */
+#define SAB_IPC_ICPH 0x03 /* push/pull active high output */
+
+/* SAB_ISR0: interrupt status 0 */
+#define SAB_ISR0_TCD 0x80 /* termination character detected */
+#define SAB_ISR0_TIME 0x40 /* time-out limit exceeded */
+#define SAB_ISR0_PERR 0x20 /* parity error */
+#define SAB_ISR0_FERR 0x10 /* framing error */
+#define SAB_ISR0_PLLA 0x08 /* dpll asynchronous */
+#define SAB_ISR0_CDSC 0x04 /* carrier detect status change */
+#define SAB_ISR0_RFO 0x02 /* rfifo overflow */
+#define SAB_ISR0_RPF 0x01 /* receive pool full */
+
+/* SAB_ISR1: interrupt status 1 */
+#define SAB_ISR1_BRK 0x80 /* break detected */
+#define SAB_ISR1_BRKT 0x40 /* break terminated */
+#define SAB_ISR1_ALLS 0x20 /* all sent */
+#define SAB_ISR1_XOFF 0x10 /* xoff detected */
+#define SAB_ISR1_TIN 0x08 /* timer interrupt */
+#define SAB_ISR1_CSC 0x04 /* clear to send status change */
+#define SAB_ISR1_XON 0x02 /* xon detected */
+#define SAB_ISR1_XPR 0x01 /* transmit pool ready */
+
+/* SAB_IMR0: interrupt mask 0 */
+#define SAB_IMR0_TCD 0x80 /* termination character detected */
+#define SAB_IMR0_TIME 0x40 /* time-out limit exceeded */
+#define SAB_IMR0_PERR 0x20 /* parity error */
+#define SAB_IMR0_FERR 0x10 /* framing error */
+#define SAB_IMR0_PLLA 0x08 /* dpll asynchronous */
+#define SAB_IMR0_CDSC 0x04 /* carrier detect status change */
+#define SAB_IMR0_RFO 0x02 /* rfifo overflow */
+#define SAB_IMR0_RPF 0x01 /* receive pool full */
+
+/* SAB_ISR1: interrupt mask 1 */
+#define SAB_IMR1_BRK 0x80 /* break detected */
+#define SAB_IMR1_BRKT 0x40 /* break terminated */
+#define SAB_IMR1_ALLS 0x20 /* all sent */
+#define SAB_IMR1_XDU 0x10 /* xoff detected */
+#define SAB_IMR1_TIN 0x08 /* timer interrupt */
+#define SAB_IMR1_CSC 0x04 /* clear to send status change */
+#define SAB_IMR1_XMR 0x02 /* xon detected */
+#define SAB_IMR1_XPR 0x01 /* transmit pool ready */
+
+/* SAB_PVR: port value register */
+#define SAB_PVR_DSR_A 0x01 /* port A DSR */
+#define SAB_PVR_DTR_A 0x02 /* port A DTR */
+#define SAB_PVR_DTR_B 0x04 /* port B DTR */
+#define SAB_PVR_DSR_B 0x08 /* port B DSR */
+#define SAB_PVR_MAGIC 0x10 /* dunno... */
+
+/* SAB_CCR4: channel configuration register 4 */
+#define SAB_CCR4_MCK4 0x80 /* master clock divide by 4 */
+#define SAB_CCR4_EBRG 0x40 /* enhanced baud rate generator mode */
+#define SAB_CCR4_TST1 0x20 /* test pin */
+#define SAB_CCR4_ICD 0x10 /* invert polarity of carrier detect */
+
+/* Receive status byte */
+#define SAB_RSTAT_PE 0x80 /* parity error */
+#define SAB_RSTAT_FE 0x40 /* framing error */
+#define SAB_RSTAT_PAR 0x01 /* parity bit */
diff --git a/sys/dev/uart/uart_dev_z8530.c b/sys/dev/uart/uart_dev_z8530.c
new file mode 100644
index 0000000..498b3a3
--- /dev/null
+++ b/sys/dev/uart/uart_dev_z8530.c
@@ -0,0 +1,512 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_dev_z8530.h>
+
+#include "uart_if.h"
+
+#define DEFAULT_RCLK 307200
+
+#define IS_CHANNEL_A(bas) (((bas)->bsh & 7) != 0)
+#define IS_CHANNEL_B(bas) (((bas)->bsh & 7) == 0)
+
+/* Multiplexed I/O. */
+static __inline void
+uart_setmreg(struct uart_bas *bas, int reg, int val)
+{
+
+ uart_setreg(bas, REG_CTRL, reg);
+ uart_barrier(bas);
+ uart_setreg(bas, REG_CTRL, val);
+}
+
+static __inline uint8_t
+uart_getmreg(struct uart_bas *bas, int reg)
+{
+
+ uart_setreg(bas, REG_CTRL, reg);
+ uart_barrier(bas);
+ return (uart_getreg(bas, REG_CTRL));
+}
+
+static int
+z8530_divisor(int rclk, int baudrate)
+{
+ int act_baud, divisor, error;
+
+ if (baudrate == 0)
+ return (0);
+
+ divisor = (rclk + baudrate) / (baudrate << 1) - 2;
+ if (divisor >= 65536)
+ return (0);
+ act_baud = rclk / 2 / (divisor + 2);
+
+ /* 10 times error in percent: */
+ error = ((act_baud - baudrate) * 2000 / baudrate + 1) >> 1;
+
+ /* 3.0% maximum error tolerance: */
+ if (error < -30 || error > 30)
+ return (0);
+
+ return (divisor);
+}
+
+static int
+z8530_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity, uint8_t *tpcp)
+{
+ int divisor;
+ uint8_t mpm, rpc, tpc;
+
+ rpc = RPC_RXE;
+ mpm = MPM_CM16;
+ tpc = TPC_TXE | (*tpcp & (TPC_DTR | TPC_RTS));
+
+ if (databits >= 8) {
+ rpc |= RPC_RB8;
+ tpc |= TPC_TB8;
+ } else if (databits == 7) {
+ rpc |= RPC_RB7;
+ tpc |= TPC_TB7;
+ } else if (databits == 6) {
+ rpc |= RPC_RB6;
+ tpc |= TPC_TB6;
+ } else {
+ rpc |= RPC_RB5;
+ tpc |= TPC_TB5;
+ }
+ mpm |= (stopbits > 1) ? MPM_SB2 : MPM_SB1;
+ switch (parity) {
+ case UART_PARITY_EVEN: mpm |= MPM_PE | MPM_EVEN; break;
+ case UART_PARITY_NONE: break;
+ case UART_PARITY_ODD: mpm |= MPM_PE; break;
+ default: return (EINVAL);
+ }
+
+ /* Set baudrate. */
+ if (baudrate > 0) {
+ divisor = z8530_divisor(bas->rclk, baudrate);
+ if (divisor == 0)
+ return (EINVAL);
+ uart_setmreg(bas, WR_TCL, divisor & 0xff);
+ uart_barrier(bas);
+ uart_setmreg(bas, WR_TCH, (divisor >> 8) & 0xff);
+ uart_barrier(bas);
+ }
+
+ uart_setmreg(bas, WR_RPC, rpc);
+ uart_barrier(bas);
+ uart_setmreg(bas, WR_MPM, mpm);
+ uart_barrier(bas);
+ uart_setmreg(bas, WR_TPC, tpc);
+ uart_barrier(bas);
+ *tpcp = tpc;
+ return (0);
+}
+
+static int
+z8530_setup(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+ uint8_t tpc;
+
+ if (bas->rclk == 0)
+ bas->rclk = DEFAULT_RCLK;
+
+ /* Assume we don't need to perform a full hardware reset. */
+ uart_setmreg(bas, WR_MIC, ((IS_CHANNEL_A(bas)) ? MIC_CRA : MIC_CRB) |
+ MIC_MIE | MIC_NV);
+ uart_barrier(bas);
+ /* Set clock sources and enable BRG. */
+ uart_setmreg(bas, WR_CMC, CMC_RC_BRG | CMC_TC_BRG);
+ uart_setmreg(bas, WR_MCB2, MCB2_PCLK | MCB2_BRGE);
+ uart_barrier(bas);
+ /* Set data encoding. */
+ uart_setmreg(bas, WR_MCB1, MCB1_NRZ);
+ uart_barrier(bas);
+
+ tpc = TPC_DTR | TPC_RTS;
+ z8530_param(bas, baudrate, databits, stopbits, parity, &tpc);
+ return (int)tpc;
+}
+
+/*
+ * Low-level UART interface.
+ */
+static int z8530_probe(struct uart_bas *bas);
+static void z8530_init(struct uart_bas *bas, int, int, int, int);
+static void z8530_term(struct uart_bas *bas);
+static void z8530_putc(struct uart_bas *bas, int);
+static int z8530_poll(struct uart_bas *bas);
+static int z8530_getc(struct uart_bas *bas);
+
+struct uart_ops uart_z8530_ops = {
+ .probe = z8530_probe,
+ .init = z8530_init,
+ .term = z8530_term,
+ .putc = z8530_putc,
+ .poll = z8530_poll,
+ .getc = z8530_getc,
+};
+
+static int
+z8530_probe(struct uart_bas *bas)
+{
+
+ return (0);
+}
+
+static void
+z8530_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+
+ z8530_setup(bas, baudrate, databits, stopbits, parity);
+}
+
+static void
+z8530_term(struct uart_bas *bas)
+{
+}
+
+static void
+z8530_putc(struct uart_bas *bas, int c)
+{
+
+ while (!(uart_getmreg(bas, RR_BES) & BES_TXE))
+ ;
+ uart_setreg(bas, REG_DATA, c);
+ uart_barrier(bas);
+}
+
+static int
+z8530_poll(struct uart_bas *bas)
+{
+
+ if (!(uart_getmreg(bas, RR_BES) & BES_RXA))
+ return (-1);
+ return (uart_getreg(bas, REG_DATA));
+}
+
+static int
+z8530_getc(struct uart_bas *bas)
+{
+
+ while (!(uart_getmreg(bas, RR_BES) & BES_RXA))
+ ;
+ return (uart_getreg(bas, REG_DATA));
+}
+
+/*
+ * High-level UART interface.
+ */
+struct z8530_softc {
+ struct uart_softc base;
+ uint8_t tpc;
+};
+
+static int z8530_bus_attach(struct uart_softc *);
+static int z8530_bus_detach(struct uart_softc *);
+static int z8530_bus_flush(struct uart_softc *, int);
+static int z8530_bus_getsig(struct uart_softc *);
+static int z8530_bus_ioctl(struct uart_softc *, int, intptr_t);
+static int z8530_bus_ipend(struct uart_softc *);
+static int z8530_bus_param(struct uart_softc *, int, int, int, int);
+static int z8530_bus_probe(struct uart_softc *);
+static int z8530_bus_receive(struct uart_softc *);
+static int z8530_bus_setsig(struct uart_softc *, int);
+static int z8530_bus_transmit(struct uart_softc *);
+
+static kobj_method_t z8530_methods[] = {
+ KOBJMETHOD(uart_attach, z8530_bus_attach),
+ KOBJMETHOD(uart_detach, z8530_bus_detach),
+ KOBJMETHOD(uart_flush, z8530_bus_flush),
+ KOBJMETHOD(uart_getsig, z8530_bus_getsig),
+ KOBJMETHOD(uart_ioctl, z8530_bus_ioctl),
+ KOBJMETHOD(uart_ipend, z8530_bus_ipend),
+ KOBJMETHOD(uart_param, z8530_bus_param),
+ KOBJMETHOD(uart_probe, z8530_bus_probe),
+ KOBJMETHOD(uart_receive, z8530_bus_receive),
+ KOBJMETHOD(uart_setsig, z8530_bus_setsig),
+ KOBJMETHOD(uart_transmit, z8530_bus_transmit),
+ { 0, 0 }
+};
+
+struct uart_class uart_z8530_class = {
+ "z8530 class",
+ z8530_methods,
+ sizeof(struct z8530_softc),
+ .uc_range = 2,
+ .uc_rclk = DEFAULT_RCLK
+};
+
+#define SIGCHG(c, i, s, d) \
+ if (c) { \
+ i |= (i & s) ? s : s | d; \
+ } else { \
+ i = (i & s) ? (i & ~s) | d : i; \
+ }
+
+static int
+z8530_bus_attach(struct uart_softc *sc)
+{
+ struct z8530_softc *z8530 = (struct z8530_softc*)sc;
+ struct uart_bas *bas;
+ struct uart_devinfo *di;
+
+ bas = &sc->sc_bas;
+ if (sc->sc_sysdev != NULL) {
+ di = sc->sc_sysdev;
+ z8530->tpc = TPC_DTR|TPC_RTS;
+ z8530_param(bas, di->baudrate, di->databits, di->stopbits,
+ di->parity, &z8530->tpc);
+ } else {
+ z8530->tpc = z8530_setup(bas, 9600, 8, 1, UART_PARITY_NONE);
+ z8530->tpc &= ~(TPC_DTR|TPC_RTS);
+ }
+
+ sc->sc_rxfifosz = 3;
+ sc->sc_txfifosz = 1;
+
+ (void)z8530_bus_getsig(sc);
+
+ uart_setmreg(bas, WR_IC, IC_BRK | IC_CTS | IC_DCD);
+ uart_barrier(bas);
+ uart_setmreg(bas, WR_IDT, IDT_TIE | IDT_RIA);
+ uart_barrier(bas);
+ uart_setmreg(bas, WR_IV, 0);
+ uart_barrier(bas);
+ uart_setmreg(bas, WR_TPC, z8530->tpc);
+ uart_barrier(bas);
+ return (0);
+}
+
+static int
+z8530_bus_detach(struct uart_softc *sc)
+{
+
+ return (0);
+}
+
+static int
+z8530_bus_flush(struct uart_softc *sc, int what)
+{
+
+ return (0);
+}
+
+static int
+z8530_bus_getsig(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ uint32_t new, old, sig;
+ uint8_t bes;
+
+ bas = &sc->sc_bas;
+ do {
+ old = sc->sc_hwsig;
+ sig = old;
+ bes = uart_getmreg(bas, RR_BES);
+ SIGCHG(bes & BES_CTS, sig, UART_SIG_CTS, UART_SIG_DCTS);
+ SIGCHG(bes & BES_DCD, sig, UART_SIG_DCD, UART_SIG_DDCD);
+ new = sig & ~UART_SIGMASK_DELTA;
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+ return (sig);
+}
+
+static int
+z8530_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
+{
+ struct z8530_softc *z8530 = (struct z8530_softc*)sc;
+ struct uart_bas *bas;
+
+ bas = &sc->sc_bas;
+ switch (request) {
+ case UART_IOCTL_BREAK:
+ if (data)
+ z8530->tpc |= TPC_BRK;
+ else
+ z8530->tpc &= ~TPC_BRK;
+ uart_setmreg(bas, WR_TPC, z8530->tpc);
+ uart_barrier(bas);
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+z8530_bus_ipend(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int ipend;
+ uint32_t sig;
+ uint8_t bes, src;
+
+ bas = &sc->sc_bas;
+ ipend = 0;
+ uart_setreg(bas, REG_CTRL, CR_RSTIUS);
+ uart_barrier(bas);
+ bes = uart_getmreg(bas, RR_BES);
+ if (bes & BES_BRK) {
+ uart_setreg(bas, REG_CTRL, CR_RSTXSI);
+ ipend |= UART_IPEND_BREAK;
+ }
+ if (bes & BES_TXE) {
+ uart_setreg(bas, REG_CTRL, CR_RSTTXI);
+ ipend |= UART_IPEND_TXIDLE;
+ }
+ if (bes & BES_RXA)
+ ipend |= UART_IPEND_RXREADY;
+ sig = sc->sc_hwsig;
+ SIGCHG(bes & BES_CTS, sig, UART_SIG_CTS, UART_SIG_DCTS);
+ SIGCHG(bes & BES_DCD, sig, UART_SIG_DCD, UART_SIG_DDCD);
+ if (sig & UART_SIGMASK_DELTA)
+ ipend |= UART_IPEND_SIGCHG;
+ src = uart_getmreg(bas, RR_SRC);
+ if (src & SRC_OVR) {
+ uart_setreg(bas, REG_CTRL, CR_RSTERR);
+ ipend |= UART_IPEND_OVERRUN;
+ }
+ return (ipend);
+}
+
+static int
+z8530_bus_param(struct uart_softc *sc, int baudrate, int databits,
+ int stopbits, int parity)
+{
+ struct z8530_softc *z8530 = (struct z8530_softc*)sc;
+ int error;
+
+ error = z8530_param(&sc->sc_bas, baudrate, databits, stopbits, parity,
+ &z8530->tpc);
+ return (error);
+}
+
+static int
+z8530_bus_probe(struct uart_softc *sc)
+{
+ char buf[80];
+ const char *ch;
+ int error;
+
+ error = z8530_probe(&sc->sc_bas);
+ if (error)
+ return (error);
+
+ /* Assume the address range is naturally aligned. */
+ ch = IS_CHANNEL_A(&sc->sc_bas) ? "A" : "B";
+
+ snprintf(buf, sizeof(buf), "z8530, channel %s", ch);
+ device_set_desc_copy(sc->sc_dev, buf);
+ return (0);
+}
+
+static int
+z8530_bus_receive(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int xc;
+ uint8_t bes, src;
+
+ bas = &sc->sc_bas;
+ bes = uart_getmreg(bas, RR_BES);
+ while ((bes & BES_RXA) && !uart_rx_full(sc)) {
+ src = uart_getmreg(bas, RR_SRC);
+ xc = uart_getreg(bas, REG_DATA);
+ if (src & SRC_FE)
+ xc |= UART_STAT_FRAMERR;
+ if (src & SRC_PE)
+ xc |= UART_STAT_PARERR;
+ uart_rx_put(sc, xc);
+ if (src & (SRC_FE | SRC_PE))
+ uart_setreg(bas, REG_CTRL, CR_RSTERR);
+ bes = uart_getmreg(bas, RR_BES);
+ }
+ return (0);
+}
+
+static int
+z8530_bus_setsig(struct uart_softc *sc, int sig)
+{
+ struct z8530_softc *z8530 = (struct z8530_softc*)sc;
+ struct uart_bas *bas;
+ uint32_t new, old;
+
+ bas = &sc->sc_bas;
+ do {
+ old = sc->sc_hwsig;
+ new = old;
+ if (sig & UART_SIG_DDTR) {
+ SIGCHG(sig & UART_SIG_DTR, new, UART_SIG_DTR,
+ UART_SIG_DDTR);
+ }
+ if (sig & UART_SIG_DRTS) {
+ SIGCHG(sig & UART_SIG_RTS, new, UART_SIG_RTS,
+ UART_SIG_DRTS);
+ }
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+
+ if (new & UART_SIG_DTR)
+ z8530->tpc |= TPC_DTR;
+ else
+ z8530->tpc &= ~TPC_DTR;
+ if (new & UART_SIG_RTS)
+ z8530->tpc |= TPC_RTS;
+ else
+ z8530->tpc &= ~TPC_RTS;
+ uart_setmreg(bas, WR_TPC, z8530->tpc);
+ uart_barrier(bas);
+ return (0);
+}
+
+static int
+z8530_bus_transmit(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+
+ bas = &sc->sc_bas;
+ while (!(uart_getmreg(bas, RR_BES) & BES_TXE))
+ ;
+ uart_setreg(bas, REG_DATA, sc->sc_txbuf[0]);
+ uart_barrier(bas);
+ sc->sc_txbusy = 1;
+ return (0);
+}
diff --git a/sys/dev/uart/uart_dev_z8530.h b/sys/dev/uart/uart_dev_z8530.h
new file mode 100644
index 0000000..458aff7
--- /dev/null
+++ b/sys/dev/uart/uart_dev_z8530.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_UART_DEV_Z8530_H_
+#define _DEV_UART_DEV_Z8530_H_
+
+/*
+ * Channel B control: 0
+ * Channel B data: 1
+ * Channel A control: 2
+ * Channel A data: 3
+ *
+ * We expect a seperate subregion for each channel.
+ */
+#define REG_CTRL 0
+#define REG_DATA 1
+
+/* Write registers. */
+#define WR_CR 0 /* Command Register. */
+#define WR_IDT 1 /* Interrupt and Data Transfer Mode. */
+#define WR_IV 2 /* Interrupt Vector (shared). */
+#define WR_RPC 3 /* Receive Parameters and Control. */
+#define WR_MPM 4 /* Miscellaneous Parameters and Modes. */
+#define WR_TPC 5 /* Transmit Parameters and Control. */
+#define WR_SCAF 6 /* Sync Character or (SDLC) Address Field. */
+#define WR_SCF 7 /* Sync Character or (SDCL) Flag. */
+#define WR_EFC 7 /* Extended Feature and FIFO Control. */
+#define WR_TB 8 /* Transmit Buffer. */
+#define WR_MIC 9 /* Master Interrupt Control (shared). */
+#define WR_MCB1 10 /* Miscellaneous Control Bits (part 1 :-). */
+#define WR_CMC 11 /* Clock Mode Control. */
+#define WR_TCL 12 /* BRG Time Constant Low. */
+#define WR_TCH 13 /* BRG Time Constant High. */
+#define WR_MCB2 14 /* Miscellaneous Control Bits (part 2 :-). */
+#define WR_IC 15 /* Interrupt Control. */
+
+/* Read registers. */
+#define RR_BES 0 /* Buffer and External Status. */
+#define RR_SRC 1 /* Special Receive Condition. */
+#define RR_IV 2 /* Interrupt Vector. */
+#define RR_IP 3 /* Interrupt Pending (ch A only). */
+#define RR_MPM 4 /* Miscellaneous Parameters and Modes. */
+#define RR_TPC 5 /* Transmit Parameters and Control. */
+#define RR_BCL 6 /* Byte Count Low. */
+#define RR_BCH 7 /* Byte Count High. */
+#define RR_RB 8 /* Receive Buffer. */
+#define RR_RPC 9 /* Receive Parameters and Contro. */
+#define RR_MSB 10 /* Miscellaneous Status Bits. */
+#define RR_MCB1 11 /* Miscellaneous Control Bits (part 1). */
+#define RR_TCL 12 /* BRG Time Constant Low. */
+#define RR_TCH 13 /* BRG Time Constant High. */
+#define RR_EFC 14 /* Extended Feature and FIFO Control. */
+#define RR_IC 15 /* Interrupt Control. */
+
+/* Buffer and External Status (RR0). */
+#define BES_BRK 0x80 /* Break (Abort). */
+#define BES_TXU 0x40 /* Tx Underrun (EOM). */
+#define BES_CTS 0x20 /* CTS. */
+#define BES_SYNC 0x10 /* Sync. */
+#define BES_DCD 0x08 /* DCD. */
+#define BES_TXE 0x04 /* Tx Empty. */
+#define BES_ZC 0x02 /* Zero Count. */
+#define BES_RXA 0x01 /* Rx Available. */
+
+/* Clock Mode Control (WR11). */
+#define CMC_XTAL 0x80 /* -RTxC connects to quartz crystal. */
+#define CMC_RC_DPLL 0x60 /* Rx Clock from DPLL. */
+#define CMC_RC_BRG 0x40 /* Rx Clock from BRG. */
+#define CMC_RC_TRXC 0x20 /* Rx Clock from -TRxC. */
+#define CMC_RC_RTXC 0x00 /* Rx Clock from -RTxC. */
+#define CMC_TC_DPLL 0x18 /* Tx Clock from DPLL */
+#define CMC_TC_BRG 0x10 /* Tx Clock from BRG */
+#define CMC_TC_TRXC 0x08 /* Tx Clock from -TRxC. */
+#define CMC_TC_RTXC 0x00 /* Tx Clock from -RTxC. */
+#define CMC_TRXC_OUT 0x04 /* -TRxC is output. */
+#define CMC_TRXC_DPLL 0x03 /* -TRxC from DPLL */
+#define CMC_TRXC_BRG 0x02 /* -TRxC from BRG */
+#define CMC_TRXC_XMIT 0x01 /* -TRxC from Tx clock. */
+#define CMC_TRXC_XTAL 0x00 /* -TRxC from XTAL. */
+
+/* Command Register (WR0). */
+#define CR_RSTTXU 0xc0 /* Reset Tx. Underrun/EOM. */
+#define CR_RSTTXCRC 0x80 /* Reset Tx. CRC. */
+#define CR_RSTRXCRC 0x40 /* Reset Rx. CRC. */
+#define CR_RSTIUS 0x38 /* Reset Int. Under Service. */
+#define CR_RSTERR 0x30 /* Error Reset. */
+#define CR_RSTTXI 0x28 /* Reset Tx. Int. */
+#define CR_ENARXI 0x20 /* Enable Rx. Int. */
+#define CR_ABORT 0x18 /* Send Abort. */
+#define CR_RSTXSI 0x10 /* Reset Ext/Status Int. */
+
+/* Extended Feature and FIFO Control (WR7 prime). */
+#define EFC_ERE 0x40 /* Extended Read Enable. */
+#define EFC_FE 0x20 /* Transmit FIFO Empty. */
+#define EFC_RQT 0x10 /* Request Timing. */
+#define EFC_FHF 0x08 /* Receive FIFO Half Full. */
+#define EFC_RTS 0x04 /* Auto RTS Deactivation. */
+#define EFC_EOM 0x02 /* Auto EOM Reset. */
+#define EFC_FLAG 0x01 /* Auto SDLC Flag on Tx. */
+
+/* Interrupt Control (WR15). */
+#define IC_BRK 0x80 /* Break (Abort) IE. */
+#define IC_TXU 0x40 /* Tx Underrun IE. */
+#define IC_CTS 0x20 /* CTS IE. */
+#define IC_SYNC 0x10 /* Sync IE. */
+#define IC_DCD 0x08 /* DCD IE. */
+#define IC_FIFO 0x04 /* SDLC FIFO Enable. */
+#define IC_ZC 0x02 /* Zero Count IE. */
+#define IC_EF 0x01 /* Extended Feature Enable. */
+
+/* Interrupt and Data Transfer Mode (WR1). */
+#define IDT_WRE 0x80 /* Wait/DMA Request Enable. */
+#define IDT_REQ 0x40 /* DMA Request. */
+#define IDT_WRR 0x20 /* Wait/DMA Reuest on Receive. */
+#define IDT_RISC 0x18 /* Rx Int. on Special Condition Only. */
+#define IDT_RIA 0x10 /* Rx Int. on All Characters. */
+#define IDT_RIF 0x08 /* Rx Int. on First Character. */
+#define IDT_PSC 0x04 /* Parity is Special Condition. */
+#define IDT_TIE 0x02 /* Tx Int. Enable. */
+#define IDT_XIE 0x01 /* Ext. Int. Enable. */
+
+/* Interrupt Pending (RR3). */
+#define IP_RIA 0x20 /* Rx. Int. ch. A. */
+#define IP_TIA 0x10 /* Tx. Int. ch. A. */
+#define IP_SIA 0x08 /* Ext/Status Int. ch. A. */
+#define IP_RIB 0x04 /* Rx. Int. ch. B. */
+#define IP_TIB 0x02 /* Tx. Int. ch. B. */
+#define IP_SIB 0x01 /* Ext/Status Int. ch. B. */
+
+/* Interrupt Vector Status Low (RR2). */
+#define IV_SCA 0x0e /* Special Condition ch. A. */
+#define IV_RAA 0x0c /* Receive Available ch. A. */
+#define IV_XSA 0x0a /* External/Status Change ch. A. */
+#define IV_TEA 0x08 /* Transmitter Empty ch. A. */
+#define IV_SCB 0x06 /* Special Condition ch. B. */
+#define IV_RAB 0x04 /* Receive Available ch. B. */
+#define IV_XSB 0x02 /* External/Status Change ch. B. */
+#define IV_TEB 0x00 /* Transmitter Empty ch. B. */
+
+/* Miscellaneous Control Bits part 1 (WR10). */
+#define MCB1_CRC1 0x80 /* CRC presets to 1. */
+#define MCB1_FM0 0x60 /* FM0 Encoding. */
+#define MCB1_FM1 0x40 /* FM1 Encoding. */
+#define MCB1_NRZI 0x20 /* NRZI Encoding. */
+#define MCB1_NRZ 0x00 /* NRZ Encoding. */
+#define MCB1_AOP 0x10 /* Active On Poll. */
+#define MCB1_MI 0x08 /* Mark Idle. */
+#define MCB1_AOU 0x04 /* Abort On Underrun. */
+#define MCB1_LM 0x02 /* Loop Mode. */
+#define MCB1_SIX 0x01 /* 6 or 12 bit SYNC. */
+
+/* Miscellaneous Control Bits part 2 (WR14). */
+#define MCB2_NRZI 0xe0 /* DPLL - NRZI mode. */
+#define MCB2_FM 0xc0 /* DPLL - FM mode. */
+#define MCB2_RTXC 0xa0 /* DPLL - Clock from -RTxC. */
+#define MCB2_BRG 0x80 /* DPLL - Clock from BRG. */
+#define MCB2_OFF 0x60 /* DPLL - Disable. */
+#define MCB2_RMC 0x40 /* DPLL - Reset Missing Clock. */
+#define MCB2_ESM 0x20 /* DPLL - Enter Search Mode. */
+#define MCB2_LL 0x10 /* Local Loopback. */
+#define MCB2_AE 0x08 /* Auto Echo. */
+#define MCB2_REQ 0x04 /* Request Function. */
+#define MCB2_PCLK 0x02 /* BRG source is PCLK. */
+#define MCB2_BRGE 0x01 /* BRG enable. */
+
+/* Master Interrupt Control (WR9). */
+#define MIC_FHR 0xc0 /* Force Hardware Reset. */
+#define MIC_CRA 0x80 /* Channel Reset A. */
+#define MIC_CRB 0x40 /* Channel Reset B. */
+#define MIC_SIE 0x20 /* Software INTACK Enable. */
+#define MIC_SH 0x10 /* Status High. */
+#define MIC_MIE 0x08 /* Master Interrupt Enable. */
+#define MIC_DLC 0x04 /* Disable Lower Chain. */
+#define MIC_NV 0x02 /* No Vector. */
+#define MIC_VIS 0x01 /* Vector Includes Status. */
+
+/* Transmit/Receive Miscellaneous Parameters and Modes (WR4). */
+#define MPM_CM64 0xc0 /* X64 Clock Mode. */
+#define MPM_CM32 0x80 /* X32 Clock Mode. */
+#define MPM_CM16 0x40 /* X16 Clock Mode. */
+#define MPM_CM1 0x00 /* X1 Clock Mode. */
+#define MPM_EXT 0x30 /* External Sync Mode. */
+#define MPM_SDLC 0x20 /* SDLC mode. */
+#define MPM_BI 0x10 /* 16-bit Sync (bi-sync). */
+#define MPM_MONO 0x00 /* 8-bit Sync (mono-sync). */
+#define MPM_SB2 0x0c /* Async mode: 2 stopbits. */
+#define MPM_SB15 0x08 /* Async mode: 1.5 stopbits. */
+#define MPM_SB1 0x04 /* Async mode: 1 stopbit. */
+#define MPM_SYNC 0x00 /* Sync Mode Enable. */
+#define MPM_EVEN 0x02 /* Async mode: even parity. */
+#define MPM_PE 0x01 /* Async mode: parity enable. */
+
+/* Receive Parameters and Control (WR3). */
+#define RPC_RB8 0xc0 /* 8 databits. */
+#define RPC_RB6 0x80 /* 6 databits. */
+#define RPC_RB7 0x40 /* 7 databits. */
+#define RPC_RB5 0x00 /* 5 databits. */
+#define RPC_AE 0x20 /* Auto Enable. */
+#define RPC_EHM 0x10 /* Enter Hunt Mode. */
+#define RPC_CRC 0x08 /* CRC Enable. */
+#define RPC_ASM 0x04 /* Address Search Mode. */
+#define RPC_LI 0x02 /* SYNC Character Load Inhibit */
+#define RPC_RXE 0x01 /* Receiver Enable */
+
+/* Special Receive Condition (RR1). */
+#define SRC_EOF 0x80 /* End Of Frame. */
+#define SRC_FE 0x40 /* Framing Error. */
+#define SRC_OVR 0x20 /* Rx. Overrun. */
+#define SRC_PE 0x10 /* Parity Error. */
+#define SRC_RC0 0x08 /* Residue Code 0. */
+#define SRC_RC1 0x04 /* Residue Code 1. */
+#define SRC_RC2 0x02 /* Residue Code 2. */
+#define SRC_AS 0x01 /* All Sent. */
+
+/* Transmit Parameter and Control (WR5). */
+#define TPC_DTR 0x80 /* DTR. */
+#define TPC_TB8 0x60 /* 8 databits. */
+#define TPC_TB6 0x40 /* 6 databits. */
+#define TPC_TB7 0x20 /* 7 databits. */
+#define TPC_TB5 0x00 /* 5 or fewer databits. */
+#define TPC_BRK 0x10 /* Send break. */
+#define TPC_TXE 0x08 /* Transmitter Enable. */
+#define TPC_CRC16 0x04 /* CRC16. */
+#define TPC_RTS 0x02 /* RTS. */
+#define TPC_CRC 0x01 /* CRC Enable. */
+
+#endif /* _DEV_UART_DEV_Z8530_H_ */
diff --git a/sys/dev/uart/uart_if.m b/sys/dev/uart/uart_if.m
new file mode 100644
index 0000000..772883d
--- /dev/null
+++ b/sys/dev/uart/uart_if.m
@@ -0,0 +1,138 @@
+# Copyright (c) 2003 Marcel Moolenaar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD$
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+
+# The UART hardware interface. The core UART code is hardware independent.
+# The details of the hardware are abstracted by the UART hardware interface.
+
+INTERFACE uart;
+
+# attach() - attach hardware.
+# This method is called when the device is being attached. All resources
+# have been allocated. The transmit and receive buffers exist, but no
+# high-level (ie tty) initialization has been done yet.
+# The intend of this method is to setup the hardware for normal operation.
+METHOD int attach {
+ struct uart_softc *this;
+};
+
+# detach() - detach hardware.
+# This method is called when a device is being detached from its bus. It
+# is the first action performed, so even the high-level (ie tty) interface
+# is still operational.
+# The intend of this method is to disable the hardware.
+METHOD int detach {
+ struct uart_softc *this;
+};
+
+# flush() - flush FIFOs.
+# This method is called to flush the transmitter and/or the receiver as
+# specified by the what argument. Characters are expected to be lost.
+METHOD int flush {
+ struct uart_softc *this;
+ int what;
+};
+
+# getsig() - get line and modem signals.
+# This method retrieves the DTE and DCE signals and their corresponding
+# delta bits. The delta bits include those corresponding to DTE signals
+# when they were changed by a call to setsig. The delta bits maintained
+# by the hardware driver are cleared as a side-effect. A second call to
+# this function will not have any delta bits set, unless there was a
+# change in the signals in the mean time.
+METHOD int getsig {
+ struct uart_softc *this;
+};
+
+# ioctl() - get or set miscellaneous parameters.
+# This method is the bitbucket method. It can (and will) be used when there's
+# something we need to set or get for which a new method is overkill. It's
+# used for example to set HW or SW flow-control.
+METHOD int ioctl {
+ struct uart_softc *this;
+ int request;
+ intptr_t data;
+};
+
+# ipend() - query UART for pending interrupts.
+# When an interrupt is signalled, the handler will call this method to find
+# out which of the interrupt sources needs attention. The handler will use
+# this information to dispatch service routines that deal with each of the
+# interrupt sources. An advantage of this approach is that it allows multi-
+# port drivers (like puc(4)) to query multiple devices concurrently and
+# service them on an interrupt priority basis. If the hardware cannot provide
+# the information reliably, it is free to service the interrupt and return 0,
+# meaning that no attention is required.
+METHOD int ipend {
+ struct uart_softc *this;
+}
+
+# param() - set communication parameters.
+# This method is called to change the communication parameters.
+METHOD int param {
+ struct uart_softc *this;
+ int baudrate;
+ int databits;
+ int stopbits;
+ int parity;
+};
+
+# probe() - detect hardware.
+# This method is called as part of the bus probe to make sure the
+# hardware exists. This function should also set the device description
+# to something that represents the hardware.
+METHOD int probe {
+ struct uart_softc *this;
+};
+
+# receive() - move data from the receive FIFO to the receive buffer.
+# This method is called to move received data to the receive buffer and
+# additionally should make sure the receive interrupt should be cleared.
+METHOD int receive {
+ struct uart_softc *this;
+};
+
+# setsig() - set line and modem signals.
+# This method allows changing DTE signals. The DTE delta bits indicate which
+# signals are to be changed and the DTE bits themselves indicate whether to
+# set or clear the signals. A subsequent call to getsig will return with the
+# DTE delta bits set of those DTE signals that did change by this method.
+METHOD int setsig {
+ struct uart_softc *this;
+ int sig;
+};
+
+# transmit() - move data from the transmit buffer to the transmit FIFO.
+# This method is responsible for writing the Tx buffer to the UART and
+# additionally should make sure that a transmit interrupt is generated
+# when transmission is complete.
+METHOD int transmit {
+ struct uart_softc *this;
+};
diff --git a/sys/dev/uart/uart_tty.c b/sys/dev/uart/uart_tty.c
new file mode 100644
index 0000000..3841889
--- /dev/null
+++ b/sys/dev/uart/uart_tty.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/cons.h>
+#include <sys/fcntl.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/reboot.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <sys/termios.h>
+#include <sys/tty.h>
+#include <machine/resource.h>
+#include <machine/stdarg.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include "uart_if.h"
+
+#define UART_MINOR_CALLOUT 0x10000
+
+static cn_probe_t uart_cnprobe;
+static cn_init_t uart_cninit;
+static cn_term_t uart_cnterm;
+static cn_getc_t uart_cngetc;
+static cn_checkc_t uart_cncheckc;
+static cn_putc_t uart_cnputc;
+
+CONS_DRIVER(uart, uart_cnprobe, uart_cninit, uart_cnterm, uart_cngetc,
+ uart_cncheckc, uart_cnputc, NULL);
+
+static d_open_t uart_tty_open;
+static d_close_t uart_tty_close;
+static d_ioctl_t uart_tty_ioctl;
+
+static struct cdevsw uart_cdevsw = {
+ .d_open = uart_tty_open,
+ .d_close = uart_tty_close,
+ .d_read = ttyread,
+ .d_write = ttywrite,
+ .d_ioctl = uart_tty_ioctl,
+ .d_poll = ttypoll,
+ .d_name = uart_driver_name,
+ .d_maj = MAJOR_AUTO,
+ .d_flags = D_TTY,
+ .d_kqfilter = ttykqfilter,
+};
+
+static struct uart_devinfo uart_console;
+
+static void
+uart_cnprobe(struct consdev *cp)
+{
+
+ cp->cn_dev = NULL;
+ cp->cn_pri = CN_DEAD;
+
+ KASSERT(uart_console.cookie == NULL, ("foo"));
+
+ if (uart_cpu_getdev(UART_DEV_CONSOLE, &uart_console))
+ return;
+
+ if (uart_probe(&uart_console))
+ return;
+
+ cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
+ cp->cn_arg = &uart_console;
+}
+
+static void
+uart_cninit(struct consdev *cp)
+{
+ struct uart_devinfo *di;
+
+ /*
+ * Yedi trick: we need to be able to define cn_dev before we go
+ * single- or multi-user. The problem is that we don't know at
+ * this time what the device will be. Hence, we need to link from
+ * the uart_devinfo to the consdev that corresponds to it so that
+ * we can define cn_dev in uart_bus_attach() when we find the
+ * device during bus enumeration. That's when we'll know what the
+ * the unit number will be.
+ */
+ di = cp->cn_arg;
+ KASSERT(di->cookie == NULL, ("foo"));
+ di->cookie = cp;
+ di->type = UART_DEV_CONSOLE;
+ uart_add_sysdev(di);
+ uart_init(di);
+}
+
+static void
+uart_cnterm(struct consdev *cp)
+{
+
+ uart_term(cp->cn_arg);
+}
+
+static void
+uart_cnputc(struct consdev *cp, int c)
+{
+
+ uart_putc(cp->cn_arg, c);
+}
+
+static int
+uart_cncheckc(struct consdev *cp)
+{
+
+ return (uart_poll(cp->cn_arg));
+}
+
+static int
+uart_cngetc(struct consdev *cp)
+{
+
+ return (uart_getc(cp->cn_arg));
+}
+
+static void
+uart_tty_oproc(struct tty *tp)
+{
+ struct uart_softc *sc;
+
+ KASSERT(tp->t_dev != NULL, ("foo"));
+ sc = tp->t_dev->si_drv1;
+ if (sc == NULL || sc->sc_leaving)
+ return;
+
+ /*
+ * Handle input flow control. Note that if we have hardware support,
+ * we don't do anything here. We continue to receive until our buffer
+ * is full. At that time we cannot empty the UART itself and it will
+ * de-assert RTS for us. In that situation we're completely stuffed.
+ * Without hardware support, we need to toggle RTS ourselves.
+ */
+ if ((tp->t_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) {
+ if ((tp->t_state & TS_TBLOCK) &&
+ (sc->sc_hwsig & UART_SIG_RTS))
+ UART_SETSIG(sc, UART_SIG_DRTS);
+ else if (!(tp->t_state & TS_TBLOCK) &&
+ !(sc->sc_hwsig & UART_SIG_RTS))
+ UART_SETSIG(sc, UART_SIG_DRTS|UART_SIG_RTS);
+ }
+
+ if (tp->t_state & TS_TTSTOP)
+ return;
+
+ if ((tp->t_state & TS_BUSY) || sc->sc_txbusy)
+ return;
+
+ if (tp->t_outq.c_cc == 0) {
+ ttwwakeup(tp);
+ return;
+ }
+
+ sc->sc_txdatasz = q_to_b(&tp->t_outq, sc->sc_txbuf, sc->sc_txfifosz);
+ tp->t_state |= TS_BUSY;
+ UART_TRANSMIT(sc);
+ ttwwakeup(tp);
+}
+
+static int
+uart_tty_param(struct tty *tp, struct termios *t)
+{
+ struct uart_softc *sc;
+ int databits, parity, stopbits;
+
+ KASSERT(tp->t_dev != NULL, ("foo"));
+ sc = tp->t_dev->si_drv1;
+ if (sc == NULL || sc->sc_leaving)
+ return (ENODEV);
+ if (t->c_ispeed != t->c_ospeed && t->c_ospeed != 0)
+ return (EINVAL);
+ /* Fixate certain parameters for system devices. */
+ if (sc->sc_sysdev != NULL) {
+ t->c_ispeed = t->c_ospeed = sc->sc_sysdev->baudrate;
+ t->c_cflag |= CLOCAL;
+ t->c_cflag &= ~HUPCL;
+ }
+ if (t->c_ospeed == 0) {
+ UART_SETSIG(sc, UART_SIG_DDTR | UART_SIG_DRTS);
+ return (0);
+ }
+ switch (t->c_cflag & CSIZE) {
+ case CS5: databits = 5; break;
+ case CS6: databits = 6; break;
+ case CS7: databits = 7; break;
+ default: databits = 8; break;
+ }
+ stopbits = (t->c_cflag & CSTOPB) ? 2 : 1;
+ if (t->c_cflag & PARENB)
+ parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD
+ : UART_PARITY_EVEN;
+ else
+ parity = UART_PARITY_NONE;
+ UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity);
+ UART_SETSIG(sc, UART_SIG_DDTR | UART_SIG_DTR);
+ /* Set input flow control state. */
+ if (!sc->sc_hwiflow) {
+ if ((t->c_cflag & CRTS_IFLOW) && (tp->t_state & TS_TBLOCK))
+ UART_SETSIG(sc, UART_SIG_DRTS);
+ else
+ UART_SETSIG(sc, UART_SIG_DRTS | UART_SIG_RTS);
+ } else
+ UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW));
+ /* Set output flow control state. */
+ if (sc->sc_hwoflow)
+ UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW));
+ ttsetwater(tp);
+ return (0);
+}
+
+static void
+uart_tty_stop(struct tty *tp, int rw)
+{
+ struct uart_softc *sc;
+
+ KASSERT(tp->t_dev != NULL, ("foo"));
+ sc = tp->t_dev->si_drv1;
+ if (sc == NULL || sc->sc_leaving)
+ return;
+ if (rw & FWRITE) {
+ if (sc->sc_txbusy) {
+ sc->sc_txbusy = 0;
+ UART_FLUSH(sc, UART_FLUSH_TRANSMITTER);
+ }
+ tp->t_state &= ~TS_BUSY;
+ }
+ if (rw & FREAD) {
+ UART_FLUSH(sc, UART_FLUSH_RECEIVER);
+ sc->sc_rxget = sc->sc_rxput = 0;
+ }
+}
+
+void
+uart_tty_intr(void *arg)
+{
+ struct uart_softc *sc = arg;
+ struct tty *tp;
+ int c, pend, sig, xc;
+
+ if (sc->sc_leaving)
+ return;
+
+ pend = atomic_readandclear_32(&sc->sc_ttypend);
+ if (!(pend & UART_IPEND_MASK))
+ return;
+
+ tp = sc->sc_u.u_tty.tp;
+
+ if (pend & UART_IPEND_RXREADY) {
+ while (!uart_rx_empty(sc) && !(tp->t_state & TS_TBLOCK)) {
+ xc = uart_rx_get(sc);
+ c = xc & 0xff;
+ if (xc & UART_STAT_FRAMERR)
+ c |= TTY_FE;
+ if (xc & UART_STAT_PARERR)
+ c |= TTY_PE;
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ }
+
+ if (pend & UART_IPEND_BREAK) {
+ if (tp != NULL && !(tp->t_iflag & IGNBRK))
+ (*linesw[tp->t_line].l_rint)(0, tp);
+ }
+
+ if (pend & UART_IPEND_SIGCHG) {
+ sig = pend & UART_IPEND_SIGMASK;
+ if (sig & UART_SIG_DDCD)
+ (*linesw[tp->t_line].l_modem)(tp, sig & UART_SIG_DCD);
+ if ((sig & UART_SIG_DCTS) && (tp->t_cflag & CCTS_OFLOW) &&
+ !sc->sc_hwoflow) {
+ if (sig & UART_SIG_CTS) {
+ tp->t_state &= ~TS_TTSTOP;
+ (*linesw[tp->t_line].l_start)(tp);
+ } else
+ tp->t_state |= TS_TTSTOP;
+ }
+ }
+
+ if (pend & UART_IPEND_TXIDLE) {
+ tp->t_state &= ~TS_BUSY;
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+}
+
+int
+uart_tty_attach(struct uart_softc *sc)
+{
+ struct tty *tp;
+
+ tp = ttymalloc(NULL);
+ sc->sc_u.u_tty.tp = tp;
+
+ sc->sc_u.u_tty.si[0] = make_dev(&uart_cdevsw,
+ device_get_unit(sc->sc_dev), UID_ROOT, GID_WHEEL, 0600, "ttyu%r",
+ device_get_unit(sc->sc_dev));
+ sc->sc_u.u_tty.si[0]->si_drv1 = sc;
+ sc->sc_u.u_tty.si[0]->si_tty = tp;
+ sc->sc_u.u_tty.si[1] = make_dev(&uart_cdevsw,
+ device_get_unit(sc->sc_dev) | UART_MINOR_CALLOUT, UID_UUCP,
+ GID_DIALER, 0660, "uart%r", device_get_unit(sc->sc_dev));
+ sc->sc_u.u_tty.si[1]->si_drv1 = sc;
+ sc->sc_u.u_tty.si[1]->si_tty = tp;
+
+ tp->t_oproc = uart_tty_oproc;
+ tp->t_param = uart_tty_param;
+ tp->t_stop = uart_tty_stop;
+
+ if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
+ ((struct consdev *)sc->sc_sysdev->cookie)->cn_dev =
+ makedev(uart_cdevsw.d_maj, device_get_unit(sc->sc_dev));
+ }
+
+ swi_add(&tty_ithd, uart_driver_name, uart_tty_intr, sc, SWI_TTY,
+ INTR_TYPE_TTY, &sc->sc_softih);
+
+ return (0);
+}
+
+int uart_tty_detach(struct uart_softc *sc)
+{
+
+ ithread_remove_handler(sc->sc_softih);
+ destroy_dev(sc->sc_u.u_tty.si[0]);
+ destroy_dev(sc->sc_u.u_tty.si[1]);
+ /* ttyfree(sc->sc_u.u_tty.tp); */
+
+ return (0);
+}
+
+static int
+uart_tty_open(dev_t dev, int flags, int mode, struct thread *td)
+{
+ struct uart_softc *sc;
+ struct tty *tp;
+ int error;
+
+ sc = dev->si_drv1;
+ if (sc == NULL || sc->sc_leaving)
+ return (ENODEV);
+
+ tp = dev->si_tty;
+
+ loop:
+ if (sc->sc_opened) {
+ KASSERT(tp->t_state & TS_ISOPEN, ("foo"));
+ /*
+ * The device is open, so everything has been initialized.
+ * Handle conflicts.
+ */
+ if (minor(dev) & UART_MINOR_CALLOUT) {
+ if (!sc->sc_callout)
+ return (EBUSY);
+ } else {
+ if (sc->sc_callout) {
+ if (flags & O_NONBLOCK)
+ return (EBUSY);
+ error = tsleep(sc, TTIPRI|PCATCH, "uartbi", 0);
+ if (error)
+ return (error);
+ sc = dev->si_drv1;
+ if (sc == NULL || sc->sc_leaving)
+ return (ENODEV);
+ goto loop;
+ }
+ }
+ if (tp->t_state & TS_XCLUDE && suser(td) != 0)
+ return (EBUSY);
+ } else {
+ KASSERT(!(tp->t_state & TS_ISOPEN), ("foo"));
+ /*
+ * The device isn't open, so there are no conflicts.
+ * Initialize it. Initialization is done twice in many
+ * cases: to preempt sleeping callin opens if we are
+ * callout, and to complete a callin open after DCD rises.
+ */
+ sc->sc_callout = (minor(dev) & UART_MINOR_CALLOUT) ? 1 : 0;
+ tp->t_dev = dev;
+
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+ ttychars(tp);
+ error = uart_tty_param(tp, &tp->t_termios);
+ if (error)
+ return (error);
+ /*
+ * Handle initial DCD.
+ */
+ if ((sc->sc_hwsig & UART_SIG_DCD) || sc->sc_callout)
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+ }
+ /*
+ * Wait for DCD if necessary.
+ */
+ if (!(tp->t_state & TS_CARR_ON) && !sc->sc_callout &&
+ !(tp->t_cflag & CLOCAL) && !(flags & O_NONBLOCK)) {
+ error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "uartdcd", 0);
+ if (error)
+ return (error);
+ sc = dev->si_drv1;
+ if (sc == NULL || sc->sc_leaving)
+ return (ENODEV);
+ goto loop;
+ }
+ error = ttyopen(dev, tp);
+ if (error)
+ return (error);
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+ if (error)
+ return (error);
+
+ KASSERT(tp->t_state & TS_ISOPEN, ("foo"));
+ sc->sc_opened = 1;
+ return (0);
+}
+
+static int
+uart_tty_close(dev_t dev, int flags, int mode, struct thread *td)
+{
+ struct uart_softc *sc;
+ struct tty *tp;
+
+ sc = dev->si_drv1;
+ if (sc == NULL || sc->sc_leaving)
+ return (ENODEV);
+ tp = dev->si_tty;
+ if (!sc->sc_opened) {
+ KASSERT(!(tp->t_state & TS_ISOPEN), ("foo"));
+ return (0);
+ }
+ KASSERT(tp->t_state & TS_ISOPEN, ("foo"));
+
+ if (sc->sc_hwiflow)
+ UART_IOCTL(sc, UART_IOCTL_IFLOW, 0);
+ if (sc->sc_hwoflow)
+ UART_IOCTL(sc, UART_IOCTL_OFLOW, 0);
+ if (sc->sc_sysdev == NULL)
+ UART_SETSIG(sc, UART_SIG_DDTR | UART_SIG_DRTS);
+
+ (*linesw[tp->t_line].l_close)(tp, flags);
+ ttyclose(tp);
+ wakeup(sc);
+ wakeup(TSA_CARR_ON(tp));
+ KASSERT(!(tp->t_state & TS_ISOPEN), ("foo"));
+ sc->sc_opened = 0;
+ return (0);
+}
+
+static int
+uart_tty_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
+ struct thread *td)
+{
+ struct uart_softc *sc;
+ struct tty *tp;
+ int bits, error, sig;
+
+ sc = dev->si_drv1;
+ if (sc == NULL || sc->sc_leaving)
+ return (ENODEV);
+
+ tp = dev->si_tty;
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, td);
+ if (error != ENOIOCTL)
+ return (error);
+ error = ttioctl(tp, cmd, data, flags);
+ if (error != ENOIOCTL)
+ return (error);
+
+ switch (cmd) {
+ case TIOCSBRK:
+ UART_IOCTL(sc, UART_IOCTL_BREAK, 1);
+ break;
+ case TIOCCBRK:
+ UART_IOCTL(sc, UART_IOCTL_BREAK, 0);
+ break;
+ case TIOCSDTR:
+ UART_SETSIG(sc, UART_SIG_DDTR | UART_SIG_DTR);
+ break;
+ case TIOCCDTR:
+ UART_SETSIG(sc, UART_SIG_DDTR);
+ break;
+ case TIOCMSET:
+ bits = *(int*)data;
+ sig = UART_SIG_DDTR | UART_SIG_DRTS;
+ if (bits & TIOCM_DTR)
+ sig |= UART_SIG_DTR;
+ if (bits & TIOCM_RTS)
+ sig |= UART_SIG_RTS;
+ UART_SETSIG(sc, sig);
+ break;
+ case TIOCMBIS:
+ bits = *(int*)data;
+ sig = 0;
+ if (bits & TIOCM_DTR)
+ sig |= UART_SIG_DDTR | UART_SIG_DTR;
+ if (bits & TIOCM_RTS)
+ sig |= UART_SIG_DRTS | UART_SIG_RTS;
+ UART_SETSIG(sc, sig);
+ break;
+ case TIOCMBIC:
+ bits = *(int*)data;
+ sig = 0;
+ if (bits & TIOCM_DTR)
+ sig |= UART_SIG_DDTR;
+ if (bits & TIOCM_RTS)
+ sig |= UART_SIG_DRTS;
+ UART_SETSIG(sc, sig);
+ break;
+ case TIOCMGET:
+ sig = sc->sc_hwsig;
+ bits = TIOCM_LE;
+ if (sig & UART_SIG_DTR)
+ bits |= TIOCM_DTR;
+ if (sig & UART_SIG_RTS)
+ bits |= TIOCM_RTS;
+ if (sig & UART_SIG_DSR)
+ bits |= TIOCM_DSR;
+ if (sig & UART_SIG_CTS)
+ bits |= TIOCM_CTS;
+ if (sig & UART_SIG_DCD)
+ bits |= TIOCM_CD;
+ if (sig & (UART_SIG_DRI | UART_SIG_RI))
+ bits |= TIOCM_RI;
+ *(int*)data = bits;
+ break;
+ default:
+ return (ENOTTY);
+ }
+ return (0);
+}
OpenPOWER on IntegriCloud