diff options
Diffstat (limited to 'drivers/tty/mxser.c')
-rw-r--r-- | drivers/tty/mxser.c | 125 |
1 files changed, 46 insertions, 79 deletions
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index c858aff721c4..6ebd3e4ed859 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -275,9 +275,6 @@ struct mxser_port { u8 read_status_mask; u8 ignore_status_mask; u8 xmit_fifo_size; - unsigned int xmit_head; - unsigned int xmit_tail; - unsigned int xmit_cnt; spinlock_t slock; }; @@ -591,21 +588,7 @@ static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_term } /* byte size and parity */ - switch (cflag & CSIZE) { - default: - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - case CS8: - cval = UART_LCR_WLEN8; - break; - } + cval = UART_LCR_WLEN(tty_get_char_size(tty->termios.c_cflag)); if (cflag & CSTOPB) cval |= UART_LCR_STOP; @@ -742,22 +725,21 @@ static void mxser_disable_and_clear_FIFO(struct mxser_port *info) static int mxser_activate(struct tty_port *port, struct tty_struct *tty) { struct mxser_port *info = container_of(port, struct mxser_port, port); - unsigned long page; unsigned long flags; + int ret; - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; + ret = tty_port_alloc_xmit_buf(port); + if (ret < 0) + return ret; spin_lock_irqsave(&info->slock, flags); if (!info->type) { set_bit(TTY_IO_ERROR, &tty->flags); - free_page(page); spin_unlock_irqrestore(&info->slock, flags); - return 0; + ret = 0; + goto err_free_xmit; } - info->port.xmit_buf = (unsigned char *) page; /* * Clear the FIFO buffers and disable them @@ -775,8 +757,10 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) if (capable(CAP_SYS_ADMIN)) { set_bit(TTY_IO_ERROR, &tty->flags); return 0; - } else - return -ENODEV; + } + + ret = -ENODEV; + goto err_free_xmit; } /* @@ -812,7 +796,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) (void) inb(info->ioaddr + UART_MSR); clear_bit(TTY_IO_ERROR, &tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + kfifo_reset(&port->xmit_fifo); /* * and set the speed of the serial port @@ -821,6 +805,9 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) spin_unlock_irqrestore(&info->slock, flags); return 0; +err_free_xmit: + tty_port_free_xmit_buf(port); + return ret; } /* @@ -855,14 +842,6 @@ static void mxser_shutdown_port(struct tty_port *port) */ wake_up_interruptible(&info->port.delta_msr_wait); - /* - * Free the xmit buffer, if necessary - */ - if (info->port.xmit_buf) { - free_page((unsigned long) info->port.xmit_buf); - info->port.xmit_buf = NULL; - } - info->IER = 0; outb(0x00, info->ioaddr + UART_IER); @@ -877,6 +856,11 @@ static void mxser_shutdown_port(struct tty_port *port) mxser_must_no_sw_flow_control(info->ioaddr); spin_unlock_irqrestore(&info->slock, flags); + + /* make sure ISR is not running while we free the buffer */ + synchronize_irq(info->board->irq); + + tty_port_free_xmit_buf(port); } /* @@ -900,9 +884,8 @@ static void mxser_flush_buffer(struct tty_struct *tty) struct mxser_port *info = tty->driver_data; unsigned long flags; - spin_lock_irqsave(&info->slock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + kfifo_reset(&info->port.xmit_fifo); outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, info->ioaddr + UART_FCR); @@ -919,50 +902,34 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) { - int c, total = 0; struct mxser_port *info = tty->driver_data; unsigned long flags; + int written; + bool is_empty; - while (1) { - c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - memcpy(info->port.xmit_buf + info->xmit_head, buf, c); - spin_lock_irqsave(&info->slock, flags); - info->xmit_head = (info->xmit_head + c) & - (SERIAL_XMIT_SIZE - 1); - info->xmit_cnt += c; - spin_unlock_irqrestore(&info->slock, flags); - - buf += c; - count -= c; - total += c; - } + spin_lock_irqsave(&info->slock, flags); + written = kfifo_in(&info->port.xmit_fifo, buf, count); + is_empty = kfifo_is_empty(&info->port.xmit_fifo); + spin_unlock_irqrestore(&info->slock, flags); - if (info->xmit_cnt && !tty->flow.stopped) + if (!is_empty && !tty->flow.stopped) if (!tty->hw_stopped || mxser_16550A_or_MUST(info)) mxser_start_tx(info); - return total; + return written; } static int mxser_put_char(struct tty_struct *tty, unsigned char ch) { struct mxser_port *info = tty->driver_data; unsigned long flags; - - if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) - return 0; + int ret; spin_lock_irqsave(&info->slock, flags); - info->port.xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= SERIAL_XMIT_SIZE - 1; - info->xmit_cnt++; + ret = kfifo_put(&info->port.xmit_fifo, ch); spin_unlock_irqrestore(&info->slock, flags); - return 1; + return ret; } @@ -970,7 +937,7 @@ static void mxser_flush_chars(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - if (!info->xmit_cnt || tty->flow.stopped || + if (kfifo_is_empty(&info->port.xmit_fifo) || tty->flow.stopped || (tty->hw_stopped && !mxser_16550A_or_MUST(info))) return; @@ -980,16 +947,15 @@ static void mxser_flush_chars(struct tty_struct *tty) static unsigned int mxser_write_room(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - int ret; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - return ret < 0 ? 0 : ret; + return kfifo_avail(&info->port.xmit_fifo); } static unsigned int mxser_chars_in_buffer(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - return info->xmit_cnt; + + return kfifo_len(&info->port.xmit_fifo); } /* @@ -1378,7 +1344,7 @@ static void mxser_start(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->xmit_cnt) + if (!kfifo_is_empty(&info->port.xmit_fifo)) __mxser_start_tx(info); spin_unlock_irqrestore(&info->slock, flags); } @@ -1609,7 +1575,7 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port return; } - if (!port->xmit_cnt || tty->flow.stopped || + if (kfifo_is_empty(&port->port.xmit_fifo) || tty->flow.stopped || (tty->hw_stopped && !mxser_16550A_or_MUST(port))) { __mxser_stop_tx(port); return; @@ -1617,18 +1583,19 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port count = port->xmit_fifo_size; do { - outb(port->port.xmit_buf[port->xmit_tail++], - port->ioaddr + UART_TX); - port->xmit_tail &= SERIAL_XMIT_SIZE - 1; - port->icount.tx++; - if (!--port->xmit_cnt) + unsigned char c; + + if (!kfifo_get(&port->port.xmit_fifo, &c)) break; + + outb(c, port->ioaddr + UART_TX); + port->icount.tx++; } while (--count > 0); - if (port->xmit_cnt < WAKEUP_CHARS) + if (kfifo_len(&port->port.xmit_fifo) < WAKEUP_CHARS) tty_wakeup(tty); - if (!port->xmit_cnt) + if (kfifo_is_empty(&port->port.xmit_fifo)) __mxser_stop_tx(port); } |