Beispiel #1
0
void
ucom_status_change(struct ucom_softc *sc)
{
	struct tty *tp = sc->sc_tty;
	u_char old_msr;

	if (sc->sc_methods->ucom_get_status != NULL) {
		old_msr = sc->sc_msr;
		sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
		    &sc->sc_lsr, &sc->sc_msr);
		if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD)) {
			mutex_spin_enter(&timecounter_lock);
			pps_capture(&sc->sc_pps_state);
			pps_event(&sc->sc_pps_state,
			    (sc->sc_msr & UMSR_DCD) ?
			    PPS_CAPTUREASSERT :
			    PPS_CAPTURECLEAR);
			mutex_spin_exit(&timecounter_lock);

			(*tp->t_linesw->l_modem)(tp,
			    ISSET(sc->sc_msr, UMSR_DCD));
		}
	} else {
		sc->sc_lsr = 0;
		/* Assume DCD is present, if we have no chance to check it. */
		sc->sc_msr = UMSR_DCD;
	}
}
Beispiel #2
0
static void
elan_poll_pps(struct timecounter *tc)
{
	static int state;
	int i;
	uint16_t u, x, y, z;
	register_t saveintr;

	/*
	 * Grab the HW state as quickly and compactly as we can.  Disable
	 * interrupts to avoid measuring our interrupt service time on
	 * hw with quality clock sources.
	 */
	saveintr = intr_disable();
	x = *pps_ap[0];	/* state, must be first, see below */
	y = *pps_ap[1]; /* timer2 */
	z = *pps_ap[2]; /* timer1 */
	intr_restore(saveintr);

	/*
	 * Order is important here.  We need to check the state of the GPIO
	 * pin first, in order to avoid reading timer 1 right before the
	 * state change.  Technically pps_a may be zero in which case we
	 * harmlessly read the REVID register and the contents of pps_d is
	 * of no concern.
	 */

	i = x & pps_d;

	/* If state did not change or we don't have a GPIO pin, return */
	if (i == state || pps_a == 0)
		return;

	state = i;

	/* If the state is "low", flip the echo GPIO and return.  */
	if (!i) {
		if (echo_a)
			mmcrptr[(echo_a ^ 0xc) / 2] = echo_d;
		return;
	}

	/*
	 * Subtract timer1 from timer2 to compensate for time from the
	 * edge until we read the counters.
	 */
	u = y - z;

	pps_capture(&elan_pps);
	elan_pps.capcount = u;
	pps_event(&elan_pps, PPS_CAPTUREASSERT);

	/* Twiddle echo bit */
	if (echo_a)
		mmcrptr[echo_a / 2] = echo_d;
}
Beispiel #3
0
static void
uart_pps_process(struct uart_softc *sc, int ser_sig)
{
	sbintime_t now;
	int is_assert, pps_sig;

	/* Which signal is configured as PPS?  Early out if none. */
	switch(sc->sc_pps_mode & UART_PPS_SIGNAL_MASK) {
	case UART_PPS_CTS:
		pps_sig = SER_CTS;
		break;
	case UART_PPS_DCD:
		pps_sig = SER_DCD;
		break;
	default:
		return;
	}

	/* Early out if there is no change in the signal configured as PPS. */
	if ((ser_sig & SER_DELTA(pps_sig)) == 0)
		return;

	/*
	 * In narrow-pulse mode we need to synthesize both capture and clear
	 * events from a single "delta occurred" indication from the uart
	 * hardware because the pulse width is too narrow to reliably detect
	 * both edges.  However, when the pulse width is close to our interrupt
	 * processing latency we might intermittantly catch both edges.  To
	 * guard against generating spurious events when that happens, we use a
	 * separate timer to ensure at least half a second elapses before we
	 * generate another event.
	 */
	pps_capture(&sc->sc_pps);
	if (sc->sc_pps_mode & UART_PPS_NARROW_PULSE) {
		now = getsbinuptime();
		if (now > sc->sc_pps_captime + 500 * SBT_1MS) {
			sc->sc_pps_captime = now;
			pps_event(&sc->sc_pps, PPS_CAPTUREASSERT);
			pps_event(&sc->sc_pps, PPS_CAPTURECLEAR);
		}
	} else  {
		is_assert = ser_sig & pps_sig;
		if (sc->sc_pps_mode & UART_PPS_INVERT_PULSE)
			is_assert = !is_assert;
		pps_event(&sc->sc_pps, is_assert ? PPS_CAPTUREASSERT :
		    PPS_CAPTURECLEAR);
	}
}
Beispiel #4
0
static void
am335x_dmtimer_tc_poll_pps(struct timecounter *tc)
{
	struct am335x_dmtimer_softc *sc;

	sc = tc->tc_priv;

	/*
	 * Note that we don't have the TCAR interrupt enabled, but the hardware
	 * still provides the status bits in the "RAW" status register even when
	 * they're masked from generating an irq.  However, when clearing the
	 * TCAR status to re-arm the capture for the next second, we have to
	 * write to the IRQ status register, not the RAW register.  Quirky.
	 */
	if (am335x_dmtimer_tc_read_4(sc, DMT_IRQSTATUS_RAW) & DMT_IRQ_TCAR) {
		pps_capture(&sc->pps);
		sc->pps.capcount = am335x_dmtimer_tc_read_4(sc, DMT_TCAR1);
		am335x_dmtimer_tc_write_4(sc, DMT_IRQSTATUS, DMT_IRQ_TCAR);
		taskqueue_enqueue_fast(taskqueue_fast, &sc->pps_task);
	}
}
Beispiel #5
0
static void
ucom_cfg_status_change(struct usb_proc_msg *_task)
{
	struct ucom_cfg_task *task = 
	    (struct ucom_cfg_task *)_task;
	struct ucom_softc *sc = task->sc;
	struct tty *tp;
	uint8_t new_msr;
	uint8_t new_lsr;
	uint8_t msr_delta;
	uint8_t lsr_delta;

	tp = sc->sc_tty;

	UCOM_MTX_ASSERT(sc, MA_OWNED);

	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
		return;
	}
	if (sc->sc_callback->ucom_cfg_get_status == NULL) {
		return;
	}
	/* get status */

	new_msr = 0;
	new_lsr = 0;

	(sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);

	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
		/* TTY device closed */
		return;
	}
	msr_delta = (sc->sc_msr ^ new_msr);
	lsr_delta = (sc->sc_lsr ^ new_lsr);

	sc->sc_msr = new_msr;
	sc->sc_lsr = new_lsr;

	/*
	 * Time pulse counting support. Note that both CTS and DCD are
	 * active-low signals. The status bit is high to indicate that
	 * the signal on the line is low, which corresponds to a PPS
	 * clear event.
	 */
	switch(ucom_pps_mode) {
	case 1:
		if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) &&
		    (msr_delta & SER_CTS)) {
			pps_capture(&sc->sc_pps);
			pps_event(&sc->sc_pps, (sc->sc_msr & SER_CTS) ?
			    PPS_CAPTURECLEAR : PPS_CAPTUREASSERT);
		}
		break;
	case 2:
		if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) &&
		    (msr_delta & SER_DCD)) {
			pps_capture(&sc->sc_pps);
			pps_event(&sc->sc_pps, (sc->sc_msr & SER_DCD) ?
			    PPS_CAPTURECLEAR : PPS_CAPTUREASSERT);
		}
		break;
	default:
		break;
	}

	if (msr_delta & SER_DCD) {

		int onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;

		DPRINTF("DCD changed to %d\n", onoff);

		ttydisc_modem(tp, onoff);
	}

	if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {

		DPRINTF("BREAK detected\n");

		ttydisc_rint(tp, 0, TRE_BREAK);
		ttydisc_rint_done(tp);
	}

	if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {

		DPRINTF("Frame error detected\n");

		ttydisc_rint(tp, 0, TRE_FRAMING);
		ttydisc_rint_done(tp);
	}

	if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {

		DPRINTF("Parity error detected\n");

		ttydisc_rint(tp, 0, TRE_PARITY);
		ttydisc_rint_done(tp);
	}
}
Beispiel #6
0
static void
ucom_cfg_status_change(struct usb_proc_msg *_task)
{
	struct ucom_cfg_task *task = 
	    (struct ucom_cfg_task *)_task;
	struct ucom_softc *sc = task->sc;
	struct tty *tp;
	int onoff;
	uint8_t new_msr;
	uint8_t new_lsr;
	uint8_t msr_delta;
	uint8_t lsr_delta;
	uint8_t pps_signal;

	tp = sc->sc_tty;

	UCOM_MTX_ASSERT(sc, MA_OWNED);

	if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) {
		return;
	}
	if (sc->sc_callback->ucom_cfg_get_status == NULL) {
		return;
	}
	/* get status */

	new_msr = 0;
	new_lsr = 0;

	(sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr);

	if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
		/* TTY device closed */
		return;
	}
	msr_delta = (sc->sc_msr ^ new_msr);
	lsr_delta = (sc->sc_lsr ^ new_lsr);

	sc->sc_msr = new_msr;
	sc->sc_lsr = new_lsr;

	/*
	 * Time pulse counting support.
	 */
	switch(ucom_pps_mode & UART_PPS_SIGNAL_MASK) {
	case UART_PPS_CTS:
		pps_signal = SER_CTS;
		break;
	case UART_PPS_DCD:
		pps_signal = SER_DCD;
		break;
	default:
		pps_signal = 0;
		break;
	}

	if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) &&
	    (msr_delta & pps_signal)) {
		pps_capture(&sc->sc_pps);
		onoff = (sc->sc_msr & pps_signal) ? 1 : 0;
		if (ucom_pps_mode & UART_PPS_INVERT_PULSE)
			onoff = !onoff;
		pps_event(&sc->sc_pps, onoff ? PPS_CAPTUREASSERT :
		    PPS_CAPTURECLEAR);
	}

	if (msr_delta & SER_DCD) {

		onoff = (sc->sc_msr & SER_DCD) ? 1 : 0;

		DPRINTF("DCD changed to %d\n", onoff);

		ttydisc_modem(tp, onoff);
	}

	if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) {

		DPRINTF("BREAK detected\n");

		ttydisc_rint(tp, 0, TRE_BREAK);
		ttydisc_rint_done(tp);
	}

	if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) {

		DPRINTF("Frame error detected\n");

		ttydisc_rint(tp, 0, TRE_FRAMING);
		ttydisc_rint_done(tp);
	}

	if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) {

		DPRINTF("Parity error detected\n");

		ttydisc_rint(tp, 0, TRE_PARITY);
		ttydisc_rint_done(tp);
	}
}