Module Name:    src
Committed By:   mrg
Date:           Sun Dec 21 23:00:35 UTC 2014

Modified Files:
        src/sys/dev/usb: FILES umidi.c umidi_quirks.c
Removed Files:
        src/sys/dev/usb: umidireg.h umidivar.h

Log Message:
various umidi clean ups:
- move the contents of umidi{reg,var}.h into umidi.c directly as they
  are not referenced by any other file.
- remove the useless include of umidi{reg,var}.h from umidi_quirks.c.
- add reference counting and wait/broadcast support to the IO paths.
- fix the error handling in midi_attach() and midi_open().
- sprinkle KASSERT() in several places.
- drop the local interrupt lock before calling into various parts of
  the USB code.  fixes lockdebug issues, and likely hangs.
- rename "binded" member as "bound".

with these most of the panics and problems i've seen are gone.  there
is still one lockdebug panic to deal with that happens when unplugging
umidi while midiplay(1) is running.


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/usb/FILES
cvs rdiff -u -r1.65 -r1.66 src/sys/dev/usb/umidi.c
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/usb/umidi_quirks.c
cvs rdiff -u -r1.8 -r0 src/sys/dev/usb/umidireg.h
cvs rdiff -u -r1.19 -r0 src/sys/dev/usb/umidivar.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/FILES
diff -u src/sys/dev/usb/FILES:1.12 src/sys/dev/usb/FILES:1.13
--- src/sys/dev/usb/FILES:1.12	Tue Jan 17 03:49:20 2012
+++ src/sys/dev/usb/FILES	Sun Dec 21 23:00:35 2014
@@ -55,8 +55,6 @@ umassvar.h		definitions for umass.c
 umidi.c			USB MIDI driver
 umidi_quirks.c		Strange MIDI devices
 umidi_quirks.h		  and definitions for it
-umidireg.h		Protocol definitions for umidi.c
-umidivar.h		definitions for umidi.c
 umodem.c		USB modem (CDC ACM) driver
 ums.c			USB mouse driver
 urio.c			USB Diamond Rio500 driver

Index: src/sys/dev/usb/umidi.c
diff -u src/sys/dev/usb/umidi.c:1.65 src/sys/dev/usb/umidi.c:1.66
--- src/sys/dev/usb/umidi.c:1.65	Tue Jan 22 21:29:53 2013
+++ src/sys/dev/usb/umidi.c	Sun Dec 21 23:00:35 2014
@@ -1,6 +1,7 @@
-/*	$NetBSD: umidi.c,v 1.65 2013/01/22 21:29:53 jmcneill Exp $	*/
+/*	$NetBSD: umidi.c,v 1.66 2014/12/21 23:00:35 mrg Exp $	*/
+
 /*
- * Copyright (c) 2001, 2012 The NetBSD Foundation, Inc.
+ * Copyright (c) 2001, 2012, 2014 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -31,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.65 2013/01/22 21:29:53 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.66 2014/12/21 23:00:35 mrg Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -54,13 +55,162 @@ __KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.
 
 #include <dev/auconv.h>
 #include <dev/usb/usbdevs.h>
-#include <dev/usb/uaudioreg.h>
-#include <dev/usb/umidireg.h>
-#include <dev/usb/umidivar.h>
 #include <dev/usb/umidi_quirks.h>
-
 #include <dev/midi_if.h>
 
+/* Jack Descriptor */
+#define UMIDI_MS_HEADER	0x01
+#define UMIDI_IN_JACK	0x02
+#define UMIDI_OUT_JACK	0x03
+
+/* Jack Type */
+#define UMIDI_EMBEDDED	0x01
+#define UMIDI_EXTERNAL	0x02
+
+/* generic, for iteration */
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDescriptorSubtype;
+} UPACKED umidi_cs_descriptor_t;
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDescriptorSubtype;
+	uWord		bcdMSC;
+	uWord		wTotalLength;
+} UPACKED umidi_cs_interface_descriptor_t;
+#define UMIDI_CS_INTERFACE_DESCRIPTOR_SIZE 7
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDescriptorSubtype;
+	uByte		bNumEmbMIDIJack;
+} UPACKED umidi_cs_endpoint_descriptor_t;
+#define UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE 4
+
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bDescriptorSubtype;
+	uByte		bJackType;
+	uByte		bJackID;
+} UPACKED umidi_jack_descriptor_t;
+#define	UMIDI_JACK_DESCRIPTOR_SIZE	5
+
+
+#define TO_D(p) ((usb_descriptor_t *)(p))
+#define NEXT_D(desc) TO_D((char *)(desc)+(desc)->bLength)
+#define TO_IFD(desc) ((usb_interface_descriptor_t *)(desc))
+#define TO_CSIFD(desc) ((umidi_cs_interface_descriptor_t *)(desc))
+#define TO_EPD(desc) ((usb_endpoint_descriptor_t *)(desc))
+#define TO_CSEPD(desc) ((umidi_cs_endpoint_descriptor_t *)(desc))
+
+
+#define UMIDI_PACKET_SIZE 4
+
+/*
+ * hierarchie
+ *
+ * <-- parent	       child -->
+ *
+ * umidi(sc) -> endpoint -> jack   <- (dynamically assignable) - mididev
+ *	   ^	 |    ^	    |
+ *	   +-----+    +-----+
+ */
+
+/* midi device */
+struct umidi_mididev {
+	struct umidi_softc	*sc;
+	device_t		mdev;
+	/* */
+	struct umidi_jack	*in_jack;
+	struct umidi_jack	*out_jack;
+	char			*label;
+	size_t			label_len;
+	/* */
+	int			opened;
+	int			closing;
+	int			flags;
+};
+
+/* Jack Information */
+struct umidi_jack {
+	struct umidi_endpoint	*endpoint;
+	/* */
+	int			cable_number;
+	void			*arg;
+	int			bound;
+	int			opened;
+	unsigned char		*midiman_ppkt;
+	union {
+		struct {
+			void			(*intr)(void *);
+		} out;
+		struct {
+			void			(*intr)(void *, int);
+		} in;
+	} u;
+};
+
+#define UMIDI_MAX_EPJACKS	16
+typedef unsigned char (*umidi_packet_bufp)[UMIDI_PACKET_SIZE];
+/* endpoint data */
+struct umidi_endpoint {
+	struct umidi_softc	*sc;
+	/* */
+	int			addr;
+	usbd_pipe_handle	pipe;
+	usbd_xfer_handle	xfer;
+	umidi_packet_bufp	buffer;
+	umidi_packet_bufp	next_slot;
+	u_int32_t               buffer_size;
+	int			num_scheduled;
+	int			num_open;
+	int			num_jacks;
+	int			soliciting;
+	void			*solicit_cookie;
+	int			armed;
+	struct umidi_jack	*jacks[UMIDI_MAX_EPJACKS];
+	u_int16_t		this_schedule; /* see UMIDI_MAX_EPJACKS */
+	u_int16_t		next_schedule;
+};
+
+/* software context */
+struct umidi_softc {
+	device_t		sc_dev;
+	usbd_device_handle	sc_udev;
+	usbd_interface_handle	sc_iface;
+	const struct umidi_quirk	*sc_quirk;
+
+	int			sc_dying;
+
+	int			sc_out_num_jacks;
+	struct umidi_jack	*sc_out_jacks;
+	int			sc_in_num_jacks;
+	struct umidi_jack	*sc_in_jacks;
+	struct umidi_jack	*sc_jacks;
+
+	int			sc_num_mididevs;
+	struct umidi_mididev	*sc_mididevs;
+
+	int			sc_out_num_endpoints;
+	struct umidi_endpoint	*sc_out_ep;
+	int			sc_in_num_endpoints;
+	struct umidi_endpoint	*sc_in_ep;
+	struct umidi_endpoint	*sc_endpoints;
+	size_t			sc_endpoints_len;
+	int			cblnums_global;
+
+	kmutex_t		sc_lock;
+	kcondvar_t		sc_cv;
+	kcondvar_t		sc_detach_cv;
+
+	int			sc_refcnt;
+};
+
 #ifdef UMIDI_DEBUG
 #define DPRINTF(x)	if (umididebug) printf x
 #define DPRINTFN(n,x)	if (umididebug >= (n)) printf x
@@ -210,36 +360,33 @@ umidi_attach(device_t parent, device_t s
 
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB);
 	cv_init(&sc->sc_cv, "umidopcl");
+	cv_init(&sc->sc_detach_cv, "umidetcv");
+	sc->sc_refcnt = 0;
 
 	err = alloc_all_endpoints(sc);
 	if (err != USBD_NORMAL_COMPLETION) {
 		aprint_error_dev(self,
 		    "alloc_all_endpoints failed. (err=%d)\n", err);
-		goto error;
+		goto out;
 	}
 	err = alloc_all_jacks(sc);
 	if (err != USBD_NORMAL_COMPLETION) {
-		free_all_endpoints(sc);
 		aprint_error_dev(self, "alloc_all_jacks failed. (err=%d)\n",
 		    err);
-		goto error;
+		goto out_free_endpoints;
 	}
 	aprint_normal_dev(self, "out=%d, in=%d\n",
 	       sc->sc_out_num_jacks, sc->sc_in_num_jacks);
 
 	err = assign_all_jacks_automatically(sc);
 	if (err != USBD_NORMAL_COMPLETION) {
-		unbind_all_jacks(sc);
-		free_all_jacks(sc);
-		free_all_endpoints(sc);
 		aprint_error_dev(self,
 		    "assign_all_jacks_automatically failed. (err=%d)\n", err);
-		goto error;
+		goto out_free_jacks;
 	}
 	err = attach_all_mididevs(sc);
 	if (err != USBD_NORMAL_COMPLETION) {
-		free_all_jacks(sc);
-		free_all_endpoints(sc);
+		goto out_free_jacks;
 		aprint_error_dev(self,
 		    "attach_all_mididevs failed. (err=%d)\n", err);
 	}
@@ -252,7 +399,15 @@ umidi_attach(device_t parent, device_t s
 			   sc->sc_udev, sc->sc_dev);
 
 	return;
-error:
+
+out_free_jacks:
+	unbind_all_jacks(sc);
+	free_all_jacks(sc);
+	
+out_free_endpoints:
+	free_all_endpoints(sc);
+
+out:
 	aprint_error_dev(self, "disabled.\n");
 	sc->sc_dying = 1;
 	KERNEL_UNLOCK_ONE(curlwp);
@@ -299,7 +454,12 @@ umidi_detach(device_t self, int flags)
 
 	DPRINTFN(1,("umidi_detach\n"));
 
+	mutex_enter(&sc->sc_lock);
 	sc->sc_dying = 1;
+	if (--sc->sc_refcnt >= 0)
+		usb_detach_wait(sc->sc_dev, &sc->sc_detach_cv, &sc->sc_lock);
+	mutex_exit(&sc->sc_lock);
+
 	detach_all_mididevs(sc, flags);
 	free_all_mididevs(sc);
 	free_all_jacks(sc);
@@ -309,6 +469,7 @@ umidi_detach(device_t self, int flags)
 			   sc->sc_dev);
 
 	mutex_destroy(&sc->sc_lock);
+	cv_destroy(&sc->sc_detach_cv);
 	cv_destroy(&sc->sc_cv);
 
 	return 0;
@@ -329,6 +490,7 @@ umidi_open(void *addr,
 	struct umidi_softc *sc = mididev->sc;
 	usbd_status err;
 
+	KASSERT(mutex_owned(&sc->sc_lock));
 	DPRINTF(("umidi_open: sc=%p\n", sc));
 
 	if (!sc)
@@ -339,24 +501,27 @@ umidi_open(void *addr,
 		return EIO;
 
 	mididev->opened = 1;
-	mididev->closing = 0;
 	mididev->flags = flags;
 	if ((mididev->flags & FWRITE) && mididev->out_jack) {
 		err = open_out_jack(mididev->out_jack, arg, ointr);
-		if ( err != USBD_NORMAL_COMPLETION )
+		if (err != USBD_NORMAL_COMPLETION)
 			goto bad;
 	}
 	if ((mididev->flags & FREAD) && mididev->in_jack) {
 		err = open_in_jack(mididev->in_jack, arg, iintr);
-		if ( err != USBD_NORMAL_COMPLETION
-		&&   err != USBD_IN_PROGRESS )
+		KASSERT(mididev->opened);
+		if (err != USBD_NORMAL_COMPLETION &&
+		    err != USBD_IN_PROGRESS) {
+			close_out_jack(mididev->out_jack);
 			goto bad;
+		}
 	}
 
 	return 0;
 bad:
 	mididev->opened = 0;
 	DPRINTF(("umidi_open: usbd_status %d\n", err));
+	KASSERT(mutex_owned(&sc->sc_lock));
 	return USBD_IN_USE == err ? EBUSY : EIO;
 }
 
@@ -364,19 +529,27 @@ void
 umidi_close(void *addr)
 {
 	struct umidi_mididev *mididev = addr;
+	struct umidi_softc *sc = mididev->sc;
+
+	KASSERT(mutex_owned(&sc->sc_lock));
+
+	if (mididev->closing)
+		return;
 
 	mididev->closing = 1;
 
-	mutex_spin_exit(&mididev->sc->sc_lock);
+	sc->sc_refcnt++;
 
 	if ((mididev->flags & FWRITE) && mididev->out_jack)
 		close_out_jack(mididev->out_jack);
 	if ((mididev->flags & FREAD) && mididev->in_jack)
 		close_in_jack(mididev->in_jack);
 
-	mutex_spin_enter(&mididev->sc->sc_lock);
+	if (--sc->sc_refcnt < 0)
+		usb_detach_broadcast(sc->sc_dev, &sc->sc_detach_cv);
 
 	mididev->opened = 0;
+	mididev->closing = 0;
 }
 
 int
@@ -385,6 +558,8 @@ umidi_channelmsg(void *addr, int status,
 {
 	struct umidi_mididev *mididev = addr;
 
+	KASSERT(mutex_owned(&mididev->sc->sc_lock));
+
 	if (!mididev->out_jack || !mididev->opened || mididev->closing)
 		return EIO;
 	
@@ -397,6 +572,8 @@ umidi_commonmsg(void *addr, int status, 
 	struct umidi_mididev *mididev = addr;
 	int cin;
 
+	KASSERT(mutex_owned(&mididev->sc->sc_lock));
+
 	if (!mididev->out_jack || !mididev->opened || mididev->closing)
 		return EIO;
 
@@ -416,6 +593,8 @@ umidi_sysex(void *addr, u_char *msg, int
 	struct umidi_mididev *mididev = addr;
 	int cin;
 
+	KASSERT(mutex_owned(&mididev->sc->sc_lock));
+
 	if (!mididev->out_jack || !mididev->opened || mididev->closing)
 		return EIO;
 
@@ -435,6 +614,8 @@ umidi_rtmsg(void *addr, int d)
 	struct umidi_mididev *mididev = addr;
 	u_char msg = d;
 
+	KASSERT(mutex_owned(&mididev->sc->sc_lock));
+
 	if (!mididev->out_jack || !mididev->opened || mididev->closing)
 		return EIO;
 
@@ -448,6 +629,8 @@ umidi_getinfo(void *addr, struct midi_in
 	struct umidi_softc *sc = mididev->sc;
 	int mm = UMQ_ISTYPE(sc, UMQ_TYPE_MIDIMAN_GARBLE);
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	mi->name = mididev->label;
 	mi->props = MIDI_PROP_OUT_INTR;
 	if (mididev->in_jack)
@@ -656,7 +839,7 @@ alloc_all_endpoints_fixed_ep(struct umid
 		switch ( UE_GET_XFERTYPE(epd->bmAttributes) ) {
 		case UE_BULK:
 		case UE_INTERRUPT:
-			if ( UE_DIR_IN == UE_GET_DIR(epd->bEndpointAddress) )
+			if (UE_DIR_IN == UE_GET_DIR(epd->bEndpointAddress))
 				break;
 			/*FALLTHROUGH*/
 		default:
@@ -916,7 +1099,7 @@ alloc_all_jacks(struct umidi_softc *sc)
 	jack = &sc->sc_out_jacks[0];
 	for (i = 0; i < sc->sc_out_num_jacks; i++) {
 		jack->opened = 0;
-		jack->binded = 0;
+		jack->bound = 0;
 		jack->arg = NULL;
 		jack->u.out.intr = NULL;
 		jack->midiman_ppkt = NULL;
@@ -927,7 +1110,7 @@ alloc_all_jacks(struct umidi_softc *sc)
 	jack = &sc->sc_in_jacks[0];
 	for (i = 0; i < sc->sc_in_num_jacks; i++) {
 		jack->opened = 0;
-		jack->binded = 0;
+		jack->bound = 0;
 		jack->arg = NULL;
 		jack->u.in.intr = NULL;
 		if (sc->cblnums_global)
@@ -990,35 +1173,43 @@ bind_jacks_to_mididev(struct umidi_softc
 		      struct umidi_jack *in_jack,
 		      struct umidi_mididev *mididev)
 {
-	if ((out_jack && out_jack->binded) || (in_jack && in_jack->binded))
+	if ((out_jack && out_jack->bound) || (in_jack && in_jack->bound))
 		return USBD_IN_USE;
 	if (mididev->out_jack || mididev->in_jack)
 		return USBD_IN_USE;
 
 	if (out_jack)
-		out_jack->binded = 1;
+		out_jack->bound = 1;
 	if (in_jack)
-		in_jack->binded = 1;
+		in_jack->bound = 1;
 	mididev->in_jack = in_jack;
 	mididev->out_jack = out_jack;
 
+	mididev->closing = 0;
+
 	return USBD_NORMAL_COMPLETION;
 }
 
 static void
 unbind_jacks_from_mididev(struct umidi_mididev *mididev)
 {
+	KASSERT(mutex_owned(&mididev->sc->sc_lock));
+
+	mididev->closing = 1;
 
 	if ((mididev->flags & FWRITE) && mididev->out_jack)
 		close_out_jack(mididev->out_jack);
 	if ((mididev->flags & FREAD) && mididev->in_jack)
 		close_in_jack(mididev->in_jack);
 
-	if (mididev->out_jack)
-		mididev->out_jack->binded = 0;
-	if (mididev->in_jack)
-		mididev->in_jack->binded = 0;
-	mididev->out_jack = mididev->in_jack = NULL;
+	if (mididev->out_jack) {
+		mididev->out_jack->bound = 0;
+		mididev->out_jack = NULL;
+	}
+	if (mididev->in_jack) {
+		mididev->in_jack->bound = 0;
+		mididev->in_jack = NULL;
+	}
 }
 
 static void
@@ -1026,9 +1217,11 @@ unbind_all_jacks(struct umidi_softc *sc)
 {
 	int i;
 
+	mutex_spin_enter(&sc->sc_lock);
 	if (sc->sc_mididevs)
 		for (i = 0; i < sc->sc_num_mididevs; i++)
 			unbind_jacks_from_mididev(&sc->sc_mididevs[i]);
+	mutex_spin_exit(&sc->sc_lock);
 }
 
 static usbd_status
@@ -1045,7 +1238,7 @@ assign_all_jacks_automatically(struct um
 	if (err!=USBD_NORMAL_COMPLETION)
 		return err;
 
-	if ( UMQ_ISTYPE(sc, UMQ_TYPE_MD_FIXED))
+	if (UMQ_ISTYPE(sc, UMQ_TYPE_MD_FIXED))
 		asg_spec = umidi_get_quirk_data_from_type(sc->sc_quirk,
 					    		  UMQ_TYPE_MD_FIXED);
 	else
@@ -1070,7 +1263,7 @@ assign_all_jacks_automatically(struct um
 						     : NULL;
 		}
 		err = bind_jacks_to_mididev(sc, out, in, &sc->sc_mididevs[i]);
-		if (err!=USBD_NORMAL_COMPLETION) {
+		if (err != USBD_NORMAL_COMPLETION) {
 			free_all_mididevs(sc);
 			return err;
 		}
@@ -1132,11 +1325,17 @@ open_in_jack(struct umidi_jack *jack, vo
 	jack->u.in.intr = intr;
 	jack->opened = 1;
 	if (ep->num_open++ == 0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) {
+		/*
+		 * Can't hold the interrupt lock while calling into USB,
+		 * but we can safely drop it here.
+		 */
+		mutex_exit(&ep->sc->sc_lock);
 		err = start_input_transfer(ep);
 		if (err != USBD_NORMAL_COMPLETION &&
 		    err != USBD_IN_PROGRESS) {
 			ep->num_open--;
 		}
+		mutex_enter(&ep->sc->sc_lock);
 	}
 
 	return err;
@@ -1153,7 +1352,8 @@ close_out_jack(struct umidi_jack *jack)
 	if (jack->opened) {
 		ep = jack->endpoint;
 		sc = ep->sc;
-		mutex_spin_enter(&sc->sc_lock);
+
+		KASSERT(mutex_owned(&sc->sc_lock));
 		mask = 1 << (jack->cable_number);
 		while (mask & (ep->this_schedule | ep->next_schedule)) {
 			err = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock,
@@ -1171,7 +1371,6 @@ close_out_jack(struct umidi_jack *jack)
 			ep->this_schedule &= ~mask;
 			ep->next_schedule &= ~mask;
 		}
-		mutex_spin_exit(&sc->sc_lock);
 	}
 }
 
@@ -1179,9 +1378,21 @@ static void
 close_in_jack(struct umidi_jack *jack)
 {
 	if (jack->opened) {
+		struct umidi_softc *sc = jack->endpoint->sc;
+
+		KASSERT(mutex_owned(&sc->sc_lock));
+
 		jack->opened = 0;
 		if (--jack->endpoint->num_open == 0) {
+			/*
+			 * We have to drop the (interrupt) lock so that
+			 * the USB thread lock can be safely taken by
+			 * the abort operation.  This is safe as this
+			 * either closing or dying will be set proerly.
+			 */
+			mutex_spin_exit(&sc->sc_lock);
 			usbd_abort_pipe(jack->endpoint->pipe);
+			mutex_spin_enter(&sc->sc_lock);
 		}
 	}
 }
@@ -1204,13 +1415,17 @@ attach_mididev(struct umidi_softc *sc, s
 static usbd_status
 detach_mididev(struct umidi_mididev *mididev, int flags)
 {
-	if (!mididev->sc)
+	struct umidi_softc *sc = mididev->sc;
+
+	if (!sc)
 		return USBD_NO_ADDR;
 
+	mutex_spin_enter(&sc->sc_lock);
 	if (mididev->opened) {
 		umidi_close(mididev);
 	}
 	unbind_jacks_from_mididev(mididev);
+	mutex_spin_exit(&sc->sc_lock);
 
 	if (mididev->mdev != NULL)
 		config_detach(mididev->mdev, flags);
@@ -1229,9 +1444,9 @@ static void
 deactivate_mididev(struct umidi_mididev *mididev)
 {
 	if (mididev->out_jack)
-		mididev->out_jack->binded = 0;
+		mididev->out_jack->bound = 0;
 	if (mididev->in_jack)
-		mididev->in_jack->binded = 0;
+		mididev->in_jack->bound = 0;
 }
 
 static usbd_status
@@ -1248,10 +1463,19 @@ alloc_all_mididevs(struct umidi_softc *s
 static void
 free_all_mididevs(struct umidi_softc *sc)
 {
-	if (sc->sc_mididevs)
-		kmem_free(sc->sc_mididevs,
-			  sizeof(*sc->sc_mididevs)*sc->sc_num_mididevs);
+	struct umidi_mididev *mididevs;
+	size_t len;
+
+	mutex_enter(&sc->sc_lock);
+	mididevs = sc->sc_mididevs;
+	if (mididevs)
+		  len = sizeof(*sc->sc_mididevs )* sc->sc_num_mididevs;
+	sc->sc_mididevs = NULL;
 	sc->sc_num_mididevs = 0;
+	mutex_exit(&sc->sc_lock);
+
+	if (mididevs)
+		kmem_free(mididevs, len);
 }
 
 static usbd_status
@@ -1326,18 +1550,18 @@ describe_mididev(struct umidi_mididev *m
 	show_ep_in  = sc-> sc_in_num_endpoints > 1 && !sc->cblnums_global;
 	show_ep_out = sc->sc_out_num_endpoints > 1 && !sc->cblnums_global;
 	
-	if ( NULL == md->in_jack )
+	if (NULL == md->in_jack)
 		in_label[0] = '\0';
-	else if ( show_ep_in )
+	else if (show_ep_in)
 		snprintf(in_label, sizeof in_label, "<%d(%x) ",
 		    md->in_jack->cable_number, md->in_jack->endpoint->addr);
 	else
 		snprintf(in_label, sizeof in_label, "<%d ",
 		    md->in_jack->cable_number);
 	
-	if ( NULL == md->out_jack )
+	if (NULL == md->out_jack)
 		out_label[0] = '\0';
-	else if ( show_ep_out )
+	else if (show_ep_out)
 		snprintf(out_label, sizeof out_label, ">%d(%x) ",
 		    md->out_jack->cable_number, md->out_jack->endpoint->addr);
 	else
@@ -1506,14 +1730,18 @@ out_jack_output(struct umidi_jack *out_j
 	int plen;
 	int poff;
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return EIO;
 
 	if (!out_jack->opened)
 		return ENODEV; /* XXX as it was, is this the right errno? */
 
+	sc->sc_refcnt++;
+
 #ifdef UMIDI_DEBUG
-	if ( umididebug >= 100 )
+	if (umididebug >= 100)
 		microtime(&umidi_tv);
 #endif
 	DPRINTFN(100, ("umidi out: %"PRIu64".%06"PRIu64"s ep=%p cn=%d len=%d cin=%#x\n",
@@ -1556,7 +1784,7 @@ out_jack_output(struct umidi_jack *out_j
 	}
 	ep->next_schedule |= 1<<(out_jack->cable_number);
 	++ ep->num_scheduled;
-	if ( !ep->armed  &&  !ep->soliciting ) {
+	if (!ep->armed && !ep->soliciting) {
 		/*
 		 * It would be bad to call out_solicit directly here (the
 		 * caller need not be reentrant) but a soft interrupt allows
@@ -1567,6 +1795,9 @@ out_jack_output(struct umidi_jack *out_j
 		ep->soliciting = 1;
 		softint_schedule(ep->solicit_cookie);
 	}
+
+	if (--sc->sc_refcnt < 0)
+		usb_detach_broadcast(sc->sc_dev, &sc->sc_detach_cv);
 	
 	return 0;
 }
@@ -1624,7 +1855,7 @@ in_intr(usbd_xfer_handle xfer, usbd_priv
 			return;
 		}
 
-		if (!jack->binded || !jack->opened)
+		if (!jack->bound || !jack->opened)
 			continue;
 
 		DPRINTFN(500,("%s: input endpoint %p cable %d len %d: "
@@ -1659,11 +1890,11 @@ out_intr(usbd_xfer_handle xfer, usbd_pri
 
 	mutex_enter(&sc->sc_lock);
 #ifdef UMIDI_DEBUG
-	if ( umididebug >= 200 )
+	if (umididebug >= 200)
 		microtime(&umidi_tv);
 #endif
 	usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
-        if ( 0 == count % UMIDI_PACKET_SIZE ) {
+        if (0 == count % UMIDI_PACKET_SIZE) {
 		DPRINTFN(200,("%s: %"PRIu64".%06"PRIu64"s out ep %p xfer length %u\n",
 			     device_xname(ep->sc->sc_dev),
 			     umidi_tv.tv_sec%100, (uint64_t)umidi_tv.tv_usec, ep, count));
@@ -1761,8 +1992,15 @@ out_solicit_locked(void *arg)
 			(*jack->u.out.intr)(jack->arg);
 	}
 	/* intr lock held at loop exit */
-	if (!ep->armed && ep->next_slot > ep->buffer)
+	if (!ep->armed && ep->next_slot > ep->buffer) {
+		/*
+		 * Can't hold the interrupt lock while calling into USB,
+		 * but we can safely drop it here.
+		 */
+		mutex_exit(&ep->sc->sc_lock);
 		ep->armed = (USBD_IN_PROGRESS == start_output_transfer(ep));
+		mutex_enter(&ep->sc->sc_lock);
+	}
 	ep->soliciting = 0;
 }
 

Index: src/sys/dev/usb/umidi_quirks.c
diff -u src/sys/dev/usb/umidi_quirks.c:1.18 src/sys/dev/usb/umidi_quirks.c:1.19
--- src/sys/dev/usb/umidi_quirks.c:1.18	Fri May 18 07:52:54 2012
+++ src/sys/dev/usb/umidi_quirks.c	Sun Dec 21 23:00:35 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: umidi_quirks.c,v 1.18 2012/05/18 07:52:54 jdc Exp $	*/
+/*	$NetBSD: umidi_quirks.c,v 1.19 2014/12/21 23:00:35 mrg Exp $	*/
 
 /*
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umidi_quirks.c,v 1.18 2012/05/18 07:52:54 jdc Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umidi_quirks.c,v 1.19 2014/12/21 23:00:35 mrg Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -52,8 +52,6 @@ __KERNEL_RCSID(0, "$NetBSD: umidi_quirks
 #include <dev/auconv.h>
 #include <dev/usb/usbdevs.h>
 #include <dev/usb/uaudioreg.h>
-#include <dev/usb/umidireg.h>
-#include <dev/usb/umidivar.h>
 #include <dev/usb/umidi_quirks.h>
 
 /*

Reply via email to