/*
* Copyright (c) 1982, 1990 The Regents of the University of California.
* All rights reserved.
*
* 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
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Copyright (c) 1994 Michael L. Hitch
*
* 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
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* if NONBLOCK requested, ignore carrier
*/
if (flag & O_NONBLOCK)
goto done;
/*
* block waiting for carrier
*/
while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
tp->t_wopen++;
error = ttysleep(tp, &tp->t_rawcv, true, 0);
tp->t_wopen--;
if (error) {
ttyunlock(tp);
return(error);
}
}
done:
/* This is a way to handle lost XON characters */
if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) {
tp->t_state &= ~TS_TTSTOP;
ttstart (tp);
}
/*
* Reset the tty pointer, as there could have been a dialout
* use of the tty with a dialin open waiting.
*/
tp->t_dev = dev;
ttyunlock(tp);
return tp->t_linesw->l_open(dev, tp);
}
/*ARGSUSED*/
int
mfcsclose(dev_t dev, int flag, int mode, struct lwp *l)
{
struct tty *tp;
int unit;
struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, dev & 31);
struct mfc_softc *scc= sc->sc_mfc;
s = splser();
if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
goto out;
cc = tp->t_outq.c_cc;
if (!ttypull(tp) || (tp->t_state & TS_BUSY))
goto out;
/*
* We only do bulk transfers if using CTSRTS flow control, not for
* (probably sloooow) ixon/ixoff devices.
*/
if ((tp->t_cflag & CRTSCTS) == 0)
cc = 1;
/*
* Limit the amount of output we do in one burst
* to prevent hogging the CPU.
*/
if (cc > SEROBUF_SIZE)
cc = SEROBUF_SIZE;
cc = q_to_b(&tp->t_outq, sc->outbuf, cc);
if (cc > 0) {
tp->t_state |= TS_BUSY;
sc->ptr = sc->outbuf;
sc->end = sc->outbuf + cc;
/*
* Get first character out, then have TBE-interrupts blow out
* further characters, until buffer is empty, and TS_BUSY gets
* cleared.
*/
sc->sc_duart->ch_tb = *sc->ptr++;
scc->imask |= 1 << (unit * 4);
sc->sc_regs->du_imr = scc->imask;
}
out:
splx(s);
}
/*
* Stop output on a line.
*/
/*ARGSUSED*/
void
mfcsstop(struct tty *tp, int flag)
{
int s;
s = splser();
if (tp->t_state & TS_BUSY) {
if ((tp->t_state & TS_TTSTOP) == 0)
tp->t_state |= TS_FLUSH;
}
splx(s);
}
int
mfcsmctl(dev_t dev, int bits, int how)
{
int unit, s;
u_char ub = 0;
struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, dev & 31);
unit = dev & 1;
/*
* convert TIOCM* mask into CIA mask
* which is active low
*/
if (how != DMGET) {
/*
* need to save current state of DTR & RTS ?
*/
if (bits & TIOCM_DTR)
ub |= 0x04 << unit;
if (bits & TIOCM_RTS)
ub |= 0x01 << unit;
}
s = splser();
switch (how) {
case DMSET:
sc->sc_regs->du_btst = ub;
sc->sc_regs->du_btrst = ub ^ (0x05 << unit);
break;
case DMBIC:
sc->sc_regs->du_btrst = ub;
ub = ~sc->sc_regs->du_ip;
break;
case DMBIS:
sc->sc_regs->du_btst = ub;
ub = ~sc->sc_regs->du_ip;
break;
case DMGET:
ub = ~sc->sc_regs->du_ip;
break;
}
(void)splx(s);
/* XXXX should keep DTR & RTS states in softc? */
bits = TIOCM_DTR | TIOCM_RTS;
if (ub & (1 << unit))
bits |= TIOCM_CTS;
if (ub & (4 << unit))
bits |= TIOCM_DSR;
if (ub & (0x10 << unit))
bits |= TIOCM_CD;
/* XXXX RI is not supported on all boards */
if (sc->sc_regs->pad26 & (1 << unit))
bits |= TIOCM_RI;
return(bits);
}
/*
* Level 6 interrupt processing for the MultiFaceCard 68681 DUART
*/
/*
* Make sure we're not interrupted by another
* vbl, but allow level6 ints
*/
s1 = spltty();
/*
* pass along any accumulated information
* while input is not blocked
*/
while (sc->incnt && (tp->t_state & TS_TBLOCK) == 0) {
/*
* no collision with ser_fastint()
*/
mfcseint(unit, *sc->rptr++);
void
mfcseint(int unit, int stat)
{
struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, unit);
struct tty *tp;
u_char ch;
int c;
tp = sc->sc_tty;
ch = stat & 0xff;
c = ch;
if ((tp->t_state & TS_ISOPEN) == 0) {
#ifdef KGDB
extern const struct cdevsw ser_cdevsw;
int maj;
/* we don't care about parity errors */
maj = cdevsw_lookup_major(&ser_cdevsw);
if (kgdb_dev == makedev(maj, unit) && c == FRAME_END)
kgdb_connect(0); /* trap into kgdb */
#endif
return;
}
/*
* Check for break and (if enabled) parity error.
*/
if (stat & 0xc000)
c |= TTY_FE;
else if (stat & 0x2000)
c |= TTY_PE;
if (stat & 0x1000)
log(LOG_WARNING, "%s: fifo overflow\n",
device_xname(device_lookup_private(&mfcs_cd, unit)));
tp->t_linesw->l_rint(c, tp);
}
/*
* This interrupt is periodically invoked in the vertical blank
* interrupt. It's used to keep track of the modem control lines
* and (new with the fast_int code) to move accumulated data
* up into the tty layer.
*/
void
mfcsmint(int unit)
{
struct tty *tp;
struct mfcs_softc *sc = device_lookup_private(&mfcs_cd, unit);
u_char stat, last, istat;