Esempio n. 1
0
void
sacomsoft(void *arg)
{
    struct sacom_softc *sc = arg;
    struct tty *tp;

    if (COM_ISALIVE(sc) == 0)
        return;

    tp = sc->sc_tty;

    if (sc->sc_rx_ready) {
        sc->sc_rx_ready = 0;
        sacom_rxsoft(sc, tp);
    }

    if (sc->sc_st_check) {
        sc->sc_st_check = 0;
        sacom_stsoft(sc, tp);
    }

    if (sc->sc_tx_done) {
        sc->sc_tx_done = 0;
        sacom_txsoft(sc, tp);
    }
}
int
at91usart_close(dev_t dev, int flag, int mode, struct lwp *l)
{
	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
	struct tty *tp = sc->sc_tty;

	/* XXX This is for cons.c. */
	if (!ISSET(tp->t_state, TS_ISOPEN))
		return (0);

	(*tp->t_linesw->l_close)(tp, flag);
	ttyclose(tp);

	if (COM_ISALIVE(sc) == 0)
		return (0);

	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
		/*
		 * Although we got a last close, the device may still be in
		 * use; e.g. if this was the dialout node, and there are still
		 * processes waiting for carrier on the non-dialout node.
		 */
		at91usart_shutdown(sc);
	}

	return (0);
}
int
at91usart_write(dev_t dev, struct uio *uio, int flag)
{
	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
	struct tty *tp = sc->sc_tty;

	if (COM_ISALIVE(sc) == 0)
		return (EIO);
 
	return ((*tp->t_linesw->l_write)(tp, uio, flag));
}
int
at91usart_poll(dev_t dev, int events, struct lwp *l)
{
	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
	struct tty *tp = sc->sc_tty;

	if (COM_ISALIVE(sc) == 0)
		return (EIO);
 
	return ((*tp->t_linesw->l_poll)(tp, events, l));
}
Esempio n. 5
0
int
sacompoll(dev_t dev, int events, struct lwp *l)
{
    struct sacom_softc *sc =
        device_lookup_private(&sacom_cd, COMUNIT(dev));
    struct tty *tp = sc->sc_tty;

    if (COM_ISALIVE(sc) == 0)
        return EIO;

    return (*tp->t_linesw->l_poll)(tp, events, l);
}
Esempio n. 6
0
int
sacomwrite(dev_t dev, struct uio *uio, int flag)
{
    struct sacom_softc *sc =
        device_lookup_private(&sacom_cd, COMUNIT(dev));
    struct tty *tp = sc->sc_tty;

    if (COM_ISALIVE(sc) == 0)
        return EIO;

    return (*tp->t_linesw->l_write)(tp, uio, flag);
}
int
at91usart_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
	struct tty *tp = sc->sc_tty;
	int error;
	int s;

	if (COM_ISALIVE(sc) == 0)
		return (EIO);

	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
	if (error != EPASSTHROUGH)
		return (error);

	error = ttioctl(tp, cmd, data, flag, l);
	if (error != EPASSTHROUGH)
		return (error);

	error = 0;

	s = spltty();

	switch (cmd) {
	case TIOCSBRK:
		at91usart_break(sc, 1);
		break;

	case TIOCCBRK:
		at91usart_break(sc, 0);
		break;

	case TIOCGFLAGS:
		*(int *)data = sc->sc_swflags;
		break;

	case TIOCSFLAGS:
		error = kauth_authorize_device_tty(l->l_cred,
		    KAUTH_DEVICE_TTY_PRIVSET, tp); 
		if (error)
			break;
		sc->sc_swflags = *(int *)data;
		break;

	default:
		error = EPASSTHROUGH;
		break;
	}

	splx(s);

	return (error);
}
Esempio n. 8
0
void
sacomstart(struct tty *tp)
{
    struct sacom_softc *sc =
        device_lookup_private(&sacom_cd, COMUNIT(tp->t_dev));
    bus_space_tag_t iot = sc->sc_iot;
    bus_space_handle_t ioh = sc->sc_ioh;
    int s;

    if (COM_ISALIVE(sc) == 0)
        return;

    s = spltty();
    if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
        goto out;
    if (!ttypull(tp))
        goto out;

    /* Grab the first contiguous region of buffer space. */
    {
        u_char *tba;
        int tbc;

        tba = tp->t_outq.c_cf;
        tbc = ndqb(&tp->t_outq, 0);

        (void)splserial();
        COM_LOCK(sc);

        sc->sc_tba = tba;
        sc->sc_tbc = tbc;
    }

    SET(tp->t_state, TS_BUSY);
    sc->sc_tx_busy = 1;

    /* Enable transmit completion interrupts if necessary. */
    if (!ISSET(sc->sc_cr3, CR3_TIE)) {
        SET(sc->sc_cr3, CR3_TIE);
        bus_space_write_4(iot, ioh, SACOM_CR3, sc->sc_cr3);
    }

    /* Output the first chunk of the contiguous buffer. */
    sacom_filltx(sc);

    COM_UNLOCK(sc);
out:
    splx(s);
    return;
}
static void
at91usart_soft(void* arg)
{
	struct at91usart_softc *sc = arg;
	int s;
	u_int csr;

	if (COM_ISALIVE(sc) == 0)
		return;

	s = spltty();
	csr = sc->sc_csr;
	while (csr != 0) {
		if ((csr &= sc->sc_ier) == 0)
			break;
//		splx(s);
		DPRINTFN(5, ("%s: %s / csr = 0x%08x\n", device_xname(sc->sc_dev), __FUNCTION__, csr));
		if (ISSET(csr, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK)) {
			/* receive interrupt */
			if (ISSET(csr, US_CSR_RXBRK)) {
				// break received!
				at91usart_writereg(sc, US_CR, US_CR_RSTSTA | US_CR_STTTO);
			} else if (ISSET(csr, US_CSR_TIMEOUT)) {
				// timeout received
				at91usart_writereg(sc, US_CR, US_CR_STTTO);
			}
			at91usart_rxsoft(sc, sc->sc_tty, csr);
		}
		if (ISSET(csr, US_CSR_TXEMPTY)) {
			at91usart_stop_tx(sc);
			CLR(sc->sc_ier, US_CSR_TXEMPTY);
			if (AT91PDC_FIFO_EMPTY(&sc->sc_tx_fifo)) {
				// everything sent!
				if (ISSET(sc->sc_tty->t_state, TS_FLUSH))
					CLR(sc->sc_tty->t_state, TS_FLUSH);
			}
		}
		if (ISSET(csr, US_CSR_TXEMPTY | US_CSR_ENDTX)) {
			/* transmit interrupt! */
			at91usart_txsoft(sc, sc->sc_tty);
		}
//		s = spltty();
		csr = at91usart_readreg(sc, US_CSR);
	}
	sc->sc_csr = 0;
	at91usart_writereg(sc, US_IER, sc->sc_ier);	// re-enable interrupts
	splx(s);
}
Esempio n. 10
0
static void
at91dbgu_soft(void* arg)
{
	struct at91dbgu_softc *sc = arg;

	if (COM_ISALIVE(sc) == 0)
		return;

	if (sc->sc_rx_ready) {
		sc->sc_rx_ready = 0;
		at91dbgu_rxsoft(sc, sc->sc_tty);
	}
	if (sc->sc_tx_done) {
		sc->sc_tx_done = 0;
		at91dbgu_txsoft(sc, sc->sc_tty);
	}
}
static void
at91usart_start(struct tty *tp)
{
	struct at91usart_softc *sc
		= device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev));
	int s;

	if (COM_ISALIVE(sc) == 0) {
		DPRINTFN(5, ("%s: %s / COM_ISALIVE == 0\n", device_xname(sc->sc_dev), __FUNCTION__));
		return;
	}

	s = spltty();
	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
		DPRINTFN(5, ("%s: %s: TS_BUSY || TS_TIMEOUT || TS_TTSTOP\n", device_xname(sc->sc_dev), __FUNCTION__));
		goto out;
	}

	if (!ttypull(tp))
		goto out;

	/* Grab the first contiguous region of buffer space. */
	{
		u_char *tba;
		int tbc;

		tba = tp->t_outq.c_cf;
		tbc = ndqb(&tp->t_outq, 0);

		sc->sc_tba = tba;
		sc->sc_tbc = tbc;
	}

	SET(tp->t_state, TS_BUSY);

	/* Output the first chunk of the contiguous buffer. */
	at91usart_filltx(sc);
	at91usart_writereg(sc, US_IER, sc->sc_ier);
	DPRINTFN(5, ("%s: %s, ier=%08x (csr=%08x)\n", device_xname(sc->sc_dev), __FUNCTION__, sc->sc_ier, at91usart_readreg(sc, US_CSR)));

out:
	splx(s);

	return;
}
Esempio n. 12
0
static void
at91dbgu_start(struct tty *tp)
{
	struct at91dbgu_softc *sc
		= device_lookup_private(&at91dbgu_cd, COMUNIT(tp->t_dev));
	int s;

	if (COM_ISALIVE(sc) == 0)
		return;

	s = spltty();
	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
		goto out;
	if (sc->sc_tx_stopped)
		goto out;
	if (!ttypull(tp))
		goto out;

	/* Grab the first contiguous region of buffer space. */
	{
		u_char *tba;
		int tbc;

		tba = tp->t_outq.c_cf;
		tbc = ndqb(&tp->t_outq, 0);

		(void)splserial();

		sc->sc_tba = tba;
		sc->sc_tbc = tbc;
	}

	SET(tp->t_state, TS_BUSY);
	sc->sc_tx_busy = 1;

	/* Output the first chunk of the contiguous buffer. */
	at91dbgu_filltx(sc);

	SET(sc->sc_ier, DBGU_INT_TXRDY);
	DBGUREG(DBGU_IER) = DBGU_INT_TXRDY;

out:
	splx(s);
	return;
}
Esempio n. 13
0
int
sacomhwiflow(struct tty *tp, int block)
{
#if 0
    struct sacom_softc *sc =
        device_lookup_private(&sacom_cd, COMUNIT(tp->t_dev));
    int s;

    if (COM_ISALIVE(sc) == 0)
        return 0;

    if (sc->sc_mcr_rts == 0)
        return 0;

    s = splserial();
    COM_LOCK(sc);

    if (block) {
        if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
            SET(sc->sc_rx_flags, RX_TTY_BLOCKED);
            sacom_hwiflow(sc);
        }
    } else {
        if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
            CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
            sacom_schedrx(sc);
        }
        if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
            CLR(sc->sc_rx_flags, RX_TTY_BLOCKED);
            sacom_hwiflow(sc);
        }
    }

    COM_UNLOCK(sc);
    splx(s);
#endif
    return 1;
}
Esempio n. 14
0
int
sacomintr(void *arg)
{
    struct sacom_softc *sc = arg;
    bus_space_tag_t iot = sc->sc_iot;
    bus_space_handle_t ioh = sc->sc_ioh;
    u_char *put, *end;
    u_int cc;
    u_int sr0, sr1;

    if (COM_ISALIVE(sc) == 0)
        return 0;

    COM_LOCK(sc);
    sr0 = bus_space_read_4(iot, ioh, SACOM_SR0);
    if (!sr0) {
        COM_UNLOCK(sc);
        return 0;
    }
    if (ISSET(sr0, SR0_EIF))
        /* XXX silently discard error bits */
        bus_space_read_4(iot, ioh, SACOM_DR);
    if (ISSET(sr0, SR0_RBB))
        bus_space_write_4(iot, ioh, SACOM_SR0, SR0_RBB);
    if (ISSET(sr0, SR0_REB)) {
        bus_space_write_4(iot, ioh, SACOM_SR0, SR0_REB);
#if defined(DDB) || defined(KGDB)
#ifndef DDB_BREAK_CHAR
        if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
            console_debugger();
        }
#endif
#endif /* DDB || KGDB */
    }


    end = sc->sc_ebuf;
    put = sc->sc_rbput;
    cc = sc->sc_rbavail;

    sr1 = bus_space_read_4(iot, ioh, SACOM_SR1);
    if (ISSET(sr0, SR0_RFS | SR0_RID)) {
        if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
            while (cc > 0) {
                if (!ISSET(sr1, SR1_RNE)) {
                    bus_space_write_4(iot, ioh, SACOM_SR0,
                                      SR0_RID);
                    break;
                }
                put[0] = bus_space_read_4(iot, ioh, SACOM_DR);
                put[1] = sr1;
#if defined(DDB) && defined(DDB_BREAK_CHAR)
                if (put[0] == DDB_BREAK_CHAR &&
                        ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
                    console_debugger();

                    sr1 = bus_space_read_4(iot, ioh, SACOM_SR1);
                    continue;
                }
#endif
                put += 2;
                if (put >= end)
                    put = sc->sc_rbuf;
                cc--;

                sr1 = bus_space_read_4(iot, ioh, SACOM_SR1);
            }

            /*
             * Current string of incoming characters ended because
             * no more data was available or we ran out of space.
             * Schedule a receive event if any data was received.
             * If we're out of space, turn off receive interrupts.
             */
            sc->sc_rbput = put;
            sc->sc_rbavail = cc;
            if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
                sc->sc_rx_ready = 1;

            /* XXX do RX hardware flow control */

            /*
             * If we're out of space, disable receive interrupts
             * until the queue has drained a bit.
             */
            if (!cc) {
                SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
                CLR(sc->sc_cr3, CR3_RIE);
                bus_space_write_4(iot, ioh, SACOM_CR3,
                                  sc->sc_cr3);
            }
        } else {
#ifdef DIAGNOSTIC
            panic("sacomintr: we shouldn't reach here");
#endif
            CLR(sc->sc_cr3, CR3_RIE);
            bus_space_write_4(iot, ioh, SACOM_CR3, sc->sc_cr3);
        }
    }

    /*
     * Done handling any receive interrupts. See if data can be
     * transmitted as well. Schedule tx done event if no data left
     * and tty was marked busy.
     */
    sr0 = bus_space_read_4(iot, ioh, SACOM_SR0);
    if (ISSET(sr0, SR0_TFS)) {
        /*
         * If we've delayed a parameter change, do it now, and restart
         * output.
         * XXX sacom_loadchannelregs() waits TX completion,
         * XXX resulting in ~0.1s hang (300bps, 4 bytes) in worst case
         */
        if (sc->sc_heldchange) {
            sacom_loadchannelregs(sc);
            sc->sc_heldchange = 0;
            sc->sc_tbc = sc->sc_heldtbc;
            sc->sc_heldtbc = 0;
        }

        /* Output the next chunk of the contiguous buffer, if any. */
        if (sc->sc_tbc > 0) {
            sacom_filltx(sc);
        } else {
            /* Disable transmit completion interrupts if necessary. */
            if (ISSET(sc->sc_cr3, CR3_TIE)) {
                CLR(sc->sc_cr3, CR3_TIE);
                bus_space_write_4(iot, ioh, SACOM_CR3,
                                  sc->sc_cr3);
            }
            if (sc->sc_tx_busy) {
                sc->sc_tx_busy = 0;
                sc->sc_tx_done = 1;
            }
        }
    }
    COM_UNLOCK(sc);

    /* Wake up the poller. */
    softint_schedule(sc->sc_si);

#if NRND > 0 && defined(RND_COM)
    rnd_add_uint32(&sc->rnd_source, iir | lsr);
#endif
    return 1;
}
Esempio n. 15
0
int
sacomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
    struct sacom_softc *sc =
        device_lookup_private(&sacom_cd, COMUNIT(dev));
    struct tty *tp = sc->sc_tty;
    int error;
    int s;

    if (COM_ISALIVE(sc) == 0)
        return EIO;

    error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    if (error != EPASSTHROUGH)
        return error;

    error = ttioctl(tp, cmd, data, flag, l);
    if (error != EPASSTHROUGH)
        return error;

    error = 0;

    s = splserial();
    COM_LOCK(sc);

    switch (cmd) {
    case TIOCSBRK:
        sacom_break(sc, 1);
        break;

    case TIOCCBRK:
        sacom_break(sc, 0);
        break;

    case TIOCSDTR:
        sacom_modem(sc, 1);
        break;

    case TIOCCDTR:
        sacom_modem(sc, 0);
        break;

    case TIOCGFLAGS:
        *(int *)data = sc->sc_swflags;
        break;

    case TIOCSFLAGS:
        error = kauth_authorize_device_tty(l->l_cred,
                                           KAUTH_DEVICE_TTY_PRIVSET, tp);
        if (error)
            break;
        sc->sc_swflags = *(int *)data;
        break;

    case TIOCMSET:
    case TIOCMBIS:
    case TIOCMBIC:
        tiocm_to_sacom(sc, cmd, *(int *)data);
        break;

    case TIOCMGET:
        *(int *)data = sacom_to_tiocm(sc);
        break;

    default:
        error = EPASSTHROUGH;
        break;
    }

    COM_UNLOCK(sc);
    splx(s);

