]> Pileus Git - ~andy/linux/commitdiff
Merge tag 'tty-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 21 Jan 2014 00:05:23 +0000 (16:05 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 21 Jan 2014 00:05:23 +0000 (16:05 -0800)
Pull tty/serial driver updates from Greg KH:
 "Here's the big tty/serial driver pull request for 3.14-rc1

  There are a number of n_tty fixes and cleanups, and some serial driver
  bugfixes, and we got rid of one obsolete driver, making this series
  remove more lines than added, always a nice surprise.

  All of these have been in linux-next with no reports of issues"

* tag 'tty-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (60 commits)
  tty/serial: at91: disable uart timer at start of shutdown
  serial: 8250: enable UART_BUG_NOMSR for Tegra
  tty/serial: at91: reset rx_ring when port is shutdown
  tty/serial: at91: fix race condition in atmel_serial_remove
  tty/serial: at91: Handle shutdown more safely
  serial: sirf: correct condition for fetching dma buffer into tty
  serial: sirf: provide pm entries of uart_ops
  serial: sirf: use PM macro initialize PM functions
  serial: clps711x: Enable driver compilation with COMPILE_TEST
  serial: clps711x: Add support for N_IRDA line discipline
  tty: synclink: avoid sleep_on race
  tty/amiserial: avoid interruptible_sleep_on
  tty: delete non-required instances of include <linux/init.h>
  tty: an overflow of multiplication in drivers/tty/cyclades.c
  serial: Remove old SC26XX driver
  serial: add support for 200 v3 series Titan card
  serial: 8250: Fix initialisation of Quatech cards with the AMCC PCI chip
  tty: Removing the deprecated function tty_vhangup_locked()
  TTY/n_gsm: Removing the wrong tty_unlock/lock() in gsm_dlci_release()
  tty/serial: at91: document clock properties
  ...

52 files changed:
Documentation/devicetree/bindings/serial/atmel-usart.txt
Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt [new file with mode: 0644]
arch/arm/mach-clps711x/devices.c
drivers/char/pcmcia/synclink_cs.c
drivers/input/serio/serport.c
drivers/parport/parport_serial.c
drivers/staging/fwserial/Kconfig
drivers/staging/fwserial/fwserial.c
drivers/staging/fwserial/fwserial.h
drivers/tty/amiserial.c
drivers/tty/cyclades.c
drivers/tty/goldfish.c
drivers/tty/hvc/hvc_console.c
drivers/tty/hvc/hvsi_lib.c
drivers/tty/ipwireless/tty.c
drivers/tty/n_gsm.c
drivers/tty/n_r3964.c
drivers/tty/n_tty.c
drivers/tty/rocket.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_em.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_pnp.c
drivers/tty/serial/8250/serial_cs.c
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/amba-pl010.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/clps711x.c
drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
drivers/tty/serial/imx.c
drivers/tty/serial/kgdb_nmi.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/of_serial.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/rp2.c
drivers/tty/serial/sc26xx.c [deleted file]
drivers/tty/serial/serial_core.c
drivers/tty/serial/sirfsoc_uart.c
drivers/tty/synclink.c
drivers/tty/synclink_gt.c
drivers/tty/synclinkmp.c
drivers/tty/tty_buffer.c
drivers/tty/tty_ldisc.c
drivers/tty/tty_port.c
include/linux/init.h
include/linux/tty.h
include/linux/tty_flip.h
include/linux/tty_ldisc.h

index 2191dcb9f1da986d008a87688ea0af693ea3bf28..9c5d19ac935c335d88400b6724aaff75b5c99712 100644 (file)
@@ -6,6 +6,9 @@ Required properties:
   additional mode or an USART new feature.
 - reg: Should contain registers location and length
 - interrupts: Should contain interrupt
+- clock-names: tuple listing input clock names.
+       Required elements: "usart"
+- clocks: phandles to input clocks.
 
 Optional properties:
 - atmel,use-dma-rx: use of PDC or DMA for receiving data
@@ -26,6 +29,8 @@ Example:
                compatible = "atmel,at91sam9260-usart";
                reg = <0xfff8c000 0x4000>;
                interrupts = <7>;
+               clocks = <&usart0_clk>;
+               clock-names = "usart";
                atmel,use-dma-rx;
                atmel,use-dma-tx;
        };
@@ -35,6 +40,8 @@ Example:
                compatible = "atmel,at91sam9260-usart";
                reg = <0xf001c000 0x100>;
                interrupts = <12 4 5>;
+               clocks = <&usart0_clk>;
+               clock-names = "usart";
                atmel,use-dma-rx;
                atmel,use-dma-tx;
                dmas = <&dma0 2 0x3>,
diff --git a/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt b/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt
new file mode 100644 (file)
index 0000000..12f3cf8
--- /dev/null
@@ -0,0 +1,28 @@
+* Cirrus Logic CLPS711X Universal Asynchronous Receiver/Transmitter (UART)
+
+Required properties:
+- compatible: Should be "cirrus,clps711x-uart".
+- reg: Address and length of the register set for the device.
+- interrupts: Should contain UART TX and RX interrupt.
+- clocks: Should contain UART core clock number.
+- syscon: Phandle to SYSCON node, which contain UART control bits.
+
+Optional properties:
+- uart-use-ms: Indicate the UART has modem signal (DCD, DSR, CTS).
+
+Note: Each UART port should have an alias correctly numbered
+in "aliases" node.
+
+Example:
+       aliases {
+               serial0 = &uart1;
+       };
+
+       uart1: uart@80000480 {
+               compatible = "cirrus,clps711x-uart";
+               reg = <0x80000480 0x80>;
+               interrupts = <12 13>;
+               clocks = <&clks 11>;
+               syscon = <&syscon1>;
+               uart-use-ms;
+       };
index fb77d1448fec880f115d45593e7ffd2a171883fa..2001488a5ef24b4831889946309bcae16d684166 100644 (file)
@@ -61,8 +61,29 @@ static void __init clps711x_add_syscon(void)
                                                &clps711x_syscon_res[i], 1);
 }
 
+static const struct resource clps711x_uart1_res[] __initconst = {
+       DEFINE_RES_MEM(CLPS711X_PHYS_BASE + UARTDR1, SZ_128),
+       DEFINE_RES_IRQ(IRQ_UTXINT1),
+       DEFINE_RES_IRQ(IRQ_URXINT1),
+};
+
+static const struct resource clps711x_uart2_res[] __initconst = {
+       DEFINE_RES_MEM(CLPS711X_PHYS_BASE + UARTDR2, SZ_128),
+       DEFINE_RES_IRQ(IRQ_UTXINT2),
+       DEFINE_RES_IRQ(IRQ_URXINT2),
+};
+
+static void __init clps711x_add_uart(void)
+{
+       platform_device_register_simple("clps711x-uart", 0, clps711x_uart1_res,
+                                       ARRAY_SIZE(clps711x_uart1_res));
+       platform_device_register_simple("clps711x-uart", 1, clps711x_uart2_res,
+                                       ARRAY_SIZE(clps711x_uart2_res));
+};
+
 void __init clps711x_devices_init(void)
 {
        clps711x_add_gpio();
        clps711x_add_syscon();
+       clps711x_add_uart();
 }
index d39cca659a3f4839233475d32a6d63c16553209d..8320abd1ef1473ddfda6820c8a6bcaa689f73824 100644 (file)
@@ -2511,8 +2511,8 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
 
        /* If port is closing, signal caller to try again */
        if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING){
-               if (port->flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&port->close_wait);
+               wait_event_interruptible_tty(tty, port->close_wait,
+                                            !(port->flags & ASYNC_CLOSING));
                retval = ((port->flags & ASYNC_HUP_NOTIFY) ?
                        -EAGAIN : -ERESTARTSYS);
                goto cleanup;
index 8755f5f3ad37c2218de60b96782c0863615a705e..0cb7ef59071b792a350a914e88f4e9be7da34efc 100644 (file)
@@ -124,7 +124,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
 {
        struct serport *serport = (struct serport*) tty->disc_data;
        unsigned long flags;
-       unsigned int ch_flags;
+       unsigned int ch_flags = 0;
        int i;
 
        spin_lock_irqsave(&serport->lock, flags);
@@ -133,18 +133,20 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
                goto out;
 
        for (i = 0; i < count; i++) {
-               switch (fp[i]) {
-               case TTY_FRAME:
-                       ch_flags = SERIO_FRAME;
-                       break;
-
-               case TTY_PARITY:
-                       ch_flags = SERIO_PARITY;
-                       break;
-
-               default:
-                       ch_flags = 0;
-                       break;
+               if (fp) {
+                       switch (fp[i]) {
+                       case TTY_FRAME:
+                               ch_flags = SERIO_FRAME;
+                               break;
+
+                       case TTY_PARITY:
+                               ch_flags = SERIO_PARITY;
+                               break;
+
+                       default:
+                               ch_flags = 0;
+                               break;
+                       }
                }
 
                serio_interrupt(serport->serio, cp[i], ch_flags);
index 1b8bdb7e9bf40a6549c5739e6d8a50a732bc9cd9..ff53314100f684ed9dcb86a9a89ea3f12b6a24e6 100644 (file)
@@ -596,13 +596,11 @@ static int parport_serial_pci_probe(struct pci_dev *dev,
 
        err = pci_enable_device (dev);
        if (err) {
-               pci_set_drvdata (dev, NULL);
                kfree (priv);
                return err;
        }
 
        if (parport_register (dev, id)) {
-               pci_set_drvdata (dev, NULL);
                kfree (priv);
                return -ENODEV;
        }
@@ -611,7 +609,6 @@ static int parport_serial_pci_probe(struct pci_dev *dev,
                int i;
                for (i = 0; i < priv->num_par; i++)
                        parport_pc_unregister_port (priv->port[i]);
-               pci_set_drvdata (dev, NULL);
                kfree (priv);
                return -ENODEV;
        }
@@ -624,8 +621,6 @@ static void parport_serial_pci_remove(struct pci_dev *dev)
        struct parport_serial_private *priv = pci_get_drvdata (dev);
        int i;
 
-       pci_set_drvdata(dev, NULL);
-
        // Serial ports
        if (priv->serial)
                pciserial_remove_ports(priv->serial);
index a0812d99136f5e171c277e88f637579cfea4c71c..9c7c9267d52cb3a62dd80452930ad33269bf2951 100644 (file)
@@ -9,3 +9,23 @@ config FIREWIRE_SERIAL
 
          To compile this driver as a module, say M here:  the module will
          be called firewire-serial.
+
+if FIREWIRE_SERIAL
+
+config FWTTY_MAX_TOTAL_PORTS
+       int "Maximum number of serial ports supported"
+       default "64"
+       help
+          Set this to the maximum number of serial ports you want the
+         firewire-serial driver to support.
+
+config FWTTY_MAX_CARD_PORTS
+       int "Maximum number of serial ports supported per adapter"
+       range 0 FWTTY_MAX_TOTAL_PORTS
+       default "32"
+       help
+          Set this to the maximum number of serial ports each firewire
+         adapter supports. The actual number of serial ports registered
+         is set with the module parameter "ttys".
+
+endif
index 62df009e5ac7c8e9bcd5779bf57e9b8c1d2c309d..8af136e9c9dc16e1ab5f5f5cecf7dfe1579c528b 100644 (file)
@@ -136,14 +136,14 @@ static struct fwtty_peer *__fwserial_peer_by_node_id(struct fw_card *card,
 
 #ifdef FWTTY_PROFILING
 
-static void profile_fifo_avail(struct fwtty_port *port, unsigned *stat)
+static void fwtty_profile_fifo(struct fwtty_port *port, unsigned *stat)
 {
        spin_lock_bh(&port->lock);
-       profile_size_distrib(stat, dma_fifo_avail(&port->tx_fifo));
+       fwtty_profile_data(stat, dma_fifo_avail(&port->tx_fifo));
        spin_unlock_bh(&port->lock);
 }
 
-static void dump_profile(struct seq_file *m, struct stats *stats)
+static void fwtty_dump_profile(struct seq_file *m, struct stats *stats)
 {
        /* for each stat, print sum of 0 to 2^k, then individually */
        int k = 4;
@@ -183,8 +183,8 @@ static void dump_profile(struct seq_file *m, struct stats *stats)
 }
 
 #else
-#define profile_fifo_avail(port, stat)
-#define dump_profile(m, stats)
+#define fwtty_profile_fifo(port, stat)
+#define fwtty_dump_profile(m, stats)
 #endif
 
 /*
@@ -456,16 +456,27 @@ static int fwtty_write_port_status(struct fwtty_port *port)
        return err;
 }
 
-static void __fwtty_throttle(struct fwtty_port *port, struct tty_struct *tty)
+static void fwtty_throttle_port(struct fwtty_port *port)
 {
+       struct tty_struct *tty;
        unsigned old;
 
+       tty = tty_port_tty_get(&port->port);
+       if (!tty)
+               return;
+
+       spin_lock_bh(&port->lock);
+
        old = port->mctrl;
        port->mctrl |= OOB_RX_THROTTLE;
        if (C_CRTSCTS(tty))
                port->mctrl &= ~TIOCM_RTS;
        if (~old & OOB_RX_THROTTLE)
                __fwtty_write_port_status(port);
+
+       spin_unlock_bh(&port->lock);
+
+       tty_kref_put(tty);
 }
 
 /**
@@ -532,80 +543,14 @@ static void fwtty_emit_breaks(struct work_struct *work)
        port->icount.brk += brk;
 }
 
-static void fwtty_pushrx(struct work_struct *work)
-{
-       struct fwtty_port *port = to_port(work, push);
-       struct tty_struct *tty;
-       struct buffered_rx *buf, *next;
-       int n, c = 0;
-
-       spin_lock_bh(&port->lock);
-       list_for_each_entry_safe(buf, next, &port->buf_list, list) {
-               n = tty_insert_flip_string_fixed_flag(&port->port, buf->data,
-                                                     TTY_NORMAL, buf->n);
-               c += n;
-               port->buffered -= n;
-               if (n < buf->n) {
-                       if (n > 0) {
-                               memmove(buf->data, buf->data + n, buf->n - n);
-                               buf->n -= n;
-                       }
-                       tty = tty_port_tty_get(&port->port);
-                       if (tty) {
-                               __fwtty_throttle(port, tty);
-                               tty_kref_put(tty);
-                       }
-                       break;
-               } else {
-                       list_del(&buf->list);
-                       kfree(buf);
-               }
-       }
-       if (c > 0)
-               tty_flip_buffer_push(&port->port);
-
-       if (list_empty(&port->buf_list))
-               clear_bit(BUFFERING_RX, &port->flags);
-       spin_unlock_bh(&port->lock);
-}
-
-static int fwtty_buffer_rx(struct fwtty_port *port, unsigned char *d, size_t n)
-{
-       struct buffered_rx *buf;
-       size_t size = (n + sizeof(struct buffered_rx) + 0xFF) & ~0xFF;
-
-       if (port->buffered + n > HIGH_WATERMARK) {
-               fwtty_err_ratelimited(port, "overflowed rx buffer: buffered: %d new: %zu wtrmk: %d\n",
-                                     port->buffered, n, HIGH_WATERMARK);
-               return 0;
-       }
-       buf = kmalloc(size, GFP_ATOMIC);
-       if (!buf)
-               return 0;
-       INIT_LIST_HEAD(&buf->list);
-       buf->n = n;
-       memcpy(buf->data, d, n);
-
-       spin_lock_bh(&port->lock);
-       list_add_tail(&buf->list, &port->buf_list);
-       port->buffered += n;
-       if (port->buffered > port->stats.watermark)
-               port->stats.watermark = port->buffered;
-       set_bit(BUFFERING_RX, &port->flags);
-       spin_unlock_bh(&port->lock);
-
-       return n;
-}
-
 static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
 {
-       struct tty_struct *tty;
        int c, n = len;
        unsigned lsr;
        int err = 0;
 
        fwtty_dbg(port, "%d\n", n);
-       profile_size_distrib(port->stats.reads, n);
+       fwtty_profile_data(port->stats.reads, n);
 
        if (port->write_only) {
                n = 0;
@@ -636,31 +581,24 @@ static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
                goto out;
        }
 
-       if (!test_bit(BUFFERING_RX, &port->flags)) {
-               c = tty_insert_flip_string_fixed_flag(&port->port, data,
-                               TTY_NORMAL, n);
-               if (c > 0)
-                       tty_flip_buffer_push(&port->port);
-               n -= c;
-
-               if (n) {
-                       /* start buffering and throttling */
-                       n -= fwtty_buffer_rx(port, &data[c], n);
-
-                       tty = tty_port_tty_get(&port->port);
-                       if (tty) {
-                               spin_lock_bh(&port->lock);
-                               __fwtty_throttle(port, tty);
-                               spin_unlock_bh(&port->lock);
-                               tty_kref_put(tty);
-                       }
-               }
-       } else
-               n -= fwtty_buffer_rx(port, data, n);
+       c = tty_insert_flip_string_fixed_flag(&port->port, data, TTY_NORMAL, n);
+       if (c > 0)
+               tty_flip_buffer_push(&port->port);
+       n -= c;
 
        if (n) {
                port->overrun = true;
                err = -EIO;
+               fwtty_err_ratelimited(port, "flip buffer overrun\n");
+
+       } else {
+               /* throttle the sender if remaining flip buffer space has
+                * reached high watermark to avoid losing data which may be
+                * in-flight. Since the AR request context is 32k, that much
+                * data may have _already_ been acked.
+                */
+               if (tty_buffer_space_avail(&port->port) < HIGH_WATERMARK)
+                       fwtty_throttle_port(port);
        }
 
 out:
@@ -821,7 +759,7 @@ static int fwtty_tx(struct fwtty_port *port, bool drain)
                        if (n == -EAGAIN)
                                ++port->stats.tx_stall;
                        else if (n == -ENODATA)
-                               profile_size_distrib(port->stats.txns, 0);
+                               fwtty_profile_data(port->stats.txns, 0);
                        else {
                                ++port->stats.fifo_errs;
                                fwtty_err_ratelimited(port, "fifo err: %d\n",
@@ -830,7 +768,7 @@ static int fwtty_tx(struct fwtty_port *port, bool drain)
                        break;
                }
 
-               profile_size_distrib(port->stats.txns, txn->dma_pended.len);
+               fwtty_profile_data(port->stats.txns, txn->dma_pended.len);
 
                fwtty_send_txn_async(peer, txn, TCODE_WRITE_BLOCK_REQUEST,
                                     peer->fifo_addr, txn->dma_pended.data,
@@ -1101,20 +1039,13 @@ static int fwtty_port_activate(struct tty_port *tty_port,
 static void fwtty_port_shutdown(struct tty_port *tty_port)
 {
        struct fwtty_port *port = to_port(tty_port, port);
-       struct buffered_rx *buf, *next;
 
        /* TODO: cancel outstanding transactions */
 
        cancel_delayed_work_sync(&port->emit_breaks);
        cancel_delayed_work_sync(&port->drain);
-       cancel_work_sync(&port->push);
 
        spin_lock_bh(&port->lock);
-       list_for_each_entry_safe(buf, next, &port->buf_list, list) {
-               list_del(&buf->list);
-               kfree(buf);
-       }
-       port->buffered = 0;
        port->flags = 0;
        port->break_ctl = 0;
        port->overrun = 0;
@@ -1184,7 +1115,7 @@ static int fwtty_write(struct tty_struct *tty, const unsigned char *buf, int c)
        int n, len;
 
        fwtty_dbg(port, "%d\n", c);
-       profile_size_distrib(port->stats.writes, c);
+       fwtty_profile_data(port->stats.writes, c);
 
        spin_lock_bh(&port->lock);
        n = dma_fifo_in(&port->tx_fifo, buf, c);
@@ -1262,9 +1193,7 @@ static void fwtty_unthrottle(struct tty_struct *tty)
 
        fwtty_dbg(port, "CRTSCTS: %d\n", (C_CRTSCTS(tty) != 0));
 
-       profile_fifo_avail(port, port->stats.unthrottle);
-
-       schedule_work(&port->push);
+       fwtty_profile_fifo(port, port->stats.unthrottle);
 
        spin_lock_bh(&port->lock);
        port->mctrl &= ~OOB_RX_THROTTLE;
@@ -1523,15 +1452,14 @@ static void fwtty_debugfs_show_port(struct seq_file *m, struct fwtty_port *port)
 
        seq_printf(m, " dr:%d st:%d err:%d lost:%d", stats.dropped,
                   stats.tx_stall, stats.fifo_errs, stats.lost);
-       seq_printf(m, " pkts:%d thr:%d wtrmk:%d", stats.sent, stats.throttled,
-                  stats.watermark);
+       seq_printf(m, " pkts:%d thr:%d", stats.sent, stats.throttled);
 
        if (port->port.console) {
                seq_puts(m, "\n    ");
                (*port->fwcon_ops->proc_show)(m, port->con_data);
        }
 
-       dump_profile(m, &port->stats);
+       fwtty_dump_profile(m, &port->stats);
 }
 
 static void fwtty_debugfs_show_peer(struct seq_file *m, struct fwtty_peer *peer)
@@ -2297,13 +2225,12 @@ static int fwserial_create(struct fw_unit *unit)
                port->index = FWTTY_INVALID_INDEX;
                port->port.ops = &fwtty_port_ops;
                port->serial = serial;
+               tty_buffer_set_limit(&port->port, 128 * 1024);
 
                spin_lock_init(&port->lock);
                INIT_DELAYED_WORK(&port->drain, fwtty_drain_tx);
                INIT_DELAYED_WORK(&port->emit_breaks, fwtty_emit_breaks);
                INIT_WORK(&port->hangup, fwtty_do_hangup);
-               INIT_WORK(&port->push, fwtty_pushrx);
-               INIT_LIST_HEAD(&port->buf_list);
                init_waitqueue_head(&port->wait_tx);
                port->max_payload = link_speed_to_max_payload(SCODE_100);
                dma_fifo_init(&port->tx_fifo);
index 24635014a2acdad232634248794e41eff2450ffa..54f7f9b9b2123a120a48595a878723b5d89d465e 100644 (file)
 #ifdef FWTTY_PROFILING
 #define DISTRIBUTION_MAX_SIZE     8192
 #define DISTRIBUTION_MAX_INDEX    (ilog2(DISTRIBUTION_MAX_SIZE) + 1)
-static inline void profile_size_distrib(unsigned stat[], unsigned val)
+static inline void fwtty_profile_data(unsigned stat[], unsigned val)
 {
        int n = (val) ? min(ilog2(val) + 1, DISTRIBUTION_MAX_INDEX) : 0;
        ++stat[n];
 }
 #else
 #define DISTRIBUTION_MAX_INDEX    0
-#define profile_size_distrib(st, n)
+#define fwtty_profile_data(st, n)
 #endif
 
 /* Parameters for both VIRT_CABLE_PLUG & VIRT_CABLE_PLUG_RSP mgmt codes */
@@ -166,7 +166,6 @@ struct stats {
        unsigned        sent;
        unsigned        lost;
        unsigned        throttled;
-       unsigned        watermark;
        unsigned        reads[DISTRIBUTION_MAX_INDEX + 1];
        unsigned        writes[DISTRIBUTION_MAX_INDEX + 1];
        unsigned        txns[DISTRIBUTION_MAX_INDEX + 1];
@@ -183,12 +182,6 @@ struct fwconsole_ops {
 #define FWCON_NOTIFY_ATTACH            1
 #define FWCON_NOTIFY_DETACH            2
 
-struct buffered_rx {
-       struct list_head        list;
-       size_t                  n;
-       unsigned char           data[0];
-};
-
 /**
  * fwtty_port: structure used to track/represent underlying tty_port
  * @port: underlying tty_port
@@ -223,11 +216,6 @@ struct buffered_rx {
  *         The work can race with the writer but concurrent sending is
  *         prevented with the IN_TX flag. Scheduled under lock to
  *         limit scheduling when fifo has just been drained.
- * @push: work responsible for pushing buffered rx to the ldisc.
- *       rx can become buffered if the tty buffer is filled before the
- *       ldisc throttles the sender.
- * @buf_list: list of buffered rx yet to be sent to ldisc
- * @buffered: byte count of buffered rx
  * @tx_fifo: fifo used to store & block-up writes for dma to remote
  * @max_payload: max bytes transmissable per dma (based on peer's max_payload)
  * @status_mask: UART_LSR_* bitmask significant to rx (based on termios)
@@ -267,9 +255,6 @@ struct fwtty_port {
        spinlock_t                 lock;
        unsigned                   mctrl;
        struct delayed_work        drain;
-       struct work_struct         push;
-       struct list_head           buf_list;
-       int                        buffered;
        struct dma_fifo            tx_fifo;
        int                        max_payload;
        unsigned                   status_mask;
@@ -291,7 +276,6 @@ struct fwtty_port {
 /* bit #s for flags field */
 #define IN_TX                      0
 #define STOP_TX                    1
-#define BUFFERING_RX              2
 
 /* bitmasks for special mctrl/mstatus bits */
 #define OOB_RX_THROTTLE   0x00010000
@@ -307,8 +291,8 @@ struct fwtty_port {
 #define FREQ_BREAKS        (HZ / 50)
 
 /* Ports are allocated in blocks of num_ports for each fw_card */
-#define MAX_CARD_PORTS           32    /* max # of ports per card */
-#define MAX_TOTAL_PORTS          64    /* max # of ports total    */
+#define MAX_CARD_PORTS           CONFIG_FWTTY_MAX_CARD_PORTS
+#define MAX_TOTAL_PORTS          CONFIG_FWTTY_MAX_TOTAL_PORTS
 
 /* tuning parameters */
 #define FWTTY_PORT_TXFIFO_LEN  4096
index 71630a2af42ccf5f2eb48ea79793cadca86ab5c6..979e7c3ea2cbc25e3cffbc0b50280414f97c09cf 100644 (file)
@@ -1248,6 +1248,8 @@ static int rs_ioctl(struct tty_struct *tty,
        struct async_icount cprev, cnow;        /* kernel counter temps */
        void __user *argp = (void __user *)arg;
        unsigned long flags;
+       DEFINE_WAIT(wait);
+       int ret;
 
        if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
                return -ENODEV;
@@ -1288,25 +1290,33 @@ static int rs_ioctl(struct tty_struct *tty,
                        cprev = info->icount;
                        local_irq_restore(flags);
                        while (1) {
-                               interruptible_sleep_on(&info->tport.delta_msr_wait);
-                               /* see if a signal did it */
-                               if (signal_pending(current))
-                                       return -ERESTARTSYS;
+                               prepare_to_wait(&info->tport.delta_msr_wait,
+                                               &wait, TASK_INTERRUPTIBLE);
                                local_irq_save(flags);
                                cnow = info->icount; /* atomic copy */
                                local_irq_restore(flags);
                                if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
-                                   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                                       return -EIO; /* no change => error */
+                                   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+                                       ret = -EIO; /* no change => error */
+                                       break;
+                               }
                                if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
                                     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
                                     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
                                     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
-                                       return 0;
+                                       ret = 0;
+                                       break;
+                               }
+                               schedule();
+                               /* see if a signal did it */
+                               if (signal_pending(current)) {
+                                       ret = -ERESTARTSYS;
+                                       break;
                                }
                                cprev = cnow;
                        }
-                       /* NOTREACHED */
+                       finish_wait(&info->tport.delta_msr_wait, &wait);
+                       return ret;
 
                case TIOCSERGWILD:
                case TIOCSERSWILD:
index 33f83fee9faec6be78206ebbc4aeee5ba1702fc8..a57bb5ab761cec2619c8ae065fce210d9b0451d0 100644 (file)
@@ -2709,6 +2709,8 @@ cy_ioctl(struct tty_struct *tty,
                break;
 #ifndef CONFIG_CYZ_INTR
        case CYZSETPOLLCYCLE:
+               if (arg > LONG_MAX / HZ)
+                       return -ENODEV;
                cyz_polling_cycle = (arg * HZ) / 1000;
                break;
        case CYZGETPOLLCYCLE:
index f17d2e4ee2caade2e6d821e9593a24deb1e3617c..75dc9d25f326dc4bfaaf42b635182082590668a2 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/console.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/tty.h>
index 9eba119bcdd3488d7d7541448a2371497c4d70f4..50b46881b6ca7bf648fe2f8b73b6782b8c1306cd 100644 (file)
@@ -788,7 +788,7 @@ static int hvc_tiocmset(struct tty_struct *tty,
 }
 
 #ifdef CONFIG_CONSOLE_POLL
-int hvc_poll_init(struct tty_driver *driver, int line, char *options)
+static int hvc_poll_init(struct tty_driver *driver, int line, char *options)
 {
        return 0;
 }
index 347050ea414a7f37e3962869f29437129cea1c75..7ae6c293e518a3be6d85013757880b1e3295250e 100644 (file)
@@ -1,5 +1,4 @@
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/console.h>
index 8fd72ff9436e12039abf43575d7cf17181132258..ebd5bff0f5c1668b70bdefead34bc60fca8a81ef 100644 (file)
@@ -15,7 +15,6 @@
  *   Copyright (C) 2007 David Sterba
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
index c0f76da553042db2f3eadb91cfb9ff08bc60e43d..f34461c5f14e102cbf64dba861e46a4a94820ecb 100644 (file)
@@ -194,6 +194,7 @@ struct gsm_control {
 struct gsm_mux {
        struct tty_struct *tty;         /* The tty our ldisc is bound to */
        spinlock_t lock;
+       struct mutex mutex;
        unsigned int num;
        struct kref ref;
 
@@ -1704,11 +1705,8 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
                gsm_destroy_network(dlci);
                mutex_unlock(&dlci->mutex);
 
-               /* tty_vhangup needs the tty_lock, so unlock and
-                  relock after doing the hangup. */
-               tty_unlock(tty);
                tty_vhangup(tty);
-               tty_lock(tty);
+
                tty_port_tty_set(&dlci->port, NULL);
                tty_kref_put(tty);
        }
@@ -2019,7 +2017,7 @@ static void gsm_error(struct gsm_mux *gsm,
  *     and then shut down each device hanging up the channels as we go.
  */
 
-void gsm_cleanup_mux(struct gsm_mux *gsm)
+static void gsm_cleanup_mux(struct gsm_mux *gsm)
 {
        int i;
        struct gsm_dlci *dlci = gsm->dlci[0];
@@ -2054,15 +2052,16 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
                                        dlci->state == DLCI_CLOSED);
        }
        /* Free up any link layer users */
+       mutex_lock(&gsm->mutex);
        for (i = 0; i < NUM_DLCI; i++)
                if (gsm->dlci[i])
                        gsm_dlci_release(gsm->dlci[i]);
+       mutex_unlock(&gsm->mutex);
        /* Now wipe the queues */
        list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
                kfree(txq);
        INIT_LIST_HEAD(&gsm->tx_list);
 }
-EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
 
 /**
  *     gsm_activate_mux        -       generic GSM setup
@@ -2073,7 +2072,7 @@ EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
  *     finally kick off connecting to DLCI 0 on the modem.
  */
 
-int gsm_activate_mux(struct gsm_mux *gsm)
+static int gsm_activate_mux(struct gsm_mux *gsm)
 {
        struct gsm_dlci *dlci;
        int i = 0;
@@ -2109,7 +2108,6 @@ int gsm_activate_mux(struct gsm_mux *gsm)
        gsm->dead = 0;          /* Tty opens are now permissible */
        return 0;
 }
-EXPORT_SYMBOL_GPL(gsm_activate_mux);
 
 /**
  *     gsm_free_mux            -       free up a mux
@@ -2117,13 +2115,12 @@ EXPORT_SYMBOL_GPL(gsm_activate_mux);
  *
  *     Dispose of allocated resources for a dead mux
  */
-void gsm_free_mux(struct gsm_mux *gsm)
+static void gsm_free_mux(struct gsm_mux *gsm)
 {
        kfree(gsm->txframe);
        kfree(gsm->buf);
        kfree(gsm);
 }
-EXPORT_SYMBOL_GPL(gsm_free_mux);
 
 /**
  *     gsm_free_muxr           -       free up a mux
@@ -2153,7 +2150,7 @@ static inline void mux_put(struct gsm_mux *gsm)
  *     Creates a new mux ready for activation.
  */
 
-struct gsm_mux *gsm_alloc_mux(void)
+static struct gsm_mux *gsm_alloc_mux(void)
 {
        struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
        if (gsm == NULL)
@@ -2170,6 +2167,7 @@ struct gsm_mux *gsm_alloc_mux(void)
                return NULL;
        }
        spin_lock_init(&gsm->lock);
+       mutex_init(&gsm->mutex);
        kref_init(&gsm->ref);
        INIT_LIST_HEAD(&gsm->tx_list);
 
@@ -2185,7 +2183,6 @@ struct gsm_mux *gsm_alloc_mux(void)
 
        return gsm;
 }
-EXPORT_SYMBOL_GPL(gsm_alloc_mux);
 
 /**
  *     gsmld_output            -       write to link
@@ -2269,14 +2266,15 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
        char *f;
        int i;
        char buf[64];
-       char flags;
+       char flags = TTY_NORMAL;
 
        if (debug & 4)
                print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET,
                                     cp, count);
 
        for (i = count, dp = cp, f = fp; i; i--, dp++) {
-               flags = *f++;
+               if (f)
+                       flags = *f++;
                switch (flags) {
                case TTY_NORMAL:
                        gsm->receive(gsm, *dp);
@@ -2711,7 +2709,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
        return;
 }
 
-int gsm_change_mtu(struct net_device *net, int new_mtu)
+static int gsm_change_mtu(struct net_device *net, int new_mtu)
 {
        struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
        if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu))
@@ -2909,23 +2907,33 @@ static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
        This is ok from a locking
        perspective as we don't have to worry about this
        if DLCI0 is lost */
-       if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
+       mutex_lock(&gsm->mutex);
+       if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) {
+               mutex_unlock(&gsm->mutex);
                return -EL2NSYNC;
+       }
        dlci = gsm->dlci[line];
        if (dlci == NULL) {
                alloc = true;
                dlci = gsm_dlci_alloc(gsm, line);
        }
-       if (dlci == NULL)
+       if (dlci == NULL) {
+               mutex_unlock(&gsm->mutex);
                return -ENOMEM;
+       }
        ret = tty_port_install(&dlci->port, driver, tty);
        if (ret) {
                if (alloc)
                        dlci_put(dlci);
+               mutex_unlock(&gsm->mutex);
                return ret;
        }
 
+       dlci_get(dlci);
+       dlci_get(gsm->dlci[0]);
+       mux_get(gsm);
        tty->driver_data = dlci;
+       mutex_unlock(&gsm->mutex);
 
        return 0;
 }
@@ -2936,9 +2944,6 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
        struct tty_port *port = &dlci->port;
 
        port->count++;
-       dlci_get(dlci);
-       dlci_get(dlci->gsm->dlci[0]);
-       mux_get(dlci->gsm);
        tty_port_tty_set(port, tty);
 
        dlci->modem_rx = 0;
@@ -2965,7 +2970,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
        mutex_unlock(&dlci->mutex);
        gsm = dlci->gsm;
        if (tty_port_close_start(&dlci->port, tty, filp) == 0)
-               goto out;
+               return;
        gsm_dlci_begin_close(dlci);
        if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {
                if (C_HUPCL(tty))
@@ -2973,10 +2978,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
        }
        tty_port_close_end(&dlci->port, tty);
        tty_port_tty_set(&dlci->port, NULL);
-out:
-       dlci_put(dlci);
-       dlci_put(gsm->dlci[0]);
-       mux_put(gsm);
+       return;
 }
 
 static void gsmtty_hangup(struct tty_struct *tty)
@@ -3153,6 +3155,16 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
        return gsmtty_modem_update(dlci, encode);
 }
 
+static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       struct gsm_mux *gsm = dlci->gsm;
+
+       dlci_put(dlci);
+       dlci_put(gsm->dlci[0]);
+       mux_put(gsm);
+       driver->ttys[tty->index] = NULL;
+}
 
 /* Virtual ttys for the demux */
 static const struct tty_operations gsmtty_ops = {
@@ -3172,6 +3184,7 @@ static const struct tty_operations gsmtty_ops = {
        .tiocmget               = gsmtty_tiocmget,
        .tiocmset               = gsmtty_tiocmset,
        .break_ctl              = gsmtty_break_ctl,
+       .remove                 = gsmtty_remove,
 };
 
 
index 1e6405070ce649e356b24d272a824e9eda737159..8b157d68a03e97aa2089d9b3c4d98fdb0b109719 100644 (file)
@@ -1244,7 +1244,7 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 {
        struct r3964_info *pInfo = tty->disc_data;
        const unsigned char *p;
-       char *f, flags = 0;
+       char *f, flags = TTY_NORMAL;
        int i;
 
        for (i = count, p = cp, f = fp; i; i--, p++) {
index 34aacaaae14ab9b595ea41744504c2cbc65b9ff3..cb8017aa443472f8b67d9ec4eab7403b268d2c0f 100644 (file)
@@ -105,6 +105,7 @@ struct n_tty_data {
 
        /* must hold exclusive termios_rwsem to reset these */
        unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
+       unsigned char push:1;
 
        /* shared by producer and consumer */
        char read_buf[N_TTY_BUF_SIZE];
@@ -275,7 +276,8 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
                        return;
                n_tty_set_room(tty);
                n_tty_write_wakeup(tty->link);
-               wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
+               if (waitqueue_active(&tty->link->write_wait))
+                       wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
                return;
        }
 
@@ -342,6 +344,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
 
        ldata->erasing = 0;
        bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
+       ldata->push = 0;
 }
 
 static void n_tty_packet_mode_flush(struct tty_struct *tty)
@@ -351,7 +354,8 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
        spin_lock_irqsave(&tty->ctrl_lock, flags);
        if (tty->link->packet) {
                tty->ctrl_status |= TIOCPKT_FLUSHREAD;
-               wake_up_interruptible(&tty->link->read_wait);
+               if (waitqueue_active(&tty->link->read_wait))
+                       wake_up_interruptible(&tty->link->read_wait);
        }
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 }
@@ -1162,7 +1166,8 @@ static void n_tty_receive_break(struct tty_struct *tty)
                put_tty_queue('\0', ldata);
        }
        put_tty_queue('\0', ldata);
-       wake_up_interruptible(&tty->read_wait);
+       if (waitqueue_active(&tty->read_wait))
+               wake_up_interruptible(&tty->read_wait);
 }
 
 /**
@@ -1220,7 +1225,8 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
                put_tty_queue('\0', ldata);
        else
                put_tty_queue(c, ldata);
-       wake_up_interruptible(&tty->read_wait);
+       if (waitqueue_active(&tty->read_wait))
+               wake_up_interruptible(&tty->read_wait);
 }
 
 static void
@@ -1264,7 +1270,6 @@ static int
 n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
 {
        struct n_tty_data *ldata = tty->disc_data;
-       int parmrk;
 
        if (I_IXON(tty)) {
                if (c == START_CHAR(tty)) {
@@ -1349,8 +1354,6 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
                }
                if ((c == EOL_CHAR(tty)) ||
                    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
-                       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
-                                ? 1 : 0;
                        /*
                         * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
                         */
@@ -1365,7 +1368,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
                         * XXX does PARMRK doubling happen for
                         * EOL_CHAR and EOL2_CHAR?
                         */
-                       if (parmrk)
+                       if (c == (unsigned char) '\377' && I_PARMRK(tty))
                                put_tty_queue(c, ldata);
 
 handle_newline:
@@ -1379,7 +1382,6 @@ handle_newline:
                }
        }
 
-       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
        if (L_ECHO(tty)) {
                finish_erasing(ldata);
                if (c == '\n')
@@ -1393,7 +1395,8 @@ handle_newline:
                commit_echoes(tty);
        }
 
-       if (parmrk)
+       /* PARMRK doubling check */
+       if (c == (unsigned char) '\377' && I_PARMRK(tty))
                put_tty_queue(c, ldata);
 
        put_tty_queue(c, ldata);
@@ -1404,7 +1407,6 @@ static inline void
 n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
 {
        struct n_tty_data *ldata = tty->disc_data;
-       int parmrk;
 
        if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
                start_tty(tty);
@@ -1418,13 +1420,13 @@ n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
                echo_char(c, tty);
                commit_echoes(tty);
        }
-       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-       if (parmrk)
+       /* PARMRK doubling check */
+       if (c == (unsigned char) '\377' && I_PARMRK(tty))
                put_tty_queue(c, ldata);
        put_tty_queue(c, ldata);
 }
 
-static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
+static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
 {
        n_tty_receive_char_inline(tty, c);
 }
@@ -1449,8 +1451,7 @@ n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
        put_tty_queue(c, ldata);
 }
 
