Beispiel #1
0
/*
 *	siparam()	: Configure line params
 *	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
siparam(struct tty *tp, struct termios *t)
{
	struct si_port *pp = tty_softc(tp);
	volatile struct si_channel *ccbp;
	int oldspl, cflag, iflag, oflag, lflag;
	int error = 0;		/* shutup gcc */
	int ispeed = 0;		/* shutup gcc */
	int ospeed = 0;		/* shutup gcc */
	BYTE val;

	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
	mtx_assert(&Giant, MA_OWNED);
	cflag = t->c_cflag;
	iflag = t->c_iflag;
	oflag = t->c_oflag;
	lflag = t->c_lflag;
	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
		oflag, cflag, iflag, lflag));

	/* XXX - if Jet host and SXDC module, use extended baud rates */

	/* if not hung up.. */
	if (t->c_ospeed != 0) {
		/* translate baud rate to firmware values */
		ospeed = si_speedtab(t->c_ospeed, bdrates);
		ispeed = t->c_ispeed ?
			 si_speedtab(t->c_ispeed, bdrates) : ospeed;
		/* enforce legit baud rate */
		if (ospeed < 0 || ispeed < 0)
			return (EINVAL);
	}

	oldspl = spltty();

	ccbp = pp->sp_ccb;

	/* ========== set hi_break ========== */
	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;
	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
		val |= BR_PARIGN;
	ccbp->hi_break = val;

	/* ========== set hi_csr ========== */
	/* if not hung up.. */
	if (t->c_ospeed != 0) {
		/* Set I/O speeds */
		 val = (ispeed << 4) | ospeed;
	}
	ccbp->hi_csr = val;

	/* ========== set hi_mr2 ========== */
	val = 0;
	if (cflag & CSTOPB)				/* Stop bits */ 
		val |= MR2_2_STOP;
	else
		val |= MR2_1_STOP;

	/*
	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
	 * a DCE, hence the reverse sense of RTS and CTS
	 */
	/* Output Flow - RTS must be raised before data can be sent */
	if (cflag & CCTS_OFLOW)
		val |= MR2_RTSCONT;

	ccbp->hi_mr2 = val;

	/* ========== set hi_mr1 ========== */
	val = 0;
	if (!(cflag & PARENB))				/* Parity */
		val |= MR1_NONE;
	else
		val |= MR1_WITH;
	if (cflag & PARODD)
		val |= MR1_ODD;

	if ((cflag & CS8) == CS8)			/* 8 data bits? */
		val |= MR1_8_BITS;
	else if ((cflag & CS7) == CS7)			/* 7 data bits? */
		val |= MR1_7_BITS;
	else if ((cflag & CS6) == CS6)			/* 6 data bits? */
		val |= MR1_6_BITS;
	else						/* Must be 5 */
		val |= MR1_5_BITS;

	/*
	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
	 * a DCE, hence the reverse sense of RTS and CTS
	 */
	/* Input Flow - CTS is raised when port is ready to receive data */
	if (cflag & CRTS_IFLOW)
		val |= MR1_CTSCONT;

	ccbp->hi_mr1 = val;

	/* ========== set hi_mask ========== */
	val = 0xff;
	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
		val &= 0xFF;
	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
		val &= 0x7F;
	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
		val &= 0x3F;
	} else {					/* Must be 5 */
		val &= 0x1F;
	}
	if (iflag & ISTRIP)
		val &= 0x7F;

	ccbp->hi_mask = val;

	/* ========== set hi_prtcl ========== */
	val = SP_DCEN;		/* Monitor DCD always, or TIOCMGET misses it */
	if (iflag & IXANY)
		val |= SP_TANY;
	if (iflag & IXON)
		val |= SP_TXEN;
	if (iflag & IXOFF)
		val |= SP_RXEN;
	if (iflag & INPCK)
		val |= SP_PAEN;

	ccbp->hi_prtcl = val;


	/* ========== set hi_{rx|tx}{on|off} ========== */
	/* XXX: the card TOTALLY shields us from the flow control... */
	ccbp->hi_txon = t->c_cc[VSTART];
	ccbp->hi_txoff = t->c_cc[VSTOP];

	ccbp->hi_rxon = t->c_cc[VSTART];
	ccbp->hi_rxoff = t->c_cc[VSTOP];

	/* ========== send settings to the card ========== */
	/* potential sleep here */
	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
		si_command(pp, LOPEN, SI_WAIT);		/* open it */
	else
		si_command(pp, CONFIG, SI_WAIT);	/* change params */

	/* ========== set DTR etc ========== */
	/* Hangup if ospeed == 0 */
	if (t->c_ospeed == 0) {
		(void) simodem(tp, 0, SER_DTR | SER_RTS);
	} else {
		/*
		 * If the previous speed was 0, may need to re-enable
		 * the modem signals
		 */
		(void) simodem(tp, SER_DTR | SER_RTS, 0);
	}

	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x HI_CSR %x\n",
		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break, ccbp->hi_csr));

	splx(oldspl);
	return(error);
}
Beispiel #2
0
static int
ptsdev_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
    int flags, struct thread *td)
{
	struct tty *tp = fp->f_data;
	struct pts_softc *psc = tty_softc(tp);
	int error = 0;
	char pkt;

	if (uio->uio_resid == 0)
		return (0);

	tty_lock(tp);

	for (;;) {
		/*
		 * Implement packet mode. When packet mode is turned on,
		 * the first byte contains a bitmask of events that
		 * occured (start, stop, flush, window size, etc).
		 */
		if (psc->pts_flags & PTS_PKT && psc->pts_pkt) {
			pkt = psc->pts_pkt;
			psc->pts_pkt = 0;
			tty_unlock(tp);

			error = ureadc(pkt, uio);
			return (error);
		}

		/*
		 * Transmit regular data.
		 *
		 * XXX: We shouldn't use ttydisc_getc_poll()! Even
		 * though in this implementation, there is likely going
		 * to be data, we should just call ttydisc_getc_uio()
		 * and use its return value to sleep.
		 */
		if (ttydisc_getc_poll(tp)) {
			if (psc->pts_flags & PTS_PKT) {
				/*
				 * XXX: Small race. Fortunately PTY
				 * consumers aren't multithreaded.
				 */

				tty_unlock(tp);
				error = ureadc(TIOCPKT_DATA, uio);
				if (error)
					return (error);
				tty_lock(tp);
			}

			error = ttydisc_getc_uio(tp, uio);
			break;
		}

		/* Maybe the device isn't used anyway. */
		if (psc->pts_flags & PTS_FINISHED)
			break;

		/* Wait for more data. */
		if (fp->f_flag & O_NONBLOCK) {
			error = EWOULDBLOCK;
			break;
		}
		error = cv_wait_sig(&psc->pts_outwait, tp->t_mtx);
		if (error != 0)
			break;
	}

	tty_unlock(tp);

	return (error);
}
Beispiel #3
0
static int
ptsdev_ioctl(struct file *fp, u_long cmd, void *data,
             struct ucred *active_cred, struct thread *td)
{
    struct tty *tp = fp->f_data;
    struct pts_softc *psc = tty_softc(tp);
    int error = 0, sig;

    switch (cmd) {
    case FIODTYPE:
        *(int *)data = D_TTY;
        return (0);
    case FIONBIO:
        /* This device supports non-blocking operation. */
        return (0);
    case FIONREAD:
        tty_lock(tp);
        if (psc->pts_flags & PTS_FINISHED) {
            /* Force read() to be called. */
            *(int *)data = 1;
        } else {
            *(int *)data = ttydisc_getc_poll(tp);
        }
        tty_unlock(tp);
        return (0);
    case FIODGNAME: {
        struct fiodgname_arg *fgn;
        const char *p;
        int i;

        /* Reverse device name lookups, for ptsname() and ttyname(). */
        fgn = data;
        p = tty_devname(tp);
        i = strlen(p) + 1;
        if (i > fgn->len)
            return (EINVAL);
        return copyout(p, fgn->buf, i);
    }

        /*
         * We need to implement TIOCGPGRP and TIOCGSID here again. When
         * called on the pseudo-terminal master, it should not check if
         * the terminal is the foreground terminal of the calling
         * process.
         *
         * TIOCGETA is also implemented here. Various Linux PTY routines
         * often call isatty(), which is implemented by tcgetattr().
         */
#ifdef PTS_LINUX
    case TIOCGETA:
        /* Obtain terminal flags through tcgetattr(). */
        tty_lock(tp);
        *(struct termios*)data = tp->t_termios;
        tty_unlock(tp);
        return (0);
#endif /* PTS_LINUX */
    case TIOCSETAF:
    case TIOCSETAW:
        /*
         * We must make sure we turn tcsetattr() calls of TCSAFLUSH and
         * TCSADRAIN into something different. If an application would
         * call TCSAFLUSH or TCSADRAIN on the master descriptor, it may
         * deadlock waiting for all data to be read.
         */
        cmd = TIOCSETA;
        break;
#if defined(PTS_COMPAT) || defined(PTS_LINUX)
    case TIOCGPTN:
        /*
         * Get the device unit number.
         */
        if (psc->pts_unit < 0)
            return (ENOTTY);
        *(unsigned int *)data = psc->pts_unit;
        return (0);
#endif /* PTS_COMPAT || PTS_LINUX */
    case TIOCGPGRP:
        /* Get the foreground process group ID. */
        tty_lock(tp);
        if (tp->t_pgrp != NULL)
            *(int *)data = tp->t_pgrp->pg_id;
        else
            *(int *)data = NO_PID;
        tty_unlock(tp);
        return (0);
    case TIOCGSID:
        /* Get the session leader process ID. */
        tty_lock(tp);
        if (tp->t_session == NULL)
            error = ENOTTY;
        else
            *(int *)data = tp->t_session->s_sid;
        tty_unlock(tp);
        return (error);
    case TIOCPTMASTER:
        /* Yes, we are a pseudo-terminal master. */
        return (0);
    case TIOCSIG:
        /* Signal the foreground process group. */
        sig = *(int *)data;
        if (sig < 1 || sig >= NSIG)
            return (EINVAL);

        tty_lock(tp);
        tty_signal_pgrp(tp, sig);
        tty_unlock(tp);
        return (0);
    case TIOCPKT:
        /* Enable/disable packet mode. */
        tty_lock(tp);
        if (*(int *)data)
            psc->pts_flags |= PTS_PKT;
        else
            psc->pts_flags &= ~PTS_PKT;
        tty_unlock(tp);
        return (0);
    }

