aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/usx2y
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-02-14 03:05:47 -0500
committerTakashi Iwai <tiwai@suse.de>2014-02-17 04:16:25 -0500
commite2439a5401486d8b7f1076fc6df9b80143ed62e2 (patch)
tree3dd69d1751290ac803fe9014db2746523eaac058 /sound/usb/usx2y
parent1f85a0f0cce583a8ac436bda8807ec8fd8e8ef16 (diff)
ALSA: usx2y: Don't peep the card internal object
Avoid traversing the device object list of the card instance just for checking the PCM streams. The driver's private object already contains the array of substream pointers, so it can be simply looked through. The card internal may be restructured in future, thus better not to rely on it. Also, this fixes the possible deadlocks in PCM mutex. Instead of taking multiple PCM mutexes, just take the common mutex in all places. Along with it, rename prepare_mutex as pcm_mutex. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/usx2y')
-rw-r--r--sound/usb/usx2y/usbusx2y.c2
-rw-r--r--sound/usb/usx2y/usbusx2y.h2
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c60
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c76
4 files changed, 61 insertions, 79 deletions
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index e38c87302b15..91e0e2a4808c 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -353,7 +353,7 @@ static int usX2Y_create_card(struct usb_device *device,
353 card->private_free = snd_usX2Y_card_private_free; 353 card->private_free = snd_usX2Y_card_private_free;
354 usX2Y(card)->dev = device; 354 usX2Y(card)->dev = device;
355 init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); 355 init_waitqueue_head(&usX2Y(card)->prepare_wait_queue);
356 mutex_init(&usX2Y(card)->prepare_mutex); 356 mutex_init(&usX2Y(card)->pcm_mutex);
357 INIT_LIST_HEAD(&usX2Y(card)->midi_list); 357 INIT_LIST_HEAD(&usX2Y(card)->midi_list);
358 strcpy(card->driver, "USB "NAME_ALLCAPS""); 358 strcpy(card->driver, "USB "NAME_ALLCAPS"");
359 sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); 359 sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
index e43c0a86441a..6ae6b0806938 100644
--- a/sound/usb/usx2y/usbusx2y.h
+++ b/sound/usb/usx2y/usbusx2y.h
@@ -36,7 +36,7 @@ struct usX2Ydev {
36 unsigned int rate, 36 unsigned int rate,
37 format; 37 format;
38 int chip_status; 38 int chip_status;
39 struct mutex prepare_mutex; 39 struct mutex pcm_mutex;
40 struct us428ctls_sharedmem *us428ctls_sharedmem; 40 struct us428ctls_sharedmem *us428ctls_sharedmem;
41 int wait_iso_frame; 41 int wait_iso_frame;
42 wait_queue_head_t us428ctls_wait_queue_head; 42 wait_queue_head_t us428ctls_wait_queue_head;
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 6234a51625b1..a63330dd1407 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -752,36 +752,44 @@ static int snd_usX2Y_pcm_hw_params(struct snd_pcm_substream *substream,
752 unsigned int rate = params_rate(hw_params); 752 unsigned int rate = params_rate(hw_params);
753 snd_pcm_format_t format = params_format(hw_params); 753 snd_pcm_format_t format = params_format(hw_params);
754 struct snd_card *card = substream->pstr->pcm->card; 754 struct snd_card *card = substream->pstr->pcm->card;
755 struct list_head *list; 755 struct usX2Ydev *dev = usX2Y(card);
756 int i;
756 757
758 mutex_lock(&usX2Y(card)->pcm_mutex);
757 snd_printdd("snd_usX2Y_hw_params(%p, %p)\n", substream, hw_params); 759 snd_printdd("snd_usX2Y_hw_params(%p, %p)\n", substream, hw_params);
758 // all pcm substreams off one usX2Y have to operate at the same rate & format 760 /* all pcm substreams off one usX2Y have to operate at the same
759 list_for_each(list, &card->devices) { 761 * rate & format
760 struct snd_device *dev; 762 */
761 struct snd_pcm *pcm; 763 for (i = 0; i < dev->pcm_devs * 2; i++) {
762 int s; 764 struct snd_usX2Y_substream *subs = dev->subs[i];
763 dev = snd_device(list); 765 struct snd_pcm_substream *test_substream;
764 if (dev->type != SNDRV_DEV_PCM) 766
767 if (!subs)
768 continue;
769 test_substream = subs->pcm_substream;
770 if (!test_substream || test_substream == substream ||
771 !test_substream->runtime)
765 continue; 772 continue;
766 pcm = dev->device_data; 773 if ((test_substream->runtime->format &&
767 for (s = 0; s < 2; ++s) { 774 test_substream->runtime->format != format) ||
768 struct snd_pcm_substream *test_substream; 775 (test_substream->runtime->rate &&
769 test_substream = pcm->streams[s].substream; 776 test_substream->runtime->rate != rate)) {
770 if (test_substream && test_substream != substream && 777 err = -EINVAL;
771 test_substream->runtime && 778 goto error;
772 ((test_substream->runtime->format &&
773 test_substream->runtime->format != format) ||
774 (test_substream->runtime->rate &&
775 test_substream->runtime->rate != rate)))
776 return -EINVAL;
777 } 779 }
778 } 780 }
779 if (0 > (err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)))) { 781
782 err = snd_pcm_lib_malloc_pages(substream,
783 params_buffer_bytes(hw_params));
784 if (err < 0) {
780 snd_printk(KERN_ERR "snd_pcm_lib_malloc_pages(%p, %i) returned %i\n", 785 snd_printk(KERN_ERR "snd_pcm_lib_malloc_pages(%p, %i) returned %i\n",
781 substream, params_buffer_bytes(hw_params), err); 786 substream, params_buffer_bytes(hw_params), err);
782 return err; 787 goto error;
783 } 788 }
784 return 0; 789
790 error:
791 mutex_unlock(&usX2Y(card)->pcm_mutex);
792 return err;
785} 793}
786 794
787/* 795/*
@@ -791,7 +799,7 @@ static int snd_usX2Y_pcm_hw_free(struct snd_pcm_substream *substream)
791{ 799{
792 struct snd_pcm_runtime *runtime = substream->runtime; 800 struct snd_pcm_runtime *runtime = substream->runtime;
793 struct snd_usX2Y_substream *subs = runtime->private_data; 801 struct snd_usX2Y_substream *subs = runtime->private_data;
794 mutex_lock(&subs->usX2Y->prepare_mutex); 802 mutex_lock(&subs->usX2Y->pcm_mutex);
795 snd_printdd("snd_usX2Y_hw_free(%p)\n", substream); 803 snd_printdd("snd_usX2Y_hw_free(%p)\n", substream);
796 804
797 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) { 805 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -812,7 +820,7 @@ static int snd_usX2Y_pcm_hw_free(struct snd_pcm_substream *substream)
812 usX2Y_urbs_release(subs); 820 usX2Y_urbs_release(subs);
813 } 821 }
814 } 822 }
815 mutex_unlock(&subs->usX2Y->prepare_mutex); 823 mutex_unlock(&subs->usX2Y->pcm_mutex);
816 return snd_pcm_lib_free_pages(substream); 824 return snd_pcm_lib_free_pages(substream);
817} 825}
818/* 826/*
@@ -829,7 +837,7 @@ static int snd_usX2Y_pcm_prepare(struct snd_pcm_substream *substream)
829 int err = 0; 837 int err = 0;
830 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream); 838 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
831 839
832 mutex_lock(&usX2Y->prepare_mutex); 840 mutex_lock(&usX2Y->pcm_mutex);
833 usX2Y_subs_prepare(subs); 841 usX2Y_subs_prepare(subs);
834// Start hardware streams 842// Start hardware streams
835// SyncStream first.... 843// SyncStream first....
@@ -849,7 +857,7 @@ static int snd_usX2Y_pcm_prepare(struct snd_pcm_substream *substream)
849 err = usX2Y_urbs_start(subs); 857 err = usX2Y_urbs_start(subs);
850 858
851 up_prepare_mutex: 859 up_prepare_mutex:
852 mutex_unlock(&usX2Y->prepare_mutex); 860 mutex_unlock(&usX2Y->pcm_mutex);
853 return err; 861 return err;
854} 862}
855 863
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 814d0e887c62..90766a92e7fd 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -358,7 +358,7 @@ static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
358 struct snd_pcm_runtime *runtime = substream->runtime; 358 struct snd_pcm_runtime *runtime = substream->runtime;
359 struct snd_usX2Y_substream *subs = runtime->private_data, 359 struct snd_usX2Y_substream *subs = runtime->private_data,
360 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2]; 360 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
361 mutex_lock(&subs->usX2Y->prepare_mutex); 361 mutex_lock(&subs->usX2Y->pcm_mutex);
362 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream); 362 snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
363 363
364 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) { 364 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -387,7 +387,7 @@ static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
387 usX2Y_usbpcm_urbs_release(cap_subs2); 387 usX2Y_usbpcm_urbs_release(cap_subs2);
388 } 388 }
389 } 389 }
390 mutex_unlock(&subs->usX2Y->prepare_mutex); 390 mutex_unlock(&subs->usX2Y->pcm_mutex);
391 return snd_pcm_lib_free_pages(substream); 391 return snd_pcm_lib_free_pages(substream);
392} 392}
393 393
@@ -493,7 +493,7 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
493 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm)); 493 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
494 } 494 }
495 495
496 mutex_lock(&usX2Y->prepare_mutex); 496 mutex_lock(&usX2Y->pcm_mutex);
497 usX2Y_subs_prepare(subs); 497 usX2Y_subs_prepare(subs);
498// Start hardware streams 498// Start hardware streams
499// SyncStream first.... 499// SyncStream first....
@@ -534,7 +534,7 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
534 usX2Y->hwdep_pcm_shm->capture_iso_start = -1; 534 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
535 535
536 up_prepare_mutex: 536 up_prepare_mutex:
537 mutex_unlock(&usX2Y->prepare_mutex); 537 mutex_unlock(&usX2Y->pcm_mutex);
538 return err; 538 return err;
539} 539}
540 540
@@ -600,59 +600,30 @@ static struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
600}; 600};
601 601
602 602
603static int usX2Y_pcms_lock_check(struct snd_card *card) 603static int usX2Y_pcms_busy_check(struct snd_card *card)
604{ 604{
605 struct list_head *list; 605 struct usX2Ydev *dev = usX2Y(card);
606 struct snd_device *dev; 606 int i;
607 struct snd_pcm *pcm;
608 int err = 0;
609 list_for_each(list, &card->devices) {
610 dev = snd_device(list);
611 if (dev->type != SNDRV_DEV_PCM)
612 continue;
613 pcm = dev->device_data;
614 mutex_lock(&pcm->open_mutex);
615 }
616 list_for_each(list, &card->devices) {
617 int s;
618 dev = snd_device(list);
619 if (dev->type != SNDRV_DEV_PCM)
620 continue;
621 pcm = dev->device_data;
622 for (s = 0; s < 2; ++s) {
623 struct snd_pcm_substream *substream;
624 substream = pcm->streams[s].substream;
625 if (substream && SUBSTREAM_BUSY(substream))
626 err = -EBUSY;
627 }
628 }
629 return err;
630}
631
632 607
633static void usX2Y_pcms_unlock(struct snd_card *card) 608 for (i = 0; i < dev->pcm_devs * 2; i++) {
634{ 609 struct snd_usX2Y_substream *subs = dev->subs[i];
635 struct list_head *list; 610 if (subs && subs->pcm_substream &&
636 struct snd_device *dev; 611 SUBSTREAM_BUSY(subs->pcm_substream))
637 struct snd_pcm *pcm; 612 return -EBUSY;
638 list_for_each(list, &card->devices) {
639 dev = snd_device(list);
640 if (dev->type != SNDRV_DEV_PCM)
641 continue;
642 pcm = dev->device_data;
643 mutex_unlock(&pcm->open_mutex);
644 } 613 }
614 return 0;
645} 615}
646 616
647
648static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file) 617static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
649{ 618{
650 // we need to be the first
651 struct snd_card *card = hw->card; 619 struct snd_card *card = hw->card;
652 int err = usX2Y_pcms_lock_check(card); 620 int err;
653 if (0 == err) 621
622 mutex_lock(&usX2Y(card)->pcm_mutex);
623 err = usX2Y_pcms_busy_check(card);
624 if (!err)
654 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS; 625 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
655 usX2Y_pcms_unlock(card); 626 mutex_unlock(&usX2Y(card)->pcm_mutex);
656 return err; 627 return err;
657} 628}
658 629
@@ -660,10 +631,13 @@ static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
660static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file) 631static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
661{ 632{
662 struct snd_card *card = hw->card; 633 struct snd_card *card = hw->card;
663 int err = usX2Y_pcms_lock_check(card); 634 int err;
664 if (0 == err) 635
636 mutex_lock(&usX2Y(card)->pcm_mutex);
637 err = usX2Y_pcms_busy_check(card);
638 if (!err)
665 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS; 639 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
666 usX2Y_pcms_unlock(card); 640 mutex_unlock(&usX2Y(card)->pcm_mutex);
667 return err; 641 return err;
668} 642}
669 643