aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2008-04-14 09:39:14 -0400
committerTakashi Iwai <tiwai@suse.de>2008-04-24 06:00:35 -0400
commit8d048841e822f745187246a036d03f2793739b7f (patch)
tree0ea6afcd5cdb817c40c9877b5f9a19982ca7afd2 /sound
parentf57ab97e767d293132a29a43ca3ecb0f73f1d5bb (diff)
[ALSA] snd_usb_caiaq: fix potential lockups locking
This patch fixes potential lockups in snd_usb_caiaq by refining the locking mechanims and by using usb_kill_urb() in favor to usb_unlink_urb(). Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/usb/caiaq/caiaq-audio.c71
-rw-r--r--sound/usb/caiaq/caiaq-device.c4
2 files changed, 31 insertions, 44 deletions
diff --git a/sound/usb/caiaq/caiaq-audio.c b/sound/usb/caiaq/caiaq-audio.c
index 9cc4cd8283f9..1aa927942cc6 100644
--- a/sound/usb/caiaq/caiaq-audio.c
+++ b/sound/usb/caiaq/caiaq-audio.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2006,2007 Daniel Mack, Karsten Wiese 2 * Copyright (c) 2006-2008 Daniel Mack, Karsten Wiese
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by 5 * it under the terms of the GNU General Public License as published by
@@ -77,10 +77,15 @@ static void
77deactivate_substream(struct snd_usb_caiaqdev *dev, 77deactivate_substream(struct snd_usb_caiaqdev *dev,
78 struct snd_pcm_substream *sub) 78 struct snd_pcm_substream *sub)
79{ 79{
80 unsigned long flags;
81 spin_lock_irqsave(&dev->spinlock, flags);
82
80 if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) 83 if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
81 dev->sub_playback[sub->number] = NULL; 84 dev->sub_playback[sub->number] = NULL;
82 else 85 else
83 dev->sub_capture[sub->number] = NULL; 86 dev->sub_capture[sub->number] = NULL;
87
88 spin_unlock_irqrestore(&dev->spinlock, flags);
84} 89}
85 90
86static int 91static int
@@ -97,13 +102,13 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
97{ 102{
98 int i, ret; 103 int i, ret;
99 104
100 debug("stream_start(%p)\n", dev); 105 debug("%s(%p)\n", __func__, dev);
101 spin_lock_irq(&dev->spinlock); 106
102 if (dev->streaming) { 107 if (dev->streaming)
103 spin_unlock_irq(&dev->spinlock);
104 return -EINVAL; 108 return -EINVAL;
105 }
106 109
110 memset(dev->sub_playback, 0, sizeof(dev->sub_playback));
111 memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
107 dev->input_panic = 0; 112 dev->input_panic = 0;
108 dev->output_panic = 0; 113 dev->output_panic = 0;
109 dev->first_packet = 1; 114 dev->first_packet = 1;
@@ -112,37 +117,35 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
112 for (i = 0; i < N_URBS; i++) { 117 for (i = 0; i < N_URBS; i++) {
113 ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC); 118 ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC);
114 if (ret) { 119 if (ret) {
115 log("unable to trigger initial read #%d! (ret = %d)\n", 120 log("unable to trigger read #%d! (ret %d)\n", i, ret);
116 i, ret);
117 dev->streaming = 0; 121 dev->streaming = 0;
118 spin_unlock_irq(&dev->spinlock);
119 return -EPIPE; 122 return -EPIPE;
120 } 123 }
121 } 124 }
122 125
123 spin_unlock_irq(&dev->spinlock);
124 return 0; 126 return 0;
125} 127}
126 128
127static void stream_stop(struct snd_usb_caiaqdev *dev) 129static void stream_stop(struct snd_usb_caiaqdev *dev)
128{ 130{
129 int i; 131 int i;
130 132
131 debug("stream_stop(%p)\n", dev); 133 debug("%s(%p)\n", __func__, dev);
132 if (!dev->streaming) 134 if (!dev->streaming)
133 return; 135 return;
134 136
135 dev->streaming = 0; 137 dev->streaming = 0;
138
136 for (i = 0; i < N_URBS; i++) { 139 for (i = 0; i < N_URBS; i++) {
137 usb_unlink_urb(dev->data_urbs_in[i]); 140 usb_kill_urb(dev->data_urbs_in[i]);
138 usb_unlink_urb(dev->data_urbs_out[i]); 141 usb_kill_urb(dev->data_urbs_out[i]);
139 } 142 }
140} 143}
141 144
142static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream) 145static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream)
143{ 146{
144 struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); 147 struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
145 debug("snd_usb_caiaq_substream_open(%p)\n", substream); 148 debug("%s(%p)\n", __func__, substream);
146 substream->runtime->hw = dev->pcm_info; 149 substream->runtime->hw = dev->pcm_info;
147 snd_pcm_limit_hw_rates(substream->runtime); 150 snd_pcm_limit_hw_rates(substream->runtime);
148 return 0; 151 return 0;
@@ -152,7 +155,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
152{ 155{
153 struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); 156 struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
154 157
155 debug("snd_usb_caiaq_substream_close(%p)\n", substream); 158 debug("%s(%p)\n", __func__, substream);
156 if (all_substreams_zero(dev->sub_playback) && 159 if (all_substreams_zero(dev->sub_playback) &&
157 all_substreams_zero(dev->sub_capture)) { 160 all_substreams_zero(dev->sub_capture)) {
158 /* when the last client has stopped streaming, 161 /* when the last client has stopped streaming,
@@ -160,24 +163,22 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
160 stream_stop(dev); 163 stream_stop(dev);
161 dev->pcm_info.rates = dev->samplerates; 164 dev->pcm_info.rates = dev->samplerates;
162 } 165 }
163 166
164 return 0; 167 return 0;
165} 168}
166 169
167static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, 170static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
168 struct snd_pcm_hw_params *hw_params) 171 struct snd_pcm_hw_params *hw_params)
169{ 172{
170 debug("snd_usb_caiaq_pcm_hw_params(%p)\n", sub); 173 debug("%s(%p)\n", __func__, sub);
171 return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); 174 return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
172} 175}
173 176
174static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) 177static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
175{ 178{
176 struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); 179 struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
177 debug("snd_usb_caiaq_pcm_hw_free(%p)\n", sub); 180 debug("%s(%p)\n", __func__, sub);
178 spin_lock_irq(&dev->spinlock);
179 deactivate_substream(dev, sub); 181 deactivate_substream(dev, sub);
180 spin_unlock_irq(&dev->spinlock);
181 return snd_pcm_lib_free_pages(sub); 182 return snd_pcm_lib_free_pages(sub);
182} 183}
183 184
@@ -196,7 +197,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
196 struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); 197 struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream);
197 struct snd_pcm_runtime *runtime = substream->runtime; 198 struct snd_pcm_runtime *runtime = substream->runtime;
198 199
199 debug("snd_usb_caiaq_pcm_prepare(%p)\n", substream); 200 debug("%s(%p)\n", __func__, substream);
200 201
201 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 202 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
202 dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; 203 dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1;
@@ -247,15 +248,11 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd)
247 switch (cmd) { 248 switch (cmd) {
248 case SNDRV_PCM_TRIGGER_START: 249 case SNDRV_PCM_TRIGGER_START:
249 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 250 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
250 spin_lock(&dev->spinlock);
251 activate_substream(dev, sub); 251 activate_substream(dev, sub);
252 spin_unlock(&dev->spinlock);
253 break; 252 break;
254 case SNDRV_PCM_TRIGGER_STOP: 253 case SNDRV_PCM_TRIGGER_STOP:
255 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 254 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
256 spin_lock(&dev->spinlock);
257 deactivate_substream(dev, sub); 255 deactivate_substream(dev, sub);
258 spin_unlock(&dev->spinlock);
259 break; 256 break;
260 default: 257 default:
261 return -EINVAL; 258 return -EINVAL;
@@ -328,8 +325,6 @@ static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev,
328 if (all_substreams_zero(dev->sub_capture)) 325 if (all_substreams_zero(dev->sub_capture))
329 return; 326 return;
330 327
331 spin_lock(&dev->spinlock);
332
333 for (i = 0; i < iso->actual_length;) { 328 for (i = 0; i < iso->actual_length;) {
334 for (stream = 0; stream < dev->n_streams; stream++, i++) { 329 for (stream = 0; stream < dev->n_streams; stream++, i++) {
335 sub = dev->sub_capture[stream]; 330 sub = dev->sub_capture[stream];
@@ -345,8 +340,6 @@ static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev,
345 } 340 }
346 } 341 }
347 } 342 }
348
349 spin_unlock(&dev->spinlock);
350} 343}
351 344
352static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, 345static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
@@ -358,8 +351,6 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
358 struct snd_pcm_substream *sub; 351 struct snd_pcm_substream *sub;
359 int stream, i; 352 int stream, i;
360 353
361 spin_lock(&dev->spinlock);
362
363 for (i = 0; i < iso->actual_length;) { 354 for (i = 0; i < iso->actual_length;) {
364 if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) { 355 if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {
365 for (stream = 0; 356 for (stream = 0;
@@ -393,8 +384,6 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
393 } 384 }
394 } 385 }
395 } 386 }
396
397 spin_unlock(&dev->spinlock);
398} 387}
399 388
400static void read_in_urb(struct snd_usb_caiaqdev *dev, 389static void read_in_urb(struct snd_usb_caiaqdev *dev,
@@ -418,8 +407,6 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
418 dev->input_panic ? "(input)" : "", 407 dev->input_panic ? "(input)" : "",
419 dev->output_panic ? "(output)" : ""); 408 dev->output_panic ? "(output)" : "");
420 } 409 }
421
422 check_for_elapsed_periods(dev, dev->sub_capture);
423} 410}
424 411
425static void fill_out_urb(struct snd_usb_caiaqdev *dev, 412static void fill_out_urb(struct snd_usb_caiaqdev *dev,
@@ -429,8 +416,6 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev,
429 unsigned char *usb_buf = urb->transfer_buffer + iso->offset; 416 unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
430 struct snd_pcm_substream *sub; 417 struct snd_pcm_substream *sub;
431 int stream, i; 418 int stream, i;
432
433 spin_lock(&dev->spinlock);
434 419
435 for (i = 0; i < iso->length;) { 420 for (i = 0; i < iso->length;) {
436 for (stream = 0; stream < dev->n_streams; stream++, i++) { 421 for (stream = 0; stream < dev->n_streams; stream++, i++) {
@@ -456,9 +441,6 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev,
456 for (stream = 0; stream < dev->n_streams; stream++, i++) 441 for (stream = 0; stream < dev->n_streams; stream++, i++)
457 usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); 442 usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
458 } 443 }
459
460 spin_unlock(&dev->spinlock);
461 check_for_elapsed_periods(dev, dev->sub_playback);
462} 444}
463 445
464static void read_completed(struct urb *urb) 446static void read_completed(struct urb *urb)
@@ -472,6 +454,7 @@ static void read_completed(struct urb *urb)
472 return; 454 return;
473 455
474 dev = info->dev; 456 dev = info->dev;
457
475 if (!dev->streaming) 458 if (!dev->streaming)
476 return; 459 return;
477 460
@@ -489,8 +472,12 @@ static void read_completed(struct urb *urb)
489 out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; 472 out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame;
490 473
491 if (len > 0) { 474 if (len > 0) {
475 spin_lock(&dev->spinlock);
492 fill_out_urb(dev, out, &out->iso_frame_desc[outframe]); 476 fill_out_urb(dev, out, &out->iso_frame_desc[outframe]);
493 read_in_urb(dev, urb, &urb->iso_frame_desc[frame]); 477 read_in_urb(dev, urb, &urb->iso_frame_desc[frame]);
478 spin_unlock(&dev->spinlock);
479 check_for_elapsed_periods(dev, dev->sub_playback);
480 check_for_elapsed_periods(dev, dev->sub_capture);
494 send_it = 1; 481 send_it = 1;
495 } 482 }
496 483
@@ -696,7 +683,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
696 683
697void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev) 684void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev)
698{ 685{
699 debug("snd_usb_caiaq_audio_free (%p)\n", dev); 686 debug("%s(%p)\n", __func__, dev);
700 stream_stop(dev); 687 stream_stop(dev);
701 free_urbs(dev->data_urbs_in); 688 free_urbs(dev->data_urbs_in);
702 free_urbs(dev->data_urbs_out); 689 free_urbs(dev->data_urbs_out);
diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c
index 7c44a2c7f963..73c08b40cc5f 100644
--- a/sound/usb/caiaq/caiaq-device.c
+++ b/sound/usb/caiaq/caiaq-device.c
@@ -42,7 +42,7 @@
42#endif 42#endif
43 43
44MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 44MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
45MODULE_DESCRIPTION("caiaq USB audio, version 1.3.2"); 45MODULE_DESCRIPTION("caiaq USB audio, version 1.3.4");
46MODULE_LICENSE("GPL"); 46MODULE_LICENSE("GPL");
47MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," 47MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
48 "{Native Instruments, RigKontrol3}," 48 "{Native Instruments, RigKontrol3},"
@@ -456,7 +456,7 @@ static void snd_disconnect(struct usb_interface *intf)
456 struct snd_usb_caiaqdev *dev; 456 struct snd_usb_caiaqdev *dev;
457 struct snd_card *card = dev_get_drvdata(&intf->dev); 457 struct snd_card *card = dev_get_drvdata(&intf->dev);
458 458
459 debug("snd_disconnect(%p)\n", intf); 459 debug("%s(%p)\n", __func__, intf);
460 460
461 if (!card) 461 if (!card)
462 return; 462 return;