Char: cyclades, dynamic ports
[powerpc.git] / drivers / char / cyclades.c
index ab9ad66..7fe4bb6 100644 (file)
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-#define        CY_LOCK(info,flags)                                     \
-               do {                                            \
-               spin_lock_irqsave(&info->card->card_lock, flags); \
-               } while (0)
-
-#define        CY_UNLOCK(info,flags)                                   \
-               do {                                            \
-               spin_unlock_irqrestore(&info->card->card_lock, flags); \
-               } while (0)
-
 #include <linux/kernel.h>
 #include <linux/pci.h>
 
@@ -732,11 +722,6 @@ module_param_array(irq, int, NULL, 0);
 */
 static struct cyclades_card cy_card[NR_CARDS];
 
-/* This is the per-channel data structure containing pointers, flags
- and variables for the port. This driver supports a maximum of NR_PORTS.
-*/
-static struct cyclades_port cy_port[NR_PORTS];
-
 static int cy_next_channel;    /* next minor available */
 
 /*
@@ -865,13 +850,6 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
                return 1;
        }
 
-       if ((long)info < (long)(&cy_port[0]) ||
-                       (long)(&cy_port[NR_PORTS]) < (long)info) {
-               printk(KERN_WARNING "cyc Warning: cyclades_port out of range "
-                               "for (%s) in %s\n", name, routine);
-               return 1;
-       }
-
        if (info->magic != CYCLADES_MAGIC) {
                printk(KERN_WARNING "cyc Warning: bad magic number for serial "
                                "struct (%s) in %s\n", name, routine);
@@ -1035,7 +1013,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
        struct cyclades_port *info;
        struct tty_struct *tty;
        int char_count;
-       int i, j, len, mdm_change, mdm_status, outch;
+       int j, len, mdm_change, mdm_status, outch;
        int save_xir, channel, save_car;
        char data;
 
@@ -1047,13 +1025,12 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
                spin_lock(&cinfo->card_lock);
                save_xir = (u_char) readb(base_addr + (CyRIR << index));
                channel = (u_short) (save_xir & CyIRChannel);
-               i = channel + chip * 4 + cinfo->first_line;
-               info = &cy_port[i];
+               info = &cinfo->ports[channel + chip * 4];
                save_car = readb(base_addr + (CyCAR << index));
                cy_writeb(base_addr + (CyCAR << index), save_xir);
 
                /* if there is nowhere to put the data, discard it */
-               if (info->tty == 0) {
+               if (info->tty == NULL) {
                        j = (readb(base_addr + (CyRIVR << index)) &
                                CyIVRMask);
                        if (j == CyIVRRxEx) {   /* exception */
@@ -1212,19 +1189,18 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
                spin_lock(&cinfo->card_lock);
                save_xir = (u_char) readb(base_addr + (CyTIR << index));
                channel = (u_short) (save_xir & CyIRChannel);
-               i = channel + chip * 4 + cinfo->first_line;
                save_car = readb(base_addr + (CyCAR << index));
                cy_writeb(base_addr + (CyCAR << index), save_xir);
 
                /* validate the port# (as configured and open) */
-               if ((i < 0) || (NR_PORTS <= i)) {
+               if (channel + chip * 4 >= cinfo->nports) {
                        cy_writeb(base_addr + (CySRER << index),
                                  readb(base_addr + (CySRER << index)) &
                                  ~CyTxRdy);
                        goto txend;
                }
-               info = &cy_port[i];
-               if (info->tty == 0) {
+               info = &cinfo->ports[channel + chip * 4];
+               if (info->tty == NULL) {
                        cy_writeb(base_addr + (CySRER << index),
                                  readb(base_addr + (CySRER << index)) &
                                  ~CyTxRdy);
@@ -1273,7 +1249,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
                                }
                                goto txdone;
                        }
-                       if (info->xmit_buf == 0) {
+                       if (info->xmit_buf == NULL) {
                                cy_writeb(base_addr + (CySRER << index),
                                        readb(base_addr + (CySRER << index)) &
                                        ~CyTxRdy);
@@ -1314,7 +1290,6 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
                                                0);
                                        info->icount.tx++;
                                        char_count--;
-                               } else {
                                }
                        }
                }
@@ -1336,16 +1311,14 @@ txend:
                spin_lock(&cinfo->card_lock);
                save_xir = (u_char) readb(base_addr + (CyMIR << index));
                channel = (u_short) (save_xir & CyIRChannel);
-               info = &cy_port[channel + chip * 4 + cinfo->first_line];
+               info = &cinfo->ports[channel + chip * 4];
                save_car = readb(base_addr + (CyCAR << index));
                cy_writeb(base_addr + (CyCAR << index), save_xir);
 
                mdm_change = readb(base_addr + (CyMISR << index));
                mdm_status = readb(base_addr + (CyMSVR1 << index));
 
-               if (info->tty == 0) {   /* no place for data, ignore it */
-                       ;
-               } else {
+               if (info->tty) {
                        if (mdm_change & CyANY_DELTA) {
                                /* For statistics only */
                                if (mdm_change & CyDCD)
@@ -1399,10 +1372,10 @@ txend:
                                        }
                                }
                        }
-                       if (mdm_change & CyDSR) {
+/*                     if (mdm_change & CyDSR) {
                        }
                        if (mdm_change & CyRI) {
-                       }
+                       }*/
                }
                /* end of service */
                cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
@@ -1418,14 +1391,14 @@ txend:
 static irqreturn_t cyy_interrupt(int irq, void *dev_id)
 {
        int status;
-       struct cyclades_card *cinfo;
+       struct cyclades_card *cinfo = dev_id;
        void __iomem *base_addr, *card_base_addr;
        int chip;
        int index;
        int too_many;
        int had_work;
 
-       if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+       if (unlikely(cinfo == NULL)) {
 #ifdef CY_DEBUG_INTERRUPTS
                printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq);
 #endif
@@ -1574,7 +1547,7 @@ cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
                        info->mon.char_max = char_count;
                info->mon.char_last = char_count;
 #endif
-               if (tty == 0) {
+               if (tty == NULL) {
                        /* flush received characters */
                        new_rx_get = (new_rx_get + char_count) &
                                        (rx_bufsize - 1);
@@ -1660,9 +1633,8 @@ cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
 
        if (char_count) {
 
-               if (tty == 0) {
+               if (tty == NULL)
                        goto ztxdone;
-               }
 
                if (info->x_char) {     /* send special char */
                        data = info->x_char;
@@ -1740,10 +1712,10 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
        while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
                special_count = 0;
                delta_count = 0;
-               info = &cy_port[channel + cinfo->first_line];
-               if ((tty = info->tty) == 0) {
+               info = &cinfo->ports[channel];
+               if ((tty = info->tty) == NULL)
                        continue;
-               }
+
                ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
                buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
 
@@ -1832,16 +1804,16 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
 #ifdef CONFIG_CYZ_INTR
 static irqreturn_t cyz_interrupt(int irq, void *dev_id)
 {
-       struct cyclades_card *cinfo;
+       struct cyclades_card *cinfo = dev_id;
 
-       if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+       if (unlikely(cinfo == NULL)) {
 #ifdef CY_DEBUG_INTERRUPTS
                printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);
 #endif
                return IRQ_NONE;        /* spurious interrupt */
        }
 
-       if (!ISZLOADED(*cinfo)) {
+       if (unlikely(!ISZLOADED(*cinfo))) {
 #ifdef CY_DEBUG_INTERRUPTS
                printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
                                "(IRQ%d).\n", irq);
@@ -1863,13 +1835,13 @@ static void cyz_rx_restart(unsigned long arg)
        __u32 channel = info->line - card->first_line;
        unsigned long flags;
 
-       CY_LOCK(info, flags);
+       spin_lock_irqsave(&card->card_lock, flags);
        retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
        if (retval != 0) {
                printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
                        info->line, retval);
        }
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&card->card_lock, flags);
 }
 
 #else                          /* CONFIG_CYZ_INTR */
@@ -1910,7 +1882,7 @@ static void cyz_poll(unsigned long arg)
                cyz_handle_cmd(cinfo);
 
                for (port = 0; port < cinfo->nports; port++) {
-                       info = &cy_port[port + cinfo->first_line];
+                       info = &cinfo->ports[port];
                        tty = info->tty;
                        ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
                        buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
@@ -1949,7 +1921,7 @@ static int startup(struct cyclades_port *info)
        if (!page)
                return -ENOMEM;
 
-       CY_LOCK(info, flags);
+       spin_lock_irqsave(&card->card_lock, flags);
 
        if (info->flags & ASYNC_INITIALIZED) {
                free_page(page);
@@ -1969,7 +1941,7 @@ static int startup(struct cyclades_port *info)
        else
                info->xmit_buf = (unsigned char *)page;
 
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&card->card_lock, flags);
 
        set_line_char(info);
 
@@ -1984,7 +1956,7 @@ static int startup(struct cyclades_port *info)
                                "base_addr %p\n",
                                card, chip, channel, base_addr);
 #endif
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
 
                cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
 
@@ -2020,7 +1992,7 @@ static int startup(struct cyclades_port *info)
                info->idle_stats.recv_idle =
                info->idle_stats.xmit_idle = jiffies;
 
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
 
        } else {
                struct FIRM_ID __iomem *firm_id;
@@ -2045,7 +2017,7 @@ static int startup(struct cyclades_port *info)
                printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
                        "base_addr %p\n", card, channel, base_addr);
 #endif
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
 
                cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
 #ifdef Z_WAKE
@@ -2085,8 +2057,7 @@ static int startup(struct cyclades_port *info)
                cy_writel(&ch_ctrl[channel].rs_control,
                        readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
                        C_RS_DTR);
-               retval = cyz_issue_cmd(info->card, channel,
-                               C_CM_IOCTLM, 0L);
+               retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
                if (retval != 0) {
                        printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was "
                                "%x\n", info->line, retval);
@@ -2108,7 +2079,7 @@ static int startup(struct cyclades_port *info)
                info->idle_stats.recv_idle =
                info->idle_stats.xmit_idle = jiffies;
 
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
        }
 
 #ifdef CY_DEBUG_OPEN
@@ -2117,7 +2088,7 @@ static int startup(struct cyclades_port *info)
        return 0;
 
 errout:
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&card->card_lock, flags);
        return retval;
 }                              /* startup */
 
@@ -2136,22 +2107,22 @@ static void start_xmit(struct cyclades_port *info)
                index = card->bus_index;
                base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
                cy_writeb(base_addr + (CyCAR << index), channel);
                cy_writeb(base_addr + (CySRER << index),
                        readb(base_addr + (CySRER << index)) | CyTxRdy);
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
        } else {
 #ifdef CONFIG_CYZ_INTR
                int retval;
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
                retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
                if (retval != 0) {
                        printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
                                "%x\n", info->line, retval);
                }
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
 #else                          /* CONFIG_CYZ_INTR */
                /* Don't have to do anything at this time */
 #endif                         /* CONFIG_CYZ_INTR */
@@ -2187,7 +2158,7 @@ static void shutdown(struct cyclades_port *info)
                                card, chip, channel, base_addr);
 #endif
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
 
                /* Clear delta_msr_wait queue to avoid mem leaks. */
                wake_up_interruptible(&info->delta_msr_wait);
@@ -2217,7 +2188,7 @@ static void shutdown(struct cyclades_port *info)
                        set_bit(TTY_IO_ERROR, &info->tty->flags);
                }
                info->flags &= ~ASYNC_INITIALIZED;
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
        } else {
                struct FIRM_ID __iomem *firm_id;
                struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -2241,7 +2212,7 @@ static void shutdown(struct cyclades_port *info)
                board_ctrl = &zfw_ctrl->board_ctrl;
                ch_ctrl = zfw_ctrl->ch_ctrl;
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
 
                if (info->xmit_buf) {
                        unsigned char *temp;
@@ -2270,7 +2241,7 @@ static void shutdown(struct cyclades_port *info)
                }
                info->flags &= ~ASYNC_INITIALIZED;
 
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
        }
 
 #ifdef CY_DEBUG_OPEN
@@ -2330,10 +2301,10 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
        printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, "
                "count = %d\n", info->line, info->count);
 #endif
-       CY_LOCK(info, flags);
+       spin_lock_irqsave(&cinfo->card_lock, flags);
        if (!tty_hung_up_p(filp))
                info->count--;
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&cinfo->card_lock, flags);
 #ifdef CY_DEBUG_COUNT
        printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to "
                "%d\n", current->pid, info->count);
@@ -2347,7 +2318,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
                base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
 
                while (1) {
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&cinfo->card_lock, flags);
                        if ((tty->termios->c_cflag & CBAUD)) {
                                cy_writeb(base_addr + (CyCAR << index),
                                          (u_char) channel);
@@ -2363,7 +2334,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
                                        readb(base_addr + (CyMSVR2 << index)));
 #endif
                        }
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&cinfo->card_lock, flags);
 
                        set_current_state(TASK_INTERRUPTIBLE);
                        if (tty_hung_up_p(filp) ||
@@ -2373,16 +2344,16 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
                                break;
                        }
 
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&cinfo->card_lock, flags);
                        cy_writeb(base_addr + (CyCAR << index),
                                  (u_char) channel);
                        if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
                                        (readb(base_addr +
                                                (CyMSVR1 << index)) & CyDCD))) {
-                               CY_UNLOCK(info, flags);
+                               spin_unlock_irqrestore(&cinfo->card_lock, flags);
                                break;
                        }
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&cinfo->card_lock, flags);
 
                        if (signal_pending(current)) {
                                retval = -ERESTARTSYS;
@@ -2419,7 +2390,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
                                cy_writel(&ch_ctrl[channel].rs_control,
                                        readl(&ch_ctrl[channel].rs_control) |
                                        C_RS_RTS | C_RS_DTR);
-                               retval = cyz_issue_cmd(info->card,
+                               retval = cyz_issue_cmd(cinfo,
                                        channel, C_CM_IOCTLM, 0L);
                                if (retval != 0) {
                                        printk(KERN_ERR "cyc:block_til_ready "
@@ -2483,13 +2454,20 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
 static int cy_open(struct tty_struct *tty, struct file *filp)
 {
        struct cyclades_port *info;
+       unsigned int i;
        int retval, line;
 
        line = tty->index;
        if ((line < 0) || (NR_PORTS <= line)) {
                return -ENODEV;
        }
-       info = &cy_port[line];
+       for (i = 0; i < NR_CARDS; i++)
+               if (line < cy_card[i].first_line + cy_card[i].nports &&
+                               line >= cy_card[i].first_line)
+                       break;
+       if (i >= NR_CARDS)
+               return -ENODEV;
+       info = &cy_card[i].ports[line - cy_card[i].first_line];
        if (info->line < 0) {
                return -ENODEV;
        }
@@ -2672,8 +2650,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
                                        timeout))
                                break;
                }
-       } else {
-               /* Nothing to do! */
        }
        /* Run one more char cycle */
        msleep_interruptible(jiffies_to_msecs(char_time * 5));
@@ -2688,6 +2664,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
 static void cy_close(struct tty_struct *tty, struct file *filp)
 {
        struct cyclades_port *info = tty->driver_data;
+       struct cyclades_card *card;
        unsigned long flags;
 
 #ifdef CY_DEBUG_OTHER
@@ -2698,10 +2675,12 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
                return;
        }
 
-       CY_LOCK(info, flags);
+       card = info->card;
+
+       spin_lock_irqsave(&card->card_lock, flags);
        /* If the TTY is being hung up, nothing to do */
        if (tty_hung_up_p(filp)) {
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
                return;
        }
 #ifdef CY_DEBUG_OPEN
@@ -2731,7 +2710,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
                info->count = 0;
        }
        if (info->count) {
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
                return;
        }
        info->flags |= ASYNC_CLOSING;
@@ -2741,16 +2720,16 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&card->card_lock, flags);
        if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
                tty_wait_until_sent(tty, info->closing_wait);
        }
-       CY_LOCK(info, flags);
+       spin_lock_irqsave(&card->card_lock, flags);
 
-       if (!IS_CYC_Z(*info->card)) {
-               int channel = info->line - info->card->first_line;
-               int index = info->card->bus_index;
-               void __iomem *base_addr = info->card->base_addr +
+       if (!IS_CYC_Z(*card)) {
+               int channel = info->line - card->first_line;
+               int index = card->bus_index;
+               void __iomem *base_addr = card->base_addr +
                        (cy_chip_offset[channel >> 2] << index);
                /* Stop accepting input */
                channel &= 0x03;
@@ -2760,53 +2739,52 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
                if (info->flags & ASYNC_INITIALIZED) {
                        /* Waiting for on-board buffers to be empty before closing
                           the port */
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&card->card_lock, flags);
                        cy_wait_until_sent(tty, info->timeout);
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&card->card_lock, flags);
                }
        } else {
 #ifdef Z_WAKE
                /* Waiting for on-board buffers to be empty before closing the port */
-               void __iomem *base_addr = info->card->base_addr;
+               void __iomem *base_addr = card->base_addr;
                struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
                struct ZFW_CTRL __iomem *zfw_ctrl =
                    base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
                struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
-               int channel = info->line - info->card->first_line;
+               int channel = info->line - card->first_line;
                int retval;
 
                if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
-                       retval = cyz_issue_cmd(info->card, channel,
-                                               C_CM_IOCTLW, 0L);
+                       retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
                        if (retval != 0) {
                                printk(KERN_DEBUG "cyc:cy_close retval on "
                                        "ttyC%d was %x\n", info->line, retval);
                        }
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&card->card_lock, flags);
                        wait_for_completion_interruptible(&info->shutdown_wait);
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&card->card_lock, flags);
                }
 #endif
        }
 
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&card->card_lock, flags);
        shutdown(info);
        if (tty->driver->flush_buffer)
                tty->driver->flush_buffer(tty);
        tty_ldisc_flush(tty);
-       CY_LOCK(info, flags);
+       spin_lock_irqsave(&card->card_lock, flags);
 
        tty->closing = 0;
        info->event = 0;
        info->tty = NULL;
        if (info->blocked_open) {
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
                if (info->close_delay) {
                        msleep_interruptible(jiffies_to_msecs
                                                (info->close_delay));
                }
                wake_up_interruptible(&info->open_wait);
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
        }
        info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
        wake_up_interruptible(&info->close_wait);
@@ -2815,7 +2793,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
        printk(KERN_DEBUG "cyc:cy_close done\n");
 #endif
 
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&card->card_lock, flags);
 }                              /* cy_close */
 
 /* This routine gets called when tty_write has put something into
@@ -2848,7 +2826,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
        if (!info->xmit_buf)
                return 0;
 
-       CY_LOCK(info, flags);
+       spin_lock_irqsave(&info->card->card_lock, flags);
        while (1) {
                c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
                                   (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
@@ -2864,7 +2842,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
                count -= c;
                ret += c;
        }
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&info->card->card_lock, flags);
 
        info->idle_stats.xmit_bytes += ret;
        info->idle_stats.xmit_idle = jiffies;
@@ -2897,9 +2875,9 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
        if (!info->xmit_buf)
                return;
 
-       CY_LOCK(info, flags);
+       spin_lock_irqsave(&info->card->card_lock, flags);
        if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&info->card->card_lock, flags);
                return;
        }
 
@@ -2908,7 +2886,7 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
        info->xmit_cnt++;
        info->idle_stats.xmit_bytes++;
        info->idle_stats.xmit_idle = jiffies;
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&info->card->card_lock, flags);
 }                              /* cy_put_char */
 
 /*
@@ -3202,7 +3180,7 @@ static void set_line_char(struct cyclades_port *info)
                channel &= 0x03;
                base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
                cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
 
                /* tx and rx baud rate */
