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: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Jiri Slaby 2007-05-08 00:37:04 -07:00 committed by Linus Torvalds
parent dd025c0c7a
commit 3137553d3f
1 changed files with 206 additions and 278 deletions

View File

@ -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)
/* 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)
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)
"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)
"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)
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)
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)
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) { addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
dev_warn(&pdev->dev, "PCI I/O bit incorrectly " if (addr0 == NULL) {
"set. Ignoring it...\n"); dev_err(&pdev->dev, "can't remap ctl region\n");
pdev->resource[2].flags &= ~IORESOURCE_IO; 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;
} }
/* Although we don't use this I/O region, we should nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
request it from the kernel anyway, to avoid problems if (nchan == 0) {
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 (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) {
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) { } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
dev_err(&pdev->dev, "Cyclom-Y/PCI found, but no " struct RUNTIME_9060 __iomem *ctl_addr;
"channels are available. Change NR_PORTS in "
"cyclades.c and recompile kernel.\n"); ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
return -EIO; if (addr0 == NULL) {
} dev_err(&pdev->dev, "can't remap ctl region\n");
/* fill the next cy_card structure available */ goto err_reg;
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;
} }
/* Disable interrupts on the PLX before resetting it */
cy_writew(addr0 + 0x68,
readw(addr0 + 0x68) & ~0x0900);
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);
mailbox = (u32)readl(&ctl_addr->mail_box_0);
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) {
card_name = "Cyclades-Ze";
readl(&ctl_addr->mail_box_0);
nchan = ZE_V1_NPORTS;
} else {
card_name = "Cyclades-8Zo";
#ifdef CY_PCI_DEBUG
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(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. */
nchan = 8;
}
}
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 */ /* allocate IRQ */
retval = request_irq(cy_pci_irq, cyy_interrupt, retval = request_irq(irq, cyy_interrupt,
IRQF_SHARED, "Cyclom-Y", &cy_card[j]); IRQF_SHARED, "Cyclom-Y", &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;
} }
cy_card[card_no].num_chips = nchan / 4;
} else {
#ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */
if (irq != 0 && irq != 255) {
retval = request_irq(irq, cyz_interrupt,
IRQF_SHARED, "Cyclades-Z",
&cy_card[card_no]);
if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n");
goto err_unmap;
}
}
#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 = cy_pci_nchan / 4; 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;
pci_set_drvdata(pdev, &cy_card[card_no]);
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
/* enable interrupts in the PCI interface */ /* enable interrupts in the PCI interface */
plx_ver = readb(cy_pci_addr2 + CyPLX_VER) & 0x0f; plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
switch (plx_ver) { switch (plx_ver) {
case PLX_9050: case PLX_9050:
cy_writeb(cy_pci_addr0 + 0x4c, 0x43); cy_writeb(addr0 + 0x4c, 0x43);
break; break;
case PLX_9060: case PLX_9060:
case PLX_9080: case PLX_9080:
default: /* Old boards, use PLX_9060 */ default: /* Old boards, use PLX_9060 */
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, pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
cy_pci_irq);
cy_writew(cy_pci_addr0 + 0x68, cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
readw(cy_pci_addr0 + 0x68) | 0x0900);
break; 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");
cy_pci_addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
/* Disable interrupts on the PLX before resetting it */
cy_writew(cy_pci_addr0 + 0x68,
readw(cy_pci_addr0 + 0x68) & ~0x0900);
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);
mailbox = (__u32)readl(&((struct RUNTIME_9060 __iomem *)
cy_pci_addr0)->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;
}
if (mailbox == ZE_V1) {
retval = cy_init_Ze(cy_pci_addr0, cy_pci_irq, pdev);
return retval;
} else {
cy_pci_addr2 = pci_iomap(pdev, 2, CyPCI_Zwin);
}
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");
}
#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;
}
/* 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-8Zo/PCI found, but no "
"more cards can be used. Change 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)) {
retval = request_irq(cy_pci_irq, cyz_interrupt,
IRQF_SHARED, "Cyclades-Z",
&cy_card[j]);
if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n");
return retval;
}
}
#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-8Zo/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;
} }
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)