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> /*