[ALSA] ymfpci - make rear channel swap optional

Modules: YMFPCI driver

Added rear_swap module option / kernel parameter to configure the rear
channel swapping. Default value is enable to make the AC3 passthrough
working, but analog only users might revert the previous behaviour.

Signed-off-by: Jaroslav Kysela <perex@suse.cz>
diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h
index d567bfd..d41cda9 100644
--- a/include/sound/ymfpci.h
+++ b/include/sound/ymfpci.h
@@ -269,9 +269,10 @@
 	enum snd_ymfpci_pcm_type type;
 	struct snd_pcm_substream *substream;
 	struct snd_ymfpci_voice *voices[2];	/* playback only */
-	unsigned int running: 1;
-	unsigned int output_front: 1;
-	unsigned int output_rear: 1;
+	unsigned int running: 1,
+	             output_front: 1,
+	             output_rear: 1,
+	             swap_rear: 1;
 	unsigned int update_pcm_vol;
 	u32 period_size;		/* cached from runtime->period_size */
 	u32 buffer_size;		/* cached from runtime->buffer_size */
@@ -344,6 +345,7 @@
 	struct snd_kcontrol *spdif_pcm_ctl;
 	int mode_dup4ch;
 	int rear_opened;
+	int rear_swap;
 	int spdif_opened;
 	struct {
 		u16 left;
@@ -376,7 +378,7 @@
 int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
 int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
 int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch);
+int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rear_swap);
 int snd_ymfpci_timer(struct snd_ymfpci *chip, int device);
 
 #endif /* __SOUND_YMFPCI_H */
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index dab9b83..db57ce9 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -49,6 +49,7 @@
 static long joystick_port[SNDRV_CARDS];
 #endif
 static int rear_switch[SNDRV_CARDS];
+static int rear_swap[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the Yamaha DS-1 PCI soundcard.");
@@ -66,6 +67,8 @@
 #endif
 module_param_array(rear_switch, bool, NULL, 0444);
 MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
+module_param_array(rear_swap, bool, NULL, 0444);
+MODULE_PARM_DESC(rear_swap, "Swap rear channels (must be enabled for correct IEC958 (S/PDIF)) output");
 
 static struct pci_device_id snd_ymfpci_ids[] = {
         { 0x1073, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF724 */
@@ -295,7 +298,7 @@
 		snd_card_free(card);
 		return err;
 	}
-	if ((err = snd_ymfpci_mixer(chip, rear_switch[dev])) < 0) {
+	if ((err = snd_ymfpci_mixer(chip, rear_switch[dev], rear_swap[dev])) < 0) {
 		snd_card_free(card);
 		return err;
 	}
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 30ee53a..8ac5ab5 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -536,19 +536,30 @@
 			}
 		}
 		if (ypcm->output_rear) {
-			/* The SPDIF out channels seem to be swapped, so we have
-			 * to swap them here, too.  The rear analog out channels
-			 * will be wrong, but otherwise AC3 would not work.
-			 */
-			if (use_left) {
-				bank->eff3_gain =
-				bank->eff3_gain_end = vol_left;
-			}
-			if (use_right) {
-				bank->eff2_gain =
-				bank->eff2_gain_end = vol_right;
-			}
-		}
+		        if (!ypcm->swap_rear) {
+        			if (use_left) {
+        				bank->eff2_gain =
+        				bank->eff2_gain_end = vol_left;
+        			}
+        			if (use_right) {
+        				bank->eff3_gain =
+        				bank->eff3_gain_end = vol_right;
+        			}
+		        } else {
+        			/* The SPDIF out channels seem to be swapped, so we have
+        			 * to swap them here, too.  The rear analog out channels
+        			 * will be wrong, but otherwise AC3 would not work.
+        			 */
+        			if (use_left) {
+        				bank->eff3_gain =
+        				bank->eff3_gain_end = vol_left;
+        			}
+        			if (use_right) {
+        				bank->eff2_gain =
+        				bank->eff2_gain_end = vol_right;
+        			}
+        		}
+                }
 	}
 }
 
@@ -898,6 +909,7 @@
 	ypcm = runtime->private_data;
 	ypcm->output_front = 1;
 	ypcm->output_rear = chip->mode_dup4ch ? 1 : 0;
+	ypcm->swap_rear = chip->rear_swap;
 	spin_lock_irq(&chip->reg_lock);
 	if (ypcm->output_rear) {
 		ymfpci_open_extension(chip);
@@ -1738,7 +1750,7 @@
 	chip->ac97 = NULL;
 }
 
-int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
+int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rear_swap)
 {
 	struct snd_ac97_template ac97;
 	struct snd_kcontrol *kctl;
@@ -1750,6 +1762,7 @@
 		.read = snd_ymfpci_codec_read,
 	};
 
+	chip->rear_swap = rear_swap;
 	if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0)
 		return err;
 	chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus;
@@ -2297,6 +2310,7 @@
 		return -EIO;
 	}
 
+	chip->rear_swap = 1;
 	if ((err = snd_ymfpci_ac3_init(chip)) < 0) {
 		snd_ymfpci_free(chip);
 		return err;