diff options
Diffstat (limited to 'drivers/tty/mxser.c')
-rw-r--r-- | drivers/tty/mxser.c | 1958 |
1 files changed, 584 insertions, 1374 deletions
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 16a852ecbe8a..900ccb2ca166 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -41,9 +41,112 @@ #include <asm/irq.h> #include <linux/uaccess.h> -#include "mxser.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 MXSER_VERSION "2.0.5" /* 1.14 */ #define MXSERMAJOR 174 #define MXSER_BOARDS 4 /* Max. boards */ @@ -51,15 +154,10 @@ #define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD) #define MXSER_ISR_PASS_LIMIT 100 -/*CheckIsMoxaMust return value*/ -#define MOXA_OTHER_UART 0x00 -#define MOXA_MUST_MU150_HWID 0x01 -#define MOXA_MUST_MU860_HWID 0x02 - #define WAKEUP_CHARS 256 -#define UART_MCR_AFE 0x20 -#define UART_LSR_SPECIAL 0x1E +#define MXSER_BAUD_BASE 921600 +#define MXSER_CUSTOM_DIVISOR (MXSER_BAUD_BASE * 16) #define PCI_DEVICE_ID_POS104UL 0x1044 #define PCI_DEVICE_ID_CB108 0x1080 @@ -70,151 +168,71 @@ #define PCI_DEVICE_ID_CB134I 0x1341 #define PCI_DEVICE_ID_CP138U 0x1380 +#define MXSER_NPORTS(ddata) ((ddata) & 0xffU) +#define MXSER_HIGHBAUD 0x0100 -#define C168_ASIC_ID 1 -#define C104_ASIC_ID 2 -#define C102_ASIC_ID 0xB -#define CI132_ASIC_ID 4 -#define CI134_ASIC_ID 3 -#define CI104J_ASIC_ID 5 - -#define MXSER_HIGHBAUD 1 -#define MXSER_HAS2 2 +enum mxser_must_hwid { + MOXA_OTHER_UART = 0x00, + MOXA_MUST_MU150_HWID = 0x01, + MOXA_MUST_MU860_HWID = 0x02, +}; -/* This is only for PCI */ static const struct { - int type; - int tx_fifo; - int rx_fifo; - int xmit_fifo_size; - int rx_high_water; - int rx_trigger; - int rx_low_water; - long max_baud; + u8 type; + u8 fifo_size; + u8 rx_high_water; + u8 rx_low_water; + speed_t max_baud; } Gpci_uart_info[] = { - {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L}, - {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L}, - {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L} + { 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) -struct mxser_cardinfo { - char *name; - unsigned int nports; - unsigned int flags; -}; - -static const struct mxser_cardinfo mxser_cards[] = { -/* 0*/ { "C168 series", 8, }, - { "C104 series", 4, }, - { "CI-104J series", 4, }, - { "C168H/PCI series", 8, }, - { "C104H/PCI series", 4, }, -/* 5*/ { "C102 series", 4, MXSER_HAS2 }, /* C102-ISA */ - { "CI-132 series", 4, MXSER_HAS2 }, - { "CI-134 series", 4, }, - { "CP-132 series", 2, }, - { "CP-114 series", 4, }, -/*10*/ { "CT-114 series", 4, }, - { "CP-102 series", 2, MXSER_HIGHBAUD }, - { "CP-104U series", 4, }, - { "CP-168U series", 8, }, - { "CP-132U series", 2, }, -/*15*/ { "CP-134U series", 4, }, - { "CP-104JU series", 4, }, - { "Moxa UC7000 Serial", 8, }, /* RC7000 */ - { "CP-118U series", 8, }, - { "CP-102UL series", 2, }, -/*20*/ { "CP-102U series", 2, }, - { "CP-118EL series", 8, }, - { "CP-168EL series", 8, }, - { "CP-104EL series", 4, }, - { "CB-108 series", 8, }, -/*25*/ { "CB-114 series", 4, }, - { "CB-134I series", 4, }, - { "CP-138U series", 8, }, - { "POS-104UL series", 4, }, - { "CP-114UL series", 4, }, -/*30*/ { "CP-102UF series", 2, }, - { "CP-112UL series", 2, }, -}; /* 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_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 8 }, { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 9 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 10 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 11 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 24 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 25 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 26 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 27 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 29 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 30 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 31 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 2 | MXSER_HIGHBAUD }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 8 }, /* RC7000 */ + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 2 }, { } }; MODULE_DEVICE_TABLE(pci, mxser_pcibrds); -static unsigned long ioaddr[MXSER_BOARDS]; static int ttymajor = MXSERMAJOR; /* Variables for insmod */ MODULE_AUTHOR("Casper Yang"); MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver"); -module_param_hw_array(ioaddr, ulong, ioport, NULL, 0); -MODULE_PARM_DESC(ioaddr, "ISA io addresses to look for a moxa board"); module_param(ttymajor, int, 0); MODULE_LICENSE("GPL"); -struct mxser_log { - int tick; - unsigned long rxcnt[MXSER_PORTS]; - unsigned long txcnt[MXSER_PORTS]; -}; - -struct mxser_mon { - unsigned long rxcnt; - unsigned long txcnt; - unsigned long up_rxcnt; - unsigned long up_txcnt; - int modem_status; - unsigned char hold_reason; -}; - -struct mxser_mon_ext { - unsigned long rx_cnt[32]; - unsigned long tx_cnt[32]; - unsigned long up_rxcnt[32]; - unsigned long up_txcnt[32]; - int modem_status[32]; - - long baudrate[32]; - int databits[32]; - int stopbits[32]; - int parity[32]; - int flowctrl[32]; - int fifo[32]; - int iftype[32]; -}; - struct mxser_board; struct mxser_port { @@ -223,274 +241,147 @@ struct mxser_port { unsigned long ioaddr; unsigned long opmode_ioaddr; - int max_baud; - int rx_high_water; - int rx_trigger; /* Rx fifo trigger level */ - int rx_low_water; - int baud_base; /* max. speed */ + u8 rx_high_water; + u8 rx_low_water; int type; /* UART type */ - int x_char; /* xon/xoff character */ - int IER; /* Interrupt Enable Register */ - int MCR; /* Modem control register */ + unsigned char x_char; /* xon/xoff character */ + u8 IER; /* Interrupt Enable Register */ + u8 MCR; /* Modem control register */ - unsigned char stop_rx; unsigned char ldisc_stop_rx; - int custom_divisor; - unsigned char err_shadow; - struct async_icount icount; /* kernel counters for 4 input interrupts */ unsigned int timeout; - int read_status_mask; - int ignore_status_mask; - unsigned int xmit_fifo_size; - int xmit_head; - int xmit_tail; - int xmit_cnt; + u8 read_status_mask; + u8 ignore_status_mask; + u8 xmit_fifo_size; + unsigned int xmit_head; + unsigned int xmit_tail; + unsigned int xmit_cnt; int closing; - struct ktermios normal_termios; - - struct mxser_mon mon_data; - spinlock_t slock; }; struct mxser_board { unsigned int idx; + unsigned short nports; int irq; - const struct mxser_cardinfo *info; unsigned long vector; - unsigned long vector_mask; - - int chip_flag; - int uart_type; - struct mxser_port ports[MXSER_PORTS_PER_BOARD]; -}; + enum mxser_must_hwid must_hwid; + speed_t max_baud; -struct mxser_mstatus { - tcflag_t cflag; - int cts; - int dsr; - int ri; - int dcd; + struct mxser_port ports[]; }; -static struct mxser_board mxser_boards[MXSER_BOARDS]; +static DECLARE_BITMAP(mxser_boards, MXSER_BOARDS); static struct tty_driver *mxvar_sdriver; -static struct mxser_log mxvar_log; -static int mxser_set_baud_method[MXSER_PORTS + 1]; -static void mxser_enable_must_enchance_mode(unsigned long baseio) +static u8 __mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set, + bool restore_LCR) { - u8 oldlcr; - u8 efr; + u8 oldlcr, efr; oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENHANCED, baseio + UART_LCR); efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr |= MOXA_MUST_EFR_EFRB_ENABLE; + efr &= ~clear; + efr |= set; outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); -} -#ifdef CONFIG_PCI -static void mxser_disable_must_enchance_mode(unsigned long baseio) -{ - u8 oldlcr; - u8 efr; + if (restore_LCR) + outb(oldlcr, baseio + UART_LCR); - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; + return oldlcr; +} - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); +static u8 mxser_must_select_bank(unsigned long baseio, u8 bank) +{ + return __mxser_must_set_EFR(baseio, MOXA_MUST_EFR_BANK_MASK, bank, + false); } -#endif static void mxser_set_must_xon1_value(unsigned long baseio, u8 value) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK0; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + 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; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK0; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + 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; - u8 efr; - - oldlcr = inb(info->ioaddr + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, info->ioaddr + UART_LCR); - - efr = inb(info->ioaddr + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK1; - - outb(efr, info->ioaddr + MOXA_MUST_EFR_REGISTER); - outb((u8)info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER); - outb((u8)info->rx_trigger, info->ioaddr + MOXA_MUST_RBRTI_REGISTER); - outb((u8)info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER); + 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; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK2; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2); outb(value, baseio + MOXA_MUST_ENUM_REGISTER); outb(oldlcr, baseio + UART_LCR); } -#ifdef CONFIG_PCI -static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId) +static u8 mxser_get_must_hardware_id(unsigned long baseio) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK2; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - *pId = inb(baseio + MOXA_MUST_HWID_REGISTER); + 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; } -#endif -static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio) +static void mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_MASK; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + __mxser_must_set_EFR(baseio, clear, set, true); } -static void mxser_enable_must_tx_software_flow_control(unsigned long baseio) +static void mxser_must_set_enhance_mode(unsigned long baseio, bool enable) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_TX_MASK; - efr |= MOXA_MUST_EFR_SF_TX1; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + mxser_must_set_EFR(baseio, + enable ? 0 : MOXA_MUST_EFR_EFRB_ENABLE, + enable ? MOXA_MUST_EFR_EFRB_ENABLE : 0); } -static void mxser_disable_must_tx_software_flow_control(unsigned long baseio) +static void mxser_must_no_sw_flow_control(unsigned long baseio) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_TX_MASK; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_MASK, 0); } -static void mxser_enable_must_rx_software_flow_control(unsigned long baseio) +static void mxser_must_set_tx_sw_flow_control(unsigned long baseio, bool enable) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_RX_MASK; - efr |= MOXA_MUST_EFR_SF_RX1; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_TX_MASK, + enable ? MOXA_MUST_EFR_SF_TX1 : 0); } -static void mxser_disable_must_rx_software_flow_control(unsigned long baseio) +static void mxser_must_set_rx_sw_flow_control(unsigned long baseio, bool enable) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_RX_MASK; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_RX_MASK, + enable ? MOXA_MUST_EFR_SF_RX1 : 0); } -#ifdef CONFIG_PCI -static int CheckIsMoxaMust(unsigned long io) +static enum mxser_must_hwid mxser_must_get_hwid(unsigned long io) { u8 oldmcr, hwid; int i; outb(0, io + UART_LCR); - mxser_disable_must_enchance_mode(io); + mxser_must_set_enhance_mode(io, false); oldmcr = inb(io + UART_MCR); outb(0, io + UART_MCR); mxser_set_must_xon1_value(io, 0x11); @@ -499,49 +390,59 @@ static int CheckIsMoxaMust(unsigned long io) return MOXA_OTHER_UART; } - mxser_get_must_hardware_id(io, &hwid); - for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = 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 (int)hwid; - } + return hwid; + return MOXA_OTHER_UART; } -#endif -static void process_txrx_fifo(struct mxser_port *info) +static bool mxser_16550A_or_MUST(struct mxser_port *info) { - int i; + return info->type == PORT_16550A || info->board->must_hwid; +} - if ((info->type == PORT_16450) || (info->type == PORT_8250)) { - info->rx_trigger = 1; +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; - } else - for (i = 0; i < UART_INFO_NUM; i++) - if (info->board->chip_flag == Gpci_uart_info[i].type) { - info->rx_trigger = Gpci_uart_info[i].rx_trigger; - 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].xmit_fifo_size; - break; - } + 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 unsigned char mxser_get_msr(int baseaddr, int mode, int port) +static void __mxser_start_tx(struct mxser_port *info) { - static unsigned char mxser_msr[MXSER_PORTS + 1]; - unsigned char status = 0; + outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); + info->IER |= UART_IER_THRI; + outb(info->IER, info->ioaddr + UART_IER); +} - status = inb(baseaddr + UART_MSR); +static void mxser_start_tx(struct mxser_port *info) +{ + unsigned long flags; - mxser_msr[port] &= 0x0F; - mxser_msr[port] |= status; - status = mxser_msr[port]; - if (mode) - mxser_msr[port] = 0; + spin_lock_irqsave(&info->slock, flags); + __mxser_start_tx(info); + spin_unlock_irqrestore(&info->slock, flags); +} - return status; +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) @@ -554,38 +455,36 @@ 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) - outb(inb(mp->ioaddr + UART_MCR) | - UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR); + mcr |= UART_MCR_DTR | UART_MCR_RTS; else - outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS), - mp->ioaddr + UART_MCR); + 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, long newspd) +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 (!info->ioaddr) - return -1; - - if (newspd > info->max_baud) + if (newspd > info->board->max_baud) return -1; if (newspd == 134) { - quot = 2 * info->baud_base / 269; + quot = 2 * MXSER_BAUD_BASE / 269; tty_encode_baud_rate(tty, 134, 134); } else if (newspd) { - quot = info->baud_base / newspd; + quot = MXSER_BAUD_BASE / newspd; if (quot == 0) quot = 1; - baud = info->baud_base/quot; + baud = MXSER_BAUD_BASE / quot; tty_encode_baud_rate(tty, baud, baud); } else { quot = 0; @@ -596,7 +495,7 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) * u64 domain */ timeout = (u64)info->xmit_fifo_size * HZ * 10 * quot; - do_div(timeout, info->baud_base); + do_div(timeout, MXSER_BAUD_BASE); info->timeout = timeout + HZ / 50; /* Add .02 seconds of slop */ if (quot) { @@ -618,7 +517,7 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) #ifdef BOTHER if (C_BAUD(tty) == BOTHER) { - quot = info->baud_base % newspd; + quot = MXSER_BAUD_BASE % newspd; quot *= 8; if (quot % newspd > newspd / 2) { quot /= newspd; @@ -634,6 +533,28 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) return 0; } +static void mxser_handle_cts(struct tty_struct *tty, struct mxser_port *info, + u8 msr) +{ + bool cts = msr & UART_MSR_CTS; + + if (tty->hw_stopped) { + if (cts) { + tty->hw_stopped = 0; + + if (!mxser_16550A_or_MUST(info)) + __mxser_start_tx(info); + tty_wakeup(tty); + } + return; + } else if (cts) + return; + + tty->hw_stopped = 1; + if (!mxser_16550A_or_MUST(info)) + __mxser_stop_tx(info); +} + /* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. @@ -642,35 +563,30 @@ static void mxser_change_speed(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; unsigned cflag, cval, fcr; - unsigned char status; cflag = tty->termios.c_cflag; - if (!info->ioaddr) - return; - if (mxser_set_baud_method[tty->index] == 0) - mxser_set_baud(tty, tty_get_baud_rate(tty)); + mxser_set_baud(tty, tty_get_baud_rate(tty)); /* byte size and parity */ switch (cflag & CSIZE) { + default: case CS5: - cval = 0x00; + cval = UART_LCR_WLEN5; break; case CS6: - cval = 0x01; + cval = UART_LCR_WLEN6; break; case CS7: - cval = 0x02; + cval = UART_LCR_WLEN7; break; case CS8: - cval = 0x03; + cval = UART_LCR_WLEN8; break; - default: - cval = 0x00; - break; /* too keep GCC shut... */ } + if (cflag & CSTOPB) - cval |= 0x04; + cval |= UART_LCR_STOP; if (cflag & PARENB) cval |= UART_LCR_PARITY; if (!(cflag & PARODD)) @@ -679,7 +595,7 @@ static void mxser_change_speed(struct tty_struct *tty) cval |= UART_LCR_SPAR; if ((info->type == PORT_8250) || (info->type == PORT_16450)) { - if (info->board->chip_flag) { + if (info->board->must_hwid) { fcr = UART_FCR_ENABLE_FIFO; fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; mxser_set_must_fifo_value(info); @@ -687,11 +603,11 @@ static void mxser_change_speed(struct tty_struct *tty) fcr = 0; } else { fcr = UART_FCR_ENABLE_FIFO; - if (info->board->chip_flag) { + if (info->board->must_hwid) { fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; mxser_set_must_fifo_value(info); } else { - switch (info->rx_trigger) { + switch (info->rx_high_water) { case 1: fcr |= UART_FCR_TRIGGER_1; break; @@ -714,35 +630,11 @@ static void mxser_change_speed(struct tty_struct *tty) tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); if (cflag & CRTSCTS) { info->IER |= UART_IER_MSI; - if ((info->type == PORT_16550A) || (info->board->chip_flag)) { + if (mxser_16550A_or_MUST(info)) { info->MCR |= UART_MCR_AFE; } else { - status = inb(info->ioaddr + UART_MSR); - if (tty->hw_stopped) { - if (status & UART_MSR_CTS) { - tty->hw_stopped = 0; - if (info->type != PORT_16550A && - !info->board->chip_flag) { - outb(info->IER & ~UART_IER_THRI, - info->ioaddr + - UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + - UART_IER); - } - tty_wakeup(tty); - } - } else { - if (!(status & UART_MSR_CTS)) { - tty->hw_stopped = 1; - if ((info->type != PORT_16550A) && - (!info->board->chip_flag)) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->ioaddr + - UART_IER); - } - } - } + mxser_handle_cts(tty, info, + inb(info->ioaddr + UART_MSR)); } } outb(info->MCR, info->ioaddr + UART_MCR); @@ -780,23 +672,11 @@ static void mxser_change_speed(struct tty_struct *tty) UART_LSR_FE; } } - if (info->board->chip_flag) { + if (info->board->must_hwid) { mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty)); mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty)); - if (I_IXON(tty)) { - mxser_enable_must_rx_software_flow_control( - info->ioaddr); - } else { - mxser_disable_must_rx_software_flow_control( - info->ioaddr); - } - if (I_IXOFF(tty)) { - mxser_enable_must_tx_software_flow_control( - info->ioaddr); - } else { - mxser_disable_must_tx_software_flow_control( - info->ioaddr); - } + mxser_must_set_rx_sw_flow_control(info->ioaddr, I_IXON(tty)); + mxser_must_set_tx_sw_flow_control(info->ioaddr, I_IXOFF(tty)); } @@ -816,7 +696,6 @@ static void mxser_check_modem_status(struct tty_struct *tty, port->icount.dcd++; if (status & UART_MSR_DCTS) port->icount.cts++; - port->mon_data.modem_status = status; wake_up_interruptible(&port->port.delta_msr_wait); if (tty_port_check_carrier(&port->port) && (status & UART_MSR_DDCD)) { @@ -824,33 +703,8 @@ static void mxser_check_modem_status(struct tty_struct *tty, wake_up_interruptible(&port->port.open_wait); } - if (tty_port_cts_enabled(&port->port)) { - if (tty->hw_stopped) { - if (status & UART_MSR_CTS) { - tty->hw_stopped = 0; - - if ((port->type != PORT_16550A) && - (!port->board->chip_flag)) { - outb(port->IER & ~UART_IER_THRI, - port->ioaddr + UART_IER); - port->IER |= UART_IER_THRI; - outb(port->IER, port->ioaddr + - UART_IER); - } - tty_wakeup(tty); - } - } else { - if (!(status & UART_MSR_CTS)) { - tty->hw_stopped = 1; - if (port->type != PORT_16550A && - !port->board->chip_flag) { - port->IER &= ~UART_IER_THRI; - outb(port->IER, port->ioaddr + - UART_IER); - } - } - } - } + if (tty_port_cts_enabled(&port->port)) + mxser_handle_cts(tty, port, status); } static int mxser_activate(struct tty_port *port, struct tty_struct *tty) @@ -865,7 +719,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) spin_lock_irqsave(&info->slock, flags); - if (!info->ioaddr || !info->type) { + if (!info->type) { set_bit(TTY_IO_ERROR, &tty->flags); free_page(page); spin_unlock_irqrestore(&info->slock, flags); @@ -877,7 +731,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) * Clear the FIFO buffers and disable them * (they will be reenabled in mxser_change_speed()) */ - if (info->board->chip_flag) + if (info->board->must_hwid) outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR); @@ -919,7 +773,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) */ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; - if (info->board->chip_flag) + if (info->board->must_hwid) info->IER |= MOXA_MUST_IER_EGDAI; outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */ @@ -971,7 +825,7 @@ static void mxser_shutdown_port(struct tty_port *port) outb(0x00, info->ioaddr + UART_IER); /* clear Rx/Tx FIFO's */ - if (info->board->chip_flag) + if (info->board->must_hwid) outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE, info->ioaddr + UART_FCR); @@ -983,8 +837,8 @@ static void mxser_shutdown_port(struct tty_port *port) (void) inb(info->ioaddr + UART_RX); - if (info->board->chip_flag) - SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr); + if (info->board->must_hwid) + mxser_must_no_sw_flow_control(info->ioaddr); spin_unlock_irqrestore(&info->slock, flags); } @@ -997,18 +851,12 @@ static void mxser_shutdown_port(struct tty_port *port) */ static int mxser_open(struct tty_struct *tty, struct file *filp) { - struct mxser_port *info; - int line; + struct tty_port *tport = tty->port; + struct mxser_port *port = container_of(tport, struct mxser_port, port); - line = tty->index; - if (line == MXSER_PORTS) - return 0; - info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD]; - if (!info->ioaddr) - return -ENODEV; + tty->driver_data = port; - tty->driver_data = info; - return tty_port_open(&info->port, tty, filp); + return tty_port_open(tport, tty, filp); } static void mxser_flush_buffer(struct tty_struct *tty) @@ -1043,7 +891,7 @@ static void mxser_close_port(struct tty_port *port) * line status register. */ info->IER &= ~UART_IER_RLSI; - if (info->board->chip_flag) + if (info->board->must_hwid) info->IER &= ~MOXA_MUST_RECV_ISR; outb(info->IER, info->ioaddr + UART_IER); @@ -1071,7 +919,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) struct mxser_port *info = tty->driver_data; struct tty_port *port = &info->port; - if (tty->index == MXSER_PORTS || info == NULL) + if (info == NULL) return; if (tty_port_close_start(port, tty, filp) == 0) return; @@ -1118,18 +966,10 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou total += c; } - if (info->xmit_cnt && !tty->stopped) { - if (!tty->hw_stopped || - (info->type == PORT_16550A) || - (info->board->chip_flag)) { - spin_lock_irqsave(&info->slock, flags); - outb(info->IER & ~UART_IER_THRI, info->ioaddr + - UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - spin_unlock_irqrestore(&info->slock, flags); - } - } + if (info->xmit_cnt && !tty->flow.stopped) + if (!tty->hw_stopped || mxser_16550A_or_MUST(info)) + mxser_start_tx(info); + return total; } @@ -1149,17 +989,7 @@ static int mxser_put_char(struct tty_struct *tty, unsigned char ch) info->xmit_head &= SERIAL_XMIT_SIZE - 1; info->xmit_cnt++; spin_unlock_irqrestore(&info->slock, flags); - if (!tty->stopped) { - if (!tty->hw_stopped || - (info->type == PORT_16550A) || - info->board->chip_flag) { - spin_lock_irqsave(&info->slock, flags); - outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - spin_unlock_irqrestore(&info->slock, flags); - } - } + return 1; } @@ -1167,23 +997,15 @@ static int mxser_put_char(struct tty_struct *tty, unsigned char ch) static void mxser_flush_chars(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - unsigned long flags; - if (info->xmit_cnt <= 0 || tty->stopped || !info->port.xmit_buf || - (tty->hw_stopped && info->type != PORT_16550A && - !info->board->chip_flag)) + if (!info->xmit_cnt || tty->flow.stopped || !info->port.xmit_buf || + (tty->hw_stopped && !mxser_16550A_or_MUST(info))) return; - spin_lock_irqsave(&info->slock, flags); - - outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - - spin_unlock_irqrestore(&info->slock, flags); + mxser_start_tx(info); } -static int mxser_write_room(struct tty_struct *tty) +static unsigned int mxser_write_room(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; int ret; @@ -1192,7 +1014,7 @@ static int mxser_write_room(struct tty_struct *tty) return ret < 0 ? 0 : ret; } -static int mxser_chars_in_buffer(struct tty_struct *tty) +static unsigned int mxser_chars_in_buffer(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; return info->xmit_cnt; @@ -1210,9 +1032,6 @@ static int mxser_get_serial_info(struct tty_struct *tty, struct tty_port *port = &info->port; unsigned int closing_wait, close_delay; - if (tty->index == MXSER_PORTS) - return -ENOTTY; - mutex_lock(&port->mutex); close_delay = jiffies_to_msecs(info->port.close_delay) / 10; @@ -1225,10 +1044,10 @@ static int mxser_get_serial_info(struct tty_struct *tty, ss->port = info->ioaddr, ss->irq = info->board->irq, ss->flags = info->port.flags, - ss->baud_base = info->baud_base, + ss->baud_base = MXSER_BAUD_BASE, ss->close_delay = close_delay; ss->closing_wait = closing_wait; - ss->custom_divisor = info->custom_divisor, + ss->custom_divisor = MXSER_CUSTOM_DIVISOR, mutex_unlock(&port->mutex); return 0; } @@ -1240,19 +1059,13 @@ static int mxser_set_serial_info(struct tty_struct *tty, struct tty_port *port = &info->port; speed_t baud; unsigned long sl_flags; - unsigned int flags, close_delay, closing_wait; + unsigned int old_speed, close_delay, closing_wait; int retval = 0; - if (tty->index == MXSER_PORTS) - return -ENOTTY; if (tty_io_error(tty)) return -EIO; mutex_lock(&port->mutex); - if (!info->ioaddr) { - mutex_unlock(&port->mutex); - return -ENODEV; - } if (ss->irq != info->board->irq || ss->port != info->ioaddr) { @@ -1260,7 +1073,7 @@ static int mxser_set_serial_info(struct tty_struct *tty, return -EINVAL; } - flags = port->flags & ASYNC_SPD_MASK; + old_speed = port->flags & ASYNC_SPD_MASK; close_delay = msecs_to_jiffies(ss->close_delay * 10); closing_wait = ss->closing_wait; @@ -1268,15 +1081,15 @@ static int mxser_set_serial_info(struct tty_struct *tty, closing_wait = msecs_to_jiffies(closing_wait * 10); if (!capable(CAP_SYS_ADMIN)) { - if ((ss->baud_base != info->baud_base) || - (close_delay != info->port.close_delay) || - (closing_wait != info->port.closing_wait) || - ((ss->flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) { + if ((ss->baud_base != MXSER_BAUD_BASE) || + (close_delay != port->close_delay) || + (closing_wait != port->closing_wait) || + ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { mutex_unlock(&port->mutex); return -EPERM; } - info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) | - (ss->flags & ASYNC_USR_MASK)); + port->flags = (port->flags & ~ASYNC_USR_MASK) | + (ss->flags & ASYNC_USR_MASK); } else { /* * OK, past this point, all the error checking has been done. @@ -1287,9 +1100,9 @@ static int mxser_set_serial_info(struct tty_struct *tty, port->close_delay = close_delay; port->closing_wait = closing_wait; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && - (ss->baud_base != info->baud_base || + (ss->baud_base != MXSER_BAUD_BASE || ss->custom_divisor != - info->custom_divisor)) { + MXSER_CUSTOM_DIVISOR)) { if (ss->custom_divisor == 0) { mutex_unlock(&port->mutex); return -EINVAL; @@ -1300,11 +1113,11 @@ static int mxser_set_serial_info(struct tty_struct *tty, info->type = ss->type; - process_txrx_fifo(info); + mxser_process_txrx_fifo(info); } if (tty_port_initialized(port)) { - if (flags != (port->flags & ASYNC_SPD_MASK)) { + if (old_speed != (port->flags & ASYNC_SPD_MASK)) { spin_lock_irqsave(&info->slock, sl_flags); mxser_change_speed(tty); spin_unlock_irqrestore(&info->slock, sl_flags); @@ -1348,19 +1161,16 @@ static int mxser_tiocmget(struct tty_struct *tty) unsigned char control, status; unsigned long flags; - - if (tty->index == MXSER_PORTS) - return -ENOIOCTLCMD; if (tty_io_error(tty)) return -EIO; - control = info->MCR; - spin_lock_irqsave(&info->slock, flags); + control = info->MCR; status = inb(info->ioaddr + UART_MSR); if (status & UART_MSR_ANY_DELTA) mxser_check_modem_status(tty, info, status); spin_unlock_irqrestore(&info->slock, flags); + return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | @@ -1375,9 +1185,6 @@ static int mxser_tiocmset(struct tty_struct *tty, struct mxser_port *info = tty->driver_data; unsigned long flags; - - if (tty->index == MXSER_PORTS) - return -ENOIOCTLCMD; if (tty_io_error(tty)) return -EIO; @@ -1398,267 +1205,6 @@ static int mxser_tiocmset(struct tty_struct *tty, return 0; } -static int __init mxser_program_mode(int port) -{ - int id, i, j, n; - - outb(0, port); - outb(0, port); - outb(0, port); - (void)inb(port); - (void)inb(port); - outb(0, port); - (void)inb(port); - - id = inb(port + 1) & 0x1F; - if ((id != C168_ASIC_ID) && - (id != C104_ASIC_ID) && - (id != C102_ASIC_ID) && - (id != CI132_ASIC_ID) && - (id != CI134_ASIC_ID) && - (id != CI104J_ASIC_ID)) - return -1; - for (i = 0, j = 0; i < 4; i++) { - n = inb(port + 2); - if (n == 'M') { - j = 1; - } else if ((j == 1) && (n == 1)) { - j = 2; - break; - } else - j = 0; - } - if (j != 2) - id = -2; - return id; -} - -static void __init mxser_normal_mode(int port) -{ - int i, n; - - outb(0xA5, port + 1); - outb(0x80, port + 3); - outb(12, port + 0); /* 9600 bps */ - outb(0, port + 1); - outb(0x03, port + 3); /* 8 data bits */ - outb(0x13, port + 4); /* loop back mode */ - for (i = 0; i < 16; i++) { - n = inb(port + 5); - if ((n & 0x61) == 0x60) - break; - if ((n & 1) == 1) - (void)inb(port); - } - outb(0x00, port + 4); -} - -#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */ -#define CHIP_DO 0x02 /* Serial Data Output in Eprom */ -#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */ -#define CHIP_DI 0x08 /* Serial Data Input in Eprom */ -#define EN_CCMD 0x000 /* Chip's command register */ -#define EN0_RSARLO 0x008 /* Remote start address reg 0 */ -#define EN0_RSARHI 0x009 /* Remote start address reg 1 */ -#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */ -#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */ -#define EN0_DCFG 0x00E /* Data configuration reg WR */ -#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ -#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ -#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ -static int __init mxser_read_register(int port, unsigned short *regs) -{ - int i, k, value, id; - unsigned int j; - - id = mxser_program_mode(port); - if (id < 0) - return id; - for (i = 0; i < 14; i++) { - k = (i & 0x3F) | 0x180; - for (j = 0x100; j > 0; j >>= 1) { - outb(CHIP_CS, port); - if (k & j) { - outb(CHIP_CS | CHIP_DO, port); - outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */ - } else { - outb(CHIP_CS, port); - outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */ - } - } - (void)inb(port); - value = 0; - for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) { - outb(CHIP_CS, port); - outb(CHIP_CS | CHIP_SK, port); - if (inb(port) & CHIP_DI) - value |= j; - } - regs[i] = value; - outb(0, port); - } - mxser_normal_mode(port); - return id; -} - -static int mxser_ioctl_special(unsigned int cmd, void __user *argp) -{ - struct mxser_port *ip; - struct tty_port *port; - struct tty_struct *tty; - int result, status; - unsigned int i, j; - int ret = 0; - - switch (cmd) { - case MOXA_GET_MAJOR: - printk_ratelimited(KERN_WARNING "mxser: '%s' uses deprecated ioctl " - "%x (GET_MAJOR), fix your userspace\n", - current->comm, cmd); - return put_user(ttymajor, (int __user *)argp); - - case MOXA_CHKPORTENABLE: - result = 0; - for (i = 0; i < MXSER_BOARDS; i++) - for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) - if (mxser_boards[i].ports[j].ioaddr) - result |= (1 << i); - return put_user(result, (unsigned long __user *)argp); - case MOXA_GETDATACOUNT: - /* The receive side is locked by port->slock but it isn't - clear that an exact snapshot is worth copying here */ - if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log))) - ret = -EFAULT; - return ret; - case MOXA_GETMSTATUS: { - struct mxser_mstatus ms, __user *msu = argp; - for (i = 0; i < MXSER_BOARDS; i++) - for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) { - ip = &mxser_boards[i].ports[j]; - port = &ip->port; - memset(&ms, 0, sizeof(ms)); - - mutex_lock(&port->mutex); - if (!ip->ioaddr) - goto copy; - - tty = tty_port_tty_get(port); - - if (!tty) - ms.cflag = ip->normal_termios.c_cflag; - else - ms.cflag = tty->termios.c_cflag; - tty_kref_put(tty); - spin_lock_irq(&ip->slock); - status = inb(ip->ioaddr + UART_MSR); - spin_unlock_irq(&ip->slock); - if (status & UART_MSR_DCD) - ms.dcd = 1; - if (status & UART_MSR_DSR) - ms.dsr = 1; - if (status & UART_MSR_CTS) - ms.cts = 1; - copy: - mutex_unlock(&port->mutex); - if (copy_to_user(msu, &ms, sizeof(ms))) - return -EFAULT; - msu++; - } - return 0; - } - case MOXA_ASPP_MON_EXT: { - struct mxser_mon_ext *me; /* it's 2k, stack unfriendly */ - unsigned int cflag, iflag, p; - u8 opmode; - - me = kzalloc(sizeof(*me), GFP_KERNEL); - if (!me) - return -ENOMEM; - - for (i = 0, p = 0; i < MXSER_BOARDS; i++) { - for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) { - if (p >= ARRAY_SIZE(me->rx_cnt)) { - i = MXSER_BOARDS; - break; - } - ip = &mxser_boards[i].ports[j]; - port = &ip->port; - - mutex_lock(&port->mutex); - if (!ip->ioaddr) { - mutex_unlock(&port->mutex); - continue; - } - - spin_lock_irq(&ip->slock); - status = mxser_get_msr(ip->ioaddr, 0, p); - - if (status & UART_MSR_TERI) - ip->icount.rng++; - if (status & UART_MSR_DDSR) - ip->icount.dsr++; - if (status & UART_MSR_DDCD) - ip->icount.dcd++; - if (status & UART_MSR_DCTS) - ip->icount.cts++; - - ip->mon_data.modem_status = status; - me->rx_cnt[p] = ip->mon_data.rxcnt; - me->tx_cnt[p] = ip->mon_data.txcnt; - me->up_rxcnt[p] = ip->mon_data.up_rxcnt; - me->up_txcnt[p] = ip->mon_data.up_txcnt; - me->modem_status[p] = - ip->mon_data.modem_status; - spin_unlock_irq(&ip->slock); - - tty = tty_port_tty_get(&ip->port); - - if (!tty) { - cflag = ip->normal_termios.c_cflag; - iflag = ip->normal_termios.c_iflag; - me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios); - } else { - cflag = tty->termios.c_cflag; - iflag = tty->termios.c_iflag; - me->baudrate[p] = tty_get_baud_rate(tty); - } - tty_kref_put(tty); - - me->databits[p] = cflag & CSIZE; - me->stopbits[p] = cflag & CSTOPB; - me->parity[p] = cflag & (PARENB | PARODD | - CMSPAR); - - if (cflag & CRTSCTS) - me->flowctrl[p] |= 0x03; - - if (iflag & (IXON | IXOFF)) - me->flowctrl[p] |= 0x0C; - - if (ip->type == PORT_16550A) - me->fifo[p] = 1; - - if (ip->board->chip_flag == MOXA_MUST_MU860_HWID) { - opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2); - opmode &= OP_MODE_MASK; - } else { - opmode = RS232_MODE; - } - me->iftype[p] = opmode; - mutex_unlock(&port->mutex); - } - } - if (copy_to_user(argp, me, sizeof(*me))) - ret = -EFAULT; - kfree(me); - return ret; - } - default: - return -ENOIOCTLCMD; - } - return 0; -} - static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg, struct async_icount *cprev) { @@ -1680,6 +1226,41 @@ static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg, return ret; } +/* We should likely switch to TIOCGRS485/TIOCSRS485. */ +static int mxser_ioctl_op_mode(struct mxser_port *port, int index, bool set, + int __user *u_opmode) +{ + int opmode, p = index % 4; + int shiftbit = p * 2; + u8 val; + + if (port->board->must_hwid != MOXA_MUST_MU860_HWID) + return -EFAULT; + + if (set) { + if (get_user(opmode, u_opmode)) + return -EFAULT; + + if (opmode & ~OP_MODE_MASK) + return -EINVAL; + + spin_lock_irq(&port->slock); + val = inb(port->opmode_ioaddr); + val &= ~(OP_MODE_MASK << shiftbit); + val |= (opmode << shiftbit); + outb(val, port->opmode_ioaddr); + spin_unlock_irq(&port->slock); + + return 0; + } + + spin_lock_irq(&port->slock); + opmode = inb(port->opmode_ioaddr) >> shiftbit; + spin_unlock_irq(&port->slock); + + return put_user(opmode & OP_MODE_MASK, u_opmode); +} + static int mxser_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -1688,47 +1269,9 @@ static int mxser_ioctl(struct tty_struct *tty, unsigned long flags; void __user *argp = (void __user *)arg; - if (tty->index == MXSER_PORTS) - return mxser_ioctl_special(cmd, argp); - - if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) { - int p; - unsigned long opmode; - static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f }; - int shiftbit; - unsigned char val, mask; - - if (info->board->chip_flag != MOXA_MUST_MU860_HWID) - return -EFAULT; - - p = tty->index % 4; - if (cmd == MOXA_SET_OP_MODE) { - if (get_user(opmode, (int __user *) argp)) - return -EFAULT; - if (opmode != RS232_MODE && - opmode != RS485_2WIRE_MODE && - opmode != RS422_MODE && - opmode != RS485_4WIRE_MODE) - return -EFAULT; - mask = ModeMask[p]; - shiftbit = p * 2; - spin_lock_irq(&info->slock); - val = inb(info->opmode_ioaddr); - val &= mask; - val |= (opmode << shiftbit); - outb(val, info->opmode_ioaddr); - spin_unlock_irq(&info->slock); - } else { - shiftbit = p * 2; - spin_lock_irq(&info->slock); - opmode = inb(info->opmode_ioaddr) >> shiftbit; - spin_unlock_irq(&info->slock); - opmode &= OP_MODE_MASK; - if (put_user(opmode, (int __user *)argp)) - return -EFAULT; - } - return 0; - } + if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) + return mxser_ioctl_op_mode(info, tty->index, + cmd == MOXA_SET_OP_MODE, argp); if (cmd != TIOCMIWAIT && tty_io_error(tty)) return -EIO; @@ -1749,72 +1292,6 @@ static int mxser_ioctl(struct tty_struct *tty, return wait_event_interruptible(info->port.delta_msr_wait, mxser_cflags_changed(info, arg, &cnow)); - case MOXA_HighSpeedOn: - return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); - case MOXA_SDS_RSTICOUNTER: - spin_lock_irq(&info->slock); - info->mon_data.rxcnt = 0; - info->mon_data.txcnt = 0; - spin_unlock_irq(&info->slock); - return 0; - - case MOXA_ASPP_OQUEUE:{ - int len, lsr; - - len = mxser_chars_in_buffer(tty); - spin_lock_irq(&info->slock); - lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE; - spin_unlock_irq(&info->slock); - len += (lsr ? 0 : 1); - - return put_user(len, (int __user *)argp); - } - case MOXA_ASPP_MON: { - int mcr, status; - - spin_lock_irq(&info->slock); - status = mxser_get_msr(info->ioaddr, 1, tty->index); - mxser_check_modem_status(tty, info, status); - - mcr = inb(info->ioaddr + UART_MCR); - spin_unlock_irq(&info->slock); - - if (mcr & MOXA_MUST_MCR_XON_FLAG) - info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD; - else - info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD; - - if (mcr & MOXA_MUST_MCR_TX_XON) - info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT; - else - info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; - - if (tty->hw_stopped) - info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; - else - info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; - - if (copy_to_user(argp, &info->mon_data, - sizeof(struct mxser_mon))) - return -EFAULT; - - return 0; - } - case MOXA_ASPP_LSTATUS: { - if (put_user(info->err_shadow, (unsigned char __user *)argp)) - return -EFAULT; - - info->err_shadow = 0; - return 0; - } - case MOXA_SET_BAUD_METHOD: { - int method; - - if (get_user(method, (int __user *)argp)) - return -EFAULT; - mxser_set_baud_method[tty->index] = method; - return put_user(method, (int __user *)argp); - } default: return -ENOIOCTLCMD; } @@ -1860,7 +1337,7 @@ static void mxser_stoprx(struct tty_struct *tty) info->ldisc_stop_rx = 1; if (I_IXOFF(tty)) { - if (info->board->chip_flag) { + if (info->board->must_hwid) { info->IER &= ~MOXA_MUST_RECV_ISR; outb(info->IER, info->ioaddr + UART_IER); } else { @@ -1896,7 +1373,7 @@ static void mxser_unthrottle(struct tty_struct *tty) if (info->x_char) info->x_char = 0; else { - if (info->board->chip_flag) { + if (info->board->must_hwid) { info->IER |= MOXA_MUST_RECV_ISR; outb(info->IER, info->ioaddr + UART_IER); } else { @@ -1917,7 +1394,7 @@ static void mxser_unthrottle(struct tty_struct *tty) /* * mxser_stop() and mxser_start() * - * This routines are called before setting or resetting tty->stopped. + * This routines are called before setting or resetting tty->flow.stopped. * They enable or disable transmitter interrupts, as necessary. */ static void mxser_stop(struct tty_struct *tty) @@ -1926,10 +1403,8 @@ static void mxser_stop(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->IER & UART_IER_THRI) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - } + if (info->IER & UART_IER_THRI) + __mxser_stop_tx(info); spin_unlock_irqrestore(&info->slock, flags); } @@ -1939,11 +1414,8 @@ static void mxser_start(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->xmit_cnt && info->port.xmit_buf) { - outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - } + if (info->xmit_cnt && info->port.xmit_buf) + __mxser_start_tx(info); spin_unlock_irqrestore(&info->slock, flags); } @@ -1963,12 +1435,11 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi /* Handle sw stopped */ if ((old_termios->c_iflag & IXON) && !I_IXON(tty)) { - tty->stopped = 0; + tty->flow.stopped = 0; - if (info->board->chip_flag) { + if (info->board->must_hwid) { spin_lock_irqsave(&info->slock, flags); - mxser_disable_must_rx_software_flow_control( - info->ioaddr); + mxser_must_set_rx_sw_flow_control(info->ioaddr, false); spin_unlock_irqrestore(&info->slock, flags); } @@ -2051,88 +1522,92 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state) { struct mxser_port *info = tty->driver_data; unsigned long flags; + u8 lcr; spin_lock_irqsave(&info->slock, flags); + lcr = inb(info->ioaddr + UART_LCR); if (break_state == -1) - outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC, - info->ioaddr + UART_LCR); + lcr |= UART_LCR_SBC; else - outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC, - info->ioaddr + UART_LCR); + lcr &= ~UART_LCR_SBC; + outb(lcr, info->ioaddr + UART_LCR); spin_unlock_irqrestore(&info->slock, flags); + return 0; } -static void mxser_receive_chars(struct tty_struct *tty, - struct mxser_port *port, int *status) +static bool mxser_receive_chars_new(struct tty_struct *tty, + struct mxser_port *port, u8 status) { - unsigned char ch, gdl; - int ignored = 0; - int cnt = 0; - int recv_room; - int max = 256; + enum mxser_must_hwid hwid = port->board->must_hwid; + u8 gdl; + + if (hwid == MOXA_OTHER_UART) + return false; + if (status & UART_LSR_BRK_ERROR_BITS) + return false; + if (hwid == MOXA_MUST_MU860_HWID && (status & MOXA_MUST_LSR_RERR)) + return false; + if (status & MOXA_MUST_LSR_RERR) + return false; - recv_room = tty->receive_room; - if (recv_room == 0 && !port->ldisc_stop_rx) + gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER); + if (hwid == MOXA_MUST_MU150_HWID) + gdl &= MOXA_MUST_GDL_MASK; + + if (gdl >= tty->receive_room && !port->ldisc_stop_rx) mxser_stoprx(tty); - if (port->board->chip_flag != MOXA_OTHER_UART) { - - if (*status & UART_LSR_SPECIAL) - goto intr_old; - if (port->board->chip_flag == MOXA_MUST_MU860_HWID && - (*status & MOXA_MUST_LSR_RERR)) - goto intr_old; - if (*status & MOXA_MUST_LSR_RERR) - goto intr_old; - - gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER); - - if (port->board->chip_flag == MOXA_MUST_MU150_HWID) - gdl &= MOXA_MUST_GDL_MASK; - if (gdl >= recv_room) { - if (!port->ldisc_stop_rx) - mxser_stoprx(tty); - } - while (gdl--) { - ch = inb(port->ioaddr + UART_RX); - tty_insert_flip_char(&port->port, ch, 0); - cnt++; - } - goto end_intr; + + while (gdl--) { + u8 ch = inb(port->ioaddr + UART_RX); + tty_insert_flip_char(&port->port, ch, 0); } -intr_old: + + return true; +} + +static u8 mxser_receive_chars_old(struct tty_struct *tty, + struct mxser_port *port, u8 status) +{ + enum mxser_must_hwid hwid = port->board->must_hwid; + int recv_room = tty->receive_room; + int ignored = 0; + int max = 256; + int cnt = 0; + u8 ch; do { if (max-- < 0) break; ch = inb(port->ioaddr + UART_RX); - if (port->board->chip_flag && (*status & UART_LSR_OE)) - outb(0x23, port->ioaddr + UART_FCR); - *status &= port->read_status_mask; - if (*status & port->ignore_status_mask) { + if (hwid && (status & UART_LSR_OE)) + outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | + MOXA_MUST_FCR_GDA_MODE_ENABLE, + port->ioaddr + UART_FCR); + status &= port->read_status_mask; + if (status & port->ignore_status_mask) { if (++ignored > 100) break; } else { char flag = 0; - if (*status & UART_LSR_SPECIAL) { - if (*status & UART_LSR_BI) { + if (status & UART_LSR_BRK_ERROR_BITS) { + if (status & UART_LSR_BI) { flag = TTY_BREAK; port->icount.brk++; if (port->port.flags & ASYNC_SAK) do_SAK(tty); - } else if (*status & UART_LSR_PE) { + } else if (status & UART_LSR_PE) { flag = TTY_PARITY; port->icount.parity++; - } else if (*status & UART_LSR_FE) { + } else if (status & UART_LSR_FE) { flag = TTY_FRAME; port->icount.frame++; - } else if (*status & UART_LSR_OE) { + } else if (status & UART_LSR_OE) { flag = TTY_OVERRUN; port->icount.overrun++; - } else - flag = TTY_BREAK; + } } tty_insert_flip_char(&port->port, ch, flag); cnt++; @@ -2144,18 +1619,27 @@ intr_old: } - if (port->board->chip_flag) + if (hwid) break; - *status = inb(port->ioaddr + UART_LSR); - } while (*status & UART_LSR_DR); + status = inb(port->ioaddr + UART_LSR); + } while (status & UART_LSR_DR); + + return status; +} + +static u8 mxser_receive_chars(struct tty_struct *tty, + struct mxser_port *port, u8 status) +{ + if (tty->receive_room == 0 && !port->ldisc_stop_rx) + mxser_stoprx(tty); -end_intr: - mxvar_log.rxcnt[tty->index] += cnt; - port->mon_data.rxcnt += cnt; - port->mon_data.up_rxcnt += cnt; + if (!mxser_receive_chars_new(tty, port, status)) + status = mxser_receive_chars_old(tty, port, status); tty_flip_buffer_push(&port->port); + + return status; } static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port) @@ -2165,9 +1649,6 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port if (port->x_char) { outb(port->x_char, port->ioaddr + UART_TX); port->x_char = 0; - mxvar_log.txcnt[tty->index]++; - port->mon_data.txcnt++; - port->mon_data.up_txcnt++; port->icount.tx++; return; } @@ -2175,12 +1656,9 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port if (port->port.xmit_buf == NULL) return; - if (port->xmit_cnt <= 0 || tty->stopped || - (tty->hw_stopped && - (port->type != PORT_16550A) && - (!port->board->chip_flag))) { - port->IER &= ~UART_IER_THRI; - outb(port->IER, port->ioaddr + UART_IER); + if (!port->xmit_cnt || tty->flow.stopped || + (tty->hw_stopped && !mxser_16550A_or_MUST(port))) { + __mxser_stop_tx(port); return; } @@ -2190,22 +1668,72 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port outb(port->port.xmit_buf[port->xmit_tail++], port->ioaddr + UART_TX); port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); - if (--port->xmit_cnt <= 0) + if (!--port->xmit_cnt) break; } while (--count > 0); - mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt); - port->mon_data.txcnt += (cnt - port->xmit_cnt); - port->mon_data.up_txcnt += (cnt - port->xmit_cnt); port->icount.tx += (cnt - port->xmit_cnt); if (port->xmit_cnt < WAKEUP_CHARS) tty_wakeup(tty); - if (port->xmit_cnt <= 0) { - port->IER &= ~UART_IER_THRI; - outb(port->IER, port->ioaddr + UART_IER); + if (!port->xmit_cnt) + __mxser_stop_tx(port); +} + +static bool mxser_port_isr(struct mxser_port *port) +{ + struct tty_struct *tty; + u8 iir, msr, status; + bool error = false; + + iir = inb(port->ioaddr + UART_IIR); + if (iir & UART_IIR_NO_INT) + return true; + + iir &= MOXA_MUST_IIR_MASK; + tty = tty_port_tty_get(&port->port); + if (!tty || port->closing || !tty_port_initialized(&port->port)) { + status = inb(port->ioaddr + UART_LSR); + outb(MOXA_MUST_FCR_GDA_MODE_ENABLE | UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + port->ioaddr + UART_FCR); + inb(port->ioaddr + UART_MSR); + + error = true; + goto put_tty; + } + + status = inb(port->ioaddr + UART_LSR); + + if (port->board->must_hwid) { + if (iir == MOXA_MUST_IIR_GDA || + iir == MOXA_MUST_IIR_RDA || + iir == MOXA_MUST_IIR_RTO || + iir == MOXA_MUST_IIR_LSR) + status = mxser_receive_chars(tty, port, status); + } else { + status &= port->read_status_mask; + if (status & UART_LSR_DR) + status = mxser_receive_chars(tty, port, status); + } + + msr = inb(port->ioaddr + UART_MSR); + if (msr & UART_MSR_ANY_DELTA) + mxser_check_modem_status(tty, port, msr); + + if (port->board->must_hwid) { + if (iir == 0x02 && (status & UART_LSR_THRE)) + mxser_transmit_chars(tty, port); + } else { + if (status & UART_LSR_THRE) + mxser_transmit_chars(tty, port); } + +put_tty: + tty_kref_put(tty); + + return error; } /* @@ -2213,33 +1741,21 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port */ static irqreturn_t mxser_interrupt(int irq, void *dev_id) { - int status, iir, i; - struct mxser_board *brd = NULL; + struct mxser_board *brd = dev_id; struct mxser_port *port; - int max, irqbits, bits, msr; unsigned int int_cnt, pass_counter = 0; + unsigned int i, max = brd->nports; int handled = IRQ_NONE; - struct tty_struct *tty; - - for (i = 0; i < MXSER_BOARDS; i++) - if (dev_id == &mxser_boards[i]) { - brd = dev_id; - break; - } + u8 irqbits, bits, mask = BIT(max) - 1; - if (i == MXSER_BOARDS) - goto irq_stop; - if (brd == NULL) - goto irq_stop; - max = brd->info->nports; while (pass_counter++ < MXSER_ISR_PASS_LIMIT) { - irqbits = inb(brd->vector) & brd->vector_mask; - if (irqbits == brd->vector_mask) + irqbits = inb(brd->vector) & mask; + if (irqbits == mask) break; handled = IRQ_HANDLED; for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { - if (irqbits == brd->vector_mask) + if (irqbits == mask) break; if (bits & irqbits) continue; @@ -2248,65 +1764,13 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) int_cnt = 0; spin_lock(&port->slock); do { - iir = inb(port->ioaddr + UART_IIR); - if (iir & UART_IIR_NO_INT) + if (mxser_port_isr(port)) break; - iir &= MOXA_MUST_IIR_MASK; - tty = tty_port_tty_get(&port->port); - if (!tty || port->closing || - !tty_port_initialized(&port->port)) { - status = inb(port->ioaddr + UART_LSR); - outb(0x27, port->ioaddr + UART_FCR); - inb(port->ioaddr + UART_MSR); - tty_kref_put(tty); - break; - } - - status = inb(port->ioaddr + UART_LSR); - - if (status & UART_LSR_PE) - port->err_shadow |= NPPI_NOTIFY_PARITY; - if (status & UART_LSR_FE) - port->err_shadow |= NPPI_NOTIFY_FRAMING; - if (status & UART_LSR_OE) - port->err_shadow |= - NPPI_NOTIFY_HW_OVERRUN; - if (status & UART_LSR_BI) - port->err_shadow |= NPPI_NOTIFY_BREAK; - - if (port->board->chip_flag) { - if (iir == MOXA_MUST_IIR_GDA || - iir == MOXA_MUST_IIR_RDA || - iir == MOXA_MUST_IIR_RTO || - iir == MOXA_MUST_IIR_LSR) - mxser_receive_chars(tty, port, - &status); - - } else { - status &= port->read_status_mask; - if (status & UART_LSR_DR) - mxser_receive_chars(tty, port, - &status); - } - msr = inb(port->ioaddr + UART_MSR); - if (msr & UART_MSR_ANY_DELTA) - mxser_check_modem_status(tty, port, msr); - - if (port->board->chip_flag) { - if (iir == 0x02 && (status & - UART_LSR_THRE)) - mxser_transmit_chars(tty, port); - } else { - if (status & UART_LSR_THRE) - mxser_transmit_chars(tty, port); - } - tty_kref_put(tty); } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); spin_unlock(&port->slock); } } -irq_stop: return handled; } @@ -2346,254 +1810,103 @@ static const struct tty_port_operations mxser_port_ops = { * The MOXA Smartio/Industio serial driver boot-time initialization code! */ -static bool allow_overlapping_vector; -module_param(allow_overlapping_vector, bool, S_IRUGO); -MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)"); - -static bool mxser_overlapping_vector(struct mxser_board *brd) -{ - return allow_overlapping_vector && - brd->vector >= brd->ports[0].ioaddr && - brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports; -} - -static int mxser_request_vector(struct mxser_board *brd) +static void mxser_initbrd(struct mxser_board *brd, bool high_baud) { - if (mxser_overlapping_vector(brd)) - return 0; - return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO; -} + struct mxser_port *info; + unsigned int i; + bool is_mu860; -static void mxser_release_vector(struct mxser_board *brd) -{ - if (mxser_overlapping_vector(brd)) - return; - release_region(brd->vector, 1); -} + brd->must_hwid = mxser_must_get_hwid(brd->ports[0].ioaddr); + is_mu860 = brd->must_hwid == MOXA_MUST_MU860_HWID; -static void mxser_release_ISA_res(struct mxser_board *brd) -{ - release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); - mxser_release_vector(brd); -} + for (i = 0; i < UART_INFO_NUM; i++) { + if (Gpci_uart_info[i].type == brd->must_hwid) { + brd->max_baud = Gpci_uart_info[i].max_baud; -static int mxser_initbrd(struct mxser_board *brd) -{ - struct mxser_port *info; - unsigned int i; - int retval; + /* exception....CP-102 */ + if (high_baud) + brd->max_baud = 921600; + break; + } + } - printk(KERN_INFO "mxser: max. baud rate = %d bps\n", - brd->ports[0].max_baud); + if (is_mu860) { + /* set to RS232 mode by default */ + outb(0, brd->vector + 4); + outb(0, brd->vector + 0x0c); + } - for (i = 0; i < brd->info->nports; i++) { + for (i = 0; i < brd->nports; i++) { info = &brd->ports[i]; + if (is_mu860) { + if (i < 4) + info->opmode_ioaddr = brd->vector + 4; + else + info->opmode_ioaddr = brd->vector + 0x0c; + } tty_port_init(&info->port); info->port.ops = &mxser_port_ops; info->board = brd; - info->stop_rx = 0; info->ldisc_stop_rx = 0; /* Enhance mode enabled here */ - if (brd->chip_flag != MOXA_OTHER_UART) - mxser_enable_must_enchance_mode(info->ioaddr); + if (brd->must_hwid != MOXA_OTHER_UART) + mxser_must_set_enhance_mode(info->ioaddr, true); - info->type = brd->uart_type; + info->type = PORT_16550A; - process_txrx_fifo(info); + mxser_process_txrx_fifo(info); - info->custom_divisor = info->baud_base * 16; info->port.close_delay = 5 * HZ / 10; info->port.closing_wait = 30 * HZ; - info->normal_termios = mxvar_sdriver->init_termios; - memset(&info->mon_data, 0, sizeof(struct mxser_mon)); - info->err_shadow = 0; spin_lock_init(&info->slock); /* before set INT ISR, disable all int */ outb(inb(info->ioaddr + UART_IER) & 0xf0, info->ioaddr + UART_IER); } - - retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser", - brd); - if (retval) { - for (i = 0; i < brd->info->nports; i++) - tty_port_destroy(&brd->ports[i].port); - printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " - "conflict with another device.\n", - brd->info->name, brd->irq); - } - - return retval; -} - -static void mxser_board_remove(struct mxser_board *brd) -{ - unsigned int i; - - for (i = 0; i < brd->info->nports; i++) { - tty_unregister_device(mxvar_sdriver, brd->idx + i); - tty_port_destroy(&brd->ports[i].port); - } - free_irq(brd->irq, brd); -} - -static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) -{ - int id, i, bits, ret; - unsigned short regs[16], irq; - unsigned char scratch, scratch2; - - brd->chip_flag = MOXA_OTHER_UART; - - id = mxser_read_register(cap, regs); - switch (id) { - case C168_ASIC_ID: - brd->info = &mxser_cards[0]; - break; - case C104_ASIC_ID: - brd->info = &mxser_cards[1]; - break; - case CI104J_ASIC_ID: - brd->info = &mxser_cards[2]; - break; - case C102_ASIC_ID: - brd->info = &mxser_cards[5]; - break; - case CI132_ASIC_ID: - brd->info = &mxser_cards[6]; - break; - case CI134_ASIC_ID: - brd->info = &mxser_cards[7]; - break; - default: - return 0; - } - - irq = 0; - /* some ISA cards have 2 ports, but we want to see them as 4-port (why?) - Flag-hack checks if configuration should be read as 2-port here. */ - if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) { - irq = regs[9] & 0xF000; - irq = irq | (irq >> 4); - if (irq != (regs[9] & 0xFF00)) - goto err_irqconflict; - } else if (brd->info->nports == 4) { - irq = regs[9] & 0xF000; - irq = irq | (irq >> 4); - irq = irq | (irq >> 8); - if (irq != regs[9]) - goto err_irqconflict; - } else if (brd->info->nports == 8) { - irq = regs[9] & 0xF000; - irq = irq | (irq >> 4); - irq = irq | (irq >> 8); - if ((irq != regs[9]) || (irq != regs[10])) - goto err_irqconflict; - } - - if (!irq) { - printk(KERN_ERR "mxser: interrupt number unset\n"); - return -EIO; - } - brd->irq = ((int)(irq & 0xF000) >> 12); - for (i = 0; i < 8; i++) - brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8; - if ((regs[12] & 0x80) == 0) { - printk(KERN_ERR "mxser: invalid interrupt vector\n"); - return -EIO; - } - brd->vector = (int)regs[11]; /* interrupt vector */ - if (id == 1) - brd->vector_mask = 0x00FF; - else - brd->vector_mask = 0x000F; - for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) { - if (regs[12] & bits) { - brd->ports[i].baud_base = 921600; - brd->ports[i].max_baud = 921600; - } else { - brd->ports[i].baud_base = 115200; - brd->ports[i].max_baud = 115200; - } - } - scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB); - outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR); - outb(0, cap + UART_EFR); /* EFR is the same as FCR */ - outb(scratch2, cap + UART_LCR); - outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR); - scratch = inb(cap + UART_IIR); - - if (scratch & 0xC0) - brd->uart_type = PORT_16550A; - else - brd->uart_type = PORT_16450; - if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports, - "mxser(IO)")) { - printk(KERN_ERR "mxser: can't request ports I/O region: " - "0x%.8lx-0x%.8lx\n", - brd->ports[0].ioaddr, brd->ports[0].ioaddr + - 8 * brd->info->nports - 1); - return -EIO; - } - - ret = mxser_request_vector(brd); - if (ret) { - release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); - printk(KERN_ERR "mxser: can't request interrupt vector region: " - "0x%.8lx-0x%.8lx\n", - brd->ports[0].ioaddr, brd->ports[0].ioaddr + - 8 * brd->info->nports - 1); - return ret; - } - return brd->info->nports; - -err_irqconflict: - printk(KERN_ERR "mxser: invalid interrupt number\n"); - return -EIO; } static int mxser_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { -#ifdef CONFIG_PCI struct mxser_board *brd; - unsigned int i, j; + unsigned int i, base; unsigned long ioaddress; + unsigned short nports = MXSER_NPORTS(ent->driver_data); struct device *tty_dev; int retval = -EINVAL; - for (i = 0; i < MXSER_BOARDS; i++) - if (mxser_boards[i].info == NULL) - break; - + i = find_first_zero_bit(mxser_boards, MXSER_BOARDS); if (i >= MXSER_BOARDS) { dev_err(&pdev->dev, "too many boards found (maximum %d), board " "not configured\n", MXSER_BOARDS); goto err; } - brd = &mxser_boards[i]; - brd->idx = i * MXSER_PORTS_PER_BOARD; - dev_info(&pdev->dev, "found MOXA %s board (BusNo=%d, DevNo=%d)\n", - mxser_cards[ent->driver_data].name, - pdev->bus->number, PCI_SLOT(pdev->devfn)); + brd = devm_kzalloc(&pdev->dev, struct_size(brd, ports, nports), + GFP_KERNEL); + if (!brd) + goto err; + + brd->idx = i; + __set_bit(brd->idx, mxser_boards); + base = i * MXSER_PORTS_PER_BOARD; - retval = pci_enable_device(pdev); + retval = pcim_enable_device(pdev); if (retval) { dev_err(&pdev->dev, "PCI enable failed\n"); - goto err; + goto err_zero; } /* io address */ ioaddress = pci_resource_start(pdev, 2); retval = pci_request_region(pdev, 2, "mxser(IO)"); if (retval) - goto err_dis; + goto err_zero; - brd->info = &mxser_cards[ent->driver_data]; - for (i = 0; i < brd->info->nports; i++) + brd->nports = nports; + for (i = 0; i < nports; i++) brd->ports[i].ioaddr = ioaddress + 8 * i; /* vector */ @@ -2606,53 +1919,23 @@ static int mxser_probe(struct pci_dev *pdev, /* irq */ brd->irq = pdev->irq; - brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr); - brd->uart_type = PORT_16550A; - brd->vector_mask = 0; - - for (i = 0; i < brd->info->nports; i++) { - for (j = 0; j < UART_INFO_NUM; j++) { - if (Gpci_uart_info[j].type == brd->chip_flag) { - brd->ports[i].max_baud = - Gpci_uart_info[j].max_baud; - - /* exception....CP-102 */ - if (brd->info->flags & MXSER_HIGHBAUD) - brd->ports[i].max_baud = 921600; - break; - } - } - } - - if (brd->chip_flag == MOXA_MUST_MU860_HWID) { - for (i = 0; i < brd->info->nports; i++) { - if (i < 4) - brd->ports[i].opmode_ioaddr = ioaddress + 4; - else - brd->ports[i].opmode_ioaddr = ioaddress + 0x0c; - } - outb(0, ioaddress + 4); /* default set to RS232 mode */ - outb(0, ioaddress + 0x0c); /* default set to RS232 mode */ - } + mxser_initbrd(brd, ent->driver_data & MXSER_HIGHBAUD); - for (i = 0; i < brd->info->nports; i++) { - brd->vector_mask |= (1 << i); - brd->ports[i].baud_base = 921600; + retval = devm_request_irq(&pdev->dev, brd->irq, mxser_interrupt, + IRQF_SHARED, "mxser", brd); + if (retval) { + dev_err(&pdev->dev, "request irq failed"); + goto err_relbrd; } - /* mxser_initbrd will hook ISR. */ - retval = mxser_initbrd(brd); - if (retval) - goto err_rel3; - - for (i = 0; i < brd->info->nports; i++) { + for (i = 0; i < nports; i++) { tty_dev = tty_port_register_device(&brd->ports[i].port, - mxvar_sdriver, brd->idx + i, &pdev->dev); + mxvar_sdriver, base + i, &pdev->dev); if (IS_ERR(tty_dev)) { retval = PTR_ERR(tty_dev); for (; i > 0; i--) tty_unregister_device(mxvar_sdriver, - brd->idx + i - 1); + base + i - 1); goto err_relbrd; } } @@ -2661,35 +1944,25 @@ static int mxser_probe(struct pci_dev *pdev, return 0; err_relbrd: - for (i = 0; i < brd->info->nports; i++) + for (i = 0; i < nports; i++) tty_port_destroy(&brd->ports[i].port); - free_irq(brd->irq, brd); -err_rel3: - pci_release_region(pdev, 3); err_zero: - brd->info = NULL; - pci_release_region(pdev, 2); -err_dis: - pci_disable_device(pdev); + __clear_bit(brd->idx, mxser_boards); err: return retval; -#else - return -ENODEV; -#endif } static void mxser_remove(struct pci_dev *pdev) { -#ifdef CONFIG_PCI struct mxser_board *brd = pci_get_drvdata(pdev); + unsigned int i, base = brd->idx * MXSER_PORTS_PER_BOARD; - mxser_board_remove(brd); + for (i = 0; i < brd->nports; i++) { + tty_unregister_device(mxvar_sdriver, base + i); + tty_port_destroy(&brd->ports[i].port); + } - pci_release_region(pdev, 2); - pci_release_region(pdev, 3); - pci_disable_device(pdev); - brd->info = NULL; -#endif + __clear_bit(brd->idx, mxser_boards); } static struct pci_driver mxser_driver = { @@ -2701,18 +1974,12 @@ static struct pci_driver mxser_driver = { static int __init mxser_module_init(void) { - struct mxser_board *brd; - struct device *tty_dev; - unsigned int b, i, m; int retval; - mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); + mxvar_sdriver = alloc_tty_driver(MXSER_PORTS); if (!mxvar_sdriver) return -ENOMEM; - printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", - MXSER_VERSION); - /* Initialize the tty_driver structure */ mxvar_sdriver->name = "ttyMI"; mxvar_sdriver->major = ttymajor; @@ -2731,57 +1998,10 @@ static int __init mxser_module_init(void) goto err_put; } - /* Start finding ISA boards here */ - for (m = 0, b = 0; b < MXSER_BOARDS; b++) { - if (!ioaddr[b]) - continue; - - brd = &mxser_boards[m]; - retval = mxser_get_ISA_conf(ioaddr[b], brd); - if (retval <= 0) { - brd->info = NULL; - continue; - } - - printk(KERN_INFO "mxser: found MOXA %s board (CAP=0x%lx)\n", - brd->info->name, ioaddr[b]); - - /* mxser_initbrd will hook ISR. */ - if (mxser_initbrd(brd) < 0) { - mxser_release_ISA_res(brd); - brd->info = NULL; - continue; - } - - brd->idx = m * MXSER_PORTS_PER_BOARD; - for (i = 0; i < brd->info->nports; i++) { - tty_dev = tty_port_register_device(&brd->ports[i].port, - mxvar_sdriver, brd->idx + i, NULL); - if (IS_ERR(tty_dev)) { - for (; i > 0; i--) - tty_unregister_device(mxvar_sdriver, - brd->idx + i - 1); - for (i = 0; i < brd->info->nports; i++) - tty_port_destroy(&brd->ports[i].port); - free_irq(brd->irq, brd); - mxser_release_ISA_res(brd); - brd->info = NULL; - break; - } - } - if (brd->info == NULL) - continue; - - m++; - } - retval = pci_register_driver(&mxser_driver); if (retval) { printk(KERN_ERR "mxser: can't register pci driver\n"); - if (!m) { - retval = -ENODEV; - goto err_unr; - } /* else: we have some ISA cards under control */ + goto err_unr; } return 0; @@ -2794,19 +2014,9 @@ err_put: static void __exit mxser_module_exit(void) { - unsigned int i; - pci_unregister_driver(&mxser_driver); - - for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */ - if (mxser_boards[i].info != NULL) - mxser_board_remove(&mxser_boards[i]); tty_unregister_driver(mxvar_sdriver); put_tty_driver(mxvar_sdriver); - - for (i = 0; i < MXSER_BOARDS; i++) - if (mxser_boards[i].info != NULL) - mxser_release_ISA_res(&mxser_boards[i]); } module_init(mxser_module_init); |