USB: cdc_acm: Fix memory leak after hangup
[safe/jmp/linux-2.6] / drivers / serial / sunzilog.c
index 1d262c0..ef693ae 100644 (file)
 #include <linux/serio.h>
 #endif
 #include <linux/init.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_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
        readb(&((__channel)->control))
 #endif
 
-static int num_sunzilog;
-#define NUM_SUNZILOG   num_sunzilog
-#define NUM_CHANNELS   (NUM_SUNZILOG * 2)
-
 #define ZS_CLOCK               4915200 /* Zilog input clock rate. */
 #define ZS_CLOCK_DIVISOR       16      /* Divisor this driver uses. */
 
@@ -332,9 +328,9 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
        unsigned char ch, r1, flag;
 
        tty = NULL;
-       if (up->port.info != NULL &&            /* Unopened serial console */
-           up->port.info->tty != NULL)         /* Keyboard || mouse */
-               tty = up->port.info->tty;
+       if (up->port.state != NULL &&           /* Unopened serial console */
+           up->port.state->port.tty != NULL)   /* Keyboard || mouse */
+               tty = up->port.state->port.tty;
 
        for (;;) {
 
@@ -455,7 +451,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
                        uart_handle_cts_change(&up->port,
                                               (status & CTS));
 
-               wake_up_interruptible(&up->port.info->delta_msr_wait);
+               wake_up_interruptible(&up->port.state->port.delta_msr_wait);
        }
 
        up->prev_status = status;
@@ -505,9 +501,9 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
                return;
        }
 
-       if (up->port.info == NULL)
+       if (up->port.state == NULL)
                goto ack_tx_int;
-       xmit = &up->port.info->xmit;
+       xmit = &up->port.state->xmit;
        if (uart_circ_empty(xmit))
                goto ack_tx_int;
 
@@ -709,7 +705,7 @@ static void sunzilog_start_tx(struct uart_port *port)
                port->icount.tx++;
                port->x_char = 0;
        } else {
-               struct circ_buf *xmit = &port->info->xmit;
+               struct circ_buf *xmit = &port->state->xmit;
 
                writeb(xmit->buf[xmit->tail], &channel->data);
                ZSDELAY();
@@ -1019,6 +1015,7 @@ static struct uart_ops sunzilog_pops = {
        .verify_port    =       sunzilog_verify_port,
 };
 
+static int uart_chip_count;
 static struct uart_sunzilog_port *sunzilog_port_table;
 static struct zilog_layout __iomem **sunzilog_chip_regs;
 
@@ -1026,23 +1023,24 @@ static struct uart_sunzilog_port *sunzilog_irq_chain;
 
 static struct uart_driver sunzilog_reg = {
        .owner          =       THIS_MODULE,
-       .driver_name    =       "ttyS",
+       .driver_name    =       "sunzilog",
        .dev_name       =       "ttyS",
        .major          =       TTY_MAJOR,
 };
 
-static int __init sunzilog_alloc_tables(void)
+static int __init sunzilog_alloc_tables(int num_sunzilog)
 {
        struct uart_sunzilog_port *up;
        unsigned long size;
+       int num_channels = num_sunzilog * 2;
        int i;
 
-       size = NUM_CHANNELS * sizeof(struct uart_sunzilog_port);
+       size = num_channels * sizeof(struct uart_sunzilog_port);
        sunzilog_port_table = kzalloc(size, GFP_KERNEL);
        if (!sunzilog_port_table)
                return -ENOMEM;
 
-       for (i = 0; i < NUM_CHANNELS; i++) {
+       for (i = 0; i < num_channels; i++) {
                up = &sunzilog_port_table[i];
 
                spin_lock_init(&up->port.lock);
@@ -1050,13 +1048,13 @@ static int __init sunzilog_alloc_tables(void)
                if (i == 0)
                        sunzilog_irq_chain = up;
 
-               if (i < NUM_CHANNELS - 1)
+               if (i < num_channels - 1)
                        up->next = up + 1;
                else
                        up->next = NULL;
        }
 
-       size = NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *);
+       size = num_sunzilog * sizeof(struct zilog_layout __iomem *);
        sunzilog_chip_regs = kzalloc(size, GFP_KERNEL);
        if (!sunzilog_chip_regs) {
                kfree(sunzilog_port_table);
@@ -1233,7 +1231,7 @@ static inline struct console *SUNZILOG_CONSOLE(void)
 #define SUNZILOG_CONSOLE()     (NULL)
 #endif
 
-static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel)
+static void __devinit sunzilog_init_kbdms(struct uart_sunzilog_port *up)
 {
        int baud, brg;
 
@@ -1307,7 +1305,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
                up->curregs[R7] = 0x7E; /* SDLC Flag    */
                up->curregs[R9] = NV;
                up->curregs[R7p] = 0x00;
-               sunzilog_init_kbdms(up, up->port.line);
+               sunzilog_init_kbdms(up);
                /* Only enable interrupts if an ISR handler available */
                if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
                        up->curregs[R9] |= MIE;
@@ -1353,16 +1351,22 @@ static int zilog_irq = -1;
 
 static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match)
 {
-       static int inst;
+       static int kbm_inst, uart_inst;
+       int inst;
        struct uart_sunzilog_port *up;
        struct zilog_layout __iomem *rp;
-       int keyboard_mouse;
+       int keyboard_mouse = 0;
        int err;
 
-       keyboard_mouse = 0;
        if (of_find_property(op->node, "keyboard", NULL))
                keyboard_mouse = 1;
 
+       /* uarts must come before keyboards/mice */
+       if (keyboard_mouse)
+               inst = uart_chip_count + kbm_inst;
+       else
+               inst = uart_inst;
+
        sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
                                              sizeof(struct zilog_layout),
                                              "zs");
@@ -1430,21 +1434,23 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
                                   rp, sizeof(struct zilog_layout));
                        return err;
                }
+               uart_inst++;
        } else {
-               printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) "
+               printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) "
                       "is a %s\n",
-                      op->dev.bus_id, up[0].port.mapbase, op->irqs[0],
-                      sunzilog_type (&up[0].port));
-               printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) "
+                      dev_name(&op->dev),
+                      (unsigned long long) up[0].port.mapbase,
+                      op->irqs[0], sunzilog_type(&up[0].port));
+               printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) "
                       "is a %s\n",
-                      op->dev.bus_id, up[1].port.mapbase, op->irqs[0],
-                      sunzilog_type (&up[1].port));
+                      dev_name(&op->dev),
+                      (unsigned long long) up[1].port.mapbase,
+                      op->irqs[0], sunzilog_type(&up[1].port));
+               kbm_inst++;
        }
 
        dev_set_drvdata(&op->dev, &up[0]);
 
-       inst++;
-
        return 0;
 }
 
@@ -1474,7 +1480,7 @@ static int __devexit zs_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id zs_match[] = {
+static const struct of_device_id zs_match[] = {
        {
                .name = "zs",
        },
@@ -1492,36 +1498,27 @@ static struct of_platform_driver zs_driver = {
 static int __init sunzilog_init(void)
 {
        struct device_node *dp;
-       int err, uart_count;
-       int num_keybms;
+       int err;
+       int num_keybms = 0;
+       int num_sunzilog = 0;
 
-       NUM_SUNZILOG = 0;
-       num_keybms = 0;
        for_each_node_by_name(dp, "zs") {
-               NUM_SUNZILOG++;
+               num_sunzilog++;
                if (of_find_property(dp, "keyboard", NULL))
                        num_keybms++;
        }
 
-       uart_count = 0;
-       if (NUM_SUNZILOG) {
-               int uart_count;
-
-               err = sunzilog_alloc_tables();
+       if (num_sunzilog) {
+               err = sunzilog_alloc_tables(num_sunzilog);
                if (err)
                        goto out;
 
-               uart_count = (NUM_SUNZILOG * 2) - (2 * num_keybms);
+               uart_chip_count = num_sunzilog - num_keybms;
 
-               sunzilog_reg.nr = uart_count;
-               sunzilog_reg.minor = sunserial_current_minor;
-               err = uart_register_driver(&sunzilog_reg);
+               err = sunserial_register_minors(&sunzilog_reg,
+                                               uart_chip_count * 2);
                if (err)
                        goto out_free_tables;
-
-               sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
-
-               sunserial_current_minor += uart_count;
        }
 
        err = of_register_driver(&zs_driver, &of_bus_type);
@@ -1555,8 +1552,8 @@ out_unregister_driver:
        of_unregister_driver(&zs_driver);
 
 out_unregister_uart:
-       if (NUM_SUNZILOG) {
-               uart_unregister_driver(&sunzilog_reg);
+       if (num_sunzilog) {
+               sunserial_unregister_minors(&sunzilog_reg, num_sunzilog);
                sunzilog_reg.cons = NULL;
        }
 
@@ -1588,8 +1585,8 @@ static void __exit sunzilog_exit(void)
                zilog_irq = -1;
        }
 
-       if (NUM_SUNZILOG) {
-               uart_unregister_driver(&sunzilog_reg);
+       if (sunzilog_reg.nr) {
+               sunserial_unregister_minors(&sunzilog_reg, sunzilog_reg.nr);
                sunzilog_free_tables();
        }
 }