Module Name:    src
Committed By:   skrll
Date:           Thu Aug  6 07:07:31 UTC 2009

Modified Files:
        src/sys/dev/usb: ucycom.c

Log Message:
Make ucycomstart use usbd_setup_xfer and a callback so that it doesn't
(attempt to) sleep in interrupt context.

>From David Howland in PR 36276 with changes from me.

XXX Still losing data on input.


To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/sys/dev/usb/ucycom.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/ucycom.c
diff -u src/sys/dev/usb/ucycom.c:1.28 src/sys/dev/usb/ucycom.c:1.29
--- src/sys/dev/usb/ucycom.c:1.28	Fri Jul 24 06:58:24 2009
+++ src/sys/dev/usb/ucycom.c	Thu Aug  6 07:07:30 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: ucycom.c,v 1.28 2009/07/24 06:58:24 skrll Exp $	*/
+/*	$NetBSD: ucycom.c,v 1.29 2009/08/06 07:07:30 skrll Exp $	*/
 
 /*
  * Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ucycom.c,v 1.28 2009/07/24 06:58:24 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucycom.c,v 1.29 2009/08/06 07:07:30 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -66,7 +66,7 @@
 #ifdef UCYCOM_DEBUG
 #define DPRINTF(x)	if (ucycomdebug) logprintf x
 #define DPRINTFN(n, x)	if (ucycomdebug > (n)) logprintf x
-int	ucycomdebug = 0;
+int	ucycomdebug = 20;
 #else
 #define DPRINTF(x)
 #define DPRINTFN(n,x)
@@ -122,6 +122,7 @@
 	size_t			sc_olen; /* output report length */
 
 	uint8_t			*sc_obuf;
+	int			sc_wlen;
 
 	/* settings */
 	uint32_t		sc_baud;
@@ -150,6 +151,7 @@
 
 Static int ucycomparam(struct tty *, struct termios *);
 Static void ucycomstart(struct tty *);
+Static void ucycomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
 Static void ucycom_intr(struct uhidev *, void *, u_int);
 Static int ucycom_configure(struct ucycom_softc *, uint32_t, uint8_t);
 Static void tiocm_to_ucycom(struct ucycom_softc *, u_long, int);
@@ -444,8 +446,9 @@
 {
 	struct ucycom_softc *sc =
 	    device_lookup_private(&ucycom_cd, UCYCOMUNIT(tp->t_dev));
+	usbd_status err;
 	u_char *data;
-	int cnt, len, err, s;
+	int cnt, len, s;
 
 	if (sc->sc_dying)
 		return;
@@ -541,6 +544,7 @@
 		goto out;
 	}
 	splx(s);
+	sc->sc_wlen = len;
 
 #ifdef UCYCOM_DEBUG
 	if (ucycomdebug > 5) {
@@ -555,26 +559,65 @@
 		}
 	}
 #endif
-	err = uhidev_write(sc->sc_hdev.sc_parent, sc->sc_obuf, sc->sc_olen);
+	DPRINTFN(4,("ucycomstart: %d chars\n", len));
+	usbd_setup_xfer(sc->sc_hdev.sc_parent->sc_oxfer,
+	    sc->sc_hdev.sc_parent->sc_opipe, (usbd_private_handle)sc,
+	    sc->sc_obuf, sc->sc_olen, 0 /* USBD_NO_COPY */, USBD_NO_TIMEOUT,
+	    ucycomwritecb);
 
-	if (err) {
-		DPRINTF(("ucycomstart: error doing uhidev_write = %d\n", err));
-	}
+	/* What can we do on error? */
+	err = usbd_transfer(sc->sc_hdev.sc_parent->sc_oxfer);
 
 #ifdef UCYCOM_DEBUG
-	ucycom_get_cfg(sc);
+	if (err != USBD_IN_PROGRESS)
+		DPRINTF(("ucycomstart: err=%s\n", usbd_errstr(err)));
 #endif
-	DPRINTFN(4,("ucycomstart: req %d chars did %d chars\n", cnt, len));
+	return;
+
+out:
+	splx(s);
+}
+
+Static void
+ucycomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
+{
+	struct ucycom_softc *sc = (struct ucycom_softc *)p;
+	struct tty *tp = sc->sc_tty;
+	usbd_status stat;
+	int len, s;
+
+	if (status == USBD_CANCELLED || sc->sc_dying)
+		goto error;
+
+	if (status) {
+		DPRINTF(("ucycomwritecb: status=%d\n", status));
+		usbd_clear_endpoint_stall(sc->sc_hdev.sc_parent->sc_opipe);
+		/* XXX we should restart after some delay. */
+		goto error;
+	}
 
- 	s = spltty();
+	usbd_get_xfer_status(xfer, NULL, NULL, &len, &stat);
+
+	if (status != USBD_NORMAL_COMPLETION) {
+		DPRINTFN(4,("ucycomwritecb: status = %d\n", status));
+		goto error;
+	}
+
+	DPRINTFN(4,("ucycomwritecb: did %d/%d chars\n", sc->sc_wlen, len));
+
+	s = spltty();
 	CLR(tp->t_state, TS_BUSY);
 	if (ISSET(tp->t_state, TS_FLUSH))
 		CLR(tp->t_state, TS_FLUSH);
 	else
-		ndflush(&tp->t_outq, len);
+		ndflush(&tp->t_outq, sc->sc_wlen);
 	(*tp->t_linesw->l_start)(tp);
+	splx(s);
+	return;
 
-out:
+error:
+	s = spltty();
+	CLR(tp->t_state, TS_BUSY);
 	splx(s);
 }
 
@@ -859,6 +902,10 @@
 	sc->sc_baud = baud;
 	sc->sc_cfg = cfg;
 
+#ifdef UCYCOM_DEBUG
+	ucycom_get_cfg(sc);
+#endif
+
 	return 0;
 }
 
@@ -902,9 +949,9 @@
 		}
 	}
 #endif
-	s = spltty();
 
 	/* Give characters to tty layer. */
+	s = spltty();
 	while (n-- > 0) {
 		DPRINTFN(7,("ucycom_intr: char=0x%02x\n", *cp));
 		if ((*rint)(*cp++, tp) == -1) {
@@ -1046,7 +1093,7 @@
 	cfg = report[4];
 	baud = (report[3] << 24) + (report[2] << 16) + (report[1] << 8) +
 	    report[0];
-	DPRINTF(("ucycom_configure: device reports %d baud, %d-%c-%d (%d)\n",
+	DPRINTF(("ucycom_get_cfg: device reports %d baud, %d-%c-%d (%d)\n",
 	    baud, 5 + (cfg & UCYCOM_DATA_MASK),
 	    (cfg & UCYCOM_PARITY_MASK) ?
 		((cfg & UCYCOM_PARITY_TYPE_MASK) ? 'O' : 'E') : 'N',

Reply via email to