rc.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,498 行 · 第 1/3 页
C
1,498 行
/* Feed characters to output buffer */static void rc_start(tp)register struct tty *tp;{ register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)]; register int nec = rc->rc_rcb->rcb_addr, s; 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 int s; register struct tty *tp; register int chan, icnt, c, 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;}void rcstop(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();}int rcopen(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); ttsetwater(tp); 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); 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;}int rcclose(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); 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 */int rcread(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 */int rcwrite(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) )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?