#ifdef COM_DEBUG
    if (sacom_debug)
        comstatus(sc, "comioctl ");
#endif

    return error;
}
Esempio n. 16
0
int
sacomparam(struct tty *tp, struct termios *t)
{
    struct sacom_softc *sc =
        device_lookup_private(&sacom_cd, COMUNIT(tp->t_dev));
    int ospeed = SACOMSPEED(t->c_ospeed);
    u_int cr0;
    int s;

    if (COM_ISALIVE(sc) == 0)
        return EIO;

    /* Check requested parameters. */
    if (ospeed < 0)
        return EINVAL;
    if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
        return EINVAL;

    /*
     * For the console, always force CLOCAL and !HUPCL, so that the port
     * is always active.
     */
    if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
            ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
        SET(t->c_cflag, CLOCAL);
        CLR(t->c_cflag, HUPCL);
    }

    /*
     * If there were no changes, don't do anything.  This avoids dropping
     * input and improves performance when all we did was frob things like
     * VMIN and VTIME.
     */
    if (tp->t_ospeed == t->c_ospeed &&
            tp->t_cflag == t->c_cflag)
        return 0;

    cr0 = cflag2cr0(t->c_cflag);

    s = splserial();
    COM_LOCK(sc);

    sc->sc_cr0 = cr0;

    sc->sc_speed = ospeed;

    /* And copy to tty. */
    tp->t_ispeed = 0;
    tp->t_ospeed = t->c_ospeed;
    tp->t_cflag = t->c_cflag;

    if (!sc->sc_heldchange) {
        if (sc->sc_tx_busy) {
            sc->sc_heldtbc = sc->sc_tbc;
            sc->sc_tbc = 0;
            sc->sc_heldchange = 1;
        } else
            sacom_loadchannelregs(sc);
    }

    if (!ISSET(t->c_cflag, CHWFLOW)) {
        /* Disable the high water mark. */
        if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
            CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
            sacom_schedrx(sc);
        }
        if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
            CLR(sc->sc_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
            sacom_hwiflow(sc);
        }
    }

    COM_UNLOCK(sc);
    splx(s);

    (void) (*tp->t_linesw->l_modem)(tp, 1);

#ifdef COM_DEBUG
    if (sacom_debug)
        comstatus(sc, "comparam ");
#endif

    return 0;
}
static int
at91usart_param(struct tty *tp, struct termios *t)
{
	struct at91usart_softc *sc
		= device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev));
	int s;

	if (COM_ISALIVE(sc) == 0)
		return (EIO);

	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
		return (EINVAL);

	/*
	 * For the console, always force CLOCAL and !HUPCL, so that the port
	 * is always active.
	 */
	if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
	    ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
		SET(t->c_cflag, CLOCAL);
		CLR(t->c_cflag, HUPCL);
	}

	/*
	 * If there were no changes, don't do anything.  This avoids dropping
	 * input and improves performance when all we did was frob things like
	 * VMIN and VTIME.
	 */
	if (tp->t_ospeed == t->c_ospeed &&
	    tp->t_cflag == t->c_cflag)
		return (0);

	s = spltty();

	sc->sc_brgr = (AT91_MSTCLK / 16 + t->c_ospeed / 2) / t->c_ospeed;
	
	/* And copy to tty. */
	tp->t_ispeed = 0;
	tp->t_ospeed = t->c_ospeed;
	tp->t_cflag = t->c_cflag;
	at91usart_set(sc);

	splx(s);

	/*
	 * Update the tty layer's idea of the carrier bit.
	 * We tell tty the carrier is always on.
	 */
	(void) (*tp->t_linesw->l_modem)(tp, 1);

#ifdef COM_DEBUG
	if (com_debug)
		comstatus(sc, "comparam ");
#endif

	/* tell the upper layer about hwflow.. */
	if (sc->hwflow)
		(*sc->hwflow)(sc, t->c_cflag);

	return (0);
}