@@ -3297,7 +3275,7 @@ static void set_line_char(struct cyclades_port *info)
                if (info->tty) {
                        clear_bit(TTY_IO_ERROR, &info->tty->flags);
                }
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
 
        } else {
                struct FIRM_ID __iomem *firm_id;
@@ -3537,10 +3515,10 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
                index = card->bus_index;
                base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
                status = readb(base_addr + (CySRER << index)) &
                                (CyTxRdy | CyTxMpty);
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
                result = (status ? 0 : TIOCSER_TEMT);
        } else {
                /* Not supported yet */
@@ -3575,11 +3553,11 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
                index = card->bus_index;
                base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
                cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
                status = readb(base_addr + (CyMSVR1 << index));
                status |= readb(base_addr + (CyMSVR2 << index));
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
 
                if (info->rtsdtr_inv) {
                        result = ((status & CyRTS) ? TIOCM_DTR : 0) |
@@ -3643,7 +3621,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
                base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
                if (set & TIOCM_RTS) {
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&card->card_lock, flags);
                        cy_writeb(base_addr + (CyCAR << index),
                                  (u_char) channel);
                        if (info->rtsdtr_inv) {
@@ -3653,10 +3631,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
                                cy_writeb(base_addr + (CyMSVR1 << index),
                                          CyRTS);
                        }
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&card->card_lock, flags);
                }
                if (clear & TIOCM_RTS) {
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&card->card_lock, flags);
                        cy_writeb(base_addr + (CyCAR << index),
                                  (u_char) channel);
                        if (info->rtsdtr_inv) {
@@ -3666,10 +3644,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
                                cy_writeb(base_addr + (CyMSVR1 << index),
                                          ~CyRTS);
                        }
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&card->card_lock, flags);
                }
                if (set & TIOCM_DTR) {
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&card->card_lock, flags);
                        cy_writeb(base_addr + (CyCAR << index),
                                  (u_char) channel);
                        if (info->rtsdtr_inv) {
@@ -3685,10 +3663,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
                                readb(base_addr + (CyMSVR1 << index)),
                                readb(base_addr + (CyMSVR2 << index)));
 #endif
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&card->card_lock, flags);
                }
                if (clear & TIOCM_DTR) {
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&card->card_lock, flags);
                        cy_writeb(base_addr + (CyCAR << index),
                                  (u_char) channel);
                        if (info->rtsdtr_inv) {
@@ -3705,7 +3683,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
                                readb(base_addr + (CyMSVR1 << index)),
                                readb(base_addr + (CyMSVR2 << index)));
 #endif
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&card->card_lock, flags);
                }
        } else {
                base_addr = card->base_addr;
@@ -3718,21 +3696,21 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
                        ch_ctrl = zfw_ctrl->ch_ctrl;
 
                        if (set & TIOCM_RTS) {
-                               CY_LOCK(info, flags);
+                               spin_lock_irqsave(&card->card_lock, flags);
                                cy_writel(&ch_ctrl[channel].rs_control,
                                        readl(&ch_ctrl[channel].rs_control) |
                                        C_RS_RTS);
-                               CY_UNLOCK(info, flags);
+                               spin_unlock_irqrestore(&card->card_lock, flags);
                        }
                        if (clear & TIOCM_RTS) {
-                               CY_LOCK(info, flags);
+                               spin_lock_irqsave(&card->card_lock, flags);
                                cy_writel(&ch_ctrl[channel].rs_control,
                                        readl(&ch_ctrl[channel].rs_control) &
                                        ~C_RS_RTS);
-                               CY_UNLOCK(info, flags);
+                               spin_unlock_irqrestore(&card->card_lock, flags);
                        }
                        if (set & TIOCM_DTR) {
-                               CY_LOCK(info, flags);
+                               spin_lock_irqsave(&card->card_lock, flags);
                                cy_writel(&ch_ctrl[channel].rs_control,
                                        readl(&ch_ctrl[channel].rs_control) |
                                        C_RS_DTR);
@@ -3740,10 +3718,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
                                printk(KERN_DEBUG "cyc:set_modem_info raising "
                                        "Z DTR\n");
 #endif
-                               CY_UNLOCK(info, flags);
+                               spin_unlock_irqrestore(&card->card_lock, flags);
                        }
                        if (clear & TIOCM_DTR) {
-                               CY_LOCK(info, flags);
+                               spin_lock_irqsave(&card->card_lock, flags);
                                cy_writel(&ch_ctrl[channel].rs_control,
                                        readl(&ch_ctrl[channel].rs_control) &
                                        ~C_RS_DTR);
@@ -3751,19 +3729,18 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
                                printk(KERN_DEBUG "cyc:set_modem_info clearing "
                                        "Z DTR\n");
 #endif
-                               CY_UNLOCK(info, flags);
+                               spin_unlock_irqrestore(&card->card_lock, flags);
                        }
                } else {
                        return -ENODEV;
                }
-               CY_LOCK(info, flags);
-               retval = cyz_issue_cmd(info->card,
-                                       channel, C_CM_IOCTLM, 0L);
+               spin_lock_irqsave(&card->card_lock, flags);
+               retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
                if (retval != 0) {
                        printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
                                "was %x\n", info->line, retval);
                }
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
        }
        return 0;
 }                              /* cy_tiocmset */
