summaryrefslogtreecommitdiffstats
path: root/sound/usb/pcm.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-10-12 09:12:55 -0400
committerTakashi Iwai <tiwai@suse.de>2012-10-30 06:06:54 -0400
commit978520b75f0a1ce82b17e1e8186417250de6d545 (patch)
tree2b0d8619df66706779d9520789e27bf6ca385383 /sound/usb/pcm.c
parent9b0573c07f278e9888c352aa9724035c75784ea0 (diff)
ALSA: usb-audio: Fix races at disconnection
Close some races at disconnection of a USB audio device by adding the chip->shutdown_mutex and chip->shutdown check at appropriate places. The spots to put bandaids are: - PCM prepare, hw_params and hw_free - where the usb device is accessed for communication or get speed, in mixer.c and others; the device speed is now cached in subs->speed instead of accessing to chip->dev The accesses in PCM open and close don't need the mutex protection because these are already handled in the core PCM disconnection code. The autosuspend/autoresume codes are still uncovered by this patch because of possible mutex deadlocks. They'll be covered by the upcoming change to rwsem. Also the mixer codes are untouched, too. These will be fixed in another patch, too. Reported-by: Matthieu CASTET <matthieu.castet@parrot.com> Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r--sound/usb/pcm.c49
1 files changed, 32 insertions, 17 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 55e19e1b80ec..55e741c5f231 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -71,6 +71,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
71 unsigned int hwptr_done; 71 unsigned int hwptr_done;
72 72
73 subs = (struct snd_usb_substream *)substream->runtime->private_data; 73 subs = (struct snd_usb_substream *)substream->runtime->private_data;
74 if (subs->stream->chip->shutdown)
75 return SNDRV_PCM_POS_XRUN;
74 spin_lock(&subs->lock); 76 spin_lock(&subs->lock);
75 hwptr_done = subs->hwptr_done; 77 hwptr_done = subs->hwptr_done;
76 substream->runtime->delay = snd_usb_pcm_delay(subs, 78 substream->runtime->delay = snd_usb_pcm_delay(subs,
@@ -444,7 +446,6 @@ static int configure_endpoint(struct snd_usb_substream *subs)
444{ 446{
445 int ret; 447 int ret;
446 448
447 mutex_lock(&subs->stream->chip->shutdown_mutex);
448 /* format changed */ 449 /* format changed */
449 stop_endpoints(subs, 0, 0, 0); 450 stop_endpoints(subs, 0, 0, 0);
450 ret = snd_usb_endpoint_set_params(subs->data_endpoint, 451 ret = snd_usb_endpoint_set_params(subs->data_endpoint,
@@ -455,7 +456,7 @@ static int configure_endpoint(struct snd_usb_substream *subs)
455 subs->cur_audiofmt, 456 subs->cur_audiofmt,
456 subs->sync_endpoint); 457 subs->sync_endpoint);
457 if (ret < 0) 458 if (ret < 0)
458 goto unlock; 459 return ret;
459 460
460 if (subs->sync_endpoint) 461 if (subs->sync_endpoint)
461 ret = snd_usb_endpoint_set_params(subs->data_endpoint, 462 ret = snd_usb_endpoint_set_params(subs->data_endpoint,
@@ -465,9 +466,6 @@ static int configure_endpoint(struct snd_usb_substream *subs)
465 subs->cur_rate, 466 subs->cur_rate,
466 subs->cur_audiofmt, 467 subs->cur_audiofmt,
467 NULL); 468 NULL);
468
469unlock:
470 mutex_unlock(&subs->stream->chip->shutdown_mutex);
471 return ret; 469 return ret;
472} 470}
473 471
@@ -505,7 +503,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
505 return -EINVAL; 503 return -EINVAL;
506 } 504 }
507 505
508 if ((ret = set_format(subs, fmt)) < 0) 506 mutex_lock(&subs->stream->chip->shutdown_mutex);
507 if (subs->stream->chip->shutdown)
508 ret = -ENODEV;
509 else
510 ret = set_format(subs, fmt);
511 mutex_unlock(&subs->stream->chip->shutdown_mutex);
512 if (ret < 0)
509 return ret; 513 return ret;
510 514
511 subs->interface = fmt->iface; 515 subs->interface = fmt->iface;
@@ -528,8 +532,10 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
528 subs->cur_rate = 0; 532 subs->cur_rate = 0;
529 subs->period_bytes = 0; 533 subs->period_bytes = 0;
530 mutex_lock(&subs->stream->chip->shutdown_mutex); 534 mutex_lock(&subs->stream->chip->shutdown_mutex);
531 stop_endpoints(subs, 0, 1, 1); 535 if (!subs->stream->chip->shutdown) {
532 deactivate_endpoints(subs); 536 stop_endpoints(subs, 0, 1, 1);
537 deactivate_endpoints(subs);
538 }
533 mutex_unlock(&subs->stream->chip->shutdown_mutex); 539 mutex_unlock(&subs->stream->chip->shutdown_mutex);
534 return snd_pcm_lib_free_vmalloc_buffer(substream); 540 return snd_pcm_lib_free_vmalloc_buffer(substream);
535} 541}
@@ -552,12 +558,19 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
552 return -ENXIO; 558 return -ENXIO;
553 } 559 }
554 560
555 if (snd_BUG_ON(!subs->data_endpoint)) 561 mutex_lock(&subs->stream->chip->shutdown_mutex);
556 return -EIO; 562 if (subs->stream->chip->shutdown) {
563 ret = -ENODEV;
564 goto unlock;
565 }
566 if (snd_BUG_ON(!subs->data_endpoint)) {
567 ret = -EIO;
568 goto unlock;
569 }
557 570
558 ret = set_format(subs, subs->cur_audiofmt); 571 ret = set_format(subs, subs->cur_audiofmt);
559 if (ret < 0) 572 if (ret < 0)
560 return ret; 573 goto unlock;
561 574
562 iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); 575 iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface);
563 alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; 576 alts = &iface->altsetting[subs->cur_audiofmt->altset_idx];
@@ -567,12 +580,12 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
567 subs->cur_audiofmt, 580 subs->cur_audiofmt,
568 subs->cur_rate); 581 subs->cur_rate);
569 if (ret < 0) 582 if (ret < 0)
570 return ret; 583 goto unlock;
571 584
572 if (subs->need_setup_ep) { 585 if (subs->need_setup_ep) {
573 ret = configure_endpoint(subs); 586 ret = configure_endpoint(subs);
574 if (ret < 0) 587 if (ret < 0)
575 return ret; 588 goto unlock;
576 subs->need_setup_ep = false; 589 subs->need_setup_ep = false;
577 } 590 }
578 591
@@ -592,9 +605,11 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
592 /* for playback, submit the URBs now; otherwise, the first hwptr_done 605 /* for playback, submit the URBs now; otherwise, the first hwptr_done
593 * updates for all URBs would happen at the same time when starting */ 606 * updates for all URBs would happen at the same time when starting */
594 if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) 607 if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
595 return start_endpoints(subs, 1); 608 ret = start_endpoints(subs, 1);
596 609
597 return 0; 610 unlock:
611 mutex_unlock(&subs->stream->chip->shutdown_mutex);
612 return ret;
598} 613}
599 614
600static struct snd_pcm_hardware snd_usb_hardware = 615static struct snd_pcm_hardware snd_usb_hardware =
@@ -647,7 +662,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs,
647 return 0; 662 return 0;
648 } 663 }
649 /* check whether the period time is >= the data packet interval */ 664 /* check whether the period time is >= the data packet interval */
650 if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { 665 if (subs->speed != USB_SPEED_FULL) {
651 ptime = 125 * (1 << fp->datainterval); 666 ptime = 125 * (1 << fp->datainterval);
652 if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { 667 if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
653 hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); 668 hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max);
@@ -925,7 +940,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
925 return err; 940 return err;
926 941
927 param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; 942 param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
928 if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) 943 if (subs->speed == USB_SPEED_FULL)
929 /* full speed devices have fixed data packet interval */ 944 /* full speed devices have fixed data packet interval */
930 ptmin = 1000; 945 ptmin = 1000;
931 if (ptmin == 1000) 946 if (ptmin == 1000)