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; } }
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; }
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); } }
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); } }
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); } }
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); } }