Module Name: src
Committed By: mrg
Date: Thu Nov 24 22:12:52 UTC 2011
Modified Files:
src/sys/dev/usb: umidi.c umidivar.h
Log Message:
several steps towards making umidi appear to work:
- split out_solicit() into locked and unlocked front end, and use the
unlocked version from the softintr
- kill sc_intr_lock, midi doesn't really use it (XXX finish this?
change this? in the midi* code)
- convert tsleep()/wakeup() to cv
- move some free's out of the lock
- KASSERT() lock is held in a few more places
TODO:
- malloc -> kmem
- crashes in midiclose(), doesn't actually play things to the right
device. "midiplay -d midi1 -xv" plays out my midi@pcppi speaker,
and then the above crash. clearly something is calling the wrong
sub-device callbacks!
To generate a diff of this commit:
cvs rdiff -u -r1.46 -r1.47 src/sys/dev/usb/umidi.c
cvs rdiff -u -r1.15 -r1.16 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/umidi.c
diff -u src/sys/dev/usb/umidi.c:1.46 src/sys/dev/usb/umidi.c:1.47
--- src/sys/dev/usb/umidi.c:1.46 Wed Nov 23 23:50:46 2011
+++ src/sys/dev/usb/umidi.c Thu Nov 24 22:12:51 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: umidi.c,v 1.46 2011/11/23 23:50:46 mrg Exp $ */
+/* $NetBSD: umidi.c,v 1.47 2011/11/24 22:12:51 mrg Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.46 2011/11/23 23:50:46 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.47 2011/11/24 22:12:51 mrg Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -125,6 +125,7 @@ static int out_jack_output(struct umidi_
static void in_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
static void out_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
static void out_solicit(void *); /* struct umidi_endpoint* for softintr */
+static void out_solicit_locked(void *); /* pre-locked version */
const struct midi_hw_if umidi_hw_if = {
@@ -201,18 +202,18 @@ umidi_attach(device_t parent, device_t s
aprint_normal_dev(self, "");
umidi_print_quirk(sc->sc_quirk);
- mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
- mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB);
+ cv_init(&sc->sc_cv, "umidopcl");
KERNEL_LOCK(1, curlwp);
err = alloc_all_endpoints(sc);
- if (err!=USBD_NORMAL_COMPLETION) {
+ if (err != USBD_NORMAL_COMPLETION) {
aprint_error_dev(self,
"alloc_all_endpoints failed. (err=%d)\n", err);
goto error;
}
err = alloc_all_jacks(sc);
- if (err!=USBD_NORMAL_COMPLETION) {
+ if (err != USBD_NORMAL_COMPLETION) {
free_all_endpoints(sc);
aprint_error_dev(self, "alloc_all_jacks failed. (err=%d)\n",
err);
@@ -222,7 +223,7 @@ umidi_attach(device_t parent, device_t s
sc->sc_out_num_jacks, sc->sc_in_num_jacks);
err = assign_all_jacks_automatically(sc);
- if (err!=USBD_NORMAL_COMPLETION) {
+ if (err != USBD_NORMAL_COMPLETION) {
unbind_all_jacks(sc);
free_all_jacks(sc);
free_all_endpoints(sc);
@@ -231,7 +232,7 @@ umidi_attach(device_t parent, device_t s
goto error;
}
err = attach_all_mididevs(sc);
- if (err!=USBD_NORMAL_COMPLETION) {
+ if (err != USBD_NORMAL_COMPLETION) {
free_all_jacks(sc);
free_all_endpoints(sc);
aprint_error_dev(self,
@@ -293,19 +294,21 @@ umidi_detach(device_t self, int flags)
DPRINTFN(1,("umidi_detach\n"));
- KERNEL_LOCK(1, curlwp);
+ mutex_enter(&sc->sc_lock);
sc->sc_dying = 1;
detach_all_mididevs(sc, flags);
free_all_mididevs(sc);
free_all_jacks(sc);
free_all_endpoints(sc);
+ mutex_exit(&sc->sc_lock);
+ KERNEL_LOCK(1, curlwp);
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
sc->sc_dev);
KERNEL_UNLOCK_ONE(curlwp);
mutex_destroy(&sc->sc_lock);
- mutex_destroy(&sc->sc_intr_lock);
+ cv_destroy(&sc->sc_cv);
return 0;
}
@@ -444,12 +447,12 @@ umidi_getinfo(void *addr, struct midi_in
}
static void
-umidi_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+umidi_get_locks(void *addr, kmutex_t **thread, kmutex_t **intr)
{
struct umidi_mididev *mididev = addr;
struct umidi_softc *sc = mididev->sc;
- *intr = &sc->sc_intr_lock;
+ *intr = NULL;
*thread = &sc->sc_lock;
}
@@ -912,23 +915,23 @@ alloc_all_jacks(struct umidi_softc *sc)
sc->sc_in_num_jacks ? sc->sc_jacks+sc->sc_out_num_jacks : NULL;
jack = &sc->sc_out_jacks[0];
- for (i=0; i<sc->sc_out_num_jacks; i++) {
+ for (i = 0; i < sc->sc_out_num_jacks; i++) {
jack->opened = 0;
jack->binded = 0;
jack->arg = NULL;
jack->u.out.intr = NULL;
jack->midiman_ppkt = NULL;
- if ( sc->cblnums_global )
+ if (sc->cblnums_global)
jack->cable_number = i;
jack++;
}
jack = &sc->sc_in_jacks[0];
- for (i=0; i<sc->sc_in_num_jacks; i++) {
+ for (i = 0; i < sc->sc_in_num_jacks; i++) {
jack->opened = 0;
jack->binded = 0;
jack->arg = NULL;
jack->u.in.intr = NULL;
- if ( sc->cblnums_global )
+ if (sc->cblnums_global)
jack->cable_number = i;
jack++;
}
@@ -936,12 +939,12 @@ alloc_all_jacks(struct umidi_softc *sc)
/* assign each jacks to each endpoints */
jack = &sc->sc_out_jacks[0];
ep = &sc->sc_out_ep[0];
- for (i=0; i<sc->sc_out_num_endpoints; i++) {
- for (j=0; j<ep->num_jacks; j++) {
+ for (i = 0; i < sc->sc_out_num_endpoints; i++) {
+ for (j = 0; j < ep->num_jacks; j++) {
jack->endpoint = ep;
- if ( cn_spec != NULL )
+ if (cn_spec != NULL)
jack->cable_number = *cn_spec++;
- else if ( !sc->cblnums_global )
+ else if (!sc->cblnums_global)
jack->cable_number = j;
ep->jacks[jack->cable_number] = jack;
jack++;
@@ -950,12 +953,12 @@ alloc_all_jacks(struct umidi_softc *sc)
}
jack = &sc->sc_in_jacks[0];
ep = &sc->sc_in_ep[0];
- for (i=0; i<sc->sc_in_num_endpoints; i++) {
- for (j=0; j<ep->num_jacks; j++) {
+ for (i = 0; i < sc->sc_in_num_endpoints; i++) {
+ for (j = 0; j < ep->num_jacks; j++) {
jack->endpoint = ep;
- if ( cn_spec != NULL )
+ if (cn_spec != NULL)
jack->cable_number = *cn_spec++;
- else if ( !sc->cblnums_global )
+ else if (!sc->cblnums_global)
jack->cable_number = j;
ep->jacks[jack->cable_number] = jack;
jack++;
@@ -969,13 +972,15 @@ alloc_all_jacks(struct umidi_softc *sc)
static void
free_all_jacks(struct umidi_softc *sc)
{
+ struct umidi_jack *jacks;
- mutex_spin_enter(&sc->sc_intr_lock);
- if (sc->sc_out_jacks) {
- free(sc->sc_jacks, M_USBDEV);
- sc->sc_jacks = sc->sc_in_jacks = sc->sc_out_jacks = NULL;
- }
- mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_enter(&sc->sc_lock);
+ jacks = sc->sc_out_jacks;
+ sc->sc_jacks = sc->sc_in_jacks = sc->sc_out_jacks = NULL;
+ mutex_exit(&sc->sc_lock);
+
+ if (jacks)
+ free(jacks, M_USBDEV);
}
static usbd_status
@@ -1020,9 +1025,8 @@ unbind_all_jacks(struct umidi_softc *sc)
int i;
if (sc->sc_mididevs)
- for (i=0; i<sc->sc_num_mididevs; i++) {
+ for (i = 0; i < sc->sc_num_mididevs; i++)
unbind_jacks_from_mididev(&sc->sc_mididevs[i]);
- }
}
static usbd_status
@@ -1045,14 +1049,14 @@ assign_all_jacks_automatically(struct um
else
asg_spec = NULL;
- for (i=0; i<sc->sc_num_mididevs; i++) {
- if ( asg_spec != NULL ) {
- if ( *asg_spec == -1 )
+ for (i = 0; i < sc->sc_num_mididevs; i++) {
+ if (asg_spec != NULL) {
+ if (*asg_spec == -1)
out = NULL;
else
out = &sc->sc_out_jacks[*asg_spec];
++ asg_spec;
- if ( *asg_spec == -1 )
+ if (*asg_spec == -1)
in = NULL;
else
in = &sc->sc_in_jacks[*asg_spec];
@@ -1081,6 +1085,8 @@ open_out_jack(struct umidi_jack *jack, v
umidi_packet_bufp end;
int err;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
if (jack->opened)
return USBD_IN_USE;
@@ -1088,7 +1094,6 @@ open_out_jack(struct umidi_jack *jack, v
jack->u.out.intr = intr;
jack->midiman_ppkt = NULL;
end = ep->buffer + ep->buffer_size / sizeof *ep->buffer;
- mutex_spin_enter(&sc->sc_intr_lock);
jack->opened = 1;
ep->num_open++;
/*
@@ -1097,16 +1102,15 @@ open_out_jack(struct umidi_jack *jack, v
* just incremented num_open, the buffer may be too full to satisfy
* the invariant until a transfer completes, for which we must wait.
*/
- while ( end - ep->next_slot < ep->num_open - ep->num_scheduled ) {
- err = tsleep(ep, PWAIT|PCATCH, "umi op", mstohz(10));
- if ( err ) {
+ while (end - ep->next_slot < ep->num_open - ep->num_scheduled) {
+ err = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock,
+ mstohz(10));
+ if (err) {
ep->num_open--;
jack->opened = 0;
- mutex_spin_exit(&sc->sc_intr_lock);
return USBD_IOERROR;
}
}
- mutex_spin_exit(&sc->sc_intr_lock);
return USBD_NORMAL_COMPLETION;
}
@@ -1116,6 +1120,9 @@ open_in_jack(struct umidi_jack *jack, vo
{
usbd_status err = USBD_NORMAL_COMPLETION;
struct umidi_endpoint *ep = jack->endpoint;
+ struct umidi_softc *sc = ep->sc;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
if (jack->opened)
return USBD_IN_USE;
@@ -1123,7 +1130,7 @@ open_in_jack(struct umidi_jack *jack, vo
jack->arg = arg;
jack->u.in.intr = intr;
jack->opened = 1;
- if (ep->num_open++==0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) {
+ if (ep->num_open++ == 0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) {
err = start_input_transfer(ep);
if (err != USBD_NORMAL_COMPLETION &&
err != USBD_IN_PROGRESS) {
@@ -1142,21 +1149,22 @@ close_out_jack(struct umidi_jack *jack)
u_int16_t mask;
int err;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
if (jack->opened) {
ep = jack->endpoint;
sc = ep->sc;
mask = 1 << (jack->cable_number);
- mutex_spin_enter(&sc->sc_intr_lock);
- while ( mask & (ep->this_schedule | ep->next_schedule) ) {
- err = tsleep(ep, PWAIT|PCATCH, "umi dr", mstohz(10));
- if ( err )
+ while (mask & (ep->this_schedule | ep->next_schedule)) {
+ err = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock,
+ mstohz(10));
+ if (err)
break;
}
jack->opened = 0;
jack->endpoint->num_open--;
ep->this_schedule &= ~mask;
ep->next_schedule &= ~mask;
- mutex_spin_exit(&sc->sc_intr_lock);
}
}
@@ -1246,9 +1254,9 @@ attach_all_mididevs(struct umidi_softc *
int i;
if (sc->sc_mididevs)
- for (i=0; i<sc->sc_num_mididevs; i++) {
+ for (i = 0; i < sc->sc_num_mididevs; i++) {
err = attach_mididev(sc, &sc->sc_mididevs[i]);
- if (err!=USBD_NORMAL_COMPLETION)
+ if (err != USBD_NORMAL_COMPLETION)
return err;
}
@@ -1262,9 +1270,9 @@ detach_all_mididevs(struct umidi_softc *
int i;
if (sc->sc_mididevs)
- for (i=0; i<sc->sc_num_mididevs; i++) {
+ for (i = 0; i < sc->sc_num_mididevs; i++) {
err = detach_mididev(&sc->sc_mididevs[i], flags);
- if (err!=USBD_NORMAL_COMPLETION)
+ if (err != USBD_NORMAL_COMPLETION)
return err;
}
@@ -1277,7 +1285,7 @@ deactivate_all_mididevs(struct umidi_sof
int i;
if (sc->sc_mididevs) {
- for (i=0; i<sc->sc_num_mididevs; i++)
+ for (i = 0; i < sc->sc_num_mididevs; i++)
deactivate_mididev(&sc->sc_mididevs[i]);
}
}
@@ -1506,7 +1514,6 @@ out_jack_output(struct umidi_jack *out_j
umidi_tv.tv_sec%100, (uint64_t)umidi_tv.tv_usec,
ep, out_jack->cable_number, len, cin));
- mutex_spin_enter(&sc->sc_intr_lock);
packet = *ep->next_slot++;
KASSERT(ep->buffer_size >=
(ep->next_slot - ep->buffer) * sizeof *ep->buffer);
@@ -1554,7 +1561,6 @@ out_jack_output(struct umidi_jack *out_j
ep->soliciting = 1;
softint_schedule(ep->solicit_cookie);
}
- mutex_spin_exit(&sc->sc_intr_lock);
return 0;
}
@@ -1576,9 +1582,9 @@ in_intr(usbd_xfer_handle xfer, usbd_priv
if (ep->sc->sc_dying || !ep->num_open)
return;
- mutex_enter(&sc->sc_intr_lock);
+ mutex_enter(&sc->sc_lock);
usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
- if ( 0 == count % UMIDI_PACKET_SIZE ) {
+ if (0 == count % UMIDI_PACKET_SIZE) {
DPRINTFN(200,("%s: input endpoint %p transfer length %u\n",
device_xname(ep->sc->sc_dev), ep, count));
} else {
@@ -1589,9 +1595,9 @@ in_intr(usbd_xfer_handle xfer, usbd_priv
slot = ep->buffer;
end = slot + count / sizeof *slot;
- for ( packet = *slot; slot < end; packet = *++slot ) {
+ for (packet = *slot; slot < end; packet = *++slot) {
- if ( UMQ_ISTYPE(ep->sc, UMQ_TYPE_MIDIMAN_GARBLE) ) {
+ if (UMQ_ISTYPE(ep->sc, UMQ_TYPE_MIDIMAN_GARBLE)) {
cn = (0xf0&(packet[3]))>>4;
len = 0x0f&(packet[3]);
data = packet;
@@ -1608,7 +1614,7 @@ in_intr(usbd_xfer_handle xfer, usbd_priv
(unsigned)data[0],
(unsigned)data[1],
(unsigned)data[2]));
- mutex_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
return;
}
@@ -1623,7 +1629,7 @@ in_intr(usbd_xfer_handle xfer, usbd_priv
(unsigned)data[2]));
if (jack->u.in.intr) {
- for (i=0; i<len; i++) {
+ for (i = 0; i < len; i++) {
(*jack->u.in.intr)(jack->arg, data[i]);
}
}
@@ -1631,7 +1637,7 @@ in_intr(usbd_xfer_handle xfer, usbd_priv
}
(void)start_input_transfer(ep);
- mutex_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
}
static void
@@ -1645,7 +1651,7 @@ out_intr(usbd_xfer_handle xfer, usbd_pri
if (sc->sc_dying)
return;
- mutex_enter(&sc->sc_intr_lock);
+ mutex_enter(&sc->sc_lock);
#ifdef UMIDI_DEBUG
if ( umididebug >= 200 )
microtime(&umidi_tv);
@@ -1666,21 +1672,21 @@ out_intr(usbd_xfer_handle xfer, usbd_pri
* move them to the start of the buffer.
*/
ep->next_slot -= count;
- if ( ep->buffer < ep->next_slot ) {
+ if (ep->buffer < ep->next_slot) {
memcpy(ep->buffer, ep->buffer + count,
(char *)ep->next_slot - (char *)ep->buffer);
}
- wakeup(ep);
+ cv_broadcast(&sc->sc_cv);
/*
* Do not want anyone else to see armed <- 0 before soliciting <- 1.
* Running at IPL_USB so the following should happen to be safe.
*/
ep->armed = 0;
- if ( !ep->soliciting ) {
+ if (!ep->soliciting) {
ep->soliciting = 1;
- out_solicit(ep);
+ out_solicit_locked(ep);
}
- mutex_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
}
/*
@@ -1699,23 +1705,25 @@ out_intr(usbd_xfer_handle xfer, usbd_pri
* packets, starting the USB transfer only when the buffer space is down to
* the minimum or no jack has any more to send.
*/
+
static void
-out_solicit(void *arg)
+out_solicit_locked(void *arg)
{
struct umidi_endpoint *ep = arg;
struct umidi_softc *sc = ep->sc;
umidi_packet_bufp end;
u_int16_t which;
struct umidi_jack *jack;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
end = ep->buffer + ep->buffer_size / sizeof *ep->buffer;
for ( ;; ) {
- mutex_spin_enter(&sc->sc_intr_lock);
- if ( end - ep->next_slot <= ep->num_open - ep->num_scheduled )
+ if (end - ep->next_slot <= ep->num_open - ep->num_scheduled)
break; /* at IPL_USB */
- if ( ep->this_schedule == 0 ) {
- if ( ep->next_schedule == 0 )
+ if (ep->this_schedule == 0) {
+ if (ep->next_schedule == 0)
break; /* at IPL_USB */
ep->this_schedule = ep->next_schedule;
ep->next_schedule = 0;
@@ -1734,25 +1742,33 @@ out_solicit(void *arg)
which = ep->this_schedule;
which &= (~which)+1; /* now mask of least set bit */
ep->this_schedule &= ~which;
- -- ep->num_scheduled;
- mutex_spin_exit(&sc->sc_intr_lock);
+ --ep->num_scheduled;
- -- which; /* now 1s below mask - count 1s to get index */
+ --which; /* now 1s below mask - count 1s to get index */
which -= ((which >> 1) & 0x5555);/* SWAR credit aggregate.org */
which = (((which >> 2) & 0x3333) + (which & 0x3333));
which = (((which >> 4) + which) & 0x0f0f);
which += (which >> 8);
which &= 0x1f; /* the bit index a/k/a jack number */
- KERNEL_LOCK(1, curlwp);
jack = ep->jacks[which];
if (jack->u.out.intr)
(*jack->u.out.intr)(jack->arg);
- KERNEL_UNLOCK_ONE(curlwp);
}
/* intr lock held at loop exit */
- if ( !ep->armed && ep->next_slot > ep->buffer )
+ if (!ep->armed && ep->next_slot > ep->buffer)
ep->armed = (USBD_IN_PROGRESS == start_output_transfer(ep));
ep->soliciting = 0;
- mutex_spin_exit(&sc->sc_intr_lock);
+}
+
+/* Entry point for the softintr. */
+static void
+out_solicit(void *arg)
+{
+ struct umidi_endpoint *ep = arg;
+ struct umidi_softc *sc = ep->sc;
+
+ mutex_enter(&sc->sc_lock);
+ out_solicit_locked(arg);
+ mutex_exit(&sc->sc_lock);
}
Index: src/sys/dev/usb/umidivar.h
diff -u src/sys/dev/usb/umidivar.h:1.15 src/sys/dev/usb/umidivar.h:1.16
--- src/sys/dev/usb/umidivar.h:1.15 Wed Nov 23 23:07:36 2011
+++ src/sys/dev/usb/umidivar.h Thu Nov 24 22:12:52 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: umidivar.h,v 1.15 2011/11/23 23:07:36 jmcneill Exp $ */
+/* $NetBSD: umidivar.h,v 1.16 2011/11/24 22:12:52 mrg Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -121,5 +121,5 @@ struct umidi_softc {
int cblnums_global;
kmutex_t sc_lock;
- kmutex_t sc_intr_lock;
+ kcondvar_t sc_cv;
};