Commit 3137553d authored by Jiri Slaby's avatar Jiri Slaby Committed by Linus Torvalds

Char: cyclades, probe cleanup

- add fail paths
- merge 3 similar initializations into one (Z, Ze, Y)

[akpm@linux-foundation.org: build fix]
Signed-off-by: default avatarJiri Slaby <jirislaby@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent dd025c0c
...@@ -4455,6 +4455,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) ...@@ -4455,6 +4455,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL); cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
if (cinfo->ports == NULL) { if (cinfo->ports == NULL) {
printk(KERN_ERR "Cyclades: cannot allocate ports\n"); printk(KERN_ERR "Cyclades: cannot allocate ports\n");
cinfo->nports = 0;
return -ENOMEM; return -ENOMEM;
} }
...@@ -4647,9 +4648,15 @@ static int __init cy_detect_isa(void) ...@@ -4647,9 +4648,15 @@ static int __init cy_detect_isa(void)
/* probe for CD1400... */ /* probe for CD1400... */
cy_isa_address = ioremap(isa_address, CyISA_Ywin); 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 * cy_isa_nchan = CyPORTS_PER_CHIP *
cyy_init_card(cy_isa_address, 0); cyy_init_card(cy_isa_address, 0);
if (cy_isa_nchan == 0) { if (cy_isa_nchan == 0) {
iounmap(cy_isa_address);
continue; continue;
} }
#ifdef MODULE #ifdef MODULE
...@@ -4663,6 +4670,7 @@ static int __init cy_detect_isa(void) ...@@ -4663,6 +4670,7 @@ static int __init cy_detect_isa(void)
printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the " printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
"IRQ could not be detected.\n", "IRQ could not be detected.\n",
(unsigned long)cy_isa_address); (unsigned long)cy_isa_address);
iounmap(cy_isa_address);
continue; continue;
} }
...@@ -4671,6 +4679,7 @@ static int __init cy_detect_isa(void) ...@@ -4671,6 +4679,7 @@ static int __init cy_detect_isa(void)
"more channels are available. Change NR_PORTS " "more channels are available. Change NR_PORTS "
"in cyclades.c and recompile kernel.\n", "in cyclades.c and recompile kernel.\n",
(unsigned long)cy_isa_address); (unsigned long)cy_isa_address);
iounmap(cy_isa_address);
return nboard; return nboard;
} }
/* fill the next cy_card structure available */ /* fill the next cy_card structure available */
...@@ -4683,6 +4692,7 @@ static int __init cy_detect_isa(void) ...@@ -4683,6 +4692,7 @@ static int __init cy_detect_isa(void)
"more cards can be used. Change NR_CARDS in " "more cards can be used. Change NR_CARDS in "
"cyclades.c and recompile kernel.\n", "cyclades.c and recompile kernel.\n",
(unsigned long)cy_isa_address); (unsigned long)cy_isa_address);
iounmap(cy_isa_address);
return nboard; return nboard;
} }
...@@ -4692,6 +4702,7 @@ static int __init cy_detect_isa(void) ...@@ -4692,6 +4702,7 @@ static int __init cy_detect_isa(void)
printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
"could not allocate IRQ#%d.\n", "could not allocate IRQ#%d.\n",
(unsigned long)cy_isa_address, cy_isa_irq); (unsigned long)cy_isa_address, cy_isa_irq);
iounmap(cy_isa_address);
return nboard; return nboard;
} }
...@@ -4702,7 +4713,12 @@ static int __init cy_detect_isa(void) ...@@ -4702,7 +4713,12 @@ static int __init cy_detect_isa(void)
cy_card[j].bus_index = 0; cy_card[j].bus_index = 0;
cy_card[j].first_line = cy_next_channel; cy_card[j].first_line = cy_next_channel;
cy_card[j].num_chips = cy_isa_nchan / 4; 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++; nboard++;
printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: " printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
...@@ -4736,267 +4752,126 @@ static void __devinit plx_init(void __iomem * addr, __u32 initctl) ...@@ -4736,267 +4752,126 @@ static void __devinit plx_init(void __iomem * addr, __u32 initctl)
cy_writel(addr + initctl, readl(addr + initctl) & ~0x20000000); 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 == NULL)
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, static int __devinit cy_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
unsigned char cyy_rev_id; void __iomem *addr0 = NULL, *addr2 = NULL;
int cy_pci_irq; char *card_name = NULL;
__u32 mailbox; u32 mailbox;
void __iomem *cy_pci_addr0, *cy_pci_addr2; unsigned int device_id, nchan = 0, card_no, i;
unsigned int device_id; unsigned char plx_ver;
unsigned short j, cy_pci_nchan, plx_ver; int retval, irq;
int retval;
retval = pci_enable_device(pdev); retval = pci_enable_device(pdev);
if (retval) { if (retval) {
dev_err(&pdev->dev, "cannot enable device\n"); dev_err(&pdev->dev, "cannot enable device\n");
return retval; goto err;
} }
/* read PCI configuration area */ /* read PCI configuration area */
cy_pci_irq = pdev->irq; irq = pdev->irq;
pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
device_id = pdev->device & ~PCI_DEVICE_ID_MASK; device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
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");
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, "Cyclom-Y");
if (retval) {
dev_err(&pdev->dev, "failed to reserve resources\n");
return retval;
}
#if defined(__alpha__) #if defined(__alpha__)
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for " dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
"low addresses on Alpha systems.\n"); "addresses on Alpha systems.\n");
return -EIO; retval = -EIO;
goto err_dis;
} }
#endif #endif
cy_pci_addr0 = pci_iomap(pdev, 0, CyPCI_Yctl); if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
cy_pci_addr2 = pci_iomap(pdev, 2, CyPCI_Ywin); dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
"addresses\n");
dev_dbg(&pdev->dev, "Cyclom-Y/PCI: relocate winaddr=0x%p " retval = -EIO;
"ctladdr=0x%p\n", cy_pci_addr2, cy_pci_addr0); goto err_dis;
cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
cyy_init_card(cy_pci_addr2, 1));
if (cy_pci_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 " if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
"channels are available. Change NR_PORTS in " dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
"cyclades.c and recompile kernel.\n"); "it...\n");
return -EIO; pdev->resource[2].flags &= ~IORESOURCE_IO;
}
/* fill the next cy_card structure available */
for (j = 0; j < NR_CARDS; j++) {
if (cy_card[j].base_addr == NULL)
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 = pci_request_regions(pdev, "cyclades");
retval = request_irq(cy_pci_irq, cyy_interrupt,
IRQF_SHARED, "Cyclom-Y", &cy_card[j]);
if (retval) { if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n"); dev_err(&pdev->dev, "failed to reserve resources\n");
return retval; goto err_dis;
} }
/* set cy_card */ retval = -EIO;
cy_card[j].base_addr = cy_pci_addr2; if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
cy_card[j].ctl_addr = cy_pci_addr0; device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
cy_card[j].irq = cy_pci_irq; card_name = "Cyclom-Y";
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, addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
readw(cy_pci_addr0 + 0x68) | 0x0900); if (addr0 == NULL) {
break; dev_err(&pdev->dev, "can't remap ctl region\n");
goto err_reg;
}
addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
if (addr2 == NULL) {
dev_err(&pdev->dev, "can't remap base region\n");
goto err_unmap;
} }
dev_info(&pdev->dev, "Cyclom-Y/PCI #%d found: %d channels " nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
"starting from port %d.\n", j + 1, cy_pci_nchan, if (nchan == 0) {
cy_next_channel); dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
"Serial-Modules\n");
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; return -EIO;
}
} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { } 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 */ /* Disable interrupts on the PLX before resetting it */
cy_writew(cy_pci_addr0 + 0x68, cy_writew(addr0 + 0x68,
readw(cy_pci_addr0 + 0x68) & ~0x0900); readw(addr0 + 0x68) & ~0x0900);
plx_init(cy_pci_addr0, 0x6c); plx_init(addr0, 0x6c);
/* For some yet unknown reason, once the PLX9060 reloads /* For some yet unknown reason, once the PLX9060 reloads
the EEPROM, the IRQ is lost and, thus, we have to the EEPROM, the IRQ is lost and, thus, we have to
re-write it to the PCI config. registers. re-write it to the PCI config. registers.
This will remain here until we find a permanent This will remain here until we find a permanent
fix. */ 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 *) mailbox = (u32)readl(&ctl_addr->mail_box_0);
cy_pci_addr0)->mail_box_0);
if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
dev_warn(&pdev->dev, "PCI I/O bit incorrectly " CyPCI_Ze_win : CyPCI_Zwin);
"set. Ignoring it...\n"); if (addr2 == NULL) {
pdev->resource[2].flags &= ~IORESOURCE_IO; dev_err(&pdev->dev, "can't remap base region\n");
} goto err_unmap;
/* 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;
} }
if (mailbox == ZE_V1) { if (mailbox == ZE_V1) {
retval = cy_init_Ze(cy_pci_addr0, cy_pci_irq, pdev); card_name = "Cyclades-Ze";
return retval;
readl(&ctl_addr->mail_box_0);
nchan = ZE_V1_NPORTS;
} else { } 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 #ifdef CY_PCI_DEBUG
if (mailbox == ZO_V1) { if (mailbox == ZO_V1) {
cy_writel(&((struct RUNTIME_9060 *) cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
(cy_pci_addr0))->loc_addr_base, dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
WIN_CREG); "id %lx, ver %lx\n", (ulong)(0xff &
dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA id %lx, " readl(&((struct CUSTOM_REG *)addr2)->
"ver %lx\n", (ulong)(0xff & fpga_id)), (ulong)(0xff &
readl(&((struct CUSTOM_REG *) readl(&((struct CUSTOM_REG *)addr2)->
cy_pci_addr2)->fpga_id)), fpga_version)));
(ulong)(0xff & readl(&((struct CUSTOM_REG *) cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
cy_pci_addr2)->fpga_version)));
cy_writel(&((struct RUNTIME_9060 *)
cy_pci_addr0)->loc_addr_base, WIN_RAM);
} else { } else {
dev_info(&pdev->dev, "Cyclades-Z/PCI: New Cyclades-Z " dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
"board. FPGA not loaded\n"); "Cyclades-Z board. FPGA not loaded\n");
} }
#endif #endif
/* The following clears the firmware id word. This /* The following clears the firmware id word. This
...@@ -5004,65 +4879,118 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, ...@@ -5004,65 +4879,118 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
the board until it has been properly initialized. the board until it has been properly initialized.
*/ */
if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L); cy_writel(addr2 + ID_ADDRESS, 0L);
/* This must be a Cyclades-8Zo/PCI. The extendable /* This must be a Cyclades-8Zo/PCI. The extendable
version will have a different device_id and will version will have a different device_id and will
be allocated its maximum number of ports. */ be allocated its maximum number of ports. */
cy_pci_nchan = 8; nchan = 8;
}
}
if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) { if ((cy_next_channel + nchan) > NR_PORTS) {
dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
"channels are available. Change NR_PORTS in " "channels are available. Change NR_PORTS in "
"cyclades.c and recompile kernel.\n"); "cyclades.c and recompile kernel.\n");
return -EIO; goto err_unmap;
} }
/* fill the next cy_card structure available */ /* fill the next cy_card structure available */
for (j = 0; j < NR_CARDS; j++) { for (card_no = 0; card_no < NR_CARDS; card_no++) {
if (cy_card[j].base_addr == NULL) if (cy_card[card_no].base_addr == NULL)
break; break;
} }
if (j == NR_CARDS) { /* no more cy_cards available */ if (card_no == NR_CARDS) { /* no more cy_cards available */
dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
"more cards can be used. Change NR_CARDS in " "more cards can be used. Change NR_CARDS in "
"cyclades.c and recompile kernel.\n"); "cyclades.c and recompile kernel.\n");
return -EIO; 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 #ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */ /* allocate IRQ only if board has an IRQ */
if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) { if (irq != 0 && irq != 255) {
retval = request_irq(cy_pci_irq, cyz_interrupt, retval = request_irq(irq, cyz_interrupt,
IRQF_SHARED, "Cyclades-Z", IRQF_SHARED, "Cyclades-Z",
&cy_card[j]); &cy_card[card_no]);
if (retval) { if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n"); dev_err(&pdev->dev, "could not allocate IRQ\n");
return retval; goto err_unmap;
} }
} }
#endif /* CONFIG_CYZ_INTR */ #endif /* CONFIG_CYZ_INTR */
cy_card[card_no].num_chips = -1;
}
/* set cy_card */ /* set cy_card */
cy_card[j].base_addr = cy_pci_addr2; cy_card[card_no].base_addr = addr2;
cy_card[j].ctl_addr = cy_pci_addr0; cy_card[card_no].ctl_addr = addr0;
cy_card[j].irq = cy_pci_irq; cy_card[card_no].irq = irq;
cy_card[j].bus_index = 1; cy_card[card_no].bus_index = 1;
cy_card[j].first_line = cy_next_channel; cy_card[card_no].first_line = cy_next_channel;
cy_card[j].num_chips = -1; retval = cy_init_card(&cy_card[card_no]);
cy_init_card(&cy_card[j]); if (retval)
pci_set_drvdata(pdev, &cy_card[j]); goto err_null;
dev_info(&pdev->dev, "Cyclades-8Zo/PCI #%d found: %d channels " pci_set_drvdata(pdev, &cy_card[card_no]);
"starting from port %d.\n", j + 1, cy_pci_nchan,
cy_next_channel);
for (j = cy_next_channel; if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
j < cy_next_channel + cy_pci_nchan; j++) device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
tty_register_device(cy_serial_driver, j, &pdev->dev); /* enable interrupts in the PCI interface */
cy_next_channel += cy_pci_nchan; 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; 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) static void __devexit cy_pci_remove(struct pci_dev *pdev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment