summaryrefslogtreecommitdiffstats
path: root/sys/dev/uart
diff options
context:
space:
mode:
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