From 4dec5f1af694526db760dfbb47211236e556e27c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Feb 2021 15:59:00 +0100 Subject: tty: serial: pch_uart.c: remove debugfs dentry pointer No need to keep around the dentry pointer for the debugfs file if all it is used for is to remove it when we are wanting to clean up, as the pointer can be looked up directly from debugfs instead. This also removes pointless #ifdef CONFIG_DEBUG_FS brackets as the compiler is smart enough to handle this properly if debugfs is disabled without us having to worry about it. Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Link: https://lore.kernel.org/r/20210216145900.3835160-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index a7363bc66c11..e9e79d181f0e 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -236,7 +236,6 @@ struct eg20t_port { void *rx_buf_virt; dma_addr_t rx_buf_dma; - struct dentry *debugfs; #define IRQ_NAME_SIZE 17 char irq_name[IRQ_NAME_SIZE]; @@ -1735,9 +1734,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, int fifosize; int port_type; struct pch_uart_driver_data *board; -#ifdef CONFIG_DEBUG_FS - char name[32]; /* for debugfs file name */ -#endif + char name[32]; board = &drv_dat[id->driver_data]; port_type = board->port_type; @@ -1813,11 +1810,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, if (ret < 0) goto init_port_hal_free; -#ifdef CONFIG_DEBUG_FS - snprintf(name, sizeof(name), "uart%d_regs", board->line_no); - priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO, - NULL, priv, &port_regs_ops); -#endif + snprintf(name, sizeof(name), "uart%d_regs", priv->port.line); + debugfs_create_file(name, S_IFREG | S_IRUGO, NULL, priv, + &port_regs_ops); return priv; @@ -1835,10 +1830,10 @@ init_port_alloc_err: static void pch_uart_exit_port(struct eg20t_port *priv) { + char name[32]; -#ifdef CONFIG_DEBUG_FS - debugfs_remove(priv->debugfs); -#endif + snprintf(name, sizeof(name), "uart%d_regs", priv->port.line); + debugfs_remove(debugfs_lookup(name, NULL)); uart_remove_one_port(&pch_uart_driver, &priv->port); free_page((unsigned long)priv->rxbuf.buf); } -- cgit From 078b23267d5f08f827fbaf9f2247226520c00dc1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:31 +0100 Subject: MAINTAINERS: orphan mxser I cannot maintain this driver for years due to missing HW. Let's orphan the entry in MAINTAINERS. And likely drop the driver later as these devices are likely gone from this world. Mxser provides different (out-of-tree) drivers for their current devices. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index d92f85ca831d..306febaae6cd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12088,8 +12088,7 @@ F: drivers/media/pci/meye/ F: include/uapi/linux/meye.h MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD -M: Jiri Slaby -S: Maintained +S: Orphan F: Documentation/driver-api/serial/moxa-smartio.rst F: drivers/tty/mxser.* -- cgit From ae6acf479be131fcd8523f655b416b7be66b68b2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:32 +0100 Subject: MAINTAINERS: drop cyclades.com reference cyclades.com is a dead domain. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 306febaae6cd..363530db37ac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4885,7 +4885,6 @@ F: include/uapi/linux/cyclades.h CYCLADES PC300 DRIVER S: Orphan -W: http://www.cyclades.com/ F: drivers/net/wan/pc300* CYPRESS_FIRMWARE MEDIA DRIVER -- cgit From 00025161b2d931f97d72418114abf73bfb51ae4c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:33 +0100 Subject: PCI: remove synclink entries from pci_ids The drivers were removed in a1f714b44e34 (tty: Remove redundant synclink driver) and 3d608a591b2b (tty: Remove redundant synclinkmp driver). So remove also the PCI ID entries. Cc: Bjorn Helgaas Cc: linux-pci@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-3-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- include/linux/pci_ids.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index a76ccb697bef..8a18517696c1 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2065,8 +2065,6 @@ #define PCI_DEVICE_ID_EXAR_XR17V358 0x0358 #define PCI_VENDOR_ID_MICROGATE 0x13c0 -#define PCI_DEVICE_ID_MICROGATE_USC 0x0010 -#define PCI_DEVICE_ID_MICROGATE_SCA 0x0030 #define PCI_VENDOR_ID_3WARE 0x13C1 #define PCI_DEVICE_ID_3WARE_1000 0x1000 -- cgit From 5a3c96e964097d5a16b360e69bdd93ba6e26d7cd Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:34 +0100 Subject: vgacon: comment on vga_rolled_over Long time ago, I figured out what this number is good for and documented that locally. But never submitted, so do it now. Cc: dri-devel@lists.freedesktop.org Cc: linux-fbdev@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-4-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/vgacon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 962c12be9774..0d26e821e73b 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -96,7 +96,7 @@ static bool vga_is_gfx; static bool vga_512_chars; static int vga_video_font_height; static int vga_scan_lines __read_mostly; -static unsigned int vga_rolled_over; +static unsigned int vga_rolled_over; /* last vc_origin offset before wrap */ static bool vgacon_text_mode_force; static bool vga_hardscroll_enabled; -- cgit From f76edd8f7ce06cdff2fe5b6b39a49644c684a161 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:35 +0100 Subject: tty: cyclades, remove this orphan The Cyclades driver was orphaned by commit d459883e6c54 (MAINTAINERS: remove two dead e-mail) 13 years ago. Noone stepped up to take care of them and to fix all the issues the driver has. On the top of that, there is no way to obtain the firmware for Z cards from the vendor as cyclades.com ceased to exist. So it's time to drop the driver with all its traces. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/devices.txt | 10 - Documentation/driver-api/serial/cyclades_z.rst | 11 - Documentation/driver-api/serial/index.rst | 1 - Documentation/process/magic-number.rst | 1 - .../translations/it_IT/process/magic-number.rst | 1 - .../translations/zh_CN/process/magic-number.rst | 1 - Documentation/userspace-api/ioctl/ioctl-number.rst | 1 - MAINTAINERS | 7 - arch/powerpc/configs/ppc6xx_defconfig | 1 - drivers/tty/Kconfig | 31 +- drivers/tty/Makefile | 1 - drivers/tty/cyclades.c | 4119 -------------------- drivers/tty/serial/8250/Kconfig | 5 +- include/linux/cyclades.h | 364 -- include/linux/pci_ids.h | 8 - include/uapi/linux/cyclades.h | 494 --- include/uapi/linux/major.h | 2 - include/uapi/linux/serial.h | 4 +- 18 files changed, 5 insertions(+), 5057 deletions(-) delete mode 100644 Documentation/driver-api/serial/cyclades_z.rst delete mode 100644 drivers/tty/cyclades.c delete mode 100644 include/linux/cyclades.h delete mode 100644 include/uapi/linux/cyclades.h diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt index 63fd4e6a014b..b5bd9d46e031 100644 --- a/Documentation/admin-guide/devices.txt +++ b/Documentation/admin-guide/devices.txt @@ -477,11 +477,6 @@ 18 block Sanyo CD-ROM 0 = /dev/sjcd Sanyo CD-ROM - 19 char Cyclades serial card - 0 = /dev/ttyC0 First Cyclades port - ... - 31 = /dev/ttyC31 32nd Cyclades port - 19 block "Double" compressed disk 0 = /dev/double0 First compressed disk ... @@ -493,11 +488,6 @@ See the Double documentation for the meaning of the mirror devices. - 20 char Cyclades serial card - alternate devices - 0 = /dev/cub0 Callout device for ttyC0 - ... - 31 = /dev/cub31 Callout device for ttyC31 - 20 block Hitachi CD-ROM (under development) 0 = /dev/hitcd Hitachi CD-ROM diff --git a/Documentation/driver-api/serial/cyclades_z.rst b/Documentation/driver-api/serial/cyclades_z.rst deleted file mode 100644 index 532ff67e2f1c..000000000000 --- a/Documentation/driver-api/serial/cyclades_z.rst +++ /dev/null @@ -1,11 +0,0 @@ -================ -Cyclades-Z notes -================ - -The Cyclades-Z must have firmware loaded onto the card before it will -operate. This operation should be performed during system startup, - -The firmware, loader program and the latest device driver code are -available from Cyclades at - - ftp://ftp.cyclades.com/pub/cyclades/cyclades-z/linux/ diff --git a/Documentation/driver-api/serial/index.rst b/Documentation/driver-api/serial/index.rst index 33ad10d05b26..21351b8c95a4 100644 --- a/Documentation/driver-api/serial/index.rst +++ b/Documentation/driver-api/serial/index.rst @@ -17,7 +17,6 @@ Serial drivers .. toctree:: :maxdepth: 1 - cyclades_z moxa-smartio n_gsm rocket diff --git a/Documentation/process/magic-number.rst b/Documentation/process/magic-number.rst index fa5a62f4150c..d4a30c09bd03 100644 --- a/Documentation/process/magic-number.rst +++ b/Documentation/process/magic-number.rst @@ -73,7 +73,6 @@ CMAGIC 0x0111 user ``include/linux/ MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -CYCLADES_MAGIC 0x4359 cyclades_port ``include/linux/cyclades.h`` DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst index 1af30f4228f2..0df2e7e32cd8 100644 --- a/Documentation/translations/it_IT/process/magic-number.rst +++ b/Documentation/translations/it_IT/process/magic-number.rst @@ -79,7 +79,6 @@ CMAGIC 0x0111 user ``include/linux/ MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -CYCLADES_MAGIC 0x4359 cyclades_port ``include/linux/cyclades.h`` DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 7bb9d4165ed3..82d62f6a4406 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -62,7 +62,6 @@ CMAGIC 0x0111 user ``include/linux/ MKISS_DRIVER_MAGIC 0x04bf mkiss_channel ``drivers/net/mkiss.h`` HDLC_MAGIC 0x239e n_hdlc ``drivers/char/n_hdlc.c`` APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c`` -CYCLADES_MAGIC 0x4359 cyclades_port ``include/linux/cyclades.h`` DB_MAGIC 0x4442 fc_info ``drivers/net/iph5526_novram.c`` DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 599bd4493944..0a7b408c0ec7 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -209,7 +209,6 @@ Code Seq# Include File Comments linux/fs.h, 'X' all fs/ocfs2/ocfs_fs.h conflict! 'X' 01 linux/pktcdvd.h conflict! -'Y' all linux/cyclades.h 'Z' 14-15 drivers/message/fusion/mptctl.h '[' 00-3F linux/usb/tmc.h USB Test and Measurement Devices diff --git a/MAINTAINERS b/MAINTAINERS index 363530db37ac..29f20a97d73d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4876,13 +4876,6 @@ S: Maintained W: http://www.armlinux.org.uk/ F: drivers/video/fbdev/cyber2000fb.* -CYCLADES ASYNC MUX DRIVER -S: Orphan -W: http://www.cyclades.com/ -F: drivers/tty/cyclades.c -F: include/linux/cyclades.h -F: include/uapi/linux/cyclades.h - CYCLADES PC300 DRIVER S: Orphan F: drivers/net/wan/pc300* diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 6677ac0da45a..1fd9d1260f9e 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -595,7 +595,6 @@ CONFIG_GAMEPORT_FM801=m # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_NONSTANDARD=y CONFIG_ROCKETPORT=m -CONFIG_CYCLADES=m CONFIG_SYNCLINK_GT=m CONFIG_NOZOMI=m CONFIG_N_HDLC=m diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index e15cd6b5bb99..397523a8095e 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -181,7 +181,7 @@ config SERIAL_NONSTANDARD help Say Y here if you have any non-standard serial boards -- boards which aren't supported using the standard "dumb" serial driver. - This includes intelligent serial boards such as Cyclades, + This includes intelligent serial boards such as Digiboards, etc. These are usually used for systems that need many serial ports because they serve many terminals or dial-in connections. @@ -207,35 +207,6 @@ config ROCKETPORT If you want to compile this driver into the kernel, say Y here. If you don't have a Comtrol RocketPort/RocketModem card installed, say N. -config CYCLADES - tristate "Cyclades async mux support" - depends on SERIAL_NONSTANDARD && (PCI || ISA) - select FW_LOADER - help - This driver supports Cyclades Z and Y multiserial boards. - You would need something like this to connect more than two modems to - your Linux box, for instance in order to become a dial-in server. - - For information about the Cyclades-Z card, read - . - - To compile this driver as a module, choose M here: the - module will be called cyclades. - - If you haven't heard about it, it's safe to say N. - -config CYZ_INTR - bool "Cyclades-Z interrupt mode operation" - depends on CYCLADES && PCI - help - The Cyclades-Z family of multiport cards allows 2 (two) driver op - modes: polling and interrupt. In polling mode, the driver will check - the status of the Cyclades-Z ports every certain amount of time - (which is called polling cycle and is configurable). In interrupt - mode, it will use an interrupt line (IRQ) in order to check the - status of the Cyclades-Z ports. The default op mode is polling. If - unsure, say N. - config MOXA_INTELLIO tristate "Moxa Intellio support" depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 730de6bf048b..94eb2bf75763 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_SERIAL_DEV_BUS) += serdev/ # tty drivers obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o -obj-$(CONFIG_CYCLADES) += cyclades.o obj-$(CONFIG_ISI) += isicom.o obj-$(CONFIG_MOXA_INTELLIO) += moxa.o obj-$(CONFIG_MOXA_SMARTIO) += mxser.o diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c deleted file mode 100644 index 097266342e5e..000000000000 --- a/drivers/tty/cyclades.c +++ /dev/null @@ -1,4119 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#undef BLOCKMOVE -#define Z_WAKE -#undef Z_EXT_CHARS_IN_BUFFER - -/* - * This file contains the driver for the Cyclades async multiport - * serial boards. - * - * Initially written by Randolph Bentson . - * Modified and maintained by Marcio Saito . - * - * Copyright (C) 2007-2009 Jiri Slaby - * - * Much of the design and some of the code came from serial.c - * which was copyright (C) 1991, 1992 Linus Torvalds. It was - * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92, - * and then fixed as suggested by Michael K. Johnson 12/12/92. - * Converted to pci probing and cleaned up by Jiri Slaby. - * - */ - -#define CY_VERSION "2.6" - -/* If you need to install more boards than NR_CARDS, change the constant - in the definition below. No other change is necessary to support up to - eight boards. Beyond that you'll have to extend cy_isa_addresses. */ - -#define NR_CARDS 4 - -/* - If the total number of ports is larger than NR_PORTS, change this - constant in the definition below. No other change is necessary to - support more boards/ports. */ - -#define NR_PORTS 256 - -#define ZO_V1 0 -#define ZO_V2 1 -#define ZE_V1 2 - -#define SERIAL_PARANOIA_CHECK -#undef CY_DEBUG_OPEN -#undef CY_DEBUG_THROTTLE -#undef CY_DEBUG_OTHER -#undef CY_DEBUG_IO -#undef CY_DEBUG_COUNT -#undef CY_DEBUG_DTR -#undef CY_DEBUG_INTERRUPTS -#undef CY_16Y_HACK -#undef CY_ENABLE_MONITORING -#undef CY_PCI_DEBUG - -/* - * Include section - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include - -static void cy_send_xchar(struct tty_struct *tty, char ch); - -#ifndef SERIAL_XMIT_SIZE -#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096)) -#endif - -/* firmware stuff */ -#define ZL_MAX_BLOCKS 16 -#define DRIVER_VERSION 0x02010203 -#define RAM_SIZE 0x80000 - -enum zblock_type { - ZBLOCK_PRG = 0, - ZBLOCK_FPGA = 1 -}; - -struct zfile_header { - char name[64]; - char date[32]; - char aux[32]; - u32 n_config; - u32 config_offset; - u32 n_blocks; - u32 block_offset; - u32 reserved[9]; -} __attribute__ ((packed)); - -struct zfile_config { - char name[64]; - u32 mailbox; - u32 function; - u32 n_blocks; - u32 block_list[ZL_MAX_BLOCKS]; -} __attribute__ ((packed)); - -struct zfile_block { - u32 type; - u32 file_offset; - u32 ram_offset; - u32 size; -} __attribute__ ((packed)); - -static struct tty_driver *cy_serial_driver; - -#ifdef CONFIG_ISA -/* This is the address lookup table. The driver will probe for - Cyclom-Y/ISA boards at all addresses in here. If you want the - driver to probe addresses at a different address, add it to - this table. If the driver is probing some other board and - causing problems, remove the offending address from this table. -*/ - -static unsigned int cy_isa_addresses[] = { - 0xD0000, - 0xD2000, - 0xD4000, - 0xD6000, - 0xD8000, - 0xDA000, - 0xDC000, - 0xDE000, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses) - -static long maddr[NR_CARDS]; -static int irq[NR_CARDS]; - -module_param_hw_array(maddr, long, iomem, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); - -#endif /* CONFIG_ISA */ - -/* This is the per-card data structure containing address, irq, number of - channels, etc. This driver supports a maximum of NR_CARDS cards. -*/ -static struct cyclades_card cy_card[NR_CARDS]; - -static int cy_next_channel; /* next minor available */ - -/* - * This is used to look up the divisor speeds and the timeouts - * We're normally limited to 15 distinct baud rates. The extra - * are accessed via settings in info->port.flags. - * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - * HI VHI - * 20 - */ -static const int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, - 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000, - 230400, 0 -}; - -static const char baud_co_25[] = { /* 25 MHz clock option table */ - /* value => 00 01 02 03 04 */ - /* divide by 8 32 128 512 2048 */ - 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, - 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */ - 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, - 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15 -}; - -static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */ - /* value => 00 01 02 03 04 */ - /* divide by 8 32 128 512 2048 */ - 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, - 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00 -}; - -static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */ - 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62, - 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32, - 0x21 -}; - -static const char baud_cor3[] = { /* receive threshold */ - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07, - 0x07 -}; - -/* - * The Cyclades driver implements HW flow control as any serial driver. - * The cyclades_port structure member rflow and the vector rflow_thr - * allows us to take advantage of a special feature in the CD1400 to avoid - * data loss even when the system interrupt latency is too high. These flags - * are to be used only with very special applications. Setting these flags - * requires the use of a special cable (DTR and RTS reversed). In the new - * CD1400-based boards (rev. 6.00 or later), there is no need for special - * cables. - */ - -static const char rflow_thr[] = { /* rflow threshold */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a -}; - -/* The Cyclom-Ye has placed the sequential chips in non-sequential - * address order. This look-up table overcomes that problem. - */ -static const unsigned int cy_chip_offset[] = { 0x0000, - 0x0400, - 0x0800, - 0x0C00, - 0x0200, - 0x0600, - 0x0A00, - 0x0E00 -}; - -/* PCI related definitions */ - -#ifdef CONFIG_PCI -static const struct pci_device_id cy_pci_dev_id[] = { - /* PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, - /* PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, - /* 4Y PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, - /* 4Y PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, - /* 8Y PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, - /* 8Y PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, - /* Z PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, - /* Z PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, - { } /* end of table */ -}; -MODULE_DEVICE_TABLE(pci, cy_pci_dev_id); -#endif - -static void cy_start(struct tty_struct *); -static void cy_set_line_char(struct cyclades_port *, struct tty_struct *); -static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32); -#ifdef CONFIG_ISA -static unsigned detect_isa_irq(void __iomem *); -#endif /* CONFIG_ISA */ - -#ifndef CONFIG_CYZ_INTR -static void cyz_poll(struct timer_list *); - -/* The Cyclades-Z polling cycle is defined by this variable */ -static long cyz_polling_cycle = CZ_DEF_POLL; - -static DEFINE_TIMER(cyz_timerlist, cyz_poll); - -#else /* CONFIG_CYZ_INTR */ -static void cyz_rx_restart(struct timer_list *); -#endif /* CONFIG_CYZ_INTR */ - -static void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val) -{ - struct cyclades_card *card = port->card; - - cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val); -} - -static u8 cyy_readb(struct cyclades_port *port, u32 reg) -{ - struct cyclades_card *card = port->card; - - return readb(port->u.cyy.base_addr + (reg << card->bus_index)); -} - -static inline bool cy_is_Z(struct cyclades_card *card) -{ - return card->num_chips == (unsigned int)-1; -} - -static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr) -{ - return readl(&ctl_addr->init_ctrl) & (1 << 17); -} - -static inline bool cyz_fpga_loaded(struct cyclades_card *card) -{ - return __cyz_fpga_loaded(card->ctl_addr.p9060); -} - -static bool cyz_is_loaded(struct cyclades_card *card) -{ - struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS; - - return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) && - readl(&fw_id->signature) == ZFIRM_ID; -} - -static int serial_paranoia_check(struct cyclades_port *info, - const char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - if (!info) { - printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) " - "in %s\n", name, routine); - return 1; - } - - if (info->magic != CYCLADES_MAGIC) { - printk(KERN_WARNING "cyc Warning: bad magic number for serial " - "struct (%s) in %s\n", name, routine); - return 1; - } -#endif - return 0; -} - -/***********************************************************/ -/********* Start of block of Cyclom-Y specific code ********/ - -/* This routine waits up to 1000 micro-seconds for the previous - command to the Cirrus chip to complete and then issues the - new command. An error is returned if the previous command - didn't finish within the time limit. - - This function is only called from inside spinlock-protected code. - */ -static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index) -{ - void __iomem *ccr = base_addr + (CyCCR << index); - unsigned int i; - - /* Check to see that the previous command has completed */ - for (i = 0; i < 100; i++) { - if (readb(ccr) == 0) - break; - udelay(10L); - } - /* if the CCR never cleared, the previous command - didn't finish within the "reasonable time" */ - if (i == 100) - return -1; - - /* Issue the new command */ - cy_writeb(ccr, cmd); - - return 0; -} - -static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd) -{ - return __cyy_issue_cmd(port->u.cyy.base_addr, cmd, - port->card->bus_index); -} - -#ifdef CONFIG_ISA -/* ISA interrupt detection code */ -static unsigned detect_isa_irq(void __iomem *address) -{ - int irq; - unsigned long irqs, flags; - int save_xir, save_car; - int index = 0; /* IRQ probing is only for ISA */ - - /* forget possible initially masked and pending IRQ */ - irq = probe_irq_off(probe_irq_on()); - - /* Clear interrupts on the board first */ - cy_writeb(address + (Cy_ClrIntr << index), 0); - /* Cy_ClrIntr is 0x1800 */ - - irqs = probe_irq_on(); - /* Wait ... */ - msleep(5); - - /* Enable the Tx interrupts on the CD1400 */ - local_irq_save(flags); - cy_writeb(address + (CyCAR << index), 0); - __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index); - - cy_writeb(address + (CyCAR << index), 0); - cy_writeb(address + (CySRER << index), - readb(address + (CySRER << index)) | CyTxRdy); - local_irq_restore(flags); - - /* Wait ... */ - msleep(5); - - /* Check which interrupt is in use */ - irq = probe_irq_off(irqs); - - /* Clean up */ - save_xir = (u_char) readb(address + (CyTIR << index)); - save_car = readb(address + (CyCAR << index)); - cy_writeb(address + (CyCAR << index), (save_xir & 0x3)); - cy_writeb(address + (CySRER << index), - readb(address + (CySRER << index)) & ~CyTxRdy); - cy_writeb(address + (CyTIR << index), (save_xir & 0x3f)); - cy_writeb(address + (CyCAR << index), (save_car)); - cy_writeb(address + (Cy_ClrIntr << index), 0); - /* Cy_ClrIntr is 0x1800 */ - - return (irq > 0) ? irq : 0; -} -#endif /* CONFIG_ISA */ - -static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, - void __iomem *base_addr) -{ - struct cyclades_port *info; - struct tty_port *port; - int len, index = cinfo->bus_index; - u8 ivr, save_xir, channel, save_car, data, char_count; - -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip); -#endif - /* determine the channel & change to that context */ - save_xir = readb(base_addr + (CyRIR << index)); - channel = save_xir & CyIRChannel; - info = &cinfo->ports[channel + chip * 4]; - port = &info->port; - save_car = cyy_readb(info, CyCAR); - cyy_writeb(info, CyCAR, save_xir); - ivr = cyy_readb(info, CyRIVR) & CyIVRMask; - - /* there is an open port for this data */ - if (ivr == CyIVRRxEx) { /* exception */ - data = cyy_readb(info, CyRDSR); - - /* For statistics only */ - if (data & CyBREAK) - info->icount.brk++; - else if (data & CyFRAME) - info->icount.frame++; - else if (data & CyPARITY) - info->icount.parity++; - else if (data & CyOVERRUN) - info->icount.overrun++; - - if (data & info->ignore_status_mask) { - info->icount.rx++; - return; - } - if (tty_buffer_request_room(port, 1)) { - if (data & info->read_status_mask) { - if (data & CyBREAK) { - tty_insert_flip_char(port, - cyy_readb(info, CyRDSR), - TTY_BREAK); - info->icount.rx++; - if (port->flags & ASYNC_SAK) { - struct tty_struct *tty = - tty_port_tty_get(port); - if (tty) { - do_SAK(tty); - tty_kref_put(tty); - } - } - } else if (data & CyFRAME) { - tty_insert_flip_char(port, - cyy_readb(info, CyRDSR), - TTY_FRAME); - info->icount.rx++; - info->idle_stats.frame_errs++; - } else if (data & CyPARITY) { - /* Pieces of seven... */ - tty_insert_flip_char(port, - cyy_readb(info, CyRDSR), - TTY_PARITY); - info->icount.rx++; - info->idle_stats.parity_errs++; - } else if (data & CyOVERRUN) { - tty_insert_flip_char(port, 0, - TTY_OVERRUN); - info->icount.rx++; - /* If the flip buffer itself is - overflowing, we still lose - the next incoming character. - */ - tty_insert_flip_char(port, - cyy_readb(info, CyRDSR), - TTY_FRAME); - info->icount.rx++; - info->idle_stats.overruns++; - /* These two conditions may imply */ - /* a normal read should be done. */ - /* } else if(data & CyTIMEOUT) { */ - /* } else if(data & CySPECHAR) { */ - } else { - tty_insert_flip_char(port, 0, - TTY_NORMAL); - info->icount.rx++; - } - } else { - tty_insert_flip_char(port, 0, TTY_NORMAL); - info->icount.rx++; - } - } else { - /* there was a software buffer overrun and nothing - * could be done about it!!! */ - info->icount.buf_overrun++; - info->idle_stats.overruns++; - } - } else { /* normal character reception */ - /* load # chars available from the chip */ - char_count = cyy_readb(info, CyRDCR); - -#ifdef CY_ENABLE_MONITORING - ++info->mon.int_count; - info->mon.char_count += char_count; - if (char_count > info->mon.char_max) - info->mon.char_max = char_count; - info->mon.char_last = char_count; -#endif - len = tty_buffer_request_room(port, char_count); - while (len--) { - data = cyy_readb(info, CyRDSR); - tty_insert_flip_char(port, data, TTY_NORMAL); - info->idle_stats.recv_bytes++; - info->icount.rx++; -#ifdef CY_16Y_HACK - udelay(10L); -#endif - } - info->idle_stats.recv_idle = jiffies; - } - tty_schedule_flip(port); - - /* end of service */ - cyy_writeb(info, CyRIR, save_xir & 0x3f); - cyy_writeb(info, CyCAR, save_car); -} - -static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, - void __iomem *base_addr) -{ - struct cyclades_port *info; - struct tty_struct *tty; - int char_count, index = cinfo->bus_index; - u8 save_xir, channel, save_car, outch; - - /* Since we only get here when the transmit buffer - is empty, we know we can always stuff a dozen - characters. */ -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip); -#endif - - /* determine the channel & change to that context */ - save_xir = readb(base_addr + (CyTIR << index)); - channel = save_xir & CyIRChannel; - save_car = readb(base_addr + (CyCAR << index)); - cy_writeb(base_addr + (CyCAR << index), save_xir); - - info = &cinfo->ports[channel + chip * 4]; - tty = tty_port_tty_get(&info->port); - if (tty == NULL) { - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy); - goto end; - } - - /* load the on-chip space for outbound data */ - char_count = info->xmit_fifo_size; - - if (info->x_char) { /* send special char */ - outch = info->x_char; - cyy_writeb(info, CyTDR, outch); - char_count--; - info->icount.tx++; - info->x_char = 0; - } - - if (info->breakon || info->breakoff) { - if (info->breakon) { - cyy_writeb(info, CyTDR, 0); - cyy_writeb(info, CyTDR, 0x81); - info->breakon = 0; - char_count -= 2; - } - if (info->breakoff) { - cyy_writeb(info, CyTDR, 0); - cyy_writeb(info, CyTDR, 0x83); - info->breakoff = 0; - char_count -= 2; - } - } - - while (char_count-- > 0) { - if (!info->xmit_cnt) { - if (cyy_readb(info, CySRER) & CyTxMpty) { - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxMpty); - } else { - cyy_writeb(info, CySRER, CyTxMpty | - (cyy_readb(info, CySRER) & ~CyTxRdy)); - } - goto done; - } - if (info->port.xmit_buf == NULL) { - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxRdy); - goto done; - } - if (tty->stopped || tty->hw_stopped) { - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxRdy); - goto done; - } - /* Because the Embedded Transmit Commands have been enabled, - * we must check to see if the escape character, NULL, is being - * sent. If it is, we must ensure that there is room for it to - * be doubled in the output stream. Therefore we no longer - * advance the pointer when the character is fetched, but - * rather wait until after the check for a NULL output - * character. This is necessary because there may not be room - * for the two chars needed to send a NULL.) - */ - outch = info->port.xmit_buf[info->xmit_tail]; - if (outch) { - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) & - (SERIAL_XMIT_SIZE - 1); - cyy_writeb(info, CyTDR, outch); - info->icount.tx++; - } else { - if (char_count > 1) { - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) & - (SERIAL_XMIT_SIZE - 1); - cyy_writeb(info, CyTDR, outch); - cyy_writeb(info, CyTDR, 0); - info->icount.tx++; - char_count--; - } - } - } - -done: - tty_wakeup(tty); - tty_kref_put(tty); -end: - /* end of service */ - cyy_writeb(info, CyTIR, save_xir & 0x3f); - cyy_writeb(info, CyCAR, save_car); -} - -static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, - void __iomem *base_addr) -{ - struct cyclades_port *info; - struct tty_struct *tty; - int index = cinfo->bus_index; - u8 save_xir, channel, save_car, mdm_change, mdm_status; - - /* determine the channel & change to that context */ - save_xir = readb(base_addr + (CyMIR << index)); - channel = save_xir & CyIRChannel; - info = &cinfo->ports[channel + chip * 4]; - save_car = cyy_readb(info, CyCAR); - cyy_writeb(info, CyCAR, save_xir); - - mdm_change = cyy_readb(info, CyMISR); - mdm_status = cyy_readb(info, CyMSVR1); - - tty = tty_port_tty_get(&info->port); - if (!tty) - goto end; - - if (mdm_change & CyANY_DELTA) { - /* For statistics only */ - if (mdm_change & CyDCD) - info->icount.dcd++; - if (mdm_change & CyCTS) - info->icount.cts++; - if (mdm_change & CyDSR) - info->icount.dsr++; - if (mdm_change & CyRI) - info->icount.rng++; - - wake_up_interruptible(&info->port.delta_msr_wait); - } - - if ((mdm_change & CyDCD) && tty_port_check_carrier(&info->port)) { - if (mdm_status & CyDCD) - wake_up_interruptible(&info->port.open_wait); - else - tty_hangup(tty); - } - if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) { - if (tty->hw_stopped) { - if (mdm_status & CyCTS) { - /* cy_start isn't used - because... !!! */ - tty->hw_stopped = 0; - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) | CyTxRdy); - tty_wakeup(tty); - } - } else { - if (!(mdm_status & CyCTS)) { - /* cy_stop isn't used - because ... !!! */ - tty->hw_stopped = 1; - cyy_writeb(info, CySRER, - cyy_readb(info, CySRER) & ~CyTxRdy); - } - } - } -/* if (mdm_change & CyDSR) { - } - if (mdm_change & CyRI) { - }*/ - tty_kref_put(tty); -end: - /* end of service */ - cyy_writeb(info, CyMIR, save_xir & 0x3f); - cyy_writeb(info, CyCAR, save_car); -} - -/* The real interrupt service routine is called - whenever the card wants its hand held--chars - received, out buffer empty, modem change, etc. - */ -static irqreturn_t cyy_interrupt(int irq, void *dev_id) -{ - int status; - struct cyclades_card *cinfo = dev_id; - void __iomem *base_addr, *card_base_addr; - unsigned int chip, too_many, had_work; - int index; - - if (unlikely(cinfo == NULL)) { -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n", - irq); -#endif - return IRQ_NONE; /* spurious interrupt */ - } - - card_base_addr = cinfo->base_addr; - index = cinfo->bus_index; - - /* card was not initialized yet (e.g. DEBUG_SHIRQ) */ - if (unlikely(card_base_addr == NULL)) - return IRQ_HANDLED; - - /* This loop checks all chips in the card. Make a note whenever - _any_ chip had some work to do, as this is considered an - indication that there will be more to do. Only when no chip - has any work does this outermost loop exit. - */ - do { - had_work = 0; - for (chip = 0; chip < cinfo->num_chips; chip++) { - base_addr = cinfo->base_addr + - (cy_chip_offset[chip] << index); - too_many = 0; - while ((status = readb(base_addr + - (CySVRR << index))) != 0x00) { - had_work++; - /* The purpose of the following test is to ensure that - no chip can monopolize the driver. This forces the - chips to be checked in a round-robin fashion (after - draining each of a bunch (1000) of characters). - */ - if (1000 < too_many++) - break; - spin_lock(&cinfo->card_lock); - if (status & CySRReceive) /* rx intr */ - cyy_chip_rx(cinfo, chip, base_addr); - if (status & CySRTransmit) /* tx intr */ - cyy_chip_tx(cinfo, chip, base_addr); - if (status & CySRModem) /* modem intr */ - cyy_chip_modem(cinfo, chip, base_addr); - spin_unlock(&cinfo->card_lock); - } - } - } while (had_work); - - /* clear interrupts */ - spin_lock(&cinfo->card_lock); - cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0); - /* Cy_ClrIntr is 0x1800 */ - spin_unlock(&cinfo->card_lock); - return IRQ_HANDLED; -} /* cyy_interrupt */ - -static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set, - unsigned int clear) -{ - struct cyclades_card *card = info->card; - int channel = info->line - card->first_line; - u32 rts, dtr, msvrr, msvrd; - - channel &= 0x03; - - if (info->rtsdtr_inv) { - msvrr = CyMSVR2; - msvrd = CyMSVR1; - rts = CyDTR; - dtr = CyRTS; - } else { - msvrr = CyMSVR1; - msvrd = CyMSVR2; - rts = CyRTS; - dtr = CyDTR; - } - if (set & TIOCM_RTS) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrr, rts); - } - if (clear & TIOCM_RTS) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrr, ~rts); - } - if (set & TIOCM_DTR) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrd, dtr); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n"); - printk(KERN_DEBUG " status: 0x%x, 0x%x\n", - cyy_readb(info, CyMSVR1), - cyy_readb(info, CyMSVR2)); -#endif - } - if (clear & TIOCM_DTR) { - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, msvrd, ~dtr); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n"); - printk(KERN_DEBUG " status: 0x%x, 0x%x\n", - cyy_readb(info, CyMSVR1), - cyy_readb(info, CyMSVR2)); -#endif - } -} - -/***********************************************************/ -/********* End of block of Cyclom-Y specific code **********/ -/******** Start of block of Cyclades-Z specific code *******/ -/***********************************************************/ - -static int -cyz_fetch_msg(struct cyclades_card *cinfo, - __u32 *channel, __u8 *cmd, __u32 *param) -{ - struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; - unsigned long loc_doorbell; - - loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell); - if (loc_doorbell) { - *cmd = (char)(0xff & loc_doorbell); - *channel = readl(&board_ctrl->fwcmd_channel); - *param = (__u32) readl(&board_ctrl->fwcmd_param); - cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff); - return 1; - } - return 0; -} /* cyz_fetch_msg */ - -static int -cyz_issue_cmd(struct cyclades_card *cinfo, - __u32 channel, __u8 cmd, __u32 param) -{ - struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; - __u32 __iomem *pci_doorbell; - unsigned int index; - - if (!cyz_is_loaded(cinfo)) - return -1; - - index = 0; - pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell; - while ((readl(pci_doorbell) & 0xff) != 0) { - if (index++ == 1000) - return (int)(readl(pci_doorbell) & 0xff); - udelay(50L); - } - cy_writel(&board_ctrl->hcmd_channel, channel); - cy_writel(&board_ctrl->hcmd_param, param); - cy_writel(pci_doorbell, (long)cmd); - - return 0; -} /* cyz_issue_cmd */ - -static void cyz_handle_rx(struct cyclades_port *info) -{ - struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; - struct cyclades_card *cinfo = info->card; - struct tty_port *port = &info->port; - unsigned int char_count; - int len; -#ifdef BLOCKMOVE - unsigned char *buf; -#else - char data; -#endif - __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr; - - rx_get = new_rx_get = readl(&buf_ctrl->rx_get); - rx_put = readl(&buf_ctrl->rx_put); - rx_bufsize = readl(&buf_ctrl->rx_bufsize); - rx_bufaddr = readl(&buf_ctrl->rx_bufaddr); - if (rx_put >= rx_get) - char_count = rx_put - rx_get; - else - char_count = rx_put - rx_get + rx_bufsize; - - if (!char_count) - return; - -#ifdef CY_ENABLE_MONITORING - info->mon.int_count++; - info->mon.char_count += char_count; - if (char_count > info->mon.char_max) - info->mon.char_max = char_count; - info->mon.char_last = char_count; -#endif - -#ifdef BLOCKMOVE - /* we'd like to use memcpy(t, f, n) and memset(s, c, count) - for performance, but because of buffer boundaries, there - may be several steps to the operation */ - while (1) { - len = tty_prepare_flip_string(port, &buf, - char_count); - if (!len) - break; - - len = min_t(unsigned int, min(len, char_count), - rx_bufsize - new_rx_get); - - memcpy_fromio(buf, cinfo->base_addr + - rx_bufaddr + new_rx_get, len); - - new_rx_get = (new_rx_get + len) & - (rx_bufsize - 1); - char_count -= len; - info->icount.rx += len; - info->idle_stats.recv_bytes += len; - } -#else - len = tty_buffer_request_room(port, char_count); - while (len--) { - data = readb(cinfo->base_addr + rx_bufaddr + - new_rx_get); - new_rx_get = (new_rx_get + 1) & - (rx_bufsize - 1); - tty_insert_flip_char(port, data, TTY_NORMAL); - info->idle_stats.recv_bytes++; - info->icount.rx++; - } -#endif -#ifdef CONFIG_CYZ_INTR - /* Recalculate the number of chars in the RX buffer and issue - a cmd in case it's higher than the RX high water mark */ - rx_put = readl(&buf_ctrl->rx_put); - if (rx_put >= rx_get) - char_count = rx_put - rx_get; - else - char_count = rx_put - rx_get + rx_bufsize; - if (char_count >= readl(&buf_ctrl->rx_threshold) && - !timer_pending(&info->rx_full_timer)) - mod_timer(&info->rx_full_timer, jiffies + 1); -#endif - info->idle_stats.recv_idle = jiffies; - tty_schedule_flip(&info->port); - - /* Update rx_get */ - cy_writel(&buf_ctrl->rx_get, new_rx_get); -} - -static void cyz_handle_tx(struct cyclades_port *info) -{ - struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; - struct cyclades_card *cinfo = info->card; - struct tty_struct *tty; - u8 data; - unsigned int char_count; -#ifdef BLOCKMOVE - int small_count; -#endif - __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr; - - if (info->xmit_cnt <= 0) /* Nothing to transmit */ - return; - - tx_get = readl(&buf_ctrl->tx_get); - tx_put = readl(&buf_ctrl->tx_put); - tx_bufsize = readl(&buf_ctrl->tx_bufsize); - tx_bufaddr = readl(&buf_ctrl->tx_bufaddr); - if (tx_put >= tx_get) - char_count = tx_get - tx_put - 1 + tx_bufsize; - else - char_count = tx_get - tx_put - 1; - - if (!char_count) - return; - - tty = tty_port_tty_get(&info->port); - if (tty == NULL) - goto ztxdone; - - if (info->x_char) { /* send special char */ - data = info->x_char; - - cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); - tx_put = (tx_put + 1) & (tx_bufsize - 1); - info->x_char = 0; - char_count--; - info->icount.tx++; - } -#ifdef BLOCKMOVE - while (0 < (small_count = min_t(unsigned int, - tx_bufsize - tx_put, min_t(unsigned int, - (SERIAL_XMIT_SIZE - info->xmit_tail), - min_t(unsigned int, info->xmit_cnt, - char_count))))) { - - memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put), - &info->port.xmit_buf[info->xmit_tail], - small_count); - - tx_put = (tx_put + small_count) & (tx_bufsize - 1); - char_count -= small_count; - info->icount.tx += small_count; - info->xmit_cnt -= small_count; - info->xmit_tail = (info->xmit_tail + small_count) & - (SERIAL_XMIT_SIZE - 1); - } -#else - while (info->xmit_cnt && char_count) { - data = info->port.xmit_buf[info->xmit_tail]; - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) & - (SERIAL_XMIT_SIZE - 1); - - cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); - tx_put = (tx_put + 1) & (tx_bufsize - 1); - char_count--; - info->icount.tx++; - } -#endif - tty_wakeup(tty); - tty_kref_put(tty); -ztxdone: - /* Update tx_put */ - cy_writel(&buf_ctrl->tx_put, tx_put); -} - -static void cyz_handle_cmd(struct cyclades_card *cinfo) -{ - struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; - struct cyclades_port *info; - __u32 channel, param, fw_ver; - __u8 cmd; - int special_count; - int delta_count; - - fw_ver = readl(&board_ctrl->fw_version); - - while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { - special_count = 0; - delta_count = 0; - info = &cinfo->ports[channel]; - - switch (cmd) { - case C_CM_PR_ERROR: - tty_insert_flip_char(&info->port, 0, TTY_PARITY); - info->icount.rx++; - special_count++; - break; - case C_CM_FR_ERROR: - tty_insert_flip_char(&info->port, 0, TTY_FRAME); - info->icount.rx++; - special_count++; - break; - case C_CM_RXBRK: - tty_insert_flip_char(&info->port, 0, TTY_BREAK); - info->icount.rx++; - special_count++; - break; - case C_CM_MDCD: - info->icount.dcd++; - delta_count++; - if (tty_port_check_carrier(&info->port)) { - u32 dcd = fw_ver > 241 ? param : - readl(&info->u.cyz.ch_ctrl->rs_status); - if (dcd & C_RS_DCD) - wake_up_interruptible(&info->port.open_wait); - else - tty_port_tty_hangup(&info->port, false); - } - break; - case C_CM_MCTS: - info->icount.cts++; - delta_count++; - break; - case C_CM_MRI: - info->icount.rng++; - delta_count++; - break; - case C_CM_MDSR: - info->icount.dsr++; - delta_count++; - break; -#ifdef Z_WAKE - case C_CM_IOCTLW: - complete(&info->shutdown_wait); - break; -#endif -#ifdef CONFIG_CYZ_INTR - case C_CM_RXHIWM: - case C_CM_RXNNDT: - case C_CM_INTBACK2: - /* Reception Interrupt */ -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " - "port %ld\n", info->card, channel); -#endif - cyz_handle_rx(info); - break; - case C_CM_TXBEMPTY: - case C_CM_TXLOWWM: - case C_CM_INTBACK: - /* Transmission Interrupt */ -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " - "port %ld\n", info->card, channel); -#endif - cyz_handle_tx(info); - break; -#endif /* CONFIG_CYZ_INTR */ - case C_CM_FATAL: - /* should do something with this !!! */ - break; - default: - break; - } - if (delta_count) - wake_up_interruptible(&info->port.delta_msr_wait); - if (special_count) - tty_schedule_flip(&info->port); - } -} - -#ifdef CONFIG_CYZ_INTR -static irqreturn_t cyz_interrupt(int irq, void *dev_id) -{ - struct cyclades_card *cinfo = dev_id; - - if (unlikely(!cyz_is_loaded(cinfo))) { -#ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyz_interrupt: board not yet loaded " - "(IRQ%d).\n", irq); -#endif - return IRQ_NONE; - } - - /* Handle the interrupts */ - cyz_handle_cmd(cinfo); - - return IRQ_HANDLED; -} /* cyz_interrupt */ - -static void cyz_rx_restart(struct timer_list *t) -{ - struct cyclades_port *info = from_timer(info, t, rx_full_timer); - struct cyclades_card *card = info->card; - int retval; - __u32 channel = info->line - card->first_line; - unsigned long flags; - - spin_lock_irqsave(&card->card_lock, flags); - retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n", - info->line, retval); - } - spin_unlock_irqrestore(&card->card_lock, flags); -} - -#else /* CONFIG_CYZ_INTR */ - -static void cyz_poll(struct timer_list *unused) -{ - struct cyclades_card *cinfo; - struct cyclades_port *info; - unsigned long expires = jiffies + HZ; - unsigned int port, card; - - for (card = 0; card < NR_CARDS; card++) { - cinfo = &cy_card[card]; - - if (!cy_is_Z(cinfo)) - continue; - if (!cyz_is_loaded(cinfo)) - continue; - - /* Skip first polling cycle to avoid racing conditions with the FW */ - if (!cinfo->intr_enabled) { - cinfo->intr_enabled = 1; - continue; - } - - cyz_handle_cmd(cinfo); - - for (port = 0; port < cinfo->nports; port++) { - info = &cinfo->ports[port]; - - if (!info->throttle) - cyz_handle_rx(info); - cyz_handle_tx(info); - } - /* poll every 'cyz_polling_cycle' period */ - expires = jiffies + cyz_polling_cycle; - } - mod_timer(&cyz_timerlist, expires); -} /* cyz_poll */ - -#endif /* CONFIG_CYZ_INTR */ - -/********** End of block of Cyclades-Z specific code *********/ -/***********************************************************/ - -/* This is called whenever a port becomes active; - interrupts are enabled and DTR & RTS are turned on. - */ -static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) -{ - struct cyclades_card *card; - unsigned long flags; - int retval = 0; - int channel; - unsigned long page; - - card = info->card; - channel = info->line - card->first_line; - - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - spin_lock_irqsave(&card->card_lock, flags); - - if (tty_port_initialized(&info->port)) - goto errout; - - if (!info->type) { - set_bit(TTY_IO_ERROR, &tty->flags); - goto errout; - } - - if (info->port.xmit_buf) - free_page(page); - else - info->port.xmit_buf = (unsigned char *)page; - - spin_unlock_irqrestore(&card->card_lock, flags); - - cy_set_line_char(info, tty); - - if (!cy_is_Z(card)) { - channel &= 0x03; - - spin_lock_irqsave(&card->card_lock, flags); - - cyy_writeb(info, CyCAR, channel); - - cyy_writeb(info, CyRTPR, - (info->default_timeout ? info->default_timeout : 0x02)); - /* 10ms rx timeout */ - - cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR); - - cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0); - - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData); - } else { - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - - if (!cyz_is_loaded(card)) - return -ENODEV; - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc startup Z card %d, channel %d, " - "base_addr %p\n", card, channel, card->base_addr); -#endif - spin_lock_irqsave(&card->card_lock, flags); - - cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE); -#ifdef Z_WAKE -#ifdef CONFIG_CYZ_INTR - cy_writel(&ch_ctrl->intr_enable, - C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | - C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD); -#else - cy_writel(&ch_ctrl->intr_enable, - C_IN_IOCTLW | C_IN_MDCD); -#endif /* CONFIG_CYZ_INTR */ -#else -#ifdef CONFIG_CYZ_INTR - cy_writel(&ch_ctrl->intr_enable, - C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | - C_IN_RXNNDT | C_IN_MDCD); -#else - cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD); -#endif /* CONFIG_CYZ_INTR */ -#endif /* Z_WAKE */ - - retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was " - "%x\n", info->line, retval); - } - - /* Flush RX buffers before raising DTR and RTS */ - retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was " - "%x\n", info->line, retval); - } - - /* set timeout !!! */ - /* set RTS and DTR !!! */ - tty_port_raise_dtr_rts(&info->port); - - /* enable send, recv, modem !!! */ - } - - tty_port_set_initialized(&info->port, 1); - - clear_bit(TTY_IO_ERROR, &tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - info->breakon = info->breakoff = 0; - memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); - info->idle_stats.in_use = - info->idle_stats.recv_idle = - info->idle_stats.xmit_idle = jiffies; - - spin_unlock_irqrestore(&card->card_lock, flags); - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc startup done\n"); -#endif - return 0; - -errout: - spin_unlock_irqrestore(&card->card_lock, flags); - free_page(page); - return retval; -} /* startup */ - -static void start_xmit(struct cyclades_port *info) -{ - struct cyclades_card *card = info->card; - unsigned long flags; - int channel = info->line - card->first_line; - - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { -#ifdef CONFIG_CYZ_INTR - int retval; - - spin_lock_irqsave(&card->card_lock, flags); - retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was " - "%x\n", info->line, retval); - } - spin_unlock_irqrestore(&card->card_lock, flags); -#else /* CONFIG_CYZ_INTR */ - /* Don't have to do anything at this time */ -#endif /* CONFIG_CYZ_INTR */ - } -} /* start_xmit */ - -/* - * This routine shuts down a serial port; interrupts are disabled, - * and DTR is dropped if the hangup on close termio flag is on. - */ -static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) -{ - struct cyclades_card *card; - unsigned long flags; - - if (!tty_port_initialized(&info->port)) - return; - - card = info->card; - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - - /* Clear delta_msr_wait queue to avoid mem leaks. */ - wake_up_interruptible(&info->port.delta_msr_wait); - - if (info->port.xmit_buf) { - unsigned char *temp; - temp = info->port.xmit_buf; - info->port.xmit_buf = NULL; - free_page((unsigned long)temp); - } - if (C_HUPCL(tty)) - cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR); - - cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR); - /* it may be appropriate to clear _XMIT at - some later date (after testing)!!! */ - - set_bit(TTY_IO_ERROR, &tty->flags); - tty_port_set_initialized(&info->port, 0); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { -#ifdef CY_DEBUG_OPEN - int channel = info->line - card->first_line; - printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, " - "base_addr %p\n", card, channel, card->base_addr); -#endif - - if (!cyz_is_loaded(card)) - return; - - spin_lock_irqsave(&card->card_lock, flags); - - if (info->port.xmit_buf) { - unsigned char *temp; - temp = info->port.xmit_buf; - info->port.xmit_buf = NULL; - free_page((unsigned long)temp); - } - - if (C_HUPCL(tty)) - tty_port_lower_dtr_rts(&info->port); - - set_bit(TTY_IO_ERROR, &tty->flags); - tty_port_set_initialized(&info->port, 0); - - spin_unlock_irqrestore(&card->card_lock, flags); - } - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc shutdown done\n"); -#endif -} /* shutdown */ - -/* - * ------------------------------------------------------------ - * cy_open() and friends - * ------------------------------------------------------------ - */ - -/* - * This routine is called whenever a serial port is opened. It - * performs the serial-specific initialization for the tty structure. - */ -static int cy_open(struct tty_struct *tty, struct file *filp) -{ - struct cyclades_port *info; - unsigned int i, line = tty->index; - int retval; - - for (i = 0; i < NR_CARDS; i++) - if (line < cy_card[i].first_line + cy_card[i].nports && - line >= cy_card[i].first_line) - break; - if (i >= NR_CARDS) - return -ENODEV; - info = &cy_card[i].ports[line - cy_card[i].first_line]; - if (info->line < 0) - return -ENODEV; - - /* If the card's firmware hasn't been loaded, - treat it as absent from the system. This - will make the user pay attention. - */ - if (cy_is_Z(info->card)) { - struct cyclades_card *cinfo = info->card; - struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS; - - if (!cyz_is_loaded(cinfo)) { - if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) && - readl(&firm_id->signature) == - ZFIRM_HLT) { - printk(KERN_ERR "cyc:Cyclades-Z Error: you " - "need an external power supply for " - "this number of ports.\nFirmware " - "halted.\n"); - } else { - printk(KERN_ERR "cyc:Cyclades-Z firmware not " - "yet loaded\n"); - } - return -ENODEV; - } -#ifdef CONFIG_CYZ_INTR - else { - /* In case this Z board is operating in interrupt mode, its - interrupts should be enabled as soon as the first open - happens to one of its ports. */ - if (!cinfo->intr_enabled) { - u16 intr; - - /* Enable interrupts on the PLX chip */ - intr = readw(&cinfo->ctl_addr.p9060-> - intr_ctrl_stat) | 0x0900; - cy_writew(&cinfo->ctl_addr.p9060-> - intr_ctrl_stat, intr); - /* Enable interrupts on the FW */ - retval = cyz_issue_cmd(cinfo, 0, - C_CM_IRQ_ENBL, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:IRQ enable retval " - "was %x\n", retval); - } - cinfo->intr_enabled = 1; - } - } -#endif /* CONFIG_CYZ_INTR */ - /* Make sure this Z port really exists in hardware */ - if (info->line > (cinfo->first_line + cinfo->nports - 1)) - return -ENODEV; - } -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line); -#endif - tty->driver_data = info; - if (serial_paranoia_check(info, tty->name, "cy_open")) - return -ENODEV; - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line, - info->port.count); -#endif - info->port.count++; -#ifdef CY_DEBUG_COUNT - printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n", - current->pid, info->port.count); -#endif - - /* - * Start up serial port - */ - retval = cy_startup(info, tty); - if (retval) - return retval; - - retval = tty_port_block_til_ready(&info->port, tty, filp); - if (retval) { -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready " - "with %d\n", retval); -#endif - return retval; - } - - info->throttle = 0; - tty_port_tty_set(&info->port, tty); - -#ifdef CY_DEBUG_OPEN - printk(KERN_DEBUG "cyc:cy_open done\n"); -#endif - return 0; -} /* cy_open */ - -/* - * cy_wait_until_sent() --- wait until the transmitter is empty - */ -static void cy_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct cyclades_card *card; - struct cyclades_port *info = tty->driver_data; - unsigned long orig_jiffies; - int char_time; - - if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent")) - return; - - if (info->xmit_fifo_size == 0) - return; /* Just in case.... */ - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size; - char_time = char_time / 5; - if (char_time <= 0) - char_time = 1; - if (timeout < 0) - timeout = 0; - if (timeout) - char_time = min(char_time, timeout); - /* - * If the transmitter hasn't cleared in twice the approximate - * amount of time to send the entire FIFO, it probably won't - * ever clear. This assumes the UART isn't doing flow - * control, which is currently the case. Hence, if it ever - * takes longer than info->timeout, this is probably due to a - * UART bug of some kind. So, we clamp the timeout parameter at - * 2*info->timeout. - */ - if (!timeout || timeout > 2 * info->timeout) - timeout = 2 * info->timeout; - - card = info->card; - if (!cy_is_Z(card)) { - while (cyy_readb(info, CySRER) & CyTxRdy) { - if (msleep_interruptible(jiffies_to_msecs(char_time))) - break; - if (timeout && time_after(jiffies, orig_jiffies + - timeout)) - break; - } - } - /* Run one more char cycle */ - msleep_interruptible(jiffies_to_msecs(char_time * 5)); -} - -static void cy_flush_buffer(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - int channel, retval; - unsigned long flags; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_flush_buffer")) - return; - - card = info->card; - channel = info->line - card->first_line; - - spin_lock_irqsave(&card->card_lock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - spin_unlock_irqrestore(&card->card_lock, flags); - - if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board - buffers as well */ - spin_lock_irqsave(&card->card_lock, flags); - retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d " - "was %x\n", info->line, retval); - } - spin_unlock_irqrestore(&card->card_lock, flags); - } - tty_wakeup(tty); -} /* cy_flush_buffer */ - - -static void cy_do_close(struct tty_port *port) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *card; - unsigned long flags; - int channel; - - card = info->card; - channel = info->line - card->first_line; - spin_lock_irqsave(&card->card_lock, flags); - - if (!cy_is_Z(card)) { - /* Stop accepting input */ - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData); - if (tty_port_initialized(&info->port)) { - /* Waiting for on-board buffers to be empty before - closing the port */ - spin_unlock_irqrestore(&card->card_lock, flags); - cy_wait_until_sent(port->tty, info->timeout); - spin_lock_irqsave(&card->card_lock, flags); - } - } else { -#ifdef Z_WAKE - /* Waiting for on-board buffers to be empty before closing - the port */ - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - int retval; - - if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) { - retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L); - if (retval != 0) { - printk(KERN_DEBUG "cyc:cy_close retval on " - "ttyC%d was %x\n", info->line, retval); - } - spin_unlock_irqrestore(&card->card_lock, flags); - wait_for_completion_interruptible(&info->shutdown_wait); - spin_lock_irqsave(&card->card_lock, flags); - } -#endif - } - spin_unlock_irqrestore(&card->card_lock, flags); - cy_shutdown(info, port->tty); -} - -/* - * This routine is called when a particular tty device is closed. - */ -static void cy_close(struct tty_struct *tty, struct file *filp) -{ - struct cyclades_port *info = tty->driver_data; - if (!info || serial_paranoia_check(info, tty->name, "cy_close")) - return; - tty_port_close(&info->port, tty, filp); -} /* cy_close */ - -/* This routine gets called when tty_write has put something into - * the write_queue. The characters may come from user space or - * kernel space. - * - * This routine will return the number of characters actually - * accepted for writing. - * - * If the port is not already transmitting stuff, start it off by - * enabling interrupts. The interrupt service routine will then - * ensure that the characters are sent. - * If the port is already active, there is no need to kick it. - * - */ -static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - struct cyclades_port *info = tty->driver_data; - unsigned long flags; - int c, ret = 0; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_write")) - return 0; - - if (!info->port.xmit_buf) - return 0; - - spin_lock_irqsave(&info->card->card_lock, flags); - while (1) { - c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1)); - c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head)); - - if (c <= 0) - break; - - memcpy(info->port.xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & - (SERIAL_XMIT_SIZE - 1); - info->xmit_cnt += c; - buf += c; - count -= c; - ret += c; - } - spin_unlock_irqrestore(&info->card->card_lock, flags); - - info->idle_stats.xmit_bytes += ret; - info->idle_stats.xmit_idle = jiffies; - - if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) - start_xmit(info); - - return ret; -} /* cy_write */ - -/* - * This routine is called by the kernel to write a single - * character to the tty device. If the kernel uses this routine, - * it must call the flush_chars() routine (if defined) when it is - * done stuffing characters into the driver. If there is no room - * in the queue, the character is ignored. - */ -static int cy_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct cyclades_port *info = tty->driver_data; - unsigned long flags; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_put_char")) - return 0; - - if (!info->port.xmit_buf) - return 0; - - spin_lock_irqsave(&info->card->card_lock, flags); - if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) { - spin_unlock_irqrestore(&info->card->card_lock, flags); - return 0; - } - - info->port.xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= SERIAL_XMIT_SIZE - 1; - info->xmit_cnt++; - info->idle_stats.xmit_bytes++; - info->idle_stats.xmit_idle = jiffies; - spin_unlock_irqrestore(&info->card->card_lock, flags); - return 1; -} /* cy_put_char */ - -/* - * This routine is called by the kernel after it has written a - * series of characters to the tty device using put_char(). - */ -static void cy_flush_chars(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_flush_chars")) - return; - - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->port.xmit_buf) - return; - - start_xmit(info); -} /* cy_flush_chars */ - -/* - * This routine returns the numbers of characters the tty driver - * will accept for queuing to be written. This number is subject - * to change as output buffers get emptied, or if the output flow - * control is activated. - */ -static int cy_write_room(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - int ret; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_write_room")) - return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} /* cy_write_room */ - -static int cy_chars_in_buffer(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer")) - return 0; - -#ifdef Z_EXT_CHARS_IN_BUFFER - if (!cy_is_Z(info->card)) { -#endif /* Z_EXT_CHARS_IN_BUFFER */ -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", - info->line, info->xmit_cnt); -#endif - return info->xmit_cnt; -#ifdef Z_EXT_CHARS_IN_BUFFER - } else { - struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; - int char_count; - __u32 tx_put, tx_get, tx_bufsize; - - tx_get = readl(&buf_ctrl->tx_get); - tx_put = readl(&buf_ctrl->tx_put); - tx_bufsize = readl(&buf_ctrl->tx_bufsize); - if (tx_put >= tx_get) - char_count = tx_put - tx_get; - else - char_count = tx_put - tx_get + tx_bufsize; -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", - info->line, info->xmit_cnt + char_count); -#endif - return info->xmit_cnt + char_count; - } -#endif /* Z_EXT_CHARS_IN_BUFFER */ -} /* cy_chars_in_buffer */ - -/* - * ------------------------------------------------------------ - * cy_ioctl() and friends - * ------------------------------------------------------------ - */ - -static void cyy_baud_calc(struct cyclades_port *info, __u32 baud) -{ - int co, co_val, bpr; - __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : - 25000000); - - if (baud == 0) { - info->tbpr = info->tco = info->rbpr = info->rco = 0; - return; - } - - /* determine which prescaler to use */ - for (co = 4, co_val = 2048; co; co--, co_val >>= 2) { - if (cy_clock / co_val / baud > 63) - break; - } - - bpr = (cy_clock / co_val * 2 / baud + 1) / 2; - if (bpr > 255) - bpr = 255; - - info->tbpr = info->rbpr = bpr; - info->tco = info->rco = co; -} - -/* - * This routine finds or computes the various line characteristics. - * It used to be called config_setup - */ -static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) -{ - struct cyclades_card *card; - unsigned long flags; - int channel; - unsigned cflag, iflag; - int baud, baud_rate = 0; - int i; - - if (info->line == -1) - return; - - cflag = tty->termios.c_cflag; - iflag = tty->termios.c_iflag; - - card = info->card; - channel = info->line - card->first_line; - - if (!cy_is_Z(card)) { - u32 cflags; - - /* baud rate */ - baud = tty_get_baud_rate(tty); - if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - if (info->custom_divisor) - baud_rate = info->baud / info->custom_divisor; - else - baud_rate = info->baud; - } else if (baud > CD1400_MAX_SPEED) { - baud = CD1400_MAX_SPEED; - } - /* find the baud index */ - for (i = 0; i < 20; i++) { - if (baud == baud_table[i]) - break; - } - if (i == 20) - i = 19; /* CD1400_MAX_SPEED */ - - if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - cyy_baud_calc(info, baud_rate); - } else { - if (info->chip_rev >= CD1400_REV_J) { - /* It is a CD1400 rev. J or later */ - info->tbpr = baud_bpr_60[i]; /* Tx BPR */ - info->tco = baud_co_60[i]; /* Tx CO */ - info->rbpr = baud_bpr_60[i]; /* Rx BPR */ - info->rco = baud_co_60[i]; /* Rx CO */ - } else { - info->tbpr = baud_bpr_25[i]; /* Tx BPR */ - info->tco = baud_co_25[i]; /* Tx CO */ - info->rbpr = baud_bpr_25[i]; /* Rx BPR */ - info->rco = baud_co_25[i]; /* Rx CO */ - } - } - if (baud_table[i] == 134) { - /* get it right for 134.5 baud */ - info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) + - 2; - } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - info->timeout = (info->xmit_fifo_size * HZ * 15 / - baud_rate) + 2; - } else if (baud_table[i]) { - info->timeout = (info->xmit_fifo_size * HZ * 15 / - baud_table[i]) + 2; - /* this needs to be propagated into the card info */ - } else { - info->timeout = 0; - } - /* By tradition (is it a standard?) a baud rate of zero - implies the line should be/has been closed. A bit - later in this routine such a test is performed. */ - - /* byte size and parity */ - info->cor5 = 0; - info->cor4 = 0; - /* receive threshold */ - info->cor3 = (info->default_threshold ? - info->default_threshold : baud_cor3[i]); - info->cor2 = CyETC; - switch (cflag & CSIZE) { - case CS5: - info->cor1 = Cy_5_BITS; - break; - case CS6: - info->cor1 = Cy_6_BITS; - break; - case CS7: - info->cor1 = Cy_7_BITS; - break; - case CS8: - info->cor1 = Cy_8_BITS; - break; - } - if (cflag & CSTOPB) - info->cor1 |= Cy_2_STOP; - - if (cflag & PARENB) { - if (cflag & PARODD) - info->cor1 |= CyPARITY_O; - else - info->cor1 |= CyPARITY_E; - } else - info->cor1 |= CyPARITY_NONE; - - /* CTS flow control flag */ - tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); - if (cflag & CRTSCTS) - info->cor2 |= CyCtsAE; - else - info->cor2 &= ~CyCtsAE; - tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); - - /*********************************************** - The hardware option, CyRtsAO, presents RTS when - the chip has characters to send. Since most modems - use RTS as reverse (inbound) flow control, this - option is not used. If inbound flow control is - necessary, DTR can be programmed to provide the - appropriate signals for use with a non-standard - cable. Contact Marcio Saito for details. - ***********************************************/ - - channel &= 0x03; - - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel); - - /* tx and rx baud rate */ - - cyy_writeb(info, CyTCOR, info->tco); - cyy_writeb(info, CyTBPR, info->tbpr); - cyy_writeb(info, CyRCOR, info->rco); - cyy_writeb(info, CyRBPR, info->rbpr); - - /* set line characteristics according configuration */ - - cyy_writeb(info, CySCHR1, START_CHAR(tty)); - cyy_writeb(info, CySCHR2, STOP_CHAR(tty)); - cyy_writeb(info, CyCOR1, info->cor1); - cyy_writeb(info, CyCOR2, info->cor2); - cyy_writeb(info, CyCOR3, info->cor3); - cyy_writeb(info, CyCOR4, info->cor4); - cyy_writeb(info, CyCOR5, info->cor5); - - cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch | - CyCOR3ch); - - /* !!! Is this needed? */ - cyy_writeb(info, CyCAR, channel); - cyy_writeb(info, CyRTPR, - (info->default_timeout ? info->default_timeout : 0x02)); - /* 10ms rx timeout */ - - cflags = CyCTS; - if (!C_CLOCAL(tty)) - cflags |= CyDSR | CyRI | CyDCD; - /* without modem intr */ - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh); - /* act on 1->0 modem transitions */ - if ((cflag & CRTSCTS) && info->rflow) - cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]); - else - cyy_writeb(info, CyMCOR1, cflags); - /* act on 0->1 modem transitions */ - cyy_writeb(info, CyMCOR2, cflags); - - if (i == 0) /* baud rate is zero, turn off line */ - cyy_change_rts_dtr(info, 0, TIOCM_DTR); - else - cyy_change_rts_dtr(info, TIOCM_DTR, 0); - - clear_bit(TTY_IO_ERROR, &tty->flags); - spin_unlock_irqrestore(&card->card_lock, flags); - - } else { - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - __u32 sw_flow; - int retval; - - if (!cyz_is_loaded(card)) - return; - - /* baud rate */ - baud = tty_get_baud_rate(tty); - if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - if (info->custom_divisor) - baud_rate = info->baud / info->custom_divisor; - else - baud_rate = info->baud; - } else if (baud > CYZ_MAX_SPEED) { - baud = CYZ_MAX_SPEED; - } - cy_writel(&ch_ctrl->comm_baud, baud); - - if (baud == 134) { - /* get it right for 134.5 baud */ - info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) + - 2; - } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == - ASYNC_SPD_CUST) { - info->timeout = (info->xmit_fifo_size * HZ * 15 / - baud_rate) + 2; - } else if (baud) { - info->timeout = (info->xmit_fifo_size * HZ * 15 / - baud) + 2; - /* this needs to be propagated into the card info */ - } else { - info->timeout = 0; - } - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: - cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5); - break; - case CS6: - cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6); - break; - case CS7: - cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7); - break; - case CS8: - cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8); - break; - } - if (cflag & CSTOPB) { - cy_writel(&ch_ctrl->comm_data_l, - readl(&ch_ctrl->comm_data_l) | C_DL_2STOP); - } else { - cy_writel(&ch_ctrl->comm_data_l, - readl(&ch_ctrl->comm_data_l) | C_DL_1STOP); - } - if (cflag & PARENB) { - if (cflag & PARODD) - cy_writel(&ch_ctrl->comm_parity, C_PR_ODD); - else - cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN); - } else - cy_writel(&ch_ctrl->comm_parity, C_PR_NONE); - - /* CTS flow control flag */ - if (cflag & CRTSCTS) { - cy_writel(&ch_ctrl->hw_flow, - readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS); - } else { - cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) & - ~(C_RS_CTS | C_RS_RTS)); - } - /* As the HW flow control is done in firmware, the driver - doesn't need to care about it */ - tty_port_set_cts_flow(&info->port, 0); - - /* XON/XOFF/XANY flow control flags */ - sw_flow = 0; - if (iflag & IXON) { - sw_flow |= C_FL_OXX; - if (iflag & IXANY) - sw_flow |= C_FL_OIXANY; - } - cy_writel(&ch_ctrl->sw_flow, sw_flow); - - retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:set_line_char retval on ttyC%d " - "was %x\n", info->line, retval); - } - - /* CD sensitivity */ - tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL); - - if (baud == 0) { /* baud rate is zero, turn off line */ - cy_writel(&ch_ctrl->rs_control, - readl(&ch_ctrl->rs_control) & ~C_RS_DTR); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n"); -#endif - } else { - cy_writel(&ch_ctrl->rs_control, - readl(&ch_ctrl->rs_control) | C_RS_DTR); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n"); -#endif - } - - retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d " - "was %x\n", info->line, retval); - } - - clear_bit(TTY_IO_ERROR, &tty->flags); - } -} /* set_line_char */ - -static int cy_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *cinfo = info->card; - - if (serial_paranoia_check(info, tty->name, "cy_ioctl")) - return -ENODEV; - ss->type = info->type; - ss->line = info->line; - ss->port = (info->card - cy_card) * 0x100 + info->line - - cinfo->first_line; - ss->irq = cinfo->irq; - ss->flags = info->port.flags; - ss->close_delay = info->port.close_delay; - ss->closing_wait = info->port.closing_wait; - ss->baud_base = info->baud; - ss->custom_divisor = info->custom_divisor; - return 0; -} - -static int cy_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct cyclades_port *info = tty->driver_data; - int old_flags; - int ret; - - if (serial_paranoia_check(info, tty->name, "cy_ioctl")) - return -ENODEV; - - mutex_lock(&info->port.mutex); - - old_flags = info->port.flags; - - if (!capable(CAP_SYS_ADMIN)) { - if (ss->close_delay != info->port.close_delay || - ss->baud_base != info->baud || - (ss->flags & ASYNC_FLAGS & - ~ASYNC_USR_MASK) != - (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)) - { - mutex_unlock(&info->port.mutex); - return -EPERM; - } - info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) | - (ss->flags & ASYNC_USR_MASK); - info->baud = ss->baud_base; - info->custom_divisor = ss->custom_divisor; - goto check_and_exit; - } - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->baud = ss->baud_base; - info->custom_divisor = ss->custom_divisor; - info->port.flags = (info->port.flags & ~ASYNC_FLAGS) | - (ss->flags & ASYNC_FLAGS); - info->port.close_delay = ss->close_delay * HZ / 100; - info->port.closing_wait = ss->closing_wait * HZ / 100; - -check_and_exit: - if (tty_port_initialized(&info->port)) { - if ((ss->flags ^ old_flags) & ASYNC_SPD_MASK) { - /* warn about deprecation unless clearing */ - if (ss->flags & ASYNC_SPD_MASK) - dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n"); - } - cy_set_line_char(info, tty); - ret = 0; - } else { - ret = cy_startup(info, tty); - } - mutex_unlock(&info->port.mutex); - return ret; -} /* set_serial_info */ - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value) -{ - struct cyclades_card *card = info->card; - unsigned int result; - unsigned long flags; - u8 status; - - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty); - spin_unlock_irqrestore(&card->card_lock, flags); - result = (status ? 0 : TIOCSER_TEMT); - } else { - /* Not supported yet */ - return -EINVAL; - } - return put_user(result, value); -} - -static int cy_tiocmget(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - int result; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - card = info->card; - - if (!cy_is_Z(card)) { - unsigned long flags; - int channel = info->line - card->first_line; - u8 status; - - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - status = cyy_readb(info, CyMSVR1); - status |= cyy_readb(info, CyMSVR2); - spin_unlock_irqrestore(&card->card_lock, flags); - - if (info->rtsdtr_inv) { - result = ((status & CyRTS) ? TIOCM_DTR : 0) | - ((status & CyDTR) ? TIOCM_RTS : 0); - } else { - result = ((status & CyRTS) ? TIOCM_RTS : 0) | - ((status & CyDTR) ? TIOCM_DTR : 0); - } - result |= ((status & CyDCD) ? TIOCM_CAR : 0) | - ((status & CyRI) ? TIOCM_RNG : 0) | - ((status & CyDSR) ? TIOCM_DSR : 0) | - ((status & CyCTS) ? TIOCM_CTS : 0); - } else { - u32 lstatus; - - if (!cyz_is_loaded(card)) { - result = -ENODEV; - goto end; - } - - lstatus = readl(&info->u.cyz.ch_ctrl->rs_status); - result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) | - ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) | - ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) | - ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) | - ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) | - ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0); - } -end: - return result; -} /* cy_tiomget */ - -static int -cy_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - card = info->card; - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_change_rts_dtr(info, set, clear); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - int retval, channel = info->line - card->first_line; - u32 rs; - - if (!cyz_is_loaded(card)) - return -ENODEV; - - spin_lock_irqsave(&card->card_lock, flags); - rs = readl(&ch_ctrl->rs_control); - if (set & TIOCM_RTS) - rs |= C_RS_RTS; - if (clear & TIOCM_RTS) - rs &= ~C_RS_RTS; - if (set & TIOCM_DTR) { - rs |= C_RS_DTR; -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n"); -#endif - } - if (clear & TIOCM_DTR) { - rs &= ~C_RS_DTR; -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "cyc:set_modem_info clearing " - "Z DTR\n"); -#endif - } - cy_writel(&ch_ctrl->rs_control, rs); - retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); - spin_unlock_irqrestore(&card->card_lock, flags); - if (retval != 0) { - printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d " - "was %x\n", info->line, retval); - } - } - return 0; -} - -/* - * cy_break() --- routine which turns the break handling on or off - */ -static int cy_break(struct tty_struct *tty, int break_state) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - unsigned long flags; - int retval = 0; - - if (serial_paranoia_check(info, tty->name, "cy_break")) - return -EINVAL; - - card = info->card; - - spin_lock_irqsave(&card->card_lock, flags); - if (!cy_is_Z(card)) { - /* Let the transmit ISR take care of this (since it - requires stuffing characters into the output stream). - */ - if (break_state == -1) { - if (!info->breakon) { - info->breakon = 1; - if (!info->xmit_cnt) { - spin_unlock_irqrestore(&card->card_lock, flags); - start_xmit(info); - spin_lock_irqsave(&card->card_lock, flags); - } - } - } else { - if (!info->breakoff) { - info->breakoff = 1; - if (!info->xmit_cnt) { - spin_unlock_irqrestore(&card->card_lock, flags); - start_xmit(info); - spin_lock_irqsave(&card->card_lock, flags); - } - } - } - } else { - if (break_state == -1) { - retval = cyz_issue_cmd(card, - info->line - card->first_line, - C_CM_SET_BREAK, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc:cy_break (set) retval on " - "ttyC%d was %x\n", info->line, retval); - } - } else { - retval = cyz_issue_cmd(card, - info->line - card->first_line, - C_CM_CLR_BREAK, 0L); - if (retval != 0) { - printk(KERN_DEBUG "cyc:cy_break (clr) retval " - "on ttyC%d was %x\n", info->line, - retval); - } - } - } - spin_unlock_irqrestore(&card->card_lock, flags); - return retval; -} /* cy_break */ - -static int set_threshold(struct cyclades_port *info, unsigned long value) -{ - struct cyclades_card *card = info->card; - unsigned long flags; - - if (!cy_is_Z(card)) { - info->cor3 &= ~CyREC_FIFO; - info->cor3 |= value & CyREC_FIFO; - - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyCOR3, info->cor3); - cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch); - spin_unlock_irqrestore(&card->card_lock, flags); - } - return 0; -} /* set_threshold */ - -static int get_threshold(struct cyclades_port *info, - unsigned long __user *value) -{ - struct cyclades_card *card = info->card; - - if (!cy_is_Z(card)) { - u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO; - return put_user(tmp, value); - } - return 0; -} /* get_threshold */ - -static int set_timeout(struct cyclades_port *info, unsigned long value) -{ - struct cyclades_card *card = info->card; - unsigned long flags; - - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_writeb(info, CyRTPR, value & 0xff); - spin_unlock_irqrestore(&card->card_lock, flags); - } - return 0; -} /* set_timeout */ - -static int get_timeout(struct cyclades_port *info, - unsigned long __user *value) -{ - struct cyclades_card *card = info->card; - - if (!cy_is_Z(card)) { - u8 tmp = cyy_readb(info, CyRTPR); - return put_user(tmp, value); - } - return 0; -} /* get_timeout */ - -static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg, - struct cyclades_icount *cprev) -{ - struct cyclades_icount cnow; - unsigned long flags; - int ret; - - spin_lock_irqsave(&info->card->card_lock, flags); - cnow = info->icount; /* atomic copy */ - spin_unlock_irqrestore(&info->card->card_lock, flags); - - ret = ((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)); - - *cprev = cnow; - - return ret; -} - -/* - * This routine allows the tty driver to implement device- - * specific ioctl's. If the ioctl number passed in cmd is - * not recognized by the driver, it should return ENOIOCTLCMD. - */ -static int -cy_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_icount cnow; /* kernel counter temps */ - int ret_val = 0; - unsigned long flags; - void __user *argp = (void __user *)arg; - - if (serial_paranoia_check(info, tty->name, "cy_ioctl")) - return -ENODEV; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", - info->line, cmd, arg); -#endif - - switch (cmd) { - case CYGETMON: - if (copy_to_user(argp, &info->mon, sizeof(info->mon))) { - ret_val = -EFAULT; - break; - } - memset(&info->mon, 0, sizeof(info->mon)); - break; - case CYGETTHRESH: - ret_val = get_threshold(info, argp); - break; - case CYSETTHRESH: - ret_val = set_threshold(info, arg); - break; - case CYGETDEFTHRESH: - ret_val = put_user(info->default_threshold, - (unsigned long __user *)argp); - break; - case CYSETDEFTHRESH: - info->default_threshold = arg & 0x0f; - break; - case CYGETTIMEOUT: - ret_val = get_timeout(info, argp); - break; - case CYSETTIMEOUT: - ret_val = set_timeout(info, arg); - break; - case CYGETDEFTIMEOUT: - ret_val = put_user(info->default_timeout, - (unsigned long __user *)argp); - break; - case CYSETDEFTIMEOUT: - info->default_timeout = arg & 0xff; - break; - case CYSETRFLOW: - info->rflow = (int)arg; - break; - case CYGETRFLOW: - ret_val = info->rflow; - break; - case CYSETRTSDTR_INV: - info->rtsdtr_inv = (int)arg; - break; - case CYGETRTSDTR_INV: - ret_val = info->rtsdtr_inv; - break; - case CYGETCD1400VER: - ret_val = info->chip_rev; - break; -#ifndef CONFIG_CYZ_INTR - case CYZSETPOLLCYCLE: - if (arg > LONG_MAX / HZ) - return -ENODEV; - cyz_polling_cycle = (arg * HZ) / 1000; - break; - case CYZGETPOLLCYCLE: - ret_val = (cyz_polling_cycle * 1000) / HZ; - break; -#endif /* CONFIG_CYZ_INTR */ - case CYSETWAIT: - info->port.closing_wait = (unsigned short)arg * HZ / 100; - break; - case CYGETWAIT: - ret_val = info->port.closing_wait / (HZ / 100); - break; - case TIOCSERGETLSR: /* Get line status register */ - ret_val = get_lsr_info(info, argp); - break; - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: - spin_lock_irqsave(&info->card->card_lock, flags); - /* note the counters on entry */ - cnow = info->icount; - spin_unlock_irqrestore(&info->card->card_lock, flags); - ret_val = wait_event_interruptible(info->port.delta_msr_wait, - cy_cflags_changed(info, arg, &cnow)); - 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. - */ - default: - ret_val = -ENOIOCTLCMD; - } - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_ioctl done\n"); -#endif - return ret_val; -} /* cy_ioctl */ - -static int cy_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *sic) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_icount cnow; /* Used to snapshot */ - unsigned long flags; - - spin_lock_irqsave(&info->card->card_lock, flags); - cnow = info->icount; - spin_unlock_irqrestore(&info->card->card_lock, flags); - - sic->cts = cnow.cts; - sic->dsr = cnow.dsr; - sic->rng = cnow.rng; - sic->dcd = cnow.dcd; - sic->rx = cnow.rx; - sic->tx = cnow.tx; - sic->frame = cnow.frame; - sic->overrun = cnow.overrun; - sic->parity = cnow.parity; - sic->brk = cnow.brk; - sic->buf_overrun = cnow.buf_overrun; - return 0; -} - -/* - * This routine allows the tty driver to be notified when - * device's termios settings have changed. Note that a - * well-designed tty driver should be prepared to accept the case - * where old == NULL, and try to do something rational. - */ -static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct cyclades_port *info = tty->driver_data; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line); -#endif - - cy_set_line_char(info, tty); - - if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; - cy_start(tty); - } -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty)) - wake_up_interruptible(&info->port.open_wait); -#endif -} /* cy_set_termios */ - -/* This function is used to send a high-priority XON/XOFF character to - the device. -*/ -static void cy_send_xchar(struct tty_struct *tty, char ch) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - int channel; - - if (serial_paranoia_check(info, tty->name, "cy_send_xchar")) - return; - - info->x_char = ch; - - if (ch) - cy_start(tty); - - card = info->card; - channel = info->line - card->first_line; - - if (cy_is_Z(card)) { - if (ch == STOP_CHAR(tty)) - cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L); - else if (ch == START_CHAR(tty)) - cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L); - } -} - -/* This routine is called by the upper-layer tty layer to signal - that incoming characters should be throttled because the input - buffers are close to full. - */ -static void cy_throttle(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - unsigned long flags; - -#ifdef CY_DEBUG_THROTTLE - printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty), - info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_throttle")) - return; - - card = info->card; - - if (I_IXOFF(tty)) { - if (!cy_is_Z(card)) - cy_send_xchar(tty, STOP_CHAR(tty)); - else - info->throttle = 1; - } - - if (C_CRTSCTS(tty)) { - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_change_rts_dtr(info, 0, TIOCM_RTS); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { - info->throttle = 1; - } - } -} /* cy_throttle */ - -/* - * This routine notifies the tty driver that it should signal - * that characters can now be sent to the tty without fear of - * overrunning the input buffers of the line disciplines. - */ -static void cy_unthrottle(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - unsigned long flags; - -#ifdef CY_DEBUG_THROTTLE - printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n", - tty_name(tty), info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - cy_send_xchar(tty, START_CHAR(tty)); - } - - if (C_CRTSCTS(tty)) { - card = info->card; - if (!cy_is_Z(card)) { - spin_lock_irqsave(&card->card_lock, flags); - cyy_change_rts_dtr(info, TIOCM_RTS, 0); - spin_unlock_irqrestore(&card->card_lock, flags); - } else { - info->throttle = 0; - } - } -} /* cy_unthrottle */ - -/* cy_start and cy_stop provide software output flow control as a - function of XON/XOFF, software CTS, and other such stuff. -*/ -static void cy_stop(struct tty_struct *tty) -{ - struct cyclades_card *cinfo; - struct cyclades_port *info = tty->driver_data; - int channel; - unsigned long flags; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_stop")) - return; - - cinfo = info->card; - channel = info->line - cinfo->first_line; - if (!cy_is_Z(cinfo)) { - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy); - spin_unlock_irqrestore(&cinfo->card_lock, flags); - } -} /* cy_stop */ - -static void cy_start(struct tty_struct *tty) -{ - struct cyclades_card *cinfo; - struct cyclades_port *info = tty->driver_data; - int channel; - unsigned long flags; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_start")) - return; - - cinfo = info->card; - channel = info->line - cinfo->first_line; - if (!cy_is_Z(cinfo)) { - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy); - spin_unlock_irqrestore(&cinfo->card_lock, flags); - } -} /* cy_start */ - -/* - * cy_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void cy_hangup(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - -#ifdef CY_DEBUG_OTHER - printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_hangup")) - return; - - cy_flush_buffer(tty); - cy_shutdown(info, tty); - tty_port_hangup(&info->port); -} /* cy_hangup */ - -static int cyy_carrier_raised(struct tty_port *port) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *cinfo = info->card; - unsigned long flags; - int channel = info->line - cinfo->first_line; - u32 cd; - - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_writeb(info, CyCAR, channel & 0x03); - cd = cyy_readb(info, CyMSVR1) & CyDCD; - spin_unlock_irqrestore(&cinfo->card_lock, flags); - - return cd; -} - -static void cyy_dtr_rts(struct tty_port *port, int raise) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *cinfo = info->card; - unsigned long flags; - - spin_lock_irqsave(&cinfo->card_lock, flags); - cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0, - raise ? 0 : TIOCM_RTS | TIOCM_DTR); - spin_unlock_irqrestore(&cinfo->card_lock, flags); -} - -static int cyz_carrier_raised(struct tty_port *port) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - - return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD; -} - -static void cyz_dtr_rts(struct tty_port *port, int raise) -{ - struct cyclades_port *info = container_of(port, struct cyclades_port, - port); - struct cyclades_card *cinfo = info->card; - struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; - int ret, channel = info->line - cinfo->first_line; - u32 rs; - - rs = readl(&ch_ctrl->rs_control); - if (raise) - rs |= C_RS_RTS | C_RS_DTR; - else - rs &= ~(C_RS_RTS | C_RS_DTR); - cy_writel(&ch_ctrl->rs_control, rs); - ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L); - if (ret != 0) - printk(KERN_ERR "%s: retval on ttyC%d was %x\n", - __func__, info->line, ret); -#ifdef CY_DEBUG_DTR - printk(KERN_DEBUG "%s: raising Z DTR\n", __func__); -#endif -} - -static const struct tty_port_operations cyy_port_ops = { - .carrier_raised = cyy_carrier_raised, - .dtr_rts = cyy_dtr_rts, - .shutdown = cy_do_close, -}; - -static const struct tty_port_operations cyz_port_ops = { - .carrier_raised = cyz_carrier_raised, - .dtr_rts = cyz_dtr_rts, - .shutdown = cy_do_close, -}; - -/* - * --------------------------------------------------------------------- - * cy_init() and friends - * - * cy_init() is called at boot-time to initialize the serial driver. - * --------------------------------------------------------------------- - */ - -static int cy_init_card(struct cyclades_card *cinfo) -{ - struct cyclades_port *info; - unsigned int channel, port; - - spin_lock_init(&cinfo->card_lock); - cinfo->intr_enabled = 0; - - cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports), - GFP_KERNEL); - if (cinfo->ports == NULL) { - printk(KERN_ERR "Cyclades: cannot allocate ports\n"); - return -ENOMEM; - } - - for (channel = 0, port = cinfo->first_line; channel < cinfo->nports; - channel++, port++) { - info = &cinfo->ports[channel]; - tty_port_init(&info->port); - info->magic = CYCLADES_MAGIC; - info->card = cinfo; - info->line = port; - - info->port.closing_wait = CLOSING_WAIT_DELAY; - info->port.close_delay = 5 * HZ / 10; - init_completion(&info->shutdown_wait); - - if (cy_is_Z(cinfo)) { - struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS; - struct ZFW_CTRL *zfw_ctrl; - - info->port.ops = &cyz_port_ops; - info->type = PORT_STARTECH; - - zfw_ctrl = cinfo->base_addr + - (readl(&firm_id->zfwctrl_addr) & 0xfffff); - info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel]; - info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; - - if (cinfo->hw_ver == ZO_V1) - info->xmit_fifo_size = CYZ_FIFO_SIZE; - else - info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE; -#ifdef CONFIG_CYZ_INTR - timer_setup(&info->rx_full_timer, cyz_rx_restart, 0); -#endif - } else { - unsigned short chip_number; - int index = cinfo->bus_index; - - info->port.ops = &cyy_port_ops; - info->type = PORT_CIRRUS; - info->xmit_fifo_size = CyMAX_CHAR_FIFO; - info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; - info->cor2 = CyETC; - info->cor3 = 0x08; /* _very_ small rcv threshold */ - - chip_number = channel / CyPORTS_PER_CHIP; - info->u.cyy.base_addr = cinfo->base_addr + - (cy_chip_offset[chip_number] << index); - info->chip_rev = cyy_readb(info, CyGFRCR); - - if (info->chip_rev >= CD1400_REV_J) { - /* It is a CD1400 rev. J or later */ - info->tbpr = baud_bpr_60[13]; /* Tx BPR */ - info->tco = baud_co_60[13]; /* Tx CO */ - info->rbpr = baud_bpr_60[13]; /* Rx BPR */ - info->rco = baud_co_60[13]; /* Rx CO */ - info->rtsdtr_inv = 1; - } else { - info->tbpr = baud_bpr_25[13]; /* Tx BPR */ - info->tco = baud_co_25[13]; /* Tx CO */ - info->rbpr = baud_bpr_25[13]; /* Rx BPR */ - info->rco = baud_co_25[13]; /* Rx CO */ - info->rtsdtr_inv = 0; - } - info->read_status_mask = CyTIMEOUT | CySPECHAR | - CyBREAK | CyPARITY | CyFRAME | CyOVERRUN; - } - - } - -#ifndef CONFIG_CYZ_INTR - if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) { - mod_timer(&cyz_timerlist, jiffies + 1); -#ifdef CY_PCI_DEBUG - printk(KERN_DEBUG "Cyclades-Z polling initialized\n"); -#endif - } -#endif - return 0; -} - -/* initialize chips on Cyclom-Y card -- return number of valid - chips (which is number of ports/4) */ -static unsigned short cyy_init_card(void __iomem *true_base_addr, - int index) -{ - unsigned int chip_number; - void __iomem *base_addr; - - cy_writeb(true_base_addr + (Cy_HwReset << index), 0); - /* Cy_HwReset is 0x1400 */ - cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0); - /* Cy_ClrIntr is 0x1800 */ - udelay(500L); - - for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; - chip_number++) { - base_addr = - true_base_addr + (cy_chip_offset[chip_number] << index); - mdelay(1); - if (readb(base_addr + (CyCCR << index)) != 0x00) { - /************* - printk(" chip #%d at %#6lx is never idle (CCR != 0)\n", - chip_number, (unsigned long)base_addr); - *************/ - return chip_number; - } - - cy_writeb(base_addr + (CyGFRCR << index), 0); - udelay(10L); - - /* The Cyclom-16Y does not decode address bit 9 and therefore - cannot distinguish between references to chip 0 and a non- - existent chip 4. If the preceding clearing of the supposed - chip 4 GFRCR register appears at chip 0, there is no chip 4 - and this must be a Cyclom-16Y, not a Cyclom-32Ye. - */ - if (chip_number == 4 && readb(true_base_addr + - (cy_chip_offset[0] << index) + - (CyGFRCR << index)) == 0) { - return chip_number; - } - - cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET); - mdelay(1); - - if (readb(base_addr + (CyGFRCR << index)) == 0x00) { - /* - printk(" chip #%d at %#6lx is not responding ", - chip_number, (unsigned long)base_addr); - printk("(GFRCR stayed 0)\n", - */ - return chip_number; - } - if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) != - 0x40) { - /* - printk(" chip #%d at %#6lx is not valid (GFRCR == " - "%#2x)\n", - chip_number, (unsigned long)base_addr, - base_addr[CyGFRCR<= CD1400_REV_J) { - /* It is a CD1400 rev. J or later */ - /* Impossible to reach 5ms with this chip. - Changed to 2ms instead (f = 500 Hz). */ - cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS); - } else { - /* f = 200 Hz */ - cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS); - } - - /* - printk(" chip #%d at %#6lx is rev 0x%2x\n", - chip_number, (unsigned long)base_addr, - readb(base_addr+(CyGFRCR< NR_PORTS) { - printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " - "more channels are available. Change NR_PORTS " - "in cyclades.c and recompile kernel.\n", - (unsigned long)cy_isa_address); - iounmap(cy_isa_address); - return nboard; - } - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - card = &cy_card[j]; - if (card->base_addr == NULL) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " - "more cards can be used. Change NR_CARDS in " - "cyclades.c and recompile kernel.\n", - (unsigned long)cy_isa_address); - iounmap(cy_isa_address); - return nboard; - } - - /* allocate IRQ */ - if (request_irq(cy_isa_irq, cyy_interrupt, - 0, "Cyclom-Y", card)) { - printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " - "could not allocate IRQ#%d.\n", - (unsigned long)cy_isa_address, cy_isa_irq); - iounmap(cy_isa_address); - return nboard; - } - - /* set cy_card */ - card->base_addr = cy_isa_address; - card->ctl_addr.p9050 = NULL; - card->irq = (int)cy_isa_irq; - card->bus_index = 0; - card->first_line = cy_next_channel; - card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP; - card->nports = cy_isa_nchan; - if (cy_init_card(card)) { - card->base_addr = NULL; - free_irq(cy_isa_irq, card); - iounmap(cy_isa_address); - continue; - } - nboard++; - - printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: " - "%d channels starting from port %d\n", - j + 1, (unsigned long)cy_isa_address, - (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)), - cy_isa_irq, cy_isa_nchan, cy_next_channel); - - for (k = 0, j = cy_next_channel; - j < cy_next_channel + cy_isa_nchan; j++, k++) - tty_port_register_device(&card->ports[k].port, - cy_serial_driver, j, NULL); - cy_next_channel += cy_isa_nchan; - } - return nboard; -#else - return 0; -#endif /* CONFIG_ISA */ -} /* cy_detect_isa */ - -#ifdef CONFIG_PCI -static inline int cyc_isfwstr(const char *str, unsigned int size) -{ - unsigned int a; - - for (a = 0; a < size && *str; a++, str++) - if (*str & 0x80) - return -EINVAL; - - for (; a < size; a++, str++) - if (*str) - return -EINVAL; - - return 0; -} - -static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data, - unsigned int size) -{ - for (; size > 0; size--) { - cy_writel(fpga, *data++); - udelay(10); - } -} - -static void plx_init(struct pci_dev *pdev, int irq, - struct RUNTIME_9060 __iomem *addr) -{ - /* Reset PLX */ - cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000); - udelay(100L); - cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000); - - /* Reload Config. Registers from EEPROM */ - cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000); - udelay(100L); - cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000); - - /* For some yet unknown reason, once the PLX9060 reloads the EEPROM, - * the IRQ is lost and, thus, we have to re-write it to the PCI config. - * registers. This will remain here until we find a permanent fix. - */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); -} - -static int __cyz_load_fw(const struct firmware *fw, - const char *name, const u32 mailbox, void __iomem *base, - void __iomem *fpga) -{ - const void *ptr = fw->data; - const struct zfile_header *h = ptr; - const struct zfile_config *c, *cs; - const struct zfile_block *b, *bs; - unsigned int a, tmp, len = fw->size; -#define BAD_FW KERN_ERR "Bad firmware: " - if (len < sizeof(*h)) { - printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h)); - return -EINVAL; - } - - cs = ptr + h->config_offset; - bs = ptr + h->block_offset; - - if ((void *)(cs + h->n_config) > ptr + len || - (void *)(bs + h->n_blocks) > ptr + len) { - printk(BAD_FW "too short"); - return -EINVAL; - } - - if (cyc_isfwstr(h->name, sizeof(h->name)) || - cyc_isfwstr(h->date, sizeof(h->date))) { - printk(BAD_FW "bad formatted header string\n"); - return -EINVAL; - } - - if (strncmp(name, h->name, sizeof(h->name))) { - printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name); - return -EINVAL; - } - - tmp = 0; - for (c = cs; c < cs + h->n_config; c++) { - for (a = 0; a < c->n_blocks; a++) - if (c->block_list[a] > h->n_blocks) { - printk(BAD_FW "bad block ref number in cfgs\n"); - return -EINVAL; - } - if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */ - tmp++; - } - if (!tmp) { - printk(BAD_FW "nothing appropriate\n"); - return -EINVAL; - } - - for (b = bs; b < bs + h->n_blocks; b++) - if (b->file_offset + b->size > len) { - printk(BAD_FW "bad block data offset\n"); - return -EINVAL; - } - - /* everything is OK, let's seek'n'load it */ - for (c = cs; c < cs + h->n_config; c++) - if (c->mailbox == mailbox && c->function == 0) - break; - - for (a = 0; a < c->n_blocks; a++) { - b = &bs[c->block_list[a]]; - if (b->type == ZBLOCK_FPGA) { - if (fpga != NULL) - cyz_fpga_copy(fpga, ptr + b->file_offset, - b->size); - } else { - if (base != NULL) - memcpy_toio(base + b->ram_offset, - ptr + b->file_offset, b->size); - } - } -#undef BAD_FW - return 0; -} - -static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, - struct RUNTIME_9060 __iomem *ctl_addr, int irq) -{ - const struct firmware *fw; - struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS; - struct CUSTOM_REG __iomem *cust = base_addr; - struct ZFW_CTRL __iomem *pt_zfwctrl; - void __iomem *tmp; - u32 mailbox, status, nchan; - unsigned int i; - int retval; - - retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev); - if (retval) { - dev_err(&pdev->dev, "can't get firmware\n"); - goto err; - } - - /* Check whether the firmware is already loaded and running. If - positive, skip this board */ - if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) { - u32 cntval = readl(base_addr + 0x190); - - udelay(100); - if (cntval != readl(base_addr + 0x190)) { - /* FW counter is working, FW is running */ - dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. " - "Skipping board.\n"); - retval = 0; - goto err_rel; - } - } - - /* start boot */ - cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) & - ~0x00030800UL); - - mailbox = readl(&ctl_addr->mail_box_0); - - if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) { - /* stops CPU and set window to beginning of RAM */ - cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); - cy_writel(&cust->cpu_stop, 0); - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - udelay(100); - } - - plx_init(pdev, irq, ctl_addr); - - if (mailbox != 0) { - /* load FPGA */ - retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL, - base_addr); - if (retval) - goto err_rel; - if (!__cyz_fpga_loaded(ctl_addr)) { - dev_err(&pdev->dev, "fw upload successful, but fw is " - "not loaded\n"); - goto err_rel; - } - } - - /* stops CPU and set window to beginning of RAM */ - cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); - cy_writel(&cust->cpu_stop, 0); - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - udelay(100); - - /* clear memory */ - for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++) - cy_writeb(tmp, 255); - if (mailbox != 0) { - /* set window to last 512K of RAM */ - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE); - for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++) - cy_writeb(tmp, 255); - /* set window to beginning of RAM */ - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - } - - retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL); - release_firmware(fw); - if (retval) - goto err; - - /* finish boot and start boards */ - cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); - cy_writel(&cust->cpu_start, 0); - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - i = 0; - while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40) - msleep(100); - if (status != ZFIRM_ID) { - if (status == ZFIRM_HLT) { - dev_err(&pdev->dev, "you need an external power supply " - "for this number of ports. Firmware halted and " - "board reset.\n"); - retval = -EIO; - goto err; - } - dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting " - "some more time\n", status); - while ((status = readl(&fid->signature)) != ZFIRM_ID && - i++ < 200) - msleep(100); - if (status != ZFIRM_ID) { - dev_err(&pdev->dev, "Board not started in 20 seconds! " - "Giving up. (fid->signature = 0x%x)\n", - status); - dev_info(&pdev->dev, "*** Warning ***: if you are " - "upgrading the FW, please power cycle the " - "system before loading the new FW to the " - "Cyclades-Z.\n"); - - if (__cyz_fpga_loaded(ctl_addr)) - plx_init(pdev, irq, ctl_addr); - - retval = -EIO; - goto err; - } - dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n", - i / 10); - } - pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr); - - dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n", - base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr), - base_addr + readl(&fid->zfwctrl_addr)); - - nchan = readl(&pt_zfwctrl->board_ctrl.n_channel); - dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n", - readl(&pt_zfwctrl->board_ctrl.fw_version), nchan); - - if (nchan == 0) { - dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please " - "check the connection between the Z host card and the " - "serial expanders.\n"); - - if (__cyz_fpga_loaded(ctl_addr)) - plx_init(pdev, irq, ctl_addr); - - dev_info(&pdev->dev, "Null number of ports detected. Board " - "reset.\n"); - retval = 0; - goto err; - } - - cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX); - cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION); - - /* - Early firmware failed to start looking for commands. - This enables firmware interrupts for those commands. - */ - cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) | - (1 << 17)); - cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) | - 0x00030800UL); - - return nchan; -err_rel: - release_firmware(fw); -err: - return retval; -} - -static int cy_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct cyclades_card *card; - void __iomem *addr0 = NULL, *addr2 = NULL; - char *card_name = NULL; - u32 mailbox; - unsigned int device_id, nchan = 0, card_no, i, j; - unsigned char plx_ver; - int retval, irq; - - retval = pci_enable_device(pdev); - if (retval) { - dev_err(&pdev->dev, "cannot enable device\n"); - goto err; - } - - /* read PCI configuration area */ - irq = pdev->irq; - device_id = pdev->device & ~PCI_DEVICE_ID_MASK; - -#if defined(__alpha__) - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ - dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low " - "addresses on Alpha systems.\n"); - retval = -EIO; - goto err_dis; - } -#endif - if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) { - dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low " - "addresses\n"); - retval = -EIO; - goto err_dis; - } - - if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { - dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring " - "it...\n"); - pdev->resource[2].flags &= ~IORESOURCE_IO; - } - - retval = pci_request_regions(pdev, "cyclades"); - if (retval) { - dev_err(&pdev->dev, "failed to reserve resources\n"); - goto err_dis; - } - - retval = -EIO; - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || - device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { - card_name = "Cyclom-Y"; - - addr0 = ioremap(pci_resource_start(pdev, 0), - CyPCI_Yctl); - if (addr0 == NULL) { - dev_err(&pdev->dev, "can't remap ctl region\n"); - goto err_reg; - } - addr2 = ioremap(pci_resource_start(pdev, 2), - CyPCI_Ywin); - if (addr2 == NULL) { - dev_err(&pdev->dev, "can't remap base region\n"); - goto err_unmap; - } - - nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1); - if (nchan == 0) { - dev_err(&pdev->dev, "Cyclom-Y PCI host card with no " - "Serial-Modules\n"); - goto err_unmap; - } - } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { - struct RUNTIME_9060 __iomem *ctl_addr; - - ctl_addr = addr0 = ioremap(pci_resource_start(pdev, 0), - CyPCI_Zctl); - if (addr0 == NULL) { - dev_err(&pdev->dev, "can't remap ctl region\n"); - goto err_reg; - } - - /* Disable interrupts on the PLX before resetting it */ - cy_writew(&ctl_addr->intr_ctrl_stat, - readw(&ctl_addr->intr_ctrl_stat) & ~0x0900); - - plx_init(pdev, irq, addr0); - - mailbox = readl(&ctl_addr->mail_box_0); - - addr2 = ioremap(pci_resource_start(pdev, 2), - mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin); - if (addr2 == NULL) { - dev_err(&pdev->dev, "can't remap base region\n"); - goto err_unmap; - } - - if (mailbox == ZE_V1) { - card_name = "Cyclades-Ze"; - } else { - card_name = "Cyclades-8Zo"; -#ifdef CY_PCI_DEBUG - if (mailbox == ZO_V1) { - cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); - dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA " - "id %lx, ver %lx\n", (ulong)(0xff & - readl(&((struct CUSTOM_REG *)addr2)-> - fpga_id)), (ulong)(0xff & - readl(&((struct CUSTOM_REG *)addr2)-> - fpga_version))); - cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - } else { - dev_info(&pdev->dev, "Cyclades-Z/PCI: New " - "Cyclades-Z board. FPGA not loaded\n"); - } -#endif - /* The following clears the firmware id word. This - ensures that the driver will not attempt to talk to - the board until it has been properly initialized. - */ - if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) - cy_writel(addr2 + ID_ADDRESS, 0L); - } - - retval = cyz_load_fw(pdev, addr2, addr0, irq); - if (retval <= 0) - goto err_unmap; - nchan = retval; - } - - if ((cy_next_channel + nchan) > NR_PORTS) { - dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " - "channels are available. Change NR_PORTS in " - "cyclades.c and recompile kernel.\n"); - goto err_unmap; - } - /* fill the next cy_card structure available */ - for (card_no = 0; card_no < NR_CARDS; card_no++) { - card = &cy_card[card_no]; - if (card->base_addr == NULL) - break; - } - if (card_no == NR_CARDS) { /* no more cy_cards available */ - dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " - "more cards can be used. Change NR_CARDS in " - "cyclades.c and recompile kernel.\n"); - goto err_unmap; - } - - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || - device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { - /* allocate IRQ */ - retval = request_irq(irq, cyy_interrupt, - IRQF_SHARED, "Cyclom-Y", card); - if (retval) { - dev_err(&pdev->dev, "could not allocate IRQ\n"); - goto err_unmap; - } - card->num_chips = nchan / CyPORTS_PER_CHIP; - } else { - struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS; - struct ZFW_CTRL __iomem *zfw_ctrl; - - zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff); - - card->hw_ver = mailbox; - card->num_chips = (unsigned int)-1; - card->board_ctrl = &zfw_ctrl->board_ctrl; -#ifdef CONFIG_CYZ_INTR - /* allocate IRQ only if board has an IRQ */ - if (irq != 0 && irq != 255) { - retval = request_irq(irq, cyz_interrupt, - IRQF_SHARED, "Cyclades-Z", card); - if (retval) { - dev_err(&pdev->dev, "could not allocate IRQ\n"); - goto err_unmap; - } - } -#endif /* CONFIG_CYZ_INTR */ - } - - /* set cy_card */ - card->base_addr = addr2; - card->ctl_addr.p9050 = addr0; - card->irq = irq; - card->bus_index = 1; - card->first_line = cy_next_channel; - card->nports = nchan; - retval = cy_init_card(card); - if (retval) - goto err_null; - - pci_set_drvdata(pdev, card); - - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || - device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { - /* enable interrupts in the PCI interface */ - plx_ver = readb(addr2 + CyPLX_VER) & 0x0f; - switch (plx_ver) { - case PLX_9050: - cy_writeb(addr0 + 0x4c, 0x43); - break; - - case PLX_9060: - case PLX_9080: - default: /* Old boards, use PLX_9060 */ - { - struct RUNTIME_9060 __iomem *ctl_addr = addr0; - plx_init(pdev, irq, ctl_addr); - cy_writew(&ctl_addr->intr_ctrl_stat, - readw(&ctl_addr->intr_ctrl_stat) | 0x0900); - break; - } - } - } - - dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from " - "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel); - for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++) - tty_port_register_device(&card->ports[j].port, - cy_serial_driver, i, &pdev->dev); - cy_next_channel += nchan; - - return 0; -err_null: - card->base_addr = NULL; - free_irq(irq, card); -err_unmap: - iounmap(addr0); - if (addr2) - iounmap(addr2); -err_reg: - pci_release_regions(pdev); -err_dis: - pci_disable_device(pdev); -err: - return retval; -} - -static void cy_pci_remove(struct pci_dev *pdev) -{ - struct cyclades_card *cinfo = pci_get_drvdata(pdev); - unsigned int i, channel; - - /* non-Z with old PLX */ - if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) == - PLX_9050) - cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0); - else -#ifndef CONFIG_CYZ_INTR - if (!cy_is_Z(cinfo)) -#endif - cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat, - readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) & - ~0x0900); - - iounmap(cinfo->base_addr); - if (cinfo->ctl_addr.p9050) - iounmap(cinfo->ctl_addr.p9050); - if (cinfo->irq -#ifndef CONFIG_CYZ_INTR - && !cy_is_Z(cinfo) -#endif /* CONFIG_CYZ_INTR */ - ) - free_irq(cinfo->irq, cinfo); - pci_release_regions(pdev); - - cinfo->base_addr = NULL; - for (channel = 0, i = cinfo->first_line; i < cinfo->first_line + - cinfo->nports; i++, channel++) { - tty_unregister_device(cy_serial_driver, i); - tty_port_destroy(&cinfo->ports[channel].port); - } - cinfo->nports = 0; - kfree(cinfo->ports); -} - -static struct pci_driver cy_pci_driver = { - .name = "cyclades", - .id_table = cy_pci_dev_id, - .probe = cy_pci_probe, - .remove = cy_pci_remove -}; -#endif - -static int cyclades_proc_show(struct seq_file *m, void *v) -{ - struct cyclades_port *info; - unsigned int i, j; - __u32 cur_jifs = jiffies; - - seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn " - "IdleIn Overruns Ldisc\n"); - - /* Output one line for each known port */ - for (i = 0; i < NR_CARDS; i++) - for (j = 0; j < cy_card[i].nports; j++) { - info = &cy_card[i].ports[j]; - - if (info->port.count) { - /* XXX is the ldisc num worth this? */ - struct tty_struct *tty; - struct tty_ldisc *ld; - int num = 0; - tty = tty_port_tty_get(&info->port); - if (tty) { - ld = tty_ldisc_ref(tty); - if (ld) { - num = ld->ops->num; - tty_ldisc_deref(ld); - } - tty_kref_put(tty); - } - seq_printf(m, "%3d %8lu %10lu %8lu " - "%10lu %8lu %9lu %6d\n", info->line, - (cur_jifs - info->idle_stats.in_use) / - HZ, info->idle_stats.xmit_bytes, - (cur_jifs - info->idle_stats.xmit_idle)/ - HZ, info->idle_stats.recv_bytes, - (cur_jifs - info->idle_stats.recv_idle)/ - HZ, info->idle_stats.overruns, - num); - } else - seq_printf(m, "%3d %8lu %10lu %8lu " - "%10lu %8lu %9lu %6ld\n", - info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); - } - return 0; -} - -/* The serial driver boot-time initialization code! - Hardware I/O ports are mapped to character special devices on a - first found, first allocated manner. That is, this code searches - for Cyclom cards in the system. As each is found, it is probed - to discover how many chips (and thus how many ports) are present. - These ports are mapped to the tty ports 32 and upward in monotonic - fashion. If an 8-port card is replaced with a 16-port card, the - port mapping on a following card will shift. - - This approach is different from what is used in the other serial - device driver because the Cyclom is more properly a multiplexer, - not just an aggregation of serial ports on one card. - - If there are more cards with more ports than have been - statically allocated above, a warning is printed and the - extra ports are ignored. - */ - -static const struct tty_operations cy_ops = { - .open = cy_open, - .close = cy_close, - .write = cy_write, - .put_char = cy_put_char, - .flush_chars = cy_flush_chars, - .write_room = cy_write_room, - .chars_in_buffer = cy_chars_in_buffer, - .flush_buffer = cy_flush_buffer, - .ioctl = cy_ioctl, - .throttle = cy_throttle, - .unthrottle = cy_unthrottle, - .set_termios = cy_set_termios, - .stop = cy_stop, - .start = cy_start, - .hangup = cy_hangup, - .break_ctl = cy_break, - .wait_until_sent = cy_wait_until_sent, - .tiocmget = cy_tiocmget, - .tiocmset = cy_tiocmset, - .get_icount = cy_get_icount, - .set_serial = cy_set_serial_info, - .get_serial = cy_get_serial_info, - .proc_show = cyclades_proc_show, -}; - -static int __init cy_init(void) -{ - unsigned int nboards; - int retval = -ENOMEM; - - cy_serial_driver = alloc_tty_driver(NR_PORTS); - if (!cy_serial_driver) - goto err; - - printk(KERN_INFO "Cyclades driver " CY_VERSION "\n"); - - /* Initialize the tty_driver structure */ - - cy_serial_driver->driver_name = "cyclades"; - cy_serial_driver->name = "ttyC"; - cy_serial_driver->major = CYCLADES_MAJOR; - cy_serial_driver->minor_start = 0; - cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - cy_serial_driver->subtype = SERIAL_TYPE_NORMAL; - cy_serial_driver->init_termios = tty_std_termios; - cy_serial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_set_operations(cy_serial_driver, &cy_ops); - - retval = tty_register_driver(cy_serial_driver); - if (retval) { - printk(KERN_ERR "Couldn't register Cyclades serial driver\n"); - goto err_frtty; - } - - /* the code below is responsible to find the boards. Each different - type of board has its own detection routine. If a board is found, - the next cy_card structure available is set by the detection - routine. These functions are responsible for checking the - availability of cy_card and cy_port data structures and updating - the cy_next_channel. */ - - /* look for isa boards */ - nboards = cy_detect_isa(); - -#ifdef CONFIG_PCI - /* look for pci boards */ - retval = pci_register_driver(&cy_pci_driver); - if (retval && !nboards) { - tty_unregister_driver(cy_serial_driver); - goto err_frtty; - } -#endif - - return 0; -err_frtty: - put_tty_driver(cy_serial_driver); -err: - return retval; -} /* cy_init */ - -static void __exit cy_cleanup_module(void) -{ - struct cyclades_card *card; - unsigned int i, e1; - -#ifndef CONFIG_CYZ_INTR - del_timer_sync(&cyz_timerlist); -#endif /* CONFIG_CYZ_INTR */ - - e1 = tty_unregister_driver(cy_serial_driver); - if (e1) - printk(KERN_ERR "failed to unregister Cyclades serial " - "driver(%d)\n", e1); - -#ifdef CONFIG_PCI - pci_unregister_driver(&cy_pci_driver); -#endif - - for (i = 0; i < NR_CARDS; i++) { - card = &cy_card[i]; - if (card->base_addr) { - /* clear interrupt */ - cy_writeb(card->base_addr + Cy_ClrIntr, 0); - iounmap(card->base_addr); - if (card->ctl_addr.p9050) - iounmap(card->ctl_addr.p9050); - if (card->irq -#ifndef CONFIG_CYZ_INTR - && !cy_is_Z(card) -#endif /* CONFIG_CYZ_INTR */ - ) - free_irq(card->irq, card); - for (e1 = card->first_line; e1 < card->first_line + - card->nports; e1++) - tty_unregister_device(cy_serial_driver, e1); - kfree(card->ports); - } - } - - put_tty_driver(cy_serial_driver); -} /* cy_cleanup_module */ - -module_init(cy_init); -module_exit(cy_cleanup_module); - -MODULE_LICENSE("GPL"); -MODULE_VERSION(CY_VERSION); -MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR); -MODULE_FIRMWARE("cyzfirm.bin"); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 603137da4736..7ec05fdb1fc3 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -15,8 +15,7 @@ config SERIAL_8250 here are those that are setting up dedicated Ethernet WWW/FTP servers, or users that have one of the various bus mice instead of a serial mouse and don't intend to use their machine's standard serial - port for anything. (Note that the Cyclades multi serial port driver - does not need this driver built in for it to work.) + port for anything. To compile this driver as a module, choose M here: the module will be called 8250. @@ -226,7 +225,7 @@ config SERIAL_8250_MANY_PORTS serial port hardware which acts similar to standard serial port hardware. If you only use the standard COM 1/2/3/4 ports, you can say N here to save some memory. You can also say Y if you have an - "intelligent" multiport card such as Cyclades, Digiboards, etc. + "intelligent" multiport card such as Digiboards, etc. # # Multi-port serial cards diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h deleted file mode 100644 index 05ee0f19448a..000000000000 --- a/include/linux/cyclades.h +++ /dev/null @@ -1,364 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* $Revision: 3.0 $$Date: 1998/11/02 14:20:59 $ - * linux/include/linux/cyclades.h - * - * This file was initially written by - * Randolph Bentson and is maintained by - * Ivan Passos . - * - * This file contains the general definitions for the cyclades.c driver - *$Log: cyclades.h,v $ - *Revision 3.1 2002/01/29 11:36:16 henrique - *added throttle field on struct cyclades_port to indicate whether the - *port is throttled or not - * - *Revision 3.1 2000/04/19 18:52:52 ivan - *converted address fields to unsigned long and added fields for physical - *addresses on cyclades_card structure; - * - *Revision 3.0 1998/11/02 14:20:59 ivan - *added nports field on cyclades_card structure; - * - *Revision 2.5 1998/08/03 16:57:01 ivan - *added cyclades_idle_stats structure; - * - *Revision 2.4 1998/06/01 12:09:53 ivan - *removed closing_wait2 from cyclades_port structure; - * - *Revision 2.3 1998/03/16 18:01:12 ivan - *changes in the cyclades_port structure to get it closer to the - *standard serial port structure; - *added constants for new ioctls; - * - *Revision 2.2 1998/02/17 16:50:00 ivan - *changes in the cyclades_port structure (addition of shutdown_wait and - *chip_rev variables); - *added constants for new ioctls and for CD1400 rev. numbers. - * - *Revision 2.1 1997/10/24 16:03:00 ivan - *added rflow (which allows enabling the CD1400 special flow control - *feature) and rtsdtr_inv (which allows DTR/RTS pin inversion) to - *cyclades_port structure; - *added Alpha support - * - *Revision 2.0 1997/06/30 10:30:00 ivan - *added some new doorbell command constants related to IOCTLW and - *UART error signaling - * - *Revision 1.8 1997/06/03 15:30:00 ivan - *added constant ZFIRM_HLT - *added constant CyPCI_Ze_win ( = 2 * Cy_PCI_Zwin) - * - *Revision 1.7 1997/03/26 10:30:00 daniel - *new entries at the end of cyclades_port struct to reallocate - *variables illegally allocated within card memory. - * - *Revision 1.6 1996/09/09 18:35:30 bentson - *fold in changes for Cyclom-Z -- including structures for - *communicating with board as well modest changes to original - *structures to support new features. - * - *Revision 1.5 1995/11/13 21:13:31 bentson - *changes suggested by Michael Chastain - *to support use of this file in non-kernel applications - * - * - */ -#ifndef _LINUX_CYCLADES_H -#define _LINUX_CYCLADES_H - -#include - - -/* Per card data structure */ -struct cyclades_card { - void __iomem *base_addr; - union { - void __iomem *p9050; - struct RUNTIME_9060 __iomem *p9060; - } ctl_addr; - struct BOARD_CTRL __iomem *board_ctrl; /* cyz specific */ - int irq; - unsigned int num_chips; /* 0 if card absent, -1 if Z/PCI, else Y */ - unsigned int first_line; /* minor number of first channel on card */ - unsigned int nports; /* Number of ports in the card */ - int bus_index; /* address shift - 0 for ISA, 1 for PCI */ - int intr_enabled; /* FW Interrupt flag - 0 disabled, 1 enabled */ - u32 hw_ver; - spinlock_t card_lock; - struct cyclades_port *ports; -}; - -/*************************************** - * Memory access functions/macros * - * (required to support Alpha systems) * - ***************************************/ - -#define cy_writeb(port,val) do { writeb((val), (port)); mb(); } while (0) -#define cy_writew(port,val) do { writew((val), (port)); mb(); } while (0) -#define cy_writel(port,val) do { writel((val), (port)); mb(); } while (0) - -/* - * Statistics counters - */ -struct cyclades_icount { - __u32 cts, dsr, rng, dcd, tx, rx; - __u32 frame, parity, overrun, brk; - __u32 buf_overrun; -}; - -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -struct cyclades_port { - int magic; - struct tty_port port; - struct cyclades_card *card; - union { - struct { - void __iomem *base_addr; - } cyy; - struct { - struct CH_CTRL __iomem *ch_ctrl; - struct BUF_CTRL __iomem *buf_ctrl; - } cyz; - } u; - int line; - int flags; /* defined in tty.h */ - int type; /* UART type */ - int read_status_mask; - int ignore_status_mask; - int timeout; - int xmit_fifo_size; - int cor1,cor2,cor3,cor4,cor5; - int tbpr,tco,rbpr,rco; - int baud; - int rflow; - int rtsdtr_inv; - int chip_rev; - int custom_divisor; - u8 x_char; /* to be pushed out ASAP */ - int breakon; - int breakoff; - int xmit_head; - int xmit_tail; - int xmit_cnt; - int default_threshold; - int default_timeout; - unsigned long rflush_count; - struct cyclades_monitor mon; - struct cyclades_idle_stats idle_stats; - struct cyclades_icount icount; - struct completion shutdown_wait; - int throttle; -#ifdef CONFIG_CYZ_INTR - struct timer_list rx_full_timer; -#endif -}; - -#define CLOSING_WAIT_DELAY 30*HZ -#define CY_CLOSING_WAIT_NONE ASYNC_CLOSING_WAIT_NONE -#define CY_CLOSING_WAIT_INF ASYNC_CLOSING_WAIT_INF - - -#define CyMAX_CHIPS_PER_CARD 8 -#define CyMAX_CHAR_FIFO 12 -#define CyPORTS_PER_CHIP 4 -#define CD1400_MAX_SPEED 115200 - -#define CyISA_Ywin 0x2000 - -#define CyPCI_Ywin 0x4000 -#define CyPCI_Yctl 0x80 -#define CyPCI_Zctl CTRL_WINDOW_SIZE -#define CyPCI_Zwin 0x80000 -#define CyPCI_Ze_win (2 * CyPCI_Zwin) - -#define PCI_DEVICE_ID_MASK 0x06 - -/**** CD1400 registers ****/ - -#define CD1400_REV_G 0x46 -#define CD1400_REV_J 0x48 - -#define CyRegSize 0x0400 -#define Cy_HwReset 0x1400 -#define Cy_ClrIntr 0x1800 -#define Cy_EpldRev 0x1e00 - -/* Global Registers */ - -#define CyGFRCR (0x40*2) -#define CyRevE (44) -#define CyCAR (0x68*2) -#define CyCHAN_0 (0x00) -#define CyCHAN_1 (0x01) -#define CyCHAN_2 (0x02) -#define CyCHAN_3 (0x03) -#define CyGCR (0x4B*2) -#define CyCH0_SERIAL (0x00) -#define CyCH0_PARALLEL (0x80) -#define CySVRR (0x67*2) -#define CySRModem (0x04) -#define CySRTransmit (0x02) -#define CySRReceive (0x01) -#define CyRICR (0x44*2) -#define CyTICR (0x45*2) -#define CyMICR (0x46*2) -#define CyICR0 (0x00) -#define CyICR1 (0x01) -#define CyICR2 (0x02) -#define CyICR3 (0x03) -#define CyRIR (0x6B*2) -#define CyTIR (0x6A*2) -#define CyMIR (0x69*2) -#define CyIRDirEq (0x80) -#define CyIRBusy (0x40) -#define CyIRUnfair (0x20) -#define CyIRContext (0x1C) -#define CyIRChannel (0x03) -#define CyPPR (0x7E*2) -#define CyCLOCK_20_1MS (0x27) -#define CyCLOCK_25_1MS (0x31) -#define CyCLOCK_25_5MS (0xf4) -#define CyCLOCK_60_1MS (0x75) -#define CyCLOCK_60_2MS (0xea) - -/* Virtual Registers */ - -#define CyRIVR (0x43*2) -#define CyTIVR (0x42*2) -#define CyMIVR (0x41*2) -#define CyIVRMask (0x07) -#define CyIVRRxEx (0x07) -#define CyIVRRxOK (0x03) -#define CyIVRTxOK (0x02) -#define CyIVRMdmOK (0x01) -#define CyTDR (0x63*2) -#define CyRDSR (0x62*2) -#define CyTIMEOUT (0x80) -#define CySPECHAR (0x70) -#define CyBREAK (0x08) -#define CyPARITY (0x04) -#define CyFRAME (0x02) -#define CyOVERRUN (0x01) -#define CyMISR (0x4C*2) -/* see CyMCOR_ and CyMSVR_ for bits*/ -#define CyEOSRR (0x60*2) - -/* Channel Registers */ - -#define CyLIVR (0x18*2) -#define CyMscsr (0x01) -#define CyTdsr (0x02) -#define CyRgdsr (0x03) -#define CyRedsr (0x07) -#define CyCCR (0x05*2) -/* Format 1 */ -#define CyCHAN_RESET (0x80) -#define CyCHIP_RESET (0x81) -#define CyFlushTransFIFO (0x82) -/* Format 2 */ -#define CyCOR_CHANGE (0x40) -#define CyCOR1ch (0x02) -#define CyCOR2ch (0x04) -#define CyCOR3ch (0x08) -/* Format 3 */ -#define CySEND_SPEC_1 (0x21) -#define CySEND_SPEC_2 (0x22) -#define CySEND_SPEC_3 (0x23) -#define CySEND_SPEC_4 (0x24) -/* Format 4 */ -#define CyCHAN_CTL (0x10) -#define CyDIS_RCVR (0x01) -#define CyENB_RCVR (0x02) -#define CyDIS_XMTR (0x04) -#define CyENB_XMTR (0x08) -#define CySRER (0x06*2) -#define CyMdmCh (0x80) -#define CyRxData (0x10) -#define CyTxRdy (0x04) -#define CyTxMpty (0x02) -#define CyNNDT (0x01) -#define CyCOR1 (0x08*2) -#define CyPARITY_NONE (0x00) -#define CyPARITY_0 (0x20) -#define CyPARITY_1 (0xA0) -#define CyPARITY_E (0x40) -#define CyPARITY_O (0xC0) -#define Cy_1_STOP (0x00) -#define Cy_1_5_STOP (0x04) -#define Cy_2_STOP (0x08) -#define Cy_5_BITS (0x00) -#define Cy_6_BITS (0x01) -#define Cy_7_BITS (0x02) -#define Cy_8_BITS (0x03) -#define CyCOR2 (0x09*2) -#define CyIXM (0x80) -#define CyTxIBE (0x40) -#define CyETC (0x20) -#define CyAUTO_TXFL (0x60) -#define CyLLM (0x10) -#define CyRLM (0x08) -#define CyRtsAO (0x04) -#define CyCtsAE (0x02) -#define CyDsrAE (0x01) -#define CyCOR3 (0x0A*2) -#define CySPL_CH_DRANGE (0x80) /* special character detect range */ -#define CySPL_CH_DET1 (0x40) /* enable special character detection - on SCHR4-SCHR3 */ -#define CyFL_CTRL_TRNSP (0x20) /* Flow Control Transparency */ -#define CySPL_CH_DET2 (0x10) /* Enable special character detection - on SCHR2-SCHR1 */ -#define CyREC_FIFO (0x0F) /* Receive FIFO threshold */ -#define CyCOR4 (0x1E*2) -#define CyCOR5 (0x1F*2) -#define CyCCSR (0x0B*2) -#define CyRxEN (0x80) -#define CyRxFloff (0x40) -#define CyRxFlon (0x20) -#define CyTxEN (0x08) -#define CyTxFloff (0x04) -#define CyTxFlon (0x02) -#define CyRDCR (0x0E*2) -#define CySCHR1 (0x1A*2) -#define CySCHR2 (0x1B*2) -#define CySCHR3 (0x1C*2) -#define CySCHR4 (0x1D*2) -#define CySCRL (0x22*2) -#define CySCRH (0x23*2) -#define CyLNC (0x24*2) -#define CyMCOR1 (0x15*2) -#define CyMCOR2 (0x16*2) -#define CyRTPR (0x21*2) -#define CyMSVR1 (0x6C*2) -#define CyMSVR2 (0x6D*2) -#define CyANY_DELTA (0xF0) -#define CyDSR (0x80) -#define CyCTS (0x40) -#define CyRI (0x20) -#define CyDCD (0x10) -#define CyDTR (0x02) -#define CyRTS (0x01) -#define CyPVSR (0x6F*2) -#define CyRBPR (0x78*2) -#define CyRCOR (0x7C*2) -#define CyTBPR (0x72*2) -#define CyTCOR (0x76*2) - -/* Custom Registers */ - -#define CyPLX_VER (0x3400) -#define PLX_9050 0x0b -#define PLX_9060 0x0c -#define PLX_9080 0x0d - -/***************************************************************************/ - -#endif /* _LINUX_CYCLADES_H */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 8a18517696c1..056d2074f07a 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1711,14 +1711,6 @@ #define PCI_DEVICE_ID_CRP16INTF 0x0903 #define PCI_VENDOR_ID_CYCLADES 0x120e -#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100 -#define PCI_DEVICE_ID_CYCLOM_Y_Hi 0x0101 -#define PCI_DEVICE_ID_CYCLOM_4Y_Lo 0x0102 -#define PCI_DEVICE_ID_CYCLOM_4Y_Hi 0x0103 -#define PCI_DEVICE_ID_CYCLOM_8Y_Lo 0x0104 -#define PCI_DEVICE_ID_CYCLOM_8Y_Hi 0x0105 -#define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200 -#define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201 #define PCI_DEVICE_ID_PC300_RX_2 0x0300 #define PCI_DEVICE_ID_PC300_RX_1 0x0301 #define PCI_DEVICE_ID_PC300_TE_2 0x0310 diff --git a/include/uapi/linux/cyclades.h b/include/uapi/linux/cyclades.h deleted file mode 100644 index fc0add2194a9..000000000000 --- a/include/uapi/linux/cyclades.h +++ /dev/null @@ -1,494 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Revision: 3.0 $$Date: 1998/11/02 14:20:59 $ - * linux/include/linux/cyclades.h - * - * This file was initially written by - * Randolph Bentson and is maintained by - * Ivan Passos . - * - * This file contains the general definitions for the cyclades.c driver - *$Log: cyclades.h,v $ - *Revision 3.1 2002/01/29 11:36:16 henrique - *added throttle field on struct cyclades_port to indicate whether the - *port is throttled or not - * - *Revision 3.1 2000/04/19 18:52:52 ivan - *converted address fields to unsigned long and added fields for physical - *addresses on cyclades_card structure; - * - *Revision 3.0 1998/11/02 14:20:59 ivan - *added nports field on cyclades_card structure; - * - *Revision 2.5 1998/08/03 16:57:01 ivan - *added cyclades_idle_stats structure; - * - *Revision 2.4 1998/06/01 12:09:53 ivan - *removed closing_wait2 from cyclades_port structure; - * - *Revision 2.3 1998/03/16 18:01:12 ivan - *changes in the cyclades_port structure to get it closer to the - *standard serial port structure; - *added constants for new ioctls; - * - *Revision 2.2 1998/02/17 16:50:00 ivan - *changes in the cyclades_port structure (addition of shutdown_wait and - *chip_rev variables); - *added constants for new ioctls and for CD1400 rev. numbers. - * - *Revision 2.1 1997/10/24 16:03:00 ivan - *added rflow (which allows enabling the CD1400 special flow control - *feature) and rtsdtr_inv (which allows DTR/RTS pin inversion) to - *cyclades_port structure; - *added Alpha support - * - *Revision 2.0 1997/06/30 10:30:00 ivan - *added some new doorbell command constants related to IOCTLW and - *UART error signaling - * - *Revision 1.8 1997/06/03 15:30:00 ivan - *added constant ZFIRM_HLT - *added constant CyPCI_Ze_win ( = 2 * Cy_PCI_Zwin) - * - *Revision 1.7 1997/03/26 10:30:00 daniel - *new entries at the end of cyclades_port struct to reallocate - *variables illegally allocated within card memory. - * - *Revision 1.6 1996/09/09 18:35:30 bentson - *fold in changes for Cyclom-Z -- including structures for - *communicating with board as well modest changes to original - *structures to support new features. - * - *Revision 1.5 1995/11/13 21:13:31 bentson - *changes suggested by Michael Chastain - *to support use of this file in non-kernel applications - * - * - */ - -#ifndef _UAPI_LINUX_CYCLADES_H -#define _UAPI_LINUX_CYCLADES_H - -#include - -struct cyclades_monitor { - unsigned long int_count; - unsigned long char_count; - unsigned long char_max; - unsigned long char_last; -}; - -/* - * These stats all reflect activity since the device was last initialized. - * (i.e., since the port was opened with no other processes already having it - * open) - */ -struct cyclades_idle_stats { - __kernel_old_time_t in_use; /* Time device has been in use (secs) */ - __kernel_old_time_t recv_idle; /* Time since last char received (secs) */ - __kernel_old_time_t xmit_idle; /* Time since last char transmitted (secs) */ - unsigned long recv_bytes; /* Bytes received */ - unsigned long xmit_bytes; /* Bytes transmitted */ - unsigned long overruns; /* Input overruns */ - unsigned long frame_errs; /* Input framing errors */ - unsigned long parity_errs; /* Input parity errors */ -}; - -#define CYCLADES_MAGIC 0x4359 - -#define CYGETMON 0x435901 -#define CYGETTHRESH 0x435902 -#define CYSETTHRESH 0x435903 -#define CYGETDEFTHRESH 0x435904 -#define CYSETDEFTHRESH 0x435905 -#define CYGETTIMEOUT 0x435906 -#define CYSETTIMEOUT 0x435907 -#define CYGETDEFTIMEOUT 0x435908 -#define CYSETDEFTIMEOUT 0x435909 -#define CYSETRFLOW 0x43590a -#define CYGETRFLOW 0x43590b -#define CYSETRTSDTR_INV 0x43590c -#define CYGETRTSDTR_INV 0x43590d -#define CYZSETPOLLCYCLE 0x43590e -#define CYZGETPOLLCYCLE 0x43590f -#define CYGETCD1400VER 0x435910 -#define CYSETWAIT 0x435912 -#define CYGETWAIT 0x435913 - -/*************** CYCLOM-Z ADDITIONS ***************/ - -#define CZIOC ('M' << 8) -#define CZ_NBOARDS (CZIOC|0xfa) -#define CZ_BOOT_START (CZIOC|0xfb) -#define CZ_BOOT_DATA (CZIOC|0xfc) -#define CZ_BOOT_END (CZIOC|0xfd) -#define CZ_TEST (CZIOC|0xfe) - -#define CZ_DEF_POLL (HZ/25) - -#define MAX_BOARD 4 /* Max number of boards */ -#define MAX_DEV 256 /* Max number of ports total */ -#define CYZ_MAX_SPEED 921600 - -#define CYZ_FIFO_SIZE 16 - -#define CYZ_BOOT_NWORDS 0x100 -struct CYZ_BOOT_CTRL { - unsigned short nboard; - int status[MAX_BOARD]; - int nchannel[MAX_BOARD]; - int fw_rev[MAX_BOARD]; - unsigned long offset; - unsigned long data[CYZ_BOOT_NWORDS]; -}; - - -#ifndef DP_WINDOW_SIZE -/* - * Memory Window Sizes - */ - -#define DP_WINDOW_SIZE (0x00080000) /* window size 512 Kb */ -#define ZE_DP_WINDOW_SIZE (0x00100000) /* window size 1 Mb (Ze and - 8Zo V.2 */ -#define CTRL_WINDOW_SIZE (0x00000080) /* runtime regs 128 bytes */ - -/* - * CUSTOM_REG - Cyclom-Z/PCI Custom Registers Set. The driver - * normally will access only interested on the fpga_id, fpga_version, - * start_cpu and stop_cpu. - */ - -struct CUSTOM_REG { - __u32 fpga_id; /* FPGA Identification Register */ - __u32 fpga_version; /* FPGA Version Number Register */ - __u32 cpu_start; /* CPU start Register (write) */ - __u32 cpu_stop; /* CPU stop Register (write) */ - __u32 misc_reg; /* Miscellaneous Register */ - __u32 idt_mode; /* IDT mode Register */ - __u32 uart_irq_status; /* UART IRQ status Register */ - __u32 clear_timer0_irq; /* Clear timer interrupt Register */ - __u32 clear_timer1_irq; /* Clear timer interrupt Register */ - __u32 clear_timer2_irq; /* Clear timer interrupt Register */ - __u32 test_register; /* Test Register */ - __u32 test_count; /* Test Count Register */ - __u32 timer_select; /* Timer select register */ - __u32 pr_uart_irq_status; /* Prioritized UART IRQ stat Reg */ - __u32 ram_wait_state; /* RAM wait-state Register */ - __u32 uart_wait_state; /* UART wait-state Register */ - __u32 timer_wait_state; /* timer wait-state Register */ - __u32 ack_wait_state; /* ACK wait State Register */ -}; - -/* - * RUNTIME_9060 - PLX PCI9060ES local configuration and shared runtime - * registers. This structure can be used to access the 9060 registers - * (memory mapped). - */ - -struct RUNTIME_9060 { - __u32 loc_addr_range; /* 00h - Local Address Range */ - __u32 loc_addr_base; /* 04h - Local Address Base */ - __u32 loc_arbitr; /* 08h - Local Arbitration */ - __u32 endian_descr; /* 0Ch - Big/Little Endian Descriptor */ - __u32 loc_rom_range; /* 10h - Local ROM Range */ - __u32 loc_rom_base; /* 14h - Local ROM Base */ - __u32 loc_bus_descr; /* 18h - Local Bus descriptor */ - __u32 loc_range_mst; /* 1Ch - Local Range for Master to PCI */ - __u32 loc_base_mst; /* 20h - Local Base for Master PCI */ - __u32 loc_range_io; /* 24h - Local Range for Master IO */ - __u32 pci_base_mst; /* 28h - PCI Base for Master PCI */ - __u32 pci_conf_io; /* 2Ch - PCI configuration for Master IO */ - __u32 filler1; /* 30h */ - __u32 filler2; /* 34h */ - __u32 filler3; /* 38h */ - __u32 filler4; /* 3Ch */ - __u32 mail_box_0; /* 40h - Mail Box 0 */ - __u32 mail_box_1; /* 44h - Mail Box 1 */ - __u32 mail_box_2; /* 48h - Mail Box 2 */ - __u32 mail_box_3; /* 4Ch - Mail Box 3 */ - __u32 filler5; /* 50h */ - __u32 filler6; /* 54h */ - __u32 filler7; /* 58h */ - __u32 filler8; /* 5Ch */ - __u32 pci_doorbell; /* 60h - PCI to Local Doorbell */ - __u32 loc_doorbell; /* 64h - Local to PCI Doorbell */ - __u32 intr_ctrl_stat; /* 68h - Interrupt Control/Status */ - __u32 init_ctrl; /* 6Ch - EEPROM control, Init Control, etc */ -}; - -/* Values for the Local Base Address re-map register */ - -#define WIN_RAM 0x00000001L /* set the sliding window to RAM */ -#define WIN_CREG 0x14000001L /* set the window to custom Registers */ - -/* Values timer select registers */ - -#define TIMER_BY_1M 0x00 /* clock divided by 1M */ -#define TIMER_BY_256K 0x01 /* clock divided by 256k */ -#define TIMER_BY_128K 0x02 /* clock divided by 128k */ -#define TIMER_BY_32K 0x03 /* clock divided by 32k */ - -/****************** ****************** *******************/ -#endif - -#ifndef ZFIRM_ID -/* #include "zfwint.h" */ -/****************** ****************** *******************/ -/* - * This file contains the definitions for interfacing with the - * Cyclom-Z ZFIRM Firmware. - */ - -/* General Constant definitions */ - -#define MAX_CHAN 64 /* max number of channels per board */ - -/* firmware id structure (set after boot) */ - -#define ID_ADDRESS 0x00000180L /* signature/pointer address */ -#define ZFIRM_ID 0x5557465AL /* ZFIRM/U signature */ -#define ZFIRM_HLT 0x59505B5CL /* ZFIRM needs external power supply */ -#define ZFIRM_RST 0x56040674L /* RST signal (due to FW reset) */ - -#define ZF_TINACT_DEF 1000 /* default inactivity timeout - (1000 ms) */ -#define ZF_TINACT ZF_TINACT_DEF - -struct FIRM_ID { - __u32 signature; /* ZFIRM/U signature */ - __u32 zfwctrl_addr; /* pointer to ZFW_CTRL structure */ -}; - -/* Op. System id */ - -#define C_OS_LINUX 0x00000030 /* generic Linux system */ - -/* channel op_mode */ - -#define C_CH_DISABLE 0x00000000 /* channel is disabled */ -#define C_CH_TXENABLE 0x00000001 /* channel Tx enabled */ -#define C_CH_RXENABLE 0x00000002 /* channel Rx enabled */ -#define C_CH_ENABLE 0x00000003 /* channel Tx/Rx enabled */ -#define C_CH_LOOPBACK 0x00000004 /* Loopback mode */ - -/* comm_parity - parity */ - -#define C_PR_NONE 0x00000000 /* None */ -#define C_PR_ODD 0x00000001 /* Odd */ -#define C_PR_EVEN 0x00000002 /* Even */ -#define C_PR_MARK 0x00000004 /* Mark */ -#define C_PR_SPACE 0x00000008 /* Space */ -#define C_PR_PARITY 0x000000ff - -#define C_PR_DISCARD 0x00000100 /* discard char with frame/par error */ -#define C_PR_IGNORE 0x00000200 /* ignore frame/par error */ - -/* comm_data_l - data length and stop bits */ - -#define C_DL_CS5 0x00000001 -#define C_DL_CS6 0x00000002 -#define C_DL_CS7 0x00000004 -#define C_DL_CS8 0x00000008 -#define C_DL_CS 0x0000000f -#define C_DL_1STOP 0x00000010 -#define C_DL_15STOP 0x00000020 -#define C_DL_2STOP 0x00000040 -#define C_DL_STOP 0x000000f0 - -/* interrupt enabling/status */ - -#define C_IN_DISABLE 0x00000000 /* zero, disable interrupts */ -#define C_IN_TXBEMPTY 0x00000001 /* tx buffer empty */ -#define C_IN_TXLOWWM 0x00000002 /* tx buffer below LWM */ -#define C_IN_RXHIWM 0x00000010 /* rx buffer above HWM */ -#define C_IN_RXNNDT 0x00000020 /* rx no new data timeout */ -#define C_IN_MDCD 0x00000100 /* modem DCD change */ -#define C_IN_MDSR 0x00000200 /* modem DSR change */ -#define C_IN_MRI 0x00000400 /* modem RI change */ -#define C_IN_MCTS 0x00000800 /* modem CTS change */ -#define C_IN_RXBRK 0x00001000 /* Break received */ -#define C_IN_PR_ERROR 0x00002000 /* parity error */ -#define C_IN_FR_ERROR 0x00004000 /* frame error */ -#define C_IN_OVR_ERROR 0x00008000 /* overrun error */ -#define C_IN_RXOFL 0x00010000 /* RX buffer overflow */ -#define C_IN_IOCTLW 0x00020000 /* I/O control w/ wait */ -#define C_IN_MRTS 0x00040000 /* modem RTS drop */ -#define C_IN_ICHAR 0x00080000 - -/* flow control */ - -#define C_FL_OXX 0x00000001 /* output Xon/Xoff flow control */ -#define C_FL_IXX 0x00000002 /* output Xon/Xoff flow control */ -#define C_FL_OIXANY 0x00000004 /* output Xon/Xoff (any xon) */ -#define C_FL_SWFLOW 0x0000000f - -/* flow status */ - -#define C_FS_TXIDLE 0x00000000 /* no Tx data in the buffer or UART */ -#define C_FS_SENDING 0x00000001 /* UART is sending data */ -#define C_FS_SWFLOW 0x00000002 /* Tx is stopped by received Xoff */ - -/* rs_control/rs_status RS-232 signals */ - -#define C_RS_PARAM 0x80000000 /* Indicates presence of parameter in - IOCTLM command */ -#define C_RS_RTS 0x00000001 /* RTS */ -#define C_RS_DTR 0x00000004 /* DTR */ -#define C_RS_DCD 0x00000100 /* CD */ -#define C_RS_DSR 0x00000200 /* DSR */ -#define C_RS_RI 0x00000400 /* RI */ -#define C_RS_CTS 0x00000800 /* CTS */ - -/* commands Host <-> Board */ - -#define C_CM_RESET 0x01 /* reset/flush buffers */ -#define C_CM_IOCTL 0x02 /* re-read CH_CTRL */ -#define C_CM_IOCTLW 0x03 /* re-read CH_CTRL, intr when done */ -#define C_CM_IOCTLM 0x04 /* RS-232 outputs change */ -#define C_CM_SENDXOFF 0x10 /* send Xoff */ -#define C_CM_SENDXON 0x11 /* send Xon */ -#define C_CM_CLFLOW 0x12 /* Clear flow control (resume) */ -#define C_CM_SENDBRK 0x41 /* send break */ -#define C_CM_INTBACK 0x42 /* Interrupt back */ -#define C_CM_SET_BREAK 0x43 /* Tx break on */ -#define C_CM_CLR_BREAK 0x44 /* Tx break off */ -#define C_CM_CMD_DONE 0x45 /* Previous command done */ -#define C_CM_INTBACK2 0x46 /* Alternate Interrupt back */ -#define C_CM_TINACT 0x51 /* set inactivity detection */ -#define C_CM_IRQ_ENBL 0x52 /* enable generation of interrupts */ -#define C_CM_IRQ_DSBL 0x53 /* disable generation of interrupts */ -#define C_CM_ACK_ENBL 0x54 /* enable acknowledged interrupt mode */ -#define C_CM_ACK_DSBL 0x55 /* disable acknowledged intr mode */ -#define C_CM_FLUSH_RX 0x56 /* flushes Rx buffer */ -#define C_CM_FLUSH_TX 0x57 /* flushes Tx buffer */ -#define C_CM_Q_ENABLE 0x58 /* enables queue access from the - driver */ -#define C_CM_Q_DISABLE 0x59 /* disables queue access from the - driver */ - -#define C_CM_TXBEMPTY 0x60 /* Tx buffer is empty */ -#define C_CM_TXLOWWM 0x61 /* Tx buffer low water mark */ -#define C_CM_RXHIWM 0x62 /* Rx buffer high water mark */ -#define C_CM_RXNNDT 0x63 /* rx no new data timeout */ -#define C_CM_TXFEMPTY 0x64 -#define C_CM_ICHAR 0x65 -#define C_CM_MDCD 0x70 /* modem DCD change */ -#define C_CM_MDSR 0x71 /* modem DSR change */ -#define C_CM_MRI 0x72 /* modem RI change */ -#define C_CM_MCTS 0x73 /* modem CTS change */ -#define C_CM_MRTS 0x74 /* modem RTS drop */ -#define C_CM_RXBRK 0x84 /* Break received */ -#define C_CM_PR_ERROR 0x85 /* Parity error */ -#define C_CM_FR_ERROR 0x86 /* Frame error */ -#define C_CM_OVR_ERROR 0x87 /* Overrun error */ -#define C_CM_RXOFL 0x88 /* RX buffer overflow */ -#define C_CM_CMDERROR 0x90 /* command error */ -#define C_CM_FATAL 0x91 /* fatal error */ -#define C_CM_HW_RESET 0x92 /* reset board */ - -/* - * CH_CTRL - This per port structure contains all parameters - * that control an specific port. It can be seen as the - * configuration registers of a "super-serial-controller". - */ - -struct CH_CTRL { - __u32 op_mode; /* operation mode */ - __u32 intr_enable; /* interrupt masking */ - __u32 sw_flow; /* SW flow control */ - __u32 flow_status; /* output flow status */ - __u32 comm_baud; /* baud rate - numerically specified */ - __u32 comm_parity; /* parity */ - __u32 comm_data_l; /* data length/stop */ - __u32 comm_flags; /* other flags */ - __u32 hw_flow; /* HW flow control */ - __u32 rs_control; /* RS-232 outputs */ - __u32 rs_status; /* RS-232 inputs */ - __u32 flow_xon; /* xon char */ - __u32 flow_xoff; /* xoff char */ - __u32 hw_overflow; /* hw overflow counter */ - __u32 sw_overflow; /* sw overflow counter */ - __u32 comm_error; /* frame/parity error counter */ - __u32 ichar; - __u32 filler[7]; -}; - - -/* - * BUF_CTRL - This per channel structure contains - * all Tx and Rx buffer control for a given channel. - */ - -struct BUF_CTRL { - __u32 flag_dma; /* buffers are in Host memory */ - __u32 tx_bufaddr; /* address of the tx buffer */ - __u32 tx_bufsize; /* tx buffer size */ - __u32 tx_threshold; /* tx low water mark */ - __u32 tx_get; /* tail index tx buf */ - __u32 tx_put; /* head index tx buf */ - __u32 rx_bufaddr; /* address of the rx buffer */ - __u32 rx_bufsize; /* rx buffer size */ - __u32 rx_threshold; /* rx high water mark */ - __u32 rx_get; /* tail index rx buf */ - __u32 rx_put; /* head index rx buf */ - __u32 filler[5]; /* filler to align structures */ -}; - -/* - * BOARD_CTRL - This per board structure contains all global - * control fields related to the board. - */ - -struct BOARD_CTRL { - - /* static info provided by the on-board CPU */ - __u32 n_channel; /* number of channels */ - __u32 fw_version; /* firmware version */ - - /* static info provided by the driver */ - __u32 op_system; /* op_system id */ - __u32 dr_version; /* driver version */ - - /* board control area */ - __u32 inactivity; /* inactivity control */ - - /* host to FW commands */ - __u32 hcmd_channel; /* channel number */ - __u32 hcmd_param; /* pointer to parameters */ - - /* FW to Host commands */ - __u32 fwcmd_channel; /* channel number */ - __u32 fwcmd_param; /* pointer to parameters */ - __u32 zf_int_queue_addr; /* offset for INT_QUEUE structure */ - - /* filler so the structures are aligned */ - __u32 filler[6]; -}; - -/* Host Interrupt Queue */ - -#define QUEUE_SIZE (10*MAX_CHAN) - -struct INT_QUEUE { - unsigned char intr_code[QUEUE_SIZE]; - unsigned long channel[QUEUE_SIZE]; - unsigned long param[QUEUE_SIZE]; - unsigned long put; - unsigned long get; -}; - -/* - * ZFW_CTRL - This is the data structure that includes all other - * data structures used by the Firmware. - */ - -struct ZFW_CTRL { - struct BOARD_CTRL board_ctrl; - struct CH_CTRL ch_ctrl[MAX_CHAN]; - struct BUF_CTRL buf_ctrl[MAX_CHAN]; -}; - -/****************** ****************** *******************/ -#endif - -#endif /* _UAPI_LINUX_CYCLADES_H */ diff --git a/include/uapi/linux/major.h b/include/uapi/linux/major.h index 7e5fa8e15c43..4e5f2b3a3d54 100644 --- a/include/uapi/linux/major.h +++ b/include/uapi/linux/major.h @@ -34,8 +34,6 @@ #define GOLDSTAR_CDROM_MAJOR 16 #define OPTICS_CDROM_MAJOR 17 #define SANYO_CDROM_MAJOR 18 -#define CYCLADES_MAJOR 19 -#define CYCLADESAUX_MAJOR 20 #define MITSUMI_X_CDROM_MAJOR 20 #define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */ #define SCSI_GENERIC_MAJOR 21 diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h index 93eb3c496ff1..fa6b16e5fdd8 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -52,11 +52,11 @@ struct serial_struct { #define PORT_16450 2 #define PORT_16550 3 #define PORT_16550A 4 -#define PORT_CIRRUS 5 /* usurped by cyclades.c */ +#define PORT_CIRRUS 5 #define PORT_16650 6 #define PORT_16650V2 7 #define PORT_16750 8 -#define PORT_STARTECH 9 /* usurped by cyclades.c */ +#define PORT_STARTECH 9 #define PORT_16C950 10 /* Oxford Semiconductor */ #define PORT_16654 11 #define PORT_16850 12 -- cgit From 67b1544a55c94b62f68488d5fcbc93cca293dc32 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:36 +0100 Subject: tty: isicom, remove this orphan The Isicom driver was orphaned by commit d86b3001a1a6 (MAINTAINERS: orphan isicom) 10 years ago. Noone stepped up to take care of them and to fix all the issues the driver has. So it's time to drop the driver with all its traces. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/devices.txt | 2 +- Documentation/process/magic-number.rst | 1 - .../translations/it_IT/process/magic-number.rst | 1 - .../translations/zh_CN/process/magic-number.rst | 1 - MAINTAINERS | 5 - drivers/tty/Kconfig | 10 - drivers/tty/Makefile | 1 - drivers/tty/isicom.c | 1699 -------------------- include/linux/isicom.h | 85 - 9 files changed, 1 insertion(+), 1804 deletions(-) delete mode 100644 drivers/tty/isicom.c delete mode 100644 include/linux/isicom.h diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt index b5bd9d46e031..ef41f77cb979 100644 --- a/Documentation/admin-guide/devices.txt +++ b/Documentation/admin-guide/devices.txt @@ -289,7 +289,7 @@ 152 = /dev/kpoll Kernel Poll Driver 153 = /dev/mergemem Memory merge device 154 = /dev/pmu Macintosh PowerBook power manager - 155 = /dev/isictl MultiTech ISICom serial control + 155 = 156 = /dev/lcd Front panel LCD display 157 = /dev/ac Applicom Intl Profibus card 158 = /dev/nwbutton Netwinder external button diff --git a/Documentation/process/magic-number.rst b/Documentation/process/magic-number.rst index d4a30c09bd03..c36f21eecefb 100644 --- a/Documentation/process/magic-number.rst +++ b/Documentation/process/magic-number.rst @@ -77,7 +77,6 @@ DB_MAGIC 0x4442 fc_info ``drivers/net/ip DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -ISICOM_MAGIC 0x4d54 isi_port ``include/linux/isicom.h`` PTY_MAGIC 0x5001 ``drivers/char/pty.c`` PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst index 0df2e7e32cd8..440087f9f402 100644 --- a/Documentation/translations/it_IT/process/magic-number.rst +++ b/Documentation/translations/it_IT/process/magic-number.rst @@ -83,7 +83,6 @@ DB_MAGIC 0x4442 fc_info ``drivers/net/ip DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -ISICOM_MAGIC 0x4d54 isi_port ``include/linux/isicom.h`` PTY_MAGIC 0x5001 ``drivers/char/pty.c`` PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 82d62f6a4406..e91bec4ec156 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -66,7 +66,6 @@ DB_MAGIC 0x4442 fc_info ``drivers/net/ip DL_MAGIC 0x444d fc_info ``drivers/net/iph5526_novram.c`` FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h`` FF_MAGIC 0x4646 fc_info ``drivers/net/iph5526_novram.c`` -ISICOM_MAGIC 0x4d54 isi_port ``include/linux/isicom.h`` PTY_MAGIC 0x5001 ``drivers/char/pty.c`` PPP_MAGIC 0x5002 ppp ``include/linux/if_pppvar.h`` SSTATE_MAGIC 0x5302 serial_state ``include/linux/serial.h`` diff --git a/MAINTAINERS b/MAINTAINERS index 29f20a97d73d..f62df0494d11 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12224,11 +12224,6 @@ F: drivers/mux/ F: include/dt-bindings/mux/ F: include/linux/mux/ -MULTITECH MULTIPORT CARD (ISICOM) -S: Orphan -F: drivers/tty/isicom.c -F: include/linux/isicom.h - MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER M: Bin Liu L: linux-usb@vger.kernel.org diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 397523a8095e..0031aa8f8b16 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -238,16 +238,6 @@ config SYNCLINK_GT synchronous and asynchronous serial adapters manufactured by Microgate Systems, Ltd. (www.microgate.com) -config ISI - tristate "Multi-Tech multiport card support" - depends on SERIAL_NONSTANDARD && PCI - select FW_LOADER - help - This is a driver for the Multi-Tech cards which provide several - serial ports. The driver is experimental and can currently only be - built as a module. The module will be called isicom. - If you want to do that, choose M here. - config N_HDLC tristate "HDLC line discipline support" depends on SERIAL_NONSTANDARD diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 94eb2bf75763..a34055bc8b7a 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_SERIAL_DEV_BUS) += serdev/ # tty drivers obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o -obj-$(CONFIG_ISI) += isicom.o obj-$(CONFIG_MOXA_INTELLIO) += moxa.o obj-$(CONFIG_MOXA_SMARTIO) += mxser.o obj-$(CONFIG_NOZOMI) += nozomi.o diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c deleted file mode 100644 index 3b2f9fb01aa0..000000000000 --- a/drivers/tty/isicom.c +++ /dev/null @@ -1,1699 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Original driver code supplied by Multi-Tech - * - * Changes - * 1/9/98 alan@lxorguk.ukuu.org.uk - * Merge to 2.0.x kernel tree - * Obtain and use official major/minors - * Loader switched to a misc device - * (fixed range check bug as a side effect) - * Printk clean up - * 9/12/98 alan@lxorguk.ukuu.org.uk - * Rough port to 2.1.x - * - * 10/6/99 sameer Merged the ISA and PCI drivers to - * a new unified driver. - * - * 3/9/99 sameer Added support for ISI4616 cards. - * - * 16/9/99 sameer We do not force RTS low anymore. - * This is to prevent the firmware - * from getting confused. - * - * 26/10/99 sameer Cosmetic changes:The driver now - * dumps the Port Count information - * along with I/O address and IRQ. - * - * 13/12/99 sameer Fixed the problem with IRQ sharing. - * - * 10/5/00 sameer Fixed isicom_shutdown_board() - * to not lower DTR on all the ports - * when the last port on the card is - * closed. - * - * 10/5/00 sameer Signal mask setup command added - * to isicom_setup_port and - * isicom_shutdown_port. - * - * 24/5/00 sameer The driver is now SMP aware. - * - * - * 27/11/00 Vinayak P Risbud Fixed the Driver Crash Problem - * - * - * 03/01/01 anil .s Added support for resetting the - * internal modems on ISI cards. - * - * 08/02/01 anil .s Upgraded the driver for kernel - * 2.4.x - * - * 11/04/01 Kevin Fixed firmware load problem with - * ISIHP-4X card - * - * 30/04/01 anil .s Fixed the remote login through - * ISI port problem. Now the link - * does not go down before password - * prompt. - * - * 03/05/01 anil .s Fixed the problem with IRQ sharing - * among ISI-PCI cards. - * - * 03/05/01 anil .s Added support to display the version - * info during insmod as well as module - * listing by lsmod. - * - * 10/05/01 anil .s Done the modifications to the source - * file and Install script so that the - * same installation can be used for - * 2.2.x and 2.4.x kernel. - * - * 06/06/01 anil .s Now we drop both dtr and rts during - * shutdown_port as well as raise them - * during isicom_config_port. - * - * 09/06/01 acme@conectiva.com.br use capable, not suser, do - * restore_flags on failure in - * isicom_send_break, verify put_user - * result - * - * 11/02/03 ranjeeth Added support for 230 Kbps and 460 Kbps - * Baud index extended to 21 - * - * 20/03/03 ranjeeth Made to work for Linux Advanced server. - * Taken care of license warning. - * - * 10/12/03 Ravindra Made to work for Fedora Core 1 of - * Red Hat Distribution - * - * 06/01/05 Alan Cox Merged the ISI and base kernel strands - * into a single 2.6 driver - * - * *********************************************************** - * - * To use this driver you also need the support package. You - * can find this in RPM format on - * ftp://ftp.linux.org.uk/pub/linux/alan - * - * You can find the original tools for this direct from Multitech - * ftp://ftp.multitech.com/ISI-Cards/ - * - * Having installed the cards the module options (/etc/modprobe.d/) - * - * options isicom io=card1,card2,card3,card4 irq=card1,card2,card3,card4 - * - * Omit those entries for boards you don't have installed. - * - * TODO - * Merge testing - * 64-bit verification - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#define InterruptTheCard(base) outw(0, (base) + 0xc) -#define ClearInterrupt(base) inw((base) + 0x0a) - -#ifdef DEBUG -#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c)) -#else -#define isicom_paranoia_check(a, b, c) 0 -#endif - -static int isicom_probe(struct pci_dev *, const struct pci_device_id *); -static void isicom_remove(struct pci_dev *); - -static const struct pci_device_id isicom_pci_tbl[] = { - { PCI_DEVICE(VENDOR_ID, 0x2028) }, - { PCI_DEVICE(VENDOR_ID, 0x2051) }, - { PCI_DEVICE(VENDOR_ID, 0x2052) }, - { PCI_DEVICE(VENDOR_ID, 0x2053) }, - { PCI_DEVICE(VENDOR_ID, 0x2054) }, - { PCI_DEVICE(VENDOR_ID, 0x2055) }, - { PCI_DEVICE(VENDOR_ID, 0x2056) }, - { PCI_DEVICE(VENDOR_ID, 0x2057) }, - { PCI_DEVICE(VENDOR_ID, 0x2058) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, isicom_pci_tbl); - -static struct pci_driver isicom_driver = { - .name = "isicom", - .id_table = isicom_pci_tbl, - .probe = isicom_probe, - .remove = isicom_remove -}; - -static int prev_card = 3; /* start servicing isi_card[0] */ -static struct tty_driver *isicom_normal; - -static void isicom_tx(struct timer_list *unused); -static void isicom_start(struct tty_struct *tty); - -static DEFINE_TIMER(tx, isicom_tx); - -/* baud index mappings from linux defns to isi */ - -static signed char linuxb_to_isib[] = { - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21 -}; - -struct isi_board { - unsigned long base; - int irq; - unsigned char port_count; - unsigned short status; - unsigned short port_status; /* each bit for each port */ - unsigned short shift_count; - struct isi_port *ports; - signed char count; - spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */ - unsigned long flags; - unsigned int index; -}; - -struct isi_port { - unsigned short magic; - struct tty_port port; - u16 channel; - u16 status; - struct isi_board *card; - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; -}; - -static struct isi_board isi_card[BOARD_COUNT]; -static struct isi_port isi_ports[PORT_COUNT]; - -/* - * Locking functions for card level locking. We need to own both - * the kernel lock for the card and have the card in a position that - * it wants to talk. - */ - -static int WaitTillCardIsFree(unsigned long base) -{ - unsigned int count = 0; - - while (!(inw(base + 0xe) & 0x1) && count++ < 100) - mdelay(1); - - return !(inw(base + 0xe) & 0x1); -} - -static int lock_card(struct isi_board *card) -{ - unsigned long base = card->base; - unsigned int retries, a; - - for (retries = 0; retries < 10; retries++) { - spin_lock_irqsave(&card->card_lock, card->flags); - for (a = 0; a < 10; a++) { - if (inw(base + 0xe) & 0x1) - return 1; - udelay(10); - } - spin_unlock_irqrestore(&card->card_lock, card->flags); - msleep(10); - } - pr_warn("Failed to lock Card (0x%lx)\n", card->base); - - return 0; /* Failed to acquire the card! */ -} - -static void unlock_card(struct isi_board *card) -{ - spin_unlock_irqrestore(&card->card_lock, card->flags); -} - -/* - * ISI Card specific ops ... - */ - -/* card->lock HAS to be held */ -static void raise_dtr(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0504, base); - InterruptTheCard(base); - port->status |= ISI_DTR; -} - -/* card->lock HAS to be held */ -static void drop_dtr(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0404, base); - InterruptTheCard(base); - port->status &= ~ISI_DTR; -} - -/* card->lock HAS to be held */ -static inline void raise_rts(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0a04, base); - InterruptTheCard(base); - port->status |= ISI_RTS; -} - -/* card->lock HAS to be held */ -static inline void drop_rts(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0804, base); - InterruptTheCard(base); - port->status &= ~ISI_RTS; -} - -/* card->lock MUST NOT be held */ - -static void isicom_dtr_rts(struct tty_port *port, int on) -{ - struct isi_port *ip = container_of(port, struct isi_port, port); - struct isi_board *card = ip->card; - unsigned long base = card->base; - u16 channel = ip->channel; - - if (!lock_card(card)) - return; - - if (on) { - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0f04, base); - InterruptTheCard(base); - ip->status |= (ISI_DTR | ISI_RTS); - } else { - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0C04, base); - InterruptTheCard(base); - ip->status &= ~(ISI_DTR | ISI_RTS); - } - unlock_card(card); -} - -/* card->lock HAS to be held */ -static void drop_dtr_rts(struct isi_port *port) -{ - struct isi_board *card = port->card; - unsigned long base = card->base; - u16 channel = port->channel; - - if (WaitTillCardIsFree(base)) - return; - - outw(0x8000 | (channel << card->shift_count) | 0x02, base); - outw(0x0c04, base); - InterruptTheCard(base); - port->status &= ~(ISI_RTS | ISI_DTR); -} - -/* - * ISICOM Driver specific routines ... - * - */ - -static inline int __isicom_paranoia_check(struct isi_port const *port, - char *name, const char *routine) -{ - if (!port) { - pr_warn("Warning: bad isicom magic for dev %s in %s\n", - name, routine); - return 1; - } - if (port->magic != ISICOM_MAGIC) { - pr_warn("Warning: NULL isicom port for dev %s in %s\n", - name, routine); - return 1; - } - - return 0; -} - -/* - * Transmitter. - * - * We shovel data into the card buffers on a regular basis. The card - * will do the rest of the work for us. - */ - -static void isicom_tx(struct timer_list *unused) -{ - unsigned long flags, base; - unsigned int retries; - short count = (BOARD_COUNT-1), card; - short txcount, wrd, residue, word_count, cnt; - struct isi_port *port; - struct tty_struct *tty; - - /* find next active board */ - card = (prev_card + 1) & 0x0003; - while (count-- > 0) { - if (isi_card[card].status & BOARD_ACTIVE) - break; - card = (card + 1) & 0x0003; - } - if (!(isi_card[card].status & BOARD_ACTIVE)) - goto sched_again; - - prev_card = card; - - count = isi_card[card].port_count; - port = isi_card[card].ports; - base = isi_card[card].base; - - spin_lock_irqsave(&isi_card[card].card_lock, flags); - for (retries = 0; retries < 100; retries++) { - if (inw(base + 0xe) & 0x1) - break; - udelay(2); - } - if (retries >= 100) - goto unlock; - - tty = tty_port_tty_get(&port->port); - if (tty == NULL) - goto put_unlock; - - for (; count > 0; count--, port++) { - /* port not active or tx disabled to force flow control */ - if (!tty_port_initialized(&port->port) || - !(port->status & ISI_TXOK)) - continue; - - txcount = min_t(short, TX_SIZE, port->xmit_cnt); - if (txcount <= 0 || tty->stopped || tty->hw_stopped) - continue; - - if (!(inw(base + 0x02) & (1 << port->channel))) - continue; - - pr_debug("txing %d bytes, port%d.\n", - txcount, port->channel + 1); - outw((port->channel << isi_card[card].shift_count) | txcount, - base); - residue = NO; - wrd = 0; - while (1) { - cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE - - port->xmit_tail)); - if (residue == YES) { - residue = NO; - if (cnt > 0) { - wrd |= (port->port.xmit_buf[port->xmit_tail] - << 8); - port->xmit_tail = (port->xmit_tail + 1) - & (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt--; - txcount--; - cnt--; - outw(wrd, base); - } else { - outw(wrd, base); - break; - } - } - if (cnt <= 0) - break; - word_count = cnt >> 1; - outsw(base, port->port.xmit_buf+port->xmit_tail, word_count); - port->xmit_tail = (port->xmit_tail - + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1); - txcount -= (word_count << 1); - port->xmit_cnt -= (word_count << 1); - if (cnt & 0x0001) { - residue = YES; - wrd = port->port.xmit_buf[port->xmit_tail]; - port->xmit_tail = (port->xmit_tail + 1) - & (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt--; - txcount--; - } - } - - InterruptTheCard(base); - if (port->xmit_cnt <= 0) - port->status &= ~ISI_TXOK; - if (port->xmit_cnt <= WAKEUP_CHARS) - tty_wakeup(tty); - } - -put_unlock: - tty_kref_put(tty); -unlock: - spin_unlock_irqrestore(&isi_card[card].card_lock, flags); - /* schedule another tx for hopefully in about 10ms */ -sched_again: - mod_timer(&tx, jiffies + msecs_to_jiffies(10)); -} - -/* - * Main interrupt handler routine - */ - -static irqreturn_t isicom_interrupt(int irq, void *dev_id) -{ - struct isi_board *card = dev_id; - struct isi_port *port; - struct tty_struct *tty; - unsigned long base; - u16 header, word_count, count, channel; - short byte_count; - unsigned char *rp; - - if (!card || !(card->status & FIRMWARE_LOADED)) - return IRQ_NONE; - - base = card->base; - - /* did the card interrupt us? */ - if (!(inw(base + 0x0e) & 0x02)) - return IRQ_NONE; - - spin_lock(&card->card_lock); - - /* - * disable any interrupts from the PCI card and lower the - * interrupt line - */ - outw(0x8000, base+0x04); - ClearInterrupt(base); - - inw(base); /* get the dummy word out */ - header = inw(base); - channel = (header & 0x7800) >> card->shift_count; - byte_count = header & 0xff; - - if (channel + 1 > card->port_count) { - pr_warn("%s(0x%lx): %d(channel) > port_count\n", - __func__, base, channel + 1); - outw(0x0000, base+0x04); /* enable interrupts */ - spin_unlock(&card->card_lock); - return IRQ_HANDLED; - } - port = card->ports + channel; - if (!tty_port_initialized(&port->port)) { - outw(0x0000, base+0x04); /* enable interrupts */ - spin_unlock(&card->card_lock); - return IRQ_HANDLED; - } - - tty = tty_port_tty_get(&port->port); - if (tty == NULL) { - while (byte_count > 1) { - inw(base); - byte_count -= 2; - } - if (byte_count & 0x01) - inw(base); - outw(0x0000, base+0x04); /* enable interrupts */ - spin_unlock(&card->card_lock); - return IRQ_HANDLED; - } - - if (header & 0x8000) { /* Status Packet */ - header = inw(base); - switch (header & 0xff) { - case 0: /* Change in EIA signals */ - if (tty_port_check_carrier(&port->port)) { - if (port->status & ISI_DCD) { - if (!(header & ISI_DCD)) { - /* Carrier has been lost */ - pr_debug("%s: DCD->low.\n", - __func__); - port->status &= ~ISI_DCD; - tty_hangup(tty); - } - } else if (header & ISI_DCD) { - /* Carrier has been detected */ - pr_debug("%s: DCD->high.\n", - __func__); - port->status |= ISI_DCD; - wake_up_interruptible(&port->port.open_wait); - } - } else { - if (header & ISI_DCD) - port->status |= ISI_DCD; - else - port->status &= ~ISI_DCD; - } - - if (tty_port_cts_enabled(&port->port)) { - if (tty->hw_stopped) { - if (header & ISI_CTS) { - tty->hw_stopped = 0; - /* start tx ing */ - port->status |= (ISI_TXOK - | ISI_CTS); - tty_wakeup(tty); - } - } else if (!(header & ISI_CTS)) { - tty->hw_stopped = 1; - /* stop tx ing */ - port->status &= ~(ISI_TXOK | ISI_CTS); - } - } else { - if (header & ISI_CTS) - port->status |= ISI_CTS; - else - port->status &= ~ISI_CTS; - } - - if (header & ISI_DSR) - port->status |= ISI_DSR; - else - port->status &= ~ISI_DSR; - - if (header & ISI_RI) - port->status |= ISI_RI; - else - port->status &= ~ISI_RI; - - break; - - case 1: /* Received Break !!! */ - tty_insert_flip_char(&port->port, 0, TTY_BREAK); - if (port->port.flags & ASYNC_SAK) - do_SAK(tty); - tty_flip_buffer_push(&port->port); - break; - - case 2: /* Statistics */ - pr_debug("%s: stats!!!\n", __func__); - break; - - default: - pr_debug("%s: Unknown code in status packet.\n", - __func__); - break; - } - } else { /* Data Packet */ - count = tty_prepare_flip_string(&port->port, &rp, - byte_count & ~1); - pr_debug("%s: Can rx %d of %d bytes.\n", - __func__, count, byte_count); - word_count = count >> 1; - insw(base, rp, word_count); - byte_count -= (word_count << 1); - if (count & 0x0001) { - tty_insert_flip_char(&port->port, inw(base) & 0xff, - TTY_NORMAL); - byte_count -= 2; - } - if (byte_count > 0) { - pr_debug("%s(0x%lx:%d): Flip buffer overflow! dropping bytes...\n", - __func__, base, channel + 1); - /* drain out unread xtra data */ - while (byte_count > 0) { - inw(base); - byte_count -= 2; - } - } - tty_flip_buffer_push(&port->port); - } - outw(0x0000, base+0x04); /* enable interrupts */ - spin_unlock(&card->card_lock); - tty_kref_put(tty); - - return IRQ_HANDLED; -} - -static void isicom_config_port(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long baud; - unsigned long base = card->base; - u16 channel_setup, channel = port->channel, - shift_count = card->shift_count; - unsigned char flow_ctrl; - - /* FIXME: Switch to new tty baud API */ - baud = C_BAUD(tty); - if (baud & CBAUDEX) { - baud &= ~CBAUDEX; - - /* if CBAUDEX bit is on and the baud is set to either 50 or 75 - * then the card is programmed for 57.6Kbps or 115Kbps - * respectively. - */ - - /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ - if (baud < 1 || baud > 4) - tty->termios.c_cflag &= ~CBAUDEX; - else - baud += 15; - } - if (baud == 15) { - - /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set - * by the set_serial_info ioctl ... this is done by - * the 'setserial' utility. - */ - - if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - baud++; /* 57.6 Kbps */ - if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baud += 2; /* 115 Kbps */ - if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - baud += 3; /* 230 kbps*/ - if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - baud += 4; /* 460 kbps*/ - } - if (linuxb_to_isib[baud] == -1) { - /* hang up */ - drop_dtr(port); - return; - } else - raise_dtr(port); - - if (WaitTillCardIsFree(base) == 0) { - outw(0x8000 | (channel << shift_count) | 0x03, base); - outw(linuxb_to_isib[baud] << 8 | 0x03, base); - channel_setup = 0; - switch (C_CSIZE(tty)) { - case CS5: - channel_setup |= ISICOM_CS5; - break; - case CS6: - channel_setup |= ISICOM_CS6; - break; - case CS7: - channel_setup |= ISICOM_CS7; - break; - case CS8: - channel_setup |= ISICOM_CS8; - break; - } - - if (C_CSTOPB(tty)) - channel_setup |= ISICOM_2SB; - if (C_PARENB(tty)) { - channel_setup |= ISICOM_EVPAR; - if (C_PARODD(tty)) - channel_setup |= ISICOM_ODPAR; - } - outw(channel_setup, base); - InterruptTheCard(base); - } - tty_port_set_check_carrier(&port->port, !C_CLOCAL(tty)); - - /* flow control settings ...*/ - flow_ctrl = 0; - tty_port_set_cts_flow(&port->port, C_CRTSCTS(tty)); - if (C_CRTSCTS(tty)) - flow_ctrl |= ISICOM_CTSRTS; - if (I_IXON(tty)) - flow_ctrl |= ISICOM_RESPOND_XONXOFF; - if (I_IXOFF(tty)) - flow_ctrl |= ISICOM_INITIATE_XONXOFF; - - if (WaitTillCardIsFree(base) == 0) { - outw(0x8000 | (channel << shift_count) | 0x04, base); - outw(flow_ctrl << 8 | 0x05, base); - outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); - InterruptTheCard(base); - } - - /* rx enabled -> enable port for rx on the card */ - if (C_CREAD(tty)) { - card->port_status |= (1 << channel); - outw(card->port_status, base + 0x02); - } -} - -/* open et all */ - -static inline void isicom_setup_board(struct isi_board *bp) -{ - int channel; - struct isi_port *port; - - bp->count++; - if (!(bp->status & BOARD_INIT)) { - port = bp->ports; - for (channel = 0; channel < bp->port_count; channel++, port++) - drop_dtr_rts(port); - } - bp->status |= BOARD_ACTIVE | BOARD_INIT; -} - -/* Activate and thus setup board are protected from races against shutdown - by the tty_port mutex */ - -static int isicom_activate(struct tty_port *tport, struct tty_struct *tty) -{ - struct isi_port *port = container_of(tport, struct isi_port, port); - struct isi_board *card = port->card; - unsigned long flags; - - if (tty_port_alloc_xmit_buf(tport) < 0) - return -ENOMEM; - - spin_lock_irqsave(&card->card_lock, flags); - isicom_setup_board(card); - - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - - /* discard any residual data */ - if (WaitTillCardIsFree(card->base) == 0) { - outw(0x8000 | (port->channel << card->shift_count) | 0x02, - card->base); - outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base); - InterruptTheCard(card->base); - } - isicom_config_port(tty); - spin_unlock_irqrestore(&card->card_lock, flags); - - return 0; -} - -static int isicom_carrier_raised(struct tty_port *port) -{ - struct isi_port *ip = container_of(port, struct isi_port, port); - return (ip->status & ISI_DCD)?1 : 0; -} - -static struct tty_port *isicom_find_port(struct tty_struct *tty) -{ - struct isi_port *port; - struct isi_board *card; - unsigned int board; - int line = tty->index; - - board = BOARD(line); - card = &isi_card[board]; - - if (!(card->status & FIRMWARE_LOADED)) - return NULL; - - /* open on a port greater than the port count for the card !!! */ - if (line > ((board * 16) + card->port_count - 1)) - return NULL; - - port = &isi_ports[line]; - if (isicom_paranoia_check(port, tty->name, "isicom_open")) - return NULL; - - return &port->port; -} - -static int isicom_open(struct tty_struct *tty, struct file *filp) -{ - struct isi_port *port; - struct tty_port *tport; - - tport = isicom_find_port(tty); - if (tport == NULL) - return -ENODEV; - port = container_of(tport, struct isi_port, port); - - tty->driver_data = port; - return tty_port_open(tport, tty, filp); -} - -/* close et all */ - -/* card->lock HAS to be held */ -static void isicom_shutdown_port(struct isi_port *port) -{ - struct isi_board *card = port->card; - - if (--card->count < 0) { - pr_debug("%s: bad board(0x%lx) count %d.\n", - __func__, card->base, card->count); - card->count = 0; - } - /* last port was closed, shutdown that board too */ - if (!card->count) - card->status &= BOARD_ACTIVE; -} - -static void isicom_flush_buffer(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long flags; - - if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer")) - return; - - spin_lock_irqsave(&card->card_lock, flags); - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - spin_unlock_irqrestore(&card->card_lock, flags); - - tty_wakeup(tty); -} - -static void isicom_shutdown(struct tty_port *port) -{ - struct isi_port *ip = container_of(port, struct isi_port, port); - struct isi_board *card = ip->card; - unsigned long flags; - - /* indicate to the card that no more data can be received - on this port */ - spin_lock_irqsave(&card->card_lock, flags); - card->port_status &= ~(1 << ip->channel); - outw(card->port_status, card->base + 0x02); - isicom_shutdown_port(ip); - spin_unlock_irqrestore(&card->card_lock, flags); - tty_port_free_xmit_buf(port); -} - -static void isicom_close(struct tty_struct *tty, struct file *filp) -{ - struct isi_port *ip = tty->driver_data; - struct tty_port *port; - - if (ip == NULL) - return; - - port = &ip->port; - if (isicom_paranoia_check(ip, tty->name, "isicom_close")) - return; - tty_port_close(port, tty, filp); -} - -/* write et all */ -static int isicom_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long flags; - int cnt, total = 0; - - if (isicom_paranoia_check(port, tty->name, "isicom_write")) - return 0; - - spin_lock_irqsave(&card->card_lock, flags); - - while (1) { - cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - - 1, SERIAL_XMIT_SIZE - port->xmit_head)); - if (cnt <= 0) - break; - - memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt); - port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - - 1); - port->xmit_cnt += cnt; - buf += cnt; - count -= cnt; - total += cnt; - } - if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped) - port->status |= ISI_TXOK; - spin_unlock_irqrestore(&card->card_lock, flags); - return total; -} - -/* put_char et all */ -static int isicom_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long flags; - - if (isicom_paranoia_check(port, tty->name, "isicom_put_char")) - return 0; - - spin_lock_irqsave(&card->card_lock, flags); - if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { - spin_unlock_irqrestore(&card->card_lock, flags); - return 0; - } - - port->port.xmit_buf[port->xmit_head++] = ch; - port->xmit_head &= (SERIAL_XMIT_SIZE - 1); - port->xmit_cnt++; - spin_unlock_irqrestore(&card->card_lock, flags); - return 1; -} - -/* flush_chars et all */ -static void isicom_flush_chars(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars")) - return; - - if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !port->port.xmit_buf) - return; - - /* this tells the transmitter to consider this port for - data output to the card ... that's the best we can do. */ - port->status |= ISI_TXOK; -} - -/* write_room et all */ -static int isicom_write_room(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - int free; - - if (isicom_paranoia_check(port, tty->name, "isicom_write_room")) - return 0; - - free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; - if (free < 0) - free = 0; - return free; -} - -/* chars_in_buffer et all */ -static int isicom_chars_in_buffer(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer")) - return 0; - return port->xmit_cnt; -} - -/* ioctl et all */ -static int isicom_send_break(struct tty_struct *tty, int length) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long base = card->base; - - if (length == -1) - return -EOPNOTSUPP; - - if (!lock_card(card)) - return -EINVAL; - - outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); - outw((length & 0xff) << 8 | 0x00, base); - outw((length & 0xff00u), base); - InterruptTheCard(base); - - unlock_card(card); - return 0; -} - -static int isicom_tiocmget(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - /* just send the port status */ - u16 status = port->status; - - if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) - return -ENODEV; - - return ((status & ISI_RTS) ? TIOCM_RTS : 0) | - ((status & ISI_DTR) ? TIOCM_DTR : 0) | - ((status & ISI_DCD) ? TIOCM_CAR : 0) | - ((status & ISI_DSR) ? TIOCM_DSR : 0) | - ((status & ISI_CTS) ? TIOCM_CTS : 0) | - ((status & ISI_RI ) ? TIOCM_RI : 0); -} - -static int isicom_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct isi_port *port = tty->driver_data; - unsigned long flags; - - if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) - return -ENODEV; - - spin_lock_irqsave(&port->card->card_lock, flags); - if (set & TIOCM_RTS) - raise_rts(port); - if (set & TIOCM_DTR) - raise_dtr(port); - - if (clear & TIOCM_RTS) - drop_rts(port); - if (clear & TIOCM_DTR) - drop_dtr(port); - spin_unlock_irqrestore(&port->card->card_lock, flags); - - return 0; -} - -static int isicom_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct isi_port *port = tty->driver_data; - int reconfig_port; - - if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) - return -ENODEV; - - mutex_lock(&port->port.mutex); - reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) != - (ss->flags & ASYNC_SPD_MASK)); - - if (!capable(CAP_SYS_ADMIN)) { - if ((ss->close_delay != port->port.close_delay) || - (ss->closing_wait != port->port.closing_wait) || - ((ss->flags & ~ASYNC_USR_MASK) != - (port->port.flags & ~ASYNC_USR_MASK))) { - mutex_unlock(&port->port.mutex); - return -EPERM; - } - port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | - (ss->flags & ASYNC_USR_MASK)); - } else { - port->port.close_delay = ss->close_delay; - port->port.closing_wait = ss->closing_wait; - port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) | - (ss->flags & ASYNC_FLAGS)); - } - if (reconfig_port) { - unsigned long flags; - spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(tty); - spin_unlock_irqrestore(&port->card->card_lock, flags); - } - mutex_unlock(&port->port.mutex); - return 0; -} - -static int isicom_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) - return -ENODEV; - - mutex_lock(&port->port.mutex); -/* ss->type = ? */ - ss->line = port - isi_ports; - ss->port = port->card->base; - ss->irq = port->card->irq; - ss->flags = port->port.flags; -/* ss->baud_base = ? */ - ss->close_delay = port->port.close_delay; - ss->closing_wait = port->port.closing_wait; - mutex_unlock(&port->port.mutex); - return 0; -} - -/* set_termios et all */ -static void isicom_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - struct isi_port *port = tty->driver_data; - unsigned long flags; - - if (isicom_paranoia_check(port, tty->name, "isicom_set_termios")) - return; - - if (tty->termios.c_cflag == old_termios->c_cflag && - tty->termios.c_iflag == old_termios->c_iflag) - return; - - spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(tty); - spin_unlock_irqrestore(&port->card->card_lock, flags); - - if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) { - tty->hw_stopped = 0; - isicom_start(tty); - } -} - -/* throttle et all */ -static void isicom_throttle(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - - if (isicom_paranoia_check(port, tty->name, "isicom_throttle")) - return; - - /* tell the card that this port cannot handle any more data for now */ - card->port_status &= ~(1 << port->channel); - outw(card->port_status, card->base + 0x02); -} - -/* unthrottle et all */ -static void isicom_unthrottle(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - - if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle")) - return; - - /* tell the card that this port is ready to accept more data */ - card->port_status |= (1 << port->channel); - outw(card->port_status, card->base + 0x02); -} - -/* stop et all */ -static void isicom_stop(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_stop")) - return; - - /* this tells the transmitter not to consider this port for - data output to the card. */ - port->status &= ~ISI_TXOK; -} - -/* start et all */ -static void isicom_start(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_start")) - return; - - /* this tells the transmitter to consider this port for - data output to the card. */ - port->status |= ISI_TXOK; -} - -static void isicom_hangup(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - - if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) - return; - tty_port_hangup(&port->port); -} - - -/* - * Driver init and deinit functions - */ - -static const struct tty_operations isicom_ops = { - .open = isicom_open, - .close = isicom_close, - .write = isicom_write, - .put_char = isicom_put_char, - .flush_chars = isicom_flush_chars, - .write_room = isicom_write_room, - .chars_in_buffer = isicom_chars_in_buffer, - .set_termios = isicom_set_termios, - .throttle = isicom_throttle, - .unthrottle = isicom_unthrottle, - .stop = isicom_stop, - .start = isicom_start, - .hangup = isicom_hangup, - .flush_buffer = isicom_flush_buffer, - .tiocmget = isicom_tiocmget, - .tiocmset = isicom_tiocmset, - .break_ctl = isicom_send_break, - .get_serial = isicom_get_serial_info, - .set_serial = isicom_set_serial_info, -}; - -static const struct tty_port_operations isicom_port_ops = { - .carrier_raised = isicom_carrier_raised, - .dtr_rts = isicom_dtr_rts, - .activate = isicom_activate, - .shutdown = isicom_shutdown, -}; - -static int reset_card(struct pci_dev *pdev, - const unsigned int card, unsigned int *signature) -{ - struct isi_board *board = pci_get_drvdata(pdev); - unsigned long base = board->base; - unsigned int sig, portcount = 0; - int retval = 0; - - dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1, - base); - - inw(base + 0x8); - - msleep(10); - - outw(0, base + 0x8); /* Reset */ - - msleep(1000); - - sig = inw(base + 0x4) & 0xff; - - if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd && - sig != 0xee) { - dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible " - "bad I/O Port Address 0x%lx).\n", card + 1, base); - dev_dbg(&pdev->dev, "Sig=0x%x\n", sig); - retval = -EIO; - goto end; - } - - msleep(10); - - portcount = inw(base + 0x2); - if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 && - portcount != 8 && portcount != 16)) { - dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n", - card + 1); - retval = -EIO; - goto end; - } - - switch (sig) { - case 0xa5: - case 0xbb: - case 0xdd: - board->port_count = (portcount == 4) ? 4 : 8; - board->shift_count = 12; - break; - case 0xcc: - case 0xee: - board->port_count = 16; - board->shift_count = 11; - break; - } - dev_info(&pdev->dev, "-Done\n"); - *signature = sig; - -end: - return retval; -} - -static int load_firmware(struct pci_dev *pdev, - const unsigned int index, const unsigned int signature) -{ - struct isi_board *board = pci_get_drvdata(pdev); - const struct firmware *fw; - unsigned long base = board->base; - unsigned int a; - u16 word_count, status; - int retval = -EIO; - char *name; - u8 *data; - - struct stframe { - u16 addr; - u16 count; - u8 data[0]; - } *frame; - - switch (signature) { - case 0xa5: - name = "isi608.bin"; - break; - case 0xbb: - name = "isi608em.bin"; - break; - case 0xcc: - name = "isi616em.bin"; - break; - case 0xdd: - name = "isi4608.bin"; - break; - case 0xee: - name = "isi4616.bin"; - break; - default: - dev_err(&pdev->dev, "Unknown signature.\n"); - goto end; - } - - retval = request_firmware(&fw, name, &pdev->dev); - if (retval) - goto end; - - retval = -EIO; - - for (frame = (struct stframe *)fw->data; - frame < (struct stframe *)(fw->data + fw->size); - frame = (struct stframe *)((u8 *)(frame + 1) + - frame->count)) { - if (WaitTillCardIsFree(base)) - goto errrelfw; - - outw(0xf0, base); /* start upload sequence */ - outw(0x00, base); - outw(frame->addr, base); /* lsb of address */ - - word_count = frame->count / 2 + frame->count % 2; - outw(word_count, base); - InterruptTheCard(base); - - udelay(100); /* 0x2f */ - - if (WaitTillCardIsFree(base)) - goto errrelfw; - - status = inw(base + 0x4); - if (status != 0) { - dev_warn(&pdev->dev, "Card%d rejected load header:\n" - "Address:0x%x\n" - "Count:0x%x\n" - "Status:0x%x\n", - index + 1, frame->addr, frame->count, status); - goto errrelfw; - } - outsw(base, frame->data, word_count); - - InterruptTheCard(base); - - udelay(50); /* 0x0f */ - - if (WaitTillCardIsFree(base)) - goto errrelfw; - - status = inw(base + 0x4); - if (status != 0) { - dev_err(&pdev->dev, "Card%d got out of sync.Card " - "Status:0x%x\n", index + 1, status); - goto errrelfw; - } - } - -/* XXX: should we test it by reading it back and comparing with original like - * in load firmware package? */ - for (frame = (struct stframe *)fw->data; - frame < (struct stframe *)(fw->data + fw->size); - frame = (struct stframe *)((u8 *)(frame + 1) + - frame->count)) { - if (WaitTillCardIsFree(base)) - goto errrelfw; - - outw(0xf1, base); /* start download sequence */ - outw(0x00, base); - outw(frame->addr, base); /* lsb of address */ - - word_count = (frame->count >> 1) + frame->count % 2; - outw(word_count + 1, base); - InterruptTheCard(base); - - udelay(50); /* 0xf */ - - if (WaitTillCardIsFree(base)) - goto errrelfw; - - status = inw(base + 0x4); - if (status != 0) { - dev_warn(&pdev->dev, "Card%d rejected verify header:\n" - "Address:0x%x\n" - "Count:0x%x\n" - "Status: 0x%x\n", - index + 1, frame->addr, frame->count, status); - goto errrelfw; - } - - data = kmalloc_array(word_count, 2, GFP_KERNEL); - if (data == NULL) { - dev_err(&pdev->dev, "Card%d, firmware upload " - "failed, not enough memory\n", index + 1); - goto errrelfw; - } - inw(base); - insw(base, data, word_count); - InterruptTheCard(base); - - for (a = 0; a < frame->count; a++) - if (data[a] != frame->data[a]) { - kfree(data); - dev_err(&pdev->dev, "Card%d, firmware upload " - "failed\n", index + 1); - goto errrelfw; - } - kfree(data); - - udelay(50); /* 0xf */ - - if (WaitTillCardIsFree(base)) - goto errrelfw; - - status = inw(base + 0x4); - if (status != 0) { - dev_err(&pdev->dev, "Card%d verify got out of sync. " - "Card Status:0x%x\n", index + 1, status); - goto errrelfw; - } - } - - /* xfer ctrl */ - if (WaitTillCardIsFree(base)) - goto errrelfw; - - outw(0xf2, base); - outw(0x800, base); - outw(0x0, base); - outw(0x0, base); - InterruptTheCard(base); - outw(0x0, base + 0x4); /* for ISI4608 cards */ - - board->status |= FIRMWARE_LOADED; - retval = 0; - -errrelfw: - release_firmware(fw); -end: - return retval; -} - -/* - * Insmod can set static symbols so keep these static - */ -static unsigned int card_count; - -static int isicom_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - unsigned int signature, index; - int retval = -EPERM; - struct isi_board *board = NULL; - - if (card_count >= BOARD_COUNT) - goto err; - - retval = pci_enable_device(pdev); - if (retval) { - dev_err(&pdev->dev, "failed to enable\n"); - goto err; - } - - dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device); - - /* allot the first empty slot in the array */ - for (index = 0; index < BOARD_COUNT; index++) { - if (isi_card[index].base == 0) { - board = &isi_card[index]; - break; - } - } - if (index == BOARD_COUNT) { - retval = -ENODEV; - goto err_disable; - } - - board->index = index; - board->base = pci_resource_start(pdev, 3); - board->irq = pdev->irq; - card_count++; - - pci_set_drvdata(pdev, board); - - retval = pci_request_region(pdev, 3, ISICOM_NAME); - if (retval) { - dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d " - "will be disabled.\n", board->base, board->base + 15, - index + 1); - retval = -EBUSY; - goto errdec; - } - - retval = request_irq(board->irq, isicom_interrupt, - IRQF_SHARED, ISICOM_NAME, board); - if (retval < 0) { - dev_err(&pdev->dev, "Could not install handler at Irq %d. " - "Card%d will be disabled.\n", board->irq, index + 1); - goto errunrr; - } - - retval = reset_card(pdev, index, &signature); - if (retval < 0) - goto errunri; - - retval = load_firmware(pdev, index, signature); - if (retval < 0) - goto errunri; - - for (index = 0; index < board->port_count; index++) { - struct tty_port *tport = &board->ports[index].port; - tty_port_init(tport); - tport->ops = &isicom_port_ops; - tport->close_delay = 50 * HZ/100; - tport->closing_wait = 3000 * HZ/100; - tty_port_register_device(tport, isicom_normal, - board->index * 16 + index, &pdev->dev); - } - - return 0; - -errunri: - free_irq(board->irq, board); -errunrr: - pci_release_region(pdev, 3); -errdec: - board->base = 0; - card_count--; -err_disable: - pci_disable_device(pdev); -err: - return retval; -} - -static void isicom_remove(struct pci_dev *pdev) -{ - struct isi_board *board = pci_get_drvdata(pdev); - unsigned int i; - - for (i = 0; i < board->port_count; i++) { - tty_unregister_device(isicom_normal, board->index * 16 + i); - tty_port_destroy(&board->ports[i].port); - } - - free_irq(board->irq, board); - pci_release_region(pdev, 3); - board->base = 0; - card_count--; - pci_disable_device(pdev); -} - -static int __init isicom_init(void) -{ - int retval, idx, channel; - struct isi_port *port; - - for (idx = 0; idx < BOARD_COUNT; idx++) { - port = &isi_ports[idx * 16]; - isi_card[idx].ports = port; - spin_lock_init(&isi_card[idx].card_lock); - for (channel = 0; channel < 16; channel++, port++) { - port->magic = ISICOM_MAGIC; - port->card = &isi_card[idx]; - port->channel = channel; - port->status = 0; - /* . . . */ - } - isi_card[idx].base = 0; - isi_card[idx].irq = 0; - } - - /* tty driver structure initialization */ - isicom_normal = alloc_tty_driver(PORT_COUNT); - if (!isicom_normal) { - retval = -ENOMEM; - goto error; - } - - isicom_normal->name = "ttyM"; - isicom_normal->major = ISICOM_NMAJOR; - isicom_normal->minor_start = 0; - isicom_normal->type = TTY_DRIVER_TYPE_SERIAL; - isicom_normal->subtype = SERIAL_TYPE_NORMAL; - isicom_normal->init_termios = tty_std_termios; - isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | - CLOCAL; - isicom_normal->flags = TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK; - tty_set_operations(isicom_normal, &isicom_ops); - - retval = tty_register_driver(isicom_normal); - if (retval) { - pr_debug("Couldn't register the dialin driver\n"); - goto err_puttty; - } - - retval = pci_register_driver(&isicom_driver); - if (retval < 0) { - pr_err("Unable to register pci driver.\n"); - goto err_unrtty; - } - - mod_timer(&tx, jiffies + 1); - - return 0; -err_unrtty: - tty_unregister_driver(isicom_normal); -err_puttty: - put_tty_driver(isicom_normal); -error: - return retval; -} - -static void __exit isicom_exit(void) -{ - del_timer_sync(&tx); - - pci_unregister_driver(&isicom_driver); - tty_unregister_driver(isicom_normal); - put_tty_driver(isicom_normal); -} - -module_init(isicom_init); -module_exit(isicom_exit); - -MODULE_AUTHOR("MultiTech"); -MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("isi608.bin"); -MODULE_FIRMWARE("isi608em.bin"); -MODULE_FIRMWARE("isi616em.bin"); -MODULE_FIRMWARE("isi4608.bin"); -MODULE_FIRMWARE("isi4616.bin"); diff --git a/include/linux/isicom.h b/include/linux/isicom.h deleted file mode 100644 index 7de6822d7b1a..000000000000 --- a/include/linux/isicom.h +++ /dev/null @@ -1,85 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LINUX_ISICOM_H -#define _LINUX_ISICOM_H - -#define YES 1 -#define NO 0 - -/* - * ISICOM Driver definitions ... - * - */ - -#define ISICOM_NAME "ISICom" - -/* - * PCI definitions - */ - -#define DEVID_COUNT 9 -#define VENDOR_ID 0x10b5 - -/* - * These are now officially allocated numbers - */ - -#define ISICOM_NMAJOR 112 /* normal */ -#define ISICOM_CMAJOR 113 /* callout */ -#define ISICOM_MAGIC (('M' << 8) | 'T') - -#define WAKEUP_CHARS 256 /* hard coded for now */ -#define TX_SIZE 254 - -#define BOARD_COUNT 4 -#define PORT_COUNT (BOARD_COUNT*16) - -/* character sizes */ - -#define ISICOM_CS5 0x0000 -#define ISICOM_CS6 0x0001 -#define ISICOM_CS7 0x0002 -#define ISICOM_CS8 0x0003 - -/* stop bits */ - -#define ISICOM_1SB 0x0000 -#define ISICOM_2SB 0x0004 - -/* parity */ - -#define ISICOM_NOPAR 0x0000 -#define ISICOM_ODPAR 0x0008 -#define ISICOM_EVPAR 0x0018 - -/* flow control */ - -#define ISICOM_CTSRTS 0x03 -#define ISICOM_INITIATE_XONXOFF 0x04 -#define ISICOM_RESPOND_XONXOFF 0x08 - -#define BOARD(line) (((line) >> 4) & 0x3) - - /* isi kill queue bitmap */ - -#define ISICOM_KILLTX 0x01 -#define ISICOM_KILLRX 0x02 - - /* isi_board status bitmap */ - -#define FIRMWARE_LOADED 0x0001 -#define BOARD_ACTIVE 0x0002 -#define BOARD_INIT 0x0004 - - /* isi_port status bitmap */ - -#define ISI_CTS 0x1000 -#define ISI_DSR 0x2000 -#define ISI_RI 0x4000 -#define ISI_DCD 0x8000 -#define ISI_DTR 0x0100 -#define ISI_RTS 0x0200 - - -#define ISI_TXOK 0x0001 - -#endif /* ISICOM_H */ -- cgit From 3b00b6af7a5bd7fd7e5189ccaad0e0cfb7dc7785 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:37 +0100 Subject: tty: rocket, remove the driver While the driver is still marked as maintained in MAINTAINERS, Comtrol does not really care about this ancient driver. They are still manufacturing serial devices, but those are controlled only by out-of-tree drivers. Comtrol didn't answer my pings, so this driver is apparently unmaintained. Aside from that, the driver was untouched for years, only whole-tree changes happened during the past years. The driver needs much more care, so drop it for now. If someone steps up to reintroduce it, they need to clean it up first. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-7-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/serial/rocket.rst | 185 -- Documentation/process/magic-number.rst | 1 - .../translations/it_IT/process/magic-number.rst | 1 - .../translations/zh_CN/process/magic-number.rst | 1 - MAINTAINERS | 6 - drivers/tty/Kconfig | 15 - drivers/tty/Makefile | 1 - drivers/tty/rocket.c | 3127 -------------------- drivers/tty/rocket.h | 111 - drivers/tty/rocket_int.h | 1214 -------- include/linux/pci_ids.h | 21 - 11 files changed, 4683 deletions(-) delete mode 100644 Documentation/driver-api/serial/rocket.rst delete mode 100644 drivers/tty/rocket.c delete mode 100644 drivers/tty/rocket.h delete mode 100644 drivers/tty/rocket_int.h diff --git a/Documentation/driver-api/serial/rocket.rst b/Documentation/driver-api/serial/rocket.rst deleted file mode 100644 index 23761eae4282..000000000000 --- a/Documentation/driver-api/serial/rocket.rst +++ /dev/null @@ -1,185 +0,0 @@ -================================================ -Comtrol(tm) RocketPort(R)/RocketModem(TM) Series -================================================ - -Device Driver for the Linux Operating System -============================================ - -Product overview ----------------- - -This driver provides a loadable kernel driver for the Comtrol RocketPort -and RocketModem PCI boards. These boards provide, 2, 4, 8, 16, or 32 -high-speed serial ports or modems. This driver supports up to a combination -of four RocketPort or RocketModems boards in one machine simultaneously. -This file assumes that you are using the RocketPort driver which is -integrated into the kernel sources. - -The driver can also be installed as an external module using the usual -"make;make install" routine. This external module driver, obtainable -from the Comtrol website listed below, is useful for updating the driver -or installing it into kernels which do not have the driver configured -into them. Installations instructions for the external module -are in the included README and HW_INSTALL files. - -RocketPort ISA and RocketModem II PCI boards currently are only supported by -this driver in module form. - -The RocketPort ISA board requires I/O ports to be configured by the DIP -switches on the board. See the section "ISA Rocketport Boards" below for -information on how to set the DIP switches. - -You pass the I/O port to the driver using the following module parameters: - -board1: - I/O port for the first ISA board -board2: - I/O port for the second ISA board -board3: - I/O port for the third ISA board -board4: - I/O port for the fourth ISA board - -There is a set of utilities and scripts provided with the external driver -(downloadable from http://www.comtrol.com) that ease the configuration and -setup of the ISA cards. - -The RocketModem II PCI boards require firmware to be loaded into the card -before it will function. The driver has only been tested as a module for this -board. - -Installation Procedures ------------------------ - -RocketPort/RocketModem PCI cards require no driver configuration, they are -automatically detected and configured. - -The RocketPort driver can be installed as a module (recommended) or built -into the kernel. This is selected, as for other drivers, through the `make config` -command from the root of the Linux source tree during the kernel build process. - -The RocketPort/RocketModem serial ports installed by this driver are assigned -device major number 46, and will be named /dev/ttyRx, where x is the port number -starting at zero (ex. /dev/ttyR0, /devttyR1, ...). If you have multiple cards -installed in the system, the mapping of port names to serial ports is displayed -in the system log at /var/log/messages. - -If installed as a module, the module must be loaded. This can be done -manually by entering "modprobe rocket". To have the module loaded automatically -upon system boot, edit a `/etc/modprobe.d/*.conf` file and add the line -"alias char-major-46 rocket". - -In order to use the ports, their device names (nodes) must be created with mknod. -This is only required once, the system will retain the names once created. To -create the RocketPort/RocketModem device names, use the command -"mknod /dev/ttyRx c 46 x" where x is the port number starting at zero. - -For example:: - - > mknod /dev/ttyR0 c 46 0 - > mknod /dev/ttyR1 c 46 1 - > mknod /dev/ttyR2 c 46 2 - -The Linux script MAKEDEV will create the first 16 ttyRx device names (nodes) -for you:: - - >/dev/MAKEDEV ttyR - -ISA Rocketport Boards ---------------------- - -You must assign and configure the I/O addresses used by the ISA Rocketport -card before installing and using it. This is done by setting a set of DIP -switches on the Rocketport board. - - -Setting the I/O address ------------------------ - -Before installing RocketPort(R) or RocketPort RA boards, you must find -a range of I/O addresses for it to use. The first RocketPort card -requires a 68-byte contiguous block of I/O addresses, starting at one -of the following: 0x100h, 0x140h, 0x180h, 0x200h, 0x240h, 0x280h, -0x300h, 0x340h, 0x380h. This I/O address must be reflected in the DIP -switches of *all* of the Rocketport cards. - -The second, third, and fourth RocketPort cards require a 64-byte -contiguous block of I/O addresses, starting at one of the following -I/O addresses: 0x100h, 0x140h, 0x180h, 0x1C0h, 0x200h, 0x240h, 0x280h, -0x2C0h, 0x300h, 0x340h, 0x380h, 0x3C0h. The I/O address used by the -second, third, and fourth Rocketport cards (if present) are set via -software control. The DIP switch settings for the I/O address must be -set to the value of the first Rocketport cards. - -In order to distinguish each of the card from the others, each card -must have a unique board ID set on the dip switches. The first -Rocketport board must be set with the DIP switches corresponding to -the first board, the second board must be set with the DIP switches -corresponding to the second board, etc. IMPORTANT: The board ID is -the only place where the DIP switch settings should differ between the -various Rocketport boards in a system. - -The I/O address range used by any of the RocketPort cards must not -conflict with any other cards in the system, including other -RocketPort cards. Below, you will find a list of commonly used I/O -address ranges which may be in use by other devices in your system. -On a Linux system, "cat /proc/ioports" will also be helpful in -identifying what I/O addresses are being used by devices on your -system. - -Remember, the FIRST RocketPort uses 68 I/O addresses. So, if you set it -for 0x100, it will occupy 0x100 to 0x143. This would mean that you -CAN NOT set the second, third or fourth board for address 0x140 since -the first 4 bytes of that range are used by the first board. You would -need to set the second, third, or fourth board to one of the next available -blocks such as 0x180. - -RocketPort and RocketPort RA SW1 Settings:: - - +-------------------------------+ - | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | - +-------+-------+---------------+ - | Unused| Card | I/O Port Block| - +-------------------------------+ - - DIP Switches DIP Switches - 7 8 6 5 - =================== =================== - On On UNUSED, MUST BE ON. On On First Card <==== Default - On Off Second Card - Off On Third Card - Off Off Fourth Card - - DIP Switches I/O Address Range - 4 3 2 1 Used by the First Card - ===================================== - On Off On Off 100-143 - On Off Off On 140-183 - On Off Off Off 180-1C3 <==== Default - Off On On Off 200-243 - Off On Off On 240-283 - Off On Off Off 280-2C3 - Off Off On Off 300-343 - Off Off Off On 340-383 - Off Off Off Off 380-3C3 - -Reporting Bugs --------------- - -For technical support, please provide the following -information: Driver version, kernel release, distribution of -kernel, and type of board you are using. Error messages and log -printouts port configuration details are especially helpful. - -USA: - :Phone: (612) 494-4100 - :FAX: (612) 494-4199 - :email: support@comtrol.com - -Comtrol Europe: - :Phone: +44 (0) 1 869 323-220 - :FAX: +44 (0) 1 869 323-211 - :email: support@comtrol.co.uk - -Web: http://www.comtrol.com -FTP: ftp.comtrol.com diff --git a/Documentation/process/magic-number.rst b/Documentation/process/magic-number.rst index c36f21eecefb..89992fe4863f 100644 --- a/Documentation/process/magic-number.rst +++ b/Documentation/process/magic-number.rst @@ -95,7 +95,6 @@ USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/cl RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -RPORT_MAGIC 0x00525001 r_port ``drivers/char/rocket_int.h`` LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` NBD_REQUEST_MAGIC 0x12560953 nbd_request ``include/linux/nbd.h`` diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst index 440087f9f402..9be170ec0d02 100644 --- a/Documentation/translations/it_IT/process/magic-number.rst +++ b/Documentation/translations/it_IT/process/magic-number.rst @@ -101,7 +101,6 @@ USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/cl RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -RPORT_MAGIC 0x00525001 r_port ``drivers/char/rocket_int.h`` LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h`` RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index e91bec4ec156..191d705349ef 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -84,7 +84,6 @@ USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/cl RFCOMM_TTY_MAGIC 0x6d02 ``net/bluetooth/rfcomm/tty.c`` USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port ``drivers/usb/serial/usb-serial.h`` CG_MAGIC 0x00090255 ufs_cylinder_group ``include/linux/ufs_fs.h`` -RPORT_MAGIC 0x00525001 r_port ``drivers/char/rocket_int.h`` LSEMAGIC 0x05091998 lse ``drivers/fc4/fc.c`` GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str ``drivers/scsi/gdth_ioctl.h`` RIEBL_MAGIC 0x09051990 ``drivers/net/atarilance.c`` diff --git a/MAINTAINERS b/MAINTAINERS index f62df0494d11..2c92d4a55d7f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15394,12 +15394,6 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/rocker/ -ROCKETPORT DRIVER -S: Maintained -W: http://www.comtrol.com -F: Documentation/driver-api/serial/rocket.rst -F: drivers/tty/rocket* - ROCKETPORT EXPRESS/INFINITY DRIVER M: Kevin Cernekee L: linux-serial@vger.kernel.org diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 0031aa8f8b16..1d30add862af 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -192,21 +192,6 @@ config SERIAL_NONSTANDARD Most people can say N here. -config ROCKETPORT - tristate "Comtrol RocketPort support" - depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) - help - This driver supports Comtrol RocketPort and RocketModem PCI boards. - These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or - modems. For information about the RocketPort/RocketModem boards - and this driver read . - - To compile this driver as a module, choose M here: the - module will be called rocket. - - If you want to compile this driver into the kernel, say Y here. If - you don't have a Comtrol RocketPort/RocketModem card installed, say N. - config MOXA_INTELLIO tristate "Moxa Intellio support" depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index a34055bc8b7a..c7054f5117c3 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_MOXA_INTELLIO) += moxa.o obj-$(CONFIG_MOXA_SMARTIO) += mxser.o obj-$(CONFIG_NOZOMI) += nozomi.o obj-$(CONFIG_NULL_TTY) += ttynull.o -obj-$(CONFIG_ROCKETPORT) += rocket.o obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c deleted file mode 100644 index 2540b2e4c8e8..000000000000 --- a/drivers/tty/rocket.c +++ /dev/null @@ -1,3127 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) -/* - * RocketPort device driver for Linux - * - * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000. - * - * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc. - */ - -/* - * Kernel Synchronization: - * - * This driver has 2 kernel control paths - exception handlers (calls into the driver - * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts - * are not used. - * - * Critical data: - * - rp_table[], accessed through passed "info" pointers, is a global (static) array of - * serial port state information and the xmit_buf circular buffer. Protected by - * a per port spinlock. - * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there - * is data to be transmitted. Protected by atomic bit operations. - * - rp_num_ports, int indicating number of open ports, protected by atomic operations. - * - * rp_write() and rp_write_char() functions use a per port semaphore to protect against - * simultaneous access to the same port by more than one process. - */ - -/****** Defines ******/ -#define ROCKET_PARANOIA_CHECK -#define ROCKET_DISABLE_SIMUSAGE - -#undef ROCKET_SOFT_FLOW -#undef ROCKET_DEBUG_OPEN -#undef ROCKET_DEBUG_INTR -#undef ROCKET_DEBUG_WRITE -#undef ROCKET_DEBUG_FLOW -#undef ROCKET_DEBUG_THROTTLE -#undef ROCKET_DEBUG_WAIT_UNTIL_SENT -#undef ROCKET_DEBUG_RECEIVE -#undef ROCKET_DEBUG_HANGUP -#undef REV_PCI_ORDER -#undef ROCKET_DEBUG_IO - -#define POLL_PERIOD (HZ/100) /* Polling period .01 seconds (10ms) */ - -/****** Kernel includes ******/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/****** RocketPort includes ******/ - -#include "rocket_int.h" -#include "rocket.h" - -#define ROCKET_VERSION "2.09" -#define ROCKET_DATE "12-June-2003" - -/****** RocketPort Local Variables ******/ - -static void rp_do_poll(struct timer_list *unused); - -static struct tty_driver *rocket_driver; - -static struct rocket_version driver_version = { - ROCKET_VERSION, ROCKET_DATE -}; - -static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */ -static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */ - /* eg. Bit 0 indicates port 0 has xmit data, ... */ -static atomic_t rp_num_ports_open; /* Number of serial ports open */ -static DEFINE_TIMER(rocket_timer, rp_do_poll); - -static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */ -static unsigned long board2; -static unsigned long board3; -static unsigned long board4; -static unsigned long controller; -static bool support_low_speed; -static unsigned long modem1; -static unsigned long modem2; -static unsigned long modem3; -static unsigned long modem4; -static unsigned long pc104_1[8]; -static unsigned long pc104_2[8]; -static unsigned long pc104_3[8]; -static unsigned long pc104_4[8]; -static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 }; - -static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */ -static unsigned long rcktpt_io_addr[NUM_BOARDS]; -static int rcktpt_type[NUM_BOARDS]; -static int is_PCI[NUM_BOARDS]; -static rocketModel_t rocketModel[NUM_BOARDS]; -static int max_board; -static const struct tty_port_operations rocket_port_ops; - -/* - * The following arrays define the interrupt bits corresponding to each AIOP. - * These bits are different between the ISA and regular PCI boards and the - * Universal PCI boards. - */ - -static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = { - AIOP_INTR_BIT_0, - AIOP_INTR_BIT_1, - AIOP_INTR_BIT_2, - AIOP_INTR_BIT_3 -}; - -#ifdef CONFIG_PCI -static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { - UPCI_AIOP_INTR_BIT_0, - UPCI_AIOP_INTR_BIT_1, - UPCI_AIOP_INTR_BIT_2, - UPCI_AIOP_INTR_BIT_3 -}; -#endif - -static Byte_t RData[RDATASIZE] = { - 0x00, 0x09, 0xf6, 0x82, - 0x02, 0x09, 0x86, 0xfb, - 0x04, 0x09, 0x00, 0x0a, - 0x06, 0x09, 0x01, 0x0a, - 0x08, 0x09, 0x8a, 0x13, - 0x0a, 0x09, 0xc5, 0x11, - 0x0c, 0x09, 0x86, 0x85, - 0x0e, 0x09, 0x20, 0x0a, - 0x10, 0x09, 0x21, 0x0a, - 0x12, 0x09, 0x41, 0xff, - 0x14, 0x09, 0x82, 0x00, - 0x16, 0x09, 0x82, 0x7b, - 0x18, 0x09, 0x8a, 0x7d, - 0x1a, 0x09, 0x88, 0x81, - 0x1c, 0x09, 0x86, 0x7a, - 0x1e, 0x09, 0x84, 0x81, - 0x20, 0x09, 0x82, 0x7c, - 0x22, 0x09, 0x0a, 0x0a -}; - -static Byte_t RRegData[RREGDATASIZE] = { - 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ - 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ - 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ - 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ - 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ - 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ - 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ - 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ - 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ - 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ - 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ - 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ - 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ -}; - -static CONTROLLER_T sController[CTL_SIZE] = { - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} -}; - -static Byte_t sBitMapClrTbl[8] = { - 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f -}; - -static Byte_t sBitMapSetTbl[8] = { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 -}; - -static int sClockPrescale = 0x14; - -/* - * Line number is the ttySIx number (x), the Minor number. We - * assign them sequentially, starting at zero. The following - * array keeps track of the line number assigned to a given board/aiop/channel. - */ -static unsigned char lineNumbers[MAX_RP_PORTS]; -static unsigned long nextLineNumber; - -/***** RocketPort Static Prototypes *********/ -static int __init init_ISA(int i); -static void rp_wait_until_sent(struct tty_struct *tty, int timeout); -static void rp_flush_buffer(struct tty_struct *tty); -static unsigned char GetLineNumber(int ctrl, int aiop, int ch); -static unsigned char SetLineNumber(int ctrl, int aiop, int ch); -static void rp_start(struct tty_struct *tty); -static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, - int ChanNum); -static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); -static void sFlushRxFIFO(CHANNEL_T * ChP); -static void sFlushTxFIFO(CHANNEL_T * ChP); -static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); -static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); -static void sModemReset(CONTROLLER_T * CtlP, int chan, int on); -static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); -static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); -static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, - ByteIO_t * AiopIOList, int AiopIOListSize, - int IRQNum, Byte_t Frequency, int PeriodicOnly); -static int sReadAiopID(ByteIO_t io); -static int sReadAiopNumChan(WordIO_t io); - -MODULE_AUTHOR("Theodore Ts'o"); -MODULE_DESCRIPTION("Comtrol RocketPort driver"); -module_param_hw(board1, ulong, ioport, 0); -MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1"); -module_param_hw(board2, ulong, ioport, 0); -MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2"); -module_param_hw(board3, ulong, ioport, 0); -MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3"); -module_param_hw(board4, ulong, ioport, 0); -MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4"); -module_param_hw(controller, ulong, ioport, 0); -MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller"); -module_param(support_low_speed, bool, 0); -MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud"); -module_param(modem1, ulong, 0); -MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem"); -module_param(modem2, ulong, 0); -MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem"); -module_param(modem3, ulong, 0); -MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem"); -module_param(modem4, ulong, 0); -MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem"); -module_param_array(pc104_1, ulong, NULL, 0); -MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,..."); -module_param_array(pc104_2, ulong, NULL, 0); -MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,..."); -module_param_array(pc104_3, ulong, NULL, 0); -MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,..."); -module_param_array(pc104_4, ulong, NULL, 0); -MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,..."); - -static int __init rp_init(void); -static void rp_cleanup_module(void); - -module_init(rp_init); -module_exit(rp_cleanup_module); - - -MODULE_LICENSE("Dual BSD/GPL"); - -/*************************************************************************/ -/* Module code starts here */ - -static inline int rocket_paranoia_check(struct r_port *info, - const char *routine) -{ -#ifdef ROCKET_PARANOIA_CHECK - if (!info) - return 1; - if (info->magic != RPORT_MAGIC) { - printk(KERN_WARNING "Warning: bad magic number for rocketport " - "struct in %s\n", routine); - return 1; - } -#endif - return 0; -} - - -/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals - * that receive data is present on a serial port. Pulls data from FIFO, moves it into the - * tty layer. - */ -static void rp_do_receive(struct r_port *info, CHANNEL_t *cp, - unsigned int ChanStatus) -{ - unsigned int CharNStat; - int ToRecv, wRecv, space; - unsigned char *cbuf; - - ToRecv = sGetRxCnt(cp); -#ifdef ROCKET_DEBUG_INTR - printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv); -#endif - if (ToRecv == 0) - return; - - /* - * if status indicates there are errored characters in the - * FIFO, then enter status mode (a word in FIFO holds - * character and status). - */ - if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { - if (!(ChanStatus & STATMODE)) { -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "Entering STATMODE...\n"); -#endif - ChanStatus |= STATMODE; - sEnRxStatusMode(cp); - } - } - - /* - * if we previously entered status mode, then read down the - * FIFO one word at a time, pulling apart the character and - * the status. Update error counters depending on status - */ - if (ChanStatus & STATMODE) { -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "Ignore %x, read %x...\n", - info->ignore_status_mask, info->read_status_mask); -#endif - while (ToRecv) { - char flag; - - CharNStat = sInW(sGetTxRxDataIO(cp)); -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "%x...\n", CharNStat); -#endif - if (CharNStat & STMBREAKH) - CharNStat &= ~(STMFRAMEH | STMPARITYH); - if (CharNStat & info->ignore_status_mask) { - ToRecv--; - continue; - } - CharNStat &= info->read_status_mask; - if (CharNStat & STMBREAKH) - flag = TTY_BREAK; - else if (CharNStat & STMPARITYH) - flag = TTY_PARITY; - else if (CharNStat & STMFRAMEH) - flag = TTY_FRAME; - else if (CharNStat & STMRCVROVRH) - flag = TTY_OVERRUN; - else - flag = TTY_NORMAL; - tty_insert_flip_char(&info->port, CharNStat & 0xff, - flag); - ToRecv--; - } - - /* - * after we've emptied the FIFO in status mode, turn - * status mode back off - */ - if (sGetRxCnt(cp) == 0) { -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "Status mode off.\n"); -#endif - sDisRxStatusMode(cp); - } - } else { - /* - * we aren't in status mode, so read down the FIFO two - * characters at time by doing repeated word IO - * transfer. - */ - space = tty_prepare_flip_string(&info->port, &cbuf, ToRecv); - if (space < ToRecv) { -#ifdef ROCKET_DEBUG_RECEIVE - printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space); -#endif - if (space <= 0) - return; - ToRecv = space; - } - wRecv = ToRecv >> 1; - if (wRecv) - sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv); - if (ToRecv & 1) - cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp)); - } - /* Push the data up to the tty layer */ - tty_flip_buffer_push(&info->port); -} - -/* - * Serial port transmit data function. Called from the timer polling loop as a - * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready - * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is - * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks. - */ -static void rp_do_transmit(struct r_port *info) -{ - int c; - CHANNEL_t *cp = &info->channel; - struct tty_struct *tty; - unsigned long flags; - -#ifdef ROCKET_DEBUG_INTR - printk(KERN_DEBUG "%s\n", __func__); -#endif - if (!info) - return; - tty = tty_port_tty_get(&info->port); - - if (tty == NULL) { - printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__); - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - return; - } - - spin_lock_irqsave(&info->slock, flags); - info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - - /* Loop sending data to FIFO until done or FIFO full */ - while (1) { - if (tty->stopped) - break; - c = min(info->xmit_fifo_room, info->xmit_cnt); - c = min(c, XMIT_BUF_SIZE - info->xmit_tail); - if (c <= 0 || info->xmit_fifo_room <= 0) - break; - sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2); - if (c & 1) - sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]); - info->xmit_tail += c; - info->xmit_tail &= XMIT_BUF_SIZE - 1; - info->xmit_cnt -= c; - info->xmit_fifo_room -= c; -#ifdef ROCKET_DEBUG_INTR - printk(KERN_INFO "tx %d chars...\n", c); -#endif - } - - if (info->xmit_cnt == 0) - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - - if (info->xmit_cnt < WAKEUP_CHARS) { - tty_wakeup(tty); -#ifdef ROCKETPORT_HAVE_POLL_WAIT - wake_up_interruptible(&tty->poll_wait); -#endif - } - - spin_unlock_irqrestore(&info->slock, flags); - tty_kref_put(tty); - -#ifdef ROCKET_DEBUG_INTR - printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head, - info->xmit_tail, info->xmit_fifo_room); -#endif -} - -/* - * Called when a serial port signals it has read data in it's RX FIFO. - * It checks what interrupts are pending and services them, including - * receiving serial data. - */ -static void rp_handle_port(struct r_port *info) -{ - CHANNEL_t *cp; - unsigned int IntMask, ChanStatus; - - if (!info) - return; - - if (!tty_port_initialized(&info->port)) { - printk(KERN_WARNING "rp: WARNING: rp_handle_port called with " - "info->flags & NOT_INIT\n"); - return; - } - - cp = &info->channel; - - IntMask = sGetChanIntID(cp) & info->intmask; -#ifdef ROCKET_DEBUG_INTR - printk(KERN_INFO "rp_interrupt %02x...\n", IntMask); -#endif - ChanStatus = sGetChanStatus(cp); - if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */ - rp_do_receive(info, cp, ChanStatus); - } - if (IntMask & DELTA_CD) { /* CD change */ -#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP)) - printk(KERN_INFO "ttyR%d CD now %s...\n", info->line, - (ChanStatus & CD_ACT) ? "on" : "off"); -#endif - if (!(ChanStatus & CD_ACT) && info->cd_status) { -#ifdef ROCKET_DEBUG_HANGUP - printk(KERN_INFO "CD drop, calling hangup.\n"); -#endif - tty_port_tty_hangup(&info->port, false); - } - info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0; - wake_up_interruptible(&info->port.open_wait); - } -#ifdef ROCKET_DEBUG_INTR - if (IntMask & DELTA_CTS) { /* CTS change */ - printk(KERN_INFO "CTS change...\n"); - } - if (IntMask & DELTA_DSR) { /* DSR change */ - printk(KERN_INFO "DSR change...\n"); - } -#endif -} - -/* - * The top level polling routine. Repeats every 1/100 HZ (10ms). - */ -static void rp_do_poll(struct timer_list *unused) -{ - CONTROLLER_t *ctlp; - int ctrl, aiop, ch, line; - unsigned int xmitmask, i; - unsigned int CtlMask; - unsigned char AiopMask; - Word_t bit; - - /* Walk through all the boards (ctrl's) */ - for (ctrl = 0; ctrl < max_board; ctrl++) { - if (rcktpt_io_addr[ctrl] <= 0) - continue; - - /* Get a ptr to the board's control struct */ - ctlp = sCtlNumToCtlPtr(ctrl); - - /* Get the interrupt status from the board */ -#ifdef CONFIG_PCI - if (ctlp->BusType == isPCI) - CtlMask = sPCIGetControllerIntStatus(ctlp); - else -#endif - CtlMask = sGetControllerIntStatus(ctlp); - - /* Check if any AIOP read bits are set */ - for (aiop = 0; CtlMask; aiop++) { - bit = ctlp->AiopIntrBits[aiop]; - if (CtlMask & bit) { - CtlMask &= ~bit; - AiopMask = sGetAiopIntStatus(ctlp, aiop); - - /* Check if any port read bits are set */ - for (ch = 0; AiopMask; AiopMask >>= 1, ch++) { - if (AiopMask & 1) { - - /* Get the line number (/dev/ttyRx number). */ - /* Read the data from the port. */ - line = GetLineNumber(ctrl, aiop, ch); - rp_handle_port(rp_table[line]); - } - } - } - } - - xmitmask = xmit_flags[ctrl]; - - /* - * xmit_flags contains bit-significant flags, indicating there is data - * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port - * 1, ... (32 total possible). The variable i has the aiop and ch - * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc). - */ - if (xmitmask) { - for (i = 0; i < rocketModel[ctrl].numPorts; i++) { - if (xmitmask & (1 << i)) { - aiop = (i & 0x18) >> 3; - ch = i & 0x07; - line = GetLineNumber(ctrl, aiop, ch); - rp_do_transmit(rp_table[line]); - } - } - } - } - - /* - * Reset the timer so we get called at the next clock tick (10ms). - */ - if (atomic_read(&rp_num_ports_open)) - mod_timer(&rocket_timer, jiffies + POLL_PERIOD); -} - -/* - * Initializes the r_port structure for a port, as well as enabling the port on - * the board. - * Inputs: board, aiop, chan numbers - */ -static void __init -init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) -{ - unsigned rocketMode; - struct r_port *info; - int line; - CONTROLLER_T *ctlp; - - /* Get the next available line number */ - line = SetLineNumber(board, aiop, chan); - - ctlp = sCtlNumToCtlPtr(board); - - /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ - info = kzalloc(sizeof (struct r_port), GFP_KERNEL); - if (!info) { - printk(KERN_ERR "Couldn't allocate info struct for line #%d\n", - line); - return; - } - - info->magic = RPORT_MAGIC; - info->line = line; - info->ctlp = ctlp; - info->board = board; - info->aiop = aiop; - info->chan = chan; - tty_port_init(&info->port); - info->port.ops = &rocket_port_ops; - info->flags &= ~ROCKET_MODE_MASK; - if (board < ARRAY_SIZE(pc104) && line < ARRAY_SIZE(pc104_1)) - switch (pc104[board][line]) { - case 422: - info->flags |= ROCKET_MODE_RS422; - break; - case 485: - info->flags |= ROCKET_MODE_RS485; - break; - case 232: - default: - info->flags |= ROCKET_MODE_RS232; - break; - } - else - info->flags |= ROCKET_MODE_RS232; - - info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; - if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { - printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n", - board, aiop, chan); - tty_port_destroy(&info->port); - kfree(info); - return; - } - - rocketMode = info->flags & ROCKET_MODE_MASK; - - if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485)) - sEnRTSToggle(&info->channel); - else - sDisRTSToggle(&info->channel); - - if (ctlp->boardType == ROCKET_TYPE_PC104) { - switch (rocketMode) { - case ROCKET_MODE_RS485: - sSetInterfaceMode(&info->channel, InterfaceModeRS485); - break; - case ROCKET_MODE_RS422: - sSetInterfaceMode(&info->channel, InterfaceModeRS422); - break; - case ROCKET_MODE_RS232: - default: - if (info->flags & ROCKET_RTS_TOGGLE) - sSetInterfaceMode(&info->channel, InterfaceModeRS232T); - else - sSetInterfaceMode(&info->channel, InterfaceModeRS232); - break; - } - } - spin_lock_init(&info->slock); - mutex_init(&info->write_mtx); - rp_table[line] = info; - tty_port_register_device(&info->port, rocket_driver, line, - pci_dev ? &pci_dev->dev : NULL); -} - -/* - * Configures a rocketport port according to its termio settings. Called from - * user mode into the driver (exception handler). *info CD manipulation is spinlock protected. - */ -static void configure_r_port(struct tty_struct *tty, struct r_port *info, - struct ktermios *old_termios) -{ - unsigned cflag; - unsigned long flags; - unsigned rocketMode; - int bits, baud, divisor; - CHANNEL_t *cp; - struct ktermios *t = &tty->termios; - - cp = &info->channel; - cflag = t->c_cflag; - - /* Byte size and parity */ - if ((cflag & CSIZE) == CS8) { - sSetData8(cp); - bits = 10; - } else { - sSetData7(cp); - bits = 9; - } - if (cflag & CSTOPB) { - sSetStop2(cp); - bits++; - } else { - sSetStop1(cp); - } - - if (cflag & PARENB) { - sEnParity(cp); - bits++; - if (cflag & PARODD) { - sSetOddParity(cp); - } else { - sSetEvenParity(cp); - } - } else { - sDisParity(cp); - } - - /* baud rate */ - baud = tty_get_baud_rate(tty); - if (!baud) - baud = 9600; - divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; - if ((divisor >= 8192 || divisor < 0) && old_termios) { - baud = tty_termios_baud_rate(old_termios); - if (!baud) - baud = 9600; - divisor = (rp_baud_base[info->board] / baud) - 1; - } - if (divisor >= 8192 || divisor < 0) { - baud = 9600; - divisor = (rp_baud_base[info->board] / baud) - 1; - } - info->cps = baud / bits; - sSetBaud(cp, divisor); - - /* FIXME: Should really back compute a baud rate from the divisor */ - tty_encode_baud_rate(tty, baud, baud); - - if (cflag & CRTSCTS) { - info->intmask |= DELTA_CTS; - sEnCTSFlowCtl(cp); - } else { - info->intmask &= ~DELTA_CTS; - sDisCTSFlowCtl(cp); - } - if (cflag & CLOCAL) { - info->intmask &= ~DELTA_CD; - } else { - spin_lock_irqsave(&info->slock, flags); - if (sGetChanStatus(cp) & CD_ACT) - info->cd_status = 1; - else - info->cd_status = 0; - info->intmask |= DELTA_CD; - spin_unlock_irqrestore(&info->slock, flags); - } - - /* - * Handle software flow control in the board - */ -#ifdef ROCKET_SOFT_FLOW - if (I_IXON(tty)) { - sEnTxSoftFlowCtl(cp); - if (I_IXANY(tty)) { - sEnIXANY(cp); - } else { - sDisIXANY(cp); - } - sSetTxXONChar(cp, START_CHAR(tty)); - sSetTxXOFFChar(cp, STOP_CHAR(tty)); - } else { - sDisTxSoftFlowCtl(cp); - sDisIXANY(cp); - sClrTxXOFF(cp); - } -#endif - - /* - * Set up ignore/read mask words - */ - info->read_status_mask = STMRCVROVRH | 0xFF; - if (I_INPCK(tty)) - info->read_status_mask |= STMFRAMEH | STMPARITYH; - if (I_BRKINT(tty) || I_PARMRK(tty)) - info->read_status_mask |= STMBREAKH; - - /* - * Characters to ignore - */ - info->ignore_status_mask = 0; - if (I_IGNPAR(tty)) - info->ignore_status_mask |= STMFRAMEH | STMPARITYH; - if (I_IGNBRK(tty)) { - info->ignore_status_mask |= STMBREAKH; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too. (For real raw support). - */ - if (I_IGNPAR(tty)) - info->ignore_status_mask |= STMRCVROVRH; - } - - rocketMode = info->flags & ROCKET_MODE_MASK; - - if ((info->flags & ROCKET_RTS_TOGGLE) - || (rocketMode == ROCKET_MODE_RS485)) - sEnRTSToggle(cp); - else - sDisRTSToggle(cp); - - sSetRTS(&info->channel); - - if (cp->CtlP->boardType == ROCKET_TYPE_PC104) { - switch (rocketMode) { - case ROCKET_MODE_RS485: - sSetInterfaceMode(cp, InterfaceModeRS485); - break; - case ROCKET_MODE_RS422: - sSetInterfaceMode(cp, InterfaceModeRS422); - break; - case ROCKET_MODE_RS232: - default: - if (info->flags & ROCKET_RTS_TOGGLE) - sSetInterfaceMode(cp, InterfaceModeRS232T); - else - sSetInterfaceMode(cp, InterfaceModeRS232); - break; - } - } -} - -static int carrier_raised(struct tty_port *port) -{ - struct r_port *info = container_of(port, struct r_port, port); - return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0; -} - -static void dtr_rts(struct tty_port *port, int on) -{ - struct r_port *info = container_of(port, struct r_port, port); - if (on) { - sSetDTR(&info->channel); - sSetRTS(&info->channel); - } else { - sClrDTR(&info->channel); - sClrRTS(&info->channel); - } -} - -/* - * Exception handler that opens a serial port. Creates xmit_buf storage, fills in - * port's r_port struct. Initializes the port hardware. - */ -static int rp_open(struct tty_struct *tty, struct file *filp) -{ - struct r_port *info; - struct tty_port *port; - int retval; - CHANNEL_t *cp; - unsigned long page; - - info = rp_table[tty->index]; - if (info == NULL) - return -ENXIO; - port = &info->port; - - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - /* - * We must not sleep from here until the port is marked fully in use. - */ - if (info->xmit_buf) - free_page(page); - else - info->xmit_buf = (unsigned char *) page; - - tty->driver_data = info; - tty_port_tty_set(port, tty); - - if (port->count++ == 0) { - atomic_inc(&rp_num_ports_open); - -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rocket mod++ = %d...\n", - atomic_read(&rp_num_ports_open)); -#endif - } -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count); -#endif - - /* - * Info->count is now 1; so it's safe to sleep now. - */ - if (!tty_port_initialized(port)) { - cp = &info->channel; - sSetRxTrigger(cp, TRIG_1); - if (sGetChanStatus(cp) & CD_ACT) - info->cd_status = 1; - else - info->cd_status = 0; - sDisRxStatusMode(cp); - sFlushRxFIFO(cp); - sFlushTxFIFO(cp); - - sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); - sSetRxTrigger(cp, TRIG_1); - - sGetChanStatus(cp); - sDisRxStatusMode(cp); - sClrTxXOFF(cp); - - sDisCTSFlowCtl(cp); - sDisTxSoftFlowCtl(cp); - - sEnRxFIFO(cp); - sEnTransmit(cp); - - tty_port_set_initialized(&info->port, 1); - - configure_r_port(tty, info, NULL); - if (C_BAUD(tty)) { - sSetDTR(cp); - sSetRTS(cp); - } - } - /* Starts (or resets) the maint polling loop */ - mod_timer(&rocket_timer, jiffies + POLL_PERIOD); - - retval = tty_port_block_til_ready(port, tty, filp); - if (retval) { -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval); -#endif - return retval; - } - return 0; -} - -/* - * Exception handler that closes a serial port. info->port.count is considered critical. - */ -static void rp_close(struct tty_struct *tty, struct file *filp) -{ - struct r_port *info = tty->driver_data; - struct tty_port *port = &info->port; - int timeout; - CHANNEL_t *cp; - - if (rocket_paranoia_check(info, "rp_close")) - return; - -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count); -#endif - - if (tty_port_close_start(port, tty, filp) == 0) - return; - - mutex_lock(&port->mutex); - cp = &info->channel; - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps; - if (timeout == 0) - timeout = 1; - rp_wait_until_sent(tty, timeout); - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - - sDisTransmit(cp); - sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); - sDisCTSFlowCtl(cp); - sDisTxSoftFlowCtl(cp); - sClrTxXOFF(cp); - sFlushRxFIFO(cp); - sFlushTxFIFO(cp); - sClrRTS(cp); - if (C_HUPCL(tty)) - sClrDTR(cp); - - rp_flush_buffer(tty); - - tty_ldisc_flush(tty); - - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - - /* We can't yet use tty_port_close_end as the buffer handling in this - driver is a bit different to the usual */ - - if (port->blocked_open) { - if (port->close_delay) { - msleep_interruptible(jiffies_to_msecs(port->close_delay)); - } - wake_up_interruptible(&port->open_wait); - } else { - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = NULL; - } - } - spin_lock_irq(&port->lock); - tty->closing = 0; - spin_unlock_irq(&port->lock); - tty_port_set_initialized(port, 0); - tty_port_set_active(port, 0); - mutex_unlock(&port->mutex); - tty_port_tty_set(port, NULL); - - atomic_dec(&rp_num_ports_open); - -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "rocket mod-- = %d...\n", - atomic_read(&rp_num_ports_open)); - printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line); -#endif - -} - -static void rp_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - unsigned cflag; - - if (rocket_paranoia_check(info, "rp_set_termios")) - return; - - cflag = tty->termios.c_cflag; - - /* - * This driver doesn't support CS5 or CS6 - */ - if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) - tty->termios.c_cflag = - ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); - /* Or CMSPAR */ - tty->termios.c_cflag &= ~CMSPAR; - - configure_r_port(tty, info, old_termios); - - cp = &info->channel; - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) { - sClrDTR(cp); - sClrRTS(cp); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) { - sSetRTS(cp); - sSetDTR(cp); - } - - if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) - rp_start(tty); -} - -static int rp_break(struct tty_struct *tty, int break_state) -{ - struct r_port *info = tty->driver_data; - unsigned long flags; - - if (rocket_paranoia_check(info, "rp_break")) - return -EINVAL; - - spin_lock_irqsave(&info->slock, flags); - if (break_state == -1) - sSendBreak(&info->channel); - else - sClrBreak(&info->channel); - spin_unlock_irqrestore(&info->slock, flags); - return 0; -} - -/* - * sGetChanRI used to be a macro in rocket_int.h. When the functionality for - * the UPCI boards was added, it was decided to make this a function because - * the macro was getting too complicated. All cases except the first one - * (UPCIRingInd) are taken directly from the original macro. - */ -static int sGetChanRI(CHANNEL_T * ChP) -{ - CONTROLLER_t *CtlP = ChP->CtlP; - int ChanNum = ChP->ChanNum; - int RingInd = 0; - - if (CtlP->UPCIRingInd) - RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]); - else if (CtlP->AltChanRingIndicator) - RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT; - else if (CtlP->boardType == ROCKET_TYPE_PC104) - RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]); - - return RingInd; -} - -/********************************************************************************************/ -/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */ - -/* - * Returns the state of the serial modem control lines. These next 2 functions - * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs. - */ -static int rp_tiocmget(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - unsigned int control, result, ChanStatus; - - ChanStatus = sGetChanStatusLo(&info->channel); - control = info->channel.TxControl[3]; - result = ((control & SET_RTS) ? TIOCM_RTS : 0) | - ((control & SET_DTR) ? TIOCM_DTR : 0) | - ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) | - (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) | - ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | - ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); - - return result; -} - -/* - * Sets the modem control lines - */ -static int rp_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct r_port *info = tty->driver_data; - - if (set & TIOCM_RTS) - info->channel.TxControl[3] |= SET_RTS; - if (set & TIOCM_DTR) - info->channel.TxControl[3] |= SET_DTR; - if (clear & TIOCM_RTS) - info->channel.TxControl[3] &= ~SET_RTS; - if (clear & TIOCM_DTR) - info->channel.TxControl[3] &= ~SET_DTR; - - out32(info->channel.IndexAddr, info->channel.TxControl); - return 0; -} - -static int get_config(struct r_port *info, struct rocket_config __user *retinfo) -{ - struct rocket_config tmp; - - memset(&tmp, 0, sizeof (tmp)); - mutex_lock(&info->port.mutex); - tmp.line = info->line; - tmp.flags = info->flags; - tmp.close_delay = info->port.close_delay; - tmp.closing_wait = info->port.closing_wait; - tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; - mutex_unlock(&info->port.mutex); - - if (copy_to_user(retinfo, &tmp, sizeof (*retinfo))) - return -EFAULT; - return 0; -} - -static int set_config(struct tty_struct *tty, struct r_port *info, - struct rocket_config __user *new_info) -{ - struct rocket_config new_serial; - - if (copy_from_user(&new_serial, new_info, sizeof (new_serial))) - return -EFAULT; - - mutex_lock(&info->port.mutex); - if (!capable(CAP_SYS_ADMIN)) - { - if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) { - mutex_unlock(&info->port.mutex); - return -EPERM; - } - info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); - mutex_unlock(&info->port.mutex); - return 0; - } - - if ((new_serial.flags ^ info->flags) & ROCKET_SPD_MASK) { - /* warn about deprecation, unless clearing */ - if (new_serial.flags & ROCKET_SPD_MASK) - dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n"); - } - - info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS)); - info->port.close_delay = new_serial.close_delay; - info->port.closing_wait = new_serial.closing_wait; - - mutex_unlock(&info->port.mutex); - - configure_r_port(tty, info, NULL); - return 0; -} - -/* - * This function fills in a rocket_ports struct with information - * about what boards/ports are in the system. This info is passed - * to user space. See setrocket.c where the info is used to create - * the /dev/ttyRx ports. - */ -static int get_ports(struct r_port *info, struct rocket_ports __user *retports) -{ - struct rocket_ports *tmp; - int board, ret = 0; - - tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - tmp->tty_major = rocket_driver->major; - - for (board = 0; board < 4; board++) { - tmp->rocketModel[board].model = rocketModel[board].model; - strcpy(tmp->rocketModel[board].modelString, - rocketModel[board].modelString); - tmp->rocketModel[board].numPorts = rocketModel[board].numPorts; - tmp->rocketModel[board].loadrm2 = rocketModel[board].loadrm2; - tmp->rocketModel[board].startingPortNumber = - rocketModel[board].startingPortNumber; - } - if (copy_to_user(retports, tmp, sizeof(*retports))) - ret = -EFAULT; - kfree(tmp); - return ret; -} - -static int reset_rm2(struct r_port *info, void __user *arg) -{ - int reset; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&reset, arg, sizeof (int))) - return -EFAULT; - if (reset) - reset = 1; - - if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII && - rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII) - return -EINVAL; - - if (info->ctlp->BusType == isISA) - sModemReset(info->ctlp, info->chan, reset); - else - sPCIModemReset(info->ctlp, info->chan, reset); - - return 0; -} - -static int get_version(struct r_port *info, struct rocket_version __user *retvers) -{ - if (copy_to_user(retvers, &driver_version, sizeof (*retvers))) - return -EFAULT; - return 0; -} - -/* IOCTL call handler into the driver */ -static int rp_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct r_port *info = tty->driver_data; - void __user *argp = (void __user *)arg; - int ret = 0; - - if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl")) - return -ENXIO; - - switch (cmd) { - case RCKP_GET_CONFIG: - dev_warn_ratelimited(tty->dev, - "RCKP_GET_CONFIG option is deprecated\n"); - ret = get_config(info, argp); - break; - case RCKP_SET_CONFIG: - dev_warn_ratelimited(tty->dev, - "RCKP_SET_CONFIG option is deprecated\n"); - ret = set_config(tty, info, argp); - break; - case RCKP_GET_PORTS: - dev_warn_ratelimited(tty->dev, - "RCKP_GET_PORTS option is deprecated\n"); - ret = get_ports(info, argp); - break; - case RCKP_RESET_RM2: - dev_warn_ratelimited(tty->dev, - "RCKP_RESET_RM2 option is deprecated\n"); - ret = reset_rm2(info, argp); - break; - case RCKP_GET_VERSION: - dev_warn_ratelimited(tty->dev, - "RCKP_GET_VERSION option is deprecated\n"); - ret = get_version(info, argp); - break; - default: - ret = -ENOIOCTLCMD; - } - return ret; -} - -static void rp_send_xchar(struct tty_struct *tty, char ch) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - - if (rocket_paranoia_check(info, "rp_send_xchar")) - return; - - cp = &info->channel; - if (sGetTxCnt(cp)) - sWriteTxPrioByte(cp, ch); - else - sWriteTxByte(sGetTxRxDataIO(cp), ch); -} - -static void rp_throttle(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - -#ifdef ROCKET_DEBUG_THROTTLE - printk(KERN_INFO "throttle %s ....\n", tty->name); -#endif - - if (rocket_paranoia_check(info, "rp_throttle")) - return; - - if (I_IXOFF(tty)) - rp_send_xchar(tty, STOP_CHAR(tty)); - - sClrRTS(&info->channel); -} - -static void rp_unthrottle(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; -#ifdef ROCKET_DEBUG_THROTTLE - printk(KERN_INFO "unthrottle %s ....\n", tty->name); -#endif - - if (rocket_paranoia_check(info, "rp_unthrottle")) - return; - - if (I_IXOFF(tty)) - rp_send_xchar(tty, START_CHAR(tty)); - - sSetRTS(&info->channel); -} - -/* - * ------------------------------------------------------------ - * rp_stop() and rp_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rp_stop(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - -#ifdef ROCKET_DEBUG_FLOW - printk(KERN_INFO "stop %s: %d %d....\n", tty->name, - info->xmit_cnt, info->xmit_fifo_room); -#endif - - if (rocket_paranoia_check(info, "rp_stop")) - return; - - if (sGetTxCnt(&info->channel)) - sDisTransmit(&info->channel); -} - -static void rp_start(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - -#ifdef ROCKET_DEBUG_FLOW - printk(KERN_INFO "start %s: %d %d....\n", tty->name, - info->xmit_cnt, info->xmit_fifo_room); -#endif - - if (rocket_paranoia_check(info, "rp_stop")) - return; - - sEnTransmit(&info->channel); - set_bit((info->aiop * 8) + info->chan, - (void *) &xmit_flags[info->board]); -} - -/* - * rp_wait_until_sent() --- wait until the transmitter is empty - */ -static void rp_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - unsigned long orig_jiffies; - int check_time, exit_time; - int txcnt; - - if (rocket_paranoia_check(info, "rp_wait_until_sent")) - return; - - cp = &info->channel; - - orig_jiffies = jiffies; -#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk(KERN_INFO "In %s(%d) (jiff=%lu)...\n", __func__, timeout, - jiffies); - printk(KERN_INFO "cps=%d...\n", info->cps); -#endif - while (1) { - txcnt = sGetTxCnt(cp); - if (!txcnt) { - if (sGetChanStatusLo(cp) & TXSHRMT) - break; - check_time = (HZ / info->cps) / 5; - } else { - check_time = HZ * txcnt / info->cps; - } - if (timeout) { - exit_time = orig_jiffies + timeout - jiffies; - if (exit_time <= 0) - break; - if (exit_time < check_time) - check_time = exit_time; - } - if (check_time == 0) - check_time = 1; -#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt, - jiffies, check_time); -#endif - msleep_interruptible(jiffies_to_msecs(check_time)); - if (signal_pending(current)) - break; - } - __set_current_state(TASK_RUNNING); -#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); -#endif -} - -/* - * rp_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void rp_hangup(struct tty_struct *tty) -{ - CHANNEL_t *cp; - struct r_port *info = tty->driver_data; - unsigned long flags; - - if (rocket_paranoia_check(info, "rp_hangup")) - return; - -#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP)) - printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line); -#endif - rp_flush_buffer(tty); - spin_lock_irqsave(&info->port.lock, flags); - if (info->port.count) - atomic_dec(&rp_num_ports_open); - clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - spin_unlock_irqrestore(&info->port.lock, flags); - - tty_port_hangup(&info->port); - - cp = &info->channel; - sDisRxFIFO(cp); - sDisTransmit(cp); - sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); - sDisCTSFlowCtl(cp); - sDisTxSoftFlowCtl(cp); - sClrTxXOFF(cp); - tty_port_set_initialized(&info->port, 0); - - wake_up_interruptible(&info->port.open_wait); -} - -/* - * Exception handler - write char routine. The RocketPort driver uses a - * double-buffering strategy, with the twist that if the in-memory CPU - * buffer is empty, and there's space in the transmit FIFO, the - * writing routines will write directly to transmit FIFO. - * Write buffer and counters protected by spinlocks - */ -static int rp_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - unsigned long flags; - - if (rocket_paranoia_check(info, "rp_put_char")) - return 0; - - /* - * Grab the port write mutex, locking out other processes that try to - * write to this port - */ - mutex_lock(&info->write_mtx); - -#ifdef ROCKET_DEBUG_WRITE - printk(KERN_INFO "rp_put_char %c...\n", ch); -#endif - - spin_lock_irqsave(&info->slock, flags); - cp = &info->channel; - - if (!tty->stopped && info->xmit_fifo_room == 0) - info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - - if (tty->stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { - info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= XMIT_BUF_SIZE - 1; - info->xmit_cnt++; - set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - } else { - sOutB(sGetTxRxDataIO(cp), ch); - info->xmit_fifo_room--; - } - spin_unlock_irqrestore(&info->slock, flags); - mutex_unlock(&info->write_mtx); - return 1; -} - -/* - * Exception handler - write routine, called when user app writes to the device. - * A per port write mutex is used to protect from another process writing to - * this port at the same time. This other process could be running on the other CPU - * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). - * Spinlocks protect the info xmit members. - */ -static int rp_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - const unsigned char *b; - int c, retval = 0; - unsigned long flags; - - if (count <= 0 || rocket_paranoia_check(info, "rp_write")) - return 0; - - if (mutex_lock_interruptible(&info->write_mtx)) - return -ERESTARTSYS; - -#ifdef ROCKET_DEBUG_WRITE - printk(KERN_INFO "rp_write %d chars...\n", count); -#endif - cp = &info->channel; - - if (!tty->stopped && info->xmit_fifo_room < count) - info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - - /* - * If the write queue for the port is empty, and there is FIFO space, stuff bytes - * into FIFO. Use the write queue for temp storage. - */ - if (!tty->stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { - c = min(count, info->xmit_fifo_room); - b = buf; - - /* Push data into FIFO, 2 bytes at a time */ - sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2); - - /* If there is a byte remaining, write it */ - if (c & 1) - sOutB(sGetTxRxDataIO(cp), b[c - 1]); - - retval += c; - buf += c; - count -= c; - - spin_lock_irqsave(&info->slock, flags); - info->xmit_fifo_room -= c; - spin_unlock_irqrestore(&info->slock, flags); - } - - /* If count is zero, we wrote it all and are done */ - if (!count) - goto end; - - /* Write remaining data into the port's xmit_buf */ - while (1) { - /* Hung up ? */ - if (!tty_port_active(&info->port)) - goto end; - c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); - c = min(c, XMIT_BUF_SIZE - info->xmit_head); - if (c <= 0) - break; - - b = buf; - memcpy(info->xmit_buf + info->xmit_head, b, c); - - spin_lock_irqsave(&info->slock, flags); - info->xmit_head = - (info->xmit_head + c) & (XMIT_BUF_SIZE - 1); - info->xmit_cnt += c; - spin_unlock_irqrestore(&info->slock, flags); - - buf += c; - count -= c; - retval += c; - } - - if ((retval > 0) && !tty->stopped) - set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); - -end: - if (info->xmit_cnt < WAKEUP_CHARS) { - tty_wakeup(tty); -#ifdef ROCKETPORT_HAVE_POLL_WAIT - wake_up_interruptible(&tty->poll_wait); -#endif - } - mutex_unlock(&info->write_mtx); - return retval; -} - -/* - * Return the number of characters that can be sent. We estimate - * only using the in-memory transmit buffer only, and ignore the - * potential space in the transmit FIFO. - */ -static int rp_write_room(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - int ret; - - if (rocket_paranoia_check(info, "rp_write_room")) - return 0; - - ret = XMIT_BUF_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; -#ifdef ROCKET_DEBUG_WRITE - printk(KERN_INFO "rp_write_room returns %d...\n", ret); -#endif - return ret; -} - -/* - * Return the number of characters in the buffer. Again, this only - * counts those characters in the in-memory transmit buffer. - */ -static int rp_chars_in_buffer(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - - if (rocket_paranoia_check(info, "rp_chars_in_buffer")) - return 0; - -#ifdef ROCKET_DEBUG_WRITE - printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt); -#endif - return info->xmit_cnt; -} - -/* - * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the - * r_port struct for the port. Note that spinlock are used to protect info members, - * do not call this function if the spinlock is already held. - */ -static void rp_flush_buffer(struct tty_struct *tty) -{ - struct r_port *info = tty->driver_data; - CHANNEL_t *cp; - unsigned long flags; - - if (rocket_paranoia_check(info, "rp_flush_buffer")) - return; - - spin_lock_irqsave(&info->slock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - spin_unlock_irqrestore(&info->slock, flags); - -#ifdef ROCKETPORT_HAVE_POLL_WAIT - wake_up_interruptible(&tty->poll_wait); -#endif - tty_wakeup(tty); - - cp = &info->channel; - sFlushTxFIFO(cp); -} - -#ifdef CONFIG_PCI - -static const struct pci_device_id rocket_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4QUAD) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8OCTA) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8J) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4J) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8SNI) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16SNI) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP16INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_CRP16INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP32INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP32INTF) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP4) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP8) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_232) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_422) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP6M) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4M) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_8PORT) }, - { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_4PORT) }, - { } -}; -MODULE_DEVICE_TABLE(pci, rocket_pci_ids); - -/* Resets the speaker controller on RocketModem II and III devices */ -static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model) -{ - ByteIO_t addr; - - /* RocketModem II speaker control is at the 8th port location of offset 0x40 */ - if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) { - addr = CtlP->AiopIO[0] + 0x4F; - sOutB(addr, 0); - } - - /* RocketModem III speaker control is at the 1st port location of offset 0x80 */ - if ((model == MODEL_UPCI_RM3_8PORT) - || (model == MODEL_UPCI_RM3_4PORT)) { - addr = CtlP->AiopIO[0] + 0x88; - sOutB(addr, 0); - } -} - -/*************************************************************************** -Function: sPCIInitController -Purpose: Initialization of controller global registers and controller - structure. -Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, - IRQNum,Frequency,PeriodicOnly) - CONTROLLER_T *CtlP; Ptr to controller structure - int CtlNum; Controller number - ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. - This list must be in the order the AIOPs will be found on the - controller. Once an AIOP in the list is not found, it is - assumed that there are no more AIOPs on the controller. - int AiopIOListSize; Number of addresses in AiopIOList - int IRQNum; Interrupt Request number. Can be any of the following: - 0: Disable global interrupts - 3: IRQ 3 - 4: IRQ 4 - 5: IRQ 5 - 9: IRQ 9 - 10: IRQ 10 - 11: IRQ 11 - 12: IRQ 12 - 15: IRQ 15 - Byte_t Frequency: A flag identifying the frequency - of the periodic interrupt, can be any one of the following: - FREQ_DIS - periodic interrupt disabled - FREQ_137HZ - 137 Hertz - FREQ_69HZ - 69 Hertz - FREQ_34HZ - 34 Hertz - FREQ_17HZ - 17 Hertz - FREQ_9HZ - 9 Hertz - FREQ_4HZ - 4 Hertz - If IRQNum is set to 0 the Frequency parameter is - overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: 1 if all interrupts except the periodic - interrupt are to be blocked. - 0 is both the periodic interrupt and - other channel interrupts are allowed. - If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of 0. -Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller - initialization failed. - -Comments: - If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. - - If interrupts are to be completely disabled set IRQNum to 0. - - Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an - invalid combination. - - This function performs initialization of global interrupt modes, - but it does not actually enable global interrupts. To enable - and disable global interrupts use functions sEnGlobalInt() and - sDisGlobalInt(). Enabling of global interrupts is normally not - done until all other initializations are complete. - - Even if interrupts are globally enabled, they must also be - individually enabled for each channel that is to generate - interrupts. - -Warnings: No range checking on any of the parameters is done. - - No context switches are allowed while executing this function. - - After this function all AIOPs on the controller are disabled, - they can be enabled with sEnAiop(). -*/ -static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, - ByteIO_t * AiopIOList, int AiopIOListSize, - WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, - int PeriodicOnly, int altChanRingIndicator, - int UPCIRingInd) -{ - int i; - ByteIO_t io; - - CtlP->AltChanRingIndicator = altChanRingIndicator; - CtlP->UPCIRingInd = UPCIRingInd; - CtlP->CtlNum = CtlNum; - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - CtlP->BusType = isPCI; /* controller release 1 */ - - if (ConfigIO) { - CtlP->isUPCI = 1; - CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL; - CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL; - CtlP->AiopIntrBits = upci_aiop_intr_bits; - } else { - CtlP->isUPCI = 0; - CtlP->PCIIO = - (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC); - CtlP->AiopIntrBits = aiop_intr_bits; - } - - sPCIControllerEOI(CtlP); /* clear EOI if warm init */ - /* Init AIOPs */ - CtlP->NumAiop = 0; - for (i = 0; i < AiopIOListSize; i++) { - io = AiopIOList[i]; - CtlP->AiopIO[i] = (WordIO_t) io; - CtlP->AiopIntChanIO[i] = io + _INT_CHAN; - - CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ - if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - break; /* done looking for AIOPs */ - - CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ - sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ - sOutB(io + _INDX_DATA, sClockPrescale); - CtlP->NumAiop++; /* bump count of AIOPs */ - } - - if (CtlP->NumAiop == 0) - return (-1); - else - return (CtlP->NumAiop); -} - -/* - * Called when a PCI card is found. Retrieves and stores model information, - * init's aiopic and serial port hardware. - * Inputs: i is the board number (0-n) - */ -static __init int register_PCI(int i, struct pci_dev *dev) -{ - int num_aiops, aiop, max_num_aiops, chan; - unsigned int aiopio[MAX_AIOPS_PER_BOARD]; - CONTROLLER_t *ctlp; - - int fast_clock = 0; - int altChanRingIndicator = 0; - int ports_per_aiop = 8; - WordIO_t ConfigIO = 0; - ByteIO_t UPCIRingInd = 0; - - if (!dev || !pci_match_id(rocket_pci_ids, dev) || - pci_enable_device(dev) || i >= NUM_BOARDS) - return 0; - - rcktpt_io_addr[i] = pci_resource_start(dev, 0); - - rcktpt_type[i] = ROCKET_TYPE_NORMAL; - rocketModel[i].loadrm2 = 0; - rocketModel[i].startingPortNumber = nextLineNumber; - - /* Depending on the model, set up some config variables */ - switch (dev->device) { - case PCI_DEVICE_ID_RP4QUAD: - max_num_aiops = 1; - ports_per_aiop = 4; - rocketModel[i].model = MODEL_RP4QUAD; - strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable"); - rocketModel[i].numPorts = 4; - break; - case PCI_DEVICE_ID_RP8OCTA: - max_num_aiops = 1; - rocketModel[i].model = MODEL_RP8OCTA; - strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_URP8OCTA: - max_num_aiops = 1; - rocketModel[i].model = MODEL_UPCI_RP8OCTA; - strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP8INTF: - max_num_aiops = 1; - rocketModel[i].model = MODEL_RP8INTF; - strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_URP8INTF: - max_num_aiops = 1; - rocketModel[i].model = MODEL_UPCI_RP8INTF; - strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP8J: - max_num_aiops = 1; - rocketModel[i].model = MODEL_RP8J; - strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP4J: - max_num_aiops = 1; - ports_per_aiop = 4; - rocketModel[i].model = MODEL_RP4J; - strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors"); - rocketModel[i].numPorts = 4; - break; - case PCI_DEVICE_ID_RP8SNI: - max_num_aiops = 1; - rocketModel[i].model = MODEL_RP8SNI; - strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP16SNI: - max_num_aiops = 2; - rocketModel[i].model = MODEL_RP16SNI; - strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78"); - rocketModel[i].numPorts = 16; - break; - case PCI_DEVICE_ID_RP16INTF: - max_num_aiops = 2; - rocketModel[i].model = MODEL_RP16INTF; - strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F"); - rocketModel[i].numPorts = 16; - break; - case PCI_DEVICE_ID_URP16INTF: - max_num_aiops = 2; - rocketModel[i].model = MODEL_UPCI_RP16INTF; - strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F"); - rocketModel[i].numPorts = 16; - break; - case PCI_DEVICE_ID_CRP16INTF: - max_num_aiops = 2; - rocketModel[i].model = MODEL_CPCI_RP16INTF; - strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F"); - rocketModel[i].numPorts = 16; - break; - case PCI_DEVICE_ID_RP32INTF: - max_num_aiops = 4; - rocketModel[i].model = MODEL_RP32INTF; - strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F"); - rocketModel[i].numPorts = 32; - break; - case PCI_DEVICE_ID_URP32INTF: - max_num_aiops = 4; - rocketModel[i].model = MODEL_UPCI_RP32INTF; - strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F"); - rocketModel[i].numPorts = 32; - break; - case PCI_DEVICE_ID_RPP4: - max_num_aiops = 1; - ports_per_aiop = 4; - altChanRingIndicator++; - fast_clock++; - rocketModel[i].model = MODEL_RPP4; - strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port"); - rocketModel[i].numPorts = 4; - break; - case PCI_DEVICE_ID_RPP8: - max_num_aiops = 2; - ports_per_aiop = 4; - altChanRingIndicator++; - fast_clock++; - rocketModel[i].model = MODEL_RPP8; - strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port"); - rocketModel[i].numPorts = 8; - break; - case PCI_DEVICE_ID_RP2_232: - max_num_aiops = 1; - ports_per_aiop = 2; - altChanRingIndicator++; - fast_clock++; - rocketModel[i].model = MODEL_RP2_232; - strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232"); - rocketModel[i].numPorts = 2; - break; - case PCI_DEVICE_ID_RP2_422: - max_num_aiops = 1; - ports_per_aiop = 2; - altChanRingIndicator++; - fast_clock++; - rocketModel[i].model = MODEL_RP2_422; - strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422"); - rocketModel[i].numPorts = 2; - break; - case PCI_DEVICE_ID_RP6M: - - max_num_aiops = 1; - ports_per_aiop = 6; - - /* If revision is 1, the rocketmodem flash must be loaded. - * If it is 2 it is a "socketed" version. */ - if (dev->revision == 1) { - rcktpt_type[i] = ROCKET_TYPE_MODEMII; - rocketModel[i].loadrm2 = 1; - } else { - rcktpt_type[i] = ROCKET_TYPE_MODEM; - } - - rocketModel[i].model = MODEL_RP6M; - strcpy(rocketModel[i].modelString, "RocketModem 6 port"); - rocketModel[i].numPorts = 6; - break; - case PCI_DEVICE_ID_RP4M: - max_num_aiops = 1; - ports_per_aiop = 4; - if (dev->revision == 1) { - rcktpt_type[i] = ROCKET_TYPE_MODEMII; - rocketModel[i].loadrm2 = 1; - } else { - rcktpt_type[i] = ROCKET_TYPE_MODEM; - } - - rocketModel[i].model = MODEL_RP4M; - strcpy(rocketModel[i].modelString, "RocketModem 4 port"); - rocketModel[i].numPorts = 4; - break; - default: - max_num_aiops = 0; - break; - } - - /* - * Check for UPCI boards. - */ - - switch (dev->device) { - case PCI_DEVICE_ID_URP32INTF: - case PCI_DEVICE_ID_URP8INTF: - case PCI_DEVICE_ID_URP16INTF: - case PCI_DEVICE_ID_CRP16INTF: - case PCI_DEVICE_ID_URP8OCTA: - rcktpt_io_addr[i] = pci_resource_start(dev, 2); - ConfigIO = pci_resource_start(dev, 1); - if (dev->device == PCI_DEVICE_ID_URP8OCTA) { - UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; - - /* - * Check for octa or quad cable. - */ - if (! - (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) & - PCI_GPIO_CTRL_8PORT)) { - ports_per_aiop = 4; - rocketModel[i].numPorts = 4; - } - } - break; - case PCI_DEVICE_ID_UPCI_RM3_8PORT: - max_num_aiops = 1; - rocketModel[i].model = MODEL_UPCI_RM3_8PORT; - strcpy(rocketModel[i].modelString, "RocketModem III 8 port"); - rocketModel[i].numPorts = 8; - rcktpt_io_addr[i] = pci_resource_start(dev, 2); - UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; - ConfigIO = pci_resource_start(dev, 1); - rcktpt_type[i] = ROCKET_TYPE_MODEMIII; - break; - case PCI_DEVICE_ID_UPCI_RM3_4PORT: - max_num_aiops = 1; - rocketModel[i].model = MODEL_UPCI_RM3_4PORT; - strcpy(rocketModel[i].modelString, "RocketModem III 4 port"); - rocketModel[i].numPorts = 4; - rcktpt_io_addr[i] = pci_resource_start(dev, 2); - UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; - ConfigIO = pci_resource_start(dev, 1); - rcktpt_type[i] = ROCKET_TYPE_MODEMIII; - break; - default: - break; - } - - if (fast_clock) { - sClockPrescale = 0x12; /* mod 2 (divide by 3) */ - rp_baud_base[i] = 921600; - } else { - /* - * If support_low_speed is set, use the slow clock - * prescale, which supports 50 bps - */ - if (support_low_speed) { - /* mod 9 (divide by 10) prescale */ - sClockPrescale = 0x19; - rp_baud_base[i] = 230400; - } else { - /* mod 4 (divide by 5) prescale */ - sClockPrescale = 0x14; - rp_baud_base[i] = 460800; - } - } - - for (aiop = 0; aiop < max_num_aiops; aiop++) - aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40); - ctlp = sCtlNumToCtlPtr(i); - num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd); - for (aiop = 0; aiop < max_num_aiops; aiop++) - ctlp->AiopNumChan[aiop] = ports_per_aiop; - - dev_info(&dev->dev, "comtrol PCI controller #%d found at " - "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n", - i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString, - rocketModel[i].startingPortNumber, - rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1); - - if (num_aiops <= 0) { - rcktpt_io_addr[i] = 0; - return (0); - } - is_PCI[i] = 1; - - /* Reset the AIOPIC, init the serial ports */ - for (aiop = 0; aiop < num_aiops; aiop++) { - sResetAiopByNum(ctlp, aiop); - for (chan = 0; chan < ports_per_aiop; chan++) - init_r_port(i, aiop, chan, dev); - } - - /* Rocket modems must be reset */ - if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || - (rcktpt_type[i] == ROCKET_TYPE_MODEMII) || - (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) { - for (chan = 0; chan < ports_per_aiop; chan++) - sPCIModemReset(ctlp, chan, 1); - msleep(500); - for (chan = 0; chan < ports_per_aiop; chan++) - sPCIModemReset(ctlp, chan, 0); - msleep(500); - rmSpeakerReset(ctlp, rocketModel[i].model); - } - return (1); -} - -/* - * Probes for PCI cards, inits them if found - * Input: board_found = number of ISA boards already found, or the - * starting board number - * Returns: Number of PCI boards found - */ -static int __init init_PCI(int boards_found) -{ - struct pci_dev *dev = NULL; - int count = 0; - - /* Work through the PCI device list, pulling out ours */ - while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) { - if (register_PCI(count + boards_found, dev)) - count++; - } - return (count); -} - -#endif /* CONFIG_PCI */ - -/* - * Probes for ISA cards - * Input: i = the board number to look for - * Returns: 1 if board found, 0 else - */ -static int __init init_ISA(int i) -{ - int num_aiops, num_chan = 0, total_num_chan = 0; - int aiop, chan; - unsigned int aiopio[MAX_AIOPS_PER_BOARD]; - CONTROLLER_t *ctlp; - char *type_string; - - /* If io_addr is zero, no board configured */ - if (rcktpt_io_addr[i] == 0) - return (0); - - /* Reserve the IO region */ - if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) { - printk(KERN_ERR "Unable to reserve IO region for configured " - "ISA RocketPort at address 0x%lx, board not " - "installed...\n", rcktpt_io_addr[i]); - rcktpt_io_addr[i] = 0; - return (0); - } - - ctlp = sCtlNumToCtlPtr(i); - - ctlp->boardType = rcktpt_type[i]; - - switch (rcktpt_type[i]) { - case ROCKET_TYPE_PC104: - type_string = "(PC104)"; - break; - case ROCKET_TYPE_MODEM: - type_string = "(RocketModem)"; - break; - case ROCKET_TYPE_MODEMII: - type_string = "(RocketModem II)"; - break; - default: - type_string = ""; - break; - } - - /* - * If support_low_speed is set, use the slow clock prescale, - * which supports 50 bps - */ - if (support_low_speed) { - sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */ - rp_baud_base[i] = 230400; - } else { - sClockPrescale = 0x14; /* mod 4 (divide by 5) prescale */ - rp_baud_base[i] = 460800; - } - - for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++) - aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400); - - num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0); - - if (ctlp->boardType == ROCKET_TYPE_PC104) { - sEnAiop(ctlp, 2); /* only one AIOPIC, but these */ - sEnAiop(ctlp, 3); /* CSels used for other stuff */ - } - - /* If something went wrong initing the AIOP's release the ISA IO memory */ - if (num_aiops <= 0) { - release_region(rcktpt_io_addr[i], 64); - rcktpt_io_addr[i] = 0; - return (0); - } - - rocketModel[i].startingPortNumber = nextLineNumber; - - for (aiop = 0; aiop < num_aiops; aiop++) { - sResetAiopByNum(ctlp, aiop); - sEnAiop(ctlp, aiop); - num_chan = sGetAiopNumChan(ctlp, aiop); - total_num_chan += num_chan; - for (chan = 0; chan < num_chan; chan++) - init_r_port(i, aiop, chan, NULL); - } - is_PCI[i] = 0; - if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) { - num_chan = sGetAiopNumChan(ctlp, 0); - total_num_chan = num_chan; - for (chan = 0; chan < num_chan; chan++) - sModemReset(ctlp, chan, 1); - msleep(500); - for (chan = 0; chan < num_chan; chan++) - sModemReset(ctlp, chan, 0); - msleep(500); - strcpy(rocketModel[i].modelString, "RocketModem ISA"); - } else { - strcpy(rocketModel[i].modelString, "RocketPort ISA"); - } - rocketModel[i].numPorts = total_num_chan; - rocketModel[i].model = MODEL_ISA; - - printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n", - i, rcktpt_io_addr[i], num_aiops, type_string); - - printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n", - rocketModel[i].modelString, - rocketModel[i].startingPortNumber, - rocketModel[i].startingPortNumber + - rocketModel[i].numPorts - 1); - - return (1); -} - -static const struct tty_operations rocket_ops = { - .open = rp_open, - .close = rp_close, - .write = rp_write, - .put_char = rp_put_char, - .write_room = rp_write_room, - .chars_in_buffer = rp_chars_in_buffer, - .flush_buffer = rp_flush_buffer, - .ioctl = rp_ioctl, - .throttle = rp_throttle, - .unthrottle = rp_unthrottle, - .set_termios = rp_set_termios, - .stop = rp_stop, - .start = rp_start, - .hangup = rp_hangup, - .break_ctl = rp_break, - .send_xchar = rp_send_xchar, - .wait_until_sent = rp_wait_until_sent, - .tiocmget = rp_tiocmget, - .tiocmset = rp_tiocmset, -}; - -static const struct tty_port_operations rocket_port_ops = { - .carrier_raised = carrier_raised, - .dtr_rts = dtr_rts, -}; - -/* - * The module "startup" routine; it's run when the module is loaded. - */ -static int __init rp_init(void) -{ - int ret = -ENOMEM, pci_boards_found, isa_boards_found, i; - - printk(KERN_INFO "RocketPort device driver module, version %s, %s\n", - ROCKET_VERSION, ROCKET_DATE); - - rocket_driver = alloc_tty_driver(MAX_RP_PORTS); - if (!rocket_driver) - goto err; - - /* - * If board 1 is non-zero, there is at least one ISA configured. If controller is - * zero, use the default controller IO address of board1 + 0x40. - */ - if (board1) { - if (controller == 0) - controller = board1 + 0x40; - } else { - controller = 0; /* Used as a flag, meaning no ISA boards */ - } - - /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */ - if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) { - printk(KERN_ERR "Unable to reserve IO region for first " - "configured ISA RocketPort controller 0x%lx. " - "Driver exiting\n", controller); - ret = -EBUSY; - goto err_tty; - } - - /* Store ISA variable retrieved from command line or .conf file. */ - rcktpt_io_addr[0] = board1; - rcktpt_io_addr[1] = board2; - rcktpt_io_addr[2] = board3; - rcktpt_io_addr[3] = board4; - - rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; - rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0]; - rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; - rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1]; - rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; - rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2]; - rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; - rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3]; - - /* - * Set up the tty driver structure and then register this - * driver with the tty layer. - */ - - rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV; - rocket_driver->name = "ttyR"; - rocket_driver->driver_name = "Comtrol RocketPort"; - rocket_driver->major = TTY_ROCKET_MAJOR; - rocket_driver->minor_start = 0; - rocket_driver->type = TTY_DRIVER_TYPE_SERIAL; - rocket_driver->subtype = SERIAL_TYPE_NORMAL; - rocket_driver->init_termios = tty_std_termios; - rocket_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - rocket_driver->init_termios.c_ispeed = 9600; - rocket_driver->init_termios.c_ospeed = 9600; -#ifdef ROCKET_SOFT_FLOW - rocket_driver->flags |= TTY_DRIVER_REAL_RAW; -#endif - tty_set_operations(rocket_driver, &rocket_ops); - - ret = tty_register_driver(rocket_driver); - if (ret < 0) { - printk(KERN_ERR "Couldn't install tty RocketPort driver\n"); - goto err_controller; - } - -#ifdef ROCKET_DEBUG_OPEN - printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major); -#endif - - /* - * OK, let's probe each of the controllers looking for boards. Any boards found - * will be initialized here. - */ - isa_boards_found = 0; - pci_boards_found = 0; - - for (i = 0; i < NUM_BOARDS; i++) { - if (init_ISA(i)) - isa_boards_found++; - } - -#ifdef CONFIG_PCI - if (isa_boards_found < NUM_BOARDS) - pci_boards_found = init_PCI(isa_boards_found); -#endif - - max_board = pci_boards_found + isa_boards_found; - - if (max_board == 0) { - printk(KERN_ERR "No rocketport ports found; unloading driver\n"); - ret = -ENXIO; - goto err_ttyu; - } - - return 0; -err_ttyu: - tty_unregister_driver(rocket_driver); -err_controller: - if (controller) - release_region(controller, 4); -err_tty: - put_tty_driver(rocket_driver); -err: - return ret; -} - - -static void rp_cleanup_module(void) -{ - int retval; - int i; - - del_timer_sync(&rocket_timer); - - retval = tty_unregister_driver(rocket_driver); - if (retval) - printk(KERN_ERR "Error %d while trying to unregister " - "rocketport driver\n", -retval); - - for (i = 0; i < MAX_RP_PORTS; i++) - if (rp_table[i]) { - tty_unregister_device(rocket_driver, i); - tty_port_destroy(&rp_table[i]->port); - kfree(rp_table[i]); - } - - put_tty_driver(rocket_driver); - - for (i = 0; i < NUM_BOARDS; i++) { - if (rcktpt_io_addr[i] <= 0 || is_PCI[i]) - continue; - release_region(rcktpt_io_addr[i], 64); - } - if (controller) - release_region(controller, 4); -} - -/*************************************************************************** -Function: sInitController -Purpose: Initialization of controller global registers and controller - structure. -Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize, - IRQNum,Frequency,PeriodicOnly) - CONTROLLER_T *CtlP; Ptr to controller structure - int CtlNum; Controller number - ByteIO_t MudbacIO; Mudbac base I/O address. - ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. - This list must be in the order the AIOPs will be found on the - controller. Once an AIOP in the list is not found, it is - assumed that there are no more AIOPs on the controller. - int AiopIOListSize; Number of addresses in AiopIOList - int IRQNum; Interrupt Request number. Can be any of the following: - 0: Disable global interrupts - 3: IRQ 3 - 4: IRQ 4 - 5: IRQ 5 - 9: IRQ 9 - 10: IRQ 10 - 11: IRQ 11 - 12: IRQ 12 - 15: IRQ 15 - Byte_t Frequency: A flag identifying the frequency - of the periodic interrupt, can be any one of the following: - FREQ_DIS - periodic interrupt disabled - FREQ_137HZ - 137 Hertz - FREQ_69HZ - 69 Hertz - FREQ_34HZ - 34 Hertz - FREQ_17HZ - 17 Hertz - FREQ_9HZ - 9 Hertz - FREQ_4HZ - 4 Hertz - If IRQNum is set to 0 the Frequency parameter is - overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: 1 if all interrupts except the periodic - interrupt are to be blocked. - 0 is both the periodic interrupt and - other channel interrupts are allowed. - If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of 0. -Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller - initialization failed. - -Comments: - If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. - - If interrupts are to be completely disabled set IRQNum to 0. - - Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an - invalid combination. - - This function performs initialization of global interrupt modes, - but it does not actually enable global interrupts. To enable - and disable global interrupts use functions sEnGlobalInt() and - sDisGlobalInt(). Enabling of global interrupts is normally not - done until all other initializations are complete. - - Even if interrupts are globally enabled, they must also be - individually enabled for each channel that is to generate - interrupts. - -Warnings: No range checking on any of the parameters is done. - - No context switches are allowed while executing this function. - - After this function all AIOPs on the controller are disabled, - they can be enabled with sEnAiop(). -*/ -static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, - ByteIO_t * AiopIOList, int AiopIOListSize, - int IRQNum, Byte_t Frequency, int PeriodicOnly) -{ - int i; - ByteIO_t io; - int done; - - CtlP->AiopIntrBits = aiop_intr_bits; - CtlP->AltChanRingIndicator = 0; - CtlP->CtlNum = CtlNum; - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - CtlP->BusType = isISA; - CtlP->MBaseIO = MudbacIO; - CtlP->MReg1IO = MudbacIO + 1; - CtlP->MReg2IO = MudbacIO + 2; - CtlP->MReg3IO = MudbacIO + 3; -#if 1 - CtlP->MReg2 = 0; /* interrupt disable */ - CtlP->MReg3 = 0; /* no periodic interrupts */ -#else - if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */ - CtlP->MReg2 = 0; /* interrupt disable */ - CtlP->MReg3 = 0; /* no periodic interrupts */ - } else { - CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ - CtlP->MReg3 = Frequency; /* set frequency */ - if (PeriodicOnly) { /* periodic interrupt only */ - CtlP->MReg3 |= PERIODIC_ONLY; - } - } -#endif - sOutB(CtlP->MReg2IO, CtlP->MReg2); - sOutB(CtlP->MReg3IO, CtlP->MReg3); - sControllerEOI(CtlP); /* clear EOI if warm init */ - /* Init AIOPs */ - CtlP->NumAiop = 0; - for (i = done = 0; i < AiopIOListSize; i++) { - io = AiopIOList[i]; - CtlP->AiopIO[i] = (WordIO_t) io; - CtlP->AiopIntChanIO[i] = io + _INT_CHAN; - sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */ - sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */ - if (done) - continue; - sEnAiop(CtlP, i); /* enable the AIOP */ - CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ - if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - done = 1; /* done looking for AIOPs */ - else { - CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ - sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ - sOutB(io + _INDX_DATA, sClockPrescale); - CtlP->NumAiop++; /* bump count of AIOPs */ - } - sDisAiop(CtlP, i); /* disable AIOP */ - } - - if (CtlP->NumAiop == 0) - return (-1); - else - return (CtlP->NumAiop); -} - -/*************************************************************************** -Function: sReadAiopID -Purpose: Read the AIOP idenfication number directly from an AIOP. -Call: sReadAiopID(io) - ByteIO_t io: AIOP base I/O address -Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X - is replace by an identifying number. - Flag AIOPID_NULL if no valid AIOP is found -Warnings: No context switches are allowed while executing this function. - -*/ -static int sReadAiopID(ByteIO_t io) -{ - Byte_t AiopID; /* ID byte from AIOP */ - - sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */ - sOutB(io + _CMD_REG, 0x0); - AiopID = sInW(io + _CHN_STAT0) & 0x07; - if (AiopID == 0x06) - return (1); - else /* AIOP does not exist */ - return (-1); -} - -/*************************************************************************** -Function: sReadAiopNumChan -Purpose: Read the number of channels available in an AIOP directly from - an AIOP. -Call: sReadAiopNumChan(io) - WordIO_t io: AIOP base I/O address -Return: int: The number of channels available -Comments: The number of channels is determined by write/reads from identical - offsets within the SRAM address spaces for channels 0 and 4. - If the channel 4 space is mirrored to channel 0 it is a 4 channel - AIOP, otherwise it is an 8 channel. -Warnings: No context switches are allowed while executing this function. -*/ -static int sReadAiopNumChan(WordIO_t io) -{ - Word_t x; - static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; - - /* write to chan 0 SRAM */ - out32((DWordIO_t) io + _INDX_ADDR, R); - sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */ - x = sInW(io + _INDX_DATA); - sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */ - if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */ - return (8); - else - return (4); -} - -/*************************************************************************** -Function: sInitChan -Purpose: Initialization of a channel and channel structure -Call: sInitChan(CtlP,ChP,AiopNum,ChanNum) - CONTROLLER_T *CtlP; Ptr to controller structure - CHANNEL_T *ChP; Ptr to channel structure - int AiopNum; AIOP number within controller - int ChanNum; Channel number within AIOP -Return: int: 1 if initialization succeeded, 0 if it fails because channel - number exceeds number of channels available in AIOP. -Comments: This function must be called before a channel can be used. -Warnings: No range checking on any of the parameters is done. - - No context switches are allowed while executing this function. -*/ -static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, - int ChanNum) -{ - int i; - WordIO_t AiopIO; - WordIO_t ChIOOff; - Byte_t *ChR; - Word_t ChOff; - static Byte_t R[4]; - int brd9600; - - if (ChanNum >= CtlP->AiopNumChan[AiopNum]) - return 0; /* exceeds num chans in AIOP */ - - /* Channel, AIOP, and controller identifiers */ - ChP->CtlP = CtlP; - ChP->ChanID = CtlP->AiopID[AiopNum]; - ChP->AiopNum = AiopNum; - ChP->ChanNum = ChanNum; - - /* Global direct addresses */ - AiopIO = CtlP->AiopIO[AiopNum]; - ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG; - ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN; - ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK; - ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR; - ChP->IndexData = AiopIO + _INDX_DATA; - - /* Channel direct addresses */ - ChIOOff = AiopIO + ChP->ChanNum * 2; - ChP->TxRxData = ChIOOff + _TD0; - ChP->ChanStat = ChIOOff + _CHN_STAT0; - ChP->TxRxCount = ChIOOff + _FIFO_CNT0; - ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0; - - /* Initialize the channel from the RData array */ - for (i = 0; i < RDATASIZE; i += 4) { - R[0] = RData[i]; - R[1] = RData[i + 1] + 0x10 * ChanNum; - R[2] = RData[i + 2]; - R[3] = RData[i + 3]; - out32(ChP->IndexAddr, R); - } - - ChR = ChP->R; - for (i = 0; i < RREGDATASIZE; i += 4) { - ChR[i] = RRegData[i]; - ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum; - ChR[i + 2] = RRegData[i + 2]; - ChR[i + 3] = RRegData[i + 3]; - } - - /* Indexed registers */ - ChOff = (Word_t) ChanNum *0x1000; - - if (sClockPrescale == 0x14) - brd9600 = 47; - else - brd9600 = 23; - - ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD); - ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8); - ChP->BaudDiv[2] = (Byte_t) brd9600; - ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8); - out32(ChP->IndexAddr, ChP->BaudDiv); - - ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL); - ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8); - ChP->TxControl[2] = 0; - ChP->TxControl[3] = 0; - out32(ChP->IndexAddr, ChP->TxControl); - - ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL); - ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8); - ChP->RxControl[2] = 0; - ChP->RxControl[3] = 0; - out32(ChP->IndexAddr, ChP->RxControl); - - ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS); - ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8); - ChP->TxEnables[2] = 0; - ChP->TxEnables[3] = 0; - out32(ChP->IndexAddr, ChP->TxEnables); - - ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1); - ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8); - ChP->TxCompare[2] = 0; - ChP->TxCompare[3] = 0; - out32(ChP->IndexAddr, ChP->TxCompare); - - ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1); - ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8); - ChP->TxReplace1[2] = 0; - ChP->TxReplace1[3] = 0; - out32(ChP->IndexAddr, ChP->TxReplace1); - - ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2); - ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8); - ChP->TxReplace2[2] = 0; - ChP->TxReplace2[3] = 0; - out32(ChP->IndexAddr, ChP->TxReplace2); - - ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; - ChP->TxFIFO = ChOff + _TX_FIFO; - - sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ - sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */ - sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - sOutW(ChP->IndexData, 0); - ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; - ChP->RxFIFO = ChOff + _RX_FIFO; - - sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ - sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */ - sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ - sOutW(ChP->IndexData, 0); - sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - sOutW(ChP->IndexData, 0); - ChP->TxPrioCnt = ChOff + _TXP_CNT; - sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt); - sOutB(ChP->IndexData, 0); - ChP->TxPrioPtr = ChOff + _TXP_PNTR; - sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr); - sOutB(ChP->IndexData, 0); - ChP->TxPrioBuf = ChOff + _TXP_BUF; - sEnRxProcessor(ChP); /* start the Rx processor */ - - return 1; -} - -/*************************************************************************** -Function: sStopRxProcessor -Purpose: Stop the receive processor from processing a channel. -Call: sStopRxProcessor(ChP) - CHANNEL_T *ChP; Ptr to channel structure - -Comments: The receive processor can be started again with sStartRxProcessor(). - This function causes the receive processor to skip over the - stopped channel. It does not stop it from processing other channels. - -Warnings: No context switches are allowed while executing this function. - - Do not leave the receive processor stopped for more than one - character time. - - After calling this function a delay of 4 uS is required to ensure - that the receive processor is no longer processing this channel. -*/ -static void sStopRxProcessor(CHANNEL_T * ChP) -{ - Byte_t R[4]; - - R[0] = ChP->R[0]; - R[1] = ChP->R[1]; - R[2] = 0x0a; - R[3] = ChP->R[3]; - out32(ChP->IndexAddr, R); -} - -/*************************************************************************** -Function: sFlushRxFIFO -Purpose: Flush the Rx FIFO -Call: sFlushRxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: void -Comments: To prevent data from being enqueued or dequeued in the Tx FIFO - while it is being flushed the receive processor is stopped - and the transmitter is disabled. After these operations a - 4 uS delay is done before clearing the pointers to allow - the receive processor to stop. These items are handled inside - this function. -Warnings: No context switches are allowed while executing this function. -*/ -static void sFlushRxFIFO(CHANNEL_T * ChP) -{ - int i; - Byte_t Ch; /* channel number within AIOP */ - int RxFIFOEnabled; /* 1 if Rx FIFO enabled */ - - if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ - return; /* don't need to flush */ - - RxFIFOEnabled = 0; - if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ - RxFIFOEnabled = 1; - sDisRxFIFO(ChP); /* disable it */ - for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ - sInB(ChP->IntChan); /* depends on bus i/o timing */ - } - sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ - Ch = (Byte_t) sGetChanNum(ChP); - sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */ - sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */ - sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ - sOutW(ChP->IndexData, 0); - sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - sOutW(ChP->IndexData, 0); - if (RxFIFOEnabled) - sEnRxFIFO(ChP); /* enable Rx FIFO */ -} - -/*************************************************************************** -Function: sFlushTxFIFO -Purpose: Flush the Tx FIFO -Call: sFlushTxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: void -Comments: To prevent data from being enqueued or dequeued in the Tx FIFO - while it is being flushed the receive processor is stopped - and the transmitter is disabled. After these operations a - 4 uS delay is done before clearing the pointers to allow - the receive processor to stop. These items are handled inside - this function. -Warnings: No context switches are allowed while executing this function. -*/ -static void sFlushTxFIFO(CHANNEL_T * ChP) -{ - int i; - Byte_t Ch; /* channel number within AIOP */ - int TxEnabled; /* 1 if transmitter enabled */ - - if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ - return; /* don't need to flush */ - - TxEnabled = 0; - if (ChP->TxControl[3] & TX_ENABLE) { - TxEnabled = 1; - sDisTransmit(ChP); /* disable transmitter */ - } - sStopRxProcessor(ChP); /* stop Rx processor */ - for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */ - sInB(ChP->IntChan); /* depends on bus i/o timing */ - Ch = (Byte_t) sGetChanNum(ChP); - sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */ - sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */ - sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - sOutW(ChP->IndexData, 0); - if (TxEnabled) - sEnTransmit(ChP); /* enable transmitter */ - sStartRxProcessor(ChP); /* restart Rx processor */ -} - -/*************************************************************************** -Function: sWriteTxPrioByte -Purpose: Write a byte of priority transmit data to a channel -Call: sWriteTxPrioByte(ChP,Data) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Data; The transmit data byte - -Return: int: 1 if the bytes is successfully written, otherwise 0. - -Comments: The priority byte is transmitted before any data in the Tx FIFO. - -Warnings: No context switches are allowed while executing this function. -*/ -static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) -{ - Byte_t DWBuf[4]; /* buffer for double word writes */ - Word_t *WordPtr; /* must be far because Win SS != DS */ - register DWordIO_t IndexAddr; - - if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */ - IndexAddr = ChP->IndexAddr; - sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */ - if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */ - return (0); /* nothing sent */ - - WordPtr = (Word_t *) (&DWBuf[0]); - *WordPtr = ChP->TxPrioBuf; /* data byte address */ - - DWBuf[2] = Data; /* data byte value */ - out32(IndexAddr, DWBuf); /* write it out */ - - *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ - - DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ - DWBuf[3] = 0; /* priority buffer pointer */ - out32(IndexAddr, DWBuf); /* write it out */ - } else { /* write it to Tx FIFO */ - - sWriteTxByte(sGetTxRxDataIO(ChP), Data); - } - return (1); /* 1 byte sent */ -} - -/*************************************************************************** -Function: sEnInterrupts -Purpose: Enable one or more interrupts for a channel -Call: sEnInterrupts(ChP,Flags) - CHANNEL_T *ChP; Ptr to channel structure - Word_t Flags: Interrupt enable flags, can be any combination - of the following flags: - TXINT_EN: Interrupt on Tx FIFO empty - RXINT_EN: Interrupt on Rx FIFO at trigger level (see - sSetRxTrigger()) - SRCINT_EN: Interrupt on SRC (Special Rx Condition) - MCINT_EN: Interrupt on modem input change - CHANINT_EN: Allow channel interrupt signal to the AIOP's - Interrupt Channel Register. -Return: void -Comments: If an interrupt enable flag is set in Flags, that interrupt will be - enabled. If an interrupt enable flag is not set in Flags, that - interrupt will not be changed. Interrupts can be disabled with - function sDisInterrupts(). - - This function sets the appropriate bit for the channel in the AIOP's - Interrupt Mask Register if the CHANINT_EN flag is set. This allows - this channel's bit to be set in the AIOP's Interrupt Channel Register. - - Interrupts must also be globally enabled before channel interrupts - will be passed on to the host. This is done with function - sEnGlobalInt(). - - In some cases it may be desirable to disable interrupts globally but - enable channel interrupts. This would allow the global interrupt - status register to be used to determine which AIOPs need service. -*/ -static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) -{ - Byte_t Mask; /* Interrupt Mask Register */ - - ChP->RxControl[2] |= - ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - - out32(ChP->IndexAddr, ChP->RxControl); - - ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN); - - out32(ChP->IndexAddr, ChP->TxControl); - - if (Flags & CHANINT_EN) { - Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; - sOutB(ChP->IntMask, Mask); - } -} - -/*************************************************************************** -Function: sDisInterrupts -Purpose: Disable one or more interrupts for a channel -Call: sDisInterrupts(ChP,Flags) - CHANNEL_T *ChP; Ptr to channel structure - Word_t Flags: Interrupt flags, can be any combination - of the following flags: - TXINT_EN: Interrupt on Tx FIFO empty - RXINT_EN: Interrupt on Rx FIFO at trigger level (see - sSetRxTrigger()) - SRCINT_EN: Interrupt on SRC (Special Rx Condition) - MCINT_EN: Interrupt on modem input change - CHANINT_EN: Disable channel interrupt signal to the - AIOP's Interrupt Channel Register. -Return: void -Comments: If an interrupt flag is set in Flags, that interrupt will be - disabled. If an interrupt flag is not set in Flags, that - interrupt will not be changed. Interrupts can be enabled with - function sEnInterrupts(). - - This function clears the appropriate bit for the channel in the AIOP's - Interrupt Mask Register if the CHANINT_EN flag is set. This blocks - this channel's bit from being set in the AIOP's Interrupt Channel - Register. -*/ -static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) -{ - Byte_t Mask; /* Interrupt Mask Register */ - - ChP->RxControl[2] &= - ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - out32(ChP->IndexAddr, ChP->RxControl); - ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN); - out32(ChP->IndexAddr, ChP->TxControl); - - if (Flags & CHANINT_EN) { - Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; - sOutB(ChP->IntMask, Mask); - } -} - -static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) -{ - sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); -} - -/* - * Not an official SSCI function, but how to reset RocketModems. - * ISA bus version - */ -static void sModemReset(CONTROLLER_T * CtlP, int chan, int on) -{ - ByteIO_t addr; - Byte_t val; - - addr = CtlP->AiopIO[0] + 0x400; - val = sInB(CtlP->MReg3IO); - /* if AIOP[1] is not enabled, enable it */ - if ((val & 2) == 0) { - val = sInB(CtlP->MReg2IO); - sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03)); - sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6)); - } - - sEnAiop(CtlP, 1); - if (!on) - addr += 8; - sOutB(addr + chan, 0); /* apply or remove reset */ - sDisAiop(CtlP, 1); -} - -/* - * Not an official SSCI function, but how to reset RocketModems. - * PCI bus version - */ -static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) -{ - ByteIO_t addr; - - addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */ - if (!on) - addr += 8; - sOutB(addr + chan, 0); /* apply or remove reset */ -} - -/* Returns the line number given the controller (board), aiop and channel number */ -static unsigned char GetLineNumber(int ctrl, int aiop, int ch) -{ - return lineNumbers[(ctrl << 5) | (aiop << 3) | ch]; -} - -/* - * Stores the line number associated with a given controller (board), aiop - * and channel number. - * Returns: The line number assigned - */ -static unsigned char SetLineNumber(int ctrl, int aiop, int ch) -{ - lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++; - return (nextLineNumber - 1); -} diff --git a/drivers/tty/rocket.h b/drivers/tty/rocket.h deleted file mode 100644 index d62ed6587f32..000000000000 --- a/drivers/tty/rocket.h +++ /dev/null @@ -1,111 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * rocket.h --- the exported interface of the rocket driver to its configuration program. - * - * Written by Theodore Ts'o, Copyright 1997. - * Copyright 1997 Comtrol Corporation. - * - */ - -/* Model Information Struct */ -typedef struct { - unsigned long model; - char modelString[80]; - unsigned long numPorts; - int loadrm2; - int startingPortNumber; -} rocketModel_t; - -struct rocket_config { - int line; - int flags; - int closing_wait; - int close_delay; - int port; - int reserved[32]; -}; - -struct rocket_ports { - int tty_major; - int callout_major; - rocketModel_t rocketModel[8]; -}; - -struct rocket_version { - char rocket_version[32]; - char rocket_date[32]; - char reserved[64]; -}; - -/* - * Rocketport flags - */ -/*#define ROCKET_CALLOUT_NOHUP 0x00000001 */ -#define ROCKET_FORCE_CD 0x00000002 -#define ROCKET_HUP_NOTIFY 0x00000004 -#define ROCKET_SPLIT_TERMIOS 0x00000008 -#define ROCKET_SPD_MASK 0x00000070 -#define ROCKET_SPD_HI 0x00000010 /* Use 57600 instead of 38400 bps */ -#define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */ -#define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */ -#define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */ -#define ROCKET_SAK 0x00000080 -#define ROCKET_SESSION_LOCKOUT 0x00000100 -#define ROCKET_PGRP_LOCKOUT 0x00000200 -#define ROCKET_RTS_TOGGLE 0x00000400 -#define ROCKET_MODE_MASK 0x00003000 -#define ROCKET_MODE_RS232 0x00000000 -#define ROCKET_MODE_RS485 0x00001000 -#define ROCKET_MODE_RS422 0x00002000 -#define ROCKET_FLAGS 0x00003FFF - -#define ROCKET_USR_MASK 0x0071 /* Legal flags that non-privileged - * users can set or reset */ - -/* - * For closing_wait and closing_wait2 - */ -#define ROCKET_CLOSING_WAIT_NONE ASYNC_CLOSING_WAIT_NONE -#define ROCKET_CLOSING_WAIT_INF ASYNC_CLOSING_WAIT_INF - -/* - * Rocketport ioctls -- "RP" - */ -#define RCKP_GET_CONFIG 0x00525002 -#define RCKP_SET_CONFIG 0x00525003 -#define RCKP_GET_PORTS 0x00525004 -#define RCKP_RESET_RM2 0x00525005 -#define RCKP_GET_VERSION 0x00525006 - -/* Rocketport Models */ -#define MODEL_RP32INTF 0x0001 /* RP 32 port w/external I/F */ -#define MODEL_RP8INTF 0x0002 /* RP 8 port w/external I/F */ -#define MODEL_RP16INTF 0x0003 /* RP 16 port w/external I/F */ -#define MODEL_RP8OCTA 0x0005 /* RP 8 port w/octa cable */ -#define MODEL_RP4QUAD 0x0004 /* RP 4 port w/quad cable */ -#define MODEL_RP8J 0x0006 /* RP 8 port w/RJ11 connectors */ -#define MODEL_RP4J 0x0007 /* RP 4 port w/RJ45 connectors */ -#define MODEL_RP8SNI 0x0008 /* RP 8 port w/ DB78 SNI connector */ -#define MODEL_RP16SNI 0x0009 /* RP 16 port w/ DB78 SNI connector */ -#define MODEL_RPP4 0x000A /* RP Plus 4 port */ -#define MODEL_RPP8 0x000B /* RP Plus 8 port */ -#define MODEL_RP2_232 0x000E /* RP Plus 2 port RS232 */ -#define MODEL_RP2_422 0x000F /* RP Plus 2 port RS232 */ - -/* Rocketmodem II Models */ -#define MODEL_RP6M 0x000C /* RM 6 port */ -#define MODEL_RP4M 0x000D /* RM 4 port */ - -/* Universal PCI boards */ -#define MODEL_UPCI_RP32INTF 0x0801 /* RP UPCI 32 port w/external I/F */ -#define MODEL_UPCI_RP8INTF 0x0802 /* RP UPCI 8 port w/external I/F */ -#define MODEL_UPCI_RP16INTF 0x0803 /* RP UPCI 16 port w/external I/F */ -#define MODEL_UPCI_RP8OCTA 0x0805 /* RP UPCI 8 port w/octa cable */ -#define MODEL_UPCI_RM3_8PORT 0x080C /* RP UPCI Rocketmodem III 8 port */ -#define MODEL_UPCI_RM3_4PORT 0x080C /* RP UPCI Rocketmodem III 4 port */ - -/* Compact PCI 16 port */ -#define MODEL_CPCI_RP16INTF 0x0903 /* RP Compact PCI 16 port w/external I/F */ - -/* All ISA boards */ -#define MODEL_ISA 0x1000 diff --git a/drivers/tty/rocket_int.h b/drivers/tty/rocket_int.h deleted file mode 100644 index 727e50dbb92f..000000000000 --- a/drivers/tty/rocket_int.h +++ /dev/null @@ -1,1214 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * rocket_int.h --- internal header file for rocket.c - * - * Written by Theodore Ts'o, Copyright 1997. - * Copyright 1997 Comtrol Corporation. - * - */ - -/* - * Definition of the types in rcktpt_type - */ -#define ROCKET_TYPE_NORMAL 0 -#define ROCKET_TYPE_MODEM 1 -#define ROCKET_TYPE_MODEMII 2 -#define ROCKET_TYPE_MODEMIII 3 -#define ROCKET_TYPE_PC104 4 - -#include - -#include -#include - -typedef unsigned char Byte_t; -typedef unsigned int ByteIO_t; - -typedef unsigned int Word_t; -typedef unsigned int WordIO_t; - -typedef unsigned int DWordIO_t; - -/* - * Note! Normally the Linux I/O macros already take care of - * byte-swapping the I/O instructions. However, all accesses using - * sOutDW aren't really 32-bit accesses, but should be handled in byte - * order. Hence the use of the cpu_to_le32() macro to byte-swap - * things to no-op the byte swapping done by the big-endian outl() - * instruction. - */ - -static inline void sOutB(unsigned short port, unsigned char value) -{ -#ifdef ROCKET_DEBUG_IO - printk(KERN_DEBUG "sOutB(%x, %x)...\n", port, value); -#endif - outb_p(value, port); -} - -static inline void sOutW(unsigned short port, unsigned short value) -{ -#ifdef ROCKET_DEBUG_IO - printk(KERN_DEBUG "sOutW(%x, %x)...\n", port, value); -#endif - outw_p(value, port); -} - -static inline void out32(unsigned short port, Byte_t *p) -{ - u32 value = get_unaligned_le32(p); -#ifdef ROCKET_DEBUG_IO - printk(KERN_DEBUG "out32(%x, %lx)...\n", port, value); -#endif - outl_p(value, port); -} - -static inline unsigned char sInB(unsigned short port) -{ - return inb_p(port); -} - -static inline unsigned short sInW(unsigned short port) -{ - return inw_p(port); -} - -/* This is used to move arrays of bytes so byte swapping isn't appropriate. */ -#define sOutStrW(port, addr, count) if (count) outsw(port, addr, count) -#define sInStrW(port, addr, count) if (count) insw(port, addr, count) - -#define CTL_SIZE 8 -#define AIOP_CTL_SIZE 4 -#define CHAN_AIOP_SIZE 8 -#define MAX_PORTS_PER_AIOP 8 -#define MAX_AIOPS_PER_BOARD 4 -#define MAX_PORTS_PER_BOARD 32 - -/* Bus type ID */ -#define isISA 0 -#define isPCI 1 -#define isMC 2 - -/* Controller ID numbers */ -#define CTLID_NULL -1 /* no controller exists */ -#define CTLID_0001 0x0001 /* controller release 1 */ - -/* AIOP ID numbers, identifies AIOP type implementing channel */ -#define AIOPID_NULL -1 /* no AIOP or channel exists */ -#define AIOPID_0001 0x0001 /* AIOP release 1 */ - -/************************************************************************ - Global Register Offsets - Direct Access - Fixed values -************************************************************************/ - -#define _CMD_REG 0x38 /* Command Register 8 Write */ -#define _INT_CHAN 0x39 /* Interrupt Channel Register 8 Read */ -#define _INT_MASK 0x3A /* Interrupt Mask Register 8 Read / Write */ -#define _UNUSED 0x3B /* Unused 8 */ -#define _INDX_ADDR 0x3C /* Index Register Address 16 Write */ -#define _INDX_DATA 0x3E /* Index Register Data 8/16 Read / Write */ - -/************************************************************************ - Channel Register Offsets for 1st channel in AIOP - Direct Access -************************************************************************/ -#define _TD0 0x00 /* Transmit Data 16 Write */ -#define _RD0 0x00 /* Receive Data 16 Read */ -#define _CHN_STAT0 0x20 /* Channel Status 8/16 Read / Write */ -#define _FIFO_CNT0 0x10 /* Transmit/Receive FIFO Count 16 Read */ -#define _INT_ID0 0x30 /* Interrupt Identification 8 Read */ - -/************************************************************************ - Tx Control Register Offsets - Indexed - External - Fixed -************************************************************************/ -#define _TX_ENBLS 0x980 /* Tx Processor Enables Register 8 Read / Write */ -#define _TXCMP1 0x988 /* Transmit Compare Value #1 8 Read / Write */ -#define _TXCMP2 0x989 /* Transmit Compare Value #2 8 Read / Write */ -#define _TXREP1B1 0x98A /* Tx Replace Value #1 - Byte 1 8 Read / Write */ -#define _TXREP1B2 0x98B /* Tx Replace Value #1 - Byte 2 8 Read / Write */ -#define _TXREP2 0x98C /* Transmit Replace Value #2 8 Read / Write */ - -/************************************************************************ -Memory Controller Register Offsets - Indexed - External - Fixed -************************************************************************/ -#define _RX_FIFO 0x000 /* Rx FIFO */ -#define _TX_FIFO 0x800 /* Tx FIFO */ -#define _RXF_OUTP 0x990 /* Rx FIFO OUT pointer 16 Read / Write */ -#define _RXF_INP 0x992 /* Rx FIFO IN pointer 16 Read / Write */ -#define _TXF_OUTP 0x994 /* Tx FIFO OUT pointer 8 Read / Write */ -#define _TXF_INP 0x995 /* Tx FIFO IN pointer 8 Read / Write */ -#define _TXP_CNT 0x996 /* Tx Priority Count 8 Read / Write */ -#define _TXP_PNTR 0x997 /* Tx Priority Pointer 8 Read / Write */ - -#define PRI_PEND 0x80 /* Priority data pending (bit7, Tx pri cnt) */ -#define TXFIFO_SIZE 255 /* size of Tx FIFO */ -#define RXFIFO_SIZE 1023 /* size of Rx FIFO */ - -/************************************************************************ -Tx Priority Buffer - Indexed - External - Fixed -************************************************************************/ -#define _TXP_BUF 0x9C0 /* Tx Priority Buffer 32 Bytes Read / Write */ -#define TXP_SIZE 0x20 /* 32 bytes */ - -/************************************************************************ -Channel Register Offsets - Indexed - Internal - Fixed -************************************************************************/ - -#define _TX_CTRL 0xFF0 /* Transmit Control 16 Write */ -#define _RX_CTRL 0xFF2 /* Receive Control 8 Write */ -#define _BAUD 0xFF4 /* Baud Rate 16 Write */ -#define _CLK_PRE 0xFF6 /* Clock Prescaler 8 Write */ - -#define STMBREAK 0x08 /* BREAK */ -#define STMFRAME 0x04 /* framing error */ -#define STMRCVROVR 0x02 /* receiver over run error */ -#define STMPARITY 0x01 /* parity error */ -#define STMERROR (STMBREAK | STMFRAME | STMPARITY) -#define STMBREAKH 0x800 /* BREAK */ -#define STMFRAMEH 0x400 /* framing error */ -#define STMRCVROVRH 0x200 /* receiver over run error */ -#define STMPARITYH 0x100 /* parity error */ -#define STMERRORH (STMBREAKH | STMFRAMEH | STMPARITYH) - -#define CTS_ACT 0x20 /* CTS input asserted */ -#define DSR_ACT 0x10 /* DSR input asserted */ -#define CD_ACT 0x08 /* CD input asserted */ -#define TXFIFOMT 0x04 /* Tx FIFO is empty */ -#define TXSHRMT 0x02 /* Tx shift register is empty */ -#define RDA 0x01 /* Rx data available */ -#define DRAINED (TXFIFOMT | TXSHRMT) /* indicates Tx is drained */ - -#define STATMODE 0x8000 /* status mode enable bit */ -#define RXFOVERFL 0x2000 /* receive FIFO overflow */ -#define RX2MATCH 0x1000 /* receive compare byte 2 match */ -#define RX1MATCH 0x0800 /* receive compare byte 1 match */ -#define RXBREAK 0x0400 /* received BREAK */ -#define RXFRAME 0x0200 /* received framing error */ -#define RXPARITY 0x0100 /* received parity error */ -#define STATERROR (RXBREAK | RXFRAME | RXPARITY) - -#define CTSFC_EN 0x80 /* CTS flow control enable bit */ -#define RTSTOG_EN 0x40 /* RTS toggle enable bit */ -#define TXINT_EN 0x10 /* transmit interrupt enable */ -#define STOP2 0x08 /* enable 2 stop bits (0 = 1 stop) */ -#define PARITY_EN 0x04 /* enable parity (0 = no parity) */ -#define EVEN_PAR 0x02 /* even parity (0 = odd parity) */ -#define DATA8BIT 0x01 /* 8 bit data (0 = 7 bit data) */ - -#define SETBREAK 0x10 /* send break condition (must clear) */ -#define LOCALLOOP 0x08 /* local loopback set for test */ -#define SET_DTR 0x04 /* assert DTR */ -#define SET_RTS 0x02 /* assert RTS */ -#define TX_ENABLE 0x01 /* enable transmitter */ - -#define RTSFC_EN 0x40 /* RTS flow control enable */ -#define RXPROC_EN 0x20 /* receive processor enable */ -#define TRIG_NO 0x00 /* Rx FIFO trigger level 0 (no trigger) */ -#define TRIG_1 0x08 /* trigger level 1 char */ -#define TRIG_1_2 0x10 /* trigger level 1/2 */ -#define TRIG_7_8 0x18 /* trigger level 7/8 */ -#define TRIG_MASK 0x18 /* trigger level mask */ -#define SRCINT_EN 0x04 /* special Rx condition interrupt enable */ -#define RXINT_EN 0x02 /* Rx interrupt enable */ -#define MCINT_EN 0x01 /* modem change interrupt enable */ - -#define RXF_TRIG 0x20 /* Rx FIFO trigger level interrupt */ -#define TXFIFO_MT 0x10 /* Tx FIFO empty interrupt */ -#define SRC_INT 0x08 /* special receive condition interrupt */ -#define DELTA_CD 0x04 /* CD change interrupt */ -#define DELTA_CTS 0x02 /* CTS change interrupt */ -#define DELTA_DSR 0x01 /* DSR change interrupt */ - -#define REP1W2_EN 0x10 /* replace byte 1 with 2 bytes enable */ -#define IGN2_EN 0x08 /* ignore byte 2 enable */ -#define IGN1_EN 0x04 /* ignore byte 1 enable */ -#define COMP2_EN 0x02 /* compare byte 2 enable */ -#define COMP1_EN 0x01 /* compare byte 1 enable */ - -#define RESET_ALL 0x80 /* reset AIOP (all channels) */ -#define TXOVERIDE 0x40 /* Transmit software off override */ -#define RESETUART 0x20 /* reset channel's UART */ -#define RESTXFCNT 0x10 /* reset channel's Tx FIFO count register */ -#define RESRXFCNT 0x08 /* reset channel's Rx FIFO count register */ - -#define INTSTAT0 0x01 /* AIOP 0 interrupt status */ -#define INTSTAT1 0x02 /* AIOP 1 interrupt status */ -#define INTSTAT2 0x04 /* AIOP 2 interrupt status */ -#define INTSTAT3 0x08 /* AIOP 3 interrupt status */ - -#define INTR_EN 0x08 /* allow interrupts to host */ -#define INT_STROB 0x04 /* strobe and clear interrupt line (EOI) */ - -/************************************************************************** - MUDBAC remapped for PCI -**************************************************************************/ - -#define _CFG_INT_PCI 0x40 -#define _PCI_INT_FUNC 0x3A - -#define PCI_STROB 0x2000 /* bit 13 of int aiop register */ -#define INTR_EN_PCI 0x0010 /* allow interrupts to host */ - -/* - * Definitions for Universal PCI board registers - */ -#define _PCI_9030_INT_CTRL 0x4c /* Offsets from BAR1 */ -#define _PCI_9030_GPIO_CTRL 0x54 -#define PCI_INT_CTRL_AIOP 0x0001 -#define PCI_GPIO_CTRL_8PORT 0x4000 -#define _PCI_9030_RING_IND 0xc0 /* Offsets from BAR1 */ - -#define CHAN3_EN 0x08 /* enable AIOP 3 */ -#define CHAN2_EN 0x04 /* enable AIOP 2 */ -#define CHAN1_EN 0x02 /* enable AIOP 1 */ -#define CHAN0_EN 0x01 /* enable AIOP 0 */ -#define FREQ_DIS 0x00 -#define FREQ_274HZ 0x60 -#define FREQ_137HZ 0x50 -#define FREQ_69HZ 0x40 -#define FREQ_34HZ 0x30 -#define FREQ_17HZ 0x20 -#define FREQ_9HZ 0x10 -#define PERIODIC_ONLY 0x80 /* only PERIODIC interrupt */ - -#define CHANINT_EN 0x0100 /* flags to enable/disable channel ints */ - -#define RDATASIZE 72 -#define RREGDATASIZE 52 - -/* - * AIOP interrupt bits for ISA/PCI boards and UPCI boards. - */ -#define AIOP_INTR_BIT_0 0x0001 -#define AIOP_INTR_BIT_1 0x0002 -#define AIOP_INTR_BIT_2 0x0004 -#define AIOP_INTR_BIT_3 0x0008 - -#define AIOP_INTR_BITS ( \ - AIOP_INTR_BIT_0 \ - | AIOP_INTR_BIT_1 \ - | AIOP_INTR_BIT_2 \ - | AIOP_INTR_BIT_3) - -#define UPCI_AIOP_INTR_BIT_0 0x0004 -#define UPCI_AIOP_INTR_BIT_1 0x0020 -#define UPCI_AIOP_INTR_BIT_2 0x0100 -#define UPCI_AIOP_INTR_BIT_3 0x0800 - -#define UPCI_AIOP_INTR_BITS ( \ - UPCI_AIOP_INTR_BIT_0 \ - | UPCI_AIOP_INTR_BIT_1 \ - | UPCI_AIOP_INTR_BIT_2 \ - | UPCI_AIOP_INTR_BIT_3) - -/* Controller level information structure */ -typedef struct { - int CtlID; - int CtlNum; - int BusType; - int boardType; - int isUPCI; - WordIO_t PCIIO; - WordIO_t PCIIO2; - ByteIO_t MBaseIO; - ByteIO_t MReg1IO; - ByteIO_t MReg2IO; - ByteIO_t MReg3IO; - Byte_t MReg2; - Byte_t MReg3; - int NumAiop; - int AltChanRingIndicator; - ByteIO_t UPCIRingInd; - WordIO_t AiopIO[AIOP_CTL_SIZE]; - ByteIO_t AiopIntChanIO[AIOP_CTL_SIZE]; - int AiopID[AIOP_CTL_SIZE]; - int AiopNumChan[AIOP_CTL_SIZE]; - Word_t *AiopIntrBits; -} CONTROLLER_T; - -typedef CONTROLLER_T CONTROLLER_t; - -/* Channel level information structure */ -typedef struct { - CONTROLLER_T *CtlP; - int AiopNum; - int ChanID; - int ChanNum; - int rtsToggle; - - ByteIO_t Cmd; - ByteIO_t IntChan; - ByteIO_t IntMask; - DWordIO_t IndexAddr; - WordIO_t IndexData; - - WordIO_t TxRxData; - WordIO_t ChanStat; - WordIO_t TxRxCount; - ByteIO_t IntID; - - Word_t TxFIFO; - Word_t TxFIFOPtrs; - Word_t RxFIFO; - Word_t RxFIFOPtrs; - Word_t TxPrioCnt; - Word_t TxPrioPtr; - Word_t TxPrioBuf; - - Byte_t R[RREGDATASIZE]; - - Byte_t BaudDiv[4]; - Byte_t TxControl[4]; - Byte_t RxControl[4]; - Byte_t TxEnables[4]; - Byte_t TxCompare[4]; - Byte_t TxReplace1[4]; - Byte_t TxReplace2[4]; -} CHANNEL_T; - -typedef CHANNEL_T CHANNEL_t; -typedef CHANNEL_T *CHANPTR_T; - -#define InterfaceModeRS232 0x00 -#define InterfaceModeRS422 0x08 -#define InterfaceModeRS485 0x10 -#define InterfaceModeRS232T 0x18 - -/*************************************************************************** -Function: sClrBreak -Purpose: Stop sending a transmit BREAK signal -Call: sClrBreak(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrBreak(ChP) \ -do { \ - (ChP)->TxControl[3] &= ~SETBREAK; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sClrDTR -Purpose: Clr the DTR output -Call: sClrDTR(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrDTR(ChP) \ -do { \ - (ChP)->TxControl[3] &= ~SET_DTR; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sClrRTS -Purpose: Clr the RTS output -Call: sClrRTS(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrRTS(ChP) \ -do { \ - if ((ChP)->rtsToggle) break; \ - (ChP)->TxControl[3] &= ~SET_RTS; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sClrTxXOFF -Purpose: Clear any existing transmit software flow control off condition -Call: sClrTxXOFF(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sClrTxXOFF(ChP) \ -do { \ - sOutB((ChP)->Cmd,TXOVERIDE | (Byte_t)(ChP)->ChanNum); \ - sOutB((ChP)->Cmd,(Byte_t)(ChP)->ChanNum); \ -} while (0) - -/*************************************************************************** -Function: sCtlNumToCtlPtr -Purpose: Convert a controller number to controller structure pointer -Call: sCtlNumToCtlPtr(CtlNum) - int CtlNum; Controller number -Return: CONTROLLER_T *: Ptr to controller structure -*/ -#define sCtlNumToCtlPtr(CTLNUM) &sController[CTLNUM] - -/*************************************************************************** -Function: sControllerEOI -Purpose: Strobe the MUDBAC's End Of Interrupt bit. -Call: sControllerEOI(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -*/ -#define sControllerEOI(CTLP) sOutB((CTLP)->MReg2IO,(CTLP)->MReg2 | INT_STROB) - -/*************************************************************************** -Function: sPCIControllerEOI -Purpose: Strobe the PCI End Of Interrupt bit. - For the UPCI boards, toggle the AIOP interrupt enable bit - (this was taken from the Windows driver). -Call: sPCIControllerEOI(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -*/ -#define sPCIControllerEOI(CTLP) \ -do { \ - if ((CTLP)->isUPCI) { \ - Word_t w = sInW((CTLP)->PCIIO); \ - sOutW((CTLP)->PCIIO, (w ^ PCI_INT_CTRL_AIOP)); \ - sOutW((CTLP)->PCIIO, w); \ - } \ - else { \ - sOutW((CTLP)->PCIIO, PCI_STROB); \ - } \ -} while (0) - -/*************************************************************************** -Function: sDisAiop -Purpose: Disable I/O access to an AIOP -Call: sDisAiop(CltP) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; Number of AIOP on controller -*/ -#define sDisAiop(CTLP,AIOPNUM) \ -do { \ - (CTLP)->MReg3 &= sBitMapClrTbl[AIOPNUM]; \ - sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ -} while (0) - -/*************************************************************************** -Function: sDisCTSFlowCtl -Purpose: Disable output flow control using CTS -Call: sDisCTSFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisCTSFlowCtl(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~CTSFC_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sDisIXANY -Purpose: Disable IXANY Software Flow Control -Call: sDisIXANY(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisIXANY(ChP) \ -do { \ - (ChP)->R[0x0e] = 0x86; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x0c]); \ -} while (0) - -/*************************************************************************** -Function: DisParity -Purpose: Disable parity -Call: sDisParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). -*/ -#define sDisParity(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~PARITY_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sDisRTSToggle -Purpose: Disable RTS toggle -Call: sDisRTSToggle(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisRTSToggle(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~RTSTOG_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ - (ChP)->rtsToggle = 0; \ -} while (0) - -/*************************************************************************** -Function: sDisRxFIFO -Purpose: Disable Rx FIFO -Call: sDisRxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisRxFIFO(ChP) \ -do { \ - (ChP)->R[0x32] = 0x0a; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x30]); \ -} while (0) - -/*************************************************************************** -Function: sDisRxStatusMode -Purpose: Disable the Rx status mode -Call: sDisRxStatusMode(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This takes the channel out of the receive status mode. All - subsequent reads of receive data using sReadRxWord() will return - two data bytes. -*/ -#define sDisRxStatusMode(ChP) sOutW((ChP)->ChanStat,0) - -/*************************************************************************** -Function: sDisTransmit -Purpose: Disable transmit -Call: sDisTransmit(ChP) - CHANNEL_T *ChP; Ptr to channel structure - This disables movement of Tx data from the Tx FIFO into the 1 byte - Tx buffer. Therefore there could be up to a 2 byte latency - between the time sDisTransmit() is called and the transmit buffer - and transmit shift register going completely empty. -*/ -#define sDisTransmit(ChP) \ -do { \ - (ChP)->TxControl[3] &= ~TX_ENABLE; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sDisTxSoftFlowCtl -Purpose: Disable Tx Software Flow Control -Call: sDisTxSoftFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sDisTxSoftFlowCtl(ChP) \ -do { \ - (ChP)->R[0x06] = 0x8a; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ -} while (0) - -/*************************************************************************** -Function: sEnAiop -Purpose: Enable I/O access to an AIOP -Call: sEnAiop(CltP) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; Number of AIOP on controller -*/ -#define sEnAiop(CTLP,AIOPNUM) \ -do { \ - (CTLP)->MReg3 |= sBitMapSetTbl[AIOPNUM]; \ - sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ -} while (0) - -/*************************************************************************** -Function: sEnCTSFlowCtl -Purpose: Enable output flow control using CTS -Call: sEnCTSFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnCTSFlowCtl(ChP) \ -do { \ - (ChP)->TxControl[2] |= CTSFC_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sEnIXANY -Purpose: Enable IXANY Software Flow Control -Call: sEnIXANY(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnIXANY(ChP) \ -do { \ - (ChP)->R[0x0e] = 0x21; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x0c]); \ -} while (0) - -/*************************************************************************** -Function: EnParity -Purpose: Enable parity -Call: sEnParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). - -Warnings: Before enabling parity odd or even parity should be chosen using - functions sSetOddParity() or sSetEvenParity(). -*/ -#define sEnParity(ChP) \ -do { \ - (ChP)->TxControl[2] |= PARITY_EN; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sEnRTSToggle -Purpose: Enable RTS toggle -Call: sEnRTSToggle(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This function will disable RTS flow control and clear the RTS - line to allow operation of RTS toggle. -*/ -#define sEnRTSToggle(ChP) \ -do { \ - (ChP)->RxControl[2] &= ~RTSFC_EN; \ - out32((ChP)->IndexAddr,(ChP)->RxControl); \ - (ChP)->TxControl[2] |= RTSTOG_EN; \ - (ChP)->TxControl[3] &= ~SET_RTS; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ - (ChP)->rtsToggle = 1; \ -} while (0) - -/*************************************************************************** -Function: sEnRxFIFO -Purpose: Enable Rx FIFO -Call: sEnRxFIFO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnRxFIFO(ChP) \ -do { \ - (ChP)->R[0x32] = 0x08; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x30]); \ -} while (0) - -/*************************************************************************** -Function: sEnRxProcessor -Purpose: Enable the receive processor -Call: sEnRxProcessor(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This function is used to start the receive processor. When - the channel is in the reset state the receive processor is not - running. This is done to prevent the receive processor from - executing invalid microcode instructions prior to the - downloading of the microcode. - -Warnings: This function must be called after valid microcode has been - downloaded to the AIOP, and it must not be called before the - microcode has been downloaded. -*/ -#define sEnRxProcessor(ChP) \ -do { \ - (ChP)->RxControl[2] |= RXPROC_EN; \ - out32((ChP)->IndexAddr,(ChP)->RxControl); \ -} while (0) - -/*************************************************************************** -Function: sEnRxStatusMode -Purpose: Enable the Rx status mode -Call: sEnRxStatusMode(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This places the channel in the receive status mode. All subsequent - reads of receive data using sReadRxWord() will return a data byte - in the low word and a status byte in the high word. - -*/ -#define sEnRxStatusMode(ChP) sOutW((ChP)->ChanStat,STATMODE) - -/*************************************************************************** -Function: sEnTransmit -Purpose: Enable transmit -Call: sEnTransmit(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnTransmit(ChP) \ -do { \ - (ChP)->TxControl[3] |= TX_ENABLE; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sEnTxSoftFlowCtl -Purpose: Enable Tx Software Flow Control -Call: sEnTxSoftFlowCtl(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sEnTxSoftFlowCtl(ChP) \ -do { \ - (ChP)->R[0x06] = 0xc5; \ - out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ -} while (0) - -/*************************************************************************** -Function: sGetAiopIntStatus -Purpose: Get the AIOP interrupt status -Call: sGetAiopIntStatus(CtlP,AiopNum) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; AIOP number -Return: Byte_t: The AIOP interrupt status. Bits 0 through 7 - represent channels 0 through 7 respectively. If a - bit is set that channel is interrupting. -*/ -#define sGetAiopIntStatus(CTLP,AIOPNUM) sInB((CTLP)->AiopIntChanIO[AIOPNUM]) - -/*************************************************************************** -Function: sGetAiopNumChan -Purpose: Get the number of channels supported by an AIOP -Call: sGetAiopNumChan(CtlP,AiopNum) - CONTROLLER_T *CtlP; Ptr to controller structure - int AiopNum; AIOP number -Return: int: The number of channels supported by the AIOP -*/ -#define sGetAiopNumChan(CTLP,AIOPNUM) (CTLP)->AiopNumChan[AIOPNUM] - -/*************************************************************************** -Function: sGetChanIntID -Purpose: Get a channel's interrupt identification byte -Call: sGetChanIntID(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Byte_t: The channel interrupt ID. Can be any - combination of the following flags: - RXF_TRIG: Rx FIFO trigger level interrupt - TXFIFO_MT: Tx FIFO empty interrupt - SRC_INT: Special receive condition interrupt - DELTA_CD: CD change interrupt - DELTA_CTS: CTS change interrupt - DELTA_DSR: DSR change interrupt -*/ -#define sGetChanIntID(ChP) (sInB((ChP)->IntID) & (RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR)) - -/*************************************************************************** -Function: sGetChanNum -Purpose: Get the number of a channel within an AIOP -Call: sGetChanNum(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: int: Channel number within AIOP, or NULLCHAN if channel does - not exist. -*/ -#define sGetChanNum(ChP) (ChP)->ChanNum - -/*************************************************************************** -Function: sGetChanStatus -Purpose: Get the channel status -Call: sGetChanStatus(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Word_t: The channel status. Can be any combination of - the following flags: - LOW BYTE FLAGS - CTS_ACT: CTS input asserted - DSR_ACT: DSR input asserted - CD_ACT: CD input asserted - TXFIFOMT: Tx FIFO is empty - TXSHRMT: Tx shift register is empty - RDA: Rx data available - - HIGH BYTE FLAGS - STATMODE: status mode enable bit - RXFOVERFL: receive FIFO overflow - RX2MATCH: receive compare byte 2 match - RX1MATCH: receive compare byte 1 match - RXBREAK: received BREAK - RXFRAME: received framing error - RXPARITY: received parity error -Warnings: This function will clear the high byte flags in the Channel - Status Register. -*/ -#define sGetChanStatus(ChP) sInW((ChP)->ChanStat) - -/*************************************************************************** -Function: sGetChanStatusLo -Purpose: Get the low byte only of the channel status -Call: sGetChanStatusLo(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Byte_t: The channel status low byte. Can be any combination - of the following flags: - CTS_ACT: CTS input asserted - DSR_ACT: DSR input asserted - CD_ACT: CD input asserted - TXFIFOMT: Tx FIFO is empty - TXSHRMT: Tx shift register is empty - RDA: Rx data available -*/ -#define sGetChanStatusLo(ChP) sInB((ByteIO_t)(ChP)->ChanStat) - -/********************************************************************** - * Get RI status of channel - * Defined as a function in rocket.c -aes - */ -#if 0 -#define sGetChanRI(ChP) ((ChP)->CtlP->AltChanRingIndicator ? \ - (sInB((ByteIO_t)((ChP)->ChanStat+8)) & DSR_ACT) : \ - (((ChP)->CtlP->boardType == ROCKET_TYPE_PC104) ? \ - (!(sInB((ChP)->CtlP->AiopIO[3]) & sBitMapSetTbl[(ChP)->ChanNum])) : \ - 0)) -#endif - -/*************************************************************************** -Function: sGetControllerIntStatus -Purpose: Get the controller interrupt status -Call: sGetControllerIntStatus(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -Return: Byte_t: The controller interrupt status in the lower 4 - bits. Bits 0 through 3 represent AIOP's 0 - through 3 respectively. If a bit is set that - AIOP is interrupting. Bits 4 through 7 will - always be cleared. -*/ -#define sGetControllerIntStatus(CTLP) (sInB((CTLP)->MReg1IO) & 0x0f) - -/*************************************************************************** -Function: sPCIGetControllerIntStatus -Purpose: Get the controller interrupt status -Call: sPCIGetControllerIntStatus(CtlP) - CONTROLLER_T *CtlP; Ptr to controller structure -Return: unsigned char: The controller interrupt status in the lower 4 - bits and bit 4. Bits 0 through 3 represent AIOP's 0 - through 3 respectively. Bit 4 is set if the int - was generated from periodic. If a bit is set the - AIOP is interrupting. -*/ -#define sPCIGetControllerIntStatus(CTLP) \ - ((CTLP)->isUPCI ? \ - (sInW((CTLP)->PCIIO2) & UPCI_AIOP_INTR_BITS) : \ - ((sInW((CTLP)->PCIIO) >> 8) & AIOP_INTR_BITS)) - -/*************************************************************************** - -Function: sGetRxCnt -Purpose: Get the number of data bytes in the Rx FIFO -Call: sGetRxCnt(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: int: The number of data bytes in the Rx FIFO. -Comments: Byte read of count register is required to obtain Rx count. - -*/ -#define sGetRxCnt(ChP) sInW((ChP)->TxRxCount) - -/*************************************************************************** -Function: sGetTxCnt -Purpose: Get the number of data bytes in the Tx FIFO -Call: sGetTxCnt(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: Byte_t: The number of data bytes in the Tx FIFO. -Comments: Byte read of count register is required to obtain Tx count. - -*/ -#define sGetTxCnt(ChP) sInB((ByteIO_t)(ChP)->TxRxCount) - -/***************************************************************************** -Function: sGetTxRxDataIO -Purpose: Get the I/O address of a channel's TxRx Data register -Call: sGetTxRxDataIO(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Return: WordIO_t: I/O address of a channel's TxRx Data register -*/ -#define sGetTxRxDataIO(ChP) (ChP)->TxRxData - -/*************************************************************************** -Function: sInitChanDefaults -Purpose: Initialize a channel structure to it's default state. -Call: sInitChanDefaults(ChP) - CHANNEL_T *ChP; Ptr to the channel structure -Comments: This function must be called once for every channel structure - that exists before any other SSCI calls can be made. - -*/ -#define sInitChanDefaults(ChP) \ -do { \ - (ChP)->CtlP = NULLCTLPTR; \ - (ChP)->AiopNum = NULLAIOP; \ - (ChP)->ChanID = AIOPID_NULL; \ - (ChP)->ChanNum = NULLCHAN; \ -} while (0) - -/*************************************************************************** -Function: sResetAiopByNum -Purpose: Reset the AIOP by number -Call: sResetAiopByNum(CTLP,AIOPNUM) - CONTROLLER_T CTLP; Ptr to controller structure - AIOPNUM; AIOP index -*/ -#define sResetAiopByNum(CTLP,AIOPNUM) \ -do { \ - sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,RESET_ALL); \ - sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,0x0); \ -} while (0) - -/*************************************************************************** -Function: sSendBreak -Purpose: Send a transmit BREAK signal -Call: sSendBreak(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSendBreak(ChP) \ -do { \ - (ChP)->TxControl[3] |= SETBREAK; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetBaud -Purpose: Set baud rate -Call: sSetBaud(ChP,Divisor) - CHANNEL_T *ChP; Ptr to channel structure - Word_t Divisor; 16 bit baud rate divisor for channel -*/ -#define sSetBaud(ChP,DIVISOR) \ -do { \ - (ChP)->BaudDiv[2] = (Byte_t)(DIVISOR); \ - (ChP)->BaudDiv[3] = (Byte_t)((DIVISOR) >> 8); \ - out32((ChP)->IndexAddr,(ChP)->BaudDiv); \ -} while (0) - -/*************************************************************************** -Function: sSetData7 -Purpose: Set data bits to 7 -Call: sSetData7(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetData7(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~DATA8BIT; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetData8 -Purpose: Set data bits to 8 -Call: sSetData8(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetData8(ChP) \ -do { \ - (ChP)->TxControl[2] |= DATA8BIT; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetDTR -Purpose: Set the DTR output -Call: sSetDTR(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetDTR(ChP) \ -do { \ - (ChP)->TxControl[3] |= SET_DTR; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetEvenParity -Purpose: Set even parity -Call: sSetEvenParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). - -Warnings: This function has no effect unless parity is enabled with function - sEnParity(). -*/ -#define sSetEvenParity(ChP) \ -do { \ - (ChP)->TxControl[2] |= EVEN_PAR; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetOddParity -Purpose: Set odd parity -Call: sSetOddParity(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: Function sSetParity() can be used in place of functions sEnParity(), - sDisParity(), sSetOddParity(), and sSetEvenParity(). - -Warnings: This function has no effect unless parity is enabled with function - sEnParity(). -*/ -#define sSetOddParity(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~EVEN_PAR; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetRTS -Purpose: Set the RTS output -Call: sSetRTS(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetRTS(ChP) \ -do { \ - if ((ChP)->rtsToggle) break; \ - (ChP)->TxControl[3] |= SET_RTS; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetRxTrigger -Purpose: Set the Rx FIFO trigger level -Call: sSetRxProcessor(ChP,Level) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Level; Number of characters in Rx FIFO at which the - interrupt will be generated. Can be any of the following flags: - - TRIG_NO: no trigger - TRIG_1: 1 character in FIFO - TRIG_1_2: FIFO 1/2 full - TRIG_7_8: FIFO 7/8 full -Comments: An interrupt will be generated when the trigger level is reached - only if function sEnInterrupt() has been called with flag - RXINT_EN set. The RXF_TRIG flag in the Interrupt Idenfification - register will be set whenever the trigger level is reached - regardless of the setting of RXINT_EN. - -*/ -#define sSetRxTrigger(ChP,LEVEL) \ -do { \ - (ChP)->RxControl[2] &= ~TRIG_MASK; \ - (ChP)->RxControl[2] |= LEVEL; \ - out32((ChP)->IndexAddr,(ChP)->RxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetStop1 -Purpose: Set stop bits to 1 -Call: sSetStop1(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetStop1(ChP) \ -do { \ - (ChP)->TxControl[2] &= ~STOP2; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetStop2 -Purpose: Set stop bits to 2 -Call: sSetStop2(ChP) - CHANNEL_T *ChP; Ptr to channel structure -*/ -#define sSetStop2(ChP) \ -do { \ - (ChP)->TxControl[2] |= STOP2; \ - out32((ChP)->IndexAddr,(ChP)->TxControl); \ -} while (0) - -/*************************************************************************** -Function: sSetTxXOFFChar -Purpose: Set the Tx XOFF flow control character -Call: sSetTxXOFFChar(ChP,Ch) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Ch; The value to set the Tx XOFF character to -*/ -#define sSetTxXOFFChar(ChP,CH) \ -do { \ - (ChP)->R[0x07] = (CH); \ - out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ -} while (0) - -/*************************************************************************** -Function: sSetTxXONChar -Purpose: Set the Tx XON flow control character -Call: sSetTxXONChar(ChP,Ch) - CHANNEL_T *ChP; Ptr to channel structure - Byte_t Ch; The value to set the Tx XON character to -*/ -#define sSetTxXONChar(ChP,CH) \ -do { \ - (ChP)->R[0x0b] = (CH); \ - out32((ChP)->IndexAddr,&(ChP)->R[0x08]); \ -} while (0) - -/*************************************************************************** -Function: sStartRxProcessor -Purpose: Start a channel's receive processor -Call: sStartRxProcessor(ChP) - CHANNEL_T *ChP; Ptr to channel structure -Comments: This function is used to start a Rx processor after it was - stopped with sStopRxProcessor() or sStopSWInFlowCtl(). It - will restart both the Rx processor and software input flow control. - -*/ -#define sStartRxProcessor(ChP) out32((ChP)->IndexAddr,&(ChP)->R[0]) - -/*************************************************************************** -Function: sWriteTxByte -Purpose: Write a transmit data byte to a channel. - ByteIO_t io: Channel transmit register I/O address. This can - be obtained with sGetTxRxDataIO(). - Byte_t Data; The transmit data byte. -Warnings: This function writes the data byte without checking to see if - sMaxTxSize is exceeded in the Tx FIFO. -*/ -#define sWriteTxByte(IO,DATA) sOutB(IO,DATA) - -/* - * Begin Linux specific definitions for the Rocketport driver - * - * This code is Copyright Theodore Ts'o, 1995-1997 - */ - -struct r_port { - int magic; - struct tty_port port; - int line; - int flags; /* Don't yet match the ASY_ flags!! */ - unsigned int board:3; - unsigned int aiop:2; - unsigned int chan:3; - CONTROLLER_t *ctlp; - CHANNEL_t channel; - int intmask; - int xmit_fifo_room; /* room in xmit fifo */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - int cd_status; - int ignore_status_mask; - int read_status_mask; - int cps; - - spinlock_t slock; - struct mutex write_mtx; -}; - -#define RPORT_MAGIC 0x525001 - -#define NUM_BOARDS 8 -#define MAX_RP_PORTS (32*NUM_BOARDS) - -/* - * The size of the xmit buffer is 1 page, or 4096 bytes - */ -#define XMIT_BUF_SIZE 4096 - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* - * Assigned major numbers for the Comtrol Rocketport - */ -#define TTY_ROCKET_MAJOR 46 -#define CUA_ROCKET_MAJOR 47 - -#ifdef PCI_VENDOR_ID_RP -#undef PCI_VENDOR_ID_RP -#undef PCI_DEVICE_ID_RP8OCTA -#undef PCI_DEVICE_ID_RP8INTF -#undef PCI_DEVICE_ID_RP16INTF -#undef PCI_DEVICE_ID_RP32INTF -#undef PCI_DEVICE_ID_URP8OCTA -#undef PCI_DEVICE_ID_URP8INTF -#undef PCI_DEVICE_ID_URP16INTF -#undef PCI_DEVICE_ID_CRP16INTF -#undef PCI_DEVICE_ID_URP32INTF -#endif - -/* Comtrol PCI Vendor ID */ -#define PCI_VENDOR_ID_RP 0x11fe - -/* Comtrol Device ID's */ -#define PCI_DEVICE_ID_RP32INTF 0x0001 /* Rocketport 32 port w/external I/F */ -#define PCI_DEVICE_ID_RP8INTF 0x0002 /* Rocketport 8 port w/external I/F */ -#define PCI_DEVICE_ID_RP16INTF 0x0003 /* Rocketport 16 port w/external I/F */ -#define PCI_DEVICE_ID_RP4QUAD 0x0004 /* Rocketport 4 port w/quad cable */ -#define PCI_DEVICE_ID_RP8OCTA 0x0005 /* Rocketport 8 port w/octa cable */ -#define PCI_DEVICE_ID_RP8J 0x0006 /* Rocketport 8 port w/RJ11 connectors */ -#define PCI_DEVICE_ID_RP4J 0x0007 /* Rocketport 4 port w/RJ11 connectors */ -#define PCI_DEVICE_ID_RP8SNI 0x0008 /* Rocketport 8 port w/ DB78 SNI (Siemens) connector */ -#define PCI_DEVICE_ID_RP16SNI 0x0009 /* Rocketport 16 port w/ DB78 SNI (Siemens) connector */ -#define PCI_DEVICE_ID_RPP4 0x000A /* Rocketport Plus 4 port */ -#define PCI_DEVICE_ID_RPP8 0x000B /* Rocketport Plus 8 port */ -#define PCI_DEVICE_ID_RP6M 0x000C /* RocketModem 6 port */ -#define PCI_DEVICE_ID_RP4M 0x000D /* RocketModem 4 port */ -#define PCI_DEVICE_ID_RP2_232 0x000E /* Rocketport Plus 2 port RS232 */ -#define PCI_DEVICE_ID_RP2_422 0x000F /* Rocketport Plus 2 port RS422 */ - -/* Universal PCI boards */ -#define PCI_DEVICE_ID_URP32INTF 0x0801 /* Rocketport UPCI 32 port w/external I/F */ -#define PCI_DEVICE_ID_URP8INTF 0x0802 /* Rocketport UPCI 8 port w/external I/F */ -#define PCI_DEVICE_ID_URP16INTF 0x0803 /* Rocketport UPCI 16 port w/external I/F */ -#define PCI_DEVICE_ID_URP8OCTA 0x0805 /* Rocketport UPCI 8 port w/octa cable */ -#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C /* Rocketmodem III 8 port */ -#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D /* Rocketmodem III 4 port */ - -/* Compact PCI device */ -#define PCI_DEVICE_ID_CRP16INTF 0x0903 /* Rocketport Compact PCI 16 port w/external I/F */ - diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 056d2074f07a..4c3fa5293d76 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1688,27 +1688,6 @@ #define PCI_VENDOR_ID_MICROSEMI 0x11f8 #define PCI_VENDOR_ID_RP 0x11fe -#define PCI_DEVICE_ID_RP32INTF 0x0001 -#define PCI_DEVICE_ID_RP8INTF 0x0002 -#define PCI_DEVICE_ID_RP16INTF 0x0003 -#define PCI_DEVICE_ID_RP4QUAD 0x0004 -#define PCI_DEVICE_ID_RP8OCTA 0x0005 -#define PCI_DEVICE_ID_RP8J 0x0006 -#define PCI_DEVICE_ID_RP4J 0x0007 -#define PCI_DEVICE_ID_RP8SNI 0x0008 -#define PCI_DEVICE_ID_RP16SNI 0x0009 -#define PCI_DEVICE_ID_RPP4 0x000A -#define PCI_DEVICE_ID_RPP8 0x000B -#define PCI_DEVICE_ID_RP4M 0x000D -#define PCI_DEVICE_ID_RP2_232 0x000E -#define PCI_DEVICE_ID_RP2_422 0x000F -#define PCI_DEVICE_ID_URP32INTF 0x0801 -#define PCI_DEVICE_ID_URP8INTF 0x0802 -#define PCI_DEVICE_ID_URP16INTF 0x0803 -#define PCI_DEVICE_ID_URP8OCTA 0x0805 -#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C -#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D -#define PCI_DEVICE_ID_CRP16INTF 0x0903 #define PCI_VENDOR_ID_CYCLADES 0x120e #define PCI_DEVICE_ID_PC300_RX_2 0x0300 -- cgit From 981b22b8777df7de070be1803f6d7ed4f634a43c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:38 +0100 Subject: tty: remove TTY_LDISC_MAGIC First, it is never checked. Second, use of it as a debugging aid is at least questionable. With the current tools, I don't think anyone used this kind of thing for debugging purposes for years. On the top of that, e.g. serdev does not set this field of tty_ldisc_ops at all. So get rid of this legacy. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/process/magic-number.rst | 1 - Documentation/translations/it_IT/process/magic-number.rst | 1 - Documentation/translations/zh_CN/process/magic-number.rst | 1 - drivers/accessibility/speakup/spk_ttyio.c | 1 - drivers/bluetooth/hci_ldisc.c | 1 - drivers/misc/ti-st/st_core.c | 1 - drivers/net/caif/caif_serial.c | 1 - drivers/net/can/slcan.c | 1 - drivers/net/hamradio/6pack.c | 1 - drivers/net/hamradio/mkiss.c | 1 - drivers/net/ppp/ppp_async.c | 1 - drivers/net/ppp/ppp_synctty.c | 1 - drivers/net/slip/slip.c | 1 - drivers/pps/clients/pps-ldisc.c | 3 --- drivers/tty/n_gsm.c | 1 - drivers/tty/n_hdlc.c | 1 - drivers/tty/n_null.c | 1 - drivers/tty/n_r3964.c | 1 - drivers/tty/n_tty.c | 1 - include/linux/tty_ldisc.h | 3 --- net/nfc/nci/uart.c | 1 - sound/soc/codecs/cx20442.c | 1 - sound/soc/ti/ams-delta.c | 1 - 23 files changed, 27 deletions(-) diff --git a/Documentation/process/magic-number.rst b/Documentation/process/magic-number.rst index 89992fe4863f..f5ba36e96461 100644 --- a/Documentation/process/magic-number.rst +++ b/Documentation/process/magic-number.rst @@ -88,7 +88,6 @@ TTY_MAGIC 0x5401 tty_struct ``include/linux/ MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h`` USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst index 9be170ec0d02..e8c782d155a3 100644 --- a/Documentation/translations/it_IT/process/magic-number.rst +++ b/Documentation/translations/it_IT/process/magic-number.rst @@ -94,7 +94,6 @@ TTY_MAGIC 0x5401 tty_struct ``include/linux/ MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h`` USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 191d705349ef..42f0635ca70a 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -77,7 +77,6 @@ TTY_MAGIC 0x5401 tty_struct ``include/linux/ MGSL_MAGIC 0x5401 mgsl_info ``drivers/char/synclink.c`` TTY_DRIVER_MAGIC 0x5402 tty_driver ``include/linux/tty_driver.h`` MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c`` -TTY_LDISC_MAGIC 0x5403 tty_ldisc ``include/linux/tty_ldisc.h`` USB_SERIAL_MAGIC 0x6702 usb_serial ``drivers/usb/serial/usb-serial.h`` FULL_DUPLEX_MAGIC 0x6969 ``drivers/net/ethernet/dec/tulip/de2104x.c`` USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth ``drivers/usb/class/bluetty.c`` diff --git a/drivers/accessibility/speakup/spk_ttyio.c b/drivers/accessibility/speakup/spk_ttyio.c index 9af1d4c124d3..2e39fcf492d8 100644 --- a/drivers/accessibility/speakup/spk_ttyio.c +++ b/drivers/accessibility/speakup/spk_ttyio.c @@ -104,7 +104,6 @@ static int spk_ttyio_receive_buf2(struct tty_struct *tty, static struct tty_ldisc_ops spk_ttyio_ldisc_ops = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "speakup_ldisc", .open = spk_ttyio_ldisc_open, .close = spk_ttyio_ldisc_close, diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 637c5b8c2aa1..71a4ca505e09 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -821,7 +821,6 @@ static __poll_t hci_uart_tty_poll(struct tty_struct *tty, static struct tty_ldisc_ops hci_uart_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_hci", .open = hci_uart_tty_open, .close = hci_uart_tty_close, diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 5a0a5fc3d3ab..071844b58073 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -845,7 +845,6 @@ static void st_tty_flush_buffer(struct tty_struct *tty) } static struct tty_ldisc_ops st_ldisc_ops = { - .magic = TTY_LDISC_MAGIC, .name = "n_st", .open = st_tty_open, .close = st_tty_close, diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 8215cd77301f..675c374b32ee 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -382,7 +382,6 @@ static void ldisc_close(struct tty_struct *tty) /* The line discipline structure. */ static struct tty_ldisc_ops caif_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_caif", .open = ldisc_open, .close = ldisc_close, diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 30c8d53c9745..31ba6664503d 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -697,7 +697,6 @@ static int slcan_ioctl(struct tty_struct *tty, struct file *file, static struct tty_ldisc_ops slc_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "slcan", .open = slcan_open, .close = slcan_close, diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 71d6629e65c9..6f71eff9c52e 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -749,7 +749,6 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file, static struct tty_ldisc_ops sp_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "6pack", .open = sixpack_open, .close = sixpack_close, diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 17be2bb2985c..65154224d5b8 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -933,7 +933,6 @@ out: static struct tty_ldisc_ops ax_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "mkiss", .open = mkiss_open, .close = mkiss_close, diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 2a91caa4f37b..8b41aa3fb64e 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -372,7 +372,6 @@ ppp_asynctty_wakeup(struct tty_struct *tty) static struct tty_ldisc_ops ppp_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "ppp", .open = ppp_asynctty_open, .close = ppp_asynctty_close, diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index d8890923a9e3..576b6a93bf23 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -365,7 +365,6 @@ ppp_sync_wakeup(struct tty_struct *tty) static struct tty_ldisc_ops ppp_sync_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "pppsync", .open = ppp_sync_open, .close = ppp_sync_close, diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index f81fb0b13a94..1ab124eba8eb 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -1263,7 +1263,6 @@ static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static struct tty_ldisc_ops sl_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "slip", .open = slip_open, .close = slip_close, diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c index 4fd0cbf7f931..bf26cc56b863 100644 --- a/drivers/pps/clients/pps-ldisc.c +++ b/drivers/pps/clients/pps-ldisc.c @@ -13,8 +13,6 @@ #include #include -#define PPS_TTY_MAGIC 0x0001 - static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status) { struct pps_device *pps; @@ -114,7 +112,6 @@ static int __init pps_tty_init(void) /* Init PPS_TTY data */ pps_ldisc_ops.owner = THIS_MODULE; - pps_ldisc_ops.magic = PPS_TTY_MAGIC; pps_ldisc_ops.name = "pps_tty"; pps_ldisc_ops.dcd_change = pps_tty_dcd_change; pps_ldisc_ops.open = pps_tty_open; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 51dafc06f541..b063bc608a8c 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2849,7 +2849,6 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) /* Line discipline for real tty */ static struct tty_ldisc_ops tty_ldisc_packet = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_gsm", .open = gsmld_open, .close = gsmld_close, diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 1363e659dc1d..290c757db1b9 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -787,7 +787,6 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list) static struct tty_ldisc_ops n_hdlc_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "hdlc", .open = n_hdlc_tty_open, .close = n_hdlc_tty_close, diff --git a/drivers/tty/n_null.c b/drivers/tty/n_null.c index ce03ae78f5c6..b8f67b5f1ef8 100644 --- a/drivers/tty/n_null.c +++ b/drivers/tty/n_null.c @@ -40,7 +40,6 @@ static void n_null_receivebuf(struct tty_struct *tty, static struct tty_ldisc_ops null_ldisc = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "n_null", .open = n_null_open, .close = n_null_close, diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 3161f0a535e3..2eb76ea1d88d 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -146,7 +146,6 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, static struct tty_ldisc_ops tty_ldisc_N_R3964 = { .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, .name = "R3964", .open = r3964_open, .close = r3964_close, diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 87ec15dbe10d..7c53185bce57 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2488,7 +2488,6 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, } static struct tty_ldisc_ops n_tty_ops = { - .magic = TTY_LDISC_MAGIC, .name = "n_tty", .open = n_tty_open, .close = n_tty_close, diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 572a07976116..31284b55bd4f 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -173,7 +173,6 @@ extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, struct tty_ldisc_ops { - int magic; char *name; int num; int flags; @@ -218,8 +217,6 @@ struct tty_ldisc { struct tty_struct *tty; }; -#define TTY_LDISC_MAGIC 0x5403 - #define LDISC_FLAG_DEFINED 0x00000001 #define MODULE_ALIAS_LDISC(ldisc) \ diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 1204c438e87d..16d009c9b6a0 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -453,7 +453,6 @@ void nci_uart_set_config(struct nci_uart *nu, int baudrate, int flow_ctrl) EXPORT_SYMBOL_GPL(nci_uart_set_config); static struct tty_ldisc_ops nci_uart_ldisc = { - .magic = TTY_LDISC_MAGIC, .owner = THIS_MODULE, .name = "n_nci", .open = nci_uart_tty_open, diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 161be8b7d131..61dfa86d444d 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -285,7 +285,6 @@ static void v253_wakeup(struct tty_struct *tty) } struct tty_ldisc_ops v253_ops = { - .magic = TTY_LDISC_MAGIC, .name = "cx20442", .owner = THIS_MODULE, .open = v253_open, diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index 57feb473a579..98198c7cc872 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -395,7 +395,6 @@ static void cx81801_wakeup(struct tty_struct *tty) } static struct tty_ldisc_ops cx81801_ops = { - .magic = TTY_LDISC_MAGIC, .name = "cx81801", .owner = THIS_MODULE, .open = cx81801_open, -- cgit From 5e30d3bf51ebb17f27bf66ae367cb0550857507a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:39 +0100 Subject: tty: n_tty, set tty_ldisc_ops::owner Set tty_ldisc_ops::owner to THIS_MODULE. This has no effect currently as n_tty cannot be built as a module. If someone ever tries to modularize tty, we wouldn't manage module's reference count as in other ldiscs. So fix this just in case. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-9-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 7c53185bce57..a6f3c5c148eb 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2488,6 +2488,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, } static struct tty_ldisc_ops n_tty_ops = { + .owner = THIS_MODULE, .name = "n_tty", .open = n_tty_open, .close = n_tty_close, -- cgit From f751ae1cbbf955d56162be85221c1f97c53a0683 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:40 +0100 Subject: tty: imx, use ms_to_ktime This really eliminates multiplications from the assembly. I would have thought they are optimized by inlining ktime_set, but not on x86_64 with gcc 10. Cc: Shawn Guo Cc: Sascha Hauer Cc: Pengutronix Kernel Team Cc: Fabio Estevam Cc: NXP Linux Team Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-10-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 8257597d034d..3f69356937ef 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -394,11 +394,7 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2) static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) { - long sec = msec / MSEC_PER_SEC; - long nsec = (msec % MSEC_PER_SEC) * 1000000; - ktime_t t = ktime_set(sec, nsec); - - hrtimer_start(hrt, t, HRTIMER_MODE_REL); + hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL); } /* called with port.lock taken and irqs off */ -- cgit From 60294d86f27c9d075ca9b700b7786cef706546b5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:41 +0100 Subject: tty: 8250, use ms_to_ktime This really eliminates multiplications from the assembly. I would have thought they are optimized by inlining ktime_set, but not on x86_64 with gcc 10. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-11-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index b0af13074cd3..167c1e3e53bc 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1487,11 +1487,7 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) { - long sec = msec / 1000; - long nsec = (msec % 1000) * 1000000; - ktime_t t = ktime_set(sec, nsec); - - hrtimer_start(hrt, t, HRTIMER_MODE_REL); + hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL); } static void __stop_tx_rs485(struct uart_8250_port *p) -- cgit From 7e3d3c08f17cf082dbfc86386a2e327ccb080c16 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:42 +0100 Subject: tty: 8250, cleanup em485 timers Initialize the variables directly by initializers in definitions. This is expected/usual for these kind of callback. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-12-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 167c1e3e53bc..9019f8f626bb 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1466,13 +1466,11 @@ EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx); static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) { - struct uart_8250_em485 *em485; - struct uart_8250_port *p; + struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485, + stop_tx_timer); + struct uart_8250_port *p = em485->port; unsigned long flags; - em485 = container_of(t, struct uart_8250_em485, stop_tx_timer); - p = em485->port; - serial8250_rpm_get(p); spin_lock_irqsave(&p->port.lock, flags); if (em485->active_timer == &em485->stop_tx_timer) { @@ -1482,6 +1480,7 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) } spin_unlock_irqrestore(&p->port.lock, flags); serial8250_rpm_put(p); + return HRTIMER_NORESTART; } @@ -1629,19 +1628,18 @@ static inline void start_tx_rs485(struct uart_port *port) static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) { - struct uart_8250_em485 *em485; - struct uart_8250_port *p; + struct uart_8250_em485 *em485 = container_of(t, struct uart_8250_em485, + start_tx_timer); + struct uart_8250_port *p = em485->port; unsigned long flags; - em485 = container_of(t, struct uart_8250_em485, start_tx_timer); - p = em485->port; - spin_lock_irqsave(&p->port.lock, flags); if (em485->active_timer == &em485->start_tx_timer) { __start_tx(&p->port); em485->active_timer = NULL; } spin_unlock_irqrestore(&p->port.lock, flags); + return HRTIMER_NORESTART; } -- cgit From 7a9ca6329807122b53955673ef453423d3e1a3ab Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:43 +0100 Subject: tty: 8250/serial_cs, propagate errors in simple_config The caller expects from the others (pfc_config and multi_config) to return standard error values. So do the same for simple_config too. We invert the if condition to handle the error case. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-13-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/serial_cs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 35ff6627c61b..63ea9c4da3d5 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -456,11 +456,11 @@ static int simple_config(struct pcmcia_device *link) * its base address, then try to grab any standard serial port * address, and finally try to get any free port. */ - if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) - goto found_port; - - dev_warn(&link->dev, "no usable port range found, giving up\n"); - return -1; + ret = pcmcia_loop_config(link, simple_config_check_notpicky, NULL); + if (ret) { + dev_warn(&link->dev, "no usable port range found, giving up\n"); + return ret; + } found_port: if (info->multi && (info->manfid == MANFID_3COM)) @@ -474,7 +474,7 @@ found_port: ret = pcmcia_enable_device(link); if (ret != 0) - return -1; + return ret; return setup_serial(link, info, link->resource[0]->start, link->irq); } -- cgit From 8ff694972fe4ba0d25396d8dee8f1c8894538aa3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:44 +0100 Subject: net: caif: inline register_ldisc register_ldisc only calls tty_register_ldisc. Inline register_ldisc into the only caller of register_ldisc, i.e. caif_ser_init. Now, caif_ser_init is symmetric to caif_ser_exit in this regard. Cc: "David S. Miller" Cc: Jakub Kicinski Cc: netdev@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-14-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/net/caif/caif_serial.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 675c374b32ee..da6fffb4d5a8 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -389,18 +389,6 @@ static struct tty_ldisc_ops caif_ldisc = { .write_wakeup = ldisc_tx_wakeup }; -static int register_ldisc(void) -{ - int result; - - result = tty_register_ldisc(N_CAIF, &caif_ldisc); - if (result < 0) { - pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF, - result); - return result; - } - return result; -} static const struct net_device_ops netdev_ops = { .ndo_open = caif_net_open, .ndo_stop = caif_net_close, @@ -443,7 +431,10 @@ static int __init caif_ser_init(void) { int ret; - ret = register_ldisc(); + ret = tty_register_ldisc(N_CAIF, &caif_ldisc); + if (ret < 0) + pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF, ret); + debugfsdir = debugfs_create_dir("caif_serial", NULL); return ret; } -- cgit From 9f3698e97df00dd5af8275a9433a7036be9388e9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:45 +0100 Subject: net: nfc: nci: remove memset of nci_uart_drivers nci_uart_drivers is a global definition, so there is no need to initialize its memory to zero during module load. Cc: "David S. Miller" Cc: Jakub Kicinski Cc: netdev@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-15-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- net/nfc/nci/uart.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 16d009c9b6a0..c9987d1cccdf 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -468,7 +468,6 @@ static struct tty_ldisc_ops nci_uart_ldisc = { static int __init nci_uart_init(void) { - memset(nci_uart_drivers, 0, sizeof(nci_uart_drivers)); return tty_register_ldisc(N_NCI, &nci_uart_ldisc); } -- cgit From c2a5a45c0276a2e183250f35f1db0a032ba00459 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:46 +0100 Subject: net: nfc: nci: drop nci_uart_ops::recv_buf There is noone setting nci_uart_ops::recv_buf, so the default one (nci_uart_default_recv_buf) is always used. So drop this hook, move nci_uart_default_recv_buf before the use in nci_uart_tty_receive and remove unused parameter flags. Cc: "David S. Miller" Cc: Jakub Kicinski Cc: netdev@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-16-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- include/net/nfc/nci_core.h | 2 - net/nfc/nci/uart.c | 136 ++++++++++++++++++++++----------------------- 2 files changed, 67 insertions(+), 71 deletions(-) diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h index 43c9c5d2bedb..bd76e8e082c0 100644 --- a/include/net/nfc/nci_core.h +++ b/include/net/nfc/nci_core.h @@ -430,8 +430,6 @@ struct nci_uart_ops { int (*open)(struct nci_uart *nci_uart); void (*close)(struct nci_uart *nci_uart); int (*recv)(struct nci_uart *nci_uart, struct sk_buff *skb); - int (*recv_buf)(struct nci_uart *nci_uart, const u8 *data, char *flags, - int count); int (*send)(struct nci_uart *nci_uart, struct sk_buff *skb); void (*tx_start)(struct nci_uart *nci_uart); void (*tx_done)(struct nci_uart *nci_uart); diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index c9987d1cccdf..5cf7d3729d5f 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -229,6 +229,72 @@ static void nci_uart_tty_wakeup(struct tty_struct *tty) nci_uart_tx_wakeup(nu); } +/* -- Default recv_buf handler -- + * + * This handler supposes that NCI frames are sent over UART link without any + * framing. It reads NCI header, retrieve the packet size and once all packet + * bytes are received it passes it to nci_uart driver for processing. + */ +static int nci_uart_default_recv_buf(struct nci_uart *nu, const u8 *data, + int count) +{ + int chunk_len; + + if (!nu->ndev) { + nfc_err(nu->tty->dev, + "receive data from tty but no NCI dev is attached yet, drop buffer\n"); + return 0; + } + + /* Decode all incoming data in packets + * and enqueue then for processing. + */ + while (count > 0) { + /* If this is the first data of a packet, allocate a buffer */ + if (!nu->rx_skb) { + nu->rx_packet_len = -1; + nu->rx_skb = nci_skb_alloc(nu->ndev, + NCI_MAX_PACKET_SIZE, + GFP_ATOMIC); + if (!nu->rx_skb) + return -ENOMEM; + } + + /* Eat byte after byte till full packet header is received */ + if (nu->rx_skb->len < NCI_CTRL_HDR_SIZE) { + skb_put_u8(nu->rx_skb, *data++); + --count; + continue; + } + + /* Header was received but packet len was not read */ + if (nu->rx_packet_len < 0) + nu->rx_packet_len = NCI_CTRL_HDR_SIZE + + nci_plen(nu->rx_skb->data); + + /* Compute how many bytes are missing and how many bytes can + * be consumed. + */ + chunk_len = nu->rx_packet_len - nu->rx_skb->len; + if (count < chunk_len) + chunk_len = count; + skb_put_data(nu->rx_skb, data, chunk_len); + data += chunk_len; + count -= chunk_len; + + /* Chcek if packet is fully received */ + if (nu->rx_packet_len == nu->rx_skb->len) { + /* Pass RX packet to driver */ + if (nu->ops.recv(nu, nu->rx_skb) != 0) + nfc_err(nu->tty->dev, "corrupted RX packet\n"); + /* Next packet will be a new one */ + nu->rx_skb = NULL; + } + } + + return 0; +} + /* nci_uart_tty_receive() * * Called by tty low level driver when receive data is @@ -250,7 +316,7 @@ static void nci_uart_tty_receive(struct tty_struct *tty, const u8 *data, return; spin_lock(&nu->rx_lock); - nu->ops.recv_buf(nu, (void *)data, flags, count); + nci_uart_default_recv_buf(nu, data, count); spin_unlock(&nu->rx_lock); tty_unthrottle(tty); @@ -321,72 +387,6 @@ static int nci_uart_send(struct nci_uart *nu, struct sk_buff *skb) return 0; } -/* -- Default recv_buf handler -- - * - * This handler supposes that NCI frames are sent over UART link without any - * framing. It reads NCI header, retrieve the packet size and once all packet - * bytes are received it passes it to nci_uart driver for processing. - */ -static int nci_uart_default_recv_buf(struct nci_uart *nu, const u8 *data, - char *flags, int count) -{ - int chunk_len; - - if (!nu->ndev) { - nfc_err(nu->tty->dev, - "receive data from tty but no NCI dev is attached yet, drop buffer\n"); - return 0; - } - - /* Decode all incoming data in packets - * and enqueue then for processing. - */ - while (count > 0) { - /* If this is the first data of a packet, allocate a buffer */ - if (!nu->rx_skb) { - nu->rx_packet_len = -1; - nu->rx_skb = nci_skb_alloc(nu->ndev, - NCI_MAX_PACKET_SIZE, - GFP_ATOMIC); - if (!nu->rx_skb) - return -ENOMEM; - } - - /* Eat byte after byte till full packet header is received */ - if (nu->rx_skb->len < NCI_CTRL_HDR_SIZE) { - skb_put_u8(nu->rx_skb, *data++); - --count; - continue; - } - - /* Header was received but packet len was not read */ - if (nu->rx_packet_len < 0) - nu->rx_packet_len = NCI_CTRL_HDR_SIZE + - nci_plen(nu->rx_skb->data); - - /* Compute how many bytes are missing and how many bytes can - * be consumed. - */ - chunk_len = nu->rx_packet_len - nu->rx_skb->len; - if (count < chunk_len) - chunk_len = count; - skb_put_data(nu->rx_skb, data, chunk_len); - data += chunk_len; - count -= chunk_len; - - /* Chcek if packet is fully received */ - if (nu->rx_packet_len == nu->rx_skb->len) { - /* Pass RX packet to driver */ - if (nu->ops.recv(nu, nu->rx_skb) != 0) - nfc_err(nu->tty->dev, "corrupted RX packet\n"); - /* Next packet will be a new one */ - nu->rx_skb = NULL; - } - } - - return 0; -} - /* -- Default recv handler -- */ static int nci_uart_default_recv(struct nci_uart *nu, struct sk_buff *skb) { @@ -403,8 +403,6 @@ int nci_uart_register(struct nci_uart *nu) nu->ops.send = nci_uart_send; /* Install default handlers if not overridden */ - if (!nu->ops.recv_buf) - nu->ops.recv_buf = nci_uart_default_recv_buf; if (!nu->ops.recv) nu->ops.recv = nci_uart_default_recv; -- cgit From 11771e0bf13c9fefc31481a4ebc9271b4d495892 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:47 +0100 Subject: net: nfc: nci: drop nci_uart_default_recv nci_uart_register returns -EINVAL immediately when nu->ops.recv is not set. So the same 'if' later never triggers so nci_uart_default_recv is never used. Drop it. Cc: "David S. Miller" Cc: Jakub Kicinski Cc: netdev@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-17-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- net/nfc/nci/uart.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 5cf7d3729d5f..9958b37d8f9d 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -387,12 +387,6 @@ static int nci_uart_send(struct nci_uart *nu, struct sk_buff *skb) return 0; } -/* -- Default recv handler -- */ -static int nci_uart_default_recv(struct nci_uart *nu, struct sk_buff *skb) -{ - return nci_recv_frame(nu->ndev, skb); -} - int nci_uart_register(struct nci_uart *nu) { if (!nu || !nu->ops.open || @@ -402,10 +396,6 @@ int nci_uart_register(struct nci_uart *nu) /* Set the send callback */ nu->ops.send = nci_uart_send; - /* Install default handlers if not overridden */ - if (!nu->ops.recv) - nu->ops.recv = nci_uart_default_recv; - /* Add this driver in the driver list */ if (nci_uart_drivers[nu->driver]) { pr_err("driver %d is already registered\n", nu->driver); -- cgit From 51f62a311c6d34b9529448271bb34e705cc5868f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:48 +0100 Subject: tty: con3215, remove tasklet for tty_wakeup tty_wakeup is safe to be called from all contexts. No need to schedule a tasklet for that. Let us call it directly like in other drivers. And delete the tasklet completely. Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-18-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/s390/char/con3215.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 671efee612af..5923a1f133ef 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -85,7 +85,6 @@ struct raw3215_info { int written; /* number of bytes in write requests */ struct raw3215_req *queued_read; /* pointer to queued read requests */ struct raw3215_req *queued_write;/* pointer to queued write requests */ - struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */ wait_queue_head_t empty_wait; /* wait queue for flushing */ struct timer_list timer; /* timer for delayed output */ int line_pos; /* position on the line (for tabs) */ @@ -329,21 +328,6 @@ static inline void raw3215_try_io(struct raw3215_info *raw) } } -/* - * Call tty_wakeup from tasklet context - */ -static void raw3215_wakeup(unsigned long data) -{ - struct raw3215_info *raw = (struct raw3215_info *) data; - struct tty_struct *tty; - - tty = tty_port_tty_get(&raw->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } -} - /* * Try to start the next IO and wake up processes waiting on the tty. */ @@ -352,7 +336,7 @@ static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty) raw3215_mk_write_req(raw); raw3215_try_io(raw); if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) - tasklet_schedule(&raw->tlet); + tty_wakeup(tty); } /* @@ -644,7 +628,6 @@ static struct raw3215_info *raw3215_alloc_info(void) timer_setup(&info->timer, raw3215_timeout, 0); init_waitqueue_head(&info->empty_wait); - tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info); tty_port_init(&info->port); return info; @@ -936,7 +919,6 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp) tty->closing = 1; /* Shutdown the terminal */ raw3215_shutdown(raw); - tasklet_kill(&raw->tlet); tty->closing = 0; tty_port_tty_set(&raw->port, NULL); } -- cgit From 56e9d0f95ad0118750b67af8fbf2920a6f930faf Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:49 +0100 Subject: tty: con3215, remove unneeded tty checks There is no need to check tty in these functions as it's always non-NULL. So remove the tests. Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-19-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/s390/char/con3215.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 5923a1f133ef..ae0dd9c1595c 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -948,8 +948,6 @@ static int tty3215_write(struct tty_struct * tty, struct raw3215_info *raw; int i, written; - if (!tty) - return 0; raw = (struct raw3215_info *) tty->driver_data; written = count; while (count > 0) { @@ -975,8 +973,6 @@ static int tty3215_put_char(struct tty_struct *tty, unsigned char ch) { struct raw3215_info *raw; - if (!tty) - return 0; raw = (struct raw3215_info *) tty->driver_data; raw3215_putchar(raw, ch); return 1; -- cgit From 2daedb1d1e453da14819d13e11bcd33b8cf85fa9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:50 +0100 Subject: tty: con3215, remove tty->driver_data casts Casts of 'void *' pointer are superfluous. So remove them. Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-20-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/s390/char/con3215.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index ae0dd9c1595c..d26947d743bc 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -911,9 +911,8 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp) */ static void tty3215_close(struct tty_struct *tty, struct file * filp) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; if (raw == NULL || tty->count > 1) return; tty->closing = 1; @@ -928,9 +927,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp) */ static int tty3215_write_room(struct tty_struct *tty) { - struct raw3215_info *raw; - - raw = (struct raw3215_info *) tty->driver_data; + struct raw3215_info *raw = tty->driver_data; /* Subtract TAB_STOP_SIZE to allow for a tab, 8 <<< 64K */ if ((RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE) >= 0) @@ -945,10 +942,9 @@ static int tty3215_write_room(struct tty_struct *tty) static int tty3215_write(struct tty_struct * tty, const unsigned char *buf, int count) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; int i, written; - raw = (struct raw3215_info *) tty->driver_data; written = count; while (count > 0) { for (i = 0; i < count; i++) @@ -971,10 +967,10 @@ static int tty3215_write(struct tty_struct * tty, */ static int tty3215_put_char(struct tty_struct *tty, unsigned char ch) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; raw3215_putchar(raw, ch); + return 1; } @@ -987,17 +983,15 @@ static void tty3215_flush_chars(struct tty_struct *tty) */ static int tty3215_chars_in_buffer(struct tty_struct *tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; return raw->count; } static void tty3215_flush_buffer(struct tty_struct *tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; raw3215_flush_buffer(raw); tty_wakeup(tty); } @@ -1007,9 +1001,8 @@ static void tty3215_flush_buffer(struct tty_struct *tty) */ static void tty3215_throttle(struct tty_struct * tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; raw->flags |= RAW3215_THROTTLED; } @@ -1018,10 +1011,9 @@ static void tty3215_throttle(struct tty_struct * tty) */ static void tty3215_unthrottle(struct tty_struct * tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; unsigned long flags; - raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_THROTTLED) { spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->flags &= ~RAW3215_THROTTLED; @@ -1035,9 +1027,8 @@ static void tty3215_unthrottle(struct tty_struct * tty) */ static void tty3215_stop(struct tty_struct *tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; - raw = (struct raw3215_info *) tty->driver_data; raw->flags |= RAW3215_STOPPED; } @@ -1046,10 +1037,9 @@ static void tty3215_stop(struct tty_struct *tty) */ static void tty3215_start(struct tty_struct *tty) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; unsigned long flags; - raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_STOPPED) { spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->flags &= ~RAW3215_STOPPED; -- cgit From df11abeb2e6007c11c611f66ae564ab52775fb24 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:51 +0100 Subject: tty: jsm_tty, make char+error handling readable The code for char+error handling in jsm_input was complete mess of letters. Introduce 3 new local variables and use them with care. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-21-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm_tty.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 512b77195e9f..8e42a7682c63 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -603,18 +603,22 @@ void jsm_input(struct jsm_channel *ch) if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { for (i = 0; i < s; i++) { + u8 chr = ch->ch_rqueue[tail + i]; + u8 error = ch->ch_equeue[tail + i]; + char flag = TTY_NORMAL; + /* - * Give the Linux ld the flags in the - * format it likes. + * Give the Linux ld the flags in the format it + * likes. */ - 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); - else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE) - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_FRAME); - else - tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_NORMAL); + if (error & UART_LSR_BI) + flag = TTY_BREAK; + else if (error & UART_LSR_PE) + flag = TTY_PARITY; + else if (error & UART_LSR_FE) + flag = TTY_FRAME; + + tty_insert_flip_char(port, chr, flag); } } else { tty_insert_flip_string(port, ch->ch_rqueue + tail, s); -- cgit From d01a83590b7d8c647337fb641b5bf09a0a8b0da2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:52 +0100 Subject: tty: nozomi, remove struct buffer It is unused. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-22-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/nozomi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 861e95043191..83490925a3e2 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -359,12 +359,6 @@ struct nozomi { u32 open_ttys; }; -/* This is a data packet that is read or written to/from card */ -struct buffer { - u32 size; /* size is the length of the data buffer */ - u8 *data; -} __attribute__ ((packed)); - /* Global variables */ static const struct pci_device_id nozomi_pci_tbl[] = { {PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */ -- cgit From 83e826bf8f4ffd7d3370822d47c0c62732ee5402 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:53 +0100 Subject: tty: nozomi, remove init/exit messages Remove useless prints from init and exit functions. The version is artificial anyway. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-23-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/nozomi.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 83490925a3e2..1ec975d66528 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -47,9 +47,6 @@ #include - -#define VERSION_STRING DRIVER_DESC " 2.1d" - /* Default debug printout level */ #define NOZOMI_DEBUG_LEVEL 0x00 static int debug = NOZOMI_DEBUG_LEVEL; @@ -89,7 +86,6 @@ do { \ /* Defines */ #define NOZOMI_NAME "nozomi" #define NOZOMI_NAME_TTY "nozomi_tty" -#define DRIVER_DESC "Nozomi driver" #define NTTY_TTY_MAXMINORS 256 #define NTTY_FIFO_BUFFER_SIZE 8192 @@ -1841,8 +1837,6 @@ static __init int nozomi_init(void) { int ret; - printk(KERN_INFO "Initializing %s\n", VERSION_STRING); - ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); if (!ntty_driver) return -ENOMEM; @@ -1882,7 +1876,6 @@ free_tty: static __exit void nozomi_exit(void) { - printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); pci_unregister_driver(&nozomi_driver); tty_unregister_driver(ntty_driver); put_tty_driver(ntty_driver); @@ -1892,4 +1885,4 @@ module_init(nozomi_init); module_exit(nozomi_exit); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_DESCRIPTION("Nozomi driver"); -- cgit From 0da4c58df1ce79daaae317ed9f4fe962b53de3a6 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:54 +0100 Subject: tty: nozomi, remove useless debug prints These are either commented out or can be printed by tracing mechanisms. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-24-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/nozomi.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 1ec975d66528..9a2d78ace49b 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -777,7 +777,6 @@ static int receive_data(enum port_type index, struct nozomi *dc) int i, ret; size = __le32_to_cpu(readl(addr)); - /* DBG1( "%d bytes port: %d", size, index); */ if (tty && tty_throttled(tty)) { DBG1("No room in tty, don't read data, don't ack interrupt, " @@ -1308,8 +1307,6 @@ static int nozomi_card_init(struct pci_dev *pdev, int ndev_idx; int i; - dev_dbg(&pdev->dev, "Init, new card found\n"); - for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) if (!ndevs[ndev_idx]) break; @@ -1443,8 +1440,6 @@ static void tty_exit(struct nozomi *dc) { unsigned int i; - DBG1(" "); - for (i = 0; i < MAX_PORT; ++i) tty_port_tty_hangup(&dc->port[i].port, false); @@ -1609,8 +1604,6 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, struct port *port = tty->driver_data; unsigned long flags; - /* DBG1( "WRITEx: %d, index = %d", count, index); */ - if (!dc || !port) return -ENODEV; @@ -1736,8 +1729,6 @@ static int ntty_ioctl(struct tty_struct *tty, struct port *port = tty->driver_data; int rval = -ENOIOCTLCMD; - DBG1("******** IOCTL, cmd: %d", cmd); - switch (cmd) { case TIOCMIWAIT: { struct async_icount cprev = port->tty_icount; @@ -1763,7 +1754,6 @@ static void ntty_unthrottle(struct tty_struct *tty) struct nozomi *dc = get_dc_by_tty(tty); unsigned long flags; - DBG1("UNTHROTTLE"); spin_lock_irqsave(&dc->spin_mutex, flags); enable_transmit_dl(tty->index % MAX_PORT, dc); set_rts(tty, 1); @@ -1780,7 +1770,6 @@ static void ntty_throttle(struct tty_struct *tty) struct nozomi *dc = get_dc_by_tty(tty); unsigned long flags; - DBG1("THROTTLE"); spin_lock_irqsave(&dc->spin_mutex, flags); set_rts(tty, 0); spin_unlock_irqrestore(&dc->spin_mutex, flags); -- cgit From 4c472fc02e2a0f4c4e9a1c69f4b63c36df150e40 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:55 +0100 Subject: tty: vcc, make globals static These are used only in this unit, so make them static. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-25-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vcc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index e2d6205f83ce..50bf9011a0c4 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -66,9 +66,9 @@ static struct tty_driver *vcc_tty_driver; static struct vcc_port *vcc_table[VCC_MAX_PORTS]; static DEFINE_SPINLOCK(vcc_table_lock); -int vcc_dbg; -int vcc_dbg_ldc; -int vcc_dbg_vio; +static unsigned int vcc_dbg; +static unsigned int vcc_dbg_ldc; +static unsigned int vcc_dbg_vio; module_param(vcc_dbg, uint, 0664); module_param(vcc_dbg_ldc, uint, 0664); -- cgit From 7330019160757744706cd559da935fae193058e5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:56 +0100 Subject: tty: vcc, drop version dump The version number is artificial, no need to dump it to logs during initialization. Cc: "David S. Miller" Cc: Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-26-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vcc.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index 50bf9011a0c4..31b8a9a77375 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -14,16 +14,9 @@ #include #include -#define DRV_MODULE_NAME "vcc" -#define DRV_MODULE_VERSION "1.1" -#define DRV_MODULE_RELDATE "July 1, 2017" - -static char version[] = - DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")"; - MODULE_DESCRIPTION("Sun LDOM virtual console concentrator driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); +MODULE_VERSION("1.1"); struct vcc_port { struct vio_driver_state vio; @@ -1066,8 +1059,6 @@ static int vcc_tty_init(void) { int rv; - pr_info("VCC: %s\n", version); - vcc_tty_driver = tty_alloc_driver(VCC_MAX_PORTS, VCC_TTY_FLAGS); if (IS_ERR(vcc_tty_driver)) { pr_err("VCC: TTY driver alloc failed\n"); -- cgit From 9af6f74d671ef3e5d3062511f229287e9f844b36 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:57 +0100 Subject: tty: vcc, use name strings directly Do not define global variables for driver/device names, use the strings directly. Cc: "David S. Miller" Cc: sparclinux@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-27-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vcc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index 31b8a9a77375..a6cdbd170a61 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -52,8 +52,6 @@ struct vcc_port { #define VCC_CTL_BREAK -1 #define VCC_CTL_HUP -2 -static const char vcc_driver_name[] = "vcc"; -static const char vcc_device_node[] = "vcc"; static struct tty_driver *vcc_tty_driver; static struct vcc_port *vcc_table[VCC_MAX_PORTS]; @@ -1065,8 +1063,8 @@ static int vcc_tty_init(void) return PTR_ERR(vcc_tty_driver); } - vcc_tty_driver->driver_name = vcc_driver_name; - vcc_tty_driver->name = vcc_device_node; + vcc_tty_driver->driver_name = "vcc"; + vcc_tty_driver->name = "vcc"; vcc_tty_driver->minor_start = VCC_MINOR_START; vcc_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; -- cgit From 5c58097eeb9a4bc67a81dfcd95e328e59f3f0ae1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:58 +0100 Subject: tty: vcc, remove useless tty checks All these functions are called with a valid tty pointer, no need to check that. Cc: "David S. Miller" Cc: sparclinux@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-28-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vcc.c | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index a6cdbd170a61..04a792749816 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -726,11 +726,6 @@ static int vcc_open(struct tty_struct *tty, struct file *vcc_file) { struct vcc_port *port; - if (unlikely(!tty)) { - pr_err("VCC: open: Invalid TTY handle\n"); - return -ENXIO; - } - if (tty->count > 1) return -EBUSY; @@ -764,11 +759,6 @@ static int vcc_open(struct tty_struct *tty, struct file *vcc_file) static void vcc_close(struct tty_struct *tty, struct file *vcc_file) { - if (unlikely(!tty)) { - pr_err("VCC: close: Invalid TTY handle\n"); - return; - } - if (unlikely(tty->count > 1)) return; @@ -796,11 +786,6 @@ static void vcc_hangup(struct tty_struct *tty) { struct vcc_port *port; - if (unlikely(!tty)) { - pr_err("VCC: hangup: Invalid TTY handle\n"); - return; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: hangup: Failed to find VCC port\n"); @@ -830,11 +815,6 @@ static int vcc_write(struct tty_struct *tty, const unsigned char *buf, int tosend = 0; int rv = -EINVAL; - if (unlikely(!tty)) { - pr_err("VCC: write: Invalid TTY handle\n"); - return -ENXIO; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: write: Failed to find VCC port"); @@ -895,11 +875,6 @@ static int vcc_write_room(struct tty_struct *tty) struct vcc_port *port; u64 num; - if (unlikely(!tty)) { - pr_err("VCC: write_room: Invalid TTY handle\n"); - return -ENXIO; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: write_room: Failed to find VCC port\n"); @@ -918,11 +893,6 @@ static int vcc_chars_in_buffer(struct tty_struct *tty) struct vcc_port *port; u64 num; - if (unlikely(!tty)) { - pr_err("VCC: chars_in_buffer: Invalid TTY handle\n"); - return -ENXIO; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: chars_in_buffer: Failed to find VCC port\n"); @@ -941,11 +911,6 @@ static int vcc_break_ctl(struct tty_struct *tty, int state) struct vcc_port *port; unsigned long flags; - if (unlikely(!tty)) { - pr_err("VCC: break_ctl: Invalid TTY handle\n"); - return -ENXIO; - } - port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: break_ctl: Failed to find VCC port\n"); @@ -976,11 +941,6 @@ static int vcc_install(struct tty_driver *driver, struct tty_struct *tty) struct tty_port *port_tty; int ret; - if (unlikely(!tty)) { - pr_err("VCC: install: Invalid TTY handle\n"); - return -ENXIO; - } - if (tty->index >= VCC_MAX_PORTS) return -EINVAL; @@ -1015,11 +975,6 @@ static void vcc_cleanup(struct tty_struct *tty) { struct vcc_port *port; - if (unlikely(!tty)) { - pr_err("VCC: cleanup: Invalid TTY handle\n"); - return; - } - port = vcc_get(tty->index, true); if (port) { port->tty = NULL; -- cgit From a32c97fd42639648707a7e0fe7abeb1f6954b27e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:21:59 +0100 Subject: tty: xtensa/iss, drop serial_version & serial_name There is no need to print the information during module load. Neither to print some artificial version. So drop these strings and a print. Cc: Chris Zankel Cc: Max Filippov Cc: linux-xtensa@linux-xtensa.org Acked-by: Max Filippov Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-29-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/platforms/iss/console.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index af81a62faba6..1179011044a7 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -37,9 +37,6 @@ static struct timer_list serial_timer; static DEFINE_SPINLOCK(timer_lock); -static char *serial_version = "0.1"; -static char *serial_name = "ISS serial driver"; - /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its async structure into @@ -149,7 +146,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) static int rs_proc_show(struct seq_file *m, void *v) { - seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); + seq_printf(m, "serinfo:1.0 driver:0.1\n"); return 0; } @@ -172,8 +169,6 @@ int __init rs_init(void) serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES); - pr_info("%s %s\n", serial_name, serial_version); - /* Initialize the tty_driver structure */ serial_driver->driver_name = "iss_serial"; -- cgit From 0894b13467a2771bd282e280cd5cc7049285c4e7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:00 +0100 Subject: tty: xtensa/iss, don't reassign to tty->port We already do tty_port_link_device in rs_init, so we don't need to reassign a port to tty->port. It would be too late in tty::ops::open anyway. Cc: Chris Zankel Cc: Max Filippov Cc: linux-xtensa@linux-xtensa.org Acked-by: Max Filippov Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-30-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/platforms/iss/console.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 1179011044a7..5d7f9c638437 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -48,7 +48,6 @@ static void rs_poll(struct timer_list *); static int rs_open(struct tty_struct *tty, struct file * filp) { - tty->port = &serial_port; spin_lock_bh(&timer_lock); if (tty->count == 1) { timer_setup(&serial_timer, rs_poll, 0); -- cgit From bd5b219425692f4a353d07f5b182e9c71bbcffc2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:01 +0100 Subject: tty: xtensa/iss, remove stale comments These are likely taken over from amiserial. iss doesn't do anything of that. Cc: Chris Zankel Cc: Max Filippov Cc: linux-xtensa@linux-xtensa.org Acked-by: Max Filippov Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-31-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/platforms/iss/console.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 5d7f9c638437..3b89d9ceb06a 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -37,13 +37,6 @@ static struct timer_list serial_timer; static DEFINE_SPINLOCK(timer_lock); -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ - static void rs_poll(struct timer_list *); static int rs_open(struct tty_struct *tty, struct file * filp) @@ -58,17 +51,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp) return 0; } - -/* - * ------------------------------------------------------------ - * iss_serial_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ static void rs_close(struct tty_struct *tty, struct file * filp) { spin_lock_bh(&timer_lock); -- cgit From 5a1a8425c4436b7a7596a0cce7857bc058c6c360 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:02 +0100 Subject: tty: xtensa/iss, setup the timer statically Use DEFINE_TIMER and avoid runtime initialization of the serial_timer. Cc: Chris Zankel Cc: Max Filippov Cc: linux-xtensa@linux-xtensa.org Acked-by: Max Filippov Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-32-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/platforms/iss/console.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 3b89d9ceb06a..8ea261b8c022 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -31,21 +31,18 @@ #define SERIAL_MAX_NUM_LINES 1 #define SERIAL_TIMER_VALUE (HZ / 10) +static void rs_poll(struct timer_list *); + static struct tty_driver *serial_driver; static struct tty_port serial_port; -static struct timer_list serial_timer; - +static DEFINE_TIMER(serial_timer, rs_poll); static DEFINE_SPINLOCK(timer_lock); -static void rs_poll(struct timer_list *); - static int rs_open(struct tty_struct *tty, struct file * filp) { spin_lock_bh(&timer_lock); - if (tty->count == 1) { - timer_setup(&serial_timer, rs_poll, 0); + if (tty->count == 1) mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); - } spin_unlock_bh(&timer_lock); return 0; -- cgit From ba444ea3bc9377c0445990da1ce7d5eb33b099d8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:03 +0100 Subject: tty: xtensa/iss, make rs_init static To fix the warning: warning: no previous prototype for 'rs_init' Cc: Chris Zankel Cc: Max Filippov Cc: linux-xtensa@linux-xtensa.org Acked-by: Max Filippov Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-33-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/platforms/iss/console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 8ea261b8c022..1e215cf5ad03 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -141,7 +141,7 @@ static const struct tty_operations serial_ops = { .proc_show = rs_proc_show, }; -int __init rs_init(void) +static int __init rs_init(void) { tty_port_init(&serial_port); -- cgit From 6c2e6317c975c3cef1e08482a6ed8b734831ffbe Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:04 +0100 Subject: tty: do not check tty_unregister_driver's return value These drivers check tty_unregister_driver return value. But they don't handle a failure correctly (they free the driver in any case). So stop checking tty_unregister_driver return value and remove also the prints. In the next patch, tty_unregister_driver's return type will be switched to void. Cc: Chris Zankel Cc: Max Filippov Cc: linux-xtensa@linux-xtensa.org Cc: Jiri Kosina Cc: David Sterba Reviewed-by: Max Filippov Acked-by: David Sterba Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-34-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/platforms/iss/console.c | 6 +----- drivers/tty/amiserial.c | 8 ++------ drivers/tty/ipwireless/tty.c | 7 +------ drivers/tty/moxa.c | 4 +--- drivers/tty/serial/kgdb_nmi.c | 4 +--- drivers/tty/synclink_gt.c | 5 +---- 6 files changed, 7 insertions(+), 27 deletions(-) diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 1e215cf5ad03..a3dda25a4e45 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -171,11 +171,7 @@ static int __init rs_init(void) static __exit void rs_exit(void) { - int error; - - if ((error = tty_unregister_driver(serial_driver))) - pr_err("ISS_SERIAL: failed to unregister serial driver (%d)\n", - error); + tty_unregister_driver(serial_driver); put_tty_driver(serial_driver); tty_port_destroy(&serial_port); } diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 18b78ea110ef..0c8157fab17f 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1622,21 +1622,17 @@ fail_put_tty_driver: static int __exit amiga_serial_remove(struct platform_device *pdev) { - int error; struct serial_state *state = platform_get_drvdata(pdev); /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - error = tty_unregister_driver(serial_driver); - if (error) - printk("SERIAL: failed to unregister serial driver (%d)\n", - error); + tty_unregister_driver(serial_driver); put_tty_driver(serial_driver); tty_port_destroy(&state->tport); free_irq(IRQ_AMIGA_TBE, state); free_irq(IRQ_AMIGA_RBF, state); - return error; + return 0; } static struct platform_driver amiga_serial_driver = { diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 6dacbc5e286c..1836746991b5 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -596,13 +596,8 @@ int ipwireless_tty_init(void) void ipwireless_tty_release(void) { - int ret; - - ret = tty_unregister_driver(ipw_tty_driver); + tty_unregister_driver(ipw_tty_driver); put_tty_driver(ipw_tty_driver); - if (ret != 0) - printk(KERN_ERR IPWIRELESS_PCCARD_NAME - ": tty_unregister_driver failed with code %d\n", ret); } int ipwireless_tty_is_modem(struct ipw_tty *tty) diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 9f13f7d49dd7..32eb6b5e510f 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1118,9 +1118,7 @@ static void __exit moxa_exit(void) del_timer_sync(&moxaTimer); - if (tty_unregister_driver(moxaDriver)) - printk(KERN_ERR "Couldn't unregister MOXA Intellio family " - "serial driver\n"); + tty_unregister_driver(moxaDriver); put_tty_driver(moxaDriver); } diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index 6004c0c1d173..db059b66438e 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -373,9 +373,7 @@ int kgdb_unregister_nmi_console(void) if (ret) return ret; - ret = tty_unregister_driver(kgdb_nmi_tty_driver); - if (ret) - return ret; + tty_unregister_driver(kgdb_nmi_tty_driver); put_tty_driver(kgdb_nmi_tty_driver); return 0; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 644173786bf0..4727a41158b0 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3705,7 +3705,6 @@ static const struct tty_operations ops = { static void slgt_cleanup(void) { - int rc; struct slgt_info *info; struct slgt_info *tmp; @@ -3714,9 +3713,7 @@ static void slgt_cleanup(void) if (serial_driver) { for (info=slgt_device_list ; info != NULL ; info=info->next_device) tty_unregister_device(serial_driver, info->line); - rc = tty_unregister_driver(serial_driver); - if (rc) - DBGERR(("tty_unregister_driver error=%d\n", rc)); + tty_unregister_driver(serial_driver); put_tty_driver(serial_driver); } -- cgit From a872ab4d6d191cca1ce84b945e394bd6a8d84dd9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:05 +0100 Subject: tty: let tty_unregister_driver return void Now that noone checks the return value, switch the return type of tty_unregister_driver to void. We can do that as we always return zero. Generally, drivers are not allowed to call tty_unregister_driver while there are open devices. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-35-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 9 +-------- include/linux/tty.h | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 74733ec8f565..c8cbf08b6dcf 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3525,21 +3525,14 @@ EXPORT_SYMBOL(tty_register_driver); /* * Called by a tty driver to unregister itself. */ -int tty_unregister_driver(struct tty_driver *driver) +void tty_unregister_driver(struct tty_driver *driver) { -#if 0 - /* FIXME */ - if (driver->refcount) - return -EBUSY; -#endif unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), driver->num); mutex_lock(&tty_mutex); list_del(&driver->tty_drivers); mutex_unlock(&tty_mutex); - return 0; } - EXPORT_SYMBOL(tty_unregister_driver); dev_t tty_devnum(struct tty_struct *tty) diff --git a/include/linux/tty.h b/include/linux/tty.h index 95fc2f100f12..51f56e5ec955 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -482,7 +482,7 @@ extern void stop_tty(struct tty_struct *tty); extern void __start_tty(struct tty_struct *tty); extern void start_tty(struct tty_struct *tty); extern int tty_register_driver(struct tty_driver *driver); -extern int tty_unregister_driver(struct tty_driver *driver); +extern void tty_unregister_driver(struct tty_driver *driver); extern struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev); extern struct device *tty_register_device_attr(struct tty_driver *driver, -- cgit From a846dcf9d7295dd45493002fdde081f1667a85d3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:06 +0100 Subject: tty: localise ptychar and make it const ptychar was not const, so mark it as such. And move this variable to the only place where it's used. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-36-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index c8cbf08b6dcf..7cf57e6cadbf 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1196,8 +1196,6 @@ int tty_send_xchar(struct tty_struct *tty, char ch) return 0; } -static char ptychar[] = "pqrstuvwxyzabcde"; - /** * pty_line_name - generate name for a pty * @driver: the tty driver in use @@ -1211,6 +1209,7 @@ static char ptychar[] = "pqrstuvwxyzabcde"; */ static void pty_line_name(struct tty_driver *driver, int index, char *p) { + static const char ptychar[] = "pqrstuvwxyzabcde"; int i = index + driver->name_base; /* ->name is initialized to "ttyp", but "tty" is expected */ sprintf(p, "%s%c%x", -- cgit From b9b90fe655c0bd816847ac1bcbf179cfa2981ecb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:09 +0100 Subject: tty: synclink_gt, drop unneeded forward declarations Forward declarations make the code larger and rewrites harder. Harder as they are often omitted from global changes. Remove forward declarations which are not really needed, i.e. the definition of the function is before its first use. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-39-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/synclink_gt.c | 57 +---------------------------------------------- 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 4727a41158b0..1db908f62fde 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -137,37 +137,14 @@ MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)"); */ static struct tty_driver *serial_driver; -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); - /* - * generic HDLC support and callbacks + * generic HDLC support */ -#if SYNCLINK_GENERIC_HDLC #define dev_to_port(D) (dev_to_hdlc(D)->priv) -static void hdlcdev_tx_done(struct slgt_info *info); -static void hdlcdev_rx(struct slgt_info *info, char *buf, int size); -static int hdlcdev_init(struct slgt_info *info); -static void hdlcdev_exit(struct slgt_info *info); -#endif /* @@ -186,9 +163,6 @@ struct cond_wait { wait_queue_entry_t wait; unsigned int data; }; -static void init_cond_wait(struct cond_wait *w, unsigned int data); -static void add_cond_wait(struct cond_wait **head, struct cond_wait *w); -static void remove_cond_wait(struct cond_wait **head, struct cond_wait *w); static void flush_cond_wait(struct cond_wait **head); /* @@ -443,12 +417,8 @@ static void shutdown(struct slgt_info *info); static void program_hw(struct slgt_info *info); static void change_params(struct slgt_info *info); -static int register_test(struct slgt_info *info); -static int irq_test(struct slgt_info *info); -static int loopback_test(struct slgt_info *info); static int adapter_test(struct slgt_info *info); -static void reset_adapter(struct slgt_info *info); static void reset_port(struct slgt_info *info); static void async_mode(struct slgt_info *info); static void sync_mode(struct slgt_info *info); @@ -457,14 +427,12 @@ static void rx_stop(struct slgt_info *info); static void rx_start(struct slgt_info *info); static void reset_rbufs(struct slgt_info *info); static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last); -static void rdma_reset(struct slgt_info *info); static bool rx_get_frame(struct slgt_info *info); static bool rx_get_buf(struct slgt_info *info); static void tx_start(struct slgt_info *info); static void tx_stop(struct slgt_info *info); static void tx_set_idle(struct slgt_info *info); -static unsigned int free_tbuf_count(struct slgt_info *info); static unsigned int tbuf_bytes(struct slgt_info *info); static void reset_tbufs(struct slgt_info *info); static void tdma_reset(struct slgt_info *info); @@ -472,26 +440,10 @@ static bool tx_load(struct slgt_info *info, const char *buf, unsigned int count) static void get_signals(struct slgt_info *info); static void set_signals(struct slgt_info *info); -static void enable_loopback(struct slgt_info *info); static void set_rate(struct slgt_info *info, u32 data_rate); -static int bh_action(struct slgt_info *info); -static void bh_handler(struct work_struct *work); static void bh_transmit(struct slgt_info *info); -static void isr_serial(struct slgt_info *info); -static void isr_rdma(struct slgt_info *info); static void isr_txeom(struct slgt_info *info, unsigned short status); -static void isr_tdma(struct slgt_info *info); - -static int alloc_dma_bufs(struct slgt_info *info); -static void free_dma_bufs(struct slgt_info *info); -static int alloc_desc(struct slgt_info *info); -static void free_desc(struct slgt_info *info); -static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); -static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); - -static int alloc_tmp_rbuf(struct slgt_info *info); -static void free_tmp_rbuf(struct slgt_info *info); static void tx_timeout(struct timer_list *t); static void rx_timeout(struct timer_list *t); @@ -509,10 +461,6 @@ static int tx_abort(struct slgt_info *info); static int rx_enable(struct slgt_info *info, int enable); static int modem_input_wait(struct slgt_info *info,int arg); static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr); -static int 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 get_interface(struct slgt_info *info, int __user *if_mode); static int set_interface(struct slgt_info *info, int if_mode); static int set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); @@ -526,9 +474,6 @@ static int set_xctrl(struct slgt_info *info, int if_mode); /* * driver functions */ -static void add_device(struct slgt_info *info); -static void device_init(int adapter_num, struct pci_dev *pdev); -static int claim_resources(struct slgt_info *info); static void release_resources(struct slgt_info *info); /* -- cgit From 9d7fd54f2a2e1f4f7248fd4bc9e1e223c1cc54cc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:10 +0100 Subject: tty: hvc, drop unneeded forward declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forward declarations make the code larger and rewrites harder. Harder as they are often omitted from global changes. Remove forward declarations which are not really needed, i.e. the definition of the function is before its first use. Cc: linuxppc-dev@lists.ozlabs.org Reviewed-by: Tyrel Datwyler Acked-by: Uwe Kleine-König Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-40-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvcs.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index c90848919644..0b89d878a108 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -290,36 +290,11 @@ static LIST_HEAD(hvcs_structs); static DEFINE_SPINLOCK(hvcs_structs_lock); static DEFINE_MUTEX(hvcs_init_mutex); -static void hvcs_unthrottle(struct tty_struct *tty); -static void hvcs_throttle(struct tty_struct *tty); -static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance); - -static int hvcs_write(struct tty_struct *tty, - const unsigned char *buf, int count); -static int hvcs_write_room(struct tty_struct *tty); -static int hvcs_chars_in_buffer(struct tty_struct *tty); - -static int hvcs_has_pi(struct hvcs_struct *hvcsd); -static void hvcs_set_pi(struct hvcs_partner_info *pi, - struct hvcs_struct *hvcsd); static int hvcs_get_pi(struct hvcs_struct *hvcsd); static int hvcs_rescan_devices_list(void); -static int hvcs_partner_connect(struct hvcs_struct *hvcsd); static void hvcs_partner_free(struct hvcs_struct *hvcsd); -static int hvcs_enable_device(struct hvcs_struct *hvcsd, - uint32_t unit_address, unsigned int irq, struct vio_dev *dev); - -static int hvcs_open(struct tty_struct *tty, struct file *filp); -static void hvcs_close(struct tty_struct *tty, struct file *filp); -static void hvcs_hangup(struct tty_struct * tty); - -static int hvcs_probe(struct vio_dev *dev, - const struct vio_device_id *id); -static int hvcs_remove(struct vio_dev *dev); -static int __init hvcs_module_init(void); -static void __exit hvcs_module_exit(void); static int hvcs_initialize(void); #define HVCS_SCHED_READ 0x00000001 -- cgit From b93db97e1ca08e500305bc46b08c72e2232c4be1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:11 +0100 Subject: tty: n_gsm, remove duplicates of parameters dp, f, and i are only duplicates of gsmld_receive_buf's parameters. Use the parameters directly (cp, fp, and count) and delete these local variables. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-41-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index b063bc608a8c..7e1d19805aa4 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2416,27 +2416,24 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct gsm_mux *gsm = tty->disc_data; - const unsigned char *dp; - char *f; - int i; char flags = TTY_NORMAL; if (debug & 4) print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET, cp, count); - for (i = count, dp = cp, f = fp; i; i--, dp++) { - if (f) - flags = *f++; + for (; count; count--, cp++) { + if (fp) + flags = *fp++; switch (flags) { case TTY_NORMAL: - gsm->receive(gsm, *dp); + gsm->receive(gsm, *cp); break; case TTY_OVERRUN: case TTY_BREAK: case TTY_PARITY: case TTY_FRAME: - gsm_error(gsm, *dp, flags); + gsm_error(gsm, *cp, flags); break; default: WARN_ONCE(1, "%s: unknown flag %d\n", -- cgit From ab78b0c9fa9dfc02f823aac9f8174d4ee0585057 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:12 +0100 Subject: tty: cleanup tty_chars_in_buffer There is no need for 'else' when the 'if' part already returned. This makes tty_chars_in_buffer similar to tty_write_room too. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-42-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ioctl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 4de1c6ddb8ff..deffaefcf41d 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -57,8 +57,7 @@ int tty_chars_in_buffer(struct tty_struct *tty) { if (tty->ops->chars_in_buffer) return tty->ops->chars_in_buffer(tty); - else - return 0; + return 0; } EXPORT_SYMBOL(tty_chars_in_buffer); -- cgit From 10eb63e5a9b243181f0e87033875f94f3698afda Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:13 +0100 Subject: tty: make everyone's chars_in_buffer return >= 0 The tty line disciplines don't expect tty_operations::chars_in_buffer to return negative values. Fix the two drivers which violate this. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-43-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 2 +- drivers/tty/vcc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 7e1d19805aa4..da10e975829f 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -3056,7 +3056,7 @@ static int gsmtty_chars_in_buffer(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) - return -EINVAL; + return 0; return kfifo_len(&dlci->fifo); } diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index 04a792749816..3106df98558a 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -896,7 +896,7 @@ static int vcc_chars_in_buffer(struct tty_struct *tty) port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: chars_in_buffer: Failed to find VCC port\n"); - return -ENODEV; + return 0; } num = port->chars_in_buffer; -- cgit From 6bfbfcfc58005ee12d37b56a5e722618ef6bee8f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:14 +0100 Subject: tty: make everyone's write_room return >= 0 The tty line disciplines don't expect tty_operations::write_room to return negative values. Fix the five drivers which violate this. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210302062214.29627-44-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/gdm724x/gdm_tty.c | 2 +- drivers/tty/ipwireless/tty.c | 4 ++-- drivers/tty/n_gsm.c | 2 +- drivers/tty/vcc.c | 2 +- drivers/usb/serial/mos7720.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c index 6e813693a766..0ccc8c24e754 100644 --- a/drivers/staging/gdm724x/gdm_tty.c +++ b/drivers/staging/gdm724x/gdm_tty.c @@ -188,7 +188,7 @@ static int gdm_tty_write_room(struct tty_struct *tty) struct gdm *gdm = tty->driver_data; if (!GDM_TTY_READY(gdm)) - return -ENODEV; + return 0; return WRITE_SIZE; } diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 1836746991b5..99bb2f149ff5 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -235,10 +235,10 @@ static int ipw_write_room(struct tty_struct *linux_tty) /* FIXME: Exactly how is the tty object locked here .. */ if (!tty) - return -ENODEV; + return 0; if (!tty->port.count) - return -EINVAL; + return 0; room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; if (room < 0) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index da10e975829f..9e12f9cb1a98 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -3048,7 +3048,7 @@ static int gsmtty_write_room(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) - return -EINVAL; + return 0; return TX_SIZE - kfifo_len(&dlci->fifo); } diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index 3106df98558a..0a3a71e14df4 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -878,7 +878,7 @@ static int vcc_write_room(struct tty_struct *tty) port = vcc_get_ne(tty->index); if (unlikely(!port)) { pr_err("VCC: write_room: Failed to find VCC port\n"); - return -ENODEV; + return 0; } num = VCC_BUFF_LEN - port->chars_in_buffer; diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 701dfb32b129..bb3d39307d93 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1042,7 +1042,7 @@ static int mos7720_write_room(struct tty_struct *tty) mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) - return -ENODEV; + return 0; /* FIXME: Locking */ for (i = 0; i < NUM_URBS; ++i) { -- cgit From 196ebe5c000afbfe67b8561f716e365174552bd7 Mon Sep 17 00:00:00 2001 From: Julian Braha Date: Wed, 24 Feb 2021 23:42:48 -0500 Subject: drivers: tty: serial: IMX_EARLYCON: fix Kconfig dependency on SERIAL_CORE When SERIAL_IMX_EARLYCON is enabled, and SERIAL_CORE is disabled, Kbuild gives the following warning: WARNING: unmet direct dependencies detected for SERIAL_EARLYCON Depends on [n]: TTY [=y] && HAS_IOMEM [=y] && SERIAL_CORE [=n] Selected by [y]: - SERIAL_IMX_EARLYCON [=y] && TTY [=y] && HAS_IOMEM [=y] && (ARCH_MXC [=y] || COMPILE_TEST [=n]) && OF [=y] This is because SERIAL_IMX_EARLYCON selects SERIAL_EARLYCON, without selecting SERIAL_CORE, despite that config option depending on SERIAL_CORE. Signed-off-by: Julian Braha Link: https://lore.kernel.org/r/20210225044248.4745-1-julianbraha@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 0c4cd4a348f4..fb9731d05f9e 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -498,6 +498,7 @@ config SERIAL_IMX_EARLYCON bool "Earlycon on IMX serial port" depends on ARCH_MXC || COMPILE_TEST depends on OF + select SERIAL_CORE select SERIAL_EARLYCON select SERIAL_CORE_CONSOLE default y if SERIAL_IMX_CONSOLE -- cgit From 19d48787e31563b57f4f5549e926fbee46b394da Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 5 Mar 2021 06:38:54 +0900 Subject: tty: serial: samsung_tty: Add ucon_mask parameter This simplifies the code by removing the only distinction between the S3C2410 and S3C2440 codepaths. Signed-off-by: Hector Martin Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210304213902.83903-20-marcan@marcan.st Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 8ae3e03fbd8c..30adb15ed2c4 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -70,6 +70,7 @@ struct s3c24xx_uart_info { unsigned long num_clks; unsigned long clksel_mask; unsigned long clksel_shift; + unsigned long ucon_mask; /* uart port features */ @@ -1706,14 +1707,9 @@ static void s3c24xx_serial_resetport(struct uart_port *port, { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); unsigned long ucon = rd_regl(port, S3C2410_UCON); - unsigned int ucon_mask; - ucon_mask = info->clksel_mask; - if (info->type == PORT_S3C2440) - ucon_mask |= S3C2440_UCON0_DIVMASK; - - ucon &= ucon_mask; - wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + ucon &= (info->clksel_mask | info->ucon_mask); + wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); /* reset both fifos */ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); @@ -2449,6 +2445,7 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { .num_clks = 4, .clksel_mask = S3C2412_UCON_CLKMASK, .clksel_shift = S3C2412_UCON_CLKSHIFT, + .ucon_mask = S3C2440_UCON0_DIVMASK, }, .def_cfg = &(struct s3c2410_uartcfg) { .ucon = S3C2410_UCON_DEFAULT, -- cgit From 646891638301dad90e4dab9bc23e939575ad8012 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 5 Mar 2021 06:38:53 +0900 Subject: tty: serial: samsung_tty: Separate S3C64XX ops structure Instead of patching a single global ops structure depending on the port type, use a separate s3c64xx_serial_ops for the S3C64XX type. This allows us to mark the structures as const. Also split out s3c64xx_serial_shutdown into a separate function now that we have a separate ops structure; this avoids excessive branching control flow and mirrors s3c64xx_serial_startup. tx_claimed and rx_claimed are only used in the S3C24XX functions. Signed-off-by: Hector Martin Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210304213902.83903-19-marcan@marcan.st Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 71 ++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 30adb15ed2c4..33b421dbeb83 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1099,27 +1099,36 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) struct s3c24xx_uart_port *ourport = to_ourport(port); if (ourport->tx_claimed) { - if (!s3c24xx_serial_has_interrupt_mask(port)) - free_irq(ourport->tx_irq, ourport); + free_irq(ourport->tx_irq, ourport); ourport->tx_enabled = 0; ourport->tx_claimed = 0; ourport->tx_mode = 0; } if (ourport->rx_claimed) { - if (!s3c24xx_serial_has_interrupt_mask(port)) - free_irq(ourport->rx_irq, ourport); + free_irq(ourport->rx_irq, ourport); ourport->rx_claimed = 0; ourport->rx_enabled = 0; } - /* Clear pending interrupts and mask all interrupts */ - if (s3c24xx_serial_has_interrupt_mask(port)) { - free_irq(port->irq, ourport); + if (ourport->dma) + s3c24xx_serial_release_dma(ourport); - wr_regl(port, S3C64XX_UINTP, 0xf); - wr_regl(port, S3C64XX_UINTM, 0xf); - } + ourport->tx_in_progress = 0; +} + +static void s3c64xx_serial_shutdown(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + ourport->tx_enabled = 0; + ourport->tx_mode = 0; + ourport->rx_enabled = 0; + + free_irq(port->irq, ourport); + + wr_regl(port, S3C64XX_UINTP, 0xf); + wr_regl(port, S3C64XX_UINTM, 0xf); if (ourport->dma) s3c24xx_serial_release_dma(ourport); @@ -1194,9 +1203,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) /* For compatibility with s3c24xx Soc's */ ourport->rx_enabled = 1; - ourport->rx_claimed = 1; ourport->tx_enabled = 0; - ourport->tx_claimed = 1; spin_lock_irqsave(&port->lock, flags); @@ -1609,7 +1616,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, unsigned char c); #endif -static struct uart_ops s3c24xx_serial_ops = { +static const struct uart_ops s3c24xx_serial_ops = { .pm = s3c24xx_serial_pm, .tx_empty = s3c24xx_serial_tx_empty, .get_mctrl = s3c24xx_serial_get_mctrl, @@ -1632,6 +1639,29 @@ static struct uart_ops s3c24xx_serial_ops = { #endif }; +static const struct uart_ops s3c64xx_serial_ops = { + .pm = s3c24xx_serial_pm, + .tx_empty = s3c24xx_serial_tx_empty, + .get_mctrl = s3c24xx_serial_get_mctrl, + .set_mctrl = s3c24xx_serial_set_mctrl, + .stop_tx = s3c24xx_serial_stop_tx, + .start_tx = s3c24xx_serial_start_tx, + .stop_rx = s3c24xx_serial_stop_rx, + .break_ctl = s3c24xx_serial_break_ctl, + .startup = s3c64xx_serial_startup, + .shutdown = s3c64xx_serial_shutdown, + .set_termios = s3c24xx_serial_set_termios, + .type = s3c24xx_serial_type, + .release_port = s3c24xx_serial_release_port, + .request_port = s3c24xx_serial_request_port, + .config_port = s3c24xx_serial_config_port, + .verify_port = s3c24xx_serial_verify_port, +#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL) + .poll_get_char = s3c24xx_serial_get_poll_char, + .poll_put_char = s3c24xx_serial_put_poll_char, +#endif +}; + static struct uart_driver s3c24xx_uart_drv = { .owner = THIS_MODULE, .driver_name = "s3c2410_serial", @@ -1864,10 +1894,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, /* setup info for port */ port->dev = &platdev->dev; - /* Startup sequence is different for s3c64xx and higher SoC's */ - if (s3c24xx_serial_has_interrupt_mask(port)) - s3c24xx_serial_ops.startup = s3c64xx_serial_startup; - port->uartclk = 1; if (cfg->uart_flags & UPF_CONS_FLOW) { @@ -2015,6 +2041,17 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev) : ourport->drv_data->def_cfg; + switch (ourport->info->type) { + case PORT_S3C2410: + case PORT_S3C2412: + case PORT_S3C2440: + ourport->port.ops = &s3c24xx_serial_ops; + break; + case PORT_S3C6400: + ourport->port.ops = &s3c64xx_serial_ops; + break; + } + if (np) { of_property_read_u32(np, "samsung,uart-fifosize", &ourport->port.fifosize); -- cgit From aaf144059ba474229b6475866ec8cf16a5780871 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 5 Mar 2021 06:38:55 +0900 Subject: tty: serial: samsung_tty: Add s3c24xx_port_type This decouples the TTY layer PORT_ types, which are exposed to userspace, from the driver-internal flag of what kind of port this is. This removes s3c24xx_serial_has_interrupt_mask, which was just checking for a specific type anyway. Signed-off-by: Hector Martin Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210304213902.83903-21-marcan@marcan.st Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 112 ++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 42 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 33b421dbeb83..39b2eb165bdc 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -56,9 +56,15 @@ /* flag to ignore all characters coming in */ #define RXSTAT_DUMMY_READ (0x10000000) +enum s3c24xx_port_type { + TYPE_S3C24XX, + TYPE_S3C6400, +}; + struct s3c24xx_uart_info { char *name; - unsigned int type; + enum s3c24xx_port_type type; + unsigned int port_type; unsigned int fifosize; unsigned long rx_fifomask; unsigned long rx_fifoshift; @@ -229,16 +235,6 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port) return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE; } -/* - * s3c64xx and later SoC's include the interrupt mask and status registers in - * the controller itself, unlike the s3c24xx SoC's which have these registers - * in the interrupt controller. Check if the port type is s3c64xx or higher. - */ -static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port) -{ - return to_ourport(port)->info->type == PORT_S3C6400; -} - static void s3c24xx_serial_rx_enable(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); @@ -290,10 +286,14 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) if (!ourport->tx_enabled) return; - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); - else + break; + default: disable_irq_nosync(ourport->tx_irq); + break; + } if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) { dmaengine_pause(dma->tx_chan); @@ -354,10 +354,14 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport) u32 ucon; /* Mask Tx interrupt */ - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); - else + break; + default: disable_irq_nosync(ourport->tx_irq); + break; + } /* Enable tx dma mode */ ucon = rd_regl(port, S3C2410_UCON); @@ -387,11 +391,15 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport) wr_regl(port, S3C2410_UCON, ucon); /* Unmask Tx interrupt */ - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); - else + break; + default: enable_irq(ourport->tx_irq); + break; + } ourport->tx_mode = S3C24XX_TX_PIO; } @@ -514,11 +522,15 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) if (ourport->rx_enabled) { dev_dbg(port->dev, "stopping rx\n"); - if (s3c24xx_serial_has_interrupt_mask(port)) + switch (ourport->info->type) { + case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); - else + break; + default: disable_irq_nosync(ourport->rx_irq); + break; + } ourport->rx_enabled = 0; } if (dma && dma->rx_chan) { @@ -1543,14 +1555,12 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, static const char *s3c24xx_serial_type(struct uart_port *port) { - switch (port->type) { - case PORT_S3C2410: - return "S3C2410"; - case PORT_S3C2440: - return "S3C2440"; - case PORT_S3C2412: - return "S3C2412"; - case PORT_S3C6400: + struct s3c24xx_uart_port *ourport = to_ourport(port); + + switch (ourport->info->type) { + case TYPE_S3C24XX: + return "S3C24XX"; + case TYPE_S3C6400: return "S3C6400/10"; default: return NULL; @@ -1577,7 +1587,7 @@ static void s3c24xx_serial_config_port(struct uart_port *port, int flags) if (flags & UART_CONFIG_TYPE && s3c24xx_serial_request_port(port) == 0) - port->type = info->type; + port->type = info->port_type; } /* @@ -1588,7 +1598,7 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser) { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - if (ser->type != PORT_UNKNOWN && ser->type != info->type) + if (ser->type != PORT_UNKNOWN && ser->type != info->port_type) return -EINVAL; return 0; @@ -1927,11 +1937,16 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->tx_irq = ret + 1; } - if (!s3c24xx_serial_has_interrupt_mask(port)) { + switch (ourport->info->type) { + case TYPE_S3C24XX: ret = platform_get_irq(platdev, 1); if (ret > 0) ourport->tx_irq = ret; + break; + default: + break; } + /* * DMA is currently supported only on DT platforms, if DMA properties * are specified. @@ -1967,10 +1982,14 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, pr_warn("uart: failed to enable baudclk\n"); /* Keep all interrupts masked and cleared */ - if (s3c24xx_serial_has_interrupt_mask(port)) { + switch (ourport->info->type) { + case TYPE_S3C6400: wr_regl(port, S3C64XX_UINTM, 0xf); wr_regl(port, S3C64XX_UINTP, 0xf); wr_regl(port, S3C64XX_UINTSP, 0xf); + break; + default: + break; } dev_dbg(port->dev, "port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n", @@ -2042,12 +2061,10 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) ourport->drv_data->def_cfg; switch (ourport->info->type) { - case PORT_S3C2410: - case PORT_S3C2412: - case PORT_S3C2440: + case TYPE_S3C24XX: ourport->port.ops = &s3c24xx_serial_ops; break; - case PORT_S3C6400: + case TYPE_S3C6400: ourport->port.ops = &s3c64xx_serial_ops; break; } @@ -2175,7 +2192,8 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) if (port) { /* restore IRQ mask */ - if (s3c24xx_serial_has_interrupt_mask(port)) { + switch (ourport->info->type) { + case TYPE_S3C6400: { unsigned int uintm = 0xf; if (ourport->tx_enabled) @@ -2189,6 +2207,10 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) if (!IS_ERR(ourport->baudclk)) clk_disable_unprepare(ourport->baudclk); clk_disable_unprepare(ourport->clk); + break; + } + default: + break; } } @@ -2413,7 +2435,8 @@ static struct console s3c24xx_serial_console = { static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C2410 UART", - .type = PORT_S3C2410, + .type = TYPE_S3C24XX, + .port_type = PORT_S3C2410, .fifosize = 16, .rx_fifomask = S3C2410_UFSTAT_RXMASK, .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, @@ -2440,7 +2463,8 @@ static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = { static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C2412 UART", - .type = PORT_S3C2412, + .type = TYPE_S3C24XX, + .port_type = PORT_S3C2412, .fifosize = 64, .has_divslot = 1, .rx_fifomask = S3C2440_UFSTAT_RXMASK, @@ -2469,7 +2493,8 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = { static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C2440 UART", - .type = PORT_S3C2440, + .type = TYPE_S3C24XX, + .port_type = PORT_S3C2440, .fifosize = 64, .has_divslot = 1, .rx_fifomask = S3C2440_UFSTAT_RXMASK, @@ -2498,7 +2523,8 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S3C6400 UART", - .type = PORT_S3C6400, + .type = TYPE_S3C6400, + .port_type = PORT_S3C6400, .fifosize = 64, .has_divslot = 1, .rx_fifomask = S3C2440_UFSTAT_RXMASK, @@ -2526,7 +2552,8 @@ static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = { static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .info = &(struct s3c24xx_uart_info) { .name = "Samsung S5PV210 UART", - .type = PORT_S3C6400, + .type = TYPE_S3C6400, + .port_type = PORT_S3C6400, .has_divslot = 1, .rx_fifomask = S5PV210_UFSTAT_RXMASK, .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, @@ -2554,7 +2581,8 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { #define EXYNOS_COMMON_SERIAL_DRV_DATA \ .info = &(struct s3c24xx_uart_info) { \ .name = "Samsung Exynos UART", \ - .type = PORT_S3C6400, \ + .type = TYPE_S3C6400, \ + .port_type = PORT_S3C6400, \ .has_divslot = 1, \ .rx_fifomask = S5PV210_UFSTAT_RXMASK, \ .rx_fifoshift = S5PV210_UFSTAT_RXSHIFT, \ -- cgit From ad5613b98a48e71a13fdb945593c7e485ed49b55 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 5 Mar 2021 06:38:56 +0900 Subject: tty: serial: samsung_tty: IRQ rework * Split out s3c24xx_serial_tx_chars from s3c24xx_serial_tx_irq, where only the latter acquires the port lock. This will be necessary on platforms which have edge-triggered IRQs, as we need to call s3c24xx_serial_tx_chars to kick off transmission from outside IRQ context, with the port lock held. * Rename s3c24xx_serial_rx_chars to s3c24xx_serial_rx_irq for consistency with the above. All it does now is call two other functions anyway. Signed-off-by: Hector Martin Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210304213902.83903-22-marcan@marcan.st Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 39b2eb165bdc..7106eb238d8c 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -827,7 +827,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id) return IRQ_HANDLED; } -static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id) +static irqreturn_t s3c24xx_serial_rx_irq(int irq, void *dev_id) { struct s3c24xx_uart_port *ourport = dev_id; @@ -836,16 +836,12 @@ static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id) return s3c24xx_serial_rx_chars_pio(dev_id); } -static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) +static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport) { - struct s3c24xx_uart_port *ourport = id; struct uart_port *port = &ourport->port; struct circ_buf *xmit = &port->state->xmit; - unsigned long flags; int count, dma_count = 0; - spin_lock_irqsave(&port->lock, flags); - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); if (ourport->dma && ourport->dma->tx_chan && @@ -862,7 +858,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) wr_reg(port, S3C2410_UTXH, port->x_char); port->icount.tx++; port->x_char = 0; - goto out; + return; } /* if there isn't anything more to transmit, or the uart is now @@ -871,7 +867,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { s3c24xx_serial_stop_tx(port); - goto out; + return; } /* try and drain the buffer... */ @@ -893,7 +889,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (!count && dma_count) { s3c24xx_serial_start_tx_dma(ourport, dma_count); - goto out; + return; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { @@ -904,8 +900,18 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (uart_circ_empty(xmit)) s3c24xx_serial_stop_tx(port); +} + +static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id) +{ + struct s3c24xx_uart_port *ourport = id; + struct uart_port *port = &ourport->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + s3c24xx_serial_tx_chars(ourport); -out: spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; } @@ -919,11 +925,11 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) irqreturn_t ret = IRQ_HANDLED; if (pend & S3C64XX_UINTM_RXD_MSK) { - ret = s3c24xx_serial_rx_chars(irq, id); + ret = s3c24xx_serial_rx_irq(irq, id); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK); } if (pend & S3C64XX_UINTM_TXD_MSK) { - ret = s3c24xx_serial_tx_chars(irq, id); + ret = s3c24xx_serial_tx_irq(irq, id); wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK); } return ret; @@ -1155,7 +1161,7 @@ static int s3c24xx_serial_startup(struct uart_port *port) ourport->rx_enabled = 1; - ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0, + ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_irq, 0, s3c24xx_serial_portname(port), ourport); if (ret != 0) { @@ -1169,7 +1175,7 @@ static int s3c24xx_serial_startup(struct uart_port *port) ourport->tx_enabled = 1; - ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0, + ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_irq, 0, s3c24xx_serial_portname(port), ourport); if (ret) { -- cgit From 0906db90c722c9fa3d41e69c02ee962b8304da21 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 5 Mar 2021 06:38:57 +0900 Subject: tty: serial: samsung_tty: Use devm_ioremap_resource This picks up the non-posted I/O mode needed for Apple platforms to work properly. This removes the request/release functions, which are no longer necessary, since devm_ioremap_resource takes care of that already. Most other drivers already do it this way, anyway. Signed-off-by: Hector Martin Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210304213902.83903-23-marcan@marcan.st Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 7106eb238d8c..26cb05992e9f 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -1573,26 +1573,11 @@ static const char *s3c24xx_serial_type(struct uart_port *port) } } -#define MAP_SIZE (0x100) - -static void s3c24xx_serial_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, MAP_SIZE); -} - -static int s3c24xx_serial_request_port(struct uart_port *port) -{ - const char *name = s3c24xx_serial_portname(port); - - return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY; -} - static void s3c24xx_serial_config_port(struct uart_port *port, int flags) { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); - if (flags & UART_CONFIG_TYPE && - s3c24xx_serial_request_port(port) == 0) + if (flags & UART_CONFIG_TYPE) port->type = info->port_type; } @@ -1645,8 +1630,6 @@ static const struct uart_ops s3c24xx_serial_ops = { .shutdown = s3c24xx_serial_shutdown, .set_termios = s3c24xx_serial_set_termios, .type = s3c24xx_serial_type, - .release_port = s3c24xx_serial_release_port, - .request_port = s3c24xx_serial_request_port, .config_port = s3c24xx_serial_config_port, .verify_port = s3c24xx_serial_verify_port, #if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL) @@ -1668,8 +1651,6 @@ static const struct uart_ops s3c64xx_serial_ops = { .shutdown = s3c64xx_serial_shutdown, .set_termios = s3c24xx_serial_set_termios, .type = s3c24xx_serial_type, - .release_port = s3c24xx_serial_release_port, - .request_port = s3c24xx_serial_request_port, .config_port = s3c24xx_serial_config_port, .verify_port = s3c24xx_serial_verify_port, #if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL) @@ -1927,8 +1908,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, dev_dbg(port->dev, "resource %pR)\n", res); - port->membase = devm_ioremap(port->dev, res->start, resource_size(res)); - if (!port->membase) { + port->membase = devm_ioremap_resource(port->dev, res); + if (IS_ERR(port->membase)) { dev_err(port->dev, "failed to remap controller address\n"); return -EBUSY; } -- cgit From b8466833391ed3362c1195aa0373198bdeddf881 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 5 Mar 2021 06:38:58 +0900 Subject: dt-bindings: serial: samsung: Add apple,s5l-uart compatible Apple mobile devices originally used Samsung SoCs (starting with the S5L8900), and their current in-house SoCs continue to use compatible UART peripherals. We'll call this UART variant apple,s5l-uart. Signed-off-by: Hector Martin Reviewed-by: Krzysztof Kozlowski Reviewed-by: Linus Walleij Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210304213902.83903-24-marcan@marcan.st Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/samsung_uart.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index 21ee627b2ced..a59be11acd4f 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/serial/samsung_uart.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Samsung S3C, S5P and Exynos SoC UART Controller +title: Samsung S3C, S5P, Exynos, and S5L (Apple SoC) SoC UART Controller maintainers: - Krzysztof Kozlowski @@ -19,6 +19,7 @@ properties: compatible: items: - enum: + - apple,s5l-uart - samsung,s3c2410-uart - samsung,s3c2412-uart - samsung,s3c2440-uart @@ -96,6 +97,7 @@ allOf: compatible: contains: enum: + - apple,s5l-uart - samsung,exynos4210-uart then: properties: -- cgit From fcbba344907afe26da487f1ed0b0e285c06a547b Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 5 Mar 2021 06:38:59 +0900 Subject: tty: serial: samsung_tty: Add support for Apple UARTs Apple SoCs are a distant descendant of Samsung designs and use yet another variant of their UART style, with different interrupt handling. In particular, this variant has the following differences with existing ones: * It includes a built-in interrupt controller with different registers, using only a single platform IRQ * Internal interrupt sources are treated as edge-triggered, even though the IRQ output is level-triggered. This chiefly affects the TX IRQ path: the driver can no longer rely on the TX buffer empty IRQ immediately firing after TX is enabled, but instead must prime the FIFO with data directly. Signed-off-by: Hector Martin Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210304213902.83903-25-marcan@marcan.st Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- drivers/tty/serial/samsung_tty.c | 238 +++++++++++++++++++++++++++++++++++++-- include/linux/serial_s3c.h | 16 +++ 3 files changed, 247 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index fb9731d05f9e..e6f55c28cc2e 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -236,7 +236,7 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" - depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST + depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_APPLE || COMPILE_TEST select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 26cb05992e9f..5ef37c4538ce 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -59,6 +59,7 @@ enum s3c24xx_port_type { TYPE_S3C24XX, TYPE_S3C6400, + TYPE_APPLE_S5L, }; struct s3c24xx_uart_info { @@ -151,6 +152,8 @@ struct s3c24xx_uart_port { #endif }; +static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport); + /* conversion functions */ #define s3c24xx_dev_to_port(__dev) dev_get_drvdata(__dev) @@ -290,6 +293,9 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); break; + case TYPE_APPLE_S5L: + s3c24xx_clear_bit(port, APPLE_S5L_UCON_TXTHRESH_ENA, S3C2410_UCON); + break; default: disable_irq_nosync(ourport->tx_irq); break; @@ -358,6 +364,9 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport) case TYPE_S3C6400: s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); break; + case TYPE_APPLE_S5L: + WARN_ON(1); // No DMA + break; default: disable_irq_nosync(ourport->tx_irq); break; @@ -396,12 +405,23 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport) s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); break; + case TYPE_APPLE_S5L: + ucon |= APPLE_S5L_UCON_TXTHRESH_ENA_MSK; + wr_regl(port, S3C2410_UCON, ucon); + break; default: enable_irq(ourport->tx_irq); break; } ourport->tx_mode = S3C24XX_TX_PIO; + + /* + * The Apple version only has edge triggered TX IRQs, so we need + * to kick off the process by sending some characters here. + */ + if (ourport->info->type == TYPE_APPLE_S5L) + s3c24xx_serial_tx_chars(ourport); } static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport) @@ -527,6 +547,10 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port) s3c24xx_set_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM); break; + case TYPE_APPLE_S5L: + s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON); + s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON); + break; default: disable_irq_nosync(ourport->rx_irq); break; @@ -664,14 +688,18 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport) /* set Rx mode to DMA mode */ ucon = rd_regl(port, S3C2410_UCON); - ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK | - S3C64XX_UCON_EMPTYINT_EN | - S3C64XX_UCON_DMASUS_EN | - S3C64XX_UCON_TIMEOUT_EN | - S3C64XX_UCON_RXMODE_MASK); - ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT | - S3C64XX_UCON_TIMEOUT_EN | - S3C64XX_UCON_RXMODE_CPU; + ucon &= ~S3C64XX_UCON_RXMODE_MASK; + ucon |= S3C64XX_UCON_RXMODE_CPU; + + /* Apple types use these bits for IRQ masks */ + if (ourport->info->type != TYPE_APPLE_S5L) { + ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK | + S3C64XX_UCON_EMPTYINT_EN | + S3C64XX_UCON_DMASUS_EN | + S3C64XX_UCON_TIMEOUT_EN); + ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT | + S3C64XX_UCON_TIMEOUT_EN; + } wr_regl(port, S3C2410_UCON, ucon); ourport->rx_mode = S3C24XX_RX_PIO; @@ -935,6 +963,27 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) return ret; } +/* interrupt handler for Apple SoC's.*/ +static irqreturn_t apple_serial_handle_irq(int irq, void *id) +{ + struct s3c24xx_uart_port *ourport = id; + struct uart_port *port = &ourport->port; + unsigned int pend = rd_regl(port, S3C2410_UTRSTAT); + irqreturn_t ret = IRQ_NONE; + + if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) { + wr_regl(port, S3C2410_UTRSTAT, + APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO); + ret = s3c24xx_serial_rx_irq(irq, id); + } + if (pend & APPLE_S5L_UTRSTAT_TXTHRESH) { + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_TXTHRESH); + ret = s3c24xx_serial_tx_irq(irq, id); + } + + return ret; +} + static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); @@ -1154,6 +1203,32 @@ static void s3c64xx_serial_shutdown(struct uart_port *port) ourport->tx_in_progress = 0; } +static void apple_s5l_serial_shutdown(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + + unsigned int ucon; + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK); + wr_regl(port, S3C2410_UCON, ucon); + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); + + free_irq(port->irq, ourport); + + ourport->tx_enabled = 0; + ourport->tx_mode = 0; + ourport->rx_enabled = 0; + + if (ourport->dma) + s3c24xx_serial_release_dma(ourport); + + ourport->tx_in_progress = 0; +} + static int s3c24xx_serial_startup(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); @@ -1241,6 +1316,45 @@ static int s3c64xx_serial_startup(struct uart_port *port) return ret; } +static int apple_s5l_serial_startup(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + unsigned long flags; + unsigned int ufcon; + int ret; + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); + + ret = request_irq(port->irq, apple_serial_handle_irq, 0, + s3c24xx_serial_portname(port), ourport); + if (ret) { + dev_err(port->dev, "cannot get irq %d\n", port->irq); + return ret; + } + + /* For compatibility with s3c24xx Soc's */ + ourport->rx_enabled = 1; + ourport->tx_enabled = 0; + + spin_lock_irqsave(&port->lock, flags); + + ufcon = rd_regl(port, S3C2410_UFCON); + ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8; + if (!uart_console(port)) + ufcon |= S3C2410_UFCON_RESETTX; + wr_regl(port, S3C2410_UFCON, ufcon); + + enable_rx_pio(ourport); + + spin_unlock_irqrestore(&port->lock, flags); + + /* Enable Rx Interrupt */ + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON); + s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON); + + return ret; +} + /* power power management control */ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, @@ -1568,6 +1682,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port) return "S3C24XX"; case TYPE_S3C6400: return "S3C6400/10"; + case TYPE_APPLE_S5L: + return "APPLE S5L"; default: return NULL; } @@ -1659,6 +1775,27 @@ static const struct uart_ops s3c64xx_serial_ops = { #endif }; +static const struct uart_ops apple_s5l_serial_ops = { + .pm = s3c24xx_serial_pm, + .tx_empty = s3c24xx_serial_tx_empty, + .get_mctrl = s3c24xx_serial_get_mctrl, + .set_mctrl = s3c24xx_serial_set_mctrl, + .stop_tx = s3c24xx_serial_stop_tx, + .start_tx = s3c24xx_serial_start_tx, + .stop_rx = s3c24xx_serial_stop_rx, + .break_ctl = s3c24xx_serial_break_ctl, + .startup = apple_s5l_serial_startup, + .shutdown = apple_s5l_serial_shutdown, + .set_termios = s3c24xx_serial_set_termios, + .type = s3c24xx_serial_type, + .config_port = s3c24xx_serial_config_port, + .verify_port = s3c24xx_serial_verify_port, +#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL) + .poll_get_char = s3c24xx_serial_get_poll_char, + .poll_put_char = s3c24xx_serial_put_poll_char, +#endif +}; + static struct uart_driver s3c24xx_uart_drv = { .owner = THIS_MODULE, .driver_name = "s3c2410_serial", @@ -1975,6 +2112,18 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, wr_regl(port, S3C64XX_UINTP, 0xf); wr_regl(port, S3C64XX_UINTSP, 0xf); break; + case TYPE_APPLE_S5L: { + unsigned int ucon; + + ucon = rd_regl(port, S3C2410_UCON); + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK); + wr_regl(port, S3C2410_UCON, ucon); + + wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS); + break; + } default: break; } @@ -2054,6 +2203,9 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) case TYPE_S3C6400: ourport->port.ops = &s3c64xx_serial_ops; break; + case TYPE_APPLE_S5L: + ourport->port.ops = &apple_s5l_serial_ops; + break; } if (np) { @@ -2196,6 +2348,43 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) clk_disable_unprepare(ourport->clk); break; } + case TYPE_APPLE_S5L: { + unsigned int ucon; + int ret; + + ret = clk_prepare_enable(ourport->clk); + if (ret) { + dev_err(dev, "clk_enable clk failed: %d\n", ret); + return ret; + } + if (!IS_ERR(ourport->baudclk)) { + ret = clk_prepare_enable(ourport->baudclk); + if (ret) { + dev_err(dev, "clk_enable baudclk failed: %d\n", ret); + clk_disable_unprepare(ourport->clk); + return ret; + } + } + + ucon = rd_regl(port, S3C2410_UCON); + + ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK); + + if (ourport->tx_enabled) + ucon |= APPLE_S5L_UCON_TXTHRESH_ENA_MSK; + if (ourport->rx_enabled) + ucon |= APPLE_S5L_UCON_RXTHRESH_ENA_MSK | + APPLE_S5L_UCON_RXTO_ENA_MSK; + + wr_regl(port, S3C2410_UCON, ucon); + + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); + clk_disable_unprepare(ourport->clk); + break; + } default: break; } @@ -2605,6 +2794,34 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { #define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL #endif +#ifdef CONFIG_ARCH_APPLE +static struct s3c24xx_serial_drv_data s5l_serial_drv_data = { + .info = &(struct s3c24xx_uart_info) { + .name = "Apple S5L UART", + .type = TYPE_APPLE_S5L, + .port_type = PORT_8250, + .fifosize = 16, + .rx_fifomask = S3C2410_UFSTAT_RXMASK, + .rx_fifoshift = S3C2410_UFSTAT_RXSHIFT, + .rx_fifofull = S3C2410_UFSTAT_RXFULL, + .tx_fifofull = S3C2410_UFSTAT_TXFULL, + .tx_fifomask = S3C2410_UFSTAT_TXMASK, + .tx_fifoshift = S3C2410_UFSTAT_TXSHIFT, + .def_clk_sel = S3C2410_UCON_CLKSEL0, + .num_clks = 1, + .clksel_mask = 0, + .clksel_shift = 0, + }, + .def_cfg = &(struct s3c2410_uartcfg) { + .ucon = APPLE_S5L_UCON_DEFAULT, + .ufcon = S3C2410_UFCON_DEFAULT, + }, +}; +#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)&s5l_serial_drv_data) +#else +#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)NULL) +#endif + static const struct platform_device_id s3c24xx_serial_driver_ids[] = { { .name = "s3c2410-uart", @@ -2627,6 +2844,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = { }, { .name = "exynos5433-uart", .driver_data = EXYNOS5433_SERIAL_DRV_DATA, + }, { + .name = "s5l-uart", + .driver_data = S5L_SERIAL_DRV_DATA, }, { }, }; @@ -2648,6 +2868,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = { .data = (void *)EXYNOS4210_SERIAL_DRV_DATA }, { .compatible = "samsung,exynos5433-uart", .data = (void *)EXYNOS5433_SERIAL_DRV_DATA }, + { .compatible = "apple,s5l-uart", + .data = (void *)S5L_SERIAL_DRV_DATA }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h index ca2c5393dc6b..f6c3323fc4c5 100644 --- a/include/linux/serial_s3c.h +++ b/include/linux/serial_s3c.h @@ -246,6 +246,22 @@ S5PV210_UFCON_TXTRIG4 | \ S5PV210_UFCON_RXTRIG4) +#define APPLE_S5L_UCON_RXTO_ENA 9 +#define APPLE_S5L_UCON_RXTHRESH_ENA 12 +#define APPLE_S5L_UCON_TXTHRESH_ENA 13 +#define APPLE_S5L_UCON_RXTO_ENA_MSK (1 << APPLE_S5L_UCON_RXTO_ENA) +#define APPLE_S5L_UCON_RXTHRESH_ENA_MSK (1 << APPLE_S5L_UCON_RXTHRESH_ENA) +#define APPLE_S5L_UCON_TXTHRESH_ENA_MSK (1 << APPLE_S5L_UCON_TXTHRESH_ENA) + +#define APPLE_S5L_UCON_DEFAULT (S3C2410_UCON_TXIRQMODE | \ + S3C2410_UCON_RXIRQMODE | \ + S3C2410_UCON_RXFIFO_TOI) + +#define APPLE_S5L_UTRSTAT_RXTHRESH (1<<4) +#define APPLE_S5L_UTRSTAT_TXTHRESH (1<<5) +#define APPLE_S5L_UTRSTAT_RXTO (1<<9) +#define APPLE_S5L_UTRSTAT_ALL_FLAGS (0x3f0) + #ifndef __ASSEMBLY__ #include -- cgit From b89cfc05a275404bcfec83e2bdf8aea9a6c6e4bb Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 5 Mar 2021 06:39:00 +0900 Subject: tty: serial: samsung_tty: Add earlycon support for Apple UARTs Earlycon support is identical to S3C2410, but Apple SoCs also need MMIO mapped as nGnRnE. This is handled generically for normal drivers including the normal UART path here, but earlycon uses fixmap and runs before that scaffolding is ready. Since this is the only case where we need this fix, it makes more sense to do it here in the UART driver instead of introducing a whole fdt nonposted-mmio resolver just for earlycon/fixmap. Suggested-by: Arnd Bergmann Signed-off-by: Hector Martin Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210304213902.83903-26-marcan@marcan.st Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung_tty.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 5ef37c4538ce..80df842bf4c7 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -3001,6 +3001,23 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart", s5pv210_early_console_setup); OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart", s5pv210_early_console_setup); + +/* Apple S5L */ +static int __init apple_s5l_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + /* Close enough to S3C2410 for earlycon... */ + device->port.private_data = &s3c2410_early_console_data; + +#ifdef CONFIG_ARM64 + /* ... but we need to override the existing fixmap entry as nGnRnE */ + __set_fixmap(FIX_EARLYCON_MEM_BASE, device->port.mapbase, + __pgprot(PROT_DEVICE_nGnRnE)); +#endif + return samsung_early_console_setup(device, opt); +} + +OF_EARLYCON_DECLARE(s5l, "apple,s5l-uart", apple_s5l_early_console_setup); #endif MODULE_ALIAS("platform:samsung-uart"); -- cgit From 81171e7d31a63e0e7f5c83701f097695e60a12db Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Thu, 4 Mar 2021 11:13:11 +0300 Subject: serial: 8250_exar: Constify the software nodes Software node is always created for additional device properties. If the properties are constant, the software node can also be constant. Reviewed-by: Andy Shevchenko Signed-off-by: Heikki Krogerus Link: https://lore.kernel.org/r/20210304081311.17340-1-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 2d0e7c7e408d..2f49c580139b 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -354,7 +354,7 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p) static void * __xr17v35x_register_gpio(struct pci_dev *pcidev, - const struct property_entry *properties) + const struct software_node *node) { struct platform_device *pdev; @@ -365,7 +365,7 @@ __xr17v35x_register_gpio(struct pci_dev *pcidev, pdev->dev.parent = &pcidev->dev; ACPI_COMPANION_SET(&pdev->dev, ACPI_COMPANION(&pcidev->dev)); - if (platform_device_add_properties(pdev, properties) < 0 || + if (device_add_software_node(&pdev->dev, node) < 0 || platform_device_add(pdev) < 0) { platform_device_put(pdev); return NULL; @@ -380,12 +380,16 @@ static const struct property_entry exar_gpio_properties[] = { { } }; +static const struct software_node exar_gpio_node = { + .properties = exar_gpio_properties, +}; + static int xr17v35x_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port) { if (pcidev->vendor == PCI_VENDOR_ID_EXAR) port->port.private_data = - __xr17v35x_register_gpio(pcidev, exar_gpio_properties); + __xr17v35x_register_gpio(pcidev, &exar_gpio_node); return 0; } @@ -457,6 +461,10 @@ static const struct property_entry iot2040_gpio_properties[] = { { } }; +static const struct software_node iot2040_gpio_node = { + .properties = iot2040_gpio_properties, +}; + static int iot2040_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port) { @@ -468,7 +476,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev, writeb(IOT2040_UARTS_GPIO_HI_MODE, p + UART_EXAR_MPIOSEL_15_8); port->port.private_data = - __xr17v35x_register_gpio(pcidev, iot2040_gpio_properties); + __xr17v35x_register_gpio(pcidev, &iot2040_gpio_node); return 0; } @@ -547,6 +555,7 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) struct uart_8250_port *port = serial8250_get_port(priv->line[0]); struct platform_device *pdev = port->port.private_data; + device_remove_software_node(&pdev->dev); platform_device_unregister(pdev); port->port.private_data = NULL; } -- cgit From cebeddd6d0d9f839b9df2930b6a768b54913a763 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 5 Mar 2021 03:49:29 +0000 Subject: serial: liteuart: fix return value check in liteuart_probe() In case of error, the function devm_platform_get_and_ioremap_resource() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Fixes: 1da81e5562fa ("drivers/tty/serial: add LiteUART driver") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20210305034929.3234352-1-weiyongjun1@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/liteuart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c index 64842f3539e1..0b06770642cb 100644 --- a/drivers/tty/serial/liteuart.c +++ b/drivers/tty/serial/liteuart.c @@ -270,8 +270,8 @@ static int liteuart_probe(struct platform_device *pdev) /* get membase */ port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); - if (!port->membase) - return -ENXIO; + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); /* values not from device tree */ port->dev = &pdev->dev; -- cgit From 71b25f4df9849799d84d9345c636aac097316052 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 12 Feb 2021 17:39:04 +0100 Subject: dt-bindings: serial: samsung: add DMA properties The Samsung SoC UART nodes have usually DMA so dtschema has to reflect this to fix dtbs_check warnings like: arch/arm/boot/dts/exynos4210-smdkv310.dt.yaml: serial@13800000: 'dma-names', 'dmas' do not match any of the regexes: 'pinctrl-[0-9]+' Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210212163905.70171-1-krzk@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/samsung_uart.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index a59be11acd4f..4f98a3896b3a 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -52,6 +52,16 @@ properties: - pattern: '^clk_uart_baud[0-3]$' - pattern: '^clk_uart_baud[0-3]$' + dmas: + items: + - description: DMA controller phandle and request line for RX + - description: DMA controller phandle and request line for TX + + dma-names: + items: + - const: rx + - const: tx + interrupts: description: RX interrupt and optionally TX interrupt. minItems: 1 -- cgit From b0b8b689d78c9666a991e1cc87c3dad4c261007f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 15 Mar 2021 11:56:24 +0000 Subject: genirq: Allow architectures to override set_handle_irq() fallback Some architectures want to provide the generic set_handle_irq() API, but for structural reasons need to provide their own implementation. For example, arm64 needs to do this to provide uniform set_handle_irq() and set_handle_fiq() registration functions. Make this possible by allowing architectures to provide their own implementation of set_handle_irq when CONFIG_GENERIC_IRQ_MULTI_HANDLER is not selected. Signed-off-by: Marc Zyngier [Mark: expand commit message] Signed-off-by: Mark Rutland Tested-by: Hector Martin Cc: James Morse Cc: Thomas Gleixner Cc: Will Deacon Link: https://lore.kernel.org/r/20210315115629.57191-2-mark.rutland@arm.com Signed-off-by: Catalin Marinas --- include/linux/irq.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/irq.h b/include/linux/irq.h index 2efde6a79b7e..9890180b84fd 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -1258,11 +1258,13 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *)); */ extern void (*handle_arch_irq)(struct pt_regs *) __ro_after_init; #else +#ifndef set_handle_irq #define set_handle_irq(handle_irq) \ do { \ (void)handle_irq; \ WARN_ON(1); \ } while (0) #endif +#endif #endif /* _LINUX_IRQ_H */ -- cgit From 338a743640e98d26baf4a1450473ddcfe0a0c025 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 15 Mar 2021 11:56:25 +0000 Subject: arm64: don't use GENERIC_IRQ_MULTI_HANDLER In subsequent patches we want to allow irqchip drivers to register as FIQ handlers, with a set_handle_fiq() function. To keep the IRQ/FIQ paths similar, we want arm64 to provide both set_handle_irq() and set_handle_fiq(), rather than using GENERIC_IRQ_MULTI_HANDLER for the former. This patch adds an arm64-specific implementation of set_handle_irq(). There should be no functional change as a result of this patch. Signed-off-by: Marc Zyngier [Mark: use a single handler pointer] Signed-off-by: Mark Rutland Tested-by: Hector Martin Cc: James Morse Cc: Thomas Gleixner Cc: Will Deacon Link: https://lore.kernel.org/r/20210315115629.57191-3-mark.rutland@arm.com Signed-off-by: Catalin Marinas --- arch/arm64/Kconfig | 1 - arch/arm64/include/asm/irq.h | 3 +++ arch/arm64/kernel/irq.c | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 5656e7aacd69..e7d2405be71f 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -110,7 +110,6 @@ config ARM64 select GENERIC_EARLY_IOREMAP select GENERIC_IDLE_POLL_SETUP select GENERIC_IRQ_IPI - select GENERIC_IRQ_MULTI_HANDLER select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW_LEVEL diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index b2b0c6405eb0..8391c6f6f746 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -8,6 +8,9 @@ struct pt_regs; +int set_handle_irq(void (*handle_irq)(struct pt_regs *)); +#define set_handle_irq set_handle_irq + static inline int nr_legacy_irqs(void) { return 0; diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index dfb1feab867d..ad63bd50fa7b 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -71,6 +71,17 @@ static void init_irq_stacks(void) } #endif +void (*handle_arch_irq)(struct pt_regs *) __ro_after_init; + +int __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) +{ + if (handle_arch_irq) + return -EBUSY; + + handle_arch_irq = handle_irq; + return 0; +} + void __init init_IRQ(void) { init_irq_stacks(); -- cgit From 8ff443cebffab22544b77a1f9fb3651a49bde300 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 15 Mar 2021 11:56:26 +0000 Subject: arm64: irq: rework root IRQ handler registration If we accidentally unmask IRQs before we've registered a root IRQ handler, handle_arch_irq will be NULL, and the IRQ exception handler will branch to a bogus address. To make this easier to debug, this patch initialises handle_arch_irq to a default handler which will panic(), making such problems easier to debug. When we add support for FIQ handlers, we can follow the same approach. When we add support for a root FIQ handler, it's possible to have root IRQ handler without an root FIQ handler, and in theory the inverse is also possible. To permit this, and to keep the IRQ/FIQ registration logic similar, this patch removes the panic in the absence of a root IRQ controller. Instead, set_handle_irq() logs when a handler is registered, which is sufficient for debug purposes. Signed-off-by: Mark Rutland Tested-by: Hector Martin Cc: James Morse Cc: Marc Zyngier Cc: Thomas Gleixner Cc: Will Deacon Acked-by: Will Deacon Link: https://lore.kernel.org/r/20210315115629.57191-4-mark.rutland@arm.com Signed-off-by: Catalin Marinas --- arch/arm64/kernel/irq.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index ad63bd50fa7b..2fe0b535de30 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -71,14 +71,20 @@ static void init_irq_stacks(void) } #endif -void (*handle_arch_irq)(struct pt_regs *) __ro_after_init; +static void default_handle_irq(struct pt_regs *regs) +{ + panic("IRQ taken without a root IRQ handler\n"); +} + +void (*handle_arch_irq)(struct pt_regs *) __ro_after_init = default_handle_irq; int __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) { - if (handle_arch_irq) + if (handle_arch_irq != default_handle_irq) return -EBUSY; handle_arch_irq = handle_irq; + pr_info("Root IRQ handler: %ps\n", handle_irq); return 0; } @@ -87,8 +93,6 @@ void __init init_IRQ(void) init_irq_stacks(); init_irq_scs(); irqchip_init(); - if (!handle_arch_irq) - panic("No interrupt controller found."); if (system_uses_irq_prio_masking()) { /* -- cgit From 9eb563cdabe1d583c262042d5d44cc256f644543 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 15 Mar 2021 11:56:27 +0000 Subject: arm64: entry: factor irq triage logic into macros In subsequent patches we'll allow an FIQ handler to be registered, and FIQ exceptions will need to be triaged very similarly to IRQ exceptions. So that we can reuse the existing logic, this patch factors the IRQ triage logic out into macros that can be reused for FIQ. The macros are named to follow the elX_foo_handler scheme used by the C exception handlers. For consistency with other top-level exception handlers, the kernel_entry/kernel_exit logic is not moved into the macros. As FIQ will use a different C handler, this handler name is provided as an argument to the macros. There should be no functional change as a result of this patch. Signed-off-by: Marc Zyngier [Mark: rework macros, commit message, rebase before DAIF rework] Signed-off-by: Mark Rutland Tested-by: Hector Martin Cc: James Morse Cc: Thomas Gleixner Cc: Will Deacon Acked-by: Will Deacon Link: https://lore.kernel.org/r/20210315115629.57191-5-mark.rutland@arm.com Signed-off-by: Catalin Marinas --- arch/arm64/kernel/entry.S | 80 +++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index a31a0a713c85..e235b0e4e468 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -491,8 +491,8 @@ tsk .req x28 // current thread_info /* * Interrupt handling. */ - .macro irq_handler - ldr_l x1, handle_arch_irq + .macro irq_handler, handler:req + ldr_l x1, \handler mov x0, sp irq_stack_entry blr x1 @@ -531,6 +531,45 @@ alternative_endif #endif .endm + .macro el1_interrupt_handler, handler:req + gic_prio_irq_setup pmr=x20, tmp=x1 + enable_da_f + + mov x0, sp + bl enter_el1_irq_or_nmi + + irq_handler \handler + +#ifdef CONFIG_PREEMPTION + ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count +alternative_if ARM64_HAS_IRQ_PRIO_MASKING + /* + * DA_F were cleared at start of handling. If anything is set in DAIF, + * we come back from an NMI, so skip preemption + */ + mrs x0, daif + orr x24, x24, x0 +alternative_else_nop_endif + cbnz x24, 1f // preempt count != 0 || NMI return path + bl arm64_preempt_schedule_irq // irq en/disable is done inside +1: +#endif + + mov x0, sp + bl exit_el1_irq_or_nmi + .endm + + .macro el0_interrupt_handler, handler:req + gic_prio_irq_setup pmr=x20, tmp=x0 + user_exit_irqoff + enable_da_f + + tbz x22, #55, 1f + bl do_el0_irq_bp_hardening +1: + irq_handler \handler + .endm + .text /* @@ -660,32 +699,7 @@ SYM_CODE_END(el1_sync) .align 6 SYM_CODE_START_LOCAL_NOALIGN(el1_irq) kernel_entry 1 - gic_prio_irq_setup pmr=x20, tmp=x1 - enable_da_f - - mov x0, sp - bl enter_el1_irq_or_nmi - - irq_handler - -#ifdef CONFIG_PREEMPTION - ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count -alternative_if ARM64_HAS_IRQ_PRIO_MASKING - /* - * DA_F were cleared at start of handling. If anything is set in DAIF, - * we come back from an NMI, so skip preemption - */ - mrs x0, daif - orr x24, x24, x0 -alternative_else_nop_endif - cbnz x24, 1f // preempt count != 0 || NMI return path - bl arm64_preempt_schedule_irq // irq en/disable is done inside -1: -#endif - - mov x0, sp - bl exit_el1_irq_or_nmi - + el1_interrupt_handler handle_arch_irq kernel_exit 1 SYM_CODE_END(el1_irq) @@ -725,15 +739,7 @@ SYM_CODE_END(el0_error_compat) SYM_CODE_START_LOCAL_NOALIGN(el0_irq) kernel_entry 0 el0_irq_naked: - gic_prio_irq_setup pmr=x20, tmp=x0 - user_exit_irqoff - enable_da_f - - tbz x22, #55, 1f - bl do_el0_irq_bp_hardening -1: - irq_handler - + el0_interrupt_handler handle_arch_irq b ret_to_user SYM_CODE_END(el0_irq) -- cgit From f0098155d337cab638cf18e37a3e9257d653d481 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 15 Mar 2021 11:56:28 +0000 Subject: arm64: Always keep DAIF.[IF] in sync Apple SoCs (A11 and newer) have some interrupt sources hardwired to the FIQ line. We implement support for this by simply treating IRQs and FIQs the same way in the interrupt vectors. To support these systems, the FIQ mask bit needs to be kept in sync with the IRQ mask bit, so both kinds of exceptions are masked together. No other platforms should be delivering FIQ exceptions right now, and we already unmask FIQ in normal process context, so this should not have an effect on other systems - if spurious FIQs were arriving, they would already panic the kernel. Signed-off-by: Hector Martin Signed-off-by: Mark Rutland Tested-by: Hector Martin Cc: James Morse Cc: Marc Zyngier Cc: Thomas Gleixner Cc: Will Deacon Acked-by: Will Deacon Link: https://lore.kernel.org/r/20210315115629.57191-6-mark.rutland@arm.com Signed-off-by: Catalin Marinas --- arch/arm64/include/asm/arch_gicv3.h | 2 +- arch/arm64/include/asm/assembler.h | 8 ++++---- arch/arm64/include/asm/daifflags.h | 10 +++++----- arch/arm64/include/asm/irqflags.h | 16 +++++++--------- arch/arm64/kernel/entry.S | 12 +++++++----- arch/arm64/kernel/process.c | 2 +- arch/arm64/kernel/smp.c | 1 + 7 files changed, 26 insertions(+), 25 deletions(-) diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index 880b9054d75c..934b9be582d2 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -173,7 +173,7 @@ static inline void gic_pmr_mask_irqs(void) static inline void gic_arch_enable_irqs(void) { - asm volatile ("msr daifclr, #2" : : : "memory"); + asm volatile ("msr daifclr, #3" : : : "memory"); } #endif /* __ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index ca31594d3d6c..b76a71e84b7c 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -40,9 +40,9 @@ msr daif, \flags .endm - /* IRQ is the lowest priority flag, unconditionally unmask the rest. */ - .macro enable_da_f - msr daifclr, #(8 | 4 | 1) + /* IRQ/FIQ are the lowest priority flags, unconditionally unmask the rest. */ + .macro enable_da + msr daifclr, #(8 | 4) .endm /* @@ -50,7 +50,7 @@ */ .macro save_and_disable_irq, flags mrs \flags, daif - msr daifset, #2 + msr daifset, #3 .endm .macro restore_irq, flags diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h index 1c26d7baa67f..5eb7af9c4557 100644 --- a/arch/arm64/include/asm/daifflags.h +++ b/arch/arm64/include/asm/daifflags.h @@ -13,8 +13,8 @@ #include #define DAIF_PROCCTX 0 -#define DAIF_PROCCTX_NOIRQ PSR_I_BIT -#define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT) +#define DAIF_PROCCTX_NOIRQ (PSR_I_BIT | PSR_F_BIT) +#define DAIF_ERRCTX (PSR_A_BIT | PSR_I_BIT | PSR_F_BIT) #define DAIF_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT) @@ -47,7 +47,7 @@ static inline unsigned long local_daif_save_flags(void) if (system_uses_irq_prio_masking()) { /* If IRQs are masked with PMR, reflect it in the flags */ if (read_sysreg_s(SYS_ICC_PMR_EL1) != GIC_PRIO_IRQON) - flags |= PSR_I_BIT; + flags |= PSR_I_BIT | PSR_F_BIT; } return flags; @@ -69,7 +69,7 @@ static inline void local_daif_restore(unsigned long flags) bool irq_disabled = flags & PSR_I_BIT; WARN_ON(system_has_prio_mask_debugging() && - !(read_sysreg(daif) & PSR_I_BIT)); + (read_sysreg(daif) & (PSR_I_BIT | PSR_F_BIT)) != (PSR_I_BIT | PSR_F_BIT)); if (!irq_disabled) { trace_hardirqs_on(); @@ -86,7 +86,7 @@ static inline void local_daif_restore(unsigned long flags) * If interrupts are disabled but we can take * asynchronous errors, we can take NMIs */ - flags &= ~PSR_I_BIT; + flags &= ~(PSR_I_BIT | PSR_F_BIT); pmr = GIC_PRIO_IRQOFF; } else { pmr = GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET; diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h index ff328e5bbb75..b57b9b1e4344 100644 --- a/arch/arm64/include/asm/irqflags.h +++ b/arch/arm64/include/asm/irqflags.h @@ -12,15 +12,13 @@ /* * Aarch64 has flags for masking: Debug, Asynchronous (serror), Interrupts and - * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'dai' + * FIQ exceptions, in the 'daif' register. We mask and unmask them in 'daif' * order: * Masking debug exceptions causes all other exceptions to be masked too/ - * Masking SError masks irq, but not debug exceptions. Masking irqs has no - * side effects for other flags. Keeping to this order makes it easier for - * entry.S to know which exceptions should be unmasked. - * - * FIQ is never expected, but we mask it when we disable debug exceptions, and - * unmask it at all other times. + * Masking SError masks IRQ/FIQ, but not debug exceptions. IRQ and FIQ are + * always masked and unmasked together, and have no side effects for other + * flags. Keeping to this order makes it easier for entry.S to know which + * exceptions should be unmasked. */ /* @@ -35,7 +33,7 @@ static inline void arch_local_irq_enable(void) } asm volatile(ALTERNATIVE( - "msr daifclr, #2 // arch_local_irq_enable", + "msr daifclr, #3 // arch_local_irq_enable", __msr_s(SYS_ICC_PMR_EL1, "%0"), ARM64_HAS_IRQ_PRIO_MASKING) : @@ -54,7 +52,7 @@ static inline void arch_local_irq_disable(void) } asm volatile(ALTERNATIVE( - "msr daifset, #2 // arch_local_irq_disable", + "msr daifset, #3 // arch_local_irq_disable", __msr_s(SYS_ICC_PMR_EL1, "%0"), ARM64_HAS_IRQ_PRIO_MASKING) : diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index e235b0e4e468..ce8d4dc416fb 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -533,7 +533,7 @@ alternative_endif .macro el1_interrupt_handler, handler:req gic_prio_irq_setup pmr=x20, tmp=x1 - enable_da_f + enable_da mov x0, sp bl enter_el1_irq_or_nmi @@ -544,8 +544,10 @@ alternative_endif ldr x24, [tsk, #TSK_TI_PREEMPT] // get preempt count alternative_if ARM64_HAS_IRQ_PRIO_MASKING /* - * DA_F were cleared at start of handling. If anything is set in DAIF, - * we come back from an NMI, so skip preemption + * DA were cleared at start of handling, and IF are cleared by + * the GIC irqchip driver using gic_arch_enable_irqs() for + * normal IRQs. If anything is set, it means we come back from + * an NMI instead of a normal IRQ, so skip preemption */ mrs x0, daif orr x24, x24, x0 @@ -562,7 +564,7 @@ alternative_else_nop_endif .macro el0_interrupt_handler, handler:req gic_prio_irq_setup pmr=x20, tmp=x0 user_exit_irqoff - enable_da_f + enable_da tbz x22, #55, 1f bl do_el0_irq_bp_hardening @@ -763,7 +765,7 @@ el0_error_naked: mov x0, sp mov x1, x25 bl do_serror - enable_da_f + enable_da b ret_to_user SYM_CODE_END(el0_error) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 325c83b1a24d..a29028d3d46e 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -84,7 +84,7 @@ static void noinstr __cpu_do_idle_irqprio(void) unsigned long daif_bits; daif_bits = read_sysreg(daif); - write_sysreg(daif_bits | PSR_I_BIT, daif); + write_sysreg(daif_bits | PSR_I_BIT | PSR_F_BIT, daif); /* * Unmask PMR before going idle to make sure interrupts can diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 357590beaabb..dcd7041b2b07 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -188,6 +188,7 @@ static void init_gic_priority_masking(void) cpuflags = read_sysreg(daif); WARN_ON(!(cpuflags & PSR_I_BIT)); + WARN_ON(!(cpuflags & PSR_F_BIT)); gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); } -- cgit From 3889ba70102ed8c609e42c1d3563c8c041ce0511 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 15 Mar 2021 11:56:29 +0000 Subject: arm64: irq: allow FIQs to be handled On contemporary platforms we don't use FIQ, and treat any stray FIQ as a fatal event. However, some platforms have an interrupt controller wired to FIQ, and need to handle FIQ as part of regular operation. So that we can support both cases dynamically, this patch updates the FIQ exception handling code to operate the same way as the IRQ handling code, with its own handle_arch_fiq handler. Where a root FIQ handler is not registered, an unexpected FIQ exception will trigger the default FIQ handler, which will panic() as today. Where a root FIQ handler is registered, handling of the FIQ is deferred to that handler. As el0_fiq_invalid_compat is supplanted by el0_fiq, the former is removed. For !CONFIG_COMPAT builds we never expect to take an exception from AArch32 EL0, so we keep the common el0_fiq_invalid handler. Signed-off-by: Mark Rutland Tested-by: Hector Martin Cc: James Morse Cc: Marc Zyngier Cc: Thomas Gleixner Cc: Will Deacon Acked-by: Will Deacon Link: https://lore.kernel.org/r/20210315115629.57191-7-mark.rutland@arm.com Signed-off-by: Catalin Marinas --- arch/arm64/include/asm/irq.h | 1 + arch/arm64/kernel/entry.S | 30 +++++++++++++++++++++--------- arch/arm64/kernel/irq.c | 16 ++++++++++++++++ 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index 8391c6f6f746..fac08e18bcd5 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -10,6 +10,7 @@ struct pt_regs; int set_handle_irq(void (*handle_irq)(struct pt_regs *)); #define set_handle_irq set_handle_irq +int set_handle_fiq(void (*handle_fiq)(struct pt_regs *)); static inline int nr_legacy_irqs(void) { diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index ce8d4dc416fb..a86f50de2c7b 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -588,18 +588,18 @@ SYM_CODE_START(vectors) kernel_ventry 1, sync // Synchronous EL1h kernel_ventry 1, irq // IRQ EL1h - kernel_ventry 1, fiq_invalid // FIQ EL1h + kernel_ventry 1, fiq // FIQ EL1h kernel_ventry 1, error // Error EL1h kernel_ventry 0, sync // Synchronous 64-bit EL0 kernel_ventry 0, irq // IRQ 64-bit EL0 - kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0 + kernel_ventry 0, fiq // FIQ 64-bit EL0 kernel_ventry 0, error // Error 64-bit EL0 #ifdef CONFIG_COMPAT kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0 kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0 - kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0 + kernel_ventry 0, fiq_compat, 32 // FIQ 32-bit EL0 kernel_ventry 0, error_compat, 32 // Error 32-bit EL0 #else kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0 @@ -665,12 +665,6 @@ SYM_CODE_START_LOCAL(el0_error_invalid) inv_entry 0, BAD_ERROR SYM_CODE_END(el0_error_invalid) -#ifdef CONFIG_COMPAT -SYM_CODE_START_LOCAL(el0_fiq_invalid_compat) - inv_entry 0, BAD_FIQ, 32 -SYM_CODE_END(el0_fiq_invalid_compat) -#endif - SYM_CODE_START_LOCAL(el1_sync_invalid) inv_entry 1, BAD_SYNC SYM_CODE_END(el1_sync_invalid) @@ -705,6 +699,12 @@ SYM_CODE_START_LOCAL_NOALIGN(el1_irq) kernel_exit 1 SYM_CODE_END(el1_irq) +SYM_CODE_START_LOCAL_NOALIGN(el1_fiq) + kernel_entry 1 + el1_interrupt_handler handle_arch_fiq + kernel_exit 1 +SYM_CODE_END(el1_fiq) + /* * EL0 mode handlers. */ @@ -731,6 +731,11 @@ SYM_CODE_START_LOCAL_NOALIGN(el0_irq_compat) b el0_irq_naked SYM_CODE_END(el0_irq_compat) +SYM_CODE_START_LOCAL_NOALIGN(el0_fiq_compat) + kernel_entry 0, 32 + b el0_fiq_naked +SYM_CODE_END(el0_fiq_compat) + SYM_CODE_START_LOCAL_NOALIGN(el0_error_compat) kernel_entry 0, 32 b el0_error_naked @@ -745,6 +750,13 @@ el0_irq_naked: b ret_to_user SYM_CODE_END(el0_irq) +SYM_CODE_START_LOCAL_NOALIGN(el0_fiq) + kernel_entry 0 +el0_fiq_naked: + el0_interrupt_handler handle_arch_fiq + b ret_to_user +SYM_CODE_END(el0_fiq) + SYM_CODE_START_LOCAL(el1_error) kernel_entry 1 mrs x1, esr_el1 diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 2fe0b535de30..bda49430c9ea 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -76,7 +76,13 @@ static void default_handle_irq(struct pt_regs *regs) panic("IRQ taken without a root IRQ handler\n"); } +static void default_handle_fiq(struct pt_regs *regs) +{ + panic("FIQ taken without a root FIQ handler\n"); +} + void (*handle_arch_irq)(struct pt_regs *) __ro_after_init = default_handle_irq; +void (*handle_arch_fiq)(struct pt_regs *) __ro_after_init = default_handle_fiq; int __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) { @@ -88,6 +94,16 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) return 0; } +int __init set_handle_fiq(void (*handle_fiq)(struct pt_regs *)) +{ + if (handle_arch_fiq != default_handle_fiq) + return -EBUSY; + + handle_arch_fiq = handle_fiq; + pr_info("Root FIQ handler: %ps\n", handle_fiq); + return 0; +} + void __init init_IRQ(void) { init_irq_stacks(); -- cgit