From a2083fd1fa7aa0ef5cd8fd92396da0de2d0654b0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Apr 2026 09:00:53 +0200 Subject: [PATCH 01/49] serial: qcom: Unify user-visible "Qualcomm" name Various names for Qualcomm as a company are used in user-visible config options: QCOM, Qualcomm and Qualcomm Technologies. Switch to unified "Qualcomm" so it will be easier for users to identify the options when for example running menuconfig. Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260427070052.18097-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 9aa61c93d7bc..3e519d001e02 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -913,13 +913,13 @@ config SERIAL_MSM_CONSOLE select SERIAL_EARLYCON config SERIAL_QCOM_GENI - tristate "QCOM on-chip GENI based serial port support" + tristate "Qualcomm on-chip GENI based serial port support" depends on ARCH_QCOM || COMPILE_TEST depends on QCOM_GENI_SE select SERIAL_CORE config SERIAL_QCOM_GENI_CONSOLE - bool "QCOM GENI Serial Console support" + bool "Qualcomm GENI Serial Console support" depends on SERIAL_QCOM_GENI select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON From f785606039fdc8c4de2908dfe9bd672de15a76ce Mon Sep 17 00:00:00 2001 From: Zhiyong Tao Date: Thu, 23 Apr 2026 14:22:45 +0800 Subject: [PATCH 02/49] serial: 8250_mtk: Add ACPI support Add ACPI support to 8250_mtk driver. This makes it possible to use UART on ARM-based desktops with EDK2 UEFI firmware. Signed-off-by: Yenchia Chen Signed-off-by: Zhiyong Tao Link: https://patch.msgid.link/20260423062345.2473300-2-zhiyong.tao@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mtk.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 5875a7b9b4b1..e6a56cf54ae0 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "8250.h" @@ -521,6 +522,7 @@ static int mtk8250_probe(struct platform_device *pdev) struct mtk8250_data *data; struct resource *regs; int irq, err; + struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev); irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -543,12 +545,13 @@ static int mtk8250_probe(struct platform_device *pdev) data->clk_count = 0; - if (pdev->dev.of_node) { + if (is_of_node(fwnode)) { err = mtk8250_probe_of(pdev, &uart.port, data); if (err) return err; - } else + } else if (!fwnode) { return -ENODEV; + } spin_lock_init(&uart.port.lock); uart.port.mapbase = regs->start; @@ -564,14 +567,18 @@ static int mtk8250_probe(struct platform_device *pdev) uart.port.startup = mtk8250_startup; uart.port.set_termios = mtk8250_set_termios; uart.port.uartclk = clk_get_rate(data->uart_clk); + if (!uart.port.uartclk) + uart.port.uartclk = 26 * HZ_PER_MHZ; #ifdef CONFIG_SERIAL_8250_DMA if (data->dma) uart.dma = data->dma; #endif - /* Disable Rate Fix function */ - writel(0x0, uart.port.membase + + if (is_of_node(fwnode)) { + /* Disable Rate Fix function */ + writel(0x0, uart.port.membase + (MTK_UART_RATE_FIX << uart.port.regshift)); + } platform_set_drvdata(pdev, data); @@ -649,11 +656,19 @@ static const struct of_device_id mtk8250_of_match[] = { }; MODULE_DEVICE_TABLE(of, mtk8250_of_match); +static const struct acpi_device_id mtk8250_acpi_match[] = { + { "MTKI0511" }, + { "NVDA0240" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, mtk8250_acpi_match); + static struct platform_driver mtk8250_platform_driver = { .driver = { .name = "mt6577-uart", .pm = &mtk8250_pm_ops, .of_match_table = mtk8250_of_match, + .acpi_match_table = mtk8250_acpi_match, }, .probe = mtk8250_probe, .remove = mtk8250_remove, From 455d4ed5ea5dbdd690f96b5e0582d760cbfc9e8d Mon Sep 17 00:00:00 2001 From: "Nikola Z. Ivanov" Date: Mon, 27 Apr 2026 00:42:50 +0300 Subject: [PATCH 03/49] serial: mxs-auart: replace hardcoded 1 with predefined macro GPIO_LINE_DIRECTION_IN The GPIO_LINE_DIRECTION_* definitions have just recently been exposed to gpio consumers.h by breaking them out in a separate defs.h file. Use this to validate the gpio direction instead of the hard-coded literal. Signed-off-by: Nikola Z. Ivanov Link: https://patch.msgid.link/20260426214250.781151-1-zlatistiv@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mxs-auart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 693b491f1e75..697318dbb146 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1520,7 +1520,7 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) for (i = 0; i < UART_GPIO_MAX; i++) { gpiod = mctrl_gpio_to_gpiod(s->gpios, i); - if (gpiod && (gpiod_get_direction(gpiod) == 1)) + if (gpiod && (gpiod_get_direction(gpiod) == GPIO_LINE_DIRECTION_IN)) s->gpio_irq[i] = gpiod_to_irq(gpiod); else s->gpio_irq[i] = -EINVAL; From a23907d034dbe92915b7af2de18c5d7faac0c0b1 Mon Sep 17 00:00:00 2001 From: Deepti Jaggi Date: Mon, 27 Apr 2026 09:01:14 +0800 Subject: [PATCH 04/49] dt-bindings: serial: Add compatible for Qualcomm SA8797P SoC Document QUP GENI UART controller on Qualcomm Nord SA8797P SoC which is compatible with SA8255P controller. Signed-off-by: Deepti Jaggi Reviewed-by: Krzysztof Kozlowski Signed-off-by: Shawn Guo Link: https://patch.msgid.link/20260427010114.230341-1-shengchao.guo@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/qcom,sa8255p-geni-uart.yaml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/qcom,sa8255p-geni-uart.yaml b/Documentation/devicetree/bindings/serial/qcom,sa8255p-geni-uart.yaml index c8f01923cb25..8496f822dfa5 100644 --- a/Documentation/devicetree/bindings/serial/qcom,sa8255p-geni-uart.yaml +++ b/Documentation/devicetree/bindings/serial/qcom,sa8255p-geni-uart.yaml @@ -14,9 +14,16 @@ allOf: properties: compatible: - enum: - - qcom,sa8255p-geni-uart - - qcom,sa8255p-geni-debug-uart + oneOf: + - enum: + - qcom,sa8255p-geni-uart + - qcom,sa8255p-geni-debug-uart + - items: + - const: qcom,sa8797p-geni-uart + - const: qcom,sa8255p-geni-uart + - items: + - const: qcom,sa8797p-geni-debug-uart + - const: qcom,sa8255p-geni-debug-uart reg: maxItems: 1 From 49fa670efdfdd27e29145cbd2beef065c08717ef Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Thu, 30 Apr 2026 15:58:22 +0200 Subject: [PATCH 05/49] serial: 8250_port: recognize UPIO_AU My MIPS Alchemy systems generate the following warning during probe of the 8250 driver: WARNING: drivers/tty/serial/8250/8250_port.c:462 at set_io_from_upio+0xfc/0x124, CPU#0: swapper/0/1 Unsupported UART type 4 [...] [<80521d40>] set_io_from_upio+0xfc/0x124 [<80521dfc>] serial8250_set_defaults+0x94/0xe0 [<80520fb4>] serial8250_register_8250_port+0x288/0x51c [<805214ec>] serial8250_probe+0x160/0x1e8 [<8053b5f0>] platform_probe+0x64/0x90 The least invasive fix is to recognize UPIO_AU (type 4) in set_io_from_upio() and do nothing, since all parameters have already been set up in 8250_rt288x.c::au_platform_setup(). Run-tested on Alchemy Au1300 platform. Signed-off-by: Manuel Lauss Link: https://patch.msgid.link/20260430135822.905035-1-manuel.lauss@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index af78cc02f38e..02e6cdefdbac 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -458,6 +458,8 @@ static void set_io_from_upio(struct uart_port *p) p->serial_out = io_serial_out; break; #endif + case UPIO_AU: + break; default: WARN(p->iotype != UPIO_PORT || p->iobase, "Unsupported UART type %x\n", p->iotype); From 61848e9799f2543a3ea144e277b17aaec9707566 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Sun, 3 May 2026 20:14:53 -0700 Subject: [PATCH 06/49] tty: synclink_gt: remove broken driver The synclink_gt driver was marked as broken in commit 426263d5fb40 ("tty: synclink_gt: mark as BROKEN") in July 2023 because it had severe structural problems and there had been no evidence of users since 2016. Since then, no meaningful improvements have been made to the driver, and it is unlikely that will ever happen due to the lack of interest. Drop the driver and references to it in comments and documentation. include/uapi/linux/synclink.h is also removed. The only use of this header I have found is the linux-raw-sys Rust crate. It generates bindings for all UAPI headers, but has a hardcoded list of headers and ioctls, including this one, so that does not indicate that anyone is using it. I have sent a pull request to remove the include and ioctl definitions for this header (see the link below). Link: https://github.com/sunfishcode/linux-raw-sys/pull/185 Signed-off-by: Ethan Nelson-Moore Acked-by: Jakub Kicinski Link: https://patch.msgid.link/20260504031519.18877-1-enelsonmoore@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../userspace-api/ioctl/ioctl-number.rst | 1 - arch/powerpc/configs/ppc6xx_defconfig | 1 - drivers/net/ppp/Kconfig | 4 +- drivers/tty/Kconfig | 11 +- drivers/tty/Makefile | 1 - drivers/tty/n_hdlc.c | 7 - drivers/tty/synclink_gt.c | 5038 ----------------- include/linux/synclink.h | 37 - include/uapi/linux/synclink.h | 301 - 9 files changed, 3 insertions(+), 5398 deletions(-) delete mode 100644 drivers/tty/synclink_gt.c delete mode 100644 include/linux/synclink.h delete mode 100644 include/uapi/linux/synclink.h diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 331223761fff..58716f4f4834 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -271,7 +271,6 @@ Code Seq# Include File Comments 'm' 00-09 linux/mmtimer.h conflict! 'm' all linux/mtio.h conflict! 'm' all linux/soundcard.h conflict! -'m' all linux/synclink.h conflict! 'm' 00-19 drivers/message/fusion/mptctl.h conflict! 'm' 00 drivers/scsi/megaraid/megaraid_ioctl.h conflict! 'n' 00-7F linux/ncp_fs.h and fs/ncpfs/ioctl.c diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index ccabc6e17168..4ddd2c01b8b7 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -551,7 +551,6 @@ CONFIG_GAMEPORT_EMU10K1=m CONFIG_GAMEPORT_FM801=m # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_NONSTANDARD=y -CONFIG_SYNCLINK_GT=m CONFIG_NOZOMI=m CONFIG_N_HDLC=m CONFIG_SERIAL_8250=y diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig index 753354b4e36c..5324e2102383 100644 --- a/drivers/net/ppp/Kconfig +++ b/drivers/net/ppp/Kconfig @@ -191,8 +191,8 @@ config PPP_SYNC_TTY tristate "PPP support for sync tty ports" help Say Y (or M) here if you want to be able to use PPP over synchronous - (HDLC) tty devices, such as the SyncLink adapter. These devices - are often used for high-speed leased lines like T1/E1. + (HDLC) tty devices. These devices are often used for high-speed leased + lines like T1/E1. To compile this driver as a module, choose M here. diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 149f3d53b760..df6832a4c237 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -231,21 +231,12 @@ config MOXA_SMARTIO This driver can also be built as a module. The module will be called mxser. If you want to do that, say M here. -config SYNCLINK_GT - tristate "SyncLink GT/AC support" - depends on SERIAL_NONSTANDARD && PCI - depends on BROKEN - help - Support for SyncLink GT and SyncLink AC families of - synchronous and asynchronous serial adapters - manufactured by Microgate Systems, Ltd. (www.microgate.com) - config N_HDLC tristate "HDLC line discipline support" depends on SERIAL_NONSTANDARD help Allows synchronous HDLC communications with tty device drivers that - support synchronous HDLC such as the Microgate SyncLink adapter. + support synchronous HDLC. This driver can be built as a module ( = code which can be inserted in and removed from the running kernel whenever you want). diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 07aca5184a55..8ca1a0a2229f 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_MOXA_INTELLIO) += moxa.o obj-$(CONFIG_MOXA_SMARTIO) += mxser.o obj-$(CONFIG_NOZOMI) += nozomi.o obj-$(CONFIG_NULL_TTY) += ttynull.o -obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 98eefa2cede4..895b850a5950 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -4,8 +4,6 @@ * Written by Paul Fulghum paulkf@microgate.com * for Microgate Corporation * - * Microgate and SyncLink are registered trademarks of Microgate Corporation - * * Adapted from ppp.c, written by Michael Callahan , * Al Longyear , * Paul Mackerras @@ -54,11 +52,6 @@ * this line discipline (or another line discipline that is frame * oriented such as N_PPP). * - * The SyncLink driver (synclink.c) implements both asynchronous - * (using standard line discipline N_TTY) and synchronous HDLC - * (using N_HDLC) communications, with the latter using the above - * conventions. - * * This implementation is very basic and does not maintain * any statistics. The main point is to enforce the raw data * and frame orientation of HDLC communications. diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c deleted file mode 100644 index bf4f50e0ce94..000000000000 --- a/drivers/tty/synclink_gt.c +++ /dev/null @@ -1,5038 +0,0 @@ -// SPDX-License-Identifier: GPL-1.0+ -/* - * Device driver for Microgate SyncLink GT serial adapters. - * - * written by Paul Fulghum for Microgate Corporation - * paulkf@microgate.com - * - * Microgate and SyncLink are trademarks of Microgate Corporation - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * DEBUG OUTPUT DEFINITIONS - * - * uncomment lines below to enable specific types of debug output - * - * DBGINFO information - most verbose output - * DBGERR serious errors - * DBGBH bottom half service routine debugging - * DBGISR interrupt service routine debugging - * DBGDATA output receive and transmit data - * DBGTBUF output transmit DMA buffers and registers - * DBGRBUF output receive DMA buffers and registers - */ - -#define DBGINFO(fmt) if (debug_level >= DEBUG_LEVEL_INFO) printk fmt -#define DBGERR(fmt) if (debug_level >= DEBUG_LEVEL_ERROR) printk fmt -#define DBGBH(fmt) if (debug_level >= DEBUG_LEVEL_BH) printk fmt -#define DBGISR(fmt) if (debug_level >= DEBUG_LEVEL_ISR) printk fmt -#define DBGDATA(info, buf, size, label) if (debug_level >= DEBUG_LEVEL_DATA) trace_block((info), (buf), (size), (label)) -/*#define DBGTBUF(info) dump_tbufs(info)*/ -/*#define DBGRBUF(info) dump_rbufs(info)*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE)) -#define SYNCLINK_GENERIC_HDLC 1 -#else -#define SYNCLINK_GENERIC_HDLC 0 -#endif - -/* - * module identification - */ -static const char driver_name[] = "SyncLink GT"; -static const char tty_dev_prefix[] = "ttySLG"; -MODULE_DESCRIPTION("Device driver for Microgate SyncLink GT serial adapters"); -MODULE_LICENSE("GPL"); -#define MAX_DEVICES 32 - -static const struct pci_device_id pci_table[] = { - { PCI_VDEVICE(MICROGATE, SYNCLINK_GT_DEVICE_ID) }, - { PCI_VDEVICE(MICROGATE, SYNCLINK_GT2_DEVICE_ID) }, - { PCI_VDEVICE(MICROGATE, SYNCLINK_GT4_DEVICE_ID) }, - { PCI_VDEVICE(MICROGATE, SYNCLINK_AC_DEVICE_ID) }, - { 0 }, /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, pci_table); - -static int init_one(struct pci_dev *dev,const struct pci_device_id *ent); -static void remove_one(struct pci_dev *dev); -static struct pci_driver pci_driver = { - .name = "synclink_gt", - .id_table = pci_table, - .probe = init_one, - .remove = remove_one, -}; - -static bool pci_registered; - -/* - * module configuration and status - */ -static struct slgt_info *slgt_device_list; -static int slgt_device_count; - -static int ttymajor; -static int debug_level; -static int maxframe[MAX_DEVICES]; - -module_param(ttymajor, int, 0); -module_param(debug_level, int, 0); -module_param_array(maxframe, int, NULL, 0); - -MODULE_PARM_DESC(ttymajor, "TTY major device number override: 0=auto assigned"); -MODULE_PARM_DESC(debug_level, "Debug syslog output: 0=disabled, 1 to 5=increasing detail"); -MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)"); - -/* - * tty support and callbacks - */ -static struct tty_driver *serial_driver; - -static void wait_until_sent(struct tty_struct *tty, int timeout); -static void flush_buffer(struct tty_struct *tty); -static void tx_release(struct tty_struct *tty); - -/* - * generic HDLC support - */ -#define dev_to_port(D) (dev_to_hdlc(D)->priv) - - -/* - * device specific structures, macros and functions - */ - -#define SLGT_MAX_PORTS 4 -#define SLGT_REG_SIZE 256 - -/* - * conditional wait facility - */ -struct cond_wait { - struct cond_wait *next; - wait_queue_head_t q; - wait_queue_entry_t wait; - unsigned int data; -}; -static void flush_cond_wait(struct cond_wait **head); - -/* - * DMA buffer descriptor and access macros - */ -struct slgt_desc -{ - __le16 count; - __le16 status; - __le32 pbuf; /* physical address of data buffer */ - __le32 next; /* physical address of next descriptor */ - - /* driver book keeping */ - char *buf; /* virtual address of data buffer */ - unsigned int pdesc; /* physical address of this descriptor */ - dma_addr_t buf_dma_addr; - unsigned short buf_count; -}; - -#define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b)) -#define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b)) -#define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b)) -#define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0)) -#define set_desc_status(a, b) (a).status = cpu_to_le16((unsigned short)(b)) -#define desc_count(a) (le16_to_cpu((a).count)) -#define desc_status(a) (le16_to_cpu((a).status)) -#define desc_complete(a) (le16_to_cpu((a).status) & BIT15) -#define desc_eof(a) (le16_to_cpu((a).status) & BIT2) -#define desc_crc_error(a) (le16_to_cpu((a).status) & BIT1) -#define desc_abort(a) (le16_to_cpu((a).status) & BIT0) -#define desc_residue(a) ((le16_to_cpu((a).status) & 0x38) >> 3) - -struct _input_signal_events { - int ri_up; - int ri_down; - int dsr_up; - int dsr_down; - int dcd_up; - int dcd_down; - int cts_up; - int cts_down; -}; - -/* - * device instance data structure - */ -struct slgt_info { - void *if_ptr; /* General purpose pointer (used by SPPP) */ - struct tty_port port; - - struct slgt_info *next_device; /* device list link */ - - char device_name[25]; - struct pci_dev *pdev; - - int port_count; /* count of ports on adapter */ - int adapter_num; /* adapter instance number */ - int port_num; /* port instance number */ - - /* array of pointers to port contexts on this adapter */ - struct slgt_info *port_array[SLGT_MAX_PORTS]; - - int line; /* tty line instance number */ - - struct mgsl_icount icount; - - int timeout; - int x_char; /* xon/xoff character */ - unsigned int read_status_mask; - unsigned int ignore_status_mask; - - wait_queue_head_t status_event_wait_q; - wait_queue_head_t event_wait_q; - struct timer_list tx_timer; - struct timer_list rx_timer; - - unsigned int gpio_present; - struct cond_wait *gpio_wait_q; - - spinlock_t lock; /* spinlock for synchronizing with ISR */ - - struct work_struct task; - u32 pending_bh; - bool bh_requested; - bool bh_running; - - int isr_overflow; - bool irq_requested; /* true if IRQ requested */ - bool irq_occurred; /* for diagnostics use */ - - /* device configuration */ - - unsigned int bus_type; - unsigned int irq_level; - unsigned long irq_flags; - - unsigned char __iomem * reg_addr; /* memory mapped registers address */ - u32 phys_reg_addr; - bool reg_addr_requested; - - MGSL_PARAMS params; /* communications parameters */ - u32 idle_mode; - u32 max_frame_size; /* as set by device config */ - - unsigned int rbuf_fill_level; - unsigned int rx_pio; - unsigned int if_mode; - unsigned int base_clock; - unsigned int xsync; - unsigned int xctrl; - - /* device status */ - - bool rx_enabled; - bool rx_restart; - - bool tx_enabled; - bool tx_active; - - unsigned char signals; /* serial signal states */ - int init_error; /* initialization error */ - - unsigned char *tx_buf; - int tx_count; - - bool drop_rts_on_tx_done; - struct _input_signal_events input_signal_events; - - int dcd_chkcount; /* check counts to prevent */ - int cts_chkcount; /* too many IRQs if a signal */ - int dsr_chkcount; /* is floating */ - int ri_chkcount; - - char *bufs; /* virtual address of DMA buffer lists */ - dma_addr_t bufs_dma_addr; /* physical address of buffer descriptors */ - - unsigned int rbuf_count; - struct slgt_desc *rbufs; - unsigned int rbuf_current; - unsigned int rbuf_index; - unsigned int rbuf_fill_index; - unsigned short rbuf_fill_count; - - unsigned int tbuf_count; - struct slgt_desc *tbufs; - unsigned int tbuf_current; - unsigned int tbuf_start; - - unsigned char *tmp_rbuf; - unsigned int tmp_rbuf_count; - - /* SPPP/Cisco HDLC device parts */ - - int netcount; - spinlock_t netlock; -#if SYNCLINK_GENERIC_HDLC - struct net_device *netdev; -#endif - -}; - -static const MGSL_PARAMS default_params = { - .mode = MGSL_MODE_HDLC, - .loopback = 0, - .flags = HDLC_FLAG_UNDERRUN_ABORT15, - .encoding = HDLC_ENCODING_NRZI_SPACE, - .clock_speed = 0, - .addr_filter = 0xff, - .crc_type = HDLC_CRC_16_CCITT, - .preamble_length = HDLC_PREAMBLE_LENGTH_8BITS, - .preamble = HDLC_PREAMBLE_PATTERN_NONE, - .data_rate = 9600, - .data_bits = 8, - .stop_bits = 1, - .parity = ASYNC_PARITY_NONE -}; - - -#define BH_RECEIVE 1 -#define BH_TRANSMIT 2 -#define BH_STATUS 4 -#define IO_PIN_SHUTDOWN_LIMIT 100 - -#define DMABUFSIZE 256 -#define DESC_LIST_SIZE 4096 - -#define MASK_PARITY BIT1 -#define MASK_FRAMING BIT0 -#define MASK_BREAK BIT14 -#define MASK_OVERRUN BIT4 - -#define GSR 0x00 /* global status */ -#define JCR 0x04 /* JTAG control */ -#define IODR 0x08 /* GPIO direction */ -#define IOER 0x0c /* GPIO interrupt enable */ -#define IOVR 0x10 /* GPIO value */ -#define IOSR 0x14 /* GPIO interrupt status */ -#define TDR 0x80 /* tx data */ -#define RDR 0x80 /* rx data */ -#define TCR 0x82 /* tx control */ -#define TIR 0x84 /* tx idle */ -#define TPR 0x85 /* tx preamble */ -#define RCR 0x86 /* rx control */ -#define VCR 0x88 /* V.24 control */ -#define CCR 0x89 /* clock control */ -#define BDR 0x8a /* baud divisor */ -#define SCR 0x8c /* serial control */ -#define SSR 0x8e /* serial status */ -#define RDCSR 0x90 /* rx DMA control/status */ -#define TDCSR 0x94 /* tx DMA control/status */ -#define RDDAR 0x98 /* rx DMA descriptor address */ -#define TDDAR 0x9c /* tx DMA descriptor address */ -#define XSR 0x40 /* extended sync pattern */ -#define XCR 0x44 /* extended control */ - -#define RXIDLE BIT14 -#define RXBREAK BIT14 -#define IRQ_TXDATA BIT13 -#define IRQ_TXIDLE BIT12 -#define IRQ_TXUNDER BIT11 /* HDLC */ -#define IRQ_RXDATA BIT10 -#define IRQ_RXIDLE BIT9 /* HDLC */ -#define IRQ_RXBREAK BIT9 /* async */ -#define IRQ_RXOVER BIT8 -#define IRQ_DSR BIT7 -#define IRQ_CTS BIT6 -#define IRQ_DCD BIT5 -#define IRQ_RI BIT4 -#define IRQ_ALL 0x3ff0 -#define IRQ_MASTER BIT0 - -#define slgt_irq_on(info, mask) \ - wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) | (mask))) -#define slgt_irq_off(info, mask) \ - wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) & ~(mask))) - -static __u8 rd_reg8(struct slgt_info *info, unsigned int addr); -static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value); -static __u16 rd_reg16(struct slgt_info *info, unsigned int addr); -static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value); -static __u32 rd_reg32(struct slgt_info *info, unsigned int addr); -static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value); - -static void msc_set_vcr(struct slgt_info *info); - -static int startup_hw(struct slgt_info *info); -static int block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info); -static void shutdown_hw(struct slgt_info *info); -static void program_hw(struct slgt_info *info); -static void change_params(struct slgt_info *info); - -static int adapter_test(struct slgt_info *info); - -static void reset_port(struct slgt_info *info); -static void async_mode(struct slgt_info *info); -static void sync_mode(struct slgt_info *info); - -static void rx_stop(struct slgt_info *info); -static void rx_start(struct slgt_info *info); -static void reset_rbufs(struct slgt_info *info); -static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last); -static bool rx_get_frame(struct slgt_info *info); -static bool rx_get_buf(struct slgt_info *info); - -static void tx_start(struct slgt_info *info); -static void tx_stop(struct slgt_info *info); -static void tx_set_idle(struct slgt_info *info); -static unsigned int tbuf_bytes(struct slgt_info *info); -static void reset_tbufs(struct slgt_info *info); -static void tdma_reset(struct slgt_info *info); -static bool tx_load(struct slgt_info *info, const u8 *buf, unsigned int count); - -static void get_gtsignals(struct slgt_info *info); -static void set_gtsignals(struct slgt_info *info); -static void set_rate(struct slgt_info *info, u32 data_rate); - -static void bh_transmit(struct slgt_info *info); -static void isr_txeom(struct slgt_info *info, unsigned short status); - -static void tx_timeout(struct timer_list *t); -static void rx_timeout(struct timer_list *t); - -/* - * ioctl handlers - */ -static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount); -static int get_params(struct slgt_info *info, MGSL_PARAMS __user *params); -static int set_params(struct slgt_info *info, MGSL_PARAMS __user *params); -static int get_txidle(struct slgt_info *info, int __user *idle_mode); -static int set_txidle(struct slgt_info *info, int idle_mode); -static int tx_enable(struct slgt_info *info, int enable); -static int tx_abort(struct slgt_info *info); -static int rx_enable(struct slgt_info *info, int enable); -static int modem_input_wait(struct slgt_info *info,int arg); -static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr); -static int get_interface(struct slgt_info *info, int __user *if_mode); -static int set_interface(struct slgt_info *info, int if_mode); -static int set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); -static int get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); -static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); -static int get_xsync(struct slgt_info *info, int __user *if_mode); -static int set_xsync(struct slgt_info *info, int if_mode); -static int get_xctrl(struct slgt_info *info, int __user *if_mode); -static int set_xctrl(struct slgt_info *info, int if_mode); - -/* - * driver functions - */ -static void release_resources(struct slgt_info *info); - -/* - * DEBUG OUTPUT CODE - */ -#ifndef DBGINFO -#define DBGINFO(fmt) -#endif -#ifndef DBGERR -#define DBGERR(fmt) -#endif -#ifndef DBGBH -#define DBGBH(fmt) -#endif -#ifndef DBGISR -#define DBGISR(fmt) -#endif - -#ifdef DBGDATA -static void trace_block(struct slgt_info *info, const char *data, int count, const char *label) -{ - int i; - int linecount; - printk("%s %s data:\n",info->device_name, label); - while(count) { - linecount = (count > 16) ? 16 : count; - for(i=0; i < linecount; i++) - printk("%02X ",(unsigned char)data[i]); - for(;i<17;i++) - printk(" "); - for(i=0;i=040 && data[i]<=0176) - printk("%c",data[i]); - else - printk("."); - } - printk("\n"); - data += linecount; - count -= linecount; - } -} -#else -#define DBGDATA(info, buf, size, label) -#endif - -#ifdef DBGTBUF -static void dump_tbufs(struct slgt_info *info) -{ - int i; - printk("tbuf_current=%d\n", info->tbuf_current); - for (i=0 ; i < info->tbuf_count ; i++) { - printk("%d: count=%04X status=%04X\n", - i, le16_to_cpu(info->tbufs[i].count), le16_to_cpu(info->tbufs[i].status)); - } -} -#else -#define DBGTBUF(info) -#endif - -#ifdef DBGRBUF -static void dump_rbufs(struct slgt_info *info) -{ - int i; - printk("rbuf_current=%d\n", info->rbuf_current); - for (i=0 ; i < info->rbuf_count ; i++) { - printk("%d: count=%04X status=%04X\n", - i, le16_to_cpu(info->rbufs[i].count), le16_to_cpu(info->rbufs[i].status)); - } -} -#else -#define DBGRBUF(info) -#endif - -static inline int sanity_check(struct slgt_info *info, char *devname, const char *name) -{ -#ifdef SANITY_CHECK - if (!info) { - printk("null struct slgt_info for (%s) in %s\n", devname, name); - return 1; - } -#else - if (!info) - return 1; -#endif - return 0; -} - -/* - * line discipline callback wrappers - * - * The wrappers maintain line discipline references - * while calling into the line discipline. - * - * ldisc_receive_buf - pass receive data to line discipline - */ -static void ldisc_receive_buf(struct tty_struct *tty, - const __u8 *data, char *flags, int count) -{ - struct tty_ldisc *ld; - if (!tty) - return; - ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->ops->receive_buf) - ld->ops->receive_buf(tty, data, flags, count); - tty_ldisc_deref(ld); - } -} - -/* tty callbacks */ - -static int open(struct tty_struct *tty, struct file *filp) -{ - struct slgt_info *info; - int retval, line; - unsigned long flags; - - line = tty->index; - if (line >= slgt_device_count) { - DBGERR(("%s: open with invalid line #%d.\n", driver_name, line)); - return -ENODEV; - } - - info = slgt_device_list; - while(info && info->line != line) - info = info->next_device; - if (sanity_check(info, tty->name, "open")) - return -ENODEV; - if (info->init_error) { - DBGERR(("%s init error=%d\n", info->device_name, info->init_error)); - return -ENODEV; - } - - tty->driver_data = info; - info->port.tty = tty; - - DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count)); - - mutex_lock(&info->port.mutex); - - spin_lock_irqsave(&info->netlock, flags); - if (info->netcount) { - retval = -EBUSY; - spin_unlock_irqrestore(&info->netlock, flags); - mutex_unlock(&info->port.mutex); - goto cleanup; - } - info->port.count++; - spin_unlock_irqrestore(&info->netlock, flags); - - if (info->port.count == 1) { - /* 1st open on this device, init hardware */ - retval = startup_hw(info); - if (retval < 0) { - mutex_unlock(&info->port.mutex); - goto cleanup; - } - } - mutex_unlock(&info->port.mutex); - retval = block_til_ready(tty, filp, info); - if (retval) { - DBGINFO(("%s block_til_ready rc=%d\n", info->device_name, retval)); - goto cleanup; - } - - retval = 0; - -cleanup: - if (retval) { - if (tty->count == 1) - info->port.tty = NULL; /* tty layer will release tty struct */ - if(info->port.count) - info->port.count--; - } - - DBGINFO(("%s open rc=%d\n", info->device_name, retval)); - return retval; -} - -static void close(struct tty_struct *tty, struct file *filp) -{ - struct slgt_info *info = tty->driver_data; - - if (sanity_check(info, tty->name, "close")) - return; - DBGINFO(("%s close entry, count=%d\n", info->device_name, info->port.count)); - - if (tty_port_close_start(&info->port, tty, filp) == 0) - goto cleanup; - - mutex_lock(&info->port.mutex); - if (tty_port_initialized(&info->port)) - wait_until_sent(tty, info->timeout); - flush_buffer(tty); - tty_ldisc_flush(tty); - - shutdown_hw(info); - mutex_unlock(&info->port.mutex); - - tty_port_close_end(&info->port, tty); - info->port.tty = NULL; -cleanup: - DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->port.count)); -} - -static void hangup(struct tty_struct *tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "hangup")) - return; - DBGINFO(("%s hangup\n", info->device_name)); - - flush_buffer(tty); - - mutex_lock(&info->port.mutex); - shutdown_hw(info); - - spin_lock_irqsave(&info->port.lock, flags); - info->port.count = 0; - info->port.tty = NULL; - spin_unlock_irqrestore(&info->port.lock, flags); - tty_port_set_active(&info->port, false); - mutex_unlock(&info->port.mutex); - - wake_up_interruptible(&info->port.open_wait); -} - -static void set_termios(struct tty_struct *tty, - const struct ktermios *old_termios) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - DBGINFO(("%s set_termios\n", tty->driver->name)); - - change_params(info); - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { - info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - spin_lock_irqsave(&info->lock,flags); - set_gtsignals(info); - spin_unlock_irqrestore(&info->lock,flags); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { - info->signals |= SerialSignal_DTR; - if (!C_CRTSCTS(tty) || !tty_throttled(tty)) - info->signals |= SerialSignal_RTS; - spin_lock_irqsave(&info->lock,flags); - set_gtsignals(info); - spin_unlock_irqrestore(&info->lock,flags); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { - tty->hw_stopped = false; - tx_release(tty); - } -} - -static void update_tx_timer(struct slgt_info *info) -{ - /* - * use worst case speed of 1200bps to calculate transmit timeout - * based on data in buffers (tbuf_bytes) and FIFO (128 bytes) - */ - if (info->params.mode == MGSL_MODE_HDLC) { - int timeout = (tbuf_bytes(info) * 7) + 1000; - mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(timeout)); - } -} - -static ssize_t write(struct tty_struct *tty, const u8 *buf, size_t count) -{ - int ret = 0; - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "write")) - return -EIO; - - DBGINFO(("%s write count=%zu\n", info->device_name, count)); - - if (!info->tx_buf || (count > info->max_frame_size)) - return -EIO; - - if (!count || tty->flow.stopped || tty->hw_stopped) - return 0; - - spin_lock_irqsave(&info->lock, flags); - - if (info->tx_count) { - /* send accumulated data from send_char() */ - if (!tx_load(info, info->tx_buf, info->tx_count)) - goto cleanup; - info->tx_count = 0; - } - - if (tx_load(info, buf, count)) - ret = count; - -cleanup: - spin_unlock_irqrestore(&info->lock, flags); - DBGINFO(("%s write rc=%d\n", info->device_name, ret)); - return ret; -} - -static int put_char(struct tty_struct *tty, u8 ch) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - int ret = 0; - - if (sanity_check(info, tty->name, "put_char")) - return 0; - DBGINFO(("%s put_char(%u)\n", info->device_name, ch)); - if (!info->tx_buf) - return 0; - spin_lock_irqsave(&info->lock,flags); - if (info->tx_count < info->max_frame_size) { - info->tx_buf[info->tx_count++] = ch; - ret = 1; - } - spin_unlock_irqrestore(&info->lock,flags); - return ret; -} - -static void send_xchar(struct tty_struct *tty, char ch) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "send_xchar")) - return; - DBGINFO(("%s send_xchar(%d)\n", info->device_name, ch)); - info->x_char = ch; - if (ch) { - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_enabled) - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - } -} - -static void wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct slgt_info *info = tty->driver_data; - unsigned long orig_jiffies, char_time; - - if (!info ) - return; - if (sanity_check(info, tty->name, "wait_until_sent")) - return; - DBGINFO(("%s wait_until_sent entry\n", info->device_name)); - if (!tty_port_initialized(&info->port)) - goto exit; - - orig_jiffies = jiffies; - - /* Set check interval to 1/5 of estimated time to - * send a character, and make it at least 1. The check - * interval should also be less than the timeout. - * Note: use tight timings here to satisfy the NIST-PCTS. - */ - - if (info->params.data_rate) { - char_time = info->timeout/(32 * 5); - if (!char_time) - char_time++; - } else - char_time = 1; - - if (timeout) - char_time = min_t(unsigned long, char_time, timeout); - - while (info->tx_active) { - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } -exit: - DBGINFO(("%s wait_until_sent exit\n", info->device_name)); -} - -static unsigned int write_room(struct tty_struct *tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned int ret; - - if (sanity_check(info, tty->name, "write_room")) - return 0; - ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; - DBGINFO(("%s write_room=%u\n", info->device_name, ret)); - return ret; -} - -static void flush_chars(struct tty_struct *tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "flush_chars")) - return; - DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count)); - - if (info->tx_count <= 0 || tty->flow.stopped || - tty->hw_stopped || !info->tx_buf) - return; - - DBGINFO(("%s flush_chars start transmit\n", info->device_name)); - - spin_lock_irqsave(&info->lock,flags); - if (info->tx_count && tx_load(info, info->tx_buf, info->tx_count)) - info->tx_count = 0; - spin_unlock_irqrestore(&info->lock,flags); -} - -static void flush_buffer(struct tty_struct *tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "flush_buffer")) - return; - DBGINFO(("%s flush_buffer\n", info->device_name)); - - spin_lock_irqsave(&info->lock, flags); - info->tx_count = 0; - spin_unlock_irqrestore(&info->lock, flags); - - tty_wakeup(tty); -} - -/* - * throttle (stop) transmitter - */ -static void tx_hold(struct tty_struct *tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "tx_hold")) - return; - DBGINFO(("%s tx_hold\n", info->device_name)); - spin_lock_irqsave(&info->lock,flags); - if (info->tx_enabled && info->params.mode == MGSL_MODE_ASYNC) - tx_stop(info); - spin_unlock_irqrestore(&info->lock,flags); -} - -/* - * release (start) transmitter - */ -static void tx_release(struct tty_struct *tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "tx_release")) - return; - DBGINFO(("%s tx_release\n", info->device_name)); - spin_lock_irqsave(&info->lock, flags); - if (info->tx_count && tx_load(info, info->tx_buf, info->tx_count)) - info->tx_count = 0; - spin_unlock_irqrestore(&info->lock, flags); -} - -/* - * Service an IOCTL request - * - * Arguments - * - * tty pointer to tty instance data - * cmd IOCTL command code - * arg command argument/context - * - * Return 0 if success, otherwise error code - */ -static int ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct slgt_info *info = tty->driver_data; - void __user *argp = (void __user *)arg; - int ret; - - if (sanity_check(info, tty->name, "ioctl")) - return -ENODEV; - DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); - - if (cmd != TIOCMIWAIT) { - if (tty_io_error(tty)) - return -EIO; - } - - switch (cmd) { - case MGSL_IOCWAITEVENT: - return wait_mgsl_event(info, argp); - case TIOCMIWAIT: - return modem_input_wait(info,(int)arg); - case MGSL_IOCSGPIO: - return set_gpio(info, argp); - case MGSL_IOCGGPIO: - return get_gpio(info, argp); - case MGSL_IOCWAITGPIO: - return wait_gpio(info, argp); - case MGSL_IOCGXSYNC: - return get_xsync(info, argp); - case MGSL_IOCSXSYNC: - return set_xsync(info, (int)arg); - case MGSL_IOCGXCTRL: - return get_xctrl(info, argp); - case MGSL_IOCSXCTRL: - return set_xctrl(info, (int)arg); - } - mutex_lock(&info->port.mutex); - switch (cmd) { - case MGSL_IOCGPARAMS: - ret = get_params(info, argp); - break; - case MGSL_IOCSPARAMS: - ret = set_params(info, argp); - break; - case MGSL_IOCGTXIDLE: - ret = get_txidle(info, argp); - break; - case MGSL_IOCSTXIDLE: - ret = set_txidle(info, (int)arg); - break; - case MGSL_IOCTXENABLE: - ret = tx_enable(info, (int)arg); - break; - case MGSL_IOCRXENABLE: - ret = rx_enable(info, (int)arg); - break; - case MGSL_IOCTXABORT: - ret = tx_abort(info); - break; - case MGSL_IOCGSTATS: - ret = get_stats(info, argp); - break; - case MGSL_IOCGIF: - ret = get_interface(info, argp); - break; - case MGSL_IOCSIF: - ret = set_interface(info,(int)arg); - break; - default: - ret = -ENOIOCTLCMD; - } - mutex_unlock(&info->port.mutex); - return ret; -} - -static int get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) - -{ - struct slgt_info *info = tty->driver_data; - struct mgsl_icount cnow; /* kernel counter temps */ - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - cnow = info->icount; - spin_unlock_irqrestore(&info->lock,flags); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - -/* - * support for 32 bit ioctl calls on 64 bit systems - */ -#ifdef CONFIG_COMPAT -static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params) -{ - struct MGSL_PARAMS32 tmp_params; - - DBGINFO(("%s get_params32\n", info->device_name)); - memset(&tmp_params, 0, sizeof(tmp_params)); - tmp_params.mode = (compat_ulong_t)info->params.mode; - tmp_params.loopback = info->params.loopback; - tmp_params.flags = info->params.flags; - tmp_params.encoding = info->params.encoding; - tmp_params.clock_speed = (compat_ulong_t)info->params.clock_speed; - tmp_params.addr_filter = info->params.addr_filter; - tmp_params.crc_type = info->params.crc_type; - tmp_params.preamble_length = info->params.preamble_length; - tmp_params.preamble = info->params.preamble; - tmp_params.data_rate = (compat_ulong_t)info->params.data_rate; - tmp_params.data_bits = info->params.data_bits; - tmp_params.stop_bits = info->params.stop_bits; - tmp_params.parity = info->params.parity; - if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32))) - return -EFAULT; - return 0; -} - -static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params) -{ - struct MGSL_PARAMS32 tmp_params; - unsigned long flags; - - DBGINFO(("%s set_params32\n", info->device_name)); - if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32))) - return -EFAULT; - - spin_lock_irqsave(&info->lock, flags); - if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) { - info->base_clock = tmp_params.clock_speed; - } else { - info->params.mode = tmp_params.mode; - info->params.loopback = tmp_params.loopback; - info->params.flags = tmp_params.flags; - info->params.encoding = tmp_params.encoding; - info->params.clock_speed = tmp_params.clock_speed; - info->params.addr_filter = tmp_params.addr_filter; - info->params.crc_type = tmp_params.crc_type; - info->params.preamble_length = tmp_params.preamble_length; - info->params.preamble = tmp_params.preamble; - info->params.data_rate = tmp_params.data_rate; - info->params.data_bits = tmp_params.data_bits; - info->params.stop_bits = tmp_params.stop_bits; - info->params.parity = tmp_params.parity; - } - spin_unlock_irqrestore(&info->lock, flags); - - program_hw(info); - - return 0; -} - -static long slgt_compat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct slgt_info *info = tty->driver_data; - int rc; - - if (sanity_check(info, tty->name, "compat_ioctl")) - return -ENODEV; - DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd)); - - switch (cmd) { - case MGSL_IOCSPARAMS32: - rc = set_params32(info, compat_ptr(arg)); - break; - - case MGSL_IOCGPARAMS32: - rc = get_params32(info, compat_ptr(arg)); - break; - - case MGSL_IOCGPARAMS: - case MGSL_IOCSPARAMS: - case MGSL_IOCGTXIDLE: - case MGSL_IOCGSTATS: - case MGSL_IOCWAITEVENT: - case MGSL_IOCGIF: - case MGSL_IOCSGPIO: - case MGSL_IOCGGPIO: - case MGSL_IOCWAITGPIO: - case MGSL_IOCGXSYNC: - case MGSL_IOCGXCTRL: - rc = ioctl(tty, cmd, (unsigned long)compat_ptr(arg)); - break; - default: - rc = ioctl(tty, cmd, arg); - } - DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc)); - return rc; -} -#else -#define slgt_compat_ioctl NULL -#endif /* ifdef CONFIG_COMPAT */ - -/* - * proc fs support - */ -static inline void line_info(struct seq_file *m, struct slgt_info *info) -{ - char stat_buf[30]; - unsigned long flags; - - seq_printf(m, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n", - info->device_name, info->phys_reg_addr, - info->irq_level, info->max_frame_size); - - /* output current serial signal states */ - spin_lock_irqsave(&info->lock,flags); - get_gtsignals(info); - spin_unlock_irqrestore(&info->lock,flags); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (info->signals & SerialSignal_RTS) - strcat(stat_buf, "|RTS"); - if (info->signals & SerialSignal_CTS) - strcat(stat_buf, "|CTS"); - if (info->signals & SerialSignal_DTR) - strcat(stat_buf, "|DTR"); - if (info->signals & SerialSignal_DSR) - strcat(stat_buf, "|DSR"); - if (info->signals & SerialSignal_DCD) - strcat(stat_buf, "|CD"); - if (info->signals & SerialSignal_RI) - strcat(stat_buf, "|RI"); - - if (info->params.mode != MGSL_MODE_ASYNC) { - seq_printf(m, "\tHDLC txok:%d rxok:%d", - info->icount.txok, info->icount.rxok); - if (info->icount.txunder) - seq_printf(m, " txunder:%d", info->icount.txunder); - if (info->icount.txabort) - seq_printf(m, " txabort:%d", info->icount.txabort); - if (info->icount.rxshort) - seq_printf(m, " rxshort:%d", info->icount.rxshort); - if (info->icount.rxlong) - seq_printf(m, " rxlong:%d", info->icount.rxlong); - if (info->icount.rxover) - seq_printf(m, " rxover:%d", info->icount.rxover); - if (info->icount.rxcrc) - seq_printf(m, " rxcrc:%d", info->icount.rxcrc); - } else { - seq_printf(m, "\tASYNC tx:%d rx:%d", - info->icount.tx, info->icount.rx); - if (info->icount.frame) - seq_printf(m, " fe:%d", info->icount.frame); - if (info->icount.parity) - seq_printf(m, " pe:%d", info->icount.parity); - if (info->icount.brk) - seq_printf(m, " brk:%d", info->icount.brk); - if (info->icount.overrun) - seq_printf(m, " oe:%d", info->icount.overrun); - } - - /* Append serial signal status to end */ - seq_printf(m, " %s\n", stat_buf+1); - - seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", - info->tx_active,info->bh_requested,info->bh_running, - info->pending_bh); -} - -/* Called to print information about devices - */ -static int synclink_gt_proc_show(struct seq_file *m, void *v) -{ - struct slgt_info *info; - - seq_puts(m, "synclink_gt driver\n"); - - info = slgt_device_list; - while( info ) { - line_info(m, info); - info = info->next_device; - } - return 0; -} - -/* - * return count of bytes in transmit buffer - */ -static unsigned int chars_in_buffer(struct tty_struct *tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned int count; - if (sanity_check(info, tty->name, "chars_in_buffer")) - return 0; - count = tbuf_bytes(info); - DBGINFO(("%s chars_in_buffer()=%u\n", info->device_name, count)); - return count; -} - -/* - * signal remote device to throttle send data (our receive data) - */ -static void throttle(struct tty_struct * tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "throttle")) - return; - DBGINFO(("%s throttle\n", info->device_name)); - if (I_IXOFF(tty)) - send_xchar(tty, STOP_CHAR(tty)); - if (C_CRTSCTS(tty)) { - spin_lock_irqsave(&info->lock,flags); - info->signals &= ~SerialSignal_RTS; - set_gtsignals(info); - spin_unlock_irqrestore(&info->lock,flags); - } -} - -/* - * signal remote device to stop throttling send data (our receive data) - */ -static void unthrottle(struct tty_struct * tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "unthrottle")) - return; - DBGINFO(("%s unthrottle\n", info->device_name)); - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - send_xchar(tty, START_CHAR(tty)); - } - if (C_CRTSCTS(tty)) { - spin_lock_irqsave(&info->lock,flags); - info->signals |= SerialSignal_RTS; - set_gtsignals(info); - spin_unlock_irqrestore(&info->lock,flags); - } -} - -/* - * set or clear transmit break condition - * break_state -1=set break condition, 0=clear - */ -static int set_break(struct tty_struct *tty, int break_state) -{ - struct slgt_info *info = tty->driver_data; - unsigned short value; - unsigned long flags; - - if (sanity_check(info, tty->name, "set_break")) - return -EINVAL; - DBGINFO(("%s set_break(%d)\n", info->device_name, break_state)); - - spin_lock_irqsave(&info->lock,flags); - value = rd_reg16(info, TCR); - if (break_state == -1) - value |= BIT6; - else - value &= ~BIT6; - wr_reg16(info, TCR, value); - spin_unlock_irqrestore(&info->lock,flags); - return 0; -} - -#if SYNCLINK_GENERIC_HDLC - -/** - * hdlcdev_attach - called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) - * @dev: pointer to network device structure - * @encoding: serial encoding setting - * @parity: FCS setting - * - * Set encoding and frame check sequence (FCS) options. - * - * Return: 0 if success, otherwise error code - */ -static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, - unsigned short parity) -{ - struct slgt_info *info = dev_to_port(dev); - unsigned char new_encoding; - unsigned short new_crctype; - - /* return error if TTY interface open */ - if (info->port.count) - return -EBUSY; - - DBGINFO(("%s hdlcdev_attach\n", info->device_name)); - - switch (encoding) - { - case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; - case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; - case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; - case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; - case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; - default: return -EINVAL; - } - - switch (parity) - { - case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; - case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; - case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; - default: return -EINVAL; - } - - info->params.encoding = new_encoding; - info->params.crc_type = new_crctype; - - /* if network interface up, reprogram hardware */ - if (info->netcount) - program_hw(info); - - return 0; -} - -/** - * hdlcdev_xmit - called by generic HDLC layer to send a frame - * @skb: socket buffer containing HDLC frame - * @dev: pointer to network device structure - */ -static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct slgt_info *info = dev_to_port(dev); - unsigned long flags; - - DBGINFO(("%s hdlc_xmit\n", dev->name)); - - if (!skb->len) - return NETDEV_TX_OK; - - /* stop sending until this frame completes */ - netif_stop_queue(dev); - - /* update network statistics */ - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - /* save start time for transmit timeout detection */ - netif_trans_update(dev); - - spin_lock_irqsave(&info->lock, flags); - tx_load(info, skb->data, skb->len); - spin_unlock_irqrestore(&info->lock, flags); - - /* done with socket buffer, so free it */ - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -/** - * hdlcdev_open - called by network layer when interface enabled - * @dev: pointer to network device structure - * - * Claim resources and initialize hardware. - * - * Return: 0 if success, otherwise error code - */ -static int hdlcdev_open(struct net_device *dev) -{ - struct slgt_info *info = dev_to_port(dev); - int rc; - unsigned long flags; - - DBGINFO(("%s hdlcdev_open\n", dev->name)); - - /* arbitrate between network and tty opens */ - spin_lock_irqsave(&info->netlock, flags); - if (info->port.count != 0 || info->netcount != 0) { - DBGINFO(("%s hdlc_open busy\n", dev->name)); - spin_unlock_irqrestore(&info->netlock, flags); - return -EBUSY; - } - info->netcount=1; - spin_unlock_irqrestore(&info->netlock, flags); - - /* claim resources and init adapter */ - if ((rc = startup_hw(info)) != 0) { - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return rc; - } - - /* generic HDLC layer open processing */ - rc = hdlc_open(dev); - if (rc) { - shutdown_hw(info); - spin_lock_irqsave(&info->netlock, flags); - info->netcount = 0; - spin_unlock_irqrestore(&info->netlock, flags); - return rc; - } - - /* assert RTS and DTR, apply hardware settings */ - info->signals |= SerialSignal_RTS | SerialSignal_DTR; - program_hw(info); - - /* enable network layer transmit */ - netif_trans_update(dev); - netif_start_queue(dev); - - /* inform generic HDLC layer of current DCD status */ - spin_lock_irqsave(&info->lock, flags); - get_gtsignals(info); - spin_unlock_irqrestore(&info->lock, flags); - if (info->signals & SerialSignal_DCD) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - return 0; -} - -/** - * hdlcdev_close - called by network layer when interface is disabled - * @dev: pointer to network device structure - * - * Shutdown hardware and release resources. - * - * Return: 0 if success, otherwise error code - */ -static int hdlcdev_close(struct net_device *dev) -{ - struct slgt_info *info = dev_to_port(dev); - unsigned long flags; - - DBGINFO(("%s hdlcdev_close\n", dev->name)); - - netif_stop_queue(dev); - - /* shutdown adapter and release resources */ - shutdown_hw(info); - - hdlc_close(dev); - - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - - return 0; -} - -/** - * hdlcdev_ioctl - called by network layer to process IOCTL call to network device - * @dev: pointer to network device structure - * @ifr: pointer to network interface request structure - * @cmd: IOCTL command code - * - * Return: 0 if success, otherwise error code - */ -static int hdlcdev_ioctl(struct net_device *dev, struct if_settings *ifs) -{ - const size_t size = sizeof(sync_serial_settings); - sync_serial_settings new_line; - sync_serial_settings __user *line = ifs->ifs_ifsu.sync; - struct slgt_info *info = dev_to_port(dev); - unsigned int flags; - - DBGINFO(("%s hdlcdev_ioctl\n", dev->name)); - - /* return error if TTY interface open */ - if (info->port.count) - return -EBUSY; - - memset(&new_line, 0, sizeof(new_line)); - - switch (ifs->type) { - case IF_GET_IFACE: /* return current sync_serial_settings */ - - ifs->type = IF_IFACE_SYNC_SERIAL; - if (ifs->size < size) { - ifs->size = size; /* data size wanted */ - return -ENOBUFS; - } - - flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | - HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | - HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | - HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); - - switch (flags){ - case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; - case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; - case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; - case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; - default: new_line.clock_type = CLOCK_DEFAULT; - } - - new_line.clock_rate = info->params.clock_speed; - new_line.loopback = info->params.loopback ? 1:0; - - if (copy_to_user(line, &new_line, size)) - return -EFAULT; - return 0; - - case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ - - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - if (copy_from_user(&new_line, line, size)) - return -EFAULT; - - switch (new_line.clock_type) - { - case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; - case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; - case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; - case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; - case CLOCK_DEFAULT: flags = info->params.flags & - (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | - HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | - HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | - HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; - default: return -EINVAL; - } - - if (new_line.loopback != 0 && new_line.loopback != 1) - return -EINVAL; - - info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | - HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | - HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | - HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); - info->params.flags |= flags; - - info->params.loopback = new_line.loopback; - - if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) - info->params.clock_speed = new_line.clock_rate; - else - info->params.clock_speed = 0; - - /* if network interface up, reprogram hardware */ - if (info->netcount) - program_hw(info); - return 0; - - default: - return hdlc_ioctl(dev, ifs); - } -} - -/** - * hdlcdev_tx_timeout - called by network layer when transmit timeout is detected - * @dev: pointer to network device structure - * @txqueue: unused - */ -static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct slgt_info *info = dev_to_port(dev); - unsigned long flags; - - DBGINFO(("%s hdlcdev_tx_timeout\n", dev->name)); - - dev->stats.tx_errors++; - dev->stats.tx_aborted_errors++; - - spin_lock_irqsave(&info->lock,flags); - tx_stop(info); - spin_unlock_irqrestore(&info->lock,flags); - - netif_wake_queue(dev); -} - -/** - * hdlcdev_tx_done - called by device driver when transmit completes - * @info: pointer to device instance information - * - * Reenable network layer transmit if stopped. - */ -static void hdlcdev_tx_done(struct slgt_info *info) -{ - if (netif_queue_stopped(info->netdev)) - netif_wake_queue(info->netdev); -} - -/** - * hdlcdev_rx - called by device driver when frame received - * @info: pointer to device instance information - * @buf: pointer to buffer contianing frame data - * @size: count of data bytes in buf - * - * Pass frame to network layer. - */ -static void hdlcdev_rx(struct slgt_info *info, char *buf, int size) -{ - struct sk_buff *skb = dev_alloc_skb(size); - struct net_device *dev = info->netdev; - - DBGINFO(("%s hdlcdev_rx\n", dev->name)); - - if (skb == NULL) { - DBGERR(("%s: can't alloc skb, drop packet\n", dev->name)); - dev->stats.rx_dropped++; - return; - } - - skb_put_data(skb, buf, size); - - skb->protocol = hdlc_type_trans(skb, dev); - - dev->stats.rx_packets++; - dev->stats.rx_bytes += size; - - netif_rx(skb); -} - -static const struct net_device_ops hdlcdev_ops = { - .ndo_open = hdlcdev_open, - .ndo_stop = hdlcdev_close, - .ndo_start_xmit = hdlc_start_xmit, - .ndo_siocwandev = hdlcdev_ioctl, - .ndo_tx_timeout = hdlcdev_tx_timeout, -}; - -/** - * hdlcdev_init - called by device driver when adding device instance - * @info: pointer to device instance information - * - * Do generic HDLC initialization. - * - * Return: 0 if success, otherwise error code - */ -static int hdlcdev_init(struct slgt_info *info) -{ - int rc; - struct net_device *dev; - hdlc_device *hdlc; - - /* allocate and initialize network and HDLC layer objects */ - - dev = alloc_hdlcdev(info); - if (!dev) { - printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name); - return -ENOMEM; - } - - /* for network layer reporting purposes only */ - dev->mem_start = info->phys_reg_addr; - dev->mem_end = info->phys_reg_addr + SLGT_REG_SIZE - 1; - dev->irq = info->irq_level; - - /* network layer callbacks and settings */ - dev->netdev_ops = &hdlcdev_ops; - dev->watchdog_timeo = 10 * HZ; - dev->tx_queue_len = 50; - - /* generic HDLC layer callbacks and settings */ - hdlc = dev_to_hdlc(dev); - hdlc->attach = hdlcdev_attach; - hdlc->xmit = hdlcdev_xmit; - - /* register objects with HDLC layer */ - rc = register_hdlc_device(dev); - if (rc) { - printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); - free_netdev(dev); - return rc; - } - - info->netdev = dev; - return 0; -} - -/** - * hdlcdev_exit - called by device driver when removing device instance - * @info: pointer to device instance information - * - * Do generic HDLC cleanup. - */ -static void hdlcdev_exit(struct slgt_info *info) -{ - if (!info->netdev) - return; - unregister_hdlc_device(info->netdev); - free_netdev(info->netdev); - info->netdev = NULL; -} - -#endif /* ifdef CONFIG_HDLC */ - -/* - * get async data from rx DMA buffers - */ -static void rx_async(struct slgt_info *info) -{ - struct mgsl_icount *icount = &info->icount; - unsigned int start, end; - unsigned char *p; - unsigned char status; - struct slgt_desc *bufs = info->rbufs; - int i, count; - int chars = 0; - int stat; - unsigned char ch; - - start = end = info->rbuf_current; - - while(desc_complete(bufs[end])) { - count = desc_count(bufs[end]) - info->rbuf_index; - p = bufs[end].buf + info->rbuf_index; - - DBGISR(("%s rx_async count=%d\n", info->device_name, count)); - DBGDATA(info, p, count, "rx"); - - for(i=0 ; i < count; i+=2, p+=2) { - ch = *p; - icount->rx++; - - stat = 0; - - status = *(p + 1) & (BIT1 + BIT0); - if (status) { - if (status & BIT1) - icount->parity++; - else if (status & BIT0) - icount->frame++; - /* discard char if tty control flags say so */ - if (status & info->ignore_status_mask) - continue; - if (status & BIT1) - stat = TTY_PARITY; - else if (status & BIT0) - stat = TTY_FRAME; - } - tty_insert_flip_char(&info->port, ch, stat); - chars++; - } - - if (i < count) { - /* receive buffer not completed */ - info->rbuf_index += i; - mod_timer(&info->rx_timer, jiffies + 1); - break; - } - - info->rbuf_index = 0; - free_rbufs(info, end, end); - - if (++end == info->rbuf_count) - end = 0; - - /* if entire list searched then no frame available */ - if (end == start) - break; - } - - if (chars) - tty_flip_buffer_push(&info->port); -} - -/* - * return next bottom half action to perform - */ -static int bh_action(struct slgt_info *info) -{ - unsigned long flags; - int rc; - - spin_lock_irqsave(&info->lock,flags); - - if (info->pending_bh & BH_RECEIVE) { - info->pending_bh &= ~BH_RECEIVE; - rc = BH_RECEIVE; - } else if (info->pending_bh & BH_TRANSMIT) { - info->pending_bh &= ~BH_TRANSMIT; - rc = BH_TRANSMIT; - } else if (info->pending_bh & BH_STATUS) { - info->pending_bh &= ~BH_STATUS; - rc = BH_STATUS; - } else { - /* Mark BH routine as complete */ - info->bh_running = false; - info->bh_requested = false; - rc = 0; - } - - spin_unlock_irqrestore(&info->lock,flags); - - return rc; -} - -/* - * perform bottom half processing - */ -static void bh_handler(struct work_struct *work) -{ - struct slgt_info *info = container_of(work, struct slgt_info, task); - int action; - - info->bh_running = true; - - while((action = bh_action(info))) { - switch (action) { - case BH_RECEIVE: - DBGBH(("%s bh receive\n", info->device_name)); - switch(info->params.mode) { - case MGSL_MODE_ASYNC: - rx_async(info); - break; - case MGSL_MODE_HDLC: - while(rx_get_frame(info)); - break; - case MGSL_MODE_RAW: - case MGSL_MODE_MONOSYNC: - case MGSL_MODE_BISYNC: - case MGSL_MODE_XSYNC: - while(rx_get_buf(info)); - break; - } - /* restart receiver if rx DMA buffers exhausted */ - if (info->rx_restart) - rx_start(info); - break; - case BH_TRANSMIT: - bh_transmit(info); - break; - case BH_STATUS: - DBGBH(("%s bh status\n", info->device_name)); - info->ri_chkcount = 0; - info->dsr_chkcount = 0; - info->dcd_chkcount = 0; - info->cts_chkcount = 0; - break; - default: - DBGBH(("%s unknown action\n", info->device_name)); - break; - } - } - DBGBH(("%s bh_handler exit\n", info->device_name)); -} - -static void bh_transmit(struct slgt_info *info) -{ - struct tty_struct *tty = info->port.tty; - - DBGBH(("%s bh_transmit\n", info->device_name)); - if (tty) - tty_wakeup(tty); -} - -static void dsr_change(struct slgt_info *info, unsigned short status) -{ - if (status & BIT3) { - info->signals |= SerialSignal_DSR; - info->input_signal_events.dsr_up++; - } else { - info->signals &= ~SerialSignal_DSR; - info->input_signal_events.dsr_down++; - } - DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals)); - if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { - slgt_irq_off(info, IRQ_DSR); - return; - } - info->icount.dsr++; - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - info->pending_bh |= BH_STATUS; -} - -static void cts_change(struct slgt_info *info, unsigned short status) -{ - if (status & BIT2) { - info->signals |= SerialSignal_CTS; - info->input_signal_events.cts_up++; - } else { - info->signals &= ~SerialSignal_CTS; - info->input_signal_events.cts_down++; - } - DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals)); - if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { - slgt_irq_off(info, IRQ_CTS); - return; - } - info->icount.cts++; - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - info->pending_bh |= BH_STATUS; - - if (tty_port_cts_enabled(&info->port)) { - if (info->port.tty) { - if (info->port.tty->hw_stopped) { - if (info->signals & SerialSignal_CTS) { - info->port.tty->hw_stopped = false; - info->pending_bh |= BH_TRANSMIT; - return; - } - } else { - if (!(info->signals & SerialSignal_CTS)) - info->port.tty->hw_stopped = true; - } - } - } -} - -static void dcd_change(struct slgt_info *info, unsigned short status) -{ - if (status & BIT1) { - info->signals |= SerialSignal_DCD; - info->input_signal_events.dcd_up++; - } else { - info->signals &= ~SerialSignal_DCD; - info->input_signal_events.dcd_down++; - } - DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals)); - if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { - slgt_irq_off(info, IRQ_DCD); - return; - } - info->icount.dcd++; -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) { - if (info->signals & SerialSignal_DCD) - netif_carrier_on(info->netdev); - else - netif_carrier_off(info->netdev); - } -#endif - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - info->pending_bh |= BH_STATUS; - - if (tty_port_check_carrier(&info->port)) { - if (info->signals & SerialSignal_DCD) - wake_up_interruptible(&info->port.open_wait); - else { - if (info->port.tty) - tty_hangup(info->port.tty); - } - } -} - -static void ri_change(struct slgt_info *info, unsigned short status) -{ - if (status & BIT0) { - info->signals |= SerialSignal_RI; - info->input_signal_events.ri_up++; - } else { - info->signals &= ~SerialSignal_RI; - info->input_signal_events.ri_down++; - } - DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals)); - if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { - slgt_irq_off(info, IRQ_RI); - return; - } - info->icount.rng++; - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - info->pending_bh |= BH_STATUS; -} - -static void isr_rxdata(struct slgt_info *info) -{ - unsigned int count = info->rbuf_fill_count; - unsigned int i = info->rbuf_fill_index; - unsigned short reg; - - while (rd_reg16(info, SSR) & IRQ_RXDATA) { - reg = rd_reg16(info, RDR); - DBGISR(("isr_rxdata %s RDR=%04X\n", info->device_name, reg)); - if (desc_complete(info->rbufs[i])) { - /* all buffers full */ - rx_stop(info); - info->rx_restart = true; - continue; - } - info->rbufs[i].buf[count++] = (unsigned char)reg; - /* async mode saves status byte to buffer for each data byte */ - if (info->params.mode == MGSL_MODE_ASYNC) - info->rbufs[i].buf[count++] = (unsigned char)(reg >> 8); - if (count == info->rbuf_fill_level || (reg & BIT10)) { - /* buffer full or end of frame */ - set_desc_count(info->rbufs[i], count); - set_desc_status(info->rbufs[i], BIT15 | (reg >> 8)); - info->rbuf_fill_count = count = 0; - if (++i == info->rbuf_count) - i = 0; - info->pending_bh |= BH_RECEIVE; - } - } - - info->rbuf_fill_index = i; - info->rbuf_fill_count = count; -} - -static void isr_serial(struct slgt_info *info) -{ - unsigned short status = rd_reg16(info, SSR); - - DBGISR(("%s isr_serial status=%04X\n", info->device_name, status)); - - wr_reg16(info, SSR, status); /* clear pending */ - - info->irq_occurred = true; - - if (info->params.mode == MGSL_MODE_ASYNC) { - if (status & IRQ_TXIDLE) { - if (info->tx_active) - isr_txeom(info, status); - } - if (info->rx_pio && (status & IRQ_RXDATA)) - isr_rxdata(info); - if ((status & IRQ_RXBREAK) && (status & RXBREAK)) { - info->icount.brk++; - /* process break detection if tty control allows */ - if (info->port.tty) { - if (!(status & info->ignore_status_mask)) { - if (info->read_status_mask & MASK_BREAK) { - tty_insert_flip_char(&info->port, 0, TTY_BREAK); - if (info->port.flags & ASYNC_SAK) - do_SAK(info->port.tty); - } - } - } - } - } else { - if (status & (IRQ_TXIDLE + IRQ_TXUNDER)) - isr_txeom(info, status); - if (info->rx_pio && (status & IRQ_RXDATA)) - isr_rxdata(info); - if (status & IRQ_RXIDLE) { - if (status & RXIDLE) - info->icount.rxidle++; - else - info->icount.exithunt++; - wake_up_interruptible(&info->event_wait_q); - } - - if (status & IRQ_RXOVER) - rx_start(info); - } - - if (status & IRQ_DSR) - dsr_change(info, status); - if (status & IRQ_CTS) - cts_change(info, status); - if (status & IRQ_DCD) - dcd_change(info, status); - if (status & IRQ_RI) - ri_change(info, status); -} - -static void isr_rdma(struct slgt_info *info) -{ - unsigned int status = rd_reg32(info, RDCSR); - - DBGISR(("%s isr_rdma status=%08x\n", info->device_name, status)); - - /* RDCSR (rx DMA control/status) - * - * 31..07 reserved - * 06 save status byte to DMA buffer - * 05 error - * 04 eol (end of list) - * 03 eob (end of buffer) - * 02 IRQ enable - * 01 reset - * 00 enable - */ - wr_reg32(info, RDCSR, status); /* clear pending */ - - if (status & (BIT5 + BIT4)) { - DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name)); - info->rx_restart = true; - } - info->pending_bh |= BH_RECEIVE; -} - -static void isr_tdma(struct slgt_info *info) -{ - unsigned int status = rd_reg32(info, TDCSR); - - DBGISR(("%s isr_tdma status=%08x\n", info->device_name, status)); - - /* TDCSR (tx DMA control/status) - * - * 31..06 reserved - * 05 error - * 04 eol (end of list) - * 03 eob (end of buffer) - * 02 IRQ enable - * 01 reset - * 00 enable - */ - wr_reg32(info, TDCSR, status); /* clear pending */ - - if (status & (BIT5 + BIT4 + BIT3)) { - // another transmit buffer has completed - // run bottom half to get more send data from user - info->pending_bh |= BH_TRANSMIT; - } -} - -/* - * return true if there are unsent tx DMA buffers, otherwise false - * - * if there are unsent buffers then info->tbuf_start - * is set to index of first unsent buffer - */ -static bool unsent_tbufs(struct slgt_info *info) -{ - unsigned int i = info->tbuf_current; - bool rc = false; - - /* - * search backwards from last loaded buffer (precedes tbuf_current) - * for first unsent buffer (desc_count > 0) - */ - - do { - if (i) - i--; - else - i = info->tbuf_count - 1; - if (!desc_count(info->tbufs[i])) - break; - info->tbuf_start = i; - rc = true; - } while (i != info->tbuf_current); - - return rc; -} - -static void isr_txeom(struct slgt_info *info, unsigned short status) -{ - DBGISR(("%s txeom status=%04x\n", info->device_name, status)); - - slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); - tdma_reset(info); - if (status & IRQ_TXUNDER) { - unsigned short val = rd_reg16(info, TCR); - wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ - wr_reg16(info, TCR, val); /* clear reset bit */ - } - - if (info->tx_active) { - if (info->params.mode != MGSL_MODE_ASYNC) { - if (status & IRQ_TXUNDER) - info->icount.txunder++; - else if (status & IRQ_TXIDLE) - info->icount.txok++; - } - - if (unsent_tbufs(info)) { - tx_start(info); - update_tx_timer(info); - return; - } - info->tx_active = false; - - timer_delete(&info->tx_timer); - - if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) { - info->signals &= ~SerialSignal_RTS; - info->drop_rts_on_tx_done = false; - set_gtsignals(info); - } - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_tx_done(info); - else -#endif - { - if (info->port.tty && (info->port.tty->flow.stopped || info->port.tty->hw_stopped)) { - tx_stop(info); - return; - } - info->pending_bh |= BH_TRANSMIT; - } - } -} - -static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int state) -{ - struct cond_wait *w, *prev; - - /* wake processes waiting for specific transitions */ - for (w = info->gpio_wait_q, prev = NULL ; w != NULL ; w = w->next) { - if (w->data & changed) { - w->data = state; - wake_up_interruptible(&w->q); - if (prev != NULL) - prev->next = w->next; - else - info->gpio_wait_q = w->next; - } else - prev = w; - } -} - -/* interrupt service routine - * - * irq interrupt number - * dev_id device ID supplied during interrupt registration - */ -static irqreturn_t slgt_interrupt(int dummy, void *dev_id) -{ - struct slgt_info *info = dev_id; - unsigned int gsr; - unsigned int i; - - DBGISR(("slgt_interrupt irq=%d entry\n", info->irq_level)); - - while((gsr = rd_reg32(info, GSR) & 0xffffff00)) { - DBGISR(("%s gsr=%08x\n", info->device_name, gsr)); - info->irq_occurred = true; - for(i=0; i < info->port_count ; i++) { - if (info->port_array[i] == NULL) - continue; - spin_lock(&info->port_array[i]->lock); - if (gsr & (BIT8 << i)) - isr_serial(info->port_array[i]); - if (gsr & (BIT16 << (i*2))) - isr_rdma(info->port_array[i]); - if (gsr & (BIT17 << (i*2))) - isr_tdma(info->port_array[i]); - spin_unlock(&info->port_array[i]->lock); - } - } - - if (info->gpio_present) { - unsigned int state; - unsigned int changed; - spin_lock(&info->lock); - while ((changed = rd_reg32(info, IOSR)) != 0) { - DBGISR(("%s iosr=%08x\n", info->device_name, changed)); - /* read latched state of GPIO signals */ - state = rd_reg32(info, IOVR); - /* clear pending GPIO interrupt bits */ - wr_reg32(info, IOSR, changed); - for (i=0 ; i < info->port_count ; i++) { - if (info->port_array[i] != NULL) - isr_gpio(info->port_array[i], changed, state); - } - } - spin_unlock(&info->lock); - } - - for(i=0; i < info->port_count ; i++) { - struct slgt_info *port = info->port_array[i]; - if (port == NULL) - continue; - spin_lock(&port->lock); - if ((port->port.count || port->netcount) && - port->pending_bh && !port->bh_running && - !port->bh_requested) { - DBGISR(("%s bh queued\n", port->device_name)); - schedule_work(&port->task); - port->bh_requested = true; - } - spin_unlock(&port->lock); - } - - DBGISR(("slgt_interrupt irq=%d exit\n", info->irq_level)); - return IRQ_HANDLED; -} - -static int startup_hw(struct slgt_info *info) -{ - DBGINFO(("%s startup\n", info->device_name)); - - if (tty_port_initialized(&info->port)) - return 0; - - if (!info->tx_buf) { - info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); - if (!info->tx_buf) { - DBGERR(("%s can't allocate tx buffer\n", info->device_name)); - return -ENOMEM; - } - } - - info->pending_bh = 0; - - memset(&info->icount, 0, sizeof(info->icount)); - - /* program hardware for current parameters */ - change_params(info); - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - tty_port_set_initialized(&info->port, true); - - return 0; -} - -/* - * called by close() and hangup() to shutdown hardware - */ -static void shutdown_hw(struct slgt_info *info) -{ - unsigned long flags; - - if (!tty_port_initialized(&info->port)) - return; - - DBGINFO(("%s shutdown\n", info->device_name)); - - /* clear status wait queue because status changes */ - /* can't happen after shutting down the hardware */ - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - - timer_delete_sync(&info->tx_timer); - timer_delete_sync(&info->rx_timer); - - kfree(info->tx_buf); - info->tx_buf = NULL; - - spin_lock_irqsave(&info->lock,flags); - - tx_stop(info); - rx_stop(info); - - slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); - - if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) { - info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_gtsignals(info); - } - - flush_cond_wait(&info->gpio_wait_q); - - spin_unlock_irqrestore(&info->lock,flags); - - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - tty_port_set_initialized(&info->port, false); -} - -static void program_hw(struct slgt_info *info) -{ - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - - rx_stop(info); - tx_stop(info); - - if (info->params.mode != MGSL_MODE_ASYNC || - info->netcount) - sync_mode(info); - else - async_mode(info); - - set_gtsignals(info); - - info->dcd_chkcount = 0; - info->cts_chkcount = 0; - info->ri_chkcount = 0; - info->dsr_chkcount = 0; - - slgt_irq_on(info, IRQ_DCD | IRQ_CTS | IRQ_DSR | IRQ_RI); - get_gtsignals(info); - - if (info->netcount || - (info->port.tty && info->port.tty->termios.c_cflag & CREAD)) - rx_start(info); - - spin_unlock_irqrestore(&info->lock,flags); -} - -/* - * reconfigure adapter based on new parameters - */ -static void change_params(struct slgt_info *info) -{ - unsigned cflag; - int bits_per_char; - - if (!info->port.tty) - return; - DBGINFO(("%s change_params\n", info->device_name)); - - cflag = info->port.tty->termios.c_cflag; - - /* if B0 rate (hangup) specified then negate RTS and DTR */ - /* otherwise assert RTS and DTR */ - if (cflag & CBAUD) - info->signals |= SerialSignal_RTS | SerialSignal_DTR; - else - info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - - /* byte size and parity */ - - info->params.data_bits = tty_get_char_size(cflag); - info->params.stop_bits = (cflag & CSTOPB) ? 2 : 1; - - if (cflag & PARENB) - info->params.parity = (cflag & PARODD) ? ASYNC_PARITY_ODD : ASYNC_PARITY_EVEN; - else - info->params.parity = ASYNC_PARITY_NONE; - - /* calculate number of jiffies to transmit a full - * FIFO (32 bytes) at specified data rate - */ - bits_per_char = info->params.data_bits + - info->params.stop_bits + 1; - - info->params.data_rate = tty_get_baud_rate(info->port.tty); - - if (info->params.data_rate) { - info->timeout = (32*HZ*bits_per_char) / - info->params.data_rate; - } - info->timeout += HZ/50; /* Add .02 seconds of slop */ - - tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); - tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); - - /* process tty input control flags */ - - info->read_status_mask = IRQ_RXOVER; - if (I_INPCK(info->port.tty)) - info->read_status_mask |= MASK_PARITY | MASK_FRAMING; - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) - info->read_status_mask |= MASK_BREAK; - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING; - if (I_IGNBRK(info->port.tty)) { - info->ignore_status_mask |= MASK_BREAK; - /* If ignoring parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= MASK_OVERRUN; - } - - program_hw(info); -} - -static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount) -{ - DBGINFO(("%s get_stats\n", info->device_name)); - if (!user_icount) { - memset(&info->icount, 0, sizeof(info->icount)); - } else { - if (copy_to_user(user_icount, &info->icount, sizeof(struct mgsl_icount))) - return -EFAULT; - } - return 0; -} - -static int get_params(struct slgt_info *info, MGSL_PARAMS __user *user_params) -{ - DBGINFO(("%s get_params\n", info->device_name)); - if (copy_to_user(user_params, &info->params, sizeof(MGSL_PARAMS))) - return -EFAULT; - return 0; -} - -static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params) -{ - unsigned long flags; - MGSL_PARAMS tmp_params; - - DBGINFO(("%s set_params\n", info->device_name)); - if (copy_from_user(&tmp_params, new_params, sizeof(MGSL_PARAMS))) - return -EFAULT; - - spin_lock_irqsave(&info->lock, flags); - if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) - info->base_clock = tmp_params.clock_speed; - else - memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS)); - spin_unlock_irqrestore(&info->lock, flags); - - program_hw(info); - - return 0; -} - -static int get_txidle(struct slgt_info *info, int __user *idle_mode) -{ - DBGINFO(("%s get_txidle=%d\n", info->device_name, info->idle_mode)); - if (put_user(info->idle_mode, idle_mode)) - return -EFAULT; - return 0; -} - -static int set_txidle(struct slgt_info *info, int idle_mode) -{ - unsigned long flags; - DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode)); - spin_lock_irqsave(&info->lock,flags); - info->idle_mode = idle_mode; - if (info->params.mode != MGSL_MODE_ASYNC) - tx_set_idle(info); - spin_unlock_irqrestore(&info->lock,flags); - return 0; -} - -static int tx_enable(struct slgt_info *info, int enable) -{ - unsigned long flags; - DBGINFO(("%s tx_enable(%d)\n", info->device_name, enable)); - spin_lock_irqsave(&info->lock,flags); - if (enable) { - if (!info->tx_enabled) - tx_start(info); - } else { - if (info->tx_enabled) - tx_stop(info); - } - spin_unlock_irqrestore(&info->lock,flags); - return 0; -} - -/* - * abort transmit HDLC frame - */ -static int tx_abort(struct slgt_info *info) -{ - unsigned long flags; - DBGINFO(("%s tx_abort\n", info->device_name)); - spin_lock_irqsave(&info->lock,flags); - tdma_reset(info); - spin_unlock_irqrestore(&info->lock,flags); - return 0; -} - -static int rx_enable(struct slgt_info *info, int enable) -{ - unsigned long flags; - unsigned int rbuf_fill_level; - DBGINFO(("%s rx_enable(%08x)\n", info->device_name, enable)); - spin_lock_irqsave(&info->lock,flags); - /* - * enable[31..16] = receive DMA buffer fill level - * 0 = noop (leave fill level unchanged) - * fill level must be multiple of 4 and <= buffer size - */ - rbuf_fill_level = ((unsigned int)enable) >> 16; - if (rbuf_fill_level) { - if ((rbuf_fill_level > DMABUFSIZE) || (rbuf_fill_level % 4)) { - spin_unlock_irqrestore(&info->lock, flags); - return -EINVAL; - } - info->rbuf_fill_level = rbuf_fill_level; - if (rbuf_fill_level < 128) - info->rx_pio = 1; /* PIO mode */ - else - info->rx_pio = 0; /* DMA mode */ - rx_stop(info); /* restart receiver to use new fill level */ - } - - /* - * enable[1..0] = receiver enable command - * 0 = disable - * 1 = enable - * 2 = enable or force hunt mode if already enabled - */ - enable &= 3; - if (enable) { - if (!info->rx_enabled) - rx_start(info); - else if (enable == 2) { - /* force hunt mode (write 1 to RCR[3]) */ - wr_reg16(info, RCR, rd_reg16(info, RCR) | BIT3); - } - } else { - if (info->rx_enabled) - rx_stop(info); - } - spin_unlock_irqrestore(&info->lock,flags); - return 0; -} - -/* - * wait for specified event to occur - */ -static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr) -{ - unsigned long flags; - int s; - int rc=0; - struct mgsl_icount cprev, cnow; - int events; - int mask; - struct _input_signal_events oldsigs, newsigs; - DECLARE_WAITQUEUE(wait, current); - - if (get_user(mask, mask_ptr)) - return -EFAULT; - - DBGINFO(("%s wait_mgsl_event(%d)\n", info->device_name, mask)); - - spin_lock_irqsave(&info->lock,flags); - - /* return immediately if state matches requested events */ - get_gtsignals(info); - s = info->signals; - - events = mask & - ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + - ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + - ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + - ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); - if (events) { - spin_unlock_irqrestore(&info->lock,flags); - goto exit; - } - - /* save current irq counts */ - cprev = info->icount; - oldsigs = info->input_signal_events; - - /* enable hunt and idle irqs if needed */ - if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) { - unsigned short val = rd_reg16(info, SCR); - if (!(val & IRQ_RXIDLE)) - wr_reg16(info, SCR, (unsigned short)(val | IRQ_RXIDLE)); - } - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&info->event_wait_q, &wait); - - spin_unlock_irqrestore(&info->lock,flags); - - for(;;) { - schedule(); - if (signal_pending(current)) { - rc = -ERESTARTSYS; - break; - } - - /* get current irq counts */ - spin_lock_irqsave(&info->lock,flags); - cnow = info->icount; - newsigs = info->input_signal_events; - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&info->lock,flags); - - /* if no change, wait aborted for some reason */ - if (newsigs.dsr_up == oldsigs.dsr_up && - newsigs.dsr_down == oldsigs.dsr_down && - newsigs.dcd_up == oldsigs.dcd_up && - newsigs.dcd_down == oldsigs.dcd_down && - newsigs.cts_up == oldsigs.cts_up && - newsigs.cts_down == oldsigs.cts_down && - newsigs.ri_up == oldsigs.ri_up && - newsigs.ri_down == oldsigs.ri_down && - cnow.exithunt == cprev.exithunt && - cnow.rxidle == cprev.rxidle) { - rc = -EIO; - break; - } - - events = mask & - ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + - (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + - (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + - (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + - (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + - (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + - (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + - (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + - (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + - (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); - if (events) - break; - - cprev = cnow; - oldsigs = newsigs; - } - - remove_wait_queue(&info->event_wait_q, &wait); - set_current_state(TASK_RUNNING); - - - if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { - spin_lock_irqsave(&info->lock,flags); - if (!waitqueue_active(&info->event_wait_q)) { - /* disable enable exit hunt mode/idle rcvd IRQs */ - wr_reg16(info, SCR, - (unsigned short)(rd_reg16(info, SCR) & ~IRQ_RXIDLE)); - } - spin_unlock_irqrestore(&info->lock,flags); - } -exit: - if (rc == 0) - rc = put_user(events, mask_ptr); - return rc; -} - -static int get_interface(struct slgt_info *info, int __user *if_mode) -{ - DBGINFO(("%s get_interface=%x\n", info->device_name, info->if_mode)); - if (put_user(info->if_mode, if_mode)) - return -EFAULT; - return 0; -} - -static int set_interface(struct slgt_info *info, int if_mode) -{ - unsigned long flags; - unsigned short val; - - DBGINFO(("%s set_interface=%x)\n", info->device_name, if_mode)); - spin_lock_irqsave(&info->lock,flags); - info->if_mode = if_mode; - - msc_set_vcr(info); - - /* TCR (tx control) 07 1=RTS driver control */ - val = rd_reg16(info, TCR); - if (info->if_mode & MGSL_INTERFACE_RTS_EN) - val |= BIT7; - else - val &= ~BIT7; - wr_reg16(info, TCR, val); - - spin_unlock_irqrestore(&info->lock,flags); - return 0; -} - -static int get_xsync(struct slgt_info *info, int __user *xsync) -{ - DBGINFO(("%s get_xsync=%x\n", info->device_name, info->xsync)); - if (put_user(info->xsync, xsync)) - return -EFAULT; - return 0; -} - -/* - * set extended sync pattern (1 to 4 bytes) for extended sync mode - * - * sync pattern is contained in least significant bytes of value - * most significant byte of sync pattern is oldest (1st sent/detected) - */ -static int set_xsync(struct slgt_info *info, int xsync) -{ - unsigned long flags; - - DBGINFO(("%s set_xsync=%x)\n", info->device_name, xsync)); - spin_lock_irqsave(&info->lock, flags); - info->xsync = xsync; - wr_reg32(info, XSR, xsync); - spin_unlock_irqrestore(&info->lock, flags); - return 0; -} - -static int get_xctrl(struct slgt_info *info, int __user *xctrl) -{ - DBGINFO(("%s get_xctrl=%x\n", info->device_name, info->xctrl)); - if (put_user(info->xctrl, xctrl)) - return -EFAULT; - return 0; -} - -/* - * set extended control options - * - * xctrl[31:19] reserved, must be zero - * xctrl[18:17] extended sync pattern length in bytes - * 00 = 1 byte in xsr[7:0] - * 01 = 2 bytes in xsr[15:0] - * 10 = 3 bytes in xsr[23:0] - * 11 = 4 bytes in xsr[31:0] - * xctrl[16] 1 = enable terminal count, 0=disabled - * xctrl[15:0] receive terminal count for fixed length packets - * value is count minus one (0 = 1 byte packet) - * when terminal count is reached, receiver - * automatically returns to hunt mode and receive - * FIFO contents are flushed to DMA buffers with - * end of frame (EOF) status - */ -static int set_xctrl(struct slgt_info *info, int xctrl) -{ - unsigned long flags; - - DBGINFO(("%s set_xctrl=%x)\n", info->device_name, xctrl)); - spin_lock_irqsave(&info->lock, flags); - info->xctrl = xctrl; - wr_reg32(info, XCR, xctrl); - spin_unlock_irqrestore(&info->lock, flags); - return 0; -} - -/* - * set general purpose IO pin state and direction - * - * user_gpio fields: - * state each bit indicates a pin state - * smask set bit indicates pin state to set - * dir each bit indicates a pin direction (0=input, 1=output) - * dmask set bit indicates pin direction to set - */ -static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) -{ - unsigned long flags; - struct gpio_desc gpio; - __u32 data; - - if (!info->gpio_present) - return -EINVAL; - if (copy_from_user(&gpio, user_gpio, sizeof(gpio))) - return -EFAULT; - DBGINFO(("%s set_gpio state=%08x smask=%08x dir=%08x dmask=%08x\n", - info->device_name, gpio.state, gpio.smask, - gpio.dir, gpio.dmask)); - - spin_lock_irqsave(&info->port_array[0]->lock, flags); - if (gpio.dmask) { - data = rd_reg32(info, IODR); - data |= gpio.dmask & gpio.dir; - data &= ~(gpio.dmask & ~gpio.dir); - wr_reg32(info, IODR, data); - } - if (gpio.smask) { - data = rd_reg32(info, IOVR); - data |= gpio.smask & gpio.state; - data &= ~(gpio.smask & ~gpio.state); - wr_reg32(info, IOVR, data); - } - spin_unlock_irqrestore(&info->port_array[0]->lock, flags); - - return 0; -} - -/* - * get general purpose IO pin state and direction - */ -static int get_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) -{ - struct gpio_desc gpio; - if (!info->gpio_present) - return -EINVAL; - gpio.state = rd_reg32(info, IOVR); - gpio.smask = 0xffffffff; - gpio.dir = rd_reg32(info, IODR); - gpio.dmask = 0xffffffff; - if (copy_to_user(user_gpio, &gpio, sizeof(gpio))) - return -EFAULT; - DBGINFO(("%s get_gpio state=%08x dir=%08x\n", - info->device_name, gpio.state, gpio.dir)); - return 0; -} - -/* - * conditional wait facility - */ -static void init_cond_wait(struct cond_wait *w, unsigned int data) -{ - init_waitqueue_head(&w->q); - init_waitqueue_entry(&w->wait, current); - w->data = data; -} - -static void add_cond_wait(struct cond_wait **head, struct cond_wait *w) -{ - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&w->q, &w->wait); - w->next = *head; - *head = w; -} - -static void remove_cond_wait(struct cond_wait **head, struct cond_wait *cw) -{ - struct cond_wait *w, *prev; - remove_wait_queue(&cw->q, &cw->wait); - set_current_state(TASK_RUNNING); - for (w = *head, prev = NULL ; w != NULL ; prev = w, w = w->next) { - if (w == cw) { - if (prev != NULL) - prev->next = w->next; - else - *head = w->next; - break; - } - } -} - -static void flush_cond_wait(struct cond_wait **head) -{ - while (*head != NULL) { - wake_up_interruptible(&(*head)->q); - *head = (*head)->next; - } -} - -/* - * wait for general purpose I/O pin(s) to enter specified state - * - * user_gpio fields: - * state - bit indicates target pin state - * smask - set bit indicates watched pin - * - * The wait ends when at least one watched pin enters the specified - * state. When 0 (no error) is returned, user_gpio->state is set to the - * state of all GPIO pins when the wait ends. - * - * Note: Each pin may be a dedicated input, dedicated output, or - * configurable input/output. The number and configuration of pins - * varies with the specific adapter model. Only input pins (dedicated - * or configured) can be monitored with this function. - */ -static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) -{ - unsigned long flags; - int rc = 0; - struct gpio_desc gpio; - struct cond_wait wait; - u32 state; - - if (!info->gpio_present) - return -EINVAL; - if (copy_from_user(&gpio, user_gpio, sizeof(gpio))) - return -EFAULT; - DBGINFO(("%s wait_gpio() state=%08x smask=%08x\n", - info->device_name, gpio.state, gpio.smask)); - /* ignore output pins identified by set IODR bit */ - if ((gpio.smask &= ~rd_reg32(info, IODR)) == 0) - return -EINVAL; - init_cond_wait(&wait, gpio.smask); - - spin_lock_irqsave(&info->port_array[0]->lock, flags); - /* enable interrupts for watched pins */ - wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask); - /* get current pin states */ - state = rd_reg32(info, IOVR); - - if (gpio.smask & ~(state ^ gpio.state)) { - /* already in target state */ - gpio.state = state; - } else { - /* wait for target state */ - add_cond_wait(&info->gpio_wait_q, &wait); - spin_unlock_irqrestore(&info->port_array[0]->lock, flags); - schedule(); - if (signal_pending(current)) - rc = -ERESTARTSYS; - else - gpio.state = wait.data; - spin_lock_irqsave(&info->port_array[0]->lock, flags); - remove_cond_wait(&info->gpio_wait_q, &wait); - } - - /* disable all GPIO interrupts if no waiting processes */ - if (info->gpio_wait_q == NULL) - wr_reg32(info, IOER, 0); - spin_unlock_irqrestore(&info->port_array[0]->lock, flags); - - if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio))) - rc = -EFAULT; - return rc; -} - -static int modem_input_wait(struct slgt_info *info,int arg) -{ - unsigned long flags; - int rc; - struct mgsl_icount cprev, cnow; - DECLARE_WAITQUEUE(wait, current); - - /* save current irq counts */ - spin_lock_irqsave(&info->lock,flags); - cprev = info->icount; - add_wait_queue(&info->status_event_wait_q, &wait); - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&info->lock,flags); - - for(;;) { - schedule(); - if (signal_pending(current)) { - rc = -ERESTARTSYS; - break; - } - - /* get new irq counts */ - spin_lock_irqsave(&info->lock,flags); - cnow = info->icount; - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&info->lock,flags); - - /* if no change, wait aborted for some reason */ - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { - rc = -EIO; - break; - } - - /* check for change in caller specified modem input */ - if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || - (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || - (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || - (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { - rc = 0; - break; - } - - cprev = cnow; - } - remove_wait_queue(&info->status_event_wait_q, &wait); - set_current_state(TASK_RUNNING); - return rc; -} - -/* - * return state of serial control and status signals - */ -static int tiocmget(struct tty_struct *tty) -{ - struct slgt_info *info = tty->driver_data; - unsigned int result; - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - get_gtsignals(info); - spin_unlock_irqrestore(&info->lock,flags); - - result = ((info->signals & SerialSignal_RTS) ? TIOCM_RTS:0) + - ((info->signals & SerialSignal_DTR) ? TIOCM_DTR:0) + - ((info->signals & SerialSignal_DCD) ? TIOCM_CAR:0) + - ((info->signals & SerialSignal_RI) ? TIOCM_RNG:0) + - ((info->signals & SerialSignal_DSR) ? TIOCM_DSR:0) + - ((info->signals & SerialSignal_CTS) ? TIOCM_CTS:0); - - DBGINFO(("%s tiocmget value=%08X\n", info->device_name, result)); - return result; -} - -/* - * set modem control signals (DTR/RTS) - * - * cmd signal command: TIOCMBIS = set bit TIOCMBIC = clear bit - * TIOCMSET = set/clear signal values - * value bit mask for command - */ -static int tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct slgt_info *info = tty->driver_data; - unsigned long flags; - - DBGINFO(("%s tiocmset(%x,%x)\n", info->device_name, set, clear)); - - if (set & TIOCM_RTS) - info->signals |= SerialSignal_RTS; - if (set & TIOCM_DTR) - info->signals |= SerialSignal_DTR; - if (clear & TIOCM_RTS) - info->signals &= ~SerialSignal_RTS; - if (clear & TIOCM_DTR) - info->signals &= ~SerialSignal_DTR; - - spin_lock_irqsave(&info->lock,flags); - set_gtsignals(info); - spin_unlock_irqrestore(&info->lock,flags); - return 0; -} - -static bool carrier_raised(struct tty_port *port) -{ - unsigned long flags; - struct slgt_info *info = container_of(port, struct slgt_info, port); - - spin_lock_irqsave(&info->lock,flags); - get_gtsignals(info); - spin_unlock_irqrestore(&info->lock,flags); - - return info->signals & SerialSignal_DCD; -} - -static void dtr_rts(struct tty_port *port, bool active) -{ - unsigned long flags; - struct slgt_info *info = container_of(port, struct slgt_info, port); - - spin_lock_irqsave(&info->lock,flags); - if (active) - info->signals |= SerialSignal_RTS | SerialSignal_DTR; - else - info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_gtsignals(info); - spin_unlock_irqrestore(&info->lock,flags); -} - - -/* - * block current process until the device is ready to open - */ -static int block_til_ready(struct tty_struct *tty, struct file *filp, - struct slgt_info *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - bool do_clocal = false; - unsigned long flags; - bool cd; - struct tty_port *port = &info->port; - - DBGINFO(("%s block_til_ready\n", tty->driver->name)); - - if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { - /* nonblock mode is set or port is not enabled */ - tty_port_set_active(port, true); - return 0; - } - - if (C_CLOCAL(tty)) - do_clocal = true; - - /* Wait for carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that - * close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - - retval = 0; - add_wait_queue(&port->open_wait, &wait); - - spin_lock_irqsave(&info->lock, flags); - port->count--; - spin_unlock_irqrestore(&info->lock, flags); - port->blocked_open++; - - while (1) { - if (C_BAUD(tty) && tty_port_initialized(port)) - tty_port_raise_dtr_rts(port); - - set_current_state(TASK_INTERRUPTIBLE); - - if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { - retval = (port->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS; - break; - } - - cd = tty_port_carrier_raised(port); - if (do_clocal || cd) - break; - - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); - tty_unlock(tty); - schedule(); - tty_lock(tty); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); - - if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; - - if (!retval) - tty_port_set_active(port, true); - - DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval)); - return retval; -} - -/* - * allocate buffers used for calling line discipline receive_buf - * directly in synchronous mode - * note: add 5 bytes to max frame size to allow appending - * 32-bit CRC and status byte when configured to do so - */ -static int alloc_tmp_rbuf(struct slgt_info *info) -{ - info->tmp_rbuf = kmalloc(info->max_frame_size + 5, GFP_KERNEL); - if (info->tmp_rbuf == NULL) - return -ENOMEM; - - return 0; -} - -static void free_tmp_rbuf(struct slgt_info *info) -{ - kfree(info->tmp_rbuf); - info->tmp_rbuf = NULL; -} - -/* - * allocate DMA descriptor lists. - */ -static int alloc_desc(struct slgt_info *info) -{ - unsigned int i; - unsigned int pbufs; - - /* allocate memory to hold descriptor lists */ - info->bufs = dma_alloc_coherent(&info->pdev->dev, DESC_LIST_SIZE, - &info->bufs_dma_addr, GFP_KERNEL); - if (info->bufs == NULL) - return -ENOMEM; - - info->rbufs = (struct slgt_desc*)info->bufs; - info->tbufs = ((struct slgt_desc*)info->bufs) + info->rbuf_count; - - pbufs = (unsigned int)info->bufs_dma_addr; - - /* - * Build circular lists of descriptors - */ - - for (i=0; i < info->rbuf_count; i++) { - /* physical address of this descriptor */ - info->rbufs[i].pdesc = pbufs + (i * sizeof(struct slgt_desc)); - - /* physical address of next descriptor */ - if (i == info->rbuf_count - 1) - info->rbufs[i].next = cpu_to_le32(pbufs); - else - info->rbufs[i].next = cpu_to_le32(pbufs + ((i+1) * sizeof(struct slgt_desc))); - set_desc_count(info->rbufs[i], DMABUFSIZE); - } - - for (i=0; i < info->tbuf_count; i++) { - /* physical address of this descriptor */ - info->tbufs[i].pdesc = pbufs + ((info->rbuf_count + i) * sizeof(struct slgt_desc)); - - /* physical address of next descriptor */ - if (i == info->tbuf_count - 1) - info->tbufs[i].next = cpu_to_le32(pbufs + info->rbuf_count * sizeof(struct slgt_desc)); - else - info->tbufs[i].next = cpu_to_le32(pbufs + ((info->rbuf_count + i + 1) * sizeof(struct slgt_desc))); - } - - return 0; -} - -static void free_desc(struct slgt_info *info) -{ - if (info->bufs != NULL) { - dma_free_coherent(&info->pdev->dev, DESC_LIST_SIZE, - info->bufs, info->bufs_dma_addr); - info->bufs = NULL; - info->rbufs = NULL; - info->tbufs = NULL; - } -} - -static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) -{ - int i; - for (i=0; i < count; i++) { - bufs[i].buf = dma_alloc_coherent(&info->pdev->dev, DMABUFSIZE, - &bufs[i].buf_dma_addr, GFP_KERNEL); - if (!bufs[i].buf) - return -ENOMEM; - bufs[i].pbuf = cpu_to_le32((unsigned int)bufs[i].buf_dma_addr); - } - return 0; -} - -static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) -{ - int i; - for (i=0; i < count; i++) { - if (bufs[i].buf == NULL) - continue; - dma_free_coherent(&info->pdev->dev, DMABUFSIZE, bufs[i].buf, - bufs[i].buf_dma_addr); - bufs[i].buf = NULL; - } -} - -static int alloc_dma_bufs(struct slgt_info *info) -{ - info->rbuf_count = 32; - info->tbuf_count = 32; - - if (alloc_desc(info) < 0 || - alloc_bufs(info, info->rbufs, info->rbuf_count) < 0 || - alloc_bufs(info, info->tbufs, info->tbuf_count) < 0 || - alloc_tmp_rbuf(info) < 0) { - DBGERR(("%s DMA buffer alloc fail\n", info->device_name)); - return -ENOMEM; - } - reset_rbufs(info); - return 0; -} - -static void free_dma_bufs(struct slgt_info *info) -{ - if (info->bufs) { - free_bufs(info, info->rbufs, info->rbuf_count); - free_bufs(info, info->tbufs, info->tbuf_count); - free_desc(info); - } - free_tmp_rbuf(info); -} - -static int claim_resources(struct slgt_info *info) -{ - if (request_mem_region(info->phys_reg_addr, SLGT_REG_SIZE, "synclink_gt") == NULL) { - DBGERR(("%s reg addr conflict, addr=%08X\n", - info->device_name, info->phys_reg_addr)); - info->init_error = DiagStatus_AddressConflict; - goto errout; - } - else - info->reg_addr_requested = true; - - info->reg_addr = ioremap(info->phys_reg_addr, SLGT_REG_SIZE); - if (!info->reg_addr) { - DBGERR(("%s can't map device registers, addr=%08X\n", - info->device_name, info->phys_reg_addr)); - info->init_error = DiagStatus_CantAssignPciResources; - goto errout; - } - return 0; - -errout: - release_resources(info); - return -ENODEV; -} - -static void release_resources(struct slgt_info *info) -{ - if (info->irq_requested) { - free_irq(info->irq_level, info); - info->irq_requested = false; - } - - if (info->reg_addr_requested) { - release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE); - info->reg_addr_requested = false; - } - - if (info->reg_addr) { - iounmap(info->reg_addr); - info->reg_addr = NULL; - } -} - -/* Add the specified device instance data structure to the - * global linked list of devices and increment the device count. - */ -static void add_device(struct slgt_info *info) -{ - char *devstr; - - info->next_device = NULL; - info->line = slgt_device_count; - sprintf(info->device_name, "%s%d", tty_dev_prefix, info->line); - - if (info->line < MAX_DEVICES) { - if (maxframe[info->line]) - info->max_frame_size = maxframe[info->line]; - } - - slgt_device_count++; - - if (!slgt_device_list) - slgt_device_list = info; - else { - struct slgt_info *current_dev = slgt_device_list; - while(current_dev->next_device) - current_dev = current_dev->next_device; - current_dev->next_device = info; - } - - if (info->max_frame_size < 4096) - info->max_frame_size = 4096; - else if (info->max_frame_size > 65535) - info->max_frame_size = 65535; - - switch(info->pdev->device) { - case SYNCLINK_GT_DEVICE_ID: - devstr = "GT"; - break; - case SYNCLINK_GT2_DEVICE_ID: - devstr = "GT2"; - break; - case SYNCLINK_GT4_DEVICE_ID: - devstr = "GT4"; - break; - case SYNCLINK_AC_DEVICE_ID: - devstr = "AC"; - info->params.mode = MGSL_MODE_ASYNC; - break; - default: - devstr = "(unknown model)"; - } - printk("SyncLink %s %s IO=%08x IRQ=%d MaxFrameSize=%u\n", - devstr, info->device_name, info->phys_reg_addr, - info->irq_level, info->max_frame_size); - -#if SYNCLINK_GENERIC_HDLC - hdlcdev_init(info); -#endif -} - -static const struct tty_port_operations slgt_port_ops = { - .carrier_raised = carrier_raised, - .dtr_rts = dtr_rts, -}; - -/* - * allocate device instance structure, return NULL on failure - */ -static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) -{ - struct slgt_info *info; - - info = kzalloc_obj(struct slgt_info); - - if (!info) { - DBGERR(("%s device alloc failed adapter=%d port=%d\n", - driver_name, adapter_num, port_num)); - } else { - tty_port_init(&info->port); - info->port.ops = &slgt_port_ops; - INIT_WORK(&info->task, bh_handler); - info->max_frame_size = 4096; - info->base_clock = 14745600; - info->rbuf_fill_level = DMABUFSIZE; - init_waitqueue_head(&info->status_event_wait_q); - init_waitqueue_head(&info->event_wait_q); - spin_lock_init(&info->netlock); - memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); - info->idle_mode = HDLC_TXIDLE_FLAGS; - info->adapter_num = adapter_num; - info->port_num = port_num; - - timer_setup(&info->tx_timer, tx_timeout, 0); - timer_setup(&info->rx_timer, rx_timeout, 0); - - /* Copy configuration info to device instance data */ - info->pdev = pdev; - info->irq_level = pdev->irq; - info->phys_reg_addr = pci_resource_start(pdev,0); - - info->bus_type = MGSL_BUS_TYPE_PCI; - info->irq_flags = IRQF_SHARED; - - info->init_error = -1; /* assume error, set to 0 on successful init */ - } - - return info; -} - -static void device_init(int adapter_num, struct pci_dev *pdev) -{ - struct slgt_info *port_array[SLGT_MAX_PORTS]; - int i; - int port_count = 1; - - if (pdev->device == SYNCLINK_GT2_DEVICE_ID) - port_count = 2; - else if (pdev->device == SYNCLINK_GT4_DEVICE_ID) - port_count = 4; - - /* allocate device instances for all ports */ - for (i=0; i < port_count; ++i) { - port_array[i] = alloc_dev(adapter_num, i, pdev); - if (port_array[i] == NULL) { - for (--i; i >= 0; --i) { - tty_port_destroy(&port_array[i]->port); - kfree(port_array[i]); - } - return; - } - } - - /* give copy of port_array to all ports and add to device list */ - for (i=0; i < port_count; ++i) { - memcpy(port_array[i]->port_array, port_array, sizeof(port_array)); - add_device(port_array[i]); - port_array[i]->port_count = port_count; - spin_lock_init(&port_array[i]->lock); - } - - /* Allocate and claim adapter resources */ - if (!claim_resources(port_array[0])) { - - alloc_dma_bufs(port_array[0]); - - /* copy resource information from first port to others */ - for (i = 1; i < port_count; ++i) { - port_array[i]->irq_level = port_array[0]->irq_level; - port_array[i]->reg_addr = port_array[0]->reg_addr; - alloc_dma_bufs(port_array[i]); - } - - if (request_irq(port_array[0]->irq_level, - slgt_interrupt, - port_array[0]->irq_flags, - port_array[0]->device_name, - port_array[0]) < 0) { - DBGERR(("%s request_irq failed IRQ=%d\n", - port_array[0]->device_name, - port_array[0]->irq_level)); - } else { - port_array[0]->irq_requested = true; - adapter_test(port_array[0]); - for (i=1 ; i < port_count ; i++) { - port_array[i]->init_error = port_array[0]->init_error; - port_array[i]->gpio_present = port_array[0]->gpio_present; - } - } - } - - for (i = 0; i < port_count; ++i) { - struct slgt_info *info = port_array[i]; - tty_port_register_device(&info->port, serial_driver, info->line, - &info->pdev->dev); - } -} - -static int init_one(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - if (pci_enable_device(dev)) { - printk("error enabling pci device %p\n", dev); - return -EIO; - } - pci_set_master(dev); - device_init(slgt_device_count, dev); - return 0; -} - -static void remove_one(struct pci_dev *dev) -{ -} - -static const struct tty_operations ops = { - .open = open, - .close = close, - .write = write, - .put_char = put_char, - .flush_chars = flush_chars, - .write_room = write_room, - .chars_in_buffer = chars_in_buffer, - .flush_buffer = flush_buffer, - .ioctl = ioctl, - .compat_ioctl = slgt_compat_ioctl, - .throttle = throttle, - .unthrottle = unthrottle, - .send_xchar = send_xchar, - .break_ctl = set_break, - .wait_until_sent = wait_until_sent, - .set_termios = set_termios, - .stop = tx_hold, - .start = tx_release, - .hangup = hangup, - .tiocmget = tiocmget, - .tiocmset = tiocmset, - .get_icount = get_icount, - .proc_show = synclink_gt_proc_show, -}; - -static void slgt_cleanup(void) -{ - struct slgt_info *info; - struct slgt_info *tmp; - - if (serial_driver) { - for (info=slgt_device_list ; info != NULL ; info=info->next_device) - tty_unregister_device(serial_driver, info->line); - tty_unregister_driver(serial_driver); - tty_driver_kref_put(serial_driver); - } - - /* reset devices */ - info = slgt_device_list; - while(info) { - reset_port(info); - info = info->next_device; - } - - /* release devices */ - info = slgt_device_list; - while(info) { -#if SYNCLINK_GENERIC_HDLC - hdlcdev_exit(info); -#endif - free_dma_bufs(info); - free_tmp_rbuf(info); - if (info->port_num == 0) - release_resources(info); - tmp = info; - info = info->next_device; - tty_port_destroy(&tmp->port); - kfree(tmp); - } - - if (pci_registered) - pci_unregister_driver(&pci_driver); -} - -/* - * Driver initialization entry point. - */ -static int __init slgt_init(void) -{ - int rc; - - serial_driver = tty_alloc_driver(MAX_DEVICES, TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV); - if (IS_ERR(serial_driver)) { - printk("%s can't allocate tty driver\n", driver_name); - return PTR_ERR(serial_driver); - } - - /* Initialize the tty_driver structure */ - - serial_driver->driver_name = "synclink_gt"; - serial_driver->name = tty_dev_prefix; - serial_driver->major = ttymajor; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->init_termios.c_ispeed = 9600; - serial_driver->init_termios.c_ospeed = 9600; - tty_set_operations(serial_driver, &ops); - if ((rc = tty_register_driver(serial_driver)) < 0) { - DBGERR(("%s can't register serial driver\n", driver_name)); - tty_driver_kref_put(serial_driver); - serial_driver = NULL; - goto error; - } - - slgt_device_count = 0; - if ((rc = pci_register_driver(&pci_driver)) < 0) { - printk("%s pci_register_driver error=%d\n", driver_name, rc); - goto error; - } - pci_registered = true; - - return 0; - -error: - slgt_cleanup(); - return rc; -} - -static void __exit slgt_exit(void) -{ - slgt_cleanup(); -} - -module_init(slgt_init); -module_exit(slgt_exit); - -/* - * register access routines - */ - -static inline void __iomem *calc_regaddr(struct slgt_info *info, - unsigned int addr) -{ - void __iomem *reg_addr = info->reg_addr + addr; - - if (addr >= 0x80) - reg_addr += info->port_num * 32; - else if (addr >= 0x40) - reg_addr += info->port_num * 16; - - return reg_addr; -} - -static __u8 rd_reg8(struct slgt_info *info, unsigned int addr) -{ - return readb(calc_regaddr(info, addr)); -} - -static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value) -{ - writeb(value, calc_regaddr(info, addr)); -} - -static __u16 rd_reg16(struct slgt_info *info, unsigned int addr) -{ - return readw(calc_regaddr(info, addr)); -} - -static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value) -{ - writew(value, calc_regaddr(info, addr)); -} - -static __u32 rd_reg32(struct slgt_info *info, unsigned int addr) -{ - return readl(calc_regaddr(info, addr)); -} - -static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value) -{ - writel(value, calc_regaddr(info, addr)); -} - -static void rdma_reset(struct slgt_info *info) -{ - unsigned int i; - - /* set reset bit */ - wr_reg32(info, RDCSR, BIT1); - - /* wait for enable bit cleared */ - for(i=0 ; i < 1000 ; i++) - if (!(rd_reg32(info, RDCSR) & BIT0)) - break; -} - -static void tdma_reset(struct slgt_info *info) -{ - unsigned int i; - - /* set reset bit */ - wr_reg32(info, TDCSR, BIT1); - - /* wait for enable bit cleared */ - for(i=0 ; i < 1000 ; i++) - if (!(rd_reg32(info, TDCSR) & BIT0)) - break; -} - -/* - * enable internal loopback - * TxCLK and RxCLK are generated from BRG - * and TxD is looped back to RxD internally. - */ -static void enable_loopback(struct slgt_info *info) -{ - /* SCR (serial control) BIT2=loopback enable */ - wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT2)); - - if (info->params.mode != MGSL_MODE_ASYNC) { - /* CCR (clock control) - * 07..05 tx clock source (010 = BRG) - * 04..02 rx clock source (010 = BRG) - * 01 auxclk enable (0 = disable) - * 00 BRG enable (1 = enable) - * - * 0100 1001 - */ - wr_reg8(info, CCR, 0x49); - - /* set speed if available, otherwise use default */ - if (info->params.clock_speed) - set_rate(info, info->params.clock_speed); - else - set_rate(info, 3686400); - } -} - -/* - * set baud rate generator to specified rate - */ -static void set_rate(struct slgt_info *info, u32 rate) -{ - unsigned int div; - unsigned int osc = info->base_clock; - - /* div = osc/rate - 1 - * - * Round div up if osc/rate is not integer to - * force to next slowest rate. - */ - - if (rate) { - div = osc/rate; - if (!(osc % rate) && div) - div--; - wr_reg16(info, BDR, (unsigned short)div); - } -} - -static void rx_stop(struct slgt_info *info) -{ - unsigned short val; - - /* disable and reset receiver */ - val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */ - wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */ - wr_reg16(info, RCR, val); /* clear reset bit */ - - slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA + IRQ_RXIDLE); - - /* clear pending rx interrupts */ - wr_reg16(info, SSR, IRQ_RXIDLE + IRQ_RXOVER); - - rdma_reset(info); - - info->rx_enabled = false; - info->rx_restart = false; -} - -static void rx_start(struct slgt_info *info) -{ - unsigned short val; - - slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA); - - /* clear pending rx overrun IRQ */ - wr_reg16(info, SSR, IRQ_RXOVER); - - /* reset and disable receiver */ - val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */ - wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */ - wr_reg16(info, RCR, val); /* clear reset bit */ - - rdma_reset(info); - reset_rbufs(info); - - if (info->rx_pio) { - /* rx request when rx FIFO not empty */ - wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14)); - slgt_irq_on(info, IRQ_RXDATA); - if (info->params.mode == MGSL_MODE_ASYNC) { - /* enable saving of rx status */ - wr_reg32(info, RDCSR, BIT6); - } - } else { - /* rx request when rx FIFO half full */ - wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT14)); - /* set 1st descriptor address */ - wr_reg32(info, RDDAR, info->rbufs[0].pdesc); - - if (info->params.mode != MGSL_MODE_ASYNC) { - /* enable rx DMA and DMA interrupt */ - wr_reg32(info, RDCSR, (BIT2 + BIT0)); - } else { - /* enable saving of rx status, rx DMA and DMA interrupt */ - wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0)); - } - } - - slgt_irq_on(info, IRQ_RXOVER); - - /* enable receiver */ - wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1)); - - info->rx_restart = false; - info->rx_enabled = true; -} - -static void tx_start(struct slgt_info *info) -{ - if (!info->tx_enabled) { - wr_reg16(info, TCR, - (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2)); - info->tx_enabled = true; - } - - if (desc_count(info->tbufs[info->tbuf_start])) { - info->drop_rts_on_tx_done = false; - - if (info->params.mode != MGSL_MODE_ASYNC) { - if (info->params.flags & HDLC_FLAG_AUTO_RTS) { - get_gtsignals(info); - if (!(info->signals & SerialSignal_RTS)) { - info->signals |= SerialSignal_RTS; - set_gtsignals(info); - info->drop_rts_on_tx_done = true; - } - } - - slgt_irq_off(info, IRQ_TXDATA); - slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE); - /* clear tx idle and underrun status bits */ - wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); - } else { - slgt_irq_off(info, IRQ_TXDATA); - slgt_irq_on(info, IRQ_TXIDLE); - /* clear tx idle status bit */ - wr_reg16(info, SSR, IRQ_TXIDLE); - } - /* set 1st descriptor address and start DMA */ - wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); - wr_reg32(info, TDCSR, BIT2 + BIT0); - info->tx_active = true; - } -} - -static void tx_stop(struct slgt_info *info) -{ - unsigned short val; - - timer_delete(&info->tx_timer); - - tdma_reset(info); - - /* reset and disable transmitter */ - val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */ - wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ - - slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); - - /* clear tx idle and underrun status bit */ - wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); - - reset_tbufs(info); - - info->tx_enabled = false; - info->tx_active = false; -} - -static void reset_port(struct slgt_info *info) -{ - if (!info->reg_addr) - return; - - tx_stop(info); - rx_stop(info); - - info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_gtsignals(info); - - slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); -} - -static void reset_adapter(struct slgt_info *info) -{ - int i; - for (i=0; i < info->port_count; ++i) { - if (info->port_array[i]) - reset_port(info->port_array[i]); - } -} - -static void async_mode(struct slgt_info *info) -{ - unsigned short val; - - slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); - tx_stop(info); - rx_stop(info); - - /* TCR (tx control) - * - * 15..13 mode, 010=async - * 12..10 encoding, 000=NRZ - * 09 parity enable - * 08 1=odd parity, 0=even parity - * 07 1=RTS driver control - * 06 1=break enable - * 05..04 character length - * 00=5 bits - * 01=6 bits - * 10=7 bits - * 11=8 bits - * 03 0=1 stop bit, 1=2 stop bits - * 02 reset - * 01 enable - * 00 auto-CTS enable - */ - val = 0x4000; - - if (info->if_mode & MGSL_INTERFACE_RTS_EN) - val |= BIT7; - - if (info->params.parity != ASYNC_PARITY_NONE) { - val |= BIT9; - if (info->params.parity == ASYNC_PARITY_ODD) - val |= BIT8; - } - - switch (info->params.data_bits) - { - case 6: val |= BIT4; break; - case 7: val |= BIT5; break; - case 8: val |= BIT5 + BIT4; break; - } - - if (info->params.stop_bits != 1) - val |= BIT3; - - if (info->params.flags & HDLC_FLAG_AUTO_CTS) - val |= BIT0; - - wr_reg16(info, TCR, val); - - /* RCR (rx control) - * - * 15..13 mode, 010=async - * 12..10 encoding, 000=NRZ - * 09 parity enable - * 08 1=odd parity, 0=even parity - * 07..06 reserved, must be 0 - * 05..04 character length - * 00=5 bits - * 01=6 bits - * 10=7 bits - * 11=8 bits - * 03 reserved, must be zero - * 02 reset - * 01 enable - * 00 auto-DCD enable - */ - val = 0x4000; - - if (info->params.parity != ASYNC_PARITY_NONE) { - val |= BIT9; - if (info->params.parity == ASYNC_PARITY_ODD) - val |= BIT8; - } - - switch (info->params.data_bits) - { - case 6: val |= BIT4; break; - case 7: val |= BIT5; break; - case 8: val |= BIT5 + BIT4; break; - } - - if (info->params.flags & HDLC_FLAG_AUTO_DCD) - val |= BIT0; - - wr_reg16(info, RCR, val); - - /* CCR (clock control) - * - * 07..05 011 = tx clock source is BRG/16 - * 04..02 010 = rx clock source is BRG - * 01 0 = auxclk disabled - * 00 1 = BRG enabled - * - * 0110 1001 - */ - wr_reg8(info, CCR, 0x69); - - msc_set_vcr(info); - - /* SCR (serial control) - * - * 15 1=tx req on FIFO half empty - * 14 1=rx req on FIFO half full - * 13 tx data IRQ enable - * 12 tx idle IRQ enable - * 11 rx break on IRQ enable - * 10 rx data IRQ enable - * 09 rx break off IRQ enable - * 08 overrun IRQ enable - * 07 DSR IRQ enable - * 06 CTS IRQ enable - * 05 DCD IRQ enable - * 04 RI IRQ enable - * 03 0=16x sampling, 1=8x sampling - * 02 1=txd->rxd internal loopback enable - * 01 reserved, must be zero - * 00 1=master IRQ enable - */ - val = BIT15 + BIT14 + BIT0; - /* JCR[8] : 1 = x8 async mode feature available */ - if ((rd_reg32(info, JCR) & BIT8) && info->params.data_rate && - ((info->base_clock < (info->params.data_rate * 16)) || - (info->base_clock % (info->params.data_rate * 16)))) { - /* use 8x sampling */ - val |= BIT3; - set_rate(info, info->params.data_rate * 8); - } else { - /* use 16x sampling */ - set_rate(info, info->params.data_rate * 16); - } - wr_reg16(info, SCR, val); - - slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER); - - if (info->params.loopback) - enable_loopback(info); -} - -static void sync_mode(struct slgt_info *info) -{ - unsigned short val; - - slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); - tx_stop(info); - rx_stop(info); - - /* TCR (tx control) - * - * 15..13 mode - * 000=HDLC/SDLC - * 001=raw bit synchronous - * 010=asynchronous/isochronous - * 011=monosync byte synchronous - * 100=bisync byte synchronous - * 101=xsync byte synchronous - * 12..10 encoding - * 09 CRC enable - * 08 CRC32 - * 07 1=RTS driver control - * 06 preamble enable - * 05..04 preamble length - * 03 share open/close flag - * 02 reset - * 01 enable - * 00 auto-CTS enable - */ - val = BIT2; - - switch(info->params.mode) { - case MGSL_MODE_XSYNC: - val |= BIT15 + BIT13; - break; - case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; - case MGSL_MODE_BISYNC: val |= BIT15; break; - case MGSL_MODE_RAW: val |= BIT13; break; - } - if (info->if_mode & MGSL_INTERFACE_RTS_EN) - val |= BIT7; - - switch(info->params.encoding) - { - case HDLC_ENCODING_NRZB: val |= BIT10; break; - case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break; - case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break; - case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break; - case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break; - case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break; - case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break; - } - - switch (info->params.crc_type & HDLC_CRC_MASK) - { - case HDLC_CRC_16_CCITT: val |= BIT9; break; - case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break; - } - - if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE) - val |= BIT6; - - switch (info->params.preamble_length) - { - case HDLC_PREAMBLE_LENGTH_16BITS: val |= BIT5; break; - case HDLC_PREAMBLE_LENGTH_32BITS: val |= BIT4; break; - case HDLC_PREAMBLE_LENGTH_64BITS: val |= BIT5 + BIT4; break; - } - - if (info->params.flags & HDLC_FLAG_AUTO_CTS) - val |= BIT0; - - wr_reg16(info, TCR, val); - - /* TPR (transmit preamble) */ - - switch (info->params.preamble) - { - case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break; - case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break; - case HDLC_PREAMBLE_PATTERN_ZEROS: val = 0x00; break; - case HDLC_PREAMBLE_PATTERN_10: val = 0x55; break; - case HDLC_PREAMBLE_PATTERN_01: val = 0xaa; break; - default: val = 0x7e; break; - } - wr_reg8(info, TPR, (unsigned char)val); - - /* RCR (rx control) - * - * 15..13 mode - * 000=HDLC/SDLC - * 001=raw bit synchronous - * 010=asynchronous/isochronous - * 011=monosync byte synchronous - * 100=bisync byte synchronous - * 101=xsync byte synchronous - * 12..10 encoding - * 09 CRC enable - * 08 CRC32 - * 07..03 reserved, must be 0 - * 02 reset - * 01 enable - * 00 auto-DCD enable - */ - val = 0; - - switch(info->params.mode) { - case MGSL_MODE_XSYNC: - val |= BIT15 + BIT13; - break; - case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; - case MGSL_MODE_BISYNC: val |= BIT15; break; - case MGSL_MODE_RAW: val |= BIT13; break; - } - - switch(info->params.encoding) - { - case HDLC_ENCODING_NRZB: val |= BIT10; break; - case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break; - case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break; - case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break; - case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break; - case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break; - case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break; - } - - switch (info->params.crc_type & HDLC_CRC_MASK) - { - case HDLC_CRC_16_CCITT: val |= BIT9; break; - case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break; - } - - if (info->params.flags & HDLC_FLAG_AUTO_DCD) - val |= BIT0; - - wr_reg16(info, RCR, val); - - /* CCR (clock control) - * - * 07..05 tx clock source - * 04..02 rx clock source - * 01 auxclk enable - * 00 BRG enable - */ - val = 0; - - if (info->params.flags & HDLC_FLAG_TXC_BRG) - { - // when RxC source is DPLL, BRG generates 16X DPLL - // reference clock, so take TxC from BRG/16 to get - // transmit clock at actual data rate - if (info->params.flags & HDLC_FLAG_RXC_DPLL) - val |= BIT6 + BIT5; /* 011, txclk = BRG/16 */ - else - val |= BIT6; /* 010, txclk = BRG */ - } - else if (info->params.flags & HDLC_FLAG_TXC_DPLL) - val |= BIT7; /* 100, txclk = DPLL Input */ - else if (info->params.flags & HDLC_FLAG_TXC_RXCPIN) - val |= BIT5; /* 001, txclk = RXC Input */ - - if (info->params.flags & HDLC_FLAG_RXC_BRG) - val |= BIT3; /* 010, rxclk = BRG */ - else if (info->params.flags & HDLC_FLAG_RXC_DPLL) - val |= BIT4; /* 100, rxclk = DPLL */ - else if (info->params.flags & HDLC_FLAG_RXC_TXCPIN) - val |= BIT2; /* 001, rxclk = TXC Input */ - - if (info->params.clock_speed) - val |= BIT1 + BIT0; - - wr_reg8(info, CCR, (unsigned char)val); - - if (info->params.flags & (HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL)) - { - // program DPLL mode - switch(info->params.encoding) - { - case HDLC_ENCODING_BIPHASE_MARK: - case HDLC_ENCODING_BIPHASE_SPACE: - val = BIT7; break; - case HDLC_ENCODING_BIPHASE_LEVEL: - case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: - val = BIT7 + BIT6; break; - default: val = BIT6; // NRZ encodings - } - wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | val)); - - // DPLL requires a 16X reference clock from BRG - set_rate(info, info->params.clock_speed * 16); - } - else - set_rate(info, info->params.clock_speed); - - tx_set_idle(info); - - msc_set_vcr(info); - - /* SCR (serial control) - * - * 15 1=tx req on FIFO half empty - * 14 1=rx req on FIFO half full - * 13 tx data IRQ enable - * 12 tx idle IRQ enable - * 11 underrun IRQ enable - * 10 rx data IRQ enable - * 09 rx idle IRQ enable - * 08 overrun IRQ enable - * 07 DSR IRQ enable - * 06 CTS IRQ enable - * 05 DCD IRQ enable - * 04 RI IRQ enable - * 03 reserved, must be zero - * 02 1=txd->rxd internal loopback enable - * 01 reserved, must be zero - * 00 1=master IRQ enable - */ - wr_reg16(info, SCR, BIT15 + BIT14 + BIT0); - - if (info->params.loopback) - enable_loopback(info); -} - -/* - * set transmit idle mode - */ -static void tx_set_idle(struct slgt_info *info) -{ - unsigned char val; - unsigned short tcr; - - /* if preamble enabled (tcr[6] == 1) then tx idle size = 8 bits - * else tcr[5:4] = tx idle size: 00 = 8 bits, 01 = 16 bits - */ - tcr = rd_reg16(info, TCR); - if (info->idle_mode & HDLC_TXIDLE_CUSTOM_16) { - /* disable preamble, set idle size to 16 bits */ - tcr = (tcr & ~(BIT6 + BIT5)) | BIT4; - /* MSB of 16 bit idle specified in tx preamble register (TPR) */ - wr_reg8(info, TPR, (unsigned char)((info->idle_mode >> 8) & 0xff)); - } else if (!(tcr & BIT6)) { - /* preamble is disabled, set idle size to 8 bits */ - tcr &= ~(BIT5 + BIT4); - } - wr_reg16(info, TCR, tcr); - - if (info->idle_mode & (HDLC_TXIDLE_CUSTOM_8 | HDLC_TXIDLE_CUSTOM_16)) { - /* LSB of custom tx idle specified in tx idle register */ - val = (unsigned char)(info->idle_mode & 0xff); - } else { - /* standard 8 bit idle patterns */ - switch(info->idle_mode) - { - case HDLC_TXIDLE_FLAGS: val = 0x7e; break; - case HDLC_TXIDLE_ALT_ZEROS_ONES: - case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break; - case HDLC_TXIDLE_ZEROS: - case HDLC_TXIDLE_SPACE: val = 0x00; break; - default: val = 0xff; - } - } - - wr_reg8(info, TIR, val); -} - -/* - * get state of V24 status (input) signals - */ -static void get_gtsignals(struct slgt_info *info) -{ - unsigned short status = rd_reg16(info, SSR); - - /* clear all serial signals except RTS and DTR */ - info->signals &= SerialSignal_RTS | SerialSignal_DTR; - - if (status & BIT3) - info->signals |= SerialSignal_DSR; - if (status & BIT2) - info->signals |= SerialSignal_CTS; - if (status & BIT1) - info->signals |= SerialSignal_DCD; - if (status & BIT0) - info->signals |= SerialSignal_RI; -} - -/* - * set V.24 Control Register based on current configuration - */ -static void msc_set_vcr(struct slgt_info *info) -{ - unsigned char val = 0; - - /* VCR (V.24 control) - * - * 07..04 serial IF select - * 03 DTR - * 02 RTS - * 01 LL - * 00 RL - */ - - switch(info->if_mode & MGSL_INTERFACE_MASK) - { - case MGSL_INTERFACE_RS232: - val |= BIT5; /* 0010 */ - break; - case MGSL_INTERFACE_V35: - val |= BIT7 + BIT6 + BIT5; /* 1110 */ - break; - case MGSL_INTERFACE_RS422: - val |= BIT6; /* 0100 */ - break; - } - - if (info->if_mode & MGSL_INTERFACE_MSB_FIRST) - val |= BIT4; - if (info->signals & SerialSignal_DTR) - val |= BIT3; - if (info->signals & SerialSignal_RTS) - val |= BIT2; - if (info->if_mode & MGSL_INTERFACE_LL) - val |= BIT1; - if (info->if_mode & MGSL_INTERFACE_RL) - val |= BIT0; - wr_reg8(info, VCR, val); -} - -/* - * set state of V24 control (output) signals - */ -static void set_gtsignals(struct slgt_info *info) -{ - unsigned char val = rd_reg8(info, VCR); - if (info->signals & SerialSignal_DTR) - val |= BIT3; - else - val &= ~BIT3; - if (info->signals & SerialSignal_RTS) - val |= BIT2; - else - val &= ~BIT2; - wr_reg8(info, VCR, val); -} - -/* - * free range of receive DMA buffers (i to last) - */ -static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last) -{ - int done = 0; - - while(!done) { - /* reset current buffer for reuse */ - info->rbufs[i].status = 0; - set_desc_count(info->rbufs[i], info->rbuf_fill_level); - if (i == last) - done = 1; - if (++i == info->rbuf_count) - i = 0; - } - info->rbuf_current = i; -} - -/* - * mark all receive DMA buffers as free - */ -static void reset_rbufs(struct slgt_info *info) -{ - free_rbufs(info, 0, info->rbuf_count - 1); - info->rbuf_fill_index = 0; - info->rbuf_fill_count = 0; -} - -/* - * pass receive HDLC frame to upper layer - * - * return true if frame available, otherwise false - */ -static bool rx_get_frame(struct slgt_info *info) -{ - unsigned int start, end; - unsigned short status; - unsigned int framesize = 0; - unsigned long flags; - struct tty_struct *tty = info->port.tty; - unsigned char addr_field = 0xff; - unsigned int crc_size = 0; - - switch (info->params.crc_type & HDLC_CRC_MASK) { - case HDLC_CRC_16_CCITT: crc_size = 2; break; - case HDLC_CRC_32_CCITT: crc_size = 4; break; - } - -check_again: - - framesize = 0; - addr_field = 0xff; - start = end = info->rbuf_current; - - for (;;) { - if (!desc_complete(info->rbufs[end])) - goto cleanup; - - if (framesize == 0 && info->params.addr_filter != 0xff) - addr_field = info->rbufs[end].buf[0]; - - framesize += desc_count(info->rbufs[end]); - - if (desc_eof(info->rbufs[end])) - break; - - if (++end == info->rbuf_count) - end = 0; - - if (end == info->rbuf_current) { - if (info->rx_enabled){ - spin_lock_irqsave(&info->lock,flags); - rx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - } - goto cleanup; - } - } - - /* status - * - * 15 buffer complete - * 14..06 reserved - * 05..04 residue - * 02 eof (end of frame) - * 01 CRC error - * 00 abort - */ - status = desc_status(info->rbufs[end]); - - /* ignore CRC bit if not using CRC (bit is undefined) */ - if ((info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_NONE) - status &= ~BIT1; - - if (framesize == 0 || - (addr_field != 0xff && addr_field != info->params.addr_filter)) { - free_rbufs(info, start, end); - goto check_again; - } - - if (framesize < (2 + crc_size) || status & BIT0) { - info->icount.rxshort++; - framesize = 0; - } else if (status & BIT1) { - info->icount.rxcrc++; - if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) - framesize = 0; - } - -#if SYNCLINK_GENERIC_HDLC - if (framesize == 0) { - info->netdev->stats.rx_errors++; - info->netdev->stats.rx_frame_errors++; - } -#endif - - DBGBH(("%s rx frame status=%04X size=%d\n", - info->device_name, status, framesize)); - DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, info->rbuf_fill_level), "rx"); - - if (framesize) { - if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) { - framesize -= crc_size; - crc_size = 0; - } - - if (framesize > info->max_frame_size + crc_size) - info->icount.rxlong++; - else { - /* copy dma buffer(s) to contiguous temp buffer */ - int copy_count = framesize; - int i = start; - unsigned char *p = info->tmp_rbuf; - info->tmp_rbuf_count = framesize; - - info->icount.rxok++; - - while(copy_count) { - int partial_count = min_t(int, copy_count, info->rbuf_fill_level); - memcpy(p, info->rbufs[i].buf, partial_count); - p += partial_count; - copy_count -= partial_count; - if (++i == info->rbuf_count) - i = 0; - } - - if (info->params.crc_type & HDLC_CRC_RETURN_EX) { - *p = (status & BIT1) ? RX_CRC_ERROR : RX_OK; - framesize++; - } - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_rx(info,info->tmp_rbuf, framesize); - else -#endif - ldisc_receive_buf(tty, info->tmp_rbuf, NULL, - framesize); - } - } - free_rbufs(info, start, end); - return true; - -cleanup: - return false; -} - -/* - * pass receive buffer (RAW synchronous mode) to tty layer - * return true if buffer available, otherwise false - */ -static bool rx_get_buf(struct slgt_info *info) -{ - unsigned int i = info->rbuf_current; - unsigned int count; - - if (!desc_complete(info->rbufs[i])) - return false; - count = desc_count(info->rbufs[i]); - switch(info->params.mode) { - case MGSL_MODE_MONOSYNC: - case MGSL_MODE_BISYNC: - case MGSL_MODE_XSYNC: - /* ignore residue in byte synchronous modes */ - if (desc_residue(info->rbufs[i])) - count--; - break; - } - DBGDATA(info, info->rbufs[i].buf, count, "rx"); - DBGINFO(("rx_get_buf size=%d\n", count)); - if (count) - ldisc_receive_buf(info->port.tty, info->rbufs[i].buf, NULL, - count); - free_rbufs(info, i, i); - return true; -} - -static void reset_tbufs(struct slgt_info *info) -{ - unsigned int i; - info->tbuf_current = 0; - for (i=0 ; i < info->tbuf_count ; i++) { - info->tbufs[i].status = 0; - info->tbufs[i].count = 0; - } -} - -/* - * return number of free transmit DMA buffers - */ -static unsigned int free_tbuf_count(struct slgt_info *info) -{ - unsigned int count = 0; - unsigned int i = info->tbuf_current; - - do - { - if (desc_count(info->tbufs[i])) - break; /* buffer in use */ - ++count; - if (++i == info->tbuf_count) - i=0; - } while (i != info->tbuf_current); - - /* if tx DMA active, last zero count buffer is in use */ - if (count && (rd_reg32(info, TDCSR) & BIT0)) - --count; - - return count; -} - -/* - * return number of bytes in unsent transmit DMA buffers - * and the serial controller tx FIFO - */ -static unsigned int tbuf_bytes(struct slgt_info *info) -{ - unsigned int total_count = 0; - unsigned int i = info->tbuf_current; - unsigned int reg_value; - unsigned int count; - unsigned int active_buf_count = 0; - - /* - * Add descriptor counts for all tx DMA buffers. - * If count is zero (cleared by DMA controller after read), - * the buffer is complete or is actively being read from. - * - * Record buf_count of last buffer with zero count starting - * from current ring position. buf_count is mirror - * copy of count and is not cleared by serial controller. - * If DMA controller is active, that buffer is actively - * being read so add to total. - */ - do { - count = desc_count(info->tbufs[i]); - if (count) - total_count += count; - else if (!total_count) - active_buf_count = info->tbufs[i].buf_count; - if (++i == info->tbuf_count) - i = 0; - } while (i != info->tbuf_current); - - /* read tx DMA status register */ - reg_value = rd_reg32(info, TDCSR); - - /* if tx DMA active, last zero count buffer is in use */ - if (reg_value & BIT0) - total_count += active_buf_count; - - /* add tx FIFO count = reg_value[15..8] */ - total_count += (reg_value >> 8) & 0xff; - - /* if transmitter active add one byte for shift register */ - if (info->tx_active) - total_count++; - - return total_count; -} - -/* - * load data into transmit DMA buffer ring and start transmitter if needed - * return true if data accepted, otherwise false (buffers full) - */ -static bool tx_load(struct slgt_info *info, const u8 *buf, unsigned int size) -{ - unsigned short count; - unsigned int i; - struct slgt_desc *d; - - /* check required buffer space */ - if (DIV_ROUND_UP(size, DMABUFSIZE) > free_tbuf_count(info)) - return false; - - DBGDATA(info, buf, size, "tx"); - - /* - * copy data to one or more DMA buffers in circular ring - * tbuf_start = first buffer for this data - * tbuf_current = next free buffer - * - * Copy all data before making data visible to DMA controller by - * setting descriptor count of the first buffer. - * This prevents an active DMA controller from reading the first DMA - * buffers of a frame and stopping before the final buffers are filled. - */ - - info->tbuf_start = i = info->tbuf_current; - - while (size) { - d = &info->tbufs[i]; - - count = (unsigned short)((size > DMABUFSIZE) ? DMABUFSIZE : size); - memcpy(d->buf, buf, count); - - size -= count; - buf += count; - - /* - * set EOF bit for last buffer of HDLC frame or - * for every buffer in raw mode - */ - if ((!size && info->params.mode == MGSL_MODE_HDLC) || - info->params.mode == MGSL_MODE_RAW) - set_desc_eof(*d, 1); - else - set_desc_eof(*d, 0); - - /* set descriptor count for all but first buffer */ - if (i != info->tbuf_start) - set_desc_count(*d, count); - d->buf_count = count; - - if (++i == info->tbuf_count) - i = 0; - } - - info->tbuf_current = i; - - /* set first buffer count to make new data visible to DMA controller */ - d = &info->tbufs[info->tbuf_start]; - set_desc_count(*d, d->buf_count); - - /* start transmitter if needed and update transmit timeout */ - if (!info->tx_active) - tx_start(info); - update_tx_timer(info); - - return true; -} - -static int register_test(struct slgt_info *info) -{ - static unsigned short patterns[] = - {0x0000, 0xffff, 0xaaaa, 0x5555, 0x6969, 0x9696}; - static unsigned int count = ARRAY_SIZE(patterns); - unsigned int i; - int rc = 0; - - for (i=0 ; i < count ; i++) { - wr_reg16(info, TIR, patterns[i]); - wr_reg16(info, BDR, patterns[(i+1)%count]); - if ((rd_reg16(info, TIR) != patterns[i]) || - (rd_reg16(info, BDR) != patterns[(i+1)%count])) { - rc = -ENODEV; - break; - } - } - info->gpio_present = (rd_reg32(info, JCR) & BIT5) ? 1 : 0; - info->init_error = rc ? 0 : DiagStatus_AddressFailure; - return rc; -} - -static int irq_test(struct slgt_info *info) -{ - unsigned long timeout; - unsigned long flags; - struct tty_struct *oldtty = info->port.tty; - u32 speed = info->params.data_rate; - - info->params.data_rate = 921600; - info->port.tty = NULL; - - spin_lock_irqsave(&info->lock, flags); - async_mode(info); - slgt_irq_on(info, IRQ_TXIDLE); - - /* enable transmitter */ - wr_reg16(info, TCR, - (unsigned short)(rd_reg16(info, TCR) | BIT1)); - - /* write one byte and wait for tx idle */ - wr_reg16(info, TDR, 0); - - /* assume failure */ - info->init_error = DiagStatus_IrqFailure; - info->irq_occurred = false; - - spin_unlock_irqrestore(&info->lock, flags); - - timeout=100; - while(timeout-- && !info->irq_occurred) - msleep_interruptible(10); - - spin_lock_irqsave(&info->lock,flags); - reset_port(info); - spin_unlock_irqrestore(&info->lock,flags); - - info->params.data_rate = speed; - info->port.tty = oldtty; - - info->init_error = info->irq_occurred ? 0 : DiagStatus_IrqFailure; - return info->irq_occurred ? 0 : -ENODEV; -} - -static int loopback_test_rx(struct slgt_info *info) -{ - unsigned char *src, *dest; - int count; - - if (desc_complete(info->rbufs[0])) { - count = desc_count(info->rbufs[0]); - src = info->rbufs[0].buf; - dest = info->tmp_rbuf; - - for( ; count ; count-=2, src+=2) { - /* src=data byte (src+1)=status byte */ - if (!(*(src+1) & (BIT9 + BIT8))) { - *dest = *src; - dest++; - info->tmp_rbuf_count++; - } - } - DBGDATA(info, info->tmp_rbuf, info->tmp_rbuf_count, "rx"); - return 1; - } - return 0; -} - -static int loopback_test(struct slgt_info *info) -{ -#define TESTFRAMESIZE 20 - - unsigned long timeout; - u16 count; - unsigned char buf[TESTFRAMESIZE]; - int rc = -ENODEV; - unsigned long flags; - - struct tty_struct *oldtty = info->port.tty; - MGSL_PARAMS params; - - memcpy(¶ms, &info->params, sizeof(params)); - - info->params.mode = MGSL_MODE_ASYNC; - info->params.data_rate = 921600; - info->params.loopback = 1; - info->port.tty = NULL; - - /* build and send transmit frame */ - for (count = 0; count < TESTFRAMESIZE; ++count) - buf[count] = (unsigned char)count; - - info->tmp_rbuf_count = 0; - memset(info->tmp_rbuf, 0, TESTFRAMESIZE); - - /* program hardware for HDLC and enabled receiver */ - spin_lock_irqsave(&info->lock,flags); - async_mode(info); - rx_start(info); - tx_load(info, buf, count); - spin_unlock_irqrestore(&info->lock, flags); - - /* wait for receive complete */ - for (timeout = 100; timeout; --timeout) { - msleep_interruptible(10); - if (loopback_test_rx(info)) { - rc = 0; - break; - } - } - - /* verify received frame length and contents */ - if (!rc && (info->tmp_rbuf_count != count || - memcmp(buf, info->tmp_rbuf, count))) { - rc = -ENODEV; - } - - spin_lock_irqsave(&info->lock,flags); - reset_adapter(info); - spin_unlock_irqrestore(&info->lock,flags); - - memcpy(&info->params, ¶ms, sizeof(info->params)); - info->port.tty = oldtty; - - info->init_error = rc ? DiagStatus_DmaFailure : 0; - return rc; -} - -static int adapter_test(struct slgt_info *info) -{ - DBGINFO(("testing %s\n", info->device_name)); - if (register_test(info) < 0) { - printk("register test failure %s addr=%08X\n", - info->device_name, info->phys_reg_addr); - } else if (irq_test(info) < 0) { - printk("IRQ test failure %s IRQ=%d\n", - info->device_name, info->irq_level); - } else if (loopback_test(info) < 0) { - printk("loopback test failure %s\n", info->device_name); - } - return info->init_error; -} - -/* - * transmit timeout handler - */ -static void tx_timeout(struct timer_list *t) -{ - struct slgt_info *info = timer_container_of(info, t, tx_timer); - unsigned long flags; - - DBGINFO(("%s tx_timeout\n", info->device_name)); - if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { - info->icount.txtimeout++; - } - spin_lock_irqsave(&info->lock,flags); - tx_stop(info); - spin_unlock_irqrestore(&info->lock,flags); - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_tx_done(info); - else -#endif - bh_transmit(info); -} - -/* - * receive buffer polling timer - */ -static void rx_timeout(struct timer_list *t) -{ - struct slgt_info *info = timer_container_of(info, t, rx_timer); - unsigned long flags; - - DBGINFO(("%s rx_timeout\n", info->device_name)); - spin_lock_irqsave(&info->lock, flags); - info->pending_bh |= BH_RECEIVE; - spin_unlock_irqrestore(&info->lock, flags); - bh_handler(&info->task); -} - diff --git a/include/linux/synclink.h b/include/linux/synclink.h deleted file mode 100644 index f1405b1c71ba..000000000000 --- a/include/linux/synclink.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SyncLink Multiprotocol Serial Adapter Driver - * - * $Id: synclink.h,v 3.14 2006/07/17 20:15:43 paulkf Exp $ - * - * Copyright (C) 1998-2000 by Microgate Corporation - * - * Redistribution of this file is permitted under - * the terms of the GNU Public License (GPL) - */ -#ifndef _SYNCLINK_H_ -#define _SYNCLINK_H_ - -#include - -/* provide 32 bit ioctl compatibility on 64 bit systems */ -#ifdef CONFIG_COMPAT -#include -struct MGSL_PARAMS32 { - compat_ulong_t mode; - unsigned char loopback; - unsigned short flags; - unsigned char encoding; - compat_ulong_t clock_speed; - unsigned char addr_filter; - unsigned short crc_type; - unsigned char preamble_length; - unsigned char preamble; - compat_ulong_t data_rate; - unsigned char data_bits; - unsigned char stop_bits; - unsigned char parity; -}; -#define MGSL_IOCSPARAMS32 _IOW(MGSL_MAGIC_IOC,0,struct MGSL_PARAMS32) -#define MGSL_IOCGPARAMS32 _IOR(MGSL_MAGIC_IOC,1,struct MGSL_PARAMS32) -#endif -#endif /* _SYNCLINK_H_ */ diff --git a/include/uapi/linux/synclink.h b/include/uapi/linux/synclink.h deleted file mode 100644 index 62f32d4e1021..000000000000 --- a/include/uapi/linux/synclink.h +++ /dev/null @@ -1,301 +0,0 @@ -/* SPDX-License-Identifier: GPL-1.0+ WITH Linux-syscall-note */ -/* - * SyncLink Multiprotocol Serial Adapter Driver - * - * $Id: synclink.h,v 3.14 2006/07/17 20:15:43 paulkf Exp $ - * - * Copyright (C) 1998-2000 by Microgate Corporation - * - * Redistribution of this file is permitted under - * the terms of the GNU Public License (GPL) - */ - -#ifndef _UAPI_SYNCLINK_H_ -#define _UAPI_SYNCLINK_H_ -#define SYNCLINK_H_VERSION 3.6 - -#include - -#define BIT0 0x0001 -#define BIT1 0x0002 -#define BIT2 0x0004 -#define BIT3 0x0008 -#define BIT4 0x0010 -#define BIT5 0x0020 -#define BIT6 0x0040 -#define BIT7 0x0080 -#define BIT8 0x0100 -#define BIT9 0x0200 -#define BIT10 0x0400 -#define BIT11 0x0800 -#define BIT12 0x1000 -#define BIT13 0x2000 -#define BIT14 0x4000 -#define BIT15 0x8000 -#define BIT16 0x00010000 -#define BIT17 0x00020000 -#define BIT18 0x00040000 -#define BIT19 0x00080000 -#define BIT20 0x00100000 -#define BIT21 0x00200000 -#define BIT22 0x00400000 -#define BIT23 0x00800000 -#define BIT24 0x01000000 -#define BIT25 0x02000000 -#define BIT26 0x04000000 -#define BIT27 0x08000000 -#define BIT28 0x10000000 -#define BIT29 0x20000000 -#define BIT30 0x40000000 -#define BIT31 0x80000000 - - -#define HDLC_MAX_FRAME_SIZE 65535 -#define MAX_ASYNC_TRANSMIT 4096 -#define MAX_ASYNC_BUFFER_SIZE 4096 - -#define ASYNC_PARITY_NONE 0 -#define ASYNC_PARITY_EVEN 1 -#define ASYNC_PARITY_ODD 2 -#define ASYNC_PARITY_SPACE 3 - -#define HDLC_FLAG_UNDERRUN_ABORT7 0x0000 -#define HDLC_FLAG_UNDERRUN_ABORT15 0x0001 -#define HDLC_FLAG_UNDERRUN_FLAG 0x0002 -#define HDLC_FLAG_UNDERRUN_CRC 0x0004 -#define HDLC_FLAG_SHARE_ZERO 0x0010 -#define HDLC_FLAG_AUTO_CTS 0x0020 -#define HDLC_FLAG_AUTO_DCD 0x0040 -#define HDLC_FLAG_AUTO_RTS 0x0080 -#define HDLC_FLAG_RXC_DPLL 0x0100 -#define HDLC_FLAG_RXC_BRG 0x0200 -#define HDLC_FLAG_RXC_TXCPIN 0x8000 -#define HDLC_FLAG_RXC_RXCPIN 0x0000 -#define HDLC_FLAG_TXC_DPLL 0x0400 -#define HDLC_FLAG_TXC_BRG 0x0800 -#define HDLC_FLAG_TXC_TXCPIN 0x0000 -#define HDLC_FLAG_TXC_RXCPIN 0x0008 -#define HDLC_FLAG_DPLL_DIV8 0x1000 -#define HDLC_FLAG_DPLL_DIV16 0x2000 -#define HDLC_FLAG_DPLL_DIV32 0x0000 -#define HDLC_FLAG_HDLC_LOOPMODE 0x4000 - -#define HDLC_CRC_NONE 0 -#define HDLC_CRC_16_CCITT 1 -#define HDLC_CRC_32_CCITT 2 -#define HDLC_CRC_MASK 0x00ff -#define HDLC_CRC_RETURN_EX 0x8000 - -#define RX_OK 0 -#define RX_CRC_ERROR 1 - -#define HDLC_TXIDLE_FLAGS 0 -#define HDLC_TXIDLE_ALT_ZEROS_ONES 1 -#define HDLC_TXIDLE_ZEROS 2 -#define HDLC_TXIDLE_ONES 3 -#define HDLC_TXIDLE_ALT_MARK_SPACE 4 -#define HDLC_TXIDLE_SPACE 5 -#define HDLC_TXIDLE_MARK 6 -#define HDLC_TXIDLE_CUSTOM_8 0x10000000 -#define HDLC_TXIDLE_CUSTOM_16 0x20000000 - -#define HDLC_ENCODING_NRZ 0 -#define HDLC_ENCODING_NRZB 1 -#define HDLC_ENCODING_NRZI_MARK 2 -#define HDLC_ENCODING_NRZI_SPACE 3 -#define HDLC_ENCODING_NRZI HDLC_ENCODING_NRZI_SPACE -#define HDLC_ENCODING_BIPHASE_MARK 4 -#define HDLC_ENCODING_BIPHASE_SPACE 5 -#define HDLC_ENCODING_BIPHASE_LEVEL 6 -#define HDLC_ENCODING_DIFF_BIPHASE_LEVEL 7 - -#define HDLC_PREAMBLE_LENGTH_8BITS 0 -#define HDLC_PREAMBLE_LENGTH_16BITS 1 -#define HDLC_PREAMBLE_LENGTH_32BITS 2 -#define HDLC_PREAMBLE_LENGTH_64BITS 3 - -#define HDLC_PREAMBLE_PATTERN_NONE 0 -#define HDLC_PREAMBLE_PATTERN_ZEROS 1 -#define HDLC_PREAMBLE_PATTERN_FLAGS 2 -#define HDLC_PREAMBLE_PATTERN_10 3 -#define HDLC_PREAMBLE_PATTERN_01 4 -#define HDLC_PREAMBLE_PATTERN_ONES 5 - -#define MGSL_MODE_ASYNC 1 -#define MGSL_MODE_HDLC 2 -#define MGSL_MODE_MONOSYNC 3 -#define MGSL_MODE_BISYNC 4 -#define MGSL_MODE_RAW 6 -#define MGSL_MODE_BASE_CLOCK 7 -#define MGSL_MODE_XSYNC 8 - -#define MGSL_BUS_TYPE_ISA 1 -#define MGSL_BUS_TYPE_EISA 2 -#define MGSL_BUS_TYPE_PCI 5 - -#define MGSL_INTERFACE_MASK 0xf -#define MGSL_INTERFACE_DISABLE 0 -#define MGSL_INTERFACE_RS232 1 -#define MGSL_INTERFACE_V35 2 -#define MGSL_INTERFACE_RS422 3 -#define MGSL_INTERFACE_RTS_EN 0x10 -#define MGSL_INTERFACE_LL 0x20 -#define MGSL_INTERFACE_RL 0x40 -#define MGSL_INTERFACE_MSB_FIRST 0x80 - -typedef struct _MGSL_PARAMS -{ - /* Common */ - - unsigned long mode; /* Asynchronous or HDLC */ - unsigned char loopback; /* internal loopback mode */ - - /* HDLC Only */ - - unsigned short flags; - unsigned char encoding; /* NRZ, NRZI, etc. */ - unsigned long clock_speed; /* external clock speed in bits per second */ - unsigned char addr_filter; /* receive HDLC address filter, 0xFF = disable */ - unsigned short crc_type; /* None, CRC16-CCITT, or CRC32-CCITT */ - unsigned char preamble_length; - unsigned char preamble; - - /* Async Only */ - - unsigned long data_rate; /* bits per second */ - unsigned char data_bits; /* 7 or 8 data bits */ - unsigned char stop_bits; /* 1 or 2 stop bits */ - unsigned char parity; /* none, even, or odd */ - -} MGSL_PARAMS, *PMGSL_PARAMS; - -#define MICROGATE_VENDOR_ID 0x13c0 -#define SYNCLINK_DEVICE_ID 0x0010 -#define MGSCC_DEVICE_ID 0x0020 -#define SYNCLINK_SCA_DEVICE_ID 0x0030 -#define SYNCLINK_GT_DEVICE_ID 0x0070 -#define SYNCLINK_GT4_DEVICE_ID 0x0080 -#define SYNCLINK_AC_DEVICE_ID 0x0090 -#define SYNCLINK_GT2_DEVICE_ID 0x00A0 -#define MGSL_MAX_SERIAL_NUMBER 30 - -/* -** device diagnostics status -*/ - -#define DiagStatus_OK 0 -#define DiagStatus_AddressFailure 1 -#define DiagStatus_AddressConflict 2 -#define DiagStatus_IrqFailure 3 -#define DiagStatus_IrqConflict 4 -#define DiagStatus_DmaFailure 5 -#define DiagStatus_DmaConflict 6 -#define DiagStatus_PciAdapterNotFound 7 -#define DiagStatus_CantAssignPciResources 8 -#define DiagStatus_CantAssignPciMemAddr 9 -#define DiagStatus_CantAssignPciIoAddr 10 -#define DiagStatus_CantAssignPciIrq 11 -#define DiagStatus_MemoryError 12 - -#define SerialSignal_DCD 0x01 /* Data Carrier Detect */ -#define SerialSignal_TXD 0x02 /* Transmit Data */ -#define SerialSignal_RI 0x04 /* Ring Indicator */ -#define SerialSignal_RXD 0x08 /* Receive Data */ -#define SerialSignal_CTS 0x10 /* Clear to Send */ -#define SerialSignal_RTS 0x20 /* Request to Send */ -#define SerialSignal_DSR 0x40 /* Data Set Ready */ -#define SerialSignal_DTR 0x80 /* Data Terminal Ready */ - - -/* - * Counters of the input lines (CTS, DSR, RI, CD) interrupts - */ -struct mgsl_icount { - __u32 cts, dsr, rng, dcd, tx, rx; - __u32 frame, parity, overrun, brk; - __u32 buf_overrun; - __u32 txok; - __u32 txunder; - __u32 txabort; - __u32 txtimeout; - __u32 rxshort; - __u32 rxlong; - __u32 rxabort; - __u32 rxover; - __u32 rxcrc; - __u32 rxok; - __u32 exithunt; - __u32 rxidle; -}; - -struct gpio_desc { - __u32 state; - __u32 smask; - __u32 dir; - __u32 dmask; -}; - -#define DEBUG_LEVEL_DATA 1 -#define DEBUG_LEVEL_ERROR 2 -#define DEBUG_LEVEL_INFO 3 -#define DEBUG_LEVEL_BH 4 -#define DEBUG_LEVEL_ISR 5 - -/* -** Event bit flags for use with MgslWaitEvent -*/ - -#define MgslEvent_DsrActive 0x0001 -#define MgslEvent_DsrInactive 0x0002 -#define MgslEvent_Dsr 0x0003 -#define MgslEvent_CtsActive 0x0004 -#define MgslEvent_CtsInactive 0x0008 -#define MgslEvent_Cts 0x000c -#define MgslEvent_DcdActive 0x0010 -#define MgslEvent_DcdInactive 0x0020 -#define MgslEvent_Dcd 0x0030 -#define MgslEvent_RiActive 0x0040 -#define MgslEvent_RiInactive 0x0080 -#define MgslEvent_Ri 0x00c0 -#define MgslEvent_ExitHuntMode 0x0100 -#define MgslEvent_IdleReceived 0x0200 - -/* Private IOCTL codes: - * - * MGSL_IOCSPARAMS set MGSL_PARAMS structure values - * MGSL_IOCGPARAMS get current MGSL_PARAMS structure values - * MGSL_IOCSTXIDLE set current transmit idle mode - * MGSL_IOCGTXIDLE get current transmit idle mode - * MGSL_IOCTXENABLE enable or disable transmitter - * MGSL_IOCRXENABLE enable or disable receiver - * MGSL_IOCTXABORT abort transmitting frame (HDLC) - * MGSL_IOCGSTATS return current statistics - * MGSL_IOCWAITEVENT wait for specified event to occur - * MGSL_LOOPTXDONE transmit in HDLC LoopMode done - * MGSL_IOCSIF set the serial interface type - * MGSL_IOCGIF get the serial interface type - */ -#define MGSL_MAGIC_IOC 'm' -#define MGSL_IOCSPARAMS _IOW(MGSL_MAGIC_IOC,0,struct _MGSL_PARAMS) -#define MGSL_IOCGPARAMS _IOR(MGSL_MAGIC_IOC,1,struct _MGSL_PARAMS) -#define MGSL_IOCSTXIDLE _IO(MGSL_MAGIC_IOC,2) -#define MGSL_IOCGTXIDLE _IO(MGSL_MAGIC_IOC,3) -#define MGSL_IOCTXENABLE _IO(MGSL_MAGIC_IOC,4) -#define MGSL_IOCRXENABLE _IO(MGSL_MAGIC_IOC,5) -#define MGSL_IOCTXABORT _IO(MGSL_MAGIC_IOC,6) -#define MGSL_IOCGSTATS _IO(MGSL_MAGIC_IOC,7) -#define MGSL_IOCWAITEVENT _IOWR(MGSL_MAGIC_IOC,8,int) -#define MGSL_IOCCLRMODCOUNT _IO(MGSL_MAGIC_IOC,15) -#define MGSL_IOCLOOPTXDONE _IO(MGSL_MAGIC_IOC,9) -#define MGSL_IOCSIF _IO(MGSL_MAGIC_IOC,10) -#define MGSL_IOCGIF _IO(MGSL_MAGIC_IOC,11) -#define MGSL_IOCSGPIO _IOW(MGSL_MAGIC_IOC,16,struct gpio_desc) -#define MGSL_IOCGGPIO _IOR(MGSL_MAGIC_IOC,17,struct gpio_desc) -#define MGSL_IOCWAITGPIO _IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc) -#define MGSL_IOCSXSYNC _IO(MGSL_MAGIC_IOC, 19) -#define MGSL_IOCGXSYNC _IO(MGSL_MAGIC_IOC, 20) -#define MGSL_IOCSXCTRL _IO(MGSL_MAGIC_IOC, 21) -#define MGSL_IOCGXCTRL _IO(MGSL_MAGIC_IOC, 22) - - -#endif /* _UAPI_SYNCLINK_H_ */ From 44e55f1f3088e4a471a943fbcf087ea7783a0199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 28 Apr 2026 16:40:33 +0200 Subject: [PATCH 07/49] serial: 8250_pci: Consistently define pci_device_ids using named initializers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... and PCI device helpers. The various struct pci_device_id were defined using a mixture of initialization by position and by name. Some use the PCI device helpers (like PCI_DEVICE and PCI_DEVICE_SUB) and others don't. Consistently use named initializers, drop assignments of 0 by position for .class and .class_mask and use the PCI device helpers. Also use consistent line-breaks and positioning for opening and closing curly braces. The secret plan is to make struct pci_device_id::driver_data an anonymous union (similar to https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/) and that requires named initializers. But it's also a nice cleanup on its own. This patch doesn't change the compiled result; this was verified using an allmodconfig with several things disabled that make reproducible builds harder on x86 and arm64. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/20260428144033.1037617-2-u.kleine-koenig@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 3120 ++++++++++++++-------------- 1 file changed, 1563 insertions(+), 1557 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 2fbd8f2603b5..3e5bc9e8d269 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -143,16 +143,15 @@ struct serial_private { #define PCIE_DEVICE_ID_AX99100 0x9100 static const struct pci_device_id pci_use_msi[] = { - { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900, - 0xA000, 0x1000) }, - { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912, - 0xA000, 0x1000) }, - { PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922, - 0xA000, 0x1000) }, - { PCI_DEVICE_SUB(PCI_VENDOR_ID_ASIX, PCI_DEVICE_ID_ASIX_AX99100, - 0xA000, 0x1000) }, - { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL, - PCI_ANY_ID, PCI_ANY_ID) }, + { PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9900, + 0xA000, 0x1000) }, + { PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9912, + 0xA000, 0x1000) }, + { PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9922, + 0xA000, 0x1000) }, + { PCI_VDEVICE_SUB(ASIX, PCI_DEVICE_ID_ASIX_AX99100, + 0xA000, 0x1000) }, + { PCI_VDEVICE(HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL) }, { PCI_DEVICE_SUB(PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100, 0xA000, 0x1000) }, { } @@ -4040,42 +4039,42 @@ static const struct pci_device_id blacklist[] = { /* multi-io cards handled by parport_serial */ /* WCH CH353 2S1P */ - { PCI_VDEVICE(WCHCN, 0x7053), REPORT_CONFIG(PARPORT_SERIAL), }, + { PCI_VDEVICE(WCHCN, 0x7053), .driver_data = REPORT_CONFIG(PARPORT_SERIAL), }, /* WCH CH353 1S1P */ - { PCI_VDEVICE(WCHCN, 0x5053), REPORT_CONFIG(PARPORT_SERIAL), }, + { PCI_VDEVICE(WCHCN, 0x5053), .driver_data = REPORT_CONFIG(PARPORT_SERIAL), }, /* WCH CH382 2S1P */ - { PCI_VDEVICE(WCHIC, 0x3250), REPORT_CONFIG(PARPORT_SERIAL), }, + { PCI_VDEVICE(WCHIC, 0x3250), .driver_data = REPORT_CONFIG(PARPORT_SERIAL), }, /* Intel platforms with MID UART */ - { PCI_VDEVICE(INTEL, 0x081b), REPORT_8250_CONFIG(MID), }, - { PCI_VDEVICE(INTEL, 0x081c), REPORT_8250_CONFIG(MID), }, - { PCI_VDEVICE(INTEL, 0x081d), REPORT_8250_CONFIG(MID), }, - { PCI_VDEVICE(INTEL, 0x1191), REPORT_8250_CONFIG(MID), }, - { PCI_VDEVICE(INTEL, 0x18d8), REPORT_8250_CONFIG(MID), }, - { PCI_VDEVICE(INTEL, 0x19d8), REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x081b), .driver_data = REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x081c), .driver_data = REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x081d), .driver_data = REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x1191), .driver_data = REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x18d8), .driver_data = REPORT_8250_CONFIG(MID), }, + { PCI_VDEVICE(INTEL, 0x19d8), .driver_data = REPORT_8250_CONFIG(MID), }, /* Intel platforms with DesignWare UART */ - { PCI_VDEVICE(INTEL, 0x0936), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x0f0a), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x0f0c), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x228a), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x228c), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x4b96), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x4b97), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x4b98), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x4b99), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x4b9a), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x4b9b), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x9ce3), REPORT_8250_CONFIG(LPSS), }, - { PCI_VDEVICE(INTEL, 0x9ce4), REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x0936), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x0f0a), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x0f0c), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x228a), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x228c), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b96), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b97), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b98), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b99), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b9a), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x4b9b), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x9ce3), .driver_data = REPORT_8250_CONFIG(LPSS), }, + { PCI_VDEVICE(INTEL, 0x9ce4), .driver_data = REPORT_8250_CONFIG(LPSS), }, /* Exar devices */ - { PCI_VDEVICE(EXAR, PCI_ANY_ID), REPORT_8250_CONFIG(EXAR), }, - { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), REPORT_8250_CONFIG(EXAR), }, + { PCI_VDEVICE(EXAR, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(EXAR), }, + { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(EXAR), }, /* Pericom devices */ - { PCI_VDEVICE(PERICOM, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), }, - { PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), }, + { PCI_VDEVICE(PERICOM, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(PERICOM), }, + { PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(PERICOM), }, /* End of the black list */ { } @@ -4448,713 +4447,753 @@ static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one, pciserial_resume_one); static const struct pci_device_id serial_pci_tbl[] = { - { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600, - PCI_DEVICE_ID_ADVANTECH_PCI1600_1611, PCI_ANY_ID, 0, 0, - pbn_b0_4_921600 }, - /* 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_VDEVICE_SUB(ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600, + PCI_DEVICE_ID_ADVANTECH_PCI1600_1611, PCI_ANY_ID), + .driver_data = pbn_b0_4_921600, + }, { + /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ + PCI_VDEVICE_SUB(ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, + PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001), + .driver_data = pbn_b2_8_921600, + }, { + /* Advantech also use 0x3618 and 0xf618 */ + PCI_VDEVICE_SUB(ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618, + PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE_SUB(ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618, + PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232), + .driver_data = pbn_b1_8_1382400, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232), + .driver_data = pbn_b1_4_1382400, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232), + .driver_data = pbn_b1_2_1382400, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232), + .driver_data = pbn_b1_8_1382400, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232), + .driver_data = pbn_b1_4_1382400, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232), + .driver_data = pbn_b1_2_1382400, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485), + .driver_data = pbn_b1_8_921600, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4), + .driver_data = pbn_b1_8_921600, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485), + .driver_data = pbn_b1_4_921600, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2), + .driver_data = pbn_b1_4_921600, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485), + .driver_data = pbn_b1_2_921600, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6), + .driver_data = pbn_b1_8_921600, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1), + .driver_data = pbn_b1_8_921600, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1), + .driver_data = pbn_b1_4_921600, + }, { + PCI_VDEVICE_SUB(V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ), + .driver_data = pbn_b1_2_1250000, + }, { + PCI_VDEVICE_SUB(OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2), + .driver_data = pbn_b0_2_1843200, + }, { + PCI_VDEVICE_SUB(OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4), + .driver_data = pbn_b0_4_1843200, + }, { + PCI_VDEVICE_SUB(OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_AFAVLAB, PCI_SUBDEVICE_ID_AFAVLAB_P061), + .driver_data = pbn_b0_4_1152000, + }, { + PCI_VDEVICE(SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530), + .driver_data = pbn_b2_bt_1_115200, + }, { + PCI_VDEVICE(SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2), + .driver_data = pbn_b2_bt_2_115200, + }, { + PCI_VDEVICE(SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422), + .driver_data = pbn_b2_bt_4_115200, + }, { + PCI_VDEVICE(SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232), + .driver_data = pbn_b2_bt_2_115200, + }, { + PCI_VDEVICE(SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4), + .driver_data = pbn_b2_bt_4_115200, + }, { + PCI_VDEVICE(SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8), + .driver_data = pbn_b2_8_115200, + }, { + PCI_VDEVICE(SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803), + .driver_data = pbn_b2_8_460800, + }, { + PCI_VDEVICE(SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8), + .driver_data = pbn_b2_8_115200, + }, { + PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2), + .driver_data = pbn_b2_bt_2_115200, + }, { + PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_SPCOM200), + .driver_data = pbn_b2_bt_2_921600, + }, { + /* VScom SPCOM800, from sl@s.pl */ + PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_SPCOM800), + .driver_data = pbn_b2_8_921600, + }, { + PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_1077), + .driver_data = pbn_b2_4_921600, + }, { + /* Unknown card - subdevice 0x1584 */ + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_UNKNOWN_0x1584), + .driver_data = pbn_b2_4_115200, + }, { + /* Unknown card - subdevice 0x1588 */ + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_UNKNOWN_0x1588), + .driver_data = pbn_b2_8_115200, + }, { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_KEYSPAN, PCI_SUBDEVICE_ID_KEYSPAN_SX2), + .driver_data = pbn_panacom, + }, { + PCI_VDEVICE(PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM), + .driver_data = pbn_panacom4, + }, { + PCI_VDEVICE(PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM), + .driver_data = pbn_panacom2, + }, { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9030, + PCI_VENDOR_ID_ESDGMBH, PCI_DEVICE_ID_ESDGMBH_CPCIASIO4), + .driver_data = pbn_b2_4_115200, + }, { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, PCI_SUBDEVICE_ID_CHASE_PCIFAST4), + .driver_data = pbn_b2_4_460800, + }, { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, PCI_SUBDEVICE_ID_CHASE_PCIFAST8), + .driver_data = pbn_b2_8_460800, + }, { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, PCI_SUBDEVICE_ID_CHASE_PCIFAST16), + .driver_data = pbn_b2_16_460800, + }, { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC), + .driver_data = pbn_b2_16_460800, + }, { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, PCI_SUBDEVICE_ID_CHASE_PCIRAS4), + .driver_data = pbn_b2_4_460800, + }, { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, PCI_SUBDEVICE_ID_CHASE_PCIRAS8), + .driver_data = pbn_b2_8_460800, + }, { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4055), + .driver_data = pbn_b2_4_115200, + }, { + /* + * Megawolf Romulus PCI Serial Card, from Mike Hudson + * (Exoray@isys.ca) + */ + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_ROMULUS, + 0x10b5, 0x106a), + .driver_data = pbn_plx_romulus, + }, - { 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 }, /* * 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 }, - + { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_QSC100), + .driver_data = pbn_b1_4_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_DSC100), + .driver_data = pbn_b1_2_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_DSC100E), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_DSC200), + .driver_data = pbn_b1_2_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_DSC200E), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_QSC200), + .driver_data = pbn_b1_4_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D), + .driver_data = pbn_b1_8_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M), + .driver_data = pbn_b1_8_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_QSCP100), + .driver_data = pbn_b1_4_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_DSCP100), + .driver_data = pbn_b1_2_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_QSCP200), + .driver_data = pbn_b1_4_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_DSCP200), + .driver_data = pbn_b1_2_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP100), + .driver_data = pbn_b2_4_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP100), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP100), + .driver_data = pbn_b2_1_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP200), + .driver_data = pbn_b2_4_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP200), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP200), + .driver_data = pbn_b2_1_115200, + }, { + PCI_VDEVICE(QUATECH, PCI_DEVICE_ID_QUATECH_ESCLP100), + .driver_data = pbn_b0_8_115200, + }, { + PCI_VDEVICE_SUB(SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE_SUB(OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL), + .driver_data = pbn_b0_4_1152000, + }, { + PCI_VDEVICE(OXSEMI, 0x9505), + .driver_data = 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 }, + PCI_VDEVICE_SUB(OXSEMI, 0x950a, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00), + .driver_data = pbn_b0_2_115200, + }, { + PCI_VDEVICE_SUB(OXSEMI, 0x950a, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30), + .driver_data = pbn_b0_2_115200, + }, { + PCI_VDEVICE(OXSEMI, 0x950a), + .driver_data = pbn_b0_2_1130000, + }, { + PCI_VDEVICE_SUB(OXSEMI, PCI_DEVICE_ID_OXSEMI_C950, + PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950), + .driver_data = pbn_b0_1_921600, + }, { + PCI_VDEVICE(OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954), + .driver_data = pbn_b0_4_115200, + }, { + PCI_VDEVICE(OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952), + .driver_data = pbn_b0_bt_2_921600, + }, { + PCI_VDEVICE(OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958), + .driver_data = 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_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, - { PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */ - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_15625000 }, + { + PCI_VDEVICE(OXSEMI, 0xc101), /* OXPCIe952 1 Legacy UART */ + .driver_data = pbn_b0_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc105), /* OXPCIe952 1 Legacy UART */ + .driver_data = pbn_b0_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc11b), /* OXPCIe952 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc11f), /* OXPCIe952 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc120), /* OXPCIe952 1 Legacy UART */ + .driver_data = pbn_b0_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc124), /* OXPCIe952 1 Legacy UART */ + .driver_data = pbn_b0_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc138), /* OXPCIe952 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc13d), /* OXPCIe952 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc140), /* OXPCIe952 1 Legacy UART */ + .driver_data = pbn_b0_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc141), /* OXPCIe952 1 Legacy UART */ + .driver_data = pbn_b0_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc144), /* OXPCIe952 1 Legacy UART */ + .driver_data = pbn_b0_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc145), /* OXPCIe952 1 Legacy UART */ + .driver_data = pbn_b0_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc158), /* OXPCIe952 2 Native UART */ + .driver_data = pbn_oxsemi_2_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc15d), /* OXPCIe952 2 Native UART */ + .driver_data = pbn_oxsemi_2_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc208), /* OXPCIe954 4 Native UART */ + .driver_data = pbn_oxsemi_4_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc20d), /* OXPCIe954 4 Native UART */ + .driver_data = pbn_oxsemi_4_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc308), /* OXPCIe958 8 Native UART */ + .driver_data = pbn_oxsemi_8_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc30d), /* OXPCIe958 8 Native UART */ + .driver_data = pbn_oxsemi_8_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc40b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc40f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc41b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc41f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc42b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc42f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc43b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc43f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc44b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc44f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc45b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc45f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc46b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc46f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc47b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc47f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc48b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc48f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc49b), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc49f), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc4ab), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc4af), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc4bb), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc4bf), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc4cb), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, { + PCI_VDEVICE(OXSEMI, 0xc4cf), /* OXPCIe200 1 Native UART */ + .driver_data = pbn_oxsemi_1_15625000, + }, /* * 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_15625000 }, - { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */ - PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0, - pbn_oxsemi_2_15625000 }, - { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */ - PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0, - pbn_oxsemi_4_15625000 }, - { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */ - PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0, - pbn_oxsemi_8_15625000 }, + { + /* IQ Express 1 Port V.34 Super-G3 Fax */ + PCI_VDEVICE_SUB(MAINPINE, 0x4000, + PCI_VENDOR_ID_MAINPINE, 0x4001), + .driver_data = pbn_oxsemi_1_15625000, + }, { + /* IQ Express 2 Port V.34 Super-G3 Fax */ + PCI_VDEVICE_SUB(MAINPINE, 0x4000, + PCI_VENDOR_ID_MAINPINE, 0x4002), + .driver_data = pbn_oxsemi_2_15625000, + }, { + /* IQ Express 4 Port V.34 Super-G3 Fax */ + PCI_VDEVICE_SUB(MAINPINE, 0x4000, + PCI_VENDOR_ID_MAINPINE, 0x4004), + .driver_data = pbn_oxsemi_4_15625000, + }, { + /* IQ Express 8 Port V.34 Super-G3 Fax */ + PCI_VDEVICE_SUB(MAINPINE, 0x4000, + PCI_VENDOR_ID_MAINPINE, 0x4008), + .driver_data = pbn_oxsemi_8_15625000, + }, /* * 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_15625000 }, + { + PCI_VDEVICE_SUB(DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM, + PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID), + .driver_data = pbn_oxsemi_2_15625000, + }, + /* * EndRun Technologies. PCI express device range. * EndRun PTP/1588 has 2 Native UARTs utilizing OxSemi 952. */ - { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_15625000 }, + { + PCI_VDEVICE(ENDRUN, PCI_DEVICE_ID_ENDRUN_1588), + .driver_data = pbn_oxsemi_2_15625000, + }, /* * 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 }, + { + PCI_VDEVICE_SUB(SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, + PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232), + .driver_data = pbn_sbsxrsio, + }, { + PCI_VDEVICE_SUB(SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, + PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422), + .driver_data = pbn_sbsxrsio, + }, { + PCI_VDEVICE_SUB(SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, + PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232), + .driver_data = pbn_sbsxrsio, + }, { + PCI_VDEVICE_SUB(SBSMODULARIO, PCI_DEVICE_ID_OCTPRO, + PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422), + .driver_data = 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 }, + { + PCI_VDEVICE(ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM), + .driver_data = 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_titan_1_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_titan_2_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_titan_4_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_titan_8_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_titan_2_4000000 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_titan_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 }, + { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_100), + .driver_data = pbn_b0_1_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_200), + .driver_data = pbn_b0_2_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_400), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_800B), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_100L), + .driver_data = pbn_b1_1_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_200L), + .driver_data = pbn_b1_bt_2_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_400L), + .driver_data = pbn_b0_bt_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_800L), + .driver_data = pbn_b0_bt_8_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_200I), + .driver_data = pbn_b4_bt_2_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_400I), + .driver_data = pbn_b4_bt_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_800I), + .driver_data = pbn_b4_bt_8_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_400EH), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_800EH), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_800EHB), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_100E), + .driver_data = pbn_titan_1_4000000, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_200E), + .driver_data = pbn_titan_2_4000000, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_400E), + .driver_data = pbn_titan_4_4000000, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_800E), + .driver_data = pbn_titan_8_4000000, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_200EI), + .driver_data = pbn_titan_2_4000000, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_200EISI), + .driver_data = pbn_titan_2_4000000, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_200V3), + .driver_data = pbn_b0_bt_2_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_400V3), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_410V3), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_800V3), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE(TITAN, PCI_DEVICE_ID_TITAN_800V3B), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550), + .driver_data = pbn_b2_1_460800, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650), + .driver_data = pbn_b2_1_460800, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850), + .driver_data = pbn_b2_1_460800, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550), + .driver_data = pbn_b2_bt_2_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650), + .driver_data = pbn_b2_bt_2_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850), + .driver_data = pbn_b2_bt_2_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550), + .driver_data = pbn_b2_bt_4_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650), + .driver_data = pbn_b2_bt_4_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850), + .driver_data = pbn_b2_bt_4_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550), + .driver_data = pbn_b0_1_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650), + .driver_data = pbn_b0_1_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850), + .driver_data = pbn_b0_1_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550), + .driver_data = pbn_b0_bt_2_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650), + .driver_data = pbn_b0_bt_2_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850), + .driver_data = pbn_b0_bt_2_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550), + .driver_data = pbn_b0_bt_4_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650), + .driver_data = pbn_b0_bt_4_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850), + .driver_data = pbn_b0_bt_4_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550), + .driver_data = pbn_b0_bt_8_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650), + .driver_data = pbn_b0_bt_8_921600, + }, { + PCI_VDEVICE(SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850), + .driver_data = 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_VDEVICE_SUB(COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4), + .driver_data = pbn_computone_4, + }, { + PCI_VDEVICE_SUB(COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8), + .driver_data = pbn_computone_8, + }, { + PCI_VDEVICE_SUB(COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6), + .driver_data = 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 }, + { + PCI_VDEVICE(OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N), + .driver_data = pbn_oxsemi, + }, { + PCI_VDEVICE_SUB(TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID), + .driver_data = 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 }, + { + PCI_VDEVICE_SUB(SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0001), + .driver_data = pbn_sunix_pci_1s, + }, { + PCI_VDEVICE_SUB(SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0002), + .driver_data = pbn_sunix_pci_2s, + }, { + PCI_VDEVICE_SUB(SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0004), + .driver_data = pbn_sunix_pci_4s, + }, { + PCI_VDEVICE_SUB(SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0084), + .driver_data = pbn_sunix_pci_4s, + }, { + PCI_VDEVICE_SUB(SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0008), + .driver_data = pbn_sunix_pci_8s, + }, { + PCI_VDEVICE_SUB(SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0088), + .driver_data = pbn_sunix_pci_8s, + }, { + PCI_VDEVICE_SUB(SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, 0x0010), + .driver_data = pbn_sunix_pci_16s, + }, /* * AFAVLAB serial card, from Harald Welte */ - { 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_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 }, + { + PCI_VDEVICE(AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028), + .driver_data = pbn_b0_bt_8_115200, + }, { + PCI_VDEVICE(AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030), + .driver_data = pbn_b0_bt_8_115200, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_DSERIAL), + .driver_data = pbn_b0_bt_2_115200, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A), + .driver_data = pbn_b0_bt_2_115200, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B), + .driver_data = pbn_b0_bt_2_115200, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_OCTO_A), + .driver_data = pbn_b0_bt_4_460800, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_OCTO_B), + .driver_data = pbn_b0_bt_4_460800, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS), + .driver_data = pbn_b0_bt_2_460800, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_QUAD_A), + .driver_data = pbn_b0_bt_2_460800, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_QUAD_B), + .driver_data = pbn_b0_bt_2_460800, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_SSERIAL), + .driver_data = pbn_b0_bt_1_115200, + }, { + PCI_VDEVICE(LAVA, PCI_DEVICE_ID_LAVA_PORT_650), + .driver_data = pbn_b0_bt_1_460800, + }, /* * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408). @@ -5164,560 +5203,533 @@ static const struct pci_device_id serial_pci_tbl[] = { * 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 }, + { + PCI_VDEVICE_SUB(KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, + 0x1204, 0x0004), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE_SUB(KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, + 0x1208, 0x0004), + .driver_data = pbn_b0_4_921600, + }, +/* { + PCI_VDEVICE_SUB(KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, + 0x1402, 0x0002), + .driver_data = pbn_b0_2_921600, + }, */ +/* { + PCI_VDEVICE_SUB(KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0, + 0x1404, 0x0004), + .driver_data = pbn_b0_4_921600, + }, */ + { + PCI_VDEVICE_SUB(KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1, + 0x1208, 0x0004), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE_SUB(KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2, + 0x1204, 0x0004), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE_SUB(KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2, + 0x1208, 0x0004), + .driver_data = pbn_b0_4_921600, + }, { + PCI_VDEVICE_SUB(KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3, + 0x1208, 0x0004), + .driver_data = 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 }, + { + PCI_VDEVICE(DELL, PCI_DEVICE_ID_DELL_RAC4), + .driver_data = 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 }, + { + PCI_VDEVICE(DELL, PCI_DEVICE_ID_DELL_RACIII), + .driver_data = 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 }, + { + PCI_VDEVICE(MORETON, PCI_DEVICE_ID_RASTEL_2PORT), + .driver_data = 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 }, + { + PCI_VDEVICE_SUB(INTEL, PCI_DEVICE_ID_INTEL_80960_RP, + 0xE4BF, PCI_ANY_ID), + .driver_data = 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 }, + { + PCI_VDEVICE(XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM), + .driver_data = 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 }, + { + PCI_VDEVICE(XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G), + .driver_data = pbn_b0_1_115200, + }, /* * Untested PCI modems, sent in from various folks... */ - /* - * Elsa Model 56K PCI Modem, from Andreas Rath - */ - { 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 }, + { + /* Elsa Model 56K PCI Modem, from Andreas Rath */ + PCI_VDEVICE_SUB(ROCKWELL, 0x1004, 0x1048, 0x1500), + .driver_data = pbn_b1_1_115200, + }, { + PCI_VDEVICE_SUB(SGI, PCI_DEVICE_ID_SGI_IOC3, 0xFF00, 0), + .driver_data = 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 }, - /* HPE PCI serial device */ - { PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_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 }, - /* - * 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-100 - */ - { PCI_VENDOR_ID_INTASHIELD, 0x0D60, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_1_115200 }, - /* - * IntaShield IS-200 - */ - { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0d80 */ - 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 }, - /* - * IntaShield IX-100 - */ - { PCI_VENDOR_ID_INTASHIELD, 0x4027, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_1_15625000 }, - /* - * IntaShield IX-200 - */ - { PCI_VENDOR_ID_INTASHIELD, 0x4028, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_2_15625000 }, - /* - * IntaShield IX-400 - */ - { PCI_VENDOR_ID_INTASHIELD, 0x4029, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_4_15625000 }, + { + PCI_VDEVICE_SUB(HP, PCI_DEVICE_ID_HP_DIVA, + PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3), + .driver_data = pbn_b1_1_115200, + }, { + PCI_VDEVICE(HP, PCI_DEVICE_ID_HP_DIVA), + .driver_data = pbn_b0_5_115200, + }, { + PCI_VDEVICE(HP, PCI_DEVICE_ID_HP_DIVA_AUX), + .driver_data = pbn_b2_1_115200, + }, { + /* HPE PCI serial device */ + PCI_VDEVICE(HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL), + .driver_data = pbn_b1_1_115200, + }, { + PCI_VDEVICE(DCI, PCI_DEVICE_ID_DCI_PCCOM2), + .driver_data = pbn_b3_2_115200, + }, { + PCI_VDEVICE(DCI, PCI_DEVICE_ID_DCI_PCCOM4), + .driver_data = pbn_b3_4_115200, + }, { + PCI_VDEVICE(DCI, PCI_DEVICE_ID_DCI_PCCOM8), + .driver_data = pbn_b3_8_115200, + }, { + /* Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) */ + PCI_VDEVICE(TOPIC, PCI_DEVICE_ID_TOPIC_TP560), + .driver_data = pbn_b0_1_115200, + }, { + /* ITE */ + PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8872), + .driver_data = pbn_b1_bt_1_115200, + }, { + /* IntaShield IS-100 */ + PCI_VDEVICE(INTASHIELD, 0x0D60), + .driver_data = pbn_b2_1_115200, + }, { + /* IntaShield IS-200; 135a.0d80 */ + PCI_VDEVICE(INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200), + .driver_data = pbn_b2_2_115200, + }, { + /* IntaShield IS-400; 135a.0dc0 */ + PCI_VDEVICE(INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400), + .driver_data = pbn_b2_4_115200, + }, { + /* IntaShield IX-100 */ + PCI_VDEVICE(INTASHIELD, 0x4027), + .driver_data = pbn_oxsemi_1_15625000, + }, { + /* IntaShield IX-200 */ + PCI_VDEVICE(INTASHIELD, 0x4028), + .driver_data = pbn_oxsemi_2_15625000, + }, { + /* IntaShield IX-400 */ + PCI_VDEVICE(INTASHIELD, 0x4029), + .driver_data = pbn_oxsemi_4_15625000, + }, /* Brainboxes Devices */ /* * Brainboxes UC-101 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0BA1, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0BA2, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0BA3, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0BA1), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0BA2), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0BA3), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UC-235/246 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0AA1, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_1_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0AA2, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_1_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0AA1), + .driver_data = pbn_b2_1_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0AA2), + .driver_data = pbn_b2_1_115200, + }, /* * Brainboxes UC-253/UC-734 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0CA1, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0CA1), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UC-260/271/701/756 */ - { 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 }, + { + PCI_VDEVICE(INTASHIELD, 0x0D21), + .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, + .class_mask = 0xffff00, + .driver_data = pbn_b2_4_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0E34), + .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, + .class_mask = 0xffff00, + .driver_data = pbn_b2_4_115200, + }, /* * Brainboxes UC-268 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0841, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_4_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0841), + .driver_data = pbn_b2_4_115200, + }, /* * Brainboxes UC-275/279 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0881, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_8_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0881), + .driver_data = pbn_b2_8_115200, + }, /* * Brainboxes UC-302 */ - { PCI_VENDOR_ID_INTASHIELD, 0x08E1, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x08E2, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x08E3, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x08E1), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x08E2), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x08E3), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UC-310 */ - { PCI_VENDOR_ID_INTASHIELD, 0x08C1, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x08C1), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UC-313 */ - { PCI_VENDOR_ID_INTASHIELD, 0x08A1, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x08A2, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x08A3, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x08A1), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x08A2), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x08A3), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UC-320/324 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0A61, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_1_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0A61), + .driver_data = pbn_b2_1_115200, + }, /* * Brainboxes UC-346 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0B01, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_4_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0B02, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_4_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0B01), + .driver_data = pbn_b2_4_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0B02), + .driver_data = pbn_b2_4_115200, + }, /* * Brainboxes UC-357 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0A81, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0A82, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0A83, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0A81), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0A82), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0A83), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UC-368 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0C41, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_4_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0C42, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_4_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0C43, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_4_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0C41), + .driver_data = pbn_b2_4_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0C42), + .driver_data = pbn_b2_4_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0C43), + .driver_data = pbn_b2_4_115200, + }, /* * Brainboxes UC-420 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0921, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_4_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0921), + .driver_data = pbn_b2_4_115200, + }, /* * Brainboxes UC-607 */ - { PCI_VENDOR_ID_INTASHIELD, 0x09A1, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x09A2, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x09A3, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x09A1), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x09A2), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x09A3), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UC-836 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0D41, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_4_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0D41), + .driver_data = pbn_b2_4_115200, + }, /* * Brainboxes UP-189 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0AC1, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0AC2, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0AC3, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0AC1), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0AC2), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0AC3), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UP-200 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0B21, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0B22, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0B23, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0B21), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0B22), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0B23), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UP-869 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0C01, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0C02, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0C03, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0C01), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0C02), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0C03), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes UP-880 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0C21, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0C22, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x0C23, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_2_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0C21), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0C22), + .driver_data = pbn_b2_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x0C23), + .driver_data = pbn_b2_2_115200, + }, /* * Brainboxes PX-101 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4005, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b0_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x4019, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_2_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4005), + .driver_data = pbn_b0_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x4019), + .driver_data = pbn_oxsemi_2_15625000, + }, /* * Brainboxes PX-235/246 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4004, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b0_1_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x4016, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_1_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4004), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x4016), + .driver_data = pbn_oxsemi_1_15625000, + }, /* * Brainboxes PX-203/PX-257 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4006, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b0_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x4015, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_2_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4006), + .driver_data = pbn_b0_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x4015), + .driver_data = pbn_oxsemi_2_15625000, + }, /* * Brainboxes PX-260/PX-701 */ - { PCI_VENDOR_ID_INTASHIELD, 0x400A, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_4_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x400A), + .driver_data = pbn_oxsemi_4_15625000, + }, /* * Brainboxes PX-275/279 */ - { PCI_VENDOR_ID_INTASHIELD, 0x0E41, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b2_8_115200 }, + { + PCI_VDEVICE(INTASHIELD, 0x0E41), + .driver_data = pbn_b2_8_115200, + }, /* * Brainboxes PX-310 */ - { PCI_VENDOR_ID_INTASHIELD, 0x400E, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_2_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x400E), + .driver_data = pbn_oxsemi_2_15625000, + }, /* * Brainboxes PX-313 */ - { PCI_VENDOR_ID_INTASHIELD, 0x400C, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_2_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x400C), + .driver_data = pbn_oxsemi_2_15625000, + }, /* * Brainboxes PX-320/324/PX-376/PX-387 */ - { PCI_VENDOR_ID_INTASHIELD, 0x400B, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_1_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x400B), + .driver_data = pbn_oxsemi_1_15625000, + }, /* * Brainboxes PX-335/346 */ - { PCI_VENDOR_ID_INTASHIELD, 0x400F, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_4_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x400F), + .driver_data = pbn_oxsemi_4_15625000, + }, /* * Brainboxes PX-368 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4010, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_4_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4010), + .driver_data = pbn_oxsemi_4_15625000, + }, /* * Brainboxes PX-420 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4000, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b0_4_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x4011, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_4_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4000), + .driver_data = pbn_b0_4_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x4011), + .driver_data = pbn_oxsemi_4_15625000, + }, /* * Brainboxes PX-475 */ - { PCI_VENDOR_ID_INTASHIELD, 0x401D, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_1_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x401D), + .driver_data = pbn_oxsemi_1_15625000, + }, /* * Brainboxes PX-803/PX-857 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4009, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b0_2_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x4018, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_2_15625000 }, - { PCI_VENDOR_ID_INTASHIELD, 0x401E, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_2_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4009), + .driver_data = pbn_b0_2_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x4018), + .driver_data = pbn_oxsemi_2_15625000, + }, { + PCI_VDEVICE(INTASHIELD, 0x401E), + .driver_data = pbn_oxsemi_2_15625000, + }, /* * Brainboxes PX-820 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4002, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b0_4_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x4013, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_4_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4002), + .driver_data = pbn_b0_4_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x4013), + .driver_data = pbn_oxsemi_4_15625000, + }, /* * Brainboxes PX-835/PX-846 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4008, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_b0_1_115200 }, - { PCI_VENDOR_ID_INTASHIELD, 0x4017, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_1_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4008), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE(INTASHIELD, 0x4017), + .driver_data = pbn_oxsemi_1_15625000, + }, /* * Brainboxes XC-235 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4026, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_1_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4026), + .driver_data = pbn_oxsemi_1_15625000, + }, /* * Brainboxes XC-475 */ - { PCI_VENDOR_ID_INTASHIELD, 0x4021, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, - pbn_oxsemi_1_15625000 }, + { + PCI_VDEVICE(INTASHIELD, 0x4021), + .driver_data = pbn_oxsemi_1_15625000, + }, /* * 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 }, + { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9030, + PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4), + .driver_data = pbn_b2_4_921600, + }, + { + PCI_VDEVICE_SUB(PLX, PCI_DEVICE_ID_PLX_9030, + PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8), + .driver_data = pbn_b2_8_921600, + }, /* * Mainpine series cards: Fairly standard layout but fools @@ -5725,375 +5737,343 @@ static const struct pci_device_id serial_pci_tbl[] = { * 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 }, + { + /* RockForceDUO */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0200), + .driver_data = pbn_b0_2_115200, + }, { + /* RockForceQUATRO */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0300), + .driver_data = pbn_b0_4_115200, + }, { + /* RockForceDUO+ */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0400), + .driver_data = pbn_b0_2_115200, + }, { + /* RockForceQUATRO+ */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0500), + .driver_data = pbn_b0_4_115200, + }, { + /* RockForce+ */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0600), + .driver_data = pbn_b0_2_115200, + }, { + /* RockForce+ */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0700), + .driver_data = pbn_b0_4_115200, + }, { + /* RockForceOCTO+ */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0800), + .driver_data = pbn_b0_8_115200, + }, { + /* RockForceDUO+ */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0C00), + .driver_data = pbn_b0_2_115200, + }, { + /* RockForceQUARTRO+ */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x0D00), + .driver_data = pbn_b0_4_115200, + }, { + /* RockForceOCTO+ */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x1D00), + .driver_data = pbn_b0_8_115200, + }, { + /* RockForceD1 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2000), + .driver_data = pbn_b0_1_115200, + }, { + /* RockForceF1 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2100), + .driver_data = pbn_b0_1_115200, + }, { /* RockForceD2 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2200), + .driver_data = pbn_b0_2_115200, + }, { /* RockForceF2 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2300), + .driver_data = pbn_b0_2_115200, + }, { + /* RockForceD4 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2400), + .driver_data = pbn_b0_4_115200, + }, { + /* RockForceF4 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2500), + .driver_data = pbn_b0_4_115200, + }, { + /* RockForceD8 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2600), + .driver_data = pbn_b0_8_115200, + }, { + /* RockForceF8 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x2700), + .driver_data = pbn_b0_8_115200, + }, { + /* IQ Express D1 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3000), + .driver_data = pbn_b0_1_115200, + }, { + /* IQ Express F1 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3100), + .driver_data = pbn_b0_1_115200, + }, { + /* IQ Express D2 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3200), + .driver_data = pbn_b0_2_115200, + }, { + /* IQ Express F2 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3300), + .driver_data = pbn_b0_2_115200, + }, { + /* IQ Express D4 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3400), + .driver_data = pbn_b0_4_115200, + }, { + /* IQ Express F4 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3500), + .driver_data = pbn_b0_4_115200, + }, { + /* IQ Express D8 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3C00), + .driver_data = pbn_b0_8_115200, + }, { + /* IQ Express F8 */ + PCI_VDEVICE_SUB(MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE, + PCI_VENDOR_ID_MAINPINE, 0x3D00), + .driver_data = 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 }, + { + /* PA Semi PA6T-1682M on-chip UART */ + PCI_VDEVICE(PASEMI, 0xa004), + .driver_data = 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_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI23216), + .driver_data = pbn_b1_16_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI2328), + .driver_data = pbn_b1_8_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI2324), + .driver_data = pbn_b1_bt_4_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI2322), + .driver_data = pbn_b1_bt_2_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI2324I), + .driver_data = pbn_b1_bt_4_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI2322I), + .driver_data = pbn_b1_bt_2_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8420_23216), + .driver_data = pbn_b1_16_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8420_2328), + .driver_data = pbn_b1_8_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8420_2324), + .driver_data = pbn_b1_bt_4_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8420_2322), + .driver_data = pbn_b1_bt_2_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8422_2324), + .driver_data = pbn_b1_bt_4_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8422_2322), + .driver_data = pbn_b1_bt_2_115200, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8430_2322), + .driver_data = pbn_ni8430_2, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI8430_2322), + .driver_data = pbn_ni8430_2, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8430_2324), + .driver_data = pbn_ni8430_4, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI8430_2324), + .driver_data = pbn_ni8430_4, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8430_2328), + .driver_data = pbn_ni8430_8, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI8430_2328), + .driver_data = pbn_ni8430_8, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8430_23216), + .driver_data = pbn_ni8430_16, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI8430_23216), + .driver_data = pbn_ni8430_16, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8432_2322), + .driver_data = pbn_ni8430_2, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI8432_2322), + .driver_data = pbn_ni8430_2, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PXI8432_2324), + .driver_data = pbn_ni8430_4, + }, { + PCI_VDEVICE(NI, PCI_DEVICE_ID_NI_PCI8432_2324), + .driver_data = pbn_ni8430_4, + }, /* * MOXA */ - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102E), pbn_moxa_2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102EL), pbn_moxa_2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102N), pbn_moxa_2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A), pbn_moxa_4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104N), pbn_moxa_4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP112N), pbn_moxa_2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114EL), pbn_moxa_4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114N), pbn_moxa_4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A), pbn_moxa_8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B), pbn_moxa_8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A), pbn_moxa_8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I), pbn_moxa_8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132EL), pbn_moxa_2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132N), pbn_moxa_2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A), pbn_moxa_4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134N), pbn_moxa_4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP138E_A), pbn_moxa_8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A), pbn_moxa_8 }, + { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102E), + .driver_data = pbn_moxa_2, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102EL), + .driver_data = pbn_moxa_2, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102N), + .driver_data = pbn_moxa_2, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A), + .driver_data = pbn_moxa_4, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104N), + .driver_data = pbn_moxa_4, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP112N), + .driver_data = pbn_moxa_2, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114EL), + .driver_data = pbn_moxa_4, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114N), + .driver_data = pbn_moxa_4, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A), + .driver_data = pbn_moxa_8, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B), + .driver_data = pbn_moxa_8, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A), + .driver_data = pbn_moxa_8, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I), + .driver_data = pbn_moxa_8, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132EL), + .driver_data = pbn_moxa_2, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132N), + .driver_data = pbn_moxa_2, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A), + .driver_data = pbn_moxa_4, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134N), + .driver_data = pbn_moxa_4, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP138E_A), + .driver_data = pbn_moxa_8, + }, { + PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A), + .driver_data = pbn_moxa_8, + }, /* * ADDI-DATA GmbH communication cards */ - { 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_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_CPCI7500, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_4_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_4_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_2_115200 }, - - { PCI_VENDOR_ID_ADDIDATA, - PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - pbn_b0_1_115200 }, - - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, - PCI_VENDOR_ID_IBM, 0x0299, - 0, 0, pbn_b0_bt_2_115200 }, + { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7500), + .driver_data = pbn_b0_4_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7420), + .driver_data = pbn_b0_2_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7300), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE(AMCC, PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800), + .driver_data = pbn_b1_8_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7500_2), + .driver_data = pbn_b0_4_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7420_2), + .driver_data = pbn_b0_2_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7300_2), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7500_3), + .driver_data = pbn_b0_4_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7420_3), + .driver_data = pbn_b0_2_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7300_3), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCI7800_3), + .driver_data = pbn_b0_8_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCIe7500), + .driver_data = pbn_ADDIDATA_PCIe_4_3906250, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCIe7420), + .driver_data = pbn_ADDIDATA_PCIe_2_3906250, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCIe7300), + .driver_data = pbn_ADDIDATA_PCIe_1_3906250, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_APCIe7800), + .driver_data = pbn_ADDIDATA_PCIe_8_3906250, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_CPCI7500), + .driver_data = pbn_b0_4_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG), + .driver_data = pbn_b0_4_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG), + .driver_data = pbn_b0_2_115200, + }, { + PCI_VDEVICE(ADDIDATA, PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9835, + PCI_VENDOR_ID_IBM, 0x0299), + .driver_data = pbn_b0_bt_2_115200, + }, /* * other NetMos 9835 devices are most likely handled by the @@ -6101,157 +6081,183 @@ static const struct pci_device_id serial_pci_tbl[] = { * 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 }, - - { PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100, - 0xA000, 0x1000, - 0, 0, pbn_b0_1_115200 }, + { + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9901, + 0xA000, 0x1000), + .driver_data = pbn_b0_1_115200, + }, { + /* the 9901 is a rebranded 9912 */ + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9912, + 0xA000, 0x1000), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9922, + 0xA000, 0x1000), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9904, + 0xA000, 0x1000), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9900, + 0xA000, 0x1000), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9900, + 0xA000, 0x3002), + .driver_data = pbn_NETMOS9900_2s_115200, + }, { + PCI_DEVICE_SUB(PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100, + 0xA000, 0x1000), + .driver_data = pbn_b0_1_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 }, + { + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9865, + 0xA000, 0x1000), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9865, + 0xA000, 0x3002), + .driver_data = pbn_b0_bt_2_115200, + }, { + PCI_VDEVICE_SUB(NETMOS, PCI_DEVICE_ID_NETMOS_9865, + 0xA000, 0x3004), + .driver_data = pbn_b0_bt_4_115200, + }, /* * ASIX AX99100 PCIe to Multi I/O Controller */ - { PCI_VENDOR_ID_ASIX, PCI_DEVICE_ID_ASIX_AX99100, - 0xA000, 0x1000, - 0, 0, pbn_b0_1_115200 }, + { + PCI_VDEVICE_SUB(ASIX, PCI_DEVICE_ID_ASIX_AX99100, + 0xA000, 0x1000), + .driver_data = pbn_b0_1_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 }, + { + PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART), + .driver_data = 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 }, + { + PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA), + .driver_data = pbn_omegapci, + }, /* * Broadcom TruManage */ - { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_brcm_trumanage }, + { + PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE), + .driver_data = 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 }, + { + PCI_VDEVICE(AGESTAR, PCI_DEVICE_ID_AGESTAR_9375), + .driver_data = pbn_b0_bt_2_115200, + }, /* * WCH CH353 series devices: The 2S1P is handled by parport_serial * so not listed here. */ - { PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_4S, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, pbn_b0_bt_4_115200 }, + { + PCI_VDEVICE(WCHCN, PCI_DEVICE_ID_WCHCN_CH353_4S), + .driver_data = pbn_b0_bt_4_115200, + }, { + PCI_VDEVICE(WCHCN, PCI_DEVICE_ID_WCHCN_CH353_2S1PF), + .driver_data = pbn_b0_bt_2_115200, + }, { + PCI_VDEVICE(WCHCN, PCI_DEVICE_ID_WCHCN_CH355_4S), + .driver_data = pbn_b0_bt_4_115200, + }, { + PCI_VDEVICE(WCHIC, PCI_DEVICE_ID_WCHIC_CH382_2S), + .driver_data = pbn_wch382_2, + }, { + PCI_VDEVICE(WCHIC, PCI_DEVICE_ID_WCHIC_CH384_4S), + .driver_data = pbn_wch384_4, + }, { + PCI_VDEVICE(WCHIC, PCI_DEVICE_ID_WCHIC_CH384_8S), + .driver_data = pbn_wch384_8, + }, - { PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_2S1PF, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, pbn_b0_bt_2_115200 }, - - { PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH355_4S, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, pbn_b0_bt_4_115200 }, - - { PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH382_2S, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, pbn_wch382_2 }, - - { PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_4S, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, pbn_wch384_4 }, - - { PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_8S, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, pbn_wch384_8 }, /* * Realtek RealManage */ - { PCI_VENDOR_ID_REALTEK, 0x816a, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, pbn_b0_1_115200 }, - - { PCI_VENDOR_ID_REALTEK, 0x816b, - PCI_ANY_ID, PCI_ANY_ID, - 0, 0, pbn_b0_1_115200 }, + { + PCI_VDEVICE(REALTEK, 0x816a), + .driver_data = pbn_b0_1_115200, + }, { + PCI_VDEVICE(REALTEK, 0x816b), + .driver_data = pbn_b0_1_115200, + }, /* Systembase Multi I/O cards */ - { PCI_VDEVICE(SYSTEMBASE, 0x0008), pbn_b0_8_921600 }, + { + PCI_VDEVICE(SYSTEMBASE, 0x0008), + .driver_data = pbn_b0_8_921600, + }, /* 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 }, + { + 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 }, + { + 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 }, + { + 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, } + { + PCI_DEVICE_CLASS(PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00), + .driver_data = pbn_default, + }, { + PCI_DEVICE_CLASS(PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00), + .driver_data = pbn_default, + }, { + PCI_DEVICE_CLASS(PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00), + .driver_data = pbn_default, + }, + { } }; static pci_ers_result_t serial8250_io_error_detected(struct pci_dev *dev, From 88af183a135ccdd004bdeebf4e0c99383b530a66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 5 May 2026 10:47:49 +0200 Subject: [PATCH 08/49] serial: jsm: Drop unused driver_data assigment and redundant zeros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver doesn't use the driver_data field, so drop the assigment together with the then redundant zero assigment for .class and .class_mask. Also drop the zero in the list terminator. While at it also use PCI_VDEVICE() to allow dropping "PCI_VENDOR_ID_". Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/20260505084749.2304121-2-u.kleine-koenig@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm_driver.c | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 4b73e51f83fb..8cd9b981bf20 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -296,25 +296,25 @@ static void jsm_remove_one(struct pci_dev *pdev) } static const struct pci_device_id jsm_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_4), 0, 0, 6 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422), 0, 0, 7 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422_485), 0, 0, 8 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2_422_485), 0, 0, 9 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8), 0, 0, 10 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4), 0, 0, 11 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4RJ45), 0, 0, 12 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8RJ45), 0, 0, 13 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4), 0, 0, 14 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4_422), 0, 0, 15 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8), 0, 0, 16 }, - { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8_422), 0, 0, 17 }, - { 0, } + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2DB9) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2DB9PRI) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2RJ45) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI) }, + { PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_4_IBM) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_NEO_8) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_4) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_1_422) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_1_422_485) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2_422_485) }, + { PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_8) }, + { PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_4) }, + { PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_4RJ45) }, + { PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_8RJ45) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_CLASSIC_4) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_CLASSIC_4_422) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_CLASSIC_8) }, + { PCI_VDEVICE(DIGI, PCI_DEVICE_ID_CLASSIC_8_422) }, + { } }; MODULE_DEVICE_TABLE(pci, jsm_pci_tbl); From 430a1386df5c98e65f6b943c15366e4ca92e3328 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 6 May 2026 14:46:43 +0200 Subject: [PATCH 09/49] serial: sh-sci: Remove plat_sci_port.flags The last setter of p->flags was removed in commit 37744feebc086908 ("sh: remove sh5 support") in v5.8. Link: https://lore.kernel.org/CAMuHMdXs94k3-7YD-yO7p2=+u8waYGAz8mpP5LDbMf3szt4V-w@mail.gmail.com Signed-off-by: Geert Uytterhoeven Reviewed-by: John Ogness Reviewed-by: Lad Prabhakar Link: https://patch.msgid.link/20260506124643.128021-1-geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 2 +- include/linux/serial_sci.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 6c819b6b2425..a35230d57540 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3369,7 +3369,7 @@ static int sci_init_single(struct platform_device *dev, } port->type = SCI_PUBLIC_PORT_ID(p->type); - port->flags = UPF_FIXED_PORT | UPF_BOOT_AUTOCONF | p->flags; + port->flags = UPF_FIXED_PORT | UPF_BOOT_AUTOCONF; port->fifosize = sci_port->params->fifosize; if (p->type == PORT_SCI && !dev->dev.of_node) { diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index 0f2f50b8d28e..36c795d61f7e 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -51,7 +51,6 @@ struct plat_sci_port_ops { */ struct plat_sci_port { unsigned int type; /* SCI / SCIF / IRDA / HSCIF */ - upf_t flags; /* UPF_* flags */ unsigned int sampling_rate; unsigned int scscr; /* SCSCR initialization */ From 9c7eb1c9c3e3bfecb556fc8fa1b68939385444de Mon Sep 17 00:00:00 2001 From: John Ogness Date: Wed, 6 May 2026 14:21:56 +0206 Subject: [PATCH 10/49] serial: core: Add dedicated uart_port field for console flow Currently the UPF_CONS_FLOW bit in the uart_port.flags field is used by serial console drivers to identify if a user has configured flow control on the console. Usually this policy is setup during early boot, but can be changed at runtime. The bits in uart_port.flags are either hardware and driver properties that are initialized before usage or are properties that can be changed via the tty layer. The UPF_CONS_FLOW bit is an exception because it is a console-only policy that can change at runtime and its setting and usage have nothing to do with the tty layer. This actually causes a problem for its usage because uart_port.flags is synchronized by a related tty_port.mutex, but a console has no relation to a tty (other than sharing the port). This is probably why console flow control is not properly available for most serial drivers. And it is hindering being able to provide a proper implementation. Commit d01f4d181c92 ("serial: core: Privatize tty->hw_stopped") addressed a similar issue to deal with software assisted CTS flow state tracking. Add a new uart_port boolean field "cons_flow" to store the user configuration for console flow control. Add getter/setter wrappers to allow for adding more policies later and/or locking constraint validation. Mark UPF_CONS_FLOW as deprecated. Signed-off-by: John Ogness Link: https://patch.msgid.link/20260506121606.5805-2-john.ogness@linutronix.de Signed-off-by: Greg Kroah-Hartman --- include/linux/serial_core.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 666430b47899..4f7bbdd90017 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -533,6 +533,7 @@ struct uart_port { #define UPF_HARD_FLOW ((__force upf_t) (UPF_AUTO_CTS | UPF_AUTO_RTS)) /* Port has hardware-assisted s/w flow control */ #define UPF_SOFT_FLOW ((__force upf_t) BIT_ULL(22)) +/* Deprecated: use uart_set_cons_flow_enabled()/uart_cons_flow_enabled() instead. */ #define UPF_CONS_FLOW ((__force upf_t) BIT_ULL(23)) #define UPF_SHARE_IRQ ((__force upf_t) BIT_ULL(24)) #define UPF_EXAR_EFR ((__force upf_t) BIT_ULL(25)) @@ -567,6 +568,7 @@ struct uart_port { #define UPSTAT_SYNC_FIFO ((__force upstat_t) (1 << 5)) bool hw_stopped; /* sw-assisted CTS flow state */ + bool cons_flow; /* user specified console flow control */ unsigned int mctrl; /* current modem ctrl settings */ unsigned int frame_time; /* frame timing in ns */ unsigned int type; /* port type */ @@ -1163,6 +1165,16 @@ static inline bool uart_softcts_mode(struct uart_port *uport) return ((uport->status & mask) == UPSTAT_CTS_ENABLE); } +static inline void uart_set_cons_flow_enabled(struct uart_port *uport, bool enabled) +{ + uport->cons_flow = enabled; +} + +static inline bool uart_cons_flow_enabled(const struct uart_port *uport) +{ + return uport->cons_flow; +} + /* * The following are helper functions for the low level drivers. */ From bf558715d91cfa28f283de7105a879a92da31fb7 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Wed, 6 May 2026 14:21:57 +0206 Subject: [PATCH 11/49] serial: Replace driver usage of UPF_CONS_FLOW Rather than using the UPF_CONS_FLOW bit of uart_port.flags to track the user configuration of console flow control, use the newly added uart_port.cons_flow (via its getter/setter functions). A coccinelle script was used to perform the search/replace. Note1: The sh-sci driver is blindly copying platform data configuration flags to uart_port.flags. Thus UPF_CONS_FLOW could get set for uart_port.flags. A follow-up commit will address this. Note2: The samsung_tty driver is using UPF_CONS_FLOW as a platform data configuration flag. However, the driver explicitly checks for this configuration flag and thus setting UPF_CONS_FLOW in uart_port.flags is avoided. Signed-off-by: John Ogness Link: https://patch.msgid.link/20260506121606.5805-3-john.ogness@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 4 ++-- drivers/tty/serial/bcm63xx_uart.c | 2 +- drivers/tty/serial/omap-serial.c | 2 +- drivers/tty/serial/pch_uart.c | 2 +- drivers/tty/serial/pxa.c | 2 +- drivers/tty/serial/samsung_tty.c | 8 ++++---- drivers/tty/serial/serial_txx9.c | 4 ++-- drivers/tty/serial/sunsu.c | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 02e6cdefdbac..e4e6a53ebea3 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1990,7 +1990,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) wait_for_lsr(up, bits); /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { + if (uart_cons_flow_enabled(&up->port)) { for (tmout = 1000000; tmout; tmout--) { unsigned int msr = serial_in(up, UART_MSR); up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; @@ -3353,7 +3353,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, * it regardless of the CTS state. Therefore, only use fifo * if we don't use control flow. */ - !(up->port.flags & UPF_CONS_FLOW); + !uart_cons_flow_enabled(&up->port); if (likely(use_fifo)) serial8250_console_fifo_write(up, s, count); diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 51df9d2d8bfc..544695cb184c 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -675,7 +675,7 @@ static void wait_for_xmitr(struct uart_port *port) } /* Wait up to 1s for flow control if necessary */ - if (port->flags & UPF_CONS_FLOW) { + if (uart_cons_flow_enabled(port)) { tmout = 1000000; while (--tmout) { unsigned int val; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 0b85f47ff19e..a689d190940c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1092,7 +1092,7 @@ static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up) } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { + if (uart_cons_flow_enabled(&up->port)) { for (tmout = 1000000; tmout; tmout--) { unsigned int msr = serial_in(up, UART_MSR); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 6729d8e83c3c..2f72cd62e248 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1444,7 +1444,7 @@ static void wait_for_xmitr(struct eg20t_port *up, int bits) } /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { + if (uart_cons_flow_enabled(&up->port)) { unsigned int tmout; for (tmout = 1000000; tmout; tmout--) { unsigned int msr = ioread8(up->membase + UART_MSR); diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index fea0255067cc..10fc8990579b 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -573,7 +573,7 @@ static void wait_for_xmitr(struct uart_pxa_port *up) } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { + if (uart_cons_flow_enabled(&up->port)) { tmout = 1000000; while (--tmout && ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index e27806bf2cf3..2f94fc798cff 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -319,7 +319,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) ourport->tx_enabled = 0; ourport->tx_in_progress = 0; - if (port->flags & UPF_CONS_FLOW) + if (uart_cons_flow_enabled(port)) s3c24xx_serial_rx_enable(port); ourport->tx_mode = 0; @@ -493,7 +493,7 @@ static void s3c24xx_serial_start_tx(struct uart_port *port) struct tty_port *tport = &port->state->port; if (!ourport->tx_enabled) { - if (port->flags & UPF_CONS_FLOW) + if (uart_cons_flow_enabled(port)) s3c24xx_serial_rx_disable(port); ourport->tx_enabled = 1; @@ -781,7 +781,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) uerstat = rd_regl(port, S3C2410_UERSTAT); ch = rd_reg(port, S3C2410_URXH); - if (port->flags & UPF_CONS_FLOW) { + if (uart_cons_flow_enabled(port)) { bool txe = s3c24xx_serial_txempty_nofifo(port); if (ourport->rx_enabled) { @@ -1830,7 +1830,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, if (cfg->uart_flags & UPF_CONS_FLOW) { dev_dbg(port->dev, "enabling flow control\n"); - port->flags |= UPF_CONS_FLOW; + uart_set_cons_flow_enabled(port, true); } /* sort our the physical and virtual addresses for each UART */ diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 436a559234df..4ae9a45c8e3a 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -422,7 +422,7 @@ static void wait_for_xmitr(struct uart_port *up) udelay(1); /* Wait up to 1s for flow control if necessary */ - if (up->flags & UPF_CONS_FLOW) { + if (uart_cons_flow_enabled(up)) { tmout = 1000000; while (--tmout && (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS)) @@ -857,7 +857,7 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count) * Disable flow-control if enabled (and unnecessary) */ flcr = sio_in(up, TXX9_SIFLCR); - if (!(up->flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES)) + if (!uart_cons_flow_enabled(up) && (flcr & TXX9_SIFLCR_TES)) sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES); uart_console_write(up, s, count, serial_txx9_console_putchar); diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 6505a1930da9..4ff3e5c41dab 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -1245,7 +1245,7 @@ static void wait_for_xmitr(struct uart_sunsu_port *up) } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { + if (uart_cons_flow_enabled(&up->port)) { tmout = 1000000; while (--tmout && ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) From 6d7f4890bbb6fc8b70f618aa0407043b32bc738a Mon Sep 17 00:00:00 2001 From: Jia Wang Date: Wed, 29 Apr 2026 17:13:25 +0800 Subject: [PATCH 12/49] serial: 8250_dwlib: move DesignWare register definitions to header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the DW_UART_* register offsets and CPR bit/field definitions from 8250_dwlib.c into 8250_dwlib.h so they can be shared by 8250_dw and 8250_dwlib users. Add an include guard for 8250_dwlib.h. Signed-off-by: Jia Wang Reviewed-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20260429-ultrarisc-serial-v7-1-e475cce9e274@ultrarisc.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 11 ----- drivers/tty/serial/8250/8250_dwlib.c | 49 -------------------- drivers/tty/serial/8250/8250_dwlib.h | 67 ++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 60 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 94beadb4024d..467755bf0092 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -34,22 +34,11 @@ #include "8250_dwlib.h" -/* Offsets for the DesignWare specific registers */ -#define DW_UART_USR 0x1f /* UART Status Register */ -#define DW_UART_DMASA 0xa8 /* DMA Software Ack */ - #define OCTEON_UART_USR 0x27 /* UART Status Register */ #define RZN1_UART_TDMACR 0x10c /* DMA Control Register Transmit Mode */ #define RZN1_UART_RDMACR 0x110 /* DMA Control Register Receive Mode */ -/* DesignWare specific register fields */ -#define DW_UART_IIR_IID GENMASK(3, 0) - -#define DW_UART_MCR_SIRE BIT(6) - -#define DW_UART_USR_BUSY BIT(0) - /* Renesas specific register fields */ #define RZN1_UART_xDMACR_DMA_EN BIT(0) #define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1) diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c index b055d89cfb39..8859e66d2d71 100644 --- a/drivers/tty/serial/8250/8250_dwlib.c +++ b/drivers/tty/serial/8250/8250_dwlib.c @@ -13,55 +13,6 @@ #include "8250_dwlib.h" -/* Offsets for the DesignWare specific registers */ -#define DW_UART_TCR 0xac /* Transceiver Control Register (RS485) */ -#define DW_UART_DE_EN 0xb0 /* Driver Output Enable Register */ -#define DW_UART_RE_EN 0xb4 /* Receiver Output Enable Register */ -#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ -#define DW_UART_RAR 0xc4 /* Receive Address Register */ -#define DW_UART_TAR 0xc8 /* Transmit Address Register */ -#define DW_UART_LCR_EXT 0xcc /* Line Extended Control Register */ -#define DW_UART_CPR 0xf4 /* Component Parameter Register */ -#define DW_UART_UCV 0xf8 /* UART Component Version */ - -/* Receive / Transmit Address Register bits */ -#define DW_UART_ADDR_MASK GENMASK(7, 0) - -/* Line Status Register bits */ -#define DW_UART_LSR_ADDR_RCVD BIT(8) - -/* Transceiver Control Register bits */ -#define DW_UART_TCR_RS485_EN BIT(0) -#define DW_UART_TCR_RE_POL BIT(1) -#define DW_UART_TCR_DE_POL BIT(2) -#define DW_UART_TCR_XFER_MODE GENMASK(4, 3) -#define DW_UART_TCR_XFER_MODE_DE_DURING_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 0) -#define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 1) -#define DW_UART_TCR_XFER_MODE_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 2) - -/* Line Extended Control Register bits */ -#define DW_UART_LCR_EXT_DLS_E BIT(0) -#define DW_UART_LCR_EXT_ADDR_MATCH BIT(1) -#define DW_UART_LCR_EXT_SEND_ADDR BIT(2) -#define DW_UART_LCR_EXT_TRANSMIT_MODE BIT(3) - -/* Component Parameter Register bits */ -#define DW_UART_CPR_ABP_DATA_WIDTH GENMASK(1, 0) -#define DW_UART_CPR_AFCE_MODE BIT(4) -#define DW_UART_CPR_THRE_MODE BIT(5) -#define DW_UART_CPR_SIR_MODE BIT(6) -#define DW_UART_CPR_SIR_LP_MODE BIT(7) -#define DW_UART_CPR_ADDITIONAL_FEATURES BIT(8) -#define DW_UART_CPR_FIFO_ACCESS BIT(9) -#define DW_UART_CPR_FIFO_STAT BIT(10) -#define DW_UART_CPR_SHADOW BIT(11) -#define DW_UART_CPR_ENCODED_PARMS BIT(12) -#define DW_UART_CPR_DMA_EXTRA BIT(13) -#define DW_UART_CPR_FIFO_MODE GENMASK(23, 16) - -/* Helper for FIFO size calculation */ -#define DW_UART_CPR_FIFO_SIZE(a) (FIELD_GET(DW_UART_CPR_FIFO_MODE, (a)) * 16) - /* * divisor = div(I) + div(F) * "I" means integer, "F" means fractional diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h index 7dd2a8e7b780..2f26f9ecacbe 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -1,11 +1,76 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* Synopsys DesignWare 8250 library header file. */ +#ifndef _SERIAL_8250_DWLIB_H_ +#define _SERIAL_8250_DWLIB_H_ + +#include +#include #include #include #include "8250.h" +/* Offsets for the DesignWare specific registers */ +#define DW_UART_USR 0x1f /* UART Status Register */ +#define DW_UART_DMASA 0xa8 /* DMA Software Ack */ +#define DW_UART_TCR 0xac /* Transceiver Control Register (RS485) */ +#define DW_UART_DE_EN 0xb0 /* Driver Output Enable Register */ +#define DW_UART_RE_EN 0xb4 /* Receiver Output Enable Register */ +#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ +#define DW_UART_RAR 0xc4 /* Receive Address Register */ +#define DW_UART_TAR 0xc8 /* Transmit Address Register */ +#define DW_UART_LCR_EXT 0xcc /* Line Extended Control Register */ +#define DW_UART_CPR 0xf4 /* Component Parameter Register */ +#define DW_UART_UCV 0xf8 /* UART Component Version */ + +/* Interrupt ID Register bits */ +#define DW_UART_IIR_IID GENMASK(3, 0) + +/* Modem Control Register bits */ +#define DW_UART_MCR_SIRE BIT(6) + +/* Line Status Register bits */ +#define DW_UART_LSR_ADDR_RCVD BIT(8) + +/* UART Status Register bits */ +#define DW_UART_USR_BUSY BIT(0) + +/* Transceiver Control Register bits */ +#define DW_UART_TCR_RS485_EN BIT(0) +#define DW_UART_TCR_RE_POL BIT(1) +#define DW_UART_TCR_DE_POL BIT(2) +#define DW_UART_TCR_XFER_MODE GENMASK(4, 3) +#define DW_UART_TCR_XFER_MODE_DE_DURING_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 0) +#define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 1) +#define DW_UART_TCR_XFER_MODE_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 2) + +/* Receive / Transmit Address Register bits */ +#define DW_UART_ADDR_MASK GENMASK(7, 0) + +/* Line Extended Control Register bits */ +#define DW_UART_LCR_EXT_DLS_E BIT(0) +#define DW_UART_LCR_EXT_ADDR_MATCH BIT(1) +#define DW_UART_LCR_EXT_SEND_ADDR BIT(2) +#define DW_UART_LCR_EXT_TRANSMIT_MODE BIT(3) + +/* Component Parameter Register bits */ +#define DW_UART_CPR_ABP_DATA_WIDTH GENMASK(1, 0) +#define DW_UART_CPR_AFCE_MODE BIT(4) +#define DW_UART_CPR_THRE_MODE BIT(5) +#define DW_UART_CPR_SIR_MODE BIT(6) +#define DW_UART_CPR_SIR_LP_MODE BIT(7) +#define DW_UART_CPR_ADDITIONAL_FEATURES BIT(8) +#define DW_UART_CPR_FIFO_ACCESS BIT(9) +#define DW_UART_CPR_FIFO_STAT BIT(10) +#define DW_UART_CPR_SHADOW BIT(11) +#define DW_UART_CPR_ENCODED_PARMS BIT(12) +#define DW_UART_CPR_DMA_EXTRA BIT(13) +#define DW_UART_CPR_FIFO_MODE GENMASK(23, 16) + +/* Helper for FIFO size calculation */ +#define DW_UART_CPR_FIFO_SIZE(a) (FIELD_GET(DW_UART_CPR_FIFO_MODE, (a)) * 16) + struct dw8250_port_data { /* Port properties */ int line; @@ -38,3 +103,5 @@ static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) else writel(reg, p->membase + offset); } + +#endif /* _SERIAL_8250_DWLIB_H_ */ From 07bb8459c443b840c55293cee1c726431dd749cf Mon Sep 17 00:00:00 2001 From: Jia Wang Date: Wed, 29 Apr 2026 17:13:26 +0800 Subject: [PATCH 13/49] serial: 8250_dw: build Renesas RZN1 CPR value from DW_UART_CPR_* definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the magic CPR value for Renesas RZ/N1 with a composition using DW_UART_CPR_* bit/field definitions and FIELD_PREP_CONST(). Introduce a helper macro to convert a FIFO size (bytes) into the CPR FIFO_MODE field value, with BUILD_BUG_ON_ZERO() checks for alignment and bounds. Use it to replace the literal FIFO_MODE values in the RZN1. Signed-off-by: Jia Wang Reviewed-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20260429-ultrarisc-serial-v7-2-e475cce9e274@ultrarisc.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 10 +++++++++- drivers/tty/serial/8250/8250_dwlib.h | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 467755bf0092..480f82d89856 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -937,7 +937,15 @@ static const struct dw8250_platform_data dw8250_armada_38x_data = { static const struct dw8250_platform_data dw8250_renesas_rzn1_data = { .usr_reg = DW_UART_USR, - .cpr_value = 0x00012f32, + .cpr_value = FIELD_PREP_CONST(DW_UART_CPR_ABP_DATA_WIDTH, 2) | + DW_UART_CPR_AFCE_MODE | + DW_UART_CPR_THRE_MODE | + DW_UART_CPR_ADDITIONAL_FEATURES | + DW_UART_CPR_FIFO_ACCESS | + DW_UART_CPR_FIFO_STAT | + DW_UART_CPR_SHADOW | + DW_UART_CPR_DMA_EXTRA | + DW_UART_CPR_FIFO_MODE_FROM_SIZE(16), .quirks = DW_UART_QUIRK_CPR_VALUE | DW_UART_QUIRK_IS_DMA_FC, }; diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h index 2f26f9ecacbe..1fe52332e774 100644 --- a/drivers/tty/serial/8250/8250_dwlib.h +++ b/drivers/tty/serial/8250/8250_dwlib.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -68,8 +69,13 @@ #define DW_UART_CPR_DMA_EXTRA BIT(13) #define DW_UART_CPR_FIFO_MODE GENMASK(23, 16) -/* Helper for FIFO size calculation */ +/* Helpers for FIFO size calculation */ #define DW_UART_CPR_FIFO_SIZE(a) (FIELD_GET(DW_UART_CPR_FIFO_MODE, (a)) * 16) +#define DW_UART_CPR_FIFO_MODE_FROM_SIZE(size) \ + (FIELD_PREP_CONST(DW_UART_CPR_FIFO_MODE, \ + BUILD_BUG_ON_ZERO((size) > 2048) + \ + BUILD_BUG_ON_ZERO((size) % 16) + \ + ((size) / 16))) struct dw8250_port_data { /* Port properties */ From d22d2e54f660eeb64e06f2cb6db068dac66a5733 Mon Sep 17 00:00:00 2001 From: Jia Wang Date: Wed, 29 Apr 2026 17:13:27 +0800 Subject: [PATCH 14/49] dt-bindings: serial: snps-dw-apb-uart: Add UltraRISC DP1000 UART UltraRISC DP1000 integrates a Synopsys DesignWare APB UART, but it does not provide the standard CPR and UCV registers. Signed-off-by: Jia Wang Acked-by: Conor Dooley Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20260429-ultrarisc-serial-v7-3-e475cce9e274@ultrarisc.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml index 685c1eceb782..49f51b002879 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -78,6 +78,7 @@ properties: - starfive,jh7100-hsuart - starfive,jh7100-uart - starfive,jh7110-uart + - ultrarisc,dp1000-uart - const: snps,dw-apb-uart - const: snps,dw-apb-uart From 4a9a0b1a82a8b23eb68032dd19b120e82cd67004 Mon Sep 17 00:00:00 2001 From: Jia Wang Date: Wed, 29 Apr 2026 17:13:28 +0800 Subject: [PATCH 15/49] serial: 8250_dw: Use a fixed CPR value for UltraRISC DP1000 UART MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The UltraRISC DP1000 UART does not provide the standard CPR register used by 8250_dw to discover port capabilities. Provide a fixed CPR value for the DP1000-specific compatible so the driver can configure the port correctly. Signed-off-by: Jia Wang Reviewed-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20260429-ultrarisc-serial-v7-4-e475cce9e274@ultrarisc.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 480f82d89856..55e40c10f46a 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -959,6 +959,15 @@ static const struct dw8250_platform_data dw8250_intc10ee = { .quirks = DW_UART_QUIRK_IER_KICK, }; +static const struct dw8250_platform_data dw8250_ultrarisc_dp1000_data = { + .usr_reg = DW_UART_USR, + .cpr_value = FIELD_PREP_CONST(DW_UART_CPR_ABP_DATA_WIDTH, 2) | + DW_UART_CPR_THRE_MODE | + DW_UART_CPR_DMA_EXTRA | + DW_UART_CPR_FIFO_MODE_FROM_SIZE(32), + .quirks = DW_UART_QUIRK_CPR_VALUE, +}; + static const struct of_device_id dw8250_of_match[] = { { .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb }, { .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data }, @@ -966,6 +975,7 @@ static const struct of_device_id dw8250_of_match[] = { { .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data }, { .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data }, { .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data }, + { .compatible = "ultrarisc,dp1000-uart", .data = &dw8250_ultrarisc_dp1000_data }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dw8250_of_match); From ba48a6b91f54ad4ad1b9b8ed5878ee17a18e0f38 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 10 Apr 2026 11:20:09 -0400 Subject: [PATCH 16/49] serial: icom: remove check for zero baud rate from uart_get_baud_rate() The minimum baud rate supported by this driver is 300, so even for the B0 case, uart_get_baud_rate() will return 9600, not zero. This check predates commit 16ae2a877bf4 ("serial: Fix crash if the minimum rate of the device is > 9600 baud") and is no longer necessary so remove it. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260410152022.2146488-2-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/icom.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index bcdc07208486..b6399d86a0bc 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -1396,8 +1396,6 @@ static void icom_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old_termios, icom_acfg_baud[0], icom_acfg_baud[BAUD_TABLE_LIMIT]); - if (!baud) - baud = 9600; /* B0 transition handled in rs_set_termios */ for (index = 0; index < BAUD_TABLE_LIMIT; index++) { if (icom_acfg_baud[index] == baud) { From 888b245964ad3617866d6d4b5bb8a154a410ef32 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 10 Apr 2026 11:20:10 -0400 Subject: [PATCH 17/49] serial: apbuart: remove check for zero baud rate from uart_get_baud_rate() The minimum baud rate supported by this driver is 0, so even for the B0 case, uart_get_baud_rate() will return 9600, not zero. This check predates commit 16ae2a877bf4 ("serial: Fix crash if the minimum rate of the device is > 9600 baud") and is no longer necessary so remove it. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260410152022.2146488-3-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/apbuart.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 3e46341cfff8..afb04d727203 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -210,8 +210,6 @@ static void apbuart_set_termios(struct uart_port *port, /* Ask the core to calculate the divisor for us. */ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - if (baud == 0) - panic("invalid baudrate %i\n", port->uartclk / 16); /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */ quot = (uart_get_divisor(port, baud)) * 2; From 2f0c8853109bca54ac28e33659ce600ceb45ff12 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 10 Apr 2026 11:20:11 -0400 Subject: [PATCH 18/49] serial: core: update uart_get_baud_rate() obsolete comments Update obsolete comments to match the actual code. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260410152022.2146488-4-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 89cebdd27841..e6a8ab40442d 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -465,7 +465,8 @@ EXPORT_SYMBOL(uart_update_timeout); * baud. * * If the new baud rate is invalid, try the @old termios setting. If it's still - * invalid, we try 9600 baud. If that is also invalid 0 is returned. + * invalid, clip to the nearest chip supported rate. + * If that is also invalid 0 is returned. * * The @termios structure is updated to reflect the baud rate we're actually * going to be using. Don't do this for the case where B0 is requested ("hang @@ -523,7 +524,7 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, return baud; /* - * Oops, the quotient was zero. Try again with + * If the range cannot be met then try again with * the old baud rate if possible. */ termios->c_cflag &= ~CBAUD; From 1097aedec77674fe4f08f40b3f0bac26ea437fc0 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 10 Apr 2026 11:20:12 -0400 Subject: [PATCH 19/49] serial: core: simplify clipping logic in uart_get_baud_rate() Simplify the clipping logic in uart_get_baud_rate() to improve code readability. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260410152022.2146488-5-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index e6a8ab40442d..f89c0dc29516 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -543,11 +543,11 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, */ if (!hung_up) { if (baud <= min) - tty_termios_encode_baud_rate(termios, - min + 1, min + 1); + baud = min + 1; else - tty_termios_encode_baud_rate(termios, - max - 1, max - 1); + baud = max - 1; + + tty_termios_encode_baud_rate(termios, baud, baud); } } return 0; From 091ea8e5d34e1dca5d8f30127173b949e3f803ce Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 10 Apr 2026 11:20:13 -0400 Subject: [PATCH 20/49] serial: core: prevent division by zero by always returning non-zero baud rate If a device has a minimum baud rate > 9600 bauds, and a new termios baud rate of 0 (hang up) is requested, uart_get_baud_rate() will return 0. Most drivers do not check this return value and call uart_update_timeout() with this zero baud rate, which will trigger a "Division by zero in kernel" fault: stty -F /dev/ttySC0 0 Division by zero in kernel. ... Fix by returning the larger of 9600 or min for the B0 case. This now ensures that a non-zero baud rate is returned, and greatly simplifies the code. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260410152022.2146488-6-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f89c0dc29516..075a69164aa7 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -462,11 +462,10 @@ EXPORT_SYMBOL(uart_update_timeout); * * Decode the termios structure into a numeric baud rate, taking account of the * magic 38400 baud rate (with spd_* flags), and mapping the %B0 rate to 9600 - * baud. + * baud or min argument, whichever is greater. * * If the new baud rate is invalid, try the @old termios setting. If it's still * invalid, clip to the nearest chip supported rate. - * If that is also invalid 0 is returned. * * The @termios structure is updated to reflect the baud rate we're actually * going to be using. Don't do this for the case where B0 is requested ("hang @@ -481,7 +480,6 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, unsigned int try; unsigned int baud; unsigned int altbaud; - int hung_up = 0; upf_t flags = port->flags & UPF_SPD_MASK; switch (flags) { @@ -515,10 +513,8 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, /* * Special case: B0 rate. */ - if (baud == 0) { - hung_up = 1; - baud = 9600; - } + if (baud == 0) + return max(min, 9600); if (baud >= min && baud <= max) return baud; @@ -530,9 +526,7 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, termios->c_cflag &= ~CBAUD; if (old) { baud = tty_termios_baud_rate(old); - if (!hung_up) - tty_termios_encode_baud_rate(termios, - baud, baud); + tty_termios_encode_baud_rate(termios, baud, baud); old = NULL; continue; } @@ -541,15 +535,16 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, * As a last resort, if the range cannot be met then clip to * the nearest chip supported rate. */ - if (!hung_up) { - if (baud <= min) - baud = min + 1; - else - baud = max - 1; + if (baud <= min) + baud = min + 1; + else + baud = max - 1; - tty_termios_encode_baud_rate(termios, baud, baud); - } + tty_termios_encode_baud_rate(termios, baud, baud); } + + /* Should never happen */ + WARN_ON(1); return 0; } EXPORT_SYMBOL(uart_get_baud_rate); From 0dcaf1c6b20546661ed14d9b1e3e9c252a0df9f7 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:28 -0400 Subject: [PATCH 21/49] serial: max310x: uniformize clock/freq types max310x_set_ref_clk() returns a 32-bits clock value, so there is no need to have parameters and intermediate values defined as long. Change clock and freq types to int. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-1-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ac7d3f197c3a..7c1c3696f568 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -545,7 +545,7 @@ static int max310x_set_baud(struct uart_port *port, int baud) return (16*port->uartclk) / (c*(16*div + frac)); } -static int max310x_update_best_err(unsigned long f, long *besterr) +static int max310x_update_best_err(unsigned int f, long *besterr) { /* Use baudrate 115200 for calculate error */ long err = f % (460800 * 16); @@ -559,11 +559,11 @@ static int max310x_update_best_err(unsigned long f, long *besterr) } static s32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, - unsigned long freq, bool xtal) + unsigned int freq, bool xtal) { unsigned int div, clksrc, pllcfg = 0; long besterr = -1; - unsigned long fdiv, fmul, bestfreq = freq; + unsigned int fdiv, fmul, bestfreq = freq; /* First, update error without PLL */ max310x_update_best_err(freq, &besterr); @@ -1268,7 +1268,8 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty const struct max310x_if_cfg *if_cfg, struct regmap *regmaps[], int irq) { - int i, ret, fmin, fmax, freq; + unsigned int fmin, fmax, freq; + int i, ret; struct max310x_port *s; s32 uartclk = 0; bool xtal; From db3c618405d2a4ac870915b8438ff17be93b5f16 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:29 -0400 Subject: [PATCH 22/49] serial: max310x: simplify max310x_update_best_err() besterr was defined as a signed type was to make sure that the first call to max310x_update_best_err() would always set besterr. Also there is no need for it to be a long. By changing its type to unsigned int and initial value to UINT_MAX, max310x_update_best_err() can be simplified and be more efficient while achieving the same initial result. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-2-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 7c1c3696f568..b68a17ebd10b 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -545,12 +545,12 @@ static int max310x_set_baud(struct uart_port *port, int baud) return (16*port->uartclk) / (c*(16*div + frac)); } -static int max310x_update_best_err(unsigned int f, long *besterr) +static int max310x_update_best_err(unsigned int f, unsigned int *besterr) { /* Use baudrate 115200 for calculate error */ - long err = f % (460800 * 16); + unsigned int err = f % (460800 * 16); - if ((*besterr < 0) || (*besterr > err)) { + if (*besterr > err) { *besterr = err; return 0; } @@ -562,7 +562,7 @@ static s32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, unsigned int freq, bool xtal) { unsigned int div, clksrc, pllcfg = 0; - long besterr = -1; + unsigned int besterr = UINT_MAX; unsigned int fdiv, fmul, bestfreq = freq; /* First, update error without PLL */ From df1490942a41f26aaea9ca487299c26286327603 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:30 -0400 Subject: [PATCH 23/49] serial: max310x: change return type of max310x_set_ref_clk() Having max310x_set_ref_clk() return an s32 as both an error code and a frequency value is ambiguous. Fix by passing a pointer to the frequency value that will then be updated, and simply return a status. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-3-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index b68a17ebd10b..cf27e597ea41 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -558,8 +558,8 @@ static int max310x_update_best_err(unsigned int f, unsigned int *besterr) return 1; } -static s32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, - unsigned int freq, bool xtal) +static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, + unsigned int freq, unsigned int *fref, bool xtal) { unsigned int div, clksrc, pllcfg = 0; unsigned int besterr = UINT_MAX; @@ -632,7 +632,9 @@ static s32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, "clock is not stable\n"); } - return bestfreq; + *fref = bestfreq; + + return 0; } static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) @@ -1271,7 +1273,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty unsigned int fmin, fmax, freq; int i, ret; struct max310x_port *s; - s32 uartclk = 0; + unsigned int uartclk = 0; bool xtal; for (i = 0; i < devtype->nr; i++) @@ -1357,11 +1359,9 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1); } - uartclk = max310x_set_ref_clk(dev, s, freq, xtal); - if (uartclk < 0) { - ret = uartclk; + ret = max310x_set_ref_clk(dev, s, freq, &uartclk, xtal); + if (ret < 0) goto out_uart; - } dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); From ffc3414d15c615bc0a46536343f917d8a5f14655 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:31 -0400 Subject: [PATCH 24/49] serial: max310x: update baudrate comments for err calculation The baudrate used to compute the best error was changed from 115200 to 460800 in commit 35240ba26a93 ("tty: max310x: Fix invalid baudrate divisors calculator"), but the comment was not updated, so fix it. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-4-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index cf27e597ea41..f689958736f7 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -547,7 +547,7 @@ static int max310x_set_baud(struct uart_port *port, int baud) static int max310x_update_best_err(unsigned int f, unsigned int *besterr) { - /* Use baudrate 115200 for calculate error */ + /* Use high-enough baudrate to calculate error */ unsigned int err = f % (460800 * 16); if (*besterr > err) { From d0001adcd1f838d97bc23a20375f60bb3304aa5c Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:32 -0400 Subject: [PATCH 25/49] serial: max310x: improve max310x_set_ref_clk() efficiency The same basic code is duplicated for each of the four PLL multiplier values, so simplify and streamline it. Doing so allows us to avoid some unnecessary (fdiv * factor) multiplications for some fdiv values and replace the second "if" statement with an "else if" and avoid a useless comparison. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-5-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 91 ++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index f689958736f7..1cd7632831a2 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -258,6 +258,17 @@ #define MAX14830_BRGCFG_CLKDIS_BIT (1 << 6) /* Clock Disable */ #define MAX14830_REV_ID (0xb0) +struct max310x_clk_config_t { + u8 prediv; /* Predivider */ + u8 pll_mult; /* PLL multiplier */ + unsigned int fref; /* + * Reference clock for fractional baud rate generator: + * PLL enabled: (freq / prediv) x pll_mult + * PLL disabled: freq + */ + unsigned int err; /* Computed error for selected parameters */ +}; + struct max310x_if_cfg { int (*extended_reg_enable)(struct device *dev, bool enable); u8 rev_id_offset; @@ -545,70 +556,72 @@ static int max310x_set_baud(struct uart_port *port, int baud) return (16*port->uartclk) / (c*(16*div + frac)); } -static int max310x_update_best_err(unsigned int f, unsigned int *besterr) +static void max310x_try_cfg(unsigned int fdiv, u8 div, u8 pll_mult, + struct max310x_clk_config_t *cfg) { + unsigned int fmul = fdiv * pll_mult; + unsigned int err; + /* Use high-enough baudrate to calculate error */ - unsigned int err = f % (460800 * 16); + err = fmul % (460800 * 16); - if (*besterr > err) { - *besterr = err; - return 0; + if (cfg->err > err) { + cfg->err = err; + cfg->pll_mult = pll_mult; + cfg->prediv = div; + cfg->fref = fmul; } +} - return 1; +static u8 max310x_pll_mult_to_id(u8 pll_mult) +{ + switch (pll_mult) { + case 144: return 3; + case 96: return 2; + case 48: return 1; + case 6: + default: return 0; + } } static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, unsigned int freq, unsigned int *fref, bool xtal) { - unsigned int div, clksrc, pllcfg = 0; - unsigned int besterr = UINT_MAX; - unsigned int fdiv, fmul, bestfreq = freq; + unsigned int div, fdiv, clksrc; + struct max310x_clk_config_t cfg; + + cfg.err = UINT_MAX; + cfg.prediv = 0; + cfg.fref = freq; /* First, update error without PLL */ - max310x_update_best_err(freq, &besterr); + max310x_try_cfg(freq, 1, 1, &cfg); /* Try all possible PLL dividers */ - for (div = 1; (div <= 63) && besterr; div++) { + for (div = 1; (div <= 63) && cfg.err; div++) { fdiv = DIV_ROUND_CLOSEST(freq, div); - /* Try multiplier 6 */ - fmul = fdiv * 6; if ((fdiv >= 500000) && (fdiv <= 800000)) - if (!max310x_update_best_err(fmul, &besterr)) { - pllcfg = (0 << 6) | div; - bestfreq = fmul; - } - /* Try multiplier 48 */ - fmul = fdiv * 48; - if ((fdiv >= 850000) && (fdiv <= 1200000)) - if (!max310x_update_best_err(fmul, &besterr)) { - pllcfg = (1 << 6) | div; - bestfreq = fmul; - } - /* Try multiplier 96 */ - fmul = fdiv * 96; + max310x_try_cfg(fdiv, div, 6, &cfg); /* PLL x6 */ + else if ((fdiv >= 850000) && (fdiv <= 1200000)) + max310x_try_cfg(fdiv, div, 48, &cfg); /* PLL x48 */ + if ((fdiv >= 425000) && (fdiv <= 1000000)) - if (!max310x_update_best_err(fmul, &besterr)) { - pllcfg = (2 << 6) | div; - bestfreq = fmul; - } - /* Try multiplier 144 */ - fmul = fdiv * 144; + max310x_try_cfg(fdiv, div, 96, &cfg); /* PLL x96 */ + if ((fdiv >= 390000) && (fdiv <= 667000)) - if (!max310x_update_best_err(fmul, &besterr)) { - pllcfg = (3 << 6) | div; - bestfreq = fmul; - } + max310x_try_cfg(fdiv, div, 144, &cfg); /* PLL x144 */ } /* Configure clock source */ clksrc = MAX310X_CLKSRC_EXTCLK_BIT | (xtal ? MAX310X_CLKSRC_CRYST_BIT : 0); /* Configure PLL */ - if (pllcfg) { + if (cfg.prediv) { + u8 pll_id = max310x_pll_mult_to_id(cfg.pll_mult); + clksrc |= MAX310X_CLKSRC_PLL_BIT; - regmap_write(s->regmap, MAX310X_PLLCFG_REG, pllcfg); + regmap_write(s->regmap, MAX310X_PLLCFG_REG, (pll_id << 6) | cfg.prediv); } else clksrc |= MAX310X_CLKSRC_PLLBYP_BIT; @@ -632,7 +645,7 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, "clock is not stable\n"); } - *fref = bestfreq; + *fref = cfg.fref; return 0; } From 9769046a06cc75e2af1d54c50238cccf95759cda Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:33 -0400 Subject: [PATCH 26/49] serial: max310x: use regmap_read_poll_timeout() for busy wait Simplify busy wait stages by using regmap_read_poll_timeout(). Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-6-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 44 ++++++++++++++---------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 1cd7632831a2..7ab5e4bd87ee 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -241,12 +241,12 @@ #define MAX310X_WRITE_BIT 0x80 /* Port startup definitions */ -#define MAX310X_PORT_STARTUP_WAIT_RETRIES 20 /* Number of retries */ -#define MAX310X_PORT_STARTUP_WAIT_DELAY_MS 10 /* Delay between retries */ +#define MAX310X_PORT_STARTUP_SLEEP_US 10000 /* Delay between retries */ +#define MAX310X_PORT_STARTUP_TIMEOUT_US (20 * MAX310X_PORT_STARTUP_SLEEP_US) /* Total timeout */ /* Crystal-related definitions */ -#define MAX310X_XTAL_WAIT_RETRIES 20 /* Number of retries */ -#define MAX310X_XTAL_WAIT_DELAY_MS 10 /* Delay between retries */ +#define MAX310X_XTAL_SLEEP_US 10000 /* Delay between retries */ +#define MAX310X_XTAL_TIMEOUT_US (20 * MAX310X_XTAL_SLEEP_US) /* Total timeout */ /* MAX3107 specific */ #define MAX3107_REV_ID (0xa0) @@ -587,7 +587,7 @@ static u8 max310x_pll_mult_to_id(u8 pll_mult) static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, unsigned int freq, unsigned int *fref, bool xtal) { - unsigned int div, fdiv, clksrc; + unsigned int div, fdiv, clksrc, val; struct max310x_clk_config_t cfg; cfg.err = UINT_MAX; @@ -629,18 +629,13 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, /* Wait for crystal */ if (xtal) { - bool stable = false; - unsigned int try = 0, val = 0; + int ret; - do { - msleep(MAX310X_XTAL_WAIT_DELAY_MS); - regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &val); - - if (val & MAX310X_STS_CLKREADY_BIT) - stable = true; - } while (!stable && (++try < MAX310X_XTAL_WAIT_RETRIES)); - - if (!stable) + ret = regmap_read_poll_timeout(s->regmap, MAX310X_STS_IRQSTS_REG, + val, val & MAX310X_STS_CLKREADY_BIT, + MAX310X_XTAL_SLEEP_US, + MAX310X_XTAL_TIMEOUT_US); + if (ret) return dev_err_probe(dev, -EAGAIN, "clock is not stable\n"); } @@ -1346,8 +1341,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty goto out_clk; for (i = 0; i < devtype->nr; i++) { - bool started = false; - unsigned int try = 0, val = 0; + unsigned int val; /* Reset port */ regmap_write(regmaps[i], MAX310X_MODE2_REG, @@ -1356,15 +1350,11 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty regmap_write(regmaps[i], MAX310X_MODE2_REG, 0); /* Wait for port startup */ - do { - msleep(MAX310X_PORT_STARTUP_WAIT_DELAY_MS); - regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &val); - - if (val == 0x01) - started = true; - } while (!started && (++try < MAX310X_PORT_STARTUP_WAIT_RETRIES)); - - if (!started) { + ret = regmap_read_poll_timeout(regmaps[i], MAX310X_BRGDIVLSB_REG, + val, val == 0x01, + MAX310X_PORT_STARTUP_SLEEP_US, + MAX310X_PORT_STARTUP_TIMEOUT_US); + if (ret) { ret = dev_err_probe(dev, -EAGAIN, "port reset failed\n"); goto out_uart; } From 877c2556adb7758ada3af8a1e87a217ed21c6ef4 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:34 -0400 Subject: [PATCH 27/49] serial: max310x: use FIELD_PREP macro to set PLL bitfields Use FIELD_PREP macros to improve code readability. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-7-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 7ab5e4bd87ee..b4449b68cfee 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -9,6 +9,7 @@ * Based on max3107.c, by Aavamobile */ +#include #include #include #include @@ -621,7 +622,9 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, u8 pll_id = max310x_pll_mult_to_id(cfg.pll_mult); clksrc |= MAX310X_CLKSRC_PLL_BIT; - regmap_write(s->regmap, MAX310X_PLLCFG_REG, (pll_id << 6) | cfg.prediv); + val = FIELD_PREP(MAX310X_PLLCFG_PLLFACTOR_MASK, pll_id) | + FIELD_PREP(MAX310X_PLLCFG_PREDIV_MASK, cfg.prediv); + regmap_write(s->regmap, MAX310X_PLLCFG_REG, val); } else clksrc |= MAX310X_CLKSRC_PLLBYP_BIT; From 20ffe4b3330a8bde9e933e9ba2323d5e9386caa5 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:35 -0400 Subject: [PATCH 28/49] serial: max310x: allow driver to be built with SPI or I2C If SPI is disabled, the max310x driver cannot be selected. Allow driver to be selected if either I2C or SPI is set. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-8-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 3e519d001e02..f834e5d292fd 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -321,7 +321,7 @@ config SERIAL_MAX3100 config SERIAL_MAX310X tristate "MAX310X support" - depends on SPI_MASTER + depends on SPI_MASTER || I2C select SERIAL_CORE select REGMAP_SPI if SPI_MASTER select REGMAP_I2C if I2C From 922cc077b248a786a93339e7b76bc21ed8575ac7 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:36 -0400 Subject: [PATCH 29/49] serial: max310x: move variables to while() scope txlen, to_send and tail variables are only used within the while() loop. Move them to that scope to keep them closer to their usage and improve readability. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-9-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index b4449b68cfee..748306d1a932 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -761,8 +761,6 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen) static void max310x_handle_tx(struct uart_port *port) { struct tty_port *tport = &port->state->port; - unsigned int txlen, to_send; - unsigned char *tail; if (unlikely(port->x_char)) { max310x_port_write(port, MAX310X_THR_REG, port->x_char); @@ -779,6 +777,9 @@ static void max310x_handle_tx(struct uart_port *port) * We could do that in one SPI transaction, but meh. */ while (!kfifo_is_empty(&tport->xmit_fifo)) { + unsigned int txlen, to_send; + unsigned char *tail; + /* Limit to space available in TX FIFO */ txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG); txlen = port->fifosize - txlen; From ebd57bda9df6234d93e05dfe2fd250c6535ca3bb Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Fri, 17 Apr 2026 10:53:37 -0400 Subject: [PATCH 30/49] serial: max310x: add comments for PLL limits Add comments to help clarify the provenance of the various hardcoded values used in computing the ref clk. Assisted-by: Gemini:Pro Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260417-max310x-2-v1-10-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 748306d1a932..9f423b3b4201 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -585,6 +585,23 @@ static u8 max310x_pll_mult_to_id(u8 pll_mult) } } +/* + * From table 7 in datasheet: PLLFactor Selector Guide + * + * +-----------+----------------+-------------------+-------------------+ + * | PLLFactor | MULTIPLICATION | fPLLIN | fREF | + * | (1 & 0) | FACTOR +---------+---------+---------+---------+ + * | | | MIN | MAX | MIN | MAX | + * +-----------+----------------+---------+---------+---------+---------+ + * | 0 | 6 | 500kHz | 800kHz | 3MHz | 4.8MHz | + * +-----------+----------------+---------+---------+---------+---------+ + * | 1 | 48 | 850kHz | 1.2MHz | 40.8MHz | 56MHz | + * +-----------+----------------+---------+---------+---------+---------+ + * | 2 | 96 | 425kHz | 1MHz | 40.8MHz | 96MHz | + * +-----------+----------------+---------+---------+---------+---------+ + * | 3 | 144 | 390kHz | 667kHz | 56MHz | 96MHz | + * +-----------+----------------+---------+---------+---------+---------+ + */ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, unsigned int freq, unsigned int *fref, bool xtal) { From 16e95bfb79b5d9d01dc7651d98caf3c2ace331cd Mon Sep 17 00:00:00 2001 From: Aniket Randive Date: Mon, 4 May 2026 15:40:45 +0530 Subject: [PATCH 31/49] serial: qcom-geni: Avoid probing debug console UART without console support When CONFIG_SERIAL_QCOM_GENI_CONSOLE is disabled, the driver still advertises the debug UART compatible strings ("qcom,geni-debug-uart" and "qcom,sa8255p-geni-debug-uart") in its of_match table. This lets the driver match and probe console UART DT nodes even though console support is not built. As a result, the console port is never registered with the UART core and uart_add_one_port() fails with -EINVAL. Fix this by only including the debug UART compatible entries in the match table when CONFIG_SERIAL_QCOM_GENI_CONSOLE is enabled, preventing the driver from probing console UART nodes when console support is absent. Reviewed-by: Praveen Talari Signed-off-by: Aniket Randive Link: https://patch.msgid.link/20260504101045.1084672-1-aniket.randive@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index b365dd5da3cb..58d142afa160 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1992,6 +1992,7 @@ static int qcom_geni_serial_resume(struct device *dev) return ret; } +#if IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE) static const struct qcom_geni_device_data qcom_geni_console_data = { .console = true, .mode = GENI_SE_FIFO, @@ -2000,14 +2001,6 @@ static const struct qcom_geni_device_data qcom_geni_console_data = { .power_state = geni_serial_resource_state, }; -static const struct qcom_geni_device_data qcom_geni_uart_data = { - .console = false, - .mode = GENI_SE_DMA, - .resources_init = geni_serial_resource_init, - .set_rate = geni_serial_set_rate, - .power_state = geni_serial_resource_state, -}; - static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = { .console = true, .mode = GENI_SE_FIFO, @@ -2019,6 +2012,15 @@ static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = { .resources_init = geni_serial_pwr_init, .set_rate = geni_serial_set_level, }; +#endif + +static const struct qcom_geni_device_data qcom_geni_uart_data = { + .console = false, + .mode = GENI_SE_DMA, + .resources_init = geni_serial_resource_init, + .set_rate = geni_serial_set_rate, + .power_state = geni_serial_resource_state, +}; static const struct qcom_geni_device_data sa8255p_qcom_geni_uart_data = { .console = false, @@ -2039,6 +2041,7 @@ static const struct dev_pm_ops qcom_geni_serial_pm_ops = { }; static const struct of_device_id qcom_geni_serial_match_table[] = { +#if IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE) { .compatible = "qcom,geni-debug-uart", .data = &qcom_geni_console_data, @@ -2047,6 +2050,7 @@ static const struct of_device_id qcom_geni_serial_match_table[] = { .compatible = "qcom,sa8255p-geni-debug-uart", .data = &sa8255p_qcom_geni_console_data, }, +#endif { .compatible = "qcom,geni-uart", .data = &qcom_geni_uart_data, From f18643843bc622e24dd6c3c704273c1f411b1b7a Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Thu, 21 May 2026 11:33:29 -0400 Subject: [PATCH 32/49] serial: max310x: fix compile errors if CONFIG_SPI_MASTER is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 20ffe4b3330a8 ("serial: max310x: allow driver to be built with SPI or I2C"), if I2C is enabled and SPI_MASTER is disabled, we have these compile errors: drivers/tty/serial/max310x.c: In function 'max310x_uart_init': drivers/tty/serial/max310x.c: error: 'max310x_spi_driver' undeclared... drivers/tty/serial/max310x.c: In function ‘max310x_uart_init’: drivers/tty/serial/max310x.c: error: label ‘err_spi_register’ defined but not used... drivers/tty/serial/max310x.c: error: ‘regcfg’ defined but not used Fix by properly encapsulating i2c/spi code/variables in their respective context with IS_ENABLED() macros for CONFIG_I2C and CONFIG_SPI_MASTER. Also fix link failure with SERIAL_MAX310X=y and I2C=m by modifying Kconfig depends. Fixes: 20ffe4b3330a8 ("serial: max310x: allow driver to be built with SPI or I2C") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202605121847.N9DVLNg2-lkp@intel.com/ Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260521153333.2336642-1-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- drivers/tty/serial/max310x.c | 48 +++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index f834e5d292fd..4accbfa75074 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -321,7 +321,7 @@ config SERIAL_MAX3100 config SERIAL_MAX310X tristate "MAX310X support" - depends on SPI_MASTER || I2C + depends on (SPI_MASTER && !I2C) || I2C select SERIAL_CORE select REGMAP_SPI if SPI_MASTER select REGMAP_I2C if I2C diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 9f423b3b4201..bad5329a0c84 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -1507,6 +1508,21 @@ static const struct of_device_id __maybe_unused max310x_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, max310x_dt_ids); +static const char *max310x_regmap_name(u8 port_id) +{ + switch (port_id) { + case 0: return "port0"; + case 1: return "port1"; + case 2: return "port2"; + case 3: return "port3"; + default: + WARN_ON(true); + return NULL; + } +} + +#if IS_ENABLED(CONFIG_SPI_MASTER) + static struct regmap_config regcfg = { .reg_bits = 8, .val_bits = 8, @@ -1522,20 +1538,6 @@ static struct regmap_config regcfg = { .max_raw_write = MAX310X_FIFO_SIZE, }; -static const char *max310x_regmap_name(u8 port_id) -{ - switch (port_id) { - case 0: return "port0"; - case 1: return "port1"; - case 2: return "port2"; - case 3: return "port3"; - default: - WARN_ON(true); - return NULL; - } -} - -#ifdef CONFIG_SPI_MASTER static int max310x_spi_extended_reg_enable(struct device *dev, bool enable) { struct max310x_port *s = dev_get_drvdata(dev); @@ -1606,7 +1608,8 @@ static struct spi_driver max310x_spi_driver = { }; #endif -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) + static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable) { return 0; @@ -1726,13 +1729,13 @@ static int __init max310x_uart_init(void) if (ret) return ret; -#ifdef CONFIG_SPI_MASTER +#if IS_ENABLED(CONFIG_SPI_MASTER) ret = spi_register_driver(&max310x_spi_driver); if (ret) goto err_spi_register; #endif -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) ret = i2c_add_driver(&max310x_i2c_driver); if (ret) goto err_i2c_register; @@ -1740,12 +1743,13 @@ static int __init max310x_uart_init(void) return 0; -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) err_i2c_register: - spi_unregister_driver(&max310x_spi_driver); #endif - +#if IS_ENABLED(CONFIG_SPI_MASTER) + spi_unregister_driver(&max310x_spi_driver); err_spi_register: +#endif uart_unregister_driver(&max310x_uart); return ret; @@ -1754,11 +1758,11 @@ module_init(max310x_uart_init); static void __exit max310x_uart_exit(void) { -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) i2c_del_driver(&max310x_i2c_driver); #endif -#ifdef CONFIG_SPI_MASTER +#if IS_ENABLED(CONFIG_SPI_MASTER) spi_unregister_driver(&max310x_spi_driver); #endif From 52f203f9a8c7e57322e79577d1a8d50a5e3a5ef2 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Thu, 23 Apr 2026 09:20:54 +0000 Subject: [PATCH 33/49] dt-bindings: arm: amlogic: add A311Y3 support Add bindings for the Amlogic BY401 board, using A311Y3 Soc from Amlogic A9 family chip. Reviewed-by: Martin Blumenstingl Acked-by: Krzysztof Kozlowski Signed-off-by: Xianwei Zhao Link: https://patch.msgid.link/20260423-a9-baisc-dts-v4-1-c26b480a068c@amlogic.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/arm/amlogic.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/amlogic.yaml b/Documentation/devicetree/bindings/arm/amlogic.yaml index a885278bc4e2..9f73a0054fb2 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.yaml +++ b/Documentation/devicetree/bindings/arm/amlogic.yaml @@ -234,6 +234,12 @@ properties: - amlogic,av400 - const: amlogic,a5 + - description: Boards with the Amlogic A9 A311Y3 SoC + items: + - enum: + - amlogic,by401 + - const: amlogic,a9 + - description: Boards with the Amlogic C3 C302X/C308L SoC items: - enum: From ab5eadfea17e9aae0760eec8f730a71a4be9ba5e Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Thu, 23 Apr 2026 09:20:55 +0000 Subject: [PATCH 34/49] arm64: dts: add support for A9 based Amlogic BY401 Add basic support for the A9 based Amlogic BY401 board, which describes the following components: CPU, GIC, IRQ, Timer and UART. These are capable of booting up into the serial console. Reviewed-by: Martin Blumenstingl Signed-off-by: Xianwei Zhao Link: https://patch.msgid.link/20260423-a9-baisc-dts-v4-2-c26b480a068c@amlogic.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/amlogic/Makefile | 1 + .../dts/amlogic/amlogic-a9-a311y3-by401.dts | 40 ++++++ arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi | 128 ++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 arch/arm64/boot/dts/amlogic/amlogic-a9-a311y3-by401.dts create mode 100644 arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile index 15f9c817e502..57bc440fa55c 100644 --- a/arch/arm64/boot/dts/amlogic/Makefile +++ b/arch/arm64/boot/dts/amlogic/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_ARCH_MESON) += amlogic-a4-a113l2-ba400.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-a5-a113x2-av400.dtb +dtb-$(CONFIG_ARCH_MESON) += amlogic-a9-a311y3-by401.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-c3-c302x-aw409.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-c3-c308l-aw419.dtb dtb-$(CONFIG_ARCH_MESON) += amlogic-s6-s905x5-bl209.dtb diff --git a/arch/arm64/boot/dts/amlogic/amlogic-a9-a311y3-by401.dts b/arch/arm64/boot/dts/amlogic/amlogic-a9-a311y3-by401.dts new file mode 100644 index 000000000000..a6b380ca47a5 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/amlogic-a9-a311y3-by401.dts @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2026 Amlogic, Inc. All rights reserved. + */ + +/dts-v1/; + +#include "amlogic-a9.dtsi" +/ { + model = "Amlogic A311DY3 BY401 Development Board"; + compatible = "amlogic,by401", "amlogic,a9"; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &uart_b; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 35 MiB reserved for ARM Trusted Firmware */ + secmon_reserved: secmon@5000000 { + compatible = "shared-dma-pool"; + reg = <0x0 0x05000000 0x0 0x2300000>; + no-map; + }; + }; +}; + +&uart_b { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi new file mode 100644 index 000000000000..660c8556a864 --- /dev/null +++ b/arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2026 Amlogic, Inc. All rights reserved. + */ + +#include +#include +#include + +/ { + interrupt-parent = <&gic>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x0>; + enable-method = "psci"; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x100>; + enable-method = "psci"; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x200>; + enable-method = "psci"; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x300>; + enable-method = "psci"; + }; + + cpu4: cpu@400 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x400>; + enable-method = "psci"; + }; + + cpu5: cpu@500 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x500>; + enable-method = "psci"; + }; + + cpu6: cpu@600 { + device_type = "cpu"; + compatible = "arm,cortex-a78"; + reg = <0x0 0x600>; + enable-method = "psci"; + }; + + cpu7: cpu@700 { + device_type = "cpu"; + compatible = "arm,cortex-a78"; + reg = <0x0 0x700>; + enable-method = "psci"; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + xtal: xtal-clk { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic: interrupt-controller@ff800000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x0 0xff800000 0 0x10000>, + <0x0 0xff840000 0 0x100000>; + interrupts = ; + }; + + aobus: bus@ffa00000 { + compatible = "simple-bus"; + reg = <0x0 0xffa00000 0x0 0x100000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xffa00000 0x0 0x100000>; + + uart_b: serial@1e000 { + compatible = "amlogic,a9-uart", + "amlogic,meson-s4-uart"; + reg = <0x0 0x1e000 0x0 0x18>; + interrupts = ; + clocks = <&xtal>, <&xtal>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; + }; + }; +}; From 941c9f84c9b6310f7aaa1c8c785dcc634ee33050 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Fri, 8 May 2026 23:12:37 +0500 Subject: [PATCH 35/49] tty: serial: 8250: protect against NULL uart->port.dev in register serial8250_register_8250_port() conditionally copies uart->port.dev from up->port.dev only when up->port.dev is non-NULL: if (up->port.dev) { uart->port.dev = up->port.dev; ... } So if both the existing uart slot and up have a NULL ->dev, uart->port.dev remains NULL. The very next ACPI companion check then dereferences it unconditionally: if (!has_acpi_companion(uart->port.dev)) { has_acpi_companion() reads dev->fwnode without a NULL guard (include/linux/acpi.h), so this NULL-derefs the kernel for the remaining no-dev case rather than just skipping the mctrl_gpio_init() initialisation as intended. smatch flags the inconsistency: drivers/tty/serial/8250/8250_core.c:767 serial8250_register_8250_port() error: 'uart->port.dev' could be null (see line 719) Guard the call with a NULL check so register continues to work for callers that legitimately have no parent device (legacy non-OF/non-ACPI registrations). No functional change for callers that pass a non-NULL ->dev. Signed-off-by: Stepan Ionichev Link: https://patch.msgid.link/20260508181237.11146-1-sozdayvek@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index a428e88938eb..e136cec0c0be 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -764,7 +764,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) * Only call mctrl_gpio_init(), if the device has no ACPI * companion device */ - if (!has_acpi_companion(uart->port.dev)) { + if (uart->port.dev && !has_acpi_companion(uart->port.dev)) { struct mctrl_gpios *gpios = mctrl_gpio_init(&uart->port, 0); if (IS_ERR(gpios)) { ret = PTR_ERR(gpios); From f69ec492244d54068f08c20f90979274d8ac3655 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 11 May 2026 17:33:00 +0206 Subject: [PATCH 36/49] serial: 8250: Set cons_flow on port registration Since console flow control policy is no longer part of uart_port.flags, explicitly set the policy for the port. Signed-off-by: John Ogness Link: https://patch.msgid.link/20260511152706.151498-2-john.ogness@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index e136cec0c0be..5ea9a8827b04 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -746,6 +746,8 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) uart->lsr_save_mask = up->lsr_save_mask; uart->dma = up->dma; + uart_set_cons_flow_enabled(&uart->port, uart_cons_flow_enabled(&up->port)); + /* Take tx_loadsz from fifosize if it wasn't set separately */ if (uart->port.fifosize && !uart->tx_loadsz) uart->tx_loadsz = uart->port.fifosize; From 39d307074f919aed4fe7b1c131e624f34fec3d51 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 11 May 2026 17:33:01 +0206 Subject: [PATCH 37/49] serial: 8250: Check LSR timeout on console flow control wait_for_xmitr() calls wait_for_lsr() to wait for the transmission registers to be empty. wait_for_lsr() can timeout after a reasonable amount of time. When console flow control is active, wait_for_xmitr() additionally polls CTS, waiting for the peer to signal that it is ready to receive more data. If hardware flow control is enabled (auto CTS) and the peer deasserts CTS, wait_for_lsr() will timeout. If additionally console flow control is active and while polling CTS the peer asserts CTS, the console will assume it can immediately transmit, even though the transmission registers may not be empty. This can lead to data loss. Avoid this problem by performing an extra wait_for_lsr() upon CTS assertion if wait_for_lsr() previously timed out. Signed-off-by: John Ogness Link: https://patch.msgid.link/20260511152706.151498-3-john.ogness@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index e4e6a53ebea3..fe2e0f1e66c2 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1986,16 +1986,20 @@ static bool wait_for_lsr(struct uart_8250_port *up, int bits) static void wait_for_xmitr(struct uart_8250_port *up, int bits) { unsigned int tmout; + bool tx_ready; - wait_for_lsr(up, bits); + tx_ready = wait_for_lsr(up, bits); /* Wait up to 1s for flow control if necessary */ if (uart_cons_flow_enabled(&up->port)) { for (tmout = 1000000; tmout; tmout--) { unsigned int msr = serial_in(up, UART_MSR); up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; - if (msr & UART_MSR_CTS) + if (msr & UART_MSR_CTS) { + if (!tx_ready) + wait_for_lsr(up, bits); break; + } udelay(1); touch_nmi_watchdog(); } From 5e6dfb87b191f34b1bb7cfb4d668665e5b70687b Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 11 May 2026 17:33:02 +0206 Subject: [PATCH 38/49] serial: 8250: Add support for console flow control The kernel documentation specifies that the console option 'r' can be used to enable hardware flow control for console writes. The 8250 driver does include code for hardware flow control on the console if cons_flow is set, but there is no code path that actually sets this. However, that is not the only issue. The problems are: 1. Specifying the console option 'r' does not lead to cons_flow being set. 2. Even if cons_flow would be set, serial8250_register_8250_port() clears it. 3. When the console option 'r' is specified, uart_set_options() attempts to initialize the port for CRTSCTS. However, afterwards it does not set the UPSTAT_CTS_ENABLE status bit and therefore on boot, uart_cts_enabled() is always false. This policy bit is important for console drivers as a criteria if they may poll CTS. 4. Even though uart_set_options() attempts to initialize the port for CRTSCTS, the 8250 set_termios() callback does not enable the RTS signal (TIOCM_RTS) and thus the hardware is not properly initialized for CTS polling. 5. Even if modem control was properly setup for CTS polling (TIOCM_RTS), uart_configure_port() clears TIOCM_RTS, thus breaking CTS polling. 6. wait_for_xmitr() and serial8250_console_write() use cons_flow to decide if CTS polling should occur. However, the condition should also include a check that it is not in RS485 mode and CRTSCTS is actually enabled in the hardware. Address all these issues as conservatively as possible by gating them behind checks focussed on the user specifying console hardware flow control support and the hardware being configured for CTS polling at the time of the write to the UART. Since checking the UPSTAT_CTS_ENABLE status bit is a part of the new condition gate, these changes also support runtime termios updates to disable/enable CRTSCTS. Signed-off-by: John Ogness Link: https://patch.msgid.link/20260511152706.151498-4-john.ogness@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 6 +++++- drivers/tty/serial/8250/8250_port.c | 13 +++++++++++-- drivers/tty/serial/serial_core.c | 21 ++++++++++++++++++++- include/linux/serial_core.h | 8 ++++++++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 5ea9a8827b04..f49862d90eeb 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -693,6 +693,7 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work) int serial8250_register_8250_port(const struct uart_8250_port *up) { struct uart_8250_port *uart; + bool cons_flow; int ret; if (up->port.uartclk == 0) @@ -716,6 +717,9 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) if (uart->port.type == PORT_8250_CIR) return -ENODEV; + /* Preserve specified console flow control. */ + cons_flow = uart_cons_flow_enabled(&uart->port); + if (uart->port.dev) uart_remove_one_port(&serial8250_reg, &uart->port); @@ -746,7 +750,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) uart->lsr_save_mask = up->lsr_save_mask; uart->dma = up->dma; - uart_set_cons_flow_enabled(&uart->port, uart_cons_flow_enabled(&up->port)); + uart_set_cons_flow_enabled(&uart->port, uart_cons_flow_enabled(&up->port) | cons_flow); /* Take tx_loadsz from fifosize if it wasn't set separately */ if (uart->port.fifosize && !uart->tx_loadsz) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index fe2e0f1e66c2..ef245114105b 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1991,7 +1991,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) tx_ready = wait_for_lsr(up, bits); /* Wait up to 1s for flow control if necessary */ - if (uart_cons_flow_enabled(&up->port)) { + if (uart_console_hwflow_active(&up->port)) { for (tmout = 1000000; tmout; tmout--) { unsigned int msr = serial_in(up, UART_MSR); up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; @@ -2788,6 +2788,12 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, serial8250_set_efr(port, termios); serial8250_set_divisor(port, baud, quot, frac); serial8250_set_fcr(port, termios); + /* Consoles manually poll CTS for hardware flow control. */ + if (uart_console(port) && + !(port->rs485.flags & SER_RS485_ENABLED) + && termios->c_cflag & CRTSCTS) { + port->mctrl |= TIOCM_RTS; + } serial8250_set_mctrl(port, port->mctrl); } @@ -3357,7 +3363,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, * it regardless of the CTS state. Therefore, only use fifo * if we don't use control flow. */ - !uart_cons_flow_enabled(&up->port); + !uart_console_hwflow_active(&up->port); if (likely(use_fifo)) serial8250_console_fifo_write(up, s, count); @@ -3427,6 +3433,9 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe) if (ret) return ret; + /* Track user-specified console flow control. */ + uart_set_cons_flow_enabled(port, flow == 'r'); + if (port->dev) pm_runtime_get_sync(port->dev); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 075a69164aa7..98ace5c492fa 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2231,6 +2231,18 @@ uart_set_options(struct uart_port *port, struct console *co, port->mctrl |= TIOCM_DTR; port->ops->set_termios(port, &termios, &dummy); + + /* + * If console hardware flow control was specified and is supported, + * the related policy UPSTAT_CTS_ENABLE must be set to allow console + * drivers to identify if CTS should be used for polling. + */ + if (flow == 'r' && (termios.c_cflag & CRTSCTS)) { + /* Synchronize @status RMW update against the console. */ + guard(uart_port_lock_irqsave)(port); + port->status |= UPSTAT_CTS_ENABLE; + } + /* * Allow the setting of the UART parameters with a NULL console * too: @@ -2537,7 +2549,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, * We probably don't need a spinlock around this, but */ scoped_guard(uart_port_lock_irqsave, port) { - port->mctrl &= TIOCM_DTR; + unsigned int mask = TIOCM_DTR; + + /* Console hardware flow control polls CTS. */ + if (uart_console_hwflow_active(port)) + mask |= TIOCM_RTS; + + port->mctrl &= mask; + if (!(port->rs485.flags & SER_RS485_ENABLED)) port->ops->set_mctrl(port, port->mctrl); } diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 4f7bbdd90017..17fcff466e30 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -1175,6 +1175,14 @@ static inline bool uart_cons_flow_enabled(const struct uart_port *uport) return uport->cons_flow; } +static inline bool uart_console_hwflow_active(struct uart_port *uport) +{ + return uart_console(uport) && + !(uport->rs485.flags & SER_RS485_ENABLED) && + uart_cons_flow_enabled(uport) && + uart_cts_enabled(uport); +} + /* * The following are helper functions for the low level drivers. */ From d9ee199c0fef5e4074e241ed328e5c18a790454b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Thu, 14 May 2026 00:34:57 +0300 Subject: [PATCH 39/49] amba/serial: amba-pl011: Bring back zx29 UART support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is based on code removed in commit 89d4f98ae90d ("ARM: remove zte zx platform"). I did not bring back the zx29-uart .compatible as the arm,primecell-periphid does the job. Reviewed-by: Linus Walleij Signed-off-by: Stefan Dösinger Link: https://patch.msgid.link/20260514-zx29uart-v1-2-68470ecc3977@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 028e37ad8d79..8ed91e1da22b 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -240,6 +240,38 @@ static struct vendor_data vendor_nvidia = { .get_fifosize = get_fifosize_nvidia, }; +static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = { + [REG_DR] = ZX_UART011_DR, + [REG_FR] = ZX_UART011_FR, + [REG_LCRH_RX] = ZX_UART011_LCRH, + [REG_LCRH_TX] = ZX_UART011_LCRH, + [REG_IBRD] = ZX_UART011_IBRD, + [REG_FBRD] = ZX_UART011_FBRD, + [REG_CR] = ZX_UART011_CR, + [REG_IFLS] = ZX_UART011_IFLS, + [REG_IMSC] = ZX_UART011_IMSC, + [REG_RIS] = ZX_UART011_RIS, + [REG_MIS] = ZX_UART011_MIS, + [REG_ICR] = ZX_UART011_ICR, + [REG_DMACR] = ZX_UART011_DMACR, +}; + +static unsigned int get_fifosize_zte(struct amba_device *dev) +{ + return 16; +} + +static struct vendor_data vendor_zte = { + .reg_offset = pl011_zte_offsets, + .access_32b = true, + .ifls = UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8, + .fr_busy = ZX_UART01x_FR_BUSY, + .fr_dsr = ZX_UART01x_FR_DSR, + .fr_cts = ZX_UART01x_FR_CTS, + .fr_ri = ZX_UART011_FR_RI, + .get_fifosize = get_fifosize_zte, +}; + /* Deals with DMA transactions */ struct pl011_dmabuf { @@ -3180,6 +3212,16 @@ static const struct amba_id pl011_ids[] = { .mask = 0x000fffff, .data = &vendor_nvidia, }, + { + /* This is an invented ID. The actual hardware that contains + * these ZTE UARTs (zx29 boards) has no AMBA PIDs stored. ZTE + * JEDEC ID (ignoring banks) and the "011" part number as used + * by ARM. + */ + .id = 0x0008c011, + .mask = 0x000fffff, + .data = &vendor_zte, + }, { 0, 0 }, }; From 10fc708b4de7f86002d2d735a2dbf3b5b7f65692 Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Thu, 14 May 2026 19:37:45 +0500 Subject: [PATCH 40/49] serial: 8250_dw: unregister 8250 port if clk_notifier_register() fails dw8250_probe() registers the 8250 port via serial8250_register_8250_port() and then, if the device has a clock, registers a clock notifier. If clk_notifier_register() fails, probe returns the error but leaves the 8250 port registered. The matching serial8250_unregister_port() lives in dw8250_remove(), which is not called when probe fails, so the port slot stays occupied until the device is rebound or the system is rebooted. The devm-allocated driver data is freed while the port still references it (via the saved private_data and serial_in/serial_out callbacks), so any access to that port slot before a rebind is a use-after-free hazard. Unregister the port on the clk_notifier_register() error path. Fixes: cc816969d7b5 ("serial: 8250_dw: Fix common clocks usage race condition") Cc: stable@vger.kernel.org Signed-off-by: Stepan Ionichev Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20260514143746.23671-2-sozdayvek@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 55e40c10f46a..2d30a164eeae 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -839,8 +839,10 @@ static int dw8250_probe(struct platform_device *pdev) */ if (data->clk) { err = clk_notifier_register(data->clk, &data->clk_notifier); - if (err) + if (err) { + serial8250_unregister_port(data->data.line); return dev_err_probe(dev, err, "Failed to set the clock notifier\n"); + } queue_work(system_dfl_wq, &data->clk_work); } From 01569a29af76aec748b77e0629bcb5615c25468b Mon Sep 17 00:00:00 2001 From: Stepan Ionichev Date: Thu, 14 May 2026 19:37:46 +0500 Subject: [PATCH 41/49] serial: 8250_dw: remove clock-notifier infrastructure The clock notifier and matching work_struct in dw8250_data were added in 2020 for the Baikal-T1 SoC, whose multiple UART ports share a single reference clock and need to be informed when another consumer re-rates that clock. Baikal SoC support has since been removed from the kernel (see e.g. commit 5d6c477687ae ("clk: baikal-t1: Remove not-going-to-be-supported code for Baikal SoC") and the matching removals across bus/, mtd/, PCI/, hwmon/, memory/). No remaining in-tree user needs the cross-device baudclk rate-change notification path: the only configuration that wired up the notifier was Baikal-T1's shared reference clock topology. Drop the now-unused clock-notifier and its deferred-update worker: - struct dw8250_data fields clk_notifier and clk_work, - the clk_to_dw8250_data() and work_to_dw8250_data() helpers, - the dw8250_clk_work_cb() and dw8250_clk_notifier_cb() callbacks, - the INIT_WORK / notifier_call setup in dw8250_probe(), - the clk_notifier_register() / queue_work() in dw8250_probe(), - the matching clk_notifier_unregister() / flush_work() in dw8250_remove(), - the stale comment in dw8250_set_termios() about the worker blocking, - the linux/notifier.h and linux/workqueue.h includes that are no longer used. dw8250_set_termios() keeps calling clk_set_rate() directly, which is all the remaining single-UART configurations require. Signed-off-by: Stepan Ionichev Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20260514143746.23671-3-sozdayvek@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 81 ------------------------------- 1 file changed, 81 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 2d30a164eeae..7920e2cb5307 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -19,13 +19,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include @@ -75,8 +73,6 @@ struct dw8250_data { u32 msr_mask_off; struct clk *clk; struct clk *pclk; - struct notifier_block clk_notifier; - struct work_struct clk_work; struct reset_control *rst; unsigned int skip_autocfg:1; @@ -91,16 +87,6 @@ static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data) return container_of(data, struct dw8250_data, data); } -static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb) -{ - return container_of(nb, struct dw8250_data, clk_notifier); -} - -static inline struct dw8250_data *work_to_dw8250_data(struct work_struct *work) -{ - return container_of(work, struct dw8250_data, clk_work); -} - static inline u32 dw8250_modify_msr(struct uart_port *p, unsigned int offset, u32 value) { struct dw8250_data *d = to_dw8250_data(p->private_data); @@ -473,46 +459,6 @@ static int dw8250_handle_irq(struct uart_port *p) return 1; } -static void dw8250_clk_work_cb(struct work_struct *work) -{ - struct dw8250_data *d = work_to_dw8250_data(work); - struct uart_8250_port *up; - unsigned long rate; - - rate = clk_get_rate(d->clk); - if (rate <= 0) - return; - - up = serial8250_get_port(d->data.line); - - serial8250_update_uartclk(&up->port, rate); -} - -static int dw8250_clk_notifier_cb(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct dw8250_data *d = clk_to_dw8250_data(nb); - - /* - * We have no choice but to defer the uartclk update due to two - * deadlocks. First one is caused by a recursive mutex lock which - * happens when clk_set_rate() is called from dw8250_set_termios(). - * Second deadlock is more tricky and is caused by an inverted order of - * the clk and tty-port mutexes lock. It happens if clock rate change - * is requested asynchronously while set_termios() is executed between - * tty-port mutex lock and clk_set_rate() function invocation and - * vise-versa. Anyway if we didn't have the reference clock alteration - * in the dw8250_set_termios() method we wouldn't have needed this - * deferred event handling complication. - */ - if (event == POST_RATE_CHANGE) { - queue_work(system_dfl_wq, &d->clk_work); - return NOTIFY_OK; - } - - return NOTIFY_DONE; -} - static void dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) { @@ -536,10 +482,6 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, clk_disable_unprepare(d->clk); rate = clk_round_rate(d->clk, newrate); if (rate > 0) { - /* - * Note that any clock-notifier worker will block in - * serial8250_update_uartclk() until we are done. - */ ret = clk_set_rate(d->clk, newrate); if (!ret) p->uartclk = rate; @@ -772,9 +714,6 @@ static int dw8250_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(data->clk), "failed to get baudclk\n"); - INIT_WORK(&data->clk_work, dw8250_clk_work_cb); - data->clk_notifier.notifier_call = dw8250_clk_notifier_cb; - if (data->clk) p->uartclk = clk_get_rate(data->clk); @@ -832,20 +771,6 @@ static int dw8250_probe(struct platform_device *pdev) if (data->data.line < 0) return data->data.line; - /* - * Some platforms may provide a reference clock shared between several - * devices. In this case any clock state change must be known to the - * UART port at least post factum. - */ - if (data->clk) { - err = clk_notifier_register(data->clk, &data->clk_notifier); - if (err) { - serial8250_unregister_port(data->data.line); - return dev_err_probe(dev, err, "Failed to set the clock notifier\n"); - } - queue_work(system_dfl_wq, &data->clk_work); - } - platform_set_drvdata(pdev, data); pm_runtime_enable(dev); @@ -860,12 +785,6 @@ static void dw8250_remove(struct platform_device *pdev) pm_runtime_get_sync(dev); - if (data->clk) { - clk_notifier_unregister(data->clk, &data->clk_notifier); - - flush_work(&data->clk_work); - } - serial8250_unregister_port(data->data.line); pm_runtime_disable(dev); From cd8e495713de3881658560aa1603bc5cc87994ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 18 May 2026 12:14:56 +0200 Subject: [PATCH 42/49] tty: serial: Use named initializers for arrays of i2c_device_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While being less compact, using named initializers allows to more easily see which members of the structs are assigned which value without having to lookup the declaration of the struct. And it's also more robust against changes to the struct definition. The mentioned robustness is relevant for a planned change to struct i2c_device_id that replaces .driver_data by an anonymous union. While touching all these arrays, unify usage of whitespace in the list terminator. This patch doesn't modify the compiled arrays, only their representation in source form benefits. The former was confirmed with x86 and arm64 builds. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/20260518101456.632410-2-u.kleine-koenig@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 8 ++++---- drivers/tty/serial/sc16is7xx_i2c.c | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index bad5329a0c84..e28e3065c99d 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1699,10 +1699,10 @@ static void max310x_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id max310x_i2c_id_table[] = { - { "max3107", (kernel_ulong_t)&max3107_devtype, }, - { "max3108", (kernel_ulong_t)&max3108_devtype, }, - { "max3109", (kernel_ulong_t)&max3109_devtype, }, - { "max14830", (kernel_ulong_t)&max14830_devtype, }, + { .name = "max3107", .driver_data = (kernel_ulong_t)&max3107_devtype }, + { .name = "max3108", .driver_data = (kernel_ulong_t)&max3108_devtype }, + { .name = "max3109", .driver_data = (kernel_ulong_t)&max3109_devtype }, + { .name = "max14830", .driver_data = (kernel_ulong_t)&max14830_devtype }, { } }; MODULE_DEVICE_TABLE(i2c, max310x_i2c_id_table); diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c index 699376c3b3a5..6c2a697556a6 100644 --- a/drivers/tty/serial/sc16is7xx_i2c.c +++ b/drivers/tty/serial/sc16is7xx_i2c.c @@ -39,13 +39,13 @@ static void sc16is7xx_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { - { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, }, - { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, - { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, - { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, - { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { .name = "sc16is74x", .driver_data = (kernel_ulong_t)&sc16is74x_devtype }, + { .name = "sc16is740", .driver_data = (kernel_ulong_t)&sc16is74x_devtype }, + { .name = "sc16is741", .driver_data = (kernel_ulong_t)&sc16is74x_devtype }, + { .name = "sc16is750", .driver_data = (kernel_ulong_t)&sc16is750_devtype }, + { .name = "sc16is752", .driver_data = (kernel_ulong_t)&sc16is752_devtype }, + { .name = "sc16is760", .driver_data = (kernel_ulong_t)&sc16is760_devtype }, + { .name = "sc16is762", .driver_data = (kernel_ulong_t)&sc16is762_devtype }, { } }; MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); From 578b269e2f5c6d990d3970a11ef43606f80dc5f8 Mon Sep 17 00:00:00 2001 From: Praveen Talari Date: Mon, 18 May 2026 23:26:55 +0530 Subject: [PATCH 43/49] serial: qcom-geni: trace: Add tracepoint support for Qualcomm GENI serial Add tracepoint support to the Qualcomm GENI serial driver to provide runtime visibility into driver behavior without requiring invasive debug patches. The trace events cover UART termios configuration, clock setup, modem control state, interrupt status, and TX/RX data, making it easier to diagnose communication issues in the field. Reviewed-by: Konrad Dybcio Signed-off-by: Praveen Talari Link: https://patch.msgid.link/20260518-add-tracepoints-for-qcom-geni-serial-v3-1-b4addb151376@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- include/trace/events/qcom_geni_serial.h | 164 ++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 include/trace/events/qcom_geni_serial.h diff --git a/include/trace/events/qcom_geni_serial.h b/include/trace/events/qcom_geni_serial.h new file mode 100644 index 000000000000..417ec01f9fc8 --- /dev/null +++ b/include/trace/events/qcom_geni_serial.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM qcom_geni_serial + +#if !defined(_TRACE_QCOM_GENI_SERIAL_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_QCOM_GENI_SERIAL_H + +#include +#include + +TRACE_EVENT(geni_serial_set_termios, + TP_PROTO(struct device *dev, unsigned int baud, + unsigned int bits_per_char, u32 tx_trans_cfg, + u32 tx_parity_cfg, u32 rx_trans_cfg, + u32 rx_parity_cfg, u32 stop_bit_len), + TP_ARGS(dev, baud, bits_per_char, tx_trans_cfg, tx_parity_cfg, + rx_trans_cfg, rx_parity_cfg, stop_bit_len), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(unsigned int, baud) + __field(unsigned int, bits_per_char) + __field(u32, tx_trans_cfg) + __field(u32, tx_parity_cfg) + __field(u32, rx_trans_cfg) + __field(u32, rx_parity_cfg) + __field(u32, stop_bit_len) + ), + + TP_fast_assign(__assign_str(name); + __entry->baud = baud; + __entry->bits_per_char = bits_per_char; + __entry->tx_trans_cfg = tx_trans_cfg; + __entry->tx_parity_cfg = tx_parity_cfg; + __entry->rx_trans_cfg = rx_trans_cfg; + __entry->rx_parity_cfg = rx_parity_cfg; + __entry->stop_bit_len = stop_bit_len; + ), + + TP_printk("%s: baud=%u bpc=%u tx_trans=0x%08x tx_par=0x%08x rx_trans=0x%08x rx_par=0x%08x stop=%u", + __get_str(name), __entry->baud, __entry->bits_per_char, + __entry->tx_trans_cfg, __entry->tx_parity_cfg, + __entry->rx_trans_cfg, __entry->rx_parity_cfg, + __entry->stop_bit_len) +); + +TRACE_EVENT(geni_serial_clk_cfg, + TP_PROTO(struct device *dev, unsigned int desired_rate, + unsigned long clk_rate, unsigned int clk_div, + unsigned int clk_idx), + TP_ARGS(dev, desired_rate, clk_rate, clk_div, clk_idx), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(unsigned int, desired_rate) + __field(unsigned long, clk_rate) + __field(unsigned int, clk_div) + __field(unsigned int, clk_idx) + ), + + TP_fast_assign(__assign_str(name); + __entry->desired_rate = desired_rate; + __entry->clk_rate = clk_rate; + __entry->clk_div = clk_div; + __entry->clk_idx = clk_idx; + ), + + TP_printk("%s: desired_rate=%u clk_rate=%lu clk_div=%u clk_idx=%u", + __get_str(name), __entry->desired_rate, __entry->clk_rate, + __entry->clk_div, __entry->clk_idx) +); + +TRACE_EVENT(geni_serial_irq, + TP_PROTO(struct device *dev, u32 m_irq, u32 s_irq, + u32 dma_tx, u32 dma_rx), + TP_ARGS(dev, m_irq, s_irq, dma_tx, dma_rx), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(u32, m_irq) + __field(u32, s_irq) + __field(u32, dma_tx) + __field(u32, dma_rx) + ), + + TP_fast_assign(__assign_str(name); + __entry->m_irq = m_irq; + __entry->s_irq = s_irq; + __entry->dma_tx = dma_tx; + __entry->dma_rx = dma_rx; + ), + + TP_printk("%s: m_irq=0x%08x s_irq=0x%08x dma_tx=0x%08x dma_rx=0x%08x", + __get_str(name), __entry->m_irq, __entry->s_irq, + __entry->dma_tx, __entry->dma_rx) +); + +DECLARE_EVENT_CLASS(geni_serial_data, + TP_PROTO(struct device *dev, const u8 *buf, unsigned int len), + TP_ARGS(dev, buf, len), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(unsigned int, len) + __dynamic_array(u8, data, len) + ), + + TP_fast_assign(__assign_str(name); + __entry->len = len; + memcpy(__get_dynamic_array(data), buf, len); + ), + + TP_printk("%s: len=%u data=%s", + __get_str(name), __entry->len, + __print_hex(__get_dynamic_array(data), __entry->len)) +); + +DEFINE_EVENT(geni_serial_data, geni_serial_tx_data, + TP_PROTO(struct device *dev, const u8 *buf, unsigned int len), + TP_ARGS(dev, buf, len) +); + +DEFINE_EVENT(geni_serial_data, geni_serial_rx_data, + TP_PROTO(struct device *dev, const u8 *buf, unsigned int len), + TP_ARGS(dev, buf, len) +); + +TRACE_EVENT(geni_serial_set_mctrl, + TP_PROTO(struct device *dev, unsigned int mctrl, + u32 uart_manual_rfr), + TP_ARGS(dev, mctrl, uart_manual_rfr), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(unsigned int, mctrl) + __field(u32, uart_manual_rfr) + ), + + TP_fast_assign(__assign_str(name); + __entry->mctrl = mctrl; + __entry->uart_manual_rfr = uart_manual_rfr; + ), + + TP_printk("%s: mctrl=0x%04x uart_manual_rfr=0x%08x", + __get_str(name), __entry->mctrl, __entry->uart_manual_rfr) +); + +TRACE_EVENT(geni_serial_get_mctrl, + TP_PROTO(struct device *dev, unsigned int mctrl, u32 geni_ios), + TP_ARGS(dev, mctrl, geni_ios), + + TP_STRUCT__entry(__string(name, dev_name(dev)) + __field(unsigned int, mctrl) + __field(u32, geni_ios) + ), + + TP_fast_assign(__assign_str(name); + __entry->mctrl = mctrl; + __entry->geni_ios = geni_ios; + ), + + TP_printk("%s: mctrl=0x%04x geni_ios=0x%08x", + __get_str(name), __entry->mctrl, __entry->geni_ios) +); + +#endif /* _TRACE_QCOM_GENI_SERIAL_H */ + +/* This part must be outside protection */ +#include From 5aaaf31af7d61c20b283dba9e84faf0d10fb265b Mon Sep 17 00:00:00 2001 From: Akash Sukhavasi Date: Thu, 21 May 2026 11:21:35 -0500 Subject: [PATCH 44/49] dt-bindings: serial: rs485: remove deprecated .txt binding stub The plain text binding file was superseded by the YAML schema in commit d50f974c4f7f ("dt-bindings: serial: Convert rs485 bindings to json-schema"). The file now contains only a redirect notice. Remove it, and update references in serial_core.c and serial-rs485.rst to point to the YAML schema. Signed-off-by: Akash Sukhavasi Acked-by: Conor Dooley Link: https://patch.msgid.link/20260521162137.6325-1-akash.sukhavasi@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/rs485.txt | 1 - Documentation/driver-api/serial/serial-rs485.rst | 2 +- drivers/tty/serial/serial_core.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 Documentation/devicetree/bindings/serial/rs485.txt diff --git a/Documentation/devicetree/bindings/serial/rs485.txt b/Documentation/devicetree/bindings/serial/rs485.txt deleted file mode 100644 index a7fe93efc4a5..000000000000 --- a/Documentation/devicetree/bindings/serial/rs485.txt +++ /dev/null @@ -1 +0,0 @@ -See rs485.yaml diff --git a/Documentation/driver-api/serial/serial-rs485.rst b/Documentation/driver-api/serial/serial-rs485.rst index dce061ef7647..f53043d21071 100644 --- a/Documentation/driver-api/serial/serial-rs485.rst +++ b/Documentation/driver-api/serial/serial-rs485.rst @@ -132,4 +132,4 @@ RS485 Serial Communications 6. References ============= -.. [#DT-bindings] Documentation/devicetree/bindings/serial/rs485.txt +.. [#DT-bindings] Documentation/devicetree/bindings/serial/rs485.yaml diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 98ace5c492fa..a530ad372b43 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3511,7 +3511,7 @@ EXPORT_SYMBOL_GPL(uart_try_toggle_sysrq); * @port: uart device's target port * * This function implements the device tree binding described in - * Documentation/devicetree/bindings/serial/rs485.txt. + * Documentation/devicetree/bindings/serial/rs485.yaml. */ int uart_get_rs485_mode(struct uart_port *port) { From 0c6bf45e5a345cc3b9ffbeaf9083ecac3c2293eb Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Tue, 19 May 2026 11:57:00 +0200 Subject: [PATCH 45/49] serial: 8250: fix possible ISR soft lockup There are rare cases in which the host gets stuck in the ISR because it is flooded with messages during the startup phase. The reason for the soft lockup in the ISR is the missing FIFO error IRQ (FIFOE) handling. Not handling it and reporting IRQ_HANDLED triggers the IRQ immediately again. Fix this by adding a check for the FIFOE status and clearing the FIFO if no data is ready (DR). This behavior was observed on an AM62L device which uses the OMAP 8250 driver. Fix it for all 8250 drivers, since the OMAP driver's special IRQ setup handling may trigger this behavior more frequently, but it is not ensured that other 8250 drivers aren't affected. Signed-off-by: Marco Felsch Link: https://patch.msgid.link/20260519-v7-1-topic-serial-8250-v1-1-56b04293a246@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index ef245114105b..141229b9bc17 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1799,6 +1799,13 @@ void serial8250_handle_irq_locked(struct uart_port *port, unsigned int iir) status = serial_lsr_in(up); + /* + * Recover from no-data-ready and FIFO error condition to avoid getting + * stuck in the ISR. + */ + if (!(status & UART_LSR_DR) && (status & UART_LSR_FIFOE)) + serial8250_clear_and_reinit_fifos(up); + /* * If port is stopped and there are no error conditions in the * FIFO, then don't drain the FIFO, as this may lead to TTY buffer From 255dc0ec0b79c354bff017f6d6202adaa092a1c9 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 14 May 2026 23:48:57 -0400 Subject: [PATCH 46/49] vt: merge ucs_is_zero_width()/ucs_is_double_width() into ucs_get_width() The hot path in vc_process_ucs() asks two independent questions about the same code point -- "is it double-width?" and "is it zero-width?" -- and was answering each with its own bsearch over its own table. For anything past the leading bounds check that meant two scans of the BMP width tables back to back for what is logically a single lookup. Replace both with one ucs_get_width(cp) returning 0, 1, or 2 in a single bsearch, while keeping the total table footprint at the same 2384 B as before. To do so, merge the zero-width and double-width ranges per region into one sorted-by-`first` table. BMP entries stay 4 bytes; per-entry width is hosted in spare bits of the non-BMP table's `last` field. Non-BMP code points use only 20 of 32 bits, so each u32 has 12 unused high bits. Store first/last shifted left by 12 and use the low 12 bits of `last` for metadata: bit 11 is this entry's own width flag, bits 0..7 host an 8-bit chunk of the BMP double-width bitmap. Because the metadata bits sit strictly below the lowest cp-scale bit, the bsearch comparator remains a plain u32 compare on shifted keys with no masking. In vc_process_ucs() the overwhelmingly common single-width path now collapses to a single predicted branch: if (likely(w == 1)) return 1; Note: scripts/checkpatch.pl complains about "Macros with complex values should be enclosed in parentheses" for the BMP_*WIDTH and RANGE_*WIDTH macros. They are deliberately defined to expand to a comma-separated (first, last) pair so they can populate the two adjacent fields of a struct initializer; wrapping them in parentheses would turn that into a comma-expression and defeat the whole construction. Please ignore. Signed-off-by: Nicolas Pitre Link: https://patch.msgid.link/20260515034857.2514225-1-nico@fluxnic.net Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/gen_ucs_width_table.py | 119 ++- drivers/tty/vt/ucs.c | 174 +++-- drivers/tty/vt/ucs_width_table.h_shipped | 919 ++++++++++++----------- drivers/tty/vt/vt.c | 11 +- include/linux/consolemap.h | 12 +- 5 files changed, 678 insertions(+), 557 deletions(-) diff --git a/drivers/tty/vt/gen_ucs_width_table.py b/drivers/tty/vt/gen_ucs_width_table.py index 76e80ebeff13..4d2476842750 100755 --- a/drivers/tty/vt/gen_ucs_width_table.py +++ b/drivers/tty/vt/gen_ucs_width_table.py @@ -190,12 +190,23 @@ def write_tables(zero_width_ranges, double_width_ranges, out_file=DEFAULT_OUT_FI """ Write the generated tables to C header file. + The output uses a single sorted-by-`first` table per region (BMP and + non-BMP), with zero-width and double-width ranges merged together. The + non-BMP table also hosts the BMP double-width bitmap in spare bits of + `last`. See the encoding comment at the top of ucs.c for the layout. + Args: zero_width_ranges: List of (start, end) ranges for zero-width characters double_width_ranges: List of (start, end) ranges for double-width characters out_file: Output file name (default: DEFAULT_OUT_FILE) """ + # Bits per BMP-bitmap chunk hosted in one non-BMP entry's `last` field. + # 8 bits makes `idx / BITS_PER_CHUNK` / `idx % BITS_PER_CHUNK` compile to + # a cheap shift+mask in the lookup. The chunk size is also emitted as + # UCS_NONBMP_BMP_BITS in the generated header so ucs.c stays in sync. + BITS_PER_CHUNK = 8 + # Function to split ranges into BMP (16-bit) and non-BMP (above 16-bit) def split_ranges_by_size(ranges): bmp_ranges = [] @@ -217,6 +228,40 @@ def write_tables(zero_width_ranges, double_width_ranges, out_file=DEFAULT_OUT_FI zero_width_bmp, zero_width_non_bmp = split_ranges_by_size(zero_width_ranges) double_width_bmp, double_width_non_bmp = split_ranges_by_size(double_width_ranges) + # Merge zero- and double-width ranges per region, tagging each with its + # width, then sort by `first` so binary search works on the union. + bmp_entries = sorted( + [(s, e, 0) for s, e in zero_width_bmp] + + [(s, e, 2) for s, e in double_width_bmp], + key=lambda t: t[0]) + nonbmp_entries = sorted( + [(s, e, 0) for s, e in zero_width_non_bmp] + + [(s, e, 2) for s, e in double_width_non_bmp], + key=lambda t: t[0]) + + # Build the BMP double-width bitmap: one bit per BMP entry (in sort + # order), set iff that entry is double-width. Pack into BITS_PER_CHUNK- + # wide chunks, with bit j of the chunk corresponding to entry + # (chunk_index * BITS_PER_CHUNK + j). + bmp_w2_bits = [1 if w == 2 else 0 for _, _, w in bmp_entries] + n_chunks = (len(bmp_w2_bits) + BITS_PER_CHUNK - 1) // BITS_PER_CHUNK + + if n_chunks > len(nonbmp_entries): + raise RuntimeError( + f"BMP bitmap needs {n_chunks} host entries, " + f"but only {len(nonbmp_entries)} non-BMP entries are available") + + chunks = [] # list of (base_index, end_index, packed_value) + for c in range(n_chunks): + base = c * BITS_PER_CHUNK + end_idx = min(base + BITS_PER_CHUNK - 1, len(bmp_w2_bits) - 1) + value = 0 + for j in range(BITS_PER_CHUNK): + k = base + j + if k < len(bmp_w2_bits) and bmp_w2_bits[k]: + value |= 1 << j + chunks.append((base, end_idx, value)) + # Function to generate code point description comments def get_code_point_comment(start, end): try: @@ -242,48 +287,47 @@ def write_tables(zero_width_ranges, double_width_ranges, out_file=DEFAULT_OUT_FI * Auto-generated by {this_file} * * Unicode Version: {unicodedata.unidata_version} + * + * Zero-width and double-width ranges are merged into one sorted-by-`first` + * table per region. The non-BMP table additionally hosts the BMP + * double-width bitmap in the low {BITS_PER_CHUNK} bits of `last` of its + * first {n_chunks} entries (covering {len(bmp_w2_bits)} BMP entries). + * See ucs.c for the encoding details and the lookup code. */ -/* Zero-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */ -static const struct ucs_interval16 ucs_zero_width_bmp_ranges[] = {{ +/* Bits per BMP-bitmap chunk hosted in one non-BMP entry's `last` field. */ +#define UCS_NONBMP_BMP_BITS {BITS_PER_CHUNK} + +/* Combined zero- and double-width ranges + * (BMP - Basic Multilingual Plane, U+0000 to U+FFFF). */ +static const struct ucs_width16 ucs_bmp_ranges[] = {{ """) - for start, end in zero_width_bmp: - comment = get_code_point_comment(start, end) - f.write(f"\t{{ 0x{start:04X}, 0x{end:04X} }}, {comment}\n") + for s, e, w in bmp_entries: + macro = "BMP_0WIDTH" if w == 0 else "BMP_2WIDTH" + comment = get_code_point_comment(s, e) + f.write(f"\t{{ {macro}(0x{s:04X}, 0x{e:04X}) }}, {comment}\n") - f.write("""\ -}; + f.write(f"""\ +}}; -/* Zero-width character ranges (non-BMP, U+10000 and above) */ -static const struct ucs_interval32 ucs_zero_width_non_bmp_ranges[] = { +/* Combined zero- and double-width ranges (non-BMP, U+10000 and above). + * The first {n_chunks} entries host the BMP double-width bitmap in the low + * {BITS_PER_CHUNK} bits of `last`. */ +static const struct ucs_width32 ucs_nonbmp_ranges[] = {{ """) - for start, end in zero_width_non_bmp: - comment = get_code_point_comment(start, end) - f.write(f"\t{{ 0x{start:05X}, 0x{end:05X} }}, {comment}\n") - - f.write("""\ -}; - -/* Double-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */ -static const struct ucs_interval16 ucs_double_width_bmp_ranges[] = { -""") - - for start, end in double_width_bmp: - comment = get_code_point_comment(start, end) - f.write(f"\t{{ 0x{start:04X}, 0x{end:04X} }}, {comment}\n") - - f.write("""\ -}; - -/* Double-width character ranges (non-BMP, U+10000 and above) */ -static const struct ucs_interval32 ucs_double_width_non_bmp_ranges[] = { -""") - - for start, end in double_width_non_bmp: - comment = get_code_point_comment(start, end) - f.write(f"\t{{ 0x{start:05X}, 0x{end:05X} }}, {comment}\n") + for i, (s, e, w) in enumerate(nonbmp_entries): + macro = "RANGE_0WIDTH" if w == 0 else "RANGE_2WIDTH" + comment = get_code_point_comment(s, e) + if i < len(chunks): + base, end_idx, value = chunks[i] + f.write( + f"\t{{ {macro}(0x{s:05X}, 0x{e:05X}) {comment}\n" + f"\t | BMP_2W_BITS(0b{value:0{BITS_PER_CHUNK}b}) }}," + f" /* BMP entries [{base:>3}..{end_idx:>3}] */\n") + else: + f.write(f"\t{{ {macro}(0x{s:05X}, 0x{e:05X}) }}, {comment}\n") f.write("};\n") @@ -301,7 +345,10 @@ if __name__ == "__main__": # Print summary zero_width_count = sum(end - start + 1 for start, end in zero_width_ranges) double_width_count = sum(end - start + 1 for start, end in double_width_ranges) + n_zero = len(zero_width_ranges) + n_double = len(double_width_ranges) print(f"Generated {args.output_file} with:") - print(f"- {len(zero_width_ranges)} zero-width ranges covering ~{zero_width_count} code points") - print(f"- {len(double_width_ranges)} double-width ranges covering ~{double_width_count} code points") + print(f"- {n_zero} zero-width ranges covering ~{zero_width_count} code points") + print(f"- {n_double} double-width ranges covering ~{double_width_count} code points") + print(f"- {n_zero + n_double} merged ranges total") print(f"- Unicode Version: {unicodedata.unidata_version}") diff --git a/drivers/tty/vt/ucs.c b/drivers/tty/vt/ucs.c index 03877485dfb7..fc41c0bb5d7b 100644 --- a/drivers/tty/vt/ucs.c +++ b/drivers/tty/vt/ucs.c @@ -4,96 +4,138 @@ */ #include +#include #include #include -#include +#include -struct ucs_interval16 { +struct ucs_width16 { u16 first; u16 last; }; -struct ucs_interval32 { +struct ucs_width32 { u32 first; u32 last; }; +/* + * Width table encoding (consumed by ucs_width_table.h): + * + * Zero- and double-width ranges are merged into one sorted-by-`first` table + * per region (BMP / non-BMP). The BMP table stores plain (first, last) + * pairs; per-entry width lives in a packed bitmap *hosted by the non-BMP + * table*. + * + * That hosting is the whole point of the encoding. Non-BMP code points use + * only 20 bits, so each u32 has 12 spare high bits sitting around doing + * nothing — we'd rather use them than spend a separate parallel array for + * width and BMP-bitmap bits. So we move the cp value up by UCS_CP_SHIFT + * and stash metadata in the now-free low bits of `last`: + * - bit UCS_NONBMP_W2_FLAG_BIT: this entry's own width (0=zero, 1=double), + * - bits 0..UCS_NONBMP_BMP_BITS-1: a chunk of the BMP double-width + * bitmap. Bit `j` of the chunk in non-BMP entry `c` is set iff BMP + * entry (c * UCS_NONBMP_BMP_BITS + j) is double-width. The first + * ceil(N_BMP / UCS_NONBMP_BMP_BITS) non-BMP entries carry the bitmap; + * the rest leave these bits zero. + * + * Because the metadata bits sit strictly below the lowest cp-scale bit, + * the bsearch comparator does plain u32 comparison on the shifted key and + * stored values without masking — ordering between distinct code points is + * undisturbed. + */ +#define UCS_CP_SHIFT 12 +#define UCS_NONBMP_W2_FLAG_BIT 11 +#define UCS_NONBMP_W2_FLAG (1u << UCS_NONBMP_W2_FLAG_BIT) + +#define BMP_0WIDTH(first, last) first, last +#define BMP_2WIDTH(first, last) first, last +#define RANGE_0WIDTH(first, last) \ + (u32)(first) << UCS_CP_SHIFT, (u32)(last) << UCS_CP_SHIFT +#define RANGE_2WIDTH(first, last) \ + (u32)(first) << UCS_CP_SHIFT, ((u32)(last) << UCS_CP_SHIFT) | UCS_NONBMP_W2_FLAG +#define BMP_2W_BITS(b) (b) + #include "ucs_width_table.h" -static int interval16_cmp(const void *key, const void *element) -{ - u16 cp = *(u16 *)key; - const struct ucs_interval16 *entry = element; - - if (cp < entry->first) - return -1; - if (cp > entry->last) - return 1; - return 0; -} - -static int interval32_cmp(const void *key, const void *element) -{ - u32 cp = *(u32 *)key; - const struct ucs_interval32 *entry = element; - - if (cp < entry->first) - return -1; - if (cp > entry->last) - return 1; - return 0; -} - -static bool cp_in_range16(u16 cp, const struct ucs_interval16 *ranges, size_t size) -{ - if (cp < ranges[0].first || cp > ranges[size - 1].last) - return false; - - return __inline_bsearch(&cp, ranges, size, sizeof(*ranges), - interval16_cmp) != NULL; -} - -static bool cp_in_range32(u32 cp, const struct ucs_interval32 *ranges, size_t size) -{ - if (cp < ranges[0].first || cp > ranges[size - 1].last) - return false; - - return __inline_bsearch(&cp, ranges, size, sizeof(*ranges), - interval32_cmp) != NULL; -} +static_assert(UCS_NONBMP_BMP_BITS <= UCS_NONBMP_W2_FLAG_BIT, + "BMP bitmap chunk would overlap the per-entry width flag"); +static_assert(UCS_NONBMP_W2_FLAG_BIT < UCS_CP_SHIFT, + "Metadata bits collide with the shifted cp value"); +static_assert(DIV_ROUND_UP(ARRAY_SIZE(ucs_bmp_ranges), UCS_NONBMP_BMP_BITS) + <= ARRAY_SIZE(ucs_nonbmp_ranges), + "Not enough non-BMP entries to host the BMP width bitmap"); #define UCS_IS_BMP(cp) ((cp) <= 0xffff) -/** - * ucs_is_zero_width() - Determine if a Unicode code point is zero-width. - * @cp: Unicode code point (UCS-4) - * - * Return: true if the character is zero-width, false otherwise - */ -bool ucs_is_zero_width(u32 cp) +static int width16_cmp(const void *key, const void *element) { - if (UCS_IS_BMP(cp)) - return cp_in_range16(cp, ucs_zero_width_bmp_ranges, - ARRAY_SIZE(ucs_zero_width_bmp_ranges)); - else - return cp_in_range32(cp, ucs_zero_width_non_bmp_ranges, - ARRAY_SIZE(ucs_zero_width_non_bmp_ranges)); + u16 cp = *(u16 *)key; + const struct ucs_width16 *entry = element; + + if (cp < entry->first) + return -1; + if (cp > entry->last) + return 1; + return 0; +} + +static int width32_cmp(const void *key, const void *element) +{ + u32 k = *(u32 *)key; + const struct ucs_width32 *entry = element; + + if (k < entry->first) + return -1; + if (k > entry->last) + return 1; + return 0; } /** - * ucs_is_double_width() - Determine if a Unicode code point is double-width. + * ucs_get_width() - Get the display width of a Unicode code point. * @cp: Unicode code point (UCS-4) * - * Return: true if the character is double-width, false otherwise + * Return: 2 for double-width (East Asian Wide/Fullwidth, emoji, ...), + * 0 for zero-width (combining marks, format characters, ...), + * 1 for everything else (the common case). */ -bool ucs_is_double_width(u32 cp) +unsigned int ucs_get_width(u32 cp) { - if (UCS_IS_BMP(cp)) - return cp_in_range16(cp, ucs_double_width_bmp_ranges, - ARRAY_SIZE(ucs_double_width_bmp_ranges)); - else - return cp_in_range32(cp, ucs_double_width_non_bmp_ranges, - ARRAY_SIZE(ucs_double_width_non_bmp_ranges)); + const struct ucs_width16 *e16; + const struct ucs_width32 *e32; + unsigned int idx; + u32 k; + + if (UCS_IS_BMP(cp)) { + u16 bmp = cp; + + if (bmp < ucs_bmp_ranges[0].first || + bmp > ucs_bmp_ranges[ARRAY_SIZE(ucs_bmp_ranges) - 1].last) + return 1; + + e16 = __inline_bsearch(&bmp, ucs_bmp_ranges, + ARRAY_SIZE(ucs_bmp_ranges), + sizeof(*ucs_bmp_ranges), width16_cmp); + if (!e16) + return 1; + + idx = e16 - ucs_bmp_ranges; + return (ucs_nonbmp_ranges[idx / UCS_NONBMP_BMP_BITS].last + >> (idx % UCS_NONBMP_BMP_BITS)) & 1 ? 2 : 0; + } + + k = cp << UCS_CP_SHIFT; + if (k < ucs_nonbmp_ranges[0].first || + k > ucs_nonbmp_ranges[ARRAY_SIZE(ucs_nonbmp_ranges) - 1].last) + return 1; + + e32 = __inline_bsearch(&k, ucs_nonbmp_ranges, + ARRAY_SIZE(ucs_nonbmp_ranges), + sizeof(*ucs_nonbmp_ranges), width32_cmp); + if (!e32) + return 1; + return (e32->last & UCS_NONBMP_W2_FLAG) ? 2 : 0; } /* diff --git a/drivers/tty/vt/ucs_width_table.h_shipped b/drivers/tty/vt/ucs_width_table.h_shipped index 6fcb8f1d577d..5cd6434bf329 100644 --- a/drivers/tty/vt/ucs_width_table.h_shipped +++ b/drivers/tty/vt/ucs_width_table.h_shipped @@ -5,449 +5,486 @@ * Auto-generated by gen_ucs_width_table.py * * Unicode Version: 16.0.0 + * + * Zero-width and double-width ranges are merged into one sorted-by-`first` + * table per region. The non-BMP table additionally hosts the BMP + * double-width bitmap in the low 8 bits of `last` of its + * first 33 entries (covering 262 BMP entries). + * See ucs.c for the encoding details and the lookup code. */ -/* Zero-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */ -static const struct ucs_interval16 ucs_zero_width_bmp_ranges[] = { - { 0x00AD, 0x00AD }, /* SOFT HYPHEN */ - { 0x0300, 0x036F }, /* COMBINING GRAVE ACCENT - COMBINING LATIN SMALL LETTER X */ - { 0x0483, 0x0489 }, /* COMBINING CYRILLIC TITLO - COMBINING CYRILLIC MILLIONS SIGN */ - { 0x0591, 0x05BD }, /* HEBREW ACCENT ETNAHTA - HEBREW POINT METEG */ - { 0x05BF, 0x05BF }, /* HEBREW POINT RAFE */ - { 0x05C1, 0x05C2 }, /* HEBREW POINT SHIN DOT - HEBREW POINT SIN DOT */ - { 0x05C4, 0x05C5 }, /* HEBREW MARK UPPER DOT - HEBREW MARK LOWER DOT */ - { 0x05C7, 0x05C7 }, /* HEBREW POINT QAMATS QATAN */ - { 0x0600, 0x0605 }, /* ARABIC NUMBER SIGN - ARABIC NUMBER MARK ABOVE */ - { 0x0610, 0x061A }, /* ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM - ARABIC SMALL KASRA */ - { 0x061C, 0x061C }, /* ARABIC LETTER MARK */ - { 0x064B, 0x065F }, /* ARABIC FATHATAN - ARABIC WAVY HAMZA BELOW */ - { 0x0670, 0x0670 }, /* ARABIC LETTER SUPERSCRIPT ALEF */ - { 0x06D6, 0x06DD }, /* ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA - ARABIC END OF AYAH */ - { 0x06DF, 0x06E4 }, /* ARABIC SMALL HIGH ROUNDED ZERO - ARABIC SMALL HIGH MADDA */ - { 0x06E7, 0x06E8 }, /* ARABIC SMALL HIGH YEH - ARABIC SMALL HIGH NOON */ - { 0x06EA, 0x06ED }, /* ARABIC EMPTY CENTRE LOW STOP - ARABIC SMALL LOW MEEM */ - { 0x070F, 0x070F }, /* SYRIAC ABBREVIATION MARK */ - { 0x0711, 0x0711 }, /* SYRIAC LETTER SUPERSCRIPT ALAPH */ - { 0x0730, 0x074A }, /* SYRIAC PTHAHA ABOVE - SYRIAC BARREKH */ - { 0x07A6, 0x07B0 }, /* THAANA ABAFILI - THAANA SUKUN */ - { 0x07EB, 0x07F3 }, /* NKO COMBINING SHORT HIGH TONE - NKO COMBINING DOUBLE DOT ABOVE */ - { 0x07FD, 0x07FD }, /* NKO DANTAYALAN */ - { 0x0816, 0x0819 }, /* SAMARITAN MARK IN - SAMARITAN MARK DAGESH */ - { 0x081B, 0x0823 }, /* SAMARITAN MARK EPENTHETIC YUT - SAMARITAN VOWEL SIGN A */ - { 0x0825, 0x0827 }, /* SAMARITAN VOWEL SIGN SHORT A - SAMARITAN VOWEL SIGN U */ - { 0x0829, 0x082D }, /* SAMARITAN VOWEL SIGN LONG I - SAMARITAN MARK NEQUDAA */ - { 0x0859, 0x085B }, /* MANDAIC AFFRICATION MARK - MANDAIC GEMINATION MARK */ - { 0x0890, 0x0891 }, /* ARABIC POUND MARK ABOVE - ARABIC PIASTRE MARK ABOVE */ - { 0x0897, 0x089F }, /* ARABIC PEPET - ARABIC HALF MADDA OVER MADDA */ - { 0x08CA, 0x0903 }, /* ARABIC SMALL HIGH FARSI YEH - DEVANAGARI SIGN VISARGA */ - { 0x093A, 0x093C }, /* DEVANAGARI VOWEL SIGN OE - DEVANAGARI SIGN NUKTA */ - { 0x093E, 0x094F }, /* DEVANAGARI VOWEL SIGN AA - DEVANAGARI VOWEL SIGN AW */ - { 0x0951, 0x0957 }, /* DEVANAGARI STRESS SIGN UDATTA - DEVANAGARI VOWEL SIGN UUE */ - { 0x0962, 0x0963 }, /* DEVANAGARI VOWEL SIGN VOCALIC L - DEVANAGARI VOWEL SIGN VOCALIC LL */ - { 0x0981, 0x0983 }, /* BENGALI SIGN CANDRABINDU - BENGALI SIGN VISARGA */ - { 0x09BC, 0x09BC }, /* BENGALI SIGN NUKTA */ - { 0x09BE, 0x09C4 }, /* BENGALI VOWEL SIGN AA - BENGALI VOWEL SIGN VOCALIC RR */ - { 0x09C7, 0x09C8 }, /* BENGALI VOWEL SIGN E - BENGALI VOWEL SIGN AI */ - { 0x09CB, 0x09CD }, /* BENGALI VOWEL SIGN O - BENGALI SIGN VIRAMA */ - { 0x09D7, 0x09D7 }, /* BENGALI AU LENGTH MARK */ - { 0x09E2, 0x09E3 }, /* BENGALI VOWEL SIGN VOCALIC L - BENGALI VOWEL SIGN VOCALIC LL */ - { 0x09FE, 0x09FE }, /* BENGALI SANDHI MARK */ - { 0x0A01, 0x0A03 }, /* GURMUKHI SIGN ADAK BINDI - GURMUKHI SIGN VISARGA */ - { 0x0A3C, 0x0A3C }, /* GURMUKHI SIGN NUKTA */ - { 0x0A3E, 0x0A42 }, /* GURMUKHI VOWEL SIGN AA - GURMUKHI VOWEL SIGN UU */ - { 0x0A47, 0x0A48 }, /* GURMUKHI VOWEL SIGN EE - GURMUKHI VOWEL SIGN AI */ - { 0x0A4B, 0x0A4D }, /* GURMUKHI VOWEL SIGN OO - GURMUKHI SIGN VIRAMA */ - { 0x0A51, 0x0A51 }, /* GURMUKHI SIGN UDAAT */ - { 0x0A70, 0x0A71 }, /* GURMUKHI TIPPI - GURMUKHI ADDAK */ - { 0x0A75, 0x0A75 }, /* GURMUKHI SIGN YAKASH */ - { 0x0A81, 0x0A83 }, /* GUJARATI SIGN CANDRABINDU - GUJARATI SIGN VISARGA */ - { 0x0ABC, 0x0ABC }, /* GUJARATI SIGN NUKTA */ - { 0x0ABE, 0x0AC5 }, /* GUJARATI VOWEL SIGN AA - GUJARATI VOWEL SIGN CANDRA E */ - { 0x0AC7, 0x0AC9 }, /* GUJARATI VOWEL SIGN E - GUJARATI VOWEL SIGN CANDRA O */ - { 0x0ACB, 0x0ACD }, /* GUJARATI VOWEL SIGN O - GUJARATI SIGN VIRAMA */ - { 0x0AE2, 0x0AE3 }, /* GUJARATI VOWEL SIGN VOCALIC L - GUJARATI VOWEL SIGN VOCALIC LL */ - { 0x0AFA, 0x0AFF }, /* GUJARATI SIGN SUKUN - GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE */ - { 0x0B01, 0x0B03 }, /* ORIYA SIGN CANDRABINDU - ORIYA SIGN VISARGA */ - { 0x0B3C, 0x0B3C }, /* ORIYA SIGN NUKTA */ - { 0x0B3E, 0x0B44 }, /* ORIYA VOWEL SIGN AA - ORIYA VOWEL SIGN VOCALIC RR */ - { 0x0B47, 0x0B48 }, /* ORIYA VOWEL SIGN E - ORIYA VOWEL SIGN AI */ - { 0x0B4B, 0x0B4D }, /* ORIYA VOWEL SIGN O - ORIYA SIGN VIRAMA */ - { 0x0B55, 0x0B57 }, /* ORIYA SIGN OVERLINE - ORIYA AU LENGTH MARK */ - { 0x0B62, 0x0B63 }, /* ORIYA VOWEL SIGN VOCALIC L - ORIYA VOWEL SIGN VOCALIC LL */ - { 0x0B82, 0x0B82 }, /* TAMIL SIGN ANUSVARA */ - { 0x0BBE, 0x0BC2 }, /* TAMIL VOWEL SIGN AA - TAMIL VOWEL SIGN UU */ - { 0x0BC6, 0x0BC8 }, /* TAMIL VOWEL SIGN E - TAMIL VOWEL SIGN AI */ - { 0x0BCA, 0x0BCD }, /* TAMIL VOWEL SIGN O - TAMIL SIGN VIRAMA */ - { 0x0BD7, 0x0BD7 }, /* TAMIL AU LENGTH MARK */ - { 0x0C00, 0x0C04 }, /* TELUGU SIGN COMBINING CANDRABINDU ABOVE - TELUGU SIGN COMBINING ANUSVARA ABOVE */ - { 0x0C3C, 0x0C3C }, /* TELUGU SIGN NUKTA */ - { 0x0C3E, 0x0C44 }, /* TELUGU VOWEL SIGN AA - TELUGU VOWEL SIGN VOCALIC RR */ - { 0x0C46, 0x0C48 }, /* TELUGU VOWEL SIGN E - TELUGU VOWEL SIGN AI */ - { 0x0C4A, 0x0C4D }, /* TELUGU VOWEL SIGN O - TELUGU SIGN VIRAMA */ - { 0x0C55, 0x0C56 }, /* TELUGU LENGTH MARK - TELUGU AI LENGTH MARK */ - { 0x0C62, 0x0C63 }, /* TELUGU VOWEL SIGN VOCALIC L - TELUGU VOWEL SIGN VOCALIC LL */ - { 0x0C81, 0x0C83 }, /* KANNADA SIGN CANDRABINDU - KANNADA SIGN VISARGA */ - { 0x0CBC, 0x0CBC }, /* KANNADA SIGN NUKTA */ - { 0x0CBE, 0x0CC4 }, /* KANNADA VOWEL SIGN AA - KANNADA VOWEL SIGN VOCALIC RR */ - { 0x0CC6, 0x0CC8 }, /* KANNADA VOWEL SIGN E - KANNADA VOWEL SIGN AI */ - { 0x0CCA, 0x0CCD }, /* KANNADA VOWEL SIGN O - KANNADA SIGN VIRAMA */ - { 0x0CD5, 0x0CD6 }, /* KANNADA LENGTH MARK - KANNADA AI LENGTH MARK */ - { 0x0CE2, 0x0CE3 }, /* KANNADA VOWEL SIGN VOCALIC L - KANNADA VOWEL SIGN VOCALIC LL */ - { 0x0CF3, 0x0CF3 }, /* KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT */ - { 0x0D00, 0x0D03 }, /* MALAYALAM SIGN COMBINING ANUSVARA ABOVE - MALAYALAM SIGN VISARGA */ - { 0x0D3B, 0x0D3C }, /* MALAYALAM SIGN VERTICAL BAR VIRAMA - MALAYALAM SIGN CIRCULAR VIRAMA */ - { 0x0D3E, 0x0D44 }, /* MALAYALAM VOWEL SIGN AA - MALAYALAM VOWEL SIGN VOCALIC RR */ - { 0x0D46, 0x0D48 }, /* MALAYALAM VOWEL SIGN E - MALAYALAM VOWEL SIGN AI */ - { 0x0D4A, 0x0D4D }, /* MALAYALAM VOWEL SIGN O - MALAYALAM SIGN VIRAMA */ - { 0x0D57, 0x0D57 }, /* MALAYALAM AU LENGTH MARK */ - { 0x0D62, 0x0D63 }, /* MALAYALAM VOWEL SIGN VOCALIC L - MALAYALAM VOWEL SIGN VOCALIC LL */ - { 0x0D81, 0x0D83 }, /* SINHALA SIGN CANDRABINDU - SINHALA SIGN VISARGAYA */ - { 0x0DCA, 0x0DCA }, /* SINHALA SIGN AL-LAKUNA */ - { 0x0DCF, 0x0DD4 }, /* SINHALA VOWEL SIGN AELA-PILLA - SINHALA VOWEL SIGN KETTI PAA-PILLA */ - { 0x0DD6, 0x0DD6 }, /* SINHALA VOWEL SIGN DIGA PAA-PILLA */ - { 0x0DD8, 0x0DDF }, /* SINHALA VOWEL SIGN GAETTA-PILLA - SINHALA VOWEL SIGN GAYANUKITTA */ - { 0x0DF2, 0x0DF3 }, /* SINHALA VOWEL SIGN DIGA GAETTA-PILLA - SINHALA VOWEL SIGN DIGA GAYANUKITTA */ - { 0x0E31, 0x0E31 }, /* THAI CHARACTER MAI HAN-AKAT */ - { 0x0E34, 0x0E3A }, /* THAI CHARACTER SARA I - THAI CHARACTER PHINTHU */ - { 0x0E47, 0x0E4E }, /* THAI CHARACTER MAITAIKHU - THAI CHARACTER YAMAKKAN */ - { 0x0EB1, 0x0EB1 }, /* LAO VOWEL SIGN MAI KAN */ - { 0x0EB4, 0x0EBC }, /* LAO VOWEL SIGN I - LAO SEMIVOWEL SIGN LO */ - { 0x0EC8, 0x0ECE }, /* LAO TONE MAI EK - LAO YAMAKKAN */ - { 0x0F18, 0x0F19 }, /* TIBETAN ASTROLOGICAL SIGN -KHYUD PA - TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS */ - { 0x0F35, 0x0F35 }, /* TIBETAN MARK NGAS BZUNG NYI ZLA */ - { 0x0F37, 0x0F37 }, /* TIBETAN MARK NGAS BZUNG SGOR RTAGS */ - { 0x0F39, 0x0F39 }, /* TIBETAN MARK TSA -PHRU */ - { 0x0F3E, 0x0F3F }, /* TIBETAN SIGN YAR TSHES - TIBETAN SIGN MAR TSHES */ - { 0x0F71, 0x0F84 }, /* TIBETAN VOWEL SIGN AA - TIBETAN MARK HALANTA */ - { 0x0F86, 0x0F87 }, /* TIBETAN SIGN LCI RTAGS - TIBETAN SIGN YANG RTAGS */ - { 0x0F8D, 0x0F97 }, /* TIBETAN SUBJOINED SIGN LCE TSA CAN - TIBETAN SUBJOINED LETTER JA */ - { 0x0F99, 0x0FBC }, /* TIBETAN SUBJOINED LETTER NYA - TIBETAN SUBJOINED LETTER FIXED-FORM RA */ - { 0x0FC6, 0x0FC6 }, /* TIBETAN SYMBOL PADMA GDAN */ - { 0x102B, 0x103E }, /* MYANMAR VOWEL SIGN TALL AA - MYANMAR CONSONANT SIGN MEDIAL HA */ - { 0x1056, 0x1059 }, /* MYANMAR VOWEL SIGN VOCALIC R - MYANMAR VOWEL SIGN VOCALIC LL */ - { 0x105E, 0x1060 }, /* MYANMAR CONSONANT SIGN MON MEDIAL NA - MYANMAR CONSONANT SIGN MON MEDIAL LA */ - { 0x1062, 0x1064 }, /* MYANMAR VOWEL SIGN SGAW KAREN EU - MYANMAR TONE MARK SGAW KAREN KE PHO */ - { 0x1067, 0x106D }, /* MYANMAR VOWEL SIGN WESTERN PWO KAREN EU - MYANMAR SIGN WESTERN PWO KAREN TONE-5 */ - { 0x1071, 0x1074 }, /* MYANMAR VOWEL SIGN GEBA KAREN I - MYANMAR VOWEL SIGN KAYAH EE */ - { 0x1082, 0x108D }, /* MYANMAR CONSONANT SIGN SHAN MEDIAL WA - MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE */ - { 0x108F, 0x108F }, /* MYANMAR SIGN RUMAI PALAUNG TONE-5 */ - { 0x109A, 0x109D }, /* MYANMAR SIGN KHAMTI TONE-1 - MYANMAR VOWEL SIGN AITON AI */ - { 0x135D, 0x135F }, /* ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK - ETHIOPIC COMBINING GEMINATION MARK */ - { 0x1712, 0x1715 }, /* TAGALOG VOWEL SIGN I - TAGALOG SIGN PAMUDPOD */ - { 0x1732, 0x1734 }, /* HANUNOO VOWEL SIGN I - HANUNOO SIGN PAMUDPOD */ - { 0x1752, 0x1753 }, /* BUHID VOWEL SIGN I - BUHID VOWEL SIGN U */ - { 0x1772, 0x1773 }, /* TAGBANWA VOWEL SIGN I - TAGBANWA VOWEL SIGN U */ - { 0x17B4, 0x17D3 }, /* KHMER VOWEL INHERENT AQ - KHMER SIGN BATHAMASAT */ - { 0x17DD, 0x17DD }, /* KHMER SIGN ATTHACAN */ - { 0x180B, 0x180F }, /* MONGOLIAN FREE VARIATION SELECTOR ONE - MONGOLIAN FREE VARIATION SELECTOR FOUR */ - { 0x1885, 0x1886 }, /* MONGOLIAN LETTER ALI GALI BALUDA - MONGOLIAN LETTER ALI GALI THREE BALUDA */ - { 0x18A9, 0x18A9 }, /* MONGOLIAN LETTER ALI GALI DAGALGA */ - { 0x1920, 0x192B }, /* LIMBU VOWEL SIGN A - LIMBU SUBJOINED LETTER WA */ - { 0x1930, 0x193B }, /* LIMBU SMALL LETTER KA - LIMBU SIGN SA-I */ - { 0x1A17, 0x1A1B }, /* BUGINESE VOWEL SIGN I - BUGINESE VOWEL SIGN AE */ - { 0x1A55, 0x1A5E }, /* TAI THAM CONSONANT SIGN MEDIAL RA - TAI THAM CONSONANT SIGN SA */ - { 0x1A60, 0x1A7C }, /* TAI THAM SIGN SAKOT - TAI THAM SIGN KHUEN-LUE KARAN */ - { 0x1A7F, 0x1A7F }, /* TAI THAM COMBINING CRYPTOGRAMMIC DOT */ - { 0x1AB0, 0x1ACE }, /* COMBINING DOUBLED CIRCUMFLEX ACCENT - COMBINING LATIN SMALL LETTER INSULAR T */ - { 0x1B00, 0x1B04 }, /* BALINESE SIGN ULU RICEM - BALINESE SIGN BISAH */ - { 0x1B34, 0x1B44 }, /* BALINESE SIGN REREKAN - BALINESE ADEG ADEG */ - { 0x1B6B, 0x1B73 }, /* BALINESE MUSICAL SYMBOL COMBINING TEGEH - BALINESE MUSICAL SYMBOL COMBINING GONG */ - { 0x1B80, 0x1B82 }, /* SUNDANESE SIGN PANYECEK - SUNDANESE SIGN PANGWISAD */ - { 0x1BA1, 0x1BAD }, /* SUNDANESE CONSONANT SIGN PAMINGKAL - SUNDANESE CONSONANT SIGN PASANGAN WA */ - { 0x1BE6, 0x1BF3 }, /* BATAK SIGN TOMPI - BATAK PANONGONAN */ - { 0x1C24, 0x1C37 }, /* LEPCHA SUBJOINED LETTER YA - LEPCHA SIGN NUKTA */ - { 0x1CD0, 0x1CD2 }, /* VEDIC TONE KARSHANA - VEDIC TONE PRENKHA */ - { 0x1CD4, 0x1CE8 }, /* VEDIC SIGN YAJURVEDIC MIDLINE SVARITA - VEDIC SIGN VISARGA ANUDATTA WITH TAIL */ - { 0x1CED, 0x1CED }, /* VEDIC SIGN TIRYAK */ - { 0x1CF4, 0x1CF4 }, /* VEDIC TONE CANDRA ABOVE */ - { 0x1CF7, 0x1CF9 }, /* VEDIC SIGN ATIKRAMA - VEDIC TONE DOUBLE RING ABOVE */ - { 0x1DC0, 0x1DFF }, /* COMBINING DOTTED GRAVE ACCENT - COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW */ - { 0x200B, 0x200F }, /* ZERO WIDTH SPACE - RIGHT-TO-LEFT MARK */ - { 0x202A, 0x202E }, /* LEFT-TO-RIGHT EMBEDDING - RIGHT-TO-LEFT OVERRIDE */ - { 0x2060, 0x2064 }, /* WORD JOINER - INVISIBLE PLUS */ - { 0x2066, 0x206F }, /* LEFT-TO-RIGHT ISOLATE - NOMINAL DIGIT SHAPES */ - { 0x20D0, 0x20F0 }, /* COMBINING LEFT HARPOON ABOVE - COMBINING ASTERISK ABOVE */ - { 0x2640, 0x2640 }, /* FEMALE SIGN */ - { 0x2642, 0x2642 }, /* MALE SIGN */ - { 0x26A7, 0x26A7 }, /* MALE WITH STROKE AND MALE AND FEMALE SIGN */ - { 0x2CEF, 0x2CF1 }, /* COPTIC COMBINING NI ABOVE - COPTIC COMBINING SPIRITUS LENIS */ - { 0x2D7F, 0x2D7F }, /* TIFINAGH CONSONANT JOINER */ - { 0x2DE0, 0x2DFF }, /* COMBINING CYRILLIC LETTER BE - COMBINING CYRILLIC LETTER IOTIFIED BIG YUS */ - { 0x302A, 0x302F }, /* IDEOGRAPHIC LEVEL TONE MARK - HANGUL DOUBLE DOT TONE MARK */ - { 0x3099, 0x309A }, /* COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK - COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ - { 0xA66F, 0xA672 }, /* COMBINING CYRILLIC VZMET - COMBINING CYRILLIC THOUSAND MILLIONS SIGN */ - { 0xA674, 0xA67D }, /* COMBINING CYRILLIC LETTER UKRAINIAN IE - COMBINING CYRILLIC PAYEROK */ - { 0xA69E, 0xA69F }, /* COMBINING CYRILLIC LETTER EF - COMBINING CYRILLIC LETTER IOTIFIED E */ - { 0xA6F0, 0xA6F1 }, /* BAMUM COMBINING MARK KOQNDON - BAMUM COMBINING MARK TUKWENTIS */ - { 0xA802, 0xA802 }, /* SYLOTI NAGRI SIGN DVISVARA */ - { 0xA806, 0xA806 }, /* SYLOTI NAGRI SIGN HASANTA */ - { 0xA80B, 0xA80B }, /* SYLOTI NAGRI SIGN ANUSVARA */ - { 0xA823, 0xA827 }, /* SYLOTI NAGRI VOWEL SIGN A - SYLOTI NAGRI VOWEL SIGN OO */ - { 0xA82C, 0xA82C }, /* SYLOTI NAGRI SIGN ALTERNATE HASANTA */ - { 0xA880, 0xA881 }, /* SAURASHTRA SIGN ANUSVARA - SAURASHTRA SIGN VISARGA */ - { 0xA8B4, 0xA8C5 }, /* SAURASHTRA CONSONANT SIGN HAARU - SAURASHTRA SIGN CANDRABINDU */ - { 0xA8E0, 0xA8F1 }, /* COMBINING DEVANAGARI DIGIT ZERO - COMBINING DEVANAGARI SIGN AVAGRAHA */ - { 0xA8FF, 0xA8FF }, /* DEVANAGARI VOWEL SIGN AY */ - { 0xA926, 0xA92D }, /* KAYAH LI VOWEL UE - KAYAH LI TONE CALYA PLOPHU */ - { 0xA947, 0xA953 }, /* REJANG VOWEL SIGN I - REJANG VIRAMA */ - { 0xA980, 0xA983 }, /* JAVANESE SIGN PANYANGGA - JAVANESE SIGN WIGNYAN */ - { 0xA9B3, 0xA9C0 }, /* JAVANESE SIGN CECAK TELU - JAVANESE PANGKON */ - { 0xA9E5, 0xA9E5 }, /* MYANMAR SIGN SHAN SAW */ - { 0xAA29, 0xAA36 }, /* CHAM VOWEL SIGN AA - CHAM CONSONANT SIGN WA */ - { 0xAA43, 0xAA43 }, /* CHAM CONSONANT SIGN FINAL NG */ - { 0xAA4C, 0xAA4D }, /* CHAM CONSONANT SIGN FINAL M - CHAM CONSONANT SIGN FINAL H */ - { 0xAA7B, 0xAA7D }, /* MYANMAR SIGN PAO KAREN TONE - MYANMAR SIGN TAI LAING TONE-5 */ - { 0xAAB0, 0xAAB0 }, /* TAI VIET MAI KANG */ - { 0xAAB2, 0xAAB4 }, /* TAI VIET VOWEL I - TAI VIET VOWEL U */ - { 0xAAB7, 0xAAB8 }, /* TAI VIET MAI KHIT - TAI VIET VOWEL IA */ - { 0xAABE, 0xAABF }, /* TAI VIET VOWEL AM - TAI VIET TONE MAI EK */ - { 0xAAC1, 0xAAC1 }, /* TAI VIET TONE MAI THO */ - { 0xAAEB, 0xAAEF }, /* MEETEI MAYEK VOWEL SIGN II - MEETEI MAYEK VOWEL SIGN AAU */ - { 0xAAF5, 0xAAF6 }, /* MEETEI MAYEK VOWEL SIGN VISARGA - MEETEI MAYEK VIRAMA */ - { 0xABE3, 0xABEA }, /* MEETEI MAYEK VOWEL SIGN ONAP - MEETEI MAYEK VOWEL SIGN NUNG */ - { 0xABEC, 0xABED }, /* MEETEI MAYEK LUM IYEK - MEETEI MAYEK APUN IYEK */ - { 0xFB1E, 0xFB1E }, /* HEBREW POINT JUDEO-SPANISH VARIKA */ - { 0xFE00, 0xFE0F }, /* VARIATION SELECTOR-1 - VARIATION SELECTOR-16 */ - { 0xFE20, 0xFE2F }, /* COMBINING LIGATURE LEFT HALF - COMBINING CYRILLIC TITLO RIGHT HALF */ - { 0xFEFF, 0xFEFF }, /* ZERO WIDTH NO-BREAK SPACE */ - { 0xFFF9, 0xFFFB }, /* INTERLINEAR ANNOTATION ANCHOR - INTERLINEAR ANNOTATION TERMINATOR */ +/* Bits per BMP-bitmap chunk hosted in one non-BMP entry's `last` field. */ +#define UCS_NONBMP_BMP_BITS 8 + +/* Combined zero- and double-width ranges + * (BMP - Basic Multilingual Plane, U+0000 to U+FFFF). */ +static const struct ucs_width16 ucs_bmp_ranges[] = { + { BMP_0WIDTH(0x00AD, 0x00AD) }, /* SOFT HYPHEN */ + { BMP_0WIDTH(0x0300, 0x036F) }, /* COMBINING GRAVE ACCENT - COMBINING LATIN SMALL LETTER X */ + { BMP_0WIDTH(0x0483, 0x0489) }, /* COMBINING CYRILLIC TITLO - COMBINING CYRILLIC MILLIONS SIGN */ + { BMP_0WIDTH(0x0591, 0x05BD) }, /* HEBREW ACCENT ETNAHTA - HEBREW POINT METEG */ + { BMP_0WIDTH(0x05BF, 0x05BF) }, /* HEBREW POINT RAFE */ + { BMP_0WIDTH(0x05C1, 0x05C2) }, /* HEBREW POINT SHIN DOT - HEBREW POINT SIN DOT */ + { BMP_0WIDTH(0x05C4, 0x05C5) }, /* HEBREW MARK UPPER DOT - HEBREW MARK LOWER DOT */ + { BMP_0WIDTH(0x05C7, 0x05C7) }, /* HEBREW POINT QAMATS QATAN */ + { BMP_0WIDTH(0x0600, 0x0605) }, /* ARABIC NUMBER SIGN - ARABIC NUMBER MARK ABOVE */ + { BMP_0WIDTH(0x0610, 0x061A) }, /* ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM - ARABIC SMALL KASRA */ + { BMP_0WIDTH(0x061C, 0x061C) }, /* ARABIC LETTER MARK */ + { BMP_0WIDTH(0x064B, 0x065F) }, /* ARABIC FATHATAN - ARABIC WAVY HAMZA BELOW */ + { BMP_0WIDTH(0x0670, 0x0670) }, /* ARABIC LETTER SUPERSCRIPT ALEF */ + { BMP_0WIDTH(0x06D6, 0x06DD) }, /* ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA - ARABIC END OF AYAH */ + { BMP_0WIDTH(0x06DF, 0x06E4) }, /* ARABIC SMALL HIGH ROUNDED ZERO - ARABIC SMALL HIGH MADDA */ + { BMP_0WIDTH(0x06E7, 0x06E8) }, /* ARABIC SMALL HIGH YEH - ARABIC SMALL HIGH NOON */ + { BMP_0WIDTH(0x06EA, 0x06ED) }, /* ARABIC EMPTY CENTRE LOW STOP - ARABIC SMALL LOW MEEM */ + { BMP_0WIDTH(0x070F, 0x070F) }, /* SYRIAC ABBREVIATION MARK */ + { BMP_0WIDTH(0x0711, 0x0711) }, /* SYRIAC LETTER SUPERSCRIPT ALAPH */ + { BMP_0WIDTH(0x0730, 0x074A) }, /* SYRIAC PTHAHA ABOVE - SYRIAC BARREKH */ + { BMP_0WIDTH(0x07A6, 0x07B0) }, /* THAANA ABAFILI - THAANA SUKUN */ + { BMP_0WIDTH(0x07EB, 0x07F3) }, /* NKO COMBINING SHORT HIGH TONE - NKO COMBINING DOUBLE DOT ABOVE */ + { BMP_0WIDTH(0x07FD, 0x07FD) }, /* NKO DANTAYALAN */ + { BMP_0WIDTH(0x0816, 0x0819) }, /* SAMARITAN MARK IN - SAMARITAN MARK DAGESH */ + { BMP_0WIDTH(0x081B, 0x0823) }, /* SAMARITAN MARK EPENTHETIC YUT - SAMARITAN VOWEL SIGN A */ + { BMP_0WIDTH(0x0825, 0x0827) }, /* SAMARITAN VOWEL SIGN SHORT A - SAMARITAN VOWEL SIGN U */ + { BMP_0WIDTH(0x0829, 0x082D) }, /* SAMARITAN VOWEL SIGN LONG I - SAMARITAN MARK NEQUDAA */ + { BMP_0WIDTH(0x0859, 0x085B) }, /* MANDAIC AFFRICATION MARK - MANDAIC GEMINATION MARK */ + { BMP_0WIDTH(0x0890, 0x0891) }, /* ARABIC POUND MARK ABOVE - ARABIC PIASTRE MARK ABOVE */ + { BMP_0WIDTH(0x0897, 0x089F) }, /* ARABIC PEPET - ARABIC HALF MADDA OVER MADDA */ + { BMP_0WIDTH(0x08CA, 0x0903) }, /* ARABIC SMALL HIGH FARSI YEH - DEVANAGARI SIGN VISARGA */ + { BMP_0WIDTH(0x093A, 0x093C) }, /* DEVANAGARI VOWEL SIGN OE - DEVANAGARI SIGN NUKTA */ + { BMP_0WIDTH(0x093E, 0x094F) }, /* DEVANAGARI VOWEL SIGN AA - DEVANAGARI VOWEL SIGN AW */ + { BMP_0WIDTH(0x0951, 0x0957) }, /* DEVANAGARI STRESS SIGN UDATTA - DEVANAGARI VOWEL SIGN UUE */ + { BMP_0WIDTH(0x0962, 0x0963) }, /* DEVANAGARI VOWEL SIGN VOCALIC L - DEVANAGARI VOWEL SIGN VOCALIC LL */ + { BMP_0WIDTH(0x0981, 0x0983) }, /* BENGALI SIGN CANDRABINDU - BENGALI SIGN VISARGA */ + { BMP_0WIDTH(0x09BC, 0x09BC) }, /* BENGALI SIGN NUKTA */ + { BMP_0WIDTH(0x09BE, 0x09C4) }, /* BENGALI VOWEL SIGN AA - BENGALI VOWEL SIGN VOCALIC RR */ + { BMP_0WIDTH(0x09C7, 0x09C8) }, /* BENGALI VOWEL SIGN E - BENGALI VOWEL SIGN AI */ + { BMP_0WIDTH(0x09CB, 0x09CD) }, /* BENGALI VOWEL SIGN O - BENGALI SIGN VIRAMA */ + { BMP_0WIDTH(0x09D7, 0x09D7) }, /* BENGALI AU LENGTH MARK */ + { BMP_0WIDTH(0x09E2, 0x09E3) }, /* BENGALI VOWEL SIGN VOCALIC L - BENGALI VOWEL SIGN VOCALIC LL */ + { BMP_0WIDTH(0x09FE, 0x09FE) }, /* BENGALI SANDHI MARK */ + { BMP_0WIDTH(0x0A01, 0x0A03) }, /* GURMUKHI SIGN ADAK BINDI - GURMUKHI SIGN VISARGA */ + { BMP_0WIDTH(0x0A3C, 0x0A3C) }, /* GURMUKHI SIGN NUKTA */ + { BMP_0WIDTH(0x0A3E, 0x0A42) }, /* GURMUKHI VOWEL SIGN AA - GURMUKHI VOWEL SIGN UU */ + { BMP_0WIDTH(0x0A47, 0x0A48) }, /* GURMUKHI VOWEL SIGN EE - GURMUKHI VOWEL SIGN AI */ + { BMP_0WIDTH(0x0A4B, 0x0A4D) }, /* GURMUKHI VOWEL SIGN OO - GURMUKHI SIGN VIRAMA */ + { BMP_0WIDTH(0x0A51, 0x0A51) }, /* GURMUKHI SIGN UDAAT */ + { BMP_0WIDTH(0x0A70, 0x0A71) }, /* GURMUKHI TIPPI - GURMUKHI ADDAK */ + { BMP_0WIDTH(0x0A75, 0x0A75) }, /* GURMUKHI SIGN YAKASH */ + { BMP_0WIDTH(0x0A81, 0x0A83) }, /* GUJARATI SIGN CANDRABINDU - GUJARATI SIGN VISARGA */ + { BMP_0WIDTH(0x0ABC, 0x0ABC) }, /* GUJARATI SIGN NUKTA */ + { BMP_0WIDTH(0x0ABE, 0x0AC5) }, /* GUJARATI VOWEL SIGN AA - GUJARATI VOWEL SIGN CANDRA E */ + { BMP_0WIDTH(0x0AC7, 0x0AC9) }, /* GUJARATI VOWEL SIGN E - GUJARATI VOWEL SIGN CANDRA O */ + { BMP_0WIDTH(0x0ACB, 0x0ACD) }, /* GUJARATI VOWEL SIGN O - GUJARATI SIGN VIRAMA */ + { BMP_0WIDTH(0x0AE2, 0x0AE3) }, /* GUJARATI VOWEL SIGN VOCALIC L - GUJARATI VOWEL SIGN VOCALIC LL */ + { BMP_0WIDTH(0x0AFA, 0x0AFF) }, /* GUJARATI SIGN SUKUN - GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE */ + { BMP_0WIDTH(0x0B01, 0x0B03) }, /* ORIYA SIGN CANDRABINDU - ORIYA SIGN VISARGA */ + { BMP_0WIDTH(0x0B3C, 0x0B3C) }, /* ORIYA SIGN NUKTA */ + { BMP_0WIDTH(0x0B3E, 0x0B44) }, /* ORIYA VOWEL SIGN AA - ORIYA VOWEL SIGN VOCALIC RR */ + { BMP_0WIDTH(0x0B47, 0x0B48) }, /* ORIYA VOWEL SIGN E - ORIYA VOWEL SIGN AI */ + { BMP_0WIDTH(0x0B4B, 0x0B4D) }, /* ORIYA VOWEL SIGN O - ORIYA SIGN VIRAMA */ + { BMP_0WIDTH(0x0B55, 0x0B57) }, /* ORIYA SIGN OVERLINE - ORIYA AU LENGTH MARK */ + { BMP_0WIDTH(0x0B62, 0x0B63) }, /* ORIYA VOWEL SIGN VOCALIC L - ORIYA VOWEL SIGN VOCALIC LL */ + { BMP_0WIDTH(0x0B82, 0x0B82) }, /* TAMIL SIGN ANUSVARA */ + { BMP_0WIDTH(0x0BBE, 0x0BC2) }, /* TAMIL VOWEL SIGN AA - TAMIL VOWEL SIGN UU */ + { BMP_0WIDTH(0x0BC6, 0x0BC8) }, /* TAMIL VOWEL SIGN E - TAMIL VOWEL SIGN AI */ + { BMP_0WIDTH(0x0BCA, 0x0BCD) }, /* TAMIL VOWEL SIGN O - TAMIL SIGN VIRAMA */ + { BMP_0WIDTH(0x0BD7, 0x0BD7) }, /* TAMIL AU LENGTH MARK */ + { BMP_0WIDTH(0x0C00, 0x0C04) }, /* TELUGU SIGN COMBINING CANDRABINDU ABOVE - TELUGU SIGN COMBINING ANUSVARA ABOVE */ + { BMP_0WIDTH(0x0C3C, 0x0C3C) }, /* TELUGU SIGN NUKTA */ + { BMP_0WIDTH(0x0C3E, 0x0C44) }, /* TELUGU VOWEL SIGN AA - TELUGU VOWEL SIGN VOCALIC RR */ + { BMP_0WIDTH(0x0C46, 0x0C48) }, /* TELUGU VOWEL SIGN E - TELUGU VOWEL SIGN AI */ + { BMP_0WIDTH(0x0C4A, 0x0C4D) }, /* TELUGU VOWEL SIGN O - TELUGU SIGN VIRAMA */ + { BMP_0WIDTH(0x0C55, 0x0C56) }, /* TELUGU LENGTH MARK - TELUGU AI LENGTH MARK */ + { BMP_0WIDTH(0x0C62, 0x0C63) }, /* TELUGU VOWEL SIGN VOCALIC L - TELUGU VOWEL SIGN VOCALIC LL */ + { BMP_0WIDTH(0x0C81, 0x0C83) }, /* KANNADA SIGN CANDRABINDU - KANNADA SIGN VISARGA */ + { BMP_0WIDTH(0x0CBC, 0x0CBC) }, /* KANNADA SIGN NUKTA */ + { BMP_0WIDTH(0x0CBE, 0x0CC4) }, /* KANNADA VOWEL SIGN AA - KANNADA VOWEL SIGN VOCALIC RR */ + { BMP_0WIDTH(0x0CC6, 0x0CC8) }, /* KANNADA VOWEL SIGN E - KANNADA VOWEL SIGN AI */ + { BMP_0WIDTH(0x0CCA, 0x0CCD) }, /* KANNADA VOWEL SIGN O - KANNADA SIGN VIRAMA */ + { BMP_0WIDTH(0x0CD5, 0x0CD6) }, /* KANNADA LENGTH MARK - KANNADA AI LENGTH MARK */ + { BMP_0WIDTH(0x0CE2, 0x0CE3) }, /* KANNADA VOWEL SIGN VOCALIC L - KANNADA VOWEL SIGN VOCALIC LL */ + { BMP_0WIDTH(0x0CF3, 0x0CF3) }, /* KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT */ + { BMP_0WIDTH(0x0D00, 0x0D03) }, /* MALAYALAM SIGN COMBINING ANUSVARA ABOVE - MALAYALAM SIGN VISARGA */ + { BMP_0WIDTH(0x0D3B, 0x0D3C) }, /* MALAYALAM SIGN VERTICAL BAR VIRAMA - MALAYALAM SIGN CIRCULAR VIRAMA */ + { BMP_0WIDTH(0x0D3E, 0x0D44) }, /* MALAYALAM VOWEL SIGN AA - MALAYALAM VOWEL SIGN VOCALIC RR */ + { BMP_0WIDTH(0x0D46, 0x0D48) }, /* MALAYALAM VOWEL SIGN E - MALAYALAM VOWEL SIGN AI */ + { BMP_0WIDTH(0x0D4A, 0x0D4D) }, /* MALAYALAM VOWEL SIGN O - MALAYALAM SIGN VIRAMA */ + { BMP_0WIDTH(0x0D57, 0x0D57) }, /* MALAYALAM AU LENGTH MARK */ + { BMP_0WIDTH(0x0D62, 0x0D63) }, /* MALAYALAM VOWEL SIGN VOCALIC L - MALAYALAM VOWEL SIGN VOCALIC LL */ + { BMP_0WIDTH(0x0D81, 0x0D83) }, /* SINHALA SIGN CANDRABINDU - SINHALA SIGN VISARGAYA */ + { BMP_0WIDTH(0x0DCA, 0x0DCA) }, /* SINHALA SIGN AL-LAKUNA */ + { BMP_0WIDTH(0x0DCF, 0x0DD4) }, /* SINHALA VOWEL SIGN AELA-PILLA - SINHALA VOWEL SIGN KETTI PAA-PILLA */ + { BMP_0WIDTH(0x0DD6, 0x0DD6) }, /* SINHALA VOWEL SIGN DIGA PAA-PILLA */ + { BMP_0WIDTH(0x0DD8, 0x0DDF) }, /* SINHALA VOWEL SIGN GAETTA-PILLA - SINHALA VOWEL SIGN GAYANUKITTA */ + { BMP_0WIDTH(0x0DF2, 0x0DF3) }, /* SINHALA VOWEL SIGN DIGA GAETTA-PILLA - SINHALA VOWEL SIGN DIGA GAYANUKITTA */ + { BMP_0WIDTH(0x0E31, 0x0E31) }, /* THAI CHARACTER MAI HAN-AKAT */ + { BMP_0WIDTH(0x0E34, 0x0E3A) }, /* THAI CHARACTER SARA I - THAI CHARACTER PHINTHU */ + { BMP_0WIDTH(0x0E47, 0x0E4E) }, /* THAI CHARACTER MAITAIKHU - THAI CHARACTER YAMAKKAN */ + { BMP_0WIDTH(0x0EB1, 0x0EB1) }, /* LAO VOWEL SIGN MAI KAN */ + { BMP_0WIDTH(0x0EB4, 0x0EBC) }, /* LAO VOWEL SIGN I - LAO SEMIVOWEL SIGN LO */ + { BMP_0WIDTH(0x0EC8, 0x0ECE) }, /* LAO TONE MAI EK - LAO YAMAKKAN */ + { BMP_0WIDTH(0x0F18, 0x0F19) }, /* TIBETAN ASTROLOGICAL SIGN -KHYUD PA - TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS */ + { BMP_0WIDTH(0x0F35, 0x0F35) }, /* TIBETAN MARK NGAS BZUNG NYI ZLA */ + { BMP_0WIDTH(0x0F37, 0x0F37) }, /* TIBETAN MARK NGAS BZUNG SGOR RTAGS */ + { BMP_0WIDTH(0x0F39, 0x0F39) }, /* TIBETAN MARK TSA -PHRU */ + { BMP_0WIDTH(0x0F3E, 0x0F3F) }, /* TIBETAN SIGN YAR TSHES - TIBETAN SIGN MAR TSHES */ + { BMP_0WIDTH(0x0F71, 0x0F84) }, /* TIBETAN VOWEL SIGN AA - TIBETAN MARK HALANTA */ + { BMP_0WIDTH(0x0F86, 0x0F87) }, /* TIBETAN SIGN LCI RTAGS - TIBETAN SIGN YANG RTAGS */ + { BMP_0WIDTH(0x0F8D, 0x0F97) }, /* TIBETAN SUBJOINED SIGN LCE TSA CAN - TIBETAN SUBJOINED LETTER JA */ + { BMP_0WIDTH(0x0F99, 0x0FBC) }, /* TIBETAN SUBJOINED LETTER NYA - TIBETAN SUBJOINED LETTER FIXED-FORM RA */ + { BMP_0WIDTH(0x0FC6, 0x0FC6) }, /* TIBETAN SYMBOL PADMA GDAN */ + { BMP_0WIDTH(0x102B, 0x103E) }, /* MYANMAR VOWEL SIGN TALL AA - MYANMAR CONSONANT SIGN MEDIAL HA */ + { BMP_0WIDTH(0x1056, 0x1059) }, /* MYANMAR VOWEL SIGN VOCALIC R - MYANMAR VOWEL SIGN VOCALIC LL */ + { BMP_0WIDTH(0x105E, 0x1060) }, /* MYANMAR CONSONANT SIGN MON MEDIAL NA - MYANMAR CONSONANT SIGN MON MEDIAL LA */ + { BMP_0WIDTH(0x1062, 0x1064) }, /* MYANMAR VOWEL SIGN SGAW KAREN EU - MYANMAR TONE MARK SGAW KAREN KE PHO */ + { BMP_0WIDTH(0x1067, 0x106D) }, /* MYANMAR VOWEL SIGN WESTERN PWO KAREN EU - MYANMAR SIGN WESTERN PWO KAREN TONE-5 */ + { BMP_0WIDTH(0x1071, 0x1074) }, /* MYANMAR VOWEL SIGN GEBA KAREN I - MYANMAR VOWEL SIGN KAYAH EE */ + { BMP_0WIDTH(0x1082, 0x108D) }, /* MYANMAR CONSONANT SIGN SHAN MEDIAL WA - MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE */ + { BMP_0WIDTH(0x108F, 0x108F) }, /* MYANMAR SIGN RUMAI PALAUNG TONE-5 */ + { BMP_0WIDTH(0x109A, 0x109D) }, /* MYANMAR SIGN KHAMTI TONE-1 - MYANMAR VOWEL SIGN AITON AI */ + { BMP_2WIDTH(0x1100, 0x115F) }, /* HANGUL CHOSEONG KIYEOK - HANGUL CHOSEONG FILLER */ + { BMP_0WIDTH(0x135D, 0x135F) }, /* ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK - ETHIOPIC COMBINING GEMINATION MARK */ + { BMP_0WIDTH(0x1712, 0x1715) }, /* TAGALOG VOWEL SIGN I - TAGALOG SIGN PAMUDPOD */ + { BMP_0WIDTH(0x1732, 0x1734) }, /* HANUNOO VOWEL SIGN I - HANUNOO SIGN PAMUDPOD */ + { BMP_0WIDTH(0x1752, 0x1753) }, /* BUHID VOWEL SIGN I - BUHID VOWEL SIGN U */ + { BMP_0WIDTH(0x1772, 0x1773) }, /* TAGBANWA VOWEL SIGN I - TAGBANWA VOWEL SIGN U */ + { BMP_0WIDTH(0x17B4, 0x17D3) }, /* KHMER VOWEL INHERENT AQ - KHMER SIGN BATHAMASAT */ + { BMP_0WIDTH(0x17DD, 0x17DD) }, /* KHMER SIGN ATTHACAN */ + { BMP_0WIDTH(0x180B, 0x180F) }, /* MONGOLIAN FREE VARIATION SELECTOR ONE - MONGOLIAN FREE VARIATION SELECTOR FOUR */ + { BMP_0WIDTH(0x1885, 0x1886) }, /* MONGOLIAN LETTER ALI GALI BALUDA - MONGOLIAN LETTER ALI GALI THREE BALUDA */ + { BMP_0WIDTH(0x18A9, 0x18A9) }, /* MONGOLIAN LETTER ALI GALI DAGALGA */ + { BMP_0WIDTH(0x1920, 0x192B) }, /* LIMBU VOWEL SIGN A - LIMBU SUBJOINED LETTER WA */ + { BMP_0WIDTH(0x1930, 0x193B) }, /* LIMBU SMALL LETTER KA - LIMBU SIGN SA-I */ + { BMP_0WIDTH(0x1A17, 0x1A1B) }, /* BUGINESE VOWEL SIGN I - BUGINESE VOWEL SIGN AE */ + { BMP_0WIDTH(0x1A55, 0x1A5E) }, /* TAI THAM CONSONANT SIGN MEDIAL RA - TAI THAM CONSONANT SIGN SA */ + { BMP_0WIDTH(0x1A60, 0x1A7C) }, /* TAI THAM SIGN SAKOT - TAI THAM SIGN KHUEN-LUE KARAN */ + { BMP_0WIDTH(0x1A7F, 0x1A7F) }, /* TAI THAM COMBINING CRYPTOGRAMMIC DOT */ + { BMP_0WIDTH(0x1AB0, 0x1ACE) }, /* COMBINING DOUBLED CIRCUMFLEX ACCENT - COMBINING LATIN SMALL LETTER INSULAR T */ + { BMP_0WIDTH(0x1B00, 0x1B04) }, /* BALINESE SIGN ULU RICEM - BALINESE SIGN BISAH */ + { BMP_0WIDTH(0x1B34, 0x1B44) }, /* BALINESE SIGN REREKAN - BALINESE ADEG ADEG */ + { BMP_0WIDTH(0x1B6B, 0x1B73) }, /* BALINESE MUSICAL SYMBOL COMBINING TEGEH - BALINESE MUSICAL SYMBOL COMBINING GONG */ + { BMP_0WIDTH(0x1B80, 0x1B82) }, /* SUNDANESE SIGN PANYECEK - SUNDANESE SIGN PANGWISAD */ + { BMP_0WIDTH(0x1BA1, 0x1BAD) }, /* SUNDANESE CONSONANT SIGN PAMINGKAL - SUNDANESE CONSONANT SIGN PASANGAN WA */ + { BMP_0WIDTH(0x1BE6, 0x1BF3) }, /* BATAK SIGN TOMPI - BATAK PANONGONAN */ + { BMP_0WIDTH(0x1C24, 0x1C37) }, /* LEPCHA SUBJOINED LETTER YA - LEPCHA SIGN NUKTA */ + { BMP_0WIDTH(0x1CD0, 0x1CD2) }, /* VEDIC TONE KARSHANA - VEDIC TONE PRENKHA */ + { BMP_0WIDTH(0x1CD4, 0x1CE8) }, /* VEDIC SIGN YAJURVEDIC MIDLINE SVARITA - VEDIC SIGN VISARGA ANUDATTA WITH TAIL */ + { BMP_0WIDTH(0x1CED, 0x1CED) }, /* VEDIC SIGN TIRYAK */ + { BMP_0WIDTH(0x1CF4, 0x1CF4) }, /* VEDIC TONE CANDRA ABOVE */ + { BMP_0WIDTH(0x1CF7, 0x1CF9) }, /* VEDIC SIGN ATIKRAMA - VEDIC TONE DOUBLE RING ABOVE */ + { BMP_0WIDTH(0x1DC0, 0x1DFF) }, /* COMBINING DOTTED GRAVE ACCENT - COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW */ + { BMP_0WIDTH(0x200B, 0x200F) }, /* ZERO WIDTH SPACE - RIGHT-TO-LEFT MARK */ + { BMP_0WIDTH(0x202A, 0x202E) }, /* LEFT-TO-RIGHT EMBEDDING - RIGHT-TO-LEFT OVERRIDE */ + { BMP_0WIDTH(0x2060, 0x2064) }, /* WORD JOINER - INVISIBLE PLUS */ + { BMP_0WIDTH(0x2066, 0x206F) }, /* LEFT-TO-RIGHT ISOLATE - NOMINAL DIGIT SHAPES */ + { BMP_0WIDTH(0x20D0, 0x20F0) }, /* COMBINING LEFT HARPOON ABOVE - COMBINING ASTERISK ABOVE */ + { BMP_2WIDTH(0x231A, 0x231B) }, /* WATCH - HOURGLASS */ + { BMP_2WIDTH(0x2329, 0x232A) }, /* LEFT-POINTING ANGLE BRACKET - RIGHT-POINTING ANGLE BRACKET */ + { BMP_2WIDTH(0x23E9, 0x23EC) }, /* BLACK RIGHT-POINTING DOUBLE TRIANGLE - BLACK DOWN-POINTING DOUBLE TRIANGLE */ + { BMP_2WIDTH(0x23F0, 0x23F0) }, /* ALARM CLOCK */ + { BMP_2WIDTH(0x23F3, 0x23F3) }, /* HOURGLASS WITH FLOWING SAND */ + { BMP_2WIDTH(0x25FD, 0x25FE) }, /* WHITE MEDIUM SMALL SQUARE - BLACK MEDIUM SMALL SQUARE */ + { BMP_2WIDTH(0x2614, 0x2615) }, /* UMBRELLA WITH RAIN DROPS - HOT BEVERAGE */ + { BMP_2WIDTH(0x2630, 0x2637) }, /* TRIGRAM FOR HEAVEN - TRIGRAM FOR EARTH */ + { BMP_0WIDTH(0x2640, 0x2640) }, /* FEMALE SIGN */ + { BMP_0WIDTH(0x2642, 0x2642) }, /* MALE SIGN */ + { BMP_2WIDTH(0x2648, 0x2653) }, /* ARIES - PISCES */ + { BMP_2WIDTH(0x267F, 0x267F) }, /* WHEELCHAIR SYMBOL */ + { BMP_2WIDTH(0x268A, 0x268F) }, /* MONOGRAM FOR YANG - DIGRAM FOR GREATER YIN */ + { BMP_2WIDTH(0x2693, 0x2693) }, /* ANCHOR */ + { BMP_2WIDTH(0x26A1, 0x26A1) }, /* HIGH VOLTAGE SIGN */ + { BMP_0WIDTH(0x26A7, 0x26A7) }, /* MALE WITH STROKE AND MALE AND FEMALE SIGN */ + { BMP_2WIDTH(0x26AA, 0x26AB) }, /* MEDIUM WHITE CIRCLE - MEDIUM BLACK CIRCLE */ + { BMP_2WIDTH(0x26BD, 0x26BE) }, /* SOCCER BALL - BASEBALL */ + { BMP_2WIDTH(0x26C4, 0x26C5) }, /* SNOWMAN WITHOUT SNOW - SUN BEHIND CLOUD */ + { BMP_2WIDTH(0x26CE, 0x26CE) }, /* OPHIUCHUS */ + { BMP_2WIDTH(0x26D4, 0x26D4) }, /* NO ENTRY */ + { BMP_2WIDTH(0x26EA, 0x26EA) }, /* CHURCH */ + { BMP_2WIDTH(0x26F2, 0x26F3) }, /* FOUNTAIN - FLAG IN HOLE */ + { BMP_2WIDTH(0x26F5, 0x26F5) }, /* SAILBOAT */ + { BMP_2WIDTH(0x26FA, 0x26FA) }, /* TENT */ + { BMP_2WIDTH(0x26FD, 0x26FD) }, /* FUEL PUMP */ + { BMP_2WIDTH(0x2705, 0x2705) }, /* WHITE HEAVY CHECK MARK */ + { BMP_2WIDTH(0x270A, 0x270B) }, /* RAISED FIST - RAISED HAND */ + { BMP_2WIDTH(0x2728, 0x2728) }, /* SPARKLES */ + { BMP_2WIDTH(0x274C, 0x274C) }, /* CROSS MARK */ + { BMP_2WIDTH(0x274E, 0x274E) }, /* NEGATIVE SQUARED CROSS MARK */ + { BMP_2WIDTH(0x2753, 0x2755) }, /* BLACK QUESTION MARK ORNAMENT - WHITE EXCLAMATION MARK ORNAMENT */ + { BMP_2WIDTH(0x2757, 0x2757) }, /* HEAVY EXCLAMATION MARK SYMBOL */ + { BMP_2WIDTH(0x2795, 0x2797) }, /* HEAVY PLUS SIGN - HEAVY DIVISION SIGN */ + { BMP_2WIDTH(0x27B0, 0x27B0) }, /* CURLY LOOP */ + { BMP_2WIDTH(0x27BF, 0x27BF) }, /* DOUBLE CURLY LOOP */ + { BMP_2WIDTH(0x2B1B, 0x2B1C) }, /* BLACK LARGE SQUARE - WHITE LARGE SQUARE */ + { BMP_2WIDTH(0x2B50, 0x2B50) }, /* WHITE MEDIUM STAR */ + { BMP_2WIDTH(0x2B55, 0x2B55) }, /* HEAVY LARGE CIRCLE */ + { BMP_0WIDTH(0x2CEF, 0x2CF1) }, /* COPTIC COMBINING NI ABOVE - COPTIC COMBINING SPIRITUS LENIS */ + { BMP_0WIDTH(0x2D7F, 0x2D7F) }, /* TIFINAGH CONSONANT JOINER */ + { BMP_0WIDTH(0x2DE0, 0x2DFF) }, /* COMBINING CYRILLIC LETTER BE - COMBINING CYRILLIC LETTER IOTIFIED BIG YUS */ + { BMP_2WIDTH(0x2E80, 0x2E99) }, /* CJK RADICAL REPEAT - CJK RADICAL RAP */ + { BMP_2WIDTH(0x2E9B, 0x2EF3) }, /* CJK RADICAL CHOKE - CJK RADICAL C-SIMPLIFIED TURTLE */ + { BMP_2WIDTH(0x2F00, 0x2FD5) }, /* KANGXI RADICAL ONE - KANGXI RADICAL FLUTE */ + { BMP_2WIDTH(0x2FF0, 0x3029) }, /* IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT - HANGZHOU NUMERAL NINE */ + { BMP_0WIDTH(0x302A, 0x302F) }, /* IDEOGRAPHIC LEVEL TONE MARK - HANGUL DOUBLE DOT TONE MARK */ + { BMP_2WIDTH(0x3030, 0x303E) }, /* WAVY DASH - IDEOGRAPHIC VARIATION INDICATOR */ + { BMP_2WIDTH(0x3041, 0x3096) }, /* HIRAGANA LETTER SMALL A - HIRAGANA LETTER SMALL KE */ + { BMP_0WIDTH(0x3099, 0x309A) }, /* COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK - COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ + { BMP_2WIDTH(0x309B, 0x30FF) }, /* KATAKANA-HIRAGANA VOICED SOUND MARK - KATAKANA DIGRAPH KOTO */ + { BMP_2WIDTH(0x3105, 0x312F) }, /* BOPOMOFO LETTER B - BOPOMOFO LETTER NN */ + { BMP_2WIDTH(0x3131, 0x318E) }, /* HANGUL LETTER KIYEOK - HANGUL LETTER ARAEAE */ + { BMP_2WIDTH(0x3190, 0x31E5) }, /* IDEOGRAPHIC ANNOTATION LINKING MARK - CJK STROKE SZP */ + { BMP_2WIDTH(0x31EF, 0x321E) }, /* IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION - PARENTHESIZED KOREAN CHARACTER O HU */ + { BMP_2WIDTH(0x3220, 0x3247) }, /* PARENTHESIZED IDEOGRAPH ONE - CIRCLED IDEOGRAPH KOTO */ + { BMP_2WIDTH(0x3250, 0xA48C) }, /* PARTNERSHIP SIGN - YI SYLLABLE YYR */ + { BMP_2WIDTH(0xA490, 0xA4C6) }, /* YI RADICAL QOT - YI RADICAL KE */ + { BMP_0WIDTH(0xA66F, 0xA672) }, /* COMBINING CYRILLIC VZMET - COMBINING CYRILLIC THOUSAND MILLIONS SIGN */ + { BMP_0WIDTH(0xA674, 0xA67D) }, /* COMBINING CYRILLIC LETTER UKRAINIAN IE - COMBINING CYRILLIC PAYEROK */ + { BMP_0WIDTH(0xA69E, 0xA69F) }, /* COMBINING CYRILLIC LETTER EF - COMBINING CYRILLIC LETTER IOTIFIED E */ + { BMP_0WIDTH(0xA6F0, 0xA6F1) }, /* BAMUM COMBINING MARK KOQNDON - BAMUM COMBINING MARK TUKWENTIS */ + { BMP_0WIDTH(0xA802, 0xA802) }, /* SYLOTI NAGRI SIGN DVISVARA */ + { BMP_0WIDTH(0xA806, 0xA806) }, /* SYLOTI NAGRI SIGN HASANTA */ + { BMP_0WIDTH(0xA80B, 0xA80B) }, /* SYLOTI NAGRI SIGN ANUSVARA */ + { BMP_0WIDTH(0xA823, 0xA827) }, /* SYLOTI NAGRI VOWEL SIGN A - SYLOTI NAGRI VOWEL SIGN OO */ + { BMP_0WIDTH(0xA82C, 0xA82C) }, /* SYLOTI NAGRI SIGN ALTERNATE HASANTA */ + { BMP_0WIDTH(0xA880, 0xA881) }, /* SAURASHTRA SIGN ANUSVARA - SAURASHTRA SIGN VISARGA */ + { BMP_0WIDTH(0xA8B4, 0xA8C5) }, /* SAURASHTRA CONSONANT SIGN HAARU - SAURASHTRA SIGN CANDRABINDU */ + { BMP_0WIDTH(0xA8E0, 0xA8F1) }, /* COMBINING DEVANAGARI DIGIT ZERO - COMBINING DEVANAGARI SIGN AVAGRAHA */ + { BMP_0WIDTH(0xA8FF, 0xA8FF) }, /* DEVANAGARI VOWEL SIGN AY */ + { BMP_0WIDTH(0xA926, 0xA92D) }, /* KAYAH LI VOWEL UE - KAYAH LI TONE CALYA PLOPHU */ + { BMP_0WIDTH(0xA947, 0xA953) }, /* REJANG VOWEL SIGN I - REJANG VIRAMA */ + { BMP_2WIDTH(0xA960, 0xA97C) }, /* HANGUL CHOSEONG TIKEUT-MIEUM - HANGUL CHOSEONG SSANGYEORINHIEUH */ + { BMP_0WIDTH(0xA980, 0xA983) }, /* JAVANESE SIGN PANYANGGA - JAVANESE SIGN WIGNYAN */ + { BMP_0WIDTH(0xA9B3, 0xA9C0) }, /* JAVANESE SIGN CECAK TELU - JAVANESE PANGKON */ + { BMP_0WIDTH(0xA9E5, 0xA9E5) }, /* MYANMAR SIGN SHAN SAW */ + { BMP_0WIDTH(0xAA29, 0xAA36) }, /* CHAM VOWEL SIGN AA - CHAM CONSONANT SIGN WA */ + { BMP_0WIDTH(0xAA43, 0xAA43) }, /* CHAM CONSONANT SIGN FINAL NG */ + { BMP_0WIDTH(0xAA4C, 0xAA4D) }, /* CHAM CONSONANT SIGN FINAL M - CHAM CONSONANT SIGN FINAL H */ + { BMP_0WIDTH(0xAA7B, 0xAA7D) }, /* MYANMAR SIGN PAO KAREN TONE - MYANMAR SIGN TAI LAING TONE-5 */ + { BMP_0WIDTH(0xAAB0, 0xAAB0) }, /* TAI VIET MAI KANG */ + { BMP_0WIDTH(0xAAB2, 0xAAB4) }, /* TAI VIET VOWEL I - TAI VIET VOWEL U */ + { BMP_0WIDTH(0xAAB7, 0xAAB8) }, /* TAI VIET MAI KHIT - TAI VIET VOWEL IA */ + { BMP_0WIDTH(0xAABE, 0xAABF) }, /* TAI VIET VOWEL AM - TAI VIET TONE MAI EK */ + { BMP_0WIDTH(0xAAC1, 0xAAC1) }, /* TAI VIET TONE MAI THO */ + { BMP_0WIDTH(0xAAEB, 0xAAEF) }, /* MEETEI MAYEK VOWEL SIGN II - MEETEI MAYEK VOWEL SIGN AAU */ + { BMP_0WIDTH(0xAAF5, 0xAAF6) }, /* MEETEI MAYEK VOWEL SIGN VISARGA - MEETEI MAYEK VIRAMA */ + { BMP_0WIDTH(0xABE3, 0xABEA) }, /* MEETEI MAYEK VOWEL SIGN ONAP - MEETEI MAYEK VOWEL SIGN NUNG */ + { BMP_0WIDTH(0xABEC, 0xABED) }, /* MEETEI MAYEK LUM IYEK - MEETEI MAYEK APUN IYEK */ + { BMP_2WIDTH(0xAC00, 0xD7A3) }, /* HANGUL SYLLABLE GA - HANGUL SYLLABLE HIH */ + { BMP_2WIDTH(0xF900, 0xFAFF) }, /* U+F900 - U+FAFF */ + { BMP_0WIDTH(0xFB1E, 0xFB1E) }, /* HEBREW POINT JUDEO-SPANISH VARIKA */ + { BMP_0WIDTH(0xFE00, 0xFE0F) }, /* VARIATION SELECTOR-1 - VARIATION SELECTOR-16 */ + { BMP_2WIDTH(0xFE10, 0xFE19) }, /* PRESENTATION FORM FOR VERTICAL COMMA - PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS */ + { BMP_0WIDTH(0xFE20, 0xFE2F) }, /* COMBINING LIGATURE LEFT HALF - COMBINING CYRILLIC TITLO RIGHT HALF */ + { BMP_2WIDTH(0xFE30, 0xFE52) }, /* PRESENTATION FORM FOR VERTICAL TWO DOT LEADER - SMALL FULL STOP */ + { BMP_2WIDTH(0xFE54, 0xFE66) }, /* SMALL SEMICOLON - SMALL EQUALS SIGN */ + { BMP_2WIDTH(0xFE68, 0xFE6B) }, /* SMALL REVERSE SOLIDUS - SMALL COMMERCIAL AT */ + { BMP_0WIDTH(0xFEFF, 0xFEFF) }, /* ZERO WIDTH NO-BREAK SPACE */ + { BMP_2WIDTH(0xFF01, 0xFF60) }, /* FULLWIDTH EXCLAMATION MARK - FULLWIDTH RIGHT WHITE PARENTHESIS */ + { BMP_2WIDTH(0xFFE0, 0xFFE6) }, /* FULLWIDTH CENT SIGN - FULLWIDTH WON SIGN */ + { BMP_0WIDTH(0xFFF9, 0xFFFB) }, /* INTERLINEAR ANNOTATION ANCHOR - INTERLINEAR ANNOTATION TERMINATOR */ }; -/* Zero-width character ranges (non-BMP, U+10000 and above) */ -static const struct ucs_interval32 ucs_zero_width_non_bmp_ranges[] = { - { 0x101FD, 0x101FD }, /* PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE */ - { 0x102E0, 0x102E0 }, /* COPTIC EPACT THOUSANDS MARK */ - { 0x10376, 0x1037A }, /* COMBINING OLD PERMIC LETTER AN - COMBINING OLD PERMIC LETTER SII */ - { 0x10A01, 0x10A03 }, /* KHAROSHTHI VOWEL SIGN I - KHAROSHTHI VOWEL SIGN VOCALIC R */ - { 0x10A05, 0x10A06 }, /* KHAROSHTHI VOWEL SIGN E - KHAROSHTHI VOWEL SIGN O */ - { 0x10A0C, 0x10A0F }, /* KHAROSHTHI VOWEL LENGTH MARK - KHAROSHTHI SIGN VISARGA */ - { 0x10A38, 0x10A3A }, /* KHAROSHTHI SIGN BAR ABOVE - KHAROSHTHI SIGN DOT BELOW */ - { 0x10A3F, 0x10A3F }, /* KHAROSHTHI VIRAMA */ - { 0x10AE5, 0x10AE6 }, /* MANICHAEAN ABBREVIATION MARK ABOVE - MANICHAEAN ABBREVIATION MARK BELOW */ - { 0x10D24, 0x10D27 }, /* HANIFI ROHINGYA SIGN HARBAHAY - HANIFI ROHINGYA SIGN TASSI */ - { 0x10D69, 0x10D6D }, /* GARAY VOWEL SIGN E - GARAY CONSONANT NASALIZATION MARK */ - { 0x10EAB, 0x10EAC }, /* YEZIDI COMBINING HAMZA MARK - YEZIDI COMBINING MADDA MARK */ - { 0x10EFC, 0x10EFF }, /* ARABIC COMBINING ALEF OVERLAY - ARABIC SMALL LOW WORD MADDA */ - { 0x10F46, 0x10F50 }, /* SOGDIAN COMBINING DOT BELOW - SOGDIAN COMBINING STROKE BELOW */ - { 0x10F82, 0x10F85 }, /* OLD UYGHUR COMBINING DOT ABOVE - OLD UYGHUR COMBINING TWO DOTS BELOW */ - { 0x11000, 0x11002 }, /* BRAHMI SIGN CANDRABINDU - BRAHMI SIGN VISARGA */ - { 0x11038, 0x11046 }, /* BRAHMI VOWEL SIGN AA - BRAHMI VIRAMA */ - { 0x11070, 0x11070 }, /* BRAHMI SIGN OLD TAMIL VIRAMA */ - { 0x11073, 0x11074 }, /* BRAHMI VOWEL SIGN OLD TAMIL SHORT E - BRAHMI VOWEL SIGN OLD TAMIL SHORT O */ - { 0x1107F, 0x11082 }, /* BRAHMI NUMBER JOINER - KAITHI SIGN VISARGA */ - { 0x110B0, 0x110BA }, /* KAITHI VOWEL SIGN AA - KAITHI SIGN NUKTA */ - { 0x110BD, 0x110BD }, /* KAITHI NUMBER SIGN */ - { 0x110C2, 0x110C2 }, /* KAITHI VOWEL SIGN VOCALIC R */ - { 0x110CD, 0x110CD }, /* KAITHI NUMBER SIGN ABOVE */ - { 0x11100, 0x11102 }, /* CHAKMA SIGN CANDRABINDU - CHAKMA SIGN VISARGA */ - { 0x11127, 0x11134 }, /* CHAKMA VOWEL SIGN A - CHAKMA MAAYYAA */ - { 0x11145, 0x11146 }, /* CHAKMA VOWEL SIGN AA - CHAKMA VOWEL SIGN EI */ - { 0x11173, 0x11173 }, /* MAHAJANI SIGN NUKTA */ - { 0x11180, 0x11182 }, /* SHARADA SIGN CANDRABINDU - SHARADA SIGN VISARGA */ - { 0x111B3, 0x111C0 }, /* SHARADA VOWEL SIGN AA - SHARADA SIGN VIRAMA */ - { 0x111C9, 0x111CC }, /* SHARADA SANDHI MARK - SHARADA EXTRA SHORT VOWEL MARK */ - { 0x111CE, 0x111CF }, /* SHARADA VOWEL SIGN PRISHTHAMATRA E - SHARADA SIGN INVERTED CANDRABINDU */ - { 0x1122C, 0x11237 }, /* KHOJKI VOWEL SIGN AA - KHOJKI SIGN SHADDA */ - { 0x1123E, 0x1123E }, /* KHOJKI SIGN SUKUN */ - { 0x11241, 0x11241 }, /* KHOJKI VOWEL SIGN VOCALIC R */ - { 0x112DF, 0x112EA }, /* KHUDAWADI SIGN ANUSVARA - KHUDAWADI SIGN VIRAMA */ - { 0x11300, 0x11303 }, /* GRANTHA SIGN COMBINING ANUSVARA ABOVE - GRANTHA SIGN VISARGA */ - { 0x1133B, 0x1133C }, /* COMBINING BINDU BELOW - GRANTHA SIGN NUKTA */ - { 0x1133E, 0x11344 }, /* GRANTHA VOWEL SIGN AA - GRANTHA VOWEL SIGN VOCALIC RR */ - { 0x11347, 0x11348 }, /* GRANTHA VOWEL SIGN EE - GRANTHA VOWEL SIGN AI */ - { 0x1134B, 0x1134D }, /* GRANTHA VOWEL SIGN OO - GRANTHA SIGN VIRAMA */ - { 0x11357, 0x11357 }, /* GRANTHA AU LENGTH MARK */ - { 0x11362, 0x11363 }, /* GRANTHA VOWEL SIGN VOCALIC L - GRANTHA VOWEL SIGN VOCALIC LL */ - { 0x11366, 0x1136C }, /* COMBINING GRANTHA DIGIT ZERO - COMBINING GRANTHA DIGIT SIX */ - { 0x11370, 0x11374 }, /* COMBINING GRANTHA LETTER A - COMBINING GRANTHA LETTER PA */ - { 0x113B8, 0x113C0 }, /* TULU-TIGALARI VOWEL SIGN AA - TULU-TIGALARI VOWEL SIGN VOCALIC LL */ - { 0x113C2, 0x113C2 }, /* TULU-TIGALARI VOWEL SIGN EE */ - { 0x113C5, 0x113C5 }, /* TULU-TIGALARI VOWEL SIGN AI */ - { 0x113C7, 0x113CA }, /* TULU-TIGALARI VOWEL SIGN OO - TULU-TIGALARI SIGN CANDRA ANUNASIKA */ - { 0x113CC, 0x113D0 }, /* TULU-TIGALARI SIGN ANUSVARA - TULU-TIGALARI CONJOINER */ - { 0x113D2, 0x113D2 }, /* TULU-TIGALARI GEMINATION MARK */ - { 0x113E1, 0x113E2 }, /* TULU-TIGALARI VEDIC TONE SVARITA - TULU-TIGALARI VEDIC TONE ANUDATTA */ - { 0x11435, 0x11446 }, /* NEWA VOWEL SIGN AA - NEWA SIGN NUKTA */ - { 0x1145E, 0x1145E }, /* NEWA SANDHI MARK */ - { 0x114B0, 0x114C3 }, /* TIRHUTA VOWEL SIGN AA - TIRHUTA SIGN NUKTA */ - { 0x115AF, 0x115B5 }, /* SIDDHAM VOWEL SIGN AA - SIDDHAM VOWEL SIGN VOCALIC RR */ - { 0x115B8, 0x115C0 }, /* SIDDHAM VOWEL SIGN E - SIDDHAM SIGN NUKTA */ - { 0x115DC, 0x115DD }, /* SIDDHAM VOWEL SIGN ALTERNATE U - SIDDHAM VOWEL SIGN ALTERNATE UU */ - { 0x11630, 0x11640 }, /* MODI VOWEL SIGN AA - MODI SIGN ARDHACANDRA */ - { 0x116AB, 0x116B7 }, /* TAKRI SIGN ANUSVARA - TAKRI SIGN NUKTA */ - { 0x1171D, 0x1172B }, /* AHOM CONSONANT SIGN MEDIAL LA - AHOM SIGN KILLER */ - { 0x1182C, 0x1183A }, /* DOGRA VOWEL SIGN AA - DOGRA SIGN NUKTA */ - { 0x11930, 0x11935 }, /* DIVES AKURU VOWEL SIGN AA - DIVES AKURU VOWEL SIGN E */ - { 0x11937, 0x11938 }, /* DIVES AKURU VOWEL SIGN AI - DIVES AKURU VOWEL SIGN O */ - { 0x1193B, 0x1193E }, /* DIVES AKURU SIGN ANUSVARA - DIVES AKURU VIRAMA */ - { 0x11940, 0x11940 }, /* DIVES AKURU MEDIAL YA */ - { 0x11942, 0x11943 }, /* DIVES AKURU MEDIAL RA - DIVES AKURU SIGN NUKTA */ - { 0x119D1, 0x119D7 }, /* NANDINAGARI VOWEL SIGN AA - NANDINAGARI VOWEL SIGN VOCALIC RR */ - { 0x119DA, 0x119E0 }, /* NANDINAGARI VOWEL SIGN E - NANDINAGARI SIGN VIRAMA */ - { 0x119E4, 0x119E4 }, /* NANDINAGARI VOWEL SIGN PRISHTHAMATRA E */ - { 0x11A01, 0x11A0A }, /* ZANABAZAR SQUARE VOWEL SIGN I - ZANABAZAR SQUARE VOWEL LENGTH MARK */ - { 0x11A33, 0x11A39 }, /* ZANABAZAR SQUARE FINAL CONSONANT MARK - ZANABAZAR SQUARE SIGN VISARGA */ - { 0x11A3B, 0x11A3E }, /* ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA - ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA */ - { 0x11A47, 0x11A47 }, /* ZANABAZAR SQUARE SUBJOINER */ - { 0x11A51, 0x11A5B }, /* SOYOMBO VOWEL SIGN I - SOYOMBO VOWEL LENGTH MARK */ - { 0x11A8A, 0x11A99 }, /* SOYOMBO FINAL CONSONANT SIGN G - SOYOMBO SUBJOINER */ - { 0x11C2F, 0x11C36 }, /* BHAIKSUKI VOWEL SIGN AA - BHAIKSUKI VOWEL SIGN VOCALIC L */ - { 0x11C38, 0x11C3F }, /* BHAIKSUKI VOWEL SIGN E - BHAIKSUKI SIGN VIRAMA */ - { 0x11C92, 0x11CA7 }, /* MARCHEN SUBJOINED LETTER KA - MARCHEN SUBJOINED LETTER ZA */ - { 0x11CA9, 0x11CB6 }, /* MARCHEN SUBJOINED LETTER YA - MARCHEN SIGN CANDRABINDU */ - { 0x11D31, 0x11D36 }, /* MASARAM GONDI VOWEL SIGN AA - MASARAM GONDI VOWEL SIGN VOCALIC R */ - { 0x11D3A, 0x11D3A }, /* MASARAM GONDI VOWEL SIGN E */ - { 0x11D3C, 0x11D3D }, /* MASARAM GONDI VOWEL SIGN AI - MASARAM GONDI VOWEL SIGN O */ - { 0x11D3F, 0x11D45 }, /* MASARAM GONDI VOWEL SIGN AU - MASARAM GONDI VIRAMA */ - { 0x11D47, 0x11D47 }, /* MASARAM GONDI RA-KARA */ - { 0x11D8A, 0x11D8E }, /* GUNJALA GONDI VOWEL SIGN AA - GUNJALA GONDI VOWEL SIGN UU */ - { 0x11D90, 0x11D91 }, /* GUNJALA GONDI VOWEL SIGN EE - GUNJALA GONDI VOWEL SIGN AI */ - { 0x11D93, 0x11D97 }, /* GUNJALA GONDI VOWEL SIGN OO - GUNJALA GONDI VIRAMA */ - { 0x11EF3, 0x11EF6 }, /* MAKASAR VOWEL SIGN I - MAKASAR VOWEL SIGN O */ - { 0x11F00, 0x11F01 }, /* KAWI SIGN CANDRABINDU - KAWI SIGN ANUSVARA */ - { 0x11F03, 0x11F03 }, /* KAWI SIGN VISARGA */ - { 0x11F34, 0x11F3A }, /* KAWI VOWEL SIGN AA - KAWI VOWEL SIGN VOCALIC R */ - { 0x11F3E, 0x11F42 }, /* KAWI VOWEL SIGN E - KAWI CONJOINER */ - { 0x11F5A, 0x11F5A }, /* KAWI SIGN NUKTA */ - { 0x13430, 0x13440 }, /* EGYPTIAN HIEROGLYPH VERTICAL JOINER - EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY */ - { 0x13447, 0x13455 }, /* EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START - EGYPTIAN HIEROGLYPH MODIFIER DAMAGED */ - { 0x1611E, 0x1612F }, /* GURUNG KHEMA VOWEL SIGN AA - GURUNG KHEMA SIGN THOLHOMA */ - { 0x16AF0, 0x16AF4 }, /* BASSA VAH COMBINING HIGH TONE - BASSA VAH COMBINING HIGH-LOW TONE */ - { 0x16B30, 0x16B36 }, /* PAHAWH HMONG MARK CIM TUB - PAHAWH HMONG MARK CIM TAUM */ - { 0x16F4F, 0x16F4F }, /* MIAO SIGN CONSONANT MODIFIER BAR */ - { 0x16F51, 0x16F87 }, /* MIAO SIGN ASPIRATION - MIAO VOWEL SIGN UI */ - { 0x16F8F, 0x16F92 }, /* MIAO TONE RIGHT - MIAO TONE BELOW */ - { 0x16FE4, 0x16FE4 }, /* KHITAN SMALL SCRIPT FILLER */ - { 0x16FF0, 0x16FF1 }, /* VIETNAMESE ALTERNATE READING MARK CA - VIETNAMESE ALTERNATE READING MARK NHAY */ - { 0x1BC9D, 0x1BC9E }, /* DUPLOYAN THICK LETTER SELECTOR - DUPLOYAN DOUBLE MARK */ - { 0x1BCA0, 0x1BCA3 }, /* SHORTHAND FORMAT LETTER OVERLAP - SHORTHAND FORMAT UP STEP */ - { 0x1CF00, 0x1CF2D }, /* ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT - ZNAMENNY COMBINING MARK KRYZH ON LEFT */ - { 0x1CF30, 0x1CF46 }, /* ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO - ZNAMENNY PRIZNAK MODIFIER ROG */ - { 0x1D165, 0x1D169 }, /* MUSICAL SYMBOL COMBINING STEM - MUSICAL SYMBOL COMBINING TREMOLO-3 */ - { 0x1D16D, 0x1D182 }, /* MUSICAL SYMBOL COMBINING AUGMENTATION DOT - MUSICAL SYMBOL COMBINING LOURE */ - { 0x1D185, 0x1D18B }, /* MUSICAL SYMBOL COMBINING DOIT - MUSICAL SYMBOL COMBINING TRIPLE TONGUE */ - { 0x1D1AA, 0x1D1AD }, /* MUSICAL SYMBOL COMBINING DOWN BOW - MUSICAL SYMBOL COMBINING SNAP PIZZICATO */ - { 0x1D242, 0x1D244 }, /* COMBINING GREEK MUSICAL TRISEME - COMBINING GREEK MUSICAL PENTASEME */ - { 0x1DA00, 0x1DA36 }, /* SIGNWRITING HEAD RIM - SIGNWRITING AIR SUCKING IN */ - { 0x1DA3B, 0x1DA6C }, /* SIGNWRITING MOUTH CLOSED NEUTRAL - SIGNWRITING EXCITEMENT */ - { 0x1DA75, 0x1DA75 }, /* SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS */ - { 0x1DA84, 0x1DA84 }, /* SIGNWRITING LOCATION HEAD NECK */ - { 0x1DA9B, 0x1DA9F }, /* SIGNWRITING FILL MODIFIER-2 - SIGNWRITING FILL MODIFIER-6 */ - { 0x1DAA1, 0x1DAAF }, /* SIGNWRITING ROTATION MODIFIER-2 - SIGNWRITING ROTATION MODIFIER-16 */ - { 0x1E000, 0x1E006 }, /* COMBINING GLAGOLITIC LETTER AZU - COMBINING GLAGOLITIC LETTER ZHIVETE */ - { 0x1E008, 0x1E018 }, /* COMBINING GLAGOLITIC LETTER ZEMLJA - COMBINING GLAGOLITIC LETTER HERU */ - { 0x1E01B, 0x1E021 }, /* COMBINING GLAGOLITIC LETTER SHTA - COMBINING GLAGOLITIC LETTER YATI */ - { 0x1E023, 0x1E024 }, /* COMBINING GLAGOLITIC LETTER YU - COMBINING GLAGOLITIC LETTER SMALL YUS */ - { 0x1E026, 0x1E02A }, /* COMBINING GLAGOLITIC LETTER YO - COMBINING GLAGOLITIC LETTER FITA */ - { 0x1E08F, 0x1E08F }, /* COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ - { 0x1E130, 0x1E136 }, /* NYIAKENG PUACHUE HMONG TONE-B - NYIAKENG PUACHUE HMONG TONE-D */ - { 0x1E2AE, 0x1E2AE }, /* TOTO SIGN RISING TONE */ - { 0x1E2EC, 0x1E2EF }, /* WANCHO TONE TUP - WANCHO TONE KOINI */ - { 0x1E4EC, 0x1E4EF }, /* NAG MUNDARI SIGN MUHOR - NAG MUNDARI SIGN SUTUH */ - { 0x1E5EE, 0x1E5EF }, /* OL ONAL SIGN MU - OL ONAL SIGN IKIR */ - { 0x1E8D0, 0x1E8D6 }, /* MENDE KIKAKUI COMBINING NUMBER TEENS - MENDE KIKAKUI COMBINING NUMBER MILLIONS */ - { 0x1E944, 0x1E94A }, /* ADLAM ALIF LENGTHENER - ADLAM NUKTA */ - { 0x1F3FB, 0x1F3FF }, /* EMOJI MODIFIER FITZPATRICK TYPE-1-2 - EMOJI MODIFIER FITZPATRICK TYPE-6 */ - { 0x1F9B0, 0x1F9B3 }, /* EMOJI COMPONENT RED HAIR - EMOJI COMPONENT WHITE HAIR */ - { 0xE0001, 0xE0001 }, /* LANGUAGE TAG */ - { 0xE0020, 0xE007F }, /* TAG SPACE - CANCEL TAG */ - { 0xE0100, 0xE01EF }, /* VARIATION SELECTOR-17 - VARIATION SELECTOR-256 */ -}; - -/* Double-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */ -static const struct ucs_interval16 ucs_double_width_bmp_ranges[] = { - { 0x1100, 0x115F }, /* HANGUL CHOSEONG KIYEOK - HANGUL CHOSEONG FILLER */ - { 0x231A, 0x231B }, /* WATCH - HOURGLASS */ - { 0x2329, 0x232A }, /* LEFT-POINTING ANGLE BRACKET - RIGHT-POINTING ANGLE BRACKET */ - { 0x23E9, 0x23EC }, /* BLACK RIGHT-POINTING DOUBLE TRIANGLE - BLACK DOWN-POINTING DOUBLE TRIANGLE */ - { 0x23F0, 0x23F0 }, /* ALARM CLOCK */ - { 0x23F3, 0x23F3 }, /* HOURGLASS WITH FLOWING SAND */ - { 0x25FD, 0x25FE }, /* WHITE MEDIUM SMALL SQUARE - BLACK MEDIUM SMALL SQUARE */ - { 0x2614, 0x2615 }, /* UMBRELLA WITH RAIN DROPS - HOT BEVERAGE */ - { 0x2630, 0x2637 }, /* TRIGRAM FOR HEAVEN - TRIGRAM FOR EARTH */ - { 0x2648, 0x2653 }, /* ARIES - PISCES */ - { 0x267F, 0x267F }, /* WHEELCHAIR SYMBOL */ - { 0x268A, 0x268F }, /* MONOGRAM FOR YANG - DIGRAM FOR GREATER YIN */ - { 0x2693, 0x2693 }, /* ANCHOR */ - { 0x26A1, 0x26A1 }, /* HIGH VOLTAGE SIGN */ - { 0x26AA, 0x26AB }, /* MEDIUM WHITE CIRCLE - MEDIUM BLACK CIRCLE */ - { 0x26BD, 0x26BE }, /* SOCCER BALL - BASEBALL */ - { 0x26C4, 0x26C5 }, /* SNOWMAN WITHOUT SNOW - SUN BEHIND CLOUD */ - { 0x26CE, 0x26CE }, /* OPHIUCHUS */ - { 0x26D4, 0x26D4 }, /* NO ENTRY */ - { 0x26EA, 0x26EA }, /* CHURCH */ - { 0x26F2, 0x26F3 }, /* FOUNTAIN - FLAG IN HOLE */ - { 0x26F5, 0x26F5 }, /* SAILBOAT */ - { 0x26FA, 0x26FA }, /* TENT */ - { 0x26FD, 0x26FD }, /* FUEL PUMP */ - { 0x2705, 0x2705 }, /* WHITE HEAVY CHECK MARK */ - { 0x270A, 0x270B }, /* RAISED FIST - RAISED HAND */ - { 0x2728, 0x2728 }, /* SPARKLES */ - { 0x274C, 0x274C }, /* CROSS MARK */ - { 0x274E, 0x274E }, /* NEGATIVE SQUARED CROSS MARK */ - { 0x2753, 0x2755 }, /* BLACK QUESTION MARK ORNAMENT - WHITE EXCLAMATION MARK ORNAMENT */ - { 0x2757, 0x2757 }, /* HEAVY EXCLAMATION MARK SYMBOL */ - { 0x2795, 0x2797 }, /* HEAVY PLUS SIGN - HEAVY DIVISION SIGN */ - { 0x27B0, 0x27B0 }, /* CURLY LOOP */ - { 0x27BF, 0x27BF }, /* DOUBLE CURLY LOOP */ - { 0x2B1B, 0x2B1C }, /* BLACK LARGE SQUARE - WHITE LARGE SQUARE */ - { 0x2B50, 0x2B50 }, /* WHITE MEDIUM STAR */ - { 0x2B55, 0x2B55 }, /* HEAVY LARGE CIRCLE */ - { 0x2E80, 0x2E99 }, /* CJK RADICAL REPEAT - CJK RADICAL RAP */ - { 0x2E9B, 0x2EF3 }, /* CJK RADICAL CHOKE - CJK RADICAL C-SIMPLIFIED TURTLE */ - { 0x2F00, 0x2FD5 }, /* KANGXI RADICAL ONE - KANGXI RADICAL FLUTE */ - { 0x2FF0, 0x3029 }, /* IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT - HANGZHOU NUMERAL NINE */ - { 0x3030, 0x303E }, /* WAVY DASH - IDEOGRAPHIC VARIATION INDICATOR */ - { 0x3041, 0x3096 }, /* HIRAGANA LETTER SMALL A - HIRAGANA LETTER SMALL KE */ - { 0x309B, 0x30FF }, /* KATAKANA-HIRAGANA VOICED SOUND MARK - KATAKANA DIGRAPH KOTO */ - { 0x3105, 0x312F }, /* BOPOMOFO LETTER B - BOPOMOFO LETTER NN */ - { 0x3131, 0x318E }, /* HANGUL LETTER KIYEOK - HANGUL LETTER ARAEAE */ - { 0x3190, 0x31E5 }, /* IDEOGRAPHIC ANNOTATION LINKING MARK - CJK STROKE SZP */ - { 0x31EF, 0x321E }, /* IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION - PARENTHESIZED KOREAN CHARACTER O HU */ - { 0x3220, 0x3247 }, /* PARENTHESIZED IDEOGRAPH ONE - CIRCLED IDEOGRAPH KOTO */ - { 0x3250, 0xA48C }, /* PARTNERSHIP SIGN - YI SYLLABLE YYR */ - { 0xA490, 0xA4C6 }, /* YI RADICAL QOT - YI RADICAL KE */ - { 0xA960, 0xA97C }, /* HANGUL CHOSEONG TIKEUT-MIEUM - HANGUL CHOSEONG SSANGYEORINHIEUH */ - { 0xAC00, 0xD7A3 }, /* HANGUL SYLLABLE GA - HANGUL SYLLABLE HIH */ - { 0xF900, 0xFAFF }, /* U+F900 - U+FAFF */ - { 0xFE10, 0xFE19 }, /* PRESENTATION FORM FOR VERTICAL COMMA - PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS */ - { 0xFE30, 0xFE52 }, /* PRESENTATION FORM FOR VERTICAL TWO DOT LEADER - SMALL FULL STOP */ - { 0xFE54, 0xFE66 }, /* SMALL SEMICOLON - SMALL EQUALS SIGN */ - { 0xFE68, 0xFE6B }, /* SMALL REVERSE SOLIDUS - SMALL COMMERCIAL AT */ - { 0xFF01, 0xFF60 }, /* FULLWIDTH EXCLAMATION MARK - FULLWIDTH RIGHT WHITE PARENTHESIS */ - { 0xFFE0, 0xFFE6 }, /* FULLWIDTH CENT SIGN - FULLWIDTH WON SIGN */ -}; - -/* Double-width character ranges (non-BMP, U+10000 and above) */ -static const struct ucs_interval32 ucs_double_width_non_bmp_ranges[] = { - { 0x16FE0, 0x16FE3 }, /* TANGUT ITERATION MARK - OLD CHINESE ITERATION MARK */ - { 0x17000, 0x187F7 }, /* U+17000 - U+187F7 */ - { 0x18800, 0x18CD5 }, /* TANGUT COMPONENT-001 - KHITAN SMALL SCRIPT CHARACTER-18CD5 */ - { 0x18CFF, 0x18D08 }, /* U+18CFF - U+18D08 */ - { 0x1AFF0, 0x1AFF3 }, /* KATAKANA LETTER MINNAN TONE-2 - KATAKANA LETTER MINNAN TONE-5 */ - { 0x1AFF5, 0x1AFFB }, /* KATAKANA LETTER MINNAN TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-5 */ - { 0x1AFFD, 0x1AFFE }, /* KATAKANA LETTER MINNAN NASALIZED TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-8 */ - { 0x1B000, 0x1B122 }, /* KATAKANA LETTER ARCHAIC E - KATAKANA LETTER ARCHAIC WU */ - { 0x1B132, 0x1B132 }, /* HIRAGANA LETTER SMALL KO */ - { 0x1B150, 0x1B152 }, /* HIRAGANA LETTER SMALL WI - HIRAGANA LETTER SMALL WO */ - { 0x1B155, 0x1B155 }, /* KATAKANA LETTER SMALL KO */ - { 0x1B164, 0x1B167 }, /* KATAKANA LETTER SMALL WI - KATAKANA LETTER SMALL N */ - { 0x1B170, 0x1B2FB }, /* NUSHU CHARACTER-1B170 - NUSHU CHARACTER-1B2FB */ - { 0x1D300, 0x1D356 }, /* MONOGRAM FOR EARTH - TETRAGRAM FOR FOSTERING */ - { 0x1D360, 0x1D376 }, /* COUNTING ROD UNIT DIGIT ONE - IDEOGRAPHIC TALLY MARK FIVE */ - { 0x1F000, 0x1F02F }, /* U+1F000 - U+1F02F */ - { 0x1F0A0, 0x1F0FF }, /* U+1F0A0 - U+1F0FF */ - { 0x1F18E, 0x1F18E }, /* NEGATIVE SQUARED AB */ - { 0x1F191, 0x1F19A }, /* SQUARED CL - SQUARED VS */ - { 0x1F200, 0x1F202 }, /* SQUARE HIRAGANA HOKA - SQUARED KATAKANA SA */ - { 0x1F210, 0x1F23B }, /* SQUARED CJK UNIFIED IDEOGRAPH-624B - SQUARED CJK UNIFIED IDEOGRAPH-914D */ - { 0x1F240, 0x1F248 }, /* TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C - TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 */ - { 0x1F250, 0x1F251 }, /* CIRCLED IDEOGRAPH ADVANTAGE - CIRCLED IDEOGRAPH ACCEPT */ - { 0x1F260, 0x1F265 }, /* ROUNDED SYMBOL FOR FU - ROUNDED SYMBOL FOR CAI */ - { 0x1F300, 0x1F3FA }, /* CYCLONE - AMPHORA */ - { 0x1F400, 0x1F64F }, /* RAT - PERSON WITH FOLDED HANDS */ - { 0x1F680, 0x1F9AF }, /* ROCKET - PROBING CANE */ - { 0x1F9B4, 0x1FAFF }, /* U+1F9B4 - U+1FAFF */ - { 0x20000, 0x2FFFD }, /* U+20000 - U+2FFFD */ - { 0x30000, 0x3FFFD }, /* U+30000 - U+3FFFD */ +/* Combined zero- and double-width ranges (non-BMP, U+10000 and above). + * The first 33 entries host the BMP double-width bitmap in the low + * 8 bits of `last`. */ +static const struct ucs_width32 ucs_nonbmp_ranges[] = { + { RANGE_0WIDTH(0x101FD, 0x101FD) /* PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 0.. 7] */ + { RANGE_0WIDTH(0x102E0, 0x102E0) /* COPTIC EPACT THOUSANDS MARK */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 8.. 15] */ + { RANGE_0WIDTH(0x10376, 0x1037A) /* COMBINING OLD PERMIC LETTER AN - COMBINING OLD PERMIC LETTER SII */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 16.. 23] */ + { RANGE_0WIDTH(0x10A01, 0x10A03) /* KHAROSHTHI VOWEL SIGN I - KHAROSHTHI VOWEL SIGN VOCALIC R */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 24.. 31] */ + { RANGE_0WIDTH(0x10A05, 0x10A06) /* KHAROSHTHI VOWEL SIGN E - KHAROSHTHI VOWEL SIGN O */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 32.. 39] */ + { RANGE_0WIDTH(0x10A0C, 0x10A0F) /* KHAROSHTHI VOWEL LENGTH MARK - KHAROSHTHI SIGN VISARGA */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 40.. 47] */ + { RANGE_0WIDTH(0x10A38, 0x10A3A) /* KHAROSHTHI SIGN BAR ABOVE - KHAROSHTHI SIGN DOT BELOW */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 48.. 55] */ + { RANGE_0WIDTH(0x10A3F, 0x10A3F) /* KHAROSHTHI VIRAMA */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 56.. 63] */ + { RANGE_0WIDTH(0x10AE5, 0x10AE6) /* MANICHAEAN ABBREVIATION MARK ABOVE - MANICHAEAN ABBREVIATION MARK BELOW */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 64.. 71] */ + { RANGE_0WIDTH(0x10D24, 0x10D27) /* HANIFI ROHINGYA SIGN HARBAHAY - HANIFI ROHINGYA SIGN TASSI */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 72.. 79] */ + { RANGE_0WIDTH(0x10D69, 0x10D6D) /* GARAY VOWEL SIGN E - GARAY CONSONANT NASALIZATION MARK */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 80.. 87] */ + { RANGE_0WIDTH(0x10EAB, 0x10EAC) /* YEZIDI COMBINING HAMZA MARK - YEZIDI COMBINING MADDA MARK */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 88.. 95] */ + { RANGE_0WIDTH(0x10EFC, 0x10EFF) /* ARABIC COMBINING ALEF OVERLAY - ARABIC SMALL LOW WORD MADDA */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [ 96..103] */ + { RANGE_0WIDTH(0x10F46, 0x10F50) /* SOGDIAN COMBINING DOT BELOW - SOGDIAN COMBINING STROKE BELOW */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [104..111] */ + { RANGE_0WIDTH(0x10F82, 0x10F85) /* OLD UYGHUR COMBINING DOT ABOVE - OLD UYGHUR COMBINING TWO DOTS BELOW */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [112..119] */ + { RANGE_0WIDTH(0x11000, 0x11002) /* BRAHMI SIGN CANDRABINDU - BRAHMI SIGN VISARGA */ + | BMP_2W_BITS(0b00001000) }, /* BMP entries [120..127] */ + { RANGE_0WIDTH(0x11038, 0x11046) /* BRAHMI VOWEL SIGN AA - BRAHMI VIRAMA */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [128..135] */ + { RANGE_0WIDTH(0x11070, 0x11070) /* BRAHMI SIGN OLD TAMIL VIRAMA */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [136..143] */ + { RANGE_0WIDTH(0x11073, 0x11074) /* BRAHMI VOWEL SIGN OLD TAMIL SHORT E - BRAHMI VOWEL SIGN OLD TAMIL SHORT O */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [144..151] */ + { RANGE_0WIDTH(0x1107F, 0x11082) /* BRAHMI NUMBER JOINER - KAITHI SIGN VISARGA */ + | BMP_2W_BITS(0b10000000) }, /* BMP entries [152..159] */ + { RANGE_0WIDTH(0x110B0, 0x110BA) /* KAITHI VOWEL SIGN AA - KAITHI SIGN NUKTA */ + | BMP_2W_BITS(0b01111111) }, /* BMP entries [160..167] */ + { RANGE_0WIDTH(0x110BD, 0x110BD) /* KAITHI NUMBER SIGN */ + | BMP_2W_BITS(0b10111110) }, /* BMP entries [168..175] */ + { RANGE_0WIDTH(0x110C2, 0x110C2) /* KAITHI VOWEL SIGN VOCALIC R */ + | BMP_2W_BITS(0b11111111) }, /* BMP entries [176..183] */ + { RANGE_0WIDTH(0x110CD, 0x110CD) /* KAITHI NUMBER SIGN ABOVE */ + | BMP_2W_BITS(0b11111111) }, /* BMP entries [184..191] */ + { RANGE_0WIDTH(0x11100, 0x11102) /* CHAKMA SIGN CANDRABINDU - CHAKMA SIGN VISARGA */ + | BMP_2W_BITS(0b00111111) }, /* BMP entries [192..199] */ + { RANGE_0WIDTH(0x11127, 0x11134) /* CHAKMA VOWEL SIGN A - CHAKMA MAAYYAA */ + | BMP_2W_BITS(0b11011110) }, /* BMP entries [200..207] */ + { RANGE_0WIDTH(0x11145, 0x11146) /* CHAKMA VOWEL SIGN AA - CHAKMA VOWEL SIGN EI */ + | BMP_2W_BITS(0b11111110) }, /* BMP entries [208..215] */ + { RANGE_0WIDTH(0x11173, 0x11173) /* MAHAJANI SIGN NUKTA */ + | BMP_2W_BITS(0b00000001) }, /* BMP entries [216..223] */ + { RANGE_0WIDTH(0x11180, 0x11182) /* SHARADA SIGN CANDRABINDU - SHARADA SIGN VISARGA */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [224..231] */ + { RANGE_0WIDTH(0x111B3, 0x111C0) /* SHARADA VOWEL SIGN AA - SHARADA SIGN VIRAMA */ + | BMP_2W_BITS(0b00000001) }, /* BMP entries [232..239] */ + { RANGE_0WIDTH(0x111C9, 0x111CC) /* SHARADA SANDHI MARK - SHARADA EXTRA SHORT VOWEL MARK */ + | BMP_2W_BITS(0b00000000) }, /* BMP entries [240..247] */ + { RANGE_0WIDTH(0x111CE, 0x111CF) /* SHARADA VOWEL SIGN PRISHTHAMATRA E - SHARADA SIGN INVERTED CANDRABINDU */ + | BMP_2W_BITS(0b10100110) }, /* BMP entries [248..255] */ + { RANGE_0WIDTH(0x1122C, 0x11237) /* KHOJKI VOWEL SIGN AA - KHOJKI SIGN SHADDA */ + | BMP_2W_BITS(0b00011011) }, /* BMP entries [256..261] */ + { RANGE_0WIDTH(0x1123E, 0x1123E) }, /* KHOJKI SIGN SUKUN */ + { RANGE_0WIDTH(0x11241, 0x11241) }, /* KHOJKI VOWEL SIGN VOCALIC R */ + { RANGE_0WIDTH(0x112DF, 0x112EA) }, /* KHUDAWADI SIGN ANUSVARA - KHUDAWADI SIGN VIRAMA */ + { RANGE_0WIDTH(0x11300, 0x11303) }, /* GRANTHA SIGN COMBINING ANUSVARA ABOVE - GRANTHA SIGN VISARGA */ + { RANGE_0WIDTH(0x1133B, 0x1133C) }, /* COMBINING BINDU BELOW - GRANTHA SIGN NUKTA */ + { RANGE_0WIDTH(0x1133E, 0x11344) }, /* GRANTHA VOWEL SIGN AA - GRANTHA VOWEL SIGN VOCALIC RR */ + { RANGE_0WIDTH(0x11347, 0x11348) }, /* GRANTHA VOWEL SIGN EE - GRANTHA VOWEL SIGN AI */ + { RANGE_0WIDTH(0x1134B, 0x1134D) }, /* GRANTHA VOWEL SIGN OO - GRANTHA SIGN VIRAMA */ + { RANGE_0WIDTH(0x11357, 0x11357) }, /* GRANTHA AU LENGTH MARK */ + { RANGE_0WIDTH(0x11362, 0x11363) }, /* GRANTHA VOWEL SIGN VOCALIC L - GRANTHA VOWEL SIGN VOCALIC LL */ + { RANGE_0WIDTH(0x11366, 0x1136C) }, /* COMBINING GRANTHA DIGIT ZERO - COMBINING GRANTHA DIGIT SIX */ + { RANGE_0WIDTH(0x11370, 0x11374) }, /* COMBINING GRANTHA LETTER A - COMBINING GRANTHA LETTER PA */ + { RANGE_0WIDTH(0x113B8, 0x113C0) }, /* TULU-TIGALARI VOWEL SIGN AA - TULU-TIGALARI VOWEL SIGN VOCALIC LL */ + { RANGE_0WIDTH(0x113C2, 0x113C2) }, /* TULU-TIGALARI VOWEL SIGN EE */ + { RANGE_0WIDTH(0x113C5, 0x113C5) }, /* TULU-TIGALARI VOWEL SIGN AI */ + { RANGE_0WIDTH(0x113C7, 0x113CA) }, /* TULU-TIGALARI VOWEL SIGN OO - TULU-TIGALARI SIGN CANDRA ANUNASIKA */ + { RANGE_0WIDTH(0x113CC, 0x113D0) }, /* TULU-TIGALARI SIGN ANUSVARA - TULU-TIGALARI CONJOINER */ + { RANGE_0WIDTH(0x113D2, 0x113D2) }, /* TULU-TIGALARI GEMINATION MARK */ + { RANGE_0WIDTH(0x113E1, 0x113E2) }, /* TULU-TIGALARI VEDIC TONE SVARITA - TULU-TIGALARI VEDIC TONE ANUDATTA */ + { RANGE_0WIDTH(0x11435, 0x11446) }, /* NEWA VOWEL SIGN AA - NEWA SIGN NUKTA */ + { RANGE_0WIDTH(0x1145E, 0x1145E) }, /* NEWA SANDHI MARK */ + { RANGE_0WIDTH(0x114B0, 0x114C3) }, /* TIRHUTA VOWEL SIGN AA - TIRHUTA SIGN NUKTA */ + { RANGE_0WIDTH(0x115AF, 0x115B5) }, /* SIDDHAM VOWEL SIGN AA - SIDDHAM VOWEL SIGN VOCALIC RR */ + { RANGE_0WIDTH(0x115B8, 0x115C0) }, /* SIDDHAM VOWEL SIGN E - SIDDHAM SIGN NUKTA */ + { RANGE_0WIDTH(0x115DC, 0x115DD) }, /* SIDDHAM VOWEL SIGN ALTERNATE U - SIDDHAM VOWEL SIGN ALTERNATE UU */ + { RANGE_0WIDTH(0x11630, 0x11640) }, /* MODI VOWEL SIGN AA - MODI SIGN ARDHACANDRA */ + { RANGE_0WIDTH(0x116AB, 0x116B7) }, /* TAKRI SIGN ANUSVARA - TAKRI SIGN NUKTA */ + { RANGE_0WIDTH(0x1171D, 0x1172B) }, /* AHOM CONSONANT SIGN MEDIAL LA - AHOM SIGN KILLER */ + { RANGE_0WIDTH(0x1182C, 0x1183A) }, /* DOGRA VOWEL SIGN AA - DOGRA SIGN NUKTA */ + { RANGE_0WIDTH(0x11930, 0x11935) }, /* DIVES AKURU VOWEL SIGN AA - DIVES AKURU VOWEL SIGN E */ + { RANGE_0WIDTH(0x11937, 0x11938) }, /* DIVES AKURU VOWEL SIGN AI - DIVES AKURU VOWEL SIGN O */ + { RANGE_0WIDTH(0x1193B, 0x1193E) }, /* DIVES AKURU SIGN ANUSVARA - DIVES AKURU VIRAMA */ + { RANGE_0WIDTH(0x11940, 0x11940) }, /* DIVES AKURU MEDIAL YA */ + { RANGE_0WIDTH(0x11942, 0x11943) }, /* DIVES AKURU MEDIAL RA - DIVES AKURU SIGN NUKTA */ + { RANGE_0WIDTH(0x119D1, 0x119D7) }, /* NANDINAGARI VOWEL SIGN AA - NANDINAGARI VOWEL SIGN VOCALIC RR */ + { RANGE_0WIDTH(0x119DA, 0x119E0) }, /* NANDINAGARI VOWEL SIGN E - NANDINAGARI SIGN VIRAMA */ + { RANGE_0WIDTH(0x119E4, 0x119E4) }, /* NANDINAGARI VOWEL SIGN PRISHTHAMATRA E */ + { RANGE_0WIDTH(0x11A01, 0x11A0A) }, /* ZANABAZAR SQUARE VOWEL SIGN I - ZANABAZAR SQUARE VOWEL LENGTH MARK */ + { RANGE_0WIDTH(0x11A33, 0x11A39) }, /* ZANABAZAR SQUARE FINAL CONSONANT MARK - ZANABAZAR SQUARE SIGN VISARGA */ + { RANGE_0WIDTH(0x11A3B, 0x11A3E) }, /* ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA - ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA */ + { RANGE_0WIDTH(0x11A47, 0x11A47) }, /* ZANABAZAR SQUARE SUBJOINER */ + { RANGE_0WIDTH(0x11A51, 0x11A5B) }, /* SOYOMBO VOWEL SIGN I - SOYOMBO VOWEL LENGTH MARK */ + { RANGE_0WIDTH(0x11A8A, 0x11A99) }, /* SOYOMBO FINAL CONSONANT SIGN G - SOYOMBO SUBJOINER */ + { RANGE_0WIDTH(0x11C2F, 0x11C36) }, /* BHAIKSUKI VOWEL SIGN AA - BHAIKSUKI VOWEL SIGN VOCALIC L */ + { RANGE_0WIDTH(0x11C38, 0x11C3F) }, /* BHAIKSUKI VOWEL SIGN E - BHAIKSUKI SIGN VIRAMA */ + { RANGE_0WIDTH(0x11C92, 0x11CA7) }, /* MARCHEN SUBJOINED LETTER KA - MARCHEN SUBJOINED LETTER ZA */ + { RANGE_0WIDTH(0x11CA9, 0x11CB6) }, /* MARCHEN SUBJOINED LETTER YA - MARCHEN SIGN CANDRABINDU */ + { RANGE_0WIDTH(0x11D31, 0x11D36) }, /* MASARAM GONDI VOWEL SIGN AA - MASARAM GONDI VOWEL SIGN VOCALIC R */ + { RANGE_0WIDTH(0x11D3A, 0x11D3A) }, /* MASARAM GONDI VOWEL SIGN E */ + { RANGE_0WIDTH(0x11D3C, 0x11D3D) }, /* MASARAM GONDI VOWEL SIGN AI - MASARAM GONDI VOWEL SIGN O */ + { RANGE_0WIDTH(0x11D3F, 0x11D45) }, /* MASARAM GONDI VOWEL SIGN AU - MASARAM GONDI VIRAMA */ + { RANGE_0WIDTH(0x11D47, 0x11D47) }, /* MASARAM GONDI RA-KARA */ + { RANGE_0WIDTH(0x11D8A, 0x11D8E) }, /* GUNJALA GONDI VOWEL SIGN AA - GUNJALA GONDI VOWEL SIGN UU */ + { RANGE_0WIDTH(0x11D90, 0x11D91) }, /* GUNJALA GONDI VOWEL SIGN EE - GUNJALA GONDI VOWEL SIGN AI */ + { RANGE_0WIDTH(0x11D93, 0x11D97) }, /* GUNJALA GONDI VOWEL SIGN OO - GUNJALA GONDI VIRAMA */ + { RANGE_0WIDTH(0x11EF3, 0x11EF6) }, /* MAKASAR VOWEL SIGN I - MAKASAR VOWEL SIGN O */ + { RANGE_0WIDTH(0x11F00, 0x11F01) }, /* KAWI SIGN CANDRABINDU - KAWI SIGN ANUSVARA */ + { RANGE_0WIDTH(0x11F03, 0x11F03) }, /* KAWI SIGN VISARGA */ + { RANGE_0WIDTH(0x11F34, 0x11F3A) }, /* KAWI VOWEL SIGN AA - KAWI VOWEL SIGN VOCALIC R */ + { RANGE_0WIDTH(0x11F3E, 0x11F42) }, /* KAWI VOWEL SIGN E - KAWI CONJOINER */ + { RANGE_0WIDTH(0x11F5A, 0x11F5A) }, /* KAWI SIGN NUKTA */ + { RANGE_0WIDTH(0x13430, 0x13440) }, /* EGYPTIAN HIEROGLYPH VERTICAL JOINER - EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY */ + { RANGE_0WIDTH(0x13447, 0x13455) }, /* EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START - EGYPTIAN HIEROGLYPH MODIFIER DAMAGED */ + { RANGE_0WIDTH(0x1611E, 0x1612F) }, /* GURUNG KHEMA VOWEL SIGN AA - GURUNG KHEMA SIGN THOLHOMA */ + { RANGE_0WIDTH(0x16AF0, 0x16AF4) }, /* BASSA VAH COMBINING HIGH TONE - BASSA VAH COMBINING HIGH-LOW TONE */ + { RANGE_0WIDTH(0x16B30, 0x16B36) }, /* PAHAWH HMONG MARK CIM TUB - PAHAWH HMONG MARK CIM TAUM */ + { RANGE_0WIDTH(0x16F4F, 0x16F4F) }, /* MIAO SIGN CONSONANT MODIFIER BAR */ + { RANGE_0WIDTH(0x16F51, 0x16F87) }, /* MIAO SIGN ASPIRATION - MIAO VOWEL SIGN UI */ + { RANGE_0WIDTH(0x16F8F, 0x16F92) }, /* MIAO TONE RIGHT - MIAO TONE BELOW */ + { RANGE_2WIDTH(0x16FE0, 0x16FE3) }, /* TANGUT ITERATION MARK - OLD CHINESE ITERATION MARK */ + { RANGE_0WIDTH(0x16FE4, 0x16FE4) }, /* KHITAN SMALL SCRIPT FILLER */ + { RANGE_0WIDTH(0x16FF0, 0x16FF1) }, /* VIETNAMESE ALTERNATE READING MARK CA - VIETNAMESE ALTERNATE READING MARK NHAY */ + { RANGE_2WIDTH(0x17000, 0x187F7) }, /* U+17000 - U+187F7 */ + { RANGE_2WIDTH(0x18800, 0x18CD5) }, /* TANGUT COMPONENT-001 - KHITAN SMALL SCRIPT CHARACTER-18CD5 */ + { RANGE_2WIDTH(0x18CFF, 0x18D08) }, /* U+18CFF - U+18D08 */ + { RANGE_2WIDTH(0x1AFF0, 0x1AFF3) }, /* KATAKANA LETTER MINNAN TONE-2 - KATAKANA LETTER MINNAN TONE-5 */ + { RANGE_2WIDTH(0x1AFF5, 0x1AFFB) }, /* KATAKANA LETTER MINNAN TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-5 */ + { RANGE_2WIDTH(0x1AFFD, 0x1AFFE) }, /* KATAKANA LETTER MINNAN NASALIZED TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-8 */ + { RANGE_2WIDTH(0x1B000, 0x1B122) }, /* KATAKANA LETTER ARCHAIC E - KATAKANA LETTER ARCHAIC WU */ + { RANGE_2WIDTH(0x1B132, 0x1B132) }, /* HIRAGANA LETTER SMALL KO */ + { RANGE_2WIDTH(0x1B150, 0x1B152) }, /* HIRAGANA LETTER SMALL WI - HIRAGANA LETTER SMALL WO */ + { RANGE_2WIDTH(0x1B155, 0x1B155) }, /* KATAKANA LETTER SMALL KO */ + { RANGE_2WIDTH(0x1B164, 0x1B167) }, /* KATAKANA LETTER SMALL WI - KATAKANA LETTER SMALL N */ + { RANGE_2WIDTH(0x1B170, 0x1B2FB) }, /* NUSHU CHARACTER-1B170 - NUSHU CHARACTER-1B2FB */ + { RANGE_0WIDTH(0x1BC9D, 0x1BC9E) }, /* DUPLOYAN THICK LETTER SELECTOR - DUPLOYAN DOUBLE MARK */ + { RANGE_0WIDTH(0x1BCA0, 0x1BCA3) }, /* SHORTHAND FORMAT LETTER OVERLAP - SHORTHAND FORMAT UP STEP */ + { RANGE_0WIDTH(0x1CF00, 0x1CF2D) }, /* ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT - ZNAMENNY COMBINING MARK KRYZH ON LEFT */ + { RANGE_0WIDTH(0x1CF30, 0x1CF46) }, /* ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO - ZNAMENNY PRIZNAK MODIFIER ROG */ + { RANGE_0WIDTH(0x1D165, 0x1D169) }, /* MUSICAL SYMBOL COMBINING STEM - MUSICAL SYMBOL COMBINING TREMOLO-3 */ + { RANGE_0WIDTH(0x1D16D, 0x1D182) }, /* MUSICAL SYMBOL COMBINING AUGMENTATION DOT - MUSICAL SYMBOL COMBINING LOURE */ + { RANGE_0WIDTH(0x1D185, 0x1D18B) }, /* MUSICAL SYMBOL COMBINING DOIT - MUSICAL SYMBOL COMBINING TRIPLE TONGUE */ + { RANGE_0WIDTH(0x1D1AA, 0x1D1AD) }, /* MUSICAL SYMBOL COMBINING DOWN BOW - MUSICAL SYMBOL COMBINING SNAP PIZZICATO */ + { RANGE_0WIDTH(0x1D242, 0x1D244) }, /* COMBINING GREEK MUSICAL TRISEME - COMBINING GREEK MUSICAL PENTASEME */ + { RANGE_2WIDTH(0x1D300, 0x1D356) }, /* MONOGRAM FOR EARTH - TETRAGRAM FOR FOSTERING */ + { RANGE_2WIDTH(0x1D360, 0x1D376) }, /* COUNTING ROD UNIT DIGIT ONE - IDEOGRAPHIC TALLY MARK FIVE */ + { RANGE_0WIDTH(0x1DA00, 0x1DA36) }, /* SIGNWRITING HEAD RIM - SIGNWRITING AIR SUCKING IN */ + { RANGE_0WIDTH(0x1DA3B, 0x1DA6C) }, /* SIGNWRITING MOUTH CLOSED NEUTRAL - SIGNWRITING EXCITEMENT */ + { RANGE_0WIDTH(0x1DA75, 0x1DA75) }, /* SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS */ + { RANGE_0WIDTH(0x1DA84, 0x1DA84) }, /* SIGNWRITING LOCATION HEAD NECK */ + { RANGE_0WIDTH(0x1DA9B, 0x1DA9F) }, /* SIGNWRITING FILL MODIFIER-2 - SIGNWRITING FILL MODIFIER-6 */ + { RANGE_0WIDTH(0x1DAA1, 0x1DAAF) }, /* SIGNWRITING ROTATION MODIFIER-2 - SIGNWRITING ROTATION MODIFIER-16 */ + { RANGE_0WIDTH(0x1E000, 0x1E006) }, /* COMBINING GLAGOLITIC LETTER AZU - COMBINING GLAGOLITIC LETTER ZHIVETE */ + { RANGE_0WIDTH(0x1E008, 0x1E018) }, /* COMBINING GLAGOLITIC LETTER ZEMLJA - COMBINING GLAGOLITIC LETTER HERU */ + { RANGE_0WIDTH(0x1E01B, 0x1E021) }, /* COMBINING GLAGOLITIC LETTER SHTA - COMBINING GLAGOLITIC LETTER YATI */ + { RANGE_0WIDTH(0x1E023, 0x1E024) }, /* COMBINING GLAGOLITIC LETTER YU - COMBINING GLAGOLITIC LETTER SMALL YUS */ + { RANGE_0WIDTH(0x1E026, 0x1E02A) }, /* COMBINING GLAGOLITIC LETTER YO - COMBINING GLAGOLITIC LETTER FITA */ + { RANGE_0WIDTH(0x1E08F, 0x1E08F) }, /* COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + { RANGE_0WIDTH(0x1E130, 0x1E136) }, /* NYIAKENG PUACHUE HMONG TONE-B - NYIAKENG PUACHUE HMONG TONE-D */ + { RANGE_0WIDTH(0x1E2AE, 0x1E2AE) }, /* TOTO SIGN RISING TONE */ + { RANGE_0WIDTH(0x1E2EC, 0x1E2EF) }, /* WANCHO TONE TUP - WANCHO TONE KOINI */ + { RANGE_0WIDTH(0x1E4EC, 0x1E4EF) }, /* NAG MUNDARI SIGN MUHOR - NAG MUNDARI SIGN SUTUH */ + { RANGE_0WIDTH(0x1E5EE, 0x1E5EF) }, /* OL ONAL SIGN MU - OL ONAL SIGN IKIR */ + { RANGE_0WIDTH(0x1E8D0, 0x1E8D6) }, /* MENDE KIKAKUI COMBINING NUMBER TEENS - MENDE KIKAKUI COMBINING NUMBER MILLIONS */ + { RANGE_0WIDTH(0x1E944, 0x1E94A) }, /* ADLAM ALIF LENGTHENER - ADLAM NUKTA */ + { RANGE_2WIDTH(0x1F000, 0x1F02F) }, /* U+1F000 - U+1F02F */ + { RANGE_2WIDTH(0x1F0A0, 0x1F0FF) }, /* U+1F0A0 - U+1F0FF */ + { RANGE_2WIDTH(0x1F18E, 0x1F18E) }, /* NEGATIVE SQUARED AB */ + { RANGE_2WIDTH(0x1F191, 0x1F19A) }, /* SQUARED CL - SQUARED VS */ + { RANGE_2WIDTH(0x1F200, 0x1F202) }, /* SQUARE HIRAGANA HOKA - SQUARED KATAKANA SA */ + { RANGE_2WIDTH(0x1F210, 0x1F23B) }, /* SQUARED CJK UNIFIED IDEOGRAPH-624B - SQUARED CJK UNIFIED IDEOGRAPH-914D */ + { RANGE_2WIDTH(0x1F240, 0x1F248) }, /* TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C - TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 */ + { RANGE_2WIDTH(0x1F250, 0x1F251) }, /* CIRCLED IDEOGRAPH ADVANTAGE - CIRCLED IDEOGRAPH ACCEPT */ + { RANGE_2WIDTH(0x1F260, 0x1F265) }, /* ROUNDED SYMBOL FOR FU - ROUNDED SYMBOL FOR CAI */ + { RANGE_2WIDTH(0x1F300, 0x1F3FA) }, /* CYCLONE - AMPHORA */ + { RANGE_0WIDTH(0x1F3FB, 0x1F3FF) }, /* EMOJI MODIFIER FITZPATRICK TYPE-1-2 - EMOJI MODIFIER FITZPATRICK TYPE-6 */ + { RANGE_2WIDTH(0x1F400, 0x1F64F) }, /* RAT - PERSON WITH FOLDED HANDS */ + { RANGE_2WIDTH(0x1F680, 0x1F9AF) }, /* ROCKET - PROBING CANE */ + { RANGE_0WIDTH(0x1F9B0, 0x1F9B3) }, /* EMOJI COMPONENT RED HAIR - EMOJI COMPONENT WHITE HAIR */ + { RANGE_2WIDTH(0x1F9B4, 0x1FAFF) }, /* U+1F9B4 - U+1FAFF */ + { RANGE_2WIDTH(0x20000, 0x2FFFD) }, /* U+20000 - U+2FFFD */ + { RANGE_2WIDTH(0x30000, 0x3FFFD) }, /* U+30000 - U+3FFFD */ + { RANGE_0WIDTH(0xE0001, 0xE0001) }, /* LANGUAGE TAG */ + { RANGE_0WIDTH(0xE0020, 0xE007F) }, /* TAG SPACE - CANCEL TAG */ + { RANGE_0WIDTH(0xE0100, 0xE01EF) }, /* VARIATION SELECTOR-17 - VARIATION SELECTOR-256 */ }; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e99636ab9db5..cf26fb8f6545 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3094,8 +3094,12 @@ static void vc_con_rewind(struct vc_data *vc) static int vc_process_ucs(struct vc_data *vc, int *c, int *tc) { u32 prev_c, curr_c = *c; + unsigned int w = ucs_get_width(curr_c); - if (ucs_is_double_width(curr_c)) { + if (likely(w == 1)) + return 1; + + if (w == 2) { /* * The Unicode screen memory is allocated only when * required. This is one such case as we need to remember @@ -3105,12 +3109,9 @@ static int vc_process_ucs(struct vc_data *vc, int *c, int *tc) return 2; } - if (!ucs_is_zero_width(curr_c)) - return 1; - /* From here curr_c is known to be zero-width. */ - if (ucs_is_double_width(vc_uniscr_getc(vc, -2))) { + if (ucs_get_width(vc_uniscr_getc(vc, -2)) == 2) { /* * Let's merge this zero-width code point with the preceding * double-width code point by replacing the existing diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index 6180b803795c..539d488fdc03 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -28,8 +28,7 @@ int conv_uni_to_pc(struct vc_data *conp, long ucs); u32 conv_8bit_to_uni(unsigned char c); int conv_uni_to_8bit(u32 uni); void console_map_init(void); -bool ucs_is_double_width(uint32_t cp); -bool ucs_is_zero_width(uint32_t cp); +unsigned int ucs_get_width(uint32_t cp); u32 ucs_recompose(u32 base, u32 mark); u32 ucs_get_fallback(u32 cp); #else @@ -62,14 +61,9 @@ static inline int conv_uni_to_8bit(u32 uni) static inline void console_map_init(void) { } -static inline bool ucs_is_double_width(uint32_t cp) +static inline unsigned int ucs_get_width(uint32_t cp) { - return false; -} - -static inline bool ucs_is_zero_width(uint32_t cp) -{ - return false; + return 1; } static inline u32 ucs_recompose(u32 base, u32 mark) From b93062b6d8a1b2d9bad235cac25558a909819026 Mon Sep 17 00:00:00 2001 From: Viken Dadhaniya Date: Thu, 28 May 2026 22:48:07 +0530 Subject: [PATCH 47/49] serial: qcom_geni: Fix RX DMA stall when SE_DMA_RX_LEN_IN is zero In qcom_geni_serial_handle_rx_dma(), geni_se_rx_dma_unprep() clears port->rx_dma_addr before SE_DMA_RX_LEN_IN is read. If the register is zero, for example when the RX stale counter fires on an idle line, the handler returns without calling geni_se_rx_dma_prep(). The next RX DMA interrupt then hits the !port->rx_dma_addr guard and returns immediately, so the RX DMA buffer is never rearmed and later input is lost. Keep the handler on the rearm path when rx_in is zero. Warn about the unexpected zero-length DMA completion, skip received-data handling, and always call geni_se_rx_dma_prep(). Fixes: 2aaa43c70778 ("tty: serial: qcom-geni-serial: add support for serial engine DMA") Cc: stable@vger.kernel.org Reviewed-by: Bartosz Golaszewski Signed-off-by: Viken Dadhaniya Link: https://patch.msgid.link/20260528-serial-rx-0-byte-fix-v2-1-b4195cfe342f@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index d81b539cff7f..7ead87b4eb65 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -905,12 +905,9 @@ static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop) port->rx_dma_addr = 0; rx_in = readl(uport->membase + SE_DMA_RX_LEN_IN); - if (!rx_in) { - dev_warn(uport->dev, "serial engine reports 0 RX bytes in!\n"); - return; - } - - if (!drop) + if (!rx_in) + dev_warn_ratelimited(uport->dev, "serial engine reports 0 RX bytes in!\n"); + else if (!drop) handle_rx_uart(uport, rx_in); ret = geni_se_rx_dma_prep(&port->se, port->rx_buf, From a287620312dc6dcb9a093417a0e589bf30fcf38a Mon Sep 17 00:00:00 2001 From: Yi Yang Date: Thu, 4 Jun 2026 06:07:34 +0000 Subject: [PATCH 48/49] vc_screen: fix null-ptr-deref in vcs_notifier() during concurrent vcs_write A KASAN null-ptr-deref was observed in vcs_notifier(): BUG: KASAN: null-ptr-deref in vcs_notifier+0x98/0x130 Read of size 2 at addr qmp_cmd_name: qmp_capabilities, arguments: {} The issue is a race condition in vcs_write(). When the console_lock is temporarily dropped (to copy data from userspace), the vc_data pointer obtained from vcs_vc() may become stale. After re-acquiring the lock, vcs_vc() is called again to re-validate the pointer. If the vc has been deallocated in the meantime, vcs_vc() returns NULL, and the while loop breaks (with written > 0). However, after the loop, vcs_scr_updated(vc) is still called with the now-NULL vc pointer, leading to a null pointer dereference in the notifier chain (vcs_notifier dereferences param->vc). Fix this by adding a NULL check for vc before calling vcs_scr_updated(). Fixes: 8fb9ea65c9d1 ("vc_screen: reload load of struct vc_data pointer in vcs_write() to avoid UAF") Cc: stable@vger.kernel.org Signed-off-by: Yi Yang Reviewed-by: Jiri Slaby Link: https://patch.msgid.link/20260604060734.2914976-1-yiyang13@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vc_screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 4d2d46c95fef..7d40eacc21b3 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -686,7 +686,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) } *ppos += written; ret = written; - if (written) + if (written && vc) vcs_scr_updated(vc); return ret; From 426e83cab1f5d53069ac7030cb03e2d7c6367ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Wed, 3 Jun 2026 11:56:16 +0200 Subject: [PATCH 49/49] serial: 8250_pci: Don't specify conflicting values to pci_device_id members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI_VDEVICE macro assigns 0 to .class and .class_mask to allow the next value in the initializer to define the value for .driver_data. So the construct { PCI_VDEVICE(INTASHIELD, 0x0D21), .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, .class_mask = 0xffff00, .driver_data = pbn_b2_4_115200, }, introduced in commit 44e55f1f3088 ("serial: 8250_pci: Consistently define pci_device_ids using named initializers") has conflicting assignments. In only some configurations (i.e. W=1 for me) that makes the compiler unhappy. So convert the two affected items to PCI_DEVICE which doesn't have that hidden assigment to .class and .class_mask. Fixes: 44e55f1f3088 ("serial: 8250_pci: Consistently define pci_device_ids using named initializers") Signed-off-by: Uwe Kleine-König (The Capable Hub) Reported-by: Andy Shevchenko Closes: https://lore.kernel.org/linux-serial/ah_5qVKOf8LXG1Xo@ashevche-desk.local/T/#ma6eab90ca801b4292639f5c255a89b4033b33d21 Tested-by: Andy Shevchenko Link: https://patch.msgid.link/20260603095616.937968-2-u.kleine-koenig@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 3e5bc9e8d269..58b4e525bdb6 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -5394,12 +5394,12 @@ static const struct pci_device_id serial_pci_tbl[] = { * Brainboxes UC-260/271/701/756 */ { - PCI_VDEVICE(INTASHIELD, 0x0D21), + PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0D21), .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, .class_mask = 0xffff00, .driver_data = pbn_b2_4_115200, }, { - PCI_VDEVICE(INTASHIELD, 0x0E34), + PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0E34), .class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, .class_mask = 0xffff00, .driver_data = pbn_b2_4_115200,