소스 검색

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

Pull TTY/serial patches from Greg KH:
 "tty and serial merge for 3.4-rc1

  Here's the big serial and tty merge for the 3.4-rc1 tree.

  There's loads of fixes and reworks in here from Jiri for the tty
  layer, and a number of patches from Alan to help try to wrestle the vt
  layer into a sane model.

  Other than that, lots of driver updates and fixes, and other minor
  stuff, all detailed in the shortlog."

* tag 'tty-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (132 commits)
  serial: pxa: add clk_prepare/clk_unprepare calls
  TTY: Wrong unicode value copied in con_set_unimap()
  serial: PL011: clear pending interrupts
  serial: bfin-uart: Don't access tty circular buffer in TX DMA interrupt after it is reset.
  vt: NULL dereference in vt_do_kdsk_ioctl()
  tty: serial: vt8500: fix annotations for probe/remove
  serial: remove back and forth conversions in serial_out_sync
  serial: use serial_port_in/out vs serial_in/out in 8250
  serial: introduce generic port in/out helpers
  serial: reduce number of indirections in 8250 code
  serial: delete useless void casts in 8250.c
  serial: make 8250's serial_in shareable to other drivers.
  serial: delete last unused traces of pausing I/O in 8250
  pch_uart: Add module parameter descriptions
  pch_uart: Use existing default_baud in setup_console
  pch_uart: Add user_uartclk parameter
  pch_uart: Add Fish River Island II uart clock quirks
  pch_uart: Use uartclk instead of base_baud
  mpc5200b/uart: select more tolerant uart prescaler on low baudrates
  tty: moxa: fix bit test in moxa_start()
  ...
Linus Torvalds 13 년 전
부모
커밋
843ec558f9
100개의 변경된 파일2832개의 추가작업 그리고 2550개의 파일을 삭제
  1. 14 0
      Documentation/devicetree/bindings/tty/serial/efm32-uart.txt
  2. 1 1
      MAINTAINERS
  3. 23 55
      arch/alpha/kernel/srmcons.c
  4. 4 13
      arch/ia64/hp/sim/boot/fw-emu.c
  5. 30 6
      arch/ia64/hp/sim/hpsim_irq.c
  6. 0 6
      arch/ia64/hp/sim/hpsim_setup.c
  7. 3 16
      arch/ia64/hp/sim/simeth.c
  8. 147 558
      arch/ia64/hp/sim/simserial.c
  9. 1 1
      arch/ia64/include/asm/hpsim.h
  10. 0 1
      arch/m68k/emu/nfcon.c
  11. 29 30
      arch/parisc/kernel/pdc_cons.c
  12. 8 14
      arch/xtensa/platforms/iss/console.c
  13. 3 6
      drivers/accessibility/braille/braille_console.c
  14. 0 15
      drivers/char/Kconfig
  15. 0 1
      drivers/char/Makefile
  16. 0 266
      drivers/char/briq_panel.c
  17. 1 2
      drivers/char/pcmcia/synclink_cs.c
  18. 0 2
      drivers/char/ttyprintk.c
  19. 4 9
      drivers/isdn/capi/capi.c
  20. 1 4
      drivers/isdn/gigaset/common.c
  21. 1 2
      drivers/isdn/gigaset/gigaset.h
  22. 34 124
      drivers/isdn/gigaset/interface.c
  23. 2 5
      drivers/isdn/i4l/isdn_tty.c
  24. 2 10
      drivers/misc/pti.c
  25. 3 7
      drivers/mmc/card/sdio_uart.c
  26. 0 2
      drivers/net/usb/hso.c
  27. 2 11
      drivers/net/wan/pc300_drv.c
  28. 0 18
      drivers/net/wan/pc300_tty.c
  29. 2 7
      drivers/s390/char/con3215.c
  30. 0 1
      drivers/s390/char/sclp_tty.c
  31. 0 1
      drivers/s390/char/sclp_vt220.c
  32. 0 1
      drivers/s390/char/tty3270.c
  33. 4 4
      drivers/staging/speakup/main.c
  34. 5 6
      drivers/staging/speakup/serialio.c
  35. 12 1
      drivers/staging/speakup/serialio.h
  36. 1 1
      drivers/staging/speakup/spk_priv.h
  37. 1 1
      drivers/staging/speakup/synth.c
  38. 167 262
      drivers/tty/amiserial.c
  39. 0 1
      drivers/tty/bfin_jtag_comm.c
  40. 2 7
      drivers/tty/cyclades.c
  41. 0 1
      drivers/tty/ehv_bytechan.c
  42. 1 1
      drivers/tty/hvc/hvc_beat.c
  43. 0 1
      drivers/tty/hvc/hvc_console.c
  44. 1 1
      drivers/tty/hvc/hvc_rtas.c
  45. 1 1
      drivers/tty/hvc/hvc_udbg.c
  46. 1 1
      drivers/tty/hvc/hvc_xen.c
  47. 12 18
      drivers/tty/hvc/hvcs.c
  48. 2 6
      drivers/tty/hvc/hvsi.c
  49. 13 24
      drivers/tty/ipwireless/tty.c
  50. 0 3
      drivers/tty/isicom.c
  51. 1 2
      drivers/tty/moxa.c
  52. 0 5
      drivers/tty/mxser.c
  53. 0 1
      drivers/tty/n_gsm.c
  54. 2 7
      drivers/tty/nozomi.c
  55. 3 60
      drivers/tty/pty.c
  56. 3 4
      drivers/tty/rocket.c
  57. 2 2
      drivers/tty/serial/21285.c
  58. 2 7
      drivers/tty/serial/68328serial.c
  59. 206 228
      drivers/tty/serial/8250/8250.c
  60. 10 0
      drivers/tty/serial/8250/8250.h
  61. 13 0
      drivers/tty/serial/Kconfig
  62. 2 1
      drivers/tty/serial/Makefile
  63. 24 23
      drivers/tty/serial/altera_uart.c
  64. 27 5
      drivers/tty/serial/amba-pl011.c
  65. 5 3
      drivers/tty/serial/bfin_uart.c
  66. 3 12
      drivers/tty/serial/crisv10.c
  67. 830 0
      drivers/tty/serial/efm32-uart.c
  68. 0 3
      drivers/tty/serial/ifx6x60.c
  69. 1 2
      drivers/tty/serial/ioc4_serial.c
  70. 2 10
      drivers/tty/serial/m32r_sio.c
  71. 1 0
      drivers/tty/serial/m32r_sio.h
  72. 5 4
      drivers/tty/serial/mpc52xx_uart.c
  73. 0 1
      drivers/tty/serial/msm_smd_tty.c
  74. 1 2
      drivers/tty/serial/mux.c
  75. 3 3
      drivers/tty/serial/omap-serial.c
  76. 128 44
      drivers/tty/serial/pch_uart.c
  77. 1 1
      drivers/tty/serial/pmac_zilog.c
  78. 4 4
      drivers/tty/serial/pxa.c
  79. 1 1
      drivers/tty/serial/samsung.c
  80. 0 1
      drivers/tty/serial/serial_core.c
  81. 2 2
      drivers/tty/serial/sn_console.c
  82. 1 1
      drivers/tty/serial/suncore.c
  83. 1 2
      drivers/tty/serial/sunhv.c
  84. 1 1
      drivers/tty/serial/sunsab.c
  85. 1 2
      drivers/tty/serial/sunsu.c
  86. 6 6
      drivers/tty/serial/sunzilog.c
  87. 1 1
      drivers/tty/serial/ucc_uart.c
  88. 2 2
      drivers/tty/serial/vr41xx_siu.c
  89. 2 2
      drivers/tty/serial/vt8500_serial.c
  90. 1 2
      drivers/tty/synclink.c
  91. 1 2
      drivers/tty/synclink_gt.c
  92. 1 2
      drivers/tty/synclinkmp.c
  93. 10 7
      drivers/tty/sysrq.c
  94. 21 33
      drivers/tty/tty_io.c
  95. 43 8
      drivers/tty/vt/consolemap.c
  96. 768 35
      drivers/tty/vt/keyboard.c
  97. 43 15
      drivers/tty/vt/selection.c
  98. 2 2
      drivers/tty/vt/vc_screen.c
  99. 36 30
      drivers/tty/vt/vt.c
  100. 71 424
      drivers/tty/vt/vt_ioctl.c

+ 14 - 0
Documentation/devicetree/bindings/tty/serial/efm32-uart.txt

@@ -0,0 +1,14 @@
+* Energymicro efm32 UART
+
+Required properties:
+- compatible : Should be "efm32,uart"
+- reg : Address and length of the register set
+- interrupts : Should contain uart interrupt
+
+Example:
+
+uart@0x4000c400 {
+	compatible = "efm32,uart";
+	reg = <0x4000c400 0x400>;
+	interrupts = <15>;
+};

+ 1 - 1
MAINTAINERS

@@ -6212,8 +6212,8 @@ L:	sparclinux@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
 S:	Maintained
+F:	include/linux/sunserialcore.h
 F:	drivers/tty/serial/suncore.c
-F:	drivers/tty/serial/suncore.h
 F:	drivers/tty/serial/sunhv.c
 F:	drivers/tty/serial/sunsab.c
 F:	drivers/tty/serial/sunsab.h

+ 23 - 55
arch/alpha/kernel/srmcons.c

@@ -30,10 +30,9 @@ static int srm_is_registered_console = 0;
 #define MAX_SRM_CONSOLE_DEVICES 1	/* only support 1 console device */
 
 struct srmcons_private {
-	struct tty_struct *tty;
+	struct tty_port port;
 	struct timer_list timer;
-	spinlock_t lock;
-};
+} srmcons_singleton;
 
 typedef union _srmcons_result {
 	struct {
@@ -68,22 +67,21 @@ static void
 srmcons_receive_chars(unsigned long data)
 {
 	struct srmcons_private *srmconsp = (struct srmcons_private *)data;
+	struct tty_port *port = &srmconsp->port;
 	unsigned long flags;
 	int incr = 10;
 
 	local_irq_save(flags);
 	if (spin_trylock(&srmcons_callback_lock)) {
-		if (!srmcons_do_receive_chars(srmconsp->tty))
+		if (!srmcons_do_receive_chars(port->tty))
 			incr = 100;
 		spin_unlock(&srmcons_callback_lock);
 	} 
 
-	spin_lock(&srmconsp->lock);
-	if (srmconsp->tty) {
-		srmconsp->timer.expires = jiffies + incr;
-		add_timer(&srmconsp->timer);
-	}
-	spin_unlock(&srmconsp->lock);
+	spin_lock(&port->lock);
+	if (port->tty)
+		mod_timer(&srmconsp->timer, jiffies + incr);
+	spin_unlock(&port->lock);
 
 	local_irq_restore(flags);
 }
@@ -155,57 +153,23 @@ srmcons_chars_in_buffer(struct tty_struct *tty)
 	return 0;
 }
 
-static int
-srmcons_get_private_struct(struct srmcons_private **ps)
-{
-	static struct srmcons_private *srmconsp = NULL;
-	static DEFINE_SPINLOCK(srmconsp_lock);
-	unsigned long flags;
-	int retval = 0;
-
-	if (srmconsp == NULL) {
-		srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
-		spin_lock_irqsave(&srmconsp_lock, flags);
-
-		if (srmconsp == NULL)
-			retval = -ENOMEM;
-		else {
-			srmconsp->tty = NULL;
-			spin_lock_init(&srmconsp->lock);
-			init_timer(&srmconsp->timer);
-		}
-
-		spin_unlock_irqrestore(&srmconsp_lock, flags);
-	}
-
-	*ps = srmconsp;
-	return retval;
-}
-
 static int
 srmcons_open(struct tty_struct *tty, struct file *filp)
 {
-	struct srmcons_private *srmconsp;
+	struct srmcons_private *srmconsp = &srmcons_singleton;
+	struct tty_port *port = &srmconsp->port;
 	unsigned long flags;
-	int retval;
-
-	retval = srmcons_get_private_struct(&srmconsp);
-	if (retval)
-		return retval;
 
-	spin_lock_irqsave(&srmconsp->lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 
-	if (!srmconsp->tty) {
+	if (!port->tty) {
 		tty->driver_data = srmconsp;
-
-		srmconsp->tty = tty;
-		srmconsp->timer.function = srmcons_receive_chars;
-		srmconsp->timer.data = (unsigned long)srmconsp;
-		srmconsp->timer.expires = jiffies + 10;
-		add_timer(&srmconsp->timer);
+		tty->port = port;
+		port->tty = tty; /* XXX proper refcounting */
+		mod_timer(&srmconsp->timer, jiffies + 10);
 	}
 
-	spin_unlock_irqrestore(&srmconsp->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
 
 	return 0;
 }
@@ -214,16 +178,17 @@ static void
 srmcons_close(struct tty_struct *tty, struct file *filp)
 {
 	struct srmcons_private *srmconsp = tty->driver_data;
+	struct tty_port *port = &srmconsp->port;
 	unsigned long flags;
 
-	spin_lock_irqsave(&srmconsp->lock, flags);
+	spin_lock_irqsave(&port->lock, flags);
 
 	if (tty->count == 1) {
-		srmconsp->tty = NULL;
+		port->tty = NULL;
 		del_timer(&srmconsp->timer);
 	}
 
-	spin_unlock_irqrestore(&srmconsp->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
 }
 
 
@@ -240,6 +205,9 @@ static const struct tty_operations srmcons_ops = {
 static int __init
 srmcons_init(void)
 {
+	tty_port_init(&srmcons_singleton.port);
+	setup_timer(&srmcons_singleton.timer, srmcons_receive_chars,
+			(unsigned long)&srmcons_singleton);
 	if (srm_is_registered_console) {
 		struct tty_driver *driver;
 		int err;

+ 4 - 13
arch/ia64/hp/sim/boot/fw-emu.c

@@ -160,28 +160,19 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
 	 */
 	status = 0;
 	if (index == SAL_FREQ_BASE) {
-		switch (in1) {
-		      case SAL_FREQ_BASE_PLATFORM:
+		if (in1 == SAL_FREQ_BASE_PLATFORM)
 			r9 = 200000000;
-			break;
-
-		      case SAL_FREQ_BASE_INTERVAL_TIMER:
+		else if (in1 == SAL_FREQ_BASE_INTERVAL_TIMER) {
 			/*
 			 * Is this supposed to be the cr.itc frequency
 			 * or something platform specific?  The SAL
 			 * doc ain't exactly clear on this...
 			 */
 			r9 = 700000000;
-			break;
-
-		      case SAL_FREQ_BASE_REALTIME_CLOCK:
+		} else if (in1 == SAL_FREQ_BASE_REALTIME_CLOCK)
 			r9 = 1;
-			break;
-
-		      default:
+		else
 			status = -1;
-			break;
-		}
 	} else if (index == SAL_SET_VECTORS) {
 		;
 	} else if (index == SAL_GET_STATE_INFO) {

+ 30 - 6
arch/ia64/hp/sim/hpsim_irq.c

@@ -10,6 +10,8 @@
 #include <linux/sched.h>
 #include <linux/irq.h>
 
+#include "hpsim_ssc.h"
+
 static unsigned int
 hpsim_irq_startup(struct irq_data *data)
 {
@@ -37,15 +39,37 @@ static struct irq_chip irq_type_hp_sim = {
 	.irq_set_affinity =	hpsim_set_affinity_noop,
 };
 
+static void hpsim_irq_set_chip(int irq)
+{
+	struct irq_chip *chip = irq_get_chip(irq);
+
+	if (chip == &no_irq_chip)
+		irq_set_chip(irq, &irq_type_hp_sim);
+}
+
+static void hpsim_connect_irq(int intr, int irq)
+{
+	ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
+}
+
+int hpsim_get_irq(int intr)
+{
+	int irq = assign_irq_vector(AUTO_ASSIGN);
+
+	if (irq >= 0) {
+		hpsim_irq_set_chip(irq);
+		irq_set_handler(irq, handle_simple_irq);
+		hpsim_connect_irq(intr, irq);
+	}
+
+	return irq;
+}
+
 void __init
 hpsim_irq_init (void)
 {
 	int i;
 
-	for_each_active_irq(i) {
-		struct irq_chip *chip = irq_get_chip(i);
-
-		if (chip == &no_irq_chip)
-			irq_set_chip(i, &irq_type_hp_sim);
-	}
+	for_each_active_irq(i)
+		hpsim_irq_set_chip(i);
 }

+ 0 - 6
arch/ia64/hp/sim/hpsim_setup.c

@@ -25,12 +25,6 @@
 
 #include "hpsim_ssc.h"
 
-void
-ia64_ssc_connect_irq (long intr, long irq)
-{
-	ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
-}
-
 void
 ia64_ctl_trace (long on)
 {

+ 3 - 16
arch/ia64/hp/sim/simeth.c

@@ -128,17 +128,6 @@ netdev_probe(char *name, unsigned char *ether)
 }
 
 
-static inline int
-netdev_connect(int irq)
-{
-	/* XXX Fix me
-	 * this does not support multiple cards
-	 * also no return value
-	 */
-	ia64_ssc_connect_irq(NETWORK_INTR, irq);
-	return 0;
-}
-
 static inline int
 netdev_attach(int fd, int irq, unsigned int ipaddr)
 {
@@ -226,15 +215,13 @@ simeth_probe1(void)
 		return err;
 	}
 
-	if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
-		panic("%s: out of interrupt vectors!\n", __func__);
-	dev->irq = rc;
-
 	/*
 	 * attach the interrupt in the simulator, this does enable interrupts
 	 * until a netdev_attach() is called
 	 */
-	netdev_connect(dev->irq);
+	if ((rc = hpsim_get_irq(NETWORK_INTR)) < 0)
+		panic("%s: out of interrupt vectors!\n", __func__);
+	dev->irq = rc;
 
 	printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr",
 	       dev->name, simeth_device, local->simfd);

+ 147 - 558
arch/ia64/hp/sim/simserial.c

@@ -4,16 +4,11 @@
  * This driver is mostly used for bringup purposes and will go away.
  * It has a strong dependency on the system console. All outputs
  * are rerouted to the same facility as the one used by printk which, in our
- * case means sys_sim.c console (goes via the simulator). The code hereafter
- * is completely leveraged from the serial.c driver.
+ * case means sys_sim.c console (goes via the simulator).
  *
  * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co
  *	Stephane Eranian <eranian@hpl.hp.com>
  *	David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * 02/04/00 D. Mosberger	Merged in serial.c bug fixes in rs_close().
- * 02/25/00 D. Mosberger	Synced up with 2.3.99pre-5 version of serial.c.
- * 07/30/02 D. Mosberger	Replace sti()/cli() with explicit spinlocks & local irq masking
  */
 
 #include <linux/init.h>
@@ -27,15 +22,17 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/capability.h>
+#include <linux/circ_buf.h>
 #include <linux/console.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 #include <linux/sysrq.h>
+#include <linux/uaccess.h>
+
+#include <asm/hpsim.h>
 
-#include <asm/irq.h>
-#include <asm/hw_irq.h>
-#include <asm/uaccess.h>
+#include "hpsim_ssc.h"
 
 #undef SIMSERIAL_DEBUG	/* define this to get some debug information */
 
@@ -43,118 +40,44 @@
 
 #define NR_PORTS	1	/* only one port for now */
 
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED)
-
-#define SSC_GETCHAR	21
-
-extern long ia64_ssc (long, long, long, long, int);
-extern void ia64_ssc_connect_irq (long intr, long irq);
-
-static char *serial_name = "SimSerial driver";
-static char *serial_version = "0.6";
-
-/*
- * This has been extracted from asm/serial.h. We need one eventually but
- * I don't know exactly what we're going to put in it so just fake one
- * for now.
- */
-#define BASE_BAUD ( 1843200 / 16 )
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-/*
- * Most of the values here are meaningless to this particular driver.
- * However some values must be preserved for the code (leveraged from serial.c
- * to work correctly).
- * port must not be 0
- * type must not be UNKNOWN
- * So I picked arbitrary (guess from where?) values instead
- */
-static struct serial_state rs_table[NR_PORTS]={
-  /* UART CLK   PORT IRQ     FLAGS        */
-  { 0, BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS,0,PORT_16550 }  /* ttyS0 */
+struct serial_state {
+	struct tty_port port;
+	struct circ_buf xmit;
+	int irq;
+	int x_char;
 };
 
-/*
- * Just for the fun of it !
- */
-static struct serial_uart_config uart_config[] = {
-	{ "unknown", 1, 0 },
-	{ "8250", 1, 0 },
-	{ "16450", 1, 0 },
-	{ "16550", 1, 0 },
-	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
-	{ "cirrus", 1, 0 },
-	{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
-	{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
-		  UART_STARTECH },
-	{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
-	{ NULL, 0}
-};
+static struct serial_state rs_table[NR_PORTS];
 
 struct tty_driver *hp_simserial_driver;
 
-static struct async_struct *IRQ_ports[NR_IRQS];
-
 static struct console *console;
 
-static unsigned char *tmp_buf;
-
-extern struct console *console_drivers; /* from kernel/printk.c */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_stop: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
-		tty->stopped, tty->hw_stopped, tty->flow_stopped);
-#endif
-
-}
-
-static void rs_start(struct tty_struct *tty)
-{
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
-		tty->stopped, tty->hw_stopped, tty->flow_stopped);
-#endif
-}
-
-static  void receive_chars(struct tty_struct *tty)
+static void receive_chars(struct tty_struct *tty)
 {
 	unsigned char ch;
 	static unsigned char seen_esc = 0;
 
 	while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) {
-		if ( ch == 27 && seen_esc == 0 ) {
+		if (ch == 27 && seen_esc == 0) {
 			seen_esc = 1;
 			continue;
-		} else {
-			if ( seen_esc==1 && ch == 'O' ) {
-				seen_esc = 2;
-				continue;
-			} else if ( seen_esc == 2 ) {
-				if ( ch == 'P' ) /* F1 */
-					show_state();
+		} else if (seen_esc == 1 && ch == 'O') {
+			seen_esc = 2;
+			continue;
+		} else if (seen_esc == 2) {
+			if (ch == 'P') /* F1 */
+				show_state();
 #ifdef CONFIG_MAGIC_SYSRQ
-				if ( ch == 'S' ) { /* F4 */
-					do
-						ch = ia64_ssc(0, 0, 0, 0,
-							      SSC_GETCHAR);
-					while (!ch);
-					handle_sysrq(ch);
-				}
-#endif
-				seen_esc = 0;
-				continue;
+			if (ch == 'S') { /* F4 */
+				do {
+					ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR);
+				} while (!ch);
+				handle_sysrq(ch);
 			}
+#endif
+			seen_esc = 0;
+			continue;
 		}
 		seen_esc = 0;
 
@@ -169,22 +92,19 @@ static  void receive_chars(struct tty_struct *tty)
  */
 static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
 {
-	struct async_struct * info;
+	struct serial_state *info = dev_id;
+	struct tty_struct *tty = tty_port_tty_get(&info->port);
 
-	/*
-	 * I don't know exactly why they don't use the dev_id opaque data
-	 * pointer instead of this extra lookup table
-	 */
-	info = IRQ_ports[irq];
-	if (!info || !info->tty) {
-		printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info);
+	if (!tty) {
+		printk(KERN_INFO "%s: tty=0 problem\n", __func__);
 		return IRQ_NONE;
 	}
 	/*
 	 * pretty simple in our case, because we only get interrupts
 	 * on inbound traffic
 	 */
-	receive_chars(info->tty);
+	receive_chars(tty);
+	tty_kref_put(tty);
 	return IRQ_HANDLED;
 }
 
@@ -194,17 +114,12 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
  * -------------------------------------------------------------------
  */
 
-static void do_softint(struct work_struct *private_)
-{
-	printk(KERN_ERR "simserial: do_softint called\n");
-}
-
 static int rs_put_char(struct tty_struct *tty, unsigned char ch)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
-	if (!tty || !info->xmit.buf)
+	if (!info->xmit.buf)
 		return 0;
 
 	local_irq_save(flags);
@@ -218,12 +133,12 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
 	return 1;
 }
 
-static void transmit_chars(struct async_struct *info, int *intr_done)
+static void transmit_chars(struct tty_struct *tty, struct serial_state *info,
+		int *intr_done)
 {
 	int count;
 	unsigned long flags;
 
-
 	local_irq_save(flags);
 
 	if (info->x_char) {
@@ -231,16 +146,16 @@ static void transmit_chars(struct async_struct *info, int *intr_done)
 
 		console->write(console, &c, 1);
 
-		info->state->icount.tx++;
 		info->x_char = 0;
 
 		goto out;
 	}
 
-	if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) {
+	if (info->xmit.head == info->xmit.tail || tty->stopped ||
+			tty->hw_stopped) {
 #ifdef SIMSERIAL_DEBUG
 		printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",
-		       info->xmit.head, info->xmit.tail, info->tty->stopped);
+		       info->xmit.head, info->xmit.tail, tty->stopped);
 #endif
 		goto out;
 	}
@@ -272,24 +187,24 @@ out:
 
 static void rs_flush_chars(struct tty_struct *tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
-	if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped ||
-	    !info->xmit.buf)
+	if (info->xmit.head == info->xmit.tail || tty->stopped ||
+			tty->hw_stopped || !info->xmit.buf)
 		return;
 
-	transmit_chars(info, NULL);
+	transmit_chars(tty, info, NULL);
 }
 
-
 static int rs_write(struct tty_struct * tty,
 		    const unsigned char *buf, int count)
 {
+	struct serial_state *info = tty->driver_data;
 	int	c, ret = 0;
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
 	unsigned long flags;
 
-	if (!tty || !info->xmit.buf || !tmp_buf) return 0;
+	if (!info->xmit.buf)
+		return 0;
 
 	local_irq_save(flags);
 	while (1) {
@@ -310,30 +225,30 @@ static int rs_write(struct tty_struct * tty,
 	/*
 	 * Hey, we transmit directly from here in our case
 	 */
-	if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE)
-	    && !tty->stopped && !tty->hw_stopped) {
-		transmit_chars(info, NULL);
-	}
+	if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) &&
+			!tty->stopped && !tty->hw_stopped)
+		transmit_chars(tty, info, NULL);
+
 	return ret;
 }
 
 static int rs_write_room(struct tty_struct *tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static void rs_flush_buffer(struct tty_struct *tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 	unsigned long flags;
 
 	local_irq_save(flags);
@@ -349,7 +264,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
  */
 static void rs_send_xchar(struct tty_struct *tty, char ch)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	info->x_char = ch;
 	if (ch) {
@@ -357,7 +272,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
 		 * I guess we could call console->write() directly but
 		 * let's do that for now.
 		 */
-		transmit_chars(info, NULL);
+		transmit_chars(tty, info, NULL);
 	}
 }
 
@@ -371,14 +286,15 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
  */
 static void rs_throttle(struct tty_struct * tty)
 {
-	if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty));
+	if (I_IXOFF(tty))
+		rs_send_xchar(tty, STOP_CHAR(tty));
 
 	printk(KERN_INFO "simrs_throttle called\n");
 }
 
 static void rs_unthrottle(struct tty_struct * tty)
 {
-	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	struct serial_state *info = tty->driver_data;
 
 	if (I_IXOFF(tty)) {
 		if (info->x_char)
@@ -389,7 +305,6 @@ static void rs_unthrottle(struct tty_struct * tty)
 	printk(KERN_INFO "simrs_unthrottle called\n");
 }
 
-
 static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
 {
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
@@ -400,48 +315,21 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
 	}
 
 	switch (cmd) {
-		case TIOCGSERIAL:
-			printk(KERN_INFO "simrs_ioctl TIOCGSERIAL called\n");
-			return 0;
-		case TIOCSSERIAL:
-			printk(KERN_INFO "simrs_ioctl TIOCSSERIAL called\n");
-			return 0;
-		case TIOCSERCONFIG:
-			printk(KERN_INFO "rs_ioctl: TIOCSERCONFIG called\n");
-			return -EINVAL;
-
-		case TIOCSERGETLSR: /* Get line status register */
-			printk(KERN_INFO "rs_ioctl: TIOCSERGETLSR called\n");
-			return  -EINVAL;
-
-		case TIOCSERGSTRUCT:
-			printk(KERN_INFO "rs_ioctl: TIOCSERGSTRUCT called\n");
-#if 0
-			if (copy_to_user((struct async_struct *) arg,
-					 info, sizeof(struct async_struct)))
-				return -EFAULT;
-#endif
-			return 0;
-
-		/*
-		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-		 * - mask passed in arg for lines of interest
-		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-		 * Caller should use TIOCGICOUNT to see which one it was
-		 */
-		case TIOCMIWAIT:
-			printk(KERN_INFO "rs_ioctl: TIOCMIWAIT: called\n");
-			return 0;
-		case TIOCSERGWILD:
-		case TIOCSERSWILD:
-			/* "setserial -W" is called in Debian boot */
-			printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n");
-			return 0;
-
-		default:
-			return -ENOIOCTLCMD;
-		}
-	return 0;
+	case TIOCGSERIAL:
+	case TIOCSSERIAL:
+	case TIOCSERGSTRUCT:
+	case TIOCMIWAIT:
+		return 0;
+	case TIOCSERCONFIG:
+	case TIOCSERGETLSR: /* Get line status register */
+		return -EINVAL;
+	case TIOCSERGWILD:
+	case TIOCSERSWILD:
+		/* "setserial -W" is called in Debian boot */
+		printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n");
+		return 0;
+	}
+	return -ENOIOCTLCMD;
 }
 
 #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
@@ -452,220 +340,50 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	    !(tty->termios->c_cflag & CRTSCTS)) {
 		tty->hw_stopped = 0;
-		rs_start(tty);
 	}
 }
 /*
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void shutdown(struct async_struct * info)
+static void shutdown(struct tty_port *port)
 {
-	unsigned long	flags;
-	struct serial_state *state;
-	int		retval;
-
-	if (!(info->flags & ASYNC_INITIALIZED)) return;
-
-	state = info->state;
-
-#ifdef SIMSERIAL_DEBUG
-	printk("Shutting down serial port %d (irq %d)....", info->line,
-	       state->irq);
-#endif
+	struct serial_state *info = container_of(port, struct serial_state,
+			port);
+	unsigned long flags;
 
 	local_irq_save(flags);
-	{
-		/*
-		 * First unlink the serial port from the IRQ chain...
-		 */
-		if (info->next_port)
-			info->next_port->prev_port = info->prev_port;
-		if (info->prev_port)
-			info->prev_port->next_port = info->next_port;
-		else
-			IRQ_ports[state->irq] = info->next_port;
-
-		/*
-		 * Free the IRQ, if necessary
-		 */
-		if (state->irq && (!IRQ_ports[state->irq] ||
-				   !IRQ_ports[state->irq]->next_port)) {
-			if (IRQ_ports[state->irq]) {
-				free_irq(state->irq, NULL);
-				retval = request_irq(state->irq, rs_interrupt_single,
-						     IRQ_T(info), "serial", NULL);
-
-				if (retval)
-					printk(KERN_ERR "serial shutdown: request_irq: error %d"
-					       "  Couldn't reacquire IRQ.\n", retval);
-			} else
-				free_irq(state->irq, NULL);
-		}
-
-		if (info->xmit.buf) {
-			free_page((unsigned long) info->xmit.buf);
-			info->xmit.buf = NULL;
-		}
-
-		if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
+	if (info->irq)
+		free_irq(info->irq, info);
 
-		info->flags &= ~ASYNC_INITIALIZED;
+	if (info->xmit.buf) {
+		free_page((unsigned long) info->xmit.buf);
+		info->xmit.buf = NULL;
 	}
 	local_irq_restore(flags);
 }
 
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.  First, we
- * wait for the last remaining data to be sent.  Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
 static void rs_close(struct tty_struct *tty, struct file * filp)
 {
-	struct async_struct * info = (struct async_struct *)tty->driver_data;
-	struct serial_state *state;
-	unsigned long flags;
-
-	if (!info ) return;
-
-	state = info->state;
-
-	local_irq_save(flags);
-	if (tty_hung_up_p(filp)) {
-#ifdef SIMSERIAL_DEBUG
-		printk("rs_close: hung_up\n");
-#endif
-		local_irq_restore(flags);
-		return;
-	}
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_close ttys%d, count = %d\n", info->line, state->count);
-#endif
-	if ((tty->count == 1) && (state->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  state->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * serial port won't be shutdown.
-		 */
-		printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, "
-		       "state->count is %d\n", state->count);
-		state->count = 1;
-	}
-	if (--state->count < 0) {
-		printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",
-		       info->line, state->count);
-		state->count = 0;
-	}
-	if (state->count) {
-		local_irq_restore(flags);
-		return;
-	}
-	info->flags |= ASYNC_CLOSING;
-	local_irq_restore(flags);
+	struct serial_state *info = tty->driver_data;
 
-	/*
-	 * Now we wait for the transmit buffer to clear; and we notify
-	 * the line discipline to only process XON/XOFF characters.
-	 */
-	shutdown(info);
-	rs_flush_buffer(tty);
-	tty_ldisc_flush(tty);
-	info->event = 0;
-	info->tty = NULL;
-	if (info->blocked_open) {
-		if (info->close_delay)
-			schedule_timeout_interruptible(info->close_delay);
-		wake_up_interruptible(&info->open_wait);
-	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-	wake_up_interruptible(&info->close_wait);
+	tty_port_close(&info->port, tty, filp);
 }
 
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-}
-
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
 static void rs_hangup(struct tty_struct *tty)
 {
-	struct async_struct * info = (struct async_struct *)tty->driver_data;
-	struct serial_state *state = info->state;
-
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_hangup: called\n");
-#endif
-
-	state = info->state;
+	struct serial_state *info = tty->driver_data;
 
 	rs_flush_buffer(tty);
-	if (info->flags & ASYNC_CLOSING)
-		return;
-	shutdown(info);
-
-	info->event = 0;
-	state->count = 0;
-	info->flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
+	tty_port_hangup(&info->port);
 }
 
-
-static int get_async_struct(int line, struct async_struct **ret_info)
+static int activate(struct tty_port *port, struct tty_struct *tty)
 {
-	struct async_struct *info;
-	struct serial_state *sstate;
-
-	sstate = rs_table + line;
-	sstate->count++;
-	if (sstate->info) {
-		*ret_info = sstate->info;
-		return 0;
-	}
-	info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
-	if (!info) {
-		sstate->count--;
-		return -ENOMEM;
-	}
-	init_waitqueue_head(&info->open_wait);
-	init_waitqueue_head(&info->close_wait);
-	init_waitqueue_head(&info->delta_msr_wait);
-	info->magic = SERIAL_MAGIC;
-	info->port = sstate->port;
-	info->flags = sstate->flags;
-	info->xmit_fifo_size = sstate->xmit_fifo_size;
-	info->line = line;
-	INIT_WORK(&info->work, do_softint);
-	info->state = sstate;
-	if (sstate->info) {
-		kfree(info);
-		*ret_info = sstate->info;
-		return 0;
-	}
-	*ret_info = sstate->info = info;
-	return 0;
-}
-
-static int
-startup(struct async_struct *info)
-{
-	unsigned long flags;
-	int	retval=0;
-	irq_handler_t handler;
-	struct serial_state *state= info->state;
-	unsigned long page;
+	struct serial_state *state = container_of(port, struct serial_state,
+			port);
+	unsigned long flags, page;
+	int retval = 0;
 
 	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
@@ -673,86 +391,31 @@ startup(struct async_struct *info)
 
 	local_irq_save(flags);
 
-	if (info->flags & ASYNC_INITIALIZED) {
-		free_page(page);
-		goto errout;
-	}
-
-	if (!state->port || !state->type) {
-		if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
-		free_page(page);
-		goto errout;
-	}
-	if (info->xmit.buf)
+	if (state->xmit.buf)
 		free_page(page);
 	else
-		info->xmit.buf = (unsigned char *) page;
-
-#ifdef SIMSERIAL_DEBUG
-	printk("startup: ttys%d (irq %d)...", info->line, state->irq);
-#endif
+		state->xmit.buf = (unsigned char *) page;
 
-	/*
-	 * Allocate the IRQ if necessary
-	 */
-	if (state->irq && (!IRQ_ports[state->irq] ||
-			  !IRQ_ports[state->irq]->next_port)) {
-		if (IRQ_ports[state->irq]) {
-			retval = -EBUSY;
-			goto errout;
-		} else
-			handler = rs_interrupt_single;
-
-		retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL);
-		if (retval) {
-			if (capable(CAP_SYS_ADMIN)) {
-				if (info->tty)
-					set_bit(TTY_IO_ERROR,
-						&info->tty->flags);
-				retval = 0;
-			}
+	if (state->irq) {
+		retval = request_irq(state->irq, rs_interrupt_single, 0,
+				"simserial", state);
+		if (retval)
 			goto errout;
-		}
 	}
 
-	/*
-	 * Insert serial port into IRQ chain.
-	 */
-	info->prev_port = NULL;
-	info->next_port = IRQ_ports[state->irq];
-	if (info->next_port)
-		info->next_port->prev_port = info;
-	IRQ_ports[state->irq] = info;
-
-	if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags);
-
-	info->xmit.head = info->xmit.tail = 0;
-
-#if 0
-	/*
-	 * Set up serial timers...
-	 */
-	timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
-	timer_active |= 1 << RS_TIMER;
-#endif
+	state->xmit.head = state->xmit.tail = 0;
 
 	/*
 	 * Set up the tty->alt_speed kludge
 	 */
-	if (info->tty) {
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-			info->tty->alt_speed = 57600;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-			info->tty->alt_speed = 115200;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-			info->tty->alt_speed = 230400;
-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-			info->tty->alt_speed = 460800;
-	}
-
-	info->flags |= ASYNC_INITIALIZED;
-	local_irq_restore(flags);
-	return 0;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+		tty->alt_speed = 57600;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		tty->alt_speed = 115200;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+		tty->alt_speed = 230400;
+	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+		tty->alt_speed = 460800;
 
 errout:
 	local_irq_restore(flags);
@@ -768,56 +431,11 @@ errout:
  */
 static int rs_open(struct tty_struct *tty, struct file * filp)
 {
-	struct async_struct	*info;
-	int			retval, line;
-	unsigned long		page;
+	struct serial_state *info = rs_table + tty->index;
+	struct tty_port *port = &info->port;
 
-	line = tty->index;
-	if ((line < 0) || (line >= NR_PORTS))
-		return -ENODEV;
-	retval = get_async_struct(line, &info);
-	if (retval)
-		return retval;
 	tty->driver_data = info;
-	info->tty = tty;
-
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_open %s, count = %d\n", tty->name, info->state->count);
-#endif
-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
-	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 the middle of closing, bail out now
-	 */
-	if (tty_hung_up_p(filp) ||
-	    (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
-		return ((info->flags & ASYNC_HUP_NOTIFY) ?
-			-EAGAIN : -ERESTARTSYS);
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/*
-	 * Start up serial port
-	 */
-	retval = startup(info);
-	if (retval) {
-		return retval;
-	}
+	tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	/*
 	 * figure out which console to use (should be one already)
@@ -828,30 +446,21 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
 		console = console->next;
 	}
 
-#ifdef SIMSERIAL_DEBUG
-	printk("rs_open ttys%d successful\n", info->line);
-#endif
-	return 0;
+	return tty_port_open(port, tty, filp);
 }
 
 /*
  * /proc fs routines....
  */
 
-static inline void line_info(struct seq_file *m, struct serial_state *state)
-{
-	seq_printf(m, "%d: uart:%s port:%lX irq:%d\n",
-		       state->line, uart_config[state->type].name,
-		       state->port, state->irq);
-}
-
 static int rs_proc_show(struct seq_file *m, void *v)
 {
 	int i;
 
-	seq_printf(m, "simserinfo:1.0 driver:%s\n", serial_version);
+	seq_printf(m, "simserinfo:1.0\n");
 	for (i = 0; i < NR_PORTS; i++)
-		line_info(m, &rs_table[i]);
+		seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n",
+		       i, rs_table[i].irq);
 	return 0;
 }
 
@@ -868,25 +477,6 @@ static const struct file_operations rs_proc_fops = {
 	.release	= single_release,
 };
 
-/*
- * ---------------------------------------------------------------------
- * rs_init() and friends
- *
- * rs_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static inline void show_serial_version(void)
-{
-	printk(KERN_INFO "%s version %s with", serial_name, serial_version);
-	printk(KERN_INFO " no serial options enabled\n");
-}
-
 static const struct tty_operations hp_ops = {
 	.open = rs_open,
 	.close = rs_close,
@@ -901,34 +491,31 @@ static const struct tty_operations hp_ops = {
 	.unthrottle = rs_unthrottle,
 	.send_xchar = rs_send_xchar,
 	.set_termios = rs_set_termios,
-	.stop = rs_stop,
-	.start = rs_start,
 	.hangup = rs_hangup,
-	.wait_until_sent = rs_wait_until_sent,
 	.proc_fops = &rs_proc_fops,
 };
 
-/*
- * The serial driver boot-time initialization code!
- */
-static int __init
-simrs_init (void)
+static const struct tty_port_operations hp_port_ops = {
+	.activate = activate,
+	.shutdown = shutdown,
+};
+
+static int __init simrs_init(void)
 {
-	int			i, rc;
-	struct serial_state	*state;
+	struct serial_state *state;
+	int retval;
 
 	if (!ia64_platform_is("hpsim"))
 		return -ENODEV;
 
-	hp_simserial_driver = alloc_tty_driver(1);
+	hp_simserial_driver = alloc_tty_driver(NR_PORTS);
 	if (!hp_simserial_driver)
 		return -ENOMEM;
 
-	show_serial_version();
+	printk(KERN_INFO "SimSerial driver with no serial options enabled\n");
 
 	/* Initialize the tty_driver structure */
 
-	hp_simserial_driver->owner = THIS_MODULE;
 	hp_simserial_driver->driver_name = "simserial";
 	hp_simserial_driver->name = "ttyS";
 	hp_simserial_driver->major = TTY_MAJOR;
@@ -941,31 +528,33 @@ simrs_init (void)
 	hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW;
 	tty_set_operations(hp_simserial_driver, &hp_ops);
 
-	/*
-	 * Let's have a little bit of fun !
-	 */
-	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+	state = rs_table;
+	tty_port_init(&state->port);
+	state->port.ops = &hp_port_ops;
+	state->port.close_delay = 0; /* XXX really 0? */
 
-		if (state->type == PORT_UNKNOWN) continue;
+	retval = hpsim_get_irq(KEYBOARD_INTR);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: out of interrupt vectors!\n",
+				__func__);
+		goto err_free_tty;
+	}
 
-		if (!state->irq) {
-			if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
-				panic("%s: out of interrupt vectors!\n",
-				      __func__);
-			state->irq = rc;
-			ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);
-		}
+	state->irq = retval;
 
-		printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n",
-		       state->line,
-		       state->port, state->irq,
-		       uart_config[state->type].name);
-	}
+	/* the port is imaginary */
+	printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);
 
-	if (tty_register_driver(hp_simserial_driver))
-		panic("Couldn't register simserial driver\n");
+	retval = tty_register_driver(hp_simserial_driver);
+	if (retval) {
+		printk(KERN_ERR "Couldn't register simserial driver\n");
+		goto err_free_tty;
+	}
 
 	return 0;
+err_free_tty:
+	put_tty_driver(hp_simserial_driver);
+	return retval;
 }
 
 #ifndef MODULE

+ 1 - 1
arch/ia64/include/asm/hpsim.h

@@ -10,7 +10,7 @@ int simcons_register(void);
 struct tty_driver;
 extern struct tty_driver *hp_simserial_driver;
 
-void ia64_ssc_connect_irq(long intr, long irq);
+extern int hpsim_get_irq(int intr);
 void ia64_ctl_trace(long on);
 
 #endif

+ 0 - 1
arch/m68k/emu/nfcon.c

@@ -127,7 +127,6 @@ static int __init nfcon_init(void)
 	if (!nfcon_tty_driver)
 		return -ENOMEM;
 
-	nfcon_tty_driver->owner = THIS_MODULE;
 	nfcon_tty_driver->driver_name = "nfcon";
 	nfcon_tty_driver->name = "nfcon";
 	nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;

+ 29 - 30
arch/parisc/kernel/pdc_cons.c

@@ -90,11 +90,13 @@ static int pdc_console_setup(struct console *co, char *options)
 
 #define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
 
-static struct timer_list pdc_console_timer;
+static void pdc_console_poll(unsigned long unused);
+static DEFINE_TIMER(pdc_console_timer, pdc_console_poll, 0, 0);
+static struct tty_port tty_port;
 
 static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
 {
-
+	tty_port_tty_set(&tty_port, tty);
 	mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
 
 	return 0;
@@ -102,8 +104,10 @@ static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
 
 static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp)
 {
-	if (!tty->count)
-		del_timer(&pdc_console_timer);
+	if (!tty->count) {
+		del_timer_sync(&pdc_console_timer);
+		tty_port_tty_set(&tty_port, NULL);
+	}
 }
 
 static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -122,8 +126,6 @@ static int pdc_console_tty_chars_in_buffer(struct tty_struct *tty)
 	return 0; /* no buffer */
 }
 
-static struct tty_driver *pdc_console_tty_driver;
-
 static const struct tty_operations pdc_console_tty_ops = {
 	.open = pdc_console_tty_open,
 	.close = pdc_console_tty_close,
@@ -134,10 +136,8 @@ static const struct tty_operations pdc_console_tty_ops = {
 
 static void pdc_console_poll(unsigned long unused)
 {
-
 	int data, count = 0;
-
-	struct tty_struct *tty = pdc_console_tty_driver->ttys[0];
+	struct tty_struct *tty = tty_port_tty_get(&tty_port);
 
 	if (!tty)
 		return;
@@ -153,15 +153,17 @@ static void pdc_console_poll(unsigned long unused)
 	if (count)
 		tty_flip_buffer_push(tty);
 
-	if (tty->count && (pdc_cons.flags & CON_ENABLED))
+	tty_kref_put(tty);
+
+	if (pdc_cons.flags & CON_ENABLED)
 		mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
 }
 
+static struct tty_driver *pdc_console_tty_driver;
+
 static int __init pdc_console_tty_driver_init(void)
 {
-
 	int err;
-	struct tty_driver *drv;
 
 	/* Check if the console driver is still registered.
 	 * It is unregistered if the pdc console was not selected as the
@@ -183,32 +185,29 @@ static int __init pdc_console_tty_driver_init(void)
 	printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n");
 	pdc_cons.flags &= ~CON_BOOT;
 
-	drv = alloc_tty_driver(1);
+	tty_port_init(&tty_port);
 
-	if (!drv)
-		return -ENOMEM;
+	pdc_console_tty_driver = alloc_tty_driver(1);
 
-	drv->driver_name = "pdc_cons";
-	drv->name = "ttyB";
-	drv->major = MUX_MAJOR;
-	drv->minor_start = 0;
-	drv->type = TTY_DRIVER_TYPE_SYSTEM;
-	drv->init_termios = tty_std_termios;
-	drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-	tty_set_operations(drv, &pdc_console_tty_ops);
+	if (!pdc_console_tty_driver)
+		return -ENOMEM;
 
-	err = tty_register_driver(drv);
+	pdc_console_tty_driver->driver_name = "pdc_cons";
+	pdc_console_tty_driver->name = "ttyB";
+	pdc_console_tty_driver->major = MUX_MAJOR;
+	pdc_console_tty_driver->minor_start = 0;
+	pdc_console_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+	pdc_console_tty_driver->init_termios = tty_std_termios;
+	pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
+		TTY_DRIVER_RESET_TERMIOS;
+	tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
+
+	err = tty_register_driver(pdc_console_tty_driver);
 	if (err) {
 		printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
 		return err;
 	}
 
-	pdc_console_tty_driver = drv;
-
-	/* No need to initialize the pdc_console_timer if tty isn't allocated */
-	init_timer(&pdc_console_timer);
-	pdc_console_timer.function = pdc_console_poll;
-
 	return 0;
 }
 

+ 8 - 14
arch/xtensa/platforms/iss/console.c

@@ -19,7 +19,6 @@
 #include <linux/param.h>
 #include <linux/seq_file.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 
 #include <asm/uaccess.h>
 #include <asm/irq.h>
@@ -37,6 +36,7 @@
 #define SERIAL_TIMER_VALUE (20 * HZ)
 
 static struct tty_driver *serial_driver;
+static struct tty_port serial_port;
 static struct timer_list serial_timer;
 
 static DEFINE_SPINLOCK(timer_lock);
@@ -68,17 +68,10 @@ static void rs_poll(unsigned long);
 
 static int rs_open(struct tty_struct *tty, struct file * filp)
 {
-	int line = tty->index;
-
-	if ((line < 0) || (line >= SERIAL_MAX_NUM_LINES))
-		return -ENODEV;
-
+	tty->port = &serial_port;
 	spin_lock(&timer_lock);
-
 	if (tty->count == 1) {
-		init_timer(&serial_timer);
-		serial_timer.data = (unsigned long) tty;
-		serial_timer.function = rs_poll;
+		setup_timer(&serial_timer, rs_poll, (unsigned long)tty);
 		mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
 	}
 	spin_unlock(&timer_lock);
@@ -99,10 +92,10 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
  */
 static void rs_close(struct tty_struct *tty, struct file * filp)
 {
-	spin_lock(&timer_lock);
+	spin_lock_bh(&timer_lock);
 	if (tty->count == 1)
 		del_timer_sync(&serial_timer);
-	spin_unlock(&timer_lock);
+	spin_unlock_bh(&timer_lock);
 }
 
 
@@ -210,13 +203,14 @@ static const struct tty_operations serial_ops = {
 
 int __init rs_init(void)
 {
-	serial_driver = alloc_tty_driver(1);
+	tty_port_init(&serial_port);
+
+	serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES);
 
 	printk ("%s %s\n", serial_name, serial_version);
 
 	/* Initialize the tty_driver structure */
 
-	serial_driver->owner = THIS_MODULE;
 	serial_driver->driver_name = "iss_serial";
 	serial_driver->name = "ttyS";
 	serial_driver->major = TTY_MAJOR;

+ 3 - 6
drivers/accessibility/braille/braille_console.c

@@ -244,16 +244,13 @@ static int keyboard_notifier_call(struct notifier_block *blk,
 
 			switch (val) {
 			case KVAL(K_CAPS):
-				on_off = vc_kbd_led(kbd_table + fg_console,
-						VC_CAPSLOCK);
+				on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
 				break;
 			case KVAL(K_NUM):
-				on_off = vc_kbd_led(kbd_table + fg_console,
-						VC_NUMLOCK);
+				on_off = vt_get_leds(fg_console, VC_NUMLOCK);
 				break;
 			case KVAL(K_HOLD):
-				on_off = vc_kbd_led(kbd_table + fg_console,
-						VC_SCROLLOCK);
+				on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
 				break;
 			}
 			if (on_off == 1)

+ 0 - 15
drivers/char/Kconfig

@@ -66,21 +66,6 @@ config TTY_PRINTK
 
 	  If unsure, say N.
 
-config BRIQ_PANEL
-	tristate 'Total Impact briQ front panel driver'
-	depends on PPC_CHRP
-	---help---
-	  The briQ is a small footprint CHRP computer with a frontpanel VFD, a
-	  tristate led and two switches. It is the size of a CDROM drive.
-
-	  If you have such one and want anything showing on the VFD then you
-	  must answer Y here.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called briq_panel.
-
-	  It's safe to say N here.
-
 config BFIN_OTP
 	tristate "Blackfin On-Chip OTP Memory Support"
 	depends on BLACKFIN && (BF51x || BF52x || BF54x)

+ 0 - 1
drivers/char/Makefile

@@ -16,7 +16,6 @@ obj-$(CONFIG_UV_MMTIMER)	+= uv_mmtimer.o
 obj-$(CONFIG_VIOTAPE)		+= viotape.o
 obj-$(CONFIG_IBM_BSR)		+= bsr.o
 obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
-obj-$(CONFIG_BRIQ_PANEL)	+= briq_panel.o
 obj-$(CONFIG_BFIN_OTP)		+= bfin-otp.o
 
 obj-$(CONFIG_PRINTER)		+= lp.o

+ 0 - 266
drivers/char/briq_panel.c

@@ -1,266 +0,0 @@
-/*
- * Drivers for the Total Impact PPC based computer "BRIQ"
- * by Dr. Karsten Jeppesen
- *
- */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-
-#define		BRIQ_PANEL_MINOR	156
-#define		BRIQ_PANEL_VFD_IOPORT	0x0390
-#define		BRIQ_PANEL_LED_IOPORT	0x0398
-#define		BRIQ_PANEL_VER		"1.1 (04/20/2002)"
-#define		BRIQ_PANEL_MSG0		"Loading Linux"
-
-static int		vfd_is_open;
-static unsigned char	vfd[40];
-static int		vfd_cursor;
-static unsigned char	ledpb, led;
-
-static void update_vfd(void)
-{
-	int	i;
-
-	/* cursor home */
-	outb(0x02, BRIQ_PANEL_VFD_IOPORT);
-	for (i=0; i<20; i++)
-		outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
-
-	/* cursor to next line */
-	outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
-	for (i=20; i<40; i++)
-		outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
-
-}
-
-static void set_led(char state)
-{
-	if (state == 'R')
-		led = 0x01;
-	else if (state == 'G')
-		led = 0x02;
-	else if (state == 'Y')
-		led = 0x03;
-	else if (state == 'X')
-		led = 0x00;
-	outb(led, BRIQ_PANEL_LED_IOPORT);
-}
-
-static int briq_panel_open(struct inode *ino, struct file *filep)
-{
-	tty_lock();
-	/* enforce single access, vfd_is_open is protected by BKL */
-	if (vfd_is_open) {
-		tty_unlock();
-		return -EBUSY;
-	}
-	vfd_is_open = 1;
-
-	tty_unlock();
-	return 0;
-}
-
-static int briq_panel_release(struct inode *ino, struct file *filep)
-{
-	if (!vfd_is_open)
-		return -ENODEV;
-
-	vfd_is_open = 0;
-
-	return 0;
-}
-
-static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
-			 loff_t *ppos)
-{
-	unsigned short c;
-	unsigned char cp;
-
-	if (!vfd_is_open)
-		return -ENODEV;
-
-	c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
-	set_led(' ');
-	/* upper button released */
-	if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
-		cp = ' ';
-		ledpb = c;
-		if (copy_to_user(buf, &cp, 1))
-			return -EFAULT;
-		return 1;
-	}
-	/* lower button released */
-	else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
-		cp = '\r';
-		ledpb = c;
-		if (copy_to_user(buf, &cp, 1))
-			return -EFAULT;
-		return 1;
-	} else {
-		ledpb = c;
-		return 0;
-	}
-}
-
-static void scroll_vfd( void )
-{
-	int	i;
-
-	for (i=0; i<20; i++) {
-		vfd[i] = vfd[i+20];
-		vfd[i+20] = ' ';
-	}
-	vfd_cursor = 20;
-}
-
-static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
-			  loff_t *ppos)
-{
-	size_t indx = len;
-	int i, esc = 0;
-
-	if (!vfd_is_open)
-		return -EBUSY;
-
-	for (;;) {
-		char c;
-		if (!indx)
-			break;
-		if (get_user(c, buf))
-			return -EFAULT;
-		if (esc) {
-			set_led(c);
-			esc = 0;
-		} else if (c == 27) {
-			esc = 1;
-		} else if (c == 12) {
-			/* do a form feed */
-			for (i=0; i<40; i++)
-				vfd[i] = ' ';
-			vfd_cursor = 0;
-		} else if (c == 10) {
-			if (vfd_cursor < 20)
-				vfd_cursor = 20;
-			else if (vfd_cursor < 40)
-				vfd_cursor = 40;
-			else if (vfd_cursor < 60)
-				vfd_cursor = 60;
-			if (vfd_cursor > 59)
-				scroll_vfd();
-		} else {
-			/* just a character */
-			if (vfd_cursor > 39)
-				scroll_vfd();
-			vfd[vfd_cursor++] = c;
-		}
-		indx--;
-		buf++;
-	}
-	update_vfd();
-
-	return len;
-}
-
-static const struct file_operations briq_panel_fops = {
-	.owner		= THIS_MODULE,
-	.read		= briq_panel_read,
-	.write		= briq_panel_write,
-	.open		= briq_panel_open,
-	.release	= briq_panel_release,
-	.llseek		= noop_llseek,
-};
-
-static struct miscdevice briq_panel_miscdev = {
-	BRIQ_PANEL_MINOR,
-	"briq_panel",
-	&briq_panel_fops
-};
-
-static int __init briq_panel_init(void)
-{
-	struct device_node *root = of_find_node_by_path("/");
-	const char *machine;
-	int i;
-
-	machine = of_get_property(root, "model", NULL);
-	if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
-		of_node_put(root);
-		return -ENODEV;
-	}
-	of_node_put(root);
-
-	printk(KERN_INFO
-		"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
-		BRIQ_PANEL_VER);
-
-	if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
-		return -EBUSY;
-
-	if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
-		release_region(BRIQ_PANEL_VFD_IOPORT, 4);
-		return -EBUSY;
-	}
-	ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
-
-	if (misc_register(&briq_panel_miscdev) < 0) {
-		release_region(BRIQ_PANEL_VFD_IOPORT, 4);
-		release_region(BRIQ_PANEL_LED_IOPORT, 2);
-		return -EBUSY;
-	}
-
-	outb(0x38, BRIQ_PANEL_VFD_IOPORT);	/* Function set */
-	outb(0x01, BRIQ_PANEL_VFD_IOPORT);	/* Clear display */
-	outb(0x0c, BRIQ_PANEL_VFD_IOPORT);	/* Display on */
-	outb(0x06, BRIQ_PANEL_VFD_IOPORT);	/* Entry normal */
-	for (i=0; i<40; i++)
-		vfd[i]=' ';
-#ifndef MODULE
-	vfd[0] = 'L';
-	vfd[1] = 'o';
-	vfd[2] = 'a';
-	vfd[3] = 'd';
-	vfd[4] = 'i';
-	vfd[5] = 'n';
-	vfd[6] = 'g';
-	vfd[7] = ' ';
-	vfd[8] = '.';
-	vfd[9] = '.';
-	vfd[10] = '.';
-#endif /* !MODULE */
-
-	update_vfd();
-
-	return 0;
-}
-
-static void __exit briq_panel_exit(void)
-{
-	misc_deregister(&briq_panel_miscdev);
-	release_region(BRIQ_PANEL_VFD_IOPORT, 4);
-	release_region(BRIQ_PANEL_LED_IOPORT, 2);
-}
-
-module_init(briq_panel_init);
-module_exit(briq_panel_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>");
-MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");

+ 1 - 2
drivers/char/pcmcia/synclink_cs.c

@@ -2484,7 +2484,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
 
 	/* verify range of specified line number */
 	line = tty->index;
-	if ((line < 0) || (line >= mgslpc_device_count)) {
+	if (line >= mgslpc_device_count) {
 		printk("%s(%d):mgslpc_open with invalid line #%d.\n",
 			__FILE__,__LINE__,line);
 		return -ENODEV;
@@ -2836,7 +2836,6 @@ static int __init synclink_cs_init(void)
 
     /* Initialize the tty_driver structure */
 
-    serial_driver->owner = THIS_MODULE;
     serial_driver->driver_name = "synclink_cs";
     serial_driver->name = "ttySLP";
     serial_driver->major = ttymajor;

+ 0 - 2
drivers/char/ttyprintk.c

@@ -184,12 +184,10 @@ static int __init ttyprintk_init(void)
 	if (!ttyprintk_driver)
 		return ret;
 
-	ttyprintk_driver->owner = THIS_MODULE;
 	ttyprintk_driver->driver_name = "ttyprintk";
 	ttyprintk_driver->name = "ttyprintk";
 	ttyprintk_driver->major = TTYAUX_MAJOR;
 	ttyprintk_driver->minor_start = 3;
-	ttyprintk_driver->num = 1;
 	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
 	ttyprintk_driver->init_termios = tty_std_termios;
 	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;

+ 4 - 9
drivers/isdn/capi/capi.c

@@ -1013,16 +1013,12 @@ static const struct file_operations capi_fops =
 static int
 capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-	int idx = tty->index;
-	struct capiminor *mp = capiminor_get(idx);
-	int ret = tty_init_termios(tty);
+	struct capiminor *mp = capiminor_get(tty->index);
+	int ret = tty_standard_install(driver, tty);
 
-	if (ret == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
+	if (ret == 0)
 		tty->driver_data = mp;
-		driver->ttys[idx] = tty;
-	} else
+	else
 		capiminor_put(mp);
 	return ret;
 }
@@ -1290,7 +1286,6 @@ static int __init capinc_tty_init(void)
 		kfree(capiminors);
 		return -ENOMEM;
 	}
-	drv->owner = THIS_MODULE;
 	drv->driver_name = "capi_nc";
 	drv->name = "capi";
 	drv->major = 0;

+ 1 - 4
drivers/isdn/gigaset/common.c

@@ -720,12 +720,11 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
 
 	tasklet_init(&cs->event_tasklet, gigaset_handle_event,
 		     (unsigned long) cs);
+	tty_port_init(&cs->port);
 	cs->commands_pending = 0;
 	cs->cur_at_seq = 0;
 	cs->gotfwver = -1;
-	cs->open_count = 0;
 	cs->dev = NULL;
-	cs->tty = NULL;
 	cs->tty_dev = NULL;
 	cs->cidmode = cidmode != 0;
 	cs->tabnocid = gigaset_tab_nocid;
@@ -1051,8 +1050,6 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
 
 struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
 {
-	if (tty->index < 0 || tty->index >= tty->driver->num)
-		return NULL;
 	return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
 }
 

+ 1 - 2
drivers/isdn/gigaset/gigaset.h

@@ -433,8 +433,7 @@ struct cardstate {
 	spinlock_t cmdlock;
 	unsigned curlen, cmdbytes;
 
-	unsigned open_count;
-	struct tty_struct *tty;
+	struct tty_port port;
 	struct tasklet_struct if_wake_tasklet;
 	unsigned control_state;
 

+ 34 - 124
drivers/isdn/gigaset/interface.c

@@ -146,13 +146,10 @@ static const struct tty_operations if_ops = {
 static int if_open(struct tty_struct *tty, struct file *filp)
 {
 	struct cardstate *cs;
-	unsigned long flags;
 
 	gig_dbg(DEBUG_IF, "%d+%d: %s()",
 		tty->driver->minor_start, tty->index, __func__);
 
-	tty->driver_data = NULL;
-
 	cs = gigaset_get_cs_by_tty(tty);
 	if (!cs || !try_module_get(cs->driver->owner))
 		return -ENODEV;
@@ -163,12 +160,10 @@ static int if_open(struct tty_struct *tty, struct file *filp)
 	}
 	tty->driver_data = cs;
 
-	++cs->open_count;
+	++cs->port.count;
 
-	if (cs->open_count == 1) {
-		spin_lock_irqsave(&cs->lock, flags);
-		cs->tty = tty;
-		spin_unlock_irqrestore(&cs->lock, flags);
+	if (cs->port.count == 1) {
+		tty_port_tty_set(&cs->port, tty);
 		tty->low_latency = 1;
 	}
 
@@ -178,12 +173,10 @@ static int if_open(struct tty_struct *tty, struct file *filp)
 
 static void if_close(struct tty_struct *tty, struct file *filp)
 {
-	struct cardstate *cs;
-	unsigned long flags;
+	struct cardstate *cs = tty->driver_data;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
+	if (!cs) { /* happens if we didn't find cs in open */
+		printk(KERN_DEBUG "%s: no cardstate\n", __func__);
 		return;
 	}
 
@@ -193,15 +186,10 @@ static void if_close(struct tty_struct *tty, struct file *filp)
 
 	if (!cs->connected)
 		gig_dbg(DEBUG_IF, "not connected");	/* nothing to do */
-	else if (!cs->open_count)
+	else if (!cs->port.count)
 		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-	else {
-		if (!--cs->open_count) {
-			spin_lock_irqsave(&cs->lock, flags);
-			cs->tty = NULL;
-			spin_unlock_irqrestore(&cs->lock, flags);
-		}
-	}
+	else if (!--cs->port.count)
+		tty_port_tty_set(&cs->port, NULL);
 
 	mutex_unlock(&cs->mutex);
 
@@ -211,18 +199,12 @@ static void if_close(struct tty_struct *tty, struct file *filp)
 static int if_ioctl(struct tty_struct *tty,
 		    unsigned int cmd, unsigned long arg)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval = -ENODEV;
 	int int_arg;
 	unsigned char buf[6];
 	unsigned version[4];
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
 
 	if (mutex_lock_interruptible(&cs->mutex))
@@ -231,9 +213,7 @@ static int if_ioctl(struct tty_struct *tty,
 	if (!cs->connected) {
 		gig_dbg(DEBUG_IF, "not connected");
 		retval = -ENODEV;
-	} else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-	else {
+	} else {
 		retval = 0;
 		switch (cmd) {
 		case GIGASET_REDIR:
@@ -285,15 +265,9 @@ static int if_ioctl(struct tty_struct *tty,
 
 static int if_tiocmget(struct tty_struct *tty)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	if (mutex_lock_interruptible(&cs->mutex))
@@ -309,16 +283,10 @@ static int if_tiocmget(struct tty_struct *tty)
 static int if_tiocmset(struct tty_struct *tty,
 		       unsigned int set, unsigned int clear)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval;
 	unsigned mc;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
 		cs->minor_index, __func__, set, clear);
 
@@ -341,16 +309,10 @@ static int if_tiocmset(struct tty_struct *tty,
 
 static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	struct cmdbuf_t *cb;
 	int retval;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	if (mutex_lock_interruptible(&cs->mutex))
@@ -361,11 +323,6 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
 		retval = -ENODEV;
 		goto done;
 	}
-	if (!cs->open_count) {
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-		retval = -ENODEV;
-		goto done;
-	}
 	if (cs->mstate != MS_LOCKED) {
 		dev_warn(cs->dev, "can't write to unlocked device\n");
 		retval = -EBUSY;
@@ -397,15 +354,9 @@ done:
 
 static int if_write_room(struct tty_struct *tty)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval = -ENODEV;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return -ENODEV;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	if (mutex_lock_interruptible(&cs->mutex))
@@ -414,9 +365,7 @@ static int if_write_room(struct tty_struct *tty)
 	if (!cs->connected) {
 		gig_dbg(DEBUG_IF, "not connected");
 		retval = -ENODEV;
-	} else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-	else if (cs->mstate != MS_LOCKED) {
+	} else if (cs->mstate != MS_LOCKED) {
 		dev_warn(cs->dev, "can't write to unlocked device\n");
 		retval = -EBUSY;
 	} else
@@ -429,23 +378,15 @@ static int if_write_room(struct tty_struct *tty)
 
 static int if_chars_in_buffer(struct tty_struct *tty)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	int retval = 0;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return 0;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	mutex_lock(&cs->mutex);
 
 	if (!cs->connected)
 		gig_dbg(DEBUG_IF, "not connected");
-	else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
 	else if (cs->mstate != MS_LOCKED)
 		dev_warn(cs->dev, "can't write to unlocked device\n");
 	else
@@ -458,13 +399,7 @@ static int if_chars_in_buffer(struct tty_struct *tty)
 
 static void if_throttle(struct tty_struct *tty)
 {
-	struct cardstate *cs;
-
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return;
-	}
+	struct cardstate *cs = tty->driver_data;
 
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
@@ -472,8 +407,6 @@ static void if_throttle(struct tty_struct *tty)
 
 	if (!cs->connected)
 		gig_dbg(DEBUG_IF, "not connected");	/* nothing to do */
-	else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
 	else
 		gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
 
@@ -482,13 +415,7 @@ static void if_throttle(struct tty_struct *tty)
 
 static void if_unthrottle(struct tty_struct *tty)
 {
-	struct cardstate *cs;
-
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return;
-	}
+	struct cardstate *cs = tty->driver_data;
 
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
@@ -496,8 +423,6 @@ static void if_unthrottle(struct tty_struct *tty)
 
 	if (!cs->connected)
 		gig_dbg(DEBUG_IF, "not connected");	/* nothing to do */
-	else if (!cs->open_count)
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
 	else
 		gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
 
@@ -506,18 +431,12 @@ static void if_unthrottle(struct tty_struct *tty)
 
 static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
-	struct cardstate *cs;
+	struct cardstate *cs = tty->driver_data;
 	unsigned int iflag;
 	unsigned int cflag;
 	unsigned int old_cflag;
 	unsigned int control_state, new_state;
 
-	cs = (struct cardstate *) tty->driver_data;
-	if (!cs) {
-		pr_err("%s: no cardstate\n", __func__);
-		return;
-	}
-
 	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
 
 	mutex_lock(&cs->mutex);
@@ -527,11 +446,6 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
 		goto out;
 	}
 
-	if (!cs->open_count) {
-		dev_warn(cs->dev, "%s: device not opened\n", __func__);
-		goto out;
-	}
-
 	iflag = tty->termios->c_iflag;
 	cflag = tty->termios->c_cflag;
 	old_cflag = old ? old->c_cflag : cflag;
@@ -588,10 +502,13 @@ out:
 /* wakeup tasklet for the write operation */
 static void if_wake(unsigned long data)
 {
-	struct cardstate *cs = (struct cardstate *) data;
+	struct cardstate *cs = (struct cardstate *)data;
+	struct tty_struct *tty = tty_port_tty_get(&cs->port);
 
-	if (cs->tty)
-		tty_wakeup(cs->tty);
+	if (tty) {
+		tty_wakeup(tty);
+		tty_kref_put(tty);
+	}
 }
 
 /*** interface to common ***/
@@ -644,18 +561,16 @@ void gigaset_if_free(struct cardstate *cs)
 void gigaset_if_receive(struct cardstate *cs,
 			unsigned char *buffer, size_t len)
 {
-	unsigned long flags;
-	struct tty_struct *tty;
+	struct tty_struct *tty = tty_port_tty_get(&cs->port);
 
-	spin_lock_irqsave(&cs->lock, flags);
-	tty = cs->tty;
-	if (tty == NULL)
+	if (tty == NULL) {
 		gig_dbg(DEBUG_IF, "receive on closed device");
-	else {
-		tty_insert_flip_string(tty, buffer, len);
-		tty_flip_buffer_push(tty);
+		return;
 	}
-	spin_unlock_irqrestore(&cs->lock, flags);
+
+	tty_insert_flip_string(tty, buffer, len);
+	tty_flip_buffer_push(tty);
+	tty_kref_put(tty);
 }
 EXPORT_SYMBOL_GPL(gigaset_if_receive);
 
@@ -669,17 +584,15 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive);
 void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
 			   const char *devname)
 {
-	unsigned minors = drv->minors;
 	int ret;
 	struct tty_driver *tty;
 
 	drv->have_tty = 0;
 
-	drv->tty = tty = alloc_tty_driver(minors);
+	drv->tty = tty = alloc_tty_driver(drv->minors);
 	if (tty == NULL)
 		goto enomem;
 
-	tty->magic =		TTY_DRIVER_MAGIC,
 	tty->type =		TTY_DRIVER_TYPE_SERIAL,
 	tty->subtype =		SERIAL_TYPE_NORMAL,
 	tty->flags =		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
@@ -687,9 +600,6 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
 	tty->driver_name =	procname;
 	tty->name =		devname;
 	tty->minor_start =	drv->minor;
-	tty->num =		drv->minors;
-
-	tty->owner =		THIS_MODULE;
 
 	tty->init_termios          = tty_std_termios;
 	tty->init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;

+ 2 - 5
drivers/isdn/i4l/isdn_tty.c

@@ -1590,12 +1590,9 @@ static int
 isdn_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	modem_info *info;
-	int retval, line;
+	int retval;
 
-	line = tty->index;
-	if (line < 0 || line >= ISDN_MAX_CHANNELS)
-		return -ENODEV;
-	info = &dev->mdm.info[line];
+	info = &dev->mdm.info[tty->index];
 	if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
 		return -ENODEV;
 	if (!try_module_get(info->owner)) {

+ 2 - 10
drivers/misc/pti.c

@@ -481,13 +481,9 @@ static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
 	int idx = tty->index;
 	struct pti_tty *pti_tty_data;
-	int ret = tty_init_termios(tty);
+	int ret = tty_standard_install(driver, tty);
 
 	if (ret == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
-		driver->ttys[idx] = tty;
-
 		pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL);
 		if (pti_tty_data == NULL)
 			return -ENOMEM;
@@ -911,21 +907,17 @@ static int __init pti_init(void)
 
 	/* First register module as tty device */
 
-	pti_tty_driver = alloc_tty_driver(1);
+	pti_tty_driver = alloc_tty_driver(PTITTY_MINOR_NUM);
 	if (pti_tty_driver == NULL) {
 		pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n",
 			__func__, __LINE__);
 		return -ENOMEM;
 	}
 
-	pti_tty_driver->owner			= THIS_MODULE;
-	pti_tty_driver->magic			= TTY_DRIVER_MAGIC;
 	pti_tty_driver->driver_name		= DRIVERNAME;
 	pti_tty_driver->name			= TTYNAME;
 	pti_tty_driver->major			= 0;
 	pti_tty_driver->minor_start		= PTITTY_MINOR_START;
-	pti_tty_driver->minor_num		= PTITTY_MINOR_NUM;
-	pti_tty_driver->num			= PTITTY_MINOR_NUM;
 	pti_tty_driver->type			= TTY_DRIVER_TYPE_SYSTEM;
 	pti_tty_driver->subtype			= SYSTEM_TYPE_SYSCONS;
 	pti_tty_driver->flags			= TTY_DRIVER_REAL_RAW |

+ 3 - 7
drivers/mmc/card/sdio_uart.c

@@ -750,15 +750,12 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
 {
 	int idx = tty->index;
 	struct sdio_uart_port *port = sdio_uart_port_get(idx);
-	int ret = tty_init_termios(tty);
+	int ret = tty_standard_install(driver, tty);
 
-	if (ret == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
+	if (ret == 0)
 		/* This is the ref sdio_uart_port get provided */
 		tty->driver_data = port;
-		driver->ttys[idx] = tty;
-	} else
+	else
 		sdio_uart_port_put(port);
 	return ret;
 }
@@ -1178,7 +1175,6 @@ static int __init sdio_uart_init(void)
 	if (!tty_drv)
 		return -ENOMEM;
 
-	tty_drv->owner = THIS_MODULE;
 	tty_drv->driver_name = "sdio_uart";
 	tty_drv->name =   "ttySDIO";
 	tty_drv->major = 0;  /* dynamically allocated */

+ 0 - 2
drivers/net/usb/hso.c

@@ -3313,7 +3313,6 @@ static int __init hso_init(void)
 
 	/* fill in all needed values */
 	tty_drv->magic = TTY_DRIVER_MAGIC;
-	tty_drv->owner = THIS_MODULE;
 	tty_drv->driver_name = driver_name;
 	tty_drv->name = tty_filename;
 
@@ -3322,7 +3321,6 @@ static int __init hso_init(void)
 		tty_drv->major = tty_major;
 
 	tty_drv->minor_start = 0;
-	tty_drv->num = HSO_SERIAL_TTY_MINORS;
 	tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
 	tty_drv->subtype = SERIAL_TYPE_NORMAL;
 	tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;

+ 2 - 11
drivers/net/wan/pc300_drv.c

@@ -299,7 +299,6 @@ void cpc_tty_init(pc300dev_t * dev);
 void cpc_tty_unregister_service(pc300dev_t * pc300dev);
 void cpc_tty_receive(pc300dev_t * pc300dev);
 void cpc_tty_trigger_poll(pc300dev_t * pc300dev);
-void cpc_tty_reset_var(void);
 #endif
 
 /************************/
@@ -3232,7 +3231,7 @@ static void plx_init(pc300_t * card)
 
 }
 
-static inline void show_version(void)
+static void show_version(void)
 {
 	char *rcsvers, *rcsdate, *tmp;
 
@@ -3413,19 +3412,10 @@ static void cpc_init_card(pc300_t * card)
 static int __devinit
 cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	static int first_time = 1;
 	int err, eeprom_outdated = 0;
 	u16 device_id;
 	pc300_t *card;
 
-	if (first_time) {
-		first_time = 0;
-		show_version();
-#ifdef CONFIG_PC300_MLPPP
-		cpc_tty_reset_var();
-#endif
-	}
-
 	if ((err = pci_enable_device(pdev)) < 0)
 		return err;
 
@@ -3661,6 +3651,7 @@ static struct pci_driver cpc_driver = {
 
 static int __init cpc_init(void)
 {
+	show_version();
 	return pci_register_driver(&cpc_driver);
 }
 

+ 0 - 18
drivers/net/wan/pc300_tty.c

@@ -139,7 +139,6 @@ void cpc_tty_init(pc300dev_t *dev);
 void cpc_tty_unregister_service(pc300dev_t *pc300dev);
 void cpc_tty_receive(pc300dev_t *pc300dev);
 void cpc_tty_trigger_poll(pc300dev_t *pc300dev);
-void cpc_tty_reset_var(void);
 
 /*
  * PC300 TTY clear "signal"
@@ -1078,20 +1077,3 @@ void cpc_tty_trigger_poll(pc300dev_t *pc300dev)
 	}
 	schedule_work(&(cpc_tty->tty_tx_work)); 
 } 
-
-/*
- * PC300 TTY reset var routine
- * This routine is called by pc300driver to init the TTY area. 
- */
-
-void cpc_tty_reset_var(void)
-{
-	int i ; 
-
-	CPC_TTY_DBG("hdlcX-tty: reset variables\n");
-	/* reset  the tty_driver structure - serial_drv */ 
-	memset(&serial_drv, 0, sizeof(struct tty_driver));
-	for (i=0; i < CPC_TTY_NPORTS; i++){
-		memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area)); 
-	}
-}

+ 2 - 7
drivers/s390/char/con3215.c

@@ -933,13 +933,9 @@ console_initcall(con3215_init);
 static int tty3215_open(struct tty_struct *tty, struct file * filp)
 {
 	struct raw3215_info *raw;
-	int retval, line;
+	int retval;
 
-	line = tty->index;
-	if ((line < 0) || (line >= NR_3215))
-		return -ENODEV;
-
-	raw = raw3215[line];
+	raw = raw3215[tty->index];
 	if (raw == NULL)
 		return -ENODEV;
 
@@ -1145,7 +1141,6 @@ static int __init tty3215_init(void)
 	 * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
 	 */
 
-	driver->owner = THIS_MODULE;
 	driver->driver_name = "tty3215";
 	driver->name = "ttyS";
 	driver->major = TTY_MAJOR;

+ 0 - 1
drivers/s390/char/sclp_tty.c

@@ -551,7 +551,6 @@ sclp_tty_init(void)
 		return rc;
 	}
 
-	driver->owner = THIS_MODULE;
 	driver->driver_name = "sclp_line";
 	driver->name = "sclp_line";
 	driver->major = TTY_MAJOR;

+ 0 - 1
drivers/s390/char/sclp_vt220.c

@@ -685,7 +685,6 @@ static int __init sclp_vt220_tty_init(void)
 	if (rc)
 		goto out_driver;
 
-	driver->owner = THIS_MODULE;
 	driver->driver_name = SCLP_VT220_DRIVER_NAME;
 	driver->name = SCLP_VT220_DEVICE_NAME;
 	driver->major = SCLP_VT220_MAJOR;

+ 0 - 1
drivers/s390/char/tty3270.c

@@ -1784,7 +1784,6 @@ static int __init tty3270_init(void)
 	 * Entries in tty3270_driver that are NOT initialized:
 	 * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
 	 */
-	driver->owner = THIS_MODULE;
 	driver->driver_name = "ttyTUB";
 	driver->name = "ttyTUB";
 	driver->major = IBM_TTY3270_MAJOR;

+ 4 - 4
drivers/staging/speakup/main.c

@@ -1731,15 +1731,15 @@ static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
 	switch (value) {
 	case KVAL(K_CAPS):
 		label = msg_get(MSG_KEYNAME_CAPSLOCK);
-		on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK));
+		on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
 		break;
 	case KVAL(K_NUM):
 		label = msg_get(MSG_KEYNAME_NUMLOCK);
-		on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK));
+		on_off = vt_get_leds(fg_console, VC_NUMLOCK);
 		break;
 	case KVAL(K_HOLD):
 		label = msg_get(MSG_KEYNAME_SCROLLLOCK);
-		on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK));
+		on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
 		if (speakup_console[vc->vc_num])
 			speakup_console[vc->vc_num]->tty_stopped = on_off;
 		break;
@@ -2020,7 +2020,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
 	if (type >= 0xf0)
 		type -= 0xf0;
 	if (type == KT_PAD
-		&& (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) {
+		&& (vt_get_leds(fg_console, VC_NUMLOCK))) {
 		if (up_flag) {
 			spk_keydown = 0;
 			goto out;

+ 5 - 6
drivers/staging/speakup/serialio.c

@@ -8,21 +8,20 @@
 
 static void start_serial_interrupt(int irq);
 
-static struct serial_state rs_table[] = {
+static const struct old_serial_port rs_table[] = {
 	SERIAL_PORT_DFNS
 };
-static struct serial_state *serstate;
+static const struct old_serial_port *serstate;
 static int timeouts;
 
-struct serial_state *spk_serial_init(int index)
+const struct old_serial_port *spk_serial_init(int index)
 {
 	int baud = 9600, quot = 0;
 	unsigned int cval = 0;
 	int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
-	struct serial_state *ser = NULL;
+	const struct old_serial_port *ser = rs_table + index;
 	int err;
 
-	ser = rs_table + index;
 	/*	Divisor, bytesize and parity */
 	quot = ser->baud_base / baud;
 	cval = cflag & (CSIZE | CSTOPB);
@@ -41,7 +40,7 @@ struct serial_state *spk_serial_init(int index)
 		__release_region(&ioport_resource, ser->port, 8);
 		err = synth_request_region(ser->port, 8);
 		if (err) {
-			pr_warn("Unable to allocate port at %lx, errno %i",
+			pr_warn("Unable to allocate port at %x, errno %i",
 				ser->port, err);
 			return NULL;
 		}

+ 12 - 1
drivers/staging/speakup/serialio.h

@@ -4,11 +4,22 @@
 #include <linux/serial.h>	/* for rs_table, serial constants &
 				   serial_uart_config */
 #include <linux/serial_reg.h>	/* for more serial constants */
-#include <linux/serialP.h>	/* for struct serial_state */
 #ifndef __sparc__
 #include <asm/serial.h>
 #endif
 
+/*
+ * this is cut&paste from 8250.h. Get rid of the structure, the definitions
+ * and this whole broken driver.
+ */
+struct old_serial_port {
+	unsigned int uart; /* unused */
+	unsigned int baud_base;
+	unsigned int port;
+	unsigned int irq;
+	unsigned int flags; /* unused */
+};
+
 /* countdown values for serial timeouts in us */
 #define SPK_SERIAL_TIMEOUT 100000
 /* countdown values transmitter/dsr timeouts in us */

+ 1 - 1
drivers/staging/speakup/spk_priv.h

@@ -44,7 +44,7 @@
 
 #define KT_SPKUP 15
 
-extern struct serial_state *spk_serial_init(int index);
+extern const struct old_serial_port *spk_serial_init(int index);
 extern void stop_serial_interrupt(void);
 extern int wait_for_xmitr(void);
 extern unsigned char spk_serial_in(void);

+ 1 - 1
drivers/staging/speakup/synth.c

@@ -34,7 +34,7 @@ static int do_synth_init(struct spk_synth *in_synth);
 
 int serial_synth_probe(struct spk_synth *synth)
 {
-	struct serial_state *ser;
+	const struct old_serial_port *ser;
 	int failed = 0;
 
 	if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) {

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 167 - 262
drivers/tty/amiserial.c


+ 0 - 1
drivers/tty/bfin_jtag_comm.c

@@ -257,7 +257,6 @@ static int __init bfin_jc_init(void)
 	if (!bfin_jc_driver)
 		goto err_driver;
 
-	bfin_jc_driver->owner        = THIS_MODULE;
 	bfin_jc_driver->driver_name  = DRV_NAME;
 	bfin_jc_driver->name         = DEV_NAME;
 	bfin_jc_driver->type         = TTY_DRIVER_TYPE_SERIAL;

+ 2 - 7
drivers/tty/cyclades.c

@@ -1515,13 +1515,9 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
 static int cy_open(struct tty_struct *tty, struct file *filp)
 {
 	struct cyclades_port *info;
-	unsigned int i, line;
+	unsigned int i, line = tty->index;
 	int retval;
 
-	line = tty->index;
-	if (tty->index < 0 || NR_PORTS <= line)
-		return -ENODEV;
-
 	for (i = 0; i < NR_CARDS; i++)
 		if (line < cy_card[i].first_line + cy_card[i].nports &&
 				line >= cy_card[i].first_line)
@@ -2413,7 +2409,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
 		/* Not supported yet */
 		return -EINVAL;
 	}
-	return put_user(result, (unsigned long __user *)value);
+	return put_user(result, value);
 }
 
 static int cy_tiocmget(struct tty_struct *tty)
@@ -4090,7 +4086,6 @@ static int __init cy_init(void)
 
 	/* Initialize the tty_driver structure */
 
-	cy_serial_driver->owner = THIS_MODULE;
 	cy_serial_driver->driver_name = "cyclades";
 	cy_serial_driver->name = "ttyC";
 	cy_serial_driver->major = CYCLADES_MAJOR;

+ 0 - 1
drivers/tty/ehv_bytechan.c

@@ -825,7 +825,6 @@ static int __init ehv_bc_init(void)
 		goto error;
 	}
 
-	ehv_bc_driver->owner = THIS_MODULE;
 	ehv_bc_driver->driver_name = "ehv-bc";
 	ehv_bc_driver->name = ehv_bc_console.name;
 	ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE;

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

@@ -113,7 +113,7 @@ static int __init hvc_beat_init(void)
 	if (!firmware_has_feature(FW_FEATURE_BEAT))
 		return -ENODEV;
 
-	hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
+	hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
 	hvc_beat_dev = hp;

+ 0 - 1
drivers/tty/hvc/hvc_console.c

@@ -917,7 +917,6 @@ static int hvc_init(void)
 		goto out;
 	}
 
-	drv->owner = THIS_MODULE;
 	drv->driver_name = "hvc";
 	drv->name = "hvc";
 	drv->major = HVC_MAJOR;

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

@@ -94,7 +94,7 @@ static int __init hvc_rtas_init(void)
 
 	/* Allocate an hvc_struct for the console device we instantiated
 	 * earlier.  Save off hp so that we can return it on exit */
-	hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16);
+	hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
 

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

@@ -69,7 +69,7 @@ static int __init hvc_udbg_init(void)
 
 	BUG_ON(hvc_udbg_dev);
 
-	hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
+	hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
 

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

@@ -176,7 +176,7 @@ static int __init xen_hvc_init(void)
 		xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
 	}
 	if (xencons_irq < 0)
-		xencons_irq = 0; /* NO_IRQ */
+		xencons_irq = 0;
 	else
 		irq_set_noprobe(xencons_irq);
 

+ 12 - 18
drivers/tty/hvc/hvcs.c

@@ -1090,27 +1090,23 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
  */
 static struct hvcs_struct *hvcs_get_by_index(int index)
 {
-	struct hvcs_struct *hvcsd = NULL;
+	struct hvcs_struct *hvcsd;
 	unsigned long flags;
 
 	spin_lock(&hvcs_structs_lock);
-	/* We can immediately discard OOB requests */
-	if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) {
-		list_for_each_entry(hvcsd, &hvcs_structs, next) {
-			spin_lock_irqsave(&hvcsd->lock, flags);
-			if (hvcsd->index == index) {
-				kref_get(&hvcsd->kref);
-				spin_unlock_irqrestore(&hvcsd->lock, flags);
-				spin_unlock(&hvcs_structs_lock);
-				return hvcsd;
-			}
+	list_for_each_entry(hvcsd, &hvcs_structs, next) {
+		spin_lock_irqsave(&hvcsd->lock, flags);
+		if (hvcsd->index == index) {
+			kref_get(&hvcsd->kref);
 			spin_unlock_irqrestore(&hvcsd->lock, flags);
+			spin_unlock(&hvcs_structs_lock);
+			return hvcsd;
 		}
-		hvcsd = NULL;
+		spin_unlock_irqrestore(&hvcsd->lock, flags);
 	}
-
 	spin_unlock(&hvcs_structs_lock);
-	return hvcsd;
+
+	return NULL;
 }
 
 /*
@@ -1203,7 +1199,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
 {
 	struct hvcs_struct *hvcsd;
 	unsigned long flags;
-	int irq = NO_IRQ;
+	int irq;
 
 	/*
 	 * Is someone trying to close the file associated with this device after
@@ -1264,7 +1260,7 @@ static void hvcs_hangup(struct tty_struct * tty)
 	struct hvcs_struct *hvcsd = tty->driver_data;
 	unsigned long flags;
 	int temp_open_count;
-	int irq = NO_IRQ;
+	int irq;
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
 	/* Preserve this so that we know how many kref refs to put */
@@ -1499,8 +1495,6 @@ static int __devinit hvcs_initialize(void)
 		goto index_fail;
 	}
 
-	hvcs_tty_driver->owner = THIS_MODULE;
-
 	hvcs_tty_driver->driver_name = hvcs_driver_name;
 	hvcs_tty_driver->name = hvcs_device_node;
 

+ 2 - 6
drivers/tty/hvc/hvsi.c

@@ -737,14 +737,11 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
 {
 	struct hvsi_struct *hp;
 	unsigned long flags;
-	int line = tty->index;
 	int ret;
 
 	pr_debug("%s\n", __func__);
 
-	if (line < 0 || line >= hvsi_count)
-		return -ENODEV;
-	hp = &hvsi_ports[line];
+	hp = &hvsi_ports[tty->index];
 
 	tty->driver_data = hp;
 
@@ -1088,7 +1085,6 @@ static int __init hvsi_init(void)
 	if (!hvsi_driver)
 		return -ENOMEM;
 
-	hvsi_driver->owner = THIS_MODULE;
 	hvsi_driver->driver_name = "hvsi";
 	hvsi_driver->name = "hvsi";
 	hvsi_driver->major = HVSI_MAJOR;
@@ -1237,7 +1233,7 @@ static int __init hvsi_console_init(void)
 		hp->state = HVSI_CLOSED;
 		hp->vtermno = *vtermno;
 		hp->virq = irq_create_mapping(NULL, irq[0]);
-		if (hp->virq == NO_IRQ) {
+		if (hp->virq == 0) {
 			printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
 				__func__, irq[0]);
 			continue;

+ 13 - 24
drivers/tty/ipwireless/tty.c

@@ -90,33 +90,23 @@ static void report_deregistering(struct ipw_tty *tty)
 	       tty->index);
 }
 
-static struct ipw_tty *get_tty(int minor)
+static struct ipw_tty *get_tty(int index)
 {
-	if (minor < ipw_tty_driver->minor_start
-			|| minor >= ipw_tty_driver->minor_start +
-			IPWIRELESS_PCMCIA_MINORS)
+	/*
+	 * The 'ras_raw' channel is only available when 'loopback' mode
+	 * is enabled.
+	 * Number of minor starts with 16 (_RANGE * _RAS_RAW).
+	 */
+	if (!ipwireless_loopback && index >=
+			 IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
 		return NULL;
-	else {
-		int minor_offset = minor - ipw_tty_driver->minor_start;
-
-		/*
-		 * The 'ras_raw' channel is only available when 'loopback' mode
-		 * is enabled.
-		 * Number of minor starts with 16 (_RANGE * _RAS_RAW).
-		 */
-		if (!ipwireless_loopback &&
-				minor_offset >=
-				 IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
-			return NULL;
-
-		return ttys[minor_offset];
-	}
+
+	return ttys[index];
 }
 
 static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
 {
-	int minor = linux_tty->index;
-	struct ipw_tty *tty = get_tty(minor);
+	struct ipw_tty *tty = get_tty(linux_tty->index);
 
 	if (!tty)
 		return -ENODEV;
@@ -510,7 +500,7 @@ static int add_tty(int j,
 		ipwireless_associate_network_tty(network,
 						 secondary_channel_idx,
 						 ttys[j]);
-	if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j])
+	if (get_tty(j) == ttys[j])
 		report_registering(ttys[j]);
 	return 0;
 }
@@ -570,7 +560,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)
 
 		if (ttyj) {
 			mutex_lock(&ttyj->ipw_tty_mutex);
-			if (get_tty(j + ipw_tty_driver->minor_start) == ttyj)
+			if (get_tty(j) == ttyj)
 				report_deregistering(ttyj);
 			ttyj->closing = 1;
 			if (ttyj->linux_tty != NULL) {
@@ -614,7 +604,6 @@ int ipwireless_tty_init(void)
 	if (!ipw_tty_driver)
 		return -ENOMEM;
 
-	ipw_tty_driver->owner = THIS_MODULE;
 	ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
 	ipw_tty_driver->name = "ttyIPWp";
 	ipw_tty_driver->major = 0;

+ 0 - 3
drivers/tty/isicom.c

@@ -849,8 +849,6 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty)
 	unsigned int board;
 	int line = tty->index;
 
-	if (line < 0 || line > PORT_COUNT-1)
-		return NULL;
 	board = BOARD(line);
 	card = &isi_card[board];
 
@@ -1678,7 +1676,6 @@ static int __init isicom_init(void)
 		goto error;
 	}
 
-	isicom_normal->owner			= THIS_MODULE;
 	isicom_normal->name 			= "ttyM";
 	isicom_normal->major			= ISICOM_NMAJOR;
 	isicom_normal->minor_start		= 0;

+ 1 - 2
drivers/tty/moxa.c

@@ -1036,7 +1036,6 @@ static int __init moxa_init(void)
 	if (!moxaDriver)
 		return -ENOMEM;
 
-	moxaDriver->owner = THIS_MODULE;
 	moxaDriver->name = "ttyMX";
 	moxaDriver->major = ttymajor;
 	moxaDriver->minor_start = 0;
@@ -1331,7 +1330,7 @@ static void moxa_start(struct tty_struct *tty)
 	if (ch == NULL)
 		return;
 
-	if (!(ch->statusflags & TXSTOPPED))
+	if (!test_bit(TXSTOPPED, &ch->statusflags))
 		return;
 
 	MoxaPortTxEnable(ch);

+ 0 - 5
drivers/tty/mxser.c

@@ -1010,8 +1010,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
 	line = tty->index;
 	if (line == MXSER_PORTS)
 		return 0;
-	if (line < 0 || line > MXSER_PORTS)
-		return -ENODEV;
 	info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
 	if (!info->ioaddr)
 		return -ENODEV;
@@ -2658,12 +2656,9 @@ static int __init mxser_module_init(void)
 		MXSER_VERSION);
 
 	/* Initialize the tty_driver structure */
-	mxvar_sdriver->owner = THIS_MODULE;
-	mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
 	mxvar_sdriver->name = "ttyMI";
 	mxvar_sdriver->major = ttymajor;
 	mxvar_sdriver->minor_start = 0;
-	mxvar_sdriver->num = MXSER_PORTS + 1;
 	mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
 	mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
 	mxvar_sdriver->init_termios = tty_std_termios;

+ 0 - 1
drivers/tty/n_gsm.c

@@ -3120,7 +3120,6 @@ static int __init gsm_init(void)
 		pr_err("gsm_init: tty allocation failed.\n");
 		return -EINVAL;
 	}
-	gsm_tty_driver->owner	= THIS_MODULE;
 	gsm_tty_driver->driver_name	= "gsmtty";
 	gsm_tty_driver->name		= "gsmtty";
 	gsm_tty_driver->major		= 0;	/* Dynamic */

+ 2 - 7
drivers/tty/nozomi.c

@@ -1602,13 +1602,9 @@ static int ntty_install(struct tty_driver *driver, struct tty_struct *tty)
 	int ret;
 	if (!port || !dc || dc->state != NOZOMI_STATE_READY)
 		return -ENODEV;
-	ret = tty_init_termios(tty);
-	if (ret == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
+	ret = tty_standard_install(driver, tty);
+	if (ret == 0)
 		tty->driver_data = port;
-		driver->ttys[tty->index] = tty;
-	}
 	return ret;
 }
 
@@ -1920,7 +1916,6 @@ static __init int nozomi_init(void)
 	if (!ntty_driver)
 		return -ENOMEM;
 
-	ntty_driver->owner = THIS_MODULE;
 	ntty_driver->driver_name = NOZOMI_NAME_TTY;
 	ntty_driver->name = "noz";
 	ntty_driver->major = 0;

+ 3 - 60
drivers/tty/pty.c

@@ -21,7 +21,6 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/init.h>
-#include <linux/sysctl.h>
 #include <linux/device.h>
 #include <linux/uaccess.h>
 #include <linux/bitops.h>
@@ -394,7 +393,6 @@ static void __init legacy_pty_init(void)
 	if (!pty_slave_driver)
 		panic("Couldn't allocate pty slave driver");
 
-	pty_driver->owner = THIS_MODULE;
 	pty_driver->driver_name = "pty_master";
 	pty_driver->name = "pty";
 	pty_driver->major = PTY_MASTER_MAJOR;
@@ -412,7 +410,6 @@ static void __init legacy_pty_init(void)
 	pty_driver->other = pty_slave_driver;
 	tty_set_operations(pty_driver, &master_pty_ops_bsd);
 
-	pty_slave_driver->owner = THIS_MODULE;
 	pty_slave_driver->driver_name = "pty_slave";
 	pty_slave_driver->name = "ttyp";
 	pty_slave_driver->major = PTY_SLAVE_MAJOR;
@@ -439,55 +436,9 @@ static inline void legacy_pty_init(void) { }
 
 /* Unix98 devices */
 #ifdef CONFIG_UNIX98_PTYS
-/*
- * sysctl support for setting limits on the number of Unix98 ptys allocated.
- * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
- */
-int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min;
-static int pty_limit_max = NR_UNIX98_PTY_MAX;
-static int pty_count;
 
 static struct cdev ptmx_cdev;
 
-static struct ctl_table pty_table[] = {
-	{
-		.procname	= "max",
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.data		= &pty_limit,
-		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &pty_limit_min,
-		.extra2		= &pty_limit_max,
-	}, {
-		.procname	= "nr",
-		.maxlen		= sizeof(int),
-		.mode		= 0444,
-		.data		= &pty_count,
-		.proc_handler	= proc_dointvec,
-	}, 
-	{}
-};
-
-static struct ctl_table pty_kern_table[] = {
-	{
-		.procname	= "pty",
-		.mode		= 0555,
-		.child		= pty_table,
-	},
-	{}
-};
-
-static struct ctl_table pty_root_table[] = {
-	{
-		.procname	= "kernel",
-		.mode		= 0555,
-		.child		= pty_kern_table,
-	},
-	{}
-};
-
-
 static int pty_unix98_ioctl(struct tty_struct *tty,
 			    unsigned int cmd, unsigned long arg)
 {
@@ -515,10 +466,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
 static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
 		struct inode *ptm_inode, int idx)
 {
-	struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
-	if (tty)
-		tty = tty->link;
-	return tty;
+	/* Master must be open via /dev/ptmx */
+	return ERR_PTR(-EIO);
 }
 
 /**
@@ -589,7 +538,6 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
 	 */
 	tty_driver_kref_get(driver);
 	tty->count++;
-	pty_count++;
 	return 0;
 err_free_mem:
 	deinitialize_tty_struct(o_tty);
@@ -603,7 +551,6 @@ err_free_tty:
 
 static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
 {
-	pty_count--;
 }
 
 static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
@@ -677,7 +624,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 
 	mutex_lock(&tty_mutex);
 	tty_lock();
-	tty = tty_init_dev(ptm_driver, index, 1);
+	tty = tty_init_dev(ptm_driver, index);
 	mutex_unlock(&tty_mutex);
 
 	if (IS_ERR(tty)) {
@@ -722,7 +669,6 @@ static void __init unix98_pty_init(void)
 	if (!pts_driver)
 		panic("Couldn't allocate Unix98 pts driver");
 
-	ptm_driver->owner = THIS_MODULE;
 	ptm_driver->driver_name = "pty_master";
 	ptm_driver->name = "ptm";
 	ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
@@ -741,7 +687,6 @@ static void __init unix98_pty_init(void)
 	ptm_driver->other = pts_driver;
 	tty_set_operations(ptm_driver, &ptm_unix98_ops);
 
-	pts_driver->owner = THIS_MODULE;
 	pts_driver->driver_name = "pty_slave";
 	pts_driver->name = "pts";
 	pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
@@ -762,8 +707,6 @@ static void __init unix98_pty_init(void)
 	if (tty_register_driver(pts_driver))
 		panic("Couldn't register Unix98 pts driver");
 
-	register_sysctl_table(pty_root_table);
-
 	/* Now create the /dev/ptmx special device */
 	tty_default_fops(&ptmx_fops);
 	ptmx_fops.open = ptmx_open;

+ 3 - 4
drivers/tty/rocket.c

@@ -892,12 +892,12 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
 {
 	struct r_port *info;
 	struct tty_port *port;
-	int line = 0, retval;
+	int retval;
 	CHANNEL_t *cp;
 	unsigned long page;
 
-	line = tty->index;
-	if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL))
+	info = rp_table[tty->index];
+	if (info == NULL)
 		return -ENXIO;
 	port = &info->port;
 	
@@ -2277,7 +2277,6 @@ static int __init rp_init(void)
 	 * driver with the tty layer.
 	 */
 
-	rocket_driver->owner = THIS_MODULE;
 	rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
 	rocket_driver->name = "ttyR";
 	rocket_driver->driver_name = "Comtrol RocketPort";

+ 2 - 2
drivers/tty/serial/21285.c

@@ -331,7 +331,7 @@ static int serial21285_verify_port(struct uart_port *port, struct serial_struct
 	int ret = 0;
 	if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
 		ret = -EINVAL;
-	if (ser->irq != NO_IRQ)
+	if (ser->irq <= 0)
 		ret = -EINVAL;
 	if (ser->baud_base != port->uartclk / 16)
 		ret = -EINVAL;
@@ -360,7 +360,7 @@ static struct uart_ops serial21285_ops = {
 static struct uart_port serial21285_port = {
 	.mapbase	= 0x42000160,
 	.iotype		= UPIO_MEM,
-	.irq		= NO_IRQ,
+	.irq		= 0,
 	.fifosize	= 16,
 	.ops		= &serial21285_ops,
 	.flags		= UPF_BOOT_AUTOCONF,

+ 2 - 7
drivers/tty/serial/68328serial.c

@@ -1190,14 +1190,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 int rs_open(struct tty_struct *tty, struct file * filp)
 {
 	struct m68k_serial	*info;
-	int 			retval, line;
-
-	line = tty->index;
-	
-	if (line >= NR_PORTS || line < 0) /* we have exactly one */
-		return -ENODEV;
+	int retval;
 
-	info = &m68k_soft[line];
+	info = &m68k_soft[tty->index];
 
 	if (serial_paranoia_check(info, tty->name, "rs_open"))
 		return -ENODEV;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 206 - 228
drivers/tty/serial/8250/8250.c


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

@@ -86,6 +86,16 @@ struct serial8250_config {
 #define SERIAL8250_SHARE_IRQS 0
 #endif
 
+static inline int serial_in(struct uart_8250_port *up, int offset)
+{
+	return up->port.serial_in(&up->port, offset);
+}
+
+static inline void serial_out(struct uart_8250_port *up, int offset, int value)
+{
+	up->port.serial_out(&up->port, offset, value);
+}
+
 #if defined(__alpha__) && !defined(CONFIG_PCI)
 /*
  * Digital did something really horribly wrong with the OUT1 and OUT2

+ 13 - 0
drivers/tty/serial/Kconfig

@@ -1347,4 +1347,17 @@ config SERIAL_AR933X_NR_UARTS
 	  Set this to the number of serial ports you want the driver
 	  to support.
 
+config SERIAL_EFM32_UART
+	tristate "EFM32 UART/USART port."
+	depends on ARCH_EFM32
+	select SERIAL_CORE
+	help
+	  This driver support the USART and UART ports on
+	  Energy Micro's efm32 SoCs.
+
+config SERIAL_EFM32_UART_CONSOLE
+	bool "EFM32 UART/USART console support"
+	depends on SERIAL_EFM32_UART=y
+	select SERIAL_CORE_CONSOLE
+
 endmenu

+ 2 - 1
drivers/tty/serial/Makefile

@@ -61,12 +61,12 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
 obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
+obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
 obj-$(CONFIG_SERIAL_TIMBERDALE)	+= timbuart.o
 obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
 obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
-obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
 obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
@@ -78,3 +78,4 @@ obj-$(CONFIG_SERIAL_LANTIQ)	+= lantiq.o
 obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
 obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
 obj-$(CONFIG_SERIAL_AR933X)   += ar933x_uart.o
+obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o

+ 24 - 23
drivers/tty/serial/altera_uart.c

@@ -377,6 +377,26 @@ static int altera_uart_verify_port(struct uart_port *port,
 	return 0;
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+static int altera_uart_poll_get_char(struct uart_port *port)
+{
+	while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+		 ALTERA_UART_STATUS_RRDY_MSK))
+		cpu_relax();
+
+	return altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
+}
+
+static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c)
+{
+	while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
+		 ALTERA_UART_STATUS_TRDY_MSK))
+		cpu_relax();
+
+	altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG);
+}
+#endif
+
 /*
  *	Define the basic serial functions we support.
  */
@@ -397,35 +417,16 @@ static struct uart_ops altera_uart_ops = {
 	.release_port	= altera_uart_release_port,
 	.config_port	= altera_uart_config_port,
 	.verify_port	= altera_uart_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_get_char	= altera_uart_poll_get_char,
+	.poll_put_char	= altera_uart_poll_put_char,
+#endif
 };
 
 static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
 
 #if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
 
-int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
-{
-	struct uart_port *port;
-	int i;
-
-	for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
-		port = &altera_uart_ports[i].port;
-
-		port->line = i;
-		port->type = PORT_ALTERA_UART;
-		port->mapbase = platp[i].mapbase;
-		port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
-		port->iotype = SERIAL_IO_MEM;
-		port->irq = platp[i].irq;
-		port->uartclk = platp[i].uartclk;
-		port->flags = UPF_BOOT_AUTOCONF;
-		port->ops = &altera_uart_ops;
-		port->private_data = platp;
-	}
-
-	return 0;
-}
-
 static void altera_uart_console_putc(struct uart_port *port, const char c)
 {
 	while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &

+ 27 - 5
drivers/tty/serial/amba-pl011.c

@@ -827,7 +827,12 @@ static void pl011_dma_rx_callback(void *data)
 {
 	struct uart_amba_port *uap = data;
 	struct pl011_dmarx_data *dmarx = &uap->dmarx;
+	struct dma_chan *rxchan = dmarx->chan;
 	bool lastbuf = dmarx->use_buf_b;
+	struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ?
+		&dmarx->sgbuf_b : &dmarx->sgbuf_a;
+	size_t pending;
+	struct dma_tx_state state;
 	int ret;
 
 	/*
@@ -838,11 +843,21 @@ static void pl011_dma_rx_callback(void *data)
 	 * we immediately trigger the next DMA job.
 	 */
 	spin_lock_irq(&uap->port.lock);
+	/*
+	 * Rx data can be taken by the UART interrupts during
+	 * the DMA irq handler. So we check the residue here.
+	 */
+	rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
+	pending = sgbuf->sg.length - state.residue;
+	BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
+	/* Then we terminate the transfer - we now know our residue */
+	dmaengine_terminate_all(rxchan);
+
 	uap->dmarx.running = false;
 	dmarx->use_buf_b = !lastbuf;
 	ret = pl011_dma_rx_trigger_dma(uap);
 
-	pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false);
+	pl011_dma_rx_chars(uap, pending, lastbuf, false);
 	spin_unlock_irq(&uap->port.lock);
 	/*
 	 * Do this check after we picked the DMA chars so we don't
@@ -1381,6 +1396,10 @@ static int pl011_startup(struct uart_port *port)
 
 	uap->port.uartclk = clk_get_rate(uap->clk);
 
+	/* Clear pending error and receive interrupts */
+	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
+	       UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
+
 	/*
 	 * Allocate the IRQ
 	 */
@@ -1417,10 +1436,6 @@ static int pl011_startup(struct uart_port *port)
 	cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
 	writew(cr, uap->port.membase + UART011_CR);
 
-	/* Clear pending error interrupts */
-	writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
-	       uap->port.membase + UART011_ICR);
-
 	/*
 	 * initialise the old status of the modem signals
 	 */
@@ -1435,6 +1450,9 @@ static int pl011_startup(struct uart_port *port)
 	 * as well.
 	 */
 	spin_lock_irq(&uap->port.lock);
+	/* Clear out any spuriously appearing RX interrupts */
+	 writew(UART011_RTIS | UART011_RXIS,
+		uap->port.membase + UART011_ICR);
 	uap->im = UART011_RTIM;
 	if (!pl011_dma_rx_running(uap))
 		uap->im |= UART011_RXIM;
@@ -1927,6 +1945,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 		goto unmap;
 	}
 
+	/* Ensure interrupts from this UART are masked and cleared */
+	writew(0, uap->port.membase + UART011_IMSC);
+	writew(0xffff, uap->port.membase + UART011_ICR);
+
 	uap->vendor = vendor;
 	uap->lcrh_rx = vendor->lcrh_rx;
 	uap->lcrh_tx = vendor->lcrh_tx;

+ 5 - 3
drivers/tty/serial/bfin_uart.c

@@ -535,11 +535,13 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
 		 *		when start a new tx.
 		 */
 		UART_CLEAR_IER(uart, ETBEI);
-		xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
 		uart->port.icount.tx += uart->tx_count;
+		if (!uart_circ_empty(xmit)) {
+			xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
 
-		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-			uart_write_wakeup(&uart->port);
+			if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+				uart_write_wakeup(&uart->port);
+		}
 
 		bfin_serial_dma_tx_chars(uart);
 	}

+ 3 - 12
drivers/tty/serial/crisv10.c

@@ -4105,20 +4105,11 @@ static int
 rs_open(struct tty_struct *tty, struct file * filp)
 {
 	struct e100_serial	*info;
-	int 			retval, line;
+	int 			retval;
 	unsigned long           page;
 	int                     allocated_resources = 0;
 
-	/* find which port we want to open */
-	line = tty->index;
-
-	if (line < 0 || line >= NR_PORTS)
-		return -ENODEV;
-
-	/* find the corresponding e100_serial struct in the table */
-	info = rs_table + line;
-
-	/* don't allow the opening of ports that are not enabled in the HW config */
+	info = rs_table + tty->index;
 	if (!info->enabled)
 		return -ENODEV;
 
@@ -4131,7 +4122,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
 	tty->driver_data = info;
 	info->port.tty = tty;
 
-	info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
 
 	if (!tmp_buf) {
 		page = get_zeroed_page(GFP_KERNEL);

+ 830 - 0
drivers/tty/serial/efm32-uart.c

@@ -0,0 +1,830 @@
+#if defined(CONFIG_SERIAL_EFM32_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/serial_core.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <linux/platform_data/efm32-uart.h>
+
+#define DRIVER_NAME "efm32-uart"
+#define DEV_NAME "ttyefm"
+
+#define UARTn_CTRL		0x00
+#define UARTn_CTRL_SYNC		0x0001
+#define UARTn_CTRL_TXBIL		0x1000
+
+#define UARTn_FRAME		0x04
+#define UARTn_FRAME_DATABITS__MASK	0x000f
+#define UARTn_FRAME_DATABITS(n)		((n) - 3)
+#define UARTn_FRAME_PARITY_NONE		0x0000
+#define UARTn_FRAME_PARITY_EVEN		0x0200
+#define UARTn_FRAME_PARITY_ODD		0x0300
+#define UARTn_FRAME_STOPBITS_HALF	0x0000
+#define UARTn_FRAME_STOPBITS_ONE	0x1000
+#define UARTn_FRAME_STOPBITS_TWO	0x3000
+
+#define UARTn_CMD		0x0c
+#define UARTn_CMD_RXEN			0x0001
+#define UARTn_CMD_RXDIS		0x0002
+#define UARTn_CMD_TXEN			0x0004
+#define UARTn_CMD_TXDIS		0x0008
+
+#define UARTn_STATUS		0x10
+#define UARTn_STATUS_TXENS		0x0002
+#define UARTn_STATUS_TXC		0x0020
+#define UARTn_STATUS_TXBL		0x0040
+#define UARTn_STATUS_RXDATAV		0x0080
+
+#define UARTn_CLKDIV		0x14
+
+#define UARTn_RXDATAX		0x18
+#define UARTn_RXDATAX_RXDATA__MASK	0x01ff
+#define UARTn_RXDATAX_PERR		0x4000
+#define UARTn_RXDATAX_FERR		0x8000
+/*
+ * This is a software only flag used for ignore_status_mask and
+ * read_status_mask! It's used for breaks that the hardware doesn't report
+ * explicitly.
+ */
+#define SW_UARTn_RXDATAX_BERR		0x2000
+
+#define UARTn_TXDATA		0x34
+
+#define UARTn_IF		0x40
+#define UARTn_IF_TXC			0x0001
+#define UARTn_IF_TXBL			0x0002
+#define UARTn_IF_RXDATAV		0x0004
+#define UARTn_IF_RXOF			0x0010
+
+#define UARTn_IFS		0x44
+#define UARTn_IFC		0x48
+#define UARTn_IEN		0x4c
+
+#define UARTn_ROUTE		0x54
+#define UARTn_ROUTE_LOCATION__MASK	0x0700
+#define UARTn_ROUTE_LOCATION(n)		(((n) << 8) & UARTn_ROUTE_LOCATION__MASK)
+#define UARTn_ROUTE_RXPEN		0x0001
+#define UARTn_ROUTE_TXPEN		0x0002
+
+struct efm32_uart_port {
+	struct uart_port port;
+	unsigned int txirq;
+	struct clk *clk;
+};
+#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port)
+#define efm_debug(efm_port, format, arg...)			\
+	dev_dbg(efm_port->port.dev, format, ##arg)
+
+static void efm32_uart_write32(struct efm32_uart_port *efm_port,
+		u32 value, unsigned offset)
+{
+	writel_relaxed(value, efm_port->port.membase + offset);
+}
+
+static u32 efm32_uart_read32(struct efm32_uart_port *efm_port,
+		unsigned offset)
+{
+	return readl_relaxed(efm_port->port.membase + offset);
+}
+
+static unsigned int efm32_uart_tx_empty(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
+
+	if (status & UARTn_STATUS_TXC)
+		return TIOCSER_TEMT;
+	else
+		return 0;
+}
+
+static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* sorry, neither handshaking lines nor loop functionallity */
+}
+
+static unsigned int efm32_uart_get_mctrl(struct uart_port *port)
+{
+	/* sorry, no handshaking lines available */
+	return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
+}
+
+static void efm32_uart_stop_tx(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	u32 ien = efm32_uart_read32(efm_port,  UARTn_IEN);
+
+	efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
+	ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL);
+	efm32_uart_write32(efm_port, ien, UARTn_IEN);
+}
+
+static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port)
+{
+	struct uart_port *port = &efm_port->port;
+	struct circ_buf *xmit = &port->state->xmit;
+
+	while (efm32_uart_read32(efm_port, UARTn_STATUS) &
+			UARTn_STATUS_TXBL) {
+		if (port->x_char) {
+			port->icount.tx++;
+			efm32_uart_write32(efm_port, port->x_char,
+					UARTn_TXDATA);
+			port->x_char = 0;
+			continue;
+		}
+		if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+			port->icount.tx++;
+			efm32_uart_write32(efm_port, xmit->buf[xmit->tail],
+					UARTn_TXDATA);
+			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		} else
+			break;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (!port->x_char && uart_circ_empty(xmit) &&
+			efm32_uart_read32(efm_port, UARTn_STATUS) &
+				UARTn_STATUS_TXC)
+		efm32_uart_stop_tx(port);
+}
+
+static void efm32_uart_start_tx(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	u32 ien;
+
+	efm32_uart_write32(efm_port,
+			UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC);
+	ien = efm32_uart_read32(efm_port, UARTn_IEN);
+	efm32_uart_write32(efm_port,
+			ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN);
+	efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
+
+	efm32_uart_tx_chars(efm_port);
+}
+
+static void efm32_uart_stop_rx(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+
+	efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD);
+}
+
+static void efm32_uart_enable_ms(struct uart_port *port)
+{
+	/* no handshake lines, no modem status interrupts */
+}
+
+static void efm32_uart_break_ctl(struct uart_port *port, int ctl)
+{
+	/* not possible without fiddling with gpios */
+}
+
+static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port,
+		struct tty_struct *tty)
+{
+	struct uart_port *port = &efm_port->port;
+
+	while (efm32_uart_read32(efm_port, UARTn_STATUS) &
+			UARTn_STATUS_RXDATAV) {
+		u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX);
+		int flag = 0;
+
+		/*
+		 * This is a reserved bit and I only saw it read as 0. But to be
+		 * sure not to be confused too much by new devices adhere to the
+		 * warning in the reference manual that reserverd bits might
+		 * read as 1 in the future.
+		 */
+		rxdata &= ~SW_UARTn_RXDATAX_BERR;
+
+		port->icount.rx++;
+
+		if ((rxdata & UARTn_RXDATAX_FERR) &&
+				!(rxdata & UARTn_RXDATAX_RXDATA__MASK)) {
+			rxdata |= SW_UARTn_RXDATAX_BERR;
+			port->icount.brk++;
+			if (uart_handle_break(port))
+				continue;
+		} else if (rxdata & UARTn_RXDATAX_PERR)
+			port->icount.parity++;
+		else if (rxdata & UARTn_RXDATAX_FERR)
+			port->icount.frame++;
+
+		rxdata &= port->read_status_mask;
+
+		if (rxdata & SW_UARTn_RXDATAX_BERR)
+			flag = TTY_BREAK;
+		else if (rxdata & UARTn_RXDATAX_PERR)
+			flag = TTY_PARITY;
+		else if (rxdata & UARTn_RXDATAX_FERR)
+			flag = TTY_FRAME;
+		else if (uart_handle_sysrq_char(port,
+					rxdata & UARTn_RXDATAX_RXDATA__MASK))
+			continue;
+
+		if (tty && (rxdata & port->ignore_status_mask) == 0)
+			tty_insert_flip_char(tty,
+					rxdata & UARTn_RXDATAX_RXDATA__MASK, flag);
+	}
+}
+
+static irqreturn_t efm32_uart_rxirq(int irq, void *data)
+{
+	struct efm32_uart_port *efm_port = data;
+	u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
+	int handled = IRQ_NONE;
+	struct uart_port *port = &efm_port->port;
+	struct tty_struct *tty;
+
+	spin_lock(&port->lock);
+
+	tty = tty_kref_get(port->state->port.tty);
+
+	if (irqflag & UARTn_IF_RXDATAV) {
+		efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC);
+		efm32_uart_rx_chars(efm_port, tty);
+
+		handled = IRQ_HANDLED;
+	}
+
+	if (irqflag & UARTn_IF_RXOF) {
+		efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC);
+		port->icount.overrun++;
+		if (tty)
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+		handled = IRQ_HANDLED;
+	}
+
+	if (tty) {
+		tty_flip_buffer_push(tty);
+		tty_kref_put(tty);
+	}
+
+	spin_unlock(&port->lock);
+
+	return handled;
+}
+
+static irqreturn_t efm32_uart_txirq(int irq, void *data)
+{
+	struct efm32_uart_port *efm_port = data;
+	u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
+
+	/* TXBL doesn't need to be cleared */
+	if (irqflag & UARTn_IF_TXC)
+		efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC);
+
+	if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) {
+		efm32_uart_tx_chars(efm_port);
+		return IRQ_HANDLED;
+	} else
+		return IRQ_NONE;
+}
+
+static int efm32_uart_startup(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	u32 location = 0;
+	struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev);
+	int ret;
+
+	if (pdata)
+		location = UARTn_ROUTE_LOCATION(pdata->location);
+
+	ret = clk_enable(efm_port->clk);
+	if (ret) {
+		efm_debug(efm_port, "failed to enable clk\n");
+		goto err_clk_enable;
+	}
+	port->uartclk = clk_get_rate(efm_port->clk);
+
+	/* Enable pins at configured location */
+	efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
+			UARTn_ROUTE);
+
+	ret = request_irq(port->irq, efm32_uart_rxirq, 0,
+			DRIVER_NAME, efm_port);
+	if (ret) {
+		efm_debug(efm_port, "failed to register rxirq\n");
+		goto err_request_irq_rx;
+	}
+
+	/* disable all irqs */
+	efm32_uart_write32(efm_port, 0, UARTn_IEN);
+
+	ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0,
+			DRIVER_NAME, efm_port);
+	if (ret) {
+		efm_debug(efm_port, "failed to register txirq\n");
+		free_irq(port->irq, efm_port);
+err_request_irq_rx:
+
+		clk_disable(efm_port->clk);
+	} else {
+		efm32_uart_write32(efm_port,
+				UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN);
+		efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD);
+	}
+
+err_clk_enable:
+	return ret;
+}
+
+static void efm32_uart_shutdown(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+
+	efm32_uart_write32(efm_port, 0, UARTn_IEN);
+	free_irq(port->irq, efm_port);
+
+	clk_disable(efm_port->clk);
+}
+
+static void efm32_uart_set_termios(struct uart_port *port,
+		struct ktermios *new, struct ktermios *old)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	unsigned long flags;
+	unsigned baud;
+	u32 clkdiv;
+	u32 frame = 0;
+
+	/* no modem control lines */
+	new->c_cflag &= ~(CRTSCTS | CMSPAR);
+
+	baud = uart_get_baud_rate(port, new, old,
+			DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192),
+			DIV_ROUND_CLOSEST(port->uartclk, 16));
+
+	switch (new->c_cflag & CSIZE) {
+	case CS5:
+		frame |= UARTn_FRAME_DATABITS(5);
+		break;
+	case CS6:
+		frame |= UARTn_FRAME_DATABITS(6);
+		break;
+	case CS7:
+		frame |= UARTn_FRAME_DATABITS(7);
+		break;
+	case CS8:
+		frame |= UARTn_FRAME_DATABITS(8);
+		break;
+	}
+
+	if (new->c_cflag & CSTOPB)
+		/* the receiver only verifies the first stop bit */
+		frame |= UARTn_FRAME_STOPBITS_TWO;
+	else
+		frame |= UARTn_FRAME_STOPBITS_ONE;
+
+	if (new->c_cflag & PARENB) {
+		if (new->c_cflag & PARODD)
+			frame |= UARTn_FRAME_PARITY_ODD;
+		else
+			frame |= UARTn_FRAME_PARITY_EVEN;
+	} else
+		frame |= UARTn_FRAME_PARITY_NONE;
+
+	/*
+	 * the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25.
+	 * port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow.
+	 */
+	clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	efm32_uart_write32(efm_port,
+			UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD);
+
+	port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK;
+	if (new->c_iflag & INPCK)
+		port->read_status_mask |=
+			UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
+	if (new->c_iflag & (BRKINT | PARMRK))
+		port->read_status_mask |= SW_UARTn_RXDATAX_BERR;
+
+	port->ignore_status_mask = 0;
+	if (new->c_iflag & IGNPAR)
+		port->ignore_status_mask |=
+			UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
+	if (new->c_iflag & IGNBRK)
+		port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR;
+
+	uart_update_timeout(port, new->c_cflag, baud);
+
+	efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL);
+	efm32_uart_write32(efm_port, frame, UARTn_FRAME);
+	efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV);
+
+	efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN,
+			UARTn_CMD);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *efm32_uart_type(struct uart_port *port)
+{
+	return port->type == PORT_EFMUART ? "efm32-uart" : NULL;
+}
+
+static void efm32_uart_release_port(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+
+	clk_unprepare(efm_port->clk);
+	clk_put(efm_port->clk);
+	iounmap(port->membase);
+}
+
+static int efm32_uart_request_port(struct uart_port *port)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	int ret;
+
+	port->membase = ioremap(port->mapbase, 60);
+	if (!efm_port->port.membase) {
+		ret = -ENOMEM;
+		efm_debug(efm_port, "failed to remap\n");
+		goto err_ioremap;
+	}
+
+	efm_port->clk = clk_get(port->dev, NULL);
+	if (IS_ERR(efm_port->clk)) {
+		ret = PTR_ERR(efm_port->clk);
+		efm_debug(efm_port, "failed to get clock\n");
+		goto err_clk_get;
+	}
+
+	ret = clk_prepare(efm_port->clk);
+	if (ret) {
+		clk_put(efm_port->clk);
+err_clk_get:
+
+		iounmap(port->membase);
+err_ioremap:
+		return ret;
+	}
+	return 0;
+}
+
+static void efm32_uart_config_port(struct uart_port *port, int type)
+{
+	if (type & UART_CONFIG_TYPE &&
+			!efm32_uart_request_port(port))
+		port->type = PORT_EFMUART;
+}
+
+static int efm32_uart_verify_port(struct uart_port *port,
+		struct serial_struct *serinfo)
+{
+	int ret = 0;
+
+	if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static struct uart_ops efm32_uart_pops = {
+	.tx_empty = efm32_uart_tx_empty,
+	.set_mctrl = efm32_uart_set_mctrl,
+	.get_mctrl = efm32_uart_get_mctrl,
+	.stop_tx = efm32_uart_stop_tx,
+	.start_tx = efm32_uart_start_tx,
+	.stop_rx = efm32_uart_stop_rx,
+	.enable_ms = efm32_uart_enable_ms,
+	.break_ctl = efm32_uart_break_ctl,
+	.startup = efm32_uart_startup,
+	.shutdown = efm32_uart_shutdown,
+	.set_termios = efm32_uart_set_termios,
+	.type = efm32_uart_type,
+	.release_port = efm32_uart_release_port,
+	.request_port = efm32_uart_request_port,
+	.config_port = efm32_uart_config_port,
+	.verify_port = efm32_uart_verify_port,
+};
+
+static struct efm32_uart_port *efm32_uart_ports[5];
+
+#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE
+static void efm32_uart_console_putchar(struct uart_port *port, int ch)
+{
+	struct efm32_uart_port *efm_port = to_efm_port(port);
+	unsigned int timeout = 0x400;
+	u32 status;
+
+	while (1) {
+		status = efm32_uart_read32(efm_port, UARTn_STATUS);
+
+		if (status & UARTn_STATUS_TXBL)
+			break;
+		if (!timeout--)
+			return;
+	}
+	efm32_uart_write32(efm_port, ch, UARTn_TXDATA);
+}
+
+static void efm32_uart_console_write(struct console *co, const char *s,
+		unsigned int count)
+{
+	struct efm32_uart_port *efm_port = efm32_uart_ports[co->index];
+	u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
+	unsigned int timeout = 0x400;
+
+	if (!(status & UARTn_STATUS_TXENS))
+		efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
+
+	uart_console_write(&efm_port->port, s, count,
+			efm32_uart_console_putchar);
+
+	/* Wait for the transmitter to become empty */
+	while (1) {
+		u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
+		if (status & UARTn_STATUS_TXC)
+			break;
+		if (!timeout--)
+			break;
+	}
+
+	if (!(status & UARTn_STATUS_TXENS))
+		efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
+}
+
+static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port,
+		int *baud, int *parity, int *bits)
+{
+	u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL);
+	u32 route, clkdiv, frame;
+
+	if (ctrl & UARTn_CTRL_SYNC)
+		/* not operating in async mode */
+		return;
+
+	route = efm32_uart_read32(efm_port, UARTn_ROUTE);
+	if (!(route & UARTn_ROUTE_TXPEN))
+		/* tx pin not routed */
+		return;
+
+	clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV);
+
+	*baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk,
+			16 * (4 + (clkdiv >> 6)));
+
+	frame = efm32_uart_read32(efm_port, UARTn_FRAME);
+	if (frame & UARTn_FRAME_PARITY_ODD)
+		*parity = 'o';
+	else if (frame & UARTn_FRAME_PARITY_EVEN)
+		*parity = 'e';
+	else
+		*parity = 'n';
+
+	*bits = (frame & UARTn_FRAME_DATABITS__MASK) -
+			UARTn_FRAME_DATABITS(4) + 4;
+
+	efm_debug(efm_port, "get_opts: options=%d%c%d\n",
+			*baud, *parity, *bits);
+}
+
+static int efm32_uart_console_setup(struct console *co, char *options)
+{
+	struct efm32_uart_port *efm_port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+	int ret;
+
+	if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) {
+		unsigned i;
+		for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) {
+			if (efm32_uart_ports[i]) {
+				pr_warn("efm32-console: fall back to console index %u (from %hhi)\n",
+						i, co->index);
+				co->index = i;
+				break;
+			}
+		}
+	}
+
+	efm_port = efm32_uart_ports[co->index];
+	if (!efm_port) {
+		pr_warn("efm32-console: No port at %d\n", co->index);
+		return -ENODEV;
+	}
+
+	ret = clk_prepare(efm_port->clk);
+	if (ret) {
+		dev_warn(efm_port->port.dev,
+				"console: clk_prepare failed: %d\n", ret);
+		return ret;
+	}
+
+	efm_port->port.uartclk = clk_get_rate(efm_port->clk);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		efm32_uart_console_get_options(efm_port,
+				&baud, &parity, &bits);
+
+	return uart_set_options(&efm_port->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver efm32_uart_reg;
+
+static struct console efm32_uart_console = {
+	.name = DEV_NAME,
+	.write = efm32_uart_console_write,
+	.device = uart_console_device,
+	.setup = efm32_uart_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+	.data = &efm32_uart_reg,
+};
+
+#else
+#define efm32_uart_console (*(struct console *)NULL)
+#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */
+
+static struct uart_driver efm32_uart_reg = {
+	.owner = THIS_MODULE,
+	.driver_name = DRIVER_NAME,
+	.dev_name = DEV_NAME,
+	.nr = ARRAY_SIZE(efm32_uart_ports),
+	.cons = &efm32_uart_console,
+};
+
+static int efm32_uart_probe_dt(struct platform_device *pdev,
+		struct efm32_uart_port *efm_port)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	if (!np)
+		return 1;
+
+	ret = of_alias_get_id(np, "serial");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
+		return ret;
+	} else {
+		efm_port->port.line = ret;
+		return 0;
+	}
+
+}
+
+static int __devinit efm32_uart_probe(struct platform_device *pdev)
+{
+	struct efm32_uart_port *efm_port;
+	struct resource *res;
+	int ret;
+
+	efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL);
+	if (!efm_port) {
+		dev_dbg(&pdev->dev, "failed to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		dev_dbg(&pdev->dev, "failed to determine base address\n");
+		goto err_get_base;
+	}
+
+	if (resource_size(res) < 60) {
+		ret = -EINVAL;
+		dev_dbg(&pdev->dev, "memory resource too small\n");
+		goto err_too_small;
+	}
+
+	ret = platform_get_irq(pdev, 0);
+	if (ret <= 0) {
+		dev_dbg(&pdev->dev, "failed to get rx irq\n");
+		goto err_get_rxirq;
+	}
+
+	efm_port->port.irq = ret;
+
+	ret = platform_get_irq(pdev, 1);
+	if (ret <= 0)
+		ret = efm_port->port.irq + 1;
+
+	efm_port->txirq = ret;
+
+	efm_port->port.dev = &pdev->dev;
+	efm_port->port.mapbase = res->start;
+	efm_port->port.type = PORT_EFMUART;
+	efm_port->port.iotype = UPIO_MEM32;
+	efm_port->port.fifosize = 2;
+	efm_port->port.ops = &efm32_uart_pops;
+	efm_port->port.flags = UPF_BOOT_AUTOCONF;
+
+	ret = efm32_uart_probe_dt(pdev, efm_port);
+	if (ret > 0)
+		/* not created by device tree */
+		efm_port->port.line = pdev->id;
+
+	if (efm_port->port.line >= 0 &&
+			efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
+		efm32_uart_ports[efm_port->port.line] = efm_port;
+
+	ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port);
+	if (ret) {
+		dev_dbg(&pdev->dev, "failed to add port: %d\n", ret);
+
+		if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
+			efm32_uart_ports[pdev->id] = NULL;
+err_get_rxirq:
+err_too_small:
+err_get_base:
+		kfree(efm_port);
+	} else {
+		platform_set_drvdata(pdev, efm_port);
+		dev_dbg(&pdev->dev, "\\o/\n");
+	}
+
+	return ret;
+}
+
+static int __devexit efm32_uart_remove(struct platform_device *pdev)
+{
+	struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	uart_remove_one_port(&efm32_uart_reg, &efm_port->port);
+
+	if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
+		efm32_uart_ports[pdev->id] = NULL;
+
+	kfree(efm_port);
+
+	return 0;
+}
+
+static struct of_device_id efm32_uart_dt_ids[] = {
+	{
+		.compatible = "efm32,uart",
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids);
+
+static struct platform_driver efm32_uart_driver = {
+	.probe = efm32_uart_probe,
+	.remove = __devexit_p(efm32_uart_remove),
+
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = efm32_uart_dt_ids,
+	},
+};
+
+static int __init efm32_uart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&efm32_uart_reg);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&efm32_uart_driver);
+	if (ret)
+		uart_unregister_driver(&efm32_uart_reg);
+
+	pr_info("EFM32 UART/USART driver\n");
+
+	return ret;
+}
+module_init(efm32_uart_init);
+
+static void __exit efm32_uart_exit(void)
+{
+	platform_driver_unregister(&efm32_uart_driver);
+	uart_unregister_driver(&efm32_uart_reg);
+}
+
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("EFM32 UART/USART driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);

+ 0 - 3
drivers/tty/serial/ifx6x60.c

@@ -1375,12 +1375,9 @@ static int __init ifx_spi_init(void)
 		return -ENOMEM;
 	}
 
-	tty_drv->magic = TTY_DRIVER_MAGIC;
-	tty_drv->owner = THIS_MODULE;
 	tty_drv->driver_name = DRVNAME;
 	tty_drv->name = TTYNAME;
 	tty_drv->minor_start = IFX_SPI_TTY_ID;
-	tty_drv->num = 1;
 	tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
 	tty_drv->subtype = SERIAL_TYPE_NORMAL;
 	tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;

+ 1 - 2
drivers/tty/serial/ioc4_serial.c

@@ -16,7 +16,6 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 #include <linux/circ_buf.h>
 #include <linux/serial_reg.h>
 #include <linux/module.h>
@@ -975,7 +974,7 @@ intr_connect(struct ioc4_soft *soft, int type,
 	BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
 	       || (type == IOC4_OTHER_INTR_TYPE)));
 
-	i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1;
+	i = atomic_inc_return(&soft-> is_intr_type[type].is_num_intrs) - 1;
 	BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
 
 	/* Save off the lower level interrupt handler */

+ 2 - 10
drivers/tty/serial/m32r_sio.c

@@ -38,7 +38,6 @@
 #include <linux/console.h>
 #include <linux/sysrq.h>
 #include <linux/serial.h>
-#include <linux/serialP.h>
 #include <linux/delay.h>
 
 #include <asm/m32r.h>
@@ -70,13 +69,6 @@
 
 #define PASS_LIMIT	256
 
-/*
- * We default to IRQ0 for the "no irq" hack.   Some
- * machine types want others as well - they're free
- * to redefine this in their header file.
- */
-#define is_real_interrupt(irq)	((irq) != 0)
-
 #define BASE_BAUD	115200
 
 /* Standard COM flags */
@@ -640,7 +632,7 @@ static int m32r_sio_startup(struct uart_port *port)
 	 * hardware interrupt, we use a timer-based system.  The original
 	 * driver used to do this with IRQ0.
 	 */
-	if (!is_real_interrupt(up->port.irq)) {
+	if (!up->port.irq) {
 		unsigned int timeout = up->port.timeout;
 
 		timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
@@ -687,7 +679,7 @@ static void m32r_sio_shutdown(struct uart_port *port)
 
 	sio_init();
 
-	if (!is_real_interrupt(up->port.irq))
+	if (!up->port.irq)
 		del_timer_sync(&up->timer);
 	else
 		serial_unlink_irq_chain(up);

+ 1 - 0
drivers/tty/serial/m32r_sio.h

@@ -15,6 +15,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/pci.h>
 
 struct m32r_sio_probe {
 	struct module	*owner;

+ 5 - 4
drivers/tty/serial/mpc52xx_uart.c

@@ -262,8 +262,9 @@ static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
 				  port->uartclk / 4);
 	divisor = (port->uartclk + 2 * baud) / (4 * baud);
 
-	/* select the proper prescaler and set the divisor */
-	if (divisor > 0xffff) {
+	/* select the proper prescaler and set the divisor
+	 * prefer high prescaler for more tolerance on low baudrates */
+	if (divisor > 0xffff || baud <= 115200) {
 		divisor = (divisor + 4) / 8;
 		prescaler = 0xdd00; /* /32 */
 	} else
@@ -507,7 +508,7 @@ static int __init mpc512x_psc_fifoc_init(void)
 
 	psc_fifoc_irq = irq_of_parse_and_map(np, 0);
 	of_node_put(np);
-	if (psc_fifoc_irq == NO_IRQ) {
+	if (psc_fifoc_irq == 0) {
 		pr_err("%s: Can't get FIFOC irq\n", __func__);
 		iounmap(psc_fifoc);
 		return -ENODEV;
@@ -1354,7 +1355,7 @@ static int __devinit mpc52xx_uart_of_probe(struct platform_device *op)
 	}
 
 	psc_ops->get_irq(port, op->dev.of_node);
-	if (port->irq == NO_IRQ) {
+	if (port->irq == 0) {
 		dev_dbg(&op->dev, "Could not get irq\n");
 		return -EINVAL;
 	}

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

@@ -203,7 +203,6 @@ static int __init smd_tty_init(void)
 	if (smd_tty_driver == 0)
 		return -ENOMEM;
 
-	smd_tty_driver->owner = THIS_MODULE;
 	smd_tty_driver->driver_name = "smd_tty_driver";
 	smd_tty_driver->name = "smd";
 	smd_tty_driver->major = 0;

+ 1 - 2
drivers/tty/serial/mux.c

@@ -17,7 +17,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/serial.h>
@@ -499,7 +498,7 @@ static int __init mux_probe(struct parisc_device *dev)
 		port->membase	= ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
 		port->iotype	= UPIO_MEM;
 		port->type	= PORT_MUX;
-		port->irq	= NO_IRQ;
+		port->irq	= 0;
 		port->uartclk	= 0;
 		port->fifosize	= MUX_FIFO_SIZE;
 		port->ops	= &mux_pops;

+ 3 - 3
drivers/tty/serial/omap-serial.c

@@ -159,7 +159,7 @@ static void serial_omap_stop_tx(struct uart_port *port)
 		serial_out(up, UART_IER, up->ier);
 	}
 
-	if (!up->use_dma && pdata->set_forceidle)
+	if (!up->use_dma && pdata && pdata->set_forceidle)
 		pdata->set_forceidle(up->pdev);
 
 	pm_runtime_mark_last_busy(&up->pdev->dev);
@@ -298,7 +298,7 @@ static void serial_omap_start_tx(struct uart_port *port)
 	if (!up->use_dma) {
 		pm_runtime_get_sync(&up->pdev->dev);
 		serial_omap_enable_ier_thri(up);
-		if (pdata->set_noidle)
+		if (pdata && pdata->set_noidle)
 			pdata->set_noidle(up->pdev);
 		pm_runtime_mark_last_busy(&up->pdev->dev);
 		pm_runtime_put_autosuspend(&up->pdev->dev);
@@ -1613,7 +1613,7 @@ static int serial_omap_runtime_resume(struct device *dev)
 	struct uart_omap_port *up = dev_get_drvdata(dev);
 	struct omap_uart_port_info *pdata = dev->platform_data;
 
-	if (up) {
+	if (up && pdata) {
 		if (pdata->get_context_loss_count) {
 			u32 loss_cnt = pdata->get_context_loss_count(dev);
 

+ 128 - 44
drivers/tty/serial/pch_uart.c

@@ -29,6 +29,7 @@
 #include <linux/nmi.h>
 #include <linux/delay.h>
 
+#include <linux/debugfs.h>
 #include <linux/dmaengine.h>
 #include <linux/pch_dma.h>
 
@@ -144,6 +145,8 @@ enum {
 #define PCH_UART_DLL		0x00
 #define PCH_UART_DLM		0x01
 
+#define PCH_UART_BRCSR		0x0E
+
 #define PCH_UART_IID_RLS	(PCH_UART_IIR_REI)
 #define PCH_UART_IID_RDR	(PCH_UART_IIR_RRI)
 #define PCH_UART_IID_RDR_TO	(PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
@@ -203,7 +206,10 @@ enum {
 
 #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
 
-#define DEFAULT_BAUD_RATE 1843200 /* 1.8432MHz */
+#define DEFAULT_UARTCLK   1843200 /*   1.8432 MHz */
+#define CMITC_UARTCLK   192000000 /* 192.0000 MHz */
+#define FRI2_64_UARTCLK  64000000 /*  64.0000 MHz */
+#define FRI2_48_UARTCLK  48000000 /*  48.0000 MHz */
 
 struct pch_uart_buffer {
 	unsigned char *buf;
@@ -218,7 +224,7 @@ struct eg20t_port {
 	unsigned int iobase;
 	struct pci_dev *pdev;
 	int fifo_size;
-	int base_baud;
+	int uartclk;
 	int start_tx;
 	int start_rx;
 	int tx_empty;
@@ -243,6 +249,8 @@ struct eg20t_port {
 	int				tx_dma_use;
 	void				*rx_buf_virt;
 	dma_addr_t			rx_buf_dma;
+
+	struct dentry	*debugfs;
 };
 
 /**
@@ -287,26 +295,100 @@ static struct pch_uart_driver_data drv_dat[] = {
 static struct eg20t_port *pch_uart_ports[PCH_UART_NR];
 #endif
 static unsigned int default_baud = 9600;
+static unsigned int user_uartclk = 0;
 static const int trigger_level_256[4] = { 1, 64, 128, 224 };
 static const int trigger_level_64[4] = { 1, 16, 32, 56 };
 static const int trigger_level_16[4] = { 1, 4, 8, 14 };
 static const int trigger_level_1[4] = { 1, 1, 1, 1 };
 
-static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
-				 int base_baud)
+#ifdef CONFIG_DEBUG_FS
+
+#define PCH_REGS_BUFSIZE	1024
+static int pch_show_regs_open(struct inode *inode, struct file *file)
 {
-	struct eg20t_port *priv = pci_get_drvdata(pdev);
+	file->private_data = inode->i_private;
+	return 0;
+}
 
-	priv->trigger_level = 1;
-	priv->fcr = 0;
+static ssize_t port_show_regs(struct file *file, char __user *user_buf,
+				size_t count, loff_t *ppos)
+{
+	struct eg20t_port *priv = file->private_data;
+	char *buf;
+	u32 len = 0;
+	ssize_t ret;
+	unsigned char lcr;
+
+	buf = kzalloc(PCH_REGS_BUFSIZE, GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"PCH EG20T port[%d] regs:\n", priv->port.line);
+
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"=================================\n");
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"IER: \t0x%02x\n", ioread8(priv->membase + UART_IER));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"BRCSR: \t0x%02x\n",
+			ioread8(priv->membase + PCH_UART_BRCSR));
+
+	lcr = ioread8(priv->membase + UART_LCR);
+	iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL));
+	len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
+			"DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM));
+	iowrite8(lcr, priv->membase + UART_LCR);
+
+	if (len > PCH_REGS_BUFSIZE)
+		len = PCH_REGS_BUFSIZE;
+
+	ret =  simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	kfree(buf);
+	return ret;
 }
 
-static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
+static const struct file_operations port_regs_ops = {
+	.owner		= THIS_MODULE,
+	.open		= pch_show_regs_open,
+	.read		= port_show_regs,
+	.llseek		= default_llseek,
+};
+#endif	/* CONFIG_DEBUG_FS */
+
+/* Return UART clock, checking for board specific clocks. */
+static int pch_uart_get_uartclk(void)
 {
-	unsigned int msr = ioread8(base + UART_MSR);
-	priv->dmsr |= msr & PCH_UART_MSR_DELTA;
+	const char *cmp;
+
+	if (user_uartclk)
+		return user_uartclk;
+
+	cmp = dmi_get_system_info(DMI_BOARD_NAME);
+	if (cmp && strstr(cmp, "CM-iTC"))
+		return CMITC_UARTCLK;
+
+	cmp = dmi_get_system_info(DMI_BIOS_VERSION);
+	if (cmp && strnstr(cmp, "FRI2", 4))
+		return FRI2_64_UARTCLK;
+
+	cmp = dmi_get_system_info(DMI_PRODUCT_NAME);
+	if (cmp && strstr(cmp, "Fish River Island II"))
+		return FRI2_48_UARTCLK;
 
-	return msr;
+	return DEFAULT_UARTCLK;
 }
 
 static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
@@ -332,7 +414,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
 	unsigned int dll, dlm, lcr;
 	int div;
 
-	div = DIV_ROUND_CLOSEST(priv->base_baud / 16, baud);
+	div = DIV_ROUND_CLOSEST(priv->uartclk / 16, baud);
 	if (div < 0 || USHRT_MAX <= div) {
 		dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div);
 		return -EINVAL;
@@ -442,8 +524,9 @@ static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
 
 static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
 {
-	priv->dmsr = 0;
-	return get_msr(priv, priv->membase);
+	unsigned int msr = ioread8(priv->membase + UART_MSR);
+	priv->dmsr = msr & PCH_UART_MSR_DELTA;
+	return (u8)msr;
 }
 
 static void pch_uart_hal_write(struct eg20t_port *priv,
@@ -524,7 +607,7 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
 
 static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
 {
-	int ret;
+	int ret = 0;
 	struct uart_port *port = &priv->port;
 
 	if (port->x_char) {
@@ -533,8 +616,6 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
 		buf[0] = port->x_char;
 		port->x_char = 0;
 		ret = 1;
-	} else {
-		ret = 0;
 	}
 
 	return ret;
@@ -1032,14 +1113,12 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
 static unsigned int pch_uart_tx_empty(struct uart_port *port)
 {
 	struct eg20t_port *priv;
-	int ret;
+
 	priv = container_of(port, struct eg20t_port, port);
 	if (priv->tx_empty)
-		ret = TIOCSER_TEMT;
+		return TIOCSER_TEMT;
 	else
-		ret = 0;
-
-	return ret;
+		return 0;
 }
 
 /* Returns the current state of modem control inputs. */
@@ -1153,9 +1232,9 @@ static int pch_uart_startup(struct uart_port *port)
 	priv->tx_empty = 1;
 
 	if (port->uartclk)
-		priv->base_baud = port->uartclk;
+		priv->uartclk = port->uartclk;
 	else
-		port->uartclk = priv->base_baud;
+		port->uartclk = priv->uartclk;
 
 	pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
 	ret = pch_uart_hal_set_line(priv, default_baud,
@@ -1273,9 +1352,8 @@ static void pch_uart_set_termios(struct uart_port *port,
 		else
 			parity = PCH_UART_HAL_PARITY_EVEN;
 
-	} else {
+	} else
 		parity = PCH_UART_HAL_PARITY_NONE;
-	}
 
 	/* Only UART0 has auto hardware flow function */
 	if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
@@ -1447,7 +1525,6 @@ static void
 pch_console_write(struct console *co, const char *s, unsigned int count)
 {
 	struct eg20t_port *priv;
-
 	unsigned long flags;
 	u8 ier;
 	int locked = 1;
@@ -1489,7 +1566,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
 static int __init pch_console_setup(struct console *co, char *options)
 {
 	struct uart_port *port;
-	int baud = 9600;
+	int baud = default_baud;
 	int bits = 8;
 	int parity = 'n';
 	int flow = 'n';
@@ -1506,8 +1583,7 @@ static int __init pch_console_setup(struct console *co, char *options)
 	if (!port || (!port->iobase && !port->membase))
 		return -ENODEV;
 
-	/* setup uartclock */
-	port->uartclk = DEFAULT_BAUD_RATE;
+	port->uartclk = pch_uart_get_uartclk();
 
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1550,10 +1626,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	unsigned int iobase;
 	unsigned int mapbase;
 	unsigned char *rxbuf;
-	int fifosize, base_baud;
+	int fifosize;
 	int port_type;
 	struct pch_uart_driver_data *board;
-	const char *board_name;
+	char name[32];	/* for debugfs file name */
 
 	board = &drv_dat[id->driver_data];
 	port_type = board->port_type;
@@ -1566,13 +1642,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	if (!rxbuf)
 		goto init_port_free_txbuf;
 
-	base_baud = DEFAULT_BAUD_RATE;
-
-	/* quirk for CM-iTC board */
-	board_name = dmi_get_system_info(DMI_BOARD_NAME);
-	if (board_name && strstr(board_name, "CM-iTC"))
-		base_baud = 192000000; /* 192.0MHz */
-
 	switch (port_type) {
 	case PORT_UNKNOWN:
 		fifosize = 256; /* EG20T/ML7213: UART0 */
@@ -1597,7 +1666,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	priv->rxbuf.size = PAGE_SIZE;
 
 	priv->fifo_size = fifosize;
-	priv->base_baud = base_baud;
+	priv->uartclk = pch_uart_get_uartclk();
 	priv->port_type = PORT_MAX_8250 + port_type + 1;
 	priv->port.dev = &pdev->dev;
 	priv->port.iobase = iobase;
@@ -1614,7 +1683,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	spin_lock_init(&priv->port.lock);
 
 	pci_set_drvdata(pdev, priv);
-	pch_uart_hal_request(pdev, fifosize, base_baud);
+	priv->trigger_level = 1;
+	priv->fcr = 0;
 
 #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
 	pch_uart_ports[board->line_no] = priv;
@@ -1623,6 +1693,12 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
 	if (ret < 0)
 		goto init_port_hal_free;
 
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof(name), "uart%d_regs", board->line_no);
+	priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO,
+				NULL, priv, &port_regs_ops);
+#endif
+
 	return priv;
 
 init_port_hal_free:
@@ -1639,6 +1715,11 @@ init_port_alloc_err:
 
 static void pch_uart_exit_port(struct eg20t_port *priv)
 {
+
+#ifdef CONFIG_DEBUG_FS
+	if (priv->debugfs)
+		debugfs_remove(priv->debugfs);
+#endif
 	uart_remove_one_port(&pch_uart_driver, &priv->port);
 	pci_set_drvdata(priv->pdev, NULL);
 	free_page((unsigned long)priv->rxbuf.buf);
@@ -1646,9 +1727,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
 
 static void pch_uart_pci_remove(struct pci_dev *pdev)
 {
-	struct eg20t_port *priv;
-
-	priv = (struct eg20t_port *)pci_get_drvdata(pdev);
+	struct eg20t_port *priv = pci_get_drvdata(pdev);
 
 	pci_disable_msi(pdev);
 
@@ -1785,3 +1864,8 @@ module_exit(pch_uart_module_exit);
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
 module_param(default_baud, uint, S_IRUGO);
+MODULE_PARM_DESC(default_baud,
+                 "Default BAUD for initial driver state and console (default 9600)");
+module_param(user_uartclk, uint, S_IRUGO);
+MODULE_PARM_DESC(user_uartclk,
+                 "Override UART default or board specific UART clock");

+ 1 - 1
drivers/tty/serial/pmac_zilog.c

@@ -1506,7 +1506,7 @@ no_dma:
 	 * fixed up interrupt info, but we use the device-tree directly
 	 * here due to early probing so we need the fixup too.
 	 */
-	if (uap->port.irq == NO_IRQ &&
+	if (uap->port.irq == 0 &&
 	    np->parent && np->parent->parent &&
 	    of_device_is_compatible(np->parent->parent, "gatwick")) {
 		/* IRQs on gatwick are offset by 64 */

+ 4 - 4
drivers/tty/serial/pxa.c

@@ -579,9 +579,9 @@ serial_pxa_pm(struct uart_port *port, unsigned int state,
 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
 
 	if (!state)
-		clk_enable(up->clk);
+		clk_prepare_enable(up->clk);
 	else
-		clk_disable(up->clk);
+		clk_disable_unprepare(up->clk);
 }
 
 static void serial_pxa_release_port(struct uart_port *port)
@@ -668,7 +668,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
 	struct uart_pxa_port *up = serial_pxa_ports[co->index];
 	unsigned int ier;
 
-	clk_enable(up->clk);
+	clk_prepare_enable(up->clk);
 
 	/*
 	 *	First save the IER then disable the interrupts
@@ -685,7 +685,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
 	wait_for_xmitr(up);
 	serial_out(up, UART_IER, ier);
 
-	clk_disable(up->clk);
+	clk_disable_unprepare(up->clk);
 }
 
 static int __init

+ 1 - 1
drivers/tty/serial/samsung.c

@@ -1507,7 +1507,7 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = {
 #endif
 
 #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \
-	defined(CONFIG_CPU_S3C2443)
+	defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442)
 static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
 	.info = &(struct s3c24xx_uart_info) {
 		.name		= "Samsung S3C2440 UART",

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

@@ -2230,7 +2230,6 @@ int uart_register_driver(struct uart_driver *drv)
 
 	drv->tty_driver = normal;
 
-	normal->owner		= drv->owner;
 	normal->driver_name	= drv->driver_name;
 	normal->name		= drv->dev_name;
 	normal->major		= drv->major;

+ 2 - 2
drivers/tty/serial/sn_console.c

@@ -461,12 +461,12 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
 	struct tty_struct *tty;
 
 	if (!port) {
-		printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n");
+		printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n");
 		return;
 	}
 
 	if (!port->sc_ops) {
-		printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receieve\n");
+		printk(KERN_ERR "sn_receive_chars - port->sc_ops  NULL so can't receive\n");
 		return;
 	}
 

+ 1 - 1
drivers/tty/serial/suncore.c

@@ -17,11 +17,11 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/serial_core.h>
+#include <linux/sunserialcore.h>
 #include <linux/init.h>
 
 #include <asm/prom.h>
 
-#include "suncore.h"
 
 static int sunserial_current_minor = 64;
 

+ 1 - 2
drivers/tty/serial/sunhv.c

@@ -29,8 +29,7 @@
 #endif
 
 #include <linux/serial_core.h>
-
-#include "suncore.h"
+#include <linux/sunserialcore.h>
 
 #define CON_BREAK	((long)-1)
 #define CON_HUP		((long)-2)

+ 1 - 1
drivers/tty/serial/sunsab.c

@@ -43,8 +43,8 @@
 #endif
 
 #include <linux/serial_core.h>
+#include <linux/sunserialcore.h>
 
-#include "suncore.h"
 #include "sunsab.h"
 
 struct uart_sunsab_port {

+ 1 - 2
drivers/tty/serial/sunsu.c

@@ -47,8 +47,7 @@
 #endif
 
 #include <linux/serial_core.h>
-
-#include "suncore.h"
+#include <linux/sunserialcore.h>
 
 /* We are on a NS PC87303 clocked with 24.0 MHz, which results
  * in a UART clock of 1.8462 MHz.

+ 6 - 6
drivers/tty/serial/sunzilog.c

@@ -43,8 +43,8 @@
 #endif
 
 #include <linux/serial_core.h>
+#include <linux/sunserialcore.h>
 
-#include "suncore.h"
 #include "sunzilog.h"
 
 /* On 32-bit sparcs we need to delay after register accesses
@@ -1397,7 +1397,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
 #endif
 }
 
-static int zilog_irq = -1;
+static int zilog_irq;
 
 static int __devinit zs_probe(struct platform_device *op)
 {
@@ -1425,7 +1425,7 @@ static int __devinit zs_probe(struct platform_device *op)
 
 	rp = sunzilog_chip_regs[inst];
 
-	if (zilog_irq == -1)
+	if (!zilog_irq)
 		zilog_irq = op->archdata.irqs[0];
 
 	up = &sunzilog_port_table[inst * 2];
@@ -1580,7 +1580,7 @@ static int __init sunzilog_init(void)
 	if (err)
 		goto out_unregister_uart;
 
-	if (zilog_irq != -1) {
+	if (!zilog_irq) {
 		struct uart_sunzilog_port *up = sunzilog_irq_chain;
 		err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
 				  "zs", sunzilog_irq_chain);
@@ -1621,7 +1621,7 @@ static void __exit sunzilog_exit(void)
 {
 	platform_driver_unregister(&zs_driver);
 
-	if (zilog_irq != -1) {
+	if (!zilog_irq) {
 		struct uart_sunzilog_port *up = sunzilog_irq_chain;
 
 		/* Disable Interrupts */
@@ -1637,7 +1637,7 @@ static void __exit sunzilog_exit(void)
 		}
 
 		free_irq(zilog_irq, sunzilog_irq_chain);
-		zilog_irq = -1;
+		zilog_irq = 0;
 	}
 
 	if (sunzilog_reg.nr) {

+ 1 - 1
drivers/tty/serial/ucc_uart.c

@@ -1360,7 +1360,7 @@ static int ucc_uart_probe(struct platform_device *ofdev)
 	}
 
 	qe_port->port.irq = irq_of_parse_and_map(np, 0);
-	if (qe_port->port.irq == NO_IRQ) {
+	if (qe_port->port.irq == 0) {
 		dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
 		       qe_port->ucc_num + 1);
 		ret = -EINVAL;

+ 2 - 2
drivers/tty/serial/vr41xx_siu.c

@@ -61,7 +61,7 @@
 static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
 	[0 ... SIU_PORTS_MAX-1] = {
 		.lock	= __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
-		.irq	= -1,
+		.irq	= 0,
 	},
 };
 
@@ -171,7 +171,7 @@ static inline unsigned int siu_check_type(struct uart_port *port)
 {
 	if (port->line == 0)
 		return PORT_VR41XX_SIU;
-	if (port->line == 1 && port->irq != -1)
+	if (port->line == 1 && port->irq)
 		return PORT_VR41XX_DSIU;
 
 	return PORT_UNKNOWN;

+ 2 - 2
drivers/tty/serial/vt8500_serial.c

@@ -544,7 +544,7 @@ static struct uart_driver vt8500_uart_driver = {
 	.cons		= VT8500_CONSOLE,
 };
 
-static int __init vt8500_serial_probe(struct platform_device *pdev)
+static int __devinit vt8500_serial_probe(struct platform_device *pdev)
 {
 	struct vt8500_port *vt8500_port;
 	struct resource *mmres, *irqres;
@@ -605,7 +605,7 @@ static int __devexit vt8500_serial_remove(struct platform_device *pdev)
 
 static struct platform_driver vt8500_platform_driver = {
 	.probe  = vt8500_serial_probe,
-	.remove = vt8500_serial_remove,
+	.remove = __devexit_p(vt8500_serial_remove),
 	.driver = {
 		.name = "vt8500_serial",
 		.owner = THIS_MODULE,

+ 1 - 2
drivers/tty/synclink.c

@@ -3381,7 +3381,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
 
 	/* verify range of specified line number */	
 	line = tty->index;
-	if ((line < 0) || (line >= mgsl_device_count)) {
+	if (line >= mgsl_device_count) {
 		printk("%s(%d):mgsl_open with invalid line #%d.\n",
 			__FILE__,__LINE__,line);
 		return -ENODEV;
@@ -4333,7 +4333,6 @@ static int mgsl_init_tty(void)
 	if (!serial_driver)
 		return -ENOMEM;
 	
-	serial_driver->owner = THIS_MODULE;
 	serial_driver->driver_name = "synclink";
 	serial_driver->name = "ttySL";
 	serial_driver->major = ttymajor;

+ 1 - 2
drivers/tty/synclink_gt.c

@@ -654,7 +654,7 @@ static int open(struct tty_struct *tty, struct file *filp)
 	unsigned long flags;
 
 	line = tty->index;
-	if ((line < 0) || (line >= slgt_device_count)) {
+	if (line >= slgt_device_count) {
 		DBGERR(("%s: open with invalid line #%d.\n", driver_name, line));
 		return -ENODEV;
 	}
@@ -3795,7 +3795,6 @@ static int __init slgt_init(void)
 
 	/* Initialize the tty_driver structure */
 
-	serial_driver->owner = THIS_MODULE;
 	serial_driver->driver_name = tty_driver_name;
 	serial_driver->name = tty_dev_prefix;
 	serial_driver->major = ttymajor;

+ 1 - 2
drivers/tty/synclinkmp.c

@@ -721,7 +721,7 @@ static int open(struct tty_struct *tty, struct file *filp)
 	unsigned long flags;
 
 	line = tty->index;
-	if ((line < 0) || (line >= synclinkmp_device_count)) {
+	if (line >= synclinkmp_device_count) {
 		printk("%s(%d): open with invalid line #%d.\n",
 			__FILE__,__LINE__,line);
 		return -ENODEV;
@@ -3977,7 +3977,6 @@ static int __init synclinkmp_init(void)
 
 	/* Initialize the tty_driver structure */
 
-	serial_driver->owner = THIS_MODULE;
 	serial_driver->driver_name = "synclinkmp";
 	serial_driver->name = "ttySLM";
 	serial_driver->major = ttymajor;

+ 10 - 7
drivers/tty/sysrq.c

@@ -110,11 +110,9 @@ static struct sysrq_key_op sysrq_SAK_op = {
 #ifdef CONFIG_VT
 static void sysrq_handle_unraw(int key)
 {
-	struct kbd_struct *kbd = &kbd_table[fg_console];
-
-	if (kbd)
-		kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+	vt_reset_unicode(fg_console);
 }
+
 static struct sysrq_key_op sysrq_unraw_op = {
 	.handler	= sysrq_handle_unraw,
 	.help_msg	= "unRaw",
@@ -322,11 +320,16 @@ static void send_sig_all(int sig)
 {
 	struct task_struct *p;
 
+	read_lock(&tasklist_lock);
 	for_each_process(p) {
-		if (p->mm && !is_global_init(p))
-			/* Not swapper, init nor kernel thread */
-			force_sig(sig, p);
+		if (p->flags & PF_KTHREAD)
+			continue;
+		if (is_global_init(p))
+			continue;
+
+		force_sig(sig, p);
 	}
+	read_unlock(&tasklist_lock);
 }
 
 static void sysrq_handle_term(int key)

+ 21 - 33
drivers/tty/tty_io.c

@@ -1230,13 +1230,10 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
 static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
 		struct inode *inode, int idx)
 {
-	struct tty_struct *tty;
-
 	if (driver->ops->lookup)
 		return driver->ops->lookup(driver, inode, idx);
 
-	tty = driver->ttys[idx];
-	return tty;
+	return driver->ttys[idx];
 }
 
 /**
@@ -1271,6 +1268,19 @@ int tty_init_termios(struct tty_struct *tty)
 }
 EXPORT_SYMBOL_GPL(tty_init_termios);
 
+int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	int ret = tty_init_termios(tty);
+	if (ret)
+		return ret;
+
+	tty_driver_kref_get(driver);
+	tty->count++;
+	driver->ttys[tty->index] = tty;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tty_standard_install);
+
 /**
  *	tty_driver_install_tty() - install a tty entry in the driver
  *	@driver: the driver for the tty
@@ -1286,21 +1296,8 @@ EXPORT_SYMBOL_GPL(tty_init_termios);
 static int tty_driver_install_tty(struct tty_driver *driver,
 						struct tty_struct *tty)
 {
-	int idx = tty->index;
-	int ret;
-
-	if (driver->ops->install) {
-		ret = driver->ops->install(driver, tty);
-		return ret;
-	}
-
-	if (tty_init_termios(tty) == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
-		driver->ttys[idx] = tty;
-		return 0;
-	}
-	return -ENOMEM;
+	return driver->ops->install ? driver->ops->install(driver, tty) :
+		tty_standard_install(driver, tty);
 }
 
 /**
@@ -1351,7 +1348,6 @@ static int tty_reopen(struct tty_struct *tty)
 		tty->link->count++;
 	}
 	tty->count++;
-	tty->driver = driver; /* N.B. why do this every time?? */
 
 	mutex_lock(&tty->ldisc_mutex);
 	WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
@@ -1365,7 +1361,6 @@ static int tty_reopen(struct tty_struct *tty)
  *	@driver: tty driver we are opening a device on
  *	@idx: device index
  *	@ret_tty: returned tty structure
- *	@first_ok: ok to open a new device (used by ptmx)
  *
  *	Prepare a tty device. This may not be a "new" clean device but
  *	could also be an active device. The pty drivers require special
@@ -1385,18 +1380,11 @@ static int tty_reopen(struct tty_struct *tty)
  * relaxed for the (most common) case of reopening a tty.
  */
 
-struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
-								int first_ok)
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
 {
 	struct tty_struct *tty;
 	int retval;
 
-	/* Check if pty master is being opened multiple times */
-	if (driver->subtype == PTY_TYPE_MASTER &&
-		(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
-		return ERR_PTR(-EIO);
-	}
-
 	/*
 	 * First time open is complex, especially for PTY devices.
 	 * This code guarantees that either everything succeeds and the
@@ -1950,7 +1938,7 @@ retry_open:
 		if (retval)
 			tty = ERR_PTR(retval);
 	} else
-		tty = tty_init_dev(driver, index, 0);
+		tty = tty_init_dev(driver, index);
 
 	mutex_unlock(&tty_mutex);
 	if (driver)
@@ -2941,7 +2929,6 @@ void initialize_tty_struct(struct tty_struct *tty,
 	tty->session = NULL;
 	tty->pgrp = NULL;
 	tty->overrun_time = jiffies;
-	tty->buf.head = tty->buf.tail = NULL;
 	tty_buffer_init(tty);
 	mutex_init(&tty->termios_mutex);
 	mutex_init(&tty->ldisc_mutex);
@@ -3058,7 +3045,7 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
 }
 EXPORT_SYMBOL(tty_unregister_device);
 
-struct tty_driver *alloc_tty_driver(int lines)
+struct tty_driver *__alloc_tty_driver(int lines, struct module *owner)
 {
 	struct tty_driver *driver;
 
@@ -3067,11 +3054,12 @@ struct tty_driver *alloc_tty_driver(int lines)
 		kref_init(&driver->kref);
 		driver->magic = TTY_DRIVER_MAGIC;
 		driver->num = lines;
+		driver->owner = owner;
 		/* later we'll move allocation of tables here */
 	}
 	return driver;
 }
-EXPORT_SYMBOL(alloc_tty_driver);
+EXPORT_SYMBOL(__alloc_tty_driver);
 
 static void destruct_tty_driver(struct kref *kref)
 {

+ 43 - 8
drivers/tty/vt/consolemap.c

@@ -516,6 +516,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 	int err = 0, err1, i;
 	struct uni_pagedir *p, *q;
 
+	/* Save original vc_unipagdir_loc in case we allocate a new one */
 	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
 	if (p->readonly) return -EIO;
 	
@@ -528,26 +529,57 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 		err1 = con_clear_unimap(vc, NULL);
 		if (err1) return err1;
 		
+		/*
+		 * Since refcount was > 1, con_clear_unimap() allocated a
+		 * a new uni_pagedir for this vc.  Re: p != q
+		 */
 		q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-		for (i = 0, l = 0; i < 32; i++)
+
+		/*
+		 * uni_pgdir is a 32*32*64 table with rows allocated
+		 * when its first entry is added.  The unicode value must
+		 * still be incremented for empty rows.  We are copying
+		 * entries from "p" (old) to "q" (new).
+		 */
+		l = 0;		/* unicode value */
+		for (i = 0; i < 32; i++)
 		if ((p1 = p->uni_pgdir[i]))
 			for (j = 0; j < 32; j++)
-			if ((p2 = p1[j]))
+			if ((p2 = p1[j])) {
 				for (k = 0; k < 64; k++, l++)
 				if (p2[k] != 0xffff) {
+					/*
+					 * Found one, copy entry for unicode
+					 * l with fontpos value p2[k].
+					 */
 					err1 = con_insert_unipair(q, l, p2[k]);
 					if (err1) {
 						p->refcount++;
 						*vc->vc_uni_pagedir_loc = (unsigned long)p;
 						con_release_unimap(q);
 						kfree(q);
-						return err1; 
+						return err1;
 					}
-              			}
-              	p = q;
-	} else if (p == dflt)
+				}
+			} else {
+				/* Account for row of 64 empty entries */
+				l += 64;
+			}
+		else
+			/* Account for empty table */
+			l += 32 * 64;
+
+		/*
+		 * Finished copying font table, set vc_uni_pagedir to new table
+		 */
+		p = q;
+	} else if (p == dflt) {
 		dflt = NULL;
-	
+	}
+
+	/*
+	 * Insert user specified unicode pairs into new table.
+	 */
 	while (ct--) {
 		unsigned short unicode, fontpos;
 		__get_user(unicode, &list->unicode);
@@ -557,11 +589,14 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
 		list++;
 	}
 	
+	/*
+	 * Merge with fontmaps of any other virtual consoles.
+	 */
 	if (con_unify_unimap(vc, p))
 		return err;
 
 	for (i = 0; i <= 3; i++)
-		set_inverse_transl(vc, p, i); /* Update all inverse translations */
+		set_inverse_transl(vc, p, i); /* Update inverse translations */
 	set_inverse_trans_unicode(vc, p);
   
 	return err;

+ 768 - 35
drivers/tty/vt/keyboard.c

@@ -41,6 +41,7 @@
 #include <linux/reboot.h>
 #include <linux/notifier.h>
 #include <linux/jiffies.h>
+#include <linux/uaccess.h>
 
 #include <asm/irq_regs.h>
 
@@ -55,8 +56,8 @@ extern void ctrl_alt_del(void);
 /*
  * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
  * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the keypad
- * to be used for numbers.
+ * of PARISC machines however there is no NumLock key and everyone expects the
+ * keypad to be used for numbers.
  */
 
 #if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
@@ -67,8 +68,6 @@ extern void ctrl_alt_del(void);
 
 #define KBD_DEFLOCK 0
 
-void compute_shiftstate(void);
-
 /*
  * Handler Tables.
  */
@@ -99,35 +98,29 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
  * Variables exported for vt_ioctl.c
  */
 
-/* maximum values each key_handler can handle */
-const int max_vals[] = {
-	255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
-	NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
-	255, NR_LOCK - 1, 255, NR_BRL - 1
-};
-
-const int NR_TYPES = ARRAY_SIZE(max_vals);
-
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-EXPORT_SYMBOL_GPL(kbd_table);
-static struct kbd_struct *kbd = kbd_table;
-
 struct vt_spawn_console vt_spawn_con = {
 	.lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
 	.pid  = NULL,
 	.sig  = 0,
 };
 
-/*
- * Variables exported for vt.c
- */
-
-int shift_state = 0;
 
 /*
  * Internal Data.
  */
 
+static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+static struct kbd_struct *kbd = kbd_table;
+
+/* maximum values each key_handler can handle */
+static const int max_vals[] = {
+	255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
+	NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
+	255, NR_LOCK - 1, 255, NR_BRL - 1
+};
+
+static const int NR_TYPES = ARRAY_SIZE(max_vals);
+
 static struct input_handler kbd_handler;
 static DEFINE_SPINLOCK(kbd_event_lock);
 static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];	/* keyboard key bitmap */
@@ -137,6 +130,8 @@ static int npadch = -1;					/* -1 or number assembled on pad */
 static unsigned int diacr;
 static char rep;					/* flag telling character repeat */
 
+static int shift_state = 0;
+
 static unsigned char ledstate = 0xff;			/* undefined */
 static unsigned char ledioctl;
 
@@ -187,7 +182,7 @@ static int getkeycode_helper(struct input_handle *handle, void *data)
 	return d->error == 0; /* stop as soon as we successfully get one */
 }
 
-int getkeycode(unsigned int scancode)
+static int getkeycode(unsigned int scancode)
 {
 	struct getset_keycode_data d = {
 		.ke	= {
@@ -214,7 +209,7 @@ static int setkeycode_helper(struct input_handle *handle, void *data)
 	return d->error == 0; /* stop as soon as we successfully set one */
 }
 
-int setkeycode(unsigned int scancode, unsigned int keycode)
+static int setkeycode(unsigned int scancode, unsigned int keycode)
 {
 	struct getset_keycode_data d = {
 		.ke	= {
@@ -382,9 +377,11 @@ static void to_utf8(struct vc_data *vc, uint c)
 /*
  * Called after returning from RAW mode or when changing consoles - recompute
  * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen
+ * undefined, so that shiftkey release is seen. The caller must hold the
+ * kbd_event_lock.
  */
-void compute_shiftstate(void)
+
+static void do_compute_shiftstate(void)
 {
 	unsigned int i, j, k, sym, val;
 
@@ -417,6 +414,15 @@ void compute_shiftstate(void)
 	}
 }
 
+/* We still have to export this method to vt.c */
+void compute_shiftstate(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	do_compute_shiftstate();
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
 /*
  * We have a combining character DIACR here, followed by the character CH.
  * If the combination occurs in the table, return the corresponding value.
@@ -636,7 +642,7 @@ static void fn_SAK(struct vc_data *vc)
 
 static void fn_null(struct vc_data *vc)
 {
-	compute_shiftstate();
+	do_compute_shiftstate();
 }
 
 /*
@@ -989,6 +995,8 @@ unsigned char getledstate(void)
 
 void setledstate(struct kbd_struct *kbd, unsigned int led)
 {
+        unsigned long flags;
+        spin_lock_irqsave(&kbd_event_lock, flags);
 	if (!(led & ~7)) {
 		ledioctl = led;
 		kbd->ledmode = LED_SHOW_IOCTL;
@@ -996,6 +1004,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
 		kbd->ledmode = LED_SHOW_FLAGS;
 
 	set_leds();
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
 }
 
 static inline unsigned char getleds(void)
@@ -1035,6 +1044,75 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data)
 	return 0;
 }
 
+/**
+ *	vt_get_leds	-	helper for braille console
+ *	@console: console to read
+ *	@flag: flag we want to check
+ *
+ *	Check the status of a keyboard led flag and report it back
+ */
+int vt_get_leds(int console, int flag)
+{
+	unsigned long flags;
+	struct kbd_struct * kbd = kbd_table + console;
+	int ret;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	ret = vc_kbd_led(kbd, flag);
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vt_get_leds);
+
+/**
+ *	vt_set_led_state	-	set LED state of a console
+ *	@console: console to set
+ *	@leds: LED bits
+ *
+ *	Set the LEDs on a console. This is a wrapper for the VT layer
+ *	so that we can keep kbd knowledge internal
+ */
+void vt_set_led_state(int console, int leds)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	setledstate(kbd, leds);
+}
+
+/**
+ *	vt_kbd_con_start	-	Keyboard side of console start
+ *	@console: console
+ *
+ *	Handle console start. This is a wrapper for the VT layer
+ *	so that we can keep kbd knowledge internal
+ */
+void vt_kbd_con_start(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	clr_vc_kbd_led(kbd, VC_SCROLLOCK);
+	set_leds();
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
+/**
+ *	vt_kbd_con_stop		-	Keyboard side of console stop
+ *	@console: console
+ *
+ *	Handle console stop. This is a wrapper for the VT layer
+ *	so that we can keep kbd knowledge internal
+ */
+void vt_kbd_con_stop(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	set_vc_kbd_led(kbd, VC_SCROLLOCK);
+	set_leds();
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
 /*
  * This is the tasklet that updates LED state on all keyboards
  * attached to the box. The reason we use tasklet is that we
@@ -1254,7 +1332,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
 	if (rc == NOTIFY_STOP || !key_map) {
 		atomic_notifier_call_chain(&keyboard_notifier_list,
 					   KBD_UNBOUND_KEYCODE, &param);
-		compute_shiftstate();
+		do_compute_shiftstate();
 		kbd->slockstate = 0;
 		return;
 	}
@@ -1404,14 +1482,14 @@ static void kbd_start(struct input_handle *handle)
 
 static const struct input_device_id kbd_ids[] = {
 	{
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_KEY) },
-        },
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+		.evbit = { BIT_MASK(EV_KEY) },
+	},
 
 	{
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_SND) },
-        },
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+		.evbit = { BIT_MASK(EV_SND) },
+	},
 
 	{ },    /* Terminating entry */
 };
@@ -1433,7 +1511,7 @@ int __init kbd_init(void)
 	int i;
 	int error;
 
-        for (i = 0; i < MAX_NR_CONSOLES; i++) {
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
 		kbd_table[i].ledflagstate = KBD_DEFLEDS;
 		kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
 		kbd_table[i].ledmode = LED_SHOW_FLAGS;
@@ -1452,3 +1530,658 @@ int __init kbd_init(void)
 
 	return 0;
 }
+
+/* Ioctl support code */
+
+/**
+ *	vt_do_diacrit		-	diacritical table updates
+ *	@cmd: ioctl request
+ *	@up: pointer to user data for ioctl
+ *	@perm: permissions check computed by caller
+ *
+ *	Update the diacritical tables atomically and safely. Lock them
+ *	against simultaneous keypresses
+ */
+int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
+{
+	struct kbdiacrs __user *a = up;
+	unsigned long flags;
+	int asize;
+	int ret = 0;
+
+	switch (cmd) {
+	case KDGKBDIACR:
+	{
+		struct kbdiacr *diacr;
+		int i;
+
+		diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr),
+								GFP_KERNEL);
+		if (diacr == NULL)
+			return -ENOMEM;
+
+		/* Lock the diacriticals table, make a copy and then
+		   copy it after we unlock */
+		spin_lock_irqsave(&kbd_event_lock, flags);
+
+		asize = accent_table_size;
+		for (i = 0; i < asize; i++) {
+			diacr[i].diacr = conv_uni_to_8bit(
+						accent_table[i].diacr);
+			diacr[i].base = conv_uni_to_8bit(
+						accent_table[i].base);
+			diacr[i].result = conv_uni_to_8bit(
+						accent_table[i].result);
+		}
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+
+		if (put_user(asize, &a->kb_cnt))
+			ret = -EFAULT;
+		else  if (copy_to_user(a->kbdiacr, diacr,
+				asize * sizeof(struct kbdiacr)))
+			ret = -EFAULT;
+		kfree(diacr);
+		return ret;
+	}
+	case KDGKBDIACRUC:
+	{
+		struct kbdiacrsuc __user *a = up;
+		void *buf;
+
+		buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc),
+								GFP_KERNEL);
+		if (buf == NULL)
+			return -ENOMEM;
+
+		/* Lock the diacriticals table, make a copy and then
+		   copy it after we unlock */
+		spin_lock_irqsave(&kbd_event_lock, flags);
+
+		asize = accent_table_size;
+		memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
+
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+
+		if (put_user(asize, &a->kb_cnt))
+			ret = -EFAULT;
+		else if (copy_to_user(a->kbdiacruc, buf,
+				asize*sizeof(struct kbdiacruc)))
+			ret = -EFAULT;
+		kfree(buf);
+		return ret;
+	}
+
+	case KDSKBDIACR:
+	{
+		struct kbdiacrs __user *a = up;
+		struct kbdiacr *diacr = NULL;
+		unsigned int ct;
+		int i;
+
+		if (!perm)
+			return -EPERM;
+		if (get_user(ct, &a->kb_cnt))
+			return -EFAULT;
+		if (ct >= MAX_DIACR)
+			return -EINVAL;
+
+		if (ct) {
+			diacr = kmalloc(sizeof(struct kbdiacr) * ct,
+								GFP_KERNEL);
+			if (diacr == NULL)
+				return -ENOMEM;
+
+			if (copy_from_user(diacr, a->kbdiacr,
+					sizeof(struct kbdiacr) * ct)) {
+				kfree(diacr);
+				return -EFAULT;
+			}
+		}
+
+		spin_lock_irqsave(&kbd_event_lock, flags);
+		accent_table_size = ct;
+		for (i = 0; i < ct; i++) {
+			accent_table[i].diacr =
+					conv_8bit_to_uni(diacr[i].diacr);
+			accent_table[i].base =
+					conv_8bit_to_uni(diacr[i].base);
+			accent_table[i].result =
+					conv_8bit_to_uni(diacr[i].result);
+		}
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+		kfree(diacr);
+		return 0;
+	}
+
+	case KDSKBDIACRUC:
+	{
+		struct kbdiacrsuc __user *a = up;
+		unsigned int ct;
+		void *buf = NULL;
+
+		if (!perm)
+			return -EPERM;
+
+		if (get_user(ct, &a->kb_cnt))
+			return -EFAULT;
+
+		if (ct >= MAX_DIACR)
+			return -EINVAL;
+
+		if (ct) {
+			buf = kmalloc(ct * sizeof(struct kbdiacruc),
+								GFP_KERNEL);
+			if (buf == NULL)
+				return -ENOMEM;
+
+			if (copy_from_user(buf, a->kbdiacruc,
+					ct * sizeof(struct kbdiacruc))) {
+				kfree(buf);
+				return -EFAULT;
+			}
+		} 
+		spin_lock_irqsave(&kbd_event_lock, flags);
+		if (ct)
+			memcpy(accent_table, buf,
+					ct * sizeof(struct kbdiacruc));
+		accent_table_size = ct;
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+		kfree(buf);
+		return 0;
+	}
+	}
+	return ret;
+}
+
+/**
+ *	vt_do_kdskbmode		-	set keyboard mode ioctl
+ *	@console: the console to use
+ *	@arg: the requested mode
+ *
+ *	Update the keyboard mode bits while holding the correct locks.
+ *	Return 0 for success or an error code.
+ */
+int vt_do_kdskbmode(int console, unsigned int arg)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	switch(arg) {
+	case K_RAW:
+		kbd->kbdmode = VC_RAW;
+		break;
+	case K_MEDIUMRAW:
+		kbd->kbdmode = VC_MEDIUMRAW;
+		break;
+	case K_XLATE:
+		kbd->kbdmode = VC_XLATE;
+		do_compute_shiftstate();
+		break;
+	case K_UNICODE:
+		kbd->kbdmode = VC_UNICODE;
+		do_compute_shiftstate();
+		break;
+	case K_OFF:
+		kbd->kbdmode = VC_OFF;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+	return ret;
+}
+
+/**
+ *	vt_do_kdskbmeta		-	set keyboard meta state
+ *	@console: the console to use
+ *	@arg: the requested meta state
+ *
+ *	Update the keyboard meta bits while holding the correct locks.
+ *	Return 0 for success or an error code.
+ */
+int vt_do_kdskbmeta(int console, unsigned int arg)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	switch(arg) {
+	case K_METABIT:
+		clr_vc_kbd_mode(kbd, VC_META);
+		break;
+	case K_ESCPREFIX:
+		set_vc_kbd_mode(kbd, VC_META);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+	return ret;
+}
+
+int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
+								int perm)
+{
+	struct kbkeycode tmp;
+	int kc = 0;
+
+	if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
+		return -EFAULT;
+	switch (cmd) {
+	case KDGETKEYCODE:
+		kc = getkeycode(tmp.scancode);
+		if (kc >= 0)
+			kc = put_user(kc, &user_kbkc->keycode);
+		break;
+	case KDSETKEYCODE:
+		if (!perm)
+			return -EPERM;
+		kc = setkeycode(tmp.scancode, tmp.keycode);
+		break;
+	}
+	return kc;
+}
+
+#define i (tmp.kb_index)
+#define s (tmp.kb_table)
+#define v (tmp.kb_value)
+
+int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
+						int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	struct kbentry tmp;
+	ushort *key_map, *new_map, val, ov;
+	unsigned long flags;
+
+	if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
+		return -EFAULT;
+
+	if (!capable(CAP_SYS_TTY_CONFIG))
+		perm = 0;
+
+	switch (cmd) {
+	case KDGKBENT:
+		/* Ensure another thread doesn't free it under us */
+		spin_lock_irqsave(&kbd_event_lock, flags);
+		key_map = key_maps[s];
+		if (key_map) {
+		    val = U(key_map[i]);
+		    if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+			val = K_HOLE;
+		} else
+		    val = (i ? K_HOLE : K_NOSUCHMAP);
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+		return put_user(val, &user_kbe->kb_value);
+	case KDSKBENT:
+		if (!perm)
+			return -EPERM;
+		if (!i && v == K_NOSUCHMAP) {
+			spin_lock_irqsave(&kbd_event_lock, flags);
+			/* deallocate map */
+			key_map = key_maps[s];
+			if (s && key_map) {
+			    key_maps[s] = NULL;
+			    if (key_map[0] == U(K_ALLOCATED)) {
+					kfree(key_map);
+					keymap_count--;
+			    }
+			}
+			spin_unlock_irqrestore(&kbd_event_lock, flags);
+			break;
+		}
+
+		if (KTYP(v) < NR_TYPES) {
+		    if (KVAL(v) > max_vals[KTYP(v)])
+				return -EINVAL;
+		} else
+		    if (kbd->kbdmode != VC_UNICODE)
+				return -EINVAL;
+
+		/* ++Geert: non-PC keyboards may generate keycode zero */
+#if !defined(__mc68000__) && !defined(__powerpc__)
+		/* assignment to entry 0 only tests validity of args */
+		if (!i)
+			break;
+#endif
+
+		new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
+		if (!new_map)
+			return -ENOMEM;
+		spin_lock_irqsave(&kbd_event_lock, flags);
+		key_map = key_maps[s];
+		if (key_map == NULL) {
+			int j;
+
+			if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
+			    !capable(CAP_SYS_RESOURCE)) {
+				spin_unlock_irqrestore(&kbd_event_lock, flags);
+				kfree(new_map);
+				return -EPERM;
+			}
+			key_maps[s] = new_map;
+			key_map = new_map;
+			key_map[0] = U(K_ALLOCATED);
+			for (j = 1; j < NR_KEYS; j++)
+				key_map[j] = U(K_HOLE);
+			keymap_count++;
+		} else
+			kfree(new_map);
+
+		ov = U(key_map[i]);
+		if (v == ov)
+			goto out;
+		/*
+		 * Attention Key.
+		 */
+		if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) {
+			spin_unlock_irqrestore(&kbd_event_lock, flags);
+			return -EPERM;
+		}
+		key_map[i] = U(v);
+		if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
+			do_compute_shiftstate();
+out:
+		spin_unlock_irqrestore(&kbd_event_lock, flags);
+		break;
+	}
+	return 0;
+}
+#undef i
+#undef s
+#undef v
+
+/* FIXME: This one needs untangling and locking */
+int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
+{
+	struct kbsentry *kbs;
+	char *p;
+	u_char *q;
+	u_char __user *up;
+	int sz;
+	int delta;
+	char *first_free, *fj, *fnw;
+	int i, j, k;
+	int ret;
+
+	if (!capable(CAP_SYS_TTY_CONFIG))
+		perm = 0;
+
+	kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
+	if (!kbs) {
+		ret = -ENOMEM;
+		goto reterr;
+	}
+
+	/* we mostly copy too much here (512bytes), but who cares ;) */
+	if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
+		ret = -EFAULT;
+		goto reterr;
+	}
+	kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
+	i = kbs->kb_func;
+
+	switch (cmd) {
+	case KDGKBSENT:
+		sz = sizeof(kbs->kb_string) - 1; /* sz should have been
+						  a struct member */
+		up = user_kdgkb->kb_string;
+		p = func_table[i];
+		if(p)
+			for ( ; *p && sz; p++, sz--)
+				if (put_user(*p, up++)) {
+					ret = -EFAULT;
+					goto reterr;
+				}
+		if (put_user('\0', up)) {
+			ret = -EFAULT;
+			goto reterr;
+		}
+		kfree(kbs);
+		return ((p && *p) ? -EOVERFLOW : 0);
+	case KDSKBSENT:
+		if (!perm) {
+			ret = -EPERM;
+			goto reterr;
+		}
+
+		q = func_table[i];
+		first_free = funcbufptr + (funcbufsize - funcbufleft);
+		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
+			;
+		if (j < MAX_NR_FUNC)
+			fj = func_table[j];
+		else
+			fj = first_free;
+
+		delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
+		if (delta <= funcbufleft) { 	/* it fits in current buf */
+		    if (j < MAX_NR_FUNC) {
+			memmove(fj + delta, fj, first_free - fj);
+			for (k = j; k < MAX_NR_FUNC; k++)
+			    if (func_table[k])
+				func_table[k] += delta;
+		    }
+		    if (!q)
+		      func_table[i] = fj;
+		    funcbufleft -= delta;
+		} else {			/* allocate a larger buffer */
+		    sz = 256;
+		    while (sz < funcbufsize - funcbufleft + delta)
+		      sz <<= 1;
+		    fnw = kmalloc(sz, GFP_KERNEL);
+		    if(!fnw) {
+		      ret = -ENOMEM;
+		      goto reterr;
+		    }
+
+		    if (!q)
+		      func_table[i] = fj;
+		    if (fj > funcbufptr)
+			memmove(fnw, funcbufptr, fj - funcbufptr);
+		    for (k = 0; k < j; k++)
+		      if (func_table[k])
+			func_table[k] = fnw + (func_table[k] - funcbufptr);
+
+		    if (first_free > fj) {
+			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
+			for (k = j; k < MAX_NR_FUNC; k++)
+			  if (func_table[k])
+			    func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
+		    }
+		    if (funcbufptr != func_buf)
+		      kfree(funcbufptr);
+		    funcbufptr = fnw;
+		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
+		    funcbufsize = sz;
+		}
+		strcpy(func_table[i], kbs->kb_string);
+		break;
+	}
+	ret = 0;
+reterr:
+	kfree(kbs);
+	return ret;
+}
+
+int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+        unsigned long flags;
+	unsigned char ucval;
+
+        switch(cmd) {
+	/* the ioctls below read/set the flags usually shown in the leds */
+	/* don't use them - they will go away without warning */
+	case KDGKBLED:
+                spin_lock_irqsave(&kbd_event_lock, flags);
+		ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
+                spin_unlock_irqrestore(&kbd_event_lock, flags);
+		return put_user(ucval, (char __user *)arg);
+
+	case KDSKBLED:
+		if (!perm)
+			return -EPERM;
+		if (arg & ~0x77)
+			return -EINVAL;
+                spin_lock_irqsave(&kbd_event_lock, flags);
+		kbd->ledflagstate = (arg & 7);
+		kbd->default_ledflagstate = ((arg >> 4) & 7);
+		set_leds();
+                spin_unlock_irqrestore(&kbd_event_lock, flags);
+		break;
+
+	/* the ioctls below only set the lights, not the functions */
+	/* for those, see KDGKBLED and KDSKBLED above */
+	case KDGETLED:
+		ucval = getledstate();
+		return put_user(ucval, (char __user *)arg);
+
+	case KDSETLED:
+		if (!perm)
+			return -EPERM;
+		setledstate(kbd, arg);
+		return 0;
+        }
+        return -ENOIOCTLCMD;
+}
+
+int vt_do_kdgkbmode(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	/* This is a spot read so needs no locking */
+	switch (kbd->kbdmode) {
+	case VC_RAW:
+		return K_RAW;
+	case VC_MEDIUMRAW:
+		return K_MEDIUMRAW;
+	case VC_UNICODE:
+		return K_UNICODE;
+	case VC_OFF:
+		return K_OFF;
+	default:
+		return K_XLATE;
+	}
+}
+
+/**
+ *	vt_do_kdgkbmeta		-	report meta status
+ *	@console: console to report
+ *
+ *	Report the meta flag status of this console
+ */
+int vt_do_kdgkbmeta(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+        /* Again a spot read so no locking */
+	return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT;
+}
+
+/**
+ *	vt_reset_unicode	-	reset the unicode status
+ *	@console: console being reset
+ *
+ *	Restore the unicode console state to its default
+ */
+void vt_reset_unicode(int console)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
+/**
+ *	vt_get_shiftstate	-	shift bit state
+ *
+ *	Report the shift bits from the keyboard state. We have to export
+ *	this to support some oddities in the vt layer.
+ */
+int vt_get_shift_state(void)
+{
+        /* Don't lock as this is a transient report */
+        return shift_state;
+}
+
+/**
+ *	vt_reset_keyboard	-	reset keyboard state
+ *	@console: console to reset
+ *
+ *	Reset the keyboard bits for a console as part of a general console
+ *	reset event
+ */
+void vt_reset_keyboard(int console)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	set_vc_kbd_mode(kbd, VC_REPEAT);
+	clr_vc_kbd_mode(kbd, VC_CKMODE);
+	clr_vc_kbd_mode(kbd, VC_APPLIC);
+	clr_vc_kbd_mode(kbd, VC_CRLF);
+	kbd->lockstate = 0;
+	kbd->slockstate = 0;
+	kbd->ledmode = LED_SHOW_FLAGS;
+	kbd->ledflagstate = kbd->default_ledflagstate;
+	/* do not do set_leds here because this causes an endless tasklet loop
+	   when the keyboard hasn't been initialized yet */
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
+/**
+ *	vt_get_kbd_mode_bit	-	read keyboard status bits
+ *	@console: console to read from
+ *	@bit: mode bit to read
+ *
+ *	Report back a vt mode bit. We do this without locking so the
+ *	caller must be sure that there are no synchronization needs
+ */
+
+int vt_get_kbd_mode_bit(int console, int bit)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	return vc_kbd_mode(kbd, bit);
+}
+
+/**
+ *	vt_set_kbd_mode_bit	-	read keyboard status bits
+ *	@console: console to read from
+ *	@bit: mode bit to read
+ *
+ *	Set a vt mode bit. We do this without locking so the
+ *	caller must be sure that there are no synchronization needs
+ */
+
+void vt_set_kbd_mode_bit(int console, int bit)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	set_vc_kbd_mode(kbd, bit);
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}
+
+/**
+ *	vt_clr_kbd_mode_bit	-	read keyboard status bits
+ *	@console: console to read from
+ *	@bit: mode bit to read
+ *
+ *	Report back a vt mode bit. We do this without locking so the
+ *	caller must be sure that there are no synchronization needs
+ */
+
+void vt_clr_kbd_mode_bit(int console, int bit)
+{
+	struct kbd_struct * kbd = kbd_table + console;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_event_lock, flags);
+	clr_vc_kbd_mode(kbd, bit);
+	spin_unlock_irqrestore(&kbd_event_lock, flags);
+}

+ 43 - 15
drivers/tty/vt/selection.c

@@ -30,6 +30,7 @@
 
 extern void poke_blanked_console(void);
 
+/* FIXME: all this needs locking */
 /* Variables for selection control. */
 /* Use a dynamic buffer, instead of static (Dec 1994) */
 struct vc_data *sel_cons;		/* must not be deallocated */
@@ -61,10 +62,14 @@ sel_pos(int n)
 				use_unicode);
 }
 
-/* remove the current selection highlight, if any,
-   from the console holding the selection. */
-void
-clear_selection(void) {
+/**
+ *	clear_selection		-	remove current selection
+ *
+ *	Remove the current selection highlight, if any from the console
+ *	holding the selection. The caller must hold the console lock.
+ */
+void clear_selection(void)
+{
 	highlight_pointer(-1); /* hide the pointer */
 	if (sel_start != -1) {
 		highlight(sel_start, sel_end);
@@ -74,7 +79,7 @@ clear_selection(void) {
 
 /*
  * User settable table: what characters are to be considered alphabetic?
- * 256 bits
+ * 256 bits. Locked by the console lock.
  */
 static u32 inwordLut[8]={
   0x00000000, /* control chars     */
@@ -91,10 +96,20 @@ static inline int inword(const u16 c) {
 	return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
 }
 
-/* set inwordLut contents. Invoked by ioctl(). */
+/**
+ *	set loadlut		-	load the LUT table
+ *	@p: user table
+ *
+ *	Load the LUT table from user space. The caller must hold the console
+ *	lock. Make a temporary copy so a partial update doesn't make a mess.
+ */
 int sel_loadlut(char __user *p)
 {
-	return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
+	u32 tmplut[8];
+	if (copy_from_user(tmplut, (u32 __user *)(p+4), 32))
+		return -EFAULT;
+	memcpy(inwordLut, tmplut, 32);
+	return 0;
 }
 
 /* does screen address p correspond to character at LH/RH edge of screen? */
@@ -130,7 +145,16 @@ static int store_utf8(u16 c, char *p)
     	}
 }
 
-/* set the current selection. Invoked by ioctl() or by kernel code. */
+/**
+ *	set_selection		- 	set the current selection.
+ *	@sel: user selection info
+ *	@tty: the console tty
+ *
+ *	Invoked by the ioctl handle for the vt layer.
+ *
+ *	The entire selection process is managed under the console_lock. It's
+ *	 a lot under the lock but its hardly a performance path
+ */
 int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
 {
 	struct vc_data *vc = vc_cons[fg_console].d;
@@ -138,7 +162,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
 	char *bp, *obp;
 	int i, ps, pe, multiplier;
 	u16 c;
-	struct kbd_struct *kbd = kbd_table + fg_console;
+	int mode;
 
 	poke_blanked_console();
 
@@ -182,7 +206,11 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
 		clear_selection();
 		sel_cons = vc_cons[fg_console].d;
 	}
-	use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
+	mode = vt_do_kdgkbmode(fg_console);
+	if (mode == K_UNICODE)
+		use_unicode = 1;
+	else
+		use_unicode = 0;
 
 	switch (sel_mode)
 	{
@@ -302,7 +330,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
  * queue of the tty associated with the current console.
  * Invoked by ioctl().
  *
- * Locking: always called with BTM from vt_ioctl
+ * Locking: called without locks. Calls the ldisc wrongly with
+ * unsafe methods,
  */
 int paste_selection(struct tty_struct *tty)
 {
@@ -317,13 +346,12 @@ int paste_selection(struct tty_struct *tty)
 	poke_blanked_console();
 	console_unlock();
 
+	/* FIXME: wtf is this supposed to achieve ? */
 	ld = tty_ldisc_ref(tty);
-	if (!ld) {
-		tty_unlock();
+	if (!ld)
 		ld = tty_ldisc_ref_wait(tty);
-		tty_lock();
-	}
 
+	/* FIXME: this is completely unsafe */
 	add_wait_queue(&vc->paste_wait, &wait);
 	while (sel_buffer && sel_buffer_lth > pasted) {
 		set_current_state(TASK_INTERRUPTIBLE);

+ 2 - 2
drivers/tty/vt/vc_screen.c

@@ -608,10 +608,10 @@ vcs_open(struct inode *inode, struct file *filp)
 	unsigned int currcons = iminor(inode) & 127;
 	int ret = 0;
 	
-	tty_lock();
+	console_lock();
 	if(currcons && !vc_cons_allocated(currcons-1))
 		ret = -ENXIO;
-	tty_unlock();
+	console_unlock();
 	return ret;
 }
 

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

@@ -1028,9 +1028,9 @@ void vc_deallocate(unsigned int currcons)
  *	VT102 emulator
  */
 
-#define set_kbd(vc, x)	set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define clr_kbd(vc, x)	clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define is_kbd(vc, x)	vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define set_kbd(vc, x)	vt_set_kbd_mode_bit((vc)->vc_num, (x))
+#define clr_kbd(vc, x)	vt_clr_kbd_mode_bit((vc)->vc_num, (x))
+#define is_kbd(vc, x)	vt_get_kbd_mode_bit((vc)->vc_num, (x))
 
 #define decarm		VC_REPEAT
 #define decckm		VC_CKMODE
@@ -1652,16 +1652,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
 	vc->vc_deccm		= global_cursor_default;
 	vc->vc_decim		= 0;
 
-	set_kbd(vc, decarm);
-	clr_kbd(vc, decckm);
-	clr_kbd(vc, kbdapplic);
-	clr_kbd(vc, lnm);
-	kbd_table[vc->vc_num].lockstate = 0;
-	kbd_table[vc->vc_num].slockstate = 0;
-	kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
-	kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
-	/* do not do set_leds here because this causes an endless tasklet loop
-	   when the keyboard hasn't been initialized yet */
+	vt_reset_keyboard(vc->vc_num);
 
 	vc->vc_cursor_type = cur_default;
 	vc->vc_complement_mask = vc->vc_s_complement_mask;
@@ -1979,7 +1970,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
 		case 'q': /* DECLL - but only 3 leds */
 			/* map 0,1,2,3 to 0,1,2,4 */
 			if (vc->vc_par[0] < 4)
-				setledstate(kbd_table + vc->vc_num,
+				vt_set_led_state(vc->vc_num,
 					    (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
 			return;
 		case 'r':
@@ -2632,7 +2623,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
 			console_unlock();
 			break;
 		case TIOCL_SELLOADLUT:
+			console_lock();
 			ret = sel_loadlut(p);
+			console_unlock();
 			break;
 		case TIOCL_GETSHIFTSTATE:
 
@@ -2642,15 +2635,19 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
 	 * kernel-internal variable; programs not closely
 	 * related to the kernel should not use this.
 	 */
-	 		data = shift_state;
+			data = vt_get_shift_state();
 			ret = __put_user(data, p);
 			break;
 		case TIOCL_GETMOUSEREPORTING:
+			console_lock();	/* May be overkill */
 			data = mouse_reporting();
+			console_unlock();
 			ret = __put_user(data, p);
 			break;
 		case TIOCL_SETVESABLANK:
+			console_lock();
 			ret = set_vesa_blanking(p);
+			console_unlock();
 			break;
 		case TIOCL_GETKMSGREDIRECT:
 			data = vt_get_kmsg_redirect();
@@ -2667,13 +2664,21 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
 			}
 			break;
 		case TIOCL_GETFGCONSOLE:
+			/* No locking needed as this is a transiently
+			   correct return anyway if the caller hasn't
+			   disabled switching */
 			ret = fg_console;
 			break;
 		case TIOCL_SCROLLCONSOLE:
 			if (get_user(lines, (s32 __user *)(p+4))) {
 				ret = -EFAULT;
 			} else {
+				/* Need the console lock here. Note that lots
+				   of other calls need fixing before the lock
+				   is actually useful ! */
+				console_lock();
 				scrollfront(vc_cons[fg_console].d, lines);
+				console_unlock();
 				ret = 0;
 			}
 			break;
@@ -2753,8 +2758,7 @@ static void con_stop(struct tty_struct *tty)
 	console_num = tty->index;
 	if (!vc_cons_allocated(console_num))
 		return;
-	set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-	set_leds();
+	vt_kbd_con_stop(console_num);
 }
 
 /*
@@ -2768,8 +2772,7 @@ static void con_start(struct tty_struct *tty)
 	console_num = tty->index;
 	if (!vc_cons_allocated(console_num))
 		return;
-	clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-	set_leds();
+	vt_kbd_con_start(console_num);
 }
 
 static void con_flush_chars(struct tty_struct *tty)
@@ -2991,7 +2994,7 @@ int __init vty_init(const struct file_operations *console_fops)
 	console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
 	if (!console_driver)
 		panic("Couldn't allocate console driver\n");
-	console_driver->owner = THIS_MODULE;
+
 	console_driver->name = "tty";
 	console_driver->name_base = 1;
 	console_driver->major = TTY_MAJOR;
@@ -3980,9 +3983,6 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
 	int rc = -EINVAL;
 	int c;
 
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
-
 	if (op->data) {
 		font.data = kmalloc(max_font_size, GFP_KERNEL);
 		if (!font.data)
@@ -3991,7 +3991,9 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
 		font.data = NULL;
 
 	console_lock();
-	if (vc->vc_sw->con_font_get)
+	if (vc->vc_mode != KD_TEXT)
+		rc = -EINVAL;
+	else if (vc->vc_sw->con_font_get)
 		rc = vc->vc_sw->con_font_get(vc, &font);
 	else
 		rc = -ENOSYS;
@@ -4073,7 +4075,9 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
 	if (IS_ERR(font.data))
 		return PTR_ERR(font.data);
 	console_lock();
-	if (vc->vc_sw->con_font_set)
+	if (vc->vc_mode != KD_TEXT)
+		rc = -EINVAL;
+	else if (vc->vc_sw->con_font_set)
 		rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
 	else
 		rc = -ENOSYS;
@@ -4089,8 +4093,6 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
 	char *s = name;
 	int rc;
 
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
 
 	if (!op->data)
 		s = NULL;
@@ -4100,6 +4102,10 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
 		name[MAX_FONT_NAME - 1] = 0;
 
 	console_lock();
+	if (vc->vc_mode != KD_TEXT) {
+		console_unlock();
+		return -EINVAL;
+	}
 	if (vc->vc_sw->con_font_default)
 		rc = vc->vc_sw->con_font_default(vc, &font, s);
 	else
@@ -4117,11 +4123,11 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
 	int con = op->height;
 	int rc;
 
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
 
 	console_lock();
-	if (!vc->vc_sw->con_font_copy)
+	if (vc->vc_mode != KD_TEXT)
+		rc = -EINVAL;
+	else if (!vc->vc_sw->con_font_copy)
 		rc = -ENOSYS;
 	else if (con < 0 || !vc_cons_allocated(con))
 		rc = -ENOTTY;

+ 71 - 424
drivers/tty/vt/vt_ioctl.c

@@ -130,7 +130,7 @@ static void vt_event_wait(struct vt_event_wait *vw)
 	list_add(&vw->list, &vt_events);
 	spin_unlock_irqrestore(&vt_event_lock, flags);
 	/* Wait for it to pass */
-	wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
+	wait_event_interruptible(vt_event_waitqueue, vw->done);
 	/* Dequeue it */
 	spin_lock_irqsave(&vt_event_lock, flags);
 	list_del(&vw->list);
@@ -195,232 +195,7 @@ int vt_waitactive(int n)
 #define GPLAST 0x3df
 #define GPNUM (GPLAST - GPFIRST + 1)
 
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
-static inline int
-do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
-{
-	struct kbentry tmp;
-	ushort *key_map, val, ov;
-
-	if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
-		return -EFAULT;
 
-	if (!capable(CAP_SYS_TTY_CONFIG))
-		perm = 0;
-
-	switch (cmd) {
-	case KDGKBENT:
-		key_map = key_maps[s];
-		if (key_map) {
-		    val = U(key_map[i]);
-		    if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-			val = K_HOLE;
-		} else
-		    val = (i ? K_HOLE : K_NOSUCHMAP);
-		return put_user(val, &user_kbe->kb_value);
-	case KDSKBENT:
-		if (!perm)
-			return -EPERM;
-		if (!i && v == K_NOSUCHMAP) {
-			/* deallocate map */
-			key_map = key_maps[s];
-			if (s && key_map) {
-			    key_maps[s] = NULL;
-			    if (key_map[0] == U(K_ALLOCATED)) {
-					kfree(key_map);
-					keymap_count--;
-			    }
-			}
-			break;
-		}
-
-		if (KTYP(v) < NR_TYPES) {
-		    if (KVAL(v) > max_vals[KTYP(v)])
-				return -EINVAL;
-		} else
-		    if (kbd->kbdmode != VC_UNICODE)
-				return -EINVAL;
-
-		/* ++Geert: non-PC keyboards may generate keycode zero */
-#if !defined(__mc68000__) && !defined(__powerpc__)
-		/* assignment to entry 0 only tests validity of args */
-		if (!i)
-			break;
-#endif
-
-		if (!(key_map = key_maps[s])) {
-			int j;
-
-			if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
-			    !capable(CAP_SYS_RESOURCE))
-				return -EPERM;
-
-			key_map = kmalloc(sizeof(plain_map),
-						     GFP_KERNEL);
-			if (!key_map)
-				return -ENOMEM;
-			key_maps[s] = key_map;
-			key_map[0] = U(K_ALLOCATED);
-			for (j = 1; j < NR_KEYS; j++)
-				key_map[j] = U(K_HOLE);
-			keymap_count++;
-		}
-		ov = U(key_map[i]);
-		if (v == ov)
-			break;	/* nothing to do */
-		/*
-		 * Attention Key.
-		 */
-		if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		key_map[i] = U(v);
-		if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
-			compute_shiftstate();
-		break;
-	}
-	return 0;
-}
-#undef i
-#undef s
-#undef v
-
-static inline int 
-do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
-{
-	struct kbkeycode tmp;
-	int kc = 0;
-
-	if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
-		return -EFAULT;
-	switch (cmd) {
-	case KDGETKEYCODE:
-		kc = getkeycode(tmp.scancode);
-		if (kc >= 0)
-			kc = put_user(kc, &user_kbkc->keycode);
-		break;
-	case KDSETKEYCODE:
-		if (!perm)
-			return -EPERM;
-		kc = setkeycode(tmp.scancode, tmp.keycode);
-		break;
-	}
-	return kc;
-}
-
-static inline int
-do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
-{
-	struct kbsentry *kbs;
-	char *p;
-	u_char *q;
-	u_char __user *up;
-	int sz;
-	int delta;
-	char *first_free, *fj, *fnw;
-	int i, j, k;
-	int ret;
-
-	if (!capable(CAP_SYS_TTY_CONFIG))
-		perm = 0;
-
-	kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
-	if (!kbs) {
-		ret = -ENOMEM;
-		goto reterr;
-	}
-
-	/* we mostly copy too much here (512bytes), but who cares ;) */
-	if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
-		ret = -EFAULT;
-		goto reterr;
-	}
-	kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
-	i = kbs->kb_func;
-
-	switch (cmd) {
-	case KDGKBSENT:
-		sz = sizeof(kbs->kb_string) - 1; /* sz should have been
-						  a struct member */
-		up = user_kdgkb->kb_string;
-		p = func_table[i];
-		if(p)
-			for ( ; *p && sz; p++, sz--)
-				if (put_user(*p, up++)) {
-					ret = -EFAULT;
-					goto reterr;
-				}
-		if (put_user('\0', up)) {
-			ret = -EFAULT;
-			goto reterr;
-		}
-		kfree(kbs);
-		return ((p && *p) ? -EOVERFLOW : 0);
-	case KDSKBSENT:
-		if (!perm) {
-			ret = -EPERM;
-			goto reterr;
-		}
-
-		q = func_table[i];
-		first_free = funcbufptr + (funcbufsize - funcbufleft);
-		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
-			;
-		if (j < MAX_NR_FUNC)
-			fj = func_table[j];
-		else
-			fj = first_free;
-
-		delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
-		if (delta <= funcbufleft) { 	/* it fits in current buf */
-		    if (j < MAX_NR_FUNC) {
-			memmove(fj + delta, fj, first_free - fj);
-			for (k = j; k < MAX_NR_FUNC; k++)
-			    if (func_table[k])
-				func_table[k] += delta;
-		    }
-		    if (!q)
-		      func_table[i] = fj;
-		    funcbufleft -= delta;
-		} else {			/* allocate a larger buffer */
-		    sz = 256;
-		    while (sz < funcbufsize - funcbufleft + delta)
-		      sz <<= 1;
-		    fnw = kmalloc(sz, GFP_KERNEL);
-		    if(!fnw) {
-		      ret = -ENOMEM;
-		      goto reterr;
-		    }
-
-		    if (!q)
-		      func_table[i] = fj;
-		    if (fj > funcbufptr)
-			memmove(fnw, funcbufptr, fj - funcbufptr);
-		    for (k = 0; k < j; k++)
-		      if (func_table[k])
-			func_table[k] = fnw + (func_table[k] - funcbufptr);
-
-		    if (first_free > fj) {
-			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
-			for (k = j; k < MAX_NR_FUNC; k++)
-			  if (func_table[k])
-			    func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
-		    }
-		    if (funcbufptr != func_buf)
-		      kfree(funcbufptr);
-		    funcbufptr = fnw;
-		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
-		    funcbufsize = sz;
-		}
-		strcpy(func_table[i], kbs->kb_string);
-		break;
-	}
-	ret = 0;
-reterr:
-	kfree(kbs);
-	return ret;
-}
 
 static inline int 
 do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
@@ -497,7 +272,6 @@ int vt_ioctl(struct tty_struct *tty,
 {
 	struct vc_data *vc = tty->driver_data;
 	struct console_font_op op;	/* used in multiple places here */
-	struct kbd_struct * kbd;
 	unsigned int console;
 	unsigned char ucval;
 	unsigned int uival;
@@ -507,7 +281,6 @@ int vt_ioctl(struct tty_struct *tty,
 
 	console = vc->vc_num;
 
-	tty_lock();
 
 	if (!vc_cons_allocated(console)) { 	/* impossible? */
 		ret = -ENOIOCTLCMD;
@@ -523,19 +296,18 @@ int vt_ioctl(struct tty_struct *tty,
 	if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
 		perm = 1;
  
-	kbd = kbd_table + console;
 	switch (cmd) {
 	case TIOCLINUX:
 		ret = tioclinux(tty, arg);
 		break;
 	case KIOCSOUND:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		/*
 		 * The use of PIT_TICK_RATE is historic, it used to be
 		 * the platform-dependent CLOCK_TICK_RATE between 2.6.12
 		 * and 2.6.36, which was a minor but unfortunate ABI
-		 * change.
+		 * change. kd_mksound is locked by the input layer.
 		 */
 		if (arg)
 			arg = PIT_TICK_RATE / arg;
@@ -544,7 +316,7 @@ int vt_ioctl(struct tty_struct *tty,
 
 	case KDMKTONE:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 	{
 		unsigned int ticks, count;
 		
@@ -562,10 +334,11 @@ int vt_ioctl(struct tty_struct *tty,
 
 	case KDGKBTYPE:
 		/*
-		 * this is naive.
+		 * this is naïve.
 		 */
 		ucval = KB_101;
-		goto setchar;
+		ret = put_user(ucval, (char __user *)arg);
+		break;
 
 		/*
 		 * These cannot be implemented on any machine that implements
@@ -579,6 +352,8 @@ int vt_ioctl(struct tty_struct *tty,
 		/*
 		 * KDADDIO and KDDELIO may be able to add ports beyond what
 		 * we reject here, but to be safe...
+		 *
+		 * These are locked internally via sys_ioperm
 		 */
 		if (arg < GPFIRST || arg > GPLAST) {
 			ret = -EINVAL;
@@ -601,7 +376,7 @@ int vt_ioctl(struct tty_struct *tty,
 		struct kbd_repeat kbrep;
 		
 		if (!capable(CAP_SYS_TTY_CONFIG))
-			goto eperm;
+			return -EPERM;
 
 		if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
 			ret =  -EFAULT;
@@ -625,7 +400,7 @@ int vt_ioctl(struct tty_struct *tty,
 		 * need to restore their engine state. --BenH
 		 */
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		switch (arg) {
 		case KD_GRAPHICS:
 			break;
@@ -638,6 +413,7 @@ int vt_ioctl(struct tty_struct *tty,
 			ret = -EINVAL;
 			goto out;
 		}
+		/* FIXME: this needs the console lock extending */
 		if (vc->vc_mode == (unsigned char) arg)
 			break;
 		vc->vc_mode = (unsigned char) arg;
@@ -669,69 +445,26 @@ int vt_ioctl(struct tty_struct *tty,
 
 	case KDSKBMODE:
 		if (!perm)
-			goto eperm;
-		switch(arg) {
-		  case K_RAW:
-			kbd->kbdmode = VC_RAW;
-			break;
-		  case K_MEDIUMRAW:
-			kbd->kbdmode = VC_MEDIUMRAW;
-			break;
-		  case K_XLATE:
-			kbd->kbdmode = VC_XLATE;
-			compute_shiftstate();
-			break;
-		  case K_UNICODE:
-			kbd->kbdmode = VC_UNICODE;
-			compute_shiftstate();
-			break;
-		  case K_OFF:
-			kbd->kbdmode = VC_OFF;
-			break;
-		  default:
-			ret = -EINVAL;
-			goto out;
-		}
-		tty_ldisc_flush(tty);
+			return -EPERM;
+		ret = vt_do_kdskbmode(console, arg);
+		if (ret == 0)
+			tty_ldisc_flush(tty);
 		break;
 
 	case KDGKBMODE:
-		switch (kbd->kbdmode) {
-		case VC_RAW:
-			uival = K_RAW;
-			break;
-		case VC_MEDIUMRAW:
-			uival = K_MEDIUMRAW;
-			break;
-		case VC_UNICODE:
-			uival = K_UNICODE;
-			break;
-		case VC_OFF:
-			uival = K_OFF;
-			break;
-		default:
-			uival = K_XLATE;
-			break;
-		}
-		goto setint;
+		uival = vt_do_kdgkbmode(console);
+		ret = put_user(uival, (int __user *)arg);
+		break;
 
 	/* this could be folded into KDSKBMODE, but for compatibility
 	   reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
 	case KDSKBMETA:
-		switch(arg) {
-		  case K_METABIT:
-			clr_vc_kbd_mode(kbd, VC_META);
-			break;
-		  case K_ESCPREFIX:
-			set_vc_kbd_mode(kbd, VC_META);
-			break;
-		  default:
-			ret = -EINVAL;
-		}
+		ret = vt_do_kdskbmeta(console, arg);
 		break;
 
 	case KDGKBMETA:
-		uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
+		/* FIXME: should review whether this is worth locking */
+		uival = vt_do_kdgkbmeta(console);
 	setint:
 		ret = put_user(uival, (int __user *)arg);
 		break;
@@ -740,133 +473,35 @@ int vt_ioctl(struct tty_struct *tty,
 	case KDSETKEYCODE:
 		if(!capable(CAP_SYS_TTY_CONFIG))
 			perm = 0;
-		ret = do_kbkeycode_ioctl(cmd, up, perm);
+		ret = vt_do_kbkeycode_ioctl(cmd, up, perm);
 		break;
 
 	case KDGKBENT:
 	case KDSKBENT:
-		ret = do_kdsk_ioctl(cmd, up, perm, kbd);
+		ret = vt_do_kdsk_ioctl(cmd, up, perm, console);
 		break;
 
 	case KDGKBSENT:
 	case KDSKBSENT:
-		ret = do_kdgkb_ioctl(cmd, up, perm);
+		ret = vt_do_kdgkb_ioctl(cmd, up, perm);
 		break;
 
+	/* Diacritical processing. Handled in keyboard.c as it has
+	   to operate on the keyboard locks and structures */
 	case KDGKBDIACR:
-	{
-		struct kbdiacrs __user *a = up;
-		struct kbdiacr diacr;
-		int i;
-
-		if (put_user(accent_table_size, &a->kb_cnt)) {
-			ret = -EFAULT;
-			break;
-		}
-		for (i = 0; i < accent_table_size; i++) {
-			diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
-			diacr.base = conv_uni_to_8bit(accent_table[i].base);
-			diacr.result = conv_uni_to_8bit(accent_table[i].result);
-			if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
-				ret = -EFAULT;
-				break;
-			}
-		}
-		break;
-	}
 	case KDGKBDIACRUC:
-	{
-		struct kbdiacrsuc __user *a = up;
-
-		if (put_user(accent_table_size, &a->kb_cnt))
-			ret = -EFAULT;
-		else if (copy_to_user(a->kbdiacruc, accent_table,
-				accent_table_size*sizeof(struct kbdiacruc)))
-			ret = -EFAULT;
-		break;
-	}
-
 	case KDSKBDIACR:
-	{
-		struct kbdiacrs __user *a = up;
-		struct kbdiacr diacr;
-		unsigned int ct;
-		int i;
-
-		if (!perm)
-			goto eperm;
-		if (get_user(ct,&a->kb_cnt)) {
-			ret = -EFAULT;
-			break;
-		}
-		if (ct >= MAX_DIACR) {
-			ret = -EINVAL;
-			break;
-		}
-		accent_table_size = ct;
-		for (i = 0; i < ct; i++) {
-			if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
-				ret = -EFAULT;
-				break;
-			}
-			accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
-			accent_table[i].base = conv_8bit_to_uni(diacr.base);
-			accent_table[i].result = conv_8bit_to_uni(diacr.result);
-		}
-		break;
-	}
-
 	case KDSKBDIACRUC:
-	{
-		struct kbdiacrsuc __user *a = up;
-		unsigned int ct;
-
-		if (!perm)
-			goto eperm;
-		if (get_user(ct,&a->kb_cnt)) {
-			ret = -EFAULT;
-			break;
-		}
-		if (ct >= MAX_DIACR) {
-			ret = -EINVAL;
-			break;
-		}
-		accent_table_size = ct;
-		if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
-			ret = -EFAULT;
+		ret = vt_do_diacrit(cmd, up, perm);
 		break;
-	}
 
 	/* the ioctls below read/set the flags usually shown in the leds */
 	/* don't use them - they will go away without warning */
 	case KDGKBLED:
-		ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
-		goto setchar;
-
 	case KDSKBLED:
-		if (!perm)
-			goto eperm;
-		if (arg & ~0x77) {
-			ret = -EINVAL;
-			break;
-		}
-		kbd->ledflagstate = (arg & 7);
-		kbd->default_ledflagstate = ((arg >> 4) & 7);
-		set_leds();
-		break;
-
-	/* the ioctls below only set the lights, not the functions */
-	/* for those, see KDGKBLED and KDSKBLED above */
 	case KDGETLED:
-		ucval = getledstate();
-	setchar:
-		ret = put_user(ucval, (char __user *)arg);
-		break;
-
 	case KDSETLED:
-		if (!perm)
-			goto eperm;
-		setledstate(kbd, arg);
+		ret = vt_do_kdskled(console, cmd, arg, perm);
 		break;
 
 	/*
@@ -879,7 +514,7 @@ int vt_ioctl(struct tty_struct *tty,
 	case KDSIGACCEPT:
 	{
 		if (!perm || !capable(CAP_KILL))
-			goto eperm;
+			return -EPERM;
 		if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
 			ret = -EINVAL;
 		else {
@@ -897,7 +532,7 @@ int vt_ioctl(struct tty_struct *tty,
 		struct vt_mode tmp;
 
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
 			ret = -EFAULT;
 			goto out;
@@ -943,6 +578,7 @@ int vt_ioctl(struct tty_struct *tty,
 		struct vt_stat __user *vtstat = up;
 		unsigned short state, mask;
 
+		/* Review: FIXME: Console lock ? */
 		if (put_user(fg_console + 1, &vtstat->v_active))
 			ret = -EFAULT;
 		else {
@@ -960,6 +596,7 @@ int vt_ioctl(struct tty_struct *tty,
 	 * Returns the first available (non-opened) console.
 	 */
 	case VT_OPENQRY:
+		/* FIXME: locking ? - but then this is a stupid API */
 		for (i = 0; i < MAX_NR_CONSOLES; ++i)
 			if (! VT_IS_IN_USE(i))
 				break;
@@ -973,7 +610,7 @@ int vt_ioctl(struct tty_struct *tty,
 	 */
 	case VT_ACTIVATE:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (arg == 0 || arg > MAX_NR_CONSOLES)
 			ret =  -ENXIO;
 		else {
@@ -992,7 +629,7 @@ int vt_ioctl(struct tty_struct *tty,
 		struct vt_setactivate vsa;
 
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 
 		if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
 					sizeof(struct vt_setactivate))) {
@@ -1020,6 +657,7 @@ int vt_ioctl(struct tty_struct *tty,
 			if (ret)
 				break;
 			/* Commence switch and lock */
+			/* Review set_console locks */
 			set_console(vsa.console);
 		}
 		break;
@@ -1030,7 +668,7 @@ int vt_ioctl(struct tty_struct *tty,
 	 */
 	case VT_WAITACTIVE:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (arg == 0 || arg > MAX_NR_CONSOLES)
 			ret = -ENXIO;
 		else
@@ -1049,16 +687,17 @@ int vt_ioctl(struct tty_struct *tty,
 	 */
 	case VT_RELDISP:
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 
+		console_lock();
 		if (vc->vt_mode.mode != VT_PROCESS) {
+			console_unlock();
 			ret = -EINVAL;
 			break;
 		}
 		/*
 		 * Switching-from response
 		 */
-		console_lock();
 		if (vc->vt_newvt >= 0) {
 			if (arg == 0)
 				/*
@@ -1135,7 +774,7 @@ int vt_ioctl(struct tty_struct *tty,
 
 		ushort ll,cc;
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (get_user(ll, &vtsizes->v_rows) ||
 		    get_user(cc, &vtsizes->v_cols))
 			ret = -EFAULT;
@@ -1146,6 +785,7 @@ int vt_ioctl(struct tty_struct *tty,
 
 				if (vc) {
 					vc->vc_resize_user = 1;
+					/* FIXME: review v tty lock */
 					vc_resize(vc_cons[i].d, cc, ll);
 				}
 			}
@@ -1159,7 +799,7 @@ int vt_ioctl(struct tty_struct *tty,
 		struct vt_consize __user *vtconsize = up;
 		ushort ll,cc,vlin,clin,vcol,ccol;
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		if (!access_ok(VERIFY_READ, vtconsize,
 				sizeof(struct vt_consize))) {
 			ret = -EFAULT;
@@ -1215,7 +855,7 @@ int vt_ioctl(struct tty_struct *tty,
 
 	case PIO_FONT: {
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		op.op = KD_FONT_OP_SET;
 		op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC;	/* Compatibility */
 		op.width = 8;
@@ -1256,7 +896,7 @@ int vt_ioctl(struct tty_struct *tty,
 	case PIO_FONTRESET:
 	{
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 
 #ifdef BROKEN_GRAPHICS_PROGRAMS
 		/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
@@ -1282,7 +922,7 @@ int vt_ioctl(struct tty_struct *tty,
 			break;
 		}
 		if (!perm && op.op != KD_FONT_OP_GET)
-			goto eperm;
+			return -EPERM;
 		ret = con_font_op(vc, &op);
 		if (ret)
 			break;
@@ -1294,50 +934,65 @@ int vt_ioctl(struct tty_struct *tty,
 	case PIO_SCRNMAP:
 		if (!perm)
 			ret = -EPERM;
-		else
+		else {
+			tty_lock();
 			ret = con_set_trans_old(up);
+			tty_unlock();
+		}
 		break;
 
 	case GIO_SCRNMAP:
+		tty_lock();
 		ret = con_get_trans_old(up);
+		tty_unlock();
 		break;
 
 	case PIO_UNISCRNMAP:
 		if (!perm)
 			ret = -EPERM;
-		else
+		else {
+			tty_lock();
 			ret = con_set_trans_new(up);
+			tty_unlock();
+		}
 		break;
 
 	case GIO_UNISCRNMAP:
+		tty_lock();
 		ret = con_get_trans_new(up);
+		tty_unlock();
 		break;
 
 	case PIO_UNIMAPCLR:
 	      { struct unimapinit ui;
 		if (!perm)
-			goto eperm;
+			return -EPERM;
 		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
 		if (ret)
 			ret = -EFAULT;
-		else
+		else {
+			tty_lock();
 			con_clear_unimap(vc, &ui);
+			tty_unlock();
+		}
 		break;
 	      }
 
 	case PIO_UNIMAP:
 	case GIO_UNIMAP:
+		tty_lock();
 		ret = do_unimap_ioctl(cmd, up, perm, vc);
+		tty_unlock();
 		break;
 
 	case VT_LOCKSWITCH:
 		if (!capable(CAP_SYS_TTY_CONFIG))
-			goto eperm;
+			return -EPERM;
 		vt_dont_switch = 1;
 		break;
 	case VT_UNLOCKSWITCH:
 		if (!capable(CAP_SYS_TTY_CONFIG))
-			goto eperm;
+			return -EPERM;
 		vt_dont_switch = 0;
 		break;
 	case VT_GETHIFONTMASK:
@@ -1351,17 +1006,13 @@ int vt_ioctl(struct tty_struct *tty,
 		ret = -ENOIOCTLCMD;
 	}
 out:
-	tty_unlock();
 	return ret;
-eperm:
-	ret = -EPERM;
-	goto out;
 }
 
 void reset_vc(struct vc_data *vc)
 {
 	vc->vc_mode = KD_TEXT;
-	kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+	vt_reset_unicode(vc->vc_num);
 	vc->vt_mode.mode = VT_AUTO;
 	vc->vt_mode.waitv = 0;
 	vc->vt_mode.relsig = 0;
@@ -1384,6 +1035,7 @@ void vc_SAK(struct work_struct *work)
 	console_lock();
 	vc = vc_con->d;
 	if (vc) {
+		/* FIXME: review tty ref counting */
 		tty = vc->port.tty;
 		/*
 		 * SAK should also work in all raw modes and reset
@@ -1516,8 +1168,6 @@ long vt_compat_ioctl(struct tty_struct *tty,
 
 	console = vc->vc_num;
 
-	tty_lock();
-
 	if (!vc_cons_allocated(console)) { 	/* impossible? */
 		ret = -ENOIOCTLCMD;
 		goto out;
@@ -1546,7 +1196,9 @@ long vt_compat_ioctl(struct tty_struct *tty,
 
 	case PIO_UNIMAP:
 	case GIO_UNIMAP:
+		tty_lock();
 		ret = compat_unimap_ioctl(cmd, up, perm, vc);
+		tty_unlock();
 		break;
 
 	/*
@@ -1583,11 +1235,9 @@ long vt_compat_ioctl(struct tty_struct *tty,
 		goto fallback;
 	}
 out:
-	tty_unlock();
 	return ret;
 
 fallback:
-	tty_unlock();
 	return vt_ioctl(tty, cmd, arg);
 }
 
@@ -1773,13 +1423,10 @@ int vt_move_to_console(unsigned int vt, int alloc)
 		return -EIO;
 	}
 	console_unlock();
-	tty_lock();
 	if (vt_waitactive(vt + 1)) {
 		pr_debug("Suspend: Can't switch VCs.");
-		tty_unlock();
 		return -EINTR;
 	}
-	tty_unlock();
 	return prev;
 }
 

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.