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

Commit 4a90f09b authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds
Browse files

tty: usb-serial krefs



Use kref in the USB serial drivers so that we don't free tty structures
from under the URB receive handlers as has historically been the case if
you were unlucky. This also gives us a framework for general tty drivers to
use tty_port objects and refcount.

Contains two err->dev_err changes merged together to fix clashes in the
-next tree.

Signed-off-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 95f9bfc6
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ void tty_port_init(struct tty_port *port)
	init_waitqueue_head(&port->open_wait);
	init_waitqueue_head(&port->close_wait);
	mutex_init(&port->mutex);
	spin_lock_init(&port->lock);
	port->close_delay = (50 * HZ) / 100;
	port->closing_wait = (3000 * HZ) / 100;
}
@@ -53,3 +54,43 @@ void tty_port_free_xmit_buf(struct tty_port *port)
EXPORT_SYMBOL(tty_port_free_xmit_buf);


/**
 *	tty_port_tty_get	-	get a tty reference
 *	@port: tty port
 *
 *	Return a refcount protected tty instance or NULL if the port is not
 *	associated with a tty (eg due to close or hangup)
 */

struct tty_struct *tty_port_tty_get(struct tty_port *port)
{
	unsigned long flags;
	struct tty_struct *tty;

	spin_lock_irqsave(&port->lock, flags);
	tty = tty_kref_get(port->tty);
	spin_unlock_irqrestore(&port->lock, flags);
	return tty;
}
EXPORT_SYMBOL(tty_port_tty_get);

/**
 *	tty_port_tty_set	-	set the tty of a port
 *	@port: tty port
 *	@tty: the tty
 *
 *	Associate the port and tty pair. Manages any internal refcounts.
 *	Pass NULL to deassociate a port
 */

void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
{
	unsigned long flags;

	spin_lock_irqsave(&port->lock, flags);
	if (port->tty)
		tty_kref_put(port->tty);
	port->tty = tty;
	spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL(tty_port_tty_set);
+9 −6
Original line number Diff line number Diff line
@@ -272,7 +272,7 @@ static void aircable_read(struct work_struct *work)
	 * 64 bytes, to ensure I do not get throttled.
	 * Ask USB mailing list for better aproach.
	 */
	tty = port->port.tty;
	tty = tty_port_tty_get(&port->port);

	if (!tty) {
		schedule_work(&priv->rx_work);
@@ -283,12 +283,13 @@ static void aircable_read(struct work_struct *work)
	count = min(64, serial_buf_data_avail(priv->rx_buf));

	if (count <= 0)
		return; /* We have finished sending everything. */
		goto out; /* We have finished sending everything. */

	tty_prepare_flip_string(tty, &data, count);
	if (!data) {
		err("%s- kzalloc(%d) failed.", __func__, count);
		return;
		dev_err(&port->dev, "%s- kzalloc(%d) failed.",
							__func__, count);
		goto out;
	}

	serial_buf_get(priv->rx_buf, data, count);
@@ -297,7 +298,8 @@ static void aircable_read(struct work_struct *work)

	if (serial_buf_data_avail(priv->rx_buf))
		schedule_work(&priv->rx_work);

out:		
	tty_kref_put(tty);
	return;
}
/* End of private methods */
@@ -495,7 +497,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
	usb_serial_debug_data(debug, &port->dev, __func__,
				urb->actual_length, urb->transfer_buffer);

	tty = port->port.tty;
	tty = tty_port_tty_get(&port->port);
	if (tty && urb->actual_length) {
		if (urb->actual_length <= 2) {
			/* This is an incomplete package */
@@ -527,6 +529,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
		}
		aircable_read(&priv->rx_work);
	}
	tty_kref_put(tty);

	/* Schedule the next read _if_ we are still open */
	if (port->port.count) {
+2 −1
Original line number Diff line number Diff line
@@ -322,7 +322,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
	 * to look in to this before committing any code.
	 */
	if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
		tty = port->port.tty;
		tty = tty_port_tty_get(&port->port);
		/* Overrun Error */
		if (priv->last_lsr & BELKIN_SA_LSR_OE) {
		}
@@ -335,6 +335,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
		/* Break Indicator */
		if (priv->last_lsr & BELKIN_SA_LSR_BI) {
		}
		tty_kref_put(tty);
	}
#endif
	spin_unlock_irqrestore(&priv->lock, flags);
+4 −4
Original line number Diff line number Diff line
@@ -117,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
	}

	port = serial->port[0];
	port->port.tty = NULL;
	tty_port_tty_set(&port->port, NULL);

	info->port = port;

@@ -143,7 +143,7 @@ static int usb_console_setup(struct console *co, char *options)
			}
			memset(&dummy, 0, sizeof(struct ktermios));
			tty->termios = termios;
			port->port.tty = tty;
			tty_port_tty_set(&port->port, tty);
		}

		/* only call the device specific open if this
@@ -163,7 +163,7 @@ static int usb_console_setup(struct console *co, char *options)
			tty_termios_encode_baud_rate(termios, baud, baud);
			serial->type->set_termios(tty, port, &dummy);

			port->port.tty = NULL;
			tty_port_tty_set(&port->port, NULL);
			kfree(termios);
			kfree(tty);
		}
@@ -176,7 +176,7 @@ static int usb_console_setup(struct console *co, char *options)
	return retval;
free_termios:
	kfree(termios);
	port->port.tty = NULL;
	tty_port_tty_set(&port->port, NULL);
free_tty:
	kfree(tty);
reset_open_count:
+2 −1
Original line number Diff line number Diff line
@@ -384,7 +384,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
		return;
	}

	tty = port->port.tty;
	tty = tty_port_tty_get(&port->port);
	if (!tty) {
		dbg("%s - ignoring since device not open\n", __func__);
		return;
@@ -394,6 +394,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
		tty_insert_flip_string(tty, data, urb->actual_length);
		tty_flip_buffer_push(tty);
	}
	tty_kref_put(tty);

	spin_lock(&priv->lock);

Loading