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