rc.c

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

C
1,514
字号
	if (rc->rc_flags & RC_OSBUSY)		return;	s = spltty();	rc->rc_flags |= RC_OSBUSY;	disable_intr();	if (tp->t_state & TS_TTSTOP)		rc->rc_flags |= RC_OSUSP;	else		rc->rc_flags &= ~RC_OSUSP;	/* Do RTS flow control stuff */	if (   (rc->rc_flags & RC_RTSFLOW)	    && (tp->t_state & TS_TBLOCK)	    && (rc->rc_msvr & MSVR_RTS)	   ) {		rcout(CD180_CAR, rc->rc_chan);		rcout(CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS);	} else if (!(rc->rc_msvr & MSVR_RTS)) {		rcout(CD180_CAR, rc->rc_chan);		rcout(CD180_MSVR, rc->rc_msvr |= MSVR_RTS);	}	enable_intr();	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))		goto out;#ifdef RCDEBUG	printrcflags(rc, "rcstart");#endif	ttwwakeup(tp);#ifdef RCDEBUG	printf("rcstart: outq = %d obuf = %d\n",		tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr);#endif	if (tp->t_state & TS_BUSY)		goto    out;    /* output still in progress ... */	if (tp->t_outq.c_cc > 0) {		u_int   ocnt;		tp->t_state |= TS_BUSY;		ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf);		disable_intr();		rc->rc_optr = rc->rc_obuf;		rc->rc_obufend = rc->rc_optr + ocnt;		enable_intr();		if (!(rc->rc_ier & IER_TxRdy)) {#ifdef RCDEBUG			printf("rc%d/%d: rcstart enable txint\n", rc->rc_rcb->rcb_unit, rc->rc_chan);#endif			rcout(CD180_CAR, rc->rc_chan);			rcout(CD180_IER, rc->rc_ier |= IER_TxRdy);		}	}out:	rc->rc_flags &= ~RC_OSBUSY;	(void) splx(s);}/* Handle delayed events. */void rcpoll(){	register struct rc_chans *rc;	register struct rc_softc *rcb;	register u_char        *tptr, *eptr;	register struct tty    *tp;	register int            chan, icnt, nec, unit;	if (rc_scheduled_event == 0)		return;repeat:	for (unit = 0; unit < NRC; unit++) {		rcb = &rc_softc[unit];		rc = rcb->rcb_baserc;		nec = rc->rc_rcb->rcb_addr;		for (chan = 0; chan < CD180_NCHAN; rc++, chan++) {			tp = rc->rc_tp;#ifdef RCDEBUG			if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG|			    RC_WAS_BUFOVFL|RC_WAS_SILOVFL))				printrcflags(rc, "rcevent");#endif			if (rc->rc_flags & RC_WAS_BUFOVFL) {				disable_intr();				rc->rc_flags &= ~RC_WAS_BUFOVFL;				rc_scheduled_event--;				enable_intr();				printf("rc%d/%d: interrupt-level buffer overflow\n",					unit, chan);			}			if (rc->rc_flags & RC_WAS_SILOVFL) {				disable_intr();				rc->rc_flags &= ~RC_WAS_SILOVFL;				rc_scheduled_event--;				enable_intr();				printf("rc%d/%d: silo overflow\n",					unit, chan);			}			if (rc->rc_flags & RC_MODCHG) {				disable_intr();				rc->rc_flags &= ~RC_MODCHG;				rc_scheduled_event -= LOTS_OF_EVENTS;				enable_intr();				(*linesw[tp->t_line].l_modem)(tp, !!(rc->rc_msvr & MSVR_CD));			}			if (rc->rc_flags & RC_DORXFER) {				disable_intr();				rc->rc_flags &= ~RC_DORXFER;				eptr = rc->rc_iptr;				if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE])					tptr = &rc->rc_ibuf[RC_IBUFSIZE];				else					tptr = rc->rc_ibuf;				icnt = eptr - tptr;				if (icnt > 0) {					if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) {						rc->rc_iptr   = rc->rc_ibuf;						rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE];						rc->rc_hiwat  = &rc->rc_ibuf[RC_IHIGHWATER];					} else {						rc->rc_iptr   = &rc->rc_ibuf[RC_IBUFSIZE];						rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE];						rc->rc_hiwat  =							&rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER];					}					if (   (rc->rc_flags & RC_RTSFLOW)					    && (tp->t_state & TS_ISOPEN)					    && !(tp->t_state & TS_TBLOCK)					    && !(rc->rc_msvr & MSVR_RTS)					    ) {						rcout(CD180_CAR, chan);						rcout(CD180_MSVR,							rc->rc_msvr |= MSVR_RTS);					}					rc_scheduled_event -= icnt;				}				enable_intr();				if (icnt <= 0 || !(tp->t_state & TS_ISOPEN))					goto done1;				if (   (tp->t_state & TS_CAN_BYPASS_L_RINT)				    && !(tp->t_state & TS_LOCAL)) {					if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER					    && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF))					    && !(tp->t_state & TS_TBLOCK))						ttyblock(tp);					tk_nin += icnt;					tk_rawcc += icnt;					tp->t_rawcc += icnt;					if (b_to_q(tptr, icnt, &tp->t_rawq))						printf("rc%d/%d: tty-level buffer overflow\n",							unit, chan);					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;						rc_start(tp);					}				} else {					for (; tptr < eptr; tptr++)						(*linesw[tp->t_line].l_rint)						    (tptr[0] |						    rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF], tp);				}done1: ;			}			if (rc->rc_flags & RC_DOXXFER) {				disable_intr();				rc_scheduled_event -= LOTS_OF_EVENTS;				rc->rc_flags &= ~RC_DOXXFER;				rc->rc_tp->t_state &= ~TS_BUSY;				enable_intr();				(*linesw[tp->t_line].l_start)(tp);			}		}		if (rc_scheduled_event == 0)			break;	}	if (rc_scheduled_event >= LOTS_OF_EVENTS)		goto repeat;}static	voidrcstop(tp, rw)	register struct tty     *tp;	int                     rw;{	register struct rc_chans        *rc = &rc_chans[GET_UNIT(tp->t_dev)];	u_char *tptr, *eptr;#ifdef RCDEBUG	printf("rc%d/%d: rcstop %s%s\n", rc->rc_rcb->rcb_unit, rc->rc_chan,		(rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":"");#endif	if (rw & FWRITE)		rc_discard_output(rc);	disable_intr();	if (rw & FREAD) {		rc->rc_flags &= ~RC_DORXFER;		eptr = rc->rc_iptr;		if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) {			tptr = &rc->rc_ibuf[RC_IBUFSIZE];			rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE];		} else {			tptr = rc->rc_ibuf;			rc->rc_iptr = rc->rc_ibuf;		}		rc_scheduled_event -= eptr - tptr;	}	if (tp->t_state & TS_TTSTOP)		rc->rc_flags |= RC_OSUSP;	else		rc->rc_flags &= ~RC_OSUSP;	enable_intr();}static	intrcopen(dev, flag, mode, p)	dev_t           dev;	int             flag, mode;	struct proc    *p;{	register struct rc_chans *rc;	register struct tty      *tp;	int             unit, nec, s, error = 0;	unit = GET_UNIT(dev);	if (unit >= NRC * CD180_NCHAN)		return ENXIO;	if (rc_softc[unit / CD180_NCHAN].rcb_probed != RC_ATTACHED)		return ENXIO;	rc  = &rc_chans[unit];	tp  = rc->rc_tp;	nec = rc->rc_rcb->rcb_addr;#ifdef RCDEBUG	printf("rc%d/%d: rcopen: dev %x\n", rc->rc_rcb->rcb_unit, unit, dev);#endif	s = spltty();again:	while (rc->rc_flags & RC_DTR_OFF) {		error = tsleep(&(rc->rc_dtrwait), TTIPRI | PCATCH, "rcdtr", 0);		if (error != 0)			goto out;	}	if (tp->t_state & TS_ISOPEN) {		if (CALLOUT(dev)) {			if (!(rc->rc_flags & RC_ACTOUT)) {				error = EBUSY;				goto out;			}		} else {			if (rc->rc_flags & RC_ACTOUT) {				if (flag & O_NONBLOCK) {					error = EBUSY;					goto out;				}				if (error = tsleep(&rc->rc_rcb,				     TTIPRI|PCATCH, "rcbi", 0))					goto out;				goto again;			}		}		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {			error = EBUSY;			goto out;		}	} else {		tp->t_oproc   = rc_start;		tp->t_param   = rc_param;		tp->t_dev     = dev;		if (CALLOUT(dev))			tp->t_cflag |= CLOCAL;		else			tp->t_cflag &= ~CLOCAL;		error = rc_param(tp, &tp->t_termios);		if (error)			goto out;		(void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMSET);		if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev))			(*linesw[tp->t_line].l_modem)(tp, 1);	}	if (!(tp->t_state & TS_CARR_ON) && !CALLOUT(dev)	    && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {		rc->rc_dcdwaits++;		error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "rcdcd", 0);		rc->rc_dcdwaits--;		if (error != 0)			goto out;		goto again;	}	error = (*linesw[tp->t_line].l_open)(dev, tp);	disc_optim(tp, &tp->t_termios, rc);	if ((tp->t_state & TS_ISOPEN) && CALLOUT(dev))		rc->rc_flags |= RC_ACTOUT;out:	(void) splx(s);	if(rc->rc_dcdwaits == 0 && !(tp->t_state & TS_ISOPEN))		rc_hardclose(rc);	return error;}static	intrcclose(dev, flag, mode, p)	dev_t           dev;	int             flag, mode;	struct proc    *p;{	register struct rc_chans *rc;	register struct tty      *tp;	int  s, unit = GET_UNIT(dev);	if (unit >= NRC * CD180_NCHAN)		return ENXIO;	rc  = &rc_chans[unit];	tp  = rc->rc_tp;#ifdef RCDEBUG	printf("rc%d/%d: rcclose dev %x\n", rc->rc_rcb->rcb_unit, unit, dev);#endif	s = spltty();	(*linesw[tp->t_line].l_close)(tp, flag);	disc_optim(tp, &tp->t_termios, rc);	rcstop(tp, FREAD | FWRITE);	rc_hardclose(rc);	ttyclose(tp);	splx(s);	return 0;}static void rc_hardclose(rc)register struct rc_chans *rc;{	register int s, nec = rc->rc_rcb->rcb_addr;	register struct tty *tp = rc->rc_tp;	s = spltty();	rcout(CD180_CAR, rc->rc_chan);	/* Disable rx/tx intrs */	rcout(CD180_IER, rc->rc_ier = 0);	if (   (tp->t_cflag & HUPCL)	    || !(rc->rc_flags & RC_ACTOUT)	       && !(rc->rc_msvr & MSVR_CD)	       && !(tp->t_cflag & CLOCAL)	    || !(tp->t_state & TS_ISOPEN)	   ) {		CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan);		WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);		(void) rc_modctl(rc, TIOCM_RTS, DMSET);		if (rc->rc_dtrwait) {			timeout(rc_dtrwakeup, rc, rc->rc_dtrwait);			rc->rc_flags |= RC_DTR_OFF;		}	}	rc->rc_flags &= ~RC_ACTOUT;	wakeup((caddr_t) &rc->rc_rcb);  /* wake bi */	wakeup(TSA_CARR_ON(tp));	(void) splx(s);}/* Read from line */static	intrcread(dev, uio, flag)	dev_t           dev;	struct uio      *uio;	int             flag;{	struct tty *tp = rc_chans[GET_UNIT(dev)].rc_tp;	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));}/* Write to line */static	intrcwrite(dev, uio, flag)	dev_t           dev;	struct uio      *uio;	int             flag;{	struct tty *tp = rc_chans[GET_UNIT(dev)].rc_tp;	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));}/* Reset the bastard */static void rc_hwreset(unit, nec, chipid)	register int    unit, nec;	unsigned int    chipid;{	CCRCMD(unit, -1, CCR_HWRESET);            /* Hardware reset */	DELAY(20000);	WAITFORCCR(unit, -1);	rcout(RC_CTOUT, 0);             /* Clear timeout  */	rcout(CD180_GIVR,  chipid);	rcout(CD180_GICR,  0);	/* Set Prescaler Registers (1 msec) */	rcout(CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF);	rcout(CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8);	/* Initialize Priority Interrupt Level Registers */	rcout(CD180_PILR1, RC_PILR_MODEM);	rcout(CD180_PILR2, RC_PILR_TX);	rcout(CD180_PILR3, RC_PILR_RX);	/* Reset DTR */	rcout(RC_DTREG, ~0);}/* Set channel parameters */static int rc_param(tp, ts)	register struct  tty    *tp;	struct termios          *ts;{	register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)];	register int    nec = rc->rc_rcb->rcb_addr;	int      idivs, odivs, s, val, cflag, iflag, lflag, inpflow;	if (   ts->c_ospeed < 0 || ts->c_ospeed > 76800	    || ts->c_ispeed < 0 || ts->c_ispeed > 76800	   )		return (EINVAL);	if (ts->c_ispeed == 0)		ts->c_ispeed = ts->c_ospeed;	odivs = RC_BRD(ts->c_ospeed);	idivs = RC_BRD(ts->c_ispeed);	s = spltty();	/* Select channel */	rcout(CD180_CAR, rc->rc_chan);	/* If speed == 0, hangup line */	if (ts->c_ospeed == 0) {		CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan);		WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);		(void) rc_modctl(rc, TIOCM_DTR, DMBIC);	}	tp->t_state &= ~TS_CAN_BYPASS_L_RINT;	cflag = ts->c_cflag;	iflag = ts->c_iflag;	lflag = ts->c_lflag;	if (idivs > 0) {		rcout(CD180_RBPRL, idivs & 0xFF);		rcout(CD180_RBPRH, idivs >> 8);	}	if (odivs > 0) {		rcout(CD180_TBPRL, odivs & 0xFF);		rcout(CD180_TBPRH, odivs >> 8);	}	/* set timeout value */	if (ts->c_ispeed > 0) {		int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1;		if (   !(lflag & ICANON)		    && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0		    && ts->c_cc[VTIME] * 10 > itm)			itm = ts->c_cc[VTIME] * 10;		rcout(CD180_RTPR, itm <= 255 ? itm : 255);	}	switch (cflag & CSIZE) {		case CS5:       val = COR1_5BITS;      break;		case CS6:       val = COR1_6BITS;      break;		case CS7:       val = COR1_7BITS;      break;		default:		case CS8:       val = COR1_8BITS;      break;	}	if (cflag & PARENB) {		val |= COR1_NORMPAR;		if (cflag & PARODD)			val |= COR1_ODDP;		if (!(cflag & INPCK))			val |= COR1_Ignore;	} else		val |= COR1_Ignore;	if (cflag & CSTOPB)		val |= COR1_2SB;	rcout(CD180_COR1, val);	/* Set FIFO threshold */	val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2;	inpflow = 0;	if (   (iflag & IXOFF)	    && (   ts->c_cc[VSTOP] != _POSIX_VDISABLE		&& (   ts->c_cc[VSTART] != _POSIX_VDISABLE		    || (iflag & IXANY)		   )	       )	   ) {		inpflow = 1;		val |= COR3_SCDE|COR3_FCT;	}	rcout(CD180_COR3, val);

⌨️ 快捷键说明

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