📄 dcm.c
字号:
{ int unit = UNIT(dev); register struct tty *tp; tp = &dcm_tty[unit]; /* * XXX we disallow virtual consoles if the physical console is * a serial port. This is in case there is a display attached that * is not the console. In that situation we don't need/want the X * server taking over the console. */ if (constty && unit == dcmconsole) constty = NULL; return ((*linesw[tp->t_line].l_write)(tp, uio, flag));} dcmintr(brd) register int brd;{ register struct dcmdevice *dcm = dcm_addr[brd]; register struct dcmischeme *dis; register int unit = MKUNIT(brd, 0); register int code, i; int pcnd[4], mcode, mcnd[4]; /* * Do all guarded register accesses right off to minimize * block out of hardware. */ SEM_LOCK(dcm); if ((dcm->dcm_ic & IC_IR) == 0) { SEM_UNLOCK(dcm); return (0); } for (i = 0; i < 4; i++) { pcnd[i] = dcm->dcm_icrtab[i].dcm_data; dcm->dcm_icrtab[i].dcm_data = 0; code = dcm_modem[unit+i]->mdmin; if (dcmsoftCAR[brd] & FLAG_STDDCE) code = hp2dce_in(code); mcnd[i] = code; } code = dcm->dcm_iir & IIR_MASK; dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */ mcode = dcm->dcm_modemintr; dcm->dcm_modemintr = 0; SEM_UNLOCK(dcm);#ifdef DEBUG if (dcmdebug & DDB_INTR) { printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ", brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3]); printf("miir %x mc %x/%x/%x/%x\n", mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]); }#endif if (code & IIR_TIMEO) dcmrint(brd, dcm); if (code & IIR_PORT0) dcmpint(unit+0, pcnd[0], dcm); if (code & IIR_PORT1) dcmpint(unit+1, pcnd[1], dcm); if (code & IIR_PORT2) dcmpint(unit+2, pcnd[2], dcm); if (code & IIR_PORT3) dcmpint(unit+3, pcnd[3], dcm); if (code & IIR_MODM) { if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */ dcmmint(unit+0, mcnd[0], dcm); if (mcode & 0x2) dcmmint(unit+1, mcnd[1], dcm); if (mcode & 0x4) dcmmint(unit+2, mcnd[2], dcm); if (mcode & 0x8) dcmmint(unit+3, mcnd[3], dcm); } dis = &dcmischeme[brd]; /* * Chalk up a receiver interrupt if the timer running or one of * the ports reports a special character interrupt. */ if ((code & IIR_TIMEO) || ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC)) dis->dis_intr++; /* * See if it is time to check/change the interrupt rate. */ if (dcmistype < 0 && (i = time.tv_sec - dis->dis_time) >= dcminterval) { /* * If currently per-character and averaged over 70 interrupts * per-second (66 is threshold of 600 baud) in last interval, * switch to timer mode. * * XXX decay counts ala load average to avoid spikes? */ if (dis->dis_perchar && dis->dis_intr > 70 * i) dcmsetischeme(brd, DIS_TIMER); /* * If currently using timer and had more interrupts than * received characters in the last interval, switch back * to per-character. Note that after changing to per-char * we must process any characters already in the queue * since they may have arrived before the bitmap was setup. * * XXX decay counts? */ else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) { dcmsetischeme(brd, DIS_PERCHAR); dcmrint(brd, dcm); } dis->dis_intr = dis->dis_char = 0; dis->dis_time = time.tv_sec; } return (1);}/* * Port interrupt. Can be two things: * First, it might be a special character (exception interrupt); * Second, it may be a buffer empty (transmit interrupt); */dcmpint(unit, code, dcm) int unit, code; struct dcmdevice *dcm;{ struct tty *tp = &dcm_tty[unit]; if (code & IT_SPEC) dcmreadbuf(unit, dcm, tp); if (code & IT_TX) dcmxint(unit, dcm, tp);}dcmrint(brd, dcm) int brd; register struct dcmdevice *dcm;{ register int i, unit; register struct tty *tp; unit = MKUNIT(brd, 0); tp = &dcm_tty[unit]; for (i = 0; i < 4; i++, tp++, unit++) dcmreadbuf(unit, dcm, tp);}dcmreadbuf(unit, dcm, tp) int unit; register struct dcmdevice *dcm; register struct tty *tp;{ int port = PORT(unit); register struct dcmpreg *pp = dcm_preg(dcm, port); register struct dcmrfifo *fifo; register int c, stat; register unsigned head; int nch = 0;#ifdef DCMSTATS struct dcmstats *dsp = &dcmstats[BOARD(unit)]; dsp->rints++;#endif if ((tp->t_state & TS_ISOPEN) == 0) {#ifdef KGDB if ((makedev(dcmmajor, unit) == kgdb_dev) && (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) && dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) { pp->r_head = (head + 2) & RX_MASK; kgdb_connect(0); /* trap into kgdb */ return; }#endif /* KGDB */ pp->r_head = pp->r_tail & RX_MASK; return; } head = pp->r_head & RX_MASK; fifo = &dcm->dcm_rfifos[3-port][head>>1]; /* * XXX upper bound on how many chars we will take in one swallow? */ while (head != (pp->r_tail & RX_MASK)) { /* * Get character/status and update head pointer as fast * as possible to make room for more characters. */ c = fifo->data_char; stat = fifo->data_stat; head = (head + 2) & RX_MASK; pp->r_head = head; fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0]; nch++;#ifdef DEBUG if (dcmdebug & DDB_INPUT) printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n", unit, c&0xFF, c, stat&0xFF, tp->t_flags, head, pp->r_tail);#endif /* * Check for and handle errors */ if (stat & RD_MASK) {#ifdef DEBUG if (dcmdebug & (DDB_INPUT|DDB_SIOERR)) printf("dcmreadbuf(%d): err: c%x('%c') s%x\n", unit, stat, c&0xFF, c);#endif if (stat & (RD_BD | RD_FE)) c |= TTY_FE; else if (stat & RD_PE) c |= TTY_PE; else if (stat & RD_OVF) log(LOG_WARNING, "dcm%d: silo overflow\n", unit); else if (stat & RD_OE) log(LOG_WARNING, "dcm%d: uart overflow\n", unit); } (*linesw[tp->t_line].l_rint)(c, tp); } dcmischeme[BOARD(unit)].dis_char += nch;#ifdef DCMSTATS dsp->rchars += nch; if (nch <= DCMRBSIZE) dsp->rsilo[nch]++; else dsp->rsilo[DCMRBSIZE+1]++;#endif}dcmxint(unit, dcm, tp) int unit; struct dcmdevice *dcm; register struct tty *tp;{ tp->t_state &= ~TS_BUSY; if (tp->t_state & TS_FLUSH) tp->t_state &= ~TS_FLUSH; (*linesw[tp->t_line].l_start)(tp);}dcmmint(unit, mcnd, dcm) register int unit; register struct dcmdevice *dcm; int mcnd;{ register struct tty *tp; int delta;#ifdef DEBUG if (dcmdebug & DDB_MODEM) printf("dcmmint: port %d mcnd %x mcndlast %x\n", unit, mcnd, mcndlast[unit]);#endif tp = &dcm_tty[unit]; delta = mcnd ^ mcndlast[unit]; mcndlast[unit] = mcnd; if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) && (tp->t_flags & CCTS_OFLOW)) { if (mcnd & MI_CTS) { tp->t_state &= ~TS_TTSTOP; ttstart(tp); } else tp->t_state |= TS_TTSTOP; /* inline dcmstop */ } if (delta & MI_CD) { if (mcnd & MI_CD) (void)(*linesw[tp->t_line].l_modem)(tp, 1); else if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0 && (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { dcm_modem[unit]->mdmout = MO_OFF; SEM_LOCK(dcm); dcm->dcm_modemchng |= 1<<(unit & 3); dcm->dcm_cr |= CR_MODM; SEM_UNLOCK(dcm); DELAY(10); /* time to change lines */ } }}dcmioctl(dev, cmd, data, flag, p) dev_t dev; int cmd; caddr_t data; int flag; struct proc *p;{ register struct tty *tp; register int unit = UNIT(dev); register struct dcmdevice *dcm; register int port; int error, s; #ifdef DEBUG if (dcmdebug & DDB_IOCTL) printf("dcmioctl: unit %d cmd %x data %x flag %x\n", unit, cmd, *data, flag);#endif tp = &dcm_tty[unit]; error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); if (error >= 0) return (error); error = ttioctl(tp, cmd, data, flag); if (error >= 0) return (error); port = PORT(unit); dcm = dcm_addr[BOARD(unit)]; switch (cmd) { case TIOCSBRK: /* * Wait for transmitter buffer to empty */ s = spltty(); while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) DELAY(DCM_USPERCH(tp->t_ospeed)); SEM_LOCK(dcm); dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; dcm->dcm_cr |= (1 << port); /* start break */ SEM_UNLOCK(dcm); splx(s); break; case TIOCCBRK: SEM_LOCK(dcm); dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; dcm->dcm_cr |= (1 << port); /* end break */ SEM_UNLOCK(dcm); break; case TIOCSDTR: (void) dcmmctl(dev, MO_ON, DMBIS); break; case TIOCCDTR: (void) dcmmctl(dev, MO_ON, DMBIC); break; case TIOCMSET: (void) dcmmctl(dev, *(int *)data, DMSET); break; case TIOCMBIS: (void) dcmmctl(dev, *(int *)data, DMBIS); break; case TIOCMBIC: (void) dcmmctl(dev, *(int *)data, DMBIC); break; case TIOCMGET: *(int *)data = dcmmctl(dev, 0, DMGET); break; default: return (ENOTTY); } return (0);}dcmparam(tp, t) register struct tty *tp; register struct termios *t;{ register struct dcmdevice *dcm; register int port, mode, cflag = t->c_cflag; int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab); /* check requested parameters */ if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) return (EINVAL); /* and copy to tty */ tp->t_ispeed = t->c_ispeed; tp->t_ospeed = t->c_ospeed; tp->t_cflag = cflag; if (ospeed == 0) { (void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET); return (0); } mode = 0; switch (cflag&CSIZE) { case CS5: mode = LC_5BITS; break; case CS6: mode = LC_6BITS; break; case CS7: mode = LC_7BITS; break; case CS8: mode = LC_8BITS; break; } if (cflag&PARENB) { if (cflag&PARODD) mode |= LC_PODD; else mode |= LC_PEVEN; } if (cflag&CSTOPB) mode |= LC_2STOP; else mode |= LC_1STOP;#ifdef DEBUG if (dcmdebug & DDB_PARAM) printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n", UNIT(tp->t_dev), cflag, mode, tp->t_ospeed, DCM_USPERCH(tp->t_ospeed));#endif port = PORT(tp->t_dev); dcm = dcm_addr[BOARD(tp->t_dev)]; /* * Wait for transmitter buffer to empty. */ while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) DELAY(DCM_USPERCH(tp->t_ospeed)); /* * Make changes known to hardware. */ dcm->dcm_data[port].dcm_baud = ospeed; 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(tp->t_ospeed)); return (0);} voiddcmstart(tp) register struct tty *tp;{ register struct dcmdevice *dcm; register struct dcmpreg *pp; register struct dcmtfifo *fifo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -