Module Name:    src
Committed By:   riastradh
Date:           Mon Mar 28 12:43:03 UTC 2022

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

Log Message:
uhidev(9): New uhidev_write_async.

Like uhidev_write but issues the transfer asynchronously with a
callback.

Use it in ucycom(4).

Also, clear endpoint stalls asynchronously -- can't do them
synchronously in xfer callbacks which run at softint and therefore
can't wait in cv_wait as usbd_do_request does.


To generate a diff of this commit:
cvs rdiff -u -r1.52 -r1.53 src/sys/dev/usb/ucycom.c
cvs rdiff -u -r1.83 -r1.84 src/sys/dev/usb/uhidev.c
cvs rdiff -u -r1.22 -r1.23 src/sys/dev/usb/uhidev.h

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.52 src/sys/dev/usb/ucycom.c:1.53
--- src/sys/dev/usb/ucycom.c:1.52	Mon Mar 28 12:42:54 2022
+++ src/sys/dev/usb/ucycom.c	Mon Mar 28 12:43:03 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ucycom.c,v 1.52 2022/03/28 12:42:54 riastradh Exp $	*/
+/*	$NetBSD: ucycom.c,v 1.53 2022/03/28 12:43:03 riastradh Exp $	*/
 
 /*
  * Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ucycom.c,v 1.52 2022/03/28 12:42:54 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucycom.c,v 1.53 2022/03/28 12:43:03 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -592,11 +592,9 @@ ucycomstart(struct tty *tp)
 	}
 #endif
 	DPRINTFN(4,("ucycomstart: %d chars\n", len));
-	usbd_setup_xfer(sc->sc_hdev.sc_parent->sc_oxfer, sc, sc->sc_obuf,
-	    sc->sc_olen, 0, USBD_NO_TIMEOUT, ucycomwritecb);
-
 	/* What can we do on error? */
-	err = usbd_transfer(sc->sc_hdev.sc_parent->sc_oxfer);
+	err = uhidev_write_async(&sc->sc_hdev, sc->sc_obuf, sc->sc_olen, 0,
+	    USBD_NO_TIMEOUT, ucycomwritecb, sc);
 
 #ifdef UCYCOM_DEBUG
 	if (err != USBD_IN_PROGRESS)
@@ -621,7 +619,6 @@ ucycomwritecb(struct usbd_xfer *xfer, vo
 
 	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;
 	}

Index: src/sys/dev/usb/uhidev.c
diff -u src/sys/dev/usb/uhidev.c:1.83 src/sys/dev/usb/uhidev.c:1.84
--- src/sys/dev/usb/uhidev.c:1.83	Mon Mar 28 12:42:54 2022
+++ src/sys/dev/usb/uhidev.c	Mon Mar 28 12:43:03 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhidev.c,v 1.83 2022/03/28 12:42:54 riastradh Exp $	*/
+/*	$NetBSD: uhidev.c,v 1.84 2022/03/28 12:43:03 riastradh Exp $	*/
 
 /*
  * Copyright (c) 2001, 2012 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.83 2022/03/28 12:42:54 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.84 2022/03/28 12:43:03 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -1025,3 +1025,74 @@ uhidev_write(struct uhidev *scd, void *d
 out:	mutex_exit(&sc->sc_lock);
 	return err;
 }
+
+static void
+uhidev_write_callback(struct usbd_xfer *xfer, void *cookie, usbd_status err)
+{
+	struct uhidev_softc *sc = cookie;
+	usbd_callback writecallback;
+	void *writecookie;
+
+	if (err) {
+		if (err != USBD_CANCELLED)
+			usbd_clear_endpoint_stall_async(sc->sc_opipe);
+	}
+
+	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_writelock == (void *)1);
+	writecallback = sc->sc_writecallback;
+	writecookie = sc->sc_writecookie;
+	sc->sc_writereportid = -1;
+	sc->sc_writelock = NULL;
+	sc->sc_writecallback = NULL;
+	sc->sc_writecookie = NULL;
+	cv_broadcast(&sc->sc_cv);
+	mutex_exit(&sc->sc_lock);
+
+	(*writecallback)(xfer, writecookie, err);
+}
+
+usbd_status
+uhidev_write_async(struct uhidev *scd, void *data, int len, int flags,
+    int timo, usbd_callback writecallback, void *writecookie)
+{
+	struct uhidev_softc *sc = scd->sc_parent;
+	usbd_status err;
+
+	DPRINTF(("%s: data=%p, len=%d\n", __func__, data, len));
+
+	if (sc->sc_opipe == NULL)
+		return USBD_INVAL;
+
+	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_refcnt);
+	if (sc->sc_dying) {
+		err = USBD_IOERROR;
+		goto out;
+	}
+	if (sc->sc_writelock != NULL) {
+		err = USBD_IN_USE;
+		goto out;
+	}
+	sc->sc_writelock = (void *)1; /* XXX no lwp to attribute async xfer */
+	sc->sc_writereportid = scd->sc_report_id;
+	sc->sc_writecallback = writecallback;
+	sc->sc_writecookie = writecookie;
+	usbd_setup_xfer(sc->sc_oxfer, sc, data, len, flags, timo,
+	    uhidev_write_callback);
+	err = usbd_transfer(sc->sc_oxfer);
+	switch (err) {
+	case USBD_IN_PROGRESS:
+		break;
+	case USBD_NORMAL_COMPLETION:
+		panic("unexpected normal completion of async xfer under lock");
+	default:		/* error */
+		sc->sc_writelock = NULL;
+		sc->sc_writereportid = -1;
+		sc->sc_writecallback = NULL;
+		sc->sc_writecookie = NULL;
+		cv_broadcast(&sc->sc_cv);
+	}
+out:	mutex_exit(&sc->sc_lock);
+	return err;
+}

Index: src/sys/dev/usb/uhidev.h
diff -u src/sys/dev/usb/uhidev.h:1.22 src/sys/dev/usb/uhidev.h:1.23
--- src/sys/dev/usb/uhidev.h:1.22	Mon Mar 28 12:42:54 2022
+++ src/sys/dev/usb/uhidev.h	Mon Mar 28 12:43:03 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhidev.h,v 1.22 2022/03/28 12:42:54 riastradh Exp $	*/
+/*	$NetBSD: uhidev.h,v 1.23 2022/03/28 12:43:03 riastradh Exp $	*/
 
 /*
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -68,6 +68,8 @@ struct uhidev_softc {
 	struct usbd_pipe *sc_ipipe;	/* input interrupt pipe */
 	struct usbd_pipe *sc_opipe;	/* output interrupt pipe */
 	struct usbd_xfer *sc_oxfer;	/* write request */
+	usbd_callback sc_writecallback;	/* async write request callback */
+	void *sc_writecookie;
 
 	u_int sc_flags;
 #define UHIDEV_F_XB1	0x0001	/* Xbox 1 controller */
@@ -98,6 +100,8 @@ void uhidev_close(struct uhidev *);
 usbd_status uhidev_set_report(struct uhidev *, int, void *, int);
 usbd_status uhidev_get_report(struct uhidev *, int, void *, int);
 usbd_status uhidev_write(struct uhidev *, void *, int);
+usbd_status uhidev_write_async(struct uhidev *, void *, int, int, int,
+    usbd_callback, void *);
 
 #define	UHIDEV_OSIZE	64
 

Reply via email to