All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/15] Serial/tty follow up fixes for 2.6,31
@ 2009-06-22 17:30 Alan Cox
  2009-06-22 17:31 ` [PATCH 01/15] bfin_jtag_comm: clean up printk usage Alan Cox
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:30 UTC (permalink / raw)
  To: torvalds, linux-kernel

---

Alan Cox (3):
      msm: fixups to match current code
      tty: fix some bogns in the serqt_usb2 driver
      ppp: Fix throttling bugs

Jiri Slaby (3):
      vt_ioctl: fix lock imbalance
      pcmcia/cm4000: fix lock imbalance
      n_r3964: fix lock imbalance

Kevin Hilman (1):
      serial@ add OMAP wakeup-enable register

Mike Frysinger (3):
      serial: bfin_5xx: fix building as module when early printk is enabled
      serial: bfin_5xx: add missing spin_lock init
      bfin_jtag_comm: clean up printk usage

Paul Fulghum (1):
      tty: n_hdlc add buffer flushing

Peter Korsgaard (1):
      serial: samsung.c: mark s3c24xx_serial_remove as __devexit

Richard Röjfors (1):
      timbuart: Fix for tx_empty

Robert Love (1):
      msm_serial: serial driver for MSM7K onboard serial peripheral.

Roel Kluin (1):
      serial: fix off by one errors


 drivers/char/bfin_jtag_comm.c           |   30 +
 drivers/char/n_hdlc.c                   |   46 +-
 drivers/char/n_r3964.c                  |   26 +
 drivers/char/pcmcia/cm4000_cs.c         |    3 
 drivers/char/vt_ioctl.c                 |    3 
 drivers/net/ppp_async.c                 |    1 
 drivers/net/ppp_synctty.c               |    1 
 drivers/serial/Kconfig                  |   10 
 drivers/serial/Makefile                 |    1 
 drivers/serial/bfin_5xx.c               |    5 
 drivers/serial/msm_serial.c             |  772 +++++++++++++++++++++++++++++++
 drivers/serial/msm_serial.h             |  117 +++++
 drivers/serial/s3c2400.c                |    2 
 drivers/serial/s3c2410.c                |    2 
 drivers/serial/s3c2412.c                |    2 
 drivers/serial/s3c2440.c                |    2 
 drivers/serial/s3c24a0.c                |    2 
 drivers/serial/s3c6400.c                |    2 
 drivers/serial/samsung.c                |    2 
 drivers/serial/samsung.h                |    2 
 drivers/serial/sb1250-duart.c           |    6 
 drivers/serial/sunhv.c                  |    2 
 drivers/serial/timbuart.c               |   50 +-
 drivers/serial/zs.c                     |    6 
 drivers/staging/serqt_usb2/serqt_usb2.c |   29 -
 include/linux/serial_core.h             |    3 
 include/linux/serial_reg.h              |    1 
 27 files changed, 1029 insertions(+), 99 deletions(-)
 create mode 100644 drivers/serial/msm_serial.c
 create mode 100644 drivers/serial/msm_serial.h

-- 
ENOJOKE

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

* [PATCH 01/15] bfin_jtag_comm: clean up printk usage
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
@ 2009-06-22 17:31 ` Alan Cox
  2009-06-22 17:37 ` [PATCH 02/15] serial: bfin_5xx: add missing spin_lock init Alan Cox
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:31 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Mike Frysinger <vapier@gentoo.org>

The original patch garned some feedback and a v2 was posted, but that
version seems to have been missed when merging the driver.

At any rate, this cleans up the printk usage as suggested by Jiri Slaby.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/char/bfin_jtag_comm.c |   30 +++++++++++++++---------------
 1 files changed, 15 insertions(+), 15 deletions(-)


diff --git a/drivers/char/bfin_jtag_comm.c b/drivers/char/bfin_jtag_comm.c
index 44c113d..1d7c34c 100644
--- a/drivers/char/bfin_jtag_comm.c
+++ b/drivers/char/bfin_jtag_comm.c
@@ -8,6 +8,10 @@
  * Licensed under the GPL-2 or later.
  */
 
+#define DRV_NAME "bfin-jtag-comm"
+#define DEV_NAME "ttyBFJC"
+#define pr_fmt(fmt) DRV_NAME ": " fmt
+
 #include <linux/circ_buf.h>
 #include <linux/console.h>
 #include <linux/delay.h>
@@ -22,18 +26,14 @@
 #include <linux/tty_flip.h>
 #include <asm/atomic.h>
 
+#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
+
 /* See the Debug/Emulation chapter in the HRM */
 #define EMUDOF   0x00000001	/* EMUDAT_OUT full & valid */
 #define EMUDIF   0x00000002	/* EMUDAT_IN full & valid */
 #define EMUDOOVF 0x00000004	/* EMUDAT_OUT overflow */
 #define EMUDIOVF 0x00000008	/* EMUDAT_IN overflow */
 
-#define DRV_NAME "bfin-jtag-comm"
-#define DEV_NAME "ttyBFJC"
-
-#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
-#define debug(fmt, args...) pr_debug(DRV_NAME ": " fmt, ## args)
-
 static inline uint32_t bfin_write_emudat(uint32_t emudat)
 {
 	__asm__ __volatile__("emudat = %0;" : : "d"(emudat));
@@ -74,7 +74,7 @@ bfin_jc_emudat_manager(void *arg)
 	while (!kthread_should_stop()) {
 		/* no one left to give data to, so sleep */
 		if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
-			debug("waiting for readers\n");
+			pr_debug("waiting for readers\n");
 			__set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule();
 			__set_current_state(TASK_RUNNING);
@@ -82,7 +82,7 @@ bfin_jc_emudat_manager(void *arg)
 
 		/* no data available, so just chill */
 		if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
-			debug("waiting for data (in_len = %i) (circ: %i %i)\n",
+			pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
 				inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
 			if (inbound_len)
 				schedule();
@@ -99,11 +99,11 @@ bfin_jc_emudat_manager(void *arg)
 			if (tty != NULL) {
 				uint32_t emudat = bfin_read_emudat();
 				if (inbound_len == 0) {
-					debug("incoming length: 0x%08x\n", emudat);
+					pr_debug("incoming length: 0x%08x\n", emudat);
 					inbound_len = emudat;
 				} else {
 					size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
-					debug("  incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
+					pr_debug("  incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
 					inbound_len -= num_chars;
 					tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars);
 					tty_flip_buffer_push(tty);
@@ -117,7 +117,7 @@ bfin_jc_emudat_manager(void *arg)
 			if (outbound_len == 0) {
 				outbound_len = circ_cnt(&bfin_jc_write_buf);
 				bfin_write_emudat(outbound_len);
-				debug("outgoing length: 0x%08x\n", outbound_len);
+				pr_debug("outgoing length: 0x%08x\n", outbound_len);
 			} else {
 				struct tty_struct *tty;
 				int tail = bfin_jc_write_buf.tail;
@@ -136,7 +136,7 @@ bfin_jc_emudat_manager(void *arg)
 				if (tty)
 					tty_wakeup(tty);
 				mutex_unlock(&bfin_jc_tty_mutex);
-				debug("  outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
+				pr_debug("  outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
 			}
 		}
 	}
@@ -149,7 +149,7 @@ static int
 bfin_jc_open(struct tty_struct *tty, struct file *filp)
 {
 	mutex_lock(&bfin_jc_tty_mutex);
-	debug("open %lu\n", bfin_jc_count);
+	pr_debug("open %lu\n", bfin_jc_count);
 	++bfin_jc_count;
 	bfin_jc_tty = tty;
 	wake_up_process(bfin_jc_kthread);
@@ -161,7 +161,7 @@ static void
 bfin_jc_close(struct tty_struct *tty, struct file *filp)
 {
 	mutex_lock(&bfin_jc_tty_mutex);
-	debug("close %lu\n", bfin_jc_count);
+	pr_debug("close %lu\n", bfin_jc_count);
 	if (--bfin_jc_count == 0)
 		bfin_jc_tty = NULL;
 	wake_up_process(bfin_jc_kthread);
@@ -174,7 +174,7 @@ bfin_jc_circ_write(const unsigned char *buf, int count)
 {
 	int i;
 	count = min(count, circ_free(&bfin_jc_write_buf));
-	debug("going to write chunk of %i bytes\n", count);
+	pr_debug("going to write chunk of %i bytes\n", count);
 	for (i = 0; i < count; ++i)
 		circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i];
 	bfin_jc_write_buf.head += i;


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

* [PATCH 02/15] serial: bfin_5xx: add missing spin_lock init
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
  2009-06-22 17:31 ` [PATCH 01/15] bfin_jtag_comm: clean up printk usage Alan Cox
@ 2009-06-22 17:37 ` Alan Cox
  2009-06-22 17:41 ` [PATCH 03/15] serial: bfin_5xx: fix building as module when early printk is enabled Alan Cox
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:37 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Mike Frysinger <vapier@gentoo.org>

The Blackfin serial driver never initialized the spin_lock that is part of
the serial core structure, but we never noticed because spin_lock's are
rarely enabled on UP systems.  Yeah lockdep and friends.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/serial/bfin_5xx.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)


diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index e2f6b1b..d7fcca1 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -1110,6 +1110,7 @@ static void __init bfin_serial_init_ports(void)
 	bfin_serial_hw_init();
 
 	for (i = 0; i < nr_active_ports; i++) {
+		spin_lock_init(&bfin_serial_ports[i].port.lock);
 		bfin_serial_ports[i].port.uartclk   = get_sclk();
 		bfin_serial_ports[i].port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
 		bfin_serial_ports[i].port.ops       = &bfin_serial_pops;


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

* [PATCH 03/15] serial: bfin_5xx: fix building as module when early printk is enabled
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
  2009-06-22 17:31 ` [PATCH 01/15] bfin_jtag_comm: clean up printk usage Alan Cox
  2009-06-22 17:37 ` [PATCH 02/15] serial: bfin_5xx: add missing spin_lock init Alan Cox
@ 2009-06-22 17:41 ` Alan Cox
  2009-06-22 17:41 ` [PATCH 04/15] serial: fix off by one errors Alan Cox
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:41 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Mike Frysinger <vapier@gentoo.org>

Since early printk only makes sense/works when the serial driver is built
into the kernel, disable the option for this driver when it is going to be
built as a module.  Otherwise we get build failures due to the ifdef
handling.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/serial/bfin_5xx.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)


diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index d7fcca1..b4a7650 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -38,6 +38,10 @@
 #include <asm/cacheflush.h>
 #endif
 
+#ifdef CONFIG_SERIAL_BFIN_MODULE
+# undef CONFIG_EARLY_PRINTK
+#endif
+
 /* UART name and device definitions */
 #define BFIN_SERIAL_NAME	"ttyBF"
 #define BFIN_SERIAL_MAJOR	204


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

* [PATCH 04/15] serial: fix off by one errors
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (2 preceding siblings ...)
  2009-06-22 17:41 ` [PATCH 03/15] serial: bfin_5xx: fix building as module when early printk is enabled Alan Cox
@ 2009-06-22 17:41 ` Alan Cox
  2009-06-22 17:42 ` [PATCH 05/15] n_r3964: fix lock imbalance Alan Cox
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:41 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Roel Kluin <roel.kluin@gmail.com>

In zs_console_putchar() occurs:

	if (zs_transmit_drain(zport, irq))
		write_zsdata(zport, ch);

However if in zs_transmit_drain() no empty Tx Buffer occurs, limit reaches
-1 => true, and the write still occurs.

This patch changes postfix to prefix decrements in this and similar
functions to prevent similar mistakes in the future.  This decreases the
iterations with one but the chosen loop count was arbitrary anyway.

In sunhv limit reaches -1, not 0, so the test is off by one.

Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Maciej W. Rozycki <macro@linux-mips.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/serial/sb1250-duart.c |    6 +++---
 drivers/serial/sunhv.c        |    2 +-
 drivers/serial/zs.c           |    6 +++---
 3 files changed, 7 insertions(+), 7 deletions(-)


diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c
index a4fb343..319e8b8 100644
--- a/drivers/serial/sb1250-duart.c
+++ b/drivers/serial/sb1250-duart.c
@@ -204,7 +204,7 @@ static int sbd_receive_drain(struct sbd_port *sport)
 {
 	int loops = 10000;
 
-	while (sbd_receive_ready(sport) && loops--)
+	while (sbd_receive_ready(sport) && --loops)
 		read_sbdchn(sport, R_DUART_RX_HOLD);
 	return loops;
 }
@@ -218,7 +218,7 @@ static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport)
 {
 	int loops = 10000;
 
-	while (!sbd_transmit_ready(sport) && loops--)
+	while (!sbd_transmit_ready(sport) && --loops)
 		udelay(2);
 	return loops;
 }
@@ -232,7 +232,7 @@ static int sbd_line_drain(struct sbd_port *sport)
 {
 	int loops = 10000;
 
-	while (!sbd_transmit_empty(sport) && loops--)
+	while (!sbd_transmit_empty(sport) && --loops)
 		udelay(2);
 	return loops;
 }
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index a94a2ab..1df5325 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -461,7 +461,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
 					break;
 				udelay(1);
 			}
-			if (limit <= 0)
+			if (limit < 0)
 				break;
 			page_bytes -= written;
 			ra += written;
diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c
index 9e6a873..d8c2809 100644
--- a/drivers/serial/zs.c
+++ b/drivers/serial/zs.c
@@ -231,7 +231,7 @@ static int zs_receive_drain(struct zs_port *zport)
 {
 	int loops = 10000;
 
-	while ((read_zsreg(zport, R0) & Rx_CH_AV) && loops--)
+	while ((read_zsreg(zport, R0) & Rx_CH_AV) && --loops)
 		read_zsdata(zport);
 	return loops;
 }
@@ -241,7 +241,7 @@ static int zs_transmit_drain(struct zs_port *zport, int irq)
 	struct zs_scc *scc = zport->scc;
 	int loops = 10000;
 
-	while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && loops--) {
+	while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && --loops) {
 		zs_spin_unlock_cond_irq(&scc->zlock, irq);
 		udelay(2);
 		zs_spin_lock_cond_irq(&scc->zlock, irq);
@@ -254,7 +254,7 @@ static int zs_line_drain(struct zs_port *zport, int irq)
 	struct zs_scc *scc = zport->scc;
 	int loops = 10000;
 
-	while (!(read_zsreg(zport, R1) & ALL_SNT) && loops--) {
+	while (!(read_zsreg(zport, R1) & ALL_SNT) && --loops) {
 		zs_spin_unlock_cond_irq(&scc->zlock, irq);
 		udelay(2);
 		zs_spin_lock_cond_irq(&scc->zlock, irq);


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

* [PATCH 05/15] n_r3964: fix lock imbalance
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (3 preceding siblings ...)
  2009-06-22 17:41 ` [PATCH 04/15] serial: fix off by one errors Alan Cox
@ 2009-06-22 17:42 ` Alan Cox
  2009-06-22 17:42 ` [PATCH 06/15] pcmcia/cm4000: " Alan Cox
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:42 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Jiri Slaby <jirislaby@gmail.com>

There is omitted BKunL in r3964_read.

Centralize the paths to one point with one unlock.

Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Cc: stable@kernel.org
---

 drivers/char/n_r3964.c |   26 ++++++++++++++------------
 1 files changed, 14 insertions(+), 12 deletions(-)


diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index d2e93e3..2e99158 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -1062,7 +1062,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 	struct r3964_client_info *pClient;
 	struct r3964_message *pMsg;
 	struct r3964_client_message theMsg;
-	int count;
+	int ret;
 
 	TRACE_L("read()");
 
@@ -1074,8 +1074,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 		if (pMsg == NULL) {
 			/* no messages available. */
 			if (file->f_flags & O_NONBLOCK) {
-				unlock_kernel();
-				return -EAGAIN;
+				ret = -EAGAIN;
+				goto unlock;
 			}
 			/* block until there is a message: */
 			wait_event_interruptible(pInfo->read_wait,
@@ -1085,29 +1085,31 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 		/* If we still haven't got a message, we must have been signalled */
 
 		if (!pMsg) {
-			unlock_kernel();
-			return -EINTR;
+			ret = -EINTR;
+			goto unlock;
 		}
 
 		/* deliver msg to client process: */
 		theMsg.msg_id = pMsg->msg_id;
 		theMsg.arg = pMsg->arg;
 		theMsg.error_code = pMsg->error_code;
-		count = sizeof(struct r3964_client_message);
+		ret = sizeof(struct r3964_client_message);
 
 		kfree(pMsg);
 		TRACE_M("r3964_read - msg kfree %p", pMsg);
 
-		if (copy_to_user(buf, &theMsg, count)) {
-			unlock_kernel();
-			return -EFAULT;
+		if (copy_to_user(buf, &theMsg, ret)) {
+			ret = -EFAULT;
+			goto unlock;
 		}
 
-		TRACE_PS("read - return %d", count);
-		return count;
+		TRACE_PS("read - return %d", ret);
+		goto unlock;
 	}
+	ret = -EPERM;
+unlock:
 	unlock_kernel();
-	return -EPERM;
+	return ret;
 }
 
 static ssize_t r3964_write(struct tty_struct *tty, struct file *file,


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

* [PATCH 06/15] pcmcia/cm4000: fix lock imbalance
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (4 preceding siblings ...)
  2009-06-22 17:42 ` [PATCH 05/15] n_r3964: fix lock imbalance Alan Cox
@ 2009-06-22 17:42 ` Alan Cox
  2009-06-22 17:42 ` [PATCH 07/15] vt_ioctl: " Alan Cox
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:42 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Jiri Slaby <jirislaby@gmail.com>

Don't return from switch/case, break instead, so that we unlock BKL.

Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Cc: stable@kernel.org
---

 drivers/char/pcmcia/cm4000_cs.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)


diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index dbb9125..881934c 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1575,7 +1575,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		clear_bit(LOCK_IO, &dev->flags);
 		wake_up_interruptible(&dev->ioq);
 
-		return 0;
+		rc = 0;
+		break;
 	case CM_IOCSPTS:
 		{
 			struct ptsreq krnptsreq;


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

* [PATCH 07/15] vt_ioctl: fix lock imbalance
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (5 preceding siblings ...)
  2009-06-22 17:42 ` [PATCH 06/15] pcmcia/cm4000: " Alan Cox
@ 2009-06-22 17:42 ` Alan Cox
  2009-06-22 17:42 ` [PATCH 08/15] ppp: Fix throttling bugs Alan Cox
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:42 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Jiri Slaby <jirislaby@gmail.com>

Don't return from switch/case directly in vt_ioctl. Set ret and break
instead so that we unlock BKL.

Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Cc: stable@kernel.org
---

 drivers/char/vt_ioctl.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)


diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index e6ce632..7539bed 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -396,7 +396,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
 	kbd = kbd_table + console;
 	switch (cmd) {
 	case TIOCLINUX:
-		return tioclinux(tty, arg);
+		ret = tioclinux(tty, arg);
+		break;
 	case KIOCSOUND:
 		if (!perm)
 			goto eperm;


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

* [PATCH 08/15] ppp: Fix throttling bugs
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (6 preceding siblings ...)
  2009-06-22 17:42 ` [PATCH 07/15] vt_ioctl: " Alan Cox
@ 2009-06-22 17:42 ` Alan Cox
  2009-06-22 17:42 ` [PATCH 09/15] tty: fix some bogns in the serqt_usb2 driver Alan Cox
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:42 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Alan Cox <alan@linux.intel.com>

The ppp layer goes around calling the unthrottle method from non sleeping
paths. This isn't safe because the unthrottle methods in the tty layer need
to be able to sleep (consider a USB dongle).

Until now this didn't show up because the ppp layer never actually throttled
a port so the unthrottle was always a no-op. Currently it's a mutex taking
path so warnings are spewed if the unthrottle occurs via certain paths.

Fix this by removing the unneccessary unthrottle calls.

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

 drivers/net/ppp_async.c   |    1 -
 drivers/net/ppp_synctty.c |    1 -
 2 files changed, 0 insertions(+), 2 deletions(-)


diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 6de8399..17c116b 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -356,7 +356,6 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
 	if (!skb_queue_empty(&ap->rqueue))
 		tasklet_schedule(&ap->tsk);
 	ap_put(ap);
-	tty_unthrottle(tty);
 }
 
 static void
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index d2fa2db..aa3d39f 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -397,7 +397,6 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
 	if (!skb_queue_empty(&ap->rqueue))
 		tasklet_schedule(&ap->tsk);
 	sp_put(ap);
-	tty_unthrottle(tty);
 }
 
 static void


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

* [PATCH 09/15] tty: fix some bogns in the serqt_usb2 driver
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (7 preceding siblings ...)
  2009-06-22 17:42 ` [PATCH 08/15] ppp: Fix throttling bugs Alan Cox
@ 2009-06-22 17:42 ` Alan Cox
  2009-06-22 17:42 ` [PATCH 10/15] serial@ add OMAP wakeup-enable register Alan Cox
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:42 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Alan Cox <alan@linux.intel.com>

Remove the replicated urban legends from the comments and fix a couple of
other silly calls

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

 drivers/staging/serqt_usb2/serqt_usb2.c |   29 ++++++++++-------------------
 1 files changed, 10 insertions(+), 19 deletions(-)


diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index 581232b..90b29b5 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -284,21 +284,12 @@ static void ProcessModemStatus(struct quatech_port *qt_port,
 	return;
 }
 
-static void ProcessRxChar(struct usb_serial_port *port, unsigned char Data)
+static void ProcessRxChar(struct tty_struct *tty, struct usb_serial_port *port,
+						unsigned char data)
 {
-	struct tty_struct *tty;
 	struct urb *urb = port->read_urb;
-	tty = tty_port_tty_get(&port->port);
-
-	/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
-
-	if (tty && urb->actual_length) {
-		tty_buffer_request_room(tty, 1);
-		tty_insert_flip_string(tty, &Data, 1);
-		/* tty_flip_buffer_push(tty); */
-	}
-
-	return;
+	if (urb->actual_length)
+		tty_insert_flip_char(tty, data, TTY_NORMAL);
 }
 
 static void qt_write_bulk_callback(struct urb *urb)
@@ -435,8 +426,10 @@ static void qt_read_bulk_callback(struct urb *urb)
 				case 0xff:
 					dbg("No status sequence. \n");
 
-					ProcessRxChar(port, data[i]);
-					ProcessRxChar(port, data[i + 1]);
+					if (tty) {
+						ProcessRxChar(tty, port, data[i]);
+						ProcessRxChar(tty, port, data[i + 1]);
+					}
 					i += 2;
 					break;
 				}
@@ -444,10 +437,8 @@ static void qt_read_bulk_callback(struct urb *urb)
 					continue;
 			}
 
-			if (tty && urb->actual_length) {
-				tty_buffer_request_room(tty, 1);
-				tty_insert_flip_string(tty, (data + i), 1);
-			}
+			if (tty && urb->actual_length)
+				tty_insert_flip_char(tty, data[i], TTY_NORMAL);
 
 		}
 		tty_flip_buffer_push(tty);


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

* [PATCH 10/15] serial@ add OMAP wakeup-enable register
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (8 preceding siblings ...)
  2009-06-22 17:42 ` [PATCH 09/15] tty: fix some bogns in the serqt_usb2 driver Alan Cox
@ 2009-06-22 17:42 ` Alan Cox
  2009-06-22 17:42 ` [PATCH 11/15] serial: samsung.c: mark s3c24xx_serial_remove as __devexit Alan Cox
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:42 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Kevin Hilman <khilman@deeprootsystems.com>

Add the wakeup enable register to the list of OMAP-specific UART
registers.  This is to support forthcoming OMAP PM enhancements which
use the wakeup feature of the OMAP's 8250-based UART.

Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 include/linux/serial_reg.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)


diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 96c0d93..850db2e 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -323,6 +323,7 @@
 #define UART_OMAP_MVER		0x14	/* Module version register */
 #define UART_OMAP_SYSC		0x15	/* System configuration register */
 #define UART_OMAP_SYSS		0x16	/* System status register */
+#define UART_OMAP_WER		0x17	/* Wake-up enable register */
 
 #endif /* _LINUX_SERIAL_REG_H */
 


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

* [PATCH 11/15] serial: samsung.c: mark s3c24xx_serial_remove as __devexit
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (9 preceding siblings ...)
  2009-06-22 17:42 ` [PATCH 10/15] serial@ add OMAP wakeup-enable register Alan Cox
@ 2009-06-22 17:42 ` Alan Cox
  2009-06-22 17:42 ` [PATCH 12/15] tty: n_hdlc add buffer flushing Alan Cox
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:42 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Peter Korsgaard <jacmet@sunsite.dk>

Mark the remove function as __devexit so it gets eliminated in
CONFIG_HOTPLUG=n builds.  Saves ~100 bytes.

Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Acked-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/serial/s3c2400.c |    2 +-
 drivers/serial/s3c2410.c |    2 +-
 drivers/serial/s3c2412.c |    2 +-
 drivers/serial/s3c2440.c |    2 +-
 drivers/serial/s3c24a0.c |    2 +-
 drivers/serial/s3c6400.c |    2 +-
 drivers/serial/samsung.c |    2 +-
 drivers/serial/samsung.h |    2 +-
 8 files changed, 8 insertions(+), 8 deletions(-)


diff --git a/drivers/serial/s3c2400.c b/drivers/serial/s3c2400.c
index 4873f29..fb00ed5 100644
--- a/drivers/serial/s3c2400.c
+++ b/drivers/serial/s3c2400.c
@@ -78,7 +78,7 @@ static int s3c2400_serial_probe(struct platform_device *dev)
 
 static struct platform_driver s3c2400_serial_drv = {
 	.probe		= s3c2400_serial_probe,
-	.remove		= s3c24xx_serial_remove,
+	.remove		= __devexit_p(s3c24xx_serial_remove),
 	.driver		= {
 		.name	= "s3c2400-uart",
 		.owner	= THIS_MODULE,
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 87c182e..b5d7cbc 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -90,7 +90,7 @@ static int s3c2410_serial_probe(struct platform_device *dev)
 
 static struct platform_driver s3c2410_serial_drv = {
 	.probe		= s3c2410_serial_probe,
-	.remove		= s3c24xx_serial_remove,
+	.remove		= __devexit_p(s3c24xx_serial_remove),
 	.driver		= {
 		.name	= "s3c2410-uart",
 		.owner	= THIS_MODULE,
diff --git a/drivers/serial/s3c2412.c b/drivers/serial/s3c2412.c
index fd017b3..11dcb90 100644
--- a/drivers/serial/s3c2412.c
+++ b/drivers/serial/s3c2412.c
@@ -123,7 +123,7 @@ static int s3c2412_serial_probe(struct platform_device *dev)
 
 static struct platform_driver s3c2412_serial_drv = {
 	.probe		= s3c2412_serial_probe,
-	.remove		= s3c24xx_serial_remove,
+	.remove		= __devexit_p(s3c24xx_serial_remove),
 	.driver		= {
 		.name	= "s3c2412-uart",
 		.owner	= THIS_MODULE,
diff --git a/drivers/serial/s3c2440.c b/drivers/serial/s3c2440.c
index 29cbb0a..06c5b0c 100644
--- a/drivers/serial/s3c2440.c
+++ b/drivers/serial/s3c2440.c
@@ -153,7 +153,7 @@ static int s3c2440_serial_probe(struct platform_device *dev)
 
 static struct platform_driver s3c2440_serial_drv = {
 	.probe		= s3c2440_serial_probe,
-	.remove		= s3c24xx_serial_remove,
+	.remove		= __devexit_p(s3c24xx_serial_remove),
 	.driver		= {
 		.name	= "s3c2440-uart",
 		.owner	= THIS_MODULE,
diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c
index ebf2fd3..786a067 100644
--- a/drivers/serial/s3c24a0.c
+++ b/drivers/serial/s3c24a0.c
@@ -94,7 +94,7 @@ static int s3c24a0_serial_probe(struct platform_device *dev)
 
 static struct platform_driver s3c24a0_serial_drv = {
 	.probe		= s3c24a0_serial_probe,
-	.remove		= s3c24xx_serial_remove,
+	.remove		= __devexit_p(s3c24xx_serial_remove),
 	.driver		= {
 		.name	= "s3c24a0-uart",
 		.owner	= THIS_MODULE,
diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c
index 3e37852..48f1a37 100644
--- a/drivers/serial/s3c6400.c
+++ b/drivers/serial/s3c6400.c
@@ -124,7 +124,7 @@ static int s3c6400_serial_probe(struct platform_device *dev)
 
 static struct platform_driver s3c6400_serial_drv = {
 	.probe		= s3c6400_serial_probe,
-	.remove		= s3c24xx_serial_remove,
+	.remove		= __devexit_p(s3c24xx_serial_remove),
 	.driver		= {
 		.name	= "s3c6400-uart",
 		.owner	= THIS_MODULE,
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
index 93b5d75..c8851a0 100644
--- a/drivers/serial/samsung.c
+++ b/drivers/serial/samsung.c
@@ -1174,7 +1174,7 @@ int s3c24xx_serial_probe(struct platform_device *dev,
 
 EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
 
-int s3c24xx_serial_remove(struct platform_device *dev)
+int __devexit s3c24xx_serial_remove(struct platform_device *dev)
 {
 	struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
 
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h
index 7afb948..d3fe315 100644
--- a/drivers/serial/samsung.h
+++ b/drivers/serial/samsung.h
@@ -72,7 +72,7 @@ struct s3c24xx_uart_port {
 extern int s3c24xx_serial_probe(struct platform_device *dev,
 				struct s3c24xx_uart_info *uart);
 
-extern int s3c24xx_serial_remove(struct platform_device *dev);
+extern int __devexit s3c24xx_serial_remove(struct platform_device *dev);
 
 extern int s3c24xx_serial_initconsole(struct platform_driver *drv,
 				      struct s3c24xx_uart_info *uart);


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

* [PATCH 12/15] tty: n_hdlc add buffer flushing
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (10 preceding siblings ...)
  2009-06-22 17:42 ` [PATCH 11/15] serial: samsung.c: mark s3c24xx_serial_remove as __devexit Alan Cox
@ 2009-06-22 17:42 ` Alan Cox
  2009-06-22 17:43 ` [PATCH 13/15] timbuart: Fix for tx_empty Alan Cox
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:42 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Paul Fulghum <paulkf@microgate.com>

Add flush_buffer tty callback to flush rx buffers.
Add TCFLSH ioctl processing to flush tx buffers.
Increase default tx buffers from 1 to 3.
Remove unneeded flush_buffer call in open callback.
Remove vendor specific CVS version string.

Signed-off-by: Paul Fulghum <paulkf@microgate.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/char/n_hdlc.c |   46 +++++++++++++++++++++++++++++++++++++---------
 1 files changed, 37 insertions(+), 9 deletions(-)


diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 461ece5..1c43c8c 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -10,7 +10,6 @@
  *	Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
  *
  * Original release 01/11/99
- * $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $
  *
  * This code is released under the GNU General Public License (GPL)
  *
@@ -79,7 +78,6 @@
  */
 
 #define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "$Revision: 4.8 $"
 
 #include <linux/module.h>
 #include <linux/init.h>
@@ -114,7 +112,7 @@
 #define MAX_HDLC_FRAME_SIZE 65535 
 #define DEFAULT_RX_BUF_COUNT 10
 #define MAX_RX_BUF_COUNT 60
-#define DEFAULT_TX_BUF_COUNT 1
+#define DEFAULT_TX_BUF_COUNT 3
 
 struct n_hdlc_buf {
 	struct n_hdlc_buf *link;
@@ -199,6 +197,31 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty);
 #define tty2n_hdlc(tty)	((struct n_hdlc *) ((tty)->disc_data))
 #define n_hdlc2tty(n_hdlc)	((n_hdlc)->tty)
 
+static void flush_rx_queue(struct tty_struct *tty)
+{
+	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+	struct n_hdlc_buf *buf;
+
+	while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
+		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
+}
+
+static void flush_tx_queue(struct tty_struct *tty)
+{
+	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+	struct n_hdlc_buf *buf;
+	unsigned long flags;
+
+	while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
+		n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
+ 	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+	if (n_hdlc->tbuf) {
+		n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
+		n_hdlc->tbuf = NULL;
+	}
+	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+}
+
 static struct tty_ldisc_ops n_hdlc_ldisc = {
 	.owner		= THIS_MODULE,
 	.magic		= TTY_LDISC_MAGIC,
@@ -211,6 +234,7 @@ static struct tty_ldisc_ops n_hdlc_ldisc = {
 	.poll		= n_hdlc_tty_poll,
 	.receive_buf	= n_hdlc_tty_receive,
 	.write_wakeup	= n_hdlc_tty_wakeup,
+	.flush_buffer   = flush_rx_queue,
 };
 
 /**
@@ -341,10 +365,7 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
 	set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
 #endif
 	
-	/* Flush any pending characters in the driver and discipline. */
-	if (tty->ldisc->ops->flush_buffer)
-		tty->ldisc->ops->flush_buffer(tty);
-
+	/* flush receive data from driver */
 	tty_driver_flush_buffer(tty);
 		
 	if (debuglevel >= DEBUG_LEVEL_INFO)	
@@ -763,6 +784,14 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
 		error = put_user(count, (int __user *)arg);
 		break;
 
+	case TCFLSH:
+		switch (arg) {
+		case TCIOFLUSH:
+		case TCOFLUSH:
+			flush_tx_queue(tty);
+		}
+		/* fall through to default */
+
 	default:
 		error = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
@@ -919,8 +948,7 @@ static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
 }	/* end of n_hdlc_buf_get() */
 
 static char hdlc_banner[] __initdata =
-	KERN_INFO "HDLC line discipline: version " HDLC_VERSION
-	", maxframe=%u\n";
+	KERN_INFO "HDLC line discipline maxframe=%u\n";
 static char hdlc_register_ok[] __initdata =
 	KERN_INFO "N_HDLC line discipline registered.\n";
 static char hdlc_register_fail[] __initdata =


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

* [PATCH 13/15] timbuart: Fix for tx_empty
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (11 preceding siblings ...)
  2009-06-22 17:42 ` [PATCH 12/15] tty: n_hdlc add buffer flushing Alan Cox
@ 2009-06-22 17:43 ` Alan Cox
  2009-06-22 17:43 ` [PATCH 14/15] msm_serial: serial driver for MSM7K onboard serial peripheral Alan Cox
  2009-06-22 17:43 ` [PATCH 15/15] msm: fixups to match current code Alan Cox
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:43 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Richard Röjfors <richard.rojfors.ext@mocean-labs.com>

Hardware updated to support TX FIFO empty.

Signed-off-by: Richard Röjfors <richard.rojfors.ext@mocean-labs.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/serial/timbuart.c |   50 +++++++++++++++++++++++----------------------
 1 files changed, 25 insertions(+), 25 deletions(-)


diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c
index ac9e5d5..063a313 100644
--- a/drivers/serial/timbuart.c
+++ b/drivers/serial/timbuart.c
@@ -33,29 +33,29 @@ struct timbuart_port {
 	struct uart_port	port;
 	struct tasklet_struct	tasklet;
 	int			usedma;
-	u8			last_ier;
+	u32			last_ier;
 	struct platform_device  *dev;
 };
 
 static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800,
 	921600, 1843200, 3250000};
 
-static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier);
+static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier);
 
 static irqreturn_t timbuart_handleinterrupt(int irq, void *devid);
 
 static void timbuart_stop_rx(struct uart_port *port)
 {
 	/* spin lock held by upper layer, disable all RX interrupts */
-	u8 ier = ioread8(port->membase + TIMBUART_IER) & ~RXFLAGS;
-	iowrite8(ier, port->membase + TIMBUART_IER);
+	u32 ier = ioread32(port->membase + TIMBUART_IER) & ~RXFLAGS;
+	iowrite32(ier, port->membase + TIMBUART_IER);
 }
 
 static void timbuart_stop_tx(struct uart_port *port)
 {
 	/* spinlock held by upper layer, disable TX interrupt */
-	u8 ier = ioread8(port->membase + TIMBUART_IER) & ~TXBAE;
-	iowrite8(ier, port->membase + TIMBUART_IER);
+	u32 ier = ioread32(port->membase + TIMBUART_IER) & ~TXBAE;
+	iowrite32(ier, port->membase + TIMBUART_IER);
 }
 
 static void timbuart_start_tx(struct uart_port *port)
@@ -72,14 +72,14 @@ static void timbuart_flush_buffer(struct uart_port *port)
 	u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | TIMBUART_CTRL_FLSHTX;
 
 	iowrite8(ctl, port->membase + TIMBUART_CTRL);
-	iowrite8(TXBF, port->membase + TIMBUART_ISR);
+	iowrite32(TXBF, port->membase + TIMBUART_ISR);
 }
 
 static void timbuart_rx_chars(struct uart_port *port)
 {
 	struct tty_struct *tty = port->info->port.tty;
 
-	while (ioread8(port->membase + TIMBUART_ISR) & RXDP) {
+	while (ioread32(port->membase + TIMBUART_ISR) & RXDP) {
 		u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
 		port->icount.rx++;
 		tty_insert_flip_char(tty, ch, TTY_NORMAL);
@@ -97,7 +97,7 @@ static void timbuart_tx_chars(struct uart_port *port)
 {
 	struct circ_buf *xmit = &port->info->xmit;
 
-	while (!(ioread8(port->membase + TIMBUART_ISR) & TXBF) &&
+	while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) &&
 		!uart_circ_empty(xmit)) {
 		iowrite8(xmit->buf[xmit->tail],
 			port->membase + TIMBUART_TXFIFO);
@@ -114,7 +114,7 @@ static void timbuart_tx_chars(struct uart_port *port)
 		ioread8(port->membase + TIMBUART_BAUDRATE));
 }
 
-static void timbuart_handle_tx_port(struct uart_port *port, u8 isr, u8 *ier)
+static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
 {
 	struct timbuart_port *uart =
 		container_of(port, struct timbuart_port, port);
@@ -129,7 +129,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u8 isr, u8 *ier)
 	if (isr & TXFLAGS) {
 		timbuart_tx_chars(port);
 		/* clear all TX interrupts */
-		iowrite8(TXFLAGS, port->membase + TIMBUART_ISR);
+		iowrite32(TXFLAGS, port->membase + TIMBUART_ISR);
 
 		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 			uart_write_wakeup(port);
@@ -148,7 +148,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u8 isr, u8 *ier)
 	dev_dbg(port->dev, "%s - leaving\n", __func__);
 }
 
-void timbuart_handle_rx_port(struct uart_port *port, u8 isr, u8 *ier)
+void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
 {
 	if (isr & RXFLAGS) {
 		/* Some RX status is set */
@@ -161,7 +161,7 @@ void timbuart_handle_rx_port(struct uart_port *port, u8 isr, u8 *ier)
 			timbuart_rx_chars(port);
 
 		/* ack all RX interrupts */
-		iowrite8(RXFLAGS, port->membase + TIMBUART_ISR);
+		iowrite32(RXFLAGS, port->membase + TIMBUART_ISR);
 	}
 
 	/* always have the RX interrupts enabled */
@@ -173,11 +173,11 @@ void timbuart_handle_rx_port(struct uart_port *port, u8 isr, u8 *ier)
 void timbuart_tasklet(unsigned long arg)
 {
 	struct timbuart_port *uart = (struct timbuart_port *)arg;
-	u8 isr, ier = 0;
+	u32 isr, ier = 0;
 
 	spin_lock(&uart->port.lock);
 
-	isr = ioread8(uart->port.membase + TIMBUART_ISR);
+	isr = ioread32(uart->port.membase + TIMBUART_ISR);
 	dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
 
 	if (!uart->usedma)
@@ -188,7 +188,7 @@ void timbuart_tasklet(unsigned long arg)
 	if (!uart->usedma)
 		timbuart_handle_rx_port(&uart->port, isr, &ier);
 
-	iowrite8(ier, uart->port.membase + TIMBUART_IER);
+	iowrite32(ier, uart->port.membase + TIMBUART_IER);
 
 	spin_unlock(&uart->port.lock);
 	dev_dbg(uart->port.dev, "%s leaving\n", __func__);
@@ -196,9 +196,9 @@ void timbuart_tasklet(unsigned long arg)
 
 static unsigned int timbuart_tx_empty(struct uart_port *port)
 {
-	u8 isr = ioread8(port->membase + TIMBUART_ISR);
+	u32 isr = ioread32(port->membase + TIMBUART_ISR);
 
-	return (isr & TXBAE) ? TIOCSER_TEMT : 0;
+	return (isr & TXBE) ? TIOCSER_TEMT : 0;
 }
 
 static unsigned int timbuart_get_mctrl(struct uart_port *port)
@@ -222,13 +222,13 @@ static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
 		iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
 }
 
-static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier)
+static void timbuart_mctrl_check(struct uart_port *port, u32 isr, u32 *ier)
 {
 	unsigned int cts;
 
 	if (isr & CTS_DELTA) {
 		/* ack */
-		iowrite8(CTS_DELTA, port->membase + TIMBUART_ISR);
+		iowrite32(CTS_DELTA, port->membase + TIMBUART_ISR);
 		cts = timbuart_get_mctrl(port);
 		uart_handle_cts_change(port, cts & TIOCM_CTS);
 		wake_up_interruptible(&port->info->delta_msr_wait);
@@ -255,9 +255,9 @@ static int timbuart_startup(struct uart_port *port)
 	dev_dbg(port->dev, "%s\n", __func__);
 
 	iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL);
-	iowrite8(0xff, port->membase + TIMBUART_ISR);
+	iowrite32(0x1ff, port->membase + TIMBUART_ISR);
 	/* Enable all but TX interrupts */
-	iowrite8(RXBAF | RXBF | RXTT | CTS_DELTA,
+	iowrite32(RXBAF | RXBF | RXTT | CTS_DELTA,
 		port->membase + TIMBUART_IER);
 
 	return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED,
@@ -270,7 +270,7 @@ static void timbuart_shutdown(struct uart_port *port)
 		container_of(port, struct timbuart_port, port);
 	dev_dbg(port->dev, "%s\n", __func__);
 	free_irq(port->irq, uart);
-	iowrite8(0, port->membase + TIMBUART_IER);
+	iowrite32(0, port->membase + TIMBUART_IER);
 }
 
 static int get_bindex(int baud)
@@ -359,10 +359,10 @@ static irqreturn_t timbuart_handleinterrupt(int irq, void *devid)
 	struct timbuart_port *uart = (struct timbuart_port *)devid;
 
 	if (ioread8(uart->port.membase + TIMBUART_IPR)) {
-		uart->last_ier = ioread8(uart->port.membase + TIMBUART_IER);
+		uart->last_ier = ioread32(uart->port.membase + TIMBUART_IER);
 
 		/* disable interrupts, the tasklet enables them again */
-		iowrite8(0, uart->port.membase + TIMBUART_IER);
+		iowrite32(0, uart->port.membase + TIMBUART_IER);
 
 		/* fire off bottom half */
 		tasklet_schedule(&uart->tasklet);


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

* [PATCH 14/15] msm_serial: serial driver for MSM7K onboard serial peripheral.
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (12 preceding siblings ...)
  2009-06-22 17:43 ` [PATCH 13/15] timbuart: Fix for tx_empty Alan Cox
@ 2009-06-22 17:43 ` Alan Cox
  2009-06-22 17:43 ` [PATCH 15/15] msm: fixups to match current code Alan Cox
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:43 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Robert Love <rlove@google.com>

Signed-off-by: Brian Swetland <swetland@google.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/serial/Kconfig      |   10 +
 drivers/serial/Makefile     |    1 
 drivers/serial/msm_serial.c |  767 +++++++++++++++++++++++++++++++++++++++++++
 drivers/serial/msm_serial.h |  117 +++++++
 include/linux/serial_core.h |    3 
 5 files changed, 898 insertions(+), 0 deletions(-)
 create mode 100644 drivers/serial/msm_serial.c
 create mode 100644 drivers/serial/msm_serial.h


diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 1132c5c..037c1e0 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1320,6 +1320,16 @@ config SERIAL_SGI_IOC3
 	  If you have an SGI Altix with an IOC3 serial card,
 	  say Y or M.  Otherwise, say N.
 
+config SERIAL_MSM
+	bool "MSM on-chip serial port support"
+	depends on ARM && ARCH_MSM
+	select SERIAL_CORE
+
+config SERIAL_MSM_CONSOLE
+	bool "MSM serial console support"
+	depends on SERIAL_MSM=y
+	select SERIAL_CORE_CONSOLE
+
 config SERIAL_NETX
 	tristate "NetX serial port support"
 	depends on ARM && ARCH_NETX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 45a8658..d5a2998 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
 obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
 obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
 obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
+obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
new file mode 100644
index 0000000..1a7c856
--- /dev/null
+++ b/drivers/serial/msm_serial.c
@@ -0,0 +1,767 @@
+/*
+ * drivers/serial/msm_serial.c - driver for msm7k serial device and console
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+# define SUPPORT_SYSRQ
+#endif
+
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include "msm_serial.h"
+
+struct msm_port {
+	struct uart_port	uart;
+	char			name[16];
+	struct clk		*clk;
+	unsigned int		imr;
+};
+
+#define UART_TO_MSM(uart_port)	((struct msm_port *) uart_port)
+
+static inline void msm_write(struct uart_port *port, unsigned int val,
+			     unsigned int off)
+{
+	__raw_writel(val, port->membase + off);
+}
+
+static inline unsigned int msm_read(struct uart_port *port, unsigned int off)
+{
+	return __raw_readl(port->membase + off);
+}
+
+static void msm_stop_tx(struct uart_port *port)
+{
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	msm_port->imr &= ~UART_IMR_TXLEV;
+	msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_start_tx(struct uart_port *port)
+{
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	msm_port->imr |= UART_IMR_TXLEV;
+	msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_stop_rx(struct uart_port *port)
+{
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
+	msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_enable_ms(struct uart_port *port)
+{
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	msm_port->imr |= UART_IMR_DELTA_CTS;
+	msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void handle_rx(struct uart_port *port)
+{
+	struct tty_struct *tty = port->info->port.tty;
+	unsigned int sr;
+
+	/*
+	 * Handle overrun. My understanding of the hardware is that overrun
+	 * is not tied to the RX buffer, so we handle the case out of band.
+	 */
+	if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
+		port->icount.overrun++;
+		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+		msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+	}
+
+	/* and now the main RX loop */
+	while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
+		unsigned int c;
+		char flag = TTY_NORMAL;
+
+		c = msm_read(port, UART_RF);
+
+		if (sr & UART_SR_RX_BREAK) {
+			port->icount.brk++;
+			if (uart_handle_break(port))
+				continue;
+		} else if (sr & UART_SR_PAR_FRAME_ERR) {
+			port->icount.frame++;
+		} else {
+			port->icount.rx++;
+		}
+
+		/* Mask conditions we're ignorning. */
+		sr &= port->read_status_mask;
+
+		if (sr & UART_SR_RX_BREAK) {
+			flag = TTY_BREAK;
+		} else if (sr & UART_SR_PAR_FRAME_ERR) {
+			flag = TTY_FRAME;
+		}
+
+		if (!uart_handle_sysrq_char(port, c))
+			tty_insert_flip_char(tty, c, flag);
+	}
+
+	tty_flip_buffer_push(tty);
+}
+
+static void handle_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+	struct msm_port *msm_port = UART_TO_MSM(port);
+	int sent_tx;
+
+	if (port->x_char) {
+		msm_write(port, port->x_char, UART_TF);
+		port->icount.tx++;
+		port->x_char = 0;
+	}
+
+	while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
+		if (uart_circ_empty(xmit)) {
+			/* disable tx interrupts */
+			msm_port->imr &= ~UART_IMR_TXLEV;
+			msm_write(port, msm_port->imr, UART_IMR);
+			break;
+		}
+
+		msm_write(port, xmit->buf[xmit->tail], UART_TF);
+
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		sent_tx = 1;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+}
+
+static void handle_delta_cts(struct uart_port *port)
+{
+	msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+	port->icount.cts++;
+	wake_up_interruptible(&port->info->delta_msr_wait);
+}
+
+static irqreturn_t msm_irq(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	struct msm_port *msm_port = UART_TO_MSM(port);
+	unsigned int misr;
+
+	spin_lock(&port->lock);
+	misr = msm_read(port, UART_MISR);
+	msm_write(port, 0, UART_IMR); /* disable interrupt */
+
+	if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
+		handle_rx(port);
+	if (misr & UART_IMR_TXLEV)
+		handle_tx(port);
+	if (misr & UART_IMR_DELTA_CTS)
+		handle_delta_cts(port);
+
+	msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int msm_tx_empty(struct uart_port *port)
+{
+	return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int msm_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
+}
+
+static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	unsigned int mr;
+
+	mr = msm_read(port, UART_MR1);
+
+	if (!(mctrl & TIOCM_RTS)) {
+		mr &= ~UART_MR1_RX_RDY_CTL;
+		msm_write(port, mr, UART_MR1);
+		msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
+	} else {
+		mr |= UART_MR1_RX_RDY_CTL;
+		msm_write(port, mr, UART_MR1);
+	}
+}
+
+static void msm_break_ctl(struct uart_port *port, int break_ctl)
+{
+	if (break_ctl)
+		msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
+	else
+		msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
+}
+
+static void msm_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+	unsigned int baud_code, rxstale, watermark;
+
+	switch (baud) {
+	case 300:
+		baud_code = UART_CSR_300;
+		rxstale = 1;
+		break;
+	case 600:
+		baud_code = UART_CSR_600;
+		rxstale = 1;
+		break;
+	case 1200:
+		baud_code = UART_CSR_1200;
+		rxstale = 1;
+		break;
+	case 2400:
+		baud_code = UART_CSR_2400;
+		rxstale = 1;
+		break;
+	case 4800:
+		baud_code = UART_CSR_4800;
+		rxstale = 1;
+		break;
+	case 9600:
+		baud_code = UART_CSR_9600;
+		rxstale = 2;
+		break;
+	case 14400:
+		baud_code = UART_CSR_14400;
+		rxstale = 3;
+		break;
+	case 19200:
+		baud_code = UART_CSR_19200;
+		rxstale = 4;
+		break;
+	case 28800:
+		baud_code = UART_CSR_28800;
+		rxstale = 6;
+		break;
+	case 38400:
+		baud_code = UART_CSR_38400;
+		rxstale = 8;
+		break;
+	case 57600:
+		baud_code = UART_CSR_57600;
+		rxstale = 16;
+		break;
+	case 115200:
+	default:
+		baud_code = UART_CSR_115200;
+		rxstale = 31;
+		break;
+	}
+
+	msm_write(port, baud_code, UART_CSR);
+
+	/* RX stale watermark */
+	watermark = UART_IPR_STALE_LSB & rxstale;
+	watermark |= UART_IPR_RXSTALE_LAST;
+	watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
+	msm_write(port, watermark, UART_IPR);
+
+	/* set RX watermark */
+	watermark = (port->fifosize * 3) / 4;
+	msm_write(port, watermark, UART_RFWR);
+
+	/* set TX watermark */
+	msm_write(port, 10, UART_TFWR);
+}
+
+static void msm_reset(struct uart_port *port)
+{
+	/* reset everything */
+	msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
+	msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
+	msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+	msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
+	msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+	msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+}
+
+static void msm_init_clock(struct uart_port *port)
+{
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	clk_enable(msm_port->clk);
+
+	msm_write(port, 0xC0, UART_MREG);
+	msm_write(port, 0xB2, UART_NREG);
+	msm_write(port, 0x7D, UART_DREG);
+	msm_write(port, 0x1C, UART_MNDREG);
+}
+
+static int msm_startup(struct uart_port *port)
+{
+	struct msm_port *msm_port = UART_TO_MSM(port);
+	unsigned int data, rfr_level;
+	int ret;
+
+	snprintf(msm_port->name, sizeof(msm_port->name),
+		 "msm_serial%d", port->line);
+
+	ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
+			  msm_port->name, port);
+	if (unlikely(ret))
+		return ret;
+
+	msm_init_clock(port);
+
+	if (likely(port->fifosize > 12))
+		rfr_level = port->fifosize - 12;
+	else
+		rfr_level = port->fifosize;
+
+	/* set automatic RFR level */
+	data = msm_read(port, UART_MR1);
+	data &= ~UART_MR1_AUTO_RFR_LEVEL1;
+	data &= ~UART_MR1_AUTO_RFR_LEVEL0;
+	data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
+	data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
+	msm_write(port, data, UART_MR1);
+
+	/* make sure that RXSTALE count is non-zero */
+	data = msm_read(port, UART_IPR);
+	if (unlikely(!data)) {
+		data |= UART_IPR_RXSTALE_LAST;
+		data |= UART_IPR_STALE_LSB;
+		msm_write(port, data, UART_IPR);
+	}
+
+	msm_reset(port);
+
+	msm_write(port, 0x05, UART_CR);	/* enable TX & RX */
+
+	/* turn on RX and CTS interrupts */
+	msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
+			UART_IMR_CURRENT_CTS;
+	msm_write(port, msm_port->imr, UART_IMR);
+
+	return 0;
+}
+
+static void msm_shutdown(struct uart_port *port)
+{
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	msm_port->imr = 0;
+	msm_write(port, 0, UART_IMR); /* disable interrupts */
+
+	clk_disable(msm_port->clk);
+
+	free_irq(port->irq, port);
+}
+
+static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
+			    struct ktermios *old)
+{
+	unsigned long flags;
+	unsigned int baud, mr;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* calculate and set baud rate */
+	baud = uart_get_baud_rate(port, termios, old, 300, 115200);
+	msm_set_baud_rate(port, baud);
+
+	/* calculate parity */
+	mr = msm_read(port, UART_MR2);
+	mr &= ~UART_MR2_PARITY_MODE;
+	if (termios->c_cflag & PARENB) {
+		if (termios->c_cflag & PARODD)
+			mr |= UART_MR2_PARITY_MODE_ODD;
+		else if (termios->c_cflag & CMSPAR)
+			mr |= UART_MR2_PARITY_MODE_SPACE;
+		else
+			mr |= UART_MR2_PARITY_MODE_EVEN;
+	}
+
+	/* calculate bits per char */
+	mr &= ~UART_MR2_BITS_PER_CHAR;
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		mr |= UART_MR2_BITS_PER_CHAR_5;
+		break;
+	case CS6:
+		mr |= UART_MR2_BITS_PER_CHAR_6;
+		break;
+	case CS7:
+		mr |= UART_MR2_BITS_PER_CHAR_7;
+		break;
+	case CS8:
+	default:
+		mr |= UART_MR2_BITS_PER_CHAR_8;
+		break;
+	}
+
+	/* calculate stop bits */
+	mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
+	if (termios->c_cflag & CSTOPB)
+		mr |= UART_MR2_STOP_BIT_LEN_TWO;
+	else
+		mr |= UART_MR2_STOP_BIT_LEN_ONE;
+
+	/* set parity, bits per char, and stop bit */
+	msm_write(port, mr, UART_MR2);
+
+	/* calculate and set hardware flow control */
+	mr = msm_read(port, UART_MR1);
+	mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
+	if (termios->c_cflag & CRTSCTS) {
+		mr |= UART_MR1_CTS_CTL;
+		mr |= UART_MR1_RX_RDY_CTL;
+	}
+	msm_write(port, mr, UART_MR1);
+
+	/* Configure status bits to ignore based on termio flags. */
+	port->read_status_mask = 0;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
+	if (termios->c_iflag & (BRKINT | PARMRK))
+		port->read_status_mask |= UART_SR_RX_BREAK;
+
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *msm_type(struct uart_port *port)
+{
+	return "MSM";
+}
+
+static void msm_release_port(struct uart_port *port)
+{
+	struct platform_device *pdev = to_platform_device(port->dev);
+	struct resource *resource;
+	resource_size_t size;
+
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!resource))
+		return;
+	size = resource->end - resource->start + 1;
+
+	release_mem_region(port->mapbase, size);
+	iounmap(port->membase);
+	port->membase = NULL;
+}
+
+static int msm_request_port(struct uart_port *port)
+{
+	struct platform_device *pdev = to_platform_device(port->dev);
+	struct resource *resource;
+	resource_size_t size;
+
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!resource))
+		return -ENXIO;
+	size = resource->end - resource->start + 1;
+
+	if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
+		return -EBUSY;
+
+	port->membase = ioremap(port->mapbase, size);
+	if (!port->membase) {
+		release_mem_region(port->mapbase, size);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void msm_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_MSM;
+		msm_request_port(port);
+	}
+}
+
+static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
+		return -EINVAL;
+	if (unlikely(port->irq != ser->irq))
+		return -EINVAL;
+	return 0;
+}
+
+static void msm_power(struct uart_port *port, unsigned int state,
+		      unsigned int oldstate)
+{
+	struct msm_port *msm_port = UART_TO_MSM(port);
+
+	switch (state) {
+	case 0:
+		clk_enable(msm_port->clk);
+		break;
+	case 3:
+		clk_disable(msm_port->clk);
+		break;
+	default:
+		printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
+	}
+}
+
+static struct uart_ops msm_uart_pops = {
+	.tx_empty = msm_tx_empty,
+	.set_mctrl = msm_set_mctrl,
+	.get_mctrl = msm_get_mctrl,
+	.stop_tx = msm_stop_tx,
+	.start_tx = msm_start_tx,
+	.stop_rx = msm_stop_rx,
+	.enable_ms = msm_enable_ms,
+	.break_ctl = msm_break_ctl,
+	.startup = msm_startup,
+	.shutdown = msm_shutdown,
+	.set_termios = msm_set_termios,
+	.type = msm_type,
+	.release_port = msm_release_port,
+	.request_port = msm_request_port,
+	.config_port = msm_config_port,
+	.verify_port = msm_verify_port,
+	.pm = msm_power,
+};
+
+static struct msm_port msm_uart_ports[] = {
+	{
+		.uart = {
+			.iotype = UPIO_MEM,
+			.ops = &msm_uart_pops,
+			.flags = UPF_BOOT_AUTOCONF,
+			.fifosize = 512,
+			.line = 0,
+		},
+	},
+	{
+		.uart = {
+			.iotype = UPIO_MEM,
+			.ops = &msm_uart_pops,
+			.flags = UPF_BOOT_AUTOCONF,
+			.fifosize = 512,
+			.line = 1,
+		},
+	},
+	{
+		.uart = {
+			.iotype = UPIO_MEM,
+			.ops = &msm_uart_pops,
+			.flags = UPF_BOOT_AUTOCONF,
+			.fifosize = 64,
+			.line = 2,
+		},
+	},
+};
+
+#define UART_NR	ARRAY_SIZE(msm_uart_ports)
+
+static inline struct uart_port *get_port_from_line(unsigned int line)
+{
+	return &msm_uart_ports[line].uart;
+}
+
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+
+static void msm_console_putchar(struct uart_port *port, int c)
+{
+	while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
+		;
+	msm_write(port, c, UART_TF);
+}
+
+static void msm_console_write(struct console *co, const char *s,
+			      unsigned int count)
+{
+	struct uart_port *port;
+	struct msm_port *msm_port;
+
+	BUG_ON(co->index < 0 || co->index >= UART_NR);
+
+	port = get_port_from_line(co->index);
+	msm_port = UART_TO_MSM(port);
+
+	spin_lock(&port->lock);
+	uart_console_write(port, s, count, msm_console_putchar);
+	spin_unlock(&port->lock);
+}
+
+static int __init msm_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud, flow, bits, parity;
+
+	if (unlikely(co->index >= UART_NR || co->index < 0))
+		return -ENXIO;
+
+	port = get_port_from_line(co->index);
+
+	if (unlikely(!port->membase))
+		return -ENXIO;
+
+	port->cons = co;
+
+	msm_init_clock(port);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	bits = 8;
+	parity = 'n';
+	flow = 'n';
+	msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
+		  UART_MR2);	/* 8N1 */
+
+	if (baud < 300 || baud > 115200)
+		baud = 115200;
+	msm_set_baud_rate(port, baud);
+
+	msm_reset(port);
+
+	printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver msm_uart_driver;
+
+static struct console msm_console = {
+	.name = "ttyMSM",
+	.write = msm_console_write,
+	.device = uart_console_device,
+	.setup = msm_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+	.data = &msm_uart_driver,
+};
+
+#define MSM_CONSOLE	(&msm_console)
+
+#else
+#define MSM_CONSOLE	NULL
+#endif
+
+static struct uart_driver msm_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "msm_serial",
+	.dev_name = "ttyMSM",
+	.nr = UART_NR,
+	.cons = MSM_CONSOLE,
+};
+
+static int __init msm_serial_probe(struct platform_device *pdev)
+{
+	struct msm_port *msm_port;
+	struct resource *resource;
+	struct uart_port *port;
+
+	if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
+		return -ENXIO;
+
+	printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
+
+	port = get_port_from_line(pdev->id);
+	port->dev = &pdev->dev;
+	msm_port = UART_TO_MSM(port);
+
+	msm_port->clk = clk_get(&pdev->dev, "uart_clk");
+	if (unlikely(IS_ERR(msm_port->clk)))
+		return PTR_ERR(msm_port->clk);
+	port->uartclk = clk_get_rate(msm_port->clk);
+
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!resource))
+		return -ENXIO;
+	port->mapbase = resource->start;
+
+	port->irq = platform_get_irq(pdev, 0);
+	if (unlikely(port->irq < 0))
+		return -ENXIO;
+
+	platform_set_drvdata(pdev, port);
+
+	return uart_add_one_port(&msm_uart_driver, port);
+}
+
+static int __devexit msm_serial_remove(struct platform_device *pdev)
+{
+	struct msm_port *msm_port = platform_get_drvdata(pdev);
+
+	clk_put(msm_port->clk);
+
+	return 0;
+}
+
+static struct platform_driver msm_platform_driver = {
+	.probe = msm_serial_probe,
+	.remove = msm_serial_remove,
+	.driver = {
+		.name = "msm_serial",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_serial_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&msm_uart_driver);
+	if (unlikely(ret))
+		return ret;
+
+	ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
+	if (unlikely(ret))
+		uart_unregister_driver(&msm_uart_driver);
+
+	printk(KERN_INFO "msm_serial: driver initialized\n");
+
+	return ret;
+}
+
+static void __exit msm_serial_exit(void)
+{
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+	unregister_console(&msm_console);
+#endif
+	platform_driver_unregister(&msm_platform_driver);
+	uart_unregister_driver(&msm_uart_driver);
+}
+
+module_init(msm_serial_init);
+module_exit(msm_serial_exit);
+
+MODULE_AUTHOR("Robert Love <rlove@google.com>");
+MODULE_DESCRIPTION("Driver for msm7x serial device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h
new file mode 100644
index 0000000..689f1fa
--- /dev/null
+++ b/drivers/serial/msm_serial.h
@@ -0,0 +1,117 @@
+/*
+ * drivers/serial/msm_serial.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
+#define __DRIVERS_SERIAL_MSM_SERIAL_H
+
+#define UART_MR1			0x0000
+
+#define UART_MR1_AUTO_RFR_LEVEL0	0x3F
+#define UART_MR1_AUTO_RFR_LEVEL1	0x3FF00
+#define UART_MR1_RX_RDY_CTL    		(1 << 7)
+#define UART_MR1_CTS_CTL       		(1 << 6)
+
+#define UART_MR2			0x0004
+#define UART_MR2_ERROR_MODE		(1 << 6)
+#define UART_MR2_BITS_PER_CHAR		0x30
+#define UART_MR2_BITS_PER_CHAR_5	(0x0 << 4)
+#define UART_MR2_BITS_PER_CHAR_6	(0x1 << 4)
+#define UART_MR2_BITS_PER_CHAR_7	(0x2 << 4)
+#define UART_MR2_BITS_PER_CHAR_8	(0x3 << 4)
+#define UART_MR2_STOP_BIT_LEN_ONE	(0x1 << 2)
+#define UART_MR2_STOP_BIT_LEN_TWO	(0x3 << 2)
+#define UART_MR2_PARITY_MODE_NONE	0x0
+#define UART_MR2_PARITY_MODE_ODD	0x1
+#define UART_MR2_PARITY_MODE_EVEN	0x2
+#define UART_MR2_PARITY_MODE_SPACE	0x3
+#define UART_MR2_PARITY_MODE		0x3
+
+#define UART_CSR	0x0008
+#define UART_CSR_115200	0xFF
+#define UART_CSR_57600	0xEE
+#define UART_CSR_38400	0xDD
+#define UART_CSR_28800	0xCC
+#define UART_CSR_19200	0xBB
+#define UART_CSR_14400	0xAA
+#define UART_CSR_9600	0x99
+#define UART_CSR_4800	0x77
+#define UART_CSR_2400	0x55
+#define UART_CSR_1200	0x44
+#define UART_CSR_600	0x33
+#define UART_CSR_300	0x22
+
+#define UART_TF		0x000C
+
+#define UART_CR				0x0010
+#define UART_CR_CMD_NULL		(0 << 4)
+#define UART_CR_CMD_RESET_RX		(1 << 4)
+#define UART_CR_CMD_RESET_TX		(2 << 4)
+#define UART_CR_CMD_RESET_ERR		(3 << 4)
+#define UART_CR_CMD_RESET_BREAK_INT	(4 << 4)
+#define UART_CR_CMD_START_BREAK		(5 << 4)
+#define UART_CR_CMD_STOP_BREAK		(6 << 4)
+#define UART_CR_CMD_RESET_CTS		(7 << 4)
+#define UART_CR_CMD_PACKET_MODE		(9 << 4)
+#define UART_CR_CMD_MODE_RESET		(12 << 4)
+#define UART_CR_CMD_SET_RFR		(13 << 4)
+#define UART_CR_CMD_RESET_RFR		(14 << 4)
+#define UART_CR_TX_DISABLE		(1 << 3)
+#define UART_CR_TX_ENABLE		(1 << 3)
+#define UART_CR_RX_DISABLE		(1 << 3)
+#define UART_CR_RX_ENABLE		(1 << 3)
+
+#define UART_IMR		0x0014
+#define UART_IMR_TXLEV		(1 << 0)
+#define UART_IMR_RXSTALE	(1 << 3)
+#define UART_IMR_RXLEV		(1 << 4)
+#define UART_IMR_DELTA_CTS	(1 << 5)
+#define UART_IMR_CURRENT_CTS	(1 << 6)
+
+#define UART_IPR_RXSTALE_LAST		0x20
+#define UART_IPR_STALE_LSB		0x1F
+#define UART_IPR_STALE_TIMEOUT_MSB	0x3FF80
+
+#define UART_IPR	0x0018
+#define UART_TFWR	0x001C
+#define UART_RFWR	0x0020
+#define UART_HCR	0x0024
+
+#define UART_MREG		0x0028
+#define UART_NREG		0x002C
+#define UART_DREG		0x0030
+#define UART_MNDREG		0x0034
+#define UART_IRDA		0x0038
+#define UART_MISR_MODE		0x0040
+#define UART_MISR_RESET		0x0044
+#define UART_MISR_EXPORT	0x0048
+#define UART_MISR_VAL		0x004C
+#define UART_TEST_CTRL		0x0050
+
+#define UART_SR			0x0008
+#define UART_SR_HUNT_CHAR	(1 << 7)
+#define UART_SR_RX_BREAK	(1 << 6)
+#define UART_SR_PAR_FRAME_ERR	(1 << 5)
+#define UART_SR_OVERRUN		(1 << 4)
+#define UART_SR_TX_EMPTY	(1 << 3)
+#define UART_SR_TX_READY	(1 << 2)
+#define UART_SR_RX_FULL		(1 << 1)
+#define UART_SR_RX_READY	(1 << 0)
+
+#define UART_RF		0x000C
+#define UART_MISR	0x0010
+#define UART_ISR	0x0014
+
+#endif	/* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 6fd80c4..23d2fb0 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -171,6 +171,9 @@
 /* Timberdale UART */
 #define PORT_TIMBUART	87
 
+/* Qualcomm MSM SoCs */
+#define PORT_MSM	88
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>


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

* [PATCH 15/15] msm: fixups to match current code
  2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
                   ` (13 preceding siblings ...)
  2009-06-22 17:43 ` [PATCH 14/15] msm_serial: serial driver for MSM7K onboard serial peripheral Alan Cox
@ 2009-06-22 17:43 ` Alan Cox
  14 siblings, 0 replies; 16+ messages in thread
From: Alan Cox @ 2009-06-22 17:43 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Alan Cox <alan@linux.intel.com>

The tty layer is now a bit more fussy about reporting the right baud rate
back. Make the msm driver match the current state of affairs.

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

 drivers/serial/msm_serial.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)


diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
index 1a7c856..698048f 100644
--- a/drivers/serial/msm_serial.c
+++ b/drivers/serial/msm_serial.c
@@ -229,7 +229,7 @@ static void msm_break_ctl(struct uart_port *port, int break_ctl)
 		msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
 }
 
-static void msm_set_baud_rate(struct uart_port *port, unsigned int baud)
+static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
 {
 	unsigned int baud_code, rxstale, watermark;
 
@@ -281,6 +281,7 @@ static void msm_set_baud_rate(struct uart_port *port, unsigned int baud)
 	case 115200:
 	default:
 		baud_code = UART_CSR_115200;
+		baud = 115200;
 		rxstale = 31;
 		break;
 	}
@@ -299,6 +300,8 @@ static void msm_set_baud_rate(struct uart_port *port, unsigned int baud)
 
 	/* set TX watermark */
 	msm_write(port, 10, UART_TFWR);
+
+	return baud;
 }
 
 static void msm_reset(struct uart_port *port)
@@ -395,8 +398,10 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
 
 	/* calculate and set baud rate */
 	baud = uart_get_baud_rate(port, termios, old, 300, 115200);
-	msm_set_baud_rate(port, baud);
-
+	baud = msm_set_baud_rate(port, baud);
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+	
 	/* calculate parity */
 	mr = msm_read(port, UART_MR2);
 	mr &= ~UART_MR2_PARITY_MODE;


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

end of thread, other threads:[~2009-06-22 16:46 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-22 17:30 [PATCH 00/15] Serial/tty follow up fixes for 2.6,31 Alan Cox
2009-06-22 17:31 ` [PATCH 01/15] bfin_jtag_comm: clean up printk usage Alan Cox
2009-06-22 17:37 ` [PATCH 02/15] serial: bfin_5xx: add missing spin_lock init Alan Cox
2009-06-22 17:41 ` [PATCH 03/15] serial: bfin_5xx: fix building as module when early printk is enabled Alan Cox
2009-06-22 17:41 ` [PATCH 04/15] serial: fix off by one errors Alan Cox
2009-06-22 17:42 ` [PATCH 05/15] n_r3964: fix lock imbalance Alan Cox
2009-06-22 17:42 ` [PATCH 06/15] pcmcia/cm4000: " Alan Cox
2009-06-22 17:42 ` [PATCH 07/15] vt_ioctl: " Alan Cox
2009-06-22 17:42 ` [PATCH 08/15] ppp: Fix throttling bugs Alan Cox
2009-06-22 17:42 ` [PATCH 09/15] tty: fix some bogns in the serqt_usb2 driver Alan Cox
2009-06-22 17:42 ` [PATCH 10/15] serial@ add OMAP wakeup-enable register Alan Cox
2009-06-22 17:42 ` [PATCH 11/15] serial: samsung.c: mark s3c24xx_serial_remove as __devexit Alan Cox
2009-06-22 17:42 ` [PATCH 12/15] tty: n_hdlc add buffer flushing Alan Cox
2009-06-22 17:43 ` [PATCH 13/15] timbuart: Fix for tx_empty Alan Cox
2009-06-22 17:43 ` [PATCH 14/15] msm_serial: serial driver for MSM7K onboard serial peripheral Alan Cox
2009-06-22 17:43 ` [PATCH 15/15] msm: fixups to match current code Alan Cox

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.