-static inline void
-n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
+static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
 {
        if (I_ISTRIP(tty))
                c &= 0x7f;
@@ -1681,32 +1682,9 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
        }
 }
 
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
-{
-       int room, n;
-
-       down_read(&tty->termios_rwsem);
-
-       while (1) {
-               room = receive_room(tty);
-               n = min(count, room);
-               if (!n)
-                       break;
-               __receive_buf(tty, cp, fp, n);
-               cp += n;
-               if (fp)
-                       fp += n;
-               count -= n;
-       }
-
-       tty->receive_room = room;
-       n_tty_check_throttle(tty);
-       up_read(&tty->termios_rwsem);
-}
-
-static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
+static int
+n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
+                        char *fp, int count, int flow)
 {
        struct n_tty_data *ldata = tty->disc_data;
        int room, n, rcvd = 0;
@@ -1717,7 +1695,7 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
                room = receive_room(tty);
                n = min(count, room);
                if (!n) {
-                       if (!room)
+                       if (flow && !room)
                                ldata->no_room = 1;
                        break;
                }
@@ -1736,6 +1714,18 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
        return rcvd;
 }
 
+static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
+{
+       n_tty_receive_buf_common(tty, cp, fp, count, 0);
+}
+
+static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
+{
+       return n_tty_receive_buf_common(tty, cp, fp, count, 1);
+}
+
 int is_ignored(int sig)
 {
        return (sigismember(&current->blocked, sig) ||
@@ -1762,7 +1752,16 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
 
        if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) {
                bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
-               ldata->line_start = ldata->canon_head = ldata->read_tail;
+               ldata->line_start = ldata->read_tail;
+               if (!L_ICANON(tty) || !read_cnt(ldata)) {
+                       ldata->canon_head = ldata->read_tail;
+                       ldata->push = 0;
+               } else {
+                       set_bit((ldata->read_head - 1) & (N_TTY_BUF_SIZE - 1),
+                               ldata->read_flags);
+                       ldata->canon_head = ldata->read_head;
+                       ldata->push = 1;
+               }
                ldata->erasing = 0;
                ldata->lnext = 0;
        }
@@ -1825,8 +1824,10 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
                start_tty(tty);
 
        /* The termios change make the tty ready for I/O */
-       wake_up_interruptible(&tty->write_wait);
-       wake_up_interruptible(&tty->read_wait);
+       if (waitqueue_active(&tty->write_wait))
+               wake_up_interruptible(&tty->write_wait);
+       if (waitqueue_active(&tty->read_wait))
+               wake_up_interruptible(&tty->read_wait);
 }
 
 /**
@@ -1892,14 +1893,15 @@ err:
        return -ENOMEM;
 }
 
-static inline int input_available_p(struct tty_struct *tty, int amt)
+static inline int input_available_p(struct tty_struct *tty, int poll)
 {
        struct n_tty_data *ldata = tty->disc_data;
+       int amt = poll && !TIME_CHAR(tty) ? MIN_CHAR(tty) : 1;
 
        if (ldata->icanon && !L_EXTPROC(tty)) {
                if (ldata->canon_head != ldata->read_tail)
                        return 1;
-       } else if (read_cnt(ldata) >= (amt ? amt : 1))
+       } else if (read_cnt(ldata) >= amt)
                return 1;
 
        return 0;
@@ -1965,6 +1967,12 @@ static int copy_from_read_buf(struct tty_struct *tty,
  *     it copies one line of input up to and including the line-delimiting
  *     character into the user-space buffer.
  *
+ *     NB: When termios is changed from non-canonical to canonical mode and
+ *     the read buffer contains data, n_tty_set_termios() simulates an EOF
+ *     push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer.
+ *     This causes data already processed as input to be immediately available
+ *     as input although a newline has not been received.
+ *
  *     Called under the atomic_read_lock mutex
  *
  *     n_tty_read()/consumer path:
@@ -2011,7 +2019,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
        n += found;
        c = n;
 
-       if (found && read_buf(ldata, eol) == __DISABLED_CHAR) {
+       if (found && !ldata->push && read_buf(ldata, eol) == __DISABLED_CHAR) {
                n--;
                eof_push = !n && ldata->read_tail != ldata->line_start;
        }
@@ -2038,7 +2046,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
        ldata->read_tail += c;
 
        if (found) {
-               ldata->line_start = ldata->read_tail;
+               if (!ldata->push)
+                       ldata->line_start = ldata->read_tail;
+               else
+                       ldata->push = 0;
                tty_audit_push(tty);
        }
        return eof_push ? -EAGAIN : 0;
@@ -2398,7 +2409,7 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
 
        poll_wait(file, &tty->read_wait, wait);
        poll_wait(file, &tty->write_wait, wait);
-       if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
+       if (input_available_p(tty, 1))
                mask |= POLLIN | POLLRDNORM;
        if (tty->packet && tty->link->ctrl_status)
                mask |= POLLPRI | POLLIN | POLLRDNORM;
index 354564ea47c504446ba5aeab1153d48edc4acc48..383c4c796637713e12bede50677803a0d639a855 100644 (file)
@@ -1744,7 +1744,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
 
 #ifdef CONFIG_PCI
 
-static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = {
+static const struct pci_device_id rocket_pci_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4QUAD) },
        { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA) },
        { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8OCTA) },
index e33d38cb170f97e4055a0a17eb0f4e7bc0b45d0e..61ecd709a7229aa7d7d6fcc91326a8eda0861fa8 100644 (file)
@@ -2670,6 +2670,10 @@ static void serial8250_config_port(struct uart_port *port, int flags)
        if (port->type == PORT_16550A && port->iotype == UPIO_AU)
                up->bugs |= UART_BUG_NOMSR;
 
+       /* HW bugs may trigger IRQ while IIR == NO_INT */
+       if (port->type == PORT_TEGRA)
+               up->bugs |= UART_BUG_NOMSR;
+
        if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
                autoconfig_irq(up);
 
index 06525f10e3641bc2140b140a50d8b994acd662d3..faa64e6461002136069e53619ad78c7534a7261d 100644 (file)
@@ -14,7 +14,6 @@
  * 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>
@@ -274,7 +273,6 @@ static int dw8250_probe_of(struct uart_port *p,
        return 0;
 }
 
-#ifdef CONFIG_ACPI
 static int dw8250_probe_acpi(struct uart_8250_port *up,
                             struct dw8250_data *data)
 {
@@ -302,13 +300,6 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
 
        return 0;
 }
-#else
-static inline int dw8250_probe_acpi(struct uart_8250_port *up,
-                                   struct dw8250_data *data)
-{
-       return -ENODEV;
-}
-#endif /* CONFIG_ACPI */
 
 static int dw8250_probe(struct platform_device *pdev)
 {
index d1a9078003bd35caa7f6ee0f8a2f6d256751686c..56c87232b6a0eadac0d02e6eb7a10997b4abd1c5 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <linux/device.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/serial_8250.h>
index 4697a514b80a6d2cafcd6a2800d8cdc820c6594f..50228eed3b6fa502a3a7bb93d14f9280f1f4e713 100644 (file)
@@ -11,7 +11,6 @@
  */
 #undef DEBUG
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -1259,10 +1258,10 @@ static int pci_quatech_init(struct pci_dev *dev)
                unsigned long base = pci_resource_start(dev, 0);
                if (base) {
                        u32 tmp;
-                       outl(inl(base + 0x38), base + 0x38);
+                       outl(inl(base + 0x38) | 0x00002000, base + 0x38);
                        tmp = inl(base + 0x3c);
                        outl(tmp | 0x01000000, base + 0x3c);
-                       outl(tmp, base + 0x3c);
+                       outl(tmp &= ~0x01000000, base + 0x3c);
                }
        }
        return 0;
@@ -1744,6 +1743,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
 #define PCI_DEVICE_ID_TITAN_800E       0xA014
 #define PCI_DEVICE_ID_TITAN_200EI      0xA016
 #define PCI_DEVICE_ID_TITAN_200EISI    0xA017
+#define PCI_DEVICE_ID_TITAN_200V3      0xA306
 #define PCI_DEVICE_ID_TITAN_400V3      0xA310
 #define PCI_DEVICE_ID_TITAN_410V3      0xA312
 #define PCI_DEVICE_ID_TITAN_800V3      0xA314
@@ -4427,6 +4427,9 @@ static struct pci_device_id serial_pci_tbl[] = {
        {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_oxsemi_2_4000000 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_bt_2_921600 },
        {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_b0_4_921600 },
index 35d9ab95c5cbb51d6092f67540678f00e4ee52bd..682a2fbe5c065be61c350088c86f16ba5a89ceff 100644 (file)
@@ -12,7 +12,6 @@
  * the Free Software Foundation; either version 2 of the License.
  */
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/pnp.h>
 #include <linux/string.h>
index 1b74b88e1e1e4ac5caab90aed58fc1a4d9cfd1d4..4d180c9423effe3994f2226bbfc7325829cf2156 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/string.h>
index a3817ab8602fe050e5cf2bf90a79102e73a49dbb..441ada489874e33c62096e3dd17295b6d2975ce5 100644 (file)
@@ -181,9 +181,8 @@ config SERIAL_KS8695_CONSOLE
 
 config SERIAL_CLPS711X
        tristate "CLPS711X serial port support"
-       depends on ARCH_CLPS711X
+       depends on ARCH_CLPS711X || COMPILE_TEST
        select SERIAL_CORE
-       default y
        help
          This enables the driver for the on-chip UARTs of the Cirrus
          Logic EP711x/EP721x/EP731x processors.
@@ -1146,31 +1145,13 @@ config SERIAL_QE
          This driver supports the QE serial ports on Freescale embedded
          PowerPC that contain a QUICC Engine.
 
-config SERIAL_SC26XX
-       tristate "SC2681/SC2692 serial port support"
-       depends on SNI_RM
-       select SERIAL_CORE
-       help
-         This is a driver for the onboard serial ports of
-         older RM400 machines.
-
-config SERIAL_SC26XX_CONSOLE
-       bool "Console on SC2681/SC2692 serial port"
-       depends on SERIAL_SC26XX=y
-       select SERIAL_CORE_CONSOLE
-       help
-         Support for Console on SC2681/SC2692 serial ports.
-
 config SERIAL_SCCNXP
        tristate "SCCNXP serial port support"
-       depends on !SERIAL_SC26XX
        select SERIAL_CORE
-       default n
        help
          This selects support for an advanced UART from NXP (Philips).
          Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92,
          SC28L202, SCC68681 and SCC68692.
-         Positioned as a replacement for the driver SC26XX.
 
 config SERIAL_SCCNXP_CONSOLE
        bool "Console on SCCNXP serial port"
index 3068c77220877e53f30773e3b550c44ad0ff6bdc..3680854fef41008e576a61db15f8d3114ac9228e 100644 (file)
@@ -47,7 +47,6 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
 obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
 obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
 obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
-obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
 obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
 obj-$(CONFIG_SERIAL_JSM) += jsm/
 obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
index 33bd8606be6272d93f82e8aa6279cc00f6da87f0..01c9e72433e192bc85423d4235ec8704c9409990 100644 (file)
@@ -756,9 +756,10 @@ static int pl010_remove(struct amba_device *dev)
        return 0;
 }
 
-static int pl010_suspend(struct amba_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int pl010_suspend(struct device *dev)
 {
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       struct uart_amba_port *uap = dev_get_drvdata(dev);
 
        if (uap)
                uart_suspend_port(&amba_reg, &uap->port);
@@ -766,15 +767,18 @@ static int pl010_suspend(struct amba_device *dev, pm_message_t state)
        return 0;
 }
 
-static int pl010_resume(struct amba_device *dev)
+static int pl010_resume(struct device *dev)
 {
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       struct uart_amba_port *uap = dev_get_drvdata(dev);
 
        if (uap)
                uart_resume_port(&amba_reg, &uap->port);
 
        return 0;
 }
+#endif
+
+static SIMPLE_DEV_PM_OPS(pl010_dev_pm_ops, pl010_suspend, pl010_resume);
 
 static struct amba_id pl010_ids[] = {
        {
@@ -789,12 +793,11 @@ MODULE_DEVICE_TABLE(amba, pl010_ids);
 static struct amba_driver pl010_driver = {
        .drv = {
                .name   = "uart-pl010",
+               .pm     = &pl010_dev_pm_ops,
        },
        .id_table       = pl010_ids,
        .probe          = pl010_probe,
        .remove         = pl010_remove,
-       .suspend        = pl010_suspend,
-       .resume         = pl010_resume,
 };
 
 static int __init pl010_init(void)
index 7203864992a523509ee0f0f42f47c36714a886aa..d58783d364e3a9443a7c2723e635467e54b014cd 100644 (file)
@@ -112,8 +112,6 @@ static struct vendor_data vendor_st = {
        .get_fifosize           = get_fifosize_st,
 };
 
-static struct uart_amba_port *amba_ports[UART_NR];
-
 /* Deals with DMA transactions */
 
 struct pl011_sgbuf {
@@ -969,6 +967,8 @@ static void pl011_dma_rx_poll(unsigned long args)
 
                spin_lock_irqsave(&uap->port.lock, flags);
                pl011_dma_rx_stop(uap);
+               uap->im |= UART011_RXIM;
+               writew(uap->im, uap->port.membase + UART011_IMSC);
                spin_unlock_irqrestore(&uap->port.lock, flags);
 
                uap->dmarx.running = false;
@@ -1216,8 +1216,8 @@ __acquires(&uap->port.lock)
                        dev_dbg(uap->port.dev, "could not trigger RX DMA job "
                                "fall back to interrupt mode again\n");
                        uap->im |= UART011_RXIM;
+                       writew(uap->im, uap->port.membase + UART011_IMSC);
                } else {
-                       uap->im &= ~UART011_RXIM;
 #ifdef CONFIG_DMA_ENGINE
                        /* Start Rx DMA poll */
                        if (uap->dmarx.poll_rate) {
@@ -1229,8 +1229,6 @@ __acquires(&uap->port.lock)
                        }
 #endif
                }
-
-               writew(uap->im, uap->port.membase + UART011_IMSC);
        }
        spin_lock(&uap->port.lock);
 }
@@ -1513,10 +1511,25 @@ static int pl011_hwinit(struct uart_port *port)
        return retval;
 }
 
+static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
+{
+       writew(lcr_h, uap->port.membase + uap->lcrh_rx);
+       if (uap->lcrh_rx != uap->lcrh_tx) {
+               int i;
+               /*
+                * Wait 10 PCLKs before writing LCRH_TX register,
+                * to get this delay write read only register 10 times
+                */
+               for (i = 0; i < 10; ++i)
+                       writew(0xff, uap->port.membase + UART011_MIS);
+               writew(lcr_h, uap->port.membase + uap->lcrh_tx);
+       }
+}
+
 static int pl011_startup(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
-       unsigned int cr;
+       unsigned int cr, lcr_h, fbrd, ibrd;
        int retval;
 
        retval = pl011_hwinit(port);
@@ -1535,32 +1548,36 @@ static int pl011_startup(struct uart_port *port)
        writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
 
        /*
-        * Provoke TX FIFO interrupt into asserting.
+        * Provoke TX FIFO interrupt into asserting. Taking care to preserve
+        * baud rate and data format specified by FBRD, IBRD and LCRH as the
+        * UART may already be in use as a console.
         */
+       spin_lock_irq(&uap->port.lock);
+
+       fbrd = readw(uap->port.membase + UART011_FBRD);
+       ibrd = readw(uap->port.membase + UART011_IBRD);
+       lcr_h = readw(uap->port.membase + uap->lcrh_rx);
+
        cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
        writew(cr, uap->port.membase + UART011_CR);
        writew(0, uap->port.membase + UART011_FBRD);
        writew(1, uap->port.membase + UART011_IBRD);
-       writew(0, uap->port.membase + uap->lcrh_rx);
-       if (uap->lcrh_tx != uap->lcrh_rx) {
-               int i;
-               /*
-                * Wait 10 PCLKs before writing LCRH_TX register,
-                * to get this delay write read only register 10 times
-                */
-               for (i = 0; i < 10; ++i)
-                       writew(0xff, uap->port.membase + UART011_MIS);
-               writew(0, uap->port.membase + uap->lcrh_tx);
-       }
+       pl011_write_lcr_h(uap, 0);
        writew(0, uap->port.membase + UART01x_DR);
        while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
                barrier();
 
+       writew(fbrd, uap->port.membase + UART011_FBRD);
+       writew(ibrd, uap->port.membase + UART011_IBRD);
+       pl011_write_lcr_h(uap, lcr_h);
+
        /* restore RTS and DTR */
        cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
        cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
        writew(cr, uap->port.membase + UART011_CR);
 
+       spin_unlock_irq(&uap->port.lock);
+
        /*
         * initialise the old status of the modem signals
         */
@@ -1629,11 +1646,13 @@ static void pl011_shutdown(struct uart_port *port)
         * it during startup().
         */
        uap->autorts = false;
+       spin_lock_irq(&uap->port.lock);
        cr = readw(uap->port.membase + UART011_CR);
        uap->old_cr = cr;
        cr &= UART011_CR_RTS | UART011_CR_DTR;
        cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
        writew(cr, uap->port.membase + UART011_CR);
+       spin_unlock_irq(&uap->port.lock);
 
        /*
         * disable break condition and fifos
@@ -1797,17 +1816,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
         * UART011_FBRD & UART011_IBRD.
         * ----------^----------^----------^----------^-----
         */
-       writew(lcr_h, port->membase + uap->lcrh_rx);
-       if (uap->lcrh_rx != uap->lcrh_tx) {
-               int i;
-               /*
-                * Wait 10 PCLKs before writing LCRH_TX register,
-                * to get this delay write read only register 10 times
-                */
-               for (i = 0; i < 10; ++i)
-                       writew(0xff, uap->port.membase + UART011_MIS);
-               writew(lcr_h, port->membase + uap->lcrh_tx);
-       }
+       pl011_write_lcr_h(uap, lcr_h);
        writew(old_cr, port->membase + UART011_CR);
 
        spin_unlock_irqrestore(&port->lock, flags);
@@ -2169,10 +2178,10 @@ static int pl011_remove(struct amba_device *dev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int pl011_suspend(struct amba_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int pl011_suspend(struct device *dev)
 {
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       struct uart_amba_port *uap = dev_get_drvdata(dev);
 
        if (!uap)
                return -EINVAL;
@@ -2180,9 +2189,9 @@ static int pl011_suspend(struct amba_device *dev, pm_message_t state)
        return uart_suspend_port(&amba_reg, &uap->port);
 }
 
-static int pl011_resume(struct amba_device *dev)
+static int pl011_resume(struct device *dev)
 {
-       struct uart_amba_port *uap = amba_get_drvdata(dev);
+       struct uart_amba_port *uap = dev_get_drvdata(dev);
 
        if (!uap)
                return -EINVAL;
@@ -2191,6 +2200,8 @@ static int pl011_resume(struct amba_device *dev)
 }
 #endif
 
+static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
+
 static struct amba_id pl011_ids[] = {
        {
                .id     = 0x00041011,
@@ -2210,14 +2221,11 @@ MODULE_DEVICE_TABLE(amba, pl011_ids);
 static struct amba_driver pl011_driver = {
        .drv = {
                .name   = "uart-pl011",
+               .pm     = &pl011_dev_pm_ops,
        },
        .id_table       = pl011_ids,
        .probe          = pl011_probe,
        .remove         = pl011_remove,
-#ifdef CONFIG_PM
-       .suspend        = pl011_suspend,
-       .resume         = pl011_resume,
-#endif
 };
 
 static int __init pl011_init(void)
index c7d99af46a966f1fdc9b9ebf0359756180e90b20..a49f10d269b20afb2e8d2a1579af8f8987ed2a16 100644 (file)
@@ -825,9 +825,6 @@ static void atmel_release_rx_dma(struct uart_port *port)
        atmel_port->desc_rx = NULL;
        atmel_port->chan_rx = NULL;
        atmel_port->cookie_rx = -EINVAL;
-
-       if (!atmel_port->is_usart)
-               del_timer_sync(&atmel_port->uart_timer);
 }
 
 static void atmel_rx_from_dma(struct uart_port *port)
@@ -1229,9 +1226,6 @@ static void atmel_release_rx_pdc(struct uart_port *port)
                                 DMA_FROM_DEVICE);
                kfree(pdc->buf);
        }
-
-       if (!atmel_port->is_usart)
-               del_timer_sync(&atmel_port->uart_timer);
 }
 
 static void atmel_rx_from_pdc(struct uart_port *port)
@@ -1604,12 +1598,13 @@ static int atmel_startup(struct uart_port *port)
        /* enable xmit & rcvr */
        UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
 
+       setup_timer(&atmel_port->uart_timer,
+                       atmel_uart_timer_callback,
+                       (unsigned long)port);
+
        if (atmel_use_pdc_rx(port)) {
                /* set UART timeout */
                if (!atmel_port->is_usart) {
-                       setup_timer(&atmel_port->uart_timer,
-                                       atmel_uart_timer_callback,
-                                       (unsigned long)port);
                        mod_timer(&atmel_port->uart_timer,
                                        jiffies + uart_poll_timeout(port));
                /* set USART timeout */
@@ -1624,9 +1619,6 @@ static int atmel_startup(struct uart_port *port)
        } else if (atmel_use_dma_rx(port)) {
                /* set UART timeout */
                if (!atmel_port->is_usart) {
-                       setup_timer(&atmel_port->uart_timer,
-                                       atmel_uart_timer_callback,
-                                       (unsigned long)port);
                        mod_timer(&atmel_port->uart_timer,
                                        jiffies + uart_poll_timeout(port));
                /* set USART timeout */
@@ -1650,12 +1642,30 @@ static int atmel_startup(struct uart_port *port)
 static void atmel_shutdown(struct uart_port *port)
 {
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
        /*
-        * Ensure everything is stopped.
+        * Prevent any tasklets being scheduled during
+        * cleanup
+        */
+       del_timer_sync(&atmel_port->uart_timer);
+
+       /*
+        * Clear out any scheduled tasklets before
+        * we destroy the buffers
+        */
+       tasklet_kill(&atmel_port->tasklet);
+
+       /*
+        * Ensure everything is stopped and
+        * disable all interrupts, port and break condition.
         */
        atmel_stop_rx(port);
        atmel_stop_tx(port);
 
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+       UART_PUT_IDR(port, -1);
+
+
        /*
         * Shut-down the DMA.
         */
@@ -1665,10 +1675,10 @@ static void atmel_shutdown(struct uart_port *port)
                atmel_port->release_tx(port);
 
        /*
-        * Disable all interrupts, port and break condition.
+        * Reset ring buffer pointers
         */
-       UART_PUT_CR(port, ATMEL_US_RSTSTA);
-       UART_PUT_IDR(port, -1);
+       atmel_port->rx_ring.head = 0;
+       atmel_port->rx_ring.tail = 0;
 
        /*
         * Free the interrupt
@@ -2441,11 +2451,12 @@ static int atmel_serial_remove(struct platform_device *pdev)
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
        int ret = 0;
 
+       tasklet_kill(&atmel_port->tasklet);
+
        device_init_wakeup(&pdev->dev, 0);
 
        ret = uart_remove_one_port(&atmel_uart, port);
 
-       tasklet_kill(&atmel_port->tasklet);
        kfree(atmel_port->rx_ring.buf);
 
        /* "port" is allocated statically, so we shouldn't free it */
index 8d0b994357c856319b2ffae055d1e605a7a40706..b0eacb83f831ec5f3e526ea31b4a93dfa75f8ecf 100644 (file)
 #include <linux/console.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
-#include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/ioport.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 
-#include <mach/hardware.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/clps711x.h>
 
-#define UART_CLPS711X_NAME     "uart-clps711x"
+#define UART_CLPS711X_DEVNAME  "ttyCL"
 #define UART_CLPS711X_NR       2
 #define UART_CLPS711X_MAJOR    204
 #define UART_CLPS711X_MINOR    40
 
-#define UBRLCR(port)           ((port)->line ? UBRLCR2 : UBRLCR1)
-#define UARTDR(port)           ((port)->line ? UARTDR2 : UARTDR1)
-#define SYSFLG(port)           ((port)->line ? SYSFLG2 : SYSFLG1)
-#define SYSCON(port)           ((port)->line ? SYSCON2 : SYSCON1)
-#define TX_IRQ(port)           ((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1)
-#define RX_IRQ(port)           ((port)->line ? IRQ_URXINT2 : IRQ_URXINT1)
+#define UARTDR_OFFSET          (0x00)
+#define UBRLCR_OFFSET          (0x40)
+
+#define UARTDR_FRMERR          (1 << 8)
+#define UARTDR_PARERR          (1 << 9)
+#define UARTDR_OVERR           (1 << 10)
+
+#define UBRLCR_BAUD_MASK       ((1 << 12) - 1)
+#define UBRLCR_BREAK           (1 << 12)
+#define UBRLCR_PRTEN           (1 << 13)
+#define UBRLCR_EVENPRT         (1 << 14)
+#define UBRLCR_XSTOP           (1 << 15)
+#define UBRLCR_FIFOEN          (1 << 16)
+#define UBRLCR_WRDLEN5         (0 << 17)
+#define UBRLCR_WRDLEN6         (1 << 17)
+#define UBRLCR_WRDLEN7         (2 << 17)
+#define UBRLCR_WRDLEN8         (3 << 17)
+#define UBRLCR_WRDLEN_MASK     (3 << 17)
 
 struct clps711x_port {
-       struct uart_driver      uart;
-       struct clk              *uart_clk;
-       struct uart_port        port[UART_CLPS711X_NR];
-       int                     tx_enabled[UART_CLPS711X_NR];
-#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
-       struct console          console;
-#endif
+       struct uart_port        port;
+       unsigned int            tx_enabled;
+       int                     rx_irq;
+       struct regmap           *syscon;
+       bool                    use_ms;
+};
+
+static struct uart_driver clps711x_uart = {
+       .owner          = THIS_MODULE,
+       .driver_name    = UART_CLPS711X_DEVNAME,
+       .dev_name       = UART_CLPS711X_DEVNAME,
+       .major          = UART_CLPS711X_MAJOR,
+       .minor          = UART_CLPS711X_MINOR,
+       .nr             = UART_CLPS711X_NR,
 };
 
 static void uart_clps711x_stop_tx(struct uart_port *port)
 {
        struct clps711x_port *s = dev_get_drvdata(port->dev);
 
-       if (s->tx_enabled[port->line]) {
-               disable_irq(TX_IRQ(port));
-               s->tx_enabled[port->line] = 0;
+       if (s->tx_enabled) {
+               disable_irq(port->irq);
+               s->tx_enabled = 0;
        }
 }
 
@@ -66,33 +88,27 @@ static void uart_clps711x_start_tx(struct uart_port *port)
 {
        struct clps711x_port *s = dev_get_drvdata(port->dev);
 
-       if (!s->tx_enabled[port->line]) {
-               enable_irq(TX_IRQ(port));
-               s->tx_enabled[port->line] = 1;
+       if (!s->tx_enabled) {
+               s->tx_enabled = 1;
+               enable_irq(port->irq);
        }
 }
 
-static void uart_clps711x_stop_rx(struct uart_port *port)
-{
-       disable_irq(RX_IRQ(port));
-}
-
-static void uart_clps711x_enable_ms(struct uart_port *port)
-{
-       /* Do nothing */
-}
-
 static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)
 {
        struct uart_port *port = dev_id;
-       unsigned int status, ch, flg;
+       struct clps711x_port *s = dev_get_drvdata(port->dev);
+       unsigned int status, flg;
+       u16 ch;
 
        for (;;) {
-               status = clps_readl(SYSFLG(port));
-               if (status & SYSFLG_URXFE)
+               u32 sysflg = 0;
+
+               regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
+               if (sysflg & SYSFLG_URXFE)
                        break;
 
-               ch = clps_readw(UARTDR(port));
+               ch = readw(port->membase + UARTDR_OFFSET);
                status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR);
                ch &= 0xff;
 
@@ -138,23 +154,29 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
        struct circ_buf *xmit = &port->state->xmit;
 
        if (port->x_char) {
-               clps_writew(port->x_char, UARTDR(port));
+               writew(port->x_char, port->membase + UARTDR_OFFSET);
                port->icount.tx++;
                port->x_char = 0;
                return IRQ_HANDLED;
        }
 
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               disable_irq_nosync(TX_IRQ(port));
-               s->tx_enabled[port->line] = 0;
+               if (s->tx_enabled) {
+                       disable_irq_nosync(port->irq);
+                       s->tx_enabled = 0;
+               }
                return IRQ_HANDLED;
        }
 
        while (!uart_circ_empty(xmit)) {
-               clps_writew(xmit->buf[xmit->tail], UARTDR(port));
+               u32 sysflg = 0;
+
+               writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET);
                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                port->icount.tx++;
-               if (clps_readl(SYSFLG(port) & SYSFLG_UTXFF))
+
+               regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
+               if (sysflg & SYSFLG_UTXFF)
                        break;
        }
 
@@ -166,20 +188,28 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
 
 static unsigned int uart_clps711x_tx_empty(struct uart_port *port)
 {
-       return (clps_readl(SYSFLG(port) & SYSFLG_UBUSY)) ? 0 : TIOCSER_TEMT;
+       struct clps711x_port *s = dev_get_drvdata(port->dev);
+       u32 sysflg = 0;
+
+       regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
+
+       return (sysflg & SYSFLG_UBUSY) ? 0 : TIOCSER_TEMT;
 }
 
 static unsigned int uart_clps711x_get_mctrl(struct uart_port *port)
 {
-       unsigned int status, result = 0;
+       struct clps711x_port *s = dev_get_drvdata(port->dev);
+       unsigned int result = 0;
+
+       if (s->use_ms) {
+               u32 sysflg = 0;
 
-       if (port->line == 0) {
-               status = clps_readl(SYSFLG1);
-               if (status & SYSFLG1_DCD)
+               regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
+               if (sysflg & SYSFLG1_DCD)
                        result |= TIOCM_CAR;
-               if (status & SYSFLG1_DSR)
+               if (sysflg & SYSFLG1_DSR)
                        result |= TIOCM_DSR;
-               if (status & SYSFLG1_CTS)
+               if (sysflg & SYSFLG1_CTS)
                        result |= TIOCM_CTS;
        } else
                result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
@@ -194,65 +224,53 @@ static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 static void uart_clps711x_break_ctl(struct uart_port *port, int break_state)
 {
-       unsigned long flags;
        unsigned int ubrlcr;
 
-       spin_lock_irqsave(&port->lock, flags);
-
-       ubrlcr = clps_readl(UBRLCR(port));
+       ubrlcr = readl(port->membase + UBRLCR_OFFSET);
        if (break_state)
                ubrlcr |= UBRLCR_BREAK;
        else
                ubrlcr &= ~UBRLCR_BREAK;
-       clps_writel(ubrlcr, UBRLCR(port));
+       writel(ubrlcr, port->membase + UBRLCR_OFFSET);
+}
+
+static void uart_clps711x_set_ldisc(struct uart_port *port, int ld)
+{
+       if (!port->line) {
+               struct clps711x_port *s = dev_get_drvdata(port->dev);
 
-       spin_unlock_irqrestore(&port->lock, flags);
+               regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON1_SIREN,
+                                  (ld == N_IRDA) ? SYSCON1_SIREN : 0);
+       }
 }
 
 static int uart_clps711x_startup(struct uart_port *port)
 {
        struct clps711x_port *s = dev_get_drvdata(port->dev);
-       int ret;
-
-       s->tx_enabled[port->line] = 1;
-       /* Allocate the IRQs */
-       ret = devm_request_irq(port->dev, TX_IRQ(port), uart_clps711x_int_tx,
-                              0, UART_CLPS711X_NAME " TX", port);
-       if (ret)
-               return ret;
-
-       ret = devm_request_irq(port->dev, RX_IRQ(port), uart_clps711x_int_rx,
-                              0, UART_CLPS711X_NAME " RX", port);
-       if (ret) {
-               devm_free_irq(port->dev, TX_IRQ(port), port);
-               return ret;
-       }
 
        /* Disable break */
-       clps_writel(clps_readl(UBRLCR(port)) & ~UBRLCR_BREAK, UBRLCR(port));
+       writel(readl(port->membase + UBRLCR_OFFSET) & ~UBRLCR_BREAK,
+              port->membase + UBRLCR_OFFSET);
 
        /* Enable the port */
-       clps_writel(clps_readl(SYSCON(port)) | SYSCON_UARTEN, SYSCON(port));
-
-       return 0;
+       return regmap_update_bits(s->syscon, SYSCON_OFFSET,
+                                 SYSCON_UARTEN, SYSCON_UARTEN);
 }
 
 static void uart_clps711x_shutdown(struct uart_port *port)
 {
-       /* Free the interrupts */
-       devm_free_irq(port->dev, TX_IRQ(port), port);
-       devm_free_irq(port->dev, RX_IRQ(port), port);
+       struct clps711x_port *s = dev_get_drvdata(port->dev);
 
        /* Disable the port */
-       clps_writel(clps_readl(SYSCON(port)) & ~SYSCON_UARTEN, SYSCON(port));
+       regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0);
 }
 
 static void uart_clps711x_set_termios(struct uart_port *port,
                                      struct ktermios *termios,
                                      struct ktermios *old)
 {
-       unsigned int ubrlcr, baud, quot;
-       unsigned long flags;
+       u32 ubrlcr;
+       unsigned int baud, quot;
 
        /* Mask termios capabilities we don't support */
        termios->c_cflag &= ~CMSPAR;
@@ -291,8 +309,6 @@ static void uart_clps711x_set_termios(struct uart_port *port,
        /* Enable FIFO */
        ubrlcr |= UBRLCR_FIFOEN;
 
-       spin_lock_irqsave(&port->lock, flags);
-
        /* Set read status mask */
        port->read_status_mask = UARTDR_OVERR;
        if (termios->c_iflag & INPCK)
@@ -306,9 +322,7 @@ static void uart_clps711x_set_termios(struct uart_port *port,
 
        uart_update_timeout(port, termios->c_cflag, baud);
 
-       clps_writel(ubrlcr | (quot - 1), UBRLCR(port));
-
-       spin_unlock_irqrestore(&port->lock, flags);
+       writel(ubrlcr | (quot - 1), port->membase + UBRLCR_OFFSET);
 }
 
 static const char *uart_clps711x_type(struct uart_port *port)
@@ -322,14 +336,12 @@ static void uart_clps711x_config_port(struct uart_port *port, int flags)
                port->type = PORT_CLPS711X;
 }
 
-static void uart_clps711x_release_port(struct uart_port *port)
+static void uart_clps711x_nop_void(struct uart_port *port)
 {
-       /* Do nothing */
 }
 
-static int uart_clps711x_request_port(struct uart_port *port)
+static int uart_clps711x_nop_int(struct uart_port *port)
 {
-       /* Do nothing */
        return 0;
 }
 
@@ -339,181 +351,237 @@ static const struct uart_ops uart_clps711x_ops = {
        .get_mctrl      = uart_clps711x_get_mctrl,
        .stop_tx        = uart_clps711x_stop_tx,
        .start_tx       = uart_clps711x_start_tx,
-       .stop_rx        = uart_clps711x_stop_rx,
-       .enable_ms      = uart_clps711x_enable_ms,
+       .stop_rx        = uart_clps711x_nop_void,
+       .enable_ms      = uart_clps711x_nop_void,
        .break_ctl      = uart_clps711x_break_ctl,
+       .set_ldisc      = uart_clps711x_set_ldisc,
        .startup        = uart_clps711x_startup,
        .shutdown       = uart_clps711x_shutdown,
        .set_termios    = uart_clps711x_set_termios,
        .type           = uart_clps711x_type,
        .config_port    = uart_clps711x_config_port,
-       .release_port   = uart_clps711x_release_port,
-       .request_port   = uart_clps711x_request_port,
+       .release_port   = uart_clps711x_nop_void,
+       .request_port   = uart_clps711x_nop_int,
 };
 
 #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
 static void uart_clps711x_console_putchar(struct uart_port *port, int ch)
 {
-       while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
-               barrier();
+       struct clps711x_port *s = dev_get_drvdata(port->dev);
+       u32 sysflg = 0;
+
+       do {
+               regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
+       } while (sysflg & SYSFLG_UTXFF);
 
-       clps_writew(ch, UARTDR(port));
+       writew(ch, port->membase + UARTDR_OFFSET);
 }
 
 static void uart_clps711x_console_write(struct console *co, const char *c,
                                        unsigned n)
 {
-       struct clps711x_port *s = (struct clps711x_port *)co->data;
-       struct uart_port *port = &s->port[co->index];
-       u32 syscon;
-
-       /* Ensure that the port is enabled */
-       syscon = clps_readl(SYSCON(port));
-       clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
+       struct uart_port *port = clps711x_uart.state[co->index].uart_port;
+       struct clps711x_port *s = dev_get_drvdata(port->dev);
+       u32 sysflg = 0;
 
        uart_console_write(port, c, n, uart_clps711x_console_putchar);
 
        /* Wait for transmitter to become empty */
-       while (clps_readl(SYSFLG(port)) & SYSFLG_UBUSY)
-               barrier();
-
-       /* Restore the uart state */
-       clps_writel(syscon, SYSCON(port));
+       do {
+               regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
+       } while (sysflg & SYSFLG_UBUSY);
 }
 
-static void uart_clps711x_console_get_options(struct uart_port *port,
-                                             int *baud, int *parity,
-                                             int *bits)
+static int uart_clps711x_console_setup(struct console *co, char *options)
 {
-       if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
-               unsigned int ubrlcr, quot;
+       int baud = 38400, bits = 8, parity = 'n', flow = 'n';
+       int ret, index = co->index;
+       struct clps711x_port *s;
+       struct uart_port *port;
+       unsigned int quot;
+       u32 ubrlcr;
 
-               ubrlcr = clps_readl(UBRLCR(port));
+       if (index < 0 || index >= UART_CLPS711X_NR)
+               return -EINVAL;
 
-               *parity = 'n';
-               if (ubrlcr & UBRLCR_PRTEN) {
-                       if (ubrlcr & UBRLCR_EVENPRT)
-                               *parity = 'e';
-                       else
-                               *parity = 'o';
-               }
+       port = clps711x_uart.state[index].uart_port;
+       if (!port)
+               return -ENODEV;
 
-               if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
-                       *bits = 7;
-               else
-                       *bits = 8;
+       s = dev_get_drvdata(port->dev);
 
-               quot = ubrlcr & UBRLCR_BAUD_MASK;
-               *baud = port->uartclk / (16 * (quot + 1));
-       }
-}
+       if (!options) {
+               u32 syscon = 0;
 
-static int uart_clps711x_console_setup(struct console *co, char *options)
-{
-       int baud = 38400, bits = 8, parity = 'n', flow = 'n';
-       struct clps711x_port *s = (struct clps711x_port *)co->data;
-       struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0];
+               regmap_read(s->syscon, SYSCON_OFFSET, &syscon);
+               if (syscon & SYSCON_UARTEN) {
+                       ubrlcr = readl(port->membase + UBRLCR_OFFSET);
+
+                       if (ubrlcr & UBRLCR_PRTEN) {
+                               if (ubrlcr & UBRLCR_EVENPRT)
+                                       parity = 'e';
+                               else
+                                       parity = 'o';
+                       }
+
+                       if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
+                               bits = 7;
 
-       if (options)
+                       quot = ubrlcr & UBRLCR_BAUD_MASK;
+                       baud = port->uartclk / (16 * (quot + 1));
+               }
+       } else
                uart_parse_options(options, &baud, &parity, &bits, &flow);
-       else
-               uart_clps711x_console_get_options(port, &baud, &parity, &bits);
 
-       return uart_set_options(port, co, baud, parity, bits, flow);
+       ret = uart_set_options(port, co, baud, parity, bits, flow);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(s->syscon, SYSCON_OFFSET,
+                                 SYSCON_UARTEN, SYSCON_UARTEN);
 }
+
+static struct console clps711x_console = {
+       .name   = UART_CLPS711X_DEVNAME,
+       .device = uart_console_device,
+       .write  = uart_clps711x_console_write,
+       .setup  = uart_clps711x_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+};
 #endif
 
 static int uart_clps711x_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
+       int ret, index = np ? of_alias_get_id(np, "serial") : pdev->id;
        struct clps711x_port *s;
-       int ret, i;
+       struct resource *res;
+       struct clk *uart_clk;
 
-       s = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_port), GFP_KERNEL);
-       if (!s) {
-               dev_err(&pdev->dev, "Error allocating port structure\n");
+       if (index < 0 || index >= UART_CLPS711X_NR)
+               return -EINVAL;
+
+       s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
+       if (!s)
                return -ENOMEM;
+
+       uart_clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(uart_clk))
+               return PTR_ERR(uart_clk);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       s->port.membase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(s->port.membase))
+               return PTR_ERR(s->port.membase);
+
+       s->port.irq = platform_get_irq(pdev, 0);
+       if (IS_ERR_VALUE(s->port.irq))
+               return s->port.irq;
+
+       s->rx_irq = platform_get_irq(pdev, 1);
+       if (IS_ERR_VALUE(s->rx_irq))
+               return s->rx_irq;
+
+       if (!np) {
+               char syscon_name[9];
+
+               sprintf(syscon_name, "syscon.%i", index + 1);
+               s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name);
+               if (IS_ERR(s->syscon))
+                       return PTR_ERR(s->syscon);
+
+               s->use_ms = !index;
+       } else {
+               s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
+               if (IS_ERR(s->syscon))
+                       return PTR_ERR(s->syscon);
+
+               if (!index)
+                       s->use_ms = of_property_read_bool(np, "uart-use-ms");
        }
+
+       s->port.line            = index;
+       s->port.dev             = &pdev->dev;
+       s->port.iotype          = UPIO_MEM32;
+       s->port.mapbase         = res->start;
+       s->port.type            = PORT_CLPS711X;
+       s->port.fifosize        = 16;
+       s->port.flags           = UPF_SKIP_TEST | UPF_FIXED_TYPE;
+       s->port.uartclk         = clk_get_rate(uart_clk);
+       s->port.ops             = &uart_clps711x_ops;
+
        platform_set_drvdata(pdev, s);
 
-       s->uart_clk = devm_clk_get(&pdev->dev, "uart");
-       if (IS_ERR(s->uart_clk)) {
-               dev_err(&pdev->dev, "Can't get UART clocks\n");
-               return PTR_ERR(s->uart_clk);
-       }
+       ret = uart_add_one_port(&clps711x_uart, &s->port);
+       if (ret)
+               return ret;
 
-       s->uart.owner           = THIS_MODULE;
-       s->uart.dev_name        = "ttyCL";
-       s->uart.major           = UART_CLPS711X_MAJOR;
-       s->uart.minor           = UART_CLPS711X_MINOR;
-       s->uart.nr              = UART_CLPS711X_NR;
-#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
-       s->uart.cons            = &s->console;
-       s->uart.cons->device    = uart_console_device;
-       s->uart.cons->write     = uart_clps711x_console_write;
-       s->uart.cons->setup     = uart_clps711x_console_setup;
-       s->uart.cons->flags     = CON_PRINTBUFFER;
-       s->uart.cons->index     = -1;
-       s->uart.cons->data      = s;
-       strcpy(s->uart.cons->name, "ttyCL");
-#endif
-       ret = uart_register_driver(&s->uart);
+       /* Disable port */
+       if (!uart_console(&s->port))
+               regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0);
+
+       s->tx_enabled = 1;
+
+       ret = devm_request_irq(&pdev->dev, s->port.irq, uart_clps711x_int_tx, 0,
+                              dev_name(&pdev->dev), &s->port);
        if (ret) {
-               dev_err(&pdev->dev, "Registering UART driver failed\n");
+               uart_remove_one_port(&clps711x_uart, &s->port);
                return ret;
        }
 
-       for (i = 0; i < UART_CLPS711X_NR; i++) {
-               s->port[i].line         = i;
-               s->port[i].dev          = &pdev->dev;
-               s->port[i].irq          = TX_IRQ(&s->port[i]);
-               s->port[i].iobase       = SYSCON(&s->port[i]);
-               s->port[i].type         = PORT_CLPS711X;
-               s->port[i].fifosize     = 16;
-               s->port[i].flags        = UPF_SKIP_TEST | UPF_FIXED_TYPE;
-               s->port[i].uartclk      = clk_get_rate(s->uart_clk);
-               s->port[i].ops          = &uart_clps711x_ops;
-               WARN_ON(uart_add_one_port(&s->uart, &s->port[i]));
-       }
+       ret = devm_request_irq(&pdev->dev, s->rx_irq, uart_clps711x_int_rx, 0,
+                              dev_name(&pdev->dev), &s->port);
+       if (ret)
+               uart_remove_one_port(&clps711x_uart, &s->port);
 
-       return 0;
+       return ret;
 }
 
 static int uart_clps711x_remove(struct platform_device *pdev)
 {
        struct clps711x_port *s = platform_get_drvdata(pdev);
-       int i;
 
-       for (i = 0; i < UART_CLPS711X_NR; i++)
-               uart_remove_one_port(&s->uart, &s->port[i]);
-
-       uart_unregister_driver(&s->uart);
-
-       return 0;
+       return uart_remove_one_port(&clps711x_uart, &s->port);
 }
 
-static struct platform_driver clps711x_uart_driver = {
+static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = {
+       { .compatible = "cirrus,clps711x-uart", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids);
+
+static struct platform_driver clps711x_uart_platform = {
        .driver = {
-               .name   = UART_CLPS711X_NAME,
-               .owner  = THIS_MODULE,
+               .name           = "clps711x-uart",
+               .owner          = THIS_MODULE,
+               .of_match_table = of_match_ptr(clps711x_uart_dt_ids),
        },
        .probe  = uart_clps711x_probe,
        .remove = uart_clps711x_remove,
 };
-module_platform_driver(clps711x_uart_driver);
-
-static struct platform_device clps711x_uart_device = {
-       .name   = UART_CLPS711X_NAME,
-};
 
 static int __init uart_clps711x_init(void)
 {
-       return platform_device_register(&clps711x_uart_device);
+       int ret;
+
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+       clps711x_uart.cons = &clps711x_console;
+       clps711x_console.data = &clps711x_uart;
+#endif
+
+       ret = uart_register_driver(&clps711x_uart);
+       if (ret)
+               return ret;
+
+       return platform_driver_register(&clps711x_uart_platform);
 }
 module_init(uart_clps711x_init);
 
 static void __exit uart_clps711x_exit(void)
 {
-       platform_device_unregister(&clps711x_uart_device);
+       platform_driver_unregister(&clps711x_uart_platform);
+       uart_unregister_driver(&clps711x_uart);
 }
 module_exit(uart_clps711x_exit);
 
index 527a969b095247b90867e17eb5b1ab9fcdcef44c..6d3b22e93246703b572ca424c5f5375cf4950021 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/tty.h>
 #include <linux/gfp.h>
 #include <linux/ioport.h>
-#include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/console.h>
 #include <linux/sysrq.h>
index a4927e66e7418de329f930bad1d50afe8fbf93d1..f46d2ca872096c0aa26e754a36cfb71d1c53f509 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/serial.h>
 #include <linux/console.h>
 #include <linux/sysrq.h>
index b2cfdb661947ec2690fc4840e089688151749a68..d799140e53b6a649b51ace8129b8846ed695a824 100644 (file)
@@ -806,6 +806,9 @@ static unsigned int imx_get_mctrl(struct uart_port *port)
        if (readl(sport->port.membase + UCR2) & UCR2_CTS)
                tmp |= TIOCM_RTS;
 
+       if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP)
+               tmp |= TIOCM_LOOP;
+
        return tmp;
 }
 
@@ -821,6 +824,11 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
                        temp |= UCR2_CTS;
 
        writel(temp, sport->port.membase + UCR2);
+
+       temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP;
+       if (mctrl & TIOCM_LOOP)
+               temp |= UTS_LOOP;
+       writel(temp, sport->port.membase + uts_reg(sport));
 }
 
 /*
index 5dafcf1c227ba88ed9cf5025e6c965203464dc4b..5f673b7ca50e300bbdde5f3343d81fd70cc89d11 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/compiler.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/atomic.h>
index d8b6fee77a039220ae8d7d8f08a9ff8e08c7066f..aa97fd845b4d8123102c6026ed9a79e53d61e45f 100644 (file)
@@ -734,9 +734,12 @@ static void mxs_auart_reset(struct uart_port *u)
 
 static int mxs_auart_startup(struct uart_port *u)
 {
+       int ret;
        struct mxs_auart_port *s = to_auart_port(u);
 
-       clk_prepare_enable(s->clk);
+       ret = clk_prepare_enable(s->clk);
+       if (ret)
+               return ret;
 
        writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
 
@@ -957,7 +960,9 @@ auart_console_setup(struct console *co, char *options)
        if (!s)
                return -ENODEV;
 
-       clk_prepare_enable(s->clk);
+       ret = clk_prepare_enable(s->clk);
+       if (ret)
+               return ret;
 
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
index 2caf9c6f61499f15738a29c6659d91f1c7fad826..99246606a256b71cbef9272b1402afc4bdcf1009 100644 (file)
@@ -9,7 +9,6 @@
  *  2 of the License, or (at your option) any later version.
  *
  */
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
index 0aa2b528ef3d76363c3cd9dcc4ebd96adee850a8..9cbd3acaf37fca13a55ea6b9a854e259790d1758 100644 (file)
@@ -1853,7 +1853,6 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
                debugfs_remove(priv->debugfs);
 #endif
        uart_remove_one_port(&pch_uart_driver, &priv->port);
-       pci_set_drvdata(priv->pdev, NULL);
        free_page((unsigned long)priv->rxbuf.buf);
 }
 
@@ -1907,7 +1906,7 @@ static int pch_uart_pci_resume(struct pci_dev *pdev)
 #define pch_uart_pci_resume NULL
 #endif
 
-static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
+static const struct pci_device_id pch_uart_pci_id[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
         .driver_data = pch_et20t_uart0},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),
index 328d6deb6b0899b490684b3735800970625cea85..056f91b3a4ca564d4a04d47183979014922f2cc3 100644 (file)
@@ -810,7 +810,7 @@ static void rp2_remove(struct pci_dev *pdev)
        rp2_remove_ports(card);
 }
 
-static DEFINE_PCI_DEVICE_TABLE(rp2_pci_tbl) = {
+static const struct pci_device_id rp2_pci_tbl[] = {
 
        /* RocketPort INFINITY cards */
 
diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
deleted file mode 100644 (file)
index 887b4f7..0000000
+++ /dev/null
@@ -1,749 +0,0 @@
-/*
- * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
- *
- * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/circ_buf.h>
-#include <linux/serial.h>
-#include <linux/sysrq.h>
-#include <linux/console.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#warning "Please try migrate to use new driver SCCNXP and report the status" \
-        "in the linux-serial mailing list."
-
-#if defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#define SC26XX_MAJOR         204
-#define SC26XX_MINOR_START   205
-#define SC26XX_NR            2
-
-struct uart_sc26xx_port {
-       struct uart_port      port[2];
-       u8     dsr_mask[2];
-       u8     cts_mask[2];
-       u8     dcd_mask[2];
-       u8     ri_mask[2];
-       u8     dtr_mask[2];
-       u8     rts_mask[2];
-       u8     imr;
-};
-
-/* register common to both ports */
-#define RD_ISR      0x14
-#define RD_IPR      0x34
-
-#define WR_ACR      0x10
-#define WR_IMR      0x14
-#define WR_OPCR     0x34
-#define WR_OPR_SET  0x38
-#define WR_OPR_CLR  0x3C
-
-/* access common register */
-#define READ_SC(p, r)        readb((p)->membase + RD_##r)
-#define WRITE_SC(p, r, v)    writeb((v), (p)->membase + WR_##r)
-
-/* register per port */
-#define RD_PORT_MRx 0x00
-#define RD_PORT_SR  0x04
-#define RD_PORT_RHR 0x0c
-
-#define WR_PORT_MRx 0x00
-#define WR_PORT_CSR 0x04
-#define WR_PORT_CR  0x08
-#define WR_PORT_THR 0x0c
-
-/* SR bits */
-#define SR_BREAK    (1 << 7)
-#define SR_FRAME    (1 << 6)
-#define SR_PARITY   (1 << 5)
-#define SR_OVERRUN  (1 << 4)
-#define SR_TXRDY    (1 << 2)
-#define SR_RXRDY    (1 << 0)
-
-#define CR_RES_MR   (1 << 4)
-#define CR_RES_RX   (2 << 4)
-#define CR_RES_TX   (3 << 4)
-#define CR_STRT_BRK (6 << 4)
-#define CR_STOP_BRK (7 << 4)
-#define CR_DIS_TX   (1 << 3)
-#define CR_ENA_TX   (1 << 2)
-#define CR_DIS_RX   (1 << 1)
-#define CR_ENA_RX   (1 << 0)
-
-/* ISR bits */
-#define ISR_RXRDYB  (1 << 5)
-#define ISR_TXRDYB  (1 << 4)
-#define ISR_RXRDYA  (1 << 1)
-#define ISR_TXRDYA  (1 << 0)
-
-/* IMR bits */
-#define IMR_RXRDY   (1 << 1)
-#define IMR_TXRDY   (1 << 0)
-
-/* access port register */
-static inline u8 read_sc_port(struct uart_port *p, u8 reg)
-{
-       return readb(p->membase + p->line * 0x20 + reg);
-}
-
-static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
-{
-       writeb(val, p->membase + p->line * 0x20 + reg);
-}
-
-#define READ_SC_PORT(p, r)     read_sc_port(p, RD_PORT_##r)
-#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
-
-static void sc26xx_enable_irq(struct uart_port *port, int mask)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-
-       up->imr |= mask << (line * 4);
-       WRITE_SC(port, IMR, up->imr);
-}
-
-static void sc26xx_disable_irq(struct uart_port *port, int mask)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-
-       up->imr &= ~(mask << (line * 4));
-       WRITE_SC(port, IMR, up->imr);
-}
-
-static bool receive_chars(struct uart_port *port)
-{
-       struct tty_port *tport = NULL;
-       int limit = 10000;
-       unsigned char ch;
-       char flag;
-       u8 status;
-
-       /* FIXME what is this trying to achieve? */
-       if (port->state != NULL)                /* Unopened serial console */
-               tport = &port->state->port;
-
-       while (limit-- > 0) {
-               status = READ_SC_PORT(port, SR);
-               if (!(status & SR_RXRDY))
-                       break;
-               ch = READ_SC_PORT(port, RHR);
-
-               flag = TTY_NORMAL;
-               port->icount.rx++;
-
-               if (unlikely(status & (SR_BREAK | SR_FRAME |
-                                      SR_PARITY | SR_OVERRUN))) {
-                       if (status & SR_BREAK) {
-                               status &= ~(SR_PARITY | SR_FRAME);
-                               port->icount.brk++;
-                               if (uart_handle_break(port))
-                                       continue;
-                       } else if (status & SR_PARITY)
-                               port->icount.parity++;
-                       else if (status & SR_FRAME)
-                               port->icount.frame++;
-                       if (status & SR_OVERRUN)
-                               port->icount.overrun++;
-
-                       status &= port->read_status_mask;
-                       if (status & SR_BREAK)
-                               flag = TTY_BREAK;
-                       else if (status & SR_PARITY)
-                               flag = TTY_PARITY;
-                       else if (status & SR_FRAME)
-                               flag = TTY_FRAME;
-               }
-
-               if (uart_handle_sysrq_char(port, ch))
-                       continue;
-
-               if (status & port->ignore_status_mask)
-                       continue;
-
-               tty_insert_flip_char(tport, ch, flag);
-       }
-       return !!tport;
-}
-
-static void transmit_chars(struct uart_port *port)
-{
-       struct circ_buf *xmit;
-
-       if (!port->state)
-               return;
-
-       xmit = &port->state->xmit;
-       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-               sc26xx_disable_irq(port, IMR_TXRDY);
-               return;
-       }
-       while (!uart_circ_empty(xmit)) {
-               if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
-                       break;
-
-               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
-}
-
-static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
-{
-       struct uart_sc26xx_port *up = dev_id;
-       unsigned long flags;
-       bool push;
-       u8 isr;
-
-       spin_lock_irqsave(&up->port[0].lock, flags);
-
-       push = false;
-       isr = READ_SC(&up->port[0], ISR);
-       if (isr & ISR_TXRDYA)
-           transmit_chars(&up->port[0]);
-       if (isr & ISR_RXRDYA)
-           push = receive_chars(&up->port[0]);
-
-       spin_unlock(&up->port[0].lock);
-
-       if (push)
-               tty_flip_buffer_push(&up->port[0].state->port);
-
-       spin_lock(&up->port[1].lock);
-
-       push = false;
-       if (isr & ISR_TXRDYB)
-           transmit_chars(&up->port[1]);
-       if (isr & ISR_RXRDYB)
-           push = receive_chars(&up->port[1]);
-
-       spin_unlock_irqrestore(&up->port[1].lock, flags);
-
-       if (push)
-               tty_flip_buffer_push(&up->port[1].state->port);
-
-       return IRQ_HANDLED;
-}
-
-/* port->lock is not held.  */
-static unsigned int sc26xx_tx_empty(struct uart_port *port)
-{
-       return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-
-       if (up->dtr_mask[line]) {
-               if (mctrl & TIOCM_DTR)
-                       WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
-               else
-                       WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
-       }
-       if (up->rts_mask[line]) {
-               if (mctrl & TIOCM_RTS)
-                       WRITE_SC(port, OPR_SET, up->rts_mask[line]);
-               else
-                       WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
-       }
-}
-
-/* port->lock is held by caller and interrupts are disabled.  */
-static unsigned int sc26xx_get_mctrl(struct uart_port *port)
-{
-       struct uart_sc26xx_port *up;
-       int line = port->line;
-       unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
-       u8 ipr;
-
-       port -= line;
-       up = container_of(port, struct uart_sc26xx_port, port[0]);
-       ipr = READ_SC(port, IPR) ^ 0xff;
-
-       if (up->dsr_mask[line]) {
-               mctrl &= ~TIOCM_DSR;
-               mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
-       }
-       if (up->cts_mask[line]) {
-               mctrl &= ~TIOCM_CTS;
-               mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
-       }
-       if (up->dcd_mask[line]) {
-               mctrl &= ~TIOCM_CAR;
-               mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
-       }
-       if (up->ri_mask[line]) {
-               mctrl &= ~TIOCM_RNG;
-               mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
-       }
-       return mctrl;
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_stop_tx(struct uart_port *port)
-{
-       return;
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_start_tx(struct uart_port *port)
-{
-       struct circ_buf *xmit = &port->state->xmit;
-
-       while (!uart_circ_empty(xmit)) {
-               if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
-                       sc26xx_enable_irq(port, IMR_TXRDY);
-                       break;
-               }
-               WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
-               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               port->icount.tx++;
-       }
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_stop_rx(struct uart_port *port)
-{
-}
-
-/* port->lock held by caller.  */
-static void sc26xx_enable_ms(struct uart_port *port)
-{
-}
-
-/* port->lock is not held.  */
-static void sc26xx_break_ctl(struct uart_port *port, int break_state)
-{
-       if (break_state == -1)
-               WRITE_SC_PORT(port, CR, CR_STRT_BRK);
-       else
-               WRITE_SC_PORT(port, CR, CR_STOP_BRK);
-}
-
-/* port->lock is not held.  */
-static int sc26xx_startup(struct uart_port *port)
-{
-       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
-       WRITE_SC(port, OPCR, 0);
-
-       /* reset tx and rx */
-       WRITE_SC_PORT(port, CR, CR_RES_RX);
-       WRITE_SC_PORT(port, CR, CR_RES_TX);
-
-       /* start rx/tx */
-       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
-
-       /* enable irqs */
-       sc26xx_enable_irq(port, IMR_RXRDY);
-       return 0;
-}
-
-/* port->lock is not held.  */
-static void sc26xx_shutdown(struct uart_port *port)
-{
-       /* disable interrupst */
-       sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
-
-       /* stop tx/rx */
-       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
-}
-
-/* port->lock is not held.  */
-static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
-                             struct ktermios *old)
-{
-       unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
-       unsigned int quot = uart_get_divisor(port, baud);
-       unsigned int iflag, cflag;
-       unsigned long flags;
-       u8 mr1, mr2, csr;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
-               udelay(2);
-
-       WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
-
-       iflag = termios->c_iflag;
-       cflag = termios->c_cflag;
-
-       port->read_status_mask = SR_OVERRUN;
-       if (iflag & INPCK)
-               port->read_status_mask |= SR_PARITY | SR_FRAME;
-       if (iflag & (BRKINT | PARMRK))
-               port->read_status_mask |= SR_BREAK;
-
-       port->ignore_status_mask = 0;
-       if (iflag & IGNBRK)
-               port->ignore_status_mask |= SR_BREAK;
-       if ((cflag & CREAD) == 0)
-               port->ignore_status_mask |= SR_BREAK | SR_FRAME |
-                                           SR_PARITY | SR_OVERRUN;
-
-       switch (cflag & CSIZE) {
-       case CS5:
-               mr1 = 0x00;
-               break;
-       case CS6:
-               mr1 = 0x01;
-               break;
-       case CS7:
-               mr1 = 0x02;
-               break;
-       default:
-       case CS8:
-               mr1 = 0x03;
-               break;
-       }
-       mr2 = 0x07;
-       if (cflag & CSTOPB)
-               mr2 = 0x0f;
-       if (cflag & PARENB) {
-               if (cflag & PARODD)
-                       mr1 |= (1 << 2);
-       } else
-               mr1 |= (2 << 3);
-
-       switch (baud) {
-       case 50:
-               csr = 0x00;
-               break;
-       case 110:
-               csr = 0x11;
-               break;
-       case 134:
-               csr = 0x22;
-               break;
-       case 200:
-               csr = 0x33;
-               break;
-       case 300:
-               csr = 0x44;
-               break;
-       case 600:
-               csr = 0x55;
-               break;
-       case 1200:
-               csr = 0x66;
-               break;
-       case 2400:
-               csr = 0x88;
-               break;
-       case 4800:
-               csr = 0x99;
-               break;
-       default:
-       case 9600:
-               csr = 0xbb;
-               break;
-       case 19200:
-               csr = 0xcc;
-               break;
-       }
-
-       WRITE_SC_PORT(port, CR, CR_RES_MR);
-       WRITE_SC_PORT(port, MRx, mr1);
-       WRITE_SC_PORT(port, MRx, mr2);
-
-       WRITE_SC(port, ACR, 0x80);
-       WRITE_SC_PORT(port, CSR, csr);
-
-       /* reset tx and rx */
-       WRITE_SC_PORT(port, CR, CR_RES_RX);
-       WRITE_SC_PORT(port, CR, CR_RES_TX);
-
-       WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
-       while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
-               udelay(2);
-
-       /* XXX */
-       uart_update_timeout(port, cflag,
-                           (port->uartclk / (16 * quot)));
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *sc26xx_type(struct uart_port *port)
-{
-       return "SC26XX";
-}
-
-static void sc26xx_release_port(struct uart_port *port)
-{
-}
-
-static int sc26xx_request_port(struct uart_port *port)
-{
-       return 0;
-}
-
-static void sc26xx_config_port(struct uart_port *port, int flags)
-{
-}
-
-static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       return -EINVAL;
-}
-
-static struct uart_ops sc26xx_ops = {
-       .tx_empty       = sc26xx_tx_empty,
-       .set_mctrl      = sc26xx_set_mctrl,
-       .get_mctrl      = sc26xx_get_mctrl,
-       .stop_tx        = sc26xx_stop_tx,
-       .start_tx       = sc26xx_start_tx,
-       .stop_rx        = sc26xx_stop_rx,
-       .enable_ms      = sc26xx_enable_ms,
-       .break_ctl      = sc26xx_break_ctl,
-       .startup        = sc26xx_startup,
-       .shutdown       = sc26xx_shutdown,
-       .set_termios    = sc26xx_set_termios,
-       .type           = sc26xx_type,
-       .release_port   = sc26xx_release_port,
-       .request_port   = sc26xx_request_port,
-       .config_port    = sc26xx_config_port,
-       .verify_port    = sc26xx_verify_port,
-};
-
-static struct uart_port *sc26xx_port;
-
-#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
-static void sc26xx_console_putchar(struct uart_port *port, char c)
-{
-       unsigned long flags;
-       int limit = 1000000;
-
-       spin_lock_irqsave(&port->lock, flags);
-
-       while (limit-- > 0) {
-               if (READ_SC_PORT(port, SR) & SR_TXRDY) {
-                       WRITE_SC_PORT(port, THR, c);
-                       break;
-               }
-               udelay(2);
-       }
-
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
-{
-       struct uart_port *port = sc26xx_port;
-       int i;
-
-       for (i = 0; i < n; i++) {
-               if (*s == '\n')
-                       sc26xx_console_putchar(port, '\r');
-               sc26xx_console_putchar(port, *s++);
-       }
-}
-
-static int __init sc26xx_console_setup(struct console *con, char *options)
-{
-       struct uart_port *port = sc26xx_port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
-
-       if (port->type != PORT_SC26XX)
-               return -1;
-
-       printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
-
-       return uart_set_options(port, con, baud, parity, bits, flow);
-}
-
-static struct uart_driver sc26xx_reg;
-static struct console sc26xx_console = {
-       .name   =       "ttySC",
-       .write  =       sc26xx_console_write,
-       .device =       uart_console_device,
-       .setup  =       sc26xx_console_setup,
-       .flags  =       CON_PRINTBUFFER,
-       .index  =       -1,
-       .data   =       &sc26xx_reg,
-};
-#define SC26XX_CONSOLE   &sc26xx_console
-#else
-#define SC26XX_CONSOLE   NULL
-#endif
-
-static struct uart_driver sc26xx_reg = {
-       .owner                  = THIS_MODULE,
-       .driver_name            = "SC26xx",
-       .dev_name               = "ttySC",
-       .major                  = SC26XX_MAJOR,
-       .minor                  = SC26XX_MINOR_START,
-       .nr                     = SC26XX_NR,
-       .cons                   = SC26XX_CONSOLE,
-};
-
-static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
-{
-       unsigned int bit = (flags >> bitpos) & 15;
-
-       return bit ? (1 << (bit - 1)) : 0;
-}
-
-static void sc26xx_init_masks(struct uart_sc26xx_port *up,
-                                       int line, unsigned int data)
-{
-       up->dtr_mask[line] = sc26xx_flags2mask(data,  0);
-       up->rts_mask[line] = sc26xx_flags2mask(data,  4);
-       up->dsr_mask[line] = sc26xx_flags2mask(data,  8);
-       up->cts_mask[line] = sc26xx_flags2mask(data, 12);
-       up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
-       up->ri_mask[line]  = sc26xx_flags2mask(data, 20);
-}
-
-static int sc26xx_probe(struct platform_device *dev)
-{
-       struct resource *res;
-       struct uart_sc26xx_port *up;
-       unsigned int *sc26xx_data = dev_get_platdata(&dev->dev);
-       int err;
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       up = kzalloc(sizeof *up, GFP_KERNEL);
-       if (unlikely(!up))
-               return -ENOMEM;
-
-       up->port[0].line = 0;
-       up->port[0].ops = &sc26xx_ops;
-       up->port[0].type = PORT_SC26XX;
-       up->port[0].uartclk = (29491200 / 16); /* arbitrary */
-
-       up->port[0].mapbase = res->start;
-       up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
-       up->port[0].iotype = UPIO_MEM;
-       up->port[0].irq = platform_get_irq(dev, 0);
-
-       up->port[0].dev = &dev->dev;
-
-       sc26xx_init_masks(up, 0, sc26xx_data[0]);
-
-       sc26xx_port = &up->port[0];
-
-       up->port[1].line = 1;
-       up->port[1].ops = &sc26xx_ops;
-       up->port[1].type = PORT_SC26XX;
-       up->port[1].uartclk = (29491200 / 16); /* arbitrary */
-
-       up->port[1].mapbase = up->port[0].mapbase;
-       up->port[1].membase = up->port[0].membase;
-       up->port[1].iotype = UPIO_MEM;
-       up->port[1].irq = up->port[0].irq;
-
-       up->port[1].dev = &dev->dev;
-
-       sc26xx_init_masks(up, 1, sc26xx_data[1]);
-
-       err = uart_register_driver(&sc26xx_reg);
-       if (err)
-               goto out_free_port;
-
-       sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
-
-       err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
-       if (err)
-               goto out_unregister_driver;
-
-       err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
-       if (err)
-               goto out_remove_port0;
-
-       err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
-       if (err)
-               goto out_remove_ports;
-
-       platform_set_drvdata(dev, up);
-       return 0;
-
-out_remove_ports:
-       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
-out_remove_port0:
-       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
-
-out_unregister_driver:
-       uart_unregister_driver(&sc26xx_reg);
-
-out_free_port:
-       kfree(up);
-       sc26xx_port = NULL;
-       return err;
-}
-
-
-static int __exit sc26xx_driver_remove(struct platform_device *dev)
-{
-       struct uart_sc26xx_port *up = platform_get_drvdata(dev);
-
-       free_irq(up->port[0].irq, up);
-
-       uart_remove_one_port(&sc26xx_reg, &up->port[0]);
-       uart_remove_one_port(&sc26xx_reg, &up->port[1]);
-
-       uart_unregister_driver(&sc26xx_reg);
-
-       kfree(up);
-       sc26xx_port = NULL;
-
-       return 0;
-}
-
-static struct platform_driver sc26xx_driver = {
-       .probe  = sc26xx_probe,
-       .remove = sc26xx_driver_remove,
-       .driver = {
-               .name   = "SC26xx",
-               .owner  = THIS_MODULE,
-       },
-};
-
-module_platform_driver(sc26xx_driver);
-
-MODULE_AUTHOR("Thomas Bogendörfer");
-MODULE_DESCRIPTION("SC681/SC2692 serial driver");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:SC26xx");
index 0f02351c9239b2221dbc3820b7896388a83a71a8..ece2049bd27016487aef8327eee7fb040ee346db 100644 (file)
@@ -1830,9 +1830,13 @@ uart_set_options(struct uart_port *port, struct console *co,
        /*
         * Ensure that the serial console lock is initialised
         * early.
+        * If this port is a console, then the spinlock is already
+        * initialised.
         */
-       spin_lock_init(&port->lock);
-       lockdep_set_class(&port->lock, &port_lock_key);
+       if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
+               spin_lock_init(&port->lock);
+               lockdep_set_class(&port->lock, &port_lock_key);
+       }
 
        memset(&termios, 0, sizeof(struct ktermios));
 
index f186a8fb8887119cd036625a129f515bb57f4210..49a2ffd101a7145ca1de4a7eccb72d56964037d0 100644 (file)
@@ -524,9 +524,11 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
        struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
        unsigned int count;
        unsigned long flags;
+       struct dma_tx_state tx_state;
 
        spin_lock_irqsave(&sirfport->rx_lock, flags);
-       while (sirfport->rx_completed != sirfport->rx_issued) {
+       while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
+               sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
                sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
                                        SIRFSOC_RX_DMA_BUF_SIZE);
                sirfport->rx_completed++;
@@ -709,8 +711,10 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
        struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
        struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
        unsigned long flags;
+       struct dma_tx_state tx_state;
        spin_lock_irqsave(&sirfport->rx_lock, flags);
-       while (sirfport->rx_completed != sirfport->rx_issued) {
+       while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
+                       sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
                sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
                                        SIRFSOC_RX_DMA_BUF_SIZE);
                if (rd_regl(port, ureg->sirfsoc_int_en_reg) &
@@ -1033,6 +1037,16 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
+static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
+                             unsigned int oldstate)
+{
+       struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+       if (!state)
+               clk_prepare_enable(sirfport->clk);
+       else
+               clk_disable_unprepare(sirfport->clk);
+}
+
 static unsigned int sirfsoc_uart_init_tx_dma(struct uart_port *port)
 {
        struct sirfsoc_uart_port *sirfport = to_sirfport(port);
@@ -1264,6 +1278,7 @@ static struct uart_ops sirfsoc_uart_ops = {
        .startup        = sirfsoc_uart_startup,
        .shutdown       = sirfsoc_uart_shutdown,
        .set_termios    = sirfsoc_uart_set_termios,
+       .pm             = sirfsoc_uart_pm,
        .type           = sirfsoc_uart_type,
        .release_port   = sirfsoc_uart_release_port,
        .request_port   = sirfsoc_uart_request_port,
@@ -1486,7 +1501,6 @@ usp_no_flow_control:
                ret = PTR_ERR(sirfport->clk);
                goto err;
        }
-       clk_prepare_enable(sirfport->clk);
        port->uartclk = clk_get_rate(sirfport->clk);
 
        port->ops = &sirfsoc_uart_ops;
@@ -1502,7 +1516,6 @@ usp_no_flow_control:
        return 0;
 
 port_err:
-       clk_disable_unprepare(sirfport->clk);
        clk_put(sirfport->clk);
 err:
        return ret;
@@ -1512,38 +1525,42 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
 {
        struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
        struct uart_port *port = &sirfport->port;
-       clk_disable_unprepare(sirfport->clk);
        clk_put(sirfport->clk);
        uart_remove_one_port(&sirfsoc_uart_drv, port);
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int
-sirfsoc_uart_suspend(struct platform_device *pdev, pm_message_t state)
+sirfsoc_uart_suspend(struct device *pdev)
 {
-       struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
+       struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev);
        struct uart_port *port = &sirfport->port;
        uart_suspend_port(&sirfsoc_uart_drv, port);
        return 0;
 }
 
-static int sirfsoc_uart_resume(struct platform_device *pdev)
+static int sirfsoc_uart_resume(struct device *pdev)
 {
-       struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
+       struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev);
        struct uart_port *port = &sirfport->port;
        uart_resume_port(&sirfsoc_uart_drv, port);
        return 0;
 }
+#endif
+
+static const struct dev_pm_ops sirfsoc_uart_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_uart_suspend, sirfsoc_uart_resume)
+};
 
 static struct platform_driver sirfsoc_uart_driver = {
        .probe          = sirfsoc_uart_probe,
        .remove         = sirfsoc_uart_remove,
-       .suspend        = sirfsoc_uart_suspend,
-       .resume         = sirfsoc_uart_resume,
        .driver         = {
                .name   = SIRFUART_PORT_NAME,
                .owner  = THIS_MODULE,
                .of_match_table = sirfsoc_uart_ids,
+               .pm     = &sirfsoc_uart_pm_ops,
        },
 };
 
index e1ce141bad5e2995afb98ee3fd9719c1558f03f8..5ae14b46cce0709aab95904ca0082ac3a29f7d7a 100644 (file)
@@ -3404,8 +3404,8 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
 
        /* If port is closing, signal caller to try again */
        if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
-               if (info->port.flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&info->port.close_wait);
+               wait_event_interruptible_tty(tty, info->port.close_wait,
+                                    !(info->port.flags & ASYNC_CLOSING));
                retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
                        -EAGAIN : -ERESTARTSYS);
                goto cleanup;
index 1abf946463f664522d1721a1537a4fdba9d45c25..c359a91f7346071396e7ba0ec9d3f4bb4a381772 100644 (file)
@@ -674,8 +674,8 @@ static int open(struct tty_struct *tty, struct file *filp)
 
        /* If port is closing, signal caller to try again */
        if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
-               if (info->port.flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&info->port.close_wait);
+               wait_event_interruptible_tty(tty, info->port.close_wait,
+                                            !(info->port.flags & ASYNC_CLOSING));
                retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
                        -EAGAIN : -ERESTARTSYS);
                goto cleanup;
index dc6e96996ead4796eace1ba3bb4b61232f132302..144202eef6fe3a3a9bda7e5dc4527a71201bd6f5 100644 (file)
@@ -754,8 +754,8 @@ static int open(struct tty_struct *tty, struct file *filp)
 
        /* If port is closing, signal caller to try again */
        if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
-               if (info->port.flags & ASYNC_CLOSING)
-                       interruptible_sleep_on(&info->port.close_wait);
+               wait_event_interruptible_tty(tty, info->port.close_wait,
+                                            !(info->port.flags & ASYNC_CLOSING));
                retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
                        -EAGAIN : -ERESTARTSYS);
                goto cleanup;
index c043136fbe5198cf0a7a8704254fc28763ecd0b9..765125dff20e36f5d07e2db53646f83f66a223f7 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
@@ -26,7 +25,7 @@
  * Byte threshold to limit memory consumption for flip buffers.
  * The actual memory limit is > 2x this amount.
  */
-#define TTYB_MEM_LIMIT 65536
+#define TTYB_DEFAULT_MEM_LIMIT 65536
 
 /*
  * We default to dicing tty buffer allocations to this many characters
@@ -89,9 +88,10 @@ void tty_buffer_unlock_exclusive(struct tty_port *port)
 
 int tty_buffer_space_avail(struct tty_port *port)
 {
-       int space = TTYB_MEM_LIMIT - atomic_read(&port->buf.memory_used);
+       int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used);
        return max(space, 0);
 }
+EXPORT_SYMBOL_GPL(tty_buffer_space_avail);
 
 static void tty_buffer_reset(struct tty_buffer *p, size_t size)
 {
@@ -100,6 +100,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size)
        p->next = NULL;
        p->commit = 0;
        p->read = 0;
+       p->flags = 0;
 }
 
 /**
@@ -129,7 +130,7 @@ void tty_buffer_free_all(struct tty_port *port)
        buf->head = &buf->sentinel;
        buf->tail = &buf->sentinel;
 
-       atomic_set(&buf->memory_used, 0);
+       atomic_set(&buf->mem_used, 0);
 }
 
 /**
@@ -162,7 +163,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
 
        /* Should possibly check if this fails for the largest buffer we
           have queued and recycle that ? */
-       if (atomic_read(&port->buf.memory_used) > TTYB_MEM_LIMIT)
+       if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit)
                return NULL;
        p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
        if (p == NULL)
@@ -170,7 +171,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
 
 found:
        tty_buffer_reset(p, size);
-       atomic_add(size, &port->buf.memory_used);
+       atomic_add(size, &port->buf.mem_used);
        return p;
 }
 
@@ -188,7 +189,7 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
        struct tty_bufhead *buf = &port->buf;
 
        /* Dumb strategy for now - should keep some stats */
-       WARN_ON(atomic_sub_return(b->size, &buf->memory_used) < 0);
+       WARN_ON(atomic_sub_return(b->size, &buf->mem_used) < 0);
 
        if (b->size > MIN_TTYB_SIZE)
                kfree(b);
@@ -200,9 +201,7 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
  *     tty_buffer_flush                -       flush full tty buffers
  *     @tty: tty to flush
  *
- *     flush all the buffers containing receive data. If the buffer is
- *     being processed by flush_to_ldisc then we defer the processing
- *     to that function
+ *     flush all the buffers containing receive data.
  *
  *     Locking: takes buffer lock to ensure single-threaded flip buffer
  *              'consumer'
@@ -230,31 +229,49 @@ void tty_buffer_flush(struct tty_struct *tty)
  *     tty_buffer_request_room         -       grow tty buffer if needed
  *     @tty: tty structure
  *     @size: size desired
+ *     @flags: buffer flags if new buffer allocated (default = 0)
  *
  *     Make at least size bytes of linear space available for the tty
  *     buffer. If we fail return the size we managed to find.
+ *
+ *     Will change over to a new buffer if the current buffer is encoded as
+ *     TTY_NORMAL (so has no flags buffer) and the new buffer requires
+ *     a flags buffer.
  */
-int tty_buffer_request_room(struct tty_port *port, size_t size)
+static int __tty_buffer_request_room(struct tty_port *port, size_t size,
+                                    int flags)
 {
        struct tty_bufhead *buf = &port->buf;
        struct tty_buffer *b, *n;
-       int left;
+       int left, change;
 
        b = buf->tail;
-       left = b->size - b->used;
+       if (b->flags & TTYB_NORMAL)
+               left = 2 * b->size - b->used;
+       else
+               left = b->size - b->used;
 
-       if (left < size) {
+       change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL);
+       if (change || left < size) {
                /* This is the slow path - looking for new buffers to use */
                if ((n = tty_buffer_alloc(port, size)) != NULL) {
+                       n->flags = flags;
                        buf->tail = n;
                        b->commit = b->used;
                        smp_mb();
                        b->next = n;
-               } else
+               } else if (change)
+                       size = 0;
+               else
                        size = left;
        }
        return size;
 }
+
+int tty_buffer_request_room(struct tty_port *port, size_t size)
+{
+       return __tty_buffer_request_room(port, size, 0);
+}
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 
 /**
@@ -274,12 +291,14 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,
        int copied = 0;
        do {
                int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-               int space = tty_buffer_request_room(port, goal);
+               int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
+               int space = __tty_buffer_request_room(port, goal, flags);
                struct tty_buffer *tb = port->buf.tail;
                if (unlikely(space == 0))
                        break;
                memcpy(char_buf_ptr(tb, tb->used), chars, space);
-               memset(flag_buf_ptr(tb, tb->used), flag, space);
+               if (~tb->flags & TTYB_NORMAL)
+                       memset(flag_buf_ptr(tb, tb->used), flag, space);
                tb->used += space;
                copied += space;
                chars += space;
@@ -362,52 +381,28 @@ EXPORT_SYMBOL(tty_schedule_flip);
 int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
                size_t size)
 {
-       int space = tty_buffer_request_room(port, size);
+       int space = __tty_buffer_request_room(port, size, TTYB_NORMAL);
        if (likely(space)) {
                struct tty_buffer *tb = port->buf.tail;
                *chars = char_buf_ptr(tb, tb->used);
-               memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
+               if (~tb->flags & TTYB_NORMAL)
+                       memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
                tb->used += space;
        }
        return space;
 }
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
 
-/**
- *     tty_prepare_flip_string_flags   -       make room for characters
- *     @port: tty port
- *     @chars: return pointer for character write area
- *     @flags: return pointer for status flag write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- */
-
-int tty_prepare_flip_string_flags(struct tty_port *port,
-                       unsigned char **chars, char **flags, size_t size)
-{
-       int space = tty_buffer_request_room(port, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = port->buf.tail;
-               *chars = char_buf_ptr(tb, tb->used);
-               *flags = flag_buf_ptr(tb, tb->used);
-               tb->used += space;
-       }
-       return space;
-}
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-
 
 static int
 receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
 {
        struct tty_ldisc *disc = tty->ldisc;
        unsigned char *p = char_buf_ptr(head, head->read);
-       char          *f = flag_buf_ptr(head, head->read);
+       char          *f = NULL;
+
+       if (~head->flags & TTYB_NORMAL)
+               f = flag_buf_ptr(head, head->read);
 
        if (disc->ops->receive_buf2)
                count = disc->ops->receive_buf2(tty, p, f, count);
@@ -533,7 +528,25 @@ void tty_buffer_init(struct tty_port *port)
        buf->head = &buf->sentinel;
        buf->tail = &buf->sentinel;
        init_llist_head(&buf->free);
-       atomic_set(&buf->memory_used, 0);
+       atomic_set(&buf->mem_used, 0);
        atomic_set(&buf->priority, 0);
        INIT_WORK(&buf->work, flush_to_ldisc);
+       buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT;
+}
+
+/**
+ *     tty_buffer_set_limit    -       change the tty buffer memory limit
+ *     @port: tty port to change
+ *
+ *     Change the tty buffer memory limit.
+ *     Must be called before the other tty buffer functions are used.
+ */
+
+int tty_buffer_set_limit(struct tty_port *port, int limit)
+{
+       if (limit < MIN_TTYB_SIZE)
+               return -EINVAL;
+       port->buf.mem_limit = limit;
+       return 0;
 }
+EXPORT_SYMBOL_GPL(tty_buffer_set_limit);
index 6458e11e8e9d656daef35b0a5aaddc21dcfd1804..2d822aa259b2f73ad93212c949e900701d776f04 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/wait.h>
index c94d2349dd0620dd183645ee37ddced4551e9ccd..3f746c8eb0dd410f36f48c29de2f4835f801c05b 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
index 8e68a64bfe00b8f151300cc240acedb3820d37dd..e1688802964f3ccb6aebc0738a98f9b838a6d02d 100644 (file)
@@ -286,9 +286,11 @@ void __init parse_early_options(char *cmdline);
 #define arch_initcall(fn)              module_init(fn)
 #define subsys_initcall(fn)            module_init(fn)
 #define fs_initcall(fn)                        module_init(fn)
+#define rootfs_initcall(fn)            module_init(fn)
 #define device_initcall(fn)            module_init(fn)
 #define late_initcall(fn)              module_init(fn)
 
+#define console_initcall(fn)           module_init(fn)
 #define security_initcall(fn)          module_init(fn)
 
 /* Each module must use one module_init(). */
index 97d660ed70c1901407dac9ea49bd1036840e649c..978d0f09d039b5e82c7190263856bc9b003885ad 100644 (file)
@@ -39,10 +39,14 @@ struct tty_buffer {
        int size;
        int commit;
        int read;
+       int flags;
        /* Data points here */
        unsigned long data[0];
 };
 
+/* Values for .flags field of tty_buffer */
+#define TTYB_NORMAL    1       /* buffer has no flags buffer */
+
 static inline unsigned char *char_buf_ptr(struct tty_buffer *b, int ofs)
 {
        return ((unsigned char *)b->data) + ofs;
@@ -60,7 +64,8 @@ struct tty_bufhead {
        atomic_t           priority;
        struct tty_buffer sentinel;
        struct llist_head free;         /* Free queue head */
-       atomic_t           memory_used; /* In-use buffers excluding free list */
+       atomic_t           mem_used;    /* In-use buffers excluding free list */
+       int                mem_limit;
        struct tty_buffer *tail;        /* Active buffer */
 };
 /*
@@ -422,7 +427,6 @@ extern int is_ignored(int sig);
 extern int tty_signal(int sig, struct tty_struct *tty);
 extern void tty_hangup(struct tty_struct *tty);
 extern void tty_vhangup(struct tty_struct *tty);
-extern void tty_vhangup_locked(struct tty_struct *tty);
 extern void tty_unhangup(struct file *filp);
 extern int tty_hung_up_p(struct file *filp);
 extern void do_SAK(struct tty_struct *tty);
index 21ddd7d9ea1fe0303e5910b7de3019b9851e8bda..c28dd523f96e655fcd89dd4bcb4ab200255cbb54 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _LINUX_TTY_FLIP_H
 #define _LINUX_TTY_FLIP_H
 
+extern int tty_buffer_set_limit(struct tty_port *port, int limit);
 extern int tty_buffer_space_avail(struct tty_port *port);
 extern int tty_buffer_request_room(struct tty_port *port, size_t size);
 extern int tty_insert_flip_string_flags(struct tty_port *port,
@@ -9,8 +10,6 @@ extern int tty_insert_flip_string_fixed_flag(struct tty_port *port,
                const unsigned char *chars, char flag, size_t size);
 extern int tty_prepare_flip_string(struct tty_port *port,
                unsigned char **chars, size_t size);
-extern int tty_prepare_flip_string_flags(struct tty_port *port,
-               unsigned char **chars, char **flags, size_t size);
 extern void tty_flip_buffer_push(struct tty_port *port);
 void tty_schedule_flip(struct tty_port *port);
 
@@ -18,8 +17,12 @@ static inline int tty_insert_flip_char(struct tty_port *port,
                                        unsigned char ch, char flag)
 {
        struct tty_buffer *tb = port->buf.tail;
-       if (tb && tb->used < tb->size) {
-               *flag_buf_ptr(tb, tb->used) = flag;
+       int change;
+
+       change = (tb->flags & TTYB_NORMAL) && (flag != TTY_NORMAL);
+       if (!change && tb->used < tb->size) {
+               if (~tb->flags & TTYB_NORMAL)
+                       *flag_buf_ptr(tb, tb->used) = flag;
                *char_buf_ptr(tb, tb->used++) = ch;
                return 1;
        }
index f15c898ff462006fb0bec91d5922ecbf24267d8c..b8347c207cb845d940ed163cb89776e0bacaf252 100644 (file)
@@ -84,7 +84,8 @@
  *     processing.  <cp> is a pointer to the buffer of input
  *     character received by the device.  <fp> is a pointer to a
  *     pointer of flag bytes which indicate whether a character was
- *     received with a parity error, etc.
+ *     received with a parity error, etc. <fp> may be NULL to indicate
+ *     all data received is TTY_NORMAL.
  *
  * void        (*write_wakeup)(struct tty_struct *);
  *
  *     processing.  <cp> is a pointer to the buffer of input
  *     character received by the device.  <fp> is a pointer to a
  *     pointer of flag bytes which indicate whether a character was
- *     received with a parity error, etc.
+ *     received with a parity error, etc. <fp> may be NULL to indicate
+ *     all data received is TTY_NORMAL.
  *     If assigned, prefer this function for automatic flow control.
  */