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

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

Log Message:
ucycom(4): Defer uhidev_write_async to taskq.

Can't submit USB transfers while holding tty_lock, a spin lock.


To generate a diff of this commit:
cvs rdiff -u -r1.53 -r1.54 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.53 src/sys/dev/usb/ucycom.c:1.54
--- src/sys/dev/usb/ucycom.c:1.53	Mon Mar 28 12:43:03 2022
+++ src/sys/dev/usb/ucycom.c	Mon Mar 28 12:43:30 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: ucycom.c,v 1.53 2022/03/28 12:43:03 riastradh Exp $	*/
+/*	$NetBSD: ucycom.c,v 1.54 2022/03/28 12:43:30 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.53 2022/03/28 12:43:03 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucycom.c,v 1.54 2022/03/28 12:43:30 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -118,7 +118,9 @@ int	ucycomdebug = 20;
 
 struct ucycom_softc {
 	struct uhidev		sc_hdev;
+	struct usbd_device	*sc_udev;
 
+	struct usb_task		sc_task;
 	struct tty		*sc_tty;
 
 	enum {
@@ -172,6 +174,7 @@ const struct cdevsw ucycom_cdevsw = {
 
 Static int ucycomparam(struct tty *, struct termios *);
 Static void ucycomstart(struct tty *);
+Static void ucycomstarttask(void *);
 Static void ucycomwritecb(struct usbd_xfer *, void *, usbd_status);
 Static void ucycom_intr(struct uhidev *, void *, u_int);
 Static int ucycom_configure(struct ucycom_softc *, uint32_t, uint8_t);
@@ -223,6 +226,7 @@ ucycom_attach(device_t parent, device_t 
 	sc->sc_hdev.sc_intr = ucycom_intr;
 	sc->sc_hdev.sc_parent = uha->parent;
 	sc->sc_hdev.sc_report_id = uha->reportid;
+	sc->sc_udev = uha->uiaa->uiaa_device;
 	sc->sc_init_state = UCYCOM_INIT_NONE;
 
 	uhidev_get_report_desc(uha->parent, &desc, &size);
@@ -237,6 +241,9 @@ ucycom_attach(device_t parent, device_t 
 
 	sc->sc_msr = sc->sc_mcr = 0;
 
+	/* not MP-safe */
+	usb_init_task(&sc->sc_task, ucycomstarttask, sc, 0);
+
 	/* set up tty */
 	sc->sc_tty = tty_alloc();
 	sc->sc_tty->t_sc = sc;
@@ -287,6 +294,8 @@ ucycom_detach(device_t self, int flags)
 	vdevgone(maj, mn | UCYCOMDIALOUT_MASK, mn | UCYCOMDIALOUT_MASK, VCHR);
 	vdevgone(maj, mn | UCYCOMCALLUNIT_MASK, mn | UCYCOMCALLUNIT_MASK, VCHR);
 
+	usb_rem_task_wait(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER, NULL);
+
 	/* Detach and free the tty. */
 	if (tp != NULL) {
 		DPRINTF(("ucycom_detach: tty_detach %p\n", tp));
@@ -482,6 +491,8 @@ ucycomstart(struct tty *tp)
 	u_char *data;
 	int cnt, len, s;
 
+	KASSERT(mutex_owned(&tty_lock));
+
 	if (sc->sc_dying)
 		return;
 
@@ -592,6 +603,19 @@ ucycomstart(struct tty *tp)
 	}
 #endif
 	DPRINTFN(4,("ucycomstart: %d chars\n", len));
+	usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER);
+	return;
+
+out:
+	splx(s);
+}
+
+Static void
+ucycomstarttask(void *cookie)
+{
+	struct ucycom_softc *sc = cookie;
+	usbd_status err;
+
 	/* What can we do on error? */
 	err = uhidev_write_async(&sc->sc_hdev, sc->sc_obuf, sc->sc_olen, 0,
 	    USBD_NO_TIMEOUT, ucycomwritecb, sc);
@@ -599,11 +623,9 @@ ucycomstart(struct tty *tp)
 #ifdef UCYCOM_DEBUG
 	if (err != USBD_IN_PROGRESS)
 		DPRINTF(("ucycomstart: err=%s\n", usbd_errstr(err)));
+#else
+	__USE(err);
 #endif
-	return;
-
-out:
-	splx(s);
 }
 
 Static void

Reply via email to