cy.c

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

C
2,542
字号
			struct com_s	*com;			u_int		count;			u_char		*ioptr;			u_char		line_status;			u_char		recv_data;			u_char		serv_type;#ifdef PollMode			u_char		save_car;			u_char		save_rir;#endif#ifdef PollMode			save_rir = cd_inb(iobase, CD1400_RIR);			save_car = cd_inb(iobase, CD1400_CAR);			/* enter rx service */			cd_outb(iobase, CD1400_CAR, save_rir);			serv_type = cd_inb(iobase, CD1400_RIVR);			com = com_addr(baseu				       + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)					  & CD1400_xIVR_CHAN));#else			/* ack receive service */			serv_type = cy_inb(iobase, CY8_SVCACKR);			com = com_addr(baseu +				       + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)					  & CD1400_xIVR_CHAN));#endif	if (com->do_timestamp)		/* XXX a little bloat here... */		com->timestamp = intr_timestamp;		if (serv_type & CD1400_RIVR_EXCEPTION) {			++com->recv_exception;			line_status = cd_inb(iobase, CD1400_RDSR);			/* break/unnattached error bits or real input? */			recv_data = cd_inb(iobase, CD1400_RDSR);#ifndef SOFT_HOTCHAR			if (line_status & CD1400_RDSR_SPECIAL			    && com->hotchar != 0)				setsofttty();#endif#if 1 /* XXX "intelligent" PFO error handling would break O error handling */			if (line_status & (LSR_PE|LSR_FE|LSR_BI)) {				/*				  Don't store PE if IGNPAR and BI if IGNBRK,				  this hack allows "raw" tty optimization				  works even if IGN* is set.				*/				if (   com->tp == NULL				    || !(com->tp->t_state & TS_ISOPEN)				    || (line_status & (LSR_PE|LSR_FE))				    &&  (com->tp->t_iflag & IGNPAR)				    || (line_status & LSR_BI)				    &&  (com->tp->t_iflag & IGNBRK))					goto cont;				if (   (line_status & (LSR_PE|LSR_FE))				    && (com->tp->t_state & TS_CAN_BYPASS_L_RINT)				    && ((line_status & LSR_FE)				    ||  (line_status & LSR_PE)				    &&  (com->tp->t_iflag & INPCK)))					recv_data = 0;			}#endif /* 1 */			++com->bytes_in;#ifdef SOFT_HOTCHAR			if (com->hotchar != 0 && recv_data == com->hotchar)				setsofttty();#endif			ioptr = com->iptr;			if (ioptr >= com->ibufend)				CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);			else {				++com_events;				ioptr[0] = recv_data;				ioptr[CE_INPUT_OFFSET] = line_status;				com->iptr = ++ioptr;				if (ioptr == com->ihighwater				    && 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				if (line_status & LSR_OE)					CE_RECORD(com, CE_OVERRUN);			}			goto cont;		} else {			int	ifree;			count = cd_inb(iobase, CD1400_RDCR);			com->bytes_in += count;			ioptr = com->iptr;			ifree = com->ibufend - ioptr;			if (count > ifree) {				count -= ifree;				com_events += ifree;				while (ifree-- != 0) {					recv_data = cd_inb(iobase, CD1400_RDSR);#ifdef SOFT_HOTCHAR					if (com->hotchar != 0					    && recv_data == com->hotchar)						setsofttty();#endif					ioptr[0] = recv_data;					ioptr[CE_INPUT_OFFSET] = 0;					++ioptr;				}				com->delta_error_counts				    [CE_INTERRUPT_BUF_OVERFLOW] += count;				do {					recv_data = cd_inb(iobase, CD1400_RDSR);#ifdef SOFT_HOTCHAR					if (com->hotchar != 0					    && recv_data == com->hotchar)						setsofttty();#endif				} while (--count != 0);			} else {				if (ioptr <= com->ihighwater				    && ioptr + count > com->ihighwater				    && 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				com_events += count;				do {					recv_data = cd_inb(iobase, CD1400_RDSR);#ifdef SOFT_HOTCHAR					if (com->hotchar != 0					    && recv_data == com->hotchar)						setsofttty();#endif					ioptr[0] = recv_data;					ioptr[CE_INPUT_OFFSET] = 0;					++ioptr;				} while (--count != 0);			}			com->iptr = ioptr;		}cont:			/* terminate service context */#ifdef PollMode			cd_outb(iobase, CD1400_RIR,				save_rir				& ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));			cd_outb(iobase, CD1400_CAR, save_car);#else			cd_outb(iobase, CD1400_EOSRR, 0);#endif		}		if (status & CD1400_SVRR_MDMCH) {			struct com_s	*com;			u_char	modem_status;#ifdef PollMode			u_char	save_car;			u_char	save_mir;#else			u_char	vector;#endif#ifdef PollMode			save_mir = cd_inb(iobase, CD1400_MIR);			save_car = cd_inb(iobase, CD1400_CAR);			/* enter modem service */			cd_outb(iobase, CD1400_CAR, save_mir);			com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS				       + (save_mir & CD1400_MIR_CHAN));#else			/* ack modem service */			vector = cy_inb(iobase, CY8_SVCACKM);			com = com_addr(baseu				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)					  & CD1400_xIVR_CHAN));#endif			++com->mdm;			modem_status = cd_inb(iobase, CD1400_MSVR2);		if (modem_status != com->last_modem_status) {			/*			 * Schedule high level to handle DCD changes.  Note			 * that we don't use the delta bits anywhere.  Some			 * UARTs mess them up, and it's easy to remember the			 * previous bits and calculate the delta.			 */			com->last_modem_status = modem_status;			if (!(com->state & CS_CHECKMSR)) {				com_events += LOTS_OF_EVENTS;				com->state |= CS_CHECKMSR;				setsofttty();			}#ifdef SOFT_CTS_OFLOW			/* handle CTS change immediately for crisp flow ctl */			if (com->state & CS_CTS_OFLOW) {				if (modem_status & MSR_CTS) {					com->state |= CS_ODEVREADY;					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);				} else {					com->state &= ~CS_ODEVREADY;					if (com->intr_enable & CD1400_SRER_TXRDY)						cd_outb(iobase, CD1400_SRER,							com->intr_enable							&= ~CD1400_SRER_TXRDY);				}			}#endif		}			/* terminate service context */#ifdef PollMode			cd_outb(iobase, CD1400_MIR,				save_mir				& ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));			cd_outb(iobase, CD1400_CAR, save_car);#else			cd_outb(iobase, CD1400_EOSRR, 0);#endif		}		if (status & CD1400_SVRR_TXRDY) {			struct com_s	*com;#ifdef PollMode			u_char	save_car;			u_char	save_tir;#else			u_char	vector;#endif#ifdef PollMode			save_tir = cd_inb(iobase, CD1400_TIR);			save_car = cd_inb(iobase, CD1400_CAR);			/* enter tx service */			cd_outb(iobase, CD1400_CAR, save_tir);			com = com_addr(baseu				       + cyu * CD1400_NO_OF_CHANNELS				       + (save_tir & CD1400_TIR_CHAN));#else			/* ack transmit service */			vector = cy_inb(iobase, CY8_SVCACKT);			com = com_addr(baseu				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)					  & CD1400_xIVR_CHAN));#endif		if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {			u_char	*ioptr;			u_int	ocount;			ioptr = com->obufq.l_head;				ocount = com->obufq.l_tail - ioptr;				if (ocount > CD1400_TX_FIFO_SIZE)					ocount = CD1400_TX_FIFO_SIZE;				com->bytes_out += ocount;				do					cd_outb(iobase, CD1400_TDR, *ioptr++);				while (--ocount != 0);			com->obufq.l_head = ioptr;			if (ioptr >= com->obufq.l_tail) {				struct lbq	*qp;				qp = com->obufq.l_next;				qp->l_queued = FALSE;				qp = qp->l_next;				if (qp != NULL) {					com->obufq.l_head = qp->l_head;					com->obufq.l_tail = qp->l_tail;					com->obufq.l_next = qp;				} else {					/* output just completed */					com->state &= ~CS_BUSY;					cd_outb(iobase, CD1400_SRER,						com->intr_enable						&= ~CD1400_SRER_TXRDY);				}				if (!(com->state & CS_ODONE)) {					com_events += LOTS_OF_EVENTS;					com->state |= CS_ODONE;					setsofttty();	/* handle at high level ASAP */				}			}		}			/* terminate service context */#ifdef PollMode			cd_outb(iobase, CD1400_TIR,				save_tir				& ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));			cd_outb(iobase, CD1400_CAR, save_car);#else			cd_outb(iobase, CD1400_EOSRR, 0);#endif		}	}	/* ensure an edge for the next interrupt */	cy_outb(cy_iobase, CY_CLEAR_INTR, 0);	schedsofttty();}static voidsiointr1(com)	struct com_s	*com;{}intsioioctl(dev, cmd, data, flag, p)	dev_t		dev;	int		cmd;	caddr_t		data;	int		flag;	struct proc	*p;{	struct com_s	*com;	int		error;	cy_addr		iobase;	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));	iobase = com->iobase;	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 >= 0)		return (error);	s = spltty();	error = ttioctl(tp, cmd, data, flag);	disc_optim(tp, &tp->t_termios, com);	if (error >= 0) {		splx(s);		return (error);	}	cd_outb(iobase, CD1400_CAR, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);	switch (cmd) {#if 0	case TIOCSBRK:		outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);		break;	case TIOCCBRK:		outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);		break;#endif /* 0 */	case TIOCSDTR:		(void)commctl(com, TIOCM_DTR, DMBIS);		break;	case TIOCCDTR:		(void)commctl(com, TIOCM_DTR, DMBIC);		break;	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;	default:		splx(s);		return (ENOTTY);	}	splx(s);	return (0);}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;		cy_addr		iobase;		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) {

⌨️ 快捷键说明

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