summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-07-30 15:01:44 +0200
committerTakashi Iwai <tiwai@suse.de>2008-10-13 02:42:58 +0200
commit176d5335fe66f379a339b0ab99cc7566e90ff1a9 (patch)
tree00f294bebf1270f65fe527141d3e6c1f440bba36 /sound/pci/hda/hda_codec.c
parent687cb98e893f492932abb3e92660d7d828bd44fb (diff)
ALSA: hda - Add infrastructure for dynamic stream allocation
Added the infrastructure for dynamic stream allocation on HD-audio. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r--sound/pci/hda/hda_codec.c74
1 files changed, 66 insertions, 8 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 6447754ae56..19b4530e3ba 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2262,6 +2262,28 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
return 0;
}
+/*
+ * attach a new PCM stream
+ */
+static int __devinit
+snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
+{
+ struct hda_pcm_stream *info;
+ int stream, err;
+
+ if (!pcm->name)
+ return -EINVAL;
+ for (stream = 0; stream < 2; stream++) {
+ info = &pcm->stream[stream];
+ if (info->substreams) {
+ err = set_pcm_default_values(codec, info);
+ if (err < 0)
+ return err;
+ }
+ }
+ return codec->bus->ops.attach_pcm(codec, pcm);
+}
+
/**
* snd_hda_build_pcms - build PCM information
* @bus: the BUS
@@ -2290,10 +2312,24 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
*/
int __devinit snd_hda_build_pcms(struct hda_bus *bus)
{
+ static const char *dev_name[HDA_PCM_NTYPES] = {
+ "Audio", "SPDIF", "HDMI", "Modem"
+ };
+ /* starting device index for each PCM type */
+ static int dev_idx[HDA_PCM_NTYPES] = {
+ [HDA_PCM_TYPE_AUDIO] = 0,
+ [HDA_PCM_TYPE_SPDIF] = 1,
+ [HDA_PCM_TYPE_HDMI] = 3,
+ [HDA_PCM_TYPE_MODEM] = 6
+ };
+ /* normal audio device indices; not linear to keep compatibility */
+ static int audio_idx[4] = { 0, 2, 4, 5 };
struct hda_codec *codec;
+ int num_devs[HDA_PCM_NTYPES];
+ memset(num_devs, 0, sizeof(num_devs));
list_for_each_entry(codec, &bus->codec_list, list) {
- unsigned int pcm, s;
+ unsigned int pcm;
int err;
if (!codec->patch_ops.build_pcms)
continue;
@@ -2301,15 +2337,37 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus)
if (err < 0)
return err;
for (pcm = 0; pcm < codec->num_pcms; pcm++) {
- for (s = 0; s < 2; s++) {
- struct hda_pcm_stream *info;
- info = &codec->pcm_info[pcm].stream[s];
- if (!info->substreams)
+ struct hda_pcm *cpcm = &codec->pcm_info[pcm];
+ int type = cpcm->pcm_type;
+ switch (type) {
+ case HDA_PCM_TYPE_AUDIO:
+ if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
+ snd_printk(KERN_WARNING
+ "Too many audio devices\n");
+ continue;
+ }
+ cpcm->device = audio_idx[num_devs[type]];
+ break;
+ case HDA_PCM_TYPE_SPDIF:
+ case HDA_PCM_TYPE_HDMI:
+ case HDA_PCM_TYPE_MODEM:
+ if (num_devs[type]) {
+ snd_printk(KERN_WARNING
+ "%s already defined\n",
+ dev_name[type]);
continue;
- err = set_pcm_default_values(codec, info);
- if (err < 0)
- return err;
+ }
+ cpcm->device = dev_idx[type];
+ break;
+ default:
+ snd_printk(KERN_WARNING
+ "Invalid PCM type %d\n", type);
+ continue;
}
+ num_devs[type]++;
+ err = snd_hda_attach_pcm(codec, cpcm);
+ if (err < 0)
+ return err;
}
}
return 0;