cy.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,542 行 · 第 1/5 页

C
2,542
字号
				incc += LOTS_OF_EVENTS;				com->state &= ~CS_CHECKMSR;			}			com_events -= incc;			enable_intr();			if (incc != 0)				log(LOG_DEBUG,				    "sio%d: %d events for device with no tp\n",				    unit, incc);			continue;		}		/* switch the role of the low-level input buffers */		if (com->iptr == (ibuf = com->ibuf)) {			buf = NULL;     /* not used, but compiler can't tell */			incc = 0;		} else {			buf = ibuf;			disable_intr();			incc = com->iptr - buf;			com_events -= incc;			if (ibuf == com->ibuf1)				ibuf = com->ibuf2;			else				ibuf = com->ibuf1;			com->ibufend = ibuf + RS_IBUFSIZE;			com->ihighwater = ibuf + RS_IHIGHWATER;			com->iptr = ibuf;			/*			 * There is now room for another low-level buffer full			 * of input, so enable RTS if it is now disabled and			 * there is room in the high-level buffer.			 */			/*			 * XXX this used not to look at CS_RTS_IFLOW.  The			 * change is to allow full control of MCR_RTS via			 * ioctls after turning CS_RTS_IFLOW off.  Check			 * for races.  We shouldn't allow the ioctls while			 * CS_RTS_IFLOW is on.			 */			if ((com->state & CS_RTS_IFLOW)			    && !(com->mcr_image & MCR_RTS)			    && !(tp->t_state & TS_TBLOCK))#if 0				outb(com->modem_ctl_port,				     com->mcr_image |= MCR_RTS);#else				iobase = com->iobase,				cd_outb(iobase, CD1400_CAR,					unit & CD1400_CAR_CHAN),				cd_outb(iobase, CD1400_MSVR1,					com->mcr_image |= MCR_RTS);#endif			enable_intr();			com->ibuf = ibuf;		}		if (com->state & CS_CHECKMSR) {			u_char	delta_modem_status;			disable_intr();			delta_modem_status = com->last_modem_status					     ^ com->prev_modem_status;			com->prev_modem_status = com->last_modem_status;			com_events -= LOTS_OF_EVENTS;			com->state &= ~CS_CHECKMSR;			enable_intr();			if (delta_modem_status & MSR_DCD)				(*linesw[tp->t_line].l_modem)					(tp, com->prev_modem_status & MSR_DCD);		}		if (com->state & CS_ODONE) {			disable_intr();			com_events -= LOTS_OF_EVENTS;			com->state &= ~CS_ODONE;			if (!(com->state & CS_BUSY))				com->tp->t_state &= ~TS_BUSY;			enable_intr();			(*linesw[tp->t_line].l_start)(tp);		}		if (incc <= 0 || !(tp->t_state & TS_ISOPEN))			continue;		/*		 * Avoid the grotesquely inefficient lineswitch routine		 * (ttyinput) in "raw" mode.  It usually takes about 450		 * instructions (that's without canonical processing or echo!).		 * slinput is reasonably fast (usually 40 instructions plus		 * call overhead).		 */		if (tp->t_state & TS_CAN_BYPASS_L_RINT) {			if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER			    && (com->state & CS_RTS_IFLOW				|| tp->t_iflag & IXOFF)			    && !(tp->t_state & TS_TBLOCK))				ttyblock(tp);			tk_nin += incc;			tk_rawcc += incc;			tp->t_rawcc += incc;			com->delta_error_counts[CE_TTY_BUF_OVERFLOW]				+= b_to_q((char *)buf, incc, &tp->t_rawq);			ttwakeup(tp);			if (tp->t_state & TS_TTSTOP			    && (tp->t_iflag & IXANY				|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {				tp->t_state &= ~TS_TTSTOP;				tp->t_lflag &= ~FLUSHO;				comstart(tp);			}		} else {			do {				u_char	line_status;				int	recv_data;				line_status = (u_char) buf[CE_INPUT_OFFSET];				recv_data = (u_char) *buf++;				if (line_status				    & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {					if (line_status & LSR_BI)						recv_data |= TTY_BI;					if (line_status & LSR_FE)						recv_data |= TTY_FE;					if (line_status & LSR_OE)						recv_data |= TTY_OE;					if (line_status & LSR_PE)						recv_data |= TTY_PE;				}				(*linesw[tp->t_line].l_rint)(recv_data, tp);			} while (--incc > 0);		}		if (com_events == 0)			break;	}	if (com_events >= LOTS_OF_EVENTS)		goto repeat;}static intcomparam(tp, t)	struct tty	*tp;	struct termios	*t;{	int		bits;	int		cflag;	struct com_s	*com;	u_char		cor_change;	int		idivisor;	int		iflag;	cy_addr		iobase;	int		iprescaler;	int		itimeout;	int		odivisor;	int		oprescaler;	u_char		opt;	int		s;	int		unit;	/* do historical conversions */	if (t->c_ispeed == 0)		t->c_ispeed = t->c_ospeed;	/* check requested parameters */	idivisor = comspeed(t->c_ispeed, &iprescaler);	if (idivisor < 0)		return (EINVAL);	odivisor = comspeed(t->c_ospeed, &oprescaler);	if (odivisor < 0)		return (EINVAL);	/* parameters are OK, convert them to the com struct and the device */	unit = DEV_TO_UNIT(tp->t_dev);	com = com_addr(unit);	iobase = com->iobase;	s = spltty();	cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);	if (odivisor == 0)		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */	else		(void)commctl(com, TIOCM_DTR, DMBIS);	if (idivisor != 0) {		cd_outb(iobase, CD1400_RBPR, idivisor);		cd_outb(iobase, CD1400_RCOR, iprescaler);	}	if (odivisor != 0) {		cd_outb(iobase, CD1400_TBPR, odivisor);		cd_outb(iobase, CD1400_TCOR, oprescaler);	}	/*	 * channel control	 *	receiver enable	 *	transmitter enable (always set)	 */	cflag = t->c_cflag;	opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN	      | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);	if (opt != com->channel_control) {		com->channel_control = opt;		cd1400_channel_cmd(iobase, opt);	}#ifdef Smarts	/* set special chars */	/* XXX if one is _POSIX_VDISABLE, can't use some others */	if (t->c_cc[VSTOP] != _POSIX_VDISABLE)		cd_outb(iobase, CD1400_SCHR1, t->c_cc[VSTOP]);	if (t->c_cc[VSTART] != _POSIX_VDISABLE)		cd_outb(iobase, CD1400_SCHR2, t->c_cc[VSTART]);	if (t->c_cc[VINTR] != _POSIX_VDISABLE)		cd_outb(iobase, CD1400_SCHR3, t->c_cc[VINTR]);	if (t->c_cc[VSUSP] != _POSIX_VDISABLE)		cd_outb(iobase, CD1400_SCHR4, t->c_cc[VSUSP]);#endif	/*	 * set channel option register 1 -	 *	parity mode	 *	stop bits	 *	char length	 */	opt = 0;	/* parity */	if (cflag & PARENB) {		if (cflag & PARODD)			opt |= CD1400_COR1_PARODD;		opt |= CD1400_COR1_PARNORMAL;	}	iflag = t->c_iflag;	if (!(iflag & INPCK))		opt |= CD1400_COR1_NOINPCK;	bits = 1 + 1;	/* stop bits */	if (cflag & CSTOPB) {		++bits;		opt |= CD1400_COR1_STOP2;	}	/* char length */	switch (cflag & CSIZE) {	case CS5:		bits += 5;		opt |= CD1400_COR1_CS5;		break;	case CS6:		bits += 6;		opt |= CD1400_COR1_CS6;		break;	case CS7:		bits += 7;		opt |= CD1400_COR1_CS7;		break;	default:		bits += 8;		opt |= CD1400_COR1_CS8;		break;	}	cor_change = 0;	if (opt != com->cor[0]) {		cor_change |= CD1400_CCR_COR1;		cd_outb(iobase, CD1400_COR1, com->cor[0] = opt);	}	/*	 * Set receive time-out period, normally to max(one char time, 5 ms).	 */	if (t->c_ispeed == 0)		itimeout = cd_inb(iobase, CD1400_RTPR);	else {		itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;#ifdef SOFT_HOTCHAR#define	MIN_RTP		1#else#define	MIN_RTP		5#endif		if (itimeout < MIN_RTP)			itimeout = MIN_RTP;	}	if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0	    && t->c_cc[VTIME] * 10 > itimeout)		itimeout = t->c_cc[VTIME] * 10;	if (itimeout > 255)		itimeout = 255;	cd_outb(iobase, CD1400_RTPR, itimeout);	/*	 * set channel option register 2 -	 *	flow control	 */	opt = 0;#ifdef Smarts	if (iflag & IXANY)		opt |= CD1400_COR2_IXANY;	if (iflag & IXOFF)		opt |= CD1400_COR2_IXOFF;#endif#ifndef SOFT_CTS_OFLOW	if (cflag & CCTS_OFLOW)		opt |= CD1400_COR2_CCTS_OFLOW;#endif	if (opt != com->cor[1]) {		cor_change |= CD1400_CCR_COR2;		cd_outb(iobase, CD1400_COR2, com->cor[1] = opt);	}	/*	 * set channel option register 3 -	 *	receiver FIFO interrupt threshold	 *	flow control	 */	opt = RxFifoThreshold;#ifdef Smarts	if (t->c_lflag & ICANON)		opt |= CD1400_COR3_SCD34;	/* detect INTR & SUSP chars */	if (iflag & IXOFF)		/* detect and transparently handle START and STOP chars */		opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12;#endif	if (opt != com->cor[2]) {		cor_change |= CD1400_CCR_COR3;		cd_outb(iobase, CD1400_COR3, com->cor[2] = opt);	}	/* notify the CD1400 if COR1-3 have changed */	if (cor_change)		cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change);	/*	 * set channel option register 4 -	 *	CR/NL processing	 *	break processing	 *	received exception processing	 */	opt = 0;	if (iflag & IGNCR)		opt |= CD1400_COR4_IGNCR;#ifdef Smarts	/*	 * we need a new ttyinput() for this, as we don't want to	 * have ICRNL && INLCR being done in both layers, or to have	 * synchronisation problems	 */	if (iflag & ICRNL)		opt |= CD1400_COR4_ICRNL;	if (iflag & INLCR)		opt |= CD1400_COR4_INLCR;#endif	if (iflag & IGNBRK)		opt |= CD1400_COR4_IGNBRK;	if (!(iflag & BRKINT))		opt |= CD1400_COR4_NOBRKINT;#if 0	/* XXX using this "intelligence" breaks reporting of overruns. */	if (iflag & IGNPAR)		opt |= CD1400_COR4_PFO_DISCARD;	else {		if (iflag & PARMRK)			opt |= CD1400_COR4_PFO_ESC;		else			opt |= CD1400_COR4_PFO_NUL;	}#else	opt |= CD1400_COR4_PFO_EXCEPTION;#endif	cd_outb(iobase, CD1400_COR4, opt);	/*	 * set channel option register 5 -	 */	opt = 0;	if (iflag & ISTRIP)		opt |= CD1400_COR5_ISTRIP;	if (t->c_iflag & IEXTEN)		/* enable LNEXT (e.g. ctrl-v quoting) handling */		opt |= CD1400_COR5_LNEXT;#ifdef Smarts	if (t->c_oflag & ONLCR)		opt |= CD1400_COR5_ONLCR;	if (t->c_oflag & OCRNL)		opt |= CD1400_COR5_OCRNL;#endif	cd_outb(iobase, CD1400_COR5, opt);	/*	 * XXX we probably alway want to track carrier changes, so that	 * TS_CARR_ON gives the true carrier.  If we don't track them,	 * then we should set TS_CARR_ON when CLOCAL drops.	 */	/*	 * set modem change option register 1	 *	generate modem interrupts on which 1 -> 0 input transitions	 *	also controls auto-DTR output flow-control, which we don't use	 */	opt = cflag & CLOCAL ? 0 : CD1400_MCOR1_CDzd;#ifdef SOFT_CTS_OFLOW	if (cflag & CCTS_OFLOW)		opt |= CD1400_MCOR1_CTSzd;#endif	cd_outb(iobase, CD1400_MCOR1, opt);	/*	 * set modem change option register 2	 *	generate modem interrupts on specific 0 -> 1 input transitions	 */	opt = cflag & CLOCAL ? 0 : CD1400_MCOR2_CDod;#ifdef SOFT_CTS_OFLOW	if (cflag & CCTS_OFLOW)		opt |= CD1400_MCOR2_CTSod;#endif	cd_outb(iobase, CD1400_MCOR2, opt);	/*	 * XXX should have done this long ago, but there is too much state	 * to change all atomically.	 */	disable_intr();	com->state &= ~CS_TTGO;	if (!(tp->t_state & TS_TTSTOP))		com->state |= CS_TTGO;	if (cflag & CRTS_IFLOW)		com->state |= CS_RTS_IFLOW;	/* XXX - secondary changes? */	else		com->state &= ~CS_RTS_IFLOW;	/*	 * Set up state to handle output flow control.	 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?	 * Now has 10+ msec latency, while CTS flow has 50- usec latency.	 */	com->state |= CS_ODEVREADY;#ifdef SOFT_CTS_OFLOW	com->state &= ~CS_CTS_OFLOW;	if (cflag & CCTS_OFLOW) {		com->state |= CS_CTS_OFLOW;		if (!(com->last_modem_status & MSR_CTS))			com->state &= ~CS_ODEVREADY;	}#endif	/* XXX shouldn't call functions while intrs are disabled. */	disc_optim(tp, t, com);#if 0	/*	 * Recover from fiddling with CS_TTGO.  We used to call siointr1()	 * unconditionally, but that defeated the careful discarding of	 * stale input in sioopen().	 */	if (com->state >= (CS_BUSY | CS_TTGO))		siointr1(com);#endif	if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {		if (!(com->intr_enable & CD1400_SRER_TXRDY))			cd_outb(iobase, CD1400_SRER,				com->intr_enable |= CD1400_SRER_TXRDY);	} else {		if (com->intr_enable & CD1400_SRER_TXRDY)			cd_outb(iobase, CD1400_SRER,				com->intr_enable &= ~CD1400_SRER_TXRDY);	}	enable_intr();	splx(s);	return (0);}static voidcomstart(tp)	struct tty	*tp;{	struct com_s	*com;	cy_addr		iobase;	int		s;#ifdef CyDebug	bool_t		started;#endif	int		unit;	unit = DEV_TO_UNIT(tp->t_dev);	com = com_addr(unit);	iobase = com->iobase;	s = spltty();#ifdef CyDebug	++com->start_count;	started = FALSE;#endif	disable_intr();	cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);	if (tp->t_state & TS_TTSTOP) {		com->state &= ~CS_TTGO;		if (com->intr_enable & CD1400_SRER_TXRDY)			cd_outb(iobase, CD1400_SRER,				com->intr_enable &= ~CD1400_SRER_TXRDY);	} else {		com->state |= CS_TTGO;		if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)		    && !(com->intr_enable & CD1400_SRER_TXRDY))			cd_outb(iobase, CD1400_SRER,				com->intr_enable |= CD1400_SRER_TXRDY);	}	if (tp->t_state & TS_TBLOCK) {		if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)#if 0			outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);#else			cd_outb(iobase, CD1400_MSVR1,				com->mcr_image &= ~MCR_RTS);#endif	} else {

⌨️ 快捷键说明

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