예제 #1
0
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;
}
예제 #2
0
파일: udsir.c 프로젝트: ryo/netbsd-src
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);
}
예제 #3
0
파일: udsir.c 프로젝트: ryo/netbsd-src
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);
	}
}
예제 #4
0
파일: udsir.c 프로젝트: ryo/netbsd-src
/* 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;
}
예제 #5
0
파일: udsir.c 프로젝트: ryo/netbsd-src
/* 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;
}