Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 26 Oct 2011 13:11:09 +0000 (15:11 +0200)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 26 Oct 2011 13:11:09 +0000 (15:11 +0200)
* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (79 commits)
  TTY: serial_core: Fix crash if DCD drop during suspend
  tty/serial: atmel_serial: bootconsole removed from auto-enumerates
  Revert "TTY: call tty_driver_lookup_tty unconditionally"
  tty/serial: atmel_serial: add device tree support
  tty/serial: atmel_serial: auto-enumerate ports
  tty/serial: atmel_serial: whitespace and braces modifications
  tty/serial: atmel_serial: change platform_data variable name
  tty/serial: RS485 bindings for device tree
  TTY: call tty_driver_lookup_tty unconditionally
  TTY: pty, release tty in all ptmx_open fail paths
  TTY: make tty_add_file non-failing
  TTY: drop driver reference in tty_open fail path
  8250_pci: Fix kernel panic when pch_uart is disabled
  h8300: drivers/serial/Kconfig was moved
  parport_pc: release IO region properly if unsupported ITE887x card is found
  tty: Support compat_ioctl get/set termios_locked
  hvc_console: display printk messages on console.
  TTY: snyclinkmp: forever loop in tx_load_dma_buffer()
  tty/n_gsm: avoid fifo overflow in gsm_dlci_data_output
  tty/n_gsm: fix a bug in gsm_dlci_data_output (adaption = 2 case)
  ...

Fix up Conflicts in:
 - drivers/tty/serial/8250_pci.c
Trivial conflict with removed duplicate device ID
 - drivers/tty/serial/atmel_serial.c
Annoying silly conflict between "specify the port num via
platform_data" and other changes to atmel_console_init

110 files changed:
Documentation/devicetree/bindings/serial/rs485.txt [new file with mode: 0644]
Documentation/devicetree/bindings/tty/serial/atmel-usart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/tty/serial/snps-dw-apb-uart.txt [new file with mode: 0644]
Documentation/serial/serial-rs485.txt
arch/arm/Kconfig
arch/arm/mach-s3c64xx/dev-uart.c
arch/arm/mach-s3c64xx/include/mach/irqs.h
arch/arm/mach-s3c64xx/irq.c
arch/arm/plat-s5p/Kconfig
arch/arm/plat-s5p/dev-uart.c
arch/arm/plat-s5p/include/plat/irqs.h
arch/arm/plat-s5p/irq.c
arch/arm/plat-samsung/Kconfig
arch/arm/plat-samsung/Makefile
arch/arm/plat-samsung/include/plat/regs-serial.h
arch/arm/plat-samsung/irq-uart.c [deleted file]
arch/h8300/Kconfig
arch/mips/pmc-sierra/msp71xx/msp_serial.c
arch/powerpc/include/asm/udbg.h
arch/powerpc/kernel/udbg.c
arch/x86/platform/mrst/mrst.c
drivers/isdn/i4l/isdn_tty.c
drivers/parport/parport_pc.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/serial/68360serial.c [moved from drivers/tty/serial/68360serial.c with 100% similarity]
drivers/staging/serial/Kconfig [new file with mode: 0644]
drivers/staging/serial/Makefile [new file with mode: 0644]
drivers/staging/serial/TODO [new file with mode: 0644]
drivers/tty/Kconfig
drivers/tty/Makefile
drivers/tty/amiserial.c
drivers/tty/cyclades.c
drivers/tty/ehv_bytechan.c [new file with mode: 0644]
drivers/tty/hvc/hvc_console.c
drivers/tty/hvc/hvc_irq.c
drivers/tty/hvc/hvcs.c
drivers/tty/hvc/hvsi.c
drivers/tty/isicom.c
drivers/tty/mxser.c
drivers/tty/n_gsm.c
drivers/tty/pty.c
drivers/tty/serial/68328serial.c
drivers/tty/serial/68328serial.h
drivers/tty/serial/8250.c
drivers/tty/serial/8250_dw.c [new file with mode: 0644]
drivers/tty/serial/8250_pci.c
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/altera_jtaguart.c
drivers/tty/serial/altera_uart.c
drivers/tty/serial/apbuart.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/bfin_sport_uart.c
drivers/tty/serial/bfin_uart.c [moved from drivers/tty/serial/bfin_5xx.c with 97% similarity]
drivers/tty/serial/cpm_uart/cpm_uart_core.c
drivers/tty/serial/crisv10.c
drivers/tty/serial/dz.c
drivers/tty/serial/icom.c
drivers/tty/serial/imx.c
drivers/tty/serial/ioc3_serial.c
drivers/tty/serial/ioc4_serial.c
drivers/tty/serial/jsm/jsm.h
drivers/tty/serial/jsm/jsm_driver.c
drivers/tty/serial/jsm/jsm_neo.c
drivers/tty/serial/jsm/jsm_tty.c
drivers/tty/serial/lantiq.c
drivers/tty/serial/m32r_sio.c
drivers/tty/serial/max3100.c
drivers/tty/serial/max3107.c
drivers/tty/serial/mcf.c
drivers/tty/serial/mfd.c
drivers/tty/serial/mpc52xx_uart.c
drivers/tty/serial/mrst_max3110.c
drivers/tty/serial/mrst_max3110.h
drivers/tty/serial/msm_serial.c
drivers/tty/serial/msm_serial_hs.c
drivers/tty/serial/mux.c
drivers/tty/serial/nwpserial.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/pxa.c
drivers/tty/serial/samsung.c
drivers/tty/serial/samsung.h
drivers/tty/serial/sb1250-duart.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/serial_ks8695.c
drivers/tty/serial/serial_txx9.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sn_console.c
drivers/tty/serial/timbuart.c
drivers/tty/serial/uartlite.c
drivers/tty/serial/ucc_uart.c
drivers/tty/serial/xilinx_uartps.c
drivers/tty/serial/zs.c
drivers/tty/synclink.c
drivers/tty/synclinkmp.c
drivers/tty/tty_io.c
drivers/tty/tty_ioctl.c
drivers/tty/tty_ldisc.c
drivers/tty/tty_mutex.c
drivers/tty/tty_port.c
drivers/tty/vt/keyboard.c
drivers/tty/vt/selection.c
drivers/tty/vt/vt.c
include/linux/serial.h
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/serial_reg.h
include/linux/tty.h
net/irda/ircomm/ircomm_tty.c

diff --git a/Documentation/devicetree/bindings/serial/rs485.txt b/Documentation/devicetree/bindings/serial/rs485.txt
new file mode 100644 (file)
index 0000000..1e753c6
--- /dev/null
@@ -0,0 +1,31 @@
+* RS485 serial communications
+
+The RTS signal is capable of automatically controlling line direction for
+the built-in half-duplex mode.
+The properties described hereafter shall be given to a half-duplex capable
+UART node.
+
+Required properties:
+- rs485-rts-delay: prop-encoded-array <a b> where:
+  * a is the delay beteween rts signal and beginning of data sent in milliseconds.
+      it corresponds to the delay before sending data.
+  * b is the delay between end of data sent and rts signal in milliseconds
+      it corresponds to the delay after sending data and actual release of the line.
+
+Optional properties:
+- linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485
+  feature at boot time. It can be disabled later with proper ioctl.
+- rs485-rx-during-tx: empty property that enables the receiving of data even
+  whilst sending data.
+
+RS485 example for Atmel USART:
+       usart0: serial@fff8c000 {
+               compatible = "atmel,at91sam9260-usart";
+               reg = <0xfff8c000 0x4000>;
+               interrupts = <7>;
+               atmel,use-dma-rx;
+               atmel,use-dma-tx;
+               linux,rs485-enabled-at-boot-time;
+               rs485-rts-delay = <0 200>;              // in milliseconds
+       };
+
diff --git a/Documentation/devicetree/bindings/tty/serial/atmel-usart.txt b/Documentation/devicetree/bindings/tty/serial/atmel-usart.txt
new file mode 100644 (file)
index 0000000..a49d9a1
--- /dev/null
@@ -0,0 +1,27 @@
+* Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART)
+
+Required properties:
+- compatible: Should be "atmel,<chip>-usart"
+  The compatible <chip> indicated will be the first SoC to support an
+  additional mode or an USART new feature.
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt
+
+Optional properties:
+- atmel,use-dma-rx: use of PDC or DMA for receiving data
+- atmel,use-dma-tx: use of PDC or DMA for transmitting data
+
+<chip> compatible description:
+- at91rm9200:  legacy USART support
+- at91sam9260: generic USART implementation for SAM9 SoCs
+
+Example:
+
+       usart0: serial@fff8c000 {
+               compatible = "atmel,at91sam9260-usart";
+               reg = <0xfff8c000 0x4000>;
+               interrupts = <7>;
+               atmel,use-dma-rx;
+               atmel,use-dma-tx;
+       };
+
diff --git a/Documentation/devicetree/bindings/tty/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/tty/serial/snps-dw-apb-uart.txt
new file mode 100644 (file)
index 0000000..f13f1c5
--- /dev/null
@@ -0,0 +1,25 @@
+* Synopsys DesignWare ABP UART
+
+Required properties:
+- compatible : "snps,dw-apb-uart"
+- 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.
+
+Optional properties:
+- reg-shift : quantity to shift the register offsets by.  If this property is
+  not present then the register offsets are not shifted.
+- reg-io-width : the size (in bytes) of the IO accesses that should be
+  performed on the device.  If this property is not present then single byte
+  accesses are used.
+
+Example:
+
+       uart@80230000 {
+               compatible = "snps,dw-apb-uart";
+               reg = <0x80230000 0x100>;
+               clock-frequency = <3686400>;
+               interrupts = <10>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+       };
index a493238..079cb3d 100644 (file)
    RS485 communications. This data structure is used to set and configure RS485
    parameters in the platform data and in ioctls.
 
+   The device tree can also provide RS485 boot time parameters (see [2]
+   for bindings). The driver is in charge of filling this data structure from
+   the values given by the device tree.
+
    Any driver for devices capable of working both as RS232 and RS485 should
    provide at least the following ioctls:
 
        rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
        rs485conf.delay_rts_after_send = ...;
 
+       /* Set this flag if you want to receive data even whilst sending data */
+       rs485conf.flags |= SER_RS485_RX_DURING_TX;
+
        if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
                /* Error handling. See errno. */
        }
 5. REFERENCES
 
  [1]   include/linux/serial.h
+ [2]   Documentation/devicetree/bindings/serial/rs485.txt
index 7536b9c..795126e 100644 (file)
@@ -727,7 +727,6 @@ config ARCH_S3C64XX
        select ARCH_REQUIRE_GPIOLIB
        select SAMSUNG_CLKSRC
        select SAMSUNG_IRQ_VIC_TIMER
-       select SAMSUNG_IRQ_UART
        select S3C_GPIO_TRACK
        select S3C_GPIO_PULL_UPDOWN
        select S3C_GPIO_CFG_S3C24XX
index f797f74..c681b99 100644 (file)
@@ -37,21 +37,10 @@ static struct resource s3c64xx_uart0_resource[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S3CUART_RX0,
-               .end    = IRQ_S3CUART_RX0,
+               .start  = IRQ_UART0,
+               .end    = IRQ_UART0,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               .start  = IRQ_S3CUART_TX0,
-               .end    = IRQ_S3CUART_TX0,
-               .flags  = IORESOURCE_IRQ,
-
-       },
-       [3] = {
-               .start  = IRQ_S3CUART_ERR0,
-               .end    = IRQ_S3CUART_ERR0,
-               .flags  = IORESOURCE_IRQ,
-       }
 };
 
 static struct resource s3c64xx_uart1_resource[] = {
@@ -61,19 +50,8 @@ static struct resource s3c64xx_uart1_resource[] = {
                .flags = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S3CUART_RX1,
-               .end    = IRQ_S3CUART_RX1,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S3CUART_TX1,
-               .end    = IRQ_S3CUART_TX1,
-               .flags  = IORESOURCE_IRQ,
-
-       },
-       [3] = {
-               .start  = IRQ_S3CUART_ERR1,
-               .end    = IRQ_S3CUART_ERR1,
+               .start  = IRQ_UART1,
+               .end    = IRQ_UART1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -85,19 +63,8 @@ static struct resource s3c6xx_uart2_resource[] = {
                .flags = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S3CUART_RX2,
-               .end    = IRQ_S3CUART_RX2,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S3CUART_TX2,
-               .end    = IRQ_S3CUART_TX2,
-               .flags  = IORESOURCE_IRQ,
-
-       },
-       [3] = {
-               .start  = IRQ_S3CUART_ERR2,
-               .end    = IRQ_S3CUART_ERR2,
+               .start  = IRQ_UART2,
+               .end    = IRQ_UART2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -109,19 +76,8 @@ static struct resource s3c64xx_uart3_resource[] = {
                .flags = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S3CUART_RX3,
-               .end    = IRQ_S3CUART_RX3,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S3CUART_TX3,
-               .end    = IRQ_S3CUART_TX3,
-               .flags  = IORESOURCE_IRQ,
-
-       },
-       [3] = {
-               .start  = IRQ_S3CUART_ERR3,
-               .end    = IRQ_S3CUART_ERR3,
+               .start  = IRQ_UART3,
+               .end    = IRQ_UART3,
                .flags  = IORESOURCE_IRQ,
        },
 };
index c026f67..443f85b 100644 (file)
 #define IRQ_VIC0_BASE  S3C_IRQ(0)
 #define IRQ_VIC1_BASE  S3C_IRQ(32)
 
-/* UART interrupts, each UART has 4 intterupts per channel so
- * use the space between the ISA and S3C main interrupts. Note, these
- * are not in the same order as the S3C24XX series! */
-
-#define IRQ_S3CUART_BASE0      (16)
-#define IRQ_S3CUART_BASE1      (20)
-#define IRQ_S3CUART_BASE2      (24)
-#define IRQ_S3CUART_BASE3      (28)
-
-#define UART_IRQ_RXD           (0)
-#define UART_IRQ_ERR           (1)
-#define UART_IRQ_TXD           (2)
-#define UART_IRQ_MODEM         (3)
-
-#define IRQ_S3CUART_RX0                (IRQ_S3CUART_BASE0 + UART_IRQ_RXD)
-#define IRQ_S3CUART_TX0                (IRQ_S3CUART_BASE0 + UART_IRQ_TXD)
-#define IRQ_S3CUART_ERR0       (IRQ_S3CUART_BASE0 + UART_IRQ_ERR)
-
-#define IRQ_S3CUART_RX1                (IRQ_S3CUART_BASE1 + UART_IRQ_RXD)
-#define IRQ_S3CUART_TX1                (IRQ_S3CUART_BASE1 + UART_IRQ_TXD)
-#define IRQ_S3CUART_ERR1       (IRQ_S3CUART_BASE1 + UART_IRQ_ERR)
-
-#define IRQ_S3CUART_RX2                (IRQ_S3CUART_BASE2 + UART_IRQ_RXD)
-#define IRQ_S3CUART_TX2                (IRQ_S3CUART_BASE2 + UART_IRQ_TXD)
-#define IRQ_S3CUART_ERR2       (IRQ_S3CUART_BASE2 + UART_IRQ_ERR)
-
-#define IRQ_S3CUART_RX3                (IRQ_S3CUART_BASE3 + UART_IRQ_RXD)
-#define IRQ_S3CUART_TX3                (IRQ_S3CUART_BASE3 + UART_IRQ_TXD)
-#define IRQ_S3CUART_ERR3       (IRQ_S3CUART_BASE3 + UART_IRQ_ERR)
-
 /* VIC based IRQs */
 
 #define S3C64XX_IRQ_VIC0(x)    (IRQ_VIC0_BASE + (x))
index 75d9a0e..b07357e 100644 (file)
 #include <plat/irq-uart.h>
 #include <plat/cpu.h>
 
-static struct s3c_uart_irq uart_irqs[] = {
-       [0] = {
-               .regs           = S3C_VA_UART0,
-               .base_irq       = IRQ_S3CUART_BASE0,
-               .parent_irq     = IRQ_UART0,
-       },
-       [1] = {
-               .regs           = S3C_VA_UART1,
-               .base_irq       = IRQ_S3CUART_BASE1,
-               .parent_irq     = IRQ_UART1,
-       },
-       [2] = {
-               .regs           = S3C_VA_UART2,
-               .base_irq       = IRQ_S3CUART_BASE2,
-               .parent_irq     = IRQ_UART2,
-       },
-       [3] = {
-               .regs           = S3C_VA_UART3,
-               .base_irq       = IRQ_S3CUART_BASE3,
-               .parent_irq     = IRQ_UART3,
-       },
-};
-
 /* setup the sources the vic should advertise resume for, even though it
  * is not doing the wake (set_irq_wake needs to be valid) */
 #define IRQ_VIC0_RESUME (1 << (IRQ_RTC_TIC - IRQ_VIC0_BASE))
@@ -67,6 +44,4 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
 
        /* add the timer sub-irqs */
        s3c_init_vic_timer_irq(5, IRQ_TIMER0);
-
-       s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
 }
index 9843c95..9a197e5 100644 (file)
@@ -22,7 +22,6 @@ config PLAT_S5P
        select PLAT_SAMSUNG
        select SAMSUNG_CLKSRC
        select SAMSUNG_IRQ_VIC_TIMER
-       select SAMSUNG_IRQ_UART
        help
          Base platform code for Samsung's S5P series SoC.
 
index afaf87f..c9308db 100644 (file)
@@ -32,20 +32,10 @@ static struct resource s5p_uart0_resource[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S5P_UART_RX0,
-               .end    = IRQ_S5P_UART_RX0,
+               .start  = IRQ_UART0,
+               .end    = IRQ_UART0,
                .flags  = IORESOURCE_IRQ,
        },
-       [2] = {
-               .start  = IRQ_S5P_UART_TX0,
-               .end    = IRQ_S5P_UART_TX0,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = IRQ_S5P_UART_ERR0,
-               .end    = IRQ_S5P_UART_ERR0,
-               .flags  = IORESOURCE_IRQ,
-       }
 };
 
 static struct resource s5p_uart1_resource[] = {
@@ -55,18 +45,8 @@ static struct resource s5p_uart1_resource[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S5P_UART_RX1,
-               .end    = IRQ_S5P_UART_RX1,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S5P_UART_TX1,
-               .end    = IRQ_S5P_UART_TX1,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = IRQ_S5P_UART_ERR1,
-               .end    = IRQ_S5P_UART_ERR1,
+               .start  = IRQ_UART1,
+               .end    = IRQ_UART1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -78,18 +58,8 @@ static struct resource s5p_uart2_resource[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S5P_UART_RX2,
-               .end    = IRQ_S5P_UART_RX2,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S5P_UART_TX2,
-               .end    = IRQ_S5P_UART_TX2,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = IRQ_S5P_UART_ERR2,
-               .end    = IRQ_S5P_UART_ERR2,
+               .start  = IRQ_UART2,
+               .end    = IRQ_UART2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -102,18 +72,8 @@ static struct resource s5p_uart3_resource[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S5P_UART_RX3,
-               .end    = IRQ_S5P_UART_RX3,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S5P_UART_TX3,
-               .end    = IRQ_S5P_UART_TX3,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = IRQ_S5P_UART_ERR3,
-               .end    = IRQ_S5P_UART_ERR3,
+               .start  = IRQ_UART3,
+               .end    = IRQ_UART3,
                .flags  = IORESOURCE_IRQ,
        },
 #endif
@@ -127,18 +87,8 @@ static struct resource s5p_uart4_resource[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S5P_UART_RX4,
-               .end    = IRQ_S5P_UART_RX4,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S5P_UART_TX4,
-               .end    = IRQ_S5P_UART_TX4,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = IRQ_S5P_UART_ERR4,
-               .end    = IRQ_S5P_UART_ERR4,
+               .start  = IRQ_UART4,
+               .end    = IRQ_UART4,
                .flags  = IORESOURCE_IRQ,
        },
 #endif
@@ -152,18 +102,8 @@ static struct resource s5p_uart5_resource[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = IRQ_S5P_UART_RX5,
-               .end    = IRQ_S5P_UART_RX5,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = IRQ_S5P_UART_TX5,
-               .end    = IRQ_S5P_UART_TX5,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = IRQ_S5P_UART_ERR5,
-               .end    = IRQ_S5P_UART_ERR5,
+               .start  = IRQ_UART5,
+               .end    = IRQ_UART5,
                .flags  = IORESOURCE_IRQ,
        },
 #endif
index ba9121c..144dbfc 100644 (file)
 #define IRQ_VIC1_BASE          S5P_VIC1_BASE
 #define IRQ_VIC2_BASE          S5P_VIC2_BASE
 
-/* UART interrupts, each UART has 4 intterupts per channel so
- * use the space between the ISA and S3C main interrupts. Note, these
- * are not in the same order as the S3C24XX series! */
-
-#define IRQ_S5P_UART_BASE0     (16)
-#define IRQ_S5P_UART_BASE1     (20)
-#define IRQ_S5P_UART_BASE2     (24)
-#define IRQ_S5P_UART_BASE3     (28)
-
-#define UART_IRQ_RXD           (0)
-#define UART_IRQ_ERR           (1)
-#define UART_IRQ_TXD           (2)
-
-#define IRQ_S5P_UART_RX0       (IRQ_S5P_UART_BASE0 + UART_IRQ_RXD)
-#define IRQ_S5P_UART_TX0       (IRQ_S5P_UART_BASE0 + UART_IRQ_TXD)
-#define IRQ_S5P_UART_ERR0      (IRQ_S5P_UART_BASE0 + UART_IRQ_ERR)
-
-#define IRQ_S5P_UART_RX1       (IRQ_S5P_UART_BASE1 + UART_IRQ_RXD)
-#define IRQ_S5P_UART_TX1       (IRQ_S5P_UART_BASE1 + UART_IRQ_TXD)
-#define IRQ_S5P_UART_ERR1      (IRQ_S5P_UART_BASE1 + UART_IRQ_ERR)
-
-#define IRQ_S5P_UART_RX2       (IRQ_S5P_UART_BASE2 + UART_IRQ_RXD)
-#define IRQ_S5P_UART_TX2       (IRQ_S5P_UART_BASE2 + UART_IRQ_TXD)
-#define IRQ_S5P_UART_ERR2      (IRQ_S5P_UART_BASE2 + UART_IRQ_ERR)
-
-#define IRQ_S5P_UART_RX3       (IRQ_S5P_UART_BASE3 + UART_IRQ_RXD)
-#define IRQ_S5P_UART_TX3       (IRQ_S5P_UART_BASE3 + UART_IRQ_TXD)
-#define IRQ_S5P_UART_ERR3      (IRQ_S5P_UART_BASE3 + UART_IRQ_ERR)
-
-/* S3C compatibilty defines */
-#define IRQ_S3CUART_RX0                IRQ_S5P_UART_RX0
-#define IRQ_S3CUART_RX1                IRQ_S5P_UART_RX1
-#define IRQ_S3CUART_RX2                IRQ_S5P_UART_RX2
-#define IRQ_S3CUART_RX3                IRQ_S5P_UART_RX3
-
 /* VIC based IRQs */
 
 #define S5P_IRQ_VIC0(x)                (S5P_VIC0_BASE + (x))
index a97c089..afdaa10 100644 (file)
 
 #include <asm/hardware/vic.h>
 
-#include <linux/serial_core.h>
 #include <mach/map.h>
 #include <plat/regs-timer.h>
-#include <plat/regs-serial.h>
 #include <plat/cpu.h>
 #include <plat/irq-vic-timer.h>
-#include <plat/irq-uart.h>
-
-/*
- * Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
- * are consecutive when looking up the interrupt in the demux routines.
- */
-static struct s3c_uart_irq uart_irqs[] = {
-       [0] = {
-               .regs           = S5P_VA_UART0,
-               .base_irq       = IRQ_S5P_UART_BASE0,
-               .parent_irq     = IRQ_UART0,
-       },
-       [1] = {
-               .regs           = S5P_VA_UART1,
-               .base_irq       = IRQ_S5P_UART_BASE1,
-               .parent_irq     = IRQ_UART1,
-       },
-       [2] = {
-               .regs           = S5P_VA_UART2,
-               .base_irq       = IRQ_S5P_UART_BASE2,
-               .parent_irq     = IRQ_UART2,
-       },
-#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
-       [3] = {
-               .regs           = S5P_VA_UART3,
-               .base_irq       = IRQ_S5P_UART_BASE3,
-               .parent_irq     = IRQ_UART3,
-       },
-#endif
-};
 
 void __init s5p_init_irq(u32 *vic, u32 num_vic)
 {
@@ -65,6 +33,4 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
 #endif
 
        s3c_init_vic_timer_irq(5, IRQ_TIMER0);
-
-       s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
 }
index b3e1065..dffa37b 100644 (file)
@@ -65,11 +65,6 @@ config SAMSUNG_IRQ_VIC_TIMER
        help
          Internal configuration to build the VIC timer interrupt code.
 
-config SAMSUNG_IRQ_UART
-       bool
-       help
-         Internal configuration to build the IRQ UART demux code.
-
 # options for gpio configuration support
 
 config SAMSUNG_GPIOLIB_4BIT
index 853764b..1105922 100644 (file)
@@ -21,7 +21,6 @@ obj-y                         += dev-asocdma.o
 
 obj-$(CONFIG_SAMSUNG_CLKSRC)   += clock-clksrc.o
 
-obj-$(CONFIG_SAMSUNG_IRQ_UART) += irq-uart.o
 obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o
 
 # ADC
index bac36fa..7207348 100644 (file)
 #define S3C64XX_UINTSP         0x34
 #define S3C64XX_UINTM          0x38
 
+#define S3C64XX_UINTM_RXD      (0)
+#define S3C64XX_UINTM_TXD      (2)
+#define S3C64XX_UINTM_RXD_MSK  (1 << S3C64XX_UINTM_RXD)
+#define S3C64XX_UINTM_TXD_MSK  (1 << S3C64XX_UINTM_TXD)
+
 /* Following are specific to S5PV210 */
 #define S5PV210_UCON_CLKMASK   (1<<10)
 #define S5PV210_UCON_PCLK      (0<<10)
diff --git a/arch/arm/plat-samsung/irq-uart.c b/arch/arm/plat-samsung/irq-uart.c
deleted file mode 100644 (file)
index 3014c72..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* arch/arm/plat-samsung/irq-uart.c
- *     originally part of arch/arm/plat-s3c64xx/irq.c
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * Samsung- UART Interrupt handling
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/serial_core.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/map.h>
-#include <plat/irq-uart.h>
-#include <plat/regs-serial.h>
-#include <plat/cpu.h>
-
-/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
- * are consecutive when looking up the interrupt in the demux routines.
- */
-static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
-{
-       struct s3c_uart_irq *uirq = desc->irq_data.handler_data;
-       struct irq_chip *chip = irq_get_chip(irq);
-       u32 pend = __raw_readl(uirq->regs + S3C64XX_UINTP);
-       int base = uirq->base_irq;
-
-       chained_irq_enter(chip, desc);
-
-       if (pend & (1 << 0))
-               generic_handle_irq(base);
-       if (pend & (1 << 1))
-               generic_handle_irq(base + 1);
-       if (pend & (1 << 2))
-               generic_handle_irq(base + 2);
-       if (pend & (1 << 3))
-               generic_handle_irq(base + 3);
-
-       chained_irq_exit(chip, desc);
-}
-
-static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
-{
-       void __iomem *reg_base = uirq->regs;
-       struct irq_chip_generic *gc;
-       struct irq_chip_type *ct;
-
-       /* mask all interrupts at the start. */
-       __raw_writel(0xf, reg_base + S3C64XX_UINTM);
-
-       gc = irq_alloc_generic_chip("s3c-uart", 1, uirq->base_irq, reg_base,
-                                   handle_level_irq);
-
-       if (!gc) {
-               pr_err("%s: irq_alloc_generic_chip for IRQ %u failed\n",
-                      __func__, uirq->base_irq);
-               return;
-       }
-
-       ct = gc->chip_types;
-       ct->chip.irq_ack = irq_gc_ack_set_bit;
-       ct->chip.irq_mask = irq_gc_mask_set_bit;
-       ct->chip.irq_unmask = irq_gc_mask_clr_bit;
-       ct->regs.ack = S3C64XX_UINTP;
-       ct->regs.mask = S3C64XX_UINTM;
-       irq_setup_generic_chip(gc, IRQ_MSK(4), IRQ_GC_INIT_MASK_CACHE,
-                              IRQ_NOREQUEST | IRQ_NOPROBE, 0);
-
-       irq_set_handler_data(uirq->parent_irq, uirq);
-       irq_set_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
-}
-
-/**
- * s3c_init_uart_irqs() - initialise UART IRQs and the necessary demuxing
- * @irq: The interrupt data for registering
- * @nr_irqs: The number of interrupt descriptions in @irq.
- *
- * Register the UART interrupts specified by @irq including the demuxing
- * routines. This supports the S3C6400 and newer style of devices.
- */
-void __init s3c_init_uart_irqs(struct s3c_uart_irq *irq, unsigned int nr_irqs)
-{
-       for (; nr_irqs > 0; nr_irqs--, irq++)
-               s3c_init_uart_irq(irq);
-}
index 7ed7714..d1f377f 100644 (file)
@@ -195,7 +195,7 @@ config UNIX98_PTYS
 
 source "drivers/char/pcmcia/Kconfig"
 
-source "drivers/serial/Kconfig"
+source "drivers/tty/serial/Kconfig"
 
 source "drivers/i2c/Kconfig"
 
index f726162..a1c7c7d 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
+#include <linux/slab.h>
 
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <msp_int.h>
 #include <msp_regs.h>
 
+struct msp_uart_data {
+       int     last_lcr;
+};
+
+static void msp_serial_out(struct uart_port *p, int offset, int value)
+{
+       struct msp_uart_data *d = p->private_data;
+
+       if (offset == UART_LCR)
+               d->last_lcr = value;
+
+       offset <<= p->regshift;
+       writeb(value, p->membase + offset);
+}
+
+static unsigned int msp_serial_in(struct uart_port *p, int offset)
+{
+       offset <<= p->regshift;
+
+       return readb(p->membase + offset);
+}
+
+static int msp_serial_handle_irq(struct uart_port *p)
+{
+       struct msp_uart_data *d = p->private_data;
+       unsigned int iir = readb(p->membase + (UART_IIR << p->regshift));
+
+       if (serial8250_handle_irq(p, iir)) {
+               return 1;
+       } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+               /*
+                * The DesignWare APB UART has an Busy Detect (0x07) interrupt
+                * meaning an LCR write attempt occurred while the UART was
+                * busy. The interrupt must be cleared by reading the UART
+                * status register (USR) and the LCR re-written.
+                *
+                * Note: MSP reserves 0x20 bytes of address space for the UART
+                * and the USR is mapped in a separate block at an offset of
+                * 0xc0 from the start of the UART.
+                */
+               (void)readb(p->membase + 0xc0);
+               writeb(d->last_lcr, p->membase + (UART_LCR << p->regshift));
+
+               return 1;
+       }
+
+       return 0;
+}
+
 void __init msp_serial_setup(void)
 {
        char    *s;
@@ -59,13 +109,22 @@ void __init msp_serial_setup(void)
        up.irq          = MSP_INT_UART0;
        up.uartclk      = uartclk;
        up.regshift     = 2;
-       up.iotype       = UPIO_DWAPB; /* UPIO_MEM like */
+       up.iotype       = UPIO_MEM;
        up.flags        = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
        up.type         = PORT_16550A;
        up.line         = 0;
-       up.private_data         = (void*)UART0_STATUS_REG;
-       if (early_serial_setup(&up))
-               printk(KERN_ERR "Early serial init of port 0 failed\n");
+       up.serial_out   = msp_serial_out;
+       up.serial_in    = msp_serial_in;
+       up.handle_irq   = msp_serial_handle_irq;
+       up.private_data = kzalloc(sizeof(struct msp_uart_data), GFP_KERNEL);
+       if (!up.private_data) {
+               pr_err("failed to allocate uart private data\n");
+               return;
+       }
+       if (early_serial_setup(&up)) {
+               kfree(up.private_data);
+               pr_err("Early serial init of port 0 failed\n");
+       }
 
        /* Initialize the second serial port, if one exists */
        switch (mips_machtype) {
@@ -88,6 +147,8 @@ void __init msp_serial_setup(void)
        up.irq          = MSP_INT_UART1;
        up.line         = 1;
        up.private_data         = (void*)UART1_STATUS_REG;
-       if (early_serial_setup(&up))
-               printk(KERN_ERR "Early serial init of port 1 failed\n");
+       if (early_serial_setup(&up)) {
+               kfree(up.private_data);
+               pr_err("Early serial init of port 1 failed\n");
+       }
 }
index 93e05d1..5354ae9 100644 (file)
@@ -54,6 +54,7 @@ extern void __init udbg_init_40x_realmode(void);
 extern void __init udbg_init_cpm(void);
 extern void __init udbg_init_usbgecko(void);
 extern void __init udbg_init_wsp(void);
+extern void __init udbg_init_ehv_bc(void);
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_UDBG_H */
index faa82c1..b4607a9 100644 (file)
@@ -67,6 +67,8 @@ void __init udbg_early_init(void)
        udbg_init_usbgecko();
 #elif defined(CONFIG_PPC_EARLY_DEBUG_WSP)
        udbg_init_wsp();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_EHV_BC)
+       udbg_init_ehv_bc();
 #endif
 
 #ifdef CONFIG_PPC_EARLY_DEBUG
index fe73276..e637952 100644 (file)
@@ -14,6 +14,8 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/scatterlist.h>
 #include <linux/sfi.h>
 #include <linux/intel_pmic_gpio.h>
 #include <linux/spi/spi.h>
@@ -392,6 +394,7 @@ static void __init *max3111_platform_data(void *info)
        struct spi_board_info *spi_info = info;
        int intr = get_gpio_by_name("max3111_int");
 
+       spi_info->mode = SPI_MODE_0;
        if (intr == -1)
                return NULL;
        spi_info->irq = intr + MRST_IRQ_OFFSET;
index d850427..e5546cb 100644 (file)
@@ -1693,7 +1693,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
         * line status register.
         */
        if (info->flags & ISDN_ASYNC_INITIALIZED) {
-               tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
+               tty_wait_until_sent_from_close(tty, 3000);      /* 30 seconds timeout */
                /*
                 * Before we drop DTR, make sure the UART transmitter
                 * has completely drained; this is especially
index d1cdb94..d0b597b 100644 (file)
@@ -2595,14 +2595,17 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
                break;
        case 0x6:
                printk(KERN_INFO "parport_pc: ITE8873 found (1S)\n");
+               release_region(inta_addr[i], 32);
                return 0;
        case 0x8:
                printk(KERN_INFO "parport_pc: ITE8874 found (2S)\n");
+               release_region(inta_addr[i], 32);
                return 0;
        default:
                printk(KERN_INFO "parport_pc: unknown ITE887x\n");
                printk(KERN_INFO "parport_pc: please mail 'lspci -nvv' "
                        "output to Rich.Liu@ite.com.tw\n");
+               release_region(inta_addr[i], 32);
                return 0;
        }
 
index 2582e18..036d9de 100644 (file)
@@ -24,6 +24,8 @@ menuconfig STAGING
 
 if STAGING
 
+source "drivers/staging/serial/Kconfig"
+
 source "drivers/staging/et131x/Kconfig"
 
 source "drivers/staging/slicoss/Kconfig"
index 50d112f..0599509 100644 (file)
@@ -3,6 +3,7 @@
 # fix for build system bug...
 obj-$(CONFIG_STAGING)          += staging.o
 
+obj-y                          += serial/
 obj-$(CONFIG_ET131X)           += et131x/
 obj-$(CONFIG_SLICOSS)          += slicoss/
 obj-$(CONFIG_VIDEO_GO7007)     += go7007/
diff --git a/drivers/staging/serial/Kconfig b/drivers/staging/serial/Kconfig
new file mode 100644 (file)
index 0000000..9489688
--- /dev/null
@@ -0,0 +1,16 @@
+config SERIAL_68360_SMC
+       bool "68360 SMC uart support"
+       depends on M68360
+       help
+         This driver supports the SMC serial ports of the Motorola 68360 CPU.
+
+config SERIAL_68360_SCC
+       bool "68360 SCC uart support"
+       depends on M68360
+       help
+         This driver supports the SCC serial ports of the Motorola 68360 CPU.
+
+config SERIAL_68360
+       bool
+       depends on SERIAL_68360_SMC || SERIAL_68360_SCC
+       default y
diff --git a/drivers/staging/serial/Makefile b/drivers/staging/serial/Makefile
new file mode 100644 (file)
index 0000000..37a6a0b
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_SERIAL_68360) += 68360serial.o
diff --git a/drivers/staging/serial/TODO b/drivers/staging/serial/TODO
new file mode 100644 (file)
index 0000000..a19cda8
--- /dev/null
@@ -0,0 +1,6 @@
+These are a few serial drivers that either do not build, or do not work if they
+do build, or if they seem to work, are for obsolete hardware, or are full of
+unfixable races and no one uses them anymore.
+
+If no one steps up to adopt any of these drivers, they will be removed
+in the 3.4 release.
index 3317550..8816f53 100644 (file)
@@ -354,3 +354,37 @@ config TRACE_SINK
 
          If you select this option, you need to select
          "Trace data router for MIPI P1149.7 cJTAG standard".
+
+config PPC_EPAPR_HV_BYTECHAN
+       tristate "ePAPR hypervisor byte channel driver"
+       depends on PPC
+       help
+         This driver creates /dev entries for each ePAPR hypervisor byte
+         channel, thereby allowing applications to communicate with byte
+         channels as if they were serial ports.
+
+config PPC_EARLY_DEBUG_EHV_BC
+       bool "Early console (udbg) support for ePAPR hypervisors"
+       depends on PPC_EPAPR_HV_BYTECHAN
+       help
+         Select this option to enable early console (a.k.a. "udbg") support
+         via an ePAPR byte channel.  You also need to choose the byte channel
+         handle below.
+
+config PPC_EARLY_DEBUG_EHV_BC_HANDLE
+       int "Byte channel handle for early console (udbg)"
+       depends on PPC_EARLY_DEBUG_EHV_BC
+       default 0
+       help
+         If you want early console (udbg) output through a byte channel,
+         specify the handle of the byte channel to use.
+
+         For this to work, the byte channel driver must be compiled
+         in-kernel, not as a module.
+
+         Note that only one early console driver can be enabled, so don't
+         enable any others if you enable this one.
+
+         If the number you specify is not a valid byte channel handle, then
+         there simply will be no early console output.  This is true also
+         if you don't boot under a hypervisor at all.
index ea89b0b..2953059 100644 (file)
@@ -26,5 +26,6 @@ obj-$(CONFIG_ROCKETPORT)      += rocket.o
 obj-$(CONFIG_SYNCLINK_GT)      += synclink_gt.o
 obj-$(CONFIG_SYNCLINKMP)       += synclinkmp.o
 obj-$(CONFIG_SYNCLINK)         += synclink.o
+obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
 
 obj-y += ipwireless/
index 2205795..b84c834 100644 (file)
@@ -1529,7 +1529,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 {
        struct async_struct * info = tty->driver_data;
        unsigned long orig_jiffies, char_time;
-       int tty_was_locked = tty_locked();
        int lsr;
 
        if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
@@ -1540,12 +1539,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 
        orig_jiffies = jiffies;
 
-       /*
-        * tty_wait_until_sent is called from lots of places,
-        * with or without the BTM.
-        */
-       if (!tty_was_locked)
-               tty_lock();
        /*
         * Set the check interval to be 1/5 of the estimated time to
         * send a single character, and make it at least 1.  The check
@@ -1586,8 +1579,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
                        break;
        }
        __set_current_state(TASK_RUNNING);
-       if (!tty_was_locked)
-               tty_unlock();
+
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
        printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
 #endif
@@ -2025,7 +2017,7 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
        if (error)
                goto fail_unregister;
 
-       error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, IRQF_DISABLED,
+       error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, 0,
                            "serial RX", state);
        if (error)
                goto fail_free_irq;
index c0e8f2e..c9bf779 100644 (file)
@@ -45,7 +45,6 @@
 #undef CY_DEBUG_IO
 #undef CY_DEBUG_COUNT
 #undef CY_DEBUG_DTR
-#undef CY_DEBUG_WAIT_UNTIL_SENT
 #undef CY_DEBUG_INTERRUPTS
 #undef CY_16Y_HACK
 #undef CY_ENABLE_MONITORING
@@ -1678,16 +1677,10 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
         */
        if (!timeout || timeout > 2 * info->timeout)
                timeout = 2 * info->timeout;
-#ifdef CY_DEBUG_WAIT_UNTIL_SENT
-       printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
-               timeout, char_time, jiffies);
-#endif
+
        card = info->card;
        if (!cy_is_Z(card)) {
                while (cyy_readb(info, CySRER) & CyTxRdy) {
-#ifdef CY_DEBUG_WAIT_UNTIL_SENT
-                       printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
-#endif
                        if (msleep_interruptible(jiffies_to_msecs(char_time)))
                                break;
                        if (timeout && time_after(jiffies, orig_jiffies +
@@ -1697,9 +1690,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
        }
        /* Run one more char cycle */
        msleep_interruptible(jiffies_to_msecs(char_time * 5));
-#ifdef CY_DEBUG_WAIT_UNTIL_SENT
-       printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
-#endif
 }
 
 static void cy_flush_buffer(struct tty_struct *tty)
@@ -3377,7 +3367,7 @@ static int __init cy_detect_isa(void)
 
                /* allocate IRQ */
                if (request_irq(cy_isa_irq, cyy_interrupt,
-                               IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
+                               0, "Cyclom-Y", &cy_card[j])) {
                        printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
                                "could not allocate IRQ#%d.\n",
                                (unsigned long)cy_isa_address, cy_isa_irq);
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
new file mode 100644 (file)
index 0000000..1595dba
--- /dev/null
@@ -0,0 +1,881 @@
+/* ePAPR hypervisor byte channel device driver
+ *
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * This driver support three distinct interfaces, all of which are related to
+ * ePAPR hypervisor byte channels.
+ *
+ * 1) An early-console (udbg) driver.  This provides early console output
+ * through a byte channel.  The byte channel handle must be specified in a
+ * Kconfig option.
+ *
+ * 2) A normal console driver.  Output is sent to the byte channel designated
+ * for stdout in the device tree.  The console driver is for handling kernel
+ * printk calls.
+ *
+ * 3) A tty driver, which is used to handle user-space input and output.  The
+ * byte channel used for the console is designated as the default tty.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <asm/epapr_hcalls.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/circ_buf.h>
+#include <asm/udbg.h>
+
+/* The size of the transmit circular buffer.  This must be a power of two. */
+#define BUF_SIZE       2048
+
+/* Per-byte channel private data */
+struct ehv_bc_data {
+       struct device *dev;
+       struct tty_port port;
+       uint32_t handle;
+       unsigned int rx_irq;
+       unsigned int tx_irq;
+
+       spinlock_t lock;        /* lock for transmit buffer */
+       unsigned char buf[BUF_SIZE];    /* transmit circular buffer */
+       unsigned int head;      /* circular buffer head */
+       unsigned int tail;      /* circular buffer tail */
+
+       int tx_irq_enabled;     /* true == TX interrupt is enabled */
+};
+
+/* Array of byte channel objects */
+static struct ehv_bc_data *bcs;
+
+/* Byte channel handle for stdout (and stdin), taken from device tree */
+static unsigned int stdout_bc;
+
+/* Virtual IRQ for the byte channel handle for stdin, taken from device tree */
+static unsigned int stdout_irq;
+
+/**************************** SUPPORT FUNCTIONS ****************************/
+
+/*
+ * Enable the transmit interrupt
+ *
+ * Unlike a serial device, byte channels have no mechanism for disabling their
+ * own receive or transmit interrupts.  To emulate that feature, we toggle
+ * the IRQ in the kernel.
+ *
+ * We cannot just blindly call enable_irq() or disable_irq(), because these
+ * calls are reference counted.  This means that we cannot call enable_irq()
+ * if interrupts are already enabled.  This can happen in two situations:
+ *
+ * 1. The tty layer makes two back-to-back calls to ehv_bc_tty_write()
+ * 2. A transmit interrupt occurs while executing ehv_bc_tx_dequeue()
+ *
+ * To work around this, we keep a flag to tell us if the IRQ is enabled or not.
+ */
+static void enable_tx_interrupt(struct ehv_bc_data *bc)
+{
+       if (!bc->tx_irq_enabled) {
+               enable_irq(bc->tx_irq);
+               bc->tx_irq_enabled = 1;
+       }
+}
+
+static void disable_tx_interrupt(struct ehv_bc_data *bc)
+{
+       if (bc->tx_irq_enabled) {
+               disable_irq_nosync(bc->tx_irq);
+               bc->tx_irq_enabled = 0;
+       }
+}
+
+/*
+ * find the byte channel handle to use for the console
+ *
+ * The byte channel to be used for the console is specified via a "stdout"
+ * property in the /chosen node.
+ *
+ * For compatible with legacy device trees, we also look for a "stdout" alias.
+ */
+static int find_console_handle(void)
+{
+       struct device_node *np, *np2;
+       const char *sprop = NULL;
+       const uint32_t *iprop;
+
+       np = of_find_node_by_path("/chosen");
+       if (np)
+               sprop = of_get_property(np, "stdout-path", NULL);
+
+       if (!np || !sprop) {
+               of_node_put(np);
+               np = of_find_node_by_name(NULL, "aliases");
+               if (np)
+                       sprop = of_get_property(np, "stdout", NULL);
+       }
+
+       if (!sprop) {
+               of_node_put(np);
+               return 0;
+       }
+
+       /* We don't care what the aliased node is actually called.  We only
+        * care if it's compatible with "epapr,hv-byte-channel", because that
+        * indicates that it's a byte channel node.  We use a temporary
+        * variable, 'np2', because we can't release 'np' until we're done with
+        * 'sprop'.
+        */
+       np2 = of_find_node_by_path(sprop);
+       of_node_put(np);
+       np = np2;
+       if (!np) {
+               pr_warning("ehv-bc: stdout node '%s' does not exist\n", sprop);
+               return 0;
+       }
+
+       /* Is it a byte channel? */
+       if (!of_device_is_compatible(np, "epapr,hv-byte-channel")) {
+               of_node_put(np);
+               return 0;
+       }
+
+       stdout_irq = irq_of_parse_and_map(np, 0);
+       if (stdout_irq == NO_IRQ) {
+               pr_err("ehv-bc: no 'interrupts' property in %s node\n", sprop);
+               of_node_put(np);
+               return 0;
+       }
+
+       /*
+        * The 'hv-handle' property contains the handle for this byte channel.
+        */
+       iprop = of_get_property(np, "hv-handle", NULL);
+       if (!iprop) {
+               pr_err("ehv-bc: no 'hv-handle' property in %s node\n",
+                      np->name);
+               of_node_put(np);
+               return 0;
+       }
+       stdout_bc = be32_to_cpu(*iprop);
+
+       of_node_put(np);
+       return 1;
+}
+
+/*************************** EARLY CONSOLE DRIVER ***************************/
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC
+
+/*
+ * send a byte to a byte channel, wait if necessary
+ *
+ * This function sends a byte to a byte channel, and it waits and
+ * retries if the byte channel is full.  It returns if the character
+ * has been sent, or if some error has occurred.
+ *
+ */
+static void byte_channel_spin_send(const char data)
+{
+       int ret, count;
+
+       do {
+               count = 1;
+               ret = ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
+                                          &count, &data);
+       } while (ret == EV_EAGAIN);
+}
+
+/*
+ * The udbg subsystem calls this function to display a single character.
+ * We convert CR to a CR/LF.
+ */
+static void ehv_bc_udbg_putc(char c)
+{
+       if (c == '\n')
+               byte_channel_spin_send('\r');
+
+       byte_channel_spin_send(c);
+}
+
+/*
+ * early console initialization
+ *
+ * PowerPC kernels support an early printk console, also known as udbg.
+ * This function must be called via the ppc_md.init_early function pointer.
+ * At this point, the device tree has been unflattened, so we can obtain the
+ * byte channel handle for stdout.
+ *
+ * We only support displaying of characters (putc).  We do not support
+ * keyboard input.
+ */
+void __init udbg_init_ehv_bc(void)
+{
+       unsigned int rx_count, tx_count;
+       unsigned int ret;
+
+       /* Verify the byte channel handle */
+       ret = ev_byte_channel_poll(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
+                                  &rx_count, &tx_count);
+       if (ret)
+               return;
+
+       udbg_putc = ehv_bc_udbg_putc;
+       register_early_udbg_console();
+
+       udbg_printf("ehv-bc: early console using byte channel handle %u\n",
+                   CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE);
+}
+
+#endif
+
+/****************************** CONSOLE DRIVER ******************************/
+
+static struct tty_driver *ehv_bc_driver;
+
+/*
+ * Byte channel console sending worker function.
+ *
+ * For consoles, if the output buffer is full, we should just spin until it
+ * clears.
+ */
+static int ehv_bc_console_byte_channel_send(unsigned int handle, const char *s,
+                            unsigned int count)
+{
+       unsigned int len;
+       int ret = 0;
+
+       while (count) {
+               len = min_t(unsigned int, count, EV_BYTE_CHANNEL_MAX_BYTES);
+               do {
+                       ret = ev_byte_channel_send(handle, &len, s);
+               } while (ret == EV_EAGAIN);
+               count -= len;
+               s += len;
+       }
+
+       return ret;
+}
+
+/*
+ * write a string to the console
+ *
+ * This function gets called to write a string from the kernel, typically from
+ * a printk().  This function spins until all data is written.
+ *
+ * We copy the data to a temporary buffer because we need to insert a \r in
+ * front of every \n.  It's more efficient to copy the data to the buffer than
+ * it is to make multiple hcalls for each character or each newline.
+ */
+static void ehv_bc_console_write(struct console *co, const char *s,
+                                unsigned int count)
+{
+       char s2[EV_BYTE_CHANNEL_MAX_BYTES];
+       unsigned int i, j = 0;
+       char c;
+
+       for (i = 0; i < count; i++) {
+               c = *s++;
+
+               if (c == '\n')
+                       s2[j++] = '\r';
+
+               s2[j++] = c;
+               if (j >= (EV_BYTE_CHANNEL_MAX_BYTES - 1)) {
+                       if (ehv_bc_console_byte_channel_send(stdout_bc, s2, j))
+                               return;
+                       j = 0;
+               }
+       }
+
+       if (j)
+               ehv_bc_console_byte_channel_send(stdout_bc, s2, j);
+}
+
+/*
+ * When /dev/console is opened, the kernel iterates the console list looking
+ * for one with ->device and then calls that method. On success, it expects
+ * the passed-in int* to contain the minor number to use.
+ */
+static struct tty_driver *ehv_bc_console_device(struct console *co, int *index)
+{
+       *index = co->index;
+
+       return ehv_bc_driver;
+}
+
+static struct console ehv_bc_console = {
+       .name           = "ttyEHV",
+       .write          = ehv_bc_console_write,
+       .device         = ehv_bc_console_device,
+       .flags          = CON_PRINTBUFFER | CON_ENABLED,
+};
+
+/*
+ * Console initialization
+ *
+ * This is the first function that is called after the device tree is
+ * available, so here is where we determine the byte channel handle and IRQ for
+ * stdout/stdin, even though that information is used by the tty and character
+ * drivers.
+ */
+static int __init ehv_bc_console_init(void)
+{
+       if (!find_console_handle()) {
+               pr_debug("ehv-bc: stdout is not a byte channel\n");
+               return -ENODEV;
+       }
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC
+       /* Print a friendly warning if the user chose the wrong byte channel
+        * handle for udbg.
+        */
+       if (stdout_bc != CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE)
+               pr_warning("ehv-bc: udbg handle %u is not the stdout handle\n",
+                          CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE);
+#endif
+
+       /* add_preferred_console() must be called before register_console(),
+          otherwise it won't work.  However, we don't want to enumerate all the
+          byte channels here, either, since we only care about one. */
+
+       add_preferred_console(ehv_bc_console.name, ehv_bc_console.index, NULL);
+       register_console(&ehv_bc_console);
+
+       pr_info("ehv-bc: registered console driver for byte channel %u\n",
+               stdout_bc);
+
+       return 0;
+}
+console_initcall(ehv_bc_console_init);
+
+/******************************** TTY DRIVER ********************************/
+
+/*
+ * byte channel receive interupt handler
+ *
+ * This ISR is called whenever data is available on a byte channel.
+ */
+static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data)
+{
+       struct ehv_bc_data *bc = data;
+       struct tty_struct *ttys = tty_port_tty_get(&bc->port);
+       unsigned int rx_count, tx_count, len;
+       int count;
+       char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
+       int ret;
+
+       /* ttys could be NULL during a hangup */
+       if (!ttys)
+               return IRQ_HANDLED;
+
+       /* Find out how much data needs to be read, and then ask the TTY layer
+        * if it can handle that much.  We want to ensure that every byte we
+        * read from the byte channel will be accepted by the TTY layer.
+        */
+       ev_byte_channel_poll(bc->handle, &rx_count, &tx_count);
+       count = tty_buffer_request_room(ttys, rx_count);
+
+       /* 'count' is the maximum amount of data the TTY layer can accept at
+        * this time.  However, during testing, I was never able to get 'count'
+        * to be less than 'rx_count'.  I'm not sure whether I'm calling it
+        * correctly.
+        */
+
+       while (count > 0) {
+               len = min_t(unsigned int, count, sizeof(buffer));
+
+               /* Read some data from the byte channel.  This function will
+                * never return more than EV_BYTE_CHANNEL_MAX_BYTES bytes.
+                */
+               ev_byte_channel_receive(bc->handle, &len, buffer);
+
+               /* 'len' is now the amount of data that's been received. 'len'
+                * can't be zero, and most likely it's equal to one.
+                */
+
+               /* Pass the received data to the tty layer. */
+               ret = tty_insert_flip_string(ttys, buffer, len);
+
+               /* 'ret' is the number of bytes that the TTY layer accepted.
+                * If it's not equal to 'len', then it means the buffer is
+                * full, which should never happen.  If it does happen, we can
+                * exit gracefully, but we drop the last 'len - ret' characters
+                * that we read from the byte channel.
+                */
+               if (ret != len)
+                       break;
+
+               count -= len;
+       }
+
+       /* Tell the tty layer that we're done. */
+       tty_flip_buffer_push(ttys);
+
+       tty_kref_put(ttys);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * dequeue the transmit buffer to the hypervisor
+ *
+ * This function, which can be called in interrupt context, dequeues as much
+ * data as possible from the transmit buffer to the byte channel.
+ */
+static void ehv_bc_tx_dequeue(struct ehv_bc_data *bc)
+{
+       unsigned int count;
+       unsigned int len, ret;
+       unsigned long flags;
+
+       do {
+               spin_lock_irqsave(&bc->lock, flags);
+               len = min_t(unsigned int,
+                           CIRC_CNT_TO_END(bc->head, bc->tail, BUF_SIZE),
+                           EV_BYTE_CHANNEL_MAX_BYTES);
+
+               ret = ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail);
+
+               /* 'len' is valid only if the return code is 0 or EV_EAGAIN */
+               if (!ret || (ret == EV_EAGAIN))
+                       bc->tail = (bc->tail + len) & (BUF_SIZE - 1);
+
+               count = CIRC_CNT(bc->head, bc->tail, BUF_SIZE);
+               spin_unlock_irqrestore(&bc->lock, flags);
+       } while (count && !ret);
+
+       spin_lock_irqsave(&bc->lock, flags);
+       if (CIRC_CNT(bc->head, bc->tail, BUF_SIZE))
+               /*
+                * If we haven't emptied the buffer, then enable the TX IRQ.
+                * We'll get an interrupt when there's more room in the
+                * hypervisor's output buffer.
+                */
+               enable_tx_interrupt(bc);
+       else
+               disable_tx_interrupt(bc);
+       spin_unlock_irqrestore(&bc->lock, flags);
+}
+
+/*
+ * byte channel transmit interupt handler
+ *
+ * This ISR is called whenever space becomes available for transmitting
+ * characters on a byte channel.
+ */
+static irqreturn_t ehv_bc_tty_tx_isr(int irq, void *data)
+{
+       struct ehv_bc_data *bc = data;
+       struct tty_struct *ttys = tty_port_tty_get(&bc->port);
+
+       ehv_bc_tx_dequeue(bc);
+       if (ttys) {
+               tty_wakeup(ttys);
+               tty_kref_put(ttys);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * This function is called when the tty layer has data for us send.  We store
+ * the data first in a circular buffer, and then dequeue as much of that data
+ * as possible.
+ *
+ * We don't need to worry about whether there is enough room in the buffer for
+ * all the data.  The purpose of ehv_bc_tty_write_room() is to tell the tty
+ * layer how much data it can safely send to us.  We guarantee that
+ * ehv_bc_tty_write_room() will never lie, so the tty layer will never send us
+ * too much data.
+ */
+static int ehv_bc_tty_write(struct tty_struct *ttys, const unsigned char *s,
+                           int count)
+{
+       struct ehv_bc_data *bc = ttys->driver_data;
+       unsigned long flags;
+       unsigned int len;
+       unsigned int written = 0;
+
+       while (1) {
+               spin_lock_irqsave(&bc->lock, flags);
+               len = CIRC_SPACE_TO_END(bc->head, bc->tail, BUF_SIZE);
+               if (count < len)
+                       len = count;
+               if (len) {
+                       memcpy(bc->buf + bc->head, s, len);
+                       bc->head = (bc->head + len) & (BUF_SIZE - 1);
+               }
+               spin_unlock_irqrestore(&bc->lock, flags);
+               if (!len)
+                       break;
+
+               s += len;
+               count -= len;
+               written += len;
+       }
+
+       ehv_bc_tx_dequeue(bc);
+
+       return written;
+}
+
+/*
+ * This function can be called multiple times for a given tty_struct, which is
+ * why we initialize bc->ttys in ehv_bc_tty_port_activate() instead.
+ *
+ * The tty layer will still call this function even if the device was not
+ * registered (i.e. tty_register_device() was not called).  This happens
+ * because tty_register_device() is optional and some legacy drivers don't
+ * use it.  So we need to check for that.
+ */
+static int ehv_bc_tty_open(struct tty_struct *ttys, struct file *filp)
+{
+       struct ehv_bc_data *bc = &bcs[ttys->index];
+
+       if (!bc->dev)
+               return -ENODEV;
+
+       return tty_port_open(&bc->port, ttys, filp);
+}
+
+/*
+ * Amazingly, if ehv_bc_tty_open() returns an error code, the tty layer will
+ * still call this function to close the tty device.  So we can't assume that
+ * the tty port has been initialized.
+ */
+static void ehv_bc_tty_close(struct tty_struct *ttys, struct file *filp)
+{
+       struct ehv_bc_data *bc = &bcs[ttys->index];
+
+       if (bc->dev)
+               tty_port_close(&bc->port, ttys, filp);
+}
+
+/*
+ * Return the amount of space in the output buffer
+ *
+ * This is actually a contract between the driver and the tty layer outlining
+ * how much write room the driver can guarantee will be sent OR BUFFERED.  This
+ * driver MUST honor the return value.
+ */
+static int ehv_bc_tty_write_room(struct tty_struct *ttys)
+{
+       struct ehv_bc_data *bc = ttys->driver_data;
+       unsigned long flags;
+       int count;
+
+       spin_lock_irqsave(&bc->lock, flags);
+       count = CIRC_SPACE(bc->head, bc->tail, BUF_SIZE);
+       spin_unlock_irqrestore(&bc->lock, flags);
+
+       return count;
+}
+
+/*
+ * Stop sending data to the tty layer
+ *
+ * This function is called when the tty layer's input buffers are getting full,
+ * so the driver should stop sending it data.  The easiest way to do this is to
+ * disable the RX IRQ, which will prevent ehv_bc_tty_rx_isr() from being
+ * called.
+ *
+ * The hypervisor will continue to queue up any incoming data.  If there is any
+ * data in the queue when the RX interrupt is enabled, we'll immediately get an
+ * RX interrupt.
+ */
+static void ehv_bc_tty_throttle(struct tty_struct *ttys)
+{
+       struct ehv_bc_data *bc = ttys->driver_data;
+
+       disable_irq(bc->rx_irq);
+}
+
+/*
+ * Resume sending data to the tty layer
+ *
+ * This function is called after previously calling ehv_bc_tty_throttle().  The
+ * tty layer's input buffers now have more room, so the driver can resume
+ * sending it data.
+ */
+static void ehv_bc_tty_unthrottle(struct tty_struct *ttys)
+{
+       struct ehv_bc_data *bc = ttys->driver_data;
+
+       /* If there is any data in the queue when the RX interrupt is enabled,
+        * we'll immediately get an RX interrupt.
+        */
+       enable_irq(bc->rx_irq);
+}
+
+static void ehv_bc_tty_hangup(struct tty_struct *ttys)
+{
+       struct ehv_bc_data *bc = ttys->driver_data;
+
+       ehv_bc_tx_dequeue(bc);
+       tty_port_hangup(&bc->port);
+}
+
+/*
+ * TTY driver operations
+ *
+ * If we could ask the hypervisor how much data is still in the TX buffer, or
+ * at least how big the TX buffers are, then we could implement the
+ * .wait_until_sent and .chars_in_buffer functions.
+ */
+static const struct tty_operations ehv_bc_ops = {
+       .open           = ehv_bc_tty_open,
+       .close          = ehv_bc_tty_close,
+       .write          = ehv_bc_tty_write,
+       .write_room     = ehv_bc_tty_write_room,
+       .throttle       = ehv_bc_tty_throttle,
+       .unthrottle     = ehv_bc_tty_unthrottle,
+       .hangup         = ehv_bc_tty_hangup,
+};
+
+/*
+ * initialize the TTY port
+ *
+ * This function will only be called once, no matter how many times
+ * ehv_bc_tty_open() is called.  That's why we register the ISR here, and also
+ * why we initialize tty_struct-related variables here.
+ */
+static int ehv_bc_tty_port_activate(struct tty_port *port,
+                                   struct tty_struct *ttys)
+{
+       struct ehv_bc_data *bc = container_of(port, struct ehv_bc_data, port);
+       int ret;
+
+       ttys->driver_data = bc;
+
+       ret = request_irq(bc->rx_irq, ehv_bc_tty_rx_isr, 0, "ehv-bc", bc);
+       if (ret < 0) {
+               dev_err(bc->dev, "could not request rx irq %u (ret=%i)\n",
+                      bc->rx_irq, ret);
+               return ret;
+       }
+
+       /* request_irq also enables the IRQ */
+       bc->tx_irq_enabled = 1;
+
+       ret = request_irq(bc->tx_irq, ehv_bc_tty_tx_isr, 0, "ehv-bc", bc);
+       if (ret < 0) {
+               dev_err(bc->dev, "could not request tx irq %u (ret=%i)\n",
+                      bc->tx_irq, ret);
+               free_irq(bc->rx_irq, bc);
+               return ret;
+       }
+
+       /* The TX IRQ is enabled only when we can't write all the data to the
+        * byte channel at once, so by default it's disabled.
+        */
+       disable_tx_interrupt(bc);
+
+       return 0;
+}
+
+static void ehv_bc_tty_port_shutdown(struct tty_port *port)
+{
+       struct ehv_bc_data *bc = container_of(port, struct ehv_bc_data, port);
+
+       free_irq(bc->tx_irq, bc);
+       free_irq(bc->rx_irq, bc);
+}
+
+static const struct tty_port_operations ehv_bc_tty_port_ops = {
+       .activate = ehv_bc_tty_port_activate,
+       .shutdown = ehv_bc_tty_port_shutdown,
+};
+
+static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct ehv_bc_data *bc;
+       const uint32_t *iprop;
+       unsigned int handle;
+       int ret;
+       static unsigned int index = 1;
+       unsigned int i;
+
+       iprop = of_get_property(np, "hv-handle", NULL);
+       if (!iprop) {
+               dev_err(&pdev->dev, "no 'hv-handle' property in %s node\n",
+                       np->name);
+               return -ENODEV;
+       }
+
+       /* We already told the console layer that the index for the console
+        * device is zero, so we need to make sure that we use that index when
+        * we probe the console byte channel node.
+        */
+       handle = be32_to_cpu(*iprop);
+       i = (handle == stdout_bc) ? 0 : index++;
+       bc = &bcs[i];
+
+       bc->handle = handle;
+       bc->head = 0;
+       bc->tail = 0;
+       spin_lock_init(&bc->lock);
+
+       bc->rx_irq = irq_of_parse_and_map(np, 0);
+       bc->tx_irq = irq_of_parse_and_map(np, 1);
+       if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) {
+               dev_err(&pdev->dev, "no 'interrupts' property in %s node\n",
+                       np->name);
+               ret = -ENODEV;
+               goto error;
+       }
+
+       bc->dev = tty_register_device(ehv_bc_driver, i, &pdev->dev);
+       if (IS_ERR(bc->dev)) {
+               ret = PTR_ERR(bc->dev);
+               dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret);
+               goto error;
+       }
+
+       tty_port_init(&bc->port);
+       bc->port.ops = &ehv_bc_tty_port_ops;
+
+       dev_set_drvdata(&pdev->dev, bc);
+
+       dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n",
+               ehv_bc_driver->name, i, bc->handle);
+
+       return 0;
+
+error:
+       irq_dispose_mapping(bc->tx_irq);
+       irq_dispose_mapping(bc->rx_irq);
+
+       memset(bc, 0, sizeof(struct ehv_bc_data));
+       return ret;
+}
+
+static int ehv_bc_tty_remove(struct platform_device *pdev)
+{
+       struct ehv_bc_data *bc = dev_get_drvdata(&pdev->dev);
+
+       tty_unregister_device(ehv_bc_driver, bc - bcs);
+
+       irq_dispose_mapping(bc->tx_irq);
+       irq_dispose_mapping(bc->rx_irq);
+
+       return 0;
+}
+
+static const struct of_device_id ehv_bc_tty_of_ids[] = {
+       { .compatible = "epapr,hv-byte-channel" },
+       {}
+};
+
+static struct platform_driver ehv_bc_tty_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "ehv-bc",
+               .of_match_table = ehv_bc_tty_of_ids,
+       },
+       .probe          = ehv_bc_tty_probe,
+       .remove         = ehv_bc_tty_remove,
+};
+
+/**
+ * ehv_bc_init - ePAPR hypervisor byte channel driver initialization
+ *
+ * This function is called when this module is loaded.
+ */
+static int __init ehv_bc_init(void)
+{
+       struct device_node *np;
+       unsigned int count = 0; /* Number of elements in bcs[] */
+       int ret;
+
+       pr_info("ePAPR hypervisor byte channel driver\n");
+
+       /* Count the number of byte channels */
+       for_each_compatible_node(np, NULL, "epapr,hv-byte-channel")
+               count++;
+
+       if (!count)
+               return -ENODEV;
+
+       /* The array index of an element in bcs[] is the same as the tty index
+        * for that element.  If you know the address of an element in the
+        * array, then you can use pointer math (e.g. "bc - bcs") to get its
+        * tty index.
+        */
+       bcs = kzalloc(count * sizeof(struct ehv_bc_data), GFP_KERNEL);
+       if (!bcs)
+               return -ENOMEM;
+
+       ehv_bc_driver = alloc_tty_driver(count);
+       if (!ehv_bc_driver) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       ehv_bc_driver->owner = THIS_MODULE;
+       ehv_bc_driver->driver_name = "ehv-bc";
+       ehv_bc_driver->name = ehv_bc_console.name;
+       ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+       ehv_bc_driver->subtype = SYSTEM_TYPE_CONSOLE;
+       ehv_bc_driver->init_termios = tty_std_termios;
+       ehv_bc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       tty_set_operations(ehv_bc_driver, &ehv_bc_ops);
+
+       ret = tty_register_driver(ehv_bc_driver);
+       if (ret) {
+               pr_err("ehv-bc: could not register tty driver (ret=%i)\n", ret);
+               goto error;
+       }
+
+       ret = platform_driver_register(&ehv_bc_tty_driver);
+       if (ret) {
+               pr_err("ehv-bc: could not register platform driver (ret=%i)\n",
+                      ret);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       if (ehv_bc_driver) {
+               tty_unregister_driver(ehv_bc_driver);
+               put_tty_driver(ehv_bc_driver);
+       }
+
+       kfree(bcs);
+
+       return ret;
+}
+
+
+/**
+ * ehv_bc_exit - ePAPR hypervisor byte channel driver termination
+ *
+ * This function is called when this driver is unloaded.
+ */
+static void __exit ehv_bc_exit(void)
+{
+       tty_unregister_driver(ehv_bc_driver);
+       put_tty_driver(ehv_bc_driver);
+       kfree(bcs);
+}
+
+module_init(ehv_bc_init);
+module_exit(ehv_bc_exit);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("ePAPR hypervisor byte channel driver");
+MODULE_LICENSE("GPL v2");
index e1aaf4f..7430bc3 100644 (file)
@@ -388,7 +388,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
                 * there is no buffered data otherwise sleeps on a wait queue
                 * waking periodically to check chars_in_buffer().
                 */
-               tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
+               tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
        } else {
                if (hp->count < 0)
                        printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
@@ -852,7 +852,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
         * find index to use:
         * see if this vterm id matches one registered for console.
         */
-       for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
+       for (i = 0; i < MAX_NR_HVC_CONSOLES; i++)
                if (vtermnos[i] == hp->vtermno &&
                    cons_ops[i] == hp->ops)
                        break;
@@ -862,9 +862,13 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
                i = ++last_hvc;
 
        hp->index = i;
+       hvc_console.index = i;
+       vtermnos[i] = vtermno;
+       cons_ops[i] = ops;
 
        list_add_tail(&(hp->next), &hvc_structs);
        spin_unlock(&hvc_structs_lock);
+       register_console(&hvc_console);
 
        return hp;
 }
@@ -875,6 +879,7 @@ int hvc_remove(struct hvc_struct *hp)
        unsigned long flags;
        struct tty_struct *tty;
 
+       unregister_console(&hvc_console);
        spin_lock_irqsave(&hp->lock, flags);
        tty = tty_kref_get(hp->tty);
 
index 2623e17..c9adb05 100644 (file)
@@ -28,7 +28,7 @@ int notifier_add_irq(struct hvc_struct *hp, int irq)
                hp->irq_requested = 0;
                return 0;
        }
-       rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED,
+       rc = request_irq(irq, hvc_handle_interrupt, 0,
                           "hvc_console", hp);
        if (!rc)
                hp->irq_requested = 1;
index 4c8b665..55882b5 100644 (file)
@@ -1057,7 +1057,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
         * the conn was registered and now.
         */
        if (!(rc = request_irq(irq, &hvcs_handle_interrupt,
-                               IRQF_DISABLED, "ibmhvcs", hvcsd))) {
+                               0, "ibmhvcs", hvcsd))) {
                /*
                 * It is possible the vty-server was removed after the irq was
                 * requested but before we have time to enable interrupts.
@@ -1237,7 +1237,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
                irq = hvcsd->vdev->irq;
                spin_unlock_irqrestore(&hvcsd->lock, flags);
 
-               tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
+               tty_wait_until_sent_from_close(tty, HVCS_CLOSE_WAIT);
 
                /*
                 * This line is important because it tells hvcs_open that this
index c94e2f5..cdfa3e0 100644 (file)
@@ -1105,7 +1105,7 @@ static int __init hvsi_init(void)
                struct hvsi_struct *hp = &hvsi_ports[i];
                int ret = 1;
 
-               ret = request_irq(hp->virq, hvsi_interrupt, IRQF_DISABLED, "hvsi", hp);
+               ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp);
                if (ret)
                        printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
                                hp->virq, ret);
index db1cf9c..e5c295a 100644 (file)
@@ -1598,7 +1598,7 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
        }
 
        retval = request_irq(board->irq, isicom_interrupt,
-                       IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
+                       IRQF_SHARED, ISICOM_NAME, board);
        if (retval < 0) {
                dev_err(&pdev->dev, "Could not install handler at Irq %d. "
                        "Card%d will be disabled.\n", board->irq, index + 1);
index 7fc8c02..8998d52 100644 (file)
@@ -2005,16 +2005,9 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
         */
        if (!timeout || timeout > 2 * info->timeout)
                timeout = 2 * info->timeout;
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
-               timeout, char_time);
-       printk("jiff=%lu...", jiffies);
-#endif
+
        spin_lock_irqsave(&info->slock, flags);
        while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
                spin_unlock_irqrestore(&info->slock, flags);
                schedule_timeout_interruptible(char_time);
                spin_lock_irqsave(&info->slock, flags);
@@ -2025,10 +2018,6 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
        }
        spin_unlock_irqrestore(&info->slock, flags);
        set_current_state(TASK_RUNNING);
-
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
 }
 
 /*
index 8a50e4e..4cb0d0a 100644 (file)
@@ -21,7 +21,6 @@
  *     Mostly done:    ioctls for setting modes/timing
  *     Partly done:    hooks so you can pull off frames to non tty devs
  *     Restart DLCI 0 when it closes ?
- *     Test basic encoding
  *     Improve the tx engine
  *     Resolve tx side locking by adding a queue_head and routing
  *             all control traffic via it
@@ -810,38 +809,41 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
 {
        struct gsm_msg *msg;
        u8 *dp;
-       int len, size;
+       int len, total_size, size;
        int h = dlci->adaption - 1;
 
-       len = kfifo_len(dlci->fifo);
-       if (len == 0)
-               return 0;
-
-       /* MTU/MRU count only the data bits */
-       if (len > gsm->mtu)
-               len = gsm->mtu;
-
-       size = len + h;
-
-       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
-       /* FIXME: need a timer or something to kick this so it can't
-          get stuck with no work outstanding and no buffer free */
-       if (msg == NULL)
-               return -ENOMEM;
-       dp = msg->data;
-       switch (dlci->adaption) {
-       case 1: /* Unstructured */
-               break;
-       case 2: /* Unstructed with modem bits. Always one byte as we never
-                  send inline break data */
-               *dp += gsm_encode_modem(dlci);
-               len--;
-               break;
+       total_size = 0;
+       while(1) {
+               len = kfifo_len(dlci->fifo);
+               if (len == 0)
+                       return total_size;
+
+               /* MTU/MRU count only the data bits */
+               if (len > gsm->mtu)
+                       len = gsm->mtu;
+
+               size = len + h;
+
+               msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+               /* FIXME: need a timer or something to kick this so it can't
+                  get stuck with no work outstanding and no buffer free */
+               if (msg == NULL)
+                       return -ENOMEM;
+               dp = msg->data;
+               switch (dlci->adaption) {
+               case 1: /* Unstructured */
+                       break;
+               case 2: /* Unstructed with modem bits. Always one byte as we never
+                          send inline break data */
+                       *dp++ = gsm_encode_modem(dlci);
+                       break;
+               }
+               WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
+               __gsm_data_queue(dlci, msg);
+               total_size += size;
        }
-       WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
-       __gsm_data_queue(dlci, msg);
        /* Bytes of data we used up */
-       return size;
+       return total_size;
 }
 
 /**
@@ -2004,6 +2006,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
        int i;
        struct gsm_dlci *dlci = gsm->dlci[0];
        struct gsm_msg *txq;
+       struct gsm_control *gc;
 
        gsm->dead = 1;
 
@@ -2017,6 +2020,13 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
        spin_unlock(&gsm_mux_lock);
        WARN_ON(i == MAX_MUX);
 
+       /* In theory disconnecting DLCI 0 is sufficient but for some
+          modems this is apparently not the case. */
+       if (dlci) {
+               gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
+               if (gc)
+                       gsm_control_wait(gsm, gc);
+       }
        del_timer_sync(&gsm->t2_timer);
        /* Now we are sure T2 has stopped */
        if (dlci) {
@@ -2982,7 +2992,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
        struct gsm_dlci *dlci = tty->driver_data;
        unsigned int modem_tx = dlci->modem_tx;
 
-       modem_tx &= clear;
+       modem_tx &= ~clear;
        modem_tx |= set;
 
        if (modem_tx != dlci->modem_tx) {
index e809e9d..e18604b 100644 (file)
@@ -670,12 +670,18 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 
        nonseekable_open(inode, filp);
 
+       retval = tty_alloc_file(filp);
+       if (retval)
+               return retval;
+
        /* find a device that is not in use. */
        tty_lock();
        index = devpts_new_index(inode);
        tty_unlock();
-       if (index < 0)
-               return index;
+       if (index < 0) {
+               retval = index;
+               goto err_file;
+       }
 
        mutex_lock(&tty_mutex);
        tty_lock();
@@ -689,27 +695,27 @@ static int ptmx_open(struct inode *inode, struct file *filp)
 
        set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 
-       retval = tty_add_file(tty, filp);
-       if (retval)
-               goto out;
+       tty_add_file(tty, filp);
 
        retval = devpts_pty_new(inode, tty->link);
        if (retval)
-               goto out1;
+               goto err_release;
 
        retval = ptm_driver->ops->open(tty, filp);
        if (retval)
-               goto out2;
-out1:
+               goto err_release;
+
        tty_unlock();
-       return retval;
-out2:
+       return 0;
+err_release:
        tty_unlock();
        tty_release(inode, filp);
        return retval;
 out:
        devpts_kill_index(inode, index);
        tty_unlock();
+err_file:
+       tty_free_file(filp);
        return retval;
 }
 
index e0a7754..a88ef97 100644 (file)
@@ -235,22 +235,6 @@ static void batten_down_hatches(void)
 
 static void status_handle(struct m68k_serial *info, unsigned short status)
 {
-#if 0
-       if(status & DCD) {
-               if((info->port.tty->termios->c_cflag & CRTSCTS) &&
-                  ((info->curregs[3] & AUTO_ENAB)==0)) {
-                       info->curregs[3] |= AUTO_ENAB;
-                       info->pendregs[3] |= AUTO_ENAB;
-                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
-               }
-       } else {
-               if((info->curregs[3] & AUTO_ENAB)) {
-                       info->curregs[3] &= ~AUTO_ENAB;
-                       info->pendregs[3] &= ~AUTO_ENAB;
-                       write_zsreg(info->m68k_channel, 3, info->curregs[3]);
-               }
-       }
-#endif
        /* If this is console input and this is a
         * 'break asserted' status change interrupt
         * see if we can drop into the debugger
@@ -340,9 +324,6 @@ static void transmit_chars(struct m68k_serial *info)
        info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
        info->xmit_cnt--;
 
-       if (info->xmit_cnt < WAKEUP_CHARS)
-               schedule_work(&info->tqueue);
-
        if(info->xmit_cnt <= 0) {
                /* All done for now... TX ints off */
                uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
@@ -378,21 +359,6 @@ irqreturn_t rs_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void do_softint(struct work_struct *work)
-{
-       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue);
-       struct tty_struct       *tty;
-       
-       tty = info->tty;
-       if (!tty)
-               return;
-#if 0
-       if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
-               tty_wakeup(tty);
-       }
-#endif   
-}
-
 static int startup(struct m68k_serial * info)
 {
        m68328_uart *uart = &uart_addr[info->line];
@@ -1324,7 +1290,6 @@ rs68328_init(void)
            info->event = 0;
            info->count = 0;
            info->blocked_open = 0;
-           INIT_WORK(&info->tqueue, do_softint);
            init_waitqueue_head(&info->open_wait);
            init_waitqueue_head(&info->close_wait);
            info->line = i;
@@ -1341,7 +1306,7 @@ rs68328_init(void)
 
            if (request_irq(uart_irqs[i],
                            rs_interrupt,
-                           IRQF_DISABLED,
+                           0,
                            "M68328_UART", info))
                 panic("Unable to attach 68328 serial interrupt\n");
        }
index 8c9c3c0..3d2faab 100644 (file)
@@ -158,7 +158,6 @@ struct m68k_serial {
        int                     xmit_head;
        int                     xmit_tail;
        int                     xmit_cnt;
-       struct work_struct      tqueue;
        wait_queue_head_t       open_wait;
        wait_queue_head_t       close_wait;
 };
index 7f50999..a87a56c 100644 (file)
@@ -309,6 +309,13 @@ static const struct serial8250_config uart_config[] = {
                                  UART_FCR_T_TRIG_01,
                .flags          = UART_CAP_FIFO | UART_CAP_RTOIE,
        },
+       [PORT_XR17D15X] = {
+               .name           = "XR17D15X",
+               .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,
+       },
 };
 
 #if defined(CONFIG_MIPS_ALCHEMY)
@@ -461,42 +468,6 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value)
                writeb(value, p->membase + offset);
 }
 
-/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
-static inline void dwapb_save_out_value(struct uart_port *p, int offset,
-                                       int value)
-{
-       struct uart_8250_port *up =
-               container_of(p, struct uart_8250_port, port);
-
-       if (offset == UART_LCR)
-               up->lcr = value;
-}
-
-/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
-static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
-{
-       if (offset == UART_TX || offset == UART_IER)
-               p->serial_in(p, UART_IER);
-}
-
-static void dwapb_serial_out(struct uart_port *p, int offset, int value)
-{
-       int save_offset = offset;
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       dwapb_save_out_value(p, save_offset, value);
-       writeb(value, p->membase + offset);
-       dwapb_check_clear_ier(p, save_offset);
-}
-
-static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
-{
-       int save_offset = offset;
-       offset = map_8250_out_reg(p, offset) << p->regshift;
-       dwapb_save_out_value(p, save_offset, value);
-       writel(value, p->membase + offset);
-       dwapb_check_clear_ier(p, save_offset);
-}
-
 static unsigned int io_serial_in(struct uart_port *p, int offset)
 {
        offset = map_8250_in_reg(p, offset) << p->regshift;
@@ -509,6 +480,8 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
        outb(value, p->iobase + offset);
 }
 
+static int serial8250_default_handle_irq(struct uart_port *port);
+
 static void set_io_from_upio(struct uart_port *p)
 {
        struct uart_8250_port *up =
@@ -540,16 +513,6 @@ static void set_io_from_upio(struct uart_port *p)
                p->serial_out = tsi_serial_out;
                break;
 
-       case UPIO_DWAPB:
-               p->serial_in = mem_serial_in;
-               p->serial_out = dwapb_serial_out;
-               break;
-
-       case UPIO_DWAPB32:
-               p->serial_in = mem32_serial_in;
-               p->serial_out = dwapb32_serial_out;
-               break;
-
        default:
                p->serial_in = io_serial_in;
                p->serial_out = io_serial_out;
@@ -557,6 +520,7 @@ static void set_io_from_upio(struct uart_port *p)
        }
        /* Remember loaded iotype */
        up->cur_iotype = p->iotype;
+       p->handle_irq = serial8250_default_handle_irq;
 }
 
 static void
@@ -567,8 +531,6 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
        case UPIO_MEM:
        case UPIO_MEM32:
        case UPIO_AU:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                p->serial_out(p, offset, value);
                p->serial_in(p, UART_LCR);      /* safe, no side-effects */
                break;
@@ -1119,6 +1081,14 @@ static void autoconfig_16550a(struct uart_8250_port *up)
        }
        serial_outp(up, UART_IER, iersave);
 
+       /*
+        * Exar uarts have EFR in a weird location
+        */
+       if (up->port.flags & UPF_EXAR_EFR) {
+               up->port.type = PORT_XR17D15X;
+               up->capabilities |= UART_CAP_AFE | UART_CAP_EFR;
+       }
+
        /*
         * We distinguish between 16550A and U6 16550A by counting
         * how many bytes are in the FIFO.
@@ -1621,6 +1591,29 @@ static void serial8250_handle_port(struct uart_8250_port *up)
        spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       if (!(iir & UART_IIR_NO_INT)) {
+               serial8250_handle_port(up);
+               return 1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_handle_irq);
+
+static int serial8250_default_handle_irq(struct uart_port *port)
+{
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+       unsigned int iir = serial_in(up, UART_IIR);
+
+       return serial8250_handle_irq(port, iir);
+}
+
 /*
  * This is the serial driver's interrupt routine.
  *
@@ -1648,30 +1641,13 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
        l = i->head;
        do {
                struct uart_8250_port *up;
-               unsigned int iir;
+               struct uart_port *port;
 
                up = list_entry(l, struct uart_8250_port, list);
+               port = &up->port;
 
-               iir = serial_in(up, UART_IIR);
-               if (!(iir & UART_IIR_NO_INT)) {
-                       serial8250_handle_port(up);
-
+               if (port->handle_irq(port)) {
                        handled = 1;
-
-                       end = NULL;
-               } else if ((up->port.iotype == UPIO_DWAPB ||
-                           up->port.iotype == UPIO_DWAPB32) &&
-                         (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
-                       /* The DesignWare APB UART has an Busy Detect (0x07)
-                        * interrupt meaning an LCR write attempt occurred while the
-                        * UART was busy. The interrupt must be cleared by reading
-                        * the UART status register (USR) and the LCR re-written. */
-                       unsigned int status;
-                       status = *(volatile u32 *)up->port.private_data;
-                       serial_out(up, UART_LCR, up->lcr);
-
-                       handled = 1;
-
                        end = NULL;
                } else if (end == NULL)
                        end = l;
@@ -2081,8 +2057,8 @@ static int serial8250_startup(struct uart_port *port)
         */
        if (!(up->port.flags & UPF_BUGGY_UART) &&
            (serial_inp(up, UART_LSR) == 0xff)) {
-               printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
-                      serial_index(&up->port));
+               printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+                                  serial_index(&up->port));
                return -ENODEV;
        }
 
@@ -2458,7 +2434,10 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
                        efr |= UART_EFR_CTS;
 
                serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
-               serial_outp(up, UART_EFR, efr);
+               if (up->port.flags & UPF_EXAR_EFR)
+                       serial_outp(up, UART_XR_EFR, efr);
+               else
+                       serial_outp(up, UART_EFR, efr);
        }
 
 #ifdef CONFIG_ARCH_OMAP
@@ -2570,8 +2549,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                if (!up->port.mapbase)
                        break;
 
@@ -2608,8 +2585,6 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                if (!up->port.mapbase)
                        break;
 
@@ -3050,6 +3025,10 @@ int __init early_serial_setup(struct uart_port *port)
                p->serial_in = port->serial_in;
        if (port->serial_out)
                p->serial_out = port->serial_out;
+       if (port->handle_irq)
+               p->handle_irq = port->handle_irq;
+       else
+               p->handle_irq = serial8250_default_handle_irq;
 
        return 0;
 }
@@ -3118,6 +3097,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
                port.type               = p->type;
                port.serial_in          = p->serial_in;
                port.serial_out         = p->serial_out;
+               port.handle_irq         = p->handle_irq;
                port.set_termios        = p->set_termios;
                port.pm                 = p->pm;
                port.dev                = &dev->dev;
@@ -3283,6 +3263,8 @@ int serial8250_register_port(struct uart_port *port)
                        uart->port.serial_in = port->serial_in;
                if (port->serial_out)
                        uart->port.serial_out = port->serial_out;
+               if (port->handle_irq)
+                       uart->port.handle_irq = port->handle_irq;
                /*  Possibly override set_termios call */
                if (port->set_termios)
                        uart->port.set_termios = port->set_termios;
diff --git a/drivers/tty/serial/8250_dw.c b/drivers/tty/serial/8250_dw.c
new file mode 100644 (file)
index 0000000..bf1fba6
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Synopsys DesignWare 8250 driver.
+ *
+ * Copyright 2011 Picochip, Jamie Iles.
+ *
+ * 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.
+ *
+ * The Synopsys DesignWare 8250 has an extra feature whereby it detects if the
+ * LCR is written whilst busy.  If it is, then a busy detect interrupt is
+ * raised, the LCR needs to be rewritten and the uart status register read.
+ */
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+struct dw8250_data {
+       int     last_lcr;
+       int     line;
+};
+
+static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+{
+       struct dw8250_data *d = p->private_data;
+
+       if (offset == UART_LCR)
+               d->last_lcr = value;
+
+       offset <<= p->regshift;
+       writeb(value, p->membase + offset);
+}
+
+static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
+{
+       offset <<= p->regshift;
+
+       return readb(p->membase + offset);
+}
+
+static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
+{
+       struct dw8250_data *d = p->private_data;
+
+       if (offset == UART_LCR)
+               d->last_lcr = value;
+
+       offset <<= p->regshift;
+       writel(value, p->membase + offset);
+}
+
+static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
+{
+       offset <<= p->regshift;
+
+       return readl(p->membase + offset);
+}
+
+/* Offset for the DesignWare's UART Status Register. */
+#define UART_USR       0x1f
+
+static int dw8250_handle_irq(struct uart_port *p)
+{
+       struct dw8250_data *d = p->private_data;
+       unsigned int iir = p->serial_in(p, UART_IIR);
+
+       if (serial8250_handle_irq(p, iir)) {
+               return 1;
+       } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+               /* Clear the USR and write the LCR again. */
+               (void)p->serial_in(p, UART_USR);
+               p->serial_out(p, d->last_lcr, UART_LCR);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static int __devinit dw8250_probe(struct platform_device *pdev)
+{
+       struct uart_port port = {};
+       struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       struct device_node *np = pdev->dev.of_node;
+       u32 val;
+       struct dw8250_data *data;
+
+       if (!regs || !irq) {
+               dev_err(&pdev->dev, "no registers/irq defined\n");
+               return -EINVAL;
+       }
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+       port.private_data = data;
+
+       spin_lock_init(&port.lock);
+       port.mapbase = regs->start;
+       port.irq = irq->start;
+       port.handle_irq = dw8250_handle_irq;
+       port.type = PORT_8250;
+       port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
+               UPF_FIXED_PORT | UPF_FIXED_TYPE;
+       port.dev = &pdev->dev;
+
+       port.iotype = UPIO_MEM;
+       port.serial_in = dw8250_serial_in;
+       port.serial_out = dw8250_serial_out;
+       if (!of_property_read_u32(np, "reg-io-width", &val)) {
+               switch (val) {
+               case 1:
+                       break;
+               case 4:
+                       port.iotype = UPIO_MEM32;
+                       port.serial_in = dw8250_serial_in32;
+                       port.serial_out = dw8250_serial_out32;
+                       break;
+               default:
+                       dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n",
+                               val);
+                       return -EINVAL;
+               }
+       }
+
+       if (!of_property_read_u32(np, "reg-shift", &val))
+               port.regshift = val;
+
+       if (of_property_read_u32(np, "clock-frequency", &val)) {
+               dev_err(&pdev->dev, "no clock-frequency property set\n");
+               return -EINVAL;
+       }
+       port.uartclk = val;
+
+       data->line = serial8250_register_port(&port);
+       if (data->line < 0)
+               return data->line;
+
+       platform_set_drvdata(pdev, data);
+
+       return 0;
+}
+
+static int __devexit dw8250_remove(struct platform_device *pdev)
+{
+       struct dw8250_data *data = platform_get_drvdata(pdev);
+
+       serial8250_unregister_port(data->line);
+
+       return 0;
+}
+
+static const struct of_device_id dw8250_match[] = {
+       { .compatible = "snps,dw-apb-uart" },
+       { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dw8250_match);
+
+static struct platform_driver dw8250_platform_driver = {
+       .driver = {
+               .name           = "dw-apb-uart",
+               .owner          = THIS_MODULE,
+               .of_match_table = dw8250_match,
+       },
+       .probe                  = dw8250_probe,
+       .remove                 = __devexit_p(dw8250_remove),
+};
+
+static int __init dw8250_init(void)
+{
+       return platform_driver_register(&dw8250_platform_driver);
+}
+module_init(dw8250_init);
+
+static void __exit dw8250_exit(void)
+{
+       platform_driver_unregister(&dw8250_platform_driver);
+}
+module_exit(dw8250_exit);
+
+MODULE_AUTHOR("Jamie Iles");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");
index 3abeca2..825937a 100644 (file)
@@ -1101,6 +1101,15 @@ static int pci_eg20t_init(struct pci_dev *dev)
 #endif
 }
 
+static int
+pci_xr17c154_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_port *port, int idx)
+{
+       port->flags |= UPF_EXAR_EFR;
+       return pci_default_setup(priv, board, port, idx);
+}
+
 /* This should be in linux/pci_ids.h */
 #define PCI_VENDOR_ID_SBSMODULARIO     0x124B
 #define PCI_SUBVENDOR_ID_SBSMODULARIO  0x124B
@@ -1505,6 +1514,30 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = pci_timedia_setup,
        },
+       /*
+        * Exar cards
+        */
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17C152,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17c154_setup,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17C154,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17c154_setup,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17C158,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17c154_setup,
+       },
        /*
         * Xircom cards
         */
@@ -1558,46 +1591,55 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = 0x8811,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = 0x8812,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = 0x8813,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = 0x8814,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x8027,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x8028,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x8029,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x800C,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        {
                .vendor         = 0x10DB,
                .device         = 0x800D,
                .init           = pci_eg20t_init,
+               .setup          = pci_default_setup,
        },
        /*
         * Cronyx Omega PCI (PLX-chip based)
index 4dcb37b..5f479da 100644 (file)
@@ -267,6 +267,13 @@ config SERIAL_8250_RM9K
          port hardware found on MIPS RM9122 and similar processors.
          If unsure, say N.
 
+config SERIAL_8250_DW
+       tristate "Support for Synopsys DesignWare 8250 quirks"
+       depends on SERIAL_8250 && OF
+       help
+         Selecting this option will enable handling of the extra features
+         present in the Synopsys DesignWare APB UART.
+
 comment "Non-8250 serial port support"
 
 config SERIAL_AMBA_PL010
@@ -522,8 +529,8 @@ config SERIAL_S3C6400
 
 config SERIAL_S5PV210
        tristate "Samsung S5PV210 Serial port support"
-       depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_EXYNOS4210)
-       select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210)
+       depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_EXYNOS4210 || SOC_EXYNOS4212)
+       select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210 || SOC_EXYNOS4212)
        default y
        help
          Serial port support for Samsung's S5P Family of SoC's
@@ -722,7 +729,7 @@ config SERIAL_BFIN
          Add support for the built-in UARTs on the Blackfin.
 
          To compile this driver as a module, choose M here: the
-         module will be called bfin_5xx.
+         module is named bfin_uart.ko.
 
 config SERIAL_BFIN_CONSOLE
        bool "Console on Blackfin serial port"
@@ -1035,23 +1042,6 @@ config SERIAL_MCF_CONSOLE
        help
          Enable a ColdFire internal serial port to be the system console.
 
-config SERIAL_68360_SMC
-       bool "68360 SMC uart support"
-       depends on M68360
-       help
-         This driver supports the SMC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360_SCC
-       bool "68360 SCC uart support"
-       depends on M68360
-       help
-         This driver supports the SCC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360
-       bool
-       depends on SERIAL_68360_SMC || SERIAL_68360_SCC
-       default y
-
 config SERIAL_PMACZILOG
        tristate "Mac or PowerMac z85c30 ESCC support"
        depends on (M68K && MAC) || (PPC_OF && PPC_PMAC)
index 83b4da6..e10cf5b 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
 obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
 obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
 obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
+obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
 obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
 obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
 obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
@@ -35,7 +36,7 @@ obj-$(CONFIG_SERIAL_PXA) += pxa.o
 obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
 obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
 obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
-obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
+obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o
 obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
 obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
 obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
@@ -49,7 +50,6 @@ obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o
 obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
 obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
-obj-$(CONFIG_SERIAL_68360) += 68360serial.o
 obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
index 60e049b..00a73ec 100644 (file)
@@ -218,7 +218,7 @@ static int altera_jtaguart_startup(struct uart_port *port)
        unsigned long flags;
        int ret;
 
-       ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED,
+       ret = request_irq(port->irq, altera_jtaguart_interrupt, 0,
                        DRV_NAME, port);
        if (ret) {
                pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
index 50bc5a5..d902558 100644 (file)
@@ -315,7 +315,7 @@ static int altera_uart_startup(struct uart_port *port)
                return 0;
        }
 
-       ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
+       ret = request_irq(port->irq, altera_uart_interrupt, 0,
                        DRV_NAME, port);
        if (ret) {
                pr_err(DRV_NAME ": unable to attach Altera UART %d "
index 19a9436..77554fd 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/module.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/serial.h>
index b922f5d..9988c0c 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/sysrq.h>
 #include <linux/tty_flip.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/atmel_pdc.h>
 #include <linux/atmel_serial.h>
@@ -157,11 +159,22 @@ struct atmel_uart_port {
 };
 
 static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
+static unsigned long atmel_ports_in_use;
 
 #ifdef SUPPORT_SYSRQ
 static struct console atmel_console;
 #endif
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_serial_dt_ids[] = {
+       { .compatible = "atmel,at91rm9200-usart" },
+       { .compatible = "atmel,at91sam9260-usart" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_serial_dt_ids);
+#endif
+
 static inline struct atmel_uart_port *
 to_atmel_uart_port(struct uart_port *uart)
 {
@@ -339,7 +352,8 @@ static void atmel_stop_tx(struct uart_port *port)
        /* Disable interrupts */
        UART_PUT_IDR(port, atmel_port->tx_done_mask);
 
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+       if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
+           !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
                atmel_start_rx(port);
 }
 
@@ -356,7 +370,8 @@ static void atmel_start_tx(struct uart_port *port)
                           really need this.*/
                        return;
 
-               if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+               if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
+                   !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
                        atmel_stop_rx(port);
 
                /* re-enable PDC transmit */
@@ -680,7 +695,8 @@ static void atmel_tx_dma(struct uart_port *port)
                /* Enable interrupts */
                UART_PUT_IER(port, atmel_port->tx_done_mask);
        } else {
-               if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+               if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
+                   !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) {
                        /* DMA done, stop TX, start RX for RS485 */
                        atmel_start_rx(port);
                }
@@ -1407,6 +1423,48 @@ static struct uart_ops atmel_pops = {
 #endif
 };
 
+static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
+                                        struct device_node *np)
+{
+       u32 rs485_delay[2];
+
+       /* DMA/PDC usage specification */
+       if (of_get_property(np, "atmel,use-dma-rx", NULL))
+               atmel_port->use_dma_rx  = 1;
+       else
+               atmel_port->use_dma_rx  = 0;
+       if (of_get_property(np, "atmel,use-dma-tx", NULL))
+               atmel_port->use_dma_tx  = 1;
+       else
+               atmel_port->use_dma_tx  = 0;
+
+       /* rs485 properties */
+       if (of_property_read_u32_array(np, "rs485-rts-delay",
+                                           rs485_delay, 2) == 0) {
+               struct serial_rs485 *rs485conf = &atmel_port->rs485;
+
+               rs485conf->delay_rts_before_send = rs485_delay[0];
+               rs485conf->delay_rts_after_send = rs485_delay[1];
+               rs485conf->flags = 0;
+
+               if (rs485conf->delay_rts_before_send == 0 &&
+                   rs485conf->delay_rts_after_send == 0) {
+                       rs485conf->flags |= SER_RS485_RTS_ON_SEND;
+               } else {
+                       if (rs485conf->delay_rts_before_send)
+                               rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND;
+                       if (rs485conf->delay_rts_after_send)
+                               rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
+               }
+
+               if (of_get_property(np, "rs485-rx-during-tx", NULL))
+                       rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
+               if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
+                       rs485conf->flags |= SER_RS485_ENABLED;
+       }
+}
+
 /*
  * Configure the port from the platform device resource info.
  */
@@ -1414,13 +1472,20 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
                                      struct platform_device *pdev)
 {
        struct uart_port *port = &atmel_port->uart;
-       struct atmel_uart_data *data = pdev->dev.platform_data;
+       struct atmel_uart_data *pdata = pdev->dev.platform_data;
+
+       if (pdev->dev.of_node) {
+               atmel_of_init_port(atmel_port, pdev->dev.of_node);
+       } else {
+               atmel_port->use_dma_rx  = pdata->use_dma_rx;
+               atmel_port->use_dma_tx  = pdata->use_dma_tx;
+               atmel_port->rs485       = pdata->rs485;
+       }
 
        port->iotype            = UPIO_MEM;
        port->flags             = UPF_BOOT_AUTOCONF;
        port->ops               = &atmel_pops;
        port->fifosize          = 1;
-       port->line              = data->num;
        port->dev               = &pdev->dev;
        port->mapbase   = pdev->resource[0].start;
        port->irq       = pdev->resource[1].start;
@@ -1430,10 +1495,10 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
 
        memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
 
-       if (data->regs)
+       if (pdata && pdata->regs) {
                /* Already mapped by setup code */
-               port->membase = data->regs;
-       else {
+               port->membase = pdata->regs;
+       else {
                port->flags     |= UPF_IOREMAP;
                port->membase   = NULL;
        }
@@ -1447,9 +1512,6 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
                /* only enable clock when USART is in use */
        }
 
-       atmel_port->use_dma_rx = data->use_dma_rx;
-       atmel_port->use_dma_tx = data->use_dma_tx;
-       atmel_port->rs485       = data->rs485;
        /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
        if (atmel_port->rs485.flags & SER_RS485_ENABLED)
                atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
@@ -1611,10 +1673,14 @@ static int __init atmel_console_init(void)
        if (atmel_default_console_device) {
                struct atmel_uart_data *pdata =
                        atmel_default_console_device->dev.platform_data;
+               int id = pdata->num;
+               struct atmel_uart_port *port = &atmel_ports[id];
+
+               port->backup_imr = 0;
+               port->uart.line = id;
 
-               add_preferred_console(ATMEL_DEVICENAME, pdata->num, NULL);
-               atmel_init_port(&atmel_ports[pdata->num],
-                               atmel_default_console_device);
+               add_preferred_console(ATMEL_DEVICENAME, id, NULL);
+               atmel_init_port(port, atmel_default_console_device);
                register_console(&atmel_console);
        }
 
@@ -1711,14 +1777,39 @@ static int atmel_serial_resume(struct platform_device *pdev)
 static int __devinit atmel_serial_probe(struct platform_device *pdev)
 {
        struct atmel_uart_port *port;
+       struct device_node *np = pdev->dev.of_node;
        struct atmel_uart_data *pdata = pdev->dev.platform_data;
        void *data;
-       int ret;
+       int ret = -ENODEV;
 
        BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
 
-       port = &atmel_ports[pdata->num];
+       if (np)
+               ret = of_alias_get_id(np, "serial");
+       else
+               if (pdata)
+                       ret = pdata->num;
+
+       if (ret < 0)
+               /* port id not found in platform data nor device-tree aliases:
+                * auto-enumerate it */
+               ret = find_first_zero_bit(&atmel_ports_in_use,
+                               sizeof(atmel_ports_in_use));
+
+       if (ret > ATMEL_MAX_UART) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       if (test_and_set_bit(ret, &atmel_ports_in_use)) {
+               /* port already in use */
+               ret = -EBUSY;
+               goto err;
+       }
+
+       port = &atmel_ports[ret];
        port->backup_imr = 0;
+       port->uart.line = ret;
 
        atmel_init_port(port, pdev);
 
@@ -1764,7 +1855,7 @@ err_alloc_ring:
                clk_put(port->clk);
                port->clk = NULL;
        }
-
+err:
        return ret;
 }
 
@@ -1784,6 +1875,8 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev)
 
        /* "port" is allocated statically, so we shouldn't free it */
 
+       clear_bit(port->line, &atmel_ports_in_use);
+
        clk_put(atmel_port->clk);
 
        return ret;
@@ -1797,6 +1890,7 @@ static struct platform_driver atmel_serial_driver = {
        .driver         = {
                .name   = "atmel_usart",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_serial_dt_ids),
        },
 };
 
index 891d194..ee101c0 100644 (file)
@@ -294,7 +294,7 @@ static int sport_startup(struct uart_port *port)
                if (request_irq(gpio_to_irq(up->cts_pin),
                        sport_mctrl_cts_int,
                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-                       IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) {
+                       0, "BFIN_SPORT_UART_CTS", up)) {
                        up->cts_pin = -1;
                        dev_info(port->dev, "Unable to attach BlackFin UART over SPORT CTS interrupt. So, disable it.\n");
                }
similarity index 97%
rename from drivers/tty/serial/bfin_5xx.c
rename to drivers/tty/serial/bfin_uart.c
index ff69791..66afb98 100644 (file)
@@ -234,8 +234,8 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
        status = UART_GET_LSR(uart);
        UART_CLEAR_LSR(uart);
 
-       ch = UART_GET_CHAR(uart);
-       uart->port.icount.rx++;
+       ch = UART_GET_CHAR(uart);
+       uart->port.icount.rx++;
 
 #if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
        defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
@@ -667,17 +667,17 @@ static int bfin_serial_startup(struct uart_port *port)
                kgdboc_break_enabled = 0;
        else {
 # endif
-       if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
+       if (request_irq(uart->rx_irq, bfin_serial_rx_int, 0,
             "BFIN_UART_RX", uart)) {
                printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
                return -EBUSY;
        }
 
        if (request_irq
-           (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
+           (uart->tx_irq, bfin_serial_tx_int, 0,
             "BFIN_UART_TX", uart)) {
                printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
-               free_irq(uart->port.irq, uart);
+               free_irq(uart->rx_irq, uart);
                return -EBUSY;
        }
 
@@ -692,7 +692,7 @@ static int bfin_serial_startup(struct uart_port *port)
                 */
                unsigned uart_dma_ch_rx, uart_dma_ch_tx;
 
-               switch (uart->port.irq) {
+               switch (uart->rx_irq) {
                case IRQ_UART3_RX:
                        uart_dma_ch_rx = CH_UART3_RX;
                        uart_dma_ch_tx = CH_UART3_TX;
@@ -709,16 +709,16 @@ static int bfin_serial_startup(struct uart_port *port)
                if (uart_dma_ch_rx &&
                        request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
                        printk(KERN_NOTICE"Fail to attach UART interrupt\n");
-                       free_irq(uart->port.irq, uart);
-                       free_irq(uart->port.irq + 1, uart);
+                       free_irq(uart->rx_irq, uart);
+                       free_irq(uart->tx_irq, uart);
                        return -EBUSY;
                }
                if (uart_dma_ch_tx &&
                        request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
                        printk(KERN_NOTICE "Fail to attach UART interrupt\n");
                        free_dma(uart_dma_ch_rx);
-                       free_irq(uart->port.irq, uart);
-                       free_irq(uart->port.irq + 1, uart);
+                       free_irq(uart->rx_irq, uart);
+                       free_irq(uart->tx_irq, uart);
                        return -EBUSY;
                }
        }
@@ -734,19 +734,18 @@ static int bfin_serial_startup(struct uart_port *port)
                if (request_irq(gpio_to_irq(uart->cts_pin),
                        bfin_serial_mctrl_cts_int,
                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
-                       IRQF_DISABLED, "BFIN_UART_CTS", uart)) {
+                       0, "BFIN_UART_CTS", uart)) {
                        uart->cts_pin = -1;
                        pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
                }
        }
-       if (uart->rts_pin >= 0) {
+       if (uart->rts_pin >= 0)
                gpio_direction_output(uart->rts_pin, 0);
-       }
 #endif
 #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
        if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
                bfin_serial_mctrl_cts_int,
-               IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
+               0, "BFIN_UART_MODEM_STATUS", uart)) {
                uart->cts_pin = -1;
                pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
        }
@@ -786,8 +785,8 @@ static void bfin_serial_shutdown(struct uart_port *port)
                break;
        };
 #endif
-       free_irq(uart->port.irq, uart);
-       free_irq(uart->port.irq+1, uart);
+       free_irq(uart->rx_irq, uart);
+       free_irq(uart->tx_irq, uart);
 #endif
 
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
@@ -1091,10 +1090,18 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
                                *parity = 'o';
                }
                switch (lcr & 0x03) {
-                       case 0: *bits = 5; break;
-                       case 1: *bits = 6; break;
-                       case 2: *bits = 7; break;
-                       case 3: *bits = 8; break;
+               case 0:
+                       *bits = 5;
+                       break;
+               case 1:
+                       *bits = 6;
+                       break;
+               case 2:
+                       *bits = 7;
+                       break;
+               case 3:
+                       *bits = 8;
+                       break;
                }
                /* Set DLAB in LCR to Access DLL and DLH */
                UART_SET_DLAB(uart);
@@ -1183,7 +1190,7 @@ static struct console bfin_serial_console = {
        .index          = -1,
        .data           = &bfin_serial_reg,
 };
-#define BFIN_SERIAL_CONSOLE    &bfin_serial_console
+#define BFIN_SERIAL_CONSOLE    (&bfin_serial_console)
 #else
 #define BFIN_SERIAL_CONSOLE    NULL
 #endif /* CONFIG_SERIAL_BFIN_CONSOLE */
@@ -1312,14 +1319,22 @@ static int bfin_serial_probe(struct platform_device *pdev)
                }
                uart->port.mapbase = res->start;
 
-               uart->port.irq = platform_get_irq(pdev, 0);
-               if (uart->port.irq < 0) {
-                       dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n");
+               uart->tx_irq = platform_get_irq(pdev, 0);
+               if (uart->tx_irq < 0) {
+                       dev_err(&pdev->dev, "No uart TX IRQ specified\n");
+                       ret = -ENOENT;
+                       goto out_error_unmap;
+               }
+
+               uart->rx_irq = platform_get_irq(pdev, 1);
+               if (uart->rx_irq < 0) {
+                       dev_err(&pdev->dev, "No uart RX IRQ specified\n");
                        ret = -ENOENT;
                        goto out_error_unmap;
                }
+               uart->port.irq = uart->rx_irq;
 
-               uart->status_irq = platform_get_irq(pdev, 1);
+               uart->status_irq = platform_get_irq(pdev, 2);
                if (uart->status_irq < 0) {
                        dev_err(&pdev->dev, "No uart status IRQ specified\n");
                        ret = -ENOENT;
index 9488da7..b418947 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <linux/module.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/serial.h>
index 58be715..b743504 100644 (file)
@@ -258,7 +258,7 @@ static struct e100_serial rs_table[] = {
          .dma_out_enabled = 1,
          .dma_out_nbr = SER0_TX_DMA_NBR,
          .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_flags = 0,
          .dma_out_irq_description = "serial 0 dma tr",
 #else
          .dma_out_enabled = 0,
@@ -271,7 +271,7 @@ static struct e100_serial rs_table[] = {
          .dma_in_enabled = 1,
          .dma_in_nbr = SER0_RX_DMA_NBR,
          .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_flags = 0,
          .dma_in_irq_description = "serial 0 dma rec",
 #else
          .dma_in_enabled = 0,
@@ -313,7 +313,7 @@ static struct e100_serial rs_table[] = {
          .dma_out_enabled = 1,
          .dma_out_nbr = SER1_TX_DMA_NBR,
          .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_flags = 0,
          .dma_out_irq_description = "serial 1 dma tr",
 #else
          .dma_out_enabled = 0,
@@ -326,7 +326,7 @@ static struct e100_serial rs_table[] = {
          .dma_in_enabled = 1,
          .dma_in_nbr = SER1_RX_DMA_NBR,
          .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_flags = 0,
          .dma_in_irq_description = "serial 1 dma rec",
 #else
          .dma_in_enabled = 0,
@@ -369,7 +369,7 @@ static struct e100_serial rs_table[] = {
          .dma_out_enabled = 1,
          .dma_out_nbr = SER2_TX_DMA_NBR,
          .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_flags = 0,
          .dma_out_irq_description = "serial 2 dma tr",
 #else
          .dma_out_enabled = 0,
@@ -382,7 +382,7 @@ static struct e100_serial rs_table[] = {
          .dma_in_enabled = 1,
          .dma_in_nbr = SER2_RX_DMA_NBR,
          .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_flags = 0,
          .dma_in_irq_description = "serial 2 dma rec",
 #else
          .dma_in_enabled = 0,
@@ -423,7 +423,7 @@ static struct e100_serial rs_table[] = {
          .dma_out_enabled = 1,
          .dma_out_nbr = SER3_TX_DMA_NBR,
          .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR,
-         .dma_out_irq_flags = IRQF_DISABLED,
+         .dma_out_irq_flags = 0,
          .dma_out_irq_description = "serial 3 dma tr",
 #else
          .dma_out_enabled = 0,
@@ -436,7 +436,7 @@ static struct e100_serial rs_table[] = {
          .dma_in_enabled = 1,
          .dma_in_nbr = SER3_RX_DMA_NBR,
          .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR,
-         .dma_in_irq_flags = IRQF_DISABLED,
+         .dma_in_irq_flags = 0,
          .dma_in_irq_description = "serial 3 dma rec",
 #else
          .dma_in_enabled = 0,
@@ -1788,7 +1788,7 @@ static unsigned int handle_descr_data(struct e100_serial *info,
        struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
 
        if (info->recv_cnt + recvl > 65536) {
-               printk(KERN_CRIT
+               printk(KERN_WARNING
                       "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl);
                return 0;
        }
@@ -3813,13 +3813,13 @@ rs_close(struct tty_struct *tty, struct file * filp)
                 * one, we've got real problems, since it means the
                 * serial port won't be shutdown.
                 */
-               printk(KERN_CRIT
+               printk(KERN_ERR
                       "rs_close: bad serial port count; tty->count is 1, "
                       "info->count is %d\n", info->count);
                info->count = 1;
        }
        if (--info->count < 0) {
-               printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n",
+               printk(KERN_ERR "rs_close: bad serial port count for ttyS%d: %d\n",
                       info->line, info->count);
                info->count = 0;
        }
@@ -4452,7 +4452,7 @@ static int __init rs_init(void)
 #if defined(CONFIG_ETRAX_RS485_ON_PA)
        if (cris_io_interface_allocate_pins(if_serial_0, 'a', rs485_pa_bit,
                        rs485_pa_bit)) {
-               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
+               printk(KERN_ERR "ETRAX100LX serial: Could not allocate "
                        "RS485 pin\n");
                put_tty_driver(driver);
                return -EBUSY;
@@ -4461,7 +4461,7 @@ static int __init rs_init(void)
 #if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
        if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit,
                        rs485_port_g_bit)) {
-               printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
+               printk(KERN_ERR "ETRAX100LX serial: Could not allocate "
                        "RS485 pin\n");
                put_tty_driver(driver);
                return -EBUSY;
@@ -4494,7 +4494,7 @@ static int __init rs_init(void)
                if (info->enabled) {
                        if (cris_request_io_interface(info->io_if,
                                        info->io_if_description)) {
-                               printk(KERN_CRIT "ETRAX100LX async serial: "
+                               printk(KERN_ERR "ETRAX100LX async serial: "
                                        "Could not allocate IO pins for "
                                        "%s, port %d\n",
                                        info->io_if_description, i);
@@ -4558,7 +4558,7 @@ static int __init rs_init(void)
        /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
 
        if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
-                       IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
+                       IRQF_SHARED, "serial ", driver))
                panic("%s: Failed to request irq8", __func__);
 
 #endif
index ddc487a..e3699a8 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/serial_core.h>
 #include <linux/sysrq.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 
 #include <linux/atomic.h>
 #include <asm/bootinfo.h>
index 8a869e5..d55709a 100644 (file)
@@ -1554,7 +1554,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
 
         /* save off irq and request irq line */
         if ( (retval = request_irq(dev->irq, icom_interrupt,
-                                  IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME,
+                                  IRQF_SHARED, ICOM_DRIVER_NAME,
                                   (void *) icom_adapter))) {
                  goto probe_exit2;
         }
index 7e91b3d..54ffdc6 100644 (file)
@@ -508,8 +508,10 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
                if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
                        continue;
 
-               if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
-                       if (rx & URXD_PRERR)
+               if (unlikely(rx & URXD_ERR)) {
+                       if (rx & URXD_BRK)
+                               sport->port.icount.brk++;
+                       else if (rx & URXD_PRERR)
                                sport->port.icount.parity++;
                        else if (rx & URXD_FRMERR)
                                sport->port.icount.frame++;
@@ -524,7 +526,9 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
 
                        rx &= sport->port.read_status_mask;
 
-                       if (rx & URXD_PRERR)
+                       if (rx & URXD_BRK)
+                               flg = TTY_BREAK;
+                       else if (rx & URXD_PRERR)
                                flg = TTY_PARITY;
                        else if (rx & URXD_FRMERR)
                                flg = TTY_FRAME;
index ee43efc..758ff31 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/errno.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/circ_buf.h>
 #include <linux/serial_reg.h>
index fcfe826..6b36c15 100644 (file)
@@ -14,6 +14,7 @@
  */
 #include <linux/errno.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
 #include <linux/circ_buf.h>
index b704c8c..529bec6 100644 (file)
@@ -88,7 +88,6 @@ enum {
 
 /* 4 extra for alignment play space */
 #define WRITEBUFLEN    ((4096) + 4)
-#define MYFLIPLEN      N_TTY_BUF_SIZE
 
 #define JSM_VERSION    "jsm: 1.2-1-INKERNEL"
 #define JSM_PARTNUM    "40002438_A-INKERNEL"
@@ -150,7 +149,6 @@ struct jsm_board
        u32             bd_uart_offset; /* Space between each UART */
 
        struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */
-       char            *flipbuf;       /* Our flip buffer, alloced if board is found */
 
        u32             bd_dividend;    /* Board/UARTs specific dividend */
 
@@ -177,16 +175,13 @@ struct jsm_board
 #define CH_TX_FIFO_LWM 0x0800          /* TX Fifo is below Low Water   */
 #define CH_BREAK_SENDING 0x1000                /* Break is being sent          */
 #define CH_LOOPBACK 0x2000             /* Channel is in lookback mode  */
-#define CH_FLIPBUF_IN_USE 0x4000       /* Channel's flipbuf is in use  */
 #define CH_BAUD0       0x08000         /* Used for checking B0 transitions */
 
 /* Our Read/Error/Write queue sizes */
 #define RQUEUEMASK     0x1FFF          /* 8 K - 1 */
 #define EQUEUEMASK     0x1FFF          /* 8 K - 1 */
-#define WQUEUEMASK     0x0FFF          /* 4 K - 1 */
 #define RQUEUESIZE     (RQUEUEMASK + 1)
 #define EQUEUESIZE     RQUEUESIZE
-#define WQUEUESIZE     (WQUEUEMASK + 1)
 
 
 /************************************************************************
@@ -226,10 +221,6 @@ struct jsm_channel {
        u16             ch_e_head;      /* Head location of the error queue */
        u16             ch_e_tail;      /* Tail location of the error queue */
 
-       u8              *ch_wqueue;     /* Our write queue buffer - malloc'ed */
-       u16             ch_w_head;      /* Head location of the write queue */
-       u16             ch_w_tail;      /* Tail location of the write queue */
-
        u64             ch_rxcount;     /* total of data received so far */
        u64             ch_txcount;     /* total of data transmitted so far */
 
@@ -378,7 +369,6 @@ extern int  jsm_debug;
  * Prototypes for non-static functions used in more than one module
  *
  *************************************************************************/
-int jsm_tty_write(struct uart_port *port);
 int jsm_tty_init(struct jsm_board *);
 int jsm_uart_port_init(struct jsm_board *);
 int jsm_remove_uart_port(struct jsm_board *);
index 96da178..648b6a3 100644 (file)
@@ -160,27 +160,10 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
        dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n",
                        adapter_count, brd->rev, brd->irq);
 
-       /*
-        * allocate flip buffer for board.
-        *
-        * Okay to malloc with GFP_KERNEL, we are not at interrupt
-        * context, and there are no locks held.
-        */
-       brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
-       if (!brd->flipbuf) {
-               /* XXX: leaking all resources from jsm_tty_init and
-                       jsm_uart_port_init here! */
-               dev_err(&pdev->dev, "memory allocation for flipbuf failed\n");
-               rc = -ENOMEM;
-               goto out_free_uart;
-       }
-
        pci_set_drvdata(pdev, brd);
        pci_save_state(pdev);
 
        return 0;
- out_free_uart:
-       jsm_remove_uart_port(brd);
  out_free_irq:
        jsm_remove_uart_port(brd);
        free_irq(brd->irq, brd);
@@ -211,14 +194,12 @@ static void __devexit jsm_remove_one(struct pci_dev *pdev)
                if (brd->channels[i]) {
                        kfree(brd->channels[i]->ch_rqueue);
                        kfree(brd->channels[i]->ch_equeue);
-                       kfree(brd->channels[i]->ch_wqueue);
                        kfree(brd->channels[i]);
                }
        }
 
        pci_release_regions(pdev);
        pci_disable_device(pdev);
-       kfree(brd->flipbuf);
        kfree(brd);
 }
 
index 4538c3e..81dfafa 100644 (file)
@@ -496,12 +496,15 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
        int s;
        int qlen;
        u32 len_written = 0;
+       struct circ_buf *circ;
 
        if (!ch)
                return;
 
+       circ = &ch->uart_port.state->xmit;
+
        /* No data to write to the UART */
-       if (ch->ch_w_tail == ch->ch_w_head)
+       if (uart_circ_empty(circ))
                return;
 
        /* If port is "stopped", don't send any data to the UART */
@@ -517,11 +520,10 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
                if (ch->ch_cached_lsr & UART_LSR_THRE) {
                        ch->ch_cached_lsr &= ~(UART_LSR_THRE);
 
-                       writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
+                       writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx);
                        jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
-                                       "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]);
-                       ch->ch_w_tail++;
-                       ch->ch_w_tail &= WQUEUEMASK;
+                                       "Tx data: %x\n", circ->buf[circ->tail]);
+                       circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1);
                        ch->ch_txcount++;
                }
                return;
@@ -536,36 +538,36 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
        n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
 
        /* cache head and tail of queue */
-       head = ch->ch_w_head & WQUEUEMASK;
-       tail = ch->ch_w_tail & WQUEUEMASK;
-       qlen = (head - tail) & WQUEUEMASK;
+       head = circ->head & (UART_XMIT_SIZE - 1);
+       tail = circ->tail & (UART_XMIT_SIZE - 1);
+       qlen = uart_circ_chars_pending(circ);
 
        /* Find minimum of the FIFO space, versus queue length */
        n = min(n, qlen);
 
        while (n > 0) {
 
-               s = ((head >= tail) ? head : WQUEUESIZE) - tail;
+               s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
                s = min(s, n);
 
                if (s <= 0)
                        break;
 
-               memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
+               memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s);
                /* Add and flip queue if needed */
-               tail = (tail + s) & WQUEUEMASK;
+               tail = (tail + s) & (UART_XMIT_SIZE - 1);
                n -= s;
                ch->ch_txcount += s;
                len_written += s;
        }
 
        /* Update the final tail */
-       ch->ch_w_tail = tail & WQUEUEMASK;
+       circ->tail = tail & (UART_XMIT_SIZE - 1);
 
        if (len_written >= ch->ch_t_tlevel)
                ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
 
-       if (!jsm_tty_write(&ch->uart_port))
+       if (uart_circ_empty(circ))
                uart_write_wakeup(&ch->uart_port);
 }
 
@@ -946,7 +948,6 @@ static void neo_param(struct jsm_channel *ch)
        if ((ch->ch_c_cflag & (CBAUD)) == 0) {
                ch->ch_r_head = ch->ch_r_tail = 0;
                ch->ch_e_head = ch->ch_e_tail = 0;
-               ch->ch_w_head = ch->ch_w_tail = 0;
 
                neo_flush_uart_write(ch);
                neo_flush_uart_read(ch);
index 7a4a914..434bd88 100644 (file)
@@ -118,6 +118,19 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
        udelay(10);
 }
 
+/*
+ * jsm_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+static void jsm_tty_write(struct uart_port *port)
+{
+       struct jsm_channel *channel;
+       channel = container_of(port, struct jsm_channel, uart_port);
+       channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
+}
+
 static void jsm_tty_start_tx(struct uart_port *port)
 {
        struct jsm_channel *channel = (struct jsm_channel *)port;
@@ -216,14 +229,6 @@ static int jsm_tty_open(struct uart_port *port)
                        return -ENOMEM;
                }
        }
-       if (!channel->ch_wqueue) {
-               channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
-               if (!channel->ch_wqueue) {
-                       jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
-                               "unable to allocate write queue buf");
-                       return -ENOMEM;
-               }
-       }
 
        channel->ch_flags &= ~(CH_OPENING);
        /*
@@ -237,7 +242,6 @@ static int jsm_tty_open(struct uart_port *port)
         */
        channel->ch_r_head = channel->ch_r_tail = 0;
        channel->ch_e_head = channel->ch_e_tail = 0;
-       channel->ch_w_head = channel->ch_w_tail = 0;
 
        brd->bd_ops->flush_uart_write(channel);
        brd->bd_ops->flush_uart_read(channel);
@@ -836,75 +840,3 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
                }
        }
 }
-
-/*
- * jsm_tty_write()
- *
- * Take data from the user or kernel and send it out to the FEP.
- * In here exists all the Transparent Print magic as well.
- */
-int jsm_tty_write(struct uart_port *port)
-{
-       int bufcount;
-       int data_count = 0,data_count1 =0;
-       u16 head;
-       u16 tail;
-       u16 tmask;
-       u32 remain;
-       int temp_tail = port->state->xmit.tail;
-       struct jsm_channel *channel = (struct jsm_channel *)port;
-
-       tmask = WQUEUEMASK;
-       head = (channel->ch_w_head) & tmask;
-       tail = (channel->ch_w_tail) & tmask;
-
-       if ((bufcount = tail - head - 1) < 0)
-               bufcount += WQUEUESIZE;
-
-       bufcount = min(bufcount, 56);
-       remain = WQUEUESIZE - head;
-
-       data_count = 0;
-       if (bufcount >= remain) {
-               bufcount -= remain;
-               while ((port->state->xmit.head != temp_tail) &&
-               (data_count < remain)) {
-                       channel->ch_wqueue[head++] =
-                       port->state->xmit.buf[temp_tail];
-
-                       temp_tail++;
-                       temp_tail &= (UART_XMIT_SIZE - 1);
-                       data_count++;
-               }
-               if (data_count == remain) head = 0;
-       }
-
-       data_count1 = 0;
-       if (bufcount > 0) {
-               remain = bufcount;
-               while ((port->state->xmit.head != temp_tail) &&
-                       (data_count1 < remain)) {
-                       channel->ch_wqueue[head++] =
-                               port->state->xmit.buf[temp_tail];
-
-                       temp_tail++;
-                       temp_tail &= (UART_XMIT_SIZE - 1);
-                       data_count1++;
-
-               }
-       }
-
-       port->state->xmit.tail = temp_tail;
-
-       data_count += data_count1;
-       if (data_count) {
-               head &= tmask;
-               channel->ch_w_head = head;
-       }
-
-       if (data_count) {
-               channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
-       }
-
-       return data_count;
-}
index bc95f52..96c1cac 100644 (file)
@@ -338,21 +338,21 @@ lqasc_startup(struct uart_port *port)
                ASCCON_ROEN, port->membase + LTQ_ASC_CON);
 
        retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
-               IRQF_DISABLED, "asc_tx", port);
+               0, "asc_tx", port);
        if (retval) {
                pr_err("failed to request lqasc_tx_int\n");
                return retval;
        }
 
        retval = request_irq(ltq_port->rx_irq, lqasc_rx_int,
-               IRQF_DISABLED, "asc_rx", port);
+               0, "asc_rx", port);
        if (retval) {
                pr_err("failed to request lqasc_rx_int\n");
                goto err1;
        }
 
        retval = request_irq(ltq_port->err_irq, lqasc_err_int,
-               IRQF_DISABLED, "asc_err", port);
+               0, "asc_err", port);
        if (retval) {
                pr_err("failed to request lqasc_err_int\n");
                goto err2;
index 8e07517..0801893 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <linux/module.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/console.h>
index 7b951ad..2af5aa5 100644 (file)
@@ -47,6 +47,8 @@
 #include <linux/serial.h>
 #include <linux/spi/spi.h>
 #include <linux/freezer.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 
 #include <linux/serial_max3100.h>
 
index a816460..db00b59 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/device.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/freezer.h>
index 3394b7c..9afca09 100644 (file)
@@ -380,7 +380,7 @@ static void mcf_config_port(struct uart_port *port, int flags)
        /* Clear mask, so no surprise interrupts. */
        writeb(0, port->membase + MCFUART_UIMR);
 
-       if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
+       if (request_irq(port->irq, mcf_interrupt, 0, "UART", port))
                printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
                        "interrupt vector=%d\n", port->line, port->irq);
 }
index cab52f4..286c386 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/pci.h>
 #include <linux/io.h>
 #include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
 
 #define HSU_DMA_BUF_SIZE       2048
 
@@ -764,6 +765,8 @@ static int serial_hsu_startup(struct uart_port *port)
                container_of(port, struct uart_hsu_port, port);
        unsigned long flags;
 
+       pm_runtime_get_sync(up->dev);
+
        /*
         * Clear the FIFO buffers and disable them.
         * (they will be reenabled in set_termios())
@@ -871,6 +874,8 @@ static void serial_hsu_shutdown(struct uart_port *port)
                                  UART_FCR_CLEAR_RCVR |
                                  UART_FCR_CLEAR_XMIT);
        serial_out(up, UART_FCR, 0);
+
+       pm_runtime_put(up->dev);
 }
 
 static void
@@ -1249,6 +1254,39 @@ static int serial_hsu_resume(struct pci_dev *pdev)
 #define serial_hsu_resume      NULL
 #endif
 
+#ifdef CONFIG_PM_RUNTIME
+static int serial_hsu_runtime_idle(struct device *dev)
+{
+       int err;
+
+       err = pm_schedule_suspend(dev, 500);
+       if (err)
+               return -EBUSY;
+
+       return 0;
+}
+
+static int serial_hsu_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int serial_hsu_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+#else
+#define serial_hsu_runtime_idle                NULL
+#define serial_hsu_runtime_suspend     NULL
+#define serial_hsu_runtime_resume      NULL
+#endif
+
+static const struct dev_pm_ops serial_hsu_pm_ops = {
+       .runtime_suspend = serial_hsu_runtime_suspend,
+       .runtime_resume = serial_hsu_runtime_resume,
+       .runtime_idle = serial_hsu_runtime_idle,
+};
+
 /* temp global pointer before we settle down on using one or four PCI dev */
 static struct hsu_port *phsu;
 
@@ -1315,6 +1353,9 @@ static int serial_hsu_probe(struct pci_dev *pdev,
                pci_set_drvdata(pdev, uport);
        }
 
+       pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_allow(&pdev->dev);
+
        return 0;
 
 err_disable:
@@ -1411,6 +1452,9 @@ static void serial_hsu_remove(struct pci_dev *pdev)
        if (!priv)
                return;
 
+       pm_runtime_forbid(&pdev->dev);
+       pm_runtime_get_noresume(&pdev->dev);
+
        /* For port 0/1/2, priv is the address of uart_hsu_port */
        if (pdev->device != 0x081E) {
                up = priv;
@@ -1423,7 +1467,7 @@ static void serial_hsu_remove(struct pci_dev *pdev)
 }
 
 /* First 3 are UART ports, and the 4th is the DMA */
-static const struct pci_device_id pci_ids[] __devinitdata = {
+static const struct pci_device_id pci_ids[] __devinitconst = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
@@ -1438,6 +1482,9 @@ static struct pci_driver hsu_pci_driver = {
        .remove =       __devexit_p(serial_hsu_remove),
        .suspend =      serial_hsu_suspend,
        .resume =       serial_hsu_resume,
+       .driver = {
+               .pm = &serial_hsu_pm_ops,
+       },
 };
 
 static int __init hsu_pci_init(void)
index a0bcd8a..1093a88 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/sysrq.h>
 #include <linux/console.h>
@@ -273,7 +274,7 @@ static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
 
 static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
 {
-       port->irqflags = IRQF_DISABLED;
+       port->irqflags = 0;
        port->irq = irq_of_parse_and_map(np, 0);
 }
 
index 492c14d..4c309e8 100644 (file)
  *    interrupt for a low speed UART device
  */
 
+#ifdef CONFIG_MAGIC_SYSRQ
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
@@ -73,9 +77,9 @@ struct uart_max3110 {
 /* global data structure, may need be removed */
 static struct uart_max3110 *pmax;
 
-static void receive_chars(struct uart_max3110 *max,
-                               unsigned char *str, int len);
-static int max3110_read_multi(struct uart_max3110 *max, u8 *buf);
+static int receive_chars(struct uart_max3110 *max,
+                               unsigned short *str, int len);
+static int max3110_read_multi(struct uart_max3110 *max);
 static void max3110_con_receive(struct uart_max3110 *max);
 
 static int max3110_write_then_read(struct uart_max3110 *max,
@@ -108,7 +112,6 @@ static int max3110_out(struct uart_max3110 *max, const u16 out)
 {
        void *buf;
        u16 *obuf, *ibuf;
-       u8  ch;
        int ret;
 
        buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
@@ -125,11 +128,7 @@ static int max3110_out(struct uart_max3110 *max, const u16 out)
                goto exit;
        }
 
-       /* If some valid data is read back */
-       if (*ibuf & MAX3110_READ_DATA_AVAILABLE) {
-               ch = *ibuf & 0xff;
-               receive_chars(max, &ch, 1);
-       }
+       receive_chars(max, ibuf, 1);
 
 exit:
        kfree(buf);
@@ -142,12 +141,11 @@ exit:
  *
  * Return how many valide bytes are read back
  */
-static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
+static int max3110_read_multi(struct uart_max3110 *max)
 {
        void *buf;
        u16 *obuf, *ibuf;
-       u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH];
-       int i, j, blen;
+       int ret, blen;
 
        blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
        buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
@@ -165,19 +163,10 @@ static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
                return 0;
        }
 
-       /* If caller doesn't provide a buffer, then handle received char */
-       pbuf = rxbuf ? rxbuf : valid_str;
-
-       for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) {
-               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                       pbuf[j++] = ibuf[i] & 0xff;
-       }
-
-       if (j && (pbuf == valid_str))
-               receive_chars(max, valid_str, j);
+       ret = receive_chars(max, ibuf, M3110_RX_FIFO_DEPTH);
 
        kfree(buf);
-       return j;
+       return ret;
 }
 
 static void serial_m3110_con_putchar(struct uart_port *port, int ch)
@@ -207,7 +196,7 @@ static void serial_m3110_con_write(struct console *co,
        uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
 
        if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
-               wake_up_process(pmax->main_thread);
+               wake_up(&pmax->wq);
 }
 
 static int __init
@@ -276,8 +265,7 @@ static void send_circ_buf(struct uart_max3110 *max,
 {
        void *buf;
        u16 *obuf, *ibuf;
-       u8 valid_str[WORDS_PER_XFER];
-       int i, j, len, blen, dma_size, left, ret = 0;
+       int i, len, blen, dma_size, left, ret = 0;
 
 
        dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
@@ -301,18 +289,13 @@ static void send_circ_buf(struct uart_max3110 *max,
                        }
 
                        /* Fail to send msg to console is not very critical */
+
                        ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
                        if (ret)
                                pr_warning(PR_FMT "%s(): get err msg %d\n",
                                                __func__, ret);
 
-                       for (i = 0, j = 0; i < len; i++) {
-                               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                                       valid_str[j++] = ibuf[i] & 0xff;
-                       }
-
-                       if (j)
-                               receive_chars(max, valid_str, j);
+                       receive_chars(max, ibuf, len);
 
                        max->port.icount.tx += len;
                        left -= len;
@@ -349,33 +332,54 @@ static void serial_m3110_start_tx(struct uart_port *port)
                container_of(port, struct uart_max3110, port);
 
        if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
-               wake_up_process(max->main_thread);
+               wake_up(&max->wq);
 }
 
-static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
+static int
+receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
 {
        struct uart_port *port = &max->port;
        struct tty_struct *tty;
-       int usable;
+       char buf[M3110_RX_FIFO_DEPTH];
+       int r, w, usable;
 
        /* If uart is not opened, just return */
        if (!port->state)
-               return;
+               return 0;
 
-       tty = port->state->port.tty;
+       tty = tty_port_tty_get(&port->state->port);
        if (!tty)
-               return;
+               return 0;
+
+       for (r = 0, w = 0; r < len; r++) {
+               if (str[r] & MAX3110_BREAK &&
+                   uart_handle_break(port))
+                       continue;
+
+               if (str[r] & MAX3110_READ_DATA_AVAILABLE) {
+                       if (uart_handle_sysrq_char(port, str[r] & 0xff))
+                               continue;
+
+                       buf[w++] = str[r] & 0xff;
+               }
+       }
+
+       if (!w) {
+               tty_kref_put(tty);
+               return 0;
+       }
 
-       while (len) {
-               usable = tty_buffer_request_room(tty, len);
+       for (r = 0; w; r += usable, w -= usable) {
+               usable = tty_buffer_request_room(tty, w);
                if (usable) {
-                       tty_insert_flip_string(tty, str, usable);
-                       str += usable;
+                       tty_insert_flip_string(tty, buf + r, usable);
                        port->icount.rx += usable;
                }
-               len -= usable;
        }
        tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+
+       return r;
 }
 
 /*
@@ -390,28 +394,15 @@ static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
  */
 static void max3110_con_receive(struct uart_max3110 *max)
 {
-       int loop = 1, num, total = 0;
-       u8 recv_buf[512], *pbuf;
+       int loop = 1, num;
 
-       pbuf = recv_buf;
        do {
-               num = max3110_read_multi(max, pbuf);
+               num = max3110_read_multi(max);
 
                if (num) {
                        loop = 5;
-                       pbuf += num;
-                       total += num;
-
-                       if (total >= 504) {
-                               receive_chars(max, recv_buf, total);
-                               pbuf = recv_buf;
-                               total = 0;
-                       }
                }
        } while (--loop);
-
-       if (total)
-               receive_chars(max, recv_buf, total);
 }
 
 static int max3110_main_thread(void *_max)
@@ -424,7 +415,8 @@ static int max3110_main_thread(void *_max)
        pr_info(PR_FMT "start main thread\n");
 
        do {
-               wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop());
+               wait_event_interruptible(*wq,
+                               max->uart_flags || kthread_should_stop());
 
                mutex_lock(&max->thread_mutex);
 
@@ -452,8 +444,9 @@ static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
 
        /* max3110's irq is a falling edge, not level triggered,
         * so no need to disable the irq */
+
        if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
-               wake_up_process(max->main_thread);
+               wake_up(&max->wq);
 
        return IRQ_HANDLED;
 }
index c37ea48..35af073 100644 (file)
@@ -7,6 +7,7 @@
 /* status bits for all 4 MAX3110 operate modes */
 #define MAX3110_READ_DATA_AVAILABLE    (1 << 15)
 #define MAX3110_WRITE_BUF_EMPTY                (1 << 14)
+#define MAX3110_BREAK                  (1 << 10)
 
 #define WC_TAG                 (3 << 14)
 #define RC_TAG                 (1 << 14)
index e6ba838..29cbfd8 100644 (file)
@@ -804,8 +804,6 @@ static int __init msm_console_setup(struct console *co, char *options)
        if (unlikely(!port->membase))
                return -ENXIO;
 
-       port->cons = co;
-
        msm_init_clock(port);
 
        if (options)
index 624701f..60c6eb8 100644 (file)
@@ -30,6 +30,8 @@
 
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 9711e06..06f6aef 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/console.h>
 #include <linux/delay.h> /* for udelay */
 #include <linux/device.h>
index de17367..9beaff1 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/serial_reg.h>
 #include <linux/serial_core.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/irqreturn.h>
 #include <linux/mutex.h>
 #include <linux/of_platform.h>
index b46218d..21febef 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/dmi.h>
index 531931c..5c8e3bb 100644 (file)
@@ -100,6 +100,16 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
        int max_count = 256;
 
        do {
+               /* work around Errata #20 according to
+                * Intel(R) PXA27x Processor Family
+                * Specification Update (May 2005)
+                *
+                * Step 2
+                * Disable the Reciever Time Out Interrupt via IER[RTOEI]
+                */
+               up->ier &= ~UART_IER_RTOIE;
+               serial_out(up, UART_IER, up->ier);
+
                ch = serial_in(up, UART_RX);
                flag = TTY_NORMAL;
                up->port.icount.rx++;
@@ -156,6 +166,16 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
                *status = serial_in(up, UART_LSR);
        } while ((*status & UART_LSR_DR) && (max_count-- > 0));
        tty_flip_buffer_push(tty);
+
+       /* work around Errata #20 according to
+        * Intel(R) PXA27x Processor Family
+        * Specification Update (May 2005)
+        *
+        * Step 6:
+        * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]
+        */
+       up->ier |= UART_IER_RTOIE;
+       serial_out(up, UART_IER, up->ier);
 }
 
 static void transmit_chars(struct uart_pxa_port *up)
index 6edafb5..b31f1c3 100644 (file)
@@ -83,6 +83,16 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
        return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
 }
 
+/*
+ * s3c64xx and later SoC's include the interrupt mask and status registers in
+ * the controller itself, unlike the s3c24xx SoC's which have these registers
+ * in the interrupt controller. Check if the port type is s3c64xx or higher.
+ */
+static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
+{
+       return to_ourport(port)->info->type == PORT_S3C6400;
+}
+
 static void s3c24xx_serial_rx_enable(struct uart_port *port)
 {
        unsigned long flags;
@@ -126,7 +136,11 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
        struct s3c24xx_uart_port *ourport = to_ourport(port);
 
        if (tx_enabled(port)) {
-               disable_irq_nosync(ourport->tx_irq);
+               if (s3c24xx_serial_has_interrupt_mask(port))
+                       __set_bit(S3C64XX_UINTM_TXD,
+                               portaddrl(port, S3C64XX_UINTM));
+               else
+                       disable_irq_nosync(ourport->tx_irq);
                tx_enabled(port) = 0;
                if (port->flags & UPF_CONS_FLOW)
                        s3c24xx_serial_rx_enable(port);
@@ -141,19 +155,26 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
                if (port->flags & UPF_CONS_FLOW)
                        s3c24xx_serial_rx_disable(port);
 
-               enable_irq(ourport->tx_irq);
+               if (s3c24xx_serial_has_interrupt_mask(port))
+                       __clear_bit(S3C64XX_UINTM_TXD,
+                               portaddrl(port, S3C64XX_UINTM));
+               else
+                       enable_irq(ourport->tx_irq);
                tx_enabled(port) = 1;
        }
 }
 
-
 static void s3c24xx_serial_stop_rx(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
 
        if (rx_enabled(port)) {
                dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
-               disable_irq_nosync(ourport->rx_irq);
+               if (s3c24xx_serial_has_interrupt_mask(port))
+                       __set_bit(S3C64XX_UINTM_RXD,
+                               portaddrl(port, S3C64XX_UINTM));
+               else
+                       disable_irq_nosync(ourport->rx_irq);
                rx_enabled(port) = 0;
        }
 }
@@ -320,6 +341,28 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
        return IRQ_HANDLED;
 }
 
+/* interrupt handler for s3c64xx and later SoC's.*/
+static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
+{
+       struct s3c24xx_uart_port *ourport = id;
+       struct uart_port *port = &ourport->port;
+       unsigned int pend = rd_regl(port, S3C64XX_UINTP);
+       unsigned long flags;
+       irqreturn_t ret = IRQ_HANDLED;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (pend & S3C64XX_UINTM_RXD_MSK) {
+               ret = s3c24xx_serial_rx_chars(irq, id);
+               wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK);
+       }
+       if (pend & S3C64XX_UINTM_TXD_MSK) {
+               ret = s3c24xx_serial_tx_chars(irq, id);
+               wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK);
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+       return ret;
+}
+
 static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
 {
        struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
@@ -377,18 +420,25 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
        struct s3c24xx_uart_port *ourport = to_ourport(port);
 
        if (ourport->tx_claimed) {
-               free_irq(ourport->tx_irq, ourport);
+               if (!s3c24xx_serial_has_interrupt_mask(port))
+                       free_irq(ourport->tx_irq, ourport);
                tx_enabled(port) = 0;
                ourport->tx_claimed = 0;
        }
 
        if (ourport->rx_claimed) {
-               free_irq(ourport->rx_irq, ourport);
+               if (!s3c24xx_serial_has_interrupt_mask(port))
+                       free_irq(ourport->rx_irq, ourport);
                ourport->rx_claimed = 0;
                rx_enabled(port) = 0;
        }
-}
 
+       /* Clear pending interrupts and mask all interrupts */
+       if (s3c24xx_serial_has_interrupt_mask(port)) {
+               wr_regl(port, S3C64XX_UINTP, 0xf);
+               wr_regl(port, S3C64XX_UINTM, 0xf);
+       }
+}
 
 static int s3c24xx_serial_startup(struct uart_port *port)
 {
@@ -436,6 +486,33 @@ static int s3c24xx_serial_startup(struct uart_port *port)
        return ret;
 }
 
+static int s3c64xx_serial_startup(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       int ret;
+
+       dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
+           port->mapbase, port->membase);
+
+       ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
+                         s3c24xx_serial_portname(port), ourport);
+       if (ret) {
+               printk(KERN_ERR "cannot get irq %d\n", port->irq);
+               return ret;
+       }
+
+       /* For compatibility with s3c24xx Soc's */
+       rx_enabled(port) = 1;
+       ourport->rx_claimed = 1;
+       tx_enabled(port) = 0;
+       ourport->tx_claimed = 1;
+
+       /* Enable Rx Interrupt */
+       __clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
+       dbg("s3c64xx_serial_startup ok\n");
+       return ret;
+}
+
 /* power power management control */
 
 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@ -879,7 +956,6 @@ static struct uart_ops s3c24xx_serial_ops = {
        .verify_port    = s3c24xx_serial_verify_port,
 };
 
-
 static struct uart_driver s3c24xx_uart_drv = {
        .owner          = THIS_MODULE,
        .driver_name    = "s3c2410_serial",
@@ -895,7 +971,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
                .port = {
                        .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
                        .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX0,
                        .uartclk        = 0,
                        .fifosize       = 16,
                        .ops            = &s3c24xx_serial_ops,
@@ -907,7 +982,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
                .port = {
                        .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
                        .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX1,
                        .uartclk        = 0,
                        .fifosize       = 16,
                        .ops            = &s3c24xx_serial_ops,
@@ -921,7 +995,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
                .port = {
                        .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
                        .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX2,
                        .uartclk        = 0,
                        .fifosize       = 16,
                        .ops            = &s3c24xx_serial_ops,
@@ -935,7 +1008,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
                .port = {
                        .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
                        .iotype         = UPIO_MEM,
-                       .irq            = IRQ_S3CUART_RX3,
                        .uartclk        = 0,
                        .fifosize       = 16,
                        .ops            = &s3c24xx_serial_ops,
@@ -1077,6 +1149,10 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
        port->dev       = &platdev->dev;
        ourport->info   = info;
 
+       /* Startup sequence is different for s3c64xx and higher SoC's */
+       if (s3c24xx_serial_has_interrupt_mask(port))
+               s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
+
        /* copy the info in from provided structure */
        ourport->port.fifosize = info->fifosize;
 
@@ -1116,6 +1192,13 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 
        ourport->clk    = clk_get(&platdev->dev, "uart");
 
+       /* Keep all interrupts masked and cleared */
+       if (s3c24xx_serial_has_interrupt_mask(port)) {
+               wr_regl(port, S3C64XX_UINTM, 0xf);
+               wr_regl(port, S3C64XX_UINTP, 0xf);
+               wr_regl(port, S3C64XX_UINTSP, 0xf);
+       }
+
        dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
            port->mapbase, port->membase, port->irq,
            ourport->rx_irq, ourport->tx_irq, port->uartclk);
index a69d9a5..8e87b78 100644 (file)
@@ -61,6 +61,7 @@ struct s3c24xx_uart_port {
 /* register access controls */
 
 #define portaddr(port, reg) ((port)->membase + (reg))
+#define portaddrl(port, reg) ((unsigned long *)((port)->membase + (reg)))
 
 #define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
 #define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
index 6bc2e3f..0be8a2f 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/spinlock.h>
 #include <linux/sysrq.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/types.h>
 
 #include <linux/atomic.h>
index a3efbea..0406d7f 100644 (file)
@@ -57,7 +57,7 @@ static struct lock_class_key port_lock_key;
 
 static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
                                        struct ktermios *old_termios);
-static void __uart_wait_until_sent(struct uart_port *port, int timeout);
+static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
 static void uart_change_pm(struct uart_state *state, int pm_state);
 
 /*
@@ -72,7 +72,7 @@ void uart_write_wakeup(struct uart_port *port)
         * closed.  No cookie for you.
         */
        BUG_ON(!state);
-       tasklet_schedule(&state->tlet);
+       tty_wakeup(state->port.tty);
 }
 
 static void uart_stop(struct tty_struct *tty)
@@ -107,12 +107,6 @@ static void uart_start(struct tty_struct *tty)
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static void uart_tasklet_action(unsigned long data)
-{
-       struct uart_state *state = (struct uart_state *)data;
-       tty_wakeup(state->port.tty);
-}
-
 static inline void
 uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
 {
@@ -255,9 +249,11 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
        }
 
        /*
-        * kill off our tasklet
+        * It's possible for shutdown to be called after suspend if we get
+        * a DCD drop (hangup) at just the right time.  Clear suspended bit so
+        * we don't try to resume a port that has been shutdown.
         */
-       tasklet_kill(&state->tlet);
+       clear_bit(ASYNCB_SUSPENDED, &port->flags);
 
        /*
         * Free the transmit buffer page.
@@ -1261,8 +1257,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        struct uart_port *uport;
        unsigned long flags;
 
-       BUG_ON(!tty_locked());
-
        if (!state)
                return;
 
@@ -1271,12 +1265,11 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
 
        pr_debug("uart_close(%d) called\n", uport->line);
 
-       mutex_lock(&port->mutex);
        spin_lock_irqsave(&port->lock, flags);
 
        if (tty_hung_up_p(filp)) {
                spin_unlock_irqrestore(&port->lock, flags);
-               goto done;
+               return;
        }
 
        if ((tty->count == 1) && (port->count != 1)) {
@@ -1298,7 +1291,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        }
        if (port->count) {
                spin_unlock_irqrestore(&port->lock, flags);
-               goto done;
+               return;
        }
 
        /*
@@ -1306,19 +1299,13 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
         * the line discipline to only process XON/XOFF characters by
         * setting tty->closing.
         */
+       set_bit(ASYNCB_CLOSING, &port->flags);
        tty->closing = 1;
        spin_unlock_irqrestore(&port->lock, flags);
 
-       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
-               /*
-                * hack: open-coded tty_wait_until_sent to avoid
-                * recursive tty_lock
-                */
-               long timeout = msecs_to_jiffies(port->closing_wait);
-               if (wait_event_interruptible_timeout(tty->write_wait,
-                               !tty_chars_in_buffer(tty), timeout) >= 0)
-                       __uart_wait_until_sent(uport, timeout);
-       }
+       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent_from_close(tty,
+                               msecs_to_jiffies(port->closing_wait));
 
        /*
         * At this point, we stop accepting input.  To do this, we
@@ -1334,9 +1321,10 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
                 * has completely drained; this is especially
                 * important if there is a transmit FIFO!
                 */
-               __uart_wait_until_sent(uport, uport->timeout);
+               uart_wait_until_sent(tty, uport->timeout);
        }
 
+       mutex_lock(&port->mutex);
        uart_shutdown(tty, state);
        uart_flush_buffer(tty);
 
@@ -1361,15 +1349,18 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
         * Wake up anyone trying to open this port.
         */
        clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
+       clear_bit(ASYNCB_CLOSING, &port->flags);
        spin_unlock_irqrestore(&port->lock, flags);
        wake_up_interruptible(&port->open_wait);
+       wake_up_interruptible(&port->close_wait);
 
-done:
        mutex_unlock(&port->mutex);
 }
 
-static void __uart_wait_until_sent(struct uart_port *port, int timeout)
+static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
 {
+       struct uart_state *state = tty->driver_data;
+       struct uart_port *port = state->uart_port;
        unsigned long char_time, expire;
 
        if (port->type == PORT_UNKNOWN || port->fifosize == 0)
@@ -1421,16 +1412,6 @@ static void __uart_wait_until_sent(struct uart_port *port, int timeout)
        }
 }
 
-static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       struct uart_state *state = tty->driver_data;
-       struct uart_port *port = state->uart_port;
-
-       tty_lock();
-       __uart_wait_until_sent(port, timeout);
-       tty_unlock();
-}
-
 /*
  * This is called with the BKL held in
  *  linux/drivers/char/tty_io.c:do_tty_hangup()
@@ -1443,7 +1424,6 @@ static void uart_hangup(struct tty_struct *tty)
        struct tty_port *port = &state->port;
        unsigned long flags;
 
-       BUG_ON(!tty_locked());
        pr_debug("uart_hangup(%d)\n", state->uart_port->line);
 
        mutex_lock(&port->mutex);
@@ -1530,7 +1510,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        struct tty_port *port;
        int retval, line = tty->index;
 
-       BUG_ON(!tty_locked());
        pr_debug("uart_open(%d) called\n", line);
 
        /*
@@ -2008,6 +1987,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
                if (port->tty && port->tty->termios && termios.c_cflag == 0)
                        termios = *(port->tty->termios);
 
+               if (console_suspend_enabled)
+                       uart_change_pm(state, 0);
                uport->ops->set_termios(uport, &termios, NULL);
                if (console_suspend_enabled)
                        console_start(uport->cons);
@@ -2068,8 +2049,6 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
        case UPIO_MEM32:
        case UPIO_AU:
        case UPIO_TSI:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                snprintf(address, sizeof(address),
                         "MMIO 0x%llx", (unsigned long long)port->mapbase);
                break;
@@ -2298,8 +2277,6 @@ int uart_register_driver(struct uart_driver *drv)
                port->ops = &uart_port_ops;
                port->close_delay     = 500;    /* .5 seconds */
                port->closing_wait    = 30000;  /* 30 seconds */
-               tasklet_init(&state->tlet, uart_tasklet_action,
-                            (unsigned long)state);
        }
 
        retval = tty_register_driver(normal);
@@ -2460,11 +2437,6 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
         */
        uport->type = PORT_UNKNOWN;
 
-       /*
-        * Kill the tasklet, and free resources.
-        */
-       tasklet_kill(&state->tlet);
-
        state->uart_port = NULL;
        mutex_unlock(&port_mutex);
 
@@ -2489,8 +2461,6 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
        case UPIO_MEM32:
        case UPIO_AU:
        case UPIO_TSI:
-       case UPIO_DWAPB:
-       case UPIO_DWAPB32:
                return (port1->mapbase == port2->mapbase);
        }
        return 0;
index 2430319..7c13639 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/module.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/serial.h>
@@ -336,19 +337,19 @@ static int ks8695uart_startup(struct uart_port *port)
        /*
         * Allocate the IRQ
         */
-       retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port);
+       retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, 0, "UART TX", port);
        if (retval)
                goto err_tx;
 
-       retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port);
+       retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, 0, "UART RX", port);
        if (retval)
                goto err_rx;
 
-       retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port);
+       retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, 0, "UART LineStatus", port);
        if (retval)
                goto err_ls;
 
-       retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port);
+       retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, 0, "UART ModemStatus", port);
        if (retval)
                goto err_ms;
 
index 8e3fc19..34bd345 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/pci.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 
 #include <asm/io.h>
 
index 5ea6ec3..9871c57 100644 (file)
@@ -1976,7 +1976,7 @@ static int __devinit sci_init_single(struct platform_device *dev,
         * For the muxed case there's nothing more to do.
         */
        port->irq               = p->irqs[SCIx_RXI_IRQ];
-       port->irqflags          = IRQF_DISABLED;
+       port->irqflags          = 0;
 
        port->serial_in         = sci_serial_in;
        port->serial_out        = sci_serial_out;
index 377ae74..238c7df 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/console.h>
 #include <linux/module.h>
@@ -737,7 +738,7 @@ static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
                DPRINTF("sn_console: switching to interrupt driven console\n");
 
                if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
-                               IRQF_DISABLED | IRQF_SHARED,
+                               IRQF_SHARED,
                                "SAL console driver", port) >= 0) {
                        spin_lock_irqsave(&port->sc_port.lock, flags);
                        port->sc_port.irq = SGI_UART_VECTOR;
index 1f36b7e..a4b63bf 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/ioport.h>
index 8af1ed8..b908615 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
index 9af9f08..cea8918 100644 (file)
 
 #include <linux/module.h>
 #include <linux/serial.h>
-#include <linux/slab.h>
 #include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/dma-mapping.h>
index 19cc1e8..8c03b12 100644 (file)
  */
 
 #include <linux/platform_device.h>
+#include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/console.h>
-#include <linux/serial.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/of.h>
index 0aebd71..b7455b5 100644 (file)
@@ -63,6 +63,7 @@
 #include <linux/spinlock.h>
 #include <linux/sysrq.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/types.h>
 
 #include <linux/atomic.h>
index 272e417..e67fb20 100644 (file)
@@ -2124,7 +2124,6 @@ static int mgsl_write(struct tty_struct * tty,
        if ( info->params.mode == MGSL_MODE_HDLC ||
                        info->params.mode == MGSL_MODE_RAW ) {
                /* operating in synchronous (frame oriented) mode */
-               /* operating in synchronous (frame oriented) mode */
                if (info->tx_active) {
 
                        if ( info->params.mode == MGSL_MODE_HDLC ) {
index c77831c..0f6b796 100644 (file)
@@ -4950,7 +4950,7 @@ CheckAgain:
 
        if ( debug_level >= DEBUG_LEVEL_DATA )
                trace_block(info,info->rx_buf_list_ex[StartIndex].virt_addr,
-                       min_t(int, framesize,SCABUFSIZE),0);
+                       min_t(unsigned int, framesize, SCABUFSIZE), 0);
 
        if (framesize) {
                if (framesize > info->max_frame_size)
@@ -5015,14 +5015,14 @@ static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int co
        SCADESC_EX *desc_ex;
 
        if ( debug_level >= DEBUG_LEVEL_DATA )
-               trace_block(info,buf, min_t(int, count,SCABUFSIZE), 1);
+               trace_block(info, buf, min_t(unsigned int, count, SCABUFSIZE), 1);
 
        /* Copy source buffer to one or more DMA buffers, starting with
         * the first transmit dma buffer.
         */
        for(i=0;;)
        {
-               copy_count = min_t(unsigned short,count,SCABUFSIZE);
+               copy_count = min_t(unsigned int, count, SCABUFSIZE);
 
                desc = &info->tx_buf_list[i];
                desc_ex = &info->tx_buf_list_ex[i];
index 4f1fc81..05085be 100644 (file)
@@ -194,8 +194,7 @@ static inline struct tty_struct *file_tty(struct file *file)
        return ((struct tty_file_private *)file->private_data)->tty;
 }
 
-/* Associate a new file with the tty structure */
-int tty_add_file(struct tty_struct *tty, struct file *file)
+int tty_alloc_file(struct file *file)
 {
        struct tty_file_private *priv;
 
@@ -203,15 +202,36 @@ int tty_add_file(struct tty_struct *tty, struct file *file)
        if (!priv)
                return -ENOMEM;
 
+       file->private_data = priv;
+
+       return 0;
+}
+
+/* Associate a new file with the tty structure */
+void tty_add_file(struct tty_struct *tty, struct file *file)
+{
+       struct tty_file_private *priv = file->private_data;
+
        priv->tty = tty;
        priv->file = file;
-       file->private_data = priv;
 
        spin_lock(&tty_files_lock);
        list_add(&priv->list, &tty->tty_files);
        spin_unlock(&tty_files_lock);
+}
 
-       return 0;
+/**
+ * tty_free_file - free file->private_data
+ *
+ * This shall be used only for fail path handling when tty_add_file was not
+ * called yet.
+ */
+void tty_free_file(struct file *file)
+{
+       struct tty_file_private *priv = file->private_data;
+
+       file->private_data = NULL;
+       kfree(priv);
 }
 
 /* Delete file from its tty */
@@ -222,8 +242,7 @@ void tty_del_file(struct file *file)
        spin_lock(&tty_files_lock);
        list_del(&priv->list);
        spin_unlock(&tty_files_lock);
-       file->private_data = NULL;
-       kfree(priv);
+       tty_free_file(file);
 }
 
 
@@ -1811,6 +1830,10 @@ static int tty_open(struct inode *inode, struct file *filp)
        nonseekable_open(inode, filp);
 
 retry_open:
+       retval = tty_alloc_file(filp);
+       if (retval)
+               return -ENOMEM;
+
        noctty = filp->f_flags & O_NOCTTY;
        index  = -1;
        retval = 0;
@@ -1823,6 +1846,7 @@ retry_open:
                if (!tty) {
                        tty_unlock();
                        mutex_unlock(&tty_mutex);
+                       tty_free_file(filp);
                        return -ENXIO;
                }
                driver = tty_driver_kref_get(tty->driver);
@@ -1855,6 +1879,7 @@ retry_open:
                }
                tty_unlock();
                mutex_unlock(&tty_mutex);
+               tty_free_file(filp);
                return -ENODEV;
        }
 
@@ -1862,6 +1887,7 @@ retry_open:
        if (!driver) {
                tty_unlock();
                mutex_unlock(&tty_mutex);
+               tty_free_file(filp);
                return -ENODEV;
        }
 got_driver:
@@ -1872,6 +1898,8 @@ got_driver:
                if (IS_ERR(tty)) {
                        tty_unlock();
                        mutex_unlock(&tty_mutex);
+                       tty_driver_kref_put(driver);
+                       tty_free_file(filp);
                        return PTR_ERR(tty);
                }
        }
@@ -1887,15 +1915,11 @@ got_driver:
        tty_driver_kref_put(driver);
        if (IS_ERR(tty)) {
                tty_unlock();
+               tty_free_file(filp);
                return PTR_ERR(tty);
        }
 
-       retval = tty_add_file(tty, filp);
-       if (retval) {
-               tty_unlock();
-               tty_release(inode, filp);
-               return retval;
-       }
+       tty_add_file(tty, filp);
 
        check_tty_count(tty, "tty_open");
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -2716,6 +2740,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
        ld = tty_ldisc_ref_wait(tty);
        if (ld->ops->compat_ioctl)
                retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
+       else
+               retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg);
        tty_ldisc_deref(ld);
 
        return retval;
index 53f2442..9314d93 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
+#include <linux/compat.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -1179,3 +1180,19 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
        }
 }
 EXPORT_SYMBOL(n_tty_ioctl_helper);
+
+#ifdef CONFIG_COMPAT
+long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
+                                       unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case TIOCGLCKTRMIOS:
+       case TIOCSLCKTRMIOS:
+               return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg));
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+EXPORT_SYMBOL(n_tty_compat_ioctl_helper);
+#endif
+
index ef925d5..512c49f 100644 (file)
@@ -450,7 +450,6 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
        if (ld->ops->open) {
                int ret;
                 /* BTM here locks versus a hangup event */
-               WARN_ON(!tty_locked());
                ret = ld->ops->open(tty);
                if (ret)
                        clear_bit(TTY_LDISC_OPEN, &tty->flags);
index 3b2bb77..9ff986c 100644 (file)
  * Don't use in new code.
  */
 static DEFINE_MUTEX(big_tty_mutex);
-struct task_struct *__big_tty_mutex_owner;
-EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
 
 /*
  * Getting the big tty mutex.
  */
 void __lockfunc tty_lock(void)
 {
-       struct task_struct *task = current;
-
-       WARN_ON(__big_tty_mutex_owner == task);
-
        mutex_lock(&big_tty_mutex);
-       __big_tty_mutex_owner = task;
 }
 EXPORT_SYMBOL(tty_lock);
 
 void __lockfunc tty_unlock(void)
 {
-       struct task_struct *task = current;
-
-       WARN_ON(__big_tty_mutex_owner != task);
-       __big_tty_mutex_owner = NULL;
-
        mutex_unlock(&big_tty_mutex);
 }
 EXPORT_SYMBOL(tty_unlock);
index 33d37d2..ef9dd62 100644 (file)
@@ -350,7 +350,7 @@ int tty_port_close_start(struct tty_port *port,
                tty_driver_flush_buffer(tty);
        if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
                        port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, port->closing_wait);
+               tty_wait_until_sent_from_close(tty, port->closing_wait);
        if (port->drain_delay) {
                unsigned int bps = tty_get_baud_rate(tty);
                long timeout;
index 3761ccf..a605549 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/irq.h>
 
 #include <linux/kbd_kern.h>
 #include <linux/kbd_diacr.h>
@@ -43,6 +42,8 @@
 #include <linux/notifier.h>
 #include <linux/jiffies.h>
 
+#include <asm/irq_regs.h>
+
 extern void ctrl_alt_del(void);
 
 /*
index fb864e7..7a0a12a 100644 (file)
@@ -301,6 +301,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
 /* Insert the contents of the selection buffer into the
  * queue of the tty associated with the current console.
  * Invoked by ioctl().
+ *
+ * Locking: always called with BTM from vt_ioctl
  */
 int paste_selection(struct tty_struct *tty)
 {
@@ -310,8 +312,6 @@ int paste_selection(struct tty_struct *tty)
        struct  tty_ldisc *ld;
        DECLARE_WAITQUEUE(wait, current);
 
-       /* always called with BTM from vt_ioctl */
-       WARN_ON(!tty_locked());
 
        console_lock();
        poke_blanked_console();
index b3915b7..e716839 100644 (file)
@@ -259,7 +259,7 @@ EXPORT_SYMBOL_GPL(unregister_vt_notifier);
 
 static void notify_write(struct vc_data *vc, unsigned int unicode)
 {
-       struct vt_notifier_param param = { .vc = vc, unicode = unicode };
+       struct vt_notifier_param param = { .vc = vc, .c = unicode };
        atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
 }
 
index ef91406..97ff8e2 100644 (file)
@@ -211,6 +211,7 @@ struct serial_rs485 {
 #define SER_RS485_RTS_ON_SEND          (1 << 1)
 #define SER_RS485_RTS_AFTER_SEND       (1 << 2)
 #define SER_RS485_RTS_BEFORE_SEND      (1 << 3)
+#define SER_RS485_RX_DURING_TX         (1 << 4)
        __u32   delay_rts_before_send;  /* Milliseconds */
        __u32   delay_rts_after_send;   /* Milliseconds */
        __u32   padding[5];             /* Memory is cheap, new structs
index 97f5b45..1f05bbe 100644 (file)
@@ -35,6 +35,7 @@ struct plat_serial8250_port {
        void            (*set_termios)(struct uart_port *,
                                       struct ktermios *new,
                                       struct ktermios *old);
+       int             (*handle_irq)(struct uart_port *);
        void            (*pm)(struct uart_port *, unsigned int state,
                              unsigned old);
 };
@@ -80,6 +81,7 @@ extern void serial8250_do_set_termios(struct uart_port *port,
                struct ktermios *termios, struct ktermios *old);
 extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
                             unsigned int oldstate);
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
 
 extern void serial8250_set_isa_configurator(void (*v)
                                        (int port, struct uart_port *up,
index a5c3114..eadf33d 100644 (file)
@@ -46,7 +46,8 @@
 #define PORT_AR7       18      /* Texas Instruments AR7 internal UART */
 #define PORT_U6_16550A 19      /* ST-Ericsson U6xxx internal UART */
 #define PORT_TEGRA     20      /* NVIDIA Tegra internal UART */
-#define PORT_MAX_8250  20      /* max port ID */
+#define PORT_XR17D15X  21      /* Exar XR17D15x UART */
+#define PORT_MAX_8250  21      /* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
@@ -300,6 +301,7 @@ struct uart_port {
        void                    (*set_termios)(struct uart_port *,
                                               struct ktermios *new,
                                               struct ktermios *old);
+       int                     (*handle_irq)(struct uart_port *);
        void                    (*pm)(struct uart_port *, unsigned int state,
                                      unsigned int old);
        unsigned int            irq;                    /* irq number */
@@ -317,9 +319,7 @@ struct uart_port {
 #define UPIO_MEM32             (3)
 #define UPIO_AU                        (4)                     /* Au1x00 type IO */
 #define UPIO_TSI               (5)                     /* Tsi108/109 type IO */
-#define UPIO_DWAPB             (6)                     /* DesignWare APB UART */
-#define UPIO_RM9000            (7)                     /* RM9000 type IO */
-#define UPIO_DWAPB32           (8)                     /* DesignWare APB UART (32 bit accesses) */
+#define UPIO_RM9000            (6)                     /* RM9000 type IO */
 
        unsigned int            read_status_mask;       /* driver specific */
        unsigned int            ignore_status_mask;     /* driver specific */
@@ -350,6 +350,7 @@ struct uart_port {
 #define UPF_MAGIC_MULTIPLIER   ((__force upf_t) (1 << 16))
 #define UPF_CONS_FLOW          ((__force upf_t) (1 << 23))
 #define UPF_SHARE_IRQ          ((__force upf_t) (1 << 24))
+#define UPF_EXAR_EFR           ((__force upf_t) (1 << 25))
 /* The exact UART type is known and should not be probed.  */
 #define UPF_FIXED_TYPE         ((__force upf_t) (1 << 27))
 #define UPF_BOOT_AUTOCONF      ((__force upf_t) (1 << 28))
@@ -384,7 +385,6 @@ struct uart_state {
        int                     pm_state;
        struct circ_buf         xmit;
 
-       struct tasklet_struct   tlet;
        struct uart_port        *uart_port;
 };
 
index c75bda3..8ce70d7 100644 (file)
  * LCR=0xBF (or DLAB=1 for 16C660)
  */
 #define UART_EFR       2       /* I/O: Extended Features Register */
+#define UART_XR_EFR    9       /* I/O: Extended Features Register (XR17D15x) */
 #define UART_EFR_CTS           0x80 /* CTS flow control */
 #define UART_EFR_RTS           0x40 /* RTS flow control */
 #define UART_EFR_SCD           0x20 /* Special character detect */
index 5f2ede8..5dbb3cb 100644 (file)
@@ -473,7 +473,9 @@ extern void proc_clear_tty(struct task_struct *p);
 extern struct tty_struct *get_current_tty(void);
 extern void tty_default_fops(struct file_operations *fops);
 extern struct tty_struct *alloc_tty_struct(void);
-extern int tty_add_file(struct tty_struct *tty, struct file *file);
+extern int tty_alloc_file(struct file *file);
+extern void tty_add_file(struct tty_struct *tty, struct file *file);
+extern void tty_free_file(struct file *file);
 extern void free_tty_struct(struct tty_struct *tty);
 extern void initialize_tty_struct(struct tty_struct *tty,
                struct tty_driver *driver, int idx);
@@ -581,6 +583,8 @@ extern int __init tty_init(void);
 /* tty_ioctl.c */
 extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
                       unsigned int cmd, unsigned long arg);
+extern long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg);
 
 /* serial.c */
 
@@ -602,8 +606,24 @@ extern long vt_compat_ioctl(struct tty_struct *tty,
 /* functions for preparation of BKL removal */
 extern void __lockfunc tty_lock(void) __acquires(tty_lock);
 extern void __lockfunc tty_unlock(void) __releases(tty_lock);
-extern struct task_struct *__big_tty_mutex_owner;
-#define tty_locked()           (current == __big_tty_mutex_owner)
+
+/*
+ * this shall be called only from where BTM is held (like close)
+ *
+ * We need this to ensure nobody waits for us to finish while we are waiting.
+ * Without this we were encountering system stalls.
+ *
+ * This should be indeed removed with BTM removal later.
+ *
+ * Locking: BTM required. Nobody is allowed to hold port->mutex.
+ */
+static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
+               long timeout)
+{
+       tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */
+       tty_wait_until_sent(tty, timeout);
+       tty_lock();
+}
 
 /*
  * wait_event_interruptible_tty -- wait for a condition with the tty lock held
index b3cc8b3..253695d 100644 (file)
@@ -551,7 +551,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
         */
        tty->closing = 1;
        if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, self->closing_wait);
+               tty_wait_until_sent_from_close(tty, self->closing_wait);
 
        ircomm_tty_shutdown(self);