- if (port->xmit_cnt < WAKEUP_CHARS) {
- set_bit(MXSER_EVENT_TXLOW, &port->event);
- schedule_work(&port->tqueue);
- }
- if (port->xmit_cnt <= 0) {
- port->IER &= ~UART_IER_THRI;
- outb(port->IER, port->ioaddr + UART_IER);
- }
-unlock:
- spin_unlock_irqrestore(&port->slock, flags);
-}
-
-static void mxser_check_modem_status(struct mxser_port *port, int status)
-{
- /* update input line counters */
- if (status & UART_MSR_TERI)
- port->icount.rng++;
- if (status & UART_MSR_DDSR)
- port->icount.dsr++;
- if (status & UART_MSR_DDCD)
- port->icount.dcd++;
- if (status & UART_MSR_DCTS)
- port->icount.cts++;
- port->mon_data.modem_status = status;
- wake_up_interruptible(&port->delta_msr_wait);
-
- 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) {
- if (port->tty->hw_stopped) {
- if (status & UART_MSR_CTS) {
- port->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);
- }
- set_bit(MXSER_EVENT_TXLOW, &port->event);
- schedule_work(&port->tqueue);
- }
- } else {
- if (!(status & UART_MSR_CTS)) {
- port->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);
- }
- }
- }
- }
-}
-
-static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, struct mxser_port *port)
-{
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0;
- unsigned long flags;
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
- port->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, port->count is dropped by one, so that
- * mxser_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&port->open_wait, &wait);
-
- spin_lock_irqsave(&port->slock, flags);
- if (!tty_hung_up_p(filp))
- port->count--;
- spin_unlock_irqrestore(&port->slock, flags);
- port->blocked_open++;
- while (1) {
- spin_lock_irqsave(&port->slock, flags);
- outb(inb(port->ioaddr + UART_MCR) |
- UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
- spin_unlock_irqrestore(&port->slock, flags);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
- if (port->flags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
- break;
- }
- if (!(port->flags & ASYNC_CLOSING) &&
- (do_clocal ||
- (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&port->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- port->count++;
- port->blocked_open--;
- if (retval)
- return retval;
- port->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
-static int mxser_startup(struct mxser_port *info)
-{
- unsigned long page;
- unsigned long flags;
-
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
-
- spin_lock_irqsave(&info->slock, flags);
-
- if (info->flags & ASYNC_INITIALIZED) {
- free_page(page);
- spin_unlock_irqrestore(&info->slock, flags);
- return 0;
- }
-
- if (!info->ioaddr || !info->type) {
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- free_page(page);
- spin_unlock_irqrestore(&info->slock, flags);
- return 0;
- }
- if (info->xmit_buf)
- free_page(page);
- else
- info->xmit_buf = (unsigned char *) page;
-
- /*
- * Clear the FIFO buffers and disable them
- * (they will be reenabled in mxser_change_speed())
- */
- 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
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
- info->ioaddr + UART_FCR);
-
- /*
- * At this point there's no way the LSR could still be 0xFF;
- * if it is, then bail out, because there's likely no UART
- * here.
- */
- if (inb(info->ioaddr + UART_LSR) == 0xff) {
- spin_unlock_irqrestore(&info->slock, flags);
- if (capable(CAP_SYS_ADMIN)) {
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- return 0;
- } else
- return -ENODEV;
- }
-
- /*
- * Clear the interrupt registers.
- */
- (void) inb(info->ioaddr + UART_LSR);
- (void) inb(info->ioaddr + UART_RX);
- (void) inb(info->ioaddr + UART_IIR);
- (void) inb(info->ioaddr + UART_MSR);
-
- /*
- * Now, initialize the UART
- */
- outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR); /* reset DLAB */
- info->MCR = UART_MCR_DTR | UART_MCR_RTS;
- outb(info->MCR, info->ioaddr + UART_MCR);
-
- /*
- * 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 clear the interrupt registers again for luck.
- */
- (void) inb(info->ioaddr + UART_LSR);
- (void) inb(info->ioaddr + UART_RX);
- (void) inb(info->ioaddr + UART_IIR);
- (void) inb(info->ioaddr + UART_MSR);
-
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- /*
- * and set the speed of the serial port
- */
- spin_unlock_irqrestore(&info->slock, flags);
- mxser_change_speed(info, NULL);
-
- info->flags |= ASYNC_INITIALIZED;
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts maybe disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void mxser_shutdown(struct mxser_port *info)
-{
- unsigned long flags;
-
- if (!(info->flags & ASYNC_INITIALIZED))
- return;
-
- spin_lock_irqsave(&info->slock, flags);
-
- /*
- * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
- * here so the queue might never be waken up
- */
- wake_up_interruptible(&info->delta_msr_wait);
-
- /*
- * Free the IRQ, if necessary
- */
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = NULL;
- }
-
- info->IER = 0;
- outb(0x00, info->ioaddr + UART_IER);
-
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
- info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
- 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);
-
- /* read data port to reset things */
- (void) inb(info->ioaddr + UART_RX);
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- 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);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static int mxser_change_speed(struct mxser_port *info,
- struct termios *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;
- cflag = info->tty->termios->c_cflag;
- if (!(info->ioaddr))
- return ret;
-
-#ifndef B921600
-#define B921600 (B460800 +1)
-#endif
- if (mxser_set_baud_method[info->tty->index] == 0) {
- baud = tty_get_baud_rate(info->tty);
- mxser_set_baud(info, baud);
- }
-
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5:
- cval = 0x00;
- break;
- case CS6:
- cval = 0x01;
- break;
- case CS7:
- cval = 0x02;
- break;
- case CS8:
- cval = 0x03;
- break;
- default:
- cval = 0x00;
- break; /* too keep GCC shut... */
- }
- if (cflag & CSTOPB)
- cval |= 0x04;
- if (cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD))
- cval |= UART_LCR_EPAR;
- if (cflag & CMSPAR)
- cval |= UART_LCR_SPAR;
-
- if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
- if (info->board->chip_flag) {
- fcr = UART_FCR_ENABLE_FIFO;
- fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
- } else
- 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;
- break;
- case 4:
- fcr |= UART_FCR_TRIGGER_4;
- break;
- case 8:
- fcr |= UART_FCR_TRIGGER_8;
- break;
- default:
- fcr |= UART_FCR_TRIGGER_14;
- break;
- }
- }
- }
-
- /* CTS flow control flag and modem status interrupts */
- info->IER &= ~UART_IER_MSI;
- info->MCR &= ~UART_MCR_AFE;
- if (cflag & CRTSCTS) {
- info->flags |= ASYNC_CTS_FLOW;
- 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;
- 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);
- }
- set_bit(MXSER_EVENT_TXLOW, &info->event);
- schedule_work(&info->tqueue); }
- } else {
- if (!(status & UART_MSR_CTS)) {
- info->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);
- }
- }
- }
- }
- } else {
- info->flags &= ~ASYNC_CTS_FLOW;
- }
- outb(info->MCR, info->ioaddr + UART_MCR);
- if (cflag & CLOCAL) {
- info->flags &= ~ASYNC_CHECK_CD;
- } else {
- info->flags |= ASYNC_CHECK_CD;
- info->IER |= UART_IER_MSI;
- }
- outb(info->IER, info->ioaddr + UART_IER);
-
- /*
- * Set up parity check flag
- */
- info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (I_INPCK(info->tty))
- info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
- info->read_status_mask |= UART_LSR_BI;
-
- info->ignore_status_mask = 0;
-
- if (I_IGNBRK(info->tty)) {
- info->ignore_status_mask |= UART_LSR_BI;
- info->read_status_mask |= UART_LSR_BI;
- /*
- * If we're ignore parity and break indicators, ignore
- * overruns too. (For real raw support).
- */
- if (I_IGNPAR(info->tty)) {
- info->ignore_status_mask |=
- UART_LSR_OE |
- UART_LSR_PE |
- UART_LSR_FE;
- info->read_status_mask |=
- UART_LSR_OE |
- UART_LSR_PE |
- 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)) {
- ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
- } else {
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
- }
- if (I_IXOFF(info->tty)) {
- ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
- } 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 */
- outb(cval, info->ioaddr + UART_LCR);
-
- return ret;
-}
-
-
-static int mxser_set_baud(struct mxser_port *info, long newspd)
-{
- int quot = 0;
- unsigned char cval;
- int ret = 0;
- unsigned long flags;
-
- if (!info->tty || !info->tty->termios)
- return ret;
-
- if (!(info->ioaddr))
- return ret;
-
- if (newspd > info->max_baud)
- 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;
- } 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;
- }
-
- cval = inb(info->ioaddr + UART_LCR);
-
- outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR); /* set DLAB */
-
- outb(quot & 0xff, info->ioaddr + UART_DLL); /* LS of divisor */
- outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */
- outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */
-