Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+42 −17
Original line number Diff line number Diff line
@@ -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);
@@ -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;

@@ -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 (tty)
				tty_insert_flip_char(tty, ch, flag);

		/*
@@ -436,18 +442,22 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
		 * it doesn't affect the current character.
		 */
		if (*status & ~port->ignore_status_mask & UART_LSR_OE)
			if (tty)
				tty_insert_flip_char(tty, 0, TTY_OVERRUN);

		*status = sdio_in(port, UART_LSR);
	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
	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);
@@ -455,8 +465,12 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
		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;
	}

@@ -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);

@@ -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) {
@@ -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)
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
@@ -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);

@@ -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:
@@ -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)
@@ -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);
@@ -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;
@@ -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;
	}