aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/usb/usbmidi.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 750e929d5870..6676a177c99e 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -104,12 +104,14 @@ struct snd_usb_midi {
104 struct usb_protocol_ops* usb_protocol_ops; 104 struct usb_protocol_ops* usb_protocol_ops;
105 struct list_head list; 105 struct list_head list;
106 struct timer_list error_timer; 106 struct timer_list error_timer;
107 spinlock_t disc_lock;
107 108
108 struct snd_usb_midi_endpoint { 109 struct snd_usb_midi_endpoint {
109 struct snd_usb_midi_out_endpoint *out; 110 struct snd_usb_midi_out_endpoint *out;
110 struct snd_usb_midi_in_endpoint *in; 111 struct snd_usb_midi_in_endpoint *in;
111 } endpoints[MIDI_MAX_ENDPOINTS]; 112 } endpoints[MIDI_MAX_ENDPOINTS];
112 unsigned long input_triggered; 113 unsigned long input_triggered;
114 unsigned char disconnected;
113}; 115};
114 116
115struct snd_usb_midi_out_endpoint { 117struct snd_usb_midi_out_endpoint {
@@ -306,6 +308,11 @@ static void snd_usbmidi_error_timer(unsigned long data)
306 struct snd_usb_midi *umidi = (struct snd_usb_midi *)data; 308 struct snd_usb_midi *umidi = (struct snd_usb_midi *)data;
307 int i; 309 int i;
308 310
311 spin_lock(&umidi->disc_lock);
312 if (umidi->disconnected) {
313 spin_unlock(&umidi->disc_lock);
314 return;
315 }
309 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { 316 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
310 struct snd_usb_midi_in_endpoint *in = umidi->endpoints[i].in; 317 struct snd_usb_midi_in_endpoint *in = umidi->endpoints[i].in;
311 if (in && in->error_resubmit) { 318 if (in && in->error_resubmit) {
@@ -316,6 +323,7 @@ static void snd_usbmidi_error_timer(unsigned long data)
316 if (umidi->endpoints[i].out) 323 if (umidi->endpoints[i].out)
317 snd_usbmidi_do_output(umidi->endpoints[i].out); 324 snd_usbmidi_do_output(umidi->endpoints[i].out);
318 } 325 }
326 spin_unlock(&umidi->disc_lock);
319} 327}
320 328
321/* helper function to send static data that may not DMA-able */ 329/* helper function to send static data that may not DMA-able */
@@ -1049,7 +1057,14 @@ void snd_usbmidi_disconnect(struct list_head* p)
1049 int i; 1057 int i;
1050 1058
1051 umidi = list_entry(p, struct snd_usb_midi, list); 1059 umidi = list_entry(p, struct snd_usb_midi, list);
1052 del_timer_sync(&umidi->error_timer); 1060 /*
1061 * an URB's completion handler may start the timer and
1062 * a timer may submit an URB. To reliably break the cycle
1063 * a flag under lock must be used
1064 */
1065 spin_lock_irq(&umidi->disc_lock);
1066 umidi->disconnected = 1;
1067 spin_unlock_irq(&umidi->disc_lock);
1053 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { 1068 for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
1054 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; 1069 struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
1055 if (ep->out) 1070 if (ep->out)
@@ -1062,6 +1077,7 @@ void snd_usbmidi_disconnect(struct list_head* p)
1062 if (ep->in) 1077 if (ep->in)
1063 usb_kill_urb(ep->in->urb); 1078 usb_kill_urb(ep->in->urb);
1064 } 1079 }
1080 del_timer_sync(&umidi->error_timer);
1065} 1081}
1066 1082
1067static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi) 1083static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)
@@ -1685,6 +1701,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
1685 umidi->quirk = quirk; 1701 umidi->quirk = quirk;
1686 umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; 1702 umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
1687 init_timer(&umidi->error_timer); 1703 init_timer(&umidi->error_timer);
1704 spin_lock_init(&umidi->disc_lock);
1688 umidi->error_timer.function = snd_usbmidi_error_timer; 1705 umidi->error_timer.function = snd_usbmidi_error_timer;
1689 umidi->error_timer.data = (unsigned long)umidi; 1706 umidi->error_timer.data = (unsigned long)umidi;
1690 1707