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

📄 zs.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
			c = cs->cs_rbuf[get++ & ZLRB_RING_MASK];			switch (ZRING_TYPE(c)) {			case ZRING_RINT:				c = ZRING_VALUE(c);				if (c & ZSRR1_DO)					zsoverrun(unit, &cs->cs_fotime, "fifo");				cc = c >> 8;				if (c & ZSRR1_FE)					cc |= TTY_FE;				if (c & ZSRR1_PE)					cc |= TTY_PE;				/*				 * this should be done through				 * bstreams	XXX gag choke				 */				if (unit == ZS_KBD)					kbd_rint(cc);				else if (unit == ZS_MOUSE)					ms_rint(cc);				else					line->l_rint(cc, tp);				break;			case ZRING_XINT:				/*				 * Transmit done: change registers and resume,				 * or clear BUSY.				 */				if (cs->cs_heldchange) {					s = splzs();					c = zc->zc_csr;					if ((c & ZSRR0_DCD) == 0)						cs->cs_preg[3] &= ~ZSWR3_HFC;					bcopy((caddr_t)cs->cs_preg,					    (caddr_t)cs->cs_creg, 16);					zs_loadchannelregs(zc, cs->cs_creg);					splx(s);					cs->cs_heldchange = 0;					if (cs->cs_heldtbc &&					    (tp->t_state & TS_TTSTOP) == 0) {						cs->cs_tbc = cs->cs_heldtbc - 1;						zc->zc_data = *cs->cs_tba++;						goto again;					}				}				tp->t_state &= ~TS_BUSY;				if (tp->t_state & TS_FLUSH)					tp->t_state &= ~TS_FLUSH;				else					ndflush(&tp->t_outq,					    cs->cs_tba - tp->t_outq.c_cf);				line->l_start(tp);				break;			case ZRING_SINT:				/*				 * Status line change.  HFC bit is run in				 * hardware interrupt, to avoid locking				 * at splzs here.				 */				c = ZRING_VALUE(c);				if ((c ^ cs->cs_rr0) & ZSRR0_DCD) {					cc = (c & ZSRR0_DCD) != 0;					if (line->l_modem(tp, cc) == 0)						zs_modem(cs, cc);				}				cs->cs_rr0 = c;				break;			default:				log(LOG_ERR, "zs%d%c: bad ZRING_TYPE (%x)\n",				    unit >> 1, (unit & 1) + 'a', c);				break;			}		}		cs->cs_rbget = get;		goto again;	}	return (1);}intzsioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p){	int unit = minor(dev);	struct zsinfo *zi = zscd.cd_devs[unit >> 1];	register struct tty *tp = zi->zi_cs[unit & 1].cs_ttyp;	register int error;	error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p);	if (error >= 0)		return (error);	error = ttioctl(tp, cmd, data, flag);	if (error >= 0)		return (error);	switch (cmd) {	case TIOCSBRK:		/* FINISH ME ... need implicit TIOCCBRK in zsclose as well */	case TIOCCBRK:	case TIOCSDTR:	case TIOCCDTR:	case TIOCMSET:	case TIOCMBIS:	case TIOCMBIC:	case TIOCMGET:	default:		return (ENOTTY);	}	return (0);}/* * Start or restart transmission. */static voidzsstart(register struct tty *tp){	register struct zs_chanstate *cs;	register int s, nch;	int unit = minor(tp->t_dev);	struct zsinfo *zi = zscd.cd_devs[unit >> 1];	cs = &zi->zi_cs[unit & 1];	s = spltty();	/*	 * If currently active or delaying, no need to do anything.	 */	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))		goto out;	/*	 * If there are sleepers, and output has drained below low	 * water mark, awaken.	 */	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);	}	nch = ndqb(&tp->t_outq, 0);	/* XXX */	if (nch) {		register char *p = tp->t_outq.c_cf;		/* mark busy, enable tx done interrupts, & send first byte */		tp->t_state |= TS_BUSY;		(void) splzs();		cs->cs_preg[1] |= ZSWR1_TIE;		cs->cs_creg[1] |= ZSWR1_TIE;		ZS_WRITE(cs->cs_zc, 1, cs->cs_creg[1]);		cs->cs_zc->zc_data = *p;		cs->cs_tba = p + 1;		cs->cs_tbc = nch - 1;	} else {		/*		 * Nothing to send, turn off transmit done interrupts.		 * This is useful if something is doing polled output.		 */		(void) splzs();		cs->cs_preg[1] &= ~ZSWR1_TIE;		cs->cs_creg[1] &= ~ZSWR1_TIE;		ZS_WRITE(cs->cs_zc, 1, cs->cs_creg[1]);	}out:	splx(s);}/* * Stop output, e.g., for ^S or output flush. */static voidzsstop(register struct tty *tp, int flag){	register struct zs_chanstate *cs;	register int s, unit = minor(tp->t_dev);	struct zsinfo *zi = zscd.cd_devs[unit >> 1];	cs = &zi->zi_cs[unit & 1];	s = splzs();	if (tp->t_state & TS_BUSY) {		/*		 * Device is transmitting; must stop it.		 */		cs->cs_tbc = 0;		if ((tp->t_state & TS_TTSTOP) == 0)			tp->t_state |= TS_FLUSH;	}	splx(s);}/* * Set ZS tty parameters from termios. * * This routine makes use of the fact that only registers * 1, 3, 4, 5, 9, 10, 11, 12, 13, 14, and 15 are written. */static intzsparam(register struct tty *tp, register struct termios *t){	int unit = minor(tp->t_dev);	struct zsinfo *zi = zscd.cd_devs[unit >> 1];	register struct zs_chanstate *cs = &zi->zi_cs[unit & 1];	register int tmp, tmp5, cflag, s;	/*	 * Because PCLK is only run at 4.9 MHz, the fastest we	 * can go is 51200 baud (this corresponds to TC=1).	 * This is somewhat unfortunate as there is no real	 * reason we should not be able to handle higher rates.	 */	tmp = t->c_ospeed;	if (tmp < 0 || (t->c_ispeed && t->c_ispeed != tmp))		return (EINVAL);	if (tmp == 0) {		/* stty 0 => drop DTR and RTS */		zs_modem(cs, 0);		return (0);	}	tmp = BPS_TO_TCONST(PCLK / 16, tmp);	if (tmp < 2)		return (EINVAL);	cflag = t->c_cflag;	tp->t_ispeed = tp->t_ospeed = TCONST_TO_BPS(PCLK / 16, tmp);	tp->t_cflag = cflag;	/*	 * Block interrupts so that state will not	 * be altered until we are done setting it up.	 */	s = splzs();	cs->cs_preg[12] = tmp;	cs->cs_preg[13] = tmp >> 8;	cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE;	switch (cflag & CSIZE) {	case CS5:		tmp = ZSWR3_RX_5;		tmp5 = ZSWR5_TX_5;		break;	case CS6:		tmp = ZSWR3_RX_6;		tmp5 = ZSWR5_TX_6;		break;	case CS7:		tmp = ZSWR3_RX_7;		tmp5 = ZSWR5_TX_7;		break;	case CS8:	default:		tmp = ZSWR3_RX_8;		tmp5 = ZSWR5_TX_8;		break;	}	/*	 * Output hardware flow control on the chip is horrendous: if	 * carrier detect drops, the receiver is disabled.  Hence we	 * can only do this when the carrier is on.	 */	if (cflag & CCTS_OFLOW && cs->cs_zc->zc_csr & ZSRR0_DCD)		tmp |= ZSWR3_HFC | ZSWR3_RX_ENABLE;	else		tmp |= ZSWR3_RX_ENABLE;	cs->cs_preg[3] = tmp;	cs->cs_preg[5] = tmp5 | ZSWR5_TX_ENABLE | ZSWR5_DTR | ZSWR5_RTS;	tmp = ZSWR4_CLK_X16 | (cflag & CSTOPB ? ZSWR4_TWOSB : ZSWR4_ONESB);	if ((cflag & PARODD) == 0)		tmp |= ZSWR4_EVENP;	if (cflag & PARENB)		tmp |= ZSWR4_PARENB;	cs->cs_preg[4] = tmp;	cs->cs_preg[9] = ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR;	cs->cs_preg[10] = ZSWR10_NRZ;	cs->cs_preg[11] = ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD;	cs->cs_preg[14] = ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA;	cs->cs_preg[15] = ZSWR15_BREAK_IE | ZSWR15_DCD_IE;	/*	 * If nothing is being transmitted, set up new current values,	 * else mark them as pending.	 */	if (cs->cs_heldchange == 0) {		if (cs->cs_ttyp->t_state & TS_BUSY) {			cs->cs_heldtbc = cs->cs_tbc;			cs->cs_tbc = 0;			cs->cs_heldchange = 1;		} else {			bcopy((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16);			zs_loadchannelregs(cs->cs_zc, cs->cs_creg);		}	}	splx(s);	return (0);}/* * Raise or lower modem control (DTR/RTS) signals.  If a character is * in transmission, the change is deferred. */static voidzs_modem(struct zs_chanstate *cs, int onoff){	int s, bis, and;	if (onoff) {		bis = ZSWR5_DTR | ZSWR5_RTS;		and = ~0;	} else {		bis = 0;		and = ~(ZSWR5_DTR | ZSWR5_RTS);	}	s = splzs();	cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and;	if (cs->cs_heldchange == 0) {		if (cs->cs_ttyp->t_state & TS_BUSY) {			cs->cs_heldtbc = cs->cs_tbc;			cs->cs_tbc = 0;			cs->cs_heldchange = 1;		} else {			cs->cs_creg[5] = (cs->cs_creg[5] | bis) & and;			ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]);		}	}	splx(s);}/* * Write the given register set to the given zs channel in the proper order. * The channel must not be transmitting at the time.  The receiver will * be disabled for the time it takes to write all the registers. */static voidzs_loadchannelregs(volatile struct zschan *zc, u_char *reg){	int i;	zc->zc_csr = ZSM_RESET_ERR;	/* reset error condition */	i = zc->zc_data;		/* drain fifo */	i = zc->zc_data;	i = zc->zc_data;	ZS_WRITE(zc, 4, reg[4]);	ZS_WRITE(zc, 10, reg[10]);	ZS_WRITE(zc, 3, reg[3] & ~ZSWR3_RX_ENABLE);	ZS_WRITE(zc, 5, reg[5] & ~ZSWR5_TX_ENABLE);	ZS_WRITE(zc, 1, reg[1]);	ZS_WRITE(zc, 9, reg[9]);	ZS_WRITE(zc, 11, reg[11]);	ZS_WRITE(zc, 12, reg[12]);	ZS_WRITE(zc, 13, reg[13]);	ZS_WRITE(zc, 14, reg[14]);	ZS_WRITE(zc, 15, reg[15]);	ZS_WRITE(zc, 3, reg[3]);	ZS_WRITE(zc, 5, reg[5]);}#ifdef KGDB/* * Get a character from the given kgdb channel.  Called at splhigh(). */static intzs_kgdb_getc(void *arg){	register volatile struct zschan *zc = (volatile struct zschan *)arg;	while ((zc->zc_csr & ZSRR0_RX_READY) == 0)		continue;	return (zc->zc_data);}/* * Put a character to the given kgdb channel.  Called at splhigh(). */static voidzs_kgdb_putc(void *arg, int c){	register volatile struct zschan *zc = (volatile struct zschan *)arg;	while ((zc->zc_csr & ZSRR0_TX_READY) == 0)		continue;	zc->zc_data = c;}/* * Set up for kgdb; called at boot time before configuration. * KGDB interrupts will be enabled later when zs0 is configured. */voidzs_kgdb_init(){	volatile struct zsdevice *addr;	volatile struct zschan *zc;	int unit, zs;	if (major(kgdb_dev) != ZSMAJOR)		return;	unit = minor(kgdb_dev);	/*	 * Unit must be 0 or 1 (zs0).	 */	if ((unsigned)unit >= ZS_KBD) {		printf("zs_kgdb_init: bad minor dev %d\n", unit);		return;	}	zs = unit >> 1;	if ((addr = zsaddr[zs]) == NULL)		addr = zsaddr[zs] = findzs(zs);	unit &= 1;	zc = unit == 0 ? &addr->zs_chan[CHAN_A] : &addr->zs_chan[CHAN_B];	zs_kgdb_savedspeed = zs_getspeed(zc);	printf("zs_kgdb_init: attaching zs%d%c at %d baud\n",	    zs, unit + 'a', kgdb_rate);	zs_reset(zc, 1, kgdb_rate);	kgdb_attach(zs_kgdb_getc, zs_kgdb_putc, (void *)zc);}#endif /* KGDB */

⌨️ 快捷键说明

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