📄 fas.c
字号:
goto sched; /* Determine how many chars to put into the transmitter register. */ if (fip->xmit_ring_cnt < num_to_output) num_to_output = fip->xmit_ring_cnt; /* no characters available ? */ if (!num_to_output) goto sched; /* output characters */ fip->xmit_ring_cnt -= num_to_output; fas_ctl (fip, XMT_DATA_PORT);#if defined(FASI) fip->characters_transmitted += num_to_output;#endif /* FASI */ do { do { (void) outb (XMT_DATA_PORT.addr, *fip->xmit_ring_take_ptr); if (++fip->xmit_ring_take_ptr == &fip->xmit_buffer [XMIT_BUFF_SIZE]) break; } while (--num_to_output); if (!num_to_output) break; fip->xmit_ring_take_ptr = &fip->xmit_buffer [0]; } while (--num_to_output); /* signal that transmitter is busy now */ fip->device_flags.s |= DF_XMIT_BUSY; /* disable guard timeout */ if (fip->device_flags.i & DF_GUARD_TIMEOUT) { fip->device_flags.s &= ~DF_GUARD_TIMEOUT; fip->tty->t_state &= ~TIMEOUT; (void) untimeout (fip->timeout_idx); } /* schedule fas_xxfer () if there are more characters to transfer into the transmitter ring buffer */sched: if ((fip->xmit_ring_size > fip->xmit_ring_cnt) && (fip->tty->t_outq.c_cc || fip->tty->t_tbuf.c_count)) { event_sched (fip, EF_DO_XXFER); }}/* Asynchronous event handler. Scheduled by functions that can't do the processing themselves because of execution time restrictions.*/static voidfas_event (dummy)void *dummy;{ register struct fas_info *fip; register uint unit; int old_level; old_level = SPLINT (); unit = 0; fip = &fas_info [0]; /* loop through all fas_info structures */ for (;; fip++, unit++) { if (unit >= fas_physical_units) break; /* all structures done */ /* process only structures that actually need to be serviced */fastloop2: if (!fip->event_flags.i) { /* speed beats beauty */ fip++; if (++unit < fas_physical_units) goto fastloop2; break; } do { /* check the modem signals */ if (fip->event_flags.i & EF_DO_MPROC) { fip->event_flags.s &= ~EF_DO_MPROC; fas_mproc (fip); /* disable the device if there were too many modem status interrupts */ if (fip->msi_cnt > (MAX_MSI_CNT / HZ) * (EVENT_TIME * HZ / 1000)) { fip->device_flags.s &= ~(DF_DEVICE_CONFIGURED | DF_XMIT_BUSY | DF_XMIT_BREAK); fip->device_flags.s |= DF_XMIT_LOCKED; if (fip->device_flags.i & DF_GUARD_TIMEOUT) { fip->device_flags.s &= ~DF_GUARD_TIMEOUT; fip->tty->t_state &= ~TIMEOUT; (void) untimeout (fip->timeout_idx); (void) wakeup ((caddr_t) &(fip)-> device_flags.i); } fip->tty->t_state &= ~CARR_ON; (void) SPLWRK (); if (!(fip->cflag & CLOCAL) && (fip->tty->t_state & ISOPEN)) (void) signal (fip->tty->t_pgrp, SIGHUP); (void) ttyflush (fip->tty, FREAD | FWRITE); (void) printf ("\nWARNING: Excessive modem status interrupts on FAS unit %d (check the cabling).\n", fip - &fas_info [0]); (void) SPLINT (); } fip->msi_cnt = 0; } /* do the break interrupt */ if (fip->event_flags.i & EF_DO_BRKINT) { fip->event_flags.s &= ~EF_DO_BRKINT; if (fip->tty->t_state & ISOPEN) { (void) SPLWRK (); (*linesw [fip->tty->t_line].l_input) (fip->tty, L_BREAK); (void) SPLINT (); } } /* transfer characters to the UNIX input buffer */ if (fip->event_flags.i & EF_DO_RXFER) { fip->event_flags.s &= ~EF_DO_RXFER; if (!(fip->flow_flags.i & FF_RXFER_STOPPED)) { (void) SPLWRK (); fas_rxfer (fip); (void) SPLINT (); /* check input buffer high/low water marks */ fas_ihlw_check (fip); } } /* transfer characters to the output ring buffer */ if (fip->event_flags.i & EF_DO_XXFER) { fip->event_flags.s &= ~EF_DO_XXFER; (void) SPLWRK (); fas_xxfer (fip); (void) SPLINT (); fas_hdx_check (fip); /* output characters */ fas_xproc (fip); }#if defined (HAVE_VPIX) /* send pseudorupt to VP/ix */ if (fip->event_flags.i & EF_SIGNAL_VPIX) { fip->event_flags.s &= ~EF_SIGNAL_VPIX; if ((fip->iflag & DOSMODE) && fip->v86_proc) { (void) SPLWRK (); (void) v86setint (fip->v86_proc, fip->v86_intmask); (void) SPLINT (); } }#endif } while (fip->event_flags.i); /* allow pending tty interrupts */ (void) SPLWRK (); (void) SPLINT (); } event_scheduled = FALSE; /* check whether there have been new requests in the mean time */ for (unit = 0, fip = &fas_info [0]; unit < fas_physical_units; fip++, unit++) if (fip->event_flags.i) { /* there is at least one new request, so schedule the next event processing */ event_scheduled = TRUE; (void) timeout (fas_event, (void *) NULL, (EVENT_TIME) * (HZ) / 1000); break; }#if defined(FASI) (void)wakeup((caddr_t)&fip->device_flags.i);#endif /* FASI */ (void) splx (old_level);}#if defined (HAVE_VPIX)/* Send port status register to VP/ix */static intfas_vpix_sr (fip, token, status)register struct fas_info *fip;uint token;uint status;{ if ((fip->recv_ring_cnt <= RECV_BUFF_SIZE - 3) && ((fip->tty->t_state & (ISOPEN | CARR_ON)) == (ISOPEN | CARR_ON))) { /* sent the character sequence 0xff, <token>, <status> to VP/ix */ fip->recv_ring_cnt += 3; *fip->recv_ring_put_ptr = 0xff; if (++fip->recv_ring_put_ptr == &fip->recv_buffer [RECV_BUFF_SIZE]) fip->recv_ring_put_ptr = &fip->recv_buffer [0]; *fip->recv_ring_put_ptr = token; if (++fip->recv_ring_put_ptr == &fip->recv_buffer [RECV_BUFF_SIZE]) fip->recv_ring_put_ptr = &fip->recv_buffer [0]; *fip->recv_ring_put_ptr = status; if (++fip->recv_ring_put_ptr == &fip->recv_buffer [RECV_BUFF_SIZE]) fip->recv_ring_put_ptr = &fip->recv_buffer [0]; return (TRUE); } return (FALSE);}#endif/* Receiver ring buffer -> UNIX buffer transfer function. */static voidfas_rxfer (fip)register struct fas_info *fip;{ register struct tty *ttyp; register int num_to_xfer; int num_save; int old_level; ttyp = fip->tty; for (;;) { if (!fip->recv_ring_cnt || !ttyp->t_rbuf.c_ptr) break; /* no characters to transfer */ /* determine how many characters to transfer */#if defined (HAVE_VPIX) num_to_xfer = ((fip->iflag & DOSMODE) ? MAX_VPIX_FILL : MAX_UNIX_FILL) - ttyp->t_rawq.c_cc;#else num_to_xfer = MAX_UNIX_FILL - ttyp->t_rawq.c_cc;#endif if (num_to_xfer < MIN_READ_CHUNK) break; /* input buffer full */#if defined (HAVE_VPIX) /* wakeup VP/ix */ if ((fip->iflag & DOSMODE) && !ttyp->t_rawq.c_cc) event_sched (fip, EF_SIGNAL_VPIX);#endif /* determine how many characters are in one contigous block */ if (fip->recv_ring_cnt < num_to_xfer) num_to_xfer = fip->recv_ring_cnt; if (&fip->recv_buffer [RECV_BUFF_SIZE] - fip->recv_ring_take_ptr < num_to_xfer) num_to_xfer = &fip->recv_buffer [RECV_BUFF_SIZE] - fip->recv_ring_take_ptr; if (ttyp->t_rbuf.c_count < num_to_xfer) num_to_xfer = ttyp->t_rbuf.c_count; num_save = num_to_xfer; ttyp->t_rbuf.c_count -= num_to_xfer; /* do the transfer */ do { *ttyp->t_rbuf.c_ptr = *fip->recv_ring_take_ptr; ttyp->t_rbuf.c_ptr++; fip->recv_ring_take_ptr++; } while (--num_to_xfer); if (fip->recv_ring_take_ptr == &fip->recv_buffer [RECV_BUFF_SIZE]) fip->recv_ring_take_ptr = &fip->recv_buffer [0]; intr_disable (); fip->recv_ring_cnt -= num_save; intr_restore (); ttyp->t_rbuf.c_ptr -= ttyp->t_rbuf.c_size - ttyp->t_rbuf.c_count; (*linesw [ttyp->t_line].l_input) (ttyp, L_BUF); }}/* UNIX buffer -> transmitter ring buffer transfer function. */static voidfas_xxfer (fip)register struct fas_info *fip;{ register struct tty *ttyp; register int num_to_xfer; int num_save; int old_level; ttyp = fip->tty; for (;;) { /* Check if tbuf is empty. If it is empty, reset buffer pointer and counter and get the next chunk of output characters. */ if (!ttyp->t_tbuf.c_ptr || !ttyp->t_tbuf.c_count) { if (ttyp->t_tbuf.c_ptr) ttyp->t_tbuf.c_ptr -= ttyp->t_tbuf.c_size; if (!((*linesw [ttyp->t_line].l_output) (ttyp) & CPRES)) break; } /* set the maximum character limit */ num_to_xfer = fip->xmit_ring_size - fip->xmit_ring_cnt; /* Return if transmitter ring buffer is full. */ if (num_to_xfer < 1) break; /* Determine how many chars to transfer this time. */ if (&fip->xmit_buffer [XMIT_BUFF_SIZE] - fip->xmit_ring_put_ptr < num_to_xfer) num_to_xfer = &fip->xmit_buffer [XMIT_BUFF_SIZE] - fip->xmit_ring_put_ptr; if (ttyp->t_tbuf.c_count < num_to_xfer) num_to_xfer = ttyp->t_tbuf.c_count; num_save = num_to_xfer; ttyp->t_tbuf.c_count -= num_to_xfer; ttyp->t_state |= BUSY; /* do the transfer */ do { *fip->xmit_ring_put_ptr = *ttyp->t_tbuf.c_ptr; ttyp->t_tbuf.c_ptr++; fip->xmit_ring_put_ptr++; } while (--num_to_xfer); if (fip->xmit_ring_put_ptr == &fip->xmit_buffer [XMIT_BUFF_SIZE]) fip->xmit_ring_put_ptr = &fip->xmit_buffer [0]; intr_disable (); fip->xmit_ring_cnt += num_save; intr_restore (); }}/* Input buffer high/low water mark check. */static voidfas_ihlw_check (fip)register struct fas_info *fip;{ REGVAR; if (fip->flow_flags.i & FF_HWI_STOPPED) { /* If input buffer level has dropped below the low water mark and input was stopped by hardware handshake, restart input. */ if (fip->recv_ring_cnt < HW_LOW_WATER) { fip->mcr |= fip->flow.m.ic; fas_first_outb (fip, MDM_CTL_PORT, fip->mcr); fip->flow_flags.s &= ~FF_HWI_STOPPED; } } else { /* If input buffer level has risen above the high water mark and input is not yet stopped, stop input by hardware handshake. */ if ((fip->flow_flags.i & FF_HWI_HANDSHAKE) && (fip->recv_ring_cnt > HW_HIGH_WATER)) { fip->mcr &= ~fip->flow.m.ic; fas_first_outb (fip, MDM_CTL_PORT, fip->mcr); fip->flow_flags.s |= FF_HWI_STOPPED;#if defined(FASI) fip->rcvr_hw_flow_count++; (void)wakeup((caddr_t)&fip->device_flags.i);#endif /* FASI */ } } if (fip->flow_flags.i & FF_SWI_STOPPED) { /* If input buffer level has dropped below the low water mark and input was stopped by XOFF, send XON to restart input. */ if (!(fip->iflag & IXOFF) || (fip->recv_ring_cnt < SW_LOW_WATER)) { fip->flow_flags.s &= ~FF_SWI_STOPPED; fip->flow_flags.s ^= FF_SW_FC_REQ; if (fip->flow_flags.i & FF_SW_FC_REQ) { fip->tty->t_state |= TTXON; fas_xproc (fip); } else fip->tty->t_state &= ~TTXOFF; } } else { /* If input buffer level has risen above the high water mark and input is not yet stopped, send XOFF to stop input. */ if ((fip->iflag & IXOFF) && (fip->recv_ring_cnt > SW_HIGH_WATER)) { fip->flow_flags.s |= FF_SWI_STOPPED; fip->flow_flags.s ^= FF_SW_FC_REQ; if (fip->flow_flags.i & FF_SW_FC_REQ) { fip->tty->t_state |= TTXOFF; fas_xproc (fip);#if defined(FASI) fip->rcvr_sw_flow_count++; (void)wakeup((caddr_t)&fip->device_flags.i);#endif /* FASI */ } else fip->tty->t_state &= ~TTXON; } }}/* Half-duplex hardware flow control check. */static voidfas_hdx_check (fip)register struct fas_info *fip;{ REGVAR; /* don't interfere with hardware input handshake */ if (fip->flow_flags.i & FF_HWI_HANDSHAKE) return;#if defined (HAVE_VPIX) /* don't touch the mcr if we are in dos mode and hdx hardware handshake is disabled (dos handles the handshake line(s) on its own in this mode) */ if ((fip->iflag & DOSMODE) && !(fip->flow_flags.i & FF_HDX_HANDSHAKE)) return;#endif if (fip->flow_flags.i & FF_HDX_STARTED) { /* If output buffer is empty signal the connected device that all output is done. */ if ((fip->flow_flags.i & FF_HDX_HANDSHAKE) && !(fip->tty->t_state & BUSY)) { fip->mcr &= ~fip->flow.m.hc; fas_first_outb (fip, MDM_CTL_PORT, fip->mcr); fip->flow_flags.s &= ~FF_HDX_STARTED; } } else { /* If the output ring buffer contains characters and was previously empty signal the connected device that output is resumed. */ if (!(fip->flow_flags.i & FF_HDX_HANDSHAKE) || (fip->tty->t_state & BUSY)) { fip->mcr |= fip->flow.m.hc; fas_first_outb (fip, MDM_CTL_PORT, fip->mcr); fip->flow_flags.s |= FF_HDX_STARTED; } }}/* Handle hangup after last close */static voidfas_hangup (fip)register struct fas_info *fip;{ int old_level; REGVAR; old_level = SPLINT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -