Browse Source

Merge tag 'tty-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull TTY updates from Greg Kroah-Hartman:
 "Here's the big TTY/serial driver pull request for the 3.5-rc1 merge
  window.

  Nothing major in here, just lots of incremental changes from Alan and
  Jiri reworking some tty core things to behave better and to get a more
  solid grasp on some of the nasty tty locking issues.

  There are a few tty and serial driver updates in here as well.

  All of this has been in the linux-next releases for a while with no
  problems.

  Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"

* tag 'tty-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (115 commits)
  serial: bfin_uart: Make MMR access compatible with 32 bits bf609 style controller.
  serial: bfin_uart: RTS and CTS MMRs can be either 16-bit width or 32-bit width.
  serial: bfin_uart: narrow the reboot condition in DMA tx interrupt
  serial: bfin_uart: Adapt bf5xx serial driver to bf60x serial4 controller.
  Revert "serial_core: Update buffer overrun statistics."
  tty: hvc_xen: NULL dereference on allocation failure
  tty: Fix LED error return
  tty: Allow uart_register/unregister/register
  tty: move global ldisc idle waitqueue to the individual ldisc
  serial8250-em: Add DT support
  serial8250-em: clk_get() IS_ERR() error handling fix
  serial_core: Update buffer overrun statistics.
  tty: drop the pty lock during hangup
  cris: fix missing tty arg in wait_event_interruptible_tty call
  tty/amiserial: Add missing argument for tty_unlock()
  tty_lock: Localise the lock
  pty: Lock the devpts bits privately
  tty_lock: undo the old tty_lock use on the ctty
  serial8250-em: Emma Mobile UART driver V2
  Add missing call to uart_update_timeout()
  ...
Linus Torvalds 13 years ago
parent
commit
94b5aff4c6
67 changed files with 1876 additions and 1956 deletions
  1. 0 8
      arch/arm/mach-omap2/serial.c
  2. 2 0
      arch/arm/mach-tegra/board-harmony.c
  3. 3 0
      arch/arm/mach-tegra/board-paz00.c
  4. 2 0
      arch/arm/mach-tegra/board-seaboard.c
  5. 2 0
      arch/arm/mach-tegra/board-trimslice.c
  6. 0 1
      arch/arm/plat-omap/include/plat/omap-serial.h
  7. 0 5
      drivers/isdn/i4l/isdn_common.c
  8. 179 287
      drivers/isdn/i4l/isdn_tty.c
  9. 44 61
      drivers/net/usb/hso.c
  10. 76 66
      drivers/s390/char/con3215.c
  11. 17 13
      drivers/s390/char/keyboard.c
  12. 11 3
      drivers/s390/char/keyboard.h
  13. 19 14
      drivers/s390/char/sclp_tty.c
  14. 15 18
      drivers/s390/char/sclp_vt220.c
  15. 56 65
      drivers/s390/char/tty3270.c
  16. 2 2
      drivers/staging/serial/68360serial.c
  17. 7 7
      drivers/tty/amiserial.c
  18. 22 22
      drivers/tty/bfin_jtag_comm.c
  19. 1 1
      drivers/tty/cyclades.c
  20. 46 50
      drivers/tty/hvc/hvc_console.c
  21. 1 3
      drivers/tty/hvc/hvc_console.h
  22. 2 2
      drivers/tty/hvc/hvc_xen.c
  23. 35 39
      drivers/tty/hvc/hvcs.c
  24. 54 74
      drivers/tty/hvc/hvsi.c
  25. 1 1
      drivers/tty/hvc/hvsi_lib.c
  26. 35 46
      drivers/tty/ipwireless/tty.c
  27. 1 1
      drivers/tty/mxser.c
  28. 6 5
      drivers/tty/n_r3964.c
  29. 5 4
      drivers/tty/n_tty.c
  30. 28 12
      drivers/tty/pty.c
  31. 152 231
      drivers/tty/serial/68328serial.c
  32. 0 186
      drivers/tty/serial/68328serial.h
  33. 150 162
      drivers/tty/serial/8250/8250.c
  34. 16 0
      drivers/tty/serial/8250/8250.h
  35. 186 0
      drivers/tty/serial/8250/8250_em.c
  36. 63 0
      drivers/tty/serial/8250/8250_pci.c
  37. 8 0
      drivers/tty/serial/8250/Kconfig
  38. 1 0
      drivers/tty/serial/8250/Makefile
  39. 18 91
      drivers/tty/serial/amba-pl011.c
  40. 27 47
      drivers/tty/serial/bfin_uart.c
  41. 6 30
      drivers/tty/serial/crisv10.c
  42. 2 0
      drivers/tty/serial/mxs-auart.c
  43. 26 0
      drivers/tty/serial/of_serial.c
  44. 73 1
      drivers/tty/serial/omap-serial.c
  45. 30 23
      drivers/tty/serial/pch_uart.c
  46. 1 0
      drivers/tty/serial/serial_core.c
  47. 2 2
      drivers/tty/synclink.c
  48. 2 2
      drivers/tty/synclink_gt.c
  49. 2 2
      drivers/tty/synclinkmp.c
  50. 65 20
      drivers/tty/tty_buffer.c
  51. 47 29
      drivers/tty/tty_io.c
  52. 19 18
      drivers/tty/tty_ldisc.c
  53. 45 15
      drivers/tty/tty_mutex.c
  54. 3 3
      drivers/tty/tty_port.c
  55. 91 32
      drivers/tty/vt/consolemap.c
  56. 32 36
      drivers/tty/vt/vt.c
  57. 5 20
      drivers/tty/vt/vt_ioctl.c
  58. 24 27
      drivers/usb/gadget/u_serial.c
  59. 2 62
      include/linux/generic_serial.h
  60. 2 24
      include/linux/isdn.h
  61. 17 0
      include/linux/of_serial.h
  62. 2 0
      include/linux/serial_8250.h
  63. 5 0
      include/linux/serial_core.h
  64. 14 9
      include/linux/tty.h
  65. 2 0
      include/linux/tty_ldisc.h
  66. 0 1
      include/linux/vt_kern.h
  67. 64 73
      net/bluetooth/rfcomm/tty.c

+ 0 - 8
arch/arm/mach-omap2/serial.c

@@ -245,14 +245,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
 	omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
 	omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
 	omap_up.autosuspend_timeout = info->autosuspend_timeout;
 	omap_up.autosuspend_timeout = info->autosuspend_timeout;
 
 
-	/* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */
-	if (!cpu_is_omap2420() && !cpu_is_ti816x())
-		omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS;
-
-	/* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */
-	if (cpu_is_omap34xx() || cpu_is_omap3630())
-		omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE;
-
 	pdata = &omap_up;
 	pdata = &omap_up;
 	pdata_size = sizeof(struct omap_uart_port_info);
 	pdata_size = sizeof(struct omap_uart_port_info);
 
 

+ 2 - 0
arch/arm/mach-tegra/board-harmony.c

@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/pda_power.h>
 #include <linux/pda_power.h>
@@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
 		.irq		= INT_UARTD,
 		.irq		= INT_UARTD,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.regshift	= 2,
 		.uartclk	= 216000000,
 		.uartclk	= 216000000,

+ 3 - 0
arch/arm/mach-tegra/board-paz00.c

@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio_keys.h>
@@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
 		.irq		= INT_UARTA,
 		.irq		= INT_UARTA,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.regshift	= 2,
 		.uartclk	= 216000000,
 		.uartclk	= 216000000,
@@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
 		.irq		= INT_UARTC,
 		.irq		= INT_UARTC,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.regshift	= 2,
 		.uartclk	= 216000000,
 		.uartclk	= 216000000,

+ 2 - 0
arch/arm/mach-tegra/board-seaboard.c

@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/input.h>
@@ -48,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
 		/* Memory and IRQ filled in before registration */
 		/* Memory and IRQ filled in before registration */
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.regshift	= 2,
 		.uartclk	= 216000000,
 		.uartclk	= 216000000,

+ 2 - 0
arch/arm/mach-tegra/board-trimslice.c

@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_8250.h>
+#include <linux/of_serial.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
@@ -49,6 +50,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
 		.irq		= INT_UARTA,
 		.irq		= INT_UARTA,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.flags		= UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
 		.type		= PORT_TEGRA,
 		.type		= PORT_TEGRA,
+		.handle_break	= tegra_serial_handle_break,
 		.iotype		= UPIO_MEM,
 		.iotype		= UPIO_MEM,
 		.regshift	= 2,
 		.regshift	= 2,
 		.uartclk	= 216000000,
 		.uartclk	= 216000000,

+ 0 - 1
arch/arm/plat-omap/include/plat/omap-serial.h

@@ -65,7 +65,6 @@ struct omap_uart_port_info {
 	bool			dma_enabled;	/* To specify DMA Mode */
 	bool			dma_enabled;	/* To specify DMA Mode */
 	unsigned int		uartclk;	/* UART clock rate */
 	unsigned int		uartclk;	/* UART clock rate */
 	upf_t			flags;		/* UPF_* flags */
 	upf_t			flags;		/* UPF_* flags */
-	u32			errata;
 	unsigned int		dma_rx_buf_size;
 	unsigned int		dma_rx_buf_size;
 	unsigned int		dma_rx_timeout;
 	unsigned int		dma_rx_timeout;
 	unsigned int		autosuspend_timeout;
 	unsigned int		autosuspend_timeout;

+ 0 - 5
drivers/isdn/i4l/isdn_common.c

@@ -46,7 +46,6 @@ static DEFINE_MUTEX(isdn_mutex);
 static char *isdn_revision = "$Revision: 1.1.2.3 $";
 static char *isdn_revision = "$Revision: 1.1.2.3 $";
 
 
 extern char *isdn_net_revision;
 extern char *isdn_net_revision;
-extern char *isdn_tty_revision;
 #ifdef CONFIG_ISDN_PPP
 #ifdef CONFIG_ISDN_PPP
 extern char *isdn_ppp_revision;
 extern char *isdn_ppp_revision;
 #else
 #else
@@ -2327,8 +2326,6 @@ static int __init isdn_init(void)
 		dev->chanmap[i] = -1;
 		dev->chanmap[i] = -1;
 		dev->m_idx[i] = -1;
 		dev->m_idx[i] = -1;
 		strcpy(dev->num[i], "???");
 		strcpy(dev->num[i], "???");
-		init_waitqueue_head(&dev->mdm.info[i].open_wait);
-		init_waitqueue_head(&dev->mdm.info[i].close_wait);
 	}
 	}
 	if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
 	if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
 		printk(KERN_WARNING "isdn: Could not register control devices\n");
 		printk(KERN_WARNING "isdn: Could not register control devices\n");
@@ -2353,8 +2350,6 @@ static int __init isdn_init(void)
 
 
 	strcpy(tmprev, isdn_revision);
 	strcpy(tmprev, isdn_revision);
 	printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
 	printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
-	strcpy(tmprev, isdn_tty_revision);
-	printk("%s/", isdn_getrev(tmprev));
 	strcpy(tmprev, isdn_net_revision);
 	strcpy(tmprev, isdn_net_revision);
 	printk("%s/", isdn_getrev(tmprev));
 	printk("%s/", isdn_getrev(tmprev));
 	strcpy(tmprev, isdn_ppp_revision);
 	strcpy(tmprev, isdn_ppp_revision);

+ 179 - 287
drivers/isdn/i4l/isdn_tty.c

@@ -1,5 +1,4 @@
-/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
+/*
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
  *
  * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
@@ -12,6 +11,7 @@
 #undef ISDN_TTY_STAT_DEBUG
 #undef ISDN_TTY_STAT_DEBUG
 
 
 #include <linux/isdn.h>
 #include <linux/isdn.h>
+#include <linux/serial.h> /* ASYNC_* flags */
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
@@ -48,9 +48,6 @@ static int bit2si[8] =
 static int si2bit[8] =
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 {4, 1, 4, 4, 4, 4, 4, 4};
 
 
-char *isdn_tty_revision = "$Revision: 1.1.2.3 $";
-
-
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
  * to stuff incoming data directly into a tty's flip-buffer. This
  * to stuff incoming data directly into a tty's flip-buffer. This
  * is done to speed up tty-receiving if the receive-queue is empty.
  * is done to speed up tty-receiving if the receive-queue is empty.
@@ -68,49 +65,54 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
 	struct tty_struct *tty;
 	struct tty_struct *tty;
 	char last;
 	char last;
 
 
-	if (info->online) {
-		if ((tty = info->tty)) {
-			if (info->mcr & UART_MCR_RTS) {
-				len = skb->len
+	if (!info->online)
+		return 0;
+
+	tty = info->port.tty;
+	if (!tty)
+		return 0;
+
+	if (!(info->mcr & UART_MCR_RTS))
+		return 0;
+
+	len = skb->len
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
-					+ ISDN_AUDIO_SKB_DLECOUNT(skb)
+		+ ISDN_AUDIO_SKB_DLECOUNT(skb)
 #endif
 #endif
-					;
+		;
+
+	c = tty_buffer_request_room(tty, len);
+	if (c < len)
+		return 0;
 
 
-				c = tty_buffer_request_room(tty, len);
-				if (c >= len) {
-#ifdef CONFIG_ISDN_AUDIO
-					if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
-						int l = skb->len;
-						unsigned char *dp = skb->data;
-						while (--l) {
-							if (*dp == DLE)
-								tty_insert_flip_char(tty, DLE, 0);
-							tty_insert_flip_char(tty, *dp++, 0);
-						}
-						if (*dp == DLE)
-							tty_insert_flip_char(tty, DLE, 0);
-						last = *dp;
-					} else {
-#endif
-						if (len > 1)
-							tty_insert_flip_string(tty, skb->data, len - 1);
-						last = skb->data[len - 1];
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
-					}
+	if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
+		int l = skb->len;
+		unsigned char *dp = skb->data;
+		while (--l) {
+			if (*dp == DLE)
+				tty_insert_flip_char(tty, DLE, 0);
+			tty_insert_flip_char(tty, *dp++, 0);
+		}
+		if (*dp == DLE)
+			tty_insert_flip_char(tty, DLE, 0);
+		last = *dp;
+	} else {
 #endif
 #endif
-					if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
-						tty_insert_flip_char(tty, last, 0xFF);
-					else
-						tty_insert_flip_char(tty, last, TTY_NORMAL);
-					tty_flip_buffer_push(tty);
-					kfree_skb(skb);
-					return 1;
-				}
-			}
-		}
+		if (len > 1)
+			tty_insert_flip_string(tty, skb->data, len - 1);
+		last = skb->data[len - 1];
+#ifdef CONFIG_ISDN_AUDIO
 	}
 	}
-	return 0;
+#endif
+	if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
+		tty_insert_flip_char(tty, last, 0xFF);
+	else
+		tty_insert_flip_char(tty, last, TTY_NORMAL);
+	tty_flip_buffer_push(tty);
+	kfree_skb(skb);
+
+	return 1;
 }
 }
 
 
 /* isdn_tty_readmodem() is called periodically from within timer-interrupt.
 /* isdn_tty_readmodem() is called periodically from within timer-interrupt.
@@ -128,35 +130,39 @@ isdn_tty_readmodem(void)
 	modem_info *info;
 	modem_info *info;
 
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		if ((midx = dev->m_idx[i]) >= 0) {
-			info = &dev->mdm.info[midx];
-			if (info->online) {
-				r = 0;
+		midx = dev->m_idx[i];
+		if (midx < 0)
+			continue;
+
+		info = &dev->mdm.info[midx];
+		if (!info->online)
+			continue;
+
+		r = 0;
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
-				isdn_audio_eval_dtmf(info);
-				if ((info->vonline & 1) && (info->emu.vpar[1]))
-					isdn_audio_eval_silence(info);
-#endif
-				if ((tty = info->tty)) {
-					if (info->mcr & UART_MCR_RTS) {
-						/* CISCO AsyncPPP Hack */
-						if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
-							r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
-						else
-							r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
-						if (r)
-							tty_flip_buffer_push(tty);
-					} else
-						r = 1;
-				} else
-					r = 1;
-				if (r) {
-					info->rcvsched = 0;
-					resched = 1;
-				} else
-					info->rcvsched = 1;
-			}
-		}
+		isdn_audio_eval_dtmf(info);
+		if ((info->vonline & 1) && (info->emu.vpar[1]))
+			isdn_audio_eval_silence(info);
+#endif
+		tty = info->port.tty;
+		if (tty) {
+			if (info->mcr & UART_MCR_RTS) {
+				/* CISCO AsyncPPP Hack */
+				if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
+					r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
+				else
+					r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
+				if (r)
+					tty_flip_buffer_push(tty);
+			} else
+				r = 1;
+		} else
+			r = 1;
+		if (r) {
+			info->rcvsched = 0;
+			resched = 1;
+		} else
+			info->rcvsched = 1;
 	}
 	}
 	if (!resched)
 	if (!resched)
 		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
 		isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
@@ -294,7 +300,7 @@ isdn_tty_tint(modem_info *info)
 	len = skb->len;
 	len = skb->len;
 	if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
 	if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
 					   info->isdn_channel, 1, skb)) == len) {
 					   info->isdn_channel, 1, skb)) == len) {
-		struct tty_struct *tty = info->tty;
+		struct tty_struct *tty = info->port.tty;
 		info->send_outstanding++;
 		info->send_outstanding++;
 		info->msr &= ~UART_MSR_CTS;
 		info->msr &= ~UART_MSR_CTS;
 		info->lsr &= ~UART_LSR_TEMT;
 		info->lsr &= ~UART_LSR_TEMT;
@@ -327,7 +333,7 @@ isdn_tty_countDLE(unsigned char *buf, int len)
 static int
 static int
 isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
 isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
 {
 {
-	unsigned char *p = &info->xmit_buf[info->xmit_count];
+	unsigned char *p = &info->port.xmit_buf[info->xmit_count];
 	int count = 0;
 	int count = 0;
 
 
 	while (len > 0) {
 	while (len > 0) {
@@ -471,7 +477,7 @@ isdn_tty_senddown(modem_info *info)
 		return;
 		return;
 	}
 	}
 	skb_reserve(skb, skb_res);
 	skb_reserve(skb, skb_res);
-	memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
+	memcpy(skb_put(skb, buflen), info->port.xmit_buf, buflen);
 	info->xmit_count = 0;
 	info->xmit_count = 0;
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
 	if (info->vonline & 2) {
 	if (info->vonline & 2) {
@@ -699,7 +705,7 @@ isdn_tty_modem_hup(modem_info *info, int local)
 	printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
 	printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
 #endif
 #endif
 	info->rcvsched = 0;
 	info->rcvsched = 0;
-	isdn_tty_flush_buffer(info->tty);
+	isdn_tty_flush_buffer(info->port.tty);
 	if (info->online) {
 	if (info->online) {
 		info->last_lhup = local;
 		info->last_lhup = local;
 		info->online = 0;
 		info->online = 0;
@@ -997,20 +1003,21 @@ isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
 static void
 static void
 isdn_tty_change_speed(modem_info *info)
 isdn_tty_change_speed(modem_info *info)
 {
 {
+	struct tty_port *port = &info->port;
 	uint cflag,
 	uint cflag,
 		cval,
 		cval,
 		quot;
 		quot;
 	int i;
 	int i;
 
 
-	if (!info->tty || !info->tty->termios)
+	if (!port->tty || !port->tty->termios)
 		return;
 		return;
-	cflag = info->tty->termios->c_cflag;
+	cflag = port->tty->termios->c_cflag;
 
 
 	quot = i = cflag & CBAUD;
 	quot = i = cflag & CBAUD;
 	if (i & CBAUDEX) {
 	if (i & CBAUDEX) {
 		i &= ~CBAUDEX;
 		i &= ~CBAUDEX;
 		if (i < 1 || i > 2)
 		if (i < 1 || i > 2)
-			info->tty->termios->c_cflag &= ~CBAUDEX;
+			port->tty->termios->c_cflag &= ~CBAUDEX;
 		else
 		else
 			i += 15;
 			i += 15;
 	}
 	}
@@ -1040,20 +1047,20 @@ isdn_tty_change_speed(modem_info *info)
 
 
 	/* CTS flow control flag and modem status interrupts */
 	/* CTS flow control flag and modem status interrupts */
 	if (cflag & CRTSCTS) {
 	if (cflag & CRTSCTS) {
-		info->flags |= ISDN_ASYNC_CTS_FLOW;
+		port->flags |= ASYNC_CTS_FLOW;
 	} else
 	} else
-		info->flags &= ~ISDN_ASYNC_CTS_FLOW;
+		port->flags &= ~ASYNC_CTS_FLOW;
 	if (cflag & CLOCAL)
 	if (cflag & CLOCAL)
-		info->flags &= ~ISDN_ASYNC_CHECK_CD;
+		port->flags &= ~ASYNC_CHECK_CD;
 	else {
 	else {
-		info->flags |= ISDN_ASYNC_CHECK_CD;
+		port->flags |= ASYNC_CHECK_CD;
 	}
 	}
 }
 }
 
 
 static int
 static int
 isdn_tty_startup(modem_info *info)
 isdn_tty_startup(modem_info *info)
 {
 {
-	if (info->flags & ISDN_ASYNC_INITIALIZED)
+	if (info->port.flags & ASYNC_INITIALIZED)
 		return 0;
 		return 0;
 	isdn_lock_drivers();
 	isdn_lock_drivers();
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1063,14 +1070,14 @@ isdn_tty_startup(modem_info *info)
 	 * Now, initialize the UART
 	 * Now, initialize the UART
 	 */
 	 */
 	info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
 	info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
 	/*
 	/*
 	 * and set the speed of the serial port
 	 * and set the speed of the serial port
 	 */
 	 */
 	isdn_tty_change_speed(info);
 	isdn_tty_change_speed(info);
 
 
-	info->flags |= ISDN_ASYNC_INITIALIZED;
+	info->port.flags |= ASYNC_INITIALIZED;
 	info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
 	info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
 	info->send_outstanding = 0;
 	info->send_outstanding = 0;
 	return 0;
 	return 0;
@@ -1083,14 +1090,14 @@ isdn_tty_startup(modem_info *info)
 static void
 static void
 isdn_tty_shutdown(modem_info *info)
 isdn_tty_shutdown(modem_info *info)
 {
 {
-	if (!(info->flags & ISDN_ASYNC_INITIALIZED))
+	if (!(info->port.flags & ASYNC_INITIALIZED))
 		return;
 		return;
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
 	printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
 #endif
 #endif
 	isdn_unlock_drivers();
 	isdn_unlock_drivers();
 	info->msr &= ~UART_MSR_RI;
 	info->msr &= ~UART_MSR_RI;
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
 		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
 		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
 		if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
 		if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
 			isdn_tty_modem_reset_regs(info, 0);
 			isdn_tty_modem_reset_regs(info, 0);
@@ -1100,10 +1107,10 @@ isdn_tty_shutdown(modem_info *info)
 			isdn_tty_modem_hup(info, 1);
 			isdn_tty_modem_hup(info, 1);
 		}
 		}
 	}
 	}
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->port.tty)
+		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
 
 
-	info->flags &= ~ISDN_ASYNC_INITIALIZED;
+	info->port.flags &= ~ASYNC_INITIALIZED;
 }
 }
 
 
 /* isdn_tty_write() is the main send-routine. It is called from the upper
 /* isdn_tty_write() is the main send-routine. It is called from the upper
@@ -1146,7 +1153,7 @@ isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count)
 				isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
 				isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
 						   &(m->pluscount),
 						   &(m->pluscount),
 						   &(m->lastplus));
 						   &(m->lastplus));
-			memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
+			memcpy(&info->port.xmit_buf[info->xmit_count], buf, c);
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
 			if (info->vonline) {
 			if (info->vonline) {
 				int cc = isdn_tty_handleDLEdown(info, m, c);
 				int cc = isdn_tty_handleDLEdown(info, m, c);
@@ -1478,107 +1485,6 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
  * isdn_tty_open() and friends
  * isdn_tty_open() and friends
  * ------------------------------------------------------------
  * ------------------------------------------------------------
  */
  */
-static int
-isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *info)
-{
-	DECLARE_WAITQUEUE(wait, NULL);
-	int do_clocal = 0;
-	int retval;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ISDN_ASYNC_CLOSING)) {
-		if (info->flags & ISDN_ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef MODEM_DO_RESTART
-		if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-	/*
-	 * If non-blocking mode is set, then make the check up front
-	 * and then exit.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
-		info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
-	 * isdn_tty_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-#ifdef ISDN_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	if (!(tty_hung_up_p(filp)))
-		info->count--;
-	info->blocked_open++;
-	while (1) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ISDN_ASYNC_INITIALIZED)) {
-#ifdef MODEM_DO_RESTART
-			if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ISDN_ASYNC_CLOSING) &&
-		    (do_clocal || (info->msr & UART_MSR_DCD))) {
-			break;
-		}
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-#ifdef ISDN_DEBUG_MODEM_OPEN
-		printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n",
-		       info->line, info->count);
-#endif
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-#ifdef ISDN_DEBUG_MODEM_OPEN
-	printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	if (retval)
-		return retval;
-	info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
-	return 0;
-}
 
 
 /*
 /*
  * This routine is called whenever a serial port is opened.  It
  * This routine is called whenever a serial port is opened.  It
@@ -1589,23 +1495,22 @@ isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *
 static int
 static int
 isdn_tty_open(struct tty_struct *tty, struct file *filp)
 isdn_tty_open(struct tty_struct *tty, struct file *filp)
 {
 {
+	struct tty_port *port;
 	modem_info *info;
 	modem_info *info;
 	int retval;
 	int retval;
 
 
 	info = &dev->mdm.info[tty->index];
 	info = &dev->mdm.info[tty->index];
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
 		return -ENODEV;
 		return -ENODEV;
-	if (!try_module_get(info->owner)) {
-		printk(KERN_WARNING "%s: cannot reserve module\n", __func__);
-		return -ENODEV;
-	}
+	port = &info->port;
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
 	printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
-	       info->count);
+	       port->count);
 #endif
 #endif
-	info->count++;
+	port->count++;
 	tty->driver_data = info;
 	tty->driver_data = info;
-	info->tty = tty;
+	port->tty = tty;
+	tty->port = port;
 	/*
 	/*
 	 * Start up serial port
 	 * Start up serial port
 	 */
 	 */
@@ -1614,15 +1519,13 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp)
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
 		printk(KERN_DEBUG "isdn_tty_open return after startup\n");
 		printk(KERN_DEBUG "isdn_tty_open return after startup\n");
 #endif
 #endif
-		module_put(info->owner);
 		return retval;
 		return retval;
 	}
 	}
-	retval = isdn_tty_block_til_ready(tty, filp, info);
+	retval = tty_port_block_til_ready(port, tty, filp);
 	if (retval) {
 	if (retval) {
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
 		printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
 		printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
 #endif
 #endif
-		module_put(info->owner);
 		return retval;
 		return retval;
 	}
 	}
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1639,6 +1542,7 @@ static void
 isdn_tty_close(struct tty_struct *tty, struct file *filp)
 isdn_tty_close(struct tty_struct *tty, struct file *filp)
 {
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 	modem_info *info = (modem_info *) tty->driver_data;
+	struct tty_port *port = &info->port;
 	ulong timeout;
 	ulong timeout;
 
 
 	if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
 	if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
@@ -1649,7 +1553,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
 #endif
 #endif
 		return;
 		return;
 	}
 	}
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (port->count != 1)) {
 		/*
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * structure will be freed.  Info->count should always
 		 * structure will be freed.  Info->count should always
@@ -1658,30 +1562,21 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
 		 * serial port won't be shutdown.
 		 * serial port won't be shutdown.
 		 */
 		 */
 		printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
 		printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
-		       "info->count is %d\n", info->count);
-		info->count = 1;
+		       "info->count is %d\n", port->count);
+		port->count = 1;
 	}
 	}
-	if (--info->count < 0) {
+	if (--port->count < 0) {
 		printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
 		printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
-		       info->line, info->count);
-		info->count = 0;
+		       info->line, port->count);
+		port->count = 0;
 	}
 	}
-	if (info->count) {
+	if (port->count) {
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
 		printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
 		printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
 #endif
 #endif
-		module_put(info->owner);
 		return;
 		return;
 	}
 	}
-	info->flags |= ISDN_ASYNC_CLOSING;
-	/*
-	 * Save the termios structure, since this port may have
-	 * separate termios for callout and dialin.
-	 */
-	if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
-		info->normal_termios = *tty->termios;
-	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
+	port->flags |= ASYNC_CLOSING;
 
 
 	tty->closing = 1;
 	tty->closing = 1;
 	/*
 	/*
@@ -1690,7 +1585,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
 	 * interrupt driver to stop checking the data ready bit in the
 	 * interrupt driver to stop checking the data ready bit in the
 	 * line status register.
 	 * line status register.
 	 */
 	 */
-	if (info->flags & ISDN_ASYNC_INITIALIZED) {
+	if (port->flags & ASYNC_INITIALIZED) {
 		tty_wait_until_sent_from_close(tty, 3000);	/* 30 seconds timeout */
 		tty_wait_until_sent_from_close(tty, 3000);	/* 30 seconds timeout */
 		/*
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
 		 * Before we drop DTR, make sure the UART transmitter
@@ -1708,16 +1603,10 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
 	isdn_tty_shutdown(info);
 	isdn_tty_shutdown(info);
 	isdn_tty_flush_buffer(tty);
 	isdn_tty_flush_buffer(tty);
 	tty_ldisc_flush(tty);
 	tty_ldisc_flush(tty);
-	info->tty = NULL;
+	port->tty = NULL;
 	info->ncarrier = 0;
 	info->ncarrier = 0;
-	tty->closing = 0;
-	module_put(info->owner);
-	if (info->blocked_open) {
-		msleep_interruptible(500);
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
+
+	tty_port_close_end(port, tty);
 #ifdef ISDN_DEBUG_MODEM_OPEN
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "isdn_tty_close normal exit\n");
 	printk(KERN_DEBUG "isdn_tty_close normal exit\n");
 #endif
 #endif
@@ -1730,14 +1619,15 @@ static void
 isdn_tty_hangup(struct tty_struct *tty)
 isdn_tty_hangup(struct tty_struct *tty)
 {
 {
 	modem_info *info = (modem_info *) tty->driver_data;
 	modem_info *info = (modem_info *) tty->driver_data;
+	struct tty_port *port = &info->port;
 
 
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
 		return;
 		return;
 	isdn_tty_shutdown(info);
 	isdn_tty_shutdown(info);
-	info->count = 0;
-	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
+	port->count = 0;
+	port->flags &= ~ASYNC_NORMAL_ACTIVE;
+	port->tty = NULL;
+	wake_up_interruptible(&port->open_wait);
 }
 }
 
 
 /* This routine initializes all emulator-data.
 /* This routine initializes all emulator-data.
@@ -1864,6 +1754,16 @@ static const struct tty_operations modem_ops = {
 	.tiocmset = isdn_tty_tiocmset,
 	.tiocmset = isdn_tty_tiocmset,
 };
 };
 
 
+static int isdn_tty_carrier_raised(struct tty_port *port)
+{
+	modem_info *info = container_of(port, modem_info, port);
+	return info->msr & UART_MSR_DCD;
+}
+
+static const struct tty_port_operations isdn_tty_port_ops = {
+	.carrier_raised = isdn_tty_carrier_raised,
+};
+
 int
 int
 isdn_tty_modem_init(void)
 isdn_tty_modem_init(void)
 {
 {
@@ -1899,9 +1799,8 @@ isdn_tty_modem_init(void)
 			goto err_unregister;
 			goto err_unregister;
 		}
 		}
 #endif
 #endif
-#ifdef MODULE
-		info->owner = THIS_MODULE;
-#endif
+		tty_port_init(&info->port);
+		info->port.ops = &isdn_tty_port_ops;
 		spin_lock_init(&info->readlock);
 		spin_lock_init(&info->readlock);
 		sprintf(info->last_cause, "0000");
 		sprintf(info->last_cause, "0000");
 		sprintf(info->last_num, "none");
 		sprintf(info->last_num, "none");
@@ -1913,12 +1812,7 @@ isdn_tty_modem_init(void)
 		isdn_tty_modem_reset_regs(info, 1);
 		isdn_tty_modem_reset_regs(info, 1);
 		info->magic = ISDN_ASYNC_MAGIC;
 		info->magic = ISDN_ASYNC_MAGIC;
 		info->line = i;
 		info->line = i;
-		info->tty = NULL;
 		info->x_char = 0;
 		info->x_char = 0;
-		info->count = 0;
-		info->blocked_open = 0;
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
 		info->isdn_driver = -1;
 		info->isdn_driver = -1;
 		info->isdn_channel = -1;
 		info->isdn_channel = -1;
 		info->drv_index = -1;
 		info->drv_index = -1;
@@ -1930,13 +1824,15 @@ isdn_tty_modem_init(void)
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
 		skb_queue_head_init(&info->dtmf_queue);
 		skb_queue_head_init(&info->dtmf_queue);
 #endif
 #endif
-		if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
+		info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5,
+				GFP_KERNEL);
+		if (!info->port.xmit_buf) {
 			printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
 			printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
 			retval = -ENOMEM;
 			retval = -ENOMEM;
 			goto err_unregister;
 			goto err_unregister;
 		}
 		}
 		/* Make room for T.70 header */
 		/* Make room for T.70 header */
-		info->xmit_buf += 4;
+		info->port.xmit_buf += 4;
 	}
 	}
 	return 0;
 	return 0;
 err_unregister:
 err_unregister:
@@ -1945,7 +1841,7 @@ err_unregister:
 #ifdef CONFIG_ISDN_TTY_FAX
 #ifdef CONFIG_ISDN_TTY_FAX
 		kfree(info->fax);
 		kfree(info->fax);
 #endif
 #endif
-		kfree(info->xmit_buf - 4);
+		kfree(info->port.xmit_buf - 4);
 	}
 	}
 	tty_unregister_driver(m->tty_modem);
 	tty_unregister_driver(m->tty_modem);
 err:
 err:
@@ -1966,7 +1862,7 @@ isdn_tty_exit(void)
 #ifdef CONFIG_ISDN_TTY_FAX
 #ifdef CONFIG_ISDN_TTY_FAX
 		kfree(info->fax);
 		kfree(info->fax);
 #endif
 #endif
-		kfree(info->xmit_buf - 4);
+		kfree(info->port.xmit_buf - 4);
 	}
 	}
 	tty_unregister_driver(dev->mdm.tty_modem);
 	tty_unregister_driver(dev->mdm.tty_modem);
 	put_tty_driver(dev->mdm.tty_modem);
 	put_tty_driver(dev->mdm.tty_modem);
@@ -2068,7 +1964,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		modem_info *info = &dev->mdm.info[i];
 		modem_info *info = &dev->mdm.info[i];
 
 
-		if (info->count == 0)
+		if (info->port.count == 0)
 			continue;
 			continue;
 		if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) &&  /* SI1 is matching */
 		if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) &&  /* SI1 is matching */
 		    (info->emu.mdmreg[REG_SI2] == si2))	{         /* SI2 is matching */
 		    (info->emu.mdmreg[REG_SI2] == si2))	{         /* SI2 is matching */
@@ -2076,12 +1972,12 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
 #ifdef ISDN_DEBUG_MODEM_ICALL
 #ifdef ISDN_DEBUG_MODEM_ICALL
 			printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
 			printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
 			printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
 			printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
-			       info->flags, info->isdn_driver, info->isdn_channel,
-			       dev->usage[idx]);
+			       info->port.flags, info->isdn_driver,
+			       info->isdn_channel, dev->usage[idx]);
 #endif
 #endif
 			if (
 			if (
 #ifndef FIX_FILE_TRANSFER
 #ifndef FIX_FILE_TRANSFER
-				(info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
+				(info->port.flags & ASYNC_NORMAL_ACTIVE) &&
 #endif
 #endif
 				(info->isdn_driver == -1) &&
 				(info->isdn_driver == -1) &&
 				(info->isdn_channel == -1) &&
 				(info->isdn_channel == -1) &&
@@ -2120,8 +2016,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
 	return (wret == 2) ? 3 : 0;
 	return (wret == 2) ? 3 : 0;
 }
 }
 
 
-#define TTY_IS_ACTIVE(info)						\
-	(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
+#define TTY_IS_ACTIVE(info)	(info->port.flags & ASYNC_NORMAL_ACTIVE)
 
 
 int
 int
 isdn_tty_stat_callback(int i, isdn_ctrl *c)
 isdn_tty_stat_callback(int i, isdn_ctrl *c)
@@ -2212,9 +2107,9 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 			 * for incoming call of this device when
 			 * for incoming call of this device when
 			 * DCD follow the state of incoming carrier
 			 * DCD follow the state of incoming carrier
 			 */
 			 */
-			if (info->blocked_open &&
+			if (info->port.blocked_open &&
 			    (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
 			    (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
-				wake_up_interruptible(&info->open_wait);
+				wake_up_interruptible(&info->port.open_wait);
 			}
 			}
 
 
 			/* Schedule CONNECT-Message to any tty
 			/* Schedule CONNECT-Message to any tty
@@ -2222,7 +2117,8 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
 			 * set DCD-bit of its modem-status.
 			 * set DCD-bit of its modem-status.
 			 */
 			 */
 			if (TTY_IS_ACTIVE(info) ||
 			if (TTY_IS_ACTIVE(info) ||
-			    (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
+			    (info->port.blocked_open &&
+			     (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
 				info->msr |= UART_MSR_DCD;
 				info->msr |= UART_MSR_DCD;
 				info->emu.charge = 0;
 				info->emu.charge = 0;
 				if (info->dialing & 0xf)
 				if (info->dialing & 0xf)
@@ -2339,8 +2235,8 @@ isdn_tty_at_cout(char *msg, modem_info *info)
 	l = strlen(msg);
 	l = strlen(msg);
 
 
 	spin_lock_irqsave(&info->readlock, flags);
 	spin_lock_irqsave(&info->readlock, flags);
-	tty = info->tty;
-	if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
+	tty = info->port.tty;
+	if ((info->port.flags & ASYNC_CLOSING) || (!tty)) {
 		spin_unlock_irqrestore(&info->readlock, flags);
 		spin_unlock_irqrestore(&info->readlock, flags);
 		return;
 		return;
 	}
 	}
@@ -2490,15 +2386,15 @@ isdn_tty_modem_result(int code, modem_info *info)
 	case RESULT_NO_CARRIER:
 	case RESULT_NO_CARRIER:
 #ifdef ISDN_DEBUG_MODEM_HUP
 #ifdef ISDN_DEBUG_MODEM_HUP
 		printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
 		printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
-		       (info->flags & ISDN_ASYNC_CLOSING),
-		       (!info->tty));
+		       (info->port.flags & ASYNC_CLOSING),
+		       (!info->port.tty));
 #endif
 #endif
 		m->mdmreg[REG_RINGCNT] = 0;
 		m->mdmreg[REG_RINGCNT] = 0;
 		del_timer(&info->nc_timer);
 		del_timer(&info->nc_timer);
 		info->ncarrier = 0;
 		info->ncarrier = 0;
-		if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+		if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
 			return;
 			return;
-		}
+
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
 		if (info->vonline & 1) {
 		if (info->vonline & 1) {
 #ifdef ISDN_DEBUG_MODEM_VOICE
 #ifdef ISDN_DEBUG_MODEM_VOICE
@@ -2629,14 +2525,11 @@ isdn_tty_modem_result(int code, modem_info *info)
 		}
 		}
 	}
 	}
 	if (code == RESULT_NO_CARRIER) {
 	if (code == RESULT_NO_CARRIER) {
-		if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+		if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
 			return;
 			return;
-		}
-		if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
-		    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
-		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
-			tty_hangup(info->tty);
-		}
+
+		if (info->port.flags & ASYNC_CHECK_CD)
+			tty_hangup(info->port.tty);
 	}
 	}
 }
 }
 
 
@@ -3803,19 +3696,19 @@ isdn_tty_modem_escape(void)
 	int midx;
 	int midx;
 
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-		if (USG_MODEM(dev->usage[i]))
-			if ((midx = dev->m_idx[i]) >= 0) {
-				modem_info *info = &dev->mdm.info[midx];
-				if (info->online) {
-					ton = 1;
-					if ((info->emu.pluscount == 3) &&
-					    time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) {
-						info->emu.pluscount = 0;
-						info->online = 0;
-						isdn_tty_modem_result(RESULT_OK, info);
-					}
+		if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) {
+			modem_info *info = &dev->mdm.info[midx];
+			if (info->online) {
+				ton = 1;
+				if ((info->emu.pluscount == 3) &&
+				    time_after(jiffies,
+					    info->emu.lastplus + PLUSWAIT2)) {
+					info->emu.pluscount = 0;
+					info->online = 0;
+					isdn_tty_modem_result(RESULT_OK, info);
 				}
 				}
 			}
 			}
+		}
 	isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
 	isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
 }
 }
 
 
@@ -3873,15 +3766,14 @@ isdn_tty_carrier_timeout(void)
 
 
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		modem_info *info = &dev->mdm.info[i];
 		modem_info *info = &dev->mdm.info[i];
-		if (info->dialing) {
-			if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
-				info->dialing = 0;
-				isdn_tty_modem_result(RESULT_NO_CARRIER, info);
-				isdn_tty_modem_hup(info, 1);
-			}
-			else
-				ton = 1;
-		}
+		if (!info->dialing)
+			continue;
+		if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
+			info->dialing = 0;
+			isdn_tty_modem_result(RESULT_NO_CARRIER, info);
+			isdn_tty_modem_hup(info, 1);
+		} else
+			ton = 1;
 	}
 	}
 	isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
 	isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
 }
 }

+ 44 - 61
drivers/net/usb/hso.c

@@ -106,13 +106,6 @@
 
 
 #define MAX_RX_URBS			2
 #define MAX_RX_URBS			2
 
 
-static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty)
-{
-	if (tty)
-		return tty->driver_data;
-	return NULL;
-}
-
 /*****************************************************************************/
 /*****************************************************************************/
 /* Debugging functions                                                       */
 /* Debugging functions                                                       */
 /*****************************************************************************/
 /*****************************************************************************/
@@ -255,9 +248,8 @@ struct hso_serial {
 	u8 dtr_state;
 	u8 dtr_state;
 	unsigned tx_urb_used:1;
 	unsigned tx_urb_used:1;
 
 
+	struct tty_port port;
 	/* from usb_serial_port */
 	/* from usb_serial_port */
-	struct tty_struct *tty;
-	int open_count;
 	spinlock_t serial_lock;
 	spinlock_t serial_lock;
 
 
 	int (*write_data) (struct hso_serial *serial);
 	int (*write_data) (struct hso_serial *serial);
@@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios)
 static void _hso_serial_set_termios(struct tty_struct *tty,
 static void _hso_serial_set_termios(struct tty_struct *tty,
 				    struct ktermios *old)
 				    struct ktermios *old)
 {
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	struct ktermios *termios;
 	struct ktermios *termios;
 
 
 	if (!serial) {
 	if (!serial) {
@@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)
 	struct urb *urb;
 	struct urb *urb;
 
 
 	urb = serial->rx_urb[0];
 	urb = serial->rx_urb[0];
-	if (serial->open_count > 0) {
+	if (serial->port.count > 0) {
 		count = put_rxbuf_data(urb, serial);
 		count = put_rxbuf_data(urb, serial);
 		if (count == -1)
 		if (count == -1)
 			return;
 			return;
@@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
 	DUMP1(urb->transfer_buffer, urb->actual_length);
 	DUMP1(urb->transfer_buffer, urb->actual_length);
 
 
 	/* Anyone listening? */
 	/* Anyone listening? */
-	if (serial->open_count == 0)
+	if (serial->port.count == 0)
 		return;
 		return;
 
 
 	if (status == 0) {
 	if (status == 0) {
@@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial)
 
 
 static	void hso_unthrottle(struct tty_struct *tty)
 static	void hso_unthrottle(struct tty_struct *tty)
 {
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 
 
 	tasklet_hi_schedule(&serial->unthrottle_tasklet);
 	tasklet_hi_schedule(&serial->unthrottle_tasklet);
 }
 }
@@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
 	kref_get(&serial->parent->ref);
 	kref_get(&serial->parent->ref);
 
 
 	/* setup */
 	/* setup */
-	spin_lock_irq(&serial->serial_lock);
 	tty->driver_data = serial;
 	tty->driver_data = serial;
-	tty_kref_put(serial->tty);
-	serial->tty = tty_kref_get(tty);
-	spin_unlock_irq(&serial->serial_lock);
+	tty_port_tty_set(&serial->port, tty);
 
 
 	/* check for port already opened, if not set the termios */
 	/* check for port already opened, if not set the termios */
-	serial->open_count++;
-	if (serial->open_count == 1) {
+	serial->port.count++;
+	if (serial->port.count == 1) {
 		serial->rx_state = RX_IDLE;
 		serial->rx_state = RX_IDLE;
 		/* Force default termio settings */
 		/* Force default termio settings */
 		_hso_serial_set_termios(tty, NULL);
 		_hso_serial_set_termios(tty, NULL);
@@ -1324,7 +1313,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
 		result = hso_start_serial_device(serial->parent, GFP_KERNEL);
 		result = hso_start_serial_device(serial->parent, GFP_KERNEL);
 		if (result) {
 		if (result) {
 			hso_stop_serial_device(serial->parent);
 			hso_stop_serial_device(serial->parent);
-			serial->open_count--;
+			serial->port.count--;
 			kref_put(&serial->parent->ref, hso_serial_ref_free);
 			kref_put(&serial->parent->ref, hso_serial_ref_free);
 		}
 		}
 	} else {
 	} else {
@@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
 
 
 	/* reset the rts and dtr */
 	/* reset the rts and dtr */
 	/* do the actual close */
 	/* do the actual close */
-	serial->open_count--;
+	serial->port.count--;
 
 
-	if (serial->open_count <= 0) {
-		serial->open_count = 0;
-		spin_lock_irq(&serial->serial_lock);
-		if (serial->tty == tty) {
-			serial->tty->driver_data = NULL;
-			serial->tty = NULL;
-			tty_kref_put(tty);
-		}
-		spin_unlock_irq(&serial->serial_lock);
+	if (serial->port.count <= 0) {
+		serial->port.count = 0;
+		tty_port_tty_set(&serial->port, NULL);
 		if (!usb_gone)
 		if (!usb_gone)
 			hso_stop_serial_device(serial->parent);
 			hso_stop_serial_device(serial->parent);
 		tasklet_kill(&serial->unthrottle_tasklet);
 		tasklet_kill(&serial->unthrottle_tasklet);
@@ -1390,7 +1373,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
 static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
 static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
 			    int count)
 			    int count)
 {
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	int space, tx_bytes;
 	int space, tx_bytes;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -1422,7 +1405,7 @@ out:
 /* how much room is there for writing */
 /* how much room is there for writing */
 static int hso_serial_write_room(struct tty_struct *tty)
 static int hso_serial_write_room(struct tty_struct *tty)
 {
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	int room;
 	int room;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty)
 /* setup the term */
 /* setup the term */
 static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
 static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	if (old)
 	if (old)
@@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
 
 
 	/* the actual setup */
 	/* the actual setup */
 	spin_lock_irqsave(&serial->serial_lock, flags);
 	spin_lock_irqsave(&serial->serial_lock, flags);
-	if (serial->open_count)
+	if (serial->port.count)
 		_hso_serial_set_termios(tty, old);
 		_hso_serial_set_termios(tty, old);
 	else
 	else
 		tty->termios = old;
 		tty->termios = old;
@@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
 /* how many characters in the buffer */
 /* how many characters in the buffer */
 static int hso_serial_chars_in_buffer(struct tty_struct *tty)
 static int hso_serial_chars_in_buffer(struct tty_struct *tty)
 {
 {
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	int chars;
 	int chars;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty,
 		  struct serial_icounter_struct *icount)
 		  struct serial_icounter_struct *icount)
 {
 {
 	struct uart_icount cnow;
 	struct uart_icount cnow;
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	struct hso_tiocmget  *tiocmget = serial->tiocmget;
 	struct hso_tiocmget  *tiocmget = serial->tiocmget;
 
 
 	memset(icount, 0, sizeof(struct serial_icounter_struct));
 	memset(icount, 0, sizeof(struct serial_icounter_struct));
@@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty,
 static int hso_serial_tiocmget(struct tty_struct *tty)
 static int hso_serial_tiocmget(struct tty_struct *tty)
 {
 {
 	int retval;
 	int retval;
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	struct hso_tiocmget  *tiocmget;
 	struct hso_tiocmget  *tiocmget;
 	u16 UART_state_bitmap;
 	u16 UART_state_bitmap;
 
 
@@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
 	int val = 0;
 	int val = 0;
 	unsigned long flags;
 	unsigned long flags;
 	int if_num;
 	int if_num;
-	struct hso_serial *serial = get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 
 
 	/* sanity check */
 	/* sanity check */
 	if (!serial) {
 	if (!serial) {
@@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
 static int hso_serial_ioctl(struct tty_struct *tty,
 static int hso_serial_ioctl(struct tty_struct *tty,
 			    unsigned int cmd, unsigned long arg)
 			    unsigned int cmd, unsigned long arg)
 {
 {
-	struct hso_serial *serial =  get_serial_by_tty(tty);
+	struct hso_serial *serial = tty->driver_data;
 	int ret = 0;
 	int ret = 0;
 	D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
 	D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
 
 
@@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb)
 				D1("Pending read interrupt on port %d\n", i);
 				D1("Pending read interrupt on port %d\n", i);
 				spin_lock(&serial->serial_lock);
 				spin_lock(&serial->serial_lock);
 				if (serial->rx_state == RX_IDLE &&
 				if (serial->rx_state == RX_IDLE &&
-					serial->open_count > 0) {
+					serial->port.count > 0) {
 					/* Setup and send a ctrl req read on
 					/* Setup and send a ctrl req read on
 					 * port i */
 					 * port i */
 					if (!serial->rx_urb_filled[0]) {
 					if (!serial->rx_urb_filled[0]) {
@@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
 
 
 	spin_lock(&serial->serial_lock);
 	spin_lock(&serial->serial_lock);
 	serial->tx_urb_used = 0;
 	serial->tx_urb_used = 0;
-	tty = tty_kref_get(serial->tty);
 	spin_unlock(&serial->serial_lock);
 	spin_unlock(&serial->serial_lock);
 	if (status) {
 	if (status) {
 		handle_usb_error(status, __func__, serial->parent);
 		handle_usb_error(status, __func__, serial->parent);
-		tty_kref_put(tty);
 		return;
 		return;
 	}
 	}
 	hso_put_activity(serial->parent);
 	hso_put_activity(serial->parent);
+	tty = tty_port_tty_get(&serial->port);
 	if (tty) {
 	if (tty) {
 		tty_wakeup(tty);
 		tty_wakeup(tty);
 		tty_kref_put(tty);
 		tty_kref_put(tty);
@@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb)
 	struct hso_serial *serial = urb->context;
 	struct hso_serial *serial = urb->context;
 	struct usb_ctrlrequest *req;
 	struct usb_ctrlrequest *req;
 	int status = urb->status;
 	int status = urb->status;
-	struct tty_struct *tty;
 
 
 	/* sanity check */
 	/* sanity check */
 	if (!serial)
 	if (!serial)
@@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb)
 
 
 	spin_lock(&serial->serial_lock);
 	spin_lock(&serial->serial_lock);
 	serial->tx_urb_used = 0;
 	serial->tx_urb_used = 0;
-	tty = tty_kref_get(serial->tty);
 	spin_unlock(&serial->serial_lock);
 	spin_unlock(&serial->serial_lock);
 	if (status) {
 	if (status) {
 		handle_usb_error(status, __func__, serial->parent);
 		handle_usb_error(status, __func__, serial->parent);
-		tty_kref_put(tty);
 		return;
 		return;
 	}
 	}
 
 
@@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb)
 		put_rxbuf_data_and_resubmit_ctrl_urb(serial);
 		put_rxbuf_data_and_resubmit_ctrl_urb(serial);
 		spin_unlock(&serial->serial_lock);
 		spin_unlock(&serial->serial_lock);
 	} else {
 	} else {
+		struct tty_struct *tty = tty_port_tty_get(&serial->port);
 		hso_put_activity(serial->parent);
 		hso_put_activity(serial->parent);
-		if (tty)
+		if (tty) {
 			tty_wakeup(tty);
 			tty_wakeup(tty);
+			tty_kref_put(tty);
+		}
 		/* response to a write command */
 		/* response to a write command */
 		hso_kick_transmit(serial);
 		hso_kick_transmit(serial);
 	}
 	}
-	tty_kref_put(tty);
 }
 }
 
 
 /* handle RX data for serial port */
 /* handle RX data for serial port */
@@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
 		return -2;
 		return -2;
 	}
 	}
 
 
-	/* All callers to put_rxbuf_data hold serial_lock */
-	tty = tty_kref_get(serial->tty);
+	tty = tty_port_tty_get(&serial->port);
 
 
 	/* Push data to tty */
 	/* Push data to tty */
 	if (tty) {
 	if (tty) {
@@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
 			write_length_remaining -= curr_write_len;
 			write_length_remaining -= curr_write_len;
 			tty_flip_buffer_push(tty);
 			tty_flip_buffer_push(tty);
 		}
 		}
+		tty_kref_put(tty);
 	}
 	}
 	if (write_length_remaining == 0) {
 	if (write_length_remaining == 0) {
 		serial->curr_rx_urb_offset = 0;
 		serial->curr_rx_urb_offset = 0;
 		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
 		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
 	}
 	}
-	tty_kref_put(tty);
 	return write_length_remaining;
 	return write_length_remaining;
 }
 }
 
 
@@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
 	serial->minor = minor;
 	serial->minor = minor;
 	serial->magic = HSO_SERIAL_MAGIC;
 	serial->magic = HSO_SERIAL_MAGIC;
 	spin_lock_init(&serial->serial_lock);
 	spin_lock_init(&serial->serial_lock);
+	tty_port_init(&serial->port);
 	serial->num_rx_urbs = num_urbs;
 	serial->num_rx_urbs = num_urbs;
 
 
 	/* RX, allocate urb and initialize */
 	/* RX, allocate urb and initialize */
@@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface)
 	/* Start all serial ports */
 	/* Start all serial ports */
 	for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
 	for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
 		if (serial_table[i] && (serial_table[i]->interface == iface)) {
 		if (serial_table[i] && (serial_table[i]->interface == iface)) {
-			if (dev2ser(serial_table[i])->open_count) {
+			if (dev2ser(serial_table[i])->port.count) {
 				result =
 				result =
 				    hso_start_serial_device(serial_table[i], GFP_NOIO);
 				    hso_start_serial_device(serial_table[i], GFP_NOIO);
 				hso_kick_transmit(dev2ser(serial_table[i]));
 				hso_kick_transmit(dev2ser(serial_table[i]));
@@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface)
 		if (serial_table[i] &&
 		if (serial_table[i] &&
 		    (serial_table[i]->interface == interface)) {
 		    (serial_table[i]->interface == interface)) {
 			hso_dev = dev2ser(serial_table[i]);
 			hso_dev = dev2ser(serial_table[i]);
-			spin_lock_irq(&hso_dev->serial_lock);
-			tty = tty_kref_get(hso_dev->tty);
-			spin_unlock_irq(&hso_dev->serial_lock);
-			if (tty)
+			tty = tty_port_tty_get(&hso_dev->port);
+			if (tty) {
 				tty_hangup(tty);
 				tty_hangup(tty);
+				tty_kref_put(tty);
+			}
 			mutex_lock(&hso_dev->parent->mutex);
 			mutex_lock(&hso_dev->parent->mutex);
-			tty_kref_put(tty);
 			hso_dev->parent->usb_gone = 1;
 			hso_dev->parent->usb_gone = 1;
 			mutex_unlock(&hso_dev->parent->mutex);
 			mutex_unlock(&hso_dev->parent->mutex);
 			kref_put(&serial_table[i]->ref, hso_serial_ref_free);
 			kref_put(&serial_table[i]->ref, hso_serial_ref_free);
@@ -3313,7 +3293,6 @@ static int __init hso_init(void)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	/* fill in all needed values */
 	/* fill in all needed values */
-	tty_drv->magic = TTY_DRIVER_MAGIC;
 	tty_drv->driver_name = driver_name;
 	tty_drv->driver_name = driver_name;
 	tty_drv->name = tty_filename;
 	tty_drv->name = tty_filename;
 
 
@@ -3334,7 +3313,7 @@ static int __init hso_init(void)
 	if (result) {
 	if (result) {
 		printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
 		printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
 			__func__, result);
 			__func__, result);
-		return result;
+		goto err_free_tty;
 	}
 	}
 
 
 	/* register this module as an usb driver */
 	/* register this module as an usb driver */
@@ -3342,13 +3321,16 @@ static int __init hso_init(void)
 	if (result) {
 	if (result) {
 		printk(KERN_ERR "Could not register hso driver? error: %d\n",
 		printk(KERN_ERR "Could not register hso driver? error: %d\n",
 			result);
 			result);
-		/* cleanup serial interface */
-		tty_unregister_driver(tty_drv);
-		return result;
+		goto err_unreg_tty;
 	}
 	}
 
 
 	/* done */
 	/* done */
 	return 0;
 	return 0;
+err_unreg_tty:
+	tty_unregister_driver(tty_drv);
+err_free_tty:
+	put_tty_driver(tty_drv);
+	return result;
 }
 }
 
 
 static void __exit hso_exit(void)
 static void __exit hso_exit(void)
@@ -3356,6 +3338,7 @@ static void __exit hso_exit(void)
 	printk(KERN_INFO "hso: unloaded\n");
 	printk(KERN_INFO "hso: unloaded\n");
 
 
 	tty_unregister_driver(tty_drv);
 	tty_unregister_driver(tty_drv);
+	put_tty_driver(tty_drv);
 	/* deregister the usb driver */
 	/* deregister the usb driver */
 	usb_deregister(&hso_driver);
 	usb_deregister(&hso_driver);
 }
 }

+ 76 - 66
drivers/s390/char/con3215.c

@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/reboot.h>
 #include <linux/reboot.h>
+#include <linux/serial.h> /* ASYNC_* flags */
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <asm/ccwdev.h>
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
 #include <asm/cio.h>
@@ -44,14 +45,11 @@
 #define RAW3215_TIMEOUT	    HZ/10     /* time for delayed output */
 #define RAW3215_TIMEOUT	    HZ/10     /* time for delayed output */
 
 
 #define RAW3215_FIXED	    1	      /* 3215 console device is not be freed */
 #define RAW3215_FIXED	    1	      /* 3215 console device is not be freed */
-#define RAW3215_ACTIVE	    2	      /* set if the device is in use */
 #define RAW3215_WORKING	    4	      /* set if a request is being worked on */
 #define RAW3215_WORKING	    4	      /* set if a request is being worked on */
 #define RAW3215_THROTTLED   8	      /* set if reading is disabled */
 #define RAW3215_THROTTLED   8	      /* set if reading is disabled */
 #define RAW3215_STOPPED	    16	      /* set if writing is disabled */
 #define RAW3215_STOPPED	    16	      /* set if writing is disabled */
-#define RAW3215_CLOSING	    32	      /* set while in close process */
 #define RAW3215_TIMER_RUNS  64	      /* set if the output delay timer is on */
 #define RAW3215_TIMER_RUNS  64	      /* set if the output delay timer is on */
 #define RAW3215_FLUSHING    128	      /* set to flush buffer (no delay) */
 #define RAW3215_FLUSHING    128	      /* set to flush buffer (no delay) */
-#define RAW3215_FROZEN	    256	      /* set if 3215 is frozen for suspend */
 
 
 #define TAB_STOP_SIZE	    8	      /* tab stop size */
 #define TAB_STOP_SIZE	    8	      /* tab stop size */
 
 
@@ -76,6 +74,7 @@ struct raw3215_req {
 } __attribute__ ((aligned(8)));
 } __attribute__ ((aligned(8)));
 
 
 struct raw3215_info {
 struct raw3215_info {
+	struct tty_port port;
 	struct ccw_device *cdev;      /* device for tty driver */
 	struct ccw_device *cdev;      /* device for tty driver */
 	spinlock_t *lock;	      /* pointer to irq lock */
 	spinlock_t *lock;	      /* pointer to irq lock */
 	int flags;		      /* state flags */
 	int flags;		      /* state flags */
@@ -84,7 +83,6 @@ struct raw3215_info {
 	int head;		      /* first free byte in output buffer */
 	int head;		      /* first free byte in output buffer */
 	int count;		      /* number of bytes in output buffer */
 	int count;		      /* number of bytes in output buffer */
 	int written;		      /* number of bytes in write requests */
 	int written;		      /* number of bytes in write requests */
-	struct tty_struct *tty;	      /* pointer to tty structure if present */
 	struct raw3215_req *queued_read; /* pointer to queued read requests */
 	struct raw3215_req *queued_read; /* pointer to queued read requests */
 	struct raw3215_req *queued_write;/* pointer to queued write requests */
 	struct raw3215_req *queued_write;/* pointer to queued write requests */
 	struct tasklet_struct tlet;   /* tasklet to invoke tty_wakeup */
 	struct tasklet_struct tlet;   /* tasklet to invoke tty_wakeup */
@@ -293,7 +291,7 @@ static void raw3215_timeout(unsigned long __data)
 	if (raw->flags & RAW3215_TIMER_RUNS) {
 	if (raw->flags & RAW3215_TIMER_RUNS) {
 		del_timer(&raw->timer);
 		del_timer(&raw->timer);
 		raw->flags &= ~RAW3215_TIMER_RUNS;
 		raw->flags &= ~RAW3215_TIMER_RUNS;
-		if (!(raw->flags & RAW3215_FROZEN)) {
+		if (!(raw->port.flags & ASYNC_SUSPENDED)) {
 			raw3215_mk_write_req(raw);
 			raw3215_mk_write_req(raw);
 			raw3215_start_io(raw);
 			raw3215_start_io(raw);
 		}
 		}
@@ -309,7 +307,8 @@ static void raw3215_timeout(unsigned long __data)
  */
  */
 static inline void raw3215_try_io(struct raw3215_info *raw)
 static inline void raw3215_try_io(struct raw3215_info *raw)
 {
 {
-	if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN))
+	if (!(raw->port.flags & ASYNC_INITIALIZED) ||
+			(raw->port.flags & ASYNC_SUSPENDED))
 		return;
 		return;
 	if (raw->queued_read != NULL)
 	if (raw->queued_read != NULL)
 		raw3215_start_io(raw);
 		raw3215_start_io(raw);
@@ -324,10 +323,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
 			}
 			}
 		} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
 		} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
 			/* delay small writes */
 			/* delay small writes */
-			init_timer(&raw->timer);
 			raw->timer.expires = RAW3215_TIMEOUT + jiffies;
 			raw->timer.expires = RAW3215_TIMEOUT + jiffies;
-			raw->timer.data = (unsigned long) raw;
-			raw->timer.function = raw3215_timeout;
 			add_timer(&raw->timer);
 			add_timer(&raw->timer);
 			raw->flags |= RAW3215_TIMER_RUNS;
 			raw->flags |= RAW3215_TIMER_RUNS;
 		}
 		}
@@ -340,17 +336,21 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
 static void raw3215_wakeup(unsigned long data)
 static void raw3215_wakeup(unsigned long data)
 {
 {
 	struct raw3215_info *raw = (struct raw3215_info *) data;
 	struct raw3215_info *raw = (struct raw3215_info *) data;
-	tty_wakeup(raw->tty);
+	struct tty_struct *tty;
+
+	tty = tty_port_tty_get(&raw->port);
+	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 }
 
 
 /*
 /*
  * Try to start the next IO and wake up processes waiting on the tty.
  * Try to start the next IO and wake up processes waiting on the tty.
  */
  */
-static void raw3215_next_io(struct raw3215_info *raw)
+static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty)
 {
 {
 	raw3215_mk_write_req(raw);
 	raw3215_mk_write_req(raw);
 	raw3215_try_io(raw);
 	raw3215_try_io(raw);
-	if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
+	if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
 		tasklet_schedule(&raw->tlet);
 		tasklet_schedule(&raw->tlet);
 }
 }
 
 
@@ -368,10 +368,11 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
 
 
 	raw = dev_get_drvdata(&cdev->dev);
 	raw = dev_get_drvdata(&cdev->dev);
 	req = (struct raw3215_req *) intparm;
 	req = (struct raw3215_req *) intparm;
+	tty = tty_port_tty_get(&raw->port);
 	cstat = irb->scsw.cmd.cstat;
 	cstat = irb->scsw.cmd.cstat;
 	dstat = irb->scsw.cmd.dstat;
 	dstat = irb->scsw.cmd.dstat;
 	if (cstat != 0)
 	if (cstat != 0)
-		raw3215_next_io(raw);
+		raw3215_next_io(raw, tty);
 	if (dstat & 0x01) { /* we got a unit exception */
 	if (dstat & 0x01) { /* we got a unit exception */
 		dstat &= ~0x01;	 /* we can ignore it */
 		dstat &= ~0x01;	 /* we can ignore it */
 	}
 	}
@@ -381,13 +382,13 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
 			break;
 			break;
 		/* Attention interrupt, someone hit the enter key */
 		/* Attention interrupt, someone hit the enter key */
 		raw3215_mk_read_req(raw);
 		raw3215_mk_read_req(raw);
-		raw3215_next_io(raw);
+		raw3215_next_io(raw, tty);
 		break;
 		break;
 	case 0x08:
 	case 0x08:
 	case 0x0C:
 	case 0x0C:
 		/* Channel end interrupt. */
 		/* Channel end interrupt. */
 		if ((raw = req->info) == NULL)
 		if ((raw = req->info) == NULL)
-			return;		     /* That shouldn't happen ... */
+			goto put_tty;	     /* That shouldn't happen ... */
 		if (req->type == RAW3215_READ) {
 		if (req->type == RAW3215_READ) {
 			/* store residual count, then wait for device end */
 			/* store residual count, then wait for device end */
 			req->residual = irb->scsw.cmd.count;
 			req->residual = irb->scsw.cmd.count;
@@ -397,11 +398,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
 	case 0x04:
 	case 0x04:
 		/* Device end interrupt. */
 		/* Device end interrupt. */
 		if ((raw = req->info) == NULL)
 		if ((raw = req->info) == NULL)
-			return;		     /* That shouldn't happen ... */
-		if (req->type == RAW3215_READ && raw->tty != NULL) {
+			goto put_tty;	     /* That shouldn't happen ... */
+		if (req->type == RAW3215_READ && tty != NULL) {
 			unsigned int cchar;
 			unsigned int cchar;
 
 
-			tty = raw->tty;
 			count = 160 - req->residual;
 			count = 160 - req->residual;
 			EBCASC(raw->inbuf, count);
 			EBCASC(raw->inbuf, count);
 			cchar = ctrlchar_handle(raw->inbuf, count, tty);
 			cchar = ctrlchar_handle(raw->inbuf, count, tty);
@@ -411,7 +411,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
 
 
 			case CTRLCHAR_CTRL:
 			case CTRLCHAR_CTRL:
 				tty_insert_flip_char(tty, cchar, TTY_NORMAL);
 				tty_insert_flip_char(tty, cchar, TTY_NORMAL);
-				tty_flip_buffer_push(raw->tty);
+				tty_flip_buffer_push(tty);
 				break;
 				break;
 
 
 			case CTRLCHAR_NONE:
 			case CTRLCHAR_NONE:
@@ -424,7 +424,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
 				} else
 				} else
 					count -= 2;
 					count -= 2;
 				tty_insert_flip_string(tty, raw->inbuf, count);
 				tty_insert_flip_string(tty, raw->inbuf, count);
-				tty_flip_buffer_push(raw->tty);
+				tty_flip_buffer_push(tty);
 				break;
 				break;
 			}
 			}
 		} else if (req->type == RAW3215_WRITE) {
 		} else if (req->type == RAW3215_WRITE) {
@@ -439,7 +439,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
 		    raw->queued_read == NULL) {
 		    raw->queued_read == NULL) {
 			wake_up_interruptible(&raw->empty_wait);
 			wake_up_interruptible(&raw->empty_wait);
 		}
 		}
-		raw3215_next_io(raw);
+		raw3215_next_io(raw, tty);
 		break;
 		break;
 	default:
 	default:
 		/* Strange interrupt, I'll do my best to clean up */
 		/* Strange interrupt, I'll do my best to clean up */
@@ -451,9 +451,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
 			raw->flags &= ~RAW3215_WORKING;
 			raw->flags &= ~RAW3215_WORKING;
 			raw3215_free_req(req);
 			raw3215_free_req(req);
 		}
 		}
-		raw3215_next_io(raw);
+		raw3215_next_io(raw, tty);
 	}
 	}
-	return;
+put_tty:
+	tty_kref_put(tty);
 }
 }
 
 
 /*
 /*
@@ -487,7 +488,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
 		/* While console is frozen for suspend we have no other
 		/* While console is frozen for suspend we have no other
 		 * choice but to drop message from the buffer to make
 		 * choice but to drop message from the buffer to make
 		 * room for even more messages. */
 		 * room for even more messages. */
-		if (raw->flags & RAW3215_FROZEN) {
+		if (raw->port.flags & ASYNC_SUSPENDED) {
 			raw3215_drop_line(raw);
 			raw3215_drop_line(raw);
 			continue;
 			continue;
 		}
 		}
@@ -609,10 +610,10 @@ static int raw3215_startup(struct raw3215_info *raw)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (raw->flags & RAW3215_ACTIVE)
+	if (raw->port.flags & ASYNC_INITIALIZED)
 		return 0;
 		return 0;
 	raw->line_pos = 0;
 	raw->line_pos = 0;
-	raw->flags |= RAW3215_ACTIVE;
+	raw->port.flags |= ASYNC_INITIALIZED;
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	raw3215_try_io(raw);
 	raw3215_try_io(raw);
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -628,14 +629,15 @@ static void raw3215_shutdown(struct raw3215_info *raw)
 	DECLARE_WAITQUEUE(wait, current);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED))
+	if (!(raw->port.flags & ASYNC_INITIALIZED) ||
+			(raw->flags & RAW3215_FIXED))
 		return;
 		return;
 	/* Wait for outstanding requests, then free irq */
 	/* Wait for outstanding requests, then free irq */
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	if ((raw->flags & RAW3215_WORKING) ||
 	if ((raw->flags & RAW3215_WORKING) ||
 	    raw->queued_write != NULL ||
 	    raw->queued_write != NULL ||
 	    raw->queued_read != NULL) {
 	    raw->queued_read != NULL) {
-		raw->flags |= RAW3215_CLOSING;
+		raw->port.flags |= ASYNC_CLOSING;
 		add_wait_queue(&raw->empty_wait, &wait);
 		add_wait_queue(&raw->empty_wait, &wait);
 		set_current_state(TASK_INTERRUPTIBLE);
 		set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 		spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -643,11 +645,41 @@ static void raw3215_shutdown(struct raw3215_info *raw)
 		spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 		spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 		remove_wait_queue(&raw->empty_wait, &wait);
 		remove_wait_queue(&raw->empty_wait, &wait);
 		set_current_state(TASK_RUNNING);
 		set_current_state(TASK_RUNNING);
-		raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
+		raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING);
 	}
 	}
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 }
 }
 
 
+static struct raw3215_info *raw3215_alloc_info(void)
+{
+	struct raw3215_info *info;
+
+	info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
+	if (!info)
+		return NULL;
+
+	info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
+	info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
+	if (!info->buffer || !info->inbuf) {
+		kfree(info);
+		return NULL;
+	}
+
+	setup_timer(&info->timer, raw3215_timeout, (unsigned long)info);
+	init_waitqueue_head(&info->empty_wait);
+	tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info);
+	tty_port_init(&info->port);
+
+	return info;
+}
+
+static void raw3215_free_info(struct raw3215_info *raw)
+{
+	kfree(raw->inbuf);
+	kfree(raw->buffer);
+	kfree(raw);
+}
+
 static int raw3215_probe (struct ccw_device *cdev)
 static int raw3215_probe (struct ccw_device *cdev)
 {
 {
 	struct raw3215_info *raw;
 	struct raw3215_info *raw;
@@ -656,11 +688,15 @@ static int raw3215_probe (struct ccw_device *cdev)
 	/* Console is special. */
 	/* Console is special. */
 	if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
 	if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
 		return 0;
 		return 0;
-	raw = kmalloc(sizeof(struct raw3215_info) +
-		      RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
+
+	raw = raw3215_alloc_info();
 	if (raw == NULL)
 	if (raw == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
+	raw->cdev = cdev;
+	dev_set_drvdata(&cdev->dev, raw);
+	cdev->handler = raw3215_irq;
+
 	spin_lock(&raw3215_device_lock);
 	spin_lock(&raw3215_device_lock);
 	for (line = 0; line < NR_3215; line++) {
 	for (line = 0; line < NR_3215; line++) {
 		if (!raw3215[line]) {
 		if (!raw3215[line]) {
@@ -670,28 +706,10 @@ static int raw3215_probe (struct ccw_device *cdev)
 	}
 	}
 	spin_unlock(&raw3215_device_lock);
 	spin_unlock(&raw3215_device_lock);
 	if (line == NR_3215) {
 	if (line == NR_3215) {
-		kfree(raw);
+		raw3215_free_info(raw);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	raw->cdev = cdev;
-	raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
-	memset(raw, 0, sizeof(struct raw3215_info));
-	raw->buffer = kmalloc(RAW3215_BUFFER_SIZE,
-				       GFP_KERNEL|GFP_DMA);
-	if (raw->buffer == NULL) {
-		spin_lock(&raw3215_device_lock);
-		raw3215[line] = NULL;
-		spin_unlock(&raw3215_device_lock);
-		kfree(raw);
-		return -ENOMEM;
-	}
-	init_waitqueue_head(&raw->empty_wait);
-	tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
-
-	dev_set_drvdata(&cdev->dev, raw);
-	cdev->handler = raw3215_irq;
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -703,8 +721,7 @@ static void raw3215_remove (struct ccw_device *cdev)
 	raw = dev_get_drvdata(&cdev->dev);
 	raw = dev_get_drvdata(&cdev->dev);
 	if (raw) {
 	if (raw) {
 		dev_set_drvdata(&cdev->dev, NULL);
 		dev_set_drvdata(&cdev->dev, NULL);
-		kfree(raw->buffer);
-		kfree(raw);
+		raw3215_free_info(raw);
 	}
 	}
 }
 }
 
 
@@ -741,7 +758,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev)
 	raw = dev_get_drvdata(&cdev->dev);
 	raw = dev_get_drvdata(&cdev->dev);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
 	raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
-	raw->flags |= RAW3215_FROZEN;
+	raw->port.flags |= ASYNC_SUSPENDED;
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 	return 0;
 	return 0;
 }
 }
@@ -754,7 +771,7 @@ static int raw3215_pm_start(struct ccw_device *cdev)
 	/* Allow I/O again and flush output buffer. */
 	/* Allow I/O again and flush output buffer. */
 	raw = dev_get_drvdata(&cdev->dev);
 	raw = dev_get_drvdata(&cdev->dev);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
 	spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
-	raw->flags &= ~RAW3215_FROZEN;
+	raw->port.flags &= ~ASYNC_SUSPENDED;
 	raw->flags |= RAW3215_FLUSHING;
 	raw->flags |= RAW3215_FLUSHING;
 	raw3215_try_io(raw);
 	raw3215_try_io(raw);
 	raw->flags &= ~RAW3215_FLUSHING;
 	raw->flags &= ~RAW3215_FLUSHING;
@@ -827,7 +844,7 @@ static void con3215_flush(void)
 	unsigned long flags;
 	unsigned long flags;
 
 
 	raw = raw3215[0];  /* console 3215 is the first one */
 	raw = raw3215[0];  /* console 3215 is the first one */
-	if (raw->flags & RAW3215_FROZEN)
+	if (raw->port.flags & ASYNC_SUSPENDED)
 		/* The console is still frozen for suspend. */
 		/* The console is still frozen for suspend. */
 		if (ccw_device_force_console())
 		if (ccw_device_force_console())
 			/* Forcing didn't work, no panic message .. */
 			/* Forcing didn't work, no panic message .. */
@@ -897,23 +914,16 @@ static int __init con3215_init(void)
 	if (IS_ERR(cdev))
 	if (IS_ERR(cdev))
 		return -ENODEV;
 		return -ENODEV;
 
 
-	raw3215[0] = raw = (struct raw3215_info *)
-		kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
-	raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
-	raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
+	raw3215[0] = raw = raw3215_alloc_info();
 	raw->cdev = cdev;
 	raw->cdev = cdev;
 	dev_set_drvdata(&cdev->dev, raw);
 	dev_set_drvdata(&cdev->dev, raw);
 	cdev->handler = raw3215_irq;
 	cdev->handler = raw3215_irq;
 
 
 	raw->flags |= RAW3215_FIXED;
 	raw->flags |= RAW3215_FIXED;
-	init_waitqueue_head(&raw->empty_wait);
-	tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
 
 
 	/* Request the console irq */
 	/* Request the console irq */
 	if (raw3215_startup(raw) != 0) {
 	if (raw3215_startup(raw) != 0) {
-		kfree(raw->inbuf);
-		kfree(raw->buffer);
-		kfree(raw);
+		raw3215_free_info(raw);
 		raw3215[0] = NULL;
 		raw3215[0] = NULL;
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -940,7 +950,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp)
 		return -ENODEV;
 		return -ENODEV;
 
 
 	tty->driver_data = raw;
 	tty->driver_data = raw;
-	raw->tty = tty;
+	tty_port_tty_set(&raw->port, tty);
 
 
 	tty->low_latency = 0;  /* don't use bottom half for pushing chars */
 	tty->low_latency = 0;  /* don't use bottom half for pushing chars */
 	/*
 	/*
@@ -971,7 +981,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
 	raw3215_shutdown(raw);
 	raw3215_shutdown(raw);
 	tasklet_kill(&raw->tlet);
 	tasklet_kill(&raw->tlet);
 	tty->closing = 0;
 	tty->closing = 0;
-	raw->tty = NULL;
+	tty_port_tty_set(&raw->port, NULL);
 }
 }
 
 
 /*
 /*

+ 17 - 13
drivers/s390/char/keyboard.c

@@ -199,7 +199,7 @@ handle_diacr(struct kbd_data *kbd, unsigned int ch)
 	if (ch == ' ' || ch == d)
 	if (ch == ' ' || ch == d)
 		return d;
 		return d;
 
 
-	kbd_put_queue(kbd->tty, d);
+	kbd_put_queue(kbd->port, d);
 	return ch;
 	return ch;
 }
 }
 
 
@@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value)
 {
 {
 	if (kbd->diacr)
 	if (kbd->diacr)
 		value = handle_diacr(kbd, value);
 		value = handle_diacr(kbd, value);
-	kbd_put_queue(kbd->tty, value);
+	kbd_put_queue(kbd->port, value);
 }
 }
 
 
 /*
 /*
@@ -239,7 +239,7 @@ static void
 k_fn(struct kbd_data *kbd, unsigned char value)
 k_fn(struct kbd_data *kbd, unsigned char value)
 {
 {
 	if (kbd->func_table[value])
 	if (kbd->func_table[value])
-		kbd_puts_queue(kbd->tty, kbd->func_table[value]);
+		kbd_puts_queue(kbd->port, kbd->func_table[value]);
 }
 }
 
 
 static void
 static void
@@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value)
  * but we need only 16 bits here
  * but we need only 16 bits here
  */
  */
 static void
 static void
-to_utf8(struct tty_struct *tty, ushort c) 
+to_utf8(struct tty_port *port, ushort c)
 {
 {
 	if (c < 0x80)
 	if (c < 0x80)
 		/*  0******* */
 		/*  0******* */
-		kbd_put_queue(tty, c);
+		kbd_put_queue(port, c);
 	else if (c < 0x800) {
 	else if (c < 0x800) {
 		/* 110***** 10****** */
 		/* 110***** 10****** */
-		kbd_put_queue(tty, 0xc0 | (c >> 6));
-		kbd_put_queue(tty, 0x80 | (c & 0x3f));
+		kbd_put_queue(port, 0xc0 | (c >> 6));
+		kbd_put_queue(port, 0x80 | (c & 0x3f));
 	} else {
 	} else {
 		/* 1110**** 10****** 10****** */
 		/* 1110**** 10****** 10****** */
-		kbd_put_queue(tty, 0xe0 | (c >> 12));
-		kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f));
-		kbd_put_queue(tty, 0x80 | (c & 0x3f));
+		kbd_put_queue(port, 0xe0 | (c >> 12));
+		kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
+		kbd_put_queue(port, 0x80 | (c & 0x3f));
 	}
 	}
 }
 }
 
 
@@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
 	unsigned short keysym;
 	unsigned short keysym;
 	unsigned char type, value;
 	unsigned char type, value;
 
 
-	if (!kbd || !kbd->tty)
+	if (!kbd)
 		return;
 		return;
 
 
 	if (keycode >= 384)
 	if (keycode >= 384)
@@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
 #endif
 #endif
 		(*k_handler[type])(kbd, value);
 		(*k_handler[type])(kbd, value);
 	} else
 	} else
-		to_utf8(kbd->tty, keysym);
+		to_utf8(kbd->port, keysym);
 }
 }
 
 
 /*
 /*
@@ -457,6 +457,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
 
 
 int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
 int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
 {
 {
+	struct tty_struct *tty;
 	void __user *argp;
 	void __user *argp;
 	unsigned int ct;
 	unsigned int ct;
 	int perm;
 	int perm;
@@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
 	 */
-	perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
+	tty = tty_port_tty_get(kbd->port);
+	/* FIXME this test is pretty racy */
+	perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG);
+	tty_kref_put(tty);
 	switch (cmd) {
 	switch (cmd) {
 	case KDGKBTYPE:
 	case KDGKBTYPE:
 		return put_user(KB_101, (char __user *)argp);
 		return put_user(KB_101, (char __user *)argp);

+ 11 - 3
drivers/s390/char/keyboard.h

@@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *);
  */
  */
 
 
 struct kbd_data {
 struct kbd_data {
-	struct tty_struct *tty;
+	struct tty_port *port;
 	unsigned short **key_maps;
 	unsigned short **key_maps;
 	char **func_table;
 	char **func_table;
 	fn_handler_fn **fn_handler;
 	fn_handler_fn **fn_handler;
@@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
  * Helper Functions.
  * Helper Functions.
  */
  */
 static inline void
 static inline void
-kbd_put_queue(struct tty_struct *tty, int ch)
+kbd_put_queue(struct tty_port *port, int ch)
 {
 {
+	struct tty_struct *tty = tty_port_tty_get(port);
+	if (!tty)
+		return;
 	tty_insert_flip_char(tty, ch, 0);
 	tty_insert_flip_char(tty, ch, 0);
 	tty_schedule_flip(tty);
 	tty_schedule_flip(tty);
+	tty_kref_put(tty);
 }
 }
 
 
 static inline void
 static inline void
-kbd_puts_queue(struct tty_struct *tty, char *cp)
+kbd_puts_queue(struct tty_port *port, char *cp)
 {
 {
+	struct tty_struct *tty = tty_port_tty_get(port);
+	if (!tty)
+		return;
 	while (*cp)
 	while (*cp)
 		tty_insert_flip_char(tty, *cp++, 0);
 		tty_insert_flip_char(tty, *cp++, 0);
 	tty_schedule_flip(tty);
 	tty_schedule_flip(tty);
+	tty_kref_put(tty);
 }
 }

+ 19 - 14
drivers/s390/char/sclp_tty.c

@@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf;
 /* Timer for delayed output of console messages. */
 /* Timer for delayed output of console messages. */
 static struct timer_list sclp_tty_timer;
 static struct timer_list sclp_tty_timer;
 
 
-static struct tty_struct *sclp_tty;
+static struct tty_port sclp_port;
 static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
 static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
 static unsigned short int sclp_tty_chars_count;
 static unsigned short int sclp_tty_chars_count;
 
 
@@ -64,7 +64,7 @@ static int sclp_tty_columns = 80;
 static int
 static int
 sclp_tty_open(struct tty_struct *tty, struct file *filp)
 sclp_tty_open(struct tty_struct *tty, struct file *filp)
 {
 {
-	sclp_tty = tty;
+	tty_port_tty_set(&sclp_port, tty);
 	tty->driver_data = NULL;
 	tty->driver_data = NULL;
 	tty->low_latency = 0;
 	tty->low_latency = 0;
 	return 0;
 	return 0;
@@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
 {
 {
 	if (tty->count > 1)
 	if (tty->count > 1)
 		return;
 		return;
-	sclp_tty = NULL;
+	tty_port_tty_set(&sclp_port, NULL);
 }
 }
 
 
 /*
 /*
@@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty)
 static void
 static void
 sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
 sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
 {
 {
+	struct tty_struct *tty;
 	unsigned long flags;
 	unsigned long flags;
 	void *page;
 	void *page;
 
 
@@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
 		spin_unlock_irqrestore(&sclp_tty_lock, flags);
 		spin_unlock_irqrestore(&sclp_tty_lock, flags);
 	} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
 	} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
 	/* check if the tty needs a wake up call */
 	/* check if the tty needs a wake up call */
-	if (sclp_tty != NULL) {
-		tty_wakeup(sclp_tty);
+	tty = tty_port_tty_get(&sclp_port);
+	if (tty != NULL) {
+		tty_wakeup(tty);
+		tty_kref_put(tty);
 	}
 	}
 }
 }
 
 
@@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty)
 static void
 static void
 sclp_tty_input(unsigned char* buf, unsigned int count)
 sclp_tty_input(unsigned char* buf, unsigned int count)
 {
 {
+	struct tty_struct *tty = tty_port_tty_get(&sclp_port);
 	unsigned int cchar;
 	unsigned int cchar;
 
 
 	/*
 	/*
 	 * If this tty driver is currently closed
 	 * If this tty driver is currently closed
 	 * then throw the received input away.
 	 * then throw the received input away.
 	 */
 	 */
-	if (sclp_tty == NULL)
+	if (tty == NULL)
 		return;
 		return;
-	cchar = ctrlchar_handle(buf, count, sclp_tty);
+	cchar = ctrlchar_handle(buf, count, tty);
 	switch (cchar & CTRLCHAR_MASK) {
 	switch (cchar & CTRLCHAR_MASK) {
 	case CTRLCHAR_SYSRQ:
 	case CTRLCHAR_SYSRQ:
 		break;
 		break;
 	case CTRLCHAR_CTRL:
 	case CTRLCHAR_CTRL:
-		tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL);
-		tty_flip_buffer_push(sclp_tty);
+		tty_insert_flip_char(tty, cchar, TTY_NORMAL);
+		tty_flip_buffer_push(tty);
 		break;
 		break;
 	case CTRLCHAR_NONE:
 	case CTRLCHAR_NONE:
 		/* send (normal) input to line discipline */
 		/* send (normal) input to line discipline */
@@ -348,13 +352,14 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
 		    (strncmp((const char *) buf + count - 2, "^n", 2) &&
 		    (strncmp((const char *) buf + count - 2, "^n", 2) &&
 		     strncmp((const char *) buf + count - 2, "\252n", 2))) {
 		     strncmp((const char *) buf + count - 2, "\252n", 2))) {
 			/* add the auto \n */
 			/* add the auto \n */
-			tty_insert_flip_string(sclp_tty, buf, count);
-			tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL);
+			tty_insert_flip_string(tty, buf, count);
+			tty_insert_flip_char(tty, '\n', TTY_NORMAL);
 		} else
 		} else
-			tty_insert_flip_string(sclp_tty, buf, count - 2);
-		tty_flip_buffer_push(sclp_tty);
+			tty_insert_flip_string(tty, buf, count - 2);
+		tty_flip_buffer_push(tty);
 		break;
 		break;
 	}
 	}
+	tty_kref_put(tty);
 }
 }
 
 
 /*
 /*
@@ -543,7 +548,7 @@ sclp_tty_init(void)
 		sclp_tty_tolower = 1;
 		sclp_tty_tolower = 1;
 	}
 	}
 	sclp_tty_chars_count = 0;
 	sclp_tty_chars_count = 0;
-	sclp_tty = NULL;
+	tty_port_init(&sclp_port);
 
 
 	rc = sclp_register(&sclp_input_event);
 	rc = sclp_register(&sclp_input_event);
 	if (rc) {
 	if (rc) {

+ 15 - 18
drivers/s390/char/sclp_vt220.c

@@ -34,7 +34,6 @@
 #define SCLP_VT220_DEVICE_NAME		"ttysclp"
 #define SCLP_VT220_DEVICE_NAME		"ttysclp"
 #define SCLP_VT220_CONSOLE_NAME		"ttyS"
 #define SCLP_VT220_CONSOLE_NAME		"ttyS"
 #define SCLP_VT220_CONSOLE_INDEX	1	/* console=ttyS1 */
 #define SCLP_VT220_CONSOLE_INDEX	1	/* console=ttyS1 */
-#define SCLP_VT220_BUF_SIZE		80
 
 
 /* Representation of a single write request */
 /* Representation of a single write request */
 struct sclp_vt220_request {
 struct sclp_vt220_request {
@@ -56,8 +55,7 @@ struct sclp_vt220_sccb {
 /* Structures and data needed to register tty driver */
 /* Structures and data needed to register tty driver */
 static struct tty_driver *sclp_vt220_driver;
 static struct tty_driver *sclp_vt220_driver;
 
 
-/* The tty_struct that the kernel associated with us */
-static struct tty_struct *sclp_vt220_tty;
+static struct tty_port sclp_vt220_port;
 
 
 /* Lock to protect internal data from concurrent access */
 /* Lock to protect internal data from concurrent access */
 static spinlock_t sclp_vt220_lock;
 static spinlock_t sclp_vt220_lock;
@@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = {
 static void
 static void
 sclp_vt220_process_queue(struct sclp_vt220_request *request)
 sclp_vt220_process_queue(struct sclp_vt220_request *request)
 {
 {
+	struct tty_struct *tty;
 	unsigned long flags;
 	unsigned long flags;
 	void *page;
 	void *page;
 
 
@@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
 	if (request == NULL && sclp_vt220_flush_later)
 	if (request == NULL && sclp_vt220_flush_later)
 		sclp_vt220_emit_current();
 		sclp_vt220_emit_current();
 	/* Check if the tty needs a wake up call */
 	/* Check if the tty needs a wake up call */
-	if (sclp_vt220_tty != NULL) {
-		tty_wakeup(sclp_vt220_tty);
+	tty = tty_port_tty_get(&sclp_vt220_port);
+	if (tty) {
+		tty_wakeup(tty);
+		tty_kref_put(tty);
 	}
 	}
 }
 }
 
 
@@ -460,11 +461,12 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
 static void
 static void
 sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
 sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
 {
 {
+	struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
 	char *buffer;
 	char *buffer;
 	unsigned int count;
 	unsigned int count;
 
 
 	/* Ignore input if device is not open */
 	/* Ignore input if device is not open */
-	if (sclp_vt220_tty == NULL)
+	if (tty == NULL)
 		return;
 		return;
 
 
 	buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
 	buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
@@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
 		/* Send input to line discipline */
 		/* Send input to line discipline */
 		buffer++;
 		buffer++;
 		count--;
 		count--;
-		tty_insert_flip_string(sclp_vt220_tty, buffer, count);
-		tty_flip_buffer_push(sclp_vt220_tty);
+		tty_insert_flip_string(tty, buffer, count);
+		tty_flip_buffer_push(tty);
 		break;
 		break;
 	}
 	}
+	tty_kref_put(tty);
 }
 }
 
 
 /*
 /*
@@ -491,10 +494,7 @@ static int
 sclp_vt220_open(struct tty_struct *tty, struct file *filp)
 sclp_vt220_open(struct tty_struct *tty, struct file *filp)
 {
 {
 	if (tty->count == 1) {
 	if (tty->count == 1) {
-		sclp_vt220_tty = tty;
-		tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);
-		if (tty->driver_data == NULL)
-			return -ENOMEM;
+		tty_port_tty_set(&sclp_vt220_port, tty);
 		tty->low_latency = 0;
 		tty->low_latency = 0;
 		if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
 		if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
 			tty->winsize.ws_row = 24;
 			tty->winsize.ws_row = 24;
@@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
 static void
 static void
 sclp_vt220_close(struct tty_struct *tty, struct file *filp)
 sclp_vt220_close(struct tty_struct *tty, struct file *filp)
 {
 {
-	if (tty->count == 1) {
-		sclp_vt220_tty = NULL;
-		kfree(tty->driver_data);
-		tty->driver_data = NULL;
-	}
+	if (tty->count == 1)
+		tty_port_tty_set(&sclp_vt220_port, NULL);
 }
 }
 
 
 /*
 /*
@@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages)
 	INIT_LIST_HEAD(&sclp_vt220_empty);
 	INIT_LIST_HEAD(&sclp_vt220_empty);
 	INIT_LIST_HEAD(&sclp_vt220_outqueue);
 	INIT_LIST_HEAD(&sclp_vt220_outqueue);
 	init_timer(&sclp_vt220_timer);
 	init_timer(&sclp_vt220_timer);
+	tty_port_init(&sclp_vt220_port);
 	sclp_vt220_current_request = NULL;
 	sclp_vt220_current_request = NULL;
 	sclp_vt220_buffered_chars = 0;
 	sclp_vt220_buffered_chars = 0;
-	sclp_vt220_tty = NULL;
 	sclp_vt220_flush_later = 0;
 	sclp_vt220_flush_later = 0;
 
 
 	/* Allocate pages for output buffering */
 	/* Allocate pages for output buffering */

+ 56 - 65
drivers/s390/char/tty3270.c

@@ -61,7 +61,7 @@ struct tty3270_line {
  */
  */
 struct tty3270 {
 struct tty3270 {
 	struct raw3270_view view;
 	struct raw3270_view view;
-	struct tty_struct *tty;		/* Pointer to tty structure */
+	struct tty_port port;
 	void **freemem_pages;		/* Array of pages used for freemem. */
 	void **freemem_pages;		/* Array of pages used for freemem. */
 	struct list_head freemem;	/* List of free memory for strings. */
 	struct list_head freemem;	/* List of free memory for strings. */
 
 
@@ -324,9 +324,8 @@ tty3270_blank_line(struct tty3270 *tp)
 static void
 static void
 tty3270_write_callback(struct raw3270_request *rq, void *data)
 tty3270_write_callback(struct raw3270_request *rq, void *data)
 {
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
 
 
-	tp = (struct tty3270 *) rq->view;
 	if (rq->rc != 0) {
 	if (rq->rc != 0) {
 		/* Write wasn't successful. Refresh all. */
 		/* Write wasn't successful. Refresh all. */
 		tp->update_flags = TTY_UPDATE_ALL;
 		tp->update_flags = TTY_UPDATE_ALL;
@@ -450,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
 static void
 static void
 tty3270_rcl_backward(struct kbd_data *kbd)
 tty3270_rcl_backward(struct kbd_data *kbd)
 {
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 	struct string *s;
 	struct string *s;
 
 
-	tp = kbd->tty->driver_data;
 	spin_lock_bh(&tp->view.lock);
 	spin_lock_bh(&tp->view.lock);
 	if (tp->inattr == TF_INPUT) {
 	if (tp->inattr == TF_INPUT) {
 		if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
 		if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
@@ -478,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd)
 static void
 static void
 tty3270_exit_tty(struct kbd_data *kbd)
 tty3270_exit_tty(struct kbd_data *kbd)
 {
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 
 
-	tp = kbd->tty->driver_data;
 	raw3270_deactivate_view(&tp->view);
 	raw3270_deactivate_view(&tp->view);
 }
 }
 
 
@@ -490,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd)
 static void
 static void
 tty3270_scroll_forward(struct kbd_data *kbd)
 tty3270_scroll_forward(struct kbd_data *kbd)
 {
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 	int nr_up;
 	int nr_up;
 
 
-	tp = kbd->tty->driver_data;
 	spin_lock_bh(&tp->view.lock);
 	spin_lock_bh(&tp->view.lock);
 	nr_up = tp->nr_up - tp->view.rows + 2;
 	nr_up = tp->nr_up - tp->view.rows + 2;
 	if (nr_up < 0)
 	if (nr_up < 0)
@@ -513,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd)
 static void
 static void
 tty3270_scroll_backward(struct kbd_data *kbd)
 tty3270_scroll_backward(struct kbd_data *kbd)
 {
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 	int nr_up;
 	int nr_up;
 
 
-	tp = kbd->tty->driver_data;
 	spin_lock_bh(&tp->view.lock);
 	spin_lock_bh(&tp->view.lock);
 	nr_up = tp->nr_up + tp->view.rows - 2;
 	nr_up = tp->nr_up + tp->view.rows - 2;
 	if (nr_up + tp->view.rows - 2 > tp->nr_lines)
 	if (nr_up + tp->view.rows - 2 > tp->nr_lines)
@@ -537,11 +532,10 @@ static void
 tty3270_read_tasklet(struct raw3270_request *rrq)
 tty3270_read_tasklet(struct raw3270_request *rrq)
 {
 {
 	static char kreset_data = TW_KR;
 	static char kreset_data = TW_KR;
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
 	char *input;
 	char *input;
 	int len;
 	int len;
 
 
-	tp = (struct tty3270 *) rrq->view;
 	spin_lock_bh(&tp->view.lock);
 	spin_lock_bh(&tp->view.lock);
 	/*
 	/*
 	 * Two AID keys are special: For 0x7d (enter) the input line
 	 * Two AID keys are special: For 0x7d (enter) the input line
@@ -577,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
 	raw3270_request_add_data(tp->kreset, &kreset_data, 1);
 	raw3270_request_add_data(tp->kreset, &kreset_data, 1);
 	raw3270_start(&tp->view, tp->kreset);
 	raw3270_start(&tp->view, tp->kreset);
 
 
-	/* Emit input string. */
-	if (tp->tty) {
-		while (len-- > 0)
-			kbd_keycode(tp->kbd, *input++);
-		/* Emit keycode for AID byte. */
-		kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
-	}
+	while (len-- > 0)
+		kbd_keycode(tp->kbd, *input++);
+	/* Emit keycode for AID byte. */
+	kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
 
 
 	raw3270_request_reset(rrq);
 	raw3270_request_reset(rrq);
 	xchg(&tp->read, rrq);
 	xchg(&tp->read, rrq);
@@ -596,9 +587,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
 static void
 static void
 tty3270_read_callback(struct raw3270_request *rq, void *data)
 tty3270_read_callback(struct raw3270_request *rq, void *data)
 {
 {
+	struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
 	raw3270_get_view(rq->view);
 	raw3270_get_view(rq->view);
 	/* Schedule tasklet to pass input to tty. */
 	/* Schedule tasklet to pass input to tty. */
-	tasklet_schedule(&((struct tty3270 *) rq->view)->readlet);
+	tasklet_schedule(&tp->readlet);
 }
 }
 
 
 /*
 /*
@@ -635,9 +627,8 @@ tty3270_issue_read(struct tty3270 *tp, int lock)
 static int
 static int
 tty3270_activate(struct raw3270_view *view)
 tty3270_activate(struct raw3270_view *view)
 {
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(view, struct tty3270, view);
 
 
-	tp = (struct tty3270 *) view;
 	tp->update_flags = TTY_UPDATE_ALL;
 	tp->update_flags = TTY_UPDATE_ALL;
 	tty3270_set_timer(tp, 1);
 	tty3270_set_timer(tp, 1);
 	return 0;
 	return 0;
@@ -646,9 +637,8 @@ tty3270_activate(struct raw3270_view *view)
 static void
 static void
 tty3270_deactivate(struct raw3270_view *view)
 tty3270_deactivate(struct raw3270_view *view)
 {
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(view, struct tty3270, view);
 
 
-	tp = (struct tty3270 *) view;
 	del_timer(&tp->timer);
 	del_timer(&tp->timer);
 }
 }
 
 
@@ -690,6 +680,17 @@ tty3270_alloc_view(void)
 	if (!tp->freemem_pages)
 	if (!tp->freemem_pages)
 		goto out_tp;
 		goto out_tp;
 	INIT_LIST_HEAD(&tp->freemem);
 	INIT_LIST_HEAD(&tp->freemem);
+	INIT_LIST_HEAD(&tp->lines);
+	INIT_LIST_HEAD(&tp->update);
+	INIT_LIST_HEAD(&tp->rcl_lines);
+	tp->rcl_max = 20;
+	tty_port_init(&tp->port);
+	setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
+		    (unsigned long) tp);
+	tasklet_init(&tp->readlet,
+		     (void (*)(unsigned long)) tty3270_read_tasklet,
+		     (unsigned long) tp->read);
+
 	for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
 	for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
 		tp->freemem_pages[pages] = (void *)
 		tp->freemem_pages[pages] = (void *)
 			__get_free_pages(GFP_KERNEL|GFP_DMA, 0);
 			__get_free_pages(GFP_KERNEL|GFP_DMA, 0);
@@ -794,16 +795,15 @@ tty3270_free_screen(struct tty3270 *tp)
 static void
 static void
 tty3270_release(struct raw3270_view *view)
 tty3270_release(struct raw3270_view *view)
 {
 {
-	struct tty3270 *tp;
-	struct tty_struct *tty;
+	struct tty3270 *tp = container_of(view, struct tty3270, view);
+	struct tty_struct *tty = tty_port_tty_get(&tp->port);
 
 
-	tp = (struct tty3270 *) view;
-	tty = tp->tty;
 	if (tty) {
 	if (tty) {
 		tty->driver_data = NULL;
 		tty->driver_data = NULL;
-		tp->tty = tp->kbd->tty = NULL;
+		tty_port_tty_set(&tp->port, NULL);
 		tty_hangup(tty);
 		tty_hangup(tty);
 		raw3270_put_view(&tp->view);
 		raw3270_put_view(&tp->view);
+		tty_kref_put(tty);
 	}
 	}
 }
 }
 
 
@@ -813,8 +813,9 @@ tty3270_release(struct raw3270_view *view)
 static void
 static void
 tty3270_free(struct raw3270_view *view)
 tty3270_free(struct raw3270_view *view)
 {
 {
-	tty3270_free_screen((struct tty3270 *) view);
-	tty3270_free_view((struct tty3270 *) view);
+	struct tty3270 *tp = container_of(view, struct tty3270, view);
+	tty3270_free_screen(tp);
+	tty3270_free_view(tp);
 }
 }
 
 
 /*
 /*
@@ -823,14 +824,13 @@ tty3270_free(struct raw3270_view *view)
 static void
 static void
 tty3270_del_views(void)
 tty3270_del_views(void)
 {
 {
-	struct tty3270 *tp;
 	int i;
 	int i;
 
 
 	for (i = 0; i < tty3270_max_index; i++) {
 	for (i = 0; i < tty3270_max_index; i++) {
-		tp = (struct tty3270 *)
+		struct raw3270_view *view =
 			raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
 			raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
-		if (!IS_ERR(tp))
-			raw3270_del_view(&tp->view);
+		if (!IS_ERR(view))
+			raw3270_del_view(view);
 	}
 	}
 }
 }
 
 
@@ -848,22 +848,23 @@ static struct raw3270_fn tty3270_fn = {
 static int
 static int
 tty3270_open(struct tty_struct *tty, struct file * filp)
 tty3270_open(struct tty_struct *tty, struct file * filp)
 {
 {
+	struct raw3270_view *view;
 	struct tty3270 *tp;
 	struct tty3270 *tp;
 	int i, rc;
 	int i, rc;
 
 
 	if (tty->count > 1)
 	if (tty->count > 1)
 		return 0;
 		return 0;
 	/* Check if the tty3270 is already there. */
 	/* Check if the tty3270 is already there. */
-	tp = (struct tty3270 *)
-		raw3270_find_view(&tty3270_fn,
+	view = raw3270_find_view(&tty3270_fn,
 				  tty->index + RAW3270_FIRSTMINOR);
 				  tty->index + RAW3270_FIRSTMINOR);
-	if (!IS_ERR(tp)) {
+	if (!IS_ERR(view)) {
+		tp = container_of(view, struct tty3270, view);
 		tty->driver_data = tp;
 		tty->driver_data = tp;
 		tty->winsize.ws_row = tp->view.rows - 2;
 		tty->winsize.ws_row = tp->view.rows - 2;
 		tty->winsize.ws_col = tp->view.cols;
 		tty->winsize.ws_col = tp->view.cols;
 		tty->low_latency = 0;
 		tty->low_latency = 0;
-		tp->tty = tty;
-		tp->kbd->tty = tty;
+		/* why to reassign? */
+		tty_port_tty_set(&tp->port, tty);
 		tp->inattr = TF_INPUT;
 		tp->inattr = TF_INPUT;
 		return 0;
 		return 0;
 	}
 	}
@@ -871,7 +872,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 		tty3270_max_index = tty->index + 1;
 		tty3270_max_index = tty->index + 1;
 
 
 	/* Quick exit if there is no device for tty->index. */
 	/* Quick exit if there is no device for tty->index. */
-	if (PTR_ERR(tp) == -ENODEV)
+	if (PTR_ERR(view) == -ENODEV)
 		return -ENODEV;
 		return -ENODEV;
 
 
 	/* Allocate tty3270 structure on first open. */
 	/* Allocate tty3270 structure on first open. */
@@ -879,16 +880,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 	if (IS_ERR(tp))
 	if (IS_ERR(tp))
 		return PTR_ERR(tp);
 		return PTR_ERR(tp);
 
 
-	INIT_LIST_HEAD(&tp->lines);
-	INIT_LIST_HEAD(&tp->update);
-	INIT_LIST_HEAD(&tp->rcl_lines);
-	tp->rcl_max = 20;
-	setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
-		    (unsigned long) tp);
-	tasklet_init(&tp->readlet, 
-		     (void (*)(unsigned long)) tty3270_read_tasklet,
-		     (unsigned long) tp->read);
-
 	rc = raw3270_add_view(&tp->view, &tty3270_fn,
 	rc = raw3270_add_view(&tp->view, &tty3270_fn,
 			      tty->index + RAW3270_FIRSTMINOR);
 			      tty->index + RAW3270_FIRSTMINOR);
 	if (rc) {
 	if (rc) {
@@ -903,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 		return rc;
 		return rc;
 	}
 	}
 
 
-	tp->tty = tty;
+	tty_port_tty_set(&tp->port, tty);
 	tty->low_latency = 0;
 	tty->low_latency = 0;
 	tty->driver_data = tp;
 	tty->driver_data = tp;
 	tty->winsize.ws_row = tp->view.rows - 2;
 	tty->winsize.ws_row = tp->view.rows - 2;
@@ -917,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 	for (i = 0; i < tp->view.rows - 2; i++)
 	for (i = 0; i < tp->view.rows - 2; i++)
 		tty3270_blank_line(tp);
 		tty3270_blank_line(tp);
 
 
-	tp->kbd->tty = tty;
+	tp->kbd->port = &tp->port;
 	tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
 	tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
 	tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
 	tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
 	tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
 	tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
@@ -935,14 +926,13 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 static void
 static void
 tty3270_close(struct tty_struct *tty, struct file * filp)
 tty3270_close(struct tty_struct *tty, struct file * filp)
 {
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = tty->driver_data;
 
 
 	if (tty->count > 1)
 	if (tty->count > 1)
 		return;
 		return;
-	tp = (struct tty3270 *) tty->driver_data;
 	if (tp) {
 	if (tp) {
 		tty->driver_data = NULL;
 		tty->driver_data = NULL;
-		tp->tty = tp->kbd->tty = NULL;
+		tty_port_tty_set(&tp->port, NULL);
 		raw3270_put_view(&tp->view);
 		raw3270_put_view(&tp->view);
 	}
 	}
 }
 }
@@ -1391,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
 			tty3270_lf(tp);
 			tty3270_lf(tp);
 			break;
 			break;
 		case 'Z':		/* Respond ID. */
 		case 'Z':		/* Respond ID. */
-			kbd_puts_queue(tp->tty, "\033[?6c");
+			kbd_puts_queue(&tp->port, "\033[?6c");
 			break;
 			break;
 		case '7':		/* Save cursor position. */
 		case '7':		/* Save cursor position. */
 			tp->saved_cx = tp->cx;
 			tp->saved_cx = tp->cx;
@@ -1437,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
 	tp->esc_state = ESnormal;
 	tp->esc_state = ESnormal;
 	if (ch == 'n' && !tp->esc_ques) {
 	if (ch == 'n' && !tp->esc_ques) {
 		if (tp->esc_par[0] == 5)		/* Status report. */
 		if (tp->esc_par[0] == 5)		/* Status report. */
-			kbd_puts_queue(tp->tty, "\033[0n");
+			kbd_puts_queue(&tp->port, "\033[0n");
 		else if (tp->esc_par[0] == 6) {	/* Cursor report. */
 		else if (tp->esc_par[0] == 6) {	/* Cursor report. */
 			char buf[40];
 			char buf[40];
 			sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
 			sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
-			kbd_puts_queue(tp->tty, buf);
+			kbd_puts_queue(&tp->port, buf);
 		}
 		}
 		return;
 		return;
 	}
 	}
@@ -1513,12 +1503,13 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
  * String write routine for 3270 ttys
  * String write routine for 3270 ttys
  */
  */
 static void
 static void
-tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count)
+tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
+		const unsigned char *buf, int count)
 {
 {
 	int i_msg, i;
 	int i_msg, i;
 
 
 	spin_lock_bh(&tp->view.lock);
 	spin_lock_bh(&tp->view.lock);
-	for (i_msg = 0; !tp->tty->stopped && i_msg < count; i_msg++) {
+	for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {
 		if (tp->esc_state != 0) {
 		if (tp->esc_state != 0) {
 			/* Continue escape sequence. */
 			/* Continue escape sequence. */
 			tty3270_escape_sequence(tp, buf[i_msg]);
 			tty3270_escape_sequence(tp, buf[i_msg]);
@@ -1595,10 +1586,10 @@ tty3270_write(struct tty_struct * tty,
 	if (!tp)
 	if (!tp)
 		return 0;
 		return 0;
 	if (tp->char_count > 0) {
 	if (tp->char_count > 0) {
-		tty3270_do_write(tp, tp->char_buf, tp->char_count);
+		tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
 		tp->char_count = 0;
 		tp->char_count = 0;
 	}
 	}
-	tty3270_do_write(tp, buf, count);
+	tty3270_do_write(tp, tty, buf, count);
 	return count;
 	return count;
 }
 }
 
 
@@ -1629,7 +1620,7 @@ tty3270_flush_chars(struct tty_struct *tty)
 	if (!tp)
 	if (!tp)
 		return;
 		return;
 	if (tp->char_count > 0) {
 	if (tp->char_count > 0) {
-		tty3270_do_write(tp, tp->char_buf, tp->char_count);
+		tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
 		tp->char_count = 0;
 		tp->char_count = 0;
 	}
 	}
 }
 }

+ 2 - 2
drivers/staging/serial/68360serial.c

@@ -1859,9 +1859,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 		printk("block_til_ready blocking: ttys%d, count = %d\n",
 		printk("block_til_ready blocking: ttys%d, count = %d\n",
 		       info->line, state->count);
 		       info->line, state->count);
 #endif
 #endif
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	}
 	current->state = TASK_RUNNING;
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&info->open_wait, &wait);
 	remove_wait_queue(&info->open_wait, &wait);

+ 7 - 7
drivers/tty/amiserial.c

@@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
 	if (!retinfo)
 	if (!retinfo)
 		return -EFAULT;
 		return -EFAULT;
 	memset(&tmp, 0, sizeof(tmp));
 	memset(&tmp, 0, sizeof(tmp));
-	tty_lock();
+	tty_lock(tty);
 	tmp.line = tty->index;
 	tmp.line = tty->index;
 	tmp.port = state->port;
 	tmp.port = state->port;
 	tmp.flags = state->tport.flags;
 	tmp.flags = state->tport.flags;
@@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
 	tmp.close_delay = state->tport.close_delay;
 	tmp.close_delay = state->tport.close_delay;
 	tmp.closing_wait = state->tport.closing_wait;
 	tmp.closing_wait = state->tport.closing_wait;
 	tmp.custom_divisor = state->custom_divisor;
 	tmp.custom_divisor = state->custom_divisor;
-	tty_unlock();
+	tty_unlock(tty);
 	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
 	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
 		return -EFAULT;
 		return -EFAULT;
 	return 0;
 	return 0;
@@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
 	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 		return -EFAULT;
 		return -EFAULT;
 
 
-	tty_lock();
+	tty_lock(tty);
 	change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
 	change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
 		new_serial.custom_divisor != state->custom_divisor;
 		new_serial.custom_divisor != state->custom_divisor;
 	if (new_serial.irq || new_serial.port != state->port ||
 	if (new_serial.irq || new_serial.port != state->port ||
 			new_serial.xmit_fifo_size != state->xmit_fifo_size) {
 			new_serial.xmit_fifo_size != state->xmit_fifo_size) {
-		tty_unlock();
+		tty_unlock(tty);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
   
   
@@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
 		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
 		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
 		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
 		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
 		     (port->flags & ~ASYNC_USR_MASK))) {
 		     (port->flags & ~ASYNC_USR_MASK))) {
-			tty_unlock();
+			tty_unlock(tty);
 			return -EPERM;
 			return -EPERM;
 		}
 		}
 		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
 		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
 	}
 	}
 
 
 	if (new_serial.baud_base < 9600) {
 	if (new_serial.baud_base < 9600) {
-		tty_unlock();
+		tty_unlock(tty);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -1116,7 +1116,7 @@ check_and_exit:
 		}
 		}
 	} else
 	} else
 		retval = startup(tty, state);
 		retval = startup(tty, state);
-	tty_unlock();
+	tty_unlock(tty);
 	return retval;
 	return retval;
 }
 }
 
 

+ 22 - 22
drivers/tty/bfin_jtag_comm.c

@@ -62,9 +62,7 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
 
 
 static struct tty_driver *bfin_jc_driver;
 static struct tty_driver *bfin_jc_driver;
 static struct task_struct *bfin_jc_kthread;
 static struct task_struct *bfin_jc_kthread;
-static struct tty_struct * volatile bfin_jc_tty;
-static unsigned long bfin_jc_count;
-static DEFINE_MUTEX(bfin_jc_tty_mutex);
+static struct tty_port port;
 static volatile struct circ_buf bfin_jc_write_buf;
 static volatile struct circ_buf bfin_jc_write_buf;
 
 
 static int
 static int
@@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg)
 	uint32_t inbound_len = 0, outbound_len = 0;
 	uint32_t inbound_len = 0, outbound_len = 0;
 
 
 	while (!kthread_should_stop()) {
 	while (!kthread_should_stop()) {
+		struct tty_struct *tty = tty_port_tty_get(&port);
 		/* no one left to give data to, so sleep */
 		/* no one left to give data to, so sleep */
-		if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
+		if (tty == NULL && circ_empty(&bfin_jc_write_buf)) {
 			pr_debug("waiting for readers\n");
 			pr_debug("waiting for readers\n");
 			__set_current_state(TASK_UNINTERRUPTIBLE);
 			__set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule();
 			schedule();
 			__set_current_state(TASK_RUNNING);
 			__set_current_state(TASK_RUNNING);
+			continue;
 		}
 		}
 
 
 		/* no data available, so just chill */
 		/* no data available, so just chill */
 		if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
 		if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
 			pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
 			pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
 				inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
 				inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
+			tty_kref_put(tty);
 			if (inbound_len)
 			if (inbound_len)
 				schedule();
 				schedule();
 			else
 			else
@@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg)
 
 
 		/* if incoming data is ready, eat it */
 		/* if incoming data is ready, eat it */
 		if (bfin_read_DBGSTAT() & EMUDIF) {
 		if (bfin_read_DBGSTAT() & EMUDIF) {
-			struct tty_struct *tty;
-			mutex_lock(&bfin_jc_tty_mutex);
-			tty = (struct tty_struct *)bfin_jc_tty;
 			if (tty != NULL) {
 			if (tty != NULL) {
 				uint32_t emudat = bfin_read_emudat();
 				uint32_t emudat = bfin_read_emudat();
 				if (inbound_len == 0) {
 				if (inbound_len == 0) {
@@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg)
 					tty_flip_buffer_push(tty);
 					tty_flip_buffer_push(tty);
 				}
 				}
 			}
 			}
-			mutex_unlock(&bfin_jc_tty_mutex);
 		}
 		}
 
 
 		/* if outgoing data is ready, post it */
 		/* if outgoing data is ready, post it */
@@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg)
 				bfin_write_emudat(outbound_len);
 				bfin_write_emudat(outbound_len);
 				pr_debug("outgoing length: 0x%08x\n", outbound_len);
 				pr_debug("outgoing length: 0x%08x\n", outbound_len);
 			} else {
 			} else {
-				struct tty_struct *tty;
 				int tail = bfin_jc_write_buf.tail;
 				int tail = bfin_jc_write_buf.tail;
 				size_t ate = (4 <= outbound_len ? 4 : outbound_len);
 				size_t ate = (4 <= outbound_len ? 4 : outbound_len);
 				uint32_t emudat =
 				uint32_t emudat =
@@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg)
 				);
 				);
 				bfin_jc_write_buf.tail += ate;
 				bfin_jc_write_buf.tail += ate;
 				outbound_len -= ate;
 				outbound_len -= ate;
-				mutex_lock(&bfin_jc_tty_mutex);
-				tty = (struct tty_struct *)bfin_jc_tty;
 				if (tty)
 				if (tty)
 					tty_wakeup(tty);
 					tty_wakeup(tty);
-				mutex_unlock(&bfin_jc_tty_mutex);
 				pr_debug("  outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
 				pr_debug("  outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
 			}
 			}
 		}
 		}
+		tty_kref_put(tty);
 	}
 	}
 
 
 	__set_current_state(TASK_RUNNING);
 	__set_current_state(TASK_RUNNING);
@@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg)
 static int
 static int
 bfin_jc_open(struct tty_struct *tty, struct file *filp)
 bfin_jc_open(struct tty_struct *tty, struct file *filp)
 {
 {
-	mutex_lock(&bfin_jc_tty_mutex);
-	pr_debug("open %lu\n", bfin_jc_count);
-	++bfin_jc_count;
-	bfin_jc_tty = tty;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port.lock, flags);
+	port.count++;
+	spin_unlock_irqrestore(&port.lock, flags);
+	tty_port_tty_set(&port, tty);
 	wake_up_process(bfin_jc_kthread);
 	wake_up_process(bfin_jc_kthread);
-	mutex_unlock(&bfin_jc_tty_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
 static void
 static void
 bfin_jc_close(struct tty_struct *tty, struct file *filp)
 bfin_jc_close(struct tty_struct *tty, struct file *filp)
 {
 {
-	mutex_lock(&bfin_jc_tty_mutex);
-	pr_debug("close %lu\n", bfin_jc_count);
-	if (--bfin_jc_count == 0)
-		bfin_jc_tty = NULL;
+	unsigned long flags;
+	bool last;
+
+	spin_lock_irqsave(&port.lock, flags);
+	last = --port.count == 0;
+	spin_unlock_irqrestore(&port.lock, flags);
+	if (last)
+		tty_port_tty_set(&port, NULL);
 	wake_up_process(bfin_jc_kthread);
 	wake_up_process(bfin_jc_kthread);
-	mutex_unlock(&bfin_jc_tty_mutex);
 }
 }
 
 
 /* XXX: we dont handle the put_char() case where we must handle count = 1 */
 /* XXX: we dont handle the put_char() case where we must handle count = 1 */
@@ -242,6 +240,8 @@ static int __init bfin_jc_init(void)
 {
 {
 	int ret;
 	int ret;
 
 
+	tty_port_init(&port);
+
 	bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
 	bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
 	if (IS_ERR(bfin_jc_kthread))
 	if (IS_ERR(bfin_jc_kthread))
 		return PTR_ERR(bfin_jc_kthread);
 		return PTR_ERR(bfin_jc_kthread);

+ 1 - 1
drivers/tty/cyclades.c

@@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
 	 * If the port is the middle of closing, bail out now
 	 * If the port is the middle of closing, bail out now
 	 */
 	 */
 	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
 	if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
-		wait_event_interruptible_tty(info->port.close_wait,
+		wait_event_interruptible_tty(tty, info->port.close_wait,
 				!(info->port.flags & ASYNC_CLOSING));
 				!(info->port.flags & ASYNC_CLOSING));
 		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
 		return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
 	}
 	}

+ 46 - 50
drivers/tty/hvc/hvc_console.c

@@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
 	list_for_each_entry(hp, &hvc_structs, next) {
 	list_for_each_entry(hp, &hvc_structs, next) {
 		spin_lock_irqsave(&hp->lock, flags);
 		spin_lock_irqsave(&hp->lock, flags);
 		if (hp->index == index) {
 		if (hp->index == index) {
-			kref_get(&hp->kref);
+			tty_port_get(&hp->port);
 			spin_unlock_irqrestore(&hp->lock, flags);
 			spin_unlock_irqrestore(&hp->lock, flags);
 			spin_unlock(&hvc_structs_lock);
 			spin_unlock(&hvc_structs_lock);
 			return hp;
 			return hp;
@@ -229,9 +229,9 @@ static int __init hvc_console_init(void)
 console_initcall(hvc_console_init);
 console_initcall(hvc_console_init);
 
 
 /* callback when the kboject ref count reaches zero. */
 /* callback when the kboject ref count reaches zero. */
-static void destroy_hvc_struct(struct kref *kref)
+static void hvc_port_destruct(struct tty_port *port)
 {
 {
-	struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
+	struct hvc_struct *hp = container_of(port, struct hvc_struct, port);
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock(&hvc_structs_lock);
 	spin_lock(&hvc_structs_lock);
@@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
 	/* make sure no no tty has been registered in this index */
 	/* make sure no no tty has been registered in this index */
 	hp = hvc_get_by_index(index);
 	hp = hvc_get_by_index(index);
 	if (hp) {
 	if (hp) {
-		kref_put(&hp->kref, destroy_hvc_struct);
+		tty_port_put(&hp->port);
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 	if (!(hp = hvc_get_by_index(tty->index)))
 	if (!(hp = hvc_get_by_index(tty->index)))
 		return -ENODEV;
 		return -ENODEV;
 
 
-	spin_lock_irqsave(&hp->lock, flags);
+	spin_lock_irqsave(&hp->port.lock, flags);
 	/* Check and then increment for fast path open. */
 	/* Check and then increment for fast path open. */
-	if (hp->count++ > 0) {
-		tty_kref_get(tty);
-		spin_unlock_irqrestore(&hp->lock, flags);
+	if (hp->port.count++ > 0) {
+		spin_unlock_irqrestore(&hp->port.lock, flags);
 		hvc_kick();
 		hvc_kick();
 		return 0;
 		return 0;
 	} /* else count == 0 */
 	} /* else count == 0 */
+	spin_unlock_irqrestore(&hp->port.lock, flags);
 
 
 	tty->driver_data = hp;
 	tty->driver_data = hp;
-
-	hp->tty = tty_kref_get(tty);
-
-	spin_unlock_irqrestore(&hp->lock, flags);
+	tty_port_tty_set(&hp->port, tty);
 
 
 	if (hp->ops->notifier_add)
 	if (hp->ops->notifier_add)
 		rc = hp->ops->notifier_add(hp, hp->data);
 		rc = hp->ops->notifier_add(hp, hp->data);
@@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 	 * tty fields and return the kref reference.
 	 * tty fields and return the kref reference.
 	 */
 	 */
 	if (rc) {
 	if (rc) {
-		spin_lock_irqsave(&hp->lock, flags);
-		hp->tty = NULL;
-		spin_unlock_irqrestore(&hp->lock, flags);
-		tty_kref_put(tty);
+		tty_port_tty_set(&hp->port, NULL);
 		tty->driver_data = NULL;
 		tty->driver_data = NULL;
-		kref_put(&hp->kref, destroy_hvc_struct);
+		tty_port_put(&hp->port);
 		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
 		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
 	}
 	}
 	/* Force wakeup of the polling thread */
 	/* Force wakeup of the polling thread */
@@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 
 
 	hp = tty->driver_data;
 	hp = tty->driver_data;
 
 
-	spin_lock_irqsave(&hp->lock, flags);
+	spin_lock_irqsave(&hp->port.lock, flags);
 
 
-	if (--hp->count == 0) {
+	if (--hp->port.count == 0) {
+		spin_unlock_irqrestore(&hp->port.lock, flags);
 		/* We are done with the tty pointer now. */
 		/* We are done with the tty pointer now. */
-		hp->tty = NULL;
-		spin_unlock_irqrestore(&hp->lock, flags);
+		tty_port_tty_set(&hp->port, NULL);
 
 
 		if (hp->ops->notifier_del)
 		if (hp->ops->notifier_del)
 			hp->ops->notifier_del(hp, hp->data);
 			hp->ops->notifier_del(hp, hp->data);
@@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 		 */
 		 */
 		tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
 		tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
 	} else {
 	} else {
-		if (hp->count < 0)
+		if (hp->port.count < 0)
 			printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
 			printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
-				hp->vtermno, hp->count);
-		spin_unlock_irqrestore(&hp->lock, flags);
+				hp->vtermno, hp->port.count);
+		spin_unlock_irqrestore(&hp->port.lock, flags);
 	}
 	}
 
 
-	tty_kref_put(tty);
-	kref_put(&hp->kref, destroy_hvc_struct);
+	tty_port_put(&hp->port);
 }
 }
 
 
 static void hvc_hangup(struct tty_struct *tty)
 static void hvc_hangup(struct tty_struct *tty)
@@ -412,32 +405,31 @@ static void hvc_hangup(struct tty_struct *tty)
 	/* cancel pending tty resize work */
 	/* cancel pending tty resize work */
 	cancel_work_sync(&hp->tty_resize);
 	cancel_work_sync(&hp->tty_resize);
 
 
-	spin_lock_irqsave(&hp->lock, flags);
+	spin_lock_irqsave(&hp->port.lock, flags);
 
 
 	/*
 	/*
 	 * The N_TTY line discipline has problems such that in a close vs
 	 * The N_TTY line discipline has problems such that in a close vs
 	 * open->hangup case this can be called after the final close so prevent
 	 * open->hangup case this can be called after the final close so prevent
 	 * that from happening for now.
 	 * that from happening for now.
 	 */
 	 */
-	if (hp->count <= 0) {
-		spin_unlock_irqrestore(&hp->lock, flags);
+	if (hp->port.count <= 0) {
+		spin_unlock_irqrestore(&hp->port.lock, flags);
 		return;
 		return;
 	}
 	}
 
 
-	temp_open_count = hp->count;
-	hp->count = 0;
-	hp->n_outbuf = 0;
-	hp->tty = NULL;
+	temp_open_count = hp->port.count;
+	hp->port.count = 0;
+	spin_unlock_irqrestore(&hp->port.lock, flags);
+	tty_port_tty_set(&hp->port, NULL);
 
 
-	spin_unlock_irqrestore(&hp->lock, flags);
+	hp->n_outbuf = 0;
 
 
 	if (hp->ops->notifier_hangup)
 	if (hp->ops->notifier_hangup)
 		hp->ops->notifier_hangup(hp, hp->data);
 		hp->ops->notifier_hangup(hp, hp->data);
 
 
 	while(temp_open_count) {
 	while(temp_open_count) {
 		--temp_open_count;
 		--temp_open_count;
-		tty_kref_put(tty);
-		kref_put(&hp->kref, destroy_hvc_struct);
+		tty_port_put(&hp->port);
 	}
 	}
 }
 }
 
 
@@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
 	if (!hp)
 	if (!hp)
 		return -EPIPE;
 		return -EPIPE;
 
 
-	if (hp->count <= 0)
+	/* FIXME what's this (unprotected) check for? */
+	if (hp->port.count <= 0)
 		return -EIO;
 		return -EIO;
 
 
 	spin_lock_irqsave(&hp->lock, flags);
 	spin_lock_irqsave(&hp->lock, flags);
@@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work)
 
 
 	hp = container_of(work, struct hvc_struct, tty_resize);
 	hp = container_of(work, struct hvc_struct, tty_resize);
 
 
-	spin_lock_irqsave(&hp->lock, hvc_flags);
-	if (!hp->tty) {
-		spin_unlock_irqrestore(&hp->lock, hvc_flags);
+	tty = tty_port_tty_get(&hp->port);
+	if (!tty)
 		return;
 		return;
-	}
-	ws  = hp->ws;
-	tty = tty_kref_get(hp->tty);
+
+	spin_lock_irqsave(&hp->lock, hvc_flags);
+	ws = hp->ws;
 	spin_unlock_irqrestore(&hp->lock, hvc_flags);
 	spin_unlock_irqrestore(&hp->lock, hvc_flags);
 
 
 	tty_do_resize(tty, &ws);
 	tty_do_resize(tty, &ws);
@@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp)
 	}
 	}
 
 
 	/* No tty attached, just skip */
 	/* No tty attached, just skip */
-	tty = tty_kref_get(hp->tty);
+	tty = tty_port_tty_get(&hp->port);
 	if (tty == NULL)
 	if (tty == NULL)
 		goto bail;
 		goto bail;
 
 
@@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp)
 
 
 		tty_flip_buffer_push(tty);
 		tty_flip_buffer_push(tty);
 	}
 	}
-	if (tty)
-		tty_kref_put(tty);
+	tty_kref_put(tty);
 
 
 	return poll_mask;
 	return poll_mask;
 }
 }
@@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = {
 #endif
 #endif
 };
 };
 
 
+static const struct tty_port_operations hvc_port_ops = {
+	.destruct = hvc_port_destruct,
+};
+
 struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
 struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
 			     const struct hv_ops *ops,
 			     const struct hv_ops *ops,
 			     int outbuf_size)
 			     int outbuf_size)
@@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
 	hp->outbuf_size = outbuf_size;
 	hp->outbuf_size = outbuf_size;
 	hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
 	hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
 
 
-	kref_init(&hp->kref);
+	tty_port_init(&hp->port);
+	hp->port.ops = &hvc_port_ops;
 
 
 	INIT_WORK(&hp->tty_resize, hvc_set_winsz);
 	INIT_WORK(&hp->tty_resize, hvc_set_winsz);
 	spin_lock_init(&hp->lock);
 	spin_lock_init(&hp->lock);
@@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp)
 	unsigned long flags;
 	unsigned long flags;
 	struct tty_struct *tty;
 	struct tty_struct *tty;
 
 
-	spin_lock_irqsave(&hp->lock, flags);
-	tty = tty_kref_get(hp->tty);
+	tty = tty_port_tty_get(&hp->port);
 
 
+	spin_lock_irqsave(&hp->lock, flags);
 	if (hp->index < MAX_NR_HVC_CONSOLES)
 	if (hp->index < MAX_NR_HVC_CONSOLES)
 		vtermnos[hp->index] = -1;
 		vtermnos[hp->index] = -1;
 
 
@@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp)
 	 * kref cause it to be removed, which will probably be the tty_vhangup
 	 * kref cause it to be removed, which will probably be the tty_vhangup
 	 * below.
 	 * below.
 	 */
 	 */
-	kref_put(&hp->kref, destroy_hvc_struct);
+	tty_port_put(&hp->port);
 
 
 	/*
 	/*
 	 * This function call will auto chain call hvc_hangup.
 	 * This function call will auto chain call hvc_hangup.

+ 1 - 3
drivers/tty/hvc/hvc_console.h

@@ -46,10 +46,9 @@
 #define HVC_ALLOC_TTY_ADAPTERS	8
 #define HVC_ALLOC_TTY_ADAPTERS	8
 
 
 struct hvc_struct {
 struct hvc_struct {
+	struct tty_port port;
 	spinlock_t lock;
 	spinlock_t lock;
 	int index;
 	int index;
-	struct tty_struct *tty;
-	int count;
 	int do_wakeup;
 	int do_wakeup;
 	char *outbuf;
 	char *outbuf;
 	int outbuf_size;
 	int outbuf_size;
@@ -61,7 +60,6 @@ struct hvc_struct {
 	struct winsize ws;
 	struct winsize ws;
 	struct work_struct tty_resize;
 	struct work_struct tty_resize;
 	struct list_head next;
 	struct list_head next;
-	struct kref kref; /* ref count & hvc_struct lifetime */
 };
 };
 
 
 /* implemented by a low level driver */
 /* implemented by a low level driver */

+ 2 - 2
drivers/tty/hvc/hvc_xen.c

@@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev,
 	if (devid == 0)
 	if (devid == 0)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+	info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
 	if (!info)
 	if (!info)
-		goto error_nomem;
+		return -ENOMEM;
 	dev_set_drvdata(&dev->dev, info);
 	dev_set_drvdata(&dev->dev, info);
 	info->xbdev = dev;
 	info->xbdev = dev;
 	info->vtermno = xenbus_devid_to_vtermno(devid);
 	info->vtermno = xenbus_devid_to_vtermno(devid);

+ 35 - 39
drivers/tty/hvc/hvcs.c

@@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock);
 
 
 /* One vty-server per hvcs_struct */
 /* One vty-server per hvcs_struct */
 struct hvcs_struct {
 struct hvcs_struct {
+	struct tty_port port;
 	spinlock_t lock;
 	spinlock_t lock;
 
 
 	/*
 	/*
@@ -269,9 +270,6 @@ struct hvcs_struct {
 	 */
 	 */
 	unsigned int index;
 	unsigned int index;
 
 
-	struct tty_struct *tty;
-	int open_count;
-
 	/*
 	/*
 	 * Used to tell the driver kernel_thread what operations need to take
 	 * Used to tell the driver kernel_thread what operations need to take
 	 * place upon this hvcs_struct instance.
 	 * place upon this hvcs_struct instance.
@@ -290,12 +288,11 @@ struct hvcs_struct {
 	int chars_in_buffer;
 	int chars_in_buffer;
 
 
 	/*
 	/*
-	 * Any variable below the kref is valid before a tty is connected and
+	 * Any variable below is valid before a tty is connected and
 	 * stays valid after the tty is disconnected.  These shouldn't be
 	 * stays valid after the tty is disconnected.  These shouldn't be
 	 * whacked until the kobject refcount reaches zero though some entries
 	 * whacked until the kobject refcount reaches zero though some entries
 	 * may be changed via sysfs initiatives.
 	 * may be changed via sysfs initiatives.
 	 */
 	 */
-	struct kref kref; /* ref count & hvcs_struct lifetime */
 	int connected; /* is the vty-server currently connected to a vty? */
 	int connected; /* is the vty-server currently connected to a vty? */
 	uint32_t p_unit_address; /* partner unit address */
 	uint32_t p_unit_address; /* partner unit address */
 	uint32_t p_partition_ID; /* partner partition ID */
 	uint32_t p_partition_ID; /* partner partition ID */
@@ -304,9 +301,6 @@ struct hvcs_struct {
 	struct vio_dev *vdev;
 	struct vio_dev *vdev;
 };
 };
 
 
-/* Required to back map a kref to its containing object */
-#define from_kref(k) container_of(k, struct hvcs_struct, kref)
-
 static LIST_HEAD(hvcs_structs);
 static LIST_HEAD(hvcs_structs);
 static DEFINE_SPINLOCK(hvcs_structs_lock);
 static DEFINE_SPINLOCK(hvcs_structs_lock);
 static DEFINE_MUTEX(hvcs_init_mutex);
 static DEFINE_MUTEX(hvcs_init_mutex);
@@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut
 
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	spin_lock_irqsave(&hvcsd->lock, flags);
 
 
-	if (hvcsd->open_count > 0) {
+	if (hvcsd->port.count > 0) {
 		spin_unlock_irqrestore(&hvcsd->lock, flags);
 		spin_unlock_irqrestore(&hvcsd->lock, flags);
 		printk(KERN_INFO "HVCS: vterm state unchanged.  "
 		printk(KERN_INFO "HVCS: vterm state unchanged.  "
 				"The hvcs device node is still in use.\n");
 				"The hvcs device node is still in use.\n");
@@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
 static void hvcs_try_write(struct hvcs_struct *hvcsd)
 static void hvcs_try_write(struct hvcs_struct *hvcsd)
 {
 {
 	uint32_t unit_address = hvcsd->vdev->unit_address;
 	uint32_t unit_address = hvcsd->vdev->unit_address;
-	struct tty_struct *tty = hvcsd->tty;
+	struct tty_struct *tty = hvcsd->port.tty;
 	int sent;
 	int sent;
 
 
 	if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
 	if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
@@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	spin_lock_irqsave(&hvcsd->lock, flags);
 
 
 	unit_address = hvcsd->vdev->unit_address;
 	unit_address = hvcsd->vdev->unit_address;
-	tty = hvcsd->tty;
+	tty = hvcsd->port.tty;
 
 
 	hvcs_try_write(hvcsd);
 	hvcs_try_write(hvcsd);
 
 
@@ -701,10 +695,9 @@ static void hvcs_return_index(int index)
 		hvcs_index_list[index] = -1;
 		hvcs_index_list[index] = -1;
 }
 }
 
 
-/* callback when the kref ref count reaches zero */
-static void destroy_hvcs_struct(struct kref *kref)
+static void hvcs_destruct_port(struct tty_port *p)
 {
 {
-	struct hvcs_struct *hvcsd = from_kref(kref);
+	struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
 	struct vio_dev *vdev;
 	struct vio_dev *vdev;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref)
 	kfree(hvcsd);
 	kfree(hvcsd);
 }
 }
 
 
+static const struct tty_port_operations hvcs_port_ops = {
+	.destruct = hvcs_destruct_port,
+};
+
 static int hvcs_get_index(void)
 static int hvcs_get_index(void)
 {
 {
 	int i;
 	int i;
@@ -789,10 +786,9 @@ static int __devinit hvcs_probe(
 	if (!hvcsd)
 	if (!hvcsd)
 		return -ENODEV;
 		return -ENODEV;
 
 
-
+	tty_port_init(&hvcsd->port);
+	hvcsd->port.ops = &hvcs_port_ops;
 	spin_lock_init(&hvcsd->lock);
 	spin_lock_init(&hvcsd->lock);
-	/* Automatically incs the refcount the first time */
-	kref_init(&hvcsd->kref);
 
 
 	hvcsd->vdev = dev;
 	hvcsd->vdev = dev;
 	dev_set_drvdata(&dev->dev, hvcsd);
 	dev_set_drvdata(&dev->dev, hvcsd);
@@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
 
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	spin_lock_irqsave(&hvcsd->lock, flags);
 
 
-	tty = hvcsd->tty;
+	tty = hvcsd->port.tty;
 
 
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
 
 
@@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
 	 * Let the last holder of this object cause it to be removed, which
 	 * Let the last holder of this object cause it to be removed, which
 	 * would probably be tty_hangup below.
 	 * would probably be tty_hangup below.
 	 */
 	 */
-	kref_put(&hvcsd->kref, destroy_hvcs_struct);
+	tty_port_put(&hvcsd->port);
 
 
 	/*
 	/*
 	 * The hangup is a scheduled function which will auto chain call
 	 * The hangup is a scheduled function which will auto chain call
@@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
 	list_for_each_entry(hvcsd, &hvcs_structs, next) {
 	list_for_each_entry(hvcsd, &hvcs_structs, next) {
 		spin_lock_irqsave(&hvcsd->lock, flags);
 		spin_lock_irqsave(&hvcsd->lock, flags);
 		if (hvcsd->index == index) {
 		if (hvcsd->index == index) {
-			kref_get(&hvcsd->kref);
+			tty_port_get(&hvcsd->port);
 			spin_unlock_irqrestore(&hvcsd->lock, flags);
 			spin_unlock_irqrestore(&hvcsd->lock, flags);
 			spin_unlock(&hvcs_structs_lock);
 			spin_unlock(&hvcs_structs_lock);
 			return hvcsd;
 			return hvcsd;
@@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
 		if ((retval = hvcs_partner_connect(hvcsd)))
 		if ((retval = hvcs_partner_connect(hvcsd)))
 			goto error_release;
 			goto error_release;
 
 
-	hvcsd->open_count = 1;
-	hvcsd->tty = tty;
+	hvcsd->port.count = 1;
+	hvcsd->port.tty = tty;
 	tty->driver_data = hvcsd;
 	tty->driver_data = hvcsd;
 
 
 	memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
 	memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
@@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
 	 * and will grab the spinlock and free the connection if it fails.
 	 * and will grab the spinlock and free the connection if it fails.
 	 */
 	 */
 	if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
 	if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
-		kref_put(&hvcsd->kref, destroy_hvcs_struct);
+		tty_port_put(&hvcsd->port);
 		printk(KERN_WARNING "HVCS: enable device failed.\n");
 		printk(KERN_WARNING "HVCS: enable device failed.\n");
 		return rc;
 		return rc;
 	}
 	}
@@ -1171,8 +1167,8 @@ fast_open:
 	hvcsd = tty->driver_data;
 	hvcsd = tty->driver_data;
 
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	spin_lock_irqsave(&hvcsd->lock, flags);
-	kref_get(&hvcsd->kref);
-	hvcsd->open_count++;
+	tty_port_get(&hvcsd->port);
+	hvcsd->port.count++;
 	hvcsd->todo_mask |= HVCS_SCHED_READ;
 	hvcsd->todo_mask |= HVCS_SCHED_READ;
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
 
 
@@ -1186,7 +1182,7 @@ open_success:
 
 
 error_release:
 error_release:
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
-	kref_put(&hvcsd->kref, destroy_hvcs_struct);
+	tty_port_put(&hvcsd->port);
 
 
 	printk(KERN_WARNING "HVCS: partner connect failed.\n");
 	printk(KERN_WARNING "HVCS: partner connect failed.\n");
 	return retval;
 	return retval;
@@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
 	hvcsd = tty->driver_data;
 	hvcsd = tty->driver_data;
 
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	spin_lock_irqsave(&hvcsd->lock, flags);
-	if (--hvcsd->open_count == 0) {
+	if (--hvcsd->port.count == 0) {
 
 
 		vio_disable_interrupts(hvcsd->vdev);
 		vio_disable_interrupts(hvcsd->vdev);
 
 
@@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
 		 * execute any operations on the TTY even though it is obligated
 		 * execute any operations on the TTY even though it is obligated
 		 * to deliver any pending I/O to the hypervisor.
 		 * to deliver any pending I/O to the hypervisor.
 		 */
 		 */
-		hvcsd->tty = NULL;
+		hvcsd->port.tty = NULL;
 
 
 		irq = hvcsd->vdev->irq;
 		irq = hvcsd->vdev->irq;
 		spin_unlock_irqrestore(&hvcsd->lock, flags);
 		spin_unlock_irqrestore(&hvcsd->lock, flags);
@@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
 		tty->driver_data = NULL;
 		tty->driver_data = NULL;
 
 
 		free_irq(irq, hvcsd);
 		free_irq(irq, hvcsd);
-		kref_put(&hvcsd->kref, destroy_hvcs_struct);
+		tty_port_put(&hvcsd->port);
 		return;
 		return;
-	} else if (hvcsd->open_count < 0) {
+	} else if (hvcsd->port.count < 0) {
 		printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
 		printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
 				" is missmanaged.\n",
 				" is missmanaged.\n",
-		hvcsd->vdev->unit_address, hvcsd->open_count);
+		hvcsd->vdev->unit_address, hvcsd->port.count);
 	}
 	}
 
 
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
-	kref_put(&hvcsd->kref, destroy_hvcs_struct);
+	tty_port_put(&hvcsd->port);
 }
 }
 
 
 static void hvcs_hangup(struct tty_struct * tty)
 static void hvcs_hangup(struct tty_struct * tty)
@@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty)
 
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	/* Preserve this so that we know how many kref refs to put */
 	/* Preserve this so that we know how many kref refs to put */
-	temp_open_count = hvcsd->open_count;
+	temp_open_count = hvcsd->port.count;
 
 
 	/*
 	/*
 	 * Don't kref put inside the spinlock because the destruction
 	 * Don't kref put inside the spinlock because the destruction
@@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty)
 	hvcsd->todo_mask = 0;
 	hvcsd->todo_mask = 0;
 
 
 	/* I don't think the tty needs the hvcs_struct pointer after a hangup */
 	/* I don't think the tty needs the hvcs_struct pointer after a hangup */
-	hvcsd->tty->driver_data = NULL;
-	hvcsd->tty = NULL;
+	tty->driver_data = NULL;
+	hvcsd->port.tty = NULL;
 
 
-	hvcsd->open_count = 0;
+	hvcsd->port.count = 0;
 
 
 	/* This will drop any buffered data on the floor which is OK in a hangup
 	/* This will drop any buffered data on the floor which is OK in a hangup
 	 * scenario. */
 	 * scenario. */
@@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty)
 		 * NOTE:  If this hangup was signaled from user space then the
 		 * NOTE:  If this hangup was signaled from user space then the
 		 * final put will never happen.
 		 * final put will never happen.
 		 */
 		 */
-		kref_put(&hvcsd->kref, destroy_hvcs_struct);
+		tty_port_put(&hvcsd->port);
 	}
 	}
 }
 }
 
 
@@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty,
 	 * the middle of a write operation?  This is a crummy place to do this
 	 * the middle of a write operation?  This is a crummy place to do this
 	 * but we want to keep it all in the spinlock.
 	 * but we want to keep it all in the spinlock.
 	 */
 	 */
-	if (hvcsd->open_count <= 0) {
+	if (hvcsd->port.count <= 0) {
 		spin_unlock_irqrestore(&hvcsd->lock, flags);
 		spin_unlock_irqrestore(&hvcsd->lock, flags);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty)
 {
 {
 	struct hvcs_struct *hvcsd = tty->driver_data;
 	struct hvcs_struct *hvcsd = tty->driver_data;
 
 
-	if (!hvcsd || hvcsd->open_count <= 0)
+	if (!hvcsd || hvcsd->port.count <= 0)
 		return 0;
 		return 0;
 
 
 	return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
 	return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;

+ 54 - 74
drivers/tty/hvc/hvsi.c

@@ -69,14 +69,13 @@
 #define __ALIGNED__	__attribute__((__aligned__(sizeof(long))))
 #define __ALIGNED__	__attribute__((__aligned__(sizeof(long))))
 
 
 struct hvsi_struct {
 struct hvsi_struct {
+	struct tty_port port;
 	struct delayed_work writer;
 	struct delayed_work writer;
 	struct work_struct handshaker;
 	struct work_struct handshaker;
 	wait_queue_head_t emptyq; /* woken when outbuf is emptied */
 	wait_queue_head_t emptyq; /* woken when outbuf is emptied */
 	wait_queue_head_t stateq; /* woken when HVSI state changes */
 	wait_queue_head_t stateq; /* woken when HVSI state changes */
 	spinlock_t lock;
 	spinlock_t lock;
 	int index;
 	int index;
-	struct tty_struct *tty;
-	int count;
 	uint8_t throttle_buf[128];
 	uint8_t throttle_buf[128];
 	uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
 	uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
 	/* inbuf is for packet reassembly. leave a little room for leftovers. */
 	/* inbuf is for packet reassembly. leave a little room for leftovers. */
@@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
 }
 }
 
 
 static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
 static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
-	struct tty_struct **to_hangup, struct hvsi_struct **to_handshake)
+	struct tty_struct *tty, struct hvsi_struct **to_handshake)
 {
 {
 	struct hvsi_control *header = (struct hvsi_control *)packet;
 	struct hvsi_control *header = (struct hvsi_control *)packet;
 
 
@@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
 				/* CD went away; no more connection */
 				/* CD went away; no more connection */
 				pr_debug("hvsi%i: CD dropped\n", hp->index);
 				pr_debug("hvsi%i: CD dropped\n", hp->index);
 				hp->mctrl &= TIOCM_CD;
 				hp->mctrl &= TIOCM_CD;
-				/* If userland hasn't done an open(2) yet, hp->tty is NULL. */
-				if (hp->tty && !(hp->tty->flags & CLOCAL))
-					*to_hangup = hp->tty;
+				if (tty && !C_CLOCAL(tty))
+					tty_hangup(tty);
 			}
 			}
 			break;
 			break;
 		case VSV_CLOSE_PROTOCOL:
 		case VSV_CLOSE_PROTOCOL:
@@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
 	}
 	}
 }
 }
 
 
-static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
+static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
+		const char *buf, int len)
 {
 {
 	int i;
 	int i;
 
 
@@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
 			continue;
 			continue;
 		}
 		}
 #endif /* CONFIG_MAGIC_SYSRQ */
 #endif /* CONFIG_MAGIC_SYSRQ */
-		tty_insert_flip_char(hp->tty, c, 0);
+		tty_insert_flip_char(tty, c, 0);
 	}
 	}
 }
 }
 
 
@@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
  * revisited.
  * revisited.
  */
  */
 #define TTY_THRESHOLD_THROTTLE 128
 #define TTY_THRESHOLD_THROTTLE 128
-static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
+static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
 		const uint8_t *packet)
 		const uint8_t *packet)
 {
 {
 	const struct hvsi_header *header = (const struct hvsi_header *)packet;
 	const struct hvsi_header *header = (const struct hvsi_header *)packet;
@@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
 	pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
 	pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
 
 
 	if (datalen == 0)
 	if (datalen == 0)
-		return NULL;
+		return false;
 
 
 	if (overflow > 0) {
 	if (overflow > 0) {
 		pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
 		pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
 		datalen = TTY_THRESHOLD_THROTTLE;
 		datalen = TTY_THRESHOLD_THROTTLE;
 	}
 	}
 
 
-	hvsi_insert_chars(hp, data, datalen);
+	hvsi_insert_chars(hp, tty, data, datalen);
 
 
 	if (overflow > 0) {
 	if (overflow > 0) {
 		/*
 		/*
@@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
 		hp->n_throttle = overflow;
 		hp->n_throttle = overflow;
 	}
 	}
 
 
-	return hp->tty;
+	return true;
 }
 }
 
 
 /*
 /*
@@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
  * machine during console handshaking (in which case tty = NULL and we ignore
  * machine during console handshaking (in which case tty = NULL and we ignore
  * incoming data).
  * incoming data).
  */
  */
-static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
-		struct tty_struct **hangup, struct hvsi_struct **handshake)
+static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
+		struct hvsi_struct **handshake)
 {
 {
 	uint8_t *packet = hp->inbuf;
 	uint8_t *packet = hp->inbuf;
 	int chunklen;
 	int chunklen;
+	bool flip = false;
 
 
-	*flip = NULL;
-	*hangup = NULL;
 	*handshake = NULL;
 	*handshake = NULL;
 
 
 	chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
 	chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
@@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
 			case VS_DATA_PACKET_HEADER:
 			case VS_DATA_PACKET_HEADER:
 				if (!is_open(hp))
 				if (!is_open(hp))
 					break;
 					break;
-				if (hp->tty == NULL)
+				if (tty == NULL)
 					break; /* no tty buffer to put data in */
 					break; /* no tty buffer to put data in */
-				*flip = hvsi_recv_data(hp, packet);
+				flip = hvsi_recv_data(hp, tty, packet);
 				break;
 				break;
 			case VS_CONTROL_PACKET_HEADER:
 			case VS_CONTROL_PACKET_HEADER:
-				hvsi_recv_control(hp, packet, hangup, handshake);
+				hvsi_recv_control(hp, packet, tty, handshake);
 				break;
 				break;
 			case VS_QUERY_RESPONSE_PACKET_HEADER:
 			case VS_QUERY_RESPONSE_PACKET_HEADER:
 				hvsi_recv_response(hp, packet);
 				hvsi_recv_response(hp, packet);
@@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
 
 
 		packet += len_packet(packet);
 		packet += len_packet(packet);
 
 
-		if (*hangup || *handshake) {
-			pr_debug("%s: hangup or handshake\n", __func__);
-			/*
-			 * we need to send the hangup now before receiving any more data.
-			 * If we get "data, hangup, data", we can't deliver the second
-			 * data before the hangup.
-			 */
+		if (*handshake) {
+			pr_debug("%s: handshake\n", __func__);
 			break;
 			break;
 		}
 		}
 	}
 	}
 
 
 	compact_inbuf(hp, packet);
 	compact_inbuf(hp, packet);
 
 
+	if (flip)
+		tty_flip_buffer_push(tty);
+
 	return 1;
 	return 1;
 }
 }
 
 
-static void hvsi_send_overflow(struct hvsi_struct *hp)
+static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)
 {
 {
 	pr_debug("%s: delivering %i bytes overflow\n", __func__,
 	pr_debug("%s: delivering %i bytes overflow\n", __func__,
 			hp->n_throttle);
 			hp->n_throttle);
 
 
-	hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
+	hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);
 	hp->n_throttle = 0;
 	hp->n_throttle = 0;
 }
 }
 
 
@@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)
 static irqreturn_t hvsi_interrupt(int irq, void *arg)
 static irqreturn_t hvsi_interrupt(int irq, void *arg)
 {
 {
 	struct hvsi_struct *hp = (struct hvsi_struct *)arg;
 	struct hvsi_struct *hp = (struct hvsi_struct *)arg;
-	struct tty_struct *flip;
-	struct tty_struct *hangup;
 	struct hvsi_struct *handshake;
 	struct hvsi_struct *handshake;
+	struct tty_struct *tty;
 	unsigned long flags;
 	unsigned long flags;
 	int again = 1;
 	int again = 1;
 
 
 	pr_debug("%s\n", __func__);
 	pr_debug("%s\n", __func__);
 
 
+	tty = tty_port_tty_get(&hp->port);
+
 	while (again) {
 	while (again) {
 		spin_lock_irqsave(&hp->lock, flags);
 		spin_lock_irqsave(&hp->lock, flags);
-		again = hvsi_load_chunk(hp, &flip, &hangup, &handshake);
+		again = hvsi_load_chunk(hp, tty, &handshake);
 		spin_unlock_irqrestore(&hp->lock, flags);
 		spin_unlock_irqrestore(&hp->lock, flags);
 
 
-		/*
-		 * we have to call tty_flip_buffer_push() and tty_hangup() outside our
-		 * spinlock. But we also have to keep going until we've read all the
-		 * available data.
-		 */
-
-		if (flip) {
-			/* there was data put in the tty flip buffer */
-			tty_flip_buffer_push(flip);
-			flip = NULL;
-		}
-
-		if (hangup) {
-			tty_hangup(hangup);
-		}
-
 		if (handshake) {
 		if (handshake) {
 			pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
 			pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
 			schedule_work(&handshake->handshaker);
 			schedule_work(&handshake->handshaker);
@@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
 	}
 	}
 
 
 	spin_lock_irqsave(&hp->lock, flags);
 	spin_lock_irqsave(&hp->lock, flags);
-	if (hp->tty && hp->n_throttle
-			&& (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
-		/* we weren't hung up and we weren't throttled, so we can deliver the
-		 * rest now */
-		flip = hp->tty;
-		hvsi_send_overflow(hp);
+	if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
+		/* we weren't hung up and we weren't throttled, so we can
+		 * deliver the rest now */
+		hvsi_send_overflow(hp, tty);
+		tty_flip_buffer_push(tty);
 	}
 	}
 	spin_unlock_irqrestore(&hp->lock, flags);
 	spin_unlock_irqrestore(&hp->lock, flags);
 
 
-	if (flip) {
-		tty_flip_buffer_push(flip);
-	}
+	tty_kref_put(tty);
 
 
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
@@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
 	if (hp->state == HVSI_FSP_DIED)
 	if (hp->state == HVSI_FSP_DIED)
 		return -EIO;
 		return -EIO;
 
 
+	tty_port_tty_set(&hp->port, tty);
 	spin_lock_irqsave(&hp->lock, flags);
 	spin_lock_irqsave(&hp->lock, flags);
-	hp->tty = tty;
-	hp->count++;
+	hp->port.count++;
 	atomic_set(&hp->seqno, 0);
 	atomic_set(&hp->seqno, 0);
 	h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
 	h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
 	spin_unlock_irqrestore(&hp->lock, flags);
 	spin_unlock_irqrestore(&hp->lock, flags);
@@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
 
 
 	spin_lock_irqsave(&hp->lock, flags);
 	spin_lock_irqsave(&hp->lock, flags);
 
 
-	if (--hp->count == 0) {
-		hp->tty = NULL;
+	if (--hp->port.count == 0) {
+		tty_port_tty_set(&hp->port, NULL);
 		hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
 		hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
 
 
 		/* only close down connection if it is not the console */
 		/* only close down connection if it is not the console */
@@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
 
 
 			spin_lock_irqsave(&hp->lock, flags);
 			spin_lock_irqsave(&hp->lock, flags);
 		}
 		}
-	} else if (hp->count < 0)
+	} else if (hp->port.count < 0)
 		printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
 		printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
-		       hp - hvsi_ports, hp->count);
+		       hp - hvsi_ports, hp->port.count);
 
 
 	spin_unlock_irqrestore(&hp->lock, flags);
 	spin_unlock_irqrestore(&hp->lock, flags);
 }
 }
@@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty)
 
 
 	pr_debug("%s\n", __func__);
 	pr_debug("%s\n", __func__);
 
 
-	spin_lock_irqsave(&hp->lock, flags);
+	tty_port_tty_set(&hp->port, NULL);
 
 
-	hp->count = 0;
+	spin_lock_irqsave(&hp->lock, flags);
+	hp->port.count = 0;
 	hp->n_outbuf = 0;
 	hp->n_outbuf = 0;
-	hp->tty = NULL;
-
 	spin_unlock_irqrestore(&hp->lock, flags);
 	spin_unlock_irqrestore(&hp->lock, flags);
 }
 }
 
 
@@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work)
 {
 {
 	struct hvsi_struct *hp =
 	struct hvsi_struct *hp =
 		container_of(work, struct hvsi_struct, writer.work);
 		container_of(work, struct hvsi_struct, writer.work);
+	struct tty_struct *tty;
 	unsigned long flags;
 	unsigned long flags;
 #ifdef DEBUG
 #ifdef DEBUG
 	static long start_j = 0;
 	static long start_j = 0;
@@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work)
 		start_j = 0;
 		start_j = 0;
 #endif /* DEBUG */
 #endif /* DEBUG */
 		wake_up_all(&hp->emptyq);
 		wake_up_all(&hp->emptyq);
-		tty_wakeup(hp->tty);
+		tty = tty_port_tty_get(&hp->port);
+		if (tty) {
+			tty_wakeup(tty);
+			tty_kref_put(tty);
+		}
 	}
 	}
 
 
 out:
 out:
@@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty,
 	 * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
 	 * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
 	 * will see there is no room in outbuf and return.
 	 * will see there is no room in outbuf and return.
 	 */
 	 */
-	while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) {
-		int chunksize = min(count, hvsi_write_room(hp->tty));
+	while ((count > 0) && (hvsi_write_room(tty) > 0)) {
+		int chunksize = min(count, hvsi_write_room(tty));
 
 
 		BUG_ON(hp->n_outbuf < 0);
 		BUG_ON(hp->n_outbuf < 0);
 		memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
 		memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
@@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty)
 {
 {
 	struct hvsi_struct *hp = tty->driver_data;
 	struct hvsi_struct *hp = tty->driver_data;
 	unsigned long flags;
 	unsigned long flags;
-	int shouldflip = 0;
 
 
 	pr_debug("%s\n", __func__);
 	pr_debug("%s\n", __func__);
 
 
 	spin_lock_irqsave(&hp->lock, flags);
 	spin_lock_irqsave(&hp->lock, flags);
 	if (hp->n_throttle) {
 	if (hp->n_throttle) {
-		hvsi_send_overflow(hp);
-		shouldflip = 1;
+		hvsi_send_overflow(hp, tty);
+		tty_flip_buffer_push(tty);
 	}
 	}
 	spin_unlock_irqrestore(&hp->lock, flags);
 	spin_unlock_irqrestore(&hp->lock, flags);
 
 
-	if (shouldflip)
-		tty_flip_buffer_push(hp->tty);
 
 
 	h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
 	h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
 }
 }
@@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void)
 		init_waitqueue_head(&hp->emptyq);
 		init_waitqueue_head(&hp->emptyq);
 		init_waitqueue_head(&hp->stateq);
 		init_waitqueue_head(&hp->stateq);
 		spin_lock_init(&hp->lock);
 		spin_lock_init(&hp->lock);
+		tty_port_init(&hp->port);
 		hp->index = hvsi_count;
 		hp->index = hvsi_count;
 		hp->inbuf_end = hp->inbuf;
 		hp->inbuf_end = hp->inbuf;
 		hp->state = HVSI_CLOSED;
 		hp->state = HVSI_CLOSED;

+ 1 - 1
drivers/tty/hvc/hvsi_lib.c

@@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
 	pr_devel("HVSI@%x: open !\n", pv->termno);
 	pr_devel("HVSI@%x: open !\n", pv->termno);
 
 
 	/* Keep track of the tty data structure */
 	/* Keep track of the tty data structure */
-	pv->tty = tty_kref_get(hp->tty);
+	pv->tty = tty_port_tty_get(&hp->port);
 
 
 	hvsilib_establish(pv);
 	hvsilib_establish(pv);
 
 

+ 35 - 46
drivers/tty/ipwireless/tty.c

@@ -44,14 +44,13 @@
 #define TTYTYPE_RAS_RAW  (2)
 #define TTYTYPE_RAS_RAW  (2)
 
 
 struct ipw_tty {
 struct ipw_tty {
+	struct tty_port port;
 	int index;
 	int index;
 	struct ipw_hardware *hardware;
 	struct ipw_hardware *hardware;
 	unsigned int channel_idx;
 	unsigned int channel_idx;
 	unsigned int secondary_channel_idx;
 	unsigned int secondary_channel_idx;
 	int tty_type;
 	int tty_type;
 	struct ipw_network *network;
 	struct ipw_network *network;
-	struct tty_struct *linux_tty;
-	int open_count;
 	unsigned int control_lines;
 	unsigned int control_lines;
 	struct mutex ipw_tty_mutex;
 	struct mutex ipw_tty_mutex;
 	int tx_bytes_queued;
 	int tx_bytes_queued;
@@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type)
 	return channel_names[tty_type];
 	return channel_names[tty_type];
 }
 }
 
 
-static void report_registering(struct ipw_tty *tty)
-{
-	char *iftype = tty_type_name(tty->tty_type);
-
-	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
-	       ": registering %s device ttyIPWp%d\n", iftype, tty->index);
-}
-
-static void report_deregistering(struct ipw_tty *tty)
-{
-	char *iftype = tty_type_name(tty->tty_type);
-
-	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
-	       ": deregistering %s device ttyIPWp%d\n", iftype,
-	       tty->index);
-}
-
 static struct ipw_tty *get_tty(int index)
 static struct ipw_tty *get_tty(int index)
 {
 {
 	/*
 	/*
@@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
 		mutex_unlock(&tty->ipw_tty_mutex);
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
-	if (tty->open_count == 0)
+	if (tty->port.count == 0)
 		tty->tx_bytes_queued = 0;
 		tty->tx_bytes_queued = 0;
 
 
-	tty->open_count++;
+	tty->port.count++;
 
 
-	tty->linux_tty = linux_tty;
+	tty->port.tty = linux_tty;
 	linux_tty->driver_data = tty;
 	linux_tty->driver_data = tty;
 	linux_tty->low_latency = 1;
 	linux_tty->low_latency = 1;
 
 
@@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
 
 
 static void do_ipw_close(struct ipw_tty *tty)
 static void do_ipw_close(struct ipw_tty *tty)
 {
 {
-	tty->open_count--;
+	tty->port.count--;
 
 
-	if (tty->open_count == 0) {
-		struct tty_struct *linux_tty = tty->linux_tty;
+	if (tty->port.count == 0) {
+		struct tty_struct *linux_tty = tty->port.tty;
 
 
 		if (linux_tty != NULL) {
 		if (linux_tty != NULL) {
-			tty->linux_tty = NULL;
+			tty->port.tty = NULL;
 			linux_tty->driver_data = NULL;
 			linux_tty->driver_data = NULL;
 
 
 			if (tty->tty_type == TTYTYPE_MODEM)
 			if (tty->tty_type == TTYTYPE_MODEM)
@@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty)
 		return;
 		return;
 
 
 	mutex_lock(&tty->ipw_tty_mutex);
 	mutex_lock(&tty->ipw_tty_mutex);
-	if (tty->open_count == 0) {
+	if (tty->port.count == 0) {
 		mutex_unlock(&tty->ipw_tty_mutex);
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return;
 		return;
 	}
 	}
@@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
 	int work = 0;
 	int work = 0;
 
 
 	mutex_lock(&tty->ipw_tty_mutex);
 	mutex_lock(&tty->ipw_tty_mutex);
-	linux_tty = tty->linux_tty;
+	linux_tty = tty->port.tty;
 	if (linux_tty == NULL) {
 	if (linux_tty == NULL) {
 		mutex_unlock(&tty->ipw_tty_mutex);
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return;
 		return;
 	}
 	}
 
 
-	if (!tty->open_count) {
+	if (!tty->port.count) {
 		mutex_unlock(&tty->ipw_tty_mutex);
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return;
 		return;
 	}
 	}
@@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty,
 		return -ENODEV;
 		return -ENODEV;
 
 
 	mutex_lock(&tty->ipw_tty_mutex);
 	mutex_lock(&tty->ipw_tty_mutex);
-	if (!tty->open_count) {
+	if (!tty->port.count) {
 		mutex_unlock(&tty->ipw_tty_mutex);
 		mutex_unlock(&tty->ipw_tty_mutex);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
 	if (!tty)
 	if (!tty)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
 	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
@@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
 	if (!tty)
 	if (!tty)
 		return 0;
 		return 0;
 
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return 0;
 		return 0;
 
 
 	return tty->tx_bytes_queued;
 	return tty->tx_bytes_queued;
@@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty)
 	if (!tty)
 	if (!tty)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	return get_control_lines(tty);
 	return get_control_lines(tty);
@@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty,
 	if (!tty)
 	if (!tty)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	return set_control_lines(tty, set, clear);
 	return set_control_lines(tty, set, clear);
@@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty,
 	if (!tty)
 	if (!tty)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (!tty->open_count)
+	if (!tty->port.count)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	/* FIXME: Exactly how is the tty object locked here .. */
 	/* FIXME: Exactly how is the tty object locked here .. */
@@ -492,6 +474,7 @@ static int add_tty(int j,
 	ttys[j]->network = network;
 	ttys[j]->network = network;
 	ttys[j]->tty_type = tty_type;
 	ttys[j]->tty_type = tty_type;
 	mutex_init(&ttys[j]->ipw_tty_mutex);
 	mutex_init(&ttys[j]->ipw_tty_mutex);
+	tty_port_init(&ttys[j]->port);
 
 
 	tty_register_device(ipw_tty_driver, j, NULL);
 	tty_register_device(ipw_tty_driver, j, NULL);
 	ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
 	ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
@@ -500,8 +483,12 @@ static int add_tty(int j,
 		ipwireless_associate_network_tty(network,
 		ipwireless_associate_network_tty(network,
 						 secondary_channel_idx,
 						 secondary_channel_idx,
 						 ttys[j]);
 						 ttys[j]);
-	if (get_tty(j) == ttys[j])
-		report_registering(ttys[j]);
+	/* check if we provide raw device (if loopback is enabled) */
+	if (get_tty(j))
+		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
+		       ": registering %s device ttyIPWp%d\n",
+		       tty_type_name(tty_type), j);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty)
 
 
 		if (ttyj) {
 		if (ttyj) {
 			mutex_lock(&ttyj->ipw_tty_mutex);
 			mutex_lock(&ttyj->ipw_tty_mutex);
-			if (get_tty(j) == ttyj)
-				report_deregistering(ttyj);
+			if (get_tty(j))
+				printk(KERN_INFO IPWIRELESS_PCCARD_NAME
+				       ": deregistering %s device ttyIPWp%d\n",
+				       tty_type_name(ttyj->tty_type), j);
 			ttyj->closing = 1;
 			ttyj->closing = 1;
-			if (ttyj->linux_tty != NULL) {
+			if (ttyj->port.tty != NULL) {
 				mutex_unlock(&ttyj->ipw_tty_mutex);
 				mutex_unlock(&ttyj->ipw_tty_mutex);
-				tty_hangup(ttyj->linux_tty);
-				/* Wait till the tty_hangup has completed */
-				flush_work_sync(&ttyj->linux_tty->hangup_work);
+				tty_vhangup(ttyj->port.tty);
 				/* FIXME: Exactly how is the tty object locked here
 				/* FIXME: Exactly how is the tty object locked here
 				   against a parallel ioctl etc */
 				   against a parallel ioctl etc */
+				/* FIXME2: hangup does not mean all processes
+				 * are gone */
 				mutex_lock(&ttyj->ipw_tty_mutex);
 				mutex_lock(&ttyj->ipw_tty_mutex);
 			}
 			}
-			while (ttyj->open_count)
+			while (ttyj->port.count)
 				do_ipw_close(ttyj);
 				do_ipw_close(ttyj);
 			ipwireless_disassociate_network_ttys(network,
 			ipwireless_disassociate_network_ttys(network,
 							     ttyj->channel_idx);
 							     ttyj->channel_idx);
@@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
 	 */
 	 */
 	if ((old_control_lines & IPW_CONTROL_LINE_DCD)
 	if ((old_control_lines & IPW_CONTROL_LINE_DCD)
 			&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
 			&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
-			&& tty->linux_tty) {
-		tty_hangup(tty->linux_tty);
+			&& tty->port.tty) {
+		tty_hangup(tty->port.tty);
 	}
 	}
 }
 }
 
 

+ 1 - 1
drivers/tty/mxser.c

@@ -2326,7 +2326,7 @@ static const struct tty_operations mxser_ops = {
 	.get_icount = mxser_get_icount,
 	.get_icount = mxser_get_icount,
 };
 };
 
 
-struct tty_port_operations mxser_port_ops = {
+static struct tty_port_operations mxser_port_ops = {
 	.carrier_raised = mxser_carrier_raised,
 	.carrier_raised = mxser_carrier_raised,
 	.dtr_rts = mxser_dtr_rts,
 	.dtr_rts = mxser_dtr_rts,
 	.activate = mxser_activate,
 	.activate = mxser_activate,

+ 6 - 5
drivers/tty/n_r3964.c

@@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 
 
 	TRACE_L("read()");
 	TRACE_L("read()");
 
 
-	tty_lock();
+	/* FIXME: should use a private lock */
+	tty_lock(tty);
 
 
 	pClient = findClient(pInfo, task_pid(current));
 	pClient = findClient(pInfo, task_pid(current));
 	if (pClient) {
 	if (pClient) {
@@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 				goto unlock;
 				goto unlock;
 			}
 			}
 			/* block until there is a message: */
 			/* block until there is a message: */
-			wait_event_interruptible_tty(pInfo->read_wait,
+			wait_event_interruptible_tty(tty, pInfo->read_wait,
 					(pMsg = remove_msg(pInfo, pClient)));
 					(pMsg = remove_msg(pInfo, pClient)));
 		}
 		}
 
 
@@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 	}
 	}
 	ret = -EPERM;
 	ret = -EPERM;
 unlock:
 unlock:
-	tty_unlock();
+	tty_unlock(tty);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
 	pHeader->locks = 0;
 	pHeader->locks = 0;
 	pHeader->owner = NULL;
 	pHeader->owner = NULL;
 
 
-	tty_lock();
+	tty_lock(tty);
 
 
 	pClient = findClient(pInfo, task_pid(current));
 	pClient = findClient(pInfo, task_pid(current));
 	if (pClient) {
 	if (pClient) {
@@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
 	add_tx_queue(pInfo, pHeader);
 	add_tx_queue(pInfo, pHeader);
 	trigger_transmit(pInfo);
 	trigger_transmit(pInfo);
 
 
-	tty_unlock();
+	tty_unlock(tty);
 
 
 	return 0;
 	return 0;
 }
 }

+ 5 - 4
drivers/tty/n_tty.c

@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
 	int retval;
 	int retval;
 	size_t n;
 	size_t n;
 	unsigned long flags;
 	unsigned long flags;
+	bool is_eof;
 
 
 	retval = 0;
 	retval = 0;
 	spin_lock_irqsave(&tty->read_lock, flags);
 	spin_lock_irqsave(&tty->read_lock, flags);
@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty,
 	if (n) {
 	if (n) {
 		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
 		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
 		n -= retval;
 		n -= retval;
+		is_eof = n == 1 &&
+			tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
 		tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
 		tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
 		spin_lock_irqsave(&tty->read_lock, flags);
 		spin_lock_irqsave(&tty->read_lock, flags);
 		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
 		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
 		tty->read_cnt -= n;
 		tty->read_cnt -= n;
 		/* Turn single EOF into zero-length read */
 		/* Turn single EOF into zero-length read */
-		if (L_EXTPROC(tty) && tty->icanon && n == 1) {
-			if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
-				n--;
-		}
+		if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
+			n = 0;
 		spin_unlock_irqrestore(&tty->read_lock, flags);
 		spin_unlock_irqrestore(&tty->read_lock, flags);
 		*b += n;
 		*b += n;
 		*nr -= n;
 		*nr -= n;

+ 28 - 12
drivers/tty/pty.c

@@ -26,11 +26,13 @@
 #include <linux/bitops.h>
 #include <linux/bitops.h>
 #include <linux/devpts_fs.h>
 #include <linux/devpts_fs.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 
 
 
 
 #ifdef CONFIG_UNIX98_PTYS
 #ifdef CONFIG_UNIX98_PTYS
 static struct tty_driver *ptm_driver;
 static struct tty_driver *ptm_driver;
 static struct tty_driver *pts_driver;
 static struct tty_driver *pts_driver;
+static DEFINE_MUTEX(devpts_mutex);
 #endif
 #endif
 
 
 static void pty_close(struct tty_struct *tty, struct file *filp)
 static void pty_close(struct tty_struct *tty, struct file *filp)
@@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 	wake_up_interruptible(&tty->read_wait);
 	wake_up_interruptible(&tty->read_wait);
 	wake_up_interruptible(&tty->write_wait);
 	wake_up_interruptible(&tty->write_wait);
 	tty->packet = 0;
 	tty->packet = 0;
+	/* Review - krefs on tty_link ?? */
 	if (!tty->link)
 	if (!tty->link)
 		return;
 		return;
 	tty->link->packet = 0;
 	tty->link->packet = 0;
@@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 	if (tty->driver->subtype == PTY_TYPE_MASTER) {
 	if (tty->driver->subtype == PTY_TYPE_MASTER) {
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
 #ifdef CONFIG_UNIX98_PTYS
-		if (tty->driver == ptm_driver)
+		if (tty->driver == ptm_driver) {
+		        mutex_lock(&devpts_mutex);
 			devpts_pty_kill(tty->link);
 			devpts_pty_kill(tty->link);
+		        mutex_unlock(&devpts_mutex);
+		}
 #endif
 #endif
-		tty_unlock();
+		tty_unlock(tty);
 		tty_vhangup(tty->link);
 		tty_vhangup(tty->link);
-		tty_lock();
+		tty_lock(tty);
 	}
 	}
 }
 }
 
 
@@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
  *	@idx: tty index
  *	@idx: tty index
  *
  *
  *	Look up a pty master device. Called under the tty_mutex for now.
  *	Look up a pty master device. Called under the tty_mutex for now.
- *	This provides our locking.
+ *	This provides our locking for the tty pointer.
  */
  */
 
 
 static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
 static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
 		struct inode *pts_inode, int idx)
 		struct inode *pts_inode, int idx)
 {
 {
-	struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+	struct tty_struct *tty;
+
+	mutex_lock(&devpts_mutex);
+	tty = devpts_get_tty(pts_inode, idx);
+	mutex_unlock(&devpts_mutex);
 	/* Master must be open before slave */
 	/* Master must be open before slave */
 	if (!tty)
 	if (!tty)
 		return ERR_PTR(-EIO);
 		return ERR_PTR(-EIO);
@@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 		return retval;
 		return retval;
 
 
 	/* find a device that is not in use. */
 	/* find a device that is not in use. */
-	tty_lock();
+	mutex_lock(&devpts_mutex);
 	index = devpts_new_index(inode);
 	index = devpts_new_index(inode);
-	tty_unlock();
 	if (index < 0) {
 	if (index < 0) {
 		retval = index;
 		retval = index;
 		goto err_file;
 		goto err_file;
 	}
 	}
 
 
+	mutex_unlock(&devpts_mutex);
+
 	mutex_lock(&tty_mutex);
 	mutex_lock(&tty_mutex);
-	tty_lock();
+	mutex_lock(&devpts_mutex);
 	tty = tty_init_dev(ptm_driver, index);
 	tty = tty_init_dev(ptm_driver, index);
-	mutex_unlock(&tty_mutex);
 
 
 	if (IS_ERR(tty)) {
 	if (IS_ERR(tty)) {
 		retval = PTR_ERR(tty);
 		retval = PTR_ERR(tty);
 		goto out;
 		goto out;
 	}
 	}
 
 
+	/* The tty returned here is locked so we can safely
+	   drop the mutex */
+	mutex_unlock(&devpts_mutex);
+	mutex_unlock(&tty_mutex);
+
 	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 
 
 	tty_add_file(tty, filp);
 	tty_add_file(tty, filp);
@@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 	if (retval)
 	if (retval)
 		goto err_release;
 		goto err_release;
 
 
-	tty_unlock();
+	tty_unlock(tty);
 	return 0;
 	return 0;
 err_release:
 err_release:
-	tty_unlock();
+	tty_unlock(tty);
 	tty_release(inode, filp);
 	tty_release(inode, filp);
 	return retval;
 	return retval;
 out:
 out:
+	mutex_unlock(&tty_mutex);
 	devpts_kill_index(inode, index);
 	devpts_kill_index(inode, index);
-	tty_unlock();
 err_file:
 err_file:
+        mutex_unlock(&devpts_mutex);
 	tty_free_file(filp);
 	tty_free_file(filp);
 	return retval;
 	return retval;
 }
 }

+ 152 - 231
drivers/tty/serial/68328serial.c

@@ -17,6 +17,7 @@
 #include <asm/dbg.h>
 #include <asm/dbg.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
+#include <linux/serial.h>
 #include <linux/signal.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/timer.h>
@@ -56,8 +57,6 @@
 #endif /* CONFIG_M68VZ328 */
 #endif /* CONFIG_M68VZ328 */
 #endif /* CONFIG_M68EZ328 */
 #endif /* CONFIG_M68EZ328 */
 
 
-#include "68328serial.h"
-
 /* Turn off usage of real serial interrupt code, to "support" Copilot */
 /* Turn off usage of real serial interrupt code, to "support" Copilot */
 #ifdef CONFIG_XCOPILOT_BUGS
 #ifdef CONFIG_XCOPILOT_BUGS
 #undef USE_INTS
 #undef USE_INTS
@@ -65,33 +64,82 @@
 #define USE_INTS
 #define USE_INTS
 #endif
 #endif
 
 
-static struct m68k_serial m68k_soft[NR_PORTS];
+/*
+ * I believe this is the optimal setting that reduces the number of interrupts.
+ * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
+ * if that bothers you), but in most cases it will not, since we try to
+ * transmit characters every time rs_interrupt is called. Thus, quite often
+ * you'll see that a receive interrupt occures before the transmit one.
+ *                                  -- Vladimir Gurevich
+ */
+#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
 
 
-static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
+/*
+ * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
+ * "Old data interrupt" which occures whenever the data stay in the FIFO
+ * longer than 30 bits time. This allows us to use FIFO without compromising
+ * latency. '328 does not have this feature and without the real  328-based
+ * board I would assume that RXRE is the safest setting.
+ *
+ * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
+ * interrupts. RXFE (receive queue full) causes the system to lose data
+ * at least at 115200 baud
+ *
+ * If your board is busy doing other stuff, you might consider to use
+ * RXRE (data ready intrrupt) instead.
+ *
+ * The other option is to make these INTR masks run-time configurable, so
+ * that people can dynamically adapt them according to the current usage.
+ *                                  -- Vladimir Gurevich
+ */
 
 
-/* multiple ports are contiguous in memory */
-m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
+/* (es) */
+#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
+#elif defined(CONFIG_M68328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
+#else
+#error Please, define the Rx interrupt events for your CPU
+#endif
+/* (/es) */
 
 
-struct tty_struct m68k_ttys;
-struct m68k_serial *m68k_consinfo = 0;
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct m68k_serial {
+	struct tty_port		tport;
+	char			is_cons;	/* Is this our console. */
+	int			magic;
+	int			baud_base;
+	int			port;
+	int			irq;
+	int			type;		/* UART type */
+	int			custom_divisor;
+	int			x_char;		/* xon/xoff character */
+	int			line;
+	unsigned char		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+};
 
 
-#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
+#define SERIAL_MAGIC 0x5301
 
 
-struct tty_driver *serial_driver;
+/*
+ * Define the number of ports supported and their irqs.
+ */
+#define NR_PORTS 1
 
 
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
+static struct m68k_serial m68k_soft[NR_PORTS];
 
 
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
+static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM };
 
 
-#define RS_ISR_PASS_LIMIT 256
+/* multiple ports are contiguous in memory */
+m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
+
+struct tty_driver *serial_driver;
 
 
-static void change_speed(struct m68k_serial *info);
+static void change_speed(struct m68k_serial *info, struct tty_struct *tty);
 
 
 /*
 /*
  *	Setup for console. Argument comes from the boot command line.
  *	Setup for console. Argument comes from the boot command line.
@@ -143,17 +191,6 @@ static int baud_table[] = {
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
 	9600, 19200, 38400, 57600, 115200, 0 };
 	9600, 19200, 38400, 57600, 115200, 0 };
 
 
-/* Sets or clears DTR/RTS on the requested line */
-static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
-{
-	if (set) {
-		/* set the RTS/CTS line */
-	} else {
-		/* clear it */
-	}
-	return;
-}
-
 /* Utility routines */
 /* Utility routines */
 static inline int get_baud(struct m68k_serial *ss)
 static inline int get_baud(struct m68k_serial *ss)
 {
 {
@@ -189,7 +226,8 @@ static void rs_stop(struct tty_struct *tty)
 
 
 static int rs_put_char(char ch)
 static int rs_put_char(char ch)
 {
 {
-        int flags, loops = 0;
+	unsigned long flags;
+	int loops = 0;
 
 
         local_irq_save(flags);
         local_irq_save(flags);
 
 
@@ -224,28 +262,9 @@ static void rs_start(struct tty_struct *tty)
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 }
 }
 
 
-/* Drop into either the boot monitor or kadb upon receiving a break
- * from keyboard/console input.
- */
-static void batten_down_hatches(void)
-{
-	/* Drop into the debugger */
-}
-
-static void status_handle(struct m68k_serial *info, unsigned short status)
+static void receive_chars(struct m68k_serial *info, struct tty_struct *tty,
+		unsigned short rx)
 {
 {
-	/* If this is console input and this is a
-	 * 'break asserted' status change interrupt
-	 * see if we can drop into the debugger
-	 */
-	if((status & URX_BREAK) && info->break_abort)
-		batten_down_hatches();
-	return;
-}
-
-static void receive_chars(struct m68k_serial *info, unsigned short rx)
-{
-	struct tty_struct *tty = info->tty;
 	m68328_uart *uart = &uart_addr[info->line];
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned char ch, flag;
 	unsigned char ch, flag;
 
 
@@ -259,7 +278,6 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
 	
 	
 		if(info->is_cons) {
 		if(info->is_cons) {
 			if(URX_BREAK & rx) { /* whee, break received */
 			if(URX_BREAK & rx) { /* whee, break received */
-				status_handle(info, rx);
 				return;
 				return;
 #ifdef CONFIG_MAGIC_SYSRQ
 #ifdef CONFIG_MAGIC_SYSRQ
 			} else if (ch == 0x10) { /* ^P */
 			} else if (ch == 0x10) { /* ^P */
@@ -280,16 +298,13 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
 		
 		
 		flag = TTY_NORMAL;
 		flag = TTY_NORMAL;
 
 
-		if(rx & URX_PARITY_ERROR) {
+		if (rx & URX_PARITY_ERROR)
 			flag = TTY_PARITY;
 			flag = TTY_PARITY;
-			status_handle(info, rx);
-		} else if(rx & URX_OVRUN) {
+		else if (rx & URX_OVRUN)
 			flag = TTY_OVERRUN;
 			flag = TTY_OVERRUN;
-			status_handle(info, rx);
-		} else if(rx & URX_FRAME_ERROR) {
+		else if (rx & URX_FRAME_ERROR)
 			flag = TTY_FRAME;
 			flag = TTY_FRAME;
-			status_handle(info, rx);
-		}
+
 		tty_insert_flip_char(tty, ch, flag);
 		tty_insert_flip_char(tty, ch, flag);
 #ifndef CONFIG_XCOPILOT_BUGS
 #ifndef CONFIG_XCOPILOT_BUGS
 	} while((rx = uart->urx.w) & URX_DATA_READY);
 	} while((rx = uart->urx.w) & URX_DATA_READY);
@@ -301,7 +316,7 @@ clear_and_exit:
 	return;
 	return;
 }
 }
 
 
-static void transmit_chars(struct m68k_serial *info)
+static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
 {
 {
 	m68328_uart *uart = &uart_addr[info->line];
 	m68328_uart *uart = &uart_addr[info->line];
 
 
@@ -312,7 +327,7 @@ static void transmit_chars(struct m68k_serial *info)
 		goto clear_and_return;
 		goto clear_and_return;
 	}
 	}
 
 
-	if((info->xmit_cnt <= 0) || info->tty->stopped) {
+	if ((info->xmit_cnt <= 0) || !tty || tty->stopped) {
 		/* That's peculiar... TX ints off */
 		/* That's peculiar... TX ints off */
 		uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
 		uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
 		goto clear_and_return;
 		goto clear_and_return;
@@ -340,6 +355,7 @@ clear_and_return:
 irqreturn_t rs_interrupt(int irq, void *dev_id)
 irqreturn_t rs_interrupt(int irq, void *dev_id)
 {
 {
 	struct m68k_serial *info = dev_id;
 	struct m68k_serial *info = dev_id;
+	struct tty_struct *tty = tty_port_tty_get(&info->tport);
 	m68328_uart *uart;
 	m68328_uart *uart;
 	unsigned short rx;
 	unsigned short rx;
 	unsigned short tx;
 	unsigned short tx;
@@ -350,20 +366,24 @@ irqreturn_t rs_interrupt(int irq, void *dev_id)
 #ifdef USE_INTS
 #ifdef USE_INTS
 	tx = uart->utx.w;
 	tx = uart->utx.w;
 
 
-	if (rx & URX_DATA_READY) receive_chars(info, rx);
-	if (tx & UTX_TX_AVAIL)   transmit_chars(info);
+	if (rx & URX_DATA_READY)
+		receive_chars(info, tty, rx);
+	if (tx & UTX_TX_AVAIL)
+		transmit_chars(info, tty);
 #else
 #else
-	receive_chars(info, rx);		
+	receive_chars(info, tty, rx);
 #endif
 #endif
+	tty_kref_put(tty);
+
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
-static int startup(struct m68k_serial * info)
+static int startup(struct m68k_serial *info, struct tty_struct *tty)
 {
 {
 	m68328_uart *uart = &uart_addr[info->line];
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned long flags;
 	unsigned long flags;
 	
 	
-	if (info->flags & S_INITIALIZED)
+	if (info->tport.flags & ASYNC_INITIALIZED)
 		return 0;
 		return 0;
 
 
 	if (!info->xmit_buf) {
 	if (!info->xmit_buf) {
@@ -380,7 +400,6 @@ static int startup(struct m68k_serial * info)
 	 */
 	 */
 
 
 	uart->ustcnt = USTCNT_UEN;
 	uart->ustcnt = USTCNT_UEN;
-	info->xmit_fifo_size = 1;
 	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
 	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
 	(void)uart->urx.w;
 	(void)uart->urx.w;
 
 
@@ -394,17 +413,17 @@ static int startup(struct m68k_serial * info)
 	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
 	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
 #endif
 #endif
 
 
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (tty)
+		clear_bit(TTY_IO_ERROR, &tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
 
 	/*
 	/*
 	 * and set the speed of the serial port
 	 * and set the speed of the serial port
 	 */
 	 */
 
 
-	change_speed(info);
+	change_speed(info, tty);
 
 
-	info->flags |= S_INITIALIZED;
+	info->tport.flags |= ASYNC_INITIALIZED;
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 	return 0;
 	return 0;
 }
 }
@@ -413,13 +432,13 @@ static int startup(struct m68k_serial * info)
  * This routine will shutdown a serial port; interrupts are disabled, and
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  * DTR is dropped if the hangup on close termio flag is on.
  */
  */
-static void shutdown(struct m68k_serial * info)
+static void shutdown(struct m68k_serial *info, struct tty_struct *tty)
 {
 {
 	m68328_uart *uart = &uart_addr[info->line];
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned long	flags;
 	unsigned long	flags;
 
 
 	uart->ustcnt = 0; /* All off! */
 	uart->ustcnt = 0; /* All off! */
-	if (!(info->flags & S_INITIALIZED))
+	if (!(info->tport.flags & ASYNC_INITIALIZED))
 		return;
 		return;
 
 
 	local_irq_save(flags);
 	local_irq_save(flags);
@@ -429,10 +448,10 @@ static void shutdown(struct m68k_serial * info)
 		info->xmit_buf = 0;
 		info->xmit_buf = 0;
 	}
 	}
 
 
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (tty)
+		set_bit(TTY_IO_ERROR, &tty->flags);
 	
 	
-	info->flags &= ~S_INITIALIZED;
+	info->tport.flags &= ~ASYNC_INITIALIZED;
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 }
 }
 
 
@@ -488,7 +507,7 @@ struct {
  * This routine is called to set the UART divisor registers to match
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  * the specified baud rate for a serial port.
  */
  */
-static void change_speed(struct m68k_serial *info)
+static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
 {
 {
 	m68328_uart *uart = &uart_addr[info->line];
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned short port;
 	unsigned short port;
@@ -496,9 +515,7 @@ static void change_speed(struct m68k_serial *info)
 	unsigned cflag;
 	unsigned cflag;
 	int	i;
 	int	i;
 
 
-	if (!info->tty || !info->tty->termios)
-		return;
-	cflag = info->tty->termios->c_cflag;
+	cflag = tty->termios->c_cflag;
 	if (!(port = info->port))
 	if (!(port = info->port))
 		return;
 		return;
 
 
@@ -510,7 +527,6 @@ static void change_speed(struct m68k_serial *info)
                 i = (i & ~CBAUDEX) + B38400;
                 i = (i & ~CBAUDEX) + B38400;
         }
         }
 
 
-	info->baud = baud_table[i];
 	uart->ubaud = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
 	uart->ubaud = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
 		PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
 		PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
 
 
@@ -807,10 +823,10 @@ static int get_serial_info(struct m68k_serial * info,
 	tmp.line = info->line;
 	tmp.line = info->line;
 	tmp.port = info->port;
 	tmp.port = info->port;
 	tmp.irq = info->irq;
 	tmp.irq = info->irq;
-	tmp.flags = info->flags;
+	tmp.flags = info->tport.flags;
 	tmp.baud_base = info->baud_base;
 	tmp.baud_base = info->baud_base;
-	tmp.close_delay = info->close_delay;
-	tmp.closing_wait = info->closing_wait;
+	tmp.close_delay = info->tport.close_delay;
+	tmp.closing_wait = info->tport.closing_wait;
 	tmp.custom_divisor = info->custom_divisor;
 	tmp.custom_divisor = info->custom_divisor;
 	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
 	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
 		return -EFAULT;
 		return -EFAULT;
@@ -818,9 +834,10 @@ static int get_serial_info(struct m68k_serial * info,
 	return 0;
 	return 0;
 }
 }
 
 
-static int set_serial_info(struct m68k_serial * info,
+static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,
 			   struct serial_struct * new_info)
 			   struct serial_struct * new_info)
 {
 {
+	struct tty_port *port = &info->tport;
 	struct serial_struct new_serial;
 	struct serial_struct new_serial;
 	struct m68k_serial old_info;
 	struct m68k_serial old_info;
 	int 			retval = 0;
 	int 			retval = 0;
@@ -834,17 +851,17 @@ static int set_serial_info(struct m68k_serial * info,
 	if (!capable(CAP_SYS_ADMIN)) {
 	if (!capable(CAP_SYS_ADMIN)) {
 		if ((new_serial.baud_base != info->baud_base) ||
 		if ((new_serial.baud_base != info->baud_base) ||
 		    (new_serial.type != info->type) ||
 		    (new_serial.type != info->type) ||
-		    (new_serial.close_delay != info->close_delay) ||
-		    ((new_serial.flags & ~S_USR_MASK) !=
-		     (info->flags & ~S_USR_MASK)))
+		    (new_serial.close_delay != port->close_delay) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (port->flags & ~ASYNC_USR_MASK)))
 			return -EPERM;
 			return -EPERM;
-		info->flags = ((info->flags & ~S_USR_MASK) |
-			       (new_serial.flags & S_USR_MASK));
+		port->flags = ((port->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
 		info->custom_divisor = new_serial.custom_divisor;
 		info->custom_divisor = new_serial.custom_divisor;
 		goto check_and_exit;
 		goto check_and_exit;
 	}
 	}
 
 
-	if (info->count > 1)
+	if (port->count > 1)
 		return -EBUSY;
 		return -EBUSY;
 
 
 	/*
 	/*
@@ -853,14 +870,14 @@ static int set_serial_info(struct m68k_serial * info,
 	 */
 	 */
 
 
 	info->baud_base = new_serial.baud_base;
 	info->baud_base = new_serial.baud_base;
-	info->flags = ((info->flags & ~S_FLAGS) |
-			(new_serial.flags & S_FLAGS));
+	port->flags = ((port->flags & ~ASYNC_FLAGS) |
+			(new_serial.flags & ASYNC_FLAGS));
 	info->type = new_serial.type;
 	info->type = new_serial.type;
-	info->close_delay = new_serial.close_delay;
-	info->closing_wait = new_serial.closing_wait;
+	port->close_delay = new_serial.close_delay;
+	port->closing_wait = new_serial.closing_wait;
 
 
 check_and_exit:
 check_and_exit:
-	retval = startup(info);
+	retval = startup(info, tty);
 	return retval;
 	return retval;
 }
 }
 
 
@@ -946,7 +963,7 @@ static int rs_ioctl(struct tty_struct *tty,
 			return get_serial_info(info,
 			return get_serial_info(info,
 				       (struct serial_struct *) arg);
 				       (struct serial_struct *) arg);
 		case TIOCSSERIAL:
 		case TIOCSSERIAL:
-			return set_serial_info(info,
+			return set_serial_info(info, tty,
 					       (struct serial_struct *) arg);
 					       (struct serial_struct *) arg);
 		case TIOCSERGETLSR: /* Get line status register */
 		case TIOCSERGETLSR: /* Get line status register */
 			return get_lsr_info(info, (unsigned int *) arg);
 			return get_lsr_info(info, (unsigned int *) arg);
@@ -965,7 +982,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
 {
 	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
 	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
 
 
-	change_speed(info);
+	change_speed(info, tty);
 
 
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	    !(tty->termios->c_cflag & CRTSCTS)) {
 	    !(tty->termios->c_cflag & CRTSCTS)) {
@@ -988,6 +1005,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 static void rs_close(struct tty_struct *tty, struct file * filp)
 static void rs_close(struct tty_struct *tty, struct file * filp)
 {
 {
 	struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
 	struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+	struct tty_port *port = &info->tport;
 	m68328_uart *uart = &uart_addr[info->line];
 	m68328_uart *uart = &uart_addr[info->line];
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -1001,7 +1019,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 		return;
 		return;
 	}
 	}
 	
 	
-	if ((tty->count == 1) && (info->count != 1)) {
+	if ((tty->count == 1) && (port->count != 1)) {
 		/*
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * Uh, oh.  tty->count is 1, which means that the tty
 		 * structure will be freed.  Info->count should always
 		 * structure will be freed.  Info->count should always
@@ -1010,26 +1028,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 		 * serial port won't be shutdown.
 		 * serial port won't be shutdown.
 		 */
 		 */
 		printk("rs_close: bad serial port count; tty->count is 1, "
 		printk("rs_close: bad serial port count; tty->count is 1, "
-		       "info->count is %d\n", info->count);
-		info->count = 1;
+		       "port->count is %d\n", port->count);
+		port->count = 1;
 	}
 	}
-	if (--info->count < 0) {
+	if (--port->count < 0) {
 		printk("rs_close: bad serial port count for ttyS%d: %d\n",
 		printk("rs_close: bad serial port count for ttyS%d: %d\n",
-		       info->line, info->count);
-		info->count = 0;
+		       info->line, port->count);
+		port->count = 0;
 	}
 	}
-	if (info->count) {
+	if (port->count) {
 		local_irq_restore(flags);
 		local_irq_restore(flags);
 		return;
 		return;
 	}
 	}
-	info->flags |= S_CLOSING;
+	port->flags |= ASYNC_CLOSING;
 	/*
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	 */
 	tty->closing = 1;
 	tty->closing = 1;
-	if (info->closing_wait != S_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
+	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, port->closing_wait);
 	/*
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
 	 * disable the receive line status interrupts, and tell the
@@ -1040,13 +1058,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 	uart->ustcnt &= ~USTCNT_RXEN;
 	uart->ustcnt &= ~USTCNT_RXEN;
 	uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
 	uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
 
 
-	shutdown(info);
+	shutdown(info, tty);
 	rs_flush_buffer(tty);
 	rs_flush_buffer(tty);
 		
 		
 	tty_ldisc_flush(tty);
 	tty_ldisc_flush(tty);
 	tty->closing = 0;
 	tty->closing = 0;
-	info->event = 0;
-	info->tty = NULL;
+	tty_port_tty_set(&info->tport, NULL);
 #warning "This is not and has never been valid so fix it"	
 #warning "This is not and has never been valid so fix it"	
 #if 0
 #if 0
 	if (tty->ldisc.num != ldiscs[N_TTY].num) {
 	if (tty->ldisc.num != ldiscs[N_TTY].num) {
@@ -1058,14 +1075,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 			(tty->ldisc.open)(tty);
 			(tty->ldisc.open)(tty);
 	}
 	}
 #endif	
 #endif	
-	if (info->blocked_open) {
-		if (info->close_delay) {
-			msleep_interruptible(jiffies_to_msecs(info->close_delay));
-		}
-		wake_up_interruptible(&info->open_wait);
+	if (port->blocked_open) {
+		if (port->close_delay)
+			msleep_interruptible(jiffies_to_msecs(port->close_delay));
+		wake_up_interruptible(&port->open_wait);
 	}
 	}
-	info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
-	wake_up_interruptible(&info->close_wait);
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+	wake_up_interruptible(&port->close_wait);
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 }
 }
 
 
@@ -1080,106 +1096,13 @@ void rs_hangup(struct tty_struct *tty)
 		return;
 		return;
 	
 	
 	rs_flush_buffer(tty);
 	rs_flush_buffer(tty);
-	shutdown(info);
-	info->event = 0;
-	info->count = 0;
-	info->flags &= ~S_NORMAL_ACTIVE;
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
+	shutdown(info, tty);
+	info->tport.count = 0;
+	info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
+	tty_port_tty_set(&info->tport, NULL);
+	wake_up_interruptible(&info->tport.open_wait);
 }
 }
 
 
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
-			   struct m68k_serial *info)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	int		retval;
-	int		do_clocal = 0;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * until it's done, and then try again.
-	 */
-	if (info->flags & S_CLOSING) {
-		interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		if (info->flags & S_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-	
-	/*
-	 * If non-blocking mode is set, or the port is not enabled,
-	 * then make the check up front and then exit.
-	 */
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		info->flags |= S_NORMAL_ACTIVE;
-		return 0;
-	}
-
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
-
-	/*
-	 * Block waiting for the carrier detect and the line to become
-	 * free (i.e., not in use by the callout).  While we are in
-	 * this loop, info->count is dropped by one, so that
-	 * rs_close() knows when to free things.  We restore it upon
-	 * exit, either normal or abnormal.
-	 */
-	retval = 0;
-	add_wait_queue(&info->open_wait, &wait);
-
-	info->count--;
-	info->blocked_open++;
-	while (1) {
-		local_irq_disable();
-		m68k_rtsdtr(info, 1);
-		local_irq_enable();
-		current->state = TASK_INTERRUPTIBLE;
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & S_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-			if (info->flags & S_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;	
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & S_CLOSING) && do_clocal)
-			break;
-                if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-		tty_unlock();
-		schedule();
-		tty_lock();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-
-	if (retval)
-		return retval;
-	info->flags |= S_NORMAL_ACTIVE;
-	return 0;
-}	
-
 /*
 /*
  * This routine is called whenever a serial port is opened.  It
  * This routine is called whenever a serial port is opened.  It
  * enables interrupts for a serial port, linking in its S structure into
  * enables interrupts for a serial port, linking in its S structure into
@@ -1196,18 +1119,18 @@ int rs_open(struct tty_struct *tty, struct file * filp)
 	if (serial_paranoia_check(info, tty->name, "rs_open"))
 	if (serial_paranoia_check(info, tty->name, "rs_open"))
 		return -ENODEV;
 		return -ENODEV;
 
 
-	info->count++;
+	info->tport.count++;
 	tty->driver_data = info;
 	tty->driver_data = info;
-	info->tty = tty;
+	tty_port_tty_set(&info->tport, tty);
 
 
 	/*
 	/*
 	 * Start up serial port
 	 * Start up serial port
 	 */
 	 */
-	retval = startup(info);
+	retval = startup(info, tty);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
-	return block_til_ready(tty, filp, info);
+	return tty_port_block_til_ready(&info->tport, tty, filp);
 }
 }
 
 
 /* Finally, routines used to initialize the serial driver. */
 /* Finally, routines used to initialize the serial driver. */
@@ -1235,11 +1158,15 @@ static const struct tty_operations rs_ops = {
 	.set_ldisc = rs_set_ldisc,
 	.set_ldisc = rs_set_ldisc,
 };
 };
 
 
+static const struct tty_port_operations rs_port_ops = {
+};
+
 /* rs_init inits the driver */
 /* rs_init inits the driver */
 static int __init
 static int __init
 rs68328_init(void)
 rs68328_init(void)
 {
 {
-	int flags, i;
+	unsigned long flags;
+	int i;
 	struct m68k_serial *info;
 	struct m68k_serial *info;
 
 
 	serial_driver = alloc_tty_driver(NR_PORTS);
 	serial_driver = alloc_tty_driver(NR_PORTS);
@@ -1273,19 +1200,13 @@ rs68328_init(void)
 	for(i=0;i<NR_PORTS;i++) {
 	for(i=0;i<NR_PORTS;i++) {
 
 
 	    info = &m68k_soft[i];
 	    info = &m68k_soft[i];
+	    tty_port_init(&info->tport);
+	    info->tport.ops = &rs_port_ops;
 	    info->magic = SERIAL_MAGIC;
 	    info->magic = SERIAL_MAGIC;
 	    info->port = (int) &uart_addr[i];
 	    info->port = (int) &uart_addr[i];
-	    info->tty = NULL;
 	    info->irq = uart_irqs[i];
 	    info->irq = uart_irqs[i];
 	    info->custom_divisor = 16;
 	    info->custom_divisor = 16;
-	    info->close_delay = 50;
-	    info->closing_wait = 3000;
 	    info->x_char = 0;
 	    info->x_char = 0;
-	    info->event = 0;
-	    info->count = 0;
-	    info->blocked_open = 0;
-	    init_waitqueue_head(&info->open_wait);
-	    init_waitqueue_head(&info->close_wait);
 	    info->line = i;
 	    info->line = i;
 	    info->is_cons = 1; /* Means shortcuts work */
 	    info->is_cons = 1; /* Means shortcuts work */
 	    
 	    

+ 0 - 186
drivers/tty/serial/68328serial.h

@@ -1,186 +0,0 @@
-/* 68328serial.h: Definitions for the mc68328 serial driver.
- *
- * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
- * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
- * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
- *
- * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
- */
-
-#ifndef _MC683XX_SERIAL_H
-#define _MC683XX_SERIAL_H
-
-
-struct serial_struct {
-	int	type;
-	int	line;
-	int	port;
-	int	irq;
-	int	flags;
-	int	xmit_fifo_size;
-	int	custom_divisor;
-	int	baud_base;
-	unsigned short	close_delay;
-	char	reserved_char[2];
-	int	hub6;  /* FIXME: We don't have AT&T Hub6 boards! */
-	unsigned short	closing_wait; /* time to wait before closing */
-	unsigned short	closing_wait2; /* no longer used... */
-	int	reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define S_CLOSING_WAIT_INF	0
-#define S_CLOSING_WAIT_NONE	65535
-
-/*
- * Definitions for S_struct (and serial_struct) flags field
- */
-#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
-				   on the callout port */
-#define S_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
-#define S_SAK	0x0004	/* Secure Attention Key (Orange book) */
-#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define S_SPD_MASK	0x0030
-#define S_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
-
-#define S_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
-#define S_SPD_CUST	0x0030  /* Use user-specified divisor */
-
-#define S_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
-#define S_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define S_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define S_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define S_FLAGS	0x0FFF	/* Possible legal S flags */
-#define S_USR_MASK 0x0430	/* Legal flags that non-privileged
-				 * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define S_INITIALIZED	0x80000000 /* Serial port was initialized */
-#define S_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
-#define S_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
-#define S_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
-#define S_CLOSING		0x08000000 /* Serial port is closing */
-#define S_CTS_FLOW		0x04000000 /* Do CTS flow control */
-#define S_CHECK_CD		0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-
-/*
- * I believe this is the optimal setting that reduces the number of interrupts.
- * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
- * if that bothers you), but in most cases it will not, since we try to 
- * transmit characters every time rs_interrupt is called. Thus, quite often
- * you'll see that a receive interrupt occures before the transmit one.
- *                                  -- Vladimir Gurevich
- */
-#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-
-/*
- * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
- * "Old data interrupt" which occures whenever the data stay in the FIFO
- * longer than 30 bits time. This allows us to use FIFO without compromising
- * latency. '328 does not have this feature and without the real  328-based
- * board I would assume that RXRE is the safest setting.
- *
- * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
- * interrupts. RXFE (receive queue full) causes the system to lose data
- * at least at 115200 baud
- *
- * If your board is busy doing other stuff, you might consider to use
- * RXRE (data ready intrrupt) instead.
- *
- * The other option is to make these INTR masks run-time configurable, so
- * that people can dynamically adapt them according to the current usage.
- *                                  -- Vladimir Gurevich
- */
-
-/* (es) */
-#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
-#elif defined(CONFIG_M68328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
-#else
-#error Please, define the Rx interrupt events for your CPU
-#endif
-/* (/es) */
-
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct m68k_serial {
-	char soft_carrier;  /* Use soft carrier on this channel */
-	char break_abort;   /* Is serial console in, so process brk/abrt */
-	char is_cons;       /* Is this our console. */
-
-	/* We need to know the current clock divisor
-	 * to read the bps rate the chip has currently
-	 * loaded.
-	 */
-	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
-	int baud;
-	int			magic;
-	int			baud_base;
-	int			port;
-	int			irq;
-	int			flags; 		/* defined in tty.h */
-	int			type; 		/* UART type */
-	struct tty_struct 	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			timeout;
-	int			xmit_fifo_size;
-	int			custom_divisor;
-	int			x_char;	/* xon/xoff character */
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
-	unsigned long		event;
-	unsigned long		last_active;
-	int			line;
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP	0
-
-/* 
- * Define the number of ports supported and their irqs.
- */
-#define NR_PORTS 1
-#define UART_IRQ_DEFNS {UART_IRQ_NUM}
-
-#endif /* __KERNEL__ */
-#endif /* !(_MC683XX_SERIAL_H) */

+ 150 - 162
drivers/tty/serial/8250/8250.c

@@ -284,7 +284,20 @@ static const struct serial8250_config uart_config[] = {
 	},
 	},
 };
 };
 
 
-#if defined(CONFIG_MIPS_ALCHEMY)
+/* Uart divisor latch read */
+static int default_serial_dl_read(struct uart_8250_port *up)
+{
+	return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static void default_serial_dl_write(struct uart_8250_port *up, int value)
+{
+	serial_out(up, UART_DLL, value & 0xff);
+	serial_out(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_MIPS_ALCHEMY
 
 
 /* Au1x00 UART hardware has a weird register layout */
 /* Au1x00 UART hardware has a weird register layout */
 static const u8 au_io_in_map[] = {
 static const u8 au_io_in_map[] = {
@@ -305,22 +318,32 @@ static const u8 au_io_out_map[] = {
 	[UART_MCR] = 6,
 	[UART_MCR] = 6,
 };
 };
 
 
-/* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
+static unsigned int au_serial_in(struct uart_port *p, int offset)
+{
+	offset = au_io_in_map[offset] << p->regshift;
+	return __raw_readl(p->membase + offset);
+}
+
+static void au_serial_out(struct uart_port *p, int offset, int value)
+{
+	offset = au_io_out_map[offset] << p->regshift;
+	__raw_writel(value, p->membase + offset);
+}
+
+/* Au1x00 haven't got a standard divisor latch */
+static int au_serial_dl_read(struct uart_8250_port *up)
 {
 {
-	if (p->iotype != UPIO_AU)
-		return offset;
-	return au_io_in_map[offset];
+	return __raw_readl(up->port.membase + 0x28);
 }
 }
 
 
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
+static void au_serial_dl_write(struct uart_8250_port *up, int value)
 {
 {
-	if (p->iotype != UPIO_AU)
-		return offset;
-	return au_io_out_map[offset];
+	__raw_writel(value, up->port.membase + 0x28);
 }
 }
 
 
-#elif defined(CONFIG_SERIAL_8250_RM9K)
+#endif
+
+#ifdef CONFIG_SERIAL_8250_RM9K
 
 
 static const u8
 static const u8
 	regmap_in[8] = {
 	regmap_in[8] = {
@@ -344,87 +367,79 @@ static const u8
 		[UART_SCR]	= 0x2c
 		[UART_SCR]	= 0x2c
 	};
 	};
 
 
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
+static unsigned int rm9k_serial_in(struct uart_port *p, int offset)
 {
 {
-	if (p->iotype != UPIO_RM9000)
-		return offset;
-	return regmap_in[offset];
+	offset = regmap_in[offset] << p->regshift;
+	return readl(p->membase + offset);
 }
 }
 
 
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
+static void rm9k_serial_out(struct uart_port *p, int offset, int value)
 {
 {
-	if (p->iotype != UPIO_RM9000)
-		return offset;
-	return regmap_out[offset];
+	offset = regmap_out[offset] << p->regshift;
+	writel(value, p->membase + offset);
 }
 }
 
 
-#else
+static int rm9k_serial_dl_read(struct uart_8250_port *up)
+{
+	return ((__raw_readl(up->port.membase + 0x10) << 8) |
+		(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff;
+}
 
 
-/* sane hardware needs no mapping */
-#define map_8250_in_reg(up, offset) (offset)
-#define map_8250_out_reg(up, offset) (offset)
+static void rm9k_serial_dl_write(struct uart_8250_port *up, int value)
+{
+	__raw_writel(value, up->port.membase + 0x08);
+	__raw_writel(value >> 8, up->port.membase + 0x10);
+}
 
 
 #endif
 #endif
 
 
 static unsigned int hub6_serial_in(struct uart_port *p, int offset)
 static unsigned int hub6_serial_in(struct uart_port *p, int offset)
 {
 {
-	offset = map_8250_in_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	outb(p->hub6 - 1 + offset, p->iobase);
 	outb(p->hub6 - 1 + offset, p->iobase);
 	return inb(p->iobase + 1);
 	return inb(p->iobase + 1);
 }
 }
 
 
 static void hub6_serial_out(struct uart_port *p, int offset, int value)
 static void hub6_serial_out(struct uart_port *p, int offset, int value)
 {
 {
-	offset = map_8250_out_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	outb(p->hub6 - 1 + offset, p->iobase);
 	outb(p->hub6 - 1 + offset, p->iobase);
 	outb(value, p->iobase + 1);
 	outb(value, p->iobase + 1);
 }
 }
 
 
 static unsigned int mem_serial_in(struct uart_port *p, int offset)
 static unsigned int mem_serial_in(struct uart_port *p, int offset)
 {
 {
-	offset = map_8250_in_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	return readb(p->membase + offset);
 	return readb(p->membase + offset);
 }
 }
 
 
 static void mem_serial_out(struct uart_port *p, int offset, int value)
 static void mem_serial_out(struct uart_port *p, int offset, int value)
 {
 {
-	offset = map_8250_out_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	writeb(value, p->membase + offset);
 	writeb(value, p->membase + offset);
 }
 }
 
 
 static void mem32_serial_out(struct uart_port *p, int offset, int value)
 static void mem32_serial_out(struct uart_port *p, int offset, int value)
 {
 {
-	offset = map_8250_out_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	writel(value, p->membase + offset);
 	writel(value, p->membase + offset);
 }
 }
 
 
 static unsigned int mem32_serial_in(struct uart_port *p, int offset)
 static unsigned int mem32_serial_in(struct uart_port *p, int offset)
 {
 {
-	offset = map_8250_in_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	return readl(p->membase + offset);
 	return readl(p->membase + offset);
 }
 }
 
 
-static unsigned int au_serial_in(struct uart_port *p, int offset)
-{
-	offset = map_8250_in_reg(p, offset) << p->regshift;
-	return __raw_readl(p->membase + offset);
-}
-
-static void au_serial_out(struct uart_port *p, int offset, int value)
-{
-	offset = map_8250_out_reg(p, offset) << p->regshift;
-	__raw_writel(value, p->membase + offset);
-}
-
 static unsigned int io_serial_in(struct uart_port *p, int offset)
 static unsigned int io_serial_in(struct uart_port *p, int offset)
 {
 {
-	offset = map_8250_in_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	return inb(p->iobase + offset);
 	return inb(p->iobase + offset);
 }
 }
 
 
 static void io_serial_out(struct uart_port *p, int offset, int value)
 static void io_serial_out(struct uart_port *p, int offset, int value)
 {
 {
-	offset = map_8250_out_reg(p, offset) << p->regshift;
+	offset = offset << p->regshift;
 	outb(value, p->iobase + offset);
 	outb(value, p->iobase + offset);
 }
 }
 
 
@@ -434,6 +449,10 @@ static void set_io_from_upio(struct uart_port *p)
 {
 {
 	struct uart_8250_port *up =
 	struct uart_8250_port *up =
 		container_of(p, struct uart_8250_port, port);
 		container_of(p, struct uart_8250_port, port);
+
+	up->dl_read = default_serial_dl_read;
+	up->dl_write = default_serial_dl_write;
+
 	switch (p->iotype) {
 	switch (p->iotype) {
 	case UPIO_HUB6:
 	case UPIO_HUB6:
 		p->serial_in = hub6_serial_in;
 		p->serial_in = hub6_serial_in;
@@ -445,16 +464,28 @@ static void set_io_from_upio(struct uart_port *p)
 		p->serial_out = mem_serial_out;
 		p->serial_out = mem_serial_out;
 		break;
 		break;
 
 
-	case UPIO_RM9000:
 	case UPIO_MEM32:
 	case UPIO_MEM32:
 		p->serial_in = mem32_serial_in;
 		p->serial_in = mem32_serial_in;
 		p->serial_out = mem32_serial_out;
 		p->serial_out = mem32_serial_out;
 		break;
 		break;
 
 
+#ifdef CONFIG_SERIAL_8250_RM9K
+	case UPIO_RM9000:
+		p->serial_in = rm9k_serial_in;
+		p->serial_out = rm9k_serial_out;
+		up->dl_read = rm9k_serial_dl_read;
+		up->dl_write = rm9k_serial_dl_write;
+		break;
+#endif
+
+#ifdef CONFIG_MIPS_ALCHEMY
 	case UPIO_AU:
 	case UPIO_AU:
 		p->serial_in = au_serial_in;
 		p->serial_in = au_serial_in;
 		p->serial_out = au_serial_out;
 		p->serial_out = au_serial_out;
+		up->dl_read = au_serial_dl_read;
+		up->dl_write = au_serial_dl_write;
 		break;
 		break;
+#endif
 
 
 	default:
 	default:
 		p->serial_in = io_serial_in;
 		p->serial_in = io_serial_in;
@@ -481,59 +512,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
 	}
 	}
 }
 }
 
 
-/* Uart divisor latch read */
-static inline int _serial_dl_read(struct uart_8250_port *up)
-{
-	return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
-}
-
-/* Uart divisor latch write */
-static inline void _serial_dl_write(struct uart_8250_port *up, int value)
-{
-	serial_out(up, UART_DLL, value & 0xff);
-	serial_out(up, UART_DLM, value >> 8 & 0xff);
-}
-
-#if defined(CONFIG_MIPS_ALCHEMY)
-/* Au1x00 haven't got a standard divisor latch */
-static int serial_dl_read(struct uart_8250_port *up)
-{
-	if (up->port.iotype == UPIO_AU)
-		return __raw_readl(up->port.membase + 0x28);
-	else
-		return _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
-	if (up->port.iotype == UPIO_AU)
-		__raw_writel(value, up->port.membase + 0x28);
-	else
-		_serial_dl_write(up, value);
-}
-#elif defined(CONFIG_SERIAL_8250_RM9K)
-static int serial_dl_read(struct uart_8250_port *up)
-{
-	return	(up->port.iotype == UPIO_RM9000) ?
-		(((__raw_readl(up->port.membase + 0x10) << 8) |
-		(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
-		_serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
-	if (up->port.iotype == UPIO_RM9000) {
-		__raw_writel(value, up->port.membase + 0x08);
-		__raw_writel(value >> 8, up->port.membase + 0x10);
-	} else {
-		_serial_dl_write(up, value);
-	}
-}
-#else
-#define serial_dl_read(up) _serial_dl_read(up)
-#define serial_dl_write(up, value) _serial_dl_write(up, value)
-#endif
-
 /*
 /*
  * For the 16C950
  * For the 16C950
  */
  */
@@ -568,6 +546,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
 	}
 	}
 }
 }
 
 
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
+{
+	unsigned char fcr;
+
+	serial8250_clear_fifos(p);
+	fcr = uart_config[p->port.type].fcr;
+	serial_out(p, UART_FCR, fcr);
+}
+EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
+
 /*
 /*
  * IER sleep support.  UARTs which have EFRs need the "extended
  * IER sleep support.  UARTs which have EFRs need the "extended
  * capability" bit enabled.  Note that on XR16C850s, we need to
  * capability" bit enabled.  Note that on XR16C850s, we need to
@@ -1331,27 +1319,6 @@ static void serial8250_enable_ms(struct uart_port *port)
 	serial_port_out(port, UART_IER, up->ier);
 	serial_port_out(port, UART_IER, up->ier);
 }
 }
 
 
-/*
- * Clear the Tegra rx fifo after a break
- *
- * FIXME: This needs to become a port specific callback once we have a
- * framework for this
- */
-static void clear_rx_fifo(struct uart_8250_port *up)
-{
-	unsigned int status, tmout = 10000;
-	do {
-		status = serial_in(up, UART_LSR);
-		if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
-			status = serial_in(up, UART_RX);
-		else
-			break;
-		if (--tmout == 0)
-			break;
-		udelay(1);
-	} while (1);
-}
-
 /*
 /*
  * serial8250_rx_chars: processes according to the passed in LSR
  * serial8250_rx_chars: processes according to the passed in LSR
  * value, and returns the remaining LSR bits not handled
  * value, and returns the remaining LSR bits not handled
@@ -1386,19 +1353,9 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
 		up->lsr_saved_flags = 0;
 		up->lsr_saved_flags = 0;
 
 
 		if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
 		if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
-			/*
-			 * For statistics only
-			 */
 			if (lsr & UART_LSR_BI) {
 			if (lsr & UART_LSR_BI) {
 				lsr &= ~(UART_LSR_FE | UART_LSR_PE);
 				lsr &= ~(UART_LSR_FE | UART_LSR_PE);
 				port->icount.brk++;
 				port->icount.brk++;
-				/*
-				 * If tegra port then clear the rx fifo to
-				 * accept another break/character.
-				 */
-				if (port->type == PORT_TEGRA)
-					clear_rx_fifo(up);
-
 				/*
 				/*
 				 * We do the SysRQ and SAK checking
 				 * We do the SysRQ and SAK checking
 				 * here because otherwise the break
 				 * here because otherwise the break
@@ -2280,10 +2237,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
 		quot++;
 		quot++;
 
 
 	if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
 	if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
-		if (baud < 2400)
-			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
-		else
-			fcr = uart_config[port->type].fcr;
+		fcr = uart_config[port->type].fcr;
+		if (baud < 2400) {
+			fcr &= ~UART_FCR_TRIGGER_MASK;
+			fcr |= UART_FCR_TRIGGER_1;
+		}
 	}
 	}
 
 
 	/*
 	/*
@@ -3037,6 +2995,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
 		port.serial_in		= p->serial_in;
 		port.serial_in		= p->serial_in;
 		port.serial_out		= p->serial_out;
 		port.serial_out		= p->serial_out;
 		port.handle_irq		= p->handle_irq;
 		port.handle_irq		= p->handle_irq;
+		port.handle_break	= p->handle_break;
 		port.set_termios	= p->set_termios;
 		port.set_termios	= p->set_termios;
 		port.pm			= p->pm;
 		port.pm			= p->pm;
 		port.dev		= &dev->dev;
 		port.dev		= &dev->dev;
@@ -3153,7 +3112,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
 }
 }
 
 
 /**
 /**
- *	serial8250_register_port - register a serial port
+ *	serial8250_register_8250_port - register a serial port
  *	@port: serial port template
  *	@port: serial port template
  *
  *
  *	Configure the serial port specified by the request. If the
  *	Configure the serial port specified by the request. If the
@@ -3165,50 +3124,56 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
  *
  *
  *	On success the port is ready to use and the line number is returned.
  *	On success the port is ready to use and the line number is returned.
  */
  */
-int serial8250_register_port(struct uart_port *port)
+int serial8250_register_8250_port(struct uart_8250_port *up)
 {
 {
 	struct uart_8250_port *uart;
 	struct uart_8250_port *uart;
 	int ret = -ENOSPC;
 	int ret = -ENOSPC;
 
 
-	if (port->uartclk == 0)
+	if (up->port.uartclk == 0)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	mutex_lock(&serial_mutex);
 	mutex_lock(&serial_mutex);
 
 
-	uart = serial8250_find_match_or_unused(port);
+	uart = serial8250_find_match_or_unused(&up->port);
 	if (uart) {
 	if (uart) {
 		uart_remove_one_port(&serial8250_reg, &uart->port);
 		uart_remove_one_port(&serial8250_reg, &uart->port);
 
 
-		uart->port.iobase       = port->iobase;
-		uart->port.membase      = port->membase;
-		uart->port.irq          = port->irq;
-		uart->port.irqflags     = port->irqflags;
-		uart->port.uartclk      = port->uartclk;
-		uart->port.fifosize     = port->fifosize;
-		uart->port.regshift     = port->regshift;
-		uart->port.iotype       = port->iotype;
-		uart->port.flags        = port->flags | UPF_BOOT_AUTOCONF;
-		uart->port.mapbase      = port->mapbase;
-		uart->port.private_data = port->private_data;
-		if (port->dev)
-			uart->port.dev = port->dev;
-
-		if (port->flags & UPF_FIXED_TYPE)
-			serial8250_init_fixed_type_port(uart, port->type);
+		uart->port.iobase       = up->port.iobase;
+		uart->port.membase      = up->port.membase;
+		uart->port.irq          = up->port.irq;
+		uart->port.irqflags     = up->port.irqflags;
+		uart->port.uartclk      = up->port.uartclk;
+		uart->port.fifosize     = up->port.fifosize;
+		uart->port.regshift     = up->port.regshift;
+		uart->port.iotype       = up->port.iotype;
+		uart->port.flags        = up->port.flags | UPF_BOOT_AUTOCONF;
+		uart->port.mapbase      = up->port.mapbase;
+		uart->port.private_data = up->port.private_data;
+		if (up->port.dev)
+			uart->port.dev = up->port.dev;
+
+		if (up->port.flags & UPF_FIXED_TYPE)
+			serial8250_init_fixed_type_port(uart, up->port.type);
 
 
 		set_io_from_upio(&uart->port);
 		set_io_from_upio(&uart->port);
 		/* Possibly override default I/O functions.  */
 		/* Possibly override default I/O functions.  */
-		if (port->serial_in)
-			uart->port.serial_in = port->serial_in;
-		if (port->serial_out)
-			uart->port.serial_out = port->serial_out;
-		if (port->handle_irq)
-			uart->port.handle_irq = port->handle_irq;
+		if (up->port.serial_in)
+			uart->port.serial_in = up->port.serial_in;
+		if (up->port.serial_out)
+			uart->port.serial_out = up->port.serial_out;
+		if (up->port.handle_irq)
+			uart->port.handle_irq = up->port.handle_irq;
 		/*  Possibly override set_termios call */
 		/*  Possibly override set_termios call */
-		if (port->set_termios)
-			uart->port.set_termios = port->set_termios;
-		if (port->pm)
-			uart->port.pm = port->pm;
+		if (up->port.set_termios)
+			uart->port.set_termios = up->port.set_termios;
+		if (up->port.pm)
+			uart->port.pm = up->port.pm;
+		if (up->port.handle_break)
+			uart->port.handle_break = up->port.handle_break;
+		if (up->dl_read)
+			uart->dl_read = up->dl_read;
+		if (up->dl_write)
+			uart->dl_write = up->dl_write;
 
 
 		if (serial8250_isa_config != NULL)
 		if (serial8250_isa_config != NULL)
 			serial8250_isa_config(0, &uart->port,
 			serial8250_isa_config(0, &uart->port,
@@ -3222,6 +3187,29 @@ int serial8250_register_port(struct uart_port *port)
 
 
 	return ret;
 	return ret;
 }
 }
+EXPORT_SYMBOL(serial8250_register_8250_port);
+
+/**
+ *	serial8250_register_port - register a serial port
+ *	@port: serial port template
+ *
+ *	Configure the serial port specified by the request. If the
+ *	port exists and is in use, it is hung up and unregistered
+ *	first.
+ *
+ *	The port is then probed and if necessary the IRQ is autodetected
+ *	If this fails an error is returned.
+ *
+ *	On success the port is ready to use and the line number is returned.
+ */
+int serial8250_register_port(struct uart_port *port)
+{
+	struct uart_8250_port up;
+
+	memset(&up, 0, sizeof(up));
+	memcpy(&up.port, port, sizeof(*port));
+	return serial8250_register_8250_port(&up);
+}
 EXPORT_SYMBOL(serial8250_register_port);
 EXPORT_SYMBOL(serial8250_register_port);
 
 
 /**
 /**

+ 16 - 0
drivers/tty/serial/8250/8250.h

@@ -37,6 +37,10 @@ struct uart_8250_port {
 	unsigned char		lsr_saved_flags;
 	unsigned char		lsr_saved_flags;
 #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
 #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
 	unsigned char		msr_saved_flags;
 	unsigned char		msr_saved_flags;
+
+	/* 8250 specific callbacks */
+	int			(*dl_read)(struct uart_8250_port *);
+	void			(*dl_write)(struct uart_8250_port *, int);
 };
 };
 
 
 struct old_serial_port {
 struct old_serial_port {
@@ -96,6 +100,18 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value)
 	up->port.serial_out(&up->port, offset, value);
 	up->port.serial_out(&up->port, offset, value);
 }
 }
 
 
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
+
+static inline int serial_dl_read(struct uart_8250_port *up)
+{
+	return up->dl_read(up);
+}
+
+static inline void serial_dl_write(struct uart_8250_port *up, int value)
+{
+	up->dl_write(up, value);
+}
+
 #if defined(__alpha__) && !defined(CONFIG_PCI)
 #if defined(__alpha__) && !defined(CONFIG_PCI)
 /*
 /*
  * Digital did something really horribly wrong with the OUT1 and OUT2
  * Digital did something really horribly wrong with the OUT1 and OUT2

+ 186 - 0
drivers/tty/serial/8250/8250_em.c

@@ -0,0 +1,186 @@
+/*
+ * Renesas Emma Mobile 8250 driver
+ *
+ *  Copyright (C) 2012 Magnus Damm
+ *
+ * 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; either 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/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include "8250.h"
+
+#define UART_DLL_EM 9
+#define UART_DLM_EM 10
+
+struct serial8250_em_priv {
+	struct clk *sclk;
+	int line;
+};
+
+static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
+{
+	switch (offset) {
+	case UART_TX: /* TX @ 0x00 */
+		writeb(value, p->membase);
+		break;
+	case UART_FCR: /* FCR @ 0x0c (+1) */
+	case UART_LCR: /* LCR @ 0x10 (+1) */
+	case UART_MCR: /* MCR @ 0x14 (+1) */
+	case UART_SCR: /* SCR @ 0x20 (+1) */
+		writel(value, p->membase + ((offset + 1) << 2));
+		break;
+	case UART_IER: /* IER @ 0x04 */
+		value &= 0x0f; /* only 4 valid bits - not Xscale */
+		/* fall-through */
+	case UART_DLL_EM: /* DLL @ 0x24 (+9) */
+	case UART_DLM_EM: /* DLM @ 0x28 (+9) */
+		writel(value, p->membase + (offset << 2));
+	}
+}
+
+static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset)
+{
+	switch (offset) {
+	case UART_RX: /* RX @ 0x00 */
+		return readb(p->membase);
+	case UART_MCR: /* MCR @ 0x14 (+1) */
+	case UART_LSR: /* LSR @ 0x18 (+1) */
+	case UART_MSR: /* MSR @ 0x1c (+1) */
+	case UART_SCR: /* SCR @ 0x20 (+1) */
+		return readl(p->membase + ((offset + 1) << 2));
+	case UART_IER: /* IER @ 0x04 */
+	case UART_IIR: /* IIR @ 0x08 */
+	case UART_DLL_EM: /* DLL @ 0x24 (+9) */
+	case UART_DLM_EM: /* DLM @ 0x28 (+9) */
+		return readl(p->membase + (offset << 2));
+	}
+	return 0;
+}
+
+static int serial8250_em_serial_dl_read(struct uart_8250_port *up)
+{
+	return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8;
+}
+
+static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
+{
+	serial_out(up, UART_DLL_EM, value & 0xff);
+	serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
+}
+
+static int __devinit serial8250_em_probe(struct platform_device *pdev)
+{
+	struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	struct serial8250_em_priv *priv;
+	struct uart_8250_port up;
+	int ret = -EINVAL;
+
+	if (!regs || !irq) {
+		dev_err(&pdev->dev, "missing registers or irq\n");
+		goto err0;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "unable to allocate private data\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	priv->sclk = clk_get(&pdev->dev, "sclk");
+	if (IS_ERR(priv->sclk)) {
+		dev_err(&pdev->dev, "unable to get clock\n");
+		ret = PTR_ERR(priv->sclk);
+		goto err1;
+	}
+
+	memset(&up, 0, sizeof(up));
+	up.port.mapbase = regs->start;
+	up.port.irq = irq->start;
+	up.port.type = PORT_UNKNOWN;
+	up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+	up.port.dev = &pdev->dev;
+	up.port.private_data = priv;
+
+	clk_enable(priv->sclk);
+	up.port.uartclk = clk_get_rate(priv->sclk);
+
+	up.port.iotype = UPIO_MEM32;
+	up.port.serial_in = serial8250_em_serial_in;
+	up.port.serial_out = serial8250_em_serial_out;
+	up.dl_read = serial8250_em_serial_dl_read;
+	up.dl_write = serial8250_em_serial_dl_write;
+
+	ret = serial8250_register_8250_port(&up);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "unable to register 8250 port\n");
+		goto err2;
+	}
+
+	priv->line = ret;
+	platform_set_drvdata(pdev, priv);
+	return 0;
+
+ err2:
+	clk_disable(priv->sclk);
+	clk_put(priv->sclk);
+ err1:
+	kfree(priv);
+ err0:
+	return ret;
+}
+
+static int __devexit serial8250_em_remove(struct platform_device *pdev)
+{
+	struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
+
+	serial8250_unregister_port(priv->line);
+	clk_disable(priv->sclk);
+	clk_put(priv->sclk);
+	kfree(priv);
+	return 0;
+}
+
+static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = {
+	{ .compatible = "renesas,em-uart", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, serial8250_em_dt_ids);
+
+static struct platform_driver serial8250_em_platform_driver = {
+	.driver = {
+		.name		= "serial8250-em",
+		.of_match_table = serial8250_em_dt_ids,
+		.owner		= THIS_MODULE,
+	},
+	.probe			= serial8250_em_probe,
+	.remove			= __devexit_p(serial8250_em_remove),
+};
+
+module_platform_driver(serial8250_em_platform_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver");
+MODULE_LICENSE("GPL v2");

+ 63 - 0
drivers/tty/serial/8250/8250_pci.c

@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/tty.h>
 #include <linux/tty.h>
+#include <linux/serial_reg.h>
 #include <linux/serial_core.h>
 #include <linux/serial_core.h>
 #include <linux/8250_pci.h>
 #include <linux/8250_pci.h>
 #include <linux/bitops.h>
 #include <linux/bitops.h>
@@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv,
 	return pci_default_setup(priv, board, port, idx);
 	return pci_default_setup(priv, board, port, idx);
 }
 }
 
 
+static void kt_handle_break(struct uart_port *p)
+{
+	struct uart_8250_port *up =
+		container_of(p, struct uart_8250_port, port);
+	/*
+	 * On receipt of a BI, serial device in Intel ME (Intel
+	 * management engine) needs to have its fifos cleared for sane
+	 * SOL (Serial Over Lan) output.
+	 */
+	serial8250_clear_and_reinit_fifos(up);
+}
+
+static unsigned int kt_serial_in(struct uart_port *p, int offset)
+{
+	struct uart_8250_port *up =
+		container_of(p, struct uart_8250_port, port);
+	unsigned int val;
+
+	/*
+	 * When the Intel ME (management engine) gets reset its serial
+	 * port registers could return 0 momentarily.  Functions like
+	 * serial8250_console_write, read and save the IER, perform
+	 * some operation and then restore it.  In order to avoid
+	 * setting IER register inadvertently to 0, if the value read
+	 * is 0, double check with ier value in uart_8250_port and use
+	 * that instead.  up->ier should be the same value as what is
+	 * currently configured.
+	 */
+	val = inb(p->iobase + offset);
+	if (offset == UART_IER) {
+		if (val == 0)
+			val = up->ier;
+	}
+	return val;
+}
+
 static int kt_serial_setup(struct serial_private *priv,
 static int kt_serial_setup(struct serial_private *priv,
 			   const struct pciserial_board *board,
 			   const struct pciserial_board *board,
 			   struct uart_port *port, int idx)
 			   struct uart_port *port, int idx)
 {
 {
 	port->flags |= UPF_BUG_THRE;
 	port->flags |= UPF_BUG_THRE;
+	port->serial_in = kt_serial_in;
+	port->handle_break = kt_handle_break;
 	return skip_tx_en_setup(priv, board, port, idx);
 	return skip_tx_en_setup(priv, board, port, idx);
 }
 }
 
 
@@ -1609,54 +1648,72 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 	{
 	{
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.device         = 0x8811,
 		.device         = 0x8811,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 		.setup		= pci_default_setup,
 	},
 	},
 	{
 	{
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.device         = 0x8812,
 		.device         = 0x8812,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 		.setup		= pci_default_setup,
 	},
 	},
 	{
 	{
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.device         = 0x8813,
 		.device         = 0x8813,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 		.setup		= pci_default_setup,
 	},
 	},
 	{
 	{
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.vendor         = PCI_VENDOR_ID_INTEL,
 		.device         = 0x8814,
 		.device         = 0x8814,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 		.setup		= pci_default_setup,
 	},
 	},
 	{
 	{
 		.vendor         = 0x10DB,
 		.vendor         = 0x10DB,
 		.device         = 0x8027,
 		.device         = 0x8027,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 		.setup		= pci_default_setup,
 	},
 	},
 	{
 	{
 		.vendor         = 0x10DB,
 		.vendor         = 0x10DB,
 		.device         = 0x8028,
 		.device         = 0x8028,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 		.setup		= pci_default_setup,
 	},
 	},
 	{
 	{
 		.vendor         = 0x10DB,
 		.vendor         = 0x10DB,
 		.device         = 0x8029,
 		.device         = 0x8029,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 		.setup		= pci_default_setup,
 	},
 	},
 	{
 	{
 		.vendor         = 0x10DB,
 		.vendor         = 0x10DB,
 		.device         = 0x800C,
 		.device         = 0x800C,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 		.setup		= pci_default_setup,
 	},
 	},
 	{
 	{
 		.vendor         = 0x10DB,
 		.vendor         = 0x10DB,
 		.device         = 0x800D,
 		.device         = 0x800D,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 		.init		= pci_eg20t_init,
 		.init		= pci_eg20t_init,
 		.setup		= pci_default_setup,
 		.setup		= pci_default_setup,
 	},
 	},
@@ -2775,6 +2832,12 @@ void pciserial_suspend_ports(struct serial_private *priv)
 	for (i = 0; i < priv->nr; i++)
 	for (i = 0; i < priv->nr; i++)
 		if (priv->line[i] >= 0)
 		if (priv->line[i] >= 0)
 			serial8250_suspend_port(priv->line[i]);
 			serial8250_suspend_port(priv->line[i]);
+
+	/*
+	 * Ensure that every init quirk is properly torn down
+	 */
+	if (priv->quirk->exit)
+		priv->quirk->exit(priv->dev);
 }
 }
 EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
 EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
 
 

+ 8 - 0
drivers/tty/serial/8250/Kconfig

@@ -278,3 +278,11 @@ config SERIAL_8250_DW
 	help
 	help
 	  Selecting this option will enable handling of the extra features
 	  Selecting this option will enable handling of the extra features
 	  present in the Synopsys DesignWare APB UART.
 	  present in the Synopsys DesignWare APB UART.
+
+config SERIAL_8250_EM
+	tristate "Support for Emma Mobile intergrated serial port"
+	depends on SERIAL_8250 && ARM && HAVE_CLK
+	help
+	  Selecting this option will add support for the integrated serial
+	  port hardware found on the Emma Mobile line of processors.
+	  If unsure, say N.

+ 1 - 0
drivers/tty/serial/8250/Makefile

@@ -18,3 +18,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6)		+= 8250_hub6.o
 obj-$(CONFIG_SERIAL_8250_MCA)		+= 8250_mca.o
 obj-$(CONFIG_SERIAL_8250_MCA)		+= 8250_mca.o
 obj-$(CONFIG_SERIAL_8250_FSL)		+= 8250_fsl.o
 obj-$(CONFIG_SERIAL_8250_FSL)		+= 8250_fsl.o
 obj-$(CONFIG_SERIAL_8250_DW)		+= 8250_dw.o
 obj-$(CONFIG_SERIAL_8250_DW)		+= 8250_dw.o
+obj-$(CONFIG_SERIAL_8250_EM)		+= 8250_em.o

+ 18 - 91
drivers/tty/serial/amba-pl011.c

@@ -68,30 +68,6 @@
 #define UART_DR_ERROR		(UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
 #define UART_DR_ERROR		(UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
 #define UART_DUMMY_DR_RX	(1 << 16)
 #define UART_DUMMY_DR_RX	(1 << 16)
 
 
-
-#define UART_WA_SAVE_NR 14
-
-static void pl011_lockup_wa(unsigned long data);
-static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
-	ST_UART011_DMAWM,
-	ST_UART011_TIMEOUT,
-	ST_UART011_LCRH_RX,
-	UART011_IBRD,
-	UART011_FBRD,
-	ST_UART011_LCRH_TX,
-	UART011_IFLS,
-	ST_UART011_XFCR,
-	ST_UART011_XON1,
-	ST_UART011_XON2,
-	ST_UART011_XOFF1,
-	ST_UART011_XOFF2,
-	UART011_CR,
-	UART011_IMSC
-};
-
-static u32 uart_wa_regdata[UART_WA_SAVE_NR];
-static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
-
 /* There is by now at least one vendor with differing details, so handle it */
 /* There is by now at least one vendor with differing details, so handle it */
 struct vendor_data {
 struct vendor_data {
 	unsigned int		ifls;
 	unsigned int		ifls;
@@ -101,6 +77,7 @@ struct vendor_data {
 	bool			oversampling;
 	bool			oversampling;
 	bool			interrupt_may_hang;   /* vendor-specific */
 	bool			interrupt_may_hang;   /* vendor-specific */
 	bool			dma_threshold;
 	bool			dma_threshold;
+	bool			cts_event_workaround;
 };
 };
 
 
 static struct vendor_data vendor_arm = {
 static struct vendor_data vendor_arm = {
@@ -110,6 +87,7 @@ static struct vendor_data vendor_arm = {
 	.lcrh_rx		= UART011_LCRH,
 	.lcrh_rx		= UART011_LCRH,
 	.oversampling		= false,
 	.oversampling		= false,
 	.dma_threshold		= false,
 	.dma_threshold		= false,
+	.cts_event_workaround	= false,
 };
 };
 
 
 static struct vendor_data vendor_st = {
 static struct vendor_data vendor_st = {
@@ -120,6 +98,7 @@ static struct vendor_data vendor_st = {
 	.oversampling		= true,
 	.oversampling		= true,
 	.interrupt_may_hang	= true,
 	.interrupt_may_hang	= true,
 	.dma_threshold		= true,
 	.dma_threshold		= true,
+	.cts_event_workaround	= true,
 };
 };
 
 
 static struct uart_amba_port *amba_ports[UART_NR];
 static struct uart_amba_port *amba_ports[UART_NR];
@@ -1055,69 +1034,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
 #define pl011_dma_flush_buffer	NULL
 #define pl011_dma_flush_buffer	NULL
 #endif
 #endif
 
 
-
-/*
- * pl011_lockup_wa
- * This workaround aims to break the deadlock situation
- * when after long transfer over uart in hardware flow
- * control, uart interrupt registers cannot be cleared.
- * Hence uart transfer gets blocked.
- *
- * It is seen that during such deadlock condition ICR
- * don't get cleared even on multiple write. This leads
- * pass_counter to decrease and finally reach zero. This
- * can be taken as trigger point to run this UART_BT_WA.
- *
- */
-static void pl011_lockup_wa(unsigned long data)
-{
-	struct uart_amba_port *uap = amba_ports[0];
-	void __iomem *base = uap->port.membase;
-	struct circ_buf *xmit = &uap->port.state->xmit;
-	struct tty_struct *tty = uap->port.state->port.tty;
-	int buf_empty_retries = 200;
-	int loop;
-
-	/* Stop HCI layer from submitting data for tx */
-	tty->hw_stopped = 1;
-	while (!uart_circ_empty(xmit)) {
-		if (buf_empty_retries-- == 0)
-			break;
-		udelay(100);
-	}
-
-	/* Backup registers */
-	for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
-		uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
-
-	/* Disable UART so that FIFO data is flushed out */
-	writew(0x00, uap->port.membase + UART011_CR);
-
-	/* Soft reset UART module */
-	if (uap->port.dev->platform_data) {
-		struct amba_pl011_data *plat;
-
-		plat = uap->port.dev->platform_data;
-		if (plat->reset)
-			plat->reset();
-	}
-
-	/* Restore registers */
-	for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
-		writew(uart_wa_regdata[loop] ,
-				uap->port.membase + uart_wa_reg[loop]);
-
-	/* Initialise the old status of the modem signals */
-	uap->old_status = readw(uap->port.membase + UART01x_FR) &
-		UART01x_FR_MODEM_ANY;
-
-	if (readl(base + UART011_MIS) & 0x2)
-		printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
-
-	/* Start Tx/Rx */
-	tty->hw_stopped = 0;
-}
-
 static void pl011_stop_tx(struct uart_port *port)
 static void pl011_stop_tx(struct uart_port *port)
 {
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1246,12 +1162,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
 	unsigned long flags;
 	unsigned long flags;
 	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
 	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
 	int handled = 0;
 	int handled = 0;
+	unsigned int dummy_read;
 
 
 	spin_lock_irqsave(&uap->port.lock, flags);
 	spin_lock_irqsave(&uap->port.lock, flags);
 
 
 	status = readw(uap->port.membase + UART011_MIS);
 	status = readw(uap->port.membase + UART011_MIS);
 	if (status) {
 	if (status) {
 		do {
 		do {
+			if (uap->vendor->cts_event_workaround) {
+				/* workaround to make sure that all bits are unlocked.. */
+				writew(0x00, uap->port.membase + UART011_ICR);
+
+				/*
+				 * WA: introduce 26ns(1 uart clk) delay before W1C;
+				 * single apb access will incur 2 pclk(133.12Mhz) delay,
+				 * so add 2 dummy reads
+				 */
+				dummy_read = readw(uap->port.membase + UART011_ICR);
+				dummy_read = readw(uap->port.membase + UART011_ICR);
+			}
+
 			writew(status & ~(UART011_TXIS|UART011_RTIS|
 			writew(status & ~(UART011_TXIS|UART011_RTIS|
 					  UART011_RXIS),
 					  UART011_RXIS),
 			       uap->port.membase + UART011_ICR);
 			       uap->port.membase + UART011_ICR);
@@ -1268,11 +1198,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
 			if (status & UART011_TXIS)
 			if (status & UART011_TXIS)
 				pl011_tx_chars(uap);
 				pl011_tx_chars(uap);
 
 
-			if (pass_counter-- == 0) {
-				if (uap->interrupt_may_hang)
-					tasklet_schedule(&pl011_lockup_tlet);
+			if (pass_counter-- == 0)
 				break;
 				break;
-			}
 
 
 			status = readw(uap->port.membase + UART011_MIS);
 			status = readw(uap->port.membase + UART011_MIS);
 		} while (status != 0);
 		} while (status != 0);

+ 27 - 47
drivers/tty/serial/bfin_uart.c

@@ -1,7 +1,7 @@
 /*
 /*
  * Blackfin On-Chip Serial Driver
  * Blackfin On-Chip Serial Driver
  *
  *
- * Copyright 2006-2010 Analog Devices Inc.
+ * Copyright 2006-2011 Analog Devices Inc.
  *
  *
  * Enter bugs at http://blackfin.uclinux.org/
  * Enter bugs at http://blackfin.uclinux.org/
  *
  *
@@ -35,10 +35,6 @@
 #include <asm/portmux.h>
 #include <asm/portmux.h>
 #include <asm/cacheflush.h>
 #include <asm/cacheflush.h>
 #include <asm/dma.h>
 #include <asm/dma.h>
-
-#define port_membase(uart)     (((struct bfin_serial_port *)(uart))->port.membase)
-#define get_lsr_cache(uart)    (((struct bfin_serial_port *)(uart))->lsr)
-#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
 #include <asm/bfin_serial.h>
 #include <asm/bfin_serial.h>
 
 
 #ifdef CONFIG_SERIAL_BFIN_MODULE
 #ifdef CONFIG_SERIAL_BFIN_MODULE
@@ -166,7 +162,7 @@ static void bfin_serial_stop_tx(struct uart_port *port)
 	uart->tx_count = 0;
 	uart->tx_count = 0;
 	uart->tx_done = 1;
 	uart->tx_done = 1;
 #else
 #else
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
 	/* Clear TFI bit */
 	/* Clear TFI bit */
 	UART_PUT_LSR(uart, TFI);
 	UART_PUT_LSR(uart, TFI);
 #endif
 #endif
@@ -337,7 +333,7 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
 	struct circ_buf *xmit = &uart->port.state->xmit;
 	struct circ_buf *xmit = &uart->port.state->xmit;
 
 
 	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
 	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
 		/* Clear TFI bit */
 		/* Clear TFI bit */
 		UART_PUT_LSR(uart, TFI);
 		UART_PUT_LSR(uart, TFI);
 #endif
 #endif
@@ -536,7 +532,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
 		 */
 		 */
 		UART_CLEAR_IER(uart, ETBEI);
 		UART_CLEAR_IER(uart, ETBEI);
 		uart->port.icount.tx += uart->tx_count;
 		uart->port.icount.tx += uart->tx_count;
-		if (!uart_circ_empty(xmit)) {
+		if (!(xmit->tail == 0 && xmit->head == 0)) {
 			xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
 			xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
 
 
 			if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 			if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -553,7 +549,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
 static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
 static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
 {
 {
 	struct bfin_serial_port *uart = dev_id;
 	struct bfin_serial_port *uart = dev_id;
-	unsigned short irqstat;
+	unsigned int irqstat;
 	int x_pos, pos;
 	int x_pos, pos;
 
 
 	spin_lock(&uart->rx_lock);
 	spin_lock(&uart->rx_lock);
@@ -586,7 +582,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
 static unsigned int bfin_serial_tx_empty(struct uart_port *port)
 static unsigned int bfin_serial_tx_empty(struct uart_port *port)
 {
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-	unsigned short lsr;
+	unsigned int lsr;
 
 
 	lsr = UART_GET_LSR(uart);
 	lsr = UART_GET_LSR(uart);
 	if (lsr & TEMT)
 	if (lsr & TEMT)
@@ -598,7 +594,7 @@ static unsigned int bfin_serial_tx_empty(struct uart_port *port)
 static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
 static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
 {
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-	u16 lcr = UART_GET_LCR(uart);
+	u32 lcr = UART_GET_LCR(uart);
 	if (break_state)
 	if (break_state)
 		lcr |= SB;
 		lcr |= SB;
 	else
 	else
@@ -745,7 +741,7 @@ static int bfin_serial_startup(struct uart_port *port)
 		}
 		}
 
 
 		/* CTS RTS PINs are negative assertive. */
 		/* CTS RTS PINs are negative assertive. */
-		UART_PUT_MCR(uart, ACTS);
+		UART_PUT_MCR(uart, UART_GET_MCR(uart) | ACTS);
 		UART_SET_IER(uart, EDSSI);
 		UART_SET_IER(uart, EDSSI);
 	}
 	}
 #endif
 #endif
@@ -803,7 +799,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 	unsigned long flags;
 	unsigned long flags;
 	unsigned int baud, quot;
 	unsigned int baud, quot;
-	unsigned short val, ier, lcr = 0;
+	unsigned int ier, lcr = 0;
 
 
 	switch (termios->c_cflag & CSIZE) {
 	switch (termios->c_cflag & CSIZE) {
 	case CS8:
 	case CS8:
@@ -875,26 +871,23 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
 
 
 	/* Disable UART */
 	/* Disable UART */
 	ier = UART_GET_IER(uart);
 	ier = UART_GET_IER(uart);
+	UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN);
 	UART_DISABLE_INTS(uart);
 	UART_DISABLE_INTS(uart);
 
 
-	/* Set DLAB in LCR to Access DLL and DLH */
+	/* Set DLAB in LCR to Access CLK */
 	UART_SET_DLAB(uart);
 	UART_SET_DLAB(uart);
 
 
-	UART_PUT_DLL(uart, quot & 0xFF);
-	UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
+	UART_PUT_CLK(uart, quot);
 	SSYNC();
 	SSYNC();
 
 
 	/* Clear DLAB in LCR to Access THR RBR IER */
 	/* Clear DLAB in LCR to Access THR RBR IER */
 	UART_CLEAR_DLAB(uart);
 	UART_CLEAR_DLAB(uart);
 
 
-	UART_PUT_LCR(uart, lcr);
+	UART_PUT_LCR(uart, (UART_GET_LCR(uart) & ~LCR_MASK) | lcr);
 
 
 	/* Enable UART */
 	/* Enable UART */
 	UART_ENABLE_INTS(uart, ier);
 	UART_ENABLE_INTS(uart, ier);
-
-	val = UART_GET_GCTL(uart);
-	val |= UCEN;
-	UART_PUT_GCTL(uart, val);
+	UART_PUT_GCTL(uart, UART_GET_GCTL(uart) | UCEN);
 
 
 	/* Port speed changed, update the per-port timeout. */
 	/* Port speed changed, update the per-port timeout. */
 	uart_update_timeout(port, termios->c_cflag, baud);
 	uart_update_timeout(port, termios->c_cflag, baud);
@@ -954,17 +947,17 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
 static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
 static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
 {
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-	unsigned short val;
+	unsigned int val;
 
 
 	switch (ld) {
 	switch (ld) {
 	case N_IRDA:
 	case N_IRDA:
 		val = UART_GET_GCTL(uart);
 		val = UART_GET_GCTL(uart);
-		val |= (IREN | RPOLC);
+		val |= (UMOD_IRDA | RPOLC);
 		UART_PUT_GCTL(uart, val);
 		UART_PUT_GCTL(uart, val);
 		break;
 		break;
 	default:
 	default:
 		val = UART_GET_GCTL(uart);
 		val = UART_GET_GCTL(uart);
-		val &= ~(IREN | RPOLC);
+		val &= ~(UMOD_MASK | RPOLC);
 		UART_PUT_GCTL(uart, val);
 		UART_PUT_GCTL(uart, val);
 	}
 	}
 }
 }
@@ -972,13 +965,13 @@ static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
 static void bfin_serial_reset_irda(struct uart_port *port)
 static void bfin_serial_reset_irda(struct uart_port *port)
 {
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-	unsigned short val;
+	unsigned int val;
 
 
 	val = UART_GET_GCTL(uart);
 	val = UART_GET_GCTL(uart);
-	val &= ~(IREN | RPOLC);
+	val &= ~(UMOD_MASK | RPOLC);
 	UART_PUT_GCTL(uart, val);
 	UART_PUT_GCTL(uart, val);
 	SSYNC();
 	SSYNC();
-	val |= (IREN | RPOLC);
+	val |= (UMOD_IRDA | RPOLC);
 	UART_PUT_GCTL(uart, val);
 	UART_PUT_GCTL(uart, val);
 	SSYNC();
 	SSYNC();
 }
 }
@@ -1070,12 +1063,12 @@ static void __init
 bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
 bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
 			   int *parity, int *bits)
 			   int *parity, int *bits)
 {
 {
-	unsigned short status;
+	unsigned int status;
 
 
 	status = UART_GET_IER(uart) & (ERBFI | ETBEI);
 	status = UART_GET_IER(uart) & (ERBFI | ETBEI);
 	if (status == (ERBFI | ETBEI)) {
 	if (status == (ERBFI | ETBEI)) {
 		/* ok, the port was enabled */
 		/* ok, the port was enabled */
-		u16 lcr, dlh, dll;
+		u32 lcr, clk;
 
 
 		lcr = UART_GET_LCR(uart);
 		lcr = UART_GET_LCR(uart);
 
 
@@ -1086,30 +1079,17 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
 			else
 			else
 				*parity = 'o';
 				*parity = 'o';
 		}
 		}
-		switch (lcr & 0x03) {
-		case 0:
-			*bits = 5;
-			break;
-		case 1:
-			*bits = 6;
-			break;
-		case 2:
-			*bits = 7;
-			break;
-		case 3:
-			*bits = 8;
-			break;
-		}
-		/* Set DLAB in LCR to Access DLL and DLH */
+		*bits = ((lcr & WLS_MASK) >> WLS_OFFSET) + 5;
+
+		/* Set DLAB in LCR to Access CLK */
 		UART_SET_DLAB(uart);
 		UART_SET_DLAB(uart);
 
 
-		dll = UART_GET_DLL(uart);
-		dlh = UART_GET_DLH(uart);
+		clk = UART_GET_CLK(uart);
 
 
 		/* Clear DLAB in LCR to Access THR RBR IER */
 		/* Clear DLAB in LCR to Access THR RBR IER */
 		UART_CLEAR_DLAB(uart);
 		UART_CLEAR_DLAB(uart);
 
 
-		*baud = get_sclk() / (16*(dll | dlh << 8));
+		*baud = get_sclk() / (16*clk);
 	}
 	}
 	pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
 	pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
 }
 }

+ 6 - 30
drivers/tty/serial/crisv10.c

@@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
 /* Input */
 /* Input */
 #define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
 #define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
 
 
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static DEFINE_MUTEX(tmp_buf_mutex);
-
 /* Calculate the chartime depending on baudrate, numbor of bits etc. */
 /* Calculate the chartime depending on baudrate, numbor of bits etc. */
 static void update_char_time(struct e100_serial * info)
 static void update_char_time(struct e100_serial * info)
 {
 {
@@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty,
 
 
 	/* first some sanity checks */
 	/* first some sanity checks */
 
 
-	if (!tty || !info->xmit.buf || !tmp_buf)
+	if (!tty || !info->xmit.buf)
 		return 0;
 		return 0;
 
 
 #ifdef SERIAL_DEBUG_DATA
 #ifdef SERIAL_DEBUG_DATA
@@ -3989,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
 	 */
 	 */
 	if (tty_hung_up_p(filp) ||
 	if (tty_hung_up_p(filp) ||
 	    (info->flags & ASYNC_CLOSING)) {
 	    (info->flags & ASYNC_CLOSING)) {
-		wait_event_interruptible_tty(info->close_wait,
+		wait_event_interruptible_tty(tty, info->close_wait,
 			!(info->flags & ASYNC_CLOSING));
 			!(info->flags & ASYNC_CLOSING));
 #ifdef SERIAL_DO_RESTART
 #ifdef SERIAL_DO_RESTART
 		if (info->flags & ASYNC_HUP_NOTIFY)
 		if (info->flags & ASYNC_HUP_NOTIFY)
@@ -4065,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
 		printk("block_til_ready blocking: ttyS%d, count = %d\n",
 		printk("block_til_ready blocking: ttyS%d, count = %d\n",
 		       info->line, info->count);
 		       info->line, info->count);
 #endif
 #endif
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	}
 	set_current_state(TASK_RUNNING);
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&info->open_wait, &wait);
 	remove_wait_queue(&info->open_wait, &wait);
@@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
 {
 {
 	struct e100_serial	*info;
 	struct e100_serial	*info;
 	int 			retval;
 	int 			retval;
-	unsigned long           page;
 	int                     allocated_resources = 0;
 	int                     allocated_resources = 0;
 
 
 	info = rs_table + tty->index;
 	info = rs_table + tty->index;
@@ -4124,23 +4110,12 @@ rs_open(struct tty_struct *tty, struct file * filp)
 
 
 	tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
 	tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
 
 
-	if (!tmp_buf) {
-		page = get_zeroed_page(GFP_KERNEL);
-		if (!page) {
-			return -ENOMEM;
-		}
-		if (tmp_buf)
-			free_page(page);
-		else
-			tmp_buf = (unsigned char *) page;
-	}
-
 	/*
 	/*
 	 * If the port is in the middle of closing, bail out now
 	 * If the port is in the middle of closing, bail out now
 	 */
 	 */
 	if (tty_hung_up_p(filp) ||
 	if (tty_hung_up_p(filp) ||
 	    (info->flags & ASYNC_CLOSING)) {
 	    (info->flags & ASYNC_CLOSING)) {
-		wait_event_interruptible_tty(info->close_wait,
+		wait_event_interruptible_tty(tty, info->close_wait,
 			!(info->flags & ASYNC_CLOSING));
 			!(info->flags & ASYNC_CLOSING));
 #ifdef SERIAL_DO_RESTART
 #ifdef SERIAL_DO_RESTART
 		return ((info->flags & ASYNC_HUP_NOTIFY) ?
 		return ((info->flags & ASYNC_HUP_NOTIFY) ?
@@ -4487,6 +4462,7 @@ static int __init rs_init(void)
 				info->enabled = 0;
 				info->enabled = 0;
 			}
 			}
 		}
 		}
+		tty_port_init(&info->port);
 		info->uses_dma_in = 0;
 		info->uses_dma_in = 0;
 		info->uses_dma_out = 0;
 		info->uses_dma_out = 0;
 		info->line = i;
 		info->line = i;

+ 2 - 0
drivers/tty/serial/mxs-auart.c

@@ -370,6 +370,8 @@ static void mxs_auart_settermios(struct uart_port *u,
 
 
 	writel(ctrl, u->membase + AUART_LINECTRL);
 	writel(ctrl, u->membase + AUART_LINECTRL);
 	writel(ctrl2, u->membase + AUART_CTRL2);
 	writel(ctrl2, u->membase + AUART_CTRL2);
+
+	uart_update_timeout(u, termios->c_cflag, baud);
 }
 }
 
 
 static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
 static irqreturn_t mxs_auart_irq_handle(int irq, void *context)

+ 26 - 0
drivers/tty/serial/of_serial.c

@@ -12,10 +12,13 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/serial_core.h>
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
 #include <linux/of_address.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_irq.h>
+#include <linux/of_serial.h>
 #include <linux/of_platform.h>
 #include <linux/of_platform.h>
 #include <linux/nwpserial.h>
 #include <linux/nwpserial.h>
 
 
@@ -24,6 +27,26 @@ struct of_serial_info {
 	int line;
 	int line;
 };
 };
 
 
+#ifdef CONFIG_ARCH_TEGRA
+void tegra_serial_handle_break(struct uart_port *p)
+{
+	unsigned int status, tmout = 10000;
+
+	do {
+		status = p->serial_in(p, UART_LSR);
+		if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
+			status = p->serial_in(p, UART_RX);
+		else
+			break;
+		if (--tmout == 0)
+			break;
+		udelay(1);
+	} while (1);
+}
+/* FIXME remove this export when tegra finishes conversion to open firmware */
+EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
+#endif
+
 /*
 /*
  * Fill a struct uart_port for a given device node
  * Fill a struct uart_port for a given device node
  */
  */
@@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
 		| UPF_FIXED_PORT | UPF_FIXED_TYPE;
 		| UPF_FIXED_PORT | UPF_FIXED_TYPE;
 	port->dev = &ofdev->dev;
 	port->dev = &ofdev->dev;
 
 
+	if (type == PORT_TEGRA)
+		port->handle_break = tegra_serial_handle_break;
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 73 - 1
drivers/tty/serial/omap-serial.c

@@ -44,6 +44,13 @@
 #include <plat/dmtimer.h>
 #include <plat/dmtimer.h>
 #include <plat/omap-serial.h>
 #include <plat/omap-serial.h>
 
 
+#define UART_BUILD_REVISION(x, y)	(((x) << 8) | (y))
+
+#define OMAP_UART_REV_42 0x0402
+#define OMAP_UART_REV_46 0x0406
+#define OMAP_UART_REV_52 0x0502
+#define OMAP_UART_REV_63 0x0603
+
 #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
 #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
 
 
 /* SCR register bitmasks */
 /* SCR register bitmasks */
@@ -53,6 +60,17 @@
 #define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT		6
 #define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT		6
 #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK			(0x3 << 6)
 #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK			(0x3 << 6)
 
 
+/* MVR register bitmasks */
+#define OMAP_UART_MVR_SCHEME_SHIFT	30
+
+#define OMAP_UART_LEGACY_MVR_MAJ_MASK	0xf0
+#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT	4
+#define OMAP_UART_LEGACY_MVR_MIN_MASK	0x0f
+
+#define OMAP_UART_MVR_MAJ_MASK		0x700
+#define OMAP_UART_MVR_MAJ_SHIFT		8
+#define OMAP_UART_MVR_MIN_MASK		0x3f
+
 static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
 
 
 /* Forward declaration of functions */
 /* Forward declaration of functions */
@@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
 	return;
 	return;
 }
 }
 
 
+static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
+{
+	u32 mvr, scheme;
+	u16 revision, major, minor;
+
+	mvr = serial_in(up, UART_OMAP_MVER);
+
+	/* Check revision register scheme */
+	scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;
+
+	switch (scheme) {
+	case 0: /* Legacy Scheme: OMAP2/3 */
+		/* MINOR_REV[0:4], MAJOR_REV[4:7] */
+		major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >>
+					OMAP_UART_LEGACY_MVR_MAJ_SHIFT;
+		minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK);
+		break;
+	case 1:
+		/* New Scheme: OMAP4+ */
+		/* MINOR_REV[0:5], MAJOR_REV[8:10] */
+		major = (mvr & OMAP_UART_MVR_MAJ_MASK) >>
+					OMAP_UART_MVR_MAJ_SHIFT;
+		minor = (mvr & OMAP_UART_MVR_MIN_MASK);
+		break;
+	default:
+		dev_warn(&up->pdev->dev,
+			"Unknown %s revision, defaulting to highest\n",
+			up->name);
+		/* highest possible revision */
+		major = 0xff;
+		minor = 0xff;
+	}
+
+	/* normalize revision for the driver */
+	revision = UART_BUILD_REVISION(major, minor);
+
+	switch (revision) {
+	case OMAP_UART_REV_46:
+		up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
+				UART_ERRATA_i291_DMA_FORCEIDLE);
+		break;
+	case OMAP_UART_REV_52:
+		up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
+				UART_ERRATA_i291_DMA_FORCEIDLE);
+		break;
+	case OMAP_UART_REV_63:
+		up->errata |= UART_ERRATA_i202_MDR1_ACCESS;
+		break;
+	default:
+		break;
+	}
+}
+
 static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
 static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
 {
 {
 	struct omap_uart_port_info *omap_up_info;
 	struct omap_uart_port_info *omap_up_info;
@@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev)
 						"%d\n", DEFAULT_CLK_SPEED);
 						"%d\n", DEFAULT_CLK_SPEED);
 	}
 	}
 	up->uart_dma.uart_base = mem->start;
 	up->uart_dma.uart_base = mem->start;
-	up->errata = omap_up_info->errata;
 
 
 	if (omap_up_info->dma_enabled) {
 	if (omap_up_info->dma_enabled) {
 		up->uart_dma.uart_dma_tx = dma_tx->start;
 		up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 
 
+	omap_serial_fill_features_erratas(up);
+
 	ui[up->port.line] = up;
 	ui[up->port.line] = up;
 	serial_omap_add_console_port(up);
 	serial_omap_add_console_port(up);
 
 

+ 30 - 23
drivers/tty/serial/pch_uart.c

@@ -39,6 +39,7 @@ enum {
 	PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
 	PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
 	PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
 	PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
 	PCH_UART_HANDLED_MS_INT_SHIFT,
 	PCH_UART_HANDLED_MS_INT_SHIFT,
+	PCH_UART_HANDLED_LS_INT_SHIFT,
 };
 };
 
 
 enum {
 enum {
@@ -63,6 +64,8 @@ enum {
 					PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<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_HANDLED_MS_INT	(1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
 
 
+#define PCH_UART_HANDLED_LS_INT	(1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1))
+
 #define PCH_UART_RBR		0x00
 #define PCH_UART_RBR		0x00
 #define PCH_UART_THR		0x00
 #define PCH_UART_THR		0x00
 
 
@@ -229,7 +232,6 @@ struct eg20t_port {
 	int start_tx;
 	int start_tx;
 	int start_rx;
 	int start_rx;
 	int tx_empty;
 	int tx_empty;
-	int int_dis_flag;
 	int trigger;
 	int trigger;
 	int trigger_level;
 	int trigger_level;
 	struct pch_uart_buffer rxbuf;
 	struct pch_uart_buffer rxbuf;
@@ -237,7 +239,6 @@ struct eg20t_port {
 	unsigned int fcr;
 	unsigned int fcr;
 	unsigned int mcr;
 	unsigned int mcr;
 	unsigned int use_dma;
 	unsigned int use_dma;
-	unsigned int use_dma_flag;
 	struct dma_async_tx_descriptor	*desc_tx;
 	struct dma_async_tx_descriptor	*desc_tx;
 	struct dma_async_tx_descriptor	*desc_rx;
 	struct dma_async_tx_descriptor	*desc_rx;
 	struct pch_dma_slave		param_tx;
 	struct pch_dma_slave		param_tx;
@@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
 	return i;
 	return i;
 }
 }
 
 
-static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
+static unsigned char 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;
+	return ioread8(priv->membase + UART_IIR) &\
+		      (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP);
 }
 }
 
 
 static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
 static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
@@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port)
 		dma_release_channel(priv->chan_rx);
 		dma_release_channel(priv->chan_rx);
 		priv->chan_rx = NULL;
 		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));
+
+	if (priv->rx_buf_dma) {
+		dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt,
+				  priv->rx_buf_dma);
+		priv->rx_buf_virt = NULL;
+		priv->rx_buf_dma = 0;
+	}
 
 
 	return;
 	return;
 }
 }
@@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
 	unsigned int handled;
 	unsigned int handled;
 	u8 lsr;
 	u8 lsr;
 	int ret = 0;
 	int ret = 0;
-	unsigned int iid;
+	unsigned char iid;
 	unsigned long flags;
 	unsigned long flags;
+	int next = 1;
+	u8 msr;
 
 
 	spin_lock_irqsave(&priv->port.lock, flags);
 	spin_lock_irqsave(&priv->port.lock, flags);
 	handled = 0;
 	handled = 0;
-	while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
+	while (next) {
+		iid = pch_uart_hal_get_iid(priv);
+		if (iid & PCH_UART_IIR_IP) /* No Interrupt */
+			break;
 		switch (iid) {
 		switch (iid) {
 		case PCH_UART_IID_RLS:	/* Receiver Line Status */
 		case PCH_UART_IID_RLS:	/* Receiver Line Status */
 			lsr = pch_uart_hal_get_line_status(priv);
 			lsr = pch_uart_hal_get_line_status(priv);
@@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
 						UART_LSR_PE | UART_LSR_OE)) {
 						UART_LSR_PE | UART_LSR_OE)) {
 				pch_uart_err_ir(priv, lsr);
 				pch_uart_err_ir(priv, lsr);
 				ret = PCH_UART_HANDLED_RX_ERR_INT;
 				ret = PCH_UART_HANDLED_RX_ERR_INT;
+			} else {
+				ret = PCH_UART_HANDLED_LS_INT;
 			}
 			}
 			break;
 			break;
 		case PCH_UART_IID_RDR:	/* Received Data Ready */
 		case PCH_UART_IID_RDR:	/* Received Data Ready */
@@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
 				ret = handle_tx(priv);
 				ret = handle_tx(priv);
 			break;
 			break;
 		case PCH_UART_IID_MS:	/* Modem Status */
 		case PCH_UART_IID_MS:	/* Modem Status */
-			ret = PCH_UART_HANDLED_MS_INT;
+			msr = pch_uart_hal_get_modem(priv);
+			next = 0; /* MS ir prioirty is the lowest. So, MS ir
+				     means final interrupt */
+			if ((msr & UART_MSR_ANY_DELTA) == 0)
+				break;
+			ret |= PCH_UART_HANDLED_MS_INT;
 			break;
 			break;
 		default:	/* Never junp to this label */
 		default:	/* Never junp to this label */
-			dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__,
+			dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__,
 				iid, jiffies);
 				iid, jiffies);
 			ret = -1;
 			ret = -1;
+			next = 0;
 			break;
 			break;
 		}
 		}
 		handled |= (unsigned int)ret;
 		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);
 	spin_unlock_irqrestore(&priv->port.lock, flags);
 	return IRQ_RETVAL(handled);
 	return IRQ_RETVAL(handled);
@@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port)
 	priv = container_of(port, struct eg20t_port, port);
 	priv = container_of(port, struct eg20t_port, port);
 	priv->start_rx = 0;
 	priv->start_rx = 0;
 	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
 	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
-	priv->int_dis_flag = 1;
 }
 }
 
 
 /* Enable the modem status interrupts. */
 /* Enable the modem status interrupts. */
@@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port,
 			__func__);
 			__func__);
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 #endif
 #endif
-		priv->use_dma_flag = 1;
 		dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
 		dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
 		if (!priv->use_dma)
 		if (!priv->use_dma)
 			pch_request_dma(port);
 			pch_request_dma(port);

+ 1 - 0
drivers/tty/serial/serial_core.c

@@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv)
 	tty_unregister_driver(p);
 	tty_unregister_driver(p);
 	put_tty_driver(p);
 	put_tty_driver(p);
 	kfree(drv->state);
 	kfree(drv->state);
+	drv->state = NULL;
 	drv->tty_driver = NULL;
 	drv->tty_driver = NULL;
 }
 }
 
 

+ 2 - 2
drivers/tty/synclink.c

@@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 			printk("%s(%d):block_til_ready blocking on %s count=%d\n",
 			printk("%s(%d):block_til_ready blocking on %s count=%d\n",
 				 __FILE__,__LINE__, tty->driver->name, port->count );
 				 __FILE__,__LINE__, tty->driver->name, port->count );
 				 
 				 
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	}
 	
 	
 	set_current_state(TASK_RUNNING);
 	set_current_state(TASK_RUNNING);

+ 2 - 2
drivers/tty/synclink_gt.c

@@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 		}
 		}
 
 
 		DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
 		DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	}
 
 
 	set_current_state(TASK_RUNNING);
 	set_current_state(TASK_RUNNING);

+ 2 - 2
drivers/tty/synclinkmp.c

@@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 			printk("%s(%d):%s block_til_ready() count=%d\n",
 			printk("%s(%d):%s block_til_ready() count=%d\n",
 				 __FILE__,__LINE__, tty->driver->name, port->count );
 				 __FILE__,__LINE__, tty->driver->name, port->count );
 
 
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	}
 
 
 	set_current_state(TASK_RUNNING);
 	set_current_state(TASK_RUNNING);

+ 65 - 20
drivers/tty/tty_buffer.c

@@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
 	/* Should possibly check if this fails for the largest buffer we
 	/* Should possibly check if this fails for the largest buffer we
 	   have queued and recycle that ? */
 	   have queued and recycle that ? */
 }
 }
-
 /**
 /**
- *	tty_buffer_request_room		-	grow tty buffer if needed
+ *	__tty_buffer_request_room		-	grow tty buffer if needed
  *	@tty: tty structure
  *	@tty: tty structure
  *	@size: size desired
  *	@size: size desired
  *
  *
  *	Make at least size bytes of linear space available for the tty
  *	Make at least size bytes of linear space available for the tty
  *	buffer. If we fail return the size we managed to find.
  *	buffer. If we fail return the size we managed to find.
- *
- *	Locking: Takes tty->buf.lock
+ *      Locking: Caller must hold tty->buf.lock
  */
  */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
 {
 {
 	struct tty_buffer *b, *n;
 	struct tty_buffer *b, *n;
 	int left;
 	int left;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tty->buf.lock, flags);
-
 	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
 	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
 	   remove this conditional if its worth it. This would be invisible
 	   remove this conditional if its worth it. This would be invisible
 	   to the callers */
 	   to the callers */
@@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
 			size = left;
 			size = left;
 	}
 	}
 
 
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
 	return size;
 	return size;
 }
 }
+
+
+/**
+ *	tty_buffer_request_room		-	grow tty buffer if needed
+ *	@tty: tty structure
+ *	@size: size desired
+ *
+ *	Make at least size bytes of linear space available for the tty
+ *	buffer. If we fail return the size we managed to find.
+ *
+ *	Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+	unsigned long flags;
+	int length;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	length = __tty_buffer_request_room(tty, size);
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
+	return length;
+}
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 
 
 /**
 /**
@@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
 	int copied = 0;
 	int copied = 0;
 	do {
 	do {
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
+		int space;
+		unsigned long flags;
+		struct tty_buffer *tb;
+
+		spin_lock_irqsave(&tty->buf.lock, flags);
+		space = __tty_buffer_request_room(tty, goal);
+		tb = tty->buf.tail;
 		/* If there is no space then tb may be NULL */
 		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
+		if (unlikely(space == 0)) {
+			spin_unlock_irqrestore(&tty->buf.lock, flags);
 			break;
 			break;
+		}
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memset(tb->flag_buf_ptr + tb->used, flag, space);
 		memset(tb->flag_buf_ptr + tb->used, flag, space);
 		tb->used += space;
 		tb->used += space;
+		spin_unlock_irqrestore(&tty->buf.lock, flags);
 		copied += space;
 		copied += space;
 		chars += space;
 		chars += space;
 		/* There is a small chance that we need to split the data over
 		/* There is a small chance that we need to split the data over
@@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
 	int copied = 0;
 	int copied = 0;
 	do {
 	do {
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
+		int space;
+		unsigned long __flags;
+		struct tty_buffer *tb;
+
+		spin_lock_irqsave(&tty->buf.lock, __flags);
+		space = __tty_buffer_request_room(tty, goal);
+		tb = tty->buf.tail;
 		/* If there is no space then tb may be NULL */
 		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
+		if (unlikely(space == 0)) {
+			spin_unlock_irqrestore(&tty->buf.lock, __flags);
 			break;
 			break;
+		}
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
 		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
 		tb->used += space;
 		tb->used += space;
+		spin_unlock_irqrestore(&tty->buf.lock, __flags);
 		copied += space;
 		copied += space;
 		chars += space;
 		chars += space;
 		flags += space;
 		flags += space;
@@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip);
 int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
 int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
 								size_t size)
 								size_t size)
 {
 {
-	int space = tty_buffer_request_room(tty, size);
+	int space;
+	unsigned long flags;
+	struct tty_buffer *tb;
+
+	spin_lock_irqsave(&tty->buf.lock, flags);
+	space = __tty_buffer_request_room(tty, size);
+
+	tb = tty->buf.tail;
 	if (likely(space)) {
 	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
 		*chars = tb->char_buf_ptr + tb->used;
 		*chars = tb->char_buf_ptr + tb->used;
 		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
 		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
 		tb->used += space;
 		tb->used += space;
 	}
 	}
+	spin_unlock_irqrestore(&tty->buf.lock, flags);
 	return space;
 	return space;
 }
 }
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
@@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
 int tty_prepare_flip_string_flags(struct tty_struct *tty,
 int tty_prepare_flip_string_flags(struct tty_struct *tty,
 			unsigned char **chars, char **flags, size_t size)
 			unsigned char **chars, char **flags, size_t size)
 {
 {
-	int space = tty_buffer_request_room(tty, size);
+	int space;
+	unsigned long __flags;
+	struct tty_buffer *tb;
+
+	spin_lock_irqsave(&tty->buf.lock, __flags);
+	space = __tty_buffer_request_room(tty, size);
+
+	tb = tty->buf.tail;
 	if (likely(space)) {
 	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
 		*chars = tb->char_buf_ptr + tb->used;
 		*chars = tb->char_buf_ptr + tb->used;
 		*flags = tb->flag_buf_ptr + tb->used;
 		*flags = tb->flag_buf_ptr + tb->used;
 		tb->used += space;
 		tb->used += space;
 	}
 	}
+	spin_unlock_irqrestore(&tty->buf.lock, __flags);
 	return space;
 	return space;
 }
 }
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);

+ 47 - 29
drivers/tty/tty_io.c

@@ -185,6 +185,7 @@ void free_tty_struct(struct tty_struct *tty)
 		put_device(tty->dev);
 		put_device(tty->dev);
 	kfree(tty->write_buf);
 	kfree(tty->write_buf);
 	tty_buffer_free_all(tty);
 	tty_buffer_free_all(tty);
+	tty->magic = 0xDEADDEAD;
 	kfree(tty);
 	kfree(tty);
 }
 }
 
 
@@ -573,7 +574,7 @@ void __tty_hangup(struct tty_struct *tty)
 	}
 	}
 	spin_unlock(&redirect_lock);
 	spin_unlock(&redirect_lock);
 
 
-	tty_lock();
+	tty_lock(tty);
 
 
 	/* some functions below drop BTM, so we need this bit */
 	/* some functions below drop BTM, so we need this bit */
 	set_bit(TTY_HUPPING, &tty->flags);
 	set_bit(TTY_HUPPING, &tty->flags);
@@ -666,7 +667,7 @@ void __tty_hangup(struct tty_struct *tty)
 	clear_bit(TTY_HUPPING, &tty->flags);
 	clear_bit(TTY_HUPPING, &tty->flags);
 	tty_ldisc_enable(tty);
 	tty_ldisc_enable(tty);
 
 
-	tty_unlock();
+	tty_unlock(tty);
 
 
 	if (f)
 	if (f)
 		fput(f);
 		fput(f);
@@ -855,10 +856,11 @@ void disassociate_ctty(int on_exit)
  */
  */
 void no_tty(void)
 void no_tty(void)
 {
 {
+	/* FIXME: Review locking here. The tty_lock never covered any race
+	   between a new association and proc_clear_tty but possible we need
+	   to protect against this anyway */
 	struct task_struct *tsk = current;
 	struct task_struct *tsk = current;
-	tty_lock();
 	disassociate_ctty(0);
 	disassociate_ctty(0);
-	tty_unlock();
 	proc_clear_tty(tsk);
 	proc_clear_tty(tsk);
 }
 }
 
 
@@ -1102,12 +1104,12 @@ void tty_write_message(struct tty_struct *tty, char *msg)
 {
 {
 	if (tty) {
 	if (tty) {
 		mutex_lock(&tty->atomic_write_lock);
 		mutex_lock(&tty->atomic_write_lock);
-		tty_lock();
+		tty_lock(tty);
 		if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
 		if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
-			tty_unlock();
+			tty_unlock(tty);
 			tty->ops->write(tty, msg, strlen(msg));
 			tty->ops->write(tty, msg, strlen(msg));
 		} else
 		} else
-			tty_unlock();
+			tty_unlock(tty);
 		tty_write_unlock(tty);
 		tty_write_unlock(tty);
 	}
 	}
 	return;
 	return;
@@ -1402,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
 	}
 	}
 	initialize_tty_struct(tty, driver, idx);
 	initialize_tty_struct(tty, driver, idx);
 
 
+	tty_lock(tty);
 	retval = tty_driver_install_tty(driver, tty);
 	retval = tty_driver_install_tty(driver, tty);
 	if (retval < 0)
 	if (retval < 0)
 		goto err_deinit_tty;
 		goto err_deinit_tty;
@@ -1414,9 +1417,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
 	retval = tty_ldisc_setup(tty, tty->link);
 	retval = tty_ldisc_setup(tty, tty->link);
 	if (retval)
 	if (retval)
 		goto err_release_tty;
 		goto err_release_tty;
+	/* Return the tty locked so that it cannot vanish under the caller */
 	return tty;
 	return tty;
 
 
 err_deinit_tty:
 err_deinit_tty:
+	tty_unlock(tty);
 	deinitialize_tty_struct(tty);
 	deinitialize_tty_struct(tty);
 	free_tty_struct(tty);
 	free_tty_struct(tty);
 err_module_put:
 err_module_put:
@@ -1425,6 +1430,7 @@ err_module_put:
 
 
 	/* call the tty release_tty routine to clean out this slot */
 	/* call the tty release_tty routine to clean out this slot */
 err_release_tty:
 err_release_tty:
+	tty_unlock(tty);
 	printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
 	printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
 				 "clearing slot %d\n", idx);
 				 "clearing slot %d\n", idx);
 	release_tty(tty, idx);
 	release_tty(tty, idx);
@@ -1627,7 +1633,7 @@ int tty_release(struct inode *inode, struct file *filp)
 	if (tty_paranoia_check(tty, inode, __func__))
 	if (tty_paranoia_check(tty, inode, __func__))
 		return 0;
 		return 0;
 
 
-	tty_lock();
+	tty_lock(tty);
 	check_tty_count(tty, __func__);
 	check_tty_count(tty, __func__);
 
 
 	__tty_fasync(-1, filp, 0);
 	__tty_fasync(-1, filp, 0);
@@ -1636,10 +1642,11 @@ int tty_release(struct inode *inode, struct file *filp)
 	pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
 	pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
 		      tty->driver->subtype == PTY_TYPE_MASTER);
 		      tty->driver->subtype == PTY_TYPE_MASTER);
 	devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
 	devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+	/* Review: parallel close */
 	o_tty = tty->link;
 	o_tty = tty->link;
 
 
 	if (tty_release_checks(tty, o_tty, idx)) {
 	if (tty_release_checks(tty, o_tty, idx)) {
-		tty_unlock();
+		tty_unlock(tty);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -1651,7 +1658,7 @@ int tty_release(struct inode *inode, struct file *filp)
 	if (tty->ops->close)
 	if (tty->ops->close)
 		tty->ops->close(tty, filp);
 		tty->ops->close(tty, filp);
 
 
-	tty_unlock();
+	tty_unlock(tty);
 	/*
 	/*
 	 * Sanity check: if tty->count is going to zero, there shouldn't be
 	 * Sanity check: if tty->count is going to zero, there shouldn't be
 	 * any waiters on tty->read_wait or tty->write_wait.  We test the
 	 * any waiters on tty->read_wait or tty->write_wait.  We test the
@@ -1674,7 +1681,7 @@ int tty_release(struct inode *inode, struct file *filp)
 		   opens on /dev/tty */
 		   opens on /dev/tty */
 
 
 		mutex_lock(&tty_mutex);
 		mutex_lock(&tty_mutex);
-		tty_lock();
+		tty_lock_pair(tty, o_tty);
 		tty_closing = tty->count <= 1;
 		tty_closing = tty->count <= 1;
 		o_tty_closing = o_tty &&
 		o_tty_closing = o_tty &&
 			(o_tty->count <= (pty_master ? 1 : 0));
 			(o_tty->count <= (pty_master ? 1 : 0));
@@ -1705,7 +1712,7 @@ int tty_release(struct inode *inode, struct file *filp)
 
 
 		printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
 		printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
 				__func__, tty_name(tty, buf));
 				__func__, tty_name(tty, buf));
-		tty_unlock();
+		tty_unlock_pair(tty, o_tty);
 		mutex_unlock(&tty_mutex);
 		mutex_unlock(&tty_mutex);
 		schedule();
 		schedule();
 	}
 	}
@@ -1768,7 +1775,7 @@ int tty_release(struct inode *inode, struct file *filp)
 
 
 	/* check whether both sides are closing ... */
 	/* check whether both sides are closing ... */
 	if (!tty_closing || (o_tty && !o_tty_closing)) {
 	if (!tty_closing || (o_tty && !o_tty_closing)) {
-		tty_unlock();
+		tty_unlock_pair(tty, o_tty);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -1781,14 +1788,16 @@ int tty_release(struct inode *inode, struct file *filp)
 	tty_ldisc_release(tty, o_tty);
 	tty_ldisc_release(tty, o_tty);
 	/*
 	/*
 	 * The release_tty function takes care of the details of clearing
 	 * The release_tty function takes care of the details of clearing
-	 * the slots and preserving the termios structure.
+	 * the slots and preserving the termios structure. The tty_unlock_pair
+	 * should be safe as we keep a kref while the tty is locked (so the
+	 * unlock never unlocks a freed tty).
 	 */
 	 */
 	release_tty(tty, idx);
 	release_tty(tty, idx);
+	tty_unlock_pair(tty, o_tty);
 
 
 	/* Make this pty number available for reallocation */
 	/* Make this pty number available for reallocation */
 	if (devpts)
 	if (devpts)
 		devpts_kill_index(inode, idx);
 		devpts_kill_index(inode, idx);
-	tty_unlock();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1800,6 +1809,9 @@ int tty_release(struct inode *inode, struct file *filp)
  *
  *
  *	We cannot return driver and index like for the other nodes because
  *	We cannot return driver and index like for the other nodes because
  *	devpts will not work then. It expects inodes to be from devpts FS.
  *	devpts will not work then. It expects inodes to be from devpts FS.
+ *
+ *	We need to move to returning a refcounted object from all the lookup
+ *	paths including this one.
  */
  */
 static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
 static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
 {
 {
@@ -1816,6 +1828,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
 	/* noctty = 1; */
 	/* noctty = 1; */
 	tty_kref_put(tty);
 	tty_kref_put(tty);
 	/* FIXME: we put a reference and return a TTY! */
 	/* FIXME: we put a reference and return a TTY! */
+	/* This is only safe because the caller holds tty_mutex */
 	return tty;
 	return tty;
 }
 }
 
 
@@ -1888,6 +1901,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
  *	Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
  *	Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
  *		 tty->count should protect the rest.
  *		 tty->count should protect the rest.
  *		 ->siglock protects ->signal/->sighand
  *		 ->siglock protects ->signal/->sighand
+ *
+ *	Note: the tty_unlock/lock cases without a ref are only safe due to
+ *	tty_mutex
  */
  */
 
 
 static int tty_open(struct inode *inode, struct file *filp)
 static int tty_open(struct inode *inode, struct file *filp)
@@ -1911,8 +1927,7 @@ retry_open:
 	retval = 0;
 	retval = 0;
 
 
 	mutex_lock(&tty_mutex);
 	mutex_lock(&tty_mutex);
-	tty_lock();
-
+	/* This is protected by the tty_mutex */
 	tty = tty_open_current_tty(device, filp);
 	tty = tty_open_current_tty(device, filp);
 	if (IS_ERR(tty)) {
 	if (IS_ERR(tty)) {
 		retval = PTR_ERR(tty);
 		retval = PTR_ERR(tty);
@@ -1933,17 +1948,19 @@ retry_open:
 	}
 	}
 
 
 	if (tty) {
 	if (tty) {
+		tty_lock(tty);
 		retval = tty_reopen(tty);
 		retval = tty_reopen(tty);
-		if (retval)
+		if (retval < 0) {
+			tty_unlock(tty);
 			tty = ERR_PTR(retval);
 			tty = ERR_PTR(retval);
-	} else
+		}
+	} else	/* Returns with the tty_lock held for now */
 		tty = tty_init_dev(driver, index);
 		tty = tty_init_dev(driver, index);
 
 
 	mutex_unlock(&tty_mutex);
 	mutex_unlock(&tty_mutex);
 	if (driver)
 	if (driver)
 		tty_driver_kref_put(driver);
 		tty_driver_kref_put(driver);
 	if (IS_ERR(tty)) {
 	if (IS_ERR(tty)) {
-		tty_unlock();
 		retval = PTR_ERR(tty);
 		retval = PTR_ERR(tty);
 		goto err_file;
 		goto err_file;
 	}
 	}
@@ -1972,7 +1989,7 @@ retry_open:
 		printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
 		printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
 				retval, tty->name);
 				retval, tty->name);
 #endif
 #endif
-		tty_unlock(); /* need to call tty_release without BTM */
+		tty_unlock(tty); /* need to call tty_release without BTM */
 		tty_release(inode, filp);
 		tty_release(inode, filp);
 		if (retval != -ERESTARTSYS)
 		if (retval != -ERESTARTSYS)
 			return retval;
 			return retval;
@@ -1984,17 +2001,15 @@ retry_open:
 		/*
 		/*
 		 * Need to reset f_op in case a hangup happened.
 		 * Need to reset f_op in case a hangup happened.
 		 */
 		 */
-		tty_lock();
 		if (filp->f_op == &hung_up_tty_fops)
 		if (filp->f_op == &hung_up_tty_fops)
 			filp->f_op = &tty_fops;
 			filp->f_op = &tty_fops;
-		tty_unlock();
 		goto retry_open;
 		goto retry_open;
 	}
 	}
-	tty_unlock();
+	tty_unlock(tty);
 
 
 
 
 	mutex_lock(&tty_mutex);
 	mutex_lock(&tty_mutex);
-	tty_lock();
+	tty_lock(tty);
 	spin_lock_irq(&current->sighand->siglock);
 	spin_lock_irq(&current->sighand->siglock);
 	if (!noctty &&
 	if (!noctty &&
 	    current->signal->leader &&
 	    current->signal->leader &&
@@ -2002,11 +2017,10 @@ retry_open:
 	    tty->session == NULL)
 	    tty->session == NULL)
 		__proc_set_tty(current, tty);
 		__proc_set_tty(current, tty);
 	spin_unlock_irq(&current->sighand->siglock);
 	spin_unlock_irq(&current->sighand->siglock);
-	tty_unlock();
+	tty_unlock(tty);
 	mutex_unlock(&tty_mutex);
 	mutex_unlock(&tty_mutex);
 	return 0;
 	return 0;
 err_unlock:
 err_unlock:
-	tty_unlock();
 	mutex_unlock(&tty_mutex);
 	mutex_unlock(&tty_mutex);
 	/* after locks to avoid deadlock */
 	/* after locks to avoid deadlock */
 	if (!IS_ERR_OR_NULL(driver))
 	if (!IS_ERR_OR_NULL(driver))
@@ -2089,10 +2103,13 @@ out:
 
 
 static int tty_fasync(int fd, struct file *filp, int on)
 static int tty_fasync(int fd, struct file *filp, int on)
 {
 {
+	struct tty_struct *tty = file_tty(filp);
 	int retval;
 	int retval;
-	tty_lock();
+
+	tty_lock(tty);
 	retval = __tty_fasync(fd, filp, on);
 	retval = __tty_fasync(fd, filp, on);
-	tty_unlock();
+	tty_unlock(tty);
+
 	return retval;
 	return retval;
 }
 }
 
 
@@ -2929,6 +2946,7 @@ void initialize_tty_struct(struct tty_struct *tty,
 	tty->pgrp = NULL;
 	tty->pgrp = NULL;
 	tty->overrun_time = jiffies;
 	tty->overrun_time = jiffies;
 	tty_buffer_init(tty);
 	tty_buffer_init(tty);
+	mutex_init(&tty->legacy_mutex);
 	mutex_init(&tty->termios_mutex);
 	mutex_init(&tty->termios_mutex);
 	mutex_init(&tty->ldisc_mutex);
 	mutex_init(&tty->ldisc_mutex);
 	init_waitqueue_head(&tty->write_wait);
 	init_waitqueue_head(&tty->write_wait);

+ 19 - 18
drivers/tty/tty_ldisc.c

@@ -28,7 +28,6 @@
 
 
 static DEFINE_SPINLOCK(tty_ldisc_lock);
 static DEFINE_SPINLOCK(tty_ldisc_lock);
 static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
 static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle);
 /* Line disc dispatch table */
 /* Line disc dispatch table */
 static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
 static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
 
 
@@ -65,7 +64,7 @@ static void put_ldisc(struct tty_ldisc *ld)
 		return;
 		return;
 	}
 	}
 	local_irq_restore(flags);
 	local_irq_restore(flags);
-	wake_up(&tty_ldisc_idle);
+	wake_up(&ld->wq_idle);
 }
 }
 
 
 /**
 /**
@@ -200,6 +199,8 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
 
 
 	ld->ops = ldops;
 	ld->ops = ldops;
 	atomic_set(&ld->users, 1);
 	atomic_set(&ld->users, 1);
+	init_waitqueue_head(&ld->wq_idle);
+
 	return ld;
 	return ld;
 }
 }
 
 
@@ -538,7 +539,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
 static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
 static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
 {
 {
 	long ret;
 	long ret;
-	ret = wait_event_timeout(tty_ldisc_idle,
+	ret = wait_event_timeout(tty->ldisc->wq_idle,
 			atomic_read(&tty->ldisc->users) == 1, timeout);
 			atomic_read(&tty->ldisc->users) == 1, timeout);
 	return ret > 0 ? 0 : -EBUSY;
 	return ret > 0 ? 0 : -EBUSY;
 }
 }
@@ -567,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 	if (IS_ERR(new_ldisc))
 	if (IS_ERR(new_ldisc))
 		return PTR_ERR(new_ldisc);
 		return PTR_ERR(new_ldisc);
 
 
-	tty_lock();
+	tty_lock(tty);
 	/*
 	/*
 	 *	We need to look at the tty locking here for pty/tty pairs
 	 *	We need to look at the tty locking here for pty/tty pairs
 	 *	when both sides try to change in parallel.
 	 *	when both sides try to change in parallel.
@@ -581,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 	 */
 	 */
 
 
 	if (tty->ldisc->ops->num == ldisc) {
 	if (tty->ldisc->ops->num == ldisc) {
-		tty_unlock();
+		tty_unlock(tty);
 		tty_ldisc_put(new_ldisc);
 		tty_ldisc_put(new_ldisc);
 		return 0;
 		return 0;
 	}
 	}
 
 
-	tty_unlock();
+	tty_unlock(tty);
 	/*
 	/*
 	 *	Problem: What do we do if this blocks ?
 	 *	Problem: What do we do if this blocks ?
 	 *	We could deadlock here
 	 *	We could deadlock here
@@ -594,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
 
 	tty_wait_until_sent(tty, 0);
 	tty_wait_until_sent(tty, 0);
 
 
-	tty_lock();
+	tty_lock(tty);
 	mutex_lock(&tty->ldisc_mutex);
 	mutex_lock(&tty->ldisc_mutex);
 
 
 	/*
 	/*
@@ -604,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
 
 	while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
 	while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
 		mutex_unlock(&tty->ldisc_mutex);
 		mutex_unlock(&tty->ldisc_mutex);
-		tty_unlock();
+		tty_unlock(tty);
 		wait_event(tty_ldisc_wait,
 		wait_event(tty_ldisc_wait,
 			test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
 			test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
-		tty_lock();
+		tty_lock(tty);
 		mutex_lock(&tty->ldisc_mutex);
 		mutex_lock(&tty->ldisc_mutex);
 	}
 	}
 
 
@@ -622,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
 
 	o_ldisc = tty->ldisc;
 	o_ldisc = tty->ldisc;
 
 
-	tty_unlock();
+	tty_unlock(tty);
 	/*
 	/*
 	 *	Make sure we don't change while someone holds a
 	 *	Make sure we don't change while someone holds a
 	 *	reference to the line discipline. The TTY_LDISC bit
 	 *	reference to the line discipline. The TTY_LDISC bit
@@ -649,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
 
 	retval = tty_ldisc_wait_idle(tty, 5 * HZ);
 	retval = tty_ldisc_wait_idle(tty, 5 * HZ);
 
 
-	tty_lock();
+	tty_lock(tty);
 	mutex_lock(&tty->ldisc_mutex);
 	mutex_lock(&tty->ldisc_mutex);
 
 
 	/* handle wait idle failure locked */
 	/* handle wait idle failure locked */
@@ -664,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 		clear_bit(TTY_LDISC_CHANGING, &tty->flags);
 		clear_bit(TTY_LDISC_CHANGING, &tty->flags);
 		mutex_unlock(&tty->ldisc_mutex);
 		mutex_unlock(&tty->ldisc_mutex);
 		tty_ldisc_put(new_ldisc);
 		tty_ldisc_put(new_ldisc);
-		tty_unlock();
+		tty_unlock(tty);
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
@@ -707,7 +708,7 @@ enable:
 	if (o_work)
 	if (o_work)
 		schedule_work(&o_tty->buf.work);
 		schedule_work(&o_tty->buf.work);
 	mutex_unlock(&tty->ldisc_mutex);
 	mutex_unlock(&tty->ldisc_mutex);
-	tty_unlock();
+	tty_unlock(tty);
 	return retval;
 	return retval;
 }
 }
 
 
@@ -815,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 	 * need to wait for another function taking the BTM
 	 * need to wait for another function taking the BTM
 	 */
 	 */
 	clear_bit(TTY_LDISC, &tty->flags);
 	clear_bit(TTY_LDISC, &tty->flags);
-	tty_unlock();
+	tty_unlock(tty);
 	cancel_work_sync(&tty->buf.work);
 	cancel_work_sync(&tty->buf.work);
 	mutex_unlock(&tty->ldisc_mutex);
 	mutex_unlock(&tty->ldisc_mutex);
 retry:
 retry:
-	tty_lock();
+	tty_lock(tty);
 	mutex_lock(&tty->ldisc_mutex);
 	mutex_lock(&tty->ldisc_mutex);
 
 
 	/* At this point we have a closed ldisc and we want to
 	/* At this point we have a closed ldisc and we want to
@@ -830,7 +831,7 @@ retry:
 		if (atomic_read(&tty->ldisc->users) != 1) {
 		if (atomic_read(&tty->ldisc->users) != 1) {
 			char cur_n[TASK_COMM_LEN], tty_n[64];
 			char cur_n[TASK_COMM_LEN], tty_n[64];
 			long timeout = 3 * HZ;
 			long timeout = 3 * HZ;
-			tty_unlock();
+			tty_unlock(tty);
 
 
 			while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
 			while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
 				timeout = MAX_SCHEDULE_TIMEOUT;
 				timeout = MAX_SCHEDULE_TIMEOUT;
@@ -911,10 +912,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
 	 * race with the set_ldisc code path.
 	 * race with the set_ldisc code path.
 	 */
 	 */
 
 
-	tty_unlock();
+	tty_unlock(tty);
 	tty_ldisc_halt(tty);
 	tty_ldisc_halt(tty);
 	tty_ldisc_flush_works(tty);
 	tty_ldisc_flush_works(tty);
-	tty_lock();
+	tty_lock(tty);
 
 
 	mutex_lock(&tty->ldisc_mutex);
 	mutex_lock(&tty->ldisc_mutex);
 	/*
 	/*

+ 45 - 15
drivers/tty/tty_mutex.c

@@ -4,29 +4,59 @@
 #include <linux/semaphore.h>
 #include <linux/semaphore.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 
 
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
+/* Legacy tty mutex glue */
 
 
 /*
 /*
  * Getting the big tty mutex.
  * Getting the big tty mutex.
  */
  */
-void __lockfunc tty_lock(void)
+
+void __lockfunc tty_lock(struct tty_struct *tty)
 {
 {
-	mutex_lock(&big_tty_mutex);
+	if (tty->magic != TTY_MAGIC) {
+		printk(KERN_ERR "L Bad %p\n", tty);
+		WARN_ON(1);
+		return;
+	}
+	tty_kref_get(tty);
+	mutex_lock(&tty->legacy_mutex);
 }
 }
 EXPORT_SYMBOL(tty_lock);
 EXPORT_SYMBOL(tty_lock);
 
 
-void __lockfunc tty_unlock(void)
+void __lockfunc tty_unlock(struct tty_struct *tty)
 {
 {
-	mutex_unlock(&big_tty_mutex);
+	if (tty->magic != TTY_MAGIC) {
+		printk(KERN_ERR "U Bad %p\n", tty);
+		WARN_ON(1);
+		return;
+	}
+	mutex_unlock(&tty->legacy_mutex);
+	tty_kref_put(tty);
 }
 }
 EXPORT_SYMBOL(tty_unlock);
 EXPORT_SYMBOL(tty_unlock);
+
+/*
+ * Getting the big tty mutex for a pair of ttys with lock ordering
+ * On a non pty/tty pair tty2 can be NULL which is just fine.
+ */
+void __lockfunc tty_lock_pair(struct tty_struct *tty,
+					struct tty_struct *tty2)
+{
+	if (tty < tty2) {
+		tty_lock(tty);
+		tty_lock(tty2);
+	} else {
+		if (tty2 && tty2 != tty)
+			tty_lock(tty2);
+		tty_lock(tty);
+	}
+}
+EXPORT_SYMBOL(tty_lock_pair);
+
+void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+						struct tty_struct *tty2)
+{
+	tty_unlock(tty);
+	if (tty2 && tty2 != tty)
+		tty_unlock(tty2);
+}
+EXPORT_SYMBOL(tty_unlock_pair);

+ 3 - 3
drivers/tty/tty_port.c

@@ -230,7 +230,7 @@ int tty_port_block_til_ready(struct tty_port *port,
 
 
 	/* block if port is in the process of being closed */
 	/* block if port is in the process of being closed */
 	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
 	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-		wait_event_interruptible_tty(port->close_wait,
+		wait_event_interruptible_tty(tty, port->close_wait,
 				!(port->flags & ASYNC_CLOSING));
 				!(port->flags & ASYNC_CLOSING));
 		if (port->flags & ASYNC_HUP_NOTIFY)
 		if (port->flags & ASYNC_HUP_NOTIFY)
 			return -EAGAIN;
 			return -EAGAIN;
@@ -296,9 +296,9 @@ int tty_port_block_til_ready(struct tty_port *port,
 			retval = -ERESTARTSYS;
 			retval = -ERESTARTSYS;
 			break;
 			break;
 		}
 		}
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	}
 	finish_wait(&port->open_wait, &wait);
 	finish_wait(&port->open_wait, &wait);
 
 

+ 91 - 32
drivers/tty/vt/consolemap.c

@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/tty.h>
 #include <linux/tty.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
+#include <linux/console.h>
 #include <linux/consolemap.h>
 #include <linux/consolemap.h>
 #include <linux/vt_kern.h>
 #include <linux/vt_kern.h>
 
 
@@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg)
 	if (!access_ok(VERIFY_READ, arg, E_TABSZ))
 	if (!access_ok(VERIFY_READ, arg, E_TABSZ))
 		return -EFAULT;
 		return -EFAULT;
 
 
+	console_lock();
 	for (i=0; i<E_TABSZ ; i++) {
 	for (i=0; i<E_TABSZ ; i++) {
 		unsigned char uc;
 		unsigned char uc;
 		__get_user(uc, arg+i);
 		__get_user(uc, arg+i);
@@ -319,6 +321,7 @@ int con_set_trans_old(unsigned char __user * arg)
 	}
 	}
 
 
 	update_user_maps();
 	update_user_maps();
+	console_unlock();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -330,11 +333,13 @@ int con_get_trans_old(unsigned char __user * arg)
 	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
 	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
 		return -EFAULT;
 		return -EFAULT;
 
 
+	console_lock();
 	for (i=0; i<E_TABSZ ; i++)
 	for (i=0; i<E_TABSZ ; i++)
-	  {
-	    ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
-	    __put_user((ch & ~0xff) ? 0 : ch, arg+i);
-	  }
+	{
+		ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
+		__put_user((ch & ~0xff) ? 0 : ch, arg+i);
+	}
+	console_unlock();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -346,6 +351,7 @@ int con_set_trans_new(ushort __user * arg)
 	if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
 	if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
 		return -EFAULT;
 		return -EFAULT;
 
 
+	console_lock();
 	for (i=0; i<E_TABSZ ; i++) {
 	for (i=0; i<E_TABSZ ; i++) {
 		unsigned short us;
 		unsigned short us;
 		__get_user(us, arg+i);
 		__get_user(us, arg+i);
@@ -353,6 +359,7 @@ int con_set_trans_new(ushort __user * arg)
 	}
 	}
 
 
 	update_user_maps();
 	update_user_maps();
+	console_unlock();
 	return 0;
 	return 0;
 }
 }
 
 
@@ -364,8 +371,10 @@ int con_get_trans_new(ushort __user * arg)
 	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
 	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
 		return -EFAULT;
 		return -EFAULT;
 
 
+	console_lock();
 	for (i=0; i<E_TABSZ ; i++)
 	for (i=0; i<E_TABSZ ; i++)
 	  __put_user(p[i], arg+i);
 	  __put_user(p[i], arg+i);
+	console_unlock();
 	
 	
 	return 0;
 	return 0;
 }
 }
@@ -407,6 +416,7 @@ static void con_release_unimap(struct uni_pagedir *p)
 	}
 	}
 }
 }
 
 
+/* Caller must hold the console lock */
 void con_free_unimap(struct vc_data *vc)
 void con_free_unimap(struct vc_data *vc)
 {
 {
 	struct uni_pagedir *p;
 	struct uni_pagedir *p;
@@ -487,17 +497,21 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
 	return 0;
 	return 0;
 }
 }
 
 
-/* ui is a leftover from using a hashtable, but might be used again */
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+/* ui is a leftover from using a hashtable, but might be used again
+   Caller must hold the lock */
+static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
 {
 {
 	struct uni_pagedir *p, *q;
 	struct uni_pagedir *p, *q;
-  
+
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	if (p && p->readonly) return -EIO;
+	if (p && p->readonly)
+		return -EIO;
+
 	if (!p || --p->refcount) {
 	if (!p || --p->refcount) {
 		q = kzalloc(sizeof(*p), GFP_KERNEL);
 		q = kzalloc(sizeof(*p), GFP_KERNEL);
 		if (!q) {
 		if (!q) {
-			if (p) p->refcount++;
+			if (p)
+				p->refcount++;
 			return -ENOMEM;
 			return -ENOMEM;
 		}
 		}
 		q->refcount=1;
 		q->refcount=1;
@@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
 	return 0;
 	return 0;
 }
 }
 
 
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+{
+	int ret;
+	console_lock();
+	ret = con_do_clear_unimap(vc, ui);
+	console_unlock();
+	return ret;
+}
+	
 int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 {
 {
 	int err = 0, err1, i;
 	int err = 0, err1, i;
 	struct uni_pagedir *p, *q;
 	struct uni_pagedir *p, *q;
 
 
+	console_lock();
+
 	/* Save original vc_unipagdir_loc in case we allocate a new one */
 	/* Save original vc_unipagdir_loc in case we allocate a new one */
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	if (p->readonly) return -EIO;
+	if (p->readonly) {
+		console_unlock();
+		return -EIO;
+	}
 	
 	
-	if (!ct) return 0;
+	if (!ct) {
+		console_unlock();
+		return 0;
+	}
 	
 	
 	if (p->refcount > 1) {
 	if (p->refcount > 1) {
 		int j, k;
 		int j, k;
 		u16 **p1, *p2, l;
 		u16 **p1, *p2, l;
 		
 		
-		err1 = con_clear_unimap(vc, NULL);
-		if (err1) return err1;
+		err1 = con_do_clear_unimap(vc, NULL);
+		if (err1) {
+			console_unlock();
+			return err1;
+		}
 		
 		
 		/*
 		/*
 		 * Since refcount was > 1, con_clear_unimap() allocated a
 		 * Since refcount was > 1, con_clear_unimap() allocated a
@@ -558,7 +592,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 						*vc->vc_uni_pagedir_loc = (unsigned long)p;
 						*vc->vc_uni_pagedir_loc = (unsigned long)p;
 						con_release_unimap(q);
 						con_release_unimap(q);
 						kfree(q);
 						kfree(q);
-						return err1;
+						console_unlock();
+						return err1; 
 					}
 					}
 				}
 				}
 			} else {
 			} else {
@@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 	/*
 	/*
 	 * Merge with fontmaps of any other virtual consoles.
 	 * Merge with fontmaps of any other virtual consoles.
 	 */
 	 */
-	if (con_unify_unimap(vc, p))
+	if (con_unify_unimap(vc, p)) {
+		console_unlock();
 		return err;
 		return err;
+	}
 
 
 	for (i = 0; i <= 3; i++)
 	for (i = 0; i <= 3; i++)
 		set_inverse_transl(vc, p, i); /* Update inverse translations */
 		set_inverse_transl(vc, p, i); /* Update inverse translations */
 	set_inverse_trans_unicode(vc, p);
 	set_inverse_trans_unicode(vc, p);
-  
+
+	console_unlock();
 	return err;
 	return err;
 }
 }
 
 
-/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
-   The representation used was the most compact I could come up
-   with.  This routine is executed at sys_setup time, and when the
-   PIO_FONTRESET ioctl is called. */
-
+/**
+ *	con_set_default_unimap	-	set default unicode map
+ *	@vc: the console we are updating
+ *
+ *	Loads the unimap for the hardware font, as defined in uni_hash.tbl.
+ *	The representation used was the most compact I could come up
+ *	with.  This routine is executed at video setup, and when the
+ *	PIO_FONTRESET ioctl is called. 
+ *
+ *	The caller must hold the console lock
+ */
 int con_set_default_unimap(struct vc_data *vc)
 int con_set_default_unimap(struct vc_data *vc)
 {
 {
 	int i, j, err = 0, err1;
 	int i, j, err = 0, err1;
@@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc)
 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 		if (p == dflt)
 		if (p == dflt)
 			return 0;
 			return 0;
+
 		dflt->refcount++;
 		dflt->refcount++;
 		*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
 		*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
 		if (p && !--p->refcount) {
 		if (p && !--p->refcount) {
@@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc)
 	
 	
 	/* The default font is always 256 characters */
 	/* The default font is always 256 characters */
 
 
-	err = con_clear_unimap(vc, NULL);
-	if (err) return err;
+	err = con_do_clear_unimap(vc, NULL);
+	if (err)
+		return err;
     
     
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	q = dfont_unitable;
 	q = dfont_unitable;
@@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc)
 }
 }
 EXPORT_SYMBOL(con_set_default_unimap);
 EXPORT_SYMBOL(con_set_default_unimap);
 
 
+/**
+ *	con_copy_unimap		-	copy unimap between two vts
+ *	@dst_vc: target
+ *	@src_vt: source
+ *
+ *	The caller must hold the console lock when invoking this method
+ */
 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
 {
 {
 	struct uni_pagedir *q;
 	struct uni_pagedir *q;
@@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
 	*dst_vc->vc_uni_pagedir_loc = (long)q;
 	*dst_vc->vc_uni_pagedir_loc = (long)q;
 	return 0;
 	return 0;
 }
 }
+EXPORT_SYMBOL(con_copy_unimap);
 
 
+/**
+ *	con_get_unimap		-	get the unicode map
+ *	@vc: the console to read from
+ *
+ *	Read the console unicode data for this console. Called from the ioctl
+ *	handlers.
+ */
 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
 {
 {
 	int i, j, k, ect;
 	int i, j, k, ect;
 	u16 **p1, *p2;
 	u16 **p1, *p2;
 	struct uni_pagedir *p;
 	struct uni_pagedir *p;
 
 
+	console_lock();
+
 	ect = 0;
 	ect = 0;
 	if (*vc->vc_uni_pagedir_loc) {
 	if (*vc->vc_uni_pagedir_loc) {
 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
@@ -694,22 +757,19 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
 				}
 				}
 	}
 	}
 	__put_user(ect, uct);
 	__put_user(ect, uct);
+	console_unlock();
 	return ((ect <= ct) ? 0 : -ENOMEM);
 	return ((ect <= ct) ? 0 : -ENOMEM);
 }
 }
 
 
-void con_protect_unimap(struct vc_data *vc, int rdonly)
-{
-	struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	
-	if (p)
-		p->readonly = rdonly;
-}
-
 /*
 /*
  * Always use USER_MAP. These functions are used by the keyboard,
  * Always use USER_MAP. These functions are used by the keyboard,
  * which shouldn't be affected by G0/G1 switching, etc.
  * which shouldn't be affected by G0/G1 switching, etc.
  * If the user map still contains default values, i.e. the
  * If the user map still contains default values, i.e. the
  * direct-to-font mapping, then assume user is using Latin1.
  * direct-to-font mapping, then assume user is using Latin1.
+ *
+ * FIXME: at some point we need to decide if we want to lock the table
+ * update element itself via the keyboard_event_lock for consistency with the
+ * keyboard driver as well as the consoles
  */
  */
 /* may be called during an interrupt */
 /* may be called during an interrupt */
 u32 conv_8bit_to_uni(unsigned char c)
 u32 conv_8bit_to_uni(unsigned char c)
@@ -777,4 +837,3 @@ console_map_init(void)
 			con_set_default_unimap(vc_cons[i].d);
 			con_set_default_unimap(vc_cons[i].d);
 }
 }
 
 
-EXPORT_SYMBOL(con_copy_unimap);

+ 32 - 36
drivers/tty/vt/vt.c

@@ -3892,36 +3892,6 @@ static void set_palette(struct vc_data *vc)
 		vc->vc_sw->con_set_palette(vc, color_table);
 		vc->vc_sw->con_set_palette(vc, color_table);
 }
 }
 
 
-static int set_get_cmap(unsigned char __user *arg, int set)
-{
-    int i, j, k;
-
-    WARN_CONSOLE_UNLOCKED();
-
-    for (i = 0; i < 16; i++)
-	if (set) {
-	    get_user(default_red[i], arg++);
-	    get_user(default_grn[i], arg++);
-	    get_user(default_blu[i], arg++);
-	} else {
-	    put_user(default_red[i], arg++);
-	    put_user(default_grn[i], arg++);
-	    put_user(default_blu[i], arg++);
-	}
-    if (set) {
-	for (i = 0; i < MAX_NR_CONSOLES; i++)
-	    if (vc_cons_allocated(i)) {
-		for (j = k = 0; j < 16; j++) {
-		    vc_cons[i].d->vc_palette[k++] = default_red[j];
-		    vc_cons[i].d->vc_palette[k++] = default_grn[j];
-		    vc_cons[i].d->vc_palette[k++] = default_blu[j];
-		}
-		set_palette(vc_cons[i].d);
-	    }
-    }
-    return 0;
-}
-
 /*
 /*
  * Load palette into the DAC registers. arg points to a colour
  * Load palette into the DAC registers. arg points to a colour
  * map, 3 bytes per colour, 16 colours, range from 0 to 255.
  * map, 3 bytes per colour, 16 colours, range from 0 to 255.
@@ -3929,24 +3899,50 @@ static int set_get_cmap(unsigned char __user *arg, int set)
 
 
 int con_set_cmap(unsigned char __user *arg)
 int con_set_cmap(unsigned char __user *arg)
 {
 {
-	int rc;
+	int i, j, k;
+	unsigned char colormap[3*16];
+
+	if (copy_from_user(colormap, arg, sizeof(colormap)))
+		return -EFAULT;
 
 
 	console_lock();
 	console_lock();
-	rc = set_get_cmap (arg,1);
+	for (i = k = 0; i < 16; i++) {
+		default_red[i] = colormap[k++];
+		default_grn[i] = colormap[k++];
+		default_blu[i] = colormap[k++];
+	}
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (!vc_cons_allocated(i))
+			continue;
+		for (j = k = 0; j < 16; j++) {
+			vc_cons[i].d->vc_palette[k++] = default_red[j];
+			vc_cons[i].d->vc_palette[k++] = default_grn[j];
+			vc_cons[i].d->vc_palette[k++] = default_blu[j];
+		}
+		set_palette(vc_cons[i].d);
+	}
 	console_unlock();
 	console_unlock();
 
 
-	return rc;
+	return 0;
 }
 }
 
 
 int con_get_cmap(unsigned char __user *arg)
 int con_get_cmap(unsigned char __user *arg)
 {
 {
-	int rc;
+	int i, k;
+	unsigned char colormap[3*16];
 
 
 	console_lock();
 	console_lock();
-	rc = set_get_cmap (arg,0);
+	for (i = k = 0; i < 16; i++) {
+		colormap[k++] = default_red[i];
+		colormap[k++] = default_grn[i];
+		colormap[k++] = default_blu[i];
+	}
 	console_unlock();
 	console_unlock();
 
 
-	return rc;
+	if (copy_to_user(arg, colormap, sizeof(colormap)))
+		return -EFAULT;
+
+	return 0;
 }
 }
 
 
 void reset_palette(struct vc_data *vc)
 void reset_palette(struct vc_data *vc)

+ 5 - 20
drivers/tty/vt/vt_ioctl.c

@@ -910,7 +910,9 @@ int vt_ioctl(struct tty_struct *tty,
 		ret = con_font_op(vc_cons[fg_console].d, &op);
 		ret = con_font_op(vc_cons[fg_console].d, &op);
 		if (ret)
 		if (ret)
 			break;
 			break;
+		console_lock();
 		con_set_default_unimap(vc_cons[fg_console].d);
 		con_set_default_unimap(vc_cons[fg_console].d);
+		console_unlock();
 		break;
 		break;
 		}
 		}
 #endif
 #endif
@@ -934,33 +936,23 @@ int vt_ioctl(struct tty_struct *tty,
 	case PIO_SCRNMAP:
 	case PIO_SCRNMAP:
 		if (!perm)
 		if (!perm)
 			ret = -EPERM;
 			ret = -EPERM;
-		else {
-			tty_lock();
+		else
 			ret = con_set_trans_old(up);
 			ret = con_set_trans_old(up);
-			tty_unlock();
-		}
 		break;
 		break;
 
 
 	case GIO_SCRNMAP:
 	case GIO_SCRNMAP:
-		tty_lock();
 		ret = con_get_trans_old(up);
 		ret = con_get_trans_old(up);
-		tty_unlock();
 		break;
 		break;
 
 
 	case PIO_UNISCRNMAP:
 	case PIO_UNISCRNMAP:
 		if (!perm)
 		if (!perm)
 			ret = -EPERM;
 			ret = -EPERM;
-		else {
-			tty_lock();
+		else
 			ret = con_set_trans_new(up);
 			ret = con_set_trans_new(up);
-			tty_unlock();
-		}
 		break;
 		break;
 
 
 	case GIO_UNISCRNMAP:
 	case GIO_UNISCRNMAP:
-		tty_lock();
 		ret = con_get_trans_new(up);
 		ret = con_get_trans_new(up);
-		tty_unlock();
 		break;
 		break;
 
 
 	case PIO_UNIMAPCLR:
 	case PIO_UNIMAPCLR:
@@ -970,19 +962,14 @@ int vt_ioctl(struct tty_struct *tty,
 		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
 		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
 		if (ret)
 		if (ret)
 			ret = -EFAULT;
 			ret = -EFAULT;
-		else {
-			tty_lock();
+		else
 			con_clear_unimap(vc, &ui);
 			con_clear_unimap(vc, &ui);
-			tty_unlock();
-		}
 		break;
 		break;
 	      }
 	      }
 
 
 	case PIO_UNIMAP:
 	case PIO_UNIMAP:
 	case GIO_UNIMAP:
 	case GIO_UNIMAP:
-		tty_lock();
 		ret = do_unimap_ioctl(cmd, up, perm, vc);
 		ret = do_unimap_ioctl(cmd, up, perm, vc);
-		tty_unlock();
 		break;
 		break;
 
 
 	case VT_LOCKSWITCH:
 	case VT_LOCKSWITCH:
@@ -1196,9 +1183,7 @@ long vt_compat_ioctl(struct tty_struct *tty,
 
 
 	case PIO_UNIMAP:
 	case PIO_UNIMAP:
 	case GIO_UNIMAP:
 	case GIO_UNIMAP:
-		tty_lock();
 		ret = compat_unimap_ioctl(cmd, up, perm, vc);
 		ret = compat_unimap_ioctl(cmd, up, perm, vc);
-		tty_unlock();
 		break;
 		break;
 
 
 	/*
 	/*

+ 24 - 27
drivers/usb/gadget/u_serial.c

@@ -94,17 +94,14 @@ struct gs_buf {
  * (and thus for each /dev/ node).
  * (and thus for each /dev/ node).
  */
  */
 struct gs_port {
 struct gs_port {
+	struct tty_port		port;
 	spinlock_t		port_lock;	/* guard port_* access */
 	spinlock_t		port_lock;	/* guard port_* access */
 
 
 	struct gserial		*port_usb;
 	struct gserial		*port_usb;
-	struct tty_struct	*port_tty;
 
 
-	unsigned		open_count;
 	bool			openclose;	/* open/close in progress */
 	bool			openclose;	/* open/close in progress */
 	u8			port_num;
 	u8			port_num;
 
 
-	wait_queue_head_t	close_wait;	/* wait for last close */
-
 	struct list_head	read_pool;
 	struct list_head	read_pool;
 	int read_started;
 	int read_started;
 	int read_allocated;
 	int read_allocated;
@@ -412,8 +409,8 @@ __acquires(&port->port_lock)
 			break;
 			break;
 	}
 	}
 
 
-	if (do_tty_wake && port->port_tty)
-		tty_wakeup(port->port_tty);
+	if (do_tty_wake && port->port.tty)
+		tty_wakeup(port->port.tty);
 	return status;
 	return status;
 }
 }
 
 
@@ -435,7 +432,7 @@ __acquires(&port->port_lock)
 		struct tty_struct	*tty;
 		struct tty_struct	*tty;
 
 
 		/* no more rx if closed */
 		/* no more rx if closed */
-		tty = port->port_tty;
+		tty = port->port.tty;
 		if (!tty)
 		if (!tty)
 			break;
 			break;
 
 
@@ -488,7 +485,7 @@ static void gs_rx_push(unsigned long _port)
 
 
 	/* hand any queued data to the tty */
 	/* hand any queued data to the tty */
 	spin_lock_irq(&port->port_lock);
 	spin_lock_irq(&port->port_lock);
-	tty = port->port_tty;
+	tty = port->port.tty;
 	while (!list_empty(queue)) {
 	while (!list_empty(queue)) {
 		struct usb_request	*req;
 		struct usb_request	*req;
 
 
@@ -699,7 +696,7 @@ static int gs_start_io(struct gs_port *port)
 
 
 	/* unblock any pending writes into our circular buffer */
 	/* unblock any pending writes into our circular buffer */
 	if (started) {
 	if (started) {
-		tty_wakeup(port->port_tty);
+		tty_wakeup(port->port.tty);
 	} else {
 	} else {
 		gs_free_requests(ep, head, &port->read_allocated);
 		gs_free_requests(ep, head, &port->read_allocated);
 		gs_free_requests(port->port_usb->in, &port->write_pool,
 		gs_free_requests(port->port_usb->in, &port->write_pool,
@@ -734,9 +731,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)
 			spin_lock_irq(&port->port_lock);
 			spin_lock_irq(&port->port_lock);
 
 
 			/* already open?  Great. */
 			/* already open?  Great. */
-			if (port->open_count) {
+			if (port->port.count) {
 				status = 0;
 				status = 0;
-				port->open_count++;
+				port->port.count++;
 
 
 			/* currently opening/closing? wait ... */
 			/* currently opening/closing? wait ... */
 			} else if (port->openclose) {
 			} else if (port->openclose) {
@@ -793,9 +790,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)
 	/* REVISIT maybe wait for "carrier detect" */
 	/* REVISIT maybe wait for "carrier detect" */
 
 
 	tty->driver_data = port;
 	tty->driver_data = port;
-	port->port_tty = tty;
+	port->port.tty = tty;
 
 
-	port->open_count = 1;
+	port->port.count = 1;
 	port->openclose = false;
 	port->openclose = false;
 
 
 	/* if connected, start the I/O stream */
 	/* if connected, start the I/O stream */
@@ -837,11 +834,11 @@ static void gs_close(struct tty_struct *tty, struct file *file)
 
 
 	spin_lock_irq(&port->port_lock);
 	spin_lock_irq(&port->port_lock);
 
 
-	if (port->open_count != 1) {
-		if (port->open_count == 0)
+	if (port->port.count != 1) {
+		if (port->port.count == 0)
 			WARN_ON(1);
 			WARN_ON(1);
 		else
 		else
-			--port->open_count;
+			--port->port.count;
 		goto exit;
 		goto exit;
 	}
 	}
 
 
@@ -851,7 +848,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
 	 * and sleep if necessary
 	 * and sleep if necessary
 	 */
 	 */
 	port->openclose = true;
 	port->openclose = true;
-	port->open_count = 0;
+	port->port.count = 0;
 
 
 	gser = port->port_usb;
 	gser = port->port_usb;
 	if (gser && gser->disconnect)
 	if (gser && gser->disconnect)
@@ -879,14 +876,14 @@ static void gs_close(struct tty_struct *tty, struct file *file)
 		gs_buf_clear(&port->port_write_buf);
 		gs_buf_clear(&port->port_write_buf);
 
 
 	tty->driver_data = NULL;
 	tty->driver_data = NULL;
-	port->port_tty = NULL;
+	port->port.tty = NULL;
 
 
 	port->openclose = false;
 	port->openclose = false;
 
 
 	pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
 	pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
 			port->port_num, tty, file);
 			port->port_num, tty, file);
 
 
-	wake_up_interruptible(&port->close_wait);
+	wake_up_interruptible(&port->port.close_wait);
 exit:
 exit:
 	spin_unlock_irq(&port->port_lock);
 	spin_unlock_irq(&port->port_lock);
 }
 }
@@ -1034,8 +1031,8 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
 	if (port == NULL)
 	if (port == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
+	tty_port_init(&port->port);
 	spin_lock_init(&port->port_lock);
 	spin_lock_init(&port->port_lock);
-	init_waitqueue_head(&port->close_wait);
 	init_waitqueue_head(&port->drain_wait);
 	init_waitqueue_head(&port->drain_wait);
 
 
 	tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
 	tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
@@ -1155,7 +1152,7 @@ static int gs_closed(struct gs_port *port)
 	int cond;
 	int cond;
 
 
 	spin_lock_irq(&port->port_lock);
 	spin_lock_irq(&port->port_lock);
-	cond = (port->open_count == 0) && !port->openclose;
+	cond = (port->port.count == 0) && !port->openclose;
 	spin_unlock_irq(&port->port_lock);
 	spin_unlock_irq(&port->port_lock);
 	return cond;
 	return cond;
 }
 }
@@ -1194,7 +1191,7 @@ void gserial_cleanup(void)
 		tasklet_kill(&port->push);
 		tasklet_kill(&port->push);
 
 
 		/* wait for old opens to finish */
 		/* wait for old opens to finish */
-		wait_event(port->close_wait, gs_closed(port));
+		wait_event(port->port.close_wait, gs_closed(port));
 
 
 		WARN_ON(port->port_usb != NULL);
 		WARN_ON(port->port_usb != NULL);
 
 
@@ -1268,7 +1265,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)
 	/* if it's already open, start I/O ... and notify the serial
 	/* if it's already open, start I/O ... and notify the serial
 	 * protocol about open/close status (connect/disconnect).
 	 * protocol about open/close status (connect/disconnect).
 	 */
 	 */
-	if (port->open_count) {
+	if (port->port.count) {
 		pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
 		pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
 		gs_start_io(port);
 		gs_start_io(port);
 		if (gser->connect)
 		if (gser->connect)
@@ -1315,10 +1312,10 @@ void gserial_disconnect(struct gserial *gser)
 
 
 	port->port_usb = NULL;
 	port->port_usb = NULL;
 	gser->ioport = NULL;
 	gser->ioport = NULL;
-	if (port->open_count > 0 || port->openclose) {
+	if (port->port.count > 0 || port->openclose) {
 		wake_up_interruptible(&port->drain_wait);
 		wake_up_interruptible(&port->drain_wait);
-		if (port->port_tty)
-			tty_hangup(port->port_tty);
+		if (port->port.tty)
+			tty_hangup(port->port.tty);
 	}
 	}
 	spin_unlock_irqrestore(&port->port_lock, flags);
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
 
@@ -1331,7 +1328,7 @@ void gserial_disconnect(struct gserial *gser)
 
 
 	/* finally, free any unused/unusable I/O buffers */
 	/* finally, free any unused/unusable I/O buffers */
 	spin_lock_irqsave(&port->port_lock, flags);
 	spin_lock_irqsave(&port->port_lock, flags);
-	if (port->open_count == 0 && !port->openclose)
+	if (port->port.count == 0 && !port->openclose)
 		gs_buf_free(&port->port_write_buf);
 		gs_buf_free(&port->port_write_buf);
 	gs_free_requests(gser->out, &port->read_pool, NULL);
 	gs_free_requests(gser->out, &port->read_pool, NULL);
 	gs_free_requests(gser->out, &port->read_queue, NULL);
 	gs_free_requests(gser->out, &port->read_queue, NULL);

+ 2 - 62
include/linux/generic_serial.h

@@ -4,7 +4,6 @@
  *  Copyright (C) 1998 R.E.Wolff@BitWizard.nl
  *  Copyright (C) 1998 R.E.Wolff@BitWizard.nl
  *
  *
  *  written for the SX serial driver.
  *  written for the SX serial driver.
- *     Contains the code that should be shared over all the serial drivers.
  *
  *
  *  Version 0.1 -- December, 1998.
  *  Version 0.1 -- December, 1998.
  */
  */
@@ -12,45 +11,8 @@
 #ifndef GENERIC_SERIAL_H
 #ifndef GENERIC_SERIAL_H
 #define GENERIC_SERIAL_H
 #define GENERIC_SERIAL_H
 
 
-#ifdef __KERNEL__
-#include <linux/mutex.h>
-#include <linux/tty.h>
-
-struct real_driver {
-  void                    (*disable_tx_interrupts) (void *);
-  void                    (*enable_tx_interrupts) (void *);
-  void                    (*disable_rx_interrupts) (void *);
-  void                    (*enable_rx_interrupts) (void *);
-  void                    (*shutdown_port) (void*);
-  int                     (*set_real_termios) (void*);
-  int                     (*chars_in_buffer) (void*);
-  void                    (*close) (void*);
-  void                    (*hungup) (void*);
-  void                    (*getserial) (void*, struct serial_struct *sp);
-};
-
-
-
-struct gs_port {
-  int                     magic;
-  struct tty_port	  port;
-  unsigned char           *xmit_buf; 
-  int                     xmit_head;
-  int                     xmit_tail;
-  int                     xmit_cnt;
-  struct mutex            port_write_mutex;
-  unsigned long           event;
-  unsigned short          closing_wait;
-  int                     close_delay;
-  struct real_driver      *rd;
-  int                     wakeup_chars;
-  int                     baud_base;
-  int                     baud;
-  int                     custom_divisor;
-  spinlock_t              driver_lock;
-};
-
-#endif /* __KERNEL__ */
+#warning Use of this header is deprecated.
+#warning Since nobody sets the constants defined here for you, you should not, in any case, use them. Including the header is thus pointless.
 
 
 /* Flags */
 /* Flags */
 /* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
 /* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
@@ -60,8 +22,6 @@ struct gs_port {
 #define GS_RX_INTEN      0x00400000
 #define GS_RX_INTEN      0x00400000
 #define GS_ACTIVE        0x00200000
 #define GS_ACTIVE        0x00200000
 
 
-
-
 #define GS_TYPE_NORMAL   1
 #define GS_TYPE_NORMAL   1
 
 
 #define GS_DEBUG_FLUSH   0x00000001
 #define GS_DEBUG_FLUSH   0x00000001
@@ -72,24 +32,4 @@ struct gs_port {
 #define GS_DEBUG_FLOW    0x00000020
 #define GS_DEBUG_FLOW    0x00000020
 #define GS_DEBUG_WRITE   0x00000040
 #define GS_DEBUG_WRITE   0x00000040
 
 
-#ifdef __KERNEL__
-int gs_put_char(struct tty_struct *tty, unsigned char ch);
-int  gs_write(struct tty_struct *tty, 
-             const unsigned char *buf, int count);
-int  gs_write_room(struct tty_struct *tty);
-int  gs_chars_in_buffer(struct tty_struct *tty);
-void gs_flush_buffer(struct tty_struct *tty);
-void gs_flush_chars(struct tty_struct *tty);
-void gs_stop(struct tty_struct *tty);
-void gs_start(struct tty_struct *tty);
-void gs_hangup(struct tty_struct *tty);
-int  gs_block_til_ready(void *port, struct file *filp);
-void gs_close(struct tty_struct *tty, struct file *filp);
-void gs_set_termios (struct tty_struct * tty, 
-                     struct ktermios * old_termios);
-int  gs_init_port(struct gs_port *port);
-int  gs_setserial(struct gs_port *port, struct serial_struct __user *sp);
-int  gs_getserial(struct gs_port *port, struct serial_struct __user *sp);
-void gs_got_break(struct gs_port *port);
-#endif /* __KERNEL__ */
 #endif
 #endif

+ 2 - 24
include/linux/isdn.h

@@ -15,6 +15,7 @@
 #define __ISDN_H__
 #define __ISDN_H__
 
 
 #include <linux/ioctl.h>
 #include <linux/ioctl.h>
+#include <linux/tty.h>
 
 
 #define ISDN_MAX_DRIVERS    32
 #define ISDN_MAX_DRIVERS    32
 #define ISDN_MAX_CHANNELS   64
 #define ISDN_MAX_CHANNELS   64
@@ -392,21 +393,8 @@ typedef struct isdn_net_dev_s {
 /*======================= Start of ISDN-tty stuff ===========================*/
 /*======================= Start of ISDN-tty stuff ===========================*/
 
 
 #define ISDN_ASYNC_MAGIC          0x49344C01 /* for paranoia-checking        */
 #define ISDN_ASYNC_MAGIC          0x49344C01 /* for paranoia-checking        */
-#define ISDN_ASYNC_INITIALIZED	  0x80000000 /* port was initialized         */
-#define ISDN_ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device active       */
-#define ISDN_ASYNC_NORMAL_ACTIVE  0x20000000 /* Normal device active         */
-#define ISDN_ASYNC_CLOSING	  0x08000000 /* Serial port is closing       */
-#define ISDN_ASYNC_CTS_FLOW	  0x04000000 /* Do CTS flow control          */
-#define ISDN_ASYNC_CHECK_CD	  0x02000000 /* i.e., CLOCAL                 */
-#define ISDN_ASYNC_HUP_NOTIFY         0x0001 /* Notify tty on hangups/closes */
-#define ISDN_ASYNC_SESSION_LOCKOUT    0x0100 /* Lock cua opens on session    */
-#define ISDN_ASYNC_PGRP_LOCKOUT       0x0200 /* Lock cua opens on pgrp       */
-#define ISDN_ASYNC_CALLOUT_NOHUP      0x0400 /* No hangup for cui            */
-#define ISDN_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
 #define ISDN_SERIAL_XMIT_SIZE           1024 /* Default bufsize for write    */
 #define ISDN_SERIAL_XMIT_SIZE           1024 /* Default bufsize for write    */
 #define ISDN_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
 #define ISDN_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
-#define ISDN_SERIAL_TYPE_NORMAL            1
-#define ISDN_SERIAL_TYPE_CALLOUT           2
 
 
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
 /* For using sk_buffs with audio we need some private variables
 /* For using sk_buffs with audio we need some private variables
@@ -448,17 +436,12 @@ typedef struct atemu {
 /* Private data (similar to async_struct in <linux/serial.h>) */
 /* Private data (similar to async_struct in <linux/serial.h>) */
 typedef struct modem_info {
 typedef struct modem_info {
   int			magic;
   int			magic;
-  struct module		*owner;
-  int			flags;		 /* defined in tty.h               */
+  struct tty_port	port;
   int			x_char;		 /* xon/xoff character             */
   int			x_char;		 /* xon/xoff character             */
   int			mcr;		 /* Modem control register         */
   int			mcr;		 /* Modem control register         */
   int                   msr;             /* Modem status register          */
   int                   msr;             /* Modem status register          */
   int                   lsr;             /* Line status register           */
   int                   lsr;             /* Line status register           */
   int			line;
   int			line;
-  int			count;		 /* # of fd on device              */
-  int			blocked_open;	 /* # of blocked opens             */
-  long			session;	 /* Session of opening process     */
-  long			pgrp;		 /* pgrp of opening process        */
   int                   online;          /* 1 = B-Channel is up, drop data */
   int                   online;          /* 1 = B-Channel is up, drop data */
 					 /* 2 = B-Channel is up, deliver d.*/
 					 /* 2 = B-Channel is up, deliver d.*/
   int                   dialing;         /* Dial in progress or ATA        */
   int                   dialing;         /* Dial in progress or ATA        */
@@ -478,7 +461,6 @@ typedef struct modem_info {
   int                   send_outstanding;/* # of outstanding send-requests */
   int                   send_outstanding;/* # of outstanding send-requests */
   int                   xmit_size;       /* max. # of chars in xmit_buf    */
   int                   xmit_size;       /* max. # of chars in xmit_buf    */
   int                   xmit_count;      /* # of chars in xmit_buf         */
   int                   xmit_count;      /* # of chars in xmit_buf         */
-  unsigned char         *xmit_buf;       /* transmit buffer                */
   struct sk_buff_head   xmit_queue;      /* transmit queue                 */
   struct sk_buff_head   xmit_queue;      /* transmit queue                 */
   atomic_t              xmit_lock;       /* Semaphore for isdn_tty_write   */
   atomic_t              xmit_lock;       /* Semaphore for isdn_tty_write   */
 #ifdef CONFIG_ISDN_AUDIO
 #ifdef CONFIG_ISDN_AUDIO
@@ -496,11 +478,7 @@ typedef struct modem_info {
   struct T30_s		*fax;		 /* T30 Fax Group 3 data/interface */
   struct T30_s		*fax;		 /* T30 Fax Group 3 data/interface */
   int			faxonline;	 /* Fax-channel status             */
   int			faxonline;	 /* Fax-channel status             */
 #endif
 #endif
-  struct tty_struct 	*tty;            /* Pointer to corresponding tty   */
   atemu                 emu;             /* AT-emulator data               */
   atemu                 emu;             /* AT-emulator data               */
-  struct ktermios	normal_termios;  /* For saving termios structs     */
-  struct ktermios	callout_termios;
-  wait_queue_head_t	open_wait, close_wait;
   spinlock_t	        readlock;
   spinlock_t	        readlock;
 } modem_info;
 } modem_info;
 
 

+ 17 - 0
include/linux/of_serial.h

@@ -0,0 +1,17 @@
+#ifndef __LINUX_OF_SERIAL_H
+#define __LINUX_OF_SERIAL_H
+
+/*
+ * FIXME remove this file when tegra finishes conversion to open firmware,
+ * expectation is that all quirks will then be self-contained in
+ * drivers/tty/serial/of_serial.c.
+ */
+#ifdef CONFIG_ARCH_TEGRA
+extern void tegra_serial_handle_break(struct uart_port *port);
+#else
+static inline void tegra_serial_handle_break(struct uart_port *port)
+{
+}
+#endif
+
+#endif /* __LINUX_OF_SERIAL */

+ 2 - 0
include/linux/serial_8250.h

@@ -38,6 +38,7 @@ struct plat_serial8250_port {
 	int		(*handle_irq)(struct uart_port *);
 	int		(*handle_irq)(struct uart_port *);
 	void		(*pm)(struct uart_port *, unsigned int state,
 	void		(*pm)(struct uart_port *, unsigned int state,
 			      unsigned old);
 			      unsigned old);
+	void		(*handle_break)(struct uart_port *);
 };
 };
 
 
 /*
 /*
@@ -68,6 +69,7 @@ enum {
 struct uart_port;
 struct uart_port;
 struct uart_8250_port;
 struct uart_8250_port;
 
 
+int serial8250_register_8250_port(struct uart_8250_port *);
 int serial8250_register_port(struct uart_port *);
 int serial8250_register_port(struct uart_port *);
 void serial8250_unregister_port(int line);
 void serial8250_unregister_port(int line);
 void serial8250_suspend_port(int line);
 void serial8250_suspend_port(int line);

+ 5 - 0
include/linux/serial_core.h

@@ -310,6 +310,7 @@ struct uart_port {
 	int			(*handle_irq)(struct uart_port *);
 	int			(*handle_irq)(struct uart_port *);
 	void			(*pm)(struct uart_port *, unsigned int state,
 	void			(*pm)(struct uart_port *, unsigned int state,
 				      unsigned int old);
 				      unsigned int old);
+	void			(*handle_break)(struct uart_port *);
 	unsigned int		irq;			/* irq number */
 	unsigned int		irq;			/* irq number */
 	unsigned long		irqflags;		/* irq flags  */
 	unsigned long		irqflags;		/* irq flags  */
 	unsigned int		uartclk;		/* base uart clock */
 	unsigned int		uartclk;		/* base uart clock */
@@ -533,6 +534,10 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
 static inline int uart_handle_break(struct uart_port *port)
 static inline int uart_handle_break(struct uart_port *port)
 {
 {
 	struct uart_state *state = port->state;
 	struct uart_state *state = port->state;
+
+	if (port->handle_break)
+		port->handle_break(port);
+
 #ifdef SUPPORT_SYSRQ
 #ifdef SUPPORT_SYSRQ
 	if (port->cons && port->cons->index == port->line) {
 	if (port->cons && port->cons->index == port->line) {
 		if (!port->sysrq) {
 		if (!port->sysrq) {

+ 14 - 9
include/linux/tty.h

@@ -268,6 +268,7 @@ struct tty_struct {
 	struct mutex ldisc_mutex;
 	struct mutex ldisc_mutex;
 	struct tty_ldisc *ldisc;
 	struct tty_ldisc *ldisc;
 
 
+	struct mutex legacy_mutex;
 	struct mutex termios_mutex;
 	struct mutex termios_mutex;
 	spinlock_t ctrl_lock;
 	spinlock_t ctrl_lock;
 	/* Termios values are protected by the termios mutex */
 	/* Termios values are protected by the termios mutex */
@@ -605,8 +606,12 @@ extern long vt_compat_ioctl(struct tty_struct *tty,
 
 
 /* tty_mutex.c */
 /* tty_mutex.c */
 /* functions for preparation of BKL removal */
 /* functions for preparation of BKL removal */
-extern void __lockfunc tty_lock(void) __acquires(tty_lock);
-extern void __lockfunc tty_unlock(void) __releases(tty_lock);
+extern void __lockfunc tty_lock(struct tty_struct *tty);
+extern void __lockfunc tty_unlock(struct tty_struct *tty);
+extern void __lockfunc tty_lock_pair(struct tty_struct *tty,
+				struct tty_struct *tty2);
+extern void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+				struct tty_struct *tty2);
 
 
 /*
 /*
  * this shall be called only from where BTM is held (like close)
  * this shall be called only from where BTM is held (like close)
@@ -621,9 +626,9 @@ extern void __lockfunc tty_unlock(void) __releases(tty_lock);
 static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
 static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
 		long timeout)
 		long timeout)
 {
 {
-	tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */
+	tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
 	tty_wait_until_sent(tty, timeout);
 	tty_wait_until_sent(tty, timeout);
-	tty_lock();
+	tty_lock(tty);
 }
 }
 
 
 /*
 /*
@@ -638,16 +643,16 @@ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
  *
  *
  * Do not use in new code.
  * Do not use in new code.
  */
  */
-#define wait_event_interruptible_tty(wq, condition)			\
+#define wait_event_interruptible_tty(tty, wq, condition)		\
 ({									\
 ({									\
 	int __ret = 0;							\
 	int __ret = 0;							\
 	if (!(condition)) {						\
 	if (!(condition)) {						\
-		__wait_event_interruptible_tty(wq, condition, __ret);	\
+		__wait_event_interruptible_tty(tty, wq, condition, __ret);	\
 	}								\
 	}								\
 	__ret;								\
 	__ret;								\
 })
 })
 
 
-#define __wait_event_interruptible_tty(wq, condition, ret)		\
+#define __wait_event_interruptible_tty(tty, wq, condition, ret)		\
 do {									\
 do {									\
 	DEFINE_WAIT(__wait);						\
 	DEFINE_WAIT(__wait);						\
 									\
 									\
@@ -656,9 +661,9 @@ do {									\
 		if (condition)						\
 		if (condition)						\
 			break;						\
 			break;						\
 		if (!signal_pending(current)) {				\
 		if (!signal_pending(current)) {				\
-			tty_unlock();					\
+			tty_unlock(tty);					\
 			schedule();					\
 			schedule();					\
-			tty_lock();					\
+			tty_lock(tty);					\
 			continue;					\
 			continue;					\
 		}							\
 		}							\
 		ret = -ERESTARTSYS;					\
 		ret = -ERESTARTSYS;					\

+ 2 - 0
include/linux/tty_ldisc.h

@@ -110,6 +110,7 @@
 #include <linux/fs.h>
 #include <linux/fs.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
 #include <linux/pps_kernel.h>
 #include <linux/pps_kernel.h>
+#include <linux/wait.h>
 
 
 struct tty_ldisc_ops {
 struct tty_ldisc_ops {
 	int	magic;
 	int	magic;
@@ -154,6 +155,7 @@ struct tty_ldisc_ops {
 struct tty_ldisc {
 struct tty_ldisc {
 	struct tty_ldisc_ops *ops;
 	struct tty_ldisc_ops *ops;
 	atomic_t users;
 	atomic_t users;
+	wait_queue_head_t wq_idle;
 };
 };
 
 
 #define TTY_LDISC_MAGIC	0x5403
 #define TTY_LDISC_MAGIC	0x5403

+ 0 - 1
include/linux/vt_kern.h

@@ -70,7 +70,6 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list);
 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list);
 int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list);
 int con_set_default_unimap(struct vc_data *vc);
 int con_set_default_unimap(struct vc_data *vc);
 void con_free_unimap(struct vc_data *vc);
 void con_free_unimap(struct vc_data *vc);
-void con_protect_unimap(struct vc_data *vc, int rdonly);
 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
 int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
 
 
 #define vc_translate(vc, c) ((vc)->vc_translate[(c) |			\
 #define vc_translate(vc, c) ((vc)->vc_translate[(c) |			\

+ 64 - 73
net/bluetooth/rfcomm/tty.c

@@ -48,13 +48,12 @@
 static struct tty_driver *rfcomm_tty_driver;
 static struct tty_driver *rfcomm_tty_driver;
 
 
 struct rfcomm_dev {
 struct rfcomm_dev {
+	struct tty_port		port;
 	struct list_head	list;
 	struct list_head	list;
-	atomic_t		refcnt;
 
 
 	char			name[12];
 	char			name[12];
 	int			id;
 	int			id;
 	unsigned long		flags;
 	unsigned long		flags;
-	atomic_t		opened;
 	int			err;
 	int			err;
 
 
 	bdaddr_t		src;
 	bdaddr_t		src;
@@ -64,9 +63,7 @@ struct rfcomm_dev {
 	uint			modem_status;
 	uint			modem_status;
 
 
 	struct rfcomm_dlc	*dlc;
 	struct rfcomm_dlc	*dlc;
-	struct tty_struct	*tty;
 	wait_queue_head_t       wait;
 	wait_queue_head_t       wait;
-	struct work_struct	wakeup_task;
 
 
 	struct device		*tty_dev;
 	struct device		*tty_dev;
 
 
@@ -82,11 +79,18 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
 static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
 static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
 
 
-static void rfcomm_tty_wakeup(struct work_struct *work);
-
 /* ---- Device functions ---- */
 /* ---- Device functions ---- */
-static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
+
+/*
+ * The reason this isn't actually a race, as you no doubt have a little voice
+ * screaming at you in your head, is that the refcount should never actually
+ * reach zero unless the device has already been taken off the list, in
+ * rfcomm_dev_del(). And if that's not true, we'll hit the BUG() in
+ * rfcomm_dev_destruct() anyway.
+ */
+static void rfcomm_dev_destruct(struct tty_port *port)
 {
 {
+	struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
 	struct rfcomm_dlc *dlc = dev->dlc;
 	struct rfcomm_dlc *dlc = dev->dlc;
 
 
 	BT_DBG("dev %p dlc %p", dev, dlc);
 	BT_DBG("dev %p dlc %p", dev, dlc);
@@ -113,23 +117,9 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
 	module_put(THIS_MODULE);
 	module_put(THIS_MODULE);
 }
 }
 
 
-static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
-{
-	atomic_inc(&dev->refcnt);
-}
-
-static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
-{
-	/* The reason this isn't actually a race, as you no
-	   doubt have a little voice screaming at you in your
-	   head, is that the refcount should never actually
-	   reach zero unless the device has already been taken
-	   off the list, in rfcomm_dev_del(). And if that's not
-	   true, we'll hit the BUG() in rfcomm_dev_destruct()
-	   anyway. */
-	if (atomic_dec_and_test(&dev->refcnt))
-		rfcomm_dev_destruct(dev);
-}
+static const struct tty_port_operations rfcomm_port_ops = {
+	.destruct = rfcomm_dev_destruct,
+};
 
 
 static struct rfcomm_dev *__rfcomm_dev_get(int id)
 static struct rfcomm_dev *__rfcomm_dev_get(int id)
 {
 {
@@ -154,7 +144,7 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
 		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
 		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
 			dev = NULL;
 			dev = NULL;
 		else
 		else
-			rfcomm_dev_hold(dev);
+			tty_port_get(&dev->port);
 	}
 	}
 
 
 	spin_unlock(&rfcomm_dev_lock);
 	spin_unlock(&rfcomm_dev_lock);
@@ -241,7 +231,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 	sprintf(dev->name, "rfcomm%d", dev->id);
 	sprintf(dev->name, "rfcomm%d", dev->id);
 
 
 	list_add(&dev->list, head);
 	list_add(&dev->list, head);
-	atomic_set(&dev->refcnt, 1);
 
 
 	bacpy(&dev->src, &req->src);
 	bacpy(&dev->src, &req->src);
 	bacpy(&dev->dst, &req->dst);
 	bacpy(&dev->dst, &req->dst);
@@ -250,10 +239,9 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 	dev->flags = req->flags &
 	dev->flags = req->flags &
 		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
 		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
 
 
-	atomic_set(&dev->opened, 0);
-
+	tty_port_init(&dev->port);
+	dev->port.ops = &rfcomm_port_ops;
 	init_waitqueue_head(&dev->wait);
 	init_waitqueue_head(&dev->wait);
-	INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
 
 
 	skb_queue_head_init(&dev->pending);
 	skb_queue_head_init(&dev->pending);
 
 
@@ -320,18 +308,23 @@ free:
 
 
 static void rfcomm_dev_del(struct rfcomm_dev *dev)
 static void rfcomm_dev_del(struct rfcomm_dev *dev)
 {
 {
+	unsigned long flags;
 	BT_DBG("dev %p", dev);
 	BT_DBG("dev %p", dev);
 
 
 	BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
 	BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
 
 
-	if (atomic_read(&dev->opened) > 0)
+	spin_lock_irqsave(&dev->port.lock, flags);
+	if (dev->port.count > 0) {
+		spin_unlock_irqrestore(&dev->port.lock, flags);
 		return;
 		return;
+	}
+	spin_unlock_irqrestore(&dev->port.lock, flags);
 
 
 	spin_lock(&rfcomm_dev_lock);
 	spin_lock(&rfcomm_dev_lock);
 	list_del_init(&dev->list);
 	list_del_init(&dev->list);
 	spin_unlock(&rfcomm_dev_lock);
 	spin_unlock(&rfcomm_dev_lock);
 
 
-	rfcomm_dev_put(dev);
+	tty_port_put(&dev->port);
 }
 }
 
 
 /* ---- Send buffer ---- */
 /* ---- Send buffer ---- */
@@ -345,15 +338,16 @@ static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
 static void rfcomm_wfree(struct sk_buff *skb)
 static void rfcomm_wfree(struct sk_buff *skb)
 {
 {
 	struct rfcomm_dev *dev = (void *) skb->sk;
 	struct rfcomm_dev *dev = (void *) skb->sk;
+	struct tty_struct *tty = dev->port.tty;
 	atomic_sub(skb->truesize, &dev->wmem_alloc);
 	atomic_sub(skb->truesize, &dev->wmem_alloc);
-	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
-		queue_work(system_nrt_wq, &dev->wakeup_task);
-	rfcomm_dev_put(dev);
+	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags) && tty)
+		tty_wakeup(tty);
+	tty_port_put(&dev->port);
 }
 }
 
 
 static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
 static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
 {
 {
-	rfcomm_dev_hold(dev);
+	tty_port_get(&dev->port);
 	atomic_add(skb->truesize, &dev->wmem_alloc);
 	atomic_add(skb->truesize, &dev->wmem_alloc);
 	skb->sk = (void *) dev;
 	skb->sk = (void *) dev;
 	skb->destructor = rfcomm_wfree;
 	skb->destructor = rfcomm_wfree;
@@ -432,7 +426,7 @@ static int rfcomm_release_dev(void __user *arg)
 		return -ENODEV;
 		return -ENODEV;
 
 
 	if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
 	if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
-		rfcomm_dev_put(dev);
+		tty_port_put(&dev->port);
 		return -EPERM;
 		return -EPERM;
 	}
 	}
 
 
@@ -440,12 +434,12 @@ static int rfcomm_release_dev(void __user *arg)
 		rfcomm_dlc_close(dev->dlc, 0);
 		rfcomm_dlc_close(dev->dlc, 0);
 
 
 	/* Shut down TTY synchronously before freeing rfcomm_dev */
 	/* Shut down TTY synchronously before freeing rfcomm_dev */
-	if (dev->tty)
-		tty_vhangup(dev->tty);
+	if (dev->port.tty)
+		tty_vhangup(dev->port.tty);
 
 
 	if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
 	if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
 		rfcomm_dev_del(dev);
 		rfcomm_dev_del(dev);
-	rfcomm_dev_put(dev);
+	tty_port_put(&dev->port);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -523,7 +517,7 @@ static int rfcomm_get_dev_info(void __user *arg)
 	if (copy_to_user(arg, &di, sizeof(di)))
 	if (copy_to_user(arg, &di, sizeof(di)))
 		err = -EFAULT;
 		err = -EFAULT;
 
 
-	rfcomm_dev_put(dev);
+	tty_port_put(&dev->port);
 	return err;
 	return err;
 }
 }
 
 
@@ -559,7 +553,7 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
 		return;
 		return;
 	}
 	}
 
 
-	tty = dev->tty;
+	tty = dev->port.tty;
 	if (!tty || !skb_queue_empty(&dev->pending)) {
 	if (!tty || !skb_queue_empty(&dev->pending)) {
 		skb_queue_tail(&dev->pending, skb);
 		skb_queue_tail(&dev->pending, skb);
 		return;
 		return;
@@ -585,13 +579,13 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
 	wake_up_interruptible(&dev->wait);
 	wake_up_interruptible(&dev->wait);
 
 
 	if (dlc->state == BT_CLOSED) {
 	if (dlc->state == BT_CLOSED) {
-		if (!dev->tty) {
+		if (!dev->port.tty) {
 			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
 			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
 				/* Drop DLC lock here to avoid deadlock
 				/* Drop DLC lock here to avoid deadlock
 				 * 1. rfcomm_dev_get will take rfcomm_dev_lock
 				 * 1. rfcomm_dev_get will take rfcomm_dev_lock
 				 *    but in rfcomm_dev_add there's lock order:
 				 *    but in rfcomm_dev_add there's lock order:
 				 *    rfcomm_dev_lock -> dlc lock
 				 *    rfcomm_dev_lock -> dlc lock
-				 * 2. rfcomm_dev_put will deadlock if it's
+				 * 2. tty_port_put will deadlock if it's
 				 *    the last reference
 				 *    the last reference
 				 */
 				 */
 				rfcomm_dlc_unlock(dlc);
 				rfcomm_dlc_unlock(dlc);
@@ -601,11 +595,11 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
 				}
 				}
 
 
 				rfcomm_dev_del(dev);
 				rfcomm_dev_del(dev);
-				rfcomm_dev_put(dev);
+				tty_port_put(&dev->port);
 				rfcomm_dlc_lock(dlc);
 				rfcomm_dlc_lock(dlc);
 			}
 			}
 		} else
 		} else
-			tty_hangup(dev->tty);
+			tty_hangup(dev->port.tty);
 	}
 	}
 }
 }
 
 
@@ -618,8 +612,8 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
 	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
 	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
 
 
 	if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {
 	if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {
-		if (dev->tty && !C_CLOCAL(dev->tty))
-			tty_hangup(dev->tty);
+		if (dev->port.tty && !C_CLOCAL(dev->port.tty))
+			tty_hangup(dev->port.tty);
 	}
 	}
 
 
 	dev->modem_status =
 	dev->modem_status =
@@ -630,21 +624,9 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
 }
 }
 
 
 /* ---- TTY functions ---- */
 /* ---- TTY functions ---- */
-static void rfcomm_tty_wakeup(struct work_struct *work)
-{
-	struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
-								wakeup_task);
-	struct tty_struct *tty = dev->tty;
-	if (!tty)
-		return;
-
-	BT_DBG("dev %p tty %p", dev, tty);
-	tty_wakeup(tty);
-}
-
 static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
 static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
 {
 {
-	struct tty_struct *tty = dev->tty;
+	struct tty_struct *tty = dev->port.tty;
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	int inserted = 0;
 	int inserted = 0;
 
 
@@ -671,6 +653,7 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
 	DECLARE_WAITQUEUE(wait, current);
 	DECLARE_WAITQUEUE(wait, current);
 	struct rfcomm_dev *dev;
 	struct rfcomm_dev *dev;
 	struct rfcomm_dlc *dlc;
 	struct rfcomm_dlc *dlc;
+	unsigned long flags;
 	int err, id;
 	int err, id;
 
 
 	id = tty->index;
 	id = tty->index;
@@ -686,10 +669,14 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
 		return -ENODEV;
 		return -ENODEV;
 
 
 	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
 	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
-				dev->channel, atomic_read(&dev->opened));
+				dev->channel, dev->port.count);
 
 
-	if (atomic_inc_return(&dev->opened) > 1)
+	spin_lock_irqsave(&dev->port.lock, flags);
+	if (++dev->port.count > 1) {
+		spin_unlock_irqrestore(&dev->port.lock, flags);
 		return 0;
 		return 0;
+	}
+	spin_unlock_irqrestore(&dev->port.lock, flags);
 
 
 	dlc = dev->dlc;
 	dlc = dev->dlc;
 
 
@@ -697,7 +684,7 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
 
 
 	rfcomm_dlc_lock(dlc);
 	rfcomm_dlc_lock(dlc);
 	tty->driver_data = dev;
 	tty->driver_data = dev;
-	dev->tty = tty;
+	dev->port.tty = tty;
 	rfcomm_dlc_unlock(dlc);
 	rfcomm_dlc_unlock(dlc);
 	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
 	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
 
 
@@ -723,9 +710,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
 			break;
 			break;
 		}
 		}
 
 
-		tty_unlock();
+		tty_unlock(tty);
 		schedule();
 		schedule();
-		tty_lock();
+		tty_lock(tty);
 	}
 	}
 	set_current_state(TASK_RUNNING);
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dev->wait, &wait);
 	remove_wait_queue(&dev->wait, &wait);
@@ -744,13 +731,17 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
 static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
 static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
 {
 {
 	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
 	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	unsigned long flags;
+
 	if (!dev)
 	if (!dev)
 		return;
 		return;
 
 
 	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
 	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
-						atomic_read(&dev->opened));
+						dev->port.count);
 
 
-	if (atomic_dec_and_test(&dev->opened)) {
+	spin_lock_irqsave(&dev->port.lock, flags);
+	if (!--dev->port.count) {
+		spin_unlock_irqrestore(&dev->port.lock, flags);
 		if (dev->tty_dev->parent)
 		if (dev->tty_dev->parent)
 			device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
 			device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
 
 
@@ -758,11 +749,10 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
 		rfcomm_dlc_close(dev->dlc, 0);
 		rfcomm_dlc_close(dev->dlc, 0);
 
 
 		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
 		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-		cancel_work_sync(&dev->wakeup_task);
 
 
 		rfcomm_dlc_lock(dev->dlc);
 		rfcomm_dlc_lock(dev->dlc);
 		tty->driver_data = NULL;
 		tty->driver_data = NULL;
-		dev->tty = NULL;
+		dev->port.tty = NULL;
 		rfcomm_dlc_unlock(dev->dlc);
 		rfcomm_dlc_unlock(dev->dlc);
 
 
 		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
 		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
@@ -770,11 +760,12 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
 			list_del_init(&dev->list);
 			list_del_init(&dev->list);
 			spin_unlock(&rfcomm_dev_lock);
 			spin_unlock(&rfcomm_dev_lock);
 
 
-			rfcomm_dev_put(dev);
+			tty_port_put(&dev->port);
 		}
 		}
-	}
+	} else
+		spin_unlock_irqrestore(&dev->port.lock, flags);
 
 
-	rfcomm_dev_put(dev);
+	tty_port_put(&dev->port);
 }
 }
 
 
 static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
 static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1083,7 +1074,7 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
 		if (rfcomm_dev_get(dev->id) == NULL)
 		if (rfcomm_dev_get(dev->id) == NULL)
 			return;
 			return;
 		rfcomm_dev_del(dev);
 		rfcomm_dev_del(dev);
-		rfcomm_dev_put(dev);
+		tty_port_put(&dev->port);
 	}
 	}
 }
 }