X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fchar%2Fcyclades.c;h=c72ee97d3892543f6e8d2ebd053657776bba49dc;hb=02a93208edec0d655c9f18613d830dc6afeda7d4;hp=6e5fca9c393a8b59041d9d04f8f115571f570b5b;hpb=9fa1b3b185a802fa0b3f764ad468efd64e1b582e;p=linux-2.6 diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 6e5fca9c39..c72ee97d38 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -10,15 +10,14 @@ * * Initially written by Randolph Bentson . * Modified and maintained by Marcio Saito . - * Currently maintained by Cyclades team . * - * For Technical support and installation problems, please send e-mail - * to support@cyclades.com. + * Copyright (C) 2007 Jiri Slaby * * Much of the design and some of the code came from serial.c * which was copyright (C) 1991, 1992 Linus Torvalds. It was * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92, * and then fixed as suggested by Michael K. Johnson 12/12/92. + * Converted to pci probing and cleaned up by Jiri Slaby. * * This version supports shared IRQ's (only for PCI boards). * @@ -591,7 +590,7 @@ * */ -#define CY_VERSION "2.4" +#define CY_VERSION "2.5" /* If you need to install more boards than NR_CARDS, change the constant in the definition below. No other change is necessary to support up to @@ -722,11 +721,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 */ /* @@ -855,13 +849,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); @@ -1025,7 +1012,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; @@ -1037,13 +1024,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 */ @@ -1202,19 +1188,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); @@ -1263,7 +1248,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); @@ -1304,7 +1289,6 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, 0); info->icount.tx++; char_count--; - } else { } } } @@ -1326,16 +1310,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) @@ -1389,10 +1371,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)); @@ -1408,14 +1390,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 @@ -1564,7 +1546,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); @@ -1650,9 +1632,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; @@ -1730,10 +1711,10 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 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]); @@ -1822,16 +1803,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); @@ -1900,7 +1881,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]); @@ -2472,13 +2453,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; } @@ -2661,8 +2649,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)); @@ -3857,8 +3843,6 @@ static int set_threshold(struct cyclades_port *info, unsigned long value) cy_writeb(base_addr + (CyCOR3 << index), info->cor3); cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index); spin_unlock_irqrestore(&card->card_lock, flags); - } else { - /* Nothing to do! */ } return 0; } /* set_threshold */ @@ -3881,10 +3865,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 @@ -3918,8 +3900,6 @@ static int set_timeout(struct cyclades_port *info, unsigned long value) spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyRTPR << index), value & 0xff); spin_unlock_irqrestore(&card->card_lock, flags); - } else { - /* Nothing to do! */ } return 0; } /* set_timeout */ @@ -3941,10 +3921,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) @@ -4348,8 +4326,6 @@ static void cy_stop(struct tty_struct *tty) cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) & ~CyTxRdy); spin_unlock_irqrestore(&cinfo->card_lock, flags); - } else { - /* Nothing to do! */ } } /* cy_stop */ @@ -4381,8 +4357,6 @@ static void cy_start(struct tty_struct *tty) cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) | CyTxRdy); spin_unlock_irqrestore(&cinfo->card_lock, flags); - } else { - /* Nothing to do! */ } } /* cy_start */ @@ -4455,7 +4429,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; @@ -4477,10 +4451,16 @@ 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"); + cinfo->nports = 0; + 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; @@ -4543,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 @@ -4666,9 +4647,15 @@ static int __init cy_detect_isa(void) /* probe for CD1400... */ cy_isa_address = ioremap(isa_address, CyISA_Ywin); + if (cy_isa_address == NULL) { + printk(KERN_ERR "Cyclom-Y/ISA: can't remap base " + "address\n"); + continue; + } cy_isa_nchan = CyPORTS_PER_CHIP * cyy_init_card(cy_isa_address, 0); if (cy_isa_nchan == 0) { + iounmap(cy_isa_address); continue; } #ifdef MODULE @@ -4682,6 +4669,7 @@ static int __init cy_detect_isa(void) printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the " "IRQ could not be detected.\n", (unsigned long)cy_isa_address); + iounmap(cy_isa_address); continue; } @@ -4690,11 +4678,12 @@ static int __init cy_detect_isa(void) "more channels are available. Change NR_PORTS " "in cyclades.c and recompile kernel.\n", (unsigned long)cy_isa_address); + iounmap(cy_isa_address); return nboard; } /* 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 */ @@ -4702,6 +4691,7 @@ static int __init cy_detect_isa(void) "more cards can be used. Change NR_CARDS in " "cyclades.c and recompile kernel.\n", (unsigned long)cy_isa_address); + iounmap(cy_isa_address); return nboard; } @@ -4711,6 +4701,7 @@ static int __init cy_detect_isa(void) printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " "could not allocate IRQ#%d.\n", (unsigned long)cy_isa_address, cy_isa_irq); + iounmap(cy_isa_address); return nboard; } @@ -4721,7 +4712,12 @@ 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]); + if (cy_init_card(&cy_card[j])) { + cy_card[j].base_addr = NULL; + free_irq(cy_isa_irq, &cy_card[j]); + iounmap(cy_isa_address); + continue; + } nboard++; printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: " @@ -4755,333 +4751,245 @@ static void __devinit plx_init(void __iomem * addr, __u32 initctl) cy_writel(addr + initctl, readl(addr + initctl) & ~0x20000000); } -static int __devinit cy_init_Ze(struct RUNTIME_9060 __iomem *cy_pci_addr0, - int cy_pci_irq, struct pci_dev *pdev) -{ - void __iomem *cy_pci_addr2; - unsigned int j; - unsigned short cy_pci_nchan; - - cy_pci_addr2 = pci_iomap(pdev, 2, CyPCI_Ze_win); - - readl(&cy_pci_addr0->mail_box_0); - dev_dbg(&pdev->dev, "new Cyclades-Z board. FPGA not loaded\n"); - - /* This must be the new Cyclades-Ze/PCI. */ - cy_pci_nchan = ZE_V1_NPORTS; - - if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { - dev_err(&pdev->dev, "Cyclades-Ze/PCI found, but no channels " - "are available.\nChange NR_PORTS in cyclades.c " - "and recompile kernel.\n"); - return -EIO; - } - - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - dev_err(&pdev->dev, "Cyclades-Ze/PCI found, but no more " - "cards can be used.\nChange NR_CARDS in " - "cyclades.c and recompile kernel.\n"); - return -EIO; - } -#ifdef CONFIG_CYZ_INTR - /* allocate IRQ only if board has an IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) { - if (request_irq(cy_pci_irq, cyz_interrupt, - IRQF_SHARED, "Cyclades-Z", - &cy_card[j])) { - dev_err(&pdev->dev, "could not allocate IRQ.\n"); - return -EIO; - } - } -#endif /* CONFIG_CYZ_INTR */ - - /* set cy_card */ - cy_card[j].base_addr = cy_pci_addr2; - cy_card[j].ctl_addr = cy_pci_addr0; - cy_card[j].irq = cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = -1; - cy_init_card(&cy_card[j]); - pci_set_drvdata(pdev, &cy_card[j]); - - dev_info(&pdev->dev, "Cyclades-Ze/PCI #%d found: %d channels starting " - "from port %d.\n", j + 1, 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; -} - static int __devinit cy_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - unsigned char cyy_rev_id; - int cy_pci_irq; - __u32 mailbox; - void __iomem *cy_pci_addr0, *cy_pci_addr2; - unsigned int device_id; - unsigned short j, cy_pci_nchan, plx_ver; - int retval; + void __iomem *addr0 = NULL, *addr2 = NULL; + char *card_name = NULL; + u32 mailbox; + unsigned int device_id, nchan = 0, card_no, i; + unsigned char plx_ver; + int retval, irq; retval = pci_enable_device(pdev); if (retval) { dev_err(&pdev->dev, "cannot enable device\n"); - return retval; + goto err; } /* read PCI configuration area */ - cy_pci_irq = pdev->irq; - pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id); - + irq = pdev->irq; device_id = pdev->device & ~PCI_DEVICE_ID_MASK; +#if defined(__alpha__) + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ + dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low " + "addresses on Alpha systems.\n"); + retval = -EIO; + goto err_dis; + } +#endif + if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) { + dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low " + "addresses\n"); + retval = -EIO; + goto err_dis; + } + + if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { + dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring " + "it...\n"); + pdev->resource[2].flags &= ~IORESOURCE_IO; + } + + retval = pci_request_regions(pdev, "cyclades"); + if (retval) { + dev_err(&pdev->dev, "failed to reserve resources\n"); + goto err_dis; + } + + retval = -EIO; if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { - dev_dbg(&pdev->dev, "Cyclom-Y/PCI found\n"); + card_name = "Cyclom-Y"; - if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { - dev_warn(&pdev->dev, "PCI I/O bit incorrectly " - "set. Ignoring it...\n"); - pdev->resource[2].flags &= ~IORESOURCE_IO; + addr0 = pci_iomap(pdev, 0, CyPCI_Yctl); + if (addr0 == NULL) { + dev_err(&pdev->dev, "can't remap ctl region\n"); + goto err_reg; } - - /* Although we don't use this I/O region, we should - request it from the kernel anyway, to avoid problems - with other drivers accessing it. */ - retval = pci_request_regions(pdev, "Cyclom-Y"); - if (retval) { - dev_err(&pdev->dev, "failed to reserve resources\n"); - return retval; + addr2 = pci_iomap(pdev, 2, CyPCI_Ywin); + if (addr2 == NULL) { + dev_err(&pdev->dev, "can't remap base region\n"); + goto err_unmap; } -#if defined(__alpha__) - if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ - dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for " - "low addresses on Alpha systems.\n"); - return -EIO; - } -#endif - cy_pci_addr0 = pci_iomap(pdev, 0, CyPCI_Yctl); - cy_pci_addr2 = pci_iomap(pdev, 2, CyPCI_Ywin); - - dev_dbg(&pdev->dev, "Cyclom-Y/PCI: relocate winaddr=0x%p " - "ctladdr=0x%p\n", cy_pci_addr2, cy_pci_addr0); - cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP * - cyy_init_card(cy_pci_addr2, 1)); - if (cy_pci_nchan == 0) { + nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1); + if (nchan == 0) { dev_err(&pdev->dev, "Cyclom-Y PCI host card with no " "Serial-Modules\n"); return -EIO; } - if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { - dev_err(&pdev->dev, "Cyclom-Y/PCI found, but no " - "channels are available. Change NR_PORTS in " - "cyclades.c and recompile kernel.\n"); - return -EIO; - } - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) - break; - } - if (j == NR_CARDS) { /* no more cy_cards available */ - dev_err(&pdev->dev, "Cyclom-Y/PCI found, but no more " - "cards can be used. Change NR_CARDS in " - "cyclades.c and recompile kernel.\n"); - return -EIO; - } - - /* allocate IRQ */ - retval = request_irq(cy_pci_irq, cyy_interrupt, - IRQF_SHARED, "Cyclom-Y", &cy_card[j]); - if (retval) { - dev_err(&pdev->dev, "could not allocate IRQ\n"); - return retval; - } - - /* set cy_card */ - cy_card[j].base_addr = cy_pci_addr2; - cy_card[j].ctl_addr = cy_pci_addr0; - cy_card[j].irq = cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = cy_pci_nchan / 4; - cy_init_card(&cy_card[j]); - pci_set_drvdata(pdev, &cy_card[j]); - - /* enable interrupts in the PCI interface */ - plx_ver = readb(cy_pci_addr2 + CyPLX_VER) & 0x0f; - switch (plx_ver) { - case PLX_9050: - - cy_writeb(cy_pci_addr0 + 0x4c, 0x43); - break; - - case PLX_9060: - case PLX_9080: - default: /* Old boards, use PLX_9060 */ - - plx_init(cy_pci_addr0, 0x6c); - /* For some yet unknown reason, once the PLX9060 reloads - the EEPROM, the IRQ is lost and, thus, we have to - re-write it to the PCI config. registers. - This will remain here until we find a permanent - fix. */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, - cy_pci_irq); - - cy_writew(cy_pci_addr0 + 0x68, - readw(cy_pci_addr0 + 0x68) | 0x0900); - break; - } - - dev_info(&pdev->dev, "Cyclom-Y/PCI #%d found: %d channels " - "starting from port %d.\n", j + 1, 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) { - dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for " - "low addresses\n"); - return -EIO; } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { - dev_dbg(&pdev->dev, "Cyclades-Z/PCI found\n"); + struct RUNTIME_9060 __iomem *ctl_addr; - cy_pci_addr0 = pci_iomap(pdev, 0, CyPCI_Zctl); + ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl); + if (addr0 == NULL) { + dev_err(&pdev->dev, "can't remap ctl region\n"); + goto err_reg; + } /* Disable interrupts on the PLX before resetting it */ - cy_writew(cy_pci_addr0 + 0x68, - readw(cy_pci_addr0 + 0x68) & ~0x0900); + cy_writew(addr0 + 0x68, + readw(addr0 + 0x68) & ~0x0900); - plx_init(cy_pci_addr0, 0x6c); + plx_init(addr0, 0x6c); /* For some yet unknown reason, once the PLX9060 reloads the EEPROM, the IRQ is lost and, thus, we have to re-write it to the PCI config. registers. This will remain here until we find a permanent fix. */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, cy_pci_irq); + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); - mailbox = (__u32)readl(&((struct RUNTIME_9060 __iomem *) - cy_pci_addr0)->mail_box_0); + mailbox = (u32)readl(&ctl_addr->mail_box_0); - if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { - dev_warn(&pdev->dev, "PCI I/O bit incorrectly " - "set. Ignoring it...\n"); - pdev->resource[2].flags &= ~IORESOURCE_IO; - } - - /* Although we don't use this I/O region, we should - request it from the kernel anyway, to avoid problems - with other drivers accessing it. */ - retval = pci_request_regions(pdev, "Cyclades-Z"); - if (retval) { - dev_err(&pdev->dev, "failed to reserve resources\n"); - return retval; + addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ? + CyPCI_Ze_win : CyPCI_Zwin); + if (addr2 == NULL) { + dev_err(&pdev->dev, "can't remap base region\n"); + goto err_unmap; } if (mailbox == ZE_V1) { - retval = cy_init_Ze(cy_pci_addr0, cy_pci_irq, pdev); - return retval; + card_name = "Cyclades-Ze"; + + readl(&ctl_addr->mail_box_0); + nchan = ZE_V1_NPORTS; } else { - cy_pci_addr2 = pci_iomap(pdev, 2, CyPCI_Zwin); - } + card_name = "Cyclades-8Zo"; - dev_dbg(&pdev->dev, "Cyclades-Z/PCI: relocate winaddr=0x%p " - "ctladdr=0x%p\n", cy_pci_addr2, cy_pci_addr0); #ifdef CY_PCI_DEBUG - if (mailbox == ZO_V1) { - cy_writel(&((struct RUNTIME_9060 *) - (cy_pci_addr0))->loc_addr_base, - WIN_CREG); - dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA id %lx, " - "ver %lx\n", (ulong)(0xff & - readl(&((struct CUSTOM_REG *) - cy_pci_addr2)->fpga_id)), - (ulong)(0xff & readl(&((struct CUSTOM_REG *) - cy_pci_addr2)->fpga_version))); - cy_writel(&((struct RUNTIME_9060 *) - cy_pci_addr0)->loc_addr_base, WIN_RAM); - } else { - dev_info(&pdev->dev, "Cyclades-Z/PCI: New Cyclades-Z " - "board. FPGA not loaded\n"); - } + if (mailbox == ZO_V1) { + cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); + dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA " + "id %lx, ver %lx\n", (ulong)(0xff & + readl(&((struct CUSTOM_REG *)addr2)-> + fpga_id)), (ulong)(0xff & + readl(&((struct CUSTOM_REG *)addr2)-> + fpga_version))); + cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); + } else { + dev_info(&pdev->dev, "Cyclades-Z/PCI: New " + "Cyclades-Z board. FPGA not loaded\n"); + } #endif - /* The following clears the firmware id word. This - ensures that the driver will not attempt to talk to - the board until it has been properly initialized. - */ - if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) - cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L); - - /* This must be a Cyclades-8Zo/PCI. The extendable - version will have a different device_id and will - be allocated its maximum number of ports. */ - cy_pci_nchan = 8; - - if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { - dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " - "channels are available. Change NR_PORTS in " - "cyclades.c and recompile kernel.\n"); - return -EIO; - } + /* The following clears the firmware id word. This + ensures that the driver will not attempt to talk to + the board until it has been properly initialized. + */ + if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) + cy_writel(addr2 + ID_ADDRESS, 0L); - /* fill the next cy_card structure available */ - for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == 0) - break; + /* This must be a Cyclades-8Zo/PCI. The extendable + version will have a different device_id and will + be allocated its maximum number of ports. */ + nchan = 8; } - if (j == NR_CARDS) { /* no more cy_cards available */ - dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " - "more cards can be used. Change NR_CARDS in " - "cyclades.c and recompile kernel.\n"); - return -EIO; + } + + if ((cy_next_channel + nchan) > NR_PORTS) { + dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " + "channels are available. Change NR_PORTS in " + "cyclades.c and recompile kernel.\n"); + goto err_unmap; + } + /* fill the next cy_card structure available */ + for (card_no = 0; card_no < NR_CARDS; card_no++) { + if (cy_card[card_no].base_addr == NULL) + break; + } + if (card_no == NR_CARDS) { /* no more cy_cards available */ + dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " + "more cards can be used. Change NR_CARDS in " + "cyclades.c and recompile kernel.\n"); + goto err_unmap; + } + + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || + device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { + /* allocate IRQ */ + retval = request_irq(irq, cyy_interrupt, + IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]); + if (retval) { + dev_err(&pdev->dev, "could not allocate IRQ\n"); + goto err_unmap; } + cy_card[card_no].num_chips = nchan / 4; + } else { #ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ - if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) { - retval = request_irq(cy_pci_irq, cyz_interrupt, + if (irq != 0 && irq != 255) { + retval = request_irq(irq, cyz_interrupt, IRQF_SHARED, "Cyclades-Z", - &cy_card[j]); + &cy_card[card_no]); if (retval) { dev_err(&pdev->dev, "could not allocate IRQ\n"); - return retval; + goto err_unmap; } } #endif /* CONFIG_CYZ_INTR */ + cy_card[card_no].num_chips = -1; + } - /* set cy_card */ - cy_card[j].base_addr = cy_pci_addr2; - cy_card[j].ctl_addr = cy_pci_addr0; - cy_card[j].irq = cy_pci_irq; - cy_card[j].bus_index = 1; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = -1; - cy_init_card(&cy_card[j]); - pci_set_drvdata(pdev, &cy_card[j]); + /* set cy_card */ + cy_card[card_no].base_addr = addr2; + cy_card[card_no].ctl_addr = addr0; + cy_card[card_no].irq = irq; + cy_card[card_no].bus_index = 1; + cy_card[card_no].first_line = cy_next_channel; + retval = cy_init_card(&cy_card[card_no]); + if (retval) + goto err_null; - dev_info(&pdev->dev, "Cyclades-8Zo/PCI #%d found: %d channels " - "starting from port %d.\n", j + 1, cy_pci_nchan, - cy_next_channel); + pci_set_drvdata(pdev, &cy_card[card_no]); - 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; + if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || + device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { + /* enable interrupts in the PCI interface */ + plx_ver = readb(addr2 + CyPLX_VER) & 0x0f; + switch (plx_ver) { + case PLX_9050: + + cy_writeb(addr0 + 0x4c, 0x43); + break; + + case PLX_9060: + case PLX_9080: + default: /* Old boards, use PLX_9060 */ + + plx_init(addr0, 0x6c); + /* For some yet unknown reason, once the PLX9060 reloads + the EEPROM, the IRQ is lost and, thus, we have to + re-write it to the PCI config. registers. + This will remain here until we find a permanent + fix. */ + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); + + cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900); + break; + } } + dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from " + "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel); + for (i = cy_next_channel; i < cy_next_channel + nchan; i++) + tty_register_device(cy_serial_driver, i, &pdev->dev); + cy_next_channel += nchan; + return 0; +err_null: + cy_card[card_no].base_addr = NULL; + free_irq(irq, &cy_card[card_no]); +err_unmap: + pci_iounmap(pdev, addr0); + if (addr2) + pci_iounmap(pdev, addr2); +err_reg: + pci_release_regions(pdev); +err_dis: + pci_disable_device(pdev); +err: + return retval; } static void __devexit cy_pci_remove(struct pci_dev *pdev) @@ -5112,13 +5020,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 = { @@ -5134,7 +5040,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; @@ -5148,33 +5054,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 */ @@ -5229,7 +5136,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); @@ -5260,11 +5167,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 @@ -5293,6 +5195,7 @@ err: static void __exit cy_cleanup_module(void) { + struct cyclades_card *card; int i, e1; #ifndef CONFIG_CYZ_INTR @@ -5303,34 +5206,37 @@ 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); module_exit(cy_cleanup_module); MODULE_LICENSE("GPL"); +MODULE_VERSION(CY_VERSION);