Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Jan 2012 20:09:24 +0000 (12:09 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Jan 2012 20:09:24 +0000 (12:09 -0800)
* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (65 commits)
  tty: serial: imx: move del_timer_sync() to avoid potential deadlock
  imx: add polled io uart methods
  imx: Add save/restore functions for UART control regs
  serial/imx: let probing fail for the dt case without a valid alias
  serial/imx: propagate error from of_alias_get_id instead of using -ENODEV
  tty: serial: imx: Allow UART to be a source for wakeup
  serial: driver for m32 arch should not have DEC alpha errata
  serial/documentation: fix documented name of DCD cpp symbol
  atmel_serial: fix spinlock lockup in RS485 code
  tty: Fix memory leak in virtual console when enable unicode translation
  serial: use DIV_ROUND_CLOSEST instead of open coding it
  serial: add support for 400 and 800 v3 series Titan cards
  serial: bfin-uart: Remove ASYNC_CTS_FLOW flag for hardware automatic CTS.
  serial: bfin-uart: Enable hardware automatic CTS only when CTS pin is available.
  serial: make FSL errata depend on 8250_CONSOLE, not just 8250
  serial: add irq handler for Freescale 16550 errata.
  serial: manually inline serial8250_handle_port
  serial: make 8250 timeout use the specified IRQ handler
  serial: export the key functions for an 8250 IRQ handler
  serial: clean up parameter passing for 8250 Rx IRQ handling
  ...

45 files changed:
Documentation/serial/driver
arch/powerpc/kernel/legacy_serial.c
arch/x86/include/asm/mrst.h
arch/x86/kernel/early_printk.c
arch/x86/platform/mrst/early_printk_mrst.c
drivers/parport/parport_ax88796.c
drivers/parport/parport_sunbpp.c
drivers/tty/n_hdlc.c
drivers/tty/n_tty.c
drivers/tty/pty.c
drivers/tty/serial/8250.c
drivers/tty/serial/8250.h
drivers/tty/serial/8250_dw.c
drivers/tty/serial/8250_fsl.c [new file with mode: 0644]
drivers/tty/serial/8250_pci.c
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/bfin_sport_uart.c
drivers/tty/serial/bfin_sport_uart.h
drivers/tty/serial/bfin_uart.c
drivers/tty/serial/ifx6x60.c
drivers/tty/serial/imx.c
drivers/tty/serial/m32r_sio.c
drivers/tty/serial/max3100.c
drivers/tty/serial/max3107-aava.c
drivers/tty/serial/max3107.c
drivers/tty/serial/mfd.c
drivers/tty/serial/mrst_max3110.c
drivers/tty/serial/msm_serial_hs.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/sc26xx.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/serial_cs.c
drivers/tty/serial/sirfsoc_uart.c [new file with mode: 0644]
drivers/tty/serial/sirfsoc_uart.h [new file with mode: 0644]
drivers/tty/serial/timbuart.c
drivers/tty/serial/vr41xx_siu.c
drivers/tty/tty_io.c
drivers/tty/tty_ldisc.c
drivers/tty/vt/consolemap.c
include/linux/serial_8250.h
include/linux/serial_core.h

index 77ba0afbe4db2c227650441af43ab3c57f2e5a6f..0a25a919186407a013f61dd97e282367bab5e77d 100644 (file)
@@ -101,7 +101,7 @@ hardware.
        Returns the current state of modem control inputs.  The state
        of the outputs should not be returned, since the core keeps
        track of their state.  The state information should include:
-               - TIOCM_DCD     state of DCD signal
+               - TIOCM_CAR     state of DCD signal
                - TIOCM_CTS     state of CTS signal
                - TIOCM_DSR     state of DSR signal
                - TIOCM_RI      state of RI signal
index c7b5afeecaf281132e80a0b218dab62a53a7b9ea..3fea3689527e963955f802ac7abf2a8471ddfd24 100644 (file)
@@ -441,6 +441,9 @@ static void __init fixup_port_irq(int index,
                return;
 
        port->irq = virq;
+
+       if (of_device_is_compatible(np, "fsl,ns16550"))
+               port->handle_irq = fsl8250_handle_irq;
 }
 
 static void __init fixup_port_pio(int index,
index 93f79094c2243211eede22db91acdf33098a059a..0a0a95460434af8ba2a791e0aec859ec49c8be46 100644 (file)
@@ -67,7 +67,7 @@ extern struct console early_mrst_console;
 extern void mrst_early_console_init(void);
 
 extern struct console early_hsu_console;
-extern void hsu_early_console_init(void);
+extern void hsu_early_console_init(const char *);
 
 extern void intel_scu_devices_create(void);
 extern void intel_scu_devices_destroy(void);
index cd28a350f7f933162a6fa9bd0de08c64e22495f2..9d42a52d233150c40a1652c574212e67c0a68708 100644 (file)
@@ -247,7 +247,7 @@ static int __init setup_early_printk(char *buf)
                }
 
                if (!strncmp(buf, "hsu", 3)) {
-                       hsu_early_console_init();
+                       hsu_early_console_init(buf + 3);
                        early_console_register(&early_hsu_console, keep);
                }
 #endif
index 25bfdbb5b1302937ce93343bcbd20372c6064b1a..3c6e328483c7dddd2e91011eec806b78b798d542 100644 (file)
@@ -245,16 +245,24 @@ struct console early_mrst_console = {
  * Following is the early console based on Medfield HSU (High
  * Speed UART) device.
  */
-#define HSU_PORT2_PADDR                0xffa28180
+#define HSU_PORT_BASE          0xffa28080
 
 static void __iomem *phsu;
 
-void hsu_early_console_init(void)
+void hsu_early_console_init(const char *s)
 {
+       unsigned long paddr, port = 0;
        u8 lcr;
 
-       phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
-                                                       HSU_PORT2_PADDR);
+       /*
+        * Select the early HSU console port if specified by user in the
+        * kernel command line.
+        */
+       if (*s && !kstrtoul(s, 10, &port))
+               port = clamp_val(port, 0, 2);
+
+       paddr = HSU_PORT_BASE + port * 0x80;
+       phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE, paddr);
 
        /* Disable FIFO */
        writeb(0x0, phsu + UART_FCR);
index 844f6137970ae1e9247e3ccf9dc5b1a373097896..7c5d86696eed92c274642ef68c3eeb1fc569cf98 100644 (file)
@@ -420,18 +420,7 @@ static struct platform_driver axdrv = {
        .resume         = parport_ax88796_resume,
 };
 
-static int __init parport_ax88796_init(void)
-{
-       return platform_driver_register(&axdrv);
-}
-
-static void __exit parport_ax88796_exit(void)
-{
-       platform_driver_unregister(&axdrv);
-}
-
-module_init(parport_ax88796_init)
-module_exit(parport_ax88796_exit)
+module_platform_driver(axdrv);
 
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("AX88796 Parport parallel port driver");
index 910c5a26e3470191bd7f0111ea2eeb65e43c459e..9390a534a2b27be95b39e4fd3555d7c371ad93b4 100644 (file)
@@ -391,21 +391,10 @@ static struct platform_driver bpp_sbus_driver = {
        .remove         = __devexit_p(bpp_remove),
 };
 
-static int __init parport_sunbpp_init(void)
-{
-       return platform_driver_register(&bpp_sbus_driver);
-}
-
-static void __exit parport_sunbpp_exit(void)
-{
-       platform_driver_unregister(&bpp_sbus_driver);
-}
+module_platform_driver(bpp_sbus_driver);
 
 MODULE_AUTHOR("Derrick J Brashear");
 MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
 MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
 MODULE_VERSION("2.0");
 MODULE_LICENSE("GPL");
-
-module_init(parport_sunbpp_init)
-module_exit(parport_sunbpp_exit)
index cea56033b34c2b490e796ae75df0fbea4e550a3f..a09ce3ef5d748f9455ebba56b38aa97f097e8187 100644 (file)
@@ -417,7 +417,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
                                __FILE__,__LINE__,tbuf,tbuf->count);
                        
                /* Send the next block of data to device */
-               tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
                actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
 
                /* rollback was possible and has been done */
@@ -459,7 +459,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
        }
        
        if (!tbuf)
-               tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
+               clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
        
        /* Clear the re-entry flag */
        spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
@@ -491,7 +491,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
                return;
 
        if (tty != n_hdlc->tty) {
-               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+               clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
                return;
        }
 
index 39d6ab6551e0884db2237f6ffeba184de92f4c22..d2256d08ee7e11995a0e5e5067d5a4c1b73b4de7 100644 (file)
@@ -61,7 +61,7 @@
  * controlling the space in the read buffer.
  */
 #define TTY_THRESHOLD_THROTTLE         128 /* now based on remaining room */
-#define TTY_THRESHOLD_UNTHROTTLE       128
+#define TTY_THRESHOLD_UNTHROTTLE       128
 
 /*
  * Special byte codes used in the echo buffer to represent operations
@@ -405,7 +405,7 @@ static ssize_t process_output_block(struct tty_struct *tty,
                                    const unsigned char *buf, unsigned int nr)
 {
        int     space;
-       int     i;
+       int     i;
        const unsigned char *cp;
 
        mutex_lock(&tty->output_lock);
@@ -1607,7 +1607,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
 }
 
 /**
- *     copy_from_read_buf      -       copy read data directly
+ *     copy_from_read_buf      -       copy read data directly
  *     @tty: terminal device
  *     @b: user data
  *     @nr: size of data
@@ -1909,7 +1909,7 @@ do_it_again:
                if (nr)
                        clear_bit(TTY_PUSH, &tty->flags);
        } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
-                goto do_it_again;
+               goto do_it_again;
 
        n_tty_set_room(tty);
        return retval;
index e18604b3fc7d6c00f13bb05079f48554dca143aa..d8653ab6f4988cf0402bbf3a527cb00a0865c6b5 100644 (file)
@@ -446,19 +446,8 @@ static inline void legacy_pty_init(void) { }
 int pty_limit = NR_UNIX98_PTY_DEFAULT;
 static int pty_limit_min;
 static int pty_limit_max = NR_UNIX98_PTY_MAX;
-static int tty_count;
 static int pty_count;
 
-static inline void pty_inc_count(void)
-{
-       pty_count = (++tty_count) / 2;
-}
-
-static inline void pty_dec_count(void)
-{
-       pty_count = (--tty_count) / 2;
-}
-
 static struct cdev ptmx_cdev;
 
 static struct ctl_table pty_table[] = {
@@ -600,8 +589,7 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
         */
        tty_driver_kref_get(driver);
        tty->count++;
-       pty_inc_count(); /* tty */
-       pty_inc_count(); /* tty->link */
+       pty_count++;
        return 0;
 err_free_mem:
        deinitialize_tty_struct(o_tty);
@@ -613,15 +601,19 @@ err_free_tty:
        return -ENOMEM;
 }
 
-static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+       pty_count--;
+}
+
+static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
 {
-       pty_dec_count();
 }
 
 static const struct tty_operations ptm_unix98_ops = {
        .lookup = ptm_unix98_lookup,
        .install = pty_unix98_install,
-       .remove = pty_unix98_remove,
+       .remove = ptm_unix98_remove,
        .open = pty_open,
        .close = pty_close,
        .write = pty_write,
@@ -638,7 +630,7 @@ static const struct tty_operations ptm_unix98_ops = {
 static const struct tty_operations pty_unix98_ops = {
        .lookup = pts_unix98_lookup,
        .install = pty_unix98_install,
-       .remove = pty_unix98_remove,
+       .remove = pts_unix98_remove,
        .open = pty_open,
        .close = pty_close,
        .write = pty_write,
index eeadf1b8e093202234b30c688490da2de10a3c04..9f50c4e3c2bea409cf85fb4779475bbad6f7f0c0 100644 (file)
@@ -129,32 +129,6 @@ static unsigned long probe_rsa[PORT_RSA_MAX];
 static unsigned int probe_rsa_count;
 #endif /* CONFIG_SERIAL_8250_RSA  */
 
-struct uart_8250_port {
-       struct uart_port        port;
-       struct timer_list       timer;          /* "no irq" timer */
-       struct list_head        list;           /* ports on this IRQ */
-       unsigned short          capabilities;   /* port capabilities */
-       unsigned short          bugs;           /* port bugs */
-       unsigned int            tx_loadsz;      /* transmit fifo load size */
-       unsigned char           acr;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr;
-       unsigned char           mcr_mask;       /* mask of user bits */
-       unsigned char           mcr_force;      /* mask of forced bits */
-       unsigned char           cur_iotype;     /* Running I/O type */
-
-       /*
-        * Some bits in registers are cleared on a read, so they must
-        * be saved whenever the register is read but the bits will not
-        * be immediately processed.
-        */
-#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
-       unsigned char           lsr_saved_flags;
-#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
-       unsigned char           msr_saved_flags;
-};
-
 struct irq_info {
        struct                  hlist_node node;
        int                     irq;
@@ -1326,8 +1300,6 @@ static void serial8250_stop_tx(struct uart_port *port)
        }
 }
 
-static void transmit_chars(struct uart_8250_port *up);
-
 static void serial8250_start_tx(struct uart_port *port)
 {
        struct uart_8250_port *up =
@@ -1344,7 +1316,7 @@ static void serial8250_start_tx(struct uart_port *port)
                        if ((up->port.type == PORT_RM9000) ?
                                (lsr & UART_LSR_THRE) :
                                (lsr & UART_LSR_TEMT))
-                               transmit_chars(up);
+                               serial8250_tx_chars(up);
                }
        }
 
@@ -1401,11 +1373,16 @@ static void clear_rx_fifo(struct uart_8250_port *up)
        } while (1);
 }
 
-static void
-receive_chars(struct uart_8250_port *up, unsigned int *status)
+/*
+ * serial8250_rx_chars: processes according to the passed in LSR
+ * value, and returns the remaining LSR bits not handled
+ * by this Rx routine.
+ */
+unsigned char
+serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
 {
        struct tty_struct *tty = up->port.state->port.tty;
-       unsigned char ch, lsr = *status;
+       unsigned char ch;
        int max_count = 256;
        char flag;
 
@@ -1481,10 +1458,11 @@ ignore_char:
        spin_unlock(&up->port.lock);
        tty_flip_buffer_push(tty);
        spin_lock(&up->port.lock);
-       *status = lsr;
+       return lsr;
 }
+EXPORT_SYMBOL_GPL(serial8250_rx_chars);
 
-static void transmit_chars(struct uart_8250_port *up)
+void serial8250_tx_chars(struct uart_8250_port *up)
 {
        struct circ_buf *xmit = &up->port.state->xmit;
        int count;
@@ -1521,8 +1499,9 @@ static void transmit_chars(struct uart_8250_port *up)
        if (uart_circ_empty(xmit))
                __stop_tx(up);
 }
+EXPORT_SYMBOL_GPL(serial8250_tx_chars);
 
-static unsigned int check_modem_status(struct uart_8250_port *up)
+unsigned int serial8250_modem_status(struct uart_8250_port *up)
 {
        unsigned int status = serial_in(up, UART_MSR);
 
@@ -1544,14 +1523,20 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
 
        return status;
 }
+EXPORT_SYMBOL_GPL(serial8250_modem_status);
 
 /*
  * This handles the interrupt from one port.
  */
-static void serial8250_handle_port(struct uart_8250_port *up)
+int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
 {
-       unsigned int status;
+       unsigned char status;
        unsigned long flags;
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       if (iir & UART_IIR_NO_INT)
+               return 0;
 
        spin_lock_irqsave(&up->port.lock, flags);
 
@@ -1560,25 +1545,13 @@ static void serial8250_handle_port(struct uart_8250_port *up)
        DEBUG_INTR("status = %x...", status);
 
        if (status & (UART_LSR_DR | UART_LSR_BI))
-               receive_chars(up, &status);
-       check_modem_status(up);
+               status = serial8250_rx_chars(up, status);
+       serial8250_modem_status(up);
        if (status & UART_LSR_THRE)
-               transmit_chars(up);
+               serial8250_tx_chars(up);
 
        spin_unlock_irqrestore(&up->port.lock, flags);
-}
-
-int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
-{
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-
-       if (!(iir & UART_IIR_NO_INT)) {
-               serial8250_handle_port(up);
-               return 1;
-       }
-
-       return 0;
+       return 1;
 }
 EXPORT_SYMBOL_GPL(serial8250_handle_irq);
 
@@ -1619,11 +1592,13 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
        do {
                struct uart_8250_port *up;
                struct uart_port *port;
+               bool skip;
 
                up = list_entry(l, struct uart_8250_port, list);
                port = &up->port;
+               skip = pass_counter && up->port.flags & UPF_IIR_ONCE;
 
-               if (port->handle_irq(port)) {
+               if (!skip && port->handle_irq(port)) {
                        handled = 1;
                        end = NULL;
                } else if (end == NULL)
@@ -1758,11 +1733,8 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
 static void serial8250_timeout(unsigned long data)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)data;
-       unsigned int iir;
 
-       iir = serial_in(up, UART_IIR);
-       if (!(iir & UART_IIR_NO_INT))
-               serial8250_handle_port(up);
+       up->port.handle_irq(&up->port);
        mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
 }
 
@@ -1801,7 +1773,7 @@ static void serial8250_backup_timeout(unsigned long data)
        }
 
        if (!(iir & UART_IIR_NO_INT))
-               transmit_chars(up);
+               serial8250_tx_chars(up);
 
        if (is_real_interrupt(up->port.irq))
                serial_out(up, UART_IER, ier);
@@ -1835,7 +1807,7 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
        unsigned int status;
        unsigned int ret;
 
-       status = check_modem_status(up);
+       status = serial8250_modem_status(up);
 
        ret = 0;
        if (status & UART_MSR_DCD)
@@ -2000,7 +1972,7 @@ static int serial8250_startup(struct uart_port *port)
                serial_outp(up, UART_IER, 0);
                serial_outp(up, UART_LCR, 0);
                serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
-               serial_outp(up, UART_LCR, 0xBF);
+               serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
                serial_outp(up, UART_EFR, UART_EFR_ECB);
                serial_outp(up, UART_LCR, 0);
        }
@@ -2848,7 +2820,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
 
        local_irq_save(flags);
        if (up->port.sysrq) {
-               /* serial8250_handle_port() already took the lock */
+               /* serial8250_handle_irq() already took the lock */
                locked = 0;
        } else if (oops_in_progress) {
                locked = spin_trylock(&up->port.lock);
@@ -2882,7 +2854,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
         *      while processing with interrupts off.
         */
        if (up->msr_saved_flags)
-               check_modem_status(up);
+               serial8250_modem_status(up);
 
        if (locked)
                spin_unlock(&up->port.lock);
index 6edf4a6a22d4b538e188d5e615634d4a0a7a6edc..ae027be57e2531d54ba9a6605b1dce4c40ab6bb7 100644 (file)
 
 #include <linux/serial_8250.h>
 
+struct uart_8250_port {
+       struct uart_port        port;
+       struct timer_list       timer;          /* "no irq" timer */
+       struct list_head        list;           /* ports on this IRQ */
+       unsigned short          capabilities;   /* port capabilities */
+       unsigned short          bugs;           /* port bugs */
+       unsigned int            tx_loadsz;      /* transmit fifo load size */
+       unsigned char           acr;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned char           mcr_mask;       /* mask of user bits */
+       unsigned char           mcr_force;      /* mask of forced bits */
+       unsigned char           cur_iotype;     /* Running I/O type */
+
+       /*
+        * Some bits in registers are cleared on a read, so they must
+        * be saved whenever the register is read but the bits will not
+        * be immediately processed.
+        */
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
+       unsigned char           lsr_saved_flags;
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+       unsigned char           msr_saved_flags;
+};
+
 struct old_serial_port {
        unsigned int uart;
        unsigned int baud_base;
index bf1fba640c2d531b2772c8b71ed8183a3a84598a..f574eef3075f987b41784c635400f970947e9480 100644 (file)
@@ -177,17 +177,7 @@ static struct platform_driver dw8250_platform_driver = {
        .remove                 = __devexit_p(dw8250_remove),
 };
 
-static int __init dw8250_init(void)
-{
-       return platform_driver_register(&dw8250_platform_driver);
-}
-module_init(dw8250_init);
-
-static void __exit dw8250_exit(void)
-{
-       platform_driver_unregister(&dw8250_platform_driver);
-}
-module_exit(dw8250_exit);
+module_platform_driver(dw8250_platform_driver);
 
 MODULE_AUTHOR("Jamie Iles");
 MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250_fsl.c b/drivers/tty/serial/8250_fsl.c
new file mode 100644 (file)
index 0000000..f4d3c47
--- /dev/null
@@ -0,0 +1,63 @@
+#include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
+
+#include "8250.h"
+
+/*
+ * Freescale 16550 UART "driver", Copyright (C) 2011 Paul Gortmaker.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This isn't a full driver; it just provides an alternate IRQ
+ * handler to deal with an errata.  Everything else is just
+ * using the bog standard 8250 support.
+ *
+ * We follow code flow of serial8250_default_handle_irq() but add
+ * a check for a break and insert a dummy read on the Rx for the
+ * immediately following IRQ event.
+ *
+ * We re-use the already existing "bug handling" lsr_saved_flags
+ * field to carry the "what we just did" information from the one
+ * IRQ event to the next one.
+ */
+
+int fsl8250_handle_irq(struct uart_port *port)
+{
+       unsigned char lsr, orig_lsr;
+       unsigned long flags;
+       unsigned int iir;
+       struct uart_8250_port *up =
+               container_of(port, struct uart_8250_port, port);
+
+       spin_lock_irqsave(&up->port.lock, flags);
+
+       iir = port->serial_in(port, UART_IIR);
+       if (iir & UART_IIR_NO_INT) {
+               spin_unlock_irqrestore(&up->port.lock, flags);
+               return 0;
+       }
+
+       /* This is the WAR; if last event was BRK, then read and return */
+       if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) {
+               up->lsr_saved_flags &= ~UART_LSR_BI;
+               port->serial_in(port, UART_RX);
+               spin_unlock_irqrestore(&up->port.lock, flags);
+               return 1;
+       }
+
+       lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
+
+       if (lsr & (UART_LSR_DR | UART_LSR_BI))
+               lsr = serial8250_rx_chars(up, lsr);
+
+       serial8250_modem_status(up);
+
+       if (lsr & UART_LSR_THRE)
+               serial8250_tx_chars(up);
+
+       up->lsr_saved_flags = orig_lsr;
+       spin_unlock_irqrestore(&up->port.lock, flags);
+       return 1;
+}
index 825937a5f21098857eb802a4303d46b9aac29909..da2b0b0a183fff27805e6c5509c655c88648353d 100644 (file)
@@ -1092,6 +1092,14 @@ static int skip_tx_en_setup(struct serial_private *priv,
        return pci_default_setup(priv, board, port, idx);
 }
 
+static int kt_serial_setup(struct serial_private *priv,
+                          const struct pciserial_board *board,
+                          struct uart_port *port, int idx)
+{
+       port->flags |= UPF_IIR_ONCE;
+       return skip_tx_en_setup(priv, board, port, idx);
+}
+
 static int pci_eg20t_init(struct pci_dev *dev)
 {
 #if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE)
@@ -1110,7 +1118,18 @@ pci_xr17c154_setup(struct serial_private *priv,
        return pci_default_setup(priv, board, port, idx);
 }
 
-/* This should be in linux/pci_ids.h */
+static int try_enable_msi(struct pci_dev *dev)
+{
+       /* use msi if available, but fallback to legacy otherwise */
+       pci_enable_msi(dev);
+       return 0;
+}
+
+static void disable_msi(struct pci_dev *dev)
+{
+       pci_disable_msi(dev);
+}
+
 #define PCI_VENDOR_ID_SBSMODULARIO     0x124B
 #define PCI_SUBVENDOR_ID_SBSMODULARIO  0x124B
 #define PCI_DEVICE_ID_OCTPRO           0x0001
@@ -1133,9 +1152,14 @@ pci_xr17c154_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_400V3      0xA310
+#define PCI_DEVICE_ID_TITAN_410V3      0xA312
+#define PCI_DEVICE_ID_TITAN_800V3      0xA314
+#define PCI_DEVICE_ID_TITAN_800V3B     0xA315
 #define PCI_DEVICE_ID_OXSEMI_16PCI958  0x9538
 #define PCIE_DEVICE_ID_NEO_2_OX_IBM    0x00F6
 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
+#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
 
 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584        0x1584
@@ -1220,6 +1244,15 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = ce4100_serial_setup,
        },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_PATSBURG_KT,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .init           = try_enable_msi,
+               .setup          = kt_serial_setup,
+               .exit           = disable_msi,
+       },
        /*
         * ITE
         */
@@ -3414,6 +3447,18 @@ 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_400V3,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_410V3,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_b0_4_921600 },
 
        {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
index 95b21a6199002afa9697430a7e40d2f050df1a17..113fccf825170a6321b8b9ceb0ceb223063f7d01 100644 (file)
@@ -97,6 +97,11 @@ config SERIAL_8250_PNP
          This builds standard PNP serial support. You may be able to
          disable this feature if you only need legacy serial support.
 
+config SERIAL_8250_FSL
+       bool
+       depends on SERIAL_8250_CONSOLE && PPC_UDBG_16550
+       default PPC
+
 config SERIAL_8250_HP300
        tristate
        depends on SERIAL_8250 && HP300
@@ -535,6 +540,27 @@ config SERIAL_S5PV210
        help
          Serial port support for Samsung's S5P Family of SoC's
 
+config SERIAL_SIRFSOC
+        tristate "SiRF SoC Platform Serial port support"
+        depends on ARM && ARCH_PRIMA2
+        select SERIAL_CORE
+        help
+          Support for the on-chip UART on the CSR SiRFprimaII series,
+          providing /dev/ttySiRF0, 1 and 2 (note, some machines may not
+          provide all of these ports, depending on how the serial port
+          pins are configured).
+
+config SERIAL_SIRFSOC_CONSOLE
+        bool "Support for console on SiRF SoC serial port"
+        depends on SERIAL_SIRFSOC=y
+        select SERIAL_CORE_CONSOLE
+        help
+          Even if you say Y here, the currently visible virtual console
+          (/dev/tty0) will still be used as the system console by default, but
+          you can alter that using a kernel command line option such as
+          "console=ttySiRFx". (Try "man bootparam" or see the documentation of
+          your boot loader about how to pass options to the kernel at
+          boot time.)
 
 config SERIAL_MAX3100
        tristate "MAX3100 support"
@@ -1324,7 +1350,7 @@ config SERIAL_OF_PLATFORM
 
 config SERIAL_OMAP
        tristate "OMAP serial port support"
-       depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
+       depends on ARCH_OMAP2PLUS
        select SERIAL_CORE
        help
          If you have a machine based on an Texas Instruments OMAP CPU you
@@ -1575,6 +1601,15 @@ config SERIAL_PCH_UART
          ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
          ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
 
+config SERIAL_PCH_UART_CONSOLE
+       bool "Support for console on Intel EG20T PCH UART/OKI SEMICONDUCTOR ML7213 IOH"
+       depends on SERIAL_PCH_UART=y
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you wish to use the PCH UART as the system console
+         (the system  console is the device which receives all kernel messages and
+         warnings and which allows logins in single user mode).
+
 config SERIAL_MSM_SMD
        bool "Enable tty device interface for some SMD ports"
        default n
index e10cf5b54b6dbc70109b29c447bbe5668048a0d2..75eadb8d717822de777c8292f22b89be10216f96 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
 obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
 obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
 obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
+obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
 obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
 obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
 obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
@@ -94,3 +95,4 @@ obj-$(CONFIG_SERIAL_MSM_SMD)  += msm_smd_tty.o
 obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
 obj-$(CONFIG_SERIAL_LANTIQ)    += lantiq.o
 obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
+obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
index 4c823f341d9895cd88a5f0d710f56449714fef86..10605ecc99abd4a3663ef020462877356a5a9921 100644 (file)
@@ -212,8 +212,9 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
 {
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
        unsigned int mode;
+       unsigned long flags;
 
-       spin_lock(&port->lock);
+       spin_lock_irqsave(&port->lock, flags);
 
        /* Disable interrupts */
        UART_PUT_IDR(port, atmel_port->tx_done_mask);
@@ -244,7 +245,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
        /* Enable interrupts */
        UART_PUT_IER(port, atmel_port->tx_done_mask);
 
-       spin_unlock(&port->lock);
+       spin_unlock_irqrestore(&port->lock, flags);
 
 }
 
@@ -1256,12 +1257,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
 
 static void atmel_set_ldisc(struct uart_port *port, int new)
 {
-       int line = port->line;
-
-       if (line >= port->state->port.tty->driver->num)
-               return;
-
-       if (port->state->port.tty->ldisc->ops->num == N_PPS) {
+       if (new == N_PPS) {
                port->flags |= UPF_HARDPPS_CD;
                atmel_enable_ms(port);
        } else {
index ee101c0d358f70f23c480adf251781d42201be89..7fbc3a08f10d7f7c16a6b79e833140ce33235f10 100644 (file)
@@ -299,8 +299,13 @@ static int sport_startup(struct uart_port *port)
                        dev_info(port->dev, "Unable to attach BlackFin UART over SPORT CTS interrupt. So, disable it.\n");
                }
        }
-       if (up->rts_pin >= 0)
-               gpio_direction_output(up->rts_pin, 0);
+       if (up->rts_pin >= 0) {
+               if (gpio_request(up->rts_pin, DRV_NAME)) {
+                       dev_info(port->dev, "fail to request RTS PIN at GPIO_%d\n", up->rts_pin);
+                       up->rts_pin = -1;
+               } else
+                       gpio_direction_output(up->rts_pin, 0);
+       }
 #endif
 
        return 0;
@@ -445,6 +450,8 @@ static void sport_shutdown(struct uart_port *port)
 #ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
        if (up->cts_pin >= 0)
                free_irq(gpio_to_irq(up->cts_pin), up);
+       if (up->rts_pin >= 0)
+               gpio_free(up->rts_pin);
 #endif
 }
 
@@ -803,17 +810,16 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
                res = platform_get_resource(pdev, IORESOURCE_IO, 0);
                if (res == NULL)
                        sport->cts_pin = -1;
-               else
+               else {
                        sport->cts_pin = res->start;
+                       sport->port.flags |= ASYNC_CTS_FLOW;
+               }
 
                res = platform_get_resource(pdev, IORESOURCE_IO, 1);
                if (res == NULL)
                        sport->rts_pin = -1;
                else
                        sport->rts_pin = res->start;
-
-               if (sport->rts_pin >= 0)
-                       gpio_request(sport->rts_pin, DRV_NAME);
 #endif
        }
 
@@ -853,10 +859,6 @@ static int __devexit sport_uart_remove(struct platform_device *pdev)
 
        if (sport) {
                uart_remove_one_port(&sport_uart_reg, &sport->port);
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-               if (sport->rts_pin >= 0)
-                       gpio_free(sport->rts_pin);
-#endif
                iounmap(sport->port.membase);
                peripheral_free_list(
                        (unsigned short *)pdev->dev.platform_data);
index 6d06ce1d5675ce12dbe8e9d9d682f3fbff4a595f..e4510ea135ceb1dc1b6a85d02320cfede400c57d 100644 (file)
 #define SPORT_GET_RX32(sport) \
 ({ \
        unsigned int __ret; \
+       unsigned long flags; \
        if (ANOMALY_05000473) \
-               local_irq_disable(); \
+               local_irq_save(flags); \
        __ret = bfin_read32((sport)->port.membase + OFFSET_RX); \
        if (ANOMALY_05000473) \
-               local_irq_enable(); \
+               local_irq_restore(flags); \
        __ret; \
 })
 #define SPORT_GET_RCR1(sport)          bfin_read16(((sport)->port.membase + OFFSET_RCR1))
index 66afb98b77b50f6d84fbeb398a231c6d62e02524..26953bfa6922f4ffbebc8da4bb7a2ac60f672695 100644 (file)
@@ -116,15 +116,22 @@ static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
 static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
 {
        struct bfin_serial_port *uart = dev_id;
-       unsigned int status;
-
-       status = bfin_serial_get_mctrl(&uart->port);
-       uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
+       unsigned int status = bfin_serial_get_mctrl(&uart->port);
 #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       uart->scts = 1;
+       struct tty_struct *tty = uart->port.state->port.tty;
+
        UART_CLEAR_SCTS(uart);
-       UART_CLEAR_IER(uart, EDSSI);
+       if (tty->hw_stopped) {
+               if (status) {
+                       tty->hw_stopped = 0;
+                       uart_write_wakeup(&uart->port);
+               }
+       } else {
+               if (!status)
+                       tty->hw_stopped = 1;
+       }
 #endif
+       uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
 
        return IRQ_HANDLED;
 }
@@ -175,13 +182,6 @@ static void bfin_serial_start_tx(struct uart_port *port)
        struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
        struct tty_struct *tty = uart->port.state->port.tty;
 
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
-               uart->scts = 0;
-               uart_handle_cts_change(&uart->port, uart->scts);
-       }
-#endif
-
        /*
         * To avoid losting RX interrupt, we reset IR function
         * before sending data.
@@ -380,12 +380,6 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
 {
        struct bfin_serial_port *uart = dev_id;
 
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port) & TIOCM_CTS)) {
-               uart->scts = 0;
-               uart_handle_cts_change(&uart->port, uart->scts);
-       }
-#endif
        spin_lock(&uart->port.lock);
        if (UART_GET_LSR(uart) & THRE)
                bfin_serial_tx_chars(uart);
@@ -531,13 +525,6 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
        struct bfin_serial_port *uart = dev_id;
        struct circ_buf *xmit = &uart->port.state->xmit;
 
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->scts && !(bfin_serial_get_mctrl(&uart->port)&TIOCM_CTS)) {
-               uart->scts = 0;
-               uart_handle_cts_change(&uart->port, uart->scts);
-       }
-#endif
-
        spin_lock(&uart->port.lock);
        if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
                disable_dma(uart->tx_dma_channel);
@@ -739,20 +726,26 @@ static int bfin_serial_startup(struct uart_port *port)
                        pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
                }
        }
-       if (uart->rts_pin >= 0)
-               gpio_direction_output(uart->rts_pin, 0);
+       if (uart->rts_pin >= 0) {
+               if (gpio_request(uart->rts_pin, DRIVER_NAME)) {
+                       pr_info("fail to request RTS PIN at GPIO_%d\n", uart->rts_pin);
+                       uart->rts_pin = -1;
+               } else
+                       gpio_direction_output(uart->rts_pin, 0);
+       }
 #endif
 #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
-               bfin_serial_mctrl_cts_int,
-               0, "BFIN_UART_MODEM_STATUS", uart)) {
-               uart->cts_pin = -1;
-               pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
-       }
+       if (uart->cts_pin >= 0) {
+               if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int,
+                       IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
+                       uart->cts_pin = -1;
+                       dev_info(port->dev, "Unable to attach BlackFin UART Modem Status interrupt.\n");
+               }
 
-       /* CTS RTS PINs are negative assertive. */
-       UART_PUT_MCR(uart, ACTS);
-       UART_SET_IER(uart, EDSSI);
+               /* CTS RTS PINs are negative assertive. */
+               UART_PUT_MCR(uart, ACTS);
+               UART_SET_IER(uart, EDSSI);
+       }
 #endif
 
        UART_SET_IER(uart, ERBFI);
@@ -792,6 +785,8 @@ static void bfin_serial_shutdown(struct uart_port *port)
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
        if (uart->cts_pin >= 0)
                free_irq(gpio_to_irq(uart->cts_pin), uart);
+       if (uart->rts_pin >= 0)
+               gpio_free(uart->rts_pin);
 #endif
 #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
        if (uart->cts_pin >= 0)
@@ -1370,18 +1365,18 @@ static int bfin_serial_probe(struct platform_device *pdev)
                res = platform_get_resource(pdev, IORESOURCE_IO, 0);
                if (res == NULL)
                        uart->cts_pin = -1;
-               else
+               else {
                        uart->cts_pin = res->start;
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+                       uart->port.flags |= ASYNC_CTS_FLOW;
+#endif
+               }
 
                res = platform_get_resource(pdev, IORESOURCE_IO, 1);
                if (res == NULL)
                        uart->rts_pin = -1;
                else
                        uart->rts_pin = res->start;
-# if defined(CONFIG_SERIAL_BFIN_CTSRTS)
-               if (uart->rts_pin >= 0)
-                       gpio_request(uart->rts_pin, DRIVER_NAME);
-# endif
 #endif
        }
 
@@ -1421,10 +1416,6 @@ static int __devexit bfin_serial_remove(struct platform_device *pdev)
 
        if (uart) {
                uart_remove_one_port(&bfin_serial_reg, &uart->port);
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-               if (uart->rts_pin >= 0)
-                       gpio_free(uart->rts_pin);
-#endif
                iounmap(uart->port.membase);
                peripheral_free_list(
                        (unsigned short *)pdev->dev.platform_data);
index 426434e5eb7c0d9ef57b8a6f3aeb047ad5f94f1d..7e925e20cbaaae5a5b65c9e5a5bb17d33f8381da 100644 (file)
@@ -1334,7 +1334,6 @@ MODULE_DEVICE_TABLE(spi, ifx_id_table);
 static const struct spi_driver ifx_spi_driver = {
        .driver = {
                .name = DRVNAME,
-               .bus = &spi_bus_type,
                .pm = &ifx_spi_pm,
                .owner = THIS_MODULE},
        .probe = ifx_spi_spi_probe,
index 163fc9021f5ad58a695c0fded23a300ed49b4627..0b7fed746b273fb5647f5f5b05fdd7a37f9c3d76 100644 (file)
 #define  UCR2_STPB       (1<<6)         /* Stop */
 #define  UCR2_WS         (1<<5)         /* Word size */
 #define  UCR2_RTSEN      (1<<4)         /* Request to send interrupt enable */
+#define  UCR2_ATEN       (1<<3)  /* Aging Timer Enable */
 #define  UCR2_TXEN       (1<<2)         /* Transmitter enabled */
 #define  UCR2_RXEN       (1<<1)         /* Receiver enabled */
 #define  UCR2_SRST      (1<<0)  /* SW reset */
@@ -207,6 +208,12 @@ struct imx_port {
        struct imx_uart_data    *devdata;
 };
 
+struct imx_port_ucrs {
+       unsigned int    ucr1;
+       unsigned int    ucr2;
+       unsigned int    ucr3;
+};
+
 #ifdef CONFIG_IRDA
 #define USE_IRDA(sport)        ((sport)->use_irda)
 #else
@@ -259,6 +266,27 @@ static inline int is_imx21_uart(struct imx_port *sport)
        return sport->devdata->devtype == IMX21_UART;
 }
 
+/*
+ * Save and restore functions for UCR1, UCR2 and UCR3 registers
+ */
+static void imx_port_ucrs_save(struct uart_port *port,
+                              struct imx_port_ucrs *ucr)
+{
+       /* save control registers */
+       ucr->ucr1 = readl(port->membase + UCR1);
+       ucr->ucr2 = readl(port->membase + UCR2);
+       ucr->ucr3 = readl(port->membase + UCR3);
+}
+
+static void imx_port_ucrs_restore(struct uart_port *port,
+                                 struct imx_port_ucrs *ucr)
+{
+       /* restore control registers */
+       writel(ucr->ucr1, port->membase + UCR1);
+       writel(ucr->ucr2, port->membase + UCR2);
+       writel(ucr->ucr3, port->membase + UCR3);
+}
+
 /*
  * Handle any change of modem status signal since we were last called.
  */
@@ -566,6 +594,9 @@ static irqreturn_t imx_int(int irq, void *dev_id)
        if (sts & USR1_RTSD)
                imx_rtsint(irq, dev_id);
 
+       if (sts & USR1_AWAKE)
+               writel(USR1_AWAKE, sport->port.membase + USR1);
+
        return IRQ_HANDLED;
 }
 
@@ -901,6 +932,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                        ucr2 |= UCR2_PROE;
        }
 
+       del_timer_sync(&sport->timer);
+
        /*
         * Ask the core to calculate the divisor for us.
         */
@@ -931,8 +964,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                        sport->port.ignore_status_mask |= URXD_OVRRUN;
        }
 
-       del_timer_sync(&sport->timer);
-
        /*
         * Update the per-port timeout.
         */
@@ -1079,6 +1110,70 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
        return ret;
 }
 
+#if defined(CONFIG_CONSOLE_POLL)
+static int imx_poll_get_char(struct uart_port *port)
+{
+       struct imx_port_ucrs old_ucr;
+       unsigned int status;
+       unsigned char c;
+
+       /* save control registers */
+       imx_port_ucrs_save(port, &old_ucr);
+
+       /* disable interrupts */
+       writel(UCR1_UARTEN, port->membase + UCR1);
+       writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
+              port->membase + UCR2);
+       writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
+              port->membase + UCR3);
+
+       /* poll */
+       do {
+               status = readl(port->membase + USR2);
+       } while (~status & USR2_RDR);
+
+       /* read */
+       c = readl(port->membase + URXD0);
+
+       /* restore control registers */
+       imx_port_ucrs_restore(port, &old_ucr);
+
+       return c;
+}
+
+static void imx_poll_put_char(struct uart_port *port, unsigned char c)
+{
+       struct imx_port_ucrs old_ucr;
+       unsigned int status;
+
+       /* save control registers */
+       imx_port_ucrs_save(port, &old_ucr);
+
+       /* disable interrupts */
+       writel(UCR1_UARTEN, port->membase + UCR1);
+       writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
+              port->membase + UCR2);
+       writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
+              port->membase + UCR3);
+
+       /* drain */
+       do {
+               status = readl(port->membase + USR1);
+       } while (~status & USR1_TRDY);
+
+       /* write */
+       writel(c, port->membase + URTX0);
+
+       /* flush */
+       do {
+               status = readl(port->membase + USR2);
+       } while (~status & USR2_TXDC);
+
+       /* restore control registers */
+       imx_port_ucrs_restore(port, &old_ucr);
+}
+#endif
+
 static struct uart_ops imx_pops = {
        .tx_empty       = imx_tx_empty,
        .set_mctrl      = imx_set_mctrl,
@@ -1096,6 +1191,10 @@ static struct uart_ops imx_pops = {
        .request_port   = imx_request_port,
        .config_port    = imx_config_port,
        .verify_port    = imx_verify_port,
+#if defined(CONFIG_CONSOLE_POLL)
+       .poll_get_char  = imx_poll_get_char,
+       .poll_put_char  = imx_poll_put_char,
+#endif
 };
 
 static struct imx_port *imx_ports[UART_NR];
@@ -1118,13 +1217,14 @@ static void
 imx_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct imx_port *sport = imx_ports[co->index];
-       unsigned int old_ucr1, old_ucr2, ucr1;
+       struct imx_port_ucrs old_ucr;
+       unsigned int ucr1;
 
        /*
-        *      First, save UCR1/2 and then disable interrupts
+        *      First, save UCR1/2/3 and then disable interrupts
         */
-       ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
-       old_ucr2 = readl(sport->port.membase + UCR2);
+       imx_port_ucrs_save(&sport->port, &old_ucr);
+       ucr1 = old_ucr.ucr1;
 
        if (is_imx1_uart(sport))
                ucr1 |= IMX1_UCR1_UARTCLKEN;
@@ -1133,18 +1233,17 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
 
        writel(ucr1, sport->port.membase + UCR1);
 
-       writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
+       writel(old_ucr.ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
 
        uart_console_write(&sport->port, s, count, imx_console_putchar);
 
        /*
         *      Finally, wait for transmitter to become empty
-        *      and restore UCR1/2
+        *      and restore UCR1/2/3
         */
        while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
 
-       writel(old_ucr1, sport->port.membase + UCR1);
-       writel(old_ucr2, sport->port.membase + UCR2);
+       imx_port_ucrs_restore(&sport->port, &old_ucr);
 }
 
 /*
@@ -1269,6 +1368,12 @@ static struct uart_driver imx_reg = {
 static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
 {
        struct imx_port *sport = platform_get_drvdata(dev);
+       unsigned int val;
+
+       /* enable wakeup from i.MX UART */
+       val = readl(sport->port.membase + UCR3);
+       val |= UCR3_AWAKEN;
+       writel(val, sport->port.membase + UCR3);
 
        if (sport)
                uart_suspend_port(&imx_reg, &sport->port);
@@ -1279,6 +1384,12 @@ static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
 static int serial_imx_resume(struct platform_device *dev)
 {
        struct imx_port *sport = platform_get_drvdata(dev);
+       unsigned int val;
+
+       /* disable wakeup from i.MX UART */
+       val = readl(sport->port.membase + UCR3);
+       val &= ~UCR3_AWAKEN;
+       writel(val, sport->port.membase + UCR3);
 
        if (sport)
                uart_resume_port(&imx_reg, &sport->port);
@@ -1287,6 +1398,10 @@ static int serial_imx_resume(struct platform_device *dev)
 }
 
 #ifdef CONFIG_OF
+/*
+ * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it
+ * could successfully get all information from dt or a negative errno.
+ */
 static int serial_imx_probe_dt(struct imx_port *sport,
                struct platform_device *pdev)
 {
@@ -1296,12 +1411,13 @@ static int serial_imx_probe_dt(struct imx_port *sport,
        int ret;
 
        if (!np)
-               return -ENODEV;
+               /* no device tree device */
+               return 1;
 
        ret = of_alias_get_id(np, "serial");
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
-               return -ENODEV;
+               return ret;
        }
        sport->port.line = ret;
 
@@ -1319,7 +1435,7 @@ static int serial_imx_probe_dt(struct imx_port *sport,
 static inline int serial_imx_probe_dt(struct imx_port *sport,
                struct platform_device *pdev)
 {
-       return -ENODEV;
+       return 1;
 }
 #endif
 
@@ -1354,8 +1470,10 @@ static int serial_imx_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        ret = serial_imx_probe_dt(sport, pdev);
-       if (ret == -ENODEV)
+       if (ret > 0)
                serial_imx_probe_pdata(sport, pdev);
+       else if (ret < 0)
+               goto free;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -1476,7 +1594,7 @@ static int __init imx_serial_init(void)
        if (ret != 0)
                uart_unregister_driver(&imx_reg);
 
-       return 0;
+       return ret;
 }
 
 static void __exit imx_serial_exit(void)
index 08018934e013495b96801b430067da242334b3c8..94a6792bf97bbba63e5b26d25771efd39dc25223 100644 (file)
@@ -1000,11 +1000,8 @@ static void __init m32r_sio_register_ports(struct uart_driver *drv)
                init_timer(&up->timer);
                up->timer.function = m32r_sio_timeout;
 
-               /*
-                * ALPHA_KLUDGE_MCR needs to be killed.
-                */
-               up->mcr_mask = ~ALPHA_KLUDGE_MCR;
-               up->mcr_force = ALPHA_KLUDGE_MCR;
+               up->mcr_mask = ~0;
+               up->mcr_force = 0;
 
                uart_add_one_port(drv, &up->port);
        }
index 8a6cc8c30b5a74eafdb774e1986712d9e80da61c..b4902b99cfd2301793785a527561ca2caf8d8b99 100644 (file)
@@ -901,7 +901,6 @@ static int max3100_resume(struct spi_device *spi)
 static struct spi_driver max3100_driver = {
        .driver = {
                .name           = "max3100",
-               .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
 
index 90c40f22ec709422e51a52648db2ea2fde4bfd9a..aae772a71de6ade2083e38288faf11e821d84f08 100644 (file)
@@ -315,7 +315,6 @@ static int __devinit max3107_probe_aava(struct spi_device *spi)
 static struct spi_driver max3107_driver = {
        .driver = {
                .name           = "aava-max3107",
-               .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
        .probe          = max3107_probe_aava,
index 7827000db4f558901a92551fd067943b78c079ed..17c7ba805d989353dab24dbd90bfce6b5dd05f0a 100644 (file)
@@ -1181,7 +1181,6 @@ static int max3107_probe_generic(struct spi_device *spi)
 static struct spi_driver max3107_driver = {
        .driver = {
                .name           = "max3107",
-               .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
        .probe          = max3107_probe_generic,
index e272d3919c67fdb6b465902fe7a5cb17978cc3a5..a9234ba8f8d5b4df867092ad4229b9b933859b6d 100644 (file)
@@ -1154,7 +1154,6 @@ serial_hsu_console_setup(struct console *co, char *options)
        int bits = 8;
        int parity = 'n';
        int flow = 'n';
-       int ret;
 
        if (co->index == -1 || co->index >= serial_hsu_reg.nr)
                co->index = 0;
@@ -1165,9 +1164,7 @@ serial_hsu_console_setup(struct console *co, char *options)
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
 
-       ret = uart_set_options(&up->port, co, baud, parity, bits, flow);
-
-       return ret;
+       return uart_set_options(&up->port, co, baud, parity, bits, flow);
 }
 
 static struct console serial_hsu_console = {
@@ -1176,9 +1173,13 @@ static struct console serial_hsu_console = {
        .device         = uart_console_device,
        .setup          = serial_hsu_console_setup,
        .flags          = CON_PRINTBUFFER,
-       .index          = 2,
+       .index          = -1,
        .data           = &serial_hsu_reg,
 };
+
+#define SERIAL_HSU_CONSOLE     (&serial_hsu_console)
+#else
+#define SERIAL_HSU_CONSOLE     NULL
 #endif
 
 struct uart_ops serial_hsu_pops = {
@@ -1208,6 +1209,7 @@ static struct uart_driver serial_hsu_reg = {
        .major          = TTY_MAJOR,
        .minor          = 128,
        .nr             = 3,
+       .cons           = SERIAL_HSU_CONSOLE,
 };
 
 #ifdef CONFIG_PM
@@ -1342,12 +1344,6 @@ static int serial_hsu_probe(struct pci_dev *pdev,
                }
                uart_add_one_port(&serial_hsu_reg, &uport->port);
 
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
-               if (index == 2) {
-                       register_console(&serial_hsu_console);
-                       uport->port.cons = &serial_hsu_console;
-               }
-#endif
                pci_set_drvdata(pdev, uport);
        }
 
index 4c309e8699031aca5408fab078c5ccd61e885fef..df2a2240a3aeda3a9aee82a22ad7e94914394173 100644 (file)
@@ -876,7 +876,6 @@ static int __devexit serial_m3110_remove(struct spi_device *dev)
 static struct spi_driver uart_max3110_driver = {
        .driver = {
                        .name   = "spi_max3111",
-                       .bus    = &spi_bus_type,
                        .owner  = THIS_MODULE,
        },
        .probe          = serial_m3110_probe,
index 60c6eb850265c18b11945bf50e685aff08c8156f..5e85e1e14c44009f80ea2ae8e668b2840efc770d 100644 (file)
@@ -422,9 +422,9 @@ static int __devexit msm_hs_remove(struct platform_device *pdev)
                      msm_uport->rx.rbuffer);
        dma_pool_destroy(msm_uport->rx.pool);
 
-       dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32 *),
+       dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32),
                         DMA_TO_DEVICE);
-       dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32 *),
+       dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32),
                         DMA_TO_DEVICE);
        dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box),
                         DMA_TO_DEVICE);
