public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 06/11] sdio_uart: Switch to the open/close helpers
  2009-11-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
@ 2009-11-03 14:18 ` Alan Cox
  0 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:18 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

Gets us proper tty semantics, removes some code and fixes up a few corner
case races (hangup during open etc)

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |  201 +++++++++++++++++++++++++-----------------
 1 files changed, 119 insertions(+), 82 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index f76741d..3e2ae66 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -77,7 +77,6 @@ struct sdio_uart_port {
 	struct kref		kref;
 	struct tty_struct	*tty;
 	unsigned int		index;
-	unsigned int		opened;
 	struct sdio_func	*func;
 	struct mutex		func_lock;
 	struct task_struct	*in_sdio_uart_irq;
@@ -150,6 +149,7 @@ static void sdio_uart_port_put(struct sdio_uart_port *port)
 static void sdio_uart_port_remove(struct sdio_uart_port *port)
 {
 	struct sdio_func *func;
+	struct tty_struct *tty;
 
 	BUG_ON(sdio_uart_table[port->index] != port);
 
@@ -170,11 +170,10 @@ 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) {
-		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 = 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->port.mutex);
@@ -559,13 +558,46 @@ static void sdio_uart_irq(struct sdio_func *func)
 	port->in_sdio_uart_irq = NULL;
 }
 
-static int sdio_uart_startup(struct sdio_uart_port *port)
+/**
+ *	uart_dtr_rts		-	 port helper to set uart signals
+ *	@tport: tty port to be updated
+ *	@onoff: set to turn on DTR/RTS
+ *
+ *	Called by the tty port helpers when the modem signals need to be
+ *	adjusted during an open, close and hangup.
+ */
+
+static void uart_dtr_rts(struct tty_port *tport, int onoff)
 {
-	unsigned long page;
-	int ret = -ENOMEM;
-	struct tty_struct *tty = tty_port_tty_get(&port->port);
+	struct sdio_uart_port *port =
+			container_of(tport, struct sdio_uart_port, port);
+	if (onoff == 0)
+		sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+	else
+		sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+}
+
+/**
+ *	sdio_uart_activate	-	start up hardware
+ *	@tport: tty port to activate
+ *	@tty: tty bound to this port
+ *
+ *	Activate a tty port. The port locking guarantees us this will be
+ *	run exactly once per set of opens, and if successful will see the
+ *	shutdown method run exactly once to match. Start up and shutdown are
+ *	protected from each other by the internal locking and will not run
+ *	at the same time even during a hangup event.
+ *
+ *	If we successfully start up the port we take an extra kref as we
+ *	will keep it around until shutdown when the kref is dropped.
+ */
 
-	/* FIXME: What if it is NULL ?? */
+static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
+{
+	struct sdio_uart_port *port =
+			container_of(tport, struct sdio_uart_port, port);
+	unsigned long page;
+	int ret;
 
 	/*
 	 * Set the TTY IO error marker - we will only clear this
@@ -576,7 +608,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)
-		goto err0;
+		return -ENOMEM;
 	port->xmit.buf = (unsigned char *)page;
 	circ_clear(&port->xmit);
 
@@ -630,7 +662,6 @@ 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:
@@ -639,15 +670,25 @@ err2:
 	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)
+	
+/**
+ *	sdio_uart_shutdown	-	stop hardware
+ *	@tport: tty port to shut down
+ *
+ *	Deactivate a tty port. The port locking guarantees us this will be
+ *	run only if a successful matching activate already ran. The two are
+ *	protected from each other by the internal locking and will not run
+ *	at the same time even during a hangup event.
+ */
+
+static void sdio_uart_shutdown(struct tty_port *tport)
 {
+	struct sdio_uart_port *port =
+			container_of(tport, struct sdio_uart_port, port);
 	int ret;
-	struct tty_struct *tty;
 
 	ret = sdio_uart_claim_func(port);
 	if (ret)
@@ -655,14 +696,6 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)
 
 	sdio_uart_stop_rx(port);
 
-	/* TODO: wait here for TX FIFO to drain */
-
-	tty = tty_port_tty_get(&port->port);
-	/* Turn off DTR and RTS early. */
-	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);
 	port->ier = 0;
@@ -687,74 +720,68 @@ skip:
 	free_page((unsigned long)port->xmit.buf);
 }
 
-static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
+/**
+ *	sdio_uart_install	-	install method
+ *	@driver: the driver in use (sdio_uart in our case)
+ *	@tty: the tty being bound
+ *
+ *	Look up and bind the tty and the driver together. Initialize
+ *	any needed private data (in our case the termios)
+ */
+
+static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-	struct sdio_uart_port *port;
-	int ret;
+	int idx = tty->index;
+	struct sdio_uart_port *port = sdio_uart_port_get(idx);
+	int ret = tty_init_termios(tty);
+
+	if (ret == 0) {
+		tty_driver_kref_get(driver);
+		tty->count++;
+		/* This is the ref sdio_uart_port get provided */
+		tty->driver_data = port;
+		driver->ttys[idx] = tty;
+	} else
+		sdio_uart_port_put(port);
+	return ret;
+		
+}
 
-	port = sdio_uart_port_get(tty->index);
-	if (!port)
-		return -ENODEV;
+/**
+ *	sdio_uart_cleanup	-	called on the last tty kref drop
+ *	@tty: the tty being destroyed
+ *
+ *	Called asynchronously when the last reference to the tty is dropped.
+ *	We cannot destroy the tty->driver_data port kref until this point
+ */
 
-	mutex_lock(&port->port.mutex);
+static void sdio_uart_cleanup(struct tty_struct *tty)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	tty->driver_data = NULL;	/* Bug trap */
+	sdio_uart_port_put(port);
+}
 
-	/*
-	 * Make sure not to mess up with a dead port
-	 * which has not been closed yet.
-	 */
-	if (tty->driver_data && tty->driver_data != port) {
-		mutex_unlock(&port->port.mutex);
-		sdio_uart_port_put(port);
-		return -EBUSY;
-	}
+/*
+ *	Open/close/hangup is now entirely boilerplate
+ */
 
-	if (!port->opened) {
-		tty->driver_data = port;
-		tty_port_tty_set(&port->port, tty);
-		ret = sdio_uart_startup(port);
-		if (ret) {
-			tty->driver_data = NULL;
-			tty_port_tty_set(&port->port, NULL);
-			mutex_unlock(&port->port.mutex);
-			sdio_uart_port_put(port);
-			return ret;
-		}
-	}
-	port->opened++;
-	mutex_unlock(&port->port.mutex);
-	return 0;
+static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	return tty_port_open(&port->port, tty, filp);
 }
 
 static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
 {
 	struct sdio_uart_port *port = tty->driver_data;
+	tty_port_close(&port->port, tty, filp);
+}
 
-	if (!port)
-		return;
-
-	mutex_lock(&port->port.mutex);
-	BUG_ON(!port->opened);
-
-	/*
-	 * This is messy.  The tty layer calls us even when open()
-	 * returned an error.  Ignore this close request if tty->count
-	 * is larger than port->count.
-	 */
-	if (tty->count > port->opened) {
-		mutex_unlock(&port->port.mutex);
-		return;
-	}
-
-	if (--port->opened == 0) {
-		tty->closing = 1;
-		sdio_uart_shutdown(port);
-		tty_ldisc_flush(tty);
-		tty_port_tty_set(&port->port, NULL);
-		tty->driver_data = NULL;
-		tty->closing = 0;
-	}
-	mutex_unlock(&port->port.mutex);
-	sdio_uart_port_put(port);
+static void sdio_uart_hangup(struct tty_struct *tty)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	tty_port_hangup(&port->port);
 }
 
 static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
@@ -1020,6 +1047,12 @@ static const struct file_operations sdio_uart_proc_fops = {
 	.release	= single_release,
 };
 
+static const struct tty_port_operations sdio_uart_port_ops = {
+	.dtr_rts = uart_dtr_rts,
+	.shutdown = sdio_uart_shutdown,
+	.activate = sdio_uart_activate,
+};
+	
 static const struct tty_operations sdio_uart_ops = {
 	.open			= sdio_uart_open,
 	.close			= sdio_uart_close,
@@ -1030,9 +1063,12 @@ static const struct tty_operations sdio_uart_ops = {
 	.throttle		= sdio_uart_throttle,
 	.unthrottle		= sdio_uart_unthrottle,
 	.set_termios		= sdio_uart_set_termios,
+	.hangup			= sdio_uart_hangup,
 	.break_ctl		= sdio_uart_break_ctl,
 	.tiocmget		= sdio_uart_tiocmget,
 	.tiocmset		= sdio_uart_tiocmset,
+	.install		= sdio_uart_install,
+	.cleanup		= sdio_uart_cleanup,
 	.proc_fops		= &sdio_uart_proc_fops,
 };
 
@@ -1095,6 +1131,7 @@ static int sdio_uart_probe(struct sdio_func *func,
 	port->func = func;
 	sdio_set_drvdata(func, port);
 	tty_port_init(&port->port);
+	port->port.ops = &sdio_uart_port_ops;
 
 	ret = sdio_uart_add_port(port);
 	if (ret) {


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 00/11] Series short description
@ 2009-11-18 14:18 Alan Cox
  2009-11-18 14:19 ` [PATCH 01/11] tty_port: Move hupcl handling Alan Cox
                   ` (10 more replies)
  0 siblings, 11 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:18 UTC (permalink / raw)
  To: greg, linux-kernel

Resend: This patch series reworks the sdio_uart driver into a modern format
and also replaces the circ buffer stuff it uses with a kfifo which makes the
code a good deal easier to follow.
---

Alan Cox (10):
      sdio_uart: add modem functionality
      sdio_uart: Fix the locking on "func" for new code
      sdio_uart: Style fixes
      sdio_uart: Use kfifo instead of the messy circ stuff
      sdio_uart: Fix termios handling
      sdio_uart: Switch to the open/close helpers
      sdio_uart: Move the open lock
      sdio_uart: refcount the tty objects
      sdio_uart: use tty_port
      tty_port: Move hupcl handling

Nicolas Pitre (1):
      sdio_uart: Fix oops caused by the previous changeset


 drivers/char/tty_port.c      |   13 +
 drivers/mmc/card/sdio_uart.c |  393 ++++++++++++++++++++++++------------------
 2 files changed, 235 insertions(+), 171 deletions(-)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 01/11] tty_port: Move hupcl handling
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
@ 2009-11-18 14:19 ` Alan Cox
  2009-11-18 14:19 ` [PATCH 02/11] sdio_uart: use tty_port Alan Cox
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:19 UTC (permalink / raw)
  To: greg, linux-kernel

Move the HUCPL handling from the end of close_port_start to the beginning
of close_port_end. What this actually does is change the ordering from

	port shutdown
	port->dtr_rts

to

	port->dtr_rts
	port shutdown

Some hardware drops the physical connection on shutdown so we must perform
the port operations before the shutdown.

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/char/tty_port.c |   13 ++++++++-----
 1 files changed, 8 insertions(+), 5 deletions(-)


diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 5e2ac57..93a5bf5 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -360,6 +360,14 @@ int tty_port_close_start(struct tty_port *port,
 			timeout = 2 * HZ;
 		schedule_timeout_interruptible(timeout);
 	}
+	/* Flush the ldisc buffering */
+	tty_ldisc_flush(tty);
+
+	/* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
+	   hang up the line */
+	if (tty->termios->c_cflag & HUPCL)
+		tty_port_lower_dtr_rts(port);
+
 	/* Don't call port->drop for the last reference. Callers will want
 	   to drop the last active reference in ->shutdown() or the tty
 	   shutdown path */
@@ -371,11 +379,6 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
 {
 	unsigned long flags;
 
-	tty_ldisc_flush(tty);
-
-	if (tty->termios->c_cflag & HUPCL)
-		tty_port_lower_dtr_rts(port);
-
 	spin_lock_irqsave(&port->lock, flags);
 	tty->closing = 0;
 


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 02/11] sdio_uart: use tty_port
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
  2009-11-18 14:19 ` [PATCH 01/11] tty_port: Move hupcl handling Alan Cox
@ 2009-11-18 14:19 ` Alan Cox
  2009-11-18 14:19 ` [PATCH 03/11] sdio_uart: Fix oops caused by the previous changeset Alan Cox
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:19 UTC (permalink / raw)
  To: greg, linux-kernel

Add a tty_port object to the sdio uart. For the moment just begin using the
tty field of the port, as this is the critical one to clean up.

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |   41 +++++++++++++++++++++++------------------
 1 files changed, 23 insertions(+), 18 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index b8e7c5a..c2759db 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -73,6 +73,7 @@ struct uart_icount {
 };
 
 struct sdio_uart_port {
+	struct tty_port		port;
 	struct kref		kref;
 	struct tty_struct	*tty;
 	unsigned int		index;
@@ -172,7 +173,7 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
 	port->func = NULL;
 	mutex_unlock(&port->func_lock);
 	if (port->opened)
-		tty_hangup(port->tty);
+		tty_hangup(port->port.tty);
 	mutex_unlock(&port->open_lock);
 	sdio_release_irq(func);
 	sdio_disable_func(func);
@@ -391,7 +392,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->tty;
+	struct tty_struct *tty = port->port.tty;
 	unsigned int ch, flag;
 	int max_count = 256;
 
@@ -446,6 +447,7 @@ 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;
 
 	if (port->x_char) {
 		sdio_out(port, UART_TX, port->x_char);
@@ -453,7 +455,7 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
 		port->x_char = 0;
 		return;
 	}
-	if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) {
+	if (circ_empty(xmit) || tty->stopped || tty->hw_stopped) {
 		sdio_uart_stop_tx(port);
 		return;
 	}
@@ -468,7 +470,7 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
 	} while (--count > 0);
 
 	if (circ_chars_pending(xmit) < WAKEUP_CHARS)
-		tty_wakeup(port->tty);
+		tty_wakeup(tty);
 
 	if (circ_empty(xmit))
 		sdio_uart_stop_tx(port);
@@ -477,6 +479,7 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
 static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
 {
 	int status;
+	struct tty_struct *tty = port->port.tty;
 
 	status = sdio_in(port, UART_MSR);
 
@@ -491,17 +494,17 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
 		port->icount.dcd++;
 	if (status & UART_MSR_DCTS) {
 		port->icount.cts++;
-		if (port->tty->termios->c_cflag & CRTSCTS) {
+		if (tty->termios->c_cflag & CRTSCTS) {
 			int cts = (status & UART_MSR_CTS);
-			if (port->tty->hw_stopped) {
+			if (tty->hw_stopped) {
 				if (cts) {
-					port->tty->hw_stopped = 0;
+					tty->hw_stopped = 0;
 					sdio_uart_start_tx(port);
-					tty_wakeup(port->tty);
+					tty_wakeup(tty);
 				}
 			} else {
 				if (!cts) {
-					port->tty->hw_stopped = 1;
+					tty->hw_stopped = 1;
 					sdio_uart_stop_tx(port);
 				}
 			}
@@ -546,12 +549,13 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
 {
 	unsigned long page;
 	int ret;
+	struct tty_struct *tty = port->port.tty;
 
 	/*
 	 * Set the TTY IO error marker - we will only clear this
 	 * once we have successfully opened the port.
 	 */
-	set_bit(TTY_IO_ERROR, &port->tty->flags);
+	set_bit(TTY_IO_ERROR, &tty->flags);
 
 	/* Initialise and allocate the transmit buffer. */
 	page = __get_free_page(GFP_KERNEL);
@@ -595,14 +599,14 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
 	port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
 	port->mctrl = TIOCM_OUT2;
 
-	sdio_uart_change_speed(port, port->tty->termios, NULL);
+	sdio_uart_change_speed(port, tty->termios, NULL);
 
-	if (port->tty->termios->c_cflag & CBAUD)
+	if (tty->termios->c_cflag & CBAUD)
 		sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
 
-	if (port->tty->termios->c_cflag & CRTSCTS)
+	if (tty->termios->c_cflag & CRTSCTS)
 		if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
-			port->tty->hw_stopped = 1;
+			tty->hw_stopped = 1;
 
 	clear_bit(TTY_IO_ERROR, &port->tty->flags);
 
@@ -634,7 +638,7 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)
 	/* TODO: wait here for TX FIFO to drain */
 
 	/* Turn off DTR and RTS early. */
-	if (port->tty->termios->c_cflag & HUPCL)
+	if (port->port.tty->termios->c_cflag & HUPCL)
 		sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 
 	/* Disable interrupts from this port */
@@ -684,11 +688,11 @@ static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
 
 	if (!port->opened) {
 		tty->driver_data = port;
-		port->tty = tty;
+		port->port.tty = tty;
 		ret = sdio_uart_startup(port);
 		if (ret) {
 			tty->driver_data = NULL;
-			port->tty = NULL;
+			port->port.tty = NULL;
 			mutex_unlock(&port->open_lock);
 			sdio_uart_port_put(port);
 			return ret;
@@ -723,7 +727,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->tty = NULL;
+		port->port.tty = NULL;
 		tty->driver_data = NULL;
 		tty->closing = 0;
 	}
@@ -1068,6 +1072,7 @@ static int sdio_uart_probe(struct sdio_func *func,
 
 	port->func = func;
 	sdio_set_drvdata(func, port);
+	tty_port_init(&port->port);
 
 	ret = sdio_uart_add_port(port);
 	if (ret) {


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 03/11] sdio_uart: Fix oops caused by the previous changeset
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
  2009-11-18 14:19 ` [PATCH 01/11] tty_port: Move hupcl handling Alan Cox
  2009-11-18 14:19 ` [PATCH 02/11] sdio_uart: use tty_port Alan Cox
@ 2009-11-18 14:19 ` Alan Cox
  2009-11-18 14:19 ` [PATCH 04/11] sdio_uart: refcount the tty objects Alan Cox
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:19 UTC (permalink / raw)
  To: greg, linux-kernel

From: Nicolas Pitre <nico@fluxnic.net>

Now... testing reveals that the very first patch "sdio_uart: use
tty_port" causes a segmentation fault in sdio_uart_open():

Unable to handle kernel NULL pointer dereference at virtual address 00000084
pgd = dfb44000 [00000084] *pgd=1fb99031, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1] PREEMPT
last sysfs file:
/sys/devices/platform/mvsdio/mmc_host/mmc0/mmc0:f111/uevent
Modules linked in:
CPU: 0    Not tainted  (2.6.32-rc5-next-20091102-00001-gb36eae9 #10)
PC is at sdio_uart_open+0x204/0x2cc
[...]

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index c2759db..671fe5e 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -608,7 +608,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port)
 		if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
 			tty->hw_stopped = 1;
 
-	clear_bit(TTY_IO_ERROR, &port->tty->flags);
+	clear_bit(TTY_IO_ERROR, &tty->flags);
 
 	/* Kick the IRQ handler once while we're still holding the host lock */
 	sdio_uart_irq(port->func);


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 04/11] sdio_uart: refcount the tty objects
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
                   ` (2 preceding siblings ...)
  2009-11-18 14:19 ` [PATCH 03/11] sdio_uart: Fix oops caused by the previous changeset Alan Cox
@ 2009-11-18 14:19 ` Alan Cox
  2009-11-18 14:19 ` [PATCH 05/11] sdio_uart: Move the open lock Alan Cox
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:19 UTC (permalink / raw)
  To: greg, linux-kernel

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 <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |   59 ++++++++++++++++++++++++++++++------------
 1 files changed, 42 insertions(+), 17 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 671fe5e..86ad543 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -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,25 +434,30 @@ 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);
@@ -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 @@ err2:
 	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;
 	}


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 05/11] sdio_uart: Move the open lock
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
                   ` (3 preceding siblings ...)
  2009-11-18 14:19 ` [PATCH 04/11] sdio_uart: refcount the tty objects Alan Cox
@ 2009-11-18 14:19 ` Alan Cox
  2009-11-18 14:19 ` [PATCH 06/11] sdio_uart: Switch to the open/close helpers Alan Cox
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:19 UTC (permalink / raw)
  To: greg, linux-kernel

When we move to the tty_port logic the port mutex will protect open v close
v hangup. Move to this first in the existing open code so we have a bisection
point.

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |   20 +++++++++-----------
 1 files changed, 9 insertions(+), 11 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 86ad543..31f7023 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -78,7 +78,6 @@ struct sdio_uart_port {
 	struct tty_struct	*tty;
 	unsigned int		index;
 	unsigned int		opened;
-	struct mutex		open_lock;
 	struct sdio_func	*func;
 	struct mutex		func_lock;
 	struct task_struct	*in_sdio_uart_irq;
@@ -103,7 +102,6 @@ static int sdio_uart_add_port(struct sdio_uart_port *port)
 	int index, ret = -EBUSY;
 
 	kref_init(&port->kref);
-	mutex_init(&port->open_lock);
 	mutex_init(&port->func_lock);
 	spin_lock_init(&port->write_lock);
 
@@ -166,7 +164,7 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
 	 * give up on that port ASAP.
 	 * Beware: the lock ordering is critical.
 	 */
-	mutex_lock(&port->open_lock);
+	mutex_lock(&port->port.mutex);
 	mutex_lock(&port->func_lock);
 	func = port->func;
 	sdio_claim_host(func);
@@ -179,7 +177,7 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
 			tty_hangup(tty);
 		tty_kref_put(tty);
 	}
-	mutex_unlock(&port->open_lock);
+	mutex_unlock(&port->port.mutex);
 	sdio_release_irq(func);
 	sdio_disable_func(func);
 	sdio_release_host(func);
@@ -699,14 +697,14 @@ static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
 	if (!port)
 		return -ENODEV;
 
-	mutex_lock(&port->open_lock);
+	mutex_lock(&port->port.mutex);
 
 	/*
 	 * Make sure not to mess up with a dead port
 	 * which has not been closed yet.
 	 */
 	if (tty->driver_data && tty->driver_data != port) {
-		mutex_unlock(&port->open_lock);
+		mutex_unlock(&port->port.mutex);
 		sdio_uart_port_put(port);
 		return -EBUSY;
 	}
@@ -718,13 +716,13 @@ static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
 		if (ret) {
 			tty->driver_data = NULL;
 			tty_port_tty_set(&port->port, NULL);
-			mutex_unlock(&port->open_lock);
+			mutex_unlock(&port->port.mutex);
 			sdio_uart_port_put(port);
 			return ret;
 		}
 	}
 	port->opened++;
-	mutex_unlock(&port->open_lock);
+	mutex_unlock(&port->port.mutex);
 	return 0;
 }
 
@@ -735,7 +733,7 @@ static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
 	if (!port)
 		return;
 
-	mutex_lock(&port->open_lock);
+	mutex_lock(&port->port.mutex);
 	BUG_ON(!port->opened);
 
 	/*
@@ -744,7 +742,7 @@ static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
 	 * is larger than port->count.
 	 */
 	if (tty->count > port->opened) {
-		mutex_unlock(&port->open_lock);
+		mutex_unlock(&port->port.mutex);
 		return;
 	}
 
@@ -756,7 +754,7 @@ static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
 		tty->driver_data = NULL;
 		tty->closing = 0;
 	}
-	mutex_unlock(&port->open_lock);
+	mutex_unlock(&port->port.mutex);
 	sdio_uart_port_put(port);
 }
 


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 06/11] sdio_uart: Switch to the open/close helpers
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
                   ` (4 preceding siblings ...)
  2009-11-18 14:19 ` [PATCH 05/11] sdio_uart: Move the open lock Alan Cox
@ 2009-11-18 14:19 ` Alan Cox
  2009-11-20 17:35   ` Greg KH
  2009-11-18 14:20 ` [PATCH 07/11] sdio_uart: Fix termios handling Alan Cox
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:19 UTC (permalink / raw)
  To: greg, linux-kernel

Gets us proper tty semantics, removes some code and fixes up a few corner
case races (hangup during open etc)

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |  201 +++++++++++++++++++++++++-----------------
 1 files changed, 119 insertions(+), 82 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 31f7023..1be90bc 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -77,7 +77,6 @@ struct sdio_uart_port {
 	struct kref		kref;
 	struct tty_struct	*tty;
 	unsigned int		index;
-	unsigned int		opened;
 	struct sdio_func	*func;
 	struct mutex		func_lock;
 	struct task_struct	*in_sdio_uart_irq;
@@ -150,6 +149,7 @@ static void sdio_uart_port_put(struct sdio_uart_port *port)
 static void sdio_uart_port_remove(struct sdio_uart_port *port)
 {
 	struct sdio_func *func;
+	struct tty_struct *tty;
 
 	BUG_ON(sdio_uart_table[port->index] != port);
 
@@ -170,11 +170,10 @@ 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) {
-		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 = 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->port.mutex);
@@ -560,13 +559,46 @@ static void sdio_uart_irq(struct sdio_func *func)
 	port->in_sdio_uart_irq = NULL;
 }
 
-static int sdio_uart_startup(struct sdio_uart_port *port)
+/**
+ *	uart_dtr_rts		-	 port helper to set uart signals
+ *	@tport: tty port to be updated
+ *	@onoff: set to turn on DTR/RTS
+ *
+ *	Called by the tty port helpers when the modem signals need to be
+ *	adjusted during an open, close and hangup.
+ */
+
+static void uart_dtr_rts(struct tty_port *tport, int onoff)
 {
-	unsigned long page;
-	int ret = -ENOMEM;
-	struct tty_struct *tty = tty_port_tty_get(&port->port);
+	struct sdio_uart_port *port =
+			container_of(tport, struct sdio_uart_port, port);
+	if (onoff == 0)
+		sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+	else
+		sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+}
+
+/**
+ *	sdio_uart_activate	-	start up hardware
+ *	@tport: tty port to activate
+ *	@tty: tty bound to this port
+ *
+ *	Activate a tty port. The port locking guarantees us this will be
+ *	run exactly once per set of opens, and if successful will see the
+ *	shutdown method run exactly once to match. Start up and shutdown are
+ *	protected from each other by the internal locking and will not run
+ *	at the same time even during a hangup event.
+ *
+ *	If we successfully start up the port we take an extra kref as we
+ *	will keep it around until shutdown when the kref is dropped.
+ */
 
-	/* FIXME: What if it is NULL ?? */
+static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
+{
+	struct sdio_uart_port *port =
+			container_of(tport, struct sdio_uart_port, port);
+	unsigned long page;
+	int ret;
 
 	/*
 	 * Set the TTY IO error marker - we will only clear this
@@ -577,7 +609,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)
-		goto err0;
+		return -ENOMEM;
 	port->xmit.buf = (unsigned char *)page;
 	circ_clear(&port->xmit);
 
@@ -631,7 +663,6 @@ 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:
@@ -640,15 +671,25 @@ err2:
 	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)
+	
+/**
+ *	sdio_uart_shutdown	-	stop hardware
+ *	@tport: tty port to shut down
+ *
+ *	Deactivate a tty port. The port locking guarantees us this will be
+ *	run only if a successful matching activate already ran. The two are
+ *	protected from each other by the internal locking and will not run
+ *	at the same time even during a hangup event.
+ */
+
+static void sdio_uart_shutdown(struct tty_port *tport)
 {
+	struct sdio_uart_port *port =
+			container_of(tport, struct sdio_uart_port, port);
 	int ret;
-	struct tty_struct *tty;
 
 	ret = sdio_uart_claim_func(port);
 	if (ret)
@@ -656,14 +697,6 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port)
 
 	sdio_uart_stop_rx(port);
 
-	/* TODO: wait here for TX FIFO to drain */
-
-	tty = tty_port_tty_get(&port->port);
-	/* Turn off DTR and RTS early. */
-	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);
 	port->ier = 0;
@@ -688,74 +721,68 @@ skip:
 	free_page((unsigned long)port->xmit.buf);
 }
 
-static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
+/**
+ *	sdio_uart_install	-	install method
+ *	@driver: the driver in use (sdio_uart in our case)
+ *	@tty: the tty being bound
+ *
+ *	Look up and bind the tty and the driver together. Initialize
+ *	any needed private data (in our case the termios)
+ */
+
+static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-	struct sdio_uart_port *port;
-	int ret;
+	int idx = tty->index;
+	struct sdio_uart_port *port = sdio_uart_port_get(idx);
+	int ret = tty_init_termios(tty);
+
+	if (ret == 0) {
+		tty_driver_kref_get(driver);
+		tty->count++;
+		/* This is the ref sdio_uart_port get provided */
+		tty->driver_data = port;
+		driver->ttys[idx] = tty;
+	} else
+		sdio_uart_port_put(port);
+	return ret;
+		
+}
 
-	port = sdio_uart_port_get(tty->index);
-	if (!port)
-		return -ENODEV;
+/**
+ *	sdio_uart_cleanup	-	called on the last tty kref drop
+ *	@tty: the tty being destroyed
+ *
+ *	Called asynchronously when the last reference to the tty is dropped.
+ *	We cannot destroy the tty->driver_data port kref until this point
+ */
 
-	mutex_lock(&port->port.mutex);
+static void sdio_uart_cleanup(struct tty_struct *tty)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	tty->driver_data = NULL;	/* Bug trap */
+	sdio_uart_port_put(port);
+}
 
-	/*
-	 * Make sure not to mess up with a dead port
-	 * which has not been closed yet.
-	 */
-	if (tty->driver_data && tty->driver_data != port) {
-		mutex_unlock(&port->port.mutex);
-		sdio_uart_port_put(port);
-		return -EBUSY;
-	}
+/*
+ *	Open/close/hangup is now entirely boilerplate
+ */
 
-	if (!port->opened) {
-		tty->driver_data = port;
-		tty_port_tty_set(&port->port, tty);
-		ret = sdio_uart_startup(port);
-		if (ret) {
-			tty->driver_data = NULL;
-			tty_port_tty_set(&port->port, NULL);
-			mutex_unlock(&port->port.mutex);
-			sdio_uart_port_put(port);
-			return ret;
-		}
-	}
-	port->opened++;
-	mutex_unlock(&port->port.mutex);
-	return 0;
+static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	return tty_port_open(&port->port, tty, filp);
 }
 
 static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
 {
 	struct sdio_uart_port *port = tty->driver_data;
+	tty_port_close(&port->port, tty, filp);
+}
 
-	if (!port)
-		return;
-
-	mutex_lock(&port->port.mutex);
-	BUG_ON(!port->opened);
-
-	/*
-	 * This is messy.  The tty layer calls us even when open()
-	 * returned an error.  Ignore this close request if tty->count
-	 * is larger than port->count.
-	 */
-	if (tty->count > port->opened) {
-		mutex_unlock(&port->port.mutex);
-		return;
-	}
-
-	if (--port->opened == 0) {
-		tty->closing = 1;
-		sdio_uart_shutdown(port);
-		tty_ldisc_flush(tty);
-		tty_port_tty_set(&port->port, NULL);
-		tty->driver_data = NULL;
-		tty->closing = 0;
-	}
-	mutex_unlock(&port->port.mutex);
-	sdio_uart_port_put(port);
+static void sdio_uart_hangup(struct tty_struct *tty)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	tty_port_hangup(&port->port);
 }
 
 static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
@@ -1021,6 +1048,12 @@ static const struct file_operations sdio_uart_proc_fops = {
 	.release	= single_release,
 };
 
+static const struct tty_port_operations sdio_uart_port_ops = {
+	.dtr_rts = uart_dtr_rts,
+	.shutdown = sdio_uart_shutdown,
+	.activate = sdio_uart_activate,
+};
+	
 static const struct tty_operations sdio_uart_ops = {
 	.open			= sdio_uart_open,
 	.close			= sdio_uart_close,
@@ -1031,9 +1064,12 @@ static const struct tty_operations sdio_uart_ops = {
 	.throttle		= sdio_uart_throttle,
 	.unthrottle		= sdio_uart_unthrottle,
 	.set_termios		= sdio_uart_set_termios,
+	.hangup			= sdio_uart_hangup,
 	.break_ctl		= sdio_uart_break_ctl,
 	.tiocmget		= sdio_uart_tiocmget,
 	.tiocmset		= sdio_uart_tiocmset,
+	.install		= sdio_uart_install,
+	.cleanup		= sdio_uart_cleanup,
 	.proc_fops		= &sdio_uart_proc_fops,
 };
 
@@ -1096,6 +1132,7 @@ static int sdio_uart_probe(struct sdio_func *func,
 	port->func = func;
 	sdio_set_drvdata(func, port);
 	tty_port_init(&port->port);
+	port->port.ops = &sdio_uart_port_ops;
 
 	ret = sdio_uart_add_port(port);
 	if (ret) {


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 07/11] sdio_uart: Fix termios handling
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
                   ` (5 preceding siblings ...)
  2009-11-18 14:19 ` [PATCH 06/11] sdio_uart: Switch to the open/close helpers Alan Cox
@ 2009-11-18 14:20 ` Alan Cox
  2009-11-18 14:20 ` [PATCH 08/11] sdio_uart: Use kfifo instead of the messy circ stuff Alan Cox
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:20 UTC (permalink / raw)
  To: greg, linux-kernel

Switching between two non standard baud rates fails because of the cflag
test. Do as we did elsewhere and just kill the "optimisation".

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 1be90bc..ffa56cb 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -902,12 +902,6 @@ static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_t
 	struct sdio_uart_port *port = tty->driver_data;
 	unsigned int cflag = tty->termios->c_cflag;
 
-#define RELEVANT_IFLAG(iflag)	((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-	if ((cflag ^ old_termios->c_cflag) == 0 &&
-	    RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
-		return;
-
 	if (sdio_uart_claim_func(port) != 0)
 		return;
 


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 08/11] sdio_uart: Use kfifo instead of the messy circ stuff
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
                   ` (6 preceding siblings ...)
  2009-11-18 14:20 ` [PATCH 07/11] sdio_uart: Fix termios handling Alan Cox
@ 2009-11-18 14:20 ` Alan Cox
  2009-11-18 14:20 ` [PATCH 09/11] sdio_uart: Style fixes Alan Cox
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:20 UTC (permalink / raw)
  To: greg, linux-kernel

Probably all the tty code should switch to this, especially when the new
lockless kfifo is merged.

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |   92 +++++++++++++-----------------------------
 1 files changed, 29 insertions(+), 63 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index ffa56cb..4139b24 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -32,7 +32,7 @@
 #include <linux/mutex.h>
 #include <linux/seq_file.h>
 #include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
+#include <linux/kfifo.h>
 #include <linux/gfp.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -46,18 +46,9 @@
 #define UART_NR		8	/* Number of UARTs this driver can handle */
 
 
-#define UART_XMIT_SIZE	PAGE_SIZE
+#define FIFO_SIZE	PAGE_SIZE
 #define WAKEUP_CHARS	256
 
-#define circ_empty(circ)	((circ)->head == (circ)->tail)
-#define circ_clear(circ)	((circ)->head = (circ)->tail = 0)
-
-#define circ_chars_pending(circ) \
-		(CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))
-
-#define circ_chars_free(circ) \
-		(CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
-
 
 struct uart_icount {
 	__u32	cts;
@@ -81,7 +72,7 @@ struct sdio_uart_port {
 	struct mutex		func_lock;
 	struct task_struct	*in_sdio_uart_irq;
 	unsigned int		regs_offset;
-	struct circ_buf		xmit;
+	struct kfifo		*xmit_fifo;
 	spinlock_t		write_lock;
 	struct uart_icount	icount;
 	unsigned int		uartclk;
@@ -103,6 +94,9 @@ static int sdio_uart_add_port(struct sdio_uart_port *port)
 	kref_init(&port->kref);
 	mutex_init(&port->func_lock);
 	spin_lock_init(&port->write_lock);
+	port->xmit_fifo = kfifo_alloc(FIFO_SIZE, GFP_KERNEL, &port->write_lock);
+	if (port->xmit_fifo == NULL)
+		return -ENOMEM;
 
 	spin_lock(&sdio_uart_table_lock);
 	for (index = 0; index < UART_NR; index++) {
@@ -138,6 +132,7 @@ static void sdio_uart_port_destroy(struct kref *kref)
 {
 	struct sdio_uart_port *port =
 		container_of(kref, struct sdio_uart_port, kref);
+	kfifo_free(port->xmit_fifo);
 	kfree(port);
 }
 
@@ -452,9 +447,11 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
 
 static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
 {
-	struct circ_buf *xmit = &port->xmit;
+	struct kfifo *xmit = port->xmit_fifo;
 	int count;
 	struct tty_struct *tty;
+	u8 iobuf[16];
+	int len;
 
 	if (port->x_char) {
 		sdio_out(port, UART_TX, port->x_char);
@@ -465,25 +462,22 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
 
 	tty = tty_port_tty_get(&port->port);
 
-	if (tty == NULL || circ_empty(xmit) || tty->stopped || tty->hw_stopped) {
+	if (tty == NULL || !kfifo_len(xmit) || tty->stopped || tty->hw_stopped) {
 		sdio_uart_stop_tx(port);
 		tty_kref_put(tty);
 		return;
 	}
 
-	count = 16;
-	do {
-		sdio_out(port, UART_TX, xmit->buf[xmit->tail]);
-		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+	len = kfifo_get(xmit, iobuf, 16);
+	for (count = 0; count < len; count++) {
+		sdio_out(port, UART_TX, iobuf[count]);
 		port->icount.tx++;
-		if (circ_empty(xmit))
-			break;
-	} while (--count > 0);
+	}
 
-	if (circ_chars_pending(xmit) < WAKEUP_CHARS)
+	if (len < WAKEUP_CHARS)
 		tty_wakeup(tty);
 
-	if (circ_empty(xmit))
+	if (len == 0)
 		sdio_uart_stop_tx(port);
 	tty_kref_put(tty);
 }
@@ -597,7 +591,6 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
 {
 	struct sdio_uart_port *port =
 			container_of(tport, struct sdio_uart_port, port);
-	unsigned long page;
 	int ret;
 
 	/*
@@ -606,22 +599,17 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
 	 */
 	set_bit(TTY_IO_ERROR, &tty->flags);
 
-	/* Initialise and allocate the transmit buffer. */
-	page = __get_free_page(GFP_KERNEL);
-	if (!page)
-		return -ENOMEM;
-	port->xmit.buf = (unsigned char *)page;
-	circ_clear(&port->xmit);
+	kfifo_reset(port->xmit_fifo);
 
 	ret = sdio_uart_claim_func(port);
 	if (ret)
-		goto err1;
+		return ret;
 	ret = sdio_enable_func(port->func);
 	if (ret)
-		goto err2;
+		goto err1;
 	ret = sdio_claim_irq(port->func, sdio_uart_irq);
 	if (ret)
-		goto err3;
+		goto err2;
 
 	/*
 	 * Clear the FIFO buffers and disable them.
@@ -665,12 +653,10 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
 	sdio_uart_release_func(port);
 	return 0;
 
-err3:
-	sdio_disable_func(port->func);
 err2:
-	sdio_uart_release_func(port);
+	sdio_disable_func(port->func);
 err1:
-	free_page((unsigned long)port->xmit.buf);
+	sdio_uart_release_func(port);
 	return ret;
 }
 
@@ -689,11 +675,9 @@ static void sdio_uart_shutdown(struct tty_port *tport)
 {
 	struct sdio_uart_port *port =
 			container_of(tport, struct sdio_uart_port, port);
-	int ret;
 
-	ret = sdio_uart_claim_func(port);
-	if (ret)
-		goto skip;
+	if (sdio_uart_claim_func(port))
+		return;
 
 	sdio_uart_stop_rx(port);
 
@@ -715,10 +699,6 @@ static void sdio_uart_shutdown(struct tty_port *tport)
 	sdio_disable_func(port->func);
 
 	sdio_uart_release_func(port);
-
-skip:
-	/* Free the transmit buffer page. */
-	free_page((unsigned long)port->xmit.buf);
 }
 
 /**
@@ -789,26 +769,12 @@ static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
 			   int count)
 {
 	struct sdio_uart_port *port = tty->driver_data;
-	struct circ_buf *circ = &port->xmit;
-	int c, ret = 0;
+	int ret;
 
 	if (!port->func)
 		return -ENODEV;
 
-	spin_lock(&port->write_lock);
-	while (1) {
-		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
-		if (count < c)
-			c = count;
-		if (c <= 0)
-			break;
-		memcpy(circ->buf + circ->head, buf, c);
-		circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
-		buf += c;
-		count -= c;
-		ret += c;
-	}
-	spin_unlock(&port->write_lock);
+	ret = kfifo_put(port->xmit_fifo, buf, count);
 
 	if ( !(port->ier & UART_IER_THRI)) {
 		int err = sdio_uart_claim_func(port);
@@ -826,13 +792,13 @@ static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
 static int sdio_uart_write_room(struct tty_struct *tty)
 {
 	struct sdio_uart_port *port = tty->driver_data;
-	return port ? circ_chars_free(&port->xmit) : 0;
+	return FIFO_SIZE - kfifo_len(port->xmit_fifo);
 }
 
 static int sdio_uart_chars_in_buffer(struct tty_struct *tty)
 {
 	struct sdio_uart_port *port = tty->driver_data;
-	return port ? circ_chars_pending(&port->xmit) : 0;
+	return kfifo_len(port->xmit_fifo);
 }
 
 static void sdio_uart_send_xchar(struct tty_struct *tty, char ch)


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 09/11] sdio_uart: Style fixes
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
                   ` (7 preceding siblings ...)
  2009-11-18 14:20 ` [PATCH 08/11] sdio_uart: Use kfifo instead of the messy circ stuff Alan Cox
@ 2009-11-18 14:20 ` Alan Cox
  2009-11-18 14:20 ` [PATCH 10/11] sdio_uart: Fix the locking on "func" for new code Alan Cox
  2009-11-18 14:21 ` [PATCH 11/11] sdio_uart: add modem functionality Alan Cox
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:20 UTC (permalink / raw)
  To: greg, linux-kernel

Running the current code through checkpatch shows a few bits of noise
mostly but not entirely from before the changes.

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |   25 +++++++++++++------------
 1 files changed, 13 insertions(+), 12 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 4139b24..f14338b 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -462,7 +462,8 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
 
 	tty = tty_port_tty_get(&port->port);
 
-	if (tty == NULL || !kfifo_len(xmit) || tty->stopped || tty->hw_stopped) {
+	if (tty == NULL || !kfifo_len(xmit)
+				|| tty->stopped || tty->hw_stopped) {
 		sdio_uart_stop_tx(port);
 		tty_kref_put(tty);
 		return;
@@ -633,7 +634,7 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
 	 */
 	sdio_out(port, UART_LCR, UART_LCR_WLEN8);
 
-	port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
+	port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
 	port->mctrl = TIOCM_OUT2;
 
 	sdio_uart_change_speed(port, tty->termios, NULL);
@@ -660,7 +661,6 @@ err1:
 	return ret;
 }
 
-	
 /**
  *	sdio_uart_shutdown	-	stop hardware
  *	@tport: tty port to shut down
@@ -725,7 +725,6 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
 	} else
 		sdio_uart_port_put(port);
 	return ret;
-		
 }
 
 /**
@@ -765,7 +764,7 @@ static void sdio_uart_hangup(struct tty_struct *tty)
 	tty_port_hangup(&port->port);
 }
 
-static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
+static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
 			   int count)
 {
 	struct sdio_uart_port *port = tty->driver_data;
@@ -776,7 +775,7 @@ static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
 
 	ret = kfifo_put(port->xmit_fifo, buf, count);
 
-	if ( !(port->ier & UART_IER_THRI)) {
+	if (!(port->ier & UART_IER_THRI)) {
 		int err = sdio_uart_claim_func(port);
 		if (!err) {
 			sdio_uart_start_tx(port);
@@ -863,7 +862,8 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
 	sdio_uart_release_func(port);
 }
 
-static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+static void sdio_uart_set_termios(struct tty_struct *tty,
+						struct ktermios *old_termios)
 {
 	struct sdio_uart_port *port = tty->driver_data;
 	unsigned int cflag = tty->termios->c_cflag;
@@ -942,7 +942,7 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
 	int result;
 
 	result = sdio_uart_claim_func(port);
-	if(!result) {
+	if (!result) {
 		sdio_uart_update_mctrl(port, set, clear);
 		sdio_uart_release_func(port);
 	}
@@ -960,7 +960,7 @@ static int sdio_uart_proc_show(struct seq_file *m, void *v)
 		struct sdio_uart_port *port = sdio_uart_port_get(i);
 		if (port) {
 			seq_printf(m, "%d: uart:SDIO", i);
-			if(capable(CAP_SYS_ADMIN)) {
+			if (capable(CAP_SYS_ADMIN)) {
 				seq_printf(m, " tx:%d rx:%d",
 					      port->icount.tx, port->icount.rx);
 				if (port->icount.frame)
@@ -1013,7 +1013,7 @@ static const struct tty_port_operations sdio_uart_port_ops = {
 	.shutdown = sdio_uart_shutdown,
 	.activate = sdio_uart_activate,
 };
-	
+
 static const struct tty_operations sdio_uart_ops = {
 	.open			= sdio_uart_open,
 	.close			= sdio_uart_close,
@@ -1066,7 +1066,7 @@ static int sdio_uart_probe(struct sdio_func *func,
 		}
 		if (!tpl) {
 			printk(KERN_WARNING
-			       "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
+       "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
 			       sdio_func_id(func));
 			kfree(port);
 			return -EINVAL;
@@ -1099,7 +1099,8 @@ static int sdio_uart_probe(struct sdio_func *func,
 		kfree(port);
 	} else {
 		struct device *dev;
-		dev = tty_register_device(sdio_uart_tty_driver, port->index, &func->dev);
+		dev = tty_register_device(sdio_uart_tty_driver,
+						port->index, &func->dev);
 		if (IS_ERR(dev)) {
 			sdio_uart_port_remove(port);
 			ret = PTR_ERR(dev);


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 10/11] sdio_uart: Fix the locking on "func" for new code
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
                   ` (8 preceding siblings ...)
  2009-11-18 14:20 ` [PATCH 09/11] sdio_uart: Style fixes Alan Cox
@ 2009-11-18 14:20 ` Alan Cox
  2009-11-18 14:21 ` [PATCH 11/11] sdio_uart: add modem functionality Alan Cox
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:20 UTC (permalink / raw)
  To: greg, linux-kernel

The new dtr_rts function didn't take the port->func lock as it should
so add use of the lock there.


Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index f14338b..6d8f019 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -567,10 +567,14 @@ static void uart_dtr_rts(struct tty_port *tport, int onoff)
 {
 	struct sdio_uart_port *port =
 			container_of(tport, struct sdio_uart_port, port);
+	int ret = sdio_uart_claim_func(port);
+	if (ret)
+		return;
 	if (onoff == 0)
 		sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 	else
 		sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+	sdio_uart_release_func(port);
 }
 
 /**


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 11/11] sdio_uart: add modem functionality
  2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
                   ` (9 preceding siblings ...)
  2009-11-18 14:20 ` [PATCH 10/11] sdio_uart: Fix the locking on "func" for new code Alan Cox
@ 2009-11-18 14:21 ` Alan Cox
  10 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-18 14:21 UTC (permalink / raw)
  To: greg, linux-kernel

Add the POSIX block for carrier

Linux TIOCMIWAIT functionality is still lacking from the driver.

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/mmc/card/sdio_uart.c |   33 ++++++++++++++++++++++++++++++++-
 1 files changed, 32 insertions(+), 1 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 6d8f019..edf2f33 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/mutex.h>
 #include <linux/seq_file.h>
 #include <linux/serial_reg.h>
@@ -77,6 +78,7 @@ struct sdio_uart_port {
 	struct uart_icount	icount;
 	unsigned int		uartclk;
 	unsigned int		mctrl;
+	unsigned int		rx_mctrl;
 	unsigned int		read_status_mask;
 	unsigned int		ignore_status_mask;
 	unsigned char		x_char;
@@ -215,6 +217,8 @@ static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
 	unsigned char status;
 	unsigned int ret;
 
+	/* FIXME: What stops this losing the delta bits and breaking
+	   sdio_uart_check_modem_status ? */
 	status = sdio_in(port, UART_MSR);
 
 	ret = 0;
@@ -497,8 +501,20 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
 		port->icount.rng++;
 	if (status & UART_MSR_DDSR)
 		port->icount.dsr++;
-	if (status & UART_MSR_DDCD)
+	if (status & UART_MSR_DDCD) {
 		port->icount.dcd++;
+		/* DCD raise - wake for open */
+		if (status & UART_MSR_DCD)
+			wake_up_interruptible(&port->port.open_wait);
+		else {
+			/* DCD drop - hang up if tty attached */
+			tty = tty_port_tty_get(&port->port);
+			if (tty) {
+				tty_hangup(tty);
+				tty_kref_put(tty);
+			}
+		}
+	}
 	if (status & UART_MSR_DCTS) {
 		port->icount.cts++;
 		tty = tty_port_tty_get(&port->port);
@@ -554,6 +570,20 @@ static void sdio_uart_irq(struct sdio_func *func)
 	port->in_sdio_uart_irq = NULL;
 }
 
+static int uart_carrier_raised(struct tty_port *tport)
+{
+	struct sdio_uart_port *port =
+			container_of(tport, struct sdio_uart_port, port);
+	unsigned int ret = sdio_uart_claim_func(port);
+	if (ret)	/* Missing hardware shoudn't block for carrier */
+		return 1;
+	ret = sdio_uart_get_mctrl(port);
+	sdio_uart_release_func(port);
+	if (ret & TIOCM_CAR)
+		return 1;
+	return 0;
+}
+
 /**
  *	uart_dtr_rts		-	 port helper to set uart signals
  *	@tport: tty port to be updated
@@ -1014,6 +1044,7 @@ static const struct file_operations sdio_uart_proc_fops = {
 
 static const struct tty_port_operations sdio_uart_port_ops = {
 	.dtr_rts = uart_dtr_rts,
+	.carrier_raised = uart_carrier_raised,
 	.shutdown = sdio_uart_shutdown,
 	.activate = sdio_uart_activate,
 };


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 06/11] sdio_uart: Switch to the open/close helpers
  2009-11-18 14:19 ` [PATCH 06/11] sdio_uart: Switch to the open/close helpers Alan Cox
@ 2009-11-20 17:35   ` Greg KH
  2009-11-20 19:23     ` Alan Cox
  0 siblings, 1 reply; 15+ messages in thread
From: Greg KH @ 2009-11-20 17:35 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-kernel

On Wed, Nov 18, 2009 at 02:19:57PM +0000, Alan Cox wrote:
> Gets us proper tty semantics, removes some code and fixes up a few corner
> case races (hangup during open etc)
> 
> Signed-off-by: Alan Cox <alan@linux.intel.com>

Something is wierd here, this patch doesn't apply.  And if I do it by
hand and fix up the errors, then patch 7 doesn't apply.

Wierd.

How about I take the first 5 and then you resync and send me the next 6?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 06/11] sdio_uart: Switch to the open/close helpers
  2009-11-20 17:35   ` Greg KH
@ 2009-11-20 19:23     ` Alan Cox
  0 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-20 19:23 UTC (permalink / raw)
  To: Greg KH; +Cc: Alan Cox, linux-kernel

> Something is wierd here, this patch doesn't apply.  And if I do it by
> hand and fix up the errors, then patch 7 doesn't apply.
> 
> Wierd.

wEIrd (sorry pet hate)

> How about I take the first 5 and then you resync and send me the next 6?

Works for me.

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2009-11-20 19:21 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-18 14:18 [PATCH 00/11] Series short description Alan Cox
2009-11-18 14:19 ` [PATCH 01/11] tty_port: Move hupcl handling Alan Cox
2009-11-18 14:19 ` [PATCH 02/11] sdio_uart: use tty_port Alan Cox
2009-11-18 14:19 ` [PATCH 03/11] sdio_uart: Fix oops caused by the previous changeset Alan Cox
2009-11-18 14:19 ` [PATCH 04/11] sdio_uart: refcount the tty objects Alan Cox
2009-11-18 14:19 ` [PATCH 05/11] sdio_uart: Move the open lock Alan Cox
2009-11-18 14:19 ` [PATCH 06/11] sdio_uart: Switch to the open/close helpers Alan Cox
2009-11-20 17:35   ` Greg KH
2009-11-20 19:23     ` Alan Cox
2009-11-18 14:20 ` [PATCH 07/11] sdio_uart: Fix termios handling Alan Cox
2009-11-18 14:20 ` [PATCH 08/11] sdio_uart: Use kfifo instead of the messy circ stuff Alan Cox
2009-11-18 14:20 ` [PATCH 09/11] sdio_uart: Style fixes Alan Cox
2009-11-18 14:20 ` [PATCH 10/11] sdio_uart: Fix the locking on "func" for new code Alan Cox
2009-11-18 14:21 ` [PATCH 11/11] sdio_uart: add modem functionality Alan Cox
  -- strict thread matches above, loose matches on Subject: below --
2009-11-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
2009-11-03 14:18 ` [PATCH 06/11] sdio_uart: Switch to the open/close helpers Alan Cox

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox