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,333 +4752,245 @@ static void __devinit plx_init(void __iomem * addr, __u32 initctl) ...@@ -4736,333 +4752,245 @@ 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 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 || if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { 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;
}
/* Although we don't use this I/O region, we should addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
request it from the kernel anyway, to avoid problems if (addr0 == NULL) {
with other drivers accessing it. */ dev_err(&pdev->dev, "can't remap ctl region\n");
retval = pci_request_regions(pdev, "Cyclom-Y"); goto err_reg;
if (retval) {
dev_err(&pdev->dev, "failed to reserve resources\n");
return retval;
} }
#if defined(__alpha__) addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ if (addr2 == NULL) {
dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for " dev_err(&pdev->dev, "can't remap base region\n");
"low addresses on Alpha systems.\n"); goto err_unmap;
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 * nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
cyy_init_card(cy_pci_addr2, 1)); if (nchan == 0) {
if (cy_pci_nchan == 0) {
dev_err(&pdev->dev, "Cyclom-Y PCI host card with no " dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
"Serial-Modules\n"); "Serial-Modules\n");
return -EIO; 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 == 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 = 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) { } 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))); } else {
cy_writel(&((struct RUNTIME_9060 *) dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
cy_pci_addr0)->loc_addr_base, WIN_RAM); "Cyclades-Z board. FPGA not loaded\n");
} else { }
dev_info(&pdev->dev, "Cyclades-Z/PCI: New 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
ensures that the driver will not attempt to talk to ensures that the driver will not attempt to talk to
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
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;
}
/* fill the next cy_card structure available */ /* This must be a Cyclades-8Zo/PCI. The extendable
for (j = 0; j < NR_CARDS; j++) { version will have a different device_id and will
if (cy_card[j].base_addr == NULL) be allocated its maximum number of ports. */
break; 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 " if ((cy_next_channel + nchan) > NR_PORTS) {
"cyclades.c and recompile kernel.\n"); dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
return -EIO; "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 #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