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_thread(void *arg) { struct udsir_softc *sc = arg; int error; DPRINTFN(20, ("%s: starting polling thread\n", __func__)); while (!sc->sc_closing) { if (!sc->sc_rd_readinprogress && !UDSIR_BLOCK_RX_DATA(sc)) udsir_periodic(sc); if (!sc->sc_closing) { error = tsleep(&sc->sc_thread, PWAIT, "udsir", hz / 10); if (error == EWOULDBLOCK && sc->sc_rd_expectdataticks > 0) /* * After a timeout decrement the tick * counter within which time we expect * data to arrive if we are receiving * data... */ sc->sc_rd_expectdataticks--; } } DPRINTFN(20, ("%s: exiting polling thread\n", __func__)); sc->sc_thread = NULL; wakeup(&sc->sc_closing); if (--sc->sc_refcnt < 0) usb_detach_wakeupold(sc->sc_dev); kthread_exit(0); }
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_write(void *h, struct uio *uio, int flag) { struct udsir_softc *sc = h; usbd_status err; uint32_t wrlen; int error, sirlength; uint8_t *wrbuf; int s; DPRINTFN(1, ("%s: sc=%p\n", __func__, sc)); if (sc->sc_dying) return EIO; #ifdef DIAGNOSTIC if (sc->sc_wr_buf == NULL) return EINVAL; #endif wrlen = uio->uio_resid; if (wrlen > sc->sc_wr_maxpsz) return EINVAL; sc->sc_refcnt++; if (!UDSIR_BLOCK_RX_DATA(sc)) { /* * If reads are not blocked, determine what action we * should potentially take... */ if (sc->sc_direction == udir_output) { /* * If the last operation was an output, wait for the * polling thread to check for incoming data. */ sc->sc_wr_stalewrite = 1; wakeup(&sc->sc_thread); } else if (!sc->sc_rd_readinprogress && (sc->sc_direction == udir_idle || sc->sc_direction == udir_input)) { /* If idle, check for input before outputting */ udsir_start_read(sc); } } s = splusb(); while (sc->sc_wr_stalewrite || (sc->sc_direction != udir_output && sc->sc_direction != udir_idle)) { DPRINTFN(5, ("%s: sc=%p stalewrite=%d direction=%d, " "calling tsleep()\n", __func__, sc, sc->sc_wr_stalewrite, sc->sc_direction)); error = tsleep(&sc->sc_wr_buf, PZERO | PCATCH, "usirwr", 0); if (sc->sc_dying) error = EIO; if (error) { splx(s); DPRINTFN(0, ("%s: tsleep() = %d\n", __func__, error)); goto ret; } } splx(s); wrbuf = sc->sc_wr_buf; sirlength = irda_sir_frame(wrbuf, MAX_UDSIR_OUTPUT_FRAME, uio, sc->sc_params.ebofs); if (sirlength < 0) error = -sirlength; else { uint32_t btlen; DPRINTFN(1, ("%s: transfer %u bytes\n", __func__, (unsigned int)wrlen)); btlen = sirlength; sc->sc_direction = udir_output; #ifdef UDSIR_DEBUG if (udsirdebug >= 20) udsir_dumpdata(wrbuf, btlen, __func__); #endif err = usbd_intr_transfer(sc->sc_wr_xfer, sc->sc_wr_pipe, USBD_FORCE_SHORT_XFER, UDSIR_WR_TIMEOUT, wrbuf, &btlen); DPRINTFN(2, ("%s: err=%d\n", __func__, err)); if (err != USBD_NORMAL_COMPLETION) { if (err == USBD_INTERRUPTED) error = EINTR; else if (err == USBD_TIMEOUT) error = ETIMEDOUT; else error = EIO; } else error = 0; } ret: if (--sc->sc_refcnt < 0) usb_detach_wakeupold(sc->sc_dev); DPRINTFN(1, ("%s: sc=%p done\n", __func__, sc)); return error; }
/* 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; }