Linux Serial subsystem development
 help / color / mirror / Atom feed
* [PATCH 05/15] serial: 8250_mxpcie: offload XON/XOFF flow control to MUEx50 hardware
From: Crescent Hsieh @ 2026-05-04  8:48 UTC (permalink / raw)
  To: gregkh, jirislaby, ilpo.jarvinen, andy.shevchenko
  Cc: crescentcy.hsieh, fangpingfp.cheng, linux-kernel, linux-serial
In-Reply-To: <20260504084900.22380-1-crescentcy.hsieh@moxa.com>

The MUEx50 UART can handle in-band software flow control (XON/XOFF)
directly in hardware.

Program the on-chip XON/XOFF characters from termios settings and enable
the corresponding MUEx50 flow control modes when IXON or IXOFF is
requested. Provide throttle and unthrottle callbacks so RX can be
stopped and resumed cleanly.

Signed-off-by: Crescent Hsieh <crescentcy.hsieh@moxa.com>
---
 drivers/tty/serial/8250/8250_mxpcie.c | 62 ++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index 89086aa7b228..99fd789b7665 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -54,13 +54,31 @@
 #define MOXA_PUART_SFR_950	BIT(5)
 
 /* Enhanced Function Register (EFR) */
+/*
+ * EFR[1:0] - In-Band Receive Flow Control Mode (Compare XON/XOFF):
+ *	00b (0x00) = Disabled
+ *	01b (0x01) = Recognize XON2 & XOFF2 as XOFF character
+ *	10b (0x02) = Recognize XON1 & XOFF1 as XOFF character
+ *	11b (0x03) = Depends on EFR[3:2]
+ * EFR[3:2] - In-Band Transmit Flow Control Mode (Insert XON/XOFF):
+ *	00b (0x00) = Disabled
+ *	01b (0x04) = Use XON2 & XOFF2 as XOFF character
+ *	10b (0x08) = Use XON1 & XOFF1 as XOFF character
+ *	11b (0x0C) = Reserved
+ */
 #define MOXA_PUART_EFR			0x0A
+#define MOXA_PUART_EFR_RX_FLOW		0x02	/* Recognize XON1 & XOFF1 as XOFF character */
+#define MOXA_PUART_EFR_TX_FLOW		0x08	/* Use XON1 & XOFF1 as XOFF character */
 #define MOXA_PUART_EFR_ENHANCED		BIT(4)
 #define MOXA_PUART_EFR_AUTO_RTS		BIT(6)
 #define MOXA_PUART_EFR_AUTO_CTS		BIT(7)
 #define MOXA_PUART_EFR_RX_FLOW_MASK	GENMASK(1, 0)
 #define MOXA_PUART_EFR_TX_FLOW_MASK	GENMASK(3, 2)
 
+#define MOXA_PUART_XON1		0x0B
+#define MOXA_PUART_XON2		0x0C
+#define MOXA_PUART_XOFF1	0x0D
+#define MOXA_PUART_XOFF2	0x0E
 #define MOXA_PUART_TTL		0x10	/* Tx Interrupt Trigger Level */
 #define MOXA_PUART_RTL		0x11	/* Rx Interrupt Trigger Level */
 #define MOXA_PUART_FCL		0x12	/* Flow Control Low Trigger Level */
@@ -161,7 +179,7 @@ static void mxpcie8250_set_termios(struct uart_port *port,
 
 	serial8250_do_set_termios(port, new, old);
 
-	up->port.status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
+	up->port.status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS | UPSTAT_AUTOXOFF);
 
 	efr = serial_in(up, MOXA_PUART_EFR);
 	efr &= ~(MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
@@ -170,6 +188,21 @@ static void mxpcie8250_set_termios(struct uart_port *port,
 		efr |= (MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
 		up->port.status |= (UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
 	}
+	/* Set on-chip software flow control character */
+	serial_out(up, MOXA_PUART_XON1, START_CHAR(tty));
+	serial_out(up, MOXA_PUART_XON2, START_CHAR(tty));
+	serial_out(up, MOXA_PUART_XOFF1, STOP_CHAR(tty));
+	serial_out(up, MOXA_PUART_XOFF2, STOP_CHAR(tty));
+
+	efr &= ~(MOXA_PUART_EFR_RX_FLOW_MASK | MOXA_PUART_EFR_TX_FLOW_MASK);
+
+	if (I_IXON(tty))
+		efr |= MOXA_PUART_EFR_RX_FLOW;
+
+	if (I_IXOFF(tty)) {
+		efr |= MOXA_PUART_EFR_TX_FLOW;
+		up->port.status |= UPSTAT_AUTOXOFF;
+	}
 	serial_out(up, MOXA_PUART_EFR, efr);
 }
 
@@ -207,6 +240,31 @@ static void mxpcie8250_shutdown(struct uart_port *port)
 	serial8250_do_shutdown(port);
 }
 
+static void mxpcie8250_throttle(struct uart_port *port)
+{
+	unsigned long flags;
+
+	uart_port_lock_irqsave(port, &flags);
+
+	port->ops->stop_rx(port);
+
+	uart_port_unlock_irqrestore(port, flags);
+}
+
+static void mxpcie8250_unthrottle(struct uart_port *port)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+	unsigned long flags;
+
+	uart_port_lock_irqsave(port, &flags);
+
+	up->ier |= UART_IER_RLSI | UART_IER_RDI;
+	port->read_status_mask |= UART_LSR_DR;
+	serial_out(up, UART_IER, up->ier);
+
+	uart_port_unlock_irqrestore(port, flags);
+}
+
 static void mxpcie8250_init_board(struct pci_dev *pdev, struct mxpcie8250 *priv)
 {
 	void __iomem *bar2_base = priv->bar2_base;
@@ -304,6 +362,8 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
 	up.port.set_termios = mxpcie8250_set_termios;
 	up.port.startup = mxpcie8250_startup;
 	up.port.shutdown = mxpcie8250_shutdown;
+	up.port.throttle = mxpcie8250_throttle;
+	up.port.unthrottle = mxpcie8250_unthrottle;
 
 	for (i = 0; i < num_ports; i++) {
 		mxpcie8250_setup_port(pdev, priv, &up, i);
-- 
2.43.0


^ permalink raw reply related

* [PATCH 04/15] serial: 8250_mxpcie: enable automatic RTS/CTS flow control
From: Crescent Hsieh @ 2026-05-04  8:48 UTC (permalink / raw)
  To: gregkh, jirislaby, ilpo.jarvinen, andy.shevchenko
  Cc: crescentcy.hsieh, fangpingfp.cheng, linux-kernel, linux-serial
In-Reply-To: <20260504084900.22380-1-crescentcy.hsieh@moxa.com>

The MUEx50 UART supports automatic RTS/CTS flow control via the enhanced
feature register.

Implement a mxpcie-specific set_termios() callback that enables MUEx50
auto-RTS/auto-CTS when CRTSCTS is requested and disables it otherwise.
Keep the 8250 port status flags in sync with the hardware configuration.

Signed-off-by: Crescent Hsieh <crescentcy.hsieh@moxa.com>
---
 drivers/tty/serial/8250/8250_mxpcie.c | 28 +++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index 7ba96a954bb1..89086aa7b228 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -56,6 +56,10 @@
 /* Enhanced Function Register (EFR) */
 #define MOXA_PUART_EFR			0x0A
 #define MOXA_PUART_EFR_ENHANCED		BIT(4)
+#define MOXA_PUART_EFR_AUTO_RTS		BIT(6)
+#define MOXA_PUART_EFR_AUTO_CTS		BIT(7)
+#define MOXA_PUART_EFR_RX_FLOW_MASK	GENMASK(1, 0)
+#define MOXA_PUART_EFR_TX_FLOW_MASK	GENMASK(3, 2)
 
 #define MOXA_PUART_TTL		0x10	/* Tx Interrupt Trigger Level */
 #define MOXA_PUART_RTL		0x11	/* Rx Interrupt Trigger Level */
@@ -146,6 +150,29 @@ static void mxpcie8250_set_interface(struct mxpcie8250 *priv,
 	iowrite8(cval, uir_addr);
 }
 
+static void mxpcie8250_set_termios(struct uart_port *port,
+				   struct ktermios *new,
+				   const struct ktermios *old)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+	struct tty_struct *tty = port->state->port.tty;
+	unsigned int cflag = tty->termios.c_cflag;
+	u8 efr;
+
+	serial8250_do_set_termios(port, new, old);
+
+	up->port.status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
+
+	efr = serial_in(up, MOXA_PUART_EFR);
+	efr &= ~(MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
+
+	if (cflag & CRTSCTS) {
+		efr |= (MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
+		up->port.status |= (UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
+	}
+	serial_out(up, MOXA_PUART_EFR, efr);
+}
+
 static int mxpcie8250_startup(struct uart_port *port)
 {
 	struct uart_8250_port *up = up_to_u8250p(port);
@@ -274,6 +301,7 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
 	up.port.iobase = 0;
 	up.port.regshift = 0;
 
+	up.port.set_termios = mxpcie8250_set_termios;
 	up.port.startup = mxpcie8250_startup;
 	up.port.shutdown = mxpcie8250_shutdown;
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH 03/15] serial: 8250_mxpcie: enable enhanced mode and program FIFO trigger levels
From: Crescent Hsieh @ 2026-05-04  8:48 UTC (permalink / raw)
  To: gregkh, jirislaby, ilpo.jarvinen, andy.shevchenko
  Cc: crescentcy.hsieh, fangpingfp.cheng, linux-kernel, linux-serial
In-Reply-To: <20260504084900.22380-1-crescentcy.hsieh@moxa.com>

The MUEx50 UART provides an enhanced register set and programmable FIFO
trigger levels for RX, TX, and flow control.

Enable enhanced mode during port startup and program the MUEx50 FIFO
trigger registers according to the configured port settings. Clear the
programmed state again during shutdown to restore the default UART
configuration.

Signed-off-by: Crescent Hsieh <crescentcy.hsieh@moxa.com>
---
 drivers/tty/serial/8250/8250_mxpcie.c | 50 +++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index ec91db1a3008..7ba96a954bb1 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -49,6 +49,19 @@
 #define MOXA_PUART_BASE_BAUD	921600
 #define MOXA_PUART_OFFSET	0x200
 
+/* Special Function Register (SFR) */
+#define MOXA_PUART_SFR		0x07
+#define MOXA_PUART_SFR_950	BIT(5)
+
+/* Enhanced Function Register (EFR) */
+#define MOXA_PUART_EFR			0x0A
+#define MOXA_PUART_EFR_ENHANCED		BIT(4)
+
+#define MOXA_PUART_TTL		0x10	/* Tx Interrupt Trigger Level */
+#define MOXA_PUART_RTL		0x11	/* Rx Interrupt Trigger Level */
+#define MOXA_PUART_FCL		0x12	/* Flow Control Low Trigger Level */
+#define MOXA_PUART_FCH		0x13	/* Flow Control High Trigger Level */
+
 #define MOXA_GPIO_DIRECTION	0x09
 #define MOXA_GPIO_OUTPUT	0x0A
 
@@ -133,6 +146,40 @@ static void mxpcie8250_set_interface(struct mxpcie8250 *priv,
 	iowrite8(cval, uir_addr);
 }
 
+static int mxpcie8250_startup(struct uart_port *port)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+	unsigned int i;
+	int ret;
+
+	ret = serial8250_do_startup(port);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < 5; ++i)
+		serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+
+	serial_out(up, MOXA_PUART_EFR, MOXA_PUART_EFR_ENHANCED);
+	serial_out(up, MOXA_PUART_SFR, MOXA_PUART_SFR_950);
+
+	serial_out(up, MOXA_PUART_TTL, 0);
+	serial_out(up, MOXA_PUART_RTL, 96);
+	serial_out(up, MOXA_PUART_FCL, 16);
+	serial_out(up, MOXA_PUART_FCH, 110);
+
+	return 0;
+}
+
+static void mxpcie8250_shutdown(struct uart_port *port)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+
+	serial_out(up, MOXA_PUART_EFR, 0);
+	serial_out(up, MOXA_PUART_SFR, 0);
+
+	serial8250_do_shutdown(port);
+}
+
 static void mxpcie8250_init_board(struct pci_dev *pdev, struct mxpcie8250 *priv)
 {
 	void __iomem *bar2_base = priv->bar2_base;
@@ -227,6 +274,9 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
 	up.port.iobase = 0;
 	up.port.regshift = 0;
 
+	up.port.startup = mxpcie8250_startup;
+	up.port.shutdown = mxpcie8250_shutdown;
+
 	for (i = 0; i < num_ports; i++) {
 		mxpcie8250_setup_port(pdev, priv, &up, i);
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH 02/15] serial: 8250: add Moxa MUEx50 UART port type
From: Crescent Hsieh @ 2026-05-04  8:48 UTC (permalink / raw)
  To: gregkh, jirislaby, ilpo.jarvinen, andy.shevchenko
  Cc: crescentcy.hsieh, fangpingfp.cheng, linux-kernel, linux-serial
In-Reply-To: <20260504084900.22380-1-crescentcy.hsieh@moxa.com>

Add a new 8250 port type for the Moxa MUEx50 UART and describe its basic
FIFO size and trigger characteristics in the 8250 port configuration
table.

The 8250_mxpcie driver sets UPF_FIXED_TYPE and uses PORT_MUEX50 so that
the generic 8250 core applies the correct defaults.

Signed-off-by: Crescent Hsieh <crescentcy.hsieh@moxa.com>
---
 drivers/tty/serial/8250/8250_mxpcie.c | 3 ++-
 drivers/tty/serial/8250/8250_port.c   | 8 ++++++++
 include/uapi/linux/serial_core.h      | 3 +++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
index aa0afdbed791..ec91db1a3008 100644
--- a/drivers/tty/serial/8250/8250_mxpcie.c
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -220,7 +220,8 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
 	up.port.dev = dev;
 	up.port.irq = pdev->irq;
 	up.port.uartclk = MOXA_PUART_BASE_BAUD * 16;
-	up.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+	up.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+	up.port.type = PORT_MUEX50;
 
 	up.port.iotype = UPIO_MEM;
 	up.port.iobase = 0;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 719faf92aa8a..a17fdb5d68d2 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -310,6 +310,14 @@ static const struct serial8250_config uart_config[] = {
 		.rxtrig_bytes	= {1, 8, 16, 30},
 		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
 	},
+	[PORT_MUEX50] = {
+		.name		= "Moxa MUEx50 UART",
+		.fifo_size	= 128,
+		.tx_loadsz	= 128,
+		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+		.rxtrig_bytes	= {15, 31, 63, 111},
+		.flags		= UART_CAP_FIFO,
+	},
 };
 
 /* Uart divisor latch read */
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 9c007a106330..377884e3856a 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -100,6 +100,9 @@
 /* TXX9 type number */
 #define PORT_TXX9	64
 
+/* Moxa MUEx50 UART */
+#define PORT_MUEX50     65
+
 /*Digi jsm */
 #define PORT_JSM        69
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH 01/15] serial: 8250: split Moxa PCIe serial board support out of 8250_pci
From: Crescent Hsieh @ 2026-05-04  8:48 UTC (permalink / raw)
  To: gregkh, jirislaby, ilpo.jarvinen, andy.shevchenko
  Cc: crescentcy.hsieh, fangpingfp.cheng, linux-kernel, linux-serial
In-Reply-To: <20260504084900.22380-1-crescentcy.hsieh@moxa.com>

The Moxa PCIe multiport serial boards are currently handled as part of
8250_pci.c. In preparation for adding Moxa-specific UART features and
optimizations, move the Moxa PCIe implementation into a dedicated
driver.

This introduces drivers/tty/serial/8250/8250_mxpcie.c and wires it up
via Kconfig and Makefile, while preserving the existing probe flow and
device IDs.

This change was suggested during earlier review by Andy Shevchenko.

No functional change intended.

Link: https://lore.kernel.org/all/ZmQovC6TbDpTb3c8@surfacebook.localdomain/
Link: https://lore.kernel.org/all/CAHp75VeDsVt0GQYUFxLM+obfmqXBPa3hM3YMsFbc26uzWZG-SQ@mail.gmail.com/
Suggested-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Crescent Hsieh <crescentcy.hsieh@moxa.com>
---
 drivers/tty/serial/8250/8250_mxpcie.c | 292 ++++++++++++++++++++++++++
 drivers/tty/serial/8250/8250_pci.c    | 208 +-----------------
 drivers/tty/serial/8250/Kconfig       |  11 +
 drivers/tty/serial/8250/Makefile      |   1 +
 4 files changed, 307 insertions(+), 205 deletions(-)
 create mode 100644 drivers/tty/serial/8250/8250_mxpcie.c

diff --git a/drivers/tty/serial/8250/8250_mxpcie.c b/drivers/tty/serial/8250/8250_mxpcie.c
new file mode 100644
index 000000000000..aa0afdbed791
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_mxpcie.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Moxa PCIe multiport serial device driver
+ *
+ * Copyright (C) 2025 Moxa Inc. (support@moxa.com)
+ * Author: Crescent Hsieh <crescentcy.hsieh@moxa.com>
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/8250_pci.h>
+
+#include "8250.h"
+#include "8250_pcilib.h"
+
+#define PCI_DEVICE_ID_MOXA_CP102E	0x1024
+#define PCI_DEVICE_ID_MOXA_CP102EL	0x1025
+#define PCI_DEVICE_ID_MOXA_CP102N	0x1027
+#define PCI_DEVICE_ID_MOXA_CP104EL_A	0x1045
+#define PCI_DEVICE_ID_MOXA_CP104N	0x1046
+#define PCI_DEVICE_ID_MOXA_CP112N	0x1121
+#define PCI_DEVICE_ID_MOXA_CP114EL	0x1144
+#define PCI_DEVICE_ID_MOXA_CP114N	0x1145
+#define PCI_DEVICE_ID_MOXA_CP116E_A_A	0x1160
+#define PCI_DEVICE_ID_MOXA_CP116E_A_B	0x1161
+#define PCI_DEVICE_ID_MOXA_CP118EL_A	0x1182
+#define PCI_DEVICE_ID_MOXA_CP118E_A_I	0x1183
+#define PCI_DEVICE_ID_MOXA_CP132EL	0x1322
+#define PCI_DEVICE_ID_MOXA_CP132N	0x1323
+#define PCI_DEVICE_ID_MOXA_CP134EL_A	0x1342
+#define PCI_DEVICE_ID_MOXA_CP134N	0x1343
+#define PCI_DEVICE_ID_MOXA_CP138E_A	0x1381
+#define PCI_DEVICE_ID_MOXA_CP168EL_A	0x1683
+
+/* Bits in PCI device ID encoding board capabilities */
+#define MOXA_DEV_ID_IFACE_MASK	GENMASK(11, 8)	/* Supported serial interface */
+#define MOXA_DEV_ID_NPORTS_MASK	GENMASK(7, 4)	/* Number of UART ports */
+
+/* UART */
+#define MOXA_PUART_BASE_BAUD	921600
+#define MOXA_PUART_OFFSET	0x200
+
+#define MOXA_GPIO_DIRECTION	0x09
+#define MOXA_GPIO_OUTPUT	0x0A
+
+#define MOXA_GPIO_PIN2	BIT(2)
+
+#define MOXA_UIR_OFFSET		0x04
+#define MOXA_UIR_RS232		0x00
+#define MOXA_UIR_RS422		0x01
+#define MOXA_UIR_RS485_4W	0x0B
+#define MOXA_UIR_RS485_2W	0x0F
+
+#define MOXA_EVEN_RS_MASK	GENMASK(3, 0)
+#define MOXA_ODD_RS_MASK	GENMASK(7, 4)
+
+struct mxpcie8250 {
+	unsigned int supp_rs;
+	unsigned int num_ports;
+	void __iomem *bar1_base; /* UART registers (MMIO) */
+	void __iomem *bar2_base; /* UIR / GPIO / CPLD (IO) */
+	int line[];
+};
+
+enum {
+	MOXA_SUPP_RS232 = BIT(0),
+	MOXA_SUPP_RS422 = BIT(1),
+	MOXA_SUPP_RS485 = BIT(2),
+};
+
+static bool mxpcie8250_is_mini_pcie(unsigned short device)
+{
+	if (device == PCI_DEVICE_ID_MOXA_CP102N ||
+	    device == PCI_DEVICE_ID_MOXA_CP104N ||
+	    device == PCI_DEVICE_ID_MOXA_CP112N ||
+	    device == PCI_DEVICE_ID_MOXA_CP114N ||
+	    device == PCI_DEVICE_ID_MOXA_CP132N ||
+	    device == PCI_DEVICE_ID_MOXA_CP134N)
+		return true;
+
+	return false;
+}
+
+static unsigned int mxpcie8250_get_supp_rs(unsigned short device)
+{
+	switch (device & MOXA_DEV_ID_IFACE_MASK) {
+	case 0x0000:
+	case 0x0600:
+		return MOXA_SUPP_RS232;
+	case 0x0100:
+		return MOXA_SUPP_RS232 | MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
+	case 0x0300:
+		return MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
+	}
+
+	return 0;
+}
+
+static unsigned short mxpcie8250_get_nports(unsigned short device)
+{
+	switch (device) {
+	case PCI_DEVICE_ID_MOXA_CP116E_A_A:
+	case PCI_DEVICE_ID_MOXA_CP116E_A_B:
+		return 8;
+	}
+
+	return FIELD_GET(MOXA_DEV_ID_NPORTS_MASK, device);
+}
+
+static void mxpcie8250_set_interface(struct mxpcie8250 *priv,
+				     unsigned int port_idx,
+				     u8 mode)
+{
+	void __iomem *uir_addr = priv->bar2_base + MOXA_UIR_OFFSET + port_idx / 2;
+	u8 cval;
+
+	cval = ioread8(uir_addr);
+
+	if (port_idx & 1)
+		cval = FIELD_MODIFY(MOXA_ODD_RS_MASK, &cval, mode);
+	else
+		cval = FIELD_MODIFY(MOXA_EVEN_RS_MASK, &cval, mode);
+
+	iowrite8(cval, uir_addr);
+}
+
+static void mxpcie8250_init_board(struct pci_dev *pdev, struct mxpcie8250 *priv)
+{
+	void __iomem *bar2_base = priv->bar2_base;
+	unsigned short device = pdev->device;
+	u8 cval;
+
+	/* Initial terminator */
+	if (device == PCI_DEVICE_ID_MOXA_CP114EL ||
+	    device == PCI_DEVICE_ID_MOXA_CP118EL_A) {
+		iowrite8(0xff, bar2_base + MOXA_GPIO_DIRECTION);
+		iowrite8(0x00, bar2_base + MOXA_GPIO_OUTPUT);
+	}
+	/*
+	 * Enable hardware buffer to prevent break signal output when system boots up.
+	 * This hardware buffer is only supported on Mini PCIe series.
+	 */
+	if (mxpcie8250_is_mini_pcie(device)) {
+		/* Set GPIO direction */
+		cval = ioread8(bar2_base + MOXA_GPIO_DIRECTION);
+		cval |= MOXA_GPIO_PIN2;
+		iowrite8(cval, bar2_base + MOXA_GPIO_DIRECTION);
+		/* Enable low GPIO */
+		cval = ioread8(bar2_base + MOXA_GPIO_OUTPUT);
+		cval &= ~MOXA_GPIO_PIN2;
+		iowrite8(cval, bar2_base + MOXA_GPIO_OUTPUT);
+	}
+}
+
+static void mxpcie8250_setup_port(struct pci_dev *pdev,
+				  struct mxpcie8250 *priv,
+				  struct uart_8250_port *up,
+				  int idx)
+{
+	unsigned short device = pdev->device;
+	int offset = idx * MOXA_PUART_OFFSET;
+	u8 init_mode = MOXA_UIR_RS232;
+
+	if (!(priv->supp_rs & MOXA_SUPP_RS232))
+		init_mode = MOXA_UIR_RS422;
+
+	mxpcie8250_set_interface(priv, idx, init_mode);
+
+	if (idx == 3 &&
+	    (device == PCI_DEVICE_ID_MOXA_CP104EL_A ||
+	     device == PCI_DEVICE_ID_MOXA_CP114EL   ||
+	     device == PCI_DEVICE_ID_MOXA_CP134EL_A))
+		offset = 7 * MOXA_PUART_OFFSET;
+
+	up->port.mapbase = pci_resource_start(pdev, FL_BASE1) + offset;
+	up->port.membase = pcim_iomap_table(pdev)[FL_BASE1] + offset;
+}
+
+static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct device *dev = &pdev->dev;
+	struct uart_8250_port up = {};
+	struct mxpcie8250 *priv;
+	unsigned short device = pdev->device;
+	unsigned int i, num_ports;
+	int ret;
+
+	ret = pcim_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	num_ports = mxpcie8250_get_nports(device);
+
+	priv = devm_kzalloc(dev, struct_size(priv, line, num_ports), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->supp_rs = mxpcie8250_get_supp_rs(device);
+	priv->num_ports = num_ports;
+
+	priv->bar1_base = pcim_iomap(pdev, FL_BASE1, 0);
+	if (!priv->bar1_base)
+		return -ENOMEM;
+
+	priv->bar2_base = pcim_iomap(pdev, FL_BASE2, 0);
+	if (!priv->bar2_base)
+		return -ENOMEM;
+
+	mxpcie8250_init_board(pdev, priv);
+
+	up.port.dev = dev;
+	up.port.irq = pdev->irq;
+	up.port.uartclk = MOXA_PUART_BASE_BAUD * 16;
+	up.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+
+	up.port.iotype = UPIO_MEM;
+	up.port.iobase = 0;
+	up.port.regshift = 0;
+
+	for (i = 0; i < num_ports; i++) {
+		mxpcie8250_setup_port(pdev, priv, &up, i);
+
+		dev_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n",
+			up.port.iobase, up.port.irq, up.port.iotype);
+
+		priv->line[i] = serial8250_register_8250_port(&up);
+		if (priv->line[i] < 0) {
+			dev_err(dev,
+				"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+				up.port.iobase, up.port.irq,
+				up.port.iotype, priv->line[i]);
+			break;
+		}
+	}
+	dev_set_drvdata(dev, priv);
+
+	return 0;
+}
+
+static void mxpcie8250_remove(struct pci_dev *pdev)
+{
+	struct mxpcie8250 *priv = dev_get_drvdata(&pdev->dev);
+	unsigned int i;
+
+	for (i = 0; i < priv->num_ports; i++)
+		serial8250_unregister_port(priv->line[i]);
+}
+
+static const struct pci_device_id mxpcie8250_pci_ids[] = {
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102E) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102EL) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102N) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104N) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP112N) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114EL) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114N) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132EL) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132N) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134N) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP138E_A) },
+	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A) },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, mxpcie8250_pci_ids);
+
+static struct pci_driver mxpcie8250_pci_driver = {
+	.name		= "8250_mxpcie",
+	.id_table	= mxpcie8250_pci_ids,
+	.probe		= mxpcie8250_probe,
+	.remove		= mxpcie8250_remove,
+};
+module_pci_driver(mxpcie8250_pci_driver);
+
+MODULE_AUTHOR("Moxa Inc.");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Moxa PCIe Multiport Serial Device Driver");
+MODULE_IMPORT_NS("SERIAL_8250_PCI");
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 152f914c599d..fa172477409a 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -76,25 +76,6 @@
 #define PCI_DEVICE_ID_WCHIC_CH384_4S	0x3470
 #define PCI_DEVICE_ID_WCHIC_CH384_8S	0x3853
 
-#define PCI_DEVICE_ID_MOXA_CP102E	0x1024
-#define PCI_DEVICE_ID_MOXA_CP102EL	0x1025
-#define PCI_DEVICE_ID_MOXA_CP102N	0x1027
-#define PCI_DEVICE_ID_MOXA_CP104EL_A	0x1045
-#define PCI_DEVICE_ID_MOXA_CP104N	0x1046
-#define PCI_DEVICE_ID_MOXA_CP112N	0x1121
-#define PCI_DEVICE_ID_MOXA_CP114EL	0x1144
-#define PCI_DEVICE_ID_MOXA_CP114N	0x1145
-#define PCI_DEVICE_ID_MOXA_CP116E_A_A	0x1160
-#define PCI_DEVICE_ID_MOXA_CP116E_A_B	0x1161
-#define PCI_DEVICE_ID_MOXA_CP118EL_A	0x1182
-#define PCI_DEVICE_ID_MOXA_CP118E_A_I	0x1183
-#define PCI_DEVICE_ID_MOXA_CP132EL	0x1322
-#define PCI_DEVICE_ID_MOXA_CP132N	0x1323
-#define PCI_DEVICE_ID_MOXA_CP134EL_A	0x1342
-#define PCI_DEVICE_ID_MOXA_CP134N	0x1343
-#define PCI_DEVICE_ID_MOXA_CP138E_A	0x1381
-#define PCI_DEVICE_ID_MOXA_CP168EL_A	0x1683
-
 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584	0x1584
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1588	0x1588
@@ -1994,138 +1975,6 @@ pci_sunix_setup(struct serial_private *priv,
 	return setup_port(priv, port, bar, offset, 0);
 }
 
-#define MOXA_PUART_GPIO_EN	0x09
-#define MOXA_PUART_GPIO_OUT	0x0A
-
-#define MOXA_GPIO_PIN2	BIT(2)
-
-#define MOXA_RS232	0x00
-#define MOXA_RS422	0x01
-#define MOXA_RS485_4W	0x0B
-#define MOXA_RS485_2W	0x0F
-#define MOXA_UIR_OFFSET	0x04
-#define MOXA_EVEN_RS_MASK	GENMASK(3, 0)
-#define MOXA_ODD_RS_MASK	GENMASK(7, 4)
-
-enum {
-	MOXA_SUPP_RS232 = BIT(0),
-	MOXA_SUPP_RS422 = BIT(1),
-	MOXA_SUPP_RS485 = BIT(2),
-};
-
-static unsigned short moxa_get_nports(unsigned short device)
-{
-	switch (device) {
-	case PCI_DEVICE_ID_MOXA_CP116E_A_A:
-	case PCI_DEVICE_ID_MOXA_CP116E_A_B:
-		return 8;
-	}
-
-	return FIELD_GET(0x00F0, device);
-}
-
-static bool pci_moxa_is_mini_pcie(unsigned short device)
-{
-	if (device == PCI_DEVICE_ID_MOXA_CP102N	||
-	    device == PCI_DEVICE_ID_MOXA_CP104N	||
-	    device == PCI_DEVICE_ID_MOXA_CP112N	||
-	    device == PCI_DEVICE_ID_MOXA_CP114N ||
-	    device == PCI_DEVICE_ID_MOXA_CP132N ||
-	    device == PCI_DEVICE_ID_MOXA_CP134N)
-		return true;
-
-	return false;
-}
-
-static unsigned int pci_moxa_supported_rs(struct pci_dev *dev)
-{
-	switch (dev->device & 0x0F00) {
-	case 0x0000:
-	case 0x0600:
-		return MOXA_SUPP_RS232;
-	case 0x0100:
-		return MOXA_SUPP_RS232 | MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
-	case 0x0300:
-		return MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
-	}
-	return 0;
-}
-
-static int pci_moxa_set_interface(const struct pci_dev *dev,
-				  unsigned int port_idx,
-				  u8 mode)
-{
-	resource_size_t iobar_addr = pci_resource_start(dev, 2);
-	resource_size_t UIR_addr = iobar_addr + MOXA_UIR_OFFSET + port_idx / 2;
-	u8 val;
-
-	val = inb(UIR_addr);
-
-	if (port_idx % 2) {
-		val &= ~MOXA_ODD_RS_MASK;
-		val |= FIELD_PREP(MOXA_ODD_RS_MASK, mode);
-	} else {
-		val &= ~MOXA_EVEN_RS_MASK;
-		val |= FIELD_PREP(MOXA_EVEN_RS_MASK, mode);
-	}
-	outb(val, UIR_addr);
-
-	return 0;
-}
-
-static int pci_moxa_init(struct pci_dev *dev)
-{
-	unsigned short device = dev->device;
-	resource_size_t iobar_addr = pci_resource_start(dev, 2);
-	unsigned int i, num_ports = moxa_get_nports(device);
-	u8 val, init_mode = MOXA_RS232;
-
-	if (!IS_ENABLED(CONFIG_HAS_IOPORT))
-		return serial_8250_warn_need_ioport(dev);
-
-	if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) {
-		init_mode = MOXA_RS422;
-	}
-	for (i = 0; i < num_ports; ++i)
-		pci_moxa_set_interface(dev, i, init_mode);
-
-	/*
-	 * Enable hardware buffer to prevent break signal output when system boots up.
-	 * This hardware buffer is only supported on Mini PCIe series.
-	 */
-	if (pci_moxa_is_mini_pcie(device)) {
-		/* Set GPIO direction */
-		val = inb(iobar_addr + MOXA_PUART_GPIO_EN);
-		val |= MOXA_GPIO_PIN2;
-		outb(val, iobar_addr + MOXA_PUART_GPIO_EN);
-		/* Enable low GPIO */
-		val = inb(iobar_addr + MOXA_PUART_GPIO_OUT);
-		val &= ~MOXA_GPIO_PIN2;
-		outb(val, iobar_addr + MOXA_PUART_GPIO_OUT);
-	}
-
-	return num_ports;
-}
-
-static int
-pci_moxa_setup(struct serial_private *priv,
-		const struct pciserial_board *board,
-		struct uart_8250_port *port, int idx)
-{
-	unsigned int bar = FL_GET_BASE(board->flags);
-	int offset;
-
-	if (!IS_ENABLED(CONFIG_HAS_IOPORT))
-		return serial_8250_warn_need_ioport(priv->dev);
-
-	if (board->num_ports == 4 && idx == 3)
-		offset = 7 * board->uart_offset;
-	else
-		offset = idx * board->uart_offset;
-
-	return setup_port(priv, port, bar, offset, 0);
-}
-
 /*
  * Master list of serial port init/setup/exit quirks.
  * This does not describe the general nature of the port.
@@ -2941,17 +2790,6 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
 		.setup		= pci_fintek_setup,
 		.init		= pci_fintek_init,
 	},
-	/*
-	 * MOXA
-	 */
-	{
-		.vendor		= PCI_VENDOR_ID_MOXA,
-		.device		= PCI_ANY_ID,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-		.init		= pci_moxa_init,
-		.setup		= pci_moxa_setup,
-	},
 	{
 		.vendor		= 0x1c29,
 		.device		= 0x1204,
@@ -3169,9 +3007,6 @@ enum pci_board_num_t {
 	pbn_titan_2_4000000,
 	pbn_titan_4_4000000,
 	pbn_titan_8_4000000,
-	pbn_moxa_2,
-	pbn_moxa_4,
-	pbn_moxa_8,
 };
 
 /*
@@ -3943,24 +3778,6 @@ static struct pciserial_board pci_boards[] = {
 		.uart_offset	= 0x200,
 		.first_offset	= 0x1000,
 	},
-	[pbn_moxa_2] = {
-		.flags		= FL_BASE1,
-		.num_ports      = 2,
-		.base_baud      = 921600,
-		.uart_offset	= 0x200,
-	},
-	[pbn_moxa_4] = {
-		.flags		= FL_BASE1,
-		.num_ports      = 4,
-		.base_baud      = 921600,
-		.uart_offset	= 0x200,
-	},
-	[pbn_moxa_8] = {
-		.flags		= FL_BASE1,
-		.num_ports      = 8,
-		.base_baud      = 921600,
-		.uart_offset	= 0x200,
-	},
 };
 
 #define REPORT_CONFIG(option) \
@@ -4014,6 +3831,9 @@ static const struct pci_device_id blacklist[] = {
 	{ PCI_VDEVICE(PERICOM, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), },
 	{ PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), },
 
+	/* Moxa devices */
+	{ PCI_VDEVICE(MOXA, PCI_ANY_ID), REPORT_8250_CONFIG(MOXA), },
+
 	/* End of the black list */
 	{ }
 };
@@ -5851,28 +5671,6 @@ static const struct pci_device_id serial_pci_tbl[] = {
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		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 },
-
 	/*
 	* ADDI-DATA GmbH communication cards <info@addi-data.com>
 	*/
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index f64ef0819cd4..7cf8547d18f6 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -157,6 +157,17 @@ config SERIAL_8250_EXAR
 	  422x PCIe serial cards that are not covered by the more generic
 	  SERIAL_8250_PCI option.
 
+config SERIAL_8250_MOXA_PCIE
+	tristate "8250/16550 Moxa PCIe device support"
+	depends on SERIAL_8250 && PCI
+	select SERIAL_8250_PCILIB
+	default SERIAL_8250
+	help
+	  Say Y here if you have a Moxa PCIe serial card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called 8250_mxpcie.
+
 config SERIAL_8250_HP300
 	tristate
 	depends on SERIAL_8250 && HP300
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 9ec4d5fe64de..be78fd6b337a 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_SERIAL_8250_LPC18XX)	+= 8250_lpc18xx.o
 obj-$(CONFIG_SERIAL_8250_LPSS)		+= 8250_lpss.o
 obj-$(CONFIG_SERIAL_8250_MEN_MCB)	+= 8250_men_mcb.o
 obj-$(CONFIG_SERIAL_8250_MID)		+= 8250_mid.o
+obj-$(CONFIG_SERIAL_8250_MOXA_PCIE)	+= 8250_mxpcie.o
 obj-$(CONFIG_SERIAL_8250_MT6577)	+= 8250_mtk.o
 obj-$(CONFIG_SERIAL_8250_NI)		+= 8250_ni.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM)	+= 8250_of.o
-- 
2.43.0


^ permalink raw reply related

* [PATCH 00/15] serial: 8250: add MUEx50 support for Moxa PCIe boards
From: Crescent Hsieh @ 2026-05-04  8:48 UTC (permalink / raw)
  To: gregkh, jirislaby, ilpo.jarvinen, andy.shevchenko
  Cc: crescentcy.hsieh, fangpingfp.cheng, linux-kernel, linux-serial

This series moves Moxa PCIe multiport serial board support out of
8250_pci into a dedicated 8250_mxpcie driver, and then extends that
driver to make use of MUEx50-specific UART features.

The split keeps the Moxa-specific logic out of the generic PCI 8250
driver and makes the follow-up changes easier to review. The new driver
continues to use the 8250 core, but adds support for MUEx50 features
such as programmable FIFO trigger levels, automatic hardware and
software flow control, interface mode switching, RS485 break handling,
and FIFO window based RX/TX paths.

The 8250 core changes in this series are limited to wiring optional
low-level driver callbacks for break control and rx_trig_bytes
handling. The hardware-specific behavior remains in the Moxa driver.

The patches are organized as follows:

- split Moxa PCIe board support out of 8250_pci
- add the MUEx50 port type
- add MUEx50-specific driver support and optimizations
- extend the 8250 layer where MUEx50 requires driver-specific handling

Crescent Hsieh (15):
  serial: 8250: split Moxa PCIe serial board support out of 8250_pci
  serial: 8250: add Moxa MUEx50 UART port type
  serial: 8250_mxpcie: enable enhanced mode and program FIFO trigger
    levels
  serial: 8250_mxpcie: enable automatic RTS/CTS flow control
  serial: 8250_mxpcie: offload XON/XOFF flow control to MUEx50 hardware
  serial: 8250_mxpcie: add custom handle_irq callback
  serial: 8250_mxpcie: speed up RX using memory-mapped FIFO window
  serial: 8250_mxpcie: speed up TX using memory-mapped FIFO window
  serial: 8250_mxpcie: introduce per-port private data structure
  serial: 8250_mxpcie: defer uart_write_wakeup() to workqueue
  serial: 8250_mxpcie: support serial interface mode switching
  serial: 8250: allow low-level drivers to override break control
  serial: 8250_mxpcie: add break support for RS485 using MUEx50 features
  serial: 8250: allow UART drivers to override rx_trig_bytes handling
  serial: 8250_mxpcie: implement rx_trig_bytes callbacks via MUEx50 RTL

 drivers/tty/serial/8250/8250_core.c   |   6 +
 drivers/tty/serial/8250/8250_mxpcie.c | 691 ++++++++++++++++++++++++++
 drivers/tty/serial/8250/8250_pci.c    | 208 +-------
 drivers/tty/serial/8250/8250_port.c   |  33 +-
 drivers/tty/serial/8250/Kconfig       |  11 +
 drivers/tty/serial/8250/Makefile      |   1 +
 include/linux/serial_8250.h           |   1 +
 include/linux/serial_core.h           |   3 +
 include/uapi/linux/serial_core.h      |   3 +
 9 files changed, 749 insertions(+), 208 deletions(-)
 create mode 100644 drivers/tty/serial/8250/8250_mxpcie.c

-- 
2.43.0

^ permalink raw reply

* Re: [PATCH v2 02/15] serial: core: add uart_iotype_mmio/legacy_io helper functions
From: Andy Shevchenko @ 2026-05-04  8:48 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Hugo Villeneuve, Greg Kroah-Hartman, Jiri Slaby,
	Ilpo Järvinen, linux-kernel, linux-serial, Hugo Villeneuve
In-Reply-To: <alpine.DEB.2.21.2605030016120.23161@angie.orcam.me.uk>

On Sun, May 03, 2026 at 12:25:24AM +0100, Maciej W. Rozycki wrote:
> On Thu, 30 Apr 2026, Andy Shevchenko wrote:
> 
> > > +bool uart_iotype_legacy_io(enum uart_iotype iotype)
> > 
> > Why do we use 'legacy'? Still in use in modern CPUs...
> 
>  Deprecated in PCIe and not available in numerous systems.  Also actually 
> called "legacy" in some serial port datasheets aged ~20 years now.  While 
> some contemporary CPUs indeed retain the port I/O address space, it's for 
> legacy use anyway, you don't want to rely on it in new designs.

For the holder of the new (modern) CPU which supports the IO ports, this is
definitely not a legacy interface despite on whatever PCIe or other datasheets
call it.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* Re: [PATCH] tty: n_tty: order lockless input availability checks
From: Cen Zhang @ 2026-05-04  8:11 UTC (permalink / raw)
  To: Greg KH; +Cc: jirislaby, peter, linux-kernel, linux-serial, baijiaju1990
In-Reply-To: <2026050455-secret-monetary-bb37@gregkh>

Dear Greg KH

Thanks for taking a look.

> Cool, where are those reports?

Sorry, I should have been clearer.

These are local data-race reports from my pty/tty fuzzing run.
They were produced on v6.17-rc5:

  76eeb9b8de98 ("Linux 6.17-rc5")

The stack line numbers below are from that tested tree.  I also checked
current v7.0.3, and the same relevant plain lockless accesses are still
present there, although some surrounding line numbers have moved.

Report 1:

  ============ DATARACE ============

  Function: chars_in_buffer drivers/tty/n_tty.c:216 [inline]
  Function: n_tty_check_unthrottle+0x25c/0xbd0 drivers/tty/n_tty.c:275
  Function: tty_io_nonblock include/linux/tty.h:323 [inline]
  Function: n_tty_wait_for_input drivers/tty/n_tty.c:2163 [inline]
  Function: n_tty_read+0xed5/0x41f0 drivers/tty/n_tty.c:2264
  Function: tty_read+0x532/0xf50 drivers/tty/tty_io.c:904
  Function: new_sync_read fs/read_write.c:489 [inline]
  Function: vfs_read+0x5fe/0xb70 fs/read_write.c:572
  Function: ksys_read+0xf7/0x1e0 fs/read_write.c:712

  ============OTHER_INFO============

  Function: n_tty_receive_char_canon drivers/tty/n_tty.c:1259 [inline]
  Function: n_tty_receive_char_special drivers/tty/n_tty.c:1372 [inline]
  Function: n_tty_receive_buf_common+0x2cb0/0x3410 drivers/tty/n_tty.c:1588
  Function: n_tty_receive_buf2+0x51/0x80 drivers/tty/n_tty.c:1487
  Function: tty_flip_buffer_commit drivers/tty/tty_buffer.c:515 [inline]
  Function: tty_ldisc_receive_buf+0x1e8/0x450 drivers/tty/tty_buffer.c:532
  Function: paste_selection+0x781/0xcd0

Report 2:

  ============ DATARACE ============

  Function: input_available_p drivers/tty/n_tty.c:1926 [inline]
  Function: n_tty_poll+0x623/0x16b0 drivers/tty/n_tty.c:2452
  Function: tty_poll+0x224/0x4a0 drivers/tty/tty_io.c:2199
  Function: do_select+0xce7/0x13d0 fs/select.c:536
  Function: __do_sys_pselect6+0x1d8/0x240 fs/select.c:793

  ============OTHER_INFO============

  Function: n_tty_set_termios+0x82b/0x37a0 drivers/tty/n_tty.c:1799
  Function: tty_set_termios+0x112d/0x1b80 drivers/tty/tty_ioctl.c:348
  Function: set_termios+0xc1b/0xca0 drivers/tty/tty_ioctl.c:512
  Function: n_tty_ioctl_helper+0xe5/0x8f0 drivers/tty/tty_ioctl.c:982
  Function: n_tty_ioctl+0x253/0x730 drivers/tty/n_tty.c:2509
  Function: tty_ioctl+0x1cfb/0x3070 drivers/tty/tty_io.c:2801

In current v7.0.3, the same relevant source pattern is still present at:

  - chars_in_buffer():
      drivers/tty/n_tty.c:216-218

  - input_available_p():
      drivers/tty/n_tty.c:1912-1915

  - n_tty_set_termios():
      drivers/tty/n_tty.c:1782
      drivers/tty/n_tty.c:1786
      drivers/tty/n_tty.c:1789

Thanks,
Cen

^ permalink raw reply

* Re: [PATCH] tty: n_tty: order lockless input availability checks
From: Greg KH @ 2026-05-04  7:53 UTC (permalink / raw)
  To: Cen Zhang; +Cc: jirislaby, peter, linux-kernel, linux-serial, baijiaju1990
In-Reply-To: <CAFRLqsVMYRESR4dhpcsxXF17FvaX5obXyT0ZXZMkHymnw-6K6Q@mail.gmail.com>

On Mon, May 04, 2026 at 03:47:01PM +0800, Cen Zhang wrote:
> Dear Greg KH
> 
> Thanks for taking a look, and sorry if the changelog made this sound
> stronger than the evidence I have.
> 
> > What tests show that this is needed?  That commit was a long time ago,
> > and surely we would have had some bug reports since then, right?
> >
> > thanks,
> >
> > greg k-h
> 
> The evidence I have is from data-race reports produced while stressing
> pty/tty ioctls.  The relevant stacks, mapped to current v7.0.3 source,
> are:

Cool, where are those reports?

>   - read/unthrottle side:
>       chars_in_buffer() at drivers/tty/n_tty.c:216
>       n_tty_check_unthrottle() at drivers/tty/n_tty.c:275
>       n_tty_read()
> 
>     racing with the receive side:
>       n_tty_receive_char_canon() at drivers/tty/n_tty.c:1258
>       __receive_buf() at drivers/tty/n_tty.c:1588
> 
>   - poll/select side:
>       input_available_p() at drivers/tty/n_tty.c:1912-1915
>       n_tty_poll() at drivers/tty/n_tty.c:2440/2444
> 
>     racing with termios changes:
>       n_tty_set_termios() at drivers/tty/n_tty.c:1782,
>       drivers/tty/n_tty.c:1786 and drivers/tty/n_tty.c:1789
> 
> My reasoning was that these helpers sample the same lockless read-buffer
> availability state that the read/copy paths already handle with
> smp_store_release()/smp_load_acquire(), but I do not have a test showing
> a concrete functional failure beyond the data-race reports.
> 
> Would you prefer that I drop the Fixes tag and respin the changelog to
> describe this as a conservative KCSAN/LKMM cleanup?  Or do you think the
> evidence is too weak for a change here?

I don't really know as I haven't seen any such reports before that I can
recall.

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH] tty: n_tty: order lockless input availability checks
From: Cen Zhang @ 2026-05-04  7:47 UTC (permalink / raw)
  To: Greg KH; +Cc: jirislaby, peter, linux-kernel, linux-serial, baijiaju1990
In-Reply-To: <2026050451-tree-trustful-a841@gregkh>

Dear Greg KH

Thanks for taking a look, and sorry if the changelog made this sound
stronger than the evidence I have.

> What tests show that this is needed?  That commit was a long time ago,
> and surely we would have had some bug reports since then, right?
>
> thanks,
>
> greg k-h

The evidence I have is from data-race reports produced while stressing
pty/tty ioctls.  The relevant stacks, mapped to current v7.0.3 source,
are:

  - read/unthrottle side:
      chars_in_buffer() at drivers/tty/n_tty.c:216
      n_tty_check_unthrottle() at drivers/tty/n_tty.c:275
      n_tty_read()

    racing with the receive side:
      n_tty_receive_char_canon() at drivers/tty/n_tty.c:1258
      __receive_buf() at drivers/tty/n_tty.c:1588

  - poll/select side:
      input_available_p() at drivers/tty/n_tty.c:1912-1915
      n_tty_poll() at drivers/tty/n_tty.c:2440/2444

    racing with termios changes:
      n_tty_set_termios() at drivers/tty/n_tty.c:1782,
      drivers/tty/n_tty.c:1786 and drivers/tty/n_tty.c:1789

My reasoning was that these helpers sample the same lockless read-buffer
availability state that the read/copy paths already handle with
smp_store_release()/smp_load_acquire(), but I do not have a test showing
a concrete functional failure beyond the data-race reports.

Would you prefer that I drop the Fixes tag and respin the changelog to
describe this as a conservative KCSAN/LKMM cleanup?  Or do you think the
evidence is too weak for a change here?

Thanks,
Cen

^ permalink raw reply

* Re: [PATCH] tty: n_tty: order lockless input availability checks
From: Greg KH @ 2026-05-04  7:34 UTC (permalink / raw)
  To: Cen Zhang; +Cc: jirislaby, peter, linux-kernel, linux-serial, baijiaju1990
In-Reply-To: <20260504072321.928921-1-zzzccc427@gmail.com>

On Mon, May 04, 2026 at 03:23:21PM +0800, Cen Zhang wrote:
> The N_TTY read buffer uses release/acquire ordering for its
> lockless ring indices. Input producers release-publish canon_head and
> commit_head after updating the buffer and delimiter flags, and readers
> acquire those heads before copying data. Readers also release-publish
> read_tail before producers use it to calculate room.
> 
> chars_in_buffer() and input_available_p() sample the same indices
> for availability and flow-control decisions, but use plain loads. That
> can miss the ordering used by the data-copy paths and can also let
> poll() observe termios-synthesized availability with weaker ordering
> than normal receive-side publication.
> 
> Use acquire loads for the lockless head/tail samples in those
> helpers. When n_tty_set_termios() updates canonical/noncanonical
> availability, publish the updated heads with release stores as well.
> Keep the cached icanon bit as an intentionally lockless mode snapshot
> and annotate that access.
> 
> Fixes: 70aca71f92ca ("n_tty: Fix unordered accesses to lockless read buffer")
> Signed-off-by: Cen Zhang <zzzccc427@gmail.com>

What tests show that this is needed?  That commit was a long time ago,
and surely we would have had some bug reports since then, right?

thanks,

greg k-h

^ permalink raw reply

* [PATCH] tty: n_tty: order lockless input availability checks
From: Cen Zhang @ 2026-05-04  7:23 UTC (permalink / raw)
  To: gregkh, jirislaby
  Cc: peter, linux-kernel, linux-serial, baijiaju1990, Cen Zhang

The N_TTY read buffer uses release/acquire ordering for its
lockless ring indices. Input producers release-publish canon_head and
commit_head after updating the buffer and delimiter flags, and readers
acquire those heads before copying data. Readers also release-publish
read_tail before producers use it to calculate room.

chars_in_buffer() and input_available_p() sample the same indices
for availability and flow-control decisions, but use plain loads. That
can miss the ordering used by the data-copy paths and can also let
poll() observe termios-synthesized availability with weaker ordering
than normal receive-side publication.

Use acquire loads for the lockless head/tail samples in those
helpers. When n_tty_set_termios() updates canonical/noncanonical
availability, publish the updated heads with release stores as well.
Keep the cached icanon bit as an intentionally lockless mode snapshot
and annotate that access.

Fixes: 70aca71f92ca ("n_tty: Fix unordered accesses to lockless read buffer")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
 drivers/tty/n_tty.c | 32 +++++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index e6a0f5b40d0a..56b0cd96a453 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -213,9 +213,17 @@ static void n_tty_kick_worker(const struct tty_struct *tty)
 static ssize_t chars_in_buffer(const struct tty_struct *tty)
 {
 	const struct n_tty_data *ldata = tty->disc_data;
-	size_t head = ldata->icanon ? ldata->canon_head : ldata->commit_head;
+	bool icanon = data_race((int)ldata->icanon); /* lockless snapshot */
+	size_t head;
+	size_t tail;
 
-	return head - ldata->read_tail;
+	if (icanon)
+		head = smp_load_acquire(&ldata->canon_head); /* producer publish */
+	else
+		head = smp_load_acquire(&ldata->commit_head); /* producer publish */
+	tail = smp_load_acquire(&ldata->read_tail); /* consumer publish */
+
+	return head - tail;
 }
 
 /**
@@ -1779,14 +1787,14 @@ static void n_tty_set_termios(struct tty_struct *tty, const struct ktermios *old
 		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
 		ldata->line_start = ldata->read_tail;
 		if (!L_ICANON(tty) || !read_cnt(ldata)) {
-			ldata->canon_head = ldata->read_tail;
+			smp_store_release(&ldata->canon_head, ldata->read_tail); /* publish */
 			ldata->push = 0;
 		} else {
 			set_bit(MASK(ldata->read_head - 1), ldata->read_flags);
-			ldata->canon_head = ldata->read_head;
+			smp_store_release(&ldata->canon_head, ldata->read_head); /* publish */
 			ldata->push = 1;
 		}
-		ldata->commit_head = ldata->read_head;
+		smp_store_release(&ldata->commit_head, ldata->read_head); /* publish */
 		ldata->erasing = 0;
 		ldata->lnext = 0;
 	}
@@ -1908,11 +1916,17 @@ static inline int input_available_p(const struct tty_struct *tty, int poll)
 {
 	const struct n_tty_data *ldata = tty->disc_data;
 	int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
+	bool icanon = data_race((int)ldata->icanon); /* lockless snapshot */
+	size_t tail = smp_load_acquire(&ldata->read_tail); /* consumer publish */
+	size_t head;
 
-	if (ldata->icanon && !L_EXTPROC(tty))
-		return ldata->canon_head != ldata->read_tail;
-	else
-		return ldata->commit_head - ldata->read_tail >= amt;
+	if (icanon && !L_EXTPROC(tty)) {
+		head = smp_load_acquire(&ldata->canon_head); /* producer publish */
+		return head != tail;
+	}
+
+	head = smp_load_acquire(&ldata->commit_head); /* producer publish */
+	return head - tail >= amt;
 }
 
 /**
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] serial: fsl_lpuart: fix rx buffer and DMA map leaks in start_rx_dma
From: Shitalkumar Gandhi @ 2026-05-04  6:49 UTC (permalink / raw)
  To: gregkh
  Cc: Frank.Li, bhuvanchandra.dv, imx, jirislaby, linux-arm-kernel,
	linux-kernel, linux-serial, peng.fan, sherry.sun, shital.gandhi45,
	Shitalkumar Gandhi
In-Reply-To: <2026050410-frozen-fondue-5476@gregkh>

On Mon, May 04, 2026 at 08:24:20AM +0200, Greg Kroah-Hartman wrote:
> > Any update on this? It has Frank's Reviewed-by but I don't see
> > it queued in tty-next or tty-testing yet.
>
> What is "this"?  I see no context here :(

Sorry for the missing context. The patch is:

  serial: fsl_lpuart: fix rx buffer and DMA map leaks in start_rx_dma

Fixes three error paths in lpuart_start_rx_dma() that leak ring->buf
and the DMA mapping. Sent April 20, Frank Li gave Reviewed-by on
April 21.

Lore: https://lore.kernel.org/linux-serial/20260420135903.2062024-1-shitalkumar.gandhi@cambiumnetworks.com/

Happy to resend with Frank's Reviewed-by added if that helps.

Thanks,
Shital

^ permalink raw reply

* Re: [PATCH] serial: fsl_lpuart: fix rx buffer and DMA map leaks in start_rx_dma
From: Greg Kroah-Hartman @ 2026-05-04  6:24 UTC (permalink / raw)
  To: Shitalkumar Gandhi
  Cc: Jiri Slaby, Frank Li, Bhuvanchandra DV, Peng Fan, Sherry Sun,
	linux-serial, imx, linux-arm-kernel, linux-kernel,
	Shitalkumar Gandhi
In-Reply-To: <20260503194921.3449864-1-shitalkumar.gandhi@cambiumnetworks.com>

On Mon, May 04, 2026 at 01:19:21AM +0530, Shitalkumar Gandhi wrote:
> Hi Greg,
> 
> Any update on this? It has Frank's Reviewed-by but I don't see
> it queued in tty-next or tty-testing yet.

What is "this"?  I see no context here :(

^ permalink raw reply

* [PATCH v3] tty: synclink_gt: remove broken driver
From: Ethan Nelson-Moore @ 2026-05-04  3:14 UTC (permalink / raw)
  To: linux-doc, netdev, linux-serial, rust-for-linux
  Cc: Ethan Nelson-Moore, Jonathan Corbet, Shuah Khan,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Greg Kroah-Hartman,
	Jiri Slaby, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Bagas Sanjaya, Haren Myneni,
	Eric Biggers, Julian Braha, Qingfang Deng

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 <enelsonmoore@gmail.com>
---
Changes from v2:
Remove UAPI header - I have sent a pull request to remove it from
linux-raw-sys

 .../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 <callahan@maths.ox.ac.uk>,
  *	Al Longyear <longyear@netcom.com>,
  *	Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
@@ -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 <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioctl.h>
-#include <linux/termios.h>
-#include <linux/bitops.h>
-#include <linux/workqueue.h>
-#include <linux/hdlc.h>
-#include <linux/synclink.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-#include <asm/types.h>
-#include <linux/uaccess.h>
-
-#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<linecount;i++) {
-			if (data[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(&params, &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, &params, 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 <uapi/linux/synclink.h>
-
-/* provide 32 bit ioctl compatibility on 64 bit systems */
-#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
-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 <linux/types.h>
-
-#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_ */
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] serial: fsl_lpuart: fix rx buffer and DMA map leaks in start_rx_dma
From: Shitalkumar Gandhi @ 2026-05-03 19:49 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby
  Cc: Frank Li, Bhuvanchandra DV, Peng Fan, Sherry Sun, linux-serial,
	imx, linux-arm-kernel, linux-kernel, Shitalkumar Gandhi
In-Reply-To: <20260420135903.2062024-1-shitalkumar.gandhi@cambiumnetworks.com>

Hi Greg,

Any update on this? It has Frank's Reviewed-by but I don't see
it queued in tty-next or tty-testing yet.

Thanks,
Shital

^ permalink raw reply

* Re: [PATCH v2] tty: synclink_gt: remove broken driver
From: Ethan Nelson-Moore @ 2026-05-03 19:25 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Greg Kroah-Hartman, linux-doc, netdev, linux-serial,
	rust-for-linux, Jonathan Corbet, Shuah Khan, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Jiri Slaby, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Bagas Sanjaya, Haren Myneni,
	Eric Biggers, Qingfang Deng, Julian Braha
In-Reply-To: <e12da6e2-5e50-4819-a5a8-2bc675da4c14@lunn.ch>

Hi, Andrew,

On Sun, May 3, 2026 at 7:23 AM Andrew Lunn <andrew@lunn.ch> wrote:
> Sounds like a whack a mole problem. I assume the recent removal of ATM
> broke it as well? Maybe __has_include() could be used?
That's a great idea. I will investigate that.

Ethan

^ permalink raw reply

* Re: [PATCH v2] tty: synclink_gt: remove broken driver
From: Andrew Lunn @ 2026-05-03 14:23 UTC (permalink / raw)
  To: Ethan Nelson-Moore
  Cc: Greg Kroah-Hartman, linux-doc, netdev, linux-serial,
	rust-for-linux, Jonathan Corbet, Shuah Khan, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Jiri Slaby, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Bagas Sanjaya, Haren Myneni,
	Eric Biggers, Qingfang Deng, Julian Braha
In-Reply-To: <CADkSEUgPtjkKC684O3qB=koKDPwJoUj-qU_4Z_18NAU_+bBqkw@mail.gmail.com>

On Sat, May 02, 2026 at 11:00:53PM -0700, Ethan Nelson-Moore wrote:
> Hi, Greg,
> 
> On Sat, May 2, 2026 at 10:44 PM Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> > Then that means someone uses it somewhere.  Don't generate bindings for
> > something that will break because it is no longer in the tree :(
> That project generates bindings for every UAPI header automatically,
> but has a hardcoded list of them, so its presence there doesn't mean
> anyone is using it.
> 
> > If no one does use it, then please get that project to fix their code so
> > that we don't break their build.
> They have had to remove headers from their list that got removed from
> the kernel before. I will send them a pull request to remove this
> header and then resend this patch with the UAPI header removal
> restored. Does that sound good to you?

Sounds like a whack a mole problem. I assume the recent removal of ATM
broke it as well? Maybe __has_include() could be used?

      Andrew

^ permalink raw reply

* Re: [PATCH v2] tty: synclink_gt: remove broken driver
From: Greg Kroah-Hartman @ 2026-05-03  6:08 UTC (permalink / raw)
  To: Ethan Nelson-Moore
  Cc: linux-doc, netdev, linux-serial, rust-for-linux, Jonathan Corbet,
	Shuah Khan, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Jiri Slaby, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Bagas Sanjaya, Haren Myneni,
	Eric Biggers, Qingfang Deng, Julian Braha
In-Reply-To: <CADkSEUgPtjkKC684O3qB=koKDPwJoUj-qU_4Z_18NAU_+bBqkw@mail.gmail.com>

On Sat, May 02, 2026 at 11:00:53PM -0700, Ethan Nelson-Moore wrote:
> Hi, Greg,
> 
> On Sat, May 2, 2026 at 10:44 PM Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> > Then that means someone uses it somewhere.  Don't generate bindings for
> > something that will break because it is no longer in the tree :(
> That project generates bindings for every UAPI header automatically,
> but has a hardcoded lost of them, so its presence there doesn't mean
> anyone is using it.
> 
> > If no one does use it, then please get that project to fix their code so
> > that we don't break their build.
> They have had to remove headers from their list that got removed from
> the kernel before. I will send them a pull request to remove this
> header and then resend this patch with the UAPI header removal
> restored. Does that sound good to you?

Yes, thanks.


^ permalink raw reply

* Re: [PATCH v2] tty: synclink_gt: remove broken driver
From: Ethan Nelson-Moore @ 2026-05-03  6:00 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-doc, netdev, linux-serial, rust-for-linux, Jonathan Corbet,
	Shuah Khan, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Jiri Slaby, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Bagas Sanjaya, Haren Myneni,
	Eric Biggers, Qingfang Deng, Julian Braha
In-Reply-To: <2026050340-kilogram-prissy-a833@gregkh>

Hi, Greg,

On Sat, May 2, 2026 at 10:44 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> Then that means someone uses it somewhere.  Don't generate bindings for
> something that will break because it is no longer in the tree :(
That project generates bindings for every UAPI header automatically,
but has a hardcoded lost of them, so its presence there doesn't mean
anyone is using it.

> If no one does use it, then please get that project to fix their code so
> that we don't break their build.
They have had to remove headers from their list that got removed from
the kernel before. I will send them a pull request to remove this
header and then resend this patch with the UAPI header removal
restored. Does that sound good to you?

Ethan

^ permalink raw reply

* Re: [PATCH v2] tty: synclink_gt: remove broken driver
From: Greg Kroah-Hartman @ 2026-05-03  5:43 UTC (permalink / raw)
  To: Ethan Nelson-Moore
  Cc: linux-doc, netdev, linux-serial, rust-for-linux, Jonathan Corbet,
	Shuah Khan, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Jiri Slaby, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Bagas Sanjaya, Haren Myneni,
	Eric Biggers, Qingfang Deng, Julian Braha
In-Reply-To: <20260503030801.14080-1-enelsonmoore@gmail.com>

On Sat, May 02, 2026 at 08:07:38PM -0700, Ethan Nelson-Moore wrote:
> 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.
> Retain include/uapi/linux/synclink.h to avoid breaking userspace
> software.
> 
> Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
> ---
> Changes from v1:
> - Retain UAPI header - the linux-raw-sys Rust crate generates bindings
> for it [1]

Then that means someone uses it somewhere.  Don't generate bindings for
something that will break because it is no longer in the tree :(

If no one does use it, then please get that project to fix their code so
that we don't break their build.

thanks,

greg k-h

^ permalink raw reply

* [PATCH v2] tty: synclink_gt: remove broken driver
From: Ethan Nelson-Moore @ 2026-05-03  3:07 UTC (permalink / raw)
  To: linux-doc, netdev, linux-serial, rust-for-linux
  Cc: Ethan Nelson-Moore, Jonathan Corbet, Shuah Khan,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Greg Kroah-Hartman,
	Jiri Slaby, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Bagas Sanjaya, Haren Myneni,
	Eric Biggers, Qingfang Deng, Julian Braha

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.
Retain include/uapi/linux/synclink.h to avoid breaking userspace
software.

Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
---
Changes from v1:
- Retain UAPI header - the linux-raw-sys Rust crate generates bindings
for it [1]
- Remove Documentation/userspace-api/ioctl/ioctl-number.rst entry
instead of marking it as dead; other recent driver removals have simply
removed entries
[1] https://github.com/sunfishcode/linux-raw-sys/blob/3b15c17f2688445cd3e9ef2907113829837773dd/gen/ioctl/list.c#L151

 .../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 -
 8 files changed, 3 insertions(+), 5097 deletions(-)
 delete mode 100644 drivers/tty/synclink_gt.c
 delete mode 100644 include/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 <callahan@maths.ox.ac.uk>,
  *	Al Longyear <longyear@netcom.com>,
  *	Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
@@ -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 <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioctl.h>
-#include <linux/termios.h>
-#include <linux/bitops.h>
-#include <linux/workqueue.h>
-#include <linux/hdlc.h>
-#include <linux/synclink.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-#include <asm/types.h>
-#include <linux/uaccess.h>
-
-#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<linecount;i++) {
-			if (data[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(&params, &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, &params, 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 <uapi/linux/synclink.h>
-
-/* provide 32 bit ioctl compatibility on 64 bit systems */
-#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
-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_ */
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH v2 02/15] serial: core: add uart_iotype_mmio/legacy_io helper functions
From: Maciej W. Rozycki @ 2026-05-02 23:25 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Hugo Villeneuve, Greg Kroah-Hartman, Jiri Slaby,
	Ilpo Järvinen, linux-kernel, linux-serial, Hugo Villeneuve
In-Reply-To: <afNwaUf8esqaqxUe@black.igk.intel.com>

On Thu, 30 Apr 2026, Andy Shevchenko wrote:

> > +bool uart_iotype_legacy_io(enum uart_iotype iotype)
> 
> Why do we use 'legacy'? Still in use in modern CPUs...

 Deprecated in PCIe and not available in numerous systems.  Also actually 
called "legacy" in some serial port datasheets aged ~20 years now.  While 
some contemporary CPUs indeed retain the port I/O address space, it's for 
legacy use anyway, you don't want to rely on it in new designs.

  Maciej

^ permalink raw reply

* [syzbot] Monthly serial report (May 2026)
From: syzbot @ 2026-05-02 20:32 UTC (permalink / raw)
  To: gregkh, linux-kernel, linux-serial, syzkaller-bugs

Hello serial maintainers/developers,

This is a 31-day syzbot report for the serial subsystem.
All related reports/information can be found at:
https://syzkaller.appspot.com/upstream/s/serial

During the period, 2 new issues were detected and 0 were fixed.
In total, 18 issues are still open and 48 have already been fixed.

Some of the still happening issues:

Ref Crashes Repro Title
<1> 3947    Yes   possible deadlock in console_lock_spinning_enable (5)
                  https://syzkaller.appspot.com/bug?extid=622acb507894a48b2ce9
<2> 3513    Yes   KMSAN: uninit-value in n_tty_receive_buf_standard
                  https://syzkaller.appspot.com/bug?extid=559c7fe4b8bac56d38c2
<3> 1194    Yes   BUG: soft lockup in tx
                  https://syzkaller.appspot.com/bug?extid=5e87db90e68fbc4707c6
<4> 255     Yes   INFO: task can't die in show_free_areas
                  https://syzkaller.appspot.com/bug?extid=8f41dccfb6c03cc36fd6
<5> 177     No    possible deadlock in kbd_event
                  https://syzkaller.appspot.com/bug?extid=781c8bb5e4d62cc883d3
<6> 131     Yes   possible deadlock in tty_buffer_flush (3)
                  https://syzkaller.appspot.com/bug?extid=52cf91760dcb1dac6376
<7> 61      No    KMSAN: uninit-value in n_tty_lookahead_flow_ctrl (2)
                  https://syzkaller.appspot.com/bug?extid=290abdcd4f509377a0eb
<8> 10      No    KASAN: slab-out-of-bounds Write in do_con_write (3)
                  https://syzkaller.appspot.com/bug?extid=8e9c1abac3ceb45abffe

---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

To disable reminders for individual bugs, reply with the following command:
#syz set <Ref> no-reminders

To change bug's subsystems, reply with:
#syz set <Ref> subsystems: new-subsystem

You may send multiple commands in a single email message.

^ permalink raw reply

* [PATCH v2 10/10] MIPS: DEC: Ensure RTC platform device deregistration upon failure
From: Maciej W. Rozycki @ 2026-05-01 23:15 UTC (permalink / raw)
  To: Thomas Bogendoerfer, Greg Kroah-Hartman, Jiri Slaby
  Cc: linux-mips, linux-serial, linux-serial
In-Reply-To: <alpine.DEB.2.21.2604302336260.38805@angie.orcam.me.uk>

Switch RTC platform device registration from platform_device_register() 
to platform_add_devices() so as to make sure any failure will result in 
automatic device deregistration.

Fixes: fae67ad43114 ("arch/mips/dec: switch DECstation systems to rtc-cmos")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
No change from v1 (8/8),
<https://lore.kernel.org/r/alpine.DEB.2.21.2604110042130.29980@angie.orcam.me.uk/>.
---
 arch/mips/dec/platform.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

linux-mips-dec-platform-rtc-unregister.diff
Index: linux-macro/arch/mips/dec/platform.c
===================================================================
--- linux-macro.orig/arch/mips/dec/platform.c
+++ linux-macro/arch/mips/dec/platform.c
@@ -38,6 +38,10 @@ static struct platform_device dec_rtc_de
 	.num_resources = ARRAY_SIZE(dec_rtc_resources),
 };
 
+static struct platform_device *dec_rtc_devices[] __initdata = {
+	&dec_rtc_device,
+};
+
 static struct resource dec_dz_resources[] = {
 	{ .name = "dz", .flags = IORESOURCE_MEM, },
 	{ .name = "dz", .flags = IORESOURCE_IRQ, },
@@ -137,7 +141,7 @@ static int __init dec_add_devices(void)
 	}
 	num_zs = i;
 
-	ret1 = platform_device_register(&dec_rtc_device);
+	ret1 = platform_add_devices(dec_rtc_devices, 1);
 	ret2 = IS_ENABLED(CONFIG_32BIT) ?
 	       platform_add_devices(dec_dz_devices, num_dz) : 0;
 	ret3 = platform_add_devices(dec_zs_devices, num_zs);

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox