summaryrefslogtreecommitdiff
path: root/drivers/tty/mxser.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/mxser.c')
-rw-r--r--drivers/tty/mxser.c125
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);
}