All of lore.kernel.org
 help / color / mirror / Atom feed
* [GIT PATCH] TTY/serial merge for .38
@ 2011-01-06 21:54 Greg KH
  2011-01-06 22:00 ` Alan Cox
                   ` (37 more replies)
  0 siblings, 38 replies; 54+ messages in thread
From: Greg KH @ 2011-01-06 21:54 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton; +Cc: linux-kernel, Alan Cox, Kay Sievers

Here is the big tty and serial merge for .38.  I'll be sending another
smaller one that just moves drivers around after .38-rc1 is out, as is
the norm for file moves to handle issues with other trees syncing up
properly.

There was some arguing about the tty console detection patches, but as
the existing ioctl does not work properly, Kay's patch was accepted to
resolve this issue and allow systemd to correctly detect consoles.  I
know Alan doesn't like this, but I feel it's the best way to solve the
issue (combined with the fact that there is no proposed other solution.)

This series also includes the long-out-of-tree ioctl that SUSE and
Debian have been dragging around in their kernels for the past 10+
years.  Thanks to Werner for finally submitting it in a mergable form.

Please pull from:
	master.kernel.org:/pub/scm/linux/kernel/git/gregkh/tty-2.6.git/ tty-next

All of these have been in the linux-next and -mm releases for quite some time.

Patches will be sent to the linux-kernel mailing list, if anyone wants
to see them.

thanks,

greg k-h

------------


 Documentation/ABI/testing/sysfs-tty     |   19 +
 Documentation/filesystems/proc.txt      |   24 +
 Documentation/serial/00-INDEX           |    2 +
 Documentation/serial/serial-rs485.txt   |  120 +++
 arch/alpha/include/asm/ioctls.h         |    1 +
 arch/mips/include/asm/ioctls.h          |    1 +
 arch/parisc/include/asm/ioctls.h        |    1 +
 arch/parisc/kernel/pdc_cons.c           |    8 +-
 arch/powerpc/include/asm/ioctls.h       |    1 +
 arch/sh/include/asm/ioctls.h            |    1 +
 arch/sparc/include/asm/ioctls.h         |    1 +
 arch/xtensa/include/asm/ioctls.h        |    1 +
 drivers/char/Kconfig                    |    9 +
 drivers/char/Makefile                   |    1 +
 drivers/char/hvc_dcc.c                  |  133 +++
 drivers/char/ip2/ip2main.c              |    2 +-
 drivers/char/rocket.c                   |    2 +-
 drivers/char/specialix.c                |    2 +-
 drivers/serial/8250.c                   |  109 ++-
 drivers/serial/8250_pci.c               |   36 +
 drivers/serial/Kconfig                  |   25 +
 drivers/serial/Makefile                 |    5 +-
 drivers/serial/apbuart.c                |   53 +-
 drivers/serial/cpm_uart/cpm_uart.h      |    6 -
 drivers/serial/cpm_uart/cpm_uart_core.c |   19 +
 drivers/serial/ifx6x60.c                | 1406 ++++++++++++++++++++++++++++++
 drivers/serial/ifx6x60.h                |  129 +++
 drivers/serial/mpc52xx_uart.c           |    6 +-
 drivers/serial/omap-serial.c            |   38 +-
 drivers/serial/pch_uart.c               | 1451 +++++++++++++++++++++++++++++++
 drivers/serial/serial_core.c            |   10 +-
 drivers/serial/vt8500_serial.c          |  648 ++++++++++++++
 drivers/tty/n_gsm.c                     |  213 +++--
 drivers/tty/tty_io.c                    |   52 +-
 drivers/tty/vt/vt.c                     |   23 +-
 drivers/video/xen-fbfront.c             |    2 +-
 fs/compat_ioctl.c                       |    1 +
 fs/proc/Makefile                        |    1 +
 fs/proc/proc_console.c                  |  114 +++
 include/asm-generic/ioctls.h            |    1 +
 include/linux/console.h                 |    8 +-
 include/linux/serial_core.h             |    7 +-
 include/linux/spi/ifx_modem.h           |   14 +
 include/linux/tty_driver.h              |    9 +-
 kernel/printk.c                         |    8 +-
 45 files changed, 4535 insertions(+), 188 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-tty
 create mode 100644 Documentation/serial/serial-rs485.txt
 create mode 100644 drivers/char/hvc_dcc.c
 create mode 100644 drivers/serial/ifx6x60.c
 create mode 100644 drivers/serial/ifx6x60.h
 create mode 100644 drivers/serial/pch_uart.c
 create mode 100644 drivers/serial/vt8500_serial.c
 create mode 100644 fs/proc/proc_console.c
 create mode 100644 include/linux/spi/ifx_modem.h

---------------

Alan Cox (4):
      n_gsm: Fix support for legacy encoding
      n_gsm: clean up printks
      serial: ifx6x60: The IFX requires SPI
      serial: ifx6x60: Fix missing include for msleep

Alexey Charkov (1):
      serial: Add support for UART on VIA VT8500 and compatibles

Baurzhan Ismagulov (2):
      serial: cpm_uat: reducing CPM serial latency
      serial: cpu_uart: Remove unused uart_cpm_port fields

Claudio Scordino (1):
      serial: add Documentation about RS485 serial communications

Cosmin Cojocar (1):
      serial: omap-serial: Add support for kernel debugger

Daniel Walker (1):
      drivers: char: hvc: add arm JTAG DCC console support

Dirk Brandewie (1):
      Serial: ce4100: Add PCI UART support for the ce4100

Govindraj.R (1):
      Serial: Avoid unbalanced IRQ wake disable during resume

Jamie Iles (2):
      8250: use container_of() instead of casting
      8250: add a UPIO_DWAPB32 for 32 bit accesses

Jiri Slaby (5):
      console: move for_each_console to linux/console.h
      TTY: include termios.h in tty_driver.h
      VIDEO: xen-fb, switch to for_each_console
      console: add /proc/consoles
      parisc: cleanup console handling

Kay Sievers (1):
      tty: add 'active' sysfs attribute to tty0 and console device

Namhyung Kim (3):
      rocket: fix compiler warning on rocket_pci_ids
      specialix: fix compiler warning on specialix_pci_tbl
      ip2: fix compiler warning on ip2main_pci_tbl

Ondrej Puzman (1):
      8250: fix uninitialized FIFOs

Randy Dunlap (1):
      serial: fix pch_uart kconfig & build

Russ Gorby (1):
      ifx6x60: SPI protocol driver for Infineon 6x60 modem

Thomas Gleixner (2):
      drivers: serial: apbuart: Handle OF failures gracefully
      serial: apbuart: Fixup apbuart_console_init()

Timur Tabi (1):
      tty: fix typos/errors in tty_driver.h comments

Tomoya MORINAGA (2):
      Serial: EG20T: add PCH_UART driver
      pch_uart : fix warnings for 64bit compile

Vasiliy Kulikov (2):
      serial: ifx6x60: free IRQ on error
      serial: ifx6x60: fix memory leak

Werner Fink (1):
      TTY: Add tty ioctl to figure device node of the system console.

Wolfram Sang (1):
      serial: mpc52xx: make printout for type more generic

Yegor Yefremov (1):
      RS485 documentation: add 16C950 UART description


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

* Re: [GIT PATCH] TTY/serial merge for .38
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
@ 2011-01-06 22:00 ` Alan Cox
  2011-01-06 22:24   ` Greg KH
  2011-01-06 22:22 ` [PATCH 01/36] ifx6x60: SPI protocol driver for Infineon 6x60 modem Greg Kroah-Hartman
                   ` (36 subsequent siblings)
  37 siblings, 1 reply; 54+ messages in thread
From: Alan Cox @ 2011-01-06 22:00 UTC (permalink / raw)
  To: Greg KH; +Cc: Linus Torvalds, Andrew Morton, linux-kernel, Kay Sievers

> There was some arguing about the tty console detection patches, but as
> the existing ioctl does not work properly, Kay's patch was accepted to
> resolve this issue and allow systemd to correctly detect consoles.  I
> know Alan doesn't like this, but I feel it's the best way to solve the
> issue (combined with the fact that there is no proposed other solution.)

I'm a bit confused about this one Greg - all the distributions used the
ioctl you refer to below for this purpose and have for years

> This series also includes the long-out-of-tree ioctl that SUSE and
> Debian have been dragging around in their kernels for the past 10+
> years.  Thanks to Werner for finally submitting it in a mergable form.

Which I believe means we don't need the sysfs patch as well - Kay ?


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

* [PATCH 01/36] ifx6x60: SPI protocol driver for Infineon 6x60 modem
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
  2011-01-06 22:00 ` Alan Cox
@ 2011-01-06 22:22 ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 02/36] serial: Add support for UART on VIA VT8500 and compatibles Greg Kroah-Hartman
                   ` (35 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: Russ Gorby, Alan Cox, Greg Kroah-Hartman

From: Russ Gorby <richardx.r.gorby@intel.com>

Prototype driver for the IFX6x60 series of SPI attached modems by Jim
Stanley and Russ Gorby

Signed-off-by: Russ Gorby <richardx.r.gorby@intel.com>

[Some reworking and a major cleanup]

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/Kconfig        |    6 +
 drivers/serial/Makefile       |    1 +
 drivers/serial/ifx6x60.c      | 1402 +++++++++++++++++++++++++++++++++++++++++
 drivers/serial/ifx6x60.h      |  129 ++++
 include/linux/spi/ifx_modem.h |   14 +
 5 files changed, 1552 insertions(+), 0 deletions(-)
 create mode 100644 drivers/serial/ifx6x60.c
 create mode 100644 drivers/serial/ifx6x60.h
 create mode 100644 include/linux/spi/ifx_modem.h

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index aff9dcd..0b9cc17 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1632,4 +1632,10 @@ config SERIAL_ALTERA_UART_CONSOLE
 	help
 	  Enable a Altera UART port to be the system console.
 
+config SERIAL_IFX6X60
+        tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
+	depends on GPIOLIB && EXPERIMENTAL
+	help
+	  Support for the IFX6x60 modem devices on Intel MID platforms.
+
 endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index c570576..783638b 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -89,3 +89,4 @@ obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
 obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
+obj-$(CONFIG_SERIAL_IFX6X60)  	+= ifx6x60.o
diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
new file mode 100644
index 0000000..b9b7e06
--- /dev/null
+++ b/drivers/serial/ifx6x60.c
@@ -0,0 +1,1402 @@
+/****************************************************************************
+ *
+ * Driver for the IFX 6x60 spi modem.
+ *
+ * Copyright (C) 2008 Option International
+ * Copyright (C) 2008 Filip Aben <f.aben@option.com>
+ *		      Denis Joseph Barrow <d.barow@option.com>
+ *		      Jan Dumon <j.dumon@option.com>
+ *
+ * Copyright (C) 2009, 2010 Intel Corp
+ * Russ Gorby <richardx.r.gorby@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA
+ *
+ * Driver modified by Intel from Option gtm501l_spi.c
+ *
+ * Notes
+ * o	The driver currently assumes a single device only. If you need to
+ *	change this then look for saved_ifx_dev and add a device lookup
+ * o	The driver is intended to be big-endian safe but has never been
+ *	tested that way (no suitable hardware). There are a couple of FIXME
+ *	notes by areas that may need addressing
+ * o	Some of the GPIO naming/setup assumptions may need revisiting if
+ *	you need to use this driver for another platform.
+ *
+ *****************************************************************************/
+#include <linux/module.h>
+#include <linux/termios.h>
+#include <linux/tty.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/tty.h>
+#include <linux/kfifo.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/serial.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/rfkill.h>
+#include <linux/fs.h>
+#include <linux/ip.h>
+#include <linux/dmapool.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/ifx_modem.h>
+
+#include "ifx6x60.h"
+
+#define IFX_SPI_MORE_MASK		0x10
+#define IFX_SPI_MORE_BIT		12	/* bit position in u16 */
+#define IFX_SPI_CTS_BIT			13	/* bit position in u16 */
+#define IFX_SPI_TTY_ID			0
+#define IFX_SPI_TIMEOUT_SEC		2
+#define IFX_SPI_HEADER_0		(-1)
+#define IFX_SPI_HEADER_F		(-2)
+
+/* forward reference */
+static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
+
+/* local variables */
+static int spi_b16 = 1;			/* 8 or 16 bit word length */
+static struct tty_driver *tty_drv;
+static struct ifx_spi_device *saved_ifx_dev;
+static struct lock_class_key ifx_spi_key;
+
+/* GPIO/GPE settings */
+
+/**
+ *	mrdy_set_high		-	set MRDY GPIO
+ *	@ifx: device we are controlling
+ *
+ */
+static inline void mrdy_set_high(struct ifx_spi_device *ifx)
+{
+	gpio_set_value(ifx->gpio.mrdy, 1);
+}
+
+/**
+ *	mrdy_set_low		-	clear MRDY GPIO
+ *	@ifx: device we are controlling
+ *
+ */
+static inline void mrdy_set_low(struct ifx_spi_device *ifx)
+{
+	gpio_set_value(ifx->gpio.mrdy, 0);
+}
+
+/**
+ *	ifx_spi_power_state_set
+ *	@ifx_dev: our SPI device
+ *	@val: bits to set
+ *
+ *	Set bit in power status and signal power system if status becomes non-0
+ */
+static void
+ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ifx_dev->power_lock, flags);
+
+	/*
+	 * if power status is already non-0, just update, else
+	 * tell power system
+	 */
+	if (!ifx_dev->power_status)
+		pm_runtime_get(&ifx_dev->spi_dev->dev);
+	ifx_dev->power_status |= val;
+
+	spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
+}
+
+/**
+ *	ifx_spi_power_state_clear	-	clear power bit
+ *	@ifx_dev: our SPI device
+ *	@val: bits to clear
+ *
+ *	clear bit in power status and signal power system if status becomes 0
+ */
+static void
+ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ifx_dev->power_lock, flags);
+
+	if (ifx_dev->power_status) {
+		ifx_dev->power_status &= ~val;
+		if (!ifx_dev->power_status)
+			pm_runtime_put(&ifx_dev->spi_dev->dev);
+	}
+
+	spin_unlock_irqrestore(&ifx_dev->power_lock, flags);
+}
+
+/**
+ *	swap_buf
+ *	@buf: our buffer
+ *	@len : number of bytes (not words) in the buffer
+ *	@end: end of buffer
+ *
+ *	Swap the contents of a buffer into big endian format
+ */
+static inline void swap_buf(u16 *buf, int len, void *end)
+{
+	int n;
+
+	len = ((len + 1) >> 1);
+	if ((void *)&buf[len] > end) {
+		pr_err("swap_buf: swap exceeds boundary (%p > %p)!",
+		       &buf[len], end);
+		return;
+	}
+	for (n = 0; n < len; n++) {
+		*buf = cpu_to_be16(*buf);
+		buf++;
+	}
+}
+
+/**
+ *	mrdy_assert		-	assert MRDY line
+ *	@ifx_dev: our SPI device
+ *
+ *	Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low
+ *	now.
+ *
+ *	FIXME: Can SRDY even go high as we are running this code ?
+ */
+static void mrdy_assert(struct ifx_spi_device *ifx_dev)
+{
+	int val = gpio_get_value(ifx_dev->gpio.srdy);
+	if (!val) {
+		if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING,
+				      &ifx_dev->flags)) {
+			ifx_dev->spi_timer.expires =
+				jiffies + IFX_SPI_TIMEOUT_SEC*HZ;
+			add_timer(&ifx_dev->spi_timer);
+
+		}
+	}
+	ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING);
+	mrdy_set_high(ifx_dev);
+}
+
+/**
+ *	ifx_spi_hangup		-	hang up an IFX device
+ *	@ifx_dev: our SPI device
+ *
+ *	Hang up the tty attached to the IFX device if one is currently
+ *	open. If not take no action
+ */
+static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev)
+{
+	struct tty_port *pport = &ifx_dev->tty_port;
+	struct tty_struct *tty = tty_port_tty_get(pport);
+	if (tty) {
+		tty_hangup(tty);
+		tty_kref_put(tty);
+	}
+}
+
+/**
+ *	ifx_spi_timeout		-	SPI timeout
+ *	@arg: our SPI device
+ *
+ *	The SPI has timed out: hang up the tty. Users will then see a hangup
+ *	and error events.
+ */
+static void ifx_spi_timeout(unsigned long arg)
+{
+	struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
+
+	dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***");
+	ifx_spi_ttyhangup(ifx_dev);
+	mrdy_set_low(ifx_dev);
+	clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+}
+
+/* char/tty operations */
+
+/**
+ *	ifx_spi_tiocmget	-	get modem lines
+ *	@tty: our tty device
+ *	@filp: file handle issuing the request
+ *
+ *	Map the signal state into Linux modem flags and report the value
+ *	in Linux terms
+ */
+static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp)
+{
+	unsigned int value;
+	struct ifx_spi_device *ifx_dev = tty->driver_data;
+
+	value =
+	(test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) |
+	(test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) |
+	(test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) |
+	(test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) |
+	(test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) |
+	(test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0);
+	return value;
+}
+
+/**
+ *	ifx_spi_tiocmset	-	set modem bits
+ *	@tty: the tty structure
+ *	@filp: file handle issuing the request
+ *	@set: bits to set
+ *	@clear: bits to clear
+ *
+ *	The IFX6x60 only supports DTR and RTS. Set them accordingly
+ *	and flag that an update to the modem is needed.
+ *
+ *	FIXME: do we need to kick the tranfers when we do this ?
+ */
+static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp,
+			    unsigned int set, unsigned int clear)
+{
+	struct ifx_spi_device *ifx_dev = tty->driver_data;
+
+	if (set & TIOCM_RTS)
+		set_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
+	if (set & TIOCM_DTR)
+		set_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
+	if (clear & TIOCM_RTS)
+		clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state);
+	if (clear & TIOCM_DTR)
+		clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state);
+
+	set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state);
+	return 0;
+}
+
+/**
+ *	ifx_spi_open	-	called on tty open
+ *	@tty: our tty device
+ *	@filp: file handle being associated with the tty
+ *
+ *	Open the tty interface. We let the tty_port layer do all the work
+ *	for us.
+ *
+ *	FIXME: Remove single device assumption and saved_ifx_dev
+ */
+static int ifx_spi_open(struct tty_struct *tty, struct file *filp)
+{
+	return tty_port_open(&saved_ifx_dev->tty_port, tty, filp);
+}
+
+/**
+ *	ifx_spi_close	-	called when our tty closes
+ *	@tty: the tty being closed
+ *	@filp: the file handle being closed
+ *
+ *	Perform the close of the tty. We use the tty_port layer to do all
+ *	our hard work.
+ */
+static void ifx_spi_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ifx_spi_device *ifx_dev = tty->driver_data;
+	tty_port_close(&ifx_dev->tty_port, tty, filp);
+	/* FIXME: should we do an ifx_spi_reset here ? */
+}
+
+/**
+ *	ifx_decode_spi_header	-	decode received header
+ *	@buffer: the received data
+ *	@length: decoded length
+ *	@more: decoded more flag
+ *	@received_cts: status of cts we received
+ *
+ *	Note how received_cts is handled -- if header is all F it is left
+ *	the same as it was, if header is all 0 it is set to 0 otherwise it is
+ *	taken from the incoming header.
+ *
+ *	FIXME: endianness
+ */
+static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length,
+			unsigned char *more, unsigned char *received_cts)
+{
+	u16 h1;
+	u16 h2;
+	u16 *in_buffer = (u16 *)buffer;
+
+	h1 = *in_buffer;
+	h2 = *(in_buffer+1);
+
+	if (h1 == 0 && h2 == 0) {
+		*received_cts = 0;
+		return IFX_SPI_HEADER_0;
+	} else if (h1 == 0xffff && h2 == 0xffff) {
+		/* spi_slave_cts remains as it was */
+		return IFX_SPI_HEADER_F;
+	}
+
+	*length = h1 & 0xfff;	/* upper bits of byte are flags */
+	*more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1;
+	*received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1;
+	return 0;
+}
+
+/**
+ *	ifx_setup_spi_header	-	set header fields
+ *	@txbuffer: pointer to start of SPI buffer
+ *	@tx_count: bytes
+ *	@more: indicate if more to follow
+ *
+ *	Format up an SPI header for a transfer
+ *
+ *	FIXME: endianness?
+ */
+static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,
+					unsigned char more)
+{
+	*(u16 *)(txbuffer) = tx_count;
+	*(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE;
+	txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK;
+}
+
+/**
+ *	ifx_spi_wakeup_serial	-	SPI space made
+ *	@port_data: our SPI device
+ *
+ *	We have emptied the FIFO enough that we want to get more data
+ *	queued into it. Poke the line discipline via tty_wakeup so that
+ *	it will feed us more bits
+ */
+static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev)
+{
+	struct tty_struct *tty;
+
+	tty = tty_port_tty_get(&ifx_dev->tty_port);
+	if (!tty)
+		return;
+	tty_wakeup(tty);
+	tty_kref_put(tty);
+}
+
+/**
+ *	ifx_spi_prepare_tx_buffer	-	prepare transmit frame
+ *	@ifx_dev: our SPI device
+ *
+ *	The transmit buffr needs a header and various other bits of
+ *	information followed by as much data as we can pull from the FIFO
+ *	and transfer. This function formats up a suitable buffer in the
+ *	ifx_dev->tx_buffer
+ *
+ *	FIXME: performance - should we wake the tty when the queue is half
+ *			     empty ?
+ */
+static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
+{
+	int temp_count;
+	int queue_length;
+	int tx_count;
+	unsigned char *tx_buffer;
+
+	tx_buffer = ifx_dev->tx_buffer;
+	memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE);
+
+	/* make room for required SPI header */
+	tx_buffer += IFX_SPI_HEADER_OVERHEAD;
+	tx_count = IFX_SPI_HEADER_OVERHEAD;
+
+	/* clear to signal no more data if this turns out to be the
+	 * last buffer sent in a sequence */
+	ifx_dev->spi_more = 0;
+
+	/* if modem cts is set, just send empty buffer */
+	if (!ifx_dev->spi_slave_cts) {
+		/* see if there's tx data */
+		queue_length = kfifo_len(&ifx_dev->tx_fifo);
+		if (queue_length != 0) {
+			/* data to mux -- see if there's room for it */
+			temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE);
+			temp_count = kfifo_out_locked(&ifx_dev->tx_fifo,
+					tx_buffer, temp_count,
+					&ifx_dev->fifo_lock);
+
+			/* update buffer pointer and data count in message */
+			tx_buffer += temp_count;
+			tx_count += temp_count;
+			if (temp_count == queue_length)
+				/* poke port to get more data */
+				ifx_spi_wakeup_serial(ifx_dev);
+			else /* more data in port, use next SPI message */
+				ifx_dev->spi_more = 1;
+		}
+	}
+	/* have data and info for header -- set up SPI header in buffer */
+	/* spi header needs payload size, not entire buffer size */
+	ifx_spi_setup_spi_header(ifx_dev->tx_buffer,
+					tx_count-IFX_SPI_HEADER_OVERHEAD,
+					ifx_dev->spi_more);
+	/* swap actual data in the buffer */
+	swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count,
+		&ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]);
+	return tx_count;
+}
+
+/**
+ *	ifx_spi_write		-	line discipline write
+ *	@tty: our tty device
+ *	@buf: pointer to buffer to write (kernel space)
+ *	@count: size of buffer
+ *
+ *	Write the characters we have been given into the FIFO. If the device
+ *	is not active then activate it, when the SRDY line is asserted back
+ *	this will commence I/O
+ */
+static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf,
+			 int count)
+{
+	struct ifx_spi_device *ifx_dev = tty->driver_data;
+	unsigned char *tmp_buf = (unsigned char *)buf;
+	int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count,
+				   &ifx_dev->fifo_lock);
+	mrdy_assert(ifx_dev);
+	return tx_count;
+}
+
+/**
+ *	ifx_spi_chars_in_buffer	-	line discipline helper
+ *	@tty: our tty device
+ *
+ *	Report how much data we can accept before we drop bytes. As we use
+ *	a simple FIFO this is nice and easy.
+ */
+static int ifx_spi_write_room(struct tty_struct *tty)
+{
+	struct ifx_spi_device *ifx_dev = tty->driver_data;
+	return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo);
+}
+
+/**
+ *	ifx_spi_chars_in_buffer	-	line discipline helper
+ *	@tty: our tty device
+ *
+ *	Report how many characters we have buffered. In our case this is the
+ *	number of bytes sitting in our transmit FIFO.
+ */
+static int ifx_spi_chars_in_buffer(struct tty_struct *tty)
+{
+	struct ifx_spi_device *ifx_dev = tty->driver_data;
+	return kfifo_len(&ifx_dev->tx_fifo);
+}
+
+/**
+ *	ifx_port_hangup
+ *	@port: our tty port
+ *
+ *	tty port hang up. Called when tty_hangup processing is invoked either
+ *	by loss of carrier, or by software (eg vhangup). Serialized against
+ *	activate/shutdown by the tty layer.
+ */
+static void ifx_spi_hangup(struct tty_struct *tty)
+{
+	struct ifx_spi_device *ifx_dev = tty->driver_data;
+	tty_port_hangup(&ifx_dev->tty_port);
+}
+
+/**
+ *	ifx_port_activate
+ *	@port: our tty port
+ *
+ *	tty port activate method - called for first open. Serialized
+ *	with hangup and shutdown by the tty layer.
+ */
+static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+	struct ifx_spi_device *ifx_dev =
+		container_of(port, struct ifx_spi_device, tty_port);
+
+	/* clear any old data; can't do this in 'close' */
+	kfifo_reset(&ifx_dev->tx_fifo);
+
+	/* put port data into this tty */
+	tty->driver_data = ifx_dev;
+
+	/* allows flip string push from int context */
+	tty->low_latency = 1;
+
+	return 0;
+}
+
+/**
+ *	ifx_port_shutdown
+ *	@port: our tty port
+ *
+ *	tty port shutdown method - called for last port close. Serialized
+ *	with hangup and activate by the tty layer.
+ */
+static void ifx_port_shutdown(struct tty_port *port)
+{
+	struct ifx_spi_device *ifx_dev =
+		container_of(port, struct ifx_spi_device, tty_port);
+
+	mrdy_set_low(ifx_dev);
+	clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+	tasklet_kill(&ifx_dev->io_work_tasklet);
+}
+
+static const struct tty_port_operations ifx_tty_port_ops = {
+	.activate = ifx_port_activate,
+	.shutdown = ifx_port_shutdown,
+};
+
+static const struct tty_operations ifx_spi_serial_ops = {
+	.open = ifx_spi_open,
+	.close = ifx_spi_close,
+	.write = ifx_spi_write,
+	.hangup = ifx_spi_hangup,
+	.write_room = ifx_spi_write_room,
+	.chars_in_buffer = ifx_spi_chars_in_buffer,
+	.tiocmget = ifx_spi_tiocmget,
+	.tiocmset = ifx_spi_tiocmset,
+};
+
+/**
+ *	ifx_spi_insert_fip_string	-	queue received data
+ *	@ifx_ser: our SPI device
+ *	@chars: buffer we have received
+ *	@size: number of chars reeived
+ *
+ *	Queue bytes to the tty assuming the tty side is currently open. If
+ *	not the discard the data.
+ */
+static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
+				    unsigned char *chars, size_t size)
+{
+	struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port);
+	if (!tty)
+		return;
+	tty_insert_flip_string(tty, chars, size);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+/**
+ *	ifx_spi_complete	-	SPI transfer completed
+ *	@ctx: our SPI device
+ *
+ *	An SPI transfer has completed. Process any received data and kick off
+ *	any further transmits we can commence.
+ */
+static void ifx_spi_complete(void *ctx)
+{
+	struct ifx_spi_device *ifx_dev = ctx;
+	struct tty_struct *tty;
+	struct tty_ldisc *ldisc = NULL;
+	int length;
+	int actual_length;
+	unsigned char more;
+	unsigned char cts;
+	int local_write_pending = 0;
+	int queue_length;
+	int srdy;
+	int decode_result;
+
+	mrdy_set_low(ifx_dev);
+
+	if (!ifx_dev->spi_msg.status) {
+		/* check header validity, get comm flags */
+		swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
+			&ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]);
+		decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer,
+				&length, &more, &cts);
+		if (decode_result == IFX_SPI_HEADER_0) {
+			dev_dbg(&ifx_dev->spi_dev->dev,
+				"ignore input: invalid header 0");
+			ifx_dev->spi_slave_cts = 0;
+			goto complete_exit;
+		} else if (decode_result == IFX_SPI_HEADER_F) {
+			dev_dbg(&ifx_dev->spi_dev->dev,
+				"ignore input: invalid header F");
+			goto complete_exit;
+		}
+
+		ifx_dev->spi_slave_cts = cts;
+
+		actual_length = min((unsigned int)length,
+					ifx_dev->spi_msg.actual_length);
+		swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
+			 actual_length,
+			 &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]);
+		ifx_spi_insert_flip_string(
+			ifx_dev,
+			ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD,
+			(size_t)actual_length);
+	} else {
+		dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d",
+		       ifx_dev->spi_msg.status);
+	}
+
+complete_exit:
+	if (ifx_dev->write_pending) {
+		ifx_dev->write_pending = 0;
+		local_write_pending = 1;
+	}
+
+	clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags));
+
+	queue_length = kfifo_len(&ifx_dev->tx_fifo);
+	srdy = gpio_get_value(ifx_dev->gpio.srdy);
+	if (!srdy)
+		ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY);
+
+	/* schedule output if there is more to do */
+	if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags))
+		tasklet_schedule(&ifx_dev->io_work_tasklet);
+	else {
+		if (more || ifx_dev->spi_more || queue_length > 0 ||
+			local_write_pending) {
+			if (ifx_dev->spi_slave_cts) {
+				if (more)
+					mrdy_assert(ifx_dev);
+			} else
+				mrdy_assert(ifx_dev);
+		} else {
+			/*
+			 * poke line discipline driver if any for more data
+			 * may or may not get more data to write
+			 * for now, say not busy
+			 */
+			ifx_spi_power_state_clear(ifx_dev,
+						  IFX_SPI_POWER_DATA_PENDING);
+			tty = tty_port_tty_get(&ifx_dev->tty_port);
+			if (tty) {
+				ldisc = tty_ldisc_ref(tty);
+				if (ldisc) {
+					ldisc->ops->write_wakeup(tty);
+					tty_ldisc_deref(ldisc);
+				}
+				tty_kref_put(tty);
+			}
+		}
+	}
+}
+
+/**
+ *	ifx_spio_io		-	I/O tasklet
+ *	@data: our SPI device
+ *
+ *	Queue data for transmission if possible and then kick off the
+ *	transfer.
+ */
+static void ifx_spi_io(unsigned long data)
+{
+	int retval;
+	struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data;
+
+	if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) {
+		if (ifx_dev->gpio.unack_srdy_int_nb > 0)
+			ifx_dev->gpio.unack_srdy_int_nb--;
+
+		ifx_spi_prepare_tx_buffer(ifx_dev);
+
+		spi_message_init(&ifx_dev->spi_msg);
+		INIT_LIST_HEAD(&ifx_dev->spi_msg.queue);
+
+		ifx_dev->spi_msg.context = ifx_dev;
+		ifx_dev->spi_msg.complete = ifx_spi_complete;
+
+		/* set up our spi transfer */
+		/* note len is BYTES, not transfers */
+		ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE;
+		ifx_dev->spi_xfer.cs_change = 0;
+		ifx_dev->spi_xfer.speed_hz = 12500000;
+		/* ifx_dev->spi_xfer.speed_hz = 390625; */
+		ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8;
+
+		ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer;
+		ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer;
+
+		/*
+		 * setup dma pointers
+		 */
+		if (ifx_dev->is_6160) {
+			ifx_dev->spi_msg.is_dma_mapped = 1;
+			ifx_dev->tx_dma = ifx_dev->tx_bus;
+			ifx_dev->rx_dma = ifx_dev->rx_bus;
+			ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma;
+			ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma;
+		} else {
+			ifx_dev->spi_msg.is_dma_mapped = 0;
+			ifx_dev->tx_dma = (dma_addr_t)0;
+			ifx_dev->rx_dma = (dma_addr_t)0;
+			ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0;
+			ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0;
+		}
+
+		spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg);
+
+		/* Assert MRDY. This may have already been done by the write
+		 * routine.
+		 */
+		mrdy_assert(ifx_dev);
+
+		retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg);
+		if (retval) {
+			clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS,
+				  &ifx_dev->flags);
+			tasklet_schedule(&ifx_dev->io_work_tasklet);
+			return;
+		}
+	} else
+		ifx_dev->write_pending = 1;
+}
+
+/**
+ *	ifx_spi_free_port	-	free up the tty side
+ *	@ifx_dev: IFX device going away
+ *
+ *	Unregister and free up a port when the device goes away
+ */
+static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev)
+{
+	if (ifx_dev->tty_dev)
+		tty_unregister_device(tty_drv, ifx_dev->minor);
+	kfifo_free(&ifx_dev->tx_fifo);
+}
+
+/**
+ *	ifx_spi_create_port	-	create a new port
+ *	@ifx_dev: our spi device
+ *
+ *	Allocate and initialise the tty port that goes with this interface
+ *	and add it to the tty layer so that it can be opened.
+ */
+static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
+{
+	int ret = 0;
+	struct tty_port *pport = &ifx_dev->tty_port;
+
+	spin_lock_init(&ifx_dev->fifo_lock);
+	lockdep_set_class_and_subclass(&ifx_dev->fifo_lock,
+		&ifx_spi_key, 0);
+
+	if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	pport->ops = &ifx_tty_port_ops;
+	tty_port_init(pport);
+	ifx_dev->minor = IFX_SPI_TTY_ID;
+	ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
+					       &ifx_dev->spi_dev->dev);
+	if (IS_ERR(ifx_dev->tty_dev)) {
+		dev_dbg(&ifx_dev->spi_dev->dev,
+			"%s: registering tty device failed", __func__);
+		ret = PTR_ERR(ifx_dev->tty_dev);
+		goto error_ret;
+	}
+	return 0;
+
+error_ret:
+	ifx_spi_free_port(ifx_dev);
+	return ret;
+}
+
+/**
+ *	ifx_spi_handle_srdy		-	handle SRDY
+ *	@ifx_dev: device asserting SRDY
+ *
+ *	Check our device state and see what we need to kick off when SRDY
+ *	is asserted. This usually means killing the timer and firing off the
+ *	I/O processing.
+ */
+static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev)
+{
+	if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) {
+		del_timer_sync(&ifx_dev->spi_timer);
+		clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
+	}
+
+	ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY);
+
+	if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags))
+		tasklet_schedule(&ifx_dev->io_work_tasklet);
+	else
+		set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags);
+}
+
+/**
+ *	ifx_spi_srdy_interrupt	-	SRDY asserted
+ *	@irq: our IRQ number
+ *	@dev: our ifx device
+ *
+ *	The modem asserted SRDY. Handle the srdy event
+ */
+static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev)
+{
+	struct ifx_spi_device *ifx_dev = dev;
+	ifx_dev->gpio.unack_srdy_int_nb++;
+	ifx_spi_handle_srdy(ifx_dev);
+	return IRQ_HANDLED;
+}
+
+/**
+ *	ifx_spi_reset_interrupt	-	Modem has changed reset state
+ *	@irq: interrupt number
+ *	@dev: our device pointer
+ *
+ *	The modem has either entered or left reset state. Check the GPIO
+ *	line to see which.
+ *
+ *	FIXME: review locking on MR_INPROGRESS versus
+ *	parallel unsolicited reset/solicited reset
+ */
+static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
+{
+	struct ifx_spi_device *ifx_dev = dev;
+	int val = gpio_get_value(ifx_dev->gpio.reset_out);
+	int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state);
+
+	if (val == 0) {
+		/* entered reset */
+		set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
+		if (!solreset) {
+			/* unsolicited reset  */
+			ifx_spi_ttyhangup(ifx_dev);
+		}
+	} else {
+		/* exited reset */
+		clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
+		if (solreset) {
+			set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state);
+			wake_up(&ifx_dev->mdm_reset_wait);
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+/**
+ *	ifx_spi_free_device - free device
+ *	@ifx_dev: device to free
+ *
+ *	Free the IFX device
+ */
+static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev)
+{
+	ifx_spi_free_port(ifx_dev);
+	dma_free_coherent(&ifx_dev->spi_dev->dev,
+				IFX_SPI_TRANSFER_SIZE,
+				ifx_dev->tx_buffer,
+				ifx_dev->tx_bus);
+	dma_free_coherent(&ifx_dev->spi_dev->dev,
+				IFX_SPI_TRANSFER_SIZE,
+				ifx_dev->rx_buffer,
+				ifx_dev->rx_bus);
+}
+
+/**
+ *	ifx_spi_reset	-	reset modem
+ *	@ifx_dev: modem to reset
+ *
+ *	Perform a reset on the modem
+ */
+static int ifx_spi_reset(struct ifx_spi_device *ifx_dev)
+{
+	int ret;
+	/*
+	 * set up modem power, reset
+	 *
+	 * delays are required on some platforms for the modem
+	 * to reset properly
+	 */
+	set_bit(MR_START, &ifx_dev->mdm_reset_state);
+	gpio_set_value(ifx_dev->gpio.po, 0);
+	gpio_set_value(ifx_dev->gpio.reset, 0);
+	msleep(25);
+	gpio_set_value(ifx_dev->gpio.reset, 1);
+	msleep(1);
+	gpio_set_value(ifx_dev->gpio.po, 1);
+	msleep(1);
+	gpio_set_value(ifx_dev->gpio.po, 0);
+	ret = wait_event_timeout(ifx_dev->mdm_reset_wait,
+				 test_bit(MR_COMPLETE,
+					  &ifx_dev->mdm_reset_state),
+				 IFX_RESET_TIMEOUT);
+	if (!ret)
+		dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)",
+			 ifx_dev->mdm_reset_state);
+
+	ifx_dev->mdm_reset_state = 0;
+	return ret;
+}
+
+/**
+ *	ifx_spi_spi_probe	-	probe callback
+ *	@spi: our possible matching SPI device
+ *
+ *	Probe for a 6x60 modem on SPI bus. Perform any needed device and
+ *	GPIO setup.
+ *
+ *	FIXME:
+ *	-	Support for multiple devices
+ *	-	Split out MID specific GPIO handling eventually
+ */
+
+static int ifx_spi_spi_probe(struct spi_device *spi)
+{
+	int ret;
+	int srdy;
+	struct ifx_modem_platform_data *pl_data = NULL;
+	struct ifx_spi_device *ifx_dev;
+
+	if (saved_ifx_dev) {
+		dev_dbg(&spi->dev, "ignoring subsequent detection");
+		return -ENODEV;
+	}
+
+	/* initialize structure to hold our device variables */
+	ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL);
+	if (!ifx_dev) {
+		dev_err(&spi->dev, "spi device allocation failed");
+		return -ENOMEM;
+	}
+	saved_ifx_dev = ifx_dev;
+	ifx_dev->spi_dev = spi;
+	clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags);
+	spin_lock_init(&ifx_dev->write_lock);
+	spin_lock_init(&ifx_dev->power_lock);
+	ifx_dev->power_status = 0;
+	init_timer(&ifx_dev->spi_timer);
+	ifx_dev->spi_timer.function = ifx_spi_timeout;
+	ifx_dev->spi_timer.data = (unsigned long)ifx_dev;
+	ifx_dev->is_6160 = pl_data->is_6160;
+
+	/* ensure SPI protocol flags are initialized to enable transfer */
+	ifx_dev->spi_more = 0;
+	ifx_dev->spi_slave_cts = 0;
+
+	/*initialize transfer and dma buffers */
+	ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
+				IFX_SPI_TRANSFER_SIZE,
+				&ifx_dev->tx_bus,
+				GFP_KERNEL);
+	if (!ifx_dev->tx_buffer) {
+		dev_err(&spi->dev, "DMA-TX buffer allocation failed");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev,
+				IFX_SPI_TRANSFER_SIZE,
+				&ifx_dev->rx_bus,
+				GFP_KERNEL);
+	if (!ifx_dev->rx_buffer) {
+		dev_err(&spi->dev, "DMA-RX buffer allocation failed");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	/* initialize waitq for modem reset */
+	init_waitqueue_head(&ifx_dev->mdm_reset_wait);
+
+	spi_set_drvdata(spi, ifx_dev);
+	tasklet_init(&ifx_dev->io_work_tasklet, ifx_spi_io,
+						(unsigned long)ifx_dev);
+
+	set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags);
+
+	/* create our tty port */
+	ret = ifx_spi_create_port(ifx_dev);
+	if (ret != 0) {
+		dev_err(&spi->dev, "create default tty port failed");
+		goto error_ret;
+	}
+
+	pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
+	if (pl_data) {
+		ifx_dev->gpio.reset = pl_data->rst_pmu;
+		ifx_dev->gpio.po = pl_data->pwr_on;
+		ifx_dev->gpio.mrdy = pl_data->mrdy;
+		ifx_dev->gpio.srdy = pl_data->srdy;
+		ifx_dev->gpio.reset_out = pl_data->rst_out;
+	} else {
+		dev_err(&spi->dev, "missing platform data!");
+		ret = -ENODEV;
+		goto error_ret;
+	}
+
+	dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d",
+		 ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy,
+		 ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out);
+
+	/* Configure gpios */
+	ret = gpio_request(ifx_dev->gpio.reset, "ifxModem");
+	if (ret < 0) {
+		dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)",
+			ifx_dev->gpio.reset);
+		goto error_ret;
+	}
+	ret += gpio_direction_output(ifx_dev->gpio.reset, 0);
+	ret += gpio_export(ifx_dev->gpio.reset, 1);
+	if (ret) {
+		dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)",
+			ifx_dev->gpio.reset);
+		ret = -EBUSY;
+		goto error_ret2;
+	}
+
+	ret = gpio_request(ifx_dev->gpio.po, "ifxModem");
+	ret += gpio_direction_output(ifx_dev->gpio.po, 0);
+	ret += gpio_export(ifx_dev->gpio.po, 1);
+	if (ret) {
+		dev_err(&spi->dev, "Unable to configure GPIO%d (ON)",
+			ifx_dev->gpio.po);
+		ret = -EBUSY;
+		goto error_ret3;
+	}
+
+	ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem");
+	if (ret < 0) {
+		dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)",
+			ifx_dev->gpio.mrdy);
+		goto error_ret3;
+	}
+	ret += gpio_export(ifx_dev->gpio.mrdy, 1);
+	ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0);
+	if (ret) {
+		dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)",
+			ifx_dev->gpio.mrdy);
+		ret = -EBUSY;
+		goto error_ret4;
+	}
+
+	ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem");
+	if (ret < 0) {
+		dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)",
+			ifx_dev->gpio.srdy);
+		ret = -EBUSY;
+		goto error_ret4;
+	}
+	ret += gpio_export(ifx_dev->gpio.srdy, 1);
+	ret += gpio_direction_input(ifx_dev->gpio.srdy);
+	if (ret) {
+		dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)",
+			ifx_dev->gpio.srdy);
+		ret = -EBUSY;
+		goto error_ret5;
+	}
+
+	ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem");
+	if (ret < 0) {
+		dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)",
+			ifx_dev->gpio.reset_out);
+		goto error_ret5;
+	}
+	ret += gpio_export(ifx_dev->gpio.reset_out, 1);
+	ret += gpio_direction_input(ifx_dev->gpio.reset_out);
+	if (ret) {
+		dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)",
+			ifx_dev->gpio.reset_out);
+		ret = -EBUSY;
+		goto error_ret6;
+	}
+
+	ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
+			  ifx_spi_reset_interrupt,
+			  IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
+		(void *)ifx_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Unable to get irq %x\n",
+			gpio_to_irq(ifx_dev->gpio.reset_out));
+		goto error_ret6;
+	}
+
+	ret = ifx_spi_reset(ifx_dev);
+
+	ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
+			  ifx_spi_srdy_interrupt,
+			  IRQF_TRIGGER_RISING, DRVNAME,
+			  (void *)ifx_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Unable to get irq %x",
+			gpio_to_irq(ifx_dev->gpio.srdy));
+		goto error_ret6;
+	}
+
+	/* set pm runtime power state and register with power system */
+	pm_runtime_set_active(&spi->dev);
+	pm_runtime_enable(&spi->dev);
+
+	/* handle case that modem is already signaling SRDY */
+	/* no outgoing tty open at this point, this just satisfies the
+	 * modem's read and should reset communication properly
+	 */
+	srdy = gpio_get_value(ifx_dev->gpio.srdy);
+
+	if (srdy) {
+		mrdy_assert(ifx_dev);
+		ifx_spi_handle_srdy(ifx_dev);
+	} else
+		mrdy_set_low(ifx_dev);
+	return 0;
+
+error_ret6:
+	gpio_free(ifx_dev->gpio.srdy);
+error_ret5:
+	gpio_free(ifx_dev->gpio.mrdy);
+error_ret4:
+	gpio_free(ifx_dev->gpio.reset);
+error_ret3:
+	gpio_free(ifx_dev->gpio.po);
+error_ret2:
+	gpio_free(ifx_dev->gpio.reset_out);
+error_ret:
+	ifx_spi_free_device(ifx_dev);
+	saved_ifx_dev = NULL;
+	return ret;
+}
+
+/**
+ *	ifx_spi_spi_remove	-	SPI device was removed
+ *	@spi: SPI device
+ *
+ *	FIXME: We should be shutting the device down here not in
+ *	the module unload path.
+ */
+
+static int ifx_spi_spi_remove(struct spi_device *spi)
+{
+	struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+	/* stop activity */
+	tasklet_kill(&ifx_dev->io_work_tasklet);
+	/* free irq */
+	free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
+	free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev);
+
+	gpio_free(ifx_dev->gpio.srdy);
+	gpio_free(ifx_dev->gpio.mrdy);
+	gpio_free(ifx_dev->gpio.reset);
+	gpio_free(ifx_dev->gpio.po);
+	gpio_free(ifx_dev->gpio.reset_out);
+
+	/* free allocations */
+	ifx_spi_free_device(ifx_dev);
+
+	saved_ifx_dev = NULL;
+	return 0;
+}
+
+/**
+ *	ifx_spi_spi_shutdown	-	called on SPI shutdown
+ *	@spi: SPI device
+ *
+ *	No action needs to be taken here
+ */
+
+static void ifx_spi_spi_shutdown(struct spi_device *spi)
+{
+}
+
+/*
+ * various suspends and resumes have nothing to do
+ * no hardware to save state for
+ */
+
+/**
+ *	ifx_spi_spi_suspend	-	suspend SPI on system suspend
+ *	@dev: device being suspended
+ *
+ *	Suspend the SPI side. No action needed on Intel MID platforms, may
+ *	need extending for other systems.
+ */
+static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg)
+{
+	return 0;
+}
+
+/**
+ *	ifx_spi_spi_resume	-	resume SPI side on system resume
+ *	@dev: device being suspended
+ *
+ *	Suspend the SPI side. No action needed on Intel MID platforms, may
+ *	need extending for other systems.
+ */
+static int ifx_spi_spi_resume(struct spi_device *spi)
+{
+	return 0;
+}
+
+/**
+ *	ifx_spi_pm_suspend	-	suspend modem on system suspend
+ *	@dev: device being suspended
+ *
+ *	Suspend the modem. No action needed on Intel MID platforms, may
+ *	need extending for other systems.
+ */
+static int ifx_spi_pm_suspend(struct device *dev)
+{
+	return 0;
+}
+
+/**
+ *	ifx_spi_pm_resume	-	resume modem on system resume
+ *	@dev: device being suspended
+ *
+ *	Allow the modem to resume. No action needed.
+ *
+ *	FIXME: do we need to reset anything here ?
+ */
+static int ifx_spi_pm_resume(struct device *dev)
+{
+	return 0;
+}
+
+/**
+ *	ifx_spi_pm_runtime_resume	-	suspend modem
+ *	@dev: device being suspended
+ *
+ *	Allow the modem to resume. No action needed.
+ */
+static int ifx_spi_pm_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+
+/**
+ *	ifx_spi_pm_runtime_suspend	-	suspend modem
+ *	@dev: device being suspended
+ *
+ *	Allow the modem to suspend and thus suspend to continue up the
+ *	device tree.
+ */
+static int ifx_spi_pm_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+/**
+ *	ifx_spi_pm_runtime_idle		-	check if modem idle
+ *	@dev: our device
+ *
+ *	Check conditions and queue runtime suspend if idle.
+ */
+static int ifx_spi_pm_runtime_idle(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+
+	if (!ifx_dev->power_status)
+		pm_runtime_suspend(dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops ifx_spi_pm = {
+	.resume = ifx_spi_pm_resume,
+	.suspend = ifx_spi_pm_suspend,
+	.runtime_resume = ifx_spi_pm_runtime_resume,
+	.runtime_suspend = ifx_spi_pm_runtime_suspend,
+	.runtime_idle = ifx_spi_pm_runtime_idle
+};
+
+static const struct spi_device_id ifx_id_table[] = {
+	{"ifx6160", 0},
+	{"ifx6260", 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ifx_id_table);
+
+/* spi operations */
+static const struct spi_driver ifx_spi_driver_6160 = {
+	.driver = {
+		.name = "ifx6160",
+		.bus = &spi_bus_type,
+		.pm = &ifx_spi_pm,
+		.owner = THIS_MODULE},
+	.probe = ifx_spi_spi_probe,
+	.shutdown = ifx_spi_spi_shutdown,
+	.remove = __devexit_p(ifx_spi_spi_remove),
+	.suspend = ifx_spi_spi_suspend,
+	.resume = ifx_spi_spi_resume,
+	.id_table = ifx_id_table
+};
+
+/**
+ *	ifx_spi_exit	-	module exit
+ *
+ *	Unload the module.
+ */
+
+static void __exit ifx_spi_exit(void)
+{
+	/* unregister */
+	tty_unregister_driver(tty_drv);
+	spi_unregister_driver((void *)&ifx_spi_driver_6160);
+}
+
+/**
+ *	ifx_spi_init		-	module entry point
+ *
+ *	Initialise the SPI and tty interfaces for the IFX SPI driver
+ *	We need to initialize upper-edge spi driver after the tty
+ *	driver because otherwise the spi probe will race
+ */
+
+static int __init ifx_spi_init(void)
+{
+	int result;
+
+	tty_drv = alloc_tty_driver(1);
+	if (!tty_drv) {
+		pr_err("%s: alloc_tty_driver failed", DRVNAME);
+		return -ENOMEM;
+	}
+
+	tty_drv->magic = TTY_DRIVER_MAGIC;
+	tty_drv->owner = THIS_MODULE;
+	tty_drv->driver_name = DRVNAME;
+	tty_drv->name = TTYNAME;
+	tty_drv->minor_start = IFX_SPI_TTY_ID;
+	tty_drv->num = 1;
+	tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+	tty_drv->subtype = SERIAL_TYPE_NORMAL;
+	tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_drv->init_termios = tty_std_termios;
+
+	tty_set_operations(tty_drv, &ifx_spi_serial_ops);
+
+	result = tty_register_driver(tty_drv);
+	if (result) {
+		pr_err("%s: tty_register_driver failed(%d)",
+			DRVNAME, result);
+		return result;
+	}
+
+	result = spi_register_driver((void *)&ifx_spi_driver_6160);
+	if (result) {
+		pr_err("%s: spi_register_driver failed(%d)",
+			DRVNAME, result);
+		tty_unregister_driver(tty_drv);
+	}
+	return result;
+}
+
+module_init(ifx_spi_init);
+module_exit(ifx_spi_exit);
+
+MODULE_AUTHOR("Intel");
+MODULE_DESCRIPTION("IFX6x60 spi driver");
+MODULE_LICENSE("GPL");
+MODULE_INFO(Version, "0.1-IFX6x60");
diff --git a/drivers/serial/ifx6x60.h b/drivers/serial/ifx6x60.h
new file mode 100644
index 0000000..deb7b8d
--- /dev/null
+++ b/drivers/serial/ifx6x60.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+ *
+ * Driver for the IFX spi modem.
+ *
+ * Copyright (C) 2009, 2010 Intel Corp
+ * Jim Stanley <jim.stanley@intel.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+ * USA
+ *
+ *
+ *
+ *****************************************************************************/
+#ifndef _IFX6X60_H
+#define _IFX6X60_H
+
+#define DRVNAME				"ifx6x60"
+#define TTYNAME				"ttyIFX"
+
+/* #define IFX_THROTTLE_CODE */
+
+#define IFX_SPI_MAX_MINORS		1
+#define IFX_SPI_TRANSFER_SIZE		2048
+#define IFX_SPI_FIFO_SIZE		4096
+
+#define IFX_SPI_HEADER_OVERHEAD		4
+#define IFX_RESET_TIMEOUT		msecs_to_jiffies(50)
+
+/* device flags bitfield definitions */
+#define IFX_SPI_STATE_PRESENT		0
+#define IFX_SPI_STATE_IO_IN_PROGRESS	1
+#define IFX_SPI_STATE_IO_READY		2
+#define IFX_SPI_STATE_TIMER_PENDING	3
+
+/* flow control bitfields */
+#define IFX_SPI_DCD			0
+#define IFX_SPI_CTS			1
+#define IFX_SPI_DSR			2
+#define IFX_SPI_RI			3
+#define IFX_SPI_DTR			4
+#define IFX_SPI_RTS			5
+#define IFX_SPI_TX_FC			6
+#define IFX_SPI_RX_FC			7
+#define IFX_SPI_UPDATE			8
+
+#define IFX_SPI_PAYLOAD_SIZE		(IFX_SPI_TRANSFER_SIZE - \
+						IFX_SPI_HEADER_OVERHEAD)
+
+#define IFX_SPI_IRQ_TYPE		DETECT_EDGE_RISING
+#define IFX_SPI_GPIO_TARGET		0
+#define IFX_SPI_GPIO0			0x105
+
+#define IFX_SPI_STATUS_TIMEOUT		(2000*HZ)
+
+/* values for bits in power status byte */
+#define IFX_SPI_POWER_DATA_PENDING	1
+#define IFX_SPI_POWER_SRDY		2
+
+struct ifx_spi_device {
+	/* Our SPI device */
+	struct spi_device *spi_dev;
+
+	/* Port specific data */
+	struct kfifo tx_fifo;
+	spinlock_t fifo_lock;
+	unsigned long signal_state;
+
+	/* TTY Layer logic */
+	struct tty_port tty_port;
+	struct device *tty_dev;
+	int minor;
+
+	/* Low level I/O work */
+	struct tasklet_struct io_work_tasklet;
+	unsigned long flags;
+	dma_addr_t rx_dma;
+	dma_addr_t tx_dma;
+
+	int is_6160;				/* Modem type */
+
+	spinlock_t write_lock;
+	int write_pending;
+	spinlock_t power_lock;
+	unsigned char power_status;
+
+	unsigned char *rx_buffer;
+	unsigned char *tx_buffer;
+	dma_addr_t rx_bus;
+	dma_addr_t tx_bus;
+	unsigned char spi_more;
+	unsigned char spi_slave_cts;
+
+	struct timer_list spi_timer;
+
+	struct spi_message spi_msg;
+	struct spi_transfer spi_xfer;
+
+	struct {
+		/* gpio lines */
+		unsigned short srdy;		/* slave-ready gpio */
+		unsigned short mrdy;		/* master-ready gpio */
+		unsigned short reset;		/* modem-reset gpio */
+		unsigned short po;		/* modem-on gpio */
+		unsigned short reset_out;	/* modem-in-reset gpio */
+		/* state/stats */
+		int unack_srdy_int_nb;
+	} gpio;
+
+	/* modem reset */
+	unsigned long mdm_reset_state;
+#define MR_START	0
+#define MR_INPROGRESS	1
+#define MR_COMPLETE	2
+	wait_queue_head_t mdm_reset_wait;
+};
+
+#endif /* _IFX6X60_H */
diff --git a/include/linux/spi/ifx_modem.h b/include/linux/spi/ifx_modem.h
new file mode 100644
index 0000000..a68f3b1
--- /dev/null
+++ b/include/linux/spi/ifx_modem.h
@@ -0,0 +1,14 @@
+#ifndef LINUX_IFX_MODEM_H
+#define LINUX_IFX_MODEM_H
+
+struct ifx_modem_platform_data {
+	unsigned short rst_out; /* modem reset out */
+	unsigned short pwr_on;  /* power on */
+	unsigned short rst_pmu; /* reset modem */
+	unsigned short tx_pwr;  /* modem power threshold */
+	unsigned short srdy;    /* SRDY */
+	unsigned short mrdy;    /* MRDY */
+	unsigned short is_6160;	/* Modem type */
+};
+
+#endif
-- 
1.7.3.2


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

* [PATCH 02/36] serial: Add support for UART on VIA VT8500 and compatibles
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
  2011-01-06 22:00 ` Alan Cox
  2011-01-06 22:22 ` [PATCH 01/36] ifx6x60: SPI protocol driver for Infineon 6x60 modem Greg Kroah-Hartman
@ 2011-01-06 22:22 ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 03/36] n_gsm: Fix support for legacy encoding Greg Kroah-Hartman
                   ` (34 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: Alexey Charkov, Greg Kroah-Hartman

From: Alexey Charkov <alchark@gmail.com>

This adds a driver for the serial ports found in VIA and WonderMedia
Systems-on-Chip. Interrupt-driven FIFO operation is implemented.
The hardware also supports pure register-based operation (which is
slower) and DMA-based FIFO operation. As the FIFOs are only 16 bytes
long, DMA operation is probably not worth the hassle.

Signed-off-by: Alexey Charkov <alchark@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/Kconfig         |   10 +
 drivers/serial/Makefile        |    1 +
 drivers/serial/vt8500_serial.c |  648 ++++++++++++++++++++++++++++++++++++++++
 include/linux/serial_core.h    |    3 +
 4 files changed, 662 insertions(+), 0 deletions(-)
 create mode 100644 drivers/serial/vt8500_serial.c

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 0b9cc17..388e371 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1381,6 +1381,16 @@ config SERIAL_MSM_CONSOLE
 	depends on SERIAL_MSM=y
 	select SERIAL_CORE_CONSOLE
 
+config SERIAL_VT8500
+	bool "VIA VT8500 on-chip serial port support"
+	depends on ARM && ARCH_VT8500
+	select SERIAL_CORE
+
+config SERIAL_VT8500_CONSOLE
+	bool "VIA VT8500 serial console support"
+	depends on SERIAL_VT8500=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 783638b..a5e2264 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_SERIAL_TIMBERDALE)	+= timbuart.o
 obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
 obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
 obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
+obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
 obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
 obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
diff --git a/drivers/serial/vt8500_serial.c b/drivers/serial/vt8500_serial.c
new file mode 100644
index 0000000..322bf56
--- /dev/null
+++ b/drivers/serial/vt8500_serial.c
@@ -0,0 +1,648 @@
+/*
+ * drivers/serial/vt8500_serial.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Based on msm_serial.c, which is:
+ * 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_VT8500_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+# define SUPPORT_SYSRQ
+#endif
+
+#include <linux/hrtimer.h>
+#include <linux/delay.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/slab.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/*
+ * UART Register offsets
+ */
+
+#define VT8500_URTDR		0x0000	/* Transmit data */
+#define VT8500_URRDR		0x0004	/* Receive data */
+#define VT8500_URDIV		0x0008	/* Clock/Baud rate divisor */
+#define VT8500_URLCR		0x000C	/* Line control */
+#define VT8500_URICR		0x0010	/* IrDA control */
+#define VT8500_URIER		0x0014	/* Interrupt enable */
+#define VT8500_URISR		0x0018	/* Interrupt status */
+#define VT8500_URUSR		0x001c	/* UART status */
+#define VT8500_URFCR		0x0020	/* FIFO control */
+#define VT8500_URFIDX		0x0024	/* FIFO index */
+#define VT8500_URBKR		0x0028	/* Break signal count */
+#define VT8500_URTOD		0x002c	/* Time out divisor */
+#define VT8500_TXFIFO		0x1000	/* Transmit FIFO (16x8) */
+#define VT8500_RXFIFO		0x1020	/* Receive FIFO (16x10) */
+
+/*
+ * Interrupt enable and status bits
+ */
+
+#define TXDE	(1 << 0)	/* Tx Data empty */
+#define RXDF	(1 << 1)	/* Rx Data full */
+#define TXFAE	(1 << 2)	/* Tx FIFO almost empty */
+#define TXFE	(1 << 3)	/* Tx FIFO empty */
+#define RXFAF	(1 << 4)	/* Rx FIFO almost full */
+#define RXFF	(1 << 5)	/* Rx FIFO full */
+#define TXUDR	(1 << 6)	/* Tx underrun */
+#define RXOVER	(1 << 7)	/* Rx overrun */
+#define PER	(1 << 8)	/* Parity error */
+#define FER	(1 << 9)	/* Frame error */
+#define TCTS	(1 << 10)	/* Toggle of CTS */
+#define RXTOUT	(1 << 11)	/* Rx timeout */
+#define BKDONE	(1 << 12)	/* Break signal done */
+#define ERR	(1 << 13)	/* AHB error response */
+
+#define RX_FIFO_INTS	(RXFAF | RXFF | RXOVER | PER | FER | RXTOUT)
+#define TX_FIFO_INTS	(TXFAE | TXFE | TXUDR)
+
+struct vt8500_port {
+	struct uart_port	uart;
+	char			name[16];
+	struct clk		*clk;
+	unsigned int		ier;
+};
+
+static inline void vt8500_write(struct uart_port *port, unsigned int val,
+			     unsigned int off)
+{
+	writel(val, port->membase + off);
+}
+
+static inline unsigned int vt8500_read(struct uart_port *port, unsigned int off)
+{
+	return readl(port->membase + off);
+}
+
+static void vt8500_stop_tx(struct uart_port *port)
+{
+	struct vt8500_port *vt8500_port = container_of(port,
+						       struct vt8500_port,
+						       uart);
+
+	vt8500_port->ier &= ~TX_FIFO_INTS;
+	vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void vt8500_stop_rx(struct uart_port *port)
+{
+	struct vt8500_port *vt8500_port = container_of(port,
+						       struct vt8500_port,
+						       uart);
+
+	vt8500_port->ier &= ~RX_FIFO_INTS;
+	vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void vt8500_enable_ms(struct uart_port *port)
+{
+	struct vt8500_port *vt8500_port = container_of(port,
+						       struct vt8500_port,
+						       uart);
+
+	vt8500_port->ier |= TCTS;
+	vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void handle_rx(struct uart_port *port)
+{
+	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+	if (!tty) {
+		/* Discard data: no tty available */
+		int count = (vt8500_read(port, VT8500_URFIDX) & 0x1f00) >> 8;
+		u16 ch;
+		while (count--)
+			ch = readw(port->membase + VT8500_RXFIFO);
+		return;
+	}
+
+	/*
+	 * Handle overrun
+	 */
+	if ((vt8500_read(port, VT8500_URISR) & RXOVER)) {
+		port->icount.overrun++;
+		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+	}
+
+	/* and now the main RX loop */
+	while (vt8500_read(port, VT8500_URFIDX) & 0x1f00) {
+		unsigned int c;
+		char flag = TTY_NORMAL;
+
+		c = readw(port->membase + VT8500_RXFIFO) & 0x3ff;
+
+		/* Mask conditions we're ignorning. */
+		c &= ~port->read_status_mask;
+
+		if (c & FER) {
+			port->icount.frame++;
+			flag = TTY_FRAME;
+		} else if (c & PER) {
+			port->icount.parity++;
+			flag = TTY_PARITY;
+		}
+		port->icount.rx++;
+
+		if (!uart_handle_sysrq_char(port, c))
+			tty_insert_flip_char(tty, c, flag);
+	}
+
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+}
+
+static void handle_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (port->x_char) {
+		writeb(port->x_char, port->membase + VT8500_TXFIFO);
+		port->icount.tx++;
+		port->x_char = 0;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		vt8500_stop_tx(port);
+		return;
+	}
+
+	while ((vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16) {
+		if (uart_circ_empty(xmit))
+			break;
+
+		writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO);
+
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		vt8500_stop_tx(port);
+}
+
+static void vt8500_start_tx(struct uart_port *port)
+{
+	struct vt8500_port *vt8500_port = container_of(port,
+						       struct vt8500_port,
+						       uart);
+
+	vt8500_port->ier &= ~TX_FIFO_INTS;
+	vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+	handle_tx(port);
+	vt8500_port->ier |= TX_FIFO_INTS;
+	vt8500_write(port, vt8500_port->ier, VT8500_URIER);
+}
+
+static void handle_delta_cts(struct uart_port *port)
+{
+	port->icount.cts++;
+	wake_up_interruptible(&port->state->port.delta_msr_wait);
+}
+
+static irqreturn_t vt8500_irq(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	unsigned long isr;
+
+	spin_lock(&port->lock);
+	isr = vt8500_read(port, VT8500_URISR);
+
+	/* Acknowledge active status bits */
+	vt8500_write(port, isr, VT8500_URISR);
+
+	if (isr & RX_FIFO_INTS)
+		handle_rx(port);
+	if (isr & TX_FIFO_INTS)
+		handle_tx(port);
+	if (isr & TCTS)
+		handle_delta_cts(port);
+
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int vt8500_tx_empty(struct uart_port *port)
+{
+	return (vt8500_read(port, VT8500_URFIDX) & 0x1f) < 16 ?
+						TIOCSER_TEMT : 0;
+}
+
+static unsigned int vt8500_get_mctrl(struct uart_port *port)
+{
+	unsigned int usr;
+
+	usr = vt8500_read(port, VT8500_URUSR);
+	if (usr & (1 << 4))
+		return TIOCM_CTS;
+	else
+		return 0;
+}
+
+static void vt8500_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void vt8500_break_ctl(struct uart_port *port, int break_ctl)
+{
+	if (break_ctl)
+		vt8500_write(port, vt8500_read(port, VT8500_URLCR) | (1 << 9),
+			     VT8500_URLCR);
+}
+
+static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+	unsigned long div;
+	unsigned int loops = 1000;
+
+	div = vt8500_read(port, VT8500_URDIV) & ~(0x3ff);
+
+	if (unlikely((baud < 900) || (baud > 921600)))
+		div |= 7;
+	else
+		div |= (921600 / baud) - 1;
+
+	while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops)
+		cpu_relax();
+	vt8500_write(port, div, VT8500_URDIV);
+
+	return baud;
+}
+
+static int vt8500_startup(struct uart_port *port)
+{
+	struct vt8500_port *vt8500_port =
+			container_of(port, struct vt8500_port, uart);
+	int ret;
+
+	snprintf(vt8500_port->name, sizeof(vt8500_port->name),
+		 "vt8500_serial%d", port->line);
+
+	ret = request_irq(port->irq, vt8500_irq, IRQF_TRIGGER_HIGH,
+			  vt8500_port->name, port);
+	if (unlikely(ret))
+		return ret;
+
+	vt8500_write(port, 0x03, VT8500_URLCR);	/* enable TX & RX */
+
+	return 0;
+}
+
+static void vt8500_shutdown(struct uart_port *port)
+{
+	struct vt8500_port *vt8500_port =
+			container_of(port, struct vt8500_port, uart);
+
+	vt8500_port->ier = 0;
+
+	/* disable interrupts and FIFOs */
+	vt8500_write(&vt8500_port->uart, 0, VT8500_URIER);
+	vt8500_write(&vt8500_port->uart, 0x880, VT8500_URFCR);
+	free_irq(port->irq, port);
+}
+
+static void vt8500_set_termios(struct uart_port *port,
+			       struct ktermios *termios,
+			       struct ktermios *old)
+{
+	struct vt8500_port *vt8500_port =
+			container_of(port, struct vt8500_port, uart);
+	unsigned long flags;
+	unsigned int baud, lcr;
+	unsigned int loops = 1000;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* calculate and set baud rate */
+	baud = uart_get_baud_rate(port, termios, old, 900, 921600);
+	baud = vt8500_set_baud_rate(port, baud);
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+
+	/* calculate parity */
+	lcr = vt8500_read(&vt8500_port->uart, VT8500_URLCR);
+	lcr &= ~((1 << 5) | (1 << 4));
+	if (termios->c_cflag & PARENB) {
+		lcr |= (1 << 4);
+		termios->c_cflag &= ~CMSPAR;
+		if (termios->c_cflag & PARODD)
+			lcr |= (1 << 5);
+	}
+
+	/* calculate bits per char */
+	lcr &= ~(1 << 2);
+	switch (termios->c_cflag & CSIZE) {
+	case CS7:
+		break;
+	case CS8:
+	default:
+		lcr |= (1 << 2);
+		termios->c_cflag &= ~CSIZE;
+		termios->c_cflag |= CS8;
+		break;
+	}
+
+	/* calculate stop bits */
+	lcr &= ~(1 << 3);
+	if (termios->c_cflag & CSTOPB)
+		lcr |= (1 << 3);
+
+	/* set parity, bits per char, and stop bit */
+	vt8500_write(&vt8500_port->uart, lcr, VT8500_URLCR);
+
+	/* Configure status bits to ignore based on termio flags. */
+	port->read_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->read_status_mask = FER | PER;
+
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	/* Reset FIFOs */
+	vt8500_write(&vt8500_port->uart, 0x88c, VT8500_URFCR);
+	while ((vt8500_read(&vt8500_port->uart, VT8500_URFCR) & 0xc)
+							&& --loops)
+		cpu_relax();
+
+	/* Every possible FIFO-related interrupt */
+	vt8500_port->ier = RX_FIFO_INTS | TX_FIFO_INTS;
+
+	/*
+	 * CTS flow control
+	 */
+	if (UART_ENABLE_MS(&vt8500_port->uart, termios->c_cflag))
+		vt8500_port->ier |= TCTS;
+
+	vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR);
+	vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *vt8500_type(struct uart_port *port)
+{
+	struct vt8500_port *vt8500_port =
+			container_of(port, struct vt8500_port, uart);
+	return vt8500_port->name;
+}
+
+static void vt8500_release_port(struct uart_port *port)
+{
+}
+
+static int vt8500_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+static void vt8500_config_port(struct uart_port *port, int flags)
+{
+	port->type = PORT_VT8500;
+}
+
+static int vt8500_verify_port(struct uart_port *port,
+			      struct serial_struct *ser)
+{
+	if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_VT8500))
+		return -EINVAL;
+	if (unlikely(port->irq != ser->irq))
+		return -EINVAL;
+	return 0;
+}
+
+static struct vt8500_port *vt8500_uart_ports[4];
+static struct uart_driver vt8500_uart_driver;
+
+#ifdef CONFIG_SERIAL_VT8500_CONSOLE
+
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+	unsigned int status, tmout = 10000;
+
+	/* Wait up to 10ms for the character(s) to be sent. */
+	do {
+		status = vt8500_read(port, VT8500_URFIDX);
+
+		if (--tmout == 0)
+			break;
+		udelay(1);
+	} while (status & 0x10);
+}
+
+static void vt8500_console_putchar(struct uart_port *port, int c)
+{
+	wait_for_xmitr(port);
+	writeb(c, port->membase + VT8500_TXFIFO);
+}
+
+static void vt8500_console_write(struct console *co, const char *s,
+			      unsigned int count)
+{
+	struct vt8500_port *vt8500_port = vt8500_uart_ports[co->index];
+	unsigned long ier;
+
+	BUG_ON(co->index < 0 || co->index >= vt8500_uart_driver.nr);
+
+	ier = vt8500_read(&vt8500_port->uart, VT8500_URIER);
+	vt8500_write(&vt8500_port->uart, VT8500_URIER, 0);
+
+	uart_console_write(&vt8500_port->uart, s, count,
+			   vt8500_console_putchar);
+
+	/*
+	 *	Finally, wait for transmitter to become empty
+	 *	and switch back to FIFO
+	 */
+	wait_for_xmitr(&vt8500_port->uart);
+	vt8500_write(&vt8500_port->uart, VT8500_URIER, ier);
+}
+
+static int __init vt8500_console_setup(struct console *co, char *options)
+{
+	struct vt8500_port *vt8500_port;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (unlikely(co->index >= vt8500_uart_driver.nr || co->index < 0))
+		return -ENXIO;
+
+	vt8500_port = vt8500_uart_ports[co->index];
+
+	if (!vt8500_port)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&vt8500_port->uart,
+				 co, baud, parity, bits, flow);
+}
+
+static struct console vt8500_console = {
+	.name = "ttyWMT",
+	.write = vt8500_console_write,
+	.device = uart_console_device,
+	.setup = vt8500_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+	.data = &vt8500_uart_driver,
+};
+
+#define VT8500_CONSOLE	(&vt8500_console)
+
+#else
+#define VT8500_CONSOLE	NULL
+#endif
+
+static struct uart_ops vt8500_uart_pops = {
+	.tx_empty	= vt8500_tx_empty,
+	.set_mctrl	= vt8500_set_mctrl,
+	.get_mctrl	= vt8500_get_mctrl,
+	.stop_tx	= vt8500_stop_tx,
+	.start_tx	= vt8500_start_tx,
+	.stop_rx	= vt8500_stop_rx,
+	.enable_ms	= vt8500_enable_ms,
+	.break_ctl	= vt8500_break_ctl,
+	.startup	= vt8500_startup,
+	.shutdown	= vt8500_shutdown,
+	.set_termios	= vt8500_set_termios,
+	.type		= vt8500_type,
+	.release_port	= vt8500_release_port,
+	.request_port	= vt8500_request_port,
+	.config_port	= vt8500_config_port,
+	.verify_port	= vt8500_verify_port,
+};
+
+static struct uart_driver vt8500_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "vt8500_serial",
+	.dev_name	= "ttyWMT",
+	.nr		= 6,
+	.cons		= VT8500_CONSOLE,
+};
+
+static int __init vt8500_serial_probe(struct platform_device *pdev)
+{
+	struct vt8500_port *vt8500_port;
+	struct resource *mmres, *irqres;
+	int ret;
+
+	mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!mmres || !irqres)
+		return -ENODEV;
+
+	vt8500_port = kzalloc(sizeof(struct vt8500_port), GFP_KERNEL);
+	if (!vt8500_port)
+		return -ENOMEM;
+
+	vt8500_port->uart.type = PORT_VT8500;
+	vt8500_port->uart.iotype = UPIO_MEM;
+	vt8500_port->uart.mapbase = mmres->start;
+	vt8500_port->uart.irq = irqres->start;
+	vt8500_port->uart.fifosize = 16;
+	vt8500_port->uart.ops = &vt8500_uart_pops;
+	vt8500_port->uart.line = pdev->id;
+	vt8500_port->uart.dev = &pdev->dev;
+	vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+	vt8500_port->uart.uartclk = 24000000;
+
+	snprintf(vt8500_port->name, sizeof(vt8500_port->name),
+		 "VT8500 UART%d", pdev->id);
+
+	vt8500_port->uart.membase = ioremap(mmres->start,
+					    mmres->end - mmres->start + 1);
+	if (!vt8500_port->uart.membase) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	vt8500_uart_ports[pdev->id] = vt8500_port;
+
+	uart_add_one_port(&vt8500_uart_driver, &vt8500_port->uart);
+
+	platform_set_drvdata(pdev, vt8500_port);
+
+	return 0;
+
+err:
+	kfree(vt8500_port);
+	return ret;
+}
+
+static int __devexit vt8500_serial_remove(struct platform_device *pdev)
+{
+	struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
+	kfree(vt8500_port);
+
+	return 0;
+}
+
+static struct platform_driver vt8500_platform_driver = {
+	.probe  = vt8500_serial_probe,
+	.remove = vt8500_serial_remove,
+	.driver = {
+		.name = "vt8500_serial",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init vt8500_serial_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&vt8500_uart_driver);
+	if (unlikely(ret))
+		return ret;
+
+	ret = platform_driver_register(&vt8500_platform_driver);
+
+	if (unlikely(ret))
+		uart_unregister_driver(&vt8500_uart_driver);
+
+	return ret;
+}
+
+static void __exit vt8500_serial_exit(void)
+{
+#ifdef CONFIG_SERIAL_VT8500_CONSOLE
+	unregister_console(&vt8500_console);
+#endif
+	platform_driver_unregister(&vt8500_platform_driver);
+	uart_unregister_driver(&vt8500_uart_driver);
+}
+
+module_init(vt8500_serial_init);
+module_exit(vt8500_serial_exit);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
+MODULE_DESCRIPTION("Driver for vt8500 serial device");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 212eb4c..41603d6 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -199,6 +199,9 @@
 /* TI OMAP-UART */
 #define PORT_OMAP	96
 
+/* VIA VT8500 SoC */
+#define PORT_VT8500	97
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
-- 
1.7.3.2


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

* [PATCH 03/36] n_gsm: Fix support for legacy encoding
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (2 preceding siblings ...)
  2011-01-06 22:22 ` [PATCH 02/36] serial: Add support for UART on VIA VT8500 and compatibles Greg Kroah-Hartman
@ 2011-01-06 22:22 ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 04/36] n_gsm: clean up printks Greg Kroah-Hartman
                   ` (33 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: Alan Cox, Ken Mills, Greg Kroah-Hartman

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

The mux supports several encoding schemes. Encoding 0 is a "not
recommended" mode still sometimes used. This has now been tested with
hardware that supports this mode, and found wanting.

Fix the FCS handling in this mode and correct the state machine.

Signed-off-by: Ken Mills <ken.k.mills@intel.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/tty/n_gsm.c |   59 +++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 04ef3ef..5256087 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -184,6 +184,9 @@ struct gsm_mux {
 #define GSM_DATA		5
 #define GSM_FCS			6
 #define GSM_OVERRUN		7
+#define GSM_LEN0		8
+#define GSM_LEN1		9
+#define GSM_SSOF		10
 	unsigned int len;
 	unsigned int address;
 	unsigned int count;
@@ -191,6 +194,7 @@ struct gsm_mux {
 	int encoding;
 	u8 control;
 	u8 fcs;
+	u8 received_fcs;
 	u8 *txframe;			/* TX framing buffer */
 
 	/* Methods for the receiver side */
@@ -1623,7 +1627,6 @@ static void gsm_dlci_free(struct gsm_dlci *dlci)
 	kfree(dlci);
 }
 
-
 /*
  *	LAPBish link layer logic
  */
@@ -1648,6 +1651,8 @@ static void gsm_queue(struct gsm_mux *gsm)
 
 	if ((gsm->control & ~PF) == UI)
 		gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
+	/* generate final CRC with received FCS */
+	gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
 	if (gsm->fcs != GOOD_FCS) {
 		gsm->bad_fcs++;
 		if (debug & 4)
@@ -1746,6 +1751,8 @@ invalid:
 
 static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
 {
+	unsigned int len;
+
 	switch (gsm->state) {
 	case GSM_SEARCH:	/* SOF marker */
 		if (c == GSM0_SOF) {
@@ -1754,8 +1761,8 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
 			gsm->len = 0;
 			gsm->fcs = INIT_FCS;
 		}
-		break;		/* Address EA */
-	case GSM_ADDRESS:
+		break;
+	case GSM_ADDRESS:	/* Address EA */
 		gsm->fcs = gsm_fcs_add(gsm->fcs, c);
 		if (gsm_read_ea(&gsm->address, c))
 			gsm->state = GSM_CONTROL;
@@ -1763,9 +1770,9 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
 	case GSM_CONTROL:	/* Control Byte */
 		gsm->fcs = gsm_fcs_add(gsm->fcs, c);
 		gsm->control = c;
-		gsm->state = GSM_LEN;
+		gsm->state = GSM_LEN0;
 		break;
-	case GSM_LEN:		/* Length EA */
+	case GSM_LEN0:		/* Length EA */
 		gsm->fcs = gsm_fcs_add(gsm->fcs, c);
 		if (gsm_read_ea(&gsm->len, c)) {
 			if (gsm->len > gsm->mru) {
@@ -1774,8 +1781,28 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
 				break;
 			}
 			gsm->count = 0;
-			gsm->state = GSM_DATA;
+			if (!gsm->len)
+				gsm->state = GSM_FCS;
+			else
+				gsm->state = GSM_DATA;
+			break;
 		}
+		gsm->state = GSM_LEN1;
+		break;
+	case GSM_LEN1:
+		gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+		len = c;
+		gsm->len |= len << 7;
+		if (gsm->len > gsm->mru) {
+			gsm->bad_size++;
+			gsm->state = GSM_SEARCH;
+			break;
+		}
+		gsm->count = 0;
+		if (!gsm->len)
+			gsm->state = GSM_FCS;
+		else
+			gsm->state = GSM_DATA;
 		break;
 	case GSM_DATA:		/* Data */
 		gsm->buf[gsm->count++] = c;
@@ -1783,16 +1810,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
 			gsm->state = GSM_FCS;
 		break;
 	case GSM_FCS:		/* FCS follows the packet */
-		gsm->fcs = c;
+		gsm->received_fcs = c;
+		if (c == GSM0_SOF) {
+			gsm->state = GSM_SEARCH;
+			break;
+		}
 		gsm_queue(gsm);
-		/* And then back for the next frame */
-		gsm->state = GSM_SEARCH;
+		gsm->state = GSM_SSOF;
+		break;
+	case GSM_SSOF:
+		if (c == GSM0_SOF) {
+			gsm->state = GSM_SEARCH;
+			break;
+		}
 		break;
 	}
 }
 
 /**
- *	gsm0_receive	-	perform processing for non-transparency
+ *	gsm1_receive	-	perform processing for non-transparency
  *	@gsm: gsm data for this ldisc instance
  *	@c: character
  *
@@ -2032,9 +2068,6 @@ struct gsm_mux *gsm_alloc_mux(void)
 }
 EXPORT_SYMBOL_GPL(gsm_alloc_mux);
 
-
-
-
 /**
  *	gsmld_output		-	write to link
  *	@gsm: our mux
-- 
1.7.3.2


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

* [PATCH 04/36] n_gsm: clean up printks
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (3 preceding siblings ...)
  2011-01-06 22:22 ` [PATCH 03/36] n_gsm: Fix support for legacy encoding Greg Kroah-Hartman
@ 2011-01-06 22:22 ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 05/36] serial: add Documentation about RS485 serial communications Greg Kroah-Hartman
                   ` (32 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: Alan Cox, Greg Kroah-Hartman

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

[Original From Ken Mills but I redid it using pr_ helpers instead]

Also fix up coding style, there are two warnings left but that is where
the CodingStyle tools blow up because they cannot handle

	if (blah) {
		foo
	} else switch (x) {
		case 1:
		}

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/tty/n_gsm.c |  154 +++++++++++++++++++++++++++------------------------
 1 files changed, 81 insertions(+), 73 deletions(-)

diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 5256087..11a25fa 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -19,7 +19,7 @@
  *
  * TO DO:
  *	Mostly done:	ioctls for setting modes/timing
- *	Partly done: 	hooks so you can pull off frames to non tty devs
+ *	Partly done:	hooks so you can pull off frames to non tty devs
  *	Restart DLCI 0 when it closes ?
  *	Test basic encoding
  *	Improve the tx engine
@@ -73,8 +73,10 @@ module_param(debug, int, 0600);
 #define T2	(2 * HZ)
 #endif
 
-/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
-   limits so this is plenty */
+/*
+ * Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
+ * limits so this is plenty
+ */
 #define MAX_MRU 512
 #define MAX_MTU 512
 
@@ -290,7 +292,7 @@ static spinlock_t gsm_mux_lock;
 #define MDM_DV			0x40
 
 #define GSM0_SOF		0xF9
-#define GSM1_SOF 		0x7E
+#define GSM1_SOF		0x7E
 #define GSM1_ESCAPE		0x7D
 #define GSM1_ESCAPE_BITS	0x20
 #define XON			0x11
@@ -433,61 +435,63 @@ static void gsm_print_packet(const char *hdr, int addr, int cr,
 	if (!(debug & 1))
 		return;
 
-	printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
+	pr_info("%s %d) %c: ", hdr, addr, "RC"[cr]);
 
 	switch (control & ~PF) {
 	case SABM:
-		printk(KERN_CONT "SABM");
+		pr_cont("SABM");
 		break;
 	case UA:
-		printk(KERN_CONT "UA");
+		pr_cont("UA");
 		break;
 	case DISC:
-		printk(KERN_CONT "DISC");
+		pr_cont("DISC");
 		break;
 	case DM:
-		printk(KERN_CONT "DM");
+		pr_cont("DM");
 		break;
 	case UI:
-		printk(KERN_CONT "UI");
+		pr_cont("UI");
 		break;
 	case UIH:
-		printk(KERN_CONT "UIH");
+		pr_cont("UIH");
 		break;
 	default:
 		if (!(control & 0x01)) {
-			printk(KERN_CONT "I N(S)%d N(R)%d",
-				(control & 0x0E) >> 1, (control & 0xE)>> 5);
+			pr_cont("I N(S)%d N(R)%d",
+				(control & 0x0E) >> 1, (control & 0xE) >> 5);
 		} else switch (control & 0x0F) {
-		case RR:
-			printk("RR(%d)", (control & 0xE0) >> 5);
-			break;
-		case RNR:
-			printk("RNR(%d)", (control & 0xE0) >> 5);
-			break;
-		case REJ:
-			printk("REJ(%d)", (control & 0xE0) >> 5);
-			break;
-		default:
-			printk(KERN_CONT "[%02X]", control);
+			case RR:
+				pr_cont("RR(%d)", (control & 0xE0) >> 5);
+				break;
+			case RNR:
+				pr_cont("RNR(%d)", (control & 0xE0) >> 5);
+				break;
+			case REJ:
+				pr_cont("REJ(%d)", (control & 0xE0) >> 5);
+				break;
+			default:
+				pr_cont("[%02X]", control);
 		}
 	}
 
 	if (control & PF)
-		printk(KERN_CONT "(P)");
+		pr_cont("(P)");
 	else
-		printk(KERN_CONT "(F)");
+		pr_cont("(F)");
 
 	if (dlen) {
 		int ct = 0;
 		while (dlen--) {
-			if (ct % 8 == 0)
-				printk(KERN_CONT "\n    ");
-			printk(KERN_CONT "%02X ", *data++);
+			if (ct % 8 == 0) {
+				pr_cont("\n");
+				pr_debug("    ");
+			}
+			pr_cont("%02X ", *data++);
 			ct++;
 		}
 	}
-	printk(KERN_CONT "\n");
+	pr_cont("\n");
 }
 
 
@@ -526,11 +530,13 @@ static void hex_packet(const unsigned char *p, int len)
 {
 	int i;
 	for (i = 0; i < len; i++) {
-		if (i && (i % 16) == 0)
-			printk("\n");
-		printk("%02X ", *p++);
+		if (i && (i % 16) == 0) {
+			pr_cont("\n");
+			pr_debug("");
+		}
+		pr_cont("%02X ", *p++);
 	}
-	printk("\n");
+	pr_cont("\n");
 }
 
 /**
@@ -680,7 +686,7 @@ static void gsm_data_kick(struct gsm_mux *gsm)
 		}
 
 		if (debug & 4) {
-			printk("gsm_data_kick: \n");
+			pr_debug("gsm_data_kick:\n");
 			hex_packet(gsm->txframe, len);
 		}
 
@@ -1233,7 +1239,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
 }
 
 /**
- *	gsm_control_transmit 	-	send control packet
+ *	gsm_control_transmit	-	send control packet
  *	@gsm: gsm mux
  *	@ctrl: frame to send
  *
@@ -1363,7 +1369,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
 {
 	del_timer(&dlci->t1);
 	if (debug & 8)
-		printk("DLCI %d goes closed.\n", dlci->addr);
+		pr_debug("DLCI %d goes closed.\n", dlci->addr);
 	dlci->state = DLCI_CLOSED;
 	if (dlci->addr != 0) {
 		struct tty_struct  *tty = tty_port_tty_get(&dlci->port);
@@ -1394,7 +1400,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
 	/* This will let a tty open continue */
 	dlci->state = DLCI_OPEN;
 	if (debug & 8)
-		printk("DLCI %d goes open.\n", dlci->addr);
+		pr_debug("DLCI %d goes open.\n", dlci->addr);
 	wake_up(&dlci->gsm->event);
 }
 
@@ -1496,29 +1502,29 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
 	unsigned int modem = 0;
 
 	if (debug & 16)
-		printk("%d bytes for tty %p\n", len, tty);
+		pr_debug("%d bytes for tty %p\n", len, tty);
 	if (tty) {
 		switch (dlci->adaption)  {
-			/* Unsupported types */
-			/* Packetised interruptible data */
-			case 4:
-				break;
-			/* Packetised uininterruptible voice/data */
-			case 3:
-				break;
-			/* Asynchronous serial with line state in each frame */
-			case 2:
-				while (gsm_read_ea(&modem, *data++) == 0) {
-					len--;
-					if (len == 0)
-						return;
-				}
-				gsm_process_modem(tty, dlci, modem);
-			/* Line state will go via DLCI 0 controls only */
-			case 1:
-			default:
-				tty_insert_flip_string(tty, data, len);
-				tty_flip_buffer_push(tty);
+		/* Unsupported types */
+		/* Packetised interruptible data */
+		case 4:
+			break;
+		/* Packetised uininterruptible voice/data */
+		case 3:
+			break;
+		/* Asynchronous serial with line state in each frame */
+		case 2:
+			while (gsm_read_ea(&modem, *data++) == 0) {
+				len--;
+				if (len == 0)
+					return;
+			}
+			gsm_process_modem(tty, dlci, modem);
+		/* Line state will go via DLCI 0 controls only */
+		case 1:
+		default:
+			tty_insert_flip_string(tty, data, len);
+			tty_flip_buffer_push(tty);
 		}
 		tty_kref_put(tty);
 	}
@@ -1656,7 +1662,7 @@ static void gsm_queue(struct gsm_mux *gsm)
 	if (gsm->fcs != GOOD_FCS) {
 		gsm->bad_fcs++;
 		if (debug & 4)
-			printk("BAD FCS %02x\n", gsm->fcs);
+			pr_debug("BAD FCS %02x\n", gsm->fcs);
 		return;
 	}
 	address = gsm->address >> 1;
@@ -1890,7 +1896,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
 		gsm->state = GSM_DATA;
 		break;
 	case GSM_DATA:		/* Data */
-		if (gsm->count > gsm->mru ) {	/* Allow one for the FCS */
+		if (gsm->count > gsm->mru) {	/* Allow one for the FCS */
 			gsm->state = GSM_OVERRUN;
 			gsm->bad_size++;
 		} else
@@ -2085,7 +2091,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
 		return -ENOSPC;
 	}
 	if (debug & 4) {
-		printk("-->%d bytes out\n", len);
+		pr_debug("-->%d bytes out\n", len);
 		hex_packet(data, len);
 	}
 	gsm->tty->ops->write(gsm->tty, data, len);
@@ -2142,7 +2148,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 	char flags;
 
 	if (debug & 4) {
-		printk("Inbytes %dd\n", count);
+		pr_debug("Inbytes %dd\n", count);
 		hex_packet(cp, count);
 	}
 
@@ -2159,7 +2165,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 			gsm->error(gsm, *dp, flags);
 			break;
 		default:
-			printk(KERN_ERR "%s: unknown flag %d\n",
+			WARN_ONCE("%s: unknown flag %d\n",
 			       tty_name(tty, buf), flags);
 			break;
 		}
@@ -2354,7 +2360,7 @@ static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
 	int need_restart = 0;
 
 	/* Stuff we don't support yet - UI or I frame transport, windowing */
-	if ((c->adaption !=1 && c->adaption != 2) || c->k)
+	if ((c->adaption != 1 && c->adaption != 2) || c->k)
 		return -EOPNOTSUPP;
 	/* Check the MRU/MTU range looks sane */
 	if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
@@ -2448,7 +2454,7 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
 			c.i = 1;
 		else
 			c.i = 2;
-		printk("Ftype %d i %d\n", gsm->ftype, c.i);
+		pr_debug("Ftype %d i %d\n", gsm->ftype, c.i);
 		c.mru = gsm->mru;
 		c.mtu = gsm->mtu;
 		c.k = 0;
@@ -2742,14 +2748,15 @@ static int __init gsm_init(void)
 	/* Fill in our line protocol discipline, and register it */
 	int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
 	if (status != 0) {
-		printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
+		pr_err("n_gsm: can't register line discipline (err = %d)\n",
+								status);
 		return status;
 	}
 
 	gsm_tty_driver = alloc_tty_driver(256);
 	if (!gsm_tty_driver) {
 		tty_unregister_ldisc(N_GSM0710);
-		printk(KERN_ERR "gsm_init: tty allocation failed.\n");
+		pr_err("gsm_init: tty allocation failed.\n");
 		return -EINVAL;
 	}
 	gsm_tty_driver->owner	= THIS_MODULE;
@@ -2760,7 +2767,7 @@ static int __init gsm_init(void)
 	gsm_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
 	gsm_tty_driver->subtype	= SERIAL_TYPE_NORMAL;
 	gsm_tty_driver->flags	= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
-							| TTY_DRIVER_HARDWARE_BREAK;
+						| TTY_DRIVER_HARDWARE_BREAK;
 	gsm_tty_driver->init_termios	= tty_std_termios;
 	/* Fixme */
 	gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
@@ -2771,10 +2778,11 @@ static int __init gsm_init(void)
 	if (tty_register_driver(gsm_tty_driver)) {
 		put_tty_driver(gsm_tty_driver);
 		tty_unregister_ldisc(N_GSM0710);
-		printk(KERN_ERR "gsm_init: tty registration failed.\n");
+		pr_err("gsm_init: tty registration failed.\n");
 		return -EBUSY;
 	}
-	printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
+	pr_debug("gsm_init: loaded as %d,%d.\n",
+			gsm_tty_driver->major, gsm_tty_driver->minor_start);
 	return 0;
 }
 
@@ -2782,10 +2790,10 @@ static void __exit gsm_exit(void)
 {
 	int status = tty_unregister_ldisc(N_GSM0710);
 	if (status != 0)
-		printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
+		pr_err("n_gsm: can't unregister line discipline (err = %d)\n",
+								status);
 	tty_unregister_driver(gsm_tty_driver);
 	put_tty_driver(gsm_tty_driver);
-	printk(KERN_INFO "gsm_init: unloaded.\n");
 }
 
 module_init(gsm_init);
-- 
1.7.3.2


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

* [PATCH 05/36] serial: add Documentation about RS485 serial communications
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (4 preceding siblings ...)
  2011-01-06 22:22 ` [PATCH 04/36] n_gsm: clean up printks Greg Kroah-Hartman
@ 2011-01-06 22:22 ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 06/36] serial: cpm_uat: reducing CPM serial latency Greg Kroah-Hartman
                   ` (31 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: Claudio Scordino, Greg Kroah-Hartman

From: Claudio Scordino <claudio@evidence.eu.com>

Documentation about RS485 serial communications

Signed-off-by: Claudio Scordino <claudio@evidence.eu.com>
Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
Acked-by: Russell King <linux@arm.linux.org.uk>
Acked-by: Grant Edwards <grant.b.edwards@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 Documentation/serial/00-INDEX         |    2 +
 Documentation/serial/serial-rs485.txt |  119 +++++++++++++++++++++++++++++++++
 2 files changed, 121 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/serial/serial-rs485.txt

diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX
index 07dcdb0..e09468a 100644
--- a/Documentation/serial/00-INDEX
+++ b/Documentation/serial/00-INDEX
@@ -14,6 +14,8 @@ riscom8.txt
 	- notes on using the RISCom/8 multi-port serial driver.
 rocket.txt
 	- info on the Comtrol RocketPort multiport serial driver.
+serial-rs485.txt
+	- info about RS485 structures and support in the kernel.
 specialix.txt
 	- info on hardware/driver for specialix IO8+ multiport serial card.
 stallion.txt
diff --git a/Documentation/serial/serial-rs485.txt b/Documentation/serial/serial-rs485.txt
new file mode 100644
index 0000000..a3b1af7
--- /dev/null
+++ b/Documentation/serial/serial-rs485.txt
@@ -0,0 +1,119 @@
+                        RS485 SERIAL COMMUNICATIONS
+
+1. INTRODUCTION
+
+   EIA-485, also known as TIA/EIA-485 or RS-485, is a standard defining the
+   electrical characteristics of drivers and receivers for use in balanced
+   digital multipoint systems.
+   This standard is widely used for communications in industrial automation
+   because it can be used effectively over long distances and in electrically
+   noisy environments.
+
+2. HARDWARE-RELATED CONSIDERATIONS
+
+   Some CPUs (e.g., Atmel AT91) contain a built-in half-duplex mode capable of
+   automatically controlling line direction by toggling RTS. That can used to
+   control external half-duplex hardware like an RS485 transceiver or any
+   RS232-connected half-duplex device like some modems.
+
+   For these microcontrollers, the Linux driver should be made capable of
+   working in both modes, and proper ioctls (see later) should be made
+   available at user-level to allow switching from one mode to the other, and
+   vice versa.
+
+3. DATA STRUCTURES ALREADY AVAILABLE IN THE KERNEL
+
+   The Linux kernel provides the serial_rs485 structure (see [1]) to handle
+   RS485 communications. This data structure is used to set and configure RS485
+   parameters in the platform data and in ioctls.
+
+   Any driver for devices capable of working both as RS232 and RS485 should
+   provide at least the following ioctls:
+
+    - TIOCSRS485 (typically associated with number 0x542F). This ioctl is used
+      to enable/disable RS485 mode from user-space
+
+    - TIOCGRS485 (typically associated with number 0x542E). This ioctl is used
+      to get RS485 mode from kernel-space (i.e., driver) to user-space.
+
+   In other words, the serial driver should contain a code similar to the next
+   one:
+
+	static struct uart_ops atmel_pops = {
+		/* ... */
+		.ioctl		= handle_ioctl,
+	};
+
+	static int handle_ioctl(struct uart_port *port,
+		unsigned int cmd,
+		unsigned long arg)
+	{
+		struct serial_rs485 rs485conf;
+
+		switch (cmd) {
+		case TIOCSRS485:
+			if (copy_from_user(&rs485conf,
+				(struct serial_rs485 *) arg,
+				sizeof(rs485conf)))
+					return -EFAULT;
+
+			/* ... */
+			break;
+
+		case TIOCGRS485:
+			if (copy_to_user((struct serial_rs485 *) arg,
+				...,
+				sizeof(rs485conf)))
+					return -EFAULT;
+			/* ... */
+			break;
+
+		/* ... */
+		}
+	}
+
+
+4. USAGE FROM USER-LEVEL
+
+   From user-level, RS485 configuration can be get/set using the previous
+   ioctls. For instance, to set RS485 you can use the following code:
+
+	#include <linux/serial.h>
+
+	/* Driver-specific ioctls: */
+	#define TIOCGRS485      0x542E
+	#define TIOCSRS485      0x542F
+
+	/* Open your specific device (e.g., /dev/mydevice): */
+	int fd = open ("/dev/mydevice", O_RDWR);
+	if (fd < 0) {
+		/* Error handling. See errno. */
+	}
+
+	struct serial_rs485 rs485conf;
+
+	/* Set RS485 mode: */
+	rs485conf.flags |= SER_RS485_ENABLED;
+
+	/* Set rts delay before send, if needed: */
+	rs485conf.flags |= SER_RS485_RTS_BEFORE_SEND;
+	rs485conf.delay_rts_before_send = ...;
+
+	/* Set rts delay after send, if needed: */
+	rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
+	rs485conf.delay_rts_after_send = ...;
+
+	if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
+		/* Error handling. See errno. */
+	}
+
+	/* Use read() and write() syscalls here... */
+
+	/* Close the device when finished: */
+	if (close (fd) < 0) {
+		/* Error handling. See errno. */
+	}
+
+5. REFERENCES
+
+ [1]	include/linux/serial.h
-- 
1.7.3.2


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

* [PATCH 06/36] serial: cpm_uat: reducing CPM serial latency
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (5 preceding siblings ...)
  2011-01-06 22:22 ` [PATCH 05/36] serial: add Documentation about RS485 serial communications Greg Kroah-Hartman
@ 2011-01-06 22:22 ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 07/36] serial: cpu_uart: Remove unused uart_cpm_port fields Greg Kroah-Hartman
                   ` (30 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: Baurzhan Ismagulov, Michael Trimarchi, Bruno Morelli, Greg Kroah-Hartman

From: Baurzhan Ismagulov <ibr@radix50.net>

Setting Rx FIFO size to 1 reduces reader process wakeup latency up to
20x for baud rates <= 9600. This patch sets the Rx FIFO size to 1 for
baud rates <= 9600 or if low latency has been requested for the tty.

Signed-off-by: Michael Trimarchi <michael@gandalf.sssup.it>
Signed-off-by: Bruno Morelli <bruno@evidence.eu.com>
Signed-off-by: Baurzhan Ismagulov <ibr@radix50.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/cpm_uart/cpm_uart_core.c |   19 +++++++++++++++++++
 1 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index f2b8adc..8692ff9 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -72,6 +72,8 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
 
 /**************************************************************/
 
+#define HW_BUF_SPD_THRESHOLD    9600
+
 /*
  * Check, if transmit buffers are processed
 */
@@ -503,6 +505,11 @@ static void cpm_uart_set_termios(struct uart_port *port,
 	pr_debug("CPM uart[%d]:set_termios\n", port->line);
 
 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+	if (baud <= HW_BUF_SPD_THRESHOLD ||
+	    (pinfo->port.state && pinfo->port.state->port.tty->low_latency))
+		pinfo->rx_fifosize = 1;
+	else
+		pinfo->rx_fifosize = RX_BUF_SIZE;
 
 	/* Character length programmed into the mode register is the
 	 * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
@@ -594,6 +601,17 @@ static void cpm_uart_set_termios(struct uart_port *port,
 	 */
 	bits++;
 	if (IS_SMC(pinfo)) {
+		/*
+		 * MRBLR can be changed while an SMC/SCC is operating only
+		 * if it is done in a single bus cycle with one 16-bit move
+		 * (not two 8-bit bus cycles back-to-back). This occurs when
+		 * the cp shifts control to the next RxBD, so the change does
+		 * not take effect immediately. To guarantee the exact RxBD
+		 * on which the change occurs, change MRBLR only while the
+		 * SMC/SCC receiver is disabled.
+		 */
+		out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize);
+
 		/* Set the mode register.  We want to keep a copy of the
 		 * enables, because we want to put them back if they were
 		 * present.
@@ -604,6 +622,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
 		out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval |
 		    SMCMR_SM_UART | prev_mode);
 	} else {
+		out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
 		out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
 	}
 
-- 
1.7.3.2


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

* [PATCH 07/36] serial: cpu_uart: Remove unused uart_cpm_port fields
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (6 preceding siblings ...)
  2011-01-06 22:22 ` [PATCH 06/36] serial: cpm_uat: reducing CPM serial latency Greg Kroah-Hartman
@ 2011-01-06 22:22 ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 08/36] console: move for_each_console to linux/console.h Greg Kroah-Hartman
                   ` (29 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: Baurzhan Ismagulov, Greg Kroah-Hartman

From: Baurzhan Ismagulov <ibr@radix50.net>

AFAICT, these fields are not used anywhere.

Signed-off-by: Baurzhan Ismagulov <ibr@radix50.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/cpm_uart/cpm_uart.h |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)

diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index 7274b52..b754dcf 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -76,18 +76,12 @@ struct uart_cpm_port {
 	unsigned char		*tx_buf;
 	unsigned char		*rx_buf;
 	u32			flags;
-	void			(*set_lineif)(struct uart_cpm_port *);
 	struct clk		*clk;
 	u8			brg;
 	uint			 dp_addr;
 	void			*mem_addr;
 	dma_addr_t		 dma_addr;
 	u32			mem_size;
-	/* helpers */
-	int			 baud;
-	int			 bits;
-	/* Keep track of 'odd' SMC2 wirings */
-	int			is_portb;
 	/* wait on close if needed */
 	int			wait_closing;
 	/* value to combine with opcode to form cpm command */
-- 
1.7.3.2


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

* [PATCH 08/36] console: move for_each_console to linux/console.h
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (7 preceding siblings ...)
  2011-01-06 22:22 ` [PATCH 07/36] serial: cpu_uart: Remove unused uart_cpm_port fields Greg Kroah-Hartman
@ 2011-01-06 22:22 ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 09/36] TTY: include termios.h in tty_driver.h Greg Kroah-Hartman
                   ` (28 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jiri Slaby, Greg Kroah-Hartman

From: Jiri Slaby <jslaby@suse.cz>

Move it out of printk.c so that we can use it all over the code. There
are some potential users which will be converted to that macro in next
patches.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 include/linux/console.h |    6 ++++++
 kernel/printk.c         |    6 ------
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/linux/console.h b/include/linux/console.h
index 95cf6f0..875cfb1 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -126,6 +126,12 @@ struct console {
 	struct	 console *next;
 };
 
+/*
+ * for_each_console() allows you to iterate on each console
+ */
+#define for_each_console(con) \
+	for (con = console_drivers; con != NULL; con = con->next)
+
 extern int console_set_on_cmdline;
 
 extern int add_preferred_console(char *name, int idx, char *options);
diff --git a/kernel/printk.c b/kernel/printk.c
index b2ebaee..bf0420a 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -43,12 +43,6 @@
 #include <asm/uaccess.h>
 
 /*
- * for_each_console() allows you to iterate on each console
- */
-#define for_each_console(con) \
-	for (con = console_drivers; con != NULL; con = con->next)
-
-/*
  * Architectures can override it:
  */
 void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
-- 
1.7.3.2


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

* [PATCH 09/36] TTY: include termios.h in tty_driver.h
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (8 preceding siblings ...)
  2011-01-06 22:22 ` [PATCH 08/36] console: move for_each_console to linux/console.h Greg Kroah-Hartman
@ 2011-01-06 22:22 ` Greg Kroah-Hartman
  2011-01-06 22:22   ` Greg Kroah-Hartman
                   ` (27 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jiri Slaby, Alan Cox, Greg KH

From: Jiri Slaby <jslaby@suse.cz>

We reference termios and termiox in tty_driver.h, but we do not include
linux/termios.h where these are defined. Add the #include properly.

Otherwise when we include tty_driver.h, we get compile errors.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Greg KH <gregkh@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 include/linux/tty_driver.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index db2d227..09678ed 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -235,6 +235,7 @@
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/cdev.h>
+#include <linux/termios.h>
 
 struct tty_struct;
 struct tty_driver;
-- 
1.7.3.2


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

* [PATCH 10/36] VIDEO: xen-fb, switch to for_each_console
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
  2011-01-06 22:00 ` Alan Cox
@ 2011-01-06 22:22   ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 02/36] serial: Add support for UART on VIA VT8500 and compatibles Greg Kroah-Hartman
                     ` (35 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: Jiri Slaby, Jeremy Fitzhardinge, Chris Wright, virtualization,
	xen-devel, linux-fbdev, Greg Kroah-Hartman

From: Jiri Slaby <jslaby@suse.cz>

Use newly added for_each_console for iterating consoles.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Jeremy Fitzhardinge <jeremy@xensource.com>
Cc: Chris Wright <chrisw@sous-sol.org>
Cc: virtualization@lists.osdl.org
Cc: xen-devel@lists.xensource.com
Cc: linux-fbdev@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/video/xen-fbfront.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 428d273..4abb0b9 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -492,7 +492,7 @@ xenfb_make_preferred_console(void)
 		return;
 
 	acquire_console_sem();
-	for (c = console_drivers; c; c = c->next) {
+	for_each_console(c) {
 		if (!strcmp(c->name, "tty") && c->index == 0)
 			break;
 	}
-- 
1.7.3.2


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

* [PATCH 10/36] VIDEO: xen-fb, switch to for_each_console
@ 2011-01-06 22:22   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: Jiri Slaby, Jeremy Fitzhardinge, Chris Wright, virtualization,
	xen-devel, linux-fbdev, Greg Kroah-Hartman

From: Jiri Slaby <jslaby@suse.cz>

Use newly added for_each_console for iterating consoles.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Jeremy Fitzhardinge <jeremy@xensource.com>
Cc: Chris Wright <chrisw@sous-sol.org>
Cc: virtualization@lists.osdl.org
Cc: xen-devel@lists.xensource.com
Cc: linux-fbdev@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/video/xen-fbfront.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 428d273..4abb0b9 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -492,7 +492,7 @@ xenfb_make_preferred_console(void)
 		return;
 
 	acquire_console_sem();
-	for (c = console_drivers; c; c = c->next) {
+	for_each_console(c) {
 		if (!strcmp(c->name, "tty") && c->index = 0)
 			break;
 	}
-- 
1.7.3.2


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

* [PATCH 10/36] VIDEO: xen-fb, switch to for_each_console
@ 2011-01-06 22:22   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-fbdev, xen-devel, Jeremy Fitzhardinge, Greg Kroah-Hartman,
	Chris Wright, virtualization, Jiri Slaby

From: Jiri Slaby <jslaby@suse.cz>

Use newly added for_each_console for iterating consoles.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Jeremy Fitzhardinge <jeremy@xensource.com>
Cc: Chris Wright <chrisw@sous-sol.org>
Cc: virtualization@lists.osdl.org
Cc: xen-devel@lists.xensource.com
Cc: linux-fbdev@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/video/xen-fbfront.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 428d273..4abb0b9 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -492,7 +492,7 @@ xenfb_make_preferred_console(void)
 		return;
 
 	acquire_console_sem();
-	for (c = console_drivers; c; c = c->next) {
+	for_each_console(c) {
 		if (!strcmp(c->name, "tty") && c->index == 0)
 			break;
 	}
-- 
1.7.3.2

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

* [PATCH 11/36] console: add /proc/consoles
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (10 preceding siblings ...)
  2011-01-06 22:22   ` Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23   ` Greg Kroah-Hartman
                   ` (25 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jiri Slaby, Dr. Werner Fink, Al Viro, Greg Kroah-Hartman

From: Jiri Slaby <jslaby@suse.cz>

It allows users to see what consoles are currently known to the system
and with what flags.

It is based on Werner's patch, the part about traversing fds was
removed, the code was moved to kernel/printk.c, where consoles are
handled and it makes more sense to me.

Signed-off-by: Jiri Slaby <jslaby@suse.cz> [cleanups]
Signed-off-by: "Dr. Werner Fink" <werner@suse.de>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 Documentation/filesystems/proc.txt |   24 ++++++++
 fs/proc/Makefile                   |    1 +
 fs/proc/proc_console.c             |  114 ++++++++++++++++++++++++++++++++++++
 3 files changed, 139 insertions(+), 0 deletions(-)
 create mode 100644 fs/proc/proc_console.c

diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index e73df27..9471225 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1181,6 +1181,30 @@ Table 1-12: Files in /proc/fs/ext4/<devname>
  mb_groups       details of multiblock allocator buddy cache of free blocks
 ..............................................................................
 
+2.0 /proc/consoles
+------------------
+Shows registered system console lines.
+
+To see which character device lines are currently used for the system console
+/dev/console, you may simply look into the file /proc/consoles:
+
+  > cat /proc/consoles
+  tty0                 -WU (ECp)       4:7
+  ttyS0                -W- (Ep)        4:64
+
+The columns are:
+
+  device               name of the device
+  operations           R = can do read operations
+                       W = can do write operations
+                       U = can do unblank
+  flags                E = it is enabled
+                       C = it is prefered console
+                       B = it is primary boot console
+                       p = it is used for printk buffer
+                       b = it is not a TTY but a Braille device
+                       a = it is safe to use when cpu is offline
+  major:minor          major and minor number of the device separated by a colon
 
 ------------------------------------------------------------------------------
 Summary
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 2758e2a..288a49e 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -15,6 +15,7 @@ proc-y	+= devices.o
 proc-y	+= interrupts.o
 proc-y	+= loadavg.o
 proc-y	+= meminfo.o
+proc-y	+= proc_console.o
 proc-y	+= stat.o
 proc-y	+= uptime.o
 proc-y	+= version.o
diff --git a/fs/proc/proc_console.c b/fs/proc/proc_console.c
new file mode 100644
index 0000000..8a70760
--- /dev/null
+++ b/fs/proc/proc_console.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2010 Werner Fink, Jiri Slaby
+ *
+ * Licensed under GPLv2
+ */
+
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/tty_driver.h>
+
+/*
+ * This is handler for /proc/consoles
+ */
+static int show_console_dev(struct seq_file *m, void *v)
+{
+	static const struct {
+		short flag;
+		char name;
+	} con_flags[] = {
+		{ CON_ENABLED,		'E' },
+		{ CON_CONSDEV,		'C' },
+		{ CON_BOOT,		'B' },
+		{ CON_PRINTBUFFER,	'p' },
+		{ CON_BRL,		'b' },
+		{ CON_ANYTIME,		'a' },
+	};
+	char flags[ARRAY_SIZE(con_flags) + 1];
+	struct console *con = v;
+	unsigned int a;
+	int len;
+	dev_t dev = 0;
+
+	if (con->device) {
+		const struct tty_driver *driver;
+		int index;
+		driver = con->device(con, &index);
+		if (driver) {
+			dev = MKDEV(driver->major, driver->minor_start);
+			dev += index;
+		}
+	}
+
+	for (a = 0; a < ARRAY_SIZE(con_flags); a++)
+		flags[a] = (con->flags & con_flags[a].flag) ?
+			con_flags[a].name : ' ';
+	flags[a] = 0;
+
+	seq_printf(m, "%s%d%n", con->name, con->index, &len);
+	len = 21 - len;
+	if (len < 1)
+		len = 1;
+	seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-',
+			con->write ? 'W' : '-', con->unblank ? 'U' : '-',
+			flags);
+	if (dev)
+		seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev));
+
+	seq_printf(m, "\n");
+
+	return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	struct console *con;
+	loff_t off = 0;
+
+	acquire_console_sem();
+	for_each_console(con)
+		if (off++ == *pos)
+			break;
+
+	return con;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct console *con = v;
+	++*pos;
+	return con->next;
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+	release_console_sem();
+}
+
+static const struct seq_operations consoles_op = {
+	.start	= c_start,
+	.next	= c_next,
+	.stop	= c_stop,
+	.show	= show_console_dev
+};
+
+static int consoles_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &consoles_op);
+}
+
+static const struct file_operations proc_consoles_operations = {
+	.open		= consoles_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int register_proc_consoles(void)
+{
+	proc_create("consoles", 0, NULL, &proc_consoles_operations);
+	return 0;
+}
+module_init(register_proc_consoles);
-- 
1.7.3.2


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

* [PATCH 12/36] parisc: cleanup console handling
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
@ 2011-01-06 22:23   ` Greg Kroah-Hartman
  2011-01-06 22:22 ` [PATCH 01/36] ifx6x60: SPI protocol driver for Infineon 6x60 modem Greg Kroah-Hartman
                     ` (36 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel
  Cc: Jiri Slaby, Helge Deller, James E.J. Bottomley, linux-parisc,
	Greg Kroah-Hartman

From: Jiri Slaby <jslaby@suse.cz>

* use newly added for_each_console for iterating consoles
* add proper console locking
* do not initialize tmp twice
* no need to declare console_drivers, it's already done in console.h

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Acked-by: Kyle McMartin <kyle@mcmartin.ca>
Cc: Helge Deller <deller@gmx.de>
Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
Cc: linux-parisc@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 arch/parisc/kernel/pdc_cons.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
index 66d1f17..11bdd68 100644
--- a/arch/parisc/kernel/pdc_cons.c
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -92,8 +92,6 @@ static int pdc_console_setup(struct console *co, char *options)
 
 static struct timer_list pdc_console_timer;
 
-extern struct console * console_drivers;

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

* [PATCH 12/36] parisc: cleanup console handling
@ 2011-01-06 22:23   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel
  Cc: Jiri Slaby, Helge Deller, James E.J. Bottomley, linux-parisc,
	Greg Kroah-Hartman

From: Jiri Slaby <jslaby@suse.cz>

* use newly added for_each_console for iterating consoles
* add proper console locking
* do not initialize tmp twice
* no need to declare console_drivers, it's already done in console.h

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Acked-by: Kyle McMartin <kyle@mcmartin.ca>
Cc: Helge Deller <deller@gmx.de>
Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
Cc: linux-parisc@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 arch/parisc/kernel/pdc_cons.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
index 66d1f17..11bdd68 100644
--- a/arch/parisc/kernel/pdc_cons.c
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -92,8 +92,6 @@ static int pdc_console_setup(struct console *co, char *options)
 
 static struct timer_list pdc_console_timer;
 
-extern struct console * console_drivers;
-
 static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
 {
 
@@ -169,11 +167,13 @@ static int __init pdc_console_tty_driver_init(void)
 	 * It is unregistered if the pdc console was not selected as the
 	 * primary console. */
 
-	struct console *tmp = console_drivers;
+	struct console *tmp;
 
-	for (tmp = console_drivers; tmp; tmp = tmp->next)
+	acquire_console_sem();
+	for_each_console(tmp)
 		if (tmp == &pdc_cons)
 			break;
+	release_console_sem();
 
 	if (!tmp) {
 		printk(KERN_INFO "PDC console driver not registered anymore, not creating %s\n", pdc_cons.name);
-- 
1.7.3.2


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

* [PATCH 13/36] serial: mpc52xx: make printout for type more generic
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (12 preceding siblings ...)
  2011-01-06 22:23   ` Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 14/36] serial: ifx6x60: The IFX requires SPI Greg Kroah-Hartman
                   ` (23 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Wolfram Sang, Grant Likely, Greg Kroah-Hartman

From: Wolfram Sang <w.sang@pengutronix.de>

The printout for the type should be just "5xxx", so 512x users won't
wonder why they have a mpc52xx-type UART.

Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/mpc52xx_uart.c |    6 +++++-
 include/linux/serial_core.h   |    2 +-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index c4399e2..126ec7f 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -838,7 +838,11 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
 static const char *
 mpc52xx_uart_type(struct uart_port *port)
 {
-	return port->type == PORT_MPC52xx ? "MPC52xx PSC" : NULL;
+	/*
+	 * We keep using PORT_MPC52xx for historic reasons although it applies
+	 * for MPC512x, too, but print "MPC5xxx" to not irritate users
+	 */
+	return port->type == PORT_MPC52xx ? "MPC5xxx PSC" : NULL;
 }
 
 static void
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 41603d6..9ff9b7d 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -95,7 +95,7 @@
 /* PPC CPM type number */
 #define PORT_CPM        58
 
-/* MPC52xx type numbers */
+/* MPC52xx (and MPC512x) type numbers */
 #define PORT_MPC52xx	59
 
 /* IBM icom */
-- 
1.7.3.2


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

* [PATCH 14/36] serial: ifx6x60: The IFX requires SPI
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (13 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 13/36] serial: mpc52xx: make printout for type more generic Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 15/36] serial: ifx6x60: Fix missing include for msleep Greg Kroah-Hartman
                   ` (22 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Alan Cox, Greg Kroah-Hartman

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

Correct the KConfig as noted by Greg.

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/Kconfig |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 388e371..9f6daae 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1644,7 +1644,7 @@ config SERIAL_ALTERA_UART_CONSOLE
 
 config SERIAL_IFX6X60
         tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
-	depends on GPIOLIB && EXPERIMENTAL
+	depends on GPIOLIB && SPI && EXPERIMENTAL
 	help
 	  Support for the IFX6x60 modem devices on Intel MID platforms.
 
-- 
1.7.3.2


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

* [PATCH 15/36] serial: ifx6x60: Fix missing include for msleep
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (14 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 14/36] serial: ifx6x60: The IFX requires SPI Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 16/36] Serial: ce4100: Add PCI UART support for the ce4100 Greg Kroah-Hartman
                   ` (21 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Alan Cox, Greg Kroah-Hartman

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

Noted by Stephen Rothwell

Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/ifx6x60.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
index b9b7e06..803264a 100644
--- a/drivers/serial/ifx6x60.c
+++ b/drivers/serial/ifx6x60.c
@@ -60,6 +60,7 @@
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/spi/ifx_modem.h>
+#include <linux/delay.h>
 
 #include "ifx6x60.h"
 
-- 
1.7.3.2


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

* [PATCH 16/36] Serial: ce4100: Add PCI UART support for the ce4100
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (15 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 15/36] serial: ifx6x60: Fix missing include for msleep Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 17/36] Serial: EG20T: add PCH_UART driver Greg Kroah-Hartman
                   ` (20 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Dirk Brandewie, Greg Kroah-Hartman

From: Dirk Brandewie <dirk.brandewie@gmail.com>

This patch adds support for the PCI UART on the ce4100.

Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/8250_pci.c |   36 ++++++++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 53be4d3..e30356d 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -957,6 +957,22 @@ pci_default_setup(struct serial_private *priv,
 	return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
+static int
+ce4100_serial_setup(struct serial_private *priv,
+		  const struct pciserial_board *board,
+		  struct uart_port *port, int idx)
+{
+	int ret;
+
+	ret = setup_port(priv, port, 0, 0, board->reg_shift);
+	port->iotype = UPIO_MEM32;
+	port->type = PORT_XSCALE;
+	port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+	port->regshift = 2;
+
+	return ret;
+}
+
 static int skip_tx_en_setup(struct serial_private *priv,
 			const struct pciserial_board *board,
 			struct uart_port *port, int idx)
@@ -981,6 +997,7 @@ static int skip_tx_en_setup(struct serial_private *priv,
 #define PCI_SUBDEVICE_ID_POCTAL232	0x0308
 #define PCI_SUBDEVICE_ID_POCTAL422	0x0408
 #define PCI_VENDOR_ID_ADVANTECH		0x13fe
+#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
 #define PCI_DEVICE_ID_ADVANTECH_PCI3620	0x3620
 #define PCI_DEVICE_ID_TITAN_200I	0x8028
 #define PCI_DEVICE_ID_TITAN_400I	0x8048
@@ -1072,6 +1089,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.setup		= skip_tx_en_setup,
 	},
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_CE4100_UART,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= ce4100_serial_setup,
+	},
 	/*
 	 * ITE
 	 */
@@ -1592,6 +1616,7 @@ enum pci_board_num_t {
 	pbn_ADDIDATA_PCIe_2_3906250,
 	pbn_ADDIDATA_PCIe_4_3906250,
 	pbn_ADDIDATA_PCIe_8_3906250,
+	pbn_ce4100_1_115200,
 };
 
 /*
@@ -2281,6 +2306,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
 		.uart_offset	= 0x200,
 		.first_offset	= 0x1000,
 	},
+	[pbn_ce4100_1_115200] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 1,
+		.base_baud	= 921600,
+		.reg_shift      = 2,
+	},
 };
 
 static const struct pci_device_id softmodem_blacklist[] = {
@@ -3760,6 +3791,11 @@ static struct pci_device_id serial_pci_tbl[] = {
 	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
 		0xA000, 0x3004,
 		0, 0, pbn_b0_bt_4_115200 },
+	/* Intel CE4100 */
+	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
+		PCI_ANY_ID,  PCI_ANY_ID, 0, 0,
+		pbn_ce4100_1_115200 },
+
 
 	/*
 	 * These entries match devices with class COMMUNICATION_SERIAL,
-- 
1.7.3.2


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

* [PATCH 17/36] Serial: EG20T: add PCH_UART driver
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (16 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 16/36] Serial: ce4100: Add PCI UART support for the ce4100 Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 18/36] serial: ifx6x60: free IRQ on error Greg Kroah-Hartman
                   ` (19 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Tomoya MORINAGA, Greg Kroah-Hartman

From: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com>

UART driver of Intel EG20T(Topcliff) PCH

Intel EG20T PCH is the platform controller hub that is going to be used in
Intel's general embedded platform. All IO peripherals in
Intel EG20T PCH are actually devices sitting on AMBA bus.
Intel EG20T PCH has UART I/F. Using this I/F, it is able to access system
devices connected to UART.

Signed-off-by: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/Kconfig    |    8 +
 drivers/serial/Makefile   |    1 +
 drivers/serial/pch_uart.c | 1450 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1459 insertions(+), 0 deletions(-)
 create mode 100644 drivers/serial/pch_uart.c

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 9f6daae..fa02904 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1648,4 +1648,12 @@ config SERIAL_IFX6X60
 	help
 	  Support for the IFX6x60 modem devices on Intel MID platforms.
 
+config SERIAL_PCH_UART
+	tristate "Intel EG20T PCH UART"
+	select SERIAL_CORE
+	depends on PCI
+	help
+	  This driver is for PCH(Platform controller Hub) UART of Intel EG20T
+	  which is an IOH(Input/Output Hub) for x86 embedded processor.
+	  Enabling PCH_DMA, this PCH UART works as DMA mode.
 endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index a5e2264..f9b26df 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -91,3 +91,4 @@ obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
 obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
 obj-$(CONFIG_SERIAL_IFX6X60)  	+= ifx6x60.o
+obj-$(CONFIG_SERIAL_PCH_UART)	+= pch_uart.o
diff --git a/drivers/serial/pch_uart.c b/drivers/serial/pch_uart.c
new file mode 100644
index 0000000..b94d1fa
--- /dev/null
+++ b/drivers/serial/pch_uart.c
@@ -0,0 +1,1450 @@
+/*
+ *Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
+ *
+ *This program is free software; you can redistribute it and/or modify
+ *it under the terms of the GNU General Public License as published by
+ *the Free Software Foundation; version 2 of the License.
+ *
+ *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.
+ *
+ *You should have received a copy of the GNU General Public License
+ *along with this program; if not, write to the Free Software
+ *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/serial_reg.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/dmaengine.h>
+#include <linux/pch_dma.h>
+
+enum {
+	PCH_UART_HANDLED_RX_INT_SHIFT,
+	PCH_UART_HANDLED_TX_INT_SHIFT,
+	PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
+	PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
+	PCH_UART_HANDLED_MS_INT_SHIFT,
+};
+
+enum {
+	PCH_UART_8LINE,
+	PCH_UART_2LINE,
+};
+
+#define PCH_UART_DRIVER_DEVICE "ttyPCH"
+
+#define PCH_UART_NR_GE_256FIFO		1
+#define PCH_UART_NR_GE_64FIFO		3
+#define PCH_UART_NR_GE	(PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO)
+#define PCH_UART_NR	PCH_UART_NR_GE
+
+#define PCH_UART_HANDLED_RX_INT	(1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_TX_INT	(1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_RX_ERR_INT	(1<<((\
+					PCH_UART_HANDLED_RX_ERR_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_RX_TRG_INT	(1<<((\
+					PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_MS_INT	(1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
+
+#define PCH_UART_RBR		0x00
+#define PCH_UART_THR		0x00
+
+#define PCH_UART_IER_MASK	(PCH_UART_IER_ERBFI|PCH_UART_IER_ETBEI|\
+				PCH_UART_IER_ELSI|PCH_UART_IER_EDSSI)
+#define PCH_UART_IER_ERBFI	0x00000001
+#define PCH_UART_IER_ETBEI	0x00000002
+#define PCH_UART_IER_ELSI	0x00000004
+#define PCH_UART_IER_EDSSI	0x00000008
+
+#define PCH_UART_IIR_IP			0x00000001
+#define PCH_UART_IIR_IID		0x00000006
+#define PCH_UART_IIR_MSI		0x00000000
+#define PCH_UART_IIR_TRI		0x00000002
+#define PCH_UART_IIR_RRI		0x00000004
+#define PCH_UART_IIR_REI		0x00000006
+#define PCH_UART_IIR_TOI		0x00000008
+#define PCH_UART_IIR_FIFO256		0x00000020
+#define PCH_UART_IIR_FIFO64		PCH_UART_IIR_FIFO256
+#define PCH_UART_IIR_FE			0x000000C0
+
+#define PCH_UART_FCR_FIFOE		0x00000001
+#define PCH_UART_FCR_RFR		0x00000002
+#define PCH_UART_FCR_TFR		0x00000004
+#define PCH_UART_FCR_DMS		0x00000008
+#define PCH_UART_FCR_FIFO256		0x00000020
+#define PCH_UART_FCR_RFTL		0x000000C0
+
+#define PCH_UART_FCR_RFTL1		0x00000000
+#define PCH_UART_FCR_RFTL64		0x00000040
+#define PCH_UART_FCR_RFTL128		0x00000080
+#define PCH_UART_FCR_RFTL224		0x000000C0
+#define PCH_UART_FCR_RFTL16		PCH_UART_FCR_RFTL64
+#define PCH_UART_FCR_RFTL32		PCH_UART_FCR_RFTL128
+#define PCH_UART_FCR_RFTL56		PCH_UART_FCR_RFTL224
+#define PCH_UART_FCR_RFTL4		PCH_UART_FCR_RFTL64
+#define PCH_UART_FCR_RFTL8		PCH_UART_FCR_RFTL128
+#define PCH_UART_FCR_RFTL14		PCH_UART_FCR_RFTL224
+#define PCH_UART_FCR_RFTL_SHIFT		6
+
+#define PCH_UART_LCR_WLS	0x00000003
+#define PCH_UART_LCR_STB	0x00000004
+#define PCH_UART_LCR_PEN	0x00000008
+#define PCH_UART_LCR_EPS	0x00000010
+#define PCH_UART_LCR_SP		0x00000020
+#define PCH_UART_LCR_SB		0x00000040
+#define PCH_UART_LCR_DLAB	0x00000080
+#define PCH_UART_LCR_NP		0x00000000
+#define PCH_UART_LCR_OP		PCH_UART_LCR_PEN
+#define PCH_UART_LCR_EP		(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS)
+#define PCH_UART_LCR_1P		(PCH_UART_LCR_PEN | PCH_UART_LCR_SP)
+#define PCH_UART_LCR_0P		(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS |\
+				PCH_UART_LCR_SP)
+
+#define PCH_UART_LCR_5BIT	0x00000000
+#define PCH_UART_LCR_6BIT	0x00000001
+#define PCH_UART_LCR_7BIT	0x00000002
+#define PCH_UART_LCR_8BIT	0x00000003
+
+#define PCH_UART_MCR_DTR	0x00000001
+#define PCH_UART_MCR_RTS	0x00000002
+#define PCH_UART_MCR_OUT	0x0000000C
+#define PCH_UART_MCR_LOOP	0x00000010
+#define PCH_UART_MCR_AFE	0x00000020
+
+#define PCH_UART_LSR_DR		0x00000001
+#define PCH_UART_LSR_ERR	(1<<7)
+
+#define PCH_UART_MSR_DCTS	0x00000001
+#define PCH_UART_MSR_DDSR	0x00000002
+#define PCH_UART_MSR_TERI	0x00000004
+#define PCH_UART_MSR_DDCD	0x00000008
+#define PCH_UART_MSR_CTS	0x00000010
+#define PCH_UART_MSR_DSR	0x00000020
+#define PCH_UART_MSR_RI		0x00000040
+#define PCH_UART_MSR_DCD	0x00000080
+#define PCH_UART_MSR_DELTA	(PCH_UART_MSR_DCTS | PCH_UART_MSR_DDSR |\
+				PCH_UART_MSR_TERI | PCH_UART_MSR_DDCD)
+
+#define PCH_UART_DLL		0x00
+#define PCH_UART_DLM		0x01
+
+#define DIV_ROUND(a, b)	(((a) + ((b)/2)) / (b))
+
+#define PCH_UART_IID_RLS	(PCH_UART_IIR_REI)
+#define PCH_UART_IID_RDR	(PCH_UART_IIR_RRI)
+#define PCH_UART_IID_RDR_TO	(PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
+#define PCH_UART_IID_THRE	(PCH_UART_IIR_TRI)
+#define PCH_UART_IID_MS		(PCH_UART_IIR_MSI)
+
+#define PCH_UART_HAL_PARITY_NONE	(PCH_UART_LCR_NP)
+#define PCH_UART_HAL_PARITY_ODD		(PCH_UART_LCR_OP)
+#define PCH_UART_HAL_PARITY_EVEN	(PCH_UART_LCR_EP)
+#define PCH_UART_HAL_PARITY_FIX1	(PCH_UART_LCR_1P)
+#define PCH_UART_HAL_PARITY_FIX0	(PCH_UART_LCR_0P)
+#define PCH_UART_HAL_5BIT		(PCH_UART_LCR_5BIT)
+#define PCH_UART_HAL_6BIT		(PCH_UART_LCR_6BIT)
+#define PCH_UART_HAL_7BIT		(PCH_UART_LCR_7BIT)
+#define PCH_UART_HAL_8BIT		(PCH_UART_LCR_8BIT)
+#define PCH_UART_HAL_STB1		0
+#define PCH_UART_HAL_STB2		(PCH_UART_LCR_STB)
+
+#define PCH_UART_HAL_CLR_TX_FIFO	(PCH_UART_FCR_TFR)
+#define PCH_UART_HAL_CLR_RX_FIFO	(PCH_UART_FCR_RFR)
+#define PCH_UART_HAL_CLR_ALL_FIFO	(PCH_UART_HAL_CLR_TX_FIFO | \
+					PCH_UART_HAL_CLR_RX_FIFO)
+
+#define PCH_UART_HAL_DMA_MODE0		0
+#define PCH_UART_HAL_FIFO_DIS		0
+#define PCH_UART_HAL_FIFO16		(PCH_UART_FCR_FIFOE)
+#define PCH_UART_HAL_FIFO256		(PCH_UART_FCR_FIFOE | \
+					PCH_UART_FCR_FIFO256)
+#define PCH_UART_HAL_FIFO64		(PCH_UART_HAL_FIFO256)
+#define PCH_UART_HAL_TRIGGER1		(PCH_UART_FCR_RFTL1)
+#define PCH_UART_HAL_TRIGGER64		(PCH_UART_FCR_RFTL64)
+#define PCH_UART_HAL_TRIGGER128		(PCH_UART_FCR_RFTL128)
+#define PCH_UART_HAL_TRIGGER224		(PCH_UART_FCR_RFTL224)
+#define PCH_UART_HAL_TRIGGER16		(PCH_UART_FCR_RFTL16)
+#define PCH_UART_HAL_TRIGGER32		(PCH_UART_FCR_RFTL32)
+#define PCH_UART_HAL_TRIGGER56		(PCH_UART_FCR_RFTL56)
+#define PCH_UART_HAL_TRIGGER4		(PCH_UART_FCR_RFTL4)
+#define PCH_UART_HAL_TRIGGER8		(PCH_UART_FCR_RFTL8)
+#define PCH_UART_HAL_TRIGGER14		(PCH_UART_FCR_RFTL14)
+#define PCH_UART_HAL_TRIGGER_L		(PCH_UART_FCR_RFTL64)
+#define PCH_UART_HAL_TRIGGER_M		(PCH_UART_FCR_RFTL128)
+#define PCH_UART_HAL_TRIGGER_H		(PCH_UART_FCR_RFTL224)
+
+#define PCH_UART_HAL_RX_INT		(PCH_UART_IER_ERBFI)
+#define PCH_UART_HAL_TX_INT		(PCH_UART_IER_ETBEI)
+#define PCH_UART_HAL_RX_ERR_INT		(PCH_UART_IER_ELSI)
+#define PCH_UART_HAL_MS_INT		(PCH_UART_IER_EDSSI)
+#define PCH_UART_HAL_ALL_INT		(PCH_UART_IER_MASK)
+
+#define PCH_UART_HAL_DTR		(PCH_UART_MCR_DTR)
+#define PCH_UART_HAL_RTS		(PCH_UART_MCR_RTS)
+#define PCH_UART_HAL_OUT		(PCH_UART_MCR_OUT)
+#define PCH_UART_HAL_LOOP		(PCH_UART_MCR_LOOP)
+#define PCH_UART_HAL_AFE		(PCH_UART_MCR_AFE)
+
+struct pch_uart_buffer {
+	unsigned char *buf;
+	int size;
+};
+
+struct eg20t_port {
+	struct uart_port port;
+	int port_type;
+	void __iomem *membase;
+	resource_size_t mapbase;
+	unsigned int iobase;
+	struct pci_dev *pdev;
+	int fifo_size;
+	int base_baud;
+	int start_tx;
+	int start_rx;
+	int tx_empty;
+	int int_dis_flag;
+	int trigger;
+	int trigger_level;
+	struct pch_uart_buffer rxbuf;
+	unsigned int dmsr;
+	unsigned int fcr;
+	unsigned int use_dma;
+	unsigned int use_dma_flag;
+	struct dma_async_tx_descriptor	*desc_tx;
+	struct dma_async_tx_descriptor	*desc_rx;
+	struct pch_dma_slave		param_tx;
+	struct pch_dma_slave		param_rx;
+	struct dma_chan			*chan_tx;
+	struct dma_chan			*chan_rx;
+	struct scatterlist		sg_tx;
+	struct scatterlist		sg_rx;
+	int				tx_dma_use;
+	void				*rx_buf_virt;
+	dma_addr_t			rx_buf_dma;
+};
+
+static unsigned int default_baud = 9600;
+static const int trigger_level_256[4] = { 1, 64, 128, 224 };
+static const int trigger_level_64[4] = { 1, 16, 32, 56 };
+static const int trigger_level_16[4] = { 1, 4, 8, 14 };
+static const int trigger_level_1[4] = { 1, 1, 1, 1 };
+
+static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
+				 int base_baud)
+{
+	struct eg20t_port *priv = pci_get_drvdata(pdev);
+
+	priv->trigger_level = 1;
+	priv->fcr = 0;
+}
+
+static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
+{
+	unsigned int msr = ioread8(base + UART_MSR);
+	priv->dmsr |= msr & PCH_UART_MSR_DELTA;
+
+	return msr;
+}
+
+static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
+					  unsigned int flag)
+{
+	u8 ier = ioread8(priv->membase + UART_IER);
+	ier |= flag & PCH_UART_IER_MASK;
+	iowrite8(ier, priv->membase + UART_IER);
+}
+
+static void pch_uart_hal_disable_interrupt(struct eg20t_port *priv,
+					   unsigned int flag)
+{
+	u8 ier = ioread8(priv->membase + UART_IER);
+	ier &= ~(flag & PCH_UART_IER_MASK);
+	iowrite8(ier, priv->membase + UART_IER);
+}
+
+static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
+				 unsigned int parity, unsigned int bits,
+				 unsigned int stb)
+{
+	unsigned int dll, dlm, lcr;
+	int div;
+
+	div = DIV_ROUND(priv->base_baud / 16, baud);
+	if (div < 0 || USHRT_MAX <= div) {
+		pr_err("Invalid Baud(div=0x%x)\n", div);
+		return -EINVAL;
+	}
+
+	dll = (unsigned int)div & 0x00FFU;
+	dlm = ((unsigned int)div >> 8) & 0x00FFU;
+
+	if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) {
+		pr_err("Invalid parity(0x%x)\n", parity);
+		return -EINVAL;
+	}
+
+	if (bits & ~PCH_UART_LCR_WLS) {
+		pr_err("Invalid bits(0x%x)\n", bits);
+		return -EINVAL;
+	}
+
+	if (stb & ~PCH_UART_LCR_STB) {
+		pr_err("Invalid STB(0x%x)\n", stb);
+		return -EINVAL;
+	}
+
+	lcr = parity;
+	lcr |= bits;
+	lcr |= stb;
+
+	pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
+		 __func__, baud, div, lcr, jiffies);
+	iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
+	iowrite8(dll, priv->membase + PCH_UART_DLL);
+	iowrite8(dlm, priv->membase + PCH_UART_DLM);
+	iowrite8(lcr, priv->membase + UART_LCR);
+
+	return 0;
+}
+
+static int pch_uart_hal_fifo_reset(struct eg20t_port *priv,
+				    unsigned int flag)
+{
+	if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) {
+		pr_err("%s:Invalid flag(0x%x)\n", __func__, flag);
+		return -EINVAL;
+	}
+
+	iowrite8(PCH_UART_FCR_FIFOE | priv->fcr, priv->membase + UART_FCR);
+	iowrite8(PCH_UART_FCR_FIFOE | priv->fcr | flag,
+		 priv->membase + UART_FCR);
+	iowrite8(priv->fcr, priv->membase + UART_FCR);
+
+	return 0;
+}
+
+static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
+				 unsigned int dmamode,
+				 unsigned int fifo_size, unsigned int trigger)
+{
+	u8 fcr;
+
+	if (dmamode & ~PCH_UART_FCR_DMS) {
+		pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode);
+		return -EINVAL;
+	}
+
+	if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) {
+		pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size);
+		return -EINVAL;
+	}
+
+	if (trigger & ~PCH_UART_FCR_RFTL) {
+		pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger);
+		return -EINVAL;
+	}
+
+	switch (priv->fifo_size) {
+	case 256:
+		priv->trigger_level =
+		    trigger_level_256[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+		break;
+	case 64:
+		priv->trigger_level =
+		    trigger_level_64[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+		break;
+	case 16:
+		priv->trigger_level =
+		    trigger_level_16[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+		break;
+	default:
+		priv->trigger_level =
+		    trigger_level_1[trigger >> PCH_UART_FCR_RFTL_SHIFT];
+		break;
+	}
+	fcr =
+	    dmamode | fifo_size | trigger | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR;
+	iowrite8(PCH_UART_FCR_FIFOE, priv->membase + UART_FCR);
+	iowrite8(PCH_UART_FCR_FIFOE | PCH_UART_FCR_RFR | PCH_UART_FCR_TFR,
+		 priv->membase + UART_FCR);
+	iowrite8(fcr, priv->membase + UART_FCR);
+	priv->fcr = fcr;
+
+	return 0;
+}
+
+static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
+{
+	priv->dmsr = 0;
+	return get_msr(priv, priv->membase);
+}
+
+static int pch_uart_hal_write(struct eg20t_port *priv,
+			      const unsigned char *buf, int tx_size)
+{
+	int i;
+	unsigned int thr;
+
+	for (i = 0; i < tx_size;) {
+		thr = buf[i++];
+		iowrite8(thr, priv->membase + PCH_UART_THR);
+	}
+	return i;
+}
+
+static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
+			     int rx_size)
+{
+	int i;
+	u8 rbr, lsr;
+
+	lsr = ioread8(priv->membase + UART_LSR);
+	for (i = 0, lsr = ioread8(priv->membase + UART_LSR);
+	     i < rx_size && lsr & UART_LSR_DR;
+	     lsr = ioread8(priv->membase + UART_LSR)) {
+		rbr = ioread8(priv->membase + PCH_UART_RBR);
+		buf[i++] = rbr;
+	}
+	return i;
+}
+
+static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
+{
+	unsigned int iir;
+	int ret;
+
+	iir = ioread8(priv->membase + UART_IIR);
+	ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
+	return ret;
+}
+
+static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
+{
+	return ioread8(priv->membase + UART_LSR);
+}
+
+static void pch_uart_hal_set_break(struct eg20t_port *priv, int on)
+{
+	unsigned int lcr;
+
+	lcr = ioread8(priv->membase + UART_LCR);
+	if (on)
+		lcr |= PCH_UART_LCR_SB;
+	else
+		lcr &= ~PCH_UART_LCR_SB;
+
+	iowrite8(lcr, priv->membase + UART_LCR);
+}
+
+static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
+		   int size)
+{
+	struct uart_port *port;
+	struct tty_struct *tty;
+
+	port = &priv->port;
+	tty = tty_port_tty_get(&port->state->port);
+	if (!tty) {
+		pr_debug("%s:tty is busy now", __func__);
+		return -EBUSY;
+	}
+
+	tty_insert_flip_string(tty, buf, size);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
+
+	return 0;
+}
+
+static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
+{
+	int ret;
+	struct uart_port *port = &priv->port;
+
+	if (port->x_char) {
+		pr_debug("%s:X character send %02x (%lu)\n", __func__,
+			port->x_char, jiffies);
+		buf[0] = port->x_char;
+		port->x_char = 0;
+		ret = 1;
+	} else {
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int dma_push_rx(struct eg20t_port *priv, int size)
+{
+	struct tty_struct *tty;
+	int room;
+	struct uart_port *port = &priv->port;
+
+	port = &priv->port;
+	tty = tty_port_tty_get(&port->state->port);
+	if (!tty) {
+		pr_debug("%s:tty is busy now", __func__);
+		return 0;
+	}
+
+	room = tty_buffer_request_room(tty, size);
+
+	if (room < size)
+		dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
+			 size - room);
+	if (!room)
+		return room;
+
+	tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
+
+	port->icount.rx += room;
+	tty_kref_put(tty);
+
+	return room;
+}
+
+static void pch_free_dma(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+	priv = container_of(port, struct eg20t_port, port);
+
+	if (priv->chan_tx) {
+		dma_release_channel(priv->chan_tx);
+		priv->chan_tx = NULL;
+	}
+	if (priv->chan_rx) {
+		dma_release_channel(priv->chan_rx);
+		priv->chan_rx = NULL;
+	}
+	if (sg_dma_address(&priv->sg_rx))
+		dma_free_coherent(port->dev, port->fifosize,
+				  sg_virt(&priv->sg_rx),
+				  sg_dma_address(&priv->sg_rx));
+
+	return;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+	struct pch_dma_slave *param = slave;
+
+	if ((chan->chan_id == param->chan_id) && (param->dma_dev ==
+						  chan->device->dev)) {
+		chan->private = param;
+		return true;
+	} else {
+		return false;
+	}
+}
+
+static void pch_request_dma(struct uart_port *port)
+{
+	dma_cap_mask_t mask;
+	struct dma_chan *chan;
+	struct pci_dev *dma_dev;
+	struct pch_dma_slave *param;
+	struct eg20t_port *priv =
+				container_of(port, struct eg20t_port, port);
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev
+								information */
+	/* Set Tx DMA */
+	param = &priv->param_tx;
+	param->dma_dev = &dma_dev->dev;
+	param->chan_id = priv->port.line;
+	param->tx_reg = port->mapbase + UART_TX;
+	chan = dma_request_channel(mask, filter, param);
+	if (!chan) {
+		pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__);
+		return;
+	}
+	priv->chan_tx = chan;
+
+	/* Set Rx DMA */
+	param = &priv->param_rx;
+	param->dma_dev = &dma_dev->dev;
+	param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */
+	param->rx_reg = port->mapbase + UART_RX;
+	chan = dma_request_channel(mask, filter, param);
+	if (!chan) {
+		pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__);
+		dma_release_channel(priv->chan_tx);
+		return;
+	}
+
+	/* Get Consistent memory for DMA */
+	priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
+				    &priv->rx_buf_dma, GFP_KERNEL);
+	priv->chan_rx = chan;
+}
+
+static void pch_dma_rx_complete(void *arg)
+{
+	struct eg20t_port *priv = arg;
+	struct uart_port *port = &priv->port;
+	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+	if (!tty) {
+		pr_debug("%s:tty is busy now", __func__);
+		return;
+	}
+
+	if (dma_push_rx(priv, priv->trigger_level))
+		tty_flip_buffer_push(tty);
+
+	tty_kref_put(tty);
+}
+
+static void pch_dma_tx_complete(void *arg)
+{
+	struct eg20t_port *priv = arg;
+	struct uart_port *port = &priv->port;
+	struct circ_buf *xmit = &port->state->xmit;
+
+	xmit->tail += sg_dma_len(&priv->sg_tx);
+	xmit->tail &= UART_XMIT_SIZE - 1;
+	port->icount.tx += sg_dma_len(&priv->sg_tx);
+
+	async_tx_ack(priv->desc_tx);
+	priv->tx_dma_use = 0;
+}
+
+static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size)
+{
+	int count = 0;
+	struct uart_port *port = &priv->port;
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size)
+		goto pop_tx_end;
+
+	do {
+		int cnt_to_end =
+		    CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+		int sz = min(size - count, cnt_to_end);
+		memcpy(&buf[count], &xmit->buf[xmit->tail], sz);
+		xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
+		count += sz;
+	} while (!uart_circ_empty(xmit) && count < size);
+
+pop_tx_end:
+	pr_debug("%d characters. Remained %d characters. (%lu)\n",
+		 count, size - count, jiffies);
+
+	return count;
+}
+
+static int handle_rx_to(struct eg20t_port *priv)
+{
+	struct pch_uart_buffer *buf;
+	int rx_size;
+	int ret;
+	if (!priv->start_rx) {
+		pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
+		return 0;
+	}
+	buf = &priv->rxbuf;
+	do {
+		rx_size = pch_uart_hal_read(priv, buf->buf, buf->size);
+		ret = push_rx(priv, buf->buf, rx_size);
+		if (ret)
+			return 0;
+	} while (rx_size == buf->size);
+
+	return PCH_UART_HANDLED_RX_INT;
+}
+
+static int handle_rx(struct eg20t_port *priv)
+{
+	return handle_rx_to(priv);
+}
+
+static int dma_handle_rx(struct eg20t_port *priv)
+{
+	struct uart_port *port = &priv->port;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist *sg;
+
+	priv = container_of(port, struct eg20t_port, port);
+	sg = &priv->sg_rx;
+
+	sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */
+
+	sg_dma_len(sg) = priv->fifo_size;
+
+	sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
+		     sg_dma_len(sg), (int)priv->rx_buf_virt & ~PAGE_MASK);
+
+	sg_dma_address(sg) = priv->rx_buf_dma;
+
+	desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx,
+			sg, 1, DMA_FROM_DEVICE,
+			DMA_PREP_INTERRUPT);
+	if (!desc)
+		return 0;
+
+	priv->desc_rx = desc;
+	desc->callback = pch_dma_rx_complete;
+	desc->callback_param = priv;
+	desc->tx_submit(desc);
+	dma_async_issue_pending(priv->chan_rx);
+
+	return PCH_UART_HANDLED_RX_INT;
+}
+
+static unsigned int handle_tx(struct eg20t_port *priv)
+{
+	struct uart_port *port = &priv->port;
+	struct circ_buf *xmit = &port->state->xmit;
+	int ret;
+	int fifo_size;
+	int tx_size;
+	int size;
+	int tx_empty;
+
+	if (!priv->start_tx) {
+		pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+		pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+		priv->tx_empty = 1;
+		return 0;
+	}
+
+	fifo_size = max(priv->fifo_size, 1);
+	tx_empty = 1;
+	if (pop_tx_x(priv, xmit->buf)) {
+		pch_uart_hal_write(priv, xmit->buf, 1);
+		port->icount.tx++;
+		tx_empty = 0;
+		fifo_size--;
+	}
+	size = min(xmit->head - xmit->tail, fifo_size);
+	tx_size = pop_tx(priv, xmit->buf, size);
+	if (tx_size > 0) {
+		ret = pch_uart_hal_write(priv, xmit->buf, tx_size);
+		port->icount.tx += ret;
+		tx_empty = 0;
+	}
+
+	priv->tx_empty = tx_empty;
+
+	if (tx_empty)
+		pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+
+	return PCH_UART_HANDLED_TX_INT;
+}
+
+static unsigned int dma_handle_tx(struct eg20t_port *priv)
+{
+	struct uart_port *port = &priv->port;
+	struct circ_buf *xmit = &port->state->xmit;
+	struct scatterlist *sg = &priv->sg_tx;
+	int nent;
+	int fifo_size;
+	int tx_empty;
+	struct dma_async_tx_descriptor *desc;
+
+	if (!priv->start_tx) {
+		pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies);
+		pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+		priv->tx_empty = 1;
+		return 0;
+	}
+
+	fifo_size = max(priv->fifo_size, 1);
+	tx_empty = 1;
+	if (pop_tx_x(priv, xmit->buf)) {
+		pch_uart_hal_write(priv, xmit->buf, 1);
+		port->icount.tx++;
+		tx_empty = 0;
+		fifo_size--;
+	}
+
+	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
+
+	priv->tx_dma_use = 1;
+
+	sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */
+
+	sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf),
+		    UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK);
+
+	nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE);
+	if (!nent) {
+		pr_err("%s:dma_map_sg Failed\n", __func__);
+		return 0;
+	}
+
+	sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+	sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
+			      sg->offset;
+	sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail,
+			     UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head,
+			     xmit->tail, UART_XMIT_SIZE));
+
+	desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx,
+		sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc) {
+		pr_err("%s:device_prep_slave_sg Failed\n", __func__);
+		return 0;
+	}
+
+	dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+
+	priv->desc_tx = desc;
+	desc->callback = pch_dma_tx_complete;
+	desc->callback_param = priv;
+
+	desc->tx_submit(desc);
+
+	dma_async_issue_pending(priv->chan_tx);
+
+	return PCH_UART_HANDLED_TX_INT;
+}
+
+static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)
+{
+	u8 fcr = ioread8(priv->membase + UART_FCR);
+
+	/* Reset FIFO */
+	fcr |= UART_FCR_CLEAR_RCVR;
+	iowrite8(fcr, priv->membase + UART_FCR);
+
+	if (lsr & PCH_UART_LSR_ERR)
+		dev_err(&priv->pdev->dev, "Error data in FIFO\n");
+
+	if (lsr & UART_LSR_FE)
+		dev_err(&priv->pdev->dev, "Framing Error\n");
+
+	if (lsr & UART_LSR_PE)
+		dev_err(&priv->pdev->dev, "Parity Error\n");
+
+	if (lsr & UART_LSR_OE)
+		dev_err(&priv->pdev->dev, "Overrun Error\n");
+}
+
+static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
+{
+	struct eg20t_port *priv = dev_id;
+	unsigned int handled;
+	u8 lsr;
+	int ret = 0;
+	unsigned int iid;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->port.lock, flags);
+	handled = 0;
+	while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
+		switch (iid) {
+		case PCH_UART_IID_RLS:	/* Receiver Line Status */
+			lsr = pch_uart_hal_get_line_status(priv);
+			if (lsr & (PCH_UART_LSR_ERR | UART_LSR_FE |
+						UART_LSR_PE | UART_LSR_OE)) {
+				pch_uart_err_ir(priv, lsr);
+				ret = PCH_UART_HANDLED_RX_ERR_INT;
+			}
+			break;
+		case PCH_UART_IID_RDR:	/* Received Data Ready */
+			if (priv->use_dma)
+				ret = dma_handle_rx(priv);
+			else
+				ret = handle_rx(priv);
+			break;
+		case PCH_UART_IID_RDR_TO:	/* Received Data Ready
+						   (FIFO Timeout) */
+			ret = handle_rx_to(priv);
+			break;
+		case PCH_UART_IID_THRE:	/* Transmitter Holding Register
+						   Empty */
+			if (priv->use_dma)
+				ret = dma_handle_tx(priv);
+			else
+				ret = handle_tx(priv);
+			break;
+		case PCH_UART_IID_MS:	/* Modem Status */
+			ret = PCH_UART_HANDLED_MS_INT;
+			break;
+		default:	/* Never junp to this label */
+			pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies);
+			ret = -1;
+			break;
+		}
+		handled |= (unsigned int)ret;
+	}
+	if (handled == 0 && iid <= 1) {
+		if (priv->int_dis_flag)
+			priv->int_dis_flag = 0;
+	}
+
+	spin_unlock_irqrestore(&priv->port.lock, flags);
+	return IRQ_RETVAL(handled);
+}
+
+/* This function tests whether the transmitter fifo and shifter for the port
+						described by 'port' is empty. */
+static unsigned int pch_uart_tx_empty(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+	int ret;
+	priv = container_of(port, struct eg20t_port, port);
+	if (priv->tx_empty)
+		ret = TIOCSER_TEMT;
+	else
+		ret = 0;
+
+	return ret;
+}
+
+/* Returns the current state of modem control inputs. */
+static unsigned int pch_uart_get_mctrl(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+	u8 modem;
+	unsigned int ret = 0;
+
+	priv = container_of(port, struct eg20t_port, port);
+	modem = pch_uart_hal_get_modem(priv);
+
+	if (modem & UART_MSR_DCD)
+		ret |= TIOCM_CAR;
+
+	if (modem & UART_MSR_RI)
+		ret |= TIOCM_RNG;
+
+	if (modem & UART_MSR_DSR)
+		ret |= TIOCM_DSR;
+
+	if (modem & UART_MSR_CTS)
+		ret |= TIOCM_CTS;
+
+	return ret;
+}
+
+static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	u32 mcr = 0;
+	unsigned int dat;
+	struct eg20t_port *priv = container_of(port, struct eg20t_port, port);
+
+	if (mctrl & TIOCM_DTR)
+		mcr |= UART_MCR_DTR;
+	if (mctrl & TIOCM_RTS)
+		mcr |= UART_MCR_RTS;
+	if (mctrl & TIOCM_LOOP)
+		mcr |= UART_MCR_LOOP;
+
+	if (mctrl) {
+		dat = pch_uart_get_mctrl(port);
+		dat |= mcr;
+		iowrite8(dat, priv->membase + UART_MCR);
+	}
+}
+
+static void pch_uart_stop_tx(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+	priv = container_of(port, struct eg20t_port, port);
+	priv->start_tx = 0;
+	priv->tx_dma_use = 0;
+}
+
+static void pch_uart_start_tx(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+
+	priv = container_of(port, struct eg20t_port, port);
+
+	if (priv->use_dma)
+		if (priv->tx_dma_use)
+			return;
+
+	priv->start_tx = 1;
+	pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT);
+}
+
+static void pch_uart_stop_rx(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+	priv = container_of(port, struct eg20t_port, port);
+	priv->start_rx = 0;
+	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
+	priv->int_dis_flag = 1;
+}
+
+/* Enable the modem status interrupts. */
+static void pch_uart_enable_ms(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+	priv = container_of(port, struct eg20t_port, port);
+	pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_MS_INT);
+}
+
+/* Control the transmission of a break signal. */
+static void pch_uart_break_ctl(struct uart_port *port, int ctl)
+{
+	struct eg20t_port *priv;
+	unsigned long flags;
+
+	priv = container_of(port, struct eg20t_port, port);
+	spin_lock_irqsave(&port->lock, flags);
+	pch_uart_hal_set_break(priv, ctl);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Grab any interrupt resources and initialise any low level driver state. */
+static int pch_uart_startup(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+	int ret;
+	int fifo_size;
+	int trigger_level;
+
+	priv = container_of(port, struct eg20t_port, port);
+	priv->tx_empty = 1;
+	port->uartclk = priv->base_baud;
+	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+	ret = pch_uart_hal_set_line(priv, default_baud,
+			      PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT,
+			      PCH_UART_HAL_STB1);
+	if (ret)
+		return ret;
+
+	switch (priv->fifo_size) {
+	case 256:
+		fifo_size = PCH_UART_HAL_FIFO256;
+		break;
+	case 64:
+		fifo_size = PCH_UART_HAL_FIFO64;
+		break;
+	case 16:
+		fifo_size = PCH_UART_HAL_FIFO16;
+	case 1:
+	default:
+		fifo_size = PCH_UART_HAL_FIFO_DIS;
+		break;
+	}
+
+	switch (priv->trigger) {
+	case PCH_UART_HAL_TRIGGER1:
+		trigger_level = 1;
+		break;
+	case PCH_UART_HAL_TRIGGER_L:
+		trigger_level = priv->fifo_size / 4;
+		break;
+	case PCH_UART_HAL_TRIGGER_M:
+		trigger_level = priv->fifo_size / 2;
+		break;
+	case PCH_UART_HAL_TRIGGER_H:
+	default:
+		trigger_level = priv->fifo_size - (priv->fifo_size / 8);
+		break;
+	}
+
+	priv->trigger_level = trigger_level;
+	ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
+				    fifo_size, priv->trigger);
+	if (ret < 0)
+		return ret;
+
+	ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
+			KBUILD_MODNAME, priv);
+	if (ret < 0)
+		return ret;
+
+	if (priv->use_dma)
+		pch_request_dma(port);
+
+	priv->start_rx = 1;
+	pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
+	uart_update_timeout(port, CS8, default_baud);
+
+	return 0;
+}
+
+static void pch_uart_shutdown(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+	int ret;
+
+	priv = container_of(port, struct eg20t_port, port);
+	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+	pch_uart_hal_fifo_reset(priv, PCH_UART_HAL_CLR_ALL_FIFO);
+	ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0,
+			      PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1);
+	if (ret)
+		pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret);
+
+	if (priv->use_dma_flag)
+		pch_free_dma(port);
+
+	free_irq(priv->port.irq, priv);
+}
+
+/* Change the port parameters, including word length, parity, stop
+ *bits.  Update read_status_mask and ignore_status_mask to indicate
+ *the types of events we are interested in receiving.  */
+static void pch_uart_set_termios(struct uart_port *port,
+				 struct ktermios *termios, struct ktermios *old)
+{
+	int baud;
+	int rtn;
+	unsigned int parity, bits, stb;
+	struct eg20t_port *priv;
+	unsigned long flags;
+
+	priv = container_of(port, struct eg20t_port, port);
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		bits = PCH_UART_HAL_5BIT;
+		break;
+	case CS6:
+		bits = PCH_UART_HAL_6BIT;
+		break;
+	case CS7:
+		bits = PCH_UART_HAL_7BIT;
+		break;
+	default:		/* CS8 */
+		bits = PCH_UART_HAL_8BIT;
+		break;
+	}
+	if (termios->c_cflag & CSTOPB)
+		stb = PCH_UART_HAL_STB2;
+	else
+		stb = PCH_UART_HAL_STB1;
+
+	if (termios->c_cflag & PARENB) {
+		if (!(termios->c_cflag & PARODD))
+			parity = PCH_UART_HAL_PARITY_ODD;
+		else
+			parity = PCH_UART_HAL_PARITY_EVEN;
+
+	} else {
+		parity = PCH_UART_HAL_PARITY_NONE;
+	}
+	termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	uart_update_timeout(port, termios->c_cflag, baud);
+	rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
+	if (rtn)
+		goto out;
+
+	/* Don't rewrite B0 */
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+
+out:
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *pch_uart_type(struct uart_port *port)
+{
+	return KBUILD_MODNAME;
+}
+
+static void pch_uart_release_port(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+
+	priv = container_of(port, struct eg20t_port, port);
+	pci_iounmap(priv->pdev, priv->membase);
+	pci_release_regions(priv->pdev);
+}
+
+static int pch_uart_request_port(struct uart_port *port)
+{
+	struct eg20t_port *priv;
+	int ret;
+	void __iomem *membase;
+
+	priv = container_of(port, struct eg20t_port, port);
+	ret = pci_request_regions(priv->pdev, KBUILD_MODNAME);
+	if (ret < 0)
+		return -EBUSY;
+
+	membase = pci_iomap(priv->pdev, 1, 0);
+	if (!membase) {
+		pci_release_regions(priv->pdev);
+		return -EBUSY;
+	}
+	priv->membase = port->membase = membase;
+
+	return 0;
+}
+
+static void pch_uart_config_port(struct uart_port *port, int type)
+{
+	struct eg20t_port *priv;
+
+	priv = container_of(port, struct eg20t_port, port);
+	if (type & UART_CONFIG_TYPE) {
+		port->type = priv->port_type;
+		pch_uart_request_port(port);
+	}
+}
+
+static int pch_uart_verify_port(struct uart_port *port,
+				struct serial_struct *serinfo)
+{
+	struct eg20t_port *priv;
+
+	priv = container_of(port, struct eg20t_port, port);
+	if (serinfo->flags & UPF_LOW_LATENCY) {
+		pr_info("PCH UART : Use PIO Mode (without DMA)\n");
+		priv->use_dma = 0;
+		serinfo->flags &= ~UPF_LOW_LATENCY;
+	} else {
+#ifndef CONFIG_PCH_DMA
+		pr_err("%s : PCH DMA is not Loaded.\n", __func__);
+		return -EOPNOTSUPP;
+#endif
+		priv->use_dma = 1;
+		priv->use_dma_flag = 1;
+		pr_info("PCH UART : Use DMA Mode\n");
+	}
+
+	return 0;
+}
+
+static struct uart_ops pch_uart_ops = {
+	.tx_empty = pch_uart_tx_empty,
+	.set_mctrl = pch_uart_set_mctrl,
+	.get_mctrl = pch_uart_get_mctrl,
+	.stop_tx = pch_uart_stop_tx,
+	.start_tx = pch_uart_start_tx,
+	.stop_rx = pch_uart_stop_rx,
+	.enable_ms = pch_uart_enable_ms,
+	.break_ctl = pch_uart_break_ctl,
+	.startup = pch_uart_startup,
+	.shutdown = pch_uart_shutdown,
+	.set_termios = pch_uart_set_termios,
+/*	.pm		= pch_uart_pm,		Not supported yet */
+/*	.set_wake	= pch_uart_set_wake,	Not supported yet */
+	.type = pch_uart_type,
+	.release_port = pch_uart_release_port,
+	.request_port = pch_uart_request_port,
+	.config_port = pch_uart_config_port,
+	.verify_port = pch_uart_verify_port
+};
+
+static struct uart_driver pch_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = KBUILD_MODNAME,
+	.dev_name = PCH_UART_DRIVER_DEVICE,
+	.major = 0,
+	.minor = 0,
+	.nr = PCH_UART_NR,
+};
+
+static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
+						int port_type)
+{
+	struct eg20t_port *priv;
+	int ret;
+	unsigned int iobase;
+	unsigned int mapbase;
+	unsigned int rxbuf;
+	int fifosize, base_baud;
+	static int num;
+
+	priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL);
+	if (priv == NULL)
+		goto init_port_alloc_err;
+
+	rxbuf = __get_free_page(GFP_KERNEL);
+	if (!rxbuf)
+		goto init_port_free_txbuf;
+
+	switch (port_type) {
+	case PORT_UNKNOWN:
+		fifosize = 256; /* UART0 */
+		base_baud = 1843200; /* 1.8432MHz */
+		break;
+	case PORT_8250:
+		fifosize = 64; /* UART1~3 */
+		base_baud = 1843200; /* 1.8432MHz */
+		break;
+	default:
+		dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type);
+		goto init_port_hal_free;
+	}
+
+	iobase = pci_resource_start(pdev, 0);
+	mapbase = pci_resource_start(pdev, 1);
+	priv->mapbase = mapbase;
+	priv->iobase = iobase;
+	priv->pdev = pdev;
+	priv->tx_empty = 1;
+	priv->rxbuf.buf = (unsigned char *)rxbuf;
+	priv->rxbuf.size = PAGE_SIZE;
+
+	priv->fifo_size = fifosize;
+	priv->base_baud = base_baud;
+	priv->port_type = PORT_MAX_8250 + port_type + 1;
+	priv->port.dev = &pdev->dev;
+	priv->port.iobase = iobase;
+	priv->port.membase = NULL;
+	priv->port.mapbase = mapbase;
+	priv->port.irq = pdev->irq;
+	priv->port.iotype = UPIO_PORT;
+	priv->port.ops = &pch_uart_ops;
+	priv->port.flags = UPF_BOOT_AUTOCONF;
+	priv->port.fifosize = fifosize;
+	priv->port.line = num++;
+	priv->trigger = PCH_UART_HAL_TRIGGER_M;
+
+	pci_set_drvdata(pdev, priv);
+	pch_uart_hal_request(pdev, fifosize, base_baud);
+	ret = uart_add_one_port(&pch_uart_driver, &priv->port);
+	if (ret < 0)
+		goto init_port_hal_free;
+
+	return priv;
+
+init_port_hal_free:
+	free_page(rxbuf);
+init_port_free_txbuf:
+	kfree(priv);
+init_port_alloc_err:
+
+	return NULL;
+}
+
+static void pch_uart_exit_port(struct eg20t_port *priv)
+{
+	uart_remove_one_port(&pch_uart_driver, &priv->port);
+	pci_set_drvdata(priv->pdev, NULL);
+	free_page((unsigned int)priv->rxbuf.buf);
+}
+
+static void pch_uart_pci_remove(struct pci_dev *pdev)
+{
+	struct eg20t_port *priv;
+
+	priv = (struct eg20t_port *)pci_get_drvdata(pdev);
+	pch_uart_exit_port(priv);
+	pci_disable_device(pdev);
+	kfree(priv);
+	return;
+}
+#ifdef CONFIG_PM
+static int pch_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct eg20t_port *priv = pci_get_drvdata(pdev);
+
+	uart_suspend_port(&pch_uart_driver, &priv->port);
+
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	return 0;
+}
+
+static int pch_uart_pci_resume(struct pci_dev *pdev)
+{
+	struct eg20t_port *priv = pci_get_drvdata(pdev);
+	int ret;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		dev_err(&pdev->dev,
+		"%s-pci_enable_device failed(ret=%d) ", __func__, ret);
+		return ret;
+	}
+
+	uart_resume_port(&pch_uart_driver, &priv->port);
+
+	return 0;
+}
+#else
+#define pch_uart_pci_suspend NULL
+#define pch_uart_pci_resume NULL
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
+	 .driver_data = PCH_UART_8LINE},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),
+	 .driver_data = PCH_UART_2LINE},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813),
+	 .driver_data = PCH_UART_2LINE},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814),
+	 .driver_data = PCH_UART_2LINE},
+	{0,},
+};
+
+static int __devinit pch_uart_pci_probe(struct pci_dev *pdev,
+					const struct pci_device_id *id)
+{
+	int ret;
+	struct eg20t_port *priv;
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		goto probe_error;
+
+	priv = pch_uart_init_port(pdev, id->driver_data);
+	if (!priv) {
+		ret = -EBUSY;
+		goto probe_disable_device;
+	}
+	pci_set_drvdata(pdev, priv);
+
+	return ret;
+
+probe_disable_device:
+	pci_disable_device(pdev);
+probe_error:
+	return ret;
+}
+
+static struct pci_driver pch_uart_pci_driver = {
+	.name = "pch_uart",
+	.id_table = pch_uart_pci_id,
+	.probe = pch_uart_pci_probe,
+	.remove = __devexit_p(pch_uart_pci_remove),
+	.suspend = pch_uart_pci_suspend,
+	.resume = pch_uart_pci_resume,
+};
+
+static int __init pch_uart_module_init(void)
+{
+	int ret;
+
+	/* register as UART driver */
+	ret = uart_register_driver(&pch_uart_driver);
+	if (ret < 0)
+		return ret;
+
+	/* register as PCI driver */
+	ret = pci_register_driver(&pch_uart_pci_driver);
+	if (ret < 0)
+		uart_unregister_driver(&pch_uart_driver);
+
+	return ret;
+}
+module_init(pch_uart_module_init);
+
+static void __exit pch_uart_module_exit(void)
+{
+	pci_unregister_driver(&pch_uart_pci_driver);
+	uart_unregister_driver(&pch_uart_driver);
+}
+module_exit(pch_uart_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
+module_param(default_baud, uint, S_IRUGO);
-- 
1.7.3.2


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

* [PATCH 18/36] serial: ifx6x60: free IRQ on error
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (17 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 17/36] Serial: EG20T: add PCH_UART driver Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 19/36] serial: ifx6x60: fix memory leak Greg Kroah-Hartman
                   ` (18 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Vasiliy Kulikov, Greg Kroah-Hartman

From: Vasiliy Kulikov <segoon@openwall.com>

If second request_irq() failed then the first IRQ must be freed in
error handling code.

Signed-off-by: Vasiliy Kulikov <segoon@openwall.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/ifx6x60.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
index 803264a..3f8d5ee 100644
--- a/drivers/serial/ifx6x60.c
+++ b/drivers/serial/ifx6x60.c
@@ -1133,7 +1133,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
 	if (ret) {
 		dev_err(&spi->dev, "Unable to get irq %x",
 			gpio_to_irq(ifx_dev->gpio.srdy));
-		goto error_ret6;
+		goto error_ret7;
 	}
 
 	/* set pm runtime power state and register with power system */
@@ -1153,6 +1153,8 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
 		mrdy_set_low(ifx_dev);
 	return 0;
 
+error_ret7:
+	free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
 error_ret6:
 	gpio_free(ifx_dev->gpio.srdy);
 error_ret5:
-- 
1.7.3.2


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

* [PATCH 19/36] serial: ifx6x60: fix memory leak
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (18 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 18/36] serial: ifx6x60: free IRQ on error Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 20/36] RS485 documentation: add 16C950 UART description Greg Kroah-Hartman
                   ` (17 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Vasiliy Kulikov, Greg Kroah-Hartman

From: Vasiliy Kulikov <segoon@openwall.com>

If tty_register_driver() failed then tty_driver is still alive.
Free it with put_tty_driver().

Signed-off-by: Vasiliy Kulikov <segoon@openwall.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/ifx6x60.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
index 3f8d5ee..ab93763 100644
--- a/drivers/serial/ifx6x60.c
+++ b/drivers/serial/ifx6x60.c
@@ -1384,6 +1384,7 @@ static int __init ifx_spi_init(void)
 	if (result) {
 		pr_err("%s: tty_register_driver failed(%d)",
 			DRVNAME, result);
+		put_tty_driver(tty_drv);
 		return result;
 	}
 
-- 
1.7.3.2


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

* [PATCH 20/36] RS485 documentation: add 16C950 UART description
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (19 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 19/36] serial: ifx6x60: fix memory leak Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 21/36] drivers: char: hvc: add arm JTAG DCC console support Greg Kroah-Hartman
                   ` (16 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Yegor Yefremov, Yegor Yefremov, Greg Kroah-Hartman

From: Yegor Yefremov <yegor_sub1@visionsystems.de>

Add a notion about 16C950 UART, that is using DTR signal for RS485 mode.

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 Documentation/serial/serial-rs485.txt |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/Documentation/serial/serial-rs485.txt b/Documentation/serial/serial-rs485.txt
index a3b1af7..a493238 100644
--- a/Documentation/serial/serial-rs485.txt
+++ b/Documentation/serial/serial-rs485.txt
@@ -11,10 +11,11 @@
 
 2. HARDWARE-RELATED CONSIDERATIONS
 
-   Some CPUs (e.g., Atmel AT91) contain a built-in half-duplex mode capable of
-   automatically controlling line direction by toggling RTS. That can used to
-   control external half-duplex hardware like an RS485 transceiver or any
-   RS232-connected half-duplex device like some modems.
+   Some CPUs/UARTs (e.g., Atmel AT91 or 16C950 UART) contain a built-in
+   half-duplex mode capable of automatically controlling line direction by
+   toggling RTS or DTR signals. That can be used to control external
+   half-duplex hardware like an RS485 transceiver or any RS232-connected
+   half-duplex devices like some modems.
 
    For these microcontrollers, the Linux driver should be made capable of
    working in both modes, and proper ioctls (see later) should be made
-- 
1.7.3.2


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

* [PATCH 21/36] drivers: char: hvc: add arm JTAG DCC console support
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (20 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 20/36] RS485 documentation: add 16C950 UART description Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 22/36] serial: fix pch_uart kconfig & build Greg Kroah-Hartman
                   ` (15 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel
  Cc: Daniel Walker, Tony Lindgren, Mike Frysinger, Greg Kroah-Hartman

From: Daniel Walker <dwalker@codeaurora.org>

This driver adds a basic console that uses the arm JTAG
DCC to transfer data back and forth. It has support for
ARMv6 and ARMv7.

This console is created under the HVC driver, and should be named
/dev/hvcX (or /dev/hvc0 for example).

Cc: Tony Lindgren <tony@atomide.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Cc: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/char/Kconfig   |    9 +++
 drivers/char/Makefile  |    1 +
 drivers/char/hvc_dcc.c |  133 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+), 0 deletions(-)
 create mode 100644 drivers/char/hvc_dcc.c

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 43d3395..d4a7776 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -682,6 +682,15 @@ config HVC_UDBG
        select HVC_DRIVER
        default n
 
+config HVC_DCC
+       bool "ARM JTAG DCC console"
+       depends on ARM
+       select HVC_DRIVER
+       help
+         This console uses the JTAG DCC on ARM to create a console under the HVC
+	 driver. This console is used through a JTAG only on ARM. If you don't have
+	 a JTAG then you probably don't want this option.
+
 config VIRTIO_CONSOLE
 	tristate "Virtio console"
 	depends on VIRTIO
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index ba53ec9..fa0b824 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_HVC_CONSOLE)	+= hvc_vio.o hvsi.o
 obj-$(CONFIG_HVC_ISERIES)	+= hvc_iseries.o
 obj-$(CONFIG_HVC_RTAS)		+= hvc_rtas.o
 obj-$(CONFIG_HVC_TILE)		+= hvc_tile.o
+obj-$(CONFIG_HVC_DCC)		+= hvc_dcc.o
 obj-$(CONFIG_HVC_BEAT)		+= hvc_beat.o
 obj-$(CONFIG_HVC_DRIVER)	+= hvc_console.o
 obj-$(CONFIG_HVC_IRQ)		+= hvc_irq.o
diff --git a/drivers/char/hvc_dcc.c b/drivers/char/hvc_dcc.c
new file mode 100644
index 0000000..6470f63
--- /dev/null
+++ b/drivers/char/hvc_dcc.c
@@ -0,0 +1,133 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+
+#include "hvc_console.h"
+
+/* DCC Status Bits */
+#define DCC_STATUS_RX		(1 << 30)
+#define DCC_STATUS_TX		(1 << 29)
+
+static inline u32 __dcc_getstatus(void)
+{
+	u32 __ret;
+
+	asm("mrc p14, 0, %0, c0, c1, 0	@ read comms ctrl reg"
+		: "=r" (__ret) : : "cc");
+
+	return __ret;
+}
+
+
+#if defined(CONFIG_CPU_V7)
+static inline char __dcc_getchar(void)
+{
+	char __c;
+
+	asm("get_wait:	mrc p14, 0, pc, c0, c1, 0                          \n\
+			bne get_wait                                       \n\
+			mrc p14, 0, %0, c0, c5, 0	@ read comms data reg"
+		: "=r" (__c) : : "cc");
+
+	return __c;
+}
+#else
+static inline char __dcc_getchar(void)
+{
+	char __c;
+
+	asm("mrc p14, 0, %0, c0, c5, 0	@ read comms data reg"
+		: "=r" (__c));
+
+	return __c;
+}
+#endif
+
+#if defined(CONFIG_CPU_V7)
+static inline void __dcc_putchar(char c)
+{
+	asm("put_wait:	mrc p14, 0, pc, c0, c1, 0                 \n\
+			bcs put_wait                              \n\
+			mcr p14, 0, %0, c0, c5, 0                   "
+	: : "r" (c) : "cc");
+}
+#else
+static inline void __dcc_putchar(char c)
+{
+	asm("mcr p14, 0, %0, c0, c5, 0	@ write a char"
+		: /* no output register */
+		: "r" (c));
+}
+#endif
+
+static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		while (__dcc_getstatus() & DCC_STATUS_TX)
+			cpu_relax();
+
+		__dcc_putchar((char)(buf[i] & 0xFF));
+	}
+
+	return count;
+}
+
+static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
+{
+	int i;
+
+	for (i = 0; i < count; ++i) {
+		int c = -1;
+
+		if (__dcc_getstatus() & DCC_STATUS_RX)
+			c = __dcc_getchar();
+		if (c < 0)
+			break;
+		buf[i] = c;
+	}
+
+	return i;
+}
+
+static const struct hv_ops hvc_dcc_get_put_ops = {
+	.get_chars = hvc_dcc_get_chars,
+	.put_chars = hvc_dcc_put_chars,
+};
+
+static int __init hvc_dcc_console_init(void)
+{
+	hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
+	return 0;
+}
+console_initcall(hvc_dcc_console_init);
+
+static int __init hvc_dcc_init(void)
+{
+	hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
+	return 0;
+}
+device_initcall(hvc_dcc_init);
-- 
1.7.3.2


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

* [PATCH 22/36] serial: fix pch_uart kconfig & build
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (21 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 21/36] drivers: char: hvc: add arm JTAG DCC console support Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-07  0:21   ` Tomoya MORINAGA
  2011-01-06 22:23 ` [PATCH 23/36] serial: omap-serial: Add support for kernel debugger Greg Kroah-Hartman
                   ` (14 subsequent siblings)
  37 siblings, 1 reply; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Randy Dunlap, Tomoya MORINAGA, Greg Kroah-Hartman

From: Randy Dunlap <randy.dunlap@oracle.com>

The dma_request_channel/dma_release_channel interfaces are not
built when DMADEVICES is not enabled, so make the driver depend on
DMADEVICES.  Also, the help text says that the driver enables & uses
PCH_DMA, which is not enabled, so select that.

ERROR: "__dma_request_channel" [drivers/serial/pch_uart.ko] undefined!
ERROR: "dma_release_channel" [drivers/serial/pch_uart.ko] undefined!

Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
Cc: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com>
Reported-by: Zimny Lech <napohybelskurwysynom2010@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/Kconfig |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index fa02904..ec3c214 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1650,8 +1650,9 @@ config SERIAL_IFX6X60
 
 config SERIAL_PCH_UART
 	tristate "Intel EG20T PCH UART"
+	depends on PCI && DMADEVICES
 	select SERIAL_CORE
-	depends on PCI
+	select PCH_DMA
 	help
 	  This driver is for PCH(Platform controller Hub) UART of Intel EG20T
 	  which is an IOH(Input/Output Hub) for x86 embedded processor.
-- 
1.7.3.2


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

* [PATCH 23/36] serial: omap-serial: Add support for kernel debugger
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (22 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 22/36] serial: fix pch_uart kconfig & build Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 24/36] 8250: use container_of() instead of casting Greg Kroah-Hartman
                   ` (13 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Cosmin Cojocar, Greg Kroah-Hartman

From: Cosmin Cojocar <cosmin.cojocar@gmail.com>

The kgdb invokes the poll_put_char and poll_get_char when communicating
with the host. This patch also changes the initialization order because the
kgdb will check at the very beginning, if there is a valid serial
driver.

Signed-off-by: Cosmin Cojocar <cosmin.cojocar@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/Makefile      |    2 +-
 drivers/serial/omap-serial.c |   38 ++++++++++++++++++++++++++++++++------
 2 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index f9b26df..8ea92e9 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
+obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
 obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
 obj-$(CONFIG_SERIAL_TIMBERDALE)	+= timbuart.o
@@ -89,6 +90,5 @@ obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
 obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
-obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
 obj-$(CONFIG_SERIAL_IFX6X60)  	+= ifx6x60.o
 obj-$(CONFIG_SERIAL_PCH_UART)	+= pch_uart.o
diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
index 14365f7..54239f5 100644
--- a/drivers/serial/omap-serial.c
+++ b/drivers/serial/omap-serial.c
@@ -866,12 +866,6 @@ serial_omap_type(struct uart_port *port)
 	return up->name;
 }
 
-#ifdef CONFIG_SERIAL_OMAP_CONSOLE
-
-static struct uart_omap_port *serial_omap_console_ports[4];
-
-static struct uart_driver serial_omap_reg;
-
 #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
 
 static inline void wait_for_xmitr(struct uart_omap_port *up)
@@ -905,6 +899,34 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)
 	}
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+
+static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	wait_for_xmitr(up);
+	serial_out(up, UART_TX, ch);
+}
+
+static int serial_omap_poll_get_char(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	unsigned int status = serial_in(up, UART_LSR);
+
+	if (!(status & UART_LSR_DR))
+		return NO_POLL_CHAR;
+
+	return serial_in(up, UART_RX);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+
+static struct uart_omap_port *serial_omap_console_ports[4];
+
+static struct uart_driver serial_omap_reg;
+
 static void serial_omap_console_putchar(struct uart_port *port, int ch)
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
@@ -1022,6 +1044,10 @@ static struct uart_ops serial_omap_pops = {
 	.request_port	= serial_omap_request_port,
 	.config_port	= serial_omap_config_port,
 	.verify_port	= serial_omap_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_put_char  = serial_omap_poll_put_char,
+	.poll_get_char  = serial_omap_poll_get_char,
+#endif
 };
 
 static struct uart_driver serial_omap_reg = {
-- 
1.7.3.2


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

* [PATCH 24/36] 8250: use container_of() instead of casting
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (23 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 23/36] serial: omap-serial: Add support for kernel debugger Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 25/36] 8250: add a UPIO_DWAPB32 for 32 bit accesses Greg Kroah-Hartman
                   ` (12 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jamie Iles, Greg Kroah-Hartman

From: Jamie Iles <jamie@jamieiles.com>

The 8250 driver structure uart_8250_port took advantage of the fact
that the struct uart_port was the first member of its structure and
used an explicit cast to convert to the derived class. Replace the
explicit casts with container_of() for safety and clarity.

Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/8250.c |   60 ++++++++++++++++++++++++++++++++----------------
 1 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 4d8e14b..0b4ce47 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -461,7 +461,8 @@ static void dwapb_serial_out(struct uart_port *p, int offset, int value)
 	/* Save the LCR value so it can be re-written when a
 	 * Busy Detect interrupt occurs. */
 	if (save_offset == UART_LCR) {
-		struct uart_8250_port *up = (struct uart_8250_port *)p;
+		struct uart_8250_port *up =
+			container_of(p, struct uart_8250_port, port);
 		up->lcr = value;
 	}
 	writeb(value, p->membase + offset);
@@ -485,7 +486,8 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
 
 static void set_io_from_upio(struct uart_port *p)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)p;
+	struct uart_8250_port *up =
+		container_of(p, struct uart_8250_port, port);
 	switch (p->iotype) {
 	case UPIO_HUB6:
 		p->serial_in = hub6_serial_in;
@@ -1319,7 +1321,8 @@ static inline void __stop_tx(struct uart_8250_port *p)
 
 static void serial8250_stop_tx(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 
 	__stop_tx(up);
 
@@ -1336,7 +1339,8 @@ static void transmit_chars(struct uart_8250_port *up);
 
 static void serial8250_start_tx(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 
 	if (!(up->ier & UART_IER_THRI)) {
 		up->ier |= UART_IER_THRI;
@@ -1364,7 +1368,8 @@ static void serial8250_start_tx(struct uart_port *port)
 
 static void serial8250_stop_rx(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 
 	up->ier &= ~UART_IER_RLSI;
 	up->port.read_status_mask &= ~UART_LSR_DR;
@@ -1373,7 +1378,8 @@ static void serial8250_stop_rx(struct uart_port *port)
 
 static void serial8250_enable_ms(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 
 	/* no MSR capabilities */
 	if (up->bugs & UART_BUG_NOMSR)
@@ -1781,7 +1787,8 @@ static void serial8250_backup_timeout(unsigned long data)
 
 static unsigned int serial8250_tx_empty(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	unsigned long flags;
 	unsigned int lsr;
 
@@ -1795,7 +1802,8 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
 
 static unsigned int serial8250_get_mctrl(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	unsigned int status;
 	unsigned int ret;
 
@@ -1815,7 +1823,8 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
 
 static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	unsigned char mcr = 0;
 
 	if (mctrl & TIOCM_RTS)
@@ -1836,7 +1845,8 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 static void serial8250_break_ctl(struct uart_port *port, int break_state)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	unsigned long flags;
 
 	spin_lock_irqsave(&up->port.lock, flags);
@@ -1890,7 +1900,8 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
 
 static int serial8250_get_poll_char(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	unsigned char lsr = serial_inp(up, UART_LSR);
 
 	if (!(lsr & UART_LSR_DR))
@@ -1904,7 +1915,8 @@ static void serial8250_put_poll_char(struct uart_port *port,
 			 unsigned char c)
 {
 	unsigned int ier;
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 
 	/*
 	 *	First save the IER then disable the interrupts
@@ -1938,7 +1950,8 @@ static void serial8250_put_poll_char(struct uart_port *port,
 
 static int serial8250_startup(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	unsigned long flags;
 	unsigned char lsr, iir;
 	int retval;
@@ -2166,7 +2179,8 @@ dont_test_tx_en:
 
 static void serial8250_shutdown(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	unsigned long flags;
 
 	/*
@@ -2235,7 +2249,8 @@ void
 serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
 		          struct ktermios *old)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	unsigned char cval, fcr = 0;
 	unsigned long flags;
 	unsigned int baud, quot;
@@ -2435,7 +2450,8 @@ serial8250_set_ldisc(struct uart_port *port, int new)
 void serial8250_do_pm(struct uart_port *port, unsigned int state,
 		      unsigned int oldstate)
 {
-	struct uart_8250_port *p = (struct uart_8250_port *)port;
+	struct uart_8250_port *p =
+		container_of(port, struct uart_8250_port, port);
 
 	serial8250_set_sleep(p, state != 0);
 }
@@ -2566,7 +2582,8 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up)
 
 static void serial8250_release_port(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 
 	serial8250_release_std_resource(up);
 	if (up->port.type == PORT_RSA)
@@ -2575,7 +2592,8 @@ static void serial8250_release_port(struct uart_port *port)
 
 static int serial8250_request_port(struct uart_port *port)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	int ret = 0;
 
 	ret = serial8250_request_std_resource(up);
@@ -2590,7 +2608,8 @@ static int serial8250_request_port(struct uart_port *port)
 
 static void serial8250_config_port(struct uart_port *port, int flags)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 	int probeflags = PROBE_ANY;
 	int ret;
 
@@ -2771,7 +2790,8 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 
 static void serial8250_console_putchar(struct uart_port *port, int ch)
 {
-	struct uart_8250_port *up = (struct uart_8250_port *)port;
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
 
 	wait_for_xmitr(up, UART_LSR_THRE);
 	serial_out(up, UART_TX, ch);
-- 
1.7.3.2


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

* [PATCH 25/36] 8250: add a UPIO_DWAPB32 for 32 bit accesses
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (24 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 24/36] 8250: use container_of() instead of casting Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 26/36] rocket: fix compiler warning on rocket_pci_ids Greg Kroah-Hartman
                   ` (11 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Jamie Iles, Greg Kroah-Hartman

From: Jamie Iles <jamie@jamieiles.com>

Some platforms contain a Synopsys DesignWare APB UART that is attached
to a 32-bit APB bus where sub-word accesses are not allowed. Add a new
IO type (UPIO_DWAPB32) that performs 32 bit acccesses to the UART.

v2:
	- don't test for 32 bit in the output fast path, provide a
	  separate dwabp32_serial_out() function. Refactor
	  dwabp_serial_out() so that we can reuse the LCR saving
	  code.
v3:
	- rebased on top of "8250: use container_of() instead of
	  casting"

Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/8250.c        |   51 ++++++++++++++++++++++++++++++++----------
 drivers/serial/serial_core.c |    2 +
 include/linux/serial_core.h  |    1 +
 3 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 0b4ce47..9839199 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -454,22 +454,40 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value)
 		writeb(value, p->membase + offset);
 }
 
+/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
+static inline void dwapb_save_out_value(struct uart_port *p, int offset,
+					int value)
+{
+	struct uart_8250_port *up =
+		container_of(p, struct uart_8250_port, port);
+
+	if (offset == UART_LCR)
+		up->lcr = value;
+}
+
+/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
+static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
+{
+	if (offset == UART_TX || offset == UART_IER)
+		p->serial_in(p, UART_IER);
+}
+
 static void dwapb_serial_out(struct uart_port *p, int offset, int value)
 {
 	int save_offset = offset;
 	offset = map_8250_out_reg(p, offset) << p->regshift;
-	/* Save the LCR value so it can be re-written when a
-	 * Busy Detect interrupt occurs. */
-	if (save_offset == UART_LCR) {
-		struct uart_8250_port *up =
-			container_of(p, struct uart_8250_port, port);
-		up->lcr = value;
-	}
+	dwapb_save_out_value(p, save_offset, value);
 	writeb(value, p->membase + offset);
-	/* Read the IER to ensure any interrupt is cleared before
-	 * returning from ISR. */
-	if (save_offset == UART_TX || save_offset == UART_IER)
-		value = p->serial_in(p, UART_IER);
+	dwapb_check_clear_ier(p, save_offset);
+}
+
+static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
+{
+	int save_offset = offset;
+	offset = map_8250_out_reg(p, offset) << p->regshift;
+	dwapb_save_out_value(p, save_offset, value);
+	writel(value, p->membase + offset);
+	dwapb_check_clear_ier(p, save_offset);
 }
 
 static unsigned int io_serial_in(struct uart_port *p, int offset)
@@ -520,6 +538,11 @@ static void set_io_from_upio(struct uart_port *p)
 		p->serial_out = dwapb_serial_out;
 		break;
 
+	case UPIO_DWAPB32:
+		p->serial_in = mem32_serial_in;
+		p->serial_out = dwapb32_serial_out;
+		break;
+
 	default:
 		p->serial_in = io_serial_in;
 		p->serial_out = io_serial_out;
@@ -538,6 +561,7 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
 	case UPIO_MEM32:
 	case UPIO_AU:
 	case UPIO_DWAPB:
+	case UPIO_DWAPB32:
 		p->serial_out(p, offset, value);
 		p->serial_in(p, UART_LCR);	/* safe, no side-effects */
 		break;
@@ -1587,7 +1611,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
 			handled = 1;
 
 			end = NULL;
-		} else if (up->port.iotype == UPIO_DWAPB &&
+		} else if ((up->port.iotype == UPIO_DWAPB ||
+			    up->port.iotype == UPIO_DWAPB32) &&
 			  (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
 			/* The DesignWare APB UART has an Busy Detect (0x07)
 			 * interrupt meaning an LCR write attempt occured while the
@@ -2492,6 +2517,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
 	case UPIO_MEM32:
 	case UPIO_MEM:
 	case UPIO_DWAPB:
+	case UPIO_DWAPB32:
 		if (!up->port.mapbase)
 			break;
 
@@ -2529,6 +2555,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
 	case UPIO_MEM32:
 	case UPIO_MEM:
 	case UPIO_DWAPB:
+	case UPIO_DWAPB32:
 		if (!up->port.mapbase)
 			break;
 
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index c4ea146..2835e29 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2135,6 +2135,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
 	case UPIO_AU:
 	case UPIO_TSI:
 	case UPIO_DWAPB:
+	case UPIO_DWAPB32:
 		snprintf(address, sizeof(address),
 			 "MMIO 0x%llx", (unsigned long long)port->mapbase);
 		break;
@@ -2555,6 +2556,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
 	case UPIO_AU:
 	case UPIO_TSI:
 	case UPIO_DWAPB:
+	case UPIO_DWAPB32:
 		return (port1->mapbase == port2->mapbase);
 	}
 	return 0;
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 9ff9b7d..7a6daf1 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -314,6 +314,7 @@ struct uart_port {
 #define UPIO_TSI		(5)			/* Tsi108/109 type IO */
 #define UPIO_DWAPB		(6)			/* DesignWare APB UART */
 #define UPIO_RM9000		(7)			/* RM9000 type IO */
+#define UPIO_DWAPB32		(8)			/* DesignWare APB UART (32 bit accesses) */
 
 	unsigned int		read_status_mask;	/* driver specific */
 	unsigned int		ignore_status_mask;	/* driver specific */
-- 
1.7.3.2


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

* [PATCH 26/36] rocket: fix compiler warning on rocket_pci_ids
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (25 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 25/36] 8250: add a UPIO_DWAPB32 for 32 bit accesses Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 27/36] specialix: fix compiler warning on specialix_pci_tbl Greg Kroah-Hartman
                   ` (10 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Namhyung Kim, Greg Kroah-Hartman

From: Namhyung Kim <namhyung@gmail.com>

Annotate rocket_pci_ids as '__used' to fix following warning:

  CC      drivers/char/rocket.o
drivers/char/rocket.c:1767: warning: ‘rocket_pci_ids’ defined but not used

Signed-off-by: Namhyung Kim <namhyung@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/char/rocket.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 86308830..3e4e73a 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -1764,7 +1764,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
 
 #ifdef CONFIG_PCI
 
-static struct pci_device_id __devinitdata rocket_pci_ids[] = {
+static struct pci_device_id __devinitdata __used rocket_pci_ids[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
 	{ }
 };
-- 
1.7.3.2


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

* [PATCH 27/36] specialix: fix compiler warning on specialix_pci_tbl
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (26 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 26/36] rocket: fix compiler warning on rocket_pci_ids Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 28/36] ip2: fix compiler warning on ip2main_pci_tbl Greg Kroah-Hartman
                   ` (9 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Namhyung Kim, Roger Wolff, Greg Kroah-Hartman

From: Namhyung Kim <namhyung@gmail.com>

Annotate specialx_pci_tbl as '__used' to fix following warning:

  CC      drivers/char/specialix.o
drivers/char/specialix.c:2358: warning: ‘specialx_pci_tbl’ defined but not used

Signed-off-by: Namhyung Kim <namhyung@gmail.com>
Cc: Roger Wolff <R.E.Wolff@BitWizard.nl>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/char/specialix.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 9f8495b..499bb0f 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -2356,7 +2356,7 @@ static void __exit specialix_exit_module(void)
 	func_exit();
 }
 
-static struct pci_device_id specialx_pci_tbl[] __devinitdata = {
+static struct pci_device_id specialx_pci_tbl[] __devinitdata __used = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8) },
 	{ }
 };
-- 
1.7.3.2


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

* [PATCH 28/36] ip2: fix compiler warning on ip2main_pci_tbl
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (27 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 27/36] specialix: fix compiler warning on specialix_pci_tbl Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 29/36] 8250: fix uninitialized FIFOs Greg Kroah-Hartman
                   ` (8 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Namhyung Kim, Michael H. Warfield, Greg Kroah-Hartman

From: Namhyung Kim <namhyung@gmail.com>

Annotate ip2main_pci_tbl as '__used' to fix following warning:

  CC      drivers/char/ip2/ip2main.o
drivers/char/ip2/ip2main.c:3227: warning: ‘ip2main_pci_tbl’ defined but not used

Signed-off-by: Namhyung Kim <namhyung@gmail.com>
Cc: "Michael H. Warfield" <mhw@wittsend.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/char/ip2/ip2main.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index fcd02ba..c3a0253 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -3224,7 +3224,7 @@ ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned lo
 
 MODULE_LICENSE("GPL");
 
-static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
+static struct pci_device_id ip2main_pci_tbl[] __devinitdata __used = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
 	{ }
 };
-- 
1.7.3.2


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

* [PATCH 29/36] 8250: fix uninitialized FIFOs
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (28 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 28/36] ip2: fix compiler warning on ip2main_pci_tbl Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 30/36] pch_uart : fix warnings for 64bit compile Greg Kroah-Hartman
                   ` (7 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ondrej Puzman, Greg Kroah-Hartman

From: Ondrej Puzman <puzman@gmail.com>

I have found a bug in 8250.c driver which causes that 16550A uart FIFOs
are not turned on during initialization if they are manually configured
by setserial. UART is then working only as plain 16450 without FIFOs. On
systems with higher interrupt latency this causes buffer overruns and
loss of received data when using higher communication speeds.

I'm working for a company which produces industrial computers. These
devices typically contain high number (8 or more) of traditional 16550A
uarts - we use TL16C554A chips, but that is not much relevant. UARTs are
connected to the CPU by ISA bus (Celeron based devices) or LPC bus (Atom
based devices).

In the Linux the UARTs are using standard 8250.c driver and are
initialized using setserial command:
setserial /dev/ttyS4 uart 16550A port 0x3E0 irq 10 baud_base 115200

This executes the UART initialization through serial8250_startup()
function. At the beginning of the function up->capabilities is
initialized from uart_config:
 up->capabilities = uart_config[up->port.type].flags;
Please note that neither up->port.fifosize nor up->tx_loadsz is
initialized here!!

Later in the same function serial8250_clear_fifos() is called and
disables FIFOs. The above comment says that they will be reenabled in
set_termios (they won't ...)

After serial8250_startup() the serial8250_set_termios() is called. In
this function the following check fails because up->port.fifosize is
zero because it is not initialized correctly.

        if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
                if (baud < 2400)
                        fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
                else
                        fcr = uart_config[up->port.type].fcr;
        }

fcr variable remains zero and in the end the FCR register is set to zero
which results in disabled FIFOs even if the UART type is 16550A. This is
also true for other types of UARTs with FIFOs.

If the UART is autoconfigured via 'setserial /dev/ttySx autoconfig' then
port.fifosize and tx_loadsz are initialized correctly in the
autoconfig() function and the UART is working correctly then.

I checked the source codes and I can say that this bug is present in
2.6.x series of kernels for a couple of years. Namely I can confirm its
presence in 2.6.16.57, 2.6.32.24 and 2.6.36.1 (tested all of them on our
hardware).

I think it was not noticed before because not many people use manually
configured non PNP UARTs on ISA/LPC bus these days. Also the data loss
caused by buffer overruns occures only if  IRQ latency is higher then
time needed to receive one character on given communication speed.
For example our hardware looses received characters only if the UARTs
are connected throught LPC bus with SERIRQ (serial IRQ transport) and
not if they are connected to ISA bus because LPC SERIRQ has higher
interrupt latency then parallel ISA interupt lines.

Here is the patch to correct the bug created against 2.6.36.1:

Signed-off-by: Ondrej Puzman <puzman@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/8250.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 9839199..8747215 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1981,6 +1981,8 @@ static int serial8250_startup(struct uart_port *port)
 	unsigned char lsr, iir;
 	int retval;
 
+	up->port.fifosize = uart_config[up->port.type].fifo_size;
+	up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
 	up->capabilities = uart_config[up->port.type].flags;
 	up->mcr = 0;
 
-- 
1.7.3.2


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

* [PATCH 30/36] pch_uart : fix warnings for 64bit compile
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (29 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 29/36] 8250: fix uninitialized FIFOs Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 31/36] tty: fix typos/errors in tty_driver.h comments Greg Kroah-Hartman
                   ` (6 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Tomoya MORINAGA, Greg Kroah-Hartman

From: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com>

Fix the following warnings
drivers/serial/pch_uart.c: In function ‘dma_handle_rx’:
drivers/serial/pch_uart.c:685:24: warning: cast from pointer to integer of different size
drivers/serial/pch_uart.c: In function ‘dma_handle_tx’:
drivers/serial/pch_uart.c:778:23: warning: cast from pointer to integer of different size
drivers/serial/pch_uart.c: In function ‘pch_uart_init_port’:
drivers/serial/pch_uart.c:1289:20: warning: cast to pointer from integer of different size
drivers/serial/pch_uart.c: In function ‘pch_uart_exit_port’:
drivers/serial/pch_uart.c:1328:2: warning: cast from pointer to integer of different size

Signed-off-by: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com>
Reported-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/pch_uart.c |   13 +++++++------
 1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/serial/pch_uart.c b/drivers/serial/pch_uart.c
index b94d1fa..70a6145 100644
--- a/drivers/serial/pch_uart.c
+++ b/drivers/serial/pch_uart.c
@@ -682,7 +682,8 @@ static int dma_handle_rx(struct eg20t_port *priv)
 	sg_dma_len(sg) = priv->fifo_size;
 
 	sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
-		     sg_dma_len(sg), (int)priv->rx_buf_virt & ~PAGE_MASK);
+		     sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
+		     ~PAGE_MASK);
 
 	sg_dma_address(sg) = priv->rx_buf_dma;
 
@@ -1254,7 +1255,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	int ret;
 	unsigned int iobase;
 	unsigned int mapbase;
-	unsigned int rxbuf;
+	unsigned char *rxbuf;
 	int fifosize, base_baud;
 	static int num;
 
@@ -1262,7 +1263,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	if (priv == NULL)
 		goto init_port_alloc_err;
 
-	rxbuf = __get_free_page(GFP_KERNEL);
+	rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
 	if (!rxbuf)
 		goto init_port_free_txbuf;
 
@@ -1286,7 +1287,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	priv->iobase = iobase;
 	priv->pdev = pdev;
 	priv->tx_empty = 1;
-	priv->rxbuf.buf = (unsigned char *)rxbuf;
+	priv->rxbuf.buf = rxbuf;
 	priv->rxbuf.size = PAGE_SIZE;
 
 	priv->fifo_size = fifosize;
@@ -1313,7 +1314,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	return priv;
 
 init_port_hal_free:
-	free_page(rxbuf);
+	free_page((unsigned long)rxbuf);
 init_port_free_txbuf:
 	kfree(priv);
 init_port_alloc_err:
@@ -1325,7 +1326,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
 {
 	uart_remove_one_port(&pch_uart_driver, &priv->port);
 	pci_set_drvdata(priv->pdev, NULL);
-	free_page((unsigned int)priv->rxbuf.buf);
+	free_page((unsigned long)priv->rxbuf.buf);
 }
 
 static void pch_uart_pci_remove(struct pci_dev *pdev)
-- 
1.7.3.2


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

* [PATCH 31/36] tty: fix typos/errors in tty_driver.h comments
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (30 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 30/36] pch_uart : fix warnings for 64bit compile Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 32/36] Serial: Avoid unbalanced IRQ wake disable during resume Greg Kroah-Hartman
                   ` (5 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Timur Tabi, Greg Kroah-Hartman

From: Timur Tabi <timur@freescale.com>

Fix various typos and other errors in comments of tty_driver.h.  The most
significant is the wrong name of a function for the description of
TTY_DRIVER_DYNAMIC_DEV.

Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 include/linux/tty_driver.h |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 09678ed..c3d43eb 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -102,7 +102,7 @@
  * 	    unsigned int cmd, unsigned long arg);
  *
  * 	This routine allows the tty driver to implement
- *	device-specific ioctl's.  If the ioctl number passed in cmd
+ *	device-specific ioctls.  If the ioctl number passed in cmd
  * 	is not recognized by the driver, it should return ENOIOCTLCMD.
  *
  *	Optional
@@ -167,12 +167,12 @@
  * 
  * void (*hangup)(struct tty_struct *tty);
  *
- * 	This routine notifies the tty driver that it should hangup the
+ * 	This routine notifies the tty driver that it should hang up the
  * 	tty device.
  *
  *	Optional:
  *
- * int (*break_ctl)(struct tty_stuct *tty, int state);
+ * int (*break_ctl)(struct tty_struct *tty, int state);
  *
  * 	This optional routine requests the tty driver to turn on or
  * 	off BREAK status on the RS-232 port.  If state is -1,
@@ -358,7 +358,7 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
  * 	overruns, either.)
  *
  * TTY_DRIVER_DYNAMIC_DEV --- if set, the individual tty devices need
- *	to be registered with a call to tty_register_driver() when the
+ *	to be registered with a call to tty_register_device() when the
  *	device is found in the system and unregistered with a call to
  *	tty_unregister_device() so the devices will be show up
  *	properly in sysfs.  If not set, driver->num entries will be
-- 
1.7.3.2


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

* [PATCH 32/36] Serial: Avoid unbalanced IRQ wake disable during resume
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (31 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 31/36] tty: fix typos/errors in tty_driver.h comments Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 33/36] drivers: serial: apbuart: Handle OF failures gracefully Greg Kroah-Hartman
                   ` (4 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Govindraj.R, Santosh Shilimkar, Greg Kroah-Hartman

From: Govindraj.R <govindraj.raja@ti.com>

To avoid unbalanced IRQ wake disable, ensure that wakeups are disabled
only when wakeups have been successfully enabled.
Tested on OMAP3630SDP/ZOOM3.

Signed-off-by: Govindraj.R <govindraj.raja@ti.com>
Reported-by: Paul Walmsley <paul@pwsan.com>
Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
Acked-by: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/serial_core.c |    8 ++++++--
 include/linux/serial_core.h  |    1 +
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 2835e29..76418c1 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1986,7 +1986,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
 
 	tty_dev = device_find_child(uport->dev, &match, serial_match_port);
 	if (device_may_wakeup(tty_dev)) {
-		enable_irq_wake(uport->irq);
+		if (!enable_irq_wake(uport->irq))
+			uport->irq_wake = 1;
 		put_device(tty_dev);
 		mutex_unlock(&port->mutex);
 		return 0;
@@ -2052,7 +2053,10 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
 
 	tty_dev = device_find_child(uport->dev, &match, serial_match_port);
 	if (!uport->suspended && device_may_wakeup(tty_dev)) {
-		disable_irq_wake(uport->irq);
+		if (uport->irq_wake) {
+			disable_irq_wake(uport->irq);
+			uport->irq_wake = 0;
+		}
 		mutex_unlock(&port->mutex);
 		return 0;
 	}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 7a6daf1..a23fa29 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -365,6 +365,7 @@ struct uart_port {
 	struct device		*dev;			/* parent device */
 	unsigned char		hub6;			/* this should be in the 8250 driver */
 	unsigned char		suspended;
+	unsigned char		irq_wake;
 	unsigned char		unused[2];
 	void			*private_data;		/* generic platform data pointer */
 };
-- 
1.7.3.2


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

* [PATCH 33/36] drivers: serial: apbuart: Handle OF failures gracefully
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (32 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 32/36] Serial: Avoid unbalanced IRQ wake disable during resume Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 34/36] tty: add 'active' sysfs attribute to tty0 and console device Greg Kroah-Hartman
                   ` (3 subsequent siblings)
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel
  Cc: Thomas Gleixner, Grant Likely, Kristoffer Glembo, Greg Kroah-Hartman

From: Thomas Gleixner <tglx@linutronix.de>

The apbuart driver depends on OF and relies on everything being
available. So if it's probed on a platform which has OF support, but
no device tree is available it crashes. Triggered by the upcoming x86
OF support in randconfig testing.

Further it's inconsistent vs. the probing and exiting from the
of_match loop.

Make it robust and consistent:

 - check the availablility of OF nodes before dereferencing
 - return -ENODEV when the device tree lookup fails
 - return -ENODEV when no uart port configuration is found
 - return -ENODEV when invalid uart port configuration is found

Remove the enum_done check while at it. Driver init functions are only
called once. Remove the pointless vendor and device queries as well.

Reported-by: Ingo Molnar <mingo.elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Kristoffer Glembo <kristoffer@gaisler.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/apbuart.c |   48 ++++++++++++++++++---------------------------
 1 files changed, 19 insertions(+), 29 deletions(-)

diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
index cc01c65..2e84d9c 100644
--- a/drivers/serial/apbuart.c
+++ b/drivers/serial/apbuart.c
@@ -593,54 +593,44 @@ static struct of_platform_driver grlib_apbuart_of_driver = {
 };
 
 
-static void grlib_apbuart_configure(void)
+static int grlib_apbuart_configure(void)
 {
-	static int enum_done;
 	struct device_node *np, *rp;
-	struct uart_port *port = NULL;
 	const u32 *prop;
-	int freq_khz;
-	int v = 0, d = 0;
-	unsigned int addr;
-	int irq, line;
-	struct amba_prom_registers *regs;
-
-	if (enum_done)
-		return;
+	int freq_khz, line = 0;
 
 	/* Get bus frequency */
 	rp = of_find_node_by_path("/");
+	if (!rp)
+		return -ENODEV;
 	rp = of_get_next_child(rp, NULL);
+	if (!rp)
+		return -ENODEV;
 	prop = of_get_property(rp, "clock-frequency", NULL);
+	if (!prop)
+		return -ENODEV;
 	freq_khz = *prop;
 
-	line = 0;
 	for_each_matching_node(np, apbuart_match) {
+		const int *irqs = of_get_property(np, "interrupts", NULL);
+		const struct amba_prom_registers *regs;
+		struct uart_port *port;
+		unsigned long addr;
 
-		int *vendor = (int *) of_get_property(np, "vendor", NULL);
-		int *device = (int *) of_get_property(np, "device", NULL);
-		int *irqs = (int *) of_get_property(np, "interrupts", NULL);
-		regs = (struct amba_prom_registers *)
-		    of_get_property(np, "reg", NULL);
-
-		if (vendor)
-			v = *vendor;
-		if (device)
-			d = *device;
+		regs = of_get_property(np, "reg", NULL);
 
 		if (!irqs || !regs)
-			return;
+			return -ENODEV;
 
 		grlib_apbuart_nodes[line] = np;
 
 		addr = regs->phys_addr;
-		irq = *irqs;
 
 		port = &grlib_apbuart_ports[line];
 
 		port->mapbase = addr;
 		port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
-		port->irq = irq;
+		port->irq = *irqs;
 		port->iotype = UPIO_MEM;
 		port->ops = &grlib_apbuart_ops;
 		port->flags = UPF_BOOT_AUTOCONF;
@@ -652,12 +642,10 @@ static void grlib_apbuart_configure(void)
 		/* We support maximum UART_NR uarts ... */
 		if (line == UART_NR)
 			break;
-
 	}
 
-	enum_done = 1;
-
 	grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
+	return line ? 0 : -ENODEV;
 }
 
 static int __init grlib_apbuart_init(void)
@@ -665,7 +653,9 @@ static int __init grlib_apbuart_init(void)
 	int ret;
 
 	/* Find all APBUARTS in device the tree and initialize their ports */
-	grlib_apbuart_configure();
+	ret = grlib_apbuart_configure();
+	if (ret)
+		return ret;
 
 	printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
 
-- 
1.7.3.2


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

* [PATCH 34/36] tty: add 'active' sysfs attribute to tty0 and console device
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (33 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 33/36] drivers: serial: apbuart: Handle OF failures gracefully Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-07  9:09   ` Jiri Slaby
  2011-01-06 22:23 ` [PATCH 35/36] TTY: Add tty ioctl to figure device node of the system console Greg Kroah-Hartman
                   ` (2 subsequent siblings)
  37 siblings, 1 reply; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Kay Sievers, Greg Kroah-Hartman

From: Kay Sievers <kay.sievers@vrfy.org>

tty: add 'active' sysfs attribute to tty0 and console device

Userspace can query the actual virtual console, and the configured
console devices behind /dev/tt0 and /dev/console.

The last entry in the list of devices is the active device, analog
to the console= kernel command line option.

The attribute supports poll(), which is raised when the virtual
console is changed or /dev/console is reconfigured.

Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

index 0000000..b138b66
---
 Documentation/ABI/testing/sysfs-tty |   19 ++++++++++++++
 drivers/tty/tty_io.c                |   47 ++++++++++++++++++++++++++++++++---
 drivers/tty/vt/vt.c                 |   23 ++++++++++++++++-
 include/linux/console.h             |    2 +-
 kernel/printk.c                     |    2 +
 5 files changed, 87 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-tty

diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty
new file mode 100644
index 0000000..b138b66
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-tty
@@ -0,0 +1,19 @@
+What:		/sys/class/tty/console/active
+Date:		Nov 2010
+Contact:	Kay Sievers <kay.sievers@vrfy.org>
+Description:
+		 Shows the list of currently configured
+		 console devices, like 'tty1 ttyS0'.
+		 The last entry in the file is the active
+		 device connected to /dev/console.
+		 The file supports poll() to detect virtual
+		 console switches.
+
+What:		/sys/class/tty/tty0/active
+Date:		Nov 2010
+Contact:	Kay Sievers <kay.sievers@vrfy.org>
+Description:
+		 Shows the currently active virtual console
+		 device, like 'tty1'.
+		 The file supports poll() to detect virtual
+		 console switches.
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index c05c5af..be5ab4a 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3232,9 +3232,45 @@ static int __init tty_class_init(void)
 postcore_initcall(tty_class_init);
 
 /* 3/2004 jmc: why do these devices exist? */
-
 static struct cdev tty_cdev, console_cdev;
 
+static ssize_t show_cons_active(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct console *cs[16];
+	int i = 0;
+	struct console *c;
+	ssize_t count = 0;
+
+	acquire_console_sem();
+	for (c = console_drivers; c; c = c->next) {
+		if (!c->device)
+			continue;
+		if (!c->write)
+			continue;
+		if ((c->flags & CON_ENABLED) == 0)
+			continue;
+		cs[i++] = c;
+		if (i >= ARRAY_SIZE(cs))
+			break;
+	}
+	while (i--)
+		count += sprintf(buf + count, "%s%d%c",
+				 cs[i]->name, cs[i]->index, i ? ' ':'\n');
+	release_console_sem();
+
+	return count;
+}
+static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL);
+
+static struct device *consdev;
+
+void console_sysfs_notify(void)
+{
+	if (consdev)
+		sysfs_notify(&consdev->kobj, NULL, "active");
+}
+
 /*
  * Ok, now we can initialize the rest of the tty devices and can count
  * on memory allocations, interrupts etc..
@@ -3245,15 +3281,18 @@ int __init tty_init(void)
 	if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
 		panic("Couldn't register /dev/tty driver\n");
-	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
-			      "tty");
+	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
 
 	cdev_init(&console_cdev, &console_fops);
 	if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
 	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
 		panic("Couldn't register /dev/console driver\n");
-	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+	consdev = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
 			      "console");
+	if (IS_ERR(consdev))
+		consdev = NULL;
+	else
+		device_create_file(consdev, &dev_attr_active);
 
 #ifdef CONFIG_VT
 	vty_init(&console_fops);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index a8ec48e..76407ec 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -236,6 +236,14 @@ enum {
 };
 
 /*
+ * /sys/class/tty/tty0/
+ *
+ * the attribute 'active' contains the name of the current vc
+ * console and it supports poll() to detect vc switches
+ */
+static struct device *tty0dev;
+
+/*
  * Notifier list for console events.
  */
 static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
@@ -688,6 +696,8 @@ void redraw_screen(struct vc_data *vc, int is_switch)
 			save_screen(old_vc);
 			set_origin(old_vc);
 		}
+		if (tty0dev)
+			sysfs_notify(&tty0dev->kobj, NULL, "active");
 	} else {
 		hide_cursor(vc);
 		redraw = 1;
@@ -2967,13 +2977,24 @@ static const struct tty_operations con_ops = {
 
 static struct cdev vc0_cdev;
 
+static ssize_t show_tty_active(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "tty%d\n", fg_console + 1);
+}
+static DEVICE_ATTR(active, S_IRUGO, show_tty_active, NULL);
+
 int __init vty_init(const struct file_operations *console_fops)
 {
 	cdev_init(&vc0_cdev, console_fops);
 	if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
 	    register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
 		panic("Couldn't register /dev/tty0 driver\n");
-	device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+	tty0dev = device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+	if (IS_ERR(tty0dev))
+		tty0dev = NULL;
+	else
+		device_create_file(tty0dev, &dev_attr_active);
 
 	vcs_init();
 
diff --git a/include/linux/console.h b/include/linux/console.h
index 875cfb1..9774fe6 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -151,7 +151,7 @@ extern int is_console_locked(void);
 extern int braille_register_console(struct console *, int index,
 		char *console_options, char *braille_options);
 extern int braille_unregister_console(struct console *);
-
+extern void console_sysfs_notify(void);
 extern int console_suspend_enabled;
 
 /* Suspend and resume console messages over PM events */
diff --git a/kernel/printk.c b/kernel/printk.c
index bf0420a..5417784 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1332,6 +1332,7 @@ void register_console(struct console *newcon)
 		spin_unlock_irqrestore(&logbuf_lock, flags);
 	}
 	release_console_sem();
+	console_sysfs_notify();
 
 	/*
 	 * By unregistering the bootconsoles after we enable the real console
@@ -1390,6 +1391,7 @@ int unregister_console(struct console *console)
 		console_drivers->flags |= CON_CONSDEV;
 
 	release_console_sem();
+	console_sysfs_notify();
 	return res;
 }
 EXPORT_SYMBOL(unregister_console);
-- 
1.7.3.2


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

* [PATCH 35/36] TTY: Add tty ioctl to figure device node of the system console.
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (34 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 34/36] tty: add 'active' sysfs attribute to tty0 and console device Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-06 22:23 ` [PATCH 36/36] serial: apbuart: Fixup apbuart_console_init() Greg Kroah-Hartman
  2011-01-07 22:44 ` [GIT PATCH] TTY/serial merge for .38 Linus Torvalds
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Werner Fink, Greg Kroah-Hartman

From: Werner Fink <werner@suse.de>

This has been in the SuSE kernels for a very long time.

Signed-off-by: Werner Fink <werner@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 arch/alpha/include/asm/ioctls.h   |    1 +
 arch/mips/include/asm/ioctls.h    |    1 +
 arch/parisc/include/asm/ioctls.h  |    1 +
 arch/powerpc/include/asm/ioctls.h |    1 +
 arch/sh/include/asm/ioctls.h      |    1 +
 arch/sparc/include/asm/ioctls.h   |    1 +
 arch/xtensa/include/asm/ioctls.h  |    1 +
 drivers/tty/tty_io.c              |    5 +++++
 fs/compat_ioctl.c                 |    1 +
 include/asm-generic/ioctls.h      |    1 +
 10 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/alpha/include/asm/ioctls.h b/arch/alpha/include/asm/ioctls.h
index 59617c3..034b6cf 100644
--- a/arch/alpha/include/asm/ioctls.h
+++ b/arch/alpha/include/asm/ioctls.h
@@ -92,6 +92,7 @@
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
 #define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+#define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 
 #define TIOCSERCONFIG	0x5453
diff --git a/arch/mips/include/asm/ioctls.h b/arch/mips/include/asm/ioctls.h
index d87cb04..d967b89 100644
--- a/arch/mips/include/asm/ioctls.h
+++ b/arch/mips/include/asm/ioctls.h
@@ -83,6 +83,7 @@
 #define TCSETSF2	_IOW('T', 0x2D, struct termios2)
 #define TIOCGPTN	_IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T', 0x31, int)  /* Lock/unlock Pty */
+#define TIOCGDEV	_IOR('T', 0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T', 0x36, int)  /* Generate signal on Pty slave */
 
 /* I hope the range from 0x5480 on is free ... */
diff --git a/arch/parisc/include/asm/ioctls.h b/arch/parisc/include/asm/ioctls.h
index 4e06144..6ba80d0 100644
--- a/arch/parisc/include/asm/ioctls.h
+++ b/arch/parisc/include/asm/ioctls.h
@@ -52,6 +52,7 @@
 #define TCSETSF2	_IOW('T',0x2D, struct termios2)
 #define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+#define TIOCGDEV	_IOR('T',0x32, int)  /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 
 #define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
diff --git a/arch/powerpc/include/asm/ioctls.h b/arch/powerpc/include/asm/ioctls.h
index 8519200..c7dc17c 100644
--- a/arch/powerpc/include/asm/ioctls.h
+++ b/arch/powerpc/include/asm/ioctls.h
@@ -94,6 +94,7 @@
 #define TIOCSRS485	0x542f
 #define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+#define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 
 #define TIOCSERCONFIG	0x5453
diff --git a/arch/sh/include/asm/ioctls.h b/arch/sh/include/asm/ioctls.h
index eb6c4c6..84e85a7 100644
--- a/arch/sh/include/asm/ioctls.h
+++ b/arch/sh/include/asm/ioctls.h
@@ -85,6 +85,7 @@
 #define TCSETSF2	_IOW('T', 45, struct termios2)
 #define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+#define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 
 #define TIOCSERCONFIG	_IO('T', 83) /* 0x5453 */
diff --git a/arch/sparc/include/asm/ioctls.h b/arch/sparc/include/asm/ioctls.h
index 53f4ee0..ed3807b 100644
--- a/arch/sparc/include/asm/ioctls.h
+++ b/arch/sparc/include/asm/ioctls.h
@@ -19,6 +19,7 @@
 #define TCSETS2		_IOW('T', 13, struct termios2)
 #define TCSETSW2	_IOW('T', 14, struct termios2)
 #define TCSETSF2	_IOW('T', 15, struct termios2)
+#define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 
 /* Note that all the ioctls that are not available in Linux have a 
  * double underscore on the front to: a) avoid some programs to
diff --git a/arch/xtensa/include/asm/ioctls.h b/arch/xtensa/include/asm/ioctls.h
index ab18000..ccf1800 100644
--- a/arch/xtensa/include/asm/ioctls.h
+++ b/arch/xtensa/include/asm/ioctls.h
@@ -98,6 +98,7 @@
 #define TCSETSF2	_IOW('T', 45, struct termios2)
 #define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+#define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 
 #define TIOCSERCONFIG	_IO('T', 83)
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index be5ab4a..d2333ab 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2618,6 +2618,11 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		return put_user(tty->ldisc->ops->num, (int __user *)p);
 	case TIOCSETD:
 		return tiocsetd(tty, p);
+	case TIOCGDEV:
+	{
+		unsigned int ret = new_encode_dev(tty_devnum(real_tty));
+		return put_user(ret, (unsigned int __user *)p);
+	}
 	/*
 	 * Break handling
 	 */
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 410ed18..a1a8f0c 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -837,6 +837,7 @@ COMPATIBLE_IOCTL(TCSETSW)
 COMPATIBLE_IOCTL(TCSETSF)
 COMPATIBLE_IOCTL(TIOCLINUX)
 COMPATIBLE_IOCTL(TIOCSBRK)
+COMPATIBLE_IOCTL(TIOCGDEV)
 COMPATIBLE_IOCTL(TIOCCBRK)
 COMPATIBLE_IOCTL(TIOCGSID)
 COMPATIBLE_IOCTL(TIOCGICOUNT)
diff --git a/include/asm-generic/ioctls.h b/include/asm-generic/ioctls.h
index a321665..3f3f2d1 100644
--- a/include/asm-generic/ioctls.h
+++ b/include/asm-generic/ioctls.h
@@ -67,6 +67,7 @@
 #endif
 #define TIOCGPTN	_IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T', 0x31, int)  /* Lock/unlock Pty */
+#define TIOCGDEV	_IOR('T', 0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TCGETX		0x5432 /* SYS5 TCGETX compatibility */
 #define TCSETX		0x5433
 #define TCSETXF		0x5434
-- 
1.7.3.2


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

* [PATCH 36/36] serial: apbuart: Fixup apbuart_console_init()
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (35 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 35/36] TTY: Add tty ioctl to figure device node of the system console Greg Kroah-Hartman
@ 2011-01-06 22:23 ` Greg Kroah-Hartman
  2011-01-07 22:44 ` [GIT PATCH] TTY/serial merge for .38 Linus Torvalds
  37 siblings, 0 replies; 54+ messages in thread
From: Greg Kroah-Hartman @ 2011-01-06 22:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Thomas Gleixner, Greg Kroah-Hartman

From: Thomas Gleixner <tglx@linutronix.de>

commit 35c64e5d (drivers: serial: apbuart: Handle OF failures
gracefully) missed that the modified grlib_apbuart_configure()
function is called from apbuart_console_init() as well.

Fix the fallout.

Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/serial/apbuart.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
index 2e84d9c..a30bb962 100644
--- a/drivers/serial/apbuart.c
+++ b/drivers/serial/apbuart.c
@@ -520,11 +520,12 @@ static struct console grlib_apbuart_console = {
 };
 
 
-static void grlib_apbuart_configure(void);
+static int grlib_apbuart_configure(void);
 
 static int __init apbuart_console_init(void)
 {
-	grlib_apbuart_configure();
+	if (grlib_apbuart_configure())
+		return -ENODEV;
 	register_console(&grlib_apbuart_console);
 	return 0;
 }
-- 
1.7.3.2


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

* Re: [GIT PATCH] TTY/serial merge for .38
  2011-01-06 22:00 ` Alan Cox
