Commit 530646f4 authored by Alan Cox's avatar Alan Cox Committed by Greg Kroah-Hartman

sdio_uart: refcount the tty objects

The tty can go away underneath us, so we must refcount it. Do the naïve
implementation initially. We will worry about startup shortly.
Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 0395b48c
...@@ -172,8 +172,13 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port) ...@@ -172,8 +172,13 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
sdio_claim_host(func); sdio_claim_host(func);
port->func = NULL; port->func = NULL;
mutex_unlock(&port->func_lock); mutex_unlock(&port->func_lock);
if (port->opened) if (port->opened) {
tty_hangup(port->port.tty); struct tty_struct *tty = tty_port_tty_get(&port->port);
/* tty_hangup is async so is this safe as is ?? */
if (tty)
tty_hangup(tty);
tty_kref_put(tty);
}
mutex_unlock(&port->open_lock); mutex_unlock(&port->open_lock);
sdio_release_irq(func); sdio_release_irq(func);
sdio_disable_func(func); sdio_disable_func(func);
...@@ -392,7 +397,7 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port) ...@@ -392,7 +397,7 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
static void sdio_uart_receive_chars(struct sdio_uart_port *port, static void sdio_uart_receive_chars(struct sdio_uart_port *port,
unsigned int *status) unsigned int *status)
{ {
struct tty_struct *tty = port->port.tty; struct tty_struct *tty = tty_port_tty_get(&port->port);
unsigned int ch, flag; unsigned int ch, flag;
int max_count = 256; int max_count = 256;
...@@ -429,6 +434,7 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, ...@@ -429,6 +434,7 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
} }
if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
if (tty)
tty_insert_flip_char(tty, ch, flag); tty_insert_flip_char(tty, ch, flag);
/* /*
...@@ -436,18 +442,22 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, ...@@ -436,18 +442,22 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
* it doesn't affect the current character. * it doesn't affect the current character.
*/ */
if (*status & ~port->ignore_status_mask & UART_LSR_OE) if (*status & ~port->ignore_status_mask & UART_LSR_OE)
if (tty)
tty_insert_flip_char(tty, 0, TTY_OVERRUN); tty_insert_flip_char(tty, 0, TTY_OVERRUN);
*status = sdio_in(port, UART_LSR); *status = sdio_in(port, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0)); } while ((*status & UART_LSR_DR) && (max_count-- > 0));
if (tty) {
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
tty_kref_put(tty);
}
} }
static void sdio_uart_transmit_chars(struct sdio_uart_port *port) static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
{ {
struct circ_buf *xmit = &port->xmit; struct circ_buf *xmit = &port->xmit;
int count; int count;
struct tty_struct *tty = port->port.tty; struct tty_struct *tty;
if (port->x_char) { if (port->x_char) {
sdio_out(port, UART_TX, port->x_char); sdio_out(port, UART_TX, port->x_char);
...@@ -455,8 +465,12 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) ...@@ -455,8 +465,12 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
port->x_char = 0; port->x_char = 0;
return; return;
} }
if (circ_empty(xmit) || tty->stopped || tty->hw_stopped) {
tty = tty_port_tty_get(&port->port);
if (tty == NULL || circ_empty(xmit) || tty->stopped || tty->hw_stopped) {
sdio_uart_stop_tx(port); sdio_uart_stop_tx(port);
tty_kref_put(tty);
return; return;
} }
...@@ -474,12 +488,13 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) ...@@ -474,12 +488,13 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
if (circ_empty(xmit)) if (circ_empty(xmit))
sdio_uart_stop_tx(port); sdio_uart_stop_tx(port);
tty_kref_put(tty);
} }
static void sdio_uart_check_modem_status(struct sdio_uart_port *port) static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
{ {
int status; int status;
struct tty_struct *tty = port->port.tty; struct tty_struct *tty;
status = sdio_in(port, UART_MSR); status = sdio_in(port, UART_MSR);
...@@ -494,7 +509,8 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) ...@@ -494,7 +509,8 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
port->icount.dcd++; port->icount.dcd++;
if (status & UART_MSR_DCTS) { if (status & UART_MSR_DCTS) {
port->icount.cts++; port->icount.cts++;
if (tty->termios->c_cflag & CRTSCTS) { tty = tty_port_tty_get(&port->port);
if (tty && (tty->termios->c_cflag & CRTSCTS)) {
int cts = (status & UART_MSR_CTS); int cts = (status & UART_MSR_CTS);
if (tty->hw_stopped) { if (tty->hw_stopped) {
if (cts) { if (cts) {
...@@ -509,6 +525,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) ...@@ -509,6 +525,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
} }
} }
} }
tty_kref_put(tty);
} }
} }
...@@ -548,8 +565,10 @@ static void sdio_uart_irq(struct sdio_func *func) ...@@ -548,8 +565,10 @@ static void sdio_uart_irq(struct sdio_func *func)
static int sdio_uart_startup(struct sdio_uart_port *port) static int sdio_uart_startup(struct sdio_uart_port *port)
{ {
unsigned long page; unsigned long page;
int ret; int ret = -ENOMEM;
struct tty_struct *tty = port->port.tty; struct tty_struct *tty = tty_port_tty_get(&port->port);
/* FIXME: What if it is NULL ?? */
/* /*
* Set the TTY IO error marker - we will only clear this * Set the TTY IO error marker - we will only clear this
...@@ -560,7 +579,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port) ...@@ -560,7 +579,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
/* Initialise and allocate the transmit buffer. */ /* Initialise and allocate the transmit buffer. */
page = __get_free_page(GFP_KERNEL); page = __get_free_page(GFP_KERNEL);
if (!page) if (!page)
return -ENOMEM; goto err0;
port->xmit.buf = (unsigned char *)page; port->xmit.buf = (unsigned char *)page;
circ_clear(&port->xmit); circ_clear(&port->xmit);
...@@ -614,6 +633,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port) ...@@ -614,6 +633,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
sdio_uart_irq(port->func); sdio_uart_irq(port->func);
sdio_uart_release_func(port); sdio_uart_release_func(port);
tty_kref_put(tty);
return 0; return 0;
err3: err3:
...@@ -622,12 +642,15 @@ err2: ...@@ -622,12 +642,15 @@ err2:
sdio_uart_release_func(port); sdio_uart_release_func(port);
err1: err1:
free_page((unsigned long)port->xmit.buf); free_page((unsigned long)port->xmit.buf);
err0:
tty_kref_put(tty);
return ret; return ret;
} }
static void sdio_uart_shutdown(struct sdio_uart_port *port) static void sdio_uart_shutdown(struct sdio_uart_port *port)
{ {
int ret; int ret;
struct tty_struct *tty;
ret = sdio_uart_claim_func(port); ret = sdio_uart_claim_func(port);
if (ret) if (ret)
...@@ -637,9 +660,11 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port) ...@@ -637,9 +660,11 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)
/* TODO: wait here for TX FIFO to drain */ /* TODO: wait here for TX FIFO to drain */
tty = tty_port_tty_get(&port->port);
/* Turn off DTR and RTS early. */ /* Turn off DTR and RTS early. */
if (port->port.tty->termios->c_cflag & HUPCL) if (tty && (tty->termios->c_cflag & HUPCL))
sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
tty_kref_put(tty);
/* Disable interrupts from this port */ /* Disable interrupts from this port */
sdio_release_irq(port->func); sdio_release_irq(port->func);
...@@ -688,11 +713,11 @@ static int sdio_uart_open(struct tty_struct *tty, struct file *filp) ...@@ -688,11 +713,11 @@ static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
if (!port->opened) { if (!port->opened) {
tty->driver_data = port; tty->driver_data = port;
port->port.tty = tty; tty_port_tty_set(&port->port, tty);
ret = sdio_uart_startup(port); ret = sdio_uart_startup(port);
if (ret) { if (ret) {
tty->driver_data = NULL; tty->driver_data = NULL;
port->port.tty = NULL; tty_port_tty_set(&port->port, NULL);
mutex_unlock(&port->open_lock); mutex_unlock(&port->open_lock);
sdio_uart_port_put(port); sdio_uart_port_put(port);
return ret; return ret;
...@@ -727,7 +752,7 @@ static void sdio_uart_close(struct tty_struct *tty, struct file * filp) ...@@ -727,7 +752,7 @@ static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
tty->closing = 1; tty->closing = 1;
sdio_uart_shutdown(port); sdio_uart_shutdown(port);
tty_ldisc_flush(tty); tty_ldisc_flush(tty);
port->port.tty = NULL; tty_port_tty_set(&port->port, NULL);
tty->driver_data = NULL; tty->driver_data = NULL;
tty->closing = 0; tty->closing = 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment