?? stallion.c
字號:
(sigs & TIOCM_DSR) ? "|DSR" : ""); *sp = ' '; sp += cnt; for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++) *sp++ = ' '; if (cnt >= MAXLINE) pos[(MAXLINE - 2)] = '+'; pos[(MAXLINE - 1)] = '\n'; return(MAXLINE);}/*****************************************************************************//* * Port info, read from the /proc file system. */static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data){ stlbrd_t *brdp; stlpanel_t *panelp; stlport_t *portp; int brdnr, panelnr, portnr, totalport; int curoff, maxoff; char *pos;#if DEBUG printk("stl_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x," "data=%x\n", (int) page, (int) start, (int) off, count, (int) eof, (int) data);#endif pos = page; totalport = 0; curoff = 0; if (off == 0) { pos += sprintf(pos, "%s: version %s", stl_drvtitle, stl_drvversion); while (pos < (page + MAXLINE - 1)) *pos++ = ' '; *pos++ = '\n'; } curoff = MAXLINE;/* * We scan through for each board, panel and port. The offset is * calculated on the fly, and irrelevant ports are skipped. */ for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) { brdp = stl_brds[brdnr]; if (brdp == (stlbrd_t *) NULL) continue; if (brdp->state == 0) continue; maxoff = curoff + (brdp->nrports * MAXLINE); if (off >= maxoff) { curoff = maxoff; continue; } totalport = brdnr * STL_MAXPORTS; for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { panelp = brdp->panels[panelnr]; if (panelp == (stlpanel_t *) NULL) continue; maxoff = curoff + (panelp->nrports * MAXLINE); if (off >= maxoff) { curoff = maxoff; totalport += panelp->nrports; continue; } for (portnr = 0; (portnr < panelp->nrports); portnr++, totalport++) { portp = panelp->ports[portnr]; if (portp == (stlport_t *) NULL) continue; if (off >= (curoff += MAXLINE)) continue; if ((pos - page + MAXLINE) > count) goto stl_readdone; pos += stl_portinfo(portp, totalport, pos); } } } *eof = 1;stl_readdone: *start = page; return(pos - page);}/*****************************************************************************//* * All board interrupts are vectored through here first. This code then * calls off to the approrpriate board interrupt handlers. */static void stl_intr(int irq, void *dev_id, struct pt_regs *regs){ stlbrd_t *brdp; int i;#if DEBUG printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs);#endif for (i = 0; (i < stl_nrbrds); i++) { if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) continue; if (brdp->state == 0) continue; (* brdp->isr)(brdp); }}/*****************************************************************************//* * Interrupt service routine for EasyIO board types. */static void stl_eiointr(stlbrd_t *brdp){ stlpanel_t *panelp; unsigned int iobase; panelp = brdp->panels[0]; iobase = panelp->iobase; while (inb(brdp->iostatus) & EIO_INTRPEND) (* panelp->isr)(panelp, iobase);}/*****************************************************************************//* * Interrupt service routine for ECH-AT board types. */static void stl_echatintr(stlbrd_t *brdp){ stlpanel_t *panelp; unsigned int ioaddr; int bnknr; outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); while (inb(brdp->iostatus) & ECH_INTRPEND) { for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { panelp = brdp->bnk2panel[bnknr]; (* panelp->isr)(panelp, (ioaddr & 0xfffc)); } } } outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);}/*****************************************************************************//* * Interrupt service routine for ECH-MCA board types. */static void stl_echmcaintr(stlbrd_t *brdp){ stlpanel_t *panelp; unsigned int ioaddr; int bnknr; while (inb(brdp->iostatus) & ECH_INTRPEND) { for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { panelp = brdp->bnk2panel[bnknr]; (* panelp->isr)(panelp, (ioaddr & 0xfffc)); } } }}/*****************************************************************************//* * Interrupt service routine for ECH-PCI board types. */static void stl_echpciintr(stlbrd_t *brdp){ stlpanel_t *panelp; unsigned int ioaddr; int bnknr, recheck; while (1) { recheck = 0; for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl); ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { panelp = brdp->bnk2panel[bnknr]; (* panelp->isr)(panelp, (ioaddr & 0xfffc)); recheck++; } } if (! recheck) break; }}/*****************************************************************************//* * Interrupt service routine for ECH-8/64-PCI board types. */static void stl_echpci64intr(stlbrd_t *brdp){ stlpanel_t *panelp; unsigned int ioaddr; int bnknr; while (inb(brdp->ioctrl) & 0x1) { for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { panelp = brdp->bnk2panel[bnknr]; (* panelp->isr)(panelp, (ioaddr & 0xfffc)); } } }}/*****************************************************************************//* * Service an off-level request for some channel. */static void stl_offintr(void *private){ stlport_t *portp; struct tty_struct *tty; unsigned int oldsigs; portp = private;#if DEBUG printk("stl_offintr(portp=%x)\n", (int) portp);#endif if (portp == (stlport_t *) NULL) return; tty = portp->tty; if (tty == (struct tty_struct *) NULL) return; lock_kernel(); if (test_bit(ASYI_TXLOW, &portp->istate)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); } if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { clear_bit(ASYI_DCDCHANGE, &portp->istate); oldsigs = portp->sigs; portp->sigs = stl_getsignals(portp); if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) wake_up_interruptible(&portp->open_wait); if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { if (portp->flags & ASYNC_CHECK_CD) { if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && (portp->flags & ASYNC_CALLOUT_NOHUP))) { tty_hangup(tty); } } } } unlock_kernel();}/*****************************************************************************//* * Map in interrupt vector to this driver. Check that we don't * already have this vector mapped, we might be sharing this * interrupt across multiple boards. */__initfunc(static int stl_mapirq(int irq, char *name)){ int rc, i;#if DEBUG printk("stl_mapirq(irq=%d,name=%s)\n", irq, name);#endif rc = 0; for (i = 0; (i < stl_numintrs); i++) { if (stl_gotintrs[i] == irq) break; } if (i >= stl_numintrs) { if (request_irq(irq, stl_intr, SA_INTERRUPT, name, NULL) != 0) { printk("STALLION: failed to register interrupt " "routine for %s irq=%d\n", name, irq); rc = -ENODEV; } else { stl_gotintrs[stl_numintrs++] = irq; } } return(rc);}/*****************************************************************************//* * Initialize all the ports on a panel. */__initfunc(static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)){ stlport_t *portp; int chipmask, i;#if DEBUG printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);#endif chipmask = stl_panelinit(brdp, panelp);/* * All UART's are initialized (if found!). Now go through and setup * each ports data structures. */ for (i = 0; (i < panelp->nrports); i++) { portp = (stlport_t *) stl_memalloc(sizeof(stlport_t)); if (portp == (stlport_t *) NULL) { printk("STALLION: failed to allocate memory " "(size=%d)\n", sizeof(stlport_t)); break; } memset(portp, 0, sizeof(stlport_t)); portp->magic = STL_PORTMAGIC; portp->portnr = i; portp->brdnr = panelp->brdnr; portp->panelnr = panelp->panelnr; portp->uartp = panelp->uartp; portp->clk = brdp->clk; portp->baud_base = STL_BAUDBASE; portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; portp->normaltermios = stl_deftermios; portp->callouttermios = stl_deftermios; portp->tqueue.routine = stl_offintr; portp->tqueue.data = portp; portp->stats.brd = portp->brdnr; portp->stats.panel = portp->panelnr; portp->stats.port = portp->portnr; panelp->ports[i] = portp; stl_portinit(brdp, panelp, portp); } return(0);}/*****************************************************************************//* * Try to find and initialize an EasyIO board. */static inline int stl_initeio(stlbrd_t *brdp){ stlpanel_t *panelp; unsigned int status; char *name; int rc;#if DEBUG printk("stl_initeio(brdp=%x)\n", (int) brdp);#endif brdp->ioctrl = brdp->ioaddr1 + 1; brdp->iostatus = brdp->ioaddr1 + 2; status = inb(brdp->iostatus); if ((status & EIO_IDBITMASK) == EIO_MK3) brdp->ioctrl++;/* * Handle board specific stuff now. The real difference is PCI * or not PCI. */ if (brdp->brdtype == BRD_EASYIOPCI) { brdp->iosize1 = 0x80; brdp->iosize2 = 0x80; name = "serial(EIO-PCI)"; outb(0x41, (brdp->ioaddr2 + 0x4c)); } else { brdp->iosize1 = 8; name = "serial(EIO)"; 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); return(-EINVAL); } outb((stl_vecmap[brdp->irq] | EIO_0WS | ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), brdp->ioctrl); } if (check_region(brdp->ioaddr1, brdp->iosize1)) { printk("STALLION: Warning, board %d I/O address %x conflicts " "with another device\n", brdp->brdnr, brdp->ioaddr1); } if (brdp->iosize2 > 0) { if (check_region(brdp->ioaddr2, brdp->iosize2)) { printk("STALLION: Warning, board %d I/O address %x " "conflicts with another device\n", brdp->brdnr, brdp->ioaddr2); } } /* * Everything looks OK, so let's go ahead and probe for the hardware. */ brdp->clk = CD1400_CLK; brdp->isr = stl_eiointr; switch (status & EIO_IDBITMASK) { case EIO_8PORTM: brdp->clk = CD1400_CLK8M; /* fall thru */ case EIO_8PORTRS: case EIO_8PORTDI: brdp->nrports = 8; break; case EIO_4PORTRS: brdp->nrports = 4; break; case EIO_MK3: switch (status & EIO_BRDMASK) { case ID_BRD4: brdp->nrports = 4; break; case ID_BRD8: brdp->nrports = 8; break; case ID_BRD16: brdp->nrports = 16; break; default: return(-ENODEV); } break; default: return(-ENODEV); }/* * We have verfied that the board is actually present, so now we * can complete the setup. */ request_region(brdp->ioaddr1, brdp->iosize1, name); if (brdp->iosize2 > 0) request_region(brdp->ioaddr2, brdp->iosize2, name); panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); if (panelp == (stlpanel_t *) NULL) { printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t)); return(-ENOMEM); } memset(panelp, 0, sizeof(stlpanel_t)); panelp->magic = STL_PANELMAGIC; panelp->brdnr = brdp->brdnr; panelp->panelnr = 0; panelp->nrports = brdp->nrports; pan
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -