Newsgroups: comp.sources.unix From: fas@geminix.in-berlin.de (FAS Support Account) Subject: v27i203: fas-2.12.0 - asynch serial driver for System V, Part06/08 References: <1.759531570.7983@gw.home.vix.com> Sender: unix-sources-moderator@gw.home.vix.com Approved: vixie@gw.home.vix.com Submitted-By: fas@geminix.in-berlin.de (FAS Support Account) Posting-Number: Volume 27, Issue 203 Archive-Name: fas-2.12.0/part06 #!/bin/sh # this is fas212pl0.06 (part 6 of a multipart archive) # do not concatenate these parts, unpack them in order with /bin/sh # file fas.c continued # if test ! -r _shar_seq_.tmp; then echo 'Please unpack part 1 first!' exit 1 fi (read Scheck if test "$Scheck" != 6; then echo Please unpack part "$Scheck" next! exit 1 else exit 0 fi ) < _shar_seq_.tmp || exit 1 if test ! -f _shar_wnt_.tmp; then echo 'x - still skipping fas.c' else echo 'x - continuing file fas.c' sed 's/^X//' << 'SHAR_EOF' >> 'fas.c' && X || (charac == fip->stop_char)) X continue; X } Xvalid_char: X if ((charac == 0xff) && (fip->iflag & PARMRK)) X { X if (fip->recv_ring_cnt < RECV_BUFF_SIZE - 1) X { X fip->recv_ring_cnt += 2; X PUT_RECV_BUFFER (fip, ring_ptr, 0xff); X PUT_RECV_BUFFER (fip, ring_ptr, 0xff); X } X } X else X { X if (fip->recv_ring_cnt < RECV_BUFF_SIZE) X { X ++fip->recv_ring_cnt; X PUT_RECV_BUFFER (fip, ring_ptr, charac); X } X } X } X } while ((line_status = FAS_INB (fip, LINE_STATUS_PORT)) X & LS_RCV_AVAIL); X X fip->recv_ring_put_ptr = ring_ptr; X X /* schedule character transfer to CLIST buffer */ X if (!(fip->event_flags & EF_DO_RXFER) X && !(fip->flow_flags & FF_RXFER_STOPPED)) X { X EVENT_SCHED (fip, EF_DO_RXFER); X } X X /* check input buffer high water marks */ X if ((fip->recv_ring_cnt > RECV_HW_HIGH_WATER) X && (fip->flow_flags & (FF_HWI_HANDSHAKE | FF_HWI_STARTED)) X == (FF_HWI_HANDSHAKE | FF_HWI_STARTED)) X { X FAS_OUTB (fip, MDM_CTL_PORT, MCR &= ~fip->flow.m.ic); X fip->flow_flags &= ~FF_HWI_STARTED; X } X if ((fip->recv_ring_cnt > RECV_SW_HIGH_WATER) X && (fip->iflag & IXOFF) X && !(fip->flow_flags & FF_SWI_STOPPED)) X fas_send_xoff (fip); X X return (line_status); X} X X/* Output characters to the transmitter register. X (called at SPLINT) X*/ XSTATIC void Xfas_xproc (fip) Xregister struct fas_internals *fip REG_SI; X{ X /* proceed only if transmitter is available */ X if (fip->device_flags & (DF_XMIT_BUSY | DF_XMIT_BREAK X | DF_XMIT_LOCKED)) X goto sched; X if (fip->flow_flags & (FF_HWO_STOPPED | FF_CARR_STOPPED)) X goto sched; X X { X register unchar *ring_ptr REG_DI; X register uint num_to_output REG_BX; X X num_to_output = fip->xmit_fifo_size; X X /* handle XON/XOFF input flow control requests */ X if (fip->flow_flags & FF_SW_FC_REQ) X { X FAS_FIRST_OUTB (fip, XMT_DATA_PORT, X (fip->flow_flags & FF_SWI_STOPPED) X ? fip->stop_char X : fip->start_char); X --num_to_output; X fip->device_flags |= DF_XMIT_BUSY; X fip->flow_flags &= ~FF_SW_FC_REQ; X fip->tty->t_state &= ~(TTXON | TTXOFF); X /* disable guard timeout */ X if (fip->device_flags & DF_GUARD_TIMEOUT) X { X fip->device_flags &= ~DF_GUARD_TIMEOUT; X (void) untimeout (fip->timeout_idx); X } X } X X /* bail out if output is suspended by XOFF */ X if (fip->flow_flags & FF_SWO_STOPPED) X goto sched; X X /* Determine how many chars to put into the transmitter X register. X */ X if (fip->xmit_ring_cnt < num_to_output) X num_to_output = fip->xmit_ring_cnt; X X /* no characters available ? */ X if (!num_to_output) X goto sched; X X /* output characters */ X fip->xmit_ring_cnt -= num_to_output; X X FAS_CTL (fip, XMT_DATA_PORT); X X ring_ptr = fip->xmit_ring_take_ptr; X X do X { X do X { X FAS_SAME_OUTB (fip, XMT_DATA_PORT, *ring_ptr); X if (++ring_ptr == XMIT_BUFF_END) X break; X } while (--num_to_output); X if (!num_to_output) X break; X ring_ptr = XMIT_BUFF_BEGIN; X } while (--num_to_output); X X fip->xmit_ring_take_ptr = ring_ptr; X X /* signal that transmitter is busy now */ X fip->device_flags |= DF_XMIT_BUSY; X /* disable guard timeout */ X if (fip->device_flags & DF_GUARD_TIMEOUT) X { X fip->device_flags &= ~DF_GUARD_TIMEOUT; X (void) untimeout (fip->timeout_idx); X } X } X X /* schedule fas_xxfer () if there are more characters to transfer X into the transmitter ring buffer X */ Xsched: X { X register struct tty *ttyp REG_DI; X X if (!(fip->event_flags & EF_DO_XXFER) X && (fip->xmit_ring_max > fip->xmit_ring_cnt) X && ((ttyp = fip->tty)->t_outq.c_cc X || (ttyp->t_tbuf.c_ptr X && ttyp->t_tbuf.c_count))) X { X EVENT_SCHED (fip, EF_DO_XXFER); X } X } X} X X/* Open device physically. X (called at SPLINT) X*/ XSTATIC void Xfas_open_device (fip) Xregister struct fas_internals *fip REG_SI; X{ X /* init some variables */ X fip->device_flags &= DF_DEVICE_CONFIGURED | DF_DEVICE_LOCKED X | DF_CTL_FIRST | DF_CTL_EVERY | DF_HUP_PROTECT X | DF_NO_OVERRUN; X fip->device_flags |= DF_DEVICE_OPEN; X fip->flow_flags &= FF_NEW_CTSRTS; X fip->flow_flags |= FF_CD_ENABLED; X fip->event_flags = 0; X fip->recv_ring_put_ptr = fip->recv_ring_take_ptr X = RECV_BUFF_BEGIN; X fip->recv_ring_cnt = 0; X fip->xmit_ring_put_ptr = fip->xmit_ring_take_ptr X = XMIT_BUFF_BEGIN; X fip->xmit_ring_cnt = 0; X fip->rxfer_timeout = MAX_RXFER_DELAY / EVENT_TIME; X LCR = 0; X MCR &= ~(fip->modem.m.di | fip->modem.m.ei | fip->modem.m.eo); X fip->start_char = CSTART; X fip->stop_char = CSTOP; X#if defined (HAVE_VPIX) X /* initialize VP/ix related variables */ X fip->v86_proc = (v86_t *) NULL; X fip->v86_intmask = 0; X#endif X X /* hook into the interrupt users chain */ X if ((fip->next_int_user = fas_first_int_user)) X fip->next_int_user->prev_int_user = fip; X else X fas_last_int_user = fip; X fas_first_int_user = fip; X fip->prev_int_user = (struct fas_internals *) NULL; X X /* enable FIFOs */ X if (DEVICE_TYPE == TYPE_NS16550A) X FAS_FIRST_OUTB (fip, NS_FIFO_CTL_PORT, FCR | NS_FIFO_CLR_XMIT); X else if (DEVICE_TYPE == TYPE_I82510) X { X FAS_FIRST_OUTB (fip, I_BANK_PORT, I_BANK_2); X FAS_OUTB (fip, I_IDM_PORT, I_FIFO_SETUP_CMD); X FAS_OUTB (fip, I_BANK_PORT, I_BANK_1); X FAS_OUTB (fip, I_TCM_PORT, I_FIFO_CLR_XMIT); X FAS_OUTB (fip, I_BANK_PORT, I_BANK_0); X } X X /* enable and clear transmitter interrupts */ X FAS_FIRST_OUTB (fip, INT_ENABLE_PORT, X IER = IE_XMIT_HOLDING_BUFFER_EMPTY); X (void) FAS_INB (fip, INT_ID_PORT); X X fas_param (fip, HARD_INIT); /* set up port regs */ X} X X/* Close device physically. X (called at SPLINT) X*/ XSTATIC void Xfas_close_device (fip) Xregister struct fas_internals *fip REG_SI; X{ X /* disable UART interrupts */ X FAS_FIRST_OUTB (fip, INT_ENABLE_PORT, IER = IE_NONE); X X /* reset break level */ X FAS_OUTB (fip, LINE_CTL_PORT, LCR = 0); X X /* clear some variables */ X fip->device_flags &= ~DF_DEVICE_OPEN; X fip->event_flags = 0; X X /* unhook from interrupt users chain */ X if (fip->prev_int_user) X fip->prev_int_user->next_int_user = fip->next_int_user; X else X fas_first_int_user = fip->next_int_user; X if (fip->next_int_user) X fip->next_int_user->prev_int_user = fip->prev_int_user; X else X fas_last_int_user = fip->prev_int_user; X} X X/* Set up a port according to the given termio structure. X (called at SPLINT) X*/ XSTATIC void Xfas_param (fip, init_type) Xregister struct fas_internals *fip REG_SI; Xint init_type; X{ X register struct tty *ttyp REG_DI; X bool do_flush; X int old_level; X X ttyp = fip->tty; X X { X register uint cflag REG_BX; X X cflag = ttyp->t_cflag; X fip->iflag = ttyp->t_iflag; X do_flush = FALSE; X X#if defined (HAVE_VPIX) X /* we don't set port registers if we are in dos mode */ X if (fip->iflag & DOSMODE) X { X /* This is a kludge. We don't know what baud rate X DOS will use. Therefore, we assume a rather low X one to be on the safe side. X */ X cflag = (cflag & ~CBAUD) | B300; X goto setflags; X } X#endif X /* Make sure that we have a valid baud rate. If we don't X get one, take the previous baud rate. X */ X if ((cflag & CBAUD) == B0) X cflag = (cflag & ~CBAUD) | (fip->cflag & CBAUD); X X /* if soft init mode: don't set port registers if cflag X didn't change X */ X if ((init_type == SOFT_INIT) X && !((cflag ^ fip->cflag) X & (CBAUD | CSIZE | CSTOPB | PARENB | PARODD))) X goto setflags; X X /* don't change break flag */ X LCR &= LC_SET_BREAK_LEVEL; X X /* set character size */ X switch (cflag & CSIZE) X { X case CS5: X LCR |= LC_WORDLEN_5; X break; X X case CS6: X LCR |= LC_WORDLEN_6; X break; X X case CS7: X LCR |= LC_WORDLEN_7; X break; X X default: X LCR |= LC_WORDLEN_8; X break; X } X X /* set # of stop bits */ X if (cflag & CSTOPB) X LCR |= LC_STOPBITS_LONG; X X /* set parity */ X if (cflag & PARENB) X { X LCR |= LC_ENABLE_PARITY; X X if (!(cflag & PARODD)) X LCR |= LC_EVEN_PARITY; X } X X /* set LCR and baud rate */ X FAS_FIRST_OUTB (fip, LINE_CTL_PORT, LCR | LC_ENABLE_DIVISOR); X FAS_OUTB (fip, DIVISOR_LSB_PORT, fas_speed_ptr [BT_SELECT] X [cflag & CBAUD] X .div.b.low); X FAS_OUTB (fip, DIVISOR_MSB_PORT, fas_speed_ptr [BT_SELECT] X [cflag & CBAUD] X .div.b.high); X FAS_OUTB (fip, LINE_CTL_PORT, LCR); X Xsetflags: X /* set dynamic xmit ring buffer size */ X fip->xmit_ring_max = fas_speed_ptr [BT_SELECT] [cflag & CBAUD] X .xbuf_size; X X /* disable modem control signals if required by open mode */ X if (fip->o_state & OS_CLOCAL) X cflag |= CLOCAL; X X /* Select hardware handshake depending on the minor device X number and various termio flags (if they are available). X */ X fip->flow_flags &= ~(FF_HWO_HANDSHAKE X | FF_HWI_HANDSHAKE X | FF_HDX_HANDSHAKE); X if (fip->o_state & (OS_HWO_HANDSHAKE | OS_HWI_HANDSHAKE X | OS_HDX_HANDSHAKE)) X { X if (fip->o_state & OS_HWO_HANDSHAKE) X fip->flow_flags |= FF_HWO_HANDSHAKE; X if (fip->o_state & OS_HWI_HANDSHAKE) X fip->flow_flags |= FF_HWI_HANDSHAKE; X if (fip->o_state & OS_HDX_HANDSHAKE) X fip->flow_flags |= FF_HDX_HANDSHAKE; X } X else X { X#if defined (CTSXON) && defined (RTSXOFF) /* SVR4 compatibility */ X if (fip->iflag & CTSXON) X fip->flow_flags |= FF_HWO_HANDSHAKE; X if (fip->iflag & RTSXOFF) X fip->flow_flags |= FF_HWI_HANDSHAKE; X#else X#if defined (CTSFLOW) && defined (RTSFLOW) /* SCO Xenix compatibility */ X if (!(cflag & CLOCAL) || (fip->flow_flags & FF_NEW_CTSRTS)) X { X#if defined (ORTSFL) /* SCO UNIX 3.2.4.2 compatibility */ X if ((cflag & (ORTSFL | CTSFLOW | RTSFLOW)) == ORTSFL) X fip->flow_flags |= FF_HWO_HANDSHAKE X | FF_HWI_HANDSHAKE; X else X { X if (cflag & CTSFLOW) X fip->flow_flags |= FF_HWO_HANDSHAKE; X if (cflag & RTSFLOW) X fip->flow_flags |= ((fip->flow_flags X & FF_NEW_CTSRTS) X || !(cflag & ORTSFL)) X ? FF_HWI_HANDSHAKE X : FF_HDX_HANDSHAKE; X } X#else X#if defined (CRTSFL) /* SCO UNIX 3.2.4 compatibility */ X if ((cflag & (CRTSFL | CTSFLOW | RTSFLOW)) == CRTSFL) X fip->flow_flags |= FF_HWO_HANDSHAKE X | FF_HWI_HANDSHAKE; X else X#endif X { X if (cflag & CTSFLOW) X fip->flow_flags |= FF_HWO_HANDSHAKE; X if (cflag & RTSFLOW) X fip->flow_flags |= (fip->flow_flags X & FF_NEW_CTSRTS) X ? FF_HWI_HANDSHAKE X : FF_HDX_HANDSHAKE; X } X#endif X } X#endif X#endif X } X X /* Determine whether to enable MSI or not. X Set the interrupt enable port accordingly. X */ X#if defined (HAVE_VPIX) X if ((cflag & CLOCAL) && !(fip->flow_flags & FF_HWO_HANDSHAKE) X && !(fip->iflag & DOSMODE)) X#else X if ((cflag & CLOCAL) && !(fip->flow_flags & FF_HWO_HANDSHAKE)) X#endif X { X if (fip->device_flags & DF_MSI_ENABLED) X { X FAS_FIRST_OUTB (fip, INT_ENABLE_PORT, X IER &= ~IE_MODEM_STATUS); X fip->device_flags &= ~DF_MSI_ENABLED; X } X fip->device_flags &= ~DF_MSI_NOISE; X } X else X { X if (!(fip->device_flags & (DF_MSI_ENABLED | DF_MSI_NOISE))) X { X /* read current modem status lines */ X MSR = NEW_MSR = FAS_FIRST_INB (fip, MDM_STATUS_PORT) X & (MS_CTS_PRESENT X | MS_DSR_PRESENT X | MS_DCD_PRESENT); X FAS_OUTB (fip, INT_ENABLE_PORT, IER |= IE_MODEM_STATUS); X fip->device_flags |= DF_MSI_ENABLED; X } X } X X /* Fake the carrier detect state flag if CLOCAL mode or if X requested by open mode. X */ X if ((cflag & CLOCAL) X || (fip->flow_flags & FF_CD_ENABLED X && !(~MSR & fip->modem.m.ca)) X || ((fip->o_state & OS_FAKE_CARRIER_ON) X && ((fip->flow_flags & FF_CARRIER_ON) X || !(fip->o_state & OS_OPEN_STATES)))) X { X fip->flow_flags |= FF_CD_ENABLED | FF_CARRIER_ON; X ttyp->t_state |= CARR_ON; X } X else X { X if (fip->flow_flags & FF_CARRIER_ON) X { X fip->flow_flags &= ((fip->device_flags X & DF_HUP_PROTECT) X && (fip->o_state X & OS_OPEN_STATES)) X ? ~(FF_CD_ENABLED X | FF_CARRIER_ON) X : ~FF_CARRIER_ON; X /* flush buffers on carrier drop */ X do_flush = TRUE; X } X ttyp->t_state &= ~CARR_ON; X } X X if ((fip->flow_flags & FF_CARRIER_ON) && (cflag & CREAD)) X { X /* enable receiver data interrupts */ X if (!(fip->device_flags & DF_RDI_ENABLED)) X fas_rdi_enable (fip); X } X else X { X /* disable receiver data interrupts */ X if (fip->device_flags & DF_RDI_ENABLED) X { X FAS_FIRST_OUTB (fip, INT_ENABLE_PORT, X IER &= ~IE_RECV_DATA_AVAILABLE); X fip->device_flags &= ~DF_RDI_ENABLED; X } X } X X fip->cflag = cflag; X } X X#if defined (XCLUDE) /* SYSV 3.2 Xenix compatibility */ X /* Permit exclusive use of this device. */ X if (ttyp->t_lflag & XCLUDE) X fip->o_state |= OS_EXCLUSIVE_OPEN_2; X else X fip->o_state &= ~OS_EXCLUSIVE_OPEN_2; X#endif X X /* re-link fas_internals structure */ X fas_pos_by_speed (fip); X X /* flush buffers if necessary */ X if (do_flush) X { X /* lock transmitter */ X fip->device_flags |= DF_XMIT_LOCKED; X old_level = SPLWRK (); X (void) ttyflush (ttyp, FREAD | FWRITE); X (void) splx (old_level); X /* enable transmitter */ X fip->device_flags &= ~DF_XMIT_LOCKED; X } X X /* setup handshake flags */ X#if defined (HAVE_VPIX) X if ((fip->flow_flags & (FF_HWI_HANDSHAKE | FF_HDX_HANDSHAKE)) X || !(fip->iflag & DOSMODE)) X#endif X { X register n_unchar mcr REG_BX; X X /* clear flow control output bits */ X mcr = MCR & ~(fip->flow.m.ic | fip->flow.m.hc); X fip->flow_flags &= ~(FF_HWI_STARTED | FF_HDX_STARTED); X X /* raise flow control bits if necessary */ X if (fip->flow_flags & FF_HWI_HANDSHAKE) X { X if (fip->recv_ring_cnt < RECV_HW_LOW_WATER) X { X mcr |= fip->flow.m.ic; X fip->flow_flags |= FF_HWI_STARTED; X } X } X else if (fip->flow_flags & FF_HDX_HANDSHAKE) X { X if (fip->flow_flags & FF_OUTPUT_BUSY) X { X mcr |= fip->flow.m.hc; X fip->flow_flags |= FF_HDX_STARTED; X } X } X else if (!(fip->flow_flags & FF_DEF_HHO_LOW)) X mcr |= fip->flow.m.hc; X X /* set modem enable bits */ X#if defined (HAVE_VPIX) X if (!(fip->iflag & DOSMODE)) X#endif X { X if ((ttyp->t_cflag & CBAUD) != B0 X && (fip->flow_flags & FF_CD_ENABLED)) X { X mcr |= (fip->o_state & OS_WAIT_OPEN) X ? fip->modem.m.ei X : fip->modem.m.eo; X } X else X { X mcr &= (fip->o_state & OS_WAIT_OPEN) X ? ~fip->modem.m.ei X : ~fip->modem.m.eo; X } X } X X if ((init_type != SOFT_INIT) || (mcr != MCR)) X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, MCR = mcr); X } X X /* set hardware output flow control flags */ X if (!(~NEW_MSR & fip->flow.m.oc) X || (~NEW_MSR & fip->flow.m.oe) X || !(fip->flow_flags & FF_HWO_HANDSHAKE)) X fip->flow_flags &= ~FF_HWO_STOPPED; X else X fip->flow_flags |= FF_HWO_STOPPED; X X /* check software input flow control */ X if (fip->flow_flags & FF_SWI_STOPPED) X { X if (!(fip->iflag & IXOFF) X || (fip->recv_ring_cnt < RECV_SW_LOW_WATER)) X fas_send_xon (fip); X } X else X { X if ((fip->iflag & IXOFF) X && (fip->recv_ring_cnt > RECV_SW_HIGH_WATER)) X fas_send_xoff (fip); X } X X /* restart output */ X fas_xproc (fip); X} X X/* Re-link fas_internals structure to interrupt users chain according X to the baud rate (fastes port comes first). X (called at SPLINT) X*/ XSTATIC void Xfas_pos_by_speed (fipp) Xstruct fas_internals *fipp; X{ X register struct fas_internals *fip REG_SI; X X { X register n_unchar my_prio REG_BX; X register n_unchar prio REG_CX; X ulong my_speed; X X fip = fipp; X X /* compute our own speed */ X if (fip->flow_flags & FF_CARRIER_ON) X { X INT_PRIO = my_prio = (fip->device_flags & DF_NO_OVERRUN) X ? NUMBER_OF_TYPES X : DEVICE_TYPE; X my_speed = fas_baud_ptr [BT_SELECT] [fip->cflag & CBAUD]; X } X else X { X my_prio = NUMBER_OF_TYPES + 1; X INT_PRIO = NUMBER_OF_TYPES + 1; X my_speed = 0L; X } X X /* unhook us from the interrupt users chain */ X if (fip->prev_int_user) X fip->prev_int_user->next_int_user = fip->next_int_user; X else X fas_first_int_user = fip->next_int_user; X if (fip->next_int_user) X fip->next_int_user->prev_int_user = fip->prev_int_user; X else X fas_last_int_user = fip->prev_int_user; X X /* find a new position for us */ X for (fip = fas_first_int_user; fip; fip = fip->next_int_user) X { Xfastloop4: X if (my_prio > (prio = INT_PRIO)) X { X /* speed beats beauty */ X fip = fip->next_int_user; X if (fip) X goto fastloop4; X break; X } X X if (my_prio < prio) X break; /* found a new position */ X if (my_speed >= ((prio == NUMBER_OF_TYPES + 1) X ? 0L X : fas_baud_ptr [BT_SELECT] X [fip->cflag & CBAUD])) X break; /* found a new position */ X } X } X X { X register struct fas_internals *my_fip REG_DI; X X my_fip = fipp; X X /* now hook us into the new position */ X if (fip) X { X /* we are in front of another entry */ X if ((my_fip->prev_int_user = fip->prev_int_user)) X my_fip->prev_int_user->next_int_user = my_fip; X else X fas_first_int_user = my_fip; X fip->prev_int_user = my_fip; X my_fip->next_int_user = fip; X } X else X { X /* we are the last entry */ X if ((my_fip->prev_int_user = fas_last_int_user)) X my_fip->prev_int_user->next_int_user = my_fip; X else X fas_first_int_user = my_fip; X fas_last_int_user = my_fip; X my_fip->next_int_user = (struct fas_internals *) NULL; X } X } X} X X/* Asynchronous event handler. Scheduled by functions that can't do the X processing themselves because of execution time restrictions. X (called via timeout () at an OS dependent SPL) X*/ XSTATIC void Xfas_event (dummy) Xvoid *dummy; X{ X register struct fas_internals *fip REG_SI; X register struct tty *ttyp REG_DI; X register uint count REG_BX; X bool idle; X int old_level; X X /* allow pending tty interrupts */ X old_level = SPLWRK (); X (void) SPLINT (); X X idle = TRUE; X X /* loop through all fas_internals structures */ X for (fip = &fas_internals [0], count = fas_physical_units; count; X ++fip, --count) X { Xfastloop3: X /* process only structures that actually need service */ X if (!fip->event_flags) X { X /* speed beats beauty */ X ++fip; X if (--count) X goto fastloop3; X break; X } X X /* we have something to do */ X idle = FALSE; X ttyp = fip->tty; X X /* check the modem signals */ X if (fip->event_flags & (EF_DO_MPROC | EF_RESET_DELTA_BITS)) X { X NEW_MSR &= ~MS_ANY_DELTA; X if (fip->event_flags & EF_DO_MPROC) X { X fip->event_flags &= ~(EF_DO_MPROC X | EF_RESET_DELTA_BITS); X fas_mproc (fip); X } X else X fip->event_flags &= ~EF_RESET_DELTA_BITS; X X /* re-enable modem status interrupts if appropriate */ X if (fip->device_flags & DF_MSI_NOISE) X { X FAS_FIRST_OUTB (fip, INT_ENABLE_PORT, X IER |= IE_MODEM_STATUS); X fip->device_flags |= DF_MSI_ENABLED; X fip->device_flags &= ~DF_MSI_NOISE; X } X } X X /* do the break interrupt */ X if (fip->event_flags & EF_DO_BRKINT) X { X fip->event_flags &= ~EF_DO_BRKINT; X if (fip->flow_flags & FF_CARRIER_ON) X { X (void) SPLWRK (); X (void) (*linesw [(unchar) ttyp->t_line].l_input) X (ttyp, L_BREAK); X (void) SPLINT (); X } X } X X /* transfer characters to the CLIST input buffer */ X if (fip->event_flags & EF_DO_RXFER) X { X#if defined (HAVE_VPIX) X fip->event_flags &= ~(EF_DO_RXFER | EF_WAKEUP_VPIX); X#else X fip->event_flags &= ~EF_DO_RXFER; X#endif X if ((fip->flow_flags & (FF_CARRIER_ON X | FF_RXFER_STOPPED)) X == FF_CARRIER_ON) X { X /* if not done, re-schedule this event */ X if (!fas_rxfer (fip)) X fip->event_flags |= EF_DO_RXFER; X /* check input buffer low water marks */ X if ((fip->recv_ring_cnt < RECV_HW_LOW_WATER) X && (fip->flow_flags & (FF_HWI_HANDSHAKE X | FF_HWI_STARTED)) X == FF_HWI_HANDSHAKE) X { X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, X MCR |= fip->flow.m.ic); X fip->flow_flags |= FF_HWI_STARTED; X } X if ((fip->recv_ring_cnt < RECV_SW_LOW_WATER) X && (fip->iflag & IXOFF) X && (fip->flow_flags & FF_SWI_STOPPED)) X fas_send_xon (fip); X } X#if defined (HAVE_VPIX) X /* send pseudorupt to VP/ix */ X if ((fip->iflag & DOSMODE) && fip->v86_proc X && (ttyp->t_rawq.c_cc || ttyp->t_canq.c_cc)) X { X (void) SPLWRK (); X (void) v86setint (fip->v86_proc, X fip->v86_intmask); X (void) SPLINT (); X fip->event_flags |= EF_WAKEUP_VPIX; X } X#endif X } X#if defined (HAVE_VPIX) X else if (fip->event_flags & EF_WAKEUP_VPIX) X { X /* send pseudorupt to VP/ix */ X if ((fip->iflag & DOSMODE) && fip->v86_proc X && (ttyp->t_rawq.c_cc || ttyp->t_canq.c_cc)) X { X (void) SPLWRK (); X (void) v86setint (fip->v86_proc, X fip->v86_intmask); X (void) SPLINT (); X } X else X fip->event_flags &= ~EF_WAKEUP_VPIX; X } X#endif X X /* transfer characters to the output ring buffer */ X if (fip->event_flags & EF_DO_XXFER) X { X fip->event_flags &= ~EF_DO_XXFER; X if (fip->flow_flags & FF_CARRIER_ON) X { X fas_xxfer (fip); X if (fip->flow_flags & FF_OUTPUT_BUSY) X ttyp->t_state |= BUSY; X /* check half duplex output flow control */ X if ((fip->flow_flags & (FF_HDX_HANDSHAKE X | FF_HDX_STARTED X | FF_OUTPUT_BUSY)) X == (FF_HDX_HANDSHAKE X | FF_OUTPUT_BUSY)) X { X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, X MCR |= fip->flow.m.hc); X fip->flow_flags |= FF_HDX_STARTED; X } X /* output characters */ X fas_xproc (fip); X } X else X { X /* throw away characters in output queue */ X (void) SPLWRK (); X (void) ttyflush (ttyp, FWRITE); X (void) SPLINT (); X } X } X X /* allow pending tty interrupts */ X (void) SPLWRK (); X (void) SPLINT (); X } X X event_scheduled = FALSE; X X /* check whether there was something to do */ X if (!idle) X { X /* there was work to do, so it's likely that there X also will be something to do in a short time from X now, so we schedule the next event processing X */ X event_scheduled = TRUE; X (void) timeout (fas_event, (caddr_t) NULL, X (EVENT_TIME) * (HZ) / 1000); X } X X (void) splx (old_level); X} X X/* Modem status handler. X (called at SPLINT) X*/ XSTATIC void Xfas_mproc (fip) Xregister struct fas_internals *fip REG_SI; X{ X register n_unchar mdm_status REG_BX; X int old_level; X X mdm_status = NEW_MSR; X NEW_MSR &= ~MS_RING_PRESENT; X X /* Check the carrier detect signal and set the state flags X accordingly. Also, if not in clocal mode, send SIGHUP on X carrier loss and flush the buffers. X */ X if (!(fip->cflag & CLOCAL) && (fip->flow_flags & FF_CD_ENABLED)) X { X register struct tty *ttyp REG_DI; X X ttyp = fip->tty; X if (!(~mdm_status & fip->modem.m.ca)) X { X /* Wake up dialin process on carrier low->high. */ X if (!(fip->flow_flags & FF_CARRIER_ON)) X { X fip->flow_flags |= FF_CARRIER_ON; X if ((ttyp->t_state |= CARR_ON) & WOPEN) X (void) wakeup ((caddr_t) &ttyp->t_canq); X /* enable receiver data interrupts */ X if ((fip->cflag & CREAD) X && !(fip->device_flags X & DF_RDI_ENABLED)) X fas_rdi_enable (fip); X /* re-link fas_internals structure */ X fas_pos_by_speed (fip); X } X } X else X { X if (!(~MSR & fip->modem.m.ca)) X { X if ((fip->device_flags & DF_HUP_PROTECT) X && (fip->o_state & OS_OPEN_STATES)) X { X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, X MCR &= (fip->o_state X & OS_WAIT_OPEN) X ? ~fip->modem.m.ei X : ~fip->modem.m.eo); X fip->flow_flags &= ~(FF_CD_ENABLED X | FF_CARRIER_ON); X } X else X fip->flow_flags &= ~FF_CARRIER_ON; X ttyp->t_state &= ~CARR_ON; X /* disable receiver data interrupts */ X if (fip->device_flags & DF_RDI_ENABLED) X { X FAS_FIRST_OUTB (fip, INT_ENABLE_PORT, X IER &= ~IE_RECV_DATA_AVAILABLE); X fip->device_flags &= ~DF_RDI_ENABLED; X } X /* re-link fas_internals structure */ X fas_pos_by_speed (fip); X old_level = SPLWRK (); X if (ttyp->t_pgrp) X { X (void) signal (ttyp->t_pgrp, SIGHUP); X#if defined (SIGCONT) X /* make sure processes are awake */ X (void) signal (ttyp->t_pgrp, SIGCONT); X#endif X } X (void) ttyflush (ttyp, FREAD | FWRITE); X (void) splx (old_level); X } X } X } X X#if defined (HAVE_VPIX) X if ((fip->iflag & (DOSMODE | PARMRK)) == (DOSMODE | PARMRK) X && (fip->flow_flags & FF_CARRIER_ON) X && fip->recv_ring_cnt < RECV_BUFF_SIZE - 2) X { X register n_unchar vpix_status REG_CX; X X /* prepare status bits for VP/ix */ X vpix_status = (((mdm_status ^ MSR) >> 4) & MS_ANY_DELTA) X | (mdm_status & (MS_CTS_PRESENT X | MS_DSR_PRESENT X | MS_DCD_PRESENT)); X if (fip->flow_flags & FF_HWO_HANDSHAKE) X { X vpix_status &= ~((n_unchar) (fip->flow.m.oc X | fip->flow.m.oe) >> 4); X vpix_status |= fip->flow.m.oc | fip->flow.m.oe; X } X if (!(fip->cflag & CLOCAL)) X { X vpix_status &= ~((n_unchar) fip->modem.m.ca >> 4); X vpix_status |= fip->modem.m.ca; X } X /* send status bits to VP/ix */ X if (vpix_status & MS_ANY_DELTA) X { X fip->recv_ring_cnt += 3; X PUT_RECV_BUFFER (fip, fip->recv_ring_put_ptr, 0xff); X PUT_RECV_BUFFER (fip, fip->recv_ring_put_ptr, 2); X PUT_RECV_BUFFER (fip, fip->recv_ring_put_ptr, X vpix_status); X EVENT_SCHED (fip, EF_DO_RXFER); X /* check input buffer high water marks */ X if ((fip->recv_ring_cnt > RECV_HW_HIGH_WATER) X && (fip->flow_flags & (FF_HWI_HANDSHAKE X | FF_HWI_STARTED)) X == (FF_HWI_HANDSHAKE | FF_HWI_STARTED)) X { X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, X MCR &= ~fip->flow.m.ic); X fip->flow_flags &= ~FF_HWI_STARTED; X } X if ((fip->recv_ring_cnt > RECV_SW_HIGH_WATER) X && (fip->iflag & IXOFF) X && !(fip->flow_flags & FF_SWI_STOPPED)) X fas_send_xoff (fip); X } X } X#endif X MSR = mdm_status & ~MS_RING_PRESENT; X X /* re-enable transmitter if it was stopped by carrier detect */ X if (fip->flow_flags & FF_CARR_STOPPED) X { X fip->flow_flags &= ~FF_CARR_STOPPED; X fas_xproc (fip); X } X} X X/* Receiver ring buffer -> CLIST buffer transfer function. X (called at SPLINT) X*/ XSTATIC bool Xfas_rxfer (fipp) Xstruct fas_internals *fipp; X{ X /* Defining register variables with function-wide scope would X break the FAS_MEM_COPY () macro below. So don't do that! X */ X unchar *tmp_srcptr, *tmp_destptr; X uint num_save; X uint recv_ring_cnt; X int old_level; X X num_save = 0; X X for (;;) X { X /* determine how many characters we have to copy */ X { X register struct fas_internals *fip REG_SI; X register struct tty *ttyp REG_DI; X register uint num_to_xfer REG_BX; X X old_level = SPLWRK (); X fip = fipp; X ttyp = fip->tty; X X /* if the target buffer is full, or if there is no X target buffer available, try to get a new one, X otherwise return X */ X if (num_save || !ttyp->t_rbuf.c_ptr) X { X (void) (*linesw [(unchar) ttyp->t_line].l_input) X (ttyp, L_BUF); X if (!ttyp->t_rbuf.c_ptr) X { X (void) splx (old_level); X return (FALSE); X } X } X X /* return if there aren't any characters to transfer */ X if (!(recv_ring_cnt = fip->recv_ring_cnt)) X { X (void) splx (old_level); X return (TRUE); X } X X /* determine how many characters to transfer */ X#if defined (XENIX) X if (ttyp->t_lflag & ICANON) X#else X if ((ttyp->t_lflag & ICANON) || ttyp->t_term) X#endif X { X num_to_xfer = recv_ring_cnt; X } X else X { X num_to_xfer = max_rawq_count - (uint) ttyp->t_rawq.c_cc; X if (!num_to_xfer) X { X (void) splx (old_level); X return (FALSE); /* input buffer full */ X } X if (recv_ring_cnt < num_to_xfer) X num_to_xfer = recv_ring_cnt; X /* if there are too few remaining characters to X completely fill a CLIST buffer, postpone the X transfer of these characters for a number of X event cycles on the assumption that by then X more characters have arrived X */ X if (ttyp->t_rbuf.c_count > num_to_xfer X && (num_save || --fip->rxfer_timeout)) X { X (void) splx (old_level); X return (FALSE); /* input buffer full */ X } X } X X /* reset timeout counter */ X fip->rxfer_timeout = MAX_RXFER_DELAY / EVENT_TIME; X X /* determine how many characters are in one contiguous block */ X if (ttyp->t_rbuf.c_count < num_to_xfer) X num_to_xfer = ttyp->t_rbuf.c_count; X if ((uint) (RECV_BUFF_END - fip->recv_ring_take_ptr) X < num_to_xfer) X num_to_xfer = RECV_BUFF_END - fip->recv_ring_take_ptr; X X if (!num_to_xfer) X { X /* invalid count, shouldn't happen */ X (void) splx (old_level); X return (FALSE); X } X X tmp_srcptr = fip->recv_ring_take_ptr; X if ((fip->recv_ring_take_ptr += num_to_xfer) == RECV_BUFF_END) X fip->recv_ring_take_ptr = RECV_BUFF_BEGIN; X tmp_destptr = (unchar *) ttyp->t_rbuf.c_ptr; X ttyp->t_rbuf.c_count -= num_to_xfer; X num_save = num_to_xfer; X } X X /* now copy from the ring buffer to the clist buffer */ X FAS_MEM_COPY (tmp_destptr, tmp_srcptr, num_save); X X (void) splx (old_level); X fipp->recv_ring_cnt -= num_save; X } X} X X/* CLIST buffer -> transmitter ring buffer transfer function. X (called at SPLINT) X*/ XSTATIC void Xfas_xxfer (fipp) Xstruct fas_internals *fipp; X{ X /* Defining register variables with function-wide scope would X break the FAS_MEM_COPY () macro below. So don't do that! X */ X unchar *tmp_srcptr, *tmp_destptr; X uint num_save; X uint xmit_ring_cnt; X int old_level; X X for (;;) X { X /* determine how many characters we have to copy */ X { X register struct fas_internals *fip REG_SI; X register struct tty *ttyp REG_DI; X register uint num_to_xfer REG_BX; X X old_level = SPLWRK (); X fip = fipp; X ttyp = fip->tty; X X /* Check if tbuf is empty. If it is empty, reset buffer X pointer and counter and get the next chunk of output X characters. X */ X if (!ttyp->t_tbuf.c_ptr || !ttyp->t_tbuf.c_count) X { X if (ttyp->t_tbuf.c_ptr) X ttyp->t_tbuf.c_ptr -= ttyp->t_tbuf.c_size; X if (!((*linesw [(unchar) ttyp->t_line].l_output) (ttyp) X & CPRES)) X { X (void) splx (old_level); X return; X } X } X X /* Return if transmitter ring buffer is full. */ X if (fip->xmit_ring_max <= (xmit_ring_cnt = fip->xmit_ring_cnt)) X { X (void) splx (old_level); X return; X } X X /* set the maximum character limit */ X num_to_xfer = fip->xmit_ring_max - xmit_ring_cnt; X X /* Determine how many chars to transfer this time. */ X if (ttyp->t_tbuf.c_count < num_to_xfer) X num_to_xfer = ttyp->t_tbuf.c_count; X if ((uint) (XMIT_BUFF_END - fip->xmit_ring_put_ptr) X < num_to_xfer) X num_to_xfer = XMIT_BUFF_END - fip->xmit_ring_put_ptr; X if (!num_to_xfer) X { X /* invalid count, shouldn't happen */ X (void) splx (old_level); X return; X } X X fip->flow_flags |= FF_OUTPUT_BUSY; X tmp_srcptr = (unchar *) ttyp->t_tbuf.c_ptr; X ttyp->t_tbuf.c_ptr += num_to_xfer; X ttyp->t_tbuf.c_count -= num_to_xfer; X tmp_destptr = fip->xmit_ring_put_ptr; X if ((fip->xmit_ring_put_ptr += num_to_xfer) == XMIT_BUFF_END) X fip->xmit_ring_put_ptr = XMIT_BUFF_BEGIN; X num_save = num_to_xfer; X } X X /* now copy from the clist buffer to the ring buffer */ X FAS_MEM_COPY (tmp_destptr, tmp_srcptr, num_save); X X (void) splx (old_level); X fipp->xmit_ring_cnt += num_save; X } X} X X/* Handle hangup after last close. X (called via timeout () at an OS dependent SPL) X*/ XSTATIC void Xfas_hangup (fip) Xregister struct fas_internals *fip REG_SI; X{ X int old_level; X X old_level = SPLINT (); X X if (fip->device_flags & DF_DO_HANGUP) X { X /* do the hangup */ X MCR &= ~(fip->modem.m.ei | fip->modem.m.eo X | fip->flow.m.ic | fip->flow.m.hc); X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, MCR |= fip->modem.m.di); X fip->device_flags &= ~DF_DO_HANGUP; X (void) timeout (fas_hangup, (caddr_t) fip, X (HANGUP_TIME) * (HZ) / 1000); X } X else X { X /* If there was a waiting dialin process on this X port, reopen the physical device. X */ X if (fip->o_state & OS_WAIT_OPEN) X { X /* allow pending tty interrupts */ X (void) SPLWRK (); X (void) SPLINT (); X X fas_open_device (fip); X X /* allow pending tty interrupts */ X (void) SPLWRK (); X (void) SPLINT (); X } X RELEASE_DEVICE_LOCK (fip); X } X X (void) splx (old_level); X} X X/* Main timeout function. X (called via timeout () at an OS dependent SPL) X*/ XSTATIC void Xfas_timeout (fip) Xregister struct fas_internals *fip REG_SI; X{ X int old_level; X X old_level = SPLINT (); X X /* handle break request */ X if (fip->device_flags & DF_DO_BREAK) X { X /* set up break request flags */ X FAS_FIRST_OUTB (fip, LINE_CTL_PORT, X LCR |= LC_SET_BREAK_LEVEL); X fip->device_flags &= ~(DF_DO_BREAK | DF_GUARD_TIMEOUT); X (void) timeout (fas_timeout, (caddr_t) fip, X (BREAK_TIME) * (HZ) / 1000); X (void) splx (old_level); X return; X } X X /* reset break state */ X if ((fip->device_flags & DF_XMIT_BREAK) X && (LCR & LC_SET_BREAK_LEVEL)) X { X FAS_FIRST_OUTB (fip, LINE_CTL_PORT, LCR &= ~LC_SET_BREAK_LEVEL); X fip->device_flags |= DF_GUARD_TIMEOUT; X fip->timeout_idx = timeout (fas_timeout, (caddr_t) fip, X fas_speed_ptr [BT_SELECT] X [fip->cflag & CBAUD] X .i.ctime); X (void) splx (old_level); X return; X } X X fip->device_flags &= ~(DF_GUARD_TIMEOUT | DF_XMIT_BREAK); X X /* restart output */ X fas_xproc (fip); X X if ((fip->flow_flags & FF_OUTPUT_BUSY) X && !fip->xmit_ring_cnt X && !(fip->device_flags & DF_XMIT_BUSY)) X { X fip->flow_flags &= ~FF_OUTPUT_BUSY; X fip->tty->t_state &= ~BUSY; X /* check half duplex output flow control */ X if ((fip->flow_flags & (FF_HDX_HANDSHAKE | FF_HDX_STARTED)) X == (FF_HDX_HANDSHAKE | FF_HDX_STARTED)) X { X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, X MCR &= ~fip->flow.m.hc); X fip->flow_flags &= ~FF_HDX_STARTED; X } X EVENT_SCHED (fip, EF_DO_XXFER); X } X X (void) wakeup ((caddr_t) &(fip)->device_flags); X (void) splx (old_level); X} X X/* Re-enable receiver data interrupts. X (called at SPLINT) X*/ XSTATIC void Xfas_rdi_enable (fip) Xregister struct fas_internals *fip REG_SI; X{ X /* flush receiver register */ X if (DEVICE_TYPE == TYPE_NS16550A) X FAS_FIRST_OUTB (fip, NS_FIFO_CTL_PORT, FCR | NS_FIFO_CLR_RECV); X else if (DEVICE_TYPE == TYPE_I82510) X { X FAS_FIRST_OUTB (fip, I_BANK_PORT, I_BANK_1); X FAS_OUTB (fip, I_RCM_PORT, I_FIFO_CLR_RECV); X FAS_OUTB (fip, I_BANK_PORT, I_BANK_0); X } X (void) FAS_FIRST_INB (fip, RCV_DATA_PORT); X if (FAS_INB (fip, LINE_STATUS_PORT) & LS_RCV_AVAIL) X (void) FAS_INB (fip, RCV_DATA_PORT); X X FAS_OUTB (fip, INT_ENABLE_PORT, IER |= IE_RECV_DATA_AVAILABLE); X fip->device_flags |= DF_RDI_ENABLED; X} X X/* Start software input flow control. X (called at SPLINT) X*/ XSTATIC void Xfas_send_xon (fip) Xregister struct fas_internals *fip REG_SI; X{ X fip->flow_flags &= ~FF_SWI_STOPPED; X fip->flow_flags ^= FF_SW_FC_REQ; X if (fip->flow_flags & FF_SW_FC_REQ) X { X if (fip->flow_flags & FF_CARRIER_ON) X { X /* start input */ X fip->flow_flags |= FF_OUTPUT_BUSY; X fip->tty->t_state |= TTXON | BUSY; X /* check half duplex output flow control */ X if ((fip->flow_flags & (FF_HDX_HANDSHAKE | FF_HDX_STARTED)) X == FF_HDX_HANDSHAKE) X { X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, X MCR |= fip->flow.m.hc); X fip->flow_flags |= FF_HDX_STARTED; X } X fas_xproc (fip); X } X else X fip->flow_flags &= ~FF_SW_FC_REQ; X } X else X { X /* there is a yet unprocessed request for XOFF, so X we just cancel it and don't need to send an XON X */ X fip->tty->t_state &= ~TTXOFF; X if ((fip->flow_flags & FF_OUTPUT_BUSY) X && !fip->xmit_ring_cnt X && !(fip->device_flags X & (DF_XMIT_BUSY X | DF_GUARD_TIMEOUT X | DF_XMIT_BREAK))) X { X fip->flow_flags &= ~FF_OUTPUT_BUSY; X fip->tty->t_state &= ~BUSY; X /* check half duplex output flow control */ X if ((fip->flow_flags & (FF_HDX_HANDSHAKE X | FF_HDX_STARTED)) X == (FF_HDX_HANDSHAKE | FF_HDX_STARTED)) X { X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, X MCR &= ~fip->flow.m.hc); X fip->flow_flags &= ~FF_HDX_STARTED; X } X EVENT_SCHED (fip, EF_DO_XXFER); X } X } X} X X/* Stop software input flow control. X (called at SPLINT) X*/ XSTATIC void Xfas_send_xoff (fip) Xregister struct fas_internals *fip REG_SI; X{ X fip->flow_flags |= FF_SWI_STOPPED; X fip->flow_flags ^= FF_SW_FC_REQ; X if (fip->flow_flags & FF_SW_FC_REQ) X { X if (fip->flow_flags & FF_CARRIER_ON) X { X /* stop input */ X fip->flow_flags |= FF_OUTPUT_BUSY; X fip->tty->t_state |= TTXOFF | BUSY; X /* check half duplex output flow control */ X if ((fip->flow_flags & (FF_HDX_HANDSHAKE | FF_HDX_STARTED)) X == FF_HDX_HANDSHAKE) X { X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, X MCR |= fip->flow.m.hc); X fip->flow_flags |= FF_HDX_STARTED; X } X fas_xproc (fip); X } X else X fip->flow_flags &= ~FF_SW_FC_REQ; X } X else X { X /* there is a yet unprocessed request for XON, so X we just cancel it and don't need to send an XOFF X */ X fip->tty->t_state &= ~TTXON; X if ((fip->flow_flags & FF_OUTPUT_BUSY) X && !fip->xmit_ring_cnt X && !(fip->device_flags X & (DF_XMIT_BUSY X | DF_GUARD_TIMEOUT X | DF_XMIT_BREAK))) X { X fip->flow_flags &= ~FF_OUTPUT_BUSY; X fip->tty->t_state &= ~BUSY; X /* check half duplex output flow control */ X if ((fip->flow_flags & (FF_HDX_HANDSHAKE X | FF_HDX_STARTED)) X == (FF_HDX_HANDSHAKE | FF_HDX_STARTED)) X { X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, X MCR &= ~fip->flow.m.hc); X fip->flow_flags &= ~FF_HDX_STARTED; X } X EVENT_SCHED (fip, EF_DO_XXFER); X } X } X} X X/* Compute the port access control value. */ XSTATIC uint Xfas_make_ctl_val (fip, unit, num) Xregister struct fas_internals *fip REG_SI; Xuint unit; Xuint num; X{ X register uint val REG_DI; X register uint mask REG_BX; X uint i; X X if (fip->device_flags & DF_CTL_FIRST) X return (fas_ctl_val [unit]); X X if (fip->device_flags & DF_CTL_EVERY) X { X for (i = 8, mask = fas_ctl_val [unit], X val = fas_ctl_val [unit] << 8; i; --i) X { X if (mask & 0x100) X { X if (num & 0x01) X val ^= 0x100; X num >>= 1; X } X mask >>= 1; X val >>= 1; X } X return (val); X } X return (0); X} X X/* Initialize memory with zeros. */ XSTATIC void Xfas_mem_zero (ptr, size) Xregister unchar *ptr REG_SI; Xuint size; X{ X register unchar *limptr REG_DI; X X for (limptr = ptr + size; ptr < limptr; ++ptr) X *ptr = 0; X} X X/* Test device thoroughly. */ XSTATIC uint Xfas_test_device (fip) Xregister struct fas_internals *fip REG_SI; X{ X register unchar *cptr REG_DI; X uint errcode; X register uint delay_count REG_BX; X uint rep_count, i; X n_unchar lsr, msr; X static uint lcrval [3] = X { X LC_WORDLEN_8, X LC_WORDLEN_8 | LC_ENABLE_PARITY, X LC_WORDLEN_8 | LC_ENABLE_PARITY | LC_EVEN_PARITY X }; X X /* make sure FIFO is off */ X FAS_FIRST_OUTB (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD); X FAS_OUTB (fip, I_BANK_PORT, I_BANK_2); X FAS_OUTB (fip, I_IDM_PORT, I_FIFO_CLEAR_CMD); X FAS_OUTB (fip, I_BANK_PORT, I_BANK_0); X X /* set counter divisor */ X FAS_OUTB (fip, LINE_CTL_PORT, LC_ENABLE_DIVISOR); X FAS_OUTB (fip, DIVISOR_LSB_PORT, fas_speed_ptr [BT_SELECT] X [B0].div.b.low); X FAS_OUTB (fip, DIVISOR_MSB_PORT, fas_speed_ptr [BT_SELECT] X [B0].div.b.high); X FAS_OUTB (fip, LINE_CTL_PORT, 0); X X /* switch to local loopback */ X FAS_OUTB (fip, MDM_CTL_PORT, MC_SET_LOOPBACK); X X errcode = 0; X X /* wait until the transmitter register is empty */ X FAS_EVERY_CTL (fip, LINE_STATUS_PORT); X for (delay_count = TEST_DELAY_LOOPS; X delay_count && (~FAS_SAME_INB (fip, LINE_STATUS_PORT) X & (LS_XMIT_AVAIL | LS_XMIT_COMPLETE)); X --delay_count) X ; X X if (!delay_count) X errcode = 1; X X if (!errcode) X { X /* clear flags */ X (void) FAS_INB (fip, RCV_DATA_PORT); X (void) FAS_SAME_INB (fip, RCV_DATA_PORT); X (void) FAS_INB (fip, LINE_STATUS_PORT); X X /* make sure there are no more characters in the X receiver register X */ X FAS_EVERY_CTL (fip, LINE_STATUS_PORT); X for (delay_count = TEST_DELAY_LOOPS; X delay_count && !(FAS_SAME_INB (fip, LINE_STATUS_PORT) X & LS_RCV_AVAIL); X --delay_count) X ; X X if (delay_count) X (void) FAS_INB (fip, RCV_DATA_PORT); X X for (rep_count = TEST_CHAR_LOOPS; rep_count; --rep_count) X { X for (i = 0; i < 3; ++i) X { X /* test pattern */ X cptr = (unchar *) "\377\125\252\045\244\0\0"; X X /* check LSR flags */ X if (FAS_INB (fip, LINE_STATUS_PORT) X != (LS_XMIT_AVAIL | LS_XMIT_COMPLETE)) X { X errcode = 2; X break; X } X X /* test transmitter and receiver X with different line settings X */ X FAS_OUTB (fip, LINE_CTL_PORT, lcrval [i]); X X /* send first test pattern */ X FAS_OUTB (fip, XMT_DATA_PORT, *cptr); X X /* wait until the transmitter holding register X is empty X */ X FAS_EVERY_CTL (fip, LINE_STATUS_PORT); X for (delay_count = TEST_DELAY_LOOPS; X delay_count X && !((lsr = FAS_SAME_INB (fip, X LINE_STATUS_PORT)) X & LS_XMIT_AVAIL); X --delay_count) X ; X X if (!delay_count) X { X errcode = 3; X break; X } X X /* check LSR flags */ X if (lsr != LS_XMIT_AVAIL) X { X errcode = 2; X break; X } X X do X { X if (*cptr) X { X /* send next test pattern */ X FAS_OUTB (fip, XMT_DATA_PORT, *(cptr + 1)); X X /* check LSR flags */ X if (FAS_INB (fip, LINE_STATUS_PORT)) X { X errcode = 2; X break; X } X } X X /* wait until the test pattern is received */ X FAS_EVERY_CTL (fip, LINE_STATUS_PORT); X for (delay_count = TEST_DELAY_LOOPS; X delay_count X && !((lsr = FAS_SAME_INB (fip, X LINE_STATUS_PORT)) X & LS_RCV_AVAIL); X --delay_count) X ; X X if (!delay_count) X { X errcode = 4; X break; X } X X /* check LSR flags */ X if ((lsr & LS_RCV_INT) != LS_RCV_AVAIL) X { X errcode = 5; X break; X } X X /* check test pattern */ X if (FAS_INB (fip, RCV_DATA_PORT) != *cptr) X { X errcode = 6; X break; X } X X /* check LSR flags */ X if (FAS_INB (fip, LINE_STATUS_PORT) X & LS_RCV_INT) X { X errcode = 5; X break; X } X X /* wait until the transmitter register X is empty X */ X if (*cptr) X { X FAS_EVERY_CTL (fip, LINE_STATUS_PORT); X for (delay_count = TEST_DELAY_LOOPS; X delay_count X && !((lsr = FAS_SAME_INB (fip, X LINE_STATUS_PORT)) X & LS_XMIT_AVAIL); X --delay_count) X ; X X if (!delay_count) X { X errcode = 7; X break; X } X X /* check LSR flags */ X if (lsr != LS_XMIT_AVAIL) X { X errcode = 8; X break; X } X } X else X { X FAS_EVERY_CTL (fip, LINE_STATUS_PORT); X for (delay_count = TEST_DELAY_LOOPS; X delay_count X && !((lsr = FAS_SAME_INB (fip, X LINE_STATUS_PORT)) X & LS_XMIT_COMPLETE); X --delay_count) X ; X X if (!delay_count) X { X errcode = 7; X break; X } X X /* check LSR flags */ X if (lsr != (LS_XMIT_AVAIL X | LS_XMIT_COMPLETE)) X { X errcode = 8; X break; X } X } X } while (*((ushort *) (cptr++))); X X if (errcode) X break; X } X X if (errcode) X break; X } X } X X if (!errcode) X { X /* clear delta bits */ X (void) FAS_INB (fip, MDM_STATUS_PORT); X X for (rep_count = TEST_CTL_LOOPS; rep_count; --rep_count) X { X /* test pattern */ X cptr = (unchar *) "\005\142\012\237\006\130\011\257\017\361\0\017\0\0"; X X for (; *((ushort *) cptr); cptr += 2) X { X /* test modem control and status lines */ X FAS_OUTB (fip, MDM_CTL_PORT, *cptr | MC_SET_LOOPBACK); X X /* wait for delta flags */ X FAS_EVERY_CTL (fip, MDM_STATUS_PORT); X for (delay_count = TEST_DELAY_LOOPS; X delay_count X && !((msr = FAS_SAME_INB (fip, X MDM_STATUS_PORT)) X & MS_ANY_DELTA); X --delay_count) X ; X X if (!delay_count) X { X errcode = 9; X break; X } X X /* check MSR flags */ X if (msr != *(cptr + 1)) X { X errcode = 9; X break; X } X X /* check whether delta flags are cleared */ X if (FAS_SAME_INB (fip, MDM_STATUS_PORT) X != (msr & ~MS_ANY_DELTA)) X { X errcode = 9; X break; X } X } X X if (errcode) X break; X } X } X X /* switch back to normal operation */ X FAS_OUTB (fip, MDM_CTL_PORT, 0); X X return (errcode); X} X X#if defined (NEED_PUT_GETCHAR) Xint XFASPUTCHAR (arg) Xunchar arg; X{ X register struct fas_internals *fip REG_SI; X X if (!fas_is_initted) X fasinit (); X X fip = &fas_internals [0]; X if (fip->device_flags & DF_DEVICE_CONFIGURED) X { X if (arg == '\n') X (void) FASPUTCHAR ('\r'); X FAS_CTL (fip, LINE_STATUS_PORT); X while (!(FAS_SAME_INB (fip, LINE_STATUS_PORT) & LS_XMIT_AVAIL)) X ; X FAS_OUTB (fip, XMT_DATA_PORT, arg); X } X return (0); X} X Xint XFASGETCHAR () X{ X register struct fas_internals *fip REG_SI; X X if (!fas_is_initted) X fasinit (); X X fip = &fas_internals [0]; X if ((fip->device_flags & DF_DEVICE_CONFIGURED) X && (FAS_FIRST_INB (fip, LINE_STATUS_PORT) & LS_RCV_AVAIL)) X return (FAS_INB (fip, RCV_DATA_PORT)); X else X return (-1); X} X#endif X X#if defined (NEED_INIT8250) X/* Reset the requested port to be used directly by a DOS process. X (DosMerge only) X*/ Xint Xinit8250 (port, ier) Xregister ushort port REG_BX; Xushort ier; /* ier not used in this stub */ X{ X register struct fas_internals *fip REG_SI; X register uint unit REG_DI; X int old_level; X X /* See if the port address matches a port that is used by X the FAS driver. X */ X for (unit = 0; unit < fas_physical_units; ++unit) X if (port == fas_port [unit]) X break; X X if (unit >= fas_physical_units) X return (-1); /* port didn't match */ X X fip = fas_internals_ptr [unit]; X X old_level = SPLINT (); X X FAS_FIRST_OUTB (fip, INT_ENABLE_PORT, IER = IE_NONE); X fip->device_flags &= ~(DF_RDI_ENABLED | DF_MSI_ENABLED | DF_MSI_NOISE); X X FAS_OUTB (fip, MDM_CTL_PORT, MCR &= ~(fip->flow.m.ic | fip->flow.m.hc)); X X if (DEVICE_TYPE == TYPE_NS16550A) X FAS_OUTB (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD); X else if (DEVICE_TYPE == TYPE_I82510) X { X FAS_OUTB (fip, I_BANK_PORT, I_BANK_1); X FAS_OUTB (fip, I_TCM_PORT, I_FIFO_CLR_XMIT); X FAS_OUTB (fip, I_RCM_PORT, I_FIFO_CLR_RECV); X FAS_OUTB (fip, I_BANK_PORT, I_BANK_2); X FAS_OUTB (fip, I_IDM_PORT, I_FIFO_CLEAR_CMD); X FAS_OUTB (fip, I_BANK_PORT, I_BANK_0); X } X X (void) FAS_INB (fip, MDM_STATUS_PORT); X (void) FAS_INB (fip, RCV_DATA_PORT); X if (FAS_INB (fip, LINE_STATUS_PORT) & LS_RCV_AVAIL) X (void) FAS_INB (fip, RCV_DATA_PORT); X (void) FAS_INB (fip, INT_ID_PORT); X (void) splx (old_level); X return (0); X} X#endif SHAR_EOF echo 'File fas.c is complete' && true || echo 'restore of fas.c failed' rm -f _shar_wnt_.tmp fi # ============= fas.h ============== if test -f 'fas.h' -a X"$1" != X"-c"; then echo 'x - skipping fas.h (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting fas.h (Text)' sed 's/^X//' << 'SHAR_EOF' > 'fas.h' && X/* This file contains various defines for the FAS async driver. X If you change anything here you have to recompile the driver module. X*/ X X#if !defined (M_I286) X#ident "@(#)fas.h 2.12" X#endif X X/* Uncomment the following line if you need (asy|sio)putchar and X (asy|sio)getchar. This is only required if you link the kernel X without the original asy or sio driver and these functions aren't X provided by any other kernel module. X*/ X/* #define NEED_PUT_GETCHAR /* */ X X/* Uncomment the following line if you have VP/ix support in the X kernel. X*/ X#define HAVE_VPIX /* */ X X/* Uncomment the following line if there is a tunable `ttyhog' variable X in the kernel. X*/ X#define TUNABLE_TTYHOG /* */ X X/* Uncomment the following line if you want FAS to make sure that the X thresholds in tthiwat [] and ttlowat [] are high enough to prevent X the CLIST buffer functions to become a bottleneck at high baud rates. X tthiwat [] and ttlowat [] are global resources and are used by other X tty drivers as well, so in case that fixing these values causes X problems with these drivers this feature is configurable. X*/ X#define FIX_TTHILOWAT /* */ X X/* Uncomment the following line if you need init8250. DosMerge needs X this function, but only if you link the kernel without the original X asy or sio driver. X*/ X/* #define NEED_INIT8250 /* */ X X/* Initial line control register. This value will only be meaningful if X NEED_PUT_GETCHAR is defined. X*/ X#define INITIAL_LINE_CONTROL LC_WORDLEN_8 X X/* Initial baud rate. This value will only be meaningful if X NEED_PUT_GETCHAR is defined. X*/ X#define INITIAL_BAUD_RATE B9600 X X/* Initial modem control register. This should probably not have to X be touched. It is here because some terminals used as the console X require one or more of the modem signals set. It is only meaningful X if NEED_PUT_GETCHAR is defined. X*/ X#define INITIAL_MDM_CONTROL 0 X X/****************************************************/ X/* Nothing past this line should have to be changed */ X/****************************************************/ X X/* The following section is, if necessary, automatically updated with X OS dependent informations. Don't change it by hand! X*/ X/* @@OS_DEP_BEGIN@@ */ X/* @@OS_DEP_END@@ */ X X#if defined (VPIX) X#undef VPIX X#endif X X#if defined (HAVE_VPIX) X#define VPIX X#endif X X#if defined (SCO) && !defined (_NO_PROTOTYPE) X#define _NO_PROTOTYPE 1 X#endif X X#include X#include X#include X#include X#include X#if defined (XENIX) X#include X#include X#endif X#include X#include X#include X#include X#include X#include X#if !defined (XENIX) X#include X#endif X#if defined (SCO) || defined (XENIX) X#include X#endif X#include X#if !defined (M_I286) X#if !defined (XENIX) X#include X#include X#include X#include X#endif X#include X#if defined (HAVE_VPIX) X#include X#endif X#endif X X#if defined (XENIX) Xtypedef unsigned char unchar; Xtypedef unsigned long ulong; X X/* Union for use by all device handler ioctl routines. */ Xunion ioctl_arg { X struct termio *stparg; /* ptr to termio struct */ X char *cparg; /* ptr to character */ X char carg; /* character */ X int *iparg; /* ptr to integer */ X int iarg; /* integer */ X long *lparg; /* ptr to long */ X long larg; /* long */ X}; X#endif X X#if defined (__GNUC__) X/* in expressions GNU C is able to use operand sizes < native integer size */ Xtypedef unchar n_unchar; X#else X/* in expressions AT&T C extends smaller types to the native integer size */ Xtypedef uint n_unchar; X#endif X X/* allow function prototypes in ANSI C */ X#if defined (__STDC__) X#define P(x) x X#else X#define P(x) () X#endif X X#if defined (TRUE) X#undef TRUE X#endif X#define TRUE (1) X X#if defined (FALSE) X#undef FALSE X#endif X#define FALSE (0) X Xtypedef int bool; X X/* Miscellaneous Constants */ X X#define HANGUP_DELAY 500 /* in milli-seconds */ X#define HANGUP_TIME 1000 /* in milli-seconds */ X#define BREAK_TIME 250 /* in milli-seconds */ X#define MAX_EVENT_TIME 10 /* in milli-seconds */ X#define MAX_RXFER_DELAY 20 /* in milli-seconds */ X#define RECV_BUFF_FILL_TIME 2000 /* in milli-seconds */ X#define XMIT_BUFF_DRAIN_TIME 2000 /* in milli-seconds */ X#if defined (M_I286) X#define RECV_BUFF_MAX_SIZE 1000 /* receiver ring buffer max size */ X#define XMIT_BUFF_MAX_SIZE 500 /* transmitter ring buffer max size */ X#else X#define RECV_BUFF_MIN_SIZE 1000 /* receiver ring buffer min size */ X#define RECV_BUFF_MAX_SIZE 10000 /* receiver ring buffer max size */ X#define XMIT_BUFF_MAX_SIZE 10000 /* transmitter ring buffer max size */ X#endif X#define RECV_PC_SW_LOW_WATER 50 /* recv sw fc low water level in % */ X#define RECV_PC_SW_HIGH_WATER 80 /* recv sw fc high water level in % */ X#define RECV_PC_HW_LOW_WATER 65 /* recv hw fc low water level in % */ X#define RECV_PC_HW_HIGH_WATER 95 /* recv hw fc high water level in % */ X#define SOFT_INIT 0 /* init registers if cflag changed */ X#define HARD_INIT 1 /* init registers w/o checking cflag */ X#define TEST_CHAR_LOOPS 100 /* no. of character test loops */ X#define TEST_CTL_LOOPS 1000 /* no. of control line test loops */ X#define TEST_DELAY_LOOPS 60000 /* no. of delay loops */ X#define TEST_INTR_LOOPS 1000 /* no. of interrupt test loops */ X#if defined (SCO) || defined (XENIX) X#define SPLWRK spl5 /* SPL for character processing */ X#define SPLINT spl7 /* SPL to disable FAS interrupts */ X#else X#define SPLWRK spl6 /* SPL for character processing */ X#define SPLINT spltty /* SPL to disable FAS interrupts */ X#endif X#define MAX_UNITS 16 /* max. number of physical units */ X#define MAX_BAUD_TABLES 256 /* max. number of baud rate tables */ X#define NUM_UART_REGS 7 /* number of UART registers */ X X/* calculate EVENT_TIME from MAX_EVENT_TIME with regard to the X clock tick granularity X*/ X X#define EVENT_TIME ((((MAX_EVENT_TIME) * (HZ) / 1000)\ X * 1000 + (HZ) - 1) / (HZ)) X#if EVENT_TIME == 0 X#undef EVENT_TIME X#define EVENT_TIME ((1000 + (HZ) - 1) / (HZ)) X#endif X X#if MAX_RXFER_DELAY < EVENT_TIME X#undef MAX_RXFER_DELAY X#define MAX_RXFER_DELAY EVENT_TIME X#endif X X#define MAX_INPUT_FIFO_SIZE INPUT_NS_FIFO_SIZE X#define MAX_OUTPUT_FIFO_SIZE OUTPUT_NS_FIFO_SIZE X X X/* Here are the modem control flags for the fas_modem array in space.c. X They are arranged in three 8-bit masks which are combined to a 32-bit X word. Each of these 32-bit words represents one entry in the fas_modem X array. X X The lowest byte is used as a mask to manipulate the modem control X register for modem disable. Use the MC_* macros to build the mask. X X The second lowest byte is used as a mask to manipulate the modem control X register for modem enable during dialout. Use the MC_* macros to build X the mask and shift them 8 bits to the left. X X The second highest byte is used as a mask to manipulate the modem control X register for modem enable during dialin. Use the MC_* macros to build X the mask and shift them 16 bits to the left. X X The highest byte is used to mask signals from the modem status X register that will be used as the carrier detect signal. Use the MS_* X macros to build the mask and shift them 24 bits to the left. If you use X more than one signal, carrier is considered on only when all signals X are on. X X Here are some useful macros for the space.c file. You may create your X own macros if you have some special requirements not met by the X predefined ones. X*/ X X/* modem disable (choose one) */ X#define DI_RTS ((ulong) MC_SET_RTS) X#define DI_DTR ((ulong) MC_SET_DTR) X#define DI_RTS_AND_DTR ((ulong) (MC_SET_RTS | MC_SET_DTR)) X X/* modem enable for dialout (choose one) */ X#define EO_RTS ((ulong) MC_SET_RTS << 8) X#define EO_DTR ((ulong) MC_SET_DTR << 8) X#define EO_RTS_AND_DTR ((ulong) (MC_SET_RTS | MC_SET_DTR) << 8) X X/* modem enable for dialin (choose one) */ X#define EI_RTS ((ulong) MC_SET_RTS << 16) X#define EI_DTR ((ulong) MC_SET_DTR << 16) X#define EI_RTS_AND_DTR ((ulong) (MC_SET_RTS | MC_SET_DTR) << 16) X X/* carrier detect signal (choose one) */ X#define CA_DCD ((ulong) MS_DCD_PRESENT << 24) X#define CA_CTS ((ulong) MS_CTS_PRESENT << 24) X#define CA_DSR ((ulong) MS_DSR_PRESENT << 24) X X X/* Here are the hardware handshake flags for the fas_flow array in space.c. X They are arranged in three 8-bit masks which are combined to a 32-bit X word. Each of these 32-bit words represents one entry in the fas_flow X array. X X The lowest byte is used as a mask to manipulate the modem control X register for input flow control. Use the MC_* macros to build the mask. X X The second lowest byte is used to mask signals from the modem status X register that will be used for output flow control. Use the MS_* macros X to build the mask and shift them 8 bits to the left. If you use more X than one signal, output is allowed only when all signals are on. X X The second highest byte is used to mask signals from the modem status X register that will be used to enable the output flow control selected X by the second lowest byte. Use the MS_* macros to build the mask and X shift them 16 bits to the left. If you use more than one signal, output X flow control is enabled only when all signals are on. X X The highest byte is used as a mask to manipulate the modem control X register for output half duplex flow control. Use the MC_* macros to X build the mask and shift them 24 bits to the left. X X Here are some useful macros for the space.c file. You may create your X own macros if you have some special requirements not met by the X predefined ones. X*/ X X/* input flow control (choose one) */ X#define HI_RTS ((ulong) MC_SET_RTS) X#define HI_DTR ((ulong) MC_SET_DTR) X#define HI_RTS_AND_DTR ((ulong) (MC_SET_RTS | MC_SET_DTR)) X X/* output flow control (choose one) */ X#define HO_CTS ((ulong) MS_CTS_PRESENT << 8) X#define HO_DSR ((ulong) MS_DSR_PRESENT << 8) X#define HO_CTS_AND_DSR ((ulong) (MS_CTS_PRESENT | MS_DSR_PRESENT) \ X << 8) X#define HO_CTS_ON_DSR (((ulong) MS_CTS_PRESENT << 8) \ X | ((ulong) MS_DSR_PRESENT << 16)) X#define HO_CTS_ON_DSR_AND_DCD (((ulong) MS_CTS_PRESENT << 8) \ X | ((ulong) (MS_DSR_PRESENT | MS_DCD_PRESENT) \ X << 16)) X X/* output hdx flow control (choose one) */ X#define HX_RTS ((ulong) MC_SET_RTS << 24) X#define HX_DTR ((ulong) MC_SET_DTR << 24) X#define HX_RTS_AND_DTR ((ulong) (MC_SET_RTS | MC_SET_DTR) << 24) X X X/* define the local open flags */ X X#define OS_DEVICE_CLOSED 0x0000 X#define OS_OPEN_FOR_DIALOUT 0x0001 X#define OS_OPEN_FOR_DIALIN 0x0002 X#define OS_WAIT_OPEN 0x0004 X#define OS_NO_DIALOUT 0x0008 X#define OS_FAKE_CARRIER_ON 0x0010 X#define OS_CLOCAL 0x0020 X#define OS_HWO_HANDSHAKE 0x0040 X#define OS_HWI_HANDSHAKE 0x0080 X#define OS_HDX_HANDSHAKE 0x0100 X#define OS_EXCLUSIVE_OPEN_1 0x0200 X#define OS_EXCLUSIVE_OPEN_2 0x0400 /* SYSV 3.2 Xenix compatibility */ X X#define OS_OPEN_STATES (OS_OPEN_FOR_DIALOUT | OS_OPEN_FOR_DIALIN) X#define OS_TEST_MASK (OS_OPEN_FOR_DIALOUT | OS_NO_DIALOUT \ X | OS_FAKE_CARRIER_ON | OS_CLOCAL \ X | OS_HWO_HANDSHAKE | OS_HWI_HANDSHAKE \ X | OS_HDX_HANDSHAKE | OS_EXCLUSIVE_OPEN_1 \ X | OS_EXCLUSIVE_OPEN_2) X#define OS_SU_TEST_MASK (OS_OPEN_FOR_DIALOUT | OS_NO_DIALOUT \ X | OS_FAKE_CARRIER_ON | OS_CLOCAL \ X | OS_HWO_HANDSHAKE | OS_HWI_HANDSHAKE \ X | OS_HDX_HANDSHAKE | OS_EXCLUSIVE_OPEN_1) X X/* define the device status flags */ X X#define DF_CTL_FIRST 0x0001 /* write ctl port at first access */ X#define DF_CTL_EVERY 0x0002 /* write ctl port at every access */ X#define DF_XMIT_BUSY 0x0004 /* transmitter busy */ X#define DF_XMIT_BREAK 0x0008 /* transmitter sends break */ X#define DF_XMIT_LOCKED 0x0010 /* transmitter locked against output */ X#define DF_GUARD_TIMEOUT 0x0020 /* protect last char from corruption */ X#define DF_MSI_NOISE 0x0040 /* modem status interrupts noise */ SHAR_EOF true || echo 'restore of fas.h failed' fi echo 'End of part 6' echo 'File fas.h is continued in part 7' echo 7 > _shar_seq_.tmp exit 0