@ 2011-01-06 22:24   ` Greg KH
  2011-01-06 23:54     ` Kay Sievers
  0 siblings, 1 reply; 54+ messages in thread
From: Greg KH @ 2011-01-06 22:24 UTC (permalink / raw)
  To: Alan Cox; +Cc: Linus Torvalds, Andrew Morton, linux-kernel, Kay Sievers

On Thu, Jan 06, 2011 at 10:00:17PM +0000, Alan Cox wrote:
> > There was some arguing about the tty console detection patches, but as
> > the existing ioctl does not work properly, Kay's patch was accepted to
> > resolve this issue and allow systemd to correctly detect consoles.  I
> > know Alan doesn't like this, but I feel it's the best way to solve the
> > issue (combined with the fact that there is no proposed other solution.)
> 
> I'm a bit confused about this one Greg - all the distributions used the
> ioctl you refer to below for this purpose and have for years
> 
> > This series also includes the long-out-of-tree ioctl that SUSE and
> > Debian have been dragging around in their kernels for the past 10+
> > years.  Thanks to Werner for finally submitting it in a mergable form.
> 
> Which I believe means we don't need the sysfs patch as well - Kay ?

I didn't think that the ioctl was sufficient for what systemd required,
it was only needed for "old-style" initrd programs like what used to be
used in SUSE and other distros, but are now being phased out.

Kay?

thanks,

greg k-h

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

* Re: [GIT PATCH] TTY/serial merge for .38
  2011-01-06 22:24   ` Greg KH
@ 2011-01-06 23:54     ` Kay Sievers
  2011-01-07  3:40       ` Greg KH
  0 siblings, 1 reply; 54+ messages in thread
From: Kay Sievers @ 2011-01-06 23:54 UTC (permalink / raw)
  To: Greg KH; +Cc: Alan Cox, Linus Torvalds, Andrew Morton, linux-kernel

On Thu, Jan 6, 2011 at 23:24, Greg KH <gregkh@suse.de> wrote:
> On Thu, Jan 06, 2011 at 10:00:17PM +0000, Alan Cox wrote:
>> > There was some arguing about the tty console detection patches, but as
>> > the existing ioctl does not work properly, Kay's patch was accepted to
>> > resolve this issue and allow systemd to correctly detect consoles.  I
>> > know Alan doesn't like this, but I feel it's the best way to solve the
>> > issue (combined with the fact that there is no proposed other solution.)
>>
>> I'm a bit confused about this one Greg - all the distributions used the
>> ioctl you refer to below for this purpose and have for years
>>
>> > This series also includes the long-out-of-tree ioctl that SUSE and
>> > Debian have been dragging around in their kernels for the past 10+
>> > years.  Thanks to Werner for finally submitting it in a mergable form.
>>
>> Which I believe means we don't need the sysfs patch as well - Kay ?
>
> I didn't think that the ioctl was sufficient for what systemd required,
> it was only needed for "old-style" initrd programs like what used to be
> used in SUSE and other distros, but are now being phased out.

We want all involved ttys below /dev/console not only the primary one.
Also we like to get notified about re-configs, hence the poll()
support. Both is not covered at the moment, or by the old, now to be
merged, ioctl.

Kay

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

* RE: [PATCH 22/36] serial: fix pch_uart kconfig & build
  2011-01-06 22:23 ` [PATCH 22/36] serial: fix pch_uart kconfig & build Greg Kroah-Hartman
@ 2011-01-07  0:21   ` Tomoya MORINAGA
  2011-01-07  0:31     ` Greg KH
  0 siblings, 1 reply; 54+ messages in thread
From: Tomoya MORINAGA @ 2011-01-07  0:21 UTC (permalink / raw)
  To: 'Greg Kroah-Hartman', linux-kernel; +Cc: 'Randy Dunlap'

Hi Greg,

On Friday, January 07, 2011 7:23 AM, Greg Kroah-Hartman wrote:
> Also, the help text says that the 
> driver enables & uses PCH_DMA, which is not enabled, so select that. 

I think PCH_DMA is not always used when a user uses PCH_UART.
Since overhead of DMA is not small, in case of low frequent communication,
without DMA is better.
Thus, I think "select PCH_DMA" is unnecessary

(Of course, the PCH_UART works both with/without PCH_DMA.)

-----------------------------------------
Tomoya MORINAGA
OKI SEMICONDUCTOR CO., LTD.


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

* Re: [PATCH 22/36] serial: fix pch_uart kconfig & build
  2011-01-07  0:21   ` Tomoya MORINAGA
@ 2011-01-07  0:31     ` Greg KH
  0 siblings, 0 replies; 54+ messages in thread
From: Greg KH @ 2011-01-07  0:31 UTC (permalink / raw)
  To: Tomoya MORINAGA; +Cc: linux-kernel, 'Randy Dunlap'

On Fri, Jan 07, 2011 at 09:21:43AM +0900, Tomoya MORINAGA wrote:
> Hi Greg,
> 
> On Friday, January 07, 2011 7:23 AM, Greg Kroah-Hartman wrote:
> > Also, the help text says that the 
> > driver enables & uses PCH_DMA, which is not enabled, so select that. 
> 
> I think PCH_DMA is not always used when a user uses PCH_UART.
> Since overhead of DMA is not small, in case of low frequent communication,
> without DMA is better.
> Thus, I think "select PCH_DMA" is unnecessary
> 
> (Of course, the PCH_UART works both with/without PCH_DMA.)

Patches are always welcome to fix things up :)

thanks,

greg k-h

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

* Re: [GIT PATCH] TTY/serial merge for .38
  2011-01-06 23:54     ` Kay Sievers
@ 2011-01-07  3:40       ` Greg KH
  0 siblings, 0 replies; 54+ messages in thread
From: Greg KH @ 2011-01-07  3:40 UTC (permalink / raw)
  To: Kay Sievers; +Cc: Alan Cox, Linus Torvalds, Andrew Morton, linux-kernel

On Fri, Jan 07, 2011 at 12:54:05AM +0100, Kay Sievers wrote:
> On Thu, Jan 6, 2011 at 23:24, Greg KH <gregkh@suse.de> wrote:
> > On Thu, Jan 06, 2011 at 10:00:17PM +0000, Alan Cox wrote:
> >> > There was some arguing about the tty console detection patches, but as
> >> > the existing ioctl does not work properly, Kay's patch was accepted to
> >> > resolve this issue and allow systemd to correctly detect consoles.  I
> >> > know Alan doesn't like this, but I feel it's the best way to solve the
> >> > issue (combined with the fact that there is no proposed other solution.)
> >>
> >> I'm a bit confused about this one Greg - all the distributions used the
> >> ioctl you refer to below for this purpose and have for years
> >>
> >> > This series also includes the long-out-of-tree ioctl that SUSE and
> >> > Debian have been dragging around in their kernels for the past 10+
> >> > years.  Thanks to Werner for finally submitting it in a mergable form.
> >>
> >> Which I believe means we don't need the sysfs patch as well - Kay ?
> >
> > I didn't think that the ioctl was sufficient for what systemd required,
> > it was only needed for "old-style" initrd programs like what used to be
> > used in SUSE and other distros, but are now being phased out.
> 
> We want all involved ttys below /dev/console not only the primary one.
> Also we like to get notified about re-configs, hence the poll()
> support. Both is not covered at the moment, or by the old, now to be
> merged, ioctl.

Ah, ok, that makes sense, and is why I merged both, they are both needed
by different users (well, the ioctl users could use the sysfs file, but
as it has been used for 10+ years, it's only fair to include it as well
to provide backward compatiblity to those users).

thanks,

greg k-h

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

* Re: [PATCH 34/36] tty: add 'active' sysfs attribute to tty0 and console device
  2011-01-06 22:23 ` [PATCH 34/36] tty: add 'active' sysfs attribute to tty0 and console device Greg Kroah-Hartman
@ 2011-01-07  9:09   ` Jiri Slaby
  2011-01-07 13:20     ` Kay Sievers
  0 siblings, 1 reply; 54+ messages in thread
From: Jiri Slaby @ 2011-01-07  9:09 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-kernel, Kay Sievers

On 01/06/2011 11:23 PM, Greg Kroah-Hartman wrote:
> --- a/drivers/tty/tty_io.c
> +++ b/drivers/tty/tty_io.c
> @@ -3232,9 +3232,45 @@ static int __init tty_class_init(void)
>  postcore_initcall(tty_class_init);
>  
>  /* 3/2004 jmc: why do these devices exist? */
> -
>  static struct cdev tty_cdev, console_cdev;
>  
> +static ssize_t show_cons_active(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct console *cs[16];
> +	int i = 0;
> +	struct console *c;
> +	ssize_t count = 0;
> +
> +	acquire_console_sem();
> +	for (c = console_drivers; c; c = c->next) {

This should be:
for_each_console(c)
like somebody already suggested.

> +		if (!c->device)
> +			continue;

Why are consoles without devices ignored here?

Other than that there are 2 build warnings, see below.

> +		if (!c->write)
> +			continue;
> +		if ((c->flags & CON_ENABLED) == 0)
> +			continue;
> +		cs[i++] = c;
> +		if (i >= ARRAY_SIZE(cs))
> +			break;
> +	}
> +	while (i--)
> +		count += sprintf(buf + count, "%s%d%c",
> +				 cs[i]->name, cs[i]->index, i ? ' ':'\n');
> +	release_console_sem();
> +
> +	return count;
> +}
> +static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL);
> +
> +static struct device *consdev;
> +
> +void console_sysfs_notify(void)
> +{
> +	if (consdev)
> +		sysfs_notify(&consdev->kobj, NULL, "active");
> +}
> +
>  /*
>   * Ok, now we can initialize the rest of the tty devices and can count
>   * on memory allocations, interrupts etc..
> @@ -3245,15 +3281,18 @@ int __init tty_init(void)
>  	if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
>  	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
>  		panic("Couldn't register /dev/tty driver\n");
> -	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
> -			      "tty");
> +	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
>  
>  	cdev_init(&console_cdev, &console_fops);
>  	if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
>  	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
>  		panic("Couldn't register /dev/console driver\n");
> -	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
> +	consdev = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
>  			      "console");
> +	if (IS_ERR(consdev))
> +		consdev = NULL;
> +	else
> +		device_create_file(consdev, &dev_attr_active);

drivers/tty/tty_io.c: In function ‘tty_init’:
drivers/tty/tty_io.c:3309:21: warning: ignoring return value of
‘device_create_file’, declared with attribute warn_unused_result

> @@ -2967,13 +2977,24 @@ static const struct tty_operations con_ops = {
>  
>  static struct cdev vc0_cdev;
>  
> +static ssize_t show_tty_active(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	return sprintf(buf, "tty%d\n", fg_console + 1);
> +}
> +static DEVICE_ATTR(active, S_IRUGO, show_tty_active, NULL);
> +
>  int __init vty_init(const struct file_operations *console_fops)
>  {
>  	cdev_init(&vc0_cdev, console_fops);
>  	if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
>  	    register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
>  		panic("Couldn't register /dev/tty0 driver\n");
> -	device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
> +	tty0dev = device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
> +	if (IS_ERR(tty0dev))
> +		tty0dev = NULL;
> +	else
> +		device_create_file(tty0dev, &dev_attr_active);

drivers/tty/vt/vt.c: In function ‘vty_init’:
drivers/tty/vt/vt.c:2997:21: warning: ignoring return value of
‘device_create_file’, declared with attribute warn_unused_result

>  
>  	vcs_init();
>  

regards,
-- 
js
suse labs

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

* Re: [PATCH 34/36] tty: add 'active' sysfs attribute to tty0 and console device
  2011-01-07  9:09   ` Jiri Slaby
@ 2011-01-07 13:20     ` Kay Sievers
  2011-01-07 15:12       ` Jiri Slaby
  0 siblings, 1 reply; 54+ messages in thread
From: Kay Sievers @ 2011-01-07 13:20 UTC (permalink / raw)
  To: Jiri Slaby; +Cc: Greg Kroah-Hartman, linux-kernel

On Fri, Jan 7, 2011 at 10:09, Jiri Slaby <jslaby@suse.cz> wrote:
> On 01/06/2011 11:23 PM, Greg Kroah-Hartman wrote:
>> --- a/drivers/tty/tty_io.c
>> +++ b/drivers/tty/tty_io.c
>> @@ -3232,9 +3232,45 @@ static int __init tty_class_init(void)
>>  postcore_initcall(tty_class_init);
>>
>>  /* 3/2004 jmc: why do these devices exist? */
>> -
>>  static struct cdev tty_cdev, console_cdev;
>>
>> +static ssize_t show_cons_active(struct device *dev,
>> +                             struct device_attribute *attr, char *buf)
>> +{
>> +     struct console *cs[16];
>> +     int i = 0;
>> +     struct console *c;
>> +     ssize_t count = 0;
>> +
>> +     acquire_console_sem();
>> +     for (c = console_drivers; c; c = c->next) {
>
> This should be:
> for_each_console(c)
> like somebody already suggested.

That's exported now? It was local to printk.c at least that time.

Anyway, the only sensible change here is to convert that home-grown
->next thing to a proper kernel linked list, and use the common
iterators instead of doing it on our own, or export new custom ones.

>> +             if (!c->device)
>> +                     continue;
>
> Why are consoles without devices ignored here?

It's a common pattern all over the place. What is a "console without a
device" that would be interesting here?

> Other than that there are 2 build warnings, see below.
>
>> -     device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
>> +     tty0dev = device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
>> +     if (IS_ERR(tty0dev))
>> +             tty0dev = NULL;
>> +     else
>> +             device_create_file(tty0dev, &dev_attr_active);
>
> drivers/tty/vt/vt.c: In function ‘vty_init’:
> drivers/tty/vt/vt.c:2997:21: warning: ignoring return value of
> ‘device_create_file’, declared with attribute warn_unused_result

The code doesn't even check device_create(). :)

Anyway we actually don't want to check the return value of
file_create(), it's a non-fatal error, if it ever happens.

What's the preferred way to do that:
  int ignore = device_create_file()
?

Kay

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

* Re: [PATCH 34/36] tty: add 'active' sysfs attribute to tty0 and console device
  2011-01-07 13:20     ` Kay Sievers
@ 2011-01-07 15:12       ` Jiri Slaby
  0 siblings, 0 replies; 54+ messages in thread
From: Jiri Slaby @ 2011-01-07 15:12 UTC (permalink / raw)
  To: Kay Sievers; +Cc: Greg Kroah-Hartman, linux-kernel

On 01/07/2011 02:20 PM, Kay Sievers wrote:
> On Fri, Jan 7, 2011 at 10:09, Jiri Slaby <jslaby@suse.cz> wrote:
>> On 01/06/2011 11:23 PM, Greg Kroah-Hartman wrote:
>>> --- a/drivers/tty/tty_io.c
>>> +++ b/drivers/tty/tty_io.c
>>> @@ -3232,9 +3232,45 @@ static int __init tty_class_init(void)
>>>  postcore_initcall(tty_class_init);
>>>
>>>  /* 3/2004 jmc: why do these devices exist? */
>>> -
>>>  static struct cdev tty_cdev, console_cdev;
>>>
>>> +static ssize_t show_cons_active(struct device *dev,
>>> +                             struct device_attribute *attr, char *buf)
>>> +{
>>> +     struct console *cs[16];
>>> +     int i = 0;
>>> +     struct console *c;
>>> +     ssize_t count = 0;
>>> +
>>> +     acquire_console_sem();
>>> +     for (c = console_drivers; c; c = c->next) {
>>
>> This should be:
>> for_each_console(c)
>> like somebody already suggested.
> 
> That's exported now? It was local to printk.c at least that time.
> 
> Anyway, the only sensible change here is to convert that home-grown
> ->next thing to a proper kernel linked list, and use the common
> iterators instead of doing it on our own, or export new custom ones.

Perhaps -- I didn't look into the code if there is something which
blocked this to be done years ago. I doubt there is...

>>> +             if (!c->device)
>>> +                     continue;
>>
>> Why are consoles without devices ignored here?
> 
> It's a common pattern all over the place. What is a "console without a
> device" that would be interesting here?

For example parport console. The question is whether you are interested
in consoles without ttys in systemd and other potential users.

>> Other than that there are 2 build warnings, see below.
>>
>>> -     device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
>>> +     tty0dev = device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
>>> +     if (IS_ERR(tty0dev))
>>> +             tty0dev = NULL;
>>> +     else
>>> +             device_create_file(tty0dev, &dev_attr_active);
>>
>> drivers/tty/vt/vt.c: In function ‘vty_init’:
>> drivers/tty/vt/vt.c:2997:21: warning: ignoring return value of
>> ‘device_create_file’, declared with attribute warn_unused_result
> 
> The code doesn't even check device_create(). :)
> 
> Anyway we actually don't want to check the return value of
> file_create(), it's a non-fatal error, if it ever happens.

Ok, but we don't want to introduce new warnings.

> What's the preferred way to do that:
>   int ignore = device_create_file()

I think the usual workaround in C is casting to void.

regards,
-- 
js
suse labs

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

* Re: [GIT PATCH] TTY/serial merge for .38
  2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
                   ` (36 preceding siblings ...)
  2011-01-06 22:23 ` [PATCH 36/36] serial: apbuart: Fixup apbuart_console_init() Greg Kroah-Hartman
@ 2011-01-07 22:44 ` Linus Torvalds
  2011-01-07 23:41   ` Greg KH
  37 siblings, 1 reply; 54+ messages in thread
From: Linus Torvalds @ 2011-01-07 22:44 UTC (permalink / raw)
  To: Greg KH, Daniel Hellstrom, David S. Miller, Thomas Gleixner, Ingo Molnar
  Cc: Andrew Morton, linux-kernel, Alan Cox, Kay Sievers

On Thu, Jan 6, 2011 at 1:54 PM, Greg KH <gregkh@suse.de> wrote:
> Here is the big tty and serial merge for .38.  I'll be sending another
> smaller one that just moves drivers around after .38-rc1 is out, as is
> the norm for file moves to handle issues with other trees syncing up
> properly.

Merged. However, the drivers/serial/apbuart.c file conflicted, and
both sides of the merge had some insanity in them.

So I did an "evil merge" - a merge that actually changed the code to
match neither side - and it looks better to me. But maybe that's just
the drugs I'm taking talking.

So people should check it out. In particular, look at the interaction
of "drivers: serial: apbuart: Handle OF failures gracefully" and the
"Added support for ampopts in APBUART driver. Used in AMP systems"
commit.

                    Linus

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

* Re: [GIT PATCH] TTY/serial merge for .38
  2011-01-07 22:44 ` [GIT PATCH] TTY/serial merge for .38 Linus Torvalds
@ 2011-01-07 23:41   ` Greg KH
  2011-01-11 14:00     ` Daniel Hellstrom
  0 siblings, 1 reply; 54+ messages in thread
From: Greg KH @ 2011-01-07 23:41 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Daniel Hellstrom, David S. Miller, Thomas Gleixner, Ingo Molnar,
	Andrew Morton, linux-kernel, Alan Cox, Kay Sievers

On Fri, Jan 07, 2011 at 02:44:14PM -0800, Linus Torvalds wrote:
> On Thu, Jan 6, 2011 at 1:54 PM, Greg KH <gregkh@suse.de> wrote:
> > Here is the big tty and serial merge for .38.  I'll be sending another
> > smaller one that just moves drivers around after .38-rc1 is out, as is
> > the norm for file moves to handle issues with other trees syncing up
> > properly.
> 
> Merged. However, the drivers/serial/apbuart.c file conflicted, and
> both sides of the merge had some insanity in them.
> 
> So I did an "evil merge" - a merge that actually changed the code to
> match neither side - and it looks better to me. But maybe that's just
> the drugs I'm taking talking.
> 
> So people should check it out. In particular, look at the interaction
> of "drivers: serial: apbuart: Handle OF failures gracefully" and the
> "Added support for ampopts in APBUART driver. Used in AMP systems"
> commit.

The merge looks ok to me, but I don't have this hardware, so I can't
test it.  Thomas, can you verify this is ok?

thanks,

greg k-h

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

* Re: [GIT PATCH] TTY/serial merge for .38
  2011-01-07 23:41   ` Greg KH
@ 2011-01-11 14:00     ` Daniel Hellstrom
  2011-01-11 14:56       ` Thomas Gleixner
  0 siblings, 1 reply; 54+ messages in thread
From: Daniel Hellstrom @ 2011-01-11 14:00 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Greg KH, David S. Miller, Thomas Gleixner, Ingo Molnar,
	Andrew Morton, linux-kernel, Alan Cox, Kay Sievers

Greg KH wrote:

>On Fri, Jan 07, 2011 at 02:44:14PM -0800, Linus Torvalds wrote:
>  
>
>>On Thu, Jan 6, 2011 at 1:54 PM, Greg KH <gregkh@suse.de> wrote:
>>    
>>
>>>Here is the big tty and serial merge for .38.  I'll be sending another
>>>smaller one that just moves drivers around after .38-rc1 is out, as is
>>>the norm for file moves to handle issues with other trees syncing up
>>>properly.
>>>      
>>>
>>Merged. However, the drivers/serial/apbuart.c file conflicted, and
>>both sides of the merge had some insanity in them.
>>
>>So I did an "evil merge" - a merge that actually changed the code to
>>match neither side - and it looks better to me. But maybe that's just
>>the drugs I'm taking talking.
>>
>>So people should check it out. In particular, look at the interaction
>>of "drivers: serial: apbuart: Handle OF failures gracefully" and the
>>"Added support for ampopts in APBUART driver. Used in AMP systems"
>>commit.
>>    
>>
>
>The merge looks ok to me, but I don't have this hardware, so I can't
>test it.  Thomas, can you verify this is ok?
>  
>

The code looks good and I have tested on the APBUART hardware - it works.

Thanks,
Daniel Hellstrom


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

* Re: [GIT PATCH] TTY/serial merge for .38
  2011-01-11 14:00     ` Daniel Hellstrom
@ 2011-01-11 14:56       ` Thomas Gleixner
  2011-01-11 15:08         ` Greg KH
  0 siblings, 1 reply; 54+ messages in thread
From: Thomas Gleixner @ 2011-01-11 14:56 UTC (permalink / raw)
  To: Daniel Hellstrom
  Cc: Linus Torvalds, Greg KH, David S. Miller, Ingo Molnar,
	Andrew Morton, linux-kernel, Alan Cox, Kay Sievers

On Tue, 11 Jan 2011, Daniel Hellstrom wrote:

> Greg KH wrote:
> 
> > On Fri, Jan 07, 2011 at 02:44:14PM -0800, Linus Torvalds wrote:
> >  
> > > On Thu, Jan 6, 2011 at 1:54 PM, Greg KH <gregkh@suse.de> wrote:
> > >    
> > > > Here is the big tty and serial merge for .38.  I'll be sending another
> > > > smaller one that just moves drivers around after .38-rc1 is out, as is
> > > > the norm for file moves to handle issues with other trees syncing up
> > > > properly.
> > > >      
> > > Merged. However, the drivers/serial/apbuart.c file conflicted, and
> > > both sides of the merge had some insanity in them.
> > > 
> > > So I did an "evil merge" - a merge that actually changed the code to
> > > match neither side - and it looks better to me. But maybe that's just
> > > the drugs I'm taking talking.
> > > 
> > > So people should check it out. In particular, look at the interaction
> > > of "drivers: serial: apbuart: Handle OF failures gracefully" and the
> > > "Added support for ampopts in APBUART driver. Used in AMP systems"
> > > commit.

Looks good.

Thanks,

	tglx

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

* Re: [GIT PATCH] TTY/serial merge for .38
  2011-01-11 14:56       ` Thomas Gleixner
@ 2011-01-11 15:08         ` Greg KH
  0 siblings, 0 replies; 54+ messages in thread
From: Greg KH @ 2011-01-11 15:08 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Daniel Hellstrom, Linus Torvalds, David S. Miller, Ingo Molnar,
	Andrew Morton, linux-kernel, Alan Cox, Kay Sievers

On Tue, Jan 11, 2011 at 03:56:19PM +0100, Thomas Gleixner wrote:
> On Tue, 11 Jan 2011, Daniel Hellstrom wrote:
> 
> > Greg KH wrote:
> > 
> > > On Fri, Jan 07, 2011 at 02:44:14PM -0800, Linus Torvalds wrote:
> > >  
> > > > On Thu, Jan 6, 2011 at 1:54 PM, Greg KH <gregkh@suse.de> wrote:
> > > >    
> > > > > Here is the big tty and serial merge for .38.  I'll be sending another
> > > > > smaller one that just moves drivers around after .38-rc1 is out, as is
> > > > > the norm for file moves to handle issues with other trees syncing up
> > > > > properly.
> > > > >      
> > > > Merged. However, the drivers/serial/apbuart.c file conflicted, and
> > > > both sides of the merge had some insanity in them.
> > > > 
> > > > So I did an "evil merge" - a merge that actually changed the code to
> > > > match neither side - and it looks better to me. But maybe that's just
> > > > the drugs I'm taking talking.
> > > > 
> > > > So people should check it out. In particular, look at the interaction
> > > > of "drivers: serial: apbuart: Handle OF failures gracefully" and the
> > > > "Added support for ampopts in APBUART driver. Used in AMP systems"
> > > > commit.
> 
> Looks good.

Great, thanks for testing.

greg k-h

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

end of thread, other threads:[~2011-01-11 15:21 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-06 21:54 [GIT PATCH] TTY/serial merge for .38 Greg KH
2011-01-06 22:00 ` Alan Cox
2011-01-06 22:24   ` Greg KH
2011-01-06 23:54     ` Kay Sievers
2011-01-07  3:40       ` Greg KH
2011-01-06 22:22 ` [PATCH 01/36] ifx6x60: SPI protocol driver for Infineon 6x60 modem Greg Kroah-Hartman
2011-01-06 22:22 ` [PATCH 02/36] serial: Add support for UART on VIA VT8500 and compatibles Greg Kroah-Hartman
2011-01-06 22:22 ` [PATCH 03/36] n_gsm: Fix support for legacy encoding Greg Kroah-Hartman
2011-01-06 22:22 ` [PATCH 04/36] n_gsm: clean up printks Greg Kroah-Hartman
2011-01-06 22:22 ` [PATCH 05/36] serial: add Documentation about RS485 serial communications Greg Kroah-Hartman
2011-01-06 22:22 ` [PATCH 06/36] serial: cpm_uat: reducing CPM serial latency Greg Kroah-Hartman
2011-01-06 22:22 ` [PATCH 07/36] serial: cpu_uart: Remove unused uart_cpm_port fields Greg Kroah-Hartman
2011-01-06 22:22 ` [PATCH 08/36] console: move for_each_console to linux/console.h Greg Kroah-Hartman
2011-01-06 22:22 ` [PATCH 09/36] TTY: include termios.h in tty_driver.h Greg Kroah-Hartman
2011-01-06 22:22 ` [PATCH 10/36] VIDEO: xen-fb, switch to for_each_console Greg Kroah-Hartman
2011-01-06 22:22   ` Greg Kroah-Hartman
2011-01-06 22:22   ` Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 11/36] console: add /proc/consoles Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 12/36] parisc: cleanup console handling Greg Kroah-Hartman
2011-01-06 22:23   ` Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 13/36] serial: mpc52xx: make printout for type more generic Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 14/36] serial: ifx6x60: The IFX requires SPI Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 15/36] serial: ifx6x60: Fix missing include for msleep Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 16/36] Serial: ce4100: Add PCI UART support for the ce4100 Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 17/36] Serial: EG20T: add PCH_UART driver Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 18/36] serial: ifx6x60: free IRQ on error Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 19/36] serial: ifx6x60: fix memory leak Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 20/36] RS485 documentation: add 16C950 UART description Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 21/36] drivers: char: hvc: add arm JTAG DCC console support Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 22/36] serial: fix pch_uart kconfig & build Greg Kroah-Hartman
2011-01-07  0:21   ` Tomoya MORINAGA
2011-01-07  0:31     ` Greg KH
2011-01-06 22:23 ` [PATCH 23/36] serial: omap-serial: Add support for kernel debugger Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 24/36] 8250: use container_of() instead of casting Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 25/36] 8250: add a UPIO_DWAPB32 for 32 bit accesses Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 26/36] rocket: fix compiler warning on rocket_pci_ids Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 27/36] specialix: fix compiler warning on specialix_pci_tbl Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 28/36] ip2: fix compiler warning on ip2main_pci_tbl Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 29/36] 8250: fix uninitialized FIFOs Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 30/36] pch_uart : fix warnings for 64bit compile Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 31/36] tty: fix typos/errors in tty_driver.h comments Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 32/36] Serial: Avoid unbalanced IRQ wake disable during resume Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 33/36] drivers: serial: apbuart: Handle OF failures gracefully Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 34/36] tty: add 'active' sysfs attribute to tty0 and console device Greg Kroah-Hartman
2011-01-07  9:09   ` Jiri Slaby
2011-01-07 13:20     ` Kay Sievers
2011-01-07 15:12       ` Jiri Slaby
2011-01-06 22:23 ` [PATCH 35/36] TTY: Add tty ioctl to figure device node of the system console Greg Kroah-Hartman
2011-01-06 22:23 ` [PATCH 36/36] serial: apbuart: Fixup apbuart_console_init() Greg Kroah-Hartman
2011-01-07 22:44 ` [GIT PATCH] TTY/serial merge for .38 Linus Torvalds
2011-01-07 23:41   ` Greg KH
2011-01-11 14:00     ` Daniel Hellstrom
2011-01-11 14:56       ` Thomas Gleixner
2011-01-11 15:08         ` Greg KH

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.