stallion.c
来自「linux 内核源代码」· C语言 代码 · 共 2,551 行 · 第 1/5 页
C
2,551 行
pr_debug("stl_initech(brdp=%p)\n", brdp); status = 0; conflict = 0;/* * Set up the initial board register contents for boards. This varies a * bit between the different board types. So we need to handle each * separately. Also do a check that the supplied IRQ is good. */ switch (brdp->brdtype) { case BRD_ECH: brdp->isr = stl_echatintr; brdp->ioctrl = brdp->ioaddr1 + 1; brdp->iostatus = brdp->ioaddr1 + 1; status = inb(brdp->iostatus); if ((status & ECH_IDBITMASK) != ECH_ID) { retval = -ENODEV; goto err; } if ((brdp->irq < 0) || (brdp->irq > 15) || (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); retval = -EINVAL; goto err; } status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1); status |= (stl_vecmap[brdp->irq] << 1); outb((status | ECH_BRDRESET), brdp->ioaddr1); brdp->ioctrlval = ECH_INTENABLE | ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE); for (i = 0; i < 10; i++) outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); brdp->iosize1 = 2; brdp->iosize2 = 32; name = "serial(EC8/32)"; outb(status, brdp->ioaddr1); break; case BRD_ECHMC: brdp->isr = stl_echmcaintr; brdp->ioctrl = brdp->ioaddr1 + 0x20; brdp->iostatus = brdp->ioctrl; status = inb(brdp->iostatus); if ((status & ECH_IDBITMASK) != ECH_ID) { retval = -ENODEV; goto err; } if ((brdp->irq < 0) || (brdp->irq > 15) || (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr); retval = -EINVAL; goto err; } outb(ECHMC_BRDRESET, brdp->ioctrl); outb(ECHMC_INTENABLE, brdp->ioctrl); brdp->iosize1 = 64; name = "serial(EC8/32-MC)"; break; case BRD_ECHPCI: brdp->isr = stl_echpciintr; brdp->ioctrl = brdp->ioaddr1 + 2; brdp->iosize1 = 4; brdp->iosize2 = 8; name = "serial(EC8/32-PCI)"; break; case BRD_ECH64PCI: brdp->isr = stl_echpci64intr; brdp->ioctrl = brdp->ioaddr2 + 0x40; outb(0x43, (brdp->ioaddr1 + 0x4c)); brdp->iosize1 = 0x80; brdp->iosize2 = 0x80; name = "serial(EC8/64-PCI)"; break; default: printk("STALLION: unknown board type=%d\n", brdp->brdtype); retval = -EINVAL; goto err; }/* * Check boards for possible IO address conflicts and return fail status * if an IO conflict found. */ retval = -EBUSY; if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) { printk(KERN_WARNING "STALLION: Warning, board %d I/O address " "%x conflicts with another device\n", brdp->brdnr, brdp->ioaddr1); goto err; } if (brdp->iosize2 > 0) if (!request_region(brdp->ioaddr2, brdp->iosize2, name)) { printk(KERN_WARNING "STALLION: Warning, board %d I/O " "address %x conflicts with another device\n", brdp->brdnr, brdp->ioaddr2); printk(KERN_WARNING "STALLION: Warning, also " "releasing board %d I/O address %x \n", brdp->brdnr, brdp->ioaddr1); goto err_rel1; }/* * Scan through the secondary io address space looking for panels. * As we find'em allocate and initialize panel structures for each. */ brdp->clk = CD1400_CLK; brdp->hwid = status; ioaddr = brdp->ioaddr2; banknr = 0; panelnr = 0; nxtid = 0; for (i = 0; i < STL_MAXPANELS; i++) { if (brdp->brdtype == BRD_ECHPCI) { outb(nxtid, brdp->ioctrl); ioaddr = brdp->ioaddr2; } status = inb(ioaddr + ECH_PNLSTATUS); if ((status & ECH_PNLIDMASK) != nxtid) break; panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL); if (!panelp) { printk("STALLION: failed to allocate memory " "(size=%Zd)\n", sizeof(struct stlpanel)); retval = -ENOMEM; goto err_fr; } panelp->magic = STL_PANELMAGIC; panelp->brdnr = brdp->brdnr; panelp->panelnr = panelnr; panelp->iobase = ioaddr; panelp->pagenr = nxtid; panelp->hwid = status; brdp->bnk2panel[banknr] = panelp; brdp->bnkpageaddr[banknr] = nxtid; brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS; if (status & ECH_PNLXPID) { panelp->uartp = &stl_sc26198uart; panelp->isr = stl_sc26198intr; if (status & ECH_PNL16PORT) { panelp->nrports = 16; brdp->bnk2panel[banknr] = panelp; brdp->bnkpageaddr[banknr] = nxtid; brdp->bnkstataddr[banknr++] = ioaddr + 4 + ECH_PNLSTATUS; } else panelp->nrports = 8; } else { panelp->uartp = &stl_cd1400uart; panelp->isr = stl_cd1400echintr; if (status & ECH_PNL16PORT) { panelp->nrports = 16; panelp->ackmask = 0x80; if (brdp->brdtype != BRD_ECHPCI) ioaddr += EREG_BANKSIZE; brdp->bnk2panel[banknr] = panelp; brdp->bnkpageaddr[banknr] = ++nxtid; brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS; } else { panelp->nrports = 8; panelp->ackmask = 0xc0; } } nxtid++; ioaddr += EREG_BANKSIZE; brdp->nrports += panelp->nrports; brdp->panels[panelnr++] = panelp; if ((brdp->brdtype != BRD_ECHPCI) && (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) { retval = -EINVAL; goto err_fr; } } brdp->nrpanels = panelnr; brdp->nrbnks = banknr; if (brdp->brdtype == BRD_ECH) outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); brdp->state |= BRD_FOUND; if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) { printk("STALLION: failed to register interrupt " "routine for %s irq=%d\n", name, brdp->irq); retval = -ENODEV; goto err_fr; } return 0;err_fr: stl_cleanup_panels(brdp); if (brdp->iosize2 > 0) release_region(brdp->ioaddr2, brdp->iosize2);err_rel1: release_region(brdp->ioaddr1, brdp->iosize1);err: return retval;}/*****************************************************************************//* * Initialize and configure the specified board. * Scan through all the boards in the configuration and see what we * can find. Handle EIO and the ECH boards a little differently here * since the initial search and setup is very different. */static int __devinit stl_brdinit(struct stlbrd *brdp){ int i, retval; pr_debug("stl_brdinit(brdp=%p)\n", brdp); switch (brdp->brdtype) { case BRD_EASYIO: case BRD_EASYIOPCI: retval = stl_initeio(brdp); if (retval) goto err; break; case BRD_ECH: case BRD_ECHMC: case BRD_ECHPCI: case BRD_ECH64PCI: retval = stl_initech(brdp); if (retval) goto err; break; default: printk("STALLION: board=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype); retval = -ENODEV; goto err; } if ((brdp->state & BRD_FOUND) == 0) { printk("STALLION: %s board not found, board=%d io=%x irq=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq); goto err_free; } for (i = 0; i < STL_MAXPANELS; i++) if (brdp->panels[i] != NULL) stl_initports(brdp, brdp->panels[i]); printk("STALLION: %s found, board=%d io=%x irq=%d " "nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, brdp->nrports); return 0;err_free: free_irq(brdp->irq, brdp); stl_cleanup_panels(brdp); release_region(brdp->ioaddr1, brdp->iosize1); if (brdp->iosize2 > 0) release_region(brdp->ioaddr2, brdp->iosize2);err: return retval;}/*****************************************************************************//* * Find the next available board number that is free. */static int __devinit stl_getbrdnr(void){ unsigned int i; for (i = 0; i < STL_MAXBRDS; i++) if (stl_brds[i] == NULL) { if (i >= stl_nrbrds) stl_nrbrds = i + 1; return i; } return -1;}/*****************************************************************************//* * We have a Stallion board. Allocate a board structure and * initialize it. Read its IO and IRQ resources from PCI * configuration space. */static int __devinit stl_pciprobe(struct pci_dev *pdev, const struct pci_device_id *ent){ struct stlbrd *brdp; unsigned int i, brdtype = ent->driver_data; int brdnr, retval = -ENODEV; if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) goto err; retval = pci_enable_device(pdev); if (retval) goto err; brdp = stl_allocbrd(); if (brdp == NULL) { retval = -ENOMEM; goto err; } mutex_lock(&stl_brdslock); brdnr = stl_getbrdnr(); if (brdnr < 0) { dev_err(&pdev->dev, "too many boards found, " "maximum supported %d\n", STL_MAXBRDS); mutex_unlock(&stl_brdslock); retval = -ENODEV; goto err_fr; } brdp->brdnr = (unsigned int)brdnr; stl_brds[brdp->brdnr] = brdp; mutex_unlock(&stl_brdslock); brdp->brdtype = brdtype; brdp->state |= STL_PROBED;/* * We have all resources from the board, so let's setup the actual * board structure now. */ switch (brdtype) { case BRD_ECHPCI: brdp->ioaddr2 = pci_resource_start(pdev, 0); brdp->ioaddr1 = pci_resource_start(pdev, 1); break; case BRD_ECH64PCI: brdp->ioaddr2 = pci_resource_start(pdev, 2); brdp->ioaddr1 = pci_resource_start(pdev, 1); break; case BRD_EASYIOPCI: brdp->ioaddr1 = pci_resource_start(pdev, 2); brdp->ioaddr2 = pci_resource_start(pdev, 1); break; default: dev_err(&pdev->dev, "unknown PCI board type=%u\n", brdtype); break; } brdp->irq = pdev->irq; retval = stl_brdinit(brdp); if (retval) goto err_null; pci_set_drvdata(pdev, brdp); for (i = 0; i < brdp->nrports; i++) tty_register_device(stl_serial, brdp->brdnr * STL_MAXPORTS + i, &pdev->dev); return 0;err_null: stl_brds[brdp->brdnr] = NULL;err_fr: kfree(brdp);err: return retval;}static void __devexit stl_pciremove(struct pci_dev *pdev){ struct stlbrd *brdp = pci_get_drvdata(pdev); unsigned int i; free_irq(brdp->irq, brdp); stl_cleanup_panels(brdp); release_region(brdp->ioaddr1, brdp->iosize1); if (brdp->iosize2 > 0) release_region(brdp->ioaddr2, brdp->iosize2); for (i = 0; i < brdp->nrports; i++) tty_unregister_device(stl_serial, brdp->brdnr * STL_MAXPORTS + i); stl_brds[brdp->brdnr] = NULL; kfree(brdp);}static struct pci_driver stl_pcidriver = { .name = "stallion", .id_table = stl_pcibrds, .probe = stl_pciprobe, .remove = __devexit_p(stl_pciremove)};/*****************************************************************************//* * Return the board stats structure to user app. */static int stl_getbrdstats(combrd_t __user *bp){ combrd_t stl_brdstats; struct stlbrd *brdp; struct stlpanel *panelp; unsigned int i; if (copy_from_user(&stl_brdstats, bp, sizeof(combrd_t))) return -EFAULT; if (stl_brdstats.brd >= STL_MAXBRDS) return -ENODEV; brdp = stl_brds[stl_brdstats.brd]; if (brdp == NULL) return -ENODEV; memset(&stl_brdstats, 0, sizeof(combrd_t)); stl_brdstats.brd = brdp->brdnr; stl_brdstats.type = brdp->brdtype; stl_brdstats.hwid = brdp->hwid; stl_brdstats.state = brdp->state; stl_brdstats.ioaddr = brdp->ioaddr1; stl_brdstats.ioaddr2 = brdp->ioaddr2; stl_brdstats.irq = brdp->irq; stl_brdstats.nrpanels = brdp->nrpanels; stl_brdstats.nrports = brdp->nrports; for (i = 0; i < brdp->nrpanels; i++) { panelp = brdp->panels[i]; stl_brdstats.panels[i].panel = i; stl_brdstats.panels[i].hwid = panelp->hwid; stl_brdstats.panels[i].nrports = panelp->nrports; } return copy_to_user(bp, &stl_brdstats, sizeof(combrd_t)) ? -EFAULT : 0;}/*****************************************************************************//* * Resolve the referenced port number into a port struct pointer. */static struct stlport *stl_getport(int brdnr, int panelnr, int portnr){ struct stlbrd *brdp; struct stlpanel *panelp; if (brdnr < 0 || brdnr >= STL_MAXBRDS) return NULL; brdp = stl_brds[brdnr]; if (brdp == NULL) return NULL; if (panelnr < 0 || (unsigned int)panelnr >= brdp->nrpanels) return NULL; panelp = brdp->panels[panelnr]; if (panelp == NULL) return NULL; if (portnr < 0 || (unsigned int)portnr >= panelp->nrports) return NULL; return panelp->ports[portnr];}/*****************************************************************************//* * Return the port stats structure to user app. A NULL port struct * pointer passed in means that we need to find out from the app * what port to get stats for (used through board control device). */static int stl_getportstats(struct stlport *portp, comstats_t __user *cp){ comstats_t stl_comstats; unsigned char *head, *tail; unsigned long flags; if (!portp) { if (copy_from_user(&stl_comstats, cp, sizeof(comstats_t))) return -EFAULT; portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port); if (portp == NULL) return -ENODEV; } portp->stats.state = portp->istate; portp->stats.flags = portp->flags; portp->stats.hwid = portp->hwid; portp->stats.ttystate = 0; portp->stats.cflags = 0; portp->stats.iflags = 0; portp->stats.oflags = 0; portp->stats.lflags = 0; portp
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?