    /* Just redirect this ioctl to the slave device. */
    tty_lock(tp);
    error = tty_ioctl(tp, cmd, data, fp->f_flag, td);
    tty_unlock(tp);
    if (error == ENOIOCTL)
        error = ENOTTY;

    return (error);
}
Beispiel #4
0
/*
 * Nudge the transmitter...
 *
 * XXX: I inherited some funny code here.  It implies the host card only
 * interrupts when the transmit buffer reaches the low-water-mark, and does
 * not interrupt when it's actually hits empty.  In some cases, we have
 * processes waiting for complete drain, and we need to simulate an interrupt
 * about when we think the buffer is going to be empty (and retry if not).
 * I really am not certain about this...  I *need* the hardware manuals.
 */
static void
si_start(struct tty *tp)
{
	struct si_port *pp;
	volatile struct si_channel *ccbp;
	BYTE ipos, count;
#if 0
	int nchar;
#endif
	int oldspl, n, amount;

	oldspl = spltty();
	mtx_assert(&Giant, MA_OWNED);

	pp = tty_softc(tp);

	DPRINT((pp, DBG_ENTRY|DBG_START,
		"si_start(%x) sp_state %x\n",
		tp, pp->sp_state));

	ccbp = pp->sp_ccb;

	while ((count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos) < 255) {
		DPRINT((pp, DBG_START, "txbuf pend count %d\n", (BYTE)count));
		ipos = (unsigned int)ccbp->hi_txipos;
		if ((int)ccbp->hi_txopos <= ipos)
			amount = SI_BUFFERSIZE - ipos;
		else
			amount = 255 - count;
		DPRINT((pp, DBG_START, "spaceleft amount %d\n", amount));
		if (amount == 0)
			break;
		n = ttydisc_getc(tp, si_txbuf, amount);
		DPRINT((pp, DBG_START, "getc n=%d\n", n));
		if (n == 0)
			break;
		si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], n);
		ccbp->hi_txipos += n;
	}

#if 0
	/*
	 * See if there are any characters still to come.  If so, we can
	 * depend on si_start being called again.
	 *
	 * XXX the manual is vague on this.  It implies we get an interrupt
	 * when the transmit queue reaches the 25% low water mark, but NOT
	 * when it hits empty.
	 */
	nchar = ttyoutq_getsize(&tp->t_outq) - ttyoutq_bytesleft(&tp->t_outq);
	DPRINT((pp, DBG_START, "count %d, nchar %d\n",
		(BYTE)count, nchar));

	if (count != 0 && nchar == 0) {
		int time;

		/* XXX lame. Ticks per character. used to be a table. */
		time = (tp->t_termios.c_ospeed + 9) / 10;

		if (time > 0) {
			if (time < nchar)
				time = nchar / time;
			else
				time = 2;
		} else {
			DPRINT((pp, DBG_START,
				"bad char time value! %d\n", time));
			time = hz/10;
		}

		if ((pp->sp_state & SS_LSTART) != 0)
			untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch);
		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
		pp->sp_state |= SS_LSTART;
		pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time);
	}
#endif

	splx(oldspl);
	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
}
Beispiel #5
0
static int
ptsdev_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
             int flags, struct thread *td)
{
    struct tty *tp = fp->f_data;
    struct pts_softc *psc = tty_softc(tp);
    char ib[256], *ibstart;
    size_t iblen, rintlen;
    int error = 0;

    if (uio->uio_resid == 0)
        return (0);

    for (;;) {
        ibstart = ib;
        iblen = MIN(uio->uio_resid, sizeof ib);
        error = uiomove(ib, iblen, uio);

        tty_lock(tp);
        if (error != 0) {
            iblen = 0;
            goto done;
        }

        /*
         * When possible, avoid the slow path. rint_bypass()
         * copies all input to the input queue at once.
         */
        MPASS(iblen > 0);
        do {
            rintlen = ttydisc_rint_simple(tp, ibstart, iblen);
            ibstart += rintlen;
            iblen -= rintlen;
            if (iblen == 0) {
                /* All data written. */
                break;
            }

            /* Maybe the device isn't used anyway. */
            if (psc->pts_flags & PTS_FINISHED) {
                error = EIO;
                goto done;
            }

            /* Wait for more data. */
            if (fp->f_flag & O_NONBLOCK) {
                error = EWOULDBLOCK;
                goto done;
            }

            /* Wake up users on the slave side. */
            ttydisc_rint_done(tp);
            error = cv_wait_sig(&psc->pts_inwait, tp->t_mtx);
            if (error != 0)
                goto done;
        } while (iblen > 0);

        if (uio->uio_resid == 0)
            break;
        tty_unlock(tp);
    }

done:
    ttydisc_rint_done(tp);
    tty_unlock(tp);

    /*
     * Don't account for the part of the buffer that we couldn't
     * pass to the TTY.
     */
    uio->uio_resid += iblen;
    return (error);
}
static int
ucom_param(struct tty *tp, struct termios *t)
{
	struct ucom_softc *sc = tty_softc(tp);
	uint8_t opened;
	int error;

	mtx_assert(sc->sc_mtx, MA_OWNED);

	opened = 0;
	error = 0;

	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {

		/* XXX the TTY layer should call "open()" first! */

		error = ucom_open(tp);
		if (error) {
			goto done;
		}
		opened = 1;
	}
	DPRINTF("sc = %p\n", sc);

	/* Check requested parameters. */
	if (t->c_ospeed < 0) {
		DPRINTF("negative ospeed\n");
		error = EINVAL;
		goto done;
	}
	if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
		DPRINTF("mismatch ispeed and ospeed\n");
		error = EINVAL;
		goto done;
	}
	t->c_ispeed = t->c_ospeed;

	if (sc->sc_callback->ucom_pre_param) {
		/* Let the lower layer verify the parameters */
		error = (sc->sc_callback->ucom_pre_param) (sc, t);
		if (error) {
			DPRINTF("callback error = %d\n", error);
			goto done;
		}
	}

	/* Disable transfers */
	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;

	/* Queue baud rate programming command first */
	ucom_queue_command(sc, ucom_cfg_param, t,
	    &sc->sc_param_task[0].hdr,
	    &sc->sc_param_task[1].hdr);

	/* Queue transfer enable command last */
	ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
	    &sc->sc_start_task[0].hdr, 
	    &sc->sc_start_task[1].hdr);

	if (t->c_cflag & CRTS_IFLOW) {
		sc->sc_flag |= UCOM_FLAG_RTS_IFLOW;
	} else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) {
		sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW;
		ucom_modem(tp, SER_RTS, 0);
	}
done:
	if (error) {
		if (opened) {
			ucom_close(tp);
		}
	}
	return (error);
}
Beispiel #7
0
static int
ucom_open(struct tty *tp)
{
	struct ucom_softc *sc = tty_softc(tp);
	int error;

	UCOM_MTX_ASSERT(sc, MA_OWNED);

	if (sc->sc_flag & UCOM_FLAG_GONE) {
		return (ENXIO);
	}
	if (sc->sc_flag & UCOM_FLAG_HL_READY) {
		/* already opened */
		return (0);
	}
	DPRINTF("tp = %p\n", tp);

	if (sc->sc_callback->ucom_pre_open) {
		/*
		 * give the lower layer a chance to disallow TTY open, for
		 * example if the device is not present:
		 */
		error = (sc->sc_callback->ucom_pre_open) (sc);
		if (error) {
			return (error);
		}
	}
	sc->sc_flag |= UCOM_FLAG_HL_READY;

	/* Disable transfers */
	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;

	sc->sc_lsr = 0;
	sc->sc_msr = 0;
	sc->sc_mcr = 0;

	/* reset programmed line state */
	sc->sc_pls_curr = 0;
	sc->sc_pls_set = 0;
	sc->sc_pls_clr = 0;

	/* reset jitter buffer */
	sc->sc_jitterbuf_in = 0;
	sc->sc_jitterbuf_out = 0;

	ucom_queue_command(sc, ucom_cfg_open, NULL,
	    &sc->sc_open_task[0].hdr,
	    &sc->sc_open_task[1].hdr);

	/* Queue transfer enable command last */
	ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
	    &sc->sc_start_task[0].hdr, 
	    &sc->sc_start_task[1].hdr);

	ucom_modem(tp, SER_DTR | SER_RTS, 0);

	ucom_ring(sc, 0);

	ucom_break(sc, 0);

	ucom_status_change(sc);

	return (0);
}
Beispiel #8
0
static int
ucom_param(struct tty *tp, struct termios *t)
{
	struct ucom_softc *sc = tty_softc(tp);
	uint8_t opened;
	int error;

	UCOM_MTX_ASSERT(sc, MA_OWNED);

	opened = 0;
	error = 0;

	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {

		/* XXX the TTY layer should call "open()" first! */
		/*
		 * Not quite: Its ordering is partly backwards, but
		 * some parameters must be set early in ttydev_open(),
		 * possibly before calling ttydevsw_open().
		 */
		error = ucom_open(tp);
		if (error)
			goto done;

		opened = 1;
	}
	DPRINTF("sc = %p\n", sc);

	/* Check requested parameters. */
	if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
		/* XXX c_ospeed == 0 is perfectly valid. */
		DPRINTF("mismatch ispeed and ospeed\n");
		error = EINVAL;
		goto done;
	}
	t->c_ispeed = t->c_ospeed;

	if (sc->sc_callback->ucom_pre_param) {
		/* Let the lower layer verify the parameters */
		error = (sc->sc_callback->ucom_pre_param) (sc, t);
		if (error) {
			DPRINTF("callback error = %d\n", error);
			goto done;
		}
	}

	/* Disable transfers */
	sc->sc_flag &= ~UCOM_FLAG_GP_DATA;

	/* Queue baud rate programming command first */
	ucom_queue_command(sc, ucom_cfg_param, t,
	    &sc->sc_param_task[0].hdr,
	    &sc->sc_param_task[1].hdr);

	/* Queue transfer enable command last */
	ucom_queue_command(sc, ucom_cfg_start_transfers, NULL,
	    &sc->sc_start_task[0].hdr, 
	    &sc->sc_start_task[1].hdr);

	if (t->c_cflag & CRTS_IFLOW) {
		sc->sc_flag |= UCOM_FLAG_RTS_IFLOW;
	} else if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) {
		sc->sc_flag &= ~UCOM_FLAG_RTS_IFLOW;
		ucom_modem(tp, SER_RTS, 0);
	}
done:
	if (error) {
		if (opened) {
			ucom_close(tp);
		}
	}
	return (error);
}
Beispiel #9
0
	if (sc->sc_isquelch) {
		if ((tp->t_termios.c_cflag & CRTS_IFLOW) && !sc->sc_hwiflow)
			UART_SETSIG(sc, SER_DRTS|SER_RTS);
		sc->sc_isquelch = 0;
		uart_sched_softih(sc, SER_INT_RXREADY);
	}
}

static int
uart_tty_ioctl(struct tty *tp, u_long cmd, caddr_t data,
    struct thread *td __unused)
{
	struct uart_softc *sc;

	sc = tty_softc(tp);

	switch (cmd) {
	case TIOCSBRK:
		UART_IOCTL(sc, UART_IOCTL_BREAK, 1);
		return (0);
	case TIOCCBRK:
		UART_IOCTL(sc, UART_IOCTL_BREAK, 0);
		return (0);
	default:
		return pps_ioctl(cmd, data, &sc->sc_pps);
	}
}

static int
uart_tty_param(struct tty *tp, struct termios *t)