📄 dcm.c
字号:
register char *bp; register unsigned tail, next; register int port, nch; unsigned head; char buf[16]; int s;#ifdef DCMSTATS struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)]; int tch = 0;#endif s = spltty();#ifdef DCMSTATS dsp->xints++;#endif#ifdef DEBUG if (dcmdebug & DDB_OUTPUT) printf("dcmstart(%d): state %x flags %x outcc %d\n", UNIT(tp->t_dev), tp->t_state, tp->t_flags, tp->t_outq.c_cc);#endif if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) goto out; if (tp->t_outq.c_cc <= tp->t_lowat) { if (tp->t_state&TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_outq); } selwakeup(&tp->t_wsel); } if (tp->t_outq.c_cc == 0) {#ifdef DCMSTATS dsp->xempty++;#endif goto out; } dcm = dcm_addr[BOARD(tp->t_dev)]; port = PORT(tp->t_dev); pp = dcm_preg(dcm, port); tail = pp->t_tail & TX_MASK; next = (tail + 1) & TX_MASK; head = pp->t_head & TX_MASK; if (head == next) goto out; fifo = &dcm->dcm_tfifos[3-port][tail];again: nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);#ifdef DCMSTATS tch += nch;#endif#ifdef DEBUG if (dcmdebug & DDB_OUTPUT) printf("\thead %x tail %x nch %d\n", head, tail, nch);#endif /* * Loop transmitting all the characters we can. */ for (bp = buf; --nch >= 0; bp++) { fifo->data_char = *bp; pp->t_tail = next; /* * If this is the first character, * get the hardware moving right now. */ if (bp == buf) { tp->t_state |= TS_BUSY; SEM_LOCK(dcm); dcm->dcm_cmdtab[port].dcm_data |= CT_TX; dcm->dcm_cr |= (1 << port); SEM_UNLOCK(dcm); } tail = next; fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0]; next = (next + 1) & TX_MASK; } /* * Head changed while we were loading the buffer, * go back and load some more if we can. */ if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {#ifdef DCMSTATS dsp->xrestarts++;#endif head = pp->t_head & TX_MASK; goto again; } /* * Kick it one last time in case it finished while we were * loading the last bunch. */ if (bp > &buf[1]) { tp->t_state |= TS_BUSY; SEM_LOCK(dcm); dcm->dcm_cmdtab[port].dcm_data |= CT_TX; dcm->dcm_cr |= (1 << port); SEM_UNLOCK(dcm); }#ifdef DEBUG if (dcmdebug & DDB_INTR) printf("dcmstart(%d): head %x tail %x outqcc %d\n", UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc);#endifout:#ifdef DCMSTATS dsp->xchars += tch; if (tch <= DCMXBSIZE) dsp->xsilo[tch]++; else dsp->xsilo[DCMXBSIZE+1]++;#endif splx(s);} /* * Stop output on a line. */dcmstop(tp, flag) register struct tty *tp; int flag;{ int s; s = spltty(); if (tp->t_state & TS_BUSY) { /* XXX is there some way to safely stop transmission? */ if ((tp->t_state&TS_TTSTOP) == 0) tp->t_state |= TS_FLUSH; } splx(s);} /* * Modem control */dcmmctl(dev, bits, how) dev_t dev; int bits, how;{ register struct dcmdevice *dcm; int s, unit, brd, hit = 0; unit = UNIT(dev);#ifdef DEBUG if (dcmdebug & DDB_MODEM) printf("dcmmctl(%d) unit %d bits 0x%x how %x\n", BOARD(unit), unit, bits, how);#endif brd = BOARD(unit); dcm = dcm_addr[brd]; s = spltty(); switch (how) { case DMSET: dcm_modem[unit]->mdmout = bits; hit++; break; case DMBIS: dcm_modem[unit]->mdmout |= bits; hit++; break; case DMBIC: dcm_modem[unit]->mdmout &= ~bits; hit++; break; case DMGET: bits = dcm_modem[unit]->mdmin; if (dcmsoftCAR[brd] & FLAG_STDDCE) bits = hp2dce_in(bits); break; } if (hit) { SEM_LOCK(dcm); dcm->dcm_modemchng |= 1<<(unit & 3); dcm->dcm_cr |= CR_MODM; SEM_UNLOCK(dcm); DELAY(10); /* delay until done */ (void) splx(s); } return (bits);}/* * Set board to either interrupt per-character or at a fixed interval. */dcmsetischeme(brd, flags) int brd, flags;{ register struct dcmdevice *dcm = dcm_addr[brd]; register struct dcmischeme *dis = &dcmischeme[brd]; register int i; u_char mask; int perchar = flags & DIS_PERCHAR;#ifdef DEBUG if (dcmdebug & DDB_INTSCHM) printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n", brd, perchar, dis->dis_perchar, dis->dis_intr, dis->dis_char); if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) { printf("dcmsetischeme(%d): redundent request %d\n", brd, perchar); return; }#endif /* * If perchar is non-zero, we enable interrupts on all characters * otherwise we disable perchar interrupts and use periodic * polling interrupts. */ dis->dis_perchar = perchar; mask = perchar ? 0xf : 0x0; for (i = 0; i < 256; i++) dcm->dcm_bmap[i].data_data = mask; /* * Don't slow down tandem mode, interrupt on flow control * chars for any port on the board. */ if (!perchar) { register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)]; int c; for (i = 0; i < 4; i++, tp++) { if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE) dcm->dcm_bmap[c].data_data |= (1 << i); if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE) dcm->dcm_bmap[c].data_data |= (1 << i); } } /* * Board starts with timer disabled so if first call is to * set perchar mode then we don't want to toggle the timer. */ if (flags == (DIS_RESET|DIS_PERCHAR)) return; /* * Toggle card 16.7ms interrupts (we first make sure that card * has cleared the bit so it will see the toggle). */ while (dcm->dcm_cr & CR_TIMER) ; SEM_LOCK(dcm); dcm->dcm_cr |= CR_TIMER; SEM_UNLOCK(dcm);}/* * Following are all routines needed for DCM to act as console */#include <hp/dev/cons.h>dcmcnprobe(cp) struct consdev *cp;{ register struct hp_hw *hw; int unit; /* locate the major number */ for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++) if (cdevsw[dcmmajor].d_open == dcmopen) break; /* * Implicitly assigns the lowest select code DCM card found to be * logical unit 0 (actually CONUNIT). If your config file does * anything different, you're screwed. */ for (hw = sc_table; hw->hw_type; hw++) if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva)) break; if (!HW_ISDEV(hw, D_COMMDCM)) { cp->cn_pri = CN_DEAD; return; } unit = CONUNIT; dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva; /* initialize required fields */ cp->cn_dev = makedev(dcmmajor, unit); cp->cn_tp = &dcm_tty[unit]; switch (dcm_addr[BOARD(unit)]->dcm_rsid) { case DCMID: cp->cn_pri = CN_NORMAL; break; case DCMID|DCMCON: cp->cn_pri = CN_REMOTE; break; default: cp->cn_pri = CN_DEAD; return; } /* * If dcmconsole is initialized, raise our priority. */ if (dcmconsole == UNIT(unit)) cp->cn_pri = CN_REMOTE;#ifdef KGDB_CHEAT /* * This doesn't currently work, at least not with ite consoles; * the console hasn't been initialized yet. */ if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) { (void) dcminit(kgdb_dev, kgdb_rate); if (kgdb_debug_init) { /* * We assume that console is ready for us... * this assumes that a dca or ite console * has been selected already and will init * on the first putc. */ printf("dcm%d: ", UNIT(kgdb_dev)); kgdb_connect(1); } }#endif}dcmcninit(cp) struct consdev *cp;{ dcminit(cp->cn_dev, dcmdefaultrate); dcmconsinit = 1; dcmconsole = UNIT(cp->cn_dev);}dcminit(dev, rate) dev_t dev; int rate;{ register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; int s, mode, port; port = PORT(dev); mode = LC_8BITS | LC_1STOP; s = splhigh(); /* * Wait for transmitter buffer to empty. */ while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) DELAY(DCM_USPERCH(rate)); /* * Make changes known to hardware. */ dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); dcm->dcm_data[port].dcm_conf = mode; SEM_LOCK(dcm); dcm->dcm_cmdtab[port].dcm_data |= CT_CON; dcm->dcm_cr |= (1 << port); SEM_UNLOCK(dcm); /* * Delay for config change to take place. Weighted by baud. * XXX why do we do this? */ DELAY(16 * DCM_USPERCH(rate)); splx(s);}dcmcngetc(dev) dev_t dev;{ register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; register struct dcmrfifo *fifo; register struct dcmpreg *pp; register unsigned head; int s, c, stat, port; port = PORT(dev); pp = dcm_preg(dcm, port); s = splhigh(); head = pp->r_head & RX_MASK; fifo = &dcm->dcm_rfifos[3-port][head>>1]; while (head == (pp->r_tail & RX_MASK)) ; /* * If board interrupts are enabled, just let our received char * interrupt through in case some other port on the board was * busy. Otherwise we must clear the interrupt. */ SEM_LOCK(dcm); if ((dcm->dcm_ic & IC_IE) == 0) stat = dcm->dcm_iir; SEM_UNLOCK(dcm); c = fifo->data_char; stat = fifo->data_stat; pp->r_head = (head + 2) & RX_MASK; splx(s); return (c);}/* * Console kernel output character routine. */dcmcnputc(dev, c) dev_t dev; int c;{ register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; register struct dcmpreg *pp; unsigned tail; int s, port, stat; port = PORT(dev); pp = dcm_preg(dcm, port); s = splhigh();#ifdef KGDB if (dev != kgdb_dev)#endif if (dcmconsinit == 0) { (void) dcminit(dev, dcmdefaultrate); dcmconsinit = 1; } tail = pp->t_tail & TX_MASK; while (tail != (pp->t_head & TX_MASK)) ; dcm->dcm_tfifos[3-port][tail].data_char = c; pp->t_tail = tail = (tail + 1) & TX_MASK; SEM_LOCK(dcm); dcm->dcm_cmdtab[port].dcm_data |= CT_TX; dcm->dcm_cr |= (1 << port); SEM_UNLOCK(dcm); while (tail != (pp->t_head & TX_MASK)) ; /* * If board interrupts are enabled, just let our completion * interrupt through in case some other port on the board * was busy. Otherwise we must clear the interrupt. */ if ((dcm->dcm_ic & IC_IE) == 0) { SEM_LOCK(dcm); stat = dcm->dcm_iir; SEM_UNLOCK(dcm); } splx(s);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -