// SPDX-License-Identifier: GPL-2.0+/* * mxser.c -- MOXA Smartio/Industio family multiport serial driver. * * Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com). * Copyright (C) 2006-2008 Jiri Slaby <jirislaby@gmail.com> * * This code is loosely based on the 1.8 moxa driver which is based on * Linux serial driver, written by Linus Torvalds, Theodore T'so and * others. * * Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox * <alan@lxorguk.ukuu.org.uk>. The original 1.8 code is available on * www.moxa.com. * - Fixed x86_64 cleanness */ #include <linux/module.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial.h>#include <linux/serial_reg.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/delay.h>#include <linux/pci.h>#include <linux/bitops.h>#include <linux/slab.h>#include <linux/ratelimit.h> #include <asm/io.h>#include <asm/irq.h>#include <linux/uaccess.h> /* * Semi-public control interfaces */ /* * MOXA ioctls */ #define MOXA 0x400#define MOXA_SET_OP_MODE (MOXA + 66)#define MOXA_GET_OP_MODE (MOXA + 67) #define RS232_MODE 0#define RS485_2WIRE_MODE 1#define RS422_MODE 2#define RS485_4WIRE_MODE 3#define OP_MODE_MASK 3 /* --------------------------------------------------- */ /* * Follow just what Moxa Must chip defines. * * When LCR register (offset 0x03) is written the following value, the Must chip * will enter enhanced mode. And a write to EFR (offset 0x02) bit 6,7 will * change bank. */#define MOXA_MUST_ENTER_ENHANCED 0xBF /* when enhanced mode is enabled, access to general bank register */#define MOXA_MUST_GDL_REGISTER 0x07#define MOXA_MUST_GDL_MASK 0x7F#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80 #define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO *//* enhanced register bank select and enhanced mode setting register *//* This works only when LCR register equals to 0xBF */#define MOXA_MUST_EFR_REGISTER 0x02#define MOXA_MUST_EFR_EFRB_ENABLE 0x10 /* enhanced mode enable *//* enhanced register bank set 0, 1, 2 */#define MOXA_MUST_EFR_BANK0 0x00#define MOXA_MUST_EFR_BANK1 0x40#define MOXA_MUST_EFR_BANK2 0x80#define MOXA_MUST_EFR_BANK3 0xC0#define MOXA_MUST_EFR_BANK_MASK 0xC0 /* set XON1 value register, when LCR=0xBF and change to bank0 */#define MOXA_MUST_XON1_REGISTER 0x04 /* set XON2 value register, when LCR=0xBF and change to bank0 */#define MOXA_MUST_XON2_REGISTER 0x05 /* set XOFF1 value register, when LCR=0xBF and change to bank0 */#define MOXA_MUST_XOFF1_REGISTER 0x06 /* set XOFF2 value register, when LCR=0xBF and change to bank0 */#define MOXA_MUST_XOFF2_REGISTER 0x07 #define MOXA_MUST_RBRTL_REGISTER 0x04#define MOXA_MUST_RBRTH_REGISTER 0x05#define MOXA_MUST_RBRTI_REGISTER 0x06#define MOXA_MUST_THRTL_REGISTER 0x07#define MOXA_MUST_ENUM_REGISTER 0x04#define MOXA_MUST_HWID_REGISTER 0x05#define MOXA_MUST_ECR_REGISTER 0x06#define MOXA_MUST_CSR_REGISTER 0x07 #define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20 /* good data mode enable */#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10 /* only good data put into RxFIFO */ #define MOXA_MUST_IER_ECTSI 0x80 /* enable CTS interrupt */#define MOXA_MUST_IER_ERTSI 0x40 /* enable RTS interrupt */#define MOXA_MUST_IER_XINT 0x20 /* enable Xon/Xoff interrupt */#define MOXA_MUST_IER_EGDAI 0x10 /* enable GDA interrupt */ #define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI) /* GDA interrupt pending */#define MOXA_MUST_IIR_GDA 0x1C#define MOXA_MUST_IIR_RDA 0x04#define MOXA_MUST_IIR_RTO 0x0C#define MOXA_MUST_IIR_LSR 0x06 /* received Xon/Xoff or specical interrupt pending */#define MOXA_MUST_IIR_XSC 0x10 /* RTS/CTS change state interrupt pending */#define MOXA_MUST_IIR_RTSCTS 0x20#define MOXA_MUST_IIR_MASK 0x3E #define MOXA_MUST_MCR_XON_FLAG 0x40#define MOXA_MUST_MCR_XON_ANY 0x80#define MOXA_MUST_MCR_TX_XON 0x08 #define MOXA_MUST_EFR_SF_MASK 0x0F /* software flow control on chip mask value */#define MOXA_MUST_EFR_SF_TX1 0x08 /* send Xon1/Xoff1 */#define MOXA_MUST_EFR_SF_TX2 0x04 /* send Xon2/Xoff2 */#define MOXA_MUST_EFR_SF_TX12 0x0C /* send Xon1,Xon2/Xoff1,Xoff2 */#define MOXA_MUST_EFR_SF_TX_NO 0x00 /* don't send Xon/Xoff */#define MOXA_MUST_EFR_SF_TX_MASK 0x0C /* Tx software flow control mask */#define MOXA_MUST_EFR_SF_RX_NO 0x00 /* don't receive Xon/Xoff */#define MOXA_MUST_EFR_SF_RX1 0x02 /* receive Xon1/Xoff1 */#define MOXA_MUST_EFR_SF_RX2 0x01 /* receive Xon2/Xoff2 */#define MOXA_MUST_EFR_SF_RX12 0x03 /* receive Xon1,Xon2/Xoff1,Xoff2 */#define MOXA_MUST_EFR_SF_RX_MASK 0x03 /* Rx software flow control mask */ #define MXSERMAJOR 174 #define MXSER_BOARDS 4 /* Max. boards */#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)#define MXSER_ISR_PASS_LIMIT 100 #define WAKEUP_CHARS 256 #define MXSER_BAUD_BASE 921600#define MXSER_CUSTOM_DIVISOR (MXSER_BAUD_BASE * 16) #define PCI_DEVICE_ID_MOXA_RC7000 0x0001#define PCI_DEVICE_ID_MOXA_CP102 0x1020#define PCI_DEVICE_ID_MOXA_CP102UL 0x1021#define PCI_DEVICE_ID_MOXA_CP102U 0x1022#define PCI_DEVICE_ID_MOXA_CP102UF 0x1023#define PCI_DEVICE_ID_MOXA_C104 0x1040#define PCI_DEVICE_ID_MOXA_CP104U 0x1041#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043#define PCI_DEVICE_ID_MOXA_POS104UL 0x1044#define PCI_DEVICE_ID_MOXA_CB108 0x1080#define PCI_DEVICE_ID_MOXA_CP112UL 0x1120#define PCI_DEVICE_ID_MOXA_CT114 0x1140#define PCI_DEVICE_ID_MOXA_CP114 0x1141#define PCI_DEVICE_ID_MOXA_CB114 0x1142#define PCI_DEVICE_ID_MOXA_CP114UL 0x1143#define PCI_DEVICE_ID_MOXA_CP118U 0x1180#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181#define PCI_DEVICE_ID_MOXA_CP132 0x1320#define PCI_DEVICE_ID_MOXA_CP132U 0x1321#define PCI_DEVICE_ID_MOXA_CP134U 0x1340#define PCI_DEVICE_ID_MOXA_CB134I 0x1341#define PCI_DEVICE_ID_MOXA_CP138U 0x1380#define PCI_DEVICE_ID_MOXA_C168 0x1680#define PCI_DEVICE_ID_MOXA_CP168U 0x1681#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682 #define MXSER_NPORTS(ddata) ((ddata) & 0xffU)#define MXSER_HIGHBAUD 0x0100 enum mxser_must_hwid { MOXA_OTHER_UART = 0x00, MOXA_MUST_MU150_HWID = 0x01, MOXA_MUST_MU860_HWID = 0x02,}; static const struct { u8 type; u8 fifo_size; u8 rx_high_water; u8 rx_low_water; speed_t max_baud;} Gpci_uart_info[] = { { MOXA_OTHER_UART, 16, 14, 1, 921600 }, { MOXA_MUST_MU150_HWID, 64, 48, 16, 230400 }, { MOXA_MUST_MU860_HWID, 128, 96, 32, 921600 }};#define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info) /* driver_data correspond to the lines in the structure above see also ISA probe function before you change something */static const struct pci_device_id mxser_pcibrds[] = { { PCI_DEVICE_DATA(MOXA, C168, 8) }, { PCI_DEVICE_DATA(MOXA, C104, 4) }, { PCI_DEVICE_DATA(MOXA, CP132, 2) }, { PCI_DEVICE_DATA(MOXA, CP114, 4) }, { PCI_DEVICE_DATA(MOXA, CT114, 4) }, { PCI_DEVICE_DATA(MOXA, CP102, 2 | MXSER_HIGHBAUD) }, { PCI_DEVICE_DATA(MOXA, CP104U, 4) }, { PCI_DEVICE_DATA(MOXA, CP168U, 8) }, { PCI_DEVICE_DATA(MOXA, CP132U, 2) }, { PCI_DEVICE_DATA(MOXA, CP134U, 4) }, { PCI_DEVICE_DATA(MOXA, CP104JU, 4) }, { PCI_DEVICE_DATA(MOXA, RC7000, 8) }, /* RC7000 */ { PCI_DEVICE_DATA(MOXA, CP118U, 8) }, { PCI_DEVICE_DATA(MOXA, CP102UL, 2) }, { PCI_DEVICE_DATA(MOXA, CP102U, 2) }, { PCI_DEVICE_DATA(MOXA, CP118EL, 8) }, { PCI_DEVICE_DATA(MOXA, CP168EL, 8) }, { PCI_DEVICE_DATA(MOXA, CP104EL, 4) }, { PCI_DEVICE_DATA(MOXA, CB108, 8) }, { PCI_DEVICE_DATA(MOXA, CB114, 4) }, { PCI_DEVICE_DATA(MOXA, CB134I, 4) }, { PCI_DEVICE_DATA(MOXA, CP138U, 8) }, { PCI_DEVICE_DATA(MOXA, POS104UL, 4) }, { PCI_DEVICE_DATA(MOXA, CP114UL, 4) }, { PCI_DEVICE_DATA(MOXA, CP102UF, 2) }, { PCI_DEVICE_DATA(MOXA, CP112UL, 2) }, { }};MODULE_DEVICE_TABLE(pci, mxser_pcibrds); static int ttymajor = MXSERMAJOR; /* Variables for insmod */ MODULE_AUTHOR("Casper Yang");MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");module_param(ttymajor, int, 0);MODULE_LICENSE("GPL"); struct mxser_board; struct mxser_port { struct tty_port port; struct mxser_board *board; unsigned long ioaddr; unsigned long opmode_ioaddr; u8 rx_high_water; u8 rx_low_water; int type; /* UART type */ unsigned char x_char; /* xon/xoff character */ u8 IER; /* Interrupt Enable Register */ u8 MCR; /* Modem control register */ u8 FCR; /* FIFO control register */ struct async_icount icount; /* kernel counters for 4 input interrupts */ unsigned int timeout; u8 read_status_mask; u8 ignore_status_mask; u8 xmit_fifo_size; spinlock_t slock;}; struct mxser_board { unsigned int idx; unsigned short nports; int irq; unsigned long vector; enum mxser_must_hwid must_hwid; speed_t max_baud; struct mxser_port ports[];}; static DECLARE_BITMAP(mxser_boards, MXSER_BOARDS);static struct tty_driver *mxvar_sdriver; static u8 __mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set, bool restore_LCR){ u8 oldlcr, efr; oldlcr = inb(baseio + UART_LCR); outb(MOXA_MUST_ENTER_ENHANCED, baseio + UART_LCR); efr = inb(baseio + MOXA_MUST_EFR_REGISTER); efr &= ~clear; efr |= set; outb(efr, baseio + MOXA_MUST_EFR_REGISTER); if (restore_LCR) outb(oldlcr, baseio + UART_LCR); return oldlcr;} static u8 mxser_must_select_bank(unsigned long baseio, u8 bank){ return __mxser_must_set_EFR(baseio, MOXA_MUST_EFR_BANK_MASK, bank, false);} static void mxser_set_must_xon1_value(unsigned long baseio, u8 value){ u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK0); outb(value, baseio + MOXA_MUST_XON1_REGISTER); outb(oldlcr, baseio + UART_LCR);} static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value){ u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK0); outb(value, baseio + MOXA_MUST_XOFF1_REGISTER); outb(oldlcr, baseio + UART_LCR);} static void mxser_set_must_fifo_value(struct mxser_port *info){ u8 oldlcr = mxser_must_select_bank(info->ioaddr, MOXA_MUST_EFR_BANK1); outb(info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER); outb(info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTI_REGISTER); outb(info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER); outb(oldlcr, info->ioaddr + UART_LCR);} static void mxser_set_must_enum_value(unsigned long baseio, u8 value){ u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2); outb(value, baseio + MOXA_MUST_ENUM_REGISTER); outb(oldlcr, baseio + UART_LCR);} static u8 mxser_get_must_hardware_id(unsigned long baseio){ u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2); u8 id = inb(baseio + MOXA_MUST_HWID_REGISTER); outb(oldlcr, baseio + UART_LCR); return id;} static void mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set){ __mxser_must_set_EFR(baseio, clear, set, true);} static void mxser_must_set_enhance_mode(unsigned long baseio, bool enable){ mxser_must_set_EFR(baseio, enable ? 0 : MOXA_MUST_EFR_EFRB_ENABLE, enable ? MOXA_MUST_EFR_EFRB_ENABLE : 0);} static void mxser_must_no_sw_flow_control(unsigned long baseio){ mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_MASK, 0);} static void mxser_must_set_tx_sw_flow_control(unsigned long baseio, bool enable){ mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_TX_MASK, enable ? MOXA_MUST_EFR_SF_TX1 : 0);} static void mxser_must_set_rx_sw_flow_control(unsigned long baseio, bool enable){ mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_RX_MASK, enable ? MOXA_MUST_EFR_SF_RX1 : 0);} static enum mxser_must_hwid mxser_must_get_hwid(unsigned long io){ u8 oldmcr, hwid; int i; outb(0, io + UART_LCR); mxser_must_set_enhance_mode(io, false); oldmcr = inb(io + UART_MCR); outb(0, io + UART_MCR); mxser_set_must_xon1_value(io, 0x11); if (inb(io + UART_MCR) != 0) { outb(oldmcr, io + UART_MCR); return MOXA_OTHER_UART; } hwid = mxser_get_must_hardware_id(io); for (i = 1; i < UART_INFO_NUM; i++) /* 0 = OTHER_UART */ if (hwid == Gpci_uart_info[i].type) return hwid; return MOXA_OTHER_UART;} static bool mxser_16550A_or_MUST(struct mxser_port *info){ return info->type == PORT_16550A || info->board->must_hwid;} static void mxser_process_txrx_fifo(struct mxser_port *info){ unsigned int i; if (info->type == PORT_16450 || info->type == PORT_8250) { info->rx_high_water = 1; info->rx_low_water = 1; info->xmit_fifo_size = 1; return; } for (i = 0; i < UART_INFO_NUM; i++) if (info->board->must_hwid == Gpci_uart_info[i].type) { info->rx_low_water = Gpci_uart_info[i].rx_low_water; info->rx_high_water = Gpci_uart_info[i].rx_high_water; info->xmit_fifo_size = Gpci_uart_info[i].fifo_size; break; }} static void __mxser_start_tx(struct mxser_port *info){ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->ioaddr + UART_IER);} static void mxser_start_tx(struct mxser_port *info){ unsigned long flags; spin_lock_irqsave(&info->slock, flags); __mxser_start_tx(info); spin_unlock_irqrestore(&info->slock, flags);} static void __mxser_stop_tx(struct mxser_port *info){ info->IER &= ~UART_IER_THRI; outb(info->IER, info->ioaddr + UART_IER);} static int mxser_carrier_raised(struct tty_port *port){ struct mxser_port *mp = container_of(port, struct mxser_port, port); return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;} static void mxser_dtr_rts(struct tty_port *port, int on){ struct mxser_port *mp = container_of(port, struct mxser_port, port); unsigned long flags; u8 mcr; spin_lock_irqsave(&mp->slock, flags); mcr = inb(mp->ioaddr + UART_MCR); if (on) mcr |= UART_MCR_DTR | UART_MCR_RTS; else mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); outb(mcr, mp->ioaddr + UART_MCR); spin_unlock_irqrestore(&mp->slock, flags);} static int mxser_set_baud(struct tty_struct *tty, speed_t newspd){ struct mxser_port *info = tty->driver_data; unsigned int quot = 0, baud; unsigned char cval; u64 timeout; if (newspd > info->board->max_baud) return -1; if (newspd == 134) { quot = 2 * MXSER_BAUD_BASE / 269; tty_encode_baud_rate(tty, 134, 134); } else if (newspd) { quot = MXSER_BAUD_BASE / newspd; if (quot == 0) quot = 1; baud = MXSER_BAUD_BASE / quot;Lines 1–500 of 1938. Load more
// SPDX-License-Identifier: GPL-2.0+ /* * mxser.c -- MOXA Smartio/Industio family multiport serial driver. * * Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com). * Copyright (C) 2006-2008 Jiri Slaby <jirislaby@gmail.com> * * This code is loosely based on the 1.8 moxa driver which is based on * Linux serial driver, written by Linus Torvalds, Theodore T'so and * others. * * Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox * <alan@lxorguk.ukuu.org.uk>. The original 1.8 code is available on * www.moxa.com. * - Fixed x86_64 cleanness */ #include <linux/module.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/serial_reg.h> #include <linux/major.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/ptrace.h> #include <linux/ioport.h> #include <linux/mm.h> #include <linux/delay.h> #include <linux/pci.h> #include <linux/bitops.h> #include <linux/slab.h> #include <linux/ratelimit.h> #include <asm/io.h> #include <asm/irq.h> #include <linux/uaccess.h> /* * Semi-public control interfaces */ /* * MOXA ioctls */ #define MOXA 0x400 #define MOXA_SET_OP_MODE (MOXA + 66) #define MOXA_GET_OP_MODE (MOXA + 67) #define RS232_MODE 0 #define RS485_2WIRE_MODE 1 #define RS422_MODE 2 #define RS485_4WIRE_MODE 3 #define OP_MODE_MASK 3 /* --------------------------------------------------- */ /* * Follow just what Moxa Must chip defines. * * When LCR register (offset 0x03) is written the following value, the Must chip * will enter enhanced mode. And a write to EFR (offset 0x02) bit 6,7 will * change bank. */ #define MOXA_MUST_ENTER_ENHANCED 0xBF /* when enhanced mode is enabled, access to general bank register */ #define MOXA_MUST_GDL_REGISTER 0x07 #define MOXA_MUST_GDL_MASK 0x7F #define MOXA_MUST_GDL_HAS_BAD_DATA 0x80 #define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO */ /* enhanced register bank select and enhanced mode setting register */ /* This works only when LCR register equals to 0xBF */ #define MOXA_MUST_EFR_REGISTER 0x02 #define MOXA_MUST_EFR_EFRB_ENABLE 0x10 /* enhanced mode enable */ /* enhanced register bank set 0, 1, 2 */ #define MOXA_MUST_EFR_BANK0 0x00 #define MOXA_MUST_EFR_BANK1 0x40 #define MOXA_MUST_EFR_BANK2 0x80 #define MOXA_MUST_EFR_BANK3 0xC0 #define MOXA_MUST_EFR_BANK_MASK 0xC0 /* set XON1 value register, when LCR=0xBF and change to bank0 */ #define MOXA_MUST_XON1_REGISTER 0x04 /* set XON2 value register, when LCR=0xBF and change to bank0 */ #define MOXA_MUST_XON2_REGISTER 0x05 /* set XOFF1 value register, when LCR=0xBF and change to bank0 */ #define MOXA_MUST_XOFF1_REGISTER 0x06 /* set XOFF2 value register, when LCR=0xBF and change to bank0 */ #define MOXA_MUST_XOFF2_REGISTER 0x07 #define MOXA_MUST_RBRTL_REGISTER 0x04 #define MOXA_MUST_RBRTH_REGISTER 0x05 #define MOXA_MUST_RBRTI_REGISTER 0x06 #define MOXA_MUST_THRTL_REGISTER 0x07 #define MOXA_MUST_ENUM_REGISTER 0x04 #define MOXA_MUST_HWID_REGISTER 0x05 #define MOXA_MUST_ECR_REGISTER 0x06 #define MOXA_MUST_CSR_REGISTER 0x07 #define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20 /* good data mode enable */ #define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10 /* only good data put into RxFIFO */ #define MOXA_MUST_IER_ECTSI 0x80 /* enable CTS interrupt */ #define MOXA_MUST_IER_ERTSI 0x40 /* enable RTS interrupt */ #define MOXA_MUST_IER_XINT 0x20 /* enable Xon/Xoff interrupt */ #define MOXA_MUST_IER_EGDAI 0x10 /* enable GDA interrupt */ #define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI) /* GDA interrupt pending */ #define MOXA_MUST_IIR_GDA 0x1C #define MOXA_MUST_IIR_RDA 0x04 #define MOXA_MUST_IIR_RTO 0x0C #define MOXA_MUST_IIR_LSR 0x06 /* received Xon/Xoff or specical interrupt pending */ #define MOXA_MUST_IIR_XSC 0x10 /* RTS/CTS change state interrupt pending */ #define MOXA_MUST_IIR_RTSCTS 0x20 #define MOXA_MUST_IIR_MASK 0x3E #define MOXA_MUST_MCR_XON_FLAG 0x40 #define MOXA_MUST_MCR_XON_ANY 0x80 #define MOXA_MUST_MCR_TX_XON 0x08 #define MOXA_MUST_EFR_SF_MASK 0x0F /* software flow control on chip mask value */ #define MOXA_MUST_EFR_SF_TX1 0x08 /* send Xon1/Xoff1 */ #define MOXA_MUST_EFR_SF_TX2 0x04 /* send Xon2/Xoff2 */ #define MOXA_MUST_EFR_SF_TX12 0x0C /* send Xon1,Xon2/Xoff1,Xoff2 */ #define MOXA_MUST_EFR_SF_TX_NO 0x00 /* don't send Xon/Xoff */ #define MOXA_MUST_EFR_SF_TX_MASK 0x0C /* Tx software flow control mask */ #define MOXA_MUST_EFR_SF_RX_NO 0x00 /* don't receive Xon/Xoff */ #define MOXA_MUST_EFR_SF_RX1 0x02 /* receive Xon1/Xoff1 */ #define MOXA_MUST_EFR_SF_RX2 0x01 /* receive Xon2/Xoff2 */ #define MOXA_MUST_EFR_SF_RX12 0x03 /* receive Xon1,Xon2/Xoff1,Xoff2 */ #define MOXA_MUST_EFR_SF_RX_MASK 0x03 /* Rx software flow control mask */ #define MXSERMAJOR 174 #define MXSER_BOARDS 4 /* Max. boards */ #define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */ #define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD) #define MXSER_ISR_PASS_LIMIT 100 #define WAKEUP_CHARS 256 #define MXSER_BAUD_BASE 921600 #define MXSER_CUSTOM_DIVISOR (MXSER_BAUD_BASE * 16) #define PCI_DEVICE_ID_MOXA_RC7000 0x0001 #define PCI_DEVICE_ID_MOXA_CP102 0x1020 #define PCI_DEVICE_ID_MOXA_CP102UL 0x1021 #define PCI_DEVICE_ID_MOXA_CP102U 0x1022 #define PCI_DEVICE_ID_MOXA_CP102UF 0x1023 #define PCI_DEVICE_ID_MOXA_C104 0x1040 #define PCI_DEVICE_ID_MOXA_CP104U 0x1041 #define PCI_DEVICE_ID_MOXA_CP104JU 0x1042 #define PCI_DEVICE_ID_MOXA_CP104EL 0x1043 #define PCI_DEVICE_ID_MOXA_POS104UL 0x1044 #define PCI_DEVICE_ID_MOXA_CB108 0x1080 #define PCI_DEVICE_ID_MOXA_CP112UL 0x1120 #define PCI_DEVICE_ID_MOXA_CT114 0x1140 #define PCI_DEVICE_ID_MOXA_CP114 0x1141 #define PCI_DEVICE_ID_MOXA_CB114 0x1142 #define PCI_DEVICE_ID_MOXA_CP114UL 0x1143 #define PCI_DEVICE_ID_MOXA_CP118U 0x1180 #define PCI_DEVICE_ID_MOXA_CP118EL 0x1181 #define PCI_DEVICE_ID_MOXA_CP132 0x1320 #define PCI_DEVICE_ID_MOXA_CP132U 0x1321 #define PCI_DEVICE_ID_MOXA_CP134U 0x1340 #define PCI_DEVICE_ID_MOXA_CB134I 0x1341 #define PCI_DEVICE_ID_MOXA_CP138U 0x1380 #define PCI_DEVICE_ID_MOXA_C168 0x1680 #define PCI_DEVICE_ID_MOXA_CP168U 0x1681 #define PCI_DEVICE_ID_MOXA_CP168EL 0x1682 #define MXSER_NPORTS(ddata) ((ddata) & 0xffU) #define MXSER_HIGHBAUD 0x0100 enum mxser_must_hwid { MOXA_OTHER_UART = 0x00, MOXA_MUST_MU150_HWID = 0x01, MOXA_MUST_MU860_HWID = 0x02, }; static const struct { u8 type; u8 fifo_size; u8 rx_high_water; u8 rx_low_water; speed_t max_baud; } Gpci_uart_info[] = { { MOXA_OTHER_UART, 16, 14, 1, 921600 }, { MOXA_MUST_MU150_HWID, 64, 48, 16, 230400 }, { MOXA_MUST_MU860_HWID, 128, 96, 32, 921600 } }; #define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info) /* driver_data correspond to the lines in the structure above see also ISA probe function before you change something */ static const struct pci_device_id mxser_pcibrds[] = { { PCI_DEVICE_DATA(MOXA, C168, 8) }, { PCI_DEVICE_DATA(MOXA, C104, 4) }, { PCI_DEVICE_DATA(MOXA, CP132, 2) }, { PCI_DEVICE_DATA(MOXA, CP114, 4) }, { PCI_DEVICE_DATA(MOXA, CT114, 4) }, { PCI_DEVICE_DATA(MOXA, CP102, 2 | MXSER_HIGHBAUD) }, { PCI_DEVICE_DATA(MOXA, CP104U, 4) }, { PCI_DEVICE_DATA(MOXA, CP168U, 8) }, { PCI_DEVICE_DATA(MOXA, CP132U, 2) }, { PCI_DEVICE_DATA(MOXA, CP134U, 4) }, { PCI_DEVICE_DATA(MOXA, CP104JU, 4) }, { PCI_DEVICE_DATA(MOXA, RC7000, 8) }, /* RC7000 */ { PCI_DEVICE_DATA(MOXA, CP118U, 8) }, { PCI_DEVICE_DATA(MOXA, CP102UL, 2) }, { PCI_DEVICE_DATA(MOXA, CP102U, 2) }, { PCI_DEVICE_DATA(MOXA, CP118EL, 8) }, { PCI_DEVICE_DATA(MOXA, CP168EL, 8) }, { PCI_DEVICE_DATA(MOXA, CP104EL, 4) }, { PCI_DEVICE_DATA(MOXA, CB108, 8) }, { PCI_DEVICE_DATA(MOXA, CB114, 4) }, { PCI_DEVICE_DATA(MOXA, CB134I, 4) }, { PCI_DEVICE_DATA(MOXA, CP138U, 8) }, { PCI_DEVICE_DATA(MOXA, POS104UL, 4) }, { PCI_DEVICE_DATA(MOXA, CP114UL, 4) }, { PCI_DEVICE_DATA(MOXA, CP102UF, 2) }, { PCI_DEVICE_DATA(MOXA, CP112UL, 2) }, { } }; MODULE_DEVICE_TABLE(pci, mxser_pcibrds); static int ttymajor = MXSERMAJOR; /* Variables for insmod */ MODULE_AUTHOR("Casper Yang"); MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver"); module_param(ttymajor, int, 0); MODULE_LICENSE("GPL"); struct mxser_board; struct mxser_port { struct tty_port port; struct mxser_board *board; unsigned long ioaddr; unsigned long opmode_ioaddr; u8 rx_high_water; u8 rx_low_water; int type; /* UART type */ unsigned char x_char; /* xon/xoff character */ u8 IER; /* Interrupt Enable Register */ u8 MCR; /* Modem control register */ u8 FCR; /* FIFO control register */ struct async_icount icount; /* kernel counters for 4 input interrupts */ unsigned int timeout; u8 read_status_mask; u8 ignore_status_mask; u8 xmit_fifo_size; spinlock_t slock; }; struct mxser_board { unsigned int idx; unsigned short nports; int irq; unsigned long vector; enum mxser_must_hwid must_hwid; speed_t max_baud; struct mxser_port ports[]; }; static DECLARE_BITMAP(mxser_boards, MXSER_BOARDS); static struct tty_driver *mxvar_sdriver; static u8 __mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set, bool restore_LCR) { u8 oldlcr, efr; oldlcr = inb(baseio + UART_LCR); outb(MOXA_MUST_ENTER_ENHANCED, baseio + UART_LCR); efr = inb(baseio + MOXA_MUST_EFR_REGISTER); efr &= ~clear; efr |= set; outb(efr, baseio + MOXA_MUST_EFR_REGISTER); if (restore_LCR) outb(oldlcr, baseio + UART_LCR); return oldlcr; } static u8 mxser_must_select_bank(unsigned long baseio, u8 bank) { return __mxser_must_set_EFR(baseio, MOXA_MUST_EFR_BANK_MASK, bank, false); } static void mxser_set_must_xon1_value(unsigned long baseio, u8 value) { u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK0); outb(value, baseio + MOXA_MUST_XON1_REGISTER); outb(oldlcr, baseio + UART_LCR); } static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value) { u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK0); outb(value, baseio + MOXA_MUST_XOFF1_REGISTER); outb(oldlcr, baseio + UART_LCR); } static void mxser_set_must_fifo_value(struct mxser_port *info) { u8 oldlcr = mxser_must_select_bank(info->ioaddr, MOXA_MUST_EFR_BANK1); outb(info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER); outb(info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTI_REGISTER); outb(info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER); outb(oldlcr, info->ioaddr + UART_LCR); } static void mxser_set_must_enum_value(unsigned long baseio, u8 value) { u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2); outb(value, baseio + MOXA_MUST_ENUM_REGISTER); outb(oldlcr, baseio + UART_LCR); } static u8 mxser_get_must_hardware_id(unsigned long baseio) { u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2); u8 id = inb(baseio + MOXA_MUST_HWID_REGISTER); outb(oldlcr, baseio + UART_LCR); return id; } static void mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set) { __mxser_must_set_EFR(baseio, clear, set, true); } static void mxser_must_set_enhance_mode(unsigned long baseio, bool enable) { mxser_must_set_EFR(baseio, enable ? 0 : MOXA_MUST_EFR_EFRB_ENABLE, enable ? MOXA_MUST_EFR_EFRB_ENABLE : 0); } static void mxser_must_no_sw_flow_control(unsigned long baseio) { mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_MASK, 0); } static void mxser_must_set_tx_sw_flow_control(unsigned long baseio, bool enable) { mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_TX_MASK, enable ? MOXA_MUST_EFR_SF_TX1 : 0); } static void mxser_must_set_rx_sw_flow_control(unsigned long baseio, bool enable) { mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_RX_MASK, enable ? MOXA_MUST_EFR_SF_RX1 : 0); } static enum mxser_must_hwid mxser_must_get_hwid(unsigned long io) { u8 oldmcr, hwid; int i; outb(0, io + UART_LCR); mxser_must_set_enhance_mode(io, false); oldmcr = inb(io + UART_MCR); outb(0, io + UART_MCR); mxser_set_must_xon1_value(io, 0x11); if (inb(io + UART_MCR) != 0) { outb(oldmcr, io + UART_MCR); return MOXA_OTHER_UART; } hwid = mxser_get_must_hardware_id(io); for (i = 1; i < UART_INFO_NUM; i++) /* 0 = OTHER_UART */ if (hwid == Gpci_uart_info[i].type) return hwid; return MOXA_OTHER_UART; } static bool mxser_16550A_or_MUST(struct mxser_port *info) { return info->type == PORT_16550A || info->board->must_hwid; } static void mxser_process_txrx_fifo(struct mxser_port *info) { unsigned int i; if (info->type == PORT_16450 || info->type == PORT_8250) { info->rx_high_water = 1; info->rx_low_water = 1; info->xmit_fifo_size = 1; return; } for (i = 0; i < UART_INFO_NUM; i++) if (info->board->must_hwid == Gpci_uart_info[i].type) { info->rx_low_water = Gpci_uart_info[i].rx_low_water; info->rx_high_water = Gpci_uart_info[i].rx_high_water; info->xmit_fifo_size = Gpci_uart_info[i].fifo_size; break; } } static void __mxser_start_tx(struct mxser_port *info) { outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->ioaddr + UART_IER); } static void mxser_start_tx(struct mxser_port *info) { unsigned long flags; spin_lock_irqsave(&info->slock, flags); __mxser_start_tx(info); spin_unlock_irqrestore(&info->slock, flags); } static void __mxser_stop_tx(struct mxser_port *info) { info->IER &= ~UART_IER_THRI; outb(info->IER, info->ioaddr + UART_IER); } static int mxser_carrier_raised(struct tty_port *port) { struct mxser_port *mp = container_of(port, struct mxser_port, port); return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0; } static void mxser_dtr_rts(struct tty_port *port, int on) { struct mxser_port *mp = container_of(port, struct mxser_port, port); unsigned long flags; u8 mcr; spin_lock_irqsave(&mp->slock, flags); mcr = inb(mp->ioaddr + UART_MCR); if (on) mcr |= UART_MCR_DTR | UART_MCR_RTS; else mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); outb(mcr, mp->ioaddr + UART_MCR); spin_unlock_irqrestore(&mp->slock, flags); } static int mxser_set_baud(struct tty_struct *tty, speed_t newspd) { struct mxser_port *info = tty->driver_data; unsigned int quot = 0, baud; unsigned char cval; u64 timeout; if (newspd > info->board->max_baud) return -1; if (newspd == 134) { quot = 2 * MXSER_BAUD_BASE / 269; tty_encode_baud_rate(tty, 134, 134); } else if (newspd) { quot = MXSER_BAUD_BASE / newspd; if (quot == 0) quot = 1; baud = MXSER_BAUD_BASE / quot;