@@ -812,7 +812,7 @@ static void msm_hs_submit_tx_locked(struct uart_port *uport)
        *tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
 
        dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
-                                  sizeof(u32 *), DMA_TO_DEVICE);
+                                  sizeof(u32), DMA_TO_DEVICE);
 
        /* Save tx_count to use in Callback */
        tx->tx_count = tx_count;
@@ -1087,12 +1087,10 @@ static void msm_hs_config_port(struct uart_port *uport, int cfg_flags)
 }
 
 /*  Handle CTS changes (Called from interrupt handler) */
-static void msm_hs_handle_delta_cts(struct uart_port *uport)
+static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
 {
-       unsigned long flags;
        struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 
-       spin_lock_irqsave(&uport->lock, flags);
        clk_enable(msm_uport->clk);
 
        /* clear interrupt */
@@ -1100,7 +1098,6 @@ static void msm_hs_handle_delta_cts(struct uart_port *uport)
        uport->icount.cts++;
 
        clk_disable(msm_uport->clk);
-       spin_unlock_irqrestore(&uport->lock, flags);
 
        /* clear the IOCTL TIOCMIWAIT if called */
        wake_up_interruptible(&uport->state->port.delta_msr_wait);
@@ -1248,7 +1245,7 @@ static irqreturn_t msm_hs_isr(int irq, void *dev)
 
        /* Change in CTS interrupt */
        if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK)
-               msm_hs_handle_delta_cts(uport);
+               msm_hs_handle_delta_cts_locked(uport);
 
        spin_unlock_irqrestore(&uport->lock, flags);
 
@@ -1537,7 +1534,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
        if (!tx->command_ptr)
                return -ENOMEM;
 
-       tx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA);
+       tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
        if (!tx->command_ptr_ptr) {
                ret = -ENOMEM;
                goto err_tx_command_ptr_ptr;
@@ -1547,7 +1544,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
                                            sizeof(dmov_box), DMA_TO_DEVICE);
        tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
                                                tx->command_ptr_ptr,
-                                               sizeof(u32 *), DMA_TO_DEVICE);
+                                               sizeof(u32), DMA_TO_DEVICE);
        tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
 
        init_waitqueue_head(&rx->wait);
@@ -1575,7 +1572,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
                goto err_rx_command_ptr;
        }
 
-       rx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA);
+       rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
        if (!rx->command_ptr_ptr) {
                pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__);
                ret = -ENOMEM;
@@ -1593,7 +1590,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
        *rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr);
 
        rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr,
-                                           sizeof(u32 *), DMA_TO_DEVICE);
+                                           sizeof(u32), DMA_TO_DEVICE);
        rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr);
 
        INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work);
@@ -1609,7 +1606,7 @@ err_dma_pool_alloc:
        dma_pool_destroy(msm_uport->rx.pool);
 err_dma_pool_create:
        dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
-                               sizeof(u32 *), DMA_TO_DEVICE);
+                               sizeof(u32), DMA_TO_DEVICE);
        dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
                                sizeof(dmov_box), DMA_TO_DEVICE);
        kfree(msm_uport->tx.command_ptr_ptr);
index 7e02c9c344fee3496814ebc8b55bbe21280f618b..076169f50b010e31716f1a8467acc1cf79ad7a12 100644 (file)
@@ -145,11 +145,12 @@ static inline void mxs_auart_tx_chars(struct mxs_auart_port *s)
                        writel(xmit->buf[xmit->tail],
                                     s->port.membase + AUART_DATA);
                        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-                       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-                               uart_write_wakeup(&s->port);
                } else
                        break;
        }
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&s->port);
+
        if (uart_circ_empty(&(s->port.state->xmit)))
                writel(AUART_INTR_TXIEN,
                             s->port.membase + AUART_INTR_CLR);
index 5e713d3ef1f47c49eaa93f8d4ced09ce87b89c1e..f2a1380ed678b007f4690ac1d6f7d10e202aca37 100644 (file)
@@ -399,7 +399,7 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)
 static unsigned int serial_omap_get_mctrl(struct uart_port *port)
 {
        struct uart_omap_port *up = (struct uart_omap_port *)port;
-       unsigned char status;
+       unsigned int status;
        unsigned int ret = 0;
 
        status = check_modem_status(up);
index d6aba8c087e4784370648976c0d018a569c374f4..de0f613ed6f56051df309abc3ad25ea804081006 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/dmi.h>
+#include <linux/console.h>
+#include <linux/nmi.h>
+#include <linux/delay.h>
 
 #include <linux/dmaengine.h>
 #include <linux/pch_dma.h>
@@ -198,6 +201,10 @@ enum {
 
 #define PCI_VENDOR_ID_ROHM             0x10DB
 
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+#define DEFAULT_BAUD_RATE 1843200 /* 1.8432MHz */
+
 struct pch_uart_buffer {
        unsigned char *buf;
        int size;
@@ -276,6 +283,9 @@ static struct pch_uart_driver_data drv_dat[] = {
        [pch_ml7831_uart1] = {PCH_UART_2LINE, 1},
 };
 
+#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
+static struct eg20t_port *pch_uart_ports[PCH_UART_NR];
+#endif
 static unsigned int default_baud = 9600;
 static const int trigger_level_256[4] = { 1, 64, 128, 224 };
 static const int trigger_level_64[4] = { 1, 16, 32, 56 };
@@ -1385,6 +1395,143 @@ static struct uart_ops pch_uart_ops = {
        .verify_port = pch_uart_verify_port
 };
 
+#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static void wait_for_xmitr(struct eg20t_port *up, int bits)
+{
+       unsigned int status, tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       for (;;) {
+               status = ioread8(up->membase + UART_LSR);
+
+               if ((status & bits) == bits)
+                       break;
+               if (--tmout == 0)
+                       break;
+               udelay(1);
+       }
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               unsigned int tmout;
+               for (tmout = 1000000; tmout; tmout--) {
+                       unsigned int msr = ioread8(up->membase + UART_MSR);
+                       if (msr & UART_MSR_CTS)
+                               break;
+                       udelay(1);
+                       touch_nmi_watchdog();
+               }
+       }
+}
+
+static void pch_console_putchar(struct uart_port *port, int ch)
+{
+       struct eg20t_port *priv =
+               container_of(port, struct eg20t_port, port);
+
+       wait_for_xmitr(priv, UART_LSR_THRE);
+       iowrite8(ch, priv->membase + PCH_UART_THR);
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ *
+ *     The console_lock must be held when we get here.
+ */
+static void
+pch_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct eg20t_port *priv;
+
+       unsigned long flags;
+       u8 ier;
+       int locked = 1;
+
+       priv = pch_uart_ports[co->index];
+
+       touch_nmi_watchdog();
+
+       local_irq_save(flags);
+       if (priv->port.sysrq) {
+               /* serial8250_handle_port() already took the lock */
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&priv->port.lock);
+       } else
+               spin_lock(&priv->port.lock);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = ioread8(priv->membase + UART_IER);
+
+       pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+
+       uart_console_write(&priv->port, s, count, pch_console_putchar);
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(priv, BOTH_EMPTY);
+       iowrite8(ier, priv->membase + UART_IER);
+
+       if (locked)
+               spin_unlock(&priv->port.lock);
+       local_irq_restore(flags);
+}
+
+static int __init pch_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= PCH_UART_NR)
+               co->index = 0;
+       port = &pch_uart_ports[co->index]->port;
+
+       if (!port || (!port->iobase && !port->membase))
+               return -ENODEV;
+
+       /* setup uartclock */
+       port->uartclk = DEFAULT_BAUD_RATE;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver pch_uart_driver;
+
+static struct console pch_console = {
+       .name           = PCH_UART_DRIVER_DEVICE,
+       .write          = pch_console_write,
+       .device         = uart_console_device,
+       .setup          = pch_console_setup,
+       .flags          = CON_PRINTBUFFER | CON_ANYTIME,
+       .index          = -1,
+       .data           = &pch_uart_driver,
+};
+
+#define PCH_CONSOLE    (&pch_console)
+#else
+#define PCH_CONSOLE    NULL
+#endif
+
 static struct uart_driver pch_uart_driver = {
        .owner = THIS_MODULE,
        .driver_name = KBUILD_MODNAME,
@@ -1392,6 +1539,7 @@ static struct uart_driver pch_uart_driver = {
        .major = 0,
        .minor = 0,
        .nr = PCH_UART_NR,
+       .cons = PCH_CONSOLE,
 };
 
 static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
@@ -1418,7 +1566,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
        if (!rxbuf)
                goto init_port_free_txbuf;
 
-       base_baud = 1843200; /* 1.8432MHz */
+       base_baud = DEFAULT_BAUD_RATE;
 
        /* quirk for CM-iTC board */
        board_name = dmi_get_system_info(DMI_BOARD_NAME);
@@ -1468,6 +1616,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
        pci_set_drvdata(pdev, priv);
        pch_uart_hal_request(pdev, fifosize, base_baud);
 
+#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
+       pch_uart_ports[board->line_no] = priv;
+#endif
        ret = uart_add_one_port(&pch_uart_driver, &priv->port);
        if (ret < 0)
                goto init_port_hal_free;
@@ -1475,6 +1626,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
        return priv;
 
 init_port_hal_free:
+#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
+       pch_uart_ports[board->line_no] = NULL;
+#endif
        free_page((unsigned long)rxbuf);
 init_port_free_txbuf:
        kfree(priv);
@@ -1497,6 +1651,10 @@ static void pch_uart_pci_remove(struct pci_dev *pdev)
        priv = (struct eg20t_port *)pci_get_drvdata(pdev);
 
        pci_disable_msi(pdev);
+
+#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
+       pch_uart_ports[priv->port.line] = NULL;
+#endif
        pch_uart_exit_port(priv);
        pci_disable_device(pdev);
        kfree(priv);
index 75038ad2b2424b3487866f6fa212c2eeeeff9cca..e0b4b0a30a5a7b7c145de9682f18859032354497 100644 (file)
@@ -736,19 +736,7 @@ static struct platform_driver sc26xx_driver = {
        },
 };
 
-static int __init sc26xx_init(void)
-{
-       return platform_driver_register(&sc26xx_driver);
-}
-
-static void __exit sc26xx_exit(void)
-{
-       platform_driver_unregister(&sc26xx_driver);
-}
-
-module_init(sc26xx_init);
-module_exit(sc26xx_exit);
-
+module_platform_driver(sc26xx_driver);
 
 MODULE_AUTHOR("Thomas Bogendörfer");
 MODULE_DESCRIPTION("SC681/SC2692 serial driver");
index 0406d7ff505ea265634c2e294be1fa8b58dc375b..c7bf31a6a7e75f711b711cad125a1b874db2fa04 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include <linux/module.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/console.h>
@@ -60,6 +61,8 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
 static void uart_change_pm(struct uart_state *state, int pm_state);
 
+static void uart_port_shutdown(struct tty_port *port);
+
 /*
  * This routine is used by the interrupt handler to schedule processing in
  * the software interrupt portion of the driver.
@@ -128,25 +131,16 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
  * Startup the port.  This will be called once per open.  All calls
  * will be serialised by the per-port mutex.
  */
-static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw)
+static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
+               int init_hw)
 {
        struct uart_port *uport = state->uart_port;
        struct tty_port *port = &state->port;
        unsigned long page;
        int retval = 0;
 
-       if (port->flags & ASYNC_INITIALIZED)
-               return 0;
-
-       /*
-        * Set the TTY IO error marker - we will only clear this
-        * once we have successfully opened the port.  Also set
-        * up the tty->alt_speed kludge
-        */
-       set_bit(TTY_IO_ERROR, &tty->flags);
-
        if (uport->type == PORT_UNKNOWN)
-               return 0;
+               return 1;
 
        /*
         * Initialise and allocate the transmit and temporary
@@ -188,10 +182,6 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, int in
                                tty->hw_stopped = 1;
                        spin_unlock_irq(&uport->lock);
                }
-
-               set_bit(ASYNCB_INITIALIZED, &port->flags);
-
-               clear_bit(TTY_IO_ERROR, &tty->flags);
        }
 
        /*
@@ -200,6 +190,31 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, int in
         * now.
         */
        if (retval && capable(CAP_SYS_ADMIN))
+               return 1;
+
+       return retval;
+}
+
+static int uart_startup(struct tty_struct *tty, struct uart_state *state,
+               int init_hw)
+{
+       struct tty_port *port = &state->port;
+       int retval;
+
+       if (port->flags & ASYNC_INITIALIZED)
+               return 0;
+
+       /*
+        * Set the TTY IO error marker - we will only clear this
+        * once we have successfully opened the port.
+        */
+       set_bit(TTY_IO_ERROR, &tty->flags);
+
+       retval = uart_port_startup(tty, state, init_hw);
+       if (!retval) {
+               set_bit(ASYNCB_INITIALIZED, &port->flags);
+               clear_bit(TTY_IO_ERROR, &tty->flags);
+       } else if (retval > 0)
                retval = 0;
 
        return retval;
@@ -228,24 +243,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
                if (!tty || (tty->termios->c_cflag & HUPCL))
                        uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
 
-               /*
-                * clear delta_msr_wait queue to avoid mem leaks: we may free
-                * the irq here so the queue might never be woken up.  Note
-                * that we won't end up waiting on delta_msr_wait again since
-                * any outstanding file descriptors should be pointing at
-                * hung_up_tty_fops now.
-                */
-               wake_up_interruptible(&port->delta_msr_wait);
-
-               /*
-                * Free the IRQ and disable the port.
-                */
-               uport->ops->shutdown(uport);
-
-               /*
-                * Ensure that the IRQ handler isn't running on another CPU.
-                */
-               synchronize_irq(uport->irq);
+               uart_port_shutdown(port);
        }
 
        /*
@@ -423,7 +421,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
        if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
                quot = port->custom_divisor;
        else
-               quot = (port->uartclk + (8 * baud)) / (16 * baud);
+               quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
 
        return quot;
 }
@@ -658,10 +656,10 @@ static int uart_get_info(struct uart_state *state,
        tmp.flags           = uport->flags;
        tmp.xmit_fifo_size  = uport->fifosize;
        tmp.baud_base       = uport->uartclk / 16;
-       tmp.close_delay     = port->close_delay / 10;
+       tmp.close_delay     = jiffies_to_msecs(port->close_delay) / 10;
        tmp.closing_wait    = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
                                ASYNC_CLOSING_WAIT_NONE :
-                               port->closing_wait / 10;
+                               jiffies_to_msecs(port->closing_wait) / 10;
        tmp.custom_divisor  = uport->custom_divisor;
        tmp.hub6            = uport->hub6;
        tmp.io_type         = uport->iotype;
@@ -695,9 +693,10 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
                new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
 
        new_serial.irq = irq_canonicalize(new_serial.irq);
-       close_delay = new_serial.close_delay * 10;
+       close_delay = msecs_to_jiffies(new_serial.close_delay * 10);
        closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
-                       ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+                       ASYNC_CLOSING_WAIT_NONE :
+                       msecs_to_jiffies(new_serial.closing_wait * 10);
 
        /*
         * This semaphore protects port->count.  It is also
@@ -1265,47 +1264,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
 
        pr_debug("uart_close(%d) called\n", uport->line);
 
-       spin_lock_irqsave(&port->lock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&port->lock, flags);
+       if (tty_port_close_start(port, tty, filp) == 0)
                return;
-       }
-
-       if ((tty->count == 1) && (port->count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  port->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, "
-                      "port->count is %d\n", port->count);
-               port->count = 1;
-       }
-       if (--port->count < 0) {
-               printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n",
-                      tty->name, port->count);
-               port->count = 0;
-       }
-       if (port->count) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               return;
-       }
-
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify
-        * the line discipline to only process XON/XOFF characters by
-        * setting tty->closing.
-        */
-       set_bit(ASYNCB_CLOSING, &port->flags);
-       tty->closing = 1;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent_from_close(tty,
-                               msecs_to_jiffies(port->closing_wait));
 
        /*
         * At this point, we stop accepting input.  To do this, we
@@ -1337,7 +1297,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        if (port->blocked_open) {
                spin_unlock_irqrestore(&port->lock, flags);
                if (port->close_delay)
-                       msleep_interruptible(port->close_delay);
+                       msleep_interruptible(
+                                       jiffies_to_msecs(port->close_delay));
                spin_lock_irqsave(&port->lock, flags);
        } else if (!uart_console(uport)) {
                spin_unlock_irqrestore(&port->lock, flags);
@@ -1441,6 +1402,36 @@ static void uart_hangup(struct tty_struct *tty)
        mutex_unlock(&port->mutex);
 }
 
+static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+       return 0;
+}
+
+static void uart_port_shutdown(struct tty_port *port)
+{
+       struct uart_state *state = container_of(port, struct uart_state, port);
+       struct uart_port *uport = state->uart_port;
+
+       /*
+        * clear delta_msr_wait queue to avoid mem leaks: we may free
+        * the irq here so the queue might never be woken up.  Note
+        * that we won't end up waiting on delta_msr_wait again since
+        * any outstanding file descriptors should be pointing at
+        * hung_up_tty_fops now.
+        */
+       wake_up_interruptible(&port->delta_msr_wait);
+
+       /*
+        * Free the IRQ and disable the port.
+        */
+       uport->ops->shutdown(uport);
+
+       /*
+        * Ensure that the IRQ handler isn't running on another CPU.
+        */
+       synchronize_irq(uport->irq);
+}
+
 static int uart_carrier_raised(struct tty_port *port)
 {
        struct uart_state *state = container_of(port, struct uart_state, port);
@@ -1466,33 +1457,6 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
                uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
 }
 
-static struct uart_state *uart_get(struct uart_driver *drv, int line)
-{
-       struct uart_state *state;
-       struct tty_port *port;
-       int ret = 0;
-
-       state = drv->state + line;
-       port = &state->port;
-       if (mutex_lock_interruptible(&port->mutex)) {
-               ret = -ERESTARTSYS;
-               goto err;
-       }
-
-       port->count++;
-       if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
-               ret = -ENXIO;
-               goto err_unlock;
-       }
-       return state;
-
- err_unlock:
-       port->count--;
-       mutex_unlock(&port->mutex);
- err:
-       return ERR_PTR(ret);
-}
-
 /*
  * calls to uart_open are serialised by the BKL in
  *   fs/char_dev.c:chrdev_open()
@@ -1506,26 +1470,29 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
 static int uart_open(struct tty_struct *tty, struct file *filp)
 {
        struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
-       struct uart_state *state;
-       struct tty_port *port;
        int retval, line = tty->index;
+       struct uart_state *state = drv->state + line;
+       struct tty_port *port = &state->port;
 
        pr_debug("uart_open(%d) called\n", line);
 
        /*
-        * We take the semaphore inside uart_get to guarantee that we won't
-        * be re-entered while allocating the state structure, or while we
-        * request any IRQs that the driver may need.  This also has the nice
-        * side-effect that it delays the action of uart_hangup, so we can
-        * guarantee that state->port.tty will always contain something
-        * reasonable.
+        * We take the semaphore here to guarantee that we won't be re-entered
+        * while allocating the state structure, or while we request any IRQs
+        * that the driver may need.  This also has the nice side-effect that
+        * it delays the action of uart_hangup, so we can guarantee that
+        * state->port.tty will always contain something reasonable.
         */
-       state = uart_get(drv, line);
-       if (IS_ERR(state)) {
-               retval = PTR_ERR(state);
-               goto fail;
+       if (mutex_lock_interruptible(&port->mutex)) {
+               retval = -ERESTARTSYS;
+               goto end;
+       }
+
+       port->count++;
+       if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
+               retval = -ENXIO;
+               goto err_dec_count;
        }
-       port = &state->port;
 
        /*
         * Once we set tty->driver_data here, we are guaranteed that
@@ -1535,7 +1502,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        tty->driver_data = state;
        state->uart_port->state = state;
        tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
-       tty->alt_speed = 0;
        tty_port_tty_set(port, tty);
 
        /*
@@ -1543,9 +1509,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
         */
        if (tty_hung_up_p(filp)) {
                retval = -EAGAIN;
-               port->count--;
-               mutex_unlock(&port->mutex);
-               goto fail;
+               goto err_dec_count;
        }
 
        /*
@@ -1566,8 +1530,12 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        if (retval == 0)
                retval = tty_port_block_til_ready(port, tty, filp);
 
-fail:
+end:
        return retval;
+err_dec_count:
+       port->count--;
+       mutex_unlock(&port->mutex);
+       goto end;
 }
 
 static const char *uart_type(struct uart_port *port)
@@ -1858,6 +1826,14 @@ uart_set_options(struct uart_port *port, struct console *co,
 EXPORT_SYMBOL_GPL(uart_set_options);
 #endif /* CONFIG_SERIAL_CORE_CONSOLE */
 
+/**
+ * uart_change_pm - set power state of the port
+ *
+ * @state: port descriptor
+ * @pm_state: new state
+ *
+ * Locking: port->mutex has to be held
+ */
 static void uart_change_pm(struct uart_state *state, int pm_state)
 {
        struct uart_port *port = state->uart_port;
@@ -2214,6 +2190,8 @@ static const struct tty_operations uart_ops = {
 };
 
 static const struct tty_port_operations uart_port_ops = {
+       .activate       = uart_port_activate,
+       .shutdown       = uart_port_shutdown,
        .carrier_raised = uart_carrier_raised,
        .dtr_rts        = uart_dtr_rts,
 };
@@ -2275,8 +2253,8 @@ int uart_register_driver(struct uart_driver *drv)
 
                tty_port_init(port);
                port->ops = &uart_port_ops;
-               port->close_delay     = 500;    /* .5 seconds */
-               port->closing_wait    = 30000;  /* 30 seconds */
+               port->close_delay     = HZ / 2; /* .5 seconds */
+               port->closing_wait    = 30 * HZ;/* 30 seconds */
        }
 
        retval = tty_register_driver(normal);
@@ -2467,6 +2445,99 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
 }
 EXPORT_SYMBOL(uart_match_port);
 
+/**
+ *     uart_handle_dcd_change - handle a change of carrier detect state
+ *     @uport: uart_port structure for the open port
+ *     @status: new carrier detect status, nonzero if active
+ */
+void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
+{
+       struct uart_state *state = uport->state;
+       struct tty_port *port = &state->port;
+       struct tty_ldisc *ld = tty_ldisc_ref(port->tty);
+       struct pps_event_time ts;
+
+       if (ld && ld->ops->dcd_change)
+               pps_get_ts(&ts);
+
+       uport->icount.dcd++;
+#ifdef CONFIG_HARD_PPS
+       if ((uport->flags & UPF_HARDPPS_CD) && status)
+               hardpps();
+#endif
+
+       if (port->flags & ASYNC_CHECK_CD) {
+               if (status)
+                       wake_up_interruptible(&port->open_wait);
+               else if (port->tty)
+                       tty_hangup(port->tty);
+       }
+
+       if (ld && ld->ops->dcd_change)
+               ld->ops->dcd_change(port->tty, status, &ts);
+       if (ld)
+               tty_ldisc_deref(ld);
+}
+EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
+
+/**
+ *     uart_handle_cts_change - handle a change of clear-to-send state
+ *     @uport: uart_port structure for the open port
+ *     @status: new clear to send status, nonzero if active
+ */
+void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
+{
+       struct tty_port *port = &uport->state->port;
+       struct tty_struct *tty = port->tty;
+
+       uport->icount.cts++;
+
+       if (port->flags & ASYNC_CTS_FLOW) {
+               if (tty->hw_stopped) {
+                       if (status) {
+                               tty->hw_stopped = 0;
+                               uport->ops->start_tx(uport);
+                               uart_write_wakeup(uport);
+                       }
+               } else {
+                       if (!status) {
+                               tty->hw_stopped = 1;
+                               uport->ops->stop_tx(uport);
+                       }
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(uart_handle_cts_change);
+
+/**
+ * uart_insert_char - push a char to the uart layer
+ *
+ * User is responsible to call tty_flip_buffer_push when they are done with
+ * insertion.
+ *
+ * @port: corresponding port
+ * @status: state of the serial port RX buffer (LSR for 8250)
+ * @overrun: mask of overrun bits in @status
+ * @ch: character to push
+ * @flag: flag for the character (see TTY_NORMAL and friends)
+ */
+void uart_insert_char(struct uart_port *port, unsigned int status,
+                unsigned int overrun, unsigned int ch, unsigned int flag)
+{
+       struct tty_struct *tty = port->state->port.tty;
+
+       if ((status & port->ignore_status_mask & ~overrun) == 0)
+               tty_insert_flip_char(tty, ch, flag);
+
+       /*
+        * Overrun is special.  Since it's reported immediately,
+        * it doesn't affect the current character.
+        */
+       if (status & ~port->ignore_status_mask & overrun)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+}
+EXPORT_SYMBOL_GPL(uart_insert_char);
+
 EXPORT_SYMBOL(uart_write_wakeup);
 EXPORT_SYMBOL(uart_register_driver);
 EXPORT_SYMBOL(uart_unregister_driver);
index eef736ff810af9d03a5a5036b682b4ac479b6084..86090605a84ee52291234c882470f67db012df4b 100644 (file)
@@ -317,7 +317,7 @@ static int serial_probe(struct pcmcia_device *link)
        info->p_dev = link;
        link->priv = info;
 
-       link->config_flags |= CONF_ENABLE_IRQ;
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
        if (do_sound)
                link->config_flags |= CONF_ENABLE_SPKR;
 
@@ -445,7 +445,7 @@ static int simple_config(struct pcmcia_device *link)
 
        /* First pass: look for a config entry that looks normal.
         * Two tries: without IO aliases, then with aliases */
-       link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO;
+       link->config_flags |= CONF_AUTO_SET_VPP;
        for (try = 0; try < 4; try++)
                if (!pcmcia_loop_config(link, simple_config_check, &try))
                        goto found_port;
@@ -501,7 +501,8 @@ static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
 {
        int *base2 = priv_data;
 
-       if (!p_dev->resource[0]->end || !p_dev->resource[1]->end)
+       if (!p_dev->resource[0]->end || !p_dev->resource[1]->end ||
+               p_dev->resource[0]->start + 8 != p_dev->resource[1]->start)
                return -ENODEV;
 
        p_dev->resource[0]->end = p_dev->resource[1]->end = 8;
@@ -520,7 +521,6 @@ static int multi_config(struct pcmcia_device *link)
        struct serial_info *info = link->priv;
        int i, base2 = 0;
 
-       link->config_flags |= CONF_AUTO_SET_IO;
        /* First, look for a generic full-sized window */
        if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
                base2 = link->resource[0]->start + 8;
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
new file mode 100644 (file)
index 0000000..a60523f
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+ * Driver for CSR SiRFprimaII onboard UARTs.
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/sysrq.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "sirfsoc_uart.h"
+
+static unsigned int
+sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count);
+static unsigned int
+sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
+static struct uart_driver sirfsoc_uart_drv;
+
+static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
+       {4000000, 2359296},
+       {3500000, 1310721},
+       {3000000, 1572865},
+       {2500000, 1245186},
+       {2000000, 1572866},
+       {1500000, 1245188},
+       {1152000, 1638404},
+       {1000000, 1572869},
+       {921600, 1114120},
+       {576000, 1245196},
+       {500000, 1245198},
+       {460800, 1572876},
+       {230400, 1310750},
+       {115200, 1310781},
+       {57600, 1310843},
+       {38400, 1114328},
+       {19200, 1114545},
+       {9600, 1114979},
+};
+
+static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = {
+       [0] = {
+               .port = {
+                       .iotype         = UPIO_MEM,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 0,
+               },
+       },
+       [1] = {
+               .port = {
+                       .iotype         = UPIO_MEM,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 1,
+               },
+       },
+       [2] = {
+               .port = {
+                       .iotype         = UPIO_MEM,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 2,
+               },
+       },
+};
+
+static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
+{
+       return container_of(port, struct sirfsoc_uart_port, port);
+}
+
+static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
+{
+       unsigned long reg;
+       reg = rd_regl(port, SIRFUART_TX_FIFO_STATUS);
+       if (reg & SIRFUART_FIFOEMPTY_MASK(port))
+               return TIOCSER_TEMT;
+       else
+               return 0;
+}
+
+static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
+{
+       struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+       if (!(sirfport->ms_enabled)) {
+               goto cts_asserted;
+       } else if (sirfport->hw_flow_ctrl) {
+               if (!(rd_regl(port, SIRFUART_AFC_CTRL) &
+                                               SIRFUART_CTS_IN_STATUS))
+                       goto cts_asserted;
+               else
+                       goto cts_deasserted;
+       }
+cts_deasserted:
+       return TIOCM_CAR | TIOCM_DSR;
+cts_asserted:
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+       unsigned int assert = mctrl & TIOCM_RTS;
+       unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
+       unsigned int current_val;
+       if (sirfport->hw_flow_ctrl) {
+               current_val = rd_regl(port, SIRFUART_AFC_CTRL) & ~0xFF;
+               val |= current_val;
+               wr_regl(port, SIRFUART_AFC_CTRL, val);
+       }
+}
+
+static void sirfsoc_uart_stop_tx(struct uart_port *port)
+{
+       unsigned int regv;
+       regv = rd_regl(port, SIRFUART_INT_EN);
+       wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_TX_INT_EN);
+}
+
+void sirfsoc_uart_start_tx(struct uart_port *port)
+{
+       struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+       unsigned long regv;
+       sirfsoc_uart_pio_tx_chars(sirfport, 1);
+       wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_START);
+       regv = rd_regl(port, SIRFUART_INT_EN);
+       wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_TX_INT_EN);
+}
+
+static void sirfsoc_uart_stop_rx(struct uart_port *port)
+{
+       unsigned long regv;
+       wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+       regv = rd_regl(port, SIRFUART_INT_EN);
+       wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_RX_IO_INT_EN);
+}
+
+static void sirfsoc_uart_disable_ms(struct uart_port *port)
+{
+       struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+       unsigned long reg;
+       sirfport->ms_enabled = 0;
+       if (!sirfport->hw_flow_ctrl)
+               return;
+       reg = rd_regl(port, SIRFUART_AFC_CTRL);
+       wr_regl(port, SIRFUART_AFC_CTRL, reg & ~0x3FF);
+       reg = rd_regl(port, SIRFUART_INT_EN);
+       wr_regl(port, SIRFUART_INT_EN, reg & ~SIRFUART_CTS_INT_EN);
+}
+
+static void sirfsoc_uart_enable_ms(struct uart_port *port)
+{
+       struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+       unsigned long reg;
+       unsigned long flg;
+       if (!sirfport->hw_flow_ctrl)
+               return;
+       flg = SIRFUART_AFC_RX_EN | SIRFUART_AFC_TX_EN;
+       reg = rd_regl(port, SIRFUART_AFC_CTRL);
+       wr_regl(port, SIRFUART_AFC_CTRL, reg | flg);
+       reg = rd_regl(port, SIRFUART_INT_EN);
+       wr_regl(port, SIRFUART_INT_EN, reg | SIRFUART_CTS_INT_EN);
+       uart_handle_cts_change(port,
+               !(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS));
+       sirfport->ms_enabled = 1;
+}
+
+static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state)
+{
+       unsigned long ulcon = rd_regl(port, SIRFUART_LINE_CTRL);
+       if (break_state)
+               ulcon |= SIRFUART_SET_BREAK;
+       else
+               ulcon &= ~SIRFUART_SET_BREAK;
+       wr_regl(port, SIRFUART_LINE_CTRL, ulcon);
+}
+
+static unsigned int
+sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
+{
+       unsigned int ch, rx_count = 0;
+       struct tty_struct *tty;
+
+       tty = tty_port_tty_get(&port->state->port);
+       if (!tty)
+               return -ENODEV;
+
+       while (!(rd_regl(port, SIRFUART_RX_FIFO_STATUS) &
+                                       SIRFUART_FIFOEMPTY_MASK(port))) {
+               ch = rd_regl(port, SIRFUART_RX_FIFO_DATA) | SIRFUART_DUMMY_READ;
+               if (unlikely(uart_handle_sysrq_char(port, ch)))
+                       continue;
+               uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
+               rx_count++;
+               if (rx_count >= max_rx_count)
+                       break;
+       }
+
+       port->icount.rx += rx_count;
+       tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+
+       return rx_count;
+}
+
+static unsigned int
+sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
+{
+       struct uart_port *port = &sirfport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int num_tx = 0;
+       while (!uart_circ_empty(xmit) &&
+               !(rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
+                                       SIRFUART_FIFOFULL_MASK(port)) &&
+               count--) {
+               wr_regl(port, SIRFUART_TX_FIFO_DATA, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               num_tx++;
+       }
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+       return num_tx;
+}
+
+static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
+{
+       unsigned long intr_status;
+       unsigned long cts_status;
+       unsigned long flag = TTY_NORMAL;
+       struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
+       struct uart_port *port = &sirfport->port;
+       struct uart_state *state = port->state;
+       struct circ_buf *xmit = &port->state->xmit;
+       intr_status = rd_regl(port, SIRFUART_INT_STATUS);
+       wr_regl(port, SIRFUART_INT_STATUS, intr_status);
+       intr_status &= rd_regl(port, SIRFUART_INT_EN);
+       if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT))) {
+               if (intr_status & SIRFUART_RXD_BREAK) {
+                       if (uart_handle_break(port))
+                               goto recv_char;
+                       uart_insert_char(port, intr_status,
+                                       SIRFUART_RX_OFLOW, 0, TTY_BREAK);
+                       return IRQ_HANDLED;
+               }
+               if (intr_status & SIRFUART_RX_OFLOW)
+                       port->icount.overrun++;
+               if (intr_status & SIRFUART_FRM_ERR) {
+                       port->icount.frame++;
+                       flag = TTY_FRAME;
+               }
+               if (intr_status & SIRFUART_PARITY_ERR)
+                       flag = TTY_PARITY;
+               wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
+               wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+               wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
+               intr_status &= port->read_status_mask;
+               uart_insert_char(port, intr_status,
+                                       SIRFUART_RX_OFLOW_INT, 0, flag);
+       }
+recv_char:
+       if (intr_status & SIRFUART_CTS_INT_EN) {
+               cts_status = !(rd_regl(port, SIRFUART_AFC_CTRL) &
+                                                       SIRFUART_CTS_IN_STATUS);
+               if (cts_status != 0) {
+                       uart_handle_cts_change(port, 1);
+               } else {
+                       uart_handle_cts_change(port, 0);
+                       wake_up_interruptible(&state->port.delta_msr_wait);
+               }
+       }
+       if (intr_status & SIRFUART_RX_IO_INT_EN)
+               sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT);
+       if (intr_status & SIRFUART_TX_INT_EN) {
+               if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+                       return IRQ_HANDLED;
+               } else {
+                       sirfsoc_uart_pio_tx_chars(sirfport,
+                                       SIRFSOC_UART_IO_TX_REASONABLE_CNT);
+                       if ((uart_circ_empty(xmit)) &&
+                               (rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
+                                               SIRFUART_FIFOEMPTY_MASK(port)))
+                               sirfsoc_uart_stop_tx(port);
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+static void sirfsoc_uart_start_rx(struct uart_port *port)
+{
+       unsigned long regv;
+       regv = rd_regl(port, SIRFUART_INT_EN);
+       wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_RX_IO_INT_EN);
+       wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
+       wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+       wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
+}
+
+static unsigned int
+sirfsoc_calc_sample_div(unsigned long baud_rate,
+                       unsigned long ioclk_rate, unsigned long *setted_baud)
+{
+       unsigned long min_delta = ~0UL;
+       unsigned short sample_div;
+       unsigned int regv = 0;
+       unsigned long ioclk_div;
+       unsigned long baud_tmp;
+       int temp_delta;
+
+       for (sample_div = SIRF_MIN_SAMPLE_DIV;
+                       sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
+               ioclk_div = (ioclk_rate / (baud_rate * (sample_div + 1))) - 1;
+               if (ioclk_div > SIRF_IOCLK_DIV_MAX)
+                       continue;
+               baud_tmp = ioclk_rate / ((ioclk_div + 1) * (sample_div + 1));
+               temp_delta = baud_tmp - baud_rate;
+               temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
+               if (temp_delta < min_delta) {
+                       regv = regv & (~SIRF_IOCLK_DIV_MASK);
+                       regv = regv | ioclk_div;
+                       regv = regv & (~SIRF_SAMPLE_DIV_MASK);
+                       regv = regv | (sample_div << SIRF_SAMPLE_DIV_SHIFT);
+                       min_delta = temp_delta;
+                       *setted_baud = baud_tmp;
+               }
+       }
+       return regv;
+}
+
+static void sirfsoc_uart_set_termios(struct uart_port *port,
+                                      struct ktermios *termios,
+                                      struct ktermios *old)
+{
+       struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+       unsigned long   ioclk_rate;
+       unsigned long   config_reg = 0;
+       unsigned long   baud_rate;
+       unsigned long   setted_baud;
+       unsigned long   flags;
+       unsigned long   ic;
+       unsigned int    clk_div_reg = 0;
+       unsigned long   temp_reg_val;
+       unsigned long   rx_time_out;
+       int             threshold_div;
+       int             temp;
+
+       ioclk_rate = 150000000;
+       switch (termios->c_cflag & CSIZE) {
+       default:
+       case CS8:
+               config_reg |= SIRFUART_DATA_BIT_LEN_8;
+               break;
+       case CS7:
+               config_reg |= SIRFUART_DATA_BIT_LEN_7;
+               break;
+       case CS6:
+               config_reg |= SIRFUART_DATA_BIT_LEN_6;
+               break;
+       case CS5:
+               config_reg |= SIRFUART_DATA_BIT_LEN_5;
+               break;
+       }
+       if (termios->c_cflag & CSTOPB)
+               config_reg |= SIRFUART_STOP_BIT_LEN_2;
+       baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
+       spin_lock_irqsave(&port->lock, flags);
+       port->read_status_mask = SIRFUART_RX_OFLOW_INT;
+       port->ignore_status_mask = 0;
+       /* read flags */
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |=
+                       SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= SIRFUART_RXD_BREAK_INT;
+       /* ignore flags */
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |=
+                       SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= SIRFUART_DUMMY_READ;
+       /* enable parity if PARENB is set*/
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & CMSPAR) {
+                       if (termios->c_cflag & PARODD)
+                               config_reg |= SIRFUART_STICK_BIT_MARK;
+                       else
+                               config_reg |= SIRFUART_STICK_BIT_SPACE;
+               } else if (termios->c_cflag & PARODD) {
+                       config_reg |= SIRFUART_STICK_BIT_ODD;
+               } else {
+                       config_reg |= SIRFUART_STICK_BIT_EVEN;
+               }
+       }
+       /* Hardware Flow Control Settings */
+       if (UART_ENABLE_MS(port, termios->c_cflag)) {
+               if (!sirfport->ms_enabled)
+                       sirfsoc_uart_enable_ms(port);
+       } else {
+               if (sirfport->ms_enabled)
+                       sirfsoc_uart_disable_ms(port);
+       }
+
+       /* common rate: fast calculation */
+       for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
+               if (baud_rate == baudrate_to_regv[ic].baud_rate)
+                       clk_div_reg = baudrate_to_regv[ic].reg_val;
+       setted_baud = baud_rate;
+       /* arbitary rate setting */
+       if (unlikely(clk_div_reg == 0))
+               clk_div_reg = sirfsoc_calc_sample_div(baud_rate, ioclk_rate,
+                                                               &setted_baud);
+       wr_regl(port, SIRFUART_DIVISOR, clk_div_reg);
+
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, setted_baud, setted_baud);
+
+       /* set receive timeout */
+       rx_time_out = SIRFSOC_UART_RX_TIMEOUT(baud_rate, 20000);
+       rx_time_out = (rx_time_out > 0xFFFF) ? 0xFFFF : rx_time_out;
+       config_reg |= SIRFUART_RECV_TIMEOUT(rx_time_out);
+       temp_reg_val = rd_regl(port, SIRFUART_TX_FIFO_OP);
+       wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+       wr_regl(port, SIRFUART_TX_FIFO_OP,
+                               temp_reg_val & ~SIRFUART_TX_FIFO_START);
+       wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, SIRFUART_TX_MODE_IO);
+       wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, SIRFUART_RX_MODE_IO);
+       wr_regl(port, SIRFUART_LINE_CTRL, config_reg);
+
+       /* Reset Rx/Tx FIFO Threshold level for proper baudrate */
+       if (baud_rate < 1000000)
+               threshold_div = 1;
+       else
+               threshold_div = 2;
+       temp = port->line == 1 ? 16 : 64;
+       wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp / threshold_div);
+       wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp / threshold_div);
+       temp_reg_val |= SIRFUART_TX_FIFO_START;
+       wr_regl(port, SIRFUART_TX_FIFO_OP, temp_reg_val);
+       uart_update_timeout(port, termios->c_cflag, baud_rate);
+       sirfsoc_uart_start_rx(port);
+       wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_TX_EN | SIRFUART_RX_EN);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void startup_uart_controller(struct uart_port *port)
+{
+       unsigned long temp_regv;
+       int temp;
+       temp_regv = rd_regl(port, SIRFUART_TX_DMA_IO_CTRL);
+       wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, temp_regv | SIRFUART_TX_MODE_IO);
+       temp_regv = rd_regl(port, SIRFUART_RX_DMA_IO_CTRL);
+       wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, temp_regv | SIRFUART_RX_MODE_IO);
+       wr_regl(port, SIRFUART_TX_DMA_IO_LEN, 0);
+       wr_regl(port, SIRFUART_RX_DMA_IO_LEN, 0);
+       wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_RX_EN | SIRFUART_TX_EN);
+       wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_RESET);
+       wr_regl(port, SIRFUART_TX_FIFO_OP, 0);
+       wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
+       wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
+       temp = port->line == 1 ? 16 : 64;
+       wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp);
+       wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp);
+}
+
+static int sirfsoc_uart_startup(struct uart_port *port)
+{
+       struct sirfsoc_uart_port *sirfport      = to_sirfport(port);
+       unsigned int index                      = port->line;
+       int ret;
+       set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
+       ret = request_irq(port->irq,
+                               sirfsoc_uart_isr,
+                               0,
+                               SIRFUART_PORT_NAME,
+                               sirfport);
+       if (ret != 0) {
+               dev_err(port->dev, "UART%d request IRQ line (%d) failed.\n",
+                                                       index, port->irq);
+               goto irq_err;
+       }
+       startup_uart_controller(port);
+       enable_irq(port->irq);
+irq_err:
+       return ret;
+}
+
+static void sirfsoc_uart_shutdown(struct uart_port *port)
+{
+       struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+       wr_regl(port, SIRFUART_INT_EN, 0);
+       free_irq(port->irq, sirfport);
+       if (sirfport->ms_enabled) {
+               sirfsoc_uart_disable_ms(port);
+               sirfport->ms_enabled = 0;
+       }
+}
+
+static const char *sirfsoc_uart_type(struct uart_port *port)
+{
+       return port->type == SIRFSOC_PORT_TYPE ? SIRFUART_PORT_NAME : NULL;
+}
+
+static int sirfsoc_uart_request_port(struct uart_port *port)
+{
+       void *ret;
+       ret = request_mem_region(port->mapbase,
+                               SIRFUART_MAP_SIZE, SIRFUART_PORT_NAME);
+       return ret ? 0 : -EBUSY;
+}
+
+static void sirfsoc_uart_release_port(struct uart_port *port)
+{
+       release_mem_region(port->mapbase, SIRFUART_MAP_SIZE);
+}
+
+static void sirfsoc_uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = SIRFSOC_PORT_TYPE;
+               sirfsoc_uart_request_port(port);
+       }
+}
+
+static struct uart_ops sirfsoc_uart_ops = {
+       .tx_empty       = sirfsoc_uart_tx_empty,
+       .get_mctrl      = sirfsoc_uart_get_mctrl,
+       .set_mctrl      = sirfsoc_uart_set_mctrl,
+       .stop_tx        = sirfsoc_uart_stop_tx,
+       .start_tx       = sirfsoc_uart_start_tx,
+       .stop_rx        = sirfsoc_uart_stop_rx,
+       .enable_ms      = sirfsoc_uart_enable_ms,
+       .break_ctl      = sirfsoc_uart_break_ctl,
+       .startup        = sirfsoc_uart_startup,
+       .shutdown       = sirfsoc_uart_shutdown,
+       .set_termios    = sirfsoc_uart_set_termios,
+       .type           = sirfsoc_uart_type,
+       .release_port   = sirfsoc_uart_release_port,
+       .request_port   = sirfsoc_uart_request_port,
+       .config_port    = sirfsoc_uart_config_port,
+};
+
+#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
+static int __init sirfsoc_uart_console_setup(struct console *co, char *options)
+{
+       unsigned int baud = 115200;
+       unsigned int bits = 8;
+       unsigned int parity = 'n';
+       unsigned int flow = 'n';
+       struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
+
+       if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
+               return -EINVAL;
+
+       if (!port->mapbase)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       port->cons = co;
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
+{
+       while (rd_regl(port,
+               SIRFUART_TX_FIFO_STATUS) & SIRFUART_FIFOFULL_MASK(port))
+               cpu_relax();
+       wr_regb(port, SIRFUART_TX_FIFO_DATA, ch);
+}
+
+static void sirfsoc_uart_console_write(struct console *co, const char *s,
+                                                       unsigned int count)
+{
+       struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
+       uart_console_write(port, s, count, sirfsoc_uart_console_putchar);
+}
+
+static struct console sirfsoc_uart_console = {
+       .name           = SIRFSOC_UART_NAME,
+       .device         = uart_console_device,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .write          = sirfsoc_uart_console_write,
+       .setup          = sirfsoc_uart_console_setup,
+       .data           = &sirfsoc_uart_drv,
+};
+
+static int __init sirfsoc_uart_console_init(void)
+{
+       register_console(&sirfsoc_uart_console);
+       return 0;
+}
+console_initcall(sirfsoc_uart_console_init);
+#endif
+
+static struct uart_driver sirfsoc_uart_drv = {
+       .owner          = THIS_MODULE,
+       .driver_name    = SIRFUART_PORT_NAME,
+       .nr             = SIRFSOC_UART_NR,
+       .dev_name       = SIRFSOC_UART_NAME,
+       .major          = SIRFSOC_UART_MAJOR,
+       .minor          = SIRFSOC_UART_MINOR,
+#ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
+       .cons                   = &sirfsoc_uart_console,
+#else
+       .cons                   = NULL,
+#endif
+};
+
+int sirfsoc_uart_probe(struct platform_device *pdev)
+{
+       struct sirfsoc_uart_port *sirfport;
+       struct uart_port *port;
+       struct resource *res;
+       int ret;
+
+       if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
+               dev_err(&pdev->dev,
+                       "Unable to find cell-index in uart node.\n");
+               ret = -EFAULT;
+               goto err;
+       }
+
+       sirfport = &sirfsoc_uart_ports[pdev->id];
+       port = &sirfport->port;
+       port->dev = &pdev->dev;
+       port->private_data = sirfport;
+
+       if (of_find_property(pdev->dev.of_node, "hw_flow_ctrl", NULL))
+               sirfport->hw_flow_ctrl = 1;
+
+       if (of_property_read_u32(pdev->dev.of_node,
+                       "fifosize",
+                       &port->fifosize)) {
+               dev_err(&pdev->dev,
+                       "Unable to find fifosize in uart node.\n");
+               ret = -EFAULT;
+               goto err;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "Insufficient resources.\n");
+               ret = -EFAULT;
+               goto err;
+       }
+       port->mapbase = res->start;
+       port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!port->membase) {
+               dev_err(&pdev->dev, "Cannot remap resource.\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "Insufficient resources.\n");
+               ret = -EFAULT;
+               goto irq_err;
+       }
+       port->irq = res->start;
+
+       if (sirfport->hw_flow_ctrl) {
+               sirfport->pmx = pinmux_get(&pdev->dev, NULL);
+               ret = IS_ERR(sirfport->pmx);
+               if (ret)
+                       goto pmx_err;
+
+               pinmux_enable(sirfport->pmx);
+       }
+
+       port->ops = &sirfsoc_uart_ops;
+       spin_lock_init(&port->lock);
+
+       platform_set_drvdata(pdev, sirfport);
+       ret = uart_add_one_port(&sirfsoc_uart_drv, port);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id);
+               goto port_err;
+       }
+
+       return 0;
+
+port_err:
+       platform_set_drvdata(pdev, NULL);
+       if (sirfport->hw_flow_ctrl) {
+               pinmux_disable(sirfport->pmx);
+               pinmux_put(sirfport->pmx);
+       }
+pmx_err:
+irq_err:
+       devm_iounmap(&pdev->dev, port->membase);
+err:
+       return ret;
+}
+
+static int sirfsoc_uart_remove(struct platform_device *pdev)
+{
+       struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
+       struct uart_port *port = &sirfport->port;
+       platform_set_drvdata(pdev, NULL);
+       if (sirfport->hw_flow_ctrl) {
+               pinmux_disable(sirfport->pmx);
+               pinmux_put(sirfport->pmx);
+       }
+       devm_iounmap(&pdev->dev, port->membase);
+       uart_remove_one_port(&sirfsoc_uart_drv, port);
+       return 0;
+}
+
+static int
+sirfsoc_uart_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct sirfsoc_uart_port *sirfport = platform_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)
+{
+       struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
+       struct uart_port *port = &sirfport->port;
+       uart_resume_port(&sirfsoc_uart_drv, port);
+       return 0;
+}
+
+static struct of_device_id sirfsoc_uart_ids[] __devinitdata = {
+       { .compatible = "sirf,prima2-uart", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, sirfsoc_serial_of_match);
+
+static struct platform_driver sirfsoc_uart_driver = {
+       .probe          = sirfsoc_uart_probe,
+       .remove         = __devexit_p(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,
+       },
+};
+
+static int __init sirfsoc_uart_init(void)
+{
+       int ret = 0;
+
+       ret = uart_register_driver(&sirfsoc_uart_drv);
+       if (ret)
+               goto out;
+
+       ret = platform_driver_register(&sirfsoc_uart_driver);
+       if (ret)
+               uart_unregister_driver(&sirfsoc_uart_drv);
+out:
+       return ret;
+}
+module_init(sirfsoc_uart_init);
+
+static void __exit sirfsoc_uart_exit(void)
+{
+       platform_driver_unregister(&sirfsoc_uart_driver);
+       uart_unregister_driver(&sirfsoc_uart_drv);
+}
+module_exit(sirfsoc_uart_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Bin Shi <Bin.Shi@csr.com>, Rong Wang<Rong.Wang@csr.com>");
+MODULE_DESCRIPTION("CSR SiRFprimaII Uart Driver");
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
new file mode 100644 (file)
index 0000000..fc64260
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Drivers for CSR SiRFprimaII onboard UARTs.
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+#include <linux/bitops.h>
+
+/* UART Register Offset Define */
+#define SIRFUART_LINE_CTRL                     0x0040
+#define SIRFUART_TX_RX_EN                      0x004c
+#define SIRFUART_DIVISOR                       0x0050
+#define SIRFUART_INT_EN                                0x0054
+#define SIRFUART_INT_STATUS                    0x0058
+#define SIRFUART_TX_DMA_IO_CTRL                        0x0100
+#define SIRFUART_TX_DMA_IO_LEN                 0x0104
+#define SIRFUART_TX_FIFO_CTRL                  0x0108
+#define SIRFUART_TX_FIFO_LEVEL_CHK             0x010C
+#define SIRFUART_TX_FIFO_OP                    0x0110
+#define SIRFUART_TX_FIFO_STATUS                        0x0114
+#define SIRFUART_TX_FIFO_DATA                  0x0118
+#define SIRFUART_RX_DMA_IO_CTRL                        0x0120
+#define SIRFUART_RX_DMA_IO_LEN                 0x0124
+#define SIRFUART_RX_FIFO_CTRL                  0x0128
+#define SIRFUART_RX_FIFO_LEVEL_CHK             0x012C
+#define SIRFUART_RX_FIFO_OP                    0x0130
+#define SIRFUART_RX_FIFO_STATUS                        0x0134
+#define SIRFUART_RX_FIFO_DATA                  0x0138
+#define SIRFUART_AFC_CTRL                      0x0140
+#define SIRFUART_SWH_DMA_IO                    0x0148
+
+/* UART Line Control Register */
+#define SIRFUART_DATA_BIT_LEN_MASK             0x3
+#define SIRFUART_DATA_BIT_LEN_5                        BIT(0)
+#define SIRFUART_DATA_BIT_LEN_6                        1
+#define SIRFUART_DATA_BIT_LEN_7                        2
+#define SIRFUART_DATA_BIT_LEN_8                        3
+#define SIRFUART_STOP_BIT_LEN_1                        0
+#define SIRFUART_STOP_BIT_LEN_2                        BIT(2)
+#define SIRFUART_PARITY_EN                     BIT(3)
+#define SIRFUART_EVEN_BIT                      BIT(4)
+#define SIRFUART_STICK_BIT_MASK                        (7 << 3)
+#define SIRFUART_STICK_BIT_NONE                        (0 << 3)
+#define SIRFUART_STICK_BIT_EVEN                        BIT(3)
+#define SIRFUART_STICK_BIT_ODD                 (3 << 3)
+#define SIRFUART_STICK_BIT_MARK                        (5 << 3)
+#define SIRFUART_STICK_BIT_SPACE               (7 << 3)
+#define SIRFUART_SET_BREAK                     BIT(6)
+#define SIRFUART_LOOP_BACK                     BIT(7)
+#define SIRFUART_PARITY_MASK                   (7 << 3)
+#define SIRFUART_DUMMY_READ                    BIT(16)
+
+#define SIRFSOC_UART_RX_TIMEOUT(br, to)        (((br) * (((to) + 999) / 1000)) / 1000)
+#define SIRFUART_RECV_TIMEOUT_MASK     (0xFFFF << 16)
+#define SIRFUART_RECV_TIMEOUT(x)       (((x) & 0xFFFF) << 16)
+
+/* UART Auto Flow Control */
+#define SIRFUART_AFC_RX_THD_MASK               0x000000FF
+#define SIRFUART_AFC_RX_EN                     BIT(8)
+#define SIRFUART_AFC_TX_EN                     BIT(9)
+#define SIRFUART_CTS_CTRL                      BIT(10)
+#define SIRFUART_RTS_CTRL                      BIT(11)
+#define SIRFUART_CTS_IN_STATUS                 BIT(12)
+#define SIRFUART_RTS_OUT_STATUS                        BIT(13)
+
+/* UART Interrupt Enable Register */
+#define SIRFUART_RX_DONE_INT                   BIT(0)
+#define SIRFUART_TX_DONE_INT                   BIT(1)
+#define SIRFUART_RX_OFLOW_INT                  BIT(2)
+#define SIRFUART_TX_ALLOUT_INT                 BIT(3)
+#define SIRFUART_RX_IO_DMA_INT                 BIT(4)
+#define SIRFUART_TX_IO_DMA_INT                 BIT(5)
+#define SIRFUART_RXFIFO_FULL_INT               BIT(6)
+#define SIRFUART_TXFIFO_EMPTY_INT              BIT(7)
+#define SIRFUART_RXFIFO_THD_INT                        BIT(8)
+#define SIRFUART_TXFIFO_THD_INT                        BIT(9)
+#define SIRFUART_FRM_ERR_INT                   BIT(10)
+#define SIRFUART_RXD_BREAK_INT                 BIT(11)
+#define SIRFUART_RX_TIMEOUT_INT                        BIT(12)
+#define SIRFUART_PARITY_ERR_INT                        BIT(13)
+#define SIRFUART_CTS_INT_EN                    BIT(14)
+#define SIRFUART_RTS_INT_EN                    BIT(15)
+
+/* UART Interrupt Status Register */
+#define SIRFUART_RX_DONE                       BIT(0)
+#define SIRFUART_TX_DONE                       BIT(1)
+#define SIRFUART_RX_OFLOW                      BIT(2)
+#define SIRFUART_TX_ALL_EMPTY                  BIT(3)
+#define SIRFUART_DMA_IO_RX_DONE                        BIT(4)
+#define SIRFUART_DMA_IO_TX_DONE                        BIT(5)
+#define SIRFUART_RXFIFO_FULL                   BIT(6)
+#define SIRFUART_TXFIFO_EMPTY                  BIT(7)
+#define SIRFUART_RXFIFO_THD_REACH              BIT(8)
+#define SIRFUART_TXFIFO_THD_REACH              BIT(9)
+#define SIRFUART_FRM_ERR                       BIT(10)
+#define SIRFUART_RXD_BREAK                     BIT(11)
+#define SIRFUART_RX_TIMEOUT                    BIT(12)
+#define SIRFUART_PARITY_ERR                    BIT(13)
+#define SIRFUART_CTS_CHANGE                    BIT(14)
+#define SIRFUART_RTS_CHANGE                    BIT(15)
+#define SIRFUART_PLUG_IN                       BIT(16)
+
+#define SIRFUART_ERR_INT_STAT                                  \
+                               (SIRFUART_RX_OFLOW |            \
+                               SIRFUART_FRM_ERR |              \
+                               SIRFUART_RXD_BREAK |            \
+                               SIRFUART_PARITY_ERR)
+#define SIRFUART_ERR_INT_EN                                    \
+                               (SIRFUART_RX_OFLOW_INT |        \
+                               SIRFUART_FRM_ERR_INT |          \
+                               SIRFUART_RXD_BREAK_INT |        \
+                               SIRFUART_PARITY_ERR_INT)
+#define SIRFUART_TX_INT_EN     SIRFUART_TXFIFO_EMPTY_INT
+#define SIRFUART_RX_IO_INT_EN                                  \
+                               (SIRFUART_RX_TIMEOUT_INT |      \
+                               SIRFUART_RXFIFO_THD_INT |       \
+                               SIRFUART_RXFIFO_FULL_INT |      \
+                               SIRFUART_ERR_INT_EN)
+
+/* UART FIFO Register */
+#define SIRFUART_TX_FIFO_STOP                  0x0
+#define SIRFUART_TX_FIFO_RESET                 0x1
+#define SIRFUART_TX_FIFO_START                 0x2
+#define SIRFUART_RX_FIFO_STOP                  0x0
+#define SIRFUART_RX_FIFO_RESET                 0x1
+#define SIRFUART_RX_FIFO_START                 0x2
+#define SIRFUART_TX_MODE_DMA                   0
+#define SIRFUART_TX_MODE_IO                    1
+#define SIRFUART_RX_MODE_DMA                   0
+#define SIRFUART_RX_MODE_IO                    1
+
+#define SIRFUART_RX_EN                         0x1
+#define SIRFUART_TX_EN                         0x2
+
+/* Generic Definitions */
+#define SIRFSOC_UART_NAME                      "ttySiRF"
+#define SIRFSOC_UART_MAJOR                     0
+#define SIRFSOC_UART_MINOR                     0
+#define SIRFUART_PORT_NAME                     "sirfsoc-uart"
+#define SIRFUART_MAP_SIZE                      0x200
+#define SIRFSOC_UART_NR                                3
+#define SIRFSOC_PORT_TYPE                      0xa5
+
+/* Baud Rate Calculation */
+#define SIRF_MIN_SAMPLE_DIV                    0xf
+#define SIRF_MAX_SAMPLE_DIV                    0x3f
+#define SIRF_IOCLK_DIV_MAX                     0xffff
+#define SIRF_SAMPLE_DIV_SHIFT                  16
+#define SIRF_IOCLK_DIV_MASK                    0xffff
+#define SIRF_SAMPLE_DIV_MASK                   0x3f0000
+#define SIRF_BAUD_RATE_SUPPORT_NR              18
+
+/* For Fast Baud Rate Calculation */
+struct sirfsoc_baudrate_to_regv {
+       unsigned int baud_rate;
+       unsigned int reg_val;
+};
+
+struct sirfsoc_uart_port {
+       unsigned char                   hw_flow_ctrl;
+       unsigned char                   ms_enabled;
+
+       struct uart_port                port;
+       struct pinmux                   *pmx;
+};
+
+/* Hardware Flow Control */
+#define SIRFUART_AFC_CTRL_RX_THD       0x70
+
+/* Register Access Control */
+#define portaddr(port, reg)            ((port)->membase + (reg))
+#define rd_regb(port, reg)             (__raw_readb(portaddr(port, reg)))
+#define rd_regl(port, reg)             (__raw_readl(portaddr(port, reg)))
+#define wr_regb(port, reg, val)                __raw_writeb(val, portaddr(port, reg))
+#define wr_regl(port, reg, val)                __raw_writel(val, portaddr(port, reg))
+
+/* UART Port Mask */
+#define SIRFUART_FIFOLEVEL_MASK(port)  ((port->line == 1) ? (0x1f) : (0x7f))
+#define SIRFUART_FIFOFULL_MASK(port)   ((port->line == 1) ? (0x20) : (0x80))
+#define SIRFUART_FIFOEMPTY_MASK(port)  ((port->line == 1) ? (0x40) : (0x100))
+
+/* I/O Mode */
+#define SIRFSOC_UART_IO_RX_MAX_CNT             256
+#define SIRFSOC_UART_IO_TX_REASONABLE_CNT      6
index e76c8b747fb83876dbf3c685c41fdb4dcedd4415..70f97491d8f28a2771bac4c563b8e781014d522d 100644 (file)
@@ -513,20 +513,7 @@ static struct platform_driver timbuart_platform_driver = {
        .remove         = __devexit_p(timbuart_remove),
 };
 
-/*--------------------------------------------------------------------------*/
-
-static int __init timbuart_init(void)
-{
-       return platform_driver_register(&timbuart_platform_driver);
-}
-
-static void __exit timbuart_exit(void)
-{
-       platform_driver_unregister(&timbuart_platform_driver);
-}
-
-module_init(timbuart_init);
-module_exit(timbuart_exit);
+module_platform_driver(timbuart_platform_driver);
 
 MODULE_DESCRIPTION("Timberdale UART driver");
 MODULE_LICENSE("GPL v2");
index 3beb6ab4fa6888df10523307b15c1b81524961d4..83148e79ca13a79693c5a8d21672d36533a03a08 100644 (file)
@@ -961,18 +961,7 @@ static struct platform_driver siu_device_driver = {
        },
 };
 
-static int __init vr41xx_siu_init(void)
-{
-       return platform_driver_register(&siu_device_driver);
-}
-
-static void __exit vr41xx_siu_exit(void)
-{
-       platform_driver_unregister(&siu_device_driver);
-}
-
-module_init(vr41xx_siu_init);
-module_exit(vr41xx_siu_exit);
+module_platform_driver(siu_device_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:SIU");
index 3fdebd306b9436e11c6f65d457464b8723895a10..e41b9bbc107dcb688bc6653e5dc379794657dbf9 100644 (file)
@@ -790,19 +790,24 @@ static void session_clear_tty(struct pid *session)
 void disassociate_ctty(int on_exit)
 {
        struct tty_struct *tty;
-       struct pid *tty_pgrp = NULL;
 
        if (!current->signal->leader)
                return;
 
        tty = get_current_tty();
        if (tty) {
-               tty_pgrp = get_pid(tty->pgrp);
+               struct pid *tty_pgrp = get_pid(tty->pgrp);
                if (on_exit) {
                        if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
                                tty_vhangup(tty);
                }
                tty_kref_put(tty);
+               if (tty_pgrp) {
+                       kill_pgrp(tty_pgrp, SIGHUP, on_exit);
+                       if (!on_exit)
+                               kill_pgrp(tty_pgrp, SIGCONT, on_exit);
+                       put_pid(tty_pgrp);
+               }
        } else if (on_exit) {
                struct pid *old_pgrp;
                spin_lock_irq(&current->sighand->siglock);
@@ -816,12 +821,6 @@ void disassociate_ctty(int on_exit)
                }
                return;
        }
-       if (tty_pgrp) {
-               kill_pgrp(tty_pgrp, SIGHUP, on_exit);
-               if (!on_exit)
-                       kill_pgrp(tty_pgrp, SIGCONT, on_exit);
-               put_pid(tty_pgrp);
-       }
 
        spin_lock_irq(&current->sighand->siglock);
        put_pid(current->signal->tty_old_pgrp);
@@ -1557,6 +1556,59 @@ static void release_tty(struct tty_struct *tty, int idx)
        tty_kref_put(tty);
 }
 
+/**
+ *     tty_release_checks - check a tty before real release
+ *     @tty: tty to check
+ *     @o_tty: link of @tty (if any)
+ *     @idx: index of the tty
+ *
+ *     Performs some paranoid checking before true release of the @tty.
+ *     This is a no-op unless TTY_PARANOIA_CHECK is defined.
+ */
+static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty,
+               int idx)
+{
+#ifdef TTY_PARANOIA_CHECK
+       if (idx < 0 || idx >= tty->driver->num) {
+               printk(KERN_DEBUG "%s: bad idx when trying to free (%s)\n",
+                               __func__, tty->name);
+               return -1;
+       }
+
+       /* not much to check for devpts */
+       if (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)
+               return 0;
+
+       if (tty != tty->driver->ttys[idx]) {
+               printk(KERN_DEBUG "%s: driver.table[%d] not tty for (%s)\n",
+                               __func__, idx, tty->name);
+               return -1;
+       }
+       if (tty->termios != tty->driver->termios[idx]) {
+               printk(KERN_DEBUG "%s: driver.termios[%d] not termios for (%s)\n",
+                               __func__, idx, tty->name);
+               return -1;
+       }
+       if (tty->driver->other) {
+               if (o_tty != tty->driver->other->ttys[idx]) {
+                       printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n",
+                                       __func__, idx, tty->name);
+                       return -1;
+               }
+               if (o_tty->termios != tty->driver->other->termios[idx]) {
+                       printk(KERN_DEBUG "%s: other->termios[%d] not o_termios for (%s)\n",
+                                       __func__, idx, tty->name);
+                       return -1;
+               }
+               if (o_tty->link != tty) {
+                       printk(KERN_DEBUG "%s: bad pty pointers\n", __func__);
+                       return -1;
+               }
+       }
+#endif
+       return 0;
+}
+
 /**
  *     tty_release             -       vfs callback for close
  *     @inode: inode of tty
@@ -1585,11 +1637,11 @@ int tty_release(struct inode *inode, struct file *filp)
        int     idx;
        char    buf[64];
 
-       if (tty_paranoia_check(tty, inode, "tty_release_dev"))
+       if (tty_paranoia_check(tty, inode, __func__))
                return 0;
 
        tty_lock();
-       check_tty_count(tty, "tty_release_dev");
+       check_tty_count(tty, __func__);
 
        __tty_fasync(-1, filp, 0);
 
@@ -1599,59 +1651,16 @@ int tty_release(struct inode *inode, struct file *filp)
        devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
        o_tty = tty->link;
 
-#ifdef TTY_PARANOIA_CHECK
-       if (idx < 0 || idx >= tty->driver->num) {
-               printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
-                                 "free (%s)\n", tty->name);
+       if (tty_release_checks(tty, o_tty, idx)) {
                tty_unlock();
                return 0;
        }
-       if (!devpts) {
-               if (tty != tty->driver->ttys[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
-                              "for (%s)\n", idx, tty->name);
-                       return 0;
-               }
-               if (tty->termios != tty->driver->termios[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
-                              "for (%s)\n",
-                              idx, tty->name);
-                       return 0;
-               }
-       }
-#endif
 
 #ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
-              tty_name(tty, buf), tty->count);
+       printk(KERN_DEBUG "%s: %s (tty count=%d)...\n", __func__,
+                       tty_name(tty, buf), tty->count);
 #endif
 
-#ifdef TTY_PARANOIA_CHECK
-       if (tty->driver->other &&
-            !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
-               if (o_tty != tty->driver->other->ttys[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
-                                         "not o_tty for (%s)\n",
-                              idx, tty->name);
-                       return 0 ;
-               }
-               if (o_tty->termios != tty->driver->other->termios[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
-                                         "not o_termios for (%s)\n",
-                              idx, tty->name);
-                       return 0;
-               }
-               if (o_tty->link != tty) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
-                       return 0;
-               }
-       }
-#endif
        if (tty->ops->close)
                tty->ops->close(tty, filp);
 
@@ -1707,8 +1716,8 @@ int tty_release(struct inode *inode, struct file *filp)
                if (!do_sleep)
                        break;
 
-               printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
-                                   "active!\n", tty_name(tty, buf));
+               printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
+                               __func__, tty_name(tty, buf));
                tty_unlock();
                mutex_unlock(&tty_mutex);
                schedule();
@@ -1721,15 +1730,14 @@ int tty_release(struct inode *inode, struct file *filp)
         */
        if (pty_master) {
                if (--o_tty->count < 0) {
-                       printk(KERN_WARNING "tty_release_dev: bad pty slave count "
-                                           "(%d) for %s\n",
-                              o_tty->count, tty_name(o_tty, buf));
+                       printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n",
+                               __func__, o_tty->count, tty_name(o_tty, buf));
                        o_tty->count = 0;
                }
        }
        if (--tty->count < 0) {
-               printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
-                      tty->count, tty_name(tty, buf));
+               printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n",
+                               __func__, tty->count, tty_name(tty, buf));
                tty->count = 0;
        }
 
