static usbd_status udsir_start_read(struct udsir_softc *sc) { usbd_status err; DPRINTFN(60, ("%s: sc=%p, size=%d\n", __func__, sc, sc->sc_rd_maxpsz)); if (sc->sc_dying) return USBD_IOERROR; if (UDSIR_BLOCK_RX_DATA(sc) || deframe_rd_ur(sc)) { /* * Can't start reading just yet. Since we aren't * going to start a read, have to switch direction to * idle. */ sc->sc_direction = udir_idle; return USBD_NORMAL_COMPLETION; } /* Starting a read... */ sc->sc_rd_readinprogress = 1; sc->sc_direction = udir_input; if (sc->sc_rd_err) { sc->sc_rd_err = 0; DPRINTFN(0, ("%s: clear stall\n", __func__)); usbd_clear_endpoint_stall(sc->sc_rd_pipe); } usbd_setup_xfer(sc->sc_rd_xfer, sc->sc_rd_pipe, sc, sc->sc_rd_buf, sc->sc_rd_maxpsz, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, udsir_rd_cb); err = usbd_transfer(sc->sc_rd_xfer); if (err != USBD_IN_PROGRESS) { DPRINTFN(0, ("%s: err=%d\n", __func__, (int)err)); return err; } return USBD_NORMAL_COMPLETION; }
static void udsir_rd_cb(struct usbd_xfer *xfer, void * priv, usbd_status status) { struct udsir_softc *sc = priv; uint32_t size; DPRINTFN(60, ("%s: sc=%p\n", __func__, sc)); /* Read is no longer in progress */ sc->sc_rd_readinprogress = 0; if (status == USBD_CANCELLED || sc->sc_closing) /* this is normal */ return; if (status) { size = 0; sc->sc_rd_err = 1; if (sc->sc_direction == udir_input || sc->sc_direction == udir_idle) { /* * Receive error, probably need to clear error * condition. */ sc->sc_direction = udir_stalled; } } else usbd_get_xfer_status(xfer, NULL, NULL, &size, NULL); sc->sc_rd_index = 0; sc->sc_rd_count = size; DPRINTFN(((size > 0 || sc->sc_rd_err != 0) ? 20 : 60), ("%s: sc=%p size=%u, err=%d\n", __func__, sc, size, sc->sc_rd_err)); #ifdef UDSIR_DEBUG if (udsirdebug >= 20 && size > 0) udsir_dumpdata(sc->sc_rd_buf, size, __func__); #endif if (deframe_rd_ur(sc) == 0) { if (!deframe_isclear(&sc->sc_framestate) && size == 0 && sc->sc_rd_expectdataticks == 0) { /* * Expected data, but didn't get it * within expected time... */ DPRINTFN(5,("%s: incoming packet timeout\n", __func__)); deframe_clear(&sc->sc_framestate); } else if (size > 0) { /* * If we also received actual data, reset the * data read timeout and wake up the possibly * sleeping thread... */ sc->sc_rd_expectdataticks = 2; wakeup(&sc->sc_thread); } } /* * Check if incoming data has stopped, or that we cannot * safely read any more data. In the case of the latter we * must switch to idle so that a write will not block... */ if (sc->sc_direction == udir_input && ((size == 0 && sc->sc_rd_expectdataticks == 0) || UDSIR_BLOCK_RX_DATA(sc))) { DPRINTFN(8, ("%s: idling on packet timeout, " "complete frame, or no data\n", __func__)); sc->sc_direction = udir_idle; /* Wake up for possible output */ wakeup(&sc->sc_wr_buf); selnotify(&sc->sc_wr_sel, 0, 0); } }
/* ARGSUSED */ static int udsir_read(void *h, struct uio *uio, int flag) { struct udsir_softc *sc = h; int s; int error; u_int uframelen; DPRINTFN(1, ("%s: sc=%p\n", __func__, sc)); if (sc->sc_dying) return EIO; #ifdef DIAGNOSTIC if (sc->sc_rd_buf == NULL) return EINVAL; #endif sc->sc_refcnt++; if (!sc->sc_rd_readinprogress && !UDSIR_BLOCK_RX_DATA(sc)) /* Possibly wake up polling thread */ wakeup(&sc->sc_thread); do { s = splusb(); while (sc->sc_ur_framelen == 0) { DPRINTFN(5, ("%s: calling tsleep()\n", __func__)); error = tsleep(&sc->sc_ur_framelen, PZERO | PCATCH, "usirrd", 0); if (sc->sc_dying) error = EIO; if (error) { splx(s); DPRINTFN(0, ("%s: tsleep() = %d\n", __func__, error)); goto ret; } } splx(s); uframelen = sc->sc_ur_framelen; DPRINTFN(1, ("%s: sc=%p framelen=%u, hdr=0x%02x\n", __func__, sc, uframelen, sc->sc_ur_buf[0])); if (uframelen > uio->uio_resid) error = EINVAL; else error = uiomove(sc->sc_ur_buf, uframelen, uio); sc->sc_ur_framelen = 0; if (deframe_rd_ur(sc) == 0 && uframelen > 0) { /* * Need to wait for another read to obtain a * complete frame... If we also obtained * actual data, wake up the possibly sleeping * thread immediately... */ wakeup(&sc->sc_thread); } } while (uframelen == 0); DPRINTFN(1, ("%s: return %d\n", __func__, error)); ret: if (--sc->sc_refcnt < 0) usb_detach_wakeupold(sc->sc_dev); return error; }