aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-04-10 15:27:23 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-04-26 10:47:54 -0400
commitfae0017ccf08a2d2ddb5c420793f3591d8ab85cb (patch)
tree9a18ac17e9affd25f00cc1ba3e6a050f389b5e3d /sound
parent2ea24ea2243e358ca74541d159da329a7e734d81 (diff)
ALSA: usb - Fix Oops after usb-midi disconnection
commit 29aac005ff4dc8a5f50b80f4e5c4f59b21c0fb50 upstream. usb-midi causes sometimes Oops at snd_usbmidi_output_drain() after disconnection. This is due to the access to the endpoints which have been already released at disconnection while the files are still alive. This patch fixes the problem by checking disconnection state at snd_usbmidi_output_drain() and by releasing urbs but keeping the endpoint instances until really all freed. Tested-by: Tvrtko Ursulin <tvrtko@ursulin.net> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/usb/usbmidi.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index b2da478a0fae..c7cb207963f5 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -984,6 +984,8 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
984 DEFINE_WAIT(wait); 984 DEFINE_WAIT(wait);
985 long timeout = msecs_to_jiffies(50); 985 long timeout = msecs_to_jiffies(50);
986 986
987 if (ep->umidi->disconnected)
988 return;
987 /* 989 /*
988 * The substream buffer is empty, but some data might still be in the 990 * The substream buffer is empty, but some data might still be in the
989 * currently active URBs, so we have to wait for those to complete. 991 * currently active URBs, so we have to wait for those to complete.
@@ -1121,14 +1123,21 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
1121 * Frees an output endpoint. 1123 * Frees an output endpoint.
1122 * May be called when ep hasn't been initialized completely. 1124 * May be called when ep hasn't been initialized completely.
1123 */ 1125 */
1124static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep) 1126static void snd_usbmidi_out_endpoint_clear(struct snd_usb_midi_out_endpoint *ep)
1125{ 1127{
1126 unsigned int i; 1128 unsigned int i;
1127 1129
1128 for (i = 0; i < OUTPUT_URBS; ++i) 1130 for (i = 0; i < OUTPUT_URBS; ++i)
1129 if (ep->urbs[i].urb) 1131 if (ep->urbs[i].urb) {
1130 free_urb_and_buffer(ep->umidi, ep->urbs[i].urb, 1132 free_urb_and_buffer(ep->umidi, ep->urbs[i].urb,
1131 ep->max_transfer); 1133 ep->max_transfer);
1134 ep->urbs[i].urb = NULL;
1135 }
1136}
1137
1138static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep)
1139{
1140 snd_usbmidi_out_endpoint_clear(ep);
1132 kfree(ep); 1141 kfree(ep);
1133} 1142}
1134 1143
@@ -1260,15 +1269,18 @@ void snd_usbmidi_disconnect(struct list_head* p)
1260 usb_kill_urb(ep->out->urbs[j].urb); 1269 usb_kill_urb(ep->out->urbs[j].urb);
1261 if (umidi->usb_protocol_ops->finish_out_endpoint) 1270 if (umidi->usb_protocol_ops->finish_out_endpoint)
1262 umidi->usb_protocol_ops->finish_out_endpoint(ep->out); 1271 umidi->usb_protocol_ops->finish_out_endpoint(ep->out);
1272 ep->out->active_urbs = 0;
1273 if (ep->out->drain_urbs) {
1274 ep->out->drain_urbs = 0;
1275 wake_up(&ep->out->drain_wait);
1276 }
1263 } 1277 }
1264 if (ep->in) 1278 if (ep->in)
1265 for (j = 0; j < INPUT_URBS; ++j) 1279 for (j = 0; j < INPUT_URBS; ++j)
1266 usb_kill_urb(ep->in->urbs[j]); 1280 usb_kill_urb(ep->in->urbs[j]);
1267 /* free endpoints here; later call can result in Oops */ 1281 /* free endpoints here; later call can result in Oops */
1268 if (ep->out) { 1282 if (ep->out)
1269 snd_usbmidi_out_endpoint_delete(ep->out); 1283 snd_usbmidi_out_endpoint_clear(ep->out);
1270 ep->out = NULL;
1271 }
1272 if (ep->in) { 1284 if (ep->in) {
1273 snd_usbmidi_in_endpoint_delete(ep->in); 1285 snd_usbmidi_in_endpoint_delete(ep->in);
1274 ep->in = NULL; 1286 ep->in = NULL;