home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-10-12 | 60.1 KB | 2,335 lines |
- Newsgroups: comp.sources.unix
- From: fas@geminix.in-berlin.de (FAS Support Account)
- Subject: v27i071: FAS-2.11.0 - asynch serial driver for System V, Part05/08
- References: <1.750471074.20539@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 71
- Archive-Name: fas-2.11.0/part05
-
- #!/bin/sh
- # this is fas211pl0.05 (part 5 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" != 5; 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' &&
- XSTATIC void fas_xxfer P((struct fas_internals *fipp));
- XSTATIC void fas_hangup P((struct fas_internals *fip));
- XSTATIC void fas_timeout P((struct fas_internals *fip));
- XSTATIC void fas_rdi_enable P((struct fas_internals *fip));
- XSTATIC void fas_send_xon P((struct fas_internals *fip));
- XSTATIC void fas_send_xoff P((struct fas_internals *fip));
- XSTATIC uint fas_make_ctl_val P((struct fas_internals *fip, uint unit,
- X uint num));
- XSTATIC void fas_mem_zero P((unchar *ptr, uint size));
- XSTATIC uint fas_test_device P((struct fas_internals *fip));
- X#if defined (NEED_PUT_GETCHAR)
- Xint FASPUTCHAR P((unchar arg));
- Xint FASGETCHAR P((void));
- X#endif
- X#if defined (NEED_INIT8250)
- Xint init8250 P((ushort port, ushort ier));
- X#endif
- X
- X/* External functions used by this driver. */
- Xextern int ttinit ();
- Xextern int ttiocom ();
- Xextern int ttyflush ();
- Xextern int SPLINT ();
- Xextern int SPLWRK ();
- Xextern int splx ();
- Xextern int sleep ();
- Xextern int wakeup ();
- Xextern void longjmp ();
- X#if !defined (SVR4)
- Xextern int signal ();
- X#endif
- Xextern int timeout ();
- Xextern int untimeout ();
- X#if defined (SCO) || defined (XENIX)
- Xextern int printcfg ();
- X#else
- Xextern int printf ();
- X#endif
- X#if defined (HAVE_VPIX)
- Xextern int copyin ();
- Xextern int copyout ();
- Xextern int v86setint ();
- X#endif
- X#if !defined (__GNUC__) || defined (NO_ASM)
- X#define INB(port) inb (port)
- X#define OUTB(port,val) outb (port, val)
- Xextern int inb ();
- Xextern int outb ();
- X#endif
- X
- X/* External data objects used by this driver. */
- Xextern int tthiwat [];
- Xextern int ttlowat [];
- X#if defined (TUNABLE_TTYHOG)
- Xextern int ttyhog;
- X#endif
- X
- X/* The following stuff is defined in `space.c'. */
- Xextern uint fas_port [];
- Xextern int fas_vec [];
- Xextern uint fas_modify [];
- Xextern uint fas_fifo_ctl [];
- Xextern uint fas_init_seq [];
- Xextern uint fas_int_ack_seq [];
- Xextern uint fas_mcb [];
- Xextern ulong fas_modem [];
- Xextern ulong fas_flow [];
- Xextern uint fas_ctl_port [];
- Xextern uint fas_ctl_val [];
- Xextern uint fas_pl_select [];
- Xextern uint fas_layout [] [NUM_UART_REGS];
- Xextern uint fas_bt_select [];
- Xextern ulong fas_baud [] [CBAUD + 1];
- Xextern uint fas_physical_units;
- Xextern uint fas_port_layouts;
- Xextern uint fas_baud_tables;
- Xextern struct fas_internals fas_internals [];
- Xextern struct tty fas_tty [];
- Xextern struct fas_speed fas_speed [] [CBAUD + 1];
- Xextern struct fas_internals *fas_internals_ptr [];
- Xextern struct tty *fas_tty_ptr [];
- Xextern struct fas_speed *fas_speed_ptr [];
- Xextern ulong *fas_baud_ptr [];
- X/* End of `space.c' references. */
- X
- X#if defined (NEED_PUT_GETCHAR)
- X/* Flag to indicate that we have been through fasinit. */
- Xstatic bool fas_is_initted = FALSE;
- X#endif
- X
- X/* Flag to indicate that the event handler has been scheduled
- X via the timeout () function.
- X*/
- Xstatic bool event_scheduled = FALSE;
- X
- X/* Pointers to the first and last fas_internals structure of the
- X interrupt users chain.
- X*/
- Xstatic struct fas_internals *fas_first_int_user = NULL;
- Xstatic struct fas_internals *fas_last_int_user = NULL;
- X
- X/* Threshold for the character transfer to the CLIST buffers. */
- Xstatic uint max_rawq_count;
- X
- X/* Counters for receiver overruns. Each UART type has its own counter
- X indexed by the device type.
- X*/
- Xuint fas_overrun [NUMBER_OF_TYPES];
- X
- X/* Counter for temporarily disabled modem status interrupts due
- X to noise on the modem status lines.
- X*/
- Xuint fas_msi_noise = 0;
- X
- X/* Lookup table for minor device number -> open mode flags translation. */
- Xstatic uint fas_open_modes [16] =
- X{
- X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARRIER_ON | OS_CLOCAL,
- X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARRIER_ON | OS_CLOCAL | OS_HWO_HANDSHAKE
- X | OS_HWI_HANDSHAKE,
- X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARRIER_ON | OS_CLOCAL | OS_HWO_HANDSHAKE,
- X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARRIER_ON | OS_CLOCAL | OS_HWO_HANDSHAKE
- X | OS_HDX_HANDSHAKE,
- X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARRIER_ON,
- X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARRIER_ON | OS_HWO_HANDSHAKE
- X | OS_HWI_HANDSHAKE,
- X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARRIER_ON | OS_HWO_HANDSHAKE,
- X OS_OPEN_FOR_DIALOUT | OS_FAKE_CARRIER_ON | OS_HWO_HANDSHAKE
- X | OS_HDX_HANDSHAKE,
- X OS_OPEN_FOR_DIALIN | OS_WAIT_OPEN | OS_NO_DIALOUT,
- X OS_OPEN_FOR_DIALIN | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HWO_HANDSHAKE
- X | OS_HWI_HANDSHAKE,
- X OS_OPEN_FOR_DIALIN | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HWO_HANDSHAKE,
- X OS_OPEN_FOR_DIALIN | OS_WAIT_OPEN | OS_NO_DIALOUT | OS_HWO_HANDSHAKE
- X | OS_HDX_HANDSHAKE,
- X OS_OPEN_FOR_DIALIN | OS_WAIT_OPEN,
- X OS_OPEN_FOR_DIALIN | OS_WAIT_OPEN | OS_HWO_HANDSHAKE
- X | OS_HWI_HANDSHAKE,
- X OS_OPEN_FOR_DIALIN | OS_WAIT_OPEN | OS_HWO_HANDSHAKE,
- X OS_OPEN_FOR_DIALIN | OS_WAIT_OPEN | OS_HWO_HANDSHAKE
- X | OS_HDX_HANDSHAKE
- X};
- X
- X/* Check for the presence of the devices in the fas_port array and if
- X the respective device is present, test and initialize it. During the
- X initialization the device type is automatically determined and the UART
- X is handled according to its requirements.
- X*/
- Xvoid
- Xfasinit ()
- X{
- X register struct fas_internals *fip REG_SI;
- X register uint unit REG_DI;
- X uint logical_units;
- X int max_tthiwat, max_ttlowat;
- X long xbuf_size, min_xbuf_size;
- X struct fas_speed *speed_ptr;
- X ulong *baud_ptr;
- X uint *offset_ptr;
- X char port_stat [MAX_UNITS + 1];
- X
- X#if defined (NEED_PUT_GETCHAR)
- X if (fas_is_initted)
- X return;
- X
- X fas_is_initted = TRUE;
- X#endif
- X
- X {
- X register uint baud_rate REG_BX;
- X
- X#if defined (FIX_TTHILOWAT)
- X /* kludge to make sure that the tty buffer high water levels
- X for fast baud rates are high enough to ensure max. throughput
- X */
- X for (baud_rate = B0 + 1, max_tthiwat = 0; baud_rate <= CBAUD;
- X ++baud_rate)
- X {
- X if (tthiwat [baud_rate] >= max_tthiwat)
- X {
- X max_tthiwat = tthiwat [baud_rate];
- X max_ttlowat = ttlowat [baud_rate];
- X }
- X else
- X {
- X tthiwat [baud_rate] = max_tthiwat;
- X ttlowat [baud_rate] = max_ttlowat;
- X }
- X }
- X#endif
- X
- X /* calculate baud rate related values */
- X for (unit = 0; unit < fas_baud_tables; ++unit)
- X {
- X baud_ptr = fas_baud_ptr [unit] = fas_baud [unit];
- X speed_ptr = fas_speed_ptr [unit] = fas_speed [unit];
- X if (baud_ptr [B0])
- X speed_ptr [B0].i.valid = TRUE;
- X else
- X {
- X speed_ptr [B0].i.valid = FALSE;
- X continue;
- X }
- X for (baud_rate = B0 + 1; baud_rate <= CBAUD; ++baud_rate)
- X {
- X if (!baud_ptr [baud_rate])
- X {
- X speed_ptr [B0].i.valid = FALSE;
- X break;
- X }
- X
- X speed_ptr [baud_rate].i.ctime
- X = ((HZ) * 150L + (baud_ptr [baud_rate] / 2L))
- X / baud_ptr [baud_rate];
- X if (speed_ptr [baud_rate].i.ctime < 2)
- X speed_ptr [baud_rate].i.ctime = 2;
- X /* ideal xbuf size */
- X xbuf_size = (baud_ptr [baud_rate] + 25L) / 50L
- X - tthiwat [baud_rate];
- X /* lower boundary to prevent bottle-neck */
- X min_xbuf_size = (baud_ptr [baud_rate] * (EVENT_TIME)
- X + 25000L) / 50000L;
- X if (xbuf_size < min_xbuf_size)
- X xbuf_size = min_xbuf_size;
- X if (xbuf_size < MAX_OUTPUT_FIFO_SIZE * 2L)
- X xbuf_size = MAX_OUTPUT_FIFO_SIZE * 2L;
- X speed_ptr [baud_rate].xbuf_size
- X = (xbuf_size > (long) XMIT_BUFF_SIZE)
- X ? (long) XMIT_BUFF_SIZE
- X : xbuf_size;
- X speed_ptr [baud_rate].div.val
- X = (baud_ptr [B0] + (baud_ptr [baud_rate] / 2L))
- X / baud_ptr [baud_rate];
- X if (!speed_ptr [baud_rate].div.val)
- X speed_ptr [baud_rate].div.val = 1;
- X }
- X }
- X }
- X
- X /* initialize threshold for the character transfer to
- X the CLIST buffers
- X */
- X#if defined (TUNABLE_TTYHOG)
- X max_rawq_count = ttyhog;
- X#else
- X max_rawq_count = TTYHOG;
- X#endif
- X
- X /* execute the init sequence for the serial cards */
- X {
- X register uint *seq_ptr REG_BX;
- X
- X for (seq_ptr = &fas_init_seq [0]; *seq_ptr; seq_ptr += 2)
- X {
- X if (*(seq_ptr + 1) & READ_PORT)
- X (void) INB (*seq_ptr);
- X else
- X (void) OUTB (*seq_ptr, *(seq_ptr + 1));
- X }
- X }
- X
- X /* set overrun counters to zero */
- X for (unit = 0; unit < NUMBER_OF_TYPES; ++unit)
- X fas_overrun [unit] = 0;
- X
- X /* setup the list of pointers to the tty structures */
- X for (unit = 0, logical_units = fas_physical_units * 2;
- X unit < logical_units; ++unit)
- X fas_mem_zero ((unchar *) (fas_tty_ptr [unit] = &fas_tty [unit]),
- X sizeof fas_tty [0]);
- X
- X /* setup and initialize all serial ports */
- X for (unit = 0; unit < fas_physical_units; ++unit)
- X {
- X fas_internals_ptr [unit] = fip = &fas_internals [unit];
- X fas_mem_zero ((unchar *) fip, (unchar *) &fip->recv_buffer [0]
- X - (unchar *) fip);
- X port_stat [unit] = '-';
- X if (fas_port [unit])
- X {
- X if (fas_bt_select [unit] >= fas_baud_tables)
- X {
- X port_stat [unit] = '!';
- X continue; /* a configuration error */
- X }
- X BT_SELECT = fas_bt_select [unit];
- X
- X if (!fas_speed_ptr [BT_SELECT] [B0].i.valid)
- X {
- X port_stat [unit] = '!';
- X continue; /* a configuration error */
- X }
- X
- X /* init all of its ports */
- X if (fas_ctl_port [unit])
- X {
- X CTL_PORT.p.addr = fas_ctl_port [unit];
- X
- X if (fas_ctl_val [unit] & 0xff00)
- X fip->device_flags |= DF_CTL_EVERY;
- X else
- X fip->device_flags |= DF_CTL_FIRST;
- X }
- X
- X if (fas_pl_select [unit] >= fas_port_layouts)
- X {
- X port_stat [unit] = '!';
- X continue; /* a configuration error */
- X }
- X
- X {
- X register uint regno REG_BX;
- X
- X offset_ptr = fas_layout [fas_pl_select [unit]];
- X
- X for (regno = 0; regno < NUM_UART_REGS; ++regno)
- X {
- X fip->port [regno].p.addr
- X = (fip->device_flags & DF_CTL_EVERY)
- X ? fas_port [unit]
- X : fas_port [unit]
- X + offset_ptr [regno];
- X fip->port [regno].p.ctl
- X = fas_make_ctl_val (fip, unit,
- X offset_ptr [regno]);
- X }
- X }
- X
- X fip->modem.l = fas_modem [unit];
- X fip->flow.l = fas_flow [unit];
- X fip->po_state = fip->o_state = OS_DEVICE_CLOSED;
- X
- X /* mask off invalid bits */
- X fip->modem.m.di &= MC_ANY_CONTROL;
- X fip->modem.m.eo &= MC_ANY_CONTROL;
- X fip->modem.m.ei &= MC_ANY_CONTROL;
- X fip->modem.m.ca &= MS_ANY_PRESENT;
- X fip->flow.m.ic &= MC_ANY_CONTROL;
- X fip->flow.m.oc &= MS_ANY_PRESENT;
- X fip->flow.m.oe &= MS_ANY_PRESENT;
- X fip->flow.m.hc &= MC_ANY_CONTROL;
- X
- X fip->recv_ring_put_ptr = fip->recv_ring_take_ptr
- X = &fip->recv_buffer [0];
- X fip->xmit_ring_put_ptr = fip->xmit_ring_take_ptr
- X = &fip->xmit_buffer [0];
- X
- X /* disable all ints */
- X FAS_FIRST_OUTB (fip, INT_ENABLE_PORT, IER = IE_NONE);
- X
- X /* is there a serial chip ? */
- X if (FAS_SAME_INB (fip, INT_ENABLE_PORT) != IER)
- X {
- X port_stat [unit] = '?';
- X continue; /* a hardware error */
- X }
- X
- X /* test the chip thoroughly */
- X if (!(fas_modify [unit] & NO_TEST)
- X && (port_stat [unit]
- X = (fas_test_device (fip) + '0'))
- X != '0')
- X continue; /* a hardware error */
- X
- X FAS_OUTB (fip, LINE_CTL_PORT, LCR = 0);
- X FAS_OUTB (fip, MDM_CTL_PORT, MCR
- X = fas_mcb [unit] | fip->modem.m.di);
- X
- X DEVICE_TYPE = TYPE_NS16450;
- X fip->xmit_fifo_size = 1;
- X port_stat [unit] = '*';
- X
- X /* let's see if it's an NS16550A */
- X FAS_OUTB (fip, NS_FIFO_CTL_PORT, NS_FIFO_INIT_CMD);
- X if (!(~FAS_INB (fip, INT_ID_PORT) & II_NS_FIFO_ENABLED))
- X {
- X DEVICE_TYPE = TYPE_NS16550A;
- X fip->xmit_fifo_size = OUTPUT_NS_FIFO_SIZE;
- X port_stat [unit] = 'F';
- X FAS_OUTB (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD);
- X }
- X else
- X {
- X FAS_OUTB (fip, NS_FIFO_CTL_PORT, NS_FIFO_CLEAR_CMD);
- X /* or is it an i82510 ? */
- X FAS_OUTB (fip, I_BANK_PORT, I_BANK_2);
- X if (!(~FAS_INB (fip, I_BANK_PORT) & I_BANK_2))
- X {
- X DEVICE_TYPE = TYPE_I82510;
- X fip->xmit_fifo_size = OUTPUT_I_FIFO_SIZE;
- X port_stat [unit] = 'f';
- 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 }
- X FAS_OUTB (fip, I_BANK_PORT, I_BANK_0);
- X }
- X
- X /* select FIFO mode */
- X if (DEVICE_TYPE != TYPE_NS16450)
- X {
- X if (fas_fifo_ctl [unit] == FIFO_DEFAULT)
- X {
- X if (DEVICE_TYPE == TYPE_NS16550A)
- X {
- X#if defined (LOW_INT_LAT)
- X FCR = NS_FIFO_SIZE_8
- X | NS_FIFO_ENABLE;
- X#else
- X FCR = NS_FIFO_SIZE_4
- X | NS_FIFO_ENABLE;
- X#endif
- X }
- X }
- X else if (fas_fifo_ctl [unit]
- X == FIFO_EMUL_NS16450)
- X {
- X fip->xmit_fifo_size = 1;
- X if (DEVICE_TYPE == TYPE_NS16550A)
- X {
- X FCR = NS_FIFO_SIZE_1
- X | NS_FIFO_ENABLE;
- X }
- X }
- X else if (fas_fifo_ctl [unit] == FIFO_OFF
- X || DEVICE_TYPE != TYPE_NS16550A)
- X {
- X DEVICE_TYPE = TYPE_NS16450;
- X fip->xmit_fifo_size = 1;
- X port_stat [unit] = '+';
- X }
- X else switch (fas_fifo_ctl [unit])
- X {
- X case FIFO_POINTER_DEV:
- X case FIFO_TRIGGER_1:
- X FCR = NS_FIFO_SIZE_1
- X | NS_FIFO_ENABLE;
- X break;
- X case FIFO_TRIGGER_4:
- X FCR = NS_FIFO_SIZE_4
- X | NS_FIFO_ENABLE;
- X break;
- X case FIFO_TRIGGER_8:
- X FCR = NS_FIFO_SIZE_8
- X | NS_FIFO_ENABLE;
- X break;
- X case FIFO_TRIGGER_14:
- X FCR = NS_FIFO_SIZE_14
- X | NS_FIFO_ENABLE;
- X break;
- X default:
- X DEVICE_TYPE = TYPE_NS16450;
- X fip->xmit_fifo_size = 1;
- X port_stat [unit] = '+';
- X break;
- X }
- X }
- X
- X /* clear potential interrupts */
- 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
- X /* do we want the fdx meaning of CTSFLOW/RTSFLOW ? */
- X if (fas_modify [unit] & NEW_CTSRTS)
- X fip->flow_flags |= FF_NEW_CTSRTS;
- X
- X /* do we want hangup protection ? */
- X if (!(fas_modify [unit] & NO_HUP_PROTECT))
- X fip->device_flags |= DF_HUP_PROTECT;
- X
- X /* is the device overrun protected ? */
- X if (fas_modify [unit] & NO_OVERRUN)
- X fip->device_flags |= DF_NO_OVERRUN;
- X
- X /* show that it is present and configured */
- X fip->device_flags |= DF_DEVICE_CONFIGURED;
- X }
- X }
- X
- X /* execute the interrupt acknowledge sequence for the serial cards */
- X {
- X register uint *seq_ptr REG_BX;
- X
- X for (seq_ptr = &fas_int_ack_seq [0]; *seq_ptr; seq_ptr += 2)
- X {
- X if (*(seq_ptr + 1) & READ_PORT)
- X (void) INB (*seq_ptr);
- X else
- X (void) OUTB (*seq_ptr, *(seq_ptr + 1));
- X }
- X }
- X
- X#if defined (NEED_PUT_GETCHAR)
- X fip = &fas_internals [0];
- X MCR &= ~fip->modem.m.di;
- X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, MCR |= INITIAL_MDM_CONTROL);
- X
- X LCR = INITIAL_LINE_CONTROL;
- X FAS_OUTB (fip, LINE_CTL_PORT, LCR | LC_ENABLE_DIVISOR);
- X FAS_OUTB (fip, DIVISOR_LSB_PORT, fas_speed_ptr [BT_SELECT]
- X [INITIAL_BAUD_RATE]
- X .div.b.low);
- X FAS_OUTB (fip, DIVISOR_MSB_PORT, fas_speed_ptr [BT_SELECT]
- X [INITIAL_BAUD_RATE]
- X .div.b.high);
- X FAS_OUTB (fip, LINE_CTL_PORT, LCR);
- X#endif
- X
- X#if defined (SCO) || defined (XENIX)
- X for (unit = 0; unit < fas_physical_units; ++unit)
- X (void) printcfg ("fas", fas_port [unit], 7,
- X fas_vec [unit], -1,
- X "unit=%d type=%c release=2.11.0",
- X unit, port_stat [unit]);
- X#else
- X port_stat [unit] = '\0';
- X (void) printf ("\nFAS 2.11.0 async driver: Unit 0-%d init state is [%s]\n\n",
- X unit - 1,
- X port_stat);
- X#endif
- X}
- X
- X/* Open a tty line. This function is called for every open, as opposed
- X to the fasclose function which is called only with the last close.
- X (called at SPL0)
- X*/
- Xvoid
- Xfasopen (dev, flag, otyp)
- Xdev_t dev;
- Xint flag;
- Xint otyp;
- X{
- X register struct fas_internals *fip REG_SI;
- X register struct tty *ttyp REG_DI;
- X register uint open_mode REG_BX;
- X uint unit;
- X bool have_lock;
- X int old_level;
- X
- X /* check for valid port number */
- X if ((unit = GET_UNIT (dev)) >= fas_physical_units)
- X {
- X u.u_error = ENXIO;
- X return;
- X }
- X
- X fip = fas_internals_ptr [unit];
- X
- X /* was the port present at init time ? */
- X if (!(fip->device_flags & DF_DEVICE_CONFIGURED))
- X {
- X u.u_error = ENXIO;
- X return;
- X }
- X
- X open_mode = GET_OPEN_MODE (dev);
- X have_lock = FALSE;
- X old_level = SPLINT ();
- X
- X /* loop until we've got the device lock and, owning the lock, we've
- X checked whether the current open mode permits us to open the
- X device
- X */
- X for (;;)
- X {
- X /* If this is a dialin open, but the device is already
- X open for dialout and the FNDELAY flag is not set,
- X wait until the device is closed.
- X */
- X if ((open_mode & OS_OPEN_FOR_DIALIN)
- X && (fip->o_state & OS_OPEN_FOR_DIALOUT)
- X#if defined (FNONBLOCK)
- X && !(flag & (FNDELAY | FNONBLOCK)))
- X#else
- X && !(flag & FNDELAY))
- X#endif
- X {
- X if (have_lock)
- X {
- X RELEASE_DEVICE_LOCK (fip);
- X have_lock = FALSE;
- X }
- X do
- X {
- X (void) sleep ((caddr_t) &fip->o_state, TTIPRI);
- X } while (fip->o_state & OS_OPEN_FOR_DIALOUT);
- X }
- X
- X /* If the device is already open and another open uses a
- X different open mode or if a dialin process waits for
- X carrier and doesn't allow parallel dialout opens, return
- X with EBUSY error.
- X */
- X if ((fip->o_state & ((open_mode & OS_OPEN_FOR_DIALIN)
- X ? (OS_OPEN_STATES | OS_WAIT_OPEN)
- X : (OS_OPEN_STATES | OS_NO_DIALOUT)))
- X && ((flag & FEXCL)
- X || ((open_mode ^ fip->o_state) & (u.u_uid
- X ? OS_TEST_MASK
- X : OS_SU_TEST_MASK))))
- X {
- X if (have_lock)
- X RELEASE_DEVICE_LOCK (fip);
- X (void) splx (old_level);
- X u.u_error = EBUSY;
- X return;
- X }
- X
- X /* If device is already open and the FAPPEND flag is set,
- X flush the output buffers. This may be used to release
- X processes that got stuck in fasclose () during an
- X exit () call.
- X */
- X if ((fip->o_state & OS_OPEN_STATES) && (flag & FAPPEND))
- X {
- X flag &= ~FAPPEND; /* flush only once */
- X (void) SPLWRK ();
- X (void) ttyflush (fip->tty, FWRITE);
- X (void) SPLINT ();
- X }
- X
- X /* if we don't have the device lock, yet, try to get it */
- X if (!have_lock)
- X {
- X if (fip->device_flags & DF_DEVICE_LOCKED)
- X {
- X GET_DEVICE_LOCK (fip, TTIPRI);
- X have_lock = TRUE;
- X /* we had to sleep for some time to get the
- X lock, therefore, re-check whether the
- X current open mode still permits us to
- X open the device
- X */
- X continue;
- X }
- X else
- X GET_DEVICE_LOCK (fip, TTIPRI);
- X }
- X
- X break;
- X }
- X
- X /* disable subsequent opens */
- X if (flag & FEXCL)
- X open_mode |= OS_EXCLUSIVE_OPEN_1;
- X
- X /* set up pointer to tty structure */
- X ttyp = (open_mode & OS_OPEN_FOR_DIALIN)
- X ? fas_tty_ptr [unit + fas_physical_units]
- X : fas_tty_ptr [unit];
- X
- X /* things to do on first open only */
- X if (!(fip->o_state & ((open_mode & OS_OPEN_FOR_DIALIN)
- X ? (OS_OPEN_STATES | OS_WAIT_OPEN)
- X : OS_OPEN_STATES)))
- X {
- X /* close dialin device before opening dialout device */
- X if (fip->o_state & OS_WAIT_OPEN)
- X {
- X fip->flow_flags &= ~(FF_CD_ENABLED | FF_CARRIER_ON);
- X fip->tty->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 /* block transmitter */
- X fip->device_flags |= DF_XMIT_LOCKED;
- X (void) SPLWRK ();
- X (void) ttyflush (fip->tty, FREAD | FWRITE);
- X (void) SPLINT ();
- X fas_close_device (fip);
- X }
- X
- X /* init data structures */
- X fip->tty = ttyp;
- X (void) ttinit (ttyp);
- X ttyp->t_proc = (int (*)()) fasproc;
- X fip->po_state = fip->o_state;
- X fip->o_state = open_mode & ~OS_OPEN_STATES;
- X fas_open_device (fip); /* open physical device */
- X
- X /* allow pending tty interrupts */
- X (void) SPLWRK ();
- X (void) SPLINT ();
- X }
- X
- X /* If dialin open and the FNDELAY flag is not set,
- X block and wait for carrier if device not yet open.
- X */
- X if ((open_mode & OS_OPEN_FOR_DIALIN)
- X#if defined (FNONBLOCK)
- X && !(flag & (FNDELAY | FNONBLOCK)))
- X#else
- X && !(flag & FNDELAY))
- X#endif
- X {
- X /* sleep while open for dialout or no carrier */
- X while ((fip->o_state & OS_OPEN_FOR_DIALOUT)
- X || (!(fip->flow_flags & FF_CARRIER_ON)
- X && !(fip->o_state & OS_OPEN_FOR_DIALIN)))
- X {
- X ttyp->t_state |= WOPEN;
- X RELEASE_DEVICE_LOCK (fip);
- X (void) sleep ((caddr_t) &ttyp->t_canq, TTIPRI);
- X GET_DEVICE_LOCK (fip, TTIPRI);
- X ttyp->t_state &= ~WOPEN;
- X }
- X }
- X
- X /* we can't have concurrent ISOPEN and WOPEN states, so
- X wake up waiting dialin processes as we are about to set
- X the ISOPEN flag
- X */
- X if (ttyp->t_state & WOPEN)
- X (void) wakeup ((caddr_t) &ttyp->t_canq);
- X
- X (void) (*linesw [(unchar) ttyp->t_line].l_open) (ttyp);
- X
- X /* set open type flags */
- X fip->o_state = open_mode;
- X
- X RELEASE_DEVICE_LOCK (fip);
- X (void) splx (old_level);
- X}
- X
- X/* Close a tty line. This is only called if there is no other
- X concurrent open left. A blocked dialin open is not counted as
- X a concurrent open because in this state it isn't really open.
- X (called at SPL0)
- X*/
- Xvoid
- Xfasclose (dev, flag, otyp)
- Xdev_t dev;
- Xint flag;
- Xint otyp;
- X{
- X register struct fas_internals *fip REG_SI;
- X register struct tty *ttyp REG_DI;
- X register uint open_mode REG_BX;
- X uint unit;
- X bool was_signal = FALSE;
- X bool ignore_signal = FALSE;
- X int old_level;
- X
- X fip = fas_internals_ptr [unit = GET_UNIT (dev)];
- X
- X /* set up pointer to tty structure */
- X ttyp = ((open_mode = GET_OPEN_MODE (dev)) & OS_OPEN_FOR_DIALIN)
- X ? fas_tty_ptr [unit + fas_physical_units]
- X : fas_tty_ptr [unit];
- X
- X old_level = SPLINT ();
- X GET_DEVICE_LOCK (fip, PZERO - 1);
- X
- X if ((fip->o_state == OS_DEVICE_CLOSED)
- X || ((open_mode & OS_OPEN_FOR_DIALIN)
- X ? (fip->o_state & OS_OPEN_FOR_DIALOUT)
- X && (fip->po_state == OS_DEVICE_CLOSED)
- X : fip->o_state & OS_WAIT_OPEN))
- X {
- X /* device is not open on the driver level */
- X RELEASE_DEVICE_LOCK (fip);
- X (void) splx (old_level);
- X return;
- X }
- X
- X if (!((open_mode & OS_OPEN_FOR_DIALIN)
- X && (fip->o_state & OS_OPEN_FOR_DIALOUT)))
- X {
- X /* wait for buffer drain and catch interrupts */
- X while ((fip->flow_flags & FF_CARRIER_ON)
- X && ((fip->flow_flags & FF_OUTPUT_BUSY)
- X || ttyp->t_outq.c_cc
- X || (ttyp->t_state & TIMEOUT)))
- X {
- X /* if FNDELAY/FNONBLOCK is set, flush output buffers */
- X#if defined (FNONBLOCK)
- X if (flag & (FNDELAY | FNONBLOCK))
- X {
- X flag &= ~(FNDELAY | FNONBLOCK);
- X#else
- X if (flag & FNDELAY)
- X {
- X flag &= ~FNDELAY;
- X#endif
- X ignore_signal = TRUE;
- X (void) SPLWRK ();
- X (void) ttyflush (ttyp, FWRITE);
- X (void) SPLINT ();
- X continue;
- X }
- X /* on receipt of a signal, flush output buffers */
- X ttyp->t_state |= TTIOW;
- X if (sleep ((caddr_t) &ttyp->t_oflag,
- X ignore_signal
- X ? PZERO - 1
- X : TTOPRI | PCATCH))
- X {
- X /* caught signal */
- X was_signal = TRUE;
- X ignore_signal = TRUE;
- X ttyp->t_state &= ~TTIOW;
- X (void) SPLWRK ();
- X (void) ttyflush (ttyp, FWRITE);
- X (void) SPLINT ();
- X }
- X }
- X
- X /* block transmitter and wait until it is
- X empty
- X */
- X fip->device_flags |= DF_XMIT_LOCKED;
- X while (fip->device_flags & (DF_XMIT_BUSY
- X | DF_XMIT_BREAK
- X | DF_GUARD_TIMEOUT))
- X (void) sleep ((caddr_t) &fip->device_flags,
- X PZERO - 1);
- X
- X fip->flow_flags &= ~(FF_CD_ENABLED | FF_CARRIER_ON);
- X ttyp->t_state &= ~(WOPEN | 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 (void) SPLWRK ();
- X (void) ttyflush (ttyp, FREAD | FWRITE);
- X (void) SPLINT ();
- X }
- X else
- X {
- X fip->flow_flags &= ~(FF_CD_ENABLED | FF_CARRIER_ON);
- X ttyp->t_state &= ~(WOPEN | CARR_ON);
- X }
- X
- X (void) (*linesw [(unchar) ttyp->t_line].l_close) (ttyp);
- X
- X if (open_mode & OS_OPEN_FOR_DIALIN)
- X {
- X if (!(fip->o_state & OS_OPEN_FOR_DIALOUT))
- X {
- X fas_close_device (fip);
- X fip->o_state = OS_DEVICE_CLOSED;
- X if (fip->cflag & HUPCL)
- X {
- X /* request hangup */
- X fip->device_flags |= DF_DO_HANGUP;
- X (void) timeout (fas_hangup, (caddr_t) fip,
- X (HANGUP_DELAY) * (HZ) / 1000);
- X }
- X }
- X else /* a parallel dialout open is active */
- X fip->po_state = OS_DEVICE_CLOSED;
- X }
- X else
- X {
- X fas_close_device (fip);
- X fip->o_state = OS_DEVICE_CLOSED;
- X if (fip->cflag & HUPCL)
- X {
- X /* request hangup */
- X fip->device_flags |= DF_DO_HANGUP;
- X (void) timeout (fas_hangup, (caddr_t) fip,
- X (HANGUP_DELAY) * (HZ) / 1000);
- X }
- X /* If there is a waiting dialin process on
- X this port, reopen the physical device.
- X */
- X if (fip->po_state & OS_WAIT_OPEN)
- X {
- X /* get the dialin version of the
- X tty structure
- X */
- X fip->tty = fas_tty_ptr [unit + fas_physical_units];
- X fip->o_state = fip->po_state;
- X fip->po_state = OS_DEVICE_CLOSED;
- X if (!(fip->device_flags & DF_DO_HANGUP))
- X {
- X /* allow pending tty interrupts */
- X (void) SPLWRK ();
- X (void) SPLINT ();
- X fas_open_device (fip);
- X }
- X }
- X
- X /* wake up dialin process (if any) */
- X (void) wakeup ((caddr_t) &fip->o_state);
- X }
- X
- X if (!(fip->device_flags & DF_DO_HANGUP))
- X RELEASE_DEVICE_LOCK (fip);
- X
- X (void) splx (old_level);
- X
- X if (was_signal)
- X#if defined (SVR4)
- X longjmp (&u.u_qsav);
- X#else
- X longjmp (u.u_qsav);
- X#endif
- X}
- X
- X/* Read characters from the input buffer.
- X (called at SPL0)
- X*/
- Xvoid
- Xfasread (dev)
- Xdev_t dev;
- X{
- X register struct tty *ttyp REG_CX;
- X
- X ttyp = fas_internals_ptr [GET_UNIT (dev)]->tty;
- X
- X (void) (*linesw [(unchar) ttyp->t_line].l_read) (ttyp);
- X}
- X
- X/* Write characters to the output buffer.
- X (called at SPL0)
- X*/
- Xvoid
- Xfaswrite (dev)
- Xdev_t dev;
- X{
- X register struct tty *ttyp REG_CX;
- X
- X ttyp = fas_internals_ptr [GET_UNIT (dev)]->tty;
- X
- X (void) (*linesw [(unchar) ttyp->t_line].l_write) (ttyp);
- X}
- X
- X/* Called by the TTY subsystem (not by FAS itself !) to process various
- X device-dependent operations.
- X (called at SPL0)
- X*/
- Xvoid
- Xfasproc (ttyp, cmd)
- Xregister struct tty *ttyp REG_SI;
- Xint cmd;
- X{
- X register struct fas_internals *fip REG_DI;
- X uint unit;
- X int old_level;
- X
- X fip = ((unit = ttyp - &fas_tty [0]) >= fas_physical_units)
- X ? fas_internals_ptr [unit - fas_physical_units]
- X : fas_internals_ptr [unit];
- X
- X old_level = SPLINT ();
- X
- X switch (cmd)
- X {
- X case T_TIME: /* timeout */
- X ttyp->t_state &= ~TIMEOUT;
- X EVENT_SCHED (fip, EF_DO_XXFER);
- X break;
- X
- X case T_OUTPUT: /* output characters to the transmitter */
- X if (fip->xmit_ring_size > fip->xmit_ring_cnt)
- X EVENT_SCHED (fip, EF_DO_XXFER);
- X break;
- X
- X case T_SUSPEND: /* suspend character output */
- X fip->flow_flags |= FF_SWO_STOPPED;
- X ttyp->t_state |= TTSTOP;
- X break;
- X
- X case T_RESUME: /* restart character output */
- X fip->flow_flags &= ~FF_SWO_STOPPED;
- X ttyp->t_state &= ~TTSTOP;
- X fas_xproc (fip);
- X break;
- X
- X case T_BLOCK: /* stop character input, request XOFF */
- X ttyp->t_state |= TBLOCK;
- X break; /* note: we do our own XON/XOFF */
- X
- X case T_UNBLOCK: /* restart character input, request XON */
- X ttyp->t_state &= ~TBLOCK;
- X break; /* note: we do our own XON/XOFF */
- X
- X case T_RFLUSH: /* flush input buffers and restart input */
- X if (DEVICE_TYPE == TYPE_NS16550A)
- X FAS_FIRST_OUTB (fip, NS_FIFO_CTL_PORT, FCR
- X | 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 fip->recv_ring_put_ptr = fip->recv_ring_take_ptr
- X = &fip->recv_buffer [0];
- X fip->recv_ring_cnt = 0;
- X ttyp->t_state &= ~TBLOCK;
- X
- X /* restart input */
- X if ((fip->flow_flags & (FF_HWI_HANDSHAKE | FF_HWI_STARTED))
- X == FF_HWI_HANDSHAKE)
- X {
- X FAS_OUTB (fip, MDM_CTL_PORT,
- X MCR |= fip->flow.m.ic);
- X fip->flow_flags |= FF_HWI_STARTED;
- X }
- X if ((fip->iflag & IXOFF)
- X && (fip->flow_flags & FF_SWI_STOPPED))
- X fas_send_xon (fip);
- X break;
- X
- X case T_WFLUSH: /* flush output buffer and restart output */
- X if (DEVICE_TYPE == TYPE_NS16550A)
- X FAS_FIRST_OUTB (fip, NS_FIFO_CTL_PORT, FCR
- X | NS_FIFO_CLR_XMIT);
- X else if (DEVICE_TYPE == TYPE_I82510)
- X {
- X FAS_FIRST_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 fip->xmit_ring_put_ptr = fip->xmit_ring_take_ptr
- X = &fip->xmit_buffer [0];
- X fip->xmit_ring_cnt = 0;
- X
- X ttyp->t_tbuf.c_size -= ttyp->t_tbuf.c_count;
- X ttyp->t_tbuf.c_count = 0;
- X
- X fip->flow_flags &= ~(FF_SWO_STOPPED | FF_SW_FC_REQ);
- X ttyp->t_state &= ~(TTSTOP | TTXON | TTXOFF);
- X
- X if ((fip->flow_flags & FF_OUTPUT_BUSY)
- X && !(fip->device_flags & (DF_XMIT_BUSY
- X | DF_GUARD_TIMEOUT
- X | DF_XMIT_BREAK)))
- X {
- X 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_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 break;
- X
- X case T_BREAK: /* do a break on the transmitter line */
- X fip->device_flags |= DF_XMIT_BREAK;
- X 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 | 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 if (fip->device_flags & (DF_XMIT_BUSY | DF_GUARD_TIMEOUT))
- X {
- X fip->device_flags |= DF_DO_BREAK;
- X }
- X else
- X {
- X /* set up break request flags */
- X FAS_FIRST_OUTB (fip, LINE_CTL_PORT,
- X LCR |= LC_SET_BREAK_LEVEL);
- X (void) timeout (fas_timeout, (caddr_t) fip,
- X (BREAK_TIME) * (HZ) / 1000);
- X }
- X break;
- X
- X case T_PARM: /* set up port according to termio structure */
- X fas_param (fip, SOFT_INIT);
- X break;
- X }
- X
- X (void) splx (old_level);
- X}
- X
- X/* Process ioctl calls.
- X (called at SPL0)
- X*/
- Xvoid
- Xfasioctl (dev, cmd, arg, mode)
- Xdev_t dev;
- Xint cmd;
- Xunion ioctl_arg arg;
- Xint mode;
- X{
- X register struct fas_internals *fip REG_SI;
- X register struct tty *ttyp REG_DI;
- X#if defined (HAVE_VPIX)
- X register int v86_cmd REG_BX;
- X int v86_data;
- X#if defined (SCO) || defined (XENIX)
- X struct termss termss;
- X#endif
- X n_unchar vpix_status;
- X unchar cpbyte;
- X#endif
- X int old_level;
- X
- X fip = fas_internals_ptr [GET_UNIT (dev)];
- X ttyp = fip->tty;
- X
- X /* process ioctl commands */
- X switch (cmd)
- X {
- X#if defined (HAVE_VPIX)
- X case AIOCINTTYPE: /* set pseudorupt type */
- X switch (arg.iarg)
- X {
- X case V86VI_KBD:
- X case V86VI_SERIAL0:
- X case V86VI_SERIAL1:
- X old_level = SPLINT ();
- X fip->v86_intmask = arg.iarg;
- X (void) splx (old_level);
- X break;
- X
- X default:
- X old_level = SPLINT ();
- X fip->v86_intmask = V86VI_SERIAL0;
- X (void) splx (old_level);
- X break;
- X }
- X break;
- X
- X case AIOCDOSMODE: /* enable dos mode */
- X if (!(fip->iflag & DOSMODE))
- X {
- X old_level = SPLINT ();
- X fip->v86_proc = u.u_procp->p_v86;
- X if (!(fip->v86_intmask))
- X fip->v86_intmask = V86VI_SERIAL0;
- X ttyp->t_iflag |= DOSMODE;
- X if (fip->v86_intmask != V86VI_KBD)
- X ttyp->t_cflag |= CLOCAL;
- X fas_param (fip, SOFT_INIT);
- X (void) splx (old_level);
- X }
- X u.u_rval1 = 0;
- X break;
- X
- X case AIOCNONDOSMODE: /* disable dos mode */
- X if (fip->iflag & DOSMODE)
- X {
- X old_level = SPLINT ();
- X fip->v86_proc = (v86_t *) NULL;
- X fip->v86_intmask = 0;
- X ttyp->t_iflag &= ~DOSMODE;
- X if (fip->flow_flags & FF_RXFER_STOPPED)
- X {
- X fip->flow_flags &= ~FF_RXFER_STOPPED;
- X /* schedule character transfer
- X to CLIST buffer
- X */
- X if (fip->recv_ring_cnt)
- X EVENT_SCHED (fip, EF_DO_RXFER);
- X }
- X LCR = 0;
- X fas_param (fip, HARD_INIT);
- X (void) splx (old_level);
- X }
- X u.u_rval1 = 0;
- X break;
- X
- X case AIOCSERIALOUT: /* setup port registers for dos */
- X if (fip->iflag & DOSMODE)
- X {
- X /* wait until output is done */
- X old_level = SPLINT ();
- X while ((fip->flow_flags & FF_OUTPUT_BUSY)
- X || ttyp->t_outq.c_cc
- X || (ttyp->t_state & TIMEOUT))
- X {
- X ttyp->t_state |= TTIOW;
- X (void) sleep ((caddr_t) &ttyp->t_oflag,
- X TTOPRI);
- X }
- X
- X /* block transmitter and wait until it is
- X empty
- X */
- X fip->device_flags |= DF_XMIT_LOCKED;
- X while (fip->device_flags & (DF_XMIT_BUSY
- X | DF_XMIT_BREAK
- X | DF_GUARD_TIMEOUT))
- X (void) sleep ((caddr_t) &fip->
- X device_flags,
- X PZERO - 1);
- X (void) splx (old_level);
- X
- X /* get port write command */
- X if (copyin (arg.cparg, &cpbyte, sizeof cpbyte)
- X == -1)
- X {
- X u.u_error = EFAULT;
- X goto restart_output;
- X }
- X v86_cmd = cpbyte;
- X /* set divisor lsb requested */
- X if (v86_cmd & SIO_MASK (SO_DIVLLSB))
- X {
- X if (copyin (arg.cparg + SO_DIVLLSB,
- X &cpbyte, sizeof cpbyte)
- X == -1)
- X {
- X u.u_error = EFAULT;
- X goto restart_output;
- X }
- X v86_data = cpbyte;
- X old_level = SPLINT ();
- X FAS_FIRST_OUTB (fip, LINE_CTL_PORT, LCR
- X | LC_ENABLE_DIVISOR);
- X FAS_OUTB (fip, DIVISOR_LSB_PORT, v86_data);
- X FAS_OUTB (fip, LINE_CTL_PORT, LCR);
- X (void) splx (old_level);
- X }
- X /* set divisor msb requested */
- X if (v86_cmd & SIO_MASK (SO_DIVLMSB))
- X {
- X if (copyin (arg.cparg + SO_DIVLMSB,
- X &cpbyte, sizeof cpbyte)
- X == -1)
- X {
- X u.u_error = EFAULT;
- X goto restart_output;
- X }
- X v86_data = cpbyte;
- X old_level = SPLINT ();
- X FAS_FIRST_OUTB (fip, LINE_CTL_PORT, LCR
- X | LC_ENABLE_DIVISOR);
- X FAS_OUTB (fip, DIVISOR_MSB_PORT, v86_data);
- X FAS_OUTB (fip, LINE_CTL_PORT, LCR);
- X (void) splx (old_level);
- X }
- X /* set lcr requested */
- X if (v86_cmd & SIO_MASK (SO_LCR))
- X {
- X if (copyin (arg.cparg + SO_LCR,
- X &cpbyte, sizeof cpbyte)
- X == -1)
- X {
- X u.u_error = EFAULT;
- X goto restart_output;
- X }
- X v86_data = cpbyte;
- X old_level = SPLINT ();
- X FAS_FIRST_OUTB (fip, LINE_CTL_PORT,
- X LCR = v86_data
- X & ~LC_ENABLE_DIVISOR);
- X (void) splx (old_level);
- X }
- X /* set mcr requested */
- X if (v86_cmd & SIO_MASK (SO_MCR))
- X {
- X if (copyin (arg.cparg + SO_MCR,
- X &cpbyte, sizeof cpbyte)
- X == -1)
- X {
- X u.u_error = EFAULT;
- X goto restart_output;
- X }
- X v86_data = cpbyte;
- X old_level = SPLINT ();
- X /* virtual dtr processing */
- X if ((v86_data & MC_SET_DTR)
- X && (fip->flow_flags
- X & FF_CD_ENABLED))
- X {
- X MCR |= (fip->o_state
- X & OS_WAIT_OPEN)
- X ? fip->modem.m.ei
- X : fip->modem.m.eo;
- X }
- X else
- X {
- X MCR &= (fip->o_state
- X & OS_WAIT_OPEN)
- X ? ~fip->modem.m.ei
- X : ~fip->modem.m.eo;
- X }
- X /* virtual rts processing */
- X if (fip->flow_flags
- X & FF_HWI_HANDSHAKE)
- X {
- X if (v86_data & MC_SET_RTS)
- X {
- X if (fip->flow_flags
- X & FF_RXFER_STOPPED)
- X {
- X fip->flow_flags
- X &= ~FF_RXFER_STOPPED;
- X /* schedule character transfer
- X to CLIST buffer
- X */
- X if (fip->recv_ring_cnt)
- X EVENT_SCHED (fip,
- X EF_DO_RXFER);
- X }
- X }
- X else
- X fip->flow_flags
- X |= FF_RXFER_STOPPED;
- X }
- X else if (!(fip->flow_flags
- X & FF_HDX_HANDSHAKE))
- X {
- X if (v86_data & MC_SET_RTS)
- X MCR |= fip->flow.m.hc;
- X else
- X MCR &= ~fip->flow.m.hc;
- X }
- X FAS_FIRST_OUTB (fip, MDM_CTL_PORT, MCR);
- X (void) splx (old_level);
- X }
- X
- Xrestart_output:
- X old_level = SPLINT ();
- X /* enable transmitter and restart output */
- X fip->device_flags &= ~DF_XMIT_LOCKED;
- X fas_xproc (fip);
- X (void) splx (old_level);
- X }
- X break;
- X
- X case AIOCSERIALIN: /* read port registers for dos */
- X if (fip->iflag & DOSMODE)
- X {
- X if (copyin (arg.cparg, &cpbyte, sizeof cpbyte)
- X == -1)
- X {
- X u.u_error = EFAULT;
- X break;
- X }
- X v86_cmd = cpbyte;
- X if (v86_cmd & SIO_MASK (SI_MSR))
- X {
- X vpix_status = MSR & MS_ANY_PRESENT;
- X if (fip->flow_flags
- X & FF_HWO_HANDSHAKE)
- X vpix_status |= fip->flow.m.oc
- X | fip->flow.m.oe;
- X if (!(fip->cflag & CLOCAL))
- X vpix_status |= fip->modem.m.ca;
- X cpbyte = vpix_status;
- X if (copyout (&cpbyte,
- X arg.cparg + SI_MSR,
- X sizeof cpbyte)
- X == -1)
- X {
- X u.u_error = EFAULT;
- X break;
- X }
- X }
- X }
- X break;
- X
- X case AIOCSETSS: /* set start/stop characters */
- X#if defined (SCO) || defined (XENIX)
- X /* SCO UNIX and Xenix pass a pointer to struct termss */
- X if (copyin (arg.cparg, &termss, sizeof termss)
- X == -1)
- X {
- X u.u_error = EFAULT;
- X break;
- X }
- X#define GET_TERMSS(member) (termss.member)
- X#else
- X /* The rest of the world passes struct termss */
- X#define GET_TERMSS(member) (((struct termss *) &arg.iarg)->member)
- X#endif
- X old_level = SPLINT ();
- X fip->start_char = GET_TERMSS (ss_start);
- X fip->stop_char = GET_TERMSS (ss_stop);
- X (void) splx (old_level);
- X break;
- X
- X case AIOCINFO: /* show what type of device we are */
- X u.u_rval1 = ('a' << 8) | GET_UNIT (dev);
- X break;
- X#endif
- X#if defined (RTS_TOG)
- X case RTS_TOG: /* set hardware handshake output */
- X if (arg.iarg == 0)
- X {
- X /* low level */
- X old_level = SPLINT ();
- X /* set hardware handshake output only if unused
- X otherwise
- X */
- X if (!(fip->flow_flags & (FF_HWI_HANDSHAKE
- X | FF_HDX_HANDSHAKE
- X | FF_DEF_HHO_LOW))
- X#if defined (HAVE_VPIX)
- X && !(fip->iflag & DOSMODE)
- X#endif
- X )
- X {
- X /* block transmitter and wait until it is
- X empty
- X */
- X fip->device_flags |= DF_XMIT_LOCKED;
- X while (fip->device_flags & (DF_XMIT_BUSY
- X | DF_XMIT_BREAK
- X | DF_GUARD_TIMEOUT))
- X (void) sleep ((caddr_t) &fip->
- X device_flags,
- X PZERO - 1);
- X /* suspend character output */
- X fip->flow_flags |= FF_SWO_STOPPED;
- X ttyp->t_state |= TTSTOP;
- X FAS_FIRST_OUTB (fip, MDM_CTL_PORT,
- X MCR &= ~fip->flow.m.hc);
- X /* enable transmitter and restart output */
- X fip->device_flags &= ~DF_XMIT_LOCKED;
- X fas_xproc (fip);
- X }
- X fip->flow_flags |= FF_DEF_HHO_LOW;
- X (void) splx (old_level);
- X }
- X else if (arg.iarg == 1)
- X {
- X /* high level */
- X old_level = SPLINT ();
- X /* set hardware handshake output only if unused
- X otherwise
- X */
- X if ((fip->flow_flags & (FF_HWI_HANDSHAKE
- X | FF_HDX_HANDSHAKE
- X | FF_DEF_HHO_LOW))
- X == FF_DEF_HHO_LOW
- X#if defined (HAVE_VPIX)
- X && !(fip->iflag & DOSMODE)
- X#endif
- X )
- X {
- X /* restart character output */
- X fip->flow_flags &= ~FF_SWO_STOPPED;
- X ttyp->t_state &= ~TTSTOP;
- X FAS_FIRST_OUTB (fip, MDM_CTL_PORT,
- X MCR |= fip->flow.m.hc);
- X fas_xproc (fip);
- X }
- X fip->flow_flags &= ~FF_DEF_HHO_LOW;
- X (void) splx (old_level);
- X }
- X break;
- X#endif
- X default: /* default ioctl processing */
- X /* If it is a TCSETA* command, call fas_param ().
- X There is a bug in ttiocom with TCSELE. It
- X always tells the tty driver to reprogram the
- X port. This will cause lost input characters.
- X So we don't do it. SCO UNIX and Xenix use
- X IOC_SELECT instead of TCSELE!
- X */
- X old_level = SPLWRK ();
- X#if defined (TCSELE)
- X if (ttiocom (ttyp, cmd, arg, mode) && cmd != TCSELE)
- X#else
- X#if defined (IOC_SELECT)
- X if (ttiocom (ttyp, cmd, arg, mode)
- X && cmd != IOC_SELECT)
- X#else
- X if (ttiocom (ttyp, cmd, arg, mode))
- X#endif
- X#endif
- X {
- X /* reprogram the port */
- X (void) SPLINT ();
- X fas_param (fip, SOFT_INIT);
- X }
- X (void) splx (old_level);
- X break;
- X }
- X}
- X
- X/* Main FAS interrupt handler. Actual character processing is splitted
- X into sub-functions.
- X (called at SPLINT)
- X*/
- Xvoid
- Xfasintr (vect)
- Xint vect;
- X{
- X register struct fas_internals *fip REG_SI;
- X uint num_polls;
- X bool was_rint, was_xint, was_mint, do_xproc;
- X
- X fip = fas_first_int_user;
- X if (!fip)
- X return; /* false alarm: must be a spurious int */
- X
- X was_rint = FALSE;
- X was_xint = FALSE;
- X was_mint = FALSE;
- X
- X {
- X register uint poll_cnt REG_DI;
- X
- X poll_cnt = 1;
- X
- X /* Loop through all users of the interrupt users chain
- X and look for characters in the receiver buffer.
- X We poll the line status register regardless of
- X whether the UART has interrupted or not. This
- X synchronizes concurrently running receiver FIFOs
- X and dramatically reduces the overall interrupt
- X frequency.
- X */
- X do
- X {
- X register n_unchar lstatus REG_BX;
- Xfastloop1:
- X /* read in all characters from all UARTs */
- X if (!(fip->device_flags & DF_RDI_ENABLED)
- X || !((lstatus = FAS_FIRST_INB (fip, LINE_STATUS_PORT))
- X & LS_RCV_AVAIL))
- X {
- X /* speed beats beauty */
- X fip = fip->next_int_user;
- X ++poll_cnt;
- X if (fip)
- X goto fastloop1;
- X break;
- X }
- X
- X /* do the character processing */
- X (void) fas_rproc (fip, lstatus);
- X was_rint = TRUE;
- X fip = fip->next_int_user;
- X ++poll_cnt;
- X } while (fip);
- X
- X /* Save the number of UARTs we have to poll to be sure that
- X there are no further pending interrupts.
- X */
- X num_polls = poll_cnt;
- X
- X /* The 8259 interrupt controller is set up for edge trigger.
- X Therefore, we must loop until we make a complete pass without
- X getting any UARTs that are interrupting.
- X */
- X for (;;)
- X {
- Xfastloop2:
- X if (!fip)
- X fip = fas_first_int_user; /* wrap around */
- X
- X /* process only ports that have an interrupt
- X pending
- X */
- X if (FAS_FIRST_INB (fip, INT_ID_PORT) & II_NO_INTS_PENDING)
- X {
- X /* speed beats beauty */
- X fip = fip->next_int_user;
- X if (--poll_cnt)
- X goto fastloop2;
- X break;
- X }
- X
- X {
- X register n_unchar mstatus REG_BX;
- X
- X /* Has there been a polarity change on
- X some of the modem lines ?
- X */
- X if ((fip->device_flags & DF_MSI_ENABLED)
- X && ((mstatus = FAS_INB (fip, MDM_STATUS_PORT))
- X & MS_ANY_DELTA))
- X {
- X /* if the same modem status line
- X is responsible for a modem status
- X interrupt twice during two
- X event scheduler runs, we disable
- X modem status interrupts until we
- X process this interrupt in the event
- X scheduler
- X */
- X if (mstatus & NEW_MSR & MS_ANY_DELTA)
- X {
- X FAS_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 ++fas_msi_noise;
- X }
- X /* Do special RING line handling.
- X RING generates an int only on the
- X trailing edge.
- X */
- X mstatus = (mstatus & ~MS_RING_PRESENT)
- X | (NEW_MSR & MS_RING_PRESENT);
- X if (mstatus & MS_RING_TEDGE)
- X mstatus |= MS_RING_PRESENT;
- X if ((mstatus ^ NEW_MSR) & MS_ANY_PRESENT)
- X {
- X do_xproc = FALSE;
- X /* check hw flow flags */
- X if (!(~mstatus & fip->flow.m.oc)
- X || (~mstatus & fip->flow.m.oe)
- X || !(fip->flow_flags
- X & FF_HWO_HANDSHAKE))
- X {
- X if (fip->flow_flags & FF_HWO_STOPPED)
- X {
- X fip->flow_flags &= ~FF_HWO_STOPPED;
- X do_xproc = TRUE;
- X }
- X }
- X else
- X fip->flow_flags |= FF_HWO_STOPPED;
- X /* check carrier detect
- X note: the actual carrier detect
- X processing is done in fas_mproc ()
- X */
- X if (!(fip->cflag & CLOCAL)
- X && (fip->flow_flags & FF_CARRIER_ON))
- X {
- X if (!(~mstatus & fip->modem.m.ca))
- X {
- X if (fip->flow_flags & FF_CARR_STOPPED)
- X {
- X fip->flow_flags &= ~FF_CARR_STOPPED;
- X do_xproc = TRUE;
- X }
- X }
- X else if (!(~NEW_MSR & fip->modem.m.ca))
- X fip->flow_flags |= FF_CARR_STOPPED;
- X }
- X if (do_xproc)
- X fas_xproc (fip);
- X EVENT_SCHED (fip, EF_DO_MPROC);
- X }
- X else
- X EVENT_SCHED (fip, EF_RESET_DELTA_BITS);
- X /* "or" the delta flags to prevent
- X excessive modem status interrupts
- X */
- X NEW_MSR = mstatus | (NEW_MSR & MS_ANY_DELTA);
- X was_mint = TRUE;
- X }
- X }
- X
- X {
- X register n_unchar lstatus REG_BX;
- X
- X lstatus = FAS_INB (fip, LINE_STATUS_PORT);
- X
- X /* Is it a receiver int ? */
- X if ((lstatus & LS_RCV_AVAIL)
- X && (fip->device_flags & DF_RDI_ENABLED))
- X {
- X /* do the character processing */
- X lstatus = fas_rproc (fip, lstatus);
- X was_rint = TRUE;
- X }
- X
- X /* Is it a transmitter int ? */
- X if (lstatus & LS_XMIT_AVAIL)
- X {
- X if (fip->device_flags & DF_XMIT_BUSY)
- X {
- X fip->device_flags &= ~DF_XMIT_BUSY;
- X /* do the character processing */
- X fas_xproc (fip);
- X if (!(fip->device_flags & DF_XMIT_BUSY))
- X {
- X fip->device_flags |= DF_GUARD_TIMEOUT;
- X fip->timeout_idx
- X = timeout (fas_timeout, (caddr_t) fip,
- X fas_speed_ptr [BT_SELECT]
- X [fip->cflag & CBAUD]
- X .i.ctime);
- X }
- X was_xint = TRUE;
- X }
- X }
- X }
- X
- X fip = fip->next_int_user;
- X poll_cnt = num_polls; /* reset counter as there was work */
- X }
- X }
- X
- X {
- X register uint *seq_ptr REG_DI;
- X register uint port REG_BX;
- X
- X /* execute the interrupt acknowledge sequence for the
- X serial cards
- X */
- X seq_ptr = &fas_int_ack_seq [0];
- X port = *seq_ptr;
- X if (port)
- X {
- X do
- X {
- X if (*(seq_ptr + 1) & READ_PORT)
- X (void) INB (port);
- X else
- X (void) OUTB (port, *(seq_ptr + 1));
- X port = *(seq_ptr += 2);
- X } while (port);
- X }
- X }
- X
- X /* provide statistical infos */
- X if (was_rint)
- X ++sysinfo.rcvint;
- X if (was_xint)
- X ++sysinfo.xmtint;
- X if (was_mint)
- X ++sysinfo.mdmint;
- X}
- X
- X/* Receiver interrupt handler. Translates input characters to character
- X sequences as described in TERMIO(7) man page.
- X (called at SPLINT)
- X*/
- XSTATIC n_unchar
- Xfas_rproc (fip, line_status)
- Xregister struct fas_internals *fip REG_SI;
- Xn_unchar line_status;
- X{
- X register unchar *ring_ptr REG_DI;
- X register n_unchar charac REG_BX;
- X
- X /* Was there a receiver overrun ? Count them in a
- X separate counter for each UART type.
- X */
- X if (line_status & LS_OVERRUN)
- X ++fas_overrun [DEVICE_TYPE];
- X
- X ring_ptr = fip->recv_ring_put_ptr;
- X
- X /* Translate characters from FIFO according to the TERMIO(7)
- X man page.
- X */
- X do
- X {
- X /* ignore parity errors ? */
- X if (!(fip->iflag & INPCK))
- X line_status &= ~LS_PARITY_ERROR;
- X
- X charac = FAS_INB (fip, RCV_DATA_PORT);
- X
- X if (fip->iflag & ISTRIP) /* strip off 8th bit ? */
- X charac &= 0x7f;
- X
- X /* do we have some kind of character error ? */
- X if (line_status & (LS_PARITY_ERROR
- X | LS_FRAMING_ERROR
- X | LS_BREAK_DETECTED))
- X {
- X#if defined (HAVE_VPIX)
- X if (fip->iflag & DOSMODE)
- X {
- X if (fip->iflag & PARMRK)
- X {
- X /* send status bits to VP/ix */
- X if (fip->recv_ring_cnt < RECV_BUFF_SIZE - 2)
- X {
- X fip->recv_ring_cnt += 3;
- X PUT_RECV_BUFFER (fip, ring_ptr, 0xff);
- X PUT_RECV_BUFFER (fip, ring_ptr, 1);
- X PUT_RECV_BUFFER (fip, ring_ptr,
- X (line_status & (LS_PARITY_ERROR
- X | LS_FRAMING_ERROR
- X | LS_BREAK_DETECTED))
- X | LS_RCV_AVAIL
- X | LS_XMIT_AVAIL
- X | LS_XMIT_COMPLETE);
- X }
- X }
- X goto valid_char;
- X }
- X else
- X#endif
- X /* is it a BREAK ? */
- X if (line_status & LS_BREAK_DETECTED)
- X {
- X if (!(fip->iflag & IGNBRK))
- X {
- X if (fip->iflag & BRKINT)
- X {
- X /* do BREAK interrupt */
- X EVENT_SCHED (fip, EF_DO_BRKINT);
- X }
- X else if (fip->iflag & PARMRK)
- X {
- X if (fip->recv_ring_cnt
- X < RECV_BUFF_SIZE - 2)
- X {
- X fip->recv_ring_cnt += 3;
- X PUT_RECV_BUFFER (fip,
- X ring_ptr,
- X 0xff);
- X PUT_RECV_BUFFER (fip,
- X ring_ptr,
- X 0);
- X PUT_RECV_BUFFER (fip,
- X ring_ptr,
- X 0);
- X }
- X }
- X else
- X {
- X if (fip->recv_ring_cnt
- X < RECV_BUFF_SIZE)
- X {
- X ++fip->recv_ring_cnt;
- X PUT_RECV_BUFFER (fip,
- X ring_ptr,
- X 0);
- X }
- X }
- X }
- X }
- X else if (!(fip->iflag & IGNPAR))
- X if (fip->iflag & PARMRK)
- X {
- X if (fip->recv_ring_cnt
- X < RECV_BUFF_SIZE - 2)
- X {
- X fip->recv_ring_cnt += 3;
- X PUT_RECV_BUFFER (fip, ring_ptr,
- X 0xff);
- X PUT_RECV_BUFFER (fip, ring_ptr,
- X 0);
- X PUT_RECV_BUFFER (fip, ring_ptr,
- X charac);
- X }
- X }
- X else
- X {
- X if (fip->recv_ring_cnt
- X < RECV_BUFF_SIZE)
- X {
- X ++fip->recv_ring_cnt;
- X PUT_RECV_BUFFER (fip, ring_ptr,
- X 0);
- X }
- X }
- X }
- X else
- X {
- X if (fip->iflag & IXON)
- X {
- X /* do output start/stop handling */
- X if (fip->flow_flags & FF_SWO_STOPPED)
- X {
- X if ((charac == fip->start_char)
- X || (fip->iflag & IXANY))
- X {
- X fip->flow_flags &=
- X ~FF_SWO_STOPPED;
- X fip->tty->t_state &= ~TTSTOP;
- X /* restart output */
- X fas_xproc (fip);
- X }
- X }
- X else
- X {
- X if (charac == fip->stop_char)
- X {
- X fip->flow_flags |=
- X FF_SWO_STOPPED;
- X fip->tty->t_state |= TTSTOP;
- X }
- X }
- X /* we don't put start/stop characters
- X into the receiver buffer
- X */
- X if ((charac == fip->start_char)
- 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 > 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 > 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
- X == &fip->xmit_buffer [XMIT_BUFF_SIZE])
- X break;
- X } while (--num_to_output);
- X if (!num_to_output)
- X break;
- X ring_ptr = &fip->xmit_buffer [0];
- 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_size > 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 = &fip->recv_buffer [0];
- X fip->recv_ring_cnt = 0;
- X fip->xmit_ring_put_ptr = fip->xmit_ring_take_ptr
- X = &fip->xmit_buffer [0];
- 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 /* drop flow control lines */
- X FAS_OUTB (fip, MDM_CTL_PORT,
- X MCR &= (fip->o_state & OS_HWI_HANDSHAKE)
- X ? ~fip->flow.m.ic
- X : ~fip->flow.m.hc);
- 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_size = 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;
- SHAR_EOF
- true || echo 'restore of fas.c failed'
- fi
- echo 'End of part 5'
- echo 'File fas.c is continued in part 6'
- echo 6 > _shar_seq_.tmp
- exit 0
-