Module Name: src
Committed By: martin
Date: Sun Jan 11 14:13:25 UTC 2015
Modified Files:
src/sys/dev [netbsd-7]: midi.c midi_if.h midivar.h sequencer.c
sequencervar.h
src/sys/dev/usb [netbsd-7]: FILES umidi.c umidi_quirks.c
Removed Files:
src/sys/dev/usb [netbsd-7]: umidireg.h umidivar.h
Log Message:
Pull up following revision(s) (requested by mrg in ticket #407):
sys/dev/midivar.h: revision 1.20
sys/dev/usb/umidivar.h: file removal
sys/dev/midi.c: revision 1.82
sys/dev/midi.c: revision 1.83
sys/dev/usb/FILES: revision 1.13
sys/dev/midi_if.h: revision 1.26
sys/dev/sequencer.c: revision 1.60
sys/dev/sequencer.c: revision 1.61
sys/dev/sequencer.c: revision 1.62
sys/dev/sequencer.c: revision 1.63
sys/dev/usb/umidi_quirks.c: revision 1.19
sys/dev/usb/umidi.c: revision 1.66
sys/dev/usb/umidi.c: revision 1.67
sys/dev/usb/umidi.c: revision 1.68
sys/dev/usb/umidireg.h: file removal
sys/dev/sequencervar.h: revision 1.17
fix the midi_if documentation to properly describe the locks that will
be held during various operations.
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.
various clean ups for midi and sequencer:
midi specific:
- add reference counting for midi operations, and ensure that
detach waits for other threads to complete before tearing
down the device completely.
- in detach, halt midi callouts before destroying them
- re-check sc->dying after sleeping in midiread()
- in real_writebytes(), make sure we're open and not dying
- make sure we drop the interrupt lock before calling any code
that may want to check thread locks. this is now safe due to
the above changes.
sequencer specific:
- avoid caching the midi softc in the sequencer softc. instead,
every time we want to use it, look it up again and make sure
it still exists.
this fixes various crashes i've seen in the usb midi code when
detaching the umidi while it is active.
use __func__ in some debug messages.
- check sc->dying after sleeping in several more places, and
convert it into EIO error where necessary.
- remove a wrong additional mutex_exit() call.
- make sure to check sc->dying under the device lock.
- fix a confusion between midi(4) unit and connected to sequencer
devices.
- minor comment/debug clean ups.
fixes problems attempting to read or write from the right midi(4)
device using the sequencer(4) device when one or more of the
non-final devices fails to open with midiseq_open().
fix !AUDIO_DEBUG build.
CID/1261465: Dereference after NULL check.
CID/1261467: Unreachable code
actually fix one of the previous: don't test for NULL after deref.
To generate a diff of this commit:
cvs rdiff -u -r1.81 -r1.81.2.1 src/sys/dev/midi.c
cvs rdiff -u -r1.25 -r1.25.14.1 src/sys/dev/midi_if.h
cvs rdiff -u -r1.19 -r1.19.14.1 src/sys/dev/midivar.h
cvs rdiff -u -r1.59 -r1.59.2.1 src/sys/dev/sequencer.c
cvs rdiff -u -r1.16 -r1.16.10.1 src/sys/dev/sequencervar.h
cvs rdiff -u -r1.12 -r1.12.22.1 src/sys/dev/usb/FILES
cvs rdiff -u -r1.65 -r1.65.12.1 src/sys/dev/usb/umidi.c
cvs rdiff -u -r1.18 -r1.18.14.1 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/midi.c
diff -u src/sys/dev/midi.c:1.81 src/sys/dev/midi.c:1.81.2.1
--- src/sys/dev/midi.c:1.81 Fri Jul 25 08:10:35 2014
+++ src/sys/dev/midi.c Sun Jan 11 14:13:25 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: midi.c,v 1.81 2014/07/25 08:10:35 dholland Exp $ */
+/* $NetBSD: midi.c,v 1.81.2.1 2015/01/11 14:13:25 martin Exp $ */
/*
* Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.81 2014/07/25 08:10:35 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.81.2.1 2015/01/11 14:13:25 martin Exp $");
#include "midi.h"
#include "sequencer.h"
@@ -204,6 +204,11 @@ mididetach(device_t self, int flags)
mutex_enter(sc->lock);
sc->dying = 1;
+
+ if (--sc->refcnt >= 0) {
+ /* Wake anything? */
+ (void)cv_timedwait(&sc->detach_cv, sc->lock, hz * 60);
+ }
cv_broadcast(&sc->wchan);
cv_broadcast(&sc->rchan);
mutex_exit(sc->lock);
@@ -236,8 +241,17 @@ mididetach(device_t self, int flags)
sc->sih = NULL;
}
+ mutex_enter(sc->lock);
+ callout_halt(&sc->xmt_asense_co, sc->lock);
+ callout_halt(&sc->rcv_asense_co, sc->lock);
+ mutex_exit(sc->lock);
+
+ callout_destroy(&sc->xmt_asense_co);
+ callout_destroy(&sc->rcv_asense_co);
+
cv_destroy(&sc->wchan);
cv_destroy(&sc->rchan);
+ cv_destroy(&sc->detach_cv);
return (0);
}
@@ -266,9 +280,11 @@ midi_attach(struct midi_softc *sc)
cv_init(&sc->rchan, "midird");
cv_init(&sc->wchan, "midiwr");
+ cv_init(&sc->detach_cv, "mididet");
sc->dying = 0;
sc->isopen = 0;
+ sc->refcnt = 0;
mutex_enter(&hwif_softc_lock);
mutex_enter(sc->lock);
@@ -864,6 +880,8 @@ midiclose(dev_t dev, int flags, int ifmt
mutex_enter(sc->lock);
/* midi_start_output(sc); anything buffered => pbus already set! */
while (sc->pbus) {
+ if (sc->dying)
+ break;
DPRINTFN(8,("midiclose sleep ...\n"));
cv_wait(&sc->wchan, sc->lock);
}
@@ -952,6 +970,10 @@ midiread(dev_t dev, struct uio *uio, int
mutex_enter(sc->lock);
if (error)
break;
+ if (sc->dying) {
+ error = EIO;
+ break;
+ }
appetite -= buf_end - buf_cur;
buf_cur = mb->buf;
}
@@ -961,6 +983,10 @@ midiread(dev_t dev, struct uio *uio, int
mutex_enter(sc->lock);
if (error)
break;
+ if (sc->dying) {
+ error = EIO;
+ break;
+ }
buf_cur += appetite;
}
@@ -1253,13 +1279,13 @@ midi_intr_out(struct midi_softc *sc)
error = sc->hw_if->output(sc->hw_hdl, *buf_cur);
if (error && error != EINPROGRESS)
break;
- ++ buf_cur;
+ ++buf_cur;
MIDI_BUF_WRAP(buf);
- -- msglen;
+ --msglen;
if (msglen)
*idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur),msglen);
else {
- ++ idx_cur;
+ ++idx_cur;
MIDI_BUF_WRAP(idx);
}
if (!error) {
@@ -1306,9 +1332,15 @@ real_writebytes(struct midi_softc *sc, u
enum fst_form form;
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
+ int error;
KASSERT(mutex_owned(sc->lock));
+ if (sc->dying || !sc->isopen)
+ return EIO;
+
+ sc->refcnt++;
+
iend = ibuf + cc;
mb = &sc->outbuf;
arming = 0;
@@ -1329,19 +1361,17 @@ real_writebytes(struct midi_softc *sc, u
MIDI_BUF_PRODUCER_INIT(mb,idx);
MIDI_BUF_PRODUCER_INIT(mb,buf);
-
- if (sc->dying)
- return EIO;
while (ibuf < iend) {
got = midi_fst(&sc->xmt, *ibuf, form);
- ++ ibuf;
+ ++ibuf;
switch ( got) {
case FST_MORE:
continue;
case FST_ERR:
case FST_HUH:
- return EPROTO;
+ error = EPROTO;
+ goto out;
case FST_CHN:
case FST_CHV: /* only occurs in VCOMP form */
case FST_COM:
@@ -1366,8 +1396,10 @@ real_writebytes(struct midi_softc *sc, u
if (idx_cur == idx_lim || count > buf_lim - buf_cur) {
MIDI_BUF_PRODUCER_REFRESH(mb,idx); /* get the most */
MIDI_BUF_PRODUCER_REFRESH(mb,buf); /* current facts */
- if (idx_cur == idx_lim || count > buf_lim - buf_cur)
- return EWOULDBLOCK; /* caller's problem */
+ if (idx_cur == idx_lim || count > buf_lim - buf_cur) {
+ error = EWOULDBLOCK; /* caller's problem */
+ goto out;
+ }
}
*idx_cur++ = PACK_MB_IDX(got,count);
MIDI_BUF_WRAP(idx);
@@ -1394,7 +1426,14 @@ real_writebytes(struct midi_softc *sc, u
callout_stop(&sc->xmt_asense_co);
arming = 1;
}
- return arming ? midi_start_output(sc) : 0;
+
+ error = arming ? midi_start_output(sc) : 0;
+
+out:
+ if (--sc->refcnt < 0)
+ cv_broadcast(&sc->detach_cv);
+
+ return error;
}
static int
@@ -1422,6 +1461,9 @@ midiwrite(dev_t dev, struct uio *uio, in
mutex_exit(sc->lock);
return EIO;
}
+
+ sc->refcnt++;
+
mb = &sc->outbuf;
error = 0;
while (uio->uio_resid > 0 && !error) {
@@ -1444,8 +1486,8 @@ midiwrite(dev_t dev, struct uio *uio, in
* the common syscall code will automagically
* convert this to success with a short count.
*/
- mutex_exit(sc->lock);
- return EWOULDBLOCK;
+ error = EWOULDBLOCK;
+ goto out;
}
if (pollout) {
mutex_exit(sc->lock);
@@ -1454,14 +1496,15 @@ midiwrite(dev_t dev, struct uio *uio, in
pollout = 0;
} else
error = cv_wait_sig(&sc->wchan, sc->lock);
+ if (sc->dying)
+ error = EIO;
if (error) {
/*
* Similarly, the common code will handle
* EINTR and ERESTART properly here, changing to
* a short count if something transferred.
*/
- mutex_exit(sc->lock);
- return error;
+ goto out;
}
}
@@ -1492,7 +1535,7 @@ midiwrite(dev_t dev, struct uio *uio, in
"xfrcount=%zu inp=%p\n",
error, xfrcount, inp);
#endif
- if ( error )
+ if (error)
break;
/*
@@ -1514,6 +1557,11 @@ midiwrite(dev_t dev, struct uio *uio, in
DPRINTFN(8,("midiwrite: uio_resid now %zu, props=%d\n",
uio->uio_resid, sc->props));
}
+
+out:
+ if (--sc->refcnt < 0)
+ cv_broadcast(&sc->detach_cv);
+
mutex_exit(sc->lock);
return error;
}
@@ -1529,11 +1577,17 @@ midi_writebytes(int unit, u_char *bf, in
device_lookup_private(&midi_cd, unit);
int error;
+ if (!sc)
+ return EIO;
+
DPRINTFN(7, ("midi_writebytes: %p, unit=%d, cc=%d %#02x %#02x %#02x\n",
sc, unit, cc, bf[0], bf[1], bf[2]));
mutex_enter(sc->lock);
- error = real_writebytes(sc, bf, cc);
+ if (sc->dying)
+ error = EIO;
+ else
+ error = real_writebytes(sc, bf, cc);
mutex_exit(sc->lock);
return error;
@@ -1548,12 +1602,18 @@ midiioctl(dev_t dev, u_long cmd, void *a
MIDI_BUF_DECLARE(buf);
(void)buf_end;
- sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));;
- if (sc->dying)
+ sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));
+
+ mutex_enter(sc->lock);
+ if (sc->dying) {
+ mutex_exit(sc->lock);
return EIO;
+ }
hw = sc->hw_if;
error = 0;
+ sc->refcnt++;
+
DPRINTFN(5,("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
switch (cmd) {
@@ -1574,13 +1634,12 @@ midiioctl(dev_t dev, u_long cmd, void *a
* read of m < n, fewer than m bytes may be read to ensure the
* read ends at a message boundary.
*/
- mutex_enter(sc->lock);
MIDI_BUF_CONSUMER_INIT(&sc->inbuf,buf);
*(int *)addr = buf_lim - buf_cur;
- mutex_exit(sc->lock);
break;
case FIOASYNC:
+ mutex_exit(sc->lock);
mutex_enter(proc_lock);
if (*(int *)addr) {
if (sc->async) {
@@ -1594,6 +1653,7 @@ midiioctl(dev_t dev, u_long cmd, void *a
sc->async = 0;
}
mutex_exit(proc_lock);
+ mutex_enter(sc->lock);
break;
#if 0
@@ -1607,20 +1667,24 @@ midiioctl(dev_t dev, u_long cmd, void *a
#ifdef MIDI_SAVE
case MIDI_GETSAVE:
+ mutex_exit(sc->lock);
error = copyout(&midisave, *(void **)addr, sizeof midisave);
+ mutex_enter(sc->lock);
break;
#endif
default:
if (hw->ioctl != NULL) {
- mutex_enter(sc->lock);
error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, l);
- mutex_exit(sc->lock);
} else {
error = EINVAL;
}
break;
}
+
+ if (--sc->refcnt < 0)
+ cv_broadcast(&sc->detach_cv);
+ mutex_exit(sc->lock);
return error;
}
@@ -1643,6 +1707,9 @@ midipoll(dev_t dev, int events, struct l
mutex_exit(sc->lock);
return POLLHUP;
}
+
+ sc->refcnt++;
+
if ((events & (POLLIN | POLLRDNORM)) != 0) {
MIDI_BUF_CONSUMER_INIT(&sc->inbuf, idx);
if (idx_cur < idx_lim)
@@ -1658,6 +1725,10 @@ midipoll(dev_t dev, int events, struct l
else
selrecord(l, &sc->wsel);
}
+
+ if (--sc->refcnt < 0)
+ cv_broadcast(&sc->detach_cv);
+
mutex_exit(sc->lock);
return revents;
@@ -1709,6 +1780,10 @@ filt_midiwrite(struct knote *kn, long hi
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
+ mutex_exit(sc->lock);
+ sc->refcnt++;
+ mutex_enter(sc->lock);
+
(void)idx_end; (void)buf_end;
if (hint != NOTE_SUBMIT)
mutex_enter(sc->lock);
@@ -1719,6 +1794,13 @@ filt_midiwrite(struct knote *kn, long hi
kn->kn_data = idx_lim - idx_cur;
if (hint != NOTE_SUBMIT)
mutex_exit(sc->lock);
+
+ // XXXMRG -- move this up, avoid the relock?
+ mutex_enter(sc->lock);
+ if (--sc->refcnt < 0)
+ cv_broadcast(&sc->detach_cv);
+ mutex_exit(sc->lock);
+
return (kn->kn_data > 0);
}
@@ -1732,6 +1814,10 @@ midikqfilter(dev_t dev, struct knote *kn
device_lookup_private(&midi_cd, MIDIUNIT(dev));
struct klist *klist;
+ mutex_exit(sc->lock);
+ sc->refcnt++;
+ mutex_enter(sc->lock);
+
switch (kn->kn_filter) {
case EVFILT_READ:
klist = &sc->rsel.sel_klist;
@@ -1751,6 +1837,8 @@ midikqfilter(dev_t dev, struct knote *kn
mutex_enter(sc->lock);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
+ if (--sc->refcnt < 0)
+ cv_broadcast(&sc->detach_cv);
mutex_exit(sc->lock);
return (0);
Index: src/sys/dev/midi_if.h
diff -u src/sys/dev/midi_if.h:1.25 src/sys/dev/midi_if.h:1.25.14.1
--- src/sys/dev/midi_if.h:1.25 Mon Apr 9 10:18:16 2012
+++ src/sys/dev/midi_if.h Sun Jan 11 14:13:25 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: midi_if.h,v 1.25 2012/04/09 10:18:16 plunky Exp $ */
+/* $NetBSD: midi_if.h,v 1.25.14.1 2015/01/11 14:13:25 martin Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -50,11 +50,11 @@ struct midi_info {
*
* METHOD INTR NOTES
* ----------------------- ------- -------------------------
- * open -
- * close -
- * output -
- * getinfo - Called at attach time
- * ioctl -
+ * open held
+ * close held
+ * output held
+ * getinfo held Called at attach time
+ * ioctl held
* get_locks - Called at attach time
*/
Index: src/sys/dev/midivar.h
diff -u src/sys/dev/midivar.h:1.19 src/sys/dev/midivar.h:1.19.14.1
--- src/sys/dev/midivar.h:1.19 Thu Apr 5 20:25:53 2012
+++ src/sys/dev/midivar.h Sun Jan 11 14:13:25 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: midivar.h,v 1.19 2012/04/05 20:25:53 plunky Exp $ */
+/* $NetBSD: midivar.h,v 1.19.14.1 2015/01/11 14:13:25 martin Exp $ */
/*
* Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@@ -189,6 +189,8 @@ struct midi_softc {
struct midi_buffer outbuf;
struct midi_buffer inbuf;
int props;
+ int refcnt;
+ kcondvar_t detach_cv;
kcondvar_t rchan;
kcondvar_t wchan;
kmutex_t *lock;
Index: src/sys/dev/sequencer.c
diff -u src/sys/dev/sequencer.c:1.59 src/sys/dev/sequencer.c:1.59.2.1
--- src/sys/dev/sequencer.c:1.59 Fri Jul 25 08:10:35 2014
+++ src/sys/dev/sequencer.c Sun Jan 11 14:13:25 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: sequencer.c,v 1.59 2014/07/25 08:10:35 dholland Exp $ */
+/* $NetBSD: sequencer.c,v 1.59.2.1 2015/01/11 14:13:25 martin Exp $ */
/*
* Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@@ -55,7 +55,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sequencer.c,v 1.59 2014/07/25 08:10:35 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sequencer.c,v 1.59.2.1 2015/01/11 14:13:25 martin Exp $");
#include "sequencer.h"
@@ -174,7 +174,9 @@ static LIST_HEAD(, sequencer_softc) sequ
static kmutex_t sequencer_lock;
static void
-sequencerdestroy(struct sequencer_softc *sc) {
+sequencerdestroy(struct sequencer_softc *sc)
+{
+ callout_halt(&sc->sc_callout, &sc->lock);
callout_destroy(&sc->sc_callout);
softint_disestablish(sc->sih);
cv_destroy(&sc->rchan);
@@ -186,7 +188,8 @@ sequencerdestroy(struct sequencer_softc
}
static struct sequencer_softc *
-sequencercreate(int unit) {
+sequencercreate(int unit)
+{
struct sequencer_softc *sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
if (sc == NULL) {
#ifdef DIAGNOSTIC
@@ -212,7 +215,8 @@ sequencercreate(int unit) {
static struct sequencer_softc *
-sequencerget(int unit) {
+sequencerget(int unit)
+{
struct sequencer_softc *sc;
if (unit < 0) {
#ifdef DIAGNOSTIC
@@ -238,7 +242,8 @@ sequencerget(int unit) {
#ifdef notyet
static void
-sequencerput(struct sequencer_softc *sc) {
+sequencerput(struct sequencer_softc *sc)
+{
mutex_enter(&sequencer_lock);
LIST_REMOVE(sc, sc_link);
mutex_exit(&sequencer_lock);
@@ -294,7 +299,7 @@ sequenceropen(dev_t dev, int flags, int
struct sequencer_softc *sc;
struct midi_dev *md;
struct midi_softc *msc;
- int error, unit;
+ int error, unit, mdno;
DPRINTF(("sequenceropen\n"));
@@ -337,6 +342,11 @@ sequenceropen(dev_t dev, int flags, int
sc->devs[sc->nmidi++] = md;
md->seq = sc;
md->doingsysex = 0;
+ DPRINTF(("%s: midi unit %d opened as seq %p\n",
+ __func__, unit, md));
+ } else {
+ DPRINTF(("%s: midi unit %d not opened as seq\n",
+ __func__, unit));
}
}
mutex_enter(&sc->lock);
@@ -345,11 +355,15 @@ sequenceropen(dev_t dev, int flags, int
}
/* Only now redirect input from MIDI devices. */
- for (unit = 0; unit < sc->nmidi; unit++) {
- msc = sc->devs[unit]->msc;
- mutex_enter(msc->lock);
- msc->seqopen = 1;
- mutex_exit(msc->lock);
+ for (mdno = 0; mdno < sc->nmidi; mdno++) {
+ extern struct cfdriver midi_cd;
+
+ msc = device_lookup_private(&midi_cd, sc->devs[mdno]->unit);
+ if (msc) {
+ mutex_enter(msc->lock);
+ msc->seqopen = 1;
+ mutex_exit(msc->lock);
+ }
}
seq_reset(sc);
@@ -429,7 +443,7 @@ sequencerclose(dev_t dev, int flags, int
struct midi_softc *msc;
int unit, error;
- DPRINTF(("sequencerclose: %"PRIx64"\n", dev));
+ DPRINTF(("%s: %"PRIx64"\n", __func__, dev));
if ((error = sequencer_enter(dev, &sc)) != 0)
return error;
@@ -440,10 +454,14 @@ sequencerclose(dev_t dev, int flags, int
}
/* Bin input from MIDI devices. */
for (unit = 0; unit < sc->nmidi; unit++) {
- msc = sc->devs[unit]->msc;
- mutex_enter(msc->lock);
- msc->seqopen = 0;
- mutex_exit(msc->lock);
+ extern struct cfdriver midi_cd;
+
+ msc = device_lookup_private(&midi_cd, unit);
+ if (msc) {
+ mutex_enter(msc->lock);
+ msc->seqopen = 0;
+ mutex_exit(msc->lock);
+ }
}
mutex_exit(&sc->lock);
@@ -460,7 +478,7 @@ sequencerclose(dev_t dev, int flags, int
sc->isopen = 0;
sequencer_exit(sc);
- DPRINTF(("sequencerclose: %"PRIx64" done\n", dev));
+ DPRINTF(("%s: %"PRIx64" done\n", __func__, dev));
return (0);
}
@@ -560,7 +578,7 @@ seq_softintr(void *addr)
t += sc->timer.divs_lastchange;
if (t != sc->input_stamp) {
seq_input_event(sc, &SEQ_MK_TIMING(WAIT_ABS, .divisions=t));
- sc->input_stamp = t; /* XXX wha hoppen if timer is reset? */
+ sc->input_stamp = t; /* XXX what happens if timer is reset? */
}
seq_input_event(sc, &ev);
mutex_exit(&sc->lock);
@@ -574,7 +592,7 @@ sequencerread(dev_t dev, struct uio *uio
seq_event_t ev;
int error;
- DPRINTFN(20, ("sequencerread: %"PRIx64", count=%d, ioflag=%x\n",
+ DPRINTFN(2, ("sequencerread: %"PRIx64", count=%d, ioflag=%x\n",
dev, (int)uio->uio_resid, ioflag));
if ((error = sequencer_enter(dev, &sc)) != 0)
@@ -701,7 +719,7 @@ sequencerioctl(dev_t dev, u_long cmd, vo
if (sc->async != 0)
return EBUSY;
sc->async = curproc->p_pid;
- DPRINTF(("sequencer_ioctl: FIOASYNC %d\n",
+ DPRINTF(("%s: FIOASYNC %d\n", __func__,
sc->async));
} else {
sc->async = 0;
@@ -787,6 +805,7 @@ sequencerioctl(dev_t dev, u_long cmd, vo
case SEQUENCER_TMR_TEMPO:
error = seq_do_timing(sc,
&SEQ_MK_TIMING(TEMPO, .bpm=*(int *)addr));
+ RECALC_USPERDIV(&sc->timer);
if (error == 0)
*(int *)addr = sc->timer.tempo_beatpermin;
break;
@@ -840,7 +859,7 @@ sequencerpoll(dev_t dev, int events, str
if ((sc = sequencerget(SEQUENCERUNIT(dev))) == NULL)
return ENXIO;
- DPRINTF(("sequencerpoll: %p events=0x%x\n", sc, events));
+ DPRINTF(("%s: %p events=0x%x\n", __func__, sc, events));
mutex_enter(&sc->lock);
if (events & (POLLIN | POLLRDNORM))
@@ -971,7 +990,7 @@ seq_reset(struct sequencer_softc *sc)
KASSERT(mutex_owned(&sc->lock));
- if ( !(sc->flags & FWRITE) )
+ if (!(sc->flags & FWRITE))
return;
for (i = 0; i < sc->nmidi; i++) {
md = sc->devs[i];
@@ -1114,7 +1133,7 @@ seq_do_sysex(struct sequencer_softc *sc,
dev = b->sysex.device;
if (dev < 0 || dev >= sc->nmidi)
return (ENXIO);
- DPRINTF(("seq_do_sysex: dev=%d\n", dev));
+ DPRINTF(("%s: dev=%d\n", __func__, dev));
md = sc->devs[dev];
if (!md->doingsysex) {
@@ -1166,7 +1185,7 @@ seq_timer_waitabs(struct sequencer_softc
}
#ifdef SEQUENCER_DEBUG
else if (tick < 0)
- DPRINTF(("seq_timer_waitabs: ticks = %d\n", ticks));
+ DPRINTF(("%s: ticks = %d\n", __func__, ticks));
#endif
}
@@ -1227,11 +1246,11 @@ seq_do_timing(struct sequencer_softc *sc
break;
case TMR_SPP:
case TMR_TIMESIG:
- DPRINTF(("seq_do_timing: unimplemented %02x\n", b->timing.op));
+ DPRINTF(("%s: unimplemented %02x\n", __func__, b->timing.op));
error = EINVAL; /* not quite accurate... */
break;
default:
- DPRINTF(("seq_timer: unknown %02x\n", b->timing.op));
+ DPRINTF(("%s: unknown %02x\n", __func__, b->timing.op));
error = EINVAL;
break;
}
@@ -1345,7 +1364,7 @@ seq_to_new(seq_event_t *ev, struct uio *
case SEQOLD_PRIVATE:
case SEQOLD_EXTENDED:
default:
- DPRINTF(("seq_to_new: not impl 0x%02x\n", cmd));
+ DPRINTF(("%s: not impl 0x%02x\n", __func__, cmd));
return EINVAL;
/* In case new-style events show up */
case SEQ_TIMING:
@@ -1420,7 +1439,6 @@ midiseq_open(int unit, int flags)
sc = device_lookup_private(&midi_cd, unit);
md = kmem_zalloc(sizeof(*md), KM_SLEEP);
- md->msc = sc;
md->unit = unit;
md->name = mi.name;
md->subtype = 0;
@@ -1451,8 +1469,8 @@ midiseq_reset(struct midi_dev *md)
static int
midiseq_out(struct midi_dev *md, u_char *bf, u_int cc, int chk)
{
- DPRINTFN(5, ("midiseq_out: m=%p, unit=%d, bf[0]=0x%02x, cc=%d\n",
- md->msc, md->unit, bf[0], cc));
+ DPRINTFN(5, ("midiseq_out: md=%p, unit=%d, bf[0]=0x%02x, cc=%d\n",
+ md, md->unit, bf[0], cc));
/* midi(4) does running status compression where appropriate. */
return midi_writebytes(md->unit, bf, cc);
Index: src/sys/dev/sequencervar.h
diff -u src/sys/dev/sequencervar.h:1.16 src/sys/dev/sequencervar.h:1.16.10.1
--- src/sys/dev/sequencervar.h:1.16 Sat Apr 27 22:12:42 2013
+++ src/sys/dev/sequencervar.h Sun Jan 11 14:13:25 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: sequencervar.h,v 1.16 2013/04/27 22:12:42 christos Exp $ */
+/* $NetBSD: sequencervar.h,v 1.16.10.1 2015/01/11 14:13:25 martin Exp $ */
/*
* Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,6 @@ struct midi_dev {
int instr_bank_size;
int unit;
struct sequencer_softc *seq;
- struct midi_softc *msc;
char doingsysex; /* doing a SEQ_SYSEX */
vnode_t *vp;
};
Index: src/sys/dev/usb/FILES
diff -u src/sys/dev/usb/FILES:1.12 src/sys/dev/usb/FILES:1.12.22.1
--- src/sys/dev/usb/FILES:1.12 Tue Jan 17 03:49:20 2012
+++ src/sys/dev/usb/FILES Sun Jan 11 14:13:25 2015
@@ -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.65.12.1
--- src/sys/dev/usb/umidi.c:1.65 Tue Jan 22 21:29:53 2013
+++ src/sys/dev/usb/umidi.c Sun Jan 11 14:13:25 2015
@@ -1,6 +1,7 @@
-/* $NetBSD: umidi.c,v 1.65 2013/01/22 21:29:53 jmcneill Exp $ */
+/* $NetBSD: umidi.c,v 1.65.12.1 2015/01/11 14:13:25 martin 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.65.12.1 2015/01/11 14:13:25 martin 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,38 +360,35 @@ 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);
aprint_error_dev(self,
"attach_all_mididevs failed. (err=%d)\n", err);
+ goto out_free_jacks;
}
#ifdef UMIDI_DEBUG
@@ -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,34 +490,37 @@ 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)
- return ENXIO;
if (mididev->opened)
return EBUSY;
if (sc->sc_dying)
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) {
+ if (mididev->out_jack)
+ 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 +528,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 +557,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 +571,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 +592,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 +613,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 +628,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 +838,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 +1098,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 +1109,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 +1172,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 +1216,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 +1237,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 +1262,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 +1324,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 +1351,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 +1370,6 @@ close_out_jack(struct umidi_jack *jack)
ep->this_schedule &= ~mask;
ep->next_schedule &= ~mask;
}
- mutex_spin_exit(&sc->sc_lock);
}
}
@@ -1179,9 +1377,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 +1414,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 +1443,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 +1462,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 +1549,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 +1729,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 +1783,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 +1794,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 +1854,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 +1889,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 +1991,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.18.14.1
--- src/sys/dev/usb/umidi_quirks.c:1.18 Fri May 18 07:52:54 2012
+++ src/sys/dev/usb/umidi_quirks.c Sun Jan 11 14:13:25 2015
@@ -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.18.14.1 2015/01/11 14:13:25 martin 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.18.14.1 2015/01/11 14:13:25 martin 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>
/*