Parent repository is http://linux-sound.bkbits.net/linux-sound
======== ChangeSet 1.1554 ========
D 1.1554 04/02/22 12:35:06-08:00 akpm@mnm.(none) 37284 37280 0/0/1
P ChangeSet
C Merge mnm.(none):/usr/src/bk25 into mnm.(none):/usr/src/bk-alsa
------------------------------------------------

diff -Nru a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
--- a/Documentation/sound/alsa/ALSA-Configuration.txt	Sun Feb 22 12:36:42 2004
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt	Sun Feb 22 12:36:42 2004
@@ -692,6 +692,15 @@
 
     The power-management is supported.
 
+  Module snd-mixart
+  -----------------
+
+    Module for Digigram miXart8 soundcards.
+
+    Module supports multiple cards.
+    Note: One miXart8 board will be represented as 4 alsa cards.
+          See MIXART.txt for details.
+
   Module snd-mpu401
   -----------------
 
diff -Nru a/Documentation/sound/alsa/MIXART.txt b/Documentation/sound/alsa/MIXART.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/sound/alsa/MIXART.txt	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,96 @@
+    Alsa driver for Digigram miXart8 and miXart8AES/EBU soundcards
+	    Digigram <alsa@digigram.com>
+
+
+GENERAL
+=======
+
+The miXart8 is a multichannel audio processing and mixing soundcard
+that has 4 stereo audio inputs and 4 stereo audio outputs.
+The miXart8AES/EBU is the same with a add-on card that offers further
+4 digital stereo audio inputs and outputs.
+Furthermore the add-on card offers external clock synchronisation
+(AES/EBU, Word Clock, Time Code and Video Synchro)
+
+The mainboard has a PowerPC that offers onboard mpeg encoding and
+decoding, samplerate conversions and various effects.
+
+The driver don't work properly at all until the certain firmwares
+are loaded, i.e. no PCM nor mixer devices will appear.
+Use the mixartloader that can be found in the alsa-tools package.
+
+
+VERSION 0.1.0
+=============
+
+One miXart8 board will be represented as 4 alsa cards, each with 1
+stereo analog capture 'pcm0c' and 1 stereo analog playback 'pcm0p' device.
+With a miXart8AES/EBU there is in addition 1 stereo digital input
+'pcm1c' and 1 stereo digital output 'pcm1p' per card.
+
+Formats
+-------
+U8, S16_LE, S16_BE, S24_3LE, S24_3BE, FLOAT_LE, FLOAT_BE
+Sample rates : 8000 - 48000 Hz continously
+
+Playback
+--------
+For instance the playback devices are configured to have max. 4
+substreams performing hardware mixing. This could be changed to a
+maximum of 24 substreams if wished.
+Mono files will be played on the left and right channel. Each channel
+can be muted for each stream to use 8 analog/digital outputs seperately.
+
+Capture
+-------
+There is one substream per capture device. For instance only stereo
+formats are supported.
+
+Mixer
+-----
+<Master> and <Master Capture> : analog volume control of playback and capture PCM.
+<PCM 0-3> and <PCM Capture> : digital volume control of each analog substream.
+<AES 0-3> and <AES Capture> : digital volume control of each AES/EBU substream.
+<Monitoring> : Loopback from 'pcm0c' to 'pcm0p' with digital volume
+and mute control.
+
+Rem : for best audio quality try to keep a 0 attenuation on the PCM
+and AES volume controls which is set by 219 in the range from 0 to 255
+(about 86% with alsamixer)
+
+
+NOT YET IMPLEMENTED
+===================
+
+- external clock support (AES/EBU, Word Clock, Time Code, Video Sync)
+- MPEG audio formats
+- mono record
+- on-board effects and samplerate conversions
+- linked streams
+
+
+FIRMWARE
+========
+
+For loading the firmware automatically after the module is loaded, use
+the post-install command.  For example, add the following entry to
+/etc/modprobe.conf for miXart driver:
+
+	install snd-mixart /sbin/modprobe --first-time -i snd-mixart && \
+			   /usr/bin/mixartloader
+(for 2.2/2.4 kernels, add "post-install snd-mixart /usr/bin/vxloader" to
+ /etc/modules.conf, instead.)
+
+The firmware binaries are installed on /usr/share/alsa/firmware
+(or /usr/local/share/alsa/firmware, depending to the prefix option of
+configure).  There will be a miXart.conf file, which define the dsp image
+files.
+
+The firmware files are copyright by Digigram SA
+
+
+COPYRIGHT
+=========
+
+Copyright (c) 2003 Digigram SA <alsa@digigram.com>
+Distributalbe under GPL.
diff -Nru a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
--- a/include/sound/pcm_oss.h	Sun Feb 22 12:36:42 2004
+++ b/include/sound/pcm_oss.h	Sun Feb 22 12:36:42 2004
@@ -50,6 +50,7 @@
 	unsigned int maxfrags;
 	unsigned int subdivision;		/* requested subdivision */
 	size_t period_bytes;			/* requested period size */
+	size_t period_frames;			/* period frames for poll */
 	size_t period_ptr;			/* actual write pointer to period */
 	unsigned int periods;
 	size_t buffer_bytes;			/* requested buffer size */
diff -Nru a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile	Sun Feb 22 12:36:42 2004
+++ b/sound/core/Makefile	Sun Feb 22 12:36:42 2004
@@ -107,5 +107,6 @@
 obj-$(CONFIG_SND_VXP440) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o
 obj-$(CONFIG_SND_VX222) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o
 obj-$(CONFIG_SND_BT87X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o
+obj-$(CONFIG_SND_MIXART) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o
 
 obj-m := $(sort $(obj-m))
diff -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
--- a/sound/core/oss/pcm_oss.c	Sun Feb 22 12:36:42 2004
+++ b/sound/core/oss/pcm_oss.c	Sun Feb 22 12:36:43 2004
@@ -133,6 +133,15 @@
 	return (runtime->oss.buffer_bytes * frames) / buffer_size;
 }
 
+static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream);
+	if (buffer_size == runtime->oss.buffer_bytes)
+		return bytes_to_frames(runtime, bytes);
+	return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
+}
+
 static int snd_pcm_oss_format_from(int format)
 {
 	switch (format) {
@@ -254,6 +263,7 @@
 
 	snd_assert(oss_period_size >= 16, return -EINVAL);
 	runtime->oss.period_bytes = oss_period_size;
+	runtime->oss.period_frames = 1;
 	runtime->oss.periods = oss_periods;
 	return 0;
 }
@@ -511,6 +521,8 @@
 	if (runtime->dma_area)
 		snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
 
+	runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
+
 	err = 0;
 failure:
 	if (sw_params)
@@ -2098,7 +2110,7 @@
 	if (atomic_read(&runtime->mmap_count))
 		return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
 	else
-		return snd_pcm_playback_ready(substream);
+		return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
 }
 
 static int snd_pcm_oss_capture_ready(snd_pcm_substream_t *substream)
@@ -2107,7 +2119,7 @@
 	if (atomic_read(&runtime->mmap_count))
 		return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
 	else
-		return snd_pcm_capture_ready(substream);
+		return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
 }
 
 static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
diff -Nru a/sound/core/pcm.c b/sound/core/pcm.c
--- a/sound/core/pcm.c	Sun Feb 22 12:36:43 2004
+++ b/sound/core/pcm.c	Sun Feb 22 12:36:43 2004
@@ -327,8 +327,9 @@
 		snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
 		snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels);	
 		snd_iprintf(buffer, "OSS rate: %u\n", runtime->oss.rate);
-		snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes);	
+		snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes);
 		snd_iprintf(buffer, "OSS periods: %u\n", runtime->oss.periods);
+		snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
 	}
 #endif
 	snd_pcm_stream_unlock_irq(substream);
diff -Nru a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
--- a/sound/core/seq/oss/seq_oss_midi.c	Sun Feb 22 12:36:42 2004
+++ b/sound/core/seq/oss/seq_oss_midi.c	Sun Feb 22 12:36:42 2004
@@ -491,7 +491,7 @@
 			}
 		}
 	}
-	snd_seq_oss_midi_close(dp, dev);
+	// snd_seq_oss_midi_close(dp, dev);
 	snd_use_lock_free(&mdev->use_lock);
 }
 
diff -Nru a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
--- a/sound/core/seq/oss/seq_oss_synth.c	Sun Feb 22 12:36:42 2004
+++ b/sound/core/seq/oss/seq_oss_synth.c	Sun Feb 22 12:36:42 2004
@@ -410,6 +410,8 @@
 		if (midi_synth_dev.opened <= 0)
 			return;
 		snd_seq_oss_midi_reset(dp, info->midi_mapped);
+		/* reopen the device */
+		snd_seq_oss_midi_close(dp, dev);
 		if (snd_seq_oss_midi_open(dp, info->midi_mapped,
 					  dp->file_mode) < 0) {
 			midi_synth_dev.opened--;
diff -Nru a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
--- a/sound/core/seq/seq_fifo.c	Sun Feb 22 12:36:42 2004
+++ b/sound/core/seq/seq_fifo.c	Sun Feb 22 12:36:42 2004
@@ -171,10 +171,12 @@
 {
 	snd_seq_event_cell_t *cell;
 	unsigned long flags;
+	wait_queue_t wait;
 
 	snd_assert(f != NULL, return -EINVAL);
 
 	*cellp = NULL;
+	init_waitqueue_entry(&wait, current);
 	spin_lock_irqsave(&f->lock, flags);
 	while ((cell = fifo_cell_out(f)) == NULL) {
 		if (nonblock) {
@@ -182,17 +184,19 @@
 			spin_unlock_irqrestore(&f->lock, flags);
 			return -EAGAIN;
 		}
-		spin_unlock(&f->lock);
-		interruptible_sleep_on(&f->input_sleep);
-		spin_lock(&f->lock);
-
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&f->input_sleep, &wait);
+		spin_unlock_irq(&f->lock);
+		schedule();
+		spin_lock_irq(&f->lock);
+		remove_wait_queue(&f->input_sleep, &wait);
 		if (signal_pending(current)) {
 			spin_unlock_irqrestore(&f->lock, flags);
 			return -ERESTARTSYS;
 		}
 	}
-	*cellp = cell;
 	spin_unlock_irqrestore(&f->lock, flags);
+	*cellp = cell;
 
 	return 0;
 }
diff -Nru a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
--- a/sound/core/seq/seq_memory.c	Sun Feb 22 12:36:42 2004
+++ b/sound/core/seq/seq_memory.c	Sun Feb 22 12:36:42 2004
@@ -220,12 +220,14 @@
 	snd_seq_event_cell_t *cell;
 	unsigned long flags;
 	int err = -EAGAIN;
+	wait_queue_t wait;
 
 	if (pool == NULL)
 		return -EINVAL;
 
 	*cellp = NULL;
 
+	init_waitqueue_entry(&wait, current);
 	spin_lock_irqsave(&pool->lock, flags);
 	if (pool->ptr == NULL) {	/* not initialized */
 		snd_printd("seq: pool is not initialized\n");
@@ -234,9 +236,12 @@
 	}
 	while (pool->free == NULL && ! nonblock && ! pool->closing) {
 
-		spin_unlock(&pool->lock);
-		interruptible_sleep_on(&pool->output_sleep);
-		spin_lock(&pool->lock);
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&pool->output_sleep, &wait);
+		spin_unlock_irq(&pool->lock);
+		schedule();
+		spin_lock_irq(&pool->lock);
+		remove_wait_queue(&pool->output_sleep, &wait);
 		/* interrupted? */
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
diff -Nru a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
--- a/sound/drivers/vx/vx_core.c	Sun Feb 22 12:36:43 2004
+++ b/sound/drivers/vx/vx_core.c	Sun Feb 22 12:36:43 2004
@@ -355,11 +355,12 @@
  */
 int vx_send_msg(vx_core_t *chip, struct vx_rmh *rmh)
 {
+	unsigned long flags;
 	int err;
 
-	spin_lock_bh(&chip->lock);
+	spin_lock_irqsave(&chip->lock, flags);
 	err = vx_send_msg_nolock(chip, rmh);
-	spin_unlock_bh(&chip->lock);
+	spin_unlock_irqrestore(&chip->lock, flags);
 	return err;
 }
 
@@ -414,11 +415,12 @@
  */
 int vx_send_rih(vx_core_t *chip, int cmd)
 {
+	unsigned long flags;
 	int err;
 
-	spin_lock_bh(&chip->lock);
+	spin_lock_irqsave(&chip->lock, flags);
 	err = vx_send_rih_nolock(chip, cmd);
-	spin_unlock_bh(&chip->lock);
+	spin_unlock_irqrestore(&chip->lock, flags);
 	return err;
 }
 
diff -Nru a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
--- a/sound/drivers/vx/vx_mixer.c	Sun Feb 22 12:36:42 2004
+++ b/sound/drivers/vx/vx_mixer.c	Sun Feb 22 12:36:42 2004
@@ -919,7 +919,7 @@
 	if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0)
 		return err;
 	/* VU, peak, saturation meters */
-	for (c = 0; c < 1; c++) {
+	for (c = 0; c < 2; c++) {
 		static char *dir[2] = { "Output", "Input" };
 		for (i = 0; i < chip->hw->num_ins; i++) {
 			int val = (i * 2) | (c << 8);
diff -Nru a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
--- a/sound/drivers/vx/vx_pcm.c	Sun Feb 22 12:36:42 2004
+++ b/sound/drivers/vx/vx_pcm.c	Sun Feb 22 12:36:42 2004
@@ -561,7 +561,7 @@
 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
 	.rate_min =		5000,
 	.rate_max =		48000,
-	.channels_min =		2,
+	.channels_min =		1,
 	.channels_max =		2,
 	.buffer_bytes_max =	(128*1024),
 	.period_bytes_min =	126,
@@ -958,7 +958,7 @@
 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
 	.rate_min =		5000,
 	.rate_max =		48000,
-	.channels_min =		2,
+	.channels_min =		1,
 	.channels_max =		2,
 	.buffer_bytes_max =	(128*1024),
 	.period_bytes_min =	126,
diff -Nru a/sound/pci/Kconfig b/sound/pci/Kconfig
--- a/sound/pci/Kconfig	Sun Feb 22 12:36:42 2004
+++ b/sound/pci/Kconfig	Sun Feb 22 12:36:42 2004
@@ -55,6 +55,12 @@
 	help
 	  Say 'Y' or 'M' to include support for Korg 1212IO.
 
+config SND_MIXART
+	tristate "Digigram miXart"
+	depends on SND
+	help
+	  Say 'Y' or 'M' to include support for Digigram miXart soundcard.
+
 config SND_NM256
 	tristate "NeoMagic NM256AV/ZX"
 	depends on SND
diff -Nru a/sound/pci/Makefile b/sound/pci/Makefile
--- a/sound/pci/Makefile	Sun Feb 22 12:36:42 2004
+++ b/sound/pci/Makefile	Sun Feb 22 12:36:42 2004
@@ -38,4 +38,16 @@
 obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o
 obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o
 
-obj-$(CONFIG_SND) += ac97/ ali5451/ cs46xx/ emu10k1/ korg1212/ nm256/ rme9652/ trident/ ymfpci/ ice1712/ vx222/
+obj-$(CONFIG_SND) += \
+	ac97/ \
+	ali5451/ \
+	cs46xx/ \
+	emu10k1/ \
+	ice1712/ \
+	korg1212/ \
+	mixart/ \
+	nm256/ \
+	rme9652/ \
+	trident/ \
+	ymfpci/ \
+	vx222/
diff -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
--- a/sound/pci/ac97/ac97_codec.c	Sun Feb 22 12:36:42 2004
+++ b/sound/pci/ac97/ac97_codec.c	Sun Feb 22 12:36:42 2004
@@ -100,6 +100,7 @@
 { 0x41445361, 0xffffffff, "AD1886",		patch_ad1886,	NULL },
 { 0x41445362, 0xffffffff, "AD1887",		patch_ad1881,	NULL },
 { 0x41445363, 0xffffffff, "AD1886A",		patch_ad1881,	NULL },
+{ 0x41445368, 0xffffffff, "AD1888",		patch_ad1888,	NULL },
 { 0x41445370, 0xffffffff, "AD1980",		patch_ad1980,	NULL },
 { 0x41445372, 0xffffffff, "AD1981A",		patch_ad1981a,	NULL },
 { 0x41445374, 0xffffffff, "AD1981B",		patch_ad1981b,	NULL },
@@ -1526,38 +1527,40 @@
 	return 0;
 }
 
-static int snd_ac97_test_rate(ac97_t *ac97, int reg, int rate)
+static int snd_ac97_test_rate(ac97_t *ac97, int reg, int shadow_reg, int rate)
 {
 	unsigned short val;
 	unsigned int tmp;
 
 	tmp = ((unsigned int)rate * ac97->bus->clock) / 48000;
 	snd_ac97_write_cache(ac97, reg, tmp & 0xffff);
+	if (shadow_reg)
+		snd_ac97_write_cache(ac97, shadow_reg, tmp & 0xffff);
 	val = snd_ac97_read(ac97, reg);
 	return val == (tmp & 0xffff);
 }
 
-static void snd_ac97_determine_rates(ac97_t *ac97, int reg, unsigned int *r_result)
+static void snd_ac97_determine_rates(ac97_t *ac97, int reg, int shadow_reg, unsigned int *r_result)
 {
 	unsigned int result = 0;
 
 	/* test a non-standard rate */
-	if (snd_ac97_test_rate(ac97, reg, 11000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11000))
 		result |= SNDRV_PCM_RATE_CONTINUOUS;
 	/* let's try to obtain standard rates */
-	if (snd_ac97_test_rate(ac97, reg, 8000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 8000))
 		result |= SNDRV_PCM_RATE_8000;
-	if (snd_ac97_test_rate(ac97, reg, 11025))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11025))
 		result |= SNDRV_PCM_RATE_11025;
-	if (snd_ac97_test_rate(ac97, reg, 16000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 16000))
 		result |= SNDRV_PCM_RATE_16000;
-	if (snd_ac97_test_rate(ac97, reg, 22050))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 22050))
 		result |= SNDRV_PCM_RATE_22050;
-	if (snd_ac97_test_rate(ac97, reg, 32000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 32000))
 		result |= SNDRV_PCM_RATE_32000;
-	if (snd_ac97_test_rate(ac97, reg, 44100))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 44100))
 		result |= SNDRV_PCM_RATE_44100;
-	if (snd_ac97_test_rate(ac97, reg, 48000))
+	if (snd_ac97_test_rate(ac97, reg, shadow_reg, 48000))
 		result |= SNDRV_PCM_RATE_48000;
 	*r_result = result;
 }
@@ -1866,8 +1869,8 @@
 	if (ac97->ext_id & 0x0189)	/* L/R, MIC, SDAC, LDAC VRA support */
 		snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, ac97->ext_id & 0x0189);
 	if (ac97->ext_id & AC97_EI_VRA) {	/* VRA support */
-		snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_FRONT_DAC]);
-		snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, &ac97->rates[AC97_RATES_ADC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, 0, &ac97->rates[AC97_RATES_FRONT_DAC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, 0, &ac97->rates[AC97_RATES_ADC]);
 	} else {
 		ac97->rates[AC97_RATES_FRONT_DAC] = SNDRV_PCM_RATE_48000;
 		ac97->rates[AC97_RATES_ADC] = SNDRV_PCM_RATE_48000;
@@ -1884,16 +1887,16 @@
 						SNDRV_PCM_RATE_32000;
 	}
 	if (ac97->ext_id & AC97_EI_VRM) {	/* MIC VRA support */
-		snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, &ac97->rates[AC97_RATES_MIC_ADC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, 0, &ac97->rates[AC97_RATES_MIC_ADC]);
 	} else {
 		ac97->rates[AC97_RATES_MIC_ADC] = SNDRV_PCM_RATE_48000;
 	}
 	if (ac97->ext_id & AC97_EI_SDAC) {	/* SDAC support */
-		snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]);
 		ac97->scaps |= AC97_SCAP_SURROUND_DAC;
 	}
 	if (ac97->ext_id & AC97_EI_LDAC) {	/* LDAC support */
-		snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]);
+		snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]);
 		ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
 	}
 	/* additional initializations */
@@ -2112,6 +2115,8 @@
 {
 	/* FIXME: error checks.. */
 	if (remove_master) {
+		if (ctl_find(ac97, "Headphone Playback Switch") == NULL)
+			return 0;
 		snd_ac97_remove_ctl(ac97, "Master Playback Switch");
 		snd_ac97_remove_ctl(ac97, "Master Playback Volume");
 	} else {
diff -Nru a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
--- a/sound/pci/ac97/ac97_patch.c	Sun Feb 22 12:36:43 2004
+++ b/sound/pci/ac97/ac97_patch.c	Sun Feb 22 12:36:43 2004
@@ -652,7 +652,7 @@
 
 static const snd_kcontrol_new_t snd_ac97_controls_ad1885[] = {
 	AC97_SINGLE("Digital Mono Direct", AC97_AD_MISC, 11, 1, 0),
-	AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0),
+	/* AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0), */ /* seems problematic */
 	AC97_SINGLE("Low Power Mixer", AC97_AD_MISC, 14, 1, 0),
 	AC97_SINGLE("Zero Fill DAC", AC97_AD_MISC, 15, 1, 0),
 };
@@ -682,6 +682,9 @@
 	jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF);
 	snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300);
 
+	/* set default */
+	snd_ac97_write_cache(ac97, AC97_AD_MISC, 0x0404);
+
 	ac97->build_ops = &patch_ad1885_build_ops;
 	return 0;
 }
@@ -799,7 +802,7 @@
 	return 0;
 }
 
-static int snd_ac97_ad1980_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+static int snd_ac97_ad1888_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 1;
@@ -808,7 +811,7 @@
 	return 0;
 }
 
-static int snd_ac97_ad1980_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
+static int snd_ac97_ad1888_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
@@ -818,7 +821,7 @@
 	return 0;
 }
 
-static int snd_ac97_ad1980_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ac97_ad1888_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
@@ -829,7 +832,7 @@
 				    AC97_AD198X_LOSEL | AC97_AD198X_HPSEL, val);
 }
 
-static int snd_ac97_ad1980_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+static int snd_ac97_ad1888_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"};
 
@@ -842,7 +845,7 @@
 	return 0;
 }
 
-static int snd_ac97_ad1980_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
+static int snd_ac97_ad1888_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
@@ -855,7 +858,7 @@
 	return 0;
 }
 
-static int snd_ac97_ad1980_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
@@ -871,51 +874,47 @@
 				    AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val);
 }
 
-static const snd_kcontrol_new_t snd_ac97_ad1980_controls[] = {
+static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Exchange Front/Surround",
-		.info = snd_ac97_ad1980_lohpsel_info,
-		.get = snd_ac97_ad1980_lohpsel_get,
-		.put = snd_ac97_ad1980_lohpsel_put
+		.info = snd_ac97_ad1888_lohpsel_info,
+		.get = snd_ac97_ad1888_lohpsel_get,
+		.put = snd_ac97_ad1888_lohpsel_put
 	},
 	AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Downmix",
-		.info = snd_ac97_ad1980_downmix_info,
-		.get = snd_ac97_ad1980_downmix_get,
-		.put = snd_ac97_ad1980_downmix_put
+		.info = snd_ac97_ad1888_downmix_info,
+		.get = snd_ac97_ad1888_downmix_get,
+		.put = snd_ac97_ad1888_downmix_put
 	},
 	AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0),
 	AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0),
 };
 
-static int patch_ad1980_specific(ac97_t *ac97)
+static int patch_ad1888_specific(ac97_t *ac97)
 {
-	int err;
-
 	/* rename 0x04 as "Master" and 0x02 as "Master Surround" */
 	snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch");
 	snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume");
 	snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch");
 	snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume");
-	if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0)
-		return err;
-	return patch_build_controls(ac97, snd_ac97_ad1980_controls, ARRAY_SIZE(snd_ac97_ad1980_controls));
+	return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls));
 }
 
-static struct snd_ac97_build_ops patch_ad1980_build_ops = {
+static struct snd_ac97_build_ops patch_ad1888_build_ops = {
 	.build_post_spdif = patch_ad198x_post_spdif,
-	.build_specific = patch_ad1980_specific
+	.build_specific = patch_ad1888_specific
 };
 
-int patch_ad1980(ac97_t * ac97)
+int patch_ad1888(ac97_t * ac97)
 {
 	unsigned short misc;
 	
 	patch_ad1881(ac97);
-	ac97->build_ops = &patch_ad1980_build_ops;
+	ac97->build_ops = &patch_ad1888_build_ops;
 	/* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */
 	/* it seems that most vendors connect line-out connector to headphone out of AC'97 */
 	/* AD-compatible mode */
@@ -930,6 +929,27 @@
 	return 0;
 }
 
+static int patch_ad1980_specific(ac97_t *ac97)
+{
+	int err;
+
+	if ((err = patch_ad1888_specific(ac97)) < 0)
+		return err;
+	return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1);
+}
+
+static struct snd_ac97_build_ops patch_ad1980_build_ops = {
+	.build_post_spdif = patch_ad198x_post_spdif,
+	.build_specific = patch_ad1980_specific
+};
+
+int patch_ad1980(ac97_t * ac97)
+{
+	patch_ad1888(ac97);
+	ac97->build_ops = &patch_ad1980_build_ops;
+	return 0;
+}
+
 static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = {
 	AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0),
 	AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
@@ -1014,8 +1034,7 @@
                                       ucontrol->value.integer.value[0] ? (1 << 10) : 0);
         if (change) {
                 /* GPIO0 write for mic */
-                snd_ac97_update_bits(ac97, 0x76, 0x01,
-                                     ucontrol->value.integer.value[0] ? 0 : 0x01);
+                snd_ac97_update_bits(ac97, 0x76, 0x01, 0x01);
                 /* GPIO0 high for mic */
                 snd_ac97_update_bits(ac97, 0x78, 0x100,
                                      ucontrol->value.integer.value[0] ? 0 : 0x100);
@@ -1092,10 +1111,7 @@
 		mic_off = snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10);
 		/* GPIO0 direction */
 		val = snd_ac97_read(ac97, AC97_ALC650_GPIO_SETUP);
-		if (mic_off)
-			val &= ~0x01;
-		else
-			val |= 0x01;
+		val |= 0x01;
 		snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_SETUP, val);
 		val = snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS);
 		if (mic_off)
@@ -1111,10 +1127,36 @@
 	return 0;
 }
 
+static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+        ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
+        return 0;
+}
+
+static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+        int change;
+
+	snd_ac97_update_bits(ac97, 0x7a, 1 << 12, /* misc control; vrefout disable */
+			     ucontrol->value.integer.value[0] ? (1 << 12) : 0);
+	change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
+				      ucontrol->value.integer.value[0] ? (1 << 10) : 0);
+	return change;
+}
+
+
 static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = {
 	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
 	AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
-	AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic As Center/LFE",
+		.info = snd_ac97_info_single,
+		.get = snd_ac97_alc655_mic_get,
+		.put = snd_ac97_alc655_mic_put,
+	},
 };
 
 static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -1187,15 +1229,21 @@
 
 int patch_alc655(ac97_t * ac97)
 {
+	unsigned int val;
+
 	ac97->spec.dev_flags = (ac97->id == 0x414c4780); /* ALC658 */
 
 	ac97->build_ops = &patch_alc655_ops;
 
-	/* enable spdif in */
-	snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
-			     snd_ac97_read(ac97, AC97_ALC650_MULTICH) | 0x8000);
-	snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
-			     snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x02);
+	/* adjust default values */
+	val = snd_ac97_read(ac97, 0x7a); /* misc control */
+	val |= (1 << 1); /* spdif input pin */
+	val &= ~(1 << 12); /* vref enable */
+	snd_ac97_write_cache(ac97, 0x7a, val);
+	val = snd_ac97_read(ac97, AC97_ALC650_MULTICH);
+	val |= (1 << 15); /* enable spdif in */
+	val &= ~(1 << 10); /* disable center on mic */
+	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, val);
 
 	/* full DAC volume */
 	snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);
diff -Nru a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
--- a/sound/pci/ac97/ac97_patch.h	Sun Feb 22 12:36:42 2004
+++ b/sound/pci/ac97/ac97_patch.h	Sun Feb 22 12:36:42 2004
@@ -41,6 +41,7 @@
 int patch_ad1881(ac97_t * ac97);
 int patch_ad1885(ac97_t * ac97);
 int patch_ad1886(ac97_t * ac97);
+int patch_ad1888(ac97_t * ac97);
 int patch_ad1980(ac97_t * ac97);
 int patch_ad1981a(ac97_t * ac97);
 int patch_ad1981b(ac97_t * ac97);
diff -Nru a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
--- a/sound/pci/ice1712/ice1712.c	Sun Feb 22 12:36:42 2004
+++ b/sound/pci/ice1712/ice1712.c	Sun Feb 22 12:36:42 2004
@@ -2375,6 +2375,7 @@
 	ice->omni = omni ? 1 : 0;
 	spin_lock_init(&ice->reg_lock);
 	init_MUTEX(&ice->gpio_mutex);
+	init_MUTEX(&ice->open_mutex);
 	ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
 	ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
 	ice->gpio.set_data = snd_ice1712_set_gpio_data;
diff -Nru a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
--- a/sound/pci/ice1712/ice1712.h	Sun Feb 22 12:36:42 2004
+++ b/sound/pci/ice1712/ice1712.h	Sun Feb 22 12:36:42 2004
@@ -335,6 +335,9 @@
 	unsigned short hoontech_boxconfig[4];
 	unsigned int cur_rate;		/* current rate */
 
+	struct semaphore open_mutex;
+	snd_pcm_substream_t *pcm_reserved[4];
+
 	unsigned int akm_codecs;
 	akm4xxx_t *akm;
 	struct snd_ice1712_spdif spdif;
diff -Nru a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
--- a/sound/pci/ice1712/ice1724.c	Sun Feb 22 12:36:42 2004
+++ b/sound/pci/ice1712/ice1724.c	Sun Feb 22 12:36:42 2004
@@ -237,6 +237,18 @@
 				if (ice->capture_pro_substream)
 					snd_pcm_period_elapsed(ice->capture_pro_substream);
 			}
+			if (mtstat & VT1724_MULTI_PDMA1) {
+				if (ice->playback_con_substream_ds[0])
+					snd_pcm_period_elapsed(ice->playback_con_substream_ds[0]);
+			}
+			if (mtstat & VT1724_MULTI_PDMA2) {
+				if (ice->playback_con_substream_ds[1])
+					snd_pcm_period_elapsed(ice->playback_con_substream_ds[1]);
+			}
+			if (mtstat & VT1724_MULTI_PDMA3) {
+				if (ice->playback_con_substream_ds[2])
+					snd_pcm_period_elapsed(ice->playback_con_substream_ds[2]);
+			}
 			if (mtstat & VT1724_MULTI_PDMA4) {
 				if (ice->playback_con_substream)
 					snd_pcm_period_elapsed(ice->playback_con_substream);
@@ -282,16 +294,6 @@
 	.mask = 0,
 };
 
-static unsigned int hw_channels[] = {
-	2, 4, 6, 8
-};
-
-static snd_pcm_hw_constraint_list_t hw_constraints_channels = {
-	.count = ARRAY_SIZE(hw_channels),
-	.list = hw_channels,
-	.mask = 0,
-};
-
 static int snd_vt1724_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
 {
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
@@ -300,21 +302,16 @@
 	struct list_head *pos;
 	snd_pcm_substream_t *s;
 
+	what = 0;
+	snd_pcm_group_for_each(pos, substream) {
+		s = snd_pcm_group_substream_entry(pos);
+		what |= (unsigned long)(s->runtime->private_data);
+		snd_pcm_trigger_done(s, substream);
+	}
+
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		what = 0;
-		snd_pcm_group_for_each(pos, substream) {
-			s = snd_pcm_group_substream_entry(pos);
-			if (s == ice->playback_pro_substream)
-				what |= VT1724_PDMA0_PAUSE;
-			else if (s == ice->capture_pro_substream)
-				what |= VT1724_RDMA0_PAUSE;
-			else if (s == ice->playback_con_substream)
-				what |= VT1724_PDMA4_PAUSE;
-			else if (s == ice->capture_con_substream)
-				what |= VT1724_RDMA1_PAUSE;
-		}
 		spin_lock(&ice->reg_lock);
 		old = inb(ICEMT1724(ice, DMA_PAUSE));
 		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
@@ -327,24 +324,6 @@
 
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_STOP:
-		what = 0;
-		s = substream;
-		snd_pcm_group_for_each(pos, substream) {
-			s = snd_pcm_group_substream_entry(pos);
-			if (s == ice->playback_pro_substream) {
-				what |= VT1724_PDMA0_START;
-				snd_pcm_trigger_done(s, substream);
-			} else if (s == ice->capture_pro_substream) {
-				what |= VT1724_RDMA0_START;
-				snd_pcm_trigger_done(s, substream);
-			} else if (s == ice->playback_con_substream) {
-				what |= VT1724_PDMA4_START;
-				snd_pcm_trigger_done(s, substream);
-			} else if (s == ice->capture_con_substream) {
-				what |= VT1724_RDMA1_START;
-				snd_pcm_trigger_done(s, substream);
-			}
-		}
 		spin_lock(&ice->reg_lock);
 		old = inb(ICEMT1724(ice, DMA_CONTROL));
 		if (cmd == SNDRV_PCM_TRIGGER_START)
@@ -364,8 +343,10 @@
 /*
  */
 
-#define DMA_STARTS	(VT1724_RDMA0_START|VT1724_PDMA0_START|VT1724_RDMA1_START|VT1724_PDMA4_START)
-#define DMA_PAUSES	(VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|VT1724_PDMA4_PAUSE)
+#define DMA_STARTS	(VT1724_RDMA0_START|VT1724_PDMA0_START|VT1724_RDMA1_START|\
+	VT1724_PDMA1_START|VT1724_PDMA2_START|VT1724_PDMA3_START|VT1724_PDMA4_START)
+#define DMA_PAUSES	(VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|\
+	VT1724_PDMA1_PAUSE|VT1724_PDMA2_PAUSE|VT1724_PDMA3_PAUSE|VT1724_PDMA4_PAUSE)
 
 static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force)
 {
@@ -448,13 +429,52 @@
 				    snd_pcm_hw_params_t * hw_params)
 {
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	int i, chs;
 
+	chs = params_channels(hw_params);
+	down(&ice->open_mutex);
+	/* mark surround channels */
+	if (substream == ice->playback_pro_substream) {
+		chs = chs / 2 - 1;
+		for (i = 0; i < chs; i++) {
+			if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) {
+				up(&ice->open_mutex);
+				return -EBUSY;
+			}
+			ice->pcm_reserved[i] = substream;
+		}
+		for (; i < 3; i++) {
+			if (ice->pcm_reserved[i] == substream)
+				ice->pcm_reserved[i] = NULL;
+		}
+	} else {
+		for (i = 0; i < 3; i++) {
+			if (ice->playback_con_substream_ds[i] == substream) {
+				if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) {
+					up(&ice->open_mutex);
+					return -EBUSY;
+				}
+				ice->pcm_reserved[i] = substream;
+				break;
+			}
+		}
+	}
+	up(&ice->open_mutex);
 	snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
 	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 }
 
 static int snd_vt1724_pcm_hw_free(snd_pcm_substream_t * substream)
 {
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	int i;
+
+	down(&ice->open_mutex);
+	/* unmark surround channels */
+	for (i = 0; i < 3; i++)
+		if (ice->pcm_reserved[i] == substream)
+			ice->pcm_reserved[i] = NULL;
+	up(&ice->open_mutex);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -593,14 +613,14 @@
 	.rate_max =		192000,
 	.channels_min =		2,
 	.channels_max =		8,
-	.buffer_bytes_max =	(1UL << 21),	/* 18bits dword */
+	.buffer_bytes_max =	(1UL << 21),	/* 19bits dword */
 	.period_bytes_min =	8 * 4 * 2,	/* FIXME: constraints needed */
 	.period_bytes_max =	(1UL << 21),
-	.periods_min =		1,
+	.periods_min =		2,
 	.periods_max =		1024,
 };
 
-static snd_pcm_hardware_t snd_vt1724_capture_pro =
+static snd_pcm_hardware_t snd_vt1724_2ch_stereo =
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -612,10 +632,10 @@
 	.rate_max =		192000,
 	.channels_min =		2,
 	.channels_max =		2,
-	.buffer_bytes_max =	(256*1024),
+	.buffer_bytes_max =	(1UL << 18),	/* 16bits dword */
 	.period_bytes_min =	2 * 4 * 2,
-	.period_bytes_max =	(256*1024),
-	.periods_min =		1,
+	.period_bytes_max =	(1UL << 18),
+	.periods_min =		2,
 	.periods_max =		1024,
 };
 
@@ -628,7 +648,9 @@
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	int chs;
 
+	runtime->private_data = (void*)VT1724_PDMA0_START; /* irq/status/trigger bit */
 	ice->playback_pro_substream = substream;
 	runtime->hw = snd_vt1724_playback_pro;
 	snd_pcm_set_sync(substream);
@@ -639,7 +661,17 @@
 	else
 		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96);
 
-	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
+	down(&ice->open_mutex);
+	/* calculate the currently available channels */
+	for (chs = 0; chs < 3; chs++) {
+		if (ice->pcm_reserved[chs])
+			break;
+	}
+	chs = (chs + 1) * 2;
+	runtime->hw.channels_max = chs;
+	if (chs > 2) /* channels must be even */
+		snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+	up(&ice->open_mutex);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
@@ -652,8 +684,9 @@
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
+	runtime->private_data = (void*)VT1724_RDMA0_START; /* irq/status/trigger bit */
 	ice->capture_pro_substream = substream;
-	runtime->hw = snd_vt1724_capture_pro;
+	runtime->hw = snd_vt1724_2ch_stereo;
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 	if ((ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) &&
@@ -735,25 +768,6 @@
  * SPDIF PCM
  */
 
-static snd_pcm_hardware_t snd_vt1724_playback_spdif =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START),
-	.formats =		SNDRV_PCM_FMTBIT_S32_LE,
-	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_192000,
-	.rate_min =		4000,
-	.rate_max =		192000,
-	.channels_min =		2,
-	.channels_max =		2,
-	.buffer_bytes_max =	(256*1024),
-	.period_bytes_min =	2 * 4 * 2,
-	.period_bytes_max =	(256*1024),
-	.periods_min =		1,
-	.periods_max =		1024,
-};
-
 const static struct vt1724_pcm_reg vt1724_playback_spdif_reg = {
 	.addr = VT1724_MT_PDMA4_ADDR,
 	.size = VT1724_MT_PDMA4_SIZE,
@@ -795,8 +809,9 @@
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
+	runtime->private_data = (void*)VT1724_PDMA4_START; /* irq/status/trigger bit */
 	ice->playback_con_substream = substream;
-	runtime->hw = snd_vt1724_playback_spdif;
+	runtime->hw = snd_vt1724_2ch_stereo;
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 
@@ -820,8 +835,9 @@
 	ice1712_t *ice = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
+	runtime->private_data = (void*)VT1724_RDMA1_START; /* irq/status/trigger bit */
 	ice->capture_con_substream = substream;
-	runtime->hw = snd_vt1724_playback_spdif;
+	runtime->hw = snd_vt1724_2ch_stereo;
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96);
@@ -903,6 +919,127 @@
 
 
 /*
+ * independent surround PCMs
+ */
+
+const static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = {
+	{
+		.addr = VT1724_MT_PDMA1_ADDR,
+		.size = VT1724_MT_PDMA1_SIZE,
+		.count = VT1724_MT_PDMA1_COUNT,
+		.start = VT1724_PDMA1_START,
+		.pause = VT1724_PDMA1_PAUSE,
+	},
+	{
+		.addr = VT1724_MT_PDMA2_ADDR,
+		.size = VT1724_MT_PDMA2_SIZE,
+		.count = VT1724_MT_PDMA2_COUNT,
+		.start = VT1724_PDMA2_START,
+		.pause = VT1724_PDMA2_PAUSE,
+	},
+	{
+		.addr = VT1724_MT_PDMA3_ADDR,
+		.size = VT1724_MT_PDMA3_SIZE,
+		.count = VT1724_MT_PDMA3_COUNT,
+		.start = VT1724_PDMA3_START,
+		.pause = VT1724_PDMA3_PAUSE,
+	},
+};
+
+static int snd_vt1724_playback_indep_prepare(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	unsigned char val;
+
+	spin_lock(&ice->reg_lock);
+	val = 3 - substream->number;
+	if (inb(ICEMT1724(ice, BURST)) < val)
+		outb(val, ICEMT1724(ice, BURST));
+	spin_unlock(&ice->reg_lock);
+	return snd_vt1724_pcm_prepare(substream, &vt1724_playback_dma_regs[substream->number]);
+}
+
+static snd_pcm_uframes_t snd_vt1724_playback_indep_pointer(snd_pcm_substream_t * substream)
+{
+	return snd_vt1724_pcm_pointer(substream, &vt1724_playback_dma_regs[substream->number]);
+}
+
+static int snd_vt1724_playback_indep_open(snd_pcm_substream_t *substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	down(&ice->open_mutex);
+	/* already used by PDMA0? */
+	if (ice->pcm_reserved[substream->number]) {
+		up(&ice->open_mutex);
+		return -EBUSY; /* FIXME: should handle blocking mode properly */
+	}
+	up(&ice->open_mutex);
+	runtime->private_data = (void*)(1 << (substream->number + 4));
+	ice->playback_con_substream_ds[substream->number] = substream;
+	runtime->hw = snd_vt1724_2ch_stereo;
+	snd_pcm_set_sync(substream);
+	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192);
+	return 0;
+}
+
+static int snd_vt1724_playback_indep_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	if (PRO_RATE_RESET)
+		snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0);
+	ice->playback_con_substream_ds[substream->number] = NULL;
+	ice->pcm_reserved[substream->number] = NULL;
+
+	return 0;
+}
+
+static snd_pcm_ops_t snd_vt1724_playback_indep_ops = {
+	.open =		snd_vt1724_playback_indep_open,
+	.close =	snd_vt1724_playback_indep_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_vt1724_pcm_hw_params,
+	.hw_free =	snd_vt1724_pcm_hw_free,
+	.prepare =	snd_vt1724_playback_indep_prepare,
+	.trigger =	snd_vt1724_pcm_trigger,
+	.pointer =	snd_vt1724_playback_indep_pointer,
+};
+
+
+static int __devinit snd_vt1724_pcm_indep(ice1712_t * ice, int device)
+{
+	snd_pcm_t *pcm;
+	int play;
+	int err;
+
+	play = ice->num_total_dacs / 2 - 1;
+	if (play <= 0)
+		return 0;
+
+	err = snd_pcm_new(ice->card, "ICE1724 Surrounds", device, play, 0, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+			&snd_vt1724_playback_indep_ops);
+
+	pcm->private_data = ice;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "ICE1724 Surround PCM");
+
+	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 64*1024);
+
+	ice->pcm_ds = pcm;
+
+	return 0;
+}
+
+
+/*
  *  Mixer section
  */
 
@@ -1808,6 +1945,7 @@
 	ice->vt1724 = 1;
 	spin_lock_init(&ice->reg_lock);
 	init_MUTEX(&ice->gpio_mutex);
+	init_MUTEX(&ice->open_mutex);
 	ice->gpio.set_mask = snd_vt1724_set_gpio_mask;
 	ice->gpio.set_dir = snd_vt1724_set_gpio_dir;
 	ice->gpio.set_data = snd_vt1724_set_gpio_data;
@@ -1932,6 +2070,11 @@
 		return err;
 	}
 	
+	if ((err = snd_vt1724_pcm_indep(ice, pcm_dev++)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
 	if ((err = snd_vt1724_ac97_mixer(ice)) < 0) {
 		snd_card_free(card);
 		return err;
diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
--- a/sound/pci/intel8x0.c	Sun Feb 22 12:36:42 2004
+++ b/sound/pci/intel8x0.c	Sun Feb 22 12:36:42 2004
@@ -143,6 +143,9 @@
 #ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO
 #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO	0x00da
 #endif
+#ifndef PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO
+#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO	0x00ea
+#endif
 
 enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE };
 
@@ -443,6 +446,7 @@
 	{ 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* NFORCE */
 	{ 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* NFORCE2 */
 	{ 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* NFORCE3 */
+	{ 0x10de, 0x00ea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },	/* CK8S */
 	{ 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD8111 */
 	{ 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD768 */
 	{ 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI },   /* Ali5455 */
@@ -804,10 +808,19 @@
 	spin_lock(&chip->reg_lock);
 	status = igetdword(chip, chip->int_sta_reg);
 	if ((status & chip->int_sta_mask) == 0) {
-		if (status)
+		static int err_count = 10;
+		if (status) {
+			/* ack */
 			iputdword(chip, chip->int_sta_reg, status);
+			status ^= igetdword(chip, chip->int_sta_reg);
+		}
 		spin_unlock(&chip->reg_lock);
-		return IRQ_NONE;
+		if (status && err_count) {
+			err_count--;
+			snd_printd("intel8x0: unknown IRQ bits 0x%x (sta_mask=0x%x)\n",
+				   status, chip->int_sta_mask);
+		}
+		return IRQ_RETVAL(status);
 	}
 
 	for (i = 0; i < chip->bdbars_count; i++) {
@@ -1017,6 +1030,7 @@
 {
 	intel8x0_t *chip = snd_pcm_substream_chip(substream);
 	ichdev_t *ichdev = get_ichdev(substream);
+	unsigned long flags;
 	size_t ptr1, ptr;
 
 	ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift;
@@ -1024,7 +1038,9 @@
 		ptr = ichdev->fragsize1 - ptr1;
 	else
 		ptr = 0;
+	spin_lock_irqsave(&chip->reg_lock, flags);
 	ptr += ichdev->position;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	if (ptr >= ichdev->size)
 		return 0;
 	return bytes_to_frames(substream->runtime, ptr);
@@ -1741,6 +1757,12 @@
 	},
 	{
 		.vendor = 0x8086,
+		.device = 0x4856,
+		.name = "Intel D845WN (82801BA)",
+		.type = AC97_TUNE_SWAP_HP
+	},
+	{
+		.vendor = 0x8086,
 		.device = 0x4d44,
 		.name = "Intel D850EMV2",	/* AD1885 */
 		.type = AC97_TUNE_HP_ONLY
@@ -2567,6 +2589,7 @@
 	{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" },
+	{ PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO, "NVidia CK8S" },
 	{ 0x746d, "AMD AMD8111" },
 	{ 0x7445, "AMD AMD768" },
 	{ 0x5455, "ALi M5455" },
diff -Nru a/sound/pci/mixart/Makefile b/sound/pci/mixart/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/Makefile	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-mixart-objs := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o
+
+obj-$(CONFIG_SND_MIXART) += snd-mixart.o
diff -Nru a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart.c	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,1448 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * main file with alsa callbacks
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <sound/core.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "mixart.h"
+#include "mixart_hwdep.h"
+#include "mixart_core.h"
+#include "mixart_mixer.h"
+
+#define CARD_NAME "miXart"
+
+MODULE_AUTHOR("Digigram <alsa@digigram.com>");
+MODULE_DESCRIPTION("Digigram " CARD_NAME);
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{Digigram," CARD_NAME "}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;             /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;              /* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
+
+#define chip_t mixart_t
+
+MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
+MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
+MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
+MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+
+/*
+ */
+
+static struct pci_device_id snd_mixart_ids[] = {
+	{ 0x1057, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* MC8240 */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_mixart_ids);
+
+
+static int mixart_set_pipe_state(mixart_mgr_t *mgr, mixart_pipe_t* pipe, int start)
+{
+	mixart_group_state_req_t group_state;
+	mixart_group_state_resp_t group_state_resp;
+	mixart_msg_t request;
+	int err;
+	u32 system_msg_uid;
+
+	switch(pipe->status) {
+	case PIPE_RUNNING:
+	case PIPE_CLOCK_SET:
+		if(start) return 0; /* already started */
+		break;
+	case PIPE_STOPPED:
+		if(!start) return 0; /* already stopped */
+		break;
+	default:
+		snd_printk(KERN_ERR "error mixart_set_pipe_state called with wrong pipe->status!\n");
+		return -EINVAL;      /* function called with wrong pipe status */
+	}
+
+	system_msg_uid = 0x12345678; /* the event ! (take care: the MSB and two LSB's have to be 0) */
+
+	/* wait on the last MSG_SYSTEM_SEND_SYNCHRO_CMD command to be really finished */
+
+	request.message_id = MSG_SYSTEM_WAIT_SYNCHRO_CMD;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &system_msg_uid;
+	request.size = sizeof(system_msg_uid);
+
+	err = snd_mixart_send_msg_wait_notif(mgr, &request, system_msg_uid);
+	if(err) {
+		snd_printk(KERN_ERR "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n");
+		return err;
+	}
+
+	/* start or stop the pipe (1 pipe) */
+
+	memset(&group_state, 0, sizeof(group_state));
+	group_state.pipe_count = 1;
+	group_state.pipe_uid[0] = pipe->group_uid;
+
+	if(start)
+		request.message_id = MSG_STREAM_START_STREAM_GRP_PACKET;
+	else
+		request.message_id = MSG_STREAM_STOP_STREAM_GRP_PACKET;
+
+	request.uid = pipe->group_uid; /*(mixart_uid_t){0,0};*/
+	request.data = &group_state;
+	request.size = sizeof(group_state);
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
+	if(err) {
+		snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET\n");
+		return err;
+	}
+	if(group_state_resp.txx_status != 0) {
+		snd_printk(KERN_ERR "error status MSG_STREAM_ST***_STREAM_GRP_PACKET (%x)!\n", group_state_resp.txx_status);
+		return -EINVAL;
+	}
+
+	if(start) {
+		u32 stat;
+
+		group_state.pipe_count = 0; /* in case of start same command once again with pipe_count=0 */
+
+		err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
+		if(err)	{
+			snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET !\n");
+			return err;
+		}
+		if(group_state_resp.txx_status != 0) {
+			snd_printk(KERN_ERR "error status MSG_STREAM_START_STREAM_GRP_PACKET (%x)!\n", group_state_resp.txx_status);
+			return -EINVAL;
+		}
+
+		/* in case of start send a synchro top */
+
+		request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
+		request.uid = (mixart_uid_t){0,0};
+		request.data = NULL;
+		request.size = 0;
+
+		err = snd_mixart_send_msg(mgr, &request, sizeof(stat), &stat);
+		if(err) {
+			snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD!\n");
+			return err;
+		}
+		if(stat) {
+			snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD stat=%x!\n", stat);
+		}
+
+		pipe->status = PIPE_RUNNING;
+	}
+	else /* !start */
+		pipe->status = PIPE_STOPPED;
+
+	return 0;
+}
+
+
+static int mixart_set_clock(mixart_mgr_t *mgr, mixart_pipe_t *pipe, unsigned int rate)
+{
+	mixart_msg_t request;
+	mixart_clock_properties_t clock_properties;
+
+	switch(pipe->status) {
+	case PIPE_CLOCK_SET:
+		break;
+	case PIPE_RUNNING:
+		if(rate != 0)
+			break;
+	default:
+		if(rate == 0)
+			return 0; /* nothing to do */
+		else {
+			snd_printk(KERN_ERR "error mixart_set_clock(%d) called with wrong pipe->status !\n", rate);
+			return -EINVAL;
+		}
+	}
+
+	memset(&clock_properties, 0, sizeof(clock_properties));
+	clock_properties.clock_generic_type = (rate != 0) ? CGT_INTERNAL_CLOCK : CGT_NO_CLOCK;
+	clock_properties.clock_mode = CM_STANDALONE;
+	clock_properties.frequency = rate;
+	clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */
+	clock_properties.uid_caller[0] = pipe->group_uid;
+
+	snd_printdd("mixart_set_clock to %d kHz\n", rate);
+
+	request.message_id = MSG_CLOCK_SET_PROPERTIES;
+	request.uid = mgr->uid_console_manager;
+	request.data = &clock_properties;
+	request.size = sizeof(clock_properties);
+
+	/* we are not allowed to wait for the response, so simply set rate */
+	/* TODO : error has to be handled later in the tasklet! */
+
+	if(rate)  pipe->status = PIPE_CLOCK_SET;
+	else      pipe->status = PIPE_RUNNING;
+
+	return snd_mixart_send_msg_nonblock(mgr, &request);
+}
+
+
+/*
+ *  Allocate or reference output pipe for analog IOs (pcmp0/1)
+ */
+mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring)
+{
+	int stream_count;
+	mixart_pipe_t *pipe;
+	mixart_msg_t request;
+
+	if(capture) {
+		if (pcm_number == MIXART_PCM_ANALOG) {
+			pipe = &(chip->pipe_in_ana);  /* analog inputs */
+		} else {
+			pipe = &(chip->pipe_in_dig); /* digital inputs */
+		}
+		request.message_id = MSG_STREAM_ADD_OUTPUT_GROUP;
+		stream_count = MIXART_CAPTURE_STREAMS;
+	} else {
+		if (pcm_number == MIXART_PCM_ANALOG) {
+			pipe = &(chip->pipe_out_ana);  /* analog outputs */
+		} else {
+			pipe = &(chip->pipe_out_dig);  /* digital outputs */
+		}
+		request.message_id = MSG_STREAM_ADD_INPUT_GROUP;
+		stream_count = MIXART_PLAYBACK_STREAMS;
+	}
+
+	/* a new stream is opened and there are already all streams in use */
+	if( (monitoring == 0) && (pipe->references >= stream_count) ) {
+		return NULL;
+	}
+
+	/* pipe is not yet defined */
+	if( pipe->status == PIPE_UNDEFINED ) {
+		int err, i;
+		mixart_streaming_group_t streaming_group_resp;
+		mixart_streaming_group_req_t streaming_group_req;
+
+		snd_printdd("add_ref_pipe audio chip(%d) pcm(%d)\n", chip->chip_idx, pcm_number);
+
+		request.uid = (mixart_uid_t){0,0};      /* should be StreamManagerUID, but zero is OK if there is only one ! */
+		request.data = &streaming_group_req;
+		request.size = sizeof(streaming_group_req);
+
+		memset(&streaming_group_req, 0, sizeof(streaming_group_req));
+
+		streaming_group_req.stream_count = stream_count;
+		streaming_group_req.channel_count = 2;
+		streaming_group_req.latency = 256;
+		streaming_group_req.connector = pipe->uid_left_connector;  /* the left connector */
+
+		for (i=0; i<stream_count; i++) {
+			int j;
+			/* we don't yet know the format, so config 16 bit pcm audio for instance */
+			streaming_group_req.stream_info[i].size_max_byte_frame = 1024;
+			streaming_group_req.stream_info[i].size_max_sample_frame = 256;
+			streaming_group_req.stream_info[i].nb_bytes_max_per_sample = MIXART_FLOAT_P__4_0_TO_HEX; /* is 4.0f */
+
+			/* find the right bufferinfo_array */
+			j = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (pcm_number * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS)) + i;
+			if(capture) j += MIXART_PLAYBACK_STREAMS; /* in the array capture is behind playback */
+
+			streaming_group_req.flow_entry[i] = j;
+
+			chip->mgr->flowinfo_array[j].bufferinfo_array_phy_address = (u32)chip->mgr->bufferinfo_physaddr + (j * sizeof(mixart_bufferinfo_t));
+			chip->mgr->flowinfo_array[j].bufferinfo_count = 1;               /* 1 will set the miXart to ring-buffer mode ! */
+
+			chip->mgr->bufferinfo_array[j].buffer_address = 0;               /* buffer is not yet allocated */
+			chip->mgr->bufferinfo_array[j].available_length = 0;             /* buffer is not yet allocated */
+
+			/* construct the identifier of the stream buffer received in the interrupts ! */
+			chip->mgr->bufferinfo_array[j].buffer_id = (chip->chip_idx << MIXART_NOTIFY_CARD_OFFSET) + (pcm_number << MIXART_NOTIFY_PCM_OFFSET ) + i;
+			if(capture) {
+				chip->mgr->bufferinfo_array[j].buffer_id |= MIXART_NOTIFY_CAPT_MASK;
+			}
+		}
+
+		err = snd_mixart_send_msg(chip->mgr, &request, sizeof(streaming_group_resp), &streaming_group_resp);
+		if((err < 0) || (streaming_group_resp.status != 0)) {
+			snd_printk(KERN_ERR "message MSG_STREAM_ADD_**PUT_GROUP return error: err(%x) status(%x)!\n", err, streaming_group_resp.status);
+			return NULL;
+		}
+
+		pipe->group_uid = streaming_group_resp.group;     /* id of the pipe, as returned by embedded */
+		pipe->stream_count = streaming_group_resp.stream_count;
+		/* pipe->stream_uid[i] = streaming_group_resp.stream[i].stream_uid; */
+
+		pipe->status = PIPE_STOPPED;
+	}
+
+	if(monitoring)	pipe->monitoring = 1;
+	else		pipe->references++;
+
+	return pipe;
+}
+
+
+int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring)
+{
+	int err = 0;
+
+	if(pipe->status == PIPE_UNDEFINED)
+		return 0;
+
+	if(monitoring)
+		pipe->monitoring = 0;
+	else
+		pipe->references--;
+
+	if((pipe->references <= 0) && (pipe->monitoring == 0)) {
+
+		mixart_msg_t request;
+		mixart_delete_group_resp_t delete_resp;
+
+		/* release the clock */
+		err = mixart_set_clock( mgr, pipe, 0);
+		if( err < 0 ) {
+			snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n");
+		}
+
+		/* stop the pipe */
+		err = mixart_set_pipe_state(mgr, pipe, 0);
+		if( err < 0 ) {
+			snd_printk(KERN_ERR "error stopping pipe!\n");
+		}
+
+		request.message_id = MSG_STREAM_DELETE_GROUP;
+		request.uid = (mixart_uid_t){0,0};
+		request.data = &pipe->group_uid;            /* the streaming group ! */
+		request.size = sizeof(pipe->group_uid);
+
+		/* delete the pipe */
+		err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp);
+		if ((err < 0) || (delete_resp.status != 0)) {
+			snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status);
+		}
+
+		pipe->group_uid = (mixart_uid_t){0,0};
+		pipe->stream_count = 0;
+		pipe->status = PIPE_UNDEFINED;
+	}
+
+	return err;
+}
+
+static int mixart_set_stream_state(mixart_stream_t *stream, int start)
+{
+	mixart_t *chip;
+	mixart_stream_state_req_t stream_state_req;
+	mixart_msg_t request;
+
+	if(!stream->substream)
+		return -EINVAL;
+
+	memset(&stream_state_req, 0, sizeof(stream_state_req));
+	stream_state_req.stream_count = 1;
+	stream_state_req.stream_info.stream_desc.uid_pipe = stream->pipe->group_uid;
+	stream_state_req.stream_info.stream_desc.stream_idx = stream->substream->number;
+
+	if (stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		request.message_id = start ? MSG_STREAM_START_INPUT_STAGE_PACKET : MSG_STREAM_STOP_INPUT_STAGE_PACKET;
+	else
+		request.message_id = start ? MSG_STREAM_START_OUTPUT_STAGE_PACKET : MSG_STREAM_STOP_OUTPUT_STAGE_PACKET;
+
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &stream_state_req;
+	request.size = sizeof(stream_state_req);
+
+	stream->abs_period_elapsed = 0;            /* reset stream pos      */
+	stream->buf_periods = 0;
+	stream->buf_period_frag = 0;
+
+	chip = snd_pcm_substream_chip(stream->substream);
+
+	return snd_mixart_send_msg_nonblock(chip->mgr, &request);
+}
+
+/*
+ *  Trigger callback
+ */
+
+static int snd_mixart_trigger(snd_pcm_substream_t *subs, int cmd)
+{
+	mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+
+		snd_printdd("SNDRV_PCM_TRIGGER_START\n");
+
+		// snd_printk(KERN_DEBUG "hw_avail = %d\n", snd_pcm_playback_hw_avail(subs->runtime));
+		/* START_STREAM */
+		if( mixart_set_stream_state(stream, 1) )
+			return -EINVAL;
+
+		stream->status = MIXART_STREAM_STATUS_RUNNING;
+
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+
+		/* STOP_STREAM */
+		if( mixart_set_stream_state(stream, 0) )
+			return -EINVAL;
+
+		/* TODO : mixart drains data transefered in advance -> mute stream ? */
+		stream->status = MIXART_STREAM_STATUS_OPEN;
+
+		snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");
+
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		/* TODO */
+		stream->status = MIXART_STREAM_STATUS_PAUSE;
+		snd_printdd("SNDRV_PCM_PAUSE_PUSH\n");
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		/* TODO */
+		stream->status = MIXART_STREAM_STATUS_RUNNING;
+		snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n");
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ *  prepare callback for all pcms
+ */
+static int snd_mixart_prepare(snd_pcm_substream_t *subs)
+{
+	mixart_t *chip = snd_pcm_substream_chip(subs);
+	mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
+
+	/* TODO de fa�on non bloquante, r�appliquer les hw_params (rate, bits, codec) */
+
+	snd_printdd("snd_mixart_prepare\n");
+
+	/* only the first stream can choose the sample rate */
+	/* the further opened streams will be limited to its frequency (see open) */
+	if(chip->mgr->ref_count_rate == 1)
+		chip->mgr->sample_rate = subs->runtime->rate;
+
+	/* set the clock only once (first stream) on the same pipe */
+	if(stream->pipe->references == 1) {
+		if( mixart_set_clock(chip->mgr, stream->pipe, subs->runtime->rate) )
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int mixart_set_format(mixart_stream_t *stream, snd_pcm_format_t format)
+{
+	int err;
+	mixart_t *chip;
+	mixart_msg_t request;
+	mixart_stream_param_desc_t stream_param;
+	mixart_return_uid_t resp;
+
+	chip = snd_pcm_substream_chip(stream->substream);
+
+	memset(&stream_param, 0, sizeof(stream_param));
+
+	stream_param.coding_type = CT_LINEAR;
+	stream_param.number_of_channel = stream->channels;
+
+	stream_param.sampling_freq = chip->mgr->sample_rate;
+	if(stream_param.sampling_freq == 0)
+		stream_param.sampling_freq = 44100; /* if frequency not yet defined, use some default */
+
+	switch(format){
+	case SNDRV_PCM_FORMAT_U8:
+		stream_param.sample_type = ST_INTEGER_8;
+		stream_param.sample_size = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		stream_param.sample_type = ST_INTEGER_16LE;
+		stream_param.sample_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S16_BE:
+		stream_param.sample_type = ST_INTEGER_16BE;
+		stream_param.sample_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		stream_param.sample_type = ST_INTEGER_24LE;
+		stream_param.sample_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3BE:
+		stream_param.sample_type = ST_INTEGER_24BE;
+		stream_param.sample_size = 24;
+		break;
+	case SNDRV_PCM_FMTBIT_FLOAT_LE:
+		stream_param.sample_type = ST_FLOATING_POINT_32LE;
+		stream_param.sample_size = 32;
+		break;
+	case  SNDRV_PCM_FMTBIT_FLOAT_BE:
+		stream_param.sample_type = ST_FLOATING_POINT_32BE;
+		stream_param.sample_size = 32;
+		break;
+	default:
+		snd_printk(KERN_DEBUG "error use default SNDRV_PCM_FORMAT_S16_LE\n");
+		stream_param.sample_type = ST_INTEGER_16LE;
+		stream_param.sample_size = 16;
+	}
+
+	snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n",
+		   stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels);
+
+	/* TODO: what else to configure ? */
+	/* stream_param.samples_per_frame = 2; */
+	/* stream_param.bytes_per_frame = 4; */
+	/* stream_param.bytes_per_sample = 2; */
+
+	stream_param.pipe_count = 1;      /* set to 1 */
+	stream_param.stream_count = 1;    /* set to 1 */
+	stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid;
+	stream_param.stream_desc[0].stream_idx = stream->substream->number;
+
+	request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &stream_param;
+	request.size = sizeof(stream_param);
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
+	if((err < 0) || resp.error_code) {
+		snd_printk(KERN_DEBUG "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+/*
+ *  HW_PARAMS callback for all pcms
+ */
+static int snd_mixart_hw_params(snd_pcm_substream_t *subs,
+                                snd_pcm_hw_params_t *hw)
+{
+	mixart_t *chip = snd_pcm_substream_chip(subs);
+	mixart_mgr_t *mgr = chip->mgr;
+	mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
+	snd_pcm_format_t format;
+	int err;
+	int channels;
+
+	/* set up channels */
+	channels = params_channels(hw);
+
+	/*  set up format for the stream */
+	format = params_format(hw);
+
+	down(&mgr->setup_mutex);
+
+	/* update the stream levels */
+	if( stream->pcm_number <= MIXART_PCM_DIGITAL ) {
+		int is_aes = stream->pcm_number > MIXART_PCM_ANALOG;
+		if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK )
+			mixart_update_playback_stream_level(chip, is_aes, subs->number);
+		else
+			mixart_update_capture_stream_level( chip, is_aes);
+	}
+
+	stream->channels = channels;
+
+	/* set the format to the board */
+	err = mixart_set_format(stream, format);
+	if(err < 0) {
+		snd_printk(KERN_DEBUG "mixart_set_format() returned error (%x)\n", err);
+		return err;
+	}
+
+	/* allocate buffer */
+	err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw));
+
+	if (err > 0) {
+		int i = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (stream->pcm_number * (MIXART_PLAYBACK_STREAMS+MIXART_CAPTURE_STREAMS)) + subs->number;
+		if( subs->stream == SNDRV_PCM_STREAM_CAPTURE ) {
+			i += MIXART_PLAYBACK_STREAMS; /* in array capture is behind playback */
+		}
+		mgr->bufferinfo_array[i].buffer_address = subs->runtime->dma_addr;
+		mgr->bufferinfo_array[i].available_length = subs->runtime->dma_bytes;
+		/* mgr->bufferinfo_array[i].buffer_id  is already defined */
+
+		snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i, subs->runtime->dma_addr, subs->runtime->dma_bytes, subs->number);
+	}
+	up(&mgr->setup_mutex);
+
+	return err;
+}
+
+static int snd_mixart_hw_free(snd_pcm_substream_t *subs)
+{
+	snd_pcm_lib_free_pages(subs);
+	return 0;
+}
+
+
+
+/*
+ *  TODO CONFIGURATION SPACE for all pcms, mono pcm must update channels_max
+ */
+static snd_pcm_hardware_t snd_mixart_analog_caps =
+{
+	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+			      SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_PAUSE),
+	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |
+			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
+			      SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
+	.rates            = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rate_min         = 8000,
+	.rate_max         = 48000,
+	.channels_min     = 1,
+	.channels_max     = 2,
+	.buffer_bytes_max = (32*1024),
+	.period_bytes_min = 256,                  /* 256 frames U8 mono*/
+	.period_bytes_max = (16*1024),
+	.periods_min      = 2,
+	.periods_max      = (32*1024/256),
+};
+
+static snd_pcm_hardware_t snd_mixart_digital_caps =
+{
+	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+			      SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_PAUSE),
+	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |
+			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
+			      SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
+	.rates            = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+	.rate_min         = 32000,
+	.rate_max         = 48000,
+	.channels_min     = 1,
+	.channels_max     = 2,
+	.buffer_bytes_max = (32*1024),
+	.period_bytes_min = 256,                  /* 256 frames U8 mono*/
+	.period_bytes_max = (16*1024),
+	.periods_min      = 2,
+	.periods_max      = (32*1024/256),
+};
+
+
+static int snd_mixart_playback_open(snd_pcm_substream_t *subs)
+{
+	mixart_t            *chip = snd_pcm_substream_chip(subs);
+	mixart_mgr_t        *mgr = chip->mgr;
+	snd_pcm_runtime_t   *runtime = subs->runtime;
+	snd_pcm_t           *pcm = subs->pcm;
+	mixart_stream_t     *stream;
+	mixart_pipe_t       *pipe;
+	int err = 0;
+	int pcm_number;
+
+	down(&mgr->setup_mutex);
+
+	if ( pcm == chip->pcm ) {
+		pcm_number = MIXART_PCM_ANALOG;
+		runtime->hw = snd_mixart_analog_caps;
+	} else {
+		snd_assert ( pcm == chip->pcm_dig ); 
+		pcm_number = MIXART_PCM_DIGITAL;
+		runtime->hw = snd_mixart_digital_caps;
+	}
+	snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
+
+	/* get stream info */
+	stream = &(chip->playback_stream[pcm_number][subs->number]);
+
+	if (stream->status != MIXART_STREAM_STATUS_FREE){
+		/* streams in use */
+		snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
+		err = -EBUSY;
+		goto _exit_open;
+	}
+
+	/* get pipe pointer (out pipe) */
+	pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0);
+
+	if (pipe == NULL) {
+		err = -EINVAL;
+		goto _exit_open;
+	}
+
+	/* start the pipe if necessary */
+	err = mixart_set_pipe_state(chip->mgr, pipe, 1);
+	if( err < 0 ) {
+		snd_printk(KERN_ERR "error starting pipe!\n");
+		snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
+		err = -EINVAL;
+		goto _exit_open;
+	}
+
+	stream->pipe        = pipe;
+	stream->pcm_number  = pcm_number;
+	stream->status      = MIXART_STREAM_STATUS_OPEN;
+	stream->substream   = subs;
+	stream->channels    = 0; /* not configured yet */
+
+	runtime->private_data = stream;
+
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);
+
+	/* if a sample rate is already used, another stream cannot change */
+	if(mgr->ref_count_rate++) {
+		if(mgr->sample_rate) {
+			runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
+		}
+	}
+
+ _exit_open:
+	up(&mgr->setup_mutex);
+
+	return err;
+}
+
+
+static int snd_mixart_capture_open(snd_pcm_substream_t *subs)
+{
+	mixart_t            *chip = snd_pcm_substream_chip(subs);
+	mixart_mgr_t        *mgr = chip->mgr;
+	snd_pcm_runtime_t   *runtime = subs->runtime;
+	snd_pcm_t           *pcm = subs->pcm;
+	mixart_stream_t     *stream;
+	mixart_pipe_t       *pipe;
+	int err = 0;
+	int pcm_number;
+
+	down(&mgr->setup_mutex);
+
+	if ( pcm == chip->pcm ) {
+		pcm_number = MIXART_PCM_ANALOG;
+		runtime->hw = snd_mixart_analog_caps;
+	} else {
+		snd_assert ( pcm == chip->pcm_dig ); 
+		pcm_number = MIXART_PCM_DIGITAL;
+		runtime->hw = snd_mixart_digital_caps;
+	}
+
+	runtime->hw.channels_min = 2; /* for instance, no mono */
+
+	snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);
+
+	/* get stream info */
+	stream = &(chip->capture_stream[pcm_number]);
+
+	if (stream->status != MIXART_STREAM_STATUS_FREE){
+		/* streams in use */
+		snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
+		err = -EBUSY;
+		goto _exit_open;
+	}
+
+	/* get pipe pointer (in pipe) */
+	pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0);
+
+	if (pipe == NULL) {
+		err = -EINVAL;
+		goto _exit_open;
+	}
+
+	/* start the pipe if necessary */
+	err = mixart_set_pipe_state(chip->mgr, pipe, 1);
+	if( err < 0 ) {
+		snd_printk(KERN_ERR "error starting pipe!\n");
+		snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
+		err = -EINVAL;
+		goto _exit_open;
+	}
+
+	stream->pipe        = pipe;
+	stream->pcm_number  = pcm_number;
+	stream->status      = MIXART_STREAM_STATUS_OPEN;
+	stream->substream   = subs;
+	stream->channels    = 0; /* not configured yet */
+
+	runtime->private_data = stream;
+
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);
+
+	/* if a sample rate is already used, another stream cannot change */
+	if(mgr->ref_count_rate++) {
+		if(mgr->sample_rate) {
+			runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
+		}
+	}
+
+ _exit_open:
+	up(&mgr->setup_mutex);
+
+	return err;
+}
+
+
+
+static int snd_mixart_close(snd_pcm_substream_t *subs)
+{
+	mixart_t *chip = snd_pcm_substream_chip(subs);
+	mixart_mgr_t *mgr = chip->mgr;
+	mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data;
+
+	down(&mgr->setup_mutex);
+
+	snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number);
+
+	/* sample rate released */
+	if(--mgr->ref_count_rate == 0) {
+		mgr->sample_rate = 0;
+	}
+
+	/* delete pipe */
+	if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) {
+
+		snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number);
+	}
+
+	stream->pipe      = NULL;
+	stream->status    = MIXART_STREAM_STATUS_FREE;
+	stream->substream = NULL;
+
+	up(&mgr->setup_mutex);
+	return 0;
+}
+
+
+static snd_pcm_uframes_t snd_mixart_stream_pointer(snd_pcm_substream_t * subs)
+{
+	snd_pcm_runtime_t *runtime = subs->runtime;
+	mixart_stream_t   *stream  = (mixart_stream_t*)runtime->private_data;
+
+	return (snd_pcm_uframes_t)((stream->buf_periods * runtime->period_size) + stream->buf_period_frag);
+}
+
+
+
+static snd_pcm_ops_t snd_mixart_playback_ops = {
+	.open      = snd_mixart_playback_open,
+	.close     = snd_mixart_close,
+	.ioctl     = snd_pcm_lib_ioctl,
+	.prepare   = snd_mixart_prepare,
+	.hw_params = snd_mixart_hw_params,
+	.hw_free   = snd_mixart_hw_free,
+	.trigger   = snd_mixart_trigger,
+	.pointer   = snd_mixart_stream_pointer,
+};
+
+static snd_pcm_ops_t snd_mixart_capture_ops = {
+	.open      = snd_mixart_capture_open,
+	.close     = snd_mixart_close,
+	.ioctl     = snd_pcm_lib_ioctl,
+	.prepare   = snd_mixart_prepare,
+	.hw_params = snd_mixart_hw_params,
+	.hw_free   = snd_mixart_hw_free,
+	.trigger   = snd_mixart_trigger,
+	.pointer   = snd_mixart_stream_pointer,
+};
+
+static void preallocate_buffers(mixart_t *chip, snd_pcm_t *pcm)
+{
+	snd_pcm_substream_t *subs;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		int idx = 0;
+		for (subs = pcm->streams[stream].substream; subs; subs = subs->next, idx++)
+			/* set up the unique device id with the chip index */
+			subs->dma_device.id = subs->pcm->device << 16 |
+				subs->stream << 8 | (subs->number + 1) |
+				(chip->chip_idx + 1) << 24;
+	}
+	snd_pcm_lib_preallocate_pci_pages_for_all(chip->mgr->pci, pcm, 32*1024, 32*1024);
+}
+
+/*
+ */
+static int snd_mixart_pcm_analog(mixart_t *chip)
+{
+	int err;
+	snd_pcm_t *pcm;
+	char name[32];
+
+	sprintf(name, "miXart analog %d", chip->chip_idx);
+	if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG,
+			       MIXART_PLAYBACK_STREAMS,
+			       MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
+		snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx);
+		return err;
+	}
+
+	pcm->private_data = chip;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
+
+	pcm->info_flags = 0;
+	strcpy(pcm->name, name);
+
+	preallocate_buffers(chip, pcm);
+
+	chip->pcm = pcm;
+	return 0;
+}
+
+
+/*
+ */
+static int snd_mixart_pcm_digital(mixart_t *chip)
+{
+	int err;
+	snd_pcm_t *pcm;
+	char name[32];
+
+	sprintf(name, "miXart AES/EBU %d", chip->chip_idx);
+	if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL,
+			       MIXART_PLAYBACK_STREAMS,
+			       MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
+		snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx);
+		return err;
+	}
+
+	pcm->private_data = chip;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
+
+	pcm->info_flags = 0;
+	strcpy(pcm->name, name);
+
+	preallocate_buffers(chip, pcm);
+
+	chip->pcm_dig = pcm;
+	return 0;
+}
+
+static int snd_mixart_chip_free(mixart_t *chip)
+{
+	snd_magic_kfree(chip);
+	return 0;
+}
+
+static int snd_mixart_chip_dev_free(snd_device_t *device)
+{
+	mixart_t *chip = snd_magic_cast(mixart_t, device->device_data, return -ENXIO);
+	return snd_mixart_chip_free(chip);
+}
+
+
+/*
+ */
+static int __devinit snd_mixart_create(mixart_mgr_t *mgr, snd_card_t *card, int idx)
+{
+	int err;
+	mixart_t *chip;
+	static snd_device_ops_t ops = {
+		.dev_free = snd_mixart_chip_dev_free,
+	};
+
+	mgr->chip[idx] = chip = snd_magic_kcalloc(mixart_t, 0, GFP_KERNEL);
+	if (! chip) {
+		snd_printk(KERN_ERR "cannot allocate chip\n");
+		return -ENOMEM;
+	}
+
+	chip->card = card;
+	chip->chip_idx = idx;
+	chip->mgr = mgr;
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		snd_mixart_chip_free(chip);
+		return err;
+	}
+
+	if (idx == 0) {
+		/* create a DSP loader only on first cardX*/
+		err = snd_mixart_hwdep_new(mgr);
+		if (err < 0)
+			return err;
+	}
+
+	snd_card_set_dev(card, &mgr->pci->dev);
+
+	return 0;
+}
+
+int snd_mixart_create_pcm(mixart_t* chip)
+{
+	int err;
+
+	err = snd_mixart_pcm_analog(chip);
+	if (err < 0)
+		return err;
+
+	if(chip->mgr->board_type == MIXART_DAUGHTER_TYPE_AES) {
+
+		err = snd_mixart_pcm_digital(chip);
+		if (err < 0)
+			return err;
+	}
+	return err;
+}
+
+
+/*
+ * release all the cards assigned to a manager instance
+ */
+static int snd_mixart_free(mixart_mgr_t *mgr)
+{
+	unsigned int i;
+
+	for (i = 0; i < mgr->num_cards; i++) {
+		if (mgr->chip[i])
+			snd_card_free(mgr->chip[i]->card);
+	}
+
+	/* stop mailbox */
+	snd_mixart_exit_mailbox(mgr);
+
+	/* release irq  */
+	if (mgr->irq >= 0)
+		free_irq(mgr->irq, (void *)mgr);
+
+	/* reset board if some firmware was loaded */
+	if(mgr->hwdep->dsp_loaded) {
+		snd_mixart_reset_board(mgr);
+		snd_printdd("reset miXart !\n");
+	}
+
+	/* release the i/o ports */
+	for (i = 0; i < 2; i++) {
+		if (mgr->mem[i].virt)
+			iounmap((void *)mgr->mem[i].virt);
+		if (mgr->mem[i].res) {
+			release_resource(mgr->mem[i].res);
+			kfree_nocheck(mgr->mem[i].res);
+		}
+	}
+
+	/* free flowarray */
+	if(mgr->flowinfo_array) {
+		snd_free_pci_pages(mgr->pci, PAGE_ALIGN(MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_flowinfo_t)),
+				   mgr->flowinfo_array, mgr->flowinfo_physaddr);
+	}
+	/* free bufferarray */
+	if(mgr->bufferinfo_array) {
+		snd_free_pci_pages(mgr->pci, PAGE_ALIGN(MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_bufferinfo_t)),
+				   mgr->bufferinfo_array, mgr->bufferinfo_physaddr);
+	}
+
+	snd_magic_kfree(mgr);
+	return 0;
+}
+
+/*
+ * proc interface
+ */
+static long long snd_mixart_BA0_llseek(snd_info_entry_t *entry,
+				       void *private_file_data,
+				       struct file *file,
+				       long long offset,
+				       int orig)
+{
+	offset = offset & ~3; /* 4 bytes aligned */
+
+	switch(orig) {
+	case 0:  /* SEEK_SET */
+		file->f_pos = offset;
+		break;
+	case 1:  /* SEEK_CUR */
+		file->f_pos += offset;
+		break;
+	case 2:  /* SEEK_END, offset is negative */
+		file->f_pos = MIXART_BA0_SIZE + offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if(file->f_pos > MIXART_BA0_SIZE)
+		file->f_pos = MIXART_BA0_SIZE;
+	return file->f_pos;
+}
+
+static long long snd_mixart_BA1_llseek(snd_info_entry_t *entry,
+				       void *private_file_data,
+				       struct file *file,
+				       long long offset,
+				       int orig)
+{
+	offset = offset & ~3; /* 4 bytes aligned */
+
+	switch(orig) {
+	case 0:  /* SEEK_SET */
+		file->f_pos = offset;
+		break;
+	case 1:  /* SEEK_CUR */
+		file->f_pos += offset;
+		break;
+	case 2: /* SEEK_END, offset is negative */
+		file->f_pos = MIXART_BA1_SIZE + offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if(file->f_pos > MIXART_BA1_SIZE)
+		file->f_pos = MIXART_BA1_SIZE;
+	return file->f_pos;
+}
+
+/*
+  mixart_BA0 proc interface for BAR 0 - read callback
+ */
+static long snd_mixart_BA0_read(snd_info_entry_t *entry, void *file_private_data,
+				struct file *file, char *buf, long count)
+{
+	mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO);
+
+	count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
+	if(count <= 0)
+		return 0;
+	if(file->f_pos + count > MIXART_BA0_SIZE)
+		count = (long)(MIXART_BA0_SIZE - file->f_pos);
+	if(copy_to_user_fromio(buf, MIXART_MEM( mgr, file->f_pos ), count))
+		return -EFAULT;
+	file->f_pos += count;
+	return count;
+}
+
+/*
+  mixart_BA1 proc interface for BAR 1 - read callback
+ */
+static long snd_mixart_BA1_read(snd_info_entry_t *entry, void *file_private_data,
+				struct file *file, char *buf, long count)
+{
+	mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO);
+
+	count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
+	if(count <= 0)
+		return 0;
+	if(file->f_pos + count > MIXART_BA1_SIZE)
+		count = (long)(MIXART_BA1_SIZE - file->f_pos);
+	if(copy_to_user_fromio(buf, MIXART_REG( mgr, file->f_pos ), count))
+		return -EFAULT;
+	file->f_pos += count;
+	return count;
+}
+
+static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = {
+	.read   = snd_mixart_BA0_read,
+	.llseek = snd_mixart_BA0_llseek
+};
+
+static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = {
+	.read   = snd_mixart_BA1_read,
+	.llseek = snd_mixart_BA1_llseek
+};
+
+
+static void snd_mixart_proc_read(snd_info_entry_t *entry, 
+                                 snd_info_buffer_t * buffer)
+{
+	mixart_t *chip = snd_magic_cast(mixart_t, entry->private_data, return);        
+	u32 ref; 
+
+	snd_iprintf(buffer, "Digigram miXart (alsa card %d)\n\n", chip->chip_idx);
+
+	/* stats available when embedded OS is running */
+	if (chip->mgr->hwdep->dsp_loaded & ( 1 << MIXART_MOTHERBOARD_ELF_INDEX)) {
+		snd_iprintf(buffer, "- hardware -\n");
+		switch (chip->mgr->board_type ) {
+		case MIXART_DAUGHTER_TYPE_NONE     : snd_iprintf(buffer, "\tmiXart8 (no daughter board)\n\n"); break;
+		case MIXART_DAUGHTER_TYPE_AES      : snd_iprintf(buffer, "\tmiXart8 AES/EBU\n\n"); break;
+		case MIXART_DAUGHTER_TYPE_COBRANET : snd_iprintf(buffer, "\tmiXart8 Cobranet\n\n"); break;
+		default:                             snd_iprintf(buffer, "\tUNKNOWN!\n\n"); break;
+		}
+
+		snd_iprintf(buffer, "- system load -\n");	 
+
+		/* get perf reference */
+
+		ref = readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET));
+
+		if (ref) {
+			u32 mailbox   = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET)) / ref;
+			u32 streaming = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET)) / ref;
+			u32 interr    = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET)) / ref;
+
+			snd_iprintf(buffer, "\tstreaming          : %d\n", streaming);
+			snd_iprintf(buffer, "\tmailbox            : %d\n", mailbox);
+			snd_iprintf(buffer, "\tinterrups handling : %d\n\n", interr);
+		}
+	} /* endif elf loaded */
+}
+
+static void __devinit snd_mixart_proc_init(mixart_t *chip)
+{
+	snd_info_entry_t *entry;
+
+	/* text interface to read perf and temp meters */
+	if (! snd_card_proc_new(chip->card, "board_info", &entry)) {
+		entry->private_data = chip;
+		entry->c.text.read_size = 1024;
+		entry->c.text.read = snd_mixart_proc_read;
+	}
+
+	if (! snd_card_proc_new(chip->card, "mixart_BA0", &entry)) {
+		entry->content = SNDRV_INFO_CONTENT_DATA;
+		entry->private_data = chip->mgr;	
+		entry->c.ops = &snd_mixart_proc_ops_BA0;
+		entry->size = MIXART_BA0_SIZE;
+	}
+	if (! snd_card_proc_new(chip->card, "mixart_BA1", &entry)) {
+		entry->content = SNDRV_INFO_CONTENT_DATA;
+		entry->private_data = chip->mgr;
+		entry->c.ops = &snd_mixart_proc_ops_BA1;
+		entry->size = MIXART_BA1_SIZE;
+	}
+}
+/* end of proc interface */
+
+
+/*
+ *    probe function - creates the card manager
+ */
+static int __devinit snd_mixart_probe(struct pci_dev *pci,
+				      const struct pci_device_id *pci_id)
+{
+	static int dev;
+	mixart_mgr_t *mgr;
+	unsigned int i;
+	int err;
+	size_t size;
+
+	/*
+	 */
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (! enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	/* enable PCI device */
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+	pci_set_master(pci);
+
+	/* check if we can restrict PCI DMA transfers to 32 bits */
+	if (!pci_dma_supported(pci, 0xffffffff)) {
+		snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
+		return -ENXIO;
+	}
+	pci_set_dma_mask(pci, 0xffffffff);
+
+	/*
+	 */
+	mgr = snd_magic_kcalloc(mixart_mgr_t, 0, GFP_KERNEL);
+	if (! mgr)
+		return -ENOMEM;
+
+	mgr->pci = pci;
+	mgr->irq = -1;
+
+	/* resource assignment */
+	for (i = 0; i < 2; i++) {
+		static int memory_sizes[2] = {
+			MIXART_BA0_SIZE, /* 16M */	  
+			MIXART_BA1_SIZE  /* 4 k */
+		};
+		mgr->mem[i].phys = pci_resource_start(pci, i);
+		mgr->mem[i].res = request_mem_region(mgr->mem[i].phys, memory_sizes[i], CARD_NAME);
+		if (! mgr->mem[i].res) {
+			snd_printk(KERN_ERR "unable to grab memory 0x%lx\n", mgr->mem[i].phys);
+			snd_mixart_free(mgr);
+			return -EBUSY;
+		}
+		mgr->mem[i].virt = (unsigned long)ioremap_nocache(mgr->mem[i].phys, memory_sizes[i]);
+	}
+
+	if (request_irq(pci->irq, snd_mixart_interrupt, SA_INTERRUPT|SA_SHIRQ, CARD_NAME, (void *)mgr)) {
+		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
+		snd_mixart_free(mgr);
+		return -EBUSY;
+	}
+	mgr->irq = pci->irq;
+
+	sprintf(mgr->shortname, "Digigram miXart");
+	sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq);
+
+	/* ISR spinlock  */
+	mgr->lock = SPIN_LOCK_UNLOCKED;
+
+	/* init mailbox  */
+	mgr->msg_fifo_readptr = 0;
+	mgr->msg_fifo_writeptr = 0;
+
+	mgr->msg_lock = SPIN_LOCK_UNLOCKED;
+	init_MUTEX(&mgr->msg_mutex);
+
+	/* init setup mutex*/
+	init_MUTEX(&mgr->setup_mutex);
+
+	/* init message taslket */
+	tasklet_init( &mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr);
+
+	/* card assignment */
+	mgr->num_cards = MIXART_MAX_CARDS; /* 4  FIXME: configurable? */
+	for (i = 0; i < mgr->num_cards; i++) {
+		snd_card_t *card;
+		char tmpid[16];
+		int idx;
+
+		if (index[dev] < 0)
+			idx = index[dev];
+		else
+			idx = index[dev] + i;
+		snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev], i);
+		card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
+
+		if (! card) {
+			snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
+			snd_mixart_free(mgr);
+			return -ENOMEM;
+		}
+
+		strcpy(card->driver, CARD_NAME);
+		sprintf(card->shortname, "%s [PCM #%d]", mgr->shortname, i);
+		sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i);
+
+		if ((err = snd_mixart_create(mgr, card, i)) < 0) {
+			snd_mixart_free(mgr);
+			return err;
+		}
+
+		if(i==0) {
+			/* init proc interface only for chip0 */
+			snd_mixart_proc_init(mgr->chip[i]);
+		}
+
+		if ((err = snd_card_register(card)) < 0) {
+			snd_mixart_free(mgr);
+			return err;
+		}
+	}
+
+	/* init firmware status (mgr->hwdep->dsp_loaded reset in hwdep_new) */
+	mgr->board_type = MIXART_DAUGHTER_TYPE_NONE;
+
+	/* create array of streaminfo */
+	size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_flowinfo_t)) );
+	mgr->flowinfo_array = snd_malloc_pci_pages(mgr->pci, size, &mgr->flowinfo_physaddr);
+	if(!mgr->flowinfo_array) {
+		snd_mixart_free(mgr);
+		return -ENOMEM;
+	}
+	/* init streaminfo_array */
+	memset(mgr->flowinfo_array, 0, size);
+
+	/* create array of bufferinfo */
+	size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_bufferinfo_t)) );
+	mgr->bufferinfo_array = snd_malloc_pci_pages(mgr->pci, size, &mgr->bufferinfo_physaddr);
+	if(!mgr->bufferinfo_array) {
+		snd_mixart_free(mgr);
+		return -ENOMEM;
+	}
+	/* init bufferinfo_array */
+	memset(mgr->bufferinfo_array, 0, size);
+
+	pci_set_drvdata(pci, mgr);
+	dev++;
+	return 0;
+}
+
+static void __devexit snd_mixart_remove(struct pci_dev *pci)
+{
+	snd_mixart_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+	.name = "Digigram miXart",
+	.id_table = snd_mixart_ids,
+	.probe = snd_mixart_probe,
+	.remove = __devexit_p(snd_mixart_remove),
+};
+
+static int __init alsa_card_mixart_init(void)
+{
+	int err;
+
+	if ((err = pci_module_init(&driver)) < 0) {
+#ifdef MODULE
+		snd_printk(KERN_ERR "Digigram miXart soundcard not found or device busy\n");
+#endif
+		return err;
+	}
+	return 0;
+}
+
+static void __exit alsa_card_mixart_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_mixart_init)
+module_exit(alsa_card_mixart_exit)
+
+#ifndef MODULE
+
+/* format is: snd-mixart=enable,index,id */
+
+static int __init alsa_card_mixart_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&enable[nr_dev]) == 2 &&
+	       get_option(&str,&index[nr_dev]) == 2 &&
+	       get_id(&str,&id[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-mixart=", alsa_card_mixart_setup);
+
+#endif /* ifndef MODULE */
diff -Nru a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart.h	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,242 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * main header file
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_MIXART_H
+#define __SOUND_MIXART_H
+
+#include <sound/pcm.h>
+
+#define MIXART_DRIVER_VERSION	0x000100	/* 0.1.0 */
+
+
+/*
+ */
+
+#define mixart_t_magic		0xa17a3e01
+#define mixart_mgr_t_magic	0xa17a3e02
+
+typedef struct snd_mixart mixart_t;
+typedef struct snd_mixart_mgr mixart_mgr_t;
+
+typedef struct snd_mixart_stream mixart_stream_t;
+typedef struct snd_mixart_pipe mixart_pipe_t;
+
+typedef struct mixart_bufferinfo mixart_bufferinfo_t;
+typedef struct mixart_flowinfo mixart_flowinfo_t;
+typedef struct mixart_uid mixart_uid_t;
+
+struct mixart_uid
+{
+	u32 object_id;
+	u32 desc;
+};
+
+struct mem_area {
+	unsigned long phys;
+	unsigned long virt;
+	struct resource *res;
+};
+
+
+typedef struct mixart_route mixart_route_t;
+struct mixart_route {
+	unsigned char connected;
+	unsigned char phase_inv;
+	int volume;
+};
+
+
+/* firmware status codes  */
+#define MIXART_MOTHERBOARD_XLX_INDEX  0
+#define MIXART_MOTHERBOARD_ELF_INDEX  1
+#define MIXART_AESEBUBOARD_XLX_INDEX  2
+#define MIXART_HARDW_FILES_MAX_INDEX  3  /* xilinx, elf, AESEBU xilinx */
+
+#define MIXART_MAX_CARDS	4
+#define MSG_FIFO_SIZE           16
+
+#define MIXART_MAX_PHYS_CONNECTORS  (MIXART_MAX_CARDS * 2 * 2) /* 4 * stereo * (analog+digital) */
+
+struct snd_mixart_mgr {
+	unsigned int num_cards;
+	mixart_t *chip[MIXART_MAX_CARDS];
+
+	struct pci_dev *pci;
+
+	int irq;
+
+	/* memory-maps */
+	struct mem_area mem[2];
+
+	/* share the name */
+	char shortname[32];         /* short name of this soundcard */
+	char longname[80];          /* name of this soundcard */
+
+	/* message tasklet */
+	struct tasklet_struct msg_taskq;
+
+	/* one and only blocking message or notification may be pending  */
+	u32 pending_event;
+	wait_queue_head_t msg_sleep;
+
+	/* messages stored for tasklet */
+	u32 msg_fifo[MSG_FIFO_SIZE];
+	int msg_fifo_readptr;
+	int msg_fifo_writeptr;
+
+	spinlock_t lock;              /* interrupt spinlock */
+	spinlock_t msg_lock;          /* mailbox spinlock */
+	struct semaphore msg_mutex;   /* mutex for blocking_requests */
+
+	struct semaphore setup_mutex; /* mutex used in hw_params, open and close */
+
+	/* hardware interface */
+	snd_hwdep_t *hwdep;
+	unsigned int board_type;      /* read from embedded once elf file is loaded, 250 = miXart8, 251 = with AES, 252 = with Cobranet */
+
+	mixart_flowinfo_t*   flowinfo_array;
+	dma_addr_t           flowinfo_physaddr;
+	mixart_bufferinfo_t* bufferinfo_array;
+	dma_addr_t           bufferinfo_physaddr;
+
+	mixart_uid_t         uid_console_manager;
+	int sample_rate;
+	int ref_count_rate;
+
+	struct semaphore mixer_mutex; /* mutex for mixer */
+
+};
+
+
+#define MIXART_STREAM_STATUS_FREE	0
+#define MIXART_STREAM_STATUS_OPEN	1
+#define MIXART_STREAM_STATUS_RUNNING	2
+#define MIXART_STREAM_STATUS_DRAINING	3
+#define MIXART_STREAM_STATUS_PAUSE	4
+
+#define MIXART_PLAYBACK_STREAMS		4
+#define MIXART_CAPTURE_STREAMS		1
+
+#define MIXART_PCM_ANALOG		0
+#define MIXART_PCM_DIGITAL		1
+#define MIXART_PCM_TOTAL		2
+
+#define MIXART_MAX_STREAM_PER_CARD  (MIXART_PCM_TOTAL * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS) )
+
+
+#define MIXART_NOTIFY_CARD_MASK		0xF000
+#define MIXART_NOTIFY_CARD_OFFSET	12
+#define MIXART_NOTIFY_PCM_MASK		0x0F00
+#define MIXART_NOTIFY_PCM_OFFSET	8
+#define MIXART_NOTIFY_CAPT_MASK		0x0080
+#define MIXART_NOTIFY_SUBS_MASK		0x007F
+
+
+struct snd_mixart_stream {
+	snd_pcm_substream_t *substream;
+	mixart_pipe_t *pipe;
+	int pcm_number;
+
+	int status;      /* nothing, running, draining */
+
+	u64  abs_period_elapsed;  /* last absolute stream position where period_elapsed was called (multiple of runtime->period_size) */
+	u32  buf_periods;         /* periods counter in the buffer (< runtime->periods) */
+	u32  buf_period_frag;     /* defines with buf_period_pos the exact position in the buffer (< runtime->period_size) */
+
+	int channels;
+};
+
+
+enum mixart_pipe_status {
+	PIPE_UNDEFINED,
+	PIPE_STOPPED,
+	PIPE_RUNNING,
+	PIPE_CLOCK_SET
+};
+
+struct snd_mixart_pipe {
+	mixart_uid_t group_uid;			/* id of the pipe, as returned by embedded */
+	int          stream_count;
+	mixart_uid_t uid_left_connector;	/* UID's for the audio connectors */
+	mixart_uid_t uid_right_connector;
+	enum mixart_pipe_status status;
+	int references;             /* number of subs openned */
+	int monitoring;             /* pipe used for monitoring issue */
+};
+
+
+struct snd_mixart {
+	snd_card_t *card;
+	mixart_mgr_t *mgr;
+	int chip_idx;               /* zero based */
+	snd_hwdep_t *hwdep;	    /* DSP loader, only for the first card */
+
+	snd_pcm_t *pcm;             /* PCM analog i/o */
+	snd_pcm_t *pcm_dig;         /* PCM digital i/o */
+
+	/* allocate stereo pipe for instance */
+	mixart_pipe_t pipe_in_ana;
+	mixart_pipe_t pipe_out_ana;
+
+	/* if AES/EBU daughter board is available, additional pipes possible on pcm_dig */
+	mixart_pipe_t pipe_in_dig;
+	mixart_pipe_t pipe_out_dig;
+
+	mixart_stream_t playback_stream[MIXART_PCM_TOTAL][MIXART_PLAYBACK_STREAMS]; /* 0 = pcm, 1 = pcm_dig */
+	mixart_stream_t capture_stream[MIXART_PCM_TOTAL];                           /* 0 = pcm, 1 = pcm_dig */
+
+	/* UID's for the physical io's */
+	mixart_uid_t uid_out_analog_physio;
+	mixart_uid_t uid_in_analog_physio;
+
+	int analog_playback_active[2];		/* Mixer : Master Playback active (!mute) */
+	int analog_playback_volume[2];		/* Mixer : Master Playback Volume */
+	int analog_capture_volume[2];		/* Mixer : Master Capture Volume */
+	int digital_playback_active[2*MIXART_PLAYBACK_STREAMS][2];	/* Mixer : Digital Playback Active [(analog+AES output)*streams][stereo]*/
+	int digital_playback_volume[2*MIXART_PLAYBACK_STREAMS][2];	/* Mixer : Digital Playback Volume [(analog+AES output)*streams][stereo]*/
+	int digital_capture_volume[2][2];	/* Mixer : Digital Capture Volume [analog+AES output][stereo] */
+	int monitoring_active[2];		/* Mixer : Monitoring Active */
+	int monitoring_volume[2];		/* Mixer : Monitoring Volume */
+};
+
+struct mixart_bufferinfo
+{
+	u32 buffer_address;
+	u32 reserved[5];
+	u32 available_length;
+	u32 buffer_id;
+};
+
+struct mixart_flowinfo
+{
+	u32 bufferinfo_array_phy_address;
+	u32 reserved[11];
+	u32 bufferinfo_count;
+	u32 capture;
+};
+
+/* exported */
+int snd_mixart_create_pcm(mixart_t* chip);
+mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring);
+int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring);
+
+#endif /* __SOUND_MIXART_H */
diff -Nru a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_core.c	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,588 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * low level interface with interrupt handling and mail box implementation
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include "mixart.h"
+#include "mixart_hwdep.h"
+#include "mixart_core.h"
+
+
+#define MSG_TIMEOUT_JIFFIES         (400 * HZ) / 1000 /* 400 ms */
+
+#define MSG_DESCRIPTOR_SIZE         0x24
+#define MSG_HEADER_SIZE             (MSG_DESCRIPTOR_SIZE + 4)
+
+#define MSG_DEFAULT_SIZE            512
+
+#define MSG_TYPE_MASK               0x00000003    /* mask for following types */
+#define MSG_TYPE_NOTIFY             0             /* embedded -> driver (only notification, do not get_msg() !) */
+#define MSG_TYPE_COMMAND            1             /* driver <-> embedded (a command has no answer) */
+#define MSG_TYPE_REQUEST            2             /* driver -> embedded (request will get an answer back) */
+#define MSG_TYPE_ANSWER             3             /* embedded -> driver */
+#define MSG_CANCEL_NOTIFY_MASK      0x80000000    /* this bit is set for a notification that has been canceled */
+
+
+static int retrieve_msg_frame(mixart_mgr_t *mgr, u32 *msg_frame)
+{
+	/* read the message frame fifo */
+	u32 headptr, tailptr;
+
+	tailptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
+	headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_HEAD));
+
+	if (tailptr == headptr)
+		return 0; /* no message posted */
+
+	snd_assert( tailptr >= MSG_OUTBOUND_POST_STACK, return 0); /* error */
+	snd_assert( tailptr < (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE), return 0); /* error */
+
+	*msg_frame = readl_be(MIXART_MEM(mgr, tailptr));
+
+	/* increment the tail index */
+	tailptr += 4;
+	if( tailptr >= (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
+		tailptr = MSG_OUTBOUND_POST_STACK;
+	writel_be(tailptr, MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
+
+	return 1;
+}
+
+static int get_msg(mixart_mgr_t *mgr, mixart_msg_t *resp, u32 msg_frame_address )
+{
+	unsigned long flags;
+	u32  headptr, i;
+	u32  size;
+	int  err;
+
+	spin_lock_irqsave(&mgr->msg_lock, flags);
+	err = 0;
+
+	/* copy message descriptor from miXart to driver */
+	size                =  readl_be(MIXART_MEM(mgr, msg_frame_address));       /* size of descriptor + response */
+	resp->message_id    =  readl_be(MIXART_MEM(mgr, msg_frame_address + 4));   /* dwMessageID */
+	resp->uid.object_id =  readl_be(MIXART_MEM(mgr, msg_frame_address + 8));   /* uidDest */
+	resp->uid.desc      =  readl_be(MIXART_MEM(mgr, msg_frame_address + 12));  /* */
+
+	if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) {
+		err = -EINVAL;
+		snd_printk(KERN_ERR "problem with response size = %d\n", size);
+		goto _clean_exit;
+	}
+	size -= MSG_DESCRIPTOR_SIZE;
+
+	memcpy_fromio(resp->data, MIXART_MEM(mgr, msg_frame_address + MSG_HEADER_SIZE ), size);
+	resp->size = size;
+
+	/* swap if necessary */
+#ifndef __BIG_ENDIAN
+	size /= 4; /* u32 size */
+	for(i=0; i < size; i++) {
+		((u32*)resp->data)[i] = be32_to_cpu(((u32*)resp->data)[i]);
+	}
+#endif
+
+	/*
+	 * free message frame address
+	 */
+	headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
+
+	if( (headptr < MSG_OUTBOUND_FREE_STACK) || ( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
+		err = -EINVAL;
+		goto _clean_exit;
+	}
+
+	/* give address back to outbound fifo */
+	writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
+
+	/* increment the outbound free head */
+	headptr += 4;
+	if( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
+		headptr = MSG_OUTBOUND_FREE_STACK;
+
+	writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
+
+ _clean_exit:
+	spin_unlock_irqrestore(&mgr->msg_lock, flags);
+
+	return err;
+}
+
+
+/*
+ * send a message to miXart. return: the msg_frame used for this message
+ */
+static int send_msg( mixart_mgr_t *mgr,
+		     mixart_msg_t *msg,
+		     int max_answersize,
+		     int mark_pending,
+		     u32 *msg_event)
+{
+	unsigned long flags;
+	u32 headptr, tailptr;
+	u32 msg_frame_address;
+	int err, i;
+
+	snd_assert(msg->size % 4 == 0, return -EINVAL);
+
+	spin_lock_irqsave(&mgr->msg_lock, flags);
+	err = 0;
+
+	/* get message frame address */
+	tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
+	headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD));
+
+	if (tailptr == headptr) {
+		snd_printk(KERN_ERR "error: no message frame available\n");
+		err = -EBUSY;
+		goto _clean_exit;
+	}
+
+	if( (tailptr < MSG_INBOUND_FREE_STACK) || (tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
+		err = -EINVAL;
+		goto _clean_exit;
+	}
+
+	msg_frame_address = readl_be(MIXART_MEM(mgr, tailptr));
+	writel(0, MIXART_MEM(mgr, tailptr)); /* set address to zero on this fifo position */
+
+	/* increment the inbound free tail */
+	tailptr += 4;
+	if( tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
+		tailptr = MSG_INBOUND_FREE_STACK;
+
+	writel_be(tailptr, MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
+
+	/* TODO : use memcpy_toio() with intermediate buffer to copy the message */
+
+	/* copy message descriptor to card memory */
+	writel_be( msg->size + MSG_DESCRIPTOR_SIZE,      MIXART_MEM(mgr, msg_frame_address) );      /* size of descriptor + request */
+	writel_be( msg->message_id ,                     MIXART_MEM(mgr, msg_frame_address + 4) );  /* dwMessageID */
+	writel_be( msg->uid.object_id,                   MIXART_MEM(mgr, msg_frame_address + 8) );  /* uidDest */
+	writel_be( msg->uid.desc,                        MIXART_MEM(mgr, msg_frame_address + 12) ); /* */
+	writel_be( MSG_DESCRIPTOR_SIZE,                  MIXART_MEM(mgr, msg_frame_address + 16) ); /* SizeHeader */
+	writel_be( MSG_DESCRIPTOR_SIZE,                  MIXART_MEM(mgr, msg_frame_address + 20) ); /* OffsetDLL_T16 */
+	writel_be( msg->size,                            MIXART_MEM(mgr, msg_frame_address + 24) ); /* SizeDLL_T16 */
+	writel_be( MSG_DESCRIPTOR_SIZE,                  MIXART_MEM(mgr, msg_frame_address + 28) ); /* OffsetDLL_DRV */
+	writel_be( 0,                                    MIXART_MEM(mgr, msg_frame_address + 32) ); /* SizeDLL_DRV */
+	writel_be( MSG_DESCRIPTOR_SIZE + max_answersize, MIXART_MEM(mgr, msg_frame_address + 36) ); /* dwExpectedAnswerSize */
+
+	/* copy message data to card memory */
+	for( i=0; i < msg->size; i+=4 ) {
+		writel_be( *(u32*)(msg->data + i), MIXART_MEM(mgr, MSG_HEADER_SIZE + msg_frame_address + i)  );
+	}
+
+	if( mark_pending ) {
+		if( *msg_event ) {
+			/* the pending event is the notification we wait for ! */
+			mgr->pending_event = *msg_event;
+		}
+		else {
+			/* the pending event is the answer we wait for (same address than the request)! */
+			mgr->pending_event = msg_frame_address;
+
+			/* copy address back to caller */
+			*msg_event = msg_frame_address;
+		}
+	}
+
+	/* mark the frame as a request (will have an answer) */
+	msg_frame_address |= MSG_TYPE_REQUEST;
+
+	/* post the frame */
+	headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
+
+	if( (headptr < MSG_INBOUND_POST_STACK) || (headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE))) {
+		err = -EINVAL;
+		goto _clean_exit;
+	}
+
+	writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
+
+	/* increment the inbound post head */
+	headptr += 4;
+	if( headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
+		headptr = MSG_INBOUND_POST_STACK;
+
+	writel_be(headptr, MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
+
+ _clean_exit:
+	spin_unlock_irqrestore(&mgr->msg_lock, flags);
+	return 0;
+}
+
+
+int snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data)
+{
+	mixart_msg_t resp;
+	u32 msg_frame = 0; /* set to 0, so it's no notification to wait for, but the answer */
+	int err;
+	wait_queue_t wait;
+	long timeout;
+
+	down(&mgr->msg_mutex);
+
+	init_waitqueue_head(&mgr->msg_sleep);
+	init_waitqueue_entry(&wait, current);
+
+	current->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue(&mgr->msg_sleep, &wait);
+
+	/* send the message */
+	err = send_msg(mgr, request, max_resp_size, 1, &msg_frame);  /* send and mark the answer pending */
+	if(err) {
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&mgr->msg_sleep, &wait);
+		up(&mgr->msg_mutex);
+		return err;
+	}
+
+	timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&mgr->msg_sleep, &wait);
+
+	if (! timeout) {
+		/* error - no ack */
+		up(&mgr->msg_mutex);
+		snd_printk(KERN_ERR "error: no reponse on msg %x\n", msg_frame);
+		return -EIO;
+	}
+
+	/* retrieve the answer into the same mixart_msg_t */
+	resp.message_id = 0;
+	resp.uid = (mixart_uid_t){0,0};
+	resp.data = resp_data;
+	resp.size = max_resp_size;
+
+	err = get_msg(mgr, &resp, msg_frame);
+
+	if( request->message_id != resp.message_id )
+		snd_printk(KERN_ERR "REPONSE ERROR!\n");
+
+	up(&mgr->msg_mutex);
+	return err;
+}
+
+
+int snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event)
+{
+	int err;
+	wait_queue_t wait;
+	long timeout;
+
+	snd_assert(notif_event != 0, return -EINVAL);
+	snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL);
+	snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL);
+
+	down(&mgr->msg_mutex);
+
+	init_waitqueue_head(&mgr->msg_sleep);
+	init_waitqueue_entry(&wait, current);
+
+	current->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue(&mgr->msg_sleep, &wait);
+
+	/* send the message */
+	err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event);  /* send and mark the notification event pending */
+	if(err) {
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&mgr->msg_sleep, &wait);
+		up(&mgr->msg_mutex);
+		return err;
+	}
+
+	timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&mgr->msg_sleep, &wait);
+
+	if (! timeout) {
+		/* error - no ack */
+		up(&mgr->msg_mutex);
+		snd_printk(KERN_ERR "error: notification %x not received\n", notif_event);
+		return -EIO;
+	}
+
+	up(&mgr->msg_mutex);
+	return 0;
+}
+
+
+int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request)
+{
+	u32 message_frame;
+
+	/* just send the message (do not mark it as a pending one) */
+	return send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
+
+	/* the answer will be handled by snd_mixart_msg_tasklet()  */
+}
+
+
+/* common buffer of tasklet and interrupt to send/receive messages */
+static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];
+
+
+void snd_mixart_msg_tasklet( unsigned long arg)
+{
+	mixart_mgr_t *mgr = ( mixart_mgr_t*)(arg);
+	mixart_msg_t resp;
+	u32 msg, addr, type;
+	int err;
+
+	spin_lock(&mgr->lock);
+
+	while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) {
+		msg = mgr->msg_fifo[mgr->msg_fifo_readptr];
+		mgr->msg_fifo_readptr++;
+		mgr->msg_fifo_readptr %= MSG_FIFO_SIZE;
+
+		/* process the message ... */
+		addr = msg & ~MSG_TYPE_MASK;
+		type = msg & MSG_TYPE_MASK;
+
+		switch (type) {
+		case MSG_TYPE_ANSWER:
+			/* answer to a message on that we did not wait for (send_msg_nonblock) */
+			resp.message_id = 0;
+			resp.data = mixart_msg_data;
+			resp.size = sizeof(mixart_msg_data);
+			err = get_msg(mgr, &resp, addr);
+			if( err < 0 ) {
+				snd_printk(KERN_ERR "tasklet: error(%d) reading mf %x\n", err, msg);
+				break;
+			}
+
+			switch(resp.message_id) {
+			case MSG_STREAM_START_INPUT_STAGE_PACKET:
+			case MSG_STREAM_START_OUTPUT_STAGE_PACKET:
+			case MSG_STREAM_STOP_INPUT_STAGE_PACKET:
+			case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
+				if(mixart_msg_data[0])
+					snd_printdd("tasklet : MSG_STREAM_ST***_***PUT_STAGE_PACKET txx_status(%x)\n", mixart_msg_data[0]);
+				break;
+			case MSG_CLOCK_CHECK_PROPERTIES:
+			case MSG_CLOCK_SET_PROPERTIES:
+				if(mixart_msg_data[0])
+					snd_printdd("tasklet : MSG_CLOCK_***_PROPERTIES txx_status(%x) clock_mode(%x)\n", mixart_msg_data[0], mixart_msg_data[1]);
+				break;
+			case MSG_SYSTEM_WAIT_SYNCHRO_CMD:
+				if(mixart_msg_data[0])
+					snd_printdd("tasklet : MSG_SYSTEM_WAIT_SYNCHRO_CMD txx_status(%x)\n", mixart_msg_data[0]);
+				break;
+			default:
+				snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%d)\n",
+					   msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
+				break;
+			}
+			break;
+		case MSG_TYPE_NOTIFY:
+			/* msg contains no address ! do not get_msg() ! */
+		case MSG_TYPE_COMMAND:
+			/* get_msg() necessary */
+		default:
+			snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg);
+		} /* switch type */
+	} /* while there is a msg in fifo */
+
+	spin_unlock(&mgr->lock);
+}
+
+
+irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, dev_id, return IRQ_NONE);
+	int err;
+	mixart_msg_t resp;
+
+	u32 msg;
+	u32 it_reg;
+
+	spin_lock(&mgr->lock);
+
+	it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET));
+	if( !(it_reg & MIXART_OIDI) ) {
+		/* this device did not cause the interrupt */
+		spin_unlock(&mgr->lock);
+		return IRQ_NONE;
+	}
+
+	/* mask all interrupts */
+	writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET));
+
+	/* outdoorbell register clear */
+	it_reg = readl(MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
+	writel(it_reg, MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
+
+	/* clear interrupt */
+	writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) );
+
+	/* process interrupt */
+	while (retrieve_msg_frame(mgr, &msg)) {
+
+		switch (msg & MSG_TYPE_MASK) {
+		case MSG_TYPE_COMMAND:
+			resp.message_id = 0;
+			resp.data = mixart_msg_data;
+			resp.size = sizeof(mixart_msg_data);
+			err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK);
+			if( err < 0 ) {
+				snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg);
+				break;
+			}
+
+			if(resp.message_id == MSG_SERVICES_TIMER_NOTIFY) {
+				int i;
+				mixart_timer_notify_t *notify = (mixart_timer_notify_t*)mixart_msg_data;
+
+				for(i=0; i<notify->stream_count; i++) {
+
+					u32 buffer_id = notify->streams[i].buffer_id;
+					unsigned int chip_number =  (buffer_id & MIXART_NOTIFY_CARD_MASK) >> MIXART_NOTIFY_CARD_OFFSET; /* card0 to 3 */
+					unsigned int pcm_number  =  (buffer_id & MIXART_NOTIFY_PCM_MASK ) >> MIXART_NOTIFY_PCM_OFFSET;  /* pcm0 to 3  */
+					unsigned int sub_number  =   buffer_id & MIXART_NOTIFY_SUBS_MASK;             /* 0 to MIXART_PLAYBACK_STREAMS */
+					unsigned int is_capture  = ((buffer_id & MIXART_NOTIFY_CAPT_MASK) != 0);      /* playback == 0 / capture == 1 */
+
+					mixart_t *chip  = mgr->chip[chip_number];
+					mixart_stream_t *stream;
+
+					if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) {
+						snd_printk(KERN_DEBUG "ERROR buffer_id (%x) pos(%d)\n", buffer_id, notify->streams[i].sample_pos_low_part);
+						break;
+					}
+
+					if (is_capture)
+						stream = &chip->capture_stream[pcm_number];
+					else
+						stream = &chip->playback_stream[pcm_number][sub_number];
+
+					if (stream->substream && (stream->status == MIXART_STREAM_STATUS_RUNNING)) {
+						snd_pcm_runtime_t *runtime = stream->substream->runtime;
+						int elapsed = 0;
+						u64 sample_count = ((u64)notify->streams[i].sample_pos_high_part) << 32;
+						sample_count |= notify->streams[i].sample_pos_low_part;
+
+						while (1) {
+							u64 new_elapse_pos = stream->abs_period_elapsed +  runtime->period_size;
+
+							if (new_elapse_pos > sample_count) {
+								break; /* while */
+							}
+							else {
+								elapsed = 1;
+								stream->buf_periods++;
+								if (stream->buf_periods >= runtime->periods)
+									stream->buf_periods = 0;
+
+								stream->abs_period_elapsed = new_elapse_pos;
+							}
+						}
+						stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed );
+
+						if(elapsed) {
+							spin_unlock(&mgr->lock);
+							snd_pcm_period_elapsed(stream->substream);
+							spin_lock(&mgr->lock);
+						}
+					}
+				}
+				break;
+			}
+			if(resp.message_id == MSG_SERVICES_REPORT_TRACES) {
+				if(resp.size > 1) {
+#ifndef __BIG_ENDIAN
+					/* Traces are text: the swapped msg_data has to be swapped back ! */
+					int i;
+					for(i=0; i<(resp.size/4); i++) {
+						(mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]);
+					}
+#endif
+					((char*)mixart_msg_data)[resp.size - 1] = 0;
+					snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data);
+				}
+				break;
+			}
+
+			snd_printdd("command %x not handled\n", resp.message_id);
+			break;
+
+		case MSG_TYPE_NOTIFY:
+			if(msg & MSG_CANCEL_NOTIFY_MASK) {
+				msg &= ~MSG_CANCEL_NOTIFY_MASK;
+				snd_printk(KERN_ERR "canceled notification %x !\n", msg);
+			}
+			/* no break, continue ! */
+		case MSG_TYPE_ANSWER:
+			/* answer or notification to a message we are waiting for*/
+			if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
+				wake_up(&mgr->msg_sleep);
+				mgr->pending_event = 0;
+			}
+			/* answer to a message we did't want to wait for */
+			else {
+				mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
+				mgr->msg_fifo_writeptr++;
+				mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
+				tasklet_hi_schedule(&mgr->msg_taskq);
+			}
+			break;
+		case MSG_TYPE_REQUEST:
+		default:
+			snd_printdd("interrupt received request %x\n", msg);
+			/* TODO : are there things to do here ? */
+			break;
+		} /* switch on msg type */
+	} /* while there are msgs */
+
+	/* allow interrupt again */
+	writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
+
+	spin_unlock(&mgr->lock);
+
+	return IRQ_HANDLED;
+}
+
+
+void snd_mixart_init_mailbox(mixart_mgr_t *mgr)
+{
+	writel( 0, MIXART_MEM( mgr, MSG_HOST_RSC_PROTECTION ) );
+	writel( 0, MIXART_MEM( mgr, MSG_AGENT_RSC_PROTECTION ) );
+
+	/* allow outbound messagebox to generate interrupts */
+	if(mgr->irq >= 0) {
+		writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
+	}
+	return;
+}
+
+void snd_mixart_exit_mailbox(mixart_mgr_t *mgr)
+{
+	/* no more interrupts on outbound messagebox */
+	writel_le( MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
+	return;
+}
+
+void snd_mixart_reset_board(mixart_mgr_t *mgr)
+{
+	/* reset miXart */
+	writel_be( 1, MIXART_REG(mgr, MIXART_BA1_BRUTAL_RESET_OFFSET) );
+	return;
+}
diff -Nru a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_core.h	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,607 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * low level interface with interrupt handling and mail box implementation
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_MIXART_CORE_H
+#define __SOUND_MIXART_CORE_H
+
+
+enum mixart_message_id {
+	MSG_CONNECTOR_GET_AUDIO_INFO         = 0x050008,
+	MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL    = 0x050009,
+	MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL    = 0x05000A,
+
+	MSG_CONSOLE_MANAGER                  = 0x070000,
+	MSG_CONSOLE_GET_CLOCK_UID            = 0x070003,
+
+	MSG_PHYSICALIO_SET_LEVEL             = 0x0F0008,
+
+	MSG_STREAM_ADD_INPUT_GROUP           = 0x130000,
+	MSG_STREAM_ADD_OUTPUT_GROUP          = 0x130001,
+	MSG_STREAM_DELETE_GROUP              = 0x130004,
+	MSG_STREAM_START_STREAM_GRP_PACKET   = 0x130006,
+	MSG_STREAM_START_INPUT_STAGE_PACKET  = 0x130007,
+	MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130008,
+	MSG_STREAM_STOP_STREAM_GRP_PACKET    = 0x130009,
+	MSG_STREAM_STOP_INPUT_STAGE_PACKET   = 0x13000A,
+	MSG_STREAM_STOP_OUTPUT_STAGE_PACKET  = 0x13000B,
+	MSG_STREAM_SET_INPUT_STAGE_PARAM     = 0x13000F,
+	MSG_STREAM_SET_OUTPUT_STAGE_PARAM    = 0x130010,
+	MSG_STREAM_SET_IN_AUDIO_LEVEL        = 0x130015,
+	MSG_STREAM_SET_OUT_STREAM_LEVEL      = 0x130017,
+
+	MSG_SYSTEM_FIRST_ID                  = 0x160000,
+	MSG_SYSTEM_ENUM_PHYSICAL_IO          = 0x16000E,
+	MSG_SYSTEM_ENUM_PLAY_CONNECTOR       = 0x160017,
+	MSG_SYSTEM_ENUM_RECORD_CONNECTOR     = 0x160018,
+	MSG_SYSTEM_WAIT_SYNCHRO_CMD          = 0x16002C,
+	MSG_SYSTEM_SEND_SYNCHRO_CMD          = 0x16002D,
+
+	MSG_SERVICES_TIMER_NOTIFY            = 0x1D0404,
+	MSG_SERVICES_REPORT_TRACES           = 0x1D0700,
+
+	MSG_CLOCK_CHECK_PROPERTIES           = 0x200001,
+	MSG_CLOCK_SET_PROPERTIES             = 0x200002,
+};
+
+
+typedef struct mixart_msg mixart_msg_t;
+struct mixart_msg
+{
+	u32          message_id;
+	mixart_uid_t uid;
+	void*        data;
+	size_t       size;
+};
+
+/* structs used to communicate with miXart */
+
+typedef struct mixart_enum_connector_resp mixart_enum_connector_resp_t;
+struct mixart_enum_connector_resp
+{
+	u32  error_code;
+	u32  first_uid_offset;
+	u32  uid_count;
+	u32  current_uid_index;
+	mixart_uid_t uid[MIXART_MAX_PHYS_CONNECTORS];
+} __attribute__((packed));
+
+
+/* used for following struct */
+#define MIXART_FLOAT_P_22_0_TO_HEX      0x41b00000  /* 22.0f */
+#define MIXART_FLOAT_M_20_0_TO_HEX      0xc1a00000  /* -20.0f */
+#define MIXART_FLOAT____0_0_TO_HEX      0x00000000  /* 0.0f */
+
+typedef struct mixart_audio_info_req mixart_audio_info_req_t;
+struct mixart_audio_info_req
+{
+	u32 line_max_level;    /* float */
+	u32 micro_max_level;   /* float */
+	u32 cd_max_level;      /* float */
+} __attribute__((packed));
+
+typedef struct mixart_analog_hw_info mixart_analog_hw_info_t;
+struct mixart_analog_hw_info
+{
+	u32 is_present;
+	u32 hw_connection_type;
+	u32 max_level;         /* float */
+	u32 min_var_level;     /* float */
+	u32 max_var_level;     /* float */
+	u32 step_var_level;    /* float */
+	u32 fix_gain;          /* float */
+	u32 zero_var;          /* float */
+} __attribute__((packed));
+
+typedef struct mixart_digital_hw_info mixart_digital_hw_info_t;
+struct mixart_digital_hw_info
+{
+	u32   hw_connection_type;
+	u32   presence;
+	u32   clock;
+	u32   reserved;
+} __attribute__((packed));
+
+typedef struct mixart_analog_info mixart_analog_info_t;
+struct mixart_analog_info
+{
+	u32                     type_mask;
+	mixart_analog_hw_info_t micro_info;
+	mixart_analog_hw_info_t line_info;
+	mixart_analog_hw_info_t cd_info;
+	u32                     analog_level_present;
+} __attribute__((packed));
+
+typedef struct mixart_digital_info mixart_digital_info_t;
+struct mixart_digital_info
+{
+	u32 type_mask;
+	mixart_digital_hw_info_t aes_info;
+	mixart_digital_hw_info_t adat_info;
+} __attribute__((packed));
+
+typedef struct mixart_audio_info mixart_audio_info_t;
+struct mixart_audio_info
+{
+	u32                   clock_type_mask;
+	mixart_analog_info_t  analog_info;
+	mixart_digital_info_t digital_info;
+} __attribute__((packed));
+
+typedef struct mixart_audio_info_resp mixart_audio_info_resp_t;
+struct mixart_audio_info_resp
+{
+	u32                 txx_status;
+	mixart_audio_info_t info;
+} __attribute__((packed));
+
+
+/* used for nb_bytes_max_per_sample */
+#define MIXART_FLOAT_P__4_0_TO_HEX      0x40800000  /* +4.0f */
+#define MIXART_FLOAT_P__8_0_TO_HEX      0x41000000  /* +8.0f */
+
+typedef struct mixart_stream_info mixart_stream_info_t;
+struct mixart_stream_info
+{
+	u32 size_max_byte_frame;
+	u32 size_max_sample_frame;
+	u32 nb_bytes_max_per_sample;  /* float */
+} __attribute__((packed));
+
+/*  MSG_STREAM_ADD_INPUT_GROUP */
+/*  MSG_STREAM_ADD_OUTPUT_GROUP */
+
+typedef struct mixart_streaming_group_req mixart_streaming_group_req_t;
+struct mixart_streaming_group_req
+{
+	u32 stream_count;
+	u32 channel_count;
+	u32 user_grp_number;
+	u32 first_phys_audio;
+	u32 latency;
+	mixart_stream_info_t stream_info[32];
+	mixart_uid_t connector;
+	u32 flow_entry[32];
+} __attribute__((packed));
+
+typedef struct mixart_stream_desc mixart_stream_desc_t;
+struct mixart_stream_desc
+{
+	mixart_uid_t stream_uid;
+	u32          stream_desc;
+} __attribute__((packed));
+
+typedef struct mixart_streaming_group mixart_streaming_group_t;
+struct mixart_streaming_group
+{
+	u32                  status;
+	mixart_uid_t         group;
+	u32                  pipe_desc;
+	u32                  stream_count;
+	mixart_stream_desc_t stream[32];
+} __attribute__((packed));
+
+/* MSG_STREAM_DELETE_GROUP */
+
+/* request : mixart_uid_t group */
+
+typedef struct mixart_delete_group_resp mixart_delete_group_resp_t;
+struct mixart_delete_group_resp
+{
+	u32  status;
+	u32  unused[2];
+} __attribute__((packed));
+
+
+/* 	MSG_STREAM_START_INPUT_STAGE_PACKET  = 0x130000 + 7,
+	MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130000 + 8,
+	MSG_STREAM_STOP_INPUT_STAGE_PACKET   = 0x130000 + 10,
+	MSG_STREAM_STOP_OUTPUT_STAGE_PACKET  = 0x130000 + 11,
+ */
+
+typedef struct mixart_fx_couple_uid mixart_fx_couple_uid_t;
+struct mixart_fx_couple_uid
+{
+	mixart_uid_t uid_fx_code;
+	mixart_uid_t uid_fx_data;
+} __attribute__((packed));
+
+typedef struct mixart_txx_stream_desc mixart_txx_stream_desc_t;
+struct mixart_txx_stream_desc
+{
+	mixart_uid_t            uid_pipe;
+	u32                     stream_idx;
+	u32                     fx_number;
+	mixart_fx_couple_uid_t  uid_fx[4];
+} __attribute__((packed));
+
+typedef struct mixart_flow_info mixart_flow_info_t;
+struct mixart_flow_info
+{
+	mixart_txx_stream_desc_t  stream_desc;
+	u32                       flow_entry;
+	u32                       flow_phy_addr;
+} __attribute__((packed));
+
+typedef struct mixart_stream_state_req mixart_stream_state_req_t;
+struct mixart_stream_state_req
+{
+	u32                 delayed;
+	u64                 scheduler;
+	u32                 reserved4np[3];
+	u32                 stream_count;  /* set to 1 for instance */
+	mixart_flow_info_t  stream_info;   /* could be an array[stream_count] */
+} __attribute__((packed));
+
+/* 	MSG_STREAM_START_STREAM_GRP_PACKET   = 0x130000 + 6
+	MSG_STREAM_STOP_STREAM_GRP_PACKET    = 0x130000 + 9
+ */
+
+typedef struct mixart_group_state_req mixart_group_state_req_t;
+struct mixart_group_state_req
+{
+	u32           delayed;
+	u64           scheduler;
+	u32           reserved4np[2];
+	u32           pipe_count;    /* set to 1 for instance */
+	mixart_uid_t  pipe_uid[1];   /* could be an array[pipe_count] */
+} __attribute__((packed));
+
+typedef struct mixart_group_state_resp mixart_group_state_resp_t;
+struct mixart_group_state_resp
+{
+	u32           txx_status;
+	u64           scheduler;
+} __attribute__((packed));
+
+
+
+/* Structures used by the MSG_SERVICES_TIMER_NOTIFY command */
+
+typedef struct mixart_sample_pos mixart_sample_pos_t;
+struct mixart_sample_pos
+{
+	u32   buffer_id;
+	u32   validity;
+	u32   sample_pos_high_part;
+	u32   sample_pos_low_part;
+} __attribute__((packed));
+
+typedef struct mixart_timer_notify mixart_timer_notify_t;
+struct mixart_timer_notify
+{
+	u32                  stream_count;
+	mixart_sample_pos_t  streams[MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS];
+} __attribute__((packed));
+
+
+/*	MSG_CONSOLE_GET_CLOCK_UID            = 0x070003,
+ */
+
+/* request is a uid with desc = MSG_CONSOLE_MANAGER | cardindex */
+
+typedef struct mixart_return_uid mixart_return_uid_t;
+struct mixart_return_uid
+{
+	u32 error_code;
+	mixart_uid_t uid;
+} __attribute__((packed));
+
+/*	MSG_CLOCK_CHECK_PROPERTIES           = 0x200001,
+	MSG_CLOCK_SET_PROPERTIES             = 0x200002,
+*/
+
+enum mixart_clock_generic_type {
+	CGT_NO_CLOCK,
+	CGT_INTERNAL_CLOCK,
+	CGT_PROGRAMMABLE_CLOCK,
+	CGT_INTERNAL_ENSLAVED_CLOCK,
+	CGT_EXTERNAL_CLOCK,
+	CGT_CURRENT_CLOCK
+};
+
+enum mixart_clock_mode {
+	CM_UNDEFINED,
+	CM_MASTER,
+	CM_SLAVE,
+	CM_STANDALONE,
+	CM_NOT_CONCERNED
+};
+
+
+typedef struct mixart_clock_properties mixart_clock_properties_t;
+struct mixart_clock_properties
+{
+	u32 error_code;
+	u32 validation_mask;
+	u32 frequency;
+	u32 reference_frequency;
+	u32 clock_generic_type;
+	u32 clock_mode;
+	mixart_uid_t uid_clock_source;
+	mixart_uid_t uid_event_source;
+	u32 event_mode;
+	u32 synchro_signal_presence;
+	u32 format;
+	u32 board_mask;
+	u32 nb_callers; /* set to 1 (see below) */
+	mixart_uid_t uid_caller[1];
+} __attribute__((packed));
+
+typedef struct mixart_clock_properties_resp mixart_clock_properties_resp_t;
+struct mixart_clock_properties_resp
+{
+	u32 status;
+	u32 clock_mode;
+} __attribute__((packed));
+
+
+/*	MSG_STREAM_SET_INPUT_STAGE_PARAM     = 0x13000F */
+/*	MSG_STREAM_SET_OUTPUT_STAGE_PARAM    = 0x130010 */
+
+enum mixart_coding_type {
+	CT_NOT_DEFINED,
+	CT_LINEAR,
+	CT_MPEG_L1,
+	CT_MPEG_L2,
+	CT_MPEG_L3,
+	CT_MPEG_L3_LSF,
+	CT_GSM
+};
+enum mixart_sample_type {
+	ST_NOT_DEFINED,
+	ST_FLOATING_POINT_32BE,
+	ST_FLOATING_POINT_32LE,
+	ST_FLOATING_POINT_64BE,
+	ST_FLOATING_POINT_64LE,
+	ST_FIXED_POINT_8,
+	ST_FIXED_POINT_16BE,
+	ST_FIXED_POINT_16LE,
+	ST_FIXED_POINT_24BE,
+	ST_FIXED_POINT_24LE,
+	ST_FIXED_POINT_32BE,
+	ST_FIXED_POINT_32LE,
+	ST_INTEGER_8,
+	ST_INTEGER_16BE,
+	ST_INTEGER_16LE,
+	ST_INTEGER_24BE,
+	ST_INTEGER_24LE,
+	ST_INTEGER_32BE,
+	ST_INTEGER_32LE
+};
+
+typedef struct mixart_stream_param_desc mixart_stream_param_desc_t;
+struct mixart_stream_param_desc
+{
+	u32 coding_type;  /* use enum mixart_coding_type */
+	u32 sample_type;  /* use enum mixart_sample_type */
+
+	union {
+		struct {
+			u32 linear_endian_ness;
+			u32 linear_bits;
+			u32 is_signed;
+			u32 is_float;
+		} linear_format_info;
+
+		struct {
+			u32 mpeg_layer;
+			u32 mpeg_mode;
+			u32 mpeg_mode_extension;
+			u32 mpeg_pre_emphasis;
+			u32 mpeg_has_padding_bit;
+			u32 mpeg_has_crc;
+			u32 mpeg_has_extension;
+			u32 mpeg_is_original;
+			u32 mpeg_has_copyright;
+		} mpeg_format_info;
+	} format_info;
+
+	u32 delayed;
+	u64 scheduler;
+	u32 sample_size;
+	u32 has_header;
+	u32 has_suffix;
+	u32 has_bitrate;
+	u32 samples_per_frame;
+	u32 bytes_per_frame;
+	u32 bytes_per_sample;
+	u32 sampling_freq;
+	u32 number_of_channel;
+	u32 stream_number;
+	u32 buffer_size;
+	u32 differed_time;
+	u32 reserved4np[3];
+	u32 pipe_count;                           /* set to 1 (array size !) */
+	u32 stream_count;                         /* set to 1 (array size !) */
+	mixart_txx_stream_desc_t stream_desc[1];  /* only one stream per command, but this could be an array */
+
+} __attribute__((packed));
+
+
+/*	MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL    = 0x050009,
+ */
+
+
+typedef struct mixart_get_out_audio_level mixart_get_out_audio_level_t;
+struct mixart_get_out_audio_level
+{
+	u32 txx_status;
+	u32 digital_level;   /* float */
+	u32 analog_level;    /* float */
+	u32 monitor_level;   /* float */
+	u32 mute;
+	u32 monitor_mute1;
+	u32 monitor_mute2;
+} __attribute__((packed));
+
+
+/*	MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL    = 0x05000A,
+ */
+
+/* used for valid_mask below */
+#define MIXART_AUDIO_LEVEL_ANALOG_MASK	0x01
+#define MIXART_AUDIO_LEVEL_DIGITAL_MASK	0x02
+#define MIXART_AUDIO_LEVEL_MONITOR_MASK	0x04
+#define MIXART_AUDIO_LEVEL_MUTE_MASK	0x08
+#define MIXART_AUDIO_LEVEL_MUTE_M1_MASK	0x10
+#define MIXART_AUDIO_LEVEL_MUTE_M2_MASK	0x20
+
+typedef struct mixart_set_out_audio_level mixart_set_out_audio_level_t;
+struct mixart_set_out_audio_level
+{
+	u32 delayed;
+	u64 scheduler;
+	u32 valid_mask1;
+	u32 valid_mask2;
+	u32 digital_level;   /* float */
+	u32 analog_level;    /* float */
+	u32 monitor_level;   /* float */
+	u32 mute;
+	u32 monitor_mute1;
+	u32 monitor_mute2;
+	u32 reserved4np;
+} __attribute__((packed));
+
+
+/*	MSG_SYSTEM_ENUM_PHYSICAL_IO          = 0x16000E,
+ */
+
+#define MIXART_MAX_PHYS_IO  (MIXART_MAX_CARDS * 2 * 2) /* 4 * (analog+digital) * (playback+capture) */
+
+typedef struct mixart_uid_enumeration mixart_uid_enumeration_t;
+struct mixart_uid_enumeration
+{
+	u32 error_code;
+	u32 first_uid_offset;
+	u32 nb_uid;
+	u32 current_uid_index;
+	mixart_uid_t uid[MIXART_MAX_PHYS_IO];
+} __attribute__((packed));
+
+
+/*	MSG_PHYSICALIO_SET_LEVEL             = 0x0F0008,
+	MSG_PHYSICALIO_GET_LEVEL             = 0x0F000C,
+*/
+
+typedef struct mixart_io_channel_level mixart_io_channel_level_t;
+struct mixart_io_channel_level
+{
+	u32 analog_level;   /* float */
+	u32 unused[2];
+} __attribute__((packed));
+
+typedef struct mixart_io_level mixart_io_level_t;
+struct mixart_io_level
+{
+	s32 channel; /* 0=left, 1=right, -1=both, -2=both same */
+	mixart_io_channel_level_t level[2];
+} __attribute__((packed));
+
+
+/*	MSG_STREAM_SET_IN_AUDIO_LEVEL        = 0x130015,
+ */
+
+typedef struct mixart_in_audio_level_info mixart_in_audio_level_info_t;
+struct mixart_in_audio_level_info
+{
+	mixart_uid_t connector;
+	u32 valid_mask1;
+	u32 valid_mask2;
+	u32 digital_level;
+	u32 analog_level;
+} __attribute__((packed));
+
+typedef struct mixart_set_in_audio_level_req mixart_set_in_audio_level_req_t;
+struct mixart_set_in_audio_level_req
+{
+	u32 delayed;
+	u64 scheduler;
+	u32 audio_count;  /* set to <= 2 */
+	u32 reserved4np;
+	mixart_in_audio_level_info_t level[2];
+} __attribute__((packed));
+
+/* response is a 32 bit status */
+
+
+/*	MSG_STREAM_SET_OUT_STREAM_LEVEL      = 0x130017,
+ */
+
+/* defines used for valid_mask1 */
+#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO1		0x01
+#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO2		0x02
+#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO1	0x04
+#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO2	0x08
+#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_1		0x10
+#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_2		0x20
+#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_1		0x40
+#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_2		0x80
+
+typedef struct mixart_out_stream_level_info mixart_out_stream_level_info_t;
+struct mixart_out_stream_level_info
+{
+	u32 valid_mask1;
+	u32 valid_mask2;
+	u32 left_to_out1_level;
+	u32 left_to_out2_level;
+	u32 right_to_out1_level;
+	u32 right_to_out2_level;
+	u32 digital_level1;
+	u32 digital_level2;
+	u32 mute1;
+	u32 mute2;
+} __attribute__((packed));
+
+typedef struct mixart_set_out_stream_level mixart_set_out_stream_level_t;
+struct mixart_set_out_stream_level
+{
+	mixart_txx_stream_desc_t desc;
+	mixart_out_stream_level_info_t out_level;
+} __attribute__((packed));
+
+typedef struct mixart_set_out_stream_level_req mixart_set_out_stream_level_req_t;
+struct mixart_set_out_stream_level_req
+{
+	u32 delayed;
+	u64 scheduler;
+	u32 reserved4np[2];
+	u32 nb_of_stream;  /* set to 1 */
+	mixart_set_out_stream_level_t stream_level; /* could be an array */
+} __attribute__((packed));
+
+/* response to this request is a u32 status value */
+
+
+/* exported */
+void snd_mixart_init_mailbox(mixart_mgr_t *mgr);
+void snd_mixart_exit_mailbox(mixart_mgr_t *mgr);
+
+int  snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data);
+int  snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event);
+int  snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request);
+
+irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+void snd_mixart_msg_tasklet( unsigned long arg);
+
+void snd_mixart_reset_board(mixart_mgr_t *mgr);
+
+#endif /* __SOUND_MIXART_CORE_H */
diff -Nru a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_hwdep.c	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,570 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * hwdep device manager
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include "mixart.h"
+#include "mixart_mixer.h"
+#include "mixart_core.h"
+#include "mixart_hwdep.h"
+
+
+/* miXart hwdep interface id string */
+#define SND_MIXART_HWDEP_ID       "miXart Loader"
+
+static int mixart_hwdep_open(snd_hwdep_t *hw, struct file *file)
+{
+	return 0;
+}
+
+static int mixart_hwdep_release(snd_hwdep_t *hw, struct file *file)
+{
+	return 0;
+}
+
+/**
+ * wait for a value on a peudo register, exit with a timeout
+ *
+ * @param mgr pointer to miXart manager structure
+ * @param offset unsigned pseudo_register base + offset of value
+ * @param value value
+ * @param timeout timeout in centisenconds
+ */
+static int mixart_wait_nice_for_register_value(mixart_mgr_t *mgr, u32 offset, int is_egal, u32 value, unsigned long timeout)
+{
+	unsigned long end_time = jiffies + (timeout * HZ / 100);
+	u32 read;
+
+	do {	/* we may take too long time in this loop.
+		 * so give controls back to kernel if needed.
+		 */
+		cond_resched();
+
+		read = readl_be( MIXART_MEM( mgr, offset ));
+		if(is_egal) {
+			if(read == value) return 0;
+		}
+		else { /* wait for different value */
+			if(read != value) return 0;
+		}
+	} while ( time_after_eq(end_time, jiffies) );
+
+	return -EBUSY;
+}
+
+
+/*
+  structures needed to upload elf code packets 
+ */
+typedef struct snd_mixart_elf32_ehdr snd_mixart_elf32_ehdr_t;
+
+struct snd_mixart_elf32_ehdr {
+	u8      e_ident[16];
+	u16     e_type;
+	u16     e_machine;
+	u32     e_version;
+	u32     e_entry;
+	u32     e_phoff;
+	u32     e_shoff;
+	u32     e_flags;
+	u16     e_ehsize;
+	u16     e_phentsize;
+	u16     e_phnum;
+	u16     e_shentsize;
+	u16     e_shnum;
+	u16     e_shstrndx;
+};
+
+typedef struct snd_mixart_elf32_phdr snd_mixart_elf32_phdr_t;
+
+struct snd_mixart_elf32_phdr {
+	u32     p_type;
+	u32     p_offset;
+	u32     p_vaddr;
+	u32     p_paddr;
+	u32     p_filesz;
+	u32     p_memsz;
+	u32     p_flags;
+	u32     p_align;
+};
+
+static int mixart_load_elf(mixart_mgr_t *mgr, snd_hwdep_dsp_image_t *dsp )
+{
+	char                    elf32_magic_number[4] = {0x7f,'E','L','F'};
+	snd_mixart_elf32_ehdr_t elf_header;
+	int                     i;
+
+	if ( copy_from_user(&elf_header, dsp->image , sizeof(snd_mixart_elf32_ehdr_t)) )
+		return -EFAULT;
+
+	for( i=0; i<4; i++ )
+		if ( elf32_magic_number[i] != elf_header.e_ident[i] )
+			return -EINVAL;
+
+	if( elf_header.e_phoff != 0 ) {
+		snd_mixart_elf32_phdr_t     elf_programheader;
+
+		for( i=0; i < be16_to_cpu(elf_header.e_phnum); i++ ) {
+			u32 pos = be32_to_cpu(elf_header.e_phoff) + (u32)(i * be16_to_cpu(elf_header.e_phentsize));
+
+			if( copy_from_user( &elf_programheader, dsp->image + pos, sizeof(elf_programheader) ) )
+				return -EFAULT;
+
+			if(elf_programheader.p_type != 0) {
+				if( elf_programheader.p_filesz != 0 ) {
+					if(copy_from_user_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
+								dsp->image + be32_to_cpu( elf_programheader.p_offset ),
+								be32_to_cpu( elf_programheader.p_filesz )))
+						return -EFAULT;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static int mixart_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info)
+{
+	mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, hw->private_data, return -ENXIO);
+
+	strcpy(info->id, "miXart");
+        info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX;
+
+	if (mgr->hwdep->dsp_loaded & (1 <<  MIXART_MOTHERBOARD_ELF_INDEX))
+		info->chip_ready = 1;
+
+	info->version = MIXART_DRIVER_VERSION;
+	return 0;
+}
+
+/*
+ * get basic information and init miXart
+ */
+
+/* audio IDs for request to the board */
+#define MIXART_FIRST_ANA_AUDIO_ID       0
+#define MIXART_FIRST_DIG_AUDIO_ID       8
+
+static int mixart_enum_connectors(mixart_mgr_t *mgr)
+{
+	u32 k;
+	int err;
+	mixart_msg_t request;
+	mixart_enum_connector_resp_t connector;
+	mixart_audio_info_req_t  audio_info_req;
+	mixart_audio_info_resp_t audio_info;
+
+	audio_info_req.line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
+	audio_info_req.micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
+	audio_info_req.cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
+
+	request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
+	request.uid = (mixart_uid_t){0,0};  /* board num = 0 */
+	request.data = NULL;
+	request.size = 0;
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(connector), &connector);
+	if((err < 0) || (connector.error_code) || (connector.uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
+		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
+		return -EINVAL;
+	}
+
+	for(k=0; k < connector.uid_count; k++) {
+		mixart_pipe_t* pipe;
+
+		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
+			pipe = &mgr->chip[k/2]->pipe_out_ana;
+		} else {
+			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
+		}
+		if(k & 1) {
+			pipe->uid_right_connector = connector.uid[k];   /* odd */
+		} else {
+			pipe->uid_left_connector = connector.uid[k];    /* even */
+		}
+
+		/* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector.uid[k].object_id); */
+
+		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
+		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
+		request.uid = connector.uid[k];
+		request.data = &audio_info_req;
+		request.size = sizeof(audio_info_req);
+
+		err = snd_mixart_send_msg(mgr, &request, sizeof(audio_info), &audio_info);
+		if( err < 0 ) {
+			snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
+			return err;
+		}
+		/*snd_printk(KERN_DEBUG "play  analog_info.analog_level_present = %x\n", audio_info.info.analog_info.analog_level_present);*/
+	}
+
+	request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
+	request.uid = (mixart_uid_t){0,0};  /* board num = 0 */
+	request.data = NULL;
+	request.size = 0;
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(connector), &connector);
+	if((err < 0) || (connector.error_code) || (connector.uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
+		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
+		return -EINVAL;
+	}
+
+	for(k=0; k < connector.uid_count; k++) {
+		mixart_pipe_t* pipe;
+
+		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
+			pipe = &mgr->chip[k/2]->pipe_in_ana;
+		} else {
+			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
+		}
+		if(k & 1) {
+			pipe->uid_right_connector = connector.uid[k];   /* odd */
+		} else {
+			pipe->uid_left_connector = connector.uid[k];    /* even */
+		}
+
+		/* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector.uid[k].object_id); */
+
+		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
+		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
+		request.uid = connector.uid[k];
+		request.data = &audio_info_req;
+		request.size = sizeof(audio_info_req);
+
+		err = snd_mixart_send_msg(mgr, &request, sizeof(audio_info), &audio_info);
+		if( err < 0 ) {
+			snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
+			return err;
+		}
+		/*snd_printk(KERN_DEBUG "rec  analog_info.analog_level_present = %x\n", audio_info.info.analog_info.analog_level_present);*/
+	}
+
+	return 0;
+}
+
+static int mixart_enum_physio(mixart_mgr_t *mgr)
+{
+	u32 k;
+	int err;
+	mixart_msg_t request;
+	mixart_uid_t get_console_mgr;
+	mixart_return_uid_t console_mgr;
+	mixart_uid_enumeration_t phys_io;
+
+	/* get the uid for the console manager */
+	get_console_mgr.object_id = 0;
+	get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */
+
+	request.message_id = MSG_CONSOLE_GET_CLOCK_UID;
+	request.uid = get_console_mgr;
+	request.data = &get_console_mgr;
+	request.size = sizeof(get_console_mgr);
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
+
+	if( (err < 0) || (console_mgr.error_code != 0) ) {
+		snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code);
+		return -EINVAL;
+	}
+
+	/* used later for clock issues ! */
+	mgr->uid_console_manager = console_mgr.uid;
+
+	request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &console_mgr.uid;
+	request.size = sizeof(console_mgr.uid);
+
+	err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
+	if( (err < 0) || ( phys_io.error_code != 0 ) ) {
+		snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code );
+		return -EINVAL;
+	}
+
+	snd_assert(phys_io.nb_uid >= (MIXART_MAX_CARDS * 2),  return -EINVAL); /* min 2 phys io per card (analog in + analog out) */
+
+	for(k=0; k<mgr->num_cards; k++) {
+		mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
+		mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k]; 
+	}
+
+	return 0;
+}
+
+
+static int mixart_first_init(mixart_mgr_t *mgr)
+{
+	u32 k;
+	int err;
+	mixart_msg_t request;
+
+	if((err = mixart_enum_connectors(mgr)) < 0) return err;
+
+	if((err = mixart_enum_physio(mgr)) < 0) return err;
+
+	/* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */
+	/* though why not here */
+	request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = NULL;
+	request.size = 0;
+	/* this command has no data. response is a 32 bit status */
+	err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
+	if( (err < 0) || (k != 0) ) {
+		snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
+		return err == 0 ? -EINVAL : err;
+	}
+
+	return 0;
+}
+
+
+/* firmware base addresses (when hard coded) */
+#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS   0x00600000
+
+static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
+{
+	mixart_mgr_t* mgr = snd_magic_cast(mixart_mgr_t, hw->private_data, return -ENXIO);
+	int           err, card_index;
+	u32           status_xilinx, status_elf, status_daught;
+	u32           val;
+
+	/* read motherboard xilinx status */
+	status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
+	/* read elf status */
+	status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
+	/* read daughterboard xilinx status */
+	status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
+
+	/* motherboard xilinx status 5 will say that the board is performing a reset */
+	if( status_xilinx == 5 ) {
+		snd_printk( KERN_ERR "miXart is resetting !\n");
+		return -EAGAIN; /* try again later */
+	}
+
+	switch (dsp->index)   {
+	case MIXART_MOTHERBOARD_XLX_INDEX:
+
+		/* xilinx already loaded ? */ 
+		if( status_xilinx == 4 ) {
+			snd_printk( KERN_DEBUG "xilinx is already loaded !\n");
+			return 0;
+		}
+		/* the status should be 0 == "idle" */
+		if( status_xilinx != 0 ) {
+			snd_printk( KERN_ERR "xilinx load error ! status = %d\n", status_xilinx);
+			return -EIO; /* modprob -r may help ? */
+		}
+
+		/* check xilinx validity */
+		snd_assert(((u32*)(dsp->image))[0]==0xFFFFFFFF, return -EINVAL);
+		snd_assert(dsp->length % 4 == 0, return -EINVAL);
+
+		/* set xilinx status to copying */
+		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
+
+		/* setup xilinx base address */
+		writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
+		/* setup code size for xilinx file */
+		writel_be( dsp->length, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
+
+		/* copy xilinx code */
+		if (copy_from_user_toio(  MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS),  dsp->image,  dsp->length))
+			return -EFAULT;
+    
+		/* set xilinx status to copy finished */
+		writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
+
+		/* return, because no further processing needed */
+		return 0;
+
+	case MIXART_MOTHERBOARD_ELF_INDEX:
+
+		if( status_elf == 4 ) {
+			snd_printk( KERN_DEBUG "elf file already loaded !\n");
+			return 0;
+		}
+
+		/* the status should be 0 == "idle" */
+		if( status_elf != 0 ) {
+			snd_printk( KERN_ERR "elf load error ! status = %d\n", status_elf);
+			return -EIO; /* modprob -r may help ? */
+		}
+
+		/* wait for xilinx status == 4 */
+		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
+		if (err < 0) {
+			snd_printk( KERN_ERR "xilinx was not loaded or could not be started\n");
+			return err;
+		}
+
+		/* init some data on the card */
+		writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) ); /* set miXart boardnumber to 0 */
+		writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) );         /* reset pointer to flow table on miXart */
+
+		/* set elf status to copying */
+		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
+
+		/* process the copying of the elf packets */
+		err = mixart_load_elf( mgr, dsp);
+		if (err < 0) return err;
+
+		/* set elf status to copy finished */
+		writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
+
+		/* wait for elf status == 4 */
+		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
+		if (err < 0) {
+			snd_printk( KERN_ERR "elf could not be started\n");
+			return err;
+		}
+
+		/* miXart waits at this point on the pointer to the flow table */
+		writel_be( (u32)mgr->flowinfo_physaddr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* give pointer of flow table to miXart */
+
+		return 0;  /* return, another xilinx file has to be loaded before */
+
+	case MIXART_AESEBUBOARD_XLX_INDEX:
+	default:
+
+		/* elf and xilinx should be loaded */
+		if( (status_elf != 4) || (status_xilinx != 4) ) {
+			printk( KERN_ERR "xilinx or elf not successfully loaded\n");
+			return -EIO; /* modprob -r may help ? */
+		}
+
+		/* wait for daughter detection != 0 */
+		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
+		if (err < 0) {
+			snd_printk( KERN_ERR "error starting elf file\n");
+			return err;
+		}
+
+		/* the board type can now be retrieved */
+		mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET)));
+
+		if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE)
+			break;  /* no daughter board; the file does not have to be loaded, continue after the switch */
+
+		/* only if aesebu daughter board presence (elf code must run)  */ 
+		if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES )
+			return -EINVAL;
+
+		/* daughter should be idle */
+		if( status_daught != 0 ) {
+			printk( KERN_ERR "daughter load error ! status = %d\n", status_daught);
+			return -EIO; /* modprob -r may help ? */
+		}
+ 
+		/* check daughterboard xilinx validity */
+		snd_assert(((u32*)(dsp->image))[0]==0xFFFFFFFF, return -EINVAL);
+		snd_assert(dsp->length % 4 == 0, return -EINVAL);
+
+		/* inform mixart about the size of the file */
+		writel_be( dsp->length, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
+
+		/* set daughterboard status to 1 */
+		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
+
+		/* wait for status == 2 */
+		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
+		if (err < 0) {
+			snd_printk( KERN_ERR "daughter board load error\n");
+			return err;
+		}
+
+		/* get the address where to write the file */
+		val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
+		snd_assert(val != 0, return -EINVAL);
+
+		/* copy daughterboard xilinx code */
+		if (copy_from_user_toio(  MIXART_MEM( mgr, val),  dsp->image,  dsp->length))
+			return -EFAULT;
+
+		/* set daughterboard status to 4 */
+		writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
+
+		/* continue with init */
+		break;
+	} /* end of switch file index*/
+
+        /* wait for daughter status == 3 */
+        err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
+        if (err < 0) {
+		snd_printk( KERN_ERR "daughter board could not be initialised\n");
+		return err;
+	}
+
+	/* init mailbox (communication with embedded) */
+	snd_mixart_init_mailbox(mgr);
+
+	/* first communication with embedded */
+	err = mixart_first_init(mgr);
+        if (err < 0) {
+		snd_printk( KERN_ERR "miXart could not be set up\n");
+		return err;
+	}
+
+       	/* create devices and mixer in accordance with HW options*/
+        for (card_index = 0; card_index < mgr->num_cards; card_index++) {
+		mixart_t *chip = mgr->chip[card_index];
+
+		if ((err = snd_mixart_create_pcm(chip)) < 0)
+			return err;
+
+		if (card_index == 0) {
+			if ((err = snd_mixart_create_mixer(chip->mgr)) < 0)
+	        		return err;
+		}
+
+		if ((err = snd_card_register(chip->card)) < 0)
+			return err;
+	};
+
+	snd_printdd("miXart firmware downloaded and successfully set up\n");
+
+	return 0;
+}
+
+
+int snd_mixart_hwdep_new(mixart_mgr_t *mgr)
+{
+	int err;
+	snd_hwdep_t *hw;
+
+	/* only create hwdep interface for first cardX (see "index" module parameter)*/
+	if ((err = snd_hwdep_new(mgr->chip[0]->card, SND_MIXART_HWDEP_ID, 0, &hw)) < 0)
+		return err;
+
+	hw->iface = SNDRV_HWDEP_IFACE_MIXART;
+	hw->private_data = mgr;
+	hw->ops.open = mixart_hwdep_open;
+	hw->ops.release = mixart_hwdep_release;
+	hw->ops.dsp_status = mixart_hwdep_dsp_status;
+	hw->ops.dsp_load = mixart_hwdep_dsp_load;
+	hw->exclusive = 1;
+	sprintf(hw->name,  SND_MIXART_HWDEP_ID);
+	mgr->hwdep = hw;
+	mgr->hwdep->dsp_loaded = 0;
+	return 0;
+}
diff -Nru a/sound/pci/mixart/mixart_hwdep.h b/sound/pci/mixart/mixart_hwdep.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_hwdep.h	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,146 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * definitions and makros for basic card access
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_MIXART_HWDEP_H
+#define __SOUND_MIXART_HWDEP_H
+
+#include <sound/hwdep.h>
+
+#define readl_be(x) be32_to_cpu(__raw_readl(x))
+#define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr)
+
+#define readl_le(x) le32_to_cpu(__raw_readl(x))
+#define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr)
+
+#define MIXART_MEM(mgr,x)	((mgr)->mem[0].virt + (x))
+#define MIXART_REG(mgr,x)	((mgr)->mem[1].virt + (x))
+
+
+/* Daughter board Type */
+#define DAUGHTER_TYPE_MASK     0x0F 
+#define DAUGHTER_VER_MASK      0xF0 
+#define DAUGHTER_TYPEVER_MASK  (DAUGHTER_TYPE_MASK|DAUGHTER_VER_MASK)
+ 
+#define MIXART_DAUGHTER_TYPE_NONE     0x00 
+#define MIXART_DAUGHTER_TYPE_COBRANET 0x08 
+#define MIXART_DAUGHTER_TYPE_AES      0x0E
+
+
+
+#define MIXART_BA0_SIZE 	(16 * 1024 * 1024) /* 16M */
+#define MIXART_BA1_SIZE 	(4  * 1024)        /* 4k */
+
+/*
+ * -----------BAR 0 --------------------------------------------------------------------------------------------------------
+ */
+#define  MIXART_PSEUDOREG                          0x2000                    /* base address for pseudoregister */
+
+#define  MIXART_PSEUDOREG_BOARDNUMBER              MIXART_PSEUDOREG+0        /* board number */
+
+/* perfmeter (available when elf loaded)*/
+#define  MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET  MIXART_PSEUDOREG+0x70     /* streaming load */
+#define  MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET  MIXART_PSEUDOREG+0x78     /* system load (reference)*/
+#define  MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET  MIXART_PSEUDOREG+0x7C     /* mailbox load */
+#define  MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET  MIXART_PSEUDOREG+0x74     /* interrupt handling  load */
+
+/* motherboard xilinx loader info */
+#define  MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET    MIXART_PSEUDOREG+0x9C     /* 0x00600000 */ 
+#define  MIXART_PSEUDOREG_MXLX_SIZE_OFFSET         MIXART_PSEUDOREG+0xA0     /* xilinx size in bytes */ 
+#define  MIXART_PSEUDOREG_MXLX_STATUS_OFFSET       MIXART_PSEUDOREG+0xA4     /* status = EMBEBBED_STAT_XXX */ 
+
+/* elf loader info */
+#define  MIXART_PSEUDOREG_ELF_STATUS_OFFSET        MIXART_PSEUDOREG+0xB0     /* status = EMBEBBED_STAT_XXX */ 
+
+/* 
+*  after the elf code is loaded, and the flowtable info was passed to it,
+*  the driver polls on this address, until it shows 1 (presence) or 2 (absence)
+*  once it is non-zero, the daughter board type may be read
+*/
+#define  MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET     MIXART_PSEUDOREG+0x990   
+
+/* Global info structure */
+#define  MIXART_PSEUDOREG_DBRD_TYPE_OFFSET         MIXART_PSEUDOREG+0x994    /* Type and version of daughterboard  */
+
+
+/* daughterboard xilinx loader info */
+#define  MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET    MIXART_PSEUDOREG+0x998    /* get the address here where to write the file */ 
+#define  MIXART_PSEUDOREG_DXLX_SIZE_OFFSET         MIXART_PSEUDOREG+0x99C    /* xilinx size in bytes */ 
+#define  MIXART_PSEUDOREG_DXLX_STATUS_OFFSET       MIXART_PSEUDOREG+0x9A0    /* status = EMBEBBED_STAT_XXX */ 
+
+/*  */
+#define  MIXART_FLOWTABLE_PTR                      0x3000                    /* pointer to flow table */
+
+/* mailbox addresses  */
+
+/* message DRV -> EMB */
+#define MSG_INBOUND_POST_HEAD       0x010008	/* DRV posts MF + increment4 */
+#define	MSG_INBOUND_POST_TAIL       0x01000C	/* EMB gets MF + increment4 */
+/* message EMB -> DRV */
+#define	MSG_OUTBOUND_POST_TAIL      0x01001C	/* DRV gets MF + increment4 */
+#define	MSG_OUTBOUND_POST_HEAD      0x010018	/* EMB posts MF + increment4 */
+/* Get Free Frames */
+#define MSG_INBOUND_FREE_TAIL       0x010004	/* DRV gets MFA + increment4 */
+#define MSG_OUTBOUND_FREE_TAIL      0x010014	/* EMB gets MFA + increment4 */
+/* Put Free Frames */
+#define MSG_OUTBOUND_FREE_HEAD      0x010010	/* DRV puts MFA + increment4 */
+#define MSG_INBOUND_FREE_HEAD       0x010000    /* EMB puts MFA + increment4 */
+
+/* firmware addresses of the message fifos */
+#define MSG_BOUND_STACK_SIZE        0x004000    /* size of each following stack */
+/* posted messages */
+#define MSG_OUTBOUND_POST_STACK     0x108000    /* stack of messages to the DRV */
+#define MSG_INBOUND_POST_STACK      0x104000    /* stack of messages to the EMB */
+/* available empty messages */
+#define MSG_OUTBOUND_FREE_STACK     0x10C000    /* stack of free enveloped for EMB */
+#define MSG_INBOUND_FREE_STACK      0x100000    /* stack of free enveloped for DRV */
+
+
+/* defines for mailbox message frames */
+#define MSG_FRAME_OFFSET            0x64
+#define MSG_FRAME_SIZE              0x6400
+#define MSG_FRAME_NUMBER            32
+#define MSG_FROM_AGENT_ITMF_OFFSET  (MSG_FRAME_OFFSET + (MSG_FRAME_SIZE * MSG_FRAME_NUMBER))
+#define MSG_TO_AGENT_ITMF_OFFSET    (MSG_FROM_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
+#define MSG_HOST_RSC_PROTECTION     (MSG_TO_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
+#define MSG_AGENT_RSC_PROTECTION    (MSG_HOST_RSC_PROTECTION + 4)
+
+
+/*
+ * -----------BAR 1 --------------------------------------------------------------------------------------------------------
+ */
+
+/* interrupt addresses and constants */
+#define MIXART_PCI_OMIMR_OFFSET                 0x34    /* outbound message interrupt mask register */
+#define MIXART_PCI_OMISR_OFFSET                 0x30    /* outbound message interrupt status register */
+#define MIXART_PCI_ODBR_OFFSET                  0x60    /* outbound doorbell register */
+
+#define MIXART_BA1_BRUTAL_RESET_OFFSET          0x68    /* write 1 in LSBit to reset board */
+
+#define MIXART_HOST_ALL_INTERRUPT_MASKED        0x02B   /* 0000 0010 1011 */
+#define MIXART_ALLOW_OUTBOUND_DOORBELL          0x023   /* 0000 0010 0011 */
+#define MIXART_OIDI                             0x008   /* 0000 0000 1000 */
+
+
+/* exported */
+int snd_mixart_hwdep_new(mixart_mgr_t *mgr);
+
+#endif /* __SOUND_MIXART_HWDEP_H */
diff -Nru a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_mixer.c	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,1137 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * mixer callbacks
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <sound/core.h>
+#include "mixart.h"
+#include "mixart_core.h"
+#include "mixart_hwdep.h"
+#include <sound/control.h>
+#include "mixart_mixer.h"
+
+#define chip_t mixart_t
+
+static u32 mixart_analog_level[256] = {
+	0xc2c00000,		/* [000] -96.0 dB */
+	0xc2bf0000,		/* [001] -95.5 dB */
+	0xc2be0000,		/* [002] -95.0 dB */
+	0xc2bd0000,		/* [003] -94.5 dB */
+	0xc2bc0000,		/* [004] -94.0 dB */
+	0xc2bb0000,		/* [005] -93.5 dB */
+	0xc2ba0000,		/* [006] -93.0 dB */
+	0xc2b90000,		/* [007] -92.5 dB */
+	0xc2b80000,		/* [008] -92.0 dB */
+	0xc2b70000,		/* [009] -91.5 dB */
+	0xc2b60000,		/* [010] -91.0 dB */
+	0xc2b50000,		/* [011] -90.5 dB */
+	0xc2b40000,		/* [012] -90.0 dB */
+	0xc2b30000,		/* [013] -89.5 dB */
+	0xc2b20000,		/* [014] -89.0 dB */
+	0xc2b10000,		/* [015] -88.5 dB */
+	0xc2b00000,		/* [016] -88.0 dB */
+	0xc2af0000,		/* [017] -87.5 dB */
+	0xc2ae0000,		/* [018] -87.0 dB */
+	0xc2ad0000,		/* [019] -86.5 dB */
+	0xc2ac0000,		/* [020] -86.0 dB */
+	0xc2ab0000,		/* [021] -85.5 dB */
+	0xc2aa0000,		/* [022] -85.0 dB */
+	0xc2a90000,		/* [023] -84.5 dB */
+	0xc2a80000,		/* [024] -84.0 dB */
+	0xc2a70000,		/* [025] -83.5 dB */
+	0xc2a60000,		/* [026] -83.0 dB */
+	0xc2a50000,		/* [027] -82.5 dB */
+	0xc2a40000,		/* [028] -82.0 dB */
+	0xc2a30000,		/* [029] -81.5 dB */
+	0xc2a20000,		/* [030] -81.0 dB */
+	0xc2a10000,		/* [031] -80.5 dB */
+	0xc2a00000,		/* [032] -80.0 dB */
+	0xc29f0000,		/* [033] -79.5 dB */
+	0xc29e0000,		/* [034] -79.0 dB */
+	0xc29d0000,		/* [035] -78.5 dB */
+	0xc29c0000,		/* [036] -78.0 dB */
+	0xc29b0000,		/* [037] -77.5 dB */
+	0xc29a0000,		/* [038] -77.0 dB */
+	0xc2990000,		/* [039] -76.5 dB */
+	0xc2980000,		/* [040] -76.0 dB */
+	0xc2970000,		/* [041] -75.5 dB */
+	0xc2960000,		/* [042] -75.0 dB */
+	0xc2950000,		/* [043] -74.5 dB */
+	0xc2940000,		/* [044] -74.0 dB */
+	0xc2930000,		/* [045] -73.5 dB */
+	0xc2920000,		/* [046] -73.0 dB */
+	0xc2910000,		/* [047] -72.5 dB */
+	0xc2900000,		/* [048] -72.0 dB */
+	0xc28f0000,		/* [049] -71.5 dB */
+	0xc28e0000,		/* [050] -71.0 dB */
+	0xc28d0000,		/* [051] -70.5 dB */
+	0xc28c0000,		/* [052] -70.0 dB */
+	0xc28b0000,		/* [053] -69.5 dB */
+	0xc28a0000,		/* [054] -69.0 dB */
+	0xc2890000,		/* [055] -68.5 dB */
+	0xc2880000,		/* [056] -68.0 dB */
+	0xc2870000,		/* [057] -67.5 dB */
+	0xc2860000,		/* [058] -67.0 dB */
+	0xc2850000,		/* [059] -66.5 dB */
+	0xc2840000,		/* [060] -66.0 dB */
+	0xc2830000,		/* [061] -65.5 dB */
+	0xc2820000,		/* [062] -65.0 dB */
+	0xc2810000,		/* [063] -64.5 dB */
+	0xc2800000,		/* [064] -64.0 dB */
+	0xc27e0000,		/* [065] -63.5 dB */
+	0xc27c0000,		/* [066] -63.0 dB */
+	0xc27a0000,		/* [067] -62.5 dB */
+	0xc2780000,		/* [068] -62.0 dB */
+	0xc2760000,		/* [069] -61.5 dB */
+	0xc2740000,		/* [070] -61.0 dB */
+	0xc2720000,		/* [071] -60.5 dB */
+	0xc2700000,		/* [072] -60.0 dB */
+	0xc26e0000,		/* [073] -59.5 dB */
+	0xc26c0000,		/* [074] -59.0 dB */
+	0xc26a0000,		/* [075] -58.5 dB */
+	0xc2680000,		/* [076] -58.0 dB */
+	0xc2660000,		/* [077] -57.5 dB */
+	0xc2640000,		/* [078] -57.0 dB */
+	0xc2620000,		/* [079] -56.5 dB */
+	0xc2600000,		/* [080] -56.0 dB */
+	0xc25e0000,		/* [081] -55.5 dB */
+	0xc25c0000,		/* [082] -55.0 dB */
+	0xc25a0000,		/* [083] -54.5 dB */
+	0xc2580000,		/* [084] -54.0 dB */
+	0xc2560000,		/* [085] -53.5 dB */
+	0xc2540000,		/* [086] -53.0 dB */
+	0xc2520000,		/* [087] -52.5 dB */
+	0xc2500000,		/* [088] -52.0 dB */
+	0xc24e0000,		/* [089] -51.5 dB */
+	0xc24c0000,		/* [090] -51.0 dB */
+	0xc24a0000,		/* [091] -50.5 dB */
+	0xc2480000,		/* [092] -50.0 dB */
+	0xc2460000,		/* [093] -49.5 dB */
+	0xc2440000,		/* [094] -49.0 dB */
+	0xc2420000,		/* [095] -48.5 dB */
+	0xc2400000,		/* [096] -48.0 dB */
+	0xc23e0000,		/* [097] -47.5 dB */
+	0xc23c0000,		/* [098] -47.0 dB */
+	0xc23a0000,		/* [099] -46.5 dB */
+	0xc2380000,		/* [100] -46.0 dB */
+	0xc2360000,		/* [101] -45.5 dB */
+	0xc2340000,		/* [102] -45.0 dB */
+	0xc2320000,		/* [103] -44.5 dB */
+	0xc2300000,		/* [104] -44.0 dB */
+	0xc22e0000,		/* [105] -43.5 dB */
+	0xc22c0000,		/* [106] -43.0 dB */
+	0xc22a0000,		/* [107] -42.5 dB */
+	0xc2280000,		/* [108] -42.0 dB */
+	0xc2260000,		/* [109] -41.5 dB */
+	0xc2240000,		/* [110] -41.0 dB */
+	0xc2220000,		/* [111] -40.5 dB */
+	0xc2200000,		/* [112] -40.0 dB */
+	0xc21e0000,		/* [113] -39.5 dB */
+	0xc21c0000,		/* [114] -39.0 dB */
+	0xc21a0000,		/* [115] -38.5 dB */
+	0xc2180000,		/* [116] -38.0 dB */
+	0xc2160000,		/* [117] -37.5 dB */
+	0xc2140000,		/* [118] -37.0 dB */
+	0xc2120000,		/* [119] -36.5 dB */
+	0xc2100000,		/* [120] -36.0 dB */
+	0xc20e0000,		/* [121] -35.5 dB */
+	0xc20c0000,		/* [122] -35.0 dB */
+	0xc20a0000,		/* [123] -34.5 dB */
+	0xc2080000,		/* [124] -34.0 dB */
+	0xc2060000,		/* [125] -33.5 dB */
+	0xc2040000,		/* [126] -33.0 dB */
+	0xc2020000,		/* [127] -32.5 dB */
+	0xc2000000,		/* [128] -32.0 dB */
+	0xc1fc0000,		/* [129] -31.5 dB */
+	0xc1f80000,		/* [130] -31.0 dB */
+	0xc1f40000,		/* [131] -30.5 dB */
+	0xc1f00000,		/* [132] -30.0 dB */
+	0xc1ec0000,		/* [133] -29.5 dB */
+	0xc1e80000,		/* [134] -29.0 dB */
+	0xc1e40000,		/* [135] -28.5 dB */
+	0xc1e00000,		/* [136] -28.0 dB */
+	0xc1dc0000,		/* [137] -27.5 dB */
+	0xc1d80000,		/* [138] -27.0 dB */
+	0xc1d40000,		/* [139] -26.5 dB */
+	0xc1d00000,		/* [140] -26.0 dB */
+	0xc1cc0000,		/* [141] -25.5 dB */
+	0xc1c80000,		/* [142] -25.0 dB */
+	0xc1c40000,		/* [143] -24.5 dB */
+	0xc1c00000,		/* [144] -24.0 dB */
+	0xc1bc0000,		/* [145] -23.5 dB */
+	0xc1b80000,		/* [146] -23.0 dB */
+	0xc1b40000,		/* [147] -22.5 dB */
+	0xc1b00000,		/* [148] -22.0 dB */
+	0xc1ac0000,		/* [149] -21.5 dB */
+	0xc1a80000,		/* [150] -21.0 dB */
+	0xc1a40000,		/* [151] -20.5 dB */
+	0xc1a00000,		/* [152] -20.0 dB */
+	0xc19c0000,		/* [153] -19.5 dB */
+	0xc1980000,		/* [154] -19.0 dB */
+	0xc1940000,		/* [155] -18.5 dB */
+	0xc1900000,		/* [156] -18.0 dB */
+	0xc18c0000,		/* [157] -17.5 dB */
+	0xc1880000,		/* [158] -17.0 dB */
+	0xc1840000,		/* [159] -16.5 dB */
+	0xc1800000,		/* [160] -16.0 dB */
+	0xc1780000,		/* [161] -15.5 dB */
+	0xc1700000,		/* [162] -15.0 dB */
+	0xc1680000,		/* [163] -14.5 dB */
+	0xc1600000,		/* [164] -14.0 dB */
+	0xc1580000,		/* [165] -13.5 dB */
+	0xc1500000,		/* [166] -13.0 dB */
+	0xc1480000,		/* [167] -12.5 dB */
+	0xc1400000,		/* [168] -12.0 dB */
+	0xc1380000,		/* [169] -11.5 dB */
+	0xc1300000,		/* [170] -11.0 dB */
+	0xc1280000,		/* [171] -10.5 dB */
+	0xc1200000,		/* [172] -10.0 dB */
+	0xc1180000,		/* [173] -9.5 dB */
+	0xc1100000,		/* [174] -9.0 dB */
+	0xc1080000,		/* [175] -8.5 dB */
+	0xc1000000,		/* [176] -8.0 dB */
+	0xc0f00000,		/* [177] -7.5 dB */
+	0xc0e00000,		/* [178] -7.0 dB */
+	0xc0d00000,		/* [179] -6.5 dB */
+	0xc0c00000,		/* [180] -6.0 dB */
+	0xc0b00000,		/* [181] -5.5 dB */
+	0xc0a00000,		/* [182] -5.0 dB */
+	0xc0900000,		/* [183] -4.5 dB */
+	0xc0800000,		/* [184] -4.0 dB */
+	0xc0600000,		/* [185] -3.5 dB */
+	0xc0400000,		/* [186] -3.0 dB */
+	0xc0200000,		/* [187] -2.5 dB */
+	0xc0000000,		/* [188] -2.0 dB */
+	0xbfc00000,		/* [189] -1.5 dB */
+	0xbf800000,		/* [190] -1.0 dB */
+	0xbf000000,		/* [191] -0.5 dB */
+	0x00000000,		/* [192] 0.0 dB */
+	0x3f000000,		/* [193] 0.5 dB */
+	0x3f800000,		/* [194] 1.0 dB */
+	0x3fc00000,		/* [195] 1.5 dB */
+	0x40000000,		/* [196] 2.0 dB */
+	0x40200000,		/* [197] 2.5 dB */
+	0x40400000,		/* [198] 3.0 dB */
+	0x40600000,		/* [199] 3.5 dB */
+	0x40800000,		/* [200] 4.0 dB */
+	0x40900000,		/* [201] 4.5 dB */
+	0x40a00000,		/* [202] 5.0 dB */
+	0x40b00000,		/* [203] 5.5 dB */
+	0x40c00000,		/* [204] 6.0 dB */
+	0x40d00000,		/* [205] 6.5 dB */
+	0x40e00000,		/* [206] 7.0 dB */
+	0x40f00000,		/* [207] 7.5 dB */
+	0x41000000,		/* [208] 8.0 dB */
+	0x41080000,		/* [209] 8.5 dB */
+	0x41100000,		/* [210] 9.0 dB */
+	0x41180000,		/* [211] 9.5 dB */
+	0x41200000,		/* [212] 10.0 dB */
+	0x41280000,		/* [213] 10.5 dB */
+	0x41300000,		/* [214] 11.0 dB */
+	0x41380000,		/* [215] 11.5 dB */
+	0x41400000,		/* [216] 12.0 dB */
+	0x41480000,		/* [217] 12.5 dB */
+	0x41500000,		/* [218] 13.0 dB */
+	0x41580000,		/* [219] 13.5 dB */
+	0x41600000,		/* [220] 14.0 dB */
+	0x41680000,		/* [221] 14.5 dB */
+	0x41700000,		/* [222] 15.0 dB */
+	0x41780000,		/* [223] 15.5 dB */
+	0x41800000,		/* [224] 16.0 dB */
+	0x41840000,		/* [225] 16.5 dB */
+	0x41880000,		/* [226] 17.0 dB */
+	0x418c0000,		/* [227] 17.5 dB */
+	0x41900000,		/* [228] 18.0 dB */
+	0x41940000,		/* [229] 18.5 dB */
+	0x41980000,		/* [230] 19.0 dB */
+	0x419c0000,		/* [231] 19.5 dB */
+	0x41a00000,		/* [232] 20.0 dB */
+	0x41a40000,		/* [233] 20.5 dB */
+	0x41a80000,		/* [234] 21.0 dB */
+	0x41ac0000,		/* [235] 21.5 dB */
+	0x41b00000,		/* [236] 22.0 dB */
+	0x41b40000,		/* [237] 22.5 dB */
+	0x41b80000,		/* [238] 23.0 dB */
+	0x41bc0000,		/* [239] 23.5 dB */
+	0x41c00000,		/* [240] 24.0 dB */
+	0x41c40000,		/* [241] 24.5 dB */
+	0x41c80000,		/* [242] 25.0 dB */
+	0x41cc0000,		/* [243] 25.5 dB */
+	0x41d00000,		/* [244] 26.0 dB */
+	0x41d40000,		/* [245] 26.5 dB */
+	0x41d80000,		/* [246] 27.0 dB */
+	0x41dc0000,		/* [247] 27.5 dB */
+	0x41e00000,		/* [248] 28.0 dB */
+	0x41e40000,		/* [249] 28.5 dB */
+	0x41e80000,		/* [250] 29.0 dB */
+	0x41ec0000,		/* [251] 29.5 dB */
+	0x41f00000,		/* [252] 30.0 dB */
+	0x41f40000,		/* [253] 30.5 dB */
+	0x41f80000,		/* [254] 31.0 dB */
+	0x41fc0000,		/* [255] 31.5 dB */
+};
+
+#define MIXART_ANALOG_CAPTURE_LEVEL_MIN   0      /* -96.0 dB + 8.0 dB = -88.0 dB */
+#define MIXART_ANALOG_CAPTURE_LEVEL_MAX   255    /*  31.5 dB + 8.0 dB =  39.5 dB */
+#define MIXART_ANALOG_CAPTURE_ZERO_LEVEL  176    /*  -8.0 dB + 8.0 dB =  0.0 dB */
+
+#define MIXART_ANALOG_PLAYBACK_LEVEL_MIN  0      /* -96.0 dB + 1.5 dB = -94.5 dB (possible is down to (-114.0+1.5)dB) */
+#define MIXART_ANALOG_PLAYBACK_LEVEL_MAX  192    /*   0.0 dB + 1.5 dB =  1.5 dB */
+#define MIXART_ANALOG_PLAYBACK_ZERO_LEVEL 189    /*  -1.5 dB + 1.5 dB =  0.0 dB */
+
+static int mixart_update_analog_audio_level(mixart_t* chip, int is_capture)
+{
+	int i, err;
+	mixart_msg_t request;
+	mixart_io_level_t io_level;
+	mixart_return_uid_t resp;
+
+	memset(&io_level, 0, sizeof(io_level));
+	io_level.channel = -1; /* left and right */
+
+	for(i=0; i<2; i++) {
+		if(is_capture) {
+			io_level.level[i].analog_level = mixart_analog_level[chip->analog_capture_volume[i]];
+		} else {
+			if(chip->analog_playback_active[i])
+				io_level.level[i].analog_level = mixart_analog_level[chip->analog_playback_volume[i]];
+			else
+				io_level.level[i].analog_level = mixart_analog_level[MIXART_ANALOG_PLAYBACK_LEVEL_MIN];
+		}
+	}
+
+	if(is_capture)	request.uid = chip->uid_in_analog_physio;
+	else		request.uid = chip->uid_out_analog_physio;
+	request.message_id = MSG_PHYSICALIO_SET_LEVEL;
+	request.data = &io_level;
+	request.size = sizeof(io_level);
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
+	if((err<0) || (resp.error_code)) {
+		snd_printk(KERN_DEBUG "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n", chip->chip_idx, is_capture, resp.error_code);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * analog level control
+ */
+static int mixart_analog_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	if(kcontrol->private_value == 0) {	/* playback */
+		uinfo->value.integer.min = MIXART_ANALOG_PLAYBACK_LEVEL_MIN;  /* -96 dB */
+		uinfo->value.integer.max = MIXART_ANALOG_PLAYBACK_LEVEL_MAX;  /* 0 dB */
+	} else {				/* capture */
+		uinfo->value.integer.min = MIXART_ANALOG_CAPTURE_LEVEL_MIN;   /* -96 dB */
+		uinfo->value.integer.max = MIXART_ANALOG_CAPTURE_LEVEL_MAX;   /* 31.5 dB */
+	}
+	return 0;
+}
+
+static int mixart_analog_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	down(&chip->mgr->mixer_mutex);
+	if(kcontrol->private_value == 0) {	/* playback */
+		ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
+		ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
+	} else {				/* capture */
+		ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
+		ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
+	}
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_analog_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int is_capture, i;
+
+	down(&chip->mgr->mixer_mutex);
+	is_capture = (kcontrol->private_value != 0);
+	for(i=0; i<2; i++) {
+		int  new_volume = ucontrol->value.integer.value[i];
+		int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i];
+		if(*stored_volume != new_volume) {
+			*stored_volume = new_volume;
+			changed = 1;
+		}
+	}
+	if(changed)	mixart_update_analog_audio_level(chip, is_capture);
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t mixart_control_analog_level = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	/* name will be filled later */
+	.info =		mixart_analog_vol_info,
+	.get =		mixart_analog_vol_get,
+	.put =		mixart_analog_vol_put,
+};
+
+/* shared */
+static int mixart_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int mixart_audio_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+
+	down(&chip->mgr->mixer_mutex);
+	ucontrol->value.integer.value[0] = chip->analog_playback_active[0];
+	ucontrol->value.integer.value[1] = chip->analog_playback_active[1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_audio_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int i, changed = 0;
+	down(&chip->mgr->mixer_mutex);
+	for(i=0; i<2; i++) {
+		if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) {
+			chip->analog_playback_active[i] = ucontrol->value.integer.value[i];
+			changed = 1;
+		}
+	}
+	if(changed)	mixart_update_analog_audio_level(chip, 0); /* update playback levels */
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t mixart_control_output_switch = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Master Playback Switch",
+	.info =         mixart_sw_info,		/* shared */
+	.get =          mixart_audio_sw_get,
+	.put =          mixart_audio_sw_put
+};
+
+static u32 mixart_digital_level[256] = {
+	0x00000000,		/* [000] = 0.00e+000 = mute if <= -109.5dB */
+	0x366e1c7a,		/* [001] = 3.55e-006 = pow(10.0, 0.05 * -109.0dB) */
+	0x367c3860,		/* [002] = 3.76e-006 = pow(10.0, 0.05 * -108.5dB) */
+	0x36859525,		/* [003] = 3.98e-006 = pow(10.0, 0.05 * -108.0dB) */
+	0x368d7f74,		/* [004] = 4.22e-006 = pow(10.0, 0.05 * -107.5dB) */
+	0x3695e1d4,		/* [005] = 4.47e-006 = pow(10.0, 0.05 * -107.0dB) */
+	0x369ec362,		/* [006] = 4.73e-006 = pow(10.0, 0.05 * -106.5dB) */
+	0x36a82ba8,		/* [007] = 5.01e-006 = pow(10.0, 0.05 * -106.0dB) */
+	0x36b222a0,		/* [008] = 5.31e-006 = pow(10.0, 0.05 * -105.5dB) */
+	0x36bcb0c1,		/* [009] = 5.62e-006 = pow(10.0, 0.05 * -105.0dB) */
+	0x36c7defd,		/* [010] = 5.96e-006 = pow(10.0, 0.05 * -104.5dB) */
+	0x36d3b6d3,		/* [011] = 6.31e-006 = pow(10.0, 0.05 * -104.0dB) */
+	0x36e0424e,		/* [012] = 6.68e-006 = pow(10.0, 0.05 * -103.5dB) */
+	0x36ed8c14,		/* [013] = 7.08e-006 = pow(10.0, 0.05 * -103.0dB) */
+	0x36fb9f6c,		/* [014] = 7.50e-006 = pow(10.0, 0.05 * -102.5dB) */
+	0x37054423,		/* [015] = 7.94e-006 = pow(10.0, 0.05 * -102.0dB) */
+	0x370d29a5,		/* [016] = 8.41e-006 = pow(10.0, 0.05 * -101.5dB) */
+	0x371586f0,		/* [017] = 8.91e-006 = pow(10.0, 0.05 * -101.0dB) */
+	0x371e631b,		/* [018] = 9.44e-006 = pow(10.0, 0.05 * -100.5dB) */
+	0x3727c5ac,		/* [019] = 1.00e-005 = pow(10.0, 0.05 * -100.0dB) */
+	0x3731b69a,		/* [020] = 1.06e-005 = pow(10.0, 0.05 * -99.5dB) */
+	0x373c3e53,		/* [021] = 1.12e-005 = pow(10.0, 0.05 * -99.0dB) */
+	0x374765c8,		/* [022] = 1.19e-005 = pow(10.0, 0.05 * -98.5dB) */
+	0x3753366f,		/* [023] = 1.26e-005 = pow(10.0, 0.05 * -98.0dB) */
+	0x375fba4f,		/* [024] = 1.33e-005 = pow(10.0, 0.05 * -97.5dB) */
+	0x376cfc07,		/* [025] = 1.41e-005 = pow(10.0, 0.05 * -97.0dB) */
+	0x377b06d5,		/* [026] = 1.50e-005 = pow(10.0, 0.05 * -96.5dB) */
+	0x3784f352,		/* [027] = 1.58e-005 = pow(10.0, 0.05 * -96.0dB) */
+	0x378cd40b,		/* [028] = 1.68e-005 = pow(10.0, 0.05 * -95.5dB) */
+	0x37952c42,		/* [029] = 1.78e-005 = pow(10.0, 0.05 * -95.0dB) */
+	0x379e030e,		/* [030] = 1.88e-005 = pow(10.0, 0.05 * -94.5dB) */
+	0x37a75fef,		/* [031] = 2.00e-005 = pow(10.0, 0.05 * -94.0dB) */
+	0x37b14ad5,		/* [032] = 2.11e-005 = pow(10.0, 0.05 * -93.5dB) */
+	0x37bbcc2c,		/* [033] = 2.24e-005 = pow(10.0, 0.05 * -93.0dB) */
+	0x37c6ecdd,		/* [034] = 2.37e-005 = pow(10.0, 0.05 * -92.5dB) */
+	0x37d2b65a,		/* [035] = 2.51e-005 = pow(10.0, 0.05 * -92.0dB) */
+	0x37df32a3,		/* [036] = 2.66e-005 = pow(10.0, 0.05 * -91.5dB) */
+	0x37ec6c50,		/* [037] = 2.82e-005 = pow(10.0, 0.05 * -91.0dB) */
+	0x37fa6e9b,		/* [038] = 2.99e-005 = pow(10.0, 0.05 * -90.5dB) */
+	0x3804a2b3,		/* [039] = 3.16e-005 = pow(10.0, 0.05 * -90.0dB) */
+	0x380c7ea4,		/* [040] = 3.35e-005 = pow(10.0, 0.05 * -89.5dB) */
+	0x3814d1cc,		/* [041] = 3.55e-005 = pow(10.0, 0.05 * -89.0dB) */
+	0x381da33c,		/* [042] = 3.76e-005 = pow(10.0, 0.05 * -88.5dB) */
+	0x3826fa6f,		/* [043] = 3.98e-005 = pow(10.0, 0.05 * -88.0dB) */
+	0x3830df51,		/* [044] = 4.22e-005 = pow(10.0, 0.05 * -87.5dB) */
+	0x383b5a49,		/* [045] = 4.47e-005 = pow(10.0, 0.05 * -87.0dB) */
+	0x3846743b,		/* [046] = 4.73e-005 = pow(10.0, 0.05 * -86.5dB) */
+	0x38523692,		/* [047] = 5.01e-005 = pow(10.0, 0.05 * -86.0dB) */
+	0x385eab48,		/* [048] = 5.31e-005 = pow(10.0, 0.05 * -85.5dB) */
+	0x386bdcf1,		/* [049] = 5.62e-005 = pow(10.0, 0.05 * -85.0dB) */
+	0x3879d6bc,		/* [050] = 5.96e-005 = pow(10.0, 0.05 * -84.5dB) */
+	0x38845244,		/* [051] = 6.31e-005 = pow(10.0, 0.05 * -84.0dB) */
+	0x388c2971,		/* [052] = 6.68e-005 = pow(10.0, 0.05 * -83.5dB) */
+	0x3894778d,		/* [053] = 7.08e-005 = pow(10.0, 0.05 * -83.0dB) */
+	0x389d43a4,		/* [054] = 7.50e-005 = pow(10.0, 0.05 * -82.5dB) */
+	0x38a6952c,		/* [055] = 7.94e-005 = pow(10.0, 0.05 * -82.0dB) */
+	0x38b0740f,		/* [056] = 8.41e-005 = pow(10.0, 0.05 * -81.5dB) */
+	0x38bae8ac,		/* [057] = 8.91e-005 = pow(10.0, 0.05 * -81.0dB) */
+	0x38c5fbe2,		/* [058] = 9.44e-005 = pow(10.0, 0.05 * -80.5dB) */
+	0x38d1b717,		/* [059] = 1.00e-004 = pow(10.0, 0.05 * -80.0dB) */
+	0x38de2440,		/* [060] = 1.06e-004 = pow(10.0, 0.05 * -79.5dB) */
+	0x38eb4de8,		/* [061] = 1.12e-004 = pow(10.0, 0.05 * -79.0dB) */
+	0x38f93f3a,		/* [062] = 1.19e-004 = pow(10.0, 0.05 * -78.5dB) */
+	0x39040206,		/* [063] = 1.26e-004 = pow(10.0, 0.05 * -78.0dB) */
+	0x390bd472,		/* [064] = 1.33e-004 = pow(10.0, 0.05 * -77.5dB) */
+	0x39141d84,		/* [065] = 1.41e-004 = pow(10.0, 0.05 * -77.0dB) */
+	0x391ce445,		/* [066] = 1.50e-004 = pow(10.0, 0.05 * -76.5dB) */
+	0x39263027,		/* [067] = 1.58e-004 = pow(10.0, 0.05 * -76.0dB) */
+	0x3930090d,		/* [068] = 1.68e-004 = pow(10.0, 0.05 * -75.5dB) */
+	0x393a7753,		/* [069] = 1.78e-004 = pow(10.0, 0.05 * -75.0dB) */
+	0x394583d2,		/* [070] = 1.88e-004 = pow(10.0, 0.05 * -74.5dB) */
+	0x395137ea,		/* [071] = 2.00e-004 = pow(10.0, 0.05 * -74.0dB) */
+	0x395d9d8a,		/* [072] = 2.11e-004 = pow(10.0, 0.05 * -73.5dB) */
+	0x396abf37,		/* [073] = 2.24e-004 = pow(10.0, 0.05 * -73.0dB) */
+	0x3978a814,		/* [074] = 2.37e-004 = pow(10.0, 0.05 * -72.5dB) */
+	0x3983b1f8,		/* [075] = 2.51e-004 = pow(10.0, 0.05 * -72.0dB) */
+	0x398b7fa6,		/* [076] = 2.66e-004 = pow(10.0, 0.05 * -71.5dB) */
+	0x3993c3b2,		/* [077] = 2.82e-004 = pow(10.0, 0.05 * -71.0dB) */
+	0x399c8521,		/* [078] = 2.99e-004 = pow(10.0, 0.05 * -70.5dB) */
+	0x39a5cb5f,		/* [079] = 3.16e-004 = pow(10.0, 0.05 * -70.0dB) */
+	0x39af9e4d,		/* [080] = 3.35e-004 = pow(10.0, 0.05 * -69.5dB) */
+	0x39ba063f,		/* [081] = 3.55e-004 = pow(10.0, 0.05 * -69.0dB) */
+	0x39c50c0b,		/* [082] = 3.76e-004 = pow(10.0, 0.05 * -68.5dB) */
+	0x39d0b90a,		/* [083] = 3.98e-004 = pow(10.0, 0.05 * -68.0dB) */
+	0x39dd1726,		/* [084] = 4.22e-004 = pow(10.0, 0.05 * -67.5dB) */
+	0x39ea30db,		/* [085] = 4.47e-004 = pow(10.0, 0.05 * -67.0dB) */
+	0x39f81149,		/* [086] = 4.73e-004 = pow(10.0, 0.05 * -66.5dB) */
+	0x3a03621b,		/* [087] = 5.01e-004 = pow(10.0, 0.05 * -66.0dB) */
+	0x3a0b2b0d,		/* [088] = 5.31e-004 = pow(10.0, 0.05 * -65.5dB) */
+	0x3a136a16,		/* [089] = 5.62e-004 = pow(10.0, 0.05 * -65.0dB) */
+	0x3a1c2636,		/* [090] = 5.96e-004 = pow(10.0, 0.05 * -64.5dB) */
+	0x3a2566d5,		/* [091] = 6.31e-004 = pow(10.0, 0.05 * -64.0dB) */
+	0x3a2f33cd,		/* [092] = 6.68e-004 = pow(10.0, 0.05 * -63.5dB) */
+	0x3a399570,		/* [093] = 7.08e-004 = pow(10.0, 0.05 * -63.0dB) */
+	0x3a44948c,		/* [094] = 7.50e-004 = pow(10.0, 0.05 * -62.5dB) */
+	0x3a503a77,		/* [095] = 7.94e-004 = pow(10.0, 0.05 * -62.0dB) */
+	0x3a5c9112,		/* [096] = 8.41e-004 = pow(10.0, 0.05 * -61.5dB) */
+	0x3a69a2d7,		/* [097] = 8.91e-004 = pow(10.0, 0.05 * -61.0dB) */
+	0x3a777ada,		/* [098] = 9.44e-004 = pow(10.0, 0.05 * -60.5dB) */
+	0x3a83126f,		/* [099] = 1.00e-003 = pow(10.0, 0.05 * -60.0dB) */
+	0x3a8ad6a8,		/* [100] = 1.06e-003 = pow(10.0, 0.05 * -59.5dB) */
+	0x3a9310b1,		/* [101] = 1.12e-003 = pow(10.0, 0.05 * -59.0dB) */
+	0x3a9bc784,		/* [102] = 1.19e-003 = pow(10.0, 0.05 * -58.5dB) */
+	0x3aa50287,		/* [103] = 1.26e-003 = pow(10.0, 0.05 * -58.0dB) */
+	0x3aaec98e,		/* [104] = 1.33e-003 = pow(10.0, 0.05 * -57.5dB) */
+	0x3ab924e5,		/* [105] = 1.41e-003 = pow(10.0, 0.05 * -57.0dB) */
+	0x3ac41d56,		/* [106] = 1.50e-003 = pow(10.0, 0.05 * -56.5dB) */
+	0x3acfbc31,		/* [107] = 1.58e-003 = pow(10.0, 0.05 * -56.0dB) */
+	0x3adc0b51,		/* [108] = 1.68e-003 = pow(10.0, 0.05 * -55.5dB) */
+	0x3ae91528,		/* [109] = 1.78e-003 = pow(10.0, 0.05 * -55.0dB) */
+	0x3af6e4c6,		/* [110] = 1.88e-003 = pow(10.0, 0.05 * -54.5dB) */
+	0x3b02c2f2,		/* [111] = 2.00e-003 = pow(10.0, 0.05 * -54.0dB) */
+	0x3b0a8276,		/* [112] = 2.11e-003 = pow(10.0, 0.05 * -53.5dB) */
+	0x3b12b782,		/* [113] = 2.24e-003 = pow(10.0, 0.05 * -53.0dB) */
+	0x3b1b690d,		/* [114] = 2.37e-003 = pow(10.0, 0.05 * -52.5dB) */
+	0x3b249e76,		/* [115] = 2.51e-003 = pow(10.0, 0.05 * -52.0dB) */
+	0x3b2e5f8f,		/* [116] = 2.66e-003 = pow(10.0, 0.05 * -51.5dB) */
+	0x3b38b49f,		/* [117] = 2.82e-003 = pow(10.0, 0.05 * -51.0dB) */
+	0x3b43a669,		/* [118] = 2.99e-003 = pow(10.0, 0.05 * -50.5dB) */
+	0x3b4f3e37,		/* [119] = 3.16e-003 = pow(10.0, 0.05 * -50.0dB) */
+	0x3b5b85e0,		/* [120] = 3.35e-003 = pow(10.0, 0.05 * -49.5dB) */
+	0x3b6887cf,		/* [121] = 3.55e-003 = pow(10.0, 0.05 * -49.0dB) */
+	0x3b764f0e,		/* [122] = 3.76e-003 = pow(10.0, 0.05 * -48.5dB) */
+	0x3b8273a6,		/* [123] = 3.98e-003 = pow(10.0, 0.05 * -48.0dB) */
+	0x3b8a2e77,		/* [124] = 4.22e-003 = pow(10.0, 0.05 * -47.5dB) */
+	0x3b925e89,		/* [125] = 4.47e-003 = pow(10.0, 0.05 * -47.0dB) */
+	0x3b9b0ace,		/* [126] = 4.73e-003 = pow(10.0, 0.05 * -46.5dB) */
+	0x3ba43aa2,		/* [127] = 5.01e-003 = pow(10.0, 0.05 * -46.0dB) */
+	0x3badf5d1,		/* [128] = 5.31e-003 = pow(10.0, 0.05 * -45.5dB) */
+	0x3bb8449c,		/* [129] = 5.62e-003 = pow(10.0, 0.05 * -45.0dB) */
+	0x3bc32fc3,		/* [130] = 5.96e-003 = pow(10.0, 0.05 * -44.5dB) */
+	0x3bcec08a,		/* [131] = 6.31e-003 = pow(10.0, 0.05 * -44.0dB) */
+	0x3bdb00c0,		/* [132] = 6.68e-003 = pow(10.0, 0.05 * -43.5dB) */
+	0x3be7facc,		/* [133] = 7.08e-003 = pow(10.0, 0.05 * -43.0dB) */
+	0x3bf5b9b0,		/* [134] = 7.50e-003 = pow(10.0, 0.05 * -42.5dB) */
+	0x3c02248a,		/* [135] = 7.94e-003 = pow(10.0, 0.05 * -42.0dB) */
+	0x3c09daac,		/* [136] = 8.41e-003 = pow(10.0, 0.05 * -41.5dB) */
+	0x3c1205c6,		/* [137] = 8.91e-003 = pow(10.0, 0.05 * -41.0dB) */
+	0x3c1aacc8,		/* [138] = 9.44e-003 = pow(10.0, 0.05 * -40.5dB) */
+	0x3c23d70a,		/* [139] = 1.00e-002 = pow(10.0, 0.05 * -40.0dB) */
+	0x3c2d8c52,		/* [140] = 1.06e-002 = pow(10.0, 0.05 * -39.5dB) */
+	0x3c37d4dd,		/* [141] = 1.12e-002 = pow(10.0, 0.05 * -39.0dB) */
+	0x3c42b965,		/* [142] = 1.19e-002 = pow(10.0, 0.05 * -38.5dB) */
+	0x3c4e4329,		/* [143] = 1.26e-002 = pow(10.0, 0.05 * -38.0dB) */
+	0x3c5a7bf1,		/* [144] = 1.33e-002 = pow(10.0, 0.05 * -37.5dB) */
+	0x3c676e1e,		/* [145] = 1.41e-002 = pow(10.0, 0.05 * -37.0dB) */
+	0x3c7524ac,		/* [146] = 1.50e-002 = pow(10.0, 0.05 * -36.5dB) */
+	0x3c81d59f,		/* [147] = 1.58e-002 = pow(10.0, 0.05 * -36.0dB) */
+	0x3c898712,		/* [148] = 1.68e-002 = pow(10.0, 0.05 * -35.5dB) */
+	0x3c91ad39,		/* [149] = 1.78e-002 = pow(10.0, 0.05 * -35.0dB) */
+	0x3c9a4efc,		/* [150] = 1.88e-002 = pow(10.0, 0.05 * -34.5dB) */
+	0x3ca373af,		/* [151] = 2.00e-002 = pow(10.0, 0.05 * -34.0dB) */
+	0x3cad2314,		/* [152] = 2.11e-002 = pow(10.0, 0.05 * -33.5dB) */
+	0x3cb76563,		/* [153] = 2.24e-002 = pow(10.0, 0.05 * -33.0dB) */
+	0x3cc24350,		/* [154] = 2.37e-002 = pow(10.0, 0.05 * -32.5dB) */
+	0x3ccdc614,		/* [155] = 2.51e-002 = pow(10.0, 0.05 * -32.0dB) */
+	0x3cd9f773,		/* [156] = 2.66e-002 = pow(10.0, 0.05 * -31.5dB) */
+	0x3ce6e1c6,		/* [157] = 2.82e-002 = pow(10.0, 0.05 * -31.0dB) */
+	0x3cf49003,		/* [158] = 2.99e-002 = pow(10.0, 0.05 * -30.5dB) */
+	0x3d0186e2,		/* [159] = 3.16e-002 = pow(10.0, 0.05 * -30.0dB) */
+	0x3d0933ac,		/* [160] = 3.35e-002 = pow(10.0, 0.05 * -29.5dB) */
+	0x3d1154e1,		/* [161] = 3.55e-002 = pow(10.0, 0.05 * -29.0dB) */
+	0x3d19f169,		/* [162] = 3.76e-002 = pow(10.0, 0.05 * -28.5dB) */
+	0x3d231090,		/* [163] = 3.98e-002 = pow(10.0, 0.05 * -28.0dB) */
+	0x3d2cba15,		/* [164] = 4.22e-002 = pow(10.0, 0.05 * -27.5dB) */
+	0x3d36f62b,		/* [165] = 4.47e-002 = pow(10.0, 0.05 * -27.0dB) */
+	0x3d41cd81,		/* [166] = 4.73e-002 = pow(10.0, 0.05 * -26.5dB) */
+	0x3d4d494a,		/* [167] = 5.01e-002 = pow(10.0, 0.05 * -26.0dB) */
+	0x3d597345,		/* [168] = 5.31e-002 = pow(10.0, 0.05 * -25.5dB) */
+	0x3d6655c3,		/* [169] = 5.62e-002 = pow(10.0, 0.05 * -25.0dB) */
+	0x3d73fbb4,		/* [170] = 5.96e-002 = pow(10.0, 0.05 * -24.5dB) */
+	0x3d813856,		/* [171] = 6.31e-002 = pow(10.0, 0.05 * -24.0dB) */
+	0x3d88e078,		/* [172] = 6.68e-002 = pow(10.0, 0.05 * -23.5dB) */
+	0x3d90fcbf,		/* [173] = 7.08e-002 = pow(10.0, 0.05 * -23.0dB) */
+	0x3d99940e,		/* [174] = 7.50e-002 = pow(10.0, 0.05 * -22.5dB) */
+	0x3da2adad,		/* [175] = 7.94e-002 = pow(10.0, 0.05 * -22.0dB) */
+	0x3dac5156,		/* [176] = 8.41e-002 = pow(10.0, 0.05 * -21.5dB) */
+	0x3db68738,		/* [177] = 8.91e-002 = pow(10.0, 0.05 * -21.0dB) */
+	0x3dc157fb,		/* [178] = 9.44e-002 = pow(10.0, 0.05 * -20.5dB) */
+	0x3dcccccd,		/* [179] = 1.00e-001 = pow(10.0, 0.05 * -20.0dB) */
+	0x3dd8ef67,		/* [180] = 1.06e-001 = pow(10.0, 0.05 * -19.5dB) */
+	0x3de5ca15,		/* [181] = 1.12e-001 = pow(10.0, 0.05 * -19.0dB) */
+	0x3df367bf,		/* [182] = 1.19e-001 = pow(10.0, 0.05 * -18.5dB) */
+	0x3e00e9f9,		/* [183] = 1.26e-001 = pow(10.0, 0.05 * -18.0dB) */
+	0x3e088d77,		/* [184] = 1.33e-001 = pow(10.0, 0.05 * -17.5dB) */
+	0x3e10a4d3,		/* [185] = 1.41e-001 = pow(10.0, 0.05 * -17.0dB) */
+	0x3e1936ec,		/* [186] = 1.50e-001 = pow(10.0, 0.05 * -16.5dB) */
+	0x3e224b06,		/* [187] = 1.58e-001 = pow(10.0, 0.05 * -16.0dB) */
+	0x3e2be8d7,		/* [188] = 1.68e-001 = pow(10.0, 0.05 * -15.5dB) */
+	0x3e361887,		/* [189] = 1.78e-001 = pow(10.0, 0.05 * -15.0dB) */
+	0x3e40e2bb,		/* [190] = 1.88e-001 = pow(10.0, 0.05 * -14.5dB) */
+	0x3e4c509b,		/* [191] = 2.00e-001 = pow(10.0, 0.05 * -14.0dB) */
+	0x3e586bd9,		/* [192] = 2.11e-001 = pow(10.0, 0.05 * -13.5dB) */
+	0x3e653ebb,		/* [193] = 2.24e-001 = pow(10.0, 0.05 * -13.0dB) */
+	0x3e72d424,		/* [194] = 2.37e-001 = pow(10.0, 0.05 * -12.5dB) */
+	0x3e809bcc,		/* [195] = 2.51e-001 = pow(10.0, 0.05 * -12.0dB) */
+	0x3e883aa8,		/* [196] = 2.66e-001 = pow(10.0, 0.05 * -11.5dB) */
+	0x3e904d1c,		/* [197] = 2.82e-001 = pow(10.0, 0.05 * -11.0dB) */
+	0x3e98da02,		/* [198] = 2.99e-001 = pow(10.0, 0.05 * -10.5dB) */
+	0x3ea1e89b,		/* [199] = 3.16e-001 = pow(10.0, 0.05 * -10.0dB) */
+	0x3eab8097,		/* [200] = 3.35e-001 = pow(10.0, 0.05 * -9.5dB) */
+	0x3eb5aa1a,		/* [201] = 3.55e-001 = pow(10.0, 0.05 * -9.0dB) */
+	0x3ec06dc3,		/* [202] = 3.76e-001 = pow(10.0, 0.05 * -8.5dB) */
+	0x3ecbd4b4,		/* [203] = 3.98e-001 = pow(10.0, 0.05 * -8.0dB) */
+	0x3ed7e89b,		/* [204] = 4.22e-001 = pow(10.0, 0.05 * -7.5dB) */
+	0x3ee4b3b6,		/* [205] = 4.47e-001 = pow(10.0, 0.05 * -7.0dB) */
+	0x3ef240e2,		/* [206] = 4.73e-001 = pow(10.0, 0.05 * -6.5dB) */
+	0x3f004dce,		/* [207] = 5.01e-001 = pow(10.0, 0.05 * -6.0dB) */
+	0x3f07e80b,		/* [208] = 5.31e-001 = pow(10.0, 0.05 * -5.5dB) */
+	0x3f0ff59a,		/* [209] = 5.62e-001 = pow(10.0, 0.05 * -5.0dB) */
+	0x3f187d50,		/* [210] = 5.96e-001 = pow(10.0, 0.05 * -4.5dB) */
+	0x3f21866c,		/* [211] = 6.31e-001 = pow(10.0, 0.05 * -4.0dB) */
+	0x3f2b1896,		/* [212] = 6.68e-001 = pow(10.0, 0.05 * -3.5dB) */
+	0x3f353bef,		/* [213] = 7.08e-001 = pow(10.0, 0.05 * -3.0dB) */
+	0x3f3ff911,		/* [214] = 7.50e-001 = pow(10.0, 0.05 * -2.5dB) */
+	0x3f4b5918,		/* [215] = 7.94e-001 = pow(10.0, 0.05 * -2.0dB) */
+	0x3f5765ac,		/* [216] = 8.41e-001 = pow(10.0, 0.05 * -1.5dB) */
+	0x3f642905,		/* [217] = 8.91e-001 = pow(10.0, 0.05 * -1.0dB) */
+	0x3f71adf9,		/* [218] = 9.44e-001 = pow(10.0, 0.05 * -0.5dB) */
+	0x3f800000,		/* [219] = 1.00e+000 = pow(10.0, 0.05 * 0.0dB) */
+	0x3f8795a0,		/* [220] = 1.06e+000 = pow(10.0, 0.05 * 0.5dB) */
+	0x3f8f9e4d,		/* [221] = 1.12e+000 = pow(10.0, 0.05 * 1.0dB) */
+	0x3f9820d7,		/* [222] = 1.19e+000 = pow(10.0, 0.05 * 1.5dB) */
+	0x3fa12478,		/* [223] = 1.26e+000 = pow(10.0, 0.05 * 2.0dB) */
+	0x3faab0d5,		/* [224] = 1.33e+000 = pow(10.0, 0.05 * 2.5dB) */
+	0x3fb4ce08,		/* [225] = 1.41e+000 = pow(10.0, 0.05 * 3.0dB) */
+	0x3fbf84a6,		/* [226] = 1.50e+000 = pow(10.0, 0.05 * 3.5dB) */
+	0x3fcaddc8,		/* [227] = 1.58e+000 = pow(10.0, 0.05 * 4.0dB) */
+	0x3fd6e30d,		/* [228] = 1.68e+000 = pow(10.0, 0.05 * 4.5dB) */
+	0x3fe39ea9,		/* [229] = 1.78e+000 = pow(10.0, 0.05 * 5.0dB) */
+	0x3ff11b6a,		/* [230] = 1.88e+000 = pow(10.0, 0.05 * 5.5dB) */
+	0x3fff64c1,		/* [231] = 2.00e+000 = pow(10.0, 0.05 * 6.0dB) */
+	0x40074368,		/* [232] = 2.11e+000 = pow(10.0, 0.05 * 6.5dB) */
+	0x400f4735,		/* [233] = 2.24e+000 = pow(10.0, 0.05 * 7.0dB) */
+	0x4017c496,		/* [234] = 2.37e+000 = pow(10.0, 0.05 * 7.5dB) */
+	0x4020c2bf,		/* [235] = 2.51e+000 = pow(10.0, 0.05 * 8.0dB) */
+	0x402a4952,		/* [236] = 2.66e+000 = pow(10.0, 0.05 * 8.5dB) */
+	0x40346063,		/* [237] = 2.82e+000 = pow(10.0, 0.05 * 9.0dB) */
+	0x403f1082,		/* [238] = 2.99e+000 = pow(10.0, 0.05 * 9.5dB) */
+	0x404a62c2,		/* [239] = 3.16e+000 = pow(10.0, 0.05 * 10.0dB) */
+	0x405660bd,		/* [240] = 3.35e+000 = pow(10.0, 0.05 * 10.5dB) */
+	0x406314a0,		/* [241] = 3.55e+000 = pow(10.0, 0.05 * 11.0dB) */
+	0x40708933,		/* [242] = 3.76e+000 = pow(10.0, 0.05 * 11.5dB) */
+	0x407ec9e1,		/* [243] = 3.98e+000 = pow(10.0, 0.05 * 12.0dB) */
+	0x4086f161,		/* [244] = 4.22e+000 = pow(10.0, 0.05 * 12.5dB) */
+	0x408ef052,		/* [245] = 4.47e+000 = pow(10.0, 0.05 * 13.0dB) */
+	0x4097688d,		/* [246] = 4.73e+000 = pow(10.0, 0.05 * 13.5dB) */
+	0x40a06142,		/* [247] = 5.01e+000 = pow(10.0, 0.05 * 14.0dB) */
+	0x40a9e20e,		/* [248] = 5.31e+000 = pow(10.0, 0.05 * 14.5dB) */
+	0x40b3f300,		/* [249] = 5.62e+000 = pow(10.0, 0.05 * 15.0dB) */
+	0x40be9ca5,		/* [250] = 5.96e+000 = pow(10.0, 0.05 * 15.5dB) */
+	0x40c9e807,		/* [251] = 6.31e+000 = pow(10.0, 0.05 * 16.0dB) */
+	0x40d5debc,		/* [252] = 6.68e+000 = pow(10.0, 0.05 * 16.5dB) */
+	0x40e28aeb,		/* [253] = 7.08e+000 = pow(10.0, 0.05 * 17.0dB) */
+	0x40eff755,		/* [254] = 7.50e+000 = pow(10.0, 0.05 * 17.5dB) */
+	0x40fe2f5e,		/* [255] = 7.94e+000 = pow(10.0, 0.05 * 18.0dB) */
+};
+
+#define MIXART_DIGITAL_LEVEL_MIN   0      /* -109.5 dB */
+#define MIXART_DIGITAL_LEVEL_MAX   255    /*  18.0 dB */
+#define MIXART_DIGITAL_ZERO_LEVEL  219    /*  0.0 dB */
+
+
+int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx)
+{
+	int err, i;
+	int volume[2];
+	mixart_msg_t request;
+	mixart_set_out_stream_level_req_t set_level;
+	u32 status;
+	mixart_pipe_t *pipe;
+
+	memset(&set_level, 0, sizeof(set_level));
+	set_level.nb_of_stream = 1;
+	set_level.stream_level.desc.stream_idx = idx;
+
+	if(is_aes) {
+		pipe = &chip->pipe_out_dig;	/* AES playback */
+		idx += MIXART_PLAYBACK_STREAMS;
+	} else {
+		pipe = &chip->pipe_out_ana;	/* analog playback */
+	}
+
+	/* only when pipe exists ! */
+	if(pipe->status == PIPE_UNDEFINED)
+		return 0;
+
+	set_level.stream_level.desc.uid_pipe = pipe->group_uid;
+
+	for(i=0; i<2; i++) {
+		if(chip->digital_playback_active[idx][i])
+			volume[i] = chip->digital_playback_volume[idx][i];
+		else
+			volume[i] = MIXART_DIGITAL_LEVEL_MIN;
+	}
+
+	set_level.stream_level.out_level.valid_mask1 = MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO1 | MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO2;
+	set_level.stream_level.out_level.left_to_out1_level = mixart_digital_level[volume[0]];
+	set_level.stream_level.out_level.right_to_out2_level = mixart_digital_level[volume[1]];
+
+	request.message_id = MSG_STREAM_SET_OUT_STREAM_LEVEL;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &set_level;
+	request.size = sizeof(set_level);
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
+	if((err<0) || status) {
+		snd_printk(KERN_DEBUG "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int mixart_update_capture_stream_level(mixart_t* chip, int is_aes)
+{
+	int err, i, idx;
+	mixart_pipe_t* pipe;
+	mixart_msg_t request;
+	mixart_set_in_audio_level_req_t set_level;
+	u32 status;
+
+	if(is_aes) {
+		idx = 1;
+		pipe = &chip->pipe_in_dig;
+	} else {
+		idx = 0;
+		pipe = &chip->pipe_in_ana;
+	}
+
+	/* only when pipe exists ! */
+	if(pipe->status == PIPE_UNDEFINED)
+		return 0;
+
+	memset(&set_level, 0, sizeof(set_level));
+	set_level.audio_count = 2;
+	set_level.level[0].connector = pipe->uid_left_connector;
+	set_level.level[1].connector = pipe->uid_right_connector;
+
+	for(i=0; i<2; i++) {
+		set_level.level[i].valid_mask1 = MIXART_AUDIO_LEVEL_DIGITAL_MASK;
+		set_level.level[i].digital_level = mixart_digital_level[chip->digital_capture_volume[idx][i]];
+	}
+
+	request.message_id = MSG_STREAM_SET_IN_AUDIO_LEVEL;
+	request.uid = (mixart_uid_t){0,0};
+	request.data = &set_level;
+	request.size = sizeof(set_level);
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status);
+	if((err<0) || status) {
+		snd_printk(KERN_DEBUG "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n", chip->chip_idx, status);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+/* shared */
+static int mixart_digital_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = MIXART_DIGITAL_LEVEL_MIN;   /* -109.5 dB */
+	uinfo->value.integer.max = MIXART_DIGITAL_LEVEL_MAX;   /*   18.0 dB */
+	return 0;
+}
+
+#define MIXART_VOL_REC_MASK	1
+#define MIXART_VOL_AES_MASK	2
+
+static int mixart_pcm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+	int *stored_volume;
+	int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK;
+	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
+	down(&chip->mgr->mixer_mutex);
+	if(is_capture) {
+		if(is_aes)	stored_volume = chip->digital_capture_volume[1];	/* AES capture */
+		else		stored_volume = chip->digital_capture_volume[0];	/* analog capture */
+	} else {
+		snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+		if(is_aes)	stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */
+		else		stored_volume = chip->digital_playback_volume[idx];	/* analog playback */
+	}
+	ucontrol->value.integer.value[0] = stored_volume[0];
+	ucontrol->value.integer.value[1] = stored_volume[1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_pcm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+	int changed = 0;
+	int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK;
+	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
+	int* stored_volume;
+	int i;
+	down(&chip->mgr->mixer_mutex);
+	if(is_capture) {
+		if(is_aes)	stored_volume = chip->digital_capture_volume[1];	/* AES capture */
+		else		stored_volume = chip->digital_capture_volume[0];	/* analog capture */
+	} else {
+		snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+		if(is_aes)	stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */
+		else		stored_volume = chip->digital_playback_volume[idx];	/* analog playback */
+	}
+	for(i=0; i<2; i++) {
+		if(stored_volume[i] != ucontrol->value.integer.value[i]) {
+			stored_volume[i] = ucontrol->value.integer.value[i];
+			changed = 1;
+		}
+	}
+	if(changed) {
+		if(is_capture)	mixart_update_capture_stream_level(chip, is_aes);
+		else		mixart_update_playback_stream_level(chip, is_aes, idx);
+	}
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t snd_mixart_pcm_vol =
+{
+	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
+	/* name will be filled later */
+	/* count will be filled later */
+	.info =         mixart_digital_vol_info,		/* shared */
+	.get =          mixart_pcm_vol_get,
+	.put =          mixart_pcm_vol_put,
+};
+
+
+static int mixart_pcm_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+	down(&chip->mgr->mixer_mutex);
+	if(kcontrol->private_value & MIXART_VOL_AES_MASK)	/* AES playback */
+		idx += MIXART_PLAYBACK_STREAMS;
+	ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0];
+	ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_pcm_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
+	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
+	int i, j;
+	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
+	down(&chip->mgr->mixer_mutex);
+	j = idx;
+	if(is_aes)	j += MIXART_PLAYBACK_STREAMS;
+	for(i=0; i<2; i++) {
+		if(chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) {
+			chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i];
+			changed = 1;
+		}
+	}
+	if(changed)	mixart_update_playback_stream_level(chip, is_aes, idx);
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t mixart_control_pcm_switch = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	/* name will be filled later */
+	.count =        MIXART_PLAYBACK_STREAMS,
+	.info =         mixart_sw_info,		/* shared */
+	.get =          mixart_pcm_sw_get,
+	.put =          mixart_pcm_sw_put
+};
+
+static int mixart_update_monitoring(mixart_t* chip, int channel)
+{
+	int err;
+	mixart_msg_t request;
+	mixart_set_out_audio_level_t audio_level;
+	u32 resp;
+
+	if(chip->pipe_out_ana.status == PIPE_UNDEFINED)
+		return -EINVAL; /* no pipe defined */
+
+	if(!channel)	request.uid = chip->pipe_out_ana.uid_left_connector;
+	else		request.uid = chip->pipe_out_ana.uid_right_connector;
+	request.message_id = MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL;
+	request.data = &audio_level;
+	request.size = sizeof(audio_level);
+
+	memset(&audio_level, 0, sizeof(audio_level));
+	audio_level.valid_mask1 = MIXART_AUDIO_LEVEL_MONITOR_MASK | MIXART_AUDIO_LEVEL_MUTE_M1_MASK;
+	audio_level.monitor_level = mixart_digital_level[chip->monitoring_volume[channel!=0]];
+	audio_level.monitor_mute1 = !chip->monitoring_active[channel!=0];
+
+	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
+	if((err<0) || resp) {
+		snd_printk(KERN_DEBUG "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n", chip->chip_idx, resp);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * monitoring level control
+ */
+
+static int mixart_monitor_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	down(&chip->mgr->mixer_mutex);
+	ucontrol->value.integer.value[0] = chip->monitoring_volume[0];
+	ucontrol->value.integer.value[1] = chip->monitoring_volume[1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_monitor_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int i;
+	down(&chip->mgr->mixer_mutex);
+	for(i=0; i<2; i++) {
+		if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) {
+			chip->monitoring_volume[i] = ucontrol->value.integer.value[i];
+			mixart_update_monitoring(chip, i);
+			changed = 1;
+		}
+	}
+	up(&chip->mgr->mixer_mutex);
+	return changed;
+}
+
+static snd_kcontrol_new_t mixart_control_monitor_vol = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Monitoring Volume",
+	.info =		mixart_digital_vol_info,		/* shared */
+	.get =		mixart_monitor_vol_get,
+	.put =		mixart_monitor_vol_put,
+};
+
+/*
+ * monitoring switch control
+ */
+
+static int mixart_monitor_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	down(&chip->mgr->mixer_mutex);
+	ucontrol->value.integer.value[0] = chip->monitoring_active[0];
+	ucontrol->value.integer.value[1] = chip->monitoring_active[1];
+	up(&chip->mgr->mixer_mutex);
+	return 0;
+}
+
+static int mixart_monitor_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	mixart_t *chip = snd_kcontrol_chip(kcontrol);
+	int changed = 0;
+	int i;
+	down(&chip->mgr->mixer_mutex);
+	for(i=0; i<2; i++) {
+		if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) {
+			chip->monitoring_active[i] = ucontrol->value.integer.value[i];
+			changed |= (1<<i); /* mask 0x01 ans 0x02 */
+		}
+	}
+	if(changed) {
+		/* allocate or release resources for monitoring */
+		int allocate = chip->monitoring_active[0] || chip->monitoring_active[1];
+		if(allocate) {
+			snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 0, 1);	/* allocate the playback pipe for monitoring */
+			snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 1, 1);	/* allocate the capture pipe for monitoring */
+		}
+		if(changed & 0x01)	mixart_update_monitoring(chip, 0);
+		if(changed & 0x02)	mixart_update_monitoring(chip, 1);
+		if(!allocate) {
+			snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_in_ana, 1);	/* release the capture pipe for monitoring */
+			snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_out_ana, 1);	/* release the playback pipe for monitoring */
+		}
+	}
+
+	up(&chip->mgr->mixer_mutex);
+	return (changed != 0);
+}
+
+static snd_kcontrol_new_t mixart_control_monitor_sw = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Monitoring Switch",
+	.info =         mixart_sw_info,		/* shared */
+	.get =          mixart_monitor_sw_get,
+	.put =          mixart_monitor_sw_put
+};
+
+
+static void mixart_reset_audio_levels(mixart_t *chip)
+{
+	/* analog volumes can be set even if there is no pipe */
+	mixart_update_analog_audio_level(chip, 0);
+	/* analog levels for capture only on the first two chips */
+	if(chip->chip_idx < 2) {
+		mixart_update_analog_audio_level(chip, 1);
+	}
+	return;
+}
+
+
+int snd_mixart_create_mixer(mixart_mgr_t *mgr)
+{
+	mixart_t *chip;
+	int err, i;
+
+	init_MUTEX(&mgr->mixer_mutex); /* can be in another place */
+
+	for(i=0; i<mgr->num_cards; i++) {
+		snd_kcontrol_new_t temp;
+		chip = mgr->chip[i];
+
+		/* analog output level control */
+		temp = mixart_control_analog_level;
+		temp.name = "Master Playback Volume";
+		temp.private_value = 0; /* playback */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			return err;
+		/* output mute controls */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_output_switch, chip))) < 0)
+			return err;
+
+		/* analog input level control only on first two chips !*/
+		if(i<2) {
+			temp = mixart_control_analog_level;
+			temp.name = "Master Capture Volume";
+			temp.private_value = 1; /* capture */
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+				return err;
+		}
+
+		temp = snd_mixart_pcm_vol;
+		temp.name = "PCM Playback Volume";
+		temp.count = MIXART_PLAYBACK_STREAMS;
+		temp.private_value = 0; /* playback analog */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			return err;
+
+		temp.name = "PCM Capture Volume";
+		temp.count = 1;
+		temp.private_value = MIXART_VOL_REC_MASK; /* capture analog */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			return err;
+
+		if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) {
+			temp.name = "AES Playback Volume";
+			temp.count = MIXART_PLAYBACK_STREAMS;
+			temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+				return err;
+
+			temp.name = "AES Capture Volume";
+			temp.count = 0;
+			temp.private_value = MIXART_VOL_REC_MASK | MIXART_VOL_AES_MASK; /* capture AES/EBU */
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+				return err;
+		}
+		temp = mixart_control_pcm_switch;
+		temp.name = "PCM Playback Switch";
+		temp.private_value = 0; /* playback analog */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+			return err;
+
+		if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) {
+			temp.name = "AES Playback Switch";
+			temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0)
+				return err;
+		}
+
+		/* monitoring */
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_vol, chip))) < 0)
+			return err;
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_sw, chip))) < 0)
+			return err;
+
+		/* init all mixer data and program the master volumes/switches */
+		mixart_reset_audio_levels(chip);
+	}
+	return 0;
+}
diff -Nru a/sound/pci/mixart/mixart_mixer.h b/sound/pci/mixart/mixart_mixer.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_mixer.h	Sun Feb 22 12:36:43 2004
@@ -0,0 +1,31 @@
+/*
+ * Driver for Digigram miXart soundcards
+ *
+ * include file for mixer
+ *
+ * Copyright (c) 2003 by Digigram <alsa@digigram.com>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __SOUND_MIXART_MIXER_H
+#define __SOUND_MIXART_MIXER_H
+
+/* exported */
+int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx);
+int mixart_update_capture_stream_level(mixart_t* chip, int is_aes);
+int snd_mixart_create_mixer(mixart_mgr_t* mgr);
+
+#endif /* __SOUND_MIXART_MIXER_H */
diff -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c
--- a/sound/pci/via82xx.c	Sun Feb 22 12:36:42 2004
+++ b/sound/pci/via82xx.c	Sun Feb 22 12:36:42 2004
@@ -922,12 +922,10 @@
 				  chip->no_vra ? 48000 : runtime->rate);
 		snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
 	}
-#if 0
-	if (chip->revision == VIA_REV_8233A)
-		rbits = 0;
+	if (runtime->rate == 48000)
+		rbits = 0xfffff;
 	else
-#endif
-		rbits = (0xfffff / 48000) * runtime->rate + ((0xfffff % 48000) * runtime->rate) / 48000;
+		rbits = (0x100000 / 48000) * runtime->rate + ((0x100000 % 48000) * runtime->rate) / 48000;
 	snd_assert((rbits & ~0xfffff) == 0, return -EINVAL);
 	snd_via82xx_channel_reset(chip, viadev);
 	snd_via82xx_set_table_ptr(chip, viadev);
@@ -1989,11 +1987,12 @@
 		{ .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
 		{ .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */
 		{ .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
-		{ .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
+		{ .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_NO_VRA }, /* Gigabyte GA-7VAXP (FIXME: or DXS_ENABLE?) */
 		{ .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
 		{ .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
 		{ .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
 		{ .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
+		{ .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
 		{ .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */
 		{ .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
 		{ .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
diff -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
--- a/sound/usb/usbaudio.c	Sun Feb 22 12:36:42 2004
+++ b/sound/usb/usbaudio.c	Sun Feb 22 12:36:42 2004
@@ -117,7 +117,7 @@
 	struct list_head list;
 	snd_pcm_format_t format;	/* format type */
 	unsigned int channels;		/* # channels */
-	unsigned int nonaudio: 1;	/* non-audio (type II) */
+	unsigned int fmt_type;		/* USB audio format type (1-3) */
 	unsigned int frame_size;	/* samples per frame for non-audio */
 	int iface;			/* interface number */
 	unsigned char altsetting;	/* corresponding alternate setting */
@@ -171,7 +171,7 @@
 	unsigned int curpacksize;	/* current packet size in bytes (for capture) */
 	unsigned int curframesize;	/* current packet size in frames (for capture) */
 	unsigned int fill_max: 1;	/* fill max packet size always */
-	unsigned int nonaudio: 1;	/* Type II format (MPEG, AC3) */
+	unsigned int fmt_type;		/* USB audio format type (1-3) */
 
 	unsigned int running: 1;	/* running status */
 
@@ -201,6 +201,7 @@
 	snd_usb_audio_t *chip;
 	snd_pcm_t *pcm;
 	int pcm_index;
+	unsigned int fmt_type;		/* USB audio format type (1-3) */
 	snd_usb_substream_t substream[2];
 	struct list_head list;
 };
@@ -477,7 +478,7 @@
 		subs->transfer_sched += counts;
 		if (subs->transfer_sched >= runtime->period_size) {
 			subs->transfer_sched -= runtime->period_size;
-			if (subs->nonaudio) {
+			if (subs->fmt_type == USB_FORMAT_TYPE_II) {
 				if (subs->transfer_sched > 0) {
 					/* FIXME: fill-max mode is not supported yet */
 					offs -= subs->transfer_sched;
@@ -894,7 +895,7 @@
 		u->subs = subs;
 		u->transfer = 0;
 		u->packets = npacks[i];
-		if (subs->nonaudio)
+		if (subs->fmt_type == USB_FORMAT_TYPE_II)
 			u->packets++; /* for transfer delimiter */
 		if (! is_playback) {
 			/* allocate a capture buffer per urb */
@@ -1588,7 +1589,7 @@
 			runtime->hw.channels_min = fp->channels;
 		if (runtime->hw.channels_max < fp->channels)
 			runtime->hw.channels_max = fp->channels;
-		if (fp->nonaudio && fp->frame_size > 0) {
+		if (fp->fmt_type == USB_FORMAT_TYPE_II && fp->frame_size > 0) {
 			/* FIXME: there might be more than one audio formats... */
 			runtime->hw.period_bytes_min = runtime->hw.period_bytes_max =
 				fp->frame_size;
@@ -1895,7 +1896,7 @@
 	subs->formats |= 1ULL << fp->format;
 	subs->endpoint = fp->endpoint;
 	subs->num_formats++;
-	subs->nonaudio = fp->nonaudio;
+	subs->fmt_type = fp->fmt_type;
 }
 
 
@@ -1954,17 +1955,12 @@
 
 	list_for_each(p, &chip->pcm_list) {
 		as = list_entry(p, snd_usb_stream_t, list);
+		if (as->fmt_type != fp->fmt_type)
+			continue;
 		subs = &as->substream[stream];
 		if (! subs->endpoint)
-			break;
+			continue;
 		if (subs->endpoint == fp->endpoint) {
-			if (fp->nonaudio) {
-				if (!subs->nonaudio || subs->formats != (1ULL << fp->format))
-					continue; /* non-linear formats are handled exclusively */
-			} else {
-				if (subs->nonaudio)
-					continue;
-			}
 			list_add_tail(&fp->list, &subs->fmt_list);
 			subs->num_formats++;
 			subs->formats |= 1ULL << fp->format;
@@ -1974,6 +1970,8 @@
 	/* look for an empty stream */
 	list_for_each(p, &chip->pcm_list) {
 		as = list_entry(p, snd_usb_stream_t, list);
+		if (as->fmt_type != fp->fmt_type)
+			continue;
 		subs = &as->substream[stream];
 		if (subs->endpoint)
 			continue;
@@ -1991,6 +1989,7 @@
 	memset(as, 0, sizeof(*as));
 	as->pcm_index = chip->pcm_devs;
 	as->chip = chip;
+	as->fmt_type = fp->fmt_type;
 	err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
 			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
 			  stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
@@ -2216,7 +2215,6 @@
 		break;
 	}
 	fp->channels = 1;
-	fp->nonaudio = 1;
 	brate = combine_word(&fmt[4]); 	/* fmt[4,5] : wMaxBitRate (in kbps) */
 	framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */
 	snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);
@@ -2242,6 +2240,7 @@
 			   dev->devnum, fp->iface, fp->altsetting, fmt[3]);
 		return -1;
 	}
+	fp->fmt_type = fmt[3];
 	if (err < 0)
 		return err;
 #if 1
diff -Nru a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
--- a/sound/usb/usbquirks.h	Sun Feb 22 12:36:42 2004
+++ b/sound/usb/usbquirks.h	Sun Feb 22 12:36:42 2004
@@ -502,6 +502,32 @@
 	}
 },
 {
+	/*
+	 * This quirk is for the "Advanced Driver" mode. If off, the UA-3FX
+	 * is standard compliant, but has only 16-bit PCM.
+	 */
+	USB_DEVICE(0x0582, 0x0050),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UA-3FX",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_COMPOSITE,
+		.data = & (const snd_usb_audio_quirk_t[]) {
+			{
+				.ifnum = 1,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = 2,
+				.type = QUIRK_AUDIO_STANDARD_INTERFACE
+			},
+			{
+				.ifnum = -1
+			}
+		}
+	}
+},
+{
 	USB_DEVICE(0x0582, 0x0052),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
@@ -686,6 +712,16 @@
 		.ifnum = QUIRK_NO_INTERFACE
 	}
 	
+},
+
+{
+	USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0013),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Terratec",
+		.product_name = "PHASE 26",
+		.ifnum = 3,
+		.type = QUIRK_MIDI_STANDARD_INTERFACE
+	}
 },
 
 #undef USB_DEVICE_VENDOR_SPEC