diff options
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r-- | sound/soc/soc-pcm.c | 1718 |
1 files changed, 1683 insertions, 35 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 0ad8dcacd2f3..bedd1717a373 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -22,12 +22,38 @@ | |||
22 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
25 | #include <linux/export.h> | ||
26 | #include <linux/debugfs.h> | ||
25 | #include <sound/core.h> | 27 | #include <sound/core.h> |
26 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
27 | #include <sound/pcm_params.h> | 29 | #include <sound/pcm_params.h> |
28 | #include <sound/soc.h> | 30 | #include <sound/soc.h> |
31 | #include <sound/soc-dpcm.h> | ||
29 | #include <sound/initval.h> | 32 | #include <sound/initval.h> |
30 | 33 | ||
34 | #define DPCM_MAX_BE_USERS 8 | ||
35 | |||
36 | /* DPCM stream event, send event to FE and all active BEs. */ | ||
37 | static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, | ||
38 | int event) | ||
39 | { | ||
40 | struct snd_soc_dpcm *dpcm; | ||
41 | |||
42 | list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) { | ||
43 | |||
44 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
45 | |||
46 | dev_dbg(be->dev, "pm: BE %s event %d dir %d\n", | ||
47 | be->dai_link->name, event, dir); | ||
48 | |||
49 | snd_soc_dapm_stream_event(be, dir, event); | ||
50 | } | ||
51 | |||
52 | snd_soc_dapm_stream_event(fe, dir, event); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
31 | static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, | 57 | static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, |
32 | struct snd_soc_dai *soc_dai) | 58 | struct snd_soc_dai *soc_dai) |
33 | { | 59 | { |
@@ -156,6 +182,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
156 | } | 182 | } |
157 | } | 183 | } |
158 | 184 | ||
185 | /* Dynamic PCM DAI links compat checks use dynamic capabilities */ | ||
186 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) | ||
187 | goto dynamic; | ||
188 | |||
159 | /* Check that the codec and cpu DAIs are compatible */ | 189 | /* Check that the codec and cpu DAIs are compatible */ |
160 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 190 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
161 | runtime->hw.rate_min = | 191 | runtime->hw.rate_min = |
@@ -248,6 +278,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
248 | pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, | 278 | pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, |
249 | runtime->hw.rate_max); | 279 | runtime->hw.rate_max); |
250 | 280 | ||
281 | dynamic: | ||
251 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 282 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
252 | cpu_dai->playback_active++; | 283 | cpu_dai->playback_active++; |
253 | codec_dai->playback_active++; | 284 | codec_dai->playback_active++; |
@@ -308,7 +339,7 @@ static void close_delayed_work(struct work_struct *work) | |||
308 | if (codec_dai->pop_wait == 1) { | 339 | if (codec_dai->pop_wait == 1) { |
309 | codec_dai->pop_wait = 0; | 340 | codec_dai->pop_wait = 0; |
310 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, | 341 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, |
311 | codec_dai, SND_SOC_DAPM_STREAM_STOP); | 342 | SND_SOC_DAPM_STREAM_STOP); |
312 | } | 343 | } |
313 | 344 | ||
314 | mutex_unlock(&rtd->pcm_mutex); | 345 | mutex_unlock(&rtd->pcm_mutex); |
@@ -373,7 +404,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
373 | /* powered down playback stream now */ | 404 | /* powered down playback stream now */ |
374 | snd_soc_dapm_stream_event(rtd, | 405 | snd_soc_dapm_stream_event(rtd, |
375 | SNDRV_PCM_STREAM_PLAYBACK, | 406 | SNDRV_PCM_STREAM_PLAYBACK, |
376 | codec_dai, | ||
377 | SND_SOC_DAPM_STREAM_STOP); | 407 | SND_SOC_DAPM_STREAM_STOP); |
378 | } else { | 408 | } else { |
379 | /* start delayed pop wq here for playback streams */ | 409 | /* start delayed pop wq here for playback streams */ |
@@ -384,7 +414,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
384 | } else { | 414 | } else { |
385 | /* capture streams can be powered down now */ | 415 | /* capture streams can be powered down now */ |
386 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, | 416 | snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, |
387 | codec_dai, SND_SOC_DAPM_STREAM_STOP); | 417 | SND_SOC_DAPM_STREAM_STOP); |
388 | } | 418 | } |
389 | 419 | ||
390 | mutex_unlock(&rtd->pcm_mutex); | 420 | mutex_unlock(&rtd->pcm_mutex); |
@@ -453,8 +483,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
453 | cancel_delayed_work(&rtd->delayed_work); | 483 | cancel_delayed_work(&rtd->delayed_work); |
454 | } | 484 | } |
455 | 485 | ||
456 | snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai, | 486 | snd_soc_dapm_stream_event(rtd, substream->stream, |
457 | SND_SOC_DAPM_STREAM_START); | 487 | SND_SOC_DAPM_STREAM_START); |
458 | 488 | ||
459 | snd_soc_dai_digital_mute(codec_dai, 0); | 489 | snd_soc_dai_digital_mute(codec_dai, 0); |
460 | 490 | ||
@@ -602,6 +632,34 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
602 | return 0; | 632 | return 0; |
603 | } | 633 | } |
604 | 634 | ||
635 | static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, | ||
636 | int cmd) | ||
637 | { | ||
638 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
639 | struct snd_soc_platform *platform = rtd->platform; | ||
640 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
641 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
642 | int ret; | ||
643 | |||
644 | if (codec_dai->driver->ops->bespoke_trigger) { | ||
645 | ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); | ||
646 | if (ret < 0) | ||
647 | return ret; | ||
648 | } | ||
649 | |||
650 | if (platform->driver->bespoke_trigger) { | ||
651 | ret = platform->driver->bespoke_trigger(substream, cmd); | ||
652 | if (ret < 0) | ||
653 | return ret; | ||
654 | } | ||
655 | |||
656 | if (cpu_dai->driver->ops->bespoke_trigger) { | ||
657 | ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); | ||
658 | if (ret < 0) | ||
659 | return ret; | ||
660 | } | ||
661 | return 0; | ||
662 | } | ||
605 | /* | 663 | /* |
606 | * soc level wrapper for pointer callback | 664 | * soc level wrapper for pointer callback |
607 | * If cpu_dai, codec_dai, platform driver has the delay callback, than | 665 | * If cpu_dai, codec_dai, platform driver has the delay callback, than |
@@ -634,6 +692,1308 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | |||
634 | return offset; | 692 | return offset; |
635 | } | 693 | } |
636 | 694 | ||
695 | /* connect a FE and BE */ | ||
696 | static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, | ||
697 | struct snd_soc_pcm_runtime *be, int stream) | ||
698 | { | ||
699 | struct snd_soc_dpcm *dpcm; | ||
700 | |||
701 | /* only add new dpcms */ | ||
702 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
703 | if (dpcm->be == be && dpcm->fe == fe) | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL); | ||
708 | if (!dpcm) | ||
709 | return -ENOMEM; | ||
710 | |||
711 | dpcm->be = be; | ||
712 | dpcm->fe = fe; | ||
713 | be->dpcm[stream].runtime = fe->dpcm[stream].runtime; | ||
714 | dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; | ||
715 | list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); | ||
716 | list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); | ||
717 | |||
718 | dev_dbg(fe->dev, " connected new DPCM %s path %s %s %s\n", | ||
719 | stream ? "capture" : "playback", fe->dai_link->name, | ||
720 | stream ? "<-" : "->", be->dai_link->name); | ||
721 | |||
722 | #ifdef CONFIG_DEBUG_FS | ||
723 | dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644, | ||
724 | fe->debugfs_dpcm_root, &dpcm->state); | ||
725 | #endif | ||
726 | return 1; | ||
727 | } | ||
728 | |||
729 | /* reparent a BE onto another FE */ | ||
730 | static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, | ||
731 | struct snd_soc_pcm_runtime *be, int stream) | ||
732 | { | ||
733 | struct snd_soc_dpcm *dpcm; | ||
734 | struct snd_pcm_substream *fe_substream, *be_substream; | ||
735 | |||
736 | /* reparent if BE is connected to other FEs */ | ||
737 | if (!be->dpcm[stream].users) | ||
738 | return; | ||
739 | |||
740 | be_substream = snd_soc_dpcm_get_substream(be, stream); | ||
741 | |||
742 | list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { | ||
743 | if (dpcm->fe == fe) | ||
744 | continue; | ||
745 | |||
746 | dev_dbg(fe->dev, " reparent %s path %s %s %s\n", | ||
747 | stream ? "capture" : "playback", | ||
748 | dpcm->fe->dai_link->name, | ||
749 | stream ? "<-" : "->", dpcm->be->dai_link->name); | ||
750 | |||
751 | fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream); | ||
752 | be_substream->runtime = fe_substream->runtime; | ||
753 | break; | ||
754 | } | ||
755 | } | ||
756 | |||
757 | /* disconnect a BE and FE */ | ||
758 | static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) | ||
759 | { | ||
760 | struct snd_soc_dpcm *dpcm, *d; | ||
761 | |||
762 | list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { | ||
763 | dev_dbg(fe->dev, "BE %s disconnect check for %s\n", | ||
764 | stream ? "capture" : "playback", | ||
765 | dpcm->be->dai_link->name); | ||
766 | |||
767 | if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE) | ||
768 | continue; | ||
769 | |||
770 | dev_dbg(fe->dev, " freed DSP %s path %s %s %s\n", | ||
771 | stream ? "capture" : "playback", fe->dai_link->name, | ||
772 | stream ? "<-" : "->", dpcm->be->dai_link->name); | ||
773 | |||
774 | /* BEs still alive need new FE */ | ||
775 | dpcm_be_reparent(fe, dpcm->be, stream); | ||
776 | |||
777 | #ifdef CONFIG_DEBUG_FS | ||
778 | debugfs_remove(dpcm->debugfs_state); | ||
779 | #endif | ||
780 | list_del(&dpcm->list_be); | ||
781 | list_del(&dpcm->list_fe); | ||
782 | kfree(dpcm); | ||
783 | } | ||
784 | } | ||
785 | |||
786 | /* get BE for DAI widget and stream */ | ||
787 | static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | ||
788 | struct snd_soc_dapm_widget *widget, int stream) | ||
789 | { | ||
790 | struct snd_soc_pcm_runtime *be; | ||
791 | int i; | ||
792 | |||
793 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
794 | for (i = 0; i < card->num_links; i++) { | ||
795 | be = &card->rtd[i]; | ||
796 | |||
797 | if (be->cpu_dai->playback_widget == widget || | ||
798 | be->codec_dai->playback_widget == widget) | ||
799 | return be; | ||
800 | } | ||
801 | } else { | ||
802 | |||
803 | for (i = 0; i < card->num_links; i++) { | ||
804 | be = &card->rtd[i]; | ||
805 | |||
806 | if (be->cpu_dai->capture_widget == widget || | ||
807 | be->codec_dai->capture_widget == widget) | ||
808 | return be; | ||
809 | } | ||
810 | } | ||
811 | |||
812 | dev_err(card->dev, "can't get %s BE for %s\n", | ||
813 | stream ? "capture" : "playback", widget->name); | ||
814 | return NULL; | ||
815 | } | ||
816 | |||
817 | static inline struct snd_soc_dapm_widget * | ||
818 | rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream) | ||
819 | { | ||
820 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
821 | return rtd->cpu_dai->playback_widget; | ||
822 | else | ||
823 | return rtd->cpu_dai->capture_widget; | ||
824 | } | ||
825 | |||
826 | static inline struct snd_soc_dapm_widget * | ||
827 | rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream) | ||
828 | { | ||
829 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
830 | return rtd->codec_dai->playback_widget; | ||
831 | else | ||
832 | return rtd->codec_dai->capture_widget; | ||
833 | } | ||
834 | |||
835 | static int widget_in_list(struct snd_soc_dapm_widget_list *list, | ||
836 | struct snd_soc_dapm_widget *widget) | ||
837 | { | ||
838 | int i; | ||
839 | |||
840 | for (i = 0; i < list->num_widgets; i++) { | ||
841 | if (widget == list->widgets[i]) | ||
842 | return 1; | ||
843 | } | ||
844 | |||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | static int dpcm_path_get(struct snd_soc_pcm_runtime *fe, | ||
849 | int stream, struct snd_soc_dapm_widget_list **list_) | ||
850 | { | ||
851 | struct snd_soc_dai *cpu_dai = fe->cpu_dai; | ||
852 | struct snd_soc_dapm_widget_list *list; | ||
853 | int paths; | ||
854 | |||
855 | list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) + | ||
856 | sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL); | ||
857 | if (list == NULL) | ||
858 | return -ENOMEM; | ||
859 | |||
860 | /* get number of valid DAI paths and their widgets */ | ||
861 | paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list); | ||
862 | |||
863 | dev_dbg(fe->dev, "found %d audio %s paths\n", paths, | ||
864 | stream ? "capture" : "playback"); | ||
865 | |||
866 | *list_ = list; | ||
867 | return paths; | ||
868 | } | ||
869 | |||
870 | static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list) | ||
871 | { | ||
872 | kfree(*list); | ||
873 | } | ||
874 | |||
875 | static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, | ||
876 | struct snd_soc_dapm_widget_list **list_) | ||
877 | { | ||
878 | struct snd_soc_dpcm *dpcm; | ||
879 | struct snd_soc_dapm_widget_list *list = *list_; | ||
880 | struct snd_soc_dapm_widget *widget; | ||
881 | int prune = 0; | ||
882 | |||
883 | /* Destroy any old FE <--> BE connections */ | ||
884 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
885 | |||
886 | /* is there a valid CPU DAI widget for this BE */ | ||
887 | widget = rtd_get_cpu_widget(dpcm->be, stream); | ||
888 | |||
889 | /* prune the BE if it's no longer in our active list */ | ||
890 | if (widget && widget_in_list(list, widget)) | ||
891 | continue; | ||
892 | |||
893 | /* is there a valid CODEC DAI widget for this BE */ | ||
894 | widget = rtd_get_codec_widget(dpcm->be, stream); | ||
895 | |||
896 | /* prune the BE if it's no longer in our active list */ | ||
897 | if (widget && widget_in_list(list, widget)) | ||
898 | continue; | ||
899 | |||
900 | dev_dbg(fe->dev, "pruning %s BE %s for %s\n", | ||
901 | stream ? "capture" : "playback", | ||
902 | dpcm->be->dai_link->name, fe->dai_link->name); | ||
903 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | ||
904 | dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | ||
905 | prune++; | ||
906 | } | ||
907 | |||
908 | dev_dbg(fe->dev, "found %d old BE paths for pruning\n", prune); | ||
909 | return prune; | ||
910 | } | ||
911 | |||
912 | static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, | ||
913 | struct snd_soc_dapm_widget_list **list_) | ||
914 | { | ||
915 | struct snd_soc_card *card = fe->card; | ||
916 | struct snd_soc_dapm_widget_list *list = *list_; | ||
917 | struct snd_soc_pcm_runtime *be; | ||
918 | int i, new = 0, err; | ||
919 | |||
920 | /* Create any new FE <--> BE connections */ | ||
921 | for (i = 0; i < list->num_widgets; i++) { | ||
922 | |||
923 | if (list->widgets[i]->id != snd_soc_dapm_dai) | ||
924 | continue; | ||
925 | |||
926 | /* is there a valid BE rtd for this widget */ | ||
927 | be = dpcm_get_be(card, list->widgets[i], stream); | ||
928 | if (!be) { | ||
929 | dev_err(fe->dev, "no BE found for %s\n", | ||
930 | list->widgets[i]->name); | ||
931 | continue; | ||
932 | } | ||
933 | |||
934 | /* make sure BE is a real BE */ | ||
935 | if (!be->dai_link->no_pcm) | ||
936 | continue; | ||
937 | |||
938 | /* don't connect if FE is not running */ | ||
939 | if (!fe->dpcm[stream].runtime) | ||
940 | continue; | ||
941 | |||
942 | /* newly connected FE and BE */ | ||
943 | err = dpcm_be_connect(fe, be, stream); | ||
944 | if (err < 0) { | ||
945 | dev_err(fe->dev, "can't connect %s\n", | ||
946 | list->widgets[i]->name); | ||
947 | break; | ||
948 | } else if (err == 0) /* already connected */ | ||
949 | continue; | ||
950 | |||
951 | /* new */ | ||
952 | be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | ||
953 | new++; | ||
954 | } | ||
955 | |||
956 | dev_dbg(fe->dev, "found %d new BE paths\n", new); | ||
957 | return new; | ||
958 | } | ||
959 | |||
960 | /* | ||
961 | * Find the corresponding BE DAIs that source or sink audio to this | ||
962 | * FE substream. | ||
963 | */ | ||
964 | static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, | ||
965 | int stream, struct snd_soc_dapm_widget_list **list, int new) | ||
966 | { | ||
967 | if (new) | ||
968 | return dpcm_add_paths(fe, stream, list); | ||
969 | else | ||
970 | return dpcm_prune_paths(fe, stream, list); | ||
971 | } | ||
972 | |||
973 | static void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) | ||
974 | { | ||
975 | struct snd_soc_dpcm *dpcm; | ||
976 | |||
977 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) | ||
978 | dpcm->be->dpcm[stream].runtime_update = | ||
979 | SND_SOC_DPCM_UPDATE_NO; | ||
980 | } | ||
981 | |||
982 | static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, | ||
983 | int stream) | ||
984 | { | ||
985 | struct snd_soc_dpcm *dpcm; | ||
986 | |||
987 | /* disable any enabled and non active backends */ | ||
988 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
989 | |||
990 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
991 | struct snd_pcm_substream *be_substream = | ||
992 | snd_soc_dpcm_get_substream(be, stream); | ||
993 | |||
994 | if (be->dpcm[stream].users == 0) | ||
995 | dev_err(be->dev, "no users %s at close - state %d\n", | ||
996 | stream ? "capture" : "playback", | ||
997 | be->dpcm[stream].state); | ||
998 | |||
999 | if (--be->dpcm[stream].users != 0) | ||
1000 | continue; | ||
1001 | |||
1002 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) | ||
1003 | continue; | ||
1004 | |||
1005 | soc_pcm_close(be_substream); | ||
1006 | be_substream->runtime = NULL; | ||
1007 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) | ||
1012 | { | ||
1013 | struct snd_soc_dpcm *dpcm; | ||
1014 | int err, count = 0; | ||
1015 | |||
1016 | /* only startup BE DAIs that are either sinks or sources to this FE DAI */ | ||
1017 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1018 | |||
1019 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1020 | struct snd_pcm_substream *be_substream = | ||
1021 | snd_soc_dpcm_get_substream(be, stream); | ||
1022 | |||
1023 | /* is this op for this BE ? */ | ||
1024 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | ||
1025 | continue; | ||
1026 | |||
1027 | /* first time the dpcm is open ? */ | ||
1028 | if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) | ||
1029 | dev_err(be->dev, "too many users %s at open %d\n", | ||
1030 | stream ? "capture" : "playback", | ||
1031 | be->dpcm[stream].state); | ||
1032 | |||
1033 | if (be->dpcm[stream].users++ != 0) | ||
1034 | continue; | ||
1035 | |||
1036 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && | ||
1037 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) | ||
1038 | continue; | ||
1039 | |||
1040 | dev_dbg(be->dev, "dpcm: open BE %s\n", be->dai_link->name); | ||
1041 | |||
1042 | be_substream->runtime = be->dpcm[stream].runtime; | ||
1043 | err = soc_pcm_open(be_substream); | ||
1044 | if (err < 0) { | ||
1045 | dev_err(be->dev, "BE open failed %d\n", err); | ||
1046 | be->dpcm[stream].users--; | ||
1047 | if (be->dpcm[stream].users < 0) | ||
1048 | dev_err(be->dev, "no users %s at unwind %d\n", | ||
1049 | stream ? "capture" : "playback", | ||
1050 | be->dpcm[stream].state); | ||
1051 | |||
1052 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | ||
1053 | goto unwind; | ||
1054 | } | ||
1055 | |||
1056 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; | ||
1057 | count++; | ||
1058 | } | ||
1059 | |||
1060 | return count; | ||
1061 | |||
1062 | unwind: | ||
1063 | /* disable any enabled and non active backends */ | ||
1064 | list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1065 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1066 | struct snd_pcm_substream *be_substream = | ||
1067 | snd_soc_dpcm_get_substream(be, stream); | ||
1068 | |||
1069 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | ||
1070 | continue; | ||
1071 | |||
1072 | if (be->dpcm[stream].users == 0) | ||
1073 | dev_err(be->dev, "no users %s at close %d\n", | ||
1074 | stream ? "capture" : "playback", | ||
1075 | be->dpcm[stream].state); | ||
1076 | |||
1077 | if (--be->dpcm[stream].users != 0) | ||
1078 | continue; | ||
1079 | |||
1080 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) | ||
1081 | continue; | ||
1082 | |||
1083 | soc_pcm_close(be_substream); | ||
1084 | be_substream->runtime = NULL; | ||
1085 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | ||
1086 | } | ||
1087 | |||
1088 | return err; | ||
1089 | } | ||
1090 | |||
1091 | static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) | ||
1092 | { | ||
1093 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1094 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1095 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
1096 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | ||
1097 | |||
1098 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1099 | runtime->hw.rate_min = cpu_dai_drv->playback.rate_min; | ||
1100 | runtime->hw.rate_max = cpu_dai_drv->playback.rate_max; | ||
1101 | runtime->hw.channels_min = cpu_dai_drv->playback.channels_min; | ||
1102 | runtime->hw.channels_max = cpu_dai_drv->playback.channels_max; | ||
1103 | runtime->hw.formats &= cpu_dai_drv->playback.formats; | ||
1104 | runtime->hw.rates = cpu_dai_drv->playback.rates; | ||
1105 | } else { | ||
1106 | runtime->hw.rate_min = cpu_dai_drv->capture.rate_min; | ||
1107 | runtime->hw.rate_max = cpu_dai_drv->capture.rate_max; | ||
1108 | runtime->hw.channels_min = cpu_dai_drv->capture.channels_min; | ||
1109 | runtime->hw.channels_max = cpu_dai_drv->capture.channels_max; | ||
1110 | runtime->hw.formats &= cpu_dai_drv->capture.formats; | ||
1111 | runtime->hw.rates = cpu_dai_drv->capture.rates; | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) | ||
1116 | { | ||
1117 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; | ||
1118 | struct snd_pcm_runtime *runtime = fe_substream->runtime; | ||
1119 | int stream = fe_substream->stream, ret = 0; | ||
1120 | |||
1121 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | ||
1122 | |||
1123 | ret = dpcm_be_dai_startup(fe, fe_substream->stream); | ||
1124 | if (ret < 0) { | ||
1125 | dev_err(fe->dev,"dpcm: failed to start some BEs %d\n", ret); | ||
1126 | goto be_err; | ||
1127 | } | ||
1128 | |||
1129 | dev_dbg(fe->dev, "dpcm: open FE %s\n", fe->dai_link->name); | ||
1130 | |||
1131 | /* start the DAI frontend */ | ||
1132 | ret = soc_pcm_open(fe_substream); | ||
1133 | if (ret < 0) { | ||
1134 | dev_err(fe->dev,"dpcm: failed to start FE %d\n", ret); | ||
1135 | goto unwind; | ||
1136 | } | ||
1137 | |||
1138 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; | ||
1139 | |||
1140 | dpcm_set_fe_runtime(fe_substream); | ||
1141 | snd_pcm_limit_hw_rates(runtime); | ||
1142 | |||
1143 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | ||
1144 | return 0; | ||
1145 | |||
1146 | unwind: | ||
1147 | dpcm_be_dai_startup_unwind(fe, fe_substream->stream); | ||
1148 | be_err: | ||
1149 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | ||
1150 | return ret; | ||
1151 | } | ||
1152 | |||
1153 | static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) | ||
1154 | { | ||
1155 | struct snd_soc_dpcm *dpcm; | ||
1156 | |||
1157 | /* only shutdown BEs that are either sinks or sources to this FE DAI */ | ||
1158 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1159 | |||
1160 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1161 | struct snd_pcm_substream *be_substream = | ||
1162 | snd_soc_dpcm_get_substream(be, stream); | ||
1163 | |||
1164 | /* is this op for this BE ? */ | ||
1165 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | ||
1166 | continue; | ||
1167 | |||
1168 | if (be->dpcm[stream].users == 0) | ||
1169 | dev_err(be->dev, "no users %s at close - state %d\n", | ||
1170 | stream ? "capture" : "playback", | ||
1171 | be->dpcm[stream].state); | ||
1172 | |||
1173 | if (--be->dpcm[stream].users != 0) | ||
1174 | continue; | ||
1175 | |||
1176 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | ||
1177 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) | ||
1178 | continue; | ||
1179 | |||
1180 | dev_dbg(be->dev, "dpcm: close BE %s\n", | ||
1181 | dpcm->fe->dai_link->name); | ||
1182 | |||
1183 | soc_pcm_close(be_substream); | ||
1184 | be_substream->runtime = NULL; | ||
1185 | |||
1186 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | ||
1187 | } | ||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) | ||
1192 | { | ||
1193 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
1194 | int stream = substream->stream; | ||
1195 | |||
1196 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | ||
1197 | |||
1198 | /* shutdown the BEs */ | ||
1199 | dpcm_be_dai_shutdown(fe, substream->stream); | ||
1200 | |||
1201 | dev_dbg(fe->dev, "dpcm: close FE %s\n", fe->dai_link->name); | ||
1202 | |||
1203 | /* now shutdown the frontend */ | ||
1204 | soc_pcm_close(substream); | ||
1205 | |||
1206 | /* run the stream event for each BE */ | ||
1207 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); | ||
1208 | |||
1209 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | ||
1210 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | ||
1211 | return 0; | ||
1212 | } | ||
1213 | |||
1214 | static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) | ||
1215 | { | ||
1216 | struct snd_soc_dpcm *dpcm; | ||
1217 | |||
1218 | /* only hw_params backends that are either sinks or sources | ||
1219 | * to this frontend DAI */ | ||
1220 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1221 | |||
1222 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1223 | struct snd_pcm_substream *be_substream = | ||
1224 | snd_soc_dpcm_get_substream(be, stream); | ||
1225 | |||
1226 | /* is this op for this BE ? */ | ||
1227 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | ||
1228 | continue; | ||
1229 | |||
1230 | /* only free hw when no longer used - check all FEs */ | ||
1231 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | ||
1232 | continue; | ||
1233 | |||
1234 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | ||
1235 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && | ||
1236 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | ||
1237 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) | ||
1238 | continue; | ||
1239 | |||
1240 | dev_dbg(be->dev, "dpcm: hw_free BE %s\n", | ||
1241 | dpcm->fe->dai_link->name); | ||
1242 | |||
1243 | soc_pcm_hw_free(be_substream); | ||
1244 | |||
1245 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; | ||
1246 | } | ||
1247 | |||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) | ||
1252 | { | ||
1253 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
1254 | int err, stream = substream->stream; | ||
1255 | |||
1256 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | ||
1257 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | ||
1258 | |||
1259 | dev_dbg(fe->dev, "dpcm: hw_free FE %s\n", fe->dai_link->name); | ||
1260 | |||
1261 | /* call hw_free on the frontend */ | ||
1262 | err = soc_pcm_hw_free(substream); | ||
1263 | if (err < 0) | ||
1264 | dev_err(fe->dev,"dpcm: hw_free FE %s failed\n", | ||
1265 | fe->dai_link->name); | ||
1266 | |||
1267 | /* only hw_params backends that are either sinks or sources | ||
1268 | * to this frontend DAI */ | ||
1269 | err = dpcm_be_dai_hw_free(fe, stream); | ||
1270 | |||
1271 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; | ||
1272 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | ||
1273 | |||
1274 | mutex_unlock(&fe->card->mutex); | ||
1275 | return 0; | ||
1276 | } | ||
1277 | |||
1278 | static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) | ||
1279 | { | ||
1280 | struct snd_soc_dpcm *dpcm; | ||
1281 | int ret; | ||
1282 | |||
1283 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1284 | |||
1285 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1286 | struct snd_pcm_substream *be_substream = | ||
1287 | snd_soc_dpcm_get_substream(be, stream); | ||
1288 | |||
1289 | /* is this op for this BE ? */ | ||
1290 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | ||
1291 | continue; | ||
1292 | |||
1293 | /* only allow hw_params() if no connected FEs are running */ | ||
1294 | if (!snd_soc_dpcm_can_be_params(fe, be, stream)) | ||
1295 | continue; | ||
1296 | |||
1297 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && | ||
1298 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | ||
1299 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE)) | ||
1300 | continue; | ||
1301 | |||
1302 | dev_dbg(be->dev, "dpcm: hw_params BE %s\n", | ||
1303 | dpcm->fe->dai_link->name); | ||
1304 | |||
1305 | /* copy params for each dpcm */ | ||
1306 | memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params, | ||
1307 | sizeof(struct snd_pcm_hw_params)); | ||
1308 | |||
1309 | /* perform any hw_params fixups */ | ||
1310 | if (be->dai_link->be_hw_params_fixup) { | ||
1311 | ret = be->dai_link->be_hw_params_fixup(be, | ||
1312 | &dpcm->hw_params); | ||
1313 | if (ret < 0) { | ||
1314 | dev_err(be->dev, | ||
1315 | "dpcm: hw_params BE fixup failed %d\n", | ||
1316 | ret); | ||
1317 | goto unwind; | ||
1318 | } | ||
1319 | } | ||
1320 | |||
1321 | ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params); | ||
1322 | if (ret < 0) { | ||
1323 | dev_err(dpcm->be->dev, | ||
1324 | "dpcm: hw_params BE failed %d\n", ret); | ||
1325 | goto unwind; | ||
1326 | } | ||
1327 | |||
1328 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; | ||
1329 | } | ||
1330 | return 0; | ||
1331 | |||
1332 | unwind: | ||
1333 | /* disable any enabled and non active backends */ | ||
1334 | list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1335 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1336 | struct snd_pcm_substream *be_substream = | ||
1337 | snd_soc_dpcm_get_substream(be, stream); | ||
1338 | |||
1339 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | ||
1340 | continue; | ||
1341 | |||
1342 | /* only allow hw_free() if no connected FEs are running */ | ||
1343 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | ||
1344 | continue; | ||
1345 | |||
1346 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) && | ||
1347 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | ||
1348 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | ||
1349 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) | ||
1350 | continue; | ||
1351 | |||
1352 | soc_pcm_hw_free(be_substream); | ||
1353 | } | ||
1354 | |||
1355 | return ret; | ||
1356 | } | ||
1357 | |||
1358 | static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, | ||
1359 | struct snd_pcm_hw_params *params) | ||
1360 | { | ||
1361 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
1362 | int ret, stream = substream->stream; | ||
1363 | |||
1364 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | ||
1365 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | ||
1366 | |||
1367 | memcpy(&fe->dpcm[substream->stream].hw_params, params, | ||
1368 | sizeof(struct snd_pcm_hw_params)); | ||
1369 | ret = dpcm_be_dai_hw_params(fe, substream->stream); | ||
1370 | if (ret < 0) { | ||
1371 | dev_err(fe->dev,"dpcm: hw_params BE failed %d\n", ret); | ||
1372 | goto out; | ||
1373 | } | ||
1374 | |||
1375 | dev_dbg(fe->dev, "dpcm: hw_params FE %s rate %d chan %x fmt %d\n", | ||
1376 | fe->dai_link->name, params_rate(params), | ||
1377 | params_channels(params), params_format(params)); | ||
1378 | |||
1379 | /* call hw_params on the frontend */ | ||
1380 | ret = soc_pcm_hw_params(substream, params); | ||
1381 | if (ret < 0) { | ||
1382 | dev_err(fe->dev,"dpcm: hw_params FE failed %d\n", ret); | ||
1383 | dpcm_be_dai_hw_free(fe, stream); | ||
1384 | } else | ||
1385 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; | ||
1386 | |||
1387 | out: | ||
1388 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | ||
1389 | mutex_unlock(&fe->card->mutex); | ||
1390 | return ret; | ||
1391 | } | ||
1392 | |||
1393 | static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm, | ||
1394 | struct snd_pcm_substream *substream, int cmd) | ||
1395 | { | ||
1396 | int ret; | ||
1397 | |||
1398 | dev_dbg(dpcm->be->dev, "dpcm: trigger BE %s cmd %d\n", | ||
1399 | dpcm->fe->dai_link->name, cmd); | ||
1400 | |||
1401 | ret = soc_pcm_trigger(substream, cmd); | ||
1402 | if (ret < 0) | ||
1403 | dev_err(dpcm->be->dev,"dpcm: trigger BE failed %d\n", ret); | ||
1404 | |||
1405 | return ret; | ||
1406 | } | ||
1407 | |||
1408 | static int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, | ||
1409 | int cmd) | ||
1410 | { | ||
1411 | struct snd_soc_dpcm *dpcm; | ||
1412 | int ret = 0; | ||
1413 | |||
1414 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1415 | |||
1416 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1417 | struct snd_pcm_substream *be_substream = | ||
1418 | snd_soc_dpcm_get_substream(be, stream); | ||
1419 | |||
1420 | /* is this op for this BE ? */ | ||
1421 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | ||
1422 | continue; | ||
1423 | |||
1424 | switch (cmd) { | ||
1425 | case SNDRV_PCM_TRIGGER_START: | ||
1426 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && | ||
1427 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) | ||
1428 | continue; | ||
1429 | |||
1430 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | ||
1431 | if (ret) | ||
1432 | return ret; | ||
1433 | |||
1434 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; | ||
1435 | break; | ||
1436 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1437 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) | ||
1438 | continue; | ||
1439 | |||
1440 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | ||
1441 | if (ret) | ||
1442 | return ret; | ||
1443 | |||
1444 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; | ||
1445 | break; | ||
1446 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1447 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) | ||
1448 | continue; | ||
1449 | |||
1450 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | ||
1451 | if (ret) | ||
1452 | return ret; | ||
1453 | |||
1454 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; | ||
1455 | break; | ||
1456 | case SNDRV_PCM_TRIGGER_STOP: | ||
1457 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) | ||
1458 | continue; | ||
1459 | |||
1460 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | ||
1461 | continue; | ||
1462 | |||
1463 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | ||
1464 | if (ret) | ||
1465 | return ret; | ||
1466 | |||
1467 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; | ||
1468 | break; | ||
1469 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1470 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) | ||
1471 | continue; | ||
1472 | |||
1473 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | ||
1474 | continue; | ||
1475 | |||
1476 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | ||
1477 | if (ret) | ||
1478 | return ret; | ||
1479 | |||
1480 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND; | ||
1481 | break; | ||
1482 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1483 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) | ||
1484 | continue; | ||
1485 | |||
1486 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | ||
1487 | continue; | ||
1488 | |||
1489 | ret = dpcm_do_trigger(dpcm, be_substream, cmd); | ||
1490 | if (ret) | ||
1491 | return ret; | ||
1492 | |||
1493 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; | ||
1494 | break; | ||
1495 | } | ||
1496 | } | ||
1497 | |||
1498 | return ret; | ||
1499 | } | ||
1500 | EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); | ||
1501 | |||
1502 | static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) | ||
1503 | { | ||
1504 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
1505 | int stream = substream->stream, ret; | ||
1506 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; | ||
1507 | |||
1508 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | ||
1509 | |||
1510 | switch (trigger) { | ||
1511 | case SND_SOC_DPCM_TRIGGER_PRE: | ||
1512 | /* call trigger on the frontend before the backend. */ | ||
1513 | |||
1514 | dev_dbg(fe->dev, "dpcm: pre trigger FE %s cmd %d\n", | ||
1515 | fe->dai_link->name, cmd); | ||
1516 | |||
1517 | ret = soc_pcm_trigger(substream, cmd); | ||
1518 | if (ret < 0) { | ||
1519 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); | ||
1520 | goto out; | ||
1521 | } | ||
1522 | |||
1523 | ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); | ||
1524 | break; | ||
1525 | case SND_SOC_DPCM_TRIGGER_POST: | ||
1526 | /* call trigger on the frontend after the backend. */ | ||
1527 | |||
1528 | ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); | ||
1529 | if (ret < 0) { | ||
1530 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); | ||
1531 | goto out; | ||
1532 | } | ||
1533 | |||
1534 | dev_dbg(fe->dev, "dpcm: post trigger FE %s cmd %d\n", | ||
1535 | fe->dai_link->name, cmd); | ||
1536 | |||
1537 | ret = soc_pcm_trigger(substream, cmd); | ||
1538 | break; | ||
1539 | case SND_SOC_DPCM_TRIGGER_BESPOKE: | ||
1540 | /* bespoke trigger() - handles both FE and BEs */ | ||
1541 | |||
1542 | dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n", | ||
1543 | fe->dai_link->name, cmd); | ||
1544 | |||
1545 | ret = soc_pcm_bespoke_trigger(substream, cmd); | ||
1546 | if (ret < 0) { | ||
1547 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); | ||
1548 | goto out; | ||
1549 | } | ||
1550 | break; | ||
1551 | default: | ||
1552 | dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd, | ||
1553 | fe->dai_link->name); | ||
1554 | ret = -EINVAL; | ||
1555 | goto out; | ||
1556 | } | ||
1557 | |||
1558 | switch (cmd) { | ||
1559 | case SNDRV_PCM_TRIGGER_START: | ||
1560 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1561 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1562 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START; | ||
1563 | break; | ||
1564 | case SNDRV_PCM_TRIGGER_STOP: | ||
1565 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1566 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1567 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; | ||
1568 | break; | ||
1569 | } | ||
1570 | |||
1571 | out: | ||
1572 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | ||
1573 | return ret; | ||
1574 | } | ||
1575 | |||
1576 | static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) | ||
1577 | { | ||
1578 | struct snd_soc_dpcm *dpcm; | ||
1579 | int ret = 0; | ||
1580 | |||
1581 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1582 | |||
1583 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1584 | struct snd_pcm_substream *be_substream = | ||
1585 | snd_soc_dpcm_get_substream(be, stream); | ||
1586 | |||
1587 | /* is this op for this BE ? */ | ||
1588 | if (!snd_soc_dpcm_be_can_update(fe, be, stream)) | ||
1589 | continue; | ||
1590 | |||
1591 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | ||
1592 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) | ||
1593 | continue; | ||
1594 | |||
1595 | dev_dbg(be->dev, "dpcm: prepare BE %s\n", | ||
1596 | dpcm->fe->dai_link->name); | ||
1597 | |||
1598 | ret = soc_pcm_prepare(be_substream); | ||
1599 | if (ret < 0) { | ||
1600 | dev_err(be->dev, "dpcm: backend prepare failed %d\n", | ||
1601 | ret); | ||
1602 | break; | ||
1603 | } | ||
1604 | |||
1605 | be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; | ||
1606 | } | ||
1607 | return ret; | ||
1608 | } | ||
1609 | |||
1610 | static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) | ||
1611 | { | ||
1612 | struct snd_soc_pcm_runtime *fe = substream->private_data; | ||
1613 | int stream = substream->stream, ret = 0; | ||
1614 | |||
1615 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | ||
1616 | |||
1617 | dev_dbg(fe->dev, "dpcm: prepare FE %s\n", fe->dai_link->name); | ||
1618 | |||
1619 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | ||
1620 | |||
1621 | /* there is no point preparing this FE if there are no BEs */ | ||
1622 | if (list_empty(&fe->dpcm[stream].be_clients)) { | ||
1623 | dev_err(fe->dev, "dpcm: no backend DAIs enabled for %s\n", | ||
1624 | fe->dai_link->name); | ||
1625 | ret = -EINVAL; | ||
1626 | goto out; | ||
1627 | } | ||
1628 | |||
1629 | ret = dpcm_be_dai_prepare(fe, substream->stream); | ||
1630 | if (ret < 0) | ||
1631 | goto out; | ||
1632 | |||
1633 | /* call prepare on the frontend */ | ||
1634 | ret = soc_pcm_prepare(substream); | ||
1635 | if (ret < 0) { | ||
1636 | dev_err(fe->dev,"dpcm: prepare FE %s failed\n", | ||
1637 | fe->dai_link->name); | ||
1638 | goto out; | ||
1639 | } | ||
1640 | |||
1641 | /* run the stream event for each BE */ | ||
1642 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); | ||
1643 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; | ||
1644 | |||
1645 | out: | ||
1646 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | ||
1647 | mutex_unlock(&fe->card->mutex); | ||
1648 | |||
1649 | return ret; | ||
1650 | } | ||
1651 | |||
1652 | static int soc_pcm_ioctl(struct snd_pcm_substream *substream, | ||
1653 | unsigned int cmd, void *arg) | ||
1654 | { | ||
1655 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1656 | struct snd_soc_platform *platform = rtd->platform; | ||
1657 | |||
1658 | if (platform->driver->ops->ioctl) | ||
1659 | return platform->driver->ops->ioctl(substream, cmd, arg); | ||
1660 | return snd_pcm_lib_ioctl(substream, cmd, arg); | ||
1661 | } | ||
1662 | |||
1663 | static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) | ||
1664 | { | ||
1665 | struct snd_pcm_substream *substream = | ||
1666 | snd_soc_dpcm_get_substream(fe, stream); | ||
1667 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; | ||
1668 | int err; | ||
1669 | |||
1670 | dev_dbg(fe->dev, "runtime %s close on FE %s\n", | ||
1671 | stream ? "capture" : "playback", fe->dai_link->name); | ||
1672 | |||
1673 | if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { | ||
1674 | /* call bespoke trigger - FE takes care of all BE triggers */ | ||
1675 | dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n", | ||
1676 | fe->dai_link->name); | ||
1677 | |||
1678 | err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); | ||
1679 | if (err < 0) | ||
1680 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); | ||
1681 | } else { | ||
1682 | dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n", | ||
1683 | fe->dai_link->name); | ||
1684 | |||
1685 | err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); | ||
1686 | if (err < 0) | ||
1687 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); | ||
1688 | } | ||
1689 | |||
1690 | err = dpcm_be_dai_hw_free(fe, stream); | ||
1691 | if (err < 0) | ||
1692 | dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err); | ||
1693 | |||
1694 | err = dpcm_be_dai_shutdown(fe, stream); | ||
1695 | if (err < 0) | ||
1696 | dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err); | ||
1697 | |||
1698 | /* run the stream event for each BE */ | ||
1699 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); | ||
1700 | |||
1701 | return 0; | ||
1702 | } | ||
1703 | |||
1704 | static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) | ||
1705 | { | ||
1706 | struct snd_pcm_substream *substream = | ||
1707 | snd_soc_dpcm_get_substream(fe, stream); | ||
1708 | struct snd_soc_dpcm *dpcm; | ||
1709 | enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; | ||
1710 | int ret; | ||
1711 | |||
1712 | dev_dbg(fe->dev, "runtime %s open on FE %s\n", | ||
1713 | stream ? "capture" : "playback", fe->dai_link->name); | ||
1714 | |||
1715 | /* Only start the BE if the FE is ready */ | ||
1716 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE || | ||
1717 | fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) | ||
1718 | return -EINVAL; | ||
1719 | |||
1720 | /* startup must always be called for new BEs */ | ||
1721 | ret = dpcm_be_dai_startup(fe, stream); | ||
1722 | if (ret < 0) { | ||
1723 | goto disconnect; | ||
1724 | return ret; | ||
1725 | } | ||
1726 | |||
1727 | /* keep going if FE state is > open */ | ||
1728 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN) | ||
1729 | return 0; | ||
1730 | |||
1731 | ret = dpcm_be_dai_hw_params(fe, stream); | ||
1732 | if (ret < 0) { | ||
1733 | goto close; | ||
1734 | return ret; | ||
1735 | } | ||
1736 | |||
1737 | /* keep going if FE state is > hw_params */ | ||
1738 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS) | ||
1739 | return 0; | ||
1740 | |||
1741 | |||
1742 | ret = dpcm_be_dai_prepare(fe, stream); | ||
1743 | if (ret < 0) { | ||
1744 | goto hw_free; | ||
1745 | return ret; | ||
1746 | } | ||
1747 | |||
1748 | /* run the stream event for each BE */ | ||
1749 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); | ||
1750 | |||
1751 | /* keep going if FE state is > prepare */ | ||
1752 | if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE || | ||
1753 | fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP) | ||
1754 | return 0; | ||
1755 | |||
1756 | if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { | ||
1757 | /* call trigger on the frontend - FE takes care of all BE triggers */ | ||
1758 | dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n", | ||
1759 | fe->dai_link->name); | ||
1760 | |||
1761 | ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); | ||
1762 | if (ret < 0) { | ||
1763 | dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret); | ||
1764 | goto hw_free; | ||
1765 | } | ||
1766 | } else { | ||
1767 | dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n", | ||
1768 | fe->dai_link->name); | ||
1769 | |||
1770 | ret = dpcm_be_dai_trigger(fe, stream, | ||
1771 | SNDRV_PCM_TRIGGER_START); | ||
1772 | if (ret < 0) { | ||
1773 | dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); | ||
1774 | goto hw_free; | ||
1775 | } | ||
1776 | } | ||
1777 | |||
1778 | return 0; | ||
1779 | |||
1780 | hw_free: | ||
1781 | dpcm_be_dai_hw_free(fe, stream); | ||
1782 | close: | ||
1783 | dpcm_be_dai_shutdown(fe, stream); | ||
1784 | disconnect: | ||
1785 | /* disconnect any non started BEs */ | ||
1786 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
1787 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1788 | if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) | ||
1789 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | ||
1790 | } | ||
1791 | |||
1792 | return ret; | ||
1793 | } | ||
1794 | |||
1795 | static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream) | ||
1796 | { | ||
1797 | int ret; | ||
1798 | |||
1799 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | ||
1800 | ret = dpcm_run_update_startup(fe, stream); | ||
1801 | if (ret < 0) | ||
1802 | dev_err(fe->dev, "failed to startup some BEs\n"); | ||
1803 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | ||
1804 | |||
1805 | return ret; | ||
1806 | } | ||
1807 | |||
1808 | static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) | ||
1809 | { | ||
1810 | int ret; | ||
1811 | |||
1812 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; | ||
1813 | ret = dpcm_run_update_shutdown(fe, stream); | ||
1814 | if (ret < 0) | ||
1815 | dev_err(fe->dev, "failed to shutdown some BEs\n"); | ||
1816 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | ||
1817 | |||
1818 | return ret; | ||
1819 | } | ||
1820 | |||
1821 | /* Called by DAPM mixer/mux changes to update audio routing between PCMs and | ||
1822 | * any DAI links. | ||
1823 | */ | ||
1824 | int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) | ||
1825 | { | ||
1826 | struct snd_soc_card *card; | ||
1827 | int i, old, new, paths; | ||
1828 | |||
1829 | if (widget->codec) | ||
1830 | card = widget->codec->card; | ||
1831 | else if (widget->platform) | ||
1832 | card = widget->platform->card; | ||
1833 | else | ||
1834 | return -EINVAL; | ||
1835 | |||
1836 | mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | ||
1837 | for (i = 0; i < card->num_rtd; i++) { | ||
1838 | struct snd_soc_dapm_widget_list *list; | ||
1839 | struct snd_soc_pcm_runtime *fe = &card->rtd[i]; | ||
1840 | |||
1841 | /* make sure link is FE */ | ||
1842 | if (!fe->dai_link->dynamic) | ||
1843 | continue; | ||
1844 | |||
1845 | /* only check active links */ | ||
1846 | if (!fe->cpu_dai->active) | ||
1847 | continue; | ||
1848 | |||
1849 | /* DAPM sync will call this to update DSP paths */ | ||
1850 | dev_dbg(fe->dev, "DPCM runtime update for FE %s\n", | ||
1851 | fe->dai_link->name); | ||
1852 | |||
1853 | /* skip if FE doesn't have playback capability */ | ||
1854 | if (!fe->cpu_dai->driver->playback.channels_min) | ||
1855 | goto capture; | ||
1856 | |||
1857 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); | ||
1858 | if (paths < 0) { | ||
1859 | dev_warn(fe->dev, "%s no valid %s path\n", | ||
1860 | fe->dai_link->name, "playback"); | ||
1861 | mutex_unlock(&card->mutex); | ||
1862 | return paths; | ||
1863 | } | ||
1864 | |||
1865 | /* update any new playback paths */ | ||
1866 | new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1); | ||
1867 | if (new) { | ||
1868 | dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK); | ||
1869 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); | ||
1870 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); | ||
1871 | } | ||
1872 | |||
1873 | /* update any old playback paths */ | ||
1874 | old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0); | ||
1875 | if (old) { | ||
1876 | dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK); | ||
1877 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); | ||
1878 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); | ||
1879 | } | ||
1880 | |||
1881 | capture: | ||
1882 | /* skip if FE doesn't have capture capability */ | ||
1883 | if (!fe->cpu_dai->driver->capture.channels_min) | ||
1884 | continue; | ||
1885 | |||
1886 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); | ||
1887 | if (paths < 0) { | ||
1888 | dev_warn(fe->dev, "%s no valid %s path\n", | ||
1889 | fe->dai_link->name, "capture"); | ||
1890 | mutex_unlock(&card->mutex); | ||
1891 | return paths; | ||
1892 | } | ||
1893 | |||
1894 | /* update any new capture paths */ | ||
1895 | new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1); | ||
1896 | if (new) { | ||
1897 | dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE); | ||
1898 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); | ||
1899 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); | ||
1900 | } | ||
1901 | |||
1902 | /* update any old capture paths */ | ||
1903 | old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0); | ||
1904 | if (old) { | ||
1905 | dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE); | ||
1906 | dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); | ||
1907 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); | ||
1908 | } | ||
1909 | |||
1910 | dpcm_path_put(&list); | ||
1911 | } | ||
1912 | |||
1913 | mutex_unlock(&card->mutex); | ||
1914 | return 0; | ||
1915 | } | ||
1916 | int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) | ||
1917 | { | ||
1918 | struct snd_soc_dpcm *dpcm; | ||
1919 | struct list_head *clients = | ||
1920 | &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; | ||
1921 | |||
1922 | list_for_each_entry(dpcm, clients, list_be) { | ||
1923 | |||
1924 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
1925 | struct snd_soc_dai *dai = be->codec_dai; | ||
1926 | struct snd_soc_dai_driver *drv = dai->driver; | ||
1927 | |||
1928 | if (be->dai_link->ignore_suspend) | ||
1929 | continue; | ||
1930 | |||
1931 | dev_dbg(be->dev, "BE digital mute %s\n", be->dai_link->name); | ||
1932 | |||
1933 | if (drv->ops->digital_mute && dai->playback_active) | ||
1934 | drv->ops->digital_mute(dai, mute); | ||
1935 | } | ||
1936 | |||
1937 | return 0; | ||
1938 | } | ||
1939 | |||
1940 | static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) | ||
1941 | { | ||
1942 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; | ||
1943 | struct snd_soc_dpcm *dpcm; | ||
1944 | struct snd_soc_dapm_widget_list *list; | ||
1945 | int ret; | ||
1946 | int stream = fe_substream->stream; | ||
1947 | |||
1948 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | ||
1949 | fe->dpcm[stream].runtime = fe_substream->runtime; | ||
1950 | |||
1951 | if (dpcm_path_get(fe, stream, &list) <= 0) { | ||
1952 | dev_warn(fe->dev, "asoc: %s no valid %s route\n", | ||
1953 | fe->dai_link->name, stream ? "capture" : "playback"); | ||
1954 | mutex_unlock(&fe->card->mutex); | ||
1955 | return -EINVAL; | ||
1956 | } | ||
1957 | |||
1958 | /* calculate valid and active FE <-> BE dpcms */ | ||
1959 | dpcm_process_paths(fe, stream, &list, 1); | ||
1960 | |||
1961 | ret = dpcm_fe_dai_startup(fe_substream); | ||
1962 | if (ret < 0) { | ||
1963 | /* clean up all links */ | ||
1964 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) | ||
1965 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | ||
1966 | |||
1967 | dpcm_be_disconnect(fe, stream); | ||
1968 | fe->dpcm[stream].runtime = NULL; | ||
1969 | } | ||
1970 | |||
1971 | dpcm_clear_pending_state(fe, stream); | ||
1972 | dpcm_path_put(&list); | ||
1973 | mutex_unlock(&fe->card->mutex); | ||
1974 | return ret; | ||
1975 | } | ||
1976 | |||
1977 | static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) | ||
1978 | { | ||
1979 | struct snd_soc_pcm_runtime *fe = fe_substream->private_data; | ||
1980 | struct snd_soc_dpcm *dpcm; | ||
1981 | int stream = fe_substream->stream, ret; | ||
1982 | |||
1983 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | ||
1984 | ret = dpcm_fe_dai_shutdown(fe_substream); | ||
1985 | |||
1986 | /* mark FE's links ready to prune */ | ||
1987 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) | ||
1988 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | ||
1989 | |||
1990 | dpcm_be_disconnect(fe, stream); | ||
1991 | |||
1992 | fe->dpcm[stream].runtime = NULL; | ||
1993 | mutex_unlock(&fe->card->mutex); | ||
1994 | return ret; | ||
1995 | } | ||
1996 | |||
637 | /* create a new pcm */ | 1997 | /* create a new pcm */ |
638 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | 1998 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) |
639 | { | 1999 | { |
@@ -641,56 +2001,94 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
641 | struct snd_soc_platform *platform = rtd->platform; | 2001 | struct snd_soc_platform *platform = rtd->platform; |
642 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 2002 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
643 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 2003 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
644 | struct snd_pcm_ops *soc_pcm_ops = &rtd->ops; | ||
645 | struct snd_pcm *pcm; | 2004 | struct snd_pcm *pcm; |
646 | char new_name[64]; | 2005 | char new_name[64]; |
647 | int ret = 0, playback = 0, capture = 0; | 2006 | int ret = 0, playback = 0, capture = 0; |
648 | 2007 | ||
649 | soc_pcm_ops->open = soc_pcm_open; | 2008 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { |
650 | soc_pcm_ops->close = soc_pcm_close; | 2009 | if (cpu_dai->driver->playback.channels_min) |
651 | soc_pcm_ops->hw_params = soc_pcm_hw_params; | 2010 | playback = 1; |
652 | soc_pcm_ops->hw_free = soc_pcm_hw_free; | 2011 | if (cpu_dai->driver->capture.channels_min) |
653 | soc_pcm_ops->prepare = soc_pcm_prepare; | 2012 | capture = 1; |
654 | soc_pcm_ops->trigger = soc_pcm_trigger; | 2013 | } else { |
655 | soc_pcm_ops->pointer = soc_pcm_pointer; | 2014 | if (codec_dai->driver->playback.channels_min) |
656 | 2015 | playback = 1; | |
657 | /* check client and interface hw capabilities */ | 2016 | if (codec_dai->driver->capture.channels_min) |
658 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | 2017 | capture = 1; |
659 | rtd->dai_link->stream_name, codec_dai->name, num); | 2018 | } |
660 | 2019 | ||
661 | if (codec_dai->driver->playback.channels_min) | 2020 | /* create the PCM */ |
662 | playback = 1; | 2021 | if (rtd->dai_link->no_pcm) { |
663 | if (codec_dai->driver->capture.channels_min) | 2022 | snprintf(new_name, sizeof(new_name), "(%s)", |
664 | capture = 1; | 2023 | rtd->dai_link->stream_name); |
665 | 2024 | ||
666 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name); | 2025 | ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, |
667 | ret = snd_pcm_new(rtd->card->snd_card, new_name, | 2026 | playback, capture, &pcm); |
668 | num, playback, capture, &pcm); | 2027 | } else { |
2028 | if (rtd->dai_link->dynamic) | ||
2029 | snprintf(new_name, sizeof(new_name), "%s (*)", | ||
2030 | rtd->dai_link->stream_name); | ||
2031 | else | ||
2032 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | ||
2033 | rtd->dai_link->stream_name, codec_dai->name, num); | ||
2034 | |||
2035 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, | ||
2036 | capture, &pcm); | ||
2037 | } | ||
669 | if (ret < 0) { | 2038 | if (ret < 0) { |
670 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); | 2039 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); |
671 | return ret; | 2040 | return ret; |
672 | } | 2041 | } |
2042 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name); | ||
673 | 2043 | ||
674 | /* DAPM dai link stream work */ | 2044 | /* DAPM dai link stream work */ |
675 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); | 2045 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); |
676 | 2046 | ||
677 | rtd->pcm = pcm; | 2047 | rtd->pcm = pcm; |
678 | pcm->private_data = rtd; | 2048 | pcm->private_data = rtd; |
2049 | |||
2050 | if (rtd->dai_link->no_pcm) { | ||
2051 | if (playback) | ||
2052 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; | ||
2053 | if (capture) | ||
2054 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; | ||
2055 | goto out; | ||
2056 | } | ||
2057 | |||
2058 | /* ASoC PCM operations */ | ||
2059 | if (rtd->dai_link->dynamic) { | ||
2060 | rtd->ops.open = dpcm_fe_dai_open; | ||
2061 | rtd->ops.hw_params = dpcm_fe_dai_hw_params; | ||
2062 | rtd->ops.prepare = dpcm_fe_dai_prepare; | ||
2063 | rtd->ops.trigger = dpcm_fe_dai_trigger; | ||
2064 | rtd->ops.hw_free = dpcm_fe_dai_hw_free; | ||
2065 | rtd->ops.close = dpcm_fe_dai_close; | ||
2066 | rtd->ops.pointer = soc_pcm_pointer; | ||
2067 | rtd->ops.ioctl = soc_pcm_ioctl; | ||
2068 | } else { | ||
2069 | rtd->ops.open = soc_pcm_open; | ||
2070 | rtd->ops.hw_params = soc_pcm_hw_params; | ||
2071 | rtd->ops.prepare = soc_pcm_prepare; | ||
2072 | rtd->ops.trigger = soc_pcm_trigger; | ||
2073 | rtd->ops.hw_free = soc_pcm_hw_free; | ||
2074 | rtd->ops.close = soc_pcm_close; | ||
2075 | rtd->ops.pointer = soc_pcm_pointer; | ||
2076 | rtd->ops.ioctl = soc_pcm_ioctl; | ||
2077 | } | ||
2078 | |||
679 | if (platform->driver->ops) { | 2079 | if (platform->driver->ops) { |
680 | soc_pcm_ops->mmap = platform->driver->ops->mmap; | 2080 | rtd->ops.ack = platform->driver->ops->ack; |
681 | soc_pcm_ops->pointer = platform->driver->ops->pointer; | 2081 | rtd->ops.copy = platform->driver->ops->copy; |
682 | soc_pcm_ops->ioctl = platform->driver->ops->ioctl; | 2082 | rtd->ops.silence = platform->driver->ops->silence; |
683 | soc_pcm_ops->copy = platform->driver->ops->copy; | 2083 | rtd->ops.page = platform->driver->ops->page; |
684 | soc_pcm_ops->silence = platform->driver->ops->silence; | 2084 | rtd->ops.mmap = platform->driver->ops->mmap; |
685 | soc_pcm_ops->ack = platform->driver->ops->ack; | ||
686 | soc_pcm_ops->page = platform->driver->ops->page; | ||
687 | } | 2085 | } |
688 | 2086 | ||
689 | if (playback) | 2087 | if (playback) |
690 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, soc_pcm_ops); | 2088 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops); |
691 | 2089 | ||
692 | if (capture) | 2090 | if (capture) |
693 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, soc_pcm_ops); | 2091 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); |
694 | 2092 | ||
695 | if (platform->driver->pcm_new) { | 2093 | if (platform->driver->pcm_new) { |
696 | ret = platform->driver->pcm_new(rtd); | 2094 | ret = platform->driver->pcm_new(rtd); |
@@ -701,7 +2099,257 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
701 | } | 2099 | } |
702 | 2100 | ||
703 | pcm->private_free = platform->driver->pcm_free; | 2101 | pcm->private_free = platform->driver->pcm_free; |
2102 | out: | ||
704 | printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, | 2103 | printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, |
705 | cpu_dai->name); | 2104 | cpu_dai->name); |
706 | return ret; | 2105 | return ret; |
707 | } | 2106 | } |
2107 | |||
2108 | /* is the current PCM operation for this FE ? */ | ||
2109 | int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream) | ||
2110 | { | ||
2111 | if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) | ||
2112 | return 1; | ||
2113 | return 0; | ||
2114 | } | ||
2115 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update); | ||
2116 | |||
2117 | /* is the current PCM operation for this BE ? */ | ||
2118 | int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe, | ||
2119 | struct snd_soc_pcm_runtime *be, int stream) | ||
2120 | { | ||
2121 | if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) || | ||
2122 | ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) && | ||
2123 | be->dpcm[stream].runtime_update)) | ||
2124 | return 1; | ||
2125 | return 0; | ||
2126 | } | ||
2127 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update); | ||
2128 | |||
2129 | /* get the substream for this BE */ | ||
2130 | struct snd_pcm_substream * | ||
2131 | snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream) | ||
2132 | { | ||
2133 | return be->pcm->streams[stream].substream; | ||
2134 | } | ||
2135 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream); | ||
2136 | |||
2137 | /* get the BE runtime state */ | ||
2138 | enum snd_soc_dpcm_state | ||
2139 | snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream) | ||
2140 | { | ||
2141 | return be->dpcm[stream].state; | ||
2142 | } | ||
2143 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state); | ||
2144 | |||
2145 | /* set the BE runtime state */ | ||
2146 | void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, | ||
2147 | int stream, enum snd_soc_dpcm_state state) | ||
2148 | { | ||
2149 | be->dpcm[stream].state = state; | ||
2150 | } | ||
2151 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state); | ||
2152 | |||
2153 | /* | ||
2154 | * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE | ||
2155 | * are not running, paused or suspended for the specified stream direction. | ||
2156 | */ | ||
2157 | int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, | ||
2158 | struct snd_soc_pcm_runtime *be, int stream) | ||
2159 | { | ||
2160 | struct snd_soc_dpcm *dpcm; | ||
2161 | int state; | ||
2162 | |||
2163 | list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { | ||
2164 | |||
2165 | if (dpcm->fe == fe) | ||
2166 | continue; | ||
2167 | |||
2168 | state = dpcm->fe->dpcm[stream].state; | ||
2169 | if (state == SND_SOC_DPCM_STATE_START || | ||
2170 | state == SND_SOC_DPCM_STATE_PAUSED || | ||
2171 | state == SND_SOC_DPCM_STATE_SUSPEND) | ||
2172 | return 0; | ||
2173 | } | ||
2174 | |||
2175 | /* it's safe to free/stop this BE DAI */ | ||
2176 | return 1; | ||
2177 | } | ||
2178 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop); | ||
2179 | |||
2180 | /* | ||
2181 | * We can only change hw params a BE DAI if any of it's FE are not prepared, | ||
2182 | * running, paused or suspended for the specified stream direction. | ||
2183 | */ | ||
2184 | int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, | ||
2185 | struct snd_soc_pcm_runtime *be, int stream) | ||
2186 | { | ||
2187 | struct snd_soc_dpcm *dpcm; | ||
2188 | int state; | ||
2189 | |||
2190 | list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { | ||
2191 | |||
2192 | if (dpcm->fe == fe) | ||
2193 | continue; | ||
2194 | |||
2195 | state = dpcm->fe->dpcm[stream].state; | ||
2196 | if (state == SND_SOC_DPCM_STATE_START || | ||
2197 | state == SND_SOC_DPCM_STATE_PAUSED || | ||
2198 | state == SND_SOC_DPCM_STATE_SUSPEND || | ||
2199 | state == SND_SOC_DPCM_STATE_PREPARE) | ||
2200 | return 0; | ||
2201 | } | ||
2202 | |||
2203 | /* it's safe to change hw_params */ | ||
2204 | return 1; | ||
2205 | } | ||
2206 | EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); | ||
2207 | |||
2208 | int snd_soc_platform_trigger(struct snd_pcm_substream *substream, | ||
2209 | int cmd, struct snd_soc_platform *platform) | ||
2210 | { | ||
2211 | if (platform->driver->ops->trigger) | ||
2212 | return platform->driver->ops->trigger(substream, cmd); | ||
2213 | return 0; | ||
2214 | } | ||
2215 | EXPORT_SYMBOL_GPL(snd_soc_platform_trigger); | ||
2216 | |||
2217 | #ifdef CONFIG_DEBUG_FS | ||
2218 | static char *dpcm_state_string(enum snd_soc_dpcm_state state) | ||
2219 | { | ||
2220 | switch (state) { | ||
2221 | case SND_SOC_DPCM_STATE_NEW: | ||
2222 | return "new"; | ||
2223 | case SND_SOC_DPCM_STATE_OPEN: | ||
2224 | return "open"; | ||
2225 | case SND_SOC_DPCM_STATE_HW_PARAMS: | ||
2226 | return "hw_params"; | ||
2227 | case SND_SOC_DPCM_STATE_PREPARE: | ||
2228 | return "prepare"; | ||
2229 | case SND_SOC_DPCM_STATE_START: | ||
2230 | return "start"; | ||
2231 | case SND_SOC_DPCM_STATE_STOP: | ||
2232 | return "stop"; | ||
2233 | case SND_SOC_DPCM_STATE_SUSPEND: | ||
2234 | return "suspend"; | ||
2235 | case SND_SOC_DPCM_STATE_PAUSED: | ||
2236 | return "paused"; | ||
2237 | case SND_SOC_DPCM_STATE_HW_FREE: | ||
2238 | return "hw_free"; | ||
2239 | case SND_SOC_DPCM_STATE_CLOSE: | ||
2240 | return "close"; | ||
2241 | } | ||
2242 | |||
2243 | return "unknown"; | ||
2244 | } | ||
2245 | |||
2246 | static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, | ||
2247 | int stream, char *buf, size_t size) | ||
2248 | { | ||
2249 | struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params; | ||
2250 | struct snd_soc_dpcm *dpcm; | ||
2251 | ssize_t offset = 0; | ||
2252 | |||
2253 | /* FE state */ | ||
2254 | offset += snprintf(buf + offset, size - offset, | ||
2255 | "[%s - %s]\n", fe->dai_link->name, | ||
2256 | stream ? "Capture" : "Playback"); | ||
2257 | |||
2258 | offset += snprintf(buf + offset, size - offset, "State: %s\n", | ||
2259 | dpcm_state_string(fe->dpcm[stream].state)); | ||
2260 | |||
2261 | if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && | ||
2262 | (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) | ||
2263 | offset += snprintf(buf + offset, size - offset, | ||
2264 | "Hardware Params: " | ||
2265 | "Format = %s, Channels = %d, Rate = %d\n", | ||
2266 | snd_pcm_format_name(params_format(params)), | ||
2267 | params_channels(params), | ||
2268 | params_rate(params)); | ||
2269 | |||
2270 | /* BEs state */ | ||
2271 | offset += snprintf(buf + offset, size - offset, "Backends:\n"); | ||
2272 | |||
2273 | if (list_empty(&fe->dpcm[stream].be_clients)) { | ||
2274 | offset += snprintf(buf + offset, size - offset, | ||
2275 | " No active DSP links\n"); | ||
2276 | goto out; | ||
2277 | } | ||
2278 | |||
2279 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | ||
2280 | struct snd_soc_pcm_runtime *be = dpcm->be; | ||
2281 | params = &dpcm->hw_params; | ||
2282 | |||
2283 | offset += snprintf(buf + offset, size - offset, | ||
2284 | "- %s\n", be->dai_link->name); | ||
2285 | |||
2286 | offset += snprintf(buf + offset, size - offset, | ||
2287 | " State: %s\n", | ||
2288 | dpcm_state_string(be->dpcm[stream].state)); | ||
2289 | |||
2290 | if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) && | ||
2291 | (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP)) | ||
2292 | offset += snprintf(buf + offset, size - offset, | ||
2293 | " Hardware Params: " | ||
2294 | "Format = %s, Channels = %d, Rate = %d\n", | ||
2295 | snd_pcm_format_name(params_format(params)), | ||
2296 | params_channels(params), | ||
2297 | params_rate(params)); | ||
2298 | } | ||
2299 | |||
2300 | out: | ||
2301 | return offset; | ||
2302 | } | ||
2303 | |||
2304 | static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, | ||
2305 | size_t count, loff_t *ppos) | ||
2306 | { | ||
2307 | struct snd_soc_pcm_runtime *fe = file->private_data; | ||
2308 | ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0; | ||
2309 | char *buf; | ||
2310 | |||
2311 | buf = kmalloc(out_count, GFP_KERNEL); | ||
2312 | if (!buf) | ||
2313 | return -ENOMEM; | ||
2314 | |||
2315 | if (fe->cpu_dai->driver->playback.channels_min) | ||
2316 | offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK, | ||
2317 | buf + offset, out_count - offset); | ||
2318 | |||
2319 | if (fe->cpu_dai->driver->capture.channels_min) | ||
2320 | offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE, | ||
2321 | buf + offset, out_count - offset); | ||
2322 | |||
2323 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset); | ||
2324 | |||
2325 | kfree(buf); | ||
2326 | return ret; | ||
2327 | } | ||
2328 | |||
2329 | static const struct file_operations dpcm_state_fops = { | ||
2330 | .open = simple_open, | ||
2331 | .read = dpcm_state_read_file, | ||
2332 | .llseek = default_llseek, | ||
2333 | }; | ||
2334 | |||
2335 | int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) | ||
2336 | { | ||
2337 | if (!rtd->dai_link) | ||
2338 | return 0; | ||
2339 | |||
2340 | rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name, | ||
2341 | rtd->card->debugfs_card_root); | ||
2342 | if (!rtd->debugfs_dpcm_root) { | ||
2343 | dev_dbg(rtd->dev, | ||
2344 | "ASoC: Failed to create dpcm debugfs directory %s\n", | ||
2345 | rtd->dai_link->name); | ||
2346 | return -EINVAL; | ||
2347 | } | ||
2348 | |||
2349 | rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444, | ||
2350 | rtd->debugfs_dpcm_root, | ||
2351 | rtd, &dpcm_state_fops); | ||
2352 | |||
2353 | return 0; | ||
2354 | } | ||
2355 | #endif | ||