#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_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
#define MXSER_ISR_PASS_LIMIT 99999L
#define MXSER_ERR_IOADDR -1
#define MXSER_ERR_IRQ_CONFLIT -3
#define MXSER_ERR_VECTOR -4
-#define SERIAL_TYPE_NORMAL 1
-#define SERIAL_TYPE_CALLOUT 2
-
#define WAKEUP_CHARS 256
#define UART_MCR_AFE 0x20
int xmit_tail;
int xmit_cnt;
- struct termios normal_termios;
- struct termios callout_termios;
+ struct ktermios normal_termios;
+ struct ktermios callout_termios;
struct mxser_mon mon_data;
};
struct mxser_board {
- struct pci_dev *pdev; /* temporary (until pci probing) */
-
+ unsigned int idx;
int irq;
const struct mxser_cardinfo *info;
unsigned long vector;
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 int mxser_set_baud_method[MXSER_PORTS + 1];
static spinlock_t gm_lock;
+#ifdef CONFIG_PCI
static int CheckIsMoxaMust(int io)
{
u8 oldmcr, 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_)
+static void mxser_do_softint(struct work_struct *work)
{
- struct mxser_port *info = private_;
- struct tty_struct *tty;
-
- tty = info->tty;
+ struct mxser_port *info = container_of(work, struct mxser_port, tqueue);
+ struct tty_struct *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)
* 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;
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;
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));
} 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 */
* 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 */
/*
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);
}
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);
/*
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);
}
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);
static int mxser_program_mode(int port)
{
int id, i, j, n;
- /* unsigned long flags; */
spin_lock(&gm_lock);
outb(0, port);
(void)inb(port);
outb(0, port);
(void)inb(port);
- /* restore_flags(flags); */
spin_unlock(&gm_lock);
id = inb(port + 1) & 0x1F;
continue;
status = mxser_get_msr(port->ioaddr, 0, i);
-/* mxser_check_modem_status(port, status); */
if (status & UART_MSR_TERI)
port->icount.rng++;
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 != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
test_bit(TTY_IO_ERROR, &tty->flags))
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))
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;
}
}
-/* 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.
*/
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;
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;
+ }
+ }
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;
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;
}
if (port->xmit_buf == 0)
goto unlock;
- 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;
} 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) {
/*
* 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;
unsigned int int_cnt;
int handled = IRQ_NONE;
- /* spin_lock(&gm_lock); */
-
for (i = 0; i < MXSER_BOARDS; i++)
if (dev_id == &mxser_boards[i]) {
brd = dev_id;
int_cnt = 0;
do {
- /* following add by Victor Yu. 09-13-2002 */
iir = inb(port->ioaddr + UART_IIR);
if (iir & UART_IIR_NO_INT)
break;
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);
}
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->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;
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);
+ INIT_WORK(&info->tqueue, mxser_do_softint);
info->normal_termios = mxvar_sdriver->init_termios;
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
"conflict with another device.\n",
brd->info->name, brd->irq);
/* We hold resources, we need to release them. */
- mxser_release_res(brd, 0);
+ mxser_release_res(brd, pdev, 0);
return retval;
}
return 0;
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);
return brd->info->nports;
}
-static int __init mxser_get_PCI_conf(const struct pci_device_id *ent,
- 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->info = &mxser_cards[ent->driver_data];
ioaddress = pci_resource_start(pdev, 2);
retval = pci_request_region(pdev, 2, "mxser(IO)");
if (retval)
goto err;
+ brd->info = &mxser_cards[ent->driver_data];
for (i = 0; i < brd->info->nports; i++)
brd->ports[i].ioaddr = ioaddress + 8 * i;
brd->vector_mask |= (1 << i);
brd->ports[i].baud_base = 921600;
}
+
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(brd, pdev) < 0)
+ goto err_relvec;
+
+ 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_relvec:
+ pci_release_region(pdev, 3);
err_relio:
pci_release_region(pdev, 2);
+ 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);
}
+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");
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->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
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 "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)
- continue;
-
- for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver,
- m * MXSER_PORTS_PER_BOARD + i, NULL);
-
- m++;
- }
-
- /* 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_cards[mxser_pcibrds[b].driver_data].name,
- 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(&mxser_pcibrds[b],
- 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");
+ if (mxser_initbrd(brd, NULL) < 0) {
+ brd->info = NULL;
continue;
}
- /* mxser_initbrd will hook ISR. */
- if (mxser_initbrd(brd) < 0)
- continue;
+
+ brd->idx = m * MXSER_PORTS_PER_BOARD;
for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver,
- m * MXSER_PORTS_PER_BOARD + i,
- &pdev->dev);
+ tty_register_device(mxvar_sdriver, brd->idx + i,
+ NULL);
m++;
- /* Keep an extra reference if we succeeded. It will
- be returned at unload time */
- pci_dev_get(pdev);
}
- }
- if (!m) {
- retval = -ENODEV;
- goto err_unr;
+ retval = pci_register_driver(&mxser_driver);
+ if (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");
static void __exit mxser_module_exit(void)
{
- unsigned int i;
+ unsigned int i, j;
pr_debug("Unloading module mxser ...\n");
- for (i = 0; i < MXSER_PORTS; i++)
- tty_unregister_device(mxvar_sdriver, i);
+ 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].info != NULL)
- mxser_release_res(&mxser_boards[i], 1);
+ mxser_release_res(&mxser_boards[i], NULL, 1);
pr_debug("Done.\n");
}