stallion.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,504 行 · 第 1/5 页

C
2,504
字号
					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 irqreturn_t stl_intr(int irq, void *dev_id, struct pt_regs *regs){	stlbrd_t	*brdp;	int		i;	int handled = 0;#ifdef 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;		handled = 1;		(* brdp->isr)(brdp);	}	return IRQ_RETVAL(handled);}/*****************************************************************************//* *	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;#ifdef 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)) {		tty_wakeup(tty);	}	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)				tty_hangup(tty);	/* FIXME: module removal race here - AKPM */		}	}	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. */static int __init stl_mapirq(int irq, char *name){	int	rc, i;#ifdef 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_SHIRQ, 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. */static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp){	stlport_t	*portp;	int		chipmask, i;#ifdef 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;		INIT_WORK(&portp->tqueue, stl_offintr, portp);		init_waitqueue_head(&portp->open_wait);		init_waitqueue_head(&portp->close_wait);		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;#ifdef 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 (!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);		return(-EBUSY);	}		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);			release_region(brdp->ioaddr1, brdp->iosize1);        		return(-EBUSY);		}/* *	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 verified that the board is actually present, so now we *	can complete the setup. */	panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));	if (panelp == (stlpanel_t *) NULL) {		printk(KERN_WARNING "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;	panelp->iobase = brdp->ioaddr1;	panelp->hwid = status;	if ((status & EIO_IDBITMASK) == EIO_MK3) {		panelp->uartp = (void *) &stl_sc26198uart;		panelp->isr = stl_sc26198intr;	} else {		panelp->uartp = (void *) &stl_cd1400uart;		panelp->isr = stl_cd1400eiointr;	}	brdp->panels[0] = panelp;	brdp->nrpanels = 1;	brdp->state |= BRD_FOUND;	brdp->hwid = status;	rc = stl_mapirq(brdp->irq, name);	return(rc);}/*****************************************************************************//* *	Try to find an ECH board and initialize it. This code is capable of *	dealing with all types of ECH board. */static inline int stl_initech(stlbrd_t *brdp){	stlpanel_t	*panelp;	unsigned int	status, nxtid, ioaddr, conflict;	int		panelnr, banknr, i;	char		*name;#ifdef DEBUG	printk("stl_initech(brdp=%x)\n", (int) brdp);#endif	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)			return(-ENODEV);		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);		}		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)			return(-ENODEV);		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(ECHMC_BRDRESET, brdp->ioctrl);		outb(ECHMC_INTENABLE, brdp->ioctrl);		brdp->iosize1 = 64;		name = "serial(EC8/32-MC)";		break;	case BRD_ECHPCI:		brdp-

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?