Skip to contentSkip to conversation

cs46xx DAC volume's mechanism rewrite, minor bugfixes]

PATCH In review Peter Good 3 participants 5 messages Nov 10, 2002 – Nov 11, 2002

lore
Share & tools
lore

Peter Good

author
#0 lore raw

PATCH 1/1 cs46xx DAC volume's mechanism rewrite, minor bugfixes]

Dammit, forgot to cc to here heh.

Signature · 6 lines
"I am neither especially clever nor especially 
gifted. I am only very, very curious." Einstein.

Peter Good
Pete's Internet Services
GnuPG Public Key: http://www.petesinternet.net/public.gpg

Ok, that's fixed the bass problem I had here.
One thing though. Benny, do you have any idea what these values "should" be?

iec958:AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2

Now that's what xine gives me, but, I know that can be reset via xine's config file. mplayer on the other hand gives this.

alsa-init: testing and bugreports are welcome.
alsa-init: requested format: 48000 Hz, 2 channels, AC3
alsa-init: compiled for ALSA-0.9.0rc5
alsa-spdif-init: playing AC3, 2 channels
alsa-init: soundcard set to iec958:AES0=0x2,AES1=0x82,AES2=0x0,AES3=0x2 ALSA lib pcm.c:1719:(snd_pcm_open_conf) Invalid type for PCM iec958:AES0=0x2,AES1=0x82,AES2=0x0,AES3=0x2 definition (id: iec958,
value: cards.pcm.iec958)
alsa-init: playback open error: Invalid argument
couldn't open/init audio device -> NOSOUND

hehe, any ideas on what the values should be would be appreciated.

Peter

Quoted 712 lines · Benny Sjostrand

Hi!

This patch changes the way the DAC volume are set on DSP SCB tasks. I would like to know
if maybe this fixes the "bass" problem that some users have experienced with the cs46xx driver.

Still some more attempts to have AC3 through IEC958, but no success yet ...

Summary:
- DAC volume mechanism rewrite (added cs46xx_dsp_set_dac_volume (...) in dsp_spos.c)
- IEC958 input volume mechanism rewrite (added cs46xx_dsp_set_iec958_volume (...) in dsp_spos.c)
- Enable IEC958 hw if not done in cs46xx_iec958_pre_open (...)
- Added "AC3 Mode Switch" in mixer, when enabled appropiate status bit's (non-audio, profesional) are set in IEC958 stream and PCM channel is locked to 48Khz
- Typo fix in constant name DSP_SDPIF... -> DSP_SPDIF...
- Some code cleanups

/Benny
----

diff --exclude=Makefile --exclude=CVS -Naur alsa-kernel/include/cs46xx_dsp_spos.h ../cvs/alsa-kernel/include/cs46xx_dsp_spos.h

cvs/alsa-kernel/include/cs46xx_dsp_spos.h renamed from include/cs46xx_dsp_spos.h +8 -5
@@ -60,9 +60,10 @@
 #define DSP_PCM_LFE_CHANNEL     4
 #define DSP_IEC958_CHANNEL      5
 
-#define DSP_SDPIF_STATUS_OUTPUT_ENABLED 1
-#define DSP_SDPIF_STATUS_PLAYBACK_OPEN  2
-#define DSP_SDPIF_STATUS_HW_ENABLED     4
+#define DSP_SPDIF_STATUS_OUTPUT_ENABLED 1
+#define DSP_SPDIF_STATUS_PLAYBACK_OPEN  2
+#define DSP_SPDIF_STATUS_HW_ENABLED     4
+#define DSP_SPDIF_STATUS_AC3_MODE       8
 
 struct _dsp_module_desc_t;
 
@@ -155,6 +156,8 @@
 
 	/* Main PCM playback mixer */
 	dsp_scb_descriptor_t * master_mix_scb;
+	u16 dac_volume_right;
+	u16 dac_volume_left;
 
 	/* Rear PCM playback mixer */
 	dsp_scb_descriptor_t * rear_mix_scb;
@@ -191,7 +194,8 @@
 	/* SPDIF status */
 	int spdif_status_out;
 	int spdif_status_in;
-	u32 spdif_input_volume;
+	u16 spdif_input_volume_right;
+	u16 spdif_input_volume_left;
 
 	/* SPDIF input sample rate converter */
 	dsp_scb_descriptor_t * spdif_in_src;
@@ -221,4 +225,3 @@
 } dsp_spos_instance_t;
 
 #endif /* __DSP_SPOS_H__ */
-

diff --exclude=Makefile --exclude=CVS -Naur alsa-kernel/pci/cs46xx/cs46xx_lib.c ../cvs/alsa-kernel/pci/cs46xx/cs46xx_lib.c

cvs/alsa-kernel/pci/cs46xx/cs46xx_lib.c renamed from pci/cs46xx/cs46xx_lib.c +142 -50
@@ -952,7 +952,9 @@
 			snd_cs46xx_playback_transfer(substream, 0);
 
 		/* raise playback volume */
-		snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0x80008000);
+		cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,
+					   chip->dsp_spos_instance->dac_volume_right,
+					   chip->dsp_spos_instance->dac_volume_left);
 #else
 		if (substream->runtime->periods != CS46XX_FRAGS)
 			snd_cs46xx_playback_transfer(substream, 0);
@@ -966,8 +968,9 @@
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-        /* mute channel */
-		snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0xffffffff);
+		/* mute channel */
+		cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,0,0);
+
 		if (!cpcm->pcm_channel->unlinked)
 			cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel);
 #else
@@ -1020,36 +1023,27 @@
 	return result;
 }
 
-static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
-					 snd_pcm_hw_params_t * hw_params)
+static int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm,
+				       int sample_rate) 
 {
-	/*cs46xx_t *chip = snd_pcm_substream_chip(substream);*/
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	cs46xx_pcm_t *cpcm;
-	int err;
-	cs46xx_t *chip = snd_pcm_substream_chip(substream);
-	int sample_rate = params_rate(hw_params);
-	int period_size = params_period_size(hw_params);
-	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
-
-#ifdef CONFIG_SND_CS46XX_NEW_DSP
-	down (&chip->spos_mutex);
-
-	snd_assert (cpcm->pcm_channel != NULL);
-
+	/* if this is the only PCMReaderSCB child under current
+	   SrcTask then there no need to re-create pcm-channel */
 	if ( cpcm->pcm_channel->src_scb->ref_count == 1 &&
 	     cpcm->pcm_channel->sample_rate != sample_rate &&
 	     /* never set a 0 khz sample rate */
 	     sample_rate) {
 		/* sample rate not set or we can reuse
 		   the same SRC*/
-
 		cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,sample_rate);
 		cpcm->pcm_channel->sample_rate = sample_rate;
 	} 
 
-	if (cpcm->pcm_channel->sample_rate != runtime->rate &&
-	    cpcm->pcm_channel->src_scb->ref_count != 1) {
+	/* if there is more then 1 PCMReaderSCB child's under current
+	   SrcTask then we must recreate channel */
+	if (cpcm->pcm_channel->sample_rate != sample_rate &&
+	    cpcm->pcm_channel->src_scb->ref_count != 1 &&
+	    /* never set a 0 khz sample rate */
+	    sample_rate) {
 		int unlinked = cpcm->pcm_channel->unlinked;
 		cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
 
@@ -1065,6 +1059,34 @@
 		cpcm->pcm_channel->sample_rate = sample_rate;
 	}
 
+	return 0;
+}
+static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
+					 snd_pcm_hw_params_t * hw_params)
+{
+	/*cs46xx_t *chip = snd_pcm_substream_chip(substream);*/
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	cs46xx_pcm_t *cpcm;
+	int err;
+	cs46xx_t *chip = snd_pcm_substream_chip(substream);
+	int sample_rate = params_rate(hw_params);
+	int period_size = params_period_size(hw_params);
+	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	down (&chip->spos_mutex);
+
+	snd_assert (cpcm->pcm_channel != NULL);
+
+	/* if IEC958 is opened in AC3 mode dont adjust SRCTask is not
+	   used so dont adjust sample rate */
+	if (cpcm->pcm_channel->pcm_channel_id != DSP_IEC958_CHANNEL ||
+	    !(chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)) {
+		if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
+			return -ENXIO;
+		}
+	}
+
 	if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size * 4)) {
 		 up (&chip->spos_mutex);
 		 return -EINVAL;
@@ -1825,7 +1847,7 @@
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 2;
 	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 32767;
+	uinfo->value.integer.max = 0x7fff;
 	return 0;
 }
 
@@ -1847,26 +1869,9 @@
 			    (0xffff - ucontrol->value.integer.value[1]));
 	unsigned int old = snd_cs46xx_peek(chip, reg);
 	int change = (old != val);
+
 	if (change) {
 		snd_cs46xx_poke(chip, reg, val);
-#ifdef CONFIG_SND_CS46XX_NEW_DSP
-		/* NOTE: this updates the current left and right volume
-		   that should be automatically updated by the DSP and
-		   not touched by the host. But for some strange reason
-		   the DSP only updates the right channel volume, so with
-		   this dirty hack we force updating the right and left
-		   channel volume. 
-		*/
-		snd_cs46xx_poke(chip, reg + 4, val);
-
-		/* shadow the SPDIF input volume */
-		if (reg == (ASYNCRX_SCB_ADDR + 0xE) << 2) {
-			/* FIXME: I known this is uggly ...
-			   any other suggestion ? 
-			*/
-			chip->dsp_spos_instance->spdif_input_volume = val;
-		}
-#endif
 	}
 
 	return change;
@@ -1874,6 +1879,57 @@
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 
+static int snd_cs46xx_vol_dac_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = chip->dsp_spos_instance->dac_volume_right;
+	ucontrol->value.integer.value[1] = chip->dsp_spos_instance->dac_volume_left;
+
+	return 0;
+}
+
+static int snd_cs46xx_vol_dac_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	int change = 0;
+
+	if (chip->dsp_spos_instance->dac_volume_right != ucontrol->value.integer.value[0] ||
+	    chip->dsp_spos_instance->dac_volume_left != ucontrol->value.integer.value[1]) {
+		cs46xx_dsp_set_dac_volume(chip,
+					  ucontrol->value.integer.value[0],
+					  ucontrol->value.integer.value[1]);
+		change = 1;
+	}
+
+	return change;
+}
+
+static int snd_cs46xx_vol_iec958_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_input_volume_right;
+	ucontrol->value.integer.value[1] = chip->dsp_spos_instance->spdif_input_volume_left;
+	return 0;
+}
+
+static int snd_cs46xx_vol_iec958_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	int change = 0;
+
+	if (chip->dsp_spos_instance->spdif_input_volume_right != ucontrol->value.integer.value[0] ||
+	    chip->dsp_spos_instance->spdif_input_volume_left != ucontrol->value.integer.value[1]) {
+		cs46xx_dsp_set_iec958_volume (chip,
+					      ucontrol->value.integer.value[0],
+					      ucontrol->value.integer.value[1]);
+		change = 1;
+	}
+
+	return change;
+}
+
 static int snd_mixer_boolean_info(snd_kcontrol_t *kcontrol, 
 				  snd_ctl_elem_info_t *uinfo)
 {
@@ -1891,7 +1947,7 @@
 	int reg = kcontrol->private_value;
 
 	if (reg == CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT)
-		ucontrol->value.integer.value[0] = (chip->dsp_spos_instance->spdif_status_out & DSP_SDPIF_STATUS_OUTPUT_ENABLED);
+		ucontrol->value.integer.value[0] = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
 	else
 		ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_in;
 
@@ -1907,13 +1963,13 @@
 	switch (kcontrol->private_value) {
 	case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT:
 		down (&chip->spos_mutex);
-		change = (chip->dsp_spos_instance->spdif_status_out & DSP_SDPIF_STATUS_OUTPUT_ENABLED);
+		change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
 		if (ucontrol->value.integer.value[0] && !change) 
 			cs46xx_dsp_enable_spdif_out(chip);
 		else if (change && !ucontrol->value.integer.value[0])
 			cs46xx_dsp_disable_spdif_out(chip);
 
-		res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SDPIF_STATUS_OUTPUT_ENABLED));
+		res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED));
 		up (&chip->spos_mutex);
 		break;
 	case CS46XX_MIXER_SPDIF_INPUT_ELEMENT:
@@ -1979,6 +2035,35 @@
 	return 0;
 }
 
+static int snd_cs46xx_iec958_ac3_mode_get(snd_kcontrol_t *kcontrol, 
+					  snd_ctl_elem_value_t *ucontrol) 
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	if (!ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) 
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	return 0;
+}
+
+static int snd_cs46xx_iec958_ac3_mode_put(snd_kcontrol_t *kcontrol, 
+                                      snd_ctl_elem_value_t *ucontrol) 
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	int old = ins->spdif_status_out;
+
+	if (ucontrol->value.integer.value[0]) 
+		ins->spdif_status_out |= DSP_SPDIF_STATUS_AC3_MODE;
+	else
+		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_AC3_MODE;
+
+	return (old != ins->spdif_status_out);
+}
+
 static int snd_cs46xx_pcm_capture_put(snd_kcontrol_t *kcontrol, 
                                       snd_ctl_elem_value_t *ucontrol)
 {
@@ -2013,7 +2098,7 @@
 }
 
 /*
- *	Game Theatre XP card - EGPIO[0] is used to select SDPIF input optical or coaxial.
+ *	Game Theatre XP card - EGPIO[0] is used to select SPDIF input optical or coaxial.
  */ 
 static int snd_herc_spdif_select_put(snd_kcontrol_t *kcontrol, 
                                        snd_ctl_elem_value_t *ucontrol)
@@ -2111,13 +2196,13 @@
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "DAC Volume",
 	.info = snd_cs46xx_vol_info,
+#ifndef CONFIG_SND_CS46XX_NEW_DSP
 	.get = snd_cs46xx_vol_get,
 	.put = snd_cs46xx_vol_put,
-
-#ifndef CONFIG_SND_CS46XX_NEW_DSP
 	.private_value = BA1_PVOL,
 #else
-	.private_value = (MASTERMIX_SCB_ADDR + 0xE) << 2,
+	.get = snd_cs46xx_vol_dac_get,
+	.put = snd_cs46xx_vol_dac_put,
 #endif
 },
 
@@ -2158,6 +2243,13 @@
 },
 {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC 958 AC3 Mode Switch",
+	.info = snd_mixer_boolean_info,
+	.get = snd_cs46xx_iec958_ac3_mode_get,
+	.put = snd_cs46xx_iec958_ac3_mode_put,
+},
+{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "IEC 958 Input Switch",
 	.info = snd_mixer_boolean_info,
 	.get = snd_cs46xx_iec958_get,
@@ -2168,8 +2260,8 @@
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "IEC 958 Input Volume",
 	.info = snd_cs46xx_vol_info,
-	.get = snd_cs46xx_vol_get,
-	.put = snd_cs46xx_vol_put,
+	.get = snd_cs46xx_vol_iec958_get,
+	.put = snd_cs46xx_vol_iec958_put,
 	.private_value = (ASYNCRX_SCB_ADDR + 0xE) << 2,
 },
 #endif

diff --exclude=Makefile --exclude=CVS -Naur alsa-kernel/pci/cs46xx/cs46xx_lib.h ../cvs/alsa-kernel/pci/cs46xx/cs46xx_lib.h

cvs/alsa-kernel/pci/cs46xx/cs46xx_lib.h renamed from pci/cs46xx/cs46xx_lib.h +2 -0
@@ -217,4 +217,6 @@
 							       int period_size);
 int                        cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip,
 							      int period_size);
+int                        cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left);
+int                        cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left);
 #endif /* __CS46XX_LIB_H__ */

diff --exclude=Makefile --exclude=CVS -Naur alsa-kernel/pci/cs46xx/dsp_spos.c ../cvs/alsa-kernel/pci/cs46xx/dsp_spos.c

cvs/alsa-kernel/pci/cs46xx/dsp_spos.c renamed from pci/cs46xx/dsp_spos.c +47 -4
@@ -257,7 +257,10 @@
 	ins->spdif_in_sample_rate = 48000;
 
 	/* maximize volume */
-	ins->spdif_input_volume = 0x80008000;
+	ins->dac_volume_right = 0x8000;
+	ins->dac_volume_left = 0x8000;
+	ins->spdif_input_volume_right = 0x8000;
+	ins->spdif_input_volume_left = 0x8000;
 
 	return ins;
 }
@@ -1549,7 +1552,7 @@
 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12));
 
 	/* monitor state */
-	ins->spdif_status_out |= DSP_SDPIF_STATUS_HW_ENABLED;
+	ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED;
 
 	return 0;
 }
@@ -1585,8 +1588,10 @@
 	cs46xx_src_link(chip,ins->spdif_in_src);
 
 	/* restore SPDIF input volume */
-	snd_cs46xx_poke(chip, (ASYNCRX_SCB_ADDR + 0xE) << 2, ins->spdif_input_volume);
-	snd_cs46xx_poke(chip, (ASYNCRX_SCB_ADDR + 0xF) << 2, ins->spdif_input_volume);
+	cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,
+				   ins->spdif_input_volume_right,
+				   ins->spdif_input_volume_left);
+
 	spin_unlock_irq(&chip->reg_lock);
 
 	/* set SPDIF input sample rate and unmute
@@ -1716,6 +1721,44 @@
 		snd_printk(KERN_ERR "dsp_spos: SPIOWriteTask not responding\n");
 		return -EBUSY;
 	}
+
+	return 0;
+}
+
+int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left)
+{
+	int i;
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	down(&chip->spos_mutex);
+
+	ins->dac_volume_right = right;
+	ins->dac_volume_left = left;
+
+	for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) {
+		if (ins->pcm_channels[i].active &&
+		    !ins->pcm_channels[i].unlinked) {
+			cs46xx_dsp_scb_set_volume (chip,ins->pcm_channels[i].pcm_reader_scb,
+						   right,left);
+			
+		}
+	}
+
+	up(&chip->spos_mutex);
+
+	return 0;
+}
+
+int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left) {
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	down(&chip->spos_mutex);
+	cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,
+				   right,left);
+
+	ins->spdif_input_volume_right = right;
+	ins->spdif_input_volume_left = left;
+	up(&chip->spos_mutex);
 
 	return 0;
 }

diff --exclude=Makefile --exclude=CVS -Naur alsa-kernel/pci/cs46xx/dsp_spos.h ../cvs/alsa-kernel/pci/cs46xx/dsp_spos.h

cvs/alsa-kernel/pci/cs46xx/dsp_spos.h renamed from pci/cs46xx/dsp_spos.h +10 -0
@@ -76,6 +76,7 @@
 #define MIX_SAMPLE_BUF2          0x2D00
 #define MIX_SAMPLE_BUF3          0x2E00
 #define MIX_SAMPLE_BUF4          0x2F00
+#define MIX_SAMPLE_BUF5          0x3000
 
 /* Task stack address */
 #define HFG_STACK                0x066A
@@ -127,6 +128,7 @@
 #define SCBfuncEntryPtr      0xA
 #define SRCCorPerGof         0x2
 #define SRCPhiIncr6Int26Frac 0xd
+#define SCBVolumeCtrl        0xe
 
 /* conf */
 #define UseASER1Input 1
@@ -190,6 +192,14 @@
 			(scb->address + SCBsubListPtr) << 2,
 			(scb->sub_list_ptr->address << 0x10) |
 			(scb->next_scb_ptr->address));	
+}
+
+static inline void cs46xx_dsp_scb_set_volume (cs46xx_t * chip,dsp_scb_descriptor_t * scb,
+					      u16 right,u16 left) {
+	unsigned int val = ((0xffff - right) << 16 | (0xffff - left));	
+
+	snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val);
+	snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val);
 }
 
 #endif /* __DSP_SPOS_H__ */

diff --exclude=Makefile --exclude=CVS -Naur alsa-kernel/pci/cs46xx/dsp_spos_scb_lib.c ../cvs/alsa-kernel/pci/cs46xx/dsp_spos_scb_lib.c

cvs/alsa-kernel/pci/cs46xx/dsp_spos_scb_lib.c renamed from pci/cs46xx/dsp_spos_scb_lib.c +42 -24
@@ -603,7 +603,7 @@
 		src_buffer_addr << 0x10,
 		0x04000000,
 		{ 
-			0xffff,0xffff,
+			0x8000,0x8000,
 			0xffff,0xffff
 		}
 	};
@@ -658,7 +658,7 @@
 		/* D */ 0,
 		{
 			/* E */ 0x8000,0x8000,
-			/* F */ 0x8000,0x8000
+			/* F */ 0xffff,0xffff
 		}
 	};
 
@@ -825,7 +825,7 @@
 		0x0058,0x0028,      /* Min Delta 7 dwords == 28 bytes */
 		/* : Max delta 25 dwords == 100 bytes */
 		0,hfg_scb_address,  /* Point to HFG task SCB */
-		0,0,				/* Initialize current Delta and Consumer ptr adjustment count */
+		0,0,		    /* Initialize current Delta and Consumer ptr adjustment count */
 		0,                  /* Initialize accumulated Phi to 0 */
 		0,0x2aab,           /* Const 1/3 */
 
@@ -840,13 +840,13 @@
 
 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
 		(asynch_buffer_address) << 0x10,  /* This should be automagically synchronized
-                                             to the producer pointer */
+                                                     to the producer pointer */
 
 		/* There is no correct initial value, it will depend upon the detected
 		   rate etc  */
 		0x18000000,                     /* Phi increment for approx 32k operation */
 		0x8000,0x8000,                  /* Volume controls are unused at this time */
-		0x8000,0x8000
+		0xffff,0xffff
 	};
 
 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
@@ -1114,7 +1114,13 @@
 		snd_assert(0);
 		break;
 	case DSP_IEC958_CHANNEL:
+		snd_assert (ins->asynch_tx_scb != NULL, return NULL);
 		mixer_scb = ins->asynch_tx_scb;
+		if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) {
+			snd_printdd ("IEC958 opened in AC3 mode\n");
+			/*src_scb = ins->asynch_tx_scb;
+			  ins->asynch_tx_scb->ref_count ++;*/
+		}
 		break;
 	default:
 		snd_assert (0);
@@ -1192,7 +1198,9 @@
 			return NULL;
 		}
 
-		cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
+		if (pcm_channel_id != DSP_IEC958_CHANNEL ||
+		    !(ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE))
+			cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
 
 		ins->nsrc_scb ++;
 	} 
@@ -1454,14 +1462,16 @@
 	spin_lock_irqsave(&chip->reg_lock, flags);
 
 	/* mute SCB */
-	snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0xffffffff);
+	/* cs46xx_dsp_scb_set_volume (chip,src,0,0); */
+
 	snd_cs46xx_poke(chip, (src->address + SRCCorPerGof) << 2,
 	  ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
 
 	snd_cs46xx_poke(chip, (src->address + SRCPhiIncr6Int26Frac) << 2, phiIncr);
 
 	/* raise volume */
-	snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0x80008000);
+	/* cs46xx_dsp_scb_set_volume (chip,src,0x7fff,0x7fff); */
+	
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
@@ -1495,7 +1505,7 @@
 	snd_assert (src->parent_scb_ptr != NULL,  return -EINVAL );
 
 	/* mute SCB */
-	snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0xffffffff);
+	cs46xx_dsp_scb_set_volume (chip,src,0,0);
 
 	_dsp_unlink_scb (chip,src);
 
@@ -1530,16 +1540,16 @@
 {
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
 
-	if ( ! (ins->spdif_status_out & DSP_SDPIF_STATUS_PLAYBACK_OPEN) ) {
+	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
 		cs46xx_dsp_enable_spdif_hw (chip);
 	}
 
 	/* dont touch anything if SPDIF is open */
-	if ( ins->spdif_status_out & DSP_SDPIF_STATUS_PLAYBACK_OPEN) {
+	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
 		/* when cs46xx_iec958_post_close(...) is called it
 		   will call this function if necesary depending on
 		   this bit */
-		ins->spdif_status_out |= DSP_SDPIF_STATUS_OUTPUT_ENABLED;
+		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
 
 		return -EBUSY;
 	}
@@ -1569,7 +1579,7 @@
 	if (!ins->spdif_pcm_input_scb) return -ENOMEM;
 
 	/* monitor state */
-	ins->spdif_status_out |= DSP_SDPIF_STATUS_OUTPUT_ENABLED;
+	ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
 
 	return 0;
 }
@@ -1579,8 +1589,8 @@
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
 
 	/* dont touch anything if SPDIF is open */
-	if ( ins->spdif_status_out & DSP_SDPIF_STATUS_PLAYBACK_OPEN) {
-		ins->spdif_status_out &= ~DSP_SDPIF_STATUS_OUTPUT_ENABLED;
+	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
+		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
 		return -EBUSY;
 	}
 
@@ -1600,7 +1610,7 @@
 	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
 
 	/* monitor state */
-	ins->spdif_status_out  &= ~DSP_SDPIF_STATUS_OUTPUT_ENABLED;
+	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
 
 
 	return 0;
@@ -1610,12 +1620,17 @@
 {
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
 
-	if ( ins->spdif_status_out & DSP_SDPIF_STATUS_OUTPUT_ENABLED ) {
+	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
 		/* remove AsynchFGTxSCB and and PCMSerialInput_II */
 		cs46xx_dsp_disable_spdif_out (chip);
 
 		/* save state */
-		ins->spdif_status_out |= DSP_SDPIF_STATUS_OUTPUT_ENABLED;
+		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+	}
+	
+	/* if not enabled already */
+	if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
+		cs46xx_dsp_enable_spdif_hw (chip);
 	}
 
 	/* Create the asynch. transfer task  for playback */
@@ -1625,10 +1640,12 @@
 								ins->master_mix_scb,
 								SCB_ON_PARENT_NEXT_SCB);
 
-	/* cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 15) | 
-	   (1 << 14) | (1 << 2) | (1 << 3)); */
 
-	ins->spdif_status_out  |= DSP_SDPIF_STATUS_PLAYBACK_OPEN;
+	if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) 
+		/* set left (13), right validity bit (12) , and non-audio(1) and profsional bit (0) */
+		cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12) | (1 << 1) | 1);
+
+	ins->spdif_status_out  |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
 
 	return 0;
 }
@@ -1639,16 +1656,17 @@
 
 	snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
 
-	ins->spdif_status_out  &= ~DSP_SDPIF_STATUS_PLAYBACK_OPEN;
+	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
 
-	/*cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12));*/
+	/* restore settings */
+	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12));
 
 	/* deallocate stuff */
 	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
 	ins->asynch_tx_scb = NULL;
 
 	/* restore state */
-	if ( ins->spdif_status_out & DSP_SDPIF_STATUS_OUTPUT_ENABLED ) {
+	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
 		cs46xx_dsp_enable_spdif_out (chip);
 	}
 
Signature · 6 lines
"I am neither especially clever nor especially 
gifted. I am only very, very curious." Einstein.

Peter Good
Pete's Internet Services
GnuPG Public Key: http://www.petesinternet.net/public.gpg
#1 lore raw
Quoted 9 lines

------------------------------------------------------------------------

Ok, that's fixed the bass problem I had here.
One thing though. Benny, do you have any idea what these values "should" be?

But I still dont understand the problem. And reports are not at all consequent ...

Quoted 3 lines

iec958:AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2

I guess you need to add in .asoundrc:
iec958 {
type hw
card 0
device 2
}

Then maybe someone knows what xine uses the AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2 values to, do they need to interfaces to the lowlevel driver ???

/Benny

-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf

#2 lore raw
Quoted 22 lines · Benny Sjostrand
Quoted 9 lines

------------------------------------------------------------------------

Ok, that's fixed the bass problem I had here.
One thing though. Benny, do you have any idea what these values "should" be?

But I still dont understand the problem. And reports are not at all consequent ...

Quoted 3 lines

iec958:AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2

I guess you need to add in .asoundrc:
iec958 {
type hw
card 0
device 2
}

Quoted 3 lines

Then maybe someone knows what xine uses the AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2 values to, do they need to interfaces to the lowlevel driver ???

It's first 32-bits to setup the channel status block in the S/PDIF stream. The main job is to tell the remote receiver, that data are 'non-audio' (bit 1 = 1).

Jaroslav

-----
Jaroslav Kysela <[email protected]>
Linux Kernel Sound Maintainer
ALSA Project, SuSE Labs

-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf

#3 lore raw
Quoted 7 lines
Quoted 3 lines

Then maybe someone knows what xine uses the AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2 values to, do they need to interfaces to the lowlevel driver ???

It's first 32-bits to setup the channel status block in the S/PDIF stream. The main job is to tell the remote receiver, that data are 'non-audio' (bit 1 = 1).

My first guess, how is this values interfaced to the lowlevel driver ? I believe that I dont need to have any "AC3 Mode" switch in the mixer if there already is way to know if application is opening the IEC958 port for AC3/raw-data.

/Benny

-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf

#4 lore raw
Quoted 4 lines · Benny Sjostrand
Quoted 4 lines
Quoted 3 lines

Then maybe someone knows what xine uses the AES0=0x6,AES1=0x82,AES2=0x0,AES3=0x2 values to, do they need to interfaces to the lowlevel driver ???

Quoted 8 lines
Quoted 3 lines

It's first 32-bits to setup the channel status block in the S/PDIF stream. The main job is to tell the remote receiver, that data are 'non-audio' (bit 1 = 1).

My first guess, how is this values interfaced to the lowlevel driver ? I believe that I dont need to have any "AC3 Mode" switch in the mixer if there already is way to know if application is opening the IEC958 port for AC3/raw-data.

It's better to have one PCM device dedicated to a raw S/PDIF stream. Then we have controls to obtain available channel status block bits and global / PCM settings:

  IEC958 [...] [Playback|Capture] Default       /* default or global value - read/write */
  IEC958 [...] [Playback|Capture] Mask          /* consumer and professional mask */
  IEC958 [...] [Playback|Capture] Con Mask      /* consumer mask */
  IEC958 [...] [Playback|Capture] Pro Mask      /* professional mask */
  IEC958 [...] [Playback|Capture] PCM Stream    /* the settings assigned to a PCM stream */

The behaviour implemented in drivers is:

- initialize IEC958 channel status block with value SNDRV_PCM_DEFAULT_CON_SPDIF
- raw S/PDIF open: copy default settings to local PCM settings
- (application optional: modify PCM settings - 'IEC958 Playback PCM Stream')
- raw S/PDIF close: return back the global settings

It seems quite complicated, but with many hardware we have 'mixed mode' when we need to output a final (mixed from many resources) stream with some IEC958 setup and do also ac3-forward (send raw S/PDIF stream). The settings for ac3-forward is valid only for one session (open/close) of course.

Jaroslav

-----
Jaroslav Kysela <[email protected]>
Linux Kernel Sound Maintainer
ALSA Project, SuSE Labs

-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf