[alsa-devel] Ooops when working with USB MIDI (2.6.33.1)

Takashi Iwai tiwai at suse.de
Fri Apr 9 09:29:33 CEST 2010


At Fri, 9 Apr 2010 07:51:35 +0100,
Tvrtko Ursulin wrote:
> 
> On Thursday 08 Apr 2010 13:22:36 Takashi Iwai wrote:
> > > Takashi, do you remember what the original problem was?
> > 
> > Well, I have only a vague memory -- it's a similar scenario that some app
> > still accessing after disconnection.  The URB can't be handled after
> > the disconnection is finished.
> > 
> > I think the patch below might fix in this case.  You can try it
> > instead of reverting the commit above.
> > 
> > 
> > thanks,
> > 
> > Takashi
> > 
> > ---
> > diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
> > index 2c59afd..81c8d85 100644
> > --- a/sound/usb/usbmidi.c
> > +++ b/sound/usb/usbmidi.c
> > @@ -986,6 +986,8 @@ static void snd_usbmidi_output_drain(struct
> >  snd_rawmidi_substream *substream) DEFINE_WAIT(wait);
> >  	long timeout = msecs_to_jiffies(50);
> > 
> > +	if (ep->umidi->disconnected)
> > +		return;
> >  	/*
> >  	 * The substream buffer is empty, but some data might still be in the
> >  	 * currently active URBs, so we have to wait for those to complete.
> > @@ -1275,6 +1277,11 @@ void snd_usbmidi_disconnect(struct list_head* p)
> >  			snd_usbmidi_in_endpoint_delete(ep->in);
> >  			ep->in = NULL;
> >  		}
> > +		ep->active_urbs = 0;
> > +		if (ep->drain_urbs) {
> > +			ep->drain_urbs = 0;
> > +			wake_up(&ep->drain_wait);
> > +		}
> >  	}
> >  	del_timer_sync(&umidi->error_timer);
> >  }
> 
> For the second hunk, do you think ep->out->... and so on? That would be more 
> in-line with code present in 2.6.33.

Ah, crap.  Sorry, that's just messing up.
The revised (compiled but untested) patch is below.


thanks,

Takashi

---
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 2c59afd..9e28b20 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -986,6 +986,8 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
 	DEFINE_WAIT(wait);
 	long timeout = msecs_to_jiffies(50);
 
+	if (ep->umidi->disconnected)
+		return;
 	/*
 	 * The substream buffer is empty, but some data might still be in the
 	 * currently active URBs, so we have to wait for those to complete.
@@ -1123,14 +1125,21 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
  * Frees an output endpoint.
  * May be called when ep hasn't been initialized completely.
  */
-static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep)
+static void snd_usbmidi_out_endpoint_clear(struct snd_usb_midi_out_endpoint *ep)
 {
 	unsigned int i;
 
 	for (i = 0; i < OUTPUT_URBS; ++i)
-		if (ep->urbs[i].urb)
+		if (ep->urbs[i].urb) {
 			free_urb_and_buffer(ep->umidi, ep->urbs[i].urb,
 					    ep->max_transfer);
+			ep->urbs[i].urb = NULL;
+		}
+}
+
+static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep)
+{
+	snd_usbmidi_out_endpoint_clear(ep);
 	kfree(ep);
 }
 
@@ -1262,15 +1271,18 @@ void snd_usbmidi_disconnect(struct list_head* p)
 				usb_kill_urb(ep->out->urbs[j].urb);
 			if (umidi->usb_protocol_ops->finish_out_endpoint)
 				umidi->usb_protocol_ops->finish_out_endpoint(ep->out);
+			ep->out->active_urbs = 0;
+			if (ep->out->drain_urbs) {
+				ep->out->drain_urbs = 0;
+				wake_up(&ep->out->drain_wait);
+			}
 		}
 		if (ep->in)
 			for (j = 0; j < INPUT_URBS; ++j)
 				usb_kill_urb(ep->in->urbs[j]);
 		/* free endpoints here; later call can result in Oops */
-		if (ep->out) {
-			snd_usbmidi_out_endpoint_delete(ep->out);
-			ep->out = NULL;
-		}
+		if (ep->out)
+			snd_usbmidi_out_endpoint_clear(ep->out);
 		if (ep->in) {
 			snd_usbmidi_in_endpoint_delete(ep->in);
 			ep->in = NULL;


More information about the Alsa-devel mailing list