diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/usb/usbmidi.c | 19 |
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 | ||
115 | struct snd_usb_midi_out_endpoint { | 117 | struct 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 | ||
1067 | static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi) | 1083 | 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, | |||
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 | ||