[ALSA] oxygen: make all DMA channels configurable

Allow the card models to specify whether each of the hardware DMA
channels is used.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 83c6fab..e2dda16 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -256,6 +256,11 @@
 	.update_dac_volume = update_ak4396_volume,
 	.update_dac_mute = update_ak4396_mute,
 	.dac_tlv = ak4396_db_scale,
+	.used_channels = OXYGEN_CHANNEL_A |
+			 OXYGEN_CHANNEL_C |
+			 OXYGEN_CHANNEL_SPDIF |
+			 OXYGEN_CHANNEL_MULTICH |
+			 OXYGEN_CHANNEL_AC97,
 	.function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
 };
 static const struct oxygen_model model_meridian = {
@@ -270,7 +275,11 @@
 	.update_dac_volume = update_ak4396_volume,
 	.update_dac_mute = update_ak4396_mute,
 	.dac_tlv = ak4396_db_scale,
-	.record_from_dma_b = 1,
+	.used_channels = OXYGEN_CHANNEL_B |
+			 OXYGEN_CHANNEL_C |
+			 OXYGEN_CHANNEL_SPDIF |
+			 OXYGEN_CHANNEL_MULTICH |
+			 OXYGEN_CHANNEL_AC97,
 	.function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
 };
 
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index fb9cb36b..9b0234d 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -80,7 +80,7 @@
 	void (*update_dac_volume)(struct oxygen *chip);
 	void (*update_dac_mute)(struct oxygen *chip);
 	const unsigned int *dac_tlv;
-	u8 record_from_dma_b;
+	u8 used_channels;
 	u8 cd_in_from_video_in;
 	u8 dac_minimum_volume;
 	u8 function_flags;
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index 0f67def..5f15d35 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -681,15 +681,22 @@
 int __devinit oxygen_pcm_init(struct oxygen *chip)
 {
 	struct snd_pcm *pcm;
+	int outs, ins;
 	int err;
 
-	err = snd_pcm_new(chip->card, "Analog", 0, 1, 1, &pcm);
+	outs = 1; /* OXYGEN_CHANNEL_MULTICH is always used */
+	ins = !!(chip->model->used_channels & (OXYGEN_CHANNEL_A |
+					       OXYGEN_CHANNEL_B));
+	err = snd_pcm_new(chip->card, "Analog", 0, outs, ins, &pcm);
 	if (err < 0)
 		return err;
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &oxygen_multich_ops);
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-			chip->model->record_from_dma_b ?
-			&oxygen_rec_b_ops : &oxygen_rec_a_ops);
+	if (chip->model->used_channels & OXYGEN_CHANNEL_A)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+				&oxygen_rec_a_ops);
+	else if (chip->model->used_channels & OXYGEN_CHANNEL_B)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+				&oxygen_rec_b_ops);
 	pcm->private_data = chip;
 	pcm->private_free = oxygen_pcm_free;
 	strcpy(pcm->name, "Analog");
@@ -697,32 +704,51 @@
 				      SNDRV_DMA_TYPE_DEV,
 				      snd_dma_pci_data(chip->pci),
 				      512 * 1024, 2048 * 1024);
-	snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
-				      SNDRV_DMA_TYPE_DEV,
-				      snd_dma_pci_data(chip->pci),
-				      128 * 1024, 256 * 1024);
-
-	err = snd_pcm_new(chip->card, "Digital", 1, 1, 1, &pcm);
-	if (err < 0)
-		return err;
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &oxygen_spdif_ops);
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &oxygen_rec_c_ops);
-	pcm->private_data = chip;
-	pcm->private_free = oxygen_pcm_free;
-	strcpy(pcm->name, "Digital");
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+	if (ins)
+		snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+					      SNDRV_DMA_TYPE_DEV,
 					      snd_dma_pci_data(chip->pci),
 					      128 * 1024, 256 * 1024);
 
-	if (chip->has_ac97_1) {
-		err = snd_pcm_new(chip->card, "AC97", 2, 1, 0, &pcm);
+	outs = !!(chip->model->used_channels & OXYGEN_CHANNEL_SPDIF);
+	ins = !!(chip->model->used_channels & OXYGEN_CHANNEL_C);
+	if (outs | ins) {
+		err = snd_pcm_new(chip->card, "Digital", 1, outs, ins, &pcm);
 		if (err < 0)
 			return err;
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-				&oxygen_ac97_ops);
+		if (outs)
+			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+					&oxygen_spdif_ops);
+		if (ins)
+			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+					&oxygen_rec_c_ops);
 		pcm->private_data = chip;
 		pcm->private_free = oxygen_pcm_free;
-		strcpy(pcm->name, "Front Panel");
+		strcpy(pcm->name, "Digital");
+		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+						      snd_dma_pci_data(chip->pci),
+						      128 * 1024, 256 * 1024);
+	}
+
+	outs = chip->has_ac97_1 &&
+		(chip->model->used_channels & OXYGEN_CHANNEL_AC97);
+	ins = (chip->model->used_channels & (OXYGEN_CHANNEL_A |
+					     OXYGEN_CHANNEL_B))
+		== (OXYGEN_CHANNEL_A | OXYGEN_CHANNEL_B);
+	if (outs | ins) {
+		err = snd_pcm_new(chip->card, ins ? "Analog2" : "AC97",
+				  2, outs, ins, &pcm);
+		if (err < 0)
+			return err;
+		if (outs)
+			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+					&oxygen_ac97_ops);
+		if (ins)
+			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+					&oxygen_rec_b_ops);
+		pcm->private_data = chip;
+		pcm->private_free = oxygen_pcm_free;
+		strcpy(pcm->name, ins ? "Analog 2" : "Front Panel");
 		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 						      snd_dma_pci_data(chip->pci),
 						      128 * 1024, 256 * 1024);
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 247d5e1..0574fa1 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -224,7 +224,10 @@
 	.update_dac_volume = update_pcm1796_volume,
 	.update_dac_mute = update_pcm1796_mute,
 	.dac_tlv = pcm1796_db_scale,
-	.record_from_dma_b = 1,
+	.used_channels = OXYGEN_CHANNEL_B |
+			 OXYGEN_CHANNEL_C |
+			 OXYGEN_CHANNEL_SPDIF |
+			 OXYGEN_CHANNEL_MULTICH,
 	.cd_in_from_video_in = 1,
 	.dac_minimum_volume = 15,
 	.function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,