diff options
author | Liam Girdwood <lrg@ti.com> | 2012-02-08 15:33:31 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-02-09 03:20:22 -0500 |
commit | 945e5038455fef18e73914c149717878d78cb4c0 (patch) | |
tree | d3ea8e7c0bd087afda16ed6b7fa145eb8c00bb68 /sound/core | |
parent | 62aa2b537c6f5957afd98e29f96897419ed5ebab (diff) |
ALSA: PCM - Add PCM creation API for internal PCMs.
The new ASoC dynamic PCM core needs to create PCMs and substreams that are
for use by internal ASoC drivers only and not visible to userspace for
direct IO. These new PCMs are similar to regular PCMs expect they have no
device nodes or procfs entries. The ASoC component drivers use them in exactly
the same way as regular PCMs for PCM and DAI operations.
The intention is that a dynamic PCM based driver will register both regular
PCMs and internal PCMs. The regular PCMs will be used for all IO with userspace
however the internal PCMs will be used by the driver to route digital audio
through numerous back end DAI links (with potentially a DSP providing different
hw_params, DAI formats based on the regular front end PCM params) to devices
like CODECs, MODEMs, Bluetooth, FM, DMICs, etc
This patch adds a new snd_pcm_new_internal() API call to create the internal PCM
without device nodes or procfs. It also adds adds a new internal flag to snd_pcm.
[fixed minor coding-style issues by tiwai]
Signed-off-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core')
-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: |