📄 dh.c
字号:
s = spl5(); dhsoftCAR[dh] &= ~(1<<(unit&0xf)); if (*(int *)data) /* make mode permanent */ dhdefaultCAR[dh] &= ~(1<<(unit&0xf)); splx(s); break; case TIOCWONLINE: dmopen(dev, 0); break; default: return (ENOTTY); } return (0);}/* * Set parameters from open or stty into the DH hardware * registers. */dhparam(unit) register int unit;{ register struct tty *tp; register struct dhdevice *addr; register int lpar; int s; tp = &dh11[unit]; addr = (struct dhdevice *)tp->t_addr; /* * Block interrupts so parameters will be set * before the line interrupts. */ s = spl5(); addr->un.dhcsrl = (unit&0xf) | DH_IE; /* * Disconnect modem line if baudrate is zero. */ if ((tp->t_cflag & CBAUD) == B0) { tp->t_cflag |= HUPCL; dmctl(unit, DML_OFF, DMSET); splx(s); return; } lpar = (((tp->t_cflag_ext&CBAUD)<<6) | ((tp->t_cflag&CBAUD)<<10)); if (tp->t_flags & (RAW|LITOUT)) lpar |= BITS8; else lpar |= BITS7|PENABLE; if ((tp->t_flags&EVENP) == 0) lpar |= OPAR; addr->dhlpr = lpar; splx(s);}/* * DH11 transmitter interrupt. * Restart each line which used to be active but has * terminated transmission since the last interrupt. */dhxint(dh) int dh;{ register struct tty *tp; register struct dhdevice *addr; short ttybit, bar, *sbar; register struct uba_device *ui; register int unit; u_short cntr; ui = dhinfo[dh]; addr = (struct dhdevice *)ui->ui_addr; if (addr->un.dhcsr & DH_NXM) { addr->un.dhcsr |= DH_CNI; printf("dh%d: NXM\n", dh); } sbar = &dhsar[dh]; bar = *sbar & ~addr->dhbar; unit = dh * 16; ttybit = 1; addr->un.dhcsr &= (short)~DH_TI; for (; bar; unit++, ttybit <<= 1) { if (bar & ttybit) { *sbar &= ~ttybit; bar &= ~ttybit; tp = &dh11[unit]; tp->t_state &= ~TS_BUSY; if (tp->t_state&TS_FLUSH) tp->t_state &= ~TS_FLUSH; else { addr->un.dhcsrl = (unit&017)|DH_IE; /* * Do arithmetic in a short to make up * for lost 16&17 bits. */ cntr = addr->dhcar - UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); ndflush(&tp->t_outq, (int)cntr); } if (tp->t_line) (*linesw[tp->t_line].l_start)(tp); else dhstart(tp); } }}/* * Start (restart) transmission on the given DH11 line. */dhstart(tp) register struct tty *tp;{ register struct dhdevice *addr; register int car, dh, unit, nch; int s; unit = minor(tp->t_dev); dh = unit >> 4; unit &= 0xf; addr = (struct dhdevice *)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. */ if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) goto out; /* * If there are sleepers, and output has drained below low * water mark, wake up the sleepers. */ if (tp->t_outq.c_cc<=TTLOWAT(tp)) { if (tp->t_state&TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_outq); } if (tp->t_wsel) { selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); tp->t_wsel = 0; tp->t_state &= ~TS_WCOLL; } } /* * Now restart transmission unless the output queue is * empty. */ if (tp->t_outq.c_cc == 0) goto out; if (tp->t_flags & (RAW|LITOUT)) nch = ndqb(&tp->t_outq, 0); else { nch = ndqb(&tp->t_outq, 0200); /* * 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) { car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; /* * The following nonsense with short word * is to make sure the dhbar |= word below * is done with an interlocking bisw2 instruction. */ { short word = 1 << unit; dhsar[dh] |= word; addr->dhcar = car; addr->dhbcr = -nch; addr->dhbar |= word; } tp->t_state |= TS_BUSY; }out: splx(s);}/* * Stop output on a line, e.g. for ^S/^Q or output flush. *//*ARGSUSED*/dhstop(tp, flag) register struct tty *tp;{ register struct dhdevice *addr; register int unit, s; addr = (struct dhdevice *)tp->t_addr; /* * Block input/output interrupts while messing with state. */ s = spl5(); if (tp->t_state & TS_BUSY) { /* * Device is transmitting; stop output * by selecting the line and setting the byte * count to -1. We will clean up later * by examining the address where the dh stopped. */ unit = minor(tp->t_dev); addr->un.dhcsrl = (unit&017) | DH_IE; if ((tp->t_state&TS_TTSTOP)==0) tp->t_state |= TS_FLUSH; addr->dhbcr = -1; } splx(s);}/* * Reset state of driver if UBA reset was necessary. * Reset the csrl and lpr registers on open lines, and * restart transmitters. */dhreset(uban) int uban;{ register int dh, unit; register struct tty *tp; register struct uba_device *ui; int i; if (tty_ubinfo[uban] == 0) return; cbase[uban] = tty_ubinfo[uban]&0x3ffff; dh = 0; for (dh = 0; dh < nNDH; dh++) { ui = dhinfo[dh]; if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) continue; printf(" dh%d", dh); ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; ((struct dhdevice *)ui->ui_addr)->dhsilo = 0; unit = dh * 16; for (i = 0; i < 16; i++) { tp = &dh11[unit]; if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { dhparam(unit); dmctl(unit, DML_ON, DMSET); tp->t_state &= ~TS_BUSY; dhstart(tp); } unit++; } } dhsilos = 0;}int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*//* * At software clock interrupt time, check status. * Empty all the dh silos that are in use, and decide whether * to turn any silos off or on. */dhtimer(){ register int dh, s; static int timercalls; if (dhsilos) { dhfasttimers++; /*DEBUG*/ timercalls++; s = spl5(); for (dh = 0; dh < nNDH; dh++) if (dhsilos & (1 << dh)) dhrint(dh); splx(s); } if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) { dhslowtimers++; /*DEBUG*/ timercalls = 0; for (dh = 0; dh < nNDH; dh++) { ave(dhrate[dh], dhchars[dh], 8); if ((dhchars[dh] > dhhighrate) && ((dhsilos & (1 << dh)) == 0)) { ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = (dhchars[dh] > 500? 32 : 16); dhsilos |= (1 << dh); dhtransitions++; /*DEBUG*/ } else if ((dhsilos & (1 << dh)) && (dhrate[dh] < dhlowrate)) { ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0; dhsilos &= ~(1 << dh); } dhchars[dh] = 0; } } timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz);}/* * Turn on the line associated with dh dev. */dmopen(dev, flag) dev_t dev;{ register struct tty *tp; register struct dmdevice *addr; register struct uba_device *ui; register int unit; register int dm; int s; int inuse; /*hold state of inuse bit while blocked waiting for carr*/ unit = minor(dev); dm = unit >> 4; tp = &dh11[unit]; unit &= 0xf; if (dm >= nNDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) return(ENXIO); addr = (struct dmdevice *)ui->ui_addr; s = spl5(); addr->dmcsr &= ~DM_SE; while (addr->dmcsr & DM_BUSY) ; addr->dmcsr = unit; addr->dmlstat = DML_ON; if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit))) tp->t_state |= TS_CARR_ON; addr->dmcsr = DM_IE|DM_SE; if (flag & O_NDELAY) 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); /* 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); } } splx(s);}/* * Dump control bits into the DM registers. */dmctl(dev, bits, how) dev_t dev; int bits, how;{ register struct uba_device *ui; register struct dmdevice *addr; register int unit, s; int dm; unit = minor(dev); dm = unit >> 4; if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) return; addr = (struct dmdevice *)ui->ui_addr; s = spl5(); addr->dmcsr &= ~DM_SE; while (addr->dmcsr & DM_BUSY) ; addr->dmcsr = unit & 0xf; switch(how) { case DMSET: addr->dmlstat = bits; break; case DMBIS: addr->dmlstat |= bits; break; case DMBIC: addr->dmlstat &= ~bits; break; } addr->dmcsr = DM_IE|DM_SE; splx(s);}/* * DM11 interrupt; deal with carrier transitions. */dmintr(dm) register int dm;{ register struct uba_device *ui; register struct tty *tp; register struct dmdevice *addr; ui = dminfo[dm]; if (ui == 0) return; addr = (struct dmdevice *)ui->ui_addr; if (addr->dmcsr&DM_DONE) { if (addr->dmcsr&DM_CF) { tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; wakeup((caddr_t)&tp->t_rawq); if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) { if (addr->dmlstat & DML_CAR) { tp->t_state &= ~TS_TTSTOP; ttstart(tp); } else if ((tp->t_state&TS_TTSTOP) == 0) { tp->t_state |= TS_TTSTOP; dhstop(tp, 0); } } else if ((addr->dmlstat&DML_CAR)==0) { if ((tp->t_state&TS_WOPEN)==0 && (tp->t_flags & NOHANG) == 0) { gsignal(tp->t_pgrp, SIGHUP); gsignal(tp->t_pgrp, SIGCONT); addr->dmlstat = 0; ttyflush(tp, FREAD|FWRITE); } tp->t_state &= ~TS_CARR_ON; } else { tp->t_state |= TS_CARR_ON; tp->t_state &= ~TS_ONDELAY; } } addr->dmcsr = DM_IE|DM_SE; }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -