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

Commit 62f228ac authored by Jiri Slaby's avatar Jiri Slaby Committed by Greg Kroah-Hartman
Browse files

TTY: ircomm, use tty from tty_port



This also includes a switch to tty refcounting. It makes sure, the
code no longer can access a freed TTY struct.

Sometimes the only thing needed is to pass tty down to the callies.

Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
Cc: Samuel Ortiz <samuel@sortiz.org>
Cc: netdev@vger.kernel.org
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e673927d
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ struct ircomm_tty_cb {

	int state;                /* Connect state */

	struct tty_struct *tty;
	struct ircomm_cb *ircomm; /* IrCOMM layer instance */

	struct sk_buff *tx_skb;   /* Transmit buffer */
+0 −5
Original line number Diff line number Diff line
@@ -99,7 +99,6 @@ pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
 */
int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
{
	struct tty_struct *tty;
	unsigned long flags;
	struct sk_buff *skb;
	int count;
@@ -109,10 +108,6 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
	IRDA_ASSERT(self != NULL, return -1;);
	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);

	tty = self->tty;
	if (!tty)
		return 0;

	/* Make sure we don't send parameters for raw mode */
	if (self->service_type == IRCOMM_3_WIRE_RAW)
		return 0;
+39 −23
Original line number Diff line number Diff line
@@ -242,18 +242,15 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
 *
 */
static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
				      struct file *filp)
		struct tty_struct *tty, struct file *filp)
{
	DECLARE_WAITQUEUE(wait, current);
	int		retval;
	int		do_clocal = 0, extra_count = 0;
	unsigned long	flags;
	struct tty_struct *tty;

	IRDA_DEBUG(2, "%s()\n", __func__ );

	tty = self->tty;

	/*
	 * If non-blocking mode is set, or the port is not enabled,
	 * then make the check up front and then exit.
@@ -412,8 +409,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
	self->port.count++;

	tty->driver_data = self;
	self->tty = tty;
	spin_unlock_irqrestore(&self->port.lock, flags);
	tty_port_tty_set(&self->port, tty);

	IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
		   self->line, self->port.count);
@@ -467,7 +464,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
	if (ret)
		return ret;

	ret = ircomm_tty_block_til_ready(self, filp);
	ret = ircomm_tty_block_til_ready(self, tty, filp);
	if (ret) {
		IRDA_DEBUG(2,
		      "%s(), returning after block_til_ready with %d\n", __func__ ,
@@ -548,7 +545,6 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)

	spin_lock_irqsave(&self->port.lock, flags);
	tty->closing = 0;
	self->tty = NULL;

	if (self->port.blocked_open) {
		if (self->port.close_delay) {
@@ -562,6 +558,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
	self->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
	spin_unlock_irqrestore(&self->port.lock, flags);
	wake_up_interruptible(&self->port.close_wait);
	tty_port_tty_set(&self->port, NULL);
}

/*
@@ -604,7 +601,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
	if (!self || self->magic != IRCOMM_TTY_MAGIC)
		return;

	tty = self->tty;
	tty = tty_port_tty_get(&self->port);
	if (!tty)
		return;

@@ -625,7 +622,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
	}

	if (tty->hw_stopped)
		return;
		goto put;

	/* Unlink transmit buffer */
	spin_lock_irqsave(&self->spinlock, flags);
@@ -644,6 +641,8 @@ static void ircomm_tty_do_softint(struct work_struct *work)

	/* Check if user (still) wants to be waken up */
	tty_wakeup(tty);
put:
	tty_kref_put(tty);
}

/*
@@ -1004,7 +1003,11 @@ static void ircomm_tty_hangup(struct tty_struct *tty)

	spin_lock_irqsave(&self->port.lock, flags);
	self->port.flags &= ~ASYNC_NORMAL_ACTIVE;
	self->tty = NULL;
	if (self->port.tty) {
		set_bit(TTY_IO_ERROR, &self->port.tty->flags);
		tty_kref_put(self->port.tty);
	}
	self->port.tty = NULL;
	self->port.count = 0;
	spin_unlock_irqrestore(&self->port.lock, flags);

@@ -1068,7 +1071,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
	IRDA_ASSERT(self != NULL, return;);
	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);

	tty = self->tty;
	tty = tty_port_tty_get(&self->port);

	status = self->settings.dce;

@@ -1089,10 +1092,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
				tty_hangup(tty);

			/* Hangup will remote the tty, so better break out */
			return;
			goto put;
		}
	}
	if (self->port.flags & ASYNC_CTS_FLOW) {
	if (tty && self->port.flags & ASYNC_CTS_FLOW) {
		if (tty->hw_stopped) {
			if (status & IRCOMM_CTS) {
				IRDA_DEBUG(2,
@@ -1103,7 +1106,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
				wake_up_interruptible(&self->port.open_wait);

				schedule_work(&self->tqueue);
				return;
				goto put;
			}
		} else {
			if (!(status & IRCOMM_CTS)) {
@@ -1113,6 +1116,8 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
			}
		}
	}
put:
	tty_kref_put(tty);
}

/*
@@ -1125,6 +1130,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
				      struct sk_buff *skb)
{
	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
	struct tty_struct *tty;

	IRDA_DEBUG(2, "%s()\n", __func__ );

@@ -1132,7 +1138,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
	IRDA_ASSERT(skb != NULL, return -1;);

	if (!self->tty) {
	tty = tty_port_tty_get(&self->port);
	if (!tty) {
		IRDA_DEBUG(0, "%s(), no tty!\n", __func__ );
		return 0;
	}
@@ -1143,7 +1150,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
	 * Devices like WinCE can do this, and since they don't send any
	 * params, we can just as well declare the hardware for running.
	 */
	if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
	if (tty->hw_stopped && (self->flow == FLOW_START)) {
		IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ );
		ircomm_param_request(self, IRCOMM_POLL, TRUE);

@@ -1156,8 +1163,9 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
	 * Use flip buffer functions since the code may be called from interrupt
	 * context
	 */
	tty_insert_flip_string(self->tty, skb->data, skb->len);
	tty_flip_buffer_push(self->tty);
	tty_insert_flip_string(tty, skb->data, skb->len);
	tty_flip_buffer_push(tty);
	tty_kref_put(tty);

	/* No need to kfree_skb - see ircomm_ttp_data_indication() */

@@ -1208,11 +1216,12 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
	IRDA_ASSERT(self != NULL, return;);
	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);

	tty = self->tty;
	tty = tty_port_tty_get(&self->port);

	switch (cmd) {
	case FLOW_START:
		IRDA_DEBUG(2, "%s(), hw start!\n", __func__ );
		if (tty)
			tty->hw_stopped = 0;

		/* ircomm_tty_do_softint will take care of the rest */
@@ -1221,15 +1230,19 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
	default:  /* If we get here, something is very wrong, better stop */
	case FLOW_STOP:
		IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ );
		if (tty)
			tty->hw_stopped = 1;
		break;
	}

	tty_kref_put(tty);
	self->flow = cmd;
}

#ifdef CONFIG_PROC_FS
static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
{
	struct tty_struct *tty;
	char sep;

	seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]);
@@ -1356,9 +1369,12 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
	seq_printf(m, "Max data size: %d\n", self->max_data_size);
	seq_printf(m, "Max header size: %d\n", self->max_header_size);

	if (self->tty)
	tty = tty_port_tty_get(&self->port);
	if (tty) {
		seq_printf(m, "Hardware: %s\n",
			       self->tty->hw_stopped ? "Stopped" : "Running");
			       tty->hw_stopped ? "Stopped" : "Running");
		tty_kref_put(tty);
	}
}

static int ircomm_tty_proc_show(struct seq_file *m, void *v)
+25 −8
Original line number Diff line number Diff line
@@ -130,6 +130,8 @@ static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
 */
int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
{
	struct tty_struct *tty;

	IRDA_DEBUG(0, "%s()\n", __func__ );

	IRDA_ASSERT(self != NULL, return -1;);
@@ -142,7 +144,11 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
	}

	/* Make sure nobody tries to write before the link is up */
	self->tty->hw_stopped = 1;
	tty = tty_port_tty_get(&self->port);
	if (tty) {
		tty->hw_stopped = 1;
		tty_kref_put(tty);
	}

	ircomm_tty_ias_register(self);

@@ -398,23 +404,26 @@ void ircomm_tty_disconnect_indication(void *instance, void *sap,
				      struct sk_buff *skb)
{
	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
	struct tty_struct *tty;

	IRDA_DEBUG(2, "%s()\n", __func__ );

	IRDA_ASSERT(self != NULL, return;);
	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);

	if (!self->tty)
	tty = tty_port_tty_get(&self->port);
	if (!tty)
		return;

	/* This will stop control data transfers */
	self->flow = FLOW_STOP;

	/* Stop data transfers */
	self->tty->hw_stopped = 1;
	tty->hw_stopped = 1;

	ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
			    NULL);
	tty_kref_put(tty);
}

/*
@@ -550,12 +559,15 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
 */
void ircomm_tty_link_established(struct ircomm_tty_cb *self)
{
	struct tty_struct *tty;

	IRDA_DEBUG(2, "%s()\n", __func__ );

	IRDA_ASSERT(self != NULL, return;);
	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);

	if (!self->tty)
	tty = tty_port_tty_get(&self->port);
	if (!tty)
		return;

	del_timer(&self->watchdog_timer);
@@ -569,17 +581,19 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
	if ((self->port.flags & ASYNC_CTS_FLOW) &&
			((self->settings.dce & IRCOMM_CTS) == 0)) {
		IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );
		return;
		goto put;
	} else {
		IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );

		self->tty->hw_stopped = 0;
		tty->hw_stopped = 0;

		/* Wake up processes blocked on open */
		wake_up_interruptible(&self->port.open_wait);
	}

	schedule_work(&self->tqueue);
put:
	tty_kref_put(tty);
}

/*
@@ -983,9 +997,12 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
			self->settings.dce = IRCOMM_DELTA_CD;
			ircomm_tty_check_modem_status(self);
		} else {
			struct tty_struct *tty = tty_port_tty_get(&self->port);
			IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
			if (self->tty)
				tty_hangup(self->tty);
			if (tty) {
				tty_hangup(tty);
				tty_kref_put(tty);
			}
		}
		break;
	default:
+6 −5
Original line number Diff line number Diff line
@@ -52,17 +52,18 @@
 *    Change speed of the driver. If the remote device is a DCE, then this
 *    should make it change the speed of its serial port
 */
static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
static void ircomm_tty_change_speed(struct ircomm_tty_cb *self,
		struct tty_struct *tty)
{
	unsigned int cflag, cval;
	int baud;

	IRDA_DEBUG(2, "%s()\n", __func__ );

	if (!self->tty || !self->tty->termios || !self->ircomm)
	if (!self->ircomm)
		return;

	cflag = self->tty->termios->c_cflag;
	cflag = tty->termios->c_cflag;

	/*  byte size and parity */
	switch (cflag & CSIZE) {
@@ -81,7 +82,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
		cval |= IRCOMM_PARITY_EVEN;

	/* Determine divisor based on baud rate */
	baud = tty_get_baud_rate(self->tty);
	baud = tty_get_baud_rate(tty);
	if (!baud)
		baud = 9600;	/* B0 transition handled in rs_set_termios */

@@ -159,7 +160,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
		return;
	}

	ircomm_tty_change_speed(self);
	ircomm_tty_change_speed(self, tty);

	/* Handle transition to B0 status */
	if ((old_termios->c_cflag & CBAUD) &&