summaryrefslogtreecommitdiffstats
path: root/drivers/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/Kconfig78
-rw-r--r--drivers/serial/Makefile10
-rw-r--r--drivers/serial/amba-pl011.c67
-rw-r--r--drivers/serial/arm_dcc.c27
-rw-r--r--drivers/serial/atmel.c28
-rw-r--r--drivers/serial/efi-stdio.c448
-rw-r--r--drivers/serial/efi-stdio.h58
-rw-r--r--drivers/serial/linux_console.c24
-rw-r--r--drivers/serial/serial_altera.c107
-rw-r--r--drivers/serial/serial_altera_jtag.c112
-rw-r--r--drivers/serial/serial_ar933x.c22
-rw-r--r--drivers/serial/serial_ar933x.h5
-rw-r--r--drivers/serial/serial_auart.c20
-rw-r--r--drivers/serial/serial_cadence.c70
-rw-r--r--drivers/serial/serial_clps711x.c68
-rw-r--r--drivers/serial/serial_digic.c19
-rw-r--r--drivers/serial/serial_efi.c5
-rw-r--r--drivers/serial/serial_imx.c43
-rw-r--r--drivers/serial/serial_litex.c100
-rw-r--r--drivers/serial/serial_lpuart.c25
-rw-r--r--drivers/serial/serial_lpuart32.c188
-rw-r--r--drivers/serial/serial_mpc5xxx.c29
-rw-r--r--drivers/serial/serial_ns16550.c261
-rw-r--r--drivers/serial/serial_ns16550.h13
-rw-r--r--drivers/serial/serial_ns16550_pci.c5305
-rw-r--r--drivers/serial/serial_omap4_usbboot.c24
-rw-r--r--drivers/serial/serial_pl010.c34
-rw-r--r--drivers/serial/serial_pl010.h26
-rw-r--r--drivers/serial/serial_pxa.c18
-rw-r--r--drivers/serial/serial_s3c.c209
-rw-r--r--drivers/serial/serial_sbi.c58
-rw-r--r--drivers/serial/serial_sifive.c173
-rw-r--r--drivers/serial/serial_stm32.c17
-rw-r--r--drivers/serial/serial_stm32.h2
-rw-r--r--drivers/serial/stm-serial.c22
-rw-r--r--drivers/serial/virtio_console.c180
36 files changed, 6682 insertions, 1213 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 7a411d456e..60b0e5f1dc 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
menu "serial drivers"
depends on !CONSOLE_NONE
@@ -30,7 +31,7 @@ config DRIVER_SERIAL_AR933X
config DRIVER_SERIAL_EFI
bool "EFI serial"
- depends on EFI_BOOTUP
+ depends on EFI_PAYLOAD
config DRIVER_SERIAL_IMX
depends on ARCH_IMX
@@ -38,8 +39,8 @@ config DRIVER_SERIAL_IMX
bool "i.MX serial driver"
config DRIVER_SERIAL_STM32
- depends on ARCH_STM32MP
- bool "stm32mp serial driver"
+ depends on ARCH_STM32
+ bool "stm32 serial driver"
config DRIVER_SERIAL_STM378X
depends on ARCH_MXS
@@ -48,15 +49,16 @@ config DRIVER_SERIAL_STM378X
config DRIVER_SERIAL_AUART
depends on ARCH_MXS
+ select STMP_DEVICE
bool "i.MX23/i.MX28 application UART serial driver"
config DRIVER_SERIAL_LINUX_CONSOLE
- depends on LINUX
+ depends on SANDBOX
default y
bool "linux console driver"
config DRIVER_SERIAL_EFI_STDIO
- depends on EFI_BOOTUP
+ depends on EFI_PAYLOAD
bool "EFI stdio driver"
config DRIVER_SERIAL_MPC5XXX
@@ -69,16 +71,6 @@ config DRIVER_SERIAL_CLPS711X
default y
bool "CLPS711X serial driver"
-config DRIVER_SERIAL_ALTERA
- depends on NIOS2
- default y
- bool "Altera serial driver"
-
-config DRIVER_SERIAL_ALTERA_JTAG
- depends on NIOS2
- default n
- bool "Altera JTAG serial driver"
-
config DRIVER_SERIAL_NS16550
default n
bool "NS16550 serial driver"
@@ -90,12 +82,13 @@ config DRIVER_SERIAL_ATMEL
default y
bool "Atmel serial driver"
-config DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
- bool "OMAP Extensions for NS16550"
+config DRIVER_SERIAL_NS16550_PCI
depends on DRIVER_SERIAL_NS16550
- depends on ARCH_OMAP
+ depends on PCI
+ default y
+ bool "NS16550 PCI serial driver"
help
- Say Y here if you are using OMAP extensions to NS16550
+ Enable this to get support for NS16550 UARTs connected over PCI
config DRIVER_SERIAL_PL010
depends on ARCH_EP93XX
@@ -104,24 +97,6 @@ config DRIVER_SERIAL_PL010
help
Enable this to get support for AMBA PL010 based serial devices
-config DRIVER_SERIAL_S3C_IMPROVED
- bool
-
-config DRIVER_SERIAL_S3C
- bool "Samsung S3C serial driver"
- depends on ARCH_SAMSUNG
- select DRIVER_SERIAL_S3C_IMPROVED if (CPU_S5PC110 || CPU_S5PV210 || CPU_S3C6410)
- default y
- help
- Say Y here if you want to use the CONS on a Samsung S3C CPU
-
-config DRIVER_SERIAL_S3C_AUTOSYNC
- bool "Enable auto flow"
- depends on DRIVER_SERIAL_S3C
- help
- Say Y here if you want to use the auto flow feature of this
- UART. RTS and CTS will be handled by the hardware when enabled.
-
config DRIVER_SERIAL_PXA
bool "PXA serial driver"
depends on ARCH_PXA
@@ -147,4 +122,33 @@ config DRIVER_SERIAL_LPUART
default y
bool "LPUART serial driver"
+config DRIVER_SERIAL_LPUART32
+ depends on ARCH_IMX
+ bool "LPUART32 serial driver"
+
+config VIRTIO_CONSOLE
+ tristate "Virtio console"
+ depends on VIRTIO
+ help
+ Virtio console for use with hypervisors.
+
+ Also serves as a general-purpose serial device for data
+ transfer between the guest and host.
+
+config SERIAL_SIFIVE
+ tristate "SiFive UART support"
+ depends on OFDEVICE
+ help
+ Select this option if you are building barebox for a device that
+ contains a SiFive UART IP block. This type of UART is present on
+ SiFive FU540 SoCs, among others.
+
+config SERIAL_SBI
+ tristate "RISCV Serial support over SBI's HTIF"
+ depends on OFDEVICE
+ depends on RISCV_SBI
+ help
+ Select this option if you are building barebox for a RISCV platform
+ that implements a serial over SBI.
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 6f9e3b7835..4887e24ee1 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_DRIVER_SERIAL_ARM_DCC) += arm_dcc.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_DRIVER_SERIAL_AR933X) += serial_ar933x.o
@@ -9,11 +10,9 @@ obj-$(CONFIG_DRIVER_SERIAL_LINUX_CONSOLE) += linux_console.o
obj-$(CONFIG_DRIVER_SERIAL_MPC5XXX) += serial_mpc5xxx.o
obj-$(CONFIG_DRIVER_SERIAL_CLPS711X) += serial_clps711x.o
obj-$(CONFIG_DRIVER_SERIAL_NS16550) += serial_ns16550.o
+obj-$(CONFIG_DRIVER_SERIAL_NS16550_PCI) += serial_ns16550_pci.o
obj-$(CONFIG_DRIVER_SERIAL_PL010) += serial_pl010.o
-obj-$(CONFIG_DRIVER_SERIAL_S3C) += serial_s3c.o
obj-$(CONFIG_DRIVER_SERIAL_STM32) += serial_stm32.o
-obj-$(CONFIG_DRIVER_SERIAL_ALTERA) += serial_altera.o
-obj-$(CONFIG_DRIVER_SERIAL_ALTERA_JTAG) += serial_altera_jtag.o
obj-$(CONFIG_DRIVER_SERIAL_PXA) += serial_pxa.o
obj-$(CONFIG_DRIVER_SERIAL_OMAP4_USBBOOT) += serial_omap4_usbboot.o
obj-$(CONFIG_DRIVER_SERIAL_AUART) += serial_auart.o
@@ -21,3 +20,8 @@ obj-$(CONFIG_DRIVER_SERIAL_CADENCE) += serial_cadence.o
obj-$(CONFIG_DRIVER_SERIAL_EFI_STDIO) += efi-stdio.o
obj-$(CONFIG_DRIVER_SERIAL_DIGIC) += serial_digic.o
obj-$(CONFIG_DRIVER_SERIAL_LPUART) += serial_lpuart.o
+obj-$(CONFIG_DRIVER_SERIAL_LPUART32) += serial_lpuart32.o
+obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
+obj-$(CONFIG_SERIAL_SIFIVE) += serial_sifive.o
+obj-$(CONFIG_SERIAL_SBI) += serial_sbi.o
+obj-$(CONFIG_SOC_LITEX) += serial_litex.o
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 9b567e3cd2..b53ff6877b 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright 2000
* Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
@@ -5,20 +6,6 @@
* (C) Copyright 2004
* ARM Ltd.
* Philippe Robin, <philippe.robin@arm.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
/* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */
@@ -67,6 +54,23 @@ to_amba_uart_port(struct console_device *uart)
return container_of(uart, struct amba_uart_port, uart);
}
+static void pl011_rlcr(struct amba_uart_port *uart, u32 lcr)
+{
+ struct vendor_data *vendor = uart->vendor;
+
+ writew(lcr, uart->base + vendor->lcrh_rx);
+ if (vendor->lcrh_tx != vendor->lcrh_rx) {
+ int i;
+ /*
+ * Wait 10 PCLKs before writing LCRH_TX register,
+ * to get this delay write read only register 10 times
+ */
+ for (i = 0; i < 10; ++i)
+ writew(0xff, uart->base + UART011_MIS);
+ writew(lcr, uart->base + vendor->lcrh_tx);
+ }
+}
+
static int pl011_setbaudrate(struct console_device *cdev, int baudrate)
{
struct amba_uart_port *uart = to_amba_uart_port(cdev);
@@ -74,6 +78,7 @@ static int pl011_setbaudrate(struct console_device *cdev, int baudrate)
unsigned int divider;
unsigned int remainder;
unsigned int fraction;
+ uint32_t cr;
/*
** Set baud rate
@@ -87,9 +92,15 @@ static int pl011_setbaudrate(struct console_device *cdev, int baudrate)
temp = (8 * remainder) / baudrate;
fraction = (temp >> 1) + (temp & 1);
+ cr = readl(uart->base + UART011_CR);
+ writel(0x0, uart->base + UART011_CR);
+
writel(divider, uart->base + UART011_IBRD);
writel(fraction, uart->base + UART011_FBRD);
+ pl011_rlcr(uart, UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN);
+ writel(cr, uart->base + UART011_CR);
+
return 0;
}
@@ -131,23 +142,6 @@ static int pl011_tstc(struct console_device *cdev)
return !(readl(uart->base + UART01x_FR) & UART01x_FR_RXFE);
}
-static void pl011_rlcr(struct amba_uart_port *uart, u32 lcr)
-{
- struct vendor_data *vendor = uart->vendor;
-
- writew(lcr, uart->base + vendor->lcrh_rx);
- if (vendor->lcrh_tx != vendor->lcrh_rx) {
- int i;
- /*
- * Wait 10 PCLKs before writing LCRH_TX register,
- * to get this delay write read only register 10 times
- */
- for (i = 0; i < 10; ++i)
- writew(0xff, uart->base + UART011_MIS);
- writew(lcr, uart->base + vendor->lcrh_tx);
- }
-}
-
static int pl011_init_port(struct console_device *cdev)
{
struct amba_uart_port *uart = to_amba_uart_port(cdev);
@@ -207,6 +201,9 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
cdev->putc = pl011_putc;
cdev->getc = pl011_getc;
cdev->setbrg = pl011_setbaudrate;
+ cdev->linux_console_name = "ttyAMA";
+ cdev->linux_earlycon_name = "pl011";
+ cdev->phys_base = uart->base;
pl011_init_port(cdev);
@@ -239,10 +236,4 @@ struct amba_driver pl011_driver = {
.id_table = pl011_ids,
};
-static int pl011_init(void)
-{
- amba_driver_register(&pl011_driver);
- return 0;
-}
-
-console_initcall(pl011_init);
+console_amba_driver(pl011_driver);
diff --git a/drivers/serial/arm_dcc.c b/drivers/serial/arm_dcc.c
index e5f2bbe5e2..1e2b4e425c 100644
--- a/drivers/serial/arm_dcc.c
+++ b/drivers/serial/arm_dcc.c
@@ -1,26 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH eCos-exception-2.0 */
/*
* Copyright (C) 2004-2007 ARM Limited.
* Copyright (C) 2008 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
- * As a special exception, if other files instantiate templates or use macros
- * or inline functions from this file, or you compile this file and link it
- * with other works to produce a work based on this file, this file does not
- * by itself cause the resulting work to be covered by the GNU General Public
- * License. However the source code for this file must still be made available
- * in accordance with section (3) of the GNU General Public License.
-
- * This exception does not invalidate any other reasons why a work based on
- * this file might be covered by the GNU General Public License.
*/
#include <common.h>
@@ -127,7 +108,7 @@ static int arm_dcc_tstc(struct console_device *cdev)
static struct console_device arm_dcc_dev;
-static int arm_dcc_probe(struct device_d *dev)
+static int arm_dcc_probe(struct device *dev)
{
struct console_device *cdev;
@@ -144,13 +125,13 @@ static int arm_dcc_probe(struct device_d *dev)
return 0;
}
-static struct driver_d arm_dcc_driver = {
+static struct driver arm_dcc_driver = {
.name = "arm_dcc",
.probe = arm_dcc_probe,
};
console_platform_driver(arm_dcc_driver);
-static struct device_d arm_dcc_device = {
+static struct device arm_dcc_device = {
.id = DEVICE_ID_DYNAMIC,
.name = "arm_dcc",
};
diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c
index 8394273f9f..b957b75284 100644
--- a/drivers/serial/atmel.c
+++ b/drivers/serial/atmel.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <common.h>
@@ -395,7 +384,7 @@ static int atmel_serial_set_mode(struct console_device *cdev, enum console_mode
*/
static int atmel_serial_init_port(struct console_device *cdev)
{
- struct device_d *dev = cdev->dev;
+ struct device *dev = cdev->dev;
struct atmel_uart_port *uart = to_atmel_uart_port(cdev);
uart->base = dev_request_mem_region_err_null(dev, 0);
@@ -423,10 +412,11 @@ static int atmel_serial_init_port(struct console_device *cdev)
return 0;
}
-static int atmel_serial_probe(struct device_d *dev)
+static int atmel_serial_probe(struct device *dev)
{
struct atmel_uart_port *uart;
struct console_device *cdev;
+ int ret;
uart = xzalloc(sizeof(struct atmel_uart_port));
cdev = &uart->uart;
@@ -437,8 +427,13 @@ static int atmel_serial_probe(struct device_d *dev)
cdev->setbrg = atmel_serial_setbaudrate;
cdev->set_mode = atmel_serial_set_mode;
cdev->linux_console_name = "ttyAT";
+ cdev->linux_earlycon_name = "atmel_serial";
+
+ ret = atmel_serial_init_port(cdev);
+ if (ret)
+ return ret;
- atmel_serial_init_port(cdev);
+ cdev->phys_base = uart->base;
/* Enable UART */
@@ -452,8 +447,9 @@ static const struct of_device_id __maybe_unused atmel_serial_dt_ids[] = {
{ .compatible = "atmel,at91sam9260-usart" },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, atmel_serial_dt_ids);
-static struct driver_d atmel_serial_driver = {
+static struct driver atmel_serial_driver = {
.name = "atmel_usart",
.probe = atmel_serial_probe,
.of_compatible = DRV_OF_COMPAT(atmel_serial_dt_ids),
diff --git a/drivers/serial/efi-stdio.c b/drivers/serial/efi-stdio.c
index 9e825181e6..92133f8378 100644
--- a/drivers/serial/efi-stdio.c
+++ b/drivers/serial/efi-stdio.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* efi_console.c - EFI console support
*
* Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
#include <driver.h>
@@ -25,63 +13,32 @@
#include <efi.h>
#include <readkey.h>
#include <linux/ctype.h>
-#include <efi/efi.h>
+#include <efi/efi-payload.h>
+#include <kfifo.h>
#include <efi/efi-device.h>
-#include "efi-stdio.h"
-
-#define EFI_SHIFT_STATE_VALID 0x80000000
-#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
-#define EFI_LEFT_CONTROL_PRESSED 0x00000008
-#define EFI_RIGHT_ALT_PRESSED 0x00000010
-#define EFI_LEFT_ALT_PRESSED 0x00000020
-
-#define EFI_CONTROL_PRESSED (EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED)
-#define EFI_ALT_PRESSED (EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED)
-#define KEYPRESS(keys, scan, uni) ((((uint64_t)keys) << 32) | ((scan) << 16) | (uni))
-#define KEYCHAR(k) ((k) & 0xffff)
-#define CHAR_CTRL(c) ((c) - 'a' + 1)
-
-#define EFI_BLACK 0x00
-#define EFI_BLUE 0x01
-#define EFI_GREEN 0x02
-#define EFI_CYAN (EFI_BLUE | EFI_GREEN)
-#define EFI_RED 0x04
-#define EFI_MAGENTA (EFI_BLUE | EFI_RED)
-#define EFI_BROWN (EFI_GREEN | EFI_RED)
-#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED)
-#define EFI_BRIGHT 0x08
-#define EFI_DARKGRAY (EFI_BRIGHT)
-#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT)
-#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT)
-#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT)
-#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT)
-#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT)
-#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT)
-#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT)
-
-#define EFI_TEXT_ATTR(f,b) ((f) | ((b) << 4))
-
-#define EFI_BACKGROUND_BLACK 0x00
-#define EFI_BACKGROUND_BLUE 0x10
-#define EFI_BACKGROUND_GREEN 0x20
-#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN)
-#define EFI_BACKGROUND_RED 0x40
-#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED)
-#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED)
-#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED)
+#include <efi/efi-stdio.h>
struct efi_console_priv {
struct efi_simple_text_output_protocol *out;
- struct efi_simple_input_interface *in;
+ struct efi_simple_text_input_protocol *in;
struct efi_simple_text_input_ex_protocol *inex;
struct console_device cdev;
- int lastkey;
- u16 efi_console_buffer[CONFIG_CBSIZE];
+ u16 efi_console_buffer[CONFIG_CBSIZE + 1];
+ int pos;
+
+ struct kfifo *inputbuffer;
unsigned long columns, rows;
- int current_color;
+ int fg;
+ int bg;
+ bool inverse;
s16 *blank_line;
+
+ struct param_d *param_mode;
+ const char **mode_names;
+ int *mode_num;
+ unsigned int var_mode;
};
static inline struct efi_console_priv *to_efi(struct console_device *cdev)
@@ -122,17 +79,23 @@ static int xlate_keypress(struct efi_input_key *k)
return k->unicode_char & 0xff;
}
+static void efi_wait_single_event(struct efi_event *event)
+{
+ size_t index;
+
+ /* wait until key is pressed */
+ BS->wait_for_event(1, &event, &index);
+}
+
static int efi_read_key(struct efi_console_priv *priv, bool wait)
{
- unsigned long index;
efi_status_t efiret;
struct efi_key_data kd;
- /* wait until key is pressed */
- if (wait)
- BS->wait_for_event(1, priv->in->wait_for_key, &index);
-
if (priv->inex) {
+ if (wait)
+ efi_wait_single_event(priv->inex->wait_for_key_ex);
+
efiret = priv->inex->read_key_stroke_ex(priv->inex, &kd);
if (efiret == EFI_NOT_READY)
@@ -161,6 +124,9 @@ static int efi_read_key(struct efi_console_priv *priv, bool wait)
}
}
+ if (wait)
+ efi_wait_single_event(priv->in->wait_for_key);
+
efiret = priv->in->read_key_stroke(priv->in, &kd.key);
if (EFI_ERROR(efiret))
@@ -169,148 +135,221 @@ static int efi_read_key(struct efi_console_priv *priv, bool wait)
return xlate_keypress(&kd.key);
}
-static void efi_console_putc(struct console_device *cdev, char c)
+static void clear_to_eol(struct efi_console_priv *priv)
{
- uint16_t str[2] = {};
- struct efi_console_priv *priv = to_efi(cdev);
- struct efi_simple_text_output_protocol *con_out = priv->out;
+ int pos = priv->out->mode->cursor_column;
- str[0] = c;
+ priv->out->output_string(priv->out, priv->blank_line + pos);
+}
- con_out->output_string(con_out, str);
+static int ansi_to_efi_color(int ansi)
+{
+ switch (ansi) {
+ case 30:
+ return EFI_BLACK;
+ case 31:
+ return EFI_RED;
+ case 32:
+ return EFI_GREEN;
+ case 33:
+ return EFI_YELLOW;
+ case 34:
+ return EFI_BLUE;
+ case 35:
+ return EFI_MAGENTA;
+ case 36:
+ return EFI_CYAN;
+ case 37:
+ return EFI_WHITE;
+ case 39:
+ return EFI_LIGHTGRAY;
+ }
+
+ return -1;
}
-static void clear_to_eol(struct efi_console_priv *priv)
+static void set_fg_bg_colors(struct efi_console_priv *priv)
{
- int pos = priv->out->mode->cursor_column;
+ int fg = priv->inverse ? priv->bg : priv->fg;
+ int bg = priv->inverse ? priv->fg : priv->bg;
- priv->out->output_string(priv->out, priv->blank_line + pos);
+ priv->out->set_attribute(priv->out, EFI_TEXT_ATTR(fg , bg));
}
static int efi_process_square_bracket(struct efi_console_priv *priv, const char *inp)
{
- int x, y;
char *endp;
+ int n, retlen;
+ int arg0 = -1, arg1 = -1, arg2 = -1;
+ char *buf;
- inp++;
-
- switch (*inp) {
- case 'A':
- /* Cursor up */
- case 'B':
- /* Cursor down */
- case 'C':
- /* Cursor right */
- case 'D':
- /* Cursor left */
- case 'H':
- /* home */
- case 'F':
- /* end */
- return 3;
- case 'K':
- clear_to_eol(priv);
- return 3;
- }
-
- if (*inp == '2' && *(inp + 1) == 'J') {
- priv->out->clear_screen(priv->out);
- return 4;
- }
+ endp = strpbrk(inp, "ABCDEFGHJKmrnhl");
+ if (!endp)
+ return 0;
- if (*inp == '0' && *(inp + 1) == 'm') {
- priv->out->set_attribute(priv->out,
- EFI_TEXT_ATTR(EFI_WHITE, EFI_BLACK));
- return 4;
- }
+ retlen = endp - inp + 1;
- if (*inp == '7' && *(inp + 1) == 'm') {
- priv->out->set_attribute(priv->out,
- EFI_TEXT_ATTR(EFI_BLACK, priv->current_color));
- return 4;
- }
+ inp++;
- if (*inp == '1' &&
- *(inp + 1) == ';' &&
- *(inp + 2) == '3' &&
- *(inp + 3) &&
- *(inp + 4) == 'm') {
- int color;
- switch (*(inp + 3)) {
- case '1': color = EFI_RED; break;
- case '4': color = EFI_BLUE; break;
- case '2': color = EFI_GREEN; break;
- case '6': color = EFI_CYAN; break;
- case '3': color = EFI_YELLOW; break;
- case '5': color = EFI_MAGENTA; break;
- case '7': color = EFI_WHITE; break;
- default: color = EFI_WHITE; break;
+ if (isdigit(*inp)) {
+ char *e;
+ arg0 = simple_strtoul(inp, &e, 10);
+ if (*e == ';') {
+ arg1 = simple_strtoul(e + 1, &e, 10);
+ if (*e == ';')
+ arg2 = simple_strtoul(e + 1, &e, 10);
}
-
- priv->current_color = color;
-
- priv->out->set_attribute(priv->out,
- EFI_TEXT_ATTR(color, EFI_BLACK));
- return 7;
+ } else if (*inp == '?') {
+ arg0 = simple_strtoul(inp + 1, NULL, 10);
}
- y = simple_strtoul(inp, &endp, 10);
- if (*endp == ';') {
- x = simple_strtoul(endp + 1, &endp, 10);
- if (*endp == 'H') {
- priv->out->set_cursor_position(priv->out, x - 1, y - 1);
- return endp - inp + 3;
+ switch (*endp) {
+ case 'K':
+ switch (arg0) {
+ case 0:
+ case -1:
+ clear_to_eol(priv);
+ break;
+ }
+ break;
+ case 'J':
+ switch (arg0) {
+ case 2:
+ priv->out->clear_screen(priv->out);
+ break;
+ }
+ break;
+ case 'H':
+ if (arg0 >= 0 && arg1 >= 0) {
+ int row = min_t(int, arg0, priv->rows);
+ int col = min_t(int, arg1, priv->columns);
+ priv->out->set_cursor_position(priv->out, col - 1, row - 1);
+ }
+ break;
+ case 'm':
+ switch (arg0) {
+ case 0:
+ priv->inverse = false;
+ priv->fg = EFI_LIGHTGRAY;
+ priv->bg = EFI_BLACK;
+ set_fg_bg_colors(priv);
+ break;
+ case 7:
+ priv->inverse = true;
+ set_fg_bg_colors(priv);
+ break;
+ case 1:
+ priv->fg = ansi_to_efi_color(arg1);
+ if (priv->fg < 0)
+ priv->fg = EFI_LIGHTGRAY;
+ priv->bg = ansi_to_efi_color(arg2);
+ if (priv->bg < 0)
+ priv->bg = EFI_BLACK;
+ set_fg_bg_colors(priv);
+ break;
}
+ break;
+ case 'n':
+ switch (arg0) {
+ case 6:
+ n = asprintf(&buf, "\033[%d;%dR", priv->out->mode->cursor_row + 1,
+ priv->out->mode->cursor_column + 1);
+ kfifo_put(priv->inputbuffer, buf, n);
+ free(buf);
+ break;
+ }
+ break;
+ case 'h':
+ if (*inp == '?' && arg0 == 25)
+ priv->out->enable_cursor(priv->out, true);
+ break;
+ case 'l':
+ if (*inp == '?' && arg0 == 25)
+ priv->out->enable_cursor(priv->out, false);
+ break;
}
- return 8;
+ return retlen;
}
-static int efi_process_key(struct efi_console_priv *priv, const char *inp)
+static int efi_process_escape(struct efi_console_priv *priv, const char *inp)
{
char c;
c = *inp;
- if (c != 27)
- return 0;
-
inp++;
if (*inp == '[')
- return efi_process_square_bracket(priv, inp);
+ return efi_process_square_bracket(priv, inp) + 1;
return 1;
}
+static void efi_console_add_char(struct efi_console_priv *priv, int c)
+{
+ if (priv->pos >= CONFIG_CBSIZE)
+ return;
+
+ priv->efi_console_buffer[priv->pos] = c;
+ priv->pos++;
+}
+
+static void efi_console_flush(struct efi_console_priv *priv)
+{
+ priv->efi_console_buffer[priv->pos] = 0;
+
+ priv->out->output_string(priv->out, priv->efi_console_buffer);
+
+ priv->pos = 0;
+}
+
static int efi_console_puts(struct console_device *cdev, const char *s,
size_t nbytes)
{
struct efi_console_priv *priv = to_efi(cdev);
- int n = 0;
-
- while (nbytes--) {
- if (*s == 27) {
- priv->efi_console_buffer[n] = 0;
- priv->out->output_string(priv->out,
- priv->efi_console_buffer);
- n = 0;
- s += efi_process_key(priv, s);
- continue;
+ int n, pos = 0;
+
+ while (pos < nbytes) {
+ switch (s[pos]) {
+ case 27:
+ efi_console_flush(priv);
+ pos += efi_process_escape(priv, s + pos);
+ break;
+ case '\n':
+ efi_console_add_char(priv, '\r');
+ efi_console_add_char(priv, '\n');
+ pos++;
+ break;
+ case '\t':
+ efi_console_flush(priv);
+ n = 8 - priv->out->mode->cursor_column % 8;
+ while (n--)
+ efi_console_add_char(priv, ' ');
+ pos++;
+ break;
+ case '\b':
+ n = priv->out->mode->cursor_column;
+ if (n > 0)
+ priv->out->set_cursor_position(priv->out,
+ n - 1, priv->out->mode->cursor_row);
+ pos++;
+ break;
+ default:
+ efi_console_add_char(priv, s[pos]);
+ pos++;
+ break;
}
-
- if (*s == '\n')
- priv->efi_console_buffer[n++] = '\r';
- priv->efi_console_buffer[n] = *s;
- s++;
- n++;
}
- priv->efi_console_buffer[n] = 0;
+ efi_console_flush(priv);
- priv->out->output_string(priv->out, priv->efi_console_buffer);
+ return nbytes;
+}
- return n;
+static void efi_console_putc(struct console_device *cdev, char c)
+{
+ efi_console_puts(cdev, &c, 1);
}
static int efi_console_tstc(struct console_device *cdev)
@@ -318,14 +357,14 @@ static int efi_console_tstc(struct console_device *cdev)
struct efi_console_priv *priv = to_efi(cdev);
int key;
- if (priv->lastkey > 0)
+ if (kfifo_len(priv->inputbuffer))
return 1;
key = efi_read_key(priv, 0);
if (key < 0)
return 0;
- priv->lastkey = key;
+ kfifo_putc(priv->inputbuffer, key);
return 1;
}
@@ -333,58 +372,74 @@ static int efi_console_tstc(struct console_device *cdev)
static int efi_console_getc(struct console_device *cdev)
{
struct efi_console_priv *priv = to_efi(cdev);
- int key;
+ unsigned char c;
- if (priv->lastkey > 0) {
- key = priv->lastkey;
- priv->lastkey = -1;
- return key;
- }
+ if (!kfifo_getc(priv->inputbuffer, &c))
+ return c;
return efi_read_key(priv, 1);
}
+static int efi_console_set_mode(struct param_d *param, void *p)
+{
+ struct efi_console_priv *priv = p;
+
+ priv->out->set_mode(priv->out, priv->mode_num[priv->var_mode]);
+
+ priv->out->query_mode(priv->out, priv->out->mode->mode,
+ &priv->columns, &priv->rows);
+ return 0;
+}
+
static void efi_set_mode(struct efi_console_priv *priv)
{
-#if 0
int i;
- unsigned long rows, columns, best = 0, mode = 0;
+ unsigned long rows, columns;
+ int n = 0;
efi_status_t efiret;
+ priv->mode_names = xzalloc(priv->out->mode->max_mode * sizeof(*priv->mode_names));
+ priv->mode_num = xzalloc(priv->out->mode->max_mode * sizeof(*priv->mode_num));
+
+ priv->out->query_mode(priv->out, priv->out->mode->mode, &priv->columns, &priv->rows);
+
for (i = 0; i < priv->out->mode->max_mode; i++) {
- priv->out->query_mode(priv->out, i, &columns, &rows);
- printf("%d: %ld %ld\n", i, columns, rows);
- if (rows * columns > best) {
- best = rows * columns;
- mode = i;
- }
+ efiret = priv->out->query_mode(priv->out, i, &columns, &rows);
+ if (EFI_ERROR(efiret))
+ continue;
+
+ if (columns == priv->columns && rows == priv->rows)
+ priv->var_mode = n;
+
+ priv->mode_names[n] = basprintf("%ldx%ld", columns, rows);
+ priv->mode_num[n] = i;
+ n++;
}
- /*
- * Setting the mode doesn't work as expected. set_mode succeeds, but
- * the graphics resolution is not changed.
- */
- priv->out->set_mode(priv->out, mode);
-#endif
- priv->out->query_mode(priv->out, priv->out->mode->mode, &priv->columns, &priv->rows);
+ priv->param_mode = dev_add_param_enum(&priv->cdev.class_dev, "mode",
+ efi_console_set_mode, NULL, &priv->var_mode,
+ priv->mode_names, n, priv);
}
-static int efi_console_probe(struct device_d *dev)
+static int efi_console_probe(struct device *dev)
{
efi_guid_t inex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
struct efi_simple_text_input_ex_protocol *inex;
struct console_device *cdev;
struct efi_console_priv *priv;
efi_status_t efiret;
-
- int i;
+ int i, ret;
priv = xzalloc(sizeof(*priv));
priv->out = efi_sys_table->con_out;
priv->in = efi_sys_table->con_in;
- efiret = BS->open_protocol((void *)efi_sys_table->con_in_handle,
+ priv->inputbuffer = kfifo_alloc(128);
+ if (!priv->inputbuffer)
+ return -ENOMEM;
+
+ efiret = BS->open_protocol(efi_sys_table->con_in_handle,
&inex_guid,
(void **)&inex,
efi_parent_image,
@@ -396,9 +451,8 @@ static int efi_console_probe(struct device_d *dev)
dev_dbg(dev, "Using simple_text_input_ex_protocol\n");
}
- priv->current_color = EFI_WHITE;
-
- efi_set_mode(priv);
+ priv->fg = EFI_LIGHTGRAY;
+ priv->bg = EFI_BLACK;
priv->out->enable_cursor(priv->out, 1);
@@ -413,12 +467,16 @@ static int efi_console_probe(struct device_d *dev)
cdev->putc = efi_console_putc;
cdev->puts = efi_console_puts;
- priv->lastkey = -1;
+ ret = console_register(cdev);
+ if (ret)
+ return ret;
+
+ efi_set_mode(priv);
- return console_register(cdev);
+ return 0;
}
-static struct driver_d efi_console_driver = {
+static struct driver efi_console_driver = {
.name = "efi-stdio",
.probe = efi_console_probe,
};
diff --git a/drivers/serial/efi-stdio.h b/drivers/serial/efi-stdio.h
deleted file mode 100644
index 1fa417c706..0000000000
--- a/drivers/serial/efi-stdio.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef EFI_STDIO_H_
-#define EFI_STDIO_H_
-
-#include <efi.h>
-
-struct efi_simple_text_input_ex_protocol;
-
-typedef efi_status_t (EFIAPI *efi_input_reset_ex)(
- struct efi_simple_text_input_ex_protocol *this,
- efi_bool_t extended_verification
-);
-
-struct efi_key_state {
- u32 shift_state;
- u8 toggle_state;
-};
-
-struct efi_key_data {
- struct efi_input_key key;
- struct efi_key_state state;
-};
-
-typedef efi_status_t (EFIAPI *efi_input_read_key_ex)(
- struct efi_simple_text_input_ex_protocol *this,
- struct efi_key_data *keydata
-);
-
-typedef efi_status_t (EFIAPI *efi_set_state)(
- struct efi_simple_text_input_ex_protocol *this,
- u8 *key_toggle_state
-);
-
-typedef efi_status_t (EFIAPI *efi_key_notify_function)(
- struct efi_key_data *keydata
-);
-
-typedef efi_status_t (EFIAPI *efi_register_keystroke_notify)(
- struct efi_simple_text_input_ex_protocol *this,
- struct efi_key_data keydata,
- efi_key_notify_function key_notification_function,
- void **notify_handle
-);
-
-typedef efi_status_t (EFIAPI *efi_unregister_keystroke_notify)(
- struct efi_simple_text_input_ex_protocol *this,
- void *notification_handle
-);
-
-struct efi_simple_text_input_ex_protocol {
- efi_input_reset_ex reset;
- efi_input_read_key_ex read_key_stroke_ex;
- void *wait_for_key_ex;
- efi_set_state set_state;
- efi_register_keystroke_notify register_key_notify;
- efi_unregister_keystroke_notify unregister_key_notify;
-};
-
-#endif
diff --git a/drivers/serial/linux_console.c b/drivers/serial/linux_console.c
index 0d5da9d1b0..b8303dfd12 100644
--- a/drivers/serial/linux_console.c
+++ b/drivers/serial/linux_console.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux_console.c - Use stdin/stdout as a console device
*
* Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -27,7 +15,7 @@
static void linux_console_putc(struct console_device *cdev, char c)
{
- struct device_d *dev = cdev->dev;
+ struct device *dev = cdev->dev;
struct linux_console_data *d = dev->platform_data;
linux_write(d->stdoutfd, &c, 1);
@@ -35,7 +23,7 @@ static void linux_console_putc(struct console_device *cdev, char c)
static int linux_console_tstc(struct console_device *cdev)
{
- struct device_d *dev = cdev->dev;
+ struct device *dev = cdev->dev;
struct linux_console_data *d = dev->platform_data;
return linux_tstc(d->stdinfd);
@@ -43,7 +31,7 @@ static int linux_console_tstc(struct console_device *cdev)
static int linux_console_getc(struct console_device *cdev)
{
- struct device_d *dev = cdev->dev;
+ struct device *dev = cdev->dev;
struct linux_console_data *d = dev->platform_data;
static char old_c;
char c;
@@ -57,7 +45,7 @@ static int linux_console_getc(struct console_device *cdev)
return c;
}
-static int linux_console_probe(struct device_d *dev)
+static int linux_console_probe(struct device *dev)
{
struct console_device *cdev;
struct linux_console_data *data = dev->platform_data;
@@ -79,7 +67,7 @@ static int linux_console_probe(struct device_d *dev)
return 0;
}
-static struct driver_d linux_console_driver = {
+static struct driver linux_console_driver = {
.name = "console",
.probe = linux_console_probe,
};
diff --git a/drivers/serial/serial_altera.c b/drivers/serial/serial_altera.c
deleted file mode 100644
index 10d1506bca..0000000000
--- a/drivers/serial/serial_altera.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * (C) Copyright 2011, Franck JULLIEN, <elec4fun@gmail.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <common.h>
-#include <driver.h>
-#include <init.h>
-#include <malloc.h>
-#include <io.h>
-#include <asm/nios2-io.h>
-
-struct altera_serial_priv {
- struct console_device cdev;
- void __iomem *regs;
-};
-
-static int altera_serial_setbaudrate(struct console_device *cdev, int baudrate)
-{
- struct altera_serial_priv *priv = container_of(cdev,
- struct altera_serial_priv, cdev);
-
- struct nios_uart *uart = priv->regs;
- uint16_t div;
-
- div = (CPU_FREQ / baudrate) - 1;
- writew(div, &uart->divisor);
-
- return 0;
-}
-
-static void altera_serial_putc(struct console_device *cdev, char c)
-{
- struct altera_serial_priv *priv = container_of(cdev,
- struct altera_serial_priv, cdev);
-
- struct nios_uart *uart = priv->regs;
-
- while ((readw(&uart->status) & NIOS_UART_TRDY) == 0);
-
- writew(c, &uart->txdata);
-}
-
-static int altera_serial_tstc(struct console_device *cdev)
-{
- struct altera_serial_priv *priv = container_of(cdev,
- struct altera_serial_priv, cdev);
-
- struct nios_uart *uart = priv->regs;
-
- return readw(&uart->status) & NIOS_UART_RRDY;
-}
-
-static int altera_serial_getc(struct console_device *cdev)
-{
- struct altera_serial_priv *priv = container_of(cdev,
- struct altera_serial_priv, cdev);
-
- struct nios_uart *uart = priv->regs;
-
- while (altera_serial_tstc(cdev) == 0);
-
- return readw(&uart->rxdata) & 0x000000FF;
-}
-
-static int altera_serial_probe(struct device_d *dev)
-{
- struct resource *iores;
- struct console_device *cdev;
- struct altera_serial_priv *priv;
-
- priv = xzalloc(sizeof(*priv));
- cdev = &priv->cdev;
-
- iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- priv->regs = IOMEM(iores->start);
- cdev->dev = dev;
- cdev->tstc = altera_serial_tstc;
- cdev->putc = altera_serial_putc;
- cdev->getc = altera_serial_getc;
- cdev->setbrg = altera_serial_setbaudrate;
-
- console_register(cdev);
-
- return 0;
-}
-
-static struct driver_d altera_serial_driver = {
- .name = "altera_serial",
- .probe = altera_serial_probe,
-};
-console_platform_driver(altera_serial_driver);
diff --git a/drivers/serial/serial_altera_jtag.c b/drivers/serial/serial_altera_jtag.c
deleted file mode 100644
index 0164ea5eff..0000000000
--- a/drivers/serial/serial_altera_jtag.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
- * Scott McNutt <smcnutt@psyent.com>
- *
- * (C) Copyright 2011 - Franck JULLIEN <elec4fun@gmail.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <common.h>
-#include <driver.h>
-#include <init.h>
-#include <malloc.h>
-#include <io.h>
-#include <asm/nios2-io.h>
-
-struct altera_serial_jtag_priv {
- struct console_device cdev;
- void __iomem *regs;
-};
-
-
-static int altera_serial_jtag_setbaudrate(struct console_device *cdev, int baudrate)
-{
- return 0;
-}
-
-static void altera_serial_jtag_putc(struct console_device *cdev, char c)
-{
- struct altera_serial_jtag_priv *priv = container_of(cdev,
- struct altera_serial_jtag_priv, cdev);
-
- struct nios_jtag *jtag = priv->regs;
- uint32_t st;
-
- while (1) {
- st = readl(&jtag->control);
- if (NIOS_JTAG_WSPACE(st))
- break;
- }
-
- writel(c, &jtag->data);
-}
-
-static int altera_serial_jtag_tstc(struct console_device *cdev)
-{
- struct altera_serial_jtag_priv *priv = container_of(cdev,
- struct altera_serial_jtag_priv, cdev);
-
- struct nios_jtag *jtag = priv->regs;
-
- return readl(&jtag->control) & NIOS_JTAG_RRDY;
-}
-
-static int altera_serial_jtag_getc(struct console_device *cdev)
-{
- struct altera_serial_jtag_priv *priv = container_of(cdev,
- struct altera_serial_jtag_priv, cdev);
-
- struct nios_jtag *jtag = priv->regs;
- uint32_t val;
-
- while (1) {
- val = readl(&jtag->data);
- if (val & NIOS_JTAG_RVALID)
- break;
- }
-
- return val & 0xFF;
-}
-
-static int altera_serial_jtag_probe(struct device_d *dev) {
- struct resource *iores;
-
- struct console_device *cdev;
- struct altera_serial_jtag_priv *priv;
-
- priv = xzalloc(sizeof(*priv));
- cdev = &priv->cdev;
-
- iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- priv->regs = IOMEM(iores->start);
- cdev->dev = dev;
- cdev->tstc = altera_serial_jtag_tstc;
- cdev->putc = altera_serial_jtag_putc;
- cdev->getc = altera_serial_jtag_getc;
- cdev->setbrg = altera_serial_jtag_setbaudrate;
-
- console_register(cdev);
-
- return 0;
-}
-
-static struct driver_d altera_serial_jtag_driver = {
- .name = "altera_serial_jtag",
- .probe = altera_serial_jtag_probe,
-};
-console_platform_driver(altera_serial_jtag_driver);
diff --git a/drivers/serial/serial_ar933x.c b/drivers/serial/serial_ar933x.c
index dda604652b..f5595ec1ee 100644
--- a/drivers/serial/serial_ar933x.c
+++ b/drivers/serial/serial_ar933x.c
@@ -1,19 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* based on linux.git/drivers/tty/serial/serial_ar933x.c
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -21,7 +8,7 @@
#include <init.h>
#include <malloc.h>
#include <io.h>
-#include <asm-generic/div64.h>
+#include <linux/math64.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -154,7 +141,7 @@ static int ar933x_serial_getc(struct console_device *cdev)
return rdata & AR933X_UART_DATA_TX_RX_MASK;
}
-static int ar933x_serial_probe(struct device_d *dev)
+static int ar933x_serial_probe(struct device *dev)
{
struct resource *iores;
struct console_device *cdev;
@@ -201,8 +188,9 @@ static struct of_device_id ar933x_serial_dt_ids[] = {
/* sentinel */
},
};
+MODULE_DEVICE_TABLE(of, ar933x_serial_dt_ids);
-static struct driver_d ar933x_serial_driver = {
+static struct driver ar933x_serial_driver = {
.name = "ar933x_serial",
.probe = ar933x_serial_probe,
.of_compatible = DRV_OF_COMPAT(ar933x_serial_dt_ids),
diff --git a/drivers/serial/serial_ar933x.h b/drivers/serial/serial_ar933x.h
index f55f0fa3d7..d73e77a603 100644
--- a/drivers/serial/serial_ar933x.h
+++ b/drivers/serial/serial_ar933x.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Atheros AR933X UART defines
*
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
*/
#ifndef __AR933X_UART_H
diff --git a/drivers/serial/serial_auart.c b/drivers/serial/serial_auart.c
index 05cc757970..217ac5c891 100644
--- a/drivers/serial/serial_auart.c
+++ b/drivers/serial/serial_auart.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) 2013 Marc Kleine-Budde <mkl@pengutronix.de>
*
@@ -23,17 +24,6 @@
*
* Copyright 2008-2010 Freescale Semiconductor, Inc.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -46,8 +36,6 @@
#include <linux/clk.h>
#include <linux/err.h>
-#include <mach/clock.h>
-
#define HW_UARTAPP_CTRL0 (0x00000000)
#define HW_UARTAPP_CTRL2 (0x00000020)
@@ -178,7 +166,7 @@ static void auart_serial_init_port(struct auart_priv *priv)
writel(0x0, priv->base + HW_UARTAPP_INTR);
}
-static int auart_serial_probe(struct device_d *dev)
+static int auart_serial_probe(struct device *dev)
{
struct resource *iores;
struct auart_priv *priv;
@@ -193,6 +181,7 @@ static int auart_serial_probe(struct device_d *dev)
cdev->flush = auart_serial_flush;
cdev->setbrg = auart_serial_setbaudrate;
cdev->dev = dev;
+ cdev->linux_console_name = "ttyAPP";
dev->priv = priv;
iores = dev_request_mem_resource(dev, 0);
@@ -227,8 +216,9 @@ static const __maybe_unused struct of_device_id auart_serial_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, auart_serial_dt_ids);
-static struct driver_d auart_serial_driver = {
+static struct driver auart_serial_driver = {
.name = "auart_serial",
.probe = auart_serial_probe,
.of_compatible = DRV_OF_COMPAT(auart_serial_dt_ids),
diff --git a/drivers/serial/serial_cadence.c b/drivers/serial/serial_cadence.c
index 6454888e3c..ee162e541a 100644
--- a/drivers/serial/serial_cadence.c
+++ b/drivers/serial/serial_cadence.c
@@ -1,58 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (c) 2012 Steffen Trumtrar <s.trumtrar@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
+
#include <common.h>
#include <driver.h>
#include <init.h>
-#include <malloc.h>
-#include <notifier.h>
#include <io.h>
-#include <linux/err.h>
#include <linux/clk.h>
-
-#define CADENCE_UART_CONTROL 0x00
-#define CADENCE_UART_MODE 0x04
-#define CADENCE_UART_BAUD_GEN 0x18
-#define CADENCE_UART_CHANNEL_STS 0x2C
-#define CADENCE_UART_RXTXFIFO 0x30
-#define CADENCE_UART_BAUD_DIV 0x34
-
-#define CADENCE_CTRL_RXRES (1 << 0)
-#define CADENCE_CTRL_TXRES (1 << 1)
-#define CADENCE_CTRL_RXEN (1 << 2)
-#define CADENCE_CTRL_RXDIS (1 << 3)
-#define CADENCE_CTRL_TXEN (1 << 4)
-#define CADENCE_CTRL_TXDIS (1 << 5)
-#define CADENCE_CTRL_RSTTO (1 << 6)
-#define CADENCE_CTRL_STTBRK (1 << 7)
-#define CADENCE_CTRL_STPBRK (1 << 8)
-
-#define CADENCE_MODE_CLK_REF (0 << 0)
-#define CADENCE_MODE_CLK_REF_DIV (1 << 0)
-#define CADENCE_MODE_CHRL_6 (3 << 1)
-#define CADENCE_MODE_CHRL_7 (2 << 1)
-#define CADENCE_MODE_CHRL_8 (0 << 1)
-#define CADENCE_MODE_PAR_EVEN (0 << 3)
-#define CADENCE_MODE_PAR_ODD (1 << 3)
-#define CADENCE_MODE_PAR_SPACE (2 << 3)
-#define CADENCE_MODE_PAR_MARK (3 << 3)
-#define CADENCE_MODE_PAR_NONE (4 << 3)
-
-#define CADENCE_STS_REMPTY (1 << 1)
-#define CADENCE_STS_RFUL (1 << 2)
-#define CADENCE_STS_TEMPTY (1 << 3)
-#define CADENCE_STS_TFUL (1 << 4)
+#include <linux/err.h>
+#include <malloc.h>
+#include <notifier.h>
+#include <serial/cadence.h>
/*
* create default values for different platforms
@@ -214,7 +173,7 @@ static int cadence_clocksource_clock_change(struct notifier_block *nb,
return 0;
}
-static int cadence_serial_probe(struct device_d *dev)
+static int cadence_serial_probe(struct device *dev)
{
struct resource *iores;
struct console_device *cdev;
@@ -272,9 +231,16 @@ static __maybe_unused struct of_device_id cadence_serial_dt_ids[] = {
.compatible = "xlnx,xuartps",
.data = &cadence_r1p08_data,
}, {
+ .compatible = "cdns,uart-r1p12",
+ .data = &cadence_r1p08_data,
+ }, {
+ .compatible = "xlnx,zynqmp-uart",
+ .data = &cadence_r1p08_data,
+ }, {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, cadence_serial_dt_ids);
static struct platform_device_id cadence_serial_ids[] = {
{
@@ -285,15 +251,11 @@ static struct platform_device_id cadence_serial_ids[] = {
},
};
-static struct driver_d cadence_serial_driver = {
+static struct driver cadence_serial_driver = {
.name = "cadence_serial",
.probe = cadence_serial_probe,
.of_compatible = DRV_OF_COMPAT(cadence_serial_dt_ids),
.id_table = cadence_serial_ids,
};
-static int cadence_serial_init(void)
-{
- return platform_driver_register(&cadence_serial_driver);
-}
-console_initcall(cadence_serial_init);
+console_platform_driver(cadence_serial_driver);
diff --git a/drivers/serial/serial_clps711x.c b/drivers/serial/serial_clps711x.c
index 7a7d595dff..2a284909bf 100644
--- a/drivers/serial/serial_clps711x.c
+++ b/drivers/serial/serial_clps711x.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/* Author: Alexander Shiyan <shc_work@mail.ru> */
#include <common.h>
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <mfd/syscon.h>
+#include <linux/regmap.h>
#define UARTDR 0x00
# define UARTDR_FRMERR (1 << 8)
@@ -35,7 +36,7 @@
struct clps711x_uart {
void __iomem *base;
- void __iomem *syscon;
+ struct regmap *regmap;
struct clk *uart_clk;
struct console_device cdev;
};
@@ -61,8 +62,7 @@ static void clps711x_init_port(struct console_device *cdev)
u32 tmp;
/* Disable the UART */
- tmp = readl(s->syscon + SYSCON);
- writel(tmp & ~SYSCON_UARTEN, s->syscon + SYSCON);
+ regmap_update_bits(s->regmap, SYSCON, SYSCON_UARTEN, 0);
/* Setup Line Control Register */
tmp = readl(s->base + UBRLCR) & UBRLCR_BAUD_MASK;
@@ -70,17 +70,19 @@ static void clps711x_init_port(struct console_device *cdev)
writel(tmp, s->base + UBRLCR);
/* Enable the UART */
- tmp = readl(s->syscon + SYSCON);
- writel(tmp | SYSCON_UARTEN, s->syscon + SYSCON);
+ regmap_update_bits(s->regmap, SYSCON, SYSCON_UARTEN, SYSCON_UARTEN);
}
static void clps711x_putc(struct console_device *cdev, char c)
{
struct clps711x_uart *s = cdev->dev->priv;
+ u32 tmp;
/* Wait until there is space in the FIFO */
do {
- } while (readl(s->syscon + SYSFLG) & SYSFLG_UTXFF);
+ regmap_read(s->regmap, SYSFLG, &tmp);
+
+ } while (tmp & SYSFLG_UTXFF);
/* Send the character */
writew(c, s->base + UARTDR);
@@ -90,10 +92,12 @@ static int clps711x_getc(struct console_device *cdev)
{
struct clps711x_uart *s = cdev->dev->priv;
u16 data;
+ u32 tmp;
/* Wait until there is data in the FIFO */
do {
- } while (readl(s->syscon + SYSFLG) & SYSFLG_URXFE);
+ regmap_read(s->regmap, SYSFLG, &tmp);
+ } while (tmp & SYSFLG_URXFE);
data = readw(s->base + UARTDR);
@@ -107,32 +111,32 @@ static int clps711x_getc(struct console_device *cdev)
static int clps711x_tstc(struct console_device *cdev)
{
struct clps711x_uart *s = cdev->dev->priv;
+ u32 tmp;
+
+ regmap_read(s->regmap, SYSFLG, &tmp);
- return !(readl(s->syscon + SYSFLG) & SYSFLG_URXFE);
+ return !(tmp & SYSFLG_URXFE);
}
static void clps711x_flush(struct console_device *cdev)
{
struct clps711x_uart *s = cdev->dev->priv;
+ u32 tmp;
do {
- } while (readl(s->syscon + SYSFLG) & SYSFLG_UBUSY);
+ regmap_read(s->regmap, SYSFLG, &tmp);
+ } while (tmp & SYSFLG_UBUSY);
}
-static int clps711x_probe(struct device_d *dev)
+static int clps711x_probe(struct device *dev)
{
+ struct device_node *syscon;
struct clps711x_uart *s;
- int err, id = dev->id;
- char syscon_dev[8];
const char *devname;
-
- if (dev->device_node)
- id = of_alias_get_id(dev->device_node, "serial");
-
- if (id != 0 && id != 1)
- return -EINVAL;
+ int err;
s = xzalloc(sizeof(struct clps711x_uart));
+
s->uart_clk = clk_get(dev, NULL);
if (IS_ERR(s->uart_clk)) {
err = PTR_ERR(s->uart_clk);
@@ -140,19 +144,15 @@ static int clps711x_probe(struct device_d *dev)
}
s->base = dev_get_mem_region(dev, 0);
- if (IS_ERR(s->base))
- return PTR_ERR(s->base);
-
- if (!dev->device_node) {
- sprintf(syscon_dev, "syscon%i", id + 1);
- s->syscon = syscon_base_lookup_by_pdevname(syscon_dev);
- } else {
- s->syscon = syscon_base_lookup_by_phandle(dev->device_node,
- "syscon");
+ if (IS_ERR(s->base)) {
+ err = PTR_ERR(s->base);
+ goto out_err;
}
- if (IS_ERR(s->syscon)) {
- err = PTR_ERR(s->syscon);
+ syscon = of_parse_phandle(dev->of_node, "syscon", 0);
+ s->regmap = syscon_node_to_regmap(syscon);
+ if (IS_ERR(s->regmap)) {
+ err = PTR_ERR(s->regmap);
goto out_err;
}
@@ -165,7 +165,7 @@ static int clps711x_probe(struct device_d *dev)
s->cdev.setbrg = clps711x_setbaudrate;
s->cdev.linux_console_name = "ttyCL";
- devname = of_alias_get(dev->device_node);
+ devname = of_alias_get(dev->of_node);
if (devname) {
s->cdev.devname = xstrdup(devname);
s->cdev.devid = DEVICE_ID_SINGLE;
@@ -182,11 +182,13 @@ out_err:
return err;
}
-static struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = {
+static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = {
{ .compatible = "cirrus,ep7209-uart", },
+ { /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids);
-static struct driver_d clps711x_driver = {
+static struct driver clps711x_driver = {
.name = "clps711x-uart",
.probe = clps711x_probe,
.of_compatible = DRV_OF_COMPAT(clps711x_uart_dt_ids),
diff --git a/drivers/serial/serial_digic.c b/drivers/serial/serial_digic.c
index 06b6e15e0c..48e9cd3248 100644
--- a/drivers/serial/serial_digic.c
+++ b/drivers/serial/serial_digic.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013, 2014 Antony Pavlov <antonynpavlov@gmail.com>
*
* This file is part of barebox.
- * See file CREDITS for list of people who contributed to this project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -20,7 +10,7 @@
#include <malloc.h>
#include <io.h>
-#include <mach/uart.h>
+#include <mach/digic/uart.h>
/*
* This driver is based on the "Serial terminal" docs here:
@@ -99,7 +89,7 @@ static int digic_serial_tstc(struct console_device *cdev)
*/
}
-static int digic_serial_probe(struct device_d *dev)
+static int digic_serial_probe(struct device *dev)
{
struct resource *iores;
struct console_device *cdev;
@@ -127,8 +117,9 @@ static __maybe_unused struct of_device_id digic_serial_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, digic_serial_dt_ids);
-static struct driver_d digic_serial_driver = {
+static struct driver digic_serial_driver = {
.name = "digic-uart",
.probe = digic_serial_probe,
.of_compatible = DRV_OF_COMPAT(digic_serial_dt_ids),
diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c
index 667d51f622..6ed068f159 100644
--- a/drivers/serial/serial_efi.c
+++ b/drivers/serial/serial_efi.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
- *
- * Under GPLv2 Only
*/
#include <common.h>
@@ -9,7 +8,7 @@
#include <init.h>
#include <malloc.h>
#include <efi.h>
-#include <efi/efi.h>
+#include <efi/efi-payload.h>
#include <efi/efi-device.h>
/*
diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c
index 09341af874..0f91028605 100644
--- a/drivers/serial/serial_imx.c
+++ b/drivers/serial/serial_imx.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <common.h>
@@ -60,6 +49,7 @@ struct imx_serial_priv {
void __iomem *regs;
struct clk *clk;
struct imx_serial_devtype_data *devtype;
+ bool rs485_mode;
};
static int imx_serial_reffreq(struct imx_serial_priv *priv)
@@ -107,6 +97,9 @@ static int imx_serial_init_port(struct console_device *cdev)
/* Enable FIFOs */
val = readl(regs + UCR2);
+ /* set CTS to not block RS485 bus */
+ if (priv->rs485_mode)
+ val |= UCR2_CTS;
val |= UCR2_SRST | UCR2_RXEN | UCR2_TXEN;
writel(val, regs + UCR2);
@@ -204,7 +197,7 @@ static int imx_clocksource_clock_change(struct notifier_block *nb,
return 0;
}
-static int imx_serial_probe(struct device_d *dev)
+static int imx_serial_probe(struct device *dev)
{
struct resource *iores;
struct console_device *cdev;
@@ -241,17 +234,23 @@ static int imx_serial_probe(struct device_d *dev)
cdev->flush = imx_serial_flush;
cdev->setbrg = imx_serial_setbaudrate;
cdev->linux_console_name = "ttymxc";
- if (dev->device_node) {
- devname = of_alias_get(dev->device_node);
+ cdev->linux_earlycon_name = "ec_imx6q";
+ cdev->phys_base = priv->regs;
+ if (dev->of_node) {
+ devname = of_alias_get(dev->of_node);
if (devname) {
cdev->devname = xstrdup(devname);
cdev->devid = DEVICE_ID_SINGLE;
}
}
- if (of_property_read_bool(dev->device_node, "fsl,dte-mode"))
+ if (of_property_read_bool(dev->of_node, "fsl,dte-mode"))
priv->dte_mode = 1;
+ if (of_property_read_bool(dev->of_node, "linux,rs485-enabled-at-boot-time") &&
+ !of_property_read_bool(dev->of_node, "rs485-rts-active-low"))
+ priv->rs485_mode = 1;
+
imx_serial_init_port(cdev);
/* Enable UART */
@@ -288,9 +287,19 @@ static __maybe_unused struct of_device_id imx_serial_dt_ids[] = {
.compatible = "fsl,imx8mq-uart",
.data = &imx21_data,
}, {
+ .compatible = "fsl,imx8mm-uart",
+ .data = &imx21_data,
+ }, {
+ .compatible = "fsl,imx8mn-uart",
+ .data = &imx21_data,
+ }, {
+ .compatible = "fsl,imx8mp-uart",
+ .data = &imx21_data,
+ }, {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, imx_serial_dt_ids);
static struct platform_device_id imx_serial_ids[] = {
{
@@ -304,7 +313,7 @@ static struct platform_device_id imx_serial_ids[] = {
},
};
-static struct driver_d imx_serial_driver = {
+static struct driver imx_serial_driver = {
.name = "imx_serial",
.probe = imx_serial_probe,
.of_compatible = DRV_OF_COMPAT(imx_serial_dt_ids),
diff --git a/drivers/serial/serial_litex.c b/drivers/serial/serial_litex.c
new file mode 100644
index 0000000000..04da556f6a
--- /dev/null
+++ b/drivers/serial/serial_litex.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+
+#define UART_RXTX 0x00
+#define UART_TXFULL 0x04
+#define UART_RXEMPTY 0x08
+#define UART_EV_PENDING 0x10
+#define UART_EV_RX (1 << 1)
+
+static inline uint32_t litex_serial_readb(struct console_device *cdev,
+ uint32_t offset)
+{
+ void __iomem *base = cdev->dev->priv;
+
+ return readb(base + offset);
+}
+
+static inline void litex_serial_writeb(struct console_device *cdev,
+ uint32_t value, uint32_t offset)
+{
+ void __iomem *base = cdev->dev->priv;
+
+ writeb(value, base + offset);
+}
+
+static void litex_serial_putc(struct console_device *cdev, char c)
+{
+ while (litex_serial_readb(cdev, UART_TXFULL))
+ ;
+
+ litex_serial_writeb(cdev, c, UART_RXTX);
+}
+
+static int litex_serial_getc(struct console_device *cdev)
+{
+ int c;
+
+ while (litex_serial_readb(cdev, UART_RXEMPTY))
+ ;
+
+ c = litex_serial_readb(cdev, UART_RXTX);
+
+ /* refresh UART_RXEMPTY by writing UART_EV_RX to UART_EV_PENDING */
+ litex_serial_writeb(cdev, UART_EV_RX, UART_EV_PENDING);
+
+ return c;
+}
+
+static int litex_serial_tstc(struct console_device *cdev)
+{
+ return !litex_serial_readb(cdev, UART_RXEMPTY);
+}
+
+static int litex_serial_probe(struct device *dev)
+{
+ struct resource *iores;
+ struct console_device *cdev;
+
+ cdev = xzalloc(sizeof(struct console_device));
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ dev->priv = IOMEM(iores->start);
+ cdev->dev = dev;
+ cdev->tstc = &litex_serial_tstc;
+ cdev->putc = &litex_serial_putc;
+ cdev->getc = &litex_serial_getc;
+ cdev->setbrg = NULL;
+ cdev->linux_console_name = "ttyLXU";
+ cdev->linux_earlycon_name = "liteuart";
+ cdev->phys_base = IOMEM(iores->start);
+
+ console_register(cdev);
+
+ return 0;
+}
+
+static __maybe_unused struct of_device_id litex_serial_dt_ids[] = {
+ {
+ .compatible = "litex,uart",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, litex_serial_dt_ids);
+
+static struct driver litex_serial_driver = {
+ .name = "litex-uart",
+ .probe = litex_serial_probe,
+ .of_compatible = DRV_OF_COMPAT(litex_serial_dt_ids),
+};
+console_platform_driver(litex_serial_driver);
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index 246fc3d3af..828a0dd0bb 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016 Zodiac Inflight Innovation
* Author: Andrey Smirnov <andrew.smirnov@gmail.com>
*
* Based on analogous driver from U-Boot
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -125,7 +113,7 @@ static int lpuart_clocksource_clock_change(struct notifier_block *nb,
return lpuart_serial_setbaudrate(&lpuart->cdev, lpuart->baudrate);
}
-static int lpuart_serial_probe(struct device_d *dev)
+static int lpuart_serial_probe(struct device *dev)
{
int ret;
struct console_device *cdev;
@@ -163,8 +151,8 @@ static int lpuart_serial_probe(struct device_d *dev)
cdev->flush = lpuart_serial_flush;
cdev->setbrg = lpuart_serial_setbaudrate;
- if (dev->device_node) {
- devname = of_alias_get(dev->device_node);
+ if (dev->of_node) {
+ devname = of_alias_get(dev->of_node);
if (devname) {
cdev->devname = xstrdup(devname);
cdev->devid = DEVICE_ID_SINGLE;
@@ -172,6 +160,8 @@ static int lpuart_serial_probe(struct device_d *dev)
}
cdev->linux_console_name = "ttyLP";
+ cdev->linux_earlycon_name = "lpuart";
+ cdev->phys_base = lpuart->base;
lpuart_setup(lpuart->base, clk_get_rate(lpuart->clk));
@@ -196,8 +186,9 @@ static struct of_device_id lpuart_serial_dt_ids[] = {
{ .compatible = "fsl,vf610-lpuart" },
{}
};
+MODULE_DEVICE_TABLE(of, lpuart_serial_dt_ids);
-static struct driver_d lpuart_serial_driver = {
+static struct driver lpuart_serial_driver = {
.name = "lpuart-serial",
.probe = lpuart_serial_probe,
.of_compatible = DRV_OF_COMPAT(lpuart_serial_dt_ids),
diff --git a/drivers/serial/serial_lpuart32.c b/drivers/serial/serial_lpuart32.c
new file mode 100644
index 0000000000..09d4b620be
--- /dev/null
+++ b/drivers/serial/serial_lpuart32.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Pengutronix
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <malloc.h>
+#include <notifier.h>
+#include <io.h>
+#include <of.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <serial/lpuart32.h>
+
+struct lpuart32_devtype_data {
+ unsigned int reg_offs;
+};
+
+struct lpuart32 {
+ struct console_device cdev;
+ int baudrate;
+ int dte_mode;
+ struct notifier_block notify;
+ struct resource *io;
+ void __iomem *base;
+ struct clk *clk;
+};
+
+static struct lpuart32 *cdev_to_lpuart32(struct console_device *cdev)
+{
+ return container_of(cdev, struct lpuart32, cdev);
+}
+
+static void lpuart32_enable(struct lpuart32 *lpuart32)
+{
+ writel(LPUART32_UARTCTRL_TE | LPUART32_UARTCTRL_RE,
+ lpuart32->base + LPUART32_UARTCTRL);
+}
+
+static void lpuart32_disable(struct lpuart32 *lpuart32)
+{
+ writel(0, lpuart32->base + LPUART32_UARTCTRL);
+}
+
+/* Test whether a character is in the RX buffer */
+static int lpuart32_serial_tstc(struct console_device *cdev)
+{
+ struct lpuart32 *lpuart32 = cdev_to_lpuart32(cdev);
+
+ if (readl(lpuart32->base + LPUART32_UARTSTAT) & LPUART32_UARTSTAT_OR)
+ writel(LPUART32_UARTSTAT_OR, lpuart32->base + LPUART32_UARTSTAT);
+
+ return readl(lpuart32->base + LPUART32_UARTSTAT) & LPUART32_UARTSTAT_RDRF;
+}
+
+static int lpuart32_serial_setbaudrate(struct console_device *cdev,
+ int baudrate)
+{
+ struct lpuart32 *lpuart32 = cdev_to_lpuart32(cdev);
+
+ lpuart32_disable(lpuart32);
+
+ /*
+ * We treat baudrate of 0 as a request to disable UART
+ */
+ if (baudrate) {
+ lpuart32_setbrg(lpuart32->base, clk_get_rate(lpuart32->clk),
+ baudrate);
+ lpuart32_enable(lpuart32);
+ }
+
+ lpuart32->baudrate = baudrate;
+
+ return 0;
+}
+
+static int lpuart32_serial_getc(struct console_device *cdev)
+{
+ struct lpuart32 *lpuart32 = cdev_to_lpuart32(cdev);
+
+ while (!lpuart32_serial_tstc(cdev));
+
+ return readl(lpuart32->base + LPUART32_UARTDATA) & 0xff;
+}
+
+static void lpuart32_serial_putc(struct console_device *cdev, char c)
+{
+ struct lpuart32 *lpuart32 = cdev_to_lpuart32(cdev);
+
+ lpuart32_putc(lpuart32->base, c);
+}
+
+static void lpuart32_serial_flush(struct console_device *cdev)
+{
+}
+
+static int lpuart32_serial_probe(struct device *dev)
+{
+ int ret;
+ struct console_device *cdev;
+ struct lpuart32 *lpuart32;
+ const char *devname;
+ struct lpuart32_devtype_data *devtype;
+
+ ret = dev_get_drvdata(dev, (const void **)&devtype);
+ if (ret)
+ return ret;
+
+ lpuart32 = xzalloc(sizeof(*lpuart32));
+ cdev = &lpuart32->cdev;
+ dev->priv = lpuart32;
+
+ lpuart32->io = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(lpuart32->io)) {
+ ret = PTR_ERR(lpuart32->io);
+ goto err_free;
+ }
+ lpuart32->base = IOMEM(lpuart32->io->start) + devtype->reg_offs;
+
+ lpuart32->clk = clk_get(dev, NULL);
+ if (IS_ERR(lpuart32->clk)) {
+ ret = PTR_ERR(lpuart32->clk);
+ dev_err(dev, "Failed to get UART clock %d\n", ret);
+ goto io_release;
+ }
+
+ ret = clk_enable(lpuart32->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable UART clock %d\n", ret);
+ goto io_release;
+ }
+
+ cdev->dev = dev;
+ cdev->tstc = lpuart32_serial_tstc;
+ cdev->putc = lpuart32_serial_putc;
+ cdev->getc = lpuart32_serial_getc;
+ cdev->flush = lpuart32_serial_flush;
+ cdev->setbrg = lpuart32_serial_setbaudrate;
+
+ if (dev->of_node) {
+ devname = of_alias_get(dev->of_node);
+ if (devname) {
+ cdev->devname = xstrdup(devname);
+ cdev->devid = DEVICE_ID_SINGLE;
+ }
+ }
+
+ cdev->linux_console_name = "ttyLP";
+ cdev->linux_earlycon_name = "lpuart";
+ cdev->phys_base = lpuart32->base;
+
+ lpuart32_setup(lpuart32->base, clk_get_rate(lpuart32->clk));
+
+ ret = console_register(cdev);
+ if (!ret)
+ return 0;
+
+ clk_put(lpuart32->clk);
+io_release:
+ release_region(lpuart32->io);
+err_free:
+ free(lpuart32);
+
+ return ret;
+}
+
+static struct lpuart32_devtype_data imx7ulp_data = {
+ .reg_offs = 0x10,
+};
+
+static struct of_device_id lpuart32_serial_dt_ids[] = {
+ {
+ .compatible = "fsl,imx7ulp-lpuart",
+ .data = &imx7ulp_data,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, lpuart32_serial_dt_ids);
+
+static struct driver lpuart32_serial_driver = {
+ .name = "lpuart32-serial",
+ .probe = lpuart32_serial_probe,
+ .of_compatible = DRV_OF_COMPAT(lpuart32_serial_dt_ids),
+};
+console_platform_driver(lpuart32_serial_driver);
diff --git a/drivers/serial/serial_mpc5xxx.c b/drivers/serial/serial_mpc5xxx.c
index cc63a84c68..4408de9e91 100644
--- a/drivers/serial/serial_mpc5xxx.c
+++ b/drivers/serial/serial_mpc5xxx.c
@@ -1,21 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright 2000 - 2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
* Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 19-Oct-00, with
* changes based on the file arch/ppc/mbxboot/m8260_tty.c from the
* Linux/PPC sources (m8260_tty.c had no copyright info in it).
@@ -59,7 +46,7 @@ static int __mpc5xxx_serial_setbaudrate(struct mpc5xxx_psc *psc, int baudrate)
static int mpc5xxx_serial_setbaudrate(struct console_device *cdev, int baudrate)
{
- struct device_d *dev = cdev->dev;
+ struct device *dev = cdev->dev;
struct mpc5xxx_psc *psc = dev->priv;
__mpc5xxx_serial_setbaudrate(psc, baudrate);
@@ -103,7 +90,7 @@ static int __mpc5xxx_serial_init(struct mpc5xxx_psc *psc)
static int mpc5xxx_serial_init(struct console_device *cdev)
{
- struct device_d *dev = cdev->dev;
+ struct device *dev = cdev->dev;
struct mpc5xxx_psc *psc = dev->priv;
__mpc5xxx_serial_init(psc);
@@ -113,7 +100,7 @@ static int mpc5xxx_serial_init(struct console_device *cdev)
static void mpc5xxx_serial_putc (struct console_device *cdev, const char c)
{
- struct device_d *dev = cdev->dev;
+ struct device *dev = cdev->dev;
struct mpc5xxx_psc *psc = dev->priv;
/* Wait for last character to go. */
@@ -125,7 +112,7 @@ static void mpc5xxx_serial_putc (struct console_device *cdev, const char c)
static int mpc5xxx_serial_getc (struct console_device *cdev)
{
- struct device_d *dev = cdev->dev;
+ struct device *dev = cdev->dev;
struct mpc5xxx_psc *psc = dev->priv;
/* Wait for a character to arrive. */
@@ -137,13 +124,13 @@ static int mpc5xxx_serial_getc (struct console_device *cdev)
static int mpc5xxx_serial_tstc (struct console_device *cdev)
{
- struct device_d *dev = cdev->dev;
+ struct device *dev = cdev->dev;
struct mpc5xxx_psc *psc = dev->priv;
return (psc->psc_status & PSC_SR_RXRDY);
}
-static int mpc5xxx_serial_probe(struct device_d *dev)
+static int mpc5xxx_serial_probe(struct device *dev)
{
struct resource *iores;
struct console_device *cdev;
@@ -166,7 +153,7 @@ static int mpc5xxx_serial_probe(struct device_d *dev)
return 0;
}
-static struct driver_d mpc5xxx_serial_driver = {
+static struct driver mpc5xxx_serial_driver = {
.name = "mpc5xxx_serial",
.probe = mpc5xxx_serial_probe,
};
diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index 3edeb0dcbe..1b1692658f 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/**
* @file
* @brief NS16550 Driver implementation
@@ -16,20 +17,6 @@
*
* (C) Copyright 2000
* Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -52,11 +39,18 @@ struct ns16550_priv {
unsigned iobase;
void (*write_reg)(struct ns16550_priv *, uint8_t val, unsigned offset);
uint8_t (*read_reg)(struct ns16550_priv *, unsigned offset);
+ const char *access_type;
+
+ bool rs485_mode;
+ bool rs485_rts_active_low;
+ bool rs485_rx_during_tx;
};
struct ns16550_drvdata {
void (*init_port)(struct console_device *cdev);
const char *linux_console_name;
+ const char *linux_earlycon_name;
+ unsigned int clk_default;
};
static inline struct ns16550_priv *to_ns16550_priv(struct console_device *cdev)
@@ -182,7 +176,6 @@ static inline unsigned int ns16550_calc_divisor(struct console_device *cdev,
unsigned int clk = plat->clock;
return (clk / MODE_X_DIV / baudrate);
-
}
/**
@@ -253,14 +246,10 @@ static void ns16550_jz_init_port(struct console_device *cdev)
ns16550_serial_init_port(cdev);
}
-#define BCM2836_AUX_CLOCK_ENB 0x3f215004 /* BCM2835 AUX Clock enable register */
-#define BCM2836_AUX_CLOCK_EN_UART BIT(0) /* Bit 0 enables the Miniuart */
-
static void rpi_init_port(struct console_device *cdev)
{
struct ns16550_priv *priv = to_ns16550_priv(cdev);
- writeb(BCM2836_AUX_CLOCK_EN_UART, BCM2836_AUX_CLOCK_ENB);
priv->plat.shift = 2;
/*
* We double the clock rate since the 16550 will divide by 16
@@ -280,9 +269,37 @@ static void rpi_init_port(struct console_device *cdev)
*/
static void ns16550_putc(struct console_device *cdev, char c)
{
- /* Loop Doing Nothing */
- while ((ns16550_read(cdev, lsr) & LSR_THRE) == 0) ;
+ struct ns16550_priv *priv = to_ns16550_priv(cdev);
+
+ /* wait until FIFO can accept at least one byte */
+ while ((ns16550_read(cdev, lsr) & (LSR_THRE)) != (LSR_THRE))
+ ;
+
+ if (priv->rs485_mode) {
+ if (priv->rs485_rts_active_low)
+ ns16550_write(cdev, MCR_RTS, mcr);
+ else
+ ns16550_write(cdev, 0, mcr);
+
+ if (!priv->rs485_rx_during_tx)
+ ns16550_write(cdev, CNTL_TXEN, cntl);
+ }
+
ns16550_write(cdev, c, thr);
+
+ if (priv->rs485_mode) {
+ /* wait until FIFO is cleared*/
+ while ((ns16550_read(cdev, lsr) & (LSR_EMPTY)) != (LSR_EMPTY))
+ ;
+
+ if (priv->rs485_rts_active_low)
+ ns16550_write(cdev, 0, mcr);
+ else
+ ns16550_write(cdev, MCR_RTS, mcr);
+
+ if (!priv->rs485_rx_during_tx)
+ ns16550_write(cdev, CNTL_TXEN | CNTL_RXEN, cntl);
+ }
}
/**
@@ -311,13 +328,24 @@ static int ns16550_tstc(struct console_device *cdev)
return ((ns16550_read(cdev, lsr) & LSR_DR) != 0);
}
-static void ns16550_probe_dt(struct device_d *dev, struct ns16550_priv *priv)
+/**
+ * @brief Flush remaining characters in serial device
+ *
+ * @param[in] cdev pointer to console device
+ */
+static void ns16550_flush(struct console_device *cdev)
+{
+ /* Loop Doing Nothing */
+ while ((ns16550_read(cdev, lsr) & LSR_TEMT) == 0) ;
+}
+
+static void ns16550_probe_dt(struct device *dev, struct ns16550_priv *priv)
{
- struct device_node *np = dev->device_node;
+ struct device_node *np = dev_of_node(dev);
u32 offset;
u32 width = 1;
- if (!IS_ENABLED(CONFIG_OFDEVICE))
+ if (!np)
return;
of_property_read_u32(np, "clock-frequency", &priv->plat.clock);
@@ -325,22 +353,33 @@ static void ns16550_probe_dt(struct device_d *dev, struct ns16550_priv *priv)
priv->mmiobase += offset;
of_property_read_u32(np, "reg-shift", &priv->plat.shift);
of_property_read_u32(np, "reg-io-width", &width);
+ priv->rs485_rts_active_low =
+ of_property_read_bool(np, "rs485-rts-active-low");
+ priv->rs485_mode =
+ of_property_read_bool(np, "linux,rs485-enabled-at-boot-time");
+ priv->rs485_rx_during_tx =
+ of_property_read_bool(np, "rs485-rx-during-tx");
+
switch (width) {
case 1:
priv->read_reg = ns16550_read_reg_mmio_8;
priv->write_reg = ns16550_write_reg_mmio_8;
+ priv->access_type = "mmio";
break;
case 2:
priv->read_reg = ns16550_read_reg_mmio_16;
priv->write_reg = ns16550_write_reg_mmio_16;
+ priv->access_type = "mmio16";
break;
case 4:
if (of_device_is_big_endian(np)) {
priv->read_reg = ns16550_read_reg_mmio_32be;
priv->write_reg = ns16550_write_reg_mmio_32be;
+ priv->access_type = "mmio32be";
} else {
priv->read_reg = ns16550_read_reg_mmio_32;
priv->write_reg = ns16550_write_reg_mmio_32;
+ priv->access_type = "mmio32";
}
break;
default:
@@ -352,98 +391,101 @@ static void ns16550_probe_dt(struct device_d *dev, struct ns16550_priv *priv)
static struct ns16550_drvdata ns16450_drvdata = {
.init_port = ns16450_serial_init_port,
.linux_console_name = "ttyS",
+ .linux_earlycon_name = "uart8250",
};
static struct ns16550_drvdata ns16550_drvdata = {
.init_port = ns16550_serial_init_port,
.linux_console_name = "ttyS",
+ .linux_earlycon_name = "uart8250",
};
static __maybe_unused struct ns16550_drvdata omap_drvdata = {
.init_port = ns16550_omap_init_port,
.linux_console_name = "ttyO",
+ .linux_earlycon_name = "omap8250",
};
-static __maybe_unused struct ns16550_drvdata jz_drvdata = {
- .init_port = ns16550_jz_init_port,
+static __maybe_unused struct ns16550_drvdata omap_clk48m_drvdata = {
+ .init_port = ns16550_omap_init_port,
+ .linux_console_name = "ttyO",
+ .clk_default = 48000000,
};
-static __maybe_unused struct ns16550_drvdata tegra_drvdata = {
- .init_port = ns16550_serial_init_port,
- .linux_console_name = "ttyS",
+static __maybe_unused struct ns16550_drvdata jz_drvdata = {
+ .init_port = ns16550_jz_init_port,
+ .linux_earlycon_name = "jz4740_uart",
};
static __maybe_unused struct ns16550_drvdata rpi_drvdata = {
.init_port = rpi_init_port,
.linux_console_name = "ttyS",
+ .linux_earlycon_name = "bcm2835aux",
};
-static int ns16550_init_iomem(struct device_d *dev, struct ns16550_priv *priv)
+/**
+ * @return the requested resource to be properly released in case probe fail
+ */
+static struct resource *ns16550_init_iores(struct device *dev, struct ns16550_priv *priv)
{
- struct resource *iores;
struct resource *res;
- int width;
+ struct resource *iores;
+ unsigned long flags;
res = dev_get_resource(dev, IORESOURCE_MEM, 0);
if (IS_ERR(res))
- return PTR_ERR(res);
+ res = dev_get_resource(dev, IORESOURCE_IO, 0);
+ if (IS_ERR(res))
+ return res;
+
+ flags = res->flags & (IORESOURCE_MEM_TYPE_MASK | IORESOURCE_IO);
- iores = dev_request_mem_resource(dev, 0);
+ if (flags & IORESOURCE_IO)
+ iores = request_ioport_region(dev_name(dev), res->start, res->end);
+ else
+ iores = request_iomem_region(dev_name(dev), res->start, res->end);
if (IS_ERR(iores))
- return PTR_ERR(iores);
- priv->mmiobase = IOMEM(iores->start);
+ return iores;
- width = res->flags & IORESOURCE_MEM_TYPE_MASK;
- switch (width) {
+ if (flags & IORESOURCE_IO)
+ priv->iobase = iores->start;
+ else
+ priv->mmiobase = IOMEM(iores->start);
+
+ switch (flags) {
+ case IORESOURCE_IO | IORESOURCE_MEM_8BIT:
+ priv->read_reg = ns16550_read_reg_ioport_8;
+ priv->write_reg = ns16550_write_reg_ioport_8;
+ priv->access_type = "io";
+ break;
+ case IORESOURCE_IO | IORESOURCE_MEM_16BIT:
+ priv->read_reg = ns16550_read_reg_ioport_16;
+ priv->write_reg = ns16550_write_reg_ioport_16;
+ priv->access_type = "io";
+ break;
+ case IORESOURCE_IO | IORESOURCE_MEM_32BIT:
+ priv->read_reg = ns16550_read_reg_ioport_32;
+ priv->write_reg = ns16550_write_reg_ioport_32;
+ priv->access_type = "io";
+ break;
case IORESOURCE_MEM_8BIT:
priv->read_reg = ns16550_read_reg_mmio_8;
priv->write_reg = ns16550_write_reg_mmio_8;
+ priv->access_type = "mmio";
break;
case IORESOURCE_MEM_16BIT:
priv->read_reg = ns16550_read_reg_mmio_16;
priv->write_reg = ns16550_write_reg_mmio_16;
+ priv->access_type = "mmio16";
break;
case IORESOURCE_MEM_32BIT:
priv->read_reg = ns16550_read_reg_mmio_32;
priv->write_reg = ns16550_write_reg_mmio_32;
+ priv->access_type = "mmio32";
break;
}
- return 0;
-}
-
-static int ns16550_init_ioport(struct device_d *dev, struct ns16550_priv *priv)
-{
- struct resource *res;
- int width;
-
- res = dev_get_resource(dev, IORESOURCE_IO, 0);
- if (IS_ERR(res))
- return PTR_ERR(res);
-
- res = request_ioport_region(dev_name(dev), res->start, res->end);
- if (IS_ERR(res))
- return PTR_ERR(res);
-
- priv->iobase = res->start;
-
- width = res->flags & IORESOURCE_MEM_TYPE_MASK;
- switch (width) {
- case IORESOURCE_MEM_8BIT:
- priv->read_reg = ns16550_read_reg_ioport_8;
- priv->write_reg = ns16550_write_reg_ioport_8;
- break;
- case IORESOURCE_MEM_16BIT:
- priv->read_reg = ns16550_read_reg_ioport_16;
- priv->write_reg = ns16550_write_reg_ioport_16;
- break;
- case IORESOURCE_MEM_32BIT:
- priv->read_reg = ns16550_read_reg_ioport_32;
- priv->write_reg = ns16550_write_reg_ioport_32;
- break;
- }
-
- return 0;
+ return iores;
}
/**
@@ -455,47 +497,50 @@ static int ns16550_init_ioport(struct device_d *dev, struct ns16550_priv *priv)
* ENOMEM if calloc failed
* else return result of console_register
*/
-static int ns16550_probe(struct device_d *dev)
+static int ns16550_probe(struct device *dev)
{
struct ns16550_priv *priv;
struct console_device *cdev;
struct NS16550_plat *plat = (struct NS16550_plat *)dev->platform_data;
- struct ns16550_drvdata *devtype;
+ const struct ns16550_drvdata *devtype;
+ struct resource *iores;
int ret;
- ret = dev_get_drvdata(dev, (const void **)&devtype);
- if (ret)
- devtype = &ns16550_drvdata;
+ devtype = device_get_match_data(dev) ?: &ns16550_drvdata;
priv = xzalloc(sizeof(*priv));
- ret = ns16550_init_iomem(dev, priv);
- if (ret)
- ret = ns16550_init_ioport(dev, priv);
-
- if (ret)
- return ret;
+ iores = ns16550_init_iores(dev, priv);
+ if (IS_ERR(iores)) {
+ ret = PTR_ERR(iores);
+ goto err;
+ }
if (plat)
priv->plat = *plat;
else
ns16550_probe_dt(dev, priv);
+ if (devtype->clk_default && !priv->plat.clock)
+ priv->plat.clock = devtype->clk_default;
+
if (!priv->plat.clock) {
priv->clk = clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
dev_err(dev, "failed to get clk (%d)\n", ret);
- goto err;
+ goto release_region;
}
- clk_enable(priv->clk);
+ ret = clk_enable(priv->clk);
+ if (ret)
+ goto clk_put;
priv->plat.clock = clk_get_rate(priv->clk);
}
if (priv->plat.clock == 0) {
dev_err(dev, "no valid clockrate\n");
ret = -EINVAL;
- goto err;
+ goto clk_disable;
}
cdev = &priv->cdev;
@@ -504,14 +549,29 @@ static int ns16550_probe(struct device_d *dev)
cdev->putc = ns16550_putc;
cdev->getc = ns16550_getc;
cdev->setbrg = ns16550_setbaudrate;
+ cdev->flush = ns16550_flush;
cdev->linux_console_name = devtype->linux_console_name;
+ cdev->linux_earlycon_name = basprintf("%s,%s", devtype->linux_earlycon_name,
+ priv->access_type);
+ cdev->phys_base = !strcmp(priv->access_type, "io") ?
+ IOMEM((ulong)priv->iobase) : priv->mmiobase;
priv->fcrval = FCRVAL;
devtype->init_port(cdev);
- return console_register(cdev);
+ ret = console_register(cdev);
+ if (ret)
+ goto clk_disable;
+ return 0;
+
+clk_disable:
+ clk_disable(priv->clk);
+clk_put:
+ clk_put(priv->clk);
+release_region:
+ release_region(iores);
err:
free(priv);
@@ -524,14 +584,19 @@ static struct of_device_id ns16550_serial_dt_ids[] = {
.data = &ns16450_drvdata,
}, {
.compatible = "ns16550a",
- .data = &ns16550_drvdata,
}, {
.compatible = "snps,dw-apb-uart",
- .data = &ns16550_drvdata,
}, {
.compatible = "marvell,armada-38x-uart",
- .data = &ns16550_drvdata,
+ }, {
+ .compatible = "nvidia,tegra20-uart",
+ },
+#if IS_ENABLED(CONFIG_ARCH_K3)
+ {
+ .compatible = "ti,am654-uart",
+ .data = &omap_clk48m_drvdata,
},
+#endif
#if IS_ENABLED(CONFIG_ARCH_OMAP)
{
.compatible = "ti,omap2-uart",
@@ -542,12 +607,9 @@ static struct of_device_id ns16550_serial_dt_ids[] = {
}, {
.compatible = "ti,omap4-uart",
.data = &omap_drvdata,
- },
-#endif
-#if IS_ENABLED(CONFIG_ARCH_TEGRA)
- {
- .compatible = "nvidia,tegra20-uart",
- .data = &tegra_drvdata,
+ }, {
+ .compatible = "ti,am4372-uart",
+ .data = &omap_clk48m_drvdata,
},
#endif
#if IS_ENABLED(CONFIG_MACH_MIPS_XBURST)
@@ -566,11 +628,12 @@ static struct of_device_id ns16550_serial_dt_ids[] = {
/* sentinel */
},
};
+MODULE_DEVICE_TABLE(of, ns16550_serial_dt_ids);
static __maybe_unused struct platform_device_id ns16550_serial_ids[] = {
{
.name = "omap-uart",
- .driver_data = (unsigned long)&omap_drvdata,
+ .driver_data = (unsigned long)&omap_clk48m_drvdata,
}, {
/* sentinel */
},
@@ -579,7 +642,7 @@ static __maybe_unused struct platform_device_id ns16550_serial_ids[] = {
/**
* @brief Driver registration structure
*/
-static struct driver_d ns16550_serial_driver = {
+static struct driver ns16550_serial_driver = {
.name = "ns16550_serial",
.probe = ns16550_probe,
.of_compatible = DRV_OF_COMPAT(ns16550_serial_dt_ids),
diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h
index c37d63ca9e..2d941cb8d1 100644
--- a/drivers/serial/serial_ns16550.h
+++ b/drivers/serial/serial_ns16550.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/**
* @file
* @brief Serial NS16550 header
@@ -8,11 +9,6 @@
* Register definitions for NS16550 device
*/
/*
- * This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
* NS16550 Serial Port
* originally from linux source (arch/ppc/boot/ns16550.h)
* modified slightly to
@@ -40,6 +36,7 @@
#define lsr 5
#define msr 6
#define scr 7
+#define cntl 8
#define thr rbr
#define iir fcr
@@ -77,6 +74,12 @@
#define LSR_TEMT 0x40 /* Xmitter empty */
#define LSR_ERR 0x80 /* Error */
+/* Transmitter FIFO completely empty */
+#define LSR_EMPTY (LSR_THRE | LSR_TEMT)
+
+#define CNTL_RXEN 0x01
+#define CNTL_TXEN 0x02
+
/* useful defaults for LCR */
#define LCR_8N1 0x03
diff --git a/drivers/serial/serial_ns16550_pci.c b/drivers/serial/serial_ns16550_pci.c
new file mode 100644
index 0000000000..f82b5797ce
--- /dev/null
+++ b/drivers/serial/serial_ns16550_pci.c
@@ -0,0 +1,5305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Probe module for 8250/16550-type PCI serial ports.
+ *
+ * Based on Linux drivers/tty/serial/8250_pci.c
+ * Itself based on Linux drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright (C) 2001 Russell King, All Rights Reserved.
+ * Copyright (C) 2019 Ahmad Fatoum, Pengutronix
+ */
+
+#include <common.h>
+#include <init.h>
+#include <linux/pci.h>
+#include <driver.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include <platform_data/serial-ns16550.h>
+#include "serial_ns16550.h"
+
+#define PCI_NUM_BAR_RESOURCES 6
+
+#define FL_BASE_MASK 0x0007
+#define FL_BASE0 0x0000
+#define FL_BASE1 0x0001
+#define FL_BASE2 0x0002
+#define FL_BASE3 0x0003
+#define FL_BASE4 0x0004
+#define FL_GET_BASE(x) (x & FL_BASE_MASK)
+
+/* Use successive BARs (PCI base address registers),
+ else use offset into some specified BAR */
+#define FL_BASE_BARS 0x0008
+
+/* do not assign an irq; no-op, we use no irqs */
+#define FL_NOIRQ 0x0080
+
+/* Use the Base address register size to cap number of ports */
+#define FL_REGION_SZ_CAP 0x0100
+
+
+struct uart_8250_port {
+ struct NS16550_plat *pdata;
+ struct resource resource;
+
+};
+
+struct pciserial_board {
+ unsigned int flags;
+ unsigned int num_ports;
+ unsigned int base_baud;
+ unsigned int uart_offset;
+ unsigned int reg_shift;
+ unsigned int first_offset;
+};
+
+struct serial_private;
+
+/*
+ * init function returns:
+ * > 0 - number of ports
+ * = 0 - use board->num_ports
+ * < 0 - error
+ */
+struct pci_serial_quirk {
+ u32 vendor;
+ u32 device;
+ u32 subvendor;
+ u32 subdevice;
+ int (*probe)(struct pci_dev *dev);
+ int (*init)(struct pci_dev *dev);
+ int (*setup)(struct serial_private *,
+ const struct pciserial_board *,
+ struct uart_8250_port *, int);
+ void (*exit)(struct pci_dev *dev);
+};
+
+#define PCI_NUM_BAR_RESOURCES 6
+
+struct serial_private {
+ struct pci_dev *dev;
+ unsigned int nr;
+ struct pci_serial_quirk *quirk;
+ const struct pciserial_board *board;
+ void *private_data; /* for use by quirks */
+};
+
+static int pci_default_setup(struct serial_private*,
+ const struct pciserial_board*, struct uart_8250_port *, int);
+
+static void moan_device(const char *str, struct pci_dev *dev)
+{
+ dev_err(&dev->dev,
+ "%s: %s\n"
+ "Please send the output of lspci -vv, this\n"
+ "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
+ "manufacturer and name of serial board or\n"
+ "modem board to <linux-serial@vger.kernel.org>.\n",
+ dev_name(&dev->dev), str, dev->vendor, dev->device,
+ dev->subsystem_vendor, dev->subsystem_device);
+}
+
+static int
+setup_port(struct serial_private *priv, struct uart_8250_port *port,
+ int bar, int offset, int regshift)
+{
+ struct pci_dev *dev = priv->dev;
+
+ if (bar >= PCI_NUM_BAR_RESOURCES)
+ return -EINVAL;
+
+ port->resource.flags = IORESOURCE_MEM_8BIT;
+
+ if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
+ if (!pci_iomap(dev, bar))
+ return -ENOMEM;
+
+ port->resource.flags |= IORESOURCE_MEM;
+ } else {
+ port->resource.flags |= IORESOURCE_IO;
+ }
+
+ port->resource.start = pci_resource_start(dev, bar) + offset;
+ port->resource.end = port->resource.start + pci_resource_len(dev, bar) - 1;
+
+ port->pdata->shift = regshift;
+
+ return 0;
+}
+
+/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+static int addidata_apci7800_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar = 0, offset = board->first_offset;
+ bar = FL_GET_BASE(board->flags);
+
+ if (idx < 2) {
+ offset += idx * board->uart_offset;
+ } else if ((idx >= 2) && (idx < 4)) {
+ bar += 1;
+ offset += ((idx - 2) * board->uart_offset);
+ } else if ((idx >= 4) && (idx < 6)) {
+ bar += 2;
+ offset += ((idx - 4) * board->uart_offset);
+ } else if (idx >= 6) {
+ bar += 3;
+ offset += ((idx - 6) * board->uart_offset);
+ }
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * AFAVLAB uses a different mixture of BARs and offsets
+ * Not that ugly ;) -- HW
+ */
+static int
+afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar, offset = board->first_offset;
+
+ bar = FL_GET_BASE(board->flags);
+ if (idx < 4)
+ bar += idx;
+ else {
+ bar = 4;
+ offset += (idx - 4) * board->uart_offset;
+ }
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * HP's Remote Management Console. The Diva chip came in several
+ * different versions. N-class, L2000 and A500 have two Diva chips, each
+ * with 3 UARTs (the third UART on the second chip is unused). Superdome
+ * and Keystone have one Diva chip with 3 UARTs. Some later machines have
+ * one Diva chip, but it has been expanded to 5 UARTs.
+ */
+static int pci_hp_diva_init(struct pci_dev *dev)
+{
+ int rc = 0;
+
+ switch (dev->subsystem_device) {
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA1:
+ case PCI_DEVICE_ID_HP_DIVA_HALFDOME:
+ case PCI_DEVICE_ID_HP_DIVA_KEYSTONE:
+ case PCI_DEVICE_ID_HP_DIVA_EVEREST:
+ rc = 3;
+ break;
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA2:
+ rc = 2;
+ break;
+ case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+ rc = 4;
+ break;
+ case PCI_DEVICE_ID_HP_DIVA_POWERBAR:
+ case PCI_DEVICE_ID_HP_DIVA_HURRICANE:
+ rc = 1;
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * HP's Diva chip puts the 4th/5th serial port further out, and
+ * some serial ports are supposed to be hidden on certain models.
+ */
+static int
+pci_hp_diva_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int offset = board->first_offset;
+ unsigned int bar = FL_GET_BASE(board->flags);
+
+ switch (priv->dev->subsystem_device) {
+ case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+ if (idx == 3)
+ idx++;
+ break;
+ case PCI_DEVICE_ID_HP_DIVA_EVEREST:
+ if (idx > 0)
+ idx++;
+ if (idx > 2)
+ idx++;
+ break;
+ }
+ if (idx > 2)
+ offset = 0x18;
+
+ offset += idx * board->uart_offset;
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * Added for EKF Intel i960 serial boards
+ */
+static int pci_inteli960ni_init(struct pci_dev *dev)
+{
+ u32 oldval;
+
+ if (!(dev->subsystem_device & 0x1000))
+ return -ENODEV;
+
+ /* is firmware started? */
+ pci_read_config_dword(dev, 0x44, &oldval);
+ if (oldval == 0x00001000L) { /* RESET value */
+ dev_dbg(&dev->dev, "Local i960 firmware missing\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/*
+ * Some PCI serial cards using the PLX 9050 PCI interface chip require
+ * that the card interrupt be explicitly enabled or disabled. This
+ * seems to be mainly needed on card using the PLX which also use I/O
+ * mapped memory.
+ */
+static int pci_plx9050_init(struct pci_dev *dev)
+{
+ void __iomem *p;
+
+ if ((pci_resource_flags(dev, 0) & IORESOURCE_MEM) == 0) {
+ moan_device("no memory in bar 0", dev);
+ return 0;
+ }
+
+ /*
+ * disable interrupts
+ */
+ p = pci_iomap(dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ writel(0, p + 0x4c);
+
+ /*
+ * Read the register back to ensure that it took effect.
+ */
+ readl(p + 0x4c);
+
+ return 0;
+}
+
+#define NI8420_INT_ENABLE_REG 0x38
+#define NI8420_INT_ENABLE_BIT 0x2000
+
+/* MITE registers */
+#define MITE_IOWBSR1 0xc4
+#define MITE_IOWCR1 0xf4
+#define MITE_LCIMR1 0x08
+#define MITE_LCIMR2 0x10
+
+#define MITE_LCIMR2_CLR_CPU_IE (1 << 30)
+
+/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
+static int
+sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar, offset = board->first_offset;
+
+ bar = 0;
+
+ if (idx < 4) {
+ /* first four channels map to 0, 0x100, 0x200, 0x300 */
+ offset += idx * board->uart_offset;
+ } else if (idx < 8) {
+ /* last four channels map to 0x1000, 0x1100, 0x1200, 0x1300 */
+ offset += idx * board->uart_offset + 0xC00;
+ } else /* we have only 8 ports on PMC-OCTALPRO */
+ return 1;
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+* This does initialization for PMC OCTALPRO cards:
+* maps the device memory, resets the UARTs (needed, bc
+* if the module is removed and inserted again, the card
+* is in the sleep mode) and enables global interrupt.
+*/
+
+/* global control register offset for SBS PMC-OctalPro */
+#define OCT_REG_CR_OFF 0x500
+
+static int sbs_init(struct pci_dev *dev)
+{
+ u8 __iomem *p;
+
+ p = pci_iomap(dev, 0);
+
+ if (p == NULL)
+ return -ENOMEM;
+ /* Set bit-4 Control Register (UART RESET) in to reset the uarts */
+ writeb(0x10, p + OCT_REG_CR_OFF);
+ udelay(50);
+ writeb(0x0, p + OCT_REG_CR_OFF);
+
+ /* Clear especially bit-2 (INTENABLE) of Control Register */
+ writeb(0, p + OCT_REG_CR_OFF);
+
+ return 0;
+}
+
+/*
+ * SIIG serial cards have an PCI interface chip which also controls
+ * the UART clocking frequency. Each UART can be clocked independently
+ * (except cards equipped with 4 UARTs) and initial clocking settings
+ * are stored in the EEPROM chip. It can cause problems because this
+ * version of serial driver doesn't support differently clocked UART's
+ * on single PCI card. To prevent this, initialization functions set
+ * high frequency clocking for all UART's on given card. It is safe (I
+ * hope) because it doesn't touch EEPROM settings to prevent conflicts
+ * with other OSes (like M$ DOS).
+ *
+ * SIIG support added by Andrey Panin <pazke@donpac.ru>, 10/1999
+ *
+ * There is two family of SIIG serial cards with different PCI
+ * interface chip and different configuration methods:
+ * - 10x cards have control registers in IO and/or memory space;
+ * - 20x cards have control registers in standard PCI configuration space.
+ *
+ * Note: all 10x cards have PCI device ids 0x10..
+ * all 20x cards have PCI device ids 0x20..
+ *
+ * There are also Quartet Serial cards which use Oxford Semiconductor
+ * 16954 quad UART PCI chip clocked by 18.432 MHz quartz.
+ *
+ * Note: some SIIG cards are probed by the parport_serial object.
+ */
+
+#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
+
+static int pci_siig10x_init(struct pci_dev *dev)
+{
+ u16 data;
+ void __iomem *p;
+
+ switch (dev->device & 0xfff8) {
+ case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
+ data = 0xffdf;
+ break;
+ case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */
+ data = 0xf7ff;
+ break;
+ default: /* 1S1P, 4S */
+ data = 0xfffb;
+ break;
+ }
+
+ p = pci_iomap(dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ writew(readw(p + 0x28) & data, p + 0x28);
+ readw(p + 0x28);
+
+
+ return 0;
+}
+
+#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
+
+static int pci_siig20x_init(struct pci_dev *dev)
+{
+ u8 data;
+
+ /* Change clock frequency for the first UART. */
+ pci_read_config_byte(dev, 0x6f, &data);
+ pci_write_config_byte(dev, 0x6f, data & 0xef);
+
+ /* If this card has 2 UART, we have to do the same with second UART. */
+ if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
+ ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
+ pci_read_config_byte(dev, 0x73, &data);
+ pci_write_config_byte(dev, 0x73, data & 0xef);
+ }
+ return 0;
+}
+
+static int pci_siig_init(struct pci_dev *dev)
+{
+ unsigned int type = dev->device & 0xff00;
+
+ if (type == 0x1000)
+ return pci_siig10x_init(dev);
+ else if (type == 0x2000)
+ return pci_siig20x_init(dev);
+
+ moan_device("Unknown SIIG card", dev);
+ return -ENODEV;
+}
+
+static int pci_siig_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
+
+ if (idx > 3) {
+ bar = 4;
+ offset = (idx - 4) * 8;
+ }
+
+ return setup_port(priv, port, bar, offset, 0);
+}
+
+/*
+ * Timedia has an explosion of boards, and to avoid the PCI table from
+ * growing *huge*, we use this function to collapse some 70 entries
+ * in the PCI table into one, for sanity's and compactness's sake.
+ */
+static const unsigned short timedia_single_port[] = {
+ 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0
+};
+
+static const unsigned short timedia_dual_port[] = {
+ 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
+ 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
+ 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
+ 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
+ 0xD079, 0
+};
+
+static const unsigned short timedia_quad_port[] = {
+ 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
+ 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
+ 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
+ 0xB157, 0
+};
+
+static const unsigned short timedia_eight_port[] = {
+ 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
+ 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0
+};
+
+static const struct timedia_struct {
+ int num;
+ const unsigned short *ids;
+} timedia_data[] = {
+ { 1, timedia_single_port },
+ { 2, timedia_dual_port },
+ { 4, timedia_quad_port },
+ { 8, timedia_eight_port }
+};
+
+/*
+ * There are nearly 70 different Timedia/SUNIX PCI serial devices. Instead of
+ * listing them individually, this driver merely grabs them all with
+ * PCI_ANY_ID. Some of these devices, however, also feature a parallel port,
+ * and should be left free to be claimed by parport_serial instead.
+ */
+static int pci_timedia_probe(struct pci_dev *dev)
+{
+ /*
+ * Check the third digit of the subdevice ID
+ * (0,2,3,5,6: serial only -- 7,8,9: serial + parallel)
+ */
+ if ((dev->subsystem_device & 0x00f0) >= 0x70) {
+ dev_info(&dev->dev,
+ "ignoring Timedia subdevice %04x for parport_serial\n",
+ dev->subsystem_device);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int pci_timedia_init(struct pci_dev *dev)
+{
+ const unsigned short *ids;
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(timedia_data); i++) {
+ ids = timedia_data[i].ids;
+ for (j = 0; ids[j]; j++)
+ if (dev->subsystem_device == ids[j])
+ return timedia_data[i].num;
+ }
+ return 0;
+}
+
+/*
+ * Timedia/SUNIX uses a mixture of BARs and offsets
+ * Ugh, this is ugly as all hell --- TYT
+ */
+static int
+pci_timedia_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar = 0, offset = board->first_offset;
+
+ switch (idx) {
+ case 0:
+ bar = 0;
+ break;
+ case 1:
+ offset = board->uart_offset;
+ bar = 0;
+ break;
+ case 2:
+ bar = 1;
+ break;
+ case 3:
+ offset = board->uart_offset;
+ /* FALLTHROUGH */
+ case 4: /* BAR 2 */
+ case 5: /* BAR 3 */
+ case 6: /* BAR 4 */
+ case 7: /* BAR 5 */
+ bar = idx - 2;
+ }
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+/*
+ * Some Titan cards are also a little weird
+ */
+static int
+titan_400l_800l_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar, offset = board->first_offset;
+
+ switch (idx) {
+ case 0:
+ bar = 1;
+ break;
+ case 1:
+ bar = 2;
+ break;
+ default:
+ bar = 4;
+ offset = (idx - 2) * board->uart_offset;
+ }
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int pci_xircom_init(struct pci_dev *dev)
+{
+ mdelay(100);
+ return 0;
+}
+
+static int pci_ni8420_init(struct pci_dev *dev)
+{
+ void __iomem *p;
+ unsigned int bar = 0;
+
+ if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
+ moan_device("no memory in bar", dev);
+ return 0;
+ }
+
+ p = pci_iomap(dev, bar);
+ if (p == NULL)
+ return -ENOMEM;
+
+ /* Disable the CPU Interrupt */
+ writel(readl(p + NI8420_INT_ENABLE_REG) & ~(NI8420_INT_ENABLE_BIT),
+ p + NI8420_INT_ENABLE_REG);
+
+ return 0;
+}
+
+static int pci_ni8430_init(struct pci_dev *dev)
+{
+ return -ENOSYS;
+}
+
+/* UART Port Control Register */
+#define NI16550_PCR_OFFSET 0x0f
+#define NI16550_PCR_RS422 0x00
+#define NI16550_PCR_ECHO_RS485 0x01
+#define NI16550_PCR_DTR_RS485 0x02
+#define NI16550_PCR_AUTO_RS485 0x03
+#define NI16550_PCR_WIRE_MODE_MASK 0x03
+#define NI16550_PCR_TXVR_ENABLE_BIT BIT(3)
+#define NI16550_PCR_RS485_TERMINATION_BIT BIT(6)
+#define NI16550_ACR_DTR_AUTO_DTR (0x2 << 3)
+#define NI16550_ACR_DTR_MANUAL_DTR (0x0 << 3)
+
+static int
+pci_ni8430_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ struct pci_dev *dev = priv->dev;
+ void __iomem *p;
+ unsigned int bar, offset = board->first_offset;
+
+ if (idx >= board->num_ports)
+ return 1;
+
+ bar = FL_GET_BASE(board->flags);
+ offset += idx * board->uart_offset;
+
+ p = pci_iomap(dev, bar);
+ if (!p)
+ return -ENOMEM;
+
+ /* enable the transceiver */
+ writeb(readb(p + offset + NI16550_PCR_OFFSET) | NI16550_PCR_TXVR_ENABLE_BIT,
+ p + offset + NI16550_PCR_OFFSET);
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
+static int pci_ni8431_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *uart, int idx)
+{
+ return -ENOSYS;
+}
+
+static int pci_netmos_9900_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar;
+
+ if ((priv->dev->device != PCI_DEVICE_ID_NETMOS_9865) &&
+ (priv->dev->subsystem_device & 0xff00) == 0x3000) {
+ /* netmos apparently orders BARs by datasheet layout, so serial
+ * ports get BARs 0 and 3 (or 1 and 4 for memmapped)
+ */
+ bar = 3 * idx;
+
+ return setup_port(priv, port, bar, 0, board->reg_shift);
+ } else {
+ return pci_default_setup(priv, board, port, idx);
+ }
+}
+
+/* the 99xx series comes with a range of device IDs and a variety
+ * of capabilities:
+ *
+ * 9900 has varying capabilities and can cascade to sub-controllers
+ * (cascading should be purely internal)
+ * 9904 is hardwired with 4 serial ports
+ * 9912 and 9922 are hardwired with 2 serial ports
+ */
+static int pci_netmos_9900_numports(struct pci_dev *dev)
+{
+ unsigned int c = dev->class;
+ unsigned int pi;
+ unsigned short sub_serports;
+
+ pi = c & 0xff;
+
+ if (pi == 2)
+ return 1;
+
+ if ((pi == 0) && (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
+ /* two possibilities: 0x30ps encodes number of parallel and
+ * serial ports, or 0x1000 indicates *something*. This is not
+ * immediately obvious, since the 2s1p+4s configuration seems
+ * to offer all functionality on functions 0..2, while still
+ * advertising the same function 3 as the 4s+2s1p config.
+ */
+ sub_serports = dev->subsystem_device & 0xf;
+ if (sub_serports > 0)
+ return sub_serports;
+
+ dev_err(&dev->dev,
+ "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
+ return 0;
+ }
+
+ moan_device("unknown NetMos/Mostech program interface", dev);
+ return 0;
+}
+
+static int pci_netmos_init(struct pci_dev *dev)
+{
+ /* subdevice 0x00PS means <P> parallel, <S> serial */
+ unsigned int num_serial = dev->subsystem_device & 0xf;
+
+ if ((dev->device == PCI_DEVICE_ID_NETMOS_9901) ||
+ (dev->device == PCI_DEVICE_ID_NETMOS_9865))
+ return 0;
+
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
+ dev->subsystem_device == 0x0299)
+ return 0;
+
+ switch (dev->device) { /* FALLTHROUGH on all */
+ case PCI_DEVICE_ID_NETMOS_9904:
+ case PCI_DEVICE_ID_NETMOS_9912:
+ case PCI_DEVICE_ID_NETMOS_9922:
+ case PCI_DEVICE_ID_NETMOS_9900:
+ num_serial = pci_netmos_9900_numports(dev);
+ break;
+
+ default:
+ break;
+ }
+
+ if (num_serial == 0) {
+ moan_device("unknown NetMos/Mostech device", dev);
+ return -ENODEV;
+ }
+
+ return num_serial;
+}
+
+/*
+ * These chips are available with optionally one parallel port and up to
+ * two serial ports. Unfortunately they all have the same product id.
+ *
+ * Basic configuration is done over a region of 32 I/O ports. The base
+ * ioport is called INTA or INTC, depending on docs/other drivers.
+ *
+ * The region of the 32 I/O ports is configured in POSIO0R...
+ */
+
+/* registers */
+#define ITE_887x_MISCR 0x9c
+#define ITE_887x_INTCBAR 0x78
+#define ITE_887x_UARTBAR 0x7c
+#define ITE_887x_PS0BAR 0x10
+#define ITE_887x_POSIO0 0x60
+
+/* I/O space size */
+#define ITE_887x_IOSIZE 32
+/* I/O space size (bits 26-24; 8 bytes = 011b) */
+#define ITE_887x_POSIO_IOSIZE_8 (3 << 24)
+/* I/O space size (bits 26-24; 32 bytes = 101b) */
+#define ITE_887x_POSIO_IOSIZE_32 (5 << 24)
+/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */
+#define ITE_887x_POSIO_SPEED (3 << 29)
+/* enable IO_Space bit */
+#define ITE_887x_POSIO_ENABLE (1 << 31)
+
+static int pci_ite887x_init(struct pci_dev *dev)
+{
+ struct serial_private *priv;
+ /* inta_addr are the configuration addresses of the ITE */
+ static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0,
+ 0x200, 0x280, 0 };
+ int ret, i, type;
+ struct resource *iobase = NULL;
+ u32 miscr, uartbar, ioport;
+
+ /* search for the base-ioport */
+ i = 0;
+ while (inta_addr[i] && iobase == NULL) {
+ iobase = request_ioport_region("ite887x",
+ inta_addr[i],
+ inta_addr[i] + ITE_887x_IOSIZE - 1);
+ if (!IS_ERR(iobase)) {
+ /* write POSIO0R - speed | size | ioport */
+ pci_write_config_dword(dev, ITE_887x_POSIO0,
+ ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+ ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]);
+ /* write INTCBAR - ioport */
+ pci_write_config_dword(dev, ITE_887x_INTCBAR,
+ inta_addr[i]);
+ ret = inb(inta_addr[i]);
+ if (ret != 0xff) {
+ /* ioport connected */
+ break;
+ }
+ release_region(iobase);
+ iobase = NULL;
+ }
+ i++;
+ }
+
+ if (!inta_addr[i]) {
+ dev_err(&dev->dev, "ite887x: could not find iobase\n");
+ return -ENODEV;
+ }
+
+ /* start of undocumented type checking (see parport_pc.c) */
+ type = inb(iobase->start + 0x18) & 0x0f;
+
+ switch (type) {
+ case 0x2: /* ITE8871 (1P) */
+ case 0xa: /* ITE8875 (1P) */
+ ret = 0;
+ break;
+ case 0xe: /* ITE8872 (2S1P) */
+ ret = 2;
+ break;
+ case 0x6: /* ITE8873 (1S) */
+ ret = 1;
+ break;
+ case 0x8: /* ITE8874 (2S) */
+ ret = 2;
+ break;
+ default:
+ moan_device("Unknown ITE887x", dev);
+ ret = -ENODEV;
+ }
+
+ /* configure all serial ports */
+ for (i = 0; i < ret; i++) {
+ /* read the I/O port from the device */
+ pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)),
+ &ioport);
+ ioport &= 0x0000FF00; /* the actual base address */
+ pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)),
+ ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+ ITE_887x_POSIO_IOSIZE_8 | ioport);
+
+ /* write the ioport to the UARTBAR */
+ pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar);
+ uartbar &= ~(0xffff << (16 * i)); /* clear half the reg */
+ uartbar |= (ioport << (16 * i)); /* set the ioport */
+ pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar);
+
+ /* get current config */
+ pci_read_config_dword(dev, ITE_887x_MISCR, &miscr);
+ /* disable interrupts (UARTx_Routing[3:0]) */
+ miscr &= ~(0xf << (12 - 4 * i));
+ /* activate the UART (UARTx_En) */
+ miscr |= 1 << (23 - i);
+ /* write new config with activated UART */
+ pci_write_config_dword(dev, ITE_887x_MISCR, miscr);
+ }
+
+ if (ret <= 0) {
+ /* the device has no UARTs if we get here */
+ release_region(iobase);
+ }
+
+ priv = dev->dev.priv;
+ priv->private_data = iobase;
+
+ return ret;
+}
+
+static void pci_ite887x_exit(struct pci_dev *dev)
+{
+ struct serial_private *priv;
+ u32 ioport;
+ /* the ioport is bit 0-15 in POSIO0R */
+ pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport);
+ ioport &= 0xffff;
+
+ priv = dev->dev.priv;
+ if (priv->private_data)
+ release_region(priv->private_data);
+}
+
+/*
+ * EndRun Technologies.
+ * Determine the number of ports available on the device.
+ */
+#define PCI_VENDOR_ID_ENDRUN 0x7401
+#define PCI_DEVICE_ID_ENDRUN_1588 0xe100
+
+static int pci_endrun_init(struct pci_dev *dev)
+{
+ u8 __iomem *p;
+ unsigned long deviceID;
+ unsigned int number_uarts = 0;
+
+ /* EndRun device is all 0xexxx */
+ if (dev->vendor == PCI_VENDOR_ID_ENDRUN &&
+ (dev->device & 0xf000) != 0xe000)
+ return 0;
+
+ p = pci_iomap(dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ deviceID = ioread32(p);
+ /* EndRun device */
+ if (deviceID == 0x07000200) {
+ number_uarts = ioread8(p + 4);
+ dev_dbg(&dev->dev,
+ "%d ports detected on EndRun PCI Express device\n",
+ number_uarts);
+ }
+
+ return number_uarts;
+}
+
+/*
+ * Oxford Semiconductor Inc.
+ * Check that device is part of the Tornado range of devices, then determine
+ * the number of ports available on the device.
+ */
+static int pci_oxsemi_tornado_init(struct pci_dev *dev)
+{
+ u8 __iomem *p;
+ unsigned long deviceID;
+ unsigned int number_uarts = 0;
+
+ /* OxSemi Tornado devices are all 0xCxxx */
+ if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
+ (dev->device & 0xF000) != 0xC000)
+ return 0;
+
+ p = pci_iomap(dev, 0);
+ if (p == NULL)
+ return -ENOMEM;
+
+ deviceID = ioread32(p);
+ /* Tornado device */
+ if (deviceID == 0x07000200) {
+ number_uarts = ioread8(p + 4);
+ dev_dbg(&dev->dev,
+ "%d ports detected on Oxford PCI Express device\n",
+ number_uarts);
+ }
+
+ return number_uarts;
+}
+
+static int pci_asix_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+/* Quatech devices have their own extra interface features */
+
+struct quatech_feature {
+ u16 devid;
+ bool amcc;
+};
+
+#define QPCR_TEST_FOR1 0x3F
+#define QPCR_TEST_GET1 0x00
+#define QPCR_TEST_FOR2 0x40
+#define QPCR_TEST_GET2 0x40
+#define QPCR_TEST_FOR3 0x80
+#define QPCR_TEST_GET3 0x40
+#define QPCR_TEST_FOR4 0xC0
+#define QPCR_TEST_GET4 0x80
+
+#define QOPR_CLOCK_X1 0x0000
+#define QOPR_CLOCK_X2 0x0001
+#define QOPR_CLOCK_X4 0x0002
+#define QOPR_CLOCK_X8 0x0003
+#define QOPR_CLOCK_RATE_MASK 0x0003
+
+
+static struct quatech_feature quatech_cards[] = {
+ { PCI_DEVICE_ID_QUATECH_QSC100, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSC100, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSC100E, 0 },
+ { PCI_DEVICE_ID_QUATECH_DSC200, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSC200E, 0 },
+ { PCI_DEVICE_ID_QUATECH_ESC100D, 1 },
+ { PCI_DEVICE_ID_QUATECH_ESC100M, 1 },
+ { PCI_DEVICE_ID_QUATECH_QSCP100, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSCP100, 1 },
+ { PCI_DEVICE_ID_QUATECH_QSCP200, 1 },
+ { PCI_DEVICE_ID_QUATECH_DSCP200, 1 },
+ { PCI_DEVICE_ID_QUATECH_ESCLP100, 0 },
+ { PCI_DEVICE_ID_QUATECH_QSCLP100, 0 },
+ { PCI_DEVICE_ID_QUATECH_DSCLP100, 0 },
+ { PCI_DEVICE_ID_QUATECH_SSCLP100, 0 },
+ { PCI_DEVICE_ID_QUATECH_QSCLP200, 0 },
+ { PCI_DEVICE_ID_QUATECH_DSCLP200, 0 },
+ { PCI_DEVICE_ID_QUATECH_SSCLP200, 0 },
+ { PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 },
+ { 0, }
+};
+
+static int pci_quatech_amcc(u16 devid)
+{
+ struct quatech_feature *qf = &quatech_cards[0];
+ while (qf->devid) {
+ if (qf->devid == devid)
+ return qf->amcc;
+ qf++;
+ }
+ pr_err("quatech: unknown port type '0x%04X'.\n", devid);
+ return 0;
+};
+
+static int pci_quatech_rqopr(struct uart_8250_port *port)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR, val;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ val = inb(base + scr);
+ outb(LCR, base + lcr);
+ return val;
+}
+
+static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ inb(base + scr);
+ outb(qopr, base + scr);
+ outb(LCR, base + lcr);
+}
+
+static int pci_quatech_rqmcr(struct uart_8250_port *port)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR, val, qmcr;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ val = inb(base + scr);
+ outb(val | 0x10, base + scr);
+ qmcr = inb(base + mcr);
+ outb(val, base + scr);
+ outb(LCR, base + lcr);
+
+ return qmcr;
+}
+
+static void pci_quatech_wqmcr(struct uart_8250_port *port, u8 qmcr)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR, val;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ val = inb(base + scr);
+ outb(val | 0x10, base + scr);
+ outb(qmcr, base + mcr);
+ outb(val, base + scr);
+ outb(LCR, base + lcr);
+}
+
+static int pci_quatech_has_qmcr(struct uart_8250_port *port)
+{
+ unsigned long base = port->resource.start;
+ u8 LCR, val;
+
+ LCR = inb(base + lcr);
+ outb(0xBF, base + lcr);
+ val = inb(base + scr);
+ if (val & 0x20) {
+ outb(0x80, lcr);
+ if (!(inb(scr) & 0x20)) {
+ outb(LCR, base + lcr);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pci_quatech_test(struct uart_8250_port *port)
+{
+ u8 reg, qopr;
+
+ qopr = pci_quatech_rqopr(port);
+ pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1);
+ reg = pci_quatech_rqopr(port) & 0xC0;
+ if (reg != QPCR_TEST_GET1)
+ return -EINVAL;
+ pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR2);
+ reg = pci_quatech_rqopr(port) & 0xC0;
+ if (reg != QPCR_TEST_GET2)
+ return -EINVAL;
+ pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR3);
+ reg = pci_quatech_rqopr(port) & 0xC0;
+ if (reg != QPCR_TEST_GET3)
+ return -EINVAL;
+ pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR4);
+ reg = pci_quatech_rqopr(port) & 0xC0;
+ if (reg != QPCR_TEST_GET4)
+ return -EINVAL;
+
+ pci_quatech_wqopr(port, qopr);
+ return 0;
+}
+
+static int pci_quatech_clock(struct uart_8250_port *port)
+{
+ u8 qopr, reg, set;
+ unsigned long clock;
+
+ if (pci_quatech_test(port) < 0)
+ return 1843200;
+
+ qopr = pci_quatech_rqopr(port);
+
+ pci_quatech_wqopr(port, qopr & ~QOPR_CLOCK_X8);
+ reg = pci_quatech_rqopr(port);
+ if (reg & QOPR_CLOCK_X8) {
+ clock = 1843200;
+ goto out;
+ }
+ pci_quatech_wqopr(port, qopr | QOPR_CLOCK_X8);
+ reg = pci_quatech_rqopr(port);
+ if (!(reg & QOPR_CLOCK_X8)) {
+ clock = 1843200;
+ goto out;
+ }
+ reg &= QOPR_CLOCK_X8;
+ if (reg == QOPR_CLOCK_X2) {
+ clock = 3685400;
+ set = QOPR_CLOCK_X2;
+ } else if (reg == QOPR_CLOCK_X4) {
+ clock = 7372800;
+ set = QOPR_CLOCK_X4;
+ } else if (reg == QOPR_CLOCK_X8) {
+ clock = 14745600;
+ set = QOPR_CLOCK_X8;
+ } else {
+ clock = 1843200;
+ set = QOPR_CLOCK_X1;
+ }
+ qopr &= ~QOPR_CLOCK_RATE_MASK;
+ qopr |= set;
+
+out:
+ pci_quatech_wqopr(port, qopr);
+ return clock;
+}
+
+static int pci_quatech_rs422(struct uart_8250_port *port)
+{
+ u8 qmcr;
+ int rs422 = 0;
+
+ if (!pci_quatech_has_qmcr(port))
+ return 0;
+ qmcr = pci_quatech_rqmcr(port);
+ pci_quatech_wqmcr(port, 0xFF);
+ if (pci_quatech_rqmcr(port))
+ rs422 = 1;
+ pci_quatech_wqmcr(port, qmcr);
+ return rs422;
+}
+
+static int pci_quatech_init(struct pci_dev *dev)
+{
+ if (pci_quatech_amcc(dev->device)) {
+ unsigned long base = pci_resource_start(dev, 0);
+ if (base) {
+ u32 tmp;
+
+ outl(inl(base + 0x38) | 0x00002000, base + 0x38);
+ tmp = inl(base + 0x3c);
+ outl(tmp | 0x01000000, base + 0x3c);
+ outl(tmp & ~0x01000000, base + 0x3c);
+ }
+ }
+ return 0;
+}
+
+static int pci_quatech_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ /* Needed by pci_quatech calls below */
+ port->resource.start = pci_resource_start(priv->dev, FL_GET_BASE(board->flags));
+ /* Set up the clocking */
+ port->pdata->clock = pci_quatech_clock(port);
+ /* For now just warn about RS422 */
+ if (pci_quatech_rs422(port))
+ pr_warn("quatech: software control of RS422 features not currently supported.\n");
+ return pci_default_setup(priv, board, port, idx);
+}
+
+static int pci_default_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar, offset = board->first_offset, maxnr;
+
+ bar = FL_GET_BASE(board->flags);
+ if (board->flags & FL_BASE_BARS)
+ bar += idx;
+ else
+ offset += idx * board->uart_offset;
+
+ maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+ (board->reg_shift + 3);
+
+ if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
+ return 1;
+
+ return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+static int pci_pericom_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int pci_pericom_setup_four_at_eight(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+ce4100_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_omegapci_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return setup_port(priv, port, 2, idx * 8, 0);
+}
+
+static int
+pci_brcm_trumanage_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+/* RTS will control by MCR if this bit is 0 */
+#define FINTEK_RTS_CONTROL_BY_HW BIT(4)
+/* only worked with FINTEK_RTS_CONTROL_BY_HW on */
+#define FINTEK_RTS_INVERT BIT(5)
+
+static int pci_fintek_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ struct pci_dev *pdev = priv->dev;
+ u8 config_base;
+ u16 iobase;
+
+ config_base = 0x40 + 0x08 * idx;
+
+ /* Get the io address from configuration space */
+ pci_read_config_word(pdev, config_base + 4, &iobase);
+
+ dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase);
+
+ port->resource.flags = IORESOURCE_IO;
+ port->resource.start = iobase;
+ port->resource.end = iobase + 8 - 1;
+
+ return 0;
+}
+
+static int pci_fintek_init(struct pci_dev *dev)
+{
+ unsigned long iobase;
+ u32 max_port, i;
+ resource_size_t bar_data[3];
+ u8 config_base;
+
+ if (!(pci_resource_flags(dev, 5) & IORESOURCE_IO) ||
+ !(pci_resource_flags(dev, 4) & IORESOURCE_IO) ||
+ !(pci_resource_flags(dev, 3) & IORESOURCE_IO))
+ return -ENODEV;
+
+ switch (dev->device) {
+ case 0x1104: /* 4 ports */
+ case 0x1108: /* 8 ports */
+ max_port = dev->device & 0xff;
+ break;
+ case 0x1112: /* 12 ports */
+ max_port = 12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Get the io address dispatch from the BIOS */
+ bar_data[0] = pci_resource_start(dev, 5);
+ bar_data[1] = pci_resource_start(dev, 4);
+ bar_data[2] = pci_resource_start(dev, 3);
+
+ for (i = 0; i < max_port; ++i) {
+ /* UART0 configuration offset start from 0x40 */
+ config_base = 0x40 + 0x08 * i;
+
+ /* Calculate Real IO Port */
+ iobase = (bar_data[i / 4] & 0xffffffe0) + (i % 4) * 8;
+
+ /* Enable UART I/O port */
+ pci_write_config_byte(dev, config_base + 0x00, 0x01);
+
+ /* Select 128-byte FIFO and 8x FIFO threshold */
+ pci_write_config_byte(dev, config_base + 0x01, 0x33);
+
+ /* LSB UART */
+ pci_write_config_byte(dev, config_base + 0x04,
+ (u8)(iobase & 0xff));
+
+ /* MSB UART */
+ pci_write_config_byte(dev, config_base + 0x05,
+ (u8)((iobase & 0xff00) >> 8));
+
+ /* First init without port data
+ * force init to RS232 Mode
+ */
+ pci_write_config_byte(dev, config_base + 0x07, 0x01);
+ }
+
+ return max_port;
+}
+
+static int pci_fintek_f815xxa_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int pci_fintek_f815xxa_init(struct pci_dev *dev)
+{
+ u32 max_port, i;
+ int config_base;
+
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM))
+ return -ENODEV;
+
+ switch (dev->device) {
+ case 0x1204: /* 4 ports */
+ case 0x1208: /* 8 ports */
+ max_port = dev->device & 0xff;
+ break;
+ case 0x1212: /* 12 ports */
+ max_port = 12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Set to mmio decode */
+ pci_write_config_byte(dev, 0x209, 0x40);
+
+ for (i = 0; i < max_port; ++i) {
+ /* UART0 configuration offset start from 0x2A0 */
+ config_base = 0x2A0 + 0x08 * i;
+
+ /* Select 128-byte FIFO and 8x FIFO threshold */
+ pci_write_config_byte(dev, config_base + 0x01, 0x33);
+
+ /* Enable UART I/O port */
+ pci_write_config_byte(dev, config_base + 0, 0x01);
+ }
+
+ return max_port;
+}
+
+static int skip_tx_en_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int kt_serial_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_wch_ch353_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_wch_ch355_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_wch_ch38x_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_sunix_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ return -ENOSYS;
+}
+
+static int
+pci_moxa_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
+{
+ unsigned int bar = FL_GET_BASE(board->flags);
+ int offset;
+
+ if (board->num_ports == 4 && idx == 3)
+ offset = 7 * board->uart_offset;
+ else
+ offset = idx * board->uart_offset;
+
+ return setup_port(priv, port, bar, offset, 0);
+}
+
+#define PCI_VENDOR_ID_SBSMODULARIO 0x124B
+#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B
+#define PCI_DEVICE_ID_OCTPRO 0x0001
+#define PCI_SUBDEVICE_ID_OCTPRO232 0x0108
+#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208
+#define PCI_SUBDEVICE_ID_POCTAL232 0x0308
+#define PCI_SUBDEVICE_ID_POCTAL422 0x0408
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_00 0x2500
+#define PCI_SUBDEVICE_ID_SIIG_DUAL_30 0x2530
+#define PCI_VENDOR_ID_ADVANTECH 0x13fe
+#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
+#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
+#define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618
+#define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618
+#define PCI_DEVICE_ID_TITAN_200I 0x8028
+#define PCI_DEVICE_ID_TITAN_400I 0x8048
+#define PCI_DEVICE_ID_TITAN_800I 0x8088
+#define PCI_DEVICE_ID_TITAN_800EH 0xA007
+#define PCI_DEVICE_ID_TITAN_800EHB 0xA008
+#define PCI_DEVICE_ID_TITAN_400EH 0xA009
+#define PCI_DEVICE_ID_TITAN_100E 0xA010
+#define PCI_DEVICE_ID_TITAN_200E 0xA012
+#define PCI_DEVICE_ID_TITAN_400E 0xA013
+#define PCI_DEVICE_ID_TITAN_800E 0xA014
+#define PCI_DEVICE_ID_TITAN_200EI 0xA016
+#define PCI_DEVICE_ID_TITAN_200EISI 0xA017
+#define PCI_DEVICE_ID_TITAN_200V3 0xA306
+#define PCI_DEVICE_ID_TITAN_400V3 0xA310
+#define PCI_DEVICE_ID_TITAN_410V3 0xA312
+#define PCI_DEVICE_ID_TITAN_800V3 0xA314
+#define PCI_DEVICE_ID_TITAN_800V3B 0xA315
+#define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538
+#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
+#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
+#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
+#define PCI_VENDOR_ID_WCH 0x4348
+#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
+#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
+#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
+#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
+#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
+#define PCI_DEVICE_ID_WCH_CH355_4S 0x7173
+#define PCI_VENDOR_ID_AGESTAR 0x5372
+#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
+#define PCI_VENDOR_ID_ASIX 0x9710
+#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
+#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
+
+#define PCIE_VENDOR_ID_WCH 0x1c00
+#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
+#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470
+#define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253
+
+#define PCI_VENDOR_ID_PERICOM 0x12D8
+#define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951
+#define PCI_DEVICE_ID_PERICOM_PI7C9X7952 0x7952
+#define PCI_DEVICE_ID_PERICOM_PI7C9X7954 0x7954
+#define PCI_DEVICE_ID_PERICOM_PI7C9X7958 0x7958
+
+#define PCI_VENDOR_ID_ACCESIO 0x494f
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB 0x1051
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S 0x1053
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB 0x105C
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S 0x105E
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB 0x1091
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2 0x1093
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB 0x1099
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4 0x109B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB 0x10D1
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM 0x10D3
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB 0x10DA
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM 0x10DC
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1 0x1108
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2 0x1110
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2 0x1111
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4 0x1118
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4 0x1119
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S 0x1152
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S 0x115A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2 0x1190
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2 0x1191
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4 0x1198
+#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4 0x1199
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM 0x11D0
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4 0x105A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4 0x105B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8 0x106A
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8 0x106B
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4 0x1098
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8 0x10A9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM 0x10D9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM 0x10E9
+#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM 0x11D8
+
+#define PCIE_DEVICE_ID_NI_PXIE8430_2328 0x74C2
+#define PCIE_DEVICE_ID_NI_PXIE8430_23216 0x74C1
+#define PCI_DEVICE_ID_NI_PXI8431_4852 0x7081
+#define PCI_DEVICE_ID_NI_PXI8431_4854 0x70DE
+#define PCI_DEVICE_ID_NI_PXI8431_4858 0x70E3
+#define PCI_DEVICE_ID_NI_PXI8433_4852 0x70E9
+#define PCI_DEVICE_ID_NI_PXI8433_4854 0x70ED
+#define PCIE_DEVICE_ID_NI_PXIE8431_4858 0x74C4
+#define PCIE_DEVICE_ID_NI_PXIE8431_48516 0x74C3
+
+#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
+#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
+#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045
+#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144
+#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160
+#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161
+#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182
+#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183
+#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322
+#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342
+#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
+#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
+
+/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
+#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
+#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588
+
+/*
+ * Master list of serial port init/setup/exit quirks.
+ * This does not describe the general nature of the port.
+ * (ie, baud base, number and location of ports, etc)
+ *
+ * This list is ordered alphabetically by vendor then device.
+ * Specific entries must come before more generic entries.
+ */
+static struct pci_serial_quirk pci_serial_quirks[] = {
+ /*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+ {
+ .vendor = PCI_VENDOR_ID_AMCC,
+ .device = PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = addidata_apci7800_setup,
+ },
+ /*
+ * AFAVLAB cards - these may be called via parport_serial
+ * It is not clear whether this applies to all products.
+ */
+ {
+ .vendor = PCI_VENDOR_ID_AFAVLAB,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = afavlab_setup,
+ },
+ /*
+ * HP Diva
+ */
+ {
+ .vendor = PCI_VENDOR_ID_HP,
+ .device = PCI_DEVICE_ID_HP_DIVA,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_hp_diva_init,
+ .setup = pci_hp_diva_setup,
+ },
+ /*
+ * Intel
+ */
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_80960_RP,
+ .subvendor = 0xe4bf,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_inteli960ni_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_8257X_SOL,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = skip_tx_en_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82573L_SOL,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = skip_tx_en_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82573E_SOL,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = skip_tx_en_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_CE4100_UART,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = ce4100_serial_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PATSBURG_KT,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = kt_serial_setup,
+ },
+ /*
+ * ITE
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ITE,
+ .device = PCI_DEVICE_ID_ITE_8872,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ite887x_init,
+ .setup = pci_default_setup,
+ .exit = pci_ite887x_exit,
+ },
+ /*
+ * National Instruments
+ */
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI23216,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2328,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2324,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2322,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2324I,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PCI2322I,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8420_23216,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8420_2328,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8420_2324,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8420_2322,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8422_2324,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8422_2322,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8420_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8430_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCIE_DEVICE_ID_NI_PXIE8430_2328,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8430_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCIE_DEVICE_ID_NI_PXIE8430_23216,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8430_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8431_4852,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8431_4854,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8431_4858,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8433_4852,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCI_DEVICE_ID_NI_PXI8433_4854,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCIE_DEVICE_ID_NI_PXIE8431_4858,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_NI,
+ .device = PCIE_DEVICE_ID_NI_PXIE8431_48516,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_ni8430_init,
+ .setup = pci_ni8431_setup,
+ },
+ /* Quatech */
+ {
+ .vendor = PCI_VENDOR_ID_QUATECH,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_quatech_init,
+ .setup = pci_quatech_setup,
+ },
+ /*
+ * Panacom
+ */
+ {
+ .vendor = PCI_VENDOR_ID_PANACOM,
+ .device = PCI_DEVICE_ID_PANACOM_QUADMODEM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PANACOM,
+ .device = PCI_DEVICE_ID_PANACOM_DUALMODEM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ /*
+ * Pericom (Only 7954 - It have a offset jump for port 4)
+ */
+ {
+ .vendor = PCI_VENDOR_ID_PERICOM,
+ .device = PCI_DEVICE_ID_PERICOM_PI7C9X7954,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ /*
+ * PLX
+ */
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9050,
+ .subvendor = PCI_SUBVENDOR_ID_EXSYS,
+ .subdevice = PCI_SUBDEVICE_ID_EXSYS_4055,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9050,
+ .subvendor = PCI_SUBVENDOR_ID_KEYSPAN,
+ .subdevice = PCI_SUBDEVICE_ID_KEYSPAN_SX2,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_ROMULUS,
+ .subvendor = PCI_VENDOR_ID_PLX,
+ .subdevice = PCI_DEVICE_ID_PLX_ROMULUS,
+ .init = pci_plx9050_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup_four_at_eight,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ }, /*
+ * SBS Technologies, Inc., PMC-OCTALPRO 232
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SBSMODULARIO,
+ .device = PCI_DEVICE_ID_OCTPRO,
+ .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO,
+ .subdevice = PCI_SUBDEVICE_ID_OCTPRO232,
+ .init = sbs_init,
+ .setup = sbs_setup,
+ },
+ /*
+ * SBS Technologies, Inc., PMC-OCTALPRO 422
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SBSMODULARIO,
+ .device = PCI_DEVICE_ID_OCTPRO,
+ .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO,
+ .subdevice = PCI_SUBDEVICE_ID_OCTPRO422,
+ .init = sbs_init,
+ .setup = sbs_setup,
+ },
+ /*
+ * SBS Technologies, Inc., P-Octal 232
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SBSMODULARIO,
+ .device = PCI_DEVICE_ID_OCTPRO,
+ .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO,
+ .subdevice = PCI_SUBDEVICE_ID_POCTAL232,
+ .init = sbs_init,
+ .setup = sbs_setup,
+ },
+ /*
+ * SBS Technologies, Inc., P-Octal 422
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SBSMODULARIO,
+ .device = PCI_DEVICE_ID_OCTPRO,
+ .subvendor = PCI_SUBVENDOR_ID_SBSMODULARIO,
+ .subdevice = PCI_SUBDEVICE_ID_POCTAL422,
+ .init = sbs_init,
+ .setup = sbs_setup,
+ },
+ /*
+ * SIIG cards - these may be called via parport_serial
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SIIG,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_siig_init,
+ .setup = pci_siig_setup,
+ },
+ /*
+ * Titan cards
+ */
+ {
+ .vendor = PCI_VENDOR_ID_TITAN,
+ .device = PCI_DEVICE_ID_TITAN_400L,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = titan_400l_800l_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_TITAN,
+ .device = PCI_DEVICE_ID_TITAN_800L,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = titan_400l_800l_setup,
+ },
+ /*
+ * Timedia cards
+ */
+ {
+ .vendor = PCI_VENDOR_ID_TIMEDIA,
+ .device = PCI_DEVICE_ID_TIMEDIA_1889,
+ .subvendor = PCI_VENDOR_ID_TIMEDIA,
+ .subdevice = PCI_ANY_ID,
+ .probe = pci_timedia_probe,
+ .init = pci_timedia_init,
+ .setup = pci_timedia_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_TIMEDIA,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_timedia_setup,
+ },
+ /*
+ * Sunix PCI serial boards
+ */
+ {
+ .vendor = PCI_VENDOR_ID_SUNIX,
+ .device = PCI_DEVICE_ID_SUNIX_1999,
+ .subvendor = PCI_VENDOR_ID_SUNIX,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_sunix_setup,
+ },
+ /*
+ * Xircom cards
+ */
+ {
+ .vendor = PCI_VENDOR_ID_XIRCOM,
+ .device = PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_xircom_init,
+ .setup = pci_default_setup,
+ },
+ /*
+ * Netmos cards - these may be called via parport_serial
+ */
+ {
+ .vendor = PCI_VENDOR_ID_NETMOS,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_netmos_init,
+ .setup = pci_netmos_9900_setup,
+ },
+ /*
+ * EndRun Technologies
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ENDRUN,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_endrun_init,
+ .setup = pci_default_setup,
+ },
+ /*
+ * For Oxford Semiconductor Tornado based devices
+ */
+ {
+ .vendor = PCI_VENDOR_ID_OXSEMI,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_MAINPINE,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_DIGI,
+ .device = PCIE_DEVICE_ID_NEO_2_OX_IBM,
+ .subvendor = PCI_SUBVENDOR_ID_IBM,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x8811,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x8812,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x8813,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x8814,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x8027,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x8028,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x8029,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x800C,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = 0x10DB,
+ .device = 0x800D,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ /*
+ * Cronyx Omega PCI (PLX-chip based)
+ */
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_CRONYX_OMEGA,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_omegapci_setup,
+ },
+ /* WCH CH353 1S1P card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_1S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 2S1P card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_2S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 4S card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 2S1PF card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH352 2S card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH352_2S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH355 4S card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH355_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch355_setup,
+ },
+ /* WCH CH382 2S card (16850 clone) */
+ {
+ .vendor = PCIE_VENDOR_ID_WCH,
+ .device = PCIE_DEVICE_ID_WCH_CH382_2S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch38x_setup,
+ },
+ /* WCH CH382 2S1P card (16850 clone) */
+ {
+ .vendor = PCIE_VENDOR_ID_WCH,
+ .device = PCIE_DEVICE_ID_WCH_CH382_2S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch38x_setup,
+ },
+ /* WCH CH384 4S card (16850 clone) */
+ {
+ .vendor = PCIE_VENDOR_ID_WCH,
+ .device = PCIE_DEVICE_ID_WCH_CH384_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch38x_setup,
+ },
+ /*
+ * ASIX devices with FIFO bug
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ASIX,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_asix_setup,
+ },
+ /*
+ * Broadcom TruManage (NetXtreme)
+ */
+ {
+ .vendor = PCI_VENDOR_ID_BROADCOM,
+ .device = PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_brcm_trumanage_setup,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1104,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_setup,
+ .init = pci_fintek_init,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1108,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_setup,
+ .init = pci_fintek_init,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1112,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_setup,
+ .init = pci_fintek_init,
+ },
+ /*
+ * MOXA
+ */
+ {
+ .vendor = PCI_VENDOR_ID_MOXA,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_moxa_setup,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1204,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_f815xxa_setup,
+ .init = pci_fintek_f815xxa_init,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1208,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_f815xxa_setup,
+ .init = pci_fintek_f815xxa_init,
+ },
+ {
+ .vendor = 0x1c29,
+ .device = 0x1212,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_fintek_f815xxa_setup,
+ .init = pci_fintek_f815xxa_init,
+ },
+
+ /*
+ * Default "match everything" terminator entry
+ */
+ {
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ }
+};
+
+static inline int quirk_id_matches(u32 quirk_id, u32 dev_id)
+{
+ return quirk_id == PCI_ANY_ID || quirk_id == dev_id;
+}
+
+static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
+{
+ struct pci_serial_quirk *quirk;
+
+ for (quirk = pci_serial_quirks; ; quirk++)
+ if (quirk_id_matches(quirk->vendor, dev->vendor) &&
+ quirk_id_matches(quirk->device, dev->device) &&
+ quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) &&
+ quirk_id_matches(quirk->subdevice, dev->subsystem_device))
+ break;
+ return quirk;
+}
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support. It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
+ *
+ * The makeup of these names are:
+ * pbn_bn{_bt}_n_baud{_offsetinhex}
+ *
+ * bn = PCI BAR number
+ * bt = Index using PCI BARs
+ * n = number of serial ports
+ * baud = baud rate
+ * offsetinhex = offset for each sequential port (in hex)
+ *
+ * This table is sorted by (in order): bn, bt, baud, offsetindex, n.
+ *
+ * Please note: in theory if n = 1, _bt infix should make no difference.
+ * ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200
+ */
+enum pci_board_num_t {
+ pbn_default = 0,
+
+ pbn_b0_1_115200,
+ pbn_b0_2_115200,
+ pbn_b0_4_115200,
+ pbn_b0_5_115200,
+ pbn_b0_8_115200,
+
+ pbn_b0_1_921600,
+ pbn_b0_2_921600,
+ pbn_b0_4_921600,
+
+ pbn_b0_2_1130000,
+
+ pbn_b0_4_1152000,
+
+ pbn_b0_4_1250000,
+
+ pbn_b0_2_1843200,
+ pbn_b0_4_1843200,
+
+ pbn_b0_1_4000000,
+
+ pbn_b0_bt_1_115200,
+ pbn_b0_bt_2_115200,
+ pbn_b0_bt_4_115200,
+ pbn_b0_bt_8_115200,
+
+ pbn_b0_bt_1_460800,
+ pbn_b0_bt_2_460800,
+ pbn_b0_bt_4_460800,
+
+ pbn_b0_bt_1_921600,
+ pbn_b0_bt_2_921600,
+ pbn_b0_bt_4_921600,
+ pbn_b0_bt_8_921600,
+
+ pbn_b1_1_115200,
+ pbn_b1_2_115200,
+ pbn_b1_4_115200,
+ pbn_b1_8_115200,
+ pbn_b1_16_115200,
+
+ pbn_b1_1_921600,
+ pbn_b1_2_921600,
+ pbn_b1_4_921600,
+ pbn_b1_8_921600,
+
+ pbn_b1_2_1250000,
+
+ pbn_b1_bt_1_115200,
+ pbn_b1_bt_2_115200,
+ pbn_b1_bt_4_115200,
+
+ pbn_b1_bt_2_921600,
+
+ pbn_b1_1_1382400,
+ pbn_b1_2_1382400,
+ pbn_b1_4_1382400,
+ pbn_b1_8_1382400,
+
+ pbn_b2_1_115200,
+ pbn_b2_2_115200,
+ pbn_b2_4_115200,
+ pbn_b2_8_115200,
+
+ pbn_b2_1_460800,
+ pbn_b2_4_460800,
+ pbn_b2_8_460800,
+ pbn_b2_16_460800,
+
+ pbn_b2_1_921600,
+ pbn_b2_4_921600,
+ pbn_b2_8_921600,
+
+ pbn_b2_8_1152000,
+
+ pbn_b2_bt_1_115200,
+ pbn_b2_bt_2_115200,
+ pbn_b2_bt_4_115200,
+
+ pbn_b2_bt_2_921600,
+ pbn_b2_bt_4_921600,
+
+ pbn_b3_2_115200,
+ pbn_b3_4_115200,
+ pbn_b3_8_115200,
+
+ pbn_b4_bt_2_921600,
+ pbn_b4_bt_4_921600,
+ pbn_b4_bt_8_921600,
+
+ /*
+ * Board-specific versions.
+ */
+ pbn_panacom,
+ pbn_panacom2,
+ pbn_panacom4,
+ pbn_plx_romulus,
+ pbn_endrun_2_4000000,
+ pbn_oxsemi,
+ pbn_oxsemi_1_4000000,
+ pbn_oxsemi_2_4000000,
+ pbn_oxsemi_4_4000000,
+ pbn_oxsemi_8_4000000,
+ pbn_intel_i960,
+ pbn_sgi_ioc3,
+ pbn_computone_4,
+ pbn_computone_6,
+ pbn_computone_8,
+ pbn_sbsxrsio,
+ pbn_pasemi_1682M,
+ pbn_ni8430_2,
+ pbn_ni8430_4,
+ pbn_ni8430_8,
+ pbn_ni8430_16,
+ pbn_ni8430_pxie_8,
+ pbn_ni8430_pxie_16,
+ pbn_ni8431_2,
+ pbn_ni8431_4,
+ pbn_ni8431_8,
+ pbn_ni8431_pxie_8,
+ pbn_ni8431_pxie_16,
+ pbn_ADDIDATA_PCIe_1_3906250,
+ pbn_ADDIDATA_PCIe_2_3906250,
+ pbn_ADDIDATA_PCIe_4_3906250,
+ pbn_ADDIDATA_PCIe_8_3906250,
+ pbn_ce4100_1_115200,
+ pbn_omegapci,
+ pbn_NETMOS9900_2s_115200,
+ pbn_brcm_trumanage,
+ pbn_fintek_4,
+ pbn_fintek_8,
+ pbn_fintek_12,
+ pbn_fintek_F81504A,
+ pbn_fintek_F81508A,
+ pbn_fintek_F81512A,
+ pbn_wch382_2,
+ pbn_wch384_4,
+ pbn_pericom_PI7C9X7951,
+ pbn_pericom_PI7C9X7952,
+ pbn_pericom_PI7C9X7954,
+ pbn_pericom_PI7C9X7958,
+ pbn_sunix_pci_1s,
+ pbn_sunix_pci_2s,
+ pbn_sunix_pci_4s,
+ pbn_sunix_pci_8s,
+ pbn_sunix_pci_16s,
+ pbn_moxa8250_2p,
+ pbn_moxa8250_4p,
+ pbn_moxa8250_8p,
+};
+
+/*
+ * uart_offset - the space between channels
+ * reg_shift - describes how the UART registers are mapped
+ * to PCI memory by the card.
+ * For example IER register on SBS, Inc. PMC-OctPro is located at
+ * offset 0x10 from the UART base, while UART_IER is defined as 1
+ * in include/linux/serial_reg.h,
+ * see first lines of serial_in() and serial_out() in 8250.c
+*/
+
+static struct pciserial_board pci_boards[] = {
+ [pbn_default] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_1_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_2_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_4_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_5_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 5,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_8_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_1_921600] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_2_921600] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_4_921600] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_2_1130000] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 1130000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_4_1152000] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 1152000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_4_1250000] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 1250000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_2_1843200] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 1843200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_4_1843200] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 1843200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_1_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 4000000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_bt_1_115200] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_2_115200] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_4_115200] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_8_115200] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_bt_1_460800] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_2_460800] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_4_460800] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+
+ [pbn_b0_bt_1_921600] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_2_921600] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_4_921600] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b0_bt_8_921600] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_1_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_2_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_4_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_8_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_16_115200] = {
+ .flags = FL_BASE1,
+ .num_ports = 16,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_1_921600] = {
+ .flags = FL_BASE1,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b1_2_921600] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b1_4_921600] = {
+ .flags = FL_BASE1,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b1_8_921600] = {
+ .flags = FL_BASE1,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b1_2_1250000] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 1250000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_bt_1_115200] = {
+ .flags = FL_BASE1|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_bt_2_115200] = {
+ .flags = FL_BASE1|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b1_bt_4_115200] = {
+ .flags = FL_BASE1|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_bt_2_921600] = {
+ .flags = FL_BASE1|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b1_1_1382400] = {
+ .flags = FL_BASE1,
+ .num_ports = 1,
+ .base_baud = 1382400,
+ .uart_offset = 8,
+ },
+ [pbn_b1_2_1382400] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 1382400,
+ .uart_offset = 8,
+ },
+ [pbn_b1_4_1382400] = {
+ .flags = FL_BASE1,
+ .num_ports = 4,
+ .base_baud = 1382400,
+ .uart_offset = 8,
+ },
+ [pbn_b1_8_1382400] = {
+ .flags = FL_BASE1,
+ .num_ports = 8,
+ .base_baud = 1382400,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_1_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_2_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_4_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_8_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_1_460800] = {
+ .flags = FL_BASE2,
+ .num_ports = 1,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b2_4_460800] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b2_8_460800] = {
+ .flags = FL_BASE2,
+ .num_ports = 8,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+ [pbn_b2_16_460800] = {
+ .flags = FL_BASE2,
+ .num_ports = 16,
+ .base_baud = 460800,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_1_921600] = {
+ .flags = FL_BASE2,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b2_4_921600] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b2_8_921600] = {
+ .flags = FL_BASE2,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_8_1152000] = {
+ .flags = FL_BASE2,
+ .num_ports = 8,
+ .base_baud = 1152000,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_bt_1_115200] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_bt_2_115200] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b2_bt_4_115200] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b2_bt_2_921600] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b2_bt_4_921600] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ [pbn_b3_2_115200] = {
+ .flags = FL_BASE3,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b3_4_115200] = {
+ .flags = FL_BASE3,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_b3_8_115200] = {
+ .flags = FL_BASE3,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+
+ [pbn_b4_bt_2_921600] = {
+ .flags = FL_BASE4,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b4_bt_4_921600] = {
+ .flags = FL_BASE4,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b4_bt_8_921600] = {
+ .flags = FL_BASE4,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
+ /*
+ * Entries following this are board-specific.
+ */
+
+ /*
+ * Panacom - IOMEM
+ */
+ [pbn_panacom] = {
+ .flags = FL_BASE2,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x400,
+ .reg_shift = 7,
+ },
+ [pbn_panacom2] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x400,
+ .reg_shift = 7,
+ },
+ [pbn_panacom4] = {
+ .flags = FL_BASE2|FL_BASE_BARS,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x400,
+ .reg_shift = 7,
+ },
+
+ /* I think this entry is broken - the first_offset looks wrong --rmk */
+ [pbn_plx_romulus] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8 << 2,
+ .reg_shift = 2,
+ .first_offset = 0x03,
+ },
+
+ /*
+ * EndRun Technologies
+ * Uses the size of PCI Base region 0 to
+ * signal now many ports are available
+ * 2 port 952 Uart support
+ */
+ [pbn_endrun_2_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+
+ /*
+ * This board uses the size of PCI Base region 0 to
+ * signal now many ports are available
+ */
+ [pbn_oxsemi] = {
+ .flags = FL_BASE0|FL_REGION_SZ_CAP,
+ .num_ports = 32,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [pbn_oxsemi_1_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_oxsemi_2_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_oxsemi_4_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_oxsemi_8_4000000] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 4000000,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+
+
+ /*
+ * EKF addition for i960 Boards form EKF with serial port.
+ * Max 256 ports.
+ */
+ [pbn_intel_i960] = {
+ .flags = FL_BASE0,
+ .num_ports = 32,
+ .base_baud = 921600,
+ .uart_offset = 8 << 2,
+ .reg_shift = 2,
+ .first_offset = 0x10000,
+ },
+ [pbn_sgi_ioc3] = {
+ .flags = FL_BASE0|FL_NOIRQ,
+ .num_ports = 1,
+ .base_baud = 458333,
+ .uart_offset = 8,
+ .reg_shift = 0,
+ .first_offset = 0x20178,
+ },
+
+ /*
+ * Computone - uses IOMEM.
+ */
+ [pbn_computone_4] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x40,
+ .reg_shift = 2,
+ .first_offset = 0x200,
+ },
+ [pbn_computone_6] = {
+ .flags = FL_BASE0,
+ .num_ports = 6,
+ .base_baud = 921600,
+ .uart_offset = 0x40,
+ .reg_shift = 2,
+ .first_offset = 0x200,
+ },
+ [pbn_computone_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 0x40,
+ .reg_shift = 2,
+ .first_offset = 0x200,
+ },
+ [pbn_sbsxrsio] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 460800,
+ .uart_offset = 256,
+ .reg_shift = 4,
+ },
+ /*
+ * PA Semi PWRficient PA6T-1682M on-chip UART
+ */
+ [pbn_pasemi_1682M] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 8333333,
+ },
+ /*
+ * National Instruments 843x
+ */
+ [pbn_ni8430_16] = {
+ .flags = FL_BASE0,
+ .num_ports = 16,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_4] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_2] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_pxie_16] = {
+ .flags = FL_BASE0,
+ .num_ports = 16,
+ .base_baud = 3125000,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8430_pxie_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3125000,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_4] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_2] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 3686400,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_pxie_16] = {
+ .flags = FL_BASE0,
+ .num_ports = 16,
+ .base_baud = 3125000,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ [pbn_ni8431_pxie_8] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3125000,
+ .uart_offset = 0x10,
+ .first_offset = 0x800,
+ },
+ /*
+ * ADDI-DATA GmbH PCI-Express communication cards <info@addi-data.com>
+ */
+ [pbn_ADDIDATA_PCIe_1_3906250] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 3906250,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_ADDIDATA_PCIe_2_3906250] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 3906250,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_ADDIDATA_PCIe_4_3906250] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 3906250,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_ADDIDATA_PCIe_8_3906250] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 3906250,
+ .uart_offset = 0x200,
+ .first_offset = 0x1000,
+ },
+ [pbn_ce4100_1_115200] = {
+ .flags = FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .reg_shift = 2,
+ },
+ [pbn_omegapci] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 0x200,
+ },
+ [pbn_NETMOS9900_2s_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 115200,
+ },
+ [pbn_brcm_trumanage] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .reg_shift = 2,
+ .base_baud = 115200,
+ },
+ [pbn_fintek_4] = {
+ .num_ports = 4,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ .first_offset = 0x40,
+ },
+ [pbn_fintek_8] = {
+ .num_ports = 8,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ .first_offset = 0x40,
+ },
+ [pbn_fintek_12] = {
+ .num_ports = 12,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ .first_offset = 0x40,
+ },
+ [pbn_fintek_F81504A] = {
+ .num_ports = 4,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ },
+ [pbn_fintek_F81508A] = {
+ .num_ports = 8,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ },
+ [pbn_fintek_F81512A] = {
+ .num_ports = 12,
+ .uart_offset = 8,
+ .base_baud = 115200,
+ },
+ [pbn_wch382_2] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ .first_offset = 0xC0,
+ },
+ [pbn_wch384_4] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ .first_offset = 0xC0,
+ },
+ /*
+ * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART
+ */
+ [pbn_pericom_PI7C9X7951] = {
+ .flags = FL_BASE0,
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_pericom_PI7C9X7952] = {
+ .flags = FL_BASE0,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_pericom_PI7C9X7954] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_pericom_PI7C9X7958] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_1s] = {
+ .num_ports = 1,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_2s] = {
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_4s] = {
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_8s] = {
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_sunix_pci_16s] = {
+ .num_ports = 16,
+ .base_baud = 921600,
+ .uart_offset = 0x8,
+ },
+ [pbn_moxa8250_2p] = {
+ .flags = FL_BASE1,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 0x200,
+ },
+ [pbn_moxa8250_4p] = {
+ .flags = FL_BASE1,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 0x200,
+ },
+ [pbn_moxa8250_8p] = {
+ .flags = FL_BASE1,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 0x200,
+ },
+};
+
+static const struct pci_device_id blacklist[] = {
+ /* softmodems */
+ { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
+ { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
+ { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
+
+ /* multi-io cards handled by parport_serial */
+ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
+ { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
+ { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
+
+ /* Intel platforms with MID UART */
+ { PCI_VDEVICE(INTEL, 0x081b), },
+ { PCI_VDEVICE(INTEL, 0x081c), },
+ { PCI_VDEVICE(INTEL, 0x081d), },
+ { PCI_VDEVICE(INTEL, 0x1191), },
+ { PCI_VDEVICE(INTEL, 0x18d8), },
+ { PCI_VDEVICE(INTEL, 0x19d8), },
+
+ /* Intel platforms with DesignWare UART */
+ { PCI_VDEVICE(INTEL, 0x0936), },
+ { PCI_VDEVICE(INTEL, 0x0f0a), },
+ { PCI_VDEVICE(INTEL, 0x0f0c), },
+ { PCI_VDEVICE(INTEL, 0x228a), },
+ { PCI_VDEVICE(INTEL, 0x228c), },
+ { PCI_VDEVICE(INTEL, 0x9ce3), },
+ { PCI_VDEVICE(INTEL, 0x9ce4), },
+
+ /* Exar devices */
+ { PCI_VDEVICE(EXAR, PCI_ANY_ID), },
+ { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), },
+
+ /* End of the black list */
+ { }
+};
+
+static int serial_pci_is_class_communication(struct pci_dev *dev)
+{
+ /*
+ * If it is not a communications device or the programming
+ * interface is greater than 6, give up.
+ */
+ if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+ ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MULTISERIAL) &&
+ ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+ (dev->class & 0xff) > 6)
+ return -ENODEV;
+
+ return 0;
+}
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs. Returns 0 on success, -ENODEV on failure.
+ */
+static int
+serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
+{
+ int num_iomem, num_port, first_port = -1, i;
+ int rc;
+
+ rc = serial_pci_is_class_communication(dev);
+ if (rc)
+ return rc;
+
+ /*
+ * Should we try to make guesses for multiport serial devices later?
+ */
+ if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_MULTISERIAL)
+ return -ENODEV;
+
+ num_iomem = num_port = 0;
+ for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+ if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
+ num_port++;
+ if (first_port == -1)
+ first_port = i;
+ }
+ if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+ num_iomem++;
+ }
+
+ /*
+ * If there is 1 or 0 iomem regions, and exactly one port,
+ * use it. We guess the number of ports based on the IO
+ * region size.
+ */
+ if (num_iomem <= 1 && num_port == 1) {
+ board->flags = first_port;
+ board->num_ports = pci_resource_len(dev, first_port) / 8;
+ return 0;
+ }
+
+ /*
+ * Now guess if we've got a board which indexes by BARs.
+ * Each IO BAR should be 8 bytes, and they should follow
+ * consecutively.
+ */
+ first_port = -1;
+ num_port = 0;
+ for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
+ if (pci_resource_flags(dev, i) & IORESOURCE_IO &&
+ pci_resource_len(dev, i) == 8 &&
+ (first_port == -1 || (first_port + num_port) == i)) {
+ num_port++;
+ if (first_port == -1)
+ first_port = i;
+ }
+ }
+
+ if (num_port > 1) {
+ board->flags = first_port | FL_BASE_BARS;
+ board->num_ports = num_port;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static inline int
+serial_pci_matches(const struct pciserial_board *board,
+ const struct pciserial_board *guessed)
+{
+ return
+ board->num_ports == guessed->num_ports &&
+ board->base_baud == guessed->base_baud &&
+ board->uart_offset == guessed->uart_offset &&
+ board->reg_shift == guessed->reg_shift &&
+ board->first_offset == guessed->first_offset;
+}
+
+static struct serial_private *
+pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
+{
+ struct uart_8250_port uart;
+ struct serial_private *priv;
+ struct pci_serial_quirk *quirk;
+ int rc, nr_ports, i;
+
+ nr_ports = board->num_ports;
+
+ /*
+ * Find an init and setup quirks.
+ */
+ quirk = find_quirk(dev);
+
+ /*
+ * Run the new-style initialization function.
+ * The initialization function returns:
+ * <0 - error
+ * 0 - use board->num_ports
+ * >0 - number of ports
+ */
+ if (quirk->init) {
+ rc = quirk->init(dev);
+ if (rc < 0) {
+ priv = ERR_PTR(rc);
+ goto err_out;
+ }
+ if (rc)
+ nr_ports = rc;
+ }
+
+ priv = xzalloc(sizeof(struct serial_private) +
+ sizeof(unsigned int) * nr_ports);
+
+ priv->dev = dev;
+ priv->quirk = quirk;
+
+ memset(&uart, 0, sizeof(uart));
+ uart.pdata = xzalloc(sizeof(*uart.pdata));
+ uart.pdata->clock = board->base_baud * 16;
+
+ for (i = 0; i < nr_ports; i++) {
+ struct device *ns16550_dev;
+ struct resource *res;
+
+ rc = quirk->setup(priv, board, &uart, i);
+ if (rc == -ENOSYS) {
+ priv = ERR_PTR(-ENOSYS);
+ goto err_deinit;
+ }
+
+ if (rc)
+ break;
+
+ res = &uart.resource;
+
+ dev_dbg(&dev->dev, "setup PCI %s console @ 0x%pa-0x%pa\n",
+ res->flags & IORESOURCE_MEM ? "MMIO" : "IO port",
+ &res->start, &res->end);
+
+ ns16550_dev = device_alloc("ns16550_serial", DEVICE_ID_DYNAMIC);
+ ns16550_dev->platform_data = uart.pdata;
+ ns16550_dev->parent = &dev->dev;
+ device_add_resource(ns16550_dev, NULL,
+ res->start, res->end - res->start + 1,
+ res->flags);
+
+ rc = platform_device_register(ns16550_dev);
+ if (rc < 0) {
+ dev_err(&dev->dev, "couldn't register PCI %s console @0x%pa: %s\n",
+ res->flags & IORESOURCE_MEM ? "MMIO" : "IO port",
+ &res->start, strerror(-rc));
+
+ break;
+ }
+ }
+ priv->nr = i;
+ priv->board = board;
+ return priv;
+
+err_deinit:
+ if (quirk->exit)
+ quirk->exit(dev);
+err_out:
+ return priv;
+}
+
+/*
+ * Probe one serial board. Unfortunately, there is no rhyme nor reason
+ * to the arrangement of serial ports on a PCI card.
+ */
+static int
+pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+ struct pci_serial_quirk *quirk;
+ struct serial_private *priv;
+ const struct pciserial_board *board;
+ const struct pci_device_id *exclude;
+ struct pciserial_board tmp;
+ int rc;
+
+ quirk = find_quirk(dev);
+ if (quirk->probe) {
+ rc = quirk->probe(dev);
+ if (rc)
+ return rc;
+ }
+
+ if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
+ dev_err(&dev->dev, "invalid driver_data: %ld\n",
+ ent->driver_data);
+ return -EINVAL;
+ }
+
+ board = &pci_boards[ent->driver_data];
+
+ exclude = pci_match_id(blacklist, dev);
+ if (exclude)
+ return -ENODEV;
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ if (ent->driver_data == pbn_default) {
+ /*
+ * Use a copy of the pci_board entry for this;
+ * avoid changing entries in the table.
+ */
+ memcpy(&tmp, board, sizeof(struct pciserial_board));
+ board = &tmp;
+
+ /*
+ * We matched one of our class entries. Try to
+ * determine the parameters of this board.
+ */
+ rc = serial_pci_guess_board(dev, &tmp);
+ if (rc)
+ return rc;
+ } else {
+ /*
+ * We matched an explicit entry. If we are able to
+ * detect this boards settings with our heuristic,
+ * then we no longer need this entry.
+ */
+ memcpy(&tmp, &pci_boards[pbn_default],
+ sizeof(struct pciserial_board));
+ rc = serial_pci_guess_board(dev, &tmp);
+ if (rc == 0 && serial_pci_matches(board, &tmp))
+ moan_device("Redundant entry in serial pci_table.",
+ dev);
+ }
+
+ priv = pciserial_init_ports(dev, board);
+ if (IS_ERR(priv)) {
+ if (PTR_ERR(priv) == -ENOSYS) {
+ dev_err(&dev->dev,
+ "serial port requires not-yet-supported quirky behavior.\n"
+ "Consider porting it over from the Linux 8250_pci driver\n");
+ }
+
+ return PTR_ERR(priv);
+ }
+
+ dev->dev.priv = priv;
+ return 0;
+}
+
+static const struct pci_device_id serial_pci_tbl[] = {
+ /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
+ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
+ PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
+ pbn_b2_8_921600 },
+ /* Advantech also use 0x3618 and 0xf618 */
+ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618,
+ PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618,
+ PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+ pbn_b1_8_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+ pbn_b1_4_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+ pbn_b1_2_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+ pbn_b1_8_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+ pbn_b1_4_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+ pbn_b1_2_1382400 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+ pbn_b1_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+ pbn_b1_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+ pbn_b1_2_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+ pbn_b1_8_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+ pbn_b1_4_921600 },
+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0,
+ pbn_b1_2_1250000 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0,
+ pbn_b0_2_1843200 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_SUBVENDOR_ID_CONNECT_TECH,
+ PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0,
+ pbn_b0_4_1843200 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_VENDOR_ID_AFAVLAB,
+ PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0,
+ pbn_b0_4_1152000 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_1_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_460800 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_115200 },
+
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
+ /*
+ * VScom SPCOM800, from sl@s.pl
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_921600 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_4_921600 },
+ /* Unknown card - subdevice 0x1584 */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_VENDOR_ID_PLX,
+ PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0,
+ pbn_b2_4_115200 },
+ /* Unknown card - subdevice 0x1588 */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_VENDOR_ID_PLX,
+ PCI_SUBDEVICE_ID_UNKNOWN_0x1588, 0, 0,
+ pbn_b2_8_115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_KEYSPAN,
+ PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+ pbn_panacom },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_panacom4 },
+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_panacom2 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ PCI_VENDOR_ID_ESDGMBH,
+ PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
+ pbn_b2_4_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
+ pbn_b2_8_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
+ pbn_b2_16_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
+ pbn_b2_16_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+ PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
+ pbn_b2_4_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+ PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
+ pbn_b2_8_460800 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_EXSYS,
+ PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
+ pbn_b2_4_115200 },
+ /*
+ * Megawolf Romulus PCI Serial Card, from Mike Hudson
+ * (Exoray@isys.ca)
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
+ 0x10b5, 0x106a, 0, 0,
+ pbn_plx_romulus },
+ /*
+ * EndRun Technologies. PCI express device range.
+ * EndRun PTP/1588 has 2 Native UARTs.
+ */
+ { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_endrun_2_4000000 },
+ /*
+ * Quatech cards. These actually have configurable clocks but for
+ * now we just use the default.
+ *
+ * 100 series are RS232, 200 series RS422,
+ */
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_115200 },
+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESCLP100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_8_115200 },
+
+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
+ 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL,
+ 0, 0,
+ pbn_b0_4_1152000 },
+ { PCI_VENDOR_ID_OXSEMI, 0x9505,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+
+ /*
+ * The below card is a little controversial since it is the
+ * subject of a PCI vendor/device ID clash. (See
+ * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html).
+ * For now just used the hex ID 0x950a.
+ */
+ { PCI_VENDOR_ID_OXSEMI, 0x950a,
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00,
+ 0, 0, pbn_b0_2_115200 },
+ { PCI_VENDOR_ID_OXSEMI, 0x950a,
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30,
+ 0, 0, pbn_b0_2_115200 },
+ { PCI_VENDOR_ID_OXSEMI, 0x950a,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_2_1130000 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
+ PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_115200 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_1152000 },
+
+ /*
+ * Oxford Semiconductor Inc. Tornado PCI express device range.
+ */
+ { PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ /*
+ * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
+ */
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */
+ PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
+ pbn_oxsemi_8_4000000 },
+
+ /*
+ * Digi/IBM PCIe 2-port Async EIA-232 Adapter utilizing OxSemi Tornado
+ */
+ { PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM,
+ PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+
+ /*
+ * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
+ * from skokodyn@yahoo.com
+ */
+ { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+ PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0,
+ pbn_sbsxrsio },
+ { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+ PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0,
+ pbn_sbsxrsio },
+ { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+ PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0,
+ pbn_sbsxrsio },
+ { PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+ PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0,
+ pbn_sbsxrsio },
+
+ /*
+ * Digitan DS560-558, from jimd@esoft.com
+ */
+ { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_115200 },
+
+ /*
+ * Titan Electronic cards
+ * The 400L and 800L have a custom setup quirk.
+ */
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b4_bt_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b4_bt_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b4_bt_8_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_410V3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_460800 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_460800 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_460800 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+
+ /*
+ * Computone devices submitted by Doug McNash dmcnash@computone.com
+ */
+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
+ 0, 0, pbn_computone_4 },
+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
+ 0, 0, pbn_computone_8 },
+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
+ 0, 0, pbn_computone_6 },
+
+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi },
+ { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+ PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_921600 },
+
+ /*
+ * Sunix PCI serial boards
+ */
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0001, 0, 0,
+ pbn_sunix_pci_1s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0002, 0, 0,
+ pbn_sunix_pci_2s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0004, 0, 0,
+ pbn_sunix_pci_4s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0084, 0, 0,
+ pbn_sunix_pci_4s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0008, 0, 0,
+ pbn_sunix_pci_8s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0088, 0, 0,
+ pbn_sunix_pci_8s },
+ { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+ PCI_VENDOR_ID_SUNIX, 0x0010, 0, 0,
+ pbn_sunix_pci_16s },
+
+ /*
+ * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org>
+ */
+ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_115200 },
+ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_115200 },
+
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATTRO_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_4_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_2_460800 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_115200 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_1_460800 },
+
+ /*
+ * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408).
+ * Cards are identified by their subsystem vendor IDs, which
+ * (in hex) match the model number.
+ *
+ * Note that JC140x are RS422/485 cards which require ox950
+ * ACR = 0x10, and as such are not currently fully supported.
+ */
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1204, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1402, 0x0002, 0, 0,
+ pbn_b0_2_921600 }, */
+/* { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+ 0x1404, 0x0004, 0, 0,
+ pbn_b0_4_921600 }, */
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+ 0x1204, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3,
+ 0x1208, 0x0004, 0, 0,
+ pbn_b0_4_921600 },
+ /*
+ * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com
+ */
+ { PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_1382400 },
+
+ /*
+ * Dell Remote Access Card III - Tim_T_Murphy@Dell.com
+ */
+ { PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_1_1382400 },
+
+ /*
+ * RAStel 2 port modem, gerg@moreton.com.au
+ */
+ { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
+
+ /*
+ * EKF addition for i960 Boards form EKF with serial port
+ */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP,
+ 0xE4BF, PCI_ANY_ID, 0, 0,
+ pbn_intel_i960 },
+
+ /*
+ * Xircom Cardbus/Ethernet combos
+ */
+ { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_115200 },
+ /*
+ * Xircom RBM56G cardbus modem - Dirk Arnold (temp entry)
+ */
+ { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_115200 },
+
+ /*
+ * Untested PCI modems, sent in from various folks...
+ */
+
+ /*
+ * Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de>
+ */
+ { PCI_VENDOR_ID_ROCKWELL, 0x1004,
+ 0x1048, 0x1500, 0, 0,
+ pbn_b1_1_115200 },
+
+ { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+ 0xFF00, 0, 0, 0,
+ pbn_sgi_ioc3 },
+
+ /*
+ * HP Diva card
+ */
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0,
+ pbn_b1_1_115200 },
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_5_115200 },
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_1_115200 },
+
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b3_2_115200 },
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b3_4_115200 },
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b3_8_115200 },
+ /*
+ * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART
+ */
+ { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7951,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_pericom_PI7C9X7951 },
+ { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7952,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7954,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7958,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_pericom_PI7C9X7958 },
+ /*
+ * ACCES I/O Products quad
+ */
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7951 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7952 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7958 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7958 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7958 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7958 },
+ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pericom_PI7C9X7954 },
+ /*
+ * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
+ */
+ { PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_1_115200 },
+ /*
+ * ITE
+ */
+ { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b1_bt_1_115200 },
+
+ /*
+ * IntaShield IS-200
+ */
+ { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0811 */
+ pbn_b2_2_115200 },
+ /*
+ * IntaShield IS-400
+ */
+ { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */
+ pbn_b2_4_115200 },
+ /*
+ * BrainBoxes UC-260
+ */
+ { PCI_VENDOR_ID_INTASHIELD, 0x0D21,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0E34,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+ pbn_b2_4_115200 },
+ /*
+ * Perle PCI-RAS cards
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4,
+ 0, 0, pbn_b2_4_921600 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
+ 0, 0, pbn_b2_8_921600 },
+
+ /*
+ * Mainpine series cards: Fairly standard layout but fools
+ * parts of the autodetect in some cases and uses otherwise
+ * unmatched communications subclasses in the PCI Express case
+ */
+
+ { /* RockForceDUO */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0200,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceQUATRO */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0300,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceDUO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0400,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceQUATRO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0500,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForce+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0600,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForce+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0700,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceOCTO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0800,
+ 0, 0, pbn_b0_8_115200 },
+ { /* RockForceDUO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0C00,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceQUARTRO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0D00,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceOCTO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x1D00,
+ 0, 0, pbn_b0_8_115200 },
+ { /* RockForceD1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2000,
+ 0, 0, pbn_b0_1_115200 },
+ { /* RockForceF1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2100,
+ 0, 0, pbn_b0_1_115200 },
+ { /* RockForceD2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2200,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceF2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2300,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceD4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2400,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceF4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2500,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceD8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2600,
+ 0, 0, pbn_b0_8_115200 },
+ { /* RockForceF8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2700,
+ 0, 0, pbn_b0_8_115200 },
+ { /* IQ Express D1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3000,
+ 0, 0, pbn_b0_1_115200 },
+ { /* IQ Express F1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3100,
+ 0, 0, pbn_b0_1_115200 },
+ { /* IQ Express D2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3200,
+ 0, 0, pbn_b0_2_115200 },
+ { /* IQ Express F2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3300,
+ 0, 0, pbn_b0_2_115200 },
+ { /* IQ Express D4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3400,
+ 0, 0, pbn_b0_4_115200 },
+ { /* IQ Express F4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3500,
+ 0, 0, pbn_b0_4_115200 },
+ { /* IQ Express D8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3C00,
+ 0, 0, pbn_b0_8_115200 },
+ { /* IQ Express F8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3D00,
+ 0, 0, pbn_b0_8_115200 },
+
+
+ /*
+ * PA Semi PA6T-1682M on-chip UART
+ */
+ { PCI_VENDOR_ID_PASEMI, 0xa004,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_pasemi_1682M },
+
+ /*
+ * National Instruments
+ */
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_16_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_4_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_4_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_16_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_8_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_4_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_4_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b1_bt_2_115200 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_4 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_4 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_8 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_8 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_16 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_16 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_4 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_4 },
+ { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_2328,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_pxie_8 },
+ { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8430_23216,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8430_pxie_16 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4852,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4854,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_4 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8431_4858,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_8 },
+ { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_4858,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_pxie_8 },
+ { PCI_VENDOR_ID_NI, PCIE_DEVICE_ID_NI_PXIE8431_48516,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_pxie_16 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4852,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_2 },
+ { PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8433_4854,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ni8431_4 },
+
+ /*
+ * MOXA
+ */
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_2p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102EL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_2p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_4p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114EL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_4p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132EL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_2p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_4p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP138E_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_moxa8250_8p },
+
+ /*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7500,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7420,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7300,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_AMCC,
+ PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b1_8_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7500_2,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7420_2,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7300_2,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7500_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7420_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7300_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCI7800_3,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_8_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCIe7500,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_ADDIDATA_PCIe_4_3906250 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCIe7420,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_ADDIDATA_PCIe_2_3906250 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCIe7300,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_ADDIDATA_PCIe_1_3906250 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_APCIe7800,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_ADDIDATA_PCIe_8_3906250 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+ PCI_VENDOR_ID_IBM, 0x0299,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ /*
+ * other NetMos 9835 devices are most likely handled by the
+ * parport_serial driver, check drivers/parport/parport_serial.c
+ * before adding them here.
+ */
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ /* the 9901 is a rebranded 9912 */
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9904,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
+ 0xA000, 0x3002,
+ 0, 0, pbn_NETMOS9900_2s_115200 },
+
+ /*
+ * Best Connectivity and Rosewill PCI Multi I/O cards
+ */
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x3002,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x3004,
+ 0, 0, pbn_b0_bt_4_115200 },
+ /* Intel CE4100 */
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_ce4100_1_115200 },
+
+ /*
+ * Cronyx Omega PCI
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_omegapci },
+
+ /*
+ * Broadcom TruManage
+ */
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_brcm_trumanage },
+
+ /*
+ * AgeStar as-prs2-009
+ */
+ { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ /*
+ * WCH CH353 series devices: The 2S1P is handled by parport_serial
+ * so not listed here.
+ */
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_4S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_4_115200 },
+
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH355_4S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_4_115200 },
+
+ { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_wch382_2 },
+
+ { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_wch384_4 },
+
+ /* Fintek PCI serial cards */
+ { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 },
+ { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 },
+ { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 },
+ { PCI_DEVICE(0x1c29, 0x1204), .driver_data = pbn_fintek_F81504A },
+ { PCI_DEVICE(0x1c29, 0x1208), .driver_data = pbn_fintek_F81508A },
+ { PCI_DEVICE(0x1c29, 0x1212), .driver_data = pbn_fintek_F81512A },
+
+ /* MKS Tenta SCOM-080x serial cards */
+ { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 },
+ { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 },
+
+ /* Amazon PCI serial device */
+ { PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 },
+
+ /*
+ * These entries match devices with class COMMUNICATION_SERIAL,
+ * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
+ */
+ { PCI_ANY_ID, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL << 8,
+ 0xffff00, pbn_default },
+ { PCI_ANY_ID, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MODEM << 8,
+ 0xffff00, pbn_default },
+ { PCI_ANY_ID, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
+ 0xffff00, pbn_default },
+ { 0, }
+};
+
+static struct pci_driver serial_pci_driver = {
+ .name = "ns16550_serial_pci",
+ .probe = pciserial_init_one,
+ .id_table = serial_pci_tbl,
+};
+
+static int __init serial_pci_register(void)
+{
+ return pci_driver_register(&serial_pci_driver);
+}
+console_initcall(serial_pci_register);
diff --git a/drivers/serial/serial_omap4_usbboot.c b/drivers/serial/serial_omap4_usbboot.c
index 2ef026c24d..6592be4f35 100644
--- a/drivers/serial/serial_omap4_usbboot.c
+++ b/drivers/serial/serial_omap4_usbboot.c
@@ -1,20 +1,10 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0-or-later
#include <common.h>
#include <init.h>
#include <malloc.h>
#include <errno.h>
-#include <mach/omap4_rom_usb.h>
+#include <mach/omap/omap4_rom_usb.h>
struct serial_omap4_usbboot_priv {
struct console_device cdev;
@@ -56,9 +46,15 @@ static int serial_omap4_usbboot_getc(struct console_device *cdev)
return priv->val;
}
-static int serial_omap4_usbboot_probe(struct device_d *dev)
+static int serial_omap4_usbboot_probe(struct device *dev)
{
struct serial_omap4_usbboot_priv *priv;
+ int ret;
+
+ ret = omap4_usbboot_open();
+ if (ret)
+ return ret;
+
priv = xzalloc(sizeof(*priv));
priv->cdev.dev = dev;
@@ -70,7 +66,7 @@ static int serial_omap4_usbboot_probe(struct device_d *dev)
return console_register(&priv->cdev);
}
-static struct driver_d serial_omap4_usbboot_driver = {
+static struct driver serial_omap4_usbboot_driver = {
.name = "serial_omap4_usbboot",
.probe = serial_omap4_usbboot_probe,
};
diff --git a/drivers/serial/serial_pl010.c b/drivers/serial/serial_pl010.c
index 06f9d2dcdc..56b9e67610 100644
--- a/drivers/serial/serial_pl010.c
+++ b/drivers/serial/serial_pl010.c
@@ -1,27 +1,9 @@
-/*
- * Copyright (C) 2010 Matthias Kaehlcke <matthias@kaehlcke.net>
- *
- * (C) Copyright 2000
- * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
- *
- * (C) Copyright 2004
- * ARM Ltd.
- * Philippe Robin, <philippe.robin@arm.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2000 Rob Taylor <robt@flyingpig.com>, Flying Pig Systems
+// SPDX-FileCopyrightText: 2004 ARM Ltd.
+// SPDX-FileCopyrightText: 2010 Matthias Kaehlcke <matthias@kaehlcke.net>
+
+/* Contributor: Philippe Robin <philippe.robin@arm.com> */
/* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */
@@ -133,7 +115,7 @@ static int pl010_tstc(struct console_device *cdev)
return !(readl(&pl010->flag) & UART_PL010_FR_RXFE);
}
-static int pl010_probe(struct device_d *dev)
+static int pl010_probe(struct device *dev)
{
struct resource *iores;
struct console_device *cdev;
@@ -156,7 +138,7 @@ static int pl010_probe(struct device_d *dev)
return 0;
}
-static struct driver_d pl010_driver = {
+static struct driver pl010_driver = {
.name = "pl010_serial",
.probe = pl010_probe,
};
diff --git a/drivers/serial/serial_pl010.h b/drivers/serial/serial_pl010.h
index ff3d2f9974..ba81a66da0 100644
--- a/drivers/serial/serial_pl010.h
+++ b/drivers/serial/serial_pl010.h
@@ -1,24 +1,8 @@
-/*
- * Copyright (C) 2010 Matthias Kaehlcke <matthias@kaehlcke.net>
- *
- * (C) Copyright 2003, 2004
- * ARM Ltd.
- * Philippe Robin, <philippe.robin@arm.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-FileCopyrightText: 2003, 2004 ARM Ltd. */
+/* SPDX-FileCopyrightText: 2010 Matthias Kaehlcke <matthias@kaehlcke.net> */
+
+/* Contributor: Philippe Robin <philippe.robin@arm.com> */
struct hldc_struct {
uint32_t ctrl;
diff --git a/drivers/serial/serial_pxa.c b/drivers/serial/serial_pxa.c
index a427437b5c..97342f923e 100644
--- a/drivers/serial/serial_pxa.c
+++ b/drivers/serial/serial_pxa.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (c) 2009 Sascha Hauer <s.hauer@pengutronix.de>
* 2010 by Marc Kleine-Budde <kernel@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -19,7 +9,7 @@
#include <init.h>
#include <malloc.h>
-#include <mach/clock.h>
+#include <mach/pxa/clock.h>
#include <asm/io.h>
#define RBR 0x00 /* Receive Buffer Register (read only) */
@@ -159,7 +149,7 @@ static int pxa_serial_setbaudrate(struct console_device *cdev, int baudrate)
return 0;
}
-static int pxa_serial_probe(struct device_d *dev)
+static int pxa_serial_probe(struct device *dev)
{
struct resource *iores;
struct console_device *cdev;
@@ -185,7 +175,7 @@ static int pxa_serial_probe(struct device_d *dev)
return 0;
}
-static struct driver_d pxa_serial_driver = {
+static struct driver pxa_serial_driver = {
.name = "pxa_serial",
.probe = pxa_serial_probe,
};
diff --git a/drivers/serial/serial_s3c.c b/drivers/serial/serial_s3c.c
deleted file mode 100644
index 1945560723..0000000000
--- a/drivers/serial/serial_s3c.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * (c) 2009...2011 Juergen Beisert <j.beisert@pengutronix.de>
- *
- * Based on code from:
- * (c) 2004 Sascha Hauer <sascha@saschahauer.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
- */
-
-#include <common.h>
-#include <driver.h>
-#include <init.h>
-#include <malloc.h>
-#include <io.h>
-#include <mach/s3c-generic.h>
-#include <mach/s3c-iomap.h>
-
-/* Note: Offsets are for little endian access */
-#define ULCON 0x00 /* line control */
-#define UCON 0x04 /* UART control */
-# define UCON_SET_CLK_SRC(x) (((x) & 0x03) << 10)
-# define UCON_GET_CLK_SRC(x) (((x) >> 10) & 0x03)
-#define UFCON 0x08 /* FIFO control */
-#define UMCON 0x0c /* modem control */
-#define UTRSTAT 0x10 /* Rx/Tx status */
-#define UERSTAT 0x14 /* error status */
-#define UFSTAT 0x18 /* FIFO status */
-#define UMSTAT 0x1c /* modem status */
-#define UTXH 0x20 /* transmitt */
-#define URXH 0x24 /* receive */
-#define UBRDIV 0x28 /* baudrate generator */
-#define UBRDIVSLOT 0x2c /* baudrate slot generator */
-#define UINTM 0x38 /* interrupt mask register */
-
-struct s3c_uart {
- void __iomem *regs;
- struct console_device cdev;
-};
-
-#define to_s3c_uart(c) container_of(c, struct s3c_uart, cdev)
-
-/* each architecture has a preferred reference clock for its UARTs */
-static unsigned s3c_select_arch_input_clock(void)
-{
- /* S3C24xx: 0=2=PCLK, 1=UEXTCLK, 3=FCLK/n */
- if (IS_ENABLED(CONFIG_ARCH_S3C24xx))
- return 0; /* use the internal PCLK */
- /* S3C64xx: 0=2=PCLK, 1=UCLK0, 3=UCLK1 */
- if (IS_ENABLED(CONFIG_ARCH_S3C64xx))
- return 3; /* use the internal UCLK1 */
- /* S5PCxx: 0=PCLK, 1=SCLK_UART */
- if (IS_ENABLED(CONFIG_ARCH_S5PCxx))
- return 0; /* use the internal PCLK */
-}
-
-static unsigned s3c_get_arch_uart_input_clock(void __iomem *base)
-{
- unsigned reg = readw(base + UCON);
- return s3c_get_uart_clk(UCON_GET_CLK_SRC(reg));
-}
-
-/*
- * This table takes the fractional value of the baud divisor and gives
- * the recommended setting for the UDIVSLOT register. Refer the datasheet
- * for further details
- */
-static const uint16_t udivslot_table[] __maybe_unused = {
- 0x0000, 0x0080, 0x0808, 0x0888, 0x2222, 0x4924, 0x4A52, 0x54AA,
- 0x5555, 0xD555, 0xD5D5, 0xDDD5, 0xDDDD, 0xDFDD, 0xDFDF, 0xFFDF,
-};
-
-static int s3c_serial_setbaudrate(struct console_device *cdev, int baudrate)
-{
- struct s3c_uart *priv = to_s3c_uart(cdev);
- void __iomem *base = priv->regs;
- unsigned val;
-
- if (IS_ENABLED(CONFIG_DRIVER_SERIAL_S3C_IMPROVED)) {
- val = s3c_get_arch_uart_input_clock(base) / baudrate;
- writew(udivslot_table[val & 15], base + UBRDIVSLOT);
- }
-
- val = s3c_get_arch_uart_input_clock(base) / (16 * baudrate) - 1;
- writew(val, base + UBRDIV);
-
- return 0;
-}
-
-static int s3c_serial_init_port(struct console_device *cdev)
-{
- struct s3c_uart *priv = to_s3c_uart(cdev);
- void __iomem *base = priv->regs;
-
- /* FIFO enable, Tx/Rx FIFO clear */
- writeb(0x07, base + UFCON);
- writeb(0x00, base + UMCON);
-
- /* Normal,No parity,1 stop,8 bit */
- writeb(0x03, base + ULCON);
-
- /*
- * S3C2440 SoC:
- * - no clock divider
- * all SoCs:
- * - enable receive and transmit mode
- */
- writew(0x0005 | UCON_SET_CLK_SRC(s3c_select_arch_input_clock()),
- base + UCON);
-
- if (IS_ENABLED(CONFIG_DRIVER_SERIAL_S3C_IMPROVED))
- /* 'interrupt or polling mode' for both directions */
- writeb(0xf, base + UINTM);
-
- if (IS_ENABLED(CONFIG_DRIVER_SERIAL_S3C_AUTOSYNC))
- writeb(0x10, base + UMCON); /* enable auto flow control */
- else
- writeb(0x01, base + UMCON); /* RTS up */
-
- return 0;
-}
-
-static void s3c_serial_putc(struct console_device *cdev, char c)
-{
- struct s3c_uart *priv = to_s3c_uart(cdev);
- void __iomem *base = priv->regs;
-
- /* Wait for Tx FIFO not full */
- while (!(readb(base + UTRSTAT) & 0x2))
- ;
-
- writeb(c, base + UTXH);
-}
-
-static int s3c_serial_tstc(struct console_device *cdev)
-{
- struct s3c_uart *priv = to_s3c_uart(cdev);
- void __iomem *base = priv->regs;
-
- /* If receive fifo is empty, return false */
- if (readb(base + UTRSTAT) & 0x1)
- return 1;
-
- return 0;
-}
-
-static int s3c_serial_getc(struct console_device *cdev)
-{
- struct s3c_uart *priv = to_s3c_uart(cdev);
- void __iomem *base = priv->regs;
-
- /* wait for a character */
- while (!(readb(base + UTRSTAT) & 0x1))
- ;
-
- return readb(base + URXH);
-}
-
-static void s3c_serial_flush(struct console_device *cdev)
-{
- struct s3c_uart *priv = to_s3c_uart(cdev);
- void __iomem *base = priv->regs;
-
- while (!(readb(base + UTRSTAT) & 0x4))
- ;
-}
-
-static int s3c_serial_probe(struct device_d *dev)
-{
- struct resource *iores;
- struct s3c_uart *priv;
- struct console_device *cdev;
-
- priv = xzalloc(sizeof(struct s3c_uart));
- cdev = &priv->cdev;
- iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- priv->regs = IOMEM(iores->start);
- dev->priv = priv;
- cdev->dev = dev;
- cdev->tstc = s3c_serial_tstc;
- cdev->putc = s3c_serial_putc;
- cdev->getc = s3c_serial_getc;
- cdev->flush = s3c_serial_flush;
- cdev->setbrg = s3c_serial_setbaudrate;
-
- s3c_serial_init_port(cdev);
-
- /* Enable UART */
- console_register(cdev);
-
- return 0;
-}
-
-static struct driver_d s3c_serial_driver = {
- .name = "s3c_serial",
- .probe = s3c_serial_probe,
-};
-console_platform_driver(s3c_serial_driver);
diff --git a/drivers/serial/serial_sbi.c b/drivers/serial/serial_sbi.c
new file mode 100644
index 0000000000..dd3eef41d1
--- /dev/null
+++ b/drivers/serial/serial_sbi.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2021 Marcelo Politzer <marcelo.politzer@cartesi.io>
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <asm/sbi.h>
+
+struct sbi_serial_priv {
+ struct console_device cdev;
+ uint8_t b[2], head, tail;
+};
+
+static int sbi_serial_getc(struct console_device *cdev)
+{
+ struct sbi_serial_priv *priv = cdev->dev->priv;
+ if (priv->head == priv->tail)
+ return -1;
+ return priv->b[priv->head++ & 0x1];
+}
+
+static void sbi_serial_putc(struct console_device *cdev, const char ch)
+{
+ sbi_console_putchar(ch);
+}
+
+static int sbi_serial_tstc(struct console_device *cdev)
+{
+ struct sbi_serial_priv *priv = cdev->dev->priv;
+ int c = sbi_console_getchar();
+
+ if (c != -1)
+ priv->b[priv->tail++ & 0x1] = c;
+ return priv->head != priv->tail;
+}
+
+static int sbi_serial_probe(struct device *dev)
+{
+ struct sbi_serial_priv *priv;
+
+ priv = dev->priv = xzalloc(sizeof(*priv));
+ priv->cdev.dev = dev;
+ priv->cdev.putc = sbi_serial_putc;
+ priv->cdev.getc = sbi_serial_getc;
+ priv->cdev.tstc = sbi_serial_tstc;
+ priv->cdev.flush = 0;
+ priv->cdev.setbrg = 0;
+
+ return console_register(&priv->cdev);
+}
+
+static struct driver serial_sbi_driver = {
+ .name = "riscv-serial-sbi",
+ .probe = sbi_serial_probe,
+};
+postcore_platform_driver(serial_sbi_driver);
diff --git a/drivers/serial/serial_sifive.c b/drivers/serial/serial_sifive.c
new file mode 100644
index 0000000000..f056233b4e
--- /dev/null
+++ b/drivers/serial/serial_sifive.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2018 Anup Patel <anup@brainfault.org>
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <io.h>
+#include <of.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#define UART_TXFIFO_FULL 0x80000000
+#define UART_RXFIFO_EMPTY 0x80000000
+#define UART_RXFIFO_DATA 0x000000ff
+#define UART_TXCTRL_TXEN 0x1
+#define UART_RXCTRL_RXEN 0x1
+
+/* IP register */
+#define UART_IP_RXWM 0x2
+
+struct sifive_serial_regs {
+ u32 txfifo;
+ u32 rxfifo;
+ u32 txctrl;
+ u32 rxctrl;
+ u32 ie;
+ u32 ip;
+ u32 div;
+};
+
+struct sifive_serial_priv {
+ unsigned long freq;
+ struct sifive_serial_regs __iomem *regs;
+ struct console_device cdev;
+};
+
+#define to_priv(cdev) container_of(cdev, struct sifive_serial_priv, cdev)
+
+/**
+ * Find minimum divisor divides in_freq to max_target_hz;
+ * Based on uart driver n SiFive FSBL.
+ *
+ * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
+ * The nearest integer solution requires rounding up as to not exceed
+ * max_target_hz.
+ * div = ceil(f_in / f_baud) - 1
+ * = floor((f_in - 1 + f_baud) / f_baud) - 1
+ * This should not overflow as long as (f_in - 1 + f_baud) does not exceed
+ * 2^32 - 1, which is unlikely since we represent frequencies in kHz.
+ */
+static inline unsigned int uart_min_clk_divisor(unsigned long in_freq,
+ unsigned long max_target_hz)
+{
+ unsigned long quotient =
+ (in_freq + max_target_hz - 1) / (max_target_hz);
+ /* Avoid underflow */
+ if (quotient == 0)
+ return 0;
+ else
+ return quotient - 1;
+}
+
+static void sifive_serial_init(struct sifive_serial_regs __iomem *regs)
+{
+ writel(UART_TXCTRL_TXEN, &regs->txctrl);
+ writel(UART_RXCTRL_RXEN, &regs->rxctrl);
+ writel(0, &regs->ie);
+}
+
+static int sifive_serial_setbrg(struct console_device *cdev, int baudrate)
+{
+ struct sifive_serial_priv *priv = to_priv(cdev);
+
+ writel((uart_min_clk_divisor(priv->freq, baudrate)), &priv->regs->div);
+
+ return 0;
+}
+
+static int sifive_serial_getc(struct console_device *cdev)
+{
+ struct sifive_serial_regs __iomem *regs = to_priv(cdev)->regs;
+ u32 ch;
+
+ do {
+ ch = readl(&regs->rxfifo);
+ } while (ch & UART_RXFIFO_EMPTY);
+
+ return ch & UART_RXFIFO_DATA;
+}
+
+static void sifive_serial_putc(struct console_device *cdev, const char ch)
+{
+ struct sifive_serial_regs __iomem *regs = to_priv(cdev)->regs;
+
+ // TODO: how to check for !empty to utilize fifo?
+ while (readl(&regs->txfifo) & UART_TXFIFO_FULL)
+ ;
+
+ writel(ch, &regs->txfifo);
+}
+
+static int sifive_serial_tstc(struct console_device *cdev)
+{
+ struct sifive_serial_regs __iomem *regs = to_priv(cdev)->regs;
+
+ return readl(&regs->ip) & UART_IP_RXWM;
+}
+
+static void sifive_serial_flush(struct console_device *cdev)
+{
+ struct sifive_serial_regs __iomem *regs = to_priv(cdev)->regs;
+
+ while (readl(&regs->txfifo) & UART_TXFIFO_FULL)
+ ;
+}
+
+static int sifive_serial_probe(struct device *dev)
+{
+ struct sifive_serial_priv *priv;
+ struct resource *iores;
+ struct clk *clk;
+ u32 freq;
+ int ret;
+
+ clk = clk_get(dev, NULL);
+ if (!IS_ERR(clk)) {
+ freq = clk_get_rate(clk);
+ } else {
+ dev_dbg(dev, "failed to get clock. Fallback to device tree.\n");
+
+ ret = of_property_read_u32(dev->of_node, "clock-frequency",
+ &freq);
+ if (ret) {
+ dev_warn(dev, "unknown clock frequency\n");
+ return ret;
+ }
+ }
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ priv = xzalloc(sizeof(*priv));
+
+ priv->freq = freq;
+ priv->regs = IOMEM(iores->start);
+
+ priv->cdev.dev = dev;
+ priv->cdev.putc = sifive_serial_putc;
+ priv->cdev.getc = sifive_serial_getc;
+ priv->cdev.tstc = sifive_serial_tstc;
+ priv->cdev.flush = sifive_serial_flush;
+ priv->cdev.setbrg = sifive_serial_setbrg,
+
+ sifive_serial_init(priv->regs);
+
+ return console_register(&priv->cdev);
+}
+
+static __maybe_unused struct of_device_id sifive_serial_dt_ids[] = {
+ { .compatible = "sifive,uart0" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sifive_serial_dt_ids);
+
+static struct driver serial_sifive_driver = {
+ .name = "serial_sifive",
+ .probe = sifive_serial_probe,
+ .of_compatible = sifive_serial_dt_ids,
+};
+console_platform_driver(serial_sifive_driver);
diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c
index 4bbfb1eef7..3e18a2c152 100644
--- a/drivers/serial/serial_stm32.c
+++ b/drivers/serial/serial_stm32.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2016, STMicroelectronics - All Rights Reserved
* Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
@@ -41,6 +41,8 @@ static int stm32_serial_setbaudrate(struct console_device *cdev, int baudrate)
unsigned long clock_rate;
clock_rate = clk_get_rate(stm32->clk);
+ if (!clock_rate)
+ return -EINVAL;
int_div = DIV_ROUND_CLOSEST(clock_rate, baudrate);
@@ -136,7 +138,7 @@ static void stm32_serial_init(struct console_device *cdev)
writel(cr1, base + CR1_OFFSET(stm32f4));
}
-static int stm32_serial_probe(struct device_d *dev)
+static int stm32_serial_probe(struct device *dev)
{
int ret;
struct console_device *cdev;
@@ -163,7 +165,7 @@ static int stm32_serial_probe(struct device_d *dev)
stm32->stm32f4 = info->stm32f4;
stm32->uart_enable_bit = info->uart_enable_bit;
- stm32->clk = clk_get(dev, NULL);
+ stm32->clk = clk_get_for_console(dev, NULL);
if (IS_ERR(stm32->clk)) {
ret = PTR_ERR(stm32->clk);
dev_err(dev, "Failed to get UART clock %d\n", ret);
@@ -181,11 +183,11 @@ static int stm32_serial_probe(struct device_d *dev)
cdev->putc = stm32_serial_putc;
cdev->getc = stm32_serial_getc;
cdev->flush = stm32_serial_flush;
- cdev->setbrg = stm32_serial_setbaudrate;
+ cdev->setbrg = stm32->clk ? stm32_serial_setbaudrate : NULL;
cdev->linux_console_name = "ttySTM";
- if (dev->device_node) {
- devname = of_alias_get(dev->device_node);
+ if (dev->of_node) {
+ devname = of_alias_get(dev->of_node);
if (devname) {
cdev->devname = xstrdup(devname);
cdev->devid = DEVICE_ID_SINGLE;
@@ -238,8 +240,9 @@ static struct of_device_id stm32_serial_dt_ids[] = {
}, {
}
};
+MODULE_DEVICE_TABLE(of, stm32_serial_dt_ids);
-static struct driver_d stm32_serial_driver = {
+static struct driver stm32_serial_driver = {
.name = "stm32-serial",
.probe = stm32_serial_probe,
.of_compatible = DRV_OF_COMPAT(stm32_serial_dt_ids),
diff --git a/drivers/serial/serial_stm32.h b/drivers/serial/serial_stm32.h
index dd3e930c93..f519f2abac 100644
--- a/drivers/serial/serial_stm32.h
+++ b/drivers/serial/serial_stm32.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2016, STMicroelectronics - All Rights Reserved
* Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
diff --git a/drivers/serial/stm-serial.c b/drivers/serial/stm-serial.c
index ea482415ce..af30bfa71d 100644
--- a/drivers/serial/stm-serial.c
+++ b/drivers/serial/stm-serial.c
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (C) Copyright 2010 Juergen Beisert - Pengutronix
*
* This code was inspired by some patches made for u-boot covered by:
* (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>
* (C) Copyright 2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
/*
@@ -31,7 +20,6 @@
#include <malloc.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <mach/clock.h>
#define UARTDBGDR 0x00
#define UARTDBGFR 0x18
@@ -143,7 +131,7 @@ static int stm_serial_init_port(struct stm_priv *priv)
return 0;
}
-static int stm_serial_probe(struct device_d *dev)
+static int stm_serial_probe(struct device *dev)
{
struct resource *iores;
struct stm_priv *priv;
@@ -159,12 +147,15 @@ static int stm_serial_probe(struct device_d *dev)
cdev->flush = stm_serial_flush;
cdev->setbrg = stm_serial_setbaudrate;
cdev->dev = dev;
+ cdev->linux_console_name = "ttyAMA";
+ cdev->linux_earlycon_name = "pl011";
dev->priv = priv;
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
priv->base = IOMEM(iores->start);
+ cdev->phys_base = priv->base;
priv->clk = clk_get(dev, NULL);
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
@@ -189,8 +180,9 @@ static __maybe_unused struct of_device_id stm_serial_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, stm_serial_dt_ids);
-static struct driver_d stm_serial_driver = {
+static struct driver stm_serial_driver = {
.name = "stm_serial",
.probe = stm_serial_probe,
.of_compatible = DRV_OF_COMPAT(stm_serial_dt_ids),
diff --git a/drivers/serial/virtio_console.c b/drivers/serial/virtio_console.c
new file mode 100644
index 0000000000..a4adb77610
--- /dev/null
+++ b/drivers/serial/virtio_console.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
+ * Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
+ * Copyright (C) 2009, 2010, 2011 Amit Shah <amit.shah@redhat.com>
+ * Copyright (C) 2021 Ahmad Fatoum
+ *
+ * This ridiculously simple implementation does a DMA transfer for
+ * every single character. On the plus side, we neither need to
+ * buffer RX or to wade through TX to turn LFs to CRLFs.
+ */
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <linux/list.h>
+#include <malloc.h>
+#include <console.h>
+#include <xfuncs.h>
+#include <linux/spinlock.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_console.h>
+
+struct virtio_console {
+ struct console_device cdev;
+ struct virtqueue *in_vq, *out_vq;
+ char inbuf[1];
+};
+
+static bool have_one;
+
+/*
+ * The put_chars() callback is pretty straightforward.
+ *
+ * We turn the characters into a scatter-gather list, add it to the
+ * output queue and then kick the Host. Then we sit here waiting for
+ * it to finish: inefficient in theory, but in practice
+ * implementations will do it immediately (lguest's Launcher does).
+ */
+static void put_chars(struct virtio_console *virtcons, const char *buf, int count)
+{
+ struct virtqueue *out_vq = virtcons->out_vq;
+ unsigned int len;
+ struct virtio_sg *sgs[1] = {
+ &(struct virtio_sg) { .addr = (void *)buf, .length = count }
+ };
+
+ /*
+ * add_buf wants a token to identify this buffer: we hand it
+ * any non-NULL pointer, since there's only ever one buffer.
+ */
+ if (virtqueue_add(out_vq, sgs, 1, 0) >= 0) {
+ /* Tell Host to go! */
+ virtqueue_kick(out_vq);
+ /* Chill out until it's done with the buffer. */
+ while (!virtqueue_get_buf(out_vq, &len))
+ cpu_relax();
+ }
+}
+
+static void virtcons_putc(struct console_device *cdev, char c)
+{
+ struct virtio_console *virtcons = container_of(cdev, struct virtio_console, cdev);
+
+ return put_chars(virtcons, &c, 1);
+}
+
+/*
+ * Create a scatter-gather list representing our input buffer and put
+ * it in the queue.
+ */
+static void add_inbuf(struct virtio_console *virtcons)
+{
+ struct virtio_sg *sgs[1] = { &(struct virtio_sg) {
+ .addr = virtcons->inbuf, .length = sizeof(virtcons->inbuf) }
+ };
+
+ /* We should always be able to add one buffer to an empty queue. */
+ if (virtqueue_add(virtcons->in_vq, sgs, 0, 1) < 0)
+ BUG();
+ virtqueue_kick(virtcons->in_vq);
+}
+
+static int virtcons_tstc(struct console_device *cdev)
+{
+ struct virtio_console *virtcons = container_of(cdev, struct virtio_console, cdev);
+
+ return virtqueue_poll(virtcons->in_vq, virtcons->in_vq->last_used_idx);
+}
+
+static int virtcons_getc(struct console_device *cdev)
+{
+ struct virtio_console *virtcons = container_of(cdev, struct virtio_console, cdev);
+ char *in;
+ int ch;
+
+ in = virtqueue_get_buf(virtcons->in_vq, NULL);
+ if (!in)
+ BUG();
+
+ ch = *in;
+
+ add_inbuf(virtcons);
+
+ return ch;
+}
+
+static int virtcons_probe(struct virtio_device *vdev)
+{
+ struct virtqueue *vqs[2];
+ struct virtio_console *virtcons;
+ int err;
+
+ if (have_one) {
+ /* Neither multiport consoles (one virtio_device for multiple consoles)
+ * nor multiple consoles (one virtio_device per each console
+ * is supported. I would've expected:
+ * -chardev socket,path=/tmp/bar,server,nowait,id=bar \
+ * -device virtconsole,chardev=bar,name=console.bar \
+ * -device virtio-serial-device \
+ * -chardev socket,path=/tmp/baz,server,nowait,id=baz \
+ * -device virtconsole,chardev=baz,name=console.baz \
+ * to just work, but it doesn't
+ */
+ dev_warn(&vdev->dev,
+ "Multiple virtio-console devices not supported yet\n");
+ return -EEXIST;
+ }
+
+ /* Find the queues. */
+ err = virtio_find_vqs(vdev, 2, vqs);
+ if (err)
+ return err;
+
+ virtcons = xzalloc(sizeof(*virtcons));
+
+ vdev->priv = virtcons;
+
+ virtcons->in_vq = vqs[0];
+ virtcons->out_vq = vqs[1];
+
+ /* Register the input buffer the first time. */
+ add_inbuf(virtcons);
+
+ virtcons->cdev.dev = &vdev->dev;
+ virtcons->cdev.tstc = virtcons_tstc;
+ virtcons->cdev.getc = virtcons_getc;
+ virtcons->cdev.putc = virtcons_putc;
+
+ have_one = true;
+
+ return console_register(&virtcons->cdev);
+}
+
+static void virtcons_remove(struct virtio_device *vdev)
+{
+ struct virtio_console *virtcons = vdev->priv;
+
+ vdev->config->reset(vdev);
+ console_unregister(&virtcons->cdev);
+ vdev->config->del_vqs(vdev);
+
+ free(virtcons);
+}
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_console = {
+ .driver.name = "virtio_console",
+ .id_table = id_table,
+ .probe = virtcons_probe,
+ .remove = virtcons_remove,
+};
+device_virtio_driver(virtio_console);
+
+MODULE_DESCRIPTION("Virtio console driver");
+MODULE_LICENSE("GPL");