From 7acea97105b7866597c9b664458b50de5f61c5a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 22 Feb 2008 18:34:44 +0100 Subject: [PATCH] --- yaml --- r: 86155 b: refs/heads/master c: c0792e00bc2dd1202d48b838b1cf59d13dd2c74a h: refs/heads/master i: 86153: db5228577cb43d0be9ae2681890b0f851e799a7c 86151: 30abb1300f730e63bc949e394927b416b6d36239 v: v3 --- [refs] | 2 +- trunk/sound/usb/usbmidi.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/[refs] b/[refs] index 47d29b6a1eba..ef9c422485a8 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 0ee46c9dadcbbd0daa12da30f226391896d90abb +refs/heads/master: c0792e00bc2dd1202d48b838b1cf59d13dd2c74a diff --git a/trunk/sound/usb/usbmidi.c b/trunk/sound/usb/usbmidi.c index 750e929d5870..6676a177c99e 100644 --- a/trunk/sound/usb/usbmidi.c +++ b/trunk/sound/usb/usbmidi.c @@ -104,12 +104,14 @@ struct snd_usb_midi { struct usb_protocol_ops* usb_protocol_ops; struct list_head list; struct timer_list error_timer; + spinlock_t disc_lock; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; + unsigned char disconnected; }; struct snd_usb_midi_out_endpoint { @@ -306,6 +308,11 @@ static void snd_usbmidi_error_timer(unsigned long data) struct snd_usb_midi *umidi = (struct snd_usb_midi *)data; int i; + spin_lock(&umidi->disc_lock); + if (umidi->disconnected) { + spin_unlock(&umidi->disc_lock); + return; + } for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_in_endpoint *in = umidi->endpoints[i].in; if (in && in->error_resubmit) { @@ -316,6 +323,7 @@ static void snd_usbmidi_error_timer(unsigned long data) if (umidi->endpoints[i].out) snd_usbmidi_do_output(umidi->endpoints[i].out); } + spin_unlock(&umidi->disc_lock); } /* helper function to send static data that may not DMA-able */ @@ -1049,7 +1057,14 @@ void snd_usbmidi_disconnect(struct list_head* p) int i; umidi = list_entry(p, struct snd_usb_midi, list); - del_timer_sync(&umidi->error_timer); + /* + * an URB's completion handler may start the timer and + * a timer may submit an URB. To reliably break the cycle + * a flag under lock must be used + */ + spin_lock_irq(&umidi->disc_lock); + umidi->disconnected = 1; + spin_unlock_irq(&umidi->disc_lock); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->out) @@ -1062,6 +1077,7 @@ void snd_usbmidi_disconnect(struct list_head* p) if (ep->in) usb_kill_urb(ep->in->urb); } + del_timer_sync(&umidi->error_timer); } static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi) @@ -1685,6 +1701,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); + spin_lock_init(&umidi->disc_lock); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi;