⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scc.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	if (ospeed == 0) {		(void) sccmctl(tp->t_dev, 0, DMSET);	/* hang up line */		return (0);	}	/* reset line */	if (line == SCC_CHANNEL_A)		value = SCC_WR9_RESET_CHA_A;	else		value = SCC_WR9_RESET_CHA_B;	SCC_WRITE_REG(regs, line, SCC_WR9, value);	DELAY(25);	/* stop bits, normally 1 */	value = sc->scc_wreg[line].wr4 & 0xf0;	if (cflag & CSTOPB)		value |= SCC_WR4_2_STOP;	else		value |= SCC_WR4_1_STOP;	if ((cflag & PARODD) == 0)		value |= SCC_WR4_EVEN_PARITY;	if (cflag & PARENB)		value |= SCC_WR4_PARITY_ENABLE;	/* set it now, remember it must be first after reset */	sc->scc_wreg[line].wr4 = value;	SCC_WRITE_REG(regs, line, SCC_WR4, value);	/* vector again */	SCC_WRITE_REG(regs, line, SCC_WR2, 0xf0);	/* clear break, keep rts dtr */	wvalue = sc->scc_wreg[line].wr5 & (SCC_WR5_DTR|SCC_WR5_RTS);	switch (cflag & CSIZE) {	case CS5:		value = SCC_WR3_RX_5_BITS;		wvalue |= SCC_WR5_TX_5_BITS;		break;	case CS6:		value = SCC_WR3_RX_6_BITS;		wvalue |= SCC_WR5_TX_6_BITS;		break;	case CS7:		value = SCC_WR3_RX_7_BITS;		wvalue |= SCC_WR5_TX_7_BITS;		break;	case CS8:	default:		value = SCC_WR3_RX_8_BITS;		wvalue |= SCC_WR5_TX_8_BITS;	};	sc->scc_wreg[line].wr3 = value;	SCC_WRITE_REG(regs, line, SCC_WR3, value);	sc->scc_wreg[line].wr5 = wvalue;	SCC_WRITE_REG(regs, line, SCC_WR5, wvalue);	SCC_WRITE_REG(regs, line, SCC_WR6, 0);	SCC_WRITE_REG(regs, line, SCC_WR7, 0);	SCC_WRITE_REG(regs, line, SCC_WR9, SCC_WR9_VIS);	SCC_WRITE_REG(regs, line, SCC_WR10, 0);	value = SCC_WR11_RCLK_BAUDR | SCC_WR11_XTLK_BAUDR |		SCC_WR11_TRc_OUT | SCC_WR11_TRcOUT_BAUDR;	SCC_WRITE_REG(regs, line, SCC_WR11, value);	SCC_SET_TIMING_BASE(regs, line, ospeed);	value = sc->scc_wreg[line].wr14;	SCC_WRITE_REG(regs, line, SCC_WR14, value);	value = SCC_WR15_BREAK_IE | SCC_WR15_CTS_IE | SCC_WR15_DCD_IE;	SCC_WRITE_REG(regs, line, SCC_WR15, value);	/* and now the enables */	value = sc->scc_wreg[line].wr3 | SCC_WR3_RX_ENABLE;	SCC_WRITE_REG(regs, line, SCC_WR3, value);	value = sc->scc_wreg[line].wr5 | SCC_WR5_TX_ENABLE;	sc->scc_wreg[line].wr5 = value;	SCC_WRITE_REG(regs, line, SCC_WR5, value);	/* master inter enable */	value = SCC_WR9_MASTER_IE | SCC_WR9_VIS;	SCC_WRITE_REG(regs, line, SCC_WR9, value);	SCC_WRITE_REG(regs, line, SCC_WR1, sc->scc_wreg[line].wr1);	MachEmptyWriteBuffer();	return (0);}/* * Check for interrupts from all devices. */voidsccintr(unit)	register int unit;{	register scc_regmap_t *regs;	register struct tty *tp;	register struct pdma *dp;	register struct scc_softc *sc;	register int cc, chan, rr1, rr2, rr3;	int overrun = 0;	sc = &scc_softc[unit];	regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;	unit <<= 1;	for (;;) {	    SCC_READ_REG(regs, SCC_CHANNEL_B, SCC_RR2, rr2);	    rr2 = SCC_RR2_STATUS(rr2);	    /* are we done yet ? */	    if (rr2 == 6) {	/* strange, distinguished value */		SCC_READ_REG(regs, SCC_CHANNEL_A, SCC_RR3, rr3);		if (rr3 == 0)			return;	    }	    SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS);	    if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) {		chan = (rr2 == SCC_RR2_A_XMIT_DONE) ?			SCC_CHANNEL_A : SCC_CHANNEL_B;		tp = &scc_tty[unit | chan];		dp = &sc->scc_pdma[chan];		if (dp->p_mem < dp->p_end) {			SCC_WRITE_DATA(regs, chan, *dp->p_mem++);			MachEmptyWriteBuffer();		} else {			tp->t_state &= ~TS_BUSY;			if (tp->t_state & TS_FLUSH)				tp->t_state &= ~TS_FLUSH;			else {				ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);				dp->p_end = dp->p_mem = tp->t_outq.c_cf;			}			if (tp->t_line)				(*linesw[tp->t_line].l_start)(tp);			else				sccstart(tp);			if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {				SCC_READ_REG(regs, chan, SCC_RR15, cc);				cc &= ~SCC_WR15_TX_UNDERRUN_IE;				SCC_WRITE_REG(regs, chan, SCC_WR15, cc);				cc = sc->scc_wreg[chan].wr1 & ~SCC_WR1_TX_IE;				SCC_WRITE_REG(regs, chan, SCC_WR1, cc);				sc->scc_wreg[chan].wr1 = cc;				MachEmptyWriteBuffer();			}		}	    } else if (rr2 == SCC_RR2_A_RECV_DONE ||		rr2 == SCC_RR2_B_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL ||		rr2 == SCC_RR2_B_RECV_SPECIAL) {		if (rr2 == SCC_RR2_A_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL)			chan = SCC_CHANNEL_A;		else			chan = SCC_CHANNEL_B;		tp = &scc_tty[unit | chan];		SCC_READ_DATA(regs, chan, cc);		if (rr2 == SCC_RR2_A_RECV_SPECIAL ||			rr2 == SCC_RR2_B_RECV_SPECIAL) {			SCC_READ_REG(regs, chan, SCC_RR1, rr1);			SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_ERROR);			if ((rr1 & SCC_RR1_RX_OVERRUN) && overrun == 0) {				log(LOG_WARNING, "scc%d,%d: silo overflow\n",					unit >> 1, chan);				overrun = 1;			}		}		/*		 * Keyboard needs special treatment.		 */		if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {#ifdef KADB			if (cc == LK_DO) {				spl0();				kdbpanic();				return;			}#endif#ifdef DEBUG			debugChar = cc;#endif			if (sccDivertXInput) {				(*sccDivertXInput)(cc);				continue;			}			if ((cc = kbdMapChar(cc)) < 0)				continue;		/*		 * Now for mousey		 */		} else if (tp == &scc_tty[SCCMOUSE_PORT] && sccMouseButtons) {			register MouseReport *mrp;			static MouseReport currentRep;			mrp = &currentRep;			mrp->byteCount++;			if (cc & MOUSE_START_FRAME) {				/*				 * The first mouse report byte (button state).				 */				mrp->state = cc;				if (mrp->byteCount > 1)					mrp->byteCount = 1;			} else if (mrp->byteCount == 2) {				/*				 * The second mouse report byte (delta x).				 */				mrp->dx = cc;			} else if (mrp->byteCount == 3) {				/*				 * The final mouse report byte (delta y).				 */				mrp->dy = cc;				mrp->byteCount = 0;				if (mrp->dx != 0 || mrp->dy != 0) {					/*					 * If the mouse moved,					 * post a motion event.					 */					(*sccMouseEvent)(mrp);				}				(*sccMouseButtons)(mrp);			}			continue;		}		if (!(tp->t_state & TS_ISOPEN)) {			wakeup((caddr_t)&tp->t_rawq);#ifdef PORTSELECTOR			if (!(tp->t_state & TS_WOPEN))#endif				continue;		}		if (rr2 == SCC_RR2_A_RECV_SPECIAL ||			rr2 == SCC_RR2_B_RECV_SPECIAL) {			if (rr1 & SCC_RR1_PARITY_ERR)				cc |= TTY_PE;			if (rr1 & SCC_RR1_FRAME_ERR)				cc |= TTY_FE;		}		(*linesw[tp->t_line].l_rint)(cc, tp);	    } else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) {		chan = (rr2 == SCC_RR2_A_EXT_STATUS) ?			SCC_CHANNEL_A : SCC_CHANNEL_B;		SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_EXT_IP);		scc_modem_intr(unit | chan);	    }	}}voidsccstart(tp)	register struct tty *tp;{	register struct pdma *dp;	register scc_regmap_t *regs;	register struct scc_softc *sc;	register int cc, chan;	u_char temp;	int s, sendone;	sc = &scc_softc[SCCUNIT(tp->t_dev)];	dp = &sc->scc_pdma[SCCLINE(tp->t_dev)];	regs = (scc_regmap_t *)dp->p_addr;	s = spltty();	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))		goto out;	if (tp->t_outq.c_cc <= tp->t_lowat) {		if (tp->t_state & TS_ASLEEP) {			tp->t_state &= ~TS_ASLEEP;			wakeup((caddr_t)&tp->t_outq);		}		selwakeup(&tp->t_wsel);	}	if (tp->t_outq.c_cc == 0)		goto out;	/* handle console specially */	if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {		while (tp->t_outq.c_cc > 0) {			cc = getc(&tp->t_outq) & 0x7f;			cnputc(cc);		}		/*		 * After we flush the output queue we may need to wake		 * up the process that made the output.		 */		if (tp->t_outq.c_cc <= tp->t_lowat) {			if (tp->t_state & TS_ASLEEP) {				tp->t_state &= ~TS_ASLEEP;				wakeup((caddr_t)&tp->t_outq);			}			selwakeup(&tp->t_wsel);		}		goto out;	}	if (tp->t_flags & (RAW|LITOUT))		cc = ndqb(&tp->t_outq, 0);	else {		cc = ndqb(&tp->t_outq, 0200);		if (cc == 0) {			cc = getc(&tp->t_outq);			timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6);			tp->t_state |= TS_TIMEOUT;			goto out;		}	}	tp->t_state |= TS_BUSY;	dp->p_end = dp->p_mem = tp->t_outq.c_cf;	dp->p_end += cc;	/*	 * Enable transmission and send the first char, as required.	 */	chan = SCCLINE(tp->t_dev);	SCC_READ_REG(regs, chan, SCC_RR0, temp);	sendone = (temp & SCC_RR0_TX_EMPTY);	SCC_READ_REG(regs, chan, SCC_RR15, temp);	temp |= SCC_WR15_TX_UNDERRUN_IE;	SCC_WRITE_REG(regs, chan, SCC_WR15, temp);	temp = sc->scc_wreg[chan].wr1 | SCC_WR1_TX_IE;	SCC_WRITE_REG(regs, chan, SCC_WR1, temp);	sc->scc_wreg[chan].wr1 = temp;	if (sendone) {#ifdef DIAGNOSTIC		if (cc == 0)			panic("sccstart: No chars");#endif		SCC_WRITE_DATA(regs, chan, *dp->p_mem++);	}	MachEmptyWriteBuffer();out:	splx(s);}/* * Stop output on a line. *//*ARGSUSED*/sccstop(tp, flag)	register struct tty *tp;{	register struct pdma *dp;	register struct scc_softc *sc;	register int s;	sc = &scc_softc[SCCUNIT(tp->t_dev)];	dp = &sc->scc_pdma[SCCLINE(tp->t_dev)];	s = spltty();	if (tp->t_state & TS_BUSY) {		dp->p_end = dp->p_mem;		if (!(tp->t_state & TS_TTSTOP))			tp->t_state |= TS_FLUSH;	}	splx(s);}sccmctl(dev, bits, how)	dev_t dev;	int bits, how;{	register struct scc_softc *sc;	register scc_regmap_t *regs;	register int line, mbits;	register u_char value;	int s;	sc = &scc_softc[SCCUNIT(dev)];	line = SCCLINE(dev);	regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;	s = spltty();	/*	 * only channel B has modem control, however the DTR and RTS	 * pins on the comm port are wired to the DTR and RTS A channel	 * signals.	 */	mbits = DML_DTR | DML_DSR | DML_CAR;	if (line == SCC_CHANNEL_B) {		if (sc->scc_wreg[SCC_CHANNEL_A].wr5 & SCC_WR5_DTR)			mbits = DML_DTR | DML_DSR;		else			mbits = 0;		SCC_READ_REG_ZERO(regs, SCC_CHANNEL_B, value);		if (value & SCC_RR0_DCD)			mbits |= DML_CAR;	}	switch (how) {	case DMSET:		mbits = bits;		break;	case DMBIS:		mbits |= bits;		break;	case DMBIC:		mbits &= ~bits;		break;	case DMGET:		(void) splx(s);		return (mbits);	}	if (line == SCC_CHANNEL_B) {		if (mbits & DML_DTR)			sc->scc_wreg[SCC_CHANNEL_A].wr5 |= SCC_WR5_DTR;		else			sc->scc_wreg[SCC_CHANNEL_A].wr5 &= ~SCC_WR5_DTR;		SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR5,			sc->scc_wreg[SCC_CHANNEL_A].wr5);	}	if ((mbits & DML_DTR) && (sc->scc_softCAR & (1 << line)))		scc_tty[minor(dev)].t_state |= TS_CARR_ON;	(void) splx(s);	return (mbits);}/* * Check for carrier transition. */static voidscc_modem_intr(dev)	dev_t dev;{	register scc_regmap_t *regs;	register struct scc_softc *sc;	register struct tty *tp;	register int car, chan;	register u_char value;	int s;	sc = &scc_softc[SCCUNIT(dev)];	tp = &scc_tty[minor(dev)];	chan = SCCLINE(dev);	regs = (scc_regmap_t *)sc->scc_pdma[chan].p_addr;	if (chan == SCC_CHANNEL_A)		return;	s = spltty();	if (sc->scc_softCAR & (1 << chan))		car = 1;	else {		SCC_READ_REG_ZERO(regs, chan, value);		car = value & SCC_RR0_DCD;	}	if (car) {		/* carrier present */		if (!(tp->t_state & TS_CARR_ON))			(void)(*linesw[tp->t_line].l_modem)(tp, 1);	} else if (tp->t_state & TS_CARR_ON)		(void)(*linesw[tp->t_line].l_modem)(tp, 0);	splx(s);}/* * Get a char off the appropriate line via. a busy wait loop. */intsccGetc(dev)	dev_t dev;{	register scc_regmap_t *regs;	register int c, line;	register u_char value;	int s;	line = SCCLINE(dev);	regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr;	if (!regs)		return (0);	s = spltty();	for (;;) {		SCC_READ_REG(regs, line, SCC_RR0, value);		if (value & SCC_RR0_RX_AVAIL) {			SCC_READ_REG(regs, line, SCC_RR1, value);			SCC_READ_DATA(regs, line, c);			if (value & (SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN |				SCC_RR1_FRAME_ERR)) {				SCC_WRITE_REG(regs, line, SCC_WR0, SCC_RESET_ERROR);				SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,					SCC_RESET_HIGHEST_IUS);			} else {				SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,					SCC_RESET_HIGHEST_IUS);				splx(s);				return (c & 0xff);			}		} else			DELAY(10);	}}/* * Send a char on a port, via a busy wait loop. */voidsccPutc(dev, c)	dev_t dev;	int c;{	register scc_regmap_t *regs;	register int line;	register u_char value;	int s;	s = spltty();	line = SCCLINE(dev);	regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr;	/*	 * Wait for transmitter to be not busy.	 */	do {		SCC_READ_REG(regs, line, SCC_RR0, value);		if (value & SCC_RR0_TX_EMPTY)			break;		DELAY(100);	} while (1);	/*	 * Send the char.	 */	SCC_WRITE_DATA(regs, line, c);	MachEmptyWriteBuffer();	splx(s);}#endif /* NSCC */

⌨️ 快捷键说明

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