summaryrefslogtreecommitdiffstats
path: root/sys/dev/sx/sx.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sx/sx.c')
-rw-r--r--sys/dev/sx/sx.c1388
1 files changed, 0 insertions, 1388 deletions
diff --git a/sys/dev/sx/sx.c b/sys/dev/sx/sx.c
deleted file mode 100644
index 8821c37..0000000
--- a/sys/dev/sx/sx.c
+++ /dev/null
@@ -1,1388 +0,0 @@
-/*-
- * Device tsfsdriver for Specialix I/O8+ multiport serial card.
- *
- * Copyright 2003 Frank Mayhar <frank@exit.com>
- *
- * Derived from the "si" driver by Peter Wemm <peter@netplex.com.au>, using
- * lots of information from the Linux "specialix" driver by Roger Wolff
- * <R.E.Wolff@BitWizard.nl> and from the Intel CD1865 "Intelligent Eight-
- * Channel Communications Controller" datasheet. Roger was also nice
- * enough to answer numerous questions about stuff specific to the I/O8+
- * not covered by the CD1865 datasheet.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notices, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notices, this list of conditions and the foljxowing disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHORS BE LIABLE.
- *
- * $FreeBSD$
- */
-
-
-/* Main tty driver routines for the Specialix I/O8+ device driver. */
-
-#include "opt_compat.h"
-#include "opt_debug_sx.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/callout.h>
-#include <sys/conf.h>
-#include <sys/proc.h>
-#include <sys/conf.h>
-#include <sys/fcntl.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/serial.h>
-#include <sys/sysctl.h>
-#include <sys/tty.h>
-
-#include <sys/bus.h>
-#include <machine/bus.h>
-#include <sys/rman.h>
-#include <machine/resource.h>
-
-#include <machine/stdarg.h>
-
-#include <dev/sx/cd1865.h>
-#include <dev/sx/sxvar.h>
-#include <dev/sx/sx.h>
-#include <dev/sx/sx_util.h>
-
-#define SX_BROKEN_CTS
-
-
-static t_modem_t sx_modem;
-static void sx_start(struct tty *);
-static void sx_stop(struct tty *, int);
-static t_close_t sxclose;
-static t_open_t sxopen;
-static void sx_shutdown_chan(struct sx_port *);
-
-static t_break_t sxbreak;
-
-static int sxparam(struct tty *, struct termios *);
-
-static void sx_modem_state(struct sx_softc *sc, struct sx_port *pp, int card);
-
-static int sx_debug = 0; /* DBG_ALL|DBG_PRINTF|DBG_MODEM|DBG_IOCTL|DBG_PARAM;e */
-SYSCTL_INT(_machdep, OID_AUTO, sx_debug, CTLFLAG_RW, &sx_debug, 0, "");
-
-static int sx_numunits;
-
-devclass_t sx_devclass;
-
-/*
- * See sx.h for these values.
- */
-static struct speedtab bdrates[] = {
- { B75, CLK75, },
- { B110, CLK110, },
- { B150, CLK150, },
- { B300, CLK300, },
- { B600, CLK600, },
- { B1200, CLK1200, },
- { B2400, CLK2400, },
- { B4800, CLK4800, },
- { B9600, CLK9600, },
- { B19200, CLK19200, },
- { B38400, CLK38400, },
- { B57600, CLK57600, },
- { B115200, CLK115200, },
- { -1, -1 },
-};
-
-
-/*
- * Approximate (rounded) character per second rates. Translated at card
- * initialization time to characters per clock tick.
- */
-static int done_chartimes = 0;
-static struct speedtab chartimes[] = {
- { B75, 8, },
- { B110, 11, },
- { B150, 15, },
- { B300, 30, },
- { B600, 60, },
- { B1200, 120, },
- { B2400, 240, },
- { B4800, 480, },
- { B9600, 960, },
- { B19200, 1920, },
- { B38400, 3840, },
- { B57600, 5760, },
- { B115200, 11520, },
- { -1, -1 },
-};
-static volatile int in_interrupt = 0; /* Inside interrupt handler? */
-
-static int sx_flags; /* The flags we were configured with. */
-SYSCTL_INT(_machdep, OID_AUTO, sx_flags, CTLFLAG_RW, &sx_flags, 0, "");
-
-#ifdef POLL
-static int sx_pollrate; /* in addition to irq */
-static int sx_realpoll = 0; /* poll HW on timer */
-
-SYSCTL_INT(_machdep, OID_AUTO, sx_pollrate, CTLFLAG_RW, &sx_pollrate, 0, "");
-SYSCTL_INT(_machdep, OID_AUTO, sx_realpoll, CTLFLAG_RW, &sx_realpoll, 0, "");
-
-static int init_finished = 0;
-static void sx_poll(void *);
-#endif
-
-/*
- * sxattach()
- * Initialize and attach the card, initialize the driver.
- *
- * Description:
- * This is the standard attach routine. It initializes the I/O8+
- * card, identifies the chip on that card, then allocates and
- * initializes the various data structures used by the driver
- * itself.
- */
-int
-sxattach(
- device_t dev)
-{
- int unit;
- struct sx_softc *sc;
- struct tty *tp;
- struct speedtab *spt;
- int chip, x;
- char rev;
- int error;
-
- sc = device_get_softc(dev);
- unit = device_get_unit(dev);
- sx_flags = device_get_flags(dev);
-
- if (sx_numunits < unit + 1)
- sx_numunits = unit + 1;
-
- DPRINT((0, DBG_AUTOBOOT, "sx%d: sxattach\n", unit));
-
- /* Reset the CD1865. */
- if ((error = sx_init_cd1865(sc, unit)) != 0) {
- return(error);
- }
-
- /*
- * ID the chip:
- *
- * Chip revcode pkgtype
- * GFRCR SRCR bit 7
- * CD180 rev B 0x81 0
- * CD180 rev C 0x82 0
- * CD1864 rev A 0x82 1
- * CD1865 rev A 0x83 1 -- Do not use!!! Does not work.
- * CD1865 rev B 0x84 1
- * -- Thanks to Gwen Wang, Cirrus Logic (via Roger Wollf).
- */
- switch (sx_cd1865_in(sc, CD1865_GFRCR)) {
- case 0x82:
- chip = 1864;
- rev = 'A';
- break;
- case 0x83:
- chip = 1865;
- rev = 'A';
- break;
- case 0x84:
- chip = 1865;
- rev = 'B';
- break;
- case 0x85:
- chip = 1865;
- rev = 'C';
- break;
- default:
- chip = -1;
- rev = '\0';
- break;
- }
-
- if (bootverbose && chip != -1)
- printf("sx%d: Specialix I/O8+ CD%d processor rev %c\n",
- unit, chip, rev);
- DPRINT((0, DBG_AUTOBOOT, "sx%d: GFRCR 0x%02x\n",
- unit, sx_cd1865_in(sc, CD1865_GFRCR)));
-#ifdef POLL
- if (sx_pollrate == 0) {
- sx_pollrate = POLLHZ; /* in addition to irq */
-#ifdef REALPOLL
- sx_realpoll = 1; /* scan always */
-#endif
- }
-#endif
- sc->sc_ports = (struct sx_port *)malloc(
- sizeof(struct sx_port) * SX_NUMCHANS,
- M_DEVBUF,
- M_NOWAIT);
- if (sc->sc_ports == NULL) {
- printf("sx%d: No memory for sx_port structs!\n", unit);
- return(EINVAL);
- }
- bzero(sc->sc_ports, sizeof(struct sx_port) * SX_NUMCHANS);
- /*
- * Initialize the channels.
- */
- for (x = 0; x < SX_NUMCHANS; x++) {
- tp = ttyalloc();
- tp->t_oproc = sx_start;
- tp->t_stop = sx_stop;
- tp->t_param = sxparam;
- tp->t_break = sxbreak;
- tp->t_open = sxopen;
- tp->t_close = sxclose;
- sc->sc_ports[x].sp_tty = tp;
- sc->sc_ports[x].sp_state = 0; /* internal flag */
- sc->sc_ports[x].sp_chan = x;
- sc->sc_ports[x].sp_sc = sc;
- tp->t_sc = &sc->sc_ports[x];
- ttycreate(tp, NULL, 0, MINOR_CALLOUT, "G%r%r", unit, x);
- }
- if (done_chartimes == 0) {
- for (spt = chartimes ; spt->sp_speed != -1; spt++) {
- if ((spt->sp_code /= hz) == 0)
- spt->sp_code = 1;
- }
- done_chartimes = 1;
- }
- return (0);
-}
-
-static int
-sxopen(struct tty *tp, struct cdev *dev)
-{
-
-#ifdef POLL
- /*
- * We've now got a device, so start the poller.
- */
- if (init_finished == 0) {
- timeout(sx_poll, (caddr_t)0L, sx_pollrate);
- init_finished = 1;
- }
-#endif
- return (0);
-}
-
-/*
- * sxclose()
- * Do hard-close processing.
- *
- * Description:
- * Called on last close. Handle DTR and RTS, do cleanup. If we have
- * pending output in the FIFO, wait for it to clear before we shut down
- * the hardware.
- */
-static void
-sxclose(struct tty *tp)
-{
- struct sx_port *pp;
- struct sx_softc *sc;
- int oldspl, dcd;
-
- oldspl = spltty();
-
- pp = tp->t_sc;
- DPRINT((pp, DBG_CLOSE, "sxhardclose sp_state:%x\n", pp->sp_state));
- sc = pp->sp_sc;
- dcd = sx_modem(tp, 0, 0) & SER_DCD;
- if (tp->t_cflag & HUPCL ||
- (!tp->t_actout && !dcd && !(tp->t_init_in.c_cflag && CLOCAL)) ||
- !(tp->t_state & TS_ISOPEN)) {
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR, pp->sp_chan);
- if (sx_cd1865_in(sc, CD1865_IER|SX_EI) & CD1865_IER_TXRDY) {
- sx_cd1865_bic(sc, CD1865_IER, CD1865_IER_TXRDY);
- sx_cd1865_bis(sc, CD1865_IER, CD1865_IER_TXEMPTY);
- enable_intr();
- splx(oldspl);
- ttysleep(tp, (caddr_t)pp,
- TTOPRI|PCATCH, "sxclose", tp->t_timeout);
- oldspl = spltty();
- }
- else {
- enable_intr();
- }
- (void)sx_modem(tp, 0, SER_DTR | SER_RTS);
-
- }
- (void)sx_shutdown_chan(pp); /* Turn off the hardware. */
- tp->t_actout = FALSE;
- wakeup((caddr_t)&tp->t_actout);
- wakeup(TSA_CARR_ON(tp));
-
- splx(oldspl);
-}
-
-
-static void
-sxbreak(struct tty *tp, int sig)
-{
- struct sx_port *pp;
-
- pp = tp->t_sc;
- if (sig) {
- /*
- * If there's already a break state change pending or
- * we're already sending a break, just ignore this.
- * Otherwise, just set our flag and start the
- * transmitter.
- */
- if (!SX_DOBRK(pp) && !SX_BREAK(pp)) {
- pp->sp_state |= SX_SS_DOBRK;
- sx_start(tp);
- }
- } else {
- /*
- * If a break is going, set our flag so we turn it off
- * when we can, then kick the transmitter. If a break
- * isn't going and the flag is set, turn it off.
- */
- if (SX_BREAK(pp)) {
- pp->sp_state |= SX_SS_DOBRK;
- sx_start(tp);
- }
- else {
- if (SX_DOBRK(pp))
- pp->sp_state &= SX_SS_DOBRK;
- }
- }
-}
-
-/*
- * sxparam()
- * Configure line parameters.
- *
- * Description:
- * Configure the bitrate, wordsize, flow control and various other serial
- * port parameters for this line.
- *
- * Environment:
- * Called at spltty(); this may sleep, does not flush nor wait for drain,
- * nor block writes. Caller must arrange this if it's important..
- */
-static int
-sxparam(
- struct tty *tp,
- struct termios *t)
-{
- struct sx_softc *sc;
- struct sx_port *pp = tp->t_sc;
- int oldspl, cflag, iflag, oflag, lflag;
- int error = 0;
- int ispd = 0;
- int ospd = 0;
- unsigned char val, cor1, cor2, cor3, ier;
-
- sc = pp->sp_sc;
- DPRINT((pp, DBG_ENTRY|DBG_PARAM, "sxparam %x/%x\n", tp, t));
- cflag = t->c_cflag;
- iflag = t->c_iflag;
- oflag = t->c_oflag;
- lflag = t->c_lflag;
- DPRINT((pp, DBG_PARAM, "OF 0x%x CF 0x%x IF 0x%x LF 0x%x\n",
- oflag, cflag, iflag, lflag));
-
- /* If the port isn't hung up... */
- if (t->c_ospeed != 0) {
- /* Convert bit rate to hardware divisor values. */
- ospd = ttspeedtab(t->c_ospeed, bdrates);
- ispd = t->c_ispeed ? ttspeedtab(t->c_ispeed, bdrates) : ospd;
- /* We only allow standard bit rates. */
- if (ospd < 0 || ispd < 0)
- return(EINVAL);
- }
- oldspl = spltty(); /* Block other activity. */
- cor1 = 0;
- cor2 = 0;
- cor3 = 0;
- ier = CD1865_IER_RXD | CD1865_IER_CD;
-#ifdef notyet
- /* We don't yet handle this stuff. */
- val = 0;
- if (iflag & IGNBRK) /* Breaks */
- val |= BR_IGN;
- if (iflag & BRKINT) /* Interrupt on break? */
- val |= BR_INT;
- if (iflag & PARMRK) /* Parity mark? */
- val |= BR_PARMRK;
-#endif /* notyet */
- /*
- * If the device isn't hung up, set the serial port bitrates.
- */
- if (t->c_ospeed != 0) {
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan);
- sx_cd1865_out(sc, CD1865_RBPRH|SX_EI, (ispd >> 8) & 0xff);
- sx_cd1865_out(sc, CD1865_RBPRL|SX_EI, ispd & 0xff);
- sx_cd1865_out(sc, CD1865_TBPRH|SX_EI, (ospd >> 8) & 0xff);
- sx_cd1865_out(sc, CD1865_TBPRL|SX_EI, ospd & 0xff);
- enable_intr();
- }
- if (cflag & CSTOPB) /* Two stop bits? */
- cor1 |= CD1865_COR1_2SB; /* Yep. */
- /*
- * Parity settings.
- */
- val = 0;
- if (cflag & PARENB) { /* Parity enabled? */
- val = CD1865_COR1_NORMPAR; /* Turn on normal parity handling. */
- if (cflag & PARODD) /* Odd Parity? */
- val |= CD1865_COR1_ODDP; /* Turn it on. */
- }
- else
- val = CD1865_COR1_NOPAR; /* Turn off parity detection. */
- cor1 |= val;
- if (iflag & IGNPAR) /* Ignore chars with parity errors? */
- cor1 |= CD1865_COR1_IGNORE;
- /*
- * Set word length.
- */
- if ((cflag & CS8) == CS8)
- val = CD1865_COR1_8BITS;
- else if ((cflag & CS7) == CS7)
- val = CD1865_COR1_7BITS;
- else if ((cflag & CS6) == CS6)
- val = CD1865_COR1_6BITS;
- else
- val = CD1865_COR1_5BITS;
- cor1 |= val;
- /*
- * Enable hardware RTS/CTS flow control. We can handle output flow
- * control at any time, since we have a dedicated CTS pin.
- * Unfortunately, though, the RTS pin is really the DTR pin. This
- * means that we can't ever use the automatic input flow control of
- * the CD1865 and that we can only use the pin for input flow
- * control when it's wired as RTS.
- */
- if (cflag & CCTS_OFLOW) { /* Output flow control... */
- pp->sp_state |= SX_SS_OFLOW;
-#ifdef SX_BROKEN_CTS
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan);
- if (sx_cd1865_in(sc, CD1865_MSVR|SX_EI) & CD1865_MSVR_CTS) {
- enable_intr();
- pp->sp_state |= SX_SS_OSTOP;
- }
- else {
- enable_intr();
- }
- ier |= CD1865_IER_CTS;
-#else /* SX_BROKEN_CTS */
- cor2 |= CD1865_COR2_CTSAE; /* Set CTS automatic enable. */
-#endif /* SX_BROKEN_CTS */
- }
- else {
- pp->sp_state &= ~SX_SS_OFLOW;
- }
- if (cflag & CRTS_IFLOW && !SX_DTRPIN(pp)) /* Input flow control. */
- pp->sp_state |= SX_SS_IFLOW;
- else
- pp->sp_state &= ~SX_SS_IFLOW;
- if (iflag & IXANY)
- cor2 |= CD1865_COR2_IXM; /* Any character is XON. */
- if (iflag & IXOFF) {
- cor2 |= CD1865_COR2_TXIBE; /* Enable inband flow control.*/
- cor3 |= CD1865_COR3_FCT | CD1865_COR3_SCDE; /* Hide from host */
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan); /* Sel chan.*/
- sx_cd1865_out(sc, CD1865_SCHR1|SX_EI, t->c_cc[VSTART]);
- sx_cd1865_out(sc, CD1865_SCHR2|SX_EI, t->c_cc[VSTOP]);
- sx_cd1865_out(sc, CD1865_SCHR3|SX_EI, t->c_cc[VSTART]);
- sx_cd1865_out(sc, CD1865_SCHR4|SX_EI, t->c_cc[VSTOP]);
- enable_intr();
- }
- /*
- * All set, now program the hardware.
- */
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan); /* Select channel. */
- sx_cd1865_out(sc, CD1865_COR1|SX_EI, cor1);
- sx_cd1865_out(sc, CD1865_COR2|SX_EI, cor2);
- sx_cd1865_out(sc, CD1865_COR3|SX_EI, cor3);
- sx_cd1865_wait_CCR(sc, SX_EI);
- sx_cd1865_out(sc, CD1865_CCR|SX_EI,
- CD1865_CCR_CORCHG1|CD1865_CCR_CORCHG2|CD1865_CCR_CORCHG3);
- sx_cd1865_wait_CCR(sc, SX_EI);
- enable_intr();
- if (SX_DTRPIN(pp))
- val = SER_DTR;
- else
- val = SER_RTS;
- if (t->c_ospeed == 0) /* Clear DTR/RTS if we're hung up. */
- (void)sx_modem(tp, 0, val);
- else /* If we were hung up, we may have to */
- (void)sx_modem(tp, 0, val);
- /*
- * Last, enable the receiver and transmitter and turn on the
- * interrupts we need (receive, carrier-detect and possibly CTS
- * (iff we're built with SX_BROKEN_CTS and CCTS_OFLOW is on).
- */
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan); /* Select channel. */
- sx_cd1865_wait_CCR(sc, SX_EI);
- sx_cd1865_out(sc, CD1865_CCR|SX_EI, CD1865_CCR_RXEN|CD1865_CCR_TXEN);
- sx_cd1865_wait_CCR(sc, SX_EI);
- sx_cd1865_out(sc, CD1865_IER|SX_EI, ier);
- enable_intr();
- DPRINT((pp, DBG_PARAM, "sxparam out\n"));
- splx(oldspl);
- return(error);
-}
-
-/*
- * sx_shutdown_chan()
- * Shut down a channel on the I/O8+.
- *
- * Description:
- * This does all hardware shutdown processing for a channel on the I/O8+.
- * It is called from sxhardclose(). We reset the channel and turn off
- * interrupts.
- */
-static void
-sx_shutdown_chan(
- struct sx_port *pp)
-{
- int s;
- struct sx_softc *sc;
-
- DPRINT((pp, DBG_ENTRY, "sx_shutdown_chan %x %x\n", pp, pp->sp_state));
- sc = pp->sp_sc;
- s = spltty();
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR, pp->sp_chan); /* Select channel. */
- sx_cd1865_wait_CCR(sc, 0); /* Wait for any commands to complete. */
- sx_cd1865_out(sc, CD1865_CCR, CD1865_CCR_SOFTRESET); /* Reset chan. */
- sx_cd1865_wait_CCR(sc, 0);
- sx_cd1865_out(sc, CD1865_IER, 0); /* Disable all interrupts. */
- enable_intr();
- splx(s);
-}
-
-/*
- * sx_modem()
- * Set/Get state of modem control lines.
- *
- * Description:
- * Get and set the state of the modem control lines that we have available
- * on the I/O8+. The only lines we are guaranteed to have are CD and CTS.
- * We have DTR if the "DTR/RTS pin is DTR" flag is set, otherwise we have
- * RTS through the DTR pin.
- */
-static int
-sx_modem(struct tty *tp, int sigon, int sigoff)
-{
- int s, x;
- struct sx_softc *sc;
- struct sx_port *pp;
-
- pp = tp->t_sc;
- sc = pp->sp_sc;
-
- s = spltty(); /* Block interrupts. */
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan); /* Select our port. */
- x = sx_cd1865_in(sc, CD1865_MSVR|SX_EI); /* Get the current signals. */
-#ifdef SX_DEBUG
- DPRINT((pp, DBG_MODEM, "sx_modem MSVR 0x%x, CCSR %x GIVR %x SRSR %x\n",
- x, sx_cd1865_in(sc, CD1865_CCSR|SX_EI),
- sx_cd1865_in(sc, CD1865_GIVR|SX_EI),
- sx_cd1865_in(sc, CD1865_SRSR|SX_EI)));
-#endif
- enable_intr(); /* Allow other interrupts. */
- if (sigon == 0 && sigoff == 0) {
- if ((x & CD1865_MSVR_CD) == 0)
- sigon |= SER_DCD;
- if ((x & CD1865_MSVR_CTS) == 0)
- sigon |= SER_CTS;
- if ((x & CD1865_MSVR_DTR) == 0) {
- if (SX_DTRPIN(pp)) /* Odd pin is DTR? */
- sigon |= SER_DTR; /* Report DTR. */
- else /* Odd pin is RTS. */
- sigon |= SER_RTS; /* Report RTS. */
- }
- return (sigon);
- }
- if ((sigon & SER_RTS && !SX_DTRPIN(pp)) ||
- (sigon & SER_DTR && SX_DTRPIN(pp)))
- x &= ~CD1865_MSVR_DTR;
- if ((sigoff & SER_RTS && !SX_DTRPIN(pp)) ||
- (sigoff & SER_DTR && SX_DTRPIN(pp)))
- x |= CD1865_MSVR_DTR;
- disable_intr();
- /*
- * Set the new modem signals.
- */
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan);
- sx_cd1865_out(sc, CD1865_MSVR|SX_EI, x);
- enable_intr();
- splx(s);
- return 0;
-}
-
-#ifdef POLL
-
-/*
- * sx_poll()
- * Poller to catch missed interrupts.
- *
- * Description:
- * Only used if we're complied with POLL. This routine is called every
- * sx_pollrate ticks to check for missed interrupts. We check each card
- * in the system; if we missed an interrupt, we complain about each one
- * and later call sx_intr() to handle them.
- */
-static void
-sx_poll(
- void *dummy)
-{
- struct sx_softc *sc;
- struct sx_port *pp;
- int card, lost, oldspl, chan;
-
- DPRINT((0, DBG_POLL, "sx_poll\n"));
- oldspl = spltty();
- if (in_interrupt)
- goto out;
- lost = 0;
- for (card = 0; card < sx_numunits; card++) {
- sc = devclass_get_softc(sx_devclass, card);
- if (sc == NULL)
- continue;
- if (sx_cd1865_in(sc, CD1865_SRSR|SX_EI) & CD1865_SRSR_REQint) {
- printf("sx%d: lost interrupt\n", card);
- lost++;
- }
- /*
- * Gripe about no input flow control.
- */
- for (chan = 0; chan < SX_NUMCHANS; pp++, chan++) {
- pp = &(sc->sc_ports[chan]);
- if (pp->sp_delta_overflows > 0) {
- printf("sx%d: %d tty level buffer overflows\n",
- card, pp->sp_delta_overflows);
- pp->sp_delta_overflows = 0;
- }
- }
- }
- if (lost || sx_realpoll)
- sx_intr(NULL); /* call intr with fake vector */
-out: splx(oldspl);
- timeout(sx_poll, (caddr_t)0L, sx_pollrate);
-}
-
-#endif /* POLL */
-
-
-/*
- * sx_transmit()
- * Handle transmit request interrupt.
- *
- * Description:
- * This routine handles the transmit request interrupt from the CD1865
- * chip on the I/O8+ card. The CD1865 interrupts us for a transmit
- * request under two circumstances: When the last character in the
- * transmit FIFO is sent and the channel is ready for more characters
- * ("transmit ready"), or when the last bit of the last character in the
- * FIFO is actually transmitted ("transmit empty"). In the former case,
- * we just pass processing off to sx_start() (via the line discipline)
- * to queue more characters. In the latter case, we were waiting for
- * the line to flush in sxhardclose() so we need to wake the sleeper.
- */
-static void
-sx_transmit(
- struct sx_softc *sc,
- struct sx_port *pp,
- int card)
-{
- struct tty *tp;
- unsigned char flags;
-
- tp = pp->sp_tty;
- /*
- * Let others know what we're doing.
- */
- pp->sp_state |= SX_SS_IXMIT;
- /*
- * Get the service request enable register to see what we're waiting
- * for.
- */
- flags = sx_cd1865_in(sc, CD1865_SRER|SX_EI);
-
- DPRINT((pp, DBG_TRANSMIT, "sx_xmit %x SRER %x\n", tp, flags));
- /*
- * "Transmit ready." The transmit FIFO is empty (but there are still
- * two characters being transmitted), so we need to tell the line
- * discipline to send more.
- */
- if (flags & CD1865_IER_TXRDY) {
- ttyld_start(tp);
- pp->sp_state &= ~SX_SS_IXMIT;
- DPRINT((pp, DBG_TRANSMIT, "sx_xmit TXRDY out\n"));
- return;
- }
- /*
- * "Transmit empty." The transmitter is completely empty; turn off the
- * service request and wake up the guy in sxhardclose() who is waiting
- * for this.
- */
- if (flags & CD1865_IER_TXEMPTY) {
- flags &= ~CD1865_IER_TXEMPTY;
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan);
- sx_cd1865_out(sc, CD1865_SRER|SX_EI, flags);
- wakeup((caddr_t)pp);
- }
- pp->sp_state &= ~SX_SS_IXMIT;
- DPRINT((pp, DBG_TRANSMIT, "sx_xmit out\n"));
-}
-
-/*
- * sx_modem_state()
- * Handle modem state-change request interrupt.
- *
- * Description:
- * Handles changed modem signals CD and CTS. We pass the CD change
- * off to the line discipline. We can't handle DSR since there isn't a
- * pin for it.
- */
-static void
-sx_modem_state(
- struct sx_softc *sc,
- struct sx_port *pp,
- int card)
-{
- struct tty *tp;
- unsigned char mcr;
-
- /*
- * Let others know what we're doing.
- */
- pp->sp_state |= SX_SS_IMODEM;
- tp = pp->sp_tty;
- /* Grab the Modem Change Register. */
- mcr = sx_cd1865_in(sc, CD1865_MCR|SX_EI);
- DPRINT((pp, DBG_MODEM_STATE,
- "sx_mdmst %x st %x sp %x mcr %x\n",
- tp, tp->t_state, pp->sp_state, mcr));
- if (mcr & CD1865_MCR_CDCHG) { /* CD changed? */
- if ((sx_cd1865_in(sc, CD1865_MSVR) & CD1865_MSVR_CD) == 0) {
- DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
- tp->t_line));
- (void)ttyld_modem(tp, 1);
- }
- else { /* CD went down. */
- DPRINT((pp, DBG_INTR, "modem carr off\n"));
- if (ttyld_modem(tp, 0))
- (void)sx_modem(tp, 0, SER_DTR | SER_RTS);
- }
- }
-#ifdef SX_BROKEN_CTS
- if (mcr & CD1865_MCR_CTSCHG) { /* CTS changed? */
- if (sx_cd1865_in(sc, CD1865_MSVR|SX_EI) & CD1865_MSVR_CTS) {
- pp->sp_state |= SX_SS_OSTOP;
- sx_cd1865_bic(sc, CD1865_IER|SX_EI, CD1865_IER_TXRDY);
- }
- else {
- pp->sp_state &= ~SX_SS_OSTOP;
- sx_cd1865_bis(sc, CD1865_IER|SX_EI, CD1865_IER_TXRDY);
- }
- }
-#endif /* SX_BROKEN_CTS */
- /* Clear state-change indicator bits. */
- sx_cd1865_out(sc, CD1865_MCR|SX_EI, 0);
- pp->sp_state &= ~SX_SS_IMODEM;
-}
-
-/*
- * sx_receive()
- * Handle receive request interrupt.
- *
- * Description:
- * Handle a receive request interrupt from the CD1865. This is just a
- * standard "we have characters to process" request, we don't have to
- * worry about exceptions like BREAK and such. Exceptions are handled
- * by sx_receive_exception().
- */
-static void
-sx_receive(
- struct sx_softc *sc,
- struct sx_port *pp,
- int card)
-{
- struct tty *tp;
- unsigned char count;
- int i, x;
- static unsigned char sx_rxbuf[SX_BUFFERSIZE]; /* input staging area */
-
- tp = pp->sp_tty;
- DPRINT((pp, DBG_RECEIVE,
- "sx_rcv %x st %x sp %x\n",
- tp, tp->t_state, pp->sp_state));
- /*
- * Let others know what we're doing.
- */
- pp->sp_state |= SX_SS_IRCV;
- /*
- * How many characters are waiting for us?
- */
- count = sx_cd1865_in(sc, CD1865_RDCR|SX_EI);
- if (count == 0) /* None? Bail. */
- return;
- DPRINT((pp, DBG_RECEIVE, "sx_receive count %d\n", count));
- /*
- * Pull the characters off the card into our local buffer, then
- * process that.
- */
- for (i = 0; i < count; i++)
- sx_rxbuf[i] = sx_cd1865_in(sc, CD1865_RDR|SX_EI);
- /*
- * If we're not open and connected, bail.
- */
- if (!(tp->t_state & TS_CONNECTED && tp->t_state & TS_ISOPEN)) {
- pp->sp_state &= ~SX_SS_IRCV;
- DPRINT((pp, DBG_RECEIVE, "sx_rcv not open\n"));
- return;
- }
- /*
- * If the tty input buffers are blocked and we have an RTS pin,
- * drop RTS and bail.
- */
- if (tp->t_state & TS_TBLOCK) {
- if (!SX_DTRPIN(pp) && SX_IFLOW(pp)) {
- (void)sx_modem(tp, 0, SER_RTS);
- pp->sp_state |= SX_SS_ISTOP;
- }
- pp->sp_state &= ~SX_SS_IRCV;
- return;
- }
- if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
- DPRINT((pp, DBG_RECEIVE, "sx_rcv BYPASS\n"));
- /*
- * Avoid the grotesquely inefficient lineswitch routine
- * (ttyinput) in "raw" mode. It usually takes about 450
- * instructions (that's without canonical processing or
- * echo!). slinput is reasonably fast (usually 40
- * instructions plus call overhead).
- */
- if (tp->t_rawq.c_cc + count >= SX_I_HIGH_WATER &&
- (tp->t_cflag & CRTS_IFLOW || tp->t_iflag & IXOFF) &&
- !(tp->t_state & TS_TBLOCK)) {
- ttyblock(tp);
- DPRINT((pp, DBG_RECEIVE, "sx_rcv block\n"));
- }
- tk_nin += count;
- tk_rawcc += count;
- tp->t_rawcc += count;
-
- pp->sp_delta_overflows +=
- b_to_q((char *)sx_rxbuf, count, &tp->t_rawq);
- ttwakeup(tp);
- /*
- * If we were stopped and need to start again because of this
- * receive, kick the output routine to get things going again.
- */
- if (tp->t_state & TS_TTSTOP && (tp->t_iflag & IXANY ||
- tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
- tp->t_state &= ~TS_TTSTOP;
- tp->t_lflag &= ~FLUSHO;
- sx_start(tp);
- }
- }
- else {
- DPRINT((pp, DBG_RECEIVE, "sx_rcv l_rint\n"));
- /*
- * It'd be nice to not have to go through the function call
- * overhead for each char here. It'd be nice to block input
- * it, saving a loop here and the call/return overhead.
- */
- for (x = 0; x < count; x++) {
- i = sx_rxbuf[x];
- if (ttyld_rint(tp, i) == -1)
- pp->sp_delta_overflows++;
- }
- }
- pp->sp_state &= ~SX_SS_IRCV;
- DPRINT((pp, DBG_RECEIVE, "sx_rcv out\n"));
-}
-
-
-
-/*
- * sx_receive_exception()
- * Handle receive exception request interrupt processing.
- *
- * Description:
- * Handle a receive exception request interrupt from the CD1865.
- * Possible exceptions include BREAK, overrun, receiver timeout
- * and parity and frame errors. We don't handle receiver timeout,
- * we just complain. The rest are passed to ttyinput().
- */
-static void
-sx_receive_exception(
- struct sx_softc *sc,
- struct sx_port *pp,
- int card)
-{
- struct tty *tp;
- unsigned char st;
- int ch, isopen;
-
- tp = pp->sp_tty;
- /*
- * Let others know what we're doing.
- */
- pp->sp_state |= SX_SS_IRCVEXC;
- /*
- * Check to see whether we should receive characters.
- */
- if (tp->t_state & TS_CONNECTED &&
- tp->t_state & TS_ISOPEN)
- isopen = 1;
- else
- isopen = 0;
-
- st = sx_cd1865_in(sc, CD1865_RCSR|SX_EI); /* Get the character status.*/
- ch = (int)sx_cd1865_in(sc, CD1865_RDR|SX_EI); /* Get the character. */
- DPRINT((pp, DBG_RECEIVE_EXC,
- "sx_rexc %x st %x sp %x st 0x%x ch 0x%x ('%c')\n",
- tp, tp->t_state, pp->sp_state, st, ch, ch));
- /* If there's no status or the tty isn't open, bail. */
- if (!st || !isopen) {
- pp->sp_state &= ~SX_SS_IRCVEXC;
- DPRINT((pp, DBG_RECEIVE_EXC, "sx_rexc not open\n"));
- return;
- }
- if (st & CD1865_RCSR_TOUT) /* Receiver timeout; just complain. */
- printf("sx%d: port %d: Receiver timeout.\n", card, pp->sp_chan);
- else if (st & CD1865_RCSR_BREAK)
- ch |= TTY_BI;
- else if (st & CD1865_RCSR_PE)
- ch |= TTY_PE;
- else if (st & CD1865_RCSR_FE)
- ch |= TTY_FE;
- else if (st & CD1865_RCSR_OE)
- ch |= TTY_OE;
- ttyld_rint(tp, ch);
- pp->sp_state &= ~SX_SS_IRCVEXC;
-}
-
-/*
- * sx_intr()
- * Field interrupts from the I/O8+.
- *
- * Description:
- * The interrupt handler polls ALL ports on ALL adapters each time
- * it is called.
- */
-void
-sx_intr(
- void *arg)
-{
- struct sx_softc *sc;
- struct sx_port *pp = NULL;
- int card;
- unsigned char ack;
-
- sc = arg;
-
- DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "sx_intr\n"));
- if (in_interrupt)
- return;
- in_interrupt = 1;
-
- /*
- * When we get an int we poll all the channels and do ALL pending
- * work, not just the first one we find. This allows all cards to
- * share the same vector.
- *
- * On the other hand, if we're sharing the vector with something
- * that's not an I/O8+, we may be making extra work for ourselves.
- */
- for (card = 0; card < sx_numunits; card++) {
- unsigned char st;
-
- sc = devclass_get_softc(sx_devclass, card);
- if (sc == NULL)
- continue;
- /*
- * Check the Service Request Status Register to see who
- * interrupted us and why. May be a receive, transmit or
- * modem-signal-change interrupt. Reading the appropriate
- * Request Acknowledge Register acknowledges the request and
- * gives us the contents of the Global Service Vector Register,
- * which in a daisy-chained configuration (not ours) uniquely
- * identifies the particular CD1865 and gives us the request
- * type. We mask off the ID part and use the rest.
- *
- * From the CD1865 specs, it appears that only one request can
- * happen at a time, but in testing it's pretty obvious that
- * the specs lie. Or perhaps we're just slow enough that the
- * requests pile up. Regardless, if we try to process more
- * than one at a time without clearing the previous request
- * (writing zero to EOIR) first, we hang the card. Thus the
- * "else if" logic here.
- */
- while ((st = (sx_cd1865_in(sc, CD1865_SRSR|SX_EI)) &
- CD1865_SRSR_REQint)) {
- /*
- * Transmit request interrupt.
- */
- if (st & CD1865_SRSR_TREQint) {
- ack = sx_cd1865_in(sc, CD1865_TRAR|SX_EI) &
- CD1865_GIVR_ITMASK;
- pp = sx_int_port(sc, card);
- if (pp == NULL) /* Bad channel. */
- goto skip;
- pp->sp_state |= SX_SS_INTR; /* In interrupt. */
- if (ack == CD1865_GIVR_IT_TX)
- sx_transmit(sc, pp, card);
- else
- printf("sx%d: Bad transmit ack 0x%02x.\n",
- card, ack);
- }
- /*
- * Modem signal change request interrupt.
- */
- else if (st & CD1865_SRSR_MREQint) {
- ack = sx_cd1865_in(sc, CD1865_MRAR|SX_EI) &
- CD1865_GIVR_ITMASK;
- pp = sx_int_port(sc, card);
- if (pp == NULL) /* Bad channel. */
- goto skip;
- pp->sp_state |= SX_SS_INTR; /* In interrupt. */
- if (ack == CD1865_GIVR_IT_MODEM)
- sx_modem_state(sc, pp, card);
- else
- printf("sx%d: Bad modem ack 0x%02x.\n",
- card, ack);
- }
- /*
- * Receive request interrupt.
- */
- else if (st & CD1865_SRSR_RREQint) {
- ack = sx_cd1865_in(sc, CD1865_RRAR|SX_EI) &
- CD1865_GIVR_ITMASK;
- pp = sx_int_port(sc, card);
- if (pp == NULL) /* Bad channel. */
- goto skip;
- pp->sp_state |= SX_SS_INTR; /* In interrupt. */
- if (ack == CD1865_GIVR_IT_RCV)
- sx_receive(sc, pp, card);
- else if (ack == CD1865_GIVR_IT_REXC)
- sx_receive_exception(sc, pp, card);
- else
- printf("sx%d: Bad receive ack 0x%02x.\n",
- card, ack);
- }
- /*
- * None of the above; this is a "can't happen," but
- * you never know...
- */
- else {
- printf("sx%d: Bad service request 0x%02x.\n",
- card, st);
- }
- pp->sp_state &= ~SX_SS_INTR;
-skip: sx_cd1865_out(sc, CD1865_EOIR|SX_EI, 0); /* EOI. */
- } /* while (st & CD1865_SRSR_REQint) */
- } /* for (card = 0; card < sx_numunits; card++) */
- in_interrupt = 0;
- DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "sx_intr out\n"));
-}
-
-/*
- * sx_start()
- * Handle transmit and state-change stuff.
- *
- * Description:
- * This is part of the line discipline processing; at various points in
- * the line discipline he calls ttstart() which calls the oproc routine,
- * which is this function. We're called by the line discipline to start
- * data transmission and to change signal states (for RTS flow control).
- * We're also called by this driver to perform line-breaks and to actually
- * do the data transmission.
-
- * We can only fill the FIFO from interrupt since the card only makes it
- * available to us during a service request such as TXRDY; this only
- * happens at interrupt.
- *
- * All paths through this code call ttwwakeup().
- */
-static void
-sx_start(
- struct tty *tp)
-{
- struct sx_softc *sc;
- struct sx_port *pp;
- struct clist *qp;
- int s;
- int count = CD1865_TFIFOSZ;
-
- s = spltty();
- pp = tp->t_sc;
- qp = &tp->t_outq;
- DPRINT((pp, DBG_ENTRY|DBG_START,
- "sx_start %x st %x sp %x cc %d\n",
- tp, tp->t_state, pp->sp_state, qp->c_cc));
-
- /*
- * If we're stopped, just wake up sleepers and get out.
- */
- if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) {
- ttwwakeup(tp);
- splx(s);
- DPRINT((pp, DBG_EXIT|DBG_START, "sx_start out\n", tp->t_state));
- return;
- }
- sc = pp->sp_sc;
- /*
- * If we're not transmitting, we may have been called to crank up the
- * transmitter and start things rolling or we may have been called to
- * get a bit of tty state. If the latter, handle it. Either way, if
- * we have data to transmit, turn on the transmit-ready interrupt,
- * set the XMIT flag and we're done. As soon as we allow interrupts
- * the card will interrupt for the first chunk of data. Note that
- * we don't mark the tty as busy until we are actually sending data
- * and then only if we have more than will fill the FIFO. If there's
- * no data to transmit, just handle the tty state.
- */
- if (!SX_XMITTING(pp)) {
- /*
- * If we were flow-controlled and input is no longer blocked,
- * raise RTS if we can.
- */
- if (SX_ISTOP(pp) && !(tp->t_state & TS_TBLOCK)) {
- if (!SX_DTRPIN(pp) && SX_IFLOW(pp))
- (void)sx_modem(tp, SER_RTS, 0);
- pp->sp_state &= ~SX_SS_ISTOP;
- }
- /*
- * If input is blocked, drop RTS if we can and set our flag.
- */
- if (tp->t_state & TS_TBLOCK) {
- if (!SX_DTRPIN(pp) && SX_IFLOW(pp))
- (void)sx_modem(tp, 0, SER_RTS);
- pp->sp_state |= SX_SS_ISTOP;
- }
- if ((qp->c_cc > 0 && !SX_OSTOP(pp)) || SX_DOBRK(pp)) {
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan);
- sx_cd1865_bis(sc, CD1865_IER|SX_EI, CD1865_IER_TXRDY);
- enable_intr();
- pp->sp_state |= SX_SS_XMIT;
- }
- ttwwakeup(tp);
- splx(s);
- DPRINT((pp, DBG_EXIT|DBG_START,
- "sx_start out B st %x sp %x cc %d\n",
- tp->t_state, pp->sp_state, qp->c_cc));
- return;
- }
- /*
- * If we weren't called from an interrupt or it wasn't a transmit
- * interrupt, we've done all we need to do. Everything else is done
- * in the transmit interrupt.
- */
- if (!SX_INTR(pp) || !SX_IXMIT(pp)) {
- ttwwakeup(tp);
- splx(s);
- DPRINT((pp, DBG_EXIT|DBG_START, "sx_start out X\n"));
- return;
- }
- /*
- * We're transmitting. If the clist is empty and we don't have a break
- * to send, turn off transmit-ready interrupts, and clear the XMIT
- * flag. Mark the tty as no longer busy, in case we haven't done
- * that yet. A future call to sxwrite() with more characters will
- * start up the process once more.
- */
- if (qp->c_cc == 0 && !SX_DOBRK(pp)) {
- disable_intr();
-/* sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan);*/
- sx_cd1865_bic(sc, CD1865_IER|SX_EI, CD1865_IER_TXRDY);
- enable_intr();
- pp->sp_state &= ~SX_SS_XMIT;
- tp->t_state &= ~TS_BUSY;
- ttwwakeup(tp);
- splx(s);
- DPRINT((pp, DBG_EXIT|DBG_START,
- "sx_start out E st %x sp %x\n",
- tp->t_state, pp->sp_state));
- return;
- }
- disable_intr();
- /*
- * If we have a BREAK state-change pending, handle it. If we aren't
- * sending a break, start one. If we are, turn it off.
- */
- if (SX_DOBRK(pp)) {
- count -= 2; /* Account for escape chars in FIFO. */
- if (SX_BREAK(pp)) { /* Doing break, stop it. */
- sx_cd1865_out(sc, CD1865_TDR, CD1865_C_ESC);
- sx_cd1865_out(sc, CD1865_TDR, CD1865_C_EBRK);
- sx_cd1865_etcmode(sc, SX_EI, pp->sp_chan, 0);
- pp->sp_state &= ~SX_SS_BREAK;
- }
- else { /* Start doing break. */
- sx_cd1865_etcmode(sc, SX_EI, pp->sp_chan, 1);
- sx_cd1865_out(sc, CD1865_TDR, CD1865_C_ESC);
- sx_cd1865_out(sc, CD1865_TDR, CD1865_C_SBRK);
- pp->sp_state |= SX_SS_BREAK;
- }
- pp->sp_state &= ~SX_SS_DOBRK;
- }
- /*
- * We've still got data in the clist, fill the channel's FIFO. The
- * CD1865 only gives us access to the FIFO during a transmit ready
- * request [interrupt] for this channel.
- */
- while (qp->c_cc > 0 && count-- >= 0) {
- register unsigned char ch, *cp;
- int nch;
-
- ch = (char)getc(qp);
- /*
- * If we're doing a break we're in ETC mode, so we need to
- * double any NULs in the stream.
- */
- if (SX_BREAK(pp)) { /* Doing break, in ETC mode. */
- if (ch == '\0') { /* NUL? Double it. */
- sx_cd1865_out(sc, CD1865_TDR, ch);
- count--;
- }
- /*
- * Peek the next character; if it's a NUL, we need
- * to escape it, but we can't if we're out of FIFO.
- * We'll do it on the next pass and leave the FIFO
- * incompletely filled.
- */
- if (qp->c_cc > 0) {
- cp = qp->c_cf;
- cp = nextc(qp, cp, &nch);
- if (nch == '\0' && count < 1)
- count = -1;
- }
- }
- sx_cd1865_out(sc, CD1865_TDR, ch);
- }
- enable_intr();
- /*
- * If we still have data to transmit, mark the tty busy for the
- * line discipline.
- */
- if (qp->c_cc > 0)
- tp->t_state |= TS_BUSY;
- else
- tp->t_state &= ~TS_BUSY;
- /* Wake up sleepers if necessary. */
- ttwwakeup(tp);
- splx(s);
- DPRINT((pp, DBG_EXIT|DBG_START,
- "sx_start out R %d/%d\n",
- count, qp->c_cc));
-}
-
-/*
- * Stop output on a line. called at spltty();
- */
-void
-sx_stop(
- struct tty *tp,
- int rw)
-{
- struct sx_softc *sc;
- struct sx_port *pp;
- int s;
-
- pp = tp->t_sc;
- sc = pp->sp_sc;
- DPRINT((pp, DBG_ENTRY|DBG_STOP, "sx_stop(%x,%x)\n", tp, rw));
-
- s = spltty();
- /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
- if (rw & FWRITE) {
- disable_intr();
- sx_cd1865_out(sc, CD1865_CAR|SX_EI, pp->sp_chan);
- sx_cd1865_bic(sc, CD1865_IER|SX_EI, CD1865_IER_TXRDY);
- sx_cd1865_wait_CCR(sc, SX_EI); /* Wait for CCR to go idle. */
- sx_cd1865_out(sc, CD1865_CCR|SX_EI, CD1865_CCR_TXDIS);
- sx_cd1865_wait_CCR(sc, SX_EI);
- enable_intr();
- /* what level are we meant to be flushing anyway? */
- if (tp->t_state & TS_BUSY) {
- if ((tp->t_state & TS_TTSTOP) == 0)
- tp->t_state |= TS_FLUSH;
- tp->t_state &= ~TS_BUSY;
- ttwwakeup(tp);
- }
- }
- /*
- * Nothing to do for FREAD.
- */
- splx(s);
-}
-
-#ifdef SX_DEBUG
-
-void
-sx_dprintf(
- struct sx_port *pp,
- int flags,
- const char *fmt, ...)
-{
- static char *logbuf = NULL;
- static char *linebuf = NULL;
- static char *logptr;
- char *lbuf;
- int n, m;
- va_list ap;
-
- if (logbuf == NULL) {
- logbuf = (char *)malloc(1024*1024, M_DEVBUF, M_WAITOK);
- linebuf = (char *)malloc(256, M_DEVBUF, M_WAITOK);
- logptr = logbuf;
- }
- lbuf = linebuf;
- n = 0;
- if ((pp == NULL && (sx_debug&flags)) ||
- (pp != NULL && ((pp->sp_debug&flags) || (sx_debug&flags)))) {
- if (pp != NULL &&
- pp->sp_tty != NULL) {
- n = snprintf(linebuf, 256, "sx%d(%d): ",
- (int)pp->sp_sc->sc_unit, (int)pp->sp_chan);
- if (n > 256)
- n = 256;
- lbuf += n;
- }
- m = n;
- va_start(ap, fmt);
- n = vsnprintf(lbuf, 256 - m, fmt, ap);
- va_end(ap);
- if (n > 256 - m)
- n = 256 - m;
- n += m;
- if (logptr + n + 1 > logbuf + (1024 * 1024)) {
- bzero(logptr, logbuf + (1024 * 1024) - logptr);
- logptr = logbuf;
- }
- bcopy(linebuf, logptr, n);
- logptr += n;
- *logptr = '\0';
- if (sx_debug & DBG_PRINTF)
- printf("%s", linebuf);
- }
-}
-
-#endif /* DEBUG */
OpenPOWER on IntegriCloud