📄 fas.c
字号:
fip->characters_transmitted = 0; fip->modem_status_events = 0; fip->overrun_errors = 0; fip->framing_errors = 0; fip->parity_errors = 0; fip->rings_detected = 0; fip->breaks_detected = 0; fip->xmtr_hw_flow_count = 0; fip->xmtr_sw_flow_count = 0; fip->rcvr_hw_flow_count = 0; fip->rcvr_sw_flow_count = 0; (void)splx(old_level); break;#endif /* FASI */#if defined (HAVE_VPIX) case AIOCINTTYPE: /* set pseudorupt type */ switch (arg3.iarg) { case V86VI_KBD: case V86VI_SERIAL0: case V86VI_SERIAL1: intr_disable (); fip->v86_intmask = arg3.iarg; intr_restore (); break; default: intr_disable (); fip->v86_intmask = V86VI_SERIAL0; intr_restore (); break; } break; case AIOCDOSMODE: /* enable dos mode */ if (!(fip->iflag & DOSMODE)) { old_level = SPLINT (); fip->v86_proc = u.u_procp->p_v86; if (!(fip->v86_intmask)) fip->v86_intmask = V86VI_SERIAL0; ttyp->t_iflag |= DOSMODE; if (fip->v86_intmask != V86VI_KBD) ttyp->t_cflag |= CLOCAL; fas_param (fip, SOFT_INIT); (void) splx (old_level); } u.u_r.r_reg.r_val1 = 0; break; case AIOCNONDOSMODE: /* disable dos mode */ if (fip->iflag & DOSMODE) { old_level = SPLINT (); fip->v86_proc = (v86_t *) NULL; fip->v86_intmask = 0; ttyp->t_iflag &= ~DOSMODE; if (fip->flow_flags.i & FF_RXFER_STOPPED) { fip->flow_flags.s &= ~FF_RXFER_STOPPED; /* schedule character transfer to UNIX buffer */ if (fip->recv_ring_cnt) event_sched (fip, EF_DO_RXFER); } fip->lcr &= ~LC_SET_BREAK_LEVEL; fas_param (fip, HARD_INIT); (void) splx (old_level); } u.u_r.r_reg.r_val1 = 0; break; case AIOCSERIALOUT: /* setup port registers for dos */ if ((fip->iflag & DOSMODE) && fip->v86_proc) { /* wait until output is done */ old_level = SPLINT (); while (ttyp->t_outq.c_cc || (ttyp->t_state & (BUSY | TIMEOUT))) { ttyp->t_state |= TTIOW; (void) sleep ((caddr_t) &ttyp->t_oflag, TTOPRI); } /* block transmitter and wait until it is empty */ fip->device_flags.s |= DF_XMIT_LOCKED; while (fip->device_flags.i & (DF_XMIT_BUSY | DF_XMIT_BREAK | DF_GUARD_TIMEOUT)) (void) sleep ((caddr_t) &fip-> device_flags.i, PZERO - 1); (void) splx (old_level); /* get port write command */ v86_cmd = fubyte (arg3.cparg); /* set divisor lsb requested */ if (v86_cmd & SIO_MASK(SO_DIVLLSB)) { v86_data = fubyte (arg3.cparg + SO_DIVLLSB); intr_disable (); fas_first_outb (fip, LINE_CTL_PORT, fip->lcr | LC_ENABLE_DIVISOR); fas_outb (fip, DIVISOR_LSB_PORT, v86_data); fas_outb (fip, LINE_CTL_PORT, fip->lcr & ~LC_ENABLE_DIVISOR); intr_restore (); } /* set divisor msb requested */ if (v86_cmd & SIO_MASK(SO_DIVLMSB)) { v86_data = fubyte (arg3.cparg + SO_DIVLMSB); intr_disable (); fas_first_outb (fip, LINE_CTL_PORT, fip->lcr | LC_ENABLE_DIVISOR); fas_outb (fip, DIVISOR_MSB_PORT, v86_data); fas_outb (fip, LINE_CTL_PORT, fip->lcr & ~LC_ENABLE_DIVISOR); intr_restore (); } /* set lcr requested */ if (v86_cmd & SIO_MASK(SO_LCR)) { v86_data = fubyte (arg3.cparg + SO_LCR); intr_disable (); fip->lcr = v86_data & ~LC_ENABLE_DIVISOR; fas_first_outb (fip, LINE_CTL_PORT, fip->lcr); intr_restore (); } /* set mcr requested */ if (v86_cmd & SIO_MASK(SO_MCR)) { v86_data = fubyte (arg3.cparg + SO_MCR); old_level = SPLINT (); /* virtual dtr processing */ if (v86_data & MC_SET_DTR) { fip->device_flags.s |= DF_MODEM_ENABLED; fip->mcr |= (fip->o_state & OS_WAIT_OPEN) ? fip->modem.m.ei : fip->modem.m.eo; } else { fip->device_flags.s &= ~DF_MODEM_ENABLED; fip->mcr &= (fip->o_state & OS_WAIT_OPEN) ? ~fip->modem.m.ei : ~fip->modem.m.eo; } /* virtual rts processing */ if (fip->flow_flags.i & FF_HWI_HANDSHAKE) { if (v86_data & MC_SET_RTS) { if (fip->flow_flags.i & FF_RXFER_STOPPED) { fip->flow_flags.s &= ~FF_RXFER_STOPPED; /* schedule character transfer to UNIX buffer */ if (fip->recv_ring_cnt) event_sched (fip, EF_DO_RXFER); } } else fip->flow_flags.s |= FF_RXFER_STOPPED; } else if (!(fip->flow_flags.i & FF_HDX_HANDSHAKE)) { if (v86_data & MC_SET_RTS) { fip->flow_flags.s |= FF_HDX_STARTED; fip->mcr |= fip->flow.m.hc; } else { fip->flow_flags.s &= ~FF_HDX_STARTED; fip->mcr &= ~fip->flow.m.hc; } } fas_first_outb (fip, MDM_CTL_PORT, fip->mcr); (void) splx (old_level); } old_level = SPLINT (); /* enable transmitter and restart output */ fip->device_flags.s &= ~DF_XMIT_LOCKED; fas_xproc (fip); (void) splx (old_level); } break; case AIOCSERIALIN: /* read port registers for dos */ if ((fip->iflag & DOSMODE) && fip->v86_proc) { v86_cmd = fubyte (arg3.cparg); if (v86_cmd & SIO_MASK(SI_MSR)) { (void) subyte (arg3.cparg + SI_MSR, ((fip->flow_flags.i & FF_HWO_HANDSHAKE) ? fip->msr | fip->flow.m.oc | fip->flow.m.oe : fip->msr) & MS_ANY_PRESENT); } } break; case AIOCSETSS: /* set start/stop characters */ intr_disable (); *((short *) (&fip->v86_ss)) = arg3.iarg; intr_restore (); break; case AIOCINFO: /* show what type of device we are */ u.u_r.r_reg.r_val1 = ('a' << 8) | (uint) ((unchar) dev); break;#endif default: /* default ioctl processing */ /* if it is a TCSETA* command, call fas_param () */ if (ttiocom (ttyp, cmd, arg3, arg4)) { old_level = SPLINT (); fas_param (fip, SOFT_INIT); (void) splx (old_level); } break; } return (0);}/* pass fas commands to the fas multi-function procedure */static intfas_proc (ttyp, arg2)struct tty *ttyp;int arg2;{ register uint physical_unit; int old_level; physical_unit = ttyp - &fas_tty [0]; if (physical_unit >= fas_physical_units) physical_unit -= fas_physical_units; old_level = SPLINT (); fas_cmd (fas_info_ptr [physical_unit], ttyp, arg2); (void) splx (old_level); return (0);}/* set up a port according to the given termio structure */static voidfas_param (fip, init_type)register struct fas_info *fip;int init_type;{ register uint cflag; uint divisor; int xmit_ring_size; REGVAR; cflag = fip->tty->t_cflag;#if defined (HAVE_VPIX) /* we don't set port registers if we are in dos mode */ if (fip->tty->t_iflag & DOSMODE) goto setflags2;#endif /* if soft init mode: don't set port registers if cflag didn't change */ if ((init_type == SOFT_INIT) && !((cflag ^ fip->cflag) & (CBAUD | CSIZE | CSTOPB | PARENB | PARODD))) goto setflags; /* lock transmitter and wait until it is empty */ fip->device_flags.s |= DF_XMIT_LOCKED; while (fip->device_flags.i & (DF_XMIT_BUSY | DF_XMIT_BREAK | DF_GUARD_TIMEOUT)) (void) sleep ((caddr_t) &fip->device_flags.i, PZERO - 1); /* hangup line if it is baud rate 0, else enable line */ if ((cflag & CBAUD) == B0) { fip->mcr &= (fip->o_state & OS_WAIT_OPEN) ? ~fip->modem.m.ei : ~fip->modem.m.eo; fas_first_outb (fip, MDM_CTL_PORT, fip->mcr); fip->device_flags.s &= ~DF_MODEM_ENABLED; } else { if (!(fip->device_flags.i & DF_MODEM_ENABLED)) { fip->mcr |= (fip->o_state & OS_WAIT_OPEN) ? fip->modem.m.ei : fip->modem.m.eo; fas_first_outb (fip, MDM_CTL_PORT, fip->mcr); fip->device_flags.s |= DF_MODEM_ENABLED; } } /* don't change break flag */ fip->lcr &= LC_SET_BREAK_LEVEL; /* set character size */ switch (cflag & CSIZE) { case CS5: fip->lcr |= LC_WORDLEN_5; break; case CS6: fip->lcr |= LC_WORDLEN_6; break; case CS7: fip->lcr |= LC_WORDLEN_7; break; default: fip->lcr |= LC_WORDLEN_8; break; } /* set # of stop bits */ if (cflag & CSTOPB) fip->lcr |= LC_STOPBITS_LONG; /* set parity */ if (cflag & PARENB) { fip->lcr |= LC_ENABLE_PARITY; if (!(cflag & PARODD)) fip->lcr |= LC_EVEN_PARITY; } /* set divisor registers only if baud rate is valid */ if ((cflag & CBAUD) != B0) { /* get counter divisor for selected baud rate */ divisor = fas_speeds [cflag & CBAUD]; /* set LCR and baud rate */ fas_first_outb (fip, LINE_CTL_PORT, fip->lcr | LC_ENABLE_DIVISOR); fas_outb (fip, DIVISOR_LSB_PORT, divisor); fas_outb (fip, DIVISOR_MSB_PORT, divisor >> 8); } fas_first_outb (fip, LINE_CTL_PORT, fip->lcr);setflags: /* check dynamic xmit ring buffer size against boundaries, modify it if necessary and update the fas_info structure */ if ((cflag & CBAUD) != B0) { xmit_ring_size = fas_xbuf_size [cflag & CBAUD] - tthiwat [cflag & CBAUD]; if (xmit_ring_size < MAX_OUTPUT_FIFO_SIZE * 2) {setflags2: xmit_ring_size = MAX_OUTPUT_FIFO_SIZE * 2; } if (xmit_ring_size > XMIT_BUFF_SIZE) xmit_ring_size = XMIT_BUFF_SIZE; fip->xmit_ring_size = xmit_ring_size; } /* setup character time for B0 mode */ fas_ctimes [B0] = fas_ctimes [cflag & CBAUD]; /* disable modem control signals if required by open mode */ if (fip->o_state & OS_CLOCAL) cflag |= CLOCAL; /* Select hardware handshake depending on the minor device number and the CTSFLOW and RTSFLOW flags (if they are available). */ fip->flow_flags.s &= ~(FF_HWO_HANDSHAKE | FF_HWI_HANDSHAKE | FF_HDX_HANDSHAKE); if (fip->o_state & (OS_HWO_HANDSHAKE | OS_HWI_HANDSHAKE | OS_HDX_HANDSHAKE)) { if (fip->o_state & OS_HWO_HANDSHAKE) fip->flow_flags.s |= FF_HWO_HANDSHAKE; if (fip->o_state & OS_HWI_HANDSHAKE) fip->flow_flags.s |= FF_HWI_HANDSHAKE; if (fip->o_state & OS_HDX_HANDSHAKE) fip->flow_flags.s |= FF_HDX_HANDSHAKE; } else {#if defined (CTSFLOW) /* SYSV 3.2 Xenix compatibility */ if ((cflag & (CTSFLOW | CLOCAL)) == CTSFLOW) fip->flow_flags.s |= FF_HWO_HANDSHAKE;#endif#if defined (RTSFLOW) /* SYSV 3.2 Xenix compatibility */ if ((cflag & (RTSFLOW | CLOCAL)) == RTSFLOW) fip->flow_flags.s |= FF_HDX_HANDSHAKE;#endif } /* Fake the carrier detect state flag if CLOCAL mode or if requested by open mode. */ if (!(~fip->msr & fip->modem.m.ca) || (fip->o_state & OS_FAKE_CARR_ON) || (cflag & CLOCAL)) fip->tty->t_state |= CARR_ON; else fip->tty->t_state &= ~CARR_ON;#if defined (XCLUDE) /* SYSV 3.2 Xenix compatibility */ /* Permit exclusive use of this device. */ if (cflag & XCLUDE) fip->o_state |= OS_EXCLUSIVE_OPEN_2; else fip->o_state &= ~OS_EXCLUSIVE_OPEN_2;#endif fip->cflag = cflag; fip->iflag = fip->tty->t_iflag; /* enable transmitter */ fip->device_flags.s &= ~DF_XMIT_LOCKED; /* setup handshake flags */ fas_hdx_check (fip); fas_ihlw_check (fip); fas_fproc (fip, fip->new_msr); /* restart output */ fas_xproc (fip);}/* Main fas interrupt handler. Actual character processing is splitted into sub-functions.*/intfasintr (vect)int vect;{ register struct fas_info *fip; register uint status; struct fas_info *old_fip; int done, drop_mode; uint port, old_recv_count; REGVAR;#if defined(FASI) fasiintr_entries++;#endif /* FASI */ drop_mode = FALSE; /* The 8259 interrupt controller is set up for edge trigger. Therefor, we must loop until we make a complete pass without getting any UARTs that are interrupting. */ do { done = TRUE; fip = fas_first_int_user [vect]; /* loop through all users of this interrupt vector */ for (;; fip = fip->next_int_user) { if (!fip) break; /* all users done */ /* process only ports that we expect ints from and that actually need to be serviced */fastloop: if (fas_first_inb (fip, INT_ID_PORT) & II_NO_INTS_PENDING) { /* restore the normal receiver trigger level */ if (fip->device_flags.i & DF_NS16550A_DROP_MODE) { fip->device_flags.s &= ~DF_NS16550A_DROP_MODE; fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_SETUP_CMD); } /* speed beats beauty */ fip = fip->next_int_user; if (fip) goto fastloop; break; } /* restore the normal receiver trigger level */ if (fip->device_flags.i & DF_NS16550A_DROP_MODE) { fip->device_flags.s &= ~DF_NS16550A_DROP_MODE; fas_outb (fip, NS_FIFO_CTL_PORT, NS_FIFO_SETUP_CMD); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -