Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / drivers / serial / sunsu.c
index 564592b..170d3d6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.55 2002/01/08 16:00:16 davem Exp $
+/*
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -17,7 +17,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/tty.h>
 #include <linux/serial_reg.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
-#include <asm/of_device.h>
 
 #if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
@@ -312,7 +311,7 @@ static void sunsu_enable_ms(struct uart_port *port)
 static struct tty_struct *
 receive_chars(struct uart_sunsu_port *up, unsigned char *status)
 {
-       struct tty_struct *tty = up->port.info->tty;
+       struct tty_struct *tty = up->port.state->port.tty;
        unsigned char ch, flag;
        int max_count = 256;
        int saw_console_brk = 0;
@@ -390,7 +389,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
 
 static void transmit_chars(struct uart_sunsu_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) {
@@ -442,7 +441,7 @@ static void check_modem_status(struct uart_sunsu_port *up)
        if (status & UART_MSR_DCTS)
                uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
 
-       wake_up_interruptible(&up->port.info->delta_msr_wait);
+       wake_up_interruptible(&up->port.state->port.delta_msr_wait);
 }
 
 static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
@@ -1174,12 +1173,12 @@ out:
 
 static struct uart_driver sunsu_reg = {
        .owner                  = THIS_MODULE,
-       .driver_name            = "serial",
+       .driver_name            = "sunsu",
        .dev_name               = "ttyS",
        .major                  = TTY_MAJOR,
 };
 
-static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up)
+static int __devinit sunsu_kbd_ms_init(struct uart_sunsu_port *up)
 {
        int quot, baud;
 #ifdef CONFIG_SERIO
@@ -1199,10 +1198,11 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up)
        if (up->port.type == PORT_UNKNOWN)
                return -ENODEV;
 
-       printk("%s: %s port at %lx, irq %u\n",
+       printk("%s: %s port at %llx, irq %u\n",
               to_of_device(up->port.dev)->node->full_name,
               (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
-              up->port.mapbase, up->port.irq);
+              (unsigned long long) up->port.mapbase,
+              up->port.irq);
 
 #ifdef CONFIG_SERIO
        serio = &up->serio;
@@ -1289,7 +1289,17 @@ static void sunsu_console_write(struct console *co, const char *s,
                                unsigned int count)
 {
        struct uart_sunsu_port *up = &sunsu_ports[co->index];
+       unsigned long flags;
        unsigned int ier;
+       int locked = 1;
+
+       local_irq_save(flags);
+       if (up->port.sysrq) {
+               locked = 0;
+       } else if (oops_in_progress) {
+               locked = spin_trylock(&up->port.lock);
+       } else
+               spin_lock(&up->port.lock);
 
        /*
         *      First save the UER then disable the interrupts
@@ -1305,6 +1315,10 @@ static void sunsu_console_write(struct console *co, const char *s,
         */
        wait_for_xmitr(up);
        serial_out(up, UART_IER, ier);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
 }
 
 /*
@@ -1313,13 +1327,11 @@ static void sunsu_console_write(struct console *co, const char *s,
  *     - initialize the serial port
  *     Return non-zero if we didn't find a serial port.
  */
-static int sunsu_console_setup(struct console *co, char *options)
+static int __init sunsu_console_setup(struct console *co, char *options)
 {
+       static struct ktermios dummy;
+       struct ktermios termios;
        struct uart_port *port;
-       int baud = 9600;
-       int bits = 8;
-       int parity = 'n';
-       int flow = 'n';
 
        printk("Console: ttyS%d (SU)\n",
               (sunsu_reg.minor - 64) + co->index);
@@ -1338,13 +1350,18 @@ static int sunsu_console_setup(struct console *co, char *options)
         */
        spin_lock_init(&port->lock);
 
-       if (options)
-               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       /* Get firmware console settings.  */
+       sunserial_console_termios(co, to_of_device(port->dev)->node);
+
+       memset(&termios, 0, sizeof(struct ktermios));
+       termios.c_cflag = co->cflag;
+       port->mctrl |= TIOCM_DTR;
+       port->ops->set_termios(port, &termios, &dummy);
 
-       return uart_set_options(port, co, baud, parity, bits, flow);
+       return 0;
 }
 
-static struct console sunsu_cons = {
+static struct console sunsu_console = {
        .name   =       "ttyS",
        .write  =       sunsu_console_write,
        .device =       uart_console_device,
@@ -1358,28 +1375,12 @@ static struct console sunsu_cons = {
  *     Register console.
  */
 
-static inline struct console *SUNSU_CONSOLE(int num_uart)
+static inline struct console *SUNSU_CONSOLE(void)
 {
-       int i;
-
-       if (con_is_present())
-               return NULL;
-
-       for (i = 0; i < num_uart; i++) {
-               int this_minor = sunsu_reg.minor + i;
-
-               if ((this_minor - 64) == (serial_console - 1))
-                       break;
-       }
-       if (i == num_uart)
-               return NULL;
-
-       sunsu_cons.index = i;
-
-       return &sunsu_cons;
+       return &sunsu_console;
 }
 #else
-#define SUNSU_CONSOLE(num_uart)                (NULL)
+#define SUNSU_CONSOLE()                        (NULL)
 #define sunsu_serial_console_init()    do { } while (0)
 #endif
 
@@ -1388,8 +1389,8 @@ static enum su_type __devinit su_get_type(struct device_node *dp)
        struct device_node *ap = of_find_node_by_path("/aliases");
 
        if (ap) {
-               char *keyb = of_get_property(ap, "keyboard", NULL);
-               char *ms = of_get_property(ap, "mouse", NULL);
+               const char *keyb = of_get_property(ap, "keyboard", NULL);
+               const char *ms = of_get_property(ap, "mouse", NULL);
 
                if (keyb) {
                        if (dp == of_find_node_by_path(keyb))
@@ -1411,6 +1412,7 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
        struct uart_sunsu_port *up;
        struct resource *rp;
        enum su_type type;
+       bool ignore_line;
        int err;
 
        type = su_get_type(dp);
@@ -1469,6 +1471,14 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
 
        up->port.ops = &sunsu_pops;
 
+       ignore_line = false;
+       if (!strcmp(dp->name, "rsc-console") ||
+           !strcmp(dp->name, "lom-console"))
+               ignore_line = true;
+
+       sunserial_console_match(SUNSU_CONSOLE(), dp,
+                               &sunsu_reg, up->port.line,
+                               ignore_line);
        err = uart_add_one_port(&sunsu_reg, &up->port);
        if (err)
                goto out_unmap;
@@ -1480,13 +1490,13 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
        return 0;
 
 out_unmap:
-       of_iounmap(up->port.membase, up->reg_size);
+       of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
        return err;
 }
 
-static int __devexit su_remove(struct of_device *dev)
+static int __devexit su_remove(struct of_device *op)
 {
-       struct uart_sunsu_port *up = dev_get_drvdata(&dev->dev);;
+       struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
 
        if (up->su_type == SU_PORT_MS ||
            up->su_type == SU_PORT_KBD) {
@@ -1499,14 +1509,14 @@ static int __devexit su_remove(struct of_device *dev)
        }
 
        if (up->port.membase)
-               of_iounmap(up->port.membase, up->reg_size);
+               of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id su_match[] = {
+static const struct of_device_id su_match[] = {
        {
                .name = "su",
        },
@@ -1517,6 +1527,10 @@ static struct of_device_id su_match[] = {
                .name = "serial",
                .compatible = "su",
        },
+       {
+               .type = "serial",
+               .compatible = "su",
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, su_match);
@@ -1528,14 +1542,12 @@ static struct of_platform_driver su_driver = {
        .remove         = __devexit_p(su_remove),
 };
 
-static int num_uart;
-
 static int __init sunsu_init(void)
 {
        struct device_node *dp;
        int err;
+       int num_uart = 0;
 
-       num_uart = 0;
        for_each_node_by_name(dp, "su") {
                if (su_get_type(dp) == SU_PORT_PORT)
                        num_uart++;
@@ -1550,29 +1562,30 @@ static int __init sunsu_init(void)
                                num_uart++;
                }
        }
+       for_each_node_by_type(dp, "serial") {
+               if (of_device_is_compatible(dp, "su")) {
+                       if (su_get_type(dp) == SU_PORT_PORT)
+                               num_uart++;
+               }
+       }
 
        if (num_uart) {
-               sunsu_reg.minor = sunserial_current_minor;
-               sunsu_reg.nr = num_uart;
-               err = uart_register_driver(&sunsu_reg);
+               err = sunserial_register_minors(&sunsu_reg, num_uart);
                if (err)
                        return err;
-               sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
-               sunserial_current_minor += num_uart;
-               sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
        }
 
        err = of_register_driver(&su_driver, &of_bus_type);
        if (err && num_uart)
-               uart_unregister_driver(&sunsu_reg);
+               sunserial_unregister_minors(&sunsu_reg, num_uart);
 
        return err;
 }
 
 static void __exit sunsu_exit(void)
 {
-       if (num_uart)
-               uart_unregister_driver(&sunsu_reg);
+       if (sunsu_reg.nr)
+               sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr);
 }
 
 module_init(sunsu_init);