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