📄 mdc.c
字号:
return ((*linesw[tp->t_line].l_open)(dev, tp));}mdcclose(dev, flag) dev_t dev;{ register volatile struct mdz_reg *dcaddr; register struct tty *tp; register int unit; register int linenum; register int minor_num; register int s; extern int wakeup(); minor_num = minor(dev); unit = minor_num >> LINEBITS; dcaddr = mdz_regs[unit]; linenum = minor_num & LINEMASK; if (minor_num >= mdc_cnt) { return (ENXIO); }# ifdef DEBUG if (mdcdebug) cprintf("mdcclose: unit=%d, linenum=%d\n",unit, linenum);# endif DEBUG tp = &mdc_tty[minor_num]; /* * Do line discipline specific close functions then return here * in the old line disc for final closing. */ if (tp->t_line) (*linesw[tp->t_line].l_close)(tp); /* * dcbreak is write-only and sends a BREAK (SPACE condition) until * the break control bit is cleared. Here we are clearing any * breaks for this line on close. */ s = spltty(); if(mdc_brk[unit] & (1<< linenum)) { dcaddr->dcbreak = (mdc_brk[unit] &= ~(1 << linenum)); wbflush(); } splx(s); if ((tp->t_cflag&HUPCL) || (tp->t_state&TS_WOPEN) || (tp->t_state&TS_ISOPEN)==0) { tp->t_state &= ~TS_CARR_ON; /* prevents recv intr. timeouts */ /* * Drop appropriate signals to terminate the connection. */ mdcmodem_active &= ~(1 << minor_num); /* * De-assert modem control leads. * No disabling of interrupts is done. Characters read in on * a non-open line will be discarded. */ if (((tp->t_cflag & CLOCAL) == 0) && (unit != NOMODEM_UNIT) && (linenum == MODEM_LINE)) { s = spltty(); dcaddr->dctcr &= ~(DC_RDTR | DC_RRTS | DC_RSS); /*drop DTR for at least a sec. if modem line*/# ifdef DEBUG if (mdcdebug) cprintf("mdcclose: DTR drop, state =%x\n" ,tp->t_state);# endif DEBUG tp->t_state |= TS_CLOSING; /* * Wait at most 5 sec for DSR to go off. * Also hold DTR down for a period. */ if (dcaddr->dcmsr & DC_DSR) { timeout(wakeup,(caddr_t)&tp->t_dev,5*hz); sleep((caddr_t)&tp->t_dev, PZERO-10); } /* * Hold DTR down for 200+ ms. */ timeout(wakeup, (caddr_t) &tp->t_dev, hz/5); sleep((caddr_t)&tp->t_dev, PZERO-10); tp->t_state &= ~(TS_CLOSING); wakeup((caddr_t)&tp->t_rawq); splx(s); mdcmodem[unit] = 0; } } /* reset line to default mode */ mdcsoftCAR[unit] &= ~(1<<(linenum)); mdcsoftCAR[unit] |= (1<<(linenum)) & mdcdefaultCAR[unit]; ttyclose(tp); tty_def_close(tp);}mdcread(dev, uio) dev_t dev; struct uio *uio;{ register struct tty *tp; register int minor_num; minor_num = minor(dev); tp = &mdc_tty[minor_num]; return ((*linesw[tp->t_line].l_read)(tp, uio));}mdcwrite(dev, uio) dev_t dev; struct uio *uio;{ register struct tty *tp; register int minor_num; minor_num = minor(dev); tp = &mdc_tty[minor_num]; return ((*linesw[tp->t_line].l_write)(tp, uio));}/* * Device interrupt service routine. Examine the csr to see what the * interrupt is all about and dispatch the appropriate handler. */mdcintr(unit) register int unit;{ register volatile struct mdz_reg *dcaddr; register unsigned int csr; if (unit > nMDC) { /* sanity check */ cprintf("mdcintr: invalid unit %d.\n",unit); return; } dcaddr = mdz_regs[unit]; csr = dcaddr->dccsr; /* * OUTPUT: * The transmitter buffer is now empty for the specified line. Call * the pdma routine to place a new character in the tbuf. */ if (csr & DC_TRDY) { _mdcpdma(unit); } /* * INPUT: * A character has been received. Pass this up to the user application. */ if (csr & DC_RDONE) { mdcrint(unit); }}/* * A character has been received. Pass this character up to the user level * application after examining for errors such as parity errors or breaks. */mdcrint(unit) register int unit;{ register volatile struct mdz_reg *dcaddr; register struct tty *tp; register u_short c; /* rbuf register is 16 bits long */ struct tty *tp0; register int flg; register int linenum; int overrun = 0; u_short data; int counter = 0; tp0 = &mdc_tty[0]; dcaddr = mdz_regs[unit]; while (dcaddr->dccsr&DC_RDONE) { /* character present */ c = dcaddr->dcrbuf; linenum = (c>>8)&LINEMASK; tp = tp0 + linenum + (NDCLINE * unit); if (tp >= &mdc_tty[mdc_cnt]) continue; if ((tp->t_state & TS_ISOPEN) == 0) { wakeup((caddr_t)&tp->t_rawq); continue; } flg = tp->t_iflag; /* DC_FE is interpreted as a break */ if (c & DC_FE) { /* * If configured for trusted path, initiate * trusted path handling. */# ifdef DEBUG if (mdcdebug) mprintf("mdcrint: BREAK RECEIVED on unit = %d, linenum = %d\n", unit, linenum);# endif DEBUG if (do_tpath) { tp->t_tpath |= TP_DOSAK; (*linesw[tp->t_line].l_rint)(c, tp); break; } if (flg & IGNBRK) continue; if (flg & BRKINT) { if ((tp->t_lflag_ext & PRAW) && (tp->t_line != TERMIODISC)) c = 0; else { ttyflush(tp, FREAD | FWRITE); gsignal(tp->t_pgrp, SIGINT); continue; } } /* * TERMIO: If neither IGNBRK or BRKINT is set, a * break condition is read as a single '\0', * or if PARMRK is set as '\377', '\0' , '\0'. */ else { if (flg & PARMRK){ (*linesw[tp->t_line].l_rint)(0377,tp); (*linesw[tp->t_line].l_rint)(0,tp); } c = 0; } } /* Parity Error */ else if (c & DC_PE){ /* * If input parity checking is not enabled, clear out * parity error in this character. */# ifdef DEBUG if (mdcdebug > 1) mprintf("mdcrint: Parity Error\n");# endif DEBUG if ((flg & INPCK) == 0) { c &= ~DC_PE; } else { if (flg & IGNPAR) { continue; } /* If PARMRK is set, return a character with * framing or parity errors as a 3 character * sequence (0377,0,c). */ if (flg & PARMRK){ (*linesw[tp->t_line].l_rint)(0377,tp); (*linesw[tp->t_line].l_rint)(0,tp); } /* * TERMIO: If neither PARMRK or IGNPAR is set, a * parity error is read as a single '\0'. */ else { c = 0; } } } /* * Data Overrun. Only complain about this once per routine * entry. Increment error count to record the number of * errors. */ if (c&DC_DO) { if(overrun == 0) { printf("mdc%d: input silo overflow\n", 0); overrun = 1; } mdc_softc[unit].sc_softcnt[linenum]++; /* overrun errs */ } /* * Strip the character to be 7 bits in length. */ if (flg & ISTRIP){ c &= 0177; } /* * Strip the character to be 8 bits in length. */ else { c &= 0377; /* If ISTRIP is not set a valid character of 377 * is read as 0377,0377 to avoid ambiguity with * the PARMARK sequence. */ if ((c == 0377) && (tp->t_line == TERMIODISC) && (flg & PARMRK)) (*linesw[tp->t_line].l_rint)(0377,tp); }#if NHC > 0 if (tp->t_line == HCLDISC) { HCINPUT(c, tp); } else#endif (*linesw[tp->t_line].l_rint)(c, tp); }}/*ARGSUSED*/mdcioctl(dev, cmd, data, flag) dev_t dev; register int cmd; caddr_t data; int flag;{ register volatile struct mdz_reg *dcaddr; register int unit; register int linenum; register struct tty *tp; register int s; struct uba_device *ui; struct devget *devget; int error; int minor_num; minor_num = minor(dev); unit = minor_num >> LINEBITS; dcaddr = mdz_regs[unit]; linenum = minor_num & LINEMASK; if (minor_num >= mdc_cnt) { return (ENXIO); } tp = &mdc_tty[minor_num]; error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); if (error >= 0) return (error); error = ttioctl(tp, cmd, data, flag); if (error >= 0) { /* * If the call is to set terminal attributes which are * represented in the device's line parameter register then * call the param routine to update the device registers. */ switch(cmd) { case TCSANOW: /* POSIX termios */ case TCSADRAIN: /* POSIX termios */ case TCSAFLUSH: /* POSIX termios */ case TCSETA: /* SVID termio */ case TCSETAW: /* SVID termio */ case TCSETAF: /* SVID termio */ case TIOCSETP: /* Berkeley sgttyb */ case TIOCSETN: /* Berkeley sgttyb */ case TIOCLBIS: /* Berkeley lmode */ case TIOCLBIC: /* Berkeley lmode */ case TIOCLSET: /* Berkeley lmode */ case TIOCLGET: /* Berkeley lmode */ mdcparam(minor_num); break; } return (error); } switch (cmd) { /* * Begin a break sequence. The line will remain in a break state * until cleared. */ case TIOCSBRK: timeout(mdcsetbreak, tp, mdc_speeds[tp->t_cflag & CBAUD].delay_set_break); TTY_SLEEP(tp, (caddr_t)&tp->t_dev, TTOPRI); s = spltty(); if((mdc_brk[unit] & (1<< linenum)) == 0) { dcaddr->dcbreak = (mdc_brk[unit] |= (1 << linenum)); wbflush(); } splx(s);#ifdef DEBUG if (mdcdebug) mprintf("TIOCSBRK: unit = %d, linenum = %d, mdc_brk = %d, dccsr = 0x%x\n", unit, linenum, mdc_brk[unit], dcaddr->dccsr);#endif DEBUG break; /* * End a break sequence. */ case TIOCCBRK: s = spltty(); if(mdc_brk[unit] & (1<< linenum)) { dcaddr->dcbreak = (mdc_brk[unit] &= ~(1 << linenum)); wbflush(); } splx(s);#ifdef DEBUG if (mdcdebug) mprintf("TIOCCBRK: unit = %d, linenum = %d, mdc_brk = %d, dccsr = 0x%x\n", unit, linenum, mdc_brk[unit], dcaddr->dccsr);#endif DEBUG break; /* * Sets DTR and RTS in the tcr register. */ case TIOCSDTR: (void) mdcmctl(dev, SML_DTR | SML_RTS, DMBIS); break; /* * Clears DTR and RTS in the tcr register. */ case TIOCCDTR: (void) mdcmctl(dev, SML_DTR | SML_RTS, DMBIC); break; /* * TIOCSMLB and TIOCCMLB are used to set and clear the maintenance * loopback mode. This is useful to test the lines without the need * for loopback connectors. Restrict access to root users. * * Note that setting this bit will loopback ALL the lines on this * particular DC chip, not just the specific line refered to by tp! * Just to be on the safe side, do not allow this on the console unit. * Perhaps this ioctl is to dangerous to include. */ case TIOCSMLB: if ((u.u_uid) || (unit == CONSOLE_UNIT)) { return(EPERM); } s = spltty(); dcaddr->dccsr |= (DC_MAINT); wbflush(); splx(s); break; case TIOCCMLB: if ((u.u_uid) || (unit == CONSOLE_UNIT)) { return(EPERM); } s = spltty(); dcaddr->dccsr &= ~(DC_MAINT); wbflush(); splx(s); break; /* * Set the specified generic modem control attributes. * No way this works! The only relevant settings are DTR and RTS, * all others are not even looked at. */ case TIOCMSET: (void) mdcmctl(dev, dmtomdc(*(int *)data), DMSET); break; /* * Set the specified bits in the generic modem control attributes. * No way this works! The only relevant settings are DTR and RTS, * all others are not even looked at. */ case TIOCMBIS: (void) mdcmctl(dev, dmtomdc(*(int *)data), DMBIS); break; /* * Clear the specified bits from the generic modem control attributes. * No way this works! The only relevant settings are DTR and RTS, * all others are not even looked at. */ case TIOCMBIC: (void) mdcmctl(dev, dmtomdc(*(int *)data), DMBIC); break; /* * Return the current generic modem control attributes. Generally * speaking this will return garbage. * No way this works! The only relevant settings are DTR and RTS, * all others are not even looked at. */ case TIOCMGET: *(int *)data = mdctodm(mdcmctl(dev, 0, DMGET)); break; /* * Specify that this line is to be considered a direct connect * (no modem) line. */ case TIOCNMODEM: /* ignore modem status */ /* * By setting the software representation of modem signals * to "on" we fake the system into thinking that this is an * established modem connection. */ s = spltty(); mdcsoftCAR[unit] |= (1<<(linenum)); if (*(int *)data) /* make mode permanent */ mdcdefaultCAR[unit] |= (1<<(linenum)); tp->t_state |= TS_CARR_ON; tp->t_cflag |= CLOCAL; /* Map to termio */ splx(s); break; /* * Specify that this line is to be considered a modem * (not direct connect) line. This means pay attention to the * modem control leads. */ case TIOCMODEM: /* look at modem status - sleep if no carrier */ s = spltty(); /* * The only lines that allow modem control are line 2 of * DC0 and DC1. Should the ioctl fail? */ if ((unit == NOMODEM_UNIT) || (linenum != MODEM_LINE)) { tp->t_cflag |= CLOCAL; /* paranoia */ splx(s); break; } mdcsoftCAR[unit] &= ~(1<<(linenum)); if (*(int *)data) { /* make mode permanent */ mdcdefaultCAR[unit] &= ~(1<<(linenum)); } /* * See if signals necessary for modem connection are present * * dc7085 chip on PMAX only provides DSR * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -