From c808fab604ca62cff19ee6b261211483830807aa Mon Sep 17 00:00:00 2001 From: Andy Shevchenko <andy.shevchenko@gmail.com> Date: Wed, 7 Oct 2020 11:46:34 +0300 Subject: [PATCH 01/89] serial: max310x: Make use of device properties Device property API allows to gather device resources from different sources, such as ACPI. Convert the drivers to unleash the power of device property API. Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com> Link: https://lore.kernel.org/r/20201007084635.594991-1-andy.shevchenko@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/max310x.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 21130af106bb..f25b9516109c 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -15,8 +15,8 @@ #include <linux/device.h> #include <linux/gpio/driver.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/serial_core.h> #include <linux/serial.h> @@ -267,7 +267,7 @@ struct max310x_one { container_of(_port, struct max310x_one, port) struct max310x_port { - struct max310x_devtype *devtype; + const struct max310x_devtype *devtype; struct regmap *regmap; struct clk *clk; #ifdef CONFIG_GPIOLIB @@ -1269,7 +1269,7 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, } #endif -static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, +static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, struct regmap *regmap, int irq) { int i, ret, fmin, fmax, freq, uartclk; @@ -1478,7 +1478,7 @@ static struct regmap_config regcfg = { #ifdef CONFIG_SPI_MASTER static int max310x_spi_probe(struct spi_device *spi) { - struct max310x_devtype *devtype; + const struct max310x_devtype *devtype; struct regmap *regmap; int ret; @@ -1490,18 +1490,9 @@ static int max310x_spi_probe(struct spi_device *spi) if (ret) return ret; - if (spi->dev.of_node) { - const struct of_device_id *of_id = - of_match_device(max310x_dt_ids, &spi->dev); - if (!of_id) - return -ENODEV; - - devtype = (struct max310x_devtype *)of_id->data; - } else { - const struct spi_device_id *id_entry = spi_get_device_id(spi); - - devtype = (struct max310x_devtype *)id_entry->driver_data; - } + devtype = device_get_match_data(&spi->dev); + if (!devtype) + devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; regcfg.max_register = devtype->nr * 0x20 - 1; regmap = devm_regmap_init_spi(spi, ®cfg); @@ -1526,7 +1517,7 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table); static struct spi_driver max310x_spi_driver = { .driver = { .name = MAX310X_NAME, - .of_match_table = of_match_ptr(max310x_dt_ids), + .of_match_table = max310x_dt_ids, .pm = &max310x_pm_ops, }, .probe = max310x_spi_probe, From 974e454d6f96da0c0ab1b4115b92587dd9406f6a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko <andy.shevchenko@gmail.com> Date: Wed, 7 Oct 2020 11:46:35 +0300 Subject: [PATCH 02/89] serial: max310x: Use devm_clk_get_optional() to get the input clock Simplify the code which fetches the input clock by using devm_clk_get_optional(). If no input clock is present devm_clk_get_optional() will return NULL instead of an error which matches the behavior of the old code. Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com> Link: https://lore.kernel.org/r/20201007084635.594991-2-andy.shevchenko@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/max310x.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index f25b9516109c..9795b2e8b0b2 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1273,7 +1273,6 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty struct regmap *regmap, int irq) { int i, ret, fmin, fmax, freq, uartclk; - struct clk *clk_osc, *clk_xtal; struct max310x_port *s; bool xtal = false; @@ -1287,23 +1286,24 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty return -ENOMEM; } - clk_osc = devm_clk_get(dev, "osc"); - clk_xtal = devm_clk_get(dev, "xtal"); - if (!IS_ERR(clk_osc)) { - s->clk = clk_osc; + s->clk = devm_clk_get_optional(dev, "osc"); + if (IS_ERR(s->clk)) + return PTR_ERR(s->clk); + if (s->clk) { fmin = 500000; fmax = 35000000; - } else if (!IS_ERR(clk_xtal)) { - s->clk = clk_xtal; - fmin = 1000000; - fmax = 4000000; - xtal = true; - } else if (PTR_ERR(clk_osc) == -EPROBE_DEFER || - PTR_ERR(clk_xtal) == -EPROBE_DEFER) { - return -EPROBE_DEFER; } else { - dev_err(dev, "Cannot get clock\n"); - return -EINVAL; + s->clk = devm_clk_get_optional(dev, "xtal"); + if (IS_ERR(s->clk)) + return PTR_ERR(s->clk); + if (s->clk) { + fmin = 1000000; + fmax = 4000000; + xtal = true; + } else { + dev_err(dev, "Cannot get clock\n"); + return -EINVAL; + } } ret = clk_prepare_enable(s->clk); From 1a460c36078e1c7c979ce2ead581ec9e40f2aac8 Mon Sep 17 00:00:00 2001 From: Tom Rix <trix@redhat.com> Date: Mon, 19 Oct 2020 10:57:32 -0700 Subject: [PATCH 03/89] tty: nozomi: remove unneeded break A break is not needed if it is preceded by a return Add explicit fallthrough Signed-off-by: Tom Rix <trix@redhat.com> Link: https://lore.kernel.org/r/20201019175732.3289-1-trix@redhat.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/nozomi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index d42b854cb7df..861e95043191 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -414,11 +414,9 @@ static void read_mem32(u32 *buf, const void __iomem *mem_addr_start, buf16 = (u16 *) buf; *buf16 = __le16_to_cpu(readw(ptr)); goto out; - break; case 4: /* 4 bytes */ *(buf) = __le32_to_cpu(readl(ptr)); goto out; - break; } while (i < size_bytes) { @@ -460,15 +458,14 @@ static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, buf16 = (const u16 *)buf; writew(__cpu_to_le16(*buf16), ptr); return 2; - break; case 1: /* * also needs to write 4 bytes in this case * so falling through.. */ + fallthrough; case 4: /* 4 bytes */ writel(__cpu_to_le32(*buf), ptr); return 4; - break; } while (i < size_bytes) { From da31de35cd2fb78f75788873e0b61e56d4bb1a90 Mon Sep 17 00:00:00 2001 From: Laurent Vivier <laurent@vivier.eu> Date: Sat, 10 Oct 2020 02:47:49 +0200 Subject: [PATCH 04/89] tty: goldfish: use __raw_writel()/__raw_readl() gf_early_console_putchar() uses __raw_writel() but the standard driver uses writel()/readl(). This means we can't use both on the same machine as the device is either big-endian, little-endian or native-endian. As android implementation defines the endianness of the device is the one of the architecture replace all writel()/readl() by __raw_writel()/__raw_readl() https://android.googlesource.com/platform/external/qemu/+/refs/heads/emu-master-dev/hw/char/goldfish_tty.c#222 Signed-off-by: Laurent Vivier <laurent@vivier.eu> Link: https://lore.kernel.org/r/20201010004749.1201695-1-laurent@vivier.eu Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/goldfish.c | 18 +++++++++--------- include/linux/goldfish.h | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index c8c5cdfc5e19..cd23a4b05c8f 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -61,13 +61,13 @@ static void do_rw_io(struct goldfish_tty *qtty, spin_lock_irqsave(&qtty->lock, irq_flags); gf_write_ptr((void *)address, base + GOLDFISH_TTY_REG_DATA_PTR, base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); - writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); + __raw_writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); if (is_write) - writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, + __raw_writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_REG_CMD); else - writel(GOLDFISH_TTY_CMD_READ_BUFFER, + __raw_writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_REG_CMD); spin_unlock_irqrestore(&qtty->lock, irq_flags); @@ -142,7 +142,7 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) unsigned char *buf; u32 count; - count = readl(base + GOLDFISH_TTY_REG_BYTES_READY); + count = __raw_readl(base + GOLDFISH_TTY_REG_BYTES_READY); if (count == 0) return IRQ_NONE; @@ -159,7 +159,7 @@ static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty) { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); - writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_REG_CMD); + __raw_writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_REG_CMD); return 0; } @@ -167,7 +167,7 @@ static void goldfish_tty_shutdown(struct tty_port *port) { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); - writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_REG_CMD); + __raw_writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_REG_CMD); } static int goldfish_tty_open(struct tty_struct *tty, struct file *filp) @@ -202,7 +202,7 @@ static int goldfish_tty_chars_in_buffer(struct tty_struct *tty) { struct goldfish_tty *qtty = &goldfish_ttys[tty->index]; void __iomem *base = qtty->base; - return readl(base + GOLDFISH_TTY_REG_BYTES_READY); + return __raw_readl(base + GOLDFISH_TTY_REG_BYTES_READY); } static void goldfish_tty_console_write(struct console *co, const char *b, @@ -357,7 +357,7 @@ static int goldfish_tty_probe(struct platform_device *pdev) * on Ranchu emulator (qemu2) returns 1 here and * driver will use physical addresses. */ - qtty->version = readl(base + GOLDFISH_TTY_REG_VERSION); + qtty->version = __raw_readl(base + GOLDFISH_TTY_REG_VERSION); /* * Goldfish TTY device on Ranchu emulator (qemu2) @@ -376,7 +376,7 @@ static int goldfish_tty_probe(struct platform_device *pdev) } } - writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD); + __raw_writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD); ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", qtty); diff --git a/include/linux/goldfish.h b/include/linux/goldfish.h index 265a099cd3b8..12be1601fd84 100644 --- a/include/linux/goldfish.h +++ b/include/linux/goldfish.h @@ -13,9 +13,9 @@ static inline void gf_write_ptr(const void *ptr, void __iomem *portl, { const unsigned long addr = (unsigned long)ptr; - writel(lower_32_bits(addr), portl); + __raw_writel(lower_32_bits(addr), portl); #ifdef CONFIG_64BIT - writel(upper_32_bits(addr), porth); + __raw_writel(upper_32_bits(addr), porth); #endif } @@ -23,9 +23,9 @@ static inline void gf_write_dma_addr(const dma_addr_t addr, void __iomem *portl, void __iomem *porth) { - writel(lower_32_bits(addr), portl); + __raw_writel(lower_32_bits(addr), portl); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - writel(upper_32_bits(addr), porth); + __raw_writel(upper_32_bits(addr), porth); #endif } From 6b8f8313c3174a8caa45ef5319cb9c8dde7cb8a8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:06 +0100 Subject: [PATCH 05/89] vt: keyboard, remove ctrl_alt_del declaration ctrl_alt_del is already declared in linux/reboot.h which we include. So remove this second (superfluous) declaration. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 78acc270e39a..69bbb6c1b3de 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -49,8 +49,6 @@ #include <asm/irq_regs.h> -extern void ctrl_alt_del(void); - /* * Exported functions/variables */ From 0df97c7b5b1878273925483cf43fd67df7613d84 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:07 +0100 Subject: [PATCH 06/89] vt: keyboard, include linux/spinlock.h We use spin locks, but don't include linux/spinlock.h in keyboards.c. So fix this up. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 69bbb6c1b3de..275093a15564 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -33,6 +33,7 @@ #include <linux/tty_flip.h> #include <linux/mm.h> #include <linux/nospec.h> +#include <linux/spinlock.h> #include <linux/string.h> #include <linux/init.h> #include <linux/slab.h> From 877a9c6a0439afbb2675e4e70ca4216912124772 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:08 +0100 Subject: [PATCH 07/89] vt: keyboard, sort includes There are many includes and it is hard to check if something is there or not. So sort them alphabetically. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 275093a15564..9e45feb15a3e 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -26,27 +26,26 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/consolemap.h> -#include <linux/module.h> -#include <linux/sched/signal.h> -#include <linux/sched/debug.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/jiffies.h> +#include <linux/kbd_diacr.h> +#include <linux/kbd_kern.h> +#include <linux/leds.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/nospec.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/sched/debug.h> +#include <linux/sched/signal.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/leds.h> - -#include <linux/kbd_kern.h> -#include <linux/kbd_diacr.h> -#include <linux/vt_kern.h> -#include <linux/input.h> -#include <linux/reboot.h> -#include <linux/notifier.h> -#include <linux/jiffies.h> +#include <linux/tty_flip.h> +#include <linux/tty.h> #include <linux/uaccess.h> +#include <linux/vt_kern.h> #include <asm/irq_regs.h> From ee49df4505347daa68d87e318503d2037154ee6a Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:09 +0100 Subject: [PATCH 08/89] vt: keyboard, sort key types by their number KT_LETTER was numerically missorted. So sort all KT_* entries. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- include/uapi/linux/keyboard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/keyboard.h b/include/uapi/linux/keyboard.h index 4846716e7c5c..36d230cedf12 100644 --- a/include/uapi/linux/keyboard.h +++ b/include/uapi/linux/keyboard.h @@ -27,7 +27,6 @@ #define MAX_NR_FUNC 256 /* max nr of strings assigned to keys */ #define KT_LATIN 0 /* we depend on this being zero */ -#define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */ #define KT_FN 1 #define KT_SPEC 2 #define KT_PAD 3 @@ -38,6 +37,7 @@ #define KT_META 8 #define KT_ASCII 9 #define KT_LOCK 10 +#define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */ #define KT_SLOCK 12 #define KT_DEAD2 13 #define KT_BRL 14 From e27979dace0438fabc0a8e882356d20f532eb1e3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:10 +0100 Subject: [PATCH 09/89] vt: keyboard, clean up max_vals Define one limit per line and index them by their index, so that it is clear what is what. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 9e45feb15a3e..4545afd3ef2f 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -111,10 +111,22 @@ static struct kbd_struct kbd_table[MAX_NR_CONSOLES]; static struct kbd_struct *kbd = kbd_table; /* maximum values each key_handler can handle */ -static const int max_vals[] = { - 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, - NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, - 255, NR_LOCK - 1, 255, NR_BRL - 1 +static const unsigned char max_vals[] = { + [ KT_LATIN ] = 255, + [ KT_FN ] = ARRAY_SIZE(func_table) - 1, + [ KT_SPEC ] = ARRAY_SIZE(fn_handler) - 1, + [ KT_PAD ] = NR_PAD - 1, + [ KT_DEAD ] = NR_DEAD - 1, + [ KT_CONS ] = 255, + [ KT_CUR ] = 3, + [ KT_SHIFT ] = NR_SHIFT - 1, + [ KT_META ] = 255, + [ KT_ASCII ] = NR_ASCII - 1, + [ KT_LOCK ] = NR_LOCK - 1, + [ KT_LETTER ] = 255, + [ KT_SLOCK ] = NR_LOCK - 1, + [ KT_DEAD2 ] = 255, + [ KT_BRL ] = NR_BRL - 1, }; static const int NR_TYPES = ARRAY_SIZE(max_vals); From fe6416e126cc17c0454c9c32d06b81a4e58ed8b7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:11 +0100 Subject: [PATCH 10/89] vt: keyboard, extract vt_kdgkbent and vt_kdskbent Split vt_do_kdsk_ioctl into three functions: * getter (KDGKBENT/vt_kdgkbent) * setter (KDSKBENT/vt_kdskbent) * switch-case helper (vt_do_kdsk_ioctl) This eliminates the need of ugly one-letter macros as we use parameters now: * i aka tmp.kb_index -> idx * s aka tmp.kb_table -> map * v aka tmp.kb_value -> val Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 193 ++++++++++++++++++++------------------ 1 file changed, 104 insertions(+), 89 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 4545afd3ef2f..c1709b8dbb52 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1897,19 +1897,111 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, return kc; } -#define i (tmp.kb_index) -#define s (tmp.kb_table) -#define v (tmp.kb_value) +static unsigned short vt_kdgkbent(unsigned char kbdmode, unsigned char idx, + unsigned char map) +{ + unsigned short *key_map, val; + unsigned long flags; + + /* Ensure another thread doesn't free it under us */ + spin_lock_irqsave(&kbd_event_lock, flags); + key_map = key_maps[map]; + if (key_map) { + val = U(key_map[idx]); + if (kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + val = K_HOLE; + } else + val = idx ? K_HOLE : K_NOSUCHMAP; + spin_unlock_irqrestore(&kbd_event_lock, flags); + + return val; +} + +static int vt_kdskbent(unsigned char kbdmode, unsigned char idx, + unsigned char map, unsigned short val) +{ + unsigned long flags; + unsigned short *key_map, *new_map, oldval; + + if (!idx && val == K_NOSUCHMAP) { + spin_lock_irqsave(&kbd_event_lock, flags); + /* deallocate map */ + key_map = key_maps[map]; + if (map && key_map) { + key_maps[map] = NULL; + if (key_map[0] == U(K_ALLOCATED)) { + kfree(key_map); + keymap_count--; + } + } + spin_unlock_irqrestore(&kbd_event_lock, flags); + + return 0; + } + + if (KTYP(val) < NR_TYPES) { + if (KVAL(val) > max_vals[KTYP(val)]) + return -EINVAL; + } else if (kbdmode != VC_UNICODE) + return -EINVAL; + + /* ++Geert: non-PC keyboards may generate keycode zero */ +#if !defined(__mc68000__) && !defined(__powerpc__) + /* assignment to entry 0 only tests validity of args */ + if (!idx) + return 0; +#endif + + new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + spin_lock_irqsave(&kbd_event_lock, flags); + key_map = key_maps[map]; + if (key_map == NULL) { + int j; + + if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && + !capable(CAP_SYS_RESOURCE)) { + spin_unlock_irqrestore(&kbd_event_lock, flags); + kfree(new_map); + return -EPERM; + } + key_maps[map] = new_map; + key_map = new_map; + key_map[0] = U(K_ALLOCATED); + for (j = 1; j < NR_KEYS; j++) + key_map[j] = U(K_HOLE); + keymap_count++; + } else + kfree(new_map); + + oldval = U(key_map[idx]); + if (val == oldval) + goto out; + + /* Attention Key */ + if ((oldval == K_SAK || val == K_SAK) && !capable(CAP_SYS_ADMIN)) { + spin_unlock_irqrestore(&kbd_event_lock, flags); + return -EPERM; + } + + key_map[idx] = U(val); + if (!map && (KTYP(oldval) == KT_SHIFT || KTYP(val) == KT_SHIFT)) + do_compute_shiftstate(); +out: + spin_unlock_irqrestore(&kbd_event_lock, flags); + + return 0; +} int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, int console) { struct kbd_struct *kb = kbd_table + console; - struct kbentry tmp; - ushort *key_map, *new_map, val, ov; - unsigned long flags; + struct kbentry kbe; - if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) + if (copy_from_user(&kbe, user_kbe, sizeof(struct kbentry))) return -EFAULT; if (!capable(CAP_SYS_TTY_CONFIG)) @@ -1917,94 +2009,17 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, switch (cmd) { case KDGKBENT: - /* Ensure another thread doesn't free it under us */ - spin_lock_irqsave(&kbd_event_lock, flags); - key_map = key_maps[s]; - if (key_map) { - val = U(key_map[i]); - if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) - val = K_HOLE; - } else - val = (i ? K_HOLE : K_NOSUCHMAP); - spin_unlock_irqrestore(&kbd_event_lock, flags); - return put_user(val, &user_kbe->kb_value); + return put_user(vt_kdgkbent(kb->kbdmode, kbe.kb_index, + kbe.kb_table), + &user_kbe->kb_value); case KDSKBENT: if (!perm) return -EPERM; - if (!i && v == K_NOSUCHMAP) { - spin_lock_irqsave(&kbd_event_lock, flags); - /* deallocate map */ - key_map = key_maps[s]; - if (s && key_map) { - key_maps[s] = NULL; - if (key_map[0] == U(K_ALLOCATED)) { - kfree(key_map); - keymap_count--; - } - } - spin_unlock_irqrestore(&kbd_event_lock, flags); - break; - } - - if (KTYP(v) < NR_TYPES) { - if (KVAL(v) > max_vals[KTYP(v)]) - return -EINVAL; - } else - if (kb->kbdmode != VC_UNICODE) - return -EINVAL; - - /* ++Geert: non-PC keyboards may generate keycode zero */ -#if !defined(__mc68000__) && !defined(__powerpc__) - /* assignment to entry 0 only tests validity of args */ - if (!i) - break; -#endif - - new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); - if (!new_map) - return -ENOMEM; - spin_lock_irqsave(&kbd_event_lock, flags); - key_map = key_maps[s]; - if (key_map == NULL) { - int j; - - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && - !capable(CAP_SYS_RESOURCE)) { - spin_unlock_irqrestore(&kbd_event_lock, flags); - kfree(new_map); - return -EPERM; - } - key_maps[s] = new_map; - key_map = new_map; - key_map[0] = U(K_ALLOCATED); - for (j = 1; j < NR_KEYS; j++) - key_map[j] = U(K_HOLE); - keymap_count++; - } else - kfree(new_map); - - ov = U(key_map[i]); - if (v == ov) - goto out; - /* - * Attention Key. - */ - if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) { - spin_unlock_irqrestore(&kbd_event_lock, flags); - return -EPERM; - } - key_map[i] = U(v); - if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) - do_compute_shiftstate(); -out: - spin_unlock_irqrestore(&kbd_event_lock, flags); - break; + return vt_kdskbent(kb->kbdmode, kbe.kb_index, kbe.kb_table, + kbe.kb_value); } return 0; } -#undef i -#undef s -#undef v /* FIXME: This one needs untangling */ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) From ee1cf8a58273d53ef56c578810f2a94b1aeb55a4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:12 +0100 Subject: [PATCH 11/89] vt: keyboard, union perm checks in vt_do_kdsk_ioctl Do the permission check on a single place. That is where perm is really checked. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-7-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index c1709b8dbb52..823df9bb52b1 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -2004,16 +2004,13 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, if (copy_from_user(&kbe, user_kbe, sizeof(struct kbentry))) return -EFAULT; - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - switch (cmd) { case KDGKBENT: return put_user(vt_kdgkbent(kb->kbdmode, kbe.kb_index, kbe.kb_table), &user_kbe->kb_value); case KDSKBENT: - if (!perm) + if (!perm || !capable(CAP_SYS_TTY_CONFIG)) return -EPERM; return vt_kdskbent(kb->kbdmode, kbe.kb_index, kbe.kb_table, kbe.kb_value); From 2939840c998de5f688ffa7cd6a2d490b00d67832 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:13 +0100 Subject: [PATCH 12/89] vt: keyboard, use DECLARE_BITMAP for key_down key_down is sued as a bitmap using test_bit, set_bit and similar. So declare it using DECLARE_BITMAP to make it obvious even from the declaration. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 823df9bb52b1..c4791f33c145 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -135,7 +135,7 @@ static struct input_handler kbd_handler; static DEFINE_SPINLOCK(kbd_event_lock); static DEFINE_SPINLOCK(led_lock); static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */ -static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ +static DECLARE_BITMAP(key_down, KEY_CNT); /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static bool dead_key_next; From fe45d6578610caab01d0728878527046f0e023f8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:14 +0100 Subject: [PATCH 13/89] vt: keyboard, use bool for rep rep is used as a bool in the code, so declare it as such. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-9-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index c4791f33c145..e47a1c6bfa44 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -144,7 +144,7 @@ static bool npadch_active; static unsigned int npadch_value; static unsigned int diacr; -static char rep; /* flag telling character repeat */ +static bool rep; /* flag telling character repeat */ static int shift_state = 0; From 9788c950ed4ad2020a7f2e8231abaf77e49d871a Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:15 +0100 Subject: [PATCH 14/89] vt: keyboard, rename i to kb_func in vt_do_kdgkb_ioctl There are too many one-letter variables in vt_do_kdgkb_ioctl which is rather confusing. Rename 'i' to 'kb_func' and change its type to be the same as its originating value (struct kbsentry.kb_func) -- unsigned char. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-10-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index e47a1c6bfa44..55014f57a3de 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -2026,9 +2026,10 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) int sz, fnw_sz; int delta; char *first_free, *fj, *fnw; - int i, j, k; + int j, k; int ret; unsigned long flags; + unsigned char kb_func; if (!capable(CAP_SYS_TTY_CONFIG)) perm = 0; @@ -2045,7 +2046,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) goto reterr; } kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; - i = array_index_nospec(kbs->kb_func, MAX_NR_FUNC); + kb_func = array_index_nospec(kbs->kb_func, MAX_NR_FUNC); switch (cmd) { case KDGKBSENT: { @@ -2053,7 +2054,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) ssize_t len = sizeof(user_kdgkb->kb_string); spin_lock_irqsave(&func_buf_lock, flags); - len = strlcpy(kbs->kb_string, func_table[i] ? : "", len); + len = strlcpy(kbs->kb_string, func_table[kb_func] ? : "", len); spin_unlock_irqrestore(&func_buf_lock, flags); ret = copy_to_user(user_kdgkb->kb_string, kbs->kb_string, @@ -2072,11 +2073,11 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) /* race aginst other writers */ again: spin_lock_irqsave(&func_buf_lock, flags); - q = func_table[i]; + q = func_table[kb_func]; /* fj pointer to next entry after 'q' */ first_free = funcbufptr + (funcbufsize - funcbufleft); - for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) + for (j = kb_func + 1; j < MAX_NR_FUNC && !func_table[j]; j++) ; if (j < MAX_NR_FUNC) fj = func_table[j]; @@ -2094,7 +2095,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) func_table[k] += delta; } if (!q) - func_table[i] = fj; + func_table[kb_func] = fj; funcbufleft -= delta; } else { /* allocate a larger buffer */ sz = 256; @@ -2113,7 +2114,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) } if (!q) - func_table[i] = fj; + func_table[kb_func] = fj; /* copy data before insertion point to new location */ if (fj > funcbufptr) memmove(fnw, funcbufptr, fj - funcbufptr); @@ -2135,7 +2136,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) funcbufsize = sz; } /* finally insert item itself */ - strcpy(func_table[i], kbs->kb_string); + strcpy(func_table[kb_func], kbs->kb_string); spin_unlock_irqrestore(&func_buf_lock, flags); break; } From 07edff9265204e15c9fc8d07cc69e38c4c484e15 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:16 +0100 Subject: [PATCH 15/89] vt: keyboard, reorder user buffer handling in vt_do_kdgkb_ioctl KDGKBSENT (the getter) needs only 'user_kdgkb->kb_func' from the userspace, i.e. the index. Then it needs a buffer for a local copy of 'kb_string'. KDSKBSENT (the setter) needs a copy up to the length of 'user_kdgkb->kb_string'. That means, we obtain the index before the switch-case and use it in both paths and: 1) allocate full space in the getter case, and 2) copy the string only in the setter case. We do it by strndup_user helper now which was not available when this function was written. Given we copy the two members of 'struct kbsentry' separately, we no longer need a local definition. Hence we need to change all the sizeofs here too. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-11-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 42 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 55014f57a3de..81afe0438b34 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -2021,7 +2021,7 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, /* FIXME: This one needs untangling */ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) { - struct kbsentry *kbs; + char *kbs; u_char *q; int sz, fnw_sz; int delta; @@ -2034,39 +2034,37 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) if (!capable(CAP_SYS_TTY_CONFIG)) perm = 0; - kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); - if (!kbs) { - ret = -ENOMEM; - goto reterr; - } + if (get_user(kb_func, &user_kdgkb->kb_func)) + return -EFAULT; - /* we mostly copy too much here (512bytes), but who cares ;) */ - if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { - ret = -EFAULT; - goto reterr; - } - kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; - kb_func = array_index_nospec(kbs->kb_func, MAX_NR_FUNC); + kb_func = array_index_nospec(kb_func, MAX_NR_FUNC); switch (cmd) { case KDGKBSENT: { /* size should have been a struct member */ ssize_t len = sizeof(user_kdgkb->kb_string); + kbs = kmalloc(len, GFP_KERNEL); + if (!kbs) + return -ENOMEM; + spin_lock_irqsave(&func_buf_lock, flags); - len = strlcpy(kbs->kb_string, func_table[kb_func] ? : "", len); + len = strlcpy(kbs, func_table[kb_func] ? : "", len); spin_unlock_irqrestore(&func_buf_lock, flags); - ret = copy_to_user(user_kdgkb->kb_string, kbs->kb_string, - len + 1) ? -EFAULT : 0; + ret = copy_to_user(user_kdgkb->kb_string, kbs, len + 1) ? + -EFAULT : 0; goto reterr; } case KDSKBSENT: - if (!perm) { - ret = -EPERM; - goto reterr; - } + if (!perm) + return -EPERM; + + kbs = strndup_user(user_kdgkb->kb_string, + sizeof(user_kdgkb->kb_string)); + if (IS_ERR(kbs)) + return PTR_ERR(kbs); fnw = NULL; fnw_sz = 0; @@ -2084,7 +2082,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) else fj = first_free; /* buffer usage increase by new entry */ - delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); + delta = (q ? -strlen(q) : 1) + strlen(kbs); if (delta <= funcbufleft) { /* it fits in current buf */ if (j < MAX_NR_FUNC) { @@ -2136,7 +2134,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) funcbufsize = sz; } /* finally insert item itself */ - strcpy(func_table[kb_func], kbs->kb_string); + strcpy(func_table[kb_func], kbs); spin_unlock_irqrestore(&func_buf_lock, flags); break; } From 4e1404a5cd043672e8039fe6f440d0b09c916303 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:17 +0100 Subject: [PATCH 16/89] vt: keyboard, extract and simplify vt_kdskbsent Setting of function key strings is now very complex. It uses a global buffer 'func_buf' which is prefilled in defkeymap.c_shipped. Then there is also an index table called 'func_table'. So initially, we have something like this: char func_buf[] = "\e[[A\0" // for F1 "\e[[B\0" // for F2 ...; char *func_table[] = { func_buf + 0, // for F1 func_buf + 5, // for F2 ... } When a user changes some specific func string by KDSKBSENT, it is changed in 'func_buf'. If it is shorter or equal to the current one, it is handled by a very quick 'strcpy'. When the user's string is longer, the whole 'func_buf' is reallocated to allow expansion somewhere in the middle. The buffer before the user's string is copied, the user's string appended and the rest appended too. Now, the index table (func_table) needs to be recomputed, of course. One more complication is the held spinlock -- we have to unlock, reallocate, lock again and do the whole thing again to be sure noone raced with us. In this patch, we chose completely orthogonal approach: when the user's string is longer than the current one, we simply assign the 'kstrdup'ed copy to the index table (func_table) and modify func_buf in no way. We only need to make sure we free the old entries. So we need a bitmap is_kmalloc and free the old entries (but not the original func_buf rodata string). Also note that we do not waste so much space as previous approach. We only allocate space for single entries which are longer, while before, the whole buffer was duplicated plus space for the longer string. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-12-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 104 +++++++++----------------------------- 1 file changed, 24 insertions(+), 80 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 81afe0438b34..648bdfb05e25 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -2018,18 +2018,27 @@ int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, return 0; } -/* FIXME: This one needs untangling */ +static char *vt_kdskbsent(char *kbs, unsigned char cur) +{ + static DECLARE_BITMAP(is_kmalloc, MAX_NR_FUNC); + char *cur_f = func_table[cur]; + + if (cur_f && strlen(cur_f) >= strlen(kbs)) { + strcpy(cur_f, kbs); + return kbs; + } + + func_table[cur] = kbs; + + return __test_and_set_bit(cur, is_kmalloc) ? cur_f : NULL; +} + int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) { - char *kbs; - u_char *q; - int sz, fnw_sz; - int delta; - char *first_free, *fj, *fnw; - int j, k; - int ret; - unsigned long flags; unsigned char kb_func; + unsigned long flags; + char *kbs; + int ret; if (!capable(CAP_SYS_TTY_CONFIG)) perm = 0; @@ -2055,7 +2064,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) ret = copy_to_user(user_kdgkb->kb_string, kbs, len + 1) ? -EFAULT : 0; - goto reterr; + break; } case KDSKBSENT: if (!perm) @@ -2066,81 +2075,16 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) if (IS_ERR(kbs)) return PTR_ERR(kbs); - fnw = NULL; - fnw_sz = 0; - /* race aginst other writers */ - again: spin_lock_irqsave(&func_buf_lock, flags); - q = func_table[kb_func]; - - /* fj pointer to next entry after 'q' */ - first_free = funcbufptr + (funcbufsize - funcbufleft); - for (j = kb_func + 1; j < MAX_NR_FUNC && !func_table[j]; j++) - ; - if (j < MAX_NR_FUNC) - fj = func_table[j]; - else - fj = first_free; - /* buffer usage increase by new entry */ - delta = (q ? -strlen(q) : 1) + strlen(kbs); - - if (delta <= funcbufleft) { /* it fits in current buf */ - if (j < MAX_NR_FUNC) { - /* make enough space for new entry at 'fj' */ - memmove(fj + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] += delta; - } - if (!q) - func_table[kb_func] = fj; - funcbufleft -= delta; - } else { /* allocate a larger buffer */ - sz = 256; - while (sz < funcbufsize - funcbufleft + delta) - sz <<= 1; - if (fnw_sz != sz) { - spin_unlock_irqrestore(&func_buf_lock, flags); - kfree(fnw); - fnw = kmalloc(sz, GFP_KERNEL); - fnw_sz = sz; - if (!fnw) { - ret = -ENOMEM; - goto reterr; - } - goto again; - } - - if (!q) - func_table[kb_func] = fj; - /* copy data before insertion point to new location */ - if (fj > funcbufptr) - memmove(fnw, funcbufptr, fj - funcbufptr); - for (k = 0; k < j; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr); - - /* copy data after insertion point to new location */ - if (first_free > fj) { - memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; - } - if (funcbufptr != func_buf) - kfree(funcbufptr); - funcbufptr = fnw; - funcbufleft = funcbufleft - delta + sz - funcbufsize; - funcbufsize = sz; - } - /* finally insert item itself */ - strcpy(func_table[kb_func], kbs); + kbs = vt_kdskbsent(kbs, kb_func); spin_unlock_irqrestore(&func_buf_lock, flags); + + ret = 0; break; } - ret = 0; -reterr: + kfree(kbs); + return ret; } From 2374a045263b47f763571ec87ad7c65ea505188a Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:18 +0100 Subject: [PATCH 17/89] vt: keyboard, remove unneeded func_* declarations Now that we removed the ugly handling of func_buf, remove unneeded declarations of func_* variables. The definitions are in the generated defkeymap.c_shipped, so we cannot really remove them (but we would love to). Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-13-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- include/linux/kbd_kern.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index bb2246c8ec13..82f29aa35062 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -9,9 +9,6 @@ extern struct tasklet_struct keyboard_tasklet; extern char *func_table[MAX_NR_FUNC]; -extern char func_buf[]; -extern char *funcbufptr; -extern int funcbufsize, funcbufleft; /* * kbd->xxx contains the VC-local things (flag settings etc..) From cb58a5046095c0b28031f1f412c27ce21df604ae Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:19 +0100 Subject: [PATCH 18/89] vt: keyboard, union perm checks in vt_do_kdgkb_ioctl Do the permission check on a single place. That is where perm is really checked. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-14-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 648bdfb05e25..1de0d5217aed 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -2040,9 +2040,6 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) char *kbs; int ret; - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - if (get_user(kb_func, &user_kdgkb->kb_func)) return -EFAULT; @@ -2067,7 +2064,7 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) break; } case KDSKBSENT: - if (!perm) + if (!perm || !capable(CAP_SYS_TTY_CONFIG)) return -EPERM; kbs = strndup_user(user_kdgkb->kb_string, From 6dee84d6bed747653914298a8913e91391a2ce10 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:20 +0100 Subject: [PATCH 19/89] vt: keyboard, make HW_RAW a function Instead of a multiline macro, convert HW_RAW to an inline function. It allows for type checking of the parameter. And given we split the code into two tests, it is now more readable too. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-15-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 1de0d5217aed..dea2f25a5d9f 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1259,8 +1259,14 @@ DECLARE_TASKLET_DISABLED_OLD(keyboard_tasklet, kbd_bh); defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) -#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ - ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) +static inline bool kbd_is_hw_raw(const struct input_dev *dev) +{ + if (!test_bit(EV_MSC, dev->evbit) || !test_bit(MSC_RAW, dev->mscbit)) + return false; + + return dev->id.bustype == BUS_I8042 && + dev->id.vendor == 0x0001 && dev->id.product == 0x0001; +} static const unsigned short x86_keycodes[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -1345,7 +1351,10 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, #else -#define HW_RAW(dev) 0 +static inline bool kbd_is_hw_raw(const struct input_dev *dev) +{ + return false; +} static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { @@ -1366,7 +1375,7 @@ static void kbd_rawcode(unsigned char data) put_queue(vc, data); } -static void kbd_keycode(unsigned int keycode, int down, int hw_raw) +static void kbd_keycode(unsigned int keycode, int down, bool hw_raw) { struct vc_data *vc = vc_cons[fg_console].d; unsigned short keysym, *key_map; @@ -1511,10 +1520,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, /* We are called with interrupts disabled, just take the lock */ spin_lock(&kbd_event_lock); - if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) + if (event_type == EV_MSC && event_code == MSC_RAW && + kbd_is_hw_raw(handle->dev)) kbd_rawcode(value); if (event_type == EV_KEY && event_code <= KEY_MAX) - kbd_keycode(event_code, value, HW_RAW(handle->dev)); + kbd_keycode(event_code, value, kbd_is_hw_raw(handle->dev)); spin_unlock(&kbd_event_lock); From 2389cdc36007ba28ebe6640d7dd5e3494318a909 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:21 +0100 Subject: [PATCH 20/89] vt: keyboard, use find_next_bit in kbd_match Instead of a 'for' loop with 'test_bit's to find a bit in a range, use find_next_bit to achieve the same in a simpler and faster manner. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-16-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index dea2f25a5d9f..149f1791d7ec 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1535,18 +1535,16 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, static bool kbd_match(struct input_handler *handler, struct input_dev *dev) { - int i; - if (test_bit(EV_SND, dev->evbit)) return true; if (test_bit(EV_KEY, dev->evbit)) { - for (i = KEY_RESERVED; i < BTN_MISC; i++) - if (test_bit(i, dev->keybit)) - return true; - for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++) - if (test_bit(i, dev->keybit)) - return true; + if (find_next_bit(dev->keybit, BTN_MISC, KEY_RESERVED) < + BTN_MISC) + return true; + if (find_next_bit(dev->keybit, KEY_BRL_DOT10 + 1, + KEY_BRL_DOT1) <= KEY_BRL_DOT10) + return true; } return false; From c35f638fc2adbb9c439ce68b559d406387cbdbe8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby <jslaby@suse.cz> Date: Thu, 29 Oct 2020 12:32:22 +0100 Subject: [PATCH 21/89] vt: keyboard, use tty_insert_flip_string in puts_queue 'puts_queue' currently loops over characters and employs the full tty buffer machinery for every character. Do the buffer allocation only once and copy all the character at once. This is achieved using tty_insert_flip_string instead of loop+tty_insert_flip_char. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Link: https://lore.kernel.org/r/20201029113222.32640-17-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 149f1791d7ec..56b5e8f8fe88 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -324,12 +324,9 @@ static void put_queue(struct vc_data *vc, int ch) tty_schedule_flip(&vc->port); } -static void puts_queue(struct vc_data *vc, char *cp) +static void puts_queue(struct vc_data *vc, const char *cp) { - while (*cp) { - tty_insert_flip_char(&vc->port, *cp, 0); - cp++; - } + tty_insert_flip_string(&vc->port, cp, strlen(cp)); tty_schedule_flip(&vc->port); } From c0ed8ecb177de776fd02ad3e0b00787828de1fb2 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:14 +0000 Subject: [PATCH 22/89] tty: serdev: core: Remove unused variable 'dummy' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to have a dummy variable here. Fixes the following W=1 kernel build warning(s): drivers/tty/serdev/core.c: In function ‘serdev_controller_remove’: drivers/tty/serdev/core.c:791:6: warning: variable ‘dummy’ set but not used [-Wunused-but-set-variable] Cc: Rob Herring <robh@kernel.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-2-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serdev/core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index c5f0d936b003..fecc28a73b3b 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -788,13 +788,10 @@ static int serdev_remove_device(struct device *dev, void *data) */ void serdev_controller_remove(struct serdev_controller *ctrl) { - int dummy; - if (!ctrl) return; - dummy = device_for_each_child(&ctrl->dev, NULL, - serdev_remove_device); + device_for_each_child(&ctrl->dev, NULL, serdev_remove_device); pm_runtime_disable(&ctrl->dev); device_del(&ctrl->dev); } From fc74d98c00d5d1b6c9f6f16fc2f679287d25eca6 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:15 +0000 Subject: [PATCH 23/89] tty: serdev: core: Provide missing description for 'owner' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serdev/core.c: In function ‘serdev_controller_remove’: drivers/tty/serdev/core.c:811: warning: Function parameter or member 'owner' not described in '__serdev_device_driver_register' Cc: Rob Herring <robh@kernel.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-3-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serdev/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index fecc28a73b3b..aead0c0c9796 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -800,6 +800,7 @@ EXPORT_SYMBOL_GPL(serdev_controller_remove); /** * serdev_driver_register() - Register client driver with serdev core * @sdrv: client driver to be associated with client-device. + * @owner: client driver owner to set. * * This API will register the client driver with the serdev framework. * It is typically called from the driver's module-init function. From 6e30f2835663b07b517c29107f576affbdb3de2b Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:16 +0000 Subject: [PATCH 24/89] tty: tty_baudrate: Add missing description for 'tty' Fixes the following W=1 kernel build warning(s): drivers/tty/tty_baudrate.c:234: warning: Function parameter or member 'tty' not described in 'tty_encode_baud_rate' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-4-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_baudrate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c index 84fec3c62d6a..6551b188b736 100644 --- a/drivers/tty/tty_baudrate.c +++ b/drivers/tty/tty_baudrate.c @@ -222,6 +222,7 @@ EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); /** * tty_encode_baud_rate - set baud rate of the tty + * @tty: terminal device * @ibaud: input baud rate * @obaud: output baud rate * From aec51036a166a0aecc26cba101bfbbdc53d64139 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:17 +0000 Subject: [PATCH 25/89] tty: tty_io: Move 'tty_sysctl_init's prototype to shared space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/tty_ldisc.c:883:6: warning: no previous prototype for ‘tty_sysctl_init’ [-Wmissing-prototypes] 883 | void tty_sysctl_init(void) | ^~~~~~~~~~~~~~~ Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Nick Holloway <alfie@dcs.warwick.ac.uk> Cc: -- <julian@uhunix.uhcc.hawaii.edu> Cc: Marko Kohtala <Marko.Kohtala@hut.fi> Cc: Bill Hawes <whawes@star.net> Cc: "C. Scott Ananian" <cananian@alumni.princeton.edu> Cc: Russell King <rmk@arm.linux.org.uk> Cc: Andrew Morton <andrewm@uow.edu.eu> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-5-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_io.c | 2 -- include/linux/tty.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 7a4c02548fb3..88b00c47b606 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -514,8 +514,6 @@ static const struct file_operations hung_up_tty_fops = { static DEFINE_SPINLOCK(redirect_lock); static struct file *redirect; -extern void tty_sysctl_init(void); - /** * tty_wakeup - request more data * @tty: terminal diff --git a/include/linux/tty.h b/include/linux/tty.h index a99e9b8e4e31..10212c6e4345 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -716,6 +716,7 @@ extern int __must_check tty_ldisc_init(struct tty_struct *tty); extern void tty_ldisc_deinit(struct tty_struct *tty); extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, char *f, int count); +extern void tty_sysctl_init(void); /* n_tty.c */ extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops); From a776f10d12cac6ac337e06457e34019f39a9ac6e Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:18 +0000 Subject: [PATCH 26/89] tty: tty_buffer: Add missing description for 'limit' Fixes the following W=1 kernel build warning(s): drivers/tty/tty_buffer.c:592: warning: Function parameter or member 'limit' not described in 'tty_buffer_set_limit' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-6-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_buffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index bd2d91546e32..6d4995a5f318 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -583,6 +583,7 @@ void tty_buffer_init(struct tty_port *port) /** * tty_buffer_set_limit - change the tty buffer memory limit * @port: tty port to change + * @limit: memory limit to set * * Change the tty buffer memory limit. * Must be called before the other tty buffer functions are used. From 1b1deb44d12cea1c127940e73efdab5a8c7c59f7 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:19 +0000 Subject: [PATCH 27/89] tty: tty_port: Demote obvious abuse of kernel-doc formatting Fixes the following W=1 kernel build warning(s): drivers/tty/tty_port.c:633: warning: Function parameter or member 'port' not described in 'tty_port_close' drivers/tty/tty_port.c:633: warning: Function parameter or member 'tty' not described in 'tty_port_close' drivers/tty/tty_port.c:633: warning: Function parameter or member 'filp' not described in 'tty_port_close' drivers/tty/tty_port.c:672: warning: Function parameter or member 'port' not described in 'tty_port_open' drivers/tty/tty_port.c:672: warning: Function parameter or member 'tty' not described in 'tty_port_open' drivers/tty/tty_port.c:672: warning: Function parameter or member 'filp' not described in 'tty_port_open' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-7-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_port.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index ea80bf872f54..346d20f4a486 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -623,7 +623,7 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) } EXPORT_SYMBOL(tty_port_close_end); -/** +/* * tty_port_close * * Caller holds tty lock @@ -659,7 +659,7 @@ int tty_port_install(struct tty_port *port, struct tty_driver *driver, } EXPORT_SYMBOL_GPL(tty_port_install); -/** +/* * tty_port_open * * Caller holds tty lock. From bc38fe241bc320fdfb4d34f5425290319c393734 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:20 +0000 Subject: [PATCH 28/89] tty: tty_jobctrl: Add missing function parameter descriptions Fixes the following W=1 kernel build warning(s): drivers/tty/tty_jobctrl.c:32: warning: Function parameter or member 'sig' not described in '__tty_check_change' drivers/tty/tty_jobctrl.c:95: warning: Function parameter or member 'tty' not described in '__proc_set_tty' drivers/tty/tty_jobctrl.c:344: warning: Function parameter or member 'file' not described in 'tiocsctty' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-8-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_jobctrl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/tty_jobctrl.c b/drivers/tty/tty_jobctrl.c index 28a23a0fef21..2054e4164c66 100644 --- a/drivers/tty/tty_jobctrl.c +++ b/drivers/tty/tty_jobctrl.c @@ -21,6 +21,7 @@ static int is_ignored(int sig) /** * tty_check_change - check for POSIX terminal changes * @tty: tty to check + * @sig: signal to send * * If we try to write to, or set the state of, a terminal and we're * not in the foreground, send a SIGTTOU. If the signal is blocked or @@ -83,6 +84,7 @@ void proc_clear_tty(struct task_struct *p) /** * proc_set_tty - set the controlling terminal + * @tty: tty structure * * Only callable by the session leader and only if it does not already have * a controlling terminal. @@ -330,6 +332,7 @@ void no_tty(void) /** * tiocsctty - set controlling tty * @tty: tty structure + * @file: file structure used to check permissions * @arg: user argument * * This ioctl is used to manage job control. It permits a session From d3e3232e7b588439d0651f1e6cf8f91c7ccdd186 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:22 +0000 Subject: [PATCH 29/89] tty: vt: consolemap: Demote weakly documented function header Fixes the following W=1 kernel build warning(s): drivers/tty/vt/consolemap.c:739: warning: Function parameter or member 'ct' not described in 'con_get_unimap' drivers/tty/vt/consolemap.c:739: warning: Function parameter or member 'uct' not described in 'con_get_unimap' drivers/tty/vt/consolemap.c:739: warning: Function parameter or member 'list' not described in 'con_get_unimap' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Jakub Jelinek <jj@ultra.linux.cz> Cc: Stanislav Voronyi <stas@cnti.uanet.kharkov.ua> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-10-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/consolemap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 5d778c0aa009..f7d015c67963 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -728,9 +728,8 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) } EXPORT_SYMBOL(con_copy_unimap); -/** +/* * con_get_unimap - get the unicode map - * @vc: the console to read from * * Read the console unicode data for this console. Called from the ioctl * handlers. From 171044a70b5750ea621659b143c075a47c1bfe40 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:23 +0000 Subject: [PATCH 30/89] tty: n_tty: Add 2 missing parameter descriptions Fixes the following W=1 kernel build warning(s): drivers/tty/n_tty.c:405: warning: Function parameter or member 'tty' not described in 'is_continuation' drivers/tty/n_tty.c:1701: warning: Function parameter or member 'flow' not described in 'n_tty_receive_buf_common' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: "Andrew J. Kroll" <ag784@freenet.buffalo.edu> Cc: processes-Sapan Bhatia <sapan@corewars.org> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-11-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/n_tty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 7e5e36315260..319d68c8a5df 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -396,6 +396,7 @@ static inline int is_utf8_continuation(unsigned char c) /** * is_continuation - multibyte check * @c: byte to check + * @tty: terminal device * * Returns true if the utf8 character 'c' is a multibyte continuation * character and the terminal is in unicode mode. @@ -1668,6 +1669,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, * @cp: input chars * @fp: flags for each char (if NULL, all chars are TTY_NORMAL) * @count: number of input chars in @cp + * @flow: enable flow control * * Called by the terminal driver when a block of characters has * been received. This function must be called from soft contexts From 5d5b53cf92a73d06181a366ae8160708a18e0e1c Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:24 +0000 Subject: [PATCH 31/89] tty: serial: jsm: jsm_cls: Remove unused variable 'discard' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serial/jsm/jsm_cls.c: In function ‘cls_copy_data_from_uart_to_queue’: drivers/tty/serial/jsm/jsm_cls.c:400:7: warning: variable ‘discard’ set but not used [-Wunused-but-set-variable] Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-12-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/jsm/jsm_cls.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c index c061a7b7bd23..b507a2cec926 100644 --- a/drivers/tty/serial/jsm/jsm_cls.c +++ b/drivers/tty/serial/jsm/jsm_cls.c @@ -397,10 +397,8 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch) * which in this case is the break signal. */ if (linestatus & error_mask) { - u8 discard; - linestatus = 0; - discard = readb(&ch->ch_cls_uart->txrx); + readb(&ch->ch_cls_uart->txrx); continue; } From 08aa5042d22bb66c90e1833f2119f272863dec87 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:25 +0000 Subject: [PATCH 32/89] tty: tty_io: Fix some kernel-doc issues Demote non-conformant headers and supply some missing descriptions. Fixes the following W=1 kernel build warning(s): drivers/tty/tty_io.c:218: warning: Function parameter or member 'file' not described in 'tty_free_file' drivers/tty/tty_io.c:566: warning: Function parameter or member 'exit_session' not described in '__tty_hangup' drivers/tty/tty_io.c:1077: warning: Function parameter or member 'tty' not described in 'tty_send_xchar' drivers/tty/tty_io.c:1077: warning: Function parameter or member 'ch' not described in 'tty_send_xchar' drivers/tty/tty_io.c:1155: warning: Function parameter or member 'file' not described in 'tty_driver_lookup_tty' drivers/tty/tty_io.c:1508: warning: Function parameter or member 'tty' not described in 'release_tty' drivers/tty/tty_io.c:1508: warning: Function parameter or member 'idx' not described in 'release_tty' drivers/tty/tty_io.c:2973: warning: Function parameter or member 'driver' not described in 'alloc_tty_struct' drivers/tty/tty_io.c:2973: warning: Function parameter or member 'idx' not described in 'alloc_tty_struct' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Nick Holloway <alfie@dcs.warwick.ac.uk> Cc: -- <julian@uhunix.uhcc.hawaii.edu> Cc: Marko Kohtala <Marko.Kohtala@hut.fi> Cc: Bill Hawes <whawes@star.net> Cc: "C. Scott Ananian" <cananian@alumni.princeton.edu> Cc: Russell King <rmk@arm.linux.org.uk> Cc: Andrew Morton <andrewm@uow.edu.eu> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-13-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_io.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 88b00c47b606..f50286fb080d 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -208,7 +208,7 @@ void tty_add_file(struct tty_struct *tty, struct file *file) spin_unlock(&tty->files_lock); } -/** +/* * tty_free_file - free file->private_data * * This shall be used only for fail path handling when tty_add_file was not @@ -543,6 +543,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup); /** * __tty_hangup - actual handler for hangup events * @tty: tty device + * @exit_session: if non-zero, signal all foreground group processes * * This can be called by a "kworker" kernel thread. That is process * synchronous but doesn't hold any locks, so we need to make sure we @@ -1065,7 +1066,7 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf, return tty_write(file, buf, count, ppos); } -/** +/* * tty_send_xchar - send priority character * * Send a high priority character to the tty even if stopped @@ -1143,6 +1144,7 @@ static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) /** * tty_driver_lookup_tty() - find an existing tty, if any * @driver: the driver for the tty + * @file: file object * @idx: the minor number * * Return the tty, if found. If not found, return NULL or ERR_PTR() if the @@ -1494,6 +1496,8 @@ EXPORT_SYMBOL(tty_kref_put); /** * release_tty - release tty structure memory + * @tty: tty device release + * @idx: index of the tty device release * * Release both @tty and a possible linked partner (think pty pair), * and decrement the refcount of the backing module. @@ -2961,7 +2965,7 @@ static struct device *tty_get_device(struct tty_struct *tty) } -/** +/* * alloc_tty_struct * * This subroutine allocates and initializes a tty structure. From 32ed248042d1809a5b4d03027432a54edd1bc80a Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:27 +0000 Subject: [PATCH 33/89] tty: serial: 8250: serial_cs: Remove unused/unchecked variable 'err' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serial/8250/serial_cs.c: In function ‘multi_config’: drivers/tty/serial/8250/serial_cs.c:562:7: warning: variable ‘err’ set but not used [-Wunused-but-set-variable] Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Colin Ian King <colin.king@canonical.com> Cc: "David A. Hinds" <dahinds@users.sourceforge.net> Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-15-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/8250/serial_cs.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index e3d10794dbba..35ff6627c61b 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -559,16 +559,13 @@ static int multi_config(struct pcmcia_device *link) */ if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC)) { - int err; - if (link->config_index == 1 || link->config_index == 3) { - err = setup_serial(link, info, base2, - link->irq); + setup_serial(link, info, base2, link->irq); base2 = link->resource[0]->start; } else { - err = setup_serial(link, info, link->resource[0]->start, - link->irq); + setup_serial(link, info, link->resource[0]->start, + link->irq); } info->c950ctrl = base2; From ffb5d9cf650f5a0596264338d8f783e11f187af7 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:28 +0000 Subject: [PATCH 34/89] tty: tty_audit: Demote non-conformant kernel-doc headers Fixes the following W=1 kernel build warning(s): drivers/tty/tty_audit.c:91: warning: Function parameter or member 'buf' not described in 'tty_audit_buf_push' drivers/tty/tty_audit.c:129: warning: Function parameter or member 'sig' not described in 'tty_audit_fork' drivers/tty/tty_audit.c:137: warning: Function parameter or member 'tty' not described in 'tty_audit_tiocsti' drivers/tty/tty_audit.c:137: warning: Function parameter or member 'ch' not described in 'tty_audit_tiocsti' drivers/tty/tty_audit.c:202: warning: Function parameter or member 'tty' not described in 'tty_audit_add_data' drivers/tty/tty_audit.c:202: warning: Function parameter or member 'data' not described in 'tty_audit_add_data' drivers/tty/tty_audit.c:202: warning: Function parameter or member 'size' not described in 'tty_audit_add_data' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Miloslav Trmac <mitr@redhat.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-16-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_audit.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index 9f906a5b8e81..32898aabcd06 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c @@ -81,7 +81,7 @@ static void tty_audit_log(const char *description, dev_t dev, } } -/** +/* * tty_audit_buf_push - Push buffered data out * * Generate an audit message from the contents of @buf, which is owned by @@ -120,7 +120,7 @@ void tty_audit_exit(void) tty_audit_buf_free(buf); } -/** +/* * tty_audit_fork - Copy TTY audit state for a new task * * Set up TTY audit state in @sig from current. @sig needs no locking. @@ -130,7 +130,7 @@ void tty_audit_fork(struct signal_struct *sig) sig->audit_tty = current->signal->audit_tty; } -/** +/* * tty_audit_tiocsti - Log TIOCSTI */ void tty_audit_tiocsti(struct tty_struct *tty, char ch) @@ -145,7 +145,7 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch) tty_audit_log("ioctl=TIOCSTI", dev, &ch, 1); } -/** +/* * tty_audit_push - Flush current's pending audit data * * Returns 0 if success, -EPERM if tty audit is disabled @@ -166,7 +166,7 @@ int tty_audit_push(void) return 0; } -/** +/* * tty_audit_buf_get - Get an audit buffer. * * Get an audit buffer, allocate it if necessary. Return %NULL @@ -193,7 +193,7 @@ static struct tty_audit_buf *tty_audit_buf_get(void) return tty_audit_buf_ref(); } -/** +/* * tty_audit_add_data - Add data for TTY auditing. * * Audit @data of @size from @tty, if necessary. From 0b0a66a5d9db2017eedaf9b04971351e53309652 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:29 +0000 Subject: [PATCH 35/89] tty: pty: Provide descriptions for the 'file' parameters Fixes the following W=1 kernel build warning(s): drivers/tty/pty.c:710: warning: Function parameter or member 'file' not described in 'ptm_unix98_lookup' drivers/tty/pty.c:726: warning: Function parameter or member 'file' not described in 'pts_unix98_lookup' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: "C. Scott Ananian" <cananian@alumni.princeton.edu> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-17-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/pty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 23368cec7ee8..a59f1e062bc6 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -699,6 +699,7 @@ static long pty_unix98_compat_ioctl(struct tty_struct *tty, /** * ptm_unix98_lookup - find a pty master * @driver: ptm driver + * @file: unused * @idx: tty index * * Look up a pty master device. Called under the tty_mutex for now. @@ -715,6 +716,7 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, /** * pts_unix98_lookup - find a pty slave * @driver: pts driver + * @file: file pointer to tty * @idx: tty index * * Look up a pty master device. Called under the tty_mutex for now. From 7789c1f1f0551b6430f524842bc8ecec85c7145e Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:30 +0000 Subject: [PATCH 36/89] tty: serial: amba-pl011: Mark 'sbsa_uart_acpi_match' as __maybe_unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When !ACPI 'sbsa_uart_acpi_match' is not referenced. Fixes the following W=1 kernel build warning(s): drivers/tty/serial/amba-pl011.c:2792:36: warning: ‘sbsa_uart_acpi_match’ defined but not used [-Wunused-const-variable=] Cc: Russell King <linux@armlinux.org.uk> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-18-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/amba-pl011.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 87dc3fc15694..c255476cce28 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2789,7 +2789,7 @@ static const struct of_device_id sbsa_uart_of_match[] = { }; MODULE_DEVICE_TABLE(of, sbsa_uart_of_match); -static const struct acpi_device_id sbsa_uart_acpi_match[] = { +static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = { { "ARMH0011", 0 }, {}, }; From b410e35dbfedcb24b74f736d69b5b6337f9eb9ba Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:31 +0000 Subject: [PATCH 37/89] tty: n_gsm: Demote obvious abuse of kernel-doc and supply other missing docss Fixes the following W=1 kernel build warning(s): drivers/tty/n_gsm.c:85: warning: Function parameter or member 'ref' not described in 'gsm_mux_net' drivers/tty/n_gsm.c:85: warning: Function parameter or member 'dlci' not described in 'gsm_mux_net' drivers/tty/n_gsm.c:664: warning: Function parameter or member 'dlci' not described in 'gsm_data_kick' drivers/tty/n_gsm.c:1015: warning: Function parameter or member 'clen' not described in 'gsm_process_modem' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-19-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/n_gsm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 25f3152089c2..c676fa89ee0b 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -74,7 +74,7 @@ module_param(debug, int, 0600); #define MAX_MTU 1500 #define GSM_NET_TX_TIMEOUT (HZ*10) -/** +/* * struct gsm_mux_net - network interface * * Created when net interface is initialized. @@ -651,6 +651,7 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, /** * gsm_data_kick - poke the queue * @gsm: GSM Mux + * @dlci: DLCI sending the data * * The tty device has called us to indicate that room has appeared in * the transmit queue. Ram more data into the pipe if we have any @@ -1005,6 +1006,7 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data, * @tty: virtual tty bound to the DLCI * @dlci: DLCI to affect * @modem: modem bits (full EA) + * @clen: command length * * Used when a modem control message or line state inline in adaption * layer 2 is processed. Sort out the local modem state and throttles From c4e3f0c0ea7982538147baa3ffe5394e164530a8 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:32 +0000 Subject: [PATCH 38/89] tty: serial: lpc32xx_hs: Remove unused variable 'tmp' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serial/lpc32xx_hs.c: In function ‘__serial_uart_flush’: drivers/tty/serial/lpc32xx_hs.c:244:6: warning: variable ‘tmp’ set but not used [-Wunused-but-set-variable] Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Vladimir Zapolskiy <vz@mleia.com> Cc: Sylvain Lemieux <slemieux.tyco@gmail.com> Cc: Kevin Wells <kevin.wells@nxp.com> Cc: Roland Stigge <stigge@antcom.de> Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Acked-by: Vladimir Zapolskiy <vz@mleia.com> Link: https://lore.kernel.org/r/20201104193549.4026187-20-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/lpc32xx_hs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index b5898c932036..1fa098d7aec4 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -241,12 +241,11 @@ static unsigned int __serial_get_clock_div(unsigned long uartclk, static void __serial_uart_flush(struct uart_port *port) { - u32 tmp; int cnt = 0; while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) && (cnt++ < FIFO_READ_LIMIT)) - tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); + readl(LPC32XX_HSUART_FIFO(port->membase)); } static void __serial_lpc32xx_rx(struct uart_port *port) From fe989920b4d12e6ecec3a89d379a35dc4a6d7af5 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:33 +0000 Subject: [PATCH 39/89] tty: serial: msm_serial: Remove set but unused variable 'status' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serial/msm_serial.c: In function ‘msm_complete_tx_dma’: drivers/tty/serial/msm_serial.c:429:18: warning: variable ‘status’ set but not used [-Wunused-but-set-variable] Cc: Andy Gross <agross@kernel.org> Cc: Bjorn Andersson <bjorn.andersson@linaro.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Robert Love <rlove@google.com> Cc: linux-arm-msm@vger.kernel.org Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Reviewed-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com> Link: https://lore.kernel.org/r/20201104193549.4026187-21-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/msm_serial.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 87f005e5d2af..ec31a809644a 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -426,7 +426,6 @@ static void msm_complete_tx_dma(void *args) struct circ_buf *xmit = &port->state->xmit; struct msm_dma *dma = &msm_port->tx_dma; struct dma_tx_state state; - enum dma_status status; unsigned long flags; unsigned int count; u32 val; @@ -437,7 +436,7 @@ static void msm_complete_tx_dma(void *args) if (!dma->count) goto done; - status = dmaengine_tx_status(dma->chan, dma->cookie, &state); + dmaengine_tx_status(dma->chan, dma->cookie, &state); dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir); From 09532ceb900a4e29f5e491043c4edec54ff2e360 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:34 +0000 Subject: [PATCH 40/89] tty: serial: ifx6x60: Fix function documentation headers Fixes the following W=1 kernel build warning(s): drivers/tty/serial/ifx6x60.c:553: warning: Function parameter or member 'tty' not described in 'ifx_port_activate' drivers/tty/serial/ifx6x60.c:728: warning: Function parameter or member 't' not described in 'ifx_spi_io' drivers/tty/serial/ifx6x60.c:728: warning: Excess function parameter 'data' description in 'ifx_spi_io' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Filip Aben <f.aben@option.com> Cc: Joseph Barrow <d.barow@option.com> Cc: Jan Dumon <j.dumon@option.com> Cc: Russ Gorby <russ.gorby@intel.com> Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-22-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/ifx6x60.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 21d519c804cb..182e0ccd60b2 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -545,6 +545,7 @@ static void ifx_spi_hangup(struct tty_struct *tty) /** * ifx_port_activate * @port: our tty port + * @tty: our tty device * * tty port activate method - called for first open. Serialized * with hangup and shutdown by the tty layer. @@ -719,7 +720,7 @@ complete_exit: /** * ifx_spio_io - I/O tasklet - * @data: our SPI device + * @t: tasklet construct used to fetch the SPI device * * Queue data for transmission if possible and then kick off the * transfer. From b482bd793c55a1a40c5ec5ab20bc7b8ee20ff6c4 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:35 +0000 Subject: [PATCH 41/89] tty: serial: xilinx_uartps: Supply description for missing member 'cts_override' Fixes the following W=1 kernel build warning(s): drivers/tty/serial/xilinx_uartps.c:205: warning: Function parameter or member 'cts_override' not described in 'cdns_uart' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Michal Simek <michal.simek@xilinx.com> Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-23-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/xilinx_uartps.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index a9b1ee27183a..a14c5d996473 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -192,6 +192,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); * @baud: Current baud rate * @clk_rate_change_nb: Notifier block for clock changes * @quirks: Flags for RXBS support. + * @cts_override: Modem control state override */ struct cdns_uart { struct uart_port *port; From 71b061e2ca9365eef1cd4dcd13ca8a707a5c4a86 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:36 +0000 Subject: [PATCH 42/89] tty: synclink_gt: Demote one kernel-doc header and repair another Fixes the following W=1 kernel build warning(s): drivers/tty/synclink_gt.c:633: warning: Function parameter or member 'tty' not described in 'ldisc_receive_buf' drivers/tty/synclink_gt.c:633: warning: Function parameter or member 'data' not described in 'ldisc_receive_buf' drivers/tty/synclink_gt.c:633: warning: Function parameter or member 'flags' not described in 'ldisc_receive_buf' drivers/tty/synclink_gt.c:633: warning: Function parameter or member 'count' not described in 'ldisc_receive_buf' drivers/tty/synclink_gt.c:1683: warning: Function parameter or member 'txqueue' not described in 'hdlcdev_tx_timeout' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: paulkf@microgate.com Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-24-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/synclink_gt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index afa4cc52e48d..c0b384e3ed4d 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -620,7 +620,7 @@ static inline int sanity_check(struct slgt_info *info, char *devname, const char return 0; } -/** +/* * line discipline callback wrappers * * The wrappers maintain line discipline references @@ -1678,6 +1678,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /** * 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) { From 0fd872d7160cc521cf4dad71f5f8cfd37d08c1bf Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:37 +0000 Subject: [PATCH 43/89] tty: serial: serial-tegra: Struct headers should start with 'struct <name>' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serial/serial-tegra.c:85: warning: cannot understand function prototype: 'struct tegra_uart_chip_data ' Cc: Laxman Dewangan <ldewangan@nvidia.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Jonathan Hunter <jonathanh@nvidia.com> Cc: Philipp Zabel <p.zabel@pengutronix.de> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: "Christian König" <christian.koenig@amd.com> Cc: linux-serial@vger.kernel.org Cc: linux-tegra@vger.kernel.org Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-25-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/serial-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index bd13014a1c53..c363ee0470f4 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -75,7 +75,7 @@ #define TEGRA_UART_FCR_IIR_FIFO_EN 0x40 /** - * tegra_uart_chip_data: SOC specific data. + * struct tegra_uart_chip_data: SOC specific data. * * @tx_fifo_full_status: Status flag available for checking tx fifo full. * @allow_txfifo_reset_fifo_mode: allow_tx fifo reset with fifo mode or not. From 180bb243de730c874b6279f702c17f5277b86693 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:38 +0000 Subject: [PATCH 44/89] tty: serial: sifive: Struct headers should start with 'struct <name>' Also supply a missing member description. Fixes the following W=1 kernel build warning(s): drivers/tty/serial/sifive.c:157: warning: cannot understand function prototype: 'struct sifive_serial_port ' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Paul Walmsley <paul.walmsley@sifive.com> Cc: linux-serial@vger.kernel.org Cc: linux-riscv@lists.infradead.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com> Link: https://lore.kernel.org/r/20201104193549.4026187-26-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/sifive.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index 13eadcb8aec4..1066eebe3b28 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -144,12 +144,13 @@ */ /** - * sifive_serial_port - driver-specific data extension to struct uart_port + * struct sifive_serial_port - driver-specific data extension to struct uart_port * @port: struct uart_port embedded in this struct * @dev: struct device * * @ier: shadowed copy of the interrupt enable register * @clkin_rate: input clock to the UART IP block. * @baud_rate: UART serial line rate (e.g., 115200 baud) + * @clk: reference to this device's clock * @clk_notifier: clock rate change notifier for upstream clock changes * * Configuration data specific to this SiFive UART. From 7285ff0b7d2ab4af12248b5226906f89e012899c Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:39 +0000 Subject: [PATCH 45/89] tty: synclinkmp: Add missing description for function param 'txqueue' Fixes the following W=1 kernel build warning(s): drivers/tty/synclinkmp.c:1808: warning: Function parameter or member 'txqueue' not described in 'hdlcdev_tx_timeout' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: paulkf@microgate.com Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-27-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/synclinkmp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index ce08c5ec331c..0ca738f61a35 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -1803,6 +1803,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /** * 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) { From 24832ca3ee85a14c42a4f23a5c8841ef5db3d029 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:41 +0000 Subject: [PATCH 46/89] tty: serial: stm32-usart: Remove set but unused 'cookie' variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serial/stm32-usart.c: In function ‘stm32_transmit_chars_dma’: drivers/tty/serial/stm32-usart.c:353:15: warning: variable ‘cookie’ set but not used [-Wunused-but-set-variable] drivers/tty/serial/stm32-usart.c: In function ‘stm32_of_dma_rx_probe’: drivers/tty/serial/stm32-usart.c:1090:15: warning: variable ‘cookie’ set but not used [-Wunused-but-set-variable] Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com> Cc: Alexandre Torgue <alexandre.torgue@st.com> Cc: Gerald Baeza <gerald.baeza@st.com> Cc: linux-serial@vger.kernel.org Cc: linux-stm32@st-md-mailman.stormreply.com Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-29-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/stm32-usart.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index ee6c7762d355..f4de32d3f2af 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -350,7 +350,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port) struct stm32_usart_offsets *ofs = &stm32port->info->ofs; struct circ_buf *xmit = &port->state->xmit; struct dma_async_tx_descriptor *desc = NULL; - dma_cookie_t cookie; unsigned int count, i; if (stm32port->tx_dma_busy) @@ -394,7 +393,7 @@ static void stm32_transmit_chars_dma(struct uart_port *port) desc->callback_param = port; /* Push current DMA TX transaction in the pending queue */ - cookie = dmaengine_submit(desc); + dmaengine_submit(desc); /* Issue pending DMA TX requests */ dma_async_issue_pending(stm32port->tx_ch); @@ -1087,7 +1086,6 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, struct device *dev = &pdev->dev; struct dma_slave_config config; struct dma_async_tx_descriptor *desc = NULL; - dma_cookie_t cookie; int ret; /* Request DMA RX channel */ @@ -1132,7 +1130,7 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, desc->callback_param = NULL; /* Push current DMA transaction in the pending queue */ - cookie = dmaengine_submit(desc); + dmaengine_submit(desc); /* Issue pending DMA requests */ dma_async_issue_pending(stm32port->rx_ch); From 8a3bdec1dff987293df05e90ec1f5030dd840803 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:42 +0000 Subject: [PATCH 47/89] tty: tty_ldisc: Supply missing description for 'tty_ldisc_get's 'tty' param Fixes the following W=1 kernel build warning(s): drivers/tty/tty_ldisc.c:160: warning: Function parameter or member 'tty' not described in 'tty_ldisc_get' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-30-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_ldisc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index fe37ec331289..e813808b27a7 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -137,6 +137,7 @@ static void put_ldops(struct tty_ldisc_ops *ldops) /** * tty_ldisc_get - take a reference to an ldisc + * @tty: tty device * @disc: ldisc number * * Takes a reference to a line discipline. Deals with refcounts and From 216daa1209e6be8cf98ebf6da2dd55e48d474ebe Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:43 +0000 Subject: [PATCH 48/89] tty: serial: serial-tegra: Provide some missing struct member descriptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serial/serial-tegra.c:94: warning: Function parameter or member 'fifo_mode_enable_status' not described in 'tegra_uart_chip_data' drivers/tty/serial/serial-tegra.c:94: warning: Function parameter or member 'uart_max_port' not described in 'tegra_uart_chip_data' drivers/tty/serial/serial-tegra.c:94: warning: Function parameter or member 'max_dma_burst_bytes' not described in 'tegra_uart_chip_data' drivers/tty/serial/serial-tegra.c:94: warning: Function parameter or member 'error_tolerance_low_range' not described in 'tegra_uart_chip_data' drivers/tty/serial/serial-tegra.c:94: warning: Function parameter or member 'error_tolerance_high_range' not described in 'tegra_uart_chip_data' Cc: Laxman Dewangan <ldewangan@nvidia.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Jonathan Hunter <jonathanh@nvidia.com> Cc: Philipp Zabel <p.zabel@pengutronix.de> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: "Christian König" <christian.koenig@amd.com> Cc: linux-serial@vger.kernel.org Cc: linux-tegra@vger.kernel.org Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-31-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/serial-tegra.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index c363ee0470f4..bbae072a125d 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -81,6 +81,11 @@ * @allow_txfifo_reset_fifo_mode: allow_tx fifo reset with fifo mode or not. * Tegra30 does not allow this. * @support_clk_src_div: Clock source support the clock divider. + * @fifo_mode_enable_status: Is FIFO mode enabled? + * @uart_max_port: Maximum number of UART ports + * @max_dma_burst_bytes: Maximum size of DMA bursts + * @error_tolerance_low_range: Lowest number in the error tolerance range + * @error_tolerance_high_range: Highest number in the error tolerance range */ struct tegra_uart_chip_data { bool tx_fifo_full_status; From 109af2a82a36e0cedb54988406e6b40de67272c7 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:45 +0000 Subject: [PATCH 49/89] tty: hvc: hvc_vio: Staticify function invoked only by reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/hvc/hvc_vio.c:181:6: warning: no previous prototype for ‘hvterm_hvsi_hangup’ [-Wmissing-prototypes] 181 | void hvterm_hvsi_hangup(struct hvc_struct *hp, int data) | ^~~~~~~~~~~~~~~~~~ Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-33-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/hvc/hvc_vio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index 7af54d6ed5b8..798f27f40cc2 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -178,7 +178,7 @@ static void hvterm_hvsi_close(struct hvc_struct *hp, int data) notifier_del_irq(hp, data); } -void hvterm_hvsi_hangup(struct hvc_struct *hp, int data) +static void hvterm_hvsi_hangup(struct hvc_struct *hp, int data) { struct hvterm_priv *pv = hvterm_privs[hp->vtermno]; From 27122bf57a62f5f816abb48b3a52226ee273a9da Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:46 +0000 Subject: [PATCH 50/89] tty: hvc: hvc_opal: Staticify function invoked by reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/hvc/hvc_opal.c:106:6: warning: no previous prototype for ‘hvc_opal_hvsi_hangup’ [-Wmissing-prototypes] Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-34-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/hvc/hvc_opal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index c66412566efc..056ae21a5121 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -103,7 +103,7 @@ static void hvc_opal_hvsi_close(struct hvc_struct *hp, int data) notifier_del_irq(hp, data); } -void hvc_opal_hvsi_hangup(struct hvc_struct *hp, int data) +static void hvc_opal_hvsi_hangup(struct hvc_struct *hp, int data) { struct hvc_opal_priv *pv = hvc_opal_privs[hp->vtermno]; From a296b3de30836e79c6d59d5349265d592a0e7993 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Wed, 4 Nov 2020 19:35:49 +0000 Subject: [PATCH 51/89] tty: synclink: Provide missing description for 'hdlcdev_tx_timeout's 'txqueue' param Fixes the following W=1 kernel build warning(s): drivers/tty/synclink.c:7708: warning: Function parameter or member 'txqueue' not described in 'hdlcdev_tx_timeout' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: paulkf@microgate.com Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201104193549.4026187-37-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/synclink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index c8324d58ef56..3b370d0a19cb 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -7703,6 +7703,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) * 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) { From 88b8138b240b43d5215bf7cb422692cd8db51f6f Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Date: Fri, 6 Nov 2020 14:03:31 +0100 Subject: [PATCH 52/89] tty: serial: remove pnx8xxx uart driver Commit 625326ea9c84 ("MIPS: Remove PNX833x alias NXP_STB22x") removed support for PNX833x, so it's time to remove serial driver, too. Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Link: https://lore.kernel.org/r/20201106130332.103476-1-tsbogend@alpha.franken.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/Kconfig | 16 - drivers/tty/serial/Makefile | 1 - drivers/tty/serial/pnx8xxx_uart.c | 858 ------------------------------ include/linux/serial_pnx8xxx.h | 67 --- include/uapi/linux/serial_core.h | 2 - 5 files changed, 944 deletions(-) delete mode 100644 drivers/tty/serial/pnx8xxx_uart.c delete mode 100644 include/linux/serial_pnx8xxx.h diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 1044fc387691..b146c93146ee 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -703,22 +703,6 @@ config SERIAL_SH_SCI_DMA depends on SERIAL_SH_SCI && DMA_ENGINE default ARCH_RENESAS -config SERIAL_PNX8XXX - bool "Enable PNX8XXX SoCs' UART Support" - depends on SOC_PNX833X - select SERIAL_CORE - help - If you have a MIPS-based Philips SoC such as PNX8330 and you want - to use serial ports, say Y. Otherwise, say N. - -config SERIAL_PNX8XXX_CONSOLE - bool "Enable PNX8XX0 serial console" - depends on SERIAL_PNX8XXX - select SERIAL_CORE_CONSOLE - help - If you have a MIPS-based Philips SoC such as PNX8330 and you want - to use serial console, say Y. Otherwise, say N. - config SERIAL_HS_LPC32XX tristate "LPC32XX high speed serial port support" depends on ARCH_LPC32XX || COMPILE_TEST diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index caf167f0c10a..af44b231123c 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -27,7 +27,6 @@ obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_PXA_NON8250) += pxa.o -obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o obj-$(CONFIG_SERIAL_SAMSUNG) += samsung_tty.o diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c deleted file mode 100644 index 972d94e8d32b..000000000000 --- a/drivers/tty/serial/pnx8xxx_uart.c +++ /dev/null @@ -1,858 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * UART driver for PNX8XXX SoCs - * - * Author: Per Hallsmark per.hallsmark@mvista.com - * Ported to 2.6 kernel by EmbeddedAlley - * Reworked by Vitaly Wool <vitalywool@gmail.com> - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * Copyright (C) 2000 Deep Blue Solutions Ltd. - */ - -#include <linux/module.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/serial.h> -#include <linux/serial_pnx8xxx.h> - -#include <asm/io.h> -#include <asm/irq.h> - -/* We'll be using StrongARM sa1100 serial port major/minor */ -#define SERIAL_PNX8XXX_MAJOR 204 -#define MINOR_START 5 - -#define NR_PORTS 2 - -#define PNX8XXX_ISR_PASS_LIMIT 256 - -/* - * Convert from ignore_status_mask or read_status_mask to FIFO - * and interrupt status bits - */ -#define SM_TO_FIFO(x) ((x) >> 10) -#define SM_TO_ISTAT(x) ((x) & 0x000001ff) -#define FIFO_TO_SM(x) ((x) << 10) -#define ISTAT_TO_SM(x) ((x) & 0x000001ff) - -/* - * This is the size of our serial port register set. - */ -#define UART_PORT_SIZE 0x1000 - -/* - * This determines how often we check the modem status signals - * for any change. They generally aren't connected to an IRQ - * so we have to poll them. We also check immediately before - * filling the TX fifo incase CTS has been dropped. - */ -#define MCTRL_TIMEOUT (250*HZ/1000) - -extern struct pnx8xxx_port pnx8xxx_ports[]; - -static inline int serial_in(struct pnx8xxx_port *sport, int offset) -{ - return (__raw_readl(sport->port.membase + offset)); -} - -static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value) -{ - __raw_writel(value, sport->port.membase + offset); -} - -/* - * Handle any change of modem status signal since we were last called. - */ -static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport) -{ - unsigned int status, changed; - - status = sport->port.ops->get_mctrl(&sport->port); - changed = status ^ sport->old_status; - - if (changed == 0) - return; - - sport->old_status = status; - - if (changed & TIOCM_RI) - sport->port.icount.rng++; - if (changed & TIOCM_DSR) - sport->port.icount.dsr++; - if (changed & TIOCM_CAR) - uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); - if (changed & TIOCM_CTS) - uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); -} - -/* - * This is our per-port timeout handler, for checking the - * modem status signals. - */ -static void pnx8xxx_timeout(struct timer_list *t) -{ - struct pnx8xxx_port *sport = from_timer(sport, t, timer); - unsigned long flags; - - if (sport->port.state) { - spin_lock_irqsave(&sport->port.lock, flags); - pnx8xxx_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); - - mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); - } -} - -/* - * interrupts disabled on entry - */ -static void pnx8xxx_stop_tx(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - u32 ien; - - /* Disable TX intr */ - ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX); - - /* Clear all pending TX intr */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); -} - -/* - * interrupts may not be disabled on entry - */ -static void pnx8xxx_start_tx(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - u32 ien; - - /* Clear all pending TX intr */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX); - - /* Enable TX intr */ - ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX); -} - -/* - * Interrupts enabled - */ -static void pnx8xxx_stop_rx(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - u32 ien; - - /* Disable RX intr */ - ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX); - - /* Clear all pending RX intr */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX); -} - -/* - * Set the modem control timer to fire immediately. - */ -static void pnx8xxx_enable_ms(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - mod_timer(&sport->timer, jiffies); -} - -static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport) -{ - unsigned int status, ch, flg; - - status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | - ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); - while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) { - ch = serial_in(sport, PNX8XXX_FIFO) & 0xff; - - sport->port.icount.rx++; - - flg = TTY_NORMAL; - - /* - * note that the error handling code is - * out of the main execution path - */ - if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE | - PNX8XXX_UART_FIFO_RXPAR | - PNX8XXX_UART_FIFO_RXBRK) | - ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) { - if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) { - status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)); - sport->port.icount.brk++; - if (uart_handle_break(&sport->port)) - goto ignore_char; - } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) - sport->port.icount.parity++; - else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) - sport->port.icount.frame++; - if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN)) - sport->port.icount.overrun++; - - status &= sport->port.read_status_mask; - - if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR)) - flg = TTY_PARITY; - else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE)) - flg = TTY_FRAME; - - sport->port.sysrq = 0; - } - - if (uart_handle_sysrq_char(&sport->port, ch)) - goto ignore_char; - - uart_insert_char(&sport->port, status, - ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg); - - ignore_char: - serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) | - PNX8XXX_UART_LCR_RX_NEXT); - status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) | - ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT)); - } - - spin_unlock(&sport->port.lock); - tty_flip_buffer_push(&sport->port.state->port); - spin_lock(&sport->port.lock); -} - -static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - - if (sport->port.x_char) { - serial_out(sport, PNX8XXX_FIFO, sport->port.x_char); - sport->port.icount.tx++; - sport->port.x_char = 0; - return; - } - - /* - * Check the modem control lines before - * transmitting anything. - */ - pnx8xxx_mctrl_check(sport); - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - pnx8xxx_stop_tx(&sport->port); - return; - } - - /* - * TX while bytes available - */ - while (((serial_in(sport, PNX8XXX_FIFO) & - PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) { - serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - pnx8xxx_stop_tx(&sport->port); -} - -static irqreturn_t pnx8xxx_int(int irq, void *dev_id) -{ - struct pnx8xxx_port *sport = dev_id; - unsigned int status; - - spin_lock(&sport->port.lock); - /* Get the interrupts */ - status = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN); - - /* Byte or break signal received */ - if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK)) - pnx8xxx_rx_chars(sport); - - /* TX holding register empty - transmit a byte */ - if (status & PNX8XXX_UART_INT_TX) - pnx8xxx_tx_chars(sport); - - /* Clear the ISTAT register */ - serial_out(sport, PNX8XXX_ICLR, status); - - spin_unlock(&sport->port.lock); - return IRQ_HANDLED; -} - -/* - * Return TIOCSER_TEMT when transmitter is not busy. - */ -static unsigned int pnx8xxx_tx_empty(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT; -} - -static unsigned int pnx8xxx_get_mctrl(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - unsigned int mctrl = TIOCM_DSR; - unsigned int msr; - - /* REVISIT */ - - msr = serial_in(sport, PNX8XXX_MCR); - - mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0; - mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0; - - return mctrl; -} - -static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -#if 0 /* FIXME */ - struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port; - unsigned int msr; -#endif -} - -/* - * Interrupts always disabled. - */ -static void pnx8xxx_break_ctl(struct uart_port *port, int break_state) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - unsigned long flags; - unsigned int lcr; - - spin_lock_irqsave(&sport->port.lock, flags); - lcr = serial_in(sport, PNX8XXX_LCR); - if (break_state == -1) - lcr |= PNX8XXX_UART_LCR_TXBREAK; - else - lcr &= ~PNX8XXX_UART_LCR_TXBREAK; - serial_out(sport, PNX8XXX_LCR, lcr); - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static int pnx8xxx_startup(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - int retval; - - /* - * Allocate the IRQ - */ - retval = request_irq(sport->port.irq, pnx8xxx_int, 0, - "pnx8xxx-uart", sport); - if (retval) - return retval; - - /* - * Finally, clear and enable interrupts - */ - - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | - PNX8XXX_UART_INT_ALLTX); - - serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) | - PNX8XXX_UART_INT_ALLRX | - PNX8XXX_UART_INT_ALLTX); - - /* - * Enable modem status interrupts - */ - spin_lock_irq(&sport->port.lock); - pnx8xxx_enable_ms(&sport->port); - spin_unlock_irq(&sport->port.lock); - - return 0; -} - -static void pnx8xxx_shutdown(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - int lcr; - - /* - * Stop our timer. - */ - del_timer_sync(&sport->timer); - - /* - * Disable all interrupts - */ - serial_out(sport, PNX8XXX_IEN, 0); - - /* - * Reset the Tx and Rx FIFOS, disable the break condition - */ - lcr = serial_in(sport, PNX8XXX_LCR); - lcr &= ~PNX8XXX_UART_LCR_TXBREAK; - lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST; - serial_out(sport, PNX8XXX_LCR, lcr); - - /* - * Clear all interrupts - */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX | - PNX8XXX_UART_INT_ALLTX); - - /* - * Free the interrupt - */ - free_irq(sport->port.irq, sport); -} - -static void -pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - unsigned long flags; - unsigned int lcr_fcr, old_ien, baud, quot; - unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - - /* - * We only support CS7 and CS8. - */ - while ((termios->c_cflag & CSIZE) != CS7 && - (termios->c_cflag & CSIZE) != CS8) { - termios->c_cflag &= ~CSIZE; - termios->c_cflag |= old_csize; - old_csize = CS8; - } - - if ((termios->c_cflag & CSIZE) == CS8) - lcr_fcr = PNX8XXX_UART_LCR_8BIT; - else - lcr_fcr = 0; - - if (termios->c_cflag & CSTOPB) - lcr_fcr |= PNX8XXX_UART_LCR_2STOPB; - if (termios->c_cflag & PARENB) { - lcr_fcr |= PNX8XXX_UART_LCR_PAREN; - if (!(termios->c_cflag & PARODD)) - lcr_fcr |= PNX8XXX_UART_LCR_PAREVN; - } - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); - - spin_lock_irqsave(&sport->port.lock, flags); - - sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) | - ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) | - ISTAT_TO_SM(PNX8XXX_UART_INT_RX); - if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - sport->port.read_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); - - /* - * Characters to ignore - */ - sport->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | - FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); - if (termios->c_iflag & IGNBRK) { - sport->port.ignore_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN); - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - sport->port.ignore_status_mask |= - ISTAT_TO_SM(PNX8XXX_UART_INT_RX); - - del_timer_sync(&sport->timer); - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - /* - * disable interrupts and drain transmitter - */ - old_ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | - PNX8XXX_UART_INT_ALLRX)); - - while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA) - barrier(); - - /* then, disable everything */ - serial_out(sport, PNX8XXX_IEN, 0); - - /* Reset the Rx and Tx FIFOs too */ - lcr_fcr |= PNX8XXX_UART_LCR_TX_RST; - lcr_fcr |= PNX8XXX_UART_LCR_RX_RST; - - /* set the parity, stop bits and data size */ - serial_out(sport, PNX8XXX_LCR, lcr_fcr); - - /* set the baud rate */ - quot -= 1; - serial_out(sport, PNX8XXX_BAUD, quot); - - serial_out(sport, PNX8XXX_ICLR, -1); - - serial_out(sport, PNX8XXX_IEN, old_ien); - - if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) - pnx8xxx_enable_ms(&sport->port); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static const char *pnx8xxx_type(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL; -} - -/* - * Release the memory region(s) being used by 'port'. - */ -static void pnx8xxx_release_port(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - release_mem_region(sport->port.mapbase, UART_PORT_SIZE); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int pnx8xxx_request_port(struct uart_port *port) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, - "pnx8xxx-uart") != NULL ? 0 : -EBUSY; -} - -/* - * Configure/autoconfigure the port. - */ -static void pnx8xxx_config_port(struct uart_port *port, int flags) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - - if (flags & UART_CONFIG_TYPE && - pnx8xxx_request_port(&sport->port) == 0) - sport->port.type = PORT_PNX8XXX; -} - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - * The only change we allow are to the flags and type, and - * even then only between PORT_PNX8XXX and PORT_UNKNOWN - */ -static int -pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - int ret = 0; - - if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX) - ret = -EINVAL; - if (sport->port.irq != ser->irq) - ret = -EINVAL; - if (ser->io_type != SERIAL_IO_MEM) - ret = -EINVAL; - if (sport->port.uartclk / 16 != ser->baud_base) - ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) - ret = -EINVAL; - if (sport->port.iobase != ser->port) - ret = -EINVAL; - if (ser->hub6 != 0) - ret = -EINVAL; - return ret; -} - -static const struct uart_ops pnx8xxx_pops = { - .tx_empty = pnx8xxx_tx_empty, - .set_mctrl = pnx8xxx_set_mctrl, - .get_mctrl = pnx8xxx_get_mctrl, - .stop_tx = pnx8xxx_stop_tx, - .start_tx = pnx8xxx_start_tx, - .stop_rx = pnx8xxx_stop_rx, - .enable_ms = pnx8xxx_enable_ms, - .break_ctl = pnx8xxx_break_ctl, - .startup = pnx8xxx_startup, - .shutdown = pnx8xxx_shutdown, - .set_termios = pnx8xxx_set_termios, - .type = pnx8xxx_type, - .release_port = pnx8xxx_release_port, - .request_port = pnx8xxx_request_port, - .config_port = pnx8xxx_config_port, - .verify_port = pnx8xxx_verify_port, -}; - - -/* - * Setup the PNX8XXX serial ports. - * - * Note also that we support "console=ttySx" where "x" is either 0 or 1. - */ -static void __init pnx8xxx_init_ports(void) -{ - static int first = 1; - int i; - - if (!first) - return; - first = 0; - - for (i = 0; i < NR_PORTS; i++) { - timer_setup(&pnx8xxx_ports[i].timer, pnx8xxx_timeout, 0); - pnx8xxx_ports[i].port.ops = &pnx8xxx_pops; - } -} - -#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE - -static void pnx8xxx_console_putchar(struct uart_port *port, int ch) -{ - struct pnx8xxx_port *sport = - container_of(port, struct pnx8xxx_port, port); - int status; - - do { - /* Wait for UART_TX register to empty */ - status = serial_in(sport, PNX8XXX_FIFO); - } while (status & PNX8XXX_UART_FIFO_TXFIFO); - serial_out(sport, PNX8XXX_FIFO, ch); -} - -/* - * Interrupts are disabled on entering - */static void -pnx8xxx_console_write(struct console *co, const char *s, unsigned int count) -{ - struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index]; - unsigned int old_ien, status; - - /* - * First, save IEN and then disable interrupts - */ - old_ien = serial_in(sport, PNX8XXX_IEN); - serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX | - PNX8XXX_UART_INT_ALLRX)); - - uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore IEN - */ - do { - /* Wait for UART_TX register to empty */ - status = serial_in(sport, PNX8XXX_FIFO); - } while (status & PNX8XXX_UART_FIFO_TXFIFO); - - /* Clear TX and EMPTY interrupt */ - serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX | - PNX8XXX_UART_INT_EMPTY); - - serial_out(sport, PNX8XXX_IEN, old_ien); -} - -static int __init -pnx8xxx_console_setup(struct console *co, char *options) -{ - struct pnx8xxx_port *sport; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - /* - * Check whether an invalid uart number has been specified, and - * if so, search for the first available port that does have - * console support. - */ - if (co->index == -1 || co->index >= NR_PORTS) - co->index = 0; - sport = &pnx8xxx_ports[co->index]; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(&sport->port, co, baud, parity, bits, flow); -} - -static struct uart_driver pnx8xxx_reg; -static struct console pnx8xxx_console = { - .name = "ttyS", - .write = pnx8xxx_console_write, - .device = uart_console_device, - .setup = pnx8xxx_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &pnx8xxx_reg, -}; - -static int __init pnx8xxx_rs_console_init(void) -{ - pnx8xxx_init_ports(); - register_console(&pnx8xxx_console); - return 0; -} -console_initcall(pnx8xxx_rs_console_init); - -#define PNX8XXX_CONSOLE &pnx8xxx_console -#else -#define PNX8XXX_CONSOLE NULL -#endif - -static struct uart_driver pnx8xxx_reg = { - .owner = THIS_MODULE, - .driver_name = "ttyS", - .dev_name = "ttyS", - .major = SERIAL_PNX8XXX_MAJOR, - .minor = MINOR_START, - .nr = NR_PORTS, - .cons = PNX8XXX_CONSOLE, -}; - -static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct pnx8xxx_port *sport = platform_get_drvdata(pdev); - - return uart_suspend_port(&pnx8xxx_reg, &sport->port); -} - -static int pnx8xxx_serial_resume(struct platform_device *pdev) -{ - struct pnx8xxx_port *sport = platform_get_drvdata(pdev); - - return uart_resume_port(&pnx8xxx_reg, &sport->port); -} - -static int pnx8xxx_serial_probe(struct platform_device *pdev) -{ - struct resource *res = pdev->resource; - int i; - - for (i = 0; i < pdev->num_resources; i++, res++) { - if (!(res->flags & IORESOURCE_MEM)) - continue; - - for (i = 0; i < NR_PORTS; i++) { - if (pnx8xxx_ports[i].port.mapbase != res->start) - continue; - - pnx8xxx_ports[i].port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_PNX8XXX_CONSOLE); - pnx8xxx_ports[i].port.dev = &pdev->dev; - uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port); - platform_set_drvdata(pdev, &pnx8xxx_ports[i]); - break; - } - } - - return 0; -} - -static int pnx8xxx_serial_remove(struct platform_device *pdev) -{ - struct pnx8xxx_port *sport = platform_get_drvdata(pdev); - - if (sport) - uart_remove_one_port(&pnx8xxx_reg, &sport->port); - - return 0; -} - -static struct platform_driver pnx8xxx_serial_driver = { - .driver = { - .name = "pnx8xxx-uart", - }, - .probe = pnx8xxx_serial_probe, - .remove = pnx8xxx_serial_remove, - .suspend = pnx8xxx_serial_suspend, - .resume = pnx8xxx_serial_resume, -}; - -static int __init pnx8xxx_serial_init(void) -{ - int ret; - - printk(KERN_INFO "Serial: PNX8XXX driver\n"); - - pnx8xxx_init_ports(); - - ret = uart_register_driver(&pnx8xxx_reg); - if (ret == 0) { - ret = platform_driver_register(&pnx8xxx_serial_driver); - if (ret) - uart_unregister_driver(&pnx8xxx_reg); - } - return ret; -} - -static void __exit pnx8xxx_serial_exit(void) -{ - platform_driver_unregister(&pnx8xxx_serial_driver); - uart_unregister_driver(&pnx8xxx_reg); -} - -module_init(pnx8xxx_serial_init); -module_exit(pnx8xxx_serial_exit); - -MODULE_AUTHOR("Embedded Alley Solutions, Inc."); -MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR); -MODULE_ALIAS("platform:pnx8xxx-uart"); diff --git a/include/linux/serial_pnx8xxx.h b/include/linux/serial_pnx8xxx.h deleted file mode 100644 index 619d748dcd44..000000000000 --- a/include/linux/serial_pnx8xxx.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Embedded Alley Solutions, source@embeddedalley.com. - */ - -#ifndef _LINUX_SERIAL_PNX8XXX_H -#define _LINUX_SERIAL_PNX8XXX_H - -#include <linux/serial_core.h> - -#define PNX8XXX_NR_PORTS 2 - -struct pnx8xxx_port { - struct uart_port port; - struct timer_list timer; - unsigned int old_status; -}; - -/* register offsets */ -#define PNX8XXX_LCR 0 -#define PNX8XXX_MCR 0x004 -#define PNX8XXX_BAUD 0x008 -#define PNX8XXX_CFG 0x00c -#define PNX8XXX_FIFO 0x028 -#define PNX8XXX_ISTAT 0xfe0 -#define PNX8XXX_IEN 0xfe4 -#define PNX8XXX_ICLR 0xfe8 -#define PNX8XXX_ISET 0xfec -#define PNX8XXX_PD 0xff4 -#define PNX8XXX_MID 0xffc - -#define PNX8XXX_UART_LCR_TXBREAK (1<<30) -#define PNX8XXX_UART_LCR_PAREVN 0x10000000 -#define PNX8XXX_UART_LCR_PAREN 0x08000000 -#define PNX8XXX_UART_LCR_2STOPB 0x04000000 -#define PNX8XXX_UART_LCR_8BIT 0x01000000 -#define PNX8XXX_UART_LCR_TX_RST 0x00040000 -#define PNX8XXX_UART_LCR_RX_RST 0x00020000 -#define PNX8XXX_UART_LCR_RX_NEXT 0x00010000 - -#define PNX8XXX_UART_MCR_SCR 0xFF000000 -#define PNX8XXX_UART_MCR_DCD 0x00800000 -#define PNX8XXX_UART_MCR_CTS 0x00100000 -#define PNX8XXX_UART_MCR_LOOP 0x00000010 -#define PNX8XXX_UART_MCR_RTS 0x00000002 -#define PNX8XXX_UART_MCR_DTR 0x00000001 - -#define PNX8XXX_UART_INT_TX 0x00000080 -#define PNX8XXX_UART_INT_EMPTY 0x00000040 -#define PNX8XXX_UART_INT_RCVTO 0x00000020 -#define PNX8XXX_UART_INT_RX 0x00000010 -#define PNX8XXX_UART_INT_RXOVRN 0x00000008 -#define PNX8XXX_UART_INT_FRERR 0x00000004 -#define PNX8XXX_UART_INT_BREAK 0x00000002 -#define PNX8XXX_UART_INT_PARITY 0x00000001 -#define PNX8XXX_UART_INT_ALLRX 0x0000003F -#define PNX8XXX_UART_INT_ALLTX 0x000000C0 - -#define PNX8XXX_UART_FIFO_TXFIFO 0x001F0000 -#define PNX8XXX_UART_FIFO_TXFIFO_STA (0x1f<<16) -#define PNX8XXX_UART_FIFO_RXBRK 0x00008000 -#define PNX8XXX_UART_FIFO_RXFE 0x00004000 -#define PNX8XXX_UART_FIFO_RXPAR 0x00002000 -#define PNX8XXX_UART_FIFO_RXFIFO 0x00001F00 -#define PNX8XXX_UART_FIFO_RBRTHR 0x000000FF - -#endif diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 851b982f8c4b..62c22045fe65 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -134,8 +134,6 @@ /*Digi jsm */ #define PORT_JSM 69 -#define PORT_PNX8XXX 70 - /* SUN4V Hypervisor Console */ #define PORT_SUNHV 72 From a1f714b44e342dc143dc4c6b909bf516f18fe412 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Thu, 5 Nov 2020 12:33:56 +0000 Subject: [PATCH 53/89] tty: Remove redundant synclink driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A note from the vendor: "The hardware used with synclink.c and synclinkmp.c has not been manufactured for 15 years and was low volume. The chances of either driver still being in use is very low. Not even Microgate (me) has the ability to test either anymore (no hardware). I don’t know the policy about driver removal, but I think both could be removed without upsetting anyone." Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201105123357.708813-2-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- arch/powerpc/configs/ppc6xx_defconfig | 1 - drivers/tty/Kconfig | 13 - drivers/tty/Makefile | 1 - drivers/tty/synclink.c | 7899 ------------------------- 4 files changed, 7914 deletions(-) delete mode 100644 drivers/tty/synclink.c diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 66e9a0fd64ff..c2052093f70c 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -598,7 +598,6 @@ CONFIG_GAMEPORT_FM801=m CONFIG_SERIAL_NONSTANDARD=y CONFIG_ROCKETPORT=m CONFIG_CYCLADES=m -CONFIG_SYNCLINK=m CONFIG_SYNCLINKMP=m CONFIG_SYNCLINK_GT=m CONFIG_NOZOMI=m diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 93fd984eb2f5..61bf4ba37c06 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -259,19 +259,6 @@ 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 - tristate "Microgate SyncLink card support" - depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API - help - Provides support for the SyncLink ISA and PCI multiprotocol serial - adapters. These adapters support asynchronous and HDLC bit - synchronous communication up to 10Mbps (PCI adapter). - - This driver can only be built as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called synclink. If you want to do that, say M - here. - config SYNCLINKMP tristate "SyncLink Multiport support" depends on SERIAL_NONSTANDARD && PCI diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 020b1cd9294f..f3dd47cad439 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -29,7 +29,6 @@ obj-$(CONFIG_NULL_TTY) += ttynull.o obj-$(CONFIG_ROCKETPORT) += rocket.o obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o -obj-$(CONFIG_SYNCLINK) += synclink.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/synclink.c b/drivers/tty/synclink.c deleted file mode 100644 index 3b370d0a19cb..000000000000 --- a/drivers/tty/synclink.c +++ /dev/null @@ -1,7899 +0,0 @@ -// SPDX-License-Identifier: GPL-1.0+ -/* - * $Id: synclink.c,v 4.38 2005/11/07 16:30:34 paulkf Exp $ - * - * Device driver for Microgate SyncLink ISA and PCI - * high speed multiprotocol serial adapters. - * - * written by Paul Fulghum for Microgate Corporation - * paulkf@microgate.com - * - * Microgate and SyncLink are trademarks of Microgate Corporation - * - * Derived from serial.c written by Theodore Ts'o and Linus Torvalds - * - * Original release 01/11/99 - * - * This driver is primarily intended for use in synchronous - * HDLC mode. Asynchronous mode is also provided. - * - * When operating in synchronous mode, each call to mgsl_write() - * contains exactly one complete HDLC frame. Calling mgsl_put_char - * will start assembling an HDLC frame that will not be sent until - * mgsl_flush_chars or mgsl_write is called. - * - * Synchronous receive data is reported as complete frames. To accomplish - * this, the TTY flip buffer is bypassed (too small to hold largest - * frame and may fragment frames) and the line discipline - * receive entry point is called directly. - * - * This driver has been tested with a slightly modified ppp.c driver - * for synchronous PPP. - * - * 2000/02/16 - * Added interface for syncppp.c driver (an alternate synchronous PPP - * implementation that also supports Cisco HDLC). Each device instance - * registers as a tty device AND a network device (if dosyncppp option - * is set for the device). The functionality is determined by which - * device interface is opened. - * - * 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. - */ - -#if defined(__i386__) -# define BREAKPOINT() asm(" int $3"); -#else -# define BREAKPOINT() { } -#endif - -#define MAX_ISA_DEVICES 10 -#define MAX_PCI_DEVICES 10 -#define MAX_TOTAL_DEVICES 20 - -#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/delay.h> -#include <linux/netdevice.h> -#include <linux/vmalloc.h> -#include <linux/init.h> -#include <linux/ioctl.h> -#include <linux/synclink.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/dma.h> -#include <linux/bitops.h> -#include <asm/types.h> -#include <linux/termios.h> -#include <linux/workqueue.h> -#include <linux/hdlc.h> -#include <linux/dma-mapping.h> - -#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_MODULE)) -#define SYNCLINK_GENERIC_HDLC 1 -#else -#define SYNCLINK_GENERIC_HDLC 0 -#endif - -#define GET_USER(error,value,addr) error = get_user(value,addr) -#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 -#define PUT_USER(error,value,addr) error = put_user(value,addr) -#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 - -#include <linux/uaccess.h> - -#define RCLRVALUE 0xffff - -static MGSL_PARAMS default_params = { - MGSL_MODE_HDLC, /* unsigned long mode */ - 0, /* unsigned char loopback; */ - HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ - HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ - 0, /* unsigned long clock_speed; */ - 0xff, /* unsigned char addr_filter; */ - HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ - HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ - HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ - 9600, /* unsigned long data_rate; */ - 8, /* unsigned char data_bits; */ - 1, /* unsigned char stop_bits; */ - ASYNC_PARITY_NONE /* unsigned char parity; */ -}; - -#define SHARED_MEM_ADDRESS_SIZE 0x40000 -#define BUFFERLISTSIZE 4096 -#define DMABUFFERSIZE 4096 -#define MAXRXFRAMES 7 - -typedef struct _DMABUFFERENTRY -{ - u32 phys_addr; /* 32-bit flat physical address of data buffer */ - volatile u16 count; /* buffer size/data count */ - volatile u16 status; /* Control/status field */ - volatile u16 rcc; /* character count field */ - u16 reserved; /* padding required by 16C32 */ - u32 link; /* 32-bit flat link to next buffer entry */ - char *virt_addr; /* virtual address of data buffer */ - u32 phys_entry; /* physical address of this buffer entry */ - dma_addr_t dma_addr; -} DMABUFFERENTRY, *DMAPBUFFERENTRY; - -/* The queue of BH actions to be performed */ - -#define BH_RECEIVE 1 -#define BH_TRANSMIT 2 -#define BH_STATUS 4 - -#define IO_PIN_SHUTDOWN_LIMIT 100 - -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; -}; - -/* transmit holding buffer definitions*/ -#define MAX_TX_HOLDING_BUFFERS 5 -struct tx_holding_buffer { - int buffer_size; - unsigned char * buffer; -}; - - -/* - * Device instance data structure - */ - -struct mgsl_struct { - int magic; - struct tty_port port; - int line; - int hw_version; - - struct mgsl_icount icount; - - int timeout; - int x_char; /* xon/xoff character */ - u16 read_status_mask; - u16 ignore_status_mask; - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - - wait_queue_head_t status_event_wait_q; - wait_queue_head_t event_wait_q; - struct timer_list tx_timer; /* HDLC transmit timeout timer */ - struct mgsl_struct *next_device; /* device list link */ - - spinlock_t irq_spinlock; /* spinlock for synchronizing with ISR */ - struct work_struct task; /* task structure for scheduling bh */ - - u32 EventMask; /* event trigger mask */ - u32 RecordedEvents; /* pending events */ - - u32 max_frame_size; /* as set by device config */ - - u32 pending_bh; - - bool bh_running; /* Protection from multiple */ - int isr_overflow; - bool bh_requested; - - 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 *buffer_list; /* virtual address of Rx & Tx buffer lists */ - u32 buffer_list_phys; - dma_addr_t buffer_list_dma_addr; - - unsigned int rx_buffer_count; /* count of total allocated Rx buffers */ - DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */ - unsigned int current_rx_buffer; - - int num_tx_dma_buffers; /* number of tx dma frames required */ - int tx_dma_buffers_used; - unsigned int tx_buffer_count; /* count of total allocated Tx buffers */ - DMABUFFERENTRY *tx_buffer_list; /* list of transmit buffer entries */ - int start_tx_dma_buffer; /* tx dma buffer to start tx dma operation */ - int current_tx_buffer; /* next tx dma buffer to be loaded */ - - unsigned char *intermediate_rxbuffer; - - int num_tx_holding_buffers; /* number of tx holding buffer allocated */ - int get_tx_holding_index; /* next tx holding buffer for adapter to load */ - int put_tx_holding_index; /* next tx holding buffer to store user request */ - int tx_holding_count; /* number of tx holding buffers waiting */ - struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS]; - - bool rx_enabled; - bool rx_overflow; - bool rx_rcc_underrun; - - bool tx_enabled; - bool tx_active; - u32 idle_mode; - - u16 cmr_value; - u16 tcsr_value; - - char device_name[25]; /* device instance name */ - - unsigned char bus; /* expansion bus number (zero based) */ - unsigned char function; /* PCI device number */ - - unsigned int io_base; /* base I/O address of adapter */ - unsigned int io_addr_size; /* size of the I/O address range */ - bool io_addr_requested; /* true if I/O address requested */ - - unsigned int irq_level; /* interrupt level */ - unsigned long irq_flags; - bool irq_requested; /* true if IRQ requested */ - - unsigned int dma_level; /* DMA channel */ - bool dma_requested; /* true if dma channel requested */ - - u16 mbre_bit; - u16 loopback_bits; - u16 usc_idle_mode; - - MGSL_PARAMS params; /* communications parameters */ - - unsigned char serial_signals; /* current serial signal states */ - - bool irq_occurred; /* for diagnostics use */ - unsigned int init_error; /* Initialization startup error (DIAGS) */ - int fDiagnosticsmode; /* Driver in Diagnostic mode? (DIAGS) */ - - u32 last_mem_alloc; - unsigned char* memory_base; /* shared memory address (PCI only) */ - u32 phys_memory_base; - bool shared_mem_requested; - - unsigned char* lcr_base; /* local config registers (PCI only) */ - u32 phys_lcr_base; - u32 lcr_offset; - bool lcr_mem_requested; - - u32 misc_ctrl_value; - char *flag_buf; - bool drop_rts_on_tx_done; - - bool loopmode_insert_requested; - bool loopmode_send_done_requested; - - struct _input_signal_events input_signal_events; - - /* generic HDLC device parts */ - int netcount; - spinlock_t netlock; - -#if SYNCLINK_GENERIC_HDLC - struct net_device *netdev; -#endif -}; - -#define MGSL_MAGIC 0x5401 - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#ifndef SERIAL_XMIT_SIZE -#define SERIAL_XMIT_SIZE 4096 -#endif - -/* - * These macros define the offsets used in calculating the - * I/O address of the specified USC registers. - */ - - -#define DCPIN 2 /* Bit 1 of I/O address */ -#define SDPIN 4 /* Bit 2 of I/O address */ - -#define DCAR 0 /* DMA command/address register */ -#define CCAR SDPIN /* channel command/address register */ -#define DATAREG DCPIN + SDPIN /* serial data register */ -#define MSBONLY 0x41 -#define LSBONLY 0x40 - -/* - * These macros define the register address (ordinal number) - * used for writing address/value pairs to the USC. - */ - -#define CMR 0x02 /* Channel mode Register */ -#define CCSR 0x04 /* Channel Command/status Register */ -#define CCR 0x06 /* Channel Control Register */ -#define PSR 0x08 /* Port status Register */ -#define PCR 0x0a /* Port Control Register */ -#define TMDR 0x0c /* Test mode Data Register */ -#define TMCR 0x0e /* Test mode Control Register */ -#define CMCR 0x10 /* Clock mode Control Register */ -#define HCR 0x12 /* Hardware Configuration Register */ -#define IVR 0x14 /* Interrupt Vector Register */ -#define IOCR 0x16 /* Input/Output Control Register */ -#define ICR 0x18 /* Interrupt Control Register */ -#define DCCR 0x1a /* Daisy Chain Control Register */ -#define MISR 0x1c /* Misc Interrupt status Register */ -#define SICR 0x1e /* status Interrupt Control Register */ -#define RDR 0x20 /* Receive Data Register */ -#define RMR 0x22 /* Receive mode Register */ -#define RCSR 0x24 /* Receive Command/status Register */ -#define RICR 0x26 /* Receive Interrupt Control Register */ -#define RSR 0x28 /* Receive Sync Register */ -#define RCLR 0x2a /* Receive count Limit Register */ -#define RCCR 0x2c /* Receive Character count Register */ -#define TC0R 0x2e /* Time Constant 0 Register */ -#define TDR 0x30 /* Transmit Data Register */ -#define TMR 0x32 /* Transmit mode Register */ -#define TCSR 0x34 /* Transmit Command/status Register */ -#define TICR 0x36 /* Transmit Interrupt Control Register */ -#define TSR 0x38 /* Transmit Sync Register */ -#define TCLR 0x3a /* Transmit count Limit Register */ -#define TCCR 0x3c /* Transmit Character count Register */ -#define TC1R 0x3e /* Time Constant 1 Register */ - - -/* - * MACRO DEFINITIONS FOR DMA REGISTERS - */ - -#define DCR 0x06 /* DMA Control Register (shared) */ -#define DACR 0x08 /* DMA Array count Register (shared) */ -#define BDCR 0x12 /* Burst/Dwell Control Register (shared) */ -#define DIVR 0x14 /* DMA Interrupt Vector Register (shared) */ -#define DICR 0x18 /* DMA Interrupt Control Register (shared) */ -#define CDIR 0x1a /* Clear DMA Interrupt Register (shared) */ -#define SDIR 0x1c /* Set DMA Interrupt Register (shared) */ - -#define TDMR 0x02 /* Transmit DMA mode Register */ -#define TDIAR 0x1e /* Transmit DMA Interrupt Arm Register */ -#define TBCR 0x2a /* Transmit Byte count Register */ -#define TARL 0x2c /* Transmit Address Register (low) */ -#define TARU 0x2e /* Transmit Address Register (high) */ -#define NTBCR 0x3a /* Next Transmit Byte count Register */ -#define NTARL 0x3c /* Next Transmit Address Register (low) */ -#define NTARU 0x3e /* Next Transmit Address Register (high) */ - -#define RDMR 0x82 /* Receive DMA mode Register (non-shared) */ -#define RDIAR 0x9e /* Receive DMA Interrupt Arm Register */ -#define RBCR 0xaa /* Receive Byte count Register */ -#define RARL 0xac /* Receive Address Register (low) */ -#define RARU 0xae /* Receive Address Register (high) */ -#define NRBCR 0xba /* Next Receive Byte count Register */ -#define NRARL 0xbc /* Next Receive Address Register (low) */ -#define NRARU 0xbe /* Next Receive Address Register (high) */ - - -/* - * MACRO DEFINITIONS FOR MODEM STATUS BITS - */ - -#define MODEMSTATUS_DTR 0x80 -#define MODEMSTATUS_DSR 0x40 -#define MODEMSTATUS_RTS 0x20 -#define MODEMSTATUS_CTS 0x10 -#define MODEMSTATUS_RI 0x04 -#define MODEMSTATUS_DCD 0x01 - - -/* - * Channel Command/Address Register (CCAR) Command Codes - */ - -#define RTCmd_Null 0x0000 -#define RTCmd_ResetHighestIus 0x1000 -#define RTCmd_TriggerChannelLoadDma 0x2000 -#define RTCmd_TriggerRxDma 0x2800 -#define RTCmd_TriggerTxDma 0x3000 -#define RTCmd_TriggerRxAndTxDma 0x3800 -#define RTCmd_PurgeRxFifo 0x4800 -#define RTCmd_PurgeTxFifo 0x5000 -#define RTCmd_PurgeRxAndTxFifo 0x5800 -#define RTCmd_LoadRcc 0x6800 -#define RTCmd_LoadTcc 0x7000 -#define RTCmd_LoadRccAndTcc 0x7800 -#define RTCmd_LoadTC0 0x8800 -#define RTCmd_LoadTC1 0x9000 -#define RTCmd_LoadTC0AndTC1 0x9800 -#define RTCmd_SerialDataLSBFirst 0xa000 -#define RTCmd_SerialDataMSBFirst 0xa800 -#define RTCmd_SelectBigEndian 0xb000 -#define RTCmd_SelectLittleEndian 0xb800 - - -/* - * DMA Command/Address Register (DCAR) Command Codes - */ - -#define DmaCmd_Null 0x0000 -#define DmaCmd_ResetTxChannel 0x1000 -#define DmaCmd_ResetRxChannel 0x1200 -#define DmaCmd_StartTxChannel 0x2000 -#define DmaCmd_StartRxChannel 0x2200 -#define DmaCmd_ContinueTxChannel 0x3000 -#define DmaCmd_ContinueRxChannel 0x3200 -#define DmaCmd_PauseTxChannel 0x4000 -#define DmaCmd_PauseRxChannel 0x4200 -#define DmaCmd_AbortTxChannel 0x5000 -#define DmaCmd_AbortRxChannel 0x5200 -#define DmaCmd_InitTxChannel 0x7000 -#define DmaCmd_InitRxChannel 0x7200 -#define DmaCmd_ResetHighestDmaIus 0x8000 -#define DmaCmd_ResetAllChannels 0x9000 -#define DmaCmd_StartAllChannels 0xa000 -#define DmaCmd_ContinueAllChannels 0xb000 -#define DmaCmd_PauseAllChannels 0xc000 -#define DmaCmd_AbortAllChannels 0xd000 -#define DmaCmd_InitAllChannels 0xf000 - -#define TCmd_Null 0x0000 -#define TCmd_ClearTxCRC 0x2000 -#define TCmd_SelectTicrTtsaData 0x4000 -#define TCmd_SelectTicrTxFifostatus 0x5000 -#define TCmd_SelectTicrIntLevel 0x6000 -#define TCmd_SelectTicrdma_level 0x7000 -#define TCmd_SendFrame 0x8000 -#define TCmd_SendAbort 0x9000 -#define TCmd_EnableDleInsertion 0xc000 -#define TCmd_DisableDleInsertion 0xd000 -#define TCmd_ClearEofEom 0xe000 -#define TCmd_SetEofEom 0xf000 - -#define RCmd_Null 0x0000 -#define RCmd_ClearRxCRC 0x2000 -#define RCmd_EnterHuntmode 0x3000 -#define RCmd_SelectRicrRtsaData 0x4000 -#define RCmd_SelectRicrRxFifostatus 0x5000 -#define RCmd_SelectRicrIntLevel 0x6000 -#define RCmd_SelectRicrdma_level 0x7000 - -/* - * Bits for enabling and disabling IRQs in Interrupt Control Register (ICR) - */ - -#define RECEIVE_STATUS BIT5 -#define RECEIVE_DATA BIT4 -#define TRANSMIT_STATUS BIT3 -#define TRANSMIT_DATA BIT2 -#define IO_PIN BIT1 -#define MISC BIT0 - - -/* - * Receive status Bits in Receive Command/status Register RCSR - */ - -#define RXSTATUS_SHORT_FRAME BIT8 -#define RXSTATUS_CODE_VIOLATION BIT8 -#define RXSTATUS_EXITED_HUNT BIT7 -#define RXSTATUS_IDLE_RECEIVED BIT6 -#define RXSTATUS_BREAK_RECEIVED BIT5 -#define RXSTATUS_ABORT_RECEIVED BIT5 -#define RXSTATUS_RXBOUND BIT4 -#define RXSTATUS_CRC_ERROR BIT3 -#define RXSTATUS_FRAMING_ERROR BIT3 -#define RXSTATUS_ABORT BIT2 -#define RXSTATUS_PARITY_ERROR BIT2 -#define RXSTATUS_OVERRUN BIT1 -#define RXSTATUS_DATA_AVAILABLE BIT0 -#define RXSTATUS_ALL 0x01f6 -#define usc_UnlatchRxstatusBits(a,b) usc_OutReg( (a), RCSR, (u16)((b) & RXSTATUS_ALL) ) - -/* - * Values for setting transmit idle mode in - * Transmit Control/status Register (TCSR) - */ -#define IDLEMODE_FLAGS 0x0000 -#define IDLEMODE_ALT_ONE_ZERO 0x0100 -#define IDLEMODE_ZERO 0x0200 -#define IDLEMODE_ONE 0x0300 -#define IDLEMODE_ALT_MARK_SPACE 0x0500 -#define IDLEMODE_SPACE 0x0600 -#define IDLEMODE_MARK 0x0700 -#define IDLEMODE_MASK 0x0700 - -/* - * IUSC revision identifiers - */ -#define IUSC_SL1660 0x4d44 -#define IUSC_PRE_SL1660 0x4553 - -/* - * Transmit status Bits in Transmit Command/status Register (TCSR) - */ - -#define TCSR_PRESERVE 0x0F00 - -#define TCSR_UNDERWAIT BIT11 -#define TXSTATUS_PREAMBLE_SENT BIT7 -#define TXSTATUS_IDLE_SENT BIT6 -#define TXSTATUS_ABORT_SENT BIT5 -#define TXSTATUS_EOF_SENT BIT4 -#define TXSTATUS_EOM_SENT BIT4 -#define TXSTATUS_CRC_SENT BIT3 -#define TXSTATUS_ALL_SENT BIT2 -#define TXSTATUS_UNDERRUN BIT1 -#define TXSTATUS_FIFO_EMPTY BIT0 -#define TXSTATUS_ALL 0x00fa -#define usc_UnlatchTxstatusBits(a,b) usc_OutReg( (a), TCSR, (u16)((a)->tcsr_value + ((b) & 0x00FF)) ) - - -#define MISCSTATUS_RXC_LATCHED BIT15 -#define MISCSTATUS_RXC BIT14 -#define MISCSTATUS_TXC_LATCHED BIT13 -#define MISCSTATUS_TXC BIT12 -#define MISCSTATUS_RI_LATCHED BIT11 -#define MISCSTATUS_RI BIT10 -#define MISCSTATUS_DSR_LATCHED BIT9 -#define MISCSTATUS_DSR BIT8 -#define MISCSTATUS_DCD_LATCHED BIT7 -#define MISCSTATUS_DCD BIT6 -#define MISCSTATUS_CTS_LATCHED BIT5 -#define MISCSTATUS_CTS BIT4 -#define MISCSTATUS_RCC_UNDERRUN BIT3 -#define MISCSTATUS_DPLL_NO_SYNC BIT2 -#define MISCSTATUS_BRG1_ZERO BIT1 -#define MISCSTATUS_BRG0_ZERO BIT0 - -#define usc_UnlatchIostatusBits(a,b) usc_OutReg((a),MISR,(u16)((b) & 0xaaa0)) -#define usc_UnlatchMiscstatusBits(a,b) usc_OutReg((a),MISR,(u16)((b) & 0x000f)) - -#define SICR_RXC_ACTIVE BIT15 -#define SICR_RXC_INACTIVE BIT14 -#define SICR_RXC (BIT15|BIT14) -#define SICR_TXC_ACTIVE BIT13 -#define SICR_TXC_INACTIVE BIT12 -#define SICR_TXC (BIT13|BIT12) -#define SICR_RI_ACTIVE BIT11 -#define SICR_RI_INACTIVE BIT10 -#define SICR_RI (BIT11|BIT10) -#define SICR_DSR_ACTIVE BIT9 -#define SICR_DSR_INACTIVE BIT8 -#define SICR_DSR (BIT9|BIT8) -#define SICR_DCD_ACTIVE BIT7 -#define SICR_DCD_INACTIVE BIT6 -#define SICR_DCD (BIT7|BIT6) -#define SICR_CTS_ACTIVE BIT5 -#define SICR_CTS_INACTIVE BIT4 -#define SICR_CTS (BIT5|BIT4) -#define SICR_RCC_UNDERFLOW BIT3 -#define SICR_DPLL_NO_SYNC BIT2 -#define SICR_BRG1_ZERO BIT1 -#define SICR_BRG0_ZERO BIT0 - -void usc_DisableMasterIrqBit( struct mgsl_struct *info ); -void usc_EnableMasterIrqBit( struct mgsl_struct *info ); -void usc_EnableInterrupts( struct mgsl_struct *info, u16 IrqMask ); -void usc_DisableInterrupts( struct mgsl_struct *info, u16 IrqMask ); -void usc_ClearIrqPendingBits( struct mgsl_struct *info, u16 IrqMask ); - -#define usc_EnableInterrupts( a, b ) \ - usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0xff00) + 0xc0 + (b)) ) - -#define usc_DisableInterrupts( a, b ) \ - usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0xff00) + 0x80 + (b)) ) - -#define usc_EnableMasterIrqBit(a) \ - usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0x0f00) + 0xb000) ) - -#define usc_DisableMasterIrqBit(a) \ - usc_OutReg( (a), ICR, (u16)(usc_InReg((a),ICR) & 0x7f00) ) - -#define usc_ClearIrqPendingBits( a, b ) usc_OutReg( (a), DCCR, 0x40 + (b) ) - -/* - * Transmit status Bits in Transmit Control status Register (TCSR) - * and Transmit Interrupt Control Register (TICR) (except BIT2, BIT0) - */ - -#define TXSTATUS_PREAMBLE_SENT BIT7 -#define TXSTATUS_IDLE_SENT BIT6 -#define TXSTATUS_ABORT_SENT BIT5 -#define TXSTATUS_EOF BIT4 -#define TXSTATUS_CRC_SENT BIT3 -#define TXSTATUS_ALL_SENT BIT2 -#define TXSTATUS_UNDERRUN BIT1 -#define TXSTATUS_FIFO_EMPTY BIT0 - -#define DICR_MASTER BIT15 -#define DICR_TRANSMIT BIT0 -#define DICR_RECEIVE BIT1 - -#define usc_EnableDmaInterrupts(a,b) \ - usc_OutDmaReg( (a), DICR, (u16)(usc_InDmaReg((a),DICR) | (b)) ) - -#define usc_DisableDmaInterrupts(a,b) \ - usc_OutDmaReg( (a), DICR, (u16)(usc_InDmaReg((a),DICR) & ~(b)) ) - -#define usc_EnableStatusIrqs(a,b) \ - usc_OutReg( (a), SICR, (u16)(usc_InReg((a),SICR) | (b)) ) - -#define usc_DisablestatusIrqs(a,b) \ - usc_OutReg( (a), SICR, (u16)(usc_InReg((a),SICR) & ~(b)) ) - -/* Transmit status Bits in Transmit Control status Register (TCSR) */ -/* and Transmit Interrupt Control Register (TICR) (except BIT2, BIT0) */ - - -#define DISABLE_UNCONDITIONAL 0 -#define DISABLE_END_OF_FRAME 1 -#define ENABLE_UNCONDITIONAL 2 -#define ENABLE_AUTO_CTS 3 -#define ENABLE_AUTO_DCD 3 -#define usc_EnableTransmitter(a,b) \ - usc_OutReg( (a), TMR, (u16)((usc_InReg((a),TMR) & 0xfffc) | (b)) ) -#define usc_EnableReceiver(a,b) \ - usc_OutReg( (a), RMR, (u16)((usc_InReg((a),RMR) & 0xfffc) | (b)) ) - -static u16 usc_InDmaReg( struct mgsl_struct *info, u16 Port ); -static void usc_OutDmaReg( struct mgsl_struct *info, u16 Port, u16 Value ); -static void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ); - -static u16 usc_InReg( struct mgsl_struct *info, u16 Port ); -static void usc_OutReg( struct mgsl_struct *info, u16 Port, u16 Value ); -static void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ); -void usc_RCmd( struct mgsl_struct *info, u16 Cmd ); -void usc_TCmd( struct mgsl_struct *info, u16 Cmd ); - -#define usc_TCmd(a,b) usc_OutReg((a), TCSR, (u16)((a)->tcsr_value + (b))) -#define usc_RCmd(a,b) usc_OutReg((a), RCSR, (b)) - -#define usc_SetTransmitSyncChars(a,s0,s1) usc_OutReg((a), TSR, (u16)(((u16)s0<<8)|(u16)s1)) - -static void usc_process_rxoverrun_sync( struct mgsl_struct *info ); -static void usc_start_receiver( struct mgsl_struct *info ); -static void usc_stop_receiver( struct mgsl_struct *info ); - -static void usc_start_transmitter( struct mgsl_struct *info ); -static void usc_stop_transmitter( struct mgsl_struct *info ); -static void usc_set_txidle( struct mgsl_struct *info ); -static void usc_load_txfifo( struct mgsl_struct *info ); - -static void usc_enable_aux_clock( struct mgsl_struct *info, u32 DataRate ); -static void usc_enable_loopback( struct mgsl_struct *info, int enable ); - -static void usc_get_serial_signals( struct mgsl_struct *info ); -static void usc_set_serial_signals( struct mgsl_struct *info ); - -static void usc_reset( struct mgsl_struct *info ); - -static void usc_set_sync_mode( struct mgsl_struct *info ); -static void usc_set_sdlc_mode( struct mgsl_struct *info ); -static void usc_set_async_mode( struct mgsl_struct *info ); -static void usc_enable_async_clock( struct mgsl_struct *info, u32 DataRate ); - -static void usc_loopback_frame( struct mgsl_struct *info ); - -static void mgsl_tx_timeout(struct timer_list *t); - - -static void usc_loopmode_cancel_transmit( struct mgsl_struct * info ); -static void usc_loopmode_insert_request( struct mgsl_struct * info ); -static int usc_loopmode_active( struct mgsl_struct * info); -static void usc_loopmode_send_done( struct mgsl_struct * info ); - -static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg); - -#if SYNCLINK_GENERIC_HDLC -#define dev_to_port(D) (dev_to_hdlc(D)->priv) -static void hdlcdev_tx_done(struct mgsl_struct *info); -static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size); -static int hdlcdev_init(struct mgsl_struct *info); -static void hdlcdev_exit(struct mgsl_struct *info); -#endif - -/* - * Defines a BUS descriptor value for the PCI adapter - * local bus address ranges. - */ - -#define BUS_DESCRIPTOR( WrHold, WrDly, RdDly, Nwdd, Nwad, Nxda, Nrdd, Nrad ) \ -(0x00400020 + \ -((WrHold) << 30) + \ -((WrDly) << 28) + \ -((RdDly) << 26) + \ -((Nwdd) << 20) + \ -((Nwad) << 15) + \ -((Nxda) << 13) + \ -((Nrdd) << 11) + \ -((Nrad) << 6) ) - -static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit); - -/* - * Adapter diagnostic routines - */ -static bool mgsl_register_test( struct mgsl_struct *info ); -static bool mgsl_irq_test( struct mgsl_struct *info ); -static bool mgsl_dma_test( struct mgsl_struct *info ); -static bool mgsl_memory_test( struct mgsl_struct *info ); -static int mgsl_adapter_test( struct mgsl_struct *info ); - -/* - * device and resource management routines - */ -static int mgsl_claim_resources(struct mgsl_struct *info); -static void mgsl_release_resources(struct mgsl_struct *info); -static void mgsl_add_device(struct mgsl_struct *info); -static struct mgsl_struct* mgsl_allocate_device(void); - -/* - * DMA buffer manupulation functions. - */ -static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); -static bool mgsl_get_rx_frame( struct mgsl_struct *info ); -static bool mgsl_get_raw_rx_frame( struct mgsl_struct *info ); -static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); -static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ); -static int num_free_tx_dma_buffers(struct mgsl_struct *info); -static void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize); -static void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count); - -/* - * DMA and Shared Memory buffer allocation and formatting - */ -static int mgsl_allocate_dma_buffers(struct mgsl_struct *info); -static void mgsl_free_dma_buffers(struct mgsl_struct *info); -static int mgsl_alloc_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); -static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); -static int mgsl_alloc_buffer_list_memory(struct mgsl_struct *info); -static void mgsl_free_buffer_list_memory(struct mgsl_struct *info); -static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info); -static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info); -static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info); -static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info); -static bool load_next_tx_holding_buffer(struct mgsl_struct *info); -static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize); - -/* - * Bottom half interrupt handlers - */ -static void mgsl_bh_handler(struct work_struct *work); -static void mgsl_bh_receive(struct mgsl_struct *info); -static void mgsl_bh_transmit(struct mgsl_struct *info); -static void mgsl_bh_status(struct mgsl_struct *info); - -/* - * Interrupt handler routines and dispatch table. - */ -static void mgsl_isr_null( struct mgsl_struct *info ); -static void mgsl_isr_transmit_data( struct mgsl_struct *info ); -static void mgsl_isr_receive_data( struct mgsl_struct *info ); -static void mgsl_isr_receive_status( struct mgsl_struct *info ); -static void mgsl_isr_transmit_status( struct mgsl_struct *info ); -static void mgsl_isr_io_pin( struct mgsl_struct *info ); -static void mgsl_isr_misc( struct mgsl_struct *info ); -static void mgsl_isr_receive_dma( struct mgsl_struct *info ); -static void mgsl_isr_transmit_dma( struct mgsl_struct *info ); - -typedef void (*isr_dispatch_func)(struct mgsl_struct *); - -static isr_dispatch_func UscIsrTable[7] = -{ - mgsl_isr_null, - mgsl_isr_misc, - mgsl_isr_io_pin, - mgsl_isr_transmit_data, - mgsl_isr_transmit_status, - mgsl_isr_receive_data, - mgsl_isr_receive_status -}; - -/* - * ioctl call handlers - */ -static int tiocmget(struct tty_struct *tty); -static int tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount - __user *user_icount); -static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS __user *user_params); -static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS __user *new_params); -static int mgsl_get_txidle(struct mgsl_struct * info, int __user *idle_mode); -static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode); -static int mgsl_txenable(struct mgsl_struct * info, int enable); -static int mgsl_txabort(struct mgsl_struct * info); -static int mgsl_rxenable(struct mgsl_struct * info, int enable); -static int mgsl_wait_event(struct mgsl_struct * info, int __user *mask); -static int mgsl_loopmode_send_done( struct mgsl_struct * info ); - -/* set non-zero on successful registration with PCI subsystem */ -static bool pci_registered; - -/* - * Global linked list of SyncLink devices - */ -static struct mgsl_struct *mgsl_device_list; -static int mgsl_device_count; - -/* - * Set this param to non-zero to load eax with the - * .text section address and breakpoint on module load. - * This is useful for use with gdb and add-symbol-file command. - */ -static bool break_on_load; - -/* - * Driver major number, defaults to zero to get auto - * assigned major number. May be forced as module parameter. - */ -static int ttymajor; - -/* - * Array of user specified options for ISA adapters. - */ -static int io[MAX_ISA_DEVICES]; -static int irq[MAX_ISA_DEVICES]; -static int dma[MAX_ISA_DEVICES]; -static int debug_level; -static int maxframe[MAX_TOTAL_DEVICES]; -static int txdmabufs[MAX_TOTAL_DEVICES]; -static int txholdbufs[MAX_TOTAL_DEVICES]; - -module_param(break_on_load, bool, 0); -module_param(ttymajor, int, 0); -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param_hw_array(dma, int, dma, NULL, 0); -module_param(debug_level, int, 0); -module_param_array(maxframe, int, NULL, 0); -module_param_array(txdmabufs, int, NULL, 0); -module_param_array(txholdbufs, int, NULL, 0); - -static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "$Revision: 4.38 $"; - -static int synclink_init_one (struct pci_dev *dev, - const struct pci_device_id *ent); -static void synclink_remove_one (struct pci_dev *dev); - -static const struct pci_device_id synclink_pci_tbl[] = { - { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, }, /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, synclink_pci_tbl); - -MODULE_LICENSE("GPL"); - -static struct pci_driver synclink_pci_driver = { - .name = "synclink", - .id_table = synclink_pci_tbl, - .probe = synclink_init_one, - .remove = synclink_remove_one, -}; - -static struct tty_driver *serial_driver; - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - - -static void mgsl_change_params(struct mgsl_struct *info); -static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout); - -/* - * 1st function defined in .text section. Calling this function in - * init_module() followed by a breakpoint allows a remote debugger - * (gdb) to get the .text address for the add-symbol-file command. - * This allows remote debugging of dynamically loadable modules. - */ -static void* mgsl_get_text_ptr(void) -{ - return mgsl_get_text_ptr; -} - -static inline int mgsl_paranoia_check(struct mgsl_struct *info, - char *name, const char *routine) -{ -#ifdef MGSL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for mgsl struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null mgsl_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != MGSL_MAGIC) { - printk(badmagic, name, routine); - 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); - } -} - -/* mgsl_stop() throttle (stop) transmitter - * - * Arguments: tty pointer to tty info structure - * Return Value: None - */ -static void mgsl_stop(struct tty_struct *tty) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if (mgsl_paranoia_check(info, tty->name, "mgsl_stop")) - return; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("mgsl_stop(%s)\n",info->device_name); - - spin_lock_irqsave(&info->irq_spinlock,flags); - if (info->tx_enabled) - usc_stop_transmitter(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - -} /* end of mgsl_stop() */ - -/* mgsl_start() release (start) transmitter - * - * Arguments: tty pointer to tty info structure - * Return Value: None - */ -static void mgsl_start(struct tty_struct *tty) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if (mgsl_paranoia_check(info, tty->name, "mgsl_start")) - return; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("mgsl_start(%s)\n",info->device_name); - - spin_lock_irqsave(&info->irq_spinlock,flags); - if (!info->tx_enabled) - usc_start_transmitter(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - -} /* end of mgsl_start() */ - -/* - * Bottom half work queue access functions - */ - -/* mgsl_bh_action() Return next bottom half action to perform. - * Return Value: BH action code or 0 if nothing to do. - */ -static int mgsl_bh_action(struct mgsl_struct *info) -{ - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&info->irq_spinlock,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; - } - - if (!rc) { - /* Mark BH routine as complete */ - info->bh_running = false; - info->bh_requested = false; - } - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - return rc; -} - -/* - * Perform bottom half processing of work items queued by ISR. - */ -static void mgsl_bh_handler(struct work_struct *work) -{ - struct mgsl_struct *info = - container_of(work, struct mgsl_struct, task); - int action; - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):mgsl_bh_handler(%s) entry\n", - __FILE__,__LINE__,info->device_name); - - info->bh_running = true; - - while((action = mgsl_bh_action(info)) != 0) { - - /* Process work item */ - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):mgsl_bh_handler() work item action=%d\n", - __FILE__,__LINE__,action); - - switch (action) { - - case BH_RECEIVE: - mgsl_bh_receive(info); - break; - case BH_TRANSMIT: - mgsl_bh_transmit(info); - break; - case BH_STATUS: - mgsl_bh_status(info); - break; - default: - /* unknown work item ID */ - printk("Unknown work item ID=%08X!\n", action); - break; - } - } - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):mgsl_bh_handler(%s) exit\n", - __FILE__,__LINE__,info->device_name); -} - -static void mgsl_bh_receive(struct mgsl_struct *info) -{ - bool (*get_rx_frame)(struct mgsl_struct *info) = - (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame); - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):mgsl_bh_receive(%s)\n", - __FILE__,__LINE__,info->device_name); - - do - { - if (info->rx_rcc_underrun) { - unsigned long flags; - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_start_receiver(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - return; - } - } while(get_rx_frame(info)); -} - -static void mgsl_bh_transmit(struct mgsl_struct *info) -{ - struct tty_struct *tty = info->port.tty; - unsigned long flags; - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):mgsl_bh_transmit() entry on %s\n", - __FILE__,__LINE__,info->device_name); - - if (tty) - tty_wakeup(tty); - - /* if transmitter idle and loopmode_send_done_requested - * then start echoing RxD to TxD - */ - spin_lock_irqsave(&info->irq_spinlock,flags); - if ( !info->tx_active && info->loopmode_send_done_requested ) - usc_loopmode_send_done( info ); - spin_unlock_irqrestore(&info->irq_spinlock,flags); -} - -static void mgsl_bh_status(struct mgsl_struct *info) -{ - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):mgsl_bh_status() entry on %s\n", - __FILE__,__LINE__,info->device_name); - - info->ri_chkcount = 0; - info->dsr_chkcount = 0; - info->dcd_chkcount = 0; - info->cts_chkcount = 0; -} - -/* mgsl_isr_receive_status() - * - * Service a receive status interrupt. The type of status - * interrupt is indicated by the state of the RCSR. - * This is only used for HDLC mode. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_isr_receive_status( struct mgsl_struct *info ) -{ - u16 status = usc_InReg( info, RCSR ); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):mgsl_isr_receive_status status=%04X\n", - __FILE__,__LINE__,status); - - if ( (status & RXSTATUS_ABORT_RECEIVED) && - info->loopmode_insert_requested && - usc_loopmode_active(info) ) - { - ++info->icount.rxabort; - info->loopmode_insert_requested = false; - - /* clear CMR:13 to start echoing RxD to TxD */ - info->cmr_value &= ~BIT13; - usc_OutReg(info, CMR, info->cmr_value); - - /* disable received abort irq (no longer required) */ - usc_OutReg(info, RICR, - (usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED)); - } - - if (status & (RXSTATUS_EXITED_HUNT | RXSTATUS_IDLE_RECEIVED)) { - if (status & RXSTATUS_EXITED_HUNT) - info->icount.exithunt++; - if (status & RXSTATUS_IDLE_RECEIVED) - info->icount.rxidle++; - wake_up_interruptible(&info->event_wait_q); - } - - if (status & RXSTATUS_OVERRUN){ - info->icount.rxover++; - usc_process_rxoverrun_sync( info ); - } - - usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); - usc_UnlatchRxstatusBits( info, status ); - -} /* end of mgsl_isr_receive_status() */ - -/* mgsl_isr_transmit_status() - * - * Service a transmit status interrupt - * HDLC mode :end of transmit frame - * Async mode:all data is sent - * transmit status is indicated by bits in the TCSR. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_isr_transmit_status( struct mgsl_struct *info ) -{ - u16 status = usc_InReg( info, TCSR ); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):mgsl_isr_transmit_status status=%04X\n", - __FILE__,__LINE__,status); - - usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); - usc_UnlatchTxstatusBits( info, status ); - - if ( status & (TXSTATUS_UNDERRUN | TXSTATUS_ABORT_SENT) ) - { - /* finished sending HDLC abort. This may leave */ - /* the TxFifo with data from the aborted frame */ - /* so purge the TxFifo. Also shutdown the DMA */ - /* channel in case there is data remaining in */ - /* the DMA buffer */ - usc_DmaCmd( info, DmaCmd_ResetTxChannel ); - usc_RTCmd( info, RTCmd_PurgeTxFifo ); - } - - if ( status & TXSTATUS_EOF_SENT ) - info->icount.txok++; - else if ( status & TXSTATUS_UNDERRUN ) - info->icount.txunder++; - else if ( status & TXSTATUS_ABORT_SENT ) - info->icount.txabort++; - else - info->icount.txunder++; - - info->tx_active = false; - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - del_timer(&info->tx_timer); - - if ( info->drop_rts_on_tx_done ) { - usc_get_serial_signals( info ); - if ( info->serial_signals & SerialSignal_RTS ) { - info->serial_signals &= ~SerialSignal_RTS; - usc_set_serial_signals( info ); - } - info->drop_rts_on_tx_done = false; - } - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_tx_done(info); - else -#endif - { - if (info->port.tty->stopped || info->port.tty->hw_stopped) { - usc_stop_transmitter(info); - return; - } - info->pending_bh |= BH_TRANSMIT; - } - -} /* end of mgsl_isr_transmit_status() */ - -/* mgsl_isr_io_pin() - * - * Service an Input/Output pin interrupt. The type of - * interrupt is indicated by bits in the MISR - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_isr_io_pin( struct mgsl_struct *info ) -{ - struct mgsl_icount *icount; - u16 status = usc_InReg( info, MISR ); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):mgsl_isr_io_pin status=%04X\n", - __FILE__,__LINE__,status); - - usc_ClearIrqPendingBits( info, IO_PIN ); - usc_UnlatchIostatusBits( info, status ); - - if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED | - MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) { - icount = &info->icount; - /* update input line counters */ - if (status & MISCSTATUS_RI_LATCHED) { - if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) - usc_DisablestatusIrqs(info,SICR_RI); - icount->rng++; - if ( status & MISCSTATUS_RI ) - info->input_signal_events.ri_up++; - else - info->input_signal_events.ri_down++; - } - if (status & MISCSTATUS_DSR_LATCHED) { - if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) - usc_DisablestatusIrqs(info,SICR_DSR); - icount->dsr++; - if ( status & MISCSTATUS_DSR ) - info->input_signal_events.dsr_up++; - else - info->input_signal_events.dsr_down++; - } - if (status & MISCSTATUS_DCD_LATCHED) { - if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) - usc_DisablestatusIrqs(info,SICR_DCD); - icount->dcd++; - if (status & MISCSTATUS_DCD) { - info->input_signal_events.dcd_up++; - } else - info->input_signal_events.dcd_down++; -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) { - if (status & MISCSTATUS_DCD) - netif_carrier_on(info->netdev); - else - netif_carrier_off(info->netdev); - } -#endif - } - if (status & MISCSTATUS_CTS_LATCHED) - { - if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) - usc_DisablestatusIrqs(info,SICR_CTS); - icount->cts++; - if ( status & MISCSTATUS_CTS ) - info->input_signal_events.cts_up++; - else - info->input_signal_events.cts_down++; - } - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - - if (tty_port_check_carrier(&info->port) && - (status & MISCSTATUS_DCD_LATCHED) ) { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s CD now %s...", info->device_name, - (status & MISCSTATUS_DCD) ? "on" : "off"); - if (status & MISCSTATUS_DCD) - wake_up_interruptible(&info->port.open_wait); - else { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("doing serial hangup..."); - if (info->port.tty) - tty_hangup(info->port.tty); - } - } - - if (tty_port_cts_enabled(&info->port) && - (status & MISCSTATUS_CTS_LATCHED) ) { - if (info->port.tty->hw_stopped) { - if (status & MISCSTATUS_CTS) { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("CTS tx start..."); - info->port.tty->hw_stopped = 0; - usc_start_transmitter(info); - info->pending_bh |= BH_TRANSMIT; - return; - } - } else { - if (!(status & MISCSTATUS_CTS)) { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("CTS tx stop..."); - if (info->port.tty) - info->port.tty->hw_stopped = 1; - usc_stop_transmitter(info); - } - } - } - } - - info->pending_bh |= BH_STATUS; - - /* for diagnostics set IRQ flag */ - if ( status & MISCSTATUS_TXC_LATCHED ){ - usc_OutReg( info, SICR, - (unsigned short)(usc_InReg(info,SICR) & ~(SICR_TXC_ACTIVE+SICR_TXC_INACTIVE)) ); - usc_UnlatchIostatusBits( info, MISCSTATUS_TXC_LATCHED ); - info->irq_occurred = true; - } - -} /* end of mgsl_isr_io_pin() */ - -/* mgsl_isr_transmit_data() - * - * Service a transmit data interrupt (async mode only). - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_isr_transmit_data( struct mgsl_struct *info ) -{ - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):mgsl_isr_transmit_data xmit_cnt=%d\n", - __FILE__,__LINE__,info->xmit_cnt); - - usc_ClearIrqPendingBits( info, TRANSMIT_DATA ); - - if (info->port.tty->stopped || info->port.tty->hw_stopped) { - usc_stop_transmitter(info); - return; - } - - if ( info->xmit_cnt ) - usc_load_txfifo( info ); - else - info->tx_active = false; - - if (info->xmit_cnt < WAKEUP_CHARS) - info->pending_bh |= BH_TRANSMIT; - -} /* end of mgsl_isr_transmit_data() */ - -/* mgsl_isr_receive_data() - * - * Service a receive data interrupt. This occurs - * when operating in asynchronous interrupt transfer mode. - * The receive data FIFO is flushed to the receive data buffers. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_isr_receive_data( struct mgsl_struct *info ) -{ - int Fifocount; - u16 status; - int work = 0; - unsigned char DataByte; - struct mgsl_icount *icount = &info->icount; - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):mgsl_isr_receive_data\n", - __FILE__,__LINE__); - - usc_ClearIrqPendingBits( info, RECEIVE_DATA ); - - /* select FIFO status for RICR readback */ - usc_RCmd( info, RCmd_SelectRicrRxFifostatus ); - - /* clear the Wordstatus bit so that status readback */ - /* only reflects the status of this byte */ - usc_OutReg( info, RICR+LSBONLY, (u16)(usc_InReg(info, RICR+LSBONLY) & ~BIT3 )); - - /* flush the receive FIFO */ - - while( (Fifocount = (usc_InReg(info,RICR) >> 8)) ) { - int flag; - - /* read one byte from RxFIFO */ - outw( (inw(info->io_base + CCAR) & 0x0780) | (RDR+LSBONLY), - info->io_base + CCAR ); - DataByte = inb( info->io_base + CCAR ); - - /* get the status of the received byte */ - status = usc_InReg(info, RCSR); - if ( status & (RXSTATUS_FRAMING_ERROR | RXSTATUS_PARITY_ERROR | - RXSTATUS_OVERRUN | RXSTATUS_BREAK_RECEIVED) ) - usc_UnlatchRxstatusBits(info,RXSTATUS_ALL); - - icount->rx++; - - flag = 0; - if ( status & (RXSTATUS_FRAMING_ERROR | RXSTATUS_PARITY_ERROR | - RXSTATUS_OVERRUN | RXSTATUS_BREAK_RECEIVED) ) { - printk("rxerr=%04X\n",status); - /* update error statistics */ - if ( status & RXSTATUS_BREAK_RECEIVED ) { - status &= ~(RXSTATUS_FRAMING_ERROR | RXSTATUS_PARITY_ERROR); - icount->brk++; - } else if (status & RXSTATUS_PARITY_ERROR) - icount->parity++; - else if (status & RXSTATUS_FRAMING_ERROR) - icount->frame++; - else if (status & RXSTATUS_OVERRUN) { - /* must issue purge fifo cmd before */ - /* 16C32 accepts more receive chars */ - usc_RTCmd(info,RTCmd_PurgeRxFifo); - icount->overrun++; - } - - /* discard char if tty control flags say so */ - if (status & info->ignore_status_mask) - continue; - - status &= info->read_status_mask; - - if (status & RXSTATUS_BREAK_RECEIVED) { - flag = TTY_BREAK; - if (info->port.flags & ASYNC_SAK) - do_SAK(info->port.tty); - } else if (status & RXSTATUS_PARITY_ERROR) - flag = TTY_PARITY; - else if (status & RXSTATUS_FRAMING_ERROR) - flag = TTY_FRAME; - } /* end of if (error) */ - tty_insert_flip_char(&info->port, DataByte, flag); - if (status & RXSTATUS_OVERRUN) { - /* Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - work += tty_insert_flip_char(&info->port, 0, TTY_OVERRUN); - } - } - - if ( debug_level >= DEBUG_LEVEL_ISR ) { - printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", - __FILE__,__LINE__,icount->rx,icount->brk, - icount->parity,icount->frame,icount->overrun); - } - - if(work) - tty_flip_buffer_push(&info->port); -} - -/* mgsl_isr_misc() - * - * Service a miscellaneous interrupt source. - * - * Arguments: info pointer to device extension (instance data) - * Return Value: None - */ -static void mgsl_isr_misc( struct mgsl_struct *info ) -{ - u16 status = usc_InReg( info, MISR ); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):mgsl_isr_misc status=%04X\n", - __FILE__,__LINE__,status); - - if ((status & MISCSTATUS_RCC_UNDERRUN) && - (info->params.mode == MGSL_MODE_HDLC)) { - - /* turn off receiver and rx DMA */ - usc_EnableReceiver(info,DISABLE_UNCONDITIONAL); - usc_DmaCmd(info, DmaCmd_ResetRxChannel); - usc_UnlatchRxstatusBits(info, RXSTATUS_ALL); - usc_ClearIrqPendingBits(info, RECEIVE_DATA | RECEIVE_STATUS); - usc_DisableInterrupts(info, RECEIVE_DATA | RECEIVE_STATUS); - - /* schedule BH handler to restart receiver */ - info->pending_bh |= BH_RECEIVE; - info->rx_rcc_underrun = true; - } - - usc_ClearIrqPendingBits( info, MISC ); - usc_UnlatchMiscstatusBits( info, status ); - -} /* end of mgsl_isr_misc() */ - -/* mgsl_isr_null() - * - * Services undefined interrupt vectors from the - * USC. (hence this function SHOULD never be called) - * - * Arguments: info pointer to device extension (instance data) - * Return Value: None - */ -static void mgsl_isr_null( struct mgsl_struct *info ) -{ - -} /* end of mgsl_isr_null() */ - -/* mgsl_isr_receive_dma() - * - * Service a receive DMA channel interrupt. - * For this driver there are two sources of receive DMA interrupts - * as identified in the Receive DMA mode Register (RDMR): - * - * BIT3 EOA/EOL End of List, all receive buffers in receive - * buffer list have been filled (no more free buffers - * available). The DMA controller has shut down. - * - * BIT2 EOB End of Buffer. This interrupt occurs when a receive - * DMA buffer is terminated in response to completion - * of a good frame or a frame with errors. The status - * of the frame is stored in the buffer entry in the - * list of receive buffer entries. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_isr_receive_dma( struct mgsl_struct *info ) -{ - u16 status; - - /* clear interrupt pending and IUS bit for Rx DMA IRQ */ - usc_OutDmaReg( info, CDIR, BIT9 | BIT1 ); - - /* Read the receive DMA status to identify interrupt type. */ - /* This also clears the status bits. */ - status = usc_InDmaReg( info, RDMR ); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):mgsl_isr_receive_dma(%s) status=%04X\n", - __FILE__,__LINE__,info->device_name,status); - - info->pending_bh |= BH_RECEIVE; - - if ( status & BIT3 ) { - info->rx_overflow = true; - info->icount.buf_overrun++; - } - -} /* end of mgsl_isr_receive_dma() */ - -/* mgsl_isr_transmit_dma() - * - * This function services a transmit DMA channel interrupt. - * - * For this driver there is one source of transmit DMA interrupts - * as identified in the Transmit DMA Mode Register (TDMR): - * - * BIT2 EOB End of Buffer. This interrupt occurs when a - * transmit DMA buffer has been emptied. - * - * The driver maintains enough transmit DMA buffers to hold at least - * one max frame size transmit frame. When operating in a buffered - * transmit mode, there may be enough transmit DMA buffers to hold at - * least two or more max frame size frames. On an EOB condition, - * determine if there are any queued transmit buffers and copy into - * transmit DMA buffers if we have room. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_isr_transmit_dma( struct mgsl_struct *info ) -{ - u16 status; - - /* clear interrupt pending and IUS bit for Tx DMA IRQ */ - usc_OutDmaReg(info, CDIR, BIT8 | BIT0 ); - - /* Read the transmit DMA status to identify interrupt type. */ - /* This also clears the status bits. */ - - status = usc_InDmaReg( info, TDMR ); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):mgsl_isr_transmit_dma(%s) status=%04X\n", - __FILE__,__LINE__,info->device_name,status); - - if ( status & BIT2 ) { - --info->tx_dma_buffers_used; - - /* if there are transmit frames queued, - * try to load the next one - */ - if ( load_next_tx_holding_buffer(info) ) { - /* if call returns non-zero value, we have - * at least one free tx holding buffer - */ - info->pending_bh |= BH_TRANSMIT; - } - } - -} /* end of mgsl_isr_transmit_dma() */ - -/* mgsl_interrupt() - * - * Interrupt service routine entry point. - * - * Arguments: - * - * irq interrupt number that caused interrupt - * dev_id device ID supplied during interrupt registration - * - * Return Value: None - */ -static irqreturn_t mgsl_interrupt(int dummy, void *dev_id) -{ - struct mgsl_struct *info = dev_id; - u16 UscVector; - u16 DmaVector; - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk(KERN_DEBUG "%s(%d):mgsl_interrupt(%d)entry.\n", - __FILE__, __LINE__, info->irq_level); - - spin_lock(&info->irq_spinlock); - - for(;;) { - /* Read the interrupt vectors from hardware. */ - UscVector = usc_InReg(info, IVR) >> 9; - DmaVector = usc_InDmaReg(info, DIVR); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s UscVector=%08X DmaVector=%08X\n", - __FILE__,__LINE__,info->device_name,UscVector,DmaVector); - - if ( !UscVector && !DmaVector ) - break; - - /* Dispatch interrupt vector */ - if ( UscVector ) - (*UscIsrTable[UscVector])(info); - else if ( (DmaVector&(BIT10|BIT9)) == BIT10) - mgsl_isr_transmit_dma(info); - else - mgsl_isr_receive_dma(info); - - if ( info->isr_overflow ) { - printk(KERN_ERR "%s(%d):%s isr overflow irq=%d\n", - __FILE__, __LINE__, info->device_name, info->irq_level); - usc_DisableMasterIrqBit(info); - usc_DisableDmaInterrupts(info,DICR_MASTER); - break; - } - } - - /* Request bottom half processing if there's something - * for it to do and the bh is not already running - */ - - if ( info->pending_bh && !info->bh_running && !info->bh_requested ) { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s queueing bh task.\n", - __FILE__,__LINE__,info->device_name); - schedule_work(&info->task); - info->bh_requested = true; - } - - spin_unlock(&info->irq_spinlock); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk(KERN_DEBUG "%s(%d):mgsl_interrupt(%d)exit.\n", - __FILE__, __LINE__, info->irq_level); - - return IRQ_HANDLED; -} /* end of mgsl_interrupt() */ - -/* startup() - * - * Initialize and start device. - * - * Arguments: info pointer to device instance data - * Return Value: 0 if success, otherwise error code - */ -static int startup(struct mgsl_struct * info) -{ - int retval = 0; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name); - - if (tty_port_initialized(&info->port)) - return 0; - - if (!info->xmit_buf) { - /* allocate a page of memory for a transmit buffer */ - info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); - if (!info->xmit_buf) { - printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", - __FILE__,__LINE__,info->device_name); - return -ENOMEM; - } - } - - info->pending_bh = 0; - - memset(&info->icount, 0, sizeof(info->icount)); - - timer_setup(&info->tx_timer, mgsl_tx_timeout, 0); - - /* Allocate and claim adapter resources */ - retval = mgsl_claim_resources(info); - - /* perform existence check and diagnostics */ - if ( !retval ) - retval = mgsl_adapter_test(info); - - if ( retval ) { - if (capable(CAP_SYS_ADMIN) && info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - mgsl_release_resources(info); - return retval; - } - - /* program hardware for current parameters */ - mgsl_change_params(info); - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - tty_port_set_initialized(&info->port, 1); - - return 0; -} /* end of startup() */ - -/* shutdown() - * - * Called by mgsl_close() and mgsl_hangup() to shutdown hardware - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void shutdown(struct mgsl_struct * info) -{ - unsigned long flags; - - if (!tty_port_initialized(&info->port)) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_shutdown(%s)\n", - __FILE__,__LINE__, 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); - - del_timer_sync(&info->tx_timer); - - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = NULL; - } - - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_DisableMasterIrqBit(info); - usc_stop_receiver(info); - usc_stop_transmitter(info); - usc_DisableInterrupts(info,RECEIVE_DATA | RECEIVE_STATUS | - TRANSMIT_DATA | TRANSMIT_STATUS | IO_PIN | MISC ); - usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE); - - /* Disable DMAEN (Port 7, Bit 14) */ - /* This disconnects the DMA request signal from the ISA bus */ - /* on the ISA adapter. This has no effect for the PCI adapter */ - usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14)); - - /* Disable INTEN (Port 6, Bit12) */ - /* This disconnects the IRQ request signal to the ISA bus */ - /* on the ISA adapter. This has no effect for the PCI adapter */ - usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12)); - - if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) { - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - usc_set_serial_signals(info); - } - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - mgsl_release_resources(info); - - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - tty_port_set_initialized(&info->port, 0); -} /* end of shutdown() */ - -static void mgsl_program_hw(struct mgsl_struct *info) -{ - unsigned long flags; - - spin_lock_irqsave(&info->irq_spinlock,flags); - - usc_stop_receiver(info); - usc_stop_transmitter(info); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - if (info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW || - info->netcount) - usc_set_sync_mode(info); - else - usc_set_async_mode(info); - - usc_set_serial_signals(info); - - info->dcd_chkcount = 0; - info->cts_chkcount = 0; - info->ri_chkcount = 0; - info->dsr_chkcount = 0; - - usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI); - usc_EnableInterrupts(info, IO_PIN); - usc_get_serial_signals(info); - - if (info->netcount || info->port.tty->termios.c_cflag & CREAD) - usc_start_receiver(info); - - spin_unlock_irqrestore(&info->irq_spinlock,flags); -} - -/* Reconfigure adapter based on new parameters - */ -static void mgsl_change_params(struct mgsl_struct *info) -{ - unsigned cflag; - int bits_per_char; - - if (!info->port.tty) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_change_params(%s)\n", - __FILE__,__LINE__, 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->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; - else - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - - /* byte size and parity */ - - switch (cflag & CSIZE) { - case CS5: info->params.data_bits = 5; break; - case CS6: info->params.data_bits = 6; break; - case CS7: info->params.data_bits = 7; break; - case CS8: info->params.data_bits = 8; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: info->params.data_bits = 7; break; - } - - if (cflag & CSTOPB) - info->params.stop_bits = 2; - else - info->params.stop_bits = 1; - - info->params.parity = ASYNC_PARITY_NONE; - if (cflag & PARENB) { - if (cflag & PARODD) - info->params.parity = ASYNC_PARITY_ODD; - else - info->params.parity = ASYNC_PARITY_EVEN; -#ifdef CMSPAR - if (cflag & CMSPAR) - info->params.parity = ASYNC_PARITY_SPACE; -#endif - } - - /* 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; - - /* if port data rate is set to 460800 or less then - * allow tty settings to override, otherwise keep the - * current data rate. - */ - if (info->params.data_rate <= 460800) - 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 = RXSTATUS_OVERRUN; - if (I_INPCK(info->port.tty)) - info->read_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) - info->read_status_mask |= RXSTATUS_BREAK_RECEIVED; - - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; - if (I_IGNBRK(info->port.tty)) { - info->ignore_status_mask |= RXSTATUS_BREAK_RECEIVED; - /* If ignoring parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= RXSTATUS_OVERRUN; - } - - mgsl_program_hw(info); - -} /* end of mgsl_change_params() */ - -/* mgsl_put_char() - * - * Add a character to the transmit buffer. - * - * Arguments: tty pointer to tty information structure - * ch character to add to transmit buffer - * - * Return Value: None - */ -static int mgsl_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - int ret = 0; - - if (debug_level >= DEBUG_LEVEL_INFO) { - printk(KERN_DEBUG "%s(%d):mgsl_put_char(%d) on %s\n", - __FILE__, __LINE__, ch, info->device_name); - } - - if (mgsl_paranoia_check(info, tty->name, "mgsl_put_char")) - return 0; - - if (!info->xmit_buf) - return 0; - - spin_lock_irqsave(&info->irq_spinlock, flags); - - if ((info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active) { - if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) { - info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= SERIAL_XMIT_SIZE-1; - info->xmit_cnt++; - ret = 1; - } - } - spin_unlock_irqrestore(&info->irq_spinlock, flags); - return ret; - -} /* end of mgsl_put_char() */ - -/* mgsl_flush_chars() - * - * Enable transmitter so remaining characters in the - * transmit buffer are sent. - * - * Arguments: tty pointer to tty information structure - * Return Value: None - */ -static void mgsl_flush_chars(struct tty_struct *tty) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_flush_chars() entry on %s xmit_cnt=%d\n", - __FILE__,__LINE__,info->device_name,info->xmit_cnt); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_flush_chars")) - return; - - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) - return; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_flush_chars() entry on %s starting transmitter\n", - __FILE__,__LINE__,info->device_name ); - - spin_lock_irqsave(&info->irq_spinlock,flags); - - if (!info->tx_active) { - if ( (info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW) && info->xmit_cnt ) { - /* operating in synchronous (frame oriented) mode */ - /* copy data from circular xmit_buf to */ - /* transmit DMA buffer. */ - mgsl_load_tx_dma_buffer(info, - info->xmit_buf,info->xmit_cnt); - } - usc_start_transmitter(info); - } - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - -} /* end of mgsl_flush_chars() */ - -/* mgsl_write() - * - * Send a block of data - * - * Arguments: - * - * tty pointer to tty information structure - * buf pointer to buffer containing send data - * count size of send data in bytes - * - * Return Value: number of characters written - */ -static int mgsl_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - int c, ret = 0; - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_write(%s) count=%d\n", - __FILE__,__LINE__,info->device_name,count); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_write")) - goto cleanup; - - if (!info->xmit_buf) - goto cleanup; - - if ( info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW ) { - /* operating in synchronous (frame oriented) mode */ - if (info->tx_active) { - - if ( info->params.mode == MGSL_MODE_HDLC ) { - ret = 0; - goto cleanup; - } - /* transmitter is actively sending data - - * if we have multiple transmit dma and - * holding buffers, attempt to queue this - * frame for transmission at a later time. - */ - if (info->tx_holding_count >= info->num_tx_holding_buffers ) { - /* no tx holding buffers available */ - ret = 0; - goto cleanup; - } - - /* queue transmit frame request */ - ret = count; - save_tx_buffer_request(info,buf,count); - - /* if we have sufficient tx dma buffers, - * load the next buffered tx request - */ - spin_lock_irqsave(&info->irq_spinlock,flags); - load_next_tx_holding_buffer(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - goto cleanup; - } - - /* if operating in HDLC LoopMode and the adapter */ - /* has yet to be inserted into the loop, we can't */ - /* transmit */ - - if ( (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) && - !usc_loopmode_active(info) ) - { - ret = 0; - goto cleanup; - } - - if ( info->xmit_cnt ) { - /* Send accumulated from send_char() calls */ - /* as frame and wait before accepting more data. */ - ret = 0; - - /* copy data from circular xmit_buf to */ - /* transmit DMA buffer. */ - mgsl_load_tx_dma_buffer(info, - info->xmit_buf,info->xmit_cnt); - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_write(%s) sync xmit_cnt flushing\n", - __FILE__,__LINE__,info->device_name); - } else { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_write(%s) sync transmit accepted\n", - __FILE__,__LINE__,info->device_name); - ret = count; - info->xmit_cnt = count; - mgsl_load_tx_dma_buffer(info,buf,count); - } - } else { - while (1) { - spin_lock_irqsave(&info->irq_spinlock,flags); - c = min_t(int, count, - min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) { - spin_unlock_irqrestore(&info->irq_spinlock,flags); - break; - } - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = ((info->xmit_head + c) & - (SERIAL_XMIT_SIZE-1)); - info->xmit_cnt += c; - spin_unlock_irqrestore(&info->irq_spinlock,flags); - buf += c; - count -= c; - ret += c; - } - } - - if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { - spin_lock_irqsave(&info->irq_spinlock,flags); - if (!info->tx_active) - usc_start_transmitter(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } -cleanup: - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_write(%s) returning=%d\n", - __FILE__,__LINE__,info->device_name,ret); - - return ret; - -} /* end of mgsl_write() */ - -/* mgsl_write_room() - * - * Return the count of free bytes in transmit buffer - * - * Arguments: tty pointer to tty info structure - * Return Value: None - */ -static int mgsl_write_room(struct tty_struct *tty) -{ - struct mgsl_struct *info = tty->driver_data; - int ret; - - if (mgsl_paranoia_check(info, tty->name, "mgsl_write_room")) - return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_write_room(%s)=%d\n", - __FILE__,__LINE__, info->device_name,ret ); - - if ( info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW ) { - /* operating in synchronous (frame oriented) mode */ - if ( info->tx_active ) - return 0; - else - return HDLC_MAX_FRAME_SIZE; - } - - return ret; - -} /* end of mgsl_write_room() */ - -/* mgsl_chars_in_buffer() - * - * Return the count of bytes in transmit buffer - * - * Arguments: tty pointer to tty info structure - * Return Value: None - */ -static int mgsl_chars_in_buffer(struct tty_struct *tty) -{ - struct mgsl_struct *info = tty->driver_data; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_chars_in_buffer(%s)\n", - __FILE__,__LINE__, info->device_name ); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_chars_in_buffer")) - return 0; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_chars_in_buffer(%s)=%d\n", - __FILE__,__LINE__, info->device_name,info->xmit_cnt ); - - if ( info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW ) { - /* operating in synchronous (frame oriented) mode */ - if ( info->tx_active ) - return info->max_frame_size; - else - return 0; - } - - return info->xmit_cnt; -} /* end of mgsl_chars_in_buffer() */ - -/* mgsl_flush_buffer() - * - * Discard all data in the send buffer - * - * Arguments: tty pointer to tty info structure - * Return Value: None - */ -static void mgsl_flush_buffer(struct tty_struct *tty) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_flush_buffer(%s) entry\n", - __FILE__,__LINE__, info->device_name ); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_flush_buffer")) - return; - - spin_lock_irqsave(&info->irq_spinlock,flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - del_timer(&info->tx_timer); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - tty_wakeup(tty); -} - -/* mgsl_send_xchar() - * - * Send a high-priority XON/XOFF character - * - * Arguments: tty pointer to tty info structure - * ch character to send - * Return Value: None - */ -static void mgsl_send_xchar(struct tty_struct *tty, char ch) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_send_xchar(%s,%d)\n", - __FILE__,__LINE__, info->device_name, ch ); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_send_xchar")) - return; - - info->x_char = ch; - if (ch) { - /* Make sure transmit interrupts are on */ - spin_lock_irqsave(&info->irq_spinlock,flags); - if (!info->tx_enabled) - usc_start_transmitter(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } -} /* end of mgsl_send_xchar() */ - -/* mgsl_throttle() - * - * Signal remote device to throttle send data (our receive data) - * - * Arguments: tty pointer to tty info structure - * Return Value: None - */ -static void mgsl_throttle(struct tty_struct * tty) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_throttle(%s) entry\n", - __FILE__,__LINE__, info->device_name ); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_throttle")) - return; - - if (I_IXOFF(tty)) - mgsl_send_xchar(tty, STOP_CHAR(tty)); - - if (C_CRTSCTS(tty)) { - spin_lock_irqsave(&info->irq_spinlock,flags); - info->serial_signals &= ~SerialSignal_RTS; - usc_set_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } -} /* end of mgsl_throttle() */ - -/* mgsl_unthrottle() - * - * Signal remote device to stop throttling send data (our receive data) - * - * Arguments: tty pointer to tty info structure - * Return Value: None - */ -static void mgsl_unthrottle(struct tty_struct * tty) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_unthrottle(%s) entry\n", - __FILE__,__LINE__, info->device_name ); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - mgsl_send_xchar(tty, START_CHAR(tty)); - } - - if (C_CRTSCTS(tty)) { - spin_lock_irqsave(&info->irq_spinlock,flags); - info->serial_signals |= SerialSignal_RTS; - usc_set_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } - -} /* end of mgsl_unthrottle() */ - -/* mgsl_get_stats() - * - * get the current serial parameters information - * - * Arguments: info pointer to device instance data - * user_icount pointer to buffer to hold returned stats - * - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount __user *user_icount) -{ - int err; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_get_params(%s)\n", - __FILE__,__LINE__, info->device_name); - - if (!user_icount) { - memset(&info->icount, 0, sizeof(info->icount)); - } else { - mutex_lock(&info->port.mutex); - COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); - mutex_unlock(&info->port.mutex); - if (err) - return -EFAULT; - } - - return 0; - -} /* end of mgsl_get_stats() */ - -/* mgsl_get_params() - * - * get the current serial parameters information - * - * Arguments: info pointer to device instance data - * user_params pointer to buffer to hold returned params - * - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS __user *user_params) -{ - int err; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_get_params(%s)\n", - __FILE__,__LINE__, info->device_name); - - mutex_lock(&info->port.mutex); - COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); - mutex_unlock(&info->port.mutex); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_get_params(%s) user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; - } - - return 0; - -} /* end of mgsl_get_params() */ - -/* mgsl_set_params() - * - * set the serial parameters - * - * Arguments: - * - * info pointer to device instance data - * new_params user buffer containing new serial params - * - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS __user *new_params) -{ - unsigned long flags; - MGSL_PARAMS tmp_params; - int err; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_set_params %s\n", __FILE__,__LINE__, - info->device_name ); - COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_set_params(%s) user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; - } - - mutex_lock(&info->port.mutex); - spin_lock_irqsave(&info->irq_spinlock,flags); - memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - mgsl_change_params(info); - mutex_unlock(&info->port.mutex); - - return 0; - -} /* end of mgsl_set_params() */ - -/* mgsl_get_txidle() - * - * get the current transmit idle mode - * - * Arguments: info pointer to device instance data - * idle_mode pointer to buffer to hold returned idle mode - * - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_get_txidle(struct mgsl_struct * info, int __user *idle_mode) -{ - int err; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_get_txidle(%s)=%d\n", - __FILE__,__LINE__, info->device_name, info->idle_mode); - - COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_get_txidle(%s) user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; - } - - return 0; - -} /* end of mgsl_get_txidle() */ - -/* mgsl_set_txidle() service ioctl to set transmit idle mode - * - * Arguments: info pointer to device instance data - * idle_mode new idle mode - * - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_set_txidle(%s,%d)\n", __FILE__,__LINE__, - info->device_name, idle_mode ); - - spin_lock_irqsave(&info->irq_spinlock,flags); - info->idle_mode = idle_mode; - usc_set_txidle( info ); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - return 0; - -} /* end of mgsl_set_txidle() */ - -/* mgsl_txenable() - * - * enable or disable the transmitter - * - * Arguments: - * - * info pointer to device instance data - * enable 1 = enable, 0 = disable - * - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_txenable(struct mgsl_struct * info, int enable) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_txenable(%s,%d)\n", __FILE__,__LINE__, - info->device_name, enable); - - spin_lock_irqsave(&info->irq_spinlock,flags); - if ( enable ) { - if ( !info->tx_enabled ) { - - usc_start_transmitter(info); - /*-------------------------------------------------- - * if HDLC/SDLC Loop mode, attempt to insert the - * station in the 'loop' by setting CMR:13. Upon - * receipt of the next GoAhead (RxAbort) sequence, - * the OnLoop indicator (CCSR:7) should go active - * to indicate that we are on the loop - *--------------------------------------------------*/ - if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) - usc_loopmode_insert_request( info ); - } - } else { - if ( info->tx_enabled ) - usc_stop_transmitter(info); - } - spin_unlock_irqrestore(&info->irq_spinlock,flags); - return 0; - -} /* end of mgsl_txenable() */ - -/* mgsl_txabort() abort send HDLC frame - * - * Arguments: info pointer to device instance data - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_txabort(struct mgsl_struct * info) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_txabort(%s)\n", __FILE__,__LINE__, - info->device_name); - - spin_lock_irqsave(&info->irq_spinlock,flags); - if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC ) - { - if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) - usc_loopmode_cancel_transmit( info ); - else - usc_TCmd(info,TCmd_SendAbort); - } - spin_unlock_irqrestore(&info->irq_spinlock,flags); - return 0; - -} /* end of mgsl_txabort() */ - -/* mgsl_rxenable() enable or disable the receiver - * - * Arguments: info pointer to device instance data - * enable 1 = enable, 0 = disable - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_rxenable(struct mgsl_struct * info, int enable) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_rxenable(%s,%d)\n", __FILE__,__LINE__, - info->device_name, enable); - - spin_lock_irqsave(&info->irq_spinlock,flags); - if ( enable ) { - if ( !info->rx_enabled ) - usc_start_receiver(info); - } else { - if ( info->rx_enabled ) - usc_stop_receiver(info); - } - spin_unlock_irqrestore(&info->irq_spinlock,flags); - return 0; - -} /* end of mgsl_rxenable() */ - -/* mgsl_wait_event() wait for specified event to occur - * - * Arguments: info pointer to device instance data - * mask pointer to bitmask of events to wait for - * Return Value: 0 if successful and bit mask updated with - * of events triggerred, - * otherwise error code - */ -static int mgsl_wait_event(struct mgsl_struct * 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); - - COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); - if (rc) { - return -EFAULT; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_wait_event(%s,%d)\n", __FILE__,__LINE__, - info->device_name, mask); - - spin_lock_irqsave(&info->irq_spinlock,flags); - - /* return immediately if state matches requested events */ - usc_get_serial_signals(info); - s = info->serial_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->irq_spinlock,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)) { - u16 oldreg = usc_InReg(info,RICR); - u16 newreg = oldreg + - (mask & MgslEvent_ExitHuntMode ? RXSTATUS_EXITED_HUNT:0) + - (mask & MgslEvent_IdleReceived ? RXSTATUS_IDLE_RECEIVED:0); - if (oldreg != newreg) - usc_OutReg(info, RICR, newreg); - } - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&info->event_wait_q, &wait); - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - - for(;;) { - schedule(); - if (signal_pending(current)) { - rc = -ERESTARTSYS; - break; - } - - /* get current irq counts */ - spin_lock_irqsave(&info->irq_spinlock,flags); - cnow = info->icount; - newsigs = info->input_signal_events; - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&info->irq_spinlock,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->irq_spinlock,flags); - if (!waitqueue_active(&info->event_wait_q)) { - /* disable enable exit hunt mode/idle rcvd IRQs */ - usc_OutReg(info, RICR, usc_InReg(info,RICR) & - ~(RXSTATUS_EXITED_HUNT | RXSTATUS_IDLE_RECEIVED)); - } - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } -exit: - if ( rc == 0 ) - PUT_USER(rc, events, mask_ptr); - - return rc; - -} /* end of mgsl_wait_event() */ - -static int modem_input_wait(struct mgsl_struct *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->irq_spinlock,flags); - cprev = info->icount; - add_wait_queue(&info->status_event_wait_q, &wait); - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - for(;;) { - schedule(); - if (signal_pending(current)) { - rc = -ERESTARTSYS; - break; - } - - /* get new irq counts */ - spin_lock_irqsave(&info->irq_spinlock,flags); - cnow = info->icount; - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&info->irq_spinlock,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 the state of the serial control and status signals - */ -static int tiocmget(struct tty_struct *tty) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned int result; - unsigned long flags; - - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_get_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) + - ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) + - ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) + - ((info->serial_signals & SerialSignal_RI) ? TIOCM_RNG:0) + - ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) + - ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0); - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s tiocmget() value=%08X\n", - __FILE__,__LINE__, info->device_name, result ); - return result; -} - -/* set modem control signals (DTR/RTS) - */ -static int tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s tiocmset(%x,%x)\n", - __FILE__,__LINE__,info->device_name, set, clear); - - if (set & TIOCM_RTS) - info->serial_signals |= SerialSignal_RTS; - if (set & TIOCM_DTR) - info->serial_signals |= SerialSignal_DTR; - if (clear & TIOCM_RTS) - info->serial_signals &= ~SerialSignal_RTS; - if (clear & TIOCM_DTR) - info->serial_signals &= ~SerialSignal_DTR; - - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_set_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - return 0; -} - -/* mgsl_break() Set or clear transmit break condition - * - * Arguments: tty pointer to tty instance data - * break_state -1=set break condition, 0=clear - * Return Value: error code - */ -static int mgsl_break(struct tty_struct *tty, int break_state) -{ - struct mgsl_struct * info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_break(%s,%d)\n", - __FILE__,__LINE__, info->device_name, break_state); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_break")) - return -EINVAL; - - spin_lock_irqsave(&info->irq_spinlock,flags); - if (break_state == -1) - usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) | BIT7)); - else - usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) & ~BIT7)); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - return 0; - -} /* end of mgsl_break() */ - -/* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ -static int msgl_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) - -{ - struct mgsl_struct * info = tty->driver_data; - struct mgsl_icount cnow; /* kernel counter temps */ - unsigned long flags; - - spin_lock_irqsave(&info->irq_spinlock,flags); - cnow = info->icount; - spin_unlock_irqrestore(&info->irq_spinlock,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; -} - -/* mgsl_ioctl() Service an IOCTL request - * - * Arguments: - * - * tty pointer to tty instance data - * cmd IOCTL command code - * arg command argument/context - * - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct mgsl_struct * info = tty->driver_data; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__, - info->device_name, cmd ); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_ioctl")) - return -ENODEV; - - if (cmd != TIOCMIWAIT) { - if (tty_io_error(tty)) - return -EIO; - } - - return mgsl_ioctl_common(info, cmd, arg); -} - -static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - - switch (cmd) { - case MGSL_IOCGPARAMS: - return mgsl_get_params(info, argp); - case MGSL_IOCSPARAMS: - return mgsl_set_params(info, argp); - case MGSL_IOCGTXIDLE: - return mgsl_get_txidle(info, argp); - case MGSL_IOCSTXIDLE: - return mgsl_set_txidle(info,(int)arg); - case MGSL_IOCTXENABLE: - return mgsl_txenable(info,(int)arg); - case MGSL_IOCRXENABLE: - return mgsl_rxenable(info,(int)arg); - case MGSL_IOCTXABORT: - return mgsl_txabort(info); - case MGSL_IOCGSTATS: - return mgsl_get_stats(info, argp); - case MGSL_IOCWAITEVENT: - return mgsl_wait_event(info, argp); - case MGSL_IOCLOOPTXDONE: - return mgsl_loopmode_send_done(info); - /* Wait for modem input (DCD,RI,DSR,CTS) change - * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS) - */ - case TIOCMIWAIT: - return modem_input_wait(info,(int)arg); - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -/* mgsl_set_termios() - * - * Set new termios settings - * - * Arguments: - * - * tty pointer to tty structure - * termios pointer to buffer to hold returned old termios - * - * Return Value: None - */ -static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_set_termios %s\n", __FILE__,__LINE__, - tty->driver->name ); - - mgsl_change_params(info); - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_set_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { - info->serial_signals |= SerialSignal_DTR; - if (!C_CRTSCTS(tty) || !tty_throttled(tty)) - info->serial_signals |= SerialSignal_RTS; - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_set_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } - - /* Handle turning off CRTSCTS */ - if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; - mgsl_start(tty); - } - -} /* end of mgsl_set_termios() */ - -/* mgsl_close() - * - * Called when port is closed. Wait for remaining data to be - * sent. Disable port and free resources. - * - * Arguments: - * - * tty pointer to open tty structure - * filp pointer to open file object - * - * Return Value: None - */ -static void mgsl_close(struct tty_struct *tty, struct file * filp) -{ - struct mgsl_struct * info = tty->driver_data; - - if (mgsl_paranoia_check(info, tty->name, "mgsl_close")) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_close(%s) entry, count=%d\n", - __FILE__,__LINE__, 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)) - mgsl_wait_until_sent(tty, info->timeout); - mgsl_flush_buffer(tty); - tty_ldisc_flush(tty); - shutdown(info); - mutex_unlock(&info->port.mutex); - - tty_port_close_end(&info->port, tty); - info->port.tty = NULL; -cleanup: - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_close(%s) exit, count=%d\n", __FILE__,__LINE__, - tty->driver->name, info->port.count); - -} /* end of mgsl_close() */ - -/* mgsl_wait_until_sent() - * - * Wait until the transmitter is empty. - * - * Arguments: - * - * tty pointer to tty info structure - * timeout time to wait for send completion - * - * Return Value: None - */ -static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct mgsl_struct * info = tty->driver_data; - unsigned long orig_jiffies, char_time; - - if (!info ) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_wait_until_sent(%s) entry\n", - __FILE__,__LINE__, info->device_name ); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_wait_until_sent")) - return; - - 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); - - if ( info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW ) { - 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; - } - } else { - while (!(usc_InReg(info,TCSR) & TXSTATUS_ALL_SENT) && - info->tx_enabled) { - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - } - -exit: - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_wait_until_sent(%s) exit\n", - __FILE__,__LINE__, info->device_name ); - -} /* end of mgsl_wait_until_sent() */ - -/* mgsl_hangup() - * - * Called by tty_hangup() when a hangup is signaled. - * This is the same as to closing all open files for the port. - * - * Arguments: tty pointer to associated tty object - * Return Value: None - */ -static void mgsl_hangup(struct tty_struct *tty) -{ - struct mgsl_struct * info = tty->driver_data; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_hangup(%s)\n", - __FILE__,__LINE__, info->device_name ); - - if (mgsl_paranoia_check(info, tty->name, "mgsl_hangup")) - return; - - mgsl_flush_buffer(tty); - shutdown(info); - - info->port.count = 0; - tty_port_set_active(&info->port, 0); - info->port.tty = NULL; - - wake_up_interruptible(&info->port.open_wait); - -} /* end of mgsl_hangup() */ - -/* - * carrier_raised() - * - * Return true if carrier is raised - */ - -static int carrier_raised(struct tty_port *port) -{ - unsigned long flags; - struct mgsl_struct *info = container_of(port, struct mgsl_struct, port); - - spin_lock_irqsave(&info->irq_spinlock, flags); - usc_get_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock, flags); - return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; -} - -static void dtr_rts(struct tty_port *port, int on) -{ - struct mgsl_struct *info = container_of(port, struct mgsl_struct, port); - unsigned long flags; - - spin_lock_irqsave(&info->irq_spinlock,flags); - if (on) - info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; - else - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - usc_set_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); -} - - -/* block_til_ready() - * - * Block the current process until the specified port - * is ready to be opened. - * - * Arguments: - * - * tty pointer to tty info structure - * filp pointer to open file object - * info pointer to device instance data - * - * Return Value: 0 if success, otherwise error code - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct mgsl_struct *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - bool do_clocal = false; - unsigned long flags; - int dcd; - struct tty_port *port = &info->port; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):block_til_ready on %s\n", - __FILE__,__LINE__, 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, 1); - 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 - * mgsl_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - - retval = 0; - add_wait_queue(&port->open_wait, &wait); - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):block_til_ready before block on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); - - spin_lock_irqsave(&info->irq_spinlock, flags); - port->count--; - spin_unlock_irqrestore(&info->irq_spinlock, 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; - } - - dcd = tty_port_carrier_raised(&info->port); - if (do_clocal || dcd) - break; - - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):block_til_ready blocking on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); - - tty_unlock(tty); - schedule(); - tty_lock(tty); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); - - /* FIXME: Racy on hangup during close wait */ - if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):block_til_ready after blocking on %s count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); - - if (!retval) - tty_port_set_active(port, 1); - - return retval; - -} /* end of block_til_ready() */ - -static int mgsl_install(struct tty_driver *driver, struct tty_struct *tty) -{ - struct mgsl_struct *info; - int line = tty->index; - - /* verify range of specified line number */ - if (line >= mgsl_device_count) { - printk("%s(%d):mgsl_open with invalid line #%d.\n", - __FILE__, __LINE__, line); - return -ENODEV; - } - - /* find the info structure for the specified line */ - info = mgsl_device_list; - while (info && info->line != line) - info = info->next_device; - if (mgsl_paranoia_check(info, tty->name, "mgsl_open")) - return -ENODEV; - tty->driver_data = info; - - return tty_port_install(&info->port, driver, tty); -} - -/* mgsl_open() - * - * Called when a port is opened. Init and enable port. - * Perform serial-specific initialization for the tty structure. - * - * Arguments: tty pointer to tty info structure - * filp associated file pointer - * - * Return Value: 0 if success, otherwise error code - */ -static int mgsl_open(struct tty_struct *tty, struct file * filp) -{ - struct mgsl_struct *info = tty->driver_data; - unsigned long flags; - int retval; - - info->port.tty = tty; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_open(%s), old ref count = %d\n", - __FILE__,__LINE__,tty->driver->name, info->port.count); - - info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - spin_lock_irqsave(&info->netlock, flags); - if (info->netcount) { - retval = -EBUSY; - spin_unlock_irqrestore(&info->netlock, flags); - 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(info); - if (retval < 0) - goto cleanup; - } - - retval = block_til_ready(tty, filp, info); - if (retval) { - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):block_til_ready(%s) returned %d\n", - __FILE__,__LINE__, info->device_name, retval); - goto cleanup; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgsl_open(%s) success\n", - __FILE__,__LINE__, info->device_name); - 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--; - } - - return retval; - -} /* end of mgsl_open() */ - -/* - * /proc fs routines.... - */ - -static inline void line_info(struct seq_file *m, struct mgsl_struct *info) -{ - char stat_buf[30]; - unsigned long flags; - - seq_printf(m, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X", - info->device_name, info->io_base, info->irq_level, - info->phys_memory_base, info->phys_lcr_base); - - /* output current serial signal states */ - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_get_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (info->serial_signals & SerialSignal_RTS) - strcat(stat_buf, "|RTS"); - if (info->serial_signals & SerialSignal_CTS) - strcat(stat_buf, "|CTS"); - if (info->serial_signals & SerialSignal_DTR) - strcat(stat_buf, "|DTR"); - if (info->serial_signals & SerialSignal_DSR) - strcat(stat_buf, "|DSR"); - if (info->serial_signals & SerialSignal_DCD) - strcat(stat_buf, "|CD"); - if (info->serial_signals & SerialSignal_RI) - strcat(stat_buf, "|RI"); - - if (info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW ) { - seq_printf(m, " HDLC 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, " ASYNC 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, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", - info->tx_active,info->bh_requested,info->bh_running, - info->pending_bh); - - spin_lock_irqsave(&info->irq_spinlock,flags); - { - u16 Tcsr = usc_InReg( info, TCSR ); - u16 Tdmr = usc_InDmaReg( info, TDMR ); - u16 Ticr = usc_InReg( info, TICR ); - u16 Rscr = usc_InReg( info, RCSR ); - u16 Rdmr = usc_InDmaReg( info, RDMR ); - u16 Ricr = usc_InReg( info, RICR ); - u16 Icr = usc_InReg( info, ICR ); - u16 Dccr = usc_InReg( info, DCCR ); - u16 Tmr = usc_InReg( info, TMR ); - u16 Tccr = usc_InReg( info, TCCR ); - u16 Ccar = inw( info->io_base + CCAR ); - seq_printf(m, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04X\n" - "ricr=%04X icr =%04X dccr=%04X tmr=%04X tccr=%04X ccar=%04X\n", - Tcsr,Tdmr,Ticr,Rscr,Rdmr,Ricr,Icr,Dccr,Tmr,Tccr,Ccar ); - } - spin_unlock_irqrestore(&info->irq_spinlock,flags); -} - -/* Called to print information about devices */ -static int mgsl_proc_show(struct seq_file *m, void *v) -{ - struct mgsl_struct *info; - - seq_printf(m, "synclink driver:%s\n", driver_version); - - info = mgsl_device_list; - while( info ) { - line_info(m, info); - info = info->next_device; - } - return 0; -} - -/* mgsl_allocate_dma_buffers() - * - * Allocate and format DMA buffers (ISA adapter) - * or format shared memory buffers (PCI adapter). - * - * Arguments: info pointer to device instance data - * Return Value: 0 if success, otherwise error - */ -static int mgsl_allocate_dma_buffers(struct mgsl_struct *info) -{ - unsigned short BuffersPerFrame; - - info->last_mem_alloc = 0; - - /* Calculate the number of DMA buffers necessary to hold the */ - /* largest allowable frame size. Note: If the max frame size is */ - /* not an even multiple of the DMA buffer size then we need to */ - /* round the buffer count per frame up one. */ - - BuffersPerFrame = (unsigned short)(info->max_frame_size/DMABUFFERSIZE); - if ( info->max_frame_size % DMABUFFERSIZE ) - BuffersPerFrame++; - - /* - * The PCI adapter has 256KBytes of shared memory to use. This is 64 - * PAGE_SIZE buffers. - * - * The first page is used for padding at this time so the buffer list - * does not begin at offset 0 of the PCI adapter's shared memory. - * - * The 2nd page is used for the buffer list. A 4K buffer list can hold - * 128 DMA_BUFFER structures at 32 bytes each. - * - * This leaves 62 4K pages. - * - * The next N pages are used for transmit frame(s). We reserve enough - * 4K page blocks to hold the required number of transmit dma buffers - * (num_tx_dma_buffers), each of MaxFrameSize size. - * - * Of the remaining pages (62-N), determine how many can be used to - * receive full MaxFrameSize inbound frames - */ - info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame; - info->rx_buffer_count = 62 - info->tx_buffer_count; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("%s(%d):Allocating %d TX and %d RX DMA buffers.\n", - __FILE__,__LINE__, info->tx_buffer_count,info->rx_buffer_count); - - if ( mgsl_alloc_buffer_list_memory( info ) < 0 || - mgsl_alloc_frame_memory(info, info->rx_buffer_list, info->rx_buffer_count) < 0 || - mgsl_alloc_frame_memory(info, info->tx_buffer_list, info->tx_buffer_count) < 0 || - mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 || - mgsl_alloc_intermediate_txbuffer_memory(info) < 0 ) { - printk("%s(%d):Can't allocate DMA buffer memory\n",__FILE__,__LINE__); - return -ENOMEM; - } - - mgsl_reset_rx_dma_buffers( info ); - mgsl_reset_tx_dma_buffers( info ); - - return 0; - -} /* end of mgsl_allocate_dma_buffers() */ - -/* - * mgsl_alloc_buffer_list_memory() - * - * Allocate a common DMA buffer for use as the - * receive and transmit buffer lists. - * - * A buffer list is a set of buffer entries where each entry contains - * a pointer to an actual buffer and a pointer to the next buffer entry - * (plus some other info about the buffer). - * - * The buffer entries for a list are built to form a circular list so - * that when the entire list has been traversed you start back at the - * beginning. - * - * This function allocates memory for just the buffer entries. - * The links (pointer to next entry) are filled in with the physical - * address of the next entry so the adapter can navigate the list - * using bus master DMA. The pointers to the actual buffers are filled - * out later when the actual buffers are allocated. - * - * Arguments: info pointer to device instance data - * Return Value: 0 if success, otherwise error - */ -static int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info ) -{ - unsigned int i; - - /* PCI adapter uses shared memory. */ - info->buffer_list = info->memory_base + info->last_mem_alloc; - info->buffer_list_phys = info->last_mem_alloc; - info->last_mem_alloc += BUFFERLISTSIZE; - - /* We got the memory for the buffer entry lists. */ - /* Initialize the memory block to all zeros. */ - memset( info->buffer_list, 0, BUFFERLISTSIZE ); - - /* Save virtual address pointers to the receive and */ - /* transmit buffer lists. (Receive 1st). These pointers will */ - /* be used by the processor to access the lists. */ - info->rx_buffer_list = (DMABUFFERENTRY *)info->buffer_list; - info->tx_buffer_list = (DMABUFFERENTRY *)info->buffer_list; - info->tx_buffer_list += info->rx_buffer_count; - - /* - * Build the links for the buffer entry lists such that - * two circular lists are built. (Transmit and Receive). - * - * Note: the links are physical addresses - * which are read by the adapter to determine the next - * buffer entry to use. - */ - - for ( i = 0; i < info->rx_buffer_count; i++ ) { - /* calculate and store physical address of this buffer entry */ - info->rx_buffer_list[i].phys_entry = - info->buffer_list_phys + (i * sizeof(DMABUFFERENTRY)); - - /* calculate and store physical address of */ - /* next entry in cirular list of entries */ - - info->rx_buffer_list[i].link = info->buffer_list_phys; - - if ( i < info->rx_buffer_count - 1 ) - info->rx_buffer_list[i].link += (i + 1) * sizeof(DMABUFFERENTRY); - } - - for ( i = 0; i < info->tx_buffer_count; i++ ) { - /* calculate and store physical address of this buffer entry */ - info->tx_buffer_list[i].phys_entry = info->buffer_list_phys + - ((info->rx_buffer_count + i) * sizeof(DMABUFFERENTRY)); - - /* calculate and store physical address of */ - /* next entry in cirular list of entries */ - - info->tx_buffer_list[i].link = info->buffer_list_phys + - info->rx_buffer_count * sizeof(DMABUFFERENTRY); - - if ( i < info->tx_buffer_count - 1 ) - info->tx_buffer_list[i].link += (i + 1) * sizeof(DMABUFFERENTRY); - } - - return 0; - -} /* end of mgsl_alloc_buffer_list_memory() */ - -/* Free DMA buffers allocated for use as the - * receive and transmit buffer lists. - * Warning: - * - * The data transfer buffers associated with the buffer list - * MUST be freed before freeing the buffer list itself because - * the buffer list contains the information necessary to free - * the individual buffers! - */ -static void mgsl_free_buffer_list_memory( struct mgsl_struct *info ) -{ - info->buffer_list = NULL; - info->rx_buffer_list = NULL; - info->tx_buffer_list = NULL; - -} /* end of mgsl_free_buffer_list_memory() */ - -/* - * mgsl_alloc_frame_memory() - * - * Allocate the frame DMA buffers used by the specified buffer list. - * Each DMA buffer will be one memory page in size. This is necessary - * because memory can fragment enough that it may be impossible - * contiguous pages. - * - * Arguments: - * - * info pointer to device instance data - * BufferList pointer to list of buffer entries - * Buffercount count of buffer entries in buffer list - * - * Return Value: 0 if success, otherwise -ENOMEM - */ -static int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount) -{ - int i; - - /* Allocate page sized buffers for the receive buffer list */ - - for ( i = 0; i < Buffercount; i++ ) { - BufferList[i].virt_addr = info->memory_base + info->last_mem_alloc; - BufferList[i].phys_addr = info->last_mem_alloc; - info->last_mem_alloc += DMABUFFERSIZE; - } - - return 0; - -} /* end of mgsl_alloc_frame_memory() */ - -/* - * mgsl_free_frame_memory() - * - * Free the buffers associated with - * each buffer entry of a buffer list. - * - * Arguments: - * - * info pointer to device instance data - * BufferList pointer to list of buffer entries - * Buffercount count of buffer entries in buffer list - * - * Return Value: None - */ -static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList, int Buffercount) -{ - int i; - - if ( BufferList ) { - for ( i = 0 ; i < Buffercount ; i++ ) { - if ( BufferList[i].virt_addr ) { - BufferList[i].virt_addr = NULL; - } - } - } - -} /* end of mgsl_free_frame_memory() */ - -/* mgsl_free_dma_buffers() - * - * Free DMA buffers - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_free_dma_buffers( struct mgsl_struct *info ) -{ - mgsl_free_frame_memory( info, info->rx_buffer_list, info->rx_buffer_count ); - mgsl_free_frame_memory( info, info->tx_buffer_list, info->tx_buffer_count ); - mgsl_free_buffer_list_memory( info ); - -} /* end of mgsl_free_dma_buffers() */ - - -/* - * mgsl_alloc_intermediate_rxbuffer_memory() - * - * Allocate a buffer large enough to hold max_frame_size. This buffer - * is used to pass an assembled frame to the line discipline. - * - * Arguments: - * - * info pointer to device instance data - * - * Return Value: 0 if success, otherwise -ENOMEM - */ -static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info) -{ - info->intermediate_rxbuffer = kmalloc(info->max_frame_size, GFP_KERNEL | GFP_DMA); - if ( info->intermediate_rxbuffer == NULL ) - return -ENOMEM; - /* unused flag buffer to satisfy receive_buf calling interface */ - info->flag_buf = kzalloc(info->max_frame_size, GFP_KERNEL); - if (!info->flag_buf) { - kfree(info->intermediate_rxbuffer); - info->intermediate_rxbuffer = NULL; - return -ENOMEM; - } - return 0; - -} /* end of mgsl_alloc_intermediate_rxbuffer_memory() */ - -/* - * mgsl_free_intermediate_rxbuffer_memory() - * - * - * Arguments: - * - * info pointer to device instance data - * - * Return Value: None - */ -static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info) -{ - kfree(info->intermediate_rxbuffer); - info->intermediate_rxbuffer = NULL; - kfree(info->flag_buf); - info->flag_buf = NULL; - -} /* end of mgsl_free_intermediate_rxbuffer_memory() */ - -/* - * mgsl_alloc_intermediate_txbuffer_memory() - * - * Allocate intermdiate transmit buffer(s) large enough to hold max_frame_size. - * This buffer is used to load transmit frames into the adapter's dma transfer - * buffers when there is sufficient space. - * - * Arguments: - * - * info pointer to device instance data - * - * Return Value: 0 if success, otherwise -ENOMEM - */ -static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) -{ - int i; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("%s %s(%d) allocating %d tx holding buffers\n", - info->device_name, __FILE__,__LINE__,info->num_tx_holding_buffers); - - memset(info->tx_holding_buffers,0,sizeof(info->tx_holding_buffers)); - - for ( i=0; i<info->num_tx_holding_buffers; ++i) { - info->tx_holding_buffers[i].buffer = - kmalloc(info->max_frame_size, GFP_KERNEL); - if (info->tx_holding_buffers[i].buffer == NULL) { - for (--i; i >= 0; i--) { - kfree(info->tx_holding_buffers[i].buffer); - info->tx_holding_buffers[i].buffer = NULL; - } - return -ENOMEM; - } - } - - return 0; - -} /* end of mgsl_alloc_intermediate_txbuffer_memory() */ - -/* - * mgsl_free_intermediate_txbuffer_memory() - * - * - * Arguments: - * - * info pointer to device instance data - * - * Return Value: None - */ -static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) -{ - int i; - - for ( i=0; i<info->num_tx_holding_buffers; ++i ) { - kfree(info->tx_holding_buffers[i].buffer); - info->tx_holding_buffers[i].buffer = NULL; - } - - info->get_tx_holding_index = 0; - info->put_tx_holding_index = 0; - info->tx_holding_count = 0; - -} /* end of mgsl_free_intermediate_txbuffer_memory() */ - - -/* - * load_next_tx_holding_buffer() - * - * attempts to load the next buffered tx request into the - * tx dma buffers - * - * Arguments: - * - * info pointer to device instance data - * - * Return Value: true if next buffered tx request loaded - * into adapter's tx dma buffer, - * false otherwise - */ -static bool load_next_tx_holding_buffer(struct mgsl_struct *info) -{ - bool ret = false; - - if ( info->tx_holding_count ) { - /* determine if we have enough tx dma buffers - * to accommodate the next tx frame - */ - struct tx_holding_buffer *ptx = - &info->tx_holding_buffers[info->get_tx_holding_index]; - int num_free = num_free_tx_dma_buffers(info); - int num_needed = ptx->buffer_size / DMABUFFERSIZE; - if ( ptx->buffer_size % DMABUFFERSIZE ) - ++num_needed; - - if (num_needed <= num_free) { - info->xmit_cnt = ptx->buffer_size; - mgsl_load_tx_dma_buffer(info,ptx->buffer,ptx->buffer_size); - - --info->tx_holding_count; - if ( ++info->get_tx_holding_index >= info->num_tx_holding_buffers) - info->get_tx_holding_index=0; - - /* restart transmit timer */ - mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); - - ret = true; - } - } - - return ret; -} - -/* - * save_tx_buffer_request() - * - * attempt to store transmit frame request for later transmission - * - * Arguments: - * - * info pointer to device instance data - * Buffer pointer to buffer containing frame to load - * BufferSize size in bytes of frame in Buffer - * - * Return Value: 1 if able to store, 0 otherwise - */ -static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize) -{ - struct tx_holding_buffer *ptx; - - if ( info->tx_holding_count >= info->num_tx_holding_buffers ) { - return 0; /* all buffers in use */ - } - - ptx = &info->tx_holding_buffers[info->put_tx_holding_index]; - ptx->buffer_size = BufferSize; - memcpy( ptx->buffer, Buffer, BufferSize); - - ++info->tx_holding_count; - if ( ++info->put_tx_holding_index >= info->num_tx_holding_buffers) - info->put_tx_holding_index=0; - - return 1; -} - -static int mgsl_claim_resources(struct mgsl_struct *info) -{ - if (request_region(info->io_base,info->io_addr_size,"synclink") == NULL) { - printk( "%s(%d):I/O address conflict on device %s Addr=%08X\n", - __FILE__,__LINE__,info->device_name, info->io_base); - return -ENODEV; - } - info->io_addr_requested = true; - - if ( request_irq(info->irq_level,mgsl_interrupt,info->irq_flags, - info->device_name, info ) < 0 ) { - printk( "%s(%d):Can't request interrupt on device %s IRQ=%d\n", - __FILE__,__LINE__,info->device_name, info->irq_level ); - goto errout; - } - info->irq_requested = true; - - if (request_mem_region(info->phys_memory_base,0x40000,"synclink") == NULL) { - printk( "%s(%d):mem addr conflict device %s Addr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_memory_base); - goto errout; - } - info->shared_mem_requested = true; - if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) { - printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset); - goto errout; - } - info->lcr_mem_requested = true; - - info->memory_base = ioremap(info->phys_memory_base, 0x40000); - if (!info->memory_base) { - printk( "%s(%d):Can't map shared memory on device %s MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_memory_base ); - goto errout; - } - - if ( !mgsl_memory_test(info) ) { - printk( "%s(%d):Failed shared memory test %s MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_memory_base ); - goto errout; - } - - info->lcr_base = ioremap(info->phys_lcr_base, PAGE_SIZE); - if (!info->lcr_base) { - printk( "%s(%d):Can't map LCR memory on device %s MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); - goto errout; - } - info->lcr_base += info->lcr_offset; - - if ( mgsl_allocate_dma_buffers(info) < 0 ) { - printk( "%s(%d):Can't allocate DMA buffers on device %s DMA=%d\n", - __FILE__,__LINE__,info->device_name, info->dma_level ); - goto errout; - } - - return 0; -errout: - mgsl_release_resources(info); - return -ENODEV; - -} /* end of mgsl_claim_resources() */ - -static void mgsl_release_resources(struct mgsl_struct *info) -{ - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_release_resources(%s) entry\n", - __FILE__,__LINE__,info->device_name ); - - if ( info->irq_requested ) { - free_irq(info->irq_level, info); - info->irq_requested = false; - } - if ( info->dma_requested ) { - disable_dma(info->dma_level); - free_dma(info->dma_level); - info->dma_requested = false; - } - mgsl_free_dma_buffers(info); - mgsl_free_intermediate_rxbuffer_memory(info); - mgsl_free_intermediate_txbuffer_memory(info); - - if ( info->io_addr_requested ) { - release_region(info->io_base,info->io_addr_size); - info->io_addr_requested = false; - } - if ( info->shared_mem_requested ) { - release_mem_region(info->phys_memory_base,0x40000); - info->shared_mem_requested = false; - } - if ( info->lcr_mem_requested ) { - release_mem_region(info->phys_lcr_base + info->lcr_offset,128); - info->lcr_mem_requested = false; - } - if (info->memory_base){ - iounmap(info->memory_base); - info->memory_base = NULL; - } - if (info->lcr_base){ - iounmap(info->lcr_base - info->lcr_offset); - info->lcr_base = NULL; - } - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_release_resources(%s) exit\n", - __FILE__,__LINE__,info->device_name ); - -} /* end of mgsl_release_resources() */ - -/* mgsl_add_device() - * - * Add the specified device instance data structure to the - * global linked list of devices and increment the device count. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_add_device( struct mgsl_struct *info ) -{ - info->next_device = NULL; - info->line = mgsl_device_count; - sprintf(info->device_name,"ttySL%d",info->line); - - if (info->line < MAX_TOTAL_DEVICES) { - if (maxframe[info->line]) - info->max_frame_size = maxframe[info->line]; - - if (txdmabufs[info->line]) { - info->num_tx_dma_buffers = txdmabufs[info->line]; - if (info->num_tx_dma_buffers < 1) - info->num_tx_dma_buffers = 1; - } - - if (txholdbufs[info->line]) { - info->num_tx_holding_buffers = txholdbufs[info->line]; - if (info->num_tx_holding_buffers < 1) - info->num_tx_holding_buffers = 1; - else if (info->num_tx_holding_buffers > MAX_TX_HOLDING_BUFFERS) - info->num_tx_holding_buffers = MAX_TX_HOLDING_BUFFERS; - } - } - - mgsl_device_count++; - - if ( !mgsl_device_list ) - mgsl_device_list = info; - else { - struct mgsl_struct *current_dev = mgsl_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; - - printk( "SyncLink PCI v%d %s: IO=%04X IRQ=%d Mem=%08X,%08X MaxFrameSize=%u\n", - info->hw_version + 1, info->device_name, info->io_base, info->irq_level, - info->phys_memory_base, info->phys_lcr_base, - info->max_frame_size ); - -#if SYNCLINK_GENERIC_HDLC - hdlcdev_init(info); -#endif - -} /* end of mgsl_add_device() */ - -static const struct tty_port_operations mgsl_port_ops = { - .carrier_raised = carrier_raised, - .dtr_rts = dtr_rts, -}; - - -/* mgsl_allocate_device() - * - * Allocate and initialize a device instance structure - * - * Arguments: none - * Return Value: pointer to mgsl_struct if success, otherwise NULL - */ -static struct mgsl_struct* mgsl_allocate_device(void) -{ - struct mgsl_struct *info; - - info = kzalloc(sizeof(struct mgsl_struct), - GFP_KERNEL); - - if (!info) { - printk("Error can't allocate device instance data\n"); - } else { - tty_port_init(&info->port); - info->port.ops = &mgsl_port_ops; - info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, mgsl_bh_handler); - info->max_frame_size = 4096; - info->port.close_delay = 5*HZ/10; - info->port.closing_wait = 30*HZ; - init_waitqueue_head(&info->status_event_wait_q); - init_waitqueue_head(&info->event_wait_q); - spin_lock_init(&info->irq_spinlock); - spin_lock_init(&info->netlock); - memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); - info->idle_mode = HDLC_TXIDLE_FLAGS; - info->num_tx_dma_buffers = 1; - info->num_tx_holding_buffers = 0; - } - - return info; - -} /* end of mgsl_allocate_device()*/ - -static const struct tty_operations mgsl_ops = { - .install = mgsl_install, - .open = mgsl_open, - .close = mgsl_close, - .write = mgsl_write, - .put_char = mgsl_put_char, - .flush_chars = mgsl_flush_chars, - .write_room = mgsl_write_room, - .chars_in_buffer = mgsl_chars_in_buffer, - .flush_buffer = mgsl_flush_buffer, - .ioctl = mgsl_ioctl, - .throttle = mgsl_throttle, - .unthrottle = mgsl_unthrottle, - .send_xchar = mgsl_send_xchar, - .break_ctl = mgsl_break, - .wait_until_sent = mgsl_wait_until_sent, - .set_termios = mgsl_set_termios, - .stop = mgsl_stop, - .start = mgsl_start, - .hangup = mgsl_hangup, - .tiocmget = tiocmget, - .tiocmset = tiocmset, - .get_icount = msgl_get_icount, - .proc_show = mgsl_proc_show, -}; - -/* - * perform tty device initialization - */ -static int mgsl_init_tty(void) -{ - int rc; - - serial_driver = alloc_tty_driver(128); - if (!serial_driver) - return -ENOMEM; - - serial_driver->driver_name = "synclink"; - serial_driver->name = "ttySL"; - 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; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &mgsl_ops); - if ((rc = tty_register_driver(serial_driver)) < 0) { - printk("%s(%d):Couldn't register serial driver\n", - __FILE__,__LINE__); - put_tty_driver(serial_driver); - serial_driver = NULL; - return rc; - } - - printk("%s %s, tty major#%d\n", - driver_name, driver_version, - serial_driver->major); - return 0; -} - -static void synclink_cleanup(void) -{ - int rc; - struct mgsl_struct *info; - struct mgsl_struct *tmp; - - printk("Unloading %s: %s\n", driver_name, driver_version); - - if (serial_driver) { - rc = tty_unregister_driver(serial_driver); - if (rc) - printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); - put_tty_driver(serial_driver); - } - - info = mgsl_device_list; - while(info) { -#if SYNCLINK_GENERIC_HDLC - hdlcdev_exit(info); -#endif - mgsl_release_resources(info); - tmp = info; - info = info->next_device; - tty_port_destroy(&tmp->port); - kfree(tmp); - } - - if (pci_registered) - pci_unregister_driver(&synclink_pci_driver); -} - -static int __init synclink_init(void) -{ - int rc; - - if (break_on_load) { - mgsl_get_text_ptr(); - BREAKPOINT(); - } - - printk("%s %s\n", driver_name, driver_version); - - if ((rc = pci_register_driver(&synclink_pci_driver)) < 0) - printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc); - else - pci_registered = true; - - if ((rc = mgsl_init_tty()) < 0) - goto error; - - return 0; - -error: - synclink_cleanup(); - return rc; -} - -static void __exit synclink_exit(void) -{ - synclink_cleanup(); -} - -module_init(synclink_init); -module_exit(synclink_exit); - -/* - * usc_RTCmd() - * - * Issue a USC Receive/Transmit command to the - * Channel Command/Address Register (CCAR). - * - * Notes: - * - * The command is encoded in the most significant 5 bits <15..11> - * of the CCAR value. Bits <10..7> of the CCAR must be preserved - * and Bits <6..0> must be written as zeros. - * - * Arguments: - * - * info pointer to device information structure - * Cmd command mask (use symbolic macros) - * - * Return Value: - * - * None - */ -static void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ) -{ - /* output command to CCAR in bits <15..11> */ - /* preserve bits <10..7>, bits <6..0> must be zero */ - - outw( Cmd + info->loopback_bits, info->io_base + CCAR ); - - /* Read to flush write to CCAR */ - inw( info->io_base + CCAR ); - -} /* end of usc_RTCmd() */ - -/* - * usc_DmaCmd() - * - * Issue a DMA command to the DMA Command/Address Register (DCAR). - * - * Arguments: - * - * info pointer to device information structure - * Cmd DMA command mask (usc_DmaCmd_XX Macros) - * - * Return Value: - * - * None - */ -static void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ) -{ - /* write command mask to DCAR */ - outw( Cmd + info->mbre_bit, info->io_base ); - - /* Read to flush write to DCAR */ - inw( info->io_base ); - -} /* end of usc_DmaCmd() */ - -/* - * usc_OutDmaReg() - * - * Write a 16-bit value to a USC DMA register - * - * Arguments: - * - * info pointer to device info structure - * RegAddr register address (number) for write - * RegValue 16-bit value to write to register - * - * Return Value: - * - * None - * - */ -static void usc_OutDmaReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) -{ - /* Note: The DCAR is located at the adapter base address */ - /* Note: must preserve state of BIT8 in DCAR */ - - outw( RegAddr + info->mbre_bit, info->io_base ); - outw( RegValue, info->io_base ); - - /* Read to flush write to DCAR */ - inw( info->io_base ); - -} /* end of usc_OutDmaReg() */ - -/* - * usc_InDmaReg() - * - * Read a 16-bit value from a DMA register - * - * Arguments: - * - * info pointer to device info structure - * RegAddr register address (number) to read from - * - * Return Value: - * - * The 16-bit value read from register - * - */ -static u16 usc_InDmaReg( struct mgsl_struct *info, u16 RegAddr ) -{ - /* Note: The DCAR is located at the adapter base address */ - /* Note: must preserve state of BIT8 in DCAR */ - - outw( RegAddr + info->mbre_bit, info->io_base ); - return inw( info->io_base ); - -} /* end of usc_InDmaReg() */ - -/* - * - * usc_OutReg() - * - * Write a 16-bit value to a USC serial channel register - * - * Arguments: - * - * info pointer to device info structure - * RegAddr register address (number) to write to - * RegValue 16-bit value to write to register - * - * Return Value: - * - * None - * - */ -static void usc_OutReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) -{ - outw( RegAddr + info->loopback_bits, info->io_base + CCAR ); - outw( RegValue, info->io_base + CCAR ); - - /* Read to flush write to CCAR */ - inw( info->io_base + CCAR ); - -} /* end of usc_OutReg() */ - -/* - * usc_InReg() - * - * Reads a 16-bit value from a USC serial channel register - * - * Arguments: - * - * info pointer to device extension - * RegAddr register address (number) to read from - * - * Return Value: - * - * 16-bit value read from register - */ -static u16 usc_InReg( struct mgsl_struct *info, u16 RegAddr ) -{ - outw( RegAddr + info->loopback_bits, info->io_base + CCAR ); - return inw( info->io_base + CCAR ); - -} /* end of usc_InReg() */ - -/* usc_set_sdlc_mode() - * - * Set up the adapter for SDLC DMA communications. - * - * Arguments: info pointer to device instance data - * Return Value: NONE - */ -static void usc_set_sdlc_mode( struct mgsl_struct *info ) -{ - u16 RegValue; - bool PreSL1660; - - /* - * determine if the IUSC on the adapter is pre-SL1660. If - * not, take advantage of the UnderWait feature of more - * modern chips. If an underrun occurs and this bit is set, - * the transmitter will idle the programmed idle pattern - * until the driver has time to service the underrun. Otherwise, - * the dma controller may get the cycles previously requested - * and begin transmitting queued tx data. - */ - usc_OutReg(info,TMCR,0x1f); - RegValue=usc_InReg(info,TMDR); - PreSL1660 = (RegValue == IUSC_PRE_SL1660); - - if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) - { - /* - ** Channel Mode Register (CMR) - ** - ** <15..14> 10 Tx Sub Modes, Send Flag on Underrun - ** <13> 0 0 = Transmit Disabled (initially) - ** <12> 0 1 = Consecutive Idles share common 0 - ** <11..8> 1110 Transmitter Mode = HDLC/SDLC Loop - ** <7..4> 0000 Rx Sub Modes, addr/ctrl field handling - ** <3..0> 0110 Receiver Mode = HDLC/SDLC - ** - ** 1000 1110 0000 0110 = 0x8e06 - */ - RegValue = 0x8e06; - - /*-------------------------------------------------- - * ignore user options for UnderRun Actions and - * preambles - *--------------------------------------------------*/ - } - else - { - /* Channel mode Register (CMR) - * - * <15..14> 00 Tx Sub modes, Underrun Action - * <13> 0 1 = Send Preamble before opening flag - * <12> 0 1 = Consecutive Idles share common 0 - * <11..8> 0110 Transmitter mode = HDLC/SDLC - * <7..4> 0000 Rx Sub modes, addr/ctrl field handling - * <3..0> 0110 Receiver mode = HDLC/SDLC - * - * 0000 0110 0000 0110 = 0x0606 - */ - if (info->params.mode == MGSL_MODE_RAW) { - RegValue = 0x0001; /* Set Receive mode = external sync */ - - usc_OutReg( info, IOCR, /* Set IOCR DCD is RxSync Detect Input */ - (unsigned short)((usc_InReg(info, IOCR) & ~(BIT13|BIT12)) | BIT12)); - - /* - * TxSubMode: - * CMR <15> 0 Don't send CRC on Tx Underrun - * CMR <14> x undefined - * CMR <13> 0 Send preamble before openning sync - * CMR <12> 0 Send 8-bit syncs, 1=send Syncs per TxLength - * - * TxMode: - * CMR <11-8) 0100 MonoSync - * - * 0x00 0100 xxxx xxxx 04xx - */ - RegValue |= 0x0400; - } - else { - - RegValue = 0x0606; - - if ( info->params.flags & HDLC_FLAG_UNDERRUN_ABORT15 ) - RegValue |= BIT14; - else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG ) - RegValue |= BIT15; - else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC ) - RegValue |= BIT15 | BIT14; - } - - if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE ) - RegValue |= BIT13; - } - - if ( info->params.mode == MGSL_MODE_HDLC && - (info->params.flags & HDLC_FLAG_SHARE_ZERO) ) - RegValue |= BIT12; - - if ( info->params.addr_filter != 0xff ) - { - /* set up receive address filtering */ - usc_OutReg( info, RSR, info->params.addr_filter ); - RegValue |= BIT4; - } - - usc_OutReg( info, CMR, RegValue ); - info->cmr_value = RegValue; - - /* Receiver mode Register (RMR) - * - * <15..13> 000 encoding - * <12..11> 00 FCS = 16bit CRC CCITT (x15 + x12 + x5 + 1) - * <10> 1 1 = Set CRC to all 1s (use for SDLC/HDLC) - * <9> 0 1 = Include Receive chars in CRC - * <8> 1 1 = Use Abort/PE bit as abort indicator - * <7..6> 00 Even parity - * <5> 0 parity disabled - * <4..2> 000 Receive Char Length = 8 bits - * <1..0> 00 Disable Receiver - * - * 0000 0101 0000 0000 = 0x0500 - */ - - RegValue = 0x0500; - - switch ( info->params.encoding ) { - case HDLC_ENCODING_NRZB: RegValue |= BIT13; break; - case HDLC_ENCODING_NRZI_MARK: RegValue |= BIT14; break; - case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 | BIT13; break; - case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT15; break; - case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 | BIT13; break; - case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14; break; - case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14 | BIT13; break; - } - - if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) - RegValue |= BIT9; - else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) - RegValue |= ( BIT12 | BIT10 | BIT9 ); - - usc_OutReg( info, RMR, RegValue ); - - /* Set the Receive count Limit Register (RCLR) to 0xffff. */ - /* When an opening flag of an SDLC frame is recognized the */ - /* Receive Character count (RCC) is loaded with the value in */ - /* RCLR. The RCC is decremented for each received byte. The */ - /* value of RCC is stored after the closing flag of the frame */ - /* allowing the frame size to be computed. */ - - usc_OutReg( info, RCLR, RCLRVALUE ); - - usc_RCmd( info, RCmd_SelectRicrdma_level ); - - /* Receive Interrupt Control Register (RICR) - * - * <15..8> ? RxFIFO DMA Request Level - * <7> 0 Exited Hunt IA (Interrupt Arm) - * <6> 0 Idle Received IA - * <5> 0 Break/Abort IA - * <4> 0 Rx Bound IA - * <3> 1 Queued status reflects oldest 2 bytes in FIFO - * <2> 0 Abort/PE IA - * <1> 1 Rx Overrun IA - * <0> 0 Select TC0 value for readback - * - * 0000 0000 0000 1000 = 0x000a - */ - - /* Carry over the Exit Hunt and Idle Received bits */ - /* in case they have been armed by usc_ArmEvents. */ - - RegValue = usc_InReg( info, RICR ) & 0xc0; - - usc_OutReg( info, RICR, (u16)(0x030a | RegValue) ); - - /* Unlatch all Rx status bits and clear Rx status IRQ Pending */ - - usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); - usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); - - /* Transmit mode Register (TMR) - * - * <15..13> 000 encoding - * <12..11> 00 FCS = 16bit CRC CCITT (x15 + x12 + x5 + 1) - * <10> 1 1 = Start CRC as all 1s (use for SDLC/HDLC) - * <9> 0 1 = Tx CRC Enabled - * <8> 0 1 = Append CRC to end of transmit frame - * <7..6> 00 Transmit parity Even - * <5> 0 Transmit parity Disabled - * <4..2> 000 Tx Char Length = 8 bits - * <1..0> 00 Disable Transmitter - * - * 0000 0100 0000 0000 = 0x0400 - */ - - RegValue = 0x0400; - - switch ( info->params.encoding ) { - case HDLC_ENCODING_NRZB: RegValue |= BIT13; break; - case HDLC_ENCODING_NRZI_MARK: RegValue |= BIT14; break; - case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 | BIT13; break; - case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT15; break; - case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 | BIT13; break; - case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14; break; - case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14 | BIT13; break; - } - - if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) - RegValue |= BIT9 | BIT8; - else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) - RegValue |= ( BIT12 | BIT10 | BIT9 | BIT8); - - usc_OutReg( info, TMR, RegValue ); - - usc_set_txidle( info ); - - - usc_TCmd( info, TCmd_SelectTicrdma_level ); - - /* Transmit Interrupt Control Register (TICR) - * - * <15..8> ? Transmit FIFO DMA Level - * <7> 0 Present IA (Interrupt Arm) - * <6> 0 Idle Sent IA - * <5> 1 Abort Sent IA - * <4> 1 EOF/EOM Sent IA - * <3> 0 CRC Sent IA - * <2> 1 1 = Wait for SW Trigger to Start Frame - * <1> 1 Tx Underrun IA - * <0> 0 TC0 constant on read back - * - * 0000 0000 0011 0110 = 0x0036 - */ - - usc_OutReg( info, TICR, 0x0736 ); - - usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); - usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); - - /* - ** Transmit Command/Status Register (TCSR) - ** - ** <15..12> 0000 TCmd - ** <11> 0/1 UnderWait - ** <10..08> 000 TxIdle - ** <7> x PreSent - ** <6> x IdleSent - ** <5> x AbortSent - ** <4> x EOF/EOM Sent - ** <3> x CRC Sent - ** <2> x All Sent - ** <1> x TxUnder - ** <0> x TxEmpty - ** - ** 0000 0000 0000 0000 = 0x0000 - */ - info->tcsr_value = 0; - - if ( !PreSL1660 ) - info->tcsr_value |= TCSR_UNDERWAIT; - - usc_OutReg( info, TCSR, info->tcsr_value ); - - /* Clock mode Control Register (CMCR) - * - * <15..14> 00 counter 1 Source = Disabled - * <13..12> 00 counter 0 Source = Disabled - * <11..10> 11 BRG1 Input is TxC Pin - * <9..8> 11 BRG0 Input is TxC Pin - * <7..6> 01 DPLL Input is BRG1 Output - * <5..3> XXX TxCLK comes from Port 0 - * <2..0> XXX RxCLK comes from Port 1 - * - * 0000 1111 0111 0111 = 0x0f77 - */ - - RegValue = 0x0f40; - - if ( info->params.flags & HDLC_FLAG_RXC_DPLL ) - RegValue |= 0x0003; /* RxCLK from DPLL */ - else if ( info->params.flags & HDLC_FLAG_RXC_BRG ) - RegValue |= 0x0004; /* RxCLK from BRG0 */ - else if ( info->params.flags & HDLC_FLAG_RXC_TXCPIN) - RegValue |= 0x0006; /* RxCLK from TXC Input */ - else - RegValue |= 0x0007; /* RxCLK from Port1 */ - - if ( info->params.flags & HDLC_FLAG_TXC_DPLL ) - RegValue |= 0x0018; /* TxCLK from DPLL */ - else if ( info->params.flags & HDLC_FLAG_TXC_BRG ) - RegValue |= 0x0020; /* TxCLK from BRG0 */ - else if ( info->params.flags & HDLC_FLAG_TXC_RXCPIN) - RegValue |= 0x0038; /* RxCLK from TXC Input */ - else - RegValue |= 0x0030; /* TxCLK from Port0 */ - - usc_OutReg( info, CMCR, RegValue ); - - - /* Hardware Configuration Register (HCR) - * - * <15..14> 00 CTR0 Divisor:00=32,01=16,10=8,11=4 - * <13> 0 CTR1DSel:0=CTR0Div determines CTR0Div - * <12> 0 CVOK:0=report code violation in biphase - * <11..10> 00 DPLL Divisor:00=32,01=16,10=8,11=4 - * <9..8> XX DPLL mode:00=disable,01=NRZ,10=Biphase,11=Biphase Level - * <7..6> 00 reserved - * <5> 0 BRG1 mode:0=continuous,1=single cycle - * <4> X BRG1 Enable - * <3..2> 00 reserved - * <1> 0 BRG0 mode:0=continuous,1=single cycle - * <0> 0 BRG0 Enable - */ - - RegValue = 0x0000; - - if ( info->params.flags & (HDLC_FLAG_RXC_DPLL | HDLC_FLAG_TXC_DPLL) ) { - u32 XtalSpeed; - u32 DpllDivisor; - u16 Tc; - - /* DPLL is enabled. Use BRG1 to provide continuous reference clock */ - /* for DPLL. DPLL mode in HCR is dependent on the encoding used. */ - - XtalSpeed = 11059200; - - if ( info->params.flags & HDLC_FLAG_DPLL_DIV16 ) { - DpllDivisor = 16; - RegValue |= BIT10; - } - else if ( info->params.flags & HDLC_FLAG_DPLL_DIV8 ) { - DpllDivisor = 8; - RegValue |= BIT11; - } - else - DpllDivisor = 32; - - /* Tc = (Xtal/Speed) - 1 */ - /* If twice the remainder of (Xtal/Speed) is greater than Speed */ - /* then rounding up gives a more precise time constant. Instead */ - /* of rounding up and then subtracting 1 we just don't subtract */ - /* the one in this case. */ - - /*-------------------------------------------------- - * ejz: for DPLL mode, application should use the - * same clock speed as the partner system, even - * though clocking is derived from the input RxData. - * In case the user uses a 0 for the clock speed, - * default to 0xffffffff and don't try to divide by - * zero - *--------------------------------------------------*/ - if ( info->params.clock_speed ) - { - Tc = (u16)((XtalSpeed/DpllDivisor)/info->params.clock_speed); - if ( !((((XtalSpeed/DpllDivisor) % info->params.clock_speed) * 2) - / info->params.clock_speed) ) - Tc--; - } - else - Tc = -1; - - - /* Write 16-bit Time Constant for BRG1 */ - usc_OutReg( info, TC1R, Tc ); - - RegValue |= BIT4; /* enable BRG1 */ - - switch ( info->params.encoding ) { - case HDLC_ENCODING_NRZ: - case HDLC_ENCODING_NRZB: - case HDLC_ENCODING_NRZI_MARK: - case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT8; break; - case HDLC_ENCODING_BIPHASE_MARK: - case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT9; break; - case HDLC_ENCODING_BIPHASE_LEVEL: - case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT9 | BIT8; break; - } - } - - usc_OutReg( info, HCR, RegValue ); - - - /* Channel Control/status Register (CCSR) - * - * <15> X RCC FIFO Overflow status (RO) - * <14> X RCC FIFO Not Empty status (RO) - * <13> 0 1 = Clear RCC FIFO (WO) - * <12> X DPLL Sync (RW) - * <11> X DPLL 2 Missed Clocks status (RO) - * <10> X DPLL 1 Missed Clock status (RO) - * <9..8> 00 DPLL Resync on rising and falling edges (RW) - * <7> X SDLC Loop On status (RO) - * <6> X SDLC Loop Send status (RO) - * <5> 1 Bypass counters for TxClk and RxClk (RW) - * <4..2> 000 Last Char of SDLC frame has 8 bits (RW) - * <1..0> 00 reserved - * - * 0000 0000 0010 0000 = 0x0020 - */ - - usc_OutReg( info, CCSR, 0x1020 ); - - - if ( info->params.flags & HDLC_FLAG_AUTO_CTS ) { - usc_OutReg( info, SICR, - (u16)(usc_InReg(info,SICR) | SICR_CTS_INACTIVE) ); - } - - - /* enable Master Interrupt Enable bit (MIE) */ - usc_EnableMasterIrqBit( info ); - - usc_ClearIrqPendingBits( info, RECEIVE_STATUS | RECEIVE_DATA | - TRANSMIT_STATUS | TRANSMIT_DATA | MISC); - - /* arm RCC underflow interrupt */ - usc_OutReg(info, SICR, (u16)(usc_InReg(info,SICR) | BIT3)); - usc_EnableInterrupts(info, MISC); - - info->mbre_bit = 0; - outw( 0, info->io_base ); /* clear Master Bus Enable (DCAR) */ - usc_DmaCmd( info, DmaCmd_ResetAllChannels ); /* disable both DMA channels */ - info->mbre_bit = BIT8; - outw( BIT8, info->io_base ); /* set Master Bus Enable (DCAR) */ - - /* DMA Control Register (DCR) - * - * <15..14> 10 Priority mode = Alternating Tx/Rx - * 01 Rx has priority - * 00 Tx has priority - * - * <13> 1 Enable Priority Preempt per DCR<15..14> - * (WARNING DCR<11..10> must be 00 when this is 1) - * 0 Choose activate channel per DCR<11..10> - * - * <12> 0 Little Endian for Array/List - * <11..10> 00 Both Channels can use each bus grant - * <9..6> 0000 reserved - * <5> 0 7 CLK - Minimum Bus Re-request Interval - * <4> 0 1 = drive D/C and S/D pins - * <3> 1 1 = Add one wait state to all DMA cycles. - * <2> 0 1 = Strobe /UAS on every transfer. - * <1..0> 11 Addr incrementing only affects LS24 bits - * - * 0110 0000 0000 1011 = 0x600b - */ - - /* PCI adapter does not need DMA wait state */ - usc_OutDmaReg( info, DCR, 0xa00b ); - - /* Receive DMA mode Register (RDMR) - * - * <15..14> 11 DMA mode = Linked List Buffer mode - * <13> 1 RSBinA/L = store Rx status Block in Arrary/List entry - * <12> 1 Clear count of List Entry after fetching - * <11..10> 00 Address mode = Increment - * <9> 1 Terminate Buffer on RxBound - * <8> 0 Bus Width = 16bits - * <7..0> ? status Bits (write as 0s) - * - * 1111 0010 0000 0000 = 0xf200 - */ - - usc_OutDmaReg( info, RDMR, 0xf200 ); - - - /* Transmit DMA mode Register (TDMR) - * - * <15..14> 11 DMA mode = Linked List Buffer mode - * <13> 1 TCBinA/L = fetch Tx Control Block from List entry - * <12> 1 Clear count of List Entry after fetching - * <11..10> 00 Address mode = Increment - * <9> 1 Terminate Buffer on end of frame - * <8> 0 Bus Width = 16bits - * <7..0> ? status Bits (Read Only so write as 0) - * - * 1111 0010 0000 0000 = 0xf200 - */ - - usc_OutDmaReg( info, TDMR, 0xf200 ); - - - /* DMA Interrupt Control Register (DICR) - * - * <15> 1 DMA Interrupt Enable - * <14> 0 1 = Disable IEO from USC - * <13> 0 1 = Don't provide vector during IntAck - * <12> 1 1 = Include status in Vector - * <10..2> 0 reserved, Must be 0s - * <1> 0 1 = Rx DMA Interrupt Enabled - * <0> 0 1 = Tx DMA Interrupt Enabled - * - * 1001 0000 0000 0000 = 0x9000 - */ - - usc_OutDmaReg( info, DICR, 0x9000 ); - - usc_InDmaReg( info, RDMR ); /* clear pending receive DMA IRQ bits */ - usc_InDmaReg( info, TDMR ); /* clear pending transmit DMA IRQ bits */ - usc_OutDmaReg( info, CDIR, 0x0303 ); /* clear IUS and Pending for Tx and Rx */ - - /* Channel Control Register (CCR) - * - * <15..14> 10 Use 32-bit Tx Control Blocks (TCBs) - * <13> 0 Trigger Tx on SW Command Disabled - * <12> 0 Flag Preamble Disabled - * <11..10> 00 Preamble Length - * <9..8> 00 Preamble Pattern - * <7..6> 10 Use 32-bit Rx status Blocks (RSBs) - * <5> 0 Trigger Rx on SW Command Disabled - * <4..0> 0 reserved - * - * 1000 0000 1000 0000 = 0x8080 - */ - - RegValue = 0x8080; - - switch ( info->params.preamble_length ) { - case HDLC_PREAMBLE_LENGTH_16BITS: RegValue |= BIT10; break; - case HDLC_PREAMBLE_LENGTH_32BITS: RegValue |= BIT11; break; - case HDLC_PREAMBLE_LENGTH_64BITS: RegValue |= BIT11 | BIT10; break; - } - - switch ( info->params.preamble ) { - case HDLC_PREAMBLE_PATTERN_FLAGS: RegValue |= BIT8 | BIT12; break; - case HDLC_PREAMBLE_PATTERN_ONES: RegValue |= BIT8; break; - case HDLC_PREAMBLE_PATTERN_10: RegValue |= BIT9; break; - case HDLC_PREAMBLE_PATTERN_01: RegValue |= BIT9 | BIT8; break; - } - - usc_OutReg( info, CCR, RegValue ); - - - /* - * Burst/Dwell Control Register - * - * <15..8> 0x20 Maximum number of transfers per bus grant - * <7..0> 0x00 Maximum number of clock cycles per bus grant - */ - - /* don't limit bus occupancy on PCI adapter */ - usc_OutDmaReg( info, BDCR, 0x0000 ); - - usc_stop_transmitter(info); - usc_stop_receiver(info); - -} /* end of usc_set_sdlc_mode() */ - -/* usc_enable_loopback() - * - * Set the 16C32 for internal loopback mode. - * The TxCLK and RxCLK signals are generated from the BRG0 and - * the TxD is looped back to the RxD internally. - * - * Arguments: info pointer to device instance data - * enable 1 = enable loopback, 0 = disable - * Return Value: None - */ -static void usc_enable_loopback(struct mgsl_struct *info, int enable) -{ - if (enable) { - /* blank external TXD output */ - usc_OutReg(info,IOCR,usc_InReg(info,IOCR) | (BIT7 | BIT6)); - - /* Clock mode Control Register (CMCR) - * - * <15..14> 00 counter 1 Disabled - * <13..12> 00 counter 0 Disabled - * <11..10> 11 BRG1 Input is TxC Pin - * <9..8> 11 BRG0 Input is TxC Pin - * <7..6> 01 DPLL Input is BRG1 Output - * <5..3> 100 TxCLK comes from BRG0 - * <2..0> 100 RxCLK comes from BRG0 - * - * 0000 1111 0110 0100 = 0x0f64 - */ - - usc_OutReg( info, CMCR, 0x0f64 ); - - /* Write 16-bit Time Constant for BRG0 */ - /* use clock speed if available, otherwise use 8 for diagnostics */ - if (info->params.clock_speed) { - usc_OutReg(info, TC0R, (u16)((11059200/info->params.clock_speed)-1)); - } else - usc_OutReg(info, TC0R, (u16)8); - - /* Hardware Configuration Register (HCR) Clear Bit 1, BRG0 - mode = Continuous Set Bit 0 to enable BRG0. */ - usc_OutReg( info, HCR, (u16)((usc_InReg( info, HCR ) & ~BIT1) | BIT0) ); - - /* Input/Output Control Reg, <2..0> = 100, Drive RxC pin with BRG0 */ - usc_OutReg(info, IOCR, (u16)((usc_InReg(info, IOCR) & 0xfff8) | 0x0004)); - - /* set Internal Data loopback mode */ - info->loopback_bits = 0x300; - outw( 0x0300, info->io_base + CCAR ); - } else { - /* enable external TXD output */ - usc_OutReg(info,IOCR,usc_InReg(info,IOCR) & ~(BIT7 | BIT6)); - - /* clear Internal Data loopback mode */ - info->loopback_bits = 0; - outw( 0,info->io_base + CCAR ); - } - -} /* end of usc_enable_loopback() */ - -/* usc_enable_aux_clock() - * - * Enabled the AUX clock output at the specified frequency. - * - * Arguments: - * - * info pointer to device extension - * data_rate data rate of clock in bits per second - * A data rate of 0 disables the AUX clock. - * - * Return Value: None - */ -static void usc_enable_aux_clock( struct mgsl_struct *info, u32 data_rate ) -{ - u32 XtalSpeed; - u16 Tc; - - if ( data_rate ) { - XtalSpeed = 11059200; - - - /* Tc = (Xtal/Speed) - 1 */ - /* If twice the remainder of (Xtal/Speed) is greater than Speed */ - /* then rounding up gives a more precise time constant. Instead */ - /* of rounding up and then subtracting 1 we just don't subtract */ - /* the one in this case. */ - - - Tc = (u16)(XtalSpeed/data_rate); - if ( !(((XtalSpeed % data_rate) * 2) / data_rate) ) - Tc--; - - /* Write 16-bit Time Constant for BRG0 */ - usc_OutReg( info, TC0R, Tc ); - - /* - * Hardware Configuration Register (HCR) - * Clear Bit 1, BRG0 mode = Continuous - * Set Bit 0 to enable BRG0. - */ - - usc_OutReg( info, HCR, (u16)((usc_InReg( info, HCR ) & ~BIT1) | BIT0) ); - - /* Input/Output Control Reg, <2..0> = 100, Drive RxC pin with BRG0 */ - usc_OutReg( info, IOCR, (u16)((usc_InReg(info, IOCR) & 0xfff8) | 0x0004) ); - } else { - /* data rate == 0 so turn off BRG0 */ - usc_OutReg( info, HCR, (u16)(usc_InReg( info, HCR ) & ~BIT0) ); - } - -} /* end of usc_enable_aux_clock() */ - -/* - * - * usc_process_rxoverrun_sync() - * - * This function processes a receive overrun by resetting the - * receive DMA buffers and issuing a Purge Rx FIFO command - * to allow the receiver to continue receiving. - * - * Arguments: - * - * info pointer to device extension - * - * Return Value: None - */ -static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) -{ - int start_index; - int end_index; - int frame_start_index; - bool start_of_frame_found = false; - bool end_of_frame_found = false; - bool reprogram_dma = false; - - DMABUFFERENTRY *buffer_list = info->rx_buffer_list; - u32 phys_addr; - - usc_DmaCmd( info, DmaCmd_PauseRxChannel ); - usc_RCmd( info, RCmd_EnterHuntmode ); - usc_RTCmd( info, RTCmd_PurgeRxFifo ); - - /* CurrentRxBuffer points to the 1st buffer of the next */ - /* possibly available receive frame. */ - - frame_start_index = start_index = end_index = info->current_rx_buffer; - - /* Search for an unfinished string of buffers. This means */ - /* that a receive frame started (at least one buffer with */ - /* count set to zero) but there is no terminiting buffer */ - /* (status set to non-zero). */ - - while( !buffer_list[end_index].count ) - { - /* Count field has been reset to zero by 16C32. */ - /* This buffer is currently in use. */ - - if ( !start_of_frame_found ) - { - start_of_frame_found = true; - frame_start_index = end_index; - end_of_frame_found = false; - } - - if ( buffer_list[end_index].status ) - { - /* Status field has been set by 16C32. */ - /* This is the last buffer of a received frame. */ - - /* We want to leave the buffers for this frame intact. */ - /* Move on to next possible frame. */ - - start_of_frame_found = false; - end_of_frame_found = true; - } - - /* advance to next buffer entry in linked list */ - end_index++; - if ( end_index == info->rx_buffer_count ) - end_index = 0; - - if ( start_index == end_index ) - { - /* The entire list has been searched with all Counts == 0 and */ - /* all Status == 0. The receive buffers are */ - /* completely screwed, reset all receive buffers! */ - mgsl_reset_rx_dma_buffers( info ); - frame_start_index = 0; - start_of_frame_found = false; - reprogram_dma = true; - break; - } - } - - if ( start_of_frame_found && !end_of_frame_found ) - { - /* There is an unfinished string of receive DMA buffers */ - /* as a result of the receiver overrun. */ - - /* Reset the buffers for the unfinished frame */ - /* and reprogram the receive DMA controller to start */ - /* at the 1st buffer of unfinished frame. */ - - start_index = frame_start_index; - - do - { - *((unsigned long *)&(info->rx_buffer_list[start_index++].count)) = DMABUFFERSIZE; - - /* Adjust index for wrap around. */ - if ( start_index == info->rx_buffer_count ) - start_index = 0; - - } while( start_index != end_index ); - - reprogram_dma = true; - } - - if ( reprogram_dma ) - { - usc_UnlatchRxstatusBits(info,RXSTATUS_ALL); - usc_ClearIrqPendingBits(info, RECEIVE_DATA|RECEIVE_STATUS); - usc_UnlatchRxstatusBits(info, RECEIVE_DATA|RECEIVE_STATUS); - - usc_EnableReceiver(info,DISABLE_UNCONDITIONAL); - - /* This empties the receive FIFO and loads the RCC with RCLR */ - usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); - - /* program 16C32 with physical address of 1st DMA buffer entry */ - phys_addr = info->rx_buffer_list[frame_start_index].phys_entry; - usc_OutDmaReg( info, NRARL, (u16)phys_addr ); - usc_OutDmaReg( info, NRARU, (u16)(phys_addr >> 16) ); - - usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); - usc_ClearIrqPendingBits( info, RECEIVE_DATA | RECEIVE_STATUS ); - usc_EnableInterrupts( info, RECEIVE_STATUS ); - - /* 1. Arm End of Buffer (EOB) Receive DMA Interrupt (BIT2 of RDIAR) */ - /* 2. Enable Receive DMA Interrupts (BIT1 of DICR) */ - - usc_OutDmaReg( info, RDIAR, BIT3 | BIT2 ); - usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT1) ); - usc_DmaCmd( info, DmaCmd_InitRxChannel ); - if ( info->params.flags & HDLC_FLAG_AUTO_DCD ) - usc_EnableReceiver(info,ENABLE_AUTO_DCD); - else - usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); - } - else - { - /* This empties the receive FIFO and loads the RCC with RCLR */ - usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); - usc_RTCmd( info, RTCmd_PurgeRxFifo ); - } - -} /* end of usc_process_rxoverrun_sync() */ - -/* usc_stop_receiver() - * - * Disable USC receiver - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void usc_stop_receiver( struct mgsl_struct *info ) -{ - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):usc_stop_receiver(%s)\n", - __FILE__,__LINE__, info->device_name ); - - /* Disable receive DMA channel. */ - /* This also disables receive DMA channel interrupts */ - usc_DmaCmd( info, DmaCmd_ResetRxChannel ); - - usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); - usc_ClearIrqPendingBits( info, RECEIVE_DATA | RECEIVE_STATUS ); - usc_DisableInterrupts( info, RECEIVE_DATA | RECEIVE_STATUS ); - - usc_EnableReceiver(info,DISABLE_UNCONDITIONAL); - - /* This empties the receive FIFO and loads the RCC with RCLR */ - usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); - usc_RTCmd( info, RTCmd_PurgeRxFifo ); - - info->rx_enabled = false; - info->rx_overflow = false; - info->rx_rcc_underrun = false; - -} /* end of stop_receiver() */ - -/* usc_start_receiver() - * - * Enable the USC receiver - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void usc_start_receiver( struct mgsl_struct *info ) -{ - u32 phys_addr; - - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):usc_start_receiver(%s)\n", - __FILE__,__LINE__, info->device_name ); - - mgsl_reset_rx_dma_buffers( info ); - usc_stop_receiver( info ); - - usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); - usc_RTCmd( info, RTCmd_PurgeRxFifo ); - - if ( info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW ) { - /* DMA mode Transfers */ - /* Program the DMA controller. */ - /* Enable the DMA controller end of buffer interrupt. */ - - /* program 16C32 with physical address of 1st DMA buffer entry */ - phys_addr = info->rx_buffer_list[0].phys_entry; - usc_OutDmaReg( info, NRARL, (u16)phys_addr ); - usc_OutDmaReg( info, NRARU, (u16)(phys_addr >> 16) ); - - usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); - usc_ClearIrqPendingBits( info, RECEIVE_DATA | RECEIVE_STATUS ); - usc_EnableInterrupts( info, RECEIVE_STATUS ); - - /* 1. Arm End of Buffer (EOB) Receive DMA Interrupt (BIT2 of RDIAR) */ - /* 2. Enable Receive DMA Interrupts (BIT1 of DICR) */ - - usc_OutDmaReg( info, RDIAR, BIT3 | BIT2 ); - usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT1) ); - usc_DmaCmd( info, DmaCmd_InitRxChannel ); - if ( info->params.flags & HDLC_FLAG_AUTO_DCD ) - usc_EnableReceiver(info,ENABLE_AUTO_DCD); - else - usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); - } else { - usc_UnlatchRxstatusBits(info, RXSTATUS_ALL); - usc_ClearIrqPendingBits(info, RECEIVE_DATA | RECEIVE_STATUS); - usc_EnableInterrupts(info, RECEIVE_DATA); - - usc_RTCmd( info, RTCmd_PurgeRxFifo ); - usc_RCmd( info, RCmd_EnterHuntmode ); - - usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); - } - - usc_OutReg( info, CCSR, 0x1020 ); - - info->rx_enabled = true; - -} /* end of usc_start_receiver() */ - -/* usc_start_transmitter() - * - * Enable the USC transmitter and send a transmit frame if - * one is loaded in the DMA buffers. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void usc_start_transmitter( struct mgsl_struct *info ) -{ - u32 phys_addr; - unsigned int FrameSize; - - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):usc_start_transmitter(%s)\n", - __FILE__,__LINE__, info->device_name ); - - if ( info->xmit_cnt ) { - - /* If auto RTS enabled and RTS is inactive, then assert */ - /* RTS and set a flag indicating that the driver should */ - /* negate RTS when the transmission completes. */ - - info->drop_rts_on_tx_done = false; - - if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) { - usc_get_serial_signals( info ); - if ( !(info->serial_signals & SerialSignal_RTS) ) { - info->serial_signals |= SerialSignal_RTS; - usc_set_serial_signals( info ); - info->drop_rts_on_tx_done = true; - } - } - - - if ( info->params.mode == MGSL_MODE_ASYNC ) { - if ( !info->tx_active ) { - usc_UnlatchTxstatusBits(info, TXSTATUS_ALL); - usc_ClearIrqPendingBits(info, TRANSMIT_STATUS + TRANSMIT_DATA); - usc_EnableInterrupts(info, TRANSMIT_DATA); - usc_load_txfifo(info); - } - } else { - /* Disable transmit DMA controller while programming. */ - usc_DmaCmd( info, DmaCmd_ResetTxChannel ); - - /* Transmit DMA buffer is loaded, so program USC */ - /* to send the frame contained in the buffers. */ - - FrameSize = info->tx_buffer_list[info->start_tx_dma_buffer].rcc; - - /* if operating in Raw sync mode, reset the rcc component - * of the tx dma buffer entry, otherwise, the serial controller - * will send a closing sync char after this count. - */ - if ( info->params.mode == MGSL_MODE_RAW ) - info->tx_buffer_list[info->start_tx_dma_buffer].rcc = 0; - - /* Program the Transmit Character Length Register (TCLR) */ - /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ - usc_OutReg( info, TCLR, (u16)FrameSize ); - - usc_RTCmd( info, RTCmd_PurgeTxFifo ); - - /* Program the address of the 1st DMA Buffer Entry in linked list */ - phys_addr = info->tx_buffer_list[info->start_tx_dma_buffer].phys_entry; - usc_OutDmaReg( info, NTARL, (u16)phys_addr ); - usc_OutDmaReg( info, NTARU, (u16)(phys_addr >> 16) ); - - usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); - usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); - usc_EnableInterrupts( info, TRANSMIT_STATUS ); - - if ( info->params.mode == MGSL_MODE_RAW && - info->num_tx_dma_buffers > 1 ) { - /* When running external sync mode, attempt to 'stream' transmit */ - /* by filling tx dma buffers as they become available. To do this */ - /* we need to enable Tx DMA EOB Status interrupts : */ - /* */ - /* 1. Arm End of Buffer (EOB) Transmit DMA Interrupt (BIT2 of TDIAR) */ - /* 2. Enable Transmit DMA Interrupts (BIT0 of DICR) */ - - usc_OutDmaReg( info, TDIAR, BIT2|BIT3 ); - usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT0) ); - } - - /* Initialize Transmit DMA Channel */ - usc_DmaCmd( info, DmaCmd_InitTxChannel ); - - usc_TCmd( info, TCmd_SendFrame ); - - mod_timer(&info->tx_timer, jiffies + - msecs_to_jiffies(5000)); - } - info->tx_active = true; - } - - if ( !info->tx_enabled ) { - info->tx_enabled = true; - if ( info->params.flags & HDLC_FLAG_AUTO_CTS ) - usc_EnableTransmitter(info,ENABLE_AUTO_CTS); - else - usc_EnableTransmitter(info,ENABLE_UNCONDITIONAL); - } - -} /* end of usc_start_transmitter() */ - -/* usc_stop_transmitter() - * - * Stops the transmitter and DMA - * - * Arguments: info pointer to device isntance data - * Return Value: None - */ -static void usc_stop_transmitter( struct mgsl_struct *info ) -{ - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):usc_stop_transmitter(%s)\n", - __FILE__,__LINE__, info->device_name ); - - del_timer(&info->tx_timer); - - usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); - usc_ClearIrqPendingBits( info, TRANSMIT_STATUS + TRANSMIT_DATA ); - usc_DisableInterrupts( info, TRANSMIT_STATUS + TRANSMIT_DATA ); - - usc_EnableTransmitter(info,DISABLE_UNCONDITIONAL); - usc_DmaCmd( info, DmaCmd_ResetTxChannel ); - usc_RTCmd( info, RTCmd_PurgeTxFifo ); - - info->tx_enabled = false; - info->tx_active = false; - -} /* end of usc_stop_transmitter() */ - -/* usc_load_txfifo() - * - * Fill the transmit FIFO until the FIFO is full or - * there is no more data to load. - * - * Arguments: info pointer to device extension (instance data) - * Return Value: None - */ -static void usc_load_txfifo( struct mgsl_struct *info ) -{ - int Fifocount; - u8 TwoBytes[2]; - - if ( !info->xmit_cnt && !info->x_char ) - return; - - /* Select transmit FIFO status readback in TICR */ - usc_TCmd( info, TCmd_SelectTicrTxFifostatus ); - - /* load the Transmit FIFO until FIFOs full or all data sent */ - - while( (Fifocount = usc_InReg(info, TICR) >> 8) && info->xmit_cnt ) { - /* there is more space in the transmit FIFO and */ - /* there is more data in transmit buffer */ - - if ( (info->xmit_cnt > 1) && (Fifocount > 1) && !info->x_char ) { - /* write a 16-bit word from transmit buffer to 16C32 */ - - TwoBytes[0] = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - TwoBytes[1] = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - - outw( *((u16 *)TwoBytes), info->io_base + DATAREG); - - info->xmit_cnt -= 2; - info->icount.tx += 2; - } else { - /* only 1 byte left to transmit or 1 FIFO slot left */ - - outw( (inw( info->io_base + CCAR) & 0x0780) | (TDR+LSBONLY), - info->io_base + CCAR ); - - if (info->x_char) { - /* transmit pending high priority char */ - outw( info->x_char,info->io_base + CCAR ); - info->x_char = 0; - } else { - outw( info->xmit_buf[info->xmit_tail++],info->io_base + CCAR ); - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - } - info->icount.tx++; - } - } - -} /* end of usc_load_txfifo() */ - -/* usc_reset() - * - * Reset the adapter to a known state and prepare it for further use. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void usc_reset( struct mgsl_struct *info ) -{ - int i; - u32 readval; - - /* Set BIT30 of Misc Control Register */ - /* (Local Control Register 0x50) to force reset of USC. */ - - volatile u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50); - u32 *LCR0BRDR = (u32 *)(info->lcr_base + 0x28); - - info->misc_ctrl_value |= BIT30; - *MiscCtrl = info->misc_ctrl_value; - - /* - * Force at least 170ns delay before clearing reset bit. Each read from - * LCR takes at least 30ns so 10 times for 300ns to be safe. - */ - for(i=0;i<10;i++) - readval = *MiscCtrl; - - info->misc_ctrl_value &= ~BIT30; - *MiscCtrl = info->misc_ctrl_value; - - *LCR0BRDR = BUS_DESCRIPTOR( - 1, // Write Strobe Hold (0-3) - 2, // Write Strobe Delay (0-3) - 2, // Read Strobe Delay (0-3) - 0, // NWDD (Write data-data) (0-3) - 4, // NWAD (Write Addr-data) (0-31) - 0, // NXDA (Read/Write Data-Addr) (0-3) - 0, // NRDD (Read Data-Data) (0-3) - 5 // NRAD (Read Addr-Data) (0-31) - ); - - info->mbre_bit = 0; - info->loopback_bits = 0; - info->usc_idle_mode = 0; - - /* - * Program the Bus Configuration Register (BCR) - * - * <15> 0 Don't use separate address - * <14..6> 0 reserved - * <5..4> 00 IAckmode = Default, don't care - * <3> 1 Bus Request Totem Pole output - * <2> 1 Use 16 Bit data bus - * <1> 0 IRQ Totem Pole output - * <0> 0 Don't Shift Right Addr - * - * 0000 0000 0000 1100 = 0x000c - * - * By writing to io_base + SDPIN the Wait/Ack pin is - * programmed to work as a Wait pin. - */ - - outw( 0x000c,info->io_base + SDPIN ); - - - outw( 0,info->io_base ); - outw( 0,info->io_base + CCAR ); - - /* select little endian byte ordering */ - usc_RTCmd( info, RTCmd_SelectLittleEndian ); - - - /* Port Control Register (PCR) - * - * <15..14> 11 Port 7 is Output (~DMAEN, Bit 14 : 0 = Enabled) - * <13..12> 11 Port 6 is Output (~INTEN, Bit 12 : 0 = Enabled) - * <11..10> 00 Port 5 is Input (No Connect, Don't Care) - * <9..8> 00 Port 4 is Input (No Connect, Don't Care) - * <7..6> 11 Port 3 is Output (~RTS, Bit 6 : 0 = Enabled ) - * <5..4> 11 Port 2 is Output (~DTR, Bit 4 : 0 = Enabled ) - * <3..2> 01 Port 1 is Input (Dedicated RxC) - * <1..0> 01 Port 0 is Input (Dedicated TxC) - * - * 1111 0000 1111 0101 = 0xf0f5 - */ - - usc_OutReg( info, PCR, 0xf0f5 ); - - - /* - * Input/Output Control Register - * - * <15..14> 00 CTS is active low input - * <13..12> 00 DCD is active low input - * <11..10> 00 TxREQ pin is input (DSR) - * <9..8> 00 RxREQ pin is input (RI) - * <7..6> 00 TxD is output (Transmit Data) - * <5..3> 000 TxC Pin in Input (14.7456MHz Clock) - * <2..0> 100 RxC is Output (drive with BRG0) - * - * 0000 0000 0000 0100 = 0x0004 - */ - - usc_OutReg( info, IOCR, 0x0004 ); - -} /* end of usc_reset() */ - -/* usc_set_async_mode() - * - * Program adapter for asynchronous communications. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void usc_set_async_mode( struct mgsl_struct *info ) -{ - u16 RegValue; - - /* disable interrupts while programming USC */ - usc_DisableMasterIrqBit( info ); - - outw( 0, info->io_base ); /* clear Master Bus Enable (DCAR) */ - usc_DmaCmd( info, DmaCmd_ResetAllChannels ); /* disable both DMA channels */ - - usc_loopback_frame( info ); - - /* Channel mode Register (CMR) - * - * <15..14> 00 Tx Sub modes, 00 = 1 Stop Bit - * <13..12> 00 00 = 16X Clock - * <11..8> 0000 Transmitter mode = Asynchronous - * <7..6> 00 reserved? - * <5..4> 00 Rx Sub modes, 00 = 16X Clock - * <3..0> 0000 Receiver mode = Asynchronous - * - * 0000 0000 0000 0000 = 0x0 - */ - - RegValue = 0; - if ( info->params.stop_bits != 1 ) - RegValue |= BIT14; - usc_OutReg( info, CMR, RegValue ); - - - /* Receiver mode Register (RMR) - * - * <15..13> 000 encoding = None - * <12..08> 00000 reserved (Sync Only) - * <7..6> 00 Even parity - * <5> 0 parity disabled - * <4..2> 000 Receive Char Length = 8 bits - * <1..0> 00 Disable Receiver - * - * 0000 0000 0000 0000 = 0x0 - */ - - RegValue = 0; - - if ( info->params.data_bits != 8 ) - RegValue |= BIT4 | BIT3 | BIT2; - - if ( info->params.parity != ASYNC_PARITY_NONE ) { - RegValue |= BIT5; - if ( info->params.parity != ASYNC_PARITY_ODD ) - RegValue |= BIT6; - } - - usc_OutReg( info, RMR, RegValue ); - - - /* Set IRQ trigger level */ - - usc_RCmd( info, RCmd_SelectRicrIntLevel ); - - - /* Receive Interrupt Control Register (RICR) - * - * <15..8> ? RxFIFO IRQ Request Level - * - * Note: For async mode the receive FIFO level must be set - * to 0 to avoid the situation where the FIFO contains fewer bytes - * than the trigger level and no more data is expected. - * - * <7> 0 Exited Hunt IA (Interrupt Arm) - * <6> 0 Idle Received IA - * <5> 0 Break/Abort IA - * <4> 0 Rx Bound IA - * <3> 0 Queued status reflects oldest byte in FIFO - * <2> 0 Abort/PE IA - * <1> 0 Rx Overrun IA - * <0> 0 Select TC0 value for readback - * - * 0000 0000 0100 0000 = 0x0000 + (FIFOLEVEL in MSB) - */ - - usc_OutReg( info, RICR, 0x0000 ); - - usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); - usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); - - - /* Transmit mode Register (TMR) - * - * <15..13> 000 encoding = None - * <12..08> 00000 reserved (Sync Only) - * <7..6> 00 Transmit parity Even - * <5> 0 Transmit parity Disabled - * <4..2> 000 Tx Char Length = 8 bits - * <1..0> 00 Disable Transmitter - * - * 0000 0000 0000 0000 = 0x0 - */ - - RegValue = 0; - - if ( info->params.data_bits != 8 ) - RegValue |= BIT4 | BIT3 | BIT2; - - if ( info->params.parity != ASYNC_PARITY_NONE ) { - RegValue |= BIT5; - if ( info->params.parity != ASYNC_PARITY_ODD ) - RegValue |= BIT6; - } - - usc_OutReg( info, TMR, RegValue ); - - usc_set_txidle( info ); - - - /* Set IRQ trigger level */ - - usc_TCmd( info, TCmd_SelectTicrIntLevel ); - - - /* Transmit Interrupt Control Register (TICR) - * - * <15..8> ? Transmit FIFO IRQ Level - * <7> 0 Present IA (Interrupt Arm) - * <6> 1 Idle Sent IA - * <5> 0 Abort Sent IA - * <4> 0 EOF/EOM Sent IA - * <3> 0 CRC Sent IA - * <2> 0 1 = Wait for SW Trigger to Start Frame - * <1> 0 Tx Underrun IA - * <0> 0 TC0 constant on read back - * - * 0000 0000 0100 0000 = 0x0040 - */ - - usc_OutReg( info, TICR, 0x1f40 ); - - usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); - usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); - - usc_enable_async_clock( info, info->params.data_rate ); - - - /* Channel Control/status Register (CCSR) - * - * <15> X RCC FIFO Overflow status (RO) - * <14> X RCC FIFO Not Empty status (RO) - * <13> 0 1 = Clear RCC FIFO (WO) - * <12> X DPLL in Sync status (RO) - * <11> X DPLL 2 Missed Clocks status (RO) - * <10> X DPLL 1 Missed Clock status (RO) - * <9..8> 00 DPLL Resync on rising and falling edges (RW) - * <7> X SDLC Loop On status (RO) - * <6> X SDLC Loop Send status (RO) - * <5> 1 Bypass counters for TxClk and RxClk (RW) - * <4..2> 000 Last Char of SDLC frame has 8 bits (RW) - * <1..0> 00 reserved - * - * 0000 0000 0010 0000 = 0x0020 - */ - - usc_OutReg( info, CCSR, 0x0020 ); - - usc_DisableInterrupts( info, TRANSMIT_STATUS + TRANSMIT_DATA + - RECEIVE_DATA + RECEIVE_STATUS ); - - usc_ClearIrqPendingBits( info, TRANSMIT_STATUS + TRANSMIT_DATA + - RECEIVE_DATA + RECEIVE_STATUS ); - - usc_EnableMasterIrqBit( info ); - - if (info->params.loopback) { - info->loopback_bits = 0x300; - outw(0x0300, info->io_base + CCAR); - } - -} /* end of usc_set_async_mode() */ - -/* usc_loopback_frame() - * - * Loop back a small (2 byte) dummy SDLC frame. - * Interrupts and DMA are NOT used. The purpose of this is to - * clear any 'stale' status info left over from running in async mode. - * - * The 16C32 shows the strange behaviour of marking the 1st - * received SDLC frame with a CRC error even when there is no - * CRC error. To get around this a small dummy from of 2 bytes - * is looped back when switching from async to sync mode. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void usc_loopback_frame( struct mgsl_struct *info ) -{ - int i; - unsigned long oldmode = info->params.mode; - - info->params.mode = MGSL_MODE_HDLC; - - usc_DisableMasterIrqBit( info ); - - usc_set_sdlc_mode( info ); - usc_enable_loopback( info, 1 ); - - /* Write 16-bit Time Constant for BRG0 */ - usc_OutReg( info, TC0R, 0 ); - - /* Channel Control Register (CCR) - * - * <15..14> 00 Don't use 32-bit Tx Control Blocks (TCBs) - * <13> 0 Trigger Tx on SW Command Disabled - * <12> 0 Flag Preamble Disabled - * <11..10> 00 Preamble Length = 8-Bits - * <9..8> 01 Preamble Pattern = flags - * <7..6> 10 Don't use 32-bit Rx status Blocks (RSBs) - * <5> 0 Trigger Rx on SW Command Disabled - * <4..0> 0 reserved - * - * 0000 0001 0000 0000 = 0x0100 - */ - - usc_OutReg( info, CCR, 0x0100 ); - - /* SETUP RECEIVER */ - usc_RTCmd( info, RTCmd_PurgeRxFifo ); - usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); - - /* SETUP TRANSMITTER */ - /* Program the Transmit Character Length Register (TCLR) */ - /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ - usc_OutReg( info, TCLR, 2 ); - usc_RTCmd( info, RTCmd_PurgeTxFifo ); - - /* unlatch Tx status bits, and start transmit channel. */ - usc_UnlatchTxstatusBits(info,TXSTATUS_ALL); - outw(0,info->io_base + DATAREG); - - /* ENABLE TRANSMITTER */ - usc_TCmd( info, TCmd_SendFrame ); - usc_EnableTransmitter(info,ENABLE_UNCONDITIONAL); - - /* WAIT FOR RECEIVE COMPLETE */ - for (i=0 ; i<1000 ; i++) - if (usc_InReg( info, RCSR ) & (BIT8 | BIT4 | BIT3 | BIT1)) - break; - - /* clear Internal Data loopback mode */ - usc_enable_loopback(info, 0); - - usc_EnableMasterIrqBit(info); - - info->params.mode = oldmode; - -} /* end of usc_loopback_frame() */ - -/* usc_set_sync_mode() Programs the USC for SDLC communications. - * - * Arguments: info pointer to adapter info structure - * Return Value: None - */ -static void usc_set_sync_mode( struct mgsl_struct *info ) -{ - usc_loopback_frame( info ); - usc_set_sdlc_mode( info ); - - usc_enable_aux_clock(info, info->params.clock_speed); - - if (info->params.loopback) - usc_enable_loopback(info,1); - -} /* end of mgsl_set_sync_mode() */ - -/* usc_set_txidle() Set the HDLC idle mode for the transmitter. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void usc_set_txidle( struct mgsl_struct *info ) -{ - u16 usc_idle_mode = IDLEMODE_FLAGS; - - /* Map API idle mode to USC register bits */ - - switch( info->idle_mode ){ - case HDLC_TXIDLE_FLAGS: usc_idle_mode = IDLEMODE_FLAGS; break; - case HDLC_TXIDLE_ALT_ZEROS_ONES: usc_idle_mode = IDLEMODE_ALT_ONE_ZERO; break; - case HDLC_TXIDLE_ZEROS: usc_idle_mode = IDLEMODE_ZERO; break; - case HDLC_TXIDLE_ONES: usc_idle_mode = IDLEMODE_ONE; break; - case HDLC_TXIDLE_ALT_MARK_SPACE: usc_idle_mode = IDLEMODE_ALT_MARK_SPACE; break; - case HDLC_TXIDLE_SPACE: usc_idle_mode = IDLEMODE_SPACE; break; - case HDLC_TXIDLE_MARK: usc_idle_mode = IDLEMODE_MARK; break; - } - - info->usc_idle_mode = usc_idle_mode; - //usc_OutReg(info, TCSR, usc_idle_mode); - info->tcsr_value &= ~IDLEMODE_MASK; /* clear idle mode bits */ - info->tcsr_value += usc_idle_mode; - usc_OutReg(info, TCSR, info->tcsr_value); - - /* - * if SyncLink WAN adapter is running in external sync mode, the - * transmitter has been set to Monosync in order to try to mimic - * a true raw outbound bit stream. Monosync still sends an open/close - * sync char at the start/end of a frame. Try to match those sync - * patterns to the idle mode set here - */ - if ( info->params.mode == MGSL_MODE_RAW ) { - unsigned char syncpat = 0; - switch( info->idle_mode ) { - case HDLC_TXIDLE_FLAGS: - syncpat = 0x7e; - break; - case HDLC_TXIDLE_ALT_ZEROS_ONES: - syncpat = 0x55; - break; - case HDLC_TXIDLE_ZEROS: - case HDLC_TXIDLE_SPACE: - syncpat = 0x00; - break; - case HDLC_TXIDLE_ONES: - case HDLC_TXIDLE_MARK: - syncpat = 0xff; - break; - case HDLC_TXIDLE_ALT_MARK_SPACE: - syncpat = 0xaa; - break; - } - - usc_SetTransmitSyncChars(info,syncpat,syncpat); - } - -} /* end of usc_set_txidle() */ - -/* usc_get_serial_signals() - * - * Query the adapter for the state of the V24 status (input) signals. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void usc_get_serial_signals( struct mgsl_struct *info ) -{ - u16 status; - - /* clear all serial signals except RTS and DTR */ - info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR; - - /* Read the Misc Interrupt status Register (MISR) to get */ - /* the V24 status signals. */ - - status = usc_InReg( info, MISR ); - - /* set serial signal bits to reflect MISR */ - - if ( status & MISCSTATUS_CTS ) - info->serial_signals |= SerialSignal_CTS; - - if ( status & MISCSTATUS_DCD ) - info->serial_signals |= SerialSignal_DCD; - - if ( status & MISCSTATUS_RI ) - info->serial_signals |= SerialSignal_RI; - - if ( status & MISCSTATUS_DSR ) - info->serial_signals |= SerialSignal_DSR; - -} /* end of usc_get_serial_signals() */ - -/* usc_set_serial_signals() - * - * Set the state of RTS and DTR based on contents of - * serial_signals member of device extension. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void usc_set_serial_signals( struct mgsl_struct *info ) -{ - u16 Control; - unsigned char V24Out = info->serial_signals; - - /* get the current value of the Port Control Register (PCR) */ - - Control = usc_InReg( info, PCR ); - - if ( V24Out & SerialSignal_RTS ) - Control &= ~(BIT6); - else - Control |= BIT6; - - if ( V24Out & SerialSignal_DTR ) - Control &= ~(BIT4); - else - Control |= BIT4; - - usc_OutReg( info, PCR, Control ); - -} /* end of usc_set_serial_signals() */ - -/* usc_enable_async_clock() - * - * Enable the async clock at the specified frequency. - * - * Arguments: info pointer to device instance data - * data_rate data rate of clock in bps - * 0 disables the AUX clock. - * Return Value: None - */ -static void usc_enable_async_clock( struct mgsl_struct *info, u32 data_rate ) -{ - if ( data_rate ) { - /* - * Clock mode Control Register (CMCR) - * - * <15..14> 00 counter 1 Disabled - * <13..12> 00 counter 0 Disabled - * <11..10> 11 BRG1 Input is TxC Pin - * <9..8> 11 BRG0 Input is TxC Pin - * <7..6> 01 DPLL Input is BRG1 Output - * <5..3> 100 TxCLK comes from BRG0 - * <2..0> 100 RxCLK comes from BRG0 - * - * 0000 1111 0110 0100 = 0x0f64 - */ - - usc_OutReg( info, CMCR, 0x0f64 ); - - - /* - * Write 16-bit Time Constant for BRG0 - * Time Constant = (ClkSpeed / data_rate) - 1 - * ClkSpeed = 921600 (ISA), 691200 (PCI) - */ - - usc_OutReg( info, TC0R, (u16)((691200/data_rate) - 1) ); - - /* - * Hardware Configuration Register (HCR) - * Clear Bit 1, BRG0 mode = Continuous - * Set Bit 0 to enable BRG0. - */ - - usc_OutReg( info, HCR, - (u16)((usc_InReg( info, HCR ) & ~BIT1) | BIT0) ); - - - /* Input/Output Control Reg, <2..0> = 100, Drive RxC pin with BRG0 */ - - usc_OutReg( info, IOCR, - (u16)((usc_InReg(info, IOCR) & 0xfff8) | 0x0004) ); - } else { - /* data rate == 0 so turn off BRG0 */ - usc_OutReg( info, HCR, (u16)(usc_InReg( info, HCR ) & ~BIT0) ); - } - -} /* end of usc_enable_async_clock() */ - -/* - * Buffer Structures: - * - * Normal memory access uses virtual addresses that can make discontiguous - * physical memory pages appear to be contiguous in the virtual address - * space (the processors memory mapping handles the conversions). - * - * DMA transfers require physically contiguous memory. This is because - * the DMA system controller and DMA bus masters deal with memory using - * only physical addresses. - * - * This causes a problem under Windows NT when large DMA buffers are - * needed. Fragmentation of the nonpaged pool prevents allocations of - * physically contiguous buffers larger than the PAGE_SIZE. - * - * However the 16C32 supports Bus Master Scatter/Gather DMA which - * allows DMA transfers to physically discontiguous buffers. Information - * about each data transfer buffer is contained in a memory structure - * called a 'buffer entry'. A list of buffer entries is maintained - * to track and control the use of the data transfer buffers. - * - * To support this strategy we will allocate sufficient PAGE_SIZE - * contiguous memory buffers to allow for the total required buffer - * space. - * - * The 16C32 accesses the list of buffer entries using Bus Master - * DMA. Control information is read from the buffer entries by the - * 16C32 to control data transfers. status information is written to - * the buffer entries by the 16C32 to indicate the status of completed - * transfers. - * - * The CPU writes control information to the buffer entries to control - * the 16C32 and reads status information from the buffer entries to - * determine information about received and transmitted frames. - * - * Because the CPU and 16C32 (adapter) both need simultaneous access - * to the buffer entries, the buffer entry memory is allocated with - * HalAllocateCommonBuffer(). This restricts the size of the buffer - * entry list to PAGE_SIZE. - * - * The actual data buffers on the other hand will only be accessed - * by the CPU or the adapter but not by both simultaneously. This allows - * Scatter/Gather packet based DMA procedures for using physically - * discontiguous pages. - */ - -/* - * mgsl_reset_tx_dma_buffers() - * - * Set the count for all transmit buffers to 0 to indicate the - * buffer is available for use and set the current buffer to the - * first buffer. This effectively makes all buffers free and - * discards any data in buffers. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ) -{ - unsigned int i; - - for ( i = 0; i < info->tx_buffer_count; i++ ) { - *((unsigned long *)&(info->tx_buffer_list[i].count)) = 0; - } - - info->current_tx_buffer = 0; - info->start_tx_dma_buffer = 0; - info->tx_dma_buffers_used = 0; - - info->get_tx_holding_index = 0; - info->put_tx_holding_index = 0; - info->tx_holding_count = 0; - -} /* end of mgsl_reset_tx_dma_buffers() */ - -/* - * num_free_tx_dma_buffers() - * - * returns the number of free tx dma buffers available - * - * Arguments: info pointer to device instance data - * Return Value: number of free tx dma buffers - */ -static int num_free_tx_dma_buffers(struct mgsl_struct *info) -{ - return info->tx_buffer_count - info->tx_dma_buffers_used; -} - -/* - * mgsl_reset_rx_dma_buffers() - * - * Set the count for all receive buffers to DMABUFFERSIZE - * and set the current buffer to the first buffer. This effectively - * makes all buffers free and discards any data in buffers. - * - * Arguments: info pointer to device instance data - * Return Value: None - */ -static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ) -{ - unsigned int i; - - for ( i = 0; i < info->rx_buffer_count; i++ ) { - *((unsigned long *)&(info->rx_buffer_list[i].count)) = DMABUFFERSIZE; -// info->rx_buffer_list[i].count = DMABUFFERSIZE; -// info->rx_buffer_list[i].status = 0; - } - - info->current_rx_buffer = 0; - -} /* end of mgsl_reset_rx_dma_buffers() */ - -/* - * mgsl_free_rx_frame_buffers() - * - * Free the receive buffers used by a received SDLC - * frame such that the buffers can be reused. - * - * Arguments: - * - * info pointer to device instance data - * StartIndex index of 1st receive buffer of frame - * EndIndex index of last receive buffer of frame - * - * Return Value: None - */ -static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ) -{ - bool Done = false; - DMABUFFERENTRY *pBufEntry; - unsigned int Index; - - /* Starting with 1st buffer entry of the frame clear the status */ - /* field and set the count field to DMA Buffer Size. */ - - Index = StartIndex; - - while( !Done ) { - pBufEntry = &(info->rx_buffer_list[Index]); - - if ( Index == EndIndex ) { - /* This is the last buffer of the frame! */ - Done = true; - } - - /* reset current buffer for reuse */ -// pBufEntry->status = 0; -// pBufEntry->count = DMABUFFERSIZE; - *((unsigned long *)&(pBufEntry->count)) = DMABUFFERSIZE; - - /* advance to next buffer entry in linked list */ - Index++; - if ( Index == info->rx_buffer_count ) - Index = 0; - } - - /* set current buffer to next buffer after last buffer of frame */ - info->current_rx_buffer = Index; - -} /* end of free_rx_frame_buffers() */ - -/* mgsl_get_rx_frame() - * - * This function attempts to return a received SDLC frame from the - * receive DMA buffers. Only frames received without errors are returned. - * - * Arguments: info pointer to device extension - * Return Value: true if frame returned, otherwise false - */ -static bool mgsl_get_rx_frame(struct mgsl_struct *info) -{ - unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ - unsigned short status; - DMABUFFERENTRY *pBufEntry; - unsigned int framesize = 0; - bool ReturnCode = false; - unsigned long flags; - struct tty_struct *tty = info->port.tty; - bool return_frame = false; - - /* - * current_rx_buffer points to the 1st buffer of the next available - * receive frame. To find the last buffer of the frame look for - * a non-zero status field in the buffer entries. (The status - * field is set by the 16C32 after completing a receive frame. - */ - - StartIndex = EndIndex = info->current_rx_buffer; - - while( !info->rx_buffer_list[EndIndex].status ) { - /* - * If the count field of the buffer entry is non-zero then - * this buffer has not been used. (The 16C32 clears the count - * field when it starts using the buffer.) If an unused buffer - * is encountered then there are no frames available. - */ - - if ( info->rx_buffer_list[EndIndex].count ) - goto Cleanup; - - /* advance to next buffer entry in linked list */ - EndIndex++; - if ( EndIndex == info->rx_buffer_count ) - EndIndex = 0; - - /* if entire list searched then no frame available */ - if ( EndIndex == StartIndex ) { - /* If this occurs then something bad happened, - * all buffers have been 'used' but none mark - * the end of a frame. Reset buffers and receiver. - */ - - if ( info->rx_enabled ){ - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_start_receiver(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } - goto Cleanup; - } - } - - - /* check status of receive frame */ - - status = info->rx_buffer_list[EndIndex].status; - - if ( status & (RXSTATUS_SHORT_FRAME | RXSTATUS_OVERRUN | - RXSTATUS_CRC_ERROR | RXSTATUS_ABORT) ) { - if ( status & RXSTATUS_SHORT_FRAME ) - info->icount.rxshort++; - else if ( status & RXSTATUS_ABORT ) - info->icount.rxabort++; - else if ( status & RXSTATUS_OVERRUN ) - info->icount.rxover++; - else { - info->icount.rxcrc++; - if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) - return_frame = true; - } - framesize = 0; -#if SYNCLINK_GENERIC_HDLC - { - info->netdev->stats.rx_errors++; - info->netdev->stats.rx_frame_errors++; - } -#endif - } else - return_frame = true; - - if ( return_frame ) { - /* receive frame has no errors, get frame size. - * The frame size is the starting value of the RCC (which was - * set to 0xffff) minus the ending value of the RCC (decremented - * once for each receive character) minus 2 for the 16-bit CRC. - */ - - framesize = RCLRVALUE - info->rx_buffer_list[EndIndex].rcc; - - /* adjust frame size for CRC if any */ - if ( info->params.crc_type == HDLC_CRC_16_CCITT ) - framesize -= 2; - else if ( info->params.crc_type == HDLC_CRC_32_CCITT ) - framesize -= 4; - } - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk("%s(%d):mgsl_get_rx_frame(%s) status=%04X size=%d\n", - __FILE__,__LINE__,info->device_name,status,framesize); - - if ( debug_level >= DEBUG_LEVEL_DATA ) - mgsl_trace_block(info,info->rx_buffer_list[StartIndex].virt_addr, - min_t(int, framesize, DMABUFFERSIZE),0); - - if (framesize) { - if ( ( (info->params.crc_type & HDLC_CRC_RETURN_EX) && - ((framesize+1) > info->max_frame_size) ) || - (framesize > info->max_frame_size) ) - info->icount.rxlong++; - else { - /* copy dma buffer(s) to contiguous intermediate buffer */ - int copy_count = framesize; - int index = StartIndex; - unsigned char *ptmp = info->intermediate_rxbuffer; - - if ( !(status & RXSTATUS_CRC_ERROR)) - info->icount.rxok++; - - while(copy_count) { - int partial_count; - if ( copy_count > DMABUFFERSIZE ) - partial_count = DMABUFFERSIZE; - else - partial_count = copy_count; - - pBufEntry = &(info->rx_buffer_list[index]); - memcpy( ptmp, pBufEntry->virt_addr, partial_count ); - ptmp += partial_count; - copy_count -= partial_count; - - if ( ++index == info->rx_buffer_count ) - index = 0; - } - - if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) { - ++framesize; - *ptmp = (status & RXSTATUS_CRC_ERROR ? - RX_CRC_ERROR : - RX_OK); - - if ( debug_level >= DEBUG_LEVEL_DATA ) - printk("%s(%d):mgsl_get_rx_frame(%s) rx frame status=%d\n", - __FILE__,__LINE__,info->device_name, - *ptmp); - } - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_rx(info,info->intermediate_rxbuffer,framesize); - else -#endif - ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); - } - } - /* Free the buffers used by this frame. */ - mgsl_free_rx_frame_buffers( info, StartIndex, EndIndex ); - - ReturnCode = true; - -Cleanup: - - if ( info->rx_enabled && info->rx_overflow ) { - /* The receiver needs to restarted because of - * a receive overflow (buffer or FIFO). If the - * receive buffers are now empty, then restart receiver. - */ - - if ( !info->rx_buffer_list[EndIndex].status && - info->rx_buffer_list[EndIndex].count ) { - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_start_receiver(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } - } - - return ReturnCode; - -} /* end of mgsl_get_rx_frame() */ - -/* mgsl_get_raw_rx_frame() - * - * This function attempts to return a received frame from the - * receive DMA buffers when running in external loop mode. In this mode, - * we will return at most one DMABUFFERSIZE frame to the application. - * The USC receiver is triggering off of DCD going active to start a new - * frame, and DCD going inactive to terminate the frame (similar to - * processing a closing flag character). - * - * In this routine, we will return DMABUFFERSIZE "chunks" at a time. - * If DCD goes inactive, the last Rx DMA Buffer will have a non-zero - * status field and the RCC field will indicate the length of the - * entire received frame. We take this RCC field and get the modulus - * of RCC and DMABUFFERSIZE to determine if number of bytes in the - * last Rx DMA buffer and return that last portion of the frame. - * - * Arguments: info pointer to device extension - * Return Value: true if frame returned, otherwise false - */ -static bool mgsl_get_raw_rx_frame(struct mgsl_struct *info) -{ - unsigned int CurrentIndex, NextIndex; - unsigned short status; - DMABUFFERENTRY *pBufEntry; - unsigned int framesize = 0; - bool ReturnCode = false; - unsigned long flags; - struct tty_struct *tty = info->port.tty; - - /* - * current_rx_buffer points to the 1st buffer of the next available - * receive frame. The status field is set by the 16C32 after - * completing a receive frame. If the status field of this buffer - * is zero, either the USC is still filling this buffer or this - * is one of a series of buffers making up a received frame. - * - * If the count field of this buffer is zero, the USC is either - * using this buffer or has used this buffer. Look at the count - * field of the next buffer. If that next buffer's count is - * non-zero, the USC is still actively using the current buffer. - * Otherwise, if the next buffer's count field is zero, the - * current buffer is complete and the USC is using the next - * buffer. - */ - CurrentIndex = NextIndex = info->current_rx_buffer; - ++NextIndex; - if ( NextIndex == info->rx_buffer_count ) - NextIndex = 0; - - if ( info->rx_buffer_list[CurrentIndex].status != 0 || - (info->rx_buffer_list[CurrentIndex].count == 0 && - info->rx_buffer_list[NextIndex].count == 0)) { - /* - * Either the status field of this dma buffer is non-zero - * (indicating the last buffer of a receive frame) or the next - * buffer is marked as in use -- implying this buffer is complete - * and an intermediate buffer for this received frame. - */ - - status = info->rx_buffer_list[CurrentIndex].status; - - if ( status & (RXSTATUS_SHORT_FRAME | RXSTATUS_OVERRUN | - RXSTATUS_CRC_ERROR | RXSTATUS_ABORT) ) { - if ( status & RXSTATUS_SHORT_FRAME ) - info->icount.rxshort++; - else if ( status & RXSTATUS_ABORT ) - info->icount.rxabort++; - else if ( status & RXSTATUS_OVERRUN ) - info->icount.rxover++; - else - info->icount.rxcrc++; - framesize = 0; - } else { - /* - * A receive frame is available, get frame size and status. - * - * The frame size is the starting value of the RCC (which was - * set to 0xffff) minus the ending value of the RCC (decremented - * once for each receive character) minus 2 or 4 for the 16-bit - * or 32-bit CRC. - * - * If the status field is zero, this is an intermediate buffer. - * It's size is 4K. - * - * If the DMA Buffer Entry's Status field is non-zero, the - * receive operation completed normally (ie: DCD dropped). The - * RCC field is valid and holds the received frame size. - * It is possible that the RCC field will be zero on a DMA buffer - * entry with a non-zero status. This can occur if the total - * frame size (number of bytes between the time DCD goes active - * to the time DCD goes inactive) exceeds 65535 bytes. In this - * case the 16C32 has underrun on the RCC count and appears to - * stop updating this counter to let us know the actual received - * frame size. If this happens (non-zero status and zero RCC), - * simply return the entire RxDMA Buffer - */ - if ( status ) { - /* - * In the event that the final RxDMA Buffer is - * terminated with a non-zero status and the RCC - * field is zero, we interpret this as the RCC - * having underflowed (received frame > 65535 bytes). - * - * Signal the event to the user by passing back - * a status of RxStatus_CrcError returning the full - * buffer and let the app figure out what data is - * actually valid - */ - if ( info->rx_buffer_list[CurrentIndex].rcc ) - framesize = RCLRVALUE - info->rx_buffer_list[CurrentIndex].rcc; - else - framesize = DMABUFFERSIZE; - } - else - framesize = DMABUFFERSIZE; - } - - if ( framesize > DMABUFFERSIZE ) { - /* - * if running in raw sync mode, ISR handler for - * End Of Buffer events terminates all buffers at 4K. - * If this frame size is said to be >4K, get the - * actual number of bytes of the frame in this buffer. - */ - framesize = framesize % DMABUFFERSIZE; - } - - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk("%s(%d):mgsl_get_raw_rx_frame(%s) status=%04X size=%d\n", - __FILE__,__LINE__,info->device_name,status,framesize); - - if ( debug_level >= DEBUG_LEVEL_DATA ) - mgsl_trace_block(info,info->rx_buffer_list[CurrentIndex].virt_addr, - min_t(int, framesize, DMABUFFERSIZE),0); - - if (framesize) { - /* copy dma buffer(s) to contiguous intermediate buffer */ - /* NOTE: we never copy more than DMABUFFERSIZE bytes */ - - pBufEntry = &(info->rx_buffer_list[CurrentIndex]); - memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize); - info->icount.rxok++; - - ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); - } - - /* Free the buffers used by this frame. */ - mgsl_free_rx_frame_buffers( info, CurrentIndex, CurrentIndex ); - - ReturnCode = true; - } - - - if ( info->rx_enabled && info->rx_overflow ) { - /* The receiver needs to restarted because of - * a receive overflow (buffer or FIFO). If the - * receive buffers are now empty, then restart receiver. - */ - - if ( !info->rx_buffer_list[CurrentIndex].status && - info->rx_buffer_list[CurrentIndex].count ) { - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_start_receiver(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } - } - - return ReturnCode; - -} /* end of mgsl_get_raw_rx_frame() */ - -/* mgsl_load_tx_dma_buffer() - * - * Load the transmit DMA buffer with the specified data. - * - * Arguments: - * - * info pointer to device extension - * Buffer pointer to buffer containing frame to load - * BufferSize size in bytes of frame in Buffer - * - * Return Value: None - */ -static void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, - const char *Buffer, unsigned int BufferSize) -{ - unsigned short Copycount; - unsigned int i = 0; - DMABUFFERENTRY *pBufEntry; - - if ( debug_level >= DEBUG_LEVEL_DATA ) - mgsl_trace_block(info,Buffer, min_t(int, BufferSize, DMABUFFERSIZE), 1); - - if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) { - /* set CMR:13 to start transmit when - * next GoAhead (abort) is received - */ - info->cmr_value |= BIT13; - } - - /* begin loading the frame in the next available tx dma - * buffer, remember it's starting location for setting - * up tx dma operation - */ - i = info->current_tx_buffer; - info->start_tx_dma_buffer = i; - - /* Setup the status and RCC (Frame Size) fields of the 1st */ - /* buffer entry in the transmit DMA buffer list. */ - - info->tx_buffer_list[i].status = info->cmr_value & 0xf000; - info->tx_buffer_list[i].rcc = BufferSize; - info->tx_buffer_list[i].count = BufferSize; - - /* Copy frame data from 1st source buffer to the DMA buffers. */ - /* The frame data may span multiple DMA buffers. */ - - while( BufferSize ){ - /* Get a pointer to next DMA buffer entry. */ - pBufEntry = &info->tx_buffer_list[i++]; - - if ( i == info->tx_buffer_count ) - i=0; - - /* Calculate the number of bytes that can be copied from */ - /* the source buffer to this DMA buffer. */ - if ( BufferSize > DMABUFFERSIZE ) - Copycount = DMABUFFERSIZE; - else - Copycount = BufferSize; - - /* Actually copy data from source buffer to DMA buffer. */ - /* Also set the data count for this individual DMA buffer. */ - mgsl_load_pci_memory(pBufEntry->virt_addr, Buffer,Copycount); - - pBufEntry->count = Copycount; - - /* Advance source pointer and reduce remaining data count. */ - Buffer += Copycount; - BufferSize -= Copycount; - - ++info->tx_dma_buffers_used; - } - - /* remember next available tx dma buffer */ - info->current_tx_buffer = i; - -} /* end of mgsl_load_tx_dma_buffer() */ - -/* - * mgsl_register_test() - * - * Performs a register test of the 16C32. - * - * Arguments: info pointer to device instance data - * Return Value: true if test passed, otherwise false - */ -static bool mgsl_register_test( struct mgsl_struct *info ) -{ - static unsigned short BitPatterns[] = - { 0x0000, 0xffff, 0xaaaa, 0x5555, 0x1234, 0x6969, 0x9696, 0x0f0f }; - static unsigned int Patterncount = ARRAY_SIZE(BitPatterns); - unsigned int i; - bool rc = true; - unsigned long flags; - - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_reset(info); - - /* Verify the reset state of some registers. */ - - if ( (usc_InReg( info, SICR ) != 0) || - (usc_InReg( info, IVR ) != 0) || - (usc_InDmaReg( info, DIVR ) != 0) ){ - rc = false; - } - - if ( rc ){ - /* Write bit patterns to various registers but do it out of */ - /* sync, then read back and verify values. */ - - for ( i = 0 ; i < Patterncount ; i++ ) { - usc_OutReg( info, TC0R, BitPatterns[i] ); - usc_OutReg( info, TC1R, BitPatterns[(i+1)%Patterncount] ); - usc_OutReg( info, TCLR, BitPatterns[(i+2)%Patterncount] ); - usc_OutReg( info, RCLR, BitPatterns[(i+3)%Patterncount] ); - usc_OutReg( info, RSR, BitPatterns[(i+4)%Patterncount] ); - usc_OutDmaReg( info, TBCR, BitPatterns[(i+5)%Patterncount] ); - - if ( (usc_InReg( info, TC0R ) != BitPatterns[i]) || - (usc_InReg( info, TC1R ) != BitPatterns[(i+1)%Patterncount]) || - (usc_InReg( info, TCLR ) != BitPatterns[(i+2)%Patterncount]) || - (usc_InReg( info, RCLR ) != BitPatterns[(i+3)%Patterncount]) || - (usc_InReg( info, RSR ) != BitPatterns[(i+4)%Patterncount]) || - (usc_InDmaReg( info, TBCR ) != BitPatterns[(i+5)%Patterncount]) ){ - rc = false; - break; - } - } - } - - usc_reset(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - return rc; - -} /* end of mgsl_register_test() */ - -/* mgsl_irq_test() Perform interrupt test of the 16C32. - * - * Arguments: info pointer to device instance data - * Return Value: true if test passed, otherwise false - */ -static bool mgsl_irq_test( struct mgsl_struct *info ) -{ - unsigned long EndTime; - unsigned long flags; - - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_reset(info); - - /* - * Setup 16C32 to interrupt on TxC pin (14MHz clock) transition. - * The ISR sets irq_occurred to true. - */ - - info->irq_occurred = false; - - /* Enable INTEN gate for ISA adapter (Port 6, Bit12) */ - /* Enable INTEN (Port 6, Bit12) */ - /* This connects the IRQ request signal to the ISA bus */ - /* on the ISA adapter. This has no effect for the PCI adapter */ - usc_OutReg( info, PCR, (unsigned short)((usc_InReg(info, PCR) | BIT13) & ~BIT12) ); - - usc_EnableMasterIrqBit(info); - usc_EnableInterrupts(info, IO_PIN); - usc_ClearIrqPendingBits(info, IO_PIN); - - usc_UnlatchIostatusBits(info, MISCSTATUS_TXC_LATCHED); - usc_EnableStatusIrqs(info, SICR_TXC_ACTIVE + SICR_TXC_INACTIVE); - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - EndTime=100; - while( EndTime-- && !info->irq_occurred ) { - msleep_interruptible(10); - } - - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_reset(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - return info->irq_occurred; - -} /* end of mgsl_irq_test() */ - -/* mgsl_dma_test() - * - * Perform a DMA test of the 16C32. A small frame is - * transmitted via DMA from a transmit buffer to a receive buffer - * using single buffer DMA mode. - * - * Arguments: info pointer to device instance data - * Return Value: true if test passed, otherwise false - */ -static bool mgsl_dma_test( struct mgsl_struct *info ) -{ - unsigned short FifoLevel; - unsigned long phys_addr; - unsigned int FrameSize; - unsigned int i; - char *TmpPtr; - bool rc = true; - unsigned short status=0; - unsigned long EndTime; - unsigned long flags; - MGSL_PARAMS tmp_params; - - /* save current port options */ - memcpy(&tmp_params,&info->params,sizeof(MGSL_PARAMS)); - /* load default port options */ - memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); - -#define TESTFRAMESIZE 40 - - spin_lock_irqsave(&info->irq_spinlock,flags); - - /* setup 16C32 for SDLC DMA transfer mode */ - - usc_reset(info); - usc_set_sdlc_mode(info); - usc_enable_loopback(info,1); - - /* Reprogram the RDMR so that the 16C32 does NOT clear the count - * field of the buffer entry after fetching buffer address. This - * way we can detect a DMA failure for a DMA read (which should be - * non-destructive to system memory) before we try and write to - * memory (where a failure could corrupt system memory). - */ - - /* Receive DMA mode Register (RDMR) - * - * <15..14> 11 DMA mode = Linked List Buffer mode - * <13> 1 RSBinA/L = store Rx status Block in List entry - * <12> 0 1 = Clear count of List Entry after fetching - * <11..10> 00 Address mode = Increment - * <9> 1 Terminate Buffer on RxBound - * <8> 0 Bus Width = 16bits - * <7..0> ? status Bits (write as 0s) - * - * 1110 0010 0000 0000 = 0xe200 - */ - - usc_OutDmaReg( info, RDMR, 0xe200 ); - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - - /* SETUP TRANSMIT AND RECEIVE DMA BUFFERS */ - - FrameSize = TESTFRAMESIZE; - - /* setup 1st transmit buffer entry: */ - /* with frame size and transmit control word */ - - info->tx_buffer_list[0].count = FrameSize; - info->tx_buffer_list[0].rcc = FrameSize; - info->tx_buffer_list[0].status = 0x4000; - - /* build a transmit frame in 1st transmit DMA buffer */ - - TmpPtr = info->tx_buffer_list[0].virt_addr; - for (i = 0; i < FrameSize; i++ ) - *TmpPtr++ = i; - - /* setup 1st receive buffer entry: */ - /* clear status, set max receive buffer size */ - - info->rx_buffer_list[0].status = 0; - info->rx_buffer_list[0].count = FrameSize + 4; - - /* zero out the 1st receive buffer */ - - memset( info->rx_buffer_list[0].virt_addr, 0, FrameSize + 4 ); - - /* Set count field of next buffer entries to prevent */ - /* 16C32 from using buffers after the 1st one. */ - - info->tx_buffer_list[1].count = 0; - info->rx_buffer_list[1].count = 0; - - - /***************************/ - /* Program 16C32 receiver. */ - /***************************/ - - spin_lock_irqsave(&info->irq_spinlock,flags); - - /* setup DMA transfers */ - usc_RTCmd( info, RTCmd_PurgeRxFifo ); - - /* program 16C32 receiver with physical address of 1st DMA buffer entry */ - phys_addr = info->rx_buffer_list[0].phys_entry; - usc_OutDmaReg( info, NRARL, (unsigned short)phys_addr ); - usc_OutDmaReg( info, NRARU, (unsigned short)(phys_addr >> 16) ); - - /* Clear the Rx DMA status bits (read RDMR) and start channel */ - usc_InDmaReg( info, RDMR ); - usc_DmaCmd( info, DmaCmd_InitRxChannel ); - - /* Enable Receiver (RMR <1..0> = 10) */ - usc_OutReg( info, RMR, (unsigned short)((usc_InReg(info, RMR) & 0xfffc) | 0x0002) ); - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - - /*************************************************************/ - /* WAIT FOR RECEIVER TO DMA ALL PARAMETERS FROM BUFFER ENTRY */ - /*************************************************************/ - - /* Wait 100ms for interrupt. */ - EndTime = jiffies + msecs_to_jiffies(100); - - for(;;) { - if (time_after(jiffies, EndTime)) { - rc = false; - break; - } - - spin_lock_irqsave(&info->irq_spinlock,flags); - status = usc_InDmaReg( info, RDMR ); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - if ( !(status & BIT4) && (status & BIT5) ) { - /* INITG (BIT 4) is inactive (no entry read in progress) AND */ - /* BUSY (BIT 5) is active (channel still active). */ - /* This means the buffer entry read has completed. */ - break; - } - } - - - /******************************/ - /* Program 16C32 transmitter. */ - /******************************/ - - spin_lock_irqsave(&info->irq_spinlock,flags); - - /* Program the Transmit Character Length Register (TCLR) */ - /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ - - usc_OutReg( info, TCLR, (unsigned short)info->tx_buffer_list[0].count ); - usc_RTCmd( info, RTCmd_PurgeTxFifo ); - - /* Program the address of the 1st DMA Buffer Entry in linked list */ - - phys_addr = info->tx_buffer_list[0].phys_entry; - usc_OutDmaReg( info, NTARL, (unsigned short)phys_addr ); - usc_OutDmaReg( info, NTARU, (unsigned short)(phys_addr >> 16) ); - - /* unlatch Tx status bits, and start transmit channel. */ - - usc_OutReg( info, TCSR, (unsigned short)(( usc_InReg(info, TCSR) & 0x0f00) | 0xfa) ); - usc_DmaCmd( info, DmaCmd_InitTxChannel ); - - /* wait for DMA controller to fill transmit FIFO */ - - usc_TCmd( info, TCmd_SelectTicrTxFifostatus ); - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - - /**********************************/ - /* WAIT FOR TRANSMIT FIFO TO FILL */ - /**********************************/ - - /* Wait 100ms */ - EndTime = jiffies + msecs_to_jiffies(100); - - for(;;) { - if (time_after(jiffies, EndTime)) { - rc = false; - break; - } - - spin_lock_irqsave(&info->irq_spinlock,flags); - FifoLevel = usc_InReg(info, TICR) >> 8; - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - if ( FifoLevel < 16 ) - break; - else - if ( FrameSize < 32 ) { - /* This frame is smaller than the entire transmit FIFO */ - /* so wait for the entire frame to be loaded. */ - if ( FifoLevel <= (32 - FrameSize) ) - break; - } - } - - - if ( rc ) - { - /* Enable 16C32 transmitter. */ - - spin_lock_irqsave(&info->irq_spinlock,flags); - - /* Transmit mode Register (TMR), <1..0> = 10, Enable Transmitter */ - usc_TCmd( info, TCmd_SendFrame ); - usc_OutReg( info, TMR, (unsigned short)((usc_InReg(info, TMR) & 0xfffc) | 0x0002) ); - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - - /******************************/ - /* WAIT FOR TRANSMIT COMPLETE */ - /******************************/ - - /* Wait 100ms */ - EndTime = jiffies + msecs_to_jiffies(100); - - /* While timer not expired wait for transmit complete */ - - spin_lock_irqsave(&info->irq_spinlock,flags); - status = usc_InReg( info, TCSR ); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - while ( !(status & (BIT6 | BIT5 | BIT4 | BIT2 | BIT1)) ) { - if (time_after(jiffies, EndTime)) { - rc = false; - break; - } - - spin_lock_irqsave(&info->irq_spinlock,flags); - status = usc_InReg( info, TCSR ); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - } - } - - - if ( rc ){ - /* CHECK FOR TRANSMIT ERRORS */ - if ( status & (BIT5 | BIT1) ) - rc = false; - } - - if ( rc ) { - /* WAIT FOR RECEIVE COMPLETE */ - - /* Wait 100ms */ - EndTime = jiffies + msecs_to_jiffies(100); - - /* Wait for 16C32 to write receive status to buffer entry. */ - status=info->rx_buffer_list[0].status; - while ( status == 0 ) { - if (time_after(jiffies, EndTime)) { - rc = false; - break; - } - status=info->rx_buffer_list[0].status; - } - } - - - if ( rc ) { - /* CHECK FOR RECEIVE ERRORS */ - status = info->rx_buffer_list[0].status; - - if ( status & (BIT8 | BIT3 | BIT1) ) { - /* receive error has occurred */ - rc = false; - } else { - if ( memcmp( info->tx_buffer_list[0].virt_addr , - info->rx_buffer_list[0].virt_addr, FrameSize ) ){ - rc = false; - } - } - } - - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_reset( info ); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - /* restore current port options */ - memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); - - return rc; - -} /* end of mgsl_dma_test() */ - -/* mgsl_adapter_test() - * - * Perform the register, IRQ, and DMA tests for the 16C32. - * - * Arguments: info pointer to device instance data - * Return Value: 0 if success, otherwise -ENODEV - */ -static int mgsl_adapter_test( struct mgsl_struct *info ) -{ - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):Testing device %s\n", - __FILE__,__LINE__,info->device_name ); - - if ( !mgsl_register_test( info ) ) { - info->init_error = DiagStatus_AddressFailure; - printk( "%s(%d):Register test failure for device %s Addr=%04X\n", - __FILE__,__LINE__,info->device_name, (unsigned short)(info->io_base) ); - return -ENODEV; - } - - if ( !mgsl_irq_test( info ) ) { - info->init_error = DiagStatus_IrqFailure; - printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n", - __FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) ); - return -ENODEV; - } - - if ( !mgsl_dma_test( info ) ) { - info->init_error = DiagStatus_DmaFailure; - printk( "%s(%d):DMA test failure for device %s DMA=%d\n", - __FILE__,__LINE__,info->device_name, (unsigned short)(info->dma_level) ); - return -ENODEV; - } - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):device %s passed diagnostics\n", - __FILE__,__LINE__,info->device_name ); - - return 0; - -} /* end of mgsl_adapter_test() */ - -/* mgsl_memory_test() - * - * Test the shared memory on a PCI adapter. - * - * Arguments: info pointer to device instance data - * Return Value: true if test passed, otherwise false - */ -static bool mgsl_memory_test( struct mgsl_struct *info ) -{ - static unsigned long BitPatterns[] = - { 0x0, 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; - unsigned long Patterncount = ARRAY_SIZE(BitPatterns); - unsigned long i; - unsigned long TestLimit = SHARED_MEM_ADDRESS_SIZE/sizeof(unsigned long); - unsigned long * TestAddr; - - TestAddr = (unsigned long *)info->memory_base; - - /* Test data lines with test pattern at one location. */ - - for ( i = 0 ; i < Patterncount ; i++ ) { - *TestAddr = BitPatterns[i]; - if ( *TestAddr != BitPatterns[i] ) - return false; - } - - /* Test address lines with incrementing pattern over */ - /* entire address range. */ - - for ( i = 0 ; i < TestLimit ; i++ ) { - *TestAddr = i * 4; - TestAddr++; - } - - TestAddr = (unsigned long *)info->memory_base; - - for ( i = 0 ; i < TestLimit ; i++ ) { - if ( *TestAddr != i * 4 ) - return false; - TestAddr++; - } - - memset( info->memory_base, 0, SHARED_MEM_ADDRESS_SIZE ); - - return true; - -} /* End Of mgsl_memory_test() */ - - -/* mgsl_load_pci_memory() - * - * Load a large block of data into the PCI shared memory. - * Use this instead of memcpy() or memmove() to move data - * into the PCI shared memory. - * - * Notes: - * - * This function prevents the PCI9050 interface chip from hogging - * the adapter local bus, which can starve the 16C32 by preventing - * 16C32 bus master cycles. - * - * The PCI9050 documentation says that the 9050 will always release - * control of the local bus after completing the current read - * or write operation. - * - * It appears that as long as the PCI9050 write FIFO is full, the - * PCI9050 treats all of the writes as a single burst transaction - * and will not release the bus. This causes DMA latency problems - * at high speeds when copying large data blocks to the shared - * memory. - * - * This function in effect, breaks the a large shared memory write - * into multiple transations by interleaving a shared memory read - * which will flush the write FIFO and 'complete' the write - * transation. This allows any pending DMA request to gain control - * of the local bus in a timely fasion. - * - * Arguments: - * - * TargetPtr pointer to target address in PCI shared memory - * SourcePtr pointer to source buffer for data - * count count in bytes of data to copy - * - * Return Value: None - */ -static void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr, - unsigned short count ) -{ - /* 16 32-bit writes @ 60ns each = 960ns max latency on local bus */ -#define PCI_LOAD_INTERVAL 64 - - unsigned short Intervalcount = count / PCI_LOAD_INTERVAL; - unsigned short Index; - unsigned long Dummy; - - for ( Index = 0 ; Index < Intervalcount ; Index++ ) - { - memcpy(TargetPtr, SourcePtr, PCI_LOAD_INTERVAL); - Dummy = *((volatile unsigned long *)TargetPtr); - TargetPtr += PCI_LOAD_INTERVAL; - SourcePtr += PCI_LOAD_INTERVAL; - } - - memcpy( TargetPtr, SourcePtr, count % PCI_LOAD_INTERVAL ); - -} /* End Of mgsl_load_pci_memory() */ - -static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit) -{ - int i; - int linecount; - if (xmit) - printk("%s tx data:\n",info->device_name); - else - printk("%s rx data:\n",info->device_name); - - while(count) { - if (count > 16) - linecount = 16; - else - linecount = 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; - } -} /* end of mgsl_trace_block() */ - -/* mgsl_tx_timeout() - * - * called when HDLC frame times out - * update stats and do tx completion processing - * - * Arguments: context pointer to device instance data - * Return Value: None - */ -static void mgsl_tx_timeout(struct timer_list *t) -{ - struct mgsl_struct *info = from_timer(info, t, tx_timer); - unsigned long flags; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_tx_timeout(%s)\n", - __FILE__,__LINE__,info->device_name); - if(info->tx_active && - (info->params.mode == MGSL_MODE_HDLC || - info->params.mode == MGSL_MODE_RAW) ) { - info->icount.txtimeout++; - } - spin_lock_irqsave(&info->irq_spinlock,flags); - info->tx_active = false; - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) - usc_loopmode_cancel_transmit( info ); - - spin_unlock_irqrestore(&info->irq_spinlock,flags); - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_tx_done(info); - else -#endif - mgsl_bh_transmit(info); - -} /* end of mgsl_tx_timeout() */ - -/* signal that there are no more frames to send, so that - * line is 'released' by echoing RxD to TxD when current - * transmission is complete (or immediately if no tx in progress). - */ -static int mgsl_loopmode_send_done( struct mgsl_struct * info ) -{ - unsigned long flags; - - spin_lock_irqsave(&info->irq_spinlock,flags); - if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) { - if (info->tx_active) - info->loopmode_send_done_requested = true; - else - usc_loopmode_send_done(info); - } - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - return 0; -} - -/* release the line by echoing RxD to TxD - * upon completion of a transmit frame - */ -static void usc_loopmode_send_done( struct mgsl_struct * info ) -{ - info->loopmode_send_done_requested = false; - /* clear CMR:13 to 0 to start echoing RxData to TxData */ - info->cmr_value &= ~BIT13; - usc_OutReg(info, CMR, info->cmr_value); -} - -/* abort a transmit in progress while in HDLC LoopMode - */ -static void usc_loopmode_cancel_transmit( struct mgsl_struct * info ) -{ - /* reset tx dma channel and purge TxFifo */ - usc_RTCmd( info, RTCmd_PurgeTxFifo ); - usc_DmaCmd( info, DmaCmd_ResetTxChannel ); - usc_loopmode_send_done( info ); -} - -/* for HDLC/SDLC LoopMode, setting CMR:13 after the transmitter is enabled - * is an Insert Into Loop action. Upon receipt of a GoAhead sequence (RxAbort) - * we must clear CMR:13 to begin repeating TxData to RxData - */ -static void usc_loopmode_insert_request( struct mgsl_struct * info ) -{ - info->loopmode_insert_requested = true; - - /* enable RxAbort irq. On next RxAbort, clear CMR:13 to - * begin repeating TxData on RxData (complete insertion) - */ - usc_OutReg( info, RICR, - (usc_InReg( info, RICR ) | RXSTATUS_ABORT_RECEIVED ) ); - - /* set CMR:13 to insert into loop on next GoAhead (RxAbort) */ - info->cmr_value |= BIT13; - usc_OutReg(info, CMR, info->cmr_value); -} - -/* return 1 if station is inserted into the loop, otherwise 0 - */ -static int usc_loopmode_active( struct mgsl_struct * info) -{ - return usc_InReg( info, CCSR ) & BIT7 ? 1 : 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 mgsl_struct *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; - - 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) - mgsl_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 mgsl_struct *info = dev_to_port(dev); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); - - /* stop sending until this frame completes */ - netif_stop_queue(dev); - - /* copy data to device buffers */ - info->xmit_cnt = skb->len; - mgsl_load_tx_dma_buffer(info, skb->data, skb->len); - - /* update network statistics */ - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - /* done with socket buffer, so free it */ - dev_kfree_skb(skb); - - /* save start time for transmit timeout detection */ - netif_trans_update(dev); - - /* start hardware transmitter if necessary */ - spin_lock_irqsave(&info->irq_spinlock,flags); - if (!info->tx_active) - usc_start_transmitter(info); - spin_unlock_irqrestore(&info->irq_spinlock,flags); - - 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 mgsl_struct *info = dev_to_port(dev); - int rc; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); - - /* generic HDLC layer open processing */ - rc = hdlc_open(dev); - if (rc) - return rc; - - /* arbitrate between network and tty opens */ - spin_lock_irqsave(&info->netlock, flags); - if (info->port.count != 0 || info->netcount != 0) { - printk(KERN_WARNING "%s: hdlc_open returning 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(info)) != 0) { - 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->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; - mgsl_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->irq_spinlock, flags); - usc_get_serial_signals(info); - spin_unlock_irqrestore(&info->irq_spinlock, flags); - if (info->serial_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 mgsl_struct *info = dev_to_port(dev); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); - - netif_stop_queue(dev); - - /* shutdown adapter and release resources */ - shutdown(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 ifreq *ifr, int cmd) -{ - const size_t size = sizeof(sync_serial_settings); - sync_serial_settings new_line; - sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; - struct mgsl_struct *info = dev_to_port(dev); - unsigned int flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); - - /* return error if TTY interface open */ - if (info->port.count) - return -EBUSY; - - if (cmd != SIOCWANDEV) - return hdlc_ioctl(dev, ifr, cmd); - - switch(ifr->ifr_settings.type) { - case IF_GET_IFACE: /* return current sync_serial_settings */ - - ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; - if (ifr->ifr_settings.size < size) { - ifr->ifr_settings.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); - - memset(&new_line, 0, sizeof(new_line)); - 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) - mgsl_program_hw(info); - return 0; - - default: - return hdlc_ioctl(dev, ifr, cmd); - } -} - -/** - * 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 mgsl_struct *info = dev_to_port(dev); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("hdlcdev_tx_timeout(%s)\n",dev->name); - - dev->stats.tx_errors++; - dev->stats.tx_aborted_errors++; - - spin_lock_irqsave(&info->irq_spinlock,flags); - usc_stop_transmitter(info); - spin_unlock_irqrestore(&info->irq_spinlock,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 mgsl_struct *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 mgsl_struct *info, char *buf, int size) -{ - struct sk_buff *skb = dev_alloc_skb(size); - struct net_device *dev = info->netdev; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("hdlcdev_rx(%s)\n", dev->name); - - if (skb == NULL) { - printk(KERN_NOTICE "%s: can't alloc skb, dropping 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_do_ioctl = 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 mgsl_struct *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 allocation failure\n",__FILE__); - return -ENOMEM; - } - - /* for network layer reporting purposes only */ - dev->base_addr = info->io_base; - dev->irq = info->irq_level; - dev->dma = info->dma_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 mgsl_struct *info) -{ - unregister_hdlc_device(info->netdev); - free_netdev(info->netdev); - info->netdev = NULL; -} - -#endif /* CONFIG_HDLC */ - - -static int synclink_init_one (struct pci_dev *dev, - const struct pci_device_id *ent) -{ - struct mgsl_struct *info; - - if (pci_enable_device(dev)) { - printk("error enabling pci device %p\n", dev); - return -EIO; - } - - info = mgsl_allocate_device(); - if (!info) { - printk("can't allocate device instance data.\n"); - return -EIO; - } - - /* Copy user configuration info to device instance data */ - - info->io_base = pci_resource_start(dev, 2); - info->irq_level = dev->irq; - info->phys_memory_base = pci_resource_start(dev, 3); - - /* Because veremap only works on page boundaries we must map - * a larger area than is actually implemented for the LCR - * memory range. We map a full page starting at the page boundary. - */ - info->phys_lcr_base = pci_resource_start(dev, 0); - info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1); - info->phys_lcr_base &= ~(PAGE_SIZE-1); - - info->io_addr_size = 8; - info->irq_flags = IRQF_SHARED; - - if (dev->device == 0x0210) { - /* Version 1 PCI9030 based universal PCI adapter */ - info->misc_ctrl_value = 0x007c4080; - info->hw_version = 1; - } else { - /* Version 0 PCI9050 based 5V PCI adapter - * A PCI9050 bug prevents reading LCR registers if - * LCR base address bit 7 is set. Maintain shadow - * value so we can write to LCR misc control reg. - */ - info->misc_ctrl_value = 0x087e4546; - info->hw_version = 0; - } - - mgsl_add_device(info); - - return 0; -} - -static void synclink_remove_one (struct pci_dev *dev) -{ -} - From 3d608a591b2b6a2cd81d6258df6d1766db05567e Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Thu, 5 Nov 2020 12:33:57 +0000 Subject: [PATCH 54/89] tty: Remove redundant synclinkmp driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A note from the vendor: "The hardware used with synclink.c and synclinkmp.c has not been manufactured for 15 years and was low volume. The chances of either driver still being in use is very low. Not even Microgate (me) has the ability to test either anymore (no hardware). I don’t know the policy about driver removal, but I think both could be removed without upsetting anyone." Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201105123357.708813-3-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- arch/powerpc/configs/ppc6xx_defconfig | 1 - drivers/tty/Kconfig | 14 - drivers/tty/Makefile | 1 - drivers/tty/synclinkmp.c | 5580 ------------------------- 4 files changed, 5596 deletions(-) delete mode 100644 drivers/tty/synclinkmp.c diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index c2052093f70c..e8ce81a5e60c 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -598,7 +598,6 @@ CONFIG_GAMEPORT_FM801=m CONFIG_SERIAL_NONSTANDARD=y CONFIG_ROCKETPORT=m CONFIG_CYCLADES=m -CONFIG_SYNCLINKMP=m CONFIG_SYNCLINK_GT=m CONFIG_NOZOMI=m CONFIG_N_HDLC=m diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 61bf4ba37c06..e15cd6b5bb99 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -259,20 +259,6 @@ 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 SYNCLINKMP - tristate "SyncLink Multiport support" - depends on SERIAL_NONSTANDARD && PCI - help - Enable support for the SyncLink Multiport (2 or 4 ports) - serial adapter, running asynchronous and HDLC communications up - to 2.048Mbps. Each ports is independently selectable for - RS-232, V.35, RS-449, RS-530, and X.21 - - This driver may be built as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called synclinkmp. If you want to do that, say M - here. - config SYNCLINK_GT tristate "SyncLink GT/AC support" depends on SERIAL_NONSTANDARD && PCI diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index f3dd47cad439..b3ccae932660 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -28,7 +28,6 @@ obj-$(CONFIG_NOZOMI) += nozomi.o obj-$(CONFIG_NULL_TTY) += ttynull.o obj-$(CONFIG_ROCKETPORT) += rocket.o obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o -obj-$(CONFIG_SYNCLINKMP) += synclinkmp.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/synclinkmp.c b/drivers/tty/synclinkmp.c deleted file mode 100644 index 0ca738f61a35..000000000000 --- a/drivers/tty/synclinkmp.c +++ /dev/null @@ -1,5580 +0,0 @@ -// SPDX-License-Identifier: GPL-1.0+ -/* - * $Id: synclinkmp.c,v 4.38 2005/07/15 13:29:44 paulkf Exp $ - * - * Device driver for Microgate SyncLink Multiport - * high speed multiprotocol serial adapter. - * - * written by Paul Fulghum for Microgate Corporation - * paulkf@microgate.com - * - * Microgate and SyncLink are trademarks of Microgate Corporation - * - * Derived from serial.c written by Theodore Ts'o and Linus Torvalds - * - * 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. - */ - -#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) -#if defined(__i386__) -# define BREAKPOINT() asm(" int $3"); -#else -# define BREAKPOINT() { } -#endif - -#define MAX_DEVICES 12 - -#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 <asm/io.h> -#include <asm/irq.h> -#include <asm/dma.h> -#include <linux/bitops.h> -#include <asm/types.h> -#include <linux/termios.h> -#include <linux/workqueue.h> -#include <linux/hdlc.h> -#include <linux/synclink.h> - -#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE)) -#define SYNCLINK_GENERIC_HDLC 1 -#else -#define SYNCLINK_GENERIC_HDLC 0 -#endif - -#define GET_USER(error,value,addr) error = get_user(value,addr) -#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 -#define PUT_USER(error,value,addr) error = put_user(value,addr) -#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 - -#include <linux/uaccess.h> - -static MGSL_PARAMS default_params = { - MGSL_MODE_HDLC, /* unsigned long mode */ - 0, /* unsigned char loopback; */ - HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ - HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ - 0, /* unsigned long clock_speed; */ - 0xff, /* unsigned char addr_filter; */ - HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ - HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ - HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ - 9600, /* unsigned long data_rate; */ - 8, /* unsigned char data_bits; */ - 1, /* unsigned char stop_bits; */ - ASYNC_PARITY_NONE /* unsigned char parity; */ -}; - -/* size in bytes of DMA data buffers */ -#define SCABUFSIZE 1024 -#define SCA_MEM_SIZE 0x40000 -#define SCA_BASE_SIZE 512 -#define SCA_REG_SIZE 16 -#define SCA_MAX_PORTS 4 -#define SCAMAXDESC 128 - -#define BUFFERLISTSIZE 4096 - -/* SCA-I style DMA buffer descriptor */ -typedef struct _SCADESC -{ - u16 next; /* lower l6 bits of next descriptor addr */ - u16 buf_ptr; /* lower 16 bits of buffer addr */ - u8 buf_base; /* upper 8 bits of buffer addr */ - u8 pad1; - u16 length; /* length of buffer */ - u8 status; /* status of buffer */ - u8 pad2; -} SCADESC, *PSCADESC; - -typedef struct _SCADESC_EX -{ - /* device driver bookkeeping section */ - char *virt_addr; /* virtual address of data buffer */ - u16 phys_entry; /* lower 16-bits of physical address of this descriptor */ -} SCADESC_EX, *PSCADESC_EX; - -/* The queue of BH actions to be performed */ - -#define BH_RECEIVE 1 -#define BH_TRANSMIT 2 -#define BH_STATUS 4 - -#define IO_PIN_SHUTDOWN_LIMIT 100 - -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 - */ -typedef struct _synclinkmp_info { - void *if_ptr; /* General purpose pointer (used by SPPP) */ - int magic; - struct tty_port port; - int line; - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ - - struct mgsl_icount icount; - - int timeout; - int x_char; /* xon/xoff character */ - u16 read_status_mask1; /* break detection (SR1 indications) */ - u16 read_status_mask2; /* parity/framing/overun (SR2 indications) */ - unsigned char ignore_status_mask1; /* break detection (SR1 indications) */ - unsigned char ignore_status_mask2; /* parity/framing/overun (SR2 indications) */ - unsigned char *tx_buf; - int tx_put; - int tx_get; - int tx_count; - - wait_queue_head_t status_event_wait_q; - wait_queue_head_t event_wait_q; - struct timer_list tx_timer; /* HDLC transmit timeout timer */ - struct _synclinkmp_info *next_device; /* device list link */ - struct timer_list status_timer; /* input signal status check timer */ - - spinlock_t lock; /* spinlock for synchronizing with ISR */ - struct work_struct task; /* task structure for scheduling bh */ - - u32 max_frame_size; /* as set by device config */ - - u32 pending_bh; - - bool bh_running; /* Protection from multiple */ - int isr_overflow; - bool bh_requested; - - 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 *buffer_list; /* virtual address of Rx & Tx buffer lists */ - unsigned long buffer_list_phys; - - unsigned int rx_buf_count; /* count of total allocated Rx buffers */ - SCADESC *rx_buf_list; /* list of receive buffer entries */ - SCADESC_EX rx_buf_list_ex[SCAMAXDESC]; /* list of receive buffer entries */ - unsigned int current_rx_buf; - - unsigned int tx_buf_count; /* count of total allocated Tx buffers */ - SCADESC *tx_buf_list; /* list of transmit buffer entries */ - SCADESC_EX tx_buf_list_ex[SCAMAXDESC]; /* list of transmit buffer entries */ - unsigned int last_tx_buf; - - unsigned char *tmp_rx_buf; - unsigned int tmp_rx_buf_count; - - bool rx_enabled; - bool rx_overflow; - - bool tx_enabled; - bool tx_active; - u32 idle_mode; - - unsigned char ie0_value; - unsigned char ie1_value; - unsigned char ie2_value; - unsigned char ctrlreg_value; - unsigned char old_signals; - - char device_name[25]; /* device instance name */ - - int port_count; - int adapter_num; - int port_num; - - struct _synclinkmp_info *port_array[SCA_MAX_PORTS]; - - unsigned int bus_type; /* expansion bus type (ISA,EISA,PCI) */ - - unsigned int irq_level; /* interrupt level */ - unsigned long irq_flags; - bool irq_requested; /* true if IRQ requested */ - - MGSL_PARAMS params; /* communications parameters */ - - unsigned char serial_signals; /* current serial signal states */ - - bool irq_occurred; /* for diagnostics use */ - unsigned int init_error; /* Initialization startup error */ - - u32 last_mem_alloc; - unsigned char* memory_base; /* shared memory address (PCI only) */ - u32 phys_memory_base; - int shared_mem_requested; - - unsigned char* sca_base; /* HD64570 SCA Memory address */ - u32 phys_sca_base; - u32 sca_offset; - bool sca_base_requested; - - unsigned char* lcr_base; /* local config registers (PCI only) */ - u32 phys_lcr_base; - u32 lcr_offset; - int lcr_mem_requested; - - unsigned char* statctrl_base; /* status/control register memory */ - u32 phys_statctrl_base; - u32 statctrl_offset; - bool sca_statctrl_requested; - - u32 misc_ctrl_value; - char *flag_buf; - bool drop_rts_on_tx_done; - - struct _input_signal_events input_signal_events; - - /* SPPP/Cisco HDLC device parts */ - int netcount; - spinlock_t netlock; - -#if SYNCLINK_GENERIC_HDLC - struct net_device *netdev; -#endif - -} SLMP_INFO; - -#define MGSL_MAGIC 0x5401 - -/* - * define serial signal status change macros - */ -#define MISCSTATUS_DCD_LATCHED (SerialSignal_DCD<<8) /* indicates change in DCD */ -#define MISCSTATUS_RI_LATCHED (SerialSignal_RI<<8) /* indicates change in RI */ -#define MISCSTATUS_CTS_LATCHED (SerialSignal_CTS<<8) /* indicates change in CTS */ -#define MISCSTATUS_DSR_LATCHED (SerialSignal_DSR<<8) /* change in DSR */ - -/* Common Register macros */ -#define LPR 0x00 -#define PABR0 0x02 -#define PABR1 0x03 -#define WCRL 0x04 -#define WCRM 0x05 -#define WCRH 0x06 -#define DPCR 0x08 -#define DMER 0x09 -#define ISR0 0x10 -#define ISR1 0x11 -#define ISR2 0x12 -#define IER0 0x14 -#define IER1 0x15 -#define IER2 0x16 -#define ITCR 0x18 -#define INTVR 0x1a -#define IMVR 0x1c - -/* MSCI Register macros */ -#define TRB 0x20 -#define TRBL 0x20 -#define TRBH 0x21 -#define SR0 0x22 -#define SR1 0x23 -#define SR2 0x24 -#define SR3 0x25 -#define FST 0x26 -#define IE0 0x28 -#define IE1 0x29 -#define IE2 0x2a -#define FIE 0x2b -#define CMD 0x2c -#define MD0 0x2e -#define MD1 0x2f -#define MD2 0x30 -#define CTL 0x31 -#define SA0 0x32 -#define SA1 0x33 -#define IDL 0x34 -#define TMC 0x35 -#define RXS 0x36 -#define TXS 0x37 -#define TRC0 0x38 -#define TRC1 0x39 -#define RRC 0x3a -#define CST0 0x3c -#define CST1 0x3d - -/* Timer Register Macros */ -#define TCNT 0x60 -#define TCNTL 0x60 -#define TCNTH 0x61 -#define TCONR 0x62 -#define TCONRL 0x62 -#define TCONRH 0x63 -#define TMCS 0x64 -#define TEPR 0x65 - -/* DMA Controller Register macros */ -#define DARL 0x80 -#define DARH 0x81 -#define DARB 0x82 -#define BAR 0x80 -#define BARL 0x80 -#define BARH 0x81 -#define BARB 0x82 -#define SAR 0x84 -#define SARL 0x84 -#define SARH 0x85 -#define SARB 0x86 -#define CPB 0x86 -#define CDA 0x88 -#define CDAL 0x88 -#define CDAH 0x89 -#define EDA 0x8a -#define EDAL 0x8a -#define EDAH 0x8b -#define BFL 0x8c -#define BFLL 0x8c -#define BFLH 0x8d -#define BCR 0x8e -#define BCRL 0x8e -#define BCRH 0x8f -#define DSR 0x90 -#define DMR 0x91 -#define FCT 0x93 -#define DIR 0x94 -#define DCMD 0x95 - -/* combine with timer or DMA register address */ -#define TIMER0 0x00 -#define TIMER1 0x08 -#define TIMER2 0x10 -#define TIMER3 0x18 -#define RXDMA 0x00 -#define TXDMA 0x20 - -/* SCA Command Codes */ -#define NOOP 0x00 -#define TXRESET 0x01 -#define TXENABLE 0x02 -#define TXDISABLE 0x03 -#define TXCRCINIT 0x04 -#define TXCRCEXCL 0x05 -#define TXEOM 0x06 -#define TXABORT 0x07 -#define MPON 0x08 -#define TXBUFCLR 0x09 -#define RXRESET 0x11 -#define RXENABLE 0x12 -#define RXDISABLE 0x13 -#define RXCRCINIT 0x14 -#define RXREJECT 0x15 -#define SEARCHMP 0x16 -#define RXCRCEXCL 0x17 -#define RXCRCCALC 0x18 -#define CHRESET 0x21 -#define HUNT 0x31 - -/* DMA command codes */ -#define SWABORT 0x01 -#define FEICLEAR 0x02 - -/* IE0 */ -#define TXINTE BIT7 -#define RXINTE BIT6 -#define TXRDYE BIT1 -#define RXRDYE BIT0 - -/* IE1 & SR1 */ -#define UDRN BIT7 -#define IDLE BIT6 -#define SYNCD BIT4 -#define FLGD BIT4 -#define CCTS BIT3 -#define CDCD BIT2 -#define BRKD BIT1 -#define ABTD BIT1 -#define GAPD BIT1 -#define BRKE BIT0 -#define IDLD BIT0 - -/* IE2 & SR2 */ -#define EOM BIT7 -#define PMP BIT6 -#define SHRT BIT6 -#define PE BIT5 -#define ABT BIT5 -#define FRME BIT4 -#define RBIT BIT4 -#define OVRN BIT3 -#define CRCE BIT2 - - -/* - * Global linked list of SyncLink devices - */ -static SLMP_INFO *synclinkmp_device_list = NULL; -static int synclinkmp_adapter_count = -1; -static int synclinkmp_device_count = 0; - -/* - * Set this param to non-zero to load eax with the - * .text section address and breakpoint on module load. - * This is useful for use with gdb and add-symbol-file command. - */ -static bool break_on_load = 0; - -/* - * Driver major number, defaults to zero to get auto - * assigned major number. May be forced as module parameter. - */ -static int ttymajor = 0; - -/* - * Array of user specified options for ISA adapters. - */ -static int debug_level = 0; -static int maxframe[MAX_DEVICES] = {0,}; - -module_param(break_on_load, bool, 0); -module_param(ttymajor, int, 0); -module_param(debug_level, int, 0); -module_param_array(maxframe, int, NULL, 0); - -static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 4.38 $"; - -static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); -static void synclinkmp_remove_one(struct pci_dev *dev); - -static const struct pci_device_id synclinkmp_pci_tbl[] = { - { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, }, /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, synclinkmp_pci_tbl); - -MODULE_LICENSE("GPL"); - -static struct pci_driver synclinkmp_pci_driver = { - .name = "synclinkmp", - .id_table = synclinkmp_pci_tbl, - .probe = synclinkmp_init_one, - .remove = synclinkmp_remove_one, -}; - - -static struct tty_driver *serial_driver; - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - - -/* tty callbacks */ - -static int open(struct tty_struct *tty, struct file * filp); -static void close(struct tty_struct *tty, struct file * filp); -static void hangup(struct tty_struct *tty); -static void set_termios(struct tty_struct *tty, struct ktermios *old_termios); - -static int write(struct tty_struct *tty, const unsigned char *buf, int count); -static int put_char(struct tty_struct *tty, unsigned char ch); -static void send_xchar(struct tty_struct *tty, char ch); -static void wait_until_sent(struct tty_struct *tty, int timeout); -static int write_room(struct tty_struct *tty); -static void flush_chars(struct tty_struct *tty); -static void flush_buffer(struct tty_struct *tty); -static void tx_hold(struct tty_struct *tty); -static void tx_release(struct tty_struct *tty); - -static int ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static int chars_in_buffer(struct tty_struct *tty); -static void throttle(struct tty_struct * tty); -static void unthrottle(struct tty_struct * tty); -static int set_break(struct tty_struct *tty, int break_state); - -#if SYNCLINK_GENERIC_HDLC -#define dev_to_port(D) (dev_to_hdlc(D)->priv) -static void hdlcdev_tx_done(SLMP_INFO *info); -static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size); -static int hdlcdev_init(SLMP_INFO *info); -static void hdlcdev_exit(SLMP_INFO *info); -#endif - -/* ioctl handlers */ - -static int get_stats(SLMP_INFO *info, struct mgsl_icount __user *user_icount); -static int get_params(SLMP_INFO *info, MGSL_PARAMS __user *params); -static int set_params(SLMP_INFO *info, MGSL_PARAMS __user *params); -static int get_txidle(SLMP_INFO *info, int __user *idle_mode); -static int set_txidle(SLMP_INFO *info, int idle_mode); -static int tx_enable(SLMP_INFO *info, int enable); -static int tx_abort(SLMP_INFO *info); -static int rx_enable(SLMP_INFO *info, int enable); -static int modem_input_wait(SLMP_INFO *info,int arg); -static int wait_mgsl_event(SLMP_INFO *info, int __user *mask_ptr); -static int tiocmget(struct tty_struct *tty); -static int tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int set_break(struct tty_struct *tty, int break_state); - -static int add_device(SLMP_INFO *info); -static int device_init(int adapter_num, struct pci_dev *pdev); -static int claim_resources(SLMP_INFO *info); -static void release_resources(SLMP_INFO *info); - -static int startup(SLMP_INFO *info); -static int block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info); -static int carrier_raised(struct tty_port *port); -static void shutdown(SLMP_INFO *info); -static void program_hw(SLMP_INFO *info); -static void change_params(SLMP_INFO *info); - -static bool init_adapter(SLMP_INFO *info); -static bool register_test(SLMP_INFO *info); -static bool irq_test(SLMP_INFO *info); -static bool loopback_test(SLMP_INFO *info); -static int adapter_test(SLMP_INFO *info); -static bool memory_test(SLMP_INFO *info); - -static void reset_adapter(SLMP_INFO *info); -static void reset_port(SLMP_INFO *info); -static void async_mode(SLMP_INFO *info); -static void hdlc_mode(SLMP_INFO *info); - -static void rx_stop(SLMP_INFO *info); -static void rx_start(SLMP_INFO *info); -static void rx_reset_buffers(SLMP_INFO *info); -static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last); -static bool rx_get_frame(SLMP_INFO *info); - -static void tx_start(SLMP_INFO *info); -static void tx_stop(SLMP_INFO *info); -static void tx_load_fifo(SLMP_INFO *info); -static void tx_set_idle(SLMP_INFO *info); -static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count); - -static void get_signals(SLMP_INFO *info); -static void set_signals(SLMP_INFO *info); -static void enable_loopback(SLMP_INFO *info, int enable); -static void set_rate(SLMP_INFO *info, u32 data_rate); - -static int bh_action(SLMP_INFO *info); -static void bh_handler(struct work_struct *work); -static void bh_receive(SLMP_INFO *info); -static void bh_transmit(SLMP_INFO *info); -static void bh_status(SLMP_INFO *info); -static void isr_timer(SLMP_INFO *info); -static void isr_rxint(SLMP_INFO *info); -static void isr_rxrdy(SLMP_INFO *info); -static void isr_txint(SLMP_INFO *info); -static void isr_txrdy(SLMP_INFO *info); -static void isr_rxdmaok(SLMP_INFO *info); -static void isr_rxdmaerror(SLMP_INFO *info); -static void isr_txdmaok(SLMP_INFO *info); -static void isr_txdmaerror(SLMP_INFO *info); -static void isr_io_pin(SLMP_INFO *info, u16 status); - -static int alloc_dma_bufs(SLMP_INFO *info); -static void free_dma_bufs(SLMP_INFO *info); -static int alloc_buf_list(SLMP_INFO *info); -static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *list, SCADESC_EX *list_ex,int count); -static int alloc_tmp_rx_buf(SLMP_INFO *info); -static void free_tmp_rx_buf(SLMP_INFO *info); - -static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count); -static void trace_block(SLMP_INFO *info, const char* data, int count, int xmit); -static void tx_timeout(struct timer_list *t); -static void status_timeout(struct timer_list *t); - -static unsigned char read_reg(SLMP_INFO *info, unsigned char addr); -static void write_reg(SLMP_INFO *info, unsigned char addr, unsigned char val); -static u16 read_reg16(SLMP_INFO *info, unsigned char addr); -static void write_reg16(SLMP_INFO *info, unsigned char addr, u16 val); -static unsigned char read_status_reg(SLMP_INFO * info); -static void write_control_reg(SLMP_INFO * info); - - -static unsigned char rx_active_fifo_level = 16; // rx request FIFO activation level in bytes -static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation level in bytes -static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes - -static u32 misc_ctrl_value = 0x007e4040; -static u32 lcr1_brdr_value = 0x00800028; - -static u32 read_ahead_count = 8; - -/* DPCR, DMA Priority Control - * - * 07..05 Not used, must be 0 - * 04 BRC, bus release condition: 0=all transfers complete - * 1=release after 1 xfer on all channels - * 03 CCC, channel change condition: 0=every cycle - * 1=after each channel completes all xfers - * 02..00 PR<2..0>, priority 100=round robin - * - * 00000100 = 0x00 - */ -static unsigned char dma_priority = 0x04; - -// Number of bytes that can be written to shared RAM -// in a single write operation -static u32 sca_pci_load_interval = 64; - -/* - * 1st function defined in .text section. Calling this function in - * init_module() followed by a breakpoint allows a remote debugger - * (gdb) to get the .text address for the add-symbol-file command. - * This allows remote debugging of dynamically loadable modules. - */ -static void* synclinkmp_get_text_ptr(void); -static void* synclinkmp_get_text_ptr(void) {return synclinkmp_get_text_ptr;} - -static inline int sanity_check(SLMP_INFO *info, - char *name, const char *routine) -{ -#ifdef SANITY_CHECK - static const char *badmagic = - "Warning: bad magic number for synclinkmp_struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null synclinkmp_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != MGSL_MAGIC) { - printk(badmagic, name, routine); - 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 install(struct tty_driver *driver, struct tty_struct *tty) -{ - SLMP_INFO *info; - int line = tty->index; - - if (line >= synclinkmp_device_count) { - printk("%s(%d): open with invalid line #%d.\n", - __FILE__,__LINE__,line); - return -ENODEV; - } - - info = synclinkmp_device_list; - while (info && info->line != line) - info = info->next_device; - if (sanity_check(info, tty->name, "open")) - return -ENODEV; - if (info->init_error) { - printk("%s(%d):%s device is not allocated, init error=%d\n", - __FILE__, __LINE__, info->device_name, - info->init_error); - return -ENODEV; - } - - tty->driver_data = info; - - return tty_port_install(&info->port, driver, tty); -} - -/* Called when a port is opened. Init and enable port. - */ -static int open(struct tty_struct *tty, struct file *filp) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - int retval; - - info->port.tty = tty; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s open(), old ref count = %d\n", - __FILE__,__LINE__,tty->driver->name, info->port.count); - - info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - spin_lock_irqsave(&info->netlock, flags); - if (info->netcount) { - retval = -EBUSY; - spin_unlock_irqrestore(&info->netlock, flags); - 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(info); - if (retval < 0) - goto cleanup; - } - - retval = block_til_ready(tty, filp, info); - if (retval) { - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s block_til_ready() returned %d\n", - __FILE__,__LINE__, info->device_name, retval); - goto cleanup; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s open() success\n", - __FILE__,__LINE__, info->device_name); - 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--; - } - - return retval; -} - -/* Called when port is closed. Wait for remaining data to be - * sent. Disable port and free resources. - */ -static void close(struct tty_struct *tty, struct file *filp) -{ - SLMP_INFO * info = tty->driver_data; - - if (sanity_check(info, tty->name, "close")) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s close() entry, count=%d\n", - __FILE__,__LINE__, 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(info); - mutex_unlock(&info->port.mutex); - - tty_port_close_end(&info->port, tty); - info->port.tty = NULL; -cleanup: - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__, - tty->driver->name, info->port.count); -} - -/* Called by tty_hangup() when a hangup is signaled. - * This is the same as closing all open descriptors for the port. - */ -static void hangup(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s hangup()\n", - __FILE__,__LINE__, info->device_name ); - - if (sanity_check(info, tty->name, "hangup")) - return; - - mutex_lock(&info->port.mutex); - flush_buffer(tty); - shutdown(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, 1); - mutex_unlock(&info->port.mutex); - - wake_up_interruptible(&info->port.open_wait); -} - -/* Set new termios settings - */ -static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s set_termios()\n", __FILE__,__LINE__, - tty->driver->name ); - - change_params(info); - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - spin_lock_irqsave(&info->lock,flags); - set_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { - info->serial_signals |= SerialSignal_DTR; - if (!C_CRTSCTS(tty) || !tty_throttled(tty)) - info->serial_signals |= SerialSignal_RTS; - spin_lock_irqsave(&info->lock,flags); - set_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - } - - /* Handle turning off CRTSCTS */ - if (old_termios->c_cflag & CRTSCTS && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; - tx_release(tty); - } -} - -/* Send a block of data - * - * Arguments: - * - * tty pointer to tty information structure - * buf pointer to buffer containing send data - * count size of send data in bytes - * - * Return Value: number of characters written - */ -static int write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - int c, ret = 0; - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s write() count=%d\n", - __FILE__,__LINE__,info->device_name,count); - - if (sanity_check(info, tty->name, "write")) - goto cleanup; - - if (!info->tx_buf) - goto cleanup; - - if (info->params.mode == MGSL_MODE_HDLC) { - if (count > info->max_frame_size) { - ret = -EIO; - goto cleanup; - } - if (info->tx_active) - goto cleanup; - if (info->tx_count) { - /* send accumulated data from send_char() calls */ - /* as frame and wait before accepting more data. */ - tx_load_dma_buffer(info, info->tx_buf, info->tx_count); - goto start; - } - ret = info->tx_count = count; - tx_load_dma_buffer(info, buf, count); - goto start; - } - - for (;;) { - c = min_t(int, count, - min(info->max_frame_size - info->tx_count - 1, - info->max_frame_size - info->tx_put)); - if (c <= 0) - break; - - memcpy(info->tx_buf + info->tx_put, buf, c); - - spin_lock_irqsave(&info->lock,flags); - info->tx_put += c; - if (info->tx_put >= info->max_frame_size) - info->tx_put -= info->max_frame_size; - info->tx_count += c; - spin_unlock_irqrestore(&info->lock,flags); - - buf += c; - count -= c; - ret += c; - } - - if (info->params.mode == MGSL_MODE_HDLC) { - if (count) { - ret = info->tx_count = 0; - goto cleanup; - } - tx_load_dma_buffer(info, info->tx_buf, info->tx_count); - } -start: - if (info->tx_count && !tty->stopped && !tty->hw_stopped) { - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_active) - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - } - -cleanup: - if (debug_level >= DEBUG_LEVEL_INFO) - printk( "%s(%d):%s write() returning=%d\n", - __FILE__,__LINE__,info->device_name,ret); - return ret; -} - -/* Add a character to the transmit buffer. - */ -static int put_char(struct tty_struct *tty, unsigned char ch) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - int ret = 0; - - if ( debug_level >= DEBUG_LEVEL_INFO ) { - printk( "%s(%d):%s put_char(%d)\n", - __FILE__,__LINE__,info->device_name,ch); - } - - if (sanity_check(info, tty->name, "put_char")) - return 0; - - if (!info->tx_buf) - return 0; - - spin_lock_irqsave(&info->lock,flags); - - if ( (info->params.mode != MGSL_MODE_HDLC) || - !info->tx_active ) { - - if (info->tx_count < info->max_frame_size - 1) { - info->tx_buf[info->tx_put++] = ch; - if (info->tx_put >= info->max_frame_size) - info->tx_put -= info->max_frame_size; - info->tx_count++; - ret = 1; - } - } - - spin_unlock_irqrestore(&info->lock,flags); - return ret; -} - -/* Send a high-priority XON/XOFF character - */ -static void send_xchar(struct tty_struct *tty, char ch) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s send_xchar(%d)\n", - __FILE__,__LINE__, info->device_name, ch ); - - if (sanity_check(info, tty->name, "send_xchar")) - return; - - info->x_char = ch; - if (ch) { - /* Make sure transmit interrupts are on */ - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_enabled) - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - } -} - -/* Wait until the transmitter is empty. - */ -static void wait_until_sent(struct tty_struct *tty, int timeout) -{ - SLMP_INFO * info = tty->driver_data; - unsigned long orig_jiffies, char_time; - - if (!info ) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s wait_until_sent() entry\n", - __FILE__,__LINE__, info->device_name ); - - if (sanity_check(info, tty->name, "wait_until_sent")) - return; - - 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); - - if ( info->params.mode == MGSL_MODE_HDLC ) { - 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; - } - } else { - /* - * TODO: determine if there is something similar to USC16C32 - * TXSTATUS_ALL_SENT status - */ - while ( info->tx_active && info->tx_enabled) { - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - } - -exit: - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s wait_until_sent() exit\n", - __FILE__,__LINE__, info->device_name ); -} - -/* Return the count of free bytes in transmit buffer - */ -static int write_room(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - int ret; - - if (sanity_check(info, tty->name, "write_room")) - return 0; - - if (info->params.mode == MGSL_MODE_HDLC) { - ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; - } else { - ret = info->max_frame_size - info->tx_count - 1; - if (ret < 0) - ret = 0; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s write_room()=%d\n", - __FILE__, __LINE__, info->device_name, ret); - - return ret; -} - -/* enable transmitter and send remaining buffered characters - */ -static void flush_chars(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s flush_chars() entry tx_count=%d\n", - __FILE__,__LINE__,info->device_name,info->tx_count); - - if (sanity_check(info, tty->name, "flush_chars")) - return; - - if (info->tx_count <= 0 || tty->stopped || tty->hw_stopped || - !info->tx_buf) - return; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s flush_chars() entry, starting transmitter\n", - __FILE__,__LINE__,info->device_name ); - - spin_lock_irqsave(&info->lock,flags); - - if (!info->tx_active) { - if ( (info->params.mode == MGSL_MODE_HDLC) && - info->tx_count ) { - /* operating in synchronous (frame oriented) mode */ - /* copy data from circular tx_buf to */ - /* transmit DMA buffer. */ - tx_load_dma_buffer(info, - info->tx_buf,info->tx_count); - } - tx_start(info); - } - - spin_unlock_irqrestore(&info->lock,flags); -} - -/* Discard all data in the send buffer - */ -static void flush_buffer(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s flush_buffer() entry\n", - __FILE__,__LINE__, info->device_name ); - - if (sanity_check(info, tty->name, "flush_buffer")) - return; - - spin_lock_irqsave(&info->lock,flags); - info->tx_count = info->tx_put = info->tx_get = 0; - del_timer(&info->tx_timer); - spin_unlock_irqrestore(&info->lock,flags); - - tty_wakeup(tty); -} - -/* throttle (stop) transmitter - */ -static void tx_hold(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "tx_hold")) - return; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("%s(%d):%s tx_hold()\n", - __FILE__,__LINE__,info->device_name); - - spin_lock_irqsave(&info->lock,flags); - if (info->tx_enabled) - tx_stop(info); - spin_unlock_irqrestore(&info->lock,flags); -} - -/* release (start) transmitter - */ -static void tx_release(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (sanity_check(info, tty->name, "tx_release")) - return; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("%s(%d):%s tx_release()\n", - __FILE__,__LINE__,info->device_name); - - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_enabled) - tx_start(info); - 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 Value: 0 if success, otherwise error code - */ -static int ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - SLMP_INFO *info = tty->driver_data; - void __user *argp = (void __user *)arg; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s ioctl() cmd=%08X\n", __FILE__,__LINE__, - info->device_name, cmd ); - - if (sanity_check(info, tty->name, "ioctl")) - return -ENODEV; - - if (cmd != TIOCMIWAIT) { - if (tty_io_error(tty)) - return -EIO; - } - - switch (cmd) { - case MGSL_IOCGPARAMS: - return get_params(info, argp); - case MGSL_IOCSPARAMS: - return set_params(info, argp); - case MGSL_IOCGTXIDLE: - return get_txidle(info, argp); - case MGSL_IOCSTXIDLE: - return set_txidle(info, (int)arg); - case MGSL_IOCTXENABLE: - return tx_enable(info, (int)arg); - case MGSL_IOCRXENABLE: - return rx_enable(info, (int)arg); - case MGSL_IOCTXABORT: - return tx_abort(info); - case MGSL_IOCGSTATS: - return get_stats(info, argp); - case MGSL_IOCWAITEVENT: - return wait_mgsl_event(info, argp); - case MGSL_IOCLOOPTXDONE: - return 0; // TODO: Not supported, need to document - /* Wait for modem input (DCD,RI,DSR,CTS) change - * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS) - */ - case TIOCMIWAIT: - return modem_input_wait(info,(int)arg); - - /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static int get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - SLMP_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; -} - -/* - * /proc fs routines.... - */ - -static inline void line_info(struct seq_file *m, SLMP_INFO *info) -{ - char stat_buf[30]; - unsigned long flags; - - seq_printf(m, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n" - "\tIRQ=%d MaxFrameSize=%u\n", - info->device_name, - info->phys_sca_base, - info->phys_memory_base, - info->phys_statctrl_base, - info->phys_lcr_base, - info->irq_level, - info->max_frame_size ); - - /* output current serial signal states */ - spin_lock_irqsave(&info->lock,flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (info->serial_signals & SerialSignal_RTS) - strcat(stat_buf, "|RTS"); - if (info->serial_signals & SerialSignal_CTS) - strcat(stat_buf, "|CTS"); - if (info->serial_signals & SerialSignal_DTR) - strcat(stat_buf, "|DTR"); - if (info->serial_signals & SerialSignal_DSR) - strcat(stat_buf, "|DSR"); - if (info->serial_signals & SerialSignal_DCD) - strcat(stat_buf, "|CD"); - if (info->serial_signals & SerialSignal_RI) - strcat(stat_buf, "|RI"); - - if (info->params.mode == MGSL_MODE_HDLC) { - 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, " rxlong:%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 synclinkmp_proc_show(struct seq_file *m, void *v) -{ - SLMP_INFO *info; - - seq_printf(m, "synclinkmp driver:%s\n", driver_version); - - info = synclinkmp_device_list; - while( info ) { - line_info(m, info); - info = info->next_device; - } - return 0; -} - -/* Return the count of bytes in transmit buffer - */ -static int chars_in_buffer(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - - if (sanity_check(info, tty->name, "chars_in_buffer")) - return 0; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s chars_in_buffer()=%d\n", - __FILE__, __LINE__, info->device_name, info->tx_count); - - return info->tx_count; -} - -/* Signal remote device to throttle send data (our receive data) - */ -static void throttle(struct tty_struct * tty) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s throttle() entry\n", - __FILE__,__LINE__, info->device_name ); - - if (sanity_check(info, tty->name, "throttle")) - return; - - if (I_IXOFF(tty)) - send_xchar(tty, STOP_CHAR(tty)); - - if (C_CRTSCTS(tty)) { - spin_lock_irqsave(&info->lock,flags); - info->serial_signals &= ~SerialSignal_RTS; - set_signals(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) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s unthrottle() entry\n", - __FILE__,__LINE__, info->device_name ); - - if (sanity_check(info, tty->name, "unthrottle")) - return; - - 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->serial_signals |= SerialSignal_RTS; - set_signals(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) -{ - unsigned char RegValue; - SLMP_INFO * info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s set_break(%d)\n", - __FILE__,__LINE__, info->device_name, break_state); - - if (sanity_check(info, tty->name, "set_break")) - return -EINVAL; - - spin_lock_irqsave(&info->lock,flags); - RegValue = read_reg(info, CTL); - if (break_state == -1) - RegValue |= BIT3; - else - RegValue &= ~BIT3; - write_reg(info, CTL, RegValue); - 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) -{ - SLMP_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; - - 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 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) -{ - SLMP_INFO *info = dev_to_port(dev); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); - - /* stop sending until this frame completes */ - netif_stop_queue(dev); - - /* copy data to device buffers */ - info->tx_count = skb->len; - tx_load_dma_buffer(info, skb->data, skb->len); - - /* update network statistics */ - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - /* done with socket buffer, so free it */ - dev_kfree_skb(skb); - - /* save start time for transmit timeout detection */ - netif_trans_update(dev); - - /* start hardware transmitter if necessary */ - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_active) - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - - 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) -{ - SLMP_INFO *info = dev_to_port(dev); - int rc; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); - - /* generic HDLC layer open processing */ - rc = hdlc_open(dev); - if (rc) - return rc; - - /* arbitrate between network and tty opens */ - spin_lock_irqsave(&info->netlock, flags); - if (info->port.count != 0 || info->netcount != 0) { - printk(KERN_WARNING "%s: hdlc_open returning 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(info)) != 0) { - 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->serial_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_signals(info); - spin_unlock_irqrestore(&info->lock, flags); - if (info->serial_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) -{ - SLMP_INFO *info = dev_to_port(dev); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); - - netif_stop_queue(dev); - - /* shutdown adapter and release resources */ - shutdown(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 ifreq *ifr, int cmd) -{ - const size_t size = sizeof(sync_serial_settings); - sync_serial_settings new_line; - sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; - SLMP_INFO *info = dev_to_port(dev); - unsigned int flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); - - /* return error if TTY interface open */ - if (info->port.count) - return -EBUSY; - - if (cmd != SIOCWANDEV) - return hdlc_ioctl(dev, ifr, cmd); - - switch(ifr->ifr_settings.type) { - case IF_GET_IFACE: /* return current sync_serial_settings */ - - ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; - if (ifr->ifr_settings.size < size) { - ifr->ifr_settings.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); - - memset(&new_line, 0, sizeof(new_line)); - 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, ifr, cmd); - } -} - -/** - * 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) -{ - SLMP_INFO *info = dev_to_port(dev); - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("hdlcdev_tx_timeout(%s)\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(SLMP_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(SLMP_INFO *info, char *buf, int size) -{ - struct sk_buff *skb = dev_alloc_skb(size); - struct net_device *dev = info->netdev; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("hdlcdev_rx(%s)\n",dev->name); - - if (skb == NULL) { - printk(KERN_NOTICE "%s: can't alloc skb, dropping 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_do_ioctl = 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(SLMP_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 allocation failure\n",__FILE__); - return -ENOMEM; - } - - /* for network layer reporting purposes only */ - dev->mem_start = info->phys_sca_base; - dev->mem_end = info->phys_sca_base + SCA_BASE_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(SLMP_INFO *info) -{ - unregister_hdlc_device(info->netdev); - free_netdev(info->netdev); - info->netdev = NULL; -} - -#endif /* CONFIG_HDLC */ - - -/* Return next bottom half action to perform. - * Return Value: BH action code or 0 if nothing to do. - */ -static int bh_action(SLMP_INFO *info) -{ - unsigned long flags; - int rc = 0; - - 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; - } - - if (!rc) { - /* Mark BH routine as complete */ - info->bh_running = false; - info->bh_requested = false; - } - - spin_unlock_irqrestore(&info->lock,flags); - - return rc; -} - -/* Perform bottom half processing of work items queued by ISR. - */ -static void bh_handler(struct work_struct *work) -{ - SLMP_INFO *info = container_of(work, SLMP_INFO, task); - int action; - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):%s bh_handler() entry\n", - __FILE__,__LINE__,info->device_name); - - info->bh_running = true; - - while((action = bh_action(info)) != 0) { - - /* Process work item */ - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):%s bh_handler() work item action=%d\n", - __FILE__,__LINE__,info->device_name, action); - - switch (action) { - - case BH_RECEIVE: - bh_receive(info); - break; - case BH_TRANSMIT: - bh_transmit(info); - break; - case BH_STATUS: - bh_status(info); - break; - default: - /* unknown work item ID */ - printk("%s(%d):%s Unknown work item ID=%08X!\n", - __FILE__,__LINE__,info->device_name,action); - break; - } - } - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):%s bh_handler() exit\n", - __FILE__,__LINE__,info->device_name); -} - -static void bh_receive(SLMP_INFO *info) -{ - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):%s bh_receive()\n", - __FILE__,__LINE__,info->device_name); - - while( rx_get_frame(info) ); -} - -static void bh_transmit(SLMP_INFO *info) -{ - struct tty_struct *tty = info->port.tty; - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):%s bh_transmit() entry\n", - __FILE__,__LINE__,info->device_name); - - if (tty) - tty_wakeup(tty); -} - -static void bh_status(SLMP_INFO *info) -{ - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):%s bh_status() entry\n", - __FILE__,__LINE__,info->device_name); - - info->ri_chkcount = 0; - info->dsr_chkcount = 0; - info->dcd_chkcount = 0; - info->cts_chkcount = 0; -} - -static void isr_timer(SLMP_INFO * info) -{ - unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0; - - /* IER2<7..4> = timer<3..0> interrupt enables (0=disabled) */ - write_reg(info, IER2, 0); - - /* TMCS, Timer Control/Status Register - * - * 07 CMF, Compare match flag (read only) 1=match - * 06 ECMI, CMF Interrupt Enable: 0=disabled - * 05 Reserved, must be 0 - * 04 TME, Timer Enable - * 03..00 Reserved, must be 0 - * - * 0000 0000 - */ - write_reg(info, (unsigned char)(timer + TMCS), 0); - - info->irq_occurred = true; - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_timer()\n", - __FILE__,__LINE__,info->device_name); -} - -static void isr_rxint(SLMP_INFO * info) -{ - struct tty_struct *tty = info->port.tty; - struct mgsl_icount *icount = &info->icount; - unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD); - unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN; - - /* clear status bits */ - if (status) - write_reg(info, SR1, status); - - if (status2) - write_reg(info, SR2, status2); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_rxint status=%02X %02x\n", - __FILE__,__LINE__,info->device_name,status,status2); - - if (info->params.mode == MGSL_MODE_ASYNC) { - if (status & BRKD) { - icount->brk++; - - /* process break detection if tty control - * is not set to ignore it - */ - if (!(status & info->ignore_status_mask1)) { - if (info->read_status_mask1 & BRKD) { - tty_insert_flip_char(&info->port, 0, TTY_BREAK); - if (tty && (info->port.flags & ASYNC_SAK)) - do_SAK(tty); - } - } - } - } - else { - if (status & (FLGD|IDLD)) { - if (status & FLGD) - info->icount.exithunt++; - else if (status & IDLD) - info->icount.rxidle++; - wake_up_interruptible(&info->event_wait_q); - } - } - - if (status & CDCD) { - /* simulate a common modem status change interrupt - * for our handler - */ - get_signals( info ); - isr_io_pin(info, - MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD)); - } -} - -/* - * handle async rx data interrupts - */ -static void isr_rxrdy(SLMP_INFO * info) -{ - u16 status; - unsigned char DataByte; - struct mgsl_icount *icount = &info->icount; - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_rxrdy\n", - __FILE__,__LINE__,info->device_name); - - while((status = read_reg(info,CST0)) & BIT0) - { - int flag = 0; - bool over = false; - DataByte = read_reg(info,TRB); - - icount->rx++; - - if ( status & (PE + FRME + OVRN) ) { - printk("%s(%d):%s rxerr=%04X\n", - __FILE__,__LINE__,info->device_name,status); - - /* update error statistics */ - if (status & PE) - icount->parity++; - else if (status & FRME) - icount->frame++; - else if (status & OVRN) - icount->overrun++; - - /* discard char if tty control flags say so */ - if (status & info->ignore_status_mask2) - continue; - - status &= info->read_status_mask2; - - if (status & PE) - flag = TTY_PARITY; - else if (status & FRME) - flag = TTY_FRAME; - if (status & OVRN) { - /* Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - over = true; - } - } /* end of if (error) */ - - tty_insert_flip_char(&info->port, DataByte, flag); - if (over) - tty_insert_flip_char(&info->port, 0, TTY_OVERRUN); - } - - if ( debug_level >= DEBUG_LEVEL_ISR ) { - printk("%s(%d):%s rx=%d brk=%d parity=%d frame=%d overrun=%d\n", - __FILE__,__LINE__,info->device_name, - icount->rx,icount->brk,icount->parity, - icount->frame,icount->overrun); - } - - tty_flip_buffer_push(&info->port); -} - -static void isr_txeom(SLMP_INFO * info, unsigned char status) -{ - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_txeom status=%02x\n", - __FILE__,__LINE__,info->device_name,status); - - write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ - write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ - write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ - - if (status & UDRN) { - write_reg(info, CMD, TXRESET); - write_reg(info, CMD, TXENABLE); - } else - write_reg(info, CMD, TXBUFCLR); - - /* disable and clear tx interrupts */ - info->ie0_value &= ~TXRDYE; - info->ie1_value &= ~(IDLE + UDRN); - write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); - write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); - - if ( info->tx_active ) { - if (info->params.mode != MGSL_MODE_ASYNC) { - if (status & UDRN) - info->icount.txunder++; - else if (status & IDLE) - info->icount.txok++; - } - - info->tx_active = false; - info->tx_count = info->tx_put = info->tx_get = 0; - - del_timer(&info->tx_timer); - - if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done ) { - info->serial_signals &= ~SerialSignal_RTS; - info->drop_rts_on_tx_done = false; - set_signals(info); - } - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_tx_done(info); - else -#endif - { - if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) { - tx_stop(info); - return; - } - info->pending_bh |= BH_TRANSMIT; - } - } -} - - -/* - * handle tx status interrupts - */ -static void isr_txint(SLMP_INFO * info) -{ - unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS); - - /* clear status bits */ - write_reg(info, SR1, status); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_txint status=%02x\n", - __FILE__,__LINE__,info->device_name,status); - - if (status & (UDRN + IDLE)) - isr_txeom(info, status); - - if (status & CCTS) { - /* simulate a common modem status change interrupt - * for our handler - */ - get_signals( info ); - isr_io_pin(info, - MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS)); - - } -} - -/* - * handle async tx data interrupts - */ -static void isr_txrdy(SLMP_INFO * info) -{ - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_txrdy() tx_count=%d\n", - __FILE__,__LINE__,info->device_name,info->tx_count); - - if (info->params.mode != MGSL_MODE_ASYNC) { - /* disable TXRDY IRQ, enable IDLE IRQ */ - info->ie0_value &= ~TXRDYE; - info->ie1_value |= IDLE; - write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); - return; - } - - if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) { - tx_stop(info); - return; - } - - if ( info->tx_count ) - tx_load_fifo( info ); - else { - info->tx_active = false; - info->ie0_value &= ~TXRDYE; - write_reg(info, IE0, info->ie0_value); - } - - if (info->tx_count < WAKEUP_CHARS) - info->pending_bh |= BH_TRANSMIT; -} - -static void isr_rxdmaok(SLMP_INFO * info) -{ - /* BIT7 = EOT (end of transfer) - * BIT6 = EOM (end of message/frame) - */ - unsigned char status = read_reg(info,RXDMA + DSR) & 0xc0; - - /* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */ - write_reg(info, RXDMA + DSR, (unsigned char)(status | 1)); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_rxdmaok(), status=%02x\n", - __FILE__,__LINE__,info->device_name,status); - - info->pending_bh |= BH_RECEIVE; -} - -static void isr_rxdmaerror(SLMP_INFO * info) -{ - /* BIT5 = BOF (buffer overflow) - * BIT4 = COF (counter overflow) - */ - unsigned char status = read_reg(info,RXDMA + DSR) & 0x30; - - /* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */ - write_reg(info, RXDMA + DSR, (unsigned char)(status | 1)); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_rxdmaerror(), status=%02x\n", - __FILE__,__LINE__,info->device_name,status); - - info->rx_overflow = true; - info->pending_bh |= BH_RECEIVE; -} - -static void isr_txdmaok(SLMP_INFO * info) -{ - unsigned char status_reg1 = read_reg(info, SR1); - - write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ - write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ - write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_txdmaok(), status=%02x\n", - __FILE__,__LINE__,info->device_name,status_reg1); - - /* program TXRDY as FIFO empty flag, enable TXRDY IRQ */ - write_reg16(info, TRC0, 0); - info->ie0_value |= TXRDYE; - write_reg(info, IE0, info->ie0_value); -} - -static void isr_txdmaerror(SLMP_INFO * info) -{ - /* BIT5 = BOF (buffer overflow) - * BIT4 = COF (counter overflow) - */ - unsigned char status = read_reg(info,TXDMA + DSR) & 0x30; - - /* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */ - write_reg(info, TXDMA + DSR, (unsigned char)(status | 1)); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s isr_txdmaerror(), status=%02x\n", - __FILE__,__LINE__,info->device_name,status); -} - -/* handle input serial signal changes - */ -static void isr_io_pin( SLMP_INFO *info, u16 status ) -{ - struct mgsl_icount *icount; - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):isr_io_pin status=%04X\n", - __FILE__,__LINE__,status); - - if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED | - MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) { - icount = &info->icount; - /* update input line counters */ - if (status & MISCSTATUS_RI_LATCHED) { - icount->rng++; - if ( status & SerialSignal_RI ) - info->input_signal_events.ri_up++; - else - info->input_signal_events.ri_down++; - } - if (status & MISCSTATUS_DSR_LATCHED) { - icount->dsr++; - if ( status & SerialSignal_DSR ) - info->input_signal_events.dsr_up++; - else - info->input_signal_events.dsr_down++; - } - if (status & MISCSTATUS_DCD_LATCHED) { - if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) { - info->ie1_value &= ~CDCD; - write_reg(info, IE1, info->ie1_value); - } - icount->dcd++; - if (status & SerialSignal_DCD) { - info->input_signal_events.dcd_up++; - } else - info->input_signal_events.dcd_down++; -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) { - if (status & SerialSignal_DCD) - netif_carrier_on(info->netdev); - else - netif_carrier_off(info->netdev); - } -#endif - } - if (status & MISCSTATUS_CTS_LATCHED) - { - if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) { - info->ie1_value &= ~CCTS; - write_reg(info, IE1, info->ie1_value); - } - icount->cts++; - if ( status & SerialSignal_CTS ) - info->input_signal_events.cts_up++; - else - info->input_signal_events.cts_down++; - } - wake_up_interruptible(&info->status_event_wait_q); - wake_up_interruptible(&info->event_wait_q); - - if (tty_port_check_carrier(&info->port) && - (status & MISCSTATUS_DCD_LATCHED) ) { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s CD now %s...", info->device_name, - (status & SerialSignal_DCD) ? "on" : "off"); - if (status & SerialSignal_DCD) - wake_up_interruptible(&info->port.open_wait); - else { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("doing serial hangup..."); - if (info->port.tty) - tty_hangup(info->port.tty); - } - } - - if (tty_port_cts_enabled(&info->port) && - (status & MISCSTATUS_CTS_LATCHED) ) { - if ( info->port.tty ) { - if (info->port.tty->hw_stopped) { - if (status & SerialSignal_CTS) { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("CTS tx start..."); - info->port.tty->hw_stopped = 0; - tx_start(info); - info->pending_bh |= BH_TRANSMIT; - return; - } - } else { - if (!(status & SerialSignal_CTS)) { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("CTS tx stop..."); - info->port.tty->hw_stopped = 1; - tx_stop(info); - } - } - } - } - } - - info->pending_bh |= BH_STATUS; -} - -/* Interrupt service routine entry point. - * - * Arguments: - * irq interrupt number that caused interrupt - * dev_id device ID supplied during interrupt registration - * regs interrupted processor context - */ -static irqreturn_t synclinkmp_interrupt(int dummy, void *dev_id) -{ - SLMP_INFO *info = dev_id; - unsigned char status, status0, status1=0; - unsigned char dmastatus, dmastatus0, dmastatus1=0; - unsigned char timerstatus0, timerstatus1=0; - unsigned char shift; - unsigned int i; - unsigned short tmp; - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk(KERN_DEBUG "%s(%d): synclinkmp_interrupt(%d)entry.\n", - __FILE__, __LINE__, info->irq_level); - - spin_lock(&info->lock); - - for(;;) { - - /* get status for SCA0 (ports 0-1) */ - tmp = read_reg16(info, ISR0); /* get ISR0 and ISR1 in one read */ - status0 = (unsigned char)tmp; - dmastatus0 = (unsigned char)(tmp>>8); - timerstatus0 = read_reg(info, ISR2); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk(KERN_DEBUG "%s(%d):%s status0=%02x, dmastatus0=%02x, timerstatus0=%02x\n", - __FILE__, __LINE__, info->device_name, - status0, dmastatus0, timerstatus0); - - if (info->port_count == 4) { - /* get status for SCA1 (ports 2-3) */ - tmp = read_reg16(info->port_array[2], ISR0); - status1 = (unsigned char)tmp; - dmastatus1 = (unsigned char)(tmp>>8); - timerstatus1 = read_reg(info->port_array[2], ISR2); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s status1=%02x, dmastatus1=%02x, timerstatus1=%02x\n", - __FILE__,__LINE__,info->device_name, - status1,dmastatus1,timerstatus1); - } - - if (!status0 && !dmastatus0 && !timerstatus0 && - !status1 && !dmastatus1 && !timerstatus1) - break; - - for(i=0; i < info->port_count ; i++) { - if (info->port_array[i] == NULL) - continue; - if (i < 2) { - status = status0; - dmastatus = dmastatus0; - } else { - status = status1; - dmastatus = dmastatus1; - } - - shift = i & 1 ? 4 :0; - - if (status & BIT0 << shift) - isr_rxrdy(info->port_array[i]); - if (status & BIT1 << shift) - isr_txrdy(info->port_array[i]); - if (status & BIT2 << shift) - isr_rxint(info->port_array[i]); - if (status & BIT3 << shift) - isr_txint(info->port_array[i]); - - if (dmastatus & BIT0 << shift) - isr_rxdmaerror(info->port_array[i]); - if (dmastatus & BIT1 << shift) - isr_rxdmaok(info->port_array[i]); - if (dmastatus & BIT2 << shift) - isr_txdmaerror(info->port_array[i]); - if (dmastatus & BIT3 << shift) - isr_txdmaok(info->port_array[i]); - } - - if (timerstatus0 & (BIT5 | BIT4)) - isr_timer(info->port_array[0]); - if (timerstatus0 & (BIT7 | BIT6)) - isr_timer(info->port_array[1]); - if (timerstatus1 & (BIT5 | BIT4)) - isr_timer(info->port_array[2]); - if (timerstatus1 & (BIT7 | BIT6)) - isr_timer(info->port_array[3]); - } - - for(i=0; i < info->port_count ; i++) { - SLMP_INFO * port = info->port_array[i]; - - /* Request bottom half processing if there's something - * for it to do and the bh is not already running. - * - * Note: startup adapter diags require interrupts. - * do not request bottom half processing if the - * device is not open in a normal mode. - */ - if ( port && (port->port.count || port->netcount) && - port->pending_bh && !port->bh_running && - !port->bh_requested ) { - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk("%s(%d):%s queueing bh task.\n", - __FILE__,__LINE__,port->device_name); - schedule_work(&port->task); - port->bh_requested = true; - } - } - - spin_unlock(&info->lock); - - if ( debug_level >= DEBUG_LEVEL_ISR ) - printk(KERN_DEBUG "%s(%d):synclinkmp_interrupt(%d)exit.\n", - __FILE__, __LINE__, info->irq_level); - return IRQ_HANDLED; -} - -/* Initialize and start device. - */ -static int startup(SLMP_INFO * info) -{ - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,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) { - printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", - __FILE__,__LINE__,info->device_name); - return -ENOMEM; - } - } - - info->pending_bh = 0; - - memset(&info->icount, 0, sizeof(info->icount)); - - /* program hardware for current parameters */ - reset_port(info); - - change_params(info); - - mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10)); - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - tty_port_set_initialized(&info->port, 1); - - return 0; -} - -/* Called by close() and hangup() to shutdown hardware - */ -static void shutdown(SLMP_INFO * info) -{ - unsigned long flags; - - if (!tty_port_initialized(&info->port)) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s synclinkmp_shutdown()\n", - __FILE__,__LINE__, 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); - - del_timer(&info->tx_timer); - del_timer(&info->status_timer); - - kfree(info->tx_buf); - info->tx_buf = NULL; - - spin_lock_irqsave(&info->lock,flags); - - reset_port(info); - - if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) { - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_signals(info); - } - - 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, 0); -} - -static void program_hw(SLMP_INFO *info) -{ - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - - rx_stop(info); - tx_stop(info); - - info->tx_count = info->tx_put = info->tx_get = 0; - - if (info->params.mode == MGSL_MODE_HDLC || info->netcount) - hdlc_mode(info); - else - async_mode(info); - - set_signals(info); - - info->dcd_chkcount = 0; - info->cts_chkcount = 0; - info->ri_chkcount = 0; - info->dsr_chkcount = 0; - - info->ie1_value |= (CDCD|CCTS); - write_reg(info, IE1, info->ie1_value); - - get_signals(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(SLMP_INFO *info) -{ - unsigned cflag; - int bits_per_char; - - if (!info->port.tty) - return; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s change_params()\n", - __FILE__,__LINE__, 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->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; - else - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - - /* byte size and parity */ - - switch (cflag & CSIZE) { - case CS5: info->params.data_bits = 5; break; - case CS6: info->params.data_bits = 6; break; - case CS7: info->params.data_bits = 7; break; - case CS8: info->params.data_bits = 8; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: info->params.data_bits = 7; break; - } - - if (cflag & CSTOPB) - info->params.stop_bits = 2; - else - info->params.stop_bits = 1; - - info->params.parity = ASYNC_PARITY_NONE; - if (cflag & PARENB) { - if (cflag & PARODD) - info->params.parity = ASYNC_PARITY_ODD; - else - info->params.parity = ASYNC_PARITY_EVEN; -#ifdef CMSPAR - if (cflag & CMSPAR) - info->params.parity = ASYNC_PARITY_SPACE; -#endif - } - - /* 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; - - /* if port data rate is set to 460800 or less then - * allow tty settings to override, otherwise keep the - * current data rate. - */ - if (info->params.data_rate <= 460800) { - 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_mask2 = OVRN; - if (I_INPCK(info->port.tty)) - info->read_status_mask2 |= PE | FRME; - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) - info->read_status_mask1 |= BRKD; - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask2 |= PE | FRME; - if (I_IGNBRK(info->port.tty)) { - info->ignore_status_mask1 |= BRKD; - /* If ignoring parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask2 |= OVRN; - } - - program_hw(info); -} - -static int get_stats(SLMP_INFO * info, struct mgsl_icount __user *user_icount) -{ - int err; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s get_params()\n", - __FILE__,__LINE__, info->device_name); - - if (!user_icount) { - memset(&info->icount, 0, sizeof(info->icount)); - } else { - mutex_lock(&info->port.mutex); - COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); - mutex_unlock(&info->port.mutex); - if (err) - return -EFAULT; - } - - return 0; -} - -static int get_params(SLMP_INFO * info, MGSL_PARAMS __user *user_params) -{ - int err; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s get_params()\n", - __FILE__,__LINE__, info->device_name); - - mutex_lock(&info->port.mutex); - COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); - mutex_unlock(&info->port.mutex); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s get_params() user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; - } - - return 0; -} - -static int set_params(SLMP_INFO * info, MGSL_PARAMS __user *new_params) -{ - unsigned long flags; - MGSL_PARAMS tmp_params; - int err; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s set_params\n", - __FILE__,__LINE__,info->device_name ); - COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s set_params() user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; - } - - mutex_lock(&info->port.mutex); - spin_lock_irqsave(&info->lock,flags); - memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); - spin_unlock_irqrestore(&info->lock,flags); - - change_params(info); - mutex_unlock(&info->port.mutex); - - return 0; -} - -static int get_txidle(SLMP_INFO * info, int __user *idle_mode) -{ - int err; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s get_txidle()=%d\n", - __FILE__,__LINE__, info->device_name, info->idle_mode); - - COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s get_txidle() user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; - } - - return 0; -} - -static int set_txidle(SLMP_INFO * info, int idle_mode) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s set_txidle(%d)\n", - __FILE__,__LINE__,info->device_name, idle_mode ); - - spin_lock_irqsave(&info->lock,flags); - info->idle_mode = idle_mode; - tx_set_idle( info ); - spin_unlock_irqrestore(&info->lock,flags); - return 0; -} - -static int tx_enable(SLMP_INFO * info, int enable) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s tx_enable(%d)\n", - __FILE__,__LINE__,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 send HDLC frame - */ -static int tx_abort(SLMP_INFO * info) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s tx_abort()\n", - __FILE__,__LINE__,info->device_name); - - spin_lock_irqsave(&info->lock,flags); - if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC ) { - info->ie1_value &= ~UDRN; - info->ie1_value |= IDLE; - write_reg(info, IE1, info->ie1_value); /* disable tx status interrupts */ - write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); /* clear pending */ - - write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ - write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ - - write_reg(info, CMD, TXABORT); - } - spin_unlock_irqrestore(&info->lock,flags); - return 0; -} - -static int rx_enable(SLMP_INFO * info, int enable) -{ - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s rx_enable(%d)\n", - __FILE__,__LINE__,info->device_name,enable); - - spin_lock_irqsave(&info->lock,flags); - if ( enable ) { - if ( !info->rx_enabled ) - rx_start(info); - } 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(SLMP_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); - - COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); - if (rc) { - return -EFAULT; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s wait_mgsl_event(%d)\n", - __FILE__,__LINE__,info->device_name,mask); - - spin_lock_irqsave(&info->lock,flags); - - /* return immediately if state matches requested events */ - get_signals(info); - s = info->serial_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 char oldval = info->ie1_value; - unsigned char newval = oldval + - (mask & MgslEvent_ExitHuntMode ? FLGD:0) + - (mask & MgslEvent_IdleReceived ? IDLD:0); - if ( oldval != newval ) { - info->ie1_value = newval; - write_reg(info, IE1, info->ie1_value); - } - } - - 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 */ - info->ie1_value &= ~(FLGD|IDLD); - write_reg(info, IE1, info->ie1_value); - } - spin_unlock_irqrestore(&info->lock,flags); - } -exit: - if ( rc == 0 ) - PUT_USER(rc, events, mask_ptr); - - return rc; -} - -static int modem_input_wait(SLMP_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 the state of the serial control and status signals - */ -static int tiocmget(struct tty_struct *tty) -{ - SLMP_INFO *info = tty->driver_data; - unsigned int result; - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - - result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS : 0) | - ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR : 0) | - ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR : 0) | - ((info->serial_signals & SerialSignal_RI) ? TIOCM_RNG : 0) | - ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR : 0) | - ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS : 0); - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s tiocmget() value=%08X\n", - __FILE__,__LINE__, info->device_name, result ); - return result; -} - -/* set modem control signals (DTR/RTS) - */ -static int tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - SLMP_INFO *info = tty->driver_data; - unsigned long flags; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s tiocmset(%x,%x)\n", - __FILE__,__LINE__,info->device_name, set, clear); - - if (set & TIOCM_RTS) - info->serial_signals |= SerialSignal_RTS; - if (set & TIOCM_DTR) - info->serial_signals |= SerialSignal_DTR; - if (clear & TIOCM_RTS) - info->serial_signals &= ~SerialSignal_RTS; - if (clear & TIOCM_DTR) - info->serial_signals &= ~SerialSignal_DTR; - - spin_lock_irqsave(&info->lock,flags); - set_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - - return 0; -} - -static int carrier_raised(struct tty_port *port) -{ - SLMP_INFO *info = container_of(port, SLMP_INFO, port); - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - - return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; -} - -static void dtr_rts(struct tty_port *port, int on) -{ - SLMP_INFO *info = container_of(port, SLMP_INFO, port); - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - if (on) - info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR; - else - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_signals(info); - spin_unlock_irqrestore(&info->lock,flags); -} - -/* Block the current process until the specified port is ready to open. - */ -static int block_til_ready(struct tty_struct *tty, struct file *filp, - SLMP_INFO *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - bool do_clocal = false; - unsigned long flags; - int cd; - struct tty_port *port = &info->port; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s block_til_ready()\n", - __FILE__,__LINE__, tty->driver->name ); - - if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { - /* nonblock mode is set or port is not enabled */ - /* just verify that callout device is not active */ - tty_port_set_active(port, 1); - 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); - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s block_til_ready() before block, count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); - - 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; - } - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s block_til_ready() count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); - - 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 (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):%s block_til_ready() after, count=%d\n", - __FILE__,__LINE__, tty->driver->name, port->count ); - - if (!retval) - tty_port_set_active(port, 1); - - return retval; -} - -static int alloc_dma_bufs(SLMP_INFO *info) -{ - unsigned short BuffersPerFrame; - unsigned short BufferCount; - - // Force allocation to start at 64K boundary for each port. - // This is necessary because *all* buffer descriptors for a port - // *must* be in the same 64K block. All descriptors on a port - // share a common 'base' address (upper 8 bits of 24 bits) programmed - // into the CBP register. - info->port_array[0]->last_mem_alloc = (SCA_MEM_SIZE/4) * info->port_num; - - /* Calculate the number of DMA buffers necessary to hold the */ - /* largest allowable frame size. Note: If the max frame size is */ - /* not an even multiple of the DMA buffer size then we need to */ - /* round the buffer count per frame up one. */ - - BuffersPerFrame = (unsigned short)(info->max_frame_size/SCABUFSIZE); - if ( info->max_frame_size % SCABUFSIZE ) - BuffersPerFrame++; - - /* calculate total number of data buffers (SCABUFSIZE) possible - * in one ports memory (SCA_MEM_SIZE/4) after allocating memory - * for the descriptor list (BUFFERLISTSIZE). - */ - BufferCount = (SCA_MEM_SIZE/4 - BUFFERLISTSIZE)/SCABUFSIZE; - - /* limit number of buffers to maximum amount of descriptors */ - if (BufferCount > BUFFERLISTSIZE/sizeof(SCADESC)) - BufferCount = BUFFERLISTSIZE/sizeof(SCADESC); - - /* use enough buffers to transmit one max size frame */ - info->tx_buf_count = BuffersPerFrame + 1; - - /* never use more than half the available buffers for transmit */ - if (info->tx_buf_count > (BufferCount/2)) - info->tx_buf_count = BufferCount/2; - - if (info->tx_buf_count > SCAMAXDESC) - info->tx_buf_count = SCAMAXDESC; - - /* use remaining buffers for receive */ - info->rx_buf_count = BufferCount - info->tx_buf_count; - - if (info->rx_buf_count > SCAMAXDESC) - info->rx_buf_count = SCAMAXDESC; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk("%s(%d):%s Allocating %d TX and %d RX DMA buffers.\n", - __FILE__,__LINE__, info->device_name, - info->tx_buf_count,info->rx_buf_count); - - if ( alloc_buf_list( info ) < 0 || - alloc_frame_bufs(info, - info->rx_buf_list, - info->rx_buf_list_ex, - info->rx_buf_count) < 0 || - alloc_frame_bufs(info, - info->tx_buf_list, - info->tx_buf_list_ex, - info->tx_buf_count) < 0 || - alloc_tmp_rx_buf(info) < 0 ) { - printk("%s(%d):%s Can't allocate DMA buffer memory\n", - __FILE__,__LINE__, info->device_name); - return -ENOMEM; - } - - rx_reset_buffers( info ); - - return 0; -} - -/* Allocate DMA buffers for the transmit and receive descriptor lists. - */ -static int alloc_buf_list(SLMP_INFO *info) -{ - unsigned int i; - - /* build list in adapter shared memory */ - info->buffer_list = info->memory_base + info->port_array[0]->last_mem_alloc; - info->buffer_list_phys = info->port_array[0]->last_mem_alloc; - info->port_array[0]->last_mem_alloc += BUFFERLISTSIZE; - - memset(info->buffer_list, 0, BUFFERLISTSIZE); - - /* Save virtual address pointers to the receive and */ - /* transmit buffer lists. (Receive 1st). These pointers will */ - /* be used by the processor to access the lists. */ - info->rx_buf_list = (SCADESC *)info->buffer_list; - - info->tx_buf_list = (SCADESC *)info->buffer_list; - info->tx_buf_list += info->rx_buf_count; - - /* Build links for circular buffer entry lists (tx and rx) - * - * Note: links are physical addresses read by the SCA device - * to determine the next buffer entry to use. - */ - - for ( i = 0; i < info->rx_buf_count; i++ ) { - /* calculate and store physical address of this buffer entry */ - info->rx_buf_list_ex[i].phys_entry = - info->buffer_list_phys + (i * SCABUFSIZE); - - /* calculate and store physical address of */ - /* next entry in cirular list of entries */ - info->rx_buf_list[i].next = info->buffer_list_phys; - if ( i < info->rx_buf_count - 1 ) - info->rx_buf_list[i].next += (i + 1) * sizeof(SCADESC); - - info->rx_buf_list[i].length = SCABUFSIZE; - } - - for ( i = 0; i < info->tx_buf_count; i++ ) { - /* calculate and store physical address of this buffer entry */ - info->tx_buf_list_ex[i].phys_entry = info->buffer_list_phys + - ((info->rx_buf_count + i) * sizeof(SCADESC)); - - /* calculate and store physical address of */ - /* next entry in cirular list of entries */ - - info->tx_buf_list[i].next = info->buffer_list_phys + - info->rx_buf_count * sizeof(SCADESC); - - if ( i < info->tx_buf_count - 1 ) - info->tx_buf_list[i].next += (i + 1) * sizeof(SCADESC); - } - - return 0; -} - -/* Allocate the frame DMA buffers used by the specified buffer list. - */ -static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count) -{ - int i; - unsigned long phys_addr; - - for ( i = 0; i < count; i++ ) { - buf_list_ex[i].virt_addr = info->memory_base + info->port_array[0]->last_mem_alloc; - phys_addr = info->port_array[0]->last_mem_alloc; - info->port_array[0]->last_mem_alloc += SCABUFSIZE; - - buf_list[i].buf_ptr = (unsigned short)phys_addr; - buf_list[i].buf_base = (unsigned char)(phys_addr >> 16); - } - - return 0; -} - -static void free_dma_bufs(SLMP_INFO *info) -{ - info->buffer_list = NULL; - info->rx_buf_list = NULL; - info->tx_buf_list = NULL; -} - -/* allocate buffer large enough to hold max_frame_size. - * This buffer is used to pass an assembled frame to the line discipline. - */ -static int alloc_tmp_rx_buf(SLMP_INFO *info) -{ - info->tmp_rx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); - if (info->tmp_rx_buf == NULL) - return -ENOMEM; - /* unused flag buffer to satisfy receive_buf calling interface */ - info->flag_buf = kzalloc(info->max_frame_size, GFP_KERNEL); - if (!info->flag_buf) { - kfree(info->tmp_rx_buf); - info->tmp_rx_buf = NULL; - return -ENOMEM; - } - return 0; -} - -static void free_tmp_rx_buf(SLMP_INFO *info) -{ - kfree(info->tmp_rx_buf); - info->tmp_rx_buf = NULL; - kfree(info->flag_buf); - info->flag_buf = NULL; -} - -static int claim_resources(SLMP_INFO *info) -{ - if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) { - printk( "%s(%d):%s mem addr conflict, Addr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_memory_base); - info->init_error = DiagStatus_AddressConflict; - goto errout; - } - else - info->shared_mem_requested = true; - - if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) { - printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_lcr_base); - info->init_error = DiagStatus_AddressConflict; - goto errout; - } - else - info->lcr_mem_requested = true; - - if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) { - printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_sca_base); - info->init_error = DiagStatus_AddressConflict; - goto errout; - } - else - info->sca_base_requested = true; - - if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) { - printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_statctrl_base); - info->init_error = DiagStatus_AddressConflict; - goto errout; - } - else - info->sca_statctrl_requested = true; - - info->memory_base = ioremap(info->phys_memory_base, - SCA_MEM_SIZE); - if (!info->memory_base) { - printk( "%s(%d):%s Can't map shared memory, MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_memory_base ); - info->init_error = DiagStatus_CantAssignPciResources; - goto errout; - } - - info->lcr_base = ioremap(info->phys_lcr_base, PAGE_SIZE); - if (!info->lcr_base) { - printk( "%s(%d):%s Can't map LCR memory, MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); - info->init_error = DiagStatus_CantAssignPciResources; - goto errout; - } - info->lcr_base += info->lcr_offset; - - info->sca_base = ioremap(info->phys_sca_base, PAGE_SIZE); - if (!info->sca_base) { - printk( "%s(%d):%s Can't map SCA memory, MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_sca_base ); - info->init_error = DiagStatus_CantAssignPciResources; - goto errout; - } - info->sca_base += info->sca_offset; - - info->statctrl_base = ioremap(info->phys_statctrl_base, - PAGE_SIZE); - if (!info->statctrl_base) { - printk( "%s(%d):%s Can't map SCA Status/Control memory, MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_statctrl_base ); - info->init_error = DiagStatus_CantAssignPciResources; - goto errout; - } - info->statctrl_base += info->statctrl_offset; - - if ( !memory_test(info) ) { - printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n", - __FILE__,__LINE__,info->device_name, info->phys_memory_base ); - info->init_error = DiagStatus_MemoryError; - goto errout; - } - - return 0; - -errout: - release_resources( info ); - return -ENODEV; -} - -static void release_resources(SLMP_INFO *info) -{ - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s release_resources() entry\n", - __FILE__,__LINE__,info->device_name ); - - if ( info->irq_requested ) { - free_irq(info->irq_level, info); - info->irq_requested = false; - } - - if ( info->shared_mem_requested ) { - release_mem_region(info->phys_memory_base,SCA_MEM_SIZE); - info->shared_mem_requested = false; - } - if ( info->lcr_mem_requested ) { - release_mem_region(info->phys_lcr_base + info->lcr_offset,128); - info->lcr_mem_requested = false; - } - if ( info->sca_base_requested ) { - release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE); - info->sca_base_requested = false; - } - if ( info->sca_statctrl_requested ) { - release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE); - info->sca_statctrl_requested = false; - } - - if (info->memory_base){ - iounmap(info->memory_base); - info->memory_base = NULL; - } - - if (info->sca_base) { - iounmap(info->sca_base - info->sca_offset); - info->sca_base=NULL; - } - - if (info->statctrl_base) { - iounmap(info->statctrl_base - info->statctrl_offset); - info->statctrl_base=NULL; - } - - if (info->lcr_base){ - iounmap(info->lcr_base - info->lcr_offset); - info->lcr_base = NULL; - } - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s release_resources() exit\n", - __FILE__,__LINE__,info->device_name ); -} - -/* Add the specified device instance data structure to the - * global linked list of devices and increment the device count. - */ -static int add_device(SLMP_INFO *info) -{ - info->next_device = NULL; - info->line = synclinkmp_device_count; - sprintf(info->device_name,"ttySLM%dp%d",info->adapter_num,info->port_num); - - if (info->line < MAX_DEVICES) { - if (maxframe[info->line]) - info->max_frame_size = maxframe[info->line]; - } - - synclinkmp_device_count++; - - if ( !synclinkmp_device_list ) - synclinkmp_device_list = info; - else { - SLMP_INFO *current_dev = synclinkmp_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; - - printk( "SyncLink MultiPort %s: " - "Mem=(%08x %08X %08x %08X) IRQ=%d MaxFrameSize=%u\n", - info->device_name, - info->phys_sca_base, - info->phys_memory_base, - info->phys_statctrl_base, - info->phys_lcr_base, - info->irq_level, - info->max_frame_size ); - -#if SYNCLINK_GENERIC_HDLC - return hdlcdev_init(info); -#else - return 0; -#endif -} - -static const struct tty_port_operations port_ops = { - .carrier_raised = carrier_raised, - .dtr_rts = dtr_rts, -}; - -/* Allocate and initialize a device instance structure - * - * Return Value: pointer to SLMP_INFO if success, otherwise NULL - */ -static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) -{ - SLMP_INFO *info; - - info = kzalloc(sizeof(SLMP_INFO), - GFP_KERNEL); - - if (!info) { - printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n", - __FILE__,__LINE__, adapter_num, port_num); - } else { - tty_port_init(&info->port); - info->port.ops = &port_ops; - info->magic = MGSL_MAGIC; - INIT_WORK(&info->task, bh_handler); - info->max_frame_size = 4096; - info->port.close_delay = 5*HZ/10; - info->port.closing_wait = 30*HZ; - 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; - - /* Copy configuration info to device instance data */ - info->irq_level = pdev->irq; - info->phys_lcr_base = pci_resource_start(pdev,0); - info->phys_sca_base = pci_resource_start(pdev,2); - info->phys_memory_base = pci_resource_start(pdev,3); - info->phys_statctrl_base = pci_resource_start(pdev,4); - - /* Because veremap only works on page boundaries we must map - * a larger area than is actually implemented for the LCR - * memory range. We map a full page starting at the page boundary. - */ - info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1); - info->phys_lcr_base &= ~(PAGE_SIZE-1); - - info->sca_offset = info->phys_sca_base & (PAGE_SIZE-1); - info->phys_sca_base &= ~(PAGE_SIZE-1); - - info->statctrl_offset = info->phys_statctrl_base & (PAGE_SIZE-1); - info->phys_statctrl_base &= ~(PAGE_SIZE-1); - - info->bus_type = MGSL_BUS_TYPE_PCI; - info->irq_flags = IRQF_SHARED; - - timer_setup(&info->tx_timer, tx_timeout, 0); - timer_setup(&info->status_timer, status_timeout, 0); - - /* Store the PCI9050 misc control register value because a flaw - * in the PCI9050 prevents LCR registers from being read if - * BIOS assigns an LCR base address with bit 7 set. - * - * Only the misc control register is accessed for which only - * write access is needed, so set an initial value and change - * bits to the device instance data as we write the value - * to the actual misc control register. - */ - info->misc_ctrl_value = 0x087e4546; - - /* initial port state is unknown - if startup errors - * occur, init_error will be set to indicate the - * problem. Once the port is fully initialized, - * this value will be set to 0 to indicate the - * port is available. - */ - info->init_error = -1; - } - - return info; -} - -static int device_init(int adapter_num, struct pci_dev *pdev) -{ - SLMP_INFO *port_array[SCA_MAX_PORTS]; - int port, rc; - - /* allocate device instances for up to SCA_MAX_PORTS devices */ - for ( port = 0; port < SCA_MAX_PORTS; ++port ) { - port_array[port] = alloc_dev(adapter_num,port,pdev); - if( port_array[port] == NULL ) { - for (--port; port >= 0; --port) { - tty_port_destroy(&port_array[port]->port); - kfree(port_array[port]); - } - return -ENOMEM; - } - } - - /* give copy of port_array to all ports and add to device list */ - for ( port = 0; port < SCA_MAX_PORTS; ++port ) { - memcpy(port_array[port]->port_array,port_array,sizeof(port_array)); - rc = add_device( port_array[port] ); - if (rc) - goto err_add; - spin_lock_init(&port_array[port]->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 ( port = 1; port < SCA_MAX_PORTS; ++port ) { - port_array[port]->lock = port_array[0]->lock; - port_array[port]->irq_level = port_array[0]->irq_level; - port_array[port]->memory_base = port_array[0]->memory_base; - port_array[port]->sca_base = port_array[0]->sca_base; - port_array[port]->statctrl_base = port_array[0]->statctrl_base; - port_array[port]->lcr_base = port_array[0]->lcr_base; - alloc_dma_bufs(port_array[port]); - } - - rc = request_irq(port_array[0]->irq_level, - synclinkmp_interrupt, - port_array[0]->irq_flags, - port_array[0]->device_name, - port_array[0]); - if ( rc ) { - printk( "%s(%d):%s Can't request interrupt, IRQ=%d\n", - __FILE__,__LINE__, - port_array[0]->device_name, - port_array[0]->irq_level ); - goto err_irq; - } - port_array[0]->irq_requested = true; - adapter_test(port_array[0]); - } - return 0; -err_irq: - release_resources( port_array[0] ); -err_add: - for ( port = 0; port < SCA_MAX_PORTS; ++port ) { - tty_port_destroy(&port_array[port]->port); - kfree(port_array[port]); - } - return rc; -} - -static const struct tty_operations ops = { - .install = install, - .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, - .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 = synclinkmp_proc_show, -}; - - -static void synclinkmp_cleanup(void) -{ - int rc; - SLMP_INFO *info; - SLMP_INFO *tmp; - - printk("Unloading %s %s\n", driver_name, driver_version); - - if (serial_driver) { - rc = tty_unregister_driver(serial_driver); - if (rc) - printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); - put_tty_driver(serial_driver); - } - - /* reset devices */ - info = synclinkmp_device_list; - while(info) { - reset_port(info); - info = info->next_device; - } - - /* release devices */ - info = synclinkmp_device_list; - while(info) { -#if SYNCLINK_GENERIC_HDLC - hdlcdev_exit(info); -#endif - free_dma_bufs(info); - free_tmp_rx_buf(info); - if ( info->port_num == 0 ) { - if (info->sca_base) - write_reg(info, LPR, 1); /* set low power mode */ - release_resources(info); - } - tmp = info; - info = info->next_device; - tty_port_destroy(&tmp->port); - kfree(tmp); - } - - pci_unregister_driver(&synclinkmp_pci_driver); -} - -/* Driver initialization entry point. - */ - -static int __init synclinkmp_init(void) -{ - int rc; - - if (break_on_load) { - synclinkmp_get_text_ptr(); - BREAKPOINT(); - } - - printk("%s %s\n", driver_name, driver_version); - - if ((rc = pci_register_driver(&synclinkmp_pci_driver)) < 0) { - printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc); - return rc; - } - - serial_driver = alloc_tty_driver(128); - if (!serial_driver) { - rc = -ENOMEM; - goto error; - } - - /* Initialize the tty_driver structure */ - - serial_driver->driver_name = "synclinkmp"; - serial_driver->name = "ttySLM"; - 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; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &ops); - if ((rc = tty_register_driver(serial_driver)) < 0) { - printk("%s(%d):Couldn't register serial driver\n", - __FILE__,__LINE__); - put_tty_driver(serial_driver); - serial_driver = NULL; - goto error; - } - - printk("%s %s, tty major#%d\n", - driver_name, driver_version, - serial_driver->major); - - return 0; - -error: - synclinkmp_cleanup(); - return rc; -} - -static void __exit synclinkmp_exit(void) -{ - synclinkmp_cleanup(); -} - -module_init(synclinkmp_init); -module_exit(synclinkmp_exit); - -/* Set the port for internal loopback mode. - * The TxCLK and RxCLK signals are generated from the BRG and - * the TxD is looped back to the RxD internally. - */ -static void enable_loopback(SLMP_INFO *info, int enable) -{ - if (enable) { - /* MD2 (Mode Register 2) - * 01..00 CNCT<1..0> Channel Connection 11=Local Loopback - */ - write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) | (BIT1 + BIT0))); - - /* degate external TxC clock source */ - info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2)); - write_control_reg(info); - - /* RXS/TXS (Rx/Tx clock source) - * 07 Reserved, must be 0 - * 06..04 Clock Source, 100=BRG - * 03..00 Clock Divisor, 0000=1 - */ - write_reg(info, RXS, 0x40); - write_reg(info, TXS, 0x40); - - } else { - /* MD2 (Mode Register 2) - * 01..00 CNCT<1..0> Channel connection, 0=normal - */ - write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) & ~(BIT1 + BIT0))); - - /* RXS/TXS (Rx/Tx clock source) - * 07 Reserved, must be 0 - * 06..04 Clock Source, 000=RxC/TxC Pin - * 03..00 Clock Divisor, 0000=1 - */ - write_reg(info, RXS, 0x00); - write_reg(info, TXS, 0x00); - } - - /* set LinkSpeed if available, otherwise default to 2Mbps */ - if (info->params.clock_speed) - set_rate(info, info->params.clock_speed); - else - set_rate(info, 3686400); -} - -/* Set the baud rate register to the desired speed - * - * data_rate data rate of clock in bits per second - * A data rate of 0 disables the AUX clock. - */ -static void set_rate( SLMP_INFO *info, u32 data_rate ) -{ - u32 TMCValue; - unsigned char BRValue; - u32 Divisor=0; - - /* fBRG = fCLK/(TMC * 2^BR) - */ - if (data_rate != 0) { - Divisor = 14745600/data_rate; - if (!Divisor) - Divisor = 1; - - TMCValue = Divisor; - - BRValue = 0; - if (TMCValue != 1 && TMCValue != 2) { - /* BRValue of 0 provides 50/50 duty cycle *only* when - * TMCValue is 1 or 2. BRValue of 1 to 9 always provides - * 50/50 duty cycle. - */ - BRValue = 1; - TMCValue >>= 1; - } - - /* while TMCValue is too big for TMC register, divide - * by 2 and increment BR exponent. - */ - for(; TMCValue > 256 && BRValue < 10; BRValue++) - TMCValue >>= 1; - - write_reg(info, TXS, - (unsigned char)((read_reg(info, TXS) & 0xf0) | BRValue)); - write_reg(info, RXS, - (unsigned char)((read_reg(info, RXS) & 0xf0) | BRValue)); - write_reg(info, TMC, (unsigned char)TMCValue); - } - else { - write_reg(info, TXS,0); - write_reg(info, RXS,0); - write_reg(info, TMC, 0); - } -} - -/* Disable receiver - */ -static void rx_stop(SLMP_INFO *info) -{ - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):%s rx_stop()\n", - __FILE__,__LINE__, info->device_name ); - - write_reg(info, CMD, RXRESET); - - info->ie0_value &= ~RXRDYE; - write_reg(info, IE0, info->ie0_value); /* disable Rx data interrupts */ - - write_reg(info, RXDMA + DSR, 0); /* disable Rx DMA */ - write_reg(info, RXDMA + DCMD, SWABORT); /* reset/init Rx DMA */ - write_reg(info, RXDMA + DIR, 0); /* disable Rx DMA interrupts */ - - info->rx_enabled = false; - info->rx_overflow = false; -} - -/* enable the receiver - */ -static void rx_start(SLMP_INFO *info) -{ - int i; - - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):%s rx_start()\n", - __FILE__,__LINE__, info->device_name ); - - write_reg(info, CMD, RXRESET); - - if ( info->params.mode == MGSL_MODE_HDLC ) { - /* HDLC, disabe IRQ on rxdata */ - info->ie0_value &= ~RXRDYE; - write_reg(info, IE0, info->ie0_value); - - /* Reset all Rx DMA buffers and program rx dma */ - write_reg(info, RXDMA + DSR, 0); /* disable Rx DMA */ - write_reg(info, RXDMA + DCMD, SWABORT); /* reset/init Rx DMA */ - - for (i = 0; i < info->rx_buf_count; i++) { - info->rx_buf_list[i].status = 0xff; - - // throttle to 4 shared memory writes at a time to prevent - // hogging local bus (keep latency time for DMA requests low). - if (!(i % 4)) - read_status_reg(info); - } - info->current_rx_buf = 0; - - /* set current/1st descriptor address */ - write_reg16(info, RXDMA + CDA, - info->rx_buf_list_ex[0].phys_entry); - - /* set new last rx descriptor address */ - write_reg16(info, RXDMA + EDA, - info->rx_buf_list_ex[info->rx_buf_count - 1].phys_entry); - - /* set buffer length (shared by all rx dma data buffers) */ - write_reg16(info, RXDMA + BFL, SCABUFSIZE); - - write_reg(info, RXDMA + DIR, 0x60); /* enable Rx DMA interrupts (EOM/BOF) */ - write_reg(info, RXDMA + DSR, 0xf2); /* clear Rx DMA IRQs, enable Rx DMA */ - } else { - /* async, enable IRQ on rxdata */ - info->ie0_value |= RXRDYE; - write_reg(info, IE0, info->ie0_value); - } - - write_reg(info, CMD, RXENABLE); - - info->rx_overflow = false; - info->rx_enabled = true; -} - -/* Enable the transmitter and send a transmit frame if - * one is loaded in the DMA buffers. - */ -static void tx_start(SLMP_INFO *info) -{ - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):%s tx_start() tx_count=%d\n", - __FILE__,__LINE__, info->device_name,info->tx_count ); - - if (!info->tx_enabled ) { - write_reg(info, CMD, TXRESET); - write_reg(info, CMD, TXENABLE); - info->tx_enabled = true; - } - - if ( info->tx_count ) { - - /* If auto RTS enabled and RTS is inactive, then assert */ - /* RTS and set a flag indicating that the driver should */ - /* negate RTS when the transmission completes. */ - - info->drop_rts_on_tx_done = false; - - if (info->params.mode != MGSL_MODE_ASYNC) { - - if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) { - get_signals( info ); - if ( !(info->serial_signals & SerialSignal_RTS) ) { - info->serial_signals |= SerialSignal_RTS; - set_signals( info ); - info->drop_rts_on_tx_done = true; - } - } - - write_reg16(info, TRC0, - (unsigned short)(((tx_negate_fifo_level-1)<<8) + tx_active_fifo_level)); - - write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ - write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ - - /* set TX CDA (current descriptor address) */ - write_reg16(info, TXDMA + CDA, - info->tx_buf_list_ex[0].phys_entry); - - /* set TX EDA (last descriptor address) */ - write_reg16(info, TXDMA + EDA, - info->tx_buf_list_ex[info->last_tx_buf].phys_entry); - - /* enable underrun IRQ */ - info->ie1_value &= ~IDLE; - info->ie1_value |= UDRN; - write_reg(info, IE1, info->ie1_value); - write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); - - write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */ - write_reg(info, TXDMA + DSR, 0xf2); /* clear Tx DMA IRQs, enable Tx DMA */ - - mod_timer(&info->tx_timer, jiffies + - msecs_to_jiffies(5000)); - } - else { - tx_load_fifo(info); - /* async, enable IRQ on txdata */ - info->ie0_value |= TXRDYE; - write_reg(info, IE0, info->ie0_value); - } - - info->tx_active = true; - } -} - -/* stop the transmitter and DMA - */ -static void tx_stop( SLMP_INFO *info ) -{ - if (debug_level >= DEBUG_LEVEL_ISR) - printk("%s(%d):%s tx_stop()\n", - __FILE__,__LINE__, info->device_name ); - - del_timer(&info->tx_timer); - - write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ - write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ - - write_reg(info, CMD, TXRESET); - - info->ie1_value &= ~(UDRN + IDLE); - write_reg(info, IE1, info->ie1_value); /* disable tx status interrupts */ - write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); /* clear pending */ - - info->ie0_value &= ~TXRDYE; - write_reg(info, IE0, info->ie0_value); /* disable tx data interrupts */ - - info->tx_enabled = false; - info->tx_active = false; -} - -/* Fill the transmit FIFO until the FIFO is full or - * there is no more data to load. - */ -static void tx_load_fifo(SLMP_INFO *info) -{ - u8 TwoBytes[2]; - - /* do nothing is now tx data available and no XON/XOFF pending */ - - if ( !info->tx_count && !info->x_char ) - return; - - /* load the Transmit FIFO until FIFOs full or all data sent */ - - while( info->tx_count && (read_reg(info,SR0) & BIT1) ) { - - /* there is more space in the transmit FIFO and */ - /* there is more data in transmit buffer */ - - if ( (info->tx_count > 1) && !info->x_char ) { - /* write 16-bits */ - TwoBytes[0] = info->tx_buf[info->tx_get++]; - if (info->tx_get >= info->max_frame_size) - info->tx_get -= info->max_frame_size; - TwoBytes[1] = info->tx_buf[info->tx_get++]; - if (info->tx_get >= info->max_frame_size) - info->tx_get -= info->max_frame_size; - - write_reg16(info, TRB, *((u16 *)TwoBytes)); - - info->tx_count -= 2; - info->icount.tx += 2; - } else { - /* only 1 byte left to transmit or 1 FIFO slot left */ - - if (info->x_char) { - /* transmit pending high priority char */ - write_reg(info, TRB, info->x_char); - info->x_char = 0; - } else { - write_reg(info, TRB, info->tx_buf[info->tx_get++]); - if (info->tx_get >= info->max_frame_size) - info->tx_get -= info->max_frame_size; - info->tx_count--; - } - info->icount.tx++; - } - } -} - -/* Reset a port to a known state - */ -static void reset_port(SLMP_INFO *info) -{ - if (info->sca_base) { - - tx_stop(info); - rx_stop(info); - - info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR); - set_signals(info); - - /* disable all port interrupts */ - info->ie0_value = 0; - info->ie1_value = 0; - info->ie2_value = 0; - write_reg(info, IE0, info->ie0_value); - write_reg(info, IE1, info->ie1_value); - write_reg(info, IE2, info->ie2_value); - - write_reg(info, CMD, CHRESET); - } -} - -/* Reset all the ports to a known state. - */ -static void reset_adapter(SLMP_INFO *info) -{ - int i; - - for ( i=0; i < SCA_MAX_PORTS; ++i) { - if (info->port_array[i]) - reset_port(info->port_array[i]); - } -} - -/* Program port for asynchronous communications. - */ -static void async_mode(SLMP_INFO *info) -{ - - unsigned char RegValue; - - tx_stop(info); - rx_stop(info); - - /* MD0, Mode Register 0 - * - * 07..05 PRCTL<2..0>, Protocol Mode, 000=async - * 04 AUTO, Auto-enable (RTS/CTS/DCD) - * 03 Reserved, must be 0 - * 02 CRCCC, CRC Calculation, 0=disabled - * 01..00 STOP<1..0> Stop bits (00=1,10=2) - * - * 0000 0000 - */ - RegValue = 0x00; - if (info->params.stop_bits != 1) - RegValue |= BIT1; - write_reg(info, MD0, RegValue); - - /* MD1, Mode Register 1 - * - * 07..06 BRATE<1..0>, bit rate, 00=1/1 01=1/16 10=1/32 11=1/64 - * 05..04 TXCHR<1..0>, tx char size, 00=8 bits,01=7,10=6,11=5 - * 03..02 RXCHR<1..0>, rx char size - * 01..00 PMPM<1..0>, Parity mode, 00=none 10=even 11=odd - * - * 0100 0000 - */ - RegValue = 0x40; - switch (info->params.data_bits) { - case 7: RegValue |= BIT4 + BIT2; break; - case 6: RegValue |= BIT5 + BIT3; break; - case 5: RegValue |= BIT5 + BIT4 + BIT3 + BIT2; break; - } - if (info->params.parity != ASYNC_PARITY_NONE) { - RegValue |= BIT1; - if (info->params.parity == ASYNC_PARITY_ODD) - RegValue |= BIT0; - } - write_reg(info, MD1, RegValue); - - /* MD2, Mode Register 2 - * - * 07..02 Reserved, must be 0 - * 01..00 CNCT<1..0> Channel connection, 00=normal 11=local loopback - * - * 0000 0000 - */ - RegValue = 0x00; - if (info->params.loopback) - RegValue |= (BIT1 + BIT0); - write_reg(info, MD2, RegValue); - - /* RXS, Receive clock source - * - * 07 Reserved, must be 0 - * 06..04 RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL - * 03..00 RXBR<3..0>, rate divisor, 0000=1 - */ - RegValue=BIT6; - write_reg(info, RXS, RegValue); - - /* TXS, Transmit clock source - * - * 07 Reserved, must be 0 - * 06..04 RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock - * 03..00 RXBR<3..0>, rate divisor, 0000=1 - */ - RegValue=BIT6; - write_reg(info, TXS, RegValue); - - /* Control Register - * - * 6,4,2,0 CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out - */ - info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2)); - write_control_reg(info); - - tx_set_idle(info); - - /* RRC Receive Ready Control 0 - * - * 07..05 Reserved, must be 0 - * 04..00 RRC<4..0> Rx FIFO trigger active 0x00 = 1 byte - */ - write_reg(info, RRC, 0x00); - - /* TRC0 Transmit Ready Control 0 - * - * 07..05 Reserved, must be 0 - * 04..00 TRC<4..0> Tx FIFO trigger active 0x10 = 16 bytes - */ - write_reg(info, TRC0, 0x10); - - /* TRC1 Transmit Ready Control 1 - * - * 07..05 Reserved, must be 0 - * 04..00 TRC<4..0> Tx FIFO trigger inactive 0x1e = 31 bytes (full-1) - */ - write_reg(info, TRC1, 0x1e); - - /* CTL, MSCI control register - * - * 07..06 Reserved, set to 0 - * 05 UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC) - * 04 IDLC, idle control, 0=mark 1=idle register - * 03 BRK, break, 0=off 1 =on (async) - * 02 SYNCLD, sync char load enable (BSC) 1=enabled - * 01 GOP, go active on poll (LOOP mode) 1=enabled - * 00 RTS, RTS output control, 0=active 1=inactive - * - * 0001 0001 - */ - RegValue = 0x10; - if (!(info->serial_signals & SerialSignal_RTS)) - RegValue |= 0x01; - write_reg(info, CTL, RegValue); - - /* enable status interrupts */ - info->ie0_value |= TXINTE + RXINTE; - write_reg(info, IE0, info->ie0_value); - - /* enable break detect interrupt */ - info->ie1_value = BRKD; - write_reg(info, IE1, info->ie1_value); - - /* enable rx overrun interrupt */ - info->ie2_value = OVRN; - write_reg(info, IE2, info->ie2_value); - - set_rate( info, info->params.data_rate * 16 ); -} - -/* Program the SCA for HDLC communications. - */ -static void hdlc_mode(SLMP_INFO *info) -{ - unsigned char RegValue; - u32 DpllDivisor; - - // Can't use DPLL because SCA outputs recovered clock on RxC when - // DPLL mode selected. This causes output contention with RxC receiver. - // Use of DPLL would require external hardware to disable RxC receiver - // when DPLL mode selected. - info->params.flags &= ~(HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL); - - /* disable DMA interrupts */ - write_reg(info, TXDMA + DIR, 0); - write_reg(info, RXDMA + DIR, 0); - - /* MD0, Mode Register 0 - * - * 07..05 PRCTL<2..0>, Protocol Mode, 100=HDLC - * 04 AUTO, Auto-enable (RTS/CTS/DCD) - * 03 Reserved, must be 0 - * 02 CRCCC, CRC Calculation, 1=enabled - * 01 CRC1, CRC selection, 0=CRC-16,1=CRC-CCITT-16 - * 00 CRC0, CRC initial value, 1 = all 1s - * - * 1000 0001 - */ - RegValue = 0x81; - if (info->params.flags & HDLC_FLAG_AUTO_CTS) - RegValue |= BIT4; - if (info->params.flags & HDLC_FLAG_AUTO_DCD) - RegValue |= BIT4; - if (info->params.crc_type == HDLC_CRC_16_CCITT) - RegValue |= BIT2 + BIT1; - write_reg(info, MD0, RegValue); - - /* MD1, Mode Register 1 - * - * 07..06 ADDRS<1..0>, Address detect, 00=no addr check - * 05..04 TXCHR<1..0>, tx char size, 00=8 bits - * 03..02 RXCHR<1..0>, rx char size, 00=8 bits - * 01..00 PMPM<1..0>, Parity mode, 00=no parity - * - * 0000 0000 - */ - RegValue = 0x00; - write_reg(info, MD1, RegValue); - - /* MD2, Mode Register 2 - * - * 07 NRZFM, 0=NRZ, 1=FM - * 06..05 CODE<1..0> Encoding, 00=NRZ - * 04..03 DRATE<1..0> DPLL Divisor, 00=8 - * 02 Reserved, must be 0 - * 01..00 CNCT<1..0> Channel connection, 0=normal - * - * 0000 0000 - */ - RegValue = 0x00; - switch(info->params.encoding) { - case HDLC_ENCODING_NRZI: RegValue |= BIT5; break; - case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT7 + BIT5; break; /* aka FM1 */ - case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT7 + BIT6; break; /* aka FM0 */ - case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT7; break; /* aka Manchester */ -#if 0 - case HDLC_ENCODING_NRZB: /* not supported */ - case HDLC_ENCODING_NRZI_MARK: /* not supported */ - case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: /* not supported */ -#endif - } - if ( info->params.flags & HDLC_FLAG_DPLL_DIV16 ) { - DpllDivisor = 16; - RegValue |= BIT3; - } else if ( info->params.flags & HDLC_FLAG_DPLL_DIV8 ) { - DpllDivisor = 8; - } else { - DpllDivisor = 32; - RegValue |= BIT4; - } - write_reg(info, MD2, RegValue); - - - /* RXS, Receive clock source - * - * 07 Reserved, must be 0 - * 06..04 RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL - * 03..00 RXBR<3..0>, rate divisor, 0000=1 - */ - RegValue=0; - if (info->params.flags & HDLC_FLAG_RXC_BRG) - RegValue |= BIT6; - if (info->params.flags & HDLC_FLAG_RXC_DPLL) - RegValue |= BIT6 + BIT5; - write_reg(info, RXS, RegValue); - - /* TXS, Transmit clock source - * - * 07 Reserved, must be 0 - * 06..04 RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock - * 03..00 RXBR<3..0>, rate divisor, 0000=1 - */ - RegValue=0; - if (info->params.flags & HDLC_FLAG_TXC_BRG) - RegValue |= BIT6; - if (info->params.flags & HDLC_FLAG_TXC_DPLL) - RegValue |= BIT6 + BIT5; - write_reg(info, TXS, RegValue); - - if (info->params.flags & HDLC_FLAG_RXC_DPLL) - set_rate(info, info->params.clock_speed * DpllDivisor); - else - set_rate(info, info->params.clock_speed); - - /* GPDATA (General Purpose I/O Data Register) - * - * 6,4,2,0 CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out - */ - if (info->params.flags & HDLC_FLAG_TXC_BRG) - info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2)); - else - info->port_array[0]->ctrlreg_value &= ~(BIT0 << (info->port_num * 2)); - write_control_reg(info); - - /* RRC Receive Ready Control 0 - * - * 07..05 Reserved, must be 0 - * 04..00 RRC<4..0> Rx FIFO trigger active - */ - write_reg(info, RRC, rx_active_fifo_level); - - /* TRC0 Transmit Ready Control 0 - * - * 07..05 Reserved, must be 0 - * 04..00 TRC<4..0> Tx FIFO trigger active - */ - write_reg(info, TRC0, tx_active_fifo_level); - - /* TRC1 Transmit Ready Control 1 - * - * 07..05 Reserved, must be 0 - * 04..00 TRC<4..0> Tx FIFO trigger inactive 0x1f = 32 bytes (full) - */ - write_reg(info, TRC1, (unsigned char)(tx_negate_fifo_level - 1)); - - /* DMR, DMA Mode Register - * - * 07..05 Reserved, must be 0 - * 04 TMOD, Transfer Mode: 1=chained-block - * 03 Reserved, must be 0 - * 02 NF, Number of Frames: 1=multi-frame - * 01 CNTE, Frame End IRQ Counter enable: 0=disabled - * 00 Reserved, must be 0 - * - * 0001 0100 - */ - write_reg(info, TXDMA + DMR, 0x14); - write_reg(info, RXDMA + DMR, 0x14); - - /* Set chain pointer base (upper 8 bits of 24 bit addr) */ - write_reg(info, RXDMA + CPB, - (unsigned char)(info->buffer_list_phys >> 16)); - - /* Set chain pointer base (upper 8 bits of 24 bit addr) */ - write_reg(info, TXDMA + CPB, - (unsigned char)(info->buffer_list_phys >> 16)); - - /* enable status interrupts. other code enables/disables - * the individual sources for these two interrupt classes. - */ - info->ie0_value |= TXINTE + RXINTE; - write_reg(info, IE0, info->ie0_value); - - /* CTL, MSCI control register - * - * 07..06 Reserved, set to 0 - * 05 UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC) - * 04 IDLC, idle control, 0=mark 1=idle register - * 03 BRK, break, 0=off 1 =on (async) - * 02 SYNCLD, sync char load enable (BSC) 1=enabled - * 01 GOP, go active on poll (LOOP mode) 1=enabled - * 00 RTS, RTS output control, 0=active 1=inactive - * - * 0001 0001 - */ - RegValue = 0x10; - if (!(info->serial_signals & SerialSignal_RTS)) - RegValue |= 0x01; - write_reg(info, CTL, RegValue); - - /* preamble not supported ! */ - - tx_set_idle(info); - tx_stop(info); - rx_stop(info); - - set_rate(info, info->params.clock_speed); - - if (info->params.loopback) - enable_loopback(info,1); -} - -/* Set the transmit HDLC idle mode - */ -static void tx_set_idle(SLMP_INFO *info) -{ - unsigned char RegValue = 0xff; - - /* Map API idle mode to SCA register bits */ - switch(info->idle_mode) { - case HDLC_TXIDLE_FLAGS: RegValue = 0x7e; break; - case HDLC_TXIDLE_ALT_ZEROS_ONES: RegValue = 0xaa; break; - case HDLC_TXIDLE_ZEROS: RegValue = 0x00; break; - case HDLC_TXIDLE_ONES: RegValue = 0xff; break; - case HDLC_TXIDLE_ALT_MARK_SPACE: RegValue = 0xaa; break; - case HDLC_TXIDLE_SPACE: RegValue = 0x00; break; - case HDLC_TXIDLE_MARK: RegValue = 0xff; break; - } - - write_reg(info, IDL, RegValue); -} - -/* Query the adapter for the state of the V24 status (input) signals. - */ -static void get_signals(SLMP_INFO *info) -{ - u16 status = read_reg(info, SR3); - u16 gpstatus = read_status_reg(info); - u16 testbit; - - /* clear all serial signals except RTS and DTR */ - info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR; - - /* set serial signal bits to reflect MISR */ - - if (!(status & BIT3)) - info->serial_signals |= SerialSignal_CTS; - - if ( !(status & BIT2)) - info->serial_signals |= SerialSignal_DCD; - - testbit = BIT1 << (info->port_num * 2); // Port 0..3 RI is GPDATA<1,3,5,7> - if (!(gpstatus & testbit)) - info->serial_signals |= SerialSignal_RI; - - testbit = BIT0 << (info->port_num * 2); // Port 0..3 DSR is GPDATA<0,2,4,6> - if (!(gpstatus & testbit)) - info->serial_signals |= SerialSignal_DSR; -} - -/* Set the state of RTS and DTR based on contents of - * serial_signals member of device context. - */ -static void set_signals(SLMP_INFO *info) -{ - unsigned char RegValue; - u16 EnableBit; - - RegValue = read_reg(info, CTL); - if (info->serial_signals & SerialSignal_RTS) - RegValue &= ~BIT0; - else - RegValue |= BIT0; - write_reg(info, CTL, RegValue); - - // Port 0..3 DTR is ctrl reg <1,3,5,7> - EnableBit = BIT1 << (info->port_num*2); - if (info->serial_signals & SerialSignal_DTR) - info->port_array[0]->ctrlreg_value &= ~EnableBit; - else - info->port_array[0]->ctrlreg_value |= EnableBit; - write_control_reg(info); -} - -/*******************/ -/* DMA Buffer Code */ -/*******************/ - -/* Set the count for all receive buffers to SCABUFSIZE - * and set the current buffer to the first buffer. This effectively - * makes all buffers free and discards any data in buffers. - */ -static void rx_reset_buffers(SLMP_INFO *info) -{ - rx_free_frame_buffers(info, 0, info->rx_buf_count - 1); -} - -/* Free the buffers used by a received frame - * - * info pointer to device instance data - * first index of 1st receive buffer of frame - * last index of last receive buffer of frame - */ -static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last) -{ - bool done = false; - - while(!done) { - /* reset current buffer for reuse */ - info->rx_buf_list[first].status = 0xff; - - if (first == last) { - done = true; - /* set new last rx descriptor address */ - write_reg16(info, RXDMA + EDA, info->rx_buf_list_ex[first].phys_entry); - } - - first++; - if (first == info->rx_buf_count) - first = 0; - } - - /* set current buffer to next buffer after last buffer of frame */ - info->current_rx_buf = first; -} - -/* Return a received frame from the receive DMA buffers. - * Only frames received without errors are returned. - * - * Return Value: true if frame returned, otherwise false - */ -static bool rx_get_frame(SLMP_INFO *info) -{ - unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ - unsigned short status; - unsigned int framesize = 0; - bool ReturnCode = false; - unsigned long flags; - struct tty_struct *tty = info->port.tty; - unsigned char addr_field = 0xff; - SCADESC *desc; - SCADESC_EX *desc_ex; - -CheckAgain: - /* assume no frame returned, set zero length */ - framesize = 0; - addr_field = 0xff; - - /* - * current_rx_buf points to the 1st buffer of the next available - * receive frame. To find the last buffer of the frame look for - * a non-zero status field in the buffer entries. (The status - * field is set by the 16C32 after completing a receive frame. - */ - StartIndex = EndIndex = info->current_rx_buf; - - for ( ;; ) { - desc = &info->rx_buf_list[EndIndex]; - desc_ex = &info->rx_buf_list_ex[EndIndex]; - - if (desc->status == 0xff) - goto Cleanup; /* current desc still in use, no frames available */ - - if (framesize == 0 && info->params.addr_filter != 0xff) - addr_field = desc_ex->virt_addr[0]; - - framesize += desc->length; - - /* Status != 0 means last buffer of frame */ - if (desc->status) - break; - - EndIndex++; - if (EndIndex == info->rx_buf_count) - EndIndex = 0; - - if (EndIndex == info->current_rx_buf) { - /* all buffers have been 'used' but none mark */ - /* the end of a frame. Reset buffers and receiver. */ - if ( info->rx_enabled ){ - spin_lock_irqsave(&info->lock,flags); - rx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - } - goto Cleanup; - } - - } - - /* check status of receive frame */ - - /* frame status is byte stored after frame data - * - * 7 EOM (end of msg), 1 = last buffer of frame - * 6 Short Frame, 1 = short frame - * 5 Abort, 1 = frame aborted - * 4 Residue, 1 = last byte is partial - * 3 Overrun, 1 = overrun occurred during frame reception - * 2 CRC, 1 = CRC error detected - * - */ - status = desc->status; - - /* ignore CRC bit if not using CRC (bit is undefined) */ - /* Note:CRC is not save to data buffer */ - if (info->params.crc_type == HDLC_CRC_NONE) - status &= ~BIT2; - - if (framesize == 0 || - (addr_field != 0xff && addr_field != info->params.addr_filter)) { - /* discard 0 byte frames, this seems to occur sometime - * when remote is idling flags. - */ - rx_free_frame_buffers(info, StartIndex, EndIndex); - goto CheckAgain; - } - - if (framesize < 2) - status |= BIT6; - - if (status & (BIT6+BIT5+BIT3+BIT2)) { - /* received frame has errors, - * update counts and mark frame size as 0 - */ - if (status & BIT6) - info->icount.rxshort++; - else if (status & BIT5) - info->icount.rxabort++; - else if (status & BIT3) - info->icount.rxover++; - else - info->icount.rxcrc++; - - framesize = 0; -#if SYNCLINK_GENERIC_HDLC - { - info->netdev->stats.rx_errors++; - info->netdev->stats.rx_frame_errors++; - } -#endif - } - - if ( debug_level >= DEBUG_LEVEL_BH ) - printk("%s(%d):%s rx_get_frame() status=%04X size=%d\n", - __FILE__,__LINE__,info->device_name,status,framesize); - - if ( debug_level >= DEBUG_LEVEL_DATA ) - trace_block(info,info->rx_buf_list_ex[StartIndex].virt_addr, - min_t(unsigned int, framesize, SCABUFSIZE), 0); - - if (framesize) { - if (framesize > info->max_frame_size) - info->icount.rxlong++; - else { - /* copy dma buffer(s) to contiguous intermediate buffer */ - int copy_count = framesize; - int index = StartIndex; - unsigned char *ptmp = info->tmp_rx_buf; - info->tmp_rx_buf_count = framesize; - - info->icount.rxok++; - - while(copy_count) { - int partial_count = min(copy_count,SCABUFSIZE); - memcpy( ptmp, - info->rx_buf_list_ex[index].virt_addr, - partial_count ); - ptmp += partial_count; - copy_count -= partial_count; - - if ( ++index == info->rx_buf_count ) - index = 0; - } - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_rx(info,info->tmp_rx_buf,framesize); - else -#endif - ldisc_receive_buf(tty,info->tmp_rx_buf, - info->flag_buf, framesize); - } - } - /* Free the buffers used by this frame. */ - rx_free_frame_buffers( info, StartIndex, EndIndex ); - - ReturnCode = true; - -Cleanup: - if ( info->rx_enabled && info->rx_overflow ) { - /* Receiver is enabled, but needs to restarted due to - * rx buffer overflow. If buffers are empty, restart receiver. - */ - if (info->rx_buf_list[EndIndex].status == 0xff) { - spin_lock_irqsave(&info->lock,flags); - rx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - } - } - - return ReturnCode; -} - -/* load the transmit DMA buffer with data - */ -static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) -{ - unsigned short copy_count; - unsigned int i = 0; - SCADESC *desc; - SCADESC_EX *desc_ex; - - if ( debug_level >= DEBUG_LEVEL_DATA ) - trace_block(info, buf, min_t(unsigned int, count, SCABUFSIZE), 1); - - /* Copy source buffer to one or more DMA buffers, starting with - * the first transmit dma buffer. - */ - for(i=0;;) - { - copy_count = min_t(unsigned int, count, SCABUFSIZE); - - desc = &info->tx_buf_list[i]; - desc_ex = &info->tx_buf_list_ex[i]; - - load_pci_memory(info, desc_ex->virt_addr,buf,copy_count); - - desc->length = copy_count; - desc->status = 0; - - buf += copy_count; - count -= copy_count; - - if (!count) - break; - - i++; - if (i >= info->tx_buf_count) - i = 0; - } - - info->tx_buf_list[i].status = 0x81; /* set EOM and EOT status */ - info->last_tx_buf = ++i; -} - -static bool register_test(SLMP_INFO *info) -{ - static unsigned char testval[] = {0x00, 0xff, 0xaa, 0x55, 0x69, 0x96}; - static unsigned int count = ARRAY_SIZE(testval); - unsigned int i; - bool rc = true; - unsigned long flags; - - spin_lock_irqsave(&info->lock,flags); - reset_port(info); - - /* assume failure */ - info->init_error = DiagStatus_AddressFailure; - - /* Write bit patterns to various registers but do it out of */ - /* sync, then read back and verify values. */ - - for (i = 0 ; i < count ; i++) { - write_reg(info, TMC, testval[i]); - write_reg(info, IDL, testval[(i+1)%count]); - write_reg(info, SA0, testval[(i+2)%count]); - write_reg(info, SA1, testval[(i+3)%count]); - - if ( (read_reg(info, TMC) != testval[i]) || - (read_reg(info, IDL) != testval[(i+1)%count]) || - (read_reg(info, SA0) != testval[(i+2)%count]) || - (read_reg(info, SA1) != testval[(i+3)%count]) ) - { - rc = false; - break; - } - } - - reset_port(info); - spin_unlock_irqrestore(&info->lock,flags); - - return rc; -} - -static bool irq_test(SLMP_INFO *info) -{ - unsigned long timeout; - unsigned long flags; - - unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0; - - spin_lock_irqsave(&info->lock,flags); - reset_port(info); - - /* assume failure */ - info->init_error = DiagStatus_IrqFailure; - info->irq_occurred = false; - - /* setup timer0 on SCA0 to interrupt */ - - /* IER2<7..4> = timer<3..0> interrupt enables (1=enabled) */ - write_reg(info, IER2, (unsigned char)((info->port_num & 1) ? BIT6 : BIT4)); - - write_reg(info, (unsigned char)(timer + TEPR), 0); /* timer expand prescale */ - write_reg16(info, (unsigned char)(timer + TCONR), 1); /* timer constant */ - - - /* TMCS, Timer Control/Status Register - * - * 07 CMF, Compare match flag (read only) 1=match - * 06 ECMI, CMF Interrupt Enable: 1=enabled - * 05 Reserved, must be 0 - * 04 TME, Timer Enable - * 03..00 Reserved, must be 0 - * - * 0101 0000 - */ - write_reg(info, (unsigned char)(timer + TMCS), 0x50); - - 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); - - return info->irq_occurred; -} - -/* initialize individual SCA device (2 ports) - */ -static bool sca_init(SLMP_INFO *info) -{ - /* set wait controller to single mem partition (low), no wait states */ - write_reg(info, PABR0, 0); /* wait controller addr boundary 0 */ - write_reg(info, PABR1, 0); /* wait controller addr boundary 1 */ - write_reg(info, WCRL, 0); /* wait controller low range */ - write_reg(info, WCRM, 0); /* wait controller mid range */ - write_reg(info, WCRH, 0); /* wait controller high range */ - - /* DPCR, DMA Priority Control - * - * 07..05 Not used, must be 0 - * 04 BRC, bus release condition: 0=all transfers complete - * 03 CCC, channel change condition: 0=every cycle - * 02..00 PR<2..0>, priority 100=round robin - * - * 00000100 = 0x04 - */ - write_reg(info, DPCR, dma_priority); - - /* DMA Master Enable, BIT7: 1=enable all channels */ - write_reg(info, DMER, 0x80); - - /* enable all interrupt classes */ - write_reg(info, IER0, 0xff); /* TxRDY,RxRDY,TxINT,RxINT (ports 0-1) */ - write_reg(info, IER1, 0xff); /* DMIB,DMIA (channels 0-3) */ - write_reg(info, IER2, 0xf0); /* TIRQ (timers 0-3) */ - - /* ITCR, interrupt control register - * 07 IPC, interrupt priority, 0=MSCI->DMA - * 06..05 IAK<1..0>, Acknowledge cycle, 00=non-ack cycle - * 04 VOS, Vector Output, 0=unmodified vector - * 03..00 Reserved, must be 0 - */ - write_reg(info, ITCR, 0); - - return true; -} - -/* initialize adapter hardware - */ -static bool init_adapter(SLMP_INFO *info) -{ - int i; - - /* Set BIT30 of Local Control Reg 0x50 to reset SCA */ - volatile u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50); - u32 readval; - - info->misc_ctrl_value |= BIT30; - *MiscCtrl = info->misc_ctrl_value; - - /* - * Force at least 170ns delay before clearing - * reset bit. Each read from LCR takes at least - * 30ns so 10 times for 300ns to be safe. - */ - for(i=0;i<10;i++) - readval = *MiscCtrl; - - info->misc_ctrl_value &= ~BIT30; - *MiscCtrl = info->misc_ctrl_value; - - /* init control reg (all DTRs off, all clksel=input) */ - info->ctrlreg_value = 0xaa; - write_control_reg(info); - - { - volatile u32 *LCR1BRDR = (u32 *)(info->lcr_base + 0x2c); - lcr1_brdr_value &= ~(BIT5 + BIT4 + BIT3); - - switch(read_ahead_count) - { - case 16: - lcr1_brdr_value |= BIT5 + BIT4 + BIT3; - break; - case 8: - lcr1_brdr_value |= BIT5 + BIT4; - break; - case 4: - lcr1_brdr_value |= BIT5 + BIT3; - break; - case 0: - lcr1_brdr_value |= BIT5; - break; - } - - *LCR1BRDR = lcr1_brdr_value; - *MiscCtrl = misc_ctrl_value; - } - - sca_init(info->port_array[0]); - sca_init(info->port_array[2]); - - return true; -} - -/* Loopback an HDLC frame to test the hardware - * interrupt and DMA functions. - */ -static bool loopback_test(SLMP_INFO *info) -{ -#define TESTFRAMESIZE 20 - - unsigned long timeout; - u16 count = TESTFRAMESIZE; - unsigned char buf[TESTFRAMESIZE]; - bool rc = false; - unsigned long flags; - - struct tty_struct *oldtty = info->port.tty; - u32 speed = info->params.clock_speed; - - info->params.clock_speed = 3686400; - info->port.tty = NULL; - - /* assume failure */ - info->init_error = DiagStatus_DmaFailure; - - /* build and send transmit frame */ - for (count = 0; count < TESTFRAMESIZE;++count) - buf[count] = (unsigned char)count; - - memset(info->tmp_rx_buf,0,TESTFRAMESIZE); - - /* program hardware for HDLC and enabled receiver */ - spin_lock_irqsave(&info->lock,flags); - hdlc_mode(info); - enable_loopback(info,1); - rx_start(info); - info->tx_count = count; - tx_load_dma_buffer(info,buf,count); - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); - - /* wait for receive complete */ - /* Set a timeout for waiting for interrupt. */ - for ( timeout = 100; timeout; --timeout ) { - msleep_interruptible(10); - - if (rx_get_frame(info)) { - rc = true; - break; - } - } - - /* verify received frame length and contents */ - if (rc && - ( info->tmp_rx_buf_count != count || - memcmp(buf, info->tmp_rx_buf,count))) { - rc = false; - } - - spin_lock_irqsave(&info->lock,flags); - reset_adapter(info); - spin_unlock_irqrestore(&info->lock,flags); - - info->params.clock_speed = speed; - info->port.tty = oldtty; - - return rc; -} - -/* Perform diagnostics on hardware - */ -static int adapter_test( SLMP_INFO *info ) -{ - unsigned long flags; - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):Testing device %s\n", - __FILE__,__LINE__,info->device_name ); - - spin_lock_irqsave(&info->lock,flags); - init_adapter(info); - spin_unlock_irqrestore(&info->lock,flags); - - info->port_array[0]->port_count = 0; - - if ( register_test(info->port_array[0]) && - register_test(info->port_array[1])) { - - info->port_array[0]->port_count = 2; - - if ( register_test(info->port_array[2]) && - register_test(info->port_array[3]) ) - info->port_array[0]->port_count += 2; - } - else { - printk( "%s(%d):Register test failure for device %s Addr=%08lX\n", - __FILE__,__LINE__,info->device_name, (unsigned long)(info->phys_sca_base)); - return -ENODEV; - } - - if ( !irq_test(info->port_array[0]) || - !irq_test(info->port_array[1]) || - (info->port_count == 4 && !irq_test(info->port_array[2])) || - (info->port_count == 4 && !irq_test(info->port_array[3]))) { - printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n", - __FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) ); - return -ENODEV; - } - - if (!loopback_test(info->port_array[0]) || - !loopback_test(info->port_array[1]) || - (info->port_count == 4 && !loopback_test(info->port_array[2])) || - (info->port_count == 4 && !loopback_test(info->port_array[3]))) { - printk( "%s(%d):DMA test failure for device %s\n", - __FILE__,__LINE__,info->device_name); - return -ENODEV; - } - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):device %s passed diagnostics\n", - __FILE__,__LINE__,info->device_name ); - - info->port_array[0]->init_error = 0; - info->port_array[1]->init_error = 0; - if ( info->port_count > 2 ) { - info->port_array[2]->init_error = 0; - info->port_array[3]->init_error = 0; - } - - return 0; -} - -/* Test the shared memory on a PCI adapter. - */ -static bool memory_test(SLMP_INFO *info) -{ - static unsigned long testval[] = { 0x0, 0x55555555, 0xaaaaaaaa, - 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; - unsigned long count = ARRAY_SIZE(testval); - unsigned long i; - unsigned long limit = SCA_MEM_SIZE/sizeof(unsigned long); - unsigned long * addr = (unsigned long *)info->memory_base; - - /* Test data lines with test pattern at one location. */ - - for ( i = 0 ; i < count ; i++ ) { - *addr = testval[i]; - if ( *addr != testval[i] ) - return false; - } - - /* Test address lines with incrementing pattern over */ - /* entire address range. */ - - for ( i = 0 ; i < limit ; i++ ) { - *addr = i * 4; - addr++; - } - - addr = (unsigned long *)info->memory_base; - - for ( i = 0 ; i < limit ; i++ ) { - if ( *addr != i * 4 ) - return false; - addr++; - } - - memset( info->memory_base, 0, SCA_MEM_SIZE ); - return true; -} - -/* Load data into PCI adapter shared memory. - * - * The PCI9050 releases control of the local bus - * after completing the current read or write operation. - * - * While the PCI9050 write FIFO not empty, the - * PCI9050 treats all of the writes as a single transaction - * and does not release the bus. This causes DMA latency problems - * at high speeds when copying large data blocks to the shared memory. - * - * This function breaks a write into multiple transations by - * interleaving a read which flushes the write FIFO and 'completes' - * the write transation. This allows any pending DMA request to gain control - * of the local bus in a timely fasion. - */ -static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count) -{ - /* A load interval of 16 allows for 4 32-bit writes at */ - /* 136ns each for a maximum latency of 542ns on the local bus.*/ - - unsigned short interval = count / sca_pci_load_interval; - unsigned short i; - - for ( i = 0 ; i < interval ; i++ ) - { - memcpy(dest, src, sca_pci_load_interval); - read_status_reg(info); - dest += sca_pci_load_interval; - src += sca_pci_load_interval; - } - - memcpy(dest, src, count % sca_pci_load_interval); -} - -static void trace_block(SLMP_INFO *info,const char* data, int count, int xmit) -{ - int i; - int linecount; - if (xmit) - printk("%s tx data:\n",info->device_name); - else - printk("%s rx data:\n",info->device_name); - - while(count) { - if (count > 16) - linecount = 16; - else - linecount = 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; - } -} /* end of trace_block() */ - -/* called when HDLC frame times out - * update stats and do tx completion processing - */ -static void tx_timeout(struct timer_list *t) -{ - SLMP_INFO *info = from_timer(info, t, tx_timer); - unsigned long flags; - - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s tx_timeout()\n", - __FILE__,__LINE__,info->device_name); - if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { - info->icount.txtimeout++; - } - spin_lock_irqsave(&info->lock,flags); - info->tx_active = false; - info->tx_count = info->tx_put = info->tx_get = 0; - - spin_unlock_irqrestore(&info->lock,flags); - -#if SYNCLINK_GENERIC_HDLC - if (info->netcount) - hdlcdev_tx_done(info); - else -#endif - bh_transmit(info); -} - -/* called to periodically check the DSR/RI modem signal input status - */ -static void status_timeout(struct timer_list *t) -{ - u16 status = 0; - SLMP_INFO *info = from_timer(info, t, status_timer); - unsigned long flags; - unsigned char delta; - - - spin_lock_irqsave(&info->lock,flags); - get_signals(info); - spin_unlock_irqrestore(&info->lock,flags); - - /* check for DSR/RI state change */ - - delta = info->old_signals ^ info->serial_signals; - info->old_signals = info->serial_signals; - - if (delta & SerialSignal_DSR) - status |= MISCSTATUS_DSR_LATCHED|(info->serial_signals&SerialSignal_DSR); - - if (delta & SerialSignal_RI) - status |= MISCSTATUS_RI_LATCHED|(info->serial_signals&SerialSignal_RI); - - if (delta & SerialSignal_DCD) - status |= MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD); - - if (delta & SerialSignal_CTS) - status |= MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS); - - if (status) - isr_io_pin(info,status); - - mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10)); -} - - -/* Register Access Routines - - * All registers are memory mapped - */ -#define CALC_REGADDR() \ - unsigned char * RegAddr = (unsigned char*)(info->sca_base + Addr); \ - if (info->port_num > 1) \ - RegAddr += 256; /* port 0-1 SCA0, 2-3 SCA1 */ \ - if ( info->port_num & 1) { \ - if (Addr > 0x7f) \ - RegAddr += 0x40; /* DMA access */ \ - else if (Addr > 0x1f && Addr < 0x60) \ - RegAddr += 0x20; /* MSCI access */ \ - } - - -static unsigned char read_reg(SLMP_INFO * info, unsigned char Addr) -{ - CALC_REGADDR(); - return *RegAddr; -} -static void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value) -{ - CALC_REGADDR(); - *RegAddr = Value; -} - -static u16 read_reg16(SLMP_INFO * info, unsigned char Addr) -{ - CALC_REGADDR(); - return *((u16 *)RegAddr); -} - -static void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value) -{ - CALC_REGADDR(); - *((u16 *)RegAddr) = Value; -} - -static unsigned char read_status_reg(SLMP_INFO * info) -{ - unsigned char *RegAddr = (unsigned char *)info->statctrl_base; - return *RegAddr; -} - -static void write_control_reg(SLMP_INFO * info) -{ - unsigned char *RegAddr = (unsigned char *)info->statctrl_base; - *RegAddr = info->port_array[0]->ctrlreg_value; -} - - -static int synclinkmp_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; - } - return device_init( ++synclinkmp_adapter_count, dev ); -} - -static void synclinkmp_remove_one (struct pci_dev *dev) -{ -} From cbd90e746148339ddbf6b980438b0adad990321e Mon Sep 17 00:00:00 2001 From: YueHaibing <yuehaibing@huawei.com> Date: Sat, 31 Oct 2020 11:05:30 +0800 Subject: [PATCH 55/89] serial: mctrl_gpio: Fix passing zero to 'ERR_PTR' warning drivers/tty/serial/serial_mctrl_gpio.c:214 mctrl_gpio_init() warn: passing zero to 'ERR_PTR' gpiod_to_irq() never return 0, so remove the useless test and make code more clear. Reviewed-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: YueHaibing <yuehaibing@huawei.com> Link: https://lore.kernel.org/r/20201031030530.1304-1-yuehaibing@huawei.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/serial_mctrl_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index fb4781292d40..c41d8911ce95 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -207,7 +207,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) continue; ret = gpiod_to_irq(gpios->gpio[i]); - if (ret <= 0) { + if (ret < 0) { dev_err(port->dev, "failed to find corresponding irq for %s (idx=%d, err=%d)\n", mctrl_gpios_desc[i].name, idx, ret); From 80f510f5fd078379b772f3b745c49e1db949bb43 Mon Sep 17 00:00:00 2001 From: Liu Xiang <liuxiang_1999@126.com> Date: Fri, 30 Oct 2020 21:43:11 +0800 Subject: [PATCH 56/89] tty: serial: linflexuart: Remove unnecessary '|' operation and add error count The '|' operation of status in linflex_rxint is unnecessary, so it can be removed. Signed-off-by: Liu Xiang <liuxiang_1999@126.com> Link: https://lore.kernel.org/r/1604065391-3790-1-git-send-email-liuxiang_1999@126.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/fsl_linflexuart.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index 3e28be402aef..d87048073abe 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -252,23 +252,22 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id) flg = TTY_NORMAL; sport->icount.rx++; - if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_SZF | - LINFLEXD_UARTSR_FEF | LINFLEXD_UARTSR_PE)) { - if (status & LINFLEXD_UARTSR_SZF) - status |= LINFLEXD_UARTSR_SZF; + if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_FEF | + LINFLEXD_UARTSR_PE)) { if (status & LINFLEXD_UARTSR_BOF) - status |= LINFLEXD_UARTSR_BOF; + sport->icount.overrun++; if (status & LINFLEXD_UARTSR_FEF) { - if (!rx) + if (!rx) { brk = true; - status |= LINFLEXD_UARTSR_FEF; + sport->icount.brk++; + } else + sport->icount.frame++; } if (status & LINFLEXD_UARTSR_PE) - status |= LINFLEXD_UARTSR_PE; + sport->icount.parity++; } - writel(status | LINFLEXD_UARTSR_RMB | LINFLEXD_UARTSR_DRFRFE, - sport->membase + UARTSR); + writel(status, sport->membase + UARTSR); status = readl(sport->membase + UARTSR); if (brk) { From 439c7183e5b97952bba1747f5ffc4dea45a6a18b Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra <vigneshr@ti.com> Date: Thu, 29 Oct 2020 10:49:30 +0530 Subject: [PATCH 57/89] serial: 8250: 8250_omap: Disable RX interrupt after DMA enable UARTs on TI SoCs prior to J7200 don't provide independent control over RX FIFO not empty interrupt (RHR_IT) and RX timeout interrupt. Starting with J7200 SoC, its possible to disable RHR_IT independent of RX timeout interrupt using bit 2 of IER2 register. So disable RHR_IT once RX DMA is started so as to avoid spurious interrupt being raised when data is in the RX FIFO but is yet to be drained by DMA (a known errata in older SoCs). Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> Link: https://lore.kernel.org/r/20201029051930.7097-1-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/8250/8250_omap.c | 42 ++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 562087df7d33..084e7bc51f0e 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -27,6 +27,7 @@ #include <linux/pm_qos.h> #include <linux/pm_wakeirq.h> #include <linux/dma-mapping.h> +#include <linux/sys_soc.h> #include "8250.h" @@ -41,6 +42,7 @@ */ #define UART_ERRATA_CLOCK_DISABLE (1 << 3) #define UART_HAS_EFR2 BIT(4) +#define UART_HAS_RHR_IT_DIS BIT(5) #define OMAP_UART_FCR_RX_TRIG 6 #define OMAP_UART_FCR_TX_TRIG 4 @@ -94,6 +96,10 @@ #define OMAP_UART_REV_52 0x0502 #define OMAP_UART_REV_63 0x0603 +/* Interrupt Enable Register 2 */ +#define UART_OMAP_IER2 0x1B +#define UART_OMAP_IER2_RHR_IT_DIS BIT(2) + /* Enhanced features register 2 */ #define UART_OMAP_EFR2 0x23 #define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6) @@ -761,17 +767,27 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; + struct omap8250_priv *priv = p->port.private_data; struct dma_chan *rxchan = dma->rxchan; dma_cookie_t cookie; struct dma_tx_state state; int count; int ret; + u32 reg; if (!dma->rx_running) goto out; cookie = dma->rx_cookie; dma->rx_running = 0; + + /* Re-enable RX FIFO interrupt now that transfer is complete */ + if (priv->habit & UART_HAS_RHR_IT_DIS) { + reg = serial_in(p, UART_OMAP_IER2); + reg &= ~UART_OMAP_IER2_RHR_IT_DIS; + serial_out(p, UART_OMAP_IER2, UART_OMAP_IER2_RHR_IT_DIS); + } + dmaengine_tx_status(rxchan, cookie, &state); count = dma->rx_size - state.residue + state.in_flight_bytes; @@ -867,6 +883,7 @@ static int omap_8250_rx_dma(struct uart_8250_port *p) int err = 0; struct dma_async_tx_descriptor *desc; unsigned long flags; + u32 reg; if (priv->rx_dma_broken) return -EINVAL; @@ -902,6 +919,17 @@ static int omap_8250_rx_dma(struct uart_8250_port *p) dma->rx_cookie = dmaengine_submit(desc); + /* + * Disable RX FIFO interrupt while RX DMA is enabled, else + * spurious interrupt may be raised when data is in the RX FIFO + * but is yet to be drained by DMA. + */ + if (priv->habit & UART_HAS_RHR_IT_DIS) { + reg = serial_in(p, UART_OMAP_IER2); + reg |= UART_OMAP_IER2_RHR_IT_DIS; + serial_out(p, UART_OMAP_IER2, UART_OMAP_IER2_RHR_IT_DIS); + } + dma_async_issue_pending(dma->rxchan); out: spin_unlock_irqrestore(&priv->rx_dma_lock, flags); @@ -1168,6 +1196,11 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static const struct soc_device_attribute k3_soc_devices[] = { + { .family = "AM65X", }, + { .family = "J721E", .revision = "SR1.0" }, +}; + static struct omap8250_dma_params am654_dma = { .rx_size = SZ_2K, .rx_trigger = 1, @@ -1182,7 +1215,7 @@ static struct omap8250_dma_params am33xx_dma = { static struct omap8250_platdata am654_platdata = { .dma_params = &am654_dma, - .habit = UART_HAS_EFR2, + .habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS, }; static struct omap8250_platdata am33xx_platdata = { @@ -1372,6 +1405,13 @@ static int omap8250_probe(struct platform_device *pdev) up.dma->rxconf.src_maxburst = RX_TRIGGER; up.dma->txconf.dst_maxburst = TX_TRIGGER; } + + /* + * AM65x SR1.0, AM65x SR2.0 and J721e SR1.0 don't + * don't have RHR_IT_DIS bit in IER2 register + */ + if (soc_device_match(k3_soc_devices)) + priv->habit &= ~UART_HAS_RHR_IT_DIS; } #endif ret = serial8250_register_8250_port(&up); From 0d66442dfdbd45019c60bb6aeaf2d5eb45534606 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn <rikard.falkeborn@gmail.com> Date: Thu, 5 Nov 2020 00:51:34 +0100 Subject: [PATCH 58/89] tty: serial: msm_serial: Constify msm_uart_pops The only usage of msm_uart_pops is to assign its address to the ops field in the uart_port struct, which is a pointer to const. Make it const to allow the compiler to put it in read-only memory. Reviewed-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com> Signed-off-by: Rikard Falkeborn <rikard.falkeborn@gmail.com> Link: https://lore.kernel.org/r/20201104235134.17793-1-rikard.falkeborn@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/msm_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index ec31a809644a..770c182e2208 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1524,7 +1524,7 @@ static void msm_poll_put_char(struct uart_port *port, unsigned char c) } #endif -static struct uart_ops msm_uart_pops = { +static const struct uart_ops msm_uart_pops = { .tx_empty = msm_tx_empty, .set_mctrl = msm_set_mctrl, .get_mctrl = msm_get_mctrl, From 441494ec2a302830357d0aa59f3b907e319a8b26 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra <vigneshr@ti.com> Date: Thu, 29 Oct 2020 12:23:18 +0530 Subject: [PATCH 59/89] dt-bindings: serial: 8250_omap: Add compatible for UART controller on AM64 SoC AM64 uses a UART controller that is compatible with AM654 UART. Introduce a specific compatible to help handle the differences if necessary. Reviewed-by: Nishanth Menon <nm@ti.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> Link: https://lore.kernel.org/r/20201029065318.2437-1-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- Documentation/devicetree/bindings/serial/omap_serial.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt index dcba86b0a0d0..c2db8cabf2ab 100644 --- a/Documentation/devicetree/bindings/serial/omap_serial.txt +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -1,6 +1,7 @@ OMAP UART controller Required properties: +- compatible : should be "ti,am64-uart", "ti,am654-uart" for AM64 controllers - compatible : should be "ti,j721e-uart", "ti,am654-uart" for J721E controllers - compatible : should be "ti,am654-uart" for AM654 controllers - compatible : should be "ti,omap2-uart" for OMAP2 controllers From d4548b14dd7e5c698f81ce23ce7b69a896373b45 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra <vigneshr@ti.com> Date: Wed, 11 Nov 2020 16:56:52 +0530 Subject: [PATCH 60/89] serial: 8250: 8250_omap: Fix possible array out of bounds access k3_soc_devices array is missing a sentinel entry which may result in out of bounds access as reported by kernel KASAN. Fix this by adding a sentinel entry. Fixes: 439c7183e5b9 ("serial: 8250: 8250_omap: Disable RX interrupt after DMA enable") Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> Link: https://lore.kernel.org/r/20201111112653.2710-1-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/8250/8250_omap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 084e7bc51f0e..ab18ef035659 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1199,6 +1199,7 @@ static int omap8250_no_handle_irq(struct uart_port *port) static const struct soc_device_attribute k3_soc_devices[] = { { .family = "AM65X", }, { .family = "J721E", .revision = "SR1.0" }, + { /* sentinel */ } }; static struct omap8250_dma_params am654_dma = { From 6f991850412963381017cfb0d691cbd4d6a551dc Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra <vigneshr@ti.com> Date: Wed, 11 Nov 2020 16:56:53 +0530 Subject: [PATCH 61/89] serial: 8250: 8250_omap: Fix unused variable warning With commit 439c7183e5b9 ("serial: 8250: 8250_omap: Disable RX interrupt after DMA enable"), below warning is seen with W=1 and CONFIG_SERIAL_8250_DMA is disabled: drivers/tty/serial/8250/8250_omap.c:1199:42: warning: unused variable 'k3_soc_devices' [-Wunused-const-variable] Fix this by moving the code using k3_soc_devices array to omap_serial_fill_features_erratas() that handles other errata flags as well. Fixes: 439c7183e5b9 ("serial: 8250: 8250_omap: Disable RX interrupt after DMA enable") Reported-by: kernel test robot <lkp@intel.com> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> Link: https://lore.kernel.org/r/20201111112653.2710-2-vigneshr@ti.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/8250/8250_omap.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index ab18ef035659..0ab6517d389a 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -539,6 +539,11 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, static void omap_serial_fill_features_erratas(struct uart_8250_port *up, struct omap8250_priv *priv) { + const struct soc_device_attribute k3_soc_devices[] = { + { .family = "AM65X", }, + { .family = "J721E", .revision = "SR1.0" }, + { /* sentinel */ } + }; u32 mvr, scheme; u16 revision, major, minor; @@ -586,6 +591,14 @@ static void omap_serial_fill_features_erratas(struct uart_8250_port *up, default: break; } + + /* + * AM65x SR1.0, AM65x SR2.0 and J721e SR1.0 don't + * don't have RHR_IT_DIS bit in IER2 register. So drop to flag + * to enable errata workaround. + */ + if (soc_device_match(k3_soc_devices)) + priv->habit &= ~UART_HAS_RHR_IT_DIS; } static void omap8250_uart_qos_work(struct work_struct *work) @@ -1196,12 +1209,6 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } -static const struct soc_device_attribute k3_soc_devices[] = { - { .family = "AM65X", }, - { .family = "J721E", .revision = "SR1.0" }, - { /* sentinel */ } -}; - static struct omap8250_dma_params am654_dma = { .rx_size = SZ_2K, .rx_trigger = 1, @@ -1406,13 +1413,6 @@ static int omap8250_probe(struct platform_device *pdev) up.dma->rxconf.src_maxburst = RX_TRIGGER; up.dma->txconf.dst_maxburst = TX_TRIGGER; } - - /* - * AM65x SR1.0, AM65x SR2.0 and J721e SR1.0 don't - * don't have RHR_IT_DIS bit in IER2 register - */ - if (soc_device_match(k3_soc_devices)) - priv->habit &= ~UART_HAS_RHR_IT_DIS; } #endif ret = serial8250_register_8250_port(&up); From c050a97d05740609794f3da38f1be8ec4a65157d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Date: Mon, 9 Nov 2020 12:55:59 +0200 Subject: [PATCH 62/89] vt: keyboard, use BIT() macro instead of open coded variants There are few places when BIT() macro is suitable and makes code easier to understand. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/20201109105601.47159-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 56b5e8f8fe88..05d7e812e0f5 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -53,7 +53,7 @@ * Exported functions/variables */ -#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) +#define KBD_DEFMODE (BIT(VC_REPEAT) | BIT(VC_META)) #if defined(CONFIG_X86) || defined(CONFIG_PARISC) #include <asm/kbdleds.h> @@ -857,9 +857,9 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) shift_down[value]++; if (shift_down[value]) - shift_state |= (1 << value); + shift_state |= BIT(value); else - shift_state &= ~(1 << value); + shift_state &= ~BIT(value); /* kludge */ if (up_flag && shift_state != old_state && npadch_active) { @@ -880,7 +880,7 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) put_queue(vc, '\033'); put_queue(vc, value); } else - put_queue(vc, value | 0x80); + put_queue(vc, value | BIT(7)); } static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) @@ -976,7 +976,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) return; if (!up_flag) { - pressed |= 1 << (value - 1); + pressed |= BIT(value - 1); if (!brl_timeout) committing = pressed; } else if (brl_timeout) { @@ -986,7 +986,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) committing = pressed; releasestart = jiffies; } - pressed &= ~(1 << (value - 1)); + pressed &= ~BIT(value - 1); if (!pressed && committing) { k_brlcommit(vc, committing, 0); committing = 0; @@ -996,7 +996,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) k_brlcommit(vc, committing, 0); committing = 0; } - pressed &= ~(1 << (value - 1)); + pressed &= ~BIT(value - 1); } } @@ -1096,9 +1096,9 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) unsigned int leds = *(unsigned int *)data; if (test_bit(EV_LED, handle->dev->evbit)) { - input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); - input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & BIT(0))); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & BIT(1))); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & BIT(2))); input_inject_event(handle, EV_SYN, SYN_REPORT, 0); } @@ -1427,8 +1427,8 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw) put_queue(vc, keycode | (!down << 7)); } else { put_queue(vc, !down << 7); - put_queue(vc, (keycode >> 7) | 0x80); - put_queue(vc, keycode | 0x80); + put_queue(vc, (keycode >> 7) | BIT(7)); + put_queue(vc, keycode | BIT(7)); } raw_mode = true; } @@ -1487,7 +1487,7 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw) if (type == KT_LETTER) { type = KT_LATIN; if (vc_kbd_led(kbd, VC_CAPSLOCK)) { - key_map = key_maps[shift_final ^ (1 << KG_SHIFT)]; + key_map = key_maps[shift_final ^ BIT(KG_SHIFT)]; if (key_map) keysym = key_map[keycode]; } From 6d2c52a83b926bdfc0e4311041459306eac7c48b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Date: Mon, 9 Nov 2020 12:56:00 +0200 Subject: [PATCH 63/89] vt: keyboard, replace numbers with \r, \n where appropriate Instead of 10, 13 use \n, \r respectively. Acked-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/20201109105601.47159-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 05d7e812e0f5..872791551c77 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -462,9 +462,9 @@ static void fn_enter(struct vc_data *vc) diacr = 0; } - put_queue(vc, 13); + put_queue(vc, '\r'); if (vc_kbd_mode(kbd, VC_CRLF)) - put_queue(vc, 10); + put_queue(vc, '\n'); } static void fn_caps_toggle(struct vc_data *vc) @@ -827,7 +827,7 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) put_queue(vc, pad_chars[value]); if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) - put_queue(vc, 10); + put_queue(vc, '\n'); } static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) From cb215da8369cbbbe3b6260b2ca43518f884ddc6b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Date: Mon, 9 Nov 2020 12:56:01 +0200 Subject: [PATCH 64/89] vt: keyboard, make use of assign_bit() API We have for some time the assign_bit() API to replace open coded if (foo) set_bit(n, bar); else clear_bit(n, bar); Use this API in VT keyboard library code. Acked-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/20201109105601.47159-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/keyboard.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 872791551c77..52922d21a49f 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1433,10 +1433,7 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw) raw_mode = true; } - if (down) - set_bit(keycode, key_down); - else - clear_bit(keycode, key_down); + assign_bit(keycode, key_down, down); if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || From 1f78ae99790812481b7944cf40008aed5fd2ef18 Mon Sep 17 00:00:00 2001 From: Fabio Estevam <festevam@gmail.com> Date: Tue, 10 Nov 2020 18:48:40 -0300 Subject: [PATCH 65/89] serial: imx: Remove unused platform data support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 5.10-rc1 i.MX is a devicetree-only platform and the existing platform data support in this driver was only useful for old non-devicetree platforms. Get rid of the platform data support since it is no longer used. Reviewed-by: Fugang Duan <fugang.duan@nxp.com> Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Fabio Estevam <festevam@gmail.com> Link: https://lore.kernel.org/r/20201110214840.16768-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/imx.c | 32 +++--------------------- include/linux/platform_data/serial-imx.h | 15 ----------- 2 files changed, 3 insertions(+), 44 deletions(-) delete mode 100644 include/linux/platform_data/serial-imx.h diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 1731d9728865..7ce38ade9a8e 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -30,7 +30,6 @@ #include <linux/dma-mapping.h> #include <asm/irq.h> -#include <linux/platform_data/serial-imx.h> #include <linux/platform_data/dma-imx.h> #include "serial_mctrl_gpio.h" @@ -2191,10 +2190,9 @@ static struct uart_driver imx_uart_uart_driver = { .cons = IMX_CONSOLE, }; -#ifdef CONFIG_OF /* - * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it - * could successfully get all information from dt or a negative errno. + * This function returns 0 iff it could successfully get all information + * from dt or a negative errno. */ static int imx_uart_probe_dt(struct imx_port *sport, struct platform_device *pdev) @@ -2232,28 +2230,6 @@ static int imx_uart_probe_dt(struct imx_port *sport, return 0; } -#else -static inline int imx_uart_probe_dt(struct imx_port *sport, - struct platform_device *pdev) -{ - return 1; -} -#endif - -static void imx_uart_probe_pdata(struct imx_port *sport, - struct platform_device *pdev) -{ - struct imxuart_platform_data *pdata = dev_get_platdata(&pdev->dev); - - sport->port.line = pdev->id; - sport->devdata = (struct imx_uart_data *) pdev->id_entry->driver_data; - - if (!pdata) - return; - - if (pdata->flags & IMXUART_HAVE_RTSCTS) - sport->have_rtscts = 1; -} static enum hrtimer_restart imx_trigger_start_tx(struct hrtimer *t) { @@ -2295,9 +2271,7 @@ static int imx_uart_probe(struct platform_device *pdev) return -ENOMEM; ret = imx_uart_probe_dt(sport, pdev); - if (ret > 0) - imx_uart_probe_pdata(sport, pdev); - else if (ret < 0) + if (ret < 0) return ret; if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) { diff --git a/include/linux/platform_data/serial-imx.h b/include/linux/platform_data/serial-imx.h deleted file mode 100644 index 0844b21372c7..000000000000 --- a/include/linux/platform_data/serial-imx.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> - */ - -#ifndef ASMARM_ARCH_UART_H -#define ASMARM_ARCH_UART_H - -#define IMXUART_HAVE_RTSCTS (1<<0) - -struct imxuart_platform_data { - unsigned int flags; -}; - -#endif From a609c58086e381c13bdad1ba97e6510a13d465e7 Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Thu, 12 Nov 2020 10:58:55 +0000 Subject: [PATCH 66/89] tty: serial: 8250: 8250_port: Move prototypes to shared location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serial/8250/8250_port.c:349:14: warning: no previous prototype for ‘au_serial_in’ [-Wmissing-prototypes] drivers/tty/serial/8250/8250_port.c:359:6: warning: no previous prototype for ‘au_serial_out’ [-Wmissing-prototypes] Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Mike Hudson <Exoray@isys.ca> Cc: linux-serial@vger.kernel.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201112105857.2078977-3-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/8250/8250_early.c | 3 --- include/linux/serial_8250.h | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 70d7826788f5..c171ce6db691 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -204,9 +204,6 @@ OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup); #ifdef CONFIG_SERIAL_8250_RT288X -unsigned int au_serial_in(struct uart_port *p, int offset); -void au_serial_out(struct uart_port *p, int offset, int value); - static int __init early_au_setup(struct earlycon_device *dev, const char *opt) { dev->port.serial_in = au_serial_in; diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 2b70f736b091..9e655055112d 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -187,4 +187,9 @@ extern void serial8250_set_isa_configurator(void (*v) (int port, struct uart_port *up, u32 *capabilities)); +#ifdef CONFIG_SERIAL_8250_RT288X +unsigned int au_serial_in(struct uart_port *p, int offset); +void au_serial_out(struct uart_port *p, int offset, int value); +#endif + #endif From 59105f9cf6e28c51ed8c93cbc44f278caa3b2b4e Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Thu, 12 Nov 2020 10:58:57 +0000 Subject: [PATCH 67/89] tty: serial: pmac_zilog: Remove unused disposable variable 'garbage' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following W=1 kernel build warning(s): drivers/tty/serial/pmac_zilog.h:365:58: warning: variable ‘garbage’ set but not used [-Wunused-but-set-variable] Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: linux-serial@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201112105857.2078977-5-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/pmac_zilog.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/pmac_zilog.h b/drivers/tty/serial/pmac_zilog.h index bb874e76810e..fa85b0de5c2f 100644 --- a/drivers/tty/serial/pmac_zilog.h +++ b/drivers/tty/serial/pmac_zilog.h @@ -362,10 +362,10 @@ static inline void zssync(struct uart_pmac_port *port) /* Misc macros */ #define ZS_CLEARERR(port) (write_zsreg(port, 0, ERR_RES)) -#define ZS_CLEARFIFO(port) do { volatile unsigned char garbage; \ - garbage = read_zsdata(port); \ - garbage = read_zsdata(port); \ - garbage = read_zsdata(port); \ +#define ZS_CLEARFIFO(port) do { \ + read_zsdata(port); \ + read_zsdata(port); \ + read_zsdata(port); \ } while(0) #define ZS_IS_CONS(UP) ((UP)->flags & PMACZILOG_FLAG_IS_CONS) From bc0468ee4922b04e529da4734bfcd3f19152db8e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Date: Fri, 13 Nov 2020 15:51:36 +0900 Subject: [PATCH 68/89] dt-bindings: serial: renesas,scif: Document r8a779a0 bindings R-Car V3U (R8A779A0) SoC also has the R-Car Gen3 compatible SCIF ports, so document the SoC specific bindings. Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> Acked-by: Rob Herring <robh@kernel.org> Link: https://lore.kernel.org/r/1605250296-30570-1-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- Documentation/devicetree/bindings/serial/renesas,scif.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml index eda3d2c6bdd3..672158906c33 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml @@ -60,6 +60,7 @@ properties: - renesas,scif-r8a77980 # R-Car V3H - renesas,scif-r8a77990 # R-Car E3 - renesas,scif-r8a77995 # R-Car D3 + - renesas,scif-r8a779a0 # R-Car V3U - const: renesas,rcar-gen3-scif # R-Car Gen3 and RZ/G2 - const: renesas,scif # generic SCIF compatible UART From 8eddcca2a746d15f4b1e58274801f9d9acf7bbcc Mon Sep 17 00:00:00 2001 From: Lee Jones <lee.jones@linaro.org> Date: Thu, 12 Nov 2020 10:58:54 +0000 Subject: [PATCH 69/89] tty: tty_ldisc: Fix some kernel-doc related misdemeanours - Functions must follow directly on from their headers - Demote non-conforming kernel-doc header - Ensure notes have unique section names - Provide missing description for 'reinit' Fixes the following W=1 kernel build warning(s): drivers/tty/tty_ldisc.c:158: warning: cannot understand function prototype: 'int tty_ldisc_autoload = IS_BUILTIN(CONFIG_LDISC_AUTOLOAD); ' drivers/tty/tty_ldisc.c:199: warning: Function parameter or member 'ld' not described in 'tty_ldisc_put' drivers/tty/tty_ldisc.c:260: warning: duplicate section name 'Note' drivers/tty/tty_ldisc.c:717: warning: Function parameter or member 'reinit' not described in 'tty_ldisc_hangup' Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org> Link: https://lore.kernel.org/r/20201112105857.2078977-2-lee.jones@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_ldisc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index e813808b27a7..1ba74d6f5e5c 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -135,6 +135,7 @@ static void put_ldops(struct tty_ldisc_ops *ldops) raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); } +static int tty_ldisc_autoload = IS_BUILTIN(CONFIG_LDISC_AUTOLOAD); /** * tty_ldisc_get - take a reference to an ldisc * @tty: tty device @@ -156,8 +157,6 @@ static void put_ldops(struct tty_ldisc_ops *ldops) * takes tty_ldiscs_lock to guard against ldisc races */ -static int tty_ldisc_autoload = IS_BUILTIN(CONFIG_LDISC_AUTOLOAD); - static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) { struct tty_ldisc *ld; @@ -191,7 +190,7 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) return ld; } -/** +/* * tty_ldisc_put - release the ldisc * * Complement of tty_ldisc_get(). @@ -251,12 +250,12 @@ const struct seq_operations tty_ldiscs_seq_ops = { * Returns: NULL if the tty has been hungup and not re-opened with * a new file descriptor, otherwise valid ldisc reference * - * Note: Must not be called from an IRQ/timer context. The caller + * Note 1: Must not be called from an IRQ/timer context. The caller * must also be careful not to hold other locks that will deadlock * against a discipline change, such as an existing ldisc reference * (which we check for) * - * Note: a file_operations routine (read/poll/write) should use this + * Note 2: a file_operations routine (read/poll/write) should use this * function to wait for any ldisc lifetime events to finish. */ @@ -702,6 +701,7 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc) /** * tty_ldisc_hangup - hangup ldisc reset * @tty: tty being hung up + * @reinit: whether to re-initialise the tty * * Some tty devices reset their termios when they receive a hangup * event. In that situation we must also switch back to N_TTY properly From 660beb0ffdc9fc0695321dde5e115cd8cc384c94 Mon Sep 17 00:00:00 2001 From: Fabio Estevam <festevam@gmail.com> Date: Sun, 15 Nov 2020 08:03:41 -0300 Subject: [PATCH 70/89] serial: imx: Remove unused .id_table support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 5.10-rc1 i.MX is a devicetree-only platform and the existing .id_table support in this driver was only useful for old non-devicetree platforms. Get rid of the .id_table since it is no longer used. Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Fabio Estevam <festevam@gmail.com> Link: https://lore.kernel.org/r/20201115110341.22761-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/imx.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 7ce38ade9a8e..5634c7e498a3 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -262,25 +262,6 @@ static struct imx_uart_data imx_uart_devdata[] = { }, }; -static const struct platform_device_id imx_uart_devtype[] = { - { - .name = "imx1-uart", - .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART], - }, { - .name = "imx21-uart", - .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART], - }, { - .name = "imx53-uart", - .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX53_UART], - }, { - .name = "imx6q-uart", - .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART], - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, imx_uart_devtype); - static const struct of_device_id imx_uart_dt_ids[] = { { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], }, { .compatible = "fsl,imx53-uart", .data = &imx_uart_devdata[IMX53_UART], }, @@ -2621,7 +2602,6 @@ static struct platform_driver imx_uart_platform_driver = { .probe = imx_uart_probe, .remove = imx_uart_remove, - .id_table = imx_uart_devtype, .driver = { .name = "imx-uart", .of_match_table = imx_uart_dt_ids, From 6e4e636e0e3e0b5deffc5e233adcb2cd4e68f2d0 Mon Sep 17 00:00:00 2001 From: Zhang Qilong <zhangqilong3@huawei.com> Date: Thu, 19 Nov 2020 22:11:26 +0800 Subject: [PATCH 71/89] serial: 8250-mtk: Fix reference leak in mtk8250_probe The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. Fixes: e32a83c70cf98 ("serial: 8250-mtk: modify mtk uart power and clock management") Signed-off-by: Zhang Qilong <zhangqilong3@huawei.com> Link: https://lore.kernel.org/r/20201119141126.168850-1-zhangqilong3@huawei.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/8250/8250_mtk.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index fa876e2c13e5..f7d3023f860f 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -572,15 +572,22 @@ static int mtk8250_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); err = mtk8250_runtime_resume(&pdev->dev); if (err) - return err; + goto err_pm_disable; data->line = serial8250_register_8250_port(&uart); - if (data->line < 0) - return data->line; + if (data->line < 0) { + err = data->line; + goto err_pm_disable; + } data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1); return 0; + +err_pm_disable: + pm_runtime_disable(&pdev->dev); + + return err; } static int mtk8250_remove(struct platform_device *pdev) From 5f1697fee6f6758ec1001569ae26d7a70a8bbc8e Mon Sep 17 00:00:00 2001 From: Fabio Estevam <festevam@gmail.com> Date: Mon, 23 Nov 2020 16:04:38 -0300 Subject: [PATCH 72/89] serial: mxs-auart: Remove unneeded platform_device_id The mxs-auart driver is only used for DT platforms and there is no need to use the platform_device_id structure. Get rid the platform_device_id structure and retrieve the data via of_device_get_match_data(), which simplifies the code. Signed-off-by: Fabio Estevam <festevam@gmail.com> Link: https://lore.kernel.org/r/20201123190438.5636-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/mxs-auart.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index b784323a6a7b..8ecf622602cb 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -443,24 +443,16 @@ struct mxs_auart_port { bool ms_irq_enabled; }; -static const struct platform_device_id mxs_auart_devtype[] = { - { .name = "mxs-auart-imx23", .driver_data = IMX23_AUART }, - { .name = "mxs-auart-imx28", .driver_data = IMX28_AUART }, - { .name = "as-auart-asm9260", .driver_data = ASM9260_AUART }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(platform, mxs_auart_devtype); - static const struct of_device_id mxs_auart_dt_ids[] = { { .compatible = "fsl,imx28-auart", - .data = &mxs_auart_devtype[IMX28_AUART] + .data = (const void *)IMX28_AUART }, { .compatible = "fsl,imx23-auart", - .data = &mxs_auart_devtype[IMX23_AUART] + .data = (const void *)IMX23_AUART }, { .compatible = "alphascale,asm9260-auart", - .data = &mxs_auart_devtype[ASM9260_AUART] + .data = (const void *)ASM9260_AUART }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids); @@ -1639,8 +1631,6 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s) static int mxs_auart_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = - of_match_device(mxs_auart_dt_ids, &pdev->dev); struct mxs_auart_port *s; u32 version; int ret, irq; @@ -1663,10 +1653,7 @@ static int mxs_auart_probe(struct platform_device *pdev) return -EINVAL; } - if (of_id) { - pdev->id_entry = of_id->data; - s->devtype = pdev->id_entry->driver_data; - } + s->devtype = (enum mxs_auart_type)of_device_get_match_data(&pdev->dev); ret = mxs_get_clks(s, pdev); if (ret) From f35a07f92616700733636c06dd6e5b6cdc807fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl> Date: Wed, 25 Nov 2020 10:06:08 +0100 Subject: [PATCH 73/89] tty: serial: bcm63xx: lower driver dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardware supported by bcm63xx is also used by BCM4908 SoCs family that is ARM64. In future more architectures may need it as well. There is nothing arch specific breaking compilation so just stick to requiring COMMON_CLK. Signed-off-by: Rafał Miłecki <rafal@milecki.pl> Link: https://lore.kernel.org/r/20201125090608.28442-1-zajec5@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 8788e504ffb5..2d73b823e91c 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1117,7 +1117,7 @@ config SERIAL_TIMBERDALE config SERIAL_BCM63XX tristate "Broadcom BCM63xx/BCM33xx UART support" select SERIAL_CORE - depends on MIPS || ARM || COMPILE_TEST + depends on COMMON_CLK help This enables the driver for the onchip UART core found on the following chipsets: From 62dcd9c59f324e484c1d655884e0101a988f6671 Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Mon, 23 Nov 2020 11:23:13 +0100 Subject: [PATCH 74/89] earlycon: simplify earlycon-table implementation Instead of using the array-of-pointers trick to avoid having gcc mess up the earlycon array stride, specify type alignment when declaring entries to prevent gcc from increasing alignment. This is essentially an alternative (one-line) fix to the problem addressed by commit dd709e72cb93 ("earlycon: Use a pointer table to fix __earlycon_table stride"). gcc can increase the alignment of larger objects with static extent as an optimisation, but this can be suppressed by using the aligned attribute when declaring variables. Note that we have been relying on this behaviour for kernel parameters for 16 years and it indeed hasn't changed since the introduction of the aligned attribute in gcc-3.1. Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://lore.kernel.org/r/20201123102319.8090-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/of/fdt.c | 7 ++----- drivers/tty/serial/earlycon.c | 6 ++---- include/linux/serial_core.h | 20 +++++++------------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 4602e467ca8b..feb0f2d67fc5 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -906,7 +906,7 @@ int __init early_init_dt_scan_chosen_stdout(void) int offset; const char *p, *q, *options = NULL; int l; - const struct earlycon_id **p_match; + const struct earlycon_id *match; const void *fdt = initial_boot_params; offset = fdt_path_offset(fdt, "/chosen"); @@ -933,10 +933,7 @@ int __init early_init_dt_scan_chosen_stdout(void) return 0; } - for (p_match = __earlycon_table; p_match < __earlycon_table_end; - p_match++) { - const struct earlycon_id *match = *p_match; - + for (match = __earlycon_table; match < __earlycon_table_end; match++) { if (!match->compatible[0]) continue; diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index b70877932d47..57c70851f22a 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -175,7 +175,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) */ int __init setup_earlycon(char *buf) { - const struct earlycon_id **p_match; + const struct earlycon_id *match; bool empty_compatible = true; if (!buf || !buf[0]) @@ -185,9 +185,7 @@ int __init setup_earlycon(char *buf) return -EALREADY; again: - for (p_match = __earlycon_table; p_match < __earlycon_table_end; - p_match++) { - const struct earlycon_id *match = *p_match; + for (match = __earlycon_table; match < __earlycon_table_end; match++) { size_t len = strlen(match->name); if (strncmp(buf, match->name, len)) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index ff63c2963359..3e32b788c28d 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -357,8 +357,8 @@ struct earlycon_id { int (*setup)(struct earlycon_device *, const char *options); }; -extern const struct earlycon_id *__earlycon_table[]; -extern const struct earlycon_id *__earlycon_table_end[]; +extern const struct earlycon_id __earlycon_table[]; +extern const struct earlycon_id __earlycon_table_end[]; #if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) #define EARLYCON_USED_OR_UNUSED __used @@ -366,19 +366,13 @@ extern const struct earlycon_id *__earlycon_table_end[]; #define EARLYCON_USED_OR_UNUSED __maybe_unused #endif -#define _OF_EARLYCON_DECLARE(_name, compat, fn, unique_id) \ - static const struct earlycon_id unique_id \ - EARLYCON_USED_OR_UNUSED __initconst \ +#define OF_EARLYCON_DECLARE(_name, compat, fn) \ + static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \ + EARLYCON_USED_OR_UNUSED __section("__earlycon_table") \ + __aligned(__alignof__(struct earlycon_id)) \ = { .name = __stringify(_name), \ .compatible = compat, \ - .setup = fn }; \ - static const struct earlycon_id EARLYCON_USED_OR_UNUSED \ - __section("__earlycon_table") \ - * const __PASTE(__p, unique_id) = &unique_id - -#define OF_EARLYCON_DECLARE(_name, compat, fn) \ - _OF_EARLYCON_DECLARE(_name, compat, fn, \ - __UNIQUE_ID(__earlycon_##_name)) + .setup = fn }; #define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn) From 0b60525b4e88b0ae656b89733f577a76d474f07a Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin <alexander.sverdlin@nokia.com> Date: Fri, 27 Nov 2020 11:19:53 +0100 Subject: [PATCH 75/89] tty: serial: uartlite: Support probe deferral Give uartlite a chance to be probed when IRQ controller will be finally available and return potential -EPROBE_DEFER as-is. The condition "<=" has been changed to "<" to follow the recommendation in the header of platform_get_irq(). Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com> Link: https://lore.kernel.org/r/20201127101953.23700-1-alexander.sverdlin@nokia.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/uartlite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 09379db613d8..f42ccc40ffa6 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -773,8 +773,8 @@ static int ulite_probe(struct platform_device *pdev) return -ENODEV; irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return -ENXIO; + if (irq < 0) + return irq; pdata->clk = devm_clk_get(&pdev->dev, "s_axi_aclk"); if (IS_ERR(pdata->clk)) { From 7af77ba42467da8a4dbfe0dfd0a467227e8fbe5f Mon Sep 17 00:00:00 2001 From: Clement Smith <rclemsmith@gmail.com> Date: Wed, 2 Dec 2020 11:39:16 +0530 Subject: [PATCH 76/89] tty : serial: jsm: Fixed file by adding spacing Fixed a coding style issue Signed-off-by: Clement Smith <rclemsmith@gmail.com> Link: https://lore.kernel.org/r/20201202060916.34130-1-rclemsmith@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/jsm/jsm_tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 689774c073ca..512b77195e9f 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -607,7 +607,7 @@ void jsm_input(struct jsm_channel *ch) * Give the Linux ld the flags in the * format it likes. */ - if (*(ch->ch_equeue +tail +i) & UART_LSR_BI) + if (*(ch->ch_equeue + tail + i) & UART_LSR_BI) tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_BREAK); else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE) tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_PARITY); From aef1b6a27970607721a618a0b990716ca8dbbf97 Mon Sep 17 00:00:00 2001 From: Mingrui Ren <jiladahe1997@gmail.com> Date: Wed, 2 Dec 2020 15:25:43 +0800 Subject: [PATCH 77/89] tty/serial/imx: Enable TXEN bit in imx_poll_init(). As described in Documentation, poll_init() is called by kgdb to initialize hardware which supports both poll_put_char() and poll_get_char(). It's necessary to enable TXEN bit, otherwise, it will cause hardware fault and kernel panic when calling imx_poll_put_char(). Generally, if use /dev/ttymxc0 as kgdb console as well as system console, ttymxc0 is initialized early by system console which does enable TXEN bit.But when use /dev/ttymxc1 as kgbd console, ttymxc1 is only initialized by imx_poll_init() cannot enable the TXEN bit, which will cause kernel panic. Signed-off-by: Mingrui Ren <jiladahe1997@gmail.com> Link: https://lore.kernel.org/r/20201202072543.151-1-972931182@qq.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index b50f97cb07e9..cafa88df5a85 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1861,7 +1861,7 @@ static int imx_uart_poll_init(struct uart_port *port) ucr1 |= UCR1_UARTEN; ucr1 &= ~(UCR1_TRDYEN | UCR1_RTSDEN | UCR1_RRDYEN); - ucr2 |= UCR2_RXEN; + ucr2 |= UCR2_RXEN | UCR2_TXEN; ucr2 &= ~UCR2_ATEN; imx_uart_writel(sport, ucr1, UCR1); From e0efb3168d34dc8c8c72718672b8902e40efff8f Mon Sep 17 00:00:00 2001 From: Jann Horn <jannh@google.com> Date: Thu, 3 Dec 2020 03:03:31 +0100 Subject: [PATCH 78/89] tty: Remove dead termiox code set_termiox() and the TCGETX handler bail out with -EINVAL immediately if ->termiox is NULL, but there are no code paths that can set ->termiox to a non-NULL pointer; and no such code paths seem to have existed since the termiox mechanism was introduced back in commit 1d65b4a088de ("tty: Add termiox") in v2.6.28. Similarly, no driver actually implements .set_termiox; and it looks like no driver ever has. Delete this dead code; but leave the definition of struct termiox in the UAPI headers intact. Signed-off-by: Jann Horn <jannh@google.com> Link: https://lore.kernel.org/r/20201203020331.2394754-1-jannh@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/tty_ioctl.c | 61 ++------------------------------------ include/linux/tty.h | 1 - include/linux/tty_driver.h | 9 ------ 3 files changed, 2 insertions(+), 69 deletions(-) diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index e18f318586ab..4de1c6ddb8ff 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -443,51 +443,6 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio) return 0; } - -#ifdef TCGETX - -/** - * set_termiox - set termiox fields if possible - * @tty: terminal - * @arg: termiox structure from user - * @opt: option flags for ioctl type - * - * Implement the device calling points for the SYS5 termiox ioctl - * interface in Linux - */ - -static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) -{ - struct termiox tnew; - struct tty_ldisc *ld; - - if (tty->termiox == NULL) - return -EINVAL; - if (copy_from_user(&tnew, arg, sizeof(struct termiox))) - return -EFAULT; - - ld = tty_ldisc_ref(tty); - if (ld != NULL) { - if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); - tty_ldisc_deref(ld); - } - if (opt & TERMIOS_WAIT) { - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - down_write(&tty->termios_rwsem); - if (tty->ops->set_termiox) - tty->ops->set_termiox(tty, &tnew); - up_write(&tty->termios_rwsem); - return 0; -} - -#endif - - #ifdef TIOCGETP /* * These are deprecated, but there is limited support.. @@ -815,23 +770,11 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return ret; #endif #ifdef TCGETX - case TCGETX: { - struct termiox ktermx; - if (real_tty->termiox == NULL) - return -EINVAL; - down_read(&real_tty->termios_rwsem); - memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox)); - up_read(&real_tty->termios_rwsem); - if (copy_to_user(p, &ktermx, sizeof(struct termiox))) - ret = -EFAULT; - return ret; - } + case TCGETX: case TCSETX: - return set_termiox(real_tty, p, 0); case TCSETXW: - return set_termiox(real_tty, p, TERMIOS_WAIT); case TCSETXF: - return set_termiox(real_tty, p, TERMIOS_FLUSH); + return -EINVAL; #endif case TIOCGSOFTCAR: copy_termios(real_tty, &kterm); diff --git a/include/linux/tty.h b/include/linux/tty.h index 10212c6e4345..67c7a07c8083 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -303,7 +303,6 @@ struct tty_struct { spinlock_t flow_lock; /* Termios values are protected by the termios rwsem */ struct ktermios termios, termios_locked; - struct termiox *termiox; /* May be NULL for unsupported */ char name[64]; struct pid *pgrp; /* Protected by ctrl lock */ struct pid *session; diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 358446247ccd..61c3372d3f32 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -224,14 +224,6 @@ * line). See tty_do_resize() if you need to wrap the standard method * in your own logic - the usual case. * - * void (*set_termiox)(struct tty_struct *tty, struct termiox *new); - * - * Called when the device receives a termiox based ioctl. Passes down - * the requested data from user space. This method will not be invoked - * unless the tty also has a valid tty->termiox pointer. - * - * Optional: Called under the termios lock - * * int (*get_icount)(struct tty_struct *tty, struct serial_icounter *icount); * * Called when the device receives a TIOCGICOUNT ioctl. Passed a kernel @@ -285,7 +277,6 @@ struct tty_operations { int (*tiocmset)(struct tty_struct *tty, unsigned int set, unsigned int clear); int (*resize)(struct tty_struct *tty, struct winsize *ws); - int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); int (*get_icount)(struct tty_struct *tty, struct serial_icounter_struct *icount); int (*get_serial)(struct tty_struct *tty, struct serial_struct *p); From 76437b340b242fd21952f54ba8965d21a1ffa8c8 Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Mon, 7 Dec 2020 10:16:01 +0100 Subject: [PATCH 79/89] earlycon: drop semicolon from earlycon macro Drop the trailing semicolon from the OF_EARLYCON_DECLARE() macro definition which was left when removing the array-of-pointer indirection. Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://lore.kernel.org/r/20201207091601.5202-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- include/linux/serial_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 3e32b788c28d..e1b684e33841 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -372,7 +372,7 @@ extern const struct earlycon_id __earlycon_table_end[]; __aligned(__alignof__(struct earlycon_id)) \ = { .name = __stringify(_name), \ .compatible = compat, \ - .setup = fn }; + .setup = fn } #define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn) From af633212c4aac1dbd3a48615a834646ce072346d Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Wed, 2 Dec 2020 12:39:36 +0100 Subject: [PATCH 80/89] tty: use assign_bit() in port-flag accessors Use the new assign_bit() wrapper in the port-flag accessors instead of open coding. Suggested-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://lore.kernel.org/r/20201202113942.27024-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- include/linux/tty.h | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/include/linux/tty.h b/include/linux/tty.h index 0c2f97ba8018..9b8e7d5bf2fc 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -615,10 +615,7 @@ static inline bool tty_port_cts_enabled(struct tty_port *port) static inline void tty_port_set_cts_flow(struct tty_port *port, bool val) { - if (val) - set_bit(TTY_PORT_CTS_FLOW, &port->iflags); - else - clear_bit(TTY_PORT_CTS_FLOW, &port->iflags); + assign_bit(TTY_PORT_CTS_FLOW, &port->iflags, val); } static inline bool tty_port_active(struct tty_port *port) @@ -628,10 +625,7 @@ static inline bool tty_port_active(struct tty_port *port) static inline void tty_port_set_active(struct tty_port *port, bool val) { - if (val) - set_bit(TTY_PORT_ACTIVE, &port->iflags); - else - clear_bit(TTY_PORT_ACTIVE, &port->iflags); + assign_bit(TTY_PORT_ACTIVE, &port->iflags, val); } static inline bool tty_port_check_carrier(struct tty_port *port) @@ -641,10 +635,7 @@ static inline bool tty_port_check_carrier(struct tty_port *port) static inline void tty_port_set_check_carrier(struct tty_port *port, bool val) { - if (val) - set_bit(TTY_PORT_CHECK_CD, &port->iflags); - else - clear_bit(TTY_PORT_CHECK_CD, &port->iflags); + assign_bit(TTY_PORT_CHECK_CD, &port->iflags, val); } static inline bool tty_port_suspended(struct tty_port *port) @@ -654,10 +645,7 @@ static inline bool tty_port_suspended(struct tty_port *port) static inline void tty_port_set_suspended(struct tty_port *port, bool val) { - if (val) - set_bit(TTY_PORT_SUSPENDED, &port->iflags); - else - clear_bit(TTY_PORT_SUSPENDED, &port->iflags); + assign_bit(TTY_PORT_SUSPENDED, &port->iflags, val); } static inline bool tty_port_initialized(struct tty_port *port) @@ -667,10 +655,7 @@ static inline bool tty_port_initialized(struct tty_port *port) static inline void tty_port_set_initialized(struct tty_port *port, bool val) { - if (val) - set_bit(TTY_PORT_INITIALIZED, &port->iflags); - else - clear_bit(TTY_PORT_INITIALIZED, &port->iflags); + assign_bit(TTY_PORT_INITIALIZED, &port->iflags, val); } static inline bool tty_port_kopened(struct tty_port *port) @@ -680,10 +665,7 @@ static inline bool tty_port_kopened(struct tty_port *port) static inline void tty_port_set_kopened(struct tty_port *port, bool val) { - if (val) - set_bit(TTY_PORT_KOPENED, &port->iflags); - else - clear_bit(TTY_PORT_KOPENED, &port->iflags); + assign_bit(TTY_PORT_KOPENED, &port->iflags, val); } extern struct tty_struct *tty_port_tty_get(struct tty_port *port); From 9e1792727ead477f49958578d0dbd466a7deea48 Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Wed, 2 Dec 2020 12:39:37 +0100 Subject: [PATCH 81/89] tty: use const parameters in port-flag accessors Declare the port parameter to the flag-test accessors as const. This is currently mostly cosmetic as the accessors are already inlined. Suggested-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://lore.kernel.org/r/20201202113942.27024-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- include/linux/tty.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/tty.h b/include/linux/tty.h index 9b8e7d5bf2fc..c873f475f0a7 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -608,7 +608,7 @@ static inline struct tty_port *tty_port_get(struct tty_port *port) } /* If the cts flow control is enabled, return true. */ -static inline bool tty_port_cts_enabled(struct tty_port *port) +static inline bool tty_port_cts_enabled(const struct tty_port *port) { return test_bit(TTY_PORT_CTS_FLOW, &port->iflags); } @@ -618,7 +618,7 @@ static inline void tty_port_set_cts_flow(struct tty_port *port, bool val) assign_bit(TTY_PORT_CTS_FLOW, &port->iflags, val); } -static inline bool tty_port_active(struct tty_port *port) +static inline bool tty_port_active(const struct tty_port *port) { return test_bit(TTY_PORT_ACTIVE, &port->iflags); } @@ -628,7 +628,7 @@ static inline void tty_port_set_active(struct tty_port *port, bool val) assign_bit(TTY_PORT_ACTIVE, &port->iflags, val); } -static inline bool tty_port_check_carrier(struct tty_port *port) +static inline bool tty_port_check_carrier(const struct tty_port *port) { return test_bit(TTY_PORT_CHECK_CD, &port->iflags); } @@ -638,7 +638,7 @@ static inline void tty_port_set_check_carrier(struct tty_port *port, bool val) assign_bit(TTY_PORT_CHECK_CD, &port->iflags, val); } -static inline bool tty_port_suspended(struct tty_port *port) +static inline bool tty_port_suspended(const struct tty_port *port) { return test_bit(TTY_PORT_SUSPENDED, &port->iflags); } @@ -648,7 +648,7 @@ static inline void tty_port_set_suspended(struct tty_port *port, bool val) assign_bit(TTY_PORT_SUSPENDED, &port->iflags, val); } -static inline bool tty_port_initialized(struct tty_port *port) +static inline bool tty_port_initialized(const struct tty_port *port) { return test_bit(TTY_PORT_INITIALIZED, &port->iflags); } @@ -658,7 +658,7 @@ static inline void tty_port_set_initialized(struct tty_port *port, bool val) assign_bit(TTY_PORT_INITIALIZED, &port->iflags, val); } -static inline bool tty_port_kopened(struct tty_port *port) +static inline bool tty_port_kopened(const struct tty_port *port) { return test_bit(TTY_PORT_KOPENED, &port->iflags); } From 9ea12edeb9ff6b485bd7ca4aaed541c7a7289046 Mon Sep 17 00:00:00 2001 From: Yash Shah <yash.shah@sifive.com> Date: Tue, 8 Dec 2020 10:25:36 +0530 Subject: [PATCH 82/89] dt-bindings: serial: Update DT binding docs to support SiFive FU740 SoC Add new compatible strings to the DT binding documents to support SiFive FU740-C000. Signed-off-by: Yash Shah <yash.shah@sifive.com> Link: https://lore.kernel.org/r/1607403341-57214-5-git-send-email-yash.shah@sifive.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- Documentation/devicetree/bindings/serial/sifive-serial.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/sifive-serial.yaml b/Documentation/devicetree/bindings/serial/sifive-serial.yaml index 92283f693de0..3ac5c7ff2758 100644 --- a/Documentation/devicetree/bindings/serial/sifive-serial.yaml +++ b/Documentation/devicetree/bindings/serial/sifive-serial.yaml @@ -17,7 +17,9 @@ allOf: properties: compatible: items: - - const: sifive,fu540-c000-uart + - enum: + - sifive,fu540-c000-uart + - sifive,fu740-c000-uart - const: sifive,uart0 description: From 2f70e49ed860020f5abae4f7015018ebc10e1f0e Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy <aik@ozlabs.ru> Date: Thu, 3 Dec 2020 16:58:34 +1100 Subject: [PATCH 83/89] serial_core: Check for port state when tty is in error state At the moment opening a serial device node (such as /dev/ttyS3) succeeds even if there is no actual serial device behind it. Reading/writing/ioctls fail as expected because the uart port is not initialized (the type is PORT_UNKNOWN) and the TTY_IO_ERROR error state bit is set fot the tty. However setting line discipline does not have these checks 8250_port.c (8250 is the default choice made by univ8250_console_init()). As the result of PORT_UNKNOWN, uart_port::iobase is NULL which a platform translates onto some address accessing which produces a crash like below. This adds tty_port_initialized() to uart_set_ldisc() to prevent the crash. Found by syzkaller. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Link: https://lore.kernel.org/r/20201203055834.45838-1-aik@ozlabs.ru Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/serial_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f41cba10b86b..828f9ad1be49 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1467,6 +1467,10 @@ static void uart_set_ldisc(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *uport; + struct tty_port *port = &state->port; + + if (!tty_port_initialized(port)) + return; mutex_lock(&state->port.mutex); uport = uart_port_check(state); From fa26b3263fd5f58a7f0cd7b3c6cea75ce714f87b Mon Sep 17 00:00:00 2001 From: "Yan.Gao" <gao.yanB@h3c.com> Date: Wed, 9 Dec 2020 11:05:51 +0800 Subject: [PATCH 84/89] tty: Fix whitespace inconsistencies in vt_io_ioctl Replaces spaces with tabs for indentation. Signed-off-by: Yan.Gao <gao.yanB@h3c.com> Link: https://lore.kernel.org/r/20201209030551.48029-1-gao.yanB@h3c.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/vt/vt_ioctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 5f61b25a9aaa..3813c40f1b48 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -596,12 +596,12 @@ static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up, return con_font_op(vc, &op); case PIO_CMAP: - if (!perm) + if (!perm) return -EPERM; return con_set_cmap(up); case GIO_CMAP: - return con_get_cmap(up); + return con_get_cmap(up); case PIO_FONTX: if (!perm) From 603012f78a3f5cb2e7f529b8e318321117a9cf7c Mon Sep 17 00:00:00 2001 From: Fabio Estevam <festevam@gmail.com> Date: Thu, 26 Nov 2020 09:46:43 -0300 Subject: [PATCH 85/89] serial: imx: Remove unneeded of_device_get_match_data() NULL check Since 5.10-rc1 i.MX is a devicetree-only platform and the NULL check on of_device_get_match_data() is no longer needed. This check was only needed when this driver supported both DT and non-DT platforms. Remove the unneeded of_device_get_match_data() NULL check. Signed-off-by: Fabio Estevam <festevam@gmail.com> Link: https://lore.kernel.org/r/20201126124643.3371-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/imx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index cafa88df5a85..2452e57a5663 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2174,9 +2174,6 @@ static int imx_uart_probe_dt(struct imx_port *sport, int ret; sport->devdata = of_device_get_match_data(&pdev->dev); - if (!sport->devdata) - /* no device tree device */ - return 1; ret = of_alias_get_id(np, "serial"); if (ret < 0) { From 4661f46e50f2d658592f665be1f1f999ff647d3c Mon Sep 17 00:00:00 2001 From: Fabio Estevam <festevam@gmail.com> Date: Wed, 9 Dec 2020 18:47:12 -0300 Subject: [PATCH 86/89] serial: imx: Move imx_uart_probe_dt() content into probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the driver only probes via devicetree, we can move the content of imx_uart_probe_dt() directly into imx_uart_probe() to make the code simpler. Suggested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Fabio Estevam <festevam@gmail.com> Link: https://lore.kernel.org/r/20201209214712.15247-1-festevam@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/imx.c | 64 +++++++++++++++------------------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 2452e57a5663..425624d794dd 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2163,44 +2163,6 @@ static struct uart_driver imx_uart_uart_driver = { .cons = IMX_CONSOLE, }; -/* - * This function returns 0 iff it could successfully get all information - * from dt or a negative errno. - */ -static int imx_uart_probe_dt(struct imx_port *sport, - struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - int ret; - - sport->devdata = of_device_get_match_data(&pdev->dev); - - ret = of_alias_get_id(np, "serial"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); - return ret; - } - sport->port.line = ret; - - if (of_get_property(np, "uart-has-rtscts", NULL) || - of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */) - sport->have_rtscts = 1; - - if (of_get_property(np, "fsl,dte-mode", NULL)) - sport->dte_mode = 1; - - if (of_get_property(np, "rts-gpios", NULL)) - sport->have_rtsgpio = 1; - - if (of_get_property(np, "fsl,inverted-tx", NULL)) - sport->inverted_tx = 1; - - if (of_get_property(np, "fsl,inverted-rx", NULL)) - sport->inverted_rx = 1; - - return 0; -} - static enum hrtimer_restart imx_trigger_start_tx(struct hrtimer *t) { struct imx_port *sport = container_of(t, struct imx_port, trigger_start_tx); @@ -2229,6 +2191,7 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t) static int imx_uart_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct imx_port *sport; void __iomem *base; int ret = 0; @@ -2240,9 +2203,30 @@ static int imx_uart_probe(struct platform_device *pdev) if (!sport) return -ENOMEM; - ret = imx_uart_probe_dt(sport, pdev); - if (ret < 0) + sport->devdata = of_device_get_match_data(&pdev->dev); + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); return ret; + } + sport->port.line = ret; + + if (of_get_property(np, "uart-has-rtscts", NULL) || + of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */) + sport->have_rtscts = 1; + + if (of_get_property(np, "fsl,dte-mode", NULL)) + sport->dte_mode = 1; + + if (of_get_property(np, "rts-gpios", NULL)) + sport->have_rtsgpio = 1; + + if (of_get_property(np, "fsl,inverted-tx", NULL)) + sport->inverted_tx = 1; + + if (of_get_property(np, "fsl,inverted-rx", NULL)) + sport->inverted_rx = 1; if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) { dev_err(&pdev->dev, "serial%d out of range\n", From d96f04d347e4011977abdbb4da5d8f303ebd26f8 Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin <alexander.sverdlin@gmail.com> Date: Thu, 10 Dec 2020 06:52:57 +0100 Subject: [PATCH 87/89] serial: 8250_omap: Avoid FIFO corruption caused by MDR1 access It has been observed that once per 300-1300 port openings the first transmitted byte is being corrupted on AM3352 ("v" written to FIFO appeared as "e" on the wire). It only happened if single byte has been transmitted right after port open, which means, DMA is not used for this transfer and the corruption never happened afterwards. Therefore I've carefully re-read the MDR1 errata (link below), which says "when accessing the MDR1 registers that causes a dummy under-run condition that will freeze the UART in IrDA transmission. In UART mode, this may corrupt the transferred data". Strictly speaking, omap_8250_mdr1_errataset() performs a read access and if the value is the same as should be written, exits without errata-recommended FIFO reset. A brief check of the serial_omap_mdr1_errataset() from the competing omap-serial driver showed it has no read access of MDR1. After removing the read access from omap_8250_mdr1_errataset() the data corruption never happened any more. Link: https://www.ti.com/lit/er/sprz360i/sprz360i.pdf Fixes: 61929cf0169d ("tty: serial: Add 8250-core based omap driver") Cc: stable@vger.kernel.org Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com> Link: https://lore.kernel.org/r/20201210055257.1053028-1-alexander.sverdlin@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/8250/8250_omap.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 0ab6517d389a..23e0decde33e 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -190,11 +190,6 @@ static void omap_8250_mdr1_errataset(struct uart_8250_port *up, struct omap8250_priv *priv) { u8 timeout = 255; - u8 old_mdr1; - - old_mdr1 = serial_in(up, UART_OMAP_MDR1); - if (old_mdr1 == priv->mdr1) - return; serial_out(up, UART_OMAP_MDR1, priv->mdr1); udelay(2); From 87a0b9f98ac5a14aae5b0fbcff930a240b24f827 Mon Sep 17 00:00:00 2001 From: Kevin Hilman <khilman@baylibre.com> Date: Thu, 10 Dec 2020 16:57:44 -0800 Subject: [PATCH 88/89] tty: serial: meson: enable console as module Enable serial driver to be built as a module. To do so, init the console support on driver/module load instead of using console_initcall(). Signed-off-by: Kevin Hilman <khilman@baylibre.com> Link: https://lore.kernel.org/r/20201211005744.12855-1-khilman@baylibre.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/Kconfig | 2 +- drivers/tty/serial/meson_uart.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 2d73b823e91c..12d71d5eb6ca 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -206,7 +206,7 @@ config SERIAL_MESON config SERIAL_MESON_CONSOLE bool "Support for console on meson" - depends on SERIAL_MESON=y + depends on SERIAL_MESON select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index d2c08b760f83..69eeef9edfa5 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -604,7 +604,6 @@ static int __init meson_serial_console_init(void) register_console(&meson_serial_console); return 0; } -console_initcall(meson_serial_console_init); static void meson_serial_early_console_write(struct console *co, const char *s, @@ -634,6 +633,9 @@ OF_EARLYCON_DECLARE(meson, "amlogic,meson-ao-uart", #define MESON_SERIAL_CONSOLE (&meson_serial_console) #else +static int __init meson_serial_console_init(void) { + return 0; +} #define MESON_SERIAL_CONSOLE NULL #endif @@ -824,6 +826,10 @@ static int __init meson_uart_init(void) { int ret; + ret = meson_serial_console_init(); + if (ret) + return ret; + ret = uart_register_driver(&meson_uart_driver); if (ret) return ret; From c3ae3dc896fab5524f9b20f547e72e4b892d8d8e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven <geert+renesas@glider.be> Date: Fri, 11 Dec 2020 14:39:07 +0100 Subject: [PATCH 89/89] serial: 8250_pci: Drop bogus __refdata annotation Since commit d73dfc6a4199e0e3 ("serial: 8250_pci: remove __devexit usage") in v3.9, the 8250/16550 PCI serial driver no longer has any code or data located in initmem, hence there is no need to annotate the pci_serial_quirks structure with __refdata. Drop the annotation, to avoid suppressing future section warnings. Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Link: https://lore.kernel.org/r/20201211133907.2970460-1-geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- drivers/tty/serial/8250/8250_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index d5a513efb261..689d8227f95f 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1964,7 +1964,7 @@ pci_moxa_setup(struct serial_private *priv, * This list is ordered alphabetically by vendor then device. * Specific entries must come before more generic entries. */ -static struct pci_serial_quirk pci_serial_quirks[] __refdata = { +static struct pci_serial_quirk pci_serial_quirks[] = { /* * ADDI-DATA GmbH communication cards <info@addi-data.com> */