diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-02-23 03:14:36 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-02-23 03:14:36 -0500 |
commit | 0eee62e08c0b3ba068472b899cdda08cf4b4544b (patch) | |
tree | 78940e4bf918ee46458f30ba5a17cd42cfa297f2 /sound/core | |
parent | 8d085d3ca9cb70e3e62456419e20f2fddc64141a (diff) | |
parent | b20221385c40155f13068be75b865170a1ad5d1e (diff) |
Merge branch 'topic/pcm-internal' into for-next
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/pcm.c | 92 |
1 files changed, 41 insertions, 51 deletions
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 0345e53a340c..e9b87465c73d 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -49,8 +49,6 @@ static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device) | |||
49 | struct snd_pcm *pcm; | 49 | struct snd_pcm *pcm; |
50 | 50 | ||
51 | list_for_each_entry(pcm, &snd_pcm_devices, list) { | 51 | list_for_each_entry(pcm, &snd_pcm_devices, list) { |
52 | if (pcm->internal) | ||
53 | continue; | ||
54 | if (pcm->card == card && pcm->device == device) | 52 | if (pcm->card == card && pcm->device == device) |
55 | return pcm; | 53 | return pcm; |
56 | } | 54 | } |
@@ -62,8 +60,6 @@ static int snd_pcm_next(struct snd_card *card, int device) | |||
62 | struct snd_pcm *pcm; | 60 | struct snd_pcm *pcm; |
63 | 61 | ||
64 | list_for_each_entry(pcm, &snd_pcm_devices, list) { | 62 | list_for_each_entry(pcm, &snd_pcm_devices, list) { |
65 | if (pcm->internal) | ||
66 | continue; | ||
67 | if (pcm->card == card && pcm->device > device) | 63 | if (pcm->card == card && pcm->device > device) |
68 | return pcm->device; | 64 | return pcm->device; |
69 | else if (pcm->card->number > card->number) | 65 | else if (pcm->card->number > card->number) |
@@ -76,6 +72,9 @@ static int snd_pcm_add(struct snd_pcm *newpcm) | |||
76 | { | 72 | { |
77 | struct snd_pcm *pcm; | 73 | struct snd_pcm *pcm; |
78 | 74 | ||
75 | if (newpcm->internal) | ||
76 | return 0; | ||
77 | |||
79 | list_for_each_entry(pcm, &snd_pcm_devices, list) { | 78 | list_for_each_entry(pcm, &snd_pcm_devices, list) { |
80 | if (pcm->card == newpcm->card && pcm->device == newpcm->device) | 79 | if (pcm->card == newpcm->card && pcm->device == newpcm->device) |
81 | return -EBUSY; | 80 | return -EBUSY; |
@@ -782,6 +781,9 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, | |||
782 | pcm->card = card; | 781 | pcm->card = card; |
783 | pcm->device = device; | 782 | pcm->device = device; |
784 | pcm->internal = internal; | 783 | pcm->internal = internal; |
784 | mutex_init(&pcm->open_mutex); | ||
785 | init_waitqueue_head(&pcm->open_wait); | ||
786 | INIT_LIST_HEAD(&pcm->list); | ||
785 | if (id) | 787 | if (id) |
786 | strlcpy(pcm->id, id, sizeof(pcm->id)); | 788 | strlcpy(pcm->id, id, sizeof(pcm->id)); |
787 | if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { | 789 | if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { |
@@ -792,8 +794,6 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, | |||
792 | snd_pcm_free(pcm); | 794 | snd_pcm_free(pcm); |
793 | return err; | 795 | return err; |
794 | } | 796 | } |
795 | mutex_init(&pcm->open_mutex); | ||
796 | init_waitqueue_head(&pcm->open_wait); | ||
797 | if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) { | 797 | if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) { |
798 | snd_pcm_free(pcm); | 798 | snd_pcm_free(pcm); |
799 | return err; | 799 | return err; |
@@ -888,8 +888,9 @@ static int snd_pcm_free(struct snd_pcm *pcm) | |||
888 | 888 | ||
889 | if (!pcm) | 889 | if (!pcm) |
890 | return 0; | 890 | return 0; |
891 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { | 891 | if (!pcm->internal) { |
892 | notify->n_unregister(pcm); | 892 | list_for_each_entry(notify, &snd_pcm_notify_list, list) |
893 | notify->n_unregister(pcm); | ||
893 | } | 894 | } |
894 | if (pcm->private_free) | 895 | if (pcm->private_free) |
895 | pcm->private_free(pcm); | 896 | pcm->private_free(pcm); |
@@ -919,6 +920,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
919 | 920 | ||
920 | if (snd_BUG_ON(!pcm || !rsubstream)) | 921 | if (snd_BUG_ON(!pcm || !rsubstream)) |
921 | return -ENXIO; | 922 | return -ENXIO; |
923 | if (snd_BUG_ON(stream != SNDRV_PCM_STREAM_PLAYBACK && | ||
924 | stream != SNDRV_PCM_STREAM_CAPTURE)) | ||
925 | return -EINVAL; | ||
922 | *rsubstream = NULL; | 926 | *rsubstream = NULL; |
923 | pstr = &pcm->streams[stream]; | 927 | pstr = &pcm->streams[stream]; |
924 | if (pstr->substream == NULL || pstr->substream_count == 0) | 928 | if (pstr->substream == NULL || pstr->substream_count == 0) |
@@ -927,25 +931,14 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
927 | card = pcm->card; | 931 | card = pcm->card; |
928 | prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM); | 932 | prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM); |
929 | 933 | ||
930 | switch (stream) { | 934 | if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { |
931 | case SNDRV_PCM_STREAM_PLAYBACK: | 935 | int opposite = !stream; |
932 | if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { | 936 | |
933 | for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) { | 937 | for (substream = pcm->streams[opposite].substream; substream; |
934 | if (SUBSTREAM_BUSY(substream)) | 938 | substream = substream->next) { |
935 | return -EAGAIN; | 939 | if (SUBSTREAM_BUSY(substream)) |
936 | } | 940 | return -EAGAIN; |
937 | } | ||
938 | break; | ||
939 | case SNDRV_PCM_STREAM_CAPTURE: | ||
940 | if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { | ||
941 | for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) { | ||
942 | if (SUBSTREAM_BUSY(substream)) | ||
943 | return -EAGAIN; | ||
944 | } | ||
945 | } | 941 | } |
946 | break; | ||
947 | default: | ||
948 | return -EINVAL; | ||
949 | } | 942 | } |
950 | 943 | ||
951 | if (file->f_flags & O_APPEND) { | 944 | if (file->f_flags & O_APPEND) { |
@@ -968,15 +961,12 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
968 | return 0; | 961 | return 0; |
969 | } | 962 | } |
970 | 963 | ||
971 | if (prefer_subdevice >= 0) { | 964 | for (substream = pstr->substream; substream; substream = substream->next) { |
972 | for (substream = pstr->substream; substream; substream = substream->next) | 965 | if (!SUBSTREAM_BUSY(substream) && |
973 | if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice) | 966 | (prefer_subdevice == -1 || |
974 | goto __ok; | 967 | substream->number == prefer_subdevice)) |
975 | } | ||
976 | for (substream = pstr->substream; substream; substream = substream->next) | ||
977 | if (!SUBSTREAM_BUSY(substream)) | ||
978 | break; | 968 | break; |
979 | __ok: | 969 | } |
980 | if (substream == NULL) | 970 | if (substream == NULL) |
981 | return -EAGAIN; | 971 | return -EAGAIN; |
982 | 972 | ||
@@ -1086,15 +1076,16 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
1086 | if (snd_BUG_ON(!device || !device->device_data)) | 1076 | if (snd_BUG_ON(!device || !device->device_data)) |
1087 | return -ENXIO; | 1077 | return -ENXIO; |
1088 | pcm = device->device_data; | 1078 | pcm = device->device_data; |
1079 | if (pcm->internal) | ||
1080 | return 0; | ||
1081 | |||
1089 | mutex_lock(®ister_mutex); | 1082 | mutex_lock(®ister_mutex); |
1090 | err = snd_pcm_add(pcm); | 1083 | err = snd_pcm_add(pcm); |
1091 | if (err) { | 1084 | if (err) |
1092 | mutex_unlock(®ister_mutex); | 1085 | goto unlock; |
1093 | return err; | ||
1094 | } | ||
1095 | for (cidx = 0; cidx < 2; cidx++) { | 1086 | for (cidx = 0; cidx < 2; cidx++) { |
1096 | int devtype = -1; | 1087 | int devtype = -1; |
1097 | if (pcm->streams[cidx].substream == NULL || pcm->internal) | 1088 | if (pcm->streams[cidx].substream == NULL) |
1098 | continue; | 1089 | continue; |
1099 | switch (cidx) { | 1090 | switch (cidx) { |
1100 | case SNDRV_PCM_STREAM_PLAYBACK: | 1091 | case SNDRV_PCM_STREAM_PLAYBACK: |
@@ -1109,9 +1100,8 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
1109 | &snd_pcm_f_ops[cidx], pcm, | 1100 | &snd_pcm_f_ops[cidx], pcm, |
1110 | &pcm->streams[cidx].dev); | 1101 | &pcm->streams[cidx].dev); |
1111 | if (err < 0) { | 1102 | if (err < 0) { |
1112 | list_del(&pcm->list); | 1103 | list_del_init(&pcm->list); |
1113 | mutex_unlock(®ister_mutex); | 1104 | goto unlock; |
1114 | return err; | ||
1115 | } | 1105 | } |
1116 | 1106 | ||
1117 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | 1107 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) |
@@ -1121,8 +1111,9 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
1121 | list_for_each_entry(notify, &snd_pcm_notify_list, list) | 1111 | list_for_each_entry(notify, &snd_pcm_notify_list, list) |
1122 | notify->n_register(pcm); | 1112 | notify->n_register(pcm); |
1123 | 1113 | ||
1114 | unlock: | ||
1124 | mutex_unlock(®ister_mutex); | 1115 | mutex_unlock(®ister_mutex); |
1125 | return 0; | 1116 | return err; |
1126 | } | 1117 | } |
1127 | 1118 | ||
1128 | static int snd_pcm_dev_disconnect(struct snd_device *device) | 1119 | static int snd_pcm_dev_disconnect(struct snd_device *device) |
@@ -1133,13 +1124,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) | |||
1133 | int cidx; | 1124 | int cidx; |
1134 | 1125 | ||
1135 | mutex_lock(®ister_mutex); | 1126 | mutex_lock(®ister_mutex); |
1136 | if (list_empty(&pcm->list)) | ||
1137 | goto unlock; | ||
1138 | |||
1139 | mutex_lock(&pcm->open_mutex); | 1127 | mutex_lock(&pcm->open_mutex); |
1140 | wake_up(&pcm->open_wait); | 1128 | wake_up(&pcm->open_wait); |
1141 | list_del_init(&pcm->list); | 1129 | list_del_init(&pcm->list); |
1142 | for (cidx = 0; cidx < 2; cidx++) | 1130 | for (cidx = 0; cidx < 2; cidx++) { |
1143 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { | 1131 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { |
1144 | snd_pcm_stream_lock_irq(substream); | 1132 | snd_pcm_stream_lock_irq(substream); |
1145 | if (substream->runtime) { | 1133 | if (substream->runtime) { |
@@ -1149,18 +1137,20 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) | |||
1149 | } | 1137 | } |
1150 | snd_pcm_stream_unlock_irq(substream); | 1138 | snd_pcm_stream_unlock_irq(substream); |
1151 | } | 1139 | } |
1152 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { | 1140 | } |
1153 | notify->n_disconnect(pcm); | 1141 | if (!pcm->internal) { |
1142 | list_for_each_entry(notify, &snd_pcm_notify_list, list) | ||
1143 | notify->n_disconnect(pcm); | ||
1154 | } | 1144 | } |
1155 | for (cidx = 0; cidx < 2; cidx++) { | 1145 | for (cidx = 0; cidx < 2; cidx++) { |
1156 | snd_unregister_device(&pcm->streams[cidx].dev); | 1146 | if (!pcm->internal) |
1147 | snd_unregister_device(&pcm->streams[cidx].dev); | ||
1157 | if (pcm->streams[cidx].chmap_kctl) { | 1148 | if (pcm->streams[cidx].chmap_kctl) { |
1158 | snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); | 1149 | snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl); |
1159 | pcm->streams[cidx].chmap_kctl = NULL; | 1150 | pcm->streams[cidx].chmap_kctl = NULL; |
1160 | } | 1151 | } |
1161 | } | 1152 | } |
1162 | mutex_unlock(&pcm->open_mutex); | 1153 | mutex_unlock(&pcm->open_mutex); |
1163 | unlock: | ||
1164 | mutex_unlock(®ister_mutex); | 1154 | mutex_unlock(®ister_mutex); |
1165 | return 0; | 1155 | return 0; |
1166 | } | 1156 | } |