* mxser.c -- MOXA Smartio/Industio family multiport serial driver.
*
* Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com.tw).
- * Copyright (C) 2006 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (C) 2006-2007 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
#include <linux/gfp.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/pci.h>
+#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/bitops.h>
#include <asm/uaccess.h>
#include "mxser_new.h"
-#define MXSER_VERSION "2.0"
+#define MXSER_VERSION "2.0.2" /* 1.10 */
#define MXSERMAJOR 174
#define MXSERCUMAJOR 175
-#define MXSER_EVENT_TXLOW 1
-#define MXSER_EVENT_HANGUP 2
-
#define MXSER_BOARDS 4 /* Max. boards */
-#define MXSER_PORTS 32 /* Max. ports */
#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
-#define MXSER_ISR_PASS_LIMIT 99999L
+#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
+#define MXSER_ISR_PASS_LIMIT 100
#define MXSER_ERR_IOADDR -1
#define MXSER_ERR_IRQ -2
#define MXSER_ERR_IRQ_CONFLIT -3
#define MXSER_ERR_VECTOR -4
-#define SERIAL_TYPE_NORMAL 1
-#define SERIAL_TYPE_CALLOUT 2
+/*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 RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
- IXON|IXOFF))
+#define PCI_DEVICE_ID_CB108 0x1080
+#define PCI_DEVICE_ID_CB114 0x1142
+#define PCI_DEVICE_ID_CB134I 0x1341
+#define PCI_DEVICE_ID_CP138U 0x1380
+#define PCI_DEVICE_ID_POS104UL 0x1044
+
#define C168_ASIC_ID 1
#define C104_ASIC_ID 2
#define CI134_ASIC_ID 3
#define CI104J_ASIC_ID 5
-enum {
- MXSER_BOARD_C168_ISA = 1,
- MXSER_BOARD_C104_ISA,
- MXSER_BOARD_CI104J,
- MXSER_BOARD_C168_PCI,
- MXSER_BOARD_C104_PCI,
- MXSER_BOARD_C102_ISA,
- MXSER_BOARD_CI132,
- MXSER_BOARD_CI134,
- MXSER_BOARD_CP132,
- MXSER_BOARD_CP114,
- MXSER_BOARD_CT114,
- MXSER_BOARD_CP102,
- MXSER_BOARD_CP104U,
- MXSER_BOARD_CP168U,
- MXSER_BOARD_CP132U,
- MXSER_BOARD_CP134U,
- MXSER_BOARD_CP104JU,
- MXSER_BOARD_RC7000,
- MXSER_BOARD_CP118U,
- MXSER_BOARD_CP102UL,
- MXSER_BOARD_CP102U,
- MXSER_BOARD_CP118EL,
- MXSER_BOARD_CP168EL,
- MXSER_BOARD_CP104EL
-};
-
-static char *mxser_brdname[] = {
- "C168 series",
- "C104 series",
- "CI-104J series",
- "C168H/PCI series",
- "C104H/PCI series",
- "C102 series",
- "CI-132 series",
- "CI-134 series",
- "CP-132 series",
- "CP-114 series",
- "CT-114 series",
- "CP-102 series",
- "CP-104U series",
- "CP-168U series",
- "CP-132U series",
- "CP-134U series",
- "CP-104JU series",
- "Moxa UC7000 Serial",
- "CP-118U series",
- "CP-102UL series",
- "CP-102U series",
- "CP-118EL series",
- "CP-168EL series",
- "CP-104EL series"
-};
-
-static int mxser_numports[] = {
- 8, /* C168-ISA */
- 4, /* C104-ISA */
- 4, /* CI104J */
- 8, /* C168-PCI */
- 4, /* C104-PCI */
- 2, /* C102-ISA */
- 2, /* CI132 */
- 4, /* CI134 */
- 2, /* CP132 */
- 4, /* CP114 */
- 4, /* CT114 */
- 2, /* CP102 */
- 4, /* CP104U */
- 8, /* CP168U */
- 2, /* CP132U */
- 4, /* CP134U */
- 4, /* CP104JU */
- 8, /* RC7000 */
- 8, /* CP118U */
- 2, /* CP102UL */
- 2, /* CP102U */
- 8, /* CP118EL */
- 8, /* CP168EL */
- 4 /* CP104EL */
-};
-
-#define UART_TYPE_NUM 2
-
-static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
- MOXA_MUST_MU150_HWID,
- MOXA_MUST_MU860_HWID
-};
+#define MXSER_HIGHBAUD 1
+#define MXSER_HAS2 2
/* This is only for PCI */
-#define UART_INFO_NUM 3
-struct mxpciuart_info {
+static const struct {
int type;
int tx_fifo;
int rx_fifo;
int rx_trigger;
int rx_low_water;
long max_baud;
-};
-
-static const struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = {
+} 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}
};
+#define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info)
+
+struct mxser_cardinfo {
+ unsigned int nports;
+ char *name;
+ unsigned int flags;
+};
+
+static const struct mxser_cardinfo mxser_cards[] = {
+/* 0*/ { 8, "C168 series", },
+ { 4, "C104 series", },
+ { 4, "CI-104J series", },
+ { 8, "C168H/PCI series", },
+ { 4, "C104H/PCI series", },
+/* 5*/ { 4, "C102 series", MXSER_HAS2 }, /* C102-ISA */
+ { 4, "CI-132 series", MXSER_HAS2 },
+ { 4, "CI-134 series", },
+ { 2, "CP-132 series", },
+ { 4, "CP-114 series", },
+/*10*/ { 4, "CT-114 series", },
+ { 2, "CP-102 series", MXSER_HIGHBAUD },
+ { 4, "CP-104U series", },
+ { 8, "CP-168U series", },
+ { 2, "CP-132U series", },
+/*15*/ { 4, "CP-134U series", },
+ { 4, "CP-104JU series", },
+ { 8, "Moxa UC7000 Serial", }, /* RC7000 */
+ { 8, "CP-118U series", },
+ { 2, "CP-102UL series", },
+/*20*/ { 2, "CP-102U series", },
+ { 8, "CP-118EL series", },
+ { 8, "CP-168EL series", },
+ { 4, "CP-104EL series", },
+ { 8, "CB-108 series", },
+/*25*/ { 4, "CB-114 series", },
+ { 4, "CB-134I series", },
+ { 8, "CP-138U series", },
+ { 4, "POS-104UL series", }
+};
+/* driver_data correspond to the lines in the structure above
+ see also ISA probe function before you change something */
static struct pci_device_id mxser_pcibrds[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168),
- .driver_data = MXSER_BOARD_C168_PCI },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104),
- .driver_data = MXSER_BOARD_C104_PCI },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132),
- .driver_data = MXSER_BOARD_CP132 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114),
- .driver_data = MXSER_BOARD_CP114 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114),
- .driver_data = MXSER_BOARD_CT114 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102),
- .driver_data = MXSER_BOARD_CP102 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U),
- .driver_data = MXSER_BOARD_CP104U },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U),
- .driver_data = MXSER_BOARD_CP168U },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U),
- .driver_data = MXSER_BOARD_CP132U },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U),
- .driver_data = MXSER_BOARD_CP134U },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU),
- .driver_data = MXSER_BOARD_CP104JU },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000),
- .driver_data = MXSER_BOARD_RC7000 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U),
- .driver_data = MXSER_BOARD_CP118U },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL),
- .driver_data = MXSER_BOARD_CP102UL },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U),
- .driver_data = MXSER_BOARD_CP102U },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL),
- .driver_data = MXSER_BOARD_CP118EL },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL),
- .driver_data = MXSER_BOARD_CP168EL },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL),
- .driver_data = MXSER_BOARD_CP104EL },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 },
+ { 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 },
{ }
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
+static int mxvar_baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
+};
+static unsigned int mxvar_baud_table1[] = {
+ 0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400,
+ B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600
+};
+#define BAUD_TABLE_NO ARRAY_SIZE(mxvar_baud_table)
+
+#define B_SPEC B2000000
+
static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
static int ttymajor = MXSERMAJOR;
static int calloutmajor = MXSERCUMAJOR;
long realbaud;
int type; /* UART type */
int flags; /* defined in tty.h */
- long session; /* Session of opening process */
- long pgrp; /* pgrp of opening process */
+ int speed;
int x_char; /* xon/xoff character */
int IER; /* Interrupt Enable Register */
int xmit_tail;
int xmit_cnt;
- struct termios normal_termios;
- struct termios callout_termios;
+ struct ktermios normal_termios;
struct mxser_mon mon_data;
spinlock_t slock;
- struct work_struct tqueue;
wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
wait_queue_head_t delta_msr_wait;
};
struct mxser_board {
- struct pci_dev *pdev; /* temporary (until pci probing) */
-
+ unsigned int idx;
int irq;
- int board_type;
- unsigned int nports;
+ const struct mxser_cardinfo *info;
unsigned long vector;
unsigned long vector_mask;
static struct mxser_board mxser_boards[MXSER_BOARDS];
static struct tty_driver *mxvar_sdriver;
-static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
-static struct termios *mxvar_termios[MXSER_PORTS + 1];
-static struct termios *mxvar_termios_locked[MXSER_PORTS + 1];
static struct mxser_log mxvar_log;
static int mxvar_diagflag;
static unsigned char mxser_msr[MXSER_PORTS + 1];
static struct mxser_mon_ext mon_data_ext;
static int mxser_set_baud_method[MXSER_PORTS + 1];
-static spinlock_t gm_lock;
-static int CheckIsMoxaMust(int io)
+#ifdef CONFIG_PCI
+static int __devinit CheckIsMoxaMust(int io)
{
u8 oldmcr, hwid;
int i;
}
GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
- for (i = 0; i < UART_TYPE_NUM; i++) {
- if (hwid == Gmoxa_uart_id[i])
+ for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
+ if (hwid == Gpci_uart_info[i].type)
return (int)hwid;
}
return MOXA_OTHER_UART;
}
-
-/* above is modified by Victor Yu. 08-15-2002 */
+#endif
static void process_txrx_fifo(struct mxser_port *info)
{
}
}
-static void mxser_do_softint(void *private_)
-{
- struct mxser_port *info = private_;
- struct tty_struct *tty;
-
- tty = info->tty;
-
- if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event))
- tty_wakeup(tty);
- if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event))
- tty_hangup(tty);
-}
-
static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
{
unsigned char status = 0;
static int mxser_set_baud(struct mxser_port *info, long newspd)
{
+ unsigned int i;
int quot = 0;
unsigned char cval;
int ret = 0;
- unsigned long flags;
if (!info->tty || !info->tty->termios)
return ret;
return 0;
info->realbaud = newspd;
- if (newspd == 134) {
- quot = (2 * info->baud_base / 269);
- } else if (newspd) {
- quot = info->baud_base / newspd;
- if (quot == 0)
- quot = 1;
+ for (i = 0; i < BAUD_TABLE_NO; i++)
+ if (newspd == mxvar_baud_table[i])
+ break;
+ if (i == BAUD_TABLE_NO) {
+ quot = info->baud_base / info->speed;
+ if (info->speed <= 0 || info->speed > info->max_baud)
+ quot = 0;
} else {
- quot = 0;
+ if (newspd == 134) {
+ quot = (2 * info->baud_base / 269);
+ } else if (newspd) {
+ quot = info->baud_base / newspd;
+ if (quot == 0)
+ quot = 1;
+ } else {
+ quot = 0;
+ }
}
info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
info->timeout += HZ / 50; /* Add .02 seconds of slop */
if (quot) {
- spin_lock_irqsave(&info->slock, flags);
info->MCR |= UART_MCR_DTR;
outb(info->MCR, info->ioaddr + UART_MCR);
- spin_unlock_irqrestore(&info->slock, flags);
} else {
- spin_lock_irqsave(&info->slock, flags);
info->MCR &= ~UART_MCR_DTR;
outb(info->MCR, info->ioaddr + UART_MCR);
- spin_unlock_irqrestore(&info->slock, flags);
return ret;
}
outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */
outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */
+ if (i == BAUD_TABLE_NO) {
+ quot = info->baud_base % info->speed;
+ quot *= 8;
+ if ((quot % info->speed) > (info->speed / 2)) {
+ quot /= info->speed;
+ quot++;
+ } else {
+ quot /= info->speed;
+ }
+ SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot);
+ } else
+ SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0);
return ret;
}
* the specified baud rate for a serial port.
*/
static int mxser_change_speed(struct mxser_port *info,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
unsigned cflag, cval, fcr;
int ret = 0;
unsigned char status;
long baud;
- unsigned long flags;
if (!info->tty || !info->tty->termios)
return ret;
return ret;
if (mxser_set_baud_method[info->tty->index] == 0) {
- baud = tty_get_baud_rate(info->tty);
+ if ((cflag & CBAUD) == B_SPEC)
+ baud = info->speed;
+ else
+ baud = tty_get_baud_rate(info->tty);
mxser_set_baud(info, baud);
}
fcr = 0;
} else {
fcr = UART_FCR_ENABLE_FIFO;
- /* following add by Victor Yu. 08-30-2002 */
if (info->board->chip_flag) {
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
SET_MOXA_MUST_FIFO_VALUE(info);
} else {
- /* above add by Victor Yu. 08-30-2002 */
switch (info->rx_trigger) {
case 1:
fcr |= UART_FCR_TRIGGER_1;
info->IER |= UART_IER_MSI;
if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
info->MCR |= UART_MCR_AFE;
-/* status = mxser_get_msr(info->ioaddr, 0, info->port); */
-/*
- save_flags(flags);
- cli();
- status = inb(baseaddr + UART_MSR);
- restore_flags(flags);
-*/
- /* mxser_check_modem_status(info, status); */
} else {
-/* status = mxser_get_msr(info->ioaddr, 0, info->port); */
- /* MX_LOCK(&info->slock); */
status = inb(info->ioaddr + UART_MSR);
- /* MX_UNLOCK(&info->slock); */
if (info->tty->hw_stopped) {
if (status & UART_MSR_CTS) {
info->tty->hw_stopped = 0;
outb(info->IER, info->ioaddr +
UART_IER);
}
- set_bit(MXSER_EVENT_TXLOW, &info->event);
- schedule_work(&info->tqueue); }
+ tty_wakeup(info->tty);
+ }
} else {
if (!(status & UART_MSR_CTS)) {
info->tty->hw_stopped = 1;
UART_LSR_FE;
}
}
- /* following add by Victor Yu. 09-02-2002 */
if (info->board->chip_flag) {
- spin_lock_irqsave(&info->slock, flags);
SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
if (I_IXON(info->tty)) {
} else {
DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
}
- /*
- if ( I_IXANY(info->tty) ) {
- info->MCR |= MOXA_MUST_MCR_XON_ANY;
- ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->ioaddr);
- } else {
- info->MCR &= ~MOXA_MUST_MCR_XON_ANY;
- DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->ioaddr);
- }
- */
- spin_unlock_irqrestore(&info->slock, flags);
}
- /* above add by Victor Yu. 09-02-2002 */
outb(fcr, info->ioaddr + UART_FCR); /* set fcr */
if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
if (status & UART_MSR_DCD)
wake_up_interruptible(&port->open_wait);
- schedule_work(&port->tqueue);
}
if (port->flags & ASYNC_CTS_FLOW) {
outb(port->IER, port->ioaddr +
UART_IER);
}
- set_bit(MXSER_EVENT_TXLOW, &port->event);
- schedule_work(&port->tqueue);
+ tty_wakeup(port->tty);
}
} else {
if (!(status & UART_MSR_CTS)) {
* Finally, enable interrupts
*/
info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
- /* info->IER = UART_IER_RLSI | UART_IER_RDI; */
- /* following add by Victor Yu. 08-30-2002 */
if (info->board->chip_flag)
info->IER |= MOXA_MUST_IER_EGDAI;
- /* above add by Victor Yu. 08-30-2002 */
outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */
/*
/*
* and set the speed of the serial port
*/
- spin_unlock_irqrestore(&info->slock, flags);
mxser_change_speed(info, NULL);
-
info->flags |= ASYNC_INITIALIZED;
+ spin_unlock_irqrestore(&info->slock, flags);
+
return 0;
}
outb(info->MCR, info->ioaddr + UART_MCR);
/* clear Rx/Tx FIFO's */
- /* following add by Victor Yu. 08-30-2002 */
if (info->board->chip_flag)
outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
MOXA_MUST_FCR_GDA_MODE_ENABLE,
info->ioaddr + UART_FCR);
else
- /* above add by Victor Yu. 08-30-2002 */
outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
info->ioaddr + UART_FCR);
info->flags &= ~ASYNC_INITIALIZED;
- /* following add by Victor Yu. 09-23-2002 */
if (info->board->chip_flag)
SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
- /* above add by Victor Yu. 09-23-2002 */
spin_unlock_irqrestore(&info->slock, flags);
}
static int mxser_open(struct tty_struct *tty, struct file *filp)
{
struct mxser_port *info;
+ unsigned long flags;
int retval, line;
- /* initialize driver_data in case something fails */
- tty->driver_data = NULL;
-
line = tty->index;
if (line == MXSER_PORTS)
return 0;
/*
* Start up serial port
*/
+ spin_lock_irqsave(&info->slock, flags);
info->count++;
+ spin_unlock_irqrestore(&info->slock, flags);
retval = mxser_startup(info);
if (retval)
return retval;
if (retval)
return retval;
- if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
- if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
- *tty->termios = info->normal_termios;
- else
- *tty->termios = info->callout_termios;
- mxser_change_speed(info, NULL);
- }
-
- info->session = process_session(current);
- info->pgrp = process_group(current);
-
- /*
- status = mxser_get_msr(info->base, 0, info->port);
- mxser_check_modem_status(info, status);
- */
-
-/* unmark here for very high baud rate (ex. 921600 bps) used */
+ /* unmark here for very high baud rate (ex. 921600 bps) used */
tty->low_latency = 1;
return 0;
}
info->IER &= ~UART_IER_RLSI;
if (info->board->chip_flag)
info->IER &= ~MOXA_MUST_RECV_ISR;
-/* by William
- info->read_status_mask &= ~UART_LSR_DR;
-*/
+
if (info->flags & ASYNC_INITIALIZED) {
outb(info->IER, info->ioaddr + UART_IER);
/*
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
-
}
static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
total += c;
}
- if (info->xmit_cnt && !tty->stopped
- /*&& !(info->IER & UART_IER_THRI)*/) {
+ if (info->xmit_cnt && !tty->stopped) {
if (!tty->hw_stopped ||
(info->type == PORT_16550A) ||
(info->board->chip_flag)) {
info->xmit_head &= SERIAL_XMIT_SIZE - 1;
info->xmit_cnt++;
spin_unlock_irqrestore(&info->slock, flags);
- if (!tty->stopped /*&& !(info->IER & UART_IER_THRI)*/) {
+ if (!tty->stopped) {
if (!tty->hw_stopped ||
(info->type == PORT_16550A) ||
info->board->chip_flag) {
static int mxser_chars_in_buffer(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
- int len = info->xmit_cnt;
-
- if (!(inb(info->ioaddr + UART_LSR) & UART_LSR_THRE))
- len++;
-
- return len;
+ return info->xmit_cnt;
}
static void mxser_flush_buffer(struct tty_struct *tty)
spin_lock_irqsave(&info->slock, flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- /* below added by shinhay */
fcr = inb(info->ioaddr + UART_FCR);
outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
info->ioaddr + UART_FCR);
outb(fcr, info->ioaddr + UART_FCR);
spin_unlock_irqrestore(&info->slock, flags);
- /* above added by shinhay */
tty_wakeup(tty);
}
struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
+ unsigned long sl_flags;
unsigned int flags;
int retval = 0;
info->closing_wait = new_serial.closing_wait * HZ / 100;
info->tty->low_latency =
(info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- info->tty->low_latency = 0; /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */
+ info->tty->low_latency = 0;
}
- /* added by casper, 3/17/2000, for mouse */
info->type = new_serial.type;
process_txrx_fifo(info);
if (info->flags & ASYNC_INITIALIZED) {
- if (flags != (info->flags & ASYNC_SPD_MASK))
+ if (flags != (info->flags & ASYNC_SPD_MASK)) {
+ spin_lock_irqsave(&info->slock, sl_flags);
mxser_change_speed(info, NULL);
+ spin_unlock_irqrestore(&info->slock, sl_flags);
+ }
} else
retval = mxser_startup(info);
return 0;
}
-static int mxser_program_mode(int port)
+static int __init mxser_program_mode(int port)
{
int id, i, j, n;
- /* unsigned long flags; */
- spin_lock(&gm_lock);
outb(0, port);
outb(0, port);
outb(0, port);
(void)inb(port);
outb(0, port);
(void)inb(port);
- /* restore_flags(flags); */
- spin_unlock(&gm_lock);
id = inb(port + 1) & 0x1F;
if ((id != C168_ASIC_ID) &&
return id;
}
-static void mxser_normal_mode(int port)
+static void __init mxser_normal_mode(int port)
{
int i, n;
#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 mxser_read_register(int port, unsigned short *regs)
+static int __init mxser_read_register(int port, unsigned short *regs)
{
int i, k, value, id;
unsigned int j;
return -EFAULT;
return 0;
case MOXA_ASPP_MON_EXT: {
- int status, p, shiftbit;
+ int p, shiftbit;
unsigned long opmode;
unsigned cflag, iflag;
continue;
status = mxser_get_msr(port->ioaddr, 0, i);
-/* mxser_check_modem_status(port, status); */
if (status & UART_MSR_TERI)
port->icount.rng++;
struct serial_icounter_struct __user *p_cuser;
unsigned long templ;
unsigned long flags;
+ unsigned int i;
void __user *argp = (void __user *)arg;
int retval;
if (tty->index == MXSER_PORTS)
return mxser_ioctl_special(cmd, argp);
- /* following add by Victor Yu. 01-05-2004 */
if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
int p;
unsigned long opmode;
}
return 0;
}
- /* above add by Victor Yu. 01-05-2004 */
+
+ if (cmd == MOXA_SET_SPECIAL_BAUD_RATE) {
+ int speed;
+
+ if (get_user(speed, (int __user *)argp))
+ return -EFAULT;
+ if (speed <= 0 || speed > info->max_baud)
+ return -EFAULT;
+ if (!info->tty || !info->tty->termios || !info->ioaddr)
+ return 0;
+ info->tty->termios->c_cflag &= ~(CBAUD | CBAUDEX);
+ for (i = 0; i < BAUD_TABLE_NO; i++)
+ if (speed == mxvar_baud_table[i])
+ break;
+ if (i == BAUD_TABLE_NO) {
+ info->tty->termios->c_cflag |= B_SPEC;
+ } else if (speed != 0)
+ info->tty->termios->c_cflag |= mxvar_baud_table1[i];
+
+ info->speed = speed;
+ spin_lock_irqsave(&info->slock, flags);
+ mxser_change_speed(info, NULL);
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ return 0;
+ } else if (cmd == MOXA_GET_SPECIAL_BAUD_RATE) {
+ if (copy_to_user(argp, &info->speed, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ }
if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
test_bit(TTY_IO_ERROR, &tty->flags))
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was
*/
- case TIOCMIWAIT: {
- DECLARE_WAITQUEUE(wait, current);
- int ret;
+ case TIOCMIWAIT:
spin_lock_irqsave(&info->slock, flags);
- cprev = info->icount; /* note the counters on entry */
+ cnow = info->icount; /* note the counters on entry */
spin_unlock_irqrestore(&info->slock, flags);
- add_wait_queue(&info->delta_msr_wait, &wait);
- while (1) {
+ wait_event_interruptible(info->delta_msr_wait, ({
+ cprev = cnow;
spin_lock_irqsave(&info->slock, flags);
cnow = info->icount; /* atomic copy */
spin_unlock_irqrestore(&info->slock, flags);
- set_current_state(TASK_INTERRUPTIBLE);
- if (((arg & TIOCM_RNG) &&
- (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) &&
- (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) &&
- (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) &&
- (cnow.cts != cprev.cts))) {
- ret = 0;
- break;
- }
- /* see if a signal did it */
- if (signal_pending(current)) {
- ret = -ERESTARTSYS;
- break;
- }
- cprev = cnow;
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->delta_msr_wait, &wait);
+ ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
+ }));
break;
- }
- /* NOTREACHED */
/*
* Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
* Return: write counters to the user passed counter struct
cnow = info->icount;
spin_unlock_irqrestore(&info->slock, flags);
p_cuser = argp;
- /* modified by casper 1/11/2000 */
if (put_user(cnow.frame, &p_cuser->frame))
return -EFAULT;
if (put_user(cnow.brk, &p_cuser->brk))
info->mon_data.rxcnt = 0;
info->mon_data.txcnt = 0;
return 0;
-/* (above) added by James. */
case MOXA_ASPP_SETBAUD:{
long baud;
if (get_user(baud, (long __user *)argp))
return -EFAULT;
+ spin_lock_irqsave(&info->slock, flags);
mxser_set_baud(info, baud);
+ spin_unlock_irqrestore(&info->slock, flags);
return 0;
}
case MOXA_ASPP_GETBAUD:
case MOXA_ASPP_MON: {
int mcr, status;
- /* info->mon_data.ser_param = tty->termios->c_cflag; */
-
status = mxser_get_msr(info->ioaddr, 1, tty->index);
mxser_check_modem_status(info, status);
info->ldisc_stop_rx = 1;
if (I_IXOFF(tty)) {
- /* following add by Victor Yu. 09-02-2002 */
if (info->board->chip_flag) {
info->IER &= ~MOXA_MUST_RECV_ISR;
outb(info->IER, info->ioaddr + UART_IER);
- } else if (!(info->flags & ASYNC_CLOSING)) {
+ } else {
info->x_char = STOP_CHAR(tty);
outb(0, info->ioaddr + UART_IER);
info->IER |= UART_IER_THRI;
if (info->x_char)
info->x_char = 0;
else {
- /* following add by Victor Yu. 09-02-2002 */
if (info->board->chip_flag) {
info->IER |= MOXA_MUST_RECV_ISR;
outb(info->IER, info->ioaddr + UART_IER);
- } else if (!(info->flags & ASYNC_CLOSING)) {
+ } else {
info->x_char = START_CHAR(tty);
outb(0, info->ioaddr + UART_IER);
info->IER |= UART_IER_THRI;
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
- if (info->xmit_cnt && info->xmit_buf
- /* && !(info->IER & UART_IER_THRI) */) {
+ if (info->xmit_cnt && info->xmit_buf) {
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);
}
-static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct mxser_port *info = tty->driver_data;
unsigned long flags;
- if ((tty->termios->c_cflag != old_termios->c_cflag) ||
- (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
-
- mxser_change_speed(info, old_termios);
+ spin_lock_irqsave(&info->slock, flags);
+ mxser_change_speed(info, old_termios);
+ spin_unlock_irqrestore(&info->slock, flags);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- mxser_start(tty);
- }
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ mxser_start(tty);
}
-/* Handle sw stopped */
+ /* Handle sw stopped */
if ((old_termios->c_iflag & IXON) &&
!(tty->termios->c_iflag & IXON)) {
tty->stopped = 0;
- /* following add by Victor Yu. 09-02-2002 */
if (info->board->chip_flag) {
spin_lock_irqsave(&info->slock, flags);
DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
spin_unlock_irqrestore(&info->slock, flags);
}
- /* above add by Victor Yu. 09-02-2002 */
mxser_start(tty);
}
#endif
}
-
/*
* This routine is called by tty_hangup() when a hangup is signaled.
*/
-void mxser_hangup(struct tty_struct *tty)
+static void mxser_hangup(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
wake_up_interruptible(&info->open_wait);
}
-
-/* added by James 03-12-2004. */
/*
* mxser_rs_break() --- routine which turns the break handling on or off
*/
spin_unlock_irqrestore(&info->slock, flags);
}
-/* (above) added by James. */
-
static void mxser_receive_chars(struct mxser_port *port, int *status)
{
struct tty_struct *tty = port->tty;
int cnt = 0;
int recv_room;
int max = 256;
- unsigned long flags;
-
- spin_lock_irqsave(&port->slock, flags);
recv_room = tty->receive_room;
- if ((recv_room == 0) && (!port->ldisc_stop_rx)) {
- /* mxser_throttle(tty); */
+ if ((recv_room == 0) && (!port->ldisc_stop_rx))
mxser_stoprx(tty);
- /* return; */
- }
- /* following add by Victor Yu. 09-02-2002 */
if (port->board->chip_flag != MOXA_OTHER_UART) {
if (*status & UART_LSR_SPECIAL)
goto intr_old;
- /* following add by Victor Yu. 02-11-2004 */
if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
(*status & MOXA_MUST_LSR_RERR))
goto intr_old;
- /* above add by Victor Yu. 02-14-2004 */
if (*status & MOXA_MUST_LSR_RERR)
goto intr_old;
gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
- /* add by Victor Yu. 02-11-2004 */
if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
gdl &= MOXA_MUST_GDL_MASK;
if (gdl >= recv_room) {
- if (!port->ldisc_stop_rx) {
- /* mxser_throttle(tty); */
+ if (!port->ldisc_stop_rx)
mxser_stoprx(tty);
- }
- /* return; */
}
while (gdl--) {
ch = inb(port->ioaddr + UART_RX);
}
goto end_intr;
}
- intr_old:
- /* above add by Victor Yu. 09-02-2002 */
+intr_old:
do {
if (max-- < 0)
break;
ch = inb(port->ioaddr + UART_RX);
- /* following add by Victor Yu. 09-02-2002 */
- if (port->board->chip_flag && (*status & UART_LSR_OE)
- /*&& !(*status&UART_LSR_DR) */)
+ if (port->board->chip_flag && (*status & UART_LSR_OE))
outb(0x23, port->ioaddr + UART_FCR);
*status &= port->read_status_mask;
- /* above add by Victor Yu. 09-02-2002 */
if (*status & port->ignore_status_mask) {
if (++ignored > 100)
break;
if (*status & UART_LSR_SPECIAL) {
if (*status & UART_LSR_BI) {
flag = TTY_BREAK;
-/* added by casper 1/11/2000 */
port->icount.brk++;
if (port->flags & ASYNC_SAK)
do_SAK(tty);
} else if (*status & UART_LSR_PE) {
flag = TTY_PARITY;
-/* added by casper 1/11/2000 */
port->icount.parity++;
} else if (*status & UART_LSR_FE) {
flag = TTY_FRAME;
-/* added by casper 1/11/2000 */
port->icount.frame++;
} else if (*status & UART_LSR_OE) {
flag = TTY_OVERRUN;
-/* added by casper 1/11/2000 */
port->icount.overrun++;
} else
- flags = TTY_BREAK;
- } else
- flags = 0;
+ flag = TTY_BREAK;
+ }
tty_insert_flip_char(tty, ch, flag);
cnt++;
if (cnt >= recv_room) {
- if (!port->ldisc_stop_rx) {
- /* mxser_throttle(tty); */
+ if (!port->ldisc_stop_rx)
mxser_stoprx(tty);
- }
break;
}
}
- /* following add by Victor Yu. 09-02-2002 */
if (port->board->chip_flag)
break;
- /* mask by Victor Yu. 09-02-2002
- *status = inb(port->ioaddr + UART_LSR) & port->read_status_mask;
- */
- /* following add by Victor Yu. 09-02-2002 */
*status = inb(port->ioaddr + UART_LSR);
- /* above add by Victor Yu. 09-02-2002 */
} while (*status & UART_LSR_DR);
-end_intr: /* add by Victor Yu. 09-02-2002 */
+end_intr:
mxvar_log.rxcnt[port->tty->index] += cnt;
port->mon_data.rxcnt += cnt;
port->mon_data.up_rxcnt += cnt;
- spin_unlock_irqrestore(&port->slock, flags);
+ /*
+ * We are called from an interrupt context with &port->slock
+ * being held. Drop it temporarily in order to prevent
+ * recursive locking.
+ */
+ spin_unlock(&port->slock);
tty_flip_buffer_push(tty);
+ spin_lock(&port->slock);
}
static void mxser_transmit_chars(struct mxser_port *port)
{
int count, cnt;
- unsigned long flags;
-
- spin_lock_irqsave(&port->slock, flags);
if (port->x_char) {
outb(port->x_char, port->ioaddr + UART_TX);
mxvar_log.txcnt[port->tty->index]++;
port->mon_data.txcnt++;
port->mon_data.up_txcnt++;
-
-/* added by casper 1/11/2000 */
port->icount.tx++;
- goto unlock;
+ return;
}
if (port->xmit_buf == 0)
- goto unlock;
+ return;
- if (port->xmit_cnt == 0) {
- if (port->xmit_cnt < WAKEUP_CHARS) { /* XXX what's this for?? */
- set_bit(MXSER_EVENT_TXLOW, &port->event);
- schedule_work(&port->tqueue);
- }
- goto unlock;
- }
- if (port->tty->stopped || (port->tty->hw_stopped &&
+ if ((port->xmit_cnt <= 0) || port->tty->stopped ||
+ (port->tty->hw_stopped &&
(port->type != PORT_16550A) &&
(!port->board->chip_flag))) {
port->IER &= ~UART_IER_THRI;
outb(port->IER, port->ioaddr + UART_IER);
- goto unlock;
+ return;
}
cnt = port->xmit_cnt;
} while (--count > 0);
mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt);
-/* added by James 03-12-2004. */
port->mon_data.txcnt += (cnt - port->xmit_cnt);
port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
-
-/* added by casper 1/11/2000 */
port->icount.tx += (cnt - port->xmit_cnt);
- if (port->xmit_cnt < WAKEUP_CHARS) {
- set_bit(MXSER_EVENT_TXLOW, &port->event);
- schedule_work(&port->tqueue);
- }
+ if (port->xmit_cnt < WAKEUP_CHARS)
+ tty_wakeup(port->tty);
+
if (port->xmit_cnt <= 0) {
port->IER &= ~UART_IER_THRI;
outb(port->IER, port->ioaddr + UART_IER);
}
-unlock:
- spin_unlock_irqrestore(&port->slock, flags);
}
/*
* This is the serial driver's generic interrupt routine
*/
-static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mxser_interrupt(int irq, void *dev_id)
{
int status, iir, i;
struct mxser_board *brd = NULL;
struct mxser_port *port;
int max, irqbits, bits, msr;
- int pass_counter = 0;
- unsigned int int_cnt;
+ unsigned int int_cnt, pass_counter = 0;
int handled = IRQ_NONE;
- /* spin_lock(&gm_lock); */
-
for (i = 0; i < MXSER_BOARDS; i++)
if (dev_id == &mxser_boards[i]) {
brd = dev_id;
goto irq_stop;
if (brd == NULL)
goto irq_stop;
- max = mxser_numports[brd->board_type - 1];
- while (1) {
+ max = brd->info->nports;
+ while (pass_counter++ < MXSER_ISR_PASS_LIMIT) {
irqbits = inb(brd->vector) & brd->vector_mask;
if (irqbits == brd->vector_mask)
break;
port = &brd->ports[i];
int_cnt = 0;
+ spin_lock(&port->slock);
do {
- /* following add by Victor Yu. 09-13-2002 */
iir = inb(port->ioaddr + UART_IIR);
if (iir & UART_IIR_NO_INT)
break;
iir &= MOXA_MUST_IIR_MASK;
- if (!port->tty) {
+ if (!port->tty ||
+ (port->flags & ASYNC_CLOSING) ||
+ !(port->flags &
+ ASYNC_INITIALIZED)) {
status = inb(port->ioaddr + UART_LSR);
outb(0x27, port->ioaddr + UART_FCR);
inb(port->ioaddr + UART_MSR);
break;
}
- /* above add by Victor Yu. 09-13-2002 */
- /* following add by Victor Yu. 09-02-2002 */
status = inb(port->ioaddr + UART_LSR);
if (status & UART_LSR_PE)
port->err_shadow |= NPPI_NOTIFY_BREAK;
if (port->board->chip_flag) {
- /*
- if ( (status & 0x02) && !(status & 0x01) ) {
- outb(port->ioaddr+UART_FCR, 0x23);
- continue;
- }
- */
if (iir == MOXA_MUST_IIR_GDA ||
iir == MOXA_MUST_IIR_RDA ||
iir == MOXA_MUST_IIR_RTO ||
&status);
} else {
- /* above add by Victor Yu. 09-02-2002 */
-
status &= port->read_status_mask;
if (status & UART_LSR_DR)
mxser_receive_chars(port,
if (msr & UART_MSR_ANY_DELTA)
mxser_check_modem_status(port, msr);
- /* following add by Victor Yu. 09-13-2002 */
if (port->board->chip_flag) {
if (iir == 0x02 && (status &
UART_LSR_THRE))
mxser_transmit_chars(port);
} else {
- /* above add by Victor Yu. 09-13-2002 */
-
if (status & UART_LSR_THRE)
mxser_transmit_chars(port);
}
} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
+ spin_unlock(&port->slock);
}
- if (pass_counter++ > MXSER_ISR_PASS_LIMIT)
- break; /* Prevent infinite loops */
}
- irq_stop:
- /* spin_unlock(&gm_lock); */
+irq_stop:
return handled;
}
* The MOXA Smartio/Industio serial driver boot-time initialization code!
*/
-static void mxser_release_res(struct mxser_board *brd, unsigned int irq)
+static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
+ unsigned int irq)
{
- struct pci_dev *pdev = brd->pdev;
-
if (irq)
free_irq(brd->irq, brd);
if (pdev != NULL) { /* PCI */
+#ifdef CONFIG_PCI
pci_release_region(pdev, 2);
pci_release_region(pdev, 3);
- pci_dev_put(pdev);
+#endif
} else {
- release_region(brd->ports[0].ioaddr, 8 * brd->nports);
+ release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
release_region(brd->vector, 1);
}
}
-static int __devinit mxser_initbrd(struct mxser_board *brd)
+static int __devinit mxser_initbrd(struct mxser_board *brd,
+ struct pci_dev *pdev)
{
struct mxser_port *info;
unsigned int i;
printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud);
- for (i = 0; i < brd->nports; i++) {
+ for (i = 0; i < brd->info->nports; i++) {
info = &brd->ports[i];
info->board = brd;
info->stop_rx = 0;
info->custom_divisor = info->baud_base * 16;
info->close_delay = 5 * HZ / 10;
info->closing_wait = 30 * HZ;
- INIT_WORK(&info->tqueue, mxser_do_softint, info);
info->normal_termios = mxvar_sdriver->init_termios;
init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
init_waitqueue_head(&info->delta_msr_wait);
+ info->speed = 9600;
memset(&info->mon_data, 0, sizeof(struct mxser_mon));
info->err_shadow = 0;
spin_lock_init(&info->slock);
outb(inb(info->ioaddr + UART_IER) & 0xf0,
info->ioaddr + UART_IER);
}
- /*
- * Allocate the IRQ if necessary
- */
- retval = request_irq(brd->irq, mxser_interrupt,
- (brd->ports[0].flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED :
- IRQF_DISABLED, "mxser", brd);
+ retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
+ brd);
if (retval) {
printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
"conflict with another device.\n",
- mxser_brdname[brd->board_type - 1], brd->irq);
+ brd->info->name, brd->irq);
/* We hold resources, we need to release them. */
- mxser_release_res(brd, 0);
- return retval;
+ mxser_release_res(brd, pdev, 0);
}
- return 0;
+ return retval;
}
static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
brd->chip_flag = MOXA_OTHER_UART;
id = mxser_read_register(cap, regs);
- if (id == C168_ASIC_ID) {
- brd->board_type = MXSER_BOARD_C168_ISA;
- brd->nports = 8;
- } else if (id == C104_ASIC_ID) {
- brd->board_type = MXSER_BOARD_C104_ISA;
- brd->nports = 4;
- } else if (id == C102_ASIC_ID) {
- brd->board_type = MXSER_BOARD_C102_ISA;
- brd->nports = 2;
- } else if (id == CI132_ASIC_ID) {
- brd->board_type = MXSER_BOARD_CI132;
- brd->nports = 2;
- } else if (id == CI134_ASIC_ID) {
- brd->board_type = MXSER_BOARD_CI134;
- brd->nports = 4;
- } else if (id == CI104J_ASIC_ID) {
- brd->board_type = MXSER_BOARD_CI104J;
- brd->nports = 4;
- } else
+ 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;
- if (brd->nports == 2) {
+ /* 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))
return MXSER_ERR_IRQ_CONFLIT;
- } else if (brd->nports == 4) {
+ } else if (brd->info->nports == 4) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
if (irq != regs[9])
return MXSER_ERR_IRQ_CONFLIT;
- } else if (brd->nports == 8) {
+ } else if (brd->info->nports == 8) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
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; /* add by Victor Yu. 09-04-2002 */
+ brd->ports[i].max_baud = 921600;
} else {
brd->ports[i].baud_base = 115200;
- brd->ports[i].max_baud = 115200; /* add by Victor Yu. 09-04-2002 */
+ brd->ports[i].max_baud = 115200;
}
}
scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
brd->uart_type = PORT_16550A;
else
brd->uart_type = PORT_16450;
- if (id == 1)
- brd->nports = 8;
- else
- brd->nports = 4;
- if (!request_region(brd->ports[0].ioaddr, 8 * brd->nports, "mxser(IO)"))
+ if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
+ "mxser(IO)"))
return MXSER_ERR_IOADDR;
if (!request_region(brd->vector, 1, "mxser(vector)")) {
- release_region(brd->ports[0].ioaddr, 8 * brd->nports);
+ release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
return MXSER_ERR_VECTOR;
}
- return brd->nports;
+ return brd->info->nports;
}
-static int __init mxser_get_PCI_conf(int board_type, struct mxser_board *brd,
- struct pci_dev *pdev)
+static int __devinit mxser_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
+#ifdef CONFIG_PCI
+ struct mxser_board *brd;
unsigned int i, j;
unsigned long ioaddress;
- int retval;
+ int retval = -EINVAL;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (mxser_boards[i].info == NULL)
+ break;
+
+ if (i >= MXSER_BOARDS) {
+ printk(KERN_ERR "Too many Smartio/Industio family boards found "
+ "(maximum %d), board not configured\n", MXSER_BOARDS);
+ goto err;
+ }
+
+ brd = &mxser_boards[i];
+ brd->idx = i * MXSER_PORTS_PER_BOARD;
+ printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
+ mxser_cards[ent->driver_data].name,
+ pdev->bus->number, PCI_SLOT(pdev->devfn));
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+ goto err;
+ }
/* io address */
- brd->board_type = board_type;
- brd->nports = mxser_numports[board_type - 1];
ioaddress = pci_resource_start(pdev, 2);
retval = pci_request_region(pdev, 2, "mxser(IO)");
if (retval)
goto err;
- for (i = 0; i < brd->nports; i++)
+ brd->info = &mxser_cards[ent->driver_data];
+ for (i = 0; i < brd->info->nports; i++)
brd->ports[i].ioaddr = ioaddress + 8 * i;
/* vector */
brd->uart_type = PORT_16550A;
brd->vector_mask = 0;
- for (i = 0; i < brd->nports; i++) {
+ 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 (board_type == MXSER_BOARD_CP102)
+ 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->nports; i++) {
+ for (i = 0; i < brd->info->nports; i++) {
if (i < 4)
brd->ports[i].opmode_ioaddr = ioaddress + 4;
else
outb(0, ioaddress + 0x0c); /* default set to RS232 mode */
}
- for (i = 0; i < brd->nports; i++) {
+ for (i = 0; i < brd->info->nports; i++) {
brd->vector_mask |= (1 << i);
brd->ports[i].baud_base = 921600;
}
+
+ /* mxser_initbrd will hook ISR. */
+ retval = mxser_initbrd(brd, pdev);
+ if (retval)
+ goto err_null;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+
+ pci_set_drvdata(pdev, brd);
+
return 0;
err_relio:
pci_release_region(pdev, 2);
+err_null:
+ brd->info = NULL;
err:
return retval;
+#else
+ return -ENODEV;
+#endif
+}
+
+static void __devexit mxser_remove(struct pci_dev *pdev)
+{
+ struct mxser_board *brd = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_unregister_device(mxvar_sdriver, brd->idx + i);
+
+ mxser_release_res(brd, pdev, 1);
+ brd->info = NULL;
}
+static struct pci_driver mxser_driver = {
+ .name = "mxser",
+ .id_table = mxser_pcibrds,
+ .probe = mxser_probe,
+ .remove = __devexit_p(mxser_remove)
+};
+
static int __init mxser_module_init(void)
{
- struct pci_dev *pdev = NULL;
struct mxser_board *brd;
unsigned long cap;
unsigned int i, m, isaloop;
- int retval, b, n;
+ int retval, b;
pr_debug("Loading module mxser ...\n");
mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
if (!mxvar_sdriver)
return -ENOMEM;
- spin_lock_init(&gm_lock);
-
- for (i = 0; i < MXSER_BOARDS; i++)
- mxser_boards[i].board_type = -1;
printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
MXSER_VERSION);
/* Initialize the tty_driver structure */
+ mxvar_sdriver->owner = THIS_MODULE;
mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
- mxvar_sdriver->name = "ttyM";
+ mxvar_sdriver->name = "ttyMI";
mxvar_sdriver->major = ttymajor;
mxvar_sdriver->minor_start = 0;
mxvar_sdriver->num = MXSER_PORTS + 1;
mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
mxvar_sdriver->init_termios = tty_std_termios;
mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
- mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
+ mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(mxvar_sdriver, &mxser_ops);
- mxvar_sdriver->ttys = mxvar_tty;
- mxvar_sdriver->termios = mxvar_termios;
- mxvar_sdriver->termios_locked = mxvar_termios_locked;
+
+ retval = tty_register_driver(mxvar_sdriver);
+ if (retval) {
+ printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family "
+ "tty driver !\n");
+ goto err_put;
+ }
mxvar_diagflag = 0;
if (retval != 0)
printk(KERN_INFO "Found MOXA %s board "
"(CAP=0x%x)\n",
- mxser_brdname[brd->board_type - 1],
- ioaddr[b]);
+ brd->info->name, ioaddr[b]);
if (retval <= 0) {
if (retval == MXSER_ERR_IRQ)
printk(KERN_ERR "Invalid I/O address, "
"board not configured\n");
+ brd->info = NULL;
continue;
}
- brd->pdev = NULL;
-
/* mxser_initbrd will hook ISR. */
- if (mxser_initbrd(brd) < 0)
+ if (mxser_initbrd(brd, NULL) < 0) {
+ brd->info = NULL;
continue;
+ }
- m++;
- }
+ brd->idx = m * MXSER_PORTS_PER_BOARD;
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i,
+ NULL);
- /* start finding PCI board here */
- n = ARRAY_SIZE(mxser_pcibrds) - 1;
- b = 0;
- while (b < n) {
- pdev = pci_get_device(mxser_pcibrds[b].vendor,
- mxser_pcibrds[b].device, pdev);
- if (pdev == NULL) {
- b++;
- continue;
- }
- printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
- mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1],
- pdev->bus->number, PCI_SLOT(pdev->devfn));
- if (m >= MXSER_BOARDS)
- printk(KERN_ERR
- "Too many Smartio/Industio family boards find "
- "(maximum %d), board not configured\n",
- MXSER_BOARDS);
- else {
- if (pci_enable_device(pdev)) {
- printk(KERN_ERR "Moxa SmartI/O PCI enable "
- "fail !\n");
- continue;
- }
- brd = &mxser_boards[m];
- brd->pdev = pdev;
- retval = mxser_get_PCI_conf(
- (int)mxser_pcibrds[b].driver_data,
- brd, pdev);
- if (retval < 0) {
- if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR
- "Invalid interrupt number, "
- "board not configured\n");
- else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR
- "Invalid interrupt number, "
- "board not configured\n");
- else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR
- "Invalid interrupt vector, "
- "board not configured\n");
- else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR
- "Invalid I/O address, "
- "board not configured\n");
- continue;
- }
- /* mxser_initbrd will hook ISR. */
- if (mxser_initbrd(brd) < 0)
- continue;
m++;
- /* Keep an extra reference if we succeeded. It will
- be returned at unload time */
- pci_dev_get(pdev);
}
- }
- retval = tty_register_driver(mxvar_sdriver);
+ retval = pci_register_driver(&mxser_driver);
if (retval) {
- printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family"
- " driver !\n");
- put_tty_driver(mxvar_sdriver);
-
- for (i = 0; i < MXSER_BOARDS; i++)
- if (mxser_boards[i].board_type != -1)
- mxser_release_res(&mxser_boards[i], 1);
- return retval;
+ printk(KERN_ERR "Can't register pci driver\n");
+ if (!m) {
+ retval = -ENODEV;
+ goto err_unr;
+ } /* else: we have some ISA cards under control */
}
pr_debug("Done.\n");
+ return 0;
+err_unr:
+ tty_unregister_driver(mxvar_sdriver);
+err_put:
+ put_tty_driver(mxvar_sdriver);
return retval;
}
static void __exit mxser_module_exit(void)
{
- unsigned int i;
+ unsigned int i, j;
pr_debug("Unloading module mxser ...\n");
+ pci_unregister_driver(&mxser_driver);
+
+ for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
+ if (mxser_boards[i].info != NULL)
+ for (j = 0; j < mxser_boards[i].info->nports; j++)
+ tty_unregister_device(mxvar_sdriver,
+ mxser_boards[i].idx + j);
tty_unregister_driver(mxvar_sdriver);
put_tty_driver(mxvar_sdriver);
for (i = 0; i < MXSER_BOARDS; i++)
- if (mxser_boards[i].board_type != -1)
- mxser_release_res(&mxser_boards[i], 1);
+ if (mxser_boards[i].info != NULL)
+ mxser_release_res(&mxser_boards[i], NULL, 1);
pr_debug("Done.\n");
}