USB: ehci: omap: fix kernel panic with rmmod
[safe/jmp/linux-2.6] / drivers / serial / serial_txx9.c
index 1deb576..c50e9fb 100644 (file)
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/console.h>
-#include <linux/sysrq.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/pci.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
-#include <linux/mutex.h>
 
 #include <asm/io.h>
 
-static char *serial_version = "1.09";
+static char *serial_version = "1.11";
 static char *serial_name = "TX39/49 Serial driver";
 
 #define PASS_LIMIT     256
@@ -68,8 +64,6 @@ static char *serial_name = "TX39/49 Serial driver";
  */
 #define UART_NR  CONFIG_SERIAL_TXX9_NR_UARTS
 
-#define HIGH_BITS_OFFSET       ((sizeof(long)-sizeof(int))*8)
-
 struct uart_txx9_port {
        struct uart_port        port;
        /* No additional info for now */
@@ -227,21 +221,26 @@ sio_quot_set(struct uart_txx9_port *up, int quot)
                sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6);
 }
 
+static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port)
+{
+       return container_of(port, struct uart_txx9_port, port);
+}
+
 static void serial_txx9_stop_tx(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
 }
 
 static void serial_txx9_start_tx(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
 }
 
 static void serial_txx9_stop_rx(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
 }
 
@@ -252,7 +251,7 @@ static void serial_txx9_enable_ms(struct uart_port *port)
 
 static void serial_txx9_initialize(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        unsigned int tmout = 10000;
 
        sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
@@ -278,7 +277,7 @@ static void serial_txx9_initialize(struct uart_port *port)
 static inline void
 receive_chars(struct uart_txx9_port *up, unsigned int *status)
 {
-       struct tty_struct *tty = up->port.info->tty;
+       struct tty_struct *tty = up->port.state->port.tty;
        unsigned char ch;
        unsigned int disr = *status;
        int max_count = 256;
@@ -354,7 +353,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status)
 
 static inline void transmit_chars(struct uart_txx9_port *up)
 {
-       struct circ_buf *xmit = &up->port.info->xmit;
+       struct circ_buf *xmit = &up->port.state->xmit;
        int count;
 
        if (up->port.x_char) {
@@ -420,7 +419,7 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
 
 static unsigned int serial_txx9_tx_empty(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        unsigned long flags;
        unsigned int ret;
 
@@ -433,18 +432,20 @@ static unsigned int serial_txx9_tx_empty(struct uart_port *port)
 
 static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        unsigned int ret;
 
-       ret =  ((sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS)
-               | ((sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS);
+       /* no modem control lines */
+       ret = TIOCM_CAR | TIOCM_DSR;
+       ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS;
+       ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS;
 
        return ret;
 }
 
 static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
 
        if (mctrl & TIOCM_RTS)
                sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
@@ -454,7 +455,7 @@ static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        unsigned long flags;
 
        spin_lock_irqsave(&up->port.lock, flags);
@@ -465,9 +466,97 @@ static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
        spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
+#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || (CONFIG_CONSOLE_POLL)
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static void wait_for_xmitr(struct uart_txx9_port *up)
+{
+       unsigned int tmout = 10000;
+
+       /* Wait up to 10ms for the character(s) to be sent. */
+       while (--tmout &&
+              !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS))
+               udelay(1);
+
+       /* Wait up to 1s for flow control if necessary */
+       if (up->port.flags & UPF_CONS_FLOW) {
+               tmout = 1000000;
+               while (--tmout &&
+                      (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
+                       udelay(1);
+       }
+}
+#endif
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static int serial_txx9_get_poll_char(struct uart_port *port)
+{
+       unsigned int ier;
+       unsigned char c;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       while (sio_in(up, TXX9_SIDISR) & TXX9_SIDISR_UVALID)
+               ;
+
+       c = sio_in(up, TXX9_SIRFIFO);
+
+       /*
+        *      Finally, clear RX interrupt status
+        *      and restore the IER
+        */
+       sio_mask(up, TXX9_SIDISR, TXX9_SIDISR_RDIS);
+       sio_out(up, TXX9_SIDICR, ier);
+       return c;
+}
+
+
+static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
+{
+       unsigned int ier;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
+
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = sio_in(up, TXX9_SIDICR);
+       sio_out(up, TXX9_SIDICR, 0);
+
+       wait_for_xmitr(up);
+       /*
+        *      Send the character out.
+        *      If a LF, also do CR...
+        */
+       sio_out(up, TXX9_SITFIFO, c);
+       if (c == 10) {
+               wait_for_xmitr(up);
+               sio_out(up, TXX9_SITFIFO, 13);
+       }
+
+       /*
+        *      Finally, wait for transmitter to become empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(up);
+       sio_out(up, TXX9_SIDICR, ier);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
 static int serial_txx9_startup(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        unsigned long flags;
        int retval;
 
@@ -512,7 +601,7 @@ static int serial_txx9_startup(struct uart_port *port)
 
 static void serial_txx9_shutdown(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        unsigned long flags;
 
        /*
@@ -552,11 +641,17 @@ static void
 serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
                       struct ktermios *old)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        unsigned int cval, fcr = 0;
        unsigned long flags;
        unsigned int baud, quot;
 
+       /*
+        * We don't support modem control lines.
+        */
+       termios->c_cflag &= ~(HUPCL | CMSPAR);
+       termios->c_cflag |= CLOCAL;
+
        cval = sio_in(up, TXX9_SILCR);
        /* byte size and parity */
        cval &= ~TXX9_SILCR_UMODE_MASK;
@@ -655,7 +750,15 @@ static void
 serial_txx9_pm(struct uart_port *port, unsigned int state,
              unsigned int oldstate)
 {
-       if (state == 0)
+       /*
+        * If oldstate was -1 this is called from
+        * uart_configure_port().  In this case do not initialize the
+        * port now, because the port was already initialized (for
+        * non-console port) or should not be initialized here (for
+        * console port).  If we initialized the port here we lose
+        * serial console settings.
+        */
+       if (state == 0 && oldstate != -1)
                serial_txx9_initialize(port);
 }
 
@@ -716,19 +819,19 @@ static void serial_txx9_release_resource(struct uart_txx9_port *up)
 
 static void serial_txx9_release_port(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        serial_txx9_release_resource(up);
 }
 
 static int serial_txx9_request_port(struct uart_port *port)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        return serial_txx9_request_resource(up);
 }
 
 static void serial_txx9_config_port(struct uart_port *port, int uflags)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
        int ret;
 
        /*
@@ -748,21 +851,6 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
        serial_txx9_initialize(port);
 }
 
-static int
-serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-       unsigned long new_port = ser->port;
-       if (HIGH_BITS_OFFSET)
-               new_port += (unsigned long)ser->port_high << HIGH_BITS_OFFSET;
-       if (ser->type != port->type ||
-           ser->irq != port->irq ||
-           ser->io_type != port->iotype ||
-           new_port != port->iobase ||
-           (unsigned long)ser->iomem_base != port->mapbase)
-               return -EINVAL;
-       return 0;
-}
-
 static const char *
 serial_txx9_type(struct uart_port *port)
 {
@@ -786,7 +874,10 @@ static struct uart_ops serial_txx9_pops = {
        .release_port   = serial_txx9_release_port,
        .request_port   = serial_txx9_request_port,
        .config_port    = serial_txx9_config_port,
-       .verify_port    = serial_txx9_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = serial_txx9_get_poll_char,
+       .poll_put_char  = serial_txx9_put_poll_char,
+#endif
 };
 
 static struct uart_txx9_port serial_txx9_ports[UART_NR];
@@ -809,30 +900,9 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv,
 
 #ifdef CONFIG_SERIAL_TXX9_CONSOLE
 
-/*
- *     Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_txx9_port *up)
-{
-       unsigned int tmout = 10000;
-
-       /* Wait up to 10ms for the character(s) to be sent. */
-       while (--tmout &&
-              !(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS))
-               udelay(1);
-
-       /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & UPF_CONS_FLOW) {
-               tmout = 1000000;
-               while (--tmout &&
-                      (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
-                       udelay(1);
-       }
-}
-
 static void serial_txx9_console_putchar(struct uart_port *port, int ch)
 {
-       struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+       struct uart_txx9_port *up = to_uart_txx9_port(port);
 
        wait_for_xmitr(up);
        sio_out(up, TXX9_SITFIFO, ch);
@@ -942,7 +1012,8 @@ int __init early_serial_txx9_setup(struct uart_port *port)
 
        serial_txx9_ports[port->line].port = *port;
        serial_txx9_ports[port->line].port.ops = &serial_txx9_pops;
-       serial_txx9_ports[port->line].port.flags |= UPF_BOOT_AUTOCONF;
+       serial_txx9_ports[port->line].port.flags |=
+               UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
        return 0;
 }
 
@@ -987,7 +1058,8 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
                uart->port.irq      = port->irq;
                uart->port.uartclk  = port->uartclk;
                uart->port.iotype   = port->iotype;
-               uart->port.flags    = port->flags | UPF_BOOT_AUTOCONF;
+               uart->port.flags    = port->flags
+                       | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
                uart->port.mapbase  = port->mapbase;
                if (port->dev)
                        uart->port.dev = port->dev;
@@ -1043,8 +1115,9 @@ static int __devinit serial_txx9_probe(struct platform_device *dev)
                ret = serial_txx9_register_port(&port);
                if (ret < 0) {
                        dev_err(&dev->dev, "unable to register port at index %d "
-                               "(IO%x MEM%lx IRQ%d): %d\n", i,
-                               p->iobase, p->mapbase, p->irq, ret);
+                               "(IO%lx MEM%llx IRQ%d): %d\n", i,
+                               p->iobase, (unsigned long long)p->mapbase,
+                               p->irq, ret);
                }
        }
        return 0;