diff options
Diffstat (limited to 'sound/core/pcm.c')
-rw-r--r-- | sound/core/pcm.c | 99 |
1 files changed, 69 insertions, 30 deletions
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8928ca871c22..6e4bfcc14254 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -650,7 +650,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) | |||
650 | pstr->stream = stream; | 650 | pstr->stream = stream; |
651 | pstr->pcm = pcm; | 651 | pstr->pcm = pcm; |
652 | pstr->substream_count = substream_count; | 652 | pstr->substream_count = substream_count; |
653 | if (substream_count > 0) { | 653 | if (substream_count > 0 && !pcm->internal) { |
654 | err = snd_pcm_stream_proc_init(pstr); | 654 | err = snd_pcm_stream_proc_init(pstr); |
655 | if (err < 0) { | 655 | if (err < 0) { |
656 | snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n"); | 656 | snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n"); |
@@ -674,15 +674,18 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) | |||
674 | pstr->substream = substream; | 674 | pstr->substream = substream; |
675 | else | 675 | else |
676 | prev->next = substream; | 676 | prev->next = substream; |
677 | err = snd_pcm_substream_proc_init(substream); | 677 | |
678 | if (err < 0) { | 678 | if (!pcm->internal) { |
679 | snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n"); | 679 | err = snd_pcm_substream_proc_init(substream); |
680 | if (prev == NULL) | 680 | if (err < 0) { |
681 | pstr->substream = NULL; | 681 | snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init\n"); |
682 | else | 682 | if (prev == NULL) |
683 | prev->next = NULL; | 683 | pstr->substream = NULL; |
684 | kfree(substream); | 684 | else |
685 | return err; | 685 | prev->next = NULL; |
686 | kfree(substream); | ||
687 | return err; | ||
688 | } | ||
686 | } | 689 | } |
687 | substream->group = &substream->self_group; | 690 | substream->group = &substream->self_group; |
688 | spin_lock_init(&substream->self_group.lock); | 691 | spin_lock_init(&substream->self_group.lock); |
@@ -696,25 +699,9 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) | |||
696 | 699 | ||
697 | EXPORT_SYMBOL(snd_pcm_new_stream); | 700 | EXPORT_SYMBOL(snd_pcm_new_stream); |
698 | 701 | ||
699 | /** | 702 | static int _snd_pcm_new(struct snd_card *card, const char *id, int device, |
700 | * snd_pcm_new - create a new PCM instance | 703 | int playback_count, int capture_count, bool internal, |
701 | * @card: the card instance | 704 | struct snd_pcm **rpcm) |
702 | * @id: the id string | ||
703 | * @device: the device index (zero based) | ||
704 | * @playback_count: the number of substreams for playback | ||
705 | * @capture_count: the number of substreams for capture | ||
706 | * @rpcm: the pointer to store the new pcm instance | ||
707 | * | ||
708 | * Creates a new PCM instance. | ||
709 | * | ||
710 | * The pcm operators have to be set afterwards to the new instance | ||
711 | * via snd_pcm_set_ops(). | ||
712 | * | ||
713 | * Returns zero if successful, or a negative error code on failure. | ||
714 | */ | ||
715 | int snd_pcm_new(struct snd_card *card, const char *id, int device, | ||
716 | int playback_count, int capture_count, | ||
717 | struct snd_pcm ** rpcm) | ||
718 | { | 705 | { |
719 | struct snd_pcm *pcm; | 706 | struct snd_pcm *pcm; |
720 | int err; | 707 | int err; |
@@ -735,6 +722,7 @@ int snd_pcm_new(struct snd_card *card, const char *id, int device, | |||
735 | } | 722 | } |
736 | pcm->card = card; | 723 | pcm->card = card; |
737 | pcm->device = device; | 724 | pcm->device = device; |
725 | pcm->internal = internal; | ||
738 | if (id) | 726 | if (id) |
739 | strlcpy(pcm->id, id, sizeof(pcm->id)); | 727 | strlcpy(pcm->id, id, sizeof(pcm->id)); |
740 | if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { | 728 | if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { |
@@ -756,8 +744,59 @@ int snd_pcm_new(struct snd_card *card, const char *id, int device, | |||
756 | return 0; | 744 | return 0; |
757 | } | 745 | } |
758 | 746 | ||
747 | /** | ||
748 | * snd_pcm_new - create a new PCM instance | ||
749 | * @card: the card instance | ||
750 | * @id: the id string | ||
751 | * @device: the device index (zero based) | ||
752 | * @playback_count: the number of substreams for playback | ||
753 | * @capture_count: the number of substreams for capture | ||
754 | * @rpcm: the pointer to store the new pcm instance | ||
755 | * | ||
756 | * Creates a new PCM instance. | ||
757 | * | ||
758 | * The pcm operators have to be set afterwards to the new instance | ||
759 | * via snd_pcm_set_ops(). | ||
760 | * | ||
761 | * Returns zero if successful, or a negative error code on failure. | ||
762 | */ | ||
763 | int snd_pcm_new(struct snd_card *card, const char *id, int device, | ||
764 | int playback_count, int capture_count, struct snd_pcm **rpcm) | ||
765 | { | ||
766 | return _snd_pcm_new(card, id, device, playback_count, capture_count, | ||
767 | false, rpcm); | ||
768 | } | ||
759 | EXPORT_SYMBOL(snd_pcm_new); | 769 | EXPORT_SYMBOL(snd_pcm_new); |
760 | 770 | ||
771 | /** | ||
772 | * snd_pcm_new_internal - create a new internal PCM instance | ||
773 | * @card: the card instance | ||
774 | * @id: the id string | ||
775 | * @device: the device index (zero based - shared with normal PCMs) | ||
776 | * @playback_count: the number of substreams for playback | ||
777 | * @capture_count: the number of substreams for capture | ||
778 | * @rpcm: the pointer to store the new pcm instance | ||
779 | * | ||
780 | * Creates a new internal PCM instance with no userspace device or procfs | ||
781 | * entries. This is used by ASoC Back End PCMs in order to create a PCM that | ||
782 | * will only be used internally by kernel drivers. i.e. it cannot be opened | ||
783 | * by userspace. It provides existing ASoC components drivers with a substream | ||
784 | * and access to any private data. | ||
785 | * | ||
786 | * The pcm operators have to be set afterwards to the new instance | ||
787 | * via snd_pcm_set_ops(). | ||
788 | * | ||
789 | * Returns zero if successful, or a negative error code on failure. | ||
790 | */ | ||
791 | int snd_pcm_new_internal(struct snd_card *card, const char *id, int device, | ||
792 | int playback_count, int capture_count, | ||
793 | struct snd_pcm **rpcm) | ||
794 | { | ||
795 | return _snd_pcm_new(card, id, device, playback_count, capture_count, | ||
796 | true, rpcm); | ||
797 | } | ||
798 | EXPORT_SYMBOL(snd_pcm_new_internal); | ||
799 | |||
761 | static void snd_pcm_free_stream(struct snd_pcm_str * pstr) | 800 | static void snd_pcm_free_stream(struct snd_pcm_str * pstr) |
762 | { | 801 | { |
763 | struct snd_pcm_substream *substream, *substream_next; | 802 | struct snd_pcm_substream *substream, *substream_next; |
@@ -994,7 +1033,7 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
994 | } | 1033 | } |
995 | for (cidx = 0; cidx < 2; cidx++) { | 1034 | for (cidx = 0; cidx < 2; cidx++) { |
996 | int devtype = -1; | 1035 | int devtype = -1; |
997 | if (pcm->streams[cidx].substream == NULL) | 1036 | if (pcm->streams[cidx].substream == NULL || pcm->internal) |
998 | continue; | 1037 | continue; |
999 | switch (cidx) { | 1038 | switch (cidx) { |
1000 | case SNDRV_PCM_STREAM_PLAYBACK: | 1039 | case SNDRV_PCM_STREAM_PLAYBACK: |