📄 sh.c
字号:
tp->t_state |= TS_WOPEN; if ((tp->t_state&TS_ISOPEN) == 0) { shmodem[unit] = MODEM_DSR_START; /* prevents spurious startups */ } tty_def_open(tp, dev, flag, (shsoftCAR[sh]&(1<<(unit&LINEMASK)))); shparam(unit); /* * Wait for carrier, then process line discipline specific open. */ /* * Set up receive hold off timer. Manual says we have * to point to line 0 before we set the timer. */ addr->csr.low = SH_RIE|(0 & LINEMASK); /* set to line 0 */ sh_softcsr = SH_RIE|(0 & LINEMASK); addr->run.rxtimer = 10; /* 10 MS hold off time */ s=spl5(); if (tp->t_cflag & CLOCAL) { /* this is a local connection - ignore carrier */ tp->t_state |= TS_CARR_ON; shmodem[unit] |= MODEM_CTS|MODEM_CD|MODEM_DSR; addr->csr.low = SH_RIE|(unit & LINEMASK); /* set to line #*/ sh_softcsr = SH_RIE|(unit & LINEMASK); /* set to line #*/ /* enable interrupts*/ addr->lnctrl &= ~(SH_MODEM); addr->lnctrl |= (SH_DTR|SH_RTS|SH_REN); /* * Set state bit to tell tty.c not to assign this line as the * controlling terminal for the process which opens this line. */ if ((flag & O_NOCTTY) && (u.u_procp->p_progenv == A_POSIX)) tp->t_state |= TS_ONOCTTY; splx(s); return ((*linesw[tp->t_line].l_open)(dev, tp)); }/* NOTREACHED (softCAR and CLOCAL always set, i.e., no modem control) */ addr->csr.low = SH_RIE|(unit & LINEMASK); sh_softcsr = SH_RIE|(unit & LINEMASK); addr->lnctrl |= (SH_DTR|SH_RTS|SH_MODEM|SH_REN); if ((flag & (O_NDELAY|O_NONBLOCK)) == 0) { if (shdsr) { if ((addr->fun.fs.stat)&SH_DSR) { shmodem[unit] |= (MODEM_DSR_START|MODEM_DSR); tp->t_dev = dev; /* need it for timeouts */ timeout(sh_dsr_check, tp, hz*30); timeout(sh_dsr_check, tp, hz/2); } } /* * Ignore DSR and immediately look for CD & CTS. */ else { shmodem[unit] |= (MODEM_DSR_START|MODEM_DSR); sh_dsr_check(tp); } }#ifdef SHDEBUG if (shdebug) mprintf("shopen: line=%d, state=%x, pid=%d\n", unit, tp->t_state, u.u_procp->p_pid);#endif if (flag & (O_NDELAY|O_NONBLOCK)) tp->t_state |= TS_ONDELAY; else while ((tp->t_state&TS_CARR_ON)==0) { inuse = tp->t_state&TS_INUSE; sleep((caddr_t)&tp->t_rawq, TTIPRI); /* * See if wakeup is due to a false call. */ if (shmodem[unit]&MODEM_BADCALL){ splx(s); return(EWOULDBLOCK); } /* if we opened "block if in use" and * the terminal was not inuse at that time * but is became "in use" while we were * waiting for carrier then return */ if ((flag & O_BLKINUSE) && (inuse==0) && (tp->t_state&TS_INUSE)) { splx(s); return(EALREADY); } } /* * Set state bit to tell tty.c not to assign this line as the * controlling terminal for the process which opens this line. */ if ((flag & O_NOCTTY) && (u.u_procp->p_progenv == A_POSIX)) tp->t_state |= TS_ONOCTTY; splx(s); return ((*linesw[tp->t_line].l_open)(dev, tp));}/* * Close a SH line. *//*ARGSUSED*/shclose(dev, flag) dev_t dev; int flag;{ register struct tty *tp; register int unit, s; register struct shdevice *addr; register sh; extern int wakeup(); int turnoff = 0; unit = minor(dev); sh = unit >> 3; tp = &sh_tty[unit]; addr = (struct shdevice *)tp->t_addr; tp->t_state |= TS_CLOSING; if (tp->t_line) (*linesw[tp->t_line].l_close)(tp); if ((tp->t_cflag&HUPCL) || (tp->t_state&TS_ISOPEN)==0) { s = spl5(); turnoff++; addr->csr.low = SH_RIE|(unit & LINEMASK); sh_softcsr = SH_RIE|(unit & LINEMASK); addr->lnctrl &= ~(SH_DTR|SH_RTS); /* turn off DTR */ tp->t_state &= ~TS_CARR_ON; /* prevents recv intr. timeouts */ if ((tp->t_cflag & CLOCAL) == 0) {#ifdef SHDEBUG if (shdebug) mprintf("shclose: DTR drop line=%d, state=%x, pid=%d\n", unit, tp->t_state, u.u_procp->p_pid);#endif /* wait an additional 5 seconds for DSR to drop */ if (shdsr && (addr->fun.fs.stat&SH_DSR)) { timeout(wakeup, (caddr_t) &tp->t_dev, 5*hz); sleep((caddr_t)&tp->t_dev, PZERO-10); } timeout(wakeup, (caddr_t) &tp->t_dev, hz/5); sleep((caddr_t)&tp->t_dev, PZERO-10); } splx(s); }#ifdef SHDEBUG if (shdebug) mprintf("shclose: line=%d, state=%x, pid=%d\n", unit, tp->t_state, u.u_procp->p_pid);#endif shsoftCAR[sh] &= ~(1<<(unit&LINEMASK)); shsoftCAR[sh] |= (1<<(unit&LINEMASK)) & shdefaultCAR[sh]; ttyclose(tp); /* remember this will clear out t_state */ if (turnoff) { /* we have to do this after the ttyclose so that output * can still drain */ s = spl5(); addr->csr.low = SH_RIE|(unit & LINEMASK); addr->lnctrl = NULL; /* turn off interrupts also */ splx(s); } shmodem[unit] = 0; tty_def_close(tp); wakeup((caddr_t)&tp->t_rawq); /* wake up anyone in shopen */}shread(dev, uio) dev_t dev; struct uio *uio;{ register struct tty *tp = &sh_tty[minor(dev)]; return ((*linesw[tp->t_line].l_read)(tp, uio));}shwrite(dev, uio) dev_t dev; struct uio *uio;{ register struct tty *tp = &sh_tty[minor(dev)]; return ((*linesw[tp->t_line].l_write)(tp, uio));}/* * SH receiver interrupt. */shrint(sh) int sh; /* module number */{ register struct tty *tp; register c, unit; register struct shdevice *addr; struct tty *tp0; register struct uba_device *ui; register flg; int overrun = 0; u_char *modem0, *modem; int modem_cont; ui = shinfo[sh]; if (ui == 0 || ui->ui_alive == 0) return; addr = (struct shdevice *)shmem; tp0 = &sh_tty[sh<<3]; /* first tty structure that corresponds * to this sh module */ modem0 = &shmodem[sh<<3]; /* * Loop fetching characters from receive fifo for this * sh until there are no more in the receive fifo. */ while ((c = addr->run.rbuf) < 0) { /* if c < 0 then data valid is set */ unit = (c>>8)&LINEMASK; tp = tp0 + unit; /* tty struct for this line */ flg = tp->t_iflag; modem = modem0 + unit; modem_cont = 0;#ifdef SHDEBUG if (shdebug > 6) mprintf("shrint0: c=%x, tp=%x\n", c, tp);#endif /* check for modem transitions */ if ((c & SH_STAT)==SH_STAT) { if (c & SH_DIAG) /* ignore diagnostic info */ continue;#ifdef SHDEBUG if (shdebug > 6) mprintf("shrint: c=%x, tp=%x\n", c, tp);#endif if (tp->t_cflag & CLOCAL) continue; /* set to line #*/ addr->csr.low = SH_RIE|(unit & LINEMASK); sh_softcsr = SH_RIE|(unit & LINEMASK); /* examine modem status */ /* * Drop DTR immediately if DSR has gone away. * If really an active close then do not * send signals. */ if ((addr->fun.fs.stat&SH_DSR)==0) { if (tp->t_state&TS_CLOSING) { untimeout(wakeup, (caddr_t) &tp->t_dev); wakeup((caddr_t) &tp->t_dev); continue; } if (tp->t_state&TS_CARR_ON) { /* * Only drop line if DSR is followed. */ if (shdsr) sh_tty_drop(tp); continue; } } /* * Check for transient CD drops. * Only drop DTR if CD is down for more than 2 secs. */ if (tp->t_state&TS_CARR_ON) if ((addr->fun.fs.stat&SH_CD)==0){ if ( *modem & MODEM_CD) { /* only start timer once */ if (shdebug) mprintf("shrint, cd_drop, tp=%x\n", tp); *modem &= ~MODEM_CD; shtimestamp[minor(tp->t_dev)] = time; timeout(sh_cd_drop, tp, hz*shcdtime); modem_cont = 1;; } } else /* * CD has come up again. * Stop timeout from occurring if set. * If interval is more than 2 secs then * drop DTR. */ if ((*modem&MODEM_CD)==0) { untimeout(sh_cd_drop, tp); if (sh_cd_down(tp)) /* drop connection */ sh_tty_drop(tp); *modem |= MODEM_CD; modem_cont = 1;; } /* CTS flow control check */ if (tp->t_state&TS_CARR_ON) if ((addr->fun.fs.stat&SH_CTS)==0) { tp->t_state |= TS_TTSTOP; *modem &= ~MODEM_CTS; if (shdebug) mprintf("shrint: CTS stop, tp=%x\n", tp); shstop(tp, 0); continue; } else if ((*modem&MODEM_CTS)==0) { tp->t_state &= ~TS_TTSTOP; *modem |= MODEM_CTS; if (shdebug) mprintf("shrint: CTS start, tp=%x\n", tp); shstart(tp); continue; } /* * Avoid calling sh_start_tty for a CD transition if * the connection has already been established. */ if (modem_cont) continue; /* * If 500 ms timer has not expired then dont * check anything yet. * Check to see if DSR|CTS|CD are asserted. * If so we have a live connection. * If DSR is set for the first time we allow * 30 seconds for a live connection. */ if (shdsr) { if ((addr->fun.fs.stat&SH_XMIT)==SH_XMIT && (*modem&MODEM_DSR_START)==0) sh_start_tty(tp); else if ((addr->fun.fs.stat&SH_DSR) && (*modem&MODEM_DSR)==0) { *modem |= (MODEM_DSR_START|MODEM_DSR); /* * we should not look for CTS|CD for * about 500 ms. */ timeout(sh_dsr_check, tp, hz*30); timeout(sh_dsr_check, tp, hz/2); } } /* * Ignore DSR but look for CD and CTS. */ else { if ((addr->fun.fs.stat&SH_NODSR)==SH_NODSR) sh_start_tty(tp); } continue; }#ifndef PORTSELECTOR if ((tp->t_state&TS_ISOPEN)==0) {#else if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) {#endif wakeup((caddr_t)tp); continue; }/* This code handles the following termio input flags. Also * listed is what the default should be for propper Ultrix * backward compatibility. * * IGNBRK FALSE * BRKINT TRUE * IGNPAR TRUE * PARMRK FALSE * INPCK TRUE * ISTRIP TRUE */ /* tp->t_flags should be register */ /* SH_FERR is interpreted as a break */ if (c & SH_FERR) { /* * If configured for trusted path, initiate * trusted path handling. */ if (do_tpath) { tp->t_tpath |= TP_DOSAK; (*linesw[tp->t_line].l_rint)(c, tp); break; } if (flg & IGNBRK) continue; if (flg & BRKINT) {#ifdef SHDEBUG if (shdebug) mprintf("shrint: BREAK RECEIVED\n");#endif SHDEBUG if ((tp->t_lflag_ext & PRAW) && (tp->t_line != TERMIODISC)) c = 0; else { ttyflush(tp, FREAD|FWRITE);#ifdef SHDEBUG if (shdebug) mprintf("sending signal to tp->t_pgrp = %d\n", tp->t_pgrp);#endif SHDEBUG gsignal(tp->t_pgrp, SIGINT); continue; } } /* * TERMIO: If neither IGNBRK or BRKINT is set, a * break condition is read as a single '\0', * or if PARMRK is set as '\377','\0,'\0'. */ else { if (flg & PARMRK){ (*linesw[tp->t_line].l_rint)(0377,tp); (*linesw[tp->t_line].l_rint)(0,tp); } c = 0; } } /* Parity Error */ else if (c & SH_PERR){ /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -