cy.c

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

C
2,536
字号
}static voidsiodtrwakeup(chan)	void	*chan;{	struct com_s	*com;	com = (struct com_s *)chan;	com->state &= ~CS_DTR_OFF;	wakeup(&com->dtr_wait);}voidsiointr(unit)	int	unit;{	int	baseu;	int	cy_align;	cy_addr	cy_iobase;	int	cyu;	cy_addr	iobase;	u_char	status;	COM_LOCK();	/* XXX could this be placed down lower in the loop? */	baseu = unit * CY_MAX_PORTS;	cy_align = com_addr(baseu)->cy_align;	cy_iobase = com_addr(baseu)->cy_iobase;	/* check each CD1400 in turn */	for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) {		iobase = (cy_addr) (cy_iobase				    + (cy_chip_offset[cyu] << cy_align));		/* poll to see if it has any work */		status = cd_inb(iobase, CD1400_SVRR, cy_align);		if (status == 0)			continue;#ifdef CyDebug		++cy_svrr_probes;#endif		/* service requests as appropriate, giving priority to RX */		if (status & CD1400_SVRR_RXRDY) {			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_rir;#endif#ifdef PollMode			save_rir = cd_inb(iobase, CD1400_RIR, cy_align);			/* enter rx service */			cd_outb(iobase, CD1400_CAR, cy_align, save_rir);			com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car			= save_rir & CD1400_CAR_CHAN;			serv_type = cd_inb(iobase, CD1400_RIVR, cy_align);			com = com_addr(baseu				       + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)					  & CD1400_xIVR_CHAN));#else			/* ack receive service */			serv_type = cy_inb(iobase, CY8_SVCACKR, cy_align);			com = com_addr(baseu +				       + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)					  & CD1400_xIVR_CHAN));#endif		if (serv_type & CD1400_RIVR_EXCEPTION) {			++com->recv_exception;			line_status = cd_inb(iobase, CD1400_RDSR, cy_align);			/* break/unnattached error bits or real input? */			recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);#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 {				if (com->do_timestamp)					microtime(&com->timestamp);				++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, com->mcr_rts_reg,						cy_align,						com->mcr_image &=						~com->mcr_rts);#endif				if (line_status & LSR_OE)					CE_RECORD(com, CE_OVERRUN);			}			goto cont;		} else {			int	ifree;			count = cd_inb(iobase, CD1400_RDCR, cy_align);			if (!count)				goto cont;			com->bytes_in += count;			ioptr = com->iptr;			ifree = com->ibufend - ioptr;			if (count > ifree) {				count -= ifree;				com_events += ifree;				if (ifree != 0) {					if (com->do_timestamp)						microtime(&com->timestamp);					do {						recv_data = cd_inb(iobase,								   CD1400_RDSR,								   cy_align);#ifdef SOFT_HOTCHAR						if (com->hotchar != 0						    && recv_data						       == com->hotchar)							setsofttty();#endif						ioptr[0] = recv_data;						ioptr[CE_INPUT_OFFSET] = 0;						++ioptr;					} while (--ifree != 0);				}				com->delta_error_counts				    [CE_INTERRUPT_BUF_OVERFLOW] += count;				do {					recv_data = cd_inb(iobase, CD1400_RDSR,							   cy_align);#ifdef SOFT_HOTCHAR					if (com->hotchar != 0					    && recv_data == com->hotchar)						setsofttty();#endif				} while (--count != 0);			} else {				if (com->do_timestamp)					microtime(&com->timestamp);				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, com->mcr_rts_reg,						cy_align,						com->mcr_image						&= ~com->mcr_rts);#endif				com_events += count;				do {					recv_data = cd_inb(iobase, CD1400_RDSR,							   cy_align);#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, cy_align,				save_rir				& ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));#else			cd_outb(iobase, CD1400_EOSRR, cy_align, 0);#endif		}		if (status & CD1400_SVRR_MDMCH) {			struct com_s	*com;			u_char	modem_status;#ifdef PollMode			u_char	save_mir;#else			u_char	vector;#endif#ifdef PollMode			save_mir = cd_inb(iobase, CD1400_MIR, cy_align);			/* enter modem service */			cd_outb(iobase, CD1400_CAR, cy_align, save_mir);			com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car			= save_mir & CD1400_CAR_CHAN;			com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS				       + (save_mir & CD1400_MIR_CHAN));#else			/* ack modem service */			vector = cy_inb(iobase, CY8_SVCACKM, cy_align);			com = com_addr(baseu				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)					  & CD1400_xIVR_CHAN));#endif			++com->mdm;			modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align);		if (modem_status != com->last_modem_status) {			if (com->do_dcd_timestamp			    && !(com->last_modem_status & MSR_DCD)			    && modem_status & MSR_DCD)				microtime(&com->dcd_timestamp);			/*			 * 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,							cy_align,							com->intr_enable							= com->intr_enable							  & ~CD1400_SRER_TXMPTY							  | CD1400_SRER_TXRDY);				} else {					com->state &= ~CS_ODEVREADY;					if (com->intr_enable					    & CD1400_SRER_TXRDY)						cd_outb(iobase, CD1400_SRER,							cy_align,							com->intr_enable							= com->intr_enable							  & ~CD1400_SRER_TXRDY							  | CD1400_SRER_TXMPTY);				}			}#endif		}			/* terminate service context */#ifdef PollMode			cd_outb(iobase, CD1400_MIR, cy_align,				save_mir				& ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));#else			cd_outb(iobase, CD1400_EOSRR, cy_align, 0);#endif		}		if (status & CD1400_SVRR_TXRDY) {			struct com_s	*com;#ifdef PollMode			u_char	save_tir;#else			u_char	vector;#endif#ifdef PollMode			save_tir = cd_inb(iobase, CD1400_TIR, cy_align);			/* enter tx service */			cd_outb(iobase, CD1400_CAR, cy_align, save_tir);			com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car			= save_tir & CD1400_CAR_CHAN;			com = com_addr(baseu				       + cyu * CD1400_NO_OF_CHANNELS				       + (save_tir & CD1400_TIR_CHAN));#else			/* ack transmit service */			vector = cy_inb(iobase, CY8_SVCACKT, cy_align);			com = com_addr(baseu				       + ((vector >> CD1400_xIVR_CHAN_SHIFT)					  & CD1400_xIVR_CHAN));#endif			if (com->etc != ETC_NONE) {				if (com->intr_enable & CD1400_SRER_TXRDY) {					/*					 * Here due to sloppy SRER_TXRDY					 * enabling.  Ignore.  Come back when					 * tx is empty.					 */					cd_outb(iobase, CD1400_SRER, cy_align,						com->intr_enable						= com->intr_enable						  & ~CD1400_SRER_TXRDY						  | CD1400_SRER_TXMPTY);					goto terminate_tx_service;				}				switch (com->etc) {				case CD1400_ETC_SENDBREAK:				case CD1400_ETC_STOPBREAK:					/*					 * Start the command.  Come back on					 * next tx empty interrupt, hopefully					 * after command has been executed.					 */					cd_outb(iobase, CD1400_COR2, cy_align,						com->cor[1] |= CD1400_COR2_ETC);					cd_outb(iobase, CD1400_TDR, cy_align,						CD1400_ETC_CMD);					cd_outb(iobase, CD1400_TDR, cy_align,						com->etc);					if (com->etc == CD1400_ETC_SENDBREAK)						com->etc = ETC_BREAK_STARTING;					else						com->etc = ETC_BREAK_ENDING;					goto terminate_tx_service;				case ETC_BREAK_STARTING:					/*					 * BREAK is now on.  Continue with					 * SRER_TXMPTY processing, hopefully					 * don't come back.					 */					com->etc = ETC_BREAK_STARTED;					break;				case ETC_BREAK_STARTED:					/*					 * Came back due to sloppy SRER_TXMPTY					 * enabling.  Hope again.					 */					break;				case ETC_BREAK_ENDING:					/*					 * BREAK is now off.  Continue with					 * SRER_TXMPTY processing and don't					 * come back.  The SWI handler will					 * restart tx interrupts if necessary.					 */					cd_outb(iobase, CD1400_COR2, cy_align,						com->cor[1]						&= ~CD1400_COR2_ETC);					com->etc = ETC_BREAK_ENDED;					if (!(com->state & CS_ODONE)) {						com_events += LOTS_OF_EVENTS;						com->state |= CS_ODONE;						setsofttty();					}					break;				case ETC_BREAK_ENDED:					/*					 * Shouldn't get here.  Hope again.					 */					break;				}			}			if (com->intr_enable & CD1400_SRER_TXMPTY) {				if (!(com->extra_state & CSE_ODONE)) {					com_events += LOTS_OF_EVENTS;					com->extra_state |= CSE_ODONE;					setsofttty();				}				cd_outb(iobase, CD1400_SRER, cy_align,					com->intr_enable					&= ~CD1400_SRER_TXMPTY);				goto terminate_tx_service;			}		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, cy_align,						*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;					/*					 * The setting of CSE_ODONE may be					 * stale here.  We currently only					 * use it when CS_BUSY is set, and					 * fixing it when we clear CS_BUSY					 * is easiest.					 */					if (com->extra_state & CSE_ODONE) {						com_events -= LOTS_OF_EVENTS;						com->extra_state &= ~CSE_ODONE;					}					cd_outb(iobase, CD1400_SRER, cy_align,						com->intr_enable						= com->intr_enable						  & ~CD1400_SRER_TXRDY						  | CD1400_SRER_TXMPTY);				}				if (!(com->state & CS_ODONE)) {					com_events += LOTS_OF_EVENTS;					com->state |= CS_ODONE;					/* handle at high level ASAP */					setsofttty();				}			}		}			/* terminate service context */terminate_tx_service:#ifdef PollMode			cd_outb(iobase, CD1400_TIR, cy_align,				save_tir				& ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));#else			cd_outb(iobase, CD1400_EOSRR, cy_align, 0);#endif		}	}	/* ensure an edge for the next interrupt */	cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);	schedsofttty();	COM_UNLOCK();}#if 0static voidsiointr1(com)	struct com_s	*com;{}#endifstatic intsioioctl(dev, cmd, data, flag, p)	dev_t		dev;	u_long		cmd;	caddr_t		data;	int		flag;	struct proc	*p;{

⌨️ 快捷键说明

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