--- es1371-orig.c	Mon Dec 11 00:49:43 2000
+++ es1371.c	Fri Dec 15 17:15:44 2000
@@ -210,6 +210,7 @@
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 
+#define CTRL_RECEN_B    0x08000000  /* 1 = don't mix analog in to digital out */
 #define CTRL_SPDIFEN_B  0x04000000
 #define CTRL_JOY_SHIFT  24
 #define CTRL_JOY_MASK   3
@@ -495,6 +496,9 @@
 		unsigned char ibuf[MIDIINBUF];
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
+	
+	/* options */
+	int spdif_out; /* S/PDIF output is enabled */
 };
 
 /* --------------------------------------------------------------------- */
@@ -1242,6 +1246,25 @@
 	[SOUND_MIXER_IGAIN] = AC97_RECORD_GAIN_MIC
 };
 
+/* Conversion table for S/PDIF PCM volume emulation through the SRC */
+/* dB-linear table of DAC vol values; -0dB to -46.5dB with mute */
+static const unsigned short DACVolTable[101] =
+{
+	0x1000, 0x0f2a, 0x0e60, 0x0da0, 0x0cea, 0x0c3e, 0x0b9a, 0x0aff,
+	0x0a6d, 0x09e1, 0x095e, 0x08e1, 0x086a, 0x07fa, 0x078f, 0x072a,
+	0x06cb, 0x0670, 0x061a, 0x05c9, 0x057b, 0x0532, 0x04ed, 0x04ab,
+	0x046d, 0x0432, 0x03fa, 0x03c5, 0x0392, 0x0363, 0x0335, 0x030b,
+	0x02e2, 0x02bc, 0x0297, 0x0275, 0x0254, 0x0235, 0x0217, 0x01fb,
+	0x01e1, 0x01c8, 0x01b0, 0x0199, 0x0184, 0x0170, 0x015d, 0x014b,
+	0x0139, 0x0129, 0x0119, 0x010b, 0x00fd, 0x00f0, 0x00e3, 0x00d7,
+	0x00cc, 0x00c1, 0x00b7, 0x00ae, 0x00a5, 0x009c, 0x0094, 0x008c,
+	0x0085, 0x007e, 0x0077, 0x0071, 0x006b, 0x0066, 0x0060, 0x005b,
+	0x0057, 0x0052, 0x004e, 0x004a, 0x0046, 0x0042, 0x003f, 0x003c,
+	0x0038, 0x0036, 0x0033, 0x0030, 0x002e, 0x002b, 0x0029, 0x0027,
+	0x0025, 0x0023, 0x0021, 0x001f, 0x001e, 0x001c, 0x001b, 0x0019,
+	0x0018, 0x0017, 0x0016, 0x0014, 0x0000
+};
+
 #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
 
 #define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
@@ -1376,22 +1399,30 @@
 	case SOUND_MIXER_VIDEO:
 	case SOUND_MIXER_LINE1:
 	case SOUND_MIXER_PCM:
-		if (l1 < 7 && r1 < 7) {
-			wrcodec(s, volreg[ch], AC97_MUTE);
+		if (ch == SOUND_MIXER_PCM && s->spdif_out) { /* use SRC for PCM volume */
+			src_write(s, SRCREG_VOL_DAC2, DACVolTable[100 - l1]);
+			src_write(s, SRCREG_VOL_DAC2+1, DACVolTable[100 - r1]);
+			return 0;
+		} else {
+			if (l1 < 7 && r1 < 7) {
+				wrcodec(s, volreg[ch], AC97_MUTE);
+				return 0;
+			}
+			if (l1 < 7)
+				l1 = 7;
+			if (r1 < 7)
+				r1 = 7;
+			wrcodec(s, volreg[ch], (((100 - l1) / 3) << 8) | ((100 - r1) / 3));
 			return 0;
 		}
-		if (l1 < 7)
-			l1 = 7;
-		if (r1 < 7)
-			r1 = 7;
-		wrcodec(s, volreg[ch], (((100 - l1) / 3) << 8) | ((100 - r1) / 3));
-		return 0;
 
 	case SOUND_MIXER_PHONEOUT:
 		if (!(s->mix.codec_id & CODEC_ID_HEADPHONEOUT))
 			return -EINVAL;
 		/* fall through */
 	case SOUND_MIXER_VOLUME:
+		if (ch == SOUND_MIXER_VOLUME && s->spdif_out) /* master stays muted */
+			return 0;
 #ifdef AC97_PESSIMISTIC
 		if (l1 < 7 && r1 < 7) {
 			wrcodec(s, volreg[ch], AC97_MUTE);
@@ -3041,6 +3072,7 @@
 static int joystick[NR_DEVICE] = { 0, };
 #endif
 static int spdif[NR_DEVICE] = { 0, };
+static int nomix[NR_DEVICE] = { 0, };
 
 /* --------------------------------------------------------------------- */
 
@@ -3137,12 +3169,16 @@
 	}
 	s->sctrl = 0;
 	cssr = 0;
+	s->spdif_out = 0;
 	/* check to see if s/pdif mode is being requested */
 	if (spdif[index]) {
 		if (s->rev >= 4) {
 			printk(KERN_INFO "es1371: enabling S/PDIF output\n");
+			s->spdif_out = 1;
 			cssr |= STAT_EN_SPDIF;
 			s->ctrl |= CTRL_SPDIFEN_B;
+			if (nomix[index]) /* don't mix analog inputs to s/pdif output */
+			s->ctrl |= CTRL_RECEN_B;
 		} else {
 			printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev);
 		}
@@ -3218,6 +3254,12 @@
 	printk(KERN_INFO "es1371: stereo enhancement: %s\n", 
 	       (val <= 26 && stereo_enhancement[val]) ? stereo_enhancement[val] : "unknown");
 
+	/* mute master and PCM when in S/PDIF mode */
+	if (s->spdif_out) {
+    	   wrcodec(s, volreg[SOUND_MIXER_VOLUME], AC97_MUTE);
+    	   wrcodec(s, volreg[SOUND_MIXER_PCM], AC97_MUTE);
+	}
+
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	val = SOUND_MASK_LINE;
@@ -3288,6 +3330,8 @@
 MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)");
 MODULE_PARM(spdif, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(spdif, "if 1 the output is in S/PDIF digital mode");
+MODULE_PARM(nomix, "1-" __MODULE_STRING(NR_DEVICE) "i");
+MODULE_PARM_DESC(nomix, "if 1 no analog audio is mixed to the digital output");
 
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("ES1371 AudioPCI97 Driver");

