Browse Source

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

Pull TTY/Serial merge from Greg Kroah-Hartman:
 "Here's the big tty/serial tree set of changes for 3.8-rc1.

  Contained in here is a bunch more reworks of the tty port layer from
  Jiri and bugfixes from Alan, along with a number of other tty and
  serial driver updates by the various driver authors.

  Also, Jiri has been coerced^Wconvinced to be the co-maintainer of the
  TTY layer, which is much appreciated by me.

  All of these have been in the linux-next tree for a while.

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

Fixed up some trivial conflicts in the staging tree, due to the fwserial
driver having come in both ways (but fixed up a bit in the serial tree),
and the ioctl handling in the dgrp driver having been done slightly
differently (staging tree got that one right, and removed both
TIOCGSOFTCAR and TIOCSSOFTCAR).

* tag 'tty-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (146 commits)
  staging: sb105x: fix potential NULL pointer dereference in mp_chars_in_buffer()
  staging/fwserial: Remove superfluous free
  staging/fwserial: Use WARN_ONCE when port table is corrupted
  staging/fwserial: Destruct embedded tty_port on teardown
  staging/fwserial: Fix build breakage when !CONFIG_BUG
  staging: fwserial: Add TTY-over-Firewire serial driver
  drivers/tty/serial/serial_core.c: clean up HIGH_BITS_OFFSET usage
  staging: dgrp: dgrp_tty.c: Audit the return values of get/put_user()
  staging: dgrp: dgrp_tty.c: Remove the TIOCSSOFTCAR ioctl handler from dgrp driver
  serial: ifx6x60: Add modem power off function in the platform reboot process
  serial: mxs-auart: unmap the scatter list before we copy the data
  serial: mxs-auart: disable the Receive Timeout Interrupt when DMA is enabled
  serial: max310x: Setup missing "can_sleep" field for GPIO
  tty/serial: fix ifx6x60.c declaration warning
  serial: samsung: add devicetree properties for non-Exynos SoCs
  serial: samsung: fix potential soft lockup during uart write
  tty: vt: Remove redundant null check before kfree.
  tty/8250 Add check for pci_ioremap_bar failure
  tty/8250 Add support for Commtech's Fastcom Async-335 and Fastcom Async-PCIe cards
  tty/8250 Add XR17D15x devices to the exar_handle_irq override
  ...
Linus Torvalds 12 years ago
parent
commit
c6bd5bcc49
100 changed files with 6731 additions and 1017 deletions
  1. 112 0
      Documentation/ABI/testing/sysfs-tty
  2. 8 0
      Documentation/devicetree/bindings/tty/serial/fsl-mxs-auart.txt
  3. 4 1
      Documentation/devicetree/bindings/tty/serial/of-serial.txt
  4. 1 0
      MAINTAINERS
  5. 3 0
      arch/alpha/include/asm/ioctls.h
  6. 4 1
      arch/alpha/kernel/srmcons.c
  7. 1 0
      arch/arm/boot/dts/imx28.dtsi
  8. 0 9
      arch/arm/plat-omap/include/plat/serial.h
  9. 1 0
      arch/ia64/hp/sim/simserial.c
  10. 4 2
      arch/m68k/emu/nfcon.c
  11. 3 0
      arch/mips/include/uapi/asm/ioctls.h
  12. 3 0
      arch/parisc/include/uapi/asm/ioctls.h
  13. 3 2
      arch/parisc/kernel/pdc_cons.c
  14. 3 0
      arch/powerpc/include/uapi/asm/ioctls.h
  15. 3 0
      arch/sh/include/uapi/asm/ioctls.h
  16. 3 0
      arch/sparc/include/uapi/asm/ioctls.h
  17. 2 15
      arch/um/drivers/chan_kern.c
  18. 2 0
      arch/um/drivers/line.c
  19. 3 0
      arch/x86/platform/ce4100/ce4100.c
  20. 3 0
      arch/xtensa/include/uapi/asm/ioctls.h
  21. 1 0
      arch/xtensa/platforms/iss/console.c
  22. 1 6
      drivers/bluetooth/hci_ldisc.c
  23. 4 1
      drivers/char/pcmcia/synclink_cs.c
  24. 3 1
      drivers/char/ttyprintk.c
  25. 2 0
      drivers/ipack/devices/ipoctal.c
  26. 17 19
      drivers/isdn/capi/capi.c
  27. 1 0
      drivers/isdn/gigaset/common.c
  28. 4 0
      drivers/isdn/i4l/isdn_tty.c
  29. 5 2
      drivers/misc/pti.c
  30. 11 13
      drivers/mmc/card/sdio_uart.c
  31. 3 2
      drivers/net/usb/hso.c
  32. 1 0
      drivers/s390/char/con3215.c
  33. 3 1
      drivers/s390/char/sclp_tty.c
  34. 2 0
      drivers/s390/char/sclp_vt220.c
  35. 2 0
      drivers/s390/char/tty3270.c
  36. 2 0
      drivers/staging/Kconfig
  37. 1 0
      drivers/staging/Makefile
  38. 4 1
      drivers/staging/ccg/u_serial.c
  39. 0 1
      drivers/staging/dgrp/dgrp_common.h
  40. 0 4
      drivers/staging/dgrp/dgrp_driver.c
  41. 11 62
      drivers/staging/dgrp/dgrp_net_ops.c
  42. 2 2
      drivers/staging/dgrp/dgrp_specproc.c
  43. 0 18
      drivers/staging/dgrp/dgrp_sysfs.c
  44. 12 12
      drivers/staging/dgrp/dgrp_tty.c
  45. 7 10
      drivers/staging/fwserial/fwserial.c
  46. 9 0
      drivers/staging/sb105x/Kconfig
  47. 3 0
      drivers/staging/sb105x/Makefile
  48. 295 0
      drivers/staging/sb105x/sb_mp_register.h
  49. 3196 0
      drivers/staging/sb105x/sb_pci_mp.c
  50. 293 0
      drivers/staging/sb105x/sb_pci_mp.h
  51. 368 0
      drivers/staging/sb105x/sb_ser_core.h
  52. 2 0
      drivers/tty/amiserial.c
  53. 4 2
      drivers/tty/bfin_jtag_comm.c
  54. 15 13
      drivers/tty/cyclades.c
  55. 3 1
      drivers/tty/ehv_bytechan.c
  56. 4 4
      drivers/tty/hvc/hvc_opal.c
  57. 3 3
      drivers/tty/hvc/hvc_vio.c
  58. 1 1
      drivers/tty/hvc/hvc_xen.c
  59. 11 9
      drivers/tty/hvc/hvcs.c
  60. 1 0
      drivers/tty/hvc/hvsi.c
  61. 4 1
      drivers/tty/ipwireless/network.c
  62. 1 0
      drivers/tty/ipwireless/tty.c
  63. 19 16
      drivers/tty/isicom.c
  64. 8 4
      drivers/tty/moxa.c
  65. 22 13
      drivers/tty/mxser.c
  66. 5 6
      drivers/tty/n_gsm.c
  67. 261 215
      drivers/tty/n_tty.c
  68. 14 9
      drivers/tty/nozomi.c
  69. 71 10
      drivers/tty/pty.c
  70. 3 1
      drivers/tty/rocket.c
  71. 2 0
      drivers/tty/serial/68328serial.c
  72. 87 11
      drivers/tty/serial/8250/8250.c
  73. 36 0
      drivers/tty/serial/8250/8250.h
  74. 3 3
      drivers/tty/serial/8250/8250_acorn.c
  75. 28 3
      drivers/tty/serial/8250/8250_dw.c
  76. 23 23
      drivers/tty/serial/8250/8250_early.c
  77. 4 4
      drivers/tty/serial/8250/8250_em.c
  78. 5 5
      drivers/tty/serial/8250/8250_hp300.c
  79. 303 49
      drivers/tty/serial/8250/8250_pci.c
  80. 7 7
      drivers/tty/serial/8250/8250_pnp.c
  81. 36 12
      drivers/tty/serial/Kconfig
  82. 1 0
      drivers/tty/serial/Makefile
  83. 3 3
      drivers/tty/serial/altera_jtaguart.c
  84. 3 3
      drivers/tty/serial/altera_uart.c
  85. 9 16
      drivers/tty/serial/amba-pl011.c
  86. 1 1
      drivers/tty/serial/apbuart.c
  87. 88 8
      drivers/tty/serial/ar933x_uart.c
  88. 746 0
      drivers/tty/serial/arc_uart.c
  89. 5 5
      drivers/tty/serial/atmel_serial.c
  90. 3 3
      drivers/tty/serial/bcm63xx_uart.c
  91. 3 3
      drivers/tty/serial/bfin_sport_uart.c
  92. 14 6
      drivers/tty/serial/bfin_uart.c
  93. 277 318
      drivers/tty/serial/clps711x.c
  94. 2 2
      drivers/tty/serial/cpm_uart/cpm_uart_core.c
  95. 3 3
      drivers/tty/serial/efm32-uart.c
  96. 7 7
      drivers/tty/serial/icom.c
  97. 143 25
      drivers/tty/serial/ifx6x60.c
  98. 2 0
      drivers/tty/serial/ifx6x60.h
  99. 1 1
      drivers/tty/serial/ioc3_serial.c
  100. 5 3
      drivers/tty/serial/jsm/jsm.h

+ 112 - 0
Documentation/ABI/testing/sysfs-tty

@@ -26,3 +26,115 @@ Description:
 		 UART port in serial_core, that is bound to TTY like ttyS0.
 		 uartclk = 16 * baud_base
 
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/type
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Shows the current tty type for this port.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/line
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Shows the current tty line number for this port.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/port
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Shows the current tty port I/O address for this port.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/irq
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Shows the current primary interrupt for this port.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/flags
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Show the tty port status flags for this port.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/xmit_fifo_size
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Show the transmit FIFO size for this port.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/close_delay
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Show the closing delay time for this port in ms.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/closing_wait
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Show the close wait time for this port in ms.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/custom_divisor
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Show the custom divisor if any that is set on this port.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/io_type
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Show the I/O type that is to be used with the iomem base
+		 address.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/iomem_base
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 The I/O memory base for this port.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.
+
+What:		/sys/class/tty/ttyS0/iomem_reg_shift
+Date:		October 2012
+Contact:	Alan Cox <alan@linux.intel.com>
+Description:
+		 Show the register shift indicating the spacing to be used
+		 for accesses on this iomem address.
+
+		 These sysfs values expose the TIOCGSERIAL interface via
+		 sysfs rather than via ioctls.

+ 8 - 0
Documentation/devicetree/bindings/tty/serial/fsl-mxs-auart.txt

@@ -6,11 +6,19 @@ Required properties:
 - reg : Address and length of the register set for the device
 - interrupts : Should contain the auart interrupt numbers
 
+Optional properties:
+- fsl,auart-dma-channel : The DMA channels, the first is for RX, the other
+		is for TX. If you add this property, it also means that you
+		will enable the DMA support for the auart.
+		Note: due to the hardware bug in imx23(see errata : 2836),
+		only the imx28 can enable the DMA support for the auart.
+
 Example:
 auart0: serial@8006a000 {
 	compatible = "fsl,imx28-auart", "fsl,imx23-auart";
 	reg = <0x8006a000 0x2000>;
 	interrupts = <112 70 71>;
+	fsl,auart-dma-channel = <8 9>;
 };
 
 Note: Each auart port should have an alias correctly numbered in "aliases"

+ 4 - 1
Documentation/devicetree/bindings/tty/serial/of-serial.txt

@@ -14,7 +14,10 @@ Required properties:
 	- "serial" if the port type is unknown.
 - reg : offset and length of the register set for the device.
 - interrupts : should contain uart interrupt.
-- clock-frequency : the input clock frequency for the UART.
+- clock-frequency : the input clock frequency for the UART
+	 or
+  clocks phandle to refer to the clk used as per Documentation/devicetree
+  /bindings/clock/clock-bindings.txt
 
 Optional properties:
 - current-speed : the current active speed of the UART.

+ 1 - 0
MAINTAINERS

@@ -7430,6 +7430,7 @@ K:	^Subject:.*(?i)trivial
 
 TTY LAYER
 M:	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+M:	Jiri Slaby <jslaby@suse.cz>
 S:	Supported
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 F:	drivers/tty/

+ 3 - 0
arch/alpha/include/asm/ioctls.h

@@ -95,6 +95,9 @@
 #define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 #define TIOCVHANGUP	0x5437
+#define TIOCGPKT	_IOR('T', 0x38, int) /* Get packet mode state */
+#define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
+#define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 
 #define TIOCSERCONFIG	0x5453
 #define TIOCSERGWILD	0x5454

+ 4 - 1
arch/alpha/kernel/srmcons.c

@@ -205,7 +205,6 @@ 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) {
@@ -215,6 +214,9 @@ srmcons_init(void)
 		driver = alloc_tty_driver(MAX_SRM_CONSOLE_DEVICES);
 		if (!driver)
 			return -ENOMEM;
+
+		tty_port_init(&srmcons_singleton.port);
+
 		driver->driver_name = "srm";
 		driver->name = "srm";
 		driver->major = 0; 	/* dynamic */
@@ -227,6 +229,7 @@ srmcons_init(void)
 		err = tty_register_driver(driver);
 		if (err) {
 			put_tty_driver(driver);
+			tty_port_destroy(&srmcons_singleton.port);
 			return err;
 		}
 		srmcons_driver = driver;

+ 1 - 0
arch/arm/boot/dts/imx28.dtsi

@@ -799,6 +799,7 @@
 				compatible = "fsl,imx28-auart", "fsl,imx23-auart";
 				reg = <0x8006a000 0x2000>;
 				interrupts = <112 70 71>;
+				fsl,auart-dma-channel = <8 9>;
 				clocks = <&clks 45>;
 				status = "disabled";
 			};

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

@@ -109,15 +109,6 @@
 #define OMAP5UART4		OMAP4UART4
 #define ZOOM_UART		95		/* Only on zoom2/3 */
 
-/* This is only used by 8250.c for omap1510 */
-#define is_omap_port(pt)	({int __ret = 0;			\
-			if ((pt)->port.mapbase == OMAP1_UART1_BASE ||	\
-			    (pt)->port.mapbase == OMAP1_UART2_BASE ||	\
-			    (pt)->port.mapbase == OMAP1_UART3_BASE)	\
-				__ret = 1;				\
-			__ret;						\
-			})
-
 #ifndef __ASSEMBLER__
 
 struct omap_board_data;

+ 1 - 0
arch/ia64/hp/sim/simserial.c

@@ -555,6 +555,7 @@ static int __init simrs_init(void)
 	return 0;
 err_free_tty:
 	put_tty_driver(hp_simserial_driver);
+	tty_port_destroy(&state->port);
 	return retval;
 }
 

+ 4 - 2
arch/m68k/emu/nfcon.c

@@ -120,8 +120,6 @@ static int __init nfcon_init(void)
 {
 	int res;
 
-	tty_port_init(&nfcon_tty_port);
-
 	stderr_id = nf_get_id("NF_STDERR");
 	if (!stderr_id)
 		return -ENODEV;
@@ -130,6 +128,8 @@ static int __init nfcon_init(void)
 	if (!nfcon_tty_driver)
 		return -ENOMEM;
 
+	tty_port_init(&nfcon_tty_port);
+
 	nfcon_tty_driver->driver_name = "nfcon";
 	nfcon_tty_driver->name = "nfcon";
 	nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
@@ -143,6 +143,7 @@ static int __init nfcon_init(void)
 	if (res) {
 		pr_err("failed to register nfcon tty driver\n");
 		put_tty_driver(nfcon_tty_driver);
+		tty_port_destroy(&nfcon_tty_port);
 		return res;
 	}
 
@@ -157,6 +158,7 @@ static void __exit nfcon_exit(void)
 	unregister_console(&nf_console);
 	tty_unregister_driver(nfcon_tty_driver);
 	put_tty_driver(nfcon_tty_driver);
+	tty_port_destroy(&nfcon_tty_port);
 }
 
 module_init(nfcon_init);

+ 3 - 0
arch/mips/include/uapi/asm/ioctls.h

@@ -86,6 +86,9 @@
 #define TIOCGDEV	_IOR('T', 0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T', 0x36, int)  /* Generate signal on Pty slave */
 #define TIOCVHANGUP	0x5437
+#define TIOCGPKT	_IOR('T', 0x38, int) /* Get packet mode state */
+#define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
+#define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 
 /* I hope the range from 0x5480 on is free ... */
 #define TIOCSCTTY	0x5480		/* become controlling tty */

+ 3 - 0
arch/parisc/include/uapi/asm/ioctls.h

@@ -55,6 +55,9 @@
 #define TIOCGDEV	_IOR('T',0x32, int)  /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 #define TIOCVHANGUP	0x5437
+#define TIOCGPKT	_IOR('T', 0x38, int) /* Get packet mode state */
+#define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
+#define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 
 #define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
 #define FIOCLEX		0x5451

+ 3 - 2
arch/parisc/kernel/pdc_cons.c

@@ -186,13 +186,13 @@ 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;
 
-	tty_port_init(&tty_port);
-
 	pdc_console_tty_driver = alloc_tty_driver(1);
 
 	if (!pdc_console_tty_driver)
 		return -ENOMEM;
 
+	tty_port_init(&tty_port);
+
 	pdc_console_tty_driver->driver_name = "pdc_cons";
 	pdc_console_tty_driver->name = "ttyB";
 	pdc_console_tty_driver->major = MUX_MAJOR;
@@ -207,6 +207,7 @@ static int __init pdc_console_tty_driver_init(void)
 	err = tty_register_driver(pdc_console_tty_driver);
 	if (err) {
 		printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
+		tty_port_destroy(&tty_port);
 		return err;
 	}
 

+ 3 - 0
arch/powerpc/include/uapi/asm/ioctls.h

@@ -97,6 +97,9 @@
 #define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 #define TIOCVHANGUP	0x5437
+#define TIOCGPKT	_IOR('T', 0x38, int) /* Get packet mode state */
+#define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
+#define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 
 #define TIOCSERCONFIG	0x5453
 #define TIOCSERGWILD	0x5454

+ 3 - 0
arch/sh/include/uapi/asm/ioctls.h

@@ -88,6 +88,9 @@
 #define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 #define TIOCVHANGUP	_IO('T', 0x37)
+#define TIOCGPKT	_IOR('T', 0x38, int) /* Get packet mode state */
+#define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
+#define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 
 #define TIOCSERCONFIG	_IO('T', 83) /* 0x5453 */
 #define TIOCSERGWILD	_IOR('T', 84,  int) /* 0x5454 */

+ 3 - 0
arch/sparc/include/uapi/asm/ioctls.h

@@ -21,6 +21,9 @@
 #define TCSETSF2	_IOW('T', 15, struct termios2)
 #define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCVHANGUP	_IO('T', 0x37)
+#define TIOCGPKT	_IOR('T', 0x38, int) /* Get packet mode state */
+#define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
+#define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 
 /* Note that all the ioctls that are not available in Linux have a 
  * double underscore on the front to: a) avoid some programs to

+ 2 - 15
arch/um/drivers/chan_kern.c

@@ -83,21 +83,8 @@ static const struct chan_ops not_configged_ops = {
 
 static void tty_receive_char(struct tty_struct *tty, char ch)
 {
-	if (tty == NULL)
-		return;
-
-	if (I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
-		if (ch == STOP_CHAR(tty)) {
-			stop_tty(tty);
-			return;
-		}
-		else if (ch == START_CHAR(tty)) {
-			start_tty(tty);
-			return;
-		}
-	}
-
-	tty_insert_flip_char(tty, ch, TTY_NORMAL);
+	if (tty)
+		tty_insert_flip_char(tty, ch, TTY_NORMAL);
 }
 
 static int open_one_chan(struct chan *chan)

+ 2 - 0
arch/um/drivers/line.c

@@ -584,6 +584,8 @@ int register_lines(struct line_driver *line_driver,
 		printk(KERN_ERR "register_lines : can't register %s driver\n",
 		       line_driver->name);
 		put_tty_driver(driver);
+		for (i = 0; i < nlines; i++)
+			tty_port_destroy(&lines[i].port);
 		return err;
 	}
 

+ 3 - 0
arch/x86/platform/ce4100/ce4100.c

@@ -105,8 +105,11 @@ static void ce4100_serial_fixup(int port, struct uart_port *up,
 		up->membase =
 			(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
 		up->membase += up->mapbase & ~PAGE_MASK;
+		up->mapbase += port * 0x100;
+		up->membase += port * 0x100;
 		up->iotype   = UPIO_MEM32;
 		up->regshift = 2;
+		up->irq = 4;
 	}
 #endif
 	up->iobase = 0;

+ 3 - 0
arch/xtensa/include/uapi/asm/ioctls.h

@@ -101,6 +101,9 @@
 #define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
 #define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
 #define TIOCVHANGUP	_IO('T', 0x37)
+#define TIOCGPKT	_IOR('T', 0x38, int) /* Get packet mode state */
+#define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
+#define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 
 #define TIOCSERCONFIG	_IO('T', 83)
 #define TIOCSERGWILD	_IOR('T', 84,  int)

+ 1 - 0
arch/xtensa/platforms/iss/console.c

@@ -221,6 +221,7 @@ static __exit void rs_exit(void)
 		printk("ISS_SERIAL: failed to unregister serial driver (%d)\n",
 		       error);
 	put_tty_driver(serial_driver);
+	tty_port_destroy(&serial_port);
 }
 
 

+ 1 - 6
drivers/bluetooth/hci_ldisc.c

@@ -270,15 +270,10 @@ static int hci_uart_send_frame(struct sk_buff *skb)
  */
 static int hci_uart_tty_open(struct tty_struct *tty)
 {
-	struct hci_uart *hu = (void *) tty->disc_data;
+	struct hci_uart *hu;
 
 	BT_DBG("tty %p", tty);
 
-	/* FIXME: This btw is bogus, nothing requires the old ldisc to clear
-	   the pointer */
-	if (hu)
-		return -EEXIST;
-
 	/* Error if the tty has no write op instead of leaving an exploitable
 	   hole */
 	if (tty->ops->write == NULL)

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

@@ -549,8 +549,10 @@ static int mgslpc_probe(struct pcmcia_device *link)
     /* Initialize the struct pcmcia_device structure */
 
     ret = mgslpc_config(link);
-    if (ret)
+    if (ret) {
+	    tty_port_destroy(&info->port);
 	    return ret;
+    }
 
     mgslpc_add_device(info);
 
@@ -2757,6 +2759,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
 			hdlcdev_exit(info);
 #endif
 			release_resources(info);
+			tty_port_destroy(&info->port);
 			kfree(info);
 			mgslpc_device_count--;
 			return;

+ 3 - 1
drivers/char/ttyprintk.c

@@ -179,7 +179,6 @@ static int __init ttyprintk_init(void)
 {
 	int ret = -ENOMEM;
 
-	tty_port_init(&tpk_port.port);
 	tpk_port.port.ops = &null_ops;
 	mutex_init(&tpk_port.port_write_mutex);
 
@@ -190,6 +189,8 @@ static int __init ttyprintk_init(void)
 	if (IS_ERR(ttyprintk_driver))
 		return PTR_ERR(ttyprintk_driver);
 
+	tty_port_init(&tpk_port.port);
+
 	ttyprintk_driver->driver_name = "ttyprintk";
 	ttyprintk_driver->name = "ttyprintk";
 	ttyprintk_driver->major = TTYAUX_MAJOR;
@@ -211,6 +212,7 @@ static int __init ttyprintk_init(void)
 error:
 	tty_unregister_driver(ttyprintk_driver);
 	put_tty_driver(ttyprintk_driver);
+	tty_port_destroy(&tpk_port.port);
 	ttyprintk_driver = NULL;
 	return ret;
 }

+ 2 - 0
drivers/ipack/devices/ipoctal.c

@@ -415,6 +415,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
 		tty_dev = tty_port_register_device(&channel->tty_port, tty, i, NULL);
 		if (IS_ERR(tty_dev)) {
 			dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n");
+			tty_port_destroy(&channel->tty_port);
 			continue;
 		}
 		dev_set_drvdata(tty_dev, channel);
@@ -700,6 +701,7 @@ static void __ipoctal_remove(struct ipoctal *ipoctal)
 		struct ipoctal_channel *channel = &ipoctal->channel[i];
 		tty_unregister_device(ipoctal->tty_drv, i);
 		tty_port_free_xmit_buf(&channel->tty_port);
+		tty_port_destroy(&channel->tty_port);
 	}
 
 	tty_unregister_driver(ipoctal->tty_drv);

+ 17 - 19
drivers/isdn/capi/capi.c

@@ -77,8 +77,6 @@ struct ackqueue_entry {
 };
 
 struct capiminor {
-	struct kref kref;
-
 	unsigned int      minor;
 
 	struct capi20_appl	*ap;
@@ -190,7 +188,20 @@ static void capiminor_del_all_ack(struct capiminor *mp)
 
 /* -------- struct capiminor ---------------------------------------- */
 
-static const struct tty_port_operations capiminor_port_ops; /* we have none */
+static void capiminor_destroy(struct tty_port *port)
+{
+	struct capiminor *mp = container_of(port, struct capiminor, port);
+
+	kfree_skb(mp->outskb);
+	skb_queue_purge(&mp->inqueue);
+	skb_queue_purge(&mp->outqueue);
+	capiminor_del_all_ack(mp);
+	kfree(mp);
+}
+
+static const struct tty_port_operations capiminor_port_ops = {
+	.destruct = capiminor_destroy,
+};
 
 static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
 {
@@ -204,8 +215,6 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
 		return NULL;
 	}
 
-	kref_init(&mp->kref);
-
 	mp->ap = ap;
 	mp->ncci = ncci;
 	INIT_LIST_HEAD(&mp->ackqueue);
@@ -247,21 +256,10 @@ err_out2:
 	spin_unlock(&capiminors_lock);
 
 err_out1:
-	kfree(mp);
+	tty_port_put(&mp->port);
 	return NULL;
 }
 
-static void capiminor_destroy(struct kref *kref)
-{
-	struct capiminor *mp = container_of(kref, struct capiminor, kref);
-
-	kfree_skb(mp->outskb);
-	skb_queue_purge(&mp->inqueue);
-	skb_queue_purge(&mp->outqueue);
-	capiminor_del_all_ack(mp);
-	kfree(mp);
-}
-
 static struct capiminor *capiminor_get(unsigned int minor)
 {
 	struct capiminor *mp;
@@ -269,7 +267,7 @@ static struct capiminor *capiminor_get(unsigned int minor)
 	spin_lock(&capiminors_lock);
 	mp = capiminors[minor];
 	if (mp)
-		kref_get(&mp->kref);
+		tty_port_get(&mp->port);
 	spin_unlock(&capiminors_lock);
 
 	return mp;
@@ -277,7 +275,7 @@ static struct capiminor *capiminor_get(unsigned int minor)
 
 static inline void capiminor_put(struct capiminor *mp)
 {
-	kref_put(&mp->kref, capiminor_destroy);
+	tty_port_put(&mp->port);
 }
 
 static void capiminor_free(struct capiminor *mp)

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

@@ -507,6 +507,7 @@ void gigaset_freecs(struct cardstate *cs)
 		gig_dbg(DEBUG_INIT, "clearing at_state");
 		clear_at_state(&cs->at_state);
 		dealloc_temp_at_states(cs);
+		tty_port_destroy(&cs->port);
 
 		/* fall through */
 	case 0:	/* error in basic setup */

+ 4 - 0
drivers/isdn/i4l/isdn_tty.c

@@ -1849,6 +1849,8 @@ err_unregister:
 		kfree(info->fax);
 #endif
 		kfree(info->port.xmit_buf - 4);
+		info->port.xmit_buf = NULL;
+		tty_port_destroy(&info->port);
 	}
 	tty_unregister_driver(m->tty_modem);
 err:
@@ -1870,6 +1872,8 @@ isdn_tty_exit(void)
 		kfree(info->fax);
 #endif
 		kfree(info->port.xmit_buf - 4);
+		info->port.xmit_buf = NULL;
+		tty_port_destroy(&info->port);
 	}
 	tty_unregister_driver(dev->mdm.tty_modem);
 	put_tty_driver(dev->mdm.tty_modem);

+ 5 - 2
drivers/misc/pti.c

@@ -882,11 +882,14 @@ err:
 static void pti_pci_remove(struct pci_dev *pdev)
 {
 	struct pti_dev *drv_data = pci_get_drvdata(pdev);
+	unsigned int a;
 
 	unregister_console(&pti_console);
 
-	tty_unregister_device(pti_tty_driver, 0);
-	tty_unregister_device(pti_tty_driver, 1);
+	for (a = 0; a < PTITTY_MINOR_NUM; a++) {
+		tty_unregister_device(pti_tty_driver, a);
+		tty_port_destroy(&drv_data->port[a]);
+	}
 
 	iounmap(drv_data->pti_ioaddr);
 	pci_set_drvdata(pdev, NULL);

+ 11 - 13
drivers/mmc/card/sdio_uart.c

@@ -66,8 +66,6 @@ struct uart_icount {
 
 struct sdio_uart_port {
 	struct tty_port		port;
-	struct kref		kref;
-	struct tty_struct	*tty;
 	unsigned int		index;
 	struct sdio_func	*func;
 	struct mutex		func_lock;
@@ -93,7 +91,6 @@ static int sdio_uart_add_port(struct sdio_uart_port *port)
 {
 	int index, ret = -EBUSY;
 
-	kref_init(&port->kref);
 	mutex_init(&port->func_lock);
 	spin_lock_init(&port->write_lock);
 	if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL))
@@ -123,23 +120,15 @@ static struct sdio_uart_port *sdio_uart_port_get(unsigned index)
 	spin_lock(&sdio_uart_table_lock);
 	port = sdio_uart_table[index];
 	if (port)
-		kref_get(&port->kref);
+		tty_port_get(&port->port);
 	spin_unlock(&sdio_uart_table_lock);
 
 	return port;
 }
 
-static void sdio_uart_port_destroy(struct kref *kref)
-{
-	struct sdio_uart_port *port =
-		container_of(kref, struct sdio_uart_port, kref);
-	kfifo_free(&port->xmit_fifo);
-	kfree(port);
-}
-
 static void sdio_uart_port_put(struct sdio_uart_port *port)
 {
-	kref_put(&port->kref, sdio_uart_port_destroy);
+	tty_port_put(&port->port);
 }
 
 static void sdio_uart_port_remove(struct sdio_uart_port *port)
@@ -737,6 +726,14 @@ static void sdio_uart_shutdown(struct tty_port *tport)
 	sdio_uart_release_func(port);
 }
 
+static void sdio_uart_port_destroy(struct tty_port *tport)
+{
+	struct sdio_uart_port *port =
+		container_of(tport, struct sdio_uart_port, port);
+	kfifo_free(&port->xmit_fifo);
+	kfree(port);
+}
+
 /**
  *	sdio_uart_install	-	install method
  *	@driver: the driver in use (sdio_uart in our case)
@@ -1045,6 +1042,7 @@ static const struct tty_port_operations sdio_uart_port_ops = {
 	.carrier_raised = uart_carrier_raised,
 	.shutdown = sdio_uart_shutdown,
 	.activate = sdio_uart_activate,
+	.destruct = sdio_uart_port_destroy,
 };
 
 static const struct tty_operations sdio_uart_ops = {

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

@@ -2274,6 +2274,7 @@ static void hso_serial_common_free(struct hso_serial *serial)
 	/* unlink and free TX URB */
 	usb_free_urb(serial->tx_urb);
 	kfree(serial->tx_data);
+	tty_port_destroy(&serial->port);
 }
 
 static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
@@ -2283,12 +2284,12 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
 	int minor;
 	int i;
 
+	tty_port_init(&serial->port);
+
 	minor = get_free_serial_index();
 	if (minor < 0)
 		goto exit;
 
-	tty_port_init(&serial->port);
-
 	/* register our minor number */
 	serial->parent->dev = tty_port_register_device(&serial->port, tty_drv,
 			minor, &serial->parent->interface->dev);

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

@@ -677,6 +677,7 @@ static void raw3215_free_info(struct raw3215_info *raw)
 {
 	kfree(raw->inbuf);
 	kfree(raw->buffer);
+	tty_port_destroy(&raw->port);
 	kfree(raw);
 }
 

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

@@ -547,7 +547,6 @@ sclp_tty_init(void)
 		sclp_tty_tolower = 1;
 	}
 	sclp_tty_chars_count = 0;
-	tty_port_init(&sclp_port);
 
 	rc = sclp_register(&sclp_input_event);
 	if (rc) {
@@ -555,6 +554,8 @@ sclp_tty_init(void)
 		return rc;
 	}
 
+	tty_port_init(&sclp_port);
+
 	driver->driver_name = "sclp_line";
 	driver->name = "sclp_line";
 	driver->major = TTY_MAJOR;
@@ -571,6 +572,7 @@ sclp_tty_init(void)
 	rc = tty_register_driver(driver);
 	if (rc) {
 		put_tty_driver(driver);
+		tty_port_destroy(&sclp_port);
 		return rc;
 	}
 	sclp_tty_driver = driver;

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

@@ -615,6 +615,7 @@ static void __init __sclp_vt220_cleanup(void)
 		return;
 	sclp_unregister(&sclp_vt220_register);
 	__sclp_vt220_free_pages();
+	tty_port_destroy(&sclp_vt220_port);
 }
 
 /* Allocate buffer pages and register with sclp core. Controlled by init
@@ -650,6 +651,7 @@ out:
 	if (rc) {
 		__sclp_vt220_free_pages();
 		sclp_vt220_init_count--;
+		tty_port_destroy(&sclp_vt220_port);
 	}
 	return rc;
 }

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

@@ -722,6 +722,7 @@ out_pages:
 	while (pages--)
 		free_pages((unsigned long) tp->freemem_pages[pages], 0);
 	kfree(tp->freemem_pages);
+	tty_port_destroy(&tp->port);
 out_tp:
 	kfree(tp);
 out_err:
@@ -744,6 +745,7 @@ tty3270_free_view(struct tty3270 *tp)
 	for (pages = 0; pages < TTY3270_STRING_PAGES; pages++)
 		free_pages((unsigned long) tp->freemem_pages[pages], 0);
 	kfree(tp->freemem_pages);
+	tty_port_destroy(&tp->port);
 	kfree(tp);
 }
 

+ 2 - 0
drivers/staging/Kconfig

@@ -138,6 +138,8 @@ source "drivers/staging/imx-drm/Kconfig"
 
 source "drivers/staging/dgrp/Kconfig"
 
+source "drivers/staging/sb105x/Kconfig"
+
 source "drivers/staging/fwserial/Kconfig"
 
 endif # STAGING

+ 1 - 0
drivers/staging/Makefile

@@ -61,4 +61,5 @@ obj-$(CONFIG_NET_VENDOR_SILICOM)	+= silicom/
 obj-$(CONFIG_CED1401)		+= ced1401/
 obj-$(CONFIG_DRM_IMX)		+= imx-drm/
 obj-$(CONFIG_DGRP)		+= dgrp/
+obj-$(CONFIG_SB105X)		+= sb105x/
 obj-$(CONFIG_FIREWIRE_SERIAL)	+= fwserial/

+ 4 - 1
drivers/staging/ccg/u_serial.c

@@ -1140,8 +1140,10 @@ int gserial_setup(struct usb_gadget *g, unsigned count)
 
 	return status;
 fail:
-	while (count--)
+	while (count--) {
+		tty_port_destroy(&ports[count].port->port);
 		kfree(ports[count].port);
+	}
 	put_tty_driver(gs_tty_driver);
 	gs_tty_driver = NULL;
 	return status;
@@ -1195,6 +1197,7 @@ void gserial_cleanup(void)
 
 		WARN_ON(port->port_usb != NULL);
 
+		tty_port_destroy(&port->port);
 		kfree(port);
 	}
 	n_ports = 0;

+ 0 - 1
drivers/staging/dgrp/dgrp_common.h

@@ -31,7 +31,6 @@
  * All global storage allocation.
  ************************************************************************/
 
-extern int dgrp_rawreadok;  /* Allow raw writing of input */
 extern int dgrp_register_cudevices; /* enable legacy cu devices */
 extern int dgrp_register_prdevices; /* enable transparent print devices */
 extern int dgrp_poll_tick;          /* Poll interval - in ms */

+ 0 - 4
drivers/staging/dgrp/dgrp_driver.c

@@ -39,14 +39,10 @@ MODULE_VERSION(DIGI_VERSION);
 struct list_head nd_struct_list;
 struct dgrp_poll_data dgrp_poll_data;
 
-int dgrp_rawreadok = 1;		/* Bypass flipbuf on input */
 int dgrp_register_cudevices = 1;/* Turn on/off registering legacy cu devices */
 int dgrp_register_prdevices = 1;/* Turn on/off registering transparent print */
 int dgrp_poll_tick = 20;	/* Poll interval - in ms */
 
-module_param_named(rawreadok, dgrp_rawreadok, int, 0644);
-MODULE_PARM_DESC(rawreadok, "Bypass flip buffers on input");
-
 module_param_named(register_cudevices, dgrp_register_cudevices, int, 0644);
 MODULE_PARM_DESC(register_cudevices, "Turn on/off registering legacy cu devices");
 

+ 11 - 62
drivers/staging/dgrp/dgrp_net_ops.c

@@ -151,20 +151,15 @@ static void dgrp_read_data_block(struct ch_struct *ch, u8 *flipbuf,
  * Copys the rbuf to the flipbuf and sends to line discipline.
  * Sends input buffer data to the line discipline.
  *
- * There are several modes to consider here:
- *    rawreadok, tty->real_raw, and IF_PARMRK
  */
 static void dgrp_input(struct ch_struct *ch)
 {
 	struct nd_struct *nd;
 	struct tty_struct *tty;
-	int remain;
 	int data_len;
 	int len;
-	int flip_len;
 	int tty_count;
 	ulong lock_flags;
-	struct tty_ldisc *ld;
 	u8  *myflipbuf;
 	u8  *myflipflagbuf;
 
@@ -212,37 +207,11 @@ static void dgrp_input(struct ch_struct *ch)
 
 	spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
 
-	/* Decide how much data we can send into the tty layer */
-	if (dgrp_rawreadok && tty->real_raw)
-		flip_len = MYFLIPLEN;
-	else
-		flip_len = TTY_FLIPBUF_SIZE;
-
 	/* data_len should be the number of chars that we read in */
 	data_len = (ch->ch_rin - ch->ch_rout) & RBUF_MASK;
-	remain = data_len;
 
 	/* len is the amount of data we are going to transfer here */
-	len = min(data_len, flip_len);
-
-	/* take into consideration length of ldisc */
-	len = min(len, (N_TTY_BUF_SIZE - 1) - tty->read_cnt);
-
-	ld = tty_ldisc_ref(tty);
-
-	/*
-	 * If we were unable to get a reference to the ld,
-	 * don't flush our buffer, and act like the ld doesn't
-	 * have any space to put the data right now.
-	 */
-	if (!ld) {
-		len = 0;
-	} else if (!ld->ops->receive_buf) {
-		spin_lock_irqsave(&nd->nd_lock, lock_flags);
-		ch->ch_rout = ch->ch_rin;
-		spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
-		len = 0;
-	}
+	len = tty_buffer_request_room(tty, data_len);
 
 	/* Check DPA flow control */
 	if ((nd->nd_dpa_debug) &&
@@ -254,42 +223,22 @@ static void dgrp_input(struct ch_struct *ch)
 
 		dgrp_read_data_block(ch, myflipbuf, len);
 
-		/*
-		 * In high performance mode, we don't have to update
-		 * flag_buf or any of the counts or pointers into flip buf.
-		 */
-		if (!dgrp_rawreadok || !tty->real_raw) {
-			if (I_PARMRK(tty) || I_BRKINT(tty) || I_INPCK(tty))
-				parity_scan(ch, myflipbuf, myflipflagbuf, &len);
-			else
-				memset(myflipflagbuf, TTY_NORMAL, len);
-		}
+		if (I_PARMRK(tty) || I_BRKINT(tty) || I_INPCK(tty))
+			parity_scan(ch, myflipbuf, myflipflagbuf, &len);
+		else
+			memset(myflipflagbuf, TTY_NORMAL, len);
 
 		if ((nd->nd_dpa_debug) &&
 		    (nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(tty)))))
 			dgrp_dpa_data(nd, 1, myflipbuf, len);
 
-		/*
-		 * If we're doing raw reads, jam it right into the
-		 * line disc bypassing the flip buffers.
-		 */
-		if (dgrp_rawreadok && tty->real_raw)
-			ld->ops->receive_buf(tty, myflipbuf, NULL, len);
-		else {
-			len = tty_buffer_request_room(tty, len);
-			tty_insert_flip_string_flags(tty, myflipbuf,
-						     myflipflagbuf, len);
-
-			/* Tell the tty layer its okay to "eat" the data now */
-			tty_flip_buffer_push(tty);
-		}
+		tty_insert_flip_string_flags(tty, myflipbuf,
+					     myflipflagbuf, len);
+		tty_flip_buffer_push(tty);
 
 		ch->ch_rxcount += len;
 	}
 
-	if (ld)
-		tty_ldisc_deref(ld);
-
 	/*
 	 * Wake up any sleepers (maybe dgrp close) that might be waiting
 	 * for a channel flag state change.
@@ -2549,7 +2498,7 @@ data:
 
 			/*
 			 *  Fabricate and insert a data packet header to
-			 *  preceed the remaining data when it comes in.
+			 *  preced the remaining data when it comes in.
 			 */
 
 			if (remain < plen) {
@@ -2718,7 +2667,7 @@ data:
 						}
 
 						/*
-						 *  Handle delayed response arrival preceeding
+						 *  Handle delayed response arrival preceding
 						 *  the open response we are waiting for.
 						 */
 
@@ -3556,7 +3505,7 @@ void dgrp_poll_handler(unsigned long arg)
 		/*
 		 * Decrement statistics.  These are only for use with
 		 * KME, so don't worry that the operations are done
-		 * unlocked, and so the results are occassionally wrong.
+		 * unlocked, and so the results are occasionally wrong.
 		 */
 
 		nd->nd_read_count -= (nd->nd_read_count +

+ 2 - 2
drivers/staging/dgrp/dgrp_specproc.c

@@ -629,8 +629,6 @@ static int info_proc_show(struct seq_file *m, void *v)
 {
 	seq_printf(m, "version: %s\n", DIGI_VERSION);
 	seq_puts(m, "register_with_sysfs: 1\n");
-	seq_printf(m, "rawreadok: 0x%08x\t(%d)\n",
-		   dgrp_rawreadok, dgrp_rawreadok);
 	seq_printf(m, "pollrate: 0x%08x\t(%d)\n",
 		   dgrp_poll_tick, dgrp_poll_tick);
 
@@ -754,6 +752,8 @@ static int dgrp_add_id(long id)
 
 	return 0;
 
+	/* FIXME this guy should free the tty driver stored in nd and destroy
+	 * all channel ports */
 error_out:
 	kfree(nd);
 	return ret;

+ 0 - 18
drivers/staging/dgrp/dgrp_sysfs.c

@@ -54,23 +54,6 @@ static DEVICE_ATTR(register_with_sysfs, 0400,
 		   dgrp_class_register_with_sysfs_show, NULL);
 
 
-static ssize_t dgrp_class_rawreadok_show(struct device *c,
-					 struct device_attribute *attr,
-					 char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_rawreadok);
-}
-static ssize_t dgrp_class_rawreadok_store(struct device *c,
-					  struct device_attribute *attr,
-					  const char *buf, size_t count)
-{
-	sscanf(buf, "0x%x\n", &dgrp_rawreadok);
-	return count;
-}
-static DEVICE_ATTR(rawreadok, 0600, dgrp_class_rawreadok_show,
-		   dgrp_class_rawreadok_store);
-
-
 static ssize_t dgrp_class_pollrate_show(struct device *c,
 					struct device_attribute *attr,
 					char *buf)
@@ -90,7 +73,6 @@ static DEVICE_ATTR(pollrate, 0600, dgrp_class_pollrate_show,
 
 static struct attribute *dgrp_sysfs_global_settings_entries[] = {
 	&dev_attr_pollrate.attr,
-	&dev_attr_rawreadok.attr,
 	&dev_attr_register_with_sysfs.attr,
 	NULL
 };

+ 12 - 12
drivers/staging/dgrp/dgrp_tty.c

@@ -432,7 +432,7 @@ static void drp_param(struct ch_struct *ch)
 	/*
 	 * From the POSIX.1 spec (7.1.2.6): "If {_POSIX_VDISABLE}
 	 * is defined for the terminal device file, and the value
-	 * of one of the changable special control characters (see
+	 * of one of the changeable special control characters (see
 	 * 7.1.1.9) is {_POSIX_VDISABLE}, that function shall be
 	 * disabled, that is, no input data shall be recognized as
 	 * the disabled special character."
@@ -2265,9 +2265,7 @@ static int get_modem_info(struct ch_struct *ch, unsigned int *value)
 		| ((mlast & DM_RI)  ? TIOCM_RNG : 0)
 		| ((mlast & DM_DSR) ? TIOCM_DSR : 0)
 		| ((mlast & DM_CTS) ? TIOCM_CTS : 0);
-	put_user(mlast, (unsigned int __user *) value);
-
-	return 0;
+	return put_user(mlast, (unsigned int __user *) value);
 }
 
 /*
@@ -2285,7 +2283,8 @@ static int set_modem_info(struct ch_struct *ch, unsigned int command,
 	if (error == 0)
 		return -EFAULT;
 
-	get_user(arg, (unsigned int __user *) value);
+	if (get_user(arg, (unsigned int __user *) value))
+		return -EFAULT;
 	mval |= ((arg & TIOCM_RTS) ? DM_RTS : 0)
 		| ((arg & TIOCM_DTR) ? DM_DTR : 0);
 
@@ -2684,7 +2683,7 @@ static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
 	- looking at the tty_ioctl code, these command all call our
 	tty_set_termios at the driver's end, when a TCSETA* is sent,
 	it is expecting the tty to have a termio structure,
-	NOT a termios stucture.  These two structures differ in size
+	NOT a termios structure.  These two structures differ in size
 	and the tty_ioctl code does a conversion before processing them both.
 	- we should treat the TCSETAW TCSETAF ioctls the same, and let
 	the tty_ioctl code do the conversion stuff.
@@ -2836,17 +2835,16 @@ static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
 		break;
 
 	case DIGI_GETCUSTOMBAUD:
-		rc = access_ok(VERIFY_WRITE, (void __user *) arg, sizeof(int));
-		if (rc == 0)
+		if (put_user(ch->ch_custom_speed, (unsigned int __user *) arg))
 			return -EFAULT;
-		put_user(ch->ch_custom_speed, (unsigned int __user *) arg);
 		break;
 
 	case DIGI_SETCUSTOMBAUD:
 	{
 		int new_rate;
 
-		get_user(new_rate, (unsigned int __user *) arg);
+		if (get_user(new_rate, (unsigned int __user *) arg))
+			return -EFAULT;
 		dgrp_set_custom_speed(ch, new_rate);
 
 		break;
@@ -2981,7 +2979,7 @@ static void dgrp_tty_start(struct tty_struct *tty)
 }
 
 /*
- *	Stop the reciever
+ *	Stop the receiver
  */
 static void dgrp_tty_input_stop(struct tty_struct *tty)
 {
@@ -3104,6 +3102,7 @@ static void dgrp_tty_hangup(struct tty_struct *tty)
 void
 dgrp_tty_uninit(struct nd_struct *nd)
 {
+	unsigned int i;
 	char id[3];
 
 	ID_TO_CHAR(nd->nd_ID, id);
@@ -3137,6 +3136,8 @@ dgrp_tty_uninit(struct nd_struct *nd)
 		put_tty_driver(nd->nd_xprint_ttdriver);
 		nd->nd_ttdriver_flags &= ~XPRINT_TTDRV_REG;
 	}
+	for (i = 0; i < CHAN_MAX; i++)
+		tty_port_destroy(&nd->nd_chan[i].port);
 }
 
 
@@ -3320,7 +3321,6 @@ dgrp_tty_init(struct nd_struct *nd)
 		init_waitqueue_head(&(ch->ch_pun.un_open_wait));
 		init_waitqueue_head(&(ch->ch_pun.un_close_wait));
 		tty_port_init(&ch->port);
-		tty_port_init(&ch->port);
 	}
 	return 0;
 }

+ 7 - 10
drivers/staging/fwserial/fwserial.c

@@ -939,14 +939,9 @@ static void fwserial_destroy(struct kref *kref)
 
 	mutex_lock(&port_table_lock);
 	for (j = 0; j < num_ports; ++i, ++j) {
-		static bool once;
-		int corrupt = port_table[i] != ports[j];
-		if (corrupt && !once) {
-			WARN(corrupt, "port_table[%d]: %p != ports[%d]: %p",
-			     i, port_table[i], j, ports[j]);
-			once = true;
-			port_table_corrupt = true;
-		}
+		port_table_corrupt |= port_table[i] != ports[j];
+		WARN_ONCE(port_table_corrupt, "port_table[%d]: %p != ports[%d]: %p",
+		     i, port_table[i], j, ports[j]);
 
 		port_table[i] = NULL;
 	}
@@ -954,7 +949,7 @@ static void fwserial_destroy(struct kref *kref)
 
 	for (j = 0; j < num_ports; ++j) {
 		fw_core_remove_address_handler(&ports[j]->rx_handler);
-		dma_fifo_free(&ports[j]->tx_fifo);
+		tty_port_destroy(&ports[j]->port);
 		kfree(ports[j]);
 	}
 	kfree(serial);
@@ -2369,8 +2364,10 @@ unregister_ttys:
 	return err;
 
 free_ports:
-	for (--i; i >= 0; --i)
+	for (--i; i >= 0; --i) {
+		tty_port_destroy(&serial->ports[i]->port);
 		kfree(serial->ports[i]);
+	}
 	kfree(serial);
 	return err;
 }

+ 9 - 0
drivers/staging/sb105x/Kconfig

@@ -0,0 +1,9 @@
+config SB105X
+	tristate "SystemBase PCI Multiport UART"
+	select SERIAL_CORE
+	depends on PCI
+	help
+	  A driver for the SystemBase Multi-2/PCI serial card
+
+	  To compile this driver a module, choose M here: the module
+	  will be called "sb105x".

+ 3 - 0
drivers/staging/sb105x/Makefile

@@ -0,0 +1,3 @@
+obj-$(CONFIG_SB105X) +=	sb105x.o
+
+sb105x-y :=  sb_pci_mp.o

+ 295 - 0
drivers/staging/sb105x/sb_mp_register.h

@@ -0,0 +1,295 @@
+
+/*
+ * SB105X_UART.h
+ *
+ * Copyright (C) 2008 systembase
+ *
+ * UART registers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef UART_SB105X_H
+#define UART_SB105X_H
+
+/* 
+ * option register 
+ */
+
+/* Device Infomation Register */
+#define MP_OPTR_DIR0		0x04 	/* port0 ~ port8 */
+#define MP_OPTR_DIR1		0x05 	/* port8 ~ port15 */
+#define MP_OPTR_DIR2		0x06 	/* port16 ~ port23 */
+#define MP_OPTR_DIR3		0x07 	/* port24 ~ port31 */
+
+#define DIR_UART_16C550 	0
+#define DIR_UART_16C1050	1
+#define DIR_UART_16C1050A	2
+
+#define	DIR_CLK_1843200		0x0		/* input clock 1843200 Hz */
+#define	DIR_CLK_3686400		0x1		/* input clock 3686400 Hz */
+#define	DIR_CLK_7372800		0x2		/* input clock 7372800 Hz */
+#define	DIR_CLK_14745600	0x3		/* input clock 14745600 Hz */
+#define	DIR_CLK_29491200	0x4		/* input clock 29491200 Hz */
+#define	DIR_CLK_58985400	0x5		/* input clock 58985400 Hz */
+
+/* Interface Information Register */
+#define MP_OPTR_IIR0		0x08 	/* port0 ~ port8 */
+#define MP_OPTR_IIR1		0x09 	/* port8 ~ port15 */
+#define MP_OPTR_IIR2		0x0A 	/* port16 ~ port23 */
+#define MP_OPTR_IIR3		0x0B 	/* port24 ~ port31 */
+
+#define IIR_RS232		0x00		/* RS232 type */
+#define IIR_RS422		0x10		/* RS422 type */
+#define IIR_RS485		0x20		/* RS485 type */
+#define IIR_UNKNOWN		0x30		/* unknown type */
+
+/* Interrrupt Mask Register */
+#define MP_OPTR_IMR0		0x0C 	/* port0 ~ port8 */
+#define MP_OPTR_IMR1		0x0D 	/* port8 ~ port15 */
+#define MP_OPTR_IMR2		0x0E 	/* port16 ~ port23 */
+#define MP_OPTR_IMR3		0x0F 	/* port24 ~ port31 */
+
+/* Interrupt Poll Register */
+#define MP_OPTR_IPR0		0x10 	/* port0 ~ port8 */
+#define MP_OPTR_IPR1		0x11 	/* port8 ~ port15 */
+#define MP_OPTR_IPR2		0x12 	/* port16 ~ port23 */
+#define MP_OPTR_IPR3		0x13 	/* port24 ~ port31 */
+
+/* General Purpose Output Control Register */
+#define MP_OPTR_GPOCR		0x20
+
+/* General Purpose Output Data Register */
+#define MP_OPTR_GPODR		0x21
+
+/* Parallel Additional Function Register */
+#define MP_OPTR_PAFR		0x23
+
+/*
+ * systembase 16c105x UART register
+ */
+
+#define PAGE_0 0
+#define PAGE_1 1
+#define PAGE_2 2
+#define PAGE_3 3
+#define PAGE_4 4
+
+/*
+ *  ******************************************************************
+ *  * DLAB=0                  ===============       Page 0 Registers *
+ *  ******************************************************************
+ */
+
+#define SB105X_RX		0	/* In:  Receive buffer */
+#define SB105X_TX		0	/* Out: Transmit buffer */
+
+#define SB105X_IER		1	/* Out: Interrupt Enable Register */
+
+#define SB105X_IER_CTSI	  	0x80	/* CTS# Interrupt Enable (Requires EFR[4] = 1) */
+#define SB105X_IER_RTSI	  	0x40	/* RTS# Interrupt Enable (Requires EFR[4] = 1) */
+#define SB105X_IER_XOI	  	0x20	/* Xoff Interrupt Enable (Requires EFR[4] = 1) */
+#define SB105X_IER_SME	  	0x10	/* Sleep Mode Enable (Requires EFR[4] = 1) */
+#define SB105X_IER_MSI	  	0x08	/* Enable Modem status interrupt */
+#define SB105X_IER_RLSI	  	0x04	/* Enable receiver line status interrupt */
+#define SB105X_IER_THRI	  	0x02	/* Enable Transmitter holding register int. */
+#define SB105X_IER_RDI	  	0x01	/* Enable receiver data interrupt */
+
+#define SB105X_ISR		2	/* In:  Interrupt ID Register */
+
+#define SB105X_ISR_NOINT	0x01	/* No interrupts pending */
+#define SB105X_ISR_RLSI	  	0x06	/* Receiver line status interrupt (Priority = 1)*/
+#define SB105X_ISR_RDAI	  	0x0c	/* Receive Data Available interrupt */
+#define SB105X_ISR_CTII	  	0x04	/* Character Timeout Indication interrupt */
+#define SB105X_ISR_THRI	  	0x02	/* Transmitter holding register empty */
+#define SB105X_ISR_MSI	  	0x00	/* Modem status interrupt */
+#define SB105X_ISR_RXCI	  	0x10	/* Receive Xoff or Special Character interrupt */
+#define SB105X_ISR_RCSI	  	0x20	/* RTS#, CTS# status interrupt during Auto RTS/CTS flow control */
+
+#define SB105X_FCR		2	/* Out: FIFO Control Register */
+
+#define SB105X_FCR_FEN    	0x01	/* FIFO Enable */
+#define SB105X_FCR_RXFR	  	0x02	/* RX FIFO Reset */
+#define SB105X_FCR_TXFR	  	0x04	/* TX FIFO Reset */
+#define SB105X_FCR_DMS	  	0x08	/* DMA Mode Select */
+
+#define SB105X_FCR_RTR08  	0x00	/* Receice Trigger Level set at 8 */
+#define SB105X_FCR_RTR16  	0x40  /* Receice Trigger Level set at 16 */
+#define SB105X_FCR_RTR56  	0x80  /* Receice Trigger Level set at 56 */
+#define SB105X_FCR_RTR60  	0xc0  /* Receice Trigger Level set at 60 */
+#define SB105X_FCR_TTR08  	0x00  /* Transmit Trigger Level set at 8 */
+#define SB105X_FCR_TTR16	0x10  /* Transmit Trigger Level set at 16 */
+#define SB105X_FCR_TTR32	0x20  /* Transmit Trigger Level set at 32 */
+#define SB105X_FCR_TTR56	0x30  /* Transmit Trigger Level set at 56 */
+
+#define SB105X_LCR		3	/* Out: Line Control Register */
+/*
+ *  * Note: if the word length is 5 bits (SB105X_LCR_WLEN5), then setting 
+ *  * SB105X_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
+ */
+#define SB105X_LCR_DLAB   	0x80  /* Divisor Latch Enable */
+#define SB105X_LCR_SBC    	0x40  /* Break Enable*/
+#define SB105X_LCR_SPAR   	0x20  /* Set Stick parity */
+#define SB105X_LCR_EPAR   	0x10  /* Even parity select */
+#define SB105X_LCR_PAREN  	0x08  /* Parity Enable */
+#define SB105X_LCR_STOP   	0x04  /* Stop bits: 0->1 bit, 1->2 bits, 1 and SB105X_LCR_WLEN5 -> 1.5 bit */
+#define SB105X_LCR_WLEN5  	0x00  /* Wordlength: 5 bits */
+#define SB105X_LCR_WLEN6  	0x01  /* Wordlength: 6 bits */
+#define SB105X_LCR_WLEN7  	0x02  /* Wordlength: 7 bits */
+#define SB105X_LCR_WLEN8  	0x03  /* Wordlength: 8 bits */
+
+#define SB105X_LCR_BF		0xBF
+
+#define SB105X_MCR		4	/* Out: Modem Control Register */
+#define SB105X_MCR_CPS    	0x80  /* Clock Prescaler Select */
+#define SB105X_MCR_P2S    	0x40  /* Page 2 Select /Xoff Re-Transmit Access Enable */
+#define SB105X_MCR_XOA    	0x20  /* Xon Any Enable */
+#define SB105X_MCR_ILB		0x10  /* Internal Loopback Enable */
+#define SB105X_MCR_OUT2		0x08  /* Out2/Interrupt Output Enable*/
+#define SB105X_MCR_OUT1		0x04  /* Out1/Interrupt Output Enable */
+#define SB105X_MCR_RTS    	0x02  /* RTS# Output */
+#define SB105X_MCR_DTR    	0x01  /* DTR# Output */
+
+#define SB105X_LSR		5	/* In:  Line Status Register */
+#define SB105X_LSR_RFEI   	0x80  /* Receive FIFO data error Indicator */
+#define SB105X_LSR_TEMI   	0x40  /* THR and TSR Empty Indicator */
+#define SB105X_LSR_THRE		0x20  /* THR Empty Indicator */
+#define SB105X_LSR_BII		0x10  /* Break interrupt indicator */
+#define SB105X_LSR_FEI		0x08  /* Frame error indicator */
+#define SB105X_LSR_PEI		0x04  /* Parity error indicator */
+#define SB105X_LSR_OEI		0x02  /* Overrun error indicator */
+#define SB105X_LSR_RDRI		0x01  /* Receive data ready Indicator*/
+
+#define SB105X_MSR		6	/* In:  Modem Status Register */
+#define SB105X_MSR_DCD		0x80  /* Data Carrier Detect */
+#define SB105X_MSR_RI		0x40  /* Ring Indicator */
+#define SB105X_MSR_DSR		0x20  /* Data Set Ready */
+#define SB105X_MSR_CTS		0x10  /* Clear to Send */
+#define SB105X_MSR_DDCD		0x08  /* Delta DCD */
+#define SB105X_MSR_DRI		0x04  /* Delta ring indicator */
+#define SB105X_MSR_DDSR		0x02  /* Delta DSR */
+#define SB105X_MSR_DCTS		0x01  /* Delta CTS */
+
+#define SB105XA_MDR		6	/* Out: Multi Drop mode Register */
+#define SB105XA_MDR_NPS		0x08  /* 9th Bit Polarity Select */
+#define SB105XA_MDR_AME		0x02  /* Auto Multi-drop Enable */
+#define SB105XA_MDR_MDE		0x01  /* Multi Drop Enable */
+
+#define SB105X_SPR		7	/* I/O: Scratch Register */
+
+/*
+ * DLAB=1
+ */
+#define SB105X_DLL		0	/* Out: Divisor Latch Low */
+#define SB105X_DLM		1	/* Out: Divisor Latch High */
+
+/*
+ *  ******************************************************************
+ *  * DLAB(LCR[7]) = 0 , MCR[6] = 1  =============  Page 2 Registers *
+ *  ******************************************************************
+ */
+#define SB105X_GICR		1	/* Global Interrupt Control Register */
+#define SB105X_GICR_GIM   	0x01  /* Global Interrupt Mask */
+
+#define SB105X_GISR		2	/* Global Interrupt Status Register */
+#define SB105X_GISR_MGICR0  	0x80  /* Mirror the content of GICR[0] */
+#define SB105X_GISR_CS3IS   	0x08  /* SB105X of CS3# Interrupt Status */
+#define SB105X_GISR_CS2IS   	0x04  /* SB105X of CS2# Interrupt Status */
+#define SB105X_GISR_CS1IS   	0x02  /* SB105X of CS1# Interrupt Status */
+#define SB105X_GISR_CS0IS   	0x01  /* SB105X of CS0# Interrupt Status */
+
+#define SB105X_TFCR		5	/* Transmit FIFO Count Register */
+
+#define SB105X_RFCR		6	/* Receive FIFO Count Register */
+
+#define	SB105X_FSR		7	/* Flow Control Status Register */
+#define SB105X_FSR_THFS     	0x20  /* Transmit Hardware Flow Control Status */
+#define SB105X_FSR_TSFS     	0x10  /* Transmit Software Flow Control Status */
+#define SB105X_FSR_RHFS     	0x02  /* Receive Hardware Flow Control Status */
+#define SB105X_FSR_RSFS     	0x01  /* Receive Software Flow Control Status */
+
+/*
+ *  ******************************************************************
+ *  * LCR = 0xBF, PSR[0] = 0       =============    Page 3 Registers *
+ *  ******************************************************************
+ */
+
+#define SB105X_PSR		0	/* Page Select Register */
+#define SB105X_PSR_P3KEY    	0xA4 /* Page 3 Select Key */
+#define SB105X_PSR_P4KEY    	0xA5 /* Page 5 Select Key */
+
+#define SB105X_ATR		1	/* Auto Toggle Control Register */
+#define SB105X_ATR_RPS      	0x80  /* RXEN Polarity Select */
+#define SB105X_ATR_RCMS     	0x40  /* RXEN Control Mode Select */
+#define SB105X_ATR_TPS      	0x20  /* TXEN Polarity Select */
+#define SB105X_ATR_TCMS     	0x10  /* TXEN Control Mode Select */
+#define SB105X_ATR_ATDIS    	0x00  /* Auto Toggle is disabled */
+#define SB105X_ATR_ART      	0x01  /* RTS#/TXEN pin operates as TXEN */
+#define SB105X_ATR_ADT      	0x02  /* DTR#/TXEN pin operates as TXEN */
+#define SB105X_ATR_A80      	0x03  /* only in 80 pin use */
+
+#define SB105X_EFR		2	/* (Auto) Enhanced Feature Register */
+#define SB105X_EFR_ACTS     	0x80  /* Auto-CTS Flow Control Enable */
+#define SB105X_EFR_ARTS     	0x40  /* Auto-RTS Flow Control Enable */
+#define SB105X_EFR_SCD      	0x20  /* Special Character Detect */
+#define SB105X_EFR_EFBEN    	0x10  /* Enhanced Function Bits Enable */
+
+#define SB105X_XON1		4	/* Xon1 Character Register */
+#define SB105X_XON2		5	/* Xon2 Character Register */
+#define SB105X_XOFF1		6	/* Xoff1 Character Register */
+#define SB105X_XOFF2		7	/* Xoff2 Character Register */
+
+/*
+ *  ******************************************************************
+ *  * LCR = 0xBF, PSR[0] = 1       ============     Page 4 Registers *
+ *  ******************************************************************
+ */
+
+#define SB105X_AFR		1	/* Additional Feature Register */
+#define SB105X_AFR_GIPS     	0x20  /* Global Interrupt Polarity Select */
+#define SB105X_AFR_GIEN     	0x10  /* Global Interrupt Enable */
+#define SB105X_AFR_AFEN     	0x01  /* 256-byte FIFO Enable */
+
+#define SB105X_XRCR		2	/* Xoff Re-transmit Count Register */
+#define SB105X_XRCR_NRC1    	0x00  /* Transmits Xoff Character whenever the number of received data is 1 during XOFF status */
+#define SB105X_XRCR_NRC4    	0x01  /* Transmits Xoff Character whenever the number of received data is 4 during XOFF status */
+#define SB105X_XRCR_NRC8    	0x02  /* Transmits Xoff Character whenever the number of received data is 8 during XOFF status */
+#define SB105X_XRCR_NRC16   	0x03  /* Transmits Xoff Character whenever the number of received data is 16 during XOFF status */
+
+#define SB105X_TTR		4	/* Transmit FIFO Trigger Level Register */
+#define SB105X_RTR		5	/* Receive FIFO Trigger Level Register */
+#define SB105X_FUR		6	/* Flow Control Upper Threshold Register */
+#define SB105X_FLR		7	/* Flow Control Lower Threshold Register */
+
+
+/* page 0 */
+
+#define SB105X_GET_CHAR(port)	inb((port)->iobase + SB105X_RX)
+#define SB105X_GET_IER(port)	inb((port)->iobase + SB105X_IER)
+#define SB105X_GET_ISR(port)	inb((port)->iobase + SB105X_ISR)
+#define SB105X_GET_LCR(port)	inb((port)->iobase + SB105X_LCR)
+#define SB105X_GET_MCR(port)	inb((port)->iobase + SB105X_MCR)
+#define SB105X_GET_LSR(port)	inb((port)->iobase + SB105X_LSR)
+#define SB105X_GET_MSR(port)	inb((port)->iobase + SB105X_MSR)
+#define SB105X_GET_SPR(port)	inb((port)->iobase + SB105X_SPR)
+
+#define SB105X_PUT_CHAR(port,v)	outb((v),(port)->iobase + SB105X_TX )
+#define SB105X_PUT_IER(port,v)	outb((v),(port)->iobase + SB105X_IER )
+#define SB105X_PUT_FCR(port,v)	outb((v),(port)->iobase + SB105X_FCR )
+#define SB105X_PUT_LCR(port,v)	outb((v),(port)->iobase + SB105X_LCR )
+#define SB105X_PUT_MCR(port,v)	outb((v),(port)->iobase + SB105X_MCR )
+#define SB105X_PUT_SPR(port,v)	outb((v),(port)->iobase + SB105X_SPR )
+
+
+/* page 1 */
+#define SB105X_GET_REG(port,reg)	inb((port)->iobase + (reg))
+#define SB105X_PUT_REG(port,reg,v)	outb((v),(port)->iobase + (reg))
+
+/* page 2 */
+
+#define SB105X_PUT_PSR(port,v)	outb((v),(port)->iobase + SB105X_PSR )
+
+#endif 

+ 3196 - 0
drivers/staging/sb105x/sb_pci_mp.c

@@ -0,0 +1,3196 @@
+#include "sb_pci_mp.h"
+#include <linux/module.h>
+#include <linux/parport.h>
+
+extern struct parport *parport_pc_probe_port(unsigned long base_lo,
+		unsigned long base_hi,
+		int irq, int dma,
+		struct device *dev,
+		int irqflags);
+
+static struct mp_device_t mp_devs[MAX_MP_DEV];
+static int mp_nrpcibrds = sizeof(mp_pciboards)/sizeof(mppcibrd_t);
+static int NR_BOARD=0;
+static int NR_PORTS=0;
+static struct mp_port multi_ports[MAX_MP_PORT];
+static struct irq_info irq_lists[NR_IRQS];
+
+static _INLINE_ unsigned int serial_in(struct mp_port *mtpt, int offset);
+static _INLINE_ void serial_out(struct mp_port *mtpt, int offset, int value);
+static _INLINE_ unsigned int read_option_register(struct mp_port *mtpt, int offset);
+static int sb1054_get_register(struct sb_uart_port * port, int page, int reg);
+static int sb1054_set_register(struct sb_uart_port * port, int page, int reg, int value);
+static void SendATCommand(struct mp_port * mtpt);
+static int set_deep_fifo(struct sb_uart_port * port, int status);
+static int get_deep_fifo(struct sb_uart_port * port);
+static int get_device_type(int arg);
+static int set_auto_rts(struct sb_uart_port *port, int status);
+static void mp_stop(struct tty_struct *tty);
+static void __mp_start(struct tty_struct *tty);
+static void mp_start(struct tty_struct *tty);
+static void mp_tasklet_action(unsigned long data);
+static inline void mp_update_mctrl(struct sb_uart_port *port, unsigned int set, unsigned int clear);
+static int mp_startup(struct sb_uart_state *state, int init_hw);
+static void mp_shutdown(struct sb_uart_state *state);
+static void mp_change_speed(struct sb_uart_state *state, struct MP_TERMIOS *old_termios);
+
+static inline int __mp_put_char(struct sb_uart_port *port, struct circ_buf *circ, unsigned char c);
+static int mp_put_char(struct tty_struct *tty, unsigned char ch);
+
+static void mp_put_chars(struct tty_struct *tty);
+static int mp_write(struct tty_struct *tty, const unsigned char * buf, int count);
+static int mp_write_room(struct tty_struct *tty);
+static int mp_chars_in_buffer(struct tty_struct *tty);
+static void mp_flush_buffer(struct tty_struct *tty);
+static void mp_send_xchar(struct tty_struct *tty, char ch);
+static void mp_throttle(struct tty_struct *tty);
+static void mp_unthrottle(struct tty_struct *tty);
+static int mp_get_info(struct sb_uart_state *state, struct serial_struct *retinfo);
+static int mp_set_info(struct sb_uart_state *state, struct serial_struct *newinfo);
+static int mp_get_lsr_info(struct sb_uart_state *state, unsigned int *value);
+
+static int mp_tiocmget(struct tty_struct *tty);
+static int mp_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
+static int mp_break_ctl(struct tty_struct *tty, int break_state);
+static int mp_do_autoconfig(struct sb_uart_state *state);
+static int mp_wait_modem_status(struct sb_uart_state *state, unsigned long arg);
+static int mp_get_count(struct sb_uart_state *state, struct serial_icounter_struct *icnt);
+static int mp_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
+static void mp_set_termios(struct tty_struct *tty, struct MP_TERMIOS *old_termios);
+static void mp_close(struct tty_struct *tty, struct file *filp);
+static void mp_wait_until_sent(struct tty_struct *tty, int timeout);
+static void mp_hangup(struct tty_struct *tty);
+static void mp_update_termios(struct sb_uart_state *state);
+static int mp_block_til_ready(struct file *filp, struct sb_uart_state *state);
+static struct sb_uart_state *uart_get(struct uart_driver *drv, int line);
+static int mp_open(struct tty_struct *tty, struct file *filp);
+static const char *mp_type(struct sb_uart_port *port);
+static void mp_change_pm(struct sb_uart_state *state, int pm_state);
+static inline void mp_report_port(struct uart_driver *drv, struct sb_uart_port *port);
+static void mp_configure_port(struct uart_driver *drv, struct sb_uart_state *state, struct sb_uart_port *port);
+static void mp_unconfigure_port(struct uart_driver *drv, struct sb_uart_state *state);
+static int mp_register_driver(struct uart_driver *drv);
+static void mp_unregister_driver(struct uart_driver *drv);
+static int mp_add_one_port(struct uart_driver *drv, struct sb_uart_port *port);
+static int mp_remove_one_port(struct uart_driver *drv, struct sb_uart_port *port);
+static void autoconfig(struct mp_port *mtpt, unsigned int probeflags);
+static void autoconfig_irq(struct mp_port *mtpt);
+static void multi_stop_tx(struct sb_uart_port *port);
+static void multi_start_tx(struct sb_uart_port *port);
+static void multi_stop_rx(struct sb_uart_port *port);
+static void multi_enable_ms(struct sb_uart_port *port);
+static _INLINE_ void receive_chars(struct mp_port *mtpt, int *status );
+static _INLINE_ void transmit_chars(struct mp_port *mtpt);
+static _INLINE_ void check_modem_status(struct mp_port *mtpt);
+static inline void multi_handle_port(struct mp_port *mtpt);
+static irqreturn_t multi_interrupt(int irq, void *dev_id);
+static void serial_do_unlink(struct irq_info *i, struct mp_port *mtpt);
+static int serial_link_irq_chain(struct mp_port *mtpt);
+static void serial_unlink_irq_chain(struct mp_port *mtpt);
+static void multi_timeout(unsigned long data);
+static unsigned int multi_tx_empty(struct sb_uart_port *port);
+static unsigned int multi_get_mctrl(struct sb_uart_port *port);
+static void multi_set_mctrl(struct sb_uart_port *port, unsigned int mctrl);
+static void multi_break_ctl(struct sb_uart_port *port, int break_state);
+static int multi_startup(struct sb_uart_port *port);
+static void multi_shutdown(struct sb_uart_port *port);
+static unsigned int multi_get_divisor(struct sb_uart_port *port, unsigned int baud);
+static void multi_set_termios(struct sb_uart_port *port, struct MP_TERMIOS *termios, struct MP_TERMIOS *old);
+static void multi_pm(struct sb_uart_port *port, unsigned int state, unsigned int oldstate);
+static void multi_release_std_resource(struct mp_port *mtpt);
+static void multi_release_port(struct sb_uart_port *port);
+static int multi_request_port(struct sb_uart_port *port);
+static void multi_config_port(struct sb_uart_port *port, int flags);
+static int multi_verify_port(struct sb_uart_port *port, struct serial_struct *ser);
+static const char * multi_type(struct sb_uart_port *port);
+static void __init multi_init_ports(void);
+static void __init multi_register_ports(struct uart_driver *drv);
+static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd);
+
+static int deep[256];
+static int deep_count;
+static int fcr_arr[256];
+static int fcr_count;
+static int ttr[256];
+static int ttr_count;
+static int rtr[256];
+static int rtr_count;
+
+module_param_array(deep,int,&deep_count,0);
+module_param_array(fcr_arr,int,&fcr_count,0);
+module_param_array(ttr,int,&ttr_count,0);
+module_param_array(rtr,int,&rtr_count,0);
+
+static _INLINE_ unsigned int serial_in(struct mp_port *mtpt, int offset)
+{
+	return inb(mtpt->port.iobase + offset);
+}
+
+static _INLINE_ void serial_out(struct mp_port *mtpt, int offset, int value)
+{
+	outb(value, mtpt->port.iobase + offset);
+}
+
+static _INLINE_ unsigned int read_option_register(struct mp_port *mtpt, int offset)
+{
+	return inb(mtpt->option_base_addr + offset);
+}
+
+static int sb1053a_get_interface(struct mp_port *mtpt, int port_num)
+{
+	unsigned long option_base_addr = mtpt->option_base_addr;
+	unsigned int  interface = 0;
+
+	switch (port_num)
+	{
+		case 0:
+		case 1:
+			/* set GPO[1:0] = 00 */
+			outb(0x00, option_base_addr + MP_OPTR_GPODR);
+			break;
+		case 2:
+		case 3:
+			/* set GPO[1:0] = 01 */
+			outb(0x01, option_base_addr + MP_OPTR_GPODR);
+			break;
+		case 4:
+		case 5:
+			/* set GPO[1:0] = 10 */
+			outb(0x02, option_base_addr + MP_OPTR_GPODR);
+			break;
+		default:
+			break;
+	}
+
+	port_num &= 0x1;
+
+	/* get interface */
+	interface = inb(option_base_addr + MP_OPTR_IIR0 + port_num);
+
+	/* set GPO[1:0] = 11 */
+	outb(0x03, option_base_addr + MP_OPTR_GPODR);
+
+	return (interface);
+}
+		
+static int sb1054_get_register(struct sb_uart_port * port, int page, int reg)
+{
+	int ret = 0;
+	unsigned int lcr = 0;
+	unsigned int mcr = 0;
+	unsigned int tmp = 0;
+
+	if( page <= 0)
+	{
+		printk(" page 0 can not use this fuction\n");
+		return -1;
+	}
+
+	switch(page)
+	{
+		case 1:
+			lcr = SB105X_GET_LCR(port);
+			tmp = lcr | SB105X_LCR_DLAB;
+			SB105X_PUT_LCR(port, tmp);
+
+			tmp = SB105X_GET_LCR(port);
+
+			ret = SB105X_GET_REG(port,reg);
+			SB105X_PUT_LCR(port,lcr);
+			break;
+		case 2:
+			mcr = SB105X_GET_MCR(port);
+			tmp = mcr | SB105X_MCR_P2S;
+			SB105X_PUT_MCR(port,tmp);
+
+			ret = SB105X_GET_REG(port,reg);
+
+			SB105X_PUT_MCR(port,mcr);
+			break;
+		case 3:
+			lcr = SB105X_GET_LCR(port);
+			tmp = lcr | SB105X_LCR_BF;
+			SB105X_PUT_LCR(port,tmp);
+			SB105X_PUT_REG(port,SB105X_PSR,SB105X_PSR_P3KEY);
+
+			ret = SB105X_GET_REG(port,reg);
+
+			SB105X_PUT_LCR(port,lcr);
+			break;
+		case 4:
+			lcr = SB105X_GET_LCR(port);
+			tmp = lcr | SB105X_LCR_BF;
+			SB105X_PUT_LCR(port,tmp);
+			SB105X_PUT_REG(port,SB105X_PSR,SB105X_PSR_P4KEY);
+
+			ret = SB105X_GET_REG(port,reg);
+
+			SB105X_PUT_LCR(port,lcr);
+			break;
+		default:
+			printk(" error invalid page number \n");
+			return -1;
+	}
+
+	return ret;
+}
+
+static int sb1054_set_register(struct sb_uart_port * port, int page, int reg, int value)
+{  
+	int lcr = 0;
+	int mcr = 0;
+	int ret = 0;
+
+	if( page <= 0)
+	{
+		printk(" page 0 can not use this fuction\n");
+		return -1;
+	}
+	switch(page)
+	{
+		case 1:
+			lcr = SB105X_GET_LCR(port);
+			SB105X_PUT_LCR(port, lcr | SB105X_LCR_DLAB);
+
+			SB105X_PUT_REG(port,reg,value);
+
+			SB105X_PUT_LCR(port, lcr);
+			ret = 1;
+			break;
+		case 2:
+			mcr = SB105X_GET_MCR(port);
+			SB105X_PUT_MCR(port, mcr | SB105X_MCR_P2S);
+
+			SB105X_PUT_REG(port,reg,value);
+
+			SB105X_PUT_MCR(port, mcr);
+			ret = 1;
+			break;
+		case 3:
+			lcr = SB105X_GET_LCR(port);
+			SB105X_PUT_LCR(port, lcr | SB105X_LCR_BF);
+			SB105X_PUT_PSR(port, SB105X_PSR_P3KEY);
+
+			SB105X_PUT_REG(port,reg,value);
+
+			SB105X_PUT_LCR(port, lcr);
+			ret = 1;
+			break;
+		case 4:
+			lcr = SB105X_GET_LCR(port);
+			SB105X_PUT_LCR(port, lcr | SB105X_LCR_BF);
+			SB105X_PUT_PSR(port, SB105X_PSR_P4KEY);
+
+			SB105X_PUT_REG(port,reg,value);
+
+			SB105X_PUT_LCR(port, lcr);
+			ret = 1;
+			break;
+		default:
+			printk(" error invalid page number \n");
+			return -1;
+	}
+
+	return ret;
+}
+
+static int set_multidrop_mode(struct sb_uart_port *port, unsigned int mode)
+{
+	int mdr = SB105XA_MDR_NPS;
+
+	if (mode & MDMODE_ENABLE)
+	{
+		mdr |= SB105XA_MDR_MDE;
+	}
+
+	if (1) //(mode & MDMODE_AUTO)
+	{
+		int efr = 0;
+		mdr |= SB105XA_MDR_AME;
+		efr = sb1054_get_register(port, PAGE_3, SB105X_EFR);
+		efr |= SB105X_EFR_SCD;
+		sb1054_set_register(port, PAGE_3, SB105X_EFR, efr);
+	}
+
+	sb1054_set_register(port, PAGE_1, SB105XA_MDR, mdr);
+	port->mdmode &= ~0x6;
+	port->mdmode |= mode;
+	printk("[%d] multidrop init: %x\n", port->line, port->mdmode);
+
+	return 0;
+}
+
+static int get_multidrop_addr(struct sb_uart_port *port)
+{
+	return sb1054_get_register(port, PAGE_3, SB105X_XOFF2);
+}
+
+static int set_multidrop_addr(struct sb_uart_port *port, unsigned int addr)
+{
+	sb1054_set_register(port, PAGE_3, SB105X_XOFF2, addr);
+
+	return 0;
+}
+
+static void SendATCommand(struct mp_port * mtpt)
+{
+	//		      a    t	cr   lf
+	unsigned char ch[] = {0x61,0x74,0x0d,0x0a,0x0};
+	unsigned char lineControl;
+	unsigned char i=0;
+	unsigned char Divisor = 0xc;
+
+	lineControl = serial_inp(mtpt,UART_LCR);
+	serial_outp(mtpt,UART_LCR,(lineControl | UART_LCR_DLAB));
+	serial_outp(mtpt,UART_DLL,(Divisor & 0xff));
+	serial_outp(mtpt,UART_DLM,(Divisor & 0xff00)>>8); //baudrate is 4800
+
+
+	serial_outp(mtpt,UART_LCR,lineControl);	
+	serial_outp(mtpt,UART_LCR,0x03); // N-8-1
+	serial_outp(mtpt,UART_FCR,7); 
+	serial_outp(mtpt,UART_MCR,0x3);
+	while(ch[i]){
+		while((serial_inp(mtpt,UART_LSR) & 0x60) !=0x60){
+			;
+		}
+		serial_outp(mtpt,0,ch[i++]);
+	}
+
+
+}// end of SendATCommand()
+
+static int set_deep_fifo(struct sb_uart_port * port, int status)
+{
+	int afr_status = 0;
+	afr_status = sb1054_get_register(port, PAGE_4, SB105X_AFR);
+
+	if(status == ENABLE)
+	{
+		afr_status |= SB105X_AFR_AFEN;
+	}
+	else
+	{
+		afr_status &= ~SB105X_AFR_AFEN;
+	}
+		
+	sb1054_set_register(port,PAGE_4,SB105X_AFR,afr_status);
+	sb1054_set_register(port,PAGE_4,SB105X_TTR,ttr[port->line]); 
+	sb1054_set_register(port,PAGE_4,SB105X_RTR,rtr[port->line]); 
+	afr_status = sb1054_get_register(port, PAGE_4, SB105X_AFR);
+		
+	return afr_status;
+}
+
+static int get_device_type(int arg)
+{
+	int ret;
+        ret = inb(mp_devs[arg].option_reg_addr+MP_OPTR_DIR0);
+        ret = (ret & 0xf0) >> 4;
+        switch (ret)
+        {
+               case DIR_UART_16C550:
+                    return PORT_16C55X;
+               case DIR_UART_16C1050:
+                    return PORT_16C105X;
+               case DIR_UART_16C1050A:
+               /*
+               if (mtpt->port.line < 2)
+               {
+                    return PORT_16C105XA;
+               }
+               else
+               {
+                   if (mtpt->device->device_id & 0x50)
+                   {
+                       return PORT_16C55X;
+                   }
+                   else
+                   {
+                       return PORT_16C105X;
+                   }
+               }*/
+               return PORT_16C105XA;
+               default:
+                    return PORT_UNKNOWN;
+        }
+
+}
+static int get_deep_fifo(struct sb_uart_port * port)
+{
+	int afr_status = 0;
+	afr_status = sb1054_get_register(port, PAGE_4, SB105X_AFR);
+	return afr_status;
+}
+
+static int set_auto_rts(struct sb_uart_port *port, int status)
+{
+	int atr_status = 0;
+
+#if 0
+	int efr_status = 0;
+
+	efr_status = sb1054_get_register(port, PAGE_3, SB105X_EFR);
+	if(status == ENABLE)
+		efr_status |= SB105X_EFR_ARTS;
+	else
+		efr_status &= ~SB105X_EFR_ARTS;
+	sb1054_set_register(port,PAGE_3,SB105X_EFR,efr_status);
+	efr_status = sb1054_get_register(port, PAGE_3, SB105X_EFR);
+#endif
+		
+//ATR
+	atr_status = sb1054_get_register(port, PAGE_3, SB105X_ATR);
+	switch(status)
+	{
+		case RS422PTP:
+			atr_status = (SB105X_ATR_TPS) | (SB105X_ATR_A80);
+			break;
+		case RS422MD:
+			atr_status = (SB105X_ATR_TPS) | (SB105X_ATR_TCMS) | (SB105X_ATR_A80);
+			break;
+		case RS485NE:
+			atr_status = (SB105X_ATR_RCMS) | (SB105X_ATR_TPS) | (SB105X_ATR_TCMS) | (SB105X_ATR_A80);
+			break;
+		case RS485ECHO:
+			atr_status = (SB105X_ATR_TPS) | (SB105X_ATR_TCMS) | (SB105X_ATR_A80);
+			break;
+	}
+
+	sb1054_set_register(port,PAGE_3,SB105X_ATR,atr_status);
+	atr_status = sb1054_get_register(port, PAGE_3, SB105X_ATR);
+
+	return atr_status;
+}
+
+static void mp_stop(struct tty_struct *tty)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port = state->port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	port->ops->stop_tx(port);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void __mp_start(struct tty_struct *tty)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port = state->port;
+
+	if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
+			!tty->stopped && !tty->hw_stopped)
+		port->ops->start_tx(port);
+}
+
+static void mp_start(struct tty_struct *tty)
+{
+	__mp_start(tty);
+}
+
+static void mp_tasklet_action(unsigned long data)
+{
+	struct sb_uart_state *state = (struct sb_uart_state *)data;
+	struct tty_struct *tty;
+
+	printk("tasklet is called!\n");
+	tty = state->info->tty;
+	tty_wakeup(tty);
+}
+
+static inline void mp_update_mctrl(struct sb_uart_port *port, unsigned int set, unsigned int clear)
+{
+	unsigned int old;
+
+	old = port->mctrl;
+	port->mctrl = (old & ~clear) | set;
+	if (old != port->mctrl)
+		port->ops->set_mctrl(port, port->mctrl);
+}
+
+#define uart_set_mctrl(port,set)	mp_update_mctrl(port,set,0)
+#define uart_clear_mctrl(port,clear)	mp_update_mctrl(port,0,clear)
+
+static int mp_startup(struct sb_uart_state *state, int init_hw)
+{
+	struct sb_uart_info *info = state->info;
+	struct sb_uart_port *port = state->port;
+	unsigned long page;
+	int retval = 0;
+
+	if (info->flags & UIF_INITIALIZED)
+		return 0;
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	if (port->type == PORT_UNKNOWN)
+		return 0;
+
+	if (!info->xmit.buf) {
+		page = get_zeroed_page(GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+
+		info->xmit.buf = (unsigned char *) page;
+			
+		uart_circ_clear(&info->xmit);
+	}
+
+	retval = port->ops->startup(port);
+	if (retval == 0) {
+		if (init_hw) {
+			mp_change_speed(state, NULL);
+
+			if (info->tty->termios.c_cflag & CBAUD)
+				uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+		}
+
+		info->flags |= UIF_INITIALIZED;
+
+
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	}
+
+	if (retval && capable(CAP_SYS_ADMIN))
+		retval = 0;
+
+	return retval;
+}
+
+static void mp_shutdown(struct sb_uart_state *state)
+{
+	struct sb_uart_info *info = state->info;
+	struct sb_uart_port *port = state->port;
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	if (info->flags & UIF_INITIALIZED) {
+		info->flags &= ~UIF_INITIALIZED;
+
+		if (!info->tty || (info->tty->termios.c_cflag & HUPCL))
+			uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+
+		wake_up_interruptible(&info->delta_msr_wait);
+
+		port->ops->shutdown(port);
+
+		synchronize_irq(port->irq);
+	}
+	tasklet_kill(&info->tlet);
+
+	if (info->xmit.buf) {
+		free_page((unsigned long)info->xmit.buf);
+		info->xmit.buf = NULL;
+	}
+}
+
+static void mp_change_speed(struct sb_uart_state *state, struct MP_TERMIOS *old_termios)
+{
+	struct tty_struct *tty = state->info->tty;
+	struct sb_uart_port *port = state->port;
+
+	if (!tty || port->type == PORT_UNKNOWN)
+		return;
+
+	if (tty->termios.c_cflag & CRTSCTS)
+		state->info->flags |= UIF_CTS_FLOW;
+	else
+		state->info->flags &= ~UIF_CTS_FLOW;
+
+	if (tty->termios.c_cflag & CLOCAL)
+		state->info->flags &= ~UIF_CHECK_CD;
+	else
+		state->info->flags |= UIF_CHECK_CD;
+
+	port->ops->set_termios(port, &tty->termios, old_termios);
+}
+
+static inline int __mp_put_char(struct sb_uart_port *port, struct circ_buf *circ, unsigned char c)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (!circ->buf)
+		return 0;
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (uart_circ_chars_free(circ) != 0) {
+		circ->buf[circ->head] = c;
+		circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&port->lock, flags);
+	return ret;
+}
+
+static int mp_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct sb_uart_state *state = tty->driver_data;
+
+	return __mp_put_char(state->port, &state->info->xmit, ch);
+}
+
+static void mp_put_chars(struct tty_struct *tty)
+{
+	mp_start(tty);
+}
+
+static int mp_write(struct tty_struct *tty, const unsigned char * buf, int count)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port;
+	struct circ_buf *circ;
+	int c, ret = 0;
+
+	if (!state || !state->info) {
+		return -EL3HLT;
+	}
+
+	port = state->port;
+	circ = &state->info->xmit;
+
+	if (!circ->buf)
+		return 0;
+		
+	while (1) {
+		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+		if (count < c)
+			c = count;
+		if (c <= 0)
+			break;
+	memcpy(circ->buf + circ->head, buf, c);
+
+		circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
+		buf += c;
+		count -= c;
+		ret += c;
+	}
+	mp_start(tty);
+	return ret;
+}
+
+static int mp_write_room(struct tty_struct *tty)
+{
+	struct sb_uart_state *state = tty->driver_data;
+
+	return uart_circ_chars_free(&state->info->xmit);
+}
+
+static int mp_chars_in_buffer(struct tty_struct *tty)
+{
+	struct sb_uart_state *state = tty->driver_data;
+
+	return uart_circ_chars_pending(&state->info->xmit);
+}
+
+static void mp_flush_buffer(struct tty_struct *tty)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port;
+	unsigned long flags;
+
+	if (!state || !state->info) {
+		return;
+	}
+
+	port = state->port;
+	spin_lock_irqsave(&port->lock, flags);
+	uart_circ_clear(&state->info->xmit);
+	spin_unlock_irqrestore(&port->lock, flags);
+	wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
+}
+
+static void mp_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port = state->port;
+	unsigned long flags;
+
+	if (port->ops->send_xchar)
+		port->ops->send_xchar(port, ch);
+	else {
+		port->x_char = ch;
+		if (ch) {
+			spin_lock_irqsave(&port->lock, flags);
+			port->ops->start_tx(port);
+			spin_unlock_irqrestore(&port->lock, flags);
+		}
+	}
+}
+
+static void mp_throttle(struct tty_struct *tty)
+{
+	struct sb_uart_state *state = tty->driver_data;
+
+	if (I_IXOFF(tty))
+		mp_send_xchar(tty, STOP_CHAR(tty));
+
+	if (tty->termios.c_cflag & CRTSCTS)
+		uart_clear_mctrl(state->port, TIOCM_RTS);
+}
+
+static void mp_unthrottle(struct tty_struct *tty)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port = state->port;
+
+	if (I_IXOFF(tty)) {
+		if (port->x_char)
+			port->x_char = 0;
+		else
+			mp_send_xchar(tty, START_CHAR(tty));
+	}
+
+	if (tty->termios.c_cflag & CRTSCTS)
+		uart_set_mctrl(port, TIOCM_RTS);
+}
+
+static int mp_get_info(struct sb_uart_state *state, struct serial_struct *retinfo)
+{
+	struct sb_uart_port *port = state->port;
+	struct serial_struct tmp;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type	    = port->type;
+	tmp.line	    = port->line;
+	tmp.port	    = port->iobase;
+	if (HIGH_BITS_OFFSET)
+		tmp.port_high = (long) port->iobase >> HIGH_BITS_OFFSET;
+	tmp.irq		    = port->irq;
+	tmp.flags	    = port->flags;
+	tmp.xmit_fifo_size  = port->fifosize;
+	tmp.baud_base	    = port->uartclk / 16;
+	tmp.close_delay	    = state->close_delay;
+	tmp.closing_wait    = state->closing_wait == USF_CLOSING_WAIT_NONE ?
+		ASYNC_CLOSING_WAIT_NONE :
+		state->closing_wait;
+	tmp.custom_divisor  = port->custom_divisor;
+	tmp.hub6	    = port->hub6;
+	tmp.io_type         = port->iotype;
+	tmp.iomem_reg_shift = port->regshift;
+	tmp.iomem_base      = (void *)port->mapbase;
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int mp_set_info(struct sb_uart_state *state, struct serial_struct *newinfo)
+{
+	struct serial_struct new_serial;
+	struct sb_uart_port *port = state->port;
+	unsigned long new_port;
+	unsigned int change_irq, change_port, closing_wait;
+	unsigned int old_custom_divisor;
+	unsigned int old_flags, new_flags;
+	int retval = 0;
+
+	if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+		return -EFAULT;
+
+	new_port = new_serial.port;
+	if (HIGH_BITS_OFFSET)
+		new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+
+	new_serial.irq = irq_canonicalize(new_serial.irq);
+
+	closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+		USF_CLOSING_WAIT_NONE : new_serial.closing_wait;
+	MP_STATE_LOCK(state);
+
+	change_irq  = new_serial.irq != port->irq;
+	change_port = new_port != port->iobase ||
+		(unsigned long)new_serial.iomem_base != port->mapbase ||
+		new_serial.hub6 != port->hub6 ||
+		new_serial.io_type != port->iotype ||
+		new_serial.iomem_reg_shift != port->regshift ||
+		new_serial.type != port->type;
+	old_flags = port->flags;
+	new_flags = new_serial.flags;
+	old_custom_divisor = port->custom_divisor;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		retval = -EPERM;
+		if (change_irq || change_port ||
+				(new_serial.baud_base != port->uartclk / 16) ||
+				(new_serial.close_delay != state->close_delay) ||
+				(closing_wait != state->closing_wait) ||
+				(new_serial.xmit_fifo_size != port->fifosize) ||
+				(((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
+			goto exit;
+		port->flags = ((port->flags & ~UPF_USR_MASK) |
+				(new_flags & UPF_USR_MASK));
+		port->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	if (port->ops->verify_port)
+		retval = port->ops->verify_port(port, &new_serial);
+
+	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
+			(new_serial.baud_base < 9600))
+		retval = -EINVAL;
+
+	if (retval)
+		goto exit;
+
+	if (change_port || change_irq) {
+		retval = -EBUSY;
+
+		if (uart_users(state) > 1)
+			goto exit;
+
+		mp_shutdown(state);
+	}
+
+	if (change_port) {
+		unsigned long old_iobase, old_mapbase;
+		unsigned int old_type, old_iotype, old_hub6, old_shift;
+
+		old_iobase = port->iobase;
+		old_mapbase = port->mapbase;
+		old_type = port->type;
+		old_hub6 = port->hub6;
+		old_iotype = port->iotype;
+		old_shift = port->regshift;
+
+		if (old_type != PORT_UNKNOWN)
+			port->ops->release_port(port);
+
+		port->iobase = new_port;
+		port->type = new_serial.type;
+		port->hub6 = new_serial.hub6;
+		port->iotype = new_serial.io_type;
+		port->regshift = new_serial.iomem_reg_shift;
+		port->mapbase = (unsigned long)new_serial.iomem_base;
+
+		if (port->type != PORT_UNKNOWN) {
+			retval = port->ops->request_port(port);
+		} else {
+			retval = 0;
+		}
+
+		if (retval && old_type != PORT_UNKNOWN) {
+			port->iobase = old_iobase;
+			port->type = old_type;
+			port->hub6 = old_hub6;
+			port->iotype = old_iotype;
+			port->regshift = old_shift;
+			port->mapbase = old_mapbase;
+			retval = port->ops->request_port(port);
+			if (retval)
+				port->type = PORT_UNKNOWN;
+
+			retval = -EBUSY;
+		}
+	}
+
+	port->irq              = new_serial.irq;
+	port->uartclk          = new_serial.baud_base * 16;
+	port->flags            = (port->flags & ~UPF_CHANGE_MASK) |
+		(new_flags & UPF_CHANGE_MASK);
+	port->custom_divisor   = new_serial.custom_divisor;
+	state->close_delay     = new_serial.close_delay;
+	state->closing_wait    = closing_wait;
+	port->fifosize         = new_serial.xmit_fifo_size;
+	if (state->info->tty)
+		state->info->tty->low_latency =
+			(port->flags & UPF_LOW_LATENCY) ? 1 : 0;
+
+check_and_exit:
+	retval = 0;
+	if (port->type == PORT_UNKNOWN)
+		goto exit;
+	if (state->info->flags & UIF_INITIALIZED) {
+		if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
+				old_custom_divisor != port->custom_divisor) {
+			if (port->flags & UPF_SPD_MASK) {
+				printk(KERN_NOTICE
+						"%s sets custom speed on ttyMP%d. This "
+						"is deprecated.\n", current->comm,
+						port->line);
+			}
+			mp_change_speed(state, NULL);
+		}
+	} else
+		retval = mp_startup(state, 1);
+exit:
+	MP_STATE_UNLOCK(state);
+	return retval;
+}
+
+
+static int mp_get_lsr_info(struct sb_uart_state *state, unsigned int *value)
+{
+	struct sb_uart_port *port = state->port;
+	unsigned int result;
+
+	result = port->ops->tx_empty(port);
+
+	if (port->x_char ||
+			((uart_circ_chars_pending(&state->info->xmit) > 0) &&
+				!state->info->tty->stopped && !state->info->tty->hw_stopped))
+		result &= ~TIOCSER_TEMT;
+
+	return put_user(result, value);
+}
+
+static int mp_tiocmget(struct tty_struct *tty)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port = state->port;
+	int result = -EIO;
+
+	MP_STATE_LOCK(state);
+	if (!(tty->flags & (1 << TTY_IO_ERROR))) {
+		result = port->mctrl;
+		spin_lock_irq(&port->lock);
+		result |= port->ops->get_mctrl(port);
+		spin_unlock_irq(&port->lock);
+	}
+	MP_STATE_UNLOCK(state);
+	return result;
+}
+
+static int mp_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port = state->port;
+	int ret = -EIO;
+
+
+	MP_STATE_LOCK(state);
+	if (!(tty->flags & (1 << TTY_IO_ERROR))) {
+		mp_update_mctrl(port, set, clear);
+		ret = 0;
+	}
+	MP_STATE_UNLOCK(state);
+
+	return ret;
+}
+
+static int mp_break_ctl(struct tty_struct *tty, int break_state)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port = state->port;
+
+	MP_STATE_LOCK(state);
+
+	if (port->type != PORT_UNKNOWN)
+		port->ops->break_ctl(port, break_state);
+
+	MP_STATE_UNLOCK(state);
+	return 0;
+}
+
+static int mp_do_autoconfig(struct sb_uart_state *state)
+{
+	struct sb_uart_port *port = state->port;
+	int flags, ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (mutex_lock_interruptible(&state->mutex))
+		return -ERESTARTSYS;
+	ret = -EBUSY;
+	if (uart_users(state) == 1) {
+		mp_shutdown(state);
+
+		if (port->type != PORT_UNKNOWN)
+			port->ops->release_port(port);
+
+		flags = UART_CONFIG_TYPE;
+		if (port->flags & UPF_AUTO_IRQ)
+			flags |= UART_CONFIG_IRQ;
+
+		port->ops->config_port(port, flags);
+
+		ret = mp_startup(state, 1);
+	}
+	MP_STATE_UNLOCK(state);
+	return ret;
+}
+
+static int mp_wait_modem_status(struct sb_uart_state *state, unsigned long arg)
+{
+	struct sb_uart_port *port = state->port;
+	DECLARE_WAITQUEUE(wait, current);
+	struct sb_uart_icount cprev, cnow;
+	int ret;
+
+	spin_lock_irq(&port->lock);
+	memcpy(&cprev, &port->icount, sizeof(struct sb_uart_icount));
+
+	port->ops->enable_ms(port);
+	spin_unlock_irq(&port->lock);
+
+	add_wait_queue(&state->info->delta_msr_wait, &wait);
+	for (;;) {
+		spin_lock_irq(&port->lock);
+		memcpy(&cnow, &port->icount, sizeof(struct sb_uart_icount));
+		spin_unlock_irq(&port->lock);
+
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+				((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+				((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+				((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+			ret = 0;
+			break;
+		}
+
+		schedule();
+
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		cprev = cnow;
+	}
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&state->info->delta_msr_wait, &wait);
+
+	return ret;
+}
+
+static int mp_get_count(struct sb_uart_state *state, struct serial_icounter_struct *icnt)
+{
+	struct serial_icounter_struct icount;
+	struct sb_uart_icount cnow;
+	struct sb_uart_port *port = state->port;
+
+	spin_lock_irq(&port->lock);
+	memcpy(&cnow, &port->icount, sizeof(struct sb_uart_icount));
+	spin_unlock_irq(&port->lock);
+
+	icount.cts         = cnow.cts;
+	icount.dsr         = cnow.dsr;
+	icount.rng         = cnow.rng;
+	icount.dcd         = cnow.dcd;
+	icount.rx          = cnow.rx;
+	icount.tx          = cnow.tx;
+	icount.frame       = cnow.frame;
+	icount.overrun     = cnow.overrun;
+	icount.parity      = cnow.parity;
+	icount.brk         = cnow.brk;
+	icount.buf_overrun = cnow.buf_overrun;
+
+	return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
+}
+
+static int mp_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct mp_port *info = (struct mp_port *)state->port;
+	int ret = -ENOIOCTLCMD;
+
+
+	switch (cmd) {
+		case TIOCSMULTIDROP:
+			/* set multi-drop mode enable or disable, and default operation mode is H/W mode */
+			if (info->port.type == PORT_16C105XA)
+			{
+				//arg &= ~0x6;
+				//state->port->mdmode = 0;
+				return set_multidrop_mode((struct sb_uart_port *)info, (unsigned int)arg);
+			}
+			ret = -ENOTSUPP;
+			break;
+		case GETDEEPFIFO:
+			ret = get_deep_fifo(state->port);
+			return ret;
+		case SETDEEPFIFO:
+			ret = set_deep_fifo(state->port,arg);
+			deep[state->port->line] = arg;
+			return ret;
+		case SETTTR:
+			if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
+				ret = sb1054_set_register(state->port,PAGE_4,SB105X_TTR,arg);
+				ttr[state->port->line] = arg;
+			}
+			return ret;
+		case SETRTR:
+			if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
+				ret = sb1054_set_register(state->port,PAGE_4,SB105X_RTR,arg);
+				rtr[state->port->line] = arg;
+			}
+			return ret;
+		case GETTTR:
+			if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
+				ret = sb1054_get_register(state->port,PAGE_4,SB105X_TTR);
+			}
+			return ret;
+		case GETRTR:
+			if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
+				ret = sb1054_get_register(state->port,PAGE_4,SB105X_RTR);
+			}
+			return ret;
+
+		case SETFCR:
+			if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){
+				ret = sb1054_set_register(state->port,PAGE_1,SB105X_FCR,arg);
+			}
+			else{
+				serial_out(info,2,arg);
+			}
+
+			return ret;
+		case TIOCSMDADDR:
+			/* set multi-drop address */
+			if (info->port.type == PORT_16C105XA)
+			{
+				state->port->mdmode |= MDMODE_ADDR;
+				return set_multidrop_addr((struct sb_uart_port *)info, (unsigned int)arg);
+			}
+			ret = -ENOTSUPP;
+			break;
+
+		case TIOCGMDADDR:
+			/* set multi-drop address */
+			if ((info->port.type == PORT_16C105XA) && (state->port->mdmode & MDMODE_ADDR))
+			{
+				return get_multidrop_addr((struct sb_uart_port *)info);
+			}
+			ret = -ENOTSUPP;
+			break;
+
+		case TIOCSENDADDR:
+			/* send address in multi-drop mode */
+			if ((info->port.type == PORT_16C105XA) 
+					&& (state->port->mdmode & (MDMODE_ENABLE)))
+			{
+				if (mp_chars_in_buffer(tty) > 0)
+				{
+					tty_wait_until_sent(tty, 0);
+				}
+				//while ((serial_in(info, UART_LSR) & 0x60) != 0x60);
+				//while (sb1054_get_register(state->port, PAGE_2, SB105X_TFCR) != 0);
+				while ((serial_in(info, UART_LSR) & 0x60) != 0x60);
+				serial_out(info, UART_SCR, (int)arg);
+			}
+			break;
+
+		case TIOCGSERIAL:
+			ret = mp_get_info(state, (struct serial_struct *)arg);
+			break;
+
+		case TIOCSSERIAL:
+			ret = mp_set_info(state, (struct serial_struct *)arg);
+			break;
+
+		case TIOCSERCONFIG:
+			ret = mp_do_autoconfig(state);
+			break;
+
+		case TIOCSERGWILD: /* obsolete */
+		case TIOCSERSWILD: /* obsolete */
+			ret = 0;
+			break;
+			/* for Multiport */
+		case TIOCGNUMOFPORT: /* Get number of ports */
+			return NR_PORTS;
+		case TIOCGGETDEVID:
+			return mp_devs[arg].device_id;
+		case TIOCGGETREV:
+			return mp_devs[arg].revision;
+		case TIOCGGETNRPORTS:
+			return mp_devs[arg].nr_ports;
+		case TIOCGGETBDNO:
+			return NR_BOARD;
+		case TIOCGGETINTERFACE:
+			if (mp_devs[arg].revision == 0xc0)
+			{
+				/* for SB16C1053APCI */
+				return (sb1053a_get_interface(info, info->port.line));
+			}
+			else
+			{
+				return (inb(mp_devs[arg].option_reg_addr+MP_OPTR_IIR0+(state->port->line/8)));
+			}
+		case TIOCGGETPORTTYPE:
+			ret = get_device_type(arg);;
+			return ret;
+		case TIOCSMULTIECHO: /* set to multi-drop mode(RS422) or echo mode(RS485)*/
+			outb( ( inb(info->interface_config_addr) & ~0x03 ) | 0x01 ,  
+					info->interface_config_addr);
+			return 0;
+		case TIOCSPTPNOECHO: /* set to multi-drop mode(RS422) or echo mode(RS485) */
+			outb( ( inb(info->interface_config_addr) & ~0x03 )  ,             
+					info->interface_config_addr);
+			return 0;
+	}
+
+	if (ret != -ENOIOCTLCMD)
+		goto out;
+
+	if (tty->flags & (1 << TTY_IO_ERROR)) {
+		ret = -EIO;
+		goto out;
+	}
+
+	switch (cmd) {
+		case TIOCMIWAIT:
+			ret = mp_wait_modem_status(state, arg);
+			break;
+
+		case TIOCGICOUNT:
+			ret = mp_get_count(state, (struct serial_icounter_struct *)arg);
+			break;
+	}
+
+	if (ret != -ENOIOCTLCMD)
+		goto out;
+
+	MP_STATE_LOCK(state);
+	switch (cmd) {
+		case TIOCSERGETLSR: /* Get line status register */
+			ret = mp_get_lsr_info(state, (unsigned int *)arg);
+			break;
+
+		default: {
+					struct sb_uart_port *port = state->port;
+					if (port->ops->ioctl)
+						ret = port->ops->ioctl(port, cmd, arg);
+					break;
+				}
+	}
+
+	MP_STATE_UNLOCK(state);
+out:
+	return ret;
+}
+
+static void mp_set_termios(struct tty_struct *tty, struct MP_TERMIOS *old_termios)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	unsigned long flags;
+	unsigned int cflag = tty->termios.c_cflag;
+
+#define RELEVANT_IFLAG(iflag)	((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+	if ((cflag ^ old_termios->c_cflag) == 0 &&
+			RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0)
+		return;
+
+	mp_change_speed(state, old_termios);
+
+	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
+		uart_clear_mctrl(state->port, TIOCM_RTS | TIOCM_DTR);
+
+	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+		unsigned int mask = TIOCM_DTR;
+		if (!(cflag & CRTSCTS) ||
+				!test_bit(TTY_THROTTLED, &tty->flags))
+			mask |= TIOCM_RTS;
+		uart_set_mctrl(state->port, mask);
+	}
+
+	if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
+		spin_lock_irqsave(&state->port->lock, flags);
+		tty->hw_stopped = 0;
+		__mp_start(tty);
+		spin_unlock_irqrestore(&state->port->lock, flags);
+	}
+
+	if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+		spin_lock_irqsave(&state->port->lock, flags);
+		if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) {
+			tty->hw_stopped = 1;
+			state->port->ops->stop_tx(state->port);
+		}
+		spin_unlock_irqrestore(&state->port->lock, flags);
+	}
+}
+
+static void mp_close(struct tty_struct *tty, struct file *filp)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port;
+
+	printk("mp_close!\n");
+	if (!state || !state->port)
+		return;
+
+	port = state->port;
+
+	printk("close1 %d\n", __LINE__);
+	MP_STATE_LOCK(state);
+
+	printk("close2 %d\n", __LINE__);
+	if (tty_hung_up_p(filp))
+		goto done;
+
+	printk("close3 %d\n", __LINE__);
+	if ((tty->count == 1) && (state->count != 1)) {
+		printk("mp_close: bad serial port count; tty->count is 1, "
+				"state->count is %d\n", state->count);
+		state->count = 1;
+	}
+	printk("close4 %d\n", __LINE__);
+	if (--state->count < 0) {
+		printk("rs_close: bad serial port count for ttyMP%d: %d\n",
+				port->line, state->count);
+		state->count = 0;
+	}
+	if (state->count)
+		goto done;
+
+	tty->closing = 1;
+
+	printk("close5 %d\n", __LINE__);
+	if (state->closing_wait != USF_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, state->closing_wait);
+
+	printk("close6 %d\n", __LINE__);
+	if (state->info->flags & UIF_INITIALIZED) {
+		unsigned long flags;
+		spin_lock_irqsave(&port->lock, flags);
+		port->ops->stop_rx(port);
+		spin_unlock_irqrestore(&port->lock, flags);
+		mp_wait_until_sent(tty, port->timeout);
+	}
+	printk("close7 %d\n", __LINE__);
+
+	mp_shutdown(state);
+	printk("close8 %d\n", __LINE__);
+	mp_flush_buffer(tty);
+	tty_ldisc_flush(tty);
+	tty->closing = 0;
+	state->info->tty = NULL;
+	if (state->info->blocked_open) 
+	{
+		if (state->close_delay)
+		{
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(state->close_delay);
+		}
+	}
+	else
+	{
+		mp_change_pm(state, 3);
+	}
+	printk("close8 %d\n", __LINE__);
+
+	state->info->flags &= ~UIF_NORMAL_ACTIVE;
+	wake_up_interruptible(&state->info->open_wait);
+
+done:
+	printk("close done\n");
+	MP_STATE_UNLOCK(state);
+	module_put(THIS_MODULE);
+}
+
+static void mp_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct sb_uart_state *state = tty->driver_data;
+	struct sb_uart_port *port = state->port;
+	unsigned long char_time, expire;
+
+	if (port->type == PORT_UNKNOWN || port->fifosize == 0)
+		return;
+
+	char_time = (port->timeout - HZ/50) / port->fifosize;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	if (timeout && timeout < char_time)
+		char_time = timeout;
+
+	if (timeout == 0 || timeout > 2 * port->timeout)
+		timeout = 2 * port->timeout;
+
+	expire = jiffies + timeout;
+
+	while (!port->ops->tx_empty(port)) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (time_after(jiffies, expire))
+			break;
+	}
+	set_current_state(TASK_RUNNING); /* might not be needed */
+}
+
+static void mp_hangup(struct tty_struct *tty)
+{
+	struct sb_uart_state *state = tty->driver_data;
+
+	MP_STATE_LOCK(state);
+	if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
+		mp_flush_buffer(tty);
+		mp_shutdown(state);
+		state->count = 0;
+		state->info->flags &= ~UIF_NORMAL_ACTIVE;
+		state->info->tty = NULL;
+		wake_up_interruptible(&state->info->open_wait);
+		wake_up_interruptible(&state->info->delta_msr_wait);
+	}
+	MP_STATE_UNLOCK(state);
+}
+
+static void mp_update_termios(struct sb_uart_state *state)
+{
+	struct tty_struct *tty = state->info->tty;
+	struct sb_uart_port *port = state->port;
+
+	if (!(tty->flags & (1 << TTY_IO_ERROR))) {
+		mp_change_speed(state, NULL);
+
+		if (tty->termios.c_cflag & CBAUD)
+			uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+	}
+}
+
+static int mp_block_til_ready(struct file *filp, struct sb_uart_state *state)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct sb_uart_info *info = state->info;
+	struct sb_uart_port *port = state->port;
+	unsigned int mctrl;
+
+	info->blocked_open++;
+	state->count--;
+
+	add_wait_queue(&info->open_wait, &wait);
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (tty_hung_up_p(filp) || info->tty == NULL)
+			break;
+
+		if (!(info->flags & UIF_INITIALIZED))
+			break;
+
+		if ((filp->f_flags & O_NONBLOCK) ||
+				(info->tty->termios.c_cflag & CLOCAL) ||
+				(info->tty->flags & (1 << TTY_IO_ERROR))) {
+			break;
+		}
+
+		if (info->tty->termios.c_cflag & CBAUD)
+			uart_set_mctrl(port, TIOCM_DTR);
+
+		spin_lock_irq(&port->lock);
+		port->ops->enable_ms(port);
+		mctrl = port->ops->get_mctrl(port);
+		spin_unlock_irq(&port->lock);
+		if (mctrl & TIOCM_CAR)
+			break;
+
+		MP_STATE_UNLOCK(state);
+		schedule();
+		MP_STATE_LOCK(state);
+
+		if (signal_pending(current))
+			break;
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&info->open_wait, &wait);
+
+	state->count++;
+	info->blocked_open--;
+
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	if (!info->tty || tty_hung_up_p(filp))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static struct sb_uart_state *uart_get(struct uart_driver *drv, int line)
+{
+	struct sb_uart_state *state;
+
+	MP_MUTEX_LOCK(mp_mutex);
+	state = drv->state + line;
+	if (mutex_lock_interruptible(&state->mutex)) {
+		state = ERR_PTR(-ERESTARTSYS);
+		goto out;
+	}
+	state->count++;
+	if (!state->port) {
+		state->count--;
+		MP_STATE_UNLOCK(state);
+		state = ERR_PTR(-ENXIO);
+		goto out;
+	}
+
+	if (!state->info) {
+		state->info = kmalloc(sizeof(struct sb_uart_info), GFP_KERNEL);
+		if (state->info) {
+			memset(state->info, 0, sizeof(struct sb_uart_info));
+			init_waitqueue_head(&state->info->open_wait);
+			init_waitqueue_head(&state->info->delta_msr_wait);
+
+			state->port->info = state->info;
+
+			tasklet_init(&state->info->tlet, mp_tasklet_action,
+					(unsigned long)state);
+		} else {
+			state->count--;
+			MP_STATE_UNLOCK(state);
+			state = ERR_PTR(-ENOMEM);
+		}
+	}
+
+out:
+	MP_MUTEX_UNLOCK(mp_mutex);
+	return state;
+}
+
+static int mp_open(struct tty_struct *tty, struct file *filp)
+{
+	struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
+	struct sb_uart_state *state;
+	int retval;
+	int  line = tty->index;
+	struct mp_port *mtpt;
+
+	retval = -ENODEV;
+	if (line >= tty->driver->num)
+		goto fail;
+
+	state = uart_get(drv, line);
+
+	mtpt  = (struct mp_port *)state->port;
+
+	if (IS_ERR(state)) {
+		retval = PTR_ERR(state);
+		goto fail;
+	}
+
+	tty->driver_data = state;
+	tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
+	tty->alt_speed = 0;
+	state->info->tty = tty;
+
+	if (tty_hung_up_p(filp)) {
+		retval = -EAGAIN;
+		state->count--;
+		MP_STATE_UNLOCK(state);
+		goto fail;
+	}
+
+	if (state->count == 1)
+		mp_change_pm(state, 0);
+
+	retval = mp_startup(state, 0);
+
+	if (retval == 0)
+		retval = mp_block_til_ready(filp, state);
+	MP_STATE_UNLOCK(state);
+
+	if (retval == 0 && !(state->info->flags & UIF_NORMAL_ACTIVE)) {
+		state->info->flags |= UIF_NORMAL_ACTIVE;
+
+		mp_update_termios(state);
+	}
+
+	uart_clear_mctrl(state->port, TIOCM_RTS);
+	try_module_get(THIS_MODULE);
+fail:
+	return retval;
+}
+
+
+static const char *mp_type(struct sb_uart_port *port)
+{
+	const char *str = NULL;
+
+	if (port->ops->type)
+		str = port->ops->type(port);
+
+	if (!str)
+		str = "unknown";
+
+	return str;
+}
+
+static void mp_change_pm(struct sb_uart_state *state, int pm_state)
+{
+	struct sb_uart_port *port = state->port;
+	if (port->ops->pm)
+		port->ops->pm(port, pm_state, state->pm_state);
+	state->pm_state = pm_state;
+}
+
+static inline void mp_report_port(struct uart_driver *drv, struct sb_uart_port *port)
+{
+	char address[64];
+
+	switch (port->iotype) {
+		case UPIO_PORT:
+			snprintf(address, sizeof(address),"I/O 0x%x", port->iobase);
+			break;
+		case UPIO_HUB6:
+			snprintf(address, sizeof(address),"I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+			break;
+		case UPIO_MEM:
+			snprintf(address, sizeof(address),"MMIO 0x%lx", port->mapbase);
+			break;
+		default:
+			snprintf(address, sizeof(address),"*unknown*" );
+			strlcpy(address, "*unknown*", sizeof(address));
+			break;
+	}
+
+	printk( "%s%d at %s (irq = %d) is a %s\n",
+			drv->dev_name, port->line, address, port->irq, mp_type(port));
+
+}
+
+static void mp_configure_port(struct uart_driver *drv, struct sb_uart_state *state, struct sb_uart_port *port)
+{
+	unsigned int flags;
+
+
+	if (!port->iobase && !port->mapbase && !port->membase)
+	{
+		DPRINTK("%s error \n",__FUNCTION__);
+		return;
+	}
+	flags = UART_CONFIG_TYPE;
+	if (port->flags & UPF_AUTO_IRQ)
+		flags |= UART_CONFIG_IRQ;
+	if (port->flags & UPF_BOOT_AUTOCONF) {
+		port->type = PORT_UNKNOWN;
+		port->ops->config_port(port, flags);
+	}
+
+	if (port->type != PORT_UNKNOWN) {
+		unsigned long flags;
+
+		mp_report_port(drv, port);
+
+		spin_lock_irqsave(&port->lock, flags);
+		port->ops->set_mctrl(port, 0);
+		spin_unlock_irqrestore(&port->lock, flags);
+
+		mp_change_pm(state, 3);
+	}
+}
+
+static void mp_unconfigure_port(struct uart_driver *drv, struct sb_uart_state *state)
+{
+	struct sb_uart_port *port = state->port;
+	struct sb_uart_info *info = state->info;
+
+	if (info && info->tty)
+		tty_hangup(info->tty);
+
+	MP_STATE_LOCK(state);
+
+	state->info = NULL;
+
+	if (port->type != PORT_UNKNOWN)
+		port->ops->release_port(port);
+
+	port->type = PORT_UNKNOWN;
+
+	if (info) {
+		tasklet_kill(&info->tlet);
+		kfree(info);
+	}
+
+	MP_STATE_UNLOCK(state);
+}
+static struct tty_operations mp_ops = {
+	.open		= mp_open,
+	.close		= mp_close,
+	.write		= mp_write,
+	.put_char	= mp_put_char,
+	.flush_chars	= mp_put_chars,
+	.write_room	= mp_write_room,
+	.chars_in_buffer= mp_chars_in_buffer,
+	.flush_buffer	= mp_flush_buffer,
+	.ioctl		= mp_ioctl,
+	.throttle	= mp_throttle,
+	.unthrottle	= mp_unthrottle,
+	.send_xchar	= mp_send_xchar,
+	.set_termios	= mp_set_termios,
+	.stop		= mp_stop,
+	.start		= mp_start,
+	.hangup		= mp_hangup,
+	.break_ctl	= mp_break_ctl,
+	.wait_until_sent= mp_wait_until_sent,
+#ifdef CONFIG_PROC_FS
+	.proc_fops	= NULL,
+#endif
+	.tiocmget	= mp_tiocmget,
+	.tiocmset	= mp_tiocmset,
+};
+
+static int mp_register_driver(struct uart_driver *drv)
+{
+	struct tty_driver *normal = NULL;
+	int i, retval;
+
+	drv->state = kmalloc(sizeof(struct sb_uart_state) * drv->nr, GFP_KERNEL);
+	retval = -ENOMEM;
+	if (!drv->state)
+	{
+		printk("SB PCI Error: Kernel memory allocation error!\n");
+		goto out;
+	}
+	memset(drv->state, 0, sizeof(struct sb_uart_state) * drv->nr);
+
+	normal = alloc_tty_driver(drv->nr);
+	if (!normal)
+	{
+		printk("SB PCI Error: tty allocation error!\n");
+		goto out;
+	}
+
+	drv->tty_driver = normal;
+
+	normal->owner           = drv->owner;
+	normal->magic		= TTY_DRIVER_MAGIC;
+	normal->driver_name     = drv->driver_name;
+	normal->name		= drv->dev_name;
+	normal->major		= drv->major;
+	normal->minor_start	= drv->minor;
+
+	normal->num		= MAX_MP_PORT ; 
+
+	normal->type		= TTY_DRIVER_TYPE_SERIAL;
+	normal->subtype		= SERIAL_TYPE_NORMAL;
+	normal->init_termios	= tty_std_termios;
+	normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	normal->flags		= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	normal->driver_state    = drv;
+
+	tty_set_operations(normal, &mp_ops);
+
+for (i = 0; i < drv->nr; i++) {
+	struct sb_uart_state *state = drv->state + i;
+
+	state->close_delay     = 500;   
+	state->closing_wait    = 30000; 
+
+	mutex_init(&state->mutex);
+	}
+
+	retval = tty_register_driver(normal);
+out:
+	if (retval < 0) {
+		printk("Register tty driver Fail!\n");
+		put_tty_driver(normal);
+		kfree(drv->state);
+	}
+
+	return retval;
+}
+
+void mp_unregister_driver(struct uart_driver *drv)
+{
+    struct tty_driver *normal = NULL;
+
+    normal = drv->tty_driver;
+
+    if (!normal)
+    {
+        return;
+    }
+
+    tty_unregister_driver(normal);
+    put_tty_driver(normal);
+    drv->tty_driver = NULL;
+
+
+    if (drv->state)
+    {
+        kfree(drv->state);
+    }
+
+}
+
+static int mp_add_one_port(struct uart_driver *drv, struct sb_uart_port *port)
+{
+	struct sb_uart_state *state;
+	int ret = 0;
+
+
+	if (port->line >= drv->nr)
+		return -EINVAL;
+
+	state = drv->state + port->line;
+
+	MP_MUTEX_LOCK(mp_mutex);
+	if (state->port) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	state->port = port;
+
+	spin_lock_init(&port->lock);
+	port->cons = drv->cons;
+	port->info = state->info;
+
+	mp_configure_port(drv, state, port);
+
+	tty_register_device(drv->tty_driver, port->line, port->dev);
+
+out:
+	MP_MUTEX_UNLOCK(mp_mutex);
+
+
+	return ret;
+}
+
+static int mp_remove_one_port(struct uart_driver *drv, struct sb_uart_port *port)
+{
+	struct sb_uart_state *state = drv->state + port->line;
+
+	if (state->port != port)
+		printk(KERN_ALERT "Removing wrong port: %p != %p\n",
+				state->port, port);
+
+	MP_MUTEX_LOCK(mp_mutex);
+
+	tty_unregister_device(drv->tty_driver, port->line);
+
+	mp_unconfigure_port(drv, state);
+	state->port = NULL;
+	MP_MUTEX_UNLOCK(mp_mutex);
+
+	return 0;
+}
+
+static void autoconfig(struct mp_port *mtpt, unsigned int probeflags)
+{
+	unsigned char status1, scratch, scratch2, scratch3;
+	unsigned char save_lcr, save_mcr;
+	unsigned long flags;
+
+	unsigned char u_type;
+	unsigned char b_ret = 0;
+
+	if (!mtpt->port.iobase && !mtpt->port.mapbase && !mtpt->port.membase)
+		return;
+
+	DEBUG_AUTOCONF("ttyMP%d: autoconf (0x%04x, 0x%p): ",
+			mtpt->port.line, mtpt->port.iobase, mtpt->port.membase);
+
+	spin_lock_irqsave(&mtpt->port.lock, flags);
+
+	if (!(mtpt->port.flags & UPF_BUGGY_UART)) {
+		scratch = serial_inp(mtpt, UART_IER);
+		serial_outp(mtpt, UART_IER, 0);
+#ifdef __i386__
+		outb(0xff, 0x080);
+#endif
+		scratch2 = serial_inp(mtpt, UART_IER) & 0x0f;
+		serial_outp(mtpt, UART_IER, 0x0F);
+#ifdef __i386__
+		outb(0, 0x080);
+#endif
+		scratch3 = serial_inp(mtpt, UART_IER) & 0x0F;
+		serial_outp(mtpt, UART_IER, scratch);
+		if (scratch2 != 0 || scratch3 != 0x0F) {
+			DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
+					scratch2, scratch3);
+			goto out;
+		}
+	}
+
+	save_mcr = serial_in(mtpt, UART_MCR);
+	save_lcr = serial_in(mtpt, UART_LCR);
+
+	if (!(mtpt->port.flags & UPF_SKIP_TEST)) {
+		serial_outp(mtpt, UART_MCR, UART_MCR_LOOP | 0x0A);
+		status1 = serial_inp(mtpt, UART_MSR) & 0xF0;
+		serial_outp(mtpt, UART_MCR, save_mcr);
+		if (status1 != 0x90) {
+			DEBUG_AUTOCONF("LOOP test failed (%02x) ",
+					status1);
+			goto out;
+		}
+	}
+
+	serial_outp(mtpt, UART_LCR, 0xBF);
+	serial_outp(mtpt, UART_EFR, 0);
+	serial_outp(mtpt, UART_LCR, 0);
+
+	serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = serial_in(mtpt, UART_IIR) >> 6;
+
+	DEBUG_AUTOCONF("iir=%d ", scratch);
+	if(mtpt->device->nr_ports >= 8)
+		b_ret = read_option_register(mtpt,(MP_OPTR_DIR0 + ((mtpt->port.line)/8)));
+	else	
+		b_ret = read_option_register(mtpt,MP_OPTR_DIR0);
+	u_type = (b_ret & 0xf0) >> 4;
+	if(mtpt->port.type == PORT_UNKNOWN )
+	{
+		switch (u_type)
+		{
+			case DIR_UART_16C550:
+				mtpt->port.type = PORT_16C55X;
+				break;
+			case DIR_UART_16C1050:
+				mtpt->port.type = PORT_16C105X;
+				break;
+			case DIR_UART_16C1050A:
+				if (mtpt->port.line < 2)
+				{
+					mtpt->port.type = PORT_16C105XA;
+				}
+				else
+				{
+					if (mtpt->device->device_id & 0x50)
+					{
+						mtpt->port.type = PORT_16C55X;
+					}
+					else
+					{
+						mtpt->port.type = PORT_16C105X;
+					}
+				}
+				break;
+			default:	
+				mtpt->port.type = PORT_UNKNOWN;
+				break;
+		}
+	}
+
+	if(mtpt->port.type == PORT_UNKNOWN )
+	{
+printk("unknow2\n");
+		switch (scratch) {
+			case 0:
+			case 1:
+				mtpt->port.type = PORT_UNKNOWN;
+				break;
+			case 2:
+			case 3:
+				mtpt->port.type = PORT_16C55X;
+				break;
+		}
+	}
+
+	serial_outp(mtpt, UART_LCR, save_lcr);
+
+	mtpt->port.fifosize = uart_config[mtpt->port.type].dfl_xmit_fifo_size;
+	mtpt->capabilities = uart_config[mtpt->port.type].flags;
+
+	if (mtpt->port.type == PORT_UNKNOWN)
+		goto out;
+	serial_outp(mtpt, UART_MCR, save_mcr);
+	serial_outp(mtpt, UART_FCR, (UART_FCR_ENABLE_FIFO |
+				UART_FCR_CLEAR_RCVR |
+				UART_FCR_CLEAR_XMIT));
+	serial_outp(mtpt, UART_FCR, 0);
+	(void)serial_in(mtpt, UART_RX);
+	serial_outp(mtpt, UART_IER, 0);
+
+out:
+	spin_unlock_irqrestore(&mtpt->port.lock, flags);
+	DEBUG_AUTOCONF("type=%s\n", uart_config[mtpt->port.type].name);
+}
+
+static void autoconfig_irq(struct mp_port *mtpt)
+{
+	unsigned char save_mcr, save_ier;
+	unsigned long irqs;
+	int irq;
+
+	/* forget possible initially masked and pending IRQ */
+	probe_irq_off(probe_irq_on());
+	save_mcr = serial_inp(mtpt, UART_MCR);
+	save_ier = serial_inp(mtpt, UART_IER);
+	serial_outp(mtpt, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+
+	irqs = probe_irq_on();
+	serial_outp(mtpt, UART_MCR, 0);
+	serial_outp(mtpt, UART_MCR,
+		UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+
+	serial_outp(mtpt, UART_IER, 0x0f);    /* enable all intrs */
+	(void)serial_inp(mtpt, UART_LSR);
+	(void)serial_inp(mtpt, UART_RX);
+	(void)serial_inp(mtpt, UART_IIR);
+	(void)serial_inp(mtpt, UART_MSR);
+	serial_outp(mtpt, UART_TX, 0xFF);
+	irq = probe_irq_off(irqs);
+
+	serial_outp(mtpt, UART_MCR, save_mcr);
+	serial_outp(mtpt, UART_IER, save_ier);
+
+	mtpt->port.irq = (irq > 0) ? irq : 0;
+}
+
+static void multi_stop_tx(struct sb_uart_port *port)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+
+	if (mtpt->ier & UART_IER_THRI) {
+		mtpt->ier &= ~UART_IER_THRI;
+		serial_out(mtpt, UART_IER, mtpt->ier);
+	}
+
+	tasklet_schedule(&port->info->tlet);
+}
+
+static void multi_start_tx(struct sb_uart_port *port)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+
+	if (!(mtpt->ier & UART_IER_THRI)) {
+		mtpt->ier |= UART_IER_THRI;
+		serial_out(mtpt, UART_IER, mtpt->ier);
+	}
+}
+
+static void multi_stop_rx(struct sb_uart_port *port)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+
+	mtpt->ier &= ~UART_IER_RLSI;
+	mtpt->port.read_status_mask &= ~UART_LSR_DR;
+	serial_out(mtpt, UART_IER, mtpt->ier);
+}
+
+static void multi_enable_ms(struct sb_uart_port *port)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+
+	mtpt->ier |= UART_IER_MSI;
+	serial_out(mtpt, UART_IER, mtpt->ier);
+}
+
+
+static _INLINE_ void receive_chars(struct mp_port *mtpt, int *status )
+{
+	struct tty_struct *tty = mtpt->port.info->tty;
+	unsigned char lsr = *status;
+	int max_count = 256;
+	unsigned char ch;
+	char flag;
+
+	//lsr &= mtpt->port.read_status_mask;
+
+	do {
+		if ((lsr & UART_LSR_PE) && (mtpt->port.mdmode & MDMODE_ENABLE))
+		{
+			ch = serial_inp(mtpt, UART_RX);
+		}
+		else if (lsr & UART_LSR_SPECIAL) 
+		{
+			flag = 0;
+			ch = serial_inp(mtpt, UART_RX);
+
+			if (lsr & UART_LSR_BI) 
+			{
+
+				mtpt->port.icount.brk++;
+				flag = TTY_BREAK;
+
+				if (sb_uart_handle_break(&mtpt->port))
+					goto ignore_char;
+			} 
+			if (lsr & UART_LSR_PE)
+			{
+				mtpt->port.icount.parity++;
+				flag = TTY_PARITY;
+			}
+			if (lsr & UART_LSR_FE)
+			{
+				mtpt->port.icount.frame++;
+				flag = TTY_FRAME;
+			}
+			if (lsr & UART_LSR_OE)
+			{
+				mtpt->port.icount.overrun++;
+				flag = TTY_OVERRUN;
+			}
+			tty_insert_flip_char(tty, ch, flag);
+		}
+		else
+		{
+			ch = serial_inp(mtpt, UART_RX);
+			tty_insert_flip_char(tty, ch, 0);
+		}
+ignore_char:
+		lsr = serial_inp(mtpt, UART_LSR);
+	} while ((lsr & UART_LSR_DR) && (max_count-- > 0));
+
+	tty_flip_buffer_push(tty);
+}
+
+
+
+
+static _INLINE_ void transmit_chars(struct mp_port *mtpt)
+{
+	struct circ_buf *xmit = &mtpt->port.info->xmit;
+	int count;
+
+	if (mtpt->port.x_char) {
+		serial_outp(mtpt, UART_TX, mtpt->port.x_char);
+		mtpt->port.icount.tx++;
+		mtpt->port.x_char = 0;
+		return;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(&mtpt->port)) {
+		multi_stop_tx(&mtpt->port);
+		return;
+	}
+
+	count = uart_circ_chars_pending(xmit);
+
+	if(count > mtpt->port.fifosize)
+	{
+		count = mtpt->port.fifosize;
+	}
+
+	printk("[%d] mdmode: %x\n", mtpt->port.line, mtpt->port.mdmode);
+	do {
+#if 0
+		/* check multi-drop mode */
+		if ((mtpt->port.mdmode & (MDMODE_ENABLE | MDMODE_ADDR)) == (MDMODE_ENABLE | MDMODE_ADDR))
+		{
+			printk("send address\n");
+			/* send multi-drop address */
+			serial_out(mtpt, UART_SCR, xmit->buf[xmit->tail]);
+		}
+		else
+#endif
+		{
+			serial_out(mtpt, UART_TX, xmit->buf[xmit->tail]);
+		}
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		mtpt->port.icount.tx++;
+	} while (--count > 0);
+}
+
+
+
+static _INLINE_ void check_modem_status(struct mp_port *mtpt)
+{
+	int status;
+
+	status = serial_in(mtpt, UART_MSR);
+
+	if ((status & UART_MSR_ANY_DELTA) == 0)
+		return;
+
+	if (status & UART_MSR_TERI)
+		mtpt->port.icount.rng++;
+	if (status & UART_MSR_DDSR)
+		mtpt->port.icount.dsr++;
+	if (status & UART_MSR_DDCD)
+		sb_uart_handle_dcd_change(&mtpt->port, status & UART_MSR_DCD);
+	if (status & UART_MSR_DCTS)
+		sb_uart_handle_cts_change(&mtpt->port, status & UART_MSR_CTS);
+
+	wake_up_interruptible(&mtpt->port.info->delta_msr_wait);
+}
+
+static inline void multi_handle_port(struct mp_port *mtpt)
+{
+	unsigned int status = serial_inp(mtpt, UART_LSR);
+
+	//printk("lsr: %x\n", status);
+
+	if ((status & UART_LSR_DR) || (status & UART_LSR_SPECIAL))
+		receive_chars(mtpt, &status);
+	check_modem_status(mtpt);
+	if (status & UART_LSR_THRE)
+	{
+		if ((mtpt->port.type == PORT_16C105X)
+			|| (mtpt->port.type == PORT_16C105XA))
+			transmit_chars(mtpt);
+		else
+		{
+			if (mtpt->interface >= RS485NE)
+				uart_set_mctrl(&mtpt->port, TIOCM_RTS);
+			
+			transmit_chars(mtpt);
+
+
+			if (mtpt->interface >= RS485NE)
+			{
+				while((status=serial_in(mtpt,UART_LSR) &0x60)!=0x60);
+				uart_clear_mctrl(&mtpt->port, TIOCM_RTS);
+			}
+		}
+	}
+}
+
+
+
+static irqreturn_t multi_interrupt(int irq, void *dev_id)
+{
+	struct irq_info *iinfo = dev_id;
+	struct list_head *lhead, *end = NULL;
+	int pass_counter = 0;
+
+
+	spin_lock(&iinfo->lock);
+
+	lhead = iinfo->head;
+	do {
+		struct mp_port *mtpt;
+		unsigned int iir;
+
+		mtpt = list_entry(lhead, struct mp_port, list);
+		
+		iir = serial_in(mtpt, UART_IIR);
+		printk("intrrupt! port %d, iir 0x%x\n", mtpt->port.line, iir); //wlee
+		if (!(iir & UART_IIR_NO_INT)) 
+		{
+			printk("interrupt handle\n");
+			spin_lock(&mtpt->port.lock);
+			multi_handle_port(mtpt);
+			spin_unlock(&mtpt->port.lock);
+
+			end = NULL;
+		} else if (end == NULL)
+			end = lhead;
+
+		lhead = lhead->next;
+		if (lhead == iinfo->head && pass_counter++ > PASS_LIMIT) 
+		{
+			printk(KERN_ERR "multi: too much work for "
+					"irq%d\n", irq);
+			printk( "multi: too much work for "
+					"irq%d\n", irq);
+			break;
+		}
+	} while (lhead != end);
+
+	spin_unlock(&iinfo->lock);
+
+
+        return IRQ_HANDLED;
+}
+
+static void serial_do_unlink(struct irq_info *i, struct mp_port *mtpt)
+{
+	spin_lock_irq(&i->lock);
+
+	if (!list_empty(i->head)) {
+		if (i->head == &mtpt->list)
+			i->head = i->head->next;
+		list_del(&mtpt->list);
+	} else {
+		i->head = NULL;
+	}
+
+	spin_unlock_irq(&i->lock);
+}
+
+static int serial_link_irq_chain(struct mp_port *mtpt)
+{
+	struct irq_info *i = irq_lists + mtpt->port.irq;
+	int ret, irq_flags = mtpt->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
+	spin_lock_irq(&i->lock);
+
+	if (i->head) {
+		list_add(&mtpt->list, i->head);
+		spin_unlock_irq(&i->lock);
+
+		ret = 0;
+	} else {
+		INIT_LIST_HEAD(&mtpt->list);
+		i->head = &mtpt->list;
+		spin_unlock_irq(&i->lock);
+
+		ret = request_irq(mtpt->port.irq, multi_interrupt,
+				irq_flags, "serial", i);
+		if (ret < 0)
+			serial_do_unlink(i, mtpt);
+	}
+
+	return ret;
+}
+
+
+
+
+static void serial_unlink_irq_chain(struct mp_port *mtpt)
+{
+	struct irq_info *i = irq_lists + mtpt->port.irq;
+
+	if (list_empty(i->head))
+	{
+		free_irq(mtpt->port.irq, i);
+	}
+	serial_do_unlink(i, mtpt);
+}
+
+static void multi_timeout(unsigned long data)
+{
+	struct mp_port *mtpt = (struct mp_port *)data;
+
+
+	spin_lock(&mtpt->port.lock);
+	multi_handle_port(mtpt);
+	spin_unlock(&mtpt->port.lock);
+
+	mod_timer(&mtpt->timer, jiffies+1 );
+}
+
+static unsigned int multi_tx_empty(struct sb_uart_port *port)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+	unsigned long flags;
+	unsigned int ret;
+
+	spin_lock_irqsave(&mtpt->port.lock, flags);
+	ret = serial_in(mtpt, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+	spin_unlock_irqrestore(&mtpt->port.lock, flags);
+
+	return ret;
+}
+
+
+static unsigned int multi_get_mctrl(struct sb_uart_port *port)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+	unsigned char status;
+	unsigned int ret;
+
+	status = serial_in(mtpt, UART_MSR);
+
+	ret = 0;
+	if (status & UART_MSR_DCD)
+		ret |= TIOCM_CAR;
+	if (status & UART_MSR_RI)
+		ret |= TIOCM_RNG;
+	if (status & UART_MSR_DSR)
+		ret |= TIOCM_DSR;
+	if (status & UART_MSR_CTS)
+		ret |= TIOCM_CTS;
+	return ret;
+}
+
+static void multi_set_mctrl(struct sb_uart_port *port, unsigned int mctrl)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+	unsigned char mcr = 0;
+
+	mctrl &= 0xff;
+
+	if (mctrl & TIOCM_RTS)
+		mcr |= UART_MCR_RTS;
+	if (mctrl & TIOCM_DTR)
+		mcr |= UART_MCR_DTR;
+	if (mctrl & TIOCM_OUT1)
+		mcr |= UART_MCR_OUT1;
+	if (mctrl & TIOCM_OUT2)
+		mcr |= UART_MCR_OUT2;
+	if (mctrl & TIOCM_LOOP)
+		mcr |= UART_MCR_LOOP;
+
+
+	serial_out(mtpt, UART_MCR, mcr);
+}
+
+
+static void multi_break_ctl(struct sb_uart_port *port, int break_state)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mtpt->port.lock, flags);
+	if (break_state == -1)
+		mtpt->lcr |= UART_LCR_SBC;
+	else
+		mtpt->lcr &= ~UART_LCR_SBC;
+	serial_out(mtpt, UART_LCR, mtpt->lcr);
+	spin_unlock_irqrestore(&mtpt->port.lock, flags);
+}
+
+
+
+static int multi_startup(struct sb_uart_port *port)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+	unsigned long flags;
+	int retval;
+
+	mtpt->capabilities = uart_config[mtpt->port.type].flags;
+	mtpt->mcr = 0;
+
+	if (mtpt->capabilities & UART_CLEAR_FIFO) {
+		serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO);
+		serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO |
+				UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+		serial_outp(mtpt, UART_FCR, 0);
+	}
+
+	(void) serial_inp(mtpt, UART_LSR);
+	(void) serial_inp(mtpt, UART_RX);
+	(void) serial_inp(mtpt, UART_IIR);
+	(void) serial_inp(mtpt, UART_MSR);
+	//test-wlee 9-bit disable
+	serial_outp(mtpt, UART_MSR, 0);
+
+
+	if (!(mtpt->port.flags & UPF_BUGGY_UART) &&
+			(serial_inp(mtpt, UART_LSR) == 0xff)) {
+		printk("ttyS%d: LSR safety check engaged!\n", mtpt->port.line);
+		//return -ENODEV;
+	}
+
+	if ((!is_real_interrupt(mtpt->port.irq)) || (mtpt->poll_type==TYPE_POLL)) {
+		unsigned int timeout = mtpt->port.timeout;
+
+		timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
+
+		mtpt->timer.data = (unsigned long)mtpt;
+		mod_timer(&mtpt->timer, jiffies + timeout);
+	} 
+	else 
+	{
+		retval = serial_link_irq_chain(mtpt);
+		if (retval)
+			return retval;
+	}
+
+	serial_outp(mtpt, UART_LCR, UART_LCR_WLEN8);
+
+	spin_lock_irqsave(&mtpt->port.lock, flags);
+	if ((is_real_interrupt(mtpt->port.irq))||(mtpt->poll_type==TYPE_INTERRUPT))
+		mtpt->port.mctrl |= TIOCM_OUT2;
+
+	multi_set_mctrl(&mtpt->port, mtpt->port.mctrl);
+	spin_unlock_irqrestore(&mtpt->port.lock, flags);
+
+	
+	mtpt->ier = UART_IER_RLSI | UART_IER_RDI;
+	serial_outp(mtpt, UART_IER, mtpt->ier);
+
+	(void) serial_inp(mtpt, UART_LSR);
+	(void) serial_inp(mtpt, UART_RX);
+	(void) serial_inp(mtpt, UART_IIR);
+	(void) serial_inp(mtpt, UART_MSR);
+
+	return 0;
+}
+
+
+
+static void multi_shutdown(struct sb_uart_port *port)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+	unsigned long flags;
+
+
+	mtpt->ier = 0;
+	serial_outp(mtpt, UART_IER, 0);
+
+	spin_lock_irqsave(&mtpt->port.lock, flags);
+	mtpt->port.mctrl &= ~TIOCM_OUT2;
+
+	multi_set_mctrl(&mtpt->port, mtpt->port.mctrl);
+	spin_unlock_irqrestore(&mtpt->port.lock, flags);
+
+	serial_out(mtpt, UART_LCR, serial_inp(mtpt, UART_LCR) & ~UART_LCR_SBC);
+	serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO |
+			UART_FCR_CLEAR_RCVR |
+			UART_FCR_CLEAR_XMIT);
+	serial_outp(mtpt, UART_FCR, 0);
+
+
+	(void) serial_in(mtpt, UART_RX);
+
+	if ((!is_real_interrupt(mtpt->port.irq))||(mtpt->poll_type==TYPE_POLL))
+	{
+		del_timer_sync(&mtpt->timer);
+	}
+	else
+	{
+		serial_unlink_irq_chain(mtpt);
+	}
+}
+
+
+
+static unsigned int multi_get_divisor(struct sb_uart_port *port, unsigned int baud)
+{
+	unsigned int quot;
+
+	if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
+			baud == (port->uartclk/4))
+		quot = 0x8001;
+	else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
+			baud == (port->uartclk/8))
+		quot = 0x8002;
+	else
+		quot = sb_uart_get_divisor(port, baud);
+
+	return quot;
+}
+
+
+
+
+static void multi_set_termios(struct sb_uart_port *port, struct MP_TERMIOS *termios, struct MP_TERMIOS *old)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+	unsigned char cval, fcr = 0;
+	unsigned long flags;
+	unsigned int baud, quot;
+
+	switch (termios->c_cflag & CSIZE) {
+		case CS5:
+			cval = 0x00;
+			break;
+		case CS6:
+			cval = 0x01;
+			break;
+		case CS7:
+			cval = 0x02;
+			break;
+		default:
+		case CS8:
+			cval = 0x03;
+			break;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		cval |= 0x04;
+	if (termios->c_cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(termios->c_cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+
+#ifdef CMSPAR
+	if (termios->c_cflag & CMSPAR)
+		cval |= UART_LCR_SPAR;
+#endif
+
+	baud = sb_uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+	quot = multi_get_divisor(port, baud);
+
+	if (mtpt->capabilities & UART_USE_FIFO) {
+		//if (baud < 2400)
+		//	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+		//else
+		//	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+
+		//	fcr = UART_FCR_ENABLE_FIFO | 0x90;
+			fcr = fcr_arr[mtpt->port.line];
+	}
+
+	spin_lock_irqsave(&mtpt->port.lock, flags);
+
+	sb_uart_update_timeout(port, termios->c_cflag, baud);
+
+	mtpt->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+	if (termios->c_iflag & INPCK)
+		mtpt->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (termios->c_iflag & (BRKINT | PARMRK))
+		mtpt->port.read_status_mask |= UART_LSR_BI;
+
+	mtpt->port.ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		mtpt->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		mtpt->port.ignore_status_mask |= UART_LSR_BI;
+		if (termios->c_iflag & IGNPAR)
+			mtpt->port.ignore_status_mask |= UART_LSR_OE;
+	}
+
+	if ((termios->c_cflag & CREAD) == 0)
+		mtpt->port.ignore_status_mask |= UART_LSR_DR;
+
+	mtpt->ier &= ~UART_IER_MSI;
+	if (UART_ENABLE_MS(&mtpt->port, termios->c_cflag))
+		mtpt->ier |= UART_IER_MSI;
+
+	serial_out(mtpt, UART_IER, mtpt->ier);
+
+	if (mtpt->capabilities & UART_STARTECH) {
+		serial_outp(mtpt, UART_LCR, 0xBF);
+		serial_outp(mtpt, UART_EFR,
+				termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0);
+	}
+
+	serial_outp(mtpt, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+
+	serial_outp(mtpt, UART_DLL, quot & 0xff);     /* LS of divisor */
+	serial_outp(mtpt, UART_DLM, quot >> 8);       /* MS of divisor */
+
+	serial_outp(mtpt, UART_LCR, cval);        /* reset DLAB */
+	mtpt->lcr = cval;                 /* Save LCR */
+
+	if (fcr & UART_FCR_ENABLE_FIFO) {
+		/* emulated UARTs (Lucent Venus 167x) need two steps */
+		serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO);
+	}
+
+	serial_outp(mtpt, UART_FCR, fcr);     /* set fcr */
+
+
+	if ((mtpt->port.type == PORT_16C105X)
+		|| (mtpt->port.type == PORT_16C105XA))
+	{
+		if(deep[mtpt->port.line]!=0)
+			set_deep_fifo(port, ENABLE);
+
+		if (mtpt->interface != RS232)
+			set_auto_rts(port,mtpt->interface);
+
+	}
+	else
+	{
+		if (mtpt->interface >= RS485NE)
+		{
+			uart_clear_mctrl(&mtpt->port, TIOCM_RTS);
+		}
+	}
+
+	if(mtpt->device->device_id == PCI_DEVICE_ID_MP4M)
+	{
+		SendATCommand(mtpt);
+		printk("SendATCommand\n");
+	}	
+	multi_set_mctrl(&mtpt->port, mtpt->port.mctrl);
+	spin_unlock_irqrestore(&mtpt->port.lock, flags);
+}
+
+static void multi_pm(struct sb_uart_port *port, unsigned int state, unsigned int oldstate)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+	if (state) {
+		if (mtpt->capabilities & UART_STARTECH) {
+			serial_outp(mtpt, UART_LCR, 0xBF);
+			serial_outp(mtpt, UART_EFR, UART_EFR_ECB);
+			serial_outp(mtpt, UART_LCR, 0);
+			serial_outp(mtpt, UART_IER, UART_IERX_SLEEP);
+			serial_outp(mtpt, UART_LCR, 0xBF);
+			serial_outp(mtpt, UART_EFR, 0);
+			serial_outp(mtpt, UART_LCR, 0);
+		}
+
+		if (mtpt->pm)
+			mtpt->pm(port, state, oldstate);
+	} 
+	else 
+	{
+		if (mtpt->capabilities & UART_STARTECH) {
+			serial_outp(mtpt, UART_LCR, 0xBF);
+			serial_outp(mtpt, UART_EFR, UART_EFR_ECB);
+			serial_outp(mtpt, UART_LCR, 0);
+			serial_outp(mtpt, UART_IER, 0);
+			serial_outp(mtpt, UART_LCR, 0xBF);
+			serial_outp(mtpt, UART_EFR, 0);
+			serial_outp(mtpt, UART_LCR, 0);
+		}
+
+		if (mtpt->pm)
+			mtpt->pm(port, state, oldstate);
+	}
+}
+
+static void multi_release_std_resource(struct mp_port *mtpt)
+{
+	unsigned int size = 8 << mtpt->port.regshift;
+
+	switch (mtpt->port.iotype) {
+		case UPIO_MEM:
+			if (!mtpt->port.mapbase)
+				break;
+
+			if (mtpt->port.flags & UPF_IOREMAP) {
+				iounmap(mtpt->port.membase);
+				mtpt->port.membase = NULL;
+			}
+
+			release_mem_region(mtpt->port.mapbase, size);
+			break;
+
+		case UPIO_HUB6:
+		case UPIO_PORT:
+			release_region(mtpt->port.iobase,size);
+			break;
+	}
+}
+
+static void multi_release_port(struct sb_uart_port *port)
+{
+}
+
+static int multi_request_port(struct sb_uart_port *port)
+{
+	return 0;
+}
+
+static void multi_config_port(struct sb_uart_port *port, int flags)
+{
+	struct mp_port *mtpt = (struct mp_port *)port;
+	int probeflags = PROBE_ANY;
+
+	if (flags & UART_CONFIG_TYPE)
+		autoconfig(mtpt, probeflags);
+	if (mtpt->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
+		autoconfig_irq(mtpt);
+
+	if (mtpt->port.type == PORT_UNKNOWN)
+		multi_release_std_resource(mtpt);
+}
+
+static int multi_verify_port(struct sb_uart_port *port, struct serial_struct *ser)
+{
+	if (ser->irq >= NR_IRQS || ser->irq < 0 ||
+			ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
+			ser->type == PORT_STARTECH)
+		return -EINVAL;
+	return 0;
+}
+
+static const char * multi_type(struct sb_uart_port *port)
+{
+	int type = port->type;
+
+	if (type >= ARRAY_SIZE(uart_config))
+		type = 0;
+	return uart_config[type].name;
+}
+
+static struct sb_uart_ops multi_pops = {
+	.tx_empty   = multi_tx_empty,
+	.set_mctrl  = multi_set_mctrl,
+	.get_mctrl  = multi_get_mctrl,
+	.stop_tx    = multi_stop_tx,
+	.start_tx   = multi_start_tx,
+	.stop_rx    = multi_stop_rx,
+	.enable_ms  = multi_enable_ms,
+	.break_ctl  = multi_break_ctl,
+	.startup    = multi_startup,
+	.shutdown   = multi_shutdown,
+	.set_termios    = multi_set_termios,
+	.pm     	= multi_pm,
+	.type       	= multi_type,
+	.release_port   = multi_release_port,
+	.request_port   = multi_request_port,
+	.config_port    = multi_config_port,
+	.verify_port    = multi_verify_port,
+};
+
+static struct uart_driver multi_reg = {
+	.owner          = THIS_MODULE,
+	.driver_name    = "goldel_tulip",
+	.dev_name       = "ttyMP",
+	.major          = SB_TTY_MP_MAJOR,
+	.minor          = 0,
+	.nr             = MAX_MP_PORT, 
+	.cons           = NULL,
+};
+
+static void __init multi_init_ports(void)
+{
+	struct mp_port *mtpt;
+	static int first = 1;
+	int i,j,k;
+	unsigned char osc;
+	unsigned char b_ret = 0;
+	static struct mp_device_t * sbdev; 
+
+	if (!first)
+		return;
+	first = 0;
+
+	mtpt = multi_ports; 
+
+	for (k=0;k<NR_BOARD;k++)
+	{
+		sbdev = &mp_devs[k];
+
+		for (i = 0; i < sbdev->nr_ports; i++, mtpt++) 
+		{
+			mtpt->device 		= sbdev;
+			mtpt->port.iobase   = sbdev->uart_access_addr + 8*i;
+			mtpt->port.irq      = sbdev->irq;
+			if ( ((sbdev->device_id == PCI_DEVICE_ID_MP4)&&(sbdev->revision==0x91)))
+				mtpt->interface_config_addr = sbdev->option_reg_addr + 0x08 + i;
+			else if (sbdev->revision == 0xc0)
+				mtpt->interface_config_addr = sbdev->option_reg_addr + 0x08 + (i & 0x1);
+			else
+				mtpt->interface_config_addr = sbdev->option_reg_addr + 0x08 + i/8;
+
+			mtpt->option_base_addr = sbdev->option_reg_addr;
+
+			mtpt->poll_type = sbdev->poll_type;
+
+			mtpt->port.uartclk  = BASE_BAUD * 16;
+
+			/* get input clock infomation */
+			osc = inb(sbdev->option_reg_addr + MP_OPTR_DIR0 + i/8) & 0x0F;
+			if (osc==0x0f)
+				osc = 0;
+			for(j=0;j<osc;j++)
+				mtpt->port.uartclk *= 2;
+			mtpt->port.flags    |= STD_COM_FLAGS | UPF_SHARE_IRQ ;
+			mtpt->port.iotype   = UPIO_PORT;
+			mtpt->port.ops      = &multi_pops;
+
+			if (sbdev->revision == 0xc0)
+			{
+				/* for SB16C1053APCI */
+				b_ret = sb1053a_get_interface(mtpt, i);
+			}
+			else
+			{
+				b_ret = read_option_register(mtpt,(MP_OPTR_IIR0 + i/8));
+				printk("IIR_RET = %x\n",b_ret);
+			}
+
+			if(IIR_RS232 == (b_ret & IIR_RS232))
+			{
+				mtpt->interface = RS232;
+			}
+			if(IIR_RS422 == (b_ret & IIR_RS422))
+			{
+				mtpt->interface = RS422PTP;
+			}
+			if(IIR_RS485 == (b_ret & IIR_RS485))
+			{
+				mtpt->interface = RS485NE;
+			}
+		}
+	}
+}
+
+static void __init multi_register_ports(struct uart_driver *drv)
+{
+	int i;
+
+	multi_init_ports();
+
+	for (i = 0; i < NR_PORTS; i++) {
+		struct mp_port *mtpt = &multi_ports[i];
+
+		mtpt->port.line = i;
+		mtpt->port.ops = &multi_pops;
+		init_timer(&mtpt->timer);
+		mtpt->timer.function = multi_timeout;
+		mp_add_one_port(drv, &mtpt->port);
+	}
+}
+
+/**
+ * pci_remap_base - remap BAR value of pci device
+ *
+ * PARAMETERS
+ *  pcidev  - pci_dev structure address
+ *  offset  - BAR offset PCI_BASE_ADDRESS_0 ~ PCI_BASE_ADDRESS_4
+ *  address - address to be changed BAR value
+ *  size	- size of address space 
+ *
+ * RETURNS
+ *  If this function performs successful, it returns 0. Otherwise, It returns -1.
+ */
+static int pci_remap_base(struct pci_dev *pcidev, unsigned int offset, 
+		unsigned int address, unsigned int size) 
+{
+#if 0
+	struct resource *root;
+	unsigned index = (offset - 0x10) >> 2;
+#endif
+
+	pci_write_config_dword(pcidev, offset, address);
+#if 0
+	root = pcidev->resource[index].parent;
+	release_resource(&pcidev->resource[index]);
+	address &= ~0x1;
+	pcidev->resource[index].start = address;
+	pcidev->resource[index].end	  = address + size - 1;
+
+	if (request_resource(root, &pcidev->resource[index]) != NULL)
+	{
+		printk(KERN_ERR "pci remap conflict!! 0x%x\n", address);
+		return (-1);
+	}
+#endif
+
+	return (0);
+}
+
+static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd)
+{
+	static struct mp_device_t * sbdev = mp_devs;
+	unsigned long addr = 0;
+	int j;
+	struct resource * ret = NULL;
+
+	sbdev->device_id = brd.device_id;
+	pci_read_config_byte(pcidev, PCI_CLASS_REVISION, &(sbdev->revision));
+	sbdev->name = brd.name;
+	sbdev->uart_access_addr = pcidev->resource[0].start & PCI_BASE_ADDRESS_IO_MASK;
+
+	/* check revision. The SB16C1053APCI's option i/o address is BAR4 */
+	if (sbdev->revision == 0xc0)
+	{
+		/* SB16C1053APCI */
+		sbdev->option_reg_addr = pcidev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK;
+	}
+	else
+	{
+		sbdev->option_reg_addr = pcidev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+	}
+#if 1	
+	if (sbdev->revision == 0xc0)
+	{
+		outb(0x00, sbdev->option_reg_addr + MP_OPTR_GPOCR);
+		inb(sbdev->option_reg_addr + MP_OPTR_GPOCR);
+		outb(0x83, sbdev->option_reg_addr + MP_OPTR_GPOCR);
+	}
+#endif
+
+	sbdev->irq = pcidev->irq;
+
+	if ((brd.device_id & 0x0800) || !(brd.device_id &0xff00))
+	{
+		sbdev->poll_type = TYPE_INTERRUPT;
+	}
+	else
+	{
+		sbdev->poll_type = TYPE_POLL;
+	}
+
+	/* codes which is specific to each board*/
+	switch(brd.device_id){
+		case PCI_DEVICE_ID_MP1 :
+		case PCIE_DEVICE_ID_MP1 :
+		case PCIE_DEVICE_ID_MP1E :
+		case PCIE_DEVICE_ID_GT_MP1 :
+			sbdev->nr_ports = 1;
+			break;
+		case PCI_DEVICE_ID_MP2 :
+		case PCIE_DEVICE_ID_MP2 :
+		case PCIE_DEVICE_ID_GT_MP2 :
+		case PCIE_DEVICE_ID_MP2B :
+		case PCIE_DEVICE_ID_MP2E :
+			sbdev->nr_ports = 2;
+
+			/* serial base address remap */
+			if (sbdev->revision == 0xc0)
+			{
+				int prev_port_addr = 0;
+
+				pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr);
+				pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8);
+			}
+			break;
+		case PCI_DEVICE_ID_MP4 :
+		case PCI_DEVICE_ID_MP4A :
+		case PCIE_DEVICE_ID_MP4 :
+		case PCI_DEVICE_ID_GT_MP4 :
+		case PCI_DEVICE_ID_GT_MP4A :
+		case PCIE_DEVICE_ID_GT_MP4 :
+		case PCI_DEVICE_ID_MP4M :
+		case PCIE_DEVICE_ID_MP4B :
+			sbdev->nr_ports = 4;
+
+			if(sbdev->revision == 0x91){
+				sbdev->reserved_addr[0] = pcidev->resource[0].start & PCI_BASE_ADDRESS_IO_MASK;
+				outb(0x03 , sbdev->reserved_addr[0] + 0x01);
+				outb(0x03 , sbdev->reserved_addr[0] + 0x02);
+				outb(0x01 , sbdev->reserved_addr[0] + 0x20);
+				outb(0x00 , sbdev->reserved_addr[0] + 0x21);
+				request_region(sbdev->reserved_addr[0], 32, sbdev->name);
+				sbdev->uart_access_addr = pcidev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+				sbdev->option_reg_addr = pcidev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
+			}
+
+			/* SB16C1053APCI */
+			if (sbdev->revision == 0xc0)
+			{
+				int prev_port_addr = 0;
+
+				pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr);
+				pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8);
+				pci_remap_base(pcidev, PCI_BASE_ADDRESS_2, prev_port_addr + 16, 8);
+				pci_remap_base(pcidev, PCI_BASE_ADDRESS_3, prev_port_addr + 24, 8);
+			}
+			break;
+		case PCI_DEVICE_ID_MP6 :
+		case PCI_DEVICE_ID_MP6A :
+		case PCI_DEVICE_ID_GT_MP6 :
+		case PCI_DEVICE_ID_GT_MP6A :
+			sbdev->nr_ports = 6;
+
+			/* SB16C1053APCI */
+			if (sbdev->revision == 0xc0)
+			{
+				int prev_port_addr = 0;
+
+				pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr);
+				pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8);
+				pci_remap_base(pcidev, PCI_BASE_ADDRESS_2, prev_port_addr + 16, 16);
+				pci_remap_base(pcidev, PCI_BASE_ADDRESS_3, prev_port_addr + 32, 16);
+			}
+			break;
+		case PCI_DEVICE_ID_MP8 :
+		case PCIE_DEVICE_ID_MP8 :
+		case PCI_DEVICE_ID_GT_MP8 :
+		case PCIE_DEVICE_ID_GT_MP8 :
+		case PCIE_DEVICE_ID_MP8B :
+			sbdev->nr_ports = 8;
+			break;
+		case PCI_DEVICE_ID_MP32 :
+		case PCIE_DEVICE_ID_MP32 :
+		case PCI_DEVICE_ID_GT_MP32 :
+		case PCIE_DEVICE_ID_GT_MP32 :
+			{
+				int portnum_hex=0;
+				portnum_hex = inb(sbdev->option_reg_addr);
+				sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16);
+			}
+			break;
+		case PCI_DEVICE_ID_MP2S1P :
+			sbdev->nr_ports = 2;
+
+			/* SB16C1053APCI */
+			if (sbdev->revision == 0xc0)
+			{
+				int prev_port_addr = 0;
+
+				pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr);
+				pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8);
+			}
+
+			/* add PC compatible parallel port */
+			parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0);
+			break;
+		case PCI_DEVICE_ID_MP1P :
+			/* add PC compatible parallel port */
+			parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0);
+			break;
+	}
+
+	ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name);
+
+	if (sbdev->revision == 0xc0)
+	{
+		ret = request_region(sbdev->option_reg_addr, 0x40, sbdev->name);
+	}
+	else
+	{
+		ret = request_region(sbdev->option_reg_addr, 0x20, sbdev->name);
+	}
+
+
+	NR_BOARD++;
+	NR_PORTS += sbdev->nr_ports;
+
+	/* Enable PCI interrupt */
+	addr = sbdev->option_reg_addr + MP_OPTR_IMR0;
+	for(j=0; j < (sbdev->nr_ports/8)+1; j++)
+	{
+		if (sbdev->poll_type == TYPE_INTERRUPT)
+		{
+			outb(0xff,addr +j);
+		}
+	}
+	sbdev++;
+
+	return 0;
+}
+
+static int __init multi_init(void)
+{
+	int ret, i;
+	struct pci_dev  *dev = NULL;
+
+	if(fcr_count==0)
+	{
+		for(i=0;i<256;i++)
+		{
+			fcr_arr[i] = 0x01;
+			
+		}
+	}
+	if(deep_count==0)
+	{
+		for(i=0;i<256;i++)
+		{
+			deep[i] = 1;
+			
+		}
+	}
+	if(rtr_count==0)
+        {
+                for(i=0;i<256;i++)
+                {
+                        rtr[i] = 0x10;
+                }
+        }
+	if(ttr_count==0)
+        {
+                for(i=0;i<256;i++)
+                {
+                        ttr[i] = 0x38;
+                }
+        }
+
+
+printk("MULTI INIT\n");
+	for( i=0; i< mp_nrpcibrds; i++)
+	{
+
+		while( (dev = pci_get_device(mp_pciboards[i].vendor_id, mp_pciboards[i].device_id, dev) ) )
+
+		{
+printk("FOUND~~~\n");
+//	Cent OS bug fix
+//			if (mp_pciboards[i].device_id & 0x0800)
+			{
+				int status;
+	        		pci_disable_device(dev);
+	        		status = pci_enable_device(dev);
+            
+	   		     	if (status != 0)
+        			{ 
+               				printk("Multiport Board Enable Fail !\n\n");
+               				status = -ENXIO;
+                			return status;
+           			}
+			}
+
+			init_mp_dev(dev, mp_pciboards[i]);	
+		}
+	}
+
+	for (i = 0; i < NR_IRQS; i++)
+		spin_lock_init(&irq_lists[i].lock);
+
+	ret = mp_register_driver(&multi_reg);
+
+	if (ret >= 0)
+		multi_register_ports(&multi_reg);
+
+	return ret;
+}
+
+static void __exit multi_exit(void)
+{
+	int i;
+
+	for (i = 0; i < NR_PORTS; i++)
+		mp_remove_one_port(&multi_reg, &multi_ports[i].port);
+
+	mp_unregister_driver(&multi_reg);
+}
+
+module_init(multi_init);
+module_exit(multi_exit);
+
+MODULE_DESCRIPTION("SystemBase Multiport PCI/PCIe CORE");
+MODULE_LICENSE("GPL");

+ 293 - 0
drivers/staging/sb105x/sb_pci_mp.h

@@ -0,0 +1,293 @@
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/tty_driver.h>
+#include <linux/pci.h>
+#include <linux/circ_buf.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+#include <asm/serial.h>
+#include <linux/interrupt.h>
+
+
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <linux/poll.h>
+
+
+#define MP_TERMIOS  ktermios
+
+#include "sb_mp_register.h"
+#include "sb_ser_core.h"
+
+#define DRIVER_VERSION  "1.1"
+#define DRIVER_DATE     "2012/01/05"
+#define DRIVER_AUTHOR  "SYSTEMBASE<tech@sysbas.com>"
+#define DRIVER_DESC  "SystemBase PCI/PCIe Multiport Core"
+
+#define SB_TTY_MP_MAJOR			54
+#define PCI_VENDOR_ID_MULTIPORT		0x14A1
+
+#define PCI_DEVICE_ID_MP1		0x4d01
+#define PCI_DEVICE_ID_MP2		0x4d02
+#define PCI_DEVICE_ID_MP4		0x4d04
+#define PCI_DEVICE_ID_MP4A		0x4d54
+#define PCI_DEVICE_ID_MP6		0x4d06
+#define PCI_DEVICE_ID_MP6A		0x4d56
+#define PCI_DEVICE_ID_MP8		0x4d08
+#define PCI_DEVICE_ID_MP32		0x4d32
+/* Parallel port */
+#define PCI_DEVICE_ID_MP1P		0x4301
+#define PCI_DEVICE_ID_MP2S1P		0x4303
+
+#define PCIE_DEVICE_ID_MP1		0x4501
+#define PCIE_DEVICE_ID_MP2		0x4502
+#define PCIE_DEVICE_ID_MP4		0x4504
+#define PCIE_DEVICE_ID_MP8		0x4508
+#define PCIE_DEVICE_ID_MP32		0x4532
+
+#define PCIE_DEVICE_ID_MP1E		0x4e01
+#define PCIE_DEVICE_ID_MP2E		0x4e02
+#define PCIE_DEVICE_ID_MP2B		0x4b02
+#define PCIE_DEVICE_ID_MP4B		0x4b04
+#define PCIE_DEVICE_ID_MP8B		0x4b08
+
+#define PCI_DEVICE_ID_GT_MP4		0x0004
+#define PCI_DEVICE_ID_GT_MP4A		0x0054
+#define PCI_DEVICE_ID_GT_MP6		0x0006
+#define PCI_DEVICE_ID_GT_MP6A		0x0056
+#define PCI_DEVICE_ID_GT_MP8		0x0008
+#define PCI_DEVICE_ID_GT_MP32		0x0032
+
+#define PCIE_DEVICE_ID_GT_MP1		0x1501
+#define PCIE_DEVICE_ID_GT_MP2		0x1502
+#define PCIE_DEVICE_ID_GT_MP4		0x1504
+#define PCIE_DEVICE_ID_GT_MP8		0x1508
+#define PCIE_DEVICE_ID_GT_MP32		0x1532
+
+#define PCI_DEVICE_ID_MP4M		0x4604  //modem
+
+#define MAX_MP_DEV  8
+#define BD_MAX_PORT 32 	/* Max serial port in one board */
+#define MAX_MP_PORT 256 /* Max serial port in one PC */
+
+#define PORT_16C105XA	3
+#define PORT_16C105X	2
+#define PORT_16C55X		1
+
+#define ENABLE		1
+#define DISABLE		0
+
+/* ioctls */
+#define TIOCGNUMOFPORT		0x545F
+#define TIOCSMULTIECHO		0x5440
+#define TIOCSPTPNOECHO		0x5441
+
+#define TIOCGOPTIONREG		0x5461
+#define TIOCGDISABLEIRQ		0x5462
+#define TIOCGENABLEIRQ		0x5463
+#define TIOCGSOFTRESET		0x5464
+#define TIOCGSOFTRESETR		0x5465
+#define TIOCGREGINFO		0x5466
+#define TIOCGGETLSR		0x5467
+#define TIOCGGETDEVID		0x5468
+#define TIOCGGETBDNO		0x5469
+#define TIOCGGETINTERFACE	0x546A
+#define TIOCGGETREV		0x546B
+#define TIOCGGETNRPORTS		0x546C
+#define TIOCGGETPORTTYPE	0x546D
+#define GETDEEPFIFO		0x54AA
+#define SETDEEPFIFO		0x54AB
+#define SETFCR			0x54BA
+#define SETTTR			0x54B1
+#define SETRTR			0x54B2
+#define GETTTR			0x54B3
+#define GETRTR			0x54B4
+
+/* multi-drop mode related ioctl commands */
+#define TIOCSMULTIDROP		0x5470
+#define TIOCSMDADDR   		0x5471
+#define TIOCGMDADDR   		0x5472
+#define TIOCSENDADDR		0x5473
+
+
+/* serial interface */
+#define RS232		1 
+#define RS422PTP	2
+#define RS422MD		3
+#define RS485NE		4
+#define RS485ECHO	5
+
+#define serial_inp(up, offset)      serial_in(up, offset)
+#define serial_outp(up, offset, value)  serial_out(up, offset, value)
+	
+#define PASS_LIMIT  256
+#define is_real_interrupt(irq)  ((irq) != 0)
+
+#define PROBE_ANY   (~0)
+
+static DEFINE_MUTEX(mp_mutex);
+#define MP_MUTEX_LOCK(x) mutex_lock(&(x)) 
+#define MP_MUTEX_UNLOCK(x) mutex_unlock(&(x)) 
+#define MP_STATE_LOCK(x) mutex_lock(&((x)->mutex)) 
+#define MP_STATE_UNLOCK(x) mutex_unlock(&((x)->mutex)) 
+        
+
+#define UART_LSR_SPECIAL    0x1E
+        
+#define HIGH_BITS_OFFSET        ((sizeof(long)-sizeof(int))*8)
+#define uart_users(state)       ((state)->count + ((state)->info ? (state)->info->blocked_open : 0))
+
+
+//#define MP_DEBUG 1
+#undef MP_DEBUG
+
+#ifdef MP_DEBUG
+#define DPRINTK(x...)   printk(x)
+#else
+#define DPRINTK(x...)   do { } while (0)
+#endif
+
+#ifdef MP_DEBUG
+#define DEBUG_AUTOCONF(fmt...)  printk(fmt)
+#else
+#define DEBUG_AUTOCONF(fmt...)  do { } while (0)
+#endif
+
+#ifdef MP_DEBUG
+#define DEBUG_INTR(fmt...)  printk(fmt)
+#else
+#define DEBUG_INTR(fmt...)  do { } while (0)
+#endif
+
+#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
+#define SERIAL_INLINE
+#endif
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#else
+#define _INLINE_
+#endif
+
+#define TYPE_POLL	1
+#define TYPE_INTERRUPT	2
+
+
+struct mp_device_t {
+        unsigned short  device_id;
+        unsigned char   revision;
+        char            *name;
+        unsigned long   uart_access_addr;
+        unsigned long   option_reg_addr;
+        unsigned long   reserved_addr[4];
+        int             irq;
+        int             nr_ports;
+        int             poll_type;
+};
+
+typedef struct mppcibrd {
+        char            *name;
+        unsigned short  vendor_id;
+        unsigned short  device_id;
+} mppcibrd_t;
+
+static mppcibrd_t mp_pciboards[] = {
+
+        { "Multi-1 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP1} ,
+        { "Multi-2 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP2} ,
+        { "Multi-4 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP4} ,
+        { "Multi-4 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP4A} ,
+        { "Multi-6 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP6} ,
+        { "Multi-6 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP6A} ,
+        { "Multi-8 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP8} ,
+        { "Multi-32 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP32} ,
+
+        { "Multi-1P PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP1P} ,
+        { "Multi-2S1P PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP2S1P} ,
+
+        { "Multi-4(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP4} ,
+        { "Multi-4(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP4A} ,
+        { "Multi-6(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP6} ,
+        { "Multi-6(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP6A} ,
+        { "Multi-8(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP8} ,
+        { "Multi-32(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP32} ,
+
+        { "Multi-1 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP1} ,
+        { "Multi-2 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP2} ,
+        { "Multi-4 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP4} ,
+        { "Multi-8 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP8} ,
+        { "Multi-32 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP32} ,
+
+        { "Multi-1 PCIe E", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP1E} ,
+        { "Multi-2 PCIe E", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP2E} ,
+        { "Multi-2 PCIe B", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP2B} ,
+        { "Multi-4 PCIe B", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP4B} ,
+        { "Multi-8 PCIe B", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP8B} ,
+
+        { "Multi-1(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP1} ,
+        { "Multi-2(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP2} ,
+        { "Multi-4(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP4} ,
+        { "Multi-8(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP8} ,
+        { "Multi-32(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP32} ,
+
+        { "Multi-4M PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP4M} ,
+};
+
+struct mp_port {
+        struct sb_uart_port port;
+
+        struct timer_list   timer;      /* "no irq" timer */
+        struct list_head    list;       /* ports on this IRQ */
+        unsigned int        capabilities;   /* port capabilities */
+        unsigned short      rev;
+        unsigned char       acr;
+        unsigned char       ier;
+        unsigned char       lcr;
+        unsigned char       mcr;
+        unsigned char       mcr_mask;   /* mask of user bits */
+        unsigned char       mcr_force;  /* mask of forced bits */
+        unsigned char       lsr_break_flag;
+
+        void            (*pm)(struct sb_uart_port *port,
+                        unsigned int state, unsigned int old);
+        struct mp_device_t *device;
+        unsigned long   interface_config_addr;
+        unsigned long   option_base_addr;
+        unsigned char   interface;
+        unsigned char   poll_type;
+};
+
+struct irq_info {
+        spinlock_t      lock;
+        struct list_head    *head;
+};
+
+struct sb105x_uart_config {
+	char    *name;
+	int     dfl_xmit_fifo_size;
+	int     flags;
+};
+
+static const struct sb105x_uart_config uart_config[] = {
+        { "unknown",    1,  0 },
+        { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
+        { "SB16C1050",    128,    UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+        { "SB16C1050A",    128,    UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+};
+
+
+

+ 368 - 0
drivers/staging/sb105x/sb_ser_core.h

@@ -0,0 +1,368 @@
+#include <linux/wait.h>
+
+#define UART_CONFIG_TYPE	(1 << 0)
+#define UART_CONFIG_IRQ		(1 << 1)
+#define UPIO_PORT		(0)
+#define UPIO_HUB6		(1)
+#define UPIO_MEM		(2)
+#define UPIO_MEM32		(3)
+#define UPIO_AU			(4)			/* Au1x00 type IO */
+#define UPIO_TSI		(5)			/* Tsi108/109 type IO */
+#define UPF_FOURPORT		(1 << 1)
+#define UPF_SAK			(1 << 2)
+#define UPF_SPD_MASK		(0x1030)
+#define UPF_SPD_HI		(0x0010)
+#define UPF_SPD_VHI		(0x0020)
+#define UPF_SPD_CUST		(0x0030)
+#define UPF_SPD_SHI		(0x1000)
+#define UPF_SPD_WARP		(0x1010)
+#define UPF_SKIP_TEST		(1 << 6)
+#define UPF_AUTO_IRQ		(1 << 7)
+#define UPF_HARDPPS_CD		(1 << 11)
+#define UPF_LOW_LATENCY		(1 << 13)
+#define UPF_BUGGY_UART		(1 << 14)
+#define UPF_MAGIC_MULTIPLIER	(1 << 16)
+#define UPF_CONS_FLOW		(1 << 23)
+#define UPF_SHARE_IRQ		(1 << 24)
+#define UPF_BOOT_AUTOCONF	(1 << 28)
+#define UPF_DEAD		(1 << 30)
+#define UPF_IOREMAP		(1 << 31)
+#define UPF_CHANGE_MASK		(0x17fff)
+#define UPF_USR_MASK		(UPF_SPD_MASK|UPF_LOW_LATENCY)
+#define USF_CLOSING_WAIT_INF	(0)
+#define USF_CLOSING_WAIT_NONE	(~0U)
+
+#define UART_XMIT_SIZE	PAGE_SIZE
+
+#define UIF_CHECK_CD		(1 << 25)
+#define UIF_CTS_FLOW		(1 << 26)
+#define UIF_NORMAL_ACTIVE	(1 << 29)
+#define UIF_INITIALIZED		(1 << 31)
+#define UIF_SUSPENDED		(1 << 30)
+
+#define WAKEUP_CHARS		256
+
+#define uart_circ_empty(circ)		((circ)->head == (circ)->tail)
+#define uart_circ_clear(circ)		((circ)->head = (circ)->tail = 0)
+
+#define uart_circ_chars_pending(circ)	\
+	(CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))
+
+#define uart_circ_chars_free(circ)	\
+	(CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
+
+#define uart_tx_stopped(port)		\
+	((port)->info->tty->stopped || (port)->info->tty->hw_stopped)
+
+#define UART_ENABLE_MS(port,cflag)	((port)->flags & UPF_HARDPPS_CD || \
+					 (cflag) & CRTSCTS || \
+					 !((cflag) & CLOCAL))
+
+
+struct sb_uart_port;
+struct sb_uart_info;
+struct serial_struct;
+struct device;
+
+struct sb_uart_ops {
+	unsigned int	(*tx_empty)(struct sb_uart_port *);
+	void		(*set_mctrl)(struct sb_uart_port *, unsigned int mctrl);
+	unsigned int	(*get_mctrl)(struct sb_uart_port *);
+	void		(*stop_tx)(struct sb_uart_port *);
+	void		(*start_tx)(struct sb_uart_port *);
+	void		(*send_xchar)(struct sb_uart_port *, char ch);
+	void		(*stop_rx)(struct sb_uart_port *);
+	void		(*enable_ms)(struct sb_uart_port *);
+	void		(*break_ctl)(struct sb_uart_port *, int ctl);
+	int		(*startup)(struct sb_uart_port *);
+	void		(*shutdown)(struct sb_uart_port *);
+	void		(*set_termios)(struct sb_uart_port *, struct MP_TERMIOS *new,
+				       struct MP_TERMIOS *old);
+	void		(*pm)(struct sb_uart_port *, unsigned int state,
+			      unsigned int oldstate);
+	int		(*set_wake)(struct sb_uart_port *, unsigned int state);
+
+	const char *(*type)(struct sb_uart_port *);
+
+	void		(*release_port)(struct sb_uart_port *);
+
+	int		(*request_port)(struct sb_uart_port *);
+	void		(*config_port)(struct sb_uart_port *, int);
+	int		(*verify_port)(struct sb_uart_port *, struct serial_struct *);
+	int		(*ioctl)(struct sb_uart_port *, unsigned int, unsigned long);
+};
+
+
+struct sb_uart_icount {
+	__u32	cts;
+	__u32	dsr;
+	__u32	rng;
+	__u32	dcd;
+	__u32	rx;
+	__u32	tx;
+	__u32	frame;
+	__u32	overrun;
+	__u32	parity;
+	__u32	brk;
+	__u32	buf_overrun;
+};
+typedef unsigned int  upf_t;
+
+struct sb_uart_port {
+	spinlock_t		lock;			/* port lock */
+	unsigned int		iobase;			/* in/out[bwl] */
+	unsigned char __iomem	*membase;		/* read/write[bwl] */
+	unsigned int		irq;			/* irq number */
+	unsigned int		uartclk;		/* base uart clock */
+	unsigned int		fifosize;		/* tx fifo size */
+	unsigned char		x_char;			/* xon/xoff char */
+	unsigned char		regshift;		/* reg offset shift */
+	unsigned char		iotype;			/* io access style */
+	unsigned char		unused1;
+
+
+	unsigned int		read_status_mask;	/* driver specific */
+	unsigned int		ignore_status_mask;	/* driver specific */
+	struct sb_uart_info	*info;			/* pointer to parent info */
+	struct sb_uart_icount	icount;			/* statistics */
+
+	struct console		*cons;			/* struct console, if any */
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+	unsigned long		sysrq;			/* sysrq timeout */
+#endif
+
+	upf_t			flags;
+
+	unsigned int		mctrl;			/* current modem ctrl settings */
+	unsigned int		timeout;		/* character-based timeout */
+	unsigned int		type;			/* port type */
+	const struct sb_uart_ops	*ops;
+	unsigned int		custom_divisor;
+	unsigned int		line;			/* port index */
+	unsigned long		mapbase;		/* for ioremap */
+	struct device		*dev;			/* parent device */
+	unsigned char		hub6;			/* this should be in the 8250 driver */
+	unsigned char		unused[3];
+};
+
+#define mdmode			unused[2]
+#define MDMODE_ADDR		0x1
+#define MDMODE_ENABLE	0x2
+#define MDMODE_AUTO		0x4
+#define MDMODE_ADDRSEND	0x8
+
+struct sb_uart_state {
+	unsigned int		close_delay;		/* msec */
+	unsigned int		closing_wait;		/* msec */
+
+
+	int			count;
+	int			pm_state;
+	struct sb_uart_info	*info;
+	struct sb_uart_port	*port;
+
+	struct mutex		mutex;
+};
+
+typedef unsigned int  uif_t;
+
+struct sb_uart_info {
+	struct tty_struct	*tty;
+	struct circ_buf		xmit;
+	uif_t			flags;
+
+	int			blocked_open;
+
+	struct tasklet_struct	tlet;
+
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	delta_msr_wait;
+};
+
+
+struct module;
+struct tty_driver;
+
+struct uart_driver {
+	struct module		*owner;
+	const char		*driver_name;
+	const char		*dev_name;
+	int			 major;
+	int			 minor;
+	int			 nr;
+	struct console		*cons;
+
+	struct sb_uart_state	*state;
+        struct tty_driver               *tty_driver;
+};
+
+void sb_uart_write_wakeup(struct sb_uart_port *port)
+{
+    struct sb_uart_info *info = port->info;
+    tasklet_schedule(&info->tlet);
+}
+
+void sb_uart_update_timeout(struct sb_uart_port *port, unsigned int cflag,
+			 unsigned int baud)
+{
+    unsigned int bits;
+
+    switch (cflag & CSIZE)
+    {
+        case CS5:
+            bits = 7;
+            break;
+
+        case CS6:
+            bits = 8;
+            break;
+
+        case CS7:
+            bits = 9;
+            break;
+
+        default:
+            bits = 10;
+            break;
+    }
+
+    if (cflag & CSTOPB)
+    {
+        bits++;
+    }
+
+    if (cflag & PARENB)
+    {
+        bits++;
+    }
+
+    bits = bits * port->fifosize;
+
+    port->timeout = (HZ * bits) / baud + HZ/50;
+}
+unsigned int sb_uart_get_baud_rate(struct sb_uart_port *port, struct MP_TERMIOS *termios,
+				struct MP_TERMIOS *old, unsigned int min,
+				unsigned int max)
+{
+        unsigned int try, baud, altbaud = 38400;
+        upf_t flags = port->flags & UPF_SPD_MASK;
+
+        if (flags == UPF_SPD_HI)
+                altbaud = 57600;
+        if (flags == UPF_SPD_VHI)
+                altbaud = 115200;
+        if (flags == UPF_SPD_SHI)
+                altbaud = 230400;
+        if (flags == UPF_SPD_WARP)
+                altbaud = 460800;
+
+        for (try = 0; try < 2; try++) {
+
+                switch (termios->c_cflag & (CBAUD | CBAUDEX))
+                {
+                	case B921600    : baud = 921600;    break;
+                	case B460800    : baud = 460800;    break;
+                	case B230400    : baud = 230400;    break;
+                	case B115200    : baud = 115200;    break;
+                	case B57600     : baud = 57600;     break;
+                	case B38400     : baud = 38400;     break;
+                	case B19200     : baud = 19200;     break;
+                	case B9600      : baud = 9600;      break;
+                	case B4800      : baud = 4800;      break;
+                	case B2400      : baud = 2400;      break;
+                	case B1800      : baud = 1800;      break;
+                	case B1200      : baud = 1200;      break;
+                	case B600       : baud = 600;       break;
+                	case B300       : baud = 300;       break;
+                        case B200       : baud = 200;       break;
+                	case B150       : baud = 150;       break;
+                	case B134       : baud = 134;       break;
+                	case B110       : baud = 110;       break;
+                	case B75        : baud = 75;        break;
+                	case B50        : baud = 50;        break;
+                	default         : baud = 9600;      break;
+                }
+
+                if (baud == 38400)
+                        baud = altbaud;
+
+                if (baud == 0)
+                        baud = 9600;
+
+                if (baud >= min && baud <= max)
+                        return baud;
+
+                termios->c_cflag &= ~CBAUD;
+                if (old) {
+                        termios->c_cflag |= old->c_cflag & CBAUD;
+                        old = NULL;
+                        continue;
+                }
+
+                termios->c_cflag |= B9600;
+        }
+
+        return 0;
+}
+unsigned int sb_uart_get_divisor(struct sb_uart_port *port, unsigned int baud)
+{
+        unsigned int quot;
+
+        if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+                quot = port->custom_divisor;
+        else
+                quot = (port->uartclk + (8 * baud)) / (16 * baud);
+
+        return quot;
+}
+
+
+
+static inline int sb_uart_handle_break(struct sb_uart_port *port)
+{
+	struct sb_uart_info *info = port->info;
+
+	if (port->flags & UPF_SAK)
+		do_SAK(info->tty);
+	return 0;
+}
+
+static inline void sb_uart_handle_dcd_change(struct sb_uart_port *port, unsigned int status)
+{
+	struct sb_uart_info *info = port->info;
+
+	port->icount.dcd++;
+
+	if (info->flags & UIF_CHECK_CD) {
+		if (status)
+			wake_up_interruptible(&info->open_wait);
+		else if (info->tty)
+			tty_hangup(info->tty);
+	}
+}
+
+static inline void sb_uart_handle_cts_change(struct sb_uart_port *port, unsigned int status)
+{
+	struct sb_uart_info *info = port->info;
+	struct tty_struct *tty = info->tty;
+
+	port->icount.cts++;
+
+	if (info->flags & UIF_CTS_FLOW) {
+		if (tty->hw_stopped) {
+			if (status) {
+				tty->hw_stopped = 0;
+				port->ops->start_tx(port);
+				sb_uart_write_wakeup(port);
+			}
+		} else {
+			if (!status) {
+				tty->hw_stopped = 1;
+				port->ops->stop_tx(port);
+			}
+		}
+	}
+}
+
+
+

+ 2 - 0
drivers/tty/amiserial.c

@@ -1771,6 +1771,7 @@ fail_free_irq:
 fail_unregister:
 	tty_unregister_driver(serial_driver);
 fail_put_tty_driver:
+	tty_port_destroy(&state->tport);
 	put_tty_driver(serial_driver);
 	return error;
 }
@@ -1785,6 +1786,7 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)
 		printk("SERIAL: failed to unregister serial driver (%d)\n",
 		       error);
 	put_tty_driver(serial_driver);
+	tty_port_destroy(&state->tport);
 
 	free_irq(IRQ_AMIGA_TBE, state);
 	free_irq(IRQ_AMIGA_RBF, state);

+ 4 - 2
drivers/tty/bfin_jtag_comm.c

@@ -240,8 +240,6 @@ static int __init bfin_jc_init(void)
 {
 	int ret;
 
-	tty_port_init(&port);
-
 	bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
 	if (IS_ERR(bfin_jc_kthread))
 		return PTR_ERR(bfin_jc_kthread);
@@ -257,6 +255,8 @@ static int __init bfin_jc_init(void)
 	if (!bfin_jc_driver)
 		goto err_driver;
 
+	tty_port_init(&port);
+
 	bfin_jc_driver->driver_name  = DRV_NAME;
 	bfin_jc_driver->name         = DEV_NAME;
 	bfin_jc_driver->type         = TTY_DRIVER_TYPE_SERIAL;
@@ -274,6 +274,7 @@ static int __init bfin_jc_init(void)
 	return 0;
 
  err:
+	tty_port_destroy(&port);
 	put_tty_driver(bfin_jc_driver);
  err_driver:
 	kfree(bfin_jc_write_buf.buf);
@@ -289,6 +290,7 @@ static void __exit bfin_jc_exit(void)
 	kfree(bfin_jc_write_buf.buf);
 	tty_unregister_driver(bfin_jc_driver);
 	put_tty_driver(bfin_jc_driver);
+	tty_port_destroy(&port);
 }
 module_exit(bfin_jc_exit);
 

+ 15 - 13
drivers/tty/cyclades.c

@@ -3099,7 +3099,7 @@ static const struct tty_port_operations cyz_port_ops = {
  * ---------------------------------------------------------------------
  */
 
-static int __devinit cy_init_card(struct cyclades_card *cinfo)
+static int cy_init_card(struct cyclades_card *cinfo)
 {
 	struct cyclades_port *info;
 	unsigned int channel, port;
@@ -3196,7 +3196,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
 
 /* initialize chips on Cyclom-Y card -- return number of valid
    chips (which is number of ports/4) */
-static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
+static unsigned short cyy_init_card(void __iomem *true_base_addr,
 		int index)
 {
 	unsigned int chip_number;
@@ -3405,7 +3405,7 @@ static int __init cy_detect_isa(void)
 }				/* cy_detect_isa */
 
 #ifdef CONFIG_PCI
-static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
+static inline int cyc_isfwstr(const char *str, unsigned int size)
 {
 	unsigned int a;
 
@@ -3420,7 +3420,7 @@ static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
 	return 0;
 }
 
-static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
+static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data,
 		unsigned int size)
 {
 	for (; size > 0; size--) {
@@ -3429,7 +3429,7 @@ static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
 	}
 }
 
-static void __devinit plx_init(struct pci_dev *pdev, int irq,
+static void plx_init(struct pci_dev *pdev, int irq,
 		struct RUNTIME_9060 __iomem *addr)
 {
 	/* Reset PLX */
@@ -3449,7 +3449,7 @@ static void __devinit plx_init(struct pci_dev *pdev, int irq,
 	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
 }
 
-static int __devinit __cyz_load_fw(const struct firmware *fw,
+static int __cyz_load_fw(const struct firmware *fw,
 		const char *name, const u32 mailbox, void __iomem *base,
 		void __iomem *fpga)
 {
@@ -3526,7 +3526,7 @@ static int __devinit __cyz_load_fw(const struct firmware *fw,
 	return 0;
 }
 
-static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
+static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
 		struct RUNTIME_9060 __iomem *ctl_addr, int irq)
 {
 	const struct firmware *fw;
@@ -3692,7 +3692,7 @@ err:
 	return retval;
 }
 
-static int __devinit cy_pci_probe(struct pci_dev *pdev,
+static int cy_pci_probe(struct pci_dev *pdev,
 		const struct pci_device_id *ent)
 {
 	struct cyclades_card *card;
@@ -3931,10 +3931,10 @@ err:
 	return retval;
 }
 
-static void __devexit cy_pci_remove(struct pci_dev *pdev)
+static void cy_pci_remove(struct pci_dev *pdev)
 {
 	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
-	unsigned int i;
+	unsigned int i, channel;
 
 	/* non-Z with old PLX */
 	if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
@@ -3960,9 +3960,11 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
 	pci_release_regions(pdev);
 
 	cinfo->base_addr = NULL;
-	for (i = cinfo->first_line; i < cinfo->first_line +
-			cinfo->nports; i++)
+	for (channel = 0, i = cinfo->first_line; i < cinfo->first_line +
+			cinfo->nports; i++, channel++) {
 		tty_unregister_device(cy_serial_driver, i);
+		tty_port_destroy(&cinfo->ports[channel].port);
+	}
 	cinfo->nports = 0;
 	kfree(cinfo->ports);
 }
@@ -3971,7 +3973,7 @@ static struct pci_driver cy_pci_driver = {
 	.name = "cyclades",
 	.id_table = cy_pci_dev_id,
 	.probe = cy_pci_probe,
-	.remove = __devexit_p(cy_pci_remove)
+	.remove = cy_pci_remove
 };
 #endif
 

+ 3 - 1
drivers/tty/ehv_bytechan.c

@@ -699,7 +699,7 @@ static const struct tty_port_operations ehv_bc_tty_port_ops = {
 	.shutdown = ehv_bc_tty_port_shutdown,
 };
 
-static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
+static int ehv_bc_tty_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct ehv_bc_data *bc;
@@ -757,6 +757,7 @@ static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
 	return 0;
 
 error:
+	tty_port_destroy(&bc->port);
 	irq_dispose_mapping(bc->tx_irq);
 	irq_dispose_mapping(bc->rx_irq);
 
@@ -770,6 +771,7 @@ static int ehv_bc_tty_remove(struct platform_device *pdev)
 
 	tty_unregister_device(ehv_bc_driver, bc - bcs);
 
+	tty_port_destroy(&bc->port);
 	irq_dispose_mapping(bc->tx_irq);
 	irq_dispose_mapping(bc->rx_irq);
 

+ 4 - 4
drivers/tty/hvc/hvc_opal.c

@@ -41,7 +41,7 @@
 
 static const char hvc_opal_name[] = "hvc_opal";
 
-static struct of_device_id hvc_opal_match[] __devinitdata = {
+static struct of_device_id hvc_opal_match[] = {
 	{ .name = "serial", .compatible = "ibm,opal-console-raw" },
 	{ .name = "serial", .compatible = "ibm,opal-console-hvsi" },
 	{ },
@@ -161,7 +161,7 @@ static const struct hv_ops hvc_opal_hvsi_ops = {
 	.tiocmset = hvc_opal_hvsi_tiocmset,
 };
 
-static int __devinit hvc_opal_probe(struct platform_device *dev)
+static int hvc_opal_probe(struct platform_device *dev)
 {
 	const struct hv_ops *ops;
 	struct hvc_struct *hp;
@@ -222,7 +222,7 @@ static int __devinit hvc_opal_probe(struct platform_device *dev)
 	return 0;
 }
 
-static int __devexit hvc_opal_remove(struct platform_device *dev)
+static int hvc_opal_remove(struct platform_device *dev)
 {
 	struct hvc_struct *hp = dev_get_drvdata(&dev->dev);
 	int rc, termno;
@@ -239,7 +239,7 @@ static int __devexit hvc_opal_remove(struct platform_device *dev)
 
 static struct platform_driver hvc_opal_driver = {
 	.probe		= hvc_opal_probe,
-	.remove		= __devexit_p(hvc_opal_remove),
+	.remove		= hvc_opal_remove,
 	.driver		= {
 		.name	= hvc_opal_name,
 		.owner	= THIS_MODULE,

+ 3 - 3
drivers/tty/hvc/hvc_vio.c

@@ -53,7 +53,7 @@
 
 static const char hvc_driver_name[] = "hvc_console";
 
-static struct vio_device_id hvc_driver_table[] __devinitdata = {
+static struct vio_device_id hvc_driver_table[] = {
 	{"serial", "hvterm1"},
 #ifndef HVC_OLD_HVSI
 	{"serial", "hvterm-protocol"},
@@ -293,7 +293,7 @@ static int udbg_hvc_getc(void)
 	}
 }
 
-static int __devinit hvc_vio_probe(struct vio_dev *vdev,
+static int hvc_vio_probe(struct vio_dev *vdev,
 				   const struct vio_device_id *id)
 {
 	const struct hv_ops *ops;
@@ -362,7 +362,7 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev,
 	return 0;
 }
 
-static int __devexit hvc_vio_remove(struct vio_dev *vdev)
+static int hvc_vio_remove(struct vio_dev *vdev)
 {
 	struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
 	int rc, termno;

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

@@ -422,7 +422,7 @@ static int xencons_connect_backend(struct xenbus_device *dev,
 	return ret;
 }
 
-static int __devinit xencons_probe(struct xenbus_device *dev,
+static int xencons_probe(struct xenbus_device *dev,
 				  const struct xenbus_device_id *id)
 {
 	int ret, devid;

+ 11 - 9
drivers/tty/hvc/hvcs.c

@@ -330,12 +330,12 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp);
 static void hvcs_close(struct tty_struct *tty, struct file *filp);
 static void hvcs_hangup(struct tty_struct * tty);
 
-static int __devinit hvcs_probe(struct vio_dev *dev,
+static int hvcs_probe(struct vio_dev *dev,
 		const struct vio_device_id *id);
-static int __devexit hvcs_remove(struct vio_dev *dev);
+static int hvcs_remove(struct vio_dev *dev);
 static int __init hvcs_module_init(void);
 static void __exit hvcs_module_exit(void);
-static int __devinit hvcs_initialize(void);
+static int hvcs_initialize(void);
 
 #define HVCS_SCHED_READ	0x00000001
 #define HVCS_QUICK_READ	0x00000002
@@ -676,7 +676,7 @@ static int khvcsd(void *unused)
 	return 0;
 }
 
-static struct vio_device_id hvcs_driver_table[] __devinitdata= {
+static struct vio_device_id hvcs_driver_table[] = {
 	{"serial-server", "hvterm2"},
 	{ "", "" }
 };
@@ -756,7 +756,7 @@ static int hvcs_get_index(void)
 	return -1;
 }
 
-static int __devinit hvcs_probe(
+static int hvcs_probe(
 	struct vio_dev *dev,
 	const struct vio_device_id *id)
 {
@@ -835,7 +835,7 @@ static int __devinit hvcs_probe(
 	return 0;
 }
 
-static int __devexit hvcs_remove(struct vio_dev *dev)
+static int hvcs_remove(struct vio_dev *dev)
 {
 	struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
 	unsigned long flags;
@@ -874,7 +874,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
 static struct vio_driver hvcs_vio_driver = {
 	.id_table	= hvcs_driver_table,
 	.probe		= hvcs_probe,
-	.remove		= __devexit_p(hvcs_remove),
+	.remove		= hvcs_remove,
 	.name		= hvcs_driver_name,
 };
 
@@ -1478,7 +1478,7 @@ static void hvcs_free_index_list(void)
 	hvcs_index_count = 0;
 }
 
-static int __devinit hvcs_initialize(void)
+static int hvcs_initialize(void)
 {
 	int rc, num_ttys_to_alloc;
 
@@ -1496,8 +1496,10 @@ static int __devinit hvcs_initialize(void)
 		num_ttys_to_alloc = hvcs_parm_num_devs;
 
 	hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc);
-	if (!hvcs_tty_driver)
+	if (!hvcs_tty_driver) {
+		mutex_unlock(&hvcs_init_mutex);
 		return -ENOMEM;
+	}
 
 	if (hvcs_alloc_index_list(num_ttys_to_alloc)) {
 		rc = -ENOMEM;

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

@@ -1218,6 +1218,7 @@ static int __init hvsi_console_init(void)
 		if (hp->virq == 0) {
 			printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
 				__func__, irq[0]);
+			tty_port_destroy(&hp->port);
 			continue;
 		}
 

+ 4 - 1
drivers/tty/ipwireless/network.c

@@ -352,6 +352,8 @@ static struct sk_buff *ipw_packet_received_skb(unsigned char *data,
 	}
 
 	skb = dev_alloc_skb(length + 4);
+	if (skb == NULL)
+		return NULL;
 	skb_reserve(skb, 2);
 	memcpy(skb_put(skb, length), data, length);
 
@@ -397,7 +399,8 @@ void ipwireless_network_packet_received(struct ipw_network *network,
 
 				/* Send the data to the ppp_generic module. */
 				skb = ipw_packet_received_skb(data, length);
-				ppp_input(network->ppp_channel, skb);
+				if (skb)
+					ppp_input(network->ppp_channel, skb);
 			} else
 				spin_unlock_irqrestore(&network->lock,
 						flags);

+ 1 - 0
drivers/tty/ipwireless/tty.c

@@ -566,6 +566,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)
 			ipwireless_disassociate_network_ttys(network,
 							     ttyj->channel_idx);
 			tty_unregister_device(ipw_tty_driver, j);
+			tty_port_destroy(&ttyj->port);
 			ttys[j] = NULL;
 			mutex_unlock(&ttyj->ipw_tty_mutex);
 			kfree(ttyj);

+ 19 - 16
drivers/tty/isicom.c

@@ -148,7 +148,7 @@
 #endif
 
 static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
-static void __devexit isicom_remove(struct pci_dev *);
+static void isicom_remove(struct pci_dev *);
 
 static struct pci_device_id isicom_pci_tbl[] = {
 	{ PCI_DEVICE(VENDOR_ID, 0x2028) },
@@ -168,7 +168,7 @@ static struct pci_driver isicom_driver = {
 	.name		= "isicom",
 	.id_table	= isicom_pci_tbl,
 	.probe		= isicom_probe,
-	.remove		= __devexit_p(isicom_remove)
+	.remove		= isicom_remove
 };
 
 static int prev_card = 3;	/*	start servicing isi_card[0]	*/
@@ -603,7 +603,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 			if (tty_port_cts_enabled(&port->port)) {
 				if (tty->hw_stopped) {
 					if (header & ISI_CTS) {
-						port->port.tty->hw_stopped = 0;
+						tty->hw_stopped = 0;
 						/* start tx ing */
 						port->status |= (ISI_TXOK
 							| ISI_CTS);
@@ -1307,7 +1307,7 @@ static const struct tty_port_operations isicom_port_ops = {
 	.shutdown		= isicom_shutdown,
 };
 
-static int __devinit reset_card(struct pci_dev *pdev,
+static int reset_card(struct pci_dev *pdev,
 	const unsigned int card, unsigned int *signature)
 {
 	struct isi_board *board = pci_get_drvdata(pdev);
@@ -1368,7 +1368,7 @@ end:
 	return retval;
 }
 
-static int __devinit load_firmware(struct pci_dev *pdev,
+static int load_firmware(struct pci_dev *pdev,
 	const unsigned int index, const unsigned int signature)
 {
 	struct isi_board *board = pci_get_drvdata(pdev);
@@ -1548,7 +1548,7 @@ end:
  */
 static unsigned int card_count;
 
-static int __devinit isicom_probe(struct pci_dev *pdev,
+static int isicom_probe(struct pci_dev *pdev,
 	const struct pci_device_id *ent)
 {
 	unsigned int uninitialized_var(signature), index;
@@ -1610,10 +1610,15 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
 	if (retval < 0)
 		goto errunri;
 
-	for (index = 0; index < board->port_count; index++)
-		tty_port_register_device(&board->ports[index].port,
-				isicom_normal, board->index * 16 + index,
-				&pdev->dev);
+	for (index = 0; index < board->port_count; index++) {
+		struct tty_port *tport = &board->ports[index].port;
+		tty_port_init(tport);
+		tport->ops = &isicom_port_ops;
+		tport->close_delay = 50 * HZ/100;
+		tport->closing_wait = 3000 * HZ/100;
+		tty_port_register_device(tport, isicom_normal,
+				board->index * 16 + index, &pdev->dev);
+	}
 
 	return 0;
 
@@ -1630,13 +1635,15 @@ err:
 	return retval;
 }
 
-static void __devexit isicom_remove(struct pci_dev *pdev)
+static void isicom_remove(struct pci_dev *pdev)
 {
 	struct isi_board *board = pci_get_drvdata(pdev);
 	unsigned int i;
 
-	for (i = 0; i < board->port_count; i++)
+	for (i = 0; i < board->port_count; i++) {
 		tty_unregister_device(isicom_normal, board->index * 16 + i);
+		tty_port_destroy(&board->ports[i].port);
+	}
 
 	free_irq(board->irq, board);
 	pci_release_region(pdev, 3);
@@ -1655,13 +1662,9 @@ static int __init isicom_init(void)
 		isi_card[idx].ports = port;
 		spin_lock_init(&isi_card[idx].card_lock);
 		for (channel = 0; channel < 16; channel++, port++) {
-			tty_port_init(&port->port);
-			port->port.ops = &isicom_port_ops;
 			port->magic = ISICOM_MAGIC;
 			port->card = &isi_card[idx];
 			port->channel = channel;
-			port->port.close_delay = 50 * HZ/100;
-			port->port.closing_wait = 3000 * HZ/100;
 			port->status = 0;
 			/*  . . .  */
 		}

+ 8 - 4
drivers/tty/moxa.c

@@ -895,6 +895,8 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
 
 	return 0;
 err_free:
+	for (i = 0; i < MAX_PORTS_PER_BOARD; i++)
+		tty_port_destroy(&brd->ports[i].port);
 	kfree(brd->ports);
 err:
 	return ret;
@@ -919,6 +921,8 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
 				tty_kref_put(tty);
 			}
 		}
+	for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
+		tty_port_destroy(&brd->ports[a].port);
 	while (1) {
 		opened = 0;
 		for (a = 0; a < brd->numPorts; a++)
@@ -941,7 +945,7 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
 }
 
 #ifdef CONFIG_PCI
-static int __devinit moxa_pci_probe(struct pci_dev *pdev,
+static int moxa_pci_probe(struct pci_dev *pdev,
 		const struct pci_device_id *ent)
 {
 	struct moxa_board_conf *board;
@@ -1016,7 +1020,7 @@ err:
 	return retval;
 }
 
-static void __devexit moxa_pci_remove(struct pci_dev *pdev)
+static void moxa_pci_remove(struct pci_dev *pdev)
 {
 	struct moxa_board_conf *brd = pci_get_drvdata(pdev);
 
@@ -1029,7 +1033,7 @@ static struct pci_driver moxa_pci_driver = {
 	.name = "moxa",
 	.id_table = moxa_pcibrds,
 	.probe = moxa_pci_probe,
-	.remove = __devexit_p(moxa_pci_remove)
+	.remove = moxa_pci_remove
 };
 #endif /* CONFIG_PCI */
 
@@ -1370,7 +1374,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
         	p->DCDState = dcd;
         	spin_unlock_irqrestore(&p->port.lock, flags);
 		tty = tty_port_tty_get(&p->port);
-		if (tty && C_CLOCAL(tty) && !dcd)
+		if (tty && !C_CLOCAL(tty) && !dcd)
 			tty_hangup(tty);
 		tty_kref_put(tty);
 	}

+ 22 - 13
drivers/tty/mxser.c

@@ -487,7 +487,7 @@ static void mxser_disable_must_rx_software_flow_control(unsigned long baseio)
 }
 
 #ifdef CONFIG_PCI
-static int __devinit CheckIsMoxaMust(unsigned long io)
+static int CheckIsMoxaMust(unsigned long io)
 {
 	u8 oldmcr, hwid;
 	int i;
@@ -2369,7 +2369,7 @@ static void mxser_release_ISA_res(struct mxser_board *brd)
 	mxser_release_vector(brd);
 }
 
-static int __devinit mxser_initbrd(struct mxser_board *brd,
+static int mxser_initbrd(struct mxser_board *brd,
 		struct pci_dev *pdev)
 {
 	struct mxser_port *info;
@@ -2411,14 +2411,27 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
 
 	retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
 			brd);
-	if (retval)
+	if (retval) {
+		for (i = 0; i < brd->info->nports; i++)
+			tty_port_destroy(&brd->ports[i].port);
 		printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
 			"conflict with another device.\n",
 			brd->info->name, brd->irq);
+	}
 
 	return retval;
 }
 
+static void mxser_board_remove(struct mxser_board *brd)
+{
+	unsigned int i;
+
+	for (i = 0; i < brd->info->nports; i++) {
+		tty_unregister_device(mxvar_sdriver, brd->idx + i);
+		tty_port_destroy(&brd->ports[i].port);
+	}
+}
+
 static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
 {
 	int id, i, bits, ret;
@@ -2534,7 +2547,7 @@ err_irqconflict:
 	return -EIO;
 }
 
-static int __devinit mxser_probe(struct pci_dev *pdev,
+static int mxser_probe(struct pci_dev *pdev,
 		const struct pci_device_id *ent)
 {
 #ifdef CONFIG_PCI
@@ -2645,14 +2658,12 @@ err:
 #endif
 }
 
-static void __devexit mxser_remove(struct pci_dev *pdev)
+static void mxser_remove(struct pci_dev *pdev)
 {
 #ifdef CONFIG_PCI
 	struct mxser_board *brd = pci_get_drvdata(pdev);
-	unsigned int i;
 
-	for (i = 0; i < brd->info->nports; i++)
-		tty_unregister_device(mxvar_sdriver, brd->idx + i);
+	mxser_board_remove(brd);
 
 	free_irq(pdev->irq, brd);
 	pci_release_region(pdev, 2);
@@ -2666,7 +2677,7 @@ static struct pci_driver mxser_driver = {
 	.name = "mxser",
 	.id_table = mxser_pcibrds,
 	.probe = mxser_probe,
-	.remove = __devexit_p(mxser_remove)
+	.remove = mxser_remove
 };
 
 static int __init mxser_module_init(void)
@@ -2748,15 +2759,13 @@ err_put:
 
 static void __exit mxser_module_exit(void)
 {
-	unsigned int i, j;
+	unsigned int i;
 
 	pci_unregister_driver(&mxser_driver);
 
 	for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
 		if (mxser_boards[i].info != NULL)
-			for (j = 0; j < mxser_boards[i].info->nports; j++)
-				tty_unregister_device(mxvar_sdriver,
-						mxser_boards[i].idx + j);
+			mxser_board_remove(&mxser_boards[i]);
 	tty_unregister_driver(mxvar_sdriver);
 	put_tty_driver(mxvar_sdriver);
 

+ 5 - 6
drivers/tty/n_gsm.c

@@ -134,7 +134,6 @@ struct gsm_dlci {
 #define DLCI_OPENING		1	/* Sending SABM not seen UA */
 #define DLCI_OPEN		2	/* SABM/UA complete */
 #define DLCI_CLOSING		3	/* Sending DISC not seen UA/DM */
-	struct kref ref;		/* freed from port or mux close */
 	struct mutex mutex;
 
 	/* Link layer */
@@ -1635,7 +1634,6 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
 	if (dlci == NULL)
 		return NULL;
 	spin_lock_init(&dlci->lock);
-	kref_init(&dlci->ref);
 	mutex_init(&dlci->mutex);
 	dlci->fifo = &dlci->_fifo;
 	if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
@@ -1669,9 +1667,9 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
  *
  *	Can sleep.
  */
-static void gsm_dlci_free(struct kref *ref)
+static void gsm_dlci_free(struct tty_port *port)
 {
-	struct gsm_dlci *dlci = container_of(ref, struct gsm_dlci, ref);
+	struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
 
 	del_timer_sync(&dlci->t1);
 	dlci->gsm->dlci[dlci->addr] = NULL;
@@ -1683,12 +1681,12 @@ static void gsm_dlci_free(struct kref *ref)
 
 static inline void dlci_get(struct gsm_dlci *dlci)
 {
-	kref_get(&dlci->ref);
+	tty_port_get(&dlci->port);
 }
 
 static inline void dlci_put(struct gsm_dlci *dlci)
 {
-	kref_put(&dlci->ref, gsm_dlci_free);
+	tty_port_put(&dlci->port);
 }
 
 /**
@@ -2874,6 +2872,7 @@ static void gsm_dtr_rts(struct tty_port *port, int onoff)
 static const struct tty_port_operations gsm_port_ops = {
 	.carrier_raised = gsm_carrier_raised,
 	.dtr_rts = gsm_dtr_rts,
+	.destruct = gsm_dlci_free,
 };
 
 static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)

File diff suppressed because it is too large
+ 261 - 215
drivers/tty/n_tty.c


+ 14 - 9
drivers/tty/nozomi.c

@@ -400,7 +400,7 @@ struct buffer {
 } __attribute__ ((packed));
 
 /*    Global variables */
-static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = {
+static const struct pci_device_id nozomi_pci_tbl[] = {
 	{PCI_DEVICE(0x1931, 0x000c)},	/* Nozomi HSDPA */
 	{},
 };
@@ -1360,7 +1360,7 @@ static void remove_sysfs_files(struct nozomi *dc)
 }
 
 /* Allocate memory for one device */
-static int __devinit nozomi_card_init(struct pci_dev *pdev,
+static int nozomi_card_init(struct pci_dev *pdev,
 				      const struct pci_device_id *ent)
 {
 	resource_size_t start;
@@ -1479,6 +1479,7 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
 		if (IS_ERR(tty_dev)) {
 			ret = PTR_ERR(tty_dev);
 			dev_err(&pdev->dev, "Could not allocate tty?\n");
+			tty_port_destroy(&port->port);
 			goto err_free_tty;
 		}
 	}
@@ -1486,8 +1487,10 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
 	return 0;
 
 err_free_tty:
-	for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
-		tty_unregister_device(ntty_driver, i);
+	for (i = 0; i < MAX_PORT; ++i) {
+		tty_unregister_device(ntty_driver, dc->index_start + i);
+		tty_port_destroy(&dc->port[i].port);
+	}
 err_free_kfifo:
 	for (i = 0; i < MAX_PORT; i++)
 		kfifo_free(&dc->port[i].fifo_ul);
@@ -1504,7 +1507,7 @@ err:
 	return ret;
 }
 
-static void __devexit tty_exit(struct nozomi *dc)
+static void tty_exit(struct nozomi *dc)
 {
 	unsigned int i;
 
@@ -1520,12 +1523,14 @@ static void __devexit tty_exit(struct nozomi *dc)
 	   complete off a hangup method ? */
 	while (dc->open_ttys)
 		msleep(1);
-	for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
-		tty_unregister_device(ntty_driver, i);
+	for (i = 0; i < MAX_PORT; ++i) {
+		tty_unregister_device(ntty_driver, dc->index_start + i);
+		tty_port_destroy(&dc->port[i].port);
+	}
 }
 
 /* Deallocate memory for one device */
-static void __devexit nozomi_card_exit(struct pci_dev *pdev)
+static void nozomi_card_exit(struct pci_dev *pdev)
 {
 	int i;
 	struct ctrl_ul ctrl;
@@ -1903,7 +1908,7 @@ static struct pci_driver nozomi_driver = {
 	.name = NOZOMI_NAME,
 	.id_table = nozomi_pci_tbl,
 	.probe = nozomi_card_init,
-	.remove = __devexit_p(nozomi_card_exit),
+	.remove = nozomi_card_exit,
 };
 
 static __init int nozomi_init(void)

+ 71 - 10
drivers/tty/pty.c

@@ -4,9 +4,6 @@
  *  Added support for a Unix98-style ptmx device.
  *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
  *
- *  When reading this code see also fs/devpts. In particular note that the
- *  driver_data field is used by the devpts side as a binding to the devpts
- *  inode.
  */
 
 #include <linux/module.h>
@@ -59,7 +56,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
 #ifdef CONFIG_UNIX98_PTYS
 		if (tty->driver == ptm_driver) {
 		        mutex_lock(&devpts_mutex);
-			devpts_pty_kill(tty->link);
+			devpts_pty_kill(tty->link->driver_data);
 		        mutex_unlock(&devpts_mutex);
 		}
 #endif
@@ -96,7 +93,7 @@ static void pty_unthrottle(struct tty_struct *tty)
 
 static int pty_space(struct tty_struct *to)
 {
-	int n = 8192 - to->buf.memory_used;
+	int n = 8192 - to->port->buf.memory_used;
 	if (n < 0)
 		return 0;
 	return n;
@@ -174,6 +171,41 @@ static int pty_set_lock(struct tty_struct *tty, int __user *arg)
 	return 0;
 }
 
+static int pty_get_lock(struct tty_struct *tty, int __user *arg)
+{
+	int locked = test_bit(TTY_PTY_LOCK, &tty->flags);
+	return put_user(locked, arg);
+}
+
+/* Set the packet mode on a pty */
+static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
+{
+	unsigned long flags;
+	int pktmode;
+
+	if (get_user(pktmode, arg))
+		return -EFAULT;
+
+	spin_lock_irqsave(&tty->ctrl_lock, flags);
+	if (pktmode) {
+		if (!tty->packet) {
+			tty->packet = 1;
+			tty->link->ctrl_status = 0;
+		}
+	} else
+		tty->packet = 0;
+	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+	return 0;
+}
+
+/* Get the packet mode of a pty */
+static int pty_get_pktmode(struct tty_struct *tty, int __user *arg)
+{
+	int pktmode = tty->packet;
+	return put_user(pktmode, arg);
+}
+
 /* Send a signal to the slave */
 static int pty_signal(struct tty_struct *tty, int sig)
 {
@@ -245,7 +277,7 @@ static void pty_set_termios(struct tty_struct *tty,
  *	peform a terminal resize correctly
  */
 
-int pty_resize(struct tty_struct *tty,  struct winsize *ws)
+static int pty_resize(struct tty_struct *tty,  struct winsize *ws)
 {
 	struct pid *pgrp, *rpgrp;
 	unsigned long flags;
@@ -348,6 +380,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
 	tty_port_init(ports[1]);
 	o_tty->port = ports[0];
 	tty->port = ports[1];
+	o_tty->port->itty = o_tty;
 
 	tty_driver_kref_get(driver);
 	tty->count++;
@@ -366,9 +399,16 @@ err:
 	return retval;
 }
 
+/* this is called once with whichever end is closed last */
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+	devpts_kill_index(tty->driver_data, tty->index);
+}
+
 static void pty_cleanup(struct tty_struct *tty)
 {
-	kfree(tty->port);
+	tty->port->itty = NULL;
+	tty_port_put(tty->port);
 }
 
 /* Traditional BSD devices */
@@ -393,6 +433,12 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
 	switch (cmd) {
 	case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
 		return pty_set_lock(tty, (int __user *) arg);
+	case TIOCGPTLCK: /* Get PT Lock status */
+		return pty_get_lock(tty, (int __user *)arg);
+	case TIOCPKT: /* Set PT packet mode */
+		return pty_set_pktmode(tty, (int __user *)arg);
+	case TIOCGPKT: /* Get PT packet mode */
+		return pty_get_pktmode(tty, (int __user *)arg);
 	case TIOCSIG:    /* Send signal to other side of pty */
 		return pty_signal(tty, (int) arg);
 	}
@@ -507,6 +553,12 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
 	switch (cmd) {
 	case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
 		return pty_set_lock(tty, (int __user *)arg);
+	case TIOCGPTLCK: /* Get PT Lock status */
+		return pty_get_lock(tty, (int __user *)arg);
+	case TIOCPKT: /* Set PT packet mode */
+		return pty_set_pktmode(tty, (int __user *)arg);
+	case TIOCGPKT: /* Get PT packet mode */
+		return pty_get_pktmode(tty, (int __user *)arg);
 	case TIOCGPTN: /* Get PT Number */
 		return put_user(tty->index, (unsigned int __user *)arg);
 	case TIOCSIG:    /* Send signal to other side of pty */
@@ -547,7 +599,7 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
 	struct tty_struct *tty;
 
 	mutex_lock(&devpts_mutex);
-	tty = devpts_get_tty(pts_inode, idx);
+	tty = devpts_get_priv(pts_inode);
 	mutex_unlock(&devpts_mutex);
 	/* Master must be open before slave */
 	if (!tty)
@@ -581,6 +633,7 @@ static const struct tty_operations ptm_unix98_ops = {
 	.set_termios = pty_set_termios,
 	.ioctl = pty_unix98_ioctl,
 	.resize = pty_resize,
+	.shutdown = pty_unix98_shutdown,
 	.cleanup = pty_cleanup
 };
 
@@ -596,6 +649,7 @@ static const struct tty_operations pty_unix98_ops = {
 	.chars_in_buffer = pty_chars_in_buffer,
 	.unthrottle = pty_unthrottle,
 	.set_termios = pty_set_termios,
+	.shutdown = pty_unix98_shutdown,
 	.cleanup = pty_cleanup,
 };
 
@@ -614,6 +668,7 @@ static const struct tty_operations pty_unix98_ops = {
 static int ptmx_open(struct inode *inode, struct file *filp)
 {
 	struct tty_struct *tty;
+	struct inode *slave_inode;
 	int retval;
 	int index;
 
@@ -650,15 +705,21 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 
 	tty_add_file(tty, filp);
 
-	retval = devpts_pty_new(inode, tty->link);
-	if (retval)
+	slave_inode = devpts_pty_new(inode,
+			MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
+			tty->link);
+	if (IS_ERR(slave_inode)) {
+		retval = PTR_ERR(slave_inode);
 		goto err_release;
+	}
 
 	retval = ptm_driver->ops->open(tty, filp);
 	if (retval)
 		goto err_release;
 
 	tty_unlock(tty);
+	tty->driver_data = inode;
+	tty->link->driver_data = slave_inode;
 	return 0;
 err_release:
 	tty_unlock(tty);

+ 3 - 1
drivers/tty/rocket.c

@@ -673,6 +673,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
 	if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
 		printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
 				board, aiop, chan);
+		tty_port_destroy(&info->port);
 		kfree(info);
 		return;
 	}
@@ -1757,7 +1758,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
 
 #ifdef CONFIG_PCI
 
-static struct pci_device_id __devinitdata __used rocket_pci_ids[] = {
+static struct pci_device_id __used rocket_pci_ids[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
 	{ }
 };
@@ -2357,6 +2358,7 @@ static void rp_cleanup_module(void)
 	for (i = 0; i < MAX_RP_PORTS; i++)
 		if (rp_table[i]) {
 			tty_unregister_device(rocket_driver, i);
+			tty_port_destroy(&rp_table[i]->port);
 			kfree(rp_table[i]);
 		}
 

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

@@ -1225,6 +1225,8 @@ rs68328_init(void)
 
 	if (tty_register_driver(serial_driver)) {
 		put_tty_driver(serial_driver);
+		for (i = 0; i < NR_PORTS; i++)
+			tty_port_destroy(&m68k_soft[i].tport);
 		printk(KERN_ERR "Couldn't register serial driver\n");
 		return -ENOMEM;
 	}

+ 87 - 11
drivers/tty/serial/8250/8250.c

@@ -280,7 +280,17 @@ static const struct serial8250_config uart_config[] = {
 		.fifo_size	= 64,
 		.tx_loadsz	= 64,
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-		.flags		= UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
+		.flags		= UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR |
+				  UART_CAP_SLEEP,
+	},
+	[PORT_XR17V35X] = {
+		.name		= "XR17V35X",
+		.fifo_size	= 256,
+		.tx_loadsz	= 256,
+		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 |
+				  UART_FCR_T_TRIG_11,
+		.flags		= UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR |
+				  UART_CAP_SLEEP,
 	},
 	[PORT_LPC3220] = {
 		.name		= "LPC3220",
@@ -455,6 +465,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
 }
 
 static int serial8250_default_handle_irq(struct uart_port *port);
+static int exar_handle_irq(struct uart_port *port);
 
 static void set_io_from_upio(struct uart_port *p)
 {
@@ -574,6 +585,19 @@ EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
  */
 static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
 {
+	/*
+	 * Exar UARTs have a SLEEP register that enables or disables
+	 * each UART to enter sleep mode separately.  On the XR17V35x the
+	 * register is accessible to each UART at the UART_EXAR_SLEEP
+	 * offset but the UART channel may only write to the corresponding
+	 * bit.
+	 */
+	if ((p->port.type == PORT_XR17V35X) ||
+	   (p->port.type == PORT_XR17D15X)) {
+		serial_out(p, UART_EXAR_SLEEP, 0xff);
+		return;
+	}
+
 	if (p->capabilities & UART_CAP_SLEEP) {
 		if (p->capabilities & UART_CAP_EFR) {
 			serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -881,6 +905,27 @@ static void autoconfig_16550a(struct uart_8250_port *up)
 	up->port.type = PORT_16550A;
 	up->capabilities |= UART_CAP_FIFO;
 
+	/*
+	 * XR17V35x UARTs have an extra divisor register, DLD
+	 * that gets enabled with when DLAB is set which will
+	 * cause the device to incorrectly match and assign
+	 * port type to PORT_16650.  The EFR for this UART is
+	 * found at offset 0x09. Instead check the Deice ID (DVID)
+	 * register for a 2, 4 or 8 port UART.
+	 */
+	if (up->port.flags & UPF_EXAR_EFR) {
+		status1 = serial_in(up, UART_EXAR_DVID);
+		if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) {
+			DEBUG_AUTOCONF("Exar XR17V35x ");
+			up->port.type = PORT_XR17V35X;
+			up->capabilities |= UART_CAP_AFE | UART_CAP_EFR |
+						UART_CAP_SLEEP;
+
+			return;
+		}
+
+	}
+
 	/*
 	 * Check for presence of the EFR when DLAB is set.
 	 * Only ST16C650V1 UARTs pass this test.
@@ -1013,8 +1058,12 @@ static void autoconfig_16550a(struct uart_8250_port *up)
 	 * Exar uarts have EFR in a weird location
 	 */
 	if (up->port.flags & UPF_EXAR_EFR) {
+		DEBUG_AUTOCONF("Exar XR17D15x ");
 		up->port.type = PORT_XR17D15X;
-		up->capabilities |= UART_CAP_AFE | UART_CAP_EFR;
+		up->capabilities |= UART_CAP_AFE | UART_CAP_EFR |
+				    UART_CAP_SLEEP;
+
+		return;
 	}
 
 	/*
@@ -1515,6 +1564,31 @@ static int serial8250_default_handle_irq(struct uart_port *port)
 	return serial8250_handle_irq(port, iir);
 }
 
+/*
+ * These Exar UARTs have an extra interrupt indicator that could
+ * fire for a few unimplemented interrupts.  One of which is a
+ * wakeup event when coming out of sleep.  Put this here just
+ * to be on the safe side that these interrupts don't go unhandled.
+ */
+static int exar_handle_irq(struct uart_port *port)
+{
+	unsigned char int0, int1, int2, int3;
+	unsigned int iir = serial_port_in(port, UART_IIR);
+	int ret;
+
+	ret = serial8250_handle_irq(port, iir);
+
+	if ((port->type == PORT_XR17V35X) ||
+	   (port->type == PORT_XR17D15X)) {
+		int0 = serial_port_in(port, 0x80);
+		int1 = serial_port_in(port, 0x81);
+		int2 = serial_port_in(port, 0x82);
+		int3 = serial_port_in(port, 0x83);
+	}
+
+	return ret;
+}
+
 /*
  * This is the serial driver's interrupt routine.
  *
@@ -2349,16 +2423,14 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
 			serial_port_out(port, UART_EFR, efr);
 	}
 
-#ifdef CONFIG_ARCH_OMAP1
 	/* Workaround to enable 115200 baud on OMAP1510 internal ports */
-	if (cpu_is_omap1510() && is_omap_port(up)) {
+	if (is_omap1510_8250(up)) {
 		if (baud == 115200) {
 			quot = 1;
 			serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
 		} else
 			serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
 	}
-#endif
 
 	/*
 	 * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
@@ -2439,10 +2511,9 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt)
 {
 	if (pt->port.iotype == UPIO_AU)
 		return 0x1000;
-#ifdef CONFIG_ARCH_OMAP1
-	if (is_omap_port(pt))
+	if (is_omap1_8250(pt))
 		return 0x16 << pt->port.regshift;
-#endif
+
 	return 8 << pt->port.regshift;
 }
 
@@ -2617,6 +2688,11 @@ static void serial8250_config_port(struct uart_port *port, int flags)
 		serial8250_release_rsa_resource(up);
 	if (port->type == PORT_UNKNOWN)
 		serial8250_release_std_resource(up);
+
+	/* Fixme: probably not the best place for this */
+	if ((port->type == PORT_XR17V35X) ||
+	   (port->type == PORT_XR17D15X))
+		port->handle_irq = exar_handle_irq;
 }
 
 static int
@@ -2992,7 +3068,7 @@ void serial8250_resume_port(int line)
  * list is terminated with a zero flags entry, which means we expect
  * all entries to have at least UPF_BOOT_AUTOCONF set.
  */
-static int __devinit serial8250_probe(struct platform_device *dev)
+static int serial8250_probe(struct platform_device *dev)
 {
 	struct plat_serial8250_port *p = dev->dev.platform_data;
 	struct uart_8250_port uart;
@@ -3038,7 +3114,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
 /*
  * Remove serial ports registered against a platform device.
  */
-static int __devexit serial8250_remove(struct platform_device *dev)
+static int serial8250_remove(struct platform_device *dev)
 {
 	int i;
 
@@ -3081,7 +3157,7 @@ static int serial8250_resume(struct platform_device *dev)
 
 static struct platform_driver serial8250_isa_driver = {
 	.probe		= serial8250_probe,
-	.remove		= __devexit_p(serial8250_remove),
+	.remove		= serial8250_remove,
 	.suspend	= serial8250_suspend,
 	.resume		= serial8250_resume,
 	.driver		= {

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

@@ -106,3 +106,39 @@ static inline int serial8250_pnp_init(void) { return 0; }
 static inline void serial8250_pnp_exit(void) { }
 #endif
 
+#ifdef CONFIG_ARCH_OMAP1
+static inline int is_omap1_8250(struct uart_8250_port *pt)
+{
+	int res;
+
+	switch (pt->port.mapbase) {
+	case OMAP1_UART1_BASE:
+	case OMAP1_UART2_BASE:
+	case OMAP1_UART3_BASE:
+		res = 1;
+		break;
+	default:
+		res = 0;
+		break;
+	}
+
+	return res;
+}
+
+static inline int is_omap1510_8250(struct uart_8250_port *pt)
+{
+	if (!cpu_is_omap1510())
+		return 0;
+
+	return is_omap1_8250(pt);
+}
+#else
+static inline int is_omap1_8250(struct uart_8250_port *pt)
+{
+	return 0;
+}
+static inline int is_omap1510_8250(struct uart_8250_port *pt)
+{
+	return 0;
+}
+#endif

+ 3 - 3
drivers/tty/serial/8250/8250_acorn.c

@@ -38,7 +38,7 @@ struct serial_card_info {
 	void __iomem *vaddr;
 };
 
-static int __devinit
+static int
 serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
 	struct serial_card_info *info;
@@ -80,7 +80,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
 	return 0;
 }
 
-static void __devexit serial_card_remove(struct expansion_card *ec)
+static void serial_card_remove(struct expansion_card *ec)
 {
 	struct serial_card_info *info = ecard_get_drvdata(ec);
 	int i;
@@ -116,7 +116,7 @@ static const struct ecard_id serial_cids[] = {
 
 static struct ecard_driver serial_card_driver = {
 	.probe		= serial_card_probe,
-	.remove 	= __devexit_p(serial_card_remove),
+	.remove		= serial_card_remove,
 	.id_table	= serial_cids,
 	.drv = {
 		.name	= "8250_acorn",

+ 28 - 3
drivers/tty/serial/8250/8250_dw.c

@@ -87,7 +87,7 @@ static int dw8250_handle_irq(struct uart_port *p)
 	return 0;
 }
 
-static int __devinit dw8250_probe(struct platform_device *pdev)
+static int dw8250_probe(struct platform_device *pdev)
 {
 	struct uart_8250_port uart = {};
 	struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -152,7 +152,7 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int __devexit dw8250_remove(struct platform_device *pdev)
+static int dw8250_remove(struct platform_device *pdev)
 {
 	struct dw8250_data *data = platform_get_drvdata(pdev);
 
@@ -161,6 +161,29 @@ static int __devexit dw8250_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int dw8250_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct dw8250_data *data = platform_get_drvdata(pdev);
+
+	serial8250_suspend_port(data->line);
+
+	return 0;
+}
+
+static int dw8250_resume(struct platform_device *pdev)
+{
+	struct dw8250_data *data = platform_get_drvdata(pdev);
+
+	serial8250_resume_port(data->line);
+
+	return 0;
+}
+#else
+#define dw8250_suspend NULL
+#define dw8250_resume NULL
+#endif /* CONFIG_PM */
+
 static const struct of_device_id dw8250_match[] = {
 	{ .compatible = "snps,dw-apb-uart" },
 	{ /* Sentinel */ }
@@ -174,7 +197,9 @@ static struct platform_driver dw8250_platform_driver = {
 		.of_match_table	= dw8250_match,
 	},
 	.probe			= dw8250_probe,
-	.remove			= __devexit_p(dw8250_remove),
+	.remove			= dw8250_remove,
+	.suspend		= dw8250_suspend,
+	.resume			= dw8250_resume,
 };
 
 module_platform_driver(dw8250_platform_driver);

+ 23 - 23
drivers/tty/serial/8250/8250_early.c

@@ -48,7 +48,7 @@ struct early_serial8250_device {
 
 static struct early_serial8250_device early_device;
 
-static unsigned int __init serial_in(struct uart_port *port, int offset)
+unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset)
 {
 	switch (port->iotype) {
 	case UPIO_MEM:
@@ -62,7 +62,7 @@ static unsigned int __init serial_in(struct uart_port *port, int offset)
 	}
 }
 
-static void __init serial_out(struct uart_port *port, int offset, int value)
+void __weak __init serial8250_early_out(struct uart_port *port, int offset, int value)
 {
 	switch (port->iotype) {
 	case UPIO_MEM:
@@ -84,7 +84,7 @@ static void __init wait_for_xmitr(struct uart_port *port)
 	unsigned int status;
 
 	for (;;) {
-		status = serial_in(port, UART_LSR);
+		status = serial8250_early_in(port, UART_LSR);
 		if ((status & BOTH_EMPTY) == BOTH_EMPTY)
 			return;
 		cpu_relax();
@@ -94,7 +94,7 @@ static void __init wait_for_xmitr(struct uart_port *port)
 static void __init serial_putc(struct uart_port *port, int c)
 {
 	wait_for_xmitr(port);
-	serial_out(port, UART_TX, c);
+	serial8250_early_out(port, UART_TX, c);
 }
 
 static void __init early_serial8250_write(struct console *console,
@@ -104,14 +104,14 @@ static void __init early_serial8250_write(struct console *console,
 	unsigned int ier;
 
 	/* Save the IER and disable interrupts */
-	ier = serial_in(port, UART_IER);
-	serial_out(port, UART_IER, 0);
+	ier = serial8250_early_in(port, UART_IER);
+	serial8250_early_out(port, UART_IER, 0);
 
 	uart_console_write(port, s, count, serial_putc);
 
 	/* Wait for transmitter to become empty and restore the IER */
 	wait_for_xmitr(port);
-	serial_out(port, UART_IER, ier);
+	serial8250_early_out(port, UART_IER, ier);
 }
 
 static unsigned int __init probe_baud(struct uart_port *port)
@@ -119,11 +119,11 @@ static unsigned int __init probe_baud(struct uart_port *port)
 	unsigned char lcr, dll, dlm;
 	unsigned int quot;
 
-	lcr = serial_in(port, UART_LCR);
-	serial_out(port, UART_LCR, lcr | UART_LCR_DLAB);
-	dll = serial_in(port, UART_DLL);
-	dlm = serial_in(port, UART_DLM);
-	serial_out(port, UART_LCR, lcr);
+	lcr = serial8250_early_in(port, UART_LCR);
+	serial8250_early_out(port, UART_LCR, lcr | UART_LCR_DLAB);
+	dll = serial8250_early_in(port, UART_DLL);
+	dlm = serial8250_early_in(port, UART_DLM);
+	serial8250_early_out(port, UART_LCR, lcr);
 
 	quot = (dlm << 8) | dll;
 	return (port->uartclk / 16) / quot;
@@ -135,17 +135,17 @@ static void __init init_port(struct early_serial8250_device *device)
 	unsigned int divisor;
 	unsigned char c;
 
-	serial_out(port, UART_LCR, 0x3);	/* 8n1 */
-	serial_out(port, UART_IER, 0);		/* no interrupt */
-	serial_out(port, UART_FCR, 0);		/* no fifo */
-	serial_out(port, UART_MCR, 0x3);	/* DTR + RTS */
-
-	divisor = port->uartclk / (16 * device->baud);
-	c = serial_in(port, UART_LCR);
-	serial_out(port, UART_LCR, c | UART_LCR_DLAB);
-	serial_out(port, UART_DLL, divisor & 0xff);
-	serial_out(port, UART_DLM, (divisor >> 8) & 0xff);
-	serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
+	serial8250_early_out(port, UART_LCR, 0x3);	/* 8n1 */
+	serial8250_early_out(port, UART_IER, 0);	/* no interrupt */
+	serial8250_early_out(port, UART_FCR, 0);	/* no fifo */
+	serial8250_early_out(port, UART_MCR, 0x3);	/* DTR + RTS */
+
+	divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
+	c = serial8250_early_in(port, UART_LCR);
+	serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB);
+	serial8250_early_out(port, UART_DLL, divisor & 0xff);
+	serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff);
+	serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
 }
 
 static int __init parse_options(struct early_serial8250_device *device,

+ 4 - 4
drivers/tty/serial/8250/8250_em.c

@@ -89,7 +89,7 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
 	serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
 }
 
-static int __devinit serial8250_em_probe(struct platform_device *pdev)
+static int serial8250_em_probe(struct platform_device *pdev)
 {
 	struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -152,7 +152,7 @@ static int __devinit serial8250_em_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int __devexit serial8250_em_remove(struct platform_device *pdev)
+static int serial8250_em_remove(struct platform_device *pdev)
 {
 	struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
 
@@ -163,7 +163,7 @@ static int __devexit serial8250_em_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = {
+static const struct of_device_id serial8250_em_dt_ids[] = {
 	{ .compatible = "renesas,em-uart", },
 	{},
 };
@@ -176,7 +176,7 @@ static struct platform_driver serial8250_em_platform_driver = {
 		.owner		= THIS_MODULE,
 	},
 	.probe			= serial8250_em_probe,
-	.remove			= __devexit_p(serial8250_em_remove),
+	.remove			= serial8250_em_remove,
 };
 
 module_platform_driver(serial8250_em_platform_driver);

+ 5 - 5
drivers/tty/serial/8250/8250_hp300.c

@@ -36,9 +36,9 @@ static struct hp300_port *hp300_ports;
 
 #ifdef CONFIG_HPDCA
 
-static int __devinit hpdca_init_one(struct dio_dev *d,
+static int hpdca_init_one(struct dio_dev *d,
 					const struct dio_device_id *ent);
-static void __devexit hpdca_remove_one(struct dio_dev *d);
+static void hpdca_remove_one(struct dio_dev *d);
 
 static struct dio_device_id hpdca_dio_tbl[] = {
 	{ DIO_ID_DCA0 },
@@ -52,7 +52,7 @@ static struct dio_driver hpdca_driver = {
 	.name      = "hpdca",
 	.id_table  = hpdca_dio_tbl,
 	.probe     = hpdca_init_one,
-	.remove    = __devexit_p(hpdca_remove_one),
+	.remove    = hpdca_remove_one,
 };
 
 #endif
@@ -159,7 +159,7 @@ int __init hp300_setup_serial_console(void)
 #endif /* CONFIG_SERIAL_8250_CONSOLE */
 
 #ifdef CONFIG_HPDCA
-static int __devinit hpdca_init_one(struct dio_dev *d,
+static int hpdca_init_one(struct dio_dev *d,
 				const struct dio_device_id *ent)
 {
 	struct uart_8250_port uart;
@@ -288,7 +288,7 @@ static int __init hp300_8250_init(void)
 }
 
 #ifdef CONFIG_HPDCA
-static void __devexit hpdca_remove_one(struct dio_dev *d)
+static void hpdca_remove_one(struct dio_dev *d)
 {
 	int line;
 

+ 303 - 49
drivers/tty/serial/8250/8250_pci.c

@@ -288,7 +288,7 @@ static int pci_plx9050_init(struct pci_dev *dev)
 	return 0;
 }
 
-static void __devexit pci_plx9050_exit(struct pci_dev *dev)
+static void pci_plx9050_exit(struct pci_dev *dev)
 {
 	u8 __iomem *p;
 
@@ -313,7 +313,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
 #define NI8420_INT_ENABLE_REG	0x38
 #define NI8420_INT_ENABLE_BIT	0x2000
 
-static void __devexit pci_ni8420_exit(struct pci_dev *dev)
+static void pci_ni8420_exit(struct pci_dev *dev)
 {
 	void __iomem *p;
 	unsigned long base, len;
@@ -345,7 +345,7 @@ static void __devexit pci_ni8420_exit(struct pci_dev *dev)
 
 #define MITE_LCIMR2_CLR_CPU_IE	(1 << 30)
 
-static void __devexit pci_ni8430_exit(struct pci_dev *dev)
+static void pci_ni8430_exit(struct pci_dev *dev)
 {
 	void __iomem *p;
 	unsigned long base, len;
@@ -422,7 +422,7 @@ static int sbs_init(struct pci_dev *dev)
  * Disables the global interrupt of PMC-OctalPro
  */
 
-static void __devexit sbs_exit(struct pci_dev *dev)
+static void sbs_exit(struct pci_dev *dev)
 {
 	u8 __iomem *p;
 
@@ -991,7 +991,7 @@ static int pci_ite887x_init(struct pci_dev *dev)
 	return ret;
 }
 
-static void __devexit pci_ite887x_exit(struct pci_dev *dev)
+static void pci_ite887x_exit(struct pci_dev *dev)
 {
 	u32 ioport;
 	/* the ioport is bit 0-15 in POSIO0R */
@@ -1068,7 +1068,7 @@ ce4100_serial_setup(struct serial_private *priv,
 {
 	int ret;
 
-	ret = setup_port(priv, port, 0, 0, board->reg_shift);
+	ret = setup_port(priv, port, idx, 0, board->reg_shift);
 	port->port.iotype = UPIO_MEM32;
 	port->port.type = PORT_XSCALE;
 	port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
@@ -1164,6 +1164,94 @@ pci_xr17c154_setup(struct serial_private *priv,
 	return pci_default_setup(priv, board, port, idx);
 }
 
+static int
+pci_xr17v35x_setup(struct serial_private *priv,
+		  const struct pciserial_board *board,
+		  struct uart_8250_port *port, int idx)
+{
+	u8 __iomem *p;
+
+	p = pci_ioremap_bar(priv->dev, 0);
+	if (p == NULL)
+		return -ENOMEM;
+
+	port->port.flags |= UPF_EXAR_EFR;
+
+	/*
+	 * Setup Multipurpose Input/Output pins.
+	 */
+	if (idx == 0) {
+		writeb(0x00, p + 0x8f); /*MPIOINT[7:0]*/
+		writeb(0x00, p + 0x90); /*MPIOLVL[7:0]*/
+		writeb(0x00, p + 0x91); /*MPIO3T[7:0]*/
+		writeb(0x00, p + 0x92); /*MPIOINV[7:0]*/
+		writeb(0x00, p + 0x93); /*MPIOSEL[7:0]*/
+		writeb(0x00, p + 0x94); /*MPIOOD[7:0]*/
+		writeb(0x00, p + 0x95); /*MPIOINT[15:8]*/
+		writeb(0x00, p + 0x96); /*MPIOLVL[15:8]*/
+		writeb(0x00, p + 0x97); /*MPIO3T[15:8]*/
+		writeb(0x00, p + 0x98); /*MPIOINV[15:8]*/
+		writeb(0x00, p + 0x99); /*MPIOSEL[15:8]*/
+		writeb(0x00, p + 0x9a); /*MPIOOD[15:8]*/
+	}
+	writeb(0x00, p + UART_EXAR_8XMODE);
+	writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
+	writeb(128, p + UART_EXAR_TXTRG);
+	writeb(128, p + UART_EXAR_RXTRG);
+	iounmap(p);
+
+	return pci_default_setup(priv, board, port, idx);
+}
+
+#define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004
+#define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002
+#define PCI_DEVICE_ID_COMMTECH_2324PCI335 0x000a
+#define PCI_DEVICE_ID_COMMTECH_2328PCI335 0x000b
+
+static int
+pci_fastcom335_setup(struct serial_private *priv,
+		  const struct pciserial_board *board,
+		  struct uart_8250_port *port, int idx)
+{
+	u8 __iomem *p;
+
+	p = pci_ioremap_bar(priv->dev, 0);
+	if (p == NULL)
+		return -ENOMEM;
+
+	port->port.flags |= UPF_EXAR_EFR;
+
+	/*
+	 * Setup Multipurpose Input/Output pins.
+	 */
+	if (idx == 0) {
+		switch (priv->dev->device) {
+		case PCI_DEVICE_ID_COMMTECH_4222PCI335:
+		case PCI_DEVICE_ID_COMMTECH_4224PCI335:
+			writeb(0x78, p + 0x90); /* MPIOLVL[7:0] */
+			writeb(0x00, p + 0x92); /* MPIOINV[7:0] */
+			writeb(0x00, p + 0x93); /* MPIOSEL[7:0] */
+			break;
+		case PCI_DEVICE_ID_COMMTECH_2324PCI335:
+		case PCI_DEVICE_ID_COMMTECH_2328PCI335:
+			writeb(0x00, p + 0x90); /* MPIOLVL[7:0] */
+			writeb(0xc0, p + 0x92); /* MPIOINV[7:0] */
+			writeb(0xc0, p + 0x93); /* MPIOSEL[7:0] */
+			break;
+		}
+		writeb(0x00, p + 0x8f); /* MPIOINT[7:0] */
+		writeb(0x00, p + 0x91); /* MPIO3T[7:0] */
+		writeb(0x00, p + 0x94); /* MPIOOD[7:0] */
+	}
+	writeb(0x00, p + UART_EXAR_8XMODE);
+	writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
+	writeb(32, p + UART_EXAR_TXTRG);
+	writeb(32, p + UART_EXAR_RXTRG);
+	iounmap(p);
+
+	return pci_default_setup(priv, board, port, idx);
+}
+
 static int
 pci_wch_ch353_setup(struct serial_private *priv,
                     const struct pciserial_board *board,
@@ -1213,6 +1301,10 @@ pci_wch_ch353_setup(struct serial_private *priv,
 #define PCI_VENDOR_ID_AGESTAR		0x5372
 #define PCI_DEVICE_ID_AGESTAR_9375	0x6872
 #define PCI_VENDOR_ID_ASIX		0x9710
+#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0019
+#define PCI_DEVICE_ID_COMMTECH_4224PCIE	0x0020
+#define PCI_DEVICE_ID_COMMTECH_4228PCIE	0x0021
+
 
 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584	0x1584
@@ -1314,7 +1406,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ite887x_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ite887x_exit),
+		.exit		= pci_ite887x_exit,
 	},
 	/*
 	 * National Instruments
@@ -1326,7 +1418,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1335,7 +1427,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1344,7 +1436,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1353,7 +1445,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1362,7 +1454,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1371,7 +1463,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1380,7 +1472,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1389,7 +1481,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1398,7 +1490,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1407,7 +1499,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1416,7 +1508,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1425,7 +1517,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8420_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_ni8420_exit),
+		.exit		= pci_ni8420_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_NI,
@@ -1434,7 +1526,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_ni8430_init,
 		.setup		= pci_ni8430_setup,
-		.exit		= __devexit_p(pci_ni8430_exit),
+		.exit		= pci_ni8430_exit,
 	},
 	/*
 	 * Panacom
@@ -1446,7 +1538,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_plx9050_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_plx9050_exit),
+		.exit		= pci_plx9050_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_PANACOM,
@@ -1455,7 +1547,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.init		= pci_plx9050_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_plx9050_exit),
+		.exit		= pci_plx9050_exit,
 	},
 	/*
 	 * PLX
@@ -1474,7 +1566,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_SUBDEVICE_ID_EXSYS_4055,
 		.init		= pci_plx9050_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_plx9050_exit),
+		.exit		= pci_plx9050_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_PLX,
@@ -1483,7 +1575,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_SUBDEVICE_ID_KEYSPAN_SX2,
 		.init		= pci_plx9050_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_plx9050_exit),
+		.exit		= pci_plx9050_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_PLX,
@@ -1492,7 +1584,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_SUBDEVICE_ID_UNKNOWN_0x1584,
 		.init		= pci_plx9050_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_plx9050_exit),
+		.exit		= pci_plx9050_exit,
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_PLX,
@@ -1501,7 +1593,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_DEVICE_ID_PLX_ROMULUS,
 		.init		= pci_plx9050_init,
 		.setup		= pci_default_setup,
-		.exit		= __devexit_p(pci_plx9050_exit),
+		.exit		= pci_plx9050_exit,
 	},
 	/*
 	 * SBS Technologies, Inc., PMC-OCTALPRO 232
@@ -1513,7 +1605,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_SUBDEVICE_ID_OCTPRO232,
 		.init		= sbs_init,
 		.setup		= sbs_setup,
-		.exit		= __devexit_p(sbs_exit),
+		.exit		= sbs_exit,
 	},
 	/*
 	 * SBS Technologies, Inc., PMC-OCTALPRO 422
@@ -1525,7 +1617,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_SUBDEVICE_ID_OCTPRO422,
 		.init		= sbs_init,
 		.setup		= sbs_setup,
-		.exit		= __devexit_p(sbs_exit),
+		.exit		= sbs_exit,
 	},
 	/*
 	 * SBS Technologies, Inc., P-Octal 232
@@ -1537,7 +1629,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_SUBDEVICE_ID_POCTAL232,
 		.init		= sbs_init,
 		.setup		= sbs_setup,
-		.exit		= __devexit_p(sbs_exit),
+		.exit		= sbs_exit,
 	},
 	/*
 	 * SBS Technologies, Inc., P-Octal 422
@@ -1549,7 +1641,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_SUBDEVICE_ID_POCTAL422,
 		.init		= sbs_init,
 		.setup		= sbs_setup,
-		.exit		= __devexit_p(sbs_exit),
+		.exit		= sbs_exit,
 	},
 	/*
 	 * SIIG cards - these may be called via parport_serial
@@ -1622,6 +1714,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.setup		= pci_xr17c154_setup,
 	},
+	{
+		.vendor = PCI_VENDOR_ID_EXAR,
+		.device = PCI_DEVICE_ID_EXAR_XR17V352,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_xr17v35x_setup,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_EXAR,
+		.device = PCI_DEVICE_ID_EXAR_XR17V354,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_xr17v35x_setup,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_EXAR,
+		.device = PCI_DEVICE_ID_EXAR_XR17V358,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_xr17v35x_setup,
+	},
 	/*
 	 * Xircom cards
 	 */
@@ -1787,6 +1900,59 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 		.subdevice	= PCI_ANY_ID,
 		.setup		= pci_asix_setup,
 	},
+	/*
+	 * Commtech, Inc. Fastcom adapters
+	 *
+	 */
+	{
+		.vendor = PCI_VENDOR_ID_COMMTECH,
+		.device = PCI_DEVICE_ID_COMMTECH_4222PCI335,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_fastcom335_setup,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_COMMTECH,
+		.device = PCI_DEVICE_ID_COMMTECH_4224PCI335,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_fastcom335_setup,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_COMMTECH,
+		.device = PCI_DEVICE_ID_COMMTECH_2324PCI335,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_fastcom335_setup,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_COMMTECH,
+		.device = PCI_DEVICE_ID_COMMTECH_2328PCI335,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_fastcom335_setup,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_COMMTECH,
+		.device = PCI_DEVICE_ID_COMMTECH_4222PCIE,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_xr17v35x_setup,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_COMMTECH,
+		.device = PCI_DEVICE_ID_COMMTECH_4224PCIE,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_xr17v35x_setup,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_COMMTECH,
+		.device = PCI_DEVICE_ID_COMMTECH_4228PCIE,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pci_xr17v35x_setup,
+	},
 	/*
 	 * Default "match everything" terminator entry
 	 */
@@ -1863,6 +2029,10 @@ enum pci_board_num_t {
 
 	pbn_b0_4_1152000,
 
+	pbn_b0_2_1152000_200,
+	pbn_b0_4_1152000_200,
+	pbn_b0_8_1152000_200,
+
 	pbn_b0_2_1843200,
 	pbn_b0_4_1843200,
 
@@ -1962,6 +2132,9 @@ enum pci_board_num_t {
 	pbn_exar_XR17C152,
 	pbn_exar_XR17C154,
 	pbn_exar_XR17C158,
+	pbn_exar_XR17V352,
+	pbn_exar_XR17V354,
+	pbn_exar_XR17V358,
 	pbn_exar_ibm_saturn,
 	pbn_pasemi_1682M,
 	pbn_ni8430_2,
@@ -1987,7 +2160,7 @@ enum pci_board_num_t {
  * see first lines of serial_in() and serial_out() in 8250.c
 */
 
-static struct pciserial_board pci_boards[] __devinitdata = {
+static struct pciserial_board pci_boards[] = {
 	[pbn_default] = {
 		.flags		= FL_BASE0,
 		.num_ports	= 1,
@@ -2057,6 +2230,27 @@ static struct pciserial_board pci_boards[] __devinitdata = {
 		.uart_offset	= 8,
 	},
 
+	[pbn_b0_2_1152000_200] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 2,
+		.base_baud	= 1152000,
+		.uart_offset	= 0x200,
+	},
+
+	[pbn_b0_4_1152000_200] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 4,
+		.base_baud	= 1152000,
+		.uart_offset	= 0x200,
+	},
+
+	[pbn_b0_8_1152000_200] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 2,
+		.base_baud	= 1152000,
+		.uart_offset	= 0x200,
+	},
+
 	[pbn_b0_2_1843200] = {
 		.flags		= FL_BASE0,
 		.num_ports	= 2,
@@ -2580,6 +2774,30 @@ static struct pciserial_board pci_boards[] __devinitdata = {
 		.base_baud	= 921600,
 		.uart_offset	= 0x200,
 	},
+	[pbn_exar_XR17V352] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 2,
+		.base_baud	= 7812500,
+		.uart_offset	= 0x400,
+		.reg_shift	= 0,
+		.first_offset	= 0,
+	},
+	[pbn_exar_XR17V354] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 4,
+		.base_baud	= 7812500,
+		.uart_offset	= 0x400,
+		.reg_shift	= 0,
+		.first_offset	= 0,
+	},
+	[pbn_exar_XR17V358] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 8,
+		.base_baud	= 7812500,
+		.uart_offset	= 0x400,
+		.reg_shift	= 0,
+		.first_offset	= 0,
+	},
 	[pbn_exar_ibm_saturn] = {
 		.flags		= FL_BASE0,
 		.num_ports	= 1,
@@ -2658,8 +2876,8 @@ static struct pciserial_board pci_boards[] __devinitdata = {
 		.first_offset	= 0x1000,
 	},
 	[pbn_ce4100_1_115200] = {
-		.flags		= FL_BASE0,
-		.num_ports	= 1,
+		.flags		= FL_BASE_BARS,
+		.num_ports	= 2,
 		.base_baud	= 921600,
 		.reg_shift      = 2,
 	},
@@ -2691,7 +2909,7 @@ static const struct pci_device_id blacklist[] = {
  * guess what the configuration might be, based on the pitiful PCI
  * serial specs.  Returns 0 on success, 1 on failure.
  */
-static int __devinit
+static int
 serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
 {
 	const struct pci_device_id *bldev;
@@ -2917,7 +3135,7 @@ EXPORT_SYMBOL_GPL(pciserial_resume_ports);
  * Probe one serial board.  Unfortunately, there is no rhyme nor reason
  * to the arrangement of serial ports on a PCI card.
  */
-static int __devinit
+static int
 pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
 {
 	struct pci_serial_quirk *quirk;
@@ -2988,7 +3206,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
 	return rc;
 }
 
-static void __devexit pciserial_remove_one(struct pci_dev *dev)
+static void pciserial_remove_one(struct pci_dev *dev)
 {
 	struct serial_private *priv = pci_get_drvdata(dev);
 
@@ -3826,6 +4044,21 @@ static struct pci_device_id serial_pci_tbl[] = {
 		PCI_ANY_ID, PCI_ANY_ID,
 		0,
 		0, pbn_exar_XR17C158 },
+	/*
+	 * Exar Corp. XR17V35[248] Dual/Quad/Octal PCIe UARTs
+	 */
+	{	PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V352,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_exar_XR17V352 },
+	{	PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V354,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_exar_XR17V354 },
+	{	PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V358,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_exar_XR17V358 },
 
 	/*
 	 * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
@@ -4256,6 +4489,38 @@ static struct pci_device_id serial_pci_tbl[] = {
 		PCI_ANY_ID, PCI_ANY_ID,
 		0, 0, pbn_b0_bt_2_115200 },
 
+	/*
+	 * Commtech, Inc. Fastcom adapters
+	 */
+	{	PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4222PCI335,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_b0_2_1152000_200 },
+	{	PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4224PCI335,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_b0_4_1152000_200 },
+	{	PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_2324PCI335,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_b0_4_1152000_200 },
+	{	PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_2328PCI335,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_b0_8_1152000_200 },
+	{	PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4222PCIE,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_exar_XR17V352 },
+	{	PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4224PCIE,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_exar_XR17V354 },
+	{	PCI_VENDOR_ID_COMMTECH, PCI_DEVICE_ID_COMMTECH_4228PCIE,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0,
+		0, pbn_exar_XR17V358 },
+
 	/*
 	 * These entries match devices with class COMMUNICATION_SERIAL,
 	 * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
@@ -4323,7 +4588,7 @@ static const struct pci_error_handlers serial8250_err_handler = {
 static struct pci_driver serial_pci_driver = {
 	.name		= "serial",
 	.probe		= pciserial_init_one,
-	.remove		= __devexit_p(pciserial_remove_one),
+	.remove		= pciserial_remove_one,
 #ifdef CONFIG_PM
 	.suspend	= pciserial_suspend_one,
 	.resume		= pciserial_resume_one,
@@ -4332,18 +4597,7 @@ static struct pci_driver serial_pci_driver = {
 	.err_handler	= &serial8250_err_handler,
 };
 
-static int __init serial8250_pci_init(void)
-{
-	return pci_register_driver(&serial_pci_driver);
-}
-
-static void __exit serial8250_pci_exit(void)
-{
-	pci_unregister_driver(&serial_pci_driver);
-}
-
-module_init(serial8250_pci_init);
-module_exit(serial8250_pci_exit);
+module_pci_driver(serial_pci_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");

+ 7 - 7
drivers/tty/serial/8250/8250_pnp.c

@@ -370,14 +370,14 @@ static const struct pnp_device_id pnp_dev_table[] = {
 
 MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
 
-static char *modem_names[] __devinitdata = {
+static char *modem_names[] = {
 	"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
 	"56K", "56k", "K56", "33.6", "28.8", "14.4",
 	"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
 	"33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
 };
 
-static int __devinit check_name(char *name)
+static int check_name(char *name)
 {
 	char **tmp;
 
@@ -388,7 +388,7 @@ static int __devinit check_name(char *name)
 	return 0;
 }
 
-static int __devinit check_resources(struct pnp_dev *dev)
+static int check_resources(struct pnp_dev *dev)
 {
 	resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
 	int i;
@@ -412,7 +412,7 @@ static int __devinit check_resources(struct pnp_dev *dev)
  * PnP modems, alternatively we must hardcode all modems in pnp_devices[]
  * table.
  */
-static int __devinit serial_pnp_guess_board(struct pnp_dev *dev)
+static int serial_pnp_guess_board(struct pnp_dev *dev)
 {
 	if (!(check_name(pnp_dev_name(dev)) ||
 		(dev->card && check_name(dev->card->name))))
@@ -424,7 +424,7 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev)
 	return -ENODEV;
 }
 
-static int __devinit
+static int
 serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 {
 	struct uart_8250_port uart;
@@ -476,7 +476,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 	return 0;
 }
 
-static void __devexit serial_pnp_remove(struct pnp_dev *dev)
+static void serial_pnp_remove(struct pnp_dev *dev)
 {
 	long line = (long)pnp_get_drvdata(dev);
 	if (line)
@@ -511,7 +511,7 @@ static int serial_pnp_resume(struct pnp_dev *dev)
 static struct pnp_driver serial_pnp_driver = {
 	.name		= "serial",
 	.probe		= serial_pnp_probe,
-	.remove		= __devexit_p(serial_pnp_remove),
+	.remove		= serial_pnp_remove,
 	.suspend	= serial_pnp_suspend,
 	.resume		= serial_pnp_resume,
 	.id_table	= pnp_dev_table,

+ 36 - 12
drivers/tty/serial/Kconfig

@@ -93,7 +93,7 @@ config SERIAL_SB1250_DUART_CONSOLE
 
 config SERIAL_ATMEL
 	bool "AT91 / AT32 on-chip serial port support"
-	depends on (ARM && ARCH_AT91) || AVR32
+	depends on ARCH_AT91 || AVR32
 	select SERIAL_CORE
 	help
 	  This enables the driver for the on-chip UARTs of the Atmel
@@ -198,7 +198,7 @@ config SERIAL_CLPS711X_CONSOLE
 
 config SERIAL_SAMSUNG
 	tristate "Samsung SoC serial support"
-	depends on ARM && PLAT_SAMSUNG
+	depends on PLAT_SAMSUNG
 	select SERIAL_CORE
 	help
 	  Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
@@ -208,14 +208,14 @@ config SERIAL_SAMSUNG
 
 config SERIAL_SAMSUNG_UARTS_4
 	bool
-	depends on ARM && PLAT_SAMSUNG
+	depends on PLAT_SAMSUNG
 	default y if !(CPU_S3C2410 || SERIAL_S3C2412 || CPU_S3C2440 || CPU_S3C2442)
 	help
 	  Internal node for the common case of 4 Samsung compatible UARTs
 
 config SERIAL_SAMSUNG_UARTS
 	int
-	depends on ARM && PLAT_SAMSUNG
+	depends on PLAT_SAMSUNG
 	default 6 if ARCH_S5P6450
 	default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416
 	default 3
@@ -249,7 +249,7 @@ config SERIAL_SAMSUNG_CONSOLE
 
 config SERIAL_SIRFSOC
         tristate "SiRF SoC Platform Serial port support"
-        depends on ARM && ARCH_PRIMA2
+        depends on ARCH_PRIMA2
         select SERIAL_CORE
         help
           Support for the on-chip UART on the CSR SiRFprimaII series,
@@ -347,7 +347,7 @@ config SERIAL_ZS_CONSOLE
 
 config SERIAL_21285
 	tristate "DC21285 serial port support"
-	depends on ARM && FOOTBRIDGE
+	depends on FOOTBRIDGE
 	select SERIAL_CORE
 	help
 	  If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
@@ -371,7 +371,7 @@ config SERIAL_21285_CONSOLE
 
 config SERIAL_MPSC
 	bool "Marvell MPSC serial port support"
-	depends on PPC32 && MV64X60
+	depends on MV64X60
 	select SERIAL_CORE
 	help
 	  Say Y here if you want to use the Marvell MPSC serial controller.
@@ -408,7 +408,7 @@ config SERIAL_PXA_CONSOLE
 
 config SERIAL_SA1100
 	bool "SA1100 serial port support"
-	depends on ARM && ARCH_SA1100
+	depends on ARCH_SA1100
 	select SERIAL_CORE
 	help
 	  If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you
@@ -716,7 +716,7 @@ config SERIAL_SH_SCI_DMA
 
 config SERIAL_PNX8XXX
 	bool "Enable PNX8XXX SoCs' UART Support"
-	depends on MIPS && (SOC_PNX8550 || SOC_PNX833X)
+	depends on SOC_PNX8550 || SOC_PNX833X
 	select SERIAL_CORE
 	help
 	  If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
@@ -1013,7 +1013,7 @@ config SERIAL_SGI_IOC3
 
 config SERIAL_MSM
 	bool "MSM on-chip serial port support"
-	depends on ARM && ARCH_MSM
+	depends on ARCH_MSM
 	select SERIAL_CORE
 
 config SERIAL_MSM_CONSOLE
@@ -1035,7 +1035,7 @@ config SERIAL_MSM_HS
 
 config SERIAL_VT8500
 	bool "VIA VT8500 on-chip serial port support"
-	depends on ARM && ARCH_VT8500
+	depends on ARCH_VT8500
 	select SERIAL_CORE
 
 config SERIAL_VT8500_CONSOLE
@@ -1045,7 +1045,7 @@ config SERIAL_VT8500_CONSOLE
 
 config SERIAL_NETX
 	tristate "NetX serial port support"
-	depends on ARM && ARCH_NETX
+	depends on ARCH_NETX
 	select SERIAL_CORE
 	help
 	  If you have a machine based on a Hilscher NetX SoC you
@@ -1376,6 +1376,7 @@ config SERIAL_MXS_AUART_CONSOLE
 
 config SERIAL_XILINX_PS_UART
 	tristate "Xilinx PS UART support"
+	depends on OF
 	select SERIAL_CORE
 	help
 	  This driver supports the Xilinx PS UART port.
@@ -1423,4 +1424,27 @@ config SERIAL_EFM32_UART_CONSOLE
 	depends on SERIAL_EFM32_UART=y
 	select SERIAL_CORE_CONSOLE
 
+config SERIAL_ARC
+	tristate "ARC UART driver support"
+	select SERIAL_CORE
+	help
+	  Driver for on-chip UART for ARC(Synopsys) for the legacy
+	  FPGA Boards (ML50x/ARCAngel4)
+
+config SERIAL_ARC_CONSOLE
+	bool "Console on ARC UART"
+	depends on SERIAL_ARC=y
+	select SERIAL_CORE_CONSOLE
+	help
+	  Enable system Console on ARC UART
+
+config SERIAL_ARC_NR_PORTS
+	int "Number of ARC UART ports"
+	depends on SERIAL_ARC
+	range 1 3
+	default "1"
+	help
+	  Set this to the number of serial ports you want the driver
+	  to support.
+
 endmenu

+ 1 - 0
drivers/tty/serial/Makefile

@@ -82,3 +82,4 @@ 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
+obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o

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

@@ -406,7 +406,7 @@ static struct uart_driver altera_jtaguart_driver = {
 	.cons		= ALTERA_JTAGUART_CONSOLE,
 };
 
-static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
+static int altera_jtaguart_probe(struct platform_device *pdev)
 {
 	struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
 	struct uart_port *port;
@@ -453,7 +453,7 @@ static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
+static int altera_jtaguart_remove(struct platform_device *pdev)
 {
 	struct uart_port *port;
 	int i = pdev->id;
@@ -477,7 +477,7 @@ MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
 
 static struct platform_driver altera_jtaguart_platform_driver = {
 	.probe	= altera_jtaguart_probe,
-	.remove	= __devexit_p(altera_jtaguart_remove),
+	.remove	= altera_jtaguart_remove,
 	.driver	= {
 		.name		= DRV_NAME,
 		.owner		= THIS_MODULE,

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

@@ -532,7 +532,7 @@ static int altera_uart_get_of_uartclk(struct platform_device *pdev,
 }
 #endif /* CONFIG_OF */
 
-static int __devinit altera_uart_probe(struct platform_device *pdev)
+static int altera_uart_probe(struct platform_device *pdev)
 {
 	struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
 	struct uart_port *port;
@@ -598,7 +598,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int __devexit altera_uart_remove(struct platform_device *pdev)
+static int altera_uart_remove(struct platform_device *pdev)
 {
 	struct uart_port *port = platform_get_drvdata(pdev);
 
@@ -621,7 +621,7 @@ MODULE_DEVICE_TABLE(of, altera_uart_match);
 
 static struct platform_driver altera_uart_platform_driver = {
 	.probe	= altera_uart_probe,
-	.remove	= __devexit_p(altera_uart_remove),
+	.remove	= altera_uart_remove,
 	.driver	= {
 		.name		= DRV_NAME,
 		.owner		= THIS_MODULE,

+ 9 - 16
drivers/tty/serial/amba-pl011.c

@@ -56,8 +56,7 @@
 #include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/sizes.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #define UART_NR			14
 
@@ -1973,7 +1972,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 		goto out;
 	}
 
-	uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+	uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
+			   GFP_KERNEL);
 	if (uap == NULL) {
 		ret = -ENOMEM;
 		goto out;
@@ -1981,16 +1981,17 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 
 	i = pl011_probe_dt_alias(i, &dev->dev);
 
-	base = ioremap(dev->res.start, resource_size(&dev->res));
+	base = devm_ioremap(&dev->dev, dev->res.start,
+			    resource_size(&dev->res));
 	if (!base) {
 		ret = -ENOMEM;
-		goto free;
+		goto out;
 	}
 
 	uap->pinctrl = devm_pinctrl_get(&dev->dev);
 	if (IS_ERR(uap->pinctrl)) {
 		ret = PTR_ERR(uap->pinctrl);
-		goto unmap;
+		goto out;
 	}
 	uap->pins_default = pinctrl_lookup_state(uap->pinctrl,
 						 PINCTRL_STATE_DEFAULT);
@@ -2002,10 +2003,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 	if (IS_ERR(uap->pins_sleep))
 		dev_dbg(&dev->dev, "could not get sleep pinstate\n");
 
-	uap->clk = clk_get(&dev->dev, NULL);
+	uap->clk = devm_clk_get(&dev->dev, NULL);
 	if (IS_ERR(uap->clk)) {
 		ret = PTR_ERR(uap->clk);
-		goto unmap;
+		goto out;
 	}
 
 	uap->vendor = vendor;
@@ -2038,11 +2039,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
 		amba_set_drvdata(dev, NULL);
 		amba_ports[i] = NULL;
 		pl011_dma_remove(uap);
-		clk_put(uap->clk);
- unmap:
-		iounmap(base);
- free:
-		kfree(uap);
 	}
  out:
 	return ret;
@@ -2062,9 +2058,6 @@ static int pl011_remove(struct amba_device *dev)
 			amba_ports[i] = NULL;
 
 	pl011_dma_remove(uap);
-	iounmap(uap->port.membase);
-	clk_put(uap->clk);
-	kfree(uap);
 	return 0;
 }
 

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

@@ -554,7 +554,7 @@ static struct uart_driver grlib_apbuart_driver = {
 /* OF Platform Driver                                                       */
 /* ======================================================================== */
 
-static int __devinit apbuart_probe(struct platform_device *op)
+static int apbuart_probe(struct platform_device *op)
 {
 	int i;
 	struct uart_port *port = NULL;

+ 88 - 8
drivers/tty/serial/ar933x_uart.c

@@ -25,11 +25,19 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 
+#include <asm/div64.h>
+
 #include <asm/mach-ath79/ar933x_uart.h>
 #include <asm/mach-ath79/ar933x_uart_platform.h>
 
 #define DRIVER_NAME "ar933x-uart"
 
+#define AR933X_UART_MAX_SCALE	0xff
+#define AR933X_UART_MAX_STEP	0xffff
+
+#define AR933X_UART_MIN_BAUD	300
+#define AR933X_UART_MAX_BAUD	3000000
+
 #define AR933X_DUMMY_STATUS_RD	0x01
 
 static struct uart_driver ar933x_uart_driver;
@@ -37,6 +45,8 @@ static struct uart_driver ar933x_uart_driver;
 struct ar933x_uart_port {
 	struct uart_port	port;
 	unsigned int		ier;	/* shadow Interrupt Enable Register */
+	unsigned int		min_baud;
+	unsigned int		max_baud;
 };
 
 static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
@@ -162,6 +172,57 @@ static void ar933x_uart_enable_ms(struct uart_port *port)
 {
 }
 
+/*
+ * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
+ */
+static unsigned long ar933x_uart_get_baud(unsigned int clk,
+					  unsigned int scale,
+					  unsigned int step)
+{
+	u64 t;
+	u32 div;
+
+	div = (2 << 16) * (scale + 1);
+	t = clk;
+	t *= step;
+	t += (div / 2);
+	do_div(t, div);
+
+	return t;
+}
+
+static void ar933x_uart_get_scale_step(unsigned int clk,
+				       unsigned int baud,
+				       unsigned int *scale,
+				       unsigned int *step)
+{
+	unsigned int tscale;
+	long min_diff;
+
+	*scale = 0;
+	*step = 0;
+
+	min_diff = baud;
+	for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
+		u64 tstep;
+		int diff;
+
+		tstep = baud * (tscale + 1);
+		tstep *= (2 << 16);
+		do_div(tstep, clk);
+
+		if (tstep > AR933X_UART_MAX_STEP)
+			break;
+
+		diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
+		if (diff < min_diff) {
+			min_diff = diff;
+			*scale = tscale;
+			*step = tstep;
+		}
+	}
+}
+
 static void ar933x_uart_set_termios(struct uart_port *port,
 				    struct ktermios *new,
 				    struct ktermios *old)
@@ -169,7 +230,7 @@ static void ar933x_uart_set_termios(struct uart_port *port,
 	struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
 	unsigned int cs;
 	unsigned long flags;
-	unsigned int baud, scale;
+	unsigned int baud, scale, step;
 
 	/* Only CS8 is supported */
 	new->c_cflag &= ~CSIZE;
@@ -191,8 +252,8 @@ static void ar933x_uart_set_termios(struct uart_port *port,
 	/* Mark/space parity is not supported */
 	new->c_cflag &= ~CMSPAR;
 
-	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
-	scale = (port->uartclk / (16 * baud)) - 1;
+	baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud);
+	ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step);
 
 	/*
 	 * Ok, we're now changing the port state. Do it with
@@ -200,6 +261,10 @@ static void ar933x_uart_set_termios(struct uart_port *port,
 	 */
 	spin_lock_irqsave(&up->port.lock, flags);
 
+	/* disable the UART */
+	ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
+		      AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S);
+
 	/* Update the per-port timeout. */
 	uart_update_timeout(port, new->c_cflag, baud);
 
@@ -210,7 +275,7 @@ static void ar933x_uart_set_termios(struct uart_port *port,
 		up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;
 
 	ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
-			  scale << AR933X_UART_CLOCK_SCALE_S | 8192);
+			  scale << AR933X_UART_CLOCK_SCALE_S | step);
 
 	/* setup configuration register */
 	ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);
@@ -219,6 +284,11 @@ static void ar933x_uart_set_termios(struct uart_port *port,
 	ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
 			    AR933X_UART_CS_HOST_INT_EN);
 
+	/* reenable the UART */
+	ar933x_uart_rmw(up, AR933X_UART_CS_REG,
+			AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
+			AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
+
 	spin_unlock_irqrestore(&up->port.lock, flags);
 
 	if (tty_termios_baud_rate(new))
@@ -401,6 +471,8 @@ static void ar933x_uart_config_port(struct uart_port *port, int flags)
 static int ar933x_uart_verify_port(struct uart_port *port,
 				   struct serial_struct *ser)
 {
+	struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+
 	if (ser->type != PORT_UNKNOWN &&
 	    ser->type != PORT_AR933X)
 		return -EINVAL;
@@ -408,7 +480,8 @@ static int ar933x_uart_verify_port(struct uart_port *port,
 	if (ser->irq < 0 || ser->irq >= NR_IRQS)
 		return -EINVAL;
 
-	if (ser->baud_base < 28800)
+	if (ser->baud_base < up->min_baud ||
+	    ser->baud_base > up->max_baud)
 		return -EINVAL;
 
 	return 0;
@@ -554,13 +627,14 @@ static struct uart_driver ar933x_uart_driver = {
 	.cons		= AR933X_SERIAL_CONSOLE,
 };
 
-static int __devinit ar933x_uart_probe(struct platform_device *pdev)
+static int ar933x_uart_probe(struct platform_device *pdev)
 {
 	struct ar933x_uart_platform_data *pdata;
 	struct ar933x_uart_port *up;
 	struct uart_port *port;
 	struct resource *mem_res;
 	struct resource *irq_res;
+	unsigned int baud;
 	int id;
 	int ret;
 
@@ -611,6 +685,12 @@ static int __devinit ar933x_uart_probe(struct platform_device *pdev)
 	port->fifosize = AR933X_UART_FIFO_SIZE;
 	port->ops = &ar933x_uart_ops;
 
+	baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
+	up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
+
+	baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
+	up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
+
 	ar933x_uart_add_console_port(up);
 
 	ret = uart_add_one_port(&ar933x_uart_driver, &up->port);
@@ -627,7 +707,7 @@ err_free_up:
 	return ret;
 }
 
-static int __devexit ar933x_uart_remove(struct platform_device *pdev)
+static int ar933x_uart_remove(struct platform_device *pdev)
 {
 	struct ar933x_uart_port *up;
 
@@ -645,7 +725,7 @@ static int __devexit ar933x_uart_remove(struct platform_device *pdev)
 
 static struct platform_driver ar933x_uart_platform_driver = {
 	.probe		= ar933x_uart_probe,
-	.remove		= __devexit_p(ar933x_uart_remove),
+	.remove		= ar933x_uart_remove,
 	.driver		= {
 		.name		= DRIVER_NAME,
 		.owner		= THIS_MODULE,

+ 746 - 0
drivers/tty/serial/arc_uart.c

@@ -0,0 +1,746 @@
+/*
+ * ARC On-Chip(fpga) UART Driver
+ *
+ * Copyright (C) 2010-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * vineetg: July 10th 2012
+ *  -Decoupled the driver from arch/arc
+ *    +Using platform_get_resource() for irq/membase (thx to bfin_uart.c)
+ *    +Using early_platform_xxx() for early console (thx to mach-shmobile/xxx)
+ *
+ * Vineetg: Aug 21st 2010
+ *  -Is uart_tx_stopped() not done in tty write path as it has already been
+ *   taken care of, in serial core
+ *
+ * Vineetg: Aug 18th 2010
+ *  -New Serial Core based ARC UART driver
+ *  -Derived largely from blackfin driver albiet with some major tweaks
+ *
+ * TODO:
+ *  -check if sysreq works
+ */
+
+#if defined(CONFIG_SERIAL_ARC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+/*************************************
+ * ARC UART Hardware Specs
+ ************************************/
+#define ARC_UART_TX_FIFO_SIZE  1
+
+/*
+ * UART Register set (this is not a Standards Compliant IP)
+ * Also each reg is Word aligned, but only 8 bits wide
+ */
+#define R_ID0	0
+#define R_ID1	4
+#define R_ID2	8
+#define R_ID3	12
+#define R_DATA	16
+#define R_STS	20
+#define R_BAUDL	24
+#define R_BAUDH	28
+
+/* Bits for UART Status Reg (R/W) */
+#define RXIENB  0x04	/* Receive Interrupt Enable */
+#define TXIENB  0x40	/* Transmit Interrupt Enable */
+
+#define RXEMPTY 0x20	/* Receive FIFO Empty: No char receivede */
+#define TXEMPTY 0x80	/* Transmit FIFO Empty, thus char can be written into */
+
+#define RXFULL  0x08	/* Receive FIFO full */
+#define RXFULL1 0x10	/* Receive FIFO has space for 1 char (tot space=4) */
+
+#define RXFERR  0x01	/* Frame Error: Stop Bit not detected */
+#define RXOERR  0x02	/* OverFlow Err: Char recv but RXFULL still set */
+
+/* Uart bit fiddling helpers: lowest level */
+#define RBASE(uart, reg)      (uart->port.membase + reg)
+#define UART_REG_SET(u, r, v) writeb((v), RBASE(u, r))
+#define UART_REG_GET(u, r)    readb(RBASE(u, r))
+
+#define UART_REG_OR(u, r, v)  UART_REG_SET(u, r, UART_REG_GET(u, r) | (v))
+#define UART_REG_CLR(u, r, v) UART_REG_SET(u, r, UART_REG_GET(u, r) & ~(v))
+
+/* Uart bit fiddling helpers: API level */
+#define UART_SET_DATA(uart, val)   UART_REG_SET(uart, R_DATA, val)
+#define UART_GET_DATA(uart)        UART_REG_GET(uart, R_DATA)
+
+#define UART_SET_BAUDH(uart, val)  UART_REG_SET(uart, R_BAUDH, val)
+#define UART_SET_BAUDL(uart, val)  UART_REG_SET(uart, R_BAUDL, val)
+
+#define UART_CLR_STATUS(uart, val) UART_REG_CLR(uart, R_STS, val)
+#define UART_GET_STATUS(uart)      UART_REG_GET(uart, R_STS)
+
+#define UART_ALL_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, RXIENB|TXIENB)
+#define UART_RX_IRQ_DISABLE(uart)  UART_REG_CLR(uart, R_STS, RXIENB)
+#define UART_TX_IRQ_DISABLE(uart)  UART_REG_CLR(uart, R_STS, TXIENB)
+
+#define UART_ALL_IRQ_ENABLE(uart)  UART_REG_OR(uart, R_STS, RXIENB|TXIENB)
+#define UART_RX_IRQ_ENABLE(uart)   UART_REG_OR(uart, R_STS, RXIENB)
+#define UART_TX_IRQ_ENABLE(uart)   UART_REG_OR(uart, R_STS, TXIENB)
+
+#define ARC_SERIAL_DEV_NAME	"ttyARC"
+
+struct arc_uart_port {
+	struct uart_port port;
+	unsigned long baud;
+	int is_emulated;	/* H/w vs. Instruction Set Simulator */
+};
+
+#define to_arc_port(uport)  container_of(uport, struct arc_uart_port, port)
+
+static struct arc_uart_port arc_uart_ports[CONFIG_SERIAL_ARC_NR_PORTS];
+
+#ifdef CONFIG_SERIAL_ARC_CONSOLE
+static struct console arc_console;
+#endif
+
+#define DRIVER_NAME	"arc-uart"
+
+static struct uart_driver arc_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= DRIVER_NAME,
+	.dev_name	= ARC_SERIAL_DEV_NAME,
+	.major		= 0,
+	.minor		= 0,
+	.nr		= CONFIG_SERIAL_ARC_NR_PORTS,
+#ifdef CONFIG_SERIAL_ARC_CONSOLE
+	.cons		= &arc_console,
+#endif
+};
+
+static void arc_serial_stop_rx(struct uart_port *port)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+
+	UART_RX_IRQ_DISABLE(uart);
+}
+
+static void arc_serial_stop_tx(struct uart_port *port)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+
+	while (!(UART_GET_STATUS(uart) & TXEMPTY))
+		cpu_relax();
+
+	UART_TX_IRQ_DISABLE(uart);
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int arc_serial_tx_empty(struct uart_port *port)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+	unsigned int stat;
+
+	stat = UART_GET_STATUS(uart);
+	if (stat & TXEMPTY)
+		return TIOCSER_TEMT;
+
+	return 0;
+}
+
+/*
+ * Driver internal routine, used by both tty(serial core) as well as tx-isr
+ *  -Called under spinlock in either cases
+ *  -also tty->stopped / tty->hw_stopped has already been checked
+ *     = by uart_start( ) before calling us
+ *     = tx_ist checks that too before calling
+ */
+static void arc_serial_tx_chars(struct arc_uart_port *uart)
+{
+	struct circ_buf *xmit = &uart->port.state->xmit;
+	int sent = 0;
+	unsigned char ch;
+
+	if (unlikely(uart->port.x_char)) {
+		UART_SET_DATA(uart, uart->port.x_char);
+		uart->port.icount.tx++;
+		uart->port.x_char = 0;
+		sent = 1;
+	} else if (xmit->tail != xmit->head) {	/* TODO: uart_circ_empty */
+		ch = xmit->buf[xmit->tail];
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		uart->port.icount.tx++;
+		while (!(UART_GET_STATUS(uart) & TXEMPTY))
+			cpu_relax();
+		UART_SET_DATA(uart, ch);
+		sent = 1;
+	}
+
+	/*
+	 * If num chars in xmit buffer are too few, ask tty layer for more.
+	 * By Hard ISR to schedule processing in software interrupt part
+	 */
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&uart->port);
+
+	if (sent)
+		UART_TX_IRQ_ENABLE(uart);
+}
+
+/*
+ * port is locked and interrupts are disabled
+ * uart_start( ) calls us under the port spinlock irqsave
+ */
+static void arc_serial_start_tx(struct uart_port *port)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+
+	arc_serial_tx_chars(uart);
+}
+
+static void arc_serial_rx_chars(struct arc_uart_port *uart)
+{
+	struct tty_struct *tty = tty_port_tty_get(&uart->port.state->port);
+	unsigned int status, ch, flg = 0;
+
+	if (!tty)
+		return;
+
+	/*
+	 * UART has 4 deep RX-FIFO. Driver's recongnition of this fact
+	 * is very subtle. Here's how ...
+	 * Upon getting a RX-Intr, such that RX-EMPTY=0, meaning data available,
+	 * driver reads the DATA Reg and keeps doing that in a loop, until
+	 * RX-EMPTY=1. Multiple chars being avail, with a single Interrupt,
+	 * before RX-EMPTY=0, implies some sort of buffering going on in the
+	 * controller, which is indeed the Rx-FIFO.
+	 */
+	while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)) {
+
+		ch = UART_GET_DATA(uart);
+		uart->port.icount.rx++;
+
+		if (unlikely(status & (RXOERR | RXFERR))) {
+			if (status & RXOERR) {
+				uart->port.icount.overrun++;
+				flg = TTY_OVERRUN;
+				UART_CLR_STATUS(uart, RXOERR);
+			}
+
+			if (status & RXFERR) {
+				uart->port.icount.frame++;
+				flg = TTY_FRAME;
+				UART_CLR_STATUS(uart, RXFERR);
+			}
+		} else
+			flg = TTY_NORMAL;
+
+		if (unlikely(uart_handle_sysrq_char(&uart->port, ch)))
+			goto done;
+
+		uart_insert_char(&uart->port, status, RXOERR, ch, flg);
+
+done:
+		tty_flip_buffer_push(tty);
+	}
+
+	tty_kref_put(tty);
+}
+
+/*
+ * A note on the Interrupt handling state machine of this driver
+ *
+ * kernel printk writes funnel thru the console driver framework and in order
+ * to keep things simple as well as efficient, it writes to UART in polled
+ * mode, in one shot, and exits.
+ *
+ * OTOH, Userland output (via tty layer), uses interrupt based writes as there
+ * can be undeterministic delay between char writes.
+ *
+ * Thus Rx-interrupts are always enabled, while tx-interrupts are by default
+ * disabled.
+ *
+ * When tty has some data to send out, serial core calls driver's start_tx
+ * which
+ *   -checks-if-tty-buffer-has-char-to-send
+ *   -writes-data-to-uart
+ *   -enable-tx-intr
+ *
+ * Once data bits are pushed out, controller raises the Tx-room-avail-Interrupt.
+ * The first thing Tx ISR does is disable further Tx interrupts (as this could
+ * be the last char to send, before settling down into the quiet polled mode).
+ * It then calls the exact routine used by tty layer write to send out any
+ * more char in tty buffer. In case of sending, it re-enables Tx-intr. In case
+ * of no data, it remains disabled.
+ * This is how the transmit state machine is dynamically switched on/off
+ */
+
+static irqreturn_t arc_serial_isr(int irq, void *dev_id)
+{
+	struct arc_uart_port *uart = dev_id;
+	unsigned int status;
+
+	status = UART_GET_STATUS(uart);
+
+	/*
+	 * Single IRQ for both Rx (data available) Tx (room available) Interrupt
+	 * notifications from the UART Controller.
+	 * To demultiplex between the two, we check the relevant bits
+	 */
+	if ((status & RXIENB) && !(status & RXEMPTY)) {
+
+		/* already in ISR, no need of xx_irqsave */
+		spin_lock(&uart->port.lock);
+		arc_serial_rx_chars(uart);
+		spin_unlock(&uart->port.lock);
+	}
+
+	if ((status & TXIENB) && (status & TXEMPTY)) {
+
+		/* Unconditionally disable further Tx-Interrupts.
+		 * will be enabled by tx_chars() if needed.
+		 */
+		UART_TX_IRQ_DISABLE(uart);
+
+		spin_lock(&uart->port.lock);
+
+		if (!uart_tx_stopped(&uart->port))
+			arc_serial_tx_chars(uart);
+
+		spin_unlock(&uart->port.lock);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int arc_serial_get_mctrl(struct uart_port *port)
+{
+	/*
+	 * Pretend we have a Modem status reg and following bits are
+	 *  always set, to satify the serial core state machine
+	 *  (DSR) Data Set Ready
+	 *  (CTS) Clear To Send
+	 *  (CAR) Carrier Detect
+	 */
+	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void arc_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* MCR not present */
+}
+
+/* Enable Modem Status Interrupts */
+
+static void arc_serial_enable_ms(struct uart_port *port)
+{
+	/* MSR not present */
+}
+
+static void arc_serial_break_ctl(struct uart_port *port, int break_state)
+{
+	/* ARC UART doesn't support sending Break signal */
+}
+
+static int arc_serial_startup(struct uart_port *port)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+
+	/* Before we hook up the ISR, Disable all UART Interrupts */
+	UART_ALL_IRQ_DISABLE(uart);
+
+	if (request_irq(uart->port.irq, arc_serial_isr, 0, "arc uart rx-tx",
+			uart)) {
+		dev_warn(uart->port.dev, "Unable to attach ARC UART intr\n");
+		return -EBUSY;
+	}
+
+	UART_RX_IRQ_ENABLE(uart); /* Only Rx IRQ enabled to begin with */
+
+	return 0;
+}
+
+/* This is not really needed */
+static void arc_serial_shutdown(struct uart_port *port)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+	free_irq(uart->port.irq, uart);
+}
+
+static void
+arc_serial_set_termios(struct uart_port *port, struct ktermios *new,
+		       struct ktermios *old)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+	unsigned int baud, uartl, uarth, hw_val;
+	unsigned long flags;
+
+	/*
+	 * Use the generic handler so that any specially encoded baud rates
+	 * such as SPD_xx flags or "%B0" can be handled
+	 * Max Baud I suppose will not be more than current 115K * 4
+	 * Formula for ARC UART is: hw-val = ((CLK/(BAUD*4)) -1)
+	 * spread over two 8-bit registers
+	 */
+	baud = uart_get_baud_rate(port, new, old, 0, 460800);
+
+	hw_val = port->uartclk / (uart->baud * 4) - 1;
+	uartl = hw_val & 0xFF;
+	uarth = (hw_val >> 8) & 0xFF;
+
+	/*
+	 * UART ISS(Instruction Set simulator) emulation has a subtle bug:
+	 * A existing value of Baudh = 0 is used as a indication to startup
+	 * it's internal state machine.
+	 * Thus if baudh is set to 0, 2 times, it chokes.
+	 * This happens with BAUD=115200 and the formaula above
+	 * Until that is fixed, when running on ISS, we will set baudh to !0
+	 */
+	if (uart->is_emulated)
+		uarth = 1;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	UART_ALL_IRQ_DISABLE(uart);
+
+	UART_SET_BAUDL(uart, uartl);
+	UART_SET_BAUDH(uart, uarth);
+
+	UART_RX_IRQ_ENABLE(uart);
+
+	/*
+	 * UART doesn't support Parity/Hardware Flow Control;
+	 * Only supports 8N1 character size
+	 */
+	new->c_cflag &= ~(CMSPAR|CRTSCTS|CSIZE);
+	new->c_cflag |= CS8;
+
+	if (old)
+		tty_termios_copy_hw(new, old);
+
+	/* Don't rewrite B0 */
+	if (tty_termios_baud_rate(new))
+		tty_termios_encode_baud_rate(new, baud, baud);
+
+	uart_update_timeout(port, new->c_cflag, baud);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *arc_serial_type(struct uart_port *port)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+
+	return uart->port.type == PORT_ARC ? DRIVER_NAME : NULL;
+}
+
+static void arc_serial_release_port(struct uart_port *port)
+{
+}
+
+static int arc_serial_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int
+arc_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	if (port->type != PORT_UNKNOWN && ser->type != PORT_ARC)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void arc_serial_config_port(struct uart_port *port, int flags)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+
+	if (flags & UART_CONFIG_TYPE)
+		uart->port.type = PORT_ARC;
+}
+
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE)
+
+static void arc_serial_poll_putchar(struct uart_port *port, unsigned char chr)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+
+	while (!(UART_GET_STATUS(uart) & TXEMPTY))
+		cpu_relax();
+
+	UART_SET_DATA(uart, chr);
+}
+#endif
+
+#ifdef CONFIG_CONSOLE_POLL
+static int arc_serial_poll_getchar(struct uart_port *port)
+{
+	struct arc_uart_port *uart = to_arc_port(port);
+	unsigned char chr;
+
+	while (!(UART_GET_STATUS(uart) & RXEMPTY))
+		cpu_relax();
+
+	chr = UART_GET_DATA(uart);
+	return chr;
+}
+#endif
+
+static struct uart_ops arc_serial_pops = {
+	.tx_empty	= arc_serial_tx_empty,
+	.set_mctrl	= arc_serial_set_mctrl,
+	.get_mctrl	= arc_serial_get_mctrl,
+	.stop_tx	= arc_serial_stop_tx,
+	.start_tx	= arc_serial_start_tx,
+	.stop_rx	= arc_serial_stop_rx,
+	.enable_ms	= arc_serial_enable_ms,
+	.break_ctl	= arc_serial_break_ctl,
+	.startup	= arc_serial_startup,
+	.shutdown	= arc_serial_shutdown,
+	.set_termios	= arc_serial_set_termios,
+	.type		= arc_serial_type,
+	.release_port	= arc_serial_release_port,
+	.request_port	= arc_serial_request_port,
+	.config_port	= arc_serial_config_port,
+	.verify_port	= arc_serial_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_put_char = arc_serial_poll_putchar,
+	.poll_get_char = arc_serial_poll_getchar,
+#endif
+};
+
+static int
+arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart)
+{
+	struct resource *res, *res2;
+	unsigned long *plat_data;
+
+	if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_ARC_NR_PORTS) {
+		dev_err(&pdev->dev, "Wrong uart platform device id.\n");
+		return -ENOENT;
+	}
+
+	plat_data = ((unsigned long *)(pdev->dev.platform_data));
+	uart->baud = plat_data[0];
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res2)
+		return -ENODEV;
+
+	uart->port.mapbase = res->start;
+	uart->port.membase = ioremap_nocache(res->start, resource_size(res));
+	if (!uart->port.membase)
+		/* No point of dev_err since UART itself is hosed here */
+		return -ENXIO;
+
+	uart->port.irq = res2->start;
+	uart->port.dev = &pdev->dev;
+	uart->port.iotype = UPIO_MEM;
+	uart->port.flags = UPF_BOOT_AUTOCONF;
+	uart->port.line = pdev->id;
+	uart->port.ops = &arc_serial_pops;
+
+	uart->port.uartclk = plat_data[1];
+	uart->port.fifosize = ARC_UART_TX_FIFO_SIZE;
+
+	/*
+	 * uart_insert_char( ) uses it in decideding whether to ignore a
+	 * char or not. Explicitly setting it here, removes the subtelty
+	 */
+	uart->port.ignore_status_mask = 0;
+
+	/* Real Hardware vs. emulated to work around a bug */
+	uart->is_emulated = !!plat_data[2];
+
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_ARC_CONSOLE
+
+static int arc_serial_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index < 0 || co->index >= CONFIG_SERIAL_ARC_NR_PORTS)
+		return -ENODEV;
+
+	/*
+	 * The uart port backing the console (e.g. ttyARC1) might not have been
+	 * init yet. If so, defer the console setup to after the port.
+	 */
+	port = &arc_uart_ports[co->index].port;
+	if (!port->membase)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	/*
+	 * Serial core will call port->ops->set_termios( )
+	 * which will set the baud reg
+	 */
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static void arc_serial_console_putchar(struct uart_port *port, int ch)
+{
+	arc_serial_poll_putchar(port, (unsigned char)ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void arc_serial_console_write(struct console *co, const char *s,
+				     unsigned int count)
+{
+	struct uart_port *port = &arc_uart_ports[co->index].port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	uart_console_write(port, s, count, arc_serial_console_putchar);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static struct console arc_console = {
+	.name	= ARC_SERIAL_DEV_NAME,
+	.write	= arc_serial_console_write,
+	.device	= uart_console_device,
+	.setup	= arc_serial_console_setup,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
+	.data	= &arc_uart_driver
+};
+
+static __init void early_serial_write(struct console *con, const char *s,
+					unsigned int n)
+{
+	struct uart_port *port = &arc_uart_ports[con->index].port;
+	unsigned int i;
+
+	for (i = 0; i < n; i++, s++) {
+		if (*s == '\n')
+			arc_serial_poll_putchar(port, '\r');
+		arc_serial_poll_putchar(port, *s);
+	}
+}
+
+static struct __initdata console arc_early_serial_console = {
+	.name = "early_ARCuart",
+	.write = early_serial_write,
+	.flags = CON_PRINTBUFFER | CON_BOOT,
+	.index = -1
+};
+
+static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
+{
+	arc_early_serial_console.index = pdev->id;
+
+	arc_uart_init_one(pdev, &arc_uart_ports[pdev->id]);
+
+	arc_serial_console_setup(&arc_early_serial_console, NULL);
+
+	register_console(&arc_early_serial_console);
+	return 0;
+}
+#else
+static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
+{
+	return -ENODEV;
+}
+#endif	/* CONFIG_SERIAL_ARC_CONSOLE */
+
+static int arc_serial_probe(struct platform_device *pdev)
+{
+	struct arc_uart_port *uart;
+	int rc;
+
+	if (is_early_platform_device(pdev))
+		return arc_serial_probe_earlyprintk(pdev);
+
+	uart = &arc_uart_ports[pdev->id];
+	rc = arc_uart_init_one(pdev, uart);
+	if (rc)
+		return rc;
+
+	return uart_add_one_port(&arc_uart_driver, &uart->port);
+}
+
+static int arc_serial_remove(struct platform_device *pdev)
+{
+	/* This will never be called */
+	return 0;
+}
+
+static struct platform_driver arc_platform_driver = {
+	.probe = arc_serial_probe,
+	.remove = arc_serial_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	 },
+};
+
+#ifdef CONFIG_SERIAL_ARC_CONSOLE
+/*
+ * Register an early platform driver of "earlyprintk" class.
+ * ARCH platform code installs the driver and probes the early devices
+ * The installation could rely on user specifying earlyprintk=xyx in cmd line
+ * or it could be done independently, for all "earlyprintk" class drivers.
+ * [see arch/arc/plat-arcfpga/platform.c]
+ */
+early_platform_init("earlyprintk", &arc_platform_driver);
+
+#endif  /* CONFIG_SERIAL_ARC_CONSOLE */
+
+static int __init arc_serial_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&arc_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&arc_platform_driver);
+	if (ret)
+		uart_unregister_driver(&arc_uart_driver);
+
+	return ret;
+}
+
+static void __exit arc_serial_exit(void)
+{
+	platform_driver_unregister(&arc_platform_driver);
+	uart_unregister_driver(&arc_uart_driver);
+}
+
+module_init(arc_serial_init);
+module_exit(arc_serial_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("plat-arcfpga/uart");
+MODULE_AUTHOR("Vineet Gupta");
+MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver");

+ 5 - 5
drivers/tty/serial/atmel_serial.c

@@ -1424,7 +1424,7 @@ static struct uart_ops atmel_pops = {
 #endif
 };
 
-static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
+static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
 					 struct device_node *np)
 {
 	u32 rs485_delay[2];
@@ -1459,7 +1459,7 @@ static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
 /*
  * Configure the port from the platform device resource info.
  */
-static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
+static void atmel_init_port(struct atmel_uart_port *atmel_port,
 				      struct platform_device *pdev)
 {
 	struct uart_port *port = &atmel_port->uart;
@@ -1767,7 +1767,7 @@ static int atmel_serial_resume(struct platform_device *pdev)
 #define atmel_serial_resume NULL
 #endif
 
-static int __devinit atmel_serial_probe(struct platform_device *pdev)
+static int atmel_serial_probe(struct platform_device *pdev)
 {
 	struct atmel_uart_port *port;
 	struct device_node *np = pdev->dev.of_node;
@@ -1859,7 +1859,7 @@ err:
 	return ret;
 }
 
-static int __devexit atmel_serial_remove(struct platform_device *pdev)
+static int atmel_serial_remove(struct platform_device *pdev)
 {
 	struct uart_port *port = platform_get_drvdata(pdev);
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -1884,7 +1884,7 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev)
 
 static struct platform_driver atmel_serial_driver = {
 	.probe		= atmel_serial_probe,
-	.remove		= __devexit_p(atmel_serial_remove),
+	.remove		= atmel_serial_remove,
 	.suspend	= atmel_serial_suspend,
 	.resume		= atmel_serial_resume,
 	.driver		= {

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

@@ -801,7 +801,7 @@ static struct uart_driver bcm_uart_driver = {
 /*
  * platform driver probe/remove callback
  */
-static int __devinit bcm_uart_probe(struct platform_device *pdev)
+static int bcm_uart_probe(struct platform_device *pdev)
 {
 	struct resource *res_mem, *res_irq;
 	struct uart_port *port;
@@ -848,7 +848,7 @@ static int __devinit bcm_uart_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int __devexit bcm_uart_remove(struct platform_device *pdev)
+static int bcm_uart_remove(struct platform_device *pdev)
 {
 	struct uart_port *port;
 
@@ -865,7 +865,7 @@ static int __devexit bcm_uart_remove(struct platform_device *pdev)
  */
 static struct platform_driver bcm_uart_platform_driver = {
 	.probe	= bcm_uart_probe,
-	.remove	= __devexit_p(bcm_uart_remove),
+	.remove	= bcm_uart_remove,
 	.driver	= {
 		.owner = THIS_MODULE,
 		.name  = "bcm63xx_uart",

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

@@ -740,7 +740,7 @@ static struct dev_pm_ops bfin_sport_uart_dev_pm_ops = {
 };
 #endif
 
-static int __devinit sport_uart_probe(struct platform_device *pdev)
+static int sport_uart_probe(struct platform_device *pdev)
 {
 	struct resource *res;
 	struct sport_uart_port *sport;
@@ -850,7 +850,7 @@ out_error_free_mem:
 	return ret;
 }
 
-static int __devexit sport_uart_remove(struct platform_device *pdev)
+static int sport_uart_remove(struct platform_device *pdev)
 {
 	struct sport_uart_port *sport = platform_get_drvdata(pdev);
 
@@ -871,7 +871,7 @@ static int __devexit sport_uart_remove(struct platform_device *pdev)
 
 static struct platform_driver sport_uart_driver = {
 	.probe		= sport_uart_probe,
-	.remove		= __devexit_p(sport_uart_remove),
+	.remove		= sport_uart_remove,
 	.driver		= {
 		.name	= DRV_NAME,
 #ifdef CONFIG_PM

+ 14 - 6
drivers/tty/serial/bfin_uart.c

@@ -477,9 +477,9 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
 void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
 {
 	int x_pos, pos;
+	unsigned long flags;
 
-	dma_disable_irq_nosync(uart->rx_dma_channel);
-	spin_lock_bh(&uart->rx_lock);
+	spin_lock_irqsave(&uart->rx_lock, flags);
 
 	/* 2D DMA RX buffer ring is used. Because curr_y_count and
 	 * curr_x_count can't be read as an atomic operation,
@@ -510,8 +510,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
 		uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
 	}
 
-	spin_unlock_bh(&uart->rx_lock);
-	dma_enable_irq(uart->rx_dma_channel);
+	spin_unlock_irqrestore(&uart->rx_lock, flags);
 
 	mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
 }
@@ -800,6 +799,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
 	unsigned long flags;
 	unsigned int baud, quot;
 	unsigned int ier, lcr = 0;
+	unsigned long timeout;
 
 	switch (termios->c_cflag & CSIZE) {
 	case CS8:
@@ -869,6 +869,14 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
 
 	UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
 
+	/* Wait till the transfer buffer is empty */
+	timeout = jiffies + msecs_to_jiffies(10);
+	while (UART_GET_GCTL(uart) & UCEN && !(UART_GET_LSR(uart) & TEMT))
+		if (time_after(jiffies, timeout)) {
+			dev_warn(port->dev, "timeout waiting for TX buffer empty\n");
+			break;
+		}
+
 	/* Disable UART */
 	ier = UART_GET_IER(uart);
 	UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN);
@@ -1390,7 +1398,7 @@ out_error_free_mem:
 	return ret;
 }
 
-static int __devexit bfin_serial_remove(struct platform_device *pdev)
+static int bfin_serial_remove(struct platform_device *pdev)
 {
 	struct bfin_serial_port *uart = platform_get_drvdata(pdev);
 
@@ -1410,7 +1418,7 @@ static int __devexit bfin_serial_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_serial_driver = {
 	.probe		= bfin_serial_probe,
-	.remove		= __devexit_p(bfin_serial_remove),
+	.remove		= bfin_serial_remove,
 	.suspend	= bfin_serial_suspend,
 	.resume		= bfin_serial_resume,
 	.driver		= {

+ 277 - 318
drivers/tty/serial/clps711x.c

@@ -10,15 +10,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -26,172 +17,169 @@
 #endif
 
 #include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/spinlock.h>
 #include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
+#include <linux/console.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
 #include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
 
 #include <mach/hardware.h>
-#include <asm/irq.h>
-
-#define UART_NR		2
-
-#define SERIAL_CLPS711X_MAJOR	204
-#define SERIAL_CLPS711X_MINOR	40
-#define SERIAL_CLPS711X_NR	UART_NR
-
-/*
- * We use the relevant SYSCON register as a base address for these ports.
- */
-#define UBRLCR(port)		((port)->iobase + UBRLCR1 - SYSCON1)
-#define UARTDR(port)		((port)->iobase + UARTDR1 - SYSCON1)
-#define SYSFLG(port)		((port)->iobase + SYSFLG1 - SYSCON1)
-#define SYSCON(port)		((port)->iobase + SYSCON1 - SYSCON1)
-
-#define TX_IRQ(port)		((port)->irq)
-#define RX_IRQ(port)		((port)->irq + 1)
 
-#define UART_ANY_ERR		(UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
-
-#define tx_enabled(port)	((port)->unused[0])
+#define UART_CLPS711X_NAME	"uart-clps711x"
+#define UART_CLPS711X_NR	2
+#define UART_CLPS711X_MAJOR	204
+#define UART_CLPS711X_MINOR	40
+
+#define UBRLCR(port)		((port)->line ? UBRLCR2 : UBRLCR1)
+#define UARTDR(port)		((port)->line ? UARTDR2 : UARTDR1)
+#define SYSFLG(port)		((port)->line ? SYSFLG2 : SYSFLG1)
+#define SYSCON(port)		((port)->line ? SYSCON2 : SYSCON1)
+#define TX_IRQ(port)		((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1)
+#define RX_IRQ(port)		((port)->line ? IRQ_URXINT2 : IRQ_URXINT1)
+
+struct clps711x_port {
+	struct uart_driver	uart;
+	struct clk		*uart_clk;
+	struct uart_port	port[UART_CLPS711X_NR];
+	int			tx_enabled[UART_CLPS711X_NR];
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+	struct console		console;
+#endif
+};
 
-static void clps711xuart_stop_tx(struct uart_port *port)
+static void uart_clps711x_stop_tx(struct uart_port *port)
 {
-	if (tx_enabled(port)) {
+	struct clps711x_port *s = dev_get_drvdata(port->dev);
+
+	if (s->tx_enabled[port->line]) {
 		disable_irq(TX_IRQ(port));
-		tx_enabled(port) = 0;
+		s->tx_enabled[port->line] = 0;
 	}
 }
 
-static void clps711xuart_start_tx(struct uart_port *port)
+static void uart_clps711x_start_tx(struct uart_port *port)
 {
-	if (!tx_enabled(port)) {
+	struct clps711x_port *s = dev_get_drvdata(port->dev);
+
+	if (!s->tx_enabled[port->line]) {
 		enable_irq(TX_IRQ(port));
-		tx_enabled(port) = 1;
+		s->tx_enabled[port->line] = 1;
 	}
 }
 
-static void clps711xuart_stop_rx(struct uart_port *port)
+static void uart_clps711x_stop_rx(struct uart_port *port)
 {
 	disable_irq(RX_IRQ(port));
 }
 
-static void clps711xuart_enable_ms(struct uart_port *port)
+static void uart_clps711x_enable_ms(struct uart_port *port)
 {
+	/* Do nothing */
 }
 
-static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
+static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)
 {
 	struct uart_port *port = dev_id;
-	struct tty_struct *tty = port->state->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
 	unsigned int status, ch, flg;
 
-	status = clps_readl(SYSFLG(port));
-	while (!(status & SYSFLG_URXFE)) {
-		ch = clps_readl(UARTDR(port));
+	if (!tty)
+		return IRQ_HANDLED;
 
-		port->icount.rx++;
+	for (;;) {
+		status = clps_readl(SYSFLG(port));
+		if (status & SYSFLG_URXFE)
+			break;
+
+		ch = clps_readw(UARTDR(port));
+		status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR);
+		ch &= 0xff;
 
+		port->icount.rx++;
 		flg = TTY_NORMAL;
 
-		/*
-		 * Note that the error handling code is
-		 * out of the main execution path
-		 */
-		if (unlikely(ch & UART_ANY_ERR)) {
-			if (ch & UARTDR_PARERR)
+		if (unlikely(status)) {
+			if (status & UARTDR_PARERR)
 				port->icount.parity++;
-			else if (ch & UARTDR_FRMERR)
+			else if (status & UARTDR_FRMERR)
 				port->icount.frame++;
-			if (ch & UARTDR_OVERR)
+			else if (status & UARTDR_OVERR)
 				port->icount.overrun++;
 
-			ch &= port->read_status_mask;
+			status &= port->read_status_mask;
 
-			if (ch & UARTDR_PARERR)
+			if (status & UARTDR_PARERR)
 				flg = TTY_PARITY;
-			else if (ch & UARTDR_FRMERR)
+			else if (status & UARTDR_FRMERR)
 				flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
-			port->sysrq = 0;
-#endif
+			else if (status & UARTDR_OVERR)
+				flg = TTY_OVERRUN;
 		}
 
 		if (uart_handle_sysrq_char(port, ch))
-			goto ignore_char;
+			continue;
 
-		/*
-		 * CHECK: does overrun affect the current character?
-		 * ASSUMPTION: it does not.
-		 */
-		uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
+		if (status & port->ignore_status_mask)
+			continue;
 
-	ignore_char:
-		status = clps_readl(SYSFLG(port));
+		uart_insert_char(port, status, UARTDR_OVERR, ch, flg);
 	}
+
 	tty_flip_buffer_push(tty);
+
+	tty_kref_put(tty);
+
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
+static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
 {
 	struct uart_port *port = dev_id;
+	struct clps711x_port *s = dev_get_drvdata(port->dev);
 	struct circ_buf *xmit = &port->state->xmit;
-	int count;
 
 	if (port->x_char) {
-		clps_writel(port->x_char, UARTDR(port));
+		clps_writew(port->x_char, UARTDR(port));
 		port->icount.tx++;
 		port->x_char = 0;
 		return IRQ_HANDLED;
 	}
 
-	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
-		goto disable_tx_irq;
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		disable_irq_nosync(TX_IRQ(port));
+		s->tx_enabled[port->line] = 0;
+		return IRQ_HANDLED;
+	}
 
-	count = port->fifosize >> 1;
-	do {
-		clps_writel(xmit->buf[xmit->tail], UARTDR(port));
+	while (!uart_circ_empty(xmit)) {
+		clps_writew(xmit->buf[xmit->tail], UARTDR(port));
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		port->icount.tx++;
-		if (uart_circ_empty(xmit))
+		if (clps_readl(SYSFLG(port) & SYSFLG_UTXFF))
 			break;
-	} while (--count > 0);
+	}
 
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(port);
 
-	if (uart_circ_empty(xmit)) {
-	disable_tx_irq:
-		disable_irq_nosync(TX_IRQ(port));
-		tx_enabled(port) = 0;
-	}
-
 	return IRQ_HANDLED;
 }
 
-static unsigned int clps711xuart_tx_empty(struct uart_port *port)
+static unsigned int uart_clps711x_tx_empty(struct uart_port *port)
 {
-	unsigned int status = clps_readl(SYSFLG(port));
-	return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
+	return (clps_readl(SYSFLG(port) & SYSFLG_UBUSY)) ? 0 : TIOCSER_TEMT;
 }
 
-static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
+static unsigned int uart_clps711x_get_mctrl(struct uart_port *port)
 {
-	unsigned int port_addr;
-	unsigned int result = 0;
-	unsigned int status;
+	unsigned int status, result = 0;
 
-	port_addr = SYSFLG(port);
-	if (port_addr == SYSFLG1) {
+	if (port->line == 0) {
 		status = clps_readl(SYSFLG1);
 		if (status & SYSFLG1_DCD)
 			result |= TIOCM_CAR;
@@ -199,104 +187,86 @@ static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
 			result |= TIOCM_DSR;
 		if (status & SYSFLG1_CTS)
 			result |= TIOCM_CTS;
-	}
+	} else
+		result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
 
 	return result;
 }
 
-static void
-clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
+static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
+	/* Do nothing */
 }
 
-static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
+static void uart_clps711x_break_ctl(struct uart_port *port, int break_state)
 {
 	unsigned long flags;
 	unsigned int ubrlcr;
 
 	spin_lock_irqsave(&port->lock, flags);
+
 	ubrlcr = clps_readl(UBRLCR(port));
-	if (break_state == -1)
+	if (break_state)
 		ubrlcr |= UBRLCR_BREAK;
 	else
 		ubrlcr &= ~UBRLCR_BREAK;
 	clps_writel(ubrlcr, UBRLCR(port));
+
 	spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static int clps711xuart_startup(struct uart_port *port)
+static int uart_clps711x_startup(struct uart_port *port)
 {
-	unsigned int syscon;
-	int retval;
-
-	tx_enabled(port) = 1;
-
-	/*
-	 * Allocate the IRQs
-	 */
-	retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
-			     "clps711xuart_tx", port);
-	if (retval)
-		return retval;
-
-	retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
-			     "clps711xuart_rx", port);
-	if (retval) {
-		free_irq(TX_IRQ(port), port);
-		return retval;
+	struct clps711x_port *s = dev_get_drvdata(port->dev);
+	int ret;
+
+	s->tx_enabled[port->line] = 1;
+	/* Allocate the IRQs */
+	ret = devm_request_irq(port->dev, TX_IRQ(port), uart_clps711x_int_tx,
+			       0, UART_CLPS711X_NAME " TX", port);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(port->dev, RX_IRQ(port), uart_clps711x_int_rx,
+			       0, UART_CLPS711X_NAME " RX", port);
+	if (ret) {
+		devm_free_irq(port->dev, TX_IRQ(port), port);
+		return ret;
 	}
 
-	/*
-	 * enable the port
-	 */
-	syscon = clps_readl(SYSCON(port));
-	syscon |= SYSCON_UARTEN;
-	clps_writel(syscon, SYSCON(port));
+	/* Disable break */
+	clps_writel(clps_readl(UBRLCR(port)) & ~UBRLCR_BREAK, UBRLCR(port));
+
+	/* Enable the port */
+	clps_writel(clps_readl(SYSCON(port)) | SYSCON_UARTEN, SYSCON(port));
 
 	return 0;
 }
 
-static void clps711xuart_shutdown(struct uart_port *port)
+static void uart_clps711x_shutdown(struct uart_port *port)
 {
-	unsigned int ubrlcr, syscon;
+	/* Free the interrupts */
+	devm_free_irq(port->dev, TX_IRQ(port), port);
+	devm_free_irq(port->dev, RX_IRQ(port), port);
 
-	/*
-	 * Free the interrupt
-	 */
-	free_irq(TX_IRQ(port), port);	/* TX interrupt */
-	free_irq(RX_IRQ(port), port);	/* RX interrupt */
-
-	/*
-	 * disable the port
-	 */
-	syscon = clps_readl(SYSCON(port));
-	syscon &= ~SYSCON_UARTEN;
-	clps_writel(syscon, SYSCON(port));
-
-	/*
-	 * disable break condition and fifos
-	 */
-	ubrlcr = clps_readl(UBRLCR(port));
-	ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
-	clps_writel(ubrlcr, UBRLCR(port));
+	/* Disable the port */
+	clps_writel(clps_readl(SYSCON(port)) & ~SYSCON_UARTEN, SYSCON(port));
 }
 
-static void
-clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
-			 struct ktermios *old)
+static void uart_clps711x_set_termios(struct uart_port *port,
+				      struct ktermios *termios,
+				      struct ktermios *old)
 {
 	unsigned int ubrlcr, baud, quot;
 	unsigned long flags;
 
-	/*
-	 * We don't implement CREAD.
-	 */
-	termios->c_cflag |= CREAD;
+	/* Mask termios capabilities we don't support */
+	termios->c_cflag &= ~CMSPAR;
+	termios->c_iflag &= ~(BRKINT | IGNBRK);
 
-	/*
-	 * Ask the core to calculate the divisor for us.
-	 */
-	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+	/* Ask the core to calculate the divisor for us */
+	baud = uart_get_baud_rate(port, termios, old, port->uartclk / 4096,
+						      port->uartclk / 16);
 	quot = uart_get_divisor(port, baud);
 
 	switch (termios->c_cflag & CSIZE) {
@@ -309,160 +279,117 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
 	case CS7:
 		ubrlcr = UBRLCR_WRDLEN7;
 		break;
-	default: // CS8
+	case CS8:
+	default:
 		ubrlcr = UBRLCR_WRDLEN8;
 		break;
 	}
+
 	if (termios->c_cflag & CSTOPB)
 		ubrlcr |= UBRLCR_XSTOP;
+
 	if (termios->c_cflag & PARENB) {
 		ubrlcr |= UBRLCR_PRTEN;
 		if (!(termios->c_cflag & PARODD))
 			ubrlcr |= UBRLCR_EVENPRT;
 	}
-	if (port->fifosize > 1)
-		ubrlcr |= UBRLCR_FIFOEN;
 
-	spin_lock_irqsave(&port->lock, flags);
+	/* Enable FIFO */
+	ubrlcr |= UBRLCR_FIFOEN;
 
-	/*
-	 * Update the per-port timeout.
-	 */
-	uart_update_timeout(port, termios->c_cflag, baud);
+	spin_lock_irqsave(&port->lock, flags);
 
+	/* Set read status mask */
 	port->read_status_mask = UARTDR_OVERR;
 	if (termios->c_iflag & INPCK)
 		port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
 
-	/*
-	 * Characters to ignore
-	 */
+	/* Set status ignore mask */
 	port->ignore_status_mask = 0;
-	if (termios->c_iflag & IGNPAR)
-		port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
-	if (termios->c_iflag & IGNBRK) {
-		/*
-		 * If we're ignoring parity and break indicators,
-		 * ignore overruns to (for real raw support).
-		 */
-		if (termios->c_iflag & IGNPAR)
-			port->ignore_status_mask |= UARTDR_OVERR;
-	}
+	if (!(termios->c_cflag & CREAD))
+		port->ignore_status_mask |= UARTDR_OVERR | UARTDR_PARERR |
+					    UARTDR_FRMERR;
 
-	quot -= 1;
+	uart_update_timeout(port, termios->c_cflag, baud);
 
-	clps_writel(ubrlcr | quot, UBRLCR(port));
+	clps_writel(ubrlcr | (quot - 1), UBRLCR(port));
 
 	spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static const char *clps711xuart_type(struct uart_port *port)
+static const char *uart_clps711x_type(struct uart_port *port)
 {
-	return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
+	return (port->type == PORT_CLPS711X) ? "CLPS711X" : NULL;
 }
 
-/*
- * Configure/autoconfigure the port.
- */
-static void clps711xuart_config_port(struct uart_port *port, int flags)
+static void uart_clps711x_config_port(struct uart_port *port, int flags)
 {
 	if (flags & UART_CONFIG_TYPE)
 		port->type = PORT_CLPS711X;
 }
 
-static void clps711xuart_release_port(struct uart_port *port)
+static void uart_clps711x_release_port(struct uart_port *port)
 {
+	/* Do nothing */
 }
 
-static int clps711xuart_request_port(struct uart_port *port)
+static int uart_clps711x_request_port(struct uart_port *port)
 {
+	/* Do nothing */
 	return 0;
 }
 
-static struct uart_ops clps711x_pops = {
-	.tx_empty	= clps711xuart_tx_empty,
-	.set_mctrl	= clps711xuart_set_mctrl_null,
-	.get_mctrl	= clps711xuart_get_mctrl,
-	.stop_tx	= clps711xuart_stop_tx,
-	.start_tx	= clps711xuart_start_tx,
-	.stop_rx	= clps711xuart_stop_rx,
-	.enable_ms	= clps711xuart_enable_ms,
-	.break_ctl	= clps711xuart_break_ctl,
-	.startup	= clps711xuart_startup,
-	.shutdown	= clps711xuart_shutdown,
-	.set_termios	= clps711xuart_set_termios,
-	.type		= clps711xuart_type,
-	.config_port	= clps711xuart_config_port,
-	.release_port	= clps711xuart_release_port,
-	.request_port	= clps711xuart_request_port,
-};
-
-static struct uart_port clps711x_ports[UART_NR] = {
-	{
-		.iobase		= SYSCON1,
-		.irq		= IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
-		.uartclk	= 3686400,
-		.fifosize	= 16,
-		.ops		= &clps711x_pops,
-		.line		= 0,
-		.flags		= UPF_BOOT_AUTOCONF,
-	},
-	{
-		.iobase		= SYSCON2,
-		.irq		= IRQ_UTXINT2, /* IRQ_URXINT2 */
-		.uartclk	= 3686400,
-		.fifosize	= 16,
-		.ops		= &clps711x_pops,
-		.line		= 1,
-		.flags		= UPF_BOOT_AUTOCONF,
-	}
+static const struct uart_ops uart_clps711x_ops = {
+	.tx_empty	= uart_clps711x_tx_empty,
+	.set_mctrl	= uart_clps711x_set_mctrl,
+	.get_mctrl	= uart_clps711x_get_mctrl,
+	.stop_tx	= uart_clps711x_stop_tx,
+	.start_tx	= uart_clps711x_start_tx,
+	.stop_rx	= uart_clps711x_stop_rx,
+	.enable_ms	= uart_clps711x_enable_ms,
+	.break_ctl	= uart_clps711x_break_ctl,
+	.startup	= uart_clps711x_startup,
+	.shutdown	= uart_clps711x_shutdown,
+	.set_termios	= uart_clps711x_set_termios,
+	.type		= uart_clps711x_type,
+	.config_port	= uart_clps711x_config_port,
+	.release_port	= uart_clps711x_release_port,
+	.request_port	= uart_clps711x_request_port,
 };
 
 #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
-static void clps711xuart_console_putchar(struct uart_port *port, int ch)
+static void uart_clps711x_console_putchar(struct uart_port *port, int ch)
 {
 	while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
 		barrier();
-	clps_writel(ch, UARTDR(port));
+
+	clps_writew(ch, UARTDR(port));
 }
 
-/*
- *	Print a string to the serial port trying not to disturb
- *	any possible real use of the port...
- *
- *	The console_lock must be held when we get here.
- *
- *	Note that this is called with interrupts already disabled
- */
-static void
-clps711xuart_console_write(struct console *co, const char *s,
-			   unsigned int count)
+static void uart_clps711x_console_write(struct console *co, const char *c,
+					unsigned n)
 {
-	struct uart_port *port = clps711x_ports + co->index;
-	unsigned int status, syscon;
+	struct clps711x_port *s = (struct clps711x_port *)co->data;
+	struct uart_port *port = &s->port[co->index];
+	u32 syscon;
 
-	/*
-	 *	Ensure that the port is enabled.
-	 */
+	/* Ensure that the port is enabled */
 	syscon = clps_readl(SYSCON(port));
 	clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
 
-	uart_console_write(port, s, count, clps711xuart_console_putchar);
+	uart_console_write(port, c, n, uart_clps711x_console_putchar);
 
-	/*
-	 *	Finally, wait for transmitter to become empty
-	 *	and restore the uart state.
-	 */
-	do {
-		status = clps_readl(SYSFLG(port));
-	} while (status & SYSFLG_UBUSY);
+	/* Wait for transmitter to become empty */
+	while (clps_readl(SYSFLG(port)) & SYSFLG_UBUSY)
+		barrier();
 
+	/* Restore the uart state */
 	clps_writel(syscon, SYSCON(port));
 }
 
-static void __init
-clps711xuart_console_get_options(struct uart_port *port, int *baud,
-				 int *parity, int *bits)
+static void uart_clps711x_console_get_options(struct uart_port *port,
+					      int *baud, int *parity,
+					      int *bits)
 {
 	if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
 		unsigned int ubrlcr, quot;
@@ -487,92 +414,124 @@ clps711xuart_console_get_options(struct uart_port *port, int *baud,
 	}
 }
 
-static int __init clps711xuart_console_setup(struct console *co, char *options)
+static int uart_clps711x_console_setup(struct console *co, char *options)
 {
-	struct uart_port *port;
-	int baud = 38400;
-	int bits = 8;
-	int parity = 'n';
-	int flow = 'n';
-
-	/*
-	 * Check whether an invalid uart number has been specified, and
-	 * if so, search for the first available port that does have
-	 * console support.
-	 */
-	port = uart_get_console(clps711x_ports, UART_NR, co);
+	int baud = 38400, bits = 8, parity = 'n', flow = 'n';
+	struct clps711x_port *s = (struct clps711x_port *)co->data;
+	struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0];
 
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 	else
-		clps711xuart_console_get_options(port, &baud, &parity, &bits);
+		uart_clps711x_console_get_options(port, &baud, &parity, &bits);
 
 	return uart_set_options(port, co, baud, parity, bits, flow);
 }
+#endif
 
-static struct uart_driver clps711x_reg;
-static struct console clps711x_console = {
-	.name		= "ttyCL",
-	.write		= clps711xuart_console_write,
-	.device		= uart_console_device,
-	.setup		= clps711xuart_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &clps711x_reg,
-};
-
-static int __init clps711xuart_console_init(void)
+static int uart_clps711x_probe(struct platform_device *pdev)
 {
-	register_console(&clps711x_console);
-	return 0;
-}
-console_initcall(clps711xuart_console_init);
+	struct clps711x_port *s;
+	int ret, i;
+
+	s = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_port), GFP_KERNEL);
+	if (!s) {
+		dev_err(&pdev->dev, "Error allocating port structure\n");
+		return -ENOMEM;
+	}
+	platform_set_drvdata(pdev, s);
 
-#define CLPS711X_CONSOLE	&clps711x_console
-#else
-#define CLPS711X_CONSOLE	NULL
+	s->uart_clk = devm_clk_get(&pdev->dev, "uart");
+	if (IS_ERR(s->uart_clk)) {
+		dev_err(&pdev->dev, "Can't get UART clocks\n");
+		ret = PTR_ERR(s->uart_clk);
+		goto err_out;
+	}
+
+	s->uart.owner		= THIS_MODULE;
+	s->uart.dev_name	= "ttyCL";
+	s->uart.major		= UART_CLPS711X_MAJOR;
+	s->uart.minor		= UART_CLPS711X_MINOR;
+	s->uart.nr		= UART_CLPS711X_NR;
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+	s->uart.cons		= &s->console;
+	s->uart.cons->device	= uart_console_device;
+	s->uart.cons->write	= uart_clps711x_console_write;
+	s->uart.cons->setup	= uart_clps711x_console_setup;
+	s->uart.cons->flags	= CON_PRINTBUFFER;
+	s->uart.cons->index	= -1;
+	s->uart.cons->data	= s;
+	strcpy(s->uart.cons->name, "ttyCL");
 #endif
+	ret = uart_register_driver(&s->uart);
+	if (ret) {
+		dev_err(&pdev->dev, "Registering UART driver failed\n");
+		devm_clk_put(&pdev->dev, s->uart_clk);
+		goto err_out;
+	}
 
-static struct uart_driver clps711x_reg = {
-	.driver_name		= "ttyCL",
-	.dev_name		= "ttyCL",
-	.major			= SERIAL_CLPS711X_MAJOR,
-	.minor			= SERIAL_CLPS711X_MINOR,
-	.nr			= UART_NR,
+	for (i = 0; i < UART_CLPS711X_NR; i++) {
+		s->port[i].line		= i;
+		s->port[i].dev		= &pdev->dev;
+		s->port[i].irq		= TX_IRQ(&s->port[i]);
+		s->port[i].iobase	= SYSCON(&s->port[i]);
+		s->port[i].type		= PORT_CLPS711X;
+		s->port[i].fifosize	= 16;
+		s->port[i].flags	= UPF_SKIP_TEST | UPF_FIXED_TYPE;
+		s->port[i].uartclk	= clk_get_rate(s->uart_clk);
+		s->port[i].ops		= &uart_clps711x_ops;
+		WARN_ON(uart_add_one_port(&s->uart, &s->port[i]));
+	}
 
-	.cons			= CLPS711X_CONSOLE,
-};
+	return 0;
 
-static int __init clps711xuart_init(void)
-{
-	int ret, i;
+err_out:
+	platform_set_drvdata(pdev, NULL);
 
-	printk(KERN_INFO "Serial: CLPS711x driver\n");
+	return ret;
+}
 
-	ret = uart_register_driver(&clps711x_reg);
-	if (ret)
-		return ret;
+static int uart_clps711x_remove(struct platform_device *pdev)
+{
+	struct clps711x_port *s = platform_get_drvdata(pdev);
+	int i;
 
-	for (i = 0; i < UART_NR; i++)
-		uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
+	for (i = 0; i < UART_CLPS711X_NR; i++)
+		uart_remove_one_port(&s->uart, &s->port[i]);
+
+	devm_clk_put(&pdev->dev, s->uart_clk);
+	uart_unregister_driver(&s->uart);
+	platform_set_drvdata(pdev, NULL);
 
 	return 0;
 }
 
-static void __exit clps711xuart_exit(void)
-{
-	int i;
+static struct platform_driver clps711x_uart_driver = {
+	.driver = {
+		.name	= UART_CLPS711X_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe	= uart_clps711x_probe,
+	.remove	= uart_clps711x_remove,
+};
+module_platform_driver(clps711x_uart_driver);
 
-	for (i = 0; i < UART_NR; i++)
-		uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
+static struct platform_device clps711x_uart_device = {
+	.name	= UART_CLPS711X_NAME,
+};
 
-	uart_unregister_driver(&clps711x_reg);
+static int __init uart_clps711x_init(void)
+{
+	return platform_device_register(&clps711x_uart_device);
 }
+module_init(uart_clps711x_init);
 
-module_init(clps711xuart_init);
-module_exit(clps711xuart_exit);
+static void __exit uart_clps711x_exit(void)
+{
+	platform_device_unregister(&clps711x_uart_device);
+}
+module_exit(uart_clps711x_exit);
 
 MODULE_AUTHOR("Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("CLPS-711x generic serial driver");
+MODULE_DESCRIPTION("CLPS711X serial driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);

+ 2 - 2
drivers/tty/serial/cpm_uart/cpm_uart_core.c

@@ -1373,7 +1373,7 @@ static struct uart_driver cpm_reg = {
 
 static int probe_index;
 
-static int __devinit cpm_uart_probe(struct platform_device *ofdev)
+static int cpm_uart_probe(struct platform_device *ofdev)
 {
 	int index = probe_index++;
 	struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
@@ -1396,7 +1396,7 @@ static int __devinit cpm_uart_probe(struct platform_device *ofdev)
 	return uart_add_one_port(&cpm_reg, &pinfo->port);
 }
 
-static int __devexit cpm_uart_remove(struct platform_device *ofdev)
+static int cpm_uart_remove(struct platform_device *ofdev)
 {
 	struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
 	return uart_remove_one_port(&cpm_reg, &pinfo->port);

+ 3 - 3
drivers/tty/serial/efm32-uart.c

@@ -690,7 +690,7 @@ static int efm32_uart_probe_dt(struct platform_device *pdev,
 
 }
 
-static int __devinit efm32_uart_probe(struct platform_device *pdev)
+static int efm32_uart_probe(struct platform_device *pdev)
 {
 	struct efm32_uart_port *efm_port;
 	struct resource *res;
@@ -764,7 +764,7 @@ err_get_base:
 	return ret;
 }
 
-static int __devexit efm32_uart_remove(struct platform_device *pdev)
+static int efm32_uart_remove(struct platform_device *pdev)
 {
 	struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
 
@@ -791,7 +791,7 @@ 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),
+	.remove = efm32_uart_remove,
 
 	.driver = {
 		.name = DRIVER_NAME,

+ 7 - 7
drivers/tty/serial/icom.c

@@ -175,7 +175,7 @@ static void free_port_memory(struct icom_port *icom_port)
 	}
 }
 
-static int __devinit get_port_memory(struct icom_port *icom_port)
+static int get_port_memory(struct icom_port *icom_port)
 {
 	int index;
 	unsigned long stgAddr;
@@ -1314,7 +1314,7 @@ static struct uart_driver icom_uart_driver = {
 	.cons = ICOM_CONSOLE,
 };
 
-static int __devinit icom_init_ports(struct icom_adapter *icom_adapter)
+static int icom_init_ports(struct icom_adapter *icom_adapter)
 {
 	u32 subsystem_id = icom_adapter->subsystem_id;
 	int i;
@@ -1381,7 +1381,7 @@ static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *i
 			    0x8024 + 2 - 2 * (icom_port->port - 2);
 	}
 }
-static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
+static int icom_load_ports(struct icom_adapter *icom_adapter)
 {
 	struct icom_port *icom_port;
 	int port_num;
@@ -1407,7 +1407,7 @@ static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
 	return 0;
 }
 
-static int __devinit icom_alloc_adapter(struct icom_adapter
+static int icom_alloc_adapter(struct icom_adapter
 					**icom_adapter_ref)
 {
 	int adapter_count = 0;
@@ -1487,7 +1487,7 @@ static void icom_kref_release(struct kref *kref)
 	icom_remove_adapter(icom_adapter);
 }
 
-static int __devinit icom_probe(struct pci_dev *dev,
+static int icom_probe(struct pci_dev *dev,
 				const struct pci_device_id *ent)
 {
 	int index;
@@ -1596,7 +1596,7 @@ probe_exit0:
 	return retval;
 }
 
-static void __devexit icom_remove(struct pci_dev *dev)
+static void icom_remove(struct pci_dev *dev)
 {
 	struct icom_adapter *icom_adapter;
 	struct list_head *tmp;
@@ -1617,7 +1617,7 @@ static struct pci_driver icom_pci_driver = {
 	.name = ICOM_DRIVER_NAME,
 	.id_table = icom_pci_table,
 	.probe = icom_probe,
-	.remove = __devexit_p(icom_remove),
+	.remove = icom_remove,
 };
 
 static int __init icom_init(void)

+ 143 - 25
drivers/tty/serial/ifx6x60.c

@@ -60,20 +60,27 @@
 #include <linux/pm_runtime.h>
 #include <linux/spi/ifx_modem.h>
 #include <linux/delay.h>
+#include <linux/reboot.h>
 
 #include "ifx6x60.h"
 
 #define IFX_SPI_MORE_MASK		0x10
-#define IFX_SPI_MORE_BIT		12	/* bit position in u16 */
-#define IFX_SPI_CTS_BIT			13	/* bit position in u16 */
+#define IFX_SPI_MORE_BIT		4	/* bit position in u8 */
+#define IFX_SPI_CTS_BIT			6	/* bit position in u8 */
 #define IFX_SPI_MODE			SPI_MODE_1
 #define IFX_SPI_TTY_ID			0
 #define IFX_SPI_TIMEOUT_SEC		2
 #define IFX_SPI_HEADER_0		(-1)
 #define IFX_SPI_HEADER_F		(-2)
 
+#define PO_POST_DELAY		200
+#define IFX_MDM_RST_PMU	4
+
 /* forward reference */
 static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
+static int ifx_modem_reboot_callback(struct notifier_block *nfb,
+				unsigned long event, void *data);
+static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev);
 
 /* local variables */
 static int spi_bpw = 16;		/* 8, 16 or 32 bit word length */
@@ -81,6 +88,29 @@ static struct tty_driver *tty_drv;
 static struct ifx_spi_device *saved_ifx_dev;
 static struct lock_class_key ifx_spi_key;
 
+static struct notifier_block ifx_modem_reboot_notifier_block = {
+	.notifier_call = ifx_modem_reboot_callback,
+};
+
+static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev)
+{
+	gpio_set_value(IFX_MDM_RST_PMU, 1);
+	msleep(PO_POST_DELAY);
+
+	return 0;
+}
+
+static int ifx_modem_reboot_callback(struct notifier_block *nfb,
+				 unsigned long event, void *data)
+{
+	if (saved_ifx_dev)
+		ifx_modem_power_off(saved_ifx_dev);
+	else
+		pr_warn("no ifx modem active;\n");
+
+	return NOTIFY_OK;
+}
+
 /* GPIO/GPE settings */
 
 /**
@@ -152,26 +182,67 @@ ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val)
 }
 
 /**
- *	swap_buf
+ *	swap_buf_8
  *	@buf: our buffer
  *	@len : number of bytes (not words) in the buffer
  *	@end: end of buffer
  *
  *	Swap the contents of a buffer into big endian format
  */
-static inline void swap_buf(u16 *buf, int len, void *end)
+static inline void swap_buf_8(unsigned char *buf, int len, void *end)
+{
+	/* don't swap buffer if SPI word width is 8 bits */
+	return;
+}
+
+/**
+ *	swap_buf_16
+ *	@buf: our buffer
+ *	@len : number of bytes (not words) in the buffer
+ *	@end: end of buffer
+ *
+ *	Swap the contents of a buffer into big endian format
+ */
+static inline void swap_buf_16(unsigned char *buf, int len, void *end)
 {
 	int n;
 
+	u16 *buf_16 = (u16 *)buf;
 	len = ((len + 1) >> 1);
-	if ((void *)&buf[len] > end) {
-		pr_err("swap_buf: swap exceeds boundary (%p > %p)!",
-		       &buf[len], end);
+	if ((void *)&buf_16[len] > end) {
+		pr_err("swap_buf_16: swap exceeds boundary (%p > %p)!",
+		       &buf_16[len], end);
+		return;
+	}
+	for (n = 0; n < len; n++) {
+		*buf_16 = cpu_to_be16(*buf_16);
+		buf_16++;
+	}
+}
+
+/**
+ *	swap_buf_32
+ *	@buf: our buffer
+ *	@len : number of bytes (not words) in the buffer
+ *	@end: end of buffer
+ *
+ *	Swap the contents of a buffer into big endian format
+ */
+static inline void swap_buf_32(unsigned char *buf, int len, void *end)
+{
+	int n;
+
+	u32 *buf_32 = (u32 *)buf;
+	len = (len + 3) >> 2;
+
+	if ((void *)&buf_32[len] > end) {
+		pr_err("swap_buf_32: swap exceeds boundary (%p > %p)!\n",
+		       &buf_32[len], end);
 		return;
 	}
 	for (n = 0; n < len; n++) {
-		*buf = cpu_to_be16(*buf);
-		buf++;
+		*buf_32 = cpu_to_be32(*buf_32);
+		buf_32++;
 	}
 }
 
@@ -190,9 +261,7 @@ static void mrdy_assert(struct ifx_spi_device *ifx_dev)
 	if (!val) {
 		if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING,
 				      &ifx_dev->flags)) {
-			ifx_dev->spi_timer.expires =
-				jiffies + IFX_SPI_TIMEOUT_SEC*HZ;
-			add_timer(&ifx_dev->spi_timer);
+			mod_timer(&ifx_dev->spi_timer,jiffies + IFX_SPI_TIMEOUT_SEC*HZ);
 
 		}
 	}
@@ -449,7 +518,7 @@ static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
 					tx_count-IFX_SPI_HEADER_OVERHEAD,
 					ifx_dev->spi_more);
 	/* swap actual data in the buffer */
-	swap_buf((u16 *)(ifx_dev->tx_buffer), tx_count,
+	ifx_dev->swap_buf((ifx_dev->tx_buffer), tx_count,
 		&ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]);
 	return tx_count;
 }
@@ -469,9 +538,17 @@ static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf,
 {
 	struct ifx_spi_device *ifx_dev = tty->driver_data;
 	unsigned char *tmp_buf = (unsigned char *)buf;
-	int tx_count = kfifo_in_locked(&ifx_dev->tx_fifo, tmp_buf, count,
-				   &ifx_dev->fifo_lock);
-	mrdy_assert(ifx_dev);
+	unsigned long flags;
+	bool is_fifo_empty;
+	int tx_count;
+
+	spin_lock_irqsave(&ifx_dev->fifo_lock, flags);
+	is_fifo_empty = kfifo_is_empty(&ifx_dev->tx_fifo);
+	tx_count = kfifo_in(&ifx_dev->tx_fifo, tmp_buf, count);
+	spin_unlock_irqrestore(&ifx_dev->fifo_lock, flags);
+	if (is_fifo_empty)
+		mrdy_assert(ifx_dev);
+
 	return tx_count;
 }
 
@@ -530,12 +607,19 @@ static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty)
 	/* clear any old data; can't do this in 'close' */
 	kfifo_reset(&ifx_dev->tx_fifo);
 
+	/* clear any flag which may be set in port shutdown procedure */
+	clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags);
+	clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags);
+
 	/* put port data into this tty */
 	tty->driver_data = ifx_dev;
 
 	/* allows flip string push from int context */
 	tty->low_latency = 1;
 
+	/* set flag to allows data transfer */
+	set_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags);
+
 	return 0;
 }
 
@@ -551,6 +635,7 @@ static void ifx_port_shutdown(struct tty_port *port)
 	struct ifx_spi_device *ifx_dev =
 		container_of(port, struct ifx_spi_device, tty_port);
 
+	clear_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags);
 	mrdy_set_low(ifx_dev);
 	clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
 	tasklet_kill(&ifx_dev->io_work_tasklet);
@@ -617,7 +702,7 @@ static void ifx_spi_complete(void *ctx)
 
 	if (!ifx_dev->spi_msg.status) {
 		/* check header validity, get comm flags */
-		swap_buf((u16 *)ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
+		ifx_dev->swap_buf(ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD,
 			&ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]);
 		decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer,
 				&length, &more, &cts);
@@ -636,7 +721,8 @@ static void ifx_spi_complete(void *ctx)
 
 		actual_length = min((unsigned int)length,
 					ifx_dev->spi_msg.actual_length);
-		swap_buf((u16 *)(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
+		ifx_dev->swap_buf(
+			(ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD),
 			 actual_length,
 			 &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]);
 		ifx_spi_insert_flip_string(
@@ -705,7 +791,8 @@ static void ifx_spi_io(unsigned long data)
 	int retval;
 	struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *) data;
 
-	if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) {
+	if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags) &&
+		test_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags)) {
 		if (ifx_dev->gpio.unack_srdy_int_nb > 0)
 			ifx_dev->gpio.unack_srdy_int_nb--;
 
@@ -773,6 +860,7 @@ static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev)
 {
 	if (ifx_dev->tty_dev)
 		tty_unregister_device(tty_drv, ifx_dev->minor);
+	tty_port_destroy(&ifx_dev->tty_port);
 	kfifo_free(&ifx_dev->tx_fifo);
 }
 
@@ -806,10 +894,12 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
 		dev_dbg(&ifx_dev->spi_dev->dev,
 			"%s: registering tty device failed", __func__);
 		ret = PTR_ERR(ifx_dev->tty_dev);
-		goto error_ret;
+		goto error_port;
 	}
 	return 0;
 
+error_port:
+	tty_port_destroy(pport);
 error_ret:
 	ifx_spi_free_port(ifx_dev);
 	return ret;
@@ -826,7 +916,7 @@ error_ret:
 static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev)
 {
 	if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) {
-		del_timer_sync(&ifx_dev->spi_timer);
+		del_timer(&ifx_dev->spi_timer);
 		clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
 	}
 
@@ -1001,6 +1091,14 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
 		return -ENODEV;
 	}
 
+	/* init swap_buf function according to word width configuration */
+	if (spi->bits_per_word == 32)
+		ifx_dev->swap_buf = swap_buf_32;
+	else if (spi->bits_per_word == 16)
+		ifx_dev->swap_buf = swap_buf_16;
+	else
+		ifx_dev->swap_buf = swap_buf_8;
+
 	/* ensure SPI protocol flags are initialized to enable transfer */
 	ifx_dev->spi_more = 0;
 	ifx_dev->spi_slave_cts = 0;
@@ -1219,6 +1317,9 @@ static int ifx_spi_spi_remove(struct spi_device *spi)
 
 static void ifx_spi_spi_shutdown(struct spi_device *spi)
 {
+	struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi);
+
+	ifx_modem_power_off(ifx_dev);
 }
 
 /*
@@ -1338,7 +1439,7 @@ static struct spi_driver ifx_spi_driver = {
 		.owner = THIS_MODULE},
 	.probe = ifx_spi_spi_probe,
 	.shutdown = ifx_spi_spi_shutdown,
-	.remove = __devexit_p(ifx_spi_spi_remove),
+	.remove = ifx_spi_spi_remove,
 	.suspend = ifx_spi_spi_suspend,
 	.resume = ifx_spi_spi_resume,
 	.id_table = ifx_id_table
@@ -1354,7 +1455,9 @@ static void __exit ifx_spi_exit(void)
 {
 	/* unregister */
 	tty_unregister_driver(tty_drv);
+	put_tty_driver(tty_drv);
 	spi_unregister_driver((void *)&ifx_spi_driver);
+	unregister_reboot_notifier(&ifx_modem_reboot_notifier_block);
 }
 
 /**
@@ -1389,16 +1492,31 @@ static int __init ifx_spi_init(void)
 	if (result) {
 		pr_err("%s: tty_register_driver failed(%d)",
 			DRVNAME, result);
-		put_tty_driver(tty_drv);
-		return result;
+		goto err_free_tty;
 	}
 
 	result = spi_register_driver((void *)&ifx_spi_driver);
 	if (result) {
 		pr_err("%s: spi_register_driver failed(%d)",
 			DRVNAME, result);
-		tty_unregister_driver(tty_drv);
+		goto err_unreg_tty;
 	}
+
+	result = register_reboot_notifier(&ifx_modem_reboot_notifier_block);
+	if (result) {
+		pr_err("%s: register ifx modem reboot notifier failed(%d)",
+			DRVNAME, result);
+		goto err_unreg_spi;
+	}
+
+	return 0;
+err_unreg_spi:
+	spi_unregister_driver((void *)&ifx_spi_driver);
+err_unreg_tty:
+	tty_unregister_driver(tty_drv);
+err_free_tty:
+	put_tty_driver(tty_drv);
+
 	return result;
 }
 

+ 2 - 0
drivers/tty/serial/ifx6x60.h

@@ -41,6 +41,7 @@
 #define IFX_SPI_STATE_IO_IN_PROGRESS	1
 #define IFX_SPI_STATE_IO_READY		2
 #define IFX_SPI_STATE_TIMER_PENDING	3
+#define IFX_SPI_STATE_IO_AVAILABLE	4
 
 /* flow control bitfields */
 #define IFX_SPI_DCD			0
@@ -124,6 +125,7 @@ struct ifx_spi_device {
 #define MR_INPROGRESS	1
 #define MR_COMPLETE	2
 	wait_queue_head_t mdm_reset_wait;
+	void (*swap_buf)(unsigned char *buf, int len, void *end);
 };
 
 #endif /* _IFX6X60_H */

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

@@ -2010,7 +2010,7 @@ static int ioc3uart_remove(struct ioc3_submodule *is,
  * @idd: ioc3 driver data for this card
  */
 
-static int __devinit
+static int
 ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
 {
 	struct pci_dev *pdev = idd->pdev;

+ 5 - 3
drivers/tty/serial/jsm/jsm.h

@@ -57,9 +57,11 @@ enum {
 	DBG_CARR	= 0x10000,
 };
 
-#define jsm_printk(nlevel, klevel, pdev, fmt, args...)	\
-	if ((DBG_##nlevel & jsm_debug))			\
-	dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
+#define jsm_dbg(nlevel, pdev, fmt, ...)				\
+do {								\
+	if (DBG_##nlevel & jsm_debug)				\
+		dev_dbg(pdev->dev, fmt, ##__VA_ARGS__);		\
+} while (0)
 
 #define	MAXLINES	256
 #define MAXPORTS	8

Some files were not shown because too many files changed in this diff