]> err.no Git - linux-2.6/blobdiff - drivers/char/cyclades.c
Char: cyclades, unexport struct cyclades_card
[linux-2.6] / drivers / char / cyclades.c
index e5de0409b37c2fd9de278ca506828681056993a1..1b4ff138b8fffec70913c591ce724a7fa461a09a 100644 (file)
@@ -818,9 +818,6 @@ static int cy_chip_offset[] = { 0x0000,
 
 /* PCI related definitions */
 
-static unsigned short cy_pci_nboard;
-static unsigned short cy_isa_nboard;
-static unsigned short cy_nboard;
 #ifdef CONFIG_PCI
 static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
        { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },      /* PCI < 1Mb */
@@ -1447,6 +1444,10 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
        card_base_addr = cinfo->base_addr;
        index = cinfo->bus_index;
 
+       /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
+       if (unlikely(card_base_addr == NULL))
+               return IRQ_HANDLED;
+
        /* This loop checks all chips in the card.  Make a note whenever
           _any_ chip had some work to do, as this is considered an
           indication that there will be more to do.  Only when no chip
@@ -3615,11 +3616,6 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
                        ((status & CyCTS) ? TIOCM_CTS : 0);
        } else {
                base_addr = cy_card[card].base_addr;
-
-               if (cy_card[card].num_chips != -1) {
-                       return -EINVAL;
-               }
-
                firm_id = cy_card[card].base_addr + ID_ADDRESS;
                if (ISZLOADED(cy_card[card])) {
                        zfw_ctrl = cy_card[card].base_addr +
@@ -4053,14 +4049,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
        case CYGETRTSDTR_INV:
                ret_val = info->rtsdtr_inv;
                break;
-       case CYGETCARDINFO:
-               if (copy_to_user(argp, &cy_card[info->card],
-                                sizeof(struct cyclades_card))) {
-                       ret_val = -EFAULT;
-                       break;
-               }
-               ret_val = 0;
-               break;
        case CYGETCD1400VER:
                ret_val = info->chip_rev;
                break;
@@ -4503,6 +4491,159 @@ static void cy_hangup(struct tty_struct *tty)
  * ---------------------------------------------------------------------
  */
 
+static void __devinit cy_init_card(struct cyclades_card *cinfo,
+               const unsigned int board)
+{
+       struct cyclades_port *info;
+       u32 mailbox;
+       unsigned int nports;
+       unsigned short chip_number;
+       int index, port;
+
+       if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */
+               mailbox = readl(&((struct RUNTIME_9060 __iomem *)
+                                    cinfo->ctl_addr)->mail_box_0);
+               nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
+               cinfo->intr_enabled = 0;
+               cinfo->nports = 0;      /* Will be correctly set later, after
+                                          Z FW is loaded */
+               spin_lock_init(&cinfo->card_lock);
+               for (port = cinfo->first_line;
+                    port < cinfo->first_line + nports; port++) {
+                       info = &cy_port[port];
+                       info->magic = CYCLADES_MAGIC;
+                       info->type = PORT_STARTECH;
+                       info->card = board;
+                       info->line = port;
+                       info->chip_rev = 0;
+                       info->flags = STD_COM_FLAGS;
+                       info->tty = NULL;
+                       if (mailbox == ZO_V1)
+                               info->xmit_fifo_size = CYZ_FIFO_SIZE;
+                       else
+                               info->xmit_fifo_size =
+                                   4 * CYZ_FIFO_SIZE;
+                       info->cor1 = 0;
+                       info->cor2 = 0;
+                       info->cor3 = 0;
+                       info->cor4 = 0;
+                       info->cor5 = 0;
+                       info->tbpr = 0;
+                       info->tco = 0;
+                       info->rbpr = 0;
+                       info->rco = 0;
+                       info->custom_divisor = 0;
+                       info->close_delay = 5 * HZ / 10;
+                       info->closing_wait = CLOSING_WAIT_DELAY;
+                       info->icount.cts = info->icount.dsr =
+                           info->icount.rng = info->icount.dcd = 0;
+                       info->icount.rx = info->icount.tx = 0;
+                       info->icount.frame = info->icount.parity = 0;
+                       info->icount.overrun = info->icount.brk = 0;
+                       info->x_char = 0;
+                       info->event = 0;
+                       info->count = 0;
+                       info->blocked_open = 0;
+                       info->default_threshold = 0;
+                       info->default_timeout = 0;
+                       INIT_WORK(&info->tqueue, do_softint);
+                       init_waitqueue_head(&info->open_wait);
+                       init_waitqueue_head(&info->close_wait);
+                       init_waitqueue_head(&info->shutdown_wait);
+                       init_waitqueue_head(&info->delta_msr_wait);
+                       /* info->session */
+                       /* info->pgrp */
+                       info->read_status_mask = 0;
+                       /* info->timeout */
+                       /* Bentson's vars */
+                       info->jiffies[0] = 0;
+                       info->jiffies[1] = 0;
+                       info->jiffies[2] = 0;
+                       info->rflush_count = 0;
+#ifdef CONFIG_CYZ_INTR
+                       init_timer(&cyz_rx_full_timer[port]);
+                       cyz_rx_full_timer[port].function = NULL;
+#endif
+               }
+#ifndef CONFIG_CYZ_INTR
+               if (!timer_pending(&cyz_timerlist)) {
+                       mod_timer(&cyz_timerlist, jiffies + 1);
+#ifdef CY_PCI_DEBUG
+                       printk("Cyclades-Z polling initialized\n");
+#endif
+               }
+#endif                         /* CONFIG_CYZ_INTR */
+
+       } else {        /* Cyclom-Y of some kind */
+               index = cinfo->bus_index;
+               spin_lock_init(&cinfo->card_lock);
+               cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
+               for (port = cinfo->first_line;
+                    port < cinfo->first_line + cinfo->nports; port++) {
+                       info = &cy_port[port];
+                       info->magic = CYCLADES_MAGIC;
+                       info->type = PORT_CIRRUS;
+                       info->card = board;
+                       info->line = port;
+                       info->flags = STD_COM_FLAGS;
+                       info->tty = NULL;
+                       info->xmit_fifo_size = CyMAX_CHAR_FIFO;
+                       info->cor1 =
+                           CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
+                       info->cor2 = CyETC;
+                       info->cor3 = 0x08;      /* _very_ small rcv threshold */
+                       info->cor4 = 0;
+                       info->cor5 = 0;
+                       info->custom_divisor = 0;
+                       info->close_delay = 5 * HZ / 10;
+                       info->closing_wait = CLOSING_WAIT_DELAY;
+                       info->icount.cts = info->icount.dsr =
+                           info->icount.rng = info->icount.dcd = 0;
+                       info->icount.rx = info->icount.tx = 0;
+                       info->icount.frame = info->icount.parity = 0;
+                       info->icount.overrun = info->icount.brk = 0;
+                       chip_number = (port - cinfo->first_line) / 4;
+                       if ((info->chip_rev =
+                            readb(cinfo->base_addr +
+                                     (cy_chip_offset[chip_number] <<
+                                      index) + (CyGFRCR << index))) >=
+                           CD1400_REV_J) {
+                               /* It is a CD1400 rev. J or later */
+                               info->tbpr = baud_bpr_60[13];   /* Tx BPR */
+                               info->tco = baud_co_60[13];     /* Tx CO */
+                               info->rbpr = baud_bpr_60[13];   /* Rx BPR */
+                               info->rco = baud_co_60[13];     /* Rx CO */
+                               info->rflow = 0;
+                               info->rtsdtr_inv = 1;
+                       } else {
+                               info->tbpr = baud_bpr_25[13];   /* Tx BPR */
+                               info->tco = baud_co_25[13];     /* Tx CO */
+                               info->rbpr = baud_bpr_25[13];   /* Rx BPR */
+                               info->rco = baud_co_25[13];     /* Rx CO */
+                               info->rflow = 0;
+                               info->rtsdtr_inv = 0;
+                       }
+                       info->x_char = 0;
+                       info->event = 0;
+                       info->count = 0;
+                       info->blocked_open = 0;
+                       info->default_threshold = 0;
+                       info->default_timeout = 0;
+                       INIT_WORK(&info->tqueue, do_softint);
+                       init_waitqueue_head(&info->open_wait);
+                       init_waitqueue_head(&info->close_wait);
+                       init_waitqueue_head(&info->shutdown_wait);
+                       init_waitqueue_head(&info->delta_msr_wait);
+                       /* info->session */
+                       /* info->pgrp */
+                       info->read_status_mask =
+                           CyTIMEOUT | CySPECHAR | CyBREAK
+                           | CyPARITY | CyFRAME | CyOVERRUN;
+                       /* info->timeout */
+               }
+       }
+}
+
 /* initialize chips on Cyclom-Y card -- return number of valid
    chips (which is number of ports/4) */
 static unsigned short __init
@@ -4681,6 +4822,7 @@ static int __init cy_detect_isa(void)
                cy_card[j].bus_index = 0;
                cy_card[j].first_line = cy_next_channel;
                cy_card[j].num_chips = cy_isa_nchan / 4;
+               cy_init_card(&cy_card[j], j);
                nboard++;
 
                /* print message */
@@ -4690,6 +4832,9 @@ static int __init cy_detect_isa(void)
                        cy_isa_irq);
                printk("%d channels starting from port %d.\n",
                        cy_isa_nchan, cy_next_channel);
+               for (j = cy_next_channel;
+                               j < cy_next_channel + cy_isa_nchan; j++)
+                       tty_register_device(cy_serial_driver, j, NULL);
                cy_next_channel += cy_isa_nchan;
        }
        return nboard;
@@ -4778,6 +4923,7 @@ static int __devinit cy_init_Ze(unsigned long cy_pci_phys0,
        cy_card[j].first_line = cy_next_channel;
        cy_card[j].num_chips = -1;
        cy_card[j].pdev = pdev;
+       cy_init_card(&cy_card[j], j);
        pci_set_drvdata(pdev, &cy_card[j]);
 
        /* print message */
@@ -4796,6 +4942,8 @@ static int __devinit cy_init_Ze(unsigned long cy_pci_phys0,
 
        printk("%d channels starting from port %d.\n",
                cy_pci_nchan, cy_next_channel);
+       for (j = cy_next_channel; j < cy_next_channel + cy_pci_nchan; j++)
+               tty_register_device(cy_serial_driver, j, &pdev->dev);
        cy_next_channel += cy_pci_nchan;
 
        return 0;
@@ -4927,6 +5075,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                cy_card[j].first_line = cy_next_channel;
                cy_card[j].num_chips = cy_pci_nchan / 4;
                cy_card[j].pdev = pdev;
+               cy_init_card(&cy_card[j], j);
                pci_set_drvdata(pdev, &cy_card[j]);
 
                /* enable interrupts in the PCI interface */
@@ -4962,6 +5111,9 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                        (int)cy_pci_irq);
                printk("%d channels starting from port %d.\n",
                        cy_pci_nchan, cy_next_channel);
+               for (j = cy_next_channel;
+                               j < cy_next_channel + cy_pci_nchan; j++)
+                       tty_register_device(cy_serial_driver, j, &pdev->dev);
 
                cy_next_channel += cy_pci_nchan;
        } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
@@ -5110,6 +5262,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                cy_card[j].first_line = cy_next_channel;
                cy_card[j].num_chips = -1;
                cy_card[j].pdev = pdev;
+               cy_init_card(&cy_card[j], j);
                pci_set_drvdata(pdev, &cy_card[j]);
 
                /* print message */
@@ -5128,68 +5281,60 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 
                printk("%d channels starting from port %d.\n",
                                cy_pci_nchan, cy_next_channel);
+               for (j = cy_next_channel;
+                               j < cy_next_channel + cy_pci_nchan; j++)
+                       tty_register_device(cy_serial_driver, j, &pdev->dev);
                cy_next_channel += cy_pci_nchan;
        }
 
        return 0;
 }
-#endif
 
-/*
- * ---------------------------------------------------------------------
- * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
- * sets global variables and return the number of PCI boards found.
- * ---------------------------------------------------------------------
- */
-static int __init cy_detect_pci(void)
+static void __devexit cy_pci_remove(struct pci_dev *pdev)
 {
-#ifdef CONFIG_PCI
-       struct pci_dev *pdev = NULL;
-       unsigned int i, device_id, dev_index = 0;
-
-       for (i = 0; i < NR_CARDS; i++) {
-               /* look for a Cyclades card by vendor and device id */
-               while ((device_id = cy_pci_dev_id[dev_index].device) != 0) {
-                       if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
-                                                  device_id, pdev)) == NULL) {
-                               dev_index++;    /* try next device id */
-                       } else {
-                               break;  /* found a board */
-                       }
-               }
-
-               if (device_id == 0)
-                       break;
-
-               i -= !!cy_pci_probe(pdev, &cy_pci_dev_id[dev_index]);
-       }
-
-       return i;
-#else
-       return 0;
-#endif                         /* ifdef CONFIG_PCI */
-}                              /* cy_detect_pci */
-
-static void __devexit cy_pci_release(struct pci_dev *pdev)
-{
-#ifdef CONFIG_PCI
        struct cyclades_card *cinfo = pci_get_drvdata(pdev);
+       unsigned int i;
+
+       /* non-Z with old PLX */
+       if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
+                       PLX_9050)
+               cy_writeb(cinfo->ctl_addr + 0x4c, 0);
+       else
+#ifndef CONFIG_CYZ_INTR
+               if (!IS_CYC_Z(*cinfo))
+#endif
+               cy_writew(cinfo->ctl_addr + 0x68,
+                               readw(cinfo->ctl_addr + 0x68) & ~0x0900);
 
        pci_iounmap(pdev, cinfo->base_addr);
        if (cinfo->ctl_addr)
                pci_iounmap(pdev, cinfo->ctl_addr);
        if (cinfo->irq
 #ifndef CONFIG_CYZ_INTR
-               && cinfo->num_chips != -1 /* not a Z card */
+               && !IS_CYC_Z(*cinfo)
 #endif /* CONFIG_CYZ_INTR */
                )
                free_irq(cinfo->irq, cinfo);
        pci_release_regions(pdev);
 
        cinfo->base_addr = NULL;
-#endif
+       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);
 }
 
+static struct pci_driver cy_pci_driver = {
+       .name = "cyclades",
+       .id_table = cy_pci_dev_id,
+       .probe = cy_pci_probe,
+       .remove = __devexit_p(cy_pci_remove)
+};
+#endif
+
 /*
  * This routine prints out the appropriate serial driver version number
  * and identifies which options were configured into this driver.
@@ -5300,17 +5445,12 @@ static const struct tty_operations cy_ops = {
 
 static int __init cy_init(void)
 {
-       struct cyclades_port *info;
-       struct cyclades_card *cinfo;
-       int number_z_boards = 0;
-       int board, port, i, index;
-       unsigned long mailbox;
-       unsigned short chip_number;
-       int nports;
+       unsigned int i, nboards;
+       int retval = -ENOMEM;
 
        cy_serial_driver = alloc_tty_driver(NR_PORTS);
        if (!cy_serial_driver)
-               return -ENOMEM;
+               goto err;
        show_version();
 
        /* Initialize the tty_driver structure */
@@ -5325,17 +5465,26 @@ static int __init cy_init(void)
        cy_serial_driver->init_termios = tty_std_termios;
        cy_serial_driver->init_termios.c_cflag =
            B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
+       cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(cy_serial_driver, &cy_ops);
 
-       if (tty_register_driver(cy_serial_driver))
-               panic("Couldn't register Cyclades serial driver\n");
+       retval = tty_register_driver(cy_serial_driver);
+       if (retval) {
+               printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
+               goto err_frtty;
+       }
 
        for (i = 0; i < NR_CARDS; i++) {
                /* base_addr=0 indicates board not found */
                cy_card[i].base_addr = NULL;
        }
 
+       /* invalidate remaining cy_port structures */
+       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
@@ -5344,182 +5493,22 @@ static int __init cy_init(void)
           the cy_next_channel. */
 
        /* look for isa boards */
-       cy_isa_nboard = cy_detect_isa();
+       nboards = cy_detect_isa();
 
+#ifdef CONFIG_PCI
        /* look for pci boards */
-       cy_pci_nboard = cy_detect_pci();
-
-       cy_nboard = cy_isa_nboard + cy_pci_nboard;
-
-       /* invalidate remaining cy_card structures */
-       for (i = 0; i < NR_CARDS; i++) {
-               if (cy_card[i].base_addr == 0) {
-                       cy_card[i].first_line = -1;
-                       cy_card[i].ctl_addr = NULL;
-                       cy_card[i].irq = 0;
-                       cy_card[i].bus_index = 0;
-                       cy_card[i].first_line = 0;
-                       cy_card[i].num_chips = 0;
-               }
-       }
-       /* invalidate remaining cy_port structures */
-       for (i = cy_next_channel; i < NR_PORTS; i++) {
-               cy_port[i].line = -1;
-               cy_port[i].magic = -1;
-       }
-
-       /* initialize per-port data structures for each valid board found */
-       for (board = 0; board < cy_nboard; board++) {
-               cinfo = &cy_card[board];
-               if (cinfo->num_chips == -1) {   /* Cyclades-Z */
-                       number_z_boards++;
-                       mailbox = readl(&((struct RUNTIME_9060 __iomem *)
-                                            cy_card[board].ctl_addr)->
-                                          mail_box_0);
-                       nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
-                       cinfo->intr_enabled = 0;
-                       cinfo->nports = 0;      /* Will be correctly set later, after 
-                                                  Z FW is loaded */
-                       spin_lock_init(&cinfo->card_lock);
-                       for (port = cinfo->first_line;
-                            port < cinfo->first_line + nports; port++) {
-                               info = &cy_port[port];
-                               info->magic = CYCLADES_MAGIC;
-                               info->type = PORT_STARTECH;
-                               info->card = board;
-                               info->line = port;
-                               info->chip_rev = 0;
-                               info->flags = STD_COM_FLAGS;
-                               info->tty = NULL;
-                               if (mailbox == ZO_V1)
-                                       info->xmit_fifo_size = CYZ_FIFO_SIZE;
-                               else
-                                       info->xmit_fifo_size =
-                                           4 * CYZ_FIFO_SIZE;
-                               info->cor1 = 0;
-                               info->cor2 = 0;
-                               info->cor3 = 0;
-                               info->cor4 = 0;
-                               info->cor5 = 0;
-                               info->tbpr = 0;
-                               info->tco = 0;
-                               info->rbpr = 0;
-                               info->rco = 0;
-                               info->custom_divisor = 0;
-                               info->close_delay = 5 * HZ / 10;
-                               info->closing_wait = CLOSING_WAIT_DELAY;
-                               info->icount.cts = info->icount.dsr =
-                                   info->icount.rng = info->icount.dcd = 0;
-                               info->icount.rx = info->icount.tx = 0;
-                               info->icount.frame = info->icount.parity = 0;
-                               info->icount.overrun = info->icount.brk = 0;
-                               info->x_char = 0;
-                               info->event = 0;
-                               info->count = 0;
-                               info->blocked_open = 0;
-                               info->default_threshold = 0;
-                               info->default_timeout = 0;
-                               INIT_WORK(&info->tqueue, do_softint);
-                               init_waitqueue_head(&info->open_wait);
-                               init_waitqueue_head(&info->close_wait);
-                               init_waitqueue_head(&info->shutdown_wait);
-                               init_waitqueue_head(&info->delta_msr_wait);
-                               /* info->session */
-                               /* info->pgrp */
-                               info->read_status_mask = 0;
-                               /* info->timeout */
-                               /* Bentson's vars */
-                               info->jiffies[0] = 0;
-                               info->jiffies[1] = 0;
-                               info->jiffies[2] = 0;
-                               info->rflush_count = 0;
-#ifdef CONFIG_CYZ_INTR
-                               init_timer(&cyz_rx_full_timer[port]);
-                               cyz_rx_full_timer[port].function = NULL;
+       retval = pci_register_driver(&cy_pci_driver);
+       if (retval && !nboards)
+               goto err_unr;
 #endif
-                       }
-                       continue;
-               } else {        /* Cyclom-Y of some kind */
-                       index = cinfo->bus_index;
-                       spin_lock_init(&cinfo->card_lock);
-                       cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
-                       for (port = cinfo->first_line;
-                            port < cinfo->first_line + cinfo->nports; port++) {
-                               info = &cy_port[port];
-                               info->magic = CYCLADES_MAGIC;
-                               info->type = PORT_CIRRUS;
-                               info->card = board;
-                               info->line = port;
-                               info->flags = STD_COM_FLAGS;
-                               info->tty = NULL;
-                               info->xmit_fifo_size = CyMAX_CHAR_FIFO;
-                               info->cor1 =
-                                   CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
-                               info->cor2 = CyETC;
-                               info->cor3 = 0x08;      /* _very_ small rcv threshold */
-                               info->cor4 = 0;
-                               info->cor5 = 0;
-                               info->custom_divisor = 0;
-                               info->close_delay = 5 * HZ / 10;
-                               info->closing_wait = CLOSING_WAIT_DELAY;
-                               info->icount.cts = info->icount.dsr =
-                                   info->icount.rng = info->icount.dcd = 0;
-                               info->icount.rx = info->icount.tx = 0;
-                               info->icount.frame = info->icount.parity = 0;
-                               info->icount.overrun = info->icount.brk = 0;
-                               chip_number = (port - cinfo->first_line) / 4;
-                               if ((info->chip_rev =
-                                    readb(cinfo->base_addr +
-                                             (cy_chip_offset[chip_number] <<
-                                              index) + (CyGFRCR << index))) >=
-                                   CD1400_REV_J) {
-                                       /* It is a CD1400 rev. J or later */
-                                       info->tbpr = baud_bpr_60[13];   /* Tx BPR */
-                                       info->tco = baud_co_60[13];     /* Tx CO */
-                                       info->rbpr = baud_bpr_60[13];   /* Rx BPR */
-                                       info->rco = baud_co_60[13];     /* Rx CO */
-                                       info->rflow = 0;
-                                       info->rtsdtr_inv = 1;
-                               } else {
-                                       info->tbpr = baud_bpr_25[13];   /* Tx BPR */
-                                       info->tco = baud_co_25[13];     /* Tx CO */
-                                       info->rbpr = baud_bpr_25[13];   /* Rx BPR */
-                                       info->rco = baud_co_25[13];     /* Rx CO */
-                                       info->rflow = 0;
-                                       info->rtsdtr_inv = 0;
-                               }
-                               info->x_char = 0;
-                               info->event = 0;
-                               info->count = 0;
-                               info->blocked_open = 0;
-                               info->default_threshold = 0;
-                               info->default_timeout = 0;
-                               INIT_WORK(&info->tqueue, do_softint);
-                               init_waitqueue_head(&info->open_wait);
-                               init_waitqueue_head(&info->close_wait);
-                               init_waitqueue_head(&info->shutdown_wait);
-                               init_waitqueue_head(&info->delta_msr_wait);
-                               /* info->session */
-                               /* info->pgrp */
-                               info->read_status_mask =
-                                   CyTIMEOUT | CySPECHAR | CyBREAK
-                                   | CyPARITY | CyFRAME | CyOVERRUN;
-                               /* info->timeout */
-                       }
-               }
-       }
-
-#ifndef CONFIG_CYZ_INTR
-       if (number_z_boards) {
-               mod_timer(&cyz_timerlist, jiffies + 1);
-#ifdef CY_PCI_DEBUG
-               printk("Cyclades-Z polling initialized\n");
-#endif
-       }
-#endif                         /* CONFIG_CYZ_INTR */
 
        return 0;
-
+err_unr:
+       tty_unregister_driver(cy_serial_driver);
+err_frtty:
+       put_tty_driver(cy_serial_driver);
+err:
+       return retval;
 }                              /* cy_init */
 
 static void __exit cy_cleanup_module(void)
@@ -5536,21 +5525,27 @@ static void __exit cy_cleanup_module(void)
 
        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) {
-                       if (cy_card[i].pdev) {
-                               cy_pci_release(cy_card[i].pdev);
-                               continue;
-                       }
+                       /* 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
 #ifndef CONFIG_CYZ_INTR
-                               && cy_card[i].num_chips != -1 /* not a Z card */
+                               && !IS_CYC_Z(cy_card[i])
 #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++)
+                               tty_unregister_device(cy_serial_driver, e1);
                }
        }
 } /* cy_cleanup_module */