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',