📄 dhu.c
字号:
if (tp->t_cflag & PARENB) { if ((tp->t_cflag & PARODD) == 0) /* else set even */ lpar |= DHU_PENABLE|DHU_EVENPAR; else /* set odd */ lpar = (lpar | DHU_PENABLE)&~DHU_EVENPAR; } /* * character size. * clear bits and check for 6,7,and 8, else its 5 bits. */ lpar &= ~DHU_BITS8; switch(tp->t_cflag&CSIZE) { case CS6: lpar |= DHU_BITS6; break; case CS7: lpar |= DHU_BITS7; break; case CS8: lpar |= DHU_BITS8; break; } /* * Outgoing Auto flow control. * No auto flow control allowed if startc != ^q and startc != * ^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 |= DHU_XFLOW; else addr->lnctrl &= ~DHU_XFLOW; WBFLUSH(); addr->lpr = lpar; WBFLUSH();#ifdef DHUDEBUG if (dhudebug) mprintf("dhuparam: tp=%x, lpr=%x\n", tp, lpar);#endif splx(s);}/* * DHU11 transmitter interrupt. * Restart each line which used to be active but has * terminated transmission since the last interrupt. */dhuxint(dhu) int dhu; /* module number */{ register struct tty *tp; register struct dhudevice *addr; register struct uba_device *ui; register int unit, totaldelay; u_short cntr; char csrxmt; ui = dhuinfo[dhu]; addr = (struct dhudevice *)ui->ui_addr; while ((csrxmt = addr->csr.high) < 0) { if (csrxmt & DHU_DMAERR) printf("dhu%d:%d DMA ERROR\n", dhu, csrxmt&0xf); if (csrxmt & DHU_DIAGFAIL) printf("dhu%d: DIAG. FAILURE\n", dhu); unit = dhu * 16; unit |= csrxmt&LINEMASK; tp = &dhu11[unit];#ifdef DHUDEBUG if (dhudebug > 4) mprintf("dhuxint: unit=%x, tp=%x, c_cc=%d\n", unit, tp, tp->t_outq.c_cc);#endif tp->t_state &= ~TS_BUSY; addr->csr.low = (unit&LINEMASK)|DHU_RIE; WBFLUSH(); totaldelay = 0; while ((addr->tbuffad2.low & DHU_START) && (totaldelay <= 100)){ totaldelay++; DELAY(10000); } if (addr->tbuffad2.low & DHU_START) { printf("dmbxint: Resetting DMA START bit on line %d\n",unit); addr->tbuffad2.low &= ~DHU_START; } if (tp->t_state&TS_FLUSH) tp->t_state &= ~TS_FLUSH; else { /* * Determine number of chars transmitted * so far and flush these from the tty * output queue. * Do arithmetic in a short to make up * for lost 16&17 bits (in tbuffad2). */ cntr = addr->tbuffad1 - UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); ndflush(&tp->t_outq, cntr); } if (tp->t_state & TS_NEED_PARAM) { tp->t_state &= ~TS_NEED_PARAM; dhuparam(unit); } if (tp->t_line) (*linesw[tp->t_line].l_start)(tp); else dhustart(tp); }}/* * Start (restart) transmission on the given DHU11 line. */dhustart(tp) register struct tty *tp;{ register struct dhudevice *addr; register int car, dhu, unit, nch; register int totaldelay; int line, s; unit = minor(tp->t_dev); dhu = unit >> 4; line = unit & LINEMASK; /* unit now equals the line number */ addr = (struct dhudevice *)tp->t_addr; /* * Must hold interrupts in following code to prevent * state of the tp from changing. */ s = spltty(); /* * 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) && (dhumodem[unit]&MODEM_CTS)==0)) goto out; /* * If there are sleepers, and output has drained below low * water mark, wake up the sleepers. */#ifdef DHUDEBUG if (dhudebug > 9) mprintf("dhustart0: 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; } } /* * 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 DHUDEBUG if (dhudebug > 9) mprintf("dhustart1: line=%x, nch=%d\n", line, nch);#endif addr->csr.low = DHU_RIE|line; /* select line */ WBFLUSH(); /* * Wait for dma start to clear to a maximum of 1 second to * prevent a system hang on hardware failure. After the bit * has stuck once, do not repeat this check. */ /* * TODO: * This should be changed to use a timeout instead of calling * microdelay!!!!! Timeouts can be of granularity of 10 ms. * Do this in the DMB driver also. */ totaldelay = 0; while ((addr->tbuffad2.low & DHU_START) && (totaldelay <= 100)) if ((dhu_softc[dhu].sc_flags[unit&LINEMASK]) == 0) { totaldelay++; DELAY(10000); } else totaldelay = 90000; if ((addr->tbuffad2.low & DHU_START) && ((dhu_softc[dhu].sc_flags[unit&LINEMASK]) == 0)) { printf("dhu%d,line%d DHU HARDWARE ERROR. TX.DMA.START failed\n",dhu,line); /* * Prevent further activity on this line by * setting state flag to dead. */ dhu_softc[dhu].sc_flags[unit&LINEMASK]++; splx(s); return; } if (addr->lnctrl & DHU_XABORT) /* clear abort if already set */ addr->lnctrl &= ~(DHU_XABORT); addr->csr.high = DHU_XIE; /* * If cblocks are ever malloc'ed we must insure that they * never cross VAX physical page boundaries. */ /* * Give the device the starting address of a DMA transfer. * Translate the system virtual address into a physical * address. */ car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); addr->tbuffad1 = car; addr->tbuffcnt = nch; /* * If Outgoing auto flow control is enabled, the hardware will * control the transmit enable bit. */ if ((tp->t_cflag_ext & PAUTOFLOW) == 0) addr->tbuffad2.high = DHU_XEN; /* get extended address bits and start DMA output */ if (dhuinfo[dhu]->ui_hd->uba_type&UBAUVI) addr->tbuffad2.low = ((car>>16)&0x3f)|DHU_START; else addr->tbuffad2.low = ((car>>16)&0x3)|DHU_START; WBFLUSH(); tp->t_state |= TS_BUSY; }out: splx(s);}/* * Stop output on a line, e.g. for ^S/^Q or output flush. *//*ARGSUSED*/dhustop(tp, flag) register struct tty *tp;{ register struct dhudevice *addr; register int unit, s; addr = (struct dhudevice *)tp->t_addr; /* * Block input/output interrupts while messing with state. */ s = spltty(); if (tp->t_state & TS_BUSY) { /* * Device is transmitting; stop output. * We can continue later * by examining the address where the dhu stopped. */ unit = minor(tp->t_dev); addr->csr.low = (unit&LINEMASK)|DHU_RIE; WBFLUSH(); if ((tp->t_state&TS_TTSTOP)==0) tp->t_state |= TS_FLUSH; addr->lnctrl |= DHU_XABORT; /* abort DMA transmission */ WBFLUSH(); } splx(s);}/* * Reset state of driver if UBA reset was necessary. * Reset the csr and lpr registers on open lines, and * restart transmitters. */dhureset(uban) int uban;{ register int dhu, unit, s; register struct tty *tp; register struct uba_device *ui; register struct dhudevice *addr; int i; if (tty_ubinfo[uban] == 0) return; /* there are no dhu11's in use */ if (uba_hd[uban].uba_type&UBAUVI) cbase[uban] = tty_ubinfo[uban]&0x3fffff; else cbase[uban] = tty_ubinfo[uban]&0x3ffff; dhu = 0; for (dhu = 0; dhu < nNDHU; dhu++) { ui = dhuinfo[dhu]; if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) continue; addr = (struct dhudevice *)ui->ui_addr; printf(" dhu%d", dhu); unit = dhu * 16; for (i = 0; i < 16; i++) { tp = &dhu11[unit]; if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { dhuparam(unit); s = spltty(); addr->csr.low = (i&LINEMASK)|DHU_RIE; WBFLUSH(); addr->lnctrl |= DHU_DTR|DHU_RTS|DHU_REN; WBFLUSH(); splx(s); tp->t_state &= ~TS_BUSY; dhustart(tp); } unit++; } } dhutimer();}/* * At software clock interrupt time or after a UNIBUS reset * empty all the dh silos. */dhutimer(){ register int dhu; register int s = spltty(); for (dhu = 0; dhu < nNDHU; dhu++) dhurint(dhu); splx(s);}dhu_cd_drop(tp)register struct tty *tp;{ register struct dhudevice *addr = (struct dhudevice *)tp->t_addr; register int unit = minor(tp->t_dev); addr->csr.low = DHU_RIE|(unit & LINEMASK); WBFLUSH(); if ((tp->t_state&TS_CARR_ON) && ((addr->fun.fs.stat&DHU_CD) == 0)) { if (dhudebug) mprintf("dhu_cd: no CD, tp=%x\n", tp); dhu_tty_drop(tp); return; } dhumodem[minor(tp->t_dev)] |= MODEM_CD; if (dhudebug) mprintf("dhu_cd: CD is up, tp=%x\n", tp);}dhu_dsr_check(tp)register struct tty *tp;{ int unit = minor(tp->t_dev); register struct dhudevice *addr = (struct dhudevice *)tp->t_addr; if (dhumodem[unit]&MODEM_DSR_START) { if (dhudebug) mprintf("dhu_dsr_check0: tp=%x\n", tp); dhumodem[unit] &= ~MODEM_DSR_START; addr->csr.low = DHU_RIE|(unit&LINEMASK); WBFLUSH(); /* * If dhudsr is set look for DSR|CTS|CD, otherwise look * for CD|CTS only. */ if (dhudsr) { if ((addr->fun.fs.stat&DHU_XMIT)==DHU_XMIT) dhu_start_tty(tp); } else if ((addr->fun.fs.stat&(DHU_CD|DHU_CTS))==(DHU_CD|DHU_CTS)) dhu_start_tty(tp); return; } if ((tp->t_state&TS_CARR_ON)==0) { dhu_tty_drop(tp); if (dhudebug) mprintf("dhu_dsr_check: no carrier, tp=%x\n", tp); } else if (dhudebug) mprintf("dhu_dsr_check: carrier is up, tp=%x\n", tp);}/* * cd_down return 1 if carrier has been down for at least 2 secs. */dhu_cd_down(tp)struct tty *tp;{ int msecs; int unit = minor(tp->t_dev); msecs = 1000000 * (time.tv_sec - dhutimestamp[unit].tv_sec) + (time.tv_usec - dhutimestamp[unit].tv_usec); if (msecs > 2000000) return(1); else return(0);}dhu_tty_drop(tp)struct tty *tp;{ register struct dhudevice *addr = (struct dhudevice *)tp->t_addr; register int unit; if (tp->t_flags&NOHANG) return; unit = minor(tp->t_dev); dhumodem[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 = DHU_RIE|(unit&LINEMASK); WBFLUSH(); addr->lnctrl &= ~(DHU_DTR|DHU_RTS); /* turn off DTR */ WBFLUSH();}dhu_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 (dhudebug) mprintf("dhu_start_tty: tp=%x\n", tp); if (dhumodem[unit]&MODEM_DSR) untimeout(dhu_dsr_check, tp); dhumodem[unit] |= MODEM_CD|MODEM_CTS|MODEM_DSR; dhutimestamp[unit] = dhuzerotime; wakeup((caddr_t)&tp->t_rawq);}dhubaudrate(speed)register int speed;{ if (dhu_valid_speeds & (1 << speed)) return (1); else return (0);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -