Skip to content

Commit

Permalink
sdio_uart: refcount the tty objects
Browse files Browse the repository at this point in the history
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: Alan Cox <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
Alan Cox authored and gregkh committed Dec 11, 2009
1 parent 0395b48 commit 530646f
Showing 1 changed file with 42 additions and 17 deletions.
59 changes: 42 additions & 17 deletions drivers/mmc/card/sdio_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,13 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
sdio_claim_host(func);
port->func = NULL;
mutex_unlock(&port->func_lock);
if (port->opened)
tty_hangup(port->port.tty);
if (port->opened) {
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);
sdio_release_irq(func);
sdio_disable_func(func);
Expand Down Expand Up @@ -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,
unsigned int *status)
{
struct tty_struct *tty = port->port.tty;
struct tty_struct *tty = tty_port_tty_get(&port->port);
unsigned int ch, flag;
int max_count = 256;

Expand Down Expand Up @@ -429,34 +434,43 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
}

if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
tty_insert_flip_char(tty, ch, flag);
if (tty)
tty_insert_flip_char(tty, ch, flag);

/*
* Overrun is special. Since it's reported immediately,
* it doesn't affect the current character.
*/
if (*status & ~port->ignore_status_mask & UART_LSR_OE)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
if (tty)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);

*status = sdio_in(port, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
tty_flip_buffer_push(tty);
if (tty) {
tty_flip_buffer_push(tty);
tty_kref_put(tty);
}
}

static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
{
struct circ_buf *xmit = &port->xmit;
int count;
struct tty_struct *tty = port->port.tty;
struct tty_struct *tty;

if (port->x_char) {
sdio_out(port, UART_TX, port->x_char);
port->icount.tx++;
port->x_char = 0;
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);
tty_kref_put(tty);
return;
}

Expand All @@ -474,12 +488,13 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)

if (circ_empty(xmit))
sdio_uart_stop_tx(port);
tty_kref_put(tty);
}

static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
{
int status;
struct tty_struct *tty = port->port.tty;
struct tty_struct *tty;

status = sdio_in(port, UART_MSR);

Expand All @@ -494,7 +509,8 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
port->icount.dcd++;
if (status & UART_MSR_DCTS) {
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);
if (tty->hw_stopped) {
if (cts) {
Expand All @@ -509,6 +525,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
}
}
}
tty_kref_put(tty);
}
}

Expand Down Expand Up @@ -548,8 +565,10 @@ static void sdio_uart_irq(struct sdio_func *func)
static int sdio_uart_startup(struct sdio_uart_port *port)
{
unsigned long page;
int ret;
struct tty_struct *tty = port->port.tty;
int ret = -ENOMEM;
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
Expand All @@ -560,7 +579,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
/* Initialise and allocate the transmit buffer. */
page = __get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
goto err0;
port->xmit.buf = (unsigned char *)page;
circ_clear(&port->xmit);

Expand Down Expand Up @@ -614,6 +633,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
sdio_uart_irq(port->func);

sdio_uart_release_func(port);
tty_kref_put(tty);
return 0;

err3:
Expand All @@ -622,12 +642,15 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
sdio_uart_release_func(port);
err1:
free_page((unsigned long)port->xmit.buf);
err0:
tty_kref_put(tty);
return ret;
}

static void sdio_uart_shutdown(struct sdio_uart_port *port)
{
int ret;
struct tty_struct *tty;

ret = sdio_uart_claim_func(port);
if (ret)
Expand All @@ -637,9 +660,11 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)

/* TODO: wait here for TX FIFO to drain */

tty = tty_port_tty_get(&port->port);
/* 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);
tty_kref_put(tty);

/* Disable interrupts from this port */
sdio_release_irq(port->func);
Expand Down Expand Up @@ -688,11 +713,11 @@ static int sdio_uart_open(struct tty_struct *tty, struct file *filp)

if (!port->opened) {
tty->driver_data = port;
port->port.tty = tty;
tty_port_tty_set(&port->port, tty);
ret = sdio_uart_startup(port);
if (ret) {
tty->driver_data = NULL;
port->port.tty = NULL;
tty_port_tty_set(&port->port, NULL);
mutex_unlock(&port->open_lock);
sdio_uart_port_put(port);
return ret;
Expand Down Expand Up @@ -727,7 +752,7 @@ static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
tty->closing = 1;
sdio_uart_shutdown(port);
tty_ldisc_flush(tty);
port->port.tty = NULL;
tty_port_tty_set(&port->port, NULL);
tty->driver_data = NULL;
tty->closing = 0;
}
Expand Down

0 comments on commit 530646f

Please sign in to comment.