cy.c

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

C
2,536
字号
	struct com_s	*com;	int		error;	int		mynor;	int		s;	struct tty	*tp;#if defined(COMPAT_43) || defined(COMPAT_SUNOS)	int		oldcmd;	struct termios	term;#endif	mynor = minor(dev);	com = com_addr(MINOR_TO_UNIT(mynor));	if (mynor & CONTROL_MASK) {		struct termios	*ct;		switch (mynor & CONTROL_MASK) {		case CONTROL_INIT_STATE:			ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;			break;		case CONTROL_LOCK_STATE:			ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;			break;		default:			return (ENODEV);	/* /dev/nodev */		}		switch (cmd) {		case TIOCSETA:			error = suser(p->p_ucred, &p->p_acflag);			if (error != 0)				return (error);			*ct = *(struct termios *)data;			return (0);		case TIOCGETA:			*(struct termios *)data = *ct;			return (0);		case TIOCGETD:			*(int *)data = TTYDISC;			return (0);		case TIOCGWINSZ:			bzero(data, sizeof(struct winsize));			return (0);		default:			return (ENOTTY);		}	}	tp = com->tp;#if defined(COMPAT_43) || defined(COMPAT_SUNOS)	term = tp->t_termios;	oldcmd = cmd;	error = ttsetcompat(tp, &cmd, data, &term);	if (error != 0)		return (error);	if (cmd != oldcmd)		data = (caddr_t)&term;#endif	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {		int	cc;		struct termios *dt = (struct termios *)data;		struct termios *lt = mynor & CALLOUT_MASK				     ? &com->lt_out : &com->lt_in;		dt->c_iflag = (tp->t_iflag & lt->c_iflag)			      | (dt->c_iflag & ~lt->c_iflag);		dt->c_oflag = (tp->t_oflag & lt->c_oflag)			      | (dt->c_oflag & ~lt->c_oflag);		dt->c_cflag = (tp->t_cflag & lt->c_cflag)			      | (dt->c_cflag & ~lt->c_cflag);		dt->c_lflag = (tp->t_lflag & lt->c_lflag)			      | (dt->c_lflag & ~lt->c_lflag);		for (cc = 0; cc < NCCS; ++cc)			if (lt->c_cc[cc] != 0)				dt->c_cc[cc] = tp->t_cc[cc];		if (lt->c_ispeed != 0)			dt->c_ispeed = tp->t_ispeed;		if (lt->c_ospeed != 0)			dt->c_ospeed = tp->t_ospeed;	}	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);	if (error != ENOIOCTL)		return (error);	s = spltty();	error = ttioctl(tp, cmd, data, flag);	disc_optim(tp, &tp->t_termios, com);	if (error != ENOIOCTL) {		splx(s);		return (error);	}	switch (cmd) {	case TIOCSBRK:#if 0		outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);#else		cd_etc(com, CD1400_ETC_SENDBREAK);#endif		break;	case TIOCCBRK:#if 0		outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);#else		cd_etc(com, CD1400_ETC_STOPBREAK);#endif		break;	case TIOCSDTR:		(void)commctl(com, TIOCM_DTR, DMBIS);		break;	case TIOCCDTR:		(void)commctl(com, TIOCM_DTR, DMBIC);		break;	/*	 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The	 * changes get undone on the next call to comparam().	 */	case TIOCMSET:		(void)commctl(com, *(int *)data, DMSET);		break;	case TIOCMBIS:		(void)commctl(com, *(int *)data, DMBIS);		break;	case TIOCMBIC:		(void)commctl(com, *(int *)data, DMBIC);		break;	case TIOCMGET:		*(int *)data = commctl(com, 0, DMGET);		break;	case TIOCMSDTRWAIT:		/* must be root since the wait applies to following logins */		error = suser(p->p_ucred, &p->p_acflag);		if (error != 0) {			splx(s);			return (error);		}		com->dtr_wait = *(int *)data * hz / 100;		break;	case TIOCMGDTRWAIT:		*(int *)data = com->dtr_wait * 100 / hz;		break;	case TIOCTIMESTAMP:		com->do_timestamp = TRUE;		*(struct timeval *)data = com->timestamp;		break;	case TIOCDCDTIMESTAMP:		com->do_dcd_timestamp = TRUE;		*(struct timeval *)data = com->dcd_timestamp;		break;	default:		splx(s);		return (ENOTTY);	}	splx(s);	return (0);}static voidsiopoll(){	int		unit;#ifdef CyDebug	++cy_timeouts;#endif	if (com_events == 0)		return;repeat:	for (unit = 0; unit < NSIO; ++unit) {		u_char		*buf;		struct com_s	*com;		u_char		*ibuf;		int		incc;		struct tty	*tp;		com = com_addr(unit);		if (com == NULL)			continue;		tp = com->tp;		if (tp == NULL) {			/*			 * XXX forget any events related to closed devices			 * (actually never opened devices) so that we don't			 * loop.			 */			disable_intr();			incc = com->iptr - com->ibuf;			com->iptr = com->ibuf;			if (com->state & CS_CHECKMSR) {				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.			 */			if ((com->state & CS_RTS_IFLOW)			    && !(com->mcr_image & com->mcr_rts)			    && !(tp->t_state & TS_TBLOCK))#if 0				outb(com->modem_ctl_port,				     com->mcr_image |= MCR_RTS);#else				cd_setreg(com, com->mcr_rts_reg,					  com->mcr_image |= com->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->extra_state & CSE_ODONE) {			disable_intr();			com_events -= LOTS_OF_EVENTS;			com->extra_state &= ~CSE_ODONE;			enable_intr();			if (!(com->state & CS_BUSY)) {				tp->t_state &= ~TS_BUSY;				ttwwakeup(com->tp);			}			if (com->etc != ETC_NONE) {				if (com->etc == ETC_BREAK_ENDED)					com->etc = ETC_NONE;				wakeup(&com->etc);			}		}		if (com->state & CS_ODONE) {			disable_intr();			com_events -= LOTS_OF_EVENTS;			com->state &= ~CS_ODONE;			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 > tp->t_ihiwat			    && (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;	u_long		cy_clock;	int		idivisor;	int		iflag;	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;	unit = DEV_TO_UNIT(tp->t_dev);	com = com_addr(unit);	/* check requested parameters */	cy_clock = CY_CLOCK(com->gfrcr_image);	idivisor = comspeed(t->c_ispeed, cy_clock, &iprescaler);	if (idivisor < 0)		return (EINVAL);	odivisor = comspeed(t->c_ospeed, cy_clock, &oprescaler);	if (odivisor < 0)		return (EINVAL);	/* parameters are OK, convert them to the com struct and the device */	s = spltty();	if (odivisor == 0)		(void)commctl(com, TIOCM_DTR, DMBIC);	/* hang up line */	else		(void)commctl(com, TIOCM_DTR, DMBIS);	if (idivisor != 0) {		cd_setreg(com, CD1400_RBPR, idivisor);		cd_setreg(com, CD1400_RCOR, iprescaler);	}	if (odivisor != 0) {		cd_setreg(com, CD1400_TBPR, odivisor);		cd_setreg(com, 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(com, 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_setreg(com, CD1400_SCHR1, t->c_cc[VSTOP]);	if (t->c_cc[VSTART] != _POSIX_VDISABLE)		cd_setreg(com, CD1400_SCHR2, t->c_cc[VSTART]);	if (t->c_cc[VINTR] != _POSIX_VDISABLE)		cd_setreg(com, CD1400_SCHR3, t->c_cc[VINTR]);	if (t->c_cc[VSUSP] != _POSIX_VDISABLE)		cd_setreg(com, 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_setreg(com, 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_getreg(com, 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_setreg(com, 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	disable_intr();	if (opt != com->cor[1]) {		cor_change |= CD1400_CCR_COR2;		cd_setreg(com, CD1400_COR2, com->cor[1] = opt);	}	enable_intr();	/*	 * 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;

⌨️ 快捷键说明

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