summaryrefslogtreecommitdiff
path: root/sys/dev/usb/serial/usb_serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/serial/usb_serial.c')
-rw-r--r--sys/dev/usb/serial/usb_serial.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/sys/dev/usb/serial/usb_serial.c b/sys/dev/usb/serial/usb_serial.c
index 23ee3305a181..c5fc14b41b4d 100644
--- a/sys/dev/usb/serial/usb_serial.c
+++ b/sys/dev/usb/serial/usb_serial.c
@@ -161,6 +161,7 @@ static tsw_param_t ucom_param;
static tsw_outwakeup_t ucom_outwakeup;
static tsw_inwakeup_t ucom_inwakeup;
static tsw_free_t ucom_free;
+static tsw_busy_t ucom_busy;
static struct ttydevsw ucom_class = {
.tsw_flags = TF_INITLOCK | TF_CALLOUT,
@@ -172,6 +173,7 @@ static struct ttydevsw ucom_class = {
.tsw_param = ucom_param,
.tsw_modem = ucom_modem,
.tsw_free = ucom_free,
+ .tsw_busy = ucom_busy,
};
MODULE_DEPEND(ucom, usb, 1, 1, 1);
@@ -1294,6 +1296,27 @@ ucom_outwakeup(struct tty *tp)
ucom_start_transfers(sc);
}
+static bool
+ucom_busy(struct tty *tp)
+{
+ struct ucom_softc *sc = tty_softc(tp);
+ const uint8_t txidle = ULSR_TXRDY | ULSR_TSRE;
+
+ UCOM_MTX_ASSERT(sc, MA_OWNED);
+
+ DPRINTFN(3, "sc = %p lsr 0x%02x\n", sc, sc->sc_lsr);
+
+ /*
+ * If the driver maintains the txidle bits in LSR, we can use them to
+ * determine whether the transmitter is busy or idle. Otherwise we have
+ * to assume it is idle to avoid hanging forever on tcdrain(3).
+ */
+ if (sc->sc_flag & UCOM_FLAG_LSRTXIDLE)
+ return ((sc->sc_lsr & txidle) != txidle);
+ else
+ return (false);
+}
+
/*------------------------------------------------------------------------*
* ucom_get_data
*