📄 mdc.c
字号:
* look for modem transitions in an already * established connection. * */ if (tp->t_state & TS_CARR_ON) { if (dcscan_modem & DC_CD) { /* * CD has come up again. * Stop timeout from occurring if set. * If interval is more than 2 secs then * drop DTR. */ if ((mdcmodem[unit] & MODEM_CD) == 0) { untimeout(mdc_cd_drop, tp); if (mdc_cd_down(tp)) { /* drop connection */ mdc_tty_drop(tp); } mdcmodem[unit] |= MODEM_CD; } } else { /* * Carrier must be down for greater than * 2 secs before closing down the line. */ if (mdcmodem[unit] & MODEM_CD) { /* only start timer once */ mdcmodem[unit] &= ~MODEM_CD; /* * Record present time so that if carrier * comes up after 2 secs, the line will drop */ mdctimestamp[unit] = time; timeout(mdc_cd_drop, tp, hz * 2); } } /* CTS flow control check */ if (!(dcscan_modem & DC_CTS)) { /* * Only allow transmission when CTS is set. */ tp->t_state |= TS_TTSTOP; mdcmodem[unit] &= ~MODEM_CTS;#ifdef DEBUG if (mdcdebug) cprintf("mdcscan: CTS stop, tp=%x,unit=%d\n",tp,unit);#endif DEBUG mdcstop(tp, 0); } else if (!(mdcmodem[unit] & MODEM_CTS)) { /* * Restart transmission upon return of CTS. */ tp->t_state &= ~TS_TTSTOP; mdcmodem[unit] |= MODEM_CTS;#ifdef DEBUG if (mdcdebug) cprintf("mdcscan: CTS start, tp=%x,unit=%d\n",tp,unit);#endif DEBUG mdcstart(tp); } } /* * See if a modem transition has occured. If we are * waiting for this signal, cause action to be take via * mdc_start_tty. */ if (((dcscan_modem & DC_XMIT) == DC_XMIT) && (!(mdcmodem[unit] & MODEM_DSR_START)) && (!(tp->t_state & TS_CARR_ON))) {#ifdef DEBUG if (mdcdebug) cprintf("mdcscan: MODEM transition: dcscan_modem = %x, mdcscan_previous = %x\n", dcscan_modem, mdcscan_previous[unit]);#endif DEBUG mdc_start_tty(tp); } } /* * Save a copy of the modem status for comparison during the * next iteration. */ mdcscan_previous[unit] = dcscan_modem; } } } /* * Schedule the next scanner iteration. Scan at a much higher frequency * when a modem line is active. */ if (mdcmodem_active) { timeout(mdcscan, (caddr_t)0, hz/40); } else { timeout(mdcscan, (caddr_t)0, hz); }}/* * Write a character to the console. */mdcputc(c) register int c;{ mdc_putc(c); if ( c == '\n') mdc_putc('\r');}/* * This routine outputs one character to the console. * * Called for system startup messages. Also used for kernel printf's. * Not called from user level; ie a console getty does not use this. * * Characters must be printed without disturbing * output in progress on other lines! * This routines works with the SLU in interrupt or * non-interrupt mode of operation. BULL! * Characters are output as follows: * spl5, remember if console line active. * set console line tcr bit. * wait for TRDY on console line (save status if wrong line). * start output of character. * wait for output complete. * if any lines were active, set their tcr bits, * otherwise clear the xmit ready interrupt. * */mdc_putc(c) int c;{ register volatile struct mdz_reg *dcaddr; register int s; register u_short oldtcr; register int ln, linenum, timo; dcaddr = mdz_regs[CONSOLE_UNIT]; linenum = CONSOLE_LINE; c &= CHAR_MASK; /* Strip character to 8-bits */ s = splhigh(); /* * Get a copy of the present transmit enable and DTR, RTS. * Next set transmit enable for this line. */ oldtcr = (dcaddr->dctcr & (1<<linenum)); dcaddr->dctcr |= (1<<linenum); while (1) { /* * Wait for the chip to be ready. Impose a timer so that the * system does not hang if this bit fails to clear due to a * hardware error. If the bit fails to clear then don't even * try to send out this character. */ timo = 1000000; while ((dcaddr->dccsr&DC_TRDY) == 0) { if(--timo == 0) break; } if(timo == 0) break; /* * The DC chip has stoppped on a line that is ready to be * loaded with another transmit character. If the line ready * for transmission is not the console line then clear * transmitter enable for the non-console line so that we * won't be bothered by that line again until the completion of * this putc operation. */ ln = (dcaddr->dccsr>>8) & LINEMASK; if (ln != linenum) { oldtcr |= (1 << ln); dcaddr->dctcr &= ~(1 << ln); continue; } /* * Output the character by writing into the transmitter buffer. * Provide a delay to allow time for the char to go out. The * registers should not be read for 1.4 microseconds. * Should this routine check to see if the console line is * presently asserting a break? */ dcaddr->dctbuf = c; DELAY(5); /* * Wait for the character to be transmitted. */ while (1) { timo = 1000000; while ((dcaddr->dccsr&DC_TRDY) == 0) { if(--timo == 0) break; } if(timo == 0) break; ln = (dcaddr->dccsr>>8) & LINEMASK; if (ln != linenum) { oldtcr |= (1 << ln); dcaddr->dctcr &= ~(1 << ln); continue; } break; } break; } /* * Clear transmit enable for this line. If this bit was set when this * routine was originaly entered it will then be restored. */ dcaddr->dctcr &= ~(1<<linenum); if (oldtcr != 0) dcaddr->dctcr |= oldtcr; wbflush(); splx(s);}/* * This routine operates on the following assumptions: * 1. putc must have happened first, so SLU already inited. * 2. getc will happed before slu reveive interrupt enabled so * don't need to worry about int_req or int_msk registers. */mdcgetc(){ register volatile struct mdz_reg *dcaddr; register u_short c; register int linenum; dcaddr = mdz_regs[CONSOLE_UNIT]; linenum = CONSOLE_LINE; while (1) { /* * This will hang the system if RDONE never gets set! */ while ((dcaddr->dccsr&DC_RDONE) == 0) ; c = dcaddr->dcrbuf; if(((c >> 8) & LINEMASK) != linenum) /* wrong line mumber */ continue; /* * Toss the character away if there is an error. I wonder if * throwing away parity errors is a bit harsh. */ if(c & (DC_DO|DC_FE|DC_PE)) continue; break; } return(c & CHAR_MASK);}/* * Modem Control Routines *//* * * Function: * * mdc_cd_drop * * Functional description: * * Determine if carrier has dropped. If so call mdc_tty_drop to terminate * the connection. * * Arguements: * * register struct tty *tp - terminal pointer ( for terminal attributes ) * * Return value: * * none * */mdc_cd_drop(tp)register struct tty *tp;{ register volatile struct mdz_reg *dcaddr; register int unit; unit = minor(tp->t_dev) >> LINEBITS; dcaddr = mdz_regs[unit]; if ((tp->t_state & TS_CARR_ON) && (!(dcaddr->dcmsr & DC_CD))) {#ifdef DEBUG if (mdcdebug) cprintf("mdc_cd_drop: no CD, tp = %x, unit = %d\n", tp, unit);#endif DEBUG mdc_tty_drop(tp); return; } mdcmodem[unit] |= MODEM_CD;#ifdef DEBUG if (mdcdebug) cprintf("mdc_cd_drop: CD is up, tp = %x, unit = %d\n", tp, unit);#endif DEBUG} /* * * Function: * * mdc_dsr_check * * Functional description: * * DSR must be asserted for a connection to be established. Here we * either start or terminate a connection on the basis of DSR. * * Arguements: * * register struct tty *tp - terminal pointer (for terminal attributes) * * Return value: * * none * */mdc_dsr_check(tp)register struct tty *tp;{ register volatile struct mdz_reg *dcaddr; register int unit; unit = minor(tp->t_dev) >> LINEBITS; dcaddr = mdz_regs[unit];# ifdef DEBUG if (mdcdebug) { cprintf("mdc_dsr_check0: tp=%x\n", tp); PRINT_SIGNALS(dcaddr); }# endif DEBUG if (mdcmodem[unit] & MODEM_DSR_START) { mdcmodem[unit] &= ~MODEM_DSR_START; if ((dcaddr->dcmsr & DC_XMIT) == DC_XMIT) { mdc_start_tty(tp); } return; } if ((tp->t_state&TS_CARR_ON)==0) mdc_tty_drop(tp);}/* * * Function: * * mdc_cd_down * * Functional description: * * Determine whether or not carrier has been down for > 2 sec. * * Arguements: * * register struct tty *tp - terminal pointer ( for terminal attributes ) * * Return value: * * 1 - if carrier was down for > 2 sec. * 0 - if carrier down <= 2 sec. * */mdc_cd_down(tp)register struct tty *tp;{ register int msecs, unit; unit = minor(tp->t_dev) >> LINEBITS; msecs = 1000000 * (time.tv_sec - mdctimestamp[unit].tv_sec) + (time.tv_usec - mdctimestamp[unit].tv_usec); if (msecs > 2000000){# ifdef DEBUG if (mdcdebug) cprintf("mdc_cd_down: msecs > 20000000\n");# endif DEBUG return(1); } else{# ifdef DEBUG if (mdcdebug) cprintf("mdc_cd_down: msecs < 20000000\n");# endif DEBUG return(0); }}/* * * Function: * * mdc_tty_drop * * Functional description: * * Terminate a connection. * * Arguements: * * register struct tty *tp - terminal pointer ( for terminal attributes ) * * Return value: * * none * */mdc_tty_drop(tp)struct tty *tp;{ register volatile struct mdz_reg *dcaddr; register int unit; register int minor_num; minor_num = minor(tp->t_dev); unit = minor_num >> LINEBITS; dcaddr = mdz_regs[unit]; mdcmodem_active &= ~(1 << minor_num); if (tp->t_flags & NOHANG) return;# ifdef DEBUG if (mdcdebug) cprintf("mdc_tty_drop: minor=%d\n",minor_num);# endif DEBUG /* * Notify any processes waiting to open this line. Useful in the * case of a false start. */ mdcmodem[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); dcaddr->dctcr &= ~(DC_RDTR | DC_RRTS | DC_RSS);}/* * * Function: * * mdc_start_tty * * Functional description: * * Establish a connection. * * Arguements: * * register struct tty *tp - terminal pointer ( for terminal attributes ) * * Return value: * * none * */mdc_start_tty(tp) register struct tty *tp;{ register int unit; register int linenum; register int minor_num; minor_num = minor(tp->t_dev); unit = minor_num >> LINEBITS; linenum = minor_num & LINEMASK; /* * Setting this variable will cause the scanner to be called with * increased frequency. As a sanity check, only set the bit if this * is a modem line to prevent the possible case where the scanner could * be increased for a no modem line. */ if ((unit != NOMODEM_UNIT) && (linenum == MODEM_LINE)) { mdcmodem_active |= (1 << minor_num); } tp->t_state &= ~(TS_ONDELAY); tp->t_state |= TS_CARR_ON;# ifdef DEBUG if (mdcdebug) cprintf("mdc_start_tty: tp=%x\n", tp);# endif DEBUG if (mdcmodem[unit] & MODEM_DSR) untimeout(mdc_dsr_check, tp); mdcmodem[unit] |= MODEM_CD|MODEM_CTS|MODEM_DSR; mdctimestamp[unit].tv_sec = mdctimestamp[unit].tv_usec = 0; wakeup((caddr_t)&tp->t_rawq);}/* * Return 1 if the baud rate is supported, 0 if not supported. * * This scheme could be improved for the case of the console line which * really can't be set to any arbirtrary baud rate. */mdcbaudrate(speed)int speed;{ return(mdc_speeds[speed & CBAUD].baud_support);}/* * Time up for process to set a break on a transmission line. */void mdcsetbreak(tp)register struct tty *tp;{ wakeup((caddr_t)&tp->t_dev);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -