*
* Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
* Modified and maintained by Marcio Saito <marcio@cyclades.com>.
- * Currently maintained by Cyclades team <async@cyclades.com>.
*
- * For Technical support and installation problems, please send e-mail
- * to support@cyclades.com.
+ * Copyright (C) 2007 Jiri Slaby <jirislaby@gmail.com>
*
* 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).
*
*
*/
-#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
*/
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 */
/*
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);
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;
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 */
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);
}
goto txdone;
}
- if (info->xmit_buf == 0) {
+ if (info->xmit_buf == NULL) {
cy_writeb(base_addr + (CySRER << index),
readb(base_addr + (CySRER << index)) &
~CyTxRdy);
0);
info->icount.tx++;
char_count--;
- } else {
}
}
}
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)
}
}
}
- if (mdm_change & CyDSR) {
+/* if (mdm_change & CyDSR) {
}
if (mdm_change & CyRI) {
- }
+ }*/
}
/* end of service */
cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
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
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);
if (char_count) {
- if (tty == 0) {
+ if (tty == NULL)
goto ztxdone;
- }
if (info->x_char) { /* send special char */
data = info->x_char;
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]);
#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);
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]);
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;
}
timeout))
break;
}
- } else {
- /* Nothing to do! */
}
/* Run one more char cycle */
msleep_interruptible(jiffies_to_msecs(char_time * 5));
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 */
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
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 */
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)
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 */
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 */
* ---------------------------------------------------------------------
*/
-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;
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;
#endif
}
#endif
+ return 0;
}
/* initialize chips on Cyclom-Y card -- return number of valid
/* 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
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;
}
"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 */
"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;
}
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;
}
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: "
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)
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 = {
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;
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 */
static int __init cy_init(void)
{
- unsigned int i, nboards;
+ unsigned int nboards;
int retval = -ENOMEM;
cy_serial_driver = alloc_tty_driver(NR_PORTS);
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
static void __exit cy_cleanup_module(void)
{
+ struct cyclades_card *card;
int i, e1;
#ifndef CONFIG_CYZ_INTR
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);