public inbox for linux-mmc@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] Sort out sdio_uart - stage two
@ 2009-11-03 14:17 Alan Cox
  2009-11-03 14:17 ` [PATCH 01/11] tty_port: Move hupcl handling Alan Cox
                   ` (11 more replies)
  0 siblings, 12 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:17 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

With the bugs Nicolas reported hopefully now nailed.
---

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 |  392 ++++++++++++++++++++++++------------------
 2 files changed, 233 insertions(+), 172 deletions(-)

-- 
"The IETF already has more than enough RFCs that codify the obvious, make
stupidity illegal, support truth, justice, and the IETF way, and generally
demonstrate the author is a brilliant and valuable Contributor to The
Standards Process." -- Vernon Schryver


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

* [PATCH 01/11] tty_port: Move hupcl handling
  2009-11-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
@ 2009-11-03 14:17 ` Alan Cox
  2009-11-03 14:17 ` [PATCH 02/11] sdio_uart: use tty_port Alan Cox
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:17 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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 da12fae..cf4b16a 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -357,6 +357,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 */
@@ -368,11 +376,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-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
  2009-11-03 14:17 ` [PATCH 01/11] tty_port: Move hupcl handling Alan Cox
@ 2009-11-03 14:17 ` Alan Cox
  2009-11-03 14:17 ` [PATCH 03/11] sdio_uart: Fix oops caused by the previous changeset Alan Cox
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:17 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
  2009-11-03 14:17 ` [PATCH 01/11] tty_port: Move hupcl handling Alan Cox
  2009-11-03 14:17 ` [PATCH 02/11] sdio_uart: use tty_port Alan Cox
@ 2009-11-03 14:17 ` Alan Cox
  2009-11-03 14:17 ` [PATCH 04/11] sdio_uart: refcount the tty objects Alan Cox
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:17 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
                   ` (2 preceding siblings ...)
  2009-11-03 14:17 ` [PATCH 03/11] sdio_uart: Fix oops caused by the previous changeset Alan Cox
@ 2009-11-03 14:17 ` Alan Cox
  2009-11-03 14:18 ` [PATCH 05/11] sdio_uart: Move the open lock Alan Cox
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:17 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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 |   58 ++++++++++++++++++++++++++++++------------
 1 files changed, 41 insertions(+), 17 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 671fe5e..51aeaf6 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,7 +465,10 @@ 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);
 		return;
 	}
@@ -474,12 +487,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 +508,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 +524,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
 				}
 			}
 		}
+		tty_kref_put(tty);
 	}
 }
 
@@ -548,8 +564,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 +578,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 +632,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 +641,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 +659,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 +712,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 +751,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-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
                   ` (3 preceding siblings ...)
  2009-11-03 14:17 ` [PATCH 04/11] sdio_uart: refcount the tty objects Alan Cox
@ 2009-11-03 14:18 ` Alan Cox
  2009-11-03 14:18 ` [PATCH 06/11] sdio_uart: Switch to the open/close helpers Alan Cox
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:18 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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 51aeaf6..f76741d 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);
@@ -698,14 +696,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;
 	}
@@ -717,13 +715,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;
 }
 
@@ -734,7 +732,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);
 
 	/*
@@ -743,7 +741,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;
 	}
 
@@ -755,7 +753,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-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
                   ` (4 preceding siblings ...)
  2009-11-03 14:18 ` [PATCH 05/11] sdio_uart: Move the open lock Alan Cox
@ 2009-11-03 14:18 ` Alan Cox
  2009-11-03 14:18 ` [PATCH 07/11] sdio_uart: Fix termios handling Alan Cox
                   ` (5 subsequent siblings)
  11 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 07/11] sdio_uart: Fix termios handling
  2009-11-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
                   ` (5 preceding siblings ...)
  2009-11-03 14:18 ` [PATCH 06/11] sdio_uart: Switch to the open/close helpers Alan Cox
@ 2009-11-03 14:18 ` Alan Cox
  2009-11-03 14:18 ` [PATCH 08/11] sdio_uart: Use kfifo instead of the messy circ stuff Alan Cox
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:18 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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 3e2ae66..d41aa35 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -901,12 +901,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-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
                   ` (6 preceding siblings ...)
  2009-11-03 14:18 ` [PATCH 07/11] sdio_uart: Fix termios handling Alan Cox
@ 2009-11-03 14:18 ` Alan Cox
  2009-11-03 14:18 ` [PATCH 09/11] sdio_uart: Style fixes Alan Cox
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:18 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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 |   86 +++++++++++++-----------------------------
 1 files changed, 27 insertions(+), 59 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index d41aa35..674f3bf 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++) {
@@ -452,9 +446,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,24 +461,21 @@ 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);
 		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);
 }
@@ -605,22 +598,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.
@@ -664,12 +652,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;
 }
 
@@ -692,7 +678,7 @@ static void sdio_uart_shutdown(struct tty_port *tport)
 
 	ret = sdio_uart_claim_func(port);
 	if (ret)
-		goto skip;
+		return ret;
 
 	sdio_uart_stop_rx(port);
 
@@ -714,10 +700,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);
 }
 
 /**
@@ -788,26 +770,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);
@@ -825,13 +793,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-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
                   ` (7 preceding siblings ...)
  2009-11-03 14:18 ` [PATCH 08/11] sdio_uart: Use kfifo instead of the messy circ stuff Alan Cox
@ 2009-11-03 14:18 ` Alan Cox
  2009-11-03 14:18 ` [PATCH 10/11] sdio_uart: Fix the locking on "func" for new code Alan Cox
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:18 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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 |   33 +++++++++++++++------------------
 1 files changed, 15 insertions(+), 18 deletions(-)


diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 674f3bf..ebb5d4b 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -461,7 +461,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);
 		return;
 	}
@@ -589,7 +590,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;
 
 	/*
@@ -632,7 +632,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);
@@ -659,7 +659,6 @@ err1:
 	return ret;
 }
 
-	
 /**
  *	sdio_uart_shutdown	-	stop hardware
  *	@tport: tty port to shut down
@@ -674,11 +673,8 @@ 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)
-		return ret;
+	if (sdio_uart_claim_func(port))
+		return;
 
 	sdio_uart_stop_rx(port);
 
@@ -726,7 +722,6 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
 	} else
 		sdio_uart_port_put(port);
 	return ret;
-		
 }
 
 /**
@@ -766,7 +761,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;
@@ -777,7 +772,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);
@@ -864,7 +859,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;
@@ -943,7 +939,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);
 	}
@@ -961,7 +957,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)
@@ -1014,7 +1010,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,
@@ -1067,7 +1063,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;
@@ -1100,7 +1096,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-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
                   ` (8 preceding siblings ...)
  2009-11-03 14:18 ` [PATCH 09/11] sdio_uart: Style fixes Alan Cox
@ 2009-11-03 14:18 ` Alan Cox
  2009-11-03 14:19 ` [PATCH 11/11] sdio_uart: add modem functionality Alan Cox
  2009-11-03 19:58 ` [PATCH 00/11] Sort out sdio_uart - stage two Nicolas Pitre
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:18 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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 ebb5d4b..0a3acfb 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -565,10 +565,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-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
                   ` (9 preceding siblings ...)
  2009-11-03 14:18 ` [PATCH 10/11] sdio_uart: Fix the locking on "func" for new code Alan Cox
@ 2009-11-03 14:19 ` Alan Cox
  2009-11-03 19:58 ` [PATCH 00/11] Sort out sdio_uart - stage two Nicolas Pitre
  11 siblings, 0 replies; 15+ messages in thread
From: Alan Cox @ 2009-11-03 14:19 UTC (permalink / raw)
  To: linux-mmc, linux-kernel, nico

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 0a3acfb..e72e2f2 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>
@@ -214,6 +216,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;
@@ -495,8 +499,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);
@@ -552,6 +568,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
@@ -1011,6 +1041,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 00/11] Sort out sdio_uart - stage two
  2009-11-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
                   ` (10 preceding siblings ...)
  2009-11-03 14:19 ` [PATCH 11/11] sdio_uart: add modem functionality Alan Cox
@ 2009-11-03 19:58 ` Nicolas Pitre
  2009-11-04  0:54   ` Alan Cox
  11 siblings, 1 reply; 15+ messages in thread
From: Nicolas Pitre @ 2009-11-03 19:58 UTC (permalink / raw)
  To: Alan Cox; +Cc: linux-mmc, lkml

On Tue, 3 Nov 2009, Alan Cox wrote:

> With the bugs Nicolas reported hopefully now nailed.

Progress, but still not there yet.

I'm still using the same "cat /dev/ttySDIO0" test with a GPS card.

Yanking the card out does terminate the cat process properly.  Inserting 
the card back in and restarting cat always fails with:

	cat: /dev/ttySDIO0: Input/output error

The same thing occurs if I terminate cat with ^C instead of pulling the 
card out.

>From what I can see, sdio_uart_open() and sdio_uart_activate() are 
called on the first cat invocation, and then sdio_uart_close() and 
sdio_uart_shutdown() when cat is stopped with ^C.  However neither 
sdio_uart_open() nor sdio_uart_activate() is ever called anymore with 
any subsequent cat invocations until a reboot.  Some upper layer must 
have taken upon itself to return -EIO to user space.


Nicolas

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

* Re: [PATCH 00/11] Sort out sdio_uart - stage two
  2009-11-03 19:58 ` [PATCH 00/11] Sort out sdio_uart - stage two Nicolas Pitre
@ 2009-11-04  0:54   ` Alan Cox
  2009-11-04  1:48     ` Nicolas Pitre
  0 siblings, 1 reply; 15+ messages in thread
From: Alan Cox @ 2009-11-04  0:54 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: Alan Cox, linux-mmc, lkml

> >From what I can see, sdio_uart_open() and sdio_uart_activate() are 
> called on the first cat invocation, and then sdio_uart_close() and 
> sdio_uart_shutdown() when cat is stopped with ^C.  However neither 

I would have expected the cat to terminate when the port is unplugged
(and the uart remove method called - doing a hangup)

> sdio_uart_open() nor sdio_uart_activate() is ever called anymore with 
> any subsequent cat invocations until a reboot.  Some upper layer must 
> have taken upon itself to return -EIO to user space.

The first call into the driver is to sdio_uart_install which looks up the
port from tty->index and would blow up if for some reason the get method
failed.

Still digging.

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

* Re: [PATCH 00/11] Sort out sdio_uart - stage two
  2009-11-04  0:54   ` Alan Cox
@ 2009-11-04  1:48     ` Nicolas Pitre
  0 siblings, 0 replies; 15+ messages in thread
From: Nicolas Pitre @ 2009-11-04  1:48 UTC (permalink / raw)
  To: Alan Cox; +Cc: Alan Cox, linux-mmc, lkml

On Wed, 4 Nov 2009, Alan Cox wrote:

> > >From what I can see, sdio_uart_open() and sdio_uart_activate() are 
> > called on the first cat invocation, and then sdio_uart_close() and 
> > sdio_uart_shutdown() when cat is stopped with ^C.  However neither 
> 
> I would have expected the cat to terminate when the port is unplugged
> (and the uart remove method called - doing a hangup)

That works fine... the first time only.  After the card is inserted back 
then -EIO is always returned on open() from user space, same thing as 
subsequent open() after ^C.

> > sdio_uart_open() nor sdio_uart_activate() is ever called anymore with 
> > any subsequent cat invocations until a reboot.  Some upper layer must 
> > have taken upon itself to return -EIO to user space.
> 
> The first call into the driver is to sdio_uart_install which looks up the
> port from tty->index and would blow up if for some reason the get method
> failed.

Well, same issue: I see it being called the first time.  No calls what 
so ever afterward until the next reboot.


Nicolas

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

end of thread, other threads:[~2009-11-04  1:48 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-03 14:17 [PATCH 00/11] Sort out sdio_uart - stage two Alan Cox
2009-11-03 14:17 ` [PATCH 01/11] tty_port: Move hupcl handling Alan Cox
2009-11-03 14:17 ` [PATCH 02/11] sdio_uart: use tty_port Alan Cox
2009-11-03 14:17 ` [PATCH 03/11] sdio_uart: Fix oops caused by the previous changeset Alan Cox
2009-11-03 14:17 ` [PATCH 04/11] sdio_uart: refcount the tty objects Alan Cox
2009-11-03 14:18 ` [PATCH 05/11] sdio_uart: Move the open lock Alan Cox
2009-11-03 14:18 ` [PATCH 06/11] sdio_uart: Switch to the open/close helpers Alan Cox
2009-11-03 14:18 ` [PATCH 07/11] sdio_uart: Fix termios handling Alan Cox
2009-11-03 14:18 ` [PATCH 08/11] sdio_uart: Use kfifo instead of the messy circ stuff Alan Cox
2009-11-03 14:18 ` [PATCH 09/11] sdio_uart: Style fixes Alan Cox
2009-11-03 14:18 ` [PATCH 10/11] sdio_uart: Fix the locking on "func" for new code Alan Cox
2009-11-03 14:19 ` [PATCH 11/11] sdio_uart: add modem functionality Alan Cox
2009-11-03 19:58 ` [PATCH 00/11] Sort out sdio_uart - stage two Nicolas Pitre
2009-11-04  0:54   ` Alan Cox
2009-11-04  1:48     ` Nicolas Pitre

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