@@ -3774,13 +3751,16 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
 static void cy_break(struct tty_struct *tty, int break_state)
 {
        struct cyclades_port *info = tty->driver_data;
+       struct cyclades_card *card;
        unsigned long flags;
 
        if (serial_paranoia_check(info, tty->name, "cy_break"))
                return;
 
-       CY_LOCK(info, flags);
-       if (!IS_CYC_Z(*info->card)) {
+       card = info->card;
+
+       spin_lock_irqsave(&card->card_lock, flags);
+       if (!IS_CYC_Z(*card)) {
                /* Let the transmit ISR take care of this (since it
                   requires stuffing characters into the output stream).
                 */
@@ -3788,18 +3768,18 @@ static void cy_break(struct tty_struct *tty, int break_state)
                        if (!info->breakon) {
                                info->breakon = 1;
                                if (!info->xmit_cnt) {
-                                       CY_UNLOCK(info, flags);
+                                       spin_unlock_irqrestore(&card->card_lock, flags);
                                        start_xmit(info);
-                                       CY_LOCK(info, flags);
+                                       spin_lock_irqsave(&card->card_lock, flags);
                                }
                        }
                } else {
                        if (!info->breakoff) {
                                info->breakoff = 1;
                                if (!info->xmit_cnt) {
-                                       CY_UNLOCK(info, flags);
+                                       spin_unlock_irqrestore(&card->card_lock, flags);
                                        start_xmit(info);
-                                       CY_LOCK(info, flags);
+                                       spin_lock_irqsave(&card->card_lock, flags);
                                }
                        }
                }
@@ -3807,16 +3787,16 @@ static void cy_break(struct tty_struct *tty, int break_state)
                int retval;
 
                if (break_state == -1) {
-                       retval = cyz_issue_cmd(info->card,
-                               info->line - info->card->first_line,
+                       retval = cyz_issue_cmd(card,
+                               info->line - card->first_line,
                                C_CM_SET_BREAK, 0L);
                        if (retval != 0) {
                                printk(KERN_ERR "cyc:cy_break (set) retval on "
                                        "ttyC%d was %x\n", info->line, retval);
                        }
                } else {
-                       retval = cyz_issue_cmd(info->card,
-                               info->line - info->card->first_line,
+                       retval = cyz_issue_cmd(card,
+                               info->line - card->first_line,
                                C_CM_CLR_BREAK, 0L);
                        if (retval != 0) {
                                printk(KERN_DEBUG "cyc:cy_break (clr) retval "
@@ -3825,7 +3805,7 @@ static void cy_break(struct tty_struct *tty, int break_state)
                        }
                }
        }
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&card->card_lock, flags);
 }                              /* cy_break */
 
 static int
@@ -3860,12 +3840,10 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
                info->cor3 &= ~CyREC_FIFO;
                info->cor3 |= value & CyREC_FIFO;
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
                cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
                cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
-               CY_UNLOCK(info, flags);
-       } else {
-               /* Nothing to do! */
+               spin_unlock_irqrestore(&card->card_lock, flags);
        }
        return 0;
 }                              /* set_threshold */
@@ -3888,10 +3866,8 @@ get_threshold(struct cyclades_port *info, unsigned long __user * value)
 
                tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
                return put_user(tmp, value);
-       } else {
-               /* Nothing to do! */
-               return 0;
        }
+       return 0;
 }                              /* get_threshold */
 
 static int
@@ -3922,11 +3898,9 @@ static int set_timeout(struct cyclades_port *info, unsigned long value)
                index = card->bus_index;
                base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
                cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
-               CY_UNLOCK(info, flags);
-       } else {
-               /* Nothing to do! */
+               spin_unlock_irqrestore(&card->card_lock, flags);
        }
        return 0;
 }                              /* set_timeout */
@@ -3948,10 +3922,8 @@ static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
 
                tmp = readb(base_addr + (CyRTPR << index));
                return put_user(tmp, value);
-       } else {
-               /* Nothing to do! */
-               return 0;
        }
+       return 0;
 }                              /* get_timeout */
 
 static int set_default_timeout(struct cyclades_port *info, unsigned long value)
@@ -4067,15 +4039,15 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
                 * Caller should use TIOCGICOUNT to see which one it was
                 */
        case TIOCMIWAIT:
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&info->card->card_lock, flags);
                /* note the counters on entry */
                cnow = info->icount;
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&info->card->card_lock, flags);
                ret_val = wait_event_interruptible(info->delta_msr_wait, ({
                        cprev = cnow;
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&info->card->card_lock, flags);
                        cnow = info->icount;    /* atomic copy */
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&info->card->card_lock, flags);
 
                        ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
                        ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
@@ -4091,9 +4063,9 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
                 *     RI where only 0->1 is counted.
                 */
        case TIOCGICOUNT:
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&info->card->card_lock, flags);
                cnow = info->icount;
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&info->card->card_lock, flags);
                p_cuser = argp;
                ret_val = put_user(cnow.cts, &p_cuser->cts);
                if (ret_val)
@@ -4248,7 +4220,7 @@ static void cy_throttle(struct tty_struct *tty)
                        base_addr = card->base_addr +
                                (cy_chip_offset[chip] << index);
 
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&card->card_lock, flags);
                        cy_writeb(base_addr + (CyCAR << index),
                                  (u_char) channel);
                        if (info->rtsdtr_inv) {
@@ -4258,7 +4230,7 @@ static void cy_throttle(struct tty_struct *tty)
                                cy_writeb(base_addr + (CyMSVR1 << index),
                                          ~CyRTS);
                        }
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&card->card_lock, flags);
                } else {
                        info->throttle = 1;
                }
@@ -4306,7 +4278,7 @@ static void cy_unthrottle(struct tty_struct *tty)
                        base_addr = card->base_addr +
                                (cy_chip_offset[chip] << index);
 
-                       CY_LOCK(info, flags);
+                       spin_lock_irqsave(&card->card_lock, flags);
                        cy_writeb(base_addr + (CyCAR << index),
                                  (u_char) channel);
                        if (info->rtsdtr_inv) {
@@ -4316,7 +4288,7 @@ static void cy_unthrottle(struct tty_struct *tty)
                                cy_writeb(base_addr + (CyMSVR1 << index),
                                          CyRTS);
                        }
-                       CY_UNLOCK(info, flags);
+                       spin_unlock_irqrestore(&card->card_lock, flags);
                } else {
                        info->throttle = 0;
                }
@@ -4347,17 +4319,14 @@ static void cy_stop(struct tty_struct *tty)
                index = cinfo->bus_index;
                chip = channel >> 2;
                channel &= 0x03;
-               base_addr = info->card->base_addr +
-                       (cy_chip_offset[chip] << index);
+               base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&cinfo->card_lock, flags);
                cy_writeb(base_addr + (CyCAR << index),
                        (u_char)(channel & 0x0003)); /* index channel */
                cy_writeb(base_addr + (CySRER << index),
                          readb(base_addr + (CySRER << index)) & ~CyTxRdy);
-               CY_UNLOCK(info, flags);
-       } else {
-               /* Nothing to do! */
+               spin_unlock_irqrestore(&cinfo->card_lock, flags);
        }
 }                              /* cy_stop */
 
@@ -4382,16 +4351,13 @@ static void cy_start(struct tty_struct *tty)
        if (!IS_CYC_Z(*cinfo)) {
                chip = channel >> 2;
                channel &= 0x03;
-               base_addr = info->card->base_addr +
-                       (cy_chip_offset[chip] << index);
+               base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
 
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&cinfo->card_lock, flags);
                cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003));   /* index channel */
                cy_writeb(base_addr + (CySRER << index),
                          readb(base_addr + (CySRER << index)) | CyTxRdy);
-               CY_UNLOCK(info, flags);
-       } else {
-               /* Nothing to do! */
+               spin_unlock_irqrestore(&cinfo->card_lock, flags);
        }
 }                              /* cy_start */
 
@@ -4412,19 +4378,19 @@ static void cy_flush_buffer(struct tty_struct *tty)
        card = info->card;
        channel = info->line - card->first_line;
 
-       CY_LOCK(info, flags);
+       spin_lock_irqsave(&card->card_lock, flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       CY_UNLOCK(info, flags);
+       spin_unlock_irqrestore(&card->card_lock, flags);
 
        if (IS_CYC_Z(*card)) {  /* If it is a Z card, flush the on-board
                                           buffers as well */
-               CY_LOCK(info, flags);
+               spin_lock_irqsave(&card->card_lock, flags);
                retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
                if (retval != 0) {
                        printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
                                "was %x\n", info->line, retval);
                }
-               CY_UNLOCK(info, flags);
+               spin_unlock_irqrestore(&card->card_lock, flags);
        }
        tty_wakeup(tty);
 }                              /* cy_flush_buffer */
@@ -4464,7 +4430,7 @@ static void cy_hangup(struct tty_struct *tty)
  * ---------------------------------------------------------------------
  */
 
-static void __devinit cy_init_card(struct cyclades_card *cinfo)
+static int __devinit cy_init_card(struct cyclades_card *cinfo)
 {
        struct cyclades_port *info;
        u32 mailbox;
@@ -4486,10 +4452,15 @@ static void __devinit cy_init_card(struct cyclades_card *cinfo)
                nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
        }
 
+       cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
+       if (cinfo->ports == NULL) {
+               printk(KERN_ERR "Cyclades: cannot allocate ports\n");
+               return -ENOMEM;
+       }
+
        for (port = cinfo->first_line; port < cinfo->first_line + nports;
                        port++) {
-               info = &cy_port[port];
-               memset(info, 0, sizeof(*info));
+               info = &cinfo->ports[port - cinfo->first_line];
                info->magic = CYCLADES_MAGIC;
                info->card = cinfo;
                info->line = port;
@@ -4552,6 +4523,7 @@ static void __devinit cy_init_card(struct cyclades_card *cinfo)
 #endif
        }
 #endif
+       return 0;
 }
 
 /* initialize chips on Cyclom-Y card -- return number of valid
@@ -4703,7 +4675,7 @@ static int __init cy_detect_isa(void)
                }
                /* fill the next cy_card structure available */
                for (j = 0; j < NR_CARDS; j++) {
-                       if (cy_card[j].base_addr == 0)
+                       if (cy_card[j].base_addr == NULL)
                                break;
                }
                if (j == NR_CARDS) {    /* no more cy_cards available */
@@ -4788,7 +4760,7 @@ static int __devinit cy_init_Ze(struct RUNTIME_9060 __iomem *cy_pci_addr0,
 
        /* fill the next cy_card structure available */
        for (j = 0; j < NR_CARDS; j++) {
-               if (cy_card[j].base_addr == 0)
+               if (cy_card[j].base_addr == NULL)
                        break;
        }
        if (j == NR_CARDS) {    /* no more cy_cards available */
@@ -4898,7 +4870,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                }
                /* fill the next cy_card structure available */
                for (j = 0; j < NR_CARDS; j++) {
-                       if (cy_card[j].base_addr == 0)
+                       if (cy_card[j].base_addr == NULL)
                                break;
                }
                if (j == NR_CARDS) {    /* no more cy_cards available */
@@ -5048,7 +5020,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 
                /* fill the next cy_card structure available */
                for (j = 0; j < NR_CARDS; j++) {
-                       if (cy_card[j].base_addr == 0)
+                       if (cy_card[j].base_addr == NULL)
                                break;
                }
                if (j == NR_CARDS) {    /* no more cy_cards available */
@@ -5121,13 +5093,11 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
        pci_release_regions(pdev);
 
        cinfo->base_addr = NULL;
-       for (i = cinfo->first_line; i < cinfo->first_line + cinfo->nports; i++){
-               cy_port[i].line = -1;
-               cy_port[i].magic = -1;
-       }
        for (i = cinfo->first_line; i < cinfo->first_line +
                        cinfo->nports; i++)
                tty_unregister_device(cy_serial_driver, i);
+       cinfo->nports = 0;
+       kfree(cinfo->ports);
 }
 
 static struct pci_driver cy_pci_driver = {
@@ -5143,7 +5113,7 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
                int *eof, void *data)
 {
        struct cyclades_port *info;
-       int i;
+       unsigned int i, j;
        int len = 0;
        off_t begin = 0;
        off_t pos = 0;
@@ -5157,33 +5127,34 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
        len += size;
 
        /* Output one line for each known port */
-       for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
-               info = &cy_port[i];
-
-               if (info->count)
-                       size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
-                               "%8lu %9lu %6ld\n", info->line,
-                               (cur_jifs - info->idle_stats.in_use) / HZ,
-                               info->idle_stats.xmit_bytes,
-                               (cur_jifs - info->idle_stats.xmit_idle) / HZ,
-                               info->idle_stats.recv_bytes,
-                               (cur_jifs - info->idle_stats.recv_idle) / HZ,
-                               info->idle_stats.overruns,
-                               (long)info->tty->ldisc.num);
-               else
-                       size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
-                               "%8lu %9lu %6ld\n",
-                               info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
-               len += size;
-               pos = begin + len;
-
-               if (pos < offset) {
-                       len = 0;
-                       begin = pos;
+       for (i = 0; i < NR_CARDS; i++)
+               for (j = 0; j < cy_card[i].nports; j++) {
+                       info = &cy_card[i].ports[j];
+
+                       if (info->count)
+                               size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+                                       "%10lu %8lu %9lu %6ld\n", info->line,
+                                       (cur_jifs - info->idle_stats.in_use) /
+                                       HZ, info->idle_stats.xmit_bytes,
+                                       (cur_jifs - info->idle_stats.xmit_idle)/
+                                       HZ, info->idle_stats.recv_bytes,
+                                       (cur_jifs - info->idle_stats.recv_idle)/
+                                       HZ, info->idle_stats.overruns,
+                                       (long)info->tty->ldisc.num);
+                       else
+                               size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+                                       "%10lu %8lu %9lu %6ld\n",
+                                       info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+                       len += size;
+                       pos = begin + len;
+
+                       if (pos < offset) {
+                               len = 0;
+                               begin = pos;
+                       }
+                       if (pos > offset + length)
+                               goto done;
                }
-               if (pos > offset + length)
-                       goto done;
-       }
        *eof = 1;
 done:
        *start = buf + (offset - begin);        /* Start of wanted data */
@@ -5238,7 +5209,7 @@ static const struct tty_operations cy_ops = {
 
 static int __init cy_init(void)
 {
-       unsigned int i, nboards;
+       unsigned int nboards;
        int retval = -ENOMEM;
 
        cy_serial_driver = alloc_tty_driver(NR_PORTS);
@@ -5269,11 +5240,6 @@ static int __init cy_init(void)
                goto err_frtty;
        }
 
-       for (i = 0; i < NR_PORTS; i++) {
-               cy_port[i].line = -1;
-               cy_port[i].magic = -1;
-       }
-
        /* the code below is responsible to find the boards. Each different
           type of board has its own detection routine. If a board is found,
           the next cy_card structure available is set by the detection
@@ -5302,6 +5268,7 @@ err:
 
 static void __exit cy_cleanup_module(void)
 {
+       struct cyclades_card *card;
        int i, e1;
 
 #ifndef CONFIG_CYZ_INTR
@@ -5312,31 +5279,33 @@ static void __exit cy_cleanup_module(void)
                printk(KERN_ERR "failed to unregister Cyclades serial "
                                "driver(%d)\n", e1);
 
-       put_tty_driver(cy_serial_driver);
-
 #ifdef CONFIG_PCI
        pci_unregister_driver(&cy_pci_driver);
 #endif
 
        for (i = 0; i < NR_CARDS; i++) {
-               if (cy_card[i].base_addr) {
+               card = &cy_card[i];
+               if (card->base_addr) {
                        /* clear interrupt */
-                       cy_writeb(cy_card[i].base_addr + Cy_ClrIntr, 0);
-                       iounmap(cy_card[i].base_addr);
-                       if (cy_card[i].ctl_addr)
-                               iounmap(cy_card[i].ctl_addr);
-                       if (cy_card[i].irq
+                       cy_writeb(card->base_addr + Cy_ClrIntr, 0);
+                       iounmap(card->base_addr);
+                       if (card->ctl_addr)
+                               iounmap(card->ctl_addr);
+                       if (card->irq
 #ifndef CONFIG_CYZ_INTR
-                               && !IS_CYC_Z(cy_card[i])
+                               && !IS_CYC_Z(*card)
 #endif /* CONFIG_CYZ_INTR */
                                )
-                               free_irq(cy_card[i].irq, &cy_card[i]);
-                       for (e1 = cy_card[i].first_line;
-                                       e1 < cy_card[i].first_line +
-                                       cy_card[i].nports; e1++)
+                               free_irq(card->irq, card);
+                       for (e1 = card->first_line;
+                                       e1 < card->first_line +
+                                       card->nports; e1++)
                                tty_unregister_device(cy_serial_driver, e1);
+                       kfree(card->ports);
                }
        }
+
+       put_tty_driver(cy_serial_driver);
 } /* cy_cleanup_module */
 
 module_init(cy_init);