@@ -1778,7 +1786,7 @@ int tty_release(struct inode *inode, struct file *filp)
        }
 
 #ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "freeing tty structure...");
+       printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
 #endif
        /*
         * Ask the line discipline code to release its structures
@@ -1797,6 +1805,83 @@ int tty_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
+/**
+ *     tty_open_current_tty - get tty of current task for open
+ *     @device: device number
+ *     @filp: file pointer to tty
+ *     @return: tty of the current task iff @device is /dev/tty
+ *
+ *     We cannot return driver and index like for the other nodes because
+ *     devpts will not work then. It expects inodes to be from devpts FS.
+ */
+static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
+{
+       struct tty_struct *tty;
+
+       if (device != MKDEV(TTYAUX_MAJOR, 0))
+               return NULL;
+
+       tty = get_current_tty();
+       if (!tty)
+               return ERR_PTR(-ENXIO);
+
+       filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
+       /* noctty = 1; */
+       tty_kref_put(tty);
+       /* FIXME: we put a reference and return a TTY! */
+       return tty;
+}
+
+/**
+ *     tty_lookup_driver - lookup a tty driver for a given device file
+ *     @device: device number
+ *     @filp: file pointer to tty
+ *     @noctty: set if the device should not become a controlling tty
+ *     @index: index for the device in the @return driver
+ *     @return: driver for this inode (with increased refcount)
+ *
+ *     If @return is not erroneous, the caller is responsible to decrement the
+ *     refcount by tty_driver_kref_put.
+ *
+ *     Locking: tty_mutex protects get_tty_driver
+ */
+static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
+               int *noctty, int *index)
+{
+       struct tty_driver *driver;
+
+       switch (device) {
+#ifdef CONFIG_VT
+       case MKDEV(TTY_MAJOR, 0): {
+               extern struct tty_driver *console_driver;
+               driver = tty_driver_kref_get(console_driver);
+               *index = fg_console;
+               *noctty = 1;
+               break;
+       }
+#endif
+       case MKDEV(TTYAUX_MAJOR, 1): {
+               struct tty_driver *console_driver = console_device(index);
+               if (console_driver) {
+                       driver = tty_driver_kref_get(console_driver);
+                       if (driver) {
+                               /* Don't let /dev/console block */
+                               filp->f_flags |= O_NONBLOCK;
+                               *noctty = 1;
+                               break;
+                       }
+               }
+               return ERR_PTR(-ENODEV);
+       }
+       default:
+               driver = get_tty_driver(device, index);
+               if (!driver)
+                       return ERR_PTR(-ENODEV);
+               break;
+       }
+       return driver;
+}
+
 /**
  *     tty_open                -       open a tty device
  *     @inode: inode of device file
@@ -1813,16 +1898,16 @@ int tty_release(struct inode *inode, struct file *filp)
  *     The termios state of a pty is reset on first open so that
  *     settings don't persist across reuse.
  *
- *     Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
+ *     Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
  *              tty->count should protect the rest.
  *              ->siglock protects ->signal/->sighand
  */
 
 static int tty_open(struct inode *inode, struct file *filp)
 {
-       struct tty_struct *tty = NULL;
+       struct tty_struct *tty;
        int noctty, retval;
-       struct tty_driver *driver;
+       struct tty_driver *driver = NULL;
        int index;
        dev_t device = inode->i_rdev;
        unsigned saved_flags = filp->f_flags;
@@ -1841,66 +1926,22 @@ retry_open:
        mutex_lock(&tty_mutex);
        tty_lock();
 
-       if (device == MKDEV(TTYAUX_MAJOR, 0)) {
-               tty = get_current_tty();
-               if (!tty) {
-                       tty_unlock();
-                       mutex_unlock(&tty_mutex);
-                       tty_free_file(filp);
-                       return -ENXIO;
-               }
-               driver = tty_driver_kref_get(tty->driver);
-               index = tty->index;
-               filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
-               /* noctty = 1; */
-               /* FIXME: Should we take a driver reference ? */
-               tty_kref_put(tty);
-               goto got_driver;
-       }
-#ifdef CONFIG_VT
-       if (device == MKDEV(TTY_MAJOR, 0)) {
-               extern struct tty_driver *console_driver;
-               driver = tty_driver_kref_get(console_driver);
-               index = fg_console;
-               noctty = 1;
-               goto got_driver;
-       }
-#endif
-       if (device == MKDEV(TTYAUX_MAJOR, 1)) {
-               struct tty_driver *console_driver = console_device(&index);
-               if (console_driver) {
-                       driver = tty_driver_kref_get(console_driver);
-                       if (driver) {
-                               /* Don't let /dev/console block */
-                               filp->f_flags |= O_NONBLOCK;
-                               noctty = 1;
-                               goto got_driver;
-                       }
+       tty = tty_open_current_tty(device, filp);
+       if (IS_ERR(tty)) {
+               retval = PTR_ERR(tty);
+               goto err_unlock;
+       } else if (!tty) {
+               driver = tty_lookup_driver(device, filp, &noctty, &index);
+               if (IS_ERR(driver)) {
+                       retval = PTR_ERR(driver);
+                       goto err_unlock;
                }
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               tty_free_file(filp);
-               return -ENODEV;
-       }
 
-       driver = get_tty_driver(device, &index);
-       if (!driver) {
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               tty_free_file(filp);
-               return -ENODEV;
-       }
-got_driver:
-       if (!tty) {
                /* check whether we're reopening an existing tty */
                tty = tty_driver_lookup_tty(driver, inode, index);
-
                if (IS_ERR(tty)) {
-                       tty_unlock();
-                       mutex_unlock(&tty_mutex);
-                       tty_driver_kref_put(driver);
-                       tty_free_file(filp);
-                       return PTR_ERR(tty);
+                       retval = PTR_ERR(tty);
+                       goto err_unlock;
                }
        }
 
@@ -1912,21 +1953,22 @@ got_driver:
                tty = tty_init_dev(driver, index, 0);
 
        mutex_unlock(&tty_mutex);
-       tty_driver_kref_put(driver);
+       if (driver)
+               tty_driver_kref_put(driver);
        if (IS_ERR(tty)) {
                tty_unlock();
-               tty_free_file(filp);
-               return PTR_ERR(tty);
+               retval = PTR_ERR(tty);
+               goto err_file;
        }
 
        tty_add_file(tty, filp);
 
-       check_tty_count(tty, "tty_open");
+       check_tty_count(tty, __func__);
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
            tty->driver->subtype == PTY_TYPE_MASTER)
                noctty = 1;
 #ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "opening %s...", tty->name);
+       printk(KERN_DEBUG "%s: opening %s...\n", __func__, tty->name);
 #endif
        if (tty->ops->open)
                retval = tty->ops->open(tty, filp);
@@ -1940,8 +1982,8 @@ got_driver:
 
        if (retval) {
 #ifdef TTY_DEBUG_HANGUP
-               printk(KERN_DEBUG "error %d in opening %s...", retval,
-                      tty->name);
+               printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
+                               retval, tty->name);
 #endif
                tty_unlock(); /* need to call tty_release without BTM */
                tty_release(inode, filp);
@@ -1976,6 +2018,15 @@ got_driver:
        tty_unlock();
        mutex_unlock(&tty_mutex);
        return 0;
+err_unlock:
+       tty_unlock();
+       mutex_unlock(&tty_mutex);
+       /* after locks to avoid deadlock */
+       if (!IS_ERR_OR_NULL(driver))
+               tty_driver_kref_put(driver);
+err_file:
+       tty_free_file(filp);
+       return retval;
 }
 
 
index 8e0924f55446f963b8b9d79a0d66347d30c982bc..24b95db75d84f8d6f42705bdfb57b622abcce322 100644 (file)
@@ -1,19 +1,11 @@
 #include <linux/types.h>
-#include <linux/major.h>
 #include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
+#include <linux/kmod.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
 #include <linux/file.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/bitops.h>
-#include <linux/delay.h>
 #include <linux/seq_file.h>
-
 #include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
 #include <linux/ratelimit.h>
 
 /*
@@ -558,8 +540,6 @@ static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
        long ret;
        ret = wait_event_timeout(tty_ldisc_idle,
                        atomic_read(&tty->ldisc->users) == 1, timeout);
-       if (ret < 0)
-               return ret;
        return ret > 0 ? 0 : -EBUSY;
 }
 
index 45d3e80156d45e15d08a1fa164686031126adc4c..a0f3d6c4d39d045008d4dd8d74b61e06a15b52f7 100644 (file)
@@ -584,7 +584,7 @@ int con_set_default_unimap(struct vc_data *vc)
                        return 0;
                dflt->refcount++;
                *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
-               if (p && --p->refcount) {
+               if (p && !--p->refcount) {
                        con_release_unimap(p);
                        kfree(p);
                }
index 1f05bbeac01e3605b7e11bd544e3edc7483c474a..8f012f8ac8e9164106231f77c6d2ae5e4105cc90 100644 (file)
@@ -66,6 +66,7 @@ enum {
  * dependent on the 8250 driver.
  */
 struct uart_port;
+struct uart_8250_port;
 
 int serial8250_register_port(struct uart_port *);
 void serial8250_unregister_port(int line);
@@ -81,7 +82,11 @@ extern void serial8250_do_set_termios(struct uart_port *port,
                struct ktermios *termios, struct ktermios *old);
 extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
                             unsigned int oldstate);
+extern int fsl8250_handle_irq(struct uart_port *port);
 int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
+unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);
+void serial8250_tx_chars(struct uart_8250_port *up);
+unsigned int serial8250_modem_status(struct uart_8250_port *up);
 
 extern void serial8250_set_isa_configurator(void (*v)
                                        (int port, struct uart_port *up,
index eadf33d0abba4b936d8ddd5421ad68a05c2b5dc6..b67305e3ad57a5078b79fec8bca9f060739e08e1 100644 (file)
@@ -351,6 +351,7 @@ struct uart_port {
 #define UPF_CONS_FLOW          ((__force upf_t) (1 << 23))
 #define UPF_SHARE_IRQ          ((__force upf_t) (1 << 24))
 #define UPF_EXAR_EFR           ((__force upf_t) (1 << 25))
+#define UPF_IIR_ONCE           ((__force upf_t) (1 << 26))
 /* The exact UART type is known and should not be probed.  */
 #define UPF_FIXED_TYPE         ((__force upf_t) (1 << 27))
 #define UPF_BOOT_AUTOCONF      ((__force upf_t) (1 << 28))
@@ -483,10 +484,19 @@ static inline int uart_tx_stopped(struct uart_port *port)
 /*
  * The following are helper functions for the low level drivers.
  */
+
+extern void uart_handle_dcd_change(struct uart_port *uport,
+               unsigned int status);
+extern void uart_handle_cts_change(struct uart_port *uport,
+               unsigned int status);
+
+extern void uart_insert_char(struct uart_port *port, unsigned int status,
+                unsigned int overrun, unsigned int ch, unsigned int flag);
+
+#ifdef SUPPORT_SYSRQ
 static inline int
 uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
 {
-#ifdef SUPPORT_SYSRQ
        if (port->sysrq) {
                if (ch && time_before(jiffies, port->sysrq)) {
                        handle_sysrq(ch);
@@ -495,11 +505,10 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
                }
                port->sysrq = 0;
        }
-#endif
        return 0;
 }
-#ifndef SUPPORT_SYSRQ
-#define uart_handle_sysrq_char(port,ch) uart_handle_sysrq_char(port, 0)
+#else
+#define uart_handle_sysrq_char(port,ch) ({ (void)port; 0; })
 #endif
 
 /*
@@ -522,89 +531,6 @@ static inline int uart_handle_break(struct uart_port *port)
        return 0;
 }
 
-/**
- *     uart_handle_dcd_change - handle a change of carrier detect state
- *     @uport: uart_port structure for the open port
- *     @status: new carrier detect status, nonzero if active
- */
-static inline void
-uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
-{
-       struct uart_state *state = uport->state;
-       struct tty_port *port = &state->port;
-       struct tty_ldisc *ld = tty_ldisc_ref(port->tty);
-       struct pps_event_time ts;
-
-       if (ld && ld->ops->dcd_change)
-               pps_get_ts(&ts);
-
-       uport->icount.dcd++;
-#ifdef CONFIG_HARD_PPS
-       if ((uport->flags & UPF_HARDPPS_CD) && status)
-               hardpps();
-#endif
-
-       if (port->flags & ASYNC_CHECK_CD) {
-               if (status)
-                       wake_up_interruptible(&port->open_wait);
-               else if (port->tty)
-                       tty_hangup(port->tty);
-       }
-
-       if (ld && ld->ops->dcd_change)
-               ld->ops->dcd_change(port->tty, status, &ts);
-       if (ld)
-               tty_ldisc_deref(ld);
-}
-
-/**
- *     uart_handle_cts_change - handle a change of clear-to-send state
- *     @uport: uart_port structure for the open port
- *     @status: new clear to send status, nonzero if active
- */
-static inline void
-uart_handle_cts_change(struct uart_port *uport, unsigned int status)
-{
-       struct tty_port *port = &uport->state->port;
-       struct tty_struct *tty = port->tty;
-
-       uport->icount.cts++;
-
-       if (port->flags & ASYNC_CTS_FLOW) {
-               if (tty->hw_stopped) {
-                       if (status) {
-                               tty->hw_stopped = 0;
-                               uport->ops->start_tx(uport);
-                               uart_write_wakeup(uport);
-                       }
-               } else {
-                       if (!status) {
-                               tty->hw_stopped = 1;
-                               uport->ops->stop_tx(uport);
-                       }
-               }
-       }
-}
-
-#include <linux/tty_flip.h>
-
-static inline void
-uart_insert_char(struct uart_port *port, unsigned int status,
-                unsigned int overrun, unsigned int ch, unsigned int flag)
-{
-       struct tty_struct *tty = port->state->port.tty;
-
-       if ((status & port->ignore_status_mask & ~overrun) == 0)
-               tty_insert_flip_char(tty, ch, flag);
-
-       /*
-        * Overrun is special.  Since it's reported immediately,
-        * it doesn't affect the current character.
-        */
-       if (status & ~port->ignore_status_mask & overrun)
-               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-}
-
 /*
  *     UART_ENABLE_MS - determine if port should enable modem status irqs
  */