📄 sh.c
字号:
* clear bits and check for 6,7,and 8, else its 5 bits. */ lpar &= ~SH_BITS8; switch(tp->t_cflag&CSIZE) { case CS6: lpar |= SH_BITS6; break; case CS7: lpar |= SH_BITS7; break; case CS8: lpar |= SH_BITS8; break; } /* * Outgoing Auto flow control. * No auto flow control allowed if startc != ^q and stopc != * ^s. Most drivers do not allow this to be changed. */ if ((tp->t_cflag_ext & PAUTOFLOW) && (tp->t_cc[VSTOP] == CTRL('s')) && (tp->t_cc[VSTART] == CTRL('q'))) addr->lnctrl |= SH_XFLOW; else addr->lnctrl &= ~SH_XFLOW;#ifdef SHDEBUG if (shdebug) mprintf("shparam: tp=%x, lpr=%x\n", tp, lpar);#endif /* * Only write the line parameter register if the * new parameters differ from the current ones. * This avoids some nasty delay timing (see below). */ if (addr->lpr != lpar) { /* * Must delay two character times before * we change the line parameters. * Find the number of microseconds of delay required, * based on the current speed setting. */ br = (addr->lpr>>12)&0x0f; for (i=0; i<SHDTSIZE; i++) if (br == sh_speeds[i]) { tcd = sh_delays[i] * 2; break; } /* * Delay long enough for two characters to be transmitted * (see comments above "#define SHDTSIZE"). * Use microdelay for times less than 10 Msec * (speeds >= 2400 BPS), otherwise use a timeout. * Timeouts are inaccurate, but better than spinning at ipl. */ if (tcd) { if (tcd < 10000) { DELAY(tcd); } else { i = (tcd / 10000); /* timeout value in ticks */ if (tcd % 10000) i += 1; /* fraction of a tick */ i += 1; /* 10 Msec clock granularity */ sh_newlpr[unit] = lpar; timeout(sh_lpr_load, tp, i); sleep((caddr_t)&tp->t_addr, PZERO-10); splx(s); return; } } addr->lpr = lpar; } splx(s);}/* * This routine loads a new value into the line * parameter register, after the two character * delay has expired (see shparam() abobe). * The spl7() makes sure the line select bits in * the CSR are saved and restored properly. This is * necessary because this routine is called via timeout, * which is clock driven (clock interrupts at spl6). * The current line number is saved in sh_softcsr, because * we can't read it from the csr without lossing xmit interrupts. */sh_lpr_load(tp)register struct tty *tp;{ register struct shdevice *addr = (struct shdevice *)tp->t_addr; register int unit = minor(tp->t_dev); register int s, oldunit; s = spl7(); /* THIS IS REALLY NECESSARY */ oldunit = (sh_softcsr & LINEMASK); addr->csr.low = SH_RIE|(unit & LINEMASK); addr->lpr = sh_newlpr[unit & LINEMASK]; wakeup((caddr_t)&tp->t_addr); addr->csr.low = (SH_RIE|oldunit); splx(s);}/* * SH transmitter interrupt. * Restart each line which used to be active but has * terminated transmission since the last interrupt. */shxint(sh) int sh; /* module number */{ register struct tty *tp; register struct shdevice *addr; register int unit; char csrxmt; addr = (struct shdevice *)shmem; while ((csrxmt = addr->csr.high) < 0) { if (csrxmt & SH_DIAGFAIL) printf("sh%d: DIAG. FAILURE\n", sh); unit = sh * 8; unit |= csrxmt&LINEMASK; tp = &sh_tty[unit];#ifdef SHDEBUG if (shdebug > 7) mprintf("shxint: unit=%x, tp=%x, c_cc=%d\n", unit, tp, tp->t_outq.c_cc);#endif tp->t_state &= ~TS_BUSY; if (tp->t_state&TS_FLUSH) tp->t_state &= ~TS_FLUSH; if (tp->t_line) (*linesw[tp->t_line].l_start)(tp); else shstart(tp); }}/* * Start (restart) transmission on the given SH line. */shstart(tp) register struct tty *tp;{ register struct shdevice *addr; register int unit, nch, line; int s; int free; char *cp = tp->t_outq.c_cf; union { int x; char y[2]; } wdbuf; unit = minor(tp->t_dev); line = unit & LINEMASK; /* unit now equals the line number */ addr = (struct shdevice *)tp->t_addr; /* * Must hold interrupts in following code to prevent * state of the tp from changing. */ s = spl5(); /* * If it's currently active, or delaying, no need to do anything. * Also do not transmit if not CTS */ if ((tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) || ((tp->t_state&TS_CARR_ON) && (shmodem[unit]&MODEM_CTS)==0)) goto out; /* * If there are sleepers, and output has drained below low * water mark, wake up the sleepers. */#ifdef SHDEBUG if (shdebug > 9) mprintf("shstart0: tp=%x, LO=%d, cc=%d \n", tp, TTLOWAT(tp), tp->t_outq.c_cc);#endif if (tp->t_outq.c_cc<=TTLOWAT(tp)) { if (tp->t_state&TS_ASLEEP) { /* wake up when output done */ tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_outq); } if (tp->t_wsel) { /* for select system call */ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); tp->t_wsel = 0; tp->t_state &= ~TS_WCOLL; } } /* * If we stopped output due to XOFF * restart it by re-setting xmit enable. * Must be done before checking if the queue is empty. * Otherwise, last line of output may not restart. */ addr->csr.low = SH_RIE|line; /* select line */ sh_softcsr = SH_RIE|line; /* select line */ if ((addr->tbuffad2.high&SH_XEN) == 0) { if (addr->lnctrl&SH_XABORT) addr->lnctrl &= ~SH_XABORT; free = addr->fun.fs.fifosize; addr->tbuffad2.high = SH_XEN; if (free < 64) { tp->t_state |= TS_BUSY; goto out; } } /* * Now restart transmission unless the output queue is * empty. */ if (tp->t_outq.c_cc == 0) goto out; if ((tp->t_lflag_ext & PRAW) || (tp->t_oflag_ext & PLITOUT) || ((tp->t_oflag & OPOST) == 0)) nch = ndqb(&tp->t_outq, 0); /* number of consecutive chars */ else { nch = ndqb(&tp->t_outq, DELAY_FLAG); /* * If first thing on queue is a delay process it. */ if (nch == 0) { nch = getc(&tp->t_outq); timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); tp->t_state |= TS_TIMEOUT; goto out; } } /* * If characters to transmit, restart transmission. */ if (nch) {#ifdef SHDEBUG if (shdebug > 9) mprintf("shstart1: line=%x, nch=%d\n", line, nch);#endif addr->csr.low = SH_RIE|line; /* select line */ sh_softcsr = SH_RIE|line; /* select line */ addr->csr.high = SH_XIE; if (addr->lnctrl&SH_XABORT) addr->lnctrl &= ~SH_XABORT; free = addr->fun.fs.fifosize; if (nch > free) nch = free; else free = nch; while (free > 1) { wdbuf.y[0] = *cp++; wdbuf.y[1] = *cp++; addr->fun.fifodata = wdbuf.x; free -= 2; } if (free == 1) addr->fun.fs.fifosize = *cp++; /* lo byte wrt */ ndflush(&tp->t_outq, nch); tp->t_state |= TS_BUSY; }out: splx(s);}/* * Stop output on a line, e.g. for ^S/^Q or output flush. *//*ARGSUSED*/shstop(tp, flag) register struct tty *tp;{ register struct shdevice *addr; register int unit, s; addr = (struct shdevice *)tp->t_addr; /* * Block input/output interrupts while messing with state. */ s = spl5(); if (tp->t_state & TS_BUSY) { /* * Device is transmitting; stop output. * We can continue later * by examining the address where the sh stopped. */ unit = minor(tp->t_dev); addr->csr.low = (unit&LINEMASK)|SH_RIE; sh_softcsr = (unit&LINEMASK)|SH_RIE; /* * Abort xmit only if flushing tty queues, i.e., * called by ttyflush(). * Otherwise, turn off Xmit enable to stop output. */ if ((tp->t_state&TS_TTSTOP)==0) { tp->t_state |= TS_FLUSH; addr->lnctrl |= SH_XABORT; /* abort transmission */ } else { /* * If flushing output in AUTOFLOW mode we have no * choice but to let the remainder drain. If this * test wasn't here and SH_XFLOW was set the device * would be waiting for ^Q once we cleared xmit * enable. */ if ((tp->t_cflag_ext & PAUTOFLOW) == 0) { /* turn off xmit enable */ addr->tbuffad2.high = 0; tp->t_state &= ~TS_BUSY; } } } splx(s);}shreset(uban) int uban;{}sh_cd_drop(tp)register struct tty *tp;{ register struct shdevice *addr = (struct shdevice *)tp->t_addr; register int unit = minor(tp->t_dev); addr->csr.low = SH_RIE|(unit & LINEMASK); sh_softcsr = SH_RIE|(unit & LINEMASK); if ((tp->t_state&TS_CARR_ON) && ((addr->fun.fs.stat&SH_CD) == 0)) { if (shdebug) mprintf("sh_cd: no CD, tp=%x\n", tp); sh_tty_drop(tp); return; } shmodem[minor(tp->t_dev)] |= MODEM_CD; if (shdebug) mprintf("sh_cd: CD is up, tp=%x\n", tp);}sh_dsr_check(tp)register struct tty *tp;{ int unit = minor(tp->t_dev); register struct shdevice *addr = (struct shdevice *)tp->t_addr; if (shmodem[unit]&MODEM_DSR_START) { if (shdebug) mprintf("sh_dsr_check0: tp=%x\n", tp); shmodem[unit] &= ~MODEM_DSR_START; addr->csr.low = SH_RIE|(unit&LINEMASK); sh_softcsr = SH_RIE|(unit&LINEMASK); /* * If shdsr is set look for DSR|CTS|CD, otherwise look * for CD|CTS only. */ if (shdsr) { if ((addr->fun.fs.stat&SH_XMIT)==SH_XMIT) sh_start_tty(tp); } else if ((addr->fun.fs.stat&SH_NODSR)==SH_NODSR) sh_start_tty(tp); return; } if ((tp->t_state&TS_CARR_ON)==0) { sh_tty_drop(tp); if (shdebug) mprintf("sh_dsr_check: no carrier, tp=%x\n", tp); } else if (shdebug) mprintf("sh_dsr_check: carrier is up, tp=%x\n", tp);}/* * cd_down return 1 if carrier has been down for at least 2 secs. */sh_cd_down(tp)struct tty *tp;{ int msecs; int unit = minor(tp->t_dev); msecs = 1000000 * (time.tv_sec - shtimestamp[unit].tv_sec) + (time.tv_usec - shtimestamp[unit].tv_usec); if (msecs > 2000000) return(1); else return(0);}sh_tty_drop(tp)struct tty *tp;{ register struct shdevice *addr = (struct shdevice *)tp->t_addr; register int unit; if (tp->t_flags&NOHANG) return; unit = minor(tp->t_dev); shmodem[unit] = MODEM_BADCALL; tp->t_state &= ~(TS_CARR_ON|TS_TTSTOP|TS_BUSY|TS_ISUSP); wakeup((caddr_t)&tp->t_rawq); gsignal(tp->t_pgrp, SIGHUP); gsignal(tp->t_pgrp, SIGCONT); addr->csr.low = SH_RIE|(unit&LINEMASK); sh_softcsr = SH_RIE|(unit&LINEMASK); addr->lnctrl &= ~(SH_DTR|SH_RTS); /* turn off DTR */}sh_start_tty(tp) register struct tty *tp;{ int unit = minor(tp->t_dev); tp->t_state &= ~TS_ONDELAY; tp->t_state |= TS_CARR_ON; if (shdebug) mprintf("sh_start_tty: tp=%x\n", tp); if (shmodem[unit]&MODEM_DSR) untimeout(sh_dsr_check, tp); shmodem[unit] |= MODEM_CD|MODEM_CTS|MODEM_DSR; shtimestamp[unit] = shzerotime; wakeup((caddr_t)&tp->t_rawq);}shbaudrate(speed)register int speed;{ if (sh_valid_speeds & (1 << speed)) return (1); else return (0);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -