You can import this changeset into BK by piping this whole message to:
'| bk receive [path to repository]' or apply the patch as usual.

===================================================================


ChangeSet@1.654, 2002-10-01 16:19:51+02:00, perex@suse.cz
  ALSA update 2002/09/17 :
    - changed bitmap_member -> DECLARE_BITMAP
    - EMU10K1
      - added gpr_list_control* variables to emu10k1_fx8010_code_t
      - added snd_emu10k1_list_controls for code_peek() and fixes few typos
    - ICE1712
      - split ice1712 code to several files for better readability


 include/sound/ac97_codec.h     |    3 
 include/sound/emu10k1.h        |    9 
 include/sound/version.h        |    2 
 sound/core/seq/seq_clientmgr.h |    3 
 sound/core/seq/seq_queue.h     |    3 
 sound/pci/emu10k1/emufx.c      |   53 
 sound/pci/ice1712/Makefile     |   13 
 sound/pci/ice1712/ak4524.c     |  324 +++++
 sound/pci/ice1712/delta.c      |  498 ++++++++
 sound/pci/ice1712/delta.h      |  120 +
 sound/pci/ice1712/ews.c        |  928 +++++++++++++++
 sound/pci/ice1712/ews.h        |   81 +
 sound/pci/ice1712/hoontech.c   |  223 +++
 sound/pci/ice1712/hoontech.h   |   64 +
 sound/pci/ice1712/ice1712.c    | 2477 +++++++++++++++++++++++++++++++++++++++++
 sound/pci/ice1712/ice1712.h    |  388 ++++++
 16 files changed, 5183 insertions(+), 6 deletions(-)


diff -Nru a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
--- a/include/sound/ac97_codec.h	Tue Oct  1 17:11:34 2002
+++ b/include/sound/ac97_codec.h	Tue Oct  1 17:11:34 2002
@@ -25,6 +25,7 @@
  *
  */
 
+#include <linux/bitops.h>
 #include "control.h"
 #include "info.h"
 
@@ -246,7 +247,7 @@
 	unsigned int spdif_status;
 	unsigned short regs[0x80]; /* register cache */
 	unsigned int limited_regs; /* allow limited registers only */
-	bitmap_member(reg_accessed,0x80); /* bit flags */
+	DECLARE_BITMAP(reg_accessed, 0x80); /* bit flags */
 	union {			/* vendor specific code */
 		struct {
 			unsigned short unchained[3];	// 0 = C34, 1 = C79, 2 = C69
diff -Nru a/include/sound/emu10k1.h b/include/sound/emu10k1.h
--- a/include/sound/emu10k1.h	Tue Oct  1 17:11:34 2002
+++ b/include/sound/emu10k1.h	Tue Oct  1 17:11:34 2002
@@ -1301,15 +1301,24 @@
 
 typedef struct {
 	char name[128];
+
 	unsigned long gpr_valid[0x100/(sizeof(unsigned long)*8)]; /* bitmask of valid initializers */
 	unsigned int gpr_map[0x100];	  /* initializers */
+
 	unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */
 	emu10k1_fx8010_control_gpr_t *gpr_add_controls; /* GPR controls to add/replace */
+
 	unsigned int gpr_del_control_count; /* count of GPR controls to remove */
 	snd_ctl_elem_id_t *gpr_del_controls; /* IDs of GPR controls to remove */
+
+	unsigned int gpr_list_control_count; /* count of GPR controls to list */
+	unsigned int gpr_list_control_total; /* total count of GPR controls */
+	emu10k1_fx8010_control_gpr_t *gpr_list_controls; /* listed GPR controls */
+
 	unsigned long tram_valid[0xa0/(sizeof(unsigned long)*8)]; /* bitmask of valid initializers */
 	unsigned int tram_data_map[0xa0]; /* data initializers */
 	unsigned int tram_addr_map[0xa0]; /* map initializers */
+
 	unsigned long code_valid[512/(sizeof(unsigned long)*8)];  /* bitmask of valid instructions */
 	unsigned int code[512][2];	  /* one instruction - 64 bits */
 } emu10k1_fx8010_code_t;
diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h	Tue Oct  1 17:11:34 2002
+++ b/include/sound/version.h	Tue Oct  1 17:11:34 2002
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #define CONFIG_SND_VERSION "0.9.0rc3"
-#define CONFIG_SND_DATE " (Mon Sep 16 18:05:43 2002 UTC)"
+#define CONFIG_SND_DATE " (Tue Sep 17 13:46:32 2002 UTC)"
diff -Nru a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
--- a/sound/core/seq/seq_clientmgr.h	Tue Oct  1 17:11:34 2002
+++ b/sound/core/seq/seq_clientmgr.h	Tue Oct  1 17:11:34 2002
@@ -22,6 +22,7 @@
 #define __SND_SEQ_CLIENTMGR_H
 
 #include <sound/seq_kernel.h>
+#include <linux/bitops.h>
 #include "seq_fifo.h"
 #include "seq_ports.h"
 #include "seq_lock.h"
@@ -53,7 +54,7 @@
 	char name[64];		/* client name */
 	int number;		/* client number */
 	unsigned int filter;	/* filter flags */
-	bitmap_member(event_filter, 256);
+	DECLARE_BITMAP(event_filter, 256);
 	snd_use_lock_t use_lock;
 	int event_lost;
 	/* ports */
diff -Nru a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
--- a/sound/core/seq/seq_queue.h	Tue Oct  1 17:11:34 2002
+++ b/sound/core/seq/seq_queue.h	Tue Oct  1 17:11:34 2002
@@ -26,6 +26,7 @@
 #include "seq_lock.h"
 #include <linux/interrupt.h>
 #include <linux/list.h>
+#include <linux/bitops.h>
 
 #define SEQ_QUEUE_NO_OWNER (-1)
 
@@ -51,7 +52,7 @@
 	spinlock_t check_lock;
 
 	/* clients which uses this queue (bitmap) */
-	bitmap_member(clients_bitmap, SNDRV_SEQ_MAX_CLIENTS);
+	DECLARE_BITMAP(clients_bitmap, SNDRV_SEQ_MAX_CLIENTS);
 	unsigned int clients;	/* users of this queue */
 	struct semaphore timer_mutex;
 
diff -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
--- a/sound/pci/emu10k1/emufx.c	Tue Oct  1 17:11:34 2002
+++ b/sound/pci/emu10k1/emufx.c	Tue Oct  1 17:11:34 2002
@@ -923,7 +923,7 @@
 			return -ENOENT;
 	}
 	for (i = 0, _gctl = icode->gpr_add_controls;
-	     i < icode->gpr_add_control_count; i++) {
+	     i < icode->gpr_add_control_count; i++, _gctl++) {
 		if (copy_from_user(&gctl, _gctl, sizeof(gctl)))
 			return -EFAULT;
 		if (snd_emu10k1_look_for_ctl(emu, &gctl.id))
@@ -934,6 +934,12 @@
 		    gctl.id.iface != SNDRV_CTL_ELEM_IFACE_PCM)
 			return -EINVAL;
 	}
+	for (i = 0, _gctl = icode->gpr_list_controls;
+	     i < icode->gpr_list_control_count; i++, _gctl++) {
+	     	/* FIXME: we need to check the WRITE access */
+		if (copy_from_user(&gctl, _gctl, sizeof(gctl)))
+			return -EFAULT;
+	}
 	return 0;
 }
 
@@ -968,6 +974,8 @@
 		knew.iface = gctl.id.iface;
 		knew.name = gctl.id.name;
 		knew.index = gctl.id.index;
+		knew.device = gctl.id.device;
+		knew.subdevice = gctl.id.subdevice;
 		knew.info = snd_emu10k1_gpr_ctl_info;
 		knew.get = snd_emu10k1_gpr_ctl_get;
 		knew.put = snd_emu10k1_gpr_ctl_put;
@@ -976,7 +984,7 @@
 		nctl.count = gctl.count;
 		for (j = 0; j < 32; j++) {
 			nctl.gpr[j] = gctl.gpr[j];
-			nctl.value[j] = ~gctl.value[j];
+			nctl.value[j] = ~gctl.value[j];	/* inverted, we want to write new value in gpr_ctl_put() */
 			val.value.integer.value[j] = gctl.value[j];
 		}
 		nctl.min = gctl.min;
@@ -1019,7 +1027,47 @@
 		ctl = snd_emu10k1_look_for_ctl(emu, &id);
 		snd_runtime_check(ctl == NULL, continue);
 		snd_ctl_remove(emu->card, ctl->kcontrol);
+		list_del(&ctl->list);
+	}
+}
+
+static void snd_emu10k1_list_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+{
+	int i = 0, j;
+	unsigned int total = 0;
+	emu10k1_fx8010_control_gpr_t *_gctl, gctl;
+	snd_emu10k1_fx8010_ctl_t *ctl;
+	snd_ctl_elem_id_t *id;
+	struct list_head *list;
+
+	_gctl = icode->gpr_list_controls;	
+	list_for_each(list, &emu->fx8010.gpr_ctl) {
+		ctl = emu10k1_gpr_ctl(list);
+		total++;
+		if (i < icode->gpr_list_control_count) {
+			memset(&gctl, 0, sizeof(gctl));
+			id = &ctl->kcontrol->id;
+			gctl.id.iface = id->iface;
+			strncpy(gctl.id.name, id->name, sizeof(gctl.id.name));
+			gctl.id.index = id->index;
+			gctl.id.device = id->device;
+			gctl.id.subdevice = id->subdevice;
+			gctl.vcount = ctl->vcount;
+			gctl.count = ctl->count;
+			for (j = 0; j < 32; j++) {
+				gctl.gpr[j] = ctl->gpr[j];
+				gctl.value[j] = ctl->value[j];
+			}
+			gctl.min = ctl->min;
+			gctl.max = ctl->max;
+			gctl.translation = ctl->translation;
+			snd_runtime_check(copy_to_user(_gctl, &gctl, sizeof(gctl)) == 0, goto __next);
+		}
+	      __next:
+		_gctl++;
+		i++;
 	}
+	icode->gpr_list_control_total = total;
 }
 
 static int snd_emu10k1_icode_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
@@ -1062,6 +1110,7 @@
 	snd_emu10k1_gpr_peek(emu, icode);
 	snd_emu10k1_tram_peek(emu, icode);
 	snd_emu10k1_code_peek(emu, icode);
+	snd_emu10k1_list_controls(emu, icode);
 	up(&emu->fx8010.lock);
 	return 0;
 }
diff -Nru a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/Makefile	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,13 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+export-objs  := ice1712.o
+
+snd-ice1712-objs := ice1712.o ak4524.o delta.o hoontech.o ews.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/sound/pci/ice1712/ak4524.c b/sound/pci/ice1712/ak4524.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/ak4524.c	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,324 @@
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   AK4524 / AK4528 interface
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *
+ *   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 <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <sound/core.h>
+#include "ice1712.h"
+
+
+/*
+ * write AK4524 register
+ */
+void snd_ice1712_ak4524_write(ice1712_t *ice, int chip,
+			      unsigned char addr, unsigned char data)
+{
+	unsigned char tmp, saved[2];
+	int idx;
+	unsigned int addrdata;
+	ak4524_t *ak = &ice->ak4524;
+
+	snd_assert(chip >= 0 && chip < 4, return);
+
+	if (ak->ops.start) {
+		if (ak->ops.start(ice, saved, chip) < 0)
+			return;
+	} else
+		snd_ice1712_save_gpio_status(ice, saved);
+
+	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+	tmp |= ak->add_flags;
+	if (ak->cif) {
+		tmp |= ak->codecs_mask; /* start without chip select */
+	}  else {
+		tmp &= ~ak->codecs_mask; /* chip select low */
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		udelay(1);
+	}
+
+	addr &= 0x07;
+	/* build I2C address + data byte */
+	addrdata = 0xa000 | (addr << 8) | data;
+	for (idx = 15; idx >= 0; idx--) {
+		tmp &= ~(ak->data_mask | ak->clk_mask);
+		if (addrdata & (1 << idx))
+			tmp |= ak->data_mask;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		//udelay(200);
+		udelay(1);
+		tmp |= ak->clk_mask;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		udelay(1);
+	}
+
+	if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0)
+		ak->images[chip][addr] = data;
+	else
+		ak->ipga_gain[chip][addr-4] = data;
+
+	if (ak->cif) {
+		/* assert a cs pulse to trigger */
+		tmp &= ~ak->codecs_mask;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		udelay(1);
+	}
+	tmp |= ak->codecs_mask; /* chip select high to trigger */
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+	udelay(1);
+
+	if (ak->ops.stop)
+		ak->ops.stop(ice, saved);
+	else
+		snd_ice1712_restore_gpio_status(ice, saved);
+}
+
+void snd_ice1712_ak4524_reset(ice1712_t *ice, int state)
+{
+	int chip;
+	unsigned char reg;
+	ak4524_t *ak = &ice->ak4524;
+	
+	for (chip = 0; chip < ak->num_dacs/2; chip++) {
+		snd_ice1712_ak4524_write(ice, chip, 0x01, state ? 0x00 : 0x03);
+		if (state)
+			continue;
+		for (reg = 0x04; reg < (ak->is_ak4528 ? 0x06 : 0x08); reg++)
+			snd_ice1712_ak4524_write(ice, chip, reg, ak->images[chip][reg]);
+		if (ak->is_ak4528)
+			continue;
+		for (reg = 0x04; reg < 0x06; reg++)
+			snd_ice1712_ak4524_write(ice, chip, reg, ak->ipga_gain[chip][reg-4]);
+	}
+}
+
+/*
+ * initialize all the ak4524/4528 chips
+ */
+void __devinit snd_ice1712_ak4524_init(ice1712_t *ice)
+{
+	static unsigned char inits[] = {
+		0x00, 0x07, /* 0: all power up */
+		0x01, 0x00, /* 1: ADC/DAC reset */
+		0x02, 0x60, /* 2: 24bit I2S */
+		0x03, 0x19, /* 3: deemphasis off */
+		0x01, 0x03, /* 1: ADC/DAC enable */
+		0x04, 0x00, /* 4: ADC left muted */
+		0x05, 0x00, /* 5: ADC right muted */
+		0x04, 0x80, /* 4: ADC IPGA gain 0dB */
+		0x05, 0x80, /* 5: ADC IPGA gain 0dB */
+		0x06, 0x00, /* 6: DAC left muted */
+		0x07, 0x00, /* 7: DAC right muted */
+		0xff, 0xff
+	};
+	int chip, idx;
+	unsigned char *ptr, reg, data;
+	ak4524_t *ak = &ice->ak4524;
+
+	for (chip = idx = 0; chip < ak->num_dacs/2; chip++) {
+		ptr = inits;
+		while (*ptr != 0xff) {
+			reg = *ptr++;
+			data = *ptr++;
+			if (ak->is_ak4528) {
+				if (reg > 5)
+					continue;
+				if (reg >= 4 && (data & 0x80))
+					continue;
+			}
+			if (reg == 0x03 && ak->is_ak4528)
+				data = 0x0d;	/* deemphasis off, turn LR highpass filters on */
+			snd_ice1712_ak4524_write(ice, chip, reg, data);
+		}
+	}
+}
+
+static int snd_ice1712_ak4524_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 127;
+	return 0;
+}
+
+static int snd_ice1712_ak4524_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int chip = kcontrol->private_value / 8;
+	int addr = kcontrol->private_value % 8;
+	ucontrol->value.integer.value[0] = ice->ak4524.images[chip][addr];
+	return 0;
+}
+
+static int snd_ice1712_ak4524_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int chip = kcontrol->private_value / 8;
+	int addr = kcontrol->private_value % 8;
+	unsigned char nval = ucontrol->value.integer.value[0];
+	int change = ice->ak4524.images[chip][addr] != nval;
+	if (change)
+		snd_ice1712_ak4524_write(ice, chip, addr, nval);
+	return change;
+}
+
+static int snd_ice1712_ak4524_ipga_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 36;
+	return 0;
+}
+
+static int snd_ice1712_ak4524_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int chip = kcontrol->private_value / 8;
+	int addr = kcontrol->private_value % 8;
+	ucontrol->value.integer.value[0] = ice->ak4524.ipga_gain[chip][addr-4] & 0x7f;
+	return 0;
+}
+
+static int snd_ice1712_ak4524_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int chip = kcontrol->private_value / 8;
+	int addr = kcontrol->private_value % 8;
+	unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80;
+	int change = ice->ak4524.ipga_gain[chip][addr] != nval;
+	if (change)
+		snd_ice1712_ak4524_write(ice, chip, addr, nval);
+	return change;
+}
+
+static int snd_ice1712_ak4524_deemphasis_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[4] = {
+		"44.1kHz", "Off", "48kHz", "32kHz",
+	};
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 4;
+	if (uinfo->value.enumerated.item >= 4)
+		uinfo->value.enumerated.item = 3;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ice1712_ak4524_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int chip = kcontrol->id.index;
+	ucontrol->value.enumerated.item[0] = ice->ak4524.images[chip][3] & 3;
+	return 0;
+}
+
+static int snd_ice1712_ak4524_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int chip = kcontrol->id.index;
+	unsigned char nval = ucontrol->value.enumerated.item[0];
+	int change;
+	nval |= (nval & 3) | (ice->ak4524.images[chip][3] & ~3);
+	change = ice->ak4524.images[chip][3] != nval;
+	if (change)
+		snd_ice1712_ak4524_write(ice, chip, 3, nval);
+	return change;
+}
+
+/*
+ * build AK4524 controls
+ */
+
+int __devinit snd_ice1712_ak4524_build_controls(ice1712_t *ice)
+{
+	int err, idx;
+	ak4524_t *ak = &ice->ak4524;
+
+	for (idx = 0; idx < ak->num_dacs; ++idx) {
+		snd_kcontrol_t ctl;
+		memset(&ctl, 0, sizeof(ctl));
+		strcpy(ctl.id.name, "DAC Volume");
+		ctl.id.index = idx;
+		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl.info = snd_ice1712_ak4524_volume_info;
+		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+		ctl.get = snd_ice1712_ak4524_volume_get;
+		ctl.put = snd_ice1712_ak4524_volume_put;
+		if (ak->is_ak4528)
+			ctl.private_value = (idx / 2) * 8 + (idx % 2) + 4; /* register 4 & 5 */
+		else
+			ctl.private_value = (idx / 2) * 8 + (idx % 2) + 6; /* register 6 & 7 */
+		ctl.private_data = ice;
+		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
+			return err;
+	}
+	for (idx = 0; idx < ak->num_adcs && !ak->is_ak4528; ++idx) {
+		snd_kcontrol_t ctl;
+		memset(&ctl, 0, sizeof(ctl));
+		strcpy(ctl.id.name, "ADC Volume");
+		ctl.id.index = idx;
+		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl.info = snd_ice1712_ak4524_volume_info;
+		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+		ctl.get = snd_ice1712_ak4524_volume_get;
+		ctl.put = snd_ice1712_ak4524_volume_put;
+		ctl.private_value = (idx / 2) * 8 + (idx % 2) + 4; /* register 4 & 5 */
+		ctl.private_data = ice;
+		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
+			return err;
+		memset(&ctl, 0, sizeof(ctl));
+		strcpy(ctl.id.name, "IPGA Analog Capture Volume");
+		ctl.id.index = idx;
+		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl.info = snd_ice1712_ak4524_ipga_gain_info;
+		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+		ctl.get = snd_ice1712_ak4524_ipga_gain_get;
+		ctl.put = snd_ice1712_ak4524_ipga_gain_put;
+		ctl.private_value = (idx / 2) * 8 + (idx % 2) + 4; /* register 4 & 5 */
+		ctl.private_data = ice;
+		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
+			return err;
+	}
+	for (idx = 0; idx < ak->num_dacs/2; idx++) {
+		snd_kcontrol_t ctl;
+		memset(&ctl, 0, sizeof(ctl));
+		strcpy(ctl.id.name, "Deemphasis");
+		ctl.id.index = idx;
+		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl.info = snd_ice1712_ak4524_deemphasis_info;
+		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+		ctl.get = snd_ice1712_ak4524_deemphasis_get;
+		ctl.put = snd_ice1712_ak4524_deemphasis_put;
+		ctl.private_data = ice;
+		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
+			return err;
+	}
+	return 0;
+}
+
+
diff -Nru a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/delta.c	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,498 @@
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   Lowlevel functions for M-Audio Delta 1010, 44, 66, Dio2496, Audiophile
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *
+ *   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 <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/cs8427.h>
+#include <sound/asoundef.h>
+
+#include "ice1712.h"
+#include "delta.h"
+
+#define SND_CS8403
+#include <sound/cs8403.h>
+
+
+/*
+ * CS8427 via SPI mode (for Audiophile), emulated I2C
+ */
+
+/* send 8 bits */
+static void ap_cs8427_write_byte(ice1712_t *ice, unsigned char data, unsigned char tmp)
+{
+	int idx;
+
+	for (idx = 7; idx >= 0; idx--) {
+		tmp &= ~(ICE1712_DELTA_AP_DOUT|ICE1712_DELTA_AP_CCLK);
+		if (data & (1 << idx))
+			tmp |= ICE1712_DELTA_AP_DOUT;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		udelay(5);
+		tmp |= ICE1712_DELTA_AP_CCLK;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		udelay(5);
+	}
+}
+
+/* read 8 bits */
+static unsigned char ap_cs8427_read_byte(ice1712_t *ice, unsigned char tmp)
+{
+	unsigned char data = 0;
+	int idx;
+	
+	for (idx = 7; idx >= 0; idx--) {
+		tmp &= ~ICE1712_DELTA_AP_CCLK;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		udelay(5);
+		if (snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ICE1712_DELTA_AP_DIN)
+			data |= 1 << idx;
+		tmp |= ICE1712_DELTA_AP_CCLK;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		udelay(5);
+	}
+	return data;
+}
+
+/* assert chip select */
+static unsigned char ap_cs8427_codec_select(ice1712_t *ice)
+{
+	unsigned char tmp;
+	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+	tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC;
+	tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+	udelay(5);
+	return tmp;
+}
+
+/* deassert chip select */
+static void ap_cs8427_codec_deassert(ice1712_t *ice, unsigned char tmp)
+{
+	tmp |= ICE1712_DELTA_AP_CS_DIGITAL;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+}
+
+/* sequential write */
+static int ap_cs8427_sendbytes(snd_i2c_device_t *device, unsigned char *bytes, int count)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, device->bus->private_data, return -EIO);
+	int res = count;
+	unsigned char tmp;
+
+	down(&ice->gpio_mutex);
+	tmp = ap_cs8427_codec_select(ice);
+	ap_cs8427_write_byte(ice, (device->addr << 1) | 0, tmp); /* address + write mode */
+	while (count-- > 0)
+		ap_cs8427_write_byte(ice, *bytes++, tmp);
+	ap_cs8427_codec_deassert(ice, tmp);
+	up(&ice->gpio_mutex);
+	return res;
+}
+
+/* sequential read */
+static int ap_cs8427_readbytes(snd_i2c_device_t *device, unsigned char *bytes, int count)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, device->bus->private_data, return -EIO);
+	int res = count;
+	unsigned char tmp;
+	
+	down(&ice->gpio_mutex);
+	tmp = ap_cs8427_codec_select(ice);
+	ap_cs8427_write_byte(ice, (device->addr << 1) | 1, tmp); /* address + read mode */
+	while (count-- > 0)
+		*bytes++ = ap_cs8427_read_byte(ice, tmp);
+	ap_cs8427_codec_deassert(ice, tmp);
+	up(&ice->gpio_mutex);
+	return res;
+}
+
+static int ap_cs8427_probeaddr(snd_i2c_bus_t *bus, unsigned short addr)
+{
+	if (addr == 0x10)
+		return 1;
+	return -ENOENT;
+}
+
+static snd_i2c_ops_t ap_cs8427_i2c_ops = {
+	.sendbytes = ap_cs8427_sendbytes,
+	.readbytes = ap_cs8427_readbytes,
+	.probeaddr = ap_cs8427_probeaddr,
+};
+
+/*
+ */
+
+static void snd_ice1712_delta_cs8403_spdif_write(ice1712_t *ice, unsigned char bits)
+{
+	unsigned char tmp, mask1, mask2;
+	int idx;
+	/* send byte to transmitter */
+	mask1 = ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK;
+	mask2 = ICE1712_DELTA_SPDIF_OUT_STAT_DATA;
+	down(&ice->gpio_mutex);
+	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+	for (idx = 7; idx >= 0; idx--) {
+		tmp &= ~(mask1 | mask2);
+		if (bits & (1 << idx))
+			tmp |= mask2;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		udelay(100);
+		tmp |= mask1;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+		udelay(100);
+	}
+	tmp &= ~mask1;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+	up(&ice->gpio_mutex);
+}
+
+
+static void delta_spdif_default_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
+{
+	snd_cs8403_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_bits);
+}
+
+static int delta_spdif_default_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	unsigned int val;
+	int change;
+
+	val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958);
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	change = ice->spdif.cs8403_bits != val;
+	ice->spdif.cs8403_bits = val;
+	if (change && ice->playback_pro_substream == NULL) {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		snd_ice1712_delta_cs8403_spdif_write(ice, val);
+	} else {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+	}
+	return change;
+}
+
+static void delta_spdif_stream_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
+{
+	snd_cs8403_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_stream_bits);
+}
+
+static int delta_spdif_stream_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	unsigned int val;
+	int change;
+
+	val = snd_cs8403_encode_spdif_bits(&ucontrol->value.iec958);
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	change = ice->spdif.cs8403_stream_bits != val;
+	ice->spdif.cs8403_stream_bits = val;
+	if (change && ice->playback_pro_substream != NULL) {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		snd_ice1712_delta_cs8403_spdif_write(ice, val);
+	} else {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+	}
+	return change;
+}
+
+
+/*
+ * AK4524 on Delta 44 and 66 to choose the chip mask
+ */
+static int delta_ak4524_start(ice1712_t *ice, unsigned char *saved, int chip)
+{
+	snd_ice1712_save_gpio_status(ice, saved);
+	ice->ak4524.codecs_mask = chip == 0 ? ICE1712_DELTA_CODEC_CHIP_A : ICE1712_DELTA_CODEC_CHIP_B;
+	return 0;
+}
+
+/*
+ * change the rate of AK4524 on Delta 44/66 and AP
+ */
+static void delta_ak4524_set_rate_val(ice1712_t *ice, unsigned char val)
+{
+	unsigned char tmp, tmp2;
+
+	/* check before reset ak4524 to avoid unnecessary clicks */
+	down(&ice->gpio_mutex);
+	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+	up(&ice->gpio_mutex);
+	tmp2 = tmp;
+	tmp2 &= ~ICE1712_DELTA_DFS; 
+	if (val == 15 || val == 11 || val == 7)
+		tmp2 |= ICE1712_DELTA_DFS;
+	if (tmp == tmp2)
+		return;
+
+	/* do it again */
+	snd_ice1712_ak4524_reset(ice, 1);
+	down(&ice->gpio_mutex);
+	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+	if (val == 15 || val == 11 || val == 7) {
+		tmp |= ICE1712_DELTA_DFS;
+	} else {
+		tmp &= ~ICE1712_DELTA_DFS;
+	}
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+	up(&ice->gpio_mutex);
+	snd_ice1712_ak4524_reset(ice, 0);
+}
+
+
+/*
+ * SPDIF ops for Delta 1010, Dio, 66
+ */
+
+/* open callback */
+static void delta_open_spdif(ice1712_t *ice, snd_pcm_substream_t * substream)
+{
+	ice->spdif.cs8403_stream_bits = ice->spdif.cs8403_bits;
+}
+
+/* set up */
+static void delta_setup_spdif(ice1712_t *ice, snd_pcm_substream_t * substream)
+{
+	unsigned long flags;
+	unsigned int tmp;
+	int change;
+
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	tmp = ice->spdif.cs8403_stream_bits;
+	if (tmp & 0x01)		/* consumer */
+		tmp &= (tmp & 0x01) ? ~0x06 : ~0x18;
+	switch (substream->runtime->rate) {
+	case 32000: tmp |= (tmp & 0x01) ? 0x04 : 0x00; break;
+	case 44100: tmp |= (tmp & 0x01) ? 0x00 : 0x10; break;
+	case 48000: tmp |= (tmp & 0x01) ? 0x02 : 0x08; break;
+	default: tmp |= (tmp & 0x01) ? 0x00 : 0x18; break;
+	}
+	change = ice->spdif.cs8403_stream_bits != tmp;
+	ice->spdif.cs8403_stream_bits = tmp;
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	if (change)
+		snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &ice->spdif.stream_ctl->id);
+	snd_ice1712_delta_cs8403_spdif_write(ice, tmp);
+}
+
+
+/*
+ * initialize the chips on M-Audio cards
+ */
+
+static int __devinit snd_ice1712_delta_init(ice1712_t *ice)
+{
+	int err;
+	ak4524_t *ak;
+
+	/* determine I2C, DACs and ADCs */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_AUDIOPHILE:
+		ice->num_total_dacs = 2;
+		break;
+	case ICE1712_SUBDEVICE_DELTA44:
+	case ICE1712_SUBDEVICE_DELTA66:
+		ice->num_total_dacs = ice->omni ? 8 : 4;
+		break;
+	case ICE1712_SUBDEVICE_DELTA1010:
+		ice->num_total_dacs = 8;
+		break;
+	}
+
+	/* initialize spdif */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_AUDIOPHILE:
+		if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {
+			snd_printk("unable to create I2C bus\n");
+			return err;
+		}
+		ice->i2c->private_data = ice;
+		ice->i2c->ops = &ap_cs8427_i2c_ops;
+		if ((err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR)) < 0)
+			return err;
+		break;
+	case ICE1712_SUBDEVICE_DELTA1010:
+	case ICE1712_SUBDEVICE_DELTADIO2496:
+	case ICE1712_SUBDEVICE_DELTA66:
+		ice->spdif.ops.open = delta_open_spdif;
+		ice->spdif.ops.setup = delta_setup_spdif;
+		ice->spdif.ops.default_get = delta_spdif_default_get;
+		ice->spdif.ops.default_put = delta_spdif_default_put;
+		ice->spdif.ops.stream_get = delta_spdif_stream_get;
+		ice->spdif.ops.stream_put = delta_spdif_stream_put;
+		/* Set spdif defaults */
+		snd_ice1712_delta_cs8403_spdif_write(ice, ice->spdif.cs8403_bits);
+		break;
+	}
+
+	/* second stage of initialization, analog parts and others */
+	ak = &ice->ak4524;
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_AUDIOPHILE:
+		ak->num_adcs = ak->num_dacs = 2;
+		ak->is_ak4528 = 1;
+		ak->cif = 0; /* the default level of the CIF pin from AK4524 */
+		ak->data_mask = ICE1712_DELTA_AP_DOUT;
+		ak->clk_mask = ICE1712_DELTA_AP_CCLK;
+		ak->codecs_mask = ICE1712_DELTA_AP_CS_CODEC; /* select AK4528 codec */
+		ak->add_flags = ICE1712_DELTA_AP_CS_DIGITAL; /* assert digital high */
+		ak->ops.set_rate_val = delta_ak4524_set_rate_val;
+		snd_ice1712_ak4524_init(ice);
+		break;
+	case ICE1712_SUBDEVICE_DELTA66:
+	case ICE1712_SUBDEVICE_DELTA44:
+		ak->num_adcs = ak->num_dacs = 4;
+		ak->cif = 0; /* the default level of the CIF pin from AK4524 */
+		ak->data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA;
+		ak->clk_mask = ICE1712_DELTA_CODEC_SERIAL_CLOCK;
+		ak->codecs_mask = 0; /* set later */
+		ak->add_flags = 0;
+		ak->ops.start = delta_ak4524_start;
+		ak->ops.set_rate_val = delta_ak4524_set_rate_val;
+		snd_ice1712_ak4524_init(ice);
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * additional controls for M-Audio cards
+ */
+
+static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_select __devinitdata =
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
+static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_status __devinitdata =
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
+static snd_kcontrol_new_t snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
+static snd_kcontrol_new_t snd_ice1712_delta_spdif_in_status __devinitdata =
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
+
+
+static int __devinit snd_ice1712_delta_add_controls(ice1712_t *ice)
+{
+	int err;
+
+	/* 1010 and dio specific controls */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_DELTA1010:
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_delta1010_wordclock_select, ice));
+		if (err < 0)
+			return err;
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_delta1010_wordclock_status, ice));
+		if (err < 0)
+			return err;
+		break;
+	case ICE1712_SUBDEVICE_DELTADIO2496:
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_deltadio2496_spdif_in_select, ice));
+		if (err < 0)
+			return err;
+		break;
+	}
+
+	/* normal spdif controls */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_DELTA1010:
+	case ICE1712_SUBDEVICE_DELTADIO2496:
+	case ICE1712_SUBDEVICE_DELTA66:
+	case ICE1712_SUBDEVICE_AUDIOPHILE:
+		err = snd_ice1712_spdif_build_controls(ice);
+		if (err < 0)
+			return err;
+		break;
+	}
+
+	/* spdif status in */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_DELTA1010:
+	case ICE1712_SUBDEVICE_DELTADIO2496:
+	case ICE1712_SUBDEVICE_DELTA66:
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_delta_spdif_in_status, ice));
+		if (err < 0)
+			return err;
+		break;
+	}
+
+	/* ak4524 controls */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_AUDIOPHILE:
+	case ICE1712_SUBDEVICE_DELTA44:
+	case ICE1712_SUBDEVICE_DELTA66:
+		err = snd_ice1712_ak4524_build_controls(ice);
+		if (err < 0)
+			return err;
+		break;
+	}
+	return 0;
+}
+
+
+/* entry point */
+struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
+	{
+		ICE1712_SUBDEVICE_DELTA1010,
+		"M Audio Delta 1010",
+		snd_ice1712_delta_init,
+		snd_ice1712_delta_add_controls,
+	},
+	{
+		ICE1712_SUBDEVICE_DELTADIO2496,
+		"M Audio Delta DiO 2496",
+		snd_ice1712_delta_init,
+		snd_ice1712_delta_add_controls,
+		1, /* NO MPU */
+	},
+	{
+		ICE1712_SUBDEVICE_DELTA66,
+		"M Audio Delta 66",
+		snd_ice1712_delta_init,
+		snd_ice1712_delta_add_controls,
+		1, /* NO MPU */
+	},
+	{
+		ICE1712_SUBDEVICE_DELTA44,
+		"M Audio Delta 44",
+		snd_ice1712_delta_init,
+		snd_ice1712_delta_add_controls,
+		1, /* NO MPU */
+	},
+	{
+		ICE1712_SUBDEVICE_AUDIOPHILE,
+		"M Audio Audiophile 24/96",
+		snd_ice1712_delta_init,
+		snd_ice1712_delta_add_controls,
+	},
+	{
+		ICE1712_SUBDEVICE_DELTA1010LT,
+		"M Audio Delta 1010LT",
+		snd_ice1712_delta_init,
+		snd_ice1712_delta_add_controls,
+	},
+	{ } /* terminator */
+};
diff -Nru a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/delta.h	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,120 @@
+#ifndef __SOUND_DELTA_H
+#define __SOUND_DELTA_H
+
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   Lowlevel functions for M-Audio Delta 1010, 44, 66, Dio2496, Audiophile
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *
+ *   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
+ *
+ */      
+
+#define DELTA_DEVICE_DESC \
+		"{MidiMan M Audio,Delta 1010},"\
+		"{MidiMan M Audio,Delta DiO 2496},"\
+		"{MidiMan M Audio,Delta 66},"\
+		"{MidiMan M Audio,Delta 44},"\
+		"{MidiMan M Audio,Audiophile 24/96},"
+
+#define ICE1712_SUBDEVICE_DELTA1010	0x121430d6
+#define ICE1712_SUBDEVICE_DELTADIO2496	0x121431d6
+#define ICE1712_SUBDEVICE_DELTA66	0x121432d6
+#define ICE1712_SUBDEVICE_DELTA44	0x121433d6
+#define ICE1712_SUBDEVICE_AUDIOPHILE	0x121434d6
+#define ICE1712_SUBDEVICE_DELTA1010LT	0x12143bd6
+
+/* entry point */
+extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
+
+
+/*
+ *  MidiMan M-Audio Delta GPIO definitions
+ */
+
+/* MidiMan M-Audio Delta1010 */
+#define ICE1712_DELTA_DFS 0x01		/* fast/slow sample rate mode */
+					/* (>48kHz must be 1) */
+#define ICE1712_DELTA_SPDIF_IN_STAT 0x02
+					/* S/PDIF input status */
+					/* 0 = valid signal is present */
+					/* all except Delta44 */
+					/* look to CS8414 datasheet */
+#define ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK 0x04
+					/* S/PDIF output status clock */
+					/* (writting on rising edge - 0->1) */
+					/* all except Delta44 */
+					/* look to CS8404A datasheet */
+#define ICE1712_DELTA_SPDIF_OUT_STAT_DATA 0x08
+					/* S/PDIF output status data */
+					/* all except Delta44 */
+					/* look to CS8404A datasheet */
+/* MidiMan M-Audio DeltaDiO */
+/* 0x01 = DFS */
+/* 0x02 = SPDIF_IN_STAT */
+/* 0x04 = SPDIF_OUT_STAT_CLOCK */
+/* 0x08 = SPDIF_OUT_STAT_DATA */
+#define ICE1712_DELTA_SPDIF_INPUT_SELECT 0x10
+					/* coaxial (0), optical (1) */
+					/* S/PDIF input select*/
+
+/* MidiMan M-Audio Delta1010 */
+/* 0x01 = DFS */
+/* 0x02 = SPDIF_IN_STAT */
+/* 0x04 = SPDIF_OUT_STAT_CLOCK */
+/* 0x08 = SPDIF_OUT_STAT_DATA */
+#define ICE1712_DELTA_WORD_CLOCK_SELECT 0x10
+					/* 1 - clock are taken from S/PDIF input */
+					/* 0 - clock are taken from Word Clock input */
+					/* affected SPMCLKIN pin of Envy24 */
+#define ICE1712_DELTA_WORD_CLOCK_STATUS	0x20
+					/* 0 = valid word clock signal is present */
+
+/* MidiMan M-Audio Delta66 */
+/* 0x01 = DFS */
+/* 0x02 = SPDIF_IN_STAT */
+/* 0x04 = SPDIF_OUT_STAT_CLOCK */
+/* 0x08 = SPDIF_OUT_STAT_DATA */
+#define ICE1712_DELTA_CODEC_SERIAL_DATA 0x10
+					/* AKM4524 serial data */
+#define ICE1712_DELTA_CODEC_SERIAL_CLOCK 0x20
+					/* AKM4524 serial clock */
+					/* (writting on rising edge - 0->1 */
+#define ICE1712_DELTA_CODEC_CHIP_A	0x40
+#define ICE1712_DELTA_CODEC_CHIP_B	0x80
+					/* 1 - select chip A or B */
+
+/* MidiMan M-Audio Delta44 */
+/* 0x01 = DFS */
+/* 0x10 = CODEC_SERIAL_DATA */
+/* 0x20 = CODEC_SERIAL_CLOCK */
+/* 0x40 = CODEC_CHIP_A */
+/* 0x80 = CODEC_CHIP_B */
+
+/* MidiMan M-Audio Audiophile definitions */
+/* 0x01 = DFS */
+#define ICE1712_DELTA_AP_CCLK	0x02	/* SPI clock */
+					/* (clocking on rising edge - 0->1) */
+#define ICE1712_DELTA_AP_DIN	0x04	/* data input */
+#define ICE1712_DELTA_AP_DOUT	0x08	/* data output */
+#define ICE1712_DELTA_AP_CS_DIGITAL 0x10 /* CS8427 chip select */
+					/* low signal = select */
+#define ICE1712_DELTA_AP_CS_CODEC 0x20	/* AK4528 chip select */
+					/* low signal = select */
+
+
+#endif /* __SOUND_DELTA_H */
diff -Nru a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/ews.c	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,928 @@
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   Lowlevel functions for Terratec EWS88MT/D, EWX24/96, DMX 6Fire
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *                    2002 Takashi Iwai <tiwai@suse.de>
+ *
+ *   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 <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/cs8427.h>
+#include <sound/asoundef.h>
+
+#include "ice1712.h"
+#include "ews.h"
+
+#define SND_CS8404
+#include <sound/cs8403.h>
+
+/*
+ * access via i2c mode (for EWX 24/96, EWS 88MT&D)
+ */
+
+/* send SDA and SCL */
+static void ewx_i2c_setlines(snd_i2c_bus_t *bus, int clk, int data)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return);
+	unsigned char tmp = 0;
+	if (clk)
+		tmp |= ICE1712_EWX2496_SERIAL_CLOCK;
+	if (data)
+		tmp |= ICE1712_EWX2496_SERIAL_DATA;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+	udelay(5);
+}
+
+static int ewx_i2c_getclock(snd_i2c_bus_t *bus)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return -EIO);
+	return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ICE1712_EWX2496_SERIAL_CLOCK ? 1 : 0;
+}
+
+static int ewx_i2c_getdata(snd_i2c_bus_t *bus, int ack)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return -EIO);
+	int bit;
+	/* set RW pin to low */
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~ICE1712_EWX2496_RW);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, 0);
+	if (ack)
+		udelay(5);
+	bit = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ICE1712_EWX2496_SERIAL_DATA ? 1 : 0;
+	/* set RW pin to high */
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ICE1712_EWX2496_RW);
+	/* reset write mask */
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~ICE1712_EWX2496_SERIAL_CLOCK);
+	return bit;
+}
+
+static void ewx_i2c_start(snd_i2c_bus_t *bus)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return);
+	unsigned char mask;
+
+	snd_ice1712_save_gpio_status(ice, (unsigned char *)&bus->private_value);
+	/* set RW high */
+	mask = ICE1712_EWX2496_RW;
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_EWX2496:
+		mask |= ICE1712_EWX2496_AK4524_CS; /* CS high also */
+		break;
+	case ICE1712_SUBDEVICE_DMX6FIRE:
+		mask |= ICE1712_6FIRE_AK4524_CS_MASK; /* CS high also */
+		break;
+	}
+	snd_ice1712_gpio_write_bits(ice, mask, mask);
+}
+
+static void ewx_i2c_stop(snd_i2c_bus_t *bus)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return);
+	snd_ice1712_restore_gpio_status(ice, (unsigned char *)&bus->private_value);
+}
+
+static void ewx_i2c_direction(snd_i2c_bus_t *bus, int clock, int data)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, bus->private_data, return);
+	unsigned char mask = 0;
+
+	if (clock)
+		mask |= ICE1712_EWX2496_SERIAL_CLOCK; /* write SCL */
+	if (data)
+		mask |= ICE1712_EWX2496_SERIAL_DATA; /* write SDA */
+	ice->gpio_direction &= ~(ICE1712_EWX2496_SERIAL_CLOCK|ICE1712_EWX2496_SERIAL_DATA);
+	ice->gpio_direction |= mask;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio_direction);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~mask);
+}
+
+static snd_i2c_bit_ops_t snd_ice1712_ewx_cs8427_bit_ops = {
+	.start = ewx_i2c_start,
+	.stop = ewx_i2c_stop,
+	.direction = ewx_i2c_direction,
+	.setlines = ewx_i2c_setlines,
+	.getclock = ewx_i2c_getclock,
+	.getdata = ewx_i2c_getdata,
+};
+
+
+/*
+ * AK4524 access
+ */
+
+/* AK4524 chip select; address 0x48 bit 0-3 */
+static int snd_ice1712_ews88mt_chip_select(ice1712_t *ice, int chip_mask)
+{
+	unsigned char data, ndata;
+
+	snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL);
+	snd_i2c_lock(ice->i2c);
+	if (snd_i2c_readbytes(ice->i2cdevs[1], &data, 1) != 1)
+		goto __error;
+	ndata = (data & 0xf0) | chip_mask;
+	if (ndata != data)
+		if (snd_i2c_sendbytes(ice->i2cdevs[1], &ndata, 1) != 1)
+			goto __error;
+	snd_i2c_unlock(ice->i2c);
+	return 0;
+
+     __error:
+	snd_i2c_unlock(ice->i2c);
+	snd_printk(KERN_ERR "AK4524 chip select failed, check cable to the front module\n");
+	return -EIO;
+}
+
+/* start callback for EWS88MT, needs to select a certain chip mask */
+static int ews88mt_ak4524_start(ice1712_t *ice, unsigned char *saved, int chip)
+{
+	unsigned char tmp;
+	/* assert AK4524 CS */
+	if (snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f) < 0)
+		return -EINVAL;
+	snd_ice1712_save_gpio_status(ice, saved);
+	tmp = ICE1712_EWS88_SERIAL_DATA |
+		ICE1712_EWS88_SERIAL_CLOCK |
+		ICE1712_EWS88_RW;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
+			  ice->gpio_direction | tmp);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
+	return 0;
+}
+
+/* stop callback for EWS88MT, needs to deselect chip mask */
+static void ews88mt_ak4524_stop(ice1712_t *ice, unsigned char *saved)
+{
+	snd_ice1712_restore_gpio_status(ice, saved);
+	udelay(1);
+	snd_ice1712_ews88mt_chip_select(ice, 0x0f);
+}
+
+/* start callback for EWX24/96 */
+static int ewx2496_ak4524_start(ice1712_t *ice, unsigned char *saved, int chip)
+{
+	unsigned char tmp;
+	snd_ice1712_save_gpio_status(ice, saved);
+	tmp =  ICE1712_EWX2496_SERIAL_DATA |
+		ICE1712_EWX2496_SERIAL_CLOCK |
+		ICE1712_EWX2496_AK4524_CS |
+		ICE1712_EWX2496_RW;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
+			  ice->gpio_direction | tmp);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
+	return 0;
+}
+
+/* start callback for DMX 6fire */
+static int dmx6fire_ak4524_start(ice1712_t *ice, unsigned char *saved, int chip)
+{
+	unsigned char tmp;
+	snd_ice1712_save_gpio_status(ice, saved);
+	tmp = ice->ak4524.codecs_mask = (1 << chip) & ICE1712_6FIRE_AK4524_CS_MASK;
+	tmp |= ICE1712_6FIRE_SERIAL_DATA |
+		ICE1712_6FIRE_SERIAL_CLOCK |
+		ICE1712_6FIRE_RW;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,
+			  ice->gpio_direction | tmp);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);
+	return 0;
+}
+
+
+/*
+ * CS8404 interface on EWS88MT/D
+ */
+
+static void snd_ice1712_ews_cs8404_spdif_write(ice1712_t *ice, unsigned char bits)
+{
+	unsigned char bytes[2];
+
+	snd_i2c_lock(ice->i2c);
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_EWS88MT:
+		snd_runtime_check(snd_i2c_sendbytes(ice->cs8404, &bits, 1) == 1, snd_i2c_unlock(ice->i2c); return);
+		break;
+	case ICE1712_SUBDEVICE_EWS88D:
+		snd_runtime_check(snd_i2c_readbytes(ice->i2cdevs[0], bytes, 2) == 2, snd_i2c_unlock(ice->i2c); return);
+		if (bits != bytes[1]) {
+			bytes[1] = bits;
+			snd_runtime_check(snd_i2c_readbytes(ice->i2cdevs[0], bytes, 2) == 2, snd_i2c_unlock(ice->i2c); return);
+		}
+		break;
+	}
+	snd_i2c_unlock(ice->i2c);
+}
+
+/*
+ */
+
+static void ews88_spdif_default_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
+{
+	snd_cs8404_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_bits);
+}
+
+static int ews88_spdif_default_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	unsigned int val;
+	int change;
+
+	val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	change = ice->spdif.cs8403_bits != val;
+	ice->spdif.cs8403_bits = val;
+	if (change && ice->playback_pro_substream == NULL) {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		snd_ice1712_ews_cs8404_spdif_write(ice, val);
+	} else {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+	}
+	return change;
+}
+
+static void ews88_spdif_stream_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
+{
+	snd_cs8404_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_stream_bits);
+}
+
+static int ews88_spdif_stream_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	unsigned int val;
+	int change;
+
+	val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	change = ice->spdif.cs8403_stream_bits != val;
+	ice->spdif.cs8403_stream_bits = val;
+	if (change && ice->playback_pro_substream != NULL) {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		snd_ice1712_ews_cs8404_spdif_write(ice, val);
+	} else {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+	}
+	return change;
+}
+
+
+/* open callback */
+static void ews88_open_spdif(ice1712_t *ice, snd_pcm_substream_t * substream)
+{
+	ice->spdif.cs8403_stream_bits = ice->spdif.cs8403_bits;
+}
+
+/* set up SPDIF for EWS88MT / EWS88D */
+static void ews88_setup_spdif(ice1712_t *ice, snd_pcm_substream_t * substream)
+{
+	unsigned long flags;
+	unsigned char tmp;
+	int change;
+
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	tmp = ice->spdif.cs8403_stream_bits;
+	if (tmp & 0x10)		/* consumer */
+		tmp &= (tmp & 0x01) ? ~0x06 : ~0x60;
+	switch (substream->runtime->rate) {
+	case 32000: tmp |= (tmp & 0x01) ? 0x02 : 0x00; break;
+	case 44100: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;
+	case 48000: tmp |= (tmp & 0x01) ? 0x04 : 0x20; break;
+	default: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;
+	}
+	change = ice->spdif.cs8403_stream_bits != tmp;
+	ice->spdif.cs8403_stream_bits = tmp;
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	if (change)
+		snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &ice->spdif.stream_ctl->id);
+	snd_ice1712_ews_cs8404_spdif_write(ice, tmp);
+}
+
+
+/*
+ * initialize the chip
+ */
+
+static int __devinit snd_ice1712_ews_init(ice1712_t *ice)
+{
+	int err;
+
+	/* set the analog DACs */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_EWX2496:
+		ice->num_total_dacs = 2;
+		break;	
+	case ICE1712_SUBDEVICE_EWS88MT:
+		ice->num_total_dacs = 8;
+		break;
+	case ICE1712_SUBDEVICE_EWS88D:
+		break; /* no analog */
+	case ICE1712_SUBDEVICE_DMX6FIRE:
+		ice->num_total_dacs = 6;
+		break;
+	}
+
+	/* create i2c */
+	if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {
+		snd_printk("unable to create I2C bus\n");
+		return err;
+	}
+	ice->i2c->private_data = ice;
+	ice->i2c->hw_ops.bit = &snd_ice1712_ewx_cs8427_bit_ops;
+
+	/* create i2c devices */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_DMX6FIRE:
+		if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", ICE1712_6FIRE_PCF9554_ADDR, &ice->i2cdevs[0])) < 0) {
+			snd_printk("PCF9554 initialization failed\n");
+			return err;
+		}
+		break;
+	case ICE1712_SUBDEVICE_EWS88MT:
+		if ((err = snd_i2c_device_create(ice->i2c, "CS8404", ICE1712_EWS88MT_CS8404_ADDR, &ice->cs8404)) < 0)
+			return err;
+		if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)", ICE1712_EWS88MT_INPUT_ADDR, &ice->i2cdevs[0])) < 0)
+			return err;
+		if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (2nd)", ICE1712_EWS88MT_OUTPUT_ADDR, &ice->i2cdevs[1])) < 0)
+			return err;
+		/* Check if the front module is connected */
+		if ((err = snd_ice1712_ews88mt_chip_select(ice, 0x0f)) < 0)
+			return err;
+		break;
+	case ICE1712_SUBDEVICE_EWS88D:
+		if ((err = snd_i2c_device_create(ice->i2c, "PCF8575", ICE1712_EWS88D_PCF_ADDR, &ice->i2cdevs[0])) < 0)
+			return err;
+		break;
+	}
+
+	/* set up SPDIF interface */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_EWX2496:
+		if ((err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR)) < 0)
+			return err;
+		break;
+#if 0 // XXX not working...
+	case ICE1712_SUBDEVICE_DMX6FIRE:
+		if ((err = snd_ice1712_init_cs8427(ice, ICE1712_6FIRE_CS8427_ADDR)) < 0)
+			return err;
+#endif
+	case ICE1712_SUBDEVICE_EWS88MT:
+	case ICE1712_SUBDEVICE_EWS88D:
+		/* set up CS8404 */
+		ice->spdif.ops.open = ews88_open_spdif;
+		ice->spdif.ops.setup = ews88_setup_spdif;
+		ice->spdif.ops.default_get = ews88_spdif_default_get;
+		ice->spdif.ops.default_put = ews88_spdif_default_put;
+		ice->spdif.ops.stream_get = ews88_spdif_stream_get;
+		ice->spdif.ops.stream_put = ews88_spdif_stream_put;
+		/* Set spdif defaults */
+		snd_ice1712_ews_cs8404_spdif_write(ice, ice->spdif.cs8403_bits);
+		break;
+	}
+
+	/* analog section */
+	ak4524_t *ak = &ice->ak4524;
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_EWS88MT:
+		ak->num_adcs = ak->num_dacs = 8;
+		ak->cif = 1; /* CIF high */
+		ak->data_mask = ICE1712_EWS88_SERIAL_DATA;
+		ak->clk_mask = ICE1712_EWS88_SERIAL_CLOCK;
+		ak->codecs_mask = 0; /* no chip select on gpio */
+		ak->add_flags = ICE1712_EWS88_RW; /* set rw bit high */
+		ak->ops.start = ews88mt_ak4524_start;
+		ak->ops.stop = ews88mt_ak4524_stop;
+		snd_ice1712_ak4524_init(ice);
+		break;
+	case ICE1712_SUBDEVICE_EWX2496:
+		ak->num_adcs = ak->num_dacs = 2;
+		ak->cif = 1; /* CIF high */
+		ak->data_mask = ICE1712_EWS88_SERIAL_DATA;
+		ak->clk_mask = ICE1712_EWS88_SERIAL_CLOCK;
+		ak->codecs_mask = ICE1712_EWX2496_AK4524_CS;
+		ak->add_flags = ICE1712_EWS88_RW; /* set rw bit high */
+		ak->ops.start = ewx2496_ak4524_start;
+		snd_ice1712_ak4524_init(ice);
+		break;
+	case ICE1712_SUBDEVICE_DMX6FIRE:
+		ak->num_adcs = ak->num_dacs = 6;
+		ak->cif = 1; /* CIF high */
+		ak->data_mask = ICE1712_6FIRE_SERIAL_DATA;
+		ak->clk_mask = ICE1712_6FIRE_SERIAL_CLOCK;
+		ak->codecs_mask = 0; /* set later */
+		ak->add_flags = ICE1712_6FIRE_RW; /* set rw bit high */
+		ak->ops.start = dmx6fire_ak4524_start;
+		snd_ice1712_ak4524_init(ice);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * EWX 24/96 specific controls
+ */
+
+/* i/o sensitivity - this callback is shared among other devices, too */
+static int snd_ice1712_ewx_io_sense_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){
+
+	static char *texts[2] = {
+		"+4dBu", "-10dBV",
+	};
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item >= 2)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ice1712_ewx_io_sense_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char mask = kcontrol->private_value & 0xff;
+	unsigned char saved[2];
+	
+	snd_ice1712_save_gpio_status(ice, saved);
+	ucontrol->value.enumerated.item[0] = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & mask ? 1 : 0;
+	snd_ice1712_restore_gpio_status(ice, saved);
+	return 0;
+}
+
+static int snd_ice1712_ewx_io_sense_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char mask = kcontrol->private_value & 0xff;
+	unsigned char saved[2];
+	int val, nval;
+
+	if (kcontrol->private_value & (1 << 31))
+		return -EPERM;
+	nval = ucontrol->value.enumerated.item[0] ? mask : 0;
+	snd_ice1712_save_gpio_status(ice, saved);
+	val = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+	nval |= val & ~mask;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, nval);
+	snd_ice1712_restore_gpio_status(ice, saved);
+	return val != nval;
+}
+
+static snd_kcontrol_new_t snd_ice1712_ewx2496_controls[] __devinitdata = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Input Sensitivity Switch",
+		.info = snd_ice1712_ewx_io_sense_info,
+		.get = snd_ice1712_ewx_io_sense_get,
+		.put = snd_ice1712_ewx_io_sense_put,
+		.private_value = ICE1712_EWX2496_AIN_SEL,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Output Sensitivity Switch",
+		.info = snd_ice1712_ewx_io_sense_info,
+		.get = snd_ice1712_ewx_io_sense_get,
+		.put = snd_ice1712_ewx_io_sense_put,
+		.private_value = ICE1712_EWX2496_AOUT_SEL,
+	},
+};
+
+
+/*
+ * EWS88MT specific controls
+ */
+/* analog output sensitivity;; address 0x48 bit 6 */
+static int snd_ice1712_ews88mt_output_sense_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char data;
+
+	snd_i2c_lock(ice->i2c);
+	if (snd_i2c_readbytes(ice->i2cdevs[1], &data, 1) != 1) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	snd_i2c_unlock(ice->i2c);
+	ucontrol->value.enumerated.item[0] = data & ICE1712_EWS88MT_OUTPUT_SENSE ? 1 : 0; /* high = -10dBV, low = +4dBu */
+	return 0;
+}
+
+/* analog output sensitivity;; address 0x48 bit 6 */
+static int snd_ice1712_ews88mt_output_sense_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char data, ndata;
+
+	snd_i2c_lock(ice->i2c);
+	if (snd_i2c_readbytes(ice->i2cdevs[1], &data, 1) != 1) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	ndata = (data & ~ICE1712_EWS88MT_OUTPUT_SENSE) | (ucontrol->value.enumerated.item[0] ? ICE1712_EWS88MT_OUTPUT_SENSE : 0);
+	if (ndata != data && snd_i2c_sendbytes(ice->i2cdevs[1], &ndata, 1) != 1) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	snd_i2c_unlock(ice->i2c);
+	return ndata != data;
+}
+
+/* analog input sensitivity; address 0x46 */
+static int snd_ice1712_ews88mt_input_sense_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int channel = kcontrol->id.index;
+	unsigned char data;
+
+	snd_assert(channel >= 0 && channel <= 7, return 0);
+	snd_i2c_lock(ice->i2c);
+	if (snd_i2c_readbytes(ice->i2cdevs[0], &data, 1) != 1) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	/* reversed; high = +4dBu, low = -10dBV */
+	ucontrol->value.enumerated.item[0] = data & (1 << channel) ? 0 : 1;
+	return 0;
+}
+
+/* analog output sensitivity; address 0x46 */
+static int snd_ice1712_ews88mt_input_sense_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int channel = kcontrol->id.index;
+	unsigned char data, ndata;
+
+	snd_assert(channel >= 0 && channel <= 7, return 0);
+	snd_i2c_lock(ice->i2c);
+	if (snd_i2c_readbytes(ice->i2cdevs[0], &data, 1) != 1) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	ndata = (data & ~(1 << channel)) | (ucontrol->value.enumerated.item[0] ? 0 : (1 << channel));
+	if (ndata != data && snd_i2c_sendbytes(ice->i2cdevs[0], &ndata, 1) != 1) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	snd_i2c_unlock(ice->i2c);
+	return ndata != data;
+}
+
+static snd_kcontrol_new_t snd_ice1712_ews88mt_input_sense __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Input Sensitivity Switch",
+	.info = snd_ice1712_ewx_io_sense_info,
+	.get = snd_ice1712_ews88mt_input_sense_get,
+	.put = snd_ice1712_ews88mt_input_sense_put,
+};
+
+static snd_kcontrol_new_t snd_ice1712_ews88mt_output_sense __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Output Sensitivity Switch",
+	.info = snd_ice1712_ewx_io_sense_info,
+	.get = snd_ice1712_ews88mt_output_sense_get,
+	.put = snd_ice1712_ews88mt_output_sense_put,
+};
+
+
+/*
+ * EWS88D specific controls
+ */
+
+static int snd_ice1712_ews88d_control_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_ice1712_ews88d_control_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value & 0xff;
+	int invert = (kcontrol->private_value >> 8) & 1;
+	unsigned char data[2];
+	
+	snd_i2c_lock(ice->i2c);
+	if (snd_i2c_readbytes(ice->i2cdevs[0], data, 2) != 2) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	snd_i2c_unlock(ice->i2c);
+	data[0] = (data[shift >> 3] >> (shift & 7)) & 0x01;
+	if (invert)
+		data[0] ^= 0x01;
+	ucontrol->value.integer.value[0] = data[0];
+	return 0;
+}
+
+static int snd_ice1712_ews88d_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value & 0xff;
+	int invert = (kcontrol->private_value >> 8) & 1;
+	unsigned char data[2], ndata[2];
+	int change;
+
+	snd_i2c_lock(ice->i2c);
+	if (snd_i2c_readbytes(ice->i2cdevs[0], data, 2) != 2) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	ndata[shift >> 3] = data[shift >> 3] & ~(1 << (shift & 7));
+	if (invert) {
+		if (! ucontrol->value.integer.value[0])
+			ndata[shift >> 3] |= (1 << (shift & 7));
+	} else {
+		if (ucontrol->value.integer.value[0])
+			ndata[shift >> 3] |= (1 << (shift & 7));
+	}
+	change = (data[shift >> 3] != ndata[shift >> 3]);
+	if (change && snd_i2c_sendbytes(ice->i2cdevs[0], data, 2) != 2) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	snd_i2c_unlock(ice->i2c);
+	return change;
+}
+
+#define EWS88D_CONTROL(xiface, xname, xshift, xinvert, xaccess) \
+{ .iface = xiface,\
+  .name = xname,\
+  .access = xaccess,\
+  .info = snd_ice1712_ews88d_control_info,\
+  .get = snd_ice1712_ews88d_control_get,\
+  .put = snd_ice1712_ews88d_control_put,\
+  .private_value = xshift | (xinvert << 8),\
+}
+
+static snd_kcontrol_new_t snd_ice1712_ews88d_controls[] __devinitdata = {
+	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */
+	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0),
+	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0),
+	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "Enable ADAT", 3, 0, 0),
+	EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Through", 4, 1, 0),
+};
+
+
+/*
+ * DMX 6Fire specific controls
+ */
+
+#define PCF9554_REG_INPUT	0
+#define PCF9554_REG_OUTPUT	1
+#define PCF9554_REG_POLARITY	2
+#define PCF9554_REG_CONFIG	3
+
+static int snd_ice1712_6fire_read_pca(ice1712_t *ice, unsigned char reg)
+{
+	unsigned char byte;
+	snd_i2c_lock(ice->i2c);
+	byte = reg;
+	snd_i2c_sendbytes(ice->i2cdevs[0], &byte, 1);
+	byte = 0;
+	if (snd_i2c_readbytes(ice->i2cdevs[0], &byte, 1) != 1) {
+		snd_i2c_unlock(ice->i2c);
+		printk("cannot read pca\n");
+		return -EIO;
+	}
+	snd_i2c_unlock(ice->i2c);
+	return byte;
+}
+
+static int snd_ice1712_6fire_write_pca(ice1712_t *ice, unsigned char reg, unsigned char data)
+{
+	unsigned char bytes[2];
+	snd_i2c_lock(ice->i2c);
+	bytes[0] = reg;
+	bytes[1] = data;
+	if (snd_i2c_sendbytes(ice->i2cdevs[0], bytes, 2) != 2) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	snd_i2c_unlock(ice->i2c);
+	return 0;
+}
+
+static int snd_ice1712_6fire_control_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_ice1712_6fire_control_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value & 0xff;
+	int invert = (kcontrol->private_value >> 8) & 1;
+	int data;
+	
+	if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
+		return data;
+	data = (data >> shift) & 1;
+	if (invert)
+		data ^= 1;
+	ucontrol->value.integer.value[0] = data;
+	return 0;
+}
+
+static int snd_ice1712_6fire_control_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int shift = kcontrol->private_value & 0xff;
+	int invert = (kcontrol->private_value >> 8) & 1;
+	int data, ndata;
+	
+	if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
+		return data;
+	ndata = data & ~(1 << shift);
+	if (ucontrol->value.integer.value[0])
+		ndata |= (1 << shift);
+	if (invert)
+		ndata ^= (1 << shift);
+	if (data != ndata) {
+		snd_ice1712_6fire_write_pca(ice, PCF9554_REG_OUTPUT, (unsigned char)ndata);
+		return 1;
+	}
+	return 0;
+}
+
+static int snd_ice1712_6fire_select_input_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[4] = {
+		"Internal", "Front Input", "Rear Input", "Wave Table"
+	};
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 4;
+	if (uinfo->value.enumerated.item >= 4)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+     
+static int snd_ice1712_6fire_select_input_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int data;
+	
+	if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
+		return data;
+	ucontrol->value.integer.value[0] = data & 3;
+	return 0;
+}
+
+static int snd_ice1712_6fire_select_input_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int data, ndata;
+	
+	if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
+		return data;
+	ndata = data & ~3;
+	ndata |= (ucontrol->value.integer.value[0] & 3);
+	if (data != ndata) {
+		snd_ice1712_6fire_write_pca(ice, PCF9554_REG_OUTPUT, (unsigned char)ndata);
+		return 1;
+	}
+	return 0;
+}
+
+
+#define DMX6FIRE_CONTROL(xname, xshift, xinvert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
+  .name = xname,\
+  .info = snd_ice1712_6fire_control_info,\
+  .get = snd_ice1712_6fire_control_get,\
+  .put = snd_ice1712_6fire_control_put,\
+  .private_value = xshift | (xinvert << 8),\
+}
+
+static snd_kcontrol_new_t snd_ice1712_6fire_controls[] __devinitdata = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Analog Input Select",
+		.info = snd_ice1712_6fire_select_input_info,
+		.get = snd_ice1712_6fire_select_input_get,
+		.put = snd_ice1712_6fire_select_input_put,
+	},
+	DMX6FIRE_CONTROL("Front Digital Input Switch", 2, 0),
+	// DMX6FIRE_CONTROL("Master Clock Select", 3, 0),
+	DMX6FIRE_CONTROL("Optical Digital Input Switch", 4, 0),
+	DMX6FIRE_CONTROL("Phono Analog Input Switch", 5, 0),
+	DMX6FIRE_CONTROL("Breakbox LED", 6, 0),
+};
+
+
+static int __devinit snd_ice1712_ews_add_controls(ice1712_t *ice)
+{
+	int err, idx;
+	snd_kcontrol_t *kctl;
+	
+	/* all terratec cards have spdif */
+	err = snd_ice1712_spdif_build_controls(ice);
+	if (err < 0)
+		return err;
+
+	/* ak4524 controls */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_EWX2496:
+	case ICE1712_SUBDEVICE_EWS88MT:
+	case ICE1712_SUBDEVICE_DMX6FIRE:
+		err = snd_ice1712_ak4524_build_controls(ice);
+		if (err < 0)
+			return err;
+		break;
+	}
+
+	/* card specific controls */
+	switch (ice->eeprom.subvendor) {
+	case ICE1712_SUBDEVICE_EWX2496:
+		for (idx = 0; idx < sizeof(snd_ice1712_ewx2496_controls)/sizeof(snd_ice1712_ewx2496_controls[0]); idx++) {
+			err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ewx2496_controls[idx], ice));
+			if (err < 0)
+				return err;
+		}
+		break;
+	case ICE1712_SUBDEVICE_EWS88MT:
+		for (idx = 0; idx < 8; idx++) {
+			kctl = snd_ctl_new1(&snd_ice1712_ews88mt_input_sense, ice);
+			kctl->id.index = idx;
+			err = snd_ctl_add(ice->card, kctl);
+			if (err < 0)
+				return err;
+		}
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ews88mt_output_sense, ice));
+		if (err < 0)
+			return err;
+		break;
+	case ICE1712_SUBDEVICE_EWS88D:
+		for (idx = 0; idx < sizeof(snd_ice1712_ews88d_controls)/sizeof(snd_ice1712_ews88d_controls[0]); idx++) {
+			err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ews88d_controls[idx], ice));
+			if (err < 0)
+				return err;
+		}
+		break;
+	case ICE1712_SUBDEVICE_DMX6FIRE:
+		for (idx = 0; idx < sizeof(snd_ice1712_6fire_controls)/sizeof(snd_ice1712_6fire_controls[0]); idx++) {
+			err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_6fire_controls[idx], ice));
+			if (err < 0)
+				return err;
+		}
+		break;
+	}
+	return 0;
+}
+
+
+/* entry point */
+struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = {
+	{
+		ICE1712_SUBDEVICE_EWX2496,
+		"TerraTec EWX 24/96",
+		snd_ice1712_ews_init,
+		snd_ice1712_ews_add_controls,
+	},
+	{
+		ICE1712_SUBDEVICE_EWS88MT,
+		"TerraTec EWS 88MT",
+		snd_ice1712_ews_init,
+		snd_ice1712_ews_add_controls,
+	},
+	{
+		ICE1712_SUBDEVICE_EWS88D,
+		"TerraTec EWS 88D",
+		snd_ice1712_ews_init,
+		snd_ice1712_ews_add_controls,
+	},
+	{
+		ICE1712_SUBDEVICE_DMX6FIRE,
+		"TerraTec DMX 6Fire",
+		snd_ice1712_ews_init,
+		snd_ice1712_ews_add_controls,
+	},
+	{ } /* terminator */
+};
diff -Nru a/sound/pci/ice1712/ews.h b/sound/pci/ice1712/ews.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/ews.h	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,81 @@
+#ifndef __SOUND_EWS_H
+#define __SOUND_EWS_H
+
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   Lowlevel functions for Terratec EWS88MT/D, EWX24/96, DMX 6Fire
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *                    2002 Takashi Iwai <tiwai@suse.de>
+ *
+ *   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
+ *
+ */      
+
+#define EWS_DEVICE_DESC \
+		"{TerraTec,EWX 24/96},"\
+		"{TerraTec,EWS 88MT},"\
+		"{TerraTec,EWS 88D},"\
+		"{TerraTec,DMX 6Fire},"
+
+#define ICE1712_SUBDEVICE_EWX2496	0x3b153011
+#define ICE1712_SUBDEVICE_EWS88MT	0x3b151511
+#define ICE1712_SUBDEVICE_EWS88D	0x3b152b11
+#define ICE1712_SUBDEVICE_DMX6FIRE	0x3b153811
+
+/* entry point */
+extern struct snd_ice1712_card_info snd_ice1712_ews_cards[];
+
+
+/* TerraTec EWX 24/96 configuration definitions */
+
+#define ICE1712_EWX2496_AK4524_CS	0x01	/* AK4524 chip select; low = active */
+#define ICE1712_EWX2496_AIN_SEL		0x02	/* input sensitivity switch; high = louder */
+#define ICE1712_EWX2496_AOUT_SEL	0x04	/* output sensitivity switch; high = louder */
+#define ICE1712_EWX2496_RW		0x08	/* read/write switch for i2c; high = write  */
+#define ICE1712_EWX2496_SERIAL_DATA	0x10	/* i2c & ak4524 data */
+#define ICE1712_EWX2496_SERIAL_CLOCK	0x20	/* i2c & ak4524 clock */
+#define ICE1712_EWX2496_TX2		0x40	/* MIDI2 (not used) */
+#define ICE1712_EWX2496_RX2		0x80	/* MIDI2 (not used) */
+
+/* TerraTec EWS 88MT/D configuration definitions */
+/* RW, SDA snd SCLK are identical with EWX24/96 */
+#define ICE1712_EWS88_CS8414_RATE	0x07	/* CS8414 sample rate: gpio 0-2 */
+#define ICE1712_EWS88_RW		0x08	/* read/write switch for i2c; high = write  */
+#define ICE1712_EWS88_SERIAL_DATA	0x10	/* i2c & ak4524 data */
+#define ICE1712_EWS88_SERIAL_CLOCK	0x20	/* i2c & ak4524 clock */
+#define ICE1712_EWS88_TX2		0x40	/* MIDI2 (only on 88D) */
+#define ICE1712_EWS88_RX2		0x80	/* MIDI2 (only on 88D) */
+
+/* i2c address */
+#define ICE1712_EWS88MT_CS8404_ADDR	(0x40>>1)
+#define ICE1712_EWS88MT_INPUT_ADDR	(0x46>>1)
+#define ICE1712_EWS88MT_OUTPUT_ADDR	(0x48>>1)
+#define ICE1712_EWS88MT_OUTPUT_SENSE	0x40	/* mask */
+#define ICE1712_EWS88D_PCF_ADDR		(0x40>>1)
+
+/* TerraTec DMX 6Fire configuration definitions */
+#define ICE1712_6FIRE_AK4524_CS_MASK	0x07	/* AK4524 chip select #1-#3 */
+#define ICE1712_6FIRE_RW		0x08	/* read/write switch for i2c; high = write  */
+#define ICE1712_6FIRE_SERIAL_DATA	0x10	/* i2c & ak4524 data */
+#define ICE1712_6FIRE_SERIAL_CLOCK	0x20	/* i2c & ak4524 clock */
+#define ICE1712_6FIRE_TX2		0x40	/* MIDI2 */
+#define ICE1712_6FIRE_RX2		0x80	/* MIDI2 */
+
+#define ICE1712_6FIRE_PCF9554_ADDR	(0x40>>1)
+#define ICE1712_6FIRE_CS8427_ADDR	(0x22>>1)
+
+#endif /* __SOUND_EWS_H */
diff -Nru a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/hoontech.c	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,223 @@
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   Lowlevel functions for Hoontech STDSP24
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *
+ *   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 <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "hoontech.h"
+
+
+static void __devinit snd_ice1712_stdsp24_gpio_write(ice1712_t *ice, unsigned char byte)
+{
+	byte |= ICE1712_STDSP24_CLOCK_BIT;
+	udelay(100);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte);
+	byte &= ~ICE1712_STDSP24_CLOCK_BIT;
+	udelay(100);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte);
+	byte |= ICE1712_STDSP24_CLOCK_BIT;
+	udelay(100);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte);
+}
+
+static void __devinit snd_ice1712_stdsp24_darear(ice1712_t *ice, int activate)
+{
+	down(&ice->gpio_mutex);
+	ICE1712_STDSP24_0_DAREAR(ice->hoontech_boxbits, activate);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[0]);
+	up(&ice->gpio_mutex);
+}
+
+static void __devinit snd_ice1712_stdsp24_mute(ice1712_t *ice, int activate)
+{
+	down(&ice->gpio_mutex);
+	ICE1712_STDSP24_3_MUTE(ice->hoontech_boxbits, activate);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[3]);
+	up(&ice->gpio_mutex);
+}
+
+static void __devinit snd_ice1712_stdsp24_insel(ice1712_t *ice, int activate)
+{
+	down(&ice->gpio_mutex);
+	ICE1712_STDSP24_3_INSEL(ice->hoontech_boxbits, activate);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[3]);
+	up(&ice->gpio_mutex);
+}
+
+static void __devinit snd_ice1712_stdsp24_box_channel(ice1712_t *ice, int box, int chn, int activate)
+{
+	down(&ice->gpio_mutex);
+
+	/* select box */
+	ICE1712_STDSP24_0_BOX(ice->hoontech_boxbits, box);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[0]);
+
+	/* prepare for write */
+	if (chn == 3)
+		ICE1712_STDSP24_2_CHN4(ice->hoontech_boxbits, 0);
+	ICE1712_STDSP24_2_MIDI1(ice->hoontech_boxbits, activate);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+
+	ICE1712_STDSP24_1_CHN1(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_1_CHN2(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_1_CHN3(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_2_CHN4(ice->hoontech_boxbits, 1);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[1]);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+	udelay(100);
+	if (chn == 3) {
+		ICE1712_STDSP24_2_CHN4(ice->hoontech_boxbits, 0);
+		snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+	} else {
+		switch (chn) {
+		case 0:	ICE1712_STDSP24_1_CHN1(ice->hoontech_boxbits, 0); break;
+		case 1:	ICE1712_STDSP24_1_CHN2(ice->hoontech_boxbits, 0); break;
+		case 2:	ICE1712_STDSP24_1_CHN3(ice->hoontech_boxbits, 0); break;
+		}
+		snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[1]);
+	}
+	udelay(100);
+	ICE1712_STDSP24_1_CHN1(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_1_CHN2(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_1_CHN3(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_2_CHN4(ice->hoontech_boxbits, 1);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[1]);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+	udelay(100);
+
+	ICE1712_STDSP24_2_MIDI1(ice->hoontech_boxbits, 0);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+
+	up(&ice->gpio_mutex);
+}
+
+static void __devinit snd_ice1712_stdsp24_box_midi(ice1712_t *ice, int box, int master, int slave)
+{
+	down(&ice->gpio_mutex);
+
+	/* select box */
+	ICE1712_STDSP24_0_BOX(ice->hoontech_boxbits, box);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[0]);
+
+	ICE1712_STDSP24_2_MIDIIN(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_2_MIDI1(ice->hoontech_boxbits, master);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+
+	udelay(100);
+	
+	ICE1712_STDSP24_2_MIDIIN(ice->hoontech_boxbits, 0);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+	
+	udelay(100);
+	
+	ICE1712_STDSP24_2_MIDIIN(ice->hoontech_boxbits, 1);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[2]);
+
+	udelay(100);
+
+	/* MIDI2 is direct */
+	ICE1712_STDSP24_3_MIDI2(ice->hoontech_boxbits, slave);
+	snd_ice1712_stdsp24_gpio_write(ice, ice->hoontech_boxbits[3]);
+
+	up(&ice->gpio_mutex);
+}
+
+static int __devinit snd_ice1712_hoontech_init(ice1712_t *ice)
+{
+	int box, chn;
+
+	ice->num_total_dacs = 8;
+
+	ice->hoontech_boxbits[0] = 
+	ice->hoontech_boxbits[1] = 
+	ice->hoontech_boxbits[2] = 
+	ice->hoontech_boxbits[3] = 0;	/* should be already */
+
+	ICE1712_STDSP24_SET_ADDR(ice->hoontech_boxbits, 0);
+	ICE1712_STDSP24_CLOCK(ice->hoontech_boxbits, 0, 1);
+	ICE1712_STDSP24_0_BOX(ice->hoontech_boxbits, 0);
+	ICE1712_STDSP24_0_DAREAR(ice->hoontech_boxbits, 0);
+
+	ICE1712_STDSP24_SET_ADDR(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_CLOCK(ice->hoontech_boxbits, 1, 1);
+	ICE1712_STDSP24_1_CHN1(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_1_CHN2(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_1_CHN3(ice->hoontech_boxbits, 1);
+	
+	ICE1712_STDSP24_SET_ADDR(ice->hoontech_boxbits, 2);
+	ICE1712_STDSP24_CLOCK(ice->hoontech_boxbits, 2, 1);
+	ICE1712_STDSP24_2_CHN4(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_2_MIDIIN(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_2_MIDI1(ice->hoontech_boxbits, 0);
+
+	ICE1712_STDSP24_SET_ADDR(ice->hoontech_boxbits, 3);
+	ICE1712_STDSP24_CLOCK(ice->hoontech_boxbits, 3, 1);
+	ICE1712_STDSP24_3_MIDI2(ice->hoontech_boxbits, 0);
+	ICE1712_STDSP24_3_MUTE(ice->hoontech_boxbits, 1);
+	ICE1712_STDSP24_3_INSEL(ice->hoontech_boxbits, 0);
+
+	/* let's go - activate only functions in first box */
+	ice->hoontech_config = 0;
+			    /* ICE1712_STDSP24_MUTE |
+			       ICE1712_STDSP24_INSEL |
+			       ICE1712_STDSP24_DAREAR; */
+	ice->hoontech_boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 |
+				     ICE1712_STDSP24_BOX_CHN2 |
+				     ICE1712_STDSP24_BOX_CHN3 |
+				     ICE1712_STDSP24_BOX_CHN4 |
+				     ICE1712_STDSP24_BOX_MIDI1 |
+				     ICE1712_STDSP24_BOX_MIDI2;
+	ice->hoontech_boxconfig[1] = 
+	ice->hoontech_boxconfig[2] = 
+	ice->hoontech_boxconfig[3] = 0;
+	snd_ice1712_stdsp24_darear(ice, (ice->hoontech_config & ICE1712_STDSP24_DAREAR) ? 1 : 0);
+	snd_ice1712_stdsp24_mute(ice, (ice->hoontech_config & ICE1712_STDSP24_MUTE) ? 1 : 0);
+	snd_ice1712_stdsp24_insel(ice, (ice->hoontech_config & ICE1712_STDSP24_INSEL) ? 1 : 0);
+	for (box = 0; box < 4; box++) {
+		for (chn = 0; chn < 4; chn++)
+			snd_ice1712_stdsp24_box_channel(ice, box, chn, (ice->hoontech_boxconfig[box] & (1 << chn)) ? 1 : 0);
+		snd_ice1712_stdsp24_box_midi(ice, box,
+				(ice->hoontech_boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0,
+				(ice->hoontech_boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) ? 1 : 0);
+	}
+
+	return 0;
+}
+
+
+/* entry point */
+struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = {
+	{
+		ICE1712_SUBDEVICE_STDSP24,
+		"Hoontech SoundTrack Audio DSP24",
+		snd_ice1712_hoontech_init,
+	},
+	{ } /* terminator */
+};
+
diff -Nru a/sound/pci/ice1712/hoontech.h b/sound/pci/ice1712/hoontech.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/hoontech.h	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,64 @@
+#ifndef __SOUND_HOONTECH_H
+#define __SOUND_HOONTECH_H
+
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *   Lowlevel functions for Hoontech STDSP24
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *
+ *   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
+ *
+ */      
+
+#define  HOONTECH_DEVICE_DESC 	       "{Hoontech SoundTrack DSP 24},"
+
+#define ICE1712_SUBDEVICE_STDSP24	0x12141217	/* Hoontech SoundTrack Audio DSP 24 */
+
+extern struct snd_ice1712_card_info snd_ice1712_hoontech_cards[];
+
+
+/* Hoontech SoundTrack Audio DSP 24 GPIO definitions */
+
+#define ICE1712_STDSP24_0_BOX(r, x)	r[0] = ((r[0] & ~3) | ((x)&3))
+#define ICE1712_STDSP24_0_DAREAR(r, x)	r[0] = ((r[0] & ~4) | (((x)&1)<<2))
+#define ICE1712_STDSP24_1_CHN1(r, x)	r[1] = ((r[1] & ~1) | ((x)&1))
+#define ICE1712_STDSP24_1_CHN2(r, x)	r[1] = ((r[1] & ~2) | (((x)&1)<<1))
+#define ICE1712_STDSP24_1_CHN3(r, x)	r[1] = ((r[1] & ~4) | (((x)&1)<<2))
+#define ICE1712_STDSP24_2_CHN4(r, x)	r[2] = ((r[2] & ~1) | ((x)&1))
+#define ICE1712_STDSP24_2_MIDIIN(r, x)	r[2] = ((r[2] & ~2) | (((x)&1)<<1))
+#define ICE1712_STDSP24_2_MIDI1(r, x)	r[2] = ((r[2] & ~4) | (((x)&1)<<2))
+#define ICE1712_STDSP24_3_MIDI2(r, x)	r[3] = ((r[3] & ~1) | ((x)&1))
+#define ICE1712_STDSP24_3_MUTE(r, x)	r[3] = ((r[3] & ~2) | (((x)&1)<<1))
+#define ICE1712_STDSP24_3_INSEL(r, x)	r[3] = ((r[3] & ~4) | (((x)&1)<<2))
+#define ICE1712_STDSP24_SET_ADDR(r, a)	r[a&3] = ((r[a&3] & ~0x18) | (((a)&3)<<3))
+#define ICE1712_STDSP24_CLOCK(r, a, c)	r[a&3] = ((r[a&3] & ~0x20) | (((c)&1)<<5))
+#define ICE1712_STDSP24_CLOCK_BIT	(1<<5)
+
+/* Hoontech SoundTrack Audio DSP 24 box configuration definitions */
+
+#define ICE1712_STDSP24_DAREAR		(1<<0)
+#define ICE1712_STDSP24_MUTE		(1<<1)
+#define ICE1712_STDSP24_INSEL		(1<<2)
+
+#define ICE1712_STDSP24_BOX_CHN1	(1<<0)	/* input channel 1 */
+#define ICE1712_STDSP24_BOX_CHN2	(1<<1)	/* input channel 2 */
+#define ICE1712_STDSP24_BOX_CHN3	(1<<2)	/* input channel 3 */
+#define ICE1712_STDSP24_BOX_CHN4	(1<<3)	/* input channel 4 */
+#define ICE1712_STDSP24_BOX_MIDI1	(1<<8)
+#define ICE1712_STDSP24_BOX_MIDI2	(1<<9)
+
+#endif /* __SOUND_HOONTECH_H */
diff -Nru a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/ice1712.c	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,2477 @@
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *
+ *   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
+ *
+ */      
+
+/*
+  NOTES:
+  - spdif nonaudio consumer mode does not work (at least with my
+    Sony STR-DB830)
+*/
+
+/*
+ * Changes:
+ *
+ *  2002.09.09	Takashi Iwai <tiwai@suse.de>
+ *	split the code to several files.  each low-level routine
+ *	is stored in the local file and called from registration
+ *	function from card_info struct.
+ */
+
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/cs8427.h>
+#include <sound/info.h>
+#include <sound/mpu401.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+#include <sound/asoundef.h>
+
+#include "ice1712.h"
+
+/* lowlevel routines */
+#include "delta.h"
+#include "ews.h"
+#include "hoontech.h"
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("ICEnsemble ICE1712 (Envy24)");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{"
+	       HOONTECH_DEVICE_DESC
+	       DELTA_DEVICE_DESC
+	       EWS_DEVICE_DESC
+		"{ICEnsemble,Generic ICE1712},"
+		"{ICEnsemble,Generic Envy24}}");
+
+static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;		/* Enable this card */
+static int snd_omni[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};	/* Delta44 & 66 Omni I/O support */
+
+MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_index, "Index value for ICE1712 soundcard.");
+MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
+MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(snd_id, "ID string for ICE1712 soundcard.");
+MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
+MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_enable, "Enable ICE1712 soundcard.");
+MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
+MODULE_PARM(snd_omni, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_omni, "Enable Midiman M-Audio Delta Omni I/O support.");
+MODULE_PARM_SYNTAX(snd_omni, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
+
+#ifndef PCI_VENDOR_ID_ICE
+#define PCI_VENDOR_ID_ICE		0x1412
+#endif
+#ifndef PCI_DEVICE_ID_ICE_1712
+#define PCI_DEVICE_ID_ICE_1712		0x1712
+#endif
+
+static struct pci_device_id snd_ice1712_ids[] __devinitdata = {
+	{ PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* ICE1712 */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_ice1712_ids);
+
+static int snd_ice1712_build_pro_mixer(ice1712_t *ice);
+static int snd_ice1712_build_controls(ice1712_t *ice);
+
+/*
+ *  Basic I/O
+ */
+ 
+static inline void snd_ice1712_ds_write(ice1712_t * ice, u8 channel, u8 addr, u32 data)
+{
+	outb((channel << 4) | addr, ICEDS(ice, INDEX));
+	outl(data, ICEDS(ice, DATA));
+}
+
+static inline u32 snd_ice1712_ds_read(ice1712_t * ice, u8 channel, u8 addr)
+{
+	outb((channel << 4) | addr, ICEDS(ice, INDEX));
+	return inl(ICEDS(ice, DATA));
+}
+
+static void snd_ice1712_ac97_write(ac97_t *ac97,
+				   unsigned short reg,
+				   unsigned short val)
+{
+	ice1712_t *ice = (ice1712_t *)ac97->private_data;
+	int tm;
+	unsigned char old_cmd = 0;
+
+	for (tm = 0; tm < 0x10000; tm++) {
+		old_cmd = inb(ICEREG(ice, AC97_CMD));
+		if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ))
+			continue;
+		if (!(old_cmd & ICE1712_AC97_READY))
+			continue;
+		break;
+	}
+	outb(reg, ICEREG(ice, AC97_INDEX));
+	outw(val, ICEREG(ice, AC97_DATA));
+	old_cmd &= ~(ICE1712_AC97_PBK_VSR | ICE1712_AC97_CAP_VSR);
+	outb(old_cmd | ICE1712_AC97_WRITE, ICEREG(ice, AC97_CMD));
+	for (tm = 0; tm < 0x10000; tm++)
+		if ((inb(ICEREG(ice, AC97_CMD)) & ICE1712_AC97_WRITE) == 0)
+			break;
+}
+
+static unsigned short snd_ice1712_ac97_read(ac97_t *ac97,
+					    unsigned short reg)
+{
+	ice1712_t *ice = (ice1712_t *)ac97->private_data;
+	int tm;
+	unsigned char old_cmd = 0;
+
+	for (tm = 0; tm < 0x10000; tm++) {
+		old_cmd = inb(ICEREG(ice, AC97_CMD));
+		if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ))
+			continue;
+		if (!(old_cmd & ICE1712_AC97_READY))
+			continue;
+		break;
+	}
+	outb(reg, ICEREG(ice, AC97_INDEX));
+	outb(old_cmd | ICE1712_AC97_READ, ICEREG(ice, AC97_CMD));
+	for (tm = 0; tm < 0x10000; tm++)
+		if ((inb(ICEREG(ice, AC97_CMD)) & ICE1712_AC97_READ) == 0)
+			break;
+	if (tm >= 0x10000)		/* timeout */
+		return ~0;
+	return inw(ICEREG(ice, AC97_DATA));
+}
+
+/*
+ * pro ac97 section
+ */
+
+static void snd_ice1712_pro_ac97_write(ac97_t *ac97,
+				       unsigned short reg,
+				       unsigned short val)
+{
+	ice1712_t *ice = (ice1712_t *)ac97->private_data;
+	int tm;
+	unsigned char old_cmd = 0;
+
+	for (tm = 0; tm < 0x10000; tm++) {
+		old_cmd = inb(ICEMT(ice, AC97_CMD));
+		if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ))
+			continue;
+		if (!(old_cmd & ICE1712_AC97_READY))
+			continue;
+		break;
+	}
+	outb(reg, ICEMT(ice, AC97_INDEX));
+	outw(val, ICEMT(ice, AC97_DATA));
+	old_cmd &= ~(ICE1712_AC97_PBK_VSR | ICE1712_AC97_CAP_VSR);
+	outb(old_cmd | ICE1712_AC97_WRITE, ICEMT(ice, AC97_CMD));
+	for (tm = 0; tm < 0x10000; tm++)
+		if ((inb(ICEMT(ice, AC97_CMD)) & ICE1712_AC97_WRITE) == 0)
+			break;
+}
+
+
+static unsigned short snd_ice1712_pro_ac97_read(ac97_t *ac97,
+						unsigned short reg)
+{
+	ice1712_t *ice = (ice1712_t *)ac97->private_data;
+	int tm;
+	unsigned char old_cmd = 0;
+
+	for (tm = 0; tm < 0x10000; tm++) {
+		old_cmd = inb(ICEMT(ice, AC97_CMD));
+		if (old_cmd & (ICE1712_AC97_WRITE | ICE1712_AC97_READ))
+			continue;
+		if (!(old_cmd & ICE1712_AC97_READY))
+			continue;
+		break;
+	}
+	outb(reg, ICEMT(ice, AC97_INDEX));
+	outb(old_cmd | ICE1712_AC97_READ, ICEMT(ice, AC97_CMD));
+	for (tm = 0; tm < 0x10000; tm++)
+		if ((inb(ICEMT(ice, AC97_CMD)) & ICE1712_AC97_READ) == 0)
+			break;
+	if (tm >= 0x10000)		/* timeout */
+		return ~0;
+	return inw(ICEMT(ice, AC97_DATA));
+}
+
+static int snd_ice1712_digmix_route_ac97_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_ice1712_digmix_route_ac97_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_ROUTECTRL)) & ICE1712_ROUTE_AC97 ? 1 : 0;
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static int snd_ice1712_digmix_route_ac97_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char val, nval;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	val = inb(ICEMT(ice, MONITOR_ROUTECTRL));
+	nval = val & ~ICE1712_ROUTE_AC97;
+	if (ucontrol->value.integer.value[0]) nval |= ICE1712_ROUTE_AC97;
+	outb(nval, ICEMT(ice, MONITOR_ROUTECTRL));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return val != nval;
+}
+
+static snd_kcontrol_new_t snd_ice1712_mixer_digmix_route_ac97 __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Digital Mixer To AC97",
+	.info = snd_ice1712_digmix_route_ac97_info,
+	.get = snd_ice1712_digmix_route_ac97_get,
+	.put = snd_ice1712_digmix_route_ac97_put,
+};
+
+
+
+/*
+ * set gpio direction, write mask and data
+ */
+void snd_ice1712_gpio_write_bits(ice1712_t *ice, int mask, int bits)
+{
+	ice->gpio_direction |= mask;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio_direction);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~mask);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, mask & bits);
+}
+
+/*
+ */
+void snd_ice1712_save_gpio_status(ice1712_t *ice, unsigned char *tmp)
+{
+	down(&ice->gpio_mutex);
+	tmp[0] = ice->gpio_direction;
+	tmp[1] = ice->gpio_write_mask;
+}
+
+void snd_ice1712_restore_gpio_status(ice1712_t *ice, unsigned char *tmp)
+{
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, tmp[0]);
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, tmp[1]);
+	ice->gpio_direction = tmp[0];
+	ice->gpio_write_mask = tmp[1];
+	up(&ice->gpio_mutex);
+}
+
+
+/*
+ *
+ * CS8427 interface
+ *
+ */
+
+/*
+ * change the input clock selection
+ * spdif_clock = 1 - IEC958 input, 0 - Envy24
+ */
+static int snd_ice1712_cs8427_set_input_clock(ice1712_t *ice, int spdif_clock)
+{
+	unsigned char reg[2] = { 0x80 | 4, 0 };   /* CS8427 auto increment | register number 4 + data */
+	unsigned char val, nval;
+	int res = 0;
+	
+	snd_i2c_lock(ice->i2c);
+	if (snd_i2c_sendbytes(ice->cs8427, reg, 1) != 1) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	if (snd_i2c_readbytes(ice->cs8427, &val, 1) != 1) {
+		snd_i2c_unlock(ice->i2c);
+		return -EIO;
+	}
+	nval = val & 0xf0;
+	if (spdif_clock)
+		nval |= 0x01;
+	else
+		nval |= 0x04;
+	if (val != nval) {
+		reg[1] = nval;
+		if (snd_i2c_sendbytes(ice->cs8427, reg, 2) != 2) {
+			res = -EIO;
+		} else {
+			res++;
+		}
+	}
+	snd_i2c_unlock(ice->i2c);
+	return res;
+}
+
+/*
+ * spdif callbacks
+ */
+static void open_cs8427(ice1712_t *ice, snd_pcm_substream_t * substream)
+{
+	snd_cs8427_iec958_active(ice->cs8427, 1);
+}
+
+static void close_cs8427(ice1712_t *ice, snd_pcm_substream_t * substream)
+{
+	snd_cs8427_iec958_active(ice->cs8427, 0);
+}
+
+static void setup_cs8427(ice1712_t *ice, snd_pcm_substream_t * substream)
+{
+	snd_cs8427_iec958_pcm(ice->cs8427, substream->runtime->rate);
+}
+
+/*
+ * create and initialize callbacks for cs8427 interface
+ */
+int __devinit snd_ice1712_init_cs8427(ice1712_t *ice, int addr)
+{
+	int err;
+
+	if ((err = snd_cs8427_create(ice->i2c, addr, &ice->cs8427)) < 0) {
+		snd_printk("CS8427 initialization failed\n");
+		return err;
+	}
+	ice->spdif.ops.open = open_cs8427;
+	ice->spdif.ops.close = close_cs8427;
+	ice->spdif.ops.setup = setup_cs8427;
+	return 0;
+}
+
+
+/*
+ *  Interrupt handler
+ */
+
+static void snd_ice1712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, dev_id, return);
+	unsigned char status;
+
+	while (1) {
+		status = inb(ICEREG(ice, IRQSTAT));
+		if (status == 0)
+			break;
+		if (status & ICE1712_IRQ_MPU1) {
+			if (ice->rmidi[0])
+				snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs);
+			outb(ICE1712_IRQ_MPU1, ICEREG(ice, IRQSTAT));
+			status &= ~ICE1712_IRQ_MPU1;
+		}
+		if (status & ICE1712_IRQ_TIMER)
+			outb(ICE1712_IRQ_TIMER, ICEREG(ice, IRQSTAT));
+		if (status & ICE1712_IRQ_MPU2) {
+			if (ice->rmidi[1])
+				snd_mpu401_uart_interrupt(irq, ice->rmidi[1]->private_data, regs);
+			outb(ICE1712_IRQ_MPU2, ICEREG(ice, IRQSTAT));
+			status &= ~ICE1712_IRQ_MPU2;
+		}
+		if (status & ICE1712_IRQ_PROPCM) {
+			unsigned char mtstat = inb(ICEMT(ice, IRQ));
+			if (mtstat & ICE1712_MULTI_PBKSTATUS) {
+				if (ice->playback_pro_substream)
+					snd_pcm_period_elapsed(ice->playback_pro_substream);
+				outb(ICE1712_MULTI_PBKSTATUS, ICEMT(ice, IRQ));
+			}
+			if (mtstat & ICE1712_MULTI_CAPSTATUS) {
+				if (ice->capture_pro_substream)
+					snd_pcm_period_elapsed(ice->capture_pro_substream);
+				outb(ICE1712_MULTI_CAPSTATUS, ICEMT(ice, IRQ));
+			}
+		}
+		if (status & ICE1712_IRQ_FM)
+			outb(ICE1712_IRQ_FM, ICEREG(ice, IRQSTAT));
+		if (status & ICE1712_IRQ_PBKDS) {
+			u32 idx;
+			u16 pbkstatus;
+			snd_pcm_substream_t *substream;
+			pbkstatus = inw(ICEDS(ice, INTSTAT));
+			//printk("pbkstatus = 0x%x\n", pbkstatus);
+			for (idx = 0; idx < 6; idx++) {
+				if ((pbkstatus & (3 << (idx * 2))) == 0)
+					continue;
+				if ((substream = ice->playback_con_substream_ds[idx]) != NULL)
+					snd_pcm_period_elapsed(substream);
+				outw(3 << (idx * 2), ICEDS(ice, INTSTAT));
+			}
+			outb(ICE1712_IRQ_PBKDS, ICEREG(ice, IRQSTAT));
+		}
+		if (status & ICE1712_IRQ_CONCAP) {
+			if (ice->capture_con_substream)
+				snd_pcm_period_elapsed(ice->capture_con_substream);
+			outb(ICE1712_IRQ_CONCAP, ICEREG(ice, IRQSTAT));
+		}
+		if (status & ICE1712_IRQ_CONPBK) {
+			if (ice->playback_con_substream)
+				snd_pcm_period_elapsed(ice->playback_con_substream);
+			outb(ICE1712_IRQ_CONPBK, ICEREG(ice, IRQSTAT));
+		}
+	}
+}
+
+
+/*
+ *  PCM part - misc
+ */
+
+static int snd_ice1712_hw_params(snd_pcm_substream_t * substream,
+				 snd_pcm_hw_params_t * hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
+static int snd_ice1712_hw_free(snd_pcm_substream_t * substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+/*
+ *  PCM part - consumer I/O
+ */
+
+static int snd_ice1712_playback_trigger(snd_pcm_substream_t * substream,
+					int cmd)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	int result = 0;
+	u32 tmp;
+	
+	spin_lock(&ice->reg_lock);
+	tmp = snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL);
+	if (cmd == SNDRV_PCM_TRIGGER_START) {
+		tmp |= 1;
+	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+		tmp &= ~1;
+	} else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) {
+		tmp |= 2;
+	} else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) {
+		tmp &= ~2;
+	} else {
+		result = -EINVAL;
+	}
+	snd_ice1712_write(ice, ICE1712_IREG_PBK_CTRL, tmp);
+	spin_unlock(&ice->reg_lock);
+	return result;
+}
+
+static int snd_ice1712_playback_ds_trigger(snd_pcm_substream_t * substream,
+					   int cmd)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	int result = 0;
+	u32 tmp;
+	
+	spin_lock(&ice->reg_lock);
+	tmp = snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL);
+	if (cmd == SNDRV_PCM_TRIGGER_START) {
+		tmp |= 1;
+	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+		tmp &= ~1;
+	} else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) {
+		tmp |= 2;
+	} else if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) {
+		tmp &= ~2;
+	} else {
+		result = -EINVAL;
+	}
+	snd_ice1712_ds_write(ice, substream->number * 2, ICE1712_DSC_CONTROL, tmp);
+	spin_unlock(&ice->reg_lock);
+	return result;
+}
+
+static int snd_ice1712_capture_trigger(snd_pcm_substream_t * substream,
+				       int cmd)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	int result = 0;
+	u8 tmp;
+	
+	spin_lock(&ice->reg_lock);
+	tmp = snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL);
+	if (cmd == SNDRV_PCM_TRIGGER_START) {
+		tmp |= 1;
+	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+		tmp &= ~1;
+	} else {
+		result = -EINVAL;
+	}
+	snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp);
+	spin_unlock(&ice->reg_lock);
+	return result;
+}
+
+static int snd_ice1712_playback_prepare(snd_pcm_substream_t * substream)
+{
+	unsigned long flags;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	u32 period_size, buf_size, rate, tmp;
+
+	period_size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1;
+	buf_size = snd_pcm_lib_buffer_bytes(substream) - 1;
+	tmp = 0x0000;
+	if (snd_pcm_format_width(runtime->format) == 16)
+		tmp |= 0x10;
+	if (runtime->channels == 2)
+		tmp |= 0x08;
+	rate = (runtime->rate * 8192) / 375;
+	if (rate > 0x000fffff)
+		rate = 0x000fffff;
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	outb(0, ice->ddma_port + 15);
+	outb(ICE1712_DMA_MODE_WRITE | ICE1712_DMA_AUTOINIT, ice->ddma_port + 0x0b);
+	outl(runtime->dma_addr, ice->ddma_port + 0);
+	outw(buf_size, ice->ddma_port + 4);
+	snd_ice1712_write(ice, ICE1712_IREG_PBK_RATE_LO, rate & 0xff);
+	snd_ice1712_write(ice, ICE1712_IREG_PBK_RATE_MID, (rate >> 8) & 0xff);
+	snd_ice1712_write(ice, ICE1712_IREG_PBK_RATE_HI, (rate >> 16) & 0xff);
+	snd_ice1712_write(ice, ICE1712_IREG_PBK_CTRL, tmp);
+	snd_ice1712_write(ice, ICE1712_IREG_PBK_COUNT_LO, period_size & 0xff);
+	snd_ice1712_write(ice, ICE1712_IREG_PBK_COUNT_HI, period_size >> 8);
+	snd_ice1712_write(ice, ICE1712_IREG_PBK_LEFT, 0);
+	snd_ice1712_write(ice, ICE1712_IREG_PBK_RIGHT, 0);
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static int snd_ice1712_playback_ds_prepare(snd_pcm_substream_t * substream)
+{
+	unsigned long flags;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	u32 period_size, buf_size, rate, tmp, chn;
+
+	period_size = snd_pcm_lib_period_bytes(substream) - 1;
+	buf_size = snd_pcm_lib_buffer_bytes(substream) - 1;
+	tmp = 0x0064;
+	if (snd_pcm_format_width(runtime->format) == 16)
+		tmp &= ~0x04;
+	if (runtime->channels == 2)
+		tmp |= 0x08;
+	rate = (runtime->rate * 8192) / 375;
+	if (rate > 0x000fffff)
+		rate = 0x000fffff;
+	ice->playback_con_active_buf[substream->number] = 0;
+	ice->playback_con_virt_addr[substream->number] = runtime->dma_addr;
+	chn = substream->number * 2;
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR0, runtime->dma_addr);
+	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_COUNT0, period_size);
+	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_ADDR1, runtime->dma_addr + (runtime->periods > 1 ? period_size + 1 : 0));
+	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_COUNT1, period_size);
+	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_RATE, rate);
+	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_VOLUME, 0);
+	snd_ice1712_ds_write(ice, chn, ICE1712_DSC_CONTROL, tmp);
+	if (runtime->channels == 2) {
+		snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_RATE, rate);
+		snd_ice1712_ds_write(ice, chn + 1, ICE1712_DSC_VOLUME, 0);
+	}
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static int snd_ice1712_capture_prepare(snd_pcm_substream_t * substream)
+{
+	unsigned long flags;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	u32 period_size, buf_size;
+	u8 tmp;
+
+	period_size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1;
+	buf_size = snd_pcm_lib_buffer_bytes(substream) - 1;
+	tmp = 0x06;
+	if (snd_pcm_format_width(runtime->format) == 16)
+		tmp &= ~0x04;
+	if (runtime->channels == 2)
+		tmp &= ~0x02;
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	outl(ice->capture_con_virt_addr = runtime->dma_addr, ICEREG(ice, CONCAP_ADDR));
+	outw(buf_size, ICEREG(ice, CONCAP_COUNT));
+	snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_HI, period_size >> 8);
+	snd_ice1712_write(ice, ICE1712_IREG_CAP_COUNT_LO, period_size & 0xff);
+	snd_ice1712_write(ice, ICE1712_IREG_CAP_CTRL, tmp);
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	snd_ac97_set_rate(ice->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_ice1712_playback_pointer(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	size_t ptr;
+
+	if (!(snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL) & 1))
+		return 0;
+	ptr = runtime->buffer_size - inw(ice->ddma_port + 4);
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_uframes_t snd_ice1712_playback_ds_pointer(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	u8 addr;
+	size_t ptr;
+
+	if (!(snd_ice1712_ds_read(ice, substream->number * 2, ICE1712_DSC_CONTROL) & 1))
+		return 0;
+	if (ice->playback_con_active_buf[substream->number])
+		addr = ICE1712_DSC_ADDR1;
+	else
+		addr = ICE1712_DSC_ADDR0;
+	ptr = snd_ice1712_ds_read(ice, substream->number * 2, addr) -
+		ice->playback_con_virt_addr[substream->number];
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_uframes_t snd_ice1712_capture_pointer(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	size_t ptr;
+
+	if (!(snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL) & 1))
+		return 0;
+	ptr = inl(ICEREG(ice, CONCAP_ADDR)) - ice->capture_con_virt_addr;
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_hardware_t snd_ice1712_playback =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_PAUSE),
+	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rate_min =		4000,
+	.rate_max =		48000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	(64*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(64*1024),
+	.periods_min =		1,
+	.periods_max =		1024,
+	.fifo_size =		0,
+};
+
+static snd_pcm_hardware_t snd_ice1712_playback_ds =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_PAUSE),
+	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rate_min =		4000,
+	.rate_max =		48000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	(128*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(128*1024),
+	.periods_min =		2,
+	.periods_max =		2,
+	.fifo_size =		0,
+};
+
+static snd_pcm_hardware_t snd_ice1712_capture =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rate_min =		4000,
+	.rate_max =		48000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	(64*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(64*1024),
+	.periods_min =		1,
+	.periods_max =		1024,
+	.fifo_size =		0,
+};
+
+static int snd_ice1712_playback_open(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->playback_con_substream = substream;
+	runtime->hw = snd_ice1712_playback;
+	return 0;
+}
+
+static int snd_ice1712_playback_ds_open(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	unsigned long flags;
+	u32 tmp;
+
+	ice->playback_con_substream_ds[substream->number] = substream;
+	runtime->hw = snd_ice1712_playback_ds;
+	spin_lock_irqsave(&ice->reg_lock, flags); 
+	tmp = inw(ICEDS(ice, INTMASK)) & ~(1 << (substream->number * 2));
+	outw(tmp, ICEDS(ice, INTMASK));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static int snd_ice1712_capture_open(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->capture_con_substream = substream;
+	runtime->hw = snd_ice1712_capture;
+	runtime->hw.rates = ice->ac97->rates[AC97_RATES_ADC];
+	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
+		runtime->hw.rate_min = 48000;
+	return 0;
+}
+
+static int snd_ice1712_playback_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->playback_con_substream = NULL;
+	return 0;
+}
+
+static int snd_ice1712_playback_ds_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&ice->reg_lock, flags); 
+	tmp = inw(ICEDS(ice, INTMASK)) | (3 << (substream->number * 2));
+	outw(tmp, ICEDS(ice, INTMASK));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	ice->playback_con_substream_ds[substream->number] = NULL;
+	return 0;
+}
+
+static int snd_ice1712_capture_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->capture_con_substream = NULL;
+	return 0;
+}
+
+static snd_pcm_ops_t snd_ice1712_playback_ops = {
+	.open =		snd_ice1712_playback_open,
+	.close =	snd_ice1712_playback_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_ice1712_hw_params,
+	.hw_free =	snd_ice1712_hw_free,
+	.prepare =	snd_ice1712_playback_prepare,
+	.trigger =	snd_ice1712_playback_trigger,
+	.pointer =	snd_ice1712_playback_pointer,
+};
+
+static snd_pcm_ops_t snd_ice1712_playback_ds_ops = {
+	.open =		snd_ice1712_playback_ds_open,
+	.close =	snd_ice1712_playback_ds_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_ice1712_hw_params,
+	.hw_free =	snd_ice1712_hw_free,
+	.prepare =	snd_ice1712_playback_ds_prepare,
+	.trigger =	snd_ice1712_playback_ds_trigger,
+	.pointer =	snd_ice1712_playback_ds_pointer,
+};
+
+static snd_pcm_ops_t snd_ice1712_capture_ops = {
+	.open =		snd_ice1712_capture_open,
+	.close =	snd_ice1712_capture_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_ice1712_hw_params,
+	.hw_free =	snd_ice1712_hw_free,
+	.prepare =	snd_ice1712_capture_prepare,
+	.trigger =	snd_ice1712_capture_trigger,
+	.pointer =	snd_ice1712_capture_pointer,
+};
+
+static void snd_ice1712_pcm_free(snd_pcm_t *pcm)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, pcm->private_data, return);
+	ice->pcm = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int __devinit snd_ice1712_pcm(ice1712_t * ice, int device, snd_pcm_t ** rpcm)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if (rpcm)
+		*rpcm = NULL;
+	err = snd_pcm_new(ice->card, "ICE1712 consumer", device, 1, 1, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ice1712_capture_ops);
+
+	pcm->private_data = ice;
+	pcm->private_free = snd_ice1712_pcm_free;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "ICE1712 consumer");
+	ice->pcm = pcm;
+
+	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 64*1024);
+
+	if (rpcm)
+		*rpcm = pcm;
+
+	printk(KERN_WARNING "Consumer PCM code does not work well at the moment --jk\n");
+
+	return 0;
+}
+
+static void snd_ice1712_pcm_free_ds(snd_pcm_t *pcm)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, pcm->private_data, return);
+	ice->pcm_ds = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int __devinit snd_ice1712_pcm_ds(ice1712_t * ice, int device, snd_pcm_t ** rpcm)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if (rpcm)
+		*rpcm = NULL;
+	err = snd_pcm_new(ice->card, "ICE1712 consumer (DS)", device, 6, 0, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_ds_ops);
+
+	pcm->private_data = ice;
+	pcm->private_free = snd_ice1712_pcm_free_ds;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "ICE1712 consumer (DS)");
+	ice->pcm_ds = pcm;
+
+	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 128*1024);
+
+	if (rpcm)
+		*rpcm = pcm;
+
+	return 0;
+}
+
+/*
+ *  PCM code - professional part (multitrack)
+ */
+
+static unsigned int rates[] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000,
+				32000, 44100, 48000, 64000, 88200, 96000 };
+
+#define RATES sizeof(rates) / sizeof(rates[0])
+
+static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+	.count = RATES,
+	.list = rates,
+	.mask = 0,
+};
+
+static int snd_ice1712_pro_trigger(snd_pcm_substream_t *substream,
+				   int cmd)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	{
+		unsigned int what;
+		unsigned int old;
+		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+			return -EINVAL;
+		what = ICE1712_PLAYBACK_PAUSE;
+		snd_pcm_trigger_done(substream, substream);
+		spin_lock(&ice->reg_lock);
+		old = inl(ICEMT(ice, PLAYBACK_CONTROL));
+		if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
+			old |= what;
+		else
+			old &= ~what;
+		outl(old, ICEMT(ice, PLAYBACK_CONTROL));
+		spin_unlock(&ice->reg_lock);
+		break;
+	}
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_STOP:
+	{
+		unsigned int what = 0;
+		unsigned int old;
+		snd_pcm_substream_t *s = substream;
+		do {
+			if (s == ice->playback_pro_substream) {
+				what |= ICE1712_PLAYBACK_START;
+				snd_pcm_trigger_done(s, substream);
+			} else if (s == ice->capture_pro_substream) {
+				what |= ICE1712_CAPTURE_START_SHADOW;
+				snd_pcm_trigger_done(s, substream);
+			}
+			s = s->link_next;
+		} while (s != substream);
+		spin_lock(&ice->reg_lock);
+		old = inl(ICEMT(ice, PLAYBACK_CONTROL));
+		if (cmd == SNDRV_PCM_TRIGGER_START)
+			old |= what;
+		else
+			old &= ~what;
+		outl(old, ICEMT(ice, PLAYBACK_CONTROL));
+		spin_unlock(&ice->reg_lock);
+		break;
+	}
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ */
+static void snd_ice1712_set_pro_rate(ice1712_t *ice, snd_pcm_substream_t *substream)
+{
+	unsigned long flags;
+	unsigned int rate;
+	unsigned char val;
+
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	if ((inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW|
+						  ICE1712_PLAYBACK_PAUSE|
+						  ICE1712_PLAYBACK_START)) ||
+	    (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER)) {
+		spin_unlock_irqrestore(&ice->reg_lock, flags);
+		return;
+	}
+	rate = substream->runtime->rate;
+	switch (rate) {
+	case 8000: val = 6; break;
+	case 9600: val = 3; break;
+	case 11025: val = 10; break;
+	case 12000: val = 2; break;
+	case 16000: val = 5; break;
+	case 22050: val = 9; break;
+	case 24000: val = 1; break;
+	case 32000: val = 4; break;
+	case 44100: val = 8; break;
+	case 48000: val = 0; break;
+	case 64000: val = 15; break;
+	case 88200: val = 11; break;
+	case 96000: val = 7; break;
+	default:
+		snd_BUG();
+		val = 0;
+		break;
+	}
+	outb(val, ICEMT(ice, RATE));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+
+	if (ice->ak4524.ops.set_rate_val)
+		ice->ak4524.ops.set_rate_val(ice, val);
+}
+
+static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream)
+{
+	unsigned long flags;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->playback_pro_size = snd_pcm_lib_buffer_bytes(substream);
+	snd_ice1712_set_pro_rate(ice, substream);
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR));
+	outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE));
+	outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, PLAYBACK_COUNT));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+
+	if (ice->spdif.ops.setup)
+		ice->spdif.ops.setup(ice, substream);
+
+	return 0;
+}
+
+static int snd_ice1712_capture_pro_prepare(snd_pcm_substream_t * substream)
+{
+	unsigned long flags;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->capture_pro_size = snd_pcm_lib_buffer_bytes(substream);
+	snd_ice1712_set_pro_rate(ice, substream);
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR));
+	outw((ice->capture_pro_size >> 2) - 1, ICEMT(ice, CAPTURE_SIZE));
+	outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, CAPTURE_COUNT));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_ice1712_playback_pro_pointer(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	size_t ptr;
+
+	if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_PLAYBACK_START))
+		return 0;
+	ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2);
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	size_t ptr;
+
+	if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_CAPTURE_START_SHADOW))
+		return 0;
+	ptr = ice->capture_pro_size - (inw(ICEMT(ice, CAPTURE_SIZE)) << 2);
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_hardware_t snd_ice1712_playback_pro =
+{
+	.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_96000,
+	.rate_min =		4000,
+	.rate_max =		96000,
+	.channels_min =		10,
+	.channels_max =		10,
+	.buffer_bytes_max =	(256*1024),
+	.period_bytes_min =	10 * 4 * 2,
+	.period_bytes_max =	131040,
+	.periods_min =		1,
+	.periods_max =		1024,
+	.fifo_size =		0,
+};
+
+static snd_pcm_hardware_t snd_ice1712_capture_pro =
+{
+	.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_96000,
+	.rate_min =		4000,
+	.rate_max =		96000,
+	.channels_min =		12,
+	.channels_max =		12,
+	.buffer_bytes_max =	(256*1024),
+	.period_bytes_min =	12 * 4 * 2,
+	.period_bytes_max =	131040,
+	.periods_min =		1,
+	.periods_max =		1024,
+	.fifo_size =		0,
+};
+
+static int snd_ice1712_playback_pro_open(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->playback_pro_substream = substream;
+	runtime->hw = snd_ice1712_playback_pro;
+	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);
+
+	if (ice->spdif.ops.open)
+		ice->spdif.ops.open(ice, substream);
+
+	return 0;
+}
+
+static int snd_ice1712_capture_pro_open(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	ice->capture_pro_substream = substream;
+	runtime->hw = snd_ice1712_capture_pro;
+	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);
+	return 0;
+}
+
+static int snd_ice1712_playback_pro_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->playback_pro_substream = NULL;
+	if (ice->spdif.ops.close)
+		ice->spdif.ops.close(ice, substream);
+
+	return 0;
+}
+
+static int snd_ice1712_capture_pro_close(snd_pcm_substream_t * substream)
+{
+	ice1712_t *ice = snd_pcm_substream_chip(substream);
+
+	ice->capture_pro_substream = NULL;
+	return 0;
+}
+
+static void snd_ice1712_pcm_profi_free(snd_pcm_t *pcm)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, pcm->private_data, return);
+	ice->pcm_pro = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static snd_pcm_ops_t snd_ice1712_playback_pro_ops = {
+	.open =		snd_ice1712_playback_pro_open,
+	.close =	snd_ice1712_playback_pro_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_ice1712_hw_params,
+	.hw_free =	snd_ice1712_hw_free,
+	.prepare =	snd_ice1712_playback_pro_prepare,
+	.trigger =	snd_ice1712_pro_trigger,
+	.pointer =	snd_ice1712_playback_pro_pointer,
+};
+
+static snd_pcm_ops_t snd_ice1712_capture_pro_ops = {
+	.open =		snd_ice1712_capture_pro_open,
+	.close =	snd_ice1712_capture_pro_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_ice1712_hw_params,
+	.hw_free =	snd_ice1712_hw_free,
+	.prepare =	snd_ice1712_capture_pro_prepare,
+	.trigger =	snd_ice1712_pro_trigger,
+	.pointer =	snd_ice1712_capture_pro_pointer,
+};
+
+static int __devinit snd_ice1712_pcm_profi(ice1712_t * ice, int device, snd_pcm_t ** rpcm)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if (rpcm)
+		*rpcm = NULL;
+	err = snd_pcm_new(ice->card, "ICE1712 multi", device, 1, 1, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_pro_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ice1712_capture_pro_ops);
+
+	pcm->private_data = ice;
+	pcm->private_free = snd_ice1712_pcm_profi_free;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "ICE1712 multi");
+
+	snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 256*1024, 256*1024);
+
+	ice->pcm_pro = pcm;
+	if (rpcm)
+		*rpcm = pcm;
+	
+	if (ice->cs8427) {
+		/* assign channels to iec958 */
+		err = snd_cs8427_iec958_build(ice->cs8427,
+					      pcm->streams[0].substream,
+					      pcm->streams[1].substream);
+		if (err < 0)
+			return err;
+	}
+
+	if ((err = snd_ice1712_build_pro_mixer(ice)) < 0)
+		return err;
+	return 0;
+}
+
+/*
+ *  Mixer section
+ */
+
+static void snd_ice1712_update_volume(ice1712_t *ice, int index)
+{
+	unsigned int vol = ice->pro_volumes[index];
+	unsigned short val = 0;
+
+	val |= (vol & 0x8000) == 0 ? (96 - (vol & 0x7f)) : 0x7f;
+	val |= ((vol & 0x80000000) == 0 ? (96 - ((vol >> 16) & 0x7f)) : 0x7f) << 8;
+	outb(index, ICEMT(ice, MONITOR_INDEX));
+	outw(val, ICEMT(ice, MONITOR_VOLUME));
+}
+
+static int snd_ice1712_pro_mixer_switch_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 snd_ice1712_pro_mixer_switch_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int index = kcontrol->private_value;
+	
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	ucontrol->value.integer.value[0] = !((ice->pro_volumes[index] >> 15) & 1);
+	ucontrol->value.integer.value[1] = !((ice->pro_volumes[index] >> 31) & 1);
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static int snd_ice1712_pro_mixer_switch_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int index = kcontrol->private_value;
+	unsigned int nval, change;
+
+	nval = (ucontrol->value.integer.value[0] ? 0 : 0x00008000) |
+	       (ucontrol->value.integer.value[1] ? 0 : 0x80000000);
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	nval |= ice->pro_volumes[index] & ~0x80008000;
+	change = nval != ice->pro_volumes[index];
+	ice->pro_volumes[index] = nval;
+	snd_ice1712_update_volume(ice, index);
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return change;
+}
+
+static int snd_ice1712_pro_mixer_volume_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 = 0;
+	uinfo->value.integer.max = 96;
+	return 0;
+}
+
+static int snd_ice1712_pro_mixer_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int index = kcontrol->private_value;
+	
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	ucontrol->value.integer.value[0] = (ice->pro_volumes[index] >> 0) & 127;
+	ucontrol->value.integer.value[1] = (ice->pro_volumes[index] >> 16) & 127;
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static int snd_ice1712_pro_mixer_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int index = kcontrol->private_value;
+	unsigned int nval, change;
+
+	nval = (ucontrol->value.integer.value[0] & 127) |
+	       ((ucontrol->value.integer.value[1] & 127) << 16);
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	nval |= ice->pro_volumes[index] & ~0x007f007f;
+	change = nval != ice->pro_volumes[index];
+	ice->pro_volumes[index] = nval;
+	snd_ice1712_update_volume(ice, index);
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return change;
+}
+
+
+static int __init snd_ice1712_build_pro_mixer(ice1712_t *ice)
+{
+	snd_card_t * card = ice->card;
+	snd_kcontrol_t ctl;
+	int idx, err;
+
+	/* PCM playback */
+	for (idx = 0; idx < 10; idx++) {
+		memset(&ctl, 0, sizeof(ctl));
+		strcpy(ctl.id.name, "Multi Playback Switch");
+		ctl.id.index = idx;
+		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl.info = snd_ice1712_pro_mixer_switch_info;
+		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+		ctl.get = snd_ice1712_pro_mixer_switch_get;
+		ctl.put = snd_ice1712_pro_mixer_switch_put;
+		ctl.private_value = idx;
+		ctl.private_data = ice;
+		if ((err = snd_ctl_add(card, snd_ctl_new(&ctl))) < 0)
+			return err;
+		memset(&ctl, 0, sizeof(ctl));
+		strcpy(ctl.id.name, "Multi Playback Volume");
+		ctl.id.index = idx;
+		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl.info = snd_ice1712_pro_mixer_volume_info;
+		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+		ctl.get = snd_ice1712_pro_mixer_volume_get;
+		ctl.put = snd_ice1712_pro_mixer_volume_put;
+		ctl.private_value = idx;
+		ctl.private_data = ice;
+		if ((err = snd_ctl_add(card, snd_ctl_new(&ctl))) < 0)
+			return err;
+	}
+
+	/* PCM capture */
+	for (idx = 0; idx < 10; idx++) {
+		memset(&ctl, 0, sizeof(ctl));
+		strcpy(ctl.id.name, "Multi Capture Switch");
+		ctl.id.index = idx;
+		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl.info = snd_ice1712_pro_mixer_switch_info;
+		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+		ctl.get = snd_ice1712_pro_mixer_switch_get;
+		ctl.put = snd_ice1712_pro_mixer_switch_put;
+		ctl.private_value = idx + 10;
+		ctl.private_data = ice;
+		if ((err = snd_ctl_add(card, snd_ctl_new(&ctl))) < 0)
+			return err;
+		memset(&ctl, 0, sizeof(ctl));
+		strcpy(ctl.id.name, "Multi Capture Volume");
+		ctl.id.index = idx;
+		ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+		ctl.info = snd_ice1712_pro_mixer_volume_info;
+		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
+		ctl.get = snd_ice1712_pro_mixer_volume_get;
+		ctl.put = snd_ice1712_pro_mixer_volume_put;
+		ctl.private_value = idx + 10;
+		ctl.private_data = ice;
+		if ((err = snd_ctl_add(card, snd_ctl_new(&ctl))) < 0)
+			return err;
+	}
+	
+	/* initialize volumes */
+	for (idx = 0; idx < 20; idx++) {
+		ice->pro_volumes[idx] = 0x80008000;	/* mute */
+		snd_ice1712_update_volume(ice, idx);
+	}
+	return 0;
+}
+
+static void snd_ice1712_mixer_free_ac97(ac97_t *ac97)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, ac97->private_data, return);
+	ice->ac97 = NULL;
+}
+
+static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice)
+{
+	int err;
+
+	if (!(ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97)) {
+		ac97_t ac97;
+		memset(&ac97, 0, sizeof(ac97));
+		ac97.write = snd_ice1712_ac97_write;
+		ac97.read = snd_ice1712_ac97_read;
+		ac97.private_data = ice;
+		ac97.private_free = snd_ice1712_mixer_free_ac97;
+		if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0)
+			printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n");
+		else {
+			if ((err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice))) < 0)
+				return err;
+			return 0;
+		}
+	}
+	/* hmm.. can we have both consumer and pro ac97 mixers? */
+	if (! (ice->eeprom.aclink & ICE1712_CFG_PRO_I2S)) {
+		ac97_t ac97;
+		memset(&ac97, 0, sizeof(ac97));
+		ac97.write = snd_ice1712_pro_ac97_write;
+		ac97.read = snd_ice1712_pro_ac97_read;
+		ac97.private_data = ice;
+		ac97.private_free = snd_ice1712_mixer_free_ac97;
+		if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0)
+			printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
+		else
+			return 0;
+	}
+	/* I2S mixer only */
+	strcat(ice->card->mixername, "ICE1712 - multitrack");
+	return 0;
+}
+
+/*
+ *
+ */
+
+static void snd_ice1712_proc_read(snd_info_entry_t *entry, 
+				  snd_info_buffer_t * buffer)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, entry->private_data, return);
+	unsigned int idx;
+
+	snd_iprintf(buffer, "ICE1712\n\n");
+	snd_iprintf(buffer, "EEPROM:\n");
+	snd_iprintf(buffer, "  Subvendor        : 0x%x\n", ice->eeprom.subvendor);
+	snd_iprintf(buffer, "  Size             : %i bytes\n", ice->eeprom.size);
+	snd_iprintf(buffer, "  Version          : %i\n", ice->eeprom.version);
+	snd_iprintf(buffer, "  Codec            : 0x%x\n", ice->eeprom.codec);
+	snd_iprintf(buffer, "  ACLink           : 0x%x\n", ice->eeprom.aclink);
+	snd_iprintf(buffer, "  I2S ID           : 0x%x\n", ice->eeprom.i2sID);
+	snd_iprintf(buffer, "  S/PDIF           : 0x%x\n", ice->eeprom.spdif);
+	snd_iprintf(buffer, "  GPIO mask        : 0x%x\n", ice->eeprom.gpiomask);
+	snd_iprintf(buffer, "  GPIO state       : 0x%x\n", ice->eeprom.gpiostate);
+	snd_iprintf(buffer, "  GPIO direction   : 0x%x\n", ice->eeprom.gpiodir);
+	snd_iprintf(buffer, "  AC'97 main       : 0x%x\n", ice->eeprom.ac97main);
+	snd_iprintf(buffer, "  AC'97 pcm        : 0x%x\n", ice->eeprom.ac97pcm);
+	snd_iprintf(buffer, "  AC'97 record     : 0x%x\n", ice->eeprom.ac97rec);
+	snd_iprintf(buffer, "  AC'97 record src : 0x%x\n", ice->eeprom.ac97recsrc);
+	for (idx = 0; idx < 4; idx++)
+		snd_iprintf(buffer, "  DAC ID #%i        : 0x%x\n", idx, ice->eeprom.dacID[idx]);
+	for (idx = 0; idx < 4; idx++)
+		snd_iprintf(buffer, "  ADC ID #%i        : 0x%x\n", idx, ice->eeprom.adcID[idx]);
+	for (idx = 0x1c; idx < ice->eeprom.size && idx < 0x1c + sizeof(ice->eeprom.extra); idx++)
+		snd_iprintf(buffer, "  Extra #%02i        : 0x%x\n", idx, ice->eeprom.extra[idx - 0x1c]);
+}
+
+static void __devinit snd_ice1712_proc_init(ice1712_t * ice)
+{
+	snd_info_entry_t *entry;
+
+	if ((entry = snd_info_create_card_entry(ice->card, "ice1712", ice->card->proc_root)) != NULL) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->private_data = ice;
+		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+		entry->c.text.read_size = 2048;
+		entry->c.text.read = snd_ice1712_proc_read;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	ice->proc_entry = entry;
+}
+
+static void snd_ice1712_proc_done(ice1712_t * ice)
+{
+	if (ice->proc_entry) {
+		snd_info_unregister(ice->proc_entry);
+		ice->proc_entry = NULL;
+	}
+}
+
+/*
+ *
+ */
+
+static int snd_ice1712_eeprom_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = 32;
+	return 0;
+}
+
+static int snd_ice1712_eeprom_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	
+	memcpy(ucontrol->value.bytes.data, &ice->eeprom, 32);
+	return 0;
+}
+
+static snd_kcontrol_new_t snd_ice1712_eeprom __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
+	.name = "ICE1712 EEPROM",
+	.access = SNDRV_CTL_ELEM_ACCESS_READ,
+	.info = snd_ice1712_eeprom_info,
+	.get = snd_ice1712_eeprom_get
+};
+
+/*
+ */
+static int snd_ice1712_spdif_default_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_ice1712_spdif_default_get(snd_kcontrol_t * kcontrol,
+					 snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	if (ice->spdif.ops.default_get)
+		ice->spdif.ops.default_get(ice, ucontrol); 
+	return 0;
+}
+
+static int snd_ice1712_spdif_default_put(snd_kcontrol_t * kcontrol,
+					 snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	if (ice->spdif.ops.default_put)
+		return ice->spdif.ops.default_put(ice, ucontrol);
+	return 0;
+}
+
+static snd_kcontrol_new_t snd_ice1712_spdif_default __devinitdata =
+{
+	.iface =		SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =           SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+	.info =		snd_ice1712_spdif_default_info,
+	.get =		snd_ice1712_spdif_default_get,
+	.put =		snd_ice1712_spdif_default_put
+};
+
+static int snd_ice1712_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_ice1712_spdif_maskc_get(snd_kcontrol_t * kcontrol,
+				       snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	if (ice->spdif.ops.default_get) {
+		ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO |
+						     IEC958_AES0_PROFESSIONAL |
+						     IEC958_AES0_CON_NOT_COPYRIGHT |
+						     IEC958_AES0_CON_EMPHASIS;
+		ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL |
+						     IEC958_AES1_CON_CATEGORY;
+		ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
+	} else {
+		ucontrol->value.iec958.status[0] = 0xff;
+		ucontrol->value.iec958.status[1] = 0xff;
+		ucontrol->value.iec958.status[2] = 0xff;
+		ucontrol->value.iec958.status[3] = 0xff;
+		ucontrol->value.iec958.status[4] = 0xff;
+	}
+	return 0;
+}
+
+static int snd_ice1712_spdif_maskp_get(snd_kcontrol_t * kcontrol,
+				       snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	if (ice->spdif.ops.default_get) {
+		ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO |
+						     IEC958_AES0_PROFESSIONAL |
+						     IEC958_AES0_PRO_FS |
+						     IEC958_AES0_PRO_EMPHASIS;
+		ucontrol->value.iec958.status[1] = IEC958_AES1_PRO_MODE;
+	} else {
+		ucontrol->value.iec958.status[0] = 0xff;
+		ucontrol->value.iec958.status[1] = 0xff;
+		ucontrol->value.iec958.status[2] = 0xff;
+		ucontrol->value.iec958.status[3] = 0xff;
+		ucontrol->value.iec958.status[4] = 0xff;
+	}
+	return 0;
+}
+
+static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
+{
+	.access =		SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =		SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =           SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+	.info =		snd_ice1712_spdif_mask_info,
+	.get =		snd_ice1712_spdif_maskc_get,
+};
+
+static snd_kcontrol_new_t snd_ice1712_spdif_maskp __devinitdata =
+{
+	.access =		SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =		SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =           SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+	.info =		snd_ice1712_spdif_mask_info,
+	.get =		snd_ice1712_spdif_maskp_get,
+};
+
+static int snd_ice1712_spdif_stream_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_ice1712_spdif_stream_get(snd_kcontrol_t * kcontrol,
+					snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	if (ice->spdif.ops.stream_get)
+		ice->spdif.ops.stream_get(ice, ucontrol);
+	return 0;
+}
+
+static int snd_ice1712_spdif_stream_put(snd_kcontrol_t * kcontrol,
+					snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	if (ice->spdif.ops.stream_put)
+		return ice->spdif.ops.stream_put(ice, ucontrol);
+	return 0;
+}
+
+static snd_kcontrol_new_t snd_ice1712_spdif_stream __devinitdata =
+{
+	.access =		SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+	.iface =		SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =           SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
+	.info =		snd_ice1712_spdif_stream_info,
+	.get =		snd_ice1712_spdif_stream_get,
+	.put =		snd_ice1712_spdif_stream_put
+};
+
+int snd_ice1712_gpio_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+int snd_ice1712_gpio_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char mask = kcontrol->private_value & 0xff;
+	int invert = (kcontrol->private_value & (1<<24)) ? 1 : 0;
+	unsigned char saved[2];
+	
+	snd_ice1712_save_gpio_status(ice, saved);
+	ucontrol->value.integer.value[0] = (snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & mask ? 1 : 0) ^ invert;
+	snd_ice1712_restore_gpio_status(ice, saved);
+	return 0;
+}
+
+int snd_ice1712_gpio_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned char mask = kcontrol->private_value & 0xff;
+	int invert = (kcontrol->private_value & (1<<24)) ? mask : 0;
+	unsigned char saved[2];
+	int val, nval;
+
+	if (kcontrol->private_value & (1 << 31))
+		return -EPERM;
+	nval = (ucontrol->value.integer.value[0] ? mask : 0) ^ invert;
+	snd_ice1712_save_gpio_status(ice, saved);
+	val = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+	nval |= val & ~mask;
+	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, nval);
+	snd_ice1712_restore_gpio_status(ice, saved);
+	return val != nval;
+}
+
+static int snd_ice1712_pro_spdif_master_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_ice1712_pro_spdif_master_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	ucontrol->value.integer.value[0] = inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER ? 1 : 0;
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static int snd_ice1712_pro_spdif_master_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int nval, change;
+
+	nval = ucontrol->value.integer.value[0] ? ICE1712_SPDIF_MASTER : 0;
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	nval |= inb(ICEMT(ice, RATE)) & ~ICE1712_SPDIF_MASTER;
+	change = inb(ICEMT(ice, RATE)) != nval;
+	outb(nval, ICEMT(ice, RATE));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+
+	if (ice->cs8427) {
+		/* change CS8427 clock source too */
+		snd_ice1712_cs8427_set_input_clock(ice, ucontrol->value.integer.value[0]);
+	}
+
+	return change;
+}
+
+static snd_kcontrol_new_t snd_ice1712_pro_spdif_master __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Multi Track IEC958 Master",
+	.info = snd_ice1712_pro_spdif_master_info,
+	.get = snd_ice1712_pro_spdif_master_get,
+	.put = snd_ice1712_pro_spdif_master_put
+};
+
+/*
+ * routing
+ */
+static int snd_ice1712_pro_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[] = {
+		"PCM Out", /* 0 */
+		"H/W In 0", "H/W In 1", "H/W In 2", "H/W In 3", /* 1-4 */
+		"H/W In 4", "H/W In 5", "H/W In 6", "H/W In 7", /* 5-8 */
+		"IEC958 In L", "IEC958 In R", /* 9-10 */
+		"Digital Mixer", /* 11 - optional */
+	};
+	
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = kcontrol->id.index < 2 ? 12 : 11;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_ice1712_pro_route_analog_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int idx = kcontrol->id.index;
+	unsigned int val, cval;
+	val = inw(ICEMT(ice, ROUTE_PSDOUT03));
+	val >>= ((idx % 2) * 8) + ((idx / 2) * 2);
+	val &= 3;
+	cval = inl(ICEMT(ice, ROUTE_CAPTURE));
+	cval >>= ((idx / 2) * 8) + ((idx % 2) * 4);
+	if (val == 1 && idx < 2)
+		ucontrol->value.enumerated.item[0] = 11;
+	else if (val == 2)
+		ucontrol->value.enumerated.item[0] = (cval & 7) + 1;
+	else if (val == 3)
+		ucontrol->value.enumerated.item[0] = ((cval >> 3) & 1) + 9;
+	else
+		ucontrol->value.enumerated.item[0] = 0;
+	return 0;
+}
+
+static int snd_ice1712_pro_route_analog_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int change, shift;
+	int idx = kcontrol->id.index;
+	unsigned int val, old_val, nval;
+	
+	/* update PSDOUT */
+	if (ucontrol->value.enumerated.item[0] >= 11)
+		nval = idx < 2 ? 1 : 0; /* dig mixer (or pcm) */
+	else if (ucontrol->value.enumerated.item[0] >= 9)
+		nval = 3; /* spdif in */
+	else if (ucontrol->value.enumerated.item[0] >= 1)
+		nval = 2; /* analog in */
+	else
+		nval = 0; /* pcm */
+	shift = ((idx % 2) * 8) + ((idx / 2) * 2);
+	val = old_val = inw(ICEMT(ice, ROUTE_PSDOUT03));
+	val &= ~(0x03 << shift);
+	val |= nval << shift;
+	change = val != old_val;
+	if (change)
+		outw(val, ICEMT(ice, ROUTE_PSDOUT03));
+	if (nval < 2) /* dig mixer of pcm */
+		return change;
+
+	/* update CAPTURE */
+	val = old_val = inl(ICEMT(ice, ROUTE_CAPTURE));
+	shift = ((idx / 2) * 8) + ((idx % 2) * 4);
+	if (nval == 2) { /* analog in */
+		nval = ucontrol->value.enumerated.item[0] - 1;
+		val &= ~(0x07 << shift);
+		val |= nval << shift;
+	} else { /* spdif in */
+		nval = (ucontrol->value.enumerated.item[0] - 9) << 3;
+		val &= ~(0x08 << shift);
+		val |= nval << shift;
+	}
+	if (val != old_val) {
+		change = 1;
+		outl(val, ICEMT(ice, ROUTE_CAPTURE));
+	}
+	return change;
+}
+
+static int snd_ice1712_pro_route_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int idx = kcontrol->id.index;
+	unsigned int val, cval;
+	val = inw(ICEMT(ice, ROUTE_SPDOUT));
+	cval = (val >> (idx * 4 + 8)) & 0x0f;
+	val = (val >> (idx * 2)) & 0x03;
+	if (val == 1)
+		ucontrol->value.enumerated.item[0] = 11;
+	else if (val == 2)
+		ucontrol->value.enumerated.item[0] = (cval & 7) + 1;
+	else if (val == 3)
+		ucontrol->value.enumerated.item[0] = ((cval >> 3) & 1) + 9;
+	else
+		ucontrol->value.enumerated.item[0] = 0;
+	return 0;
+}
+
+static int snd_ice1712_pro_route_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int change, shift;
+	int idx = kcontrol->id.index;
+	unsigned int val, old_val, nval;
+	
+	/* update SPDOUT */
+	val = old_val = inw(ICEMT(ice, ROUTE_SPDOUT));
+	if (ucontrol->value.enumerated.item[0] >= 11)
+		nval = 1;
+	else if (ucontrol->value.enumerated.item[0] >= 9)
+		nval = 3;
+	else if (ucontrol->value.enumerated.item[0] >= 1)
+		nval = 2;
+	else
+		nval = 0;
+	shift = idx * 2;
+	val &= ~(0x03 << shift);
+	val |= nval << shift;
+	shift = idx * 4 + 8;
+	if (nval == 2) {
+		nval = ucontrol->value.enumerated.item[0] - 1;
+		val &= ~(0x07 << shift);
+		val |= nval << shift;
+	} else if (nval == 3) {
+		nval = (ucontrol->value.enumerated.item[0] - 9) << 3;
+		val &= ~(0x08 << shift);
+		val |= nval << shift;
+	}
+	change = val != old_val;
+	if (change)
+		outw(val, ICEMT(ice, ROUTE_SPDOUT));
+	return change;
+}
+
+static snd_kcontrol_new_t snd_ice1712_mixer_pro_analog_route __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "H/W Playback Route",
+	.info = snd_ice1712_pro_route_info,
+	.get = snd_ice1712_pro_route_analog_get,
+	.put = snd_ice1712_pro_route_analog_put,
+};
+
+static snd_kcontrol_new_t snd_ice1712_mixer_pro_spdif_route __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC958 Playback Route",
+	.info = snd_ice1712_pro_route_info,
+	.get = snd_ice1712_pro_route_spdif_get,
+	.put = snd_ice1712_pro_route_spdif_put,
+};
+
+
+static int snd_ice1712_pro_volume_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 255;
+	return 0;
+}
+
+static int snd_ice1712_pro_volume_rate_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	ucontrol->value.integer.value[0] = inb(ICEMT(ice, MONITOR_RATE));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static int snd_ice1712_pro_volume_rate_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	unsigned long flags;
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int change;
+
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	change = inb(ICEMT(ice, MONITOR_RATE)) != ucontrol->value.integer.value[0];
+	outb(ucontrol->value.integer.value[0], ICEMT(ice, MONITOR_RATE));
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return change;
+}
+
+static snd_kcontrol_new_t snd_ice1712_mixer_pro_volume_rate __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Multi Track Volume Rate",
+	.info = snd_ice1712_pro_volume_rate_info,
+	.get = snd_ice1712_pro_volume_rate_get,
+	.put = snd_ice1712_pro_volume_rate_put
+};
+
+static int snd_ice1712_pro_peak_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 22;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 255;
+	return 0;
+}
+
+static int snd_ice1712_pro_peak_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int idx;
+	
+	spin_lock_irqsave(&ice->reg_lock, flags);
+	for (idx = 0; idx < 22; idx++) {
+		outb(idx, ICEMT(ice, MONITOR_PEAKINDEX));
+		ucontrol->value.integer.value[idx] = inb(ICEMT(ice, MONITOR_PEAKDATA));
+	}
+	spin_unlock_irqrestore(&ice->reg_lock, flags);
+	return 0;
+}
+
+static snd_kcontrol_new_t snd_ice1712_mixer_pro_peak __devinitdata = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Multi Track Peak",
+	.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+	.info = snd_ice1712_pro_peak_info,
+	.get = snd_ice1712_pro_peak_get
+};
+
+/*
+ *
+ */
+
+static unsigned char __devinit snd_ice1712_read_i2c(ice1712_t *ice,
+						 unsigned char dev,
+						 unsigned char addr)
+{
+	long t = 0x10000;
+
+	outb(addr, ICEREG(ice, I2C_BYTE_ADDR));
+	outb(dev & ~ICE1712_I2C_WRITE, ICEREG(ice, I2C_DEV_ADDR));
+	while (t-- > 0 && (inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_BUSY)) ;
+	return inb(ICEREG(ice, I2C_DATA));
+}
+
+static int __devinit snd_ice1712_read_eeprom(ice1712_t *ice)
+{
+	int dev = 0xa0;		/* EEPROM device address */
+	unsigned int idx;
+
+	if ((inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_EEPROM) == 0) {
+		snd_printk("ICE1712 has not detected EEPROM\n");
+		return -EIO;
+	}
+	ice->eeprom.subvendor = (snd_ice1712_read_i2c(ice, dev, 0x00) << 0) |
+				(snd_ice1712_read_i2c(ice, dev, 0x01) << 8) | 
+				(snd_ice1712_read_i2c(ice, dev, 0x02) << 16) | 
+				(snd_ice1712_read_i2c(ice, dev, 0x03) << 24);
+	ice->eeprom.size = snd_ice1712_read_i2c(ice, dev, 0x04);
+	if (ice->eeprom.size < 28) {
+		snd_printk("invalid EEPROM (size = %i)\n", ice->eeprom.size);
+		return -EIO;
+	}
+	ice->eeprom.version = snd_ice1712_read_i2c(ice, dev, 0x05);
+	if (ice->eeprom.version != 1) {
+		snd_printk("invalid EEPROM version %i\n", ice->eeprom.version);
+		return -EIO;
+	}
+	ice->eeprom.codec = snd_ice1712_read_i2c(ice, dev, 0x06);
+	ice->eeprom.aclink = snd_ice1712_read_i2c(ice, dev, 0x07);
+	ice->eeprom.i2sID = snd_ice1712_read_i2c(ice, dev, 0x08);
+	ice->eeprom.spdif = snd_ice1712_read_i2c(ice, dev, 0x09);
+	ice->eeprom.gpiomask = snd_ice1712_read_i2c(ice, dev, 0x0a);
+	ice->eeprom.gpiostate = snd_ice1712_read_i2c(ice, dev, 0x0b);
+	ice->eeprom.gpiodir = snd_ice1712_read_i2c(ice, dev, 0x0c);
+	ice->eeprom.ac97main = (snd_ice1712_read_i2c(ice, dev, 0x0d) << 0) |
+			       (snd_ice1712_read_i2c(ice, dev, 0x0e) << 8);
+	ice->eeprom.ac97pcm = (snd_ice1712_read_i2c(ice, dev, 0x0f) << 0) |
+			      (snd_ice1712_read_i2c(ice, dev, 0x10) << 8);
+	ice->eeprom.ac97rec = (snd_ice1712_read_i2c(ice, dev, 0x11) << 0) |
+			      (snd_ice1712_read_i2c(ice, dev, 0x12) << 8);
+	ice->eeprom.ac97recsrc = snd_ice1712_read_i2c(ice, dev, 0x13) << 0;
+	for (idx = 0; idx < 4; idx++) {
+		ice->eeprom.dacID[idx] = snd_ice1712_read_i2c(ice, dev, 0x14 + idx);
+		ice->eeprom.adcID[idx] = snd_ice1712_read_i2c(ice, dev, 0x18 + idx);
+	}
+	for (idx = 0x1c; idx < ice->eeprom.size && idx < 0x1c + sizeof(ice->eeprom.extra); idx++)
+		ice->eeprom.extra[idx - 0x1c] = snd_ice1712_read_i2c(ice, dev, idx);
+	return 0;
+}
+
+
+
+static int __devinit snd_ice1712_chip_init(ice1712_t *ice)
+{
+	outb(ICE1712_RESET | ICE1712_NATIVE, ICEREG(ice, CONTROL));
+	udelay(200);
+	outb(ICE1712_NATIVE, ICEREG(ice, CONTROL));
+	udelay(200);
+	pci_write_config_byte(ice->pci, 0x60, ice->eeprom.codec);
+	pci_write_config_byte(ice->pci, 0x61, ice->eeprom.aclink);
+	pci_write_config_byte(ice->pci, 0x62, ice->eeprom.i2sID);
+	pci_write_config_byte(ice->pci, 0x63, ice->eeprom.spdif);
+	if (ice->eeprom.subvendor != ICE1712_SUBDEVICE_STDSP24) {
+		ice->gpio_write_mask = ice->eeprom.gpiomask;
+		ice->gpio_direction = ice->eeprom.gpiodir;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ice->eeprom.gpiomask);
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->eeprom.gpiodir);
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ice->eeprom.gpiostate);
+	} else {
+		ice->gpio_write_mask = 0xc0;
+		ice->gpio_direction = 0xff;
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, 0xc0);
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, 0xff);
+		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ICE1712_STDSP24_CLOCK_BIT);
+	}
+	snd_ice1712_write(ice, ICE1712_IREG_PRO_POWERDOWN, 0);
+	if (!(ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97)) {
+		outb(ICE1712_AC97_WARM, ICEREG(ice, AC97_CMD));
+		udelay(100);
+		outb(0, ICEREG(ice, AC97_CMD));
+		udelay(200);
+		snd_ice1712_write(ice, ICE1712_IREG_CONSUMER_POWERDOWN, 0);
+	}
+
+	return 0;
+}
+
+
+int __devinit snd_ice1712_spdif_build_controls(ice1712_t *ice)
+{
+	int err;
+	snd_kcontrol_t *kctl;
+
+	snd_assert(ice->pcm_pro != NULL, return -EIO);
+	err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice));
+	if (err < 0)
+		return err;
+	kctl->id.device = ice->pcm_pro->device;
+	err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_maskc, ice));
+	if (err < 0)
+		return err;
+	kctl->id.device = ice->pcm_pro->device;
+	err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_maskp, ice));
+	if (err < 0)
+		return err;
+	kctl->id.device = ice->pcm_pro->device;
+	err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_stream, ice));
+	if (err < 0)
+		return err;
+	kctl->id.device = ice->pcm_pro->device;
+	ice->spdif.stream_ctl = kctl;
+	return 0;
+}
+
+
+static int __devinit snd_ice1712_build_controls(ice1712_t *ice)
+{
+	unsigned int idx;
+	snd_kcontrol_t *kctl;
+	int err;
+
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_eeprom, ice));
+	if (err < 0)
+		return err;
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_pro_spdif_master, ice));
+	if (err < 0)
+		return err;
+	for (idx = 0; idx < ice->num_total_dacs; idx++) {
+		kctl = snd_ctl_new1(&snd_ice1712_mixer_pro_analog_route, ice);
+		if (kctl == NULL)
+			return -ENOMEM;
+		kctl->id.index = idx;
+		err = snd_ctl_add(ice->card, kctl);
+		if (err < 0)
+			return err;
+	}
+	for (idx = 0; idx < 2; idx++) {
+		kctl = snd_ctl_new1(&snd_ice1712_mixer_pro_spdif_route, ice);
+		if (kctl == NULL)
+			return -ENOMEM;
+		kctl->id.index = idx;
+		err = snd_ctl_add(ice->card, kctl);
+		if (err < 0)
+			return err;
+	}
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_volume_rate, ice));
+	if (err < 0)
+		return err;
+	err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice));
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int snd_ice1712_free(ice1712_t *ice)
+{
+	if (ice->res_port == NULL)
+		goto __hw_end;
+	/* mask all interrupts */
+	outb(0xc0, ICEMT(ice, IRQ));
+	outb(0xff, ICEREG(ice, IRQMASK));
+	/* --- */
+      __hw_end:
+	snd_ice1712_proc_done(ice);
+	if (ice->irq >= 0) {
+		synchronize_irq(ice->irq);
+		free_irq(ice->irq, (void *) ice);
+	}
+	if (ice->res_port) {
+		release_resource(ice->res_port);
+		kfree_nocheck(ice->res_port);
+	}
+	if (ice->res_ddma_port) {
+		release_resource(ice->res_ddma_port);
+		kfree_nocheck(ice->res_ddma_port);
+	}
+	if (ice->res_dmapath_port) {
+		release_resource(ice->res_dmapath_port);
+		kfree_nocheck(ice->res_dmapath_port);
+	}
+	if (ice->res_profi_port) {
+		release_resource(ice->res_profi_port);
+		kfree_nocheck(ice->res_profi_port);
+	}
+	snd_magic_kfree(ice);
+	return 0;
+}
+
+static int snd_ice1712_dev_free(snd_device_t *device)
+{
+	ice1712_t *ice = snd_magic_cast(ice1712_t, device->device_data, return -ENXIO);
+	return snd_ice1712_free(ice);
+}
+
+static int __devinit snd_ice1712_create(snd_card_t * card,
+				     struct pci_dev *pci,
+				     int omni,
+				     ice1712_t ** r_ice1712)
+{
+	ice1712_t *ice;
+	int err;
+	static snd_device_ops_t ops = {
+		.dev_free =	snd_ice1712_dev_free,
+	};
+
+	*r_ice1712 = NULL;
+
+        /* enable PCI device */
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+	/* check, if we can restrict PCI DMA transfers to 28 bits */
+	if (!pci_dma_supported(pci, 0x0fffffff)) {
+		snd_printk("architecture does not support 28bit PCI busmaster DMA\n");
+		return -ENXIO;
+	}
+	pci_set_dma_mask(pci, 0x0fffffff);
+
+	ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL);
+	if (ice == NULL)
+		return -ENOMEM;
+	ice->omni = omni ? 1 : 0;
+	spin_lock_init(&ice->reg_lock);
+	init_MUTEX(&ice->gpio_mutex);
+	ice->spdif.cs8403_bits =
+		ice->spdif.cs8403_stream_bits = (0x01 |	/* consumer format */
+						 0x10 |	/* no emphasis */
+						 0x20);	/* PCM encoder/decoder */
+	ice->card = card;
+	ice->pci = pci;
+	ice->irq = -1;
+	ice->port = pci_resource_start(pci, 0);
+	ice->ddma_port = pci_resource_start(pci, 1);
+	ice->dmapath_port = pci_resource_start(pci, 2);
+	ice->profi_port = pci_resource_start(pci, 3);
+	pci_set_master(pci);
+	pci_write_config_word(ice->pci, 0x40, 0x807f);
+	pci_write_config_word(ice->pci, 0x42, 0x0006);
+	snd_ice1712_proc_init(ice);
+	synchronize_irq(pci->irq);
+
+	if ((ice->res_port = request_region(ice->port, 32, "ICE1712 - Controller")) == NULL) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->port, ice->port + 32 - 1);
+		return -EIO;
+	}
+	if ((ice->res_ddma_port = request_region(ice->ddma_port, 16, "ICE1712 - DDMA")) == NULL) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->ddma_port, ice->ddma_port + 16 - 1);
+		return -EIO;
+	}
+	if ((ice->res_dmapath_port = request_region(ice->dmapath_port, 16, "ICE1712 - DMA path")) == NULL) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->dmapath_port, ice->dmapath_port + 16 - 1);
+		return -EIO;
+	}
+	if ((ice->res_profi_port = request_region(ice->profi_port, 64, "ICE1712 - Professional")) == NULL) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", ice->profi_port, ice->profi_port + 16 - 1);
+		return -EIO;
+	}
+	if (request_irq(pci->irq, snd_ice1712_interrupt, SA_INTERRUPT|SA_SHIRQ, "ICE1712", (void *) ice)) {
+		snd_ice1712_free(ice);
+		snd_printk("unable to grab IRQ %d\n", pci->irq);
+		return -EIO;
+	}
+	ice->irq = pci->irq;
+
+	if (snd_ice1712_read_eeprom(ice) < 0) {
+		snd_ice1712_free(ice);
+		return -EIO;
+	}
+	if (snd_ice1712_chip_init(ice) < 0) {
+		snd_ice1712_free(ice);
+		return -EIO;
+	}
+
+	/* unmask used interrupts */
+	outb((ice->eeprom.codec & ICE1712_CFG_2xMPU401) == 0 ? ICE1712_IRQ_MPU2 : 0 |
+	     (ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97) ? ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0,
+	     ICEREG(ice, IRQMASK));
+	outb(0x00, ICEMT(ice, IRQ));
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops)) < 0) {
+		snd_ice1712_free(ice);
+		return err;
+	}
+
+	*r_ice1712 = ice;
+	return 0;
+}
+
+
+/*
+ *
+ * Registraton
+ *
+ */
+
+static struct snd_ice1712_card_info no_matched __devinitdata;
+
+static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
+	snd_ice1712_hoontech_cards,
+	snd_ice1712_delta_cards,
+	snd_ice1712_ews_cards,
+	0,
+};
+
+
+static int __devinit snd_ice1712_probe(struct pci_dev *pci,
+				       const struct pci_device_id *id)
+{
+	static int dev;
+	snd_card_t *card;
+	ice1712_t *ice;
+	int pcm_dev = 0, err;
+	struct snd_ice1712_card_info **tbl, *c;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!snd_enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
+	if (card == NULL)
+		return -ENOMEM;
+
+	strcpy(card->driver, "ICE1712");
+	strcpy(card->shortname, "ICEnsemble ICE1712");
+	
+	if ((err = snd_ice1712_create(card, pci, snd_omni[dev], &ice)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	for (tbl = card_tables; *tbl; tbl++) {
+		for (c = *tbl; c->subvendor; c++) {
+			if (c->subvendor == ice->eeprom.subvendor) {
+				strcpy(card->shortname, c->name);
+				if (c->chip_init) {
+					if ((err = c->chip_init(ice)) < 0) {
+						snd_card_free(card);
+						return err;
+					}
+				}
+				goto __found;
+			}
+		}
+	}
+	c = &no_matched;
+ __found:
+
+	if ((err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	
+	if (!(ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97))
+		if ((err = snd_ice1712_pcm(ice, pcm_dev++, NULL)) < 0) {
+			snd_card_free(card);
+			return err;
+		}
+
+	if ((err = snd_ice1712_ac97_mixer(ice)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	if ((err = snd_ice1712_build_controls(ice)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	if (c->build_controls) {
+		if ((err = c->build_controls(ice)) < 0) {
+			snd_card_free(card);
+			return err;
+		}
+	}
+
+	if (!(ice->eeprom.codec & ICE1712_CFG_NO_CON_AC97))
+		if ((err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL)) < 0) {
+			snd_card_free(card);
+			return err;
+		}
+
+	if (! c->no_mpu401) {
+		if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
+					       ICEREG(ice, MPU1_CTRL), 1,
+					       ice->irq, 0,
+					       &ice->rmidi[0])) < 0) {
+			snd_card_free(card);
+			return err;
+		}
+
+		if (ice->eeprom.codec & ICE1712_CFG_2xMPU401)
+			if ((err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
+						       ICEREG(ice, MPU2_CTRL), 1,
+						       ice->irq, 0,
+						       &ice->rmidi[1])) < 0) {
+				snd_card_free(card);
+				return err;
+			}
+	}
+
+	sprintf(card->longname, "%s at 0x%lx, irq %i",
+		card->shortname, ice->port, ice->irq);
+
+	if ((err = snd_card_register(card)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	pci_set_drvdata(pci, card);
+	dev++;
+	return 0;
+}
+
+static void __devexit snd_ice1712_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+	.name = "ICE1712",
+	.id_table = snd_ice1712_ids,
+	.probe = snd_ice1712_probe,
+	.remove = __devexit_p(snd_ice1712_remove),
+};
+
+static int __init alsa_card_ice1712_init(void)
+{
+	int err;
+
+	if ((err = pci_module_init(&driver)) < 0) {
+#ifdef MODULE
+		printk(KERN_ERR "ICE1712 soundcard not found or device busy\n");
+#endif
+		return err;
+	}
+	return 0;
+}
+
+static void __exit alsa_card_ice1712_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_ice1712_init)
+module_exit(alsa_card_ice1712_exit)
+
+#ifndef MODULE
+
+/* format is: snd-ice1712=snd_enable,snd_index,snd_id */
+
+static int __init alsa_card_ice1712_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
+	       get_option(&str,&snd_index[nr_dev]) == 2 &&
+	       get_id(&str,&snd_id[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-ice1712=", alsa_card_ice1712_setup);
+
+#endif /* ifndef MODULE */
diff -Nru a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ice1712/ice1712.h	Tue Oct  1 17:11:34 2002
@@ -0,0 +1,388 @@
+#ifndef __SOUND_ICE1712_H
+#define __SOUND_ICE1712_H
+
+/*
+ *   ALSA driver for ICEnsemble ICE1712 (Envy24)
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *
+ *   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/control.h>
+#include <sound/ac97_codec.h>
+#include <sound/rawmidi.h>
+#include <sound/i2c.h>
+#include <sound/pcm.h>
+
+
+/*
+ *  Direct registers
+ */
+
+#define ICEREG(ice, x) ((ice)->port + ICE1712_REG_##x)
+
+#define ICE1712_REG_CONTROL		0x00	/* byte */
+#define   ICE1712_RESET			0x80	/* reset whole chip */
+#define   ICE1712_SERR_LEVEL		0x04	/* SERR# level otherwise edge */
+#define   ICE1712_NATIVE		0x01	/* native mode otherwise SB */
+#define ICE1712_REG_IRQMASK		0x01	/* byte */
+#define   ICE1712_IRQ_MPU1		0x80
+#define   ICE1712_IRQ_TIMER		0x40
+#define   ICE1712_IRQ_MPU2		0x20
+#define   ICE1712_IRQ_PROPCM		0x10
+#define   ICE1712_IRQ_FM		0x08	/* FM/MIDI - legacy */
+#define   ICE1712_IRQ_PBKDS		0x04	/* playback DS channels */
+#define   ICE1712_IRQ_CONCAP		0x02	/* consumer capture */
+#define   ICE1712_IRQ_CONPBK		0x01	/* consumer playback */
+#define ICE1712_REG_IRQSTAT		0x02	/* byte */
+/* look to ICE1712_IRQ_* */
+#define ICE1712_REG_INDEX		0x03	/* byte - indirect CCIxx regs */
+#define ICE1712_REG_DATA		0x04	/* byte - indirect CCIxx regs */
+#define ICE1712_REG_NMI_STAT1		0x05	/* byte */
+#define ICE1712_REG_NMI_DATA		0x06	/* byte */
+#define ICE1712_REG_NMI_INDEX		0x07	/* byte */
+#define ICE1712_REG_AC97_INDEX		0x08	/* byte */
+#define ICE1712_REG_AC97_CMD		0x09	/* byte */
+#define   ICE1712_AC97_COLD		0x80	/* cold reset */
+#define   ICE1712_AC97_WARM		0x40	/* warm reset */
+#define   ICE1712_AC97_WRITE		0x20	/* W: write, R: write in progress */
+#define   ICE1712_AC97_READ		0x10	/* W: read, R: read in progress */
+#define   ICE1712_AC97_READY		0x08	/* codec ready status bit */
+#define   ICE1712_AC97_PBK_VSR		0x02	/* playback VSR */
+#define   ICE1712_AC97_CAP_VSR		0x01	/* capture VSR */
+#define ICE1712_REG_AC97_DATA		0x0a	/* word (little endian) */
+#define ICE1712_REG_MPU1_CTRL		0x0c	/* byte */
+#define ICE1712_REG_MPU1_DATA		0x0d	/* byte */
+#define ICE1712_REG_I2C_DEV_ADDR	0x10	/* byte */
+#define   ICE1712_I2C_WRITE		0x01	/* write direction */
+#define ICE1712_REG_I2C_BYTE_ADDR	0x11	/* byte */
+#define ICE1712_REG_I2C_DATA		0x12	/* byte */
+#define ICE1712_REG_I2C_CTRL		0x13	/* byte */
+#define   ICE1712_I2C_EEPROM		0x80	/* EEPROM exists */
+#define   ICE1712_I2C_BUSY		0x01	/* busy bit */
+#define ICE1712_REG_CONCAP_ADDR		0x14	/* dword - consumer capture */
+#define ICE1712_REG_CONCAP_COUNT	0x18	/* word - current/base count */
+#define ICE1712_REG_SERR_SHADOW		0x1b	/* byte */
+#define ICE1712_REG_MPU2_CTRL		0x1c	/* byte */
+#define ICE1712_REG_MPU2_DATA		0x1d	/* byte */
+#define ICE1712_REG_TIMER		0x1e	/* word */
+
+/*
+ *  Indirect registers
+ */
+
+#define ICE1712_IREG_PBK_COUNT_HI	0x00
+#define ICE1712_IREG_PBK_COUNT_LO	0x01
+#define ICE1712_IREG_PBK_CTRL		0x02
+#define ICE1712_IREG_PBK_LEFT		0x03	/* left volume */
+#define ICE1712_IREG_PBK_RIGHT		0x04	/* right volume */
+#define ICE1712_IREG_PBK_SOFT		0x05	/* soft volume */
+#define ICE1712_IREG_PBK_RATE_LO	0x06
+#define ICE1712_IREG_PBK_RATE_MID	0x07
+#define ICE1712_IREG_PBK_RATE_HI	0x08
+#define ICE1712_IREG_CAP_COUNT_HI	0x10
+#define ICE1712_IREG_CAP_COUNT_LO	0x11
+#define ICE1712_IREG_CAP_CTRL		0x12
+#define ICE1712_IREG_GPIO_DATA		0x20
+#define ICE1712_IREG_GPIO_WRITE_MASK	0x21
+#define ICE1712_IREG_GPIO_DIRECTION	0x22
+#define ICE1712_IREG_CONSUMER_POWERDOWN	0x30
+#define ICE1712_IREG_PRO_POWERDOWN	0x31
+
+/*
+ *  Consumer section direct DMA registers
+ */
+
+#define ICEDS(ice, x) ((ice)->dmapath_port + ICE1712_DS_##x)
+ 
+#define ICE1712_DS_INTMASK		0x00	/* word - interrupt mask */
+#define ICE1712_DS_INTSTAT		0x02	/* word - interrupt status */
+#define ICE1712_DS_DATA			0x04	/* dword - channel data */
+#define ICE1712_DS_INDEX		0x08	/* dword - channel index */
+
+/*
+ *  Consumer section channel registers
+ */
+ 
+#define ICE1712_DSC_ADDR0		0x00	/* dword - base address 0 */
+#define ICE1712_DSC_COUNT0		0x01	/* word - count 0 */
+#define ICE1712_DSC_ADDR1		0x02	/* dword - base address 1 */
+#define ICE1712_DSC_COUNT1		0x03	/* word - count 1 */
+#define ICE1712_DSC_CONTROL		0x04	/* byte - control & status */
+#define   ICE1712_BUFFER1		0x80	/* buffer1 is active */
+#define   ICE1712_BUFFER1_AUTO		0x40	/* buffer1 auto init */
+#define   ICE1712_BUFFER0_AUTO		0x20	/* buffer0 auto init */
+#define   ICE1712_FLUSH			0x10	/* flush FIFO */
+#define   ICE1712_STEREO		0x08	/* stereo */
+#define   ICE1712_16BIT			0x04	/* 16-bit data */
+#define   ICE1712_PAUSE			0x02	/* pause */
+#define   ICE1712_START			0x01	/* start */
+#define ICE1712_DSC_RATE		0x05	/* dword - rate */
+#define ICE1712_DSC_VOLUME		0x06	/* word - volume control */
+
+/* 
+ *  Professional multi-track direct control registers
+ */
+
+#define ICEMT(ice, x) ((ice)->profi_port + ICE1712_MT_##x)
+
+#define ICE1712_MT_IRQ			0x00	/* byte - interrupt mask */
+#define   ICE1712_MULTI_CAPTURE		0x80	/* capture IRQ */
+#define   ICE1712_MULTI_PLAYBACK	0x40	/* playback IRQ */
+#define   ICE1712_MULTI_CAPSTATUS	0x02	/* capture IRQ status */
+#define   ICE1712_MULTI_PBKSTATUS	0x01	/* playback IRQ status */
+#define ICE1712_MT_RATE			0x01	/* byte - sampling rate select */
+#define   ICE1712_SPDIF_MASTER		0x10	/* S/PDIF input is master clock */
+#define ICE1712_MT_I2S_FORMAT		0x02	/* byte - I2S data format */
+#define ICE1712_MT_AC97_INDEX		0x04	/* byte - AC'97 index */
+#define ICE1712_MT_AC97_CMD		0x05	/* byte - AC'97 command & status */
+/* look to ICE1712_AC97_* */
+#define ICE1712_MT_AC97_DATA		0x06	/* word - AC'97 data */
+#define ICE1712_MT_PLAYBACK_ADDR	0x10	/* dword - playback address */
+#define ICE1712_MT_PLAYBACK_SIZE	0x14	/* word - playback size */
+#define ICE1712_MT_PLAYBACK_COUNT	0x16	/* word - playback count */
+#define ICE1712_MT_PLAYBACK_CONTROL	0x18	/* byte - control */
+#define   ICE1712_CAPTURE_START_SHADOW	0x04	/* capture start */
+#define   ICE1712_PLAYBACK_PAUSE	0x02	/* playback pause */
+#define   ICE1712_PLAYBACK_START	0x01	/* playback start */
+#define ICE1712_MT_CAPTURE_ADDR		0x20	/* dword - capture address */
+#define ICE1712_MT_CAPTURE_SIZE		0x24	/* word - capture size */
+#define ICE1712_MT_CAPTURE_COUNT	0x26	/* word - capture count */
+#define ICE1712_MT_CAPTURE_CONTROL	0x28	/* byte - control */
+#define   ICE1712_CAPTURE_START		0x01	/* capture start */
+#define ICE1712_MT_ROUTE_PSDOUT03	0x30	/* word */
+#define ICE1712_MT_ROUTE_SPDOUT		0x32	/* word */
+#define ICE1712_MT_ROUTE_CAPTURE	0x34	/* dword */
+#define ICE1712_MT_MONITOR_VOLUME	0x38	/* word */
+#define ICE1712_MT_MONITOR_INDEX	0x3a	/* byte */
+#define ICE1712_MT_MONITOR_RATE		0x3b	/* byte */
+#define ICE1712_MT_MONITOR_ROUTECTRL	0x3c	/* byte */
+#define   ICE1712_ROUTE_AC97		0x01	/* route digital mixer output to AC'97 */
+#define ICE1712_MT_MONITOR_PEAKINDEX	0x3e	/* byte */
+#define ICE1712_MT_MONITOR_PEAKDATA	0x3f	/* byte */
+
+/*
+ *  Codec configuration bits
+ */
+
+/* PCI[60] System Configuration */
+#define ICE1712_CFG_CLOCK	0xc0
+#define   ICE1712_CFG_CLOCK512	0x00	/* 22.5692Mhz, 44.1kHz*512 */
+#define   ICE1712_CFG_CLOCK384  0x40	/* 16.9344Mhz, 44.1kHz*384 */
+#define   ICE1712_CFG_EXT	0x80	/* external clock */
+#define ICE1712_CFG_2xMPU401	0x20	/* two MPU401 UARTs */
+#define ICE1712_CFG_NO_CON_AC97 0x10	/* consumer AC'97 codec is not present */
+#define ICE1712_CFG_ADC_MASK	0x0c	/* one, two, three, four stereo ADCs */
+#define ICE1712_CFG_DAC_MASK	0x03	/* one, two, three, four stereo DACs */
+/* PCI[61] AC-Link Configuration */
+#define ICE1712_CFG_PRO_I2S	0x80	/* multitrack converter: I2S or AC'97 */
+#define ICE1712_CFG_AC97_PACKED	0x01	/* split or packed mode - AC'97 */
+/* PCI[62] I2S Features */
+#define ICE1712_CFG_I2S_VOLUME	0x80	/* volume/mute capability */
+#define ICE1712_CFG_I2S_96KHZ	0x40	/* supports 96kHz sampling */
+#define ICE1712_CFG_I2S_RESMASK	0x30	/* resolution mask, 16,18,20,24-bit */
+#define ICE1712_CFG_I2S_OTHER	0x0f	/* other I2S IDs */
+/* PCI[63] S/PDIF Configuration */
+#define ICE1712_CFG_I2S_CHIPID	0xfc	/* I2S chip ID */
+#define ICE1712_CFG_SPDIF_IN	0x02	/* S/PDIF input is present */
+#define ICE1712_CFG_SPDIF_OUT	0x01	/* S/PDIF output is present */
+
+/*
+ * DMA mode values
+ * identical with DMA_XXX on i386 architecture.
+ */
+#define ICE1712_DMA_MODE_WRITE		0x48
+#define ICE1712_DMA_AUTOINIT		0x10
+
+
+/*
+ *  
+ */
+
+typedef struct _snd_ice1712 ice1712_t;
+typedef struct snd_ak4524 ak4524_t;
+
+typedef struct {
+	unsigned int subvendor;	/* PCI[2c-2f] */
+	unsigned char size;	/* size of EEPROM image in bytes */
+	unsigned char version;	/* must be 1 */
+	unsigned char codec;	/* codec configuration PCI[60] */
+	unsigned char aclink;	/* ACLink configuration PCI[61] */
+	unsigned char i2sID;	/* PCI[62] */
+	unsigned char spdif;	/* S/PDIF configuration PCI[63] */
+	unsigned char gpiomask;	/* GPIO initial mask, 0 = write, 1 = don't */
+	unsigned char gpiostate; /* GPIO initial state */
+	unsigned char gpiodir;	/* GPIO direction state */
+	unsigned short ac97main;
+	unsigned short ac97pcm;
+	unsigned short ac97rec;
+	unsigned char ac97recsrc;
+	unsigned char dacID[4];	/* I2S IDs for DACs */
+	unsigned char adcID[4];	/* I2S IDs for ADCs */
+	unsigned char extra[4];
+} ice1712_eeprom_t;
+
+struct snd_ak4524 {
+	int num_adcs;			/* AK4524 or AK4528 ADCs */
+	int num_dacs;			/* AK4524 or AK4528 DACs */
+	unsigned char images[4][8];
+	unsigned char ipga_gain[4][2];
+	/* */
+	unsigned int is_ak4528: 1;	/* AK4524 or AK4528 */
+	unsigned int cif: 1;
+	unsigned char data_mask;
+	unsigned char clk_mask;
+	unsigned char codecs_mask;
+	unsigned char add_flags;
+	struct snd_ak4524_ops {
+		int (*start)(ice1712_t *, unsigned char *, int);
+		void (*stop)(ice1712_t *, unsigned char *);
+		void (*set_rate_val)(ice1712_t *, unsigned char);
+	} ops;
+};
+
+struct snd_ice1712_spdif {
+	unsigned char cs8403_bits;
+	unsigned char cs8403_stream_bits;
+	snd_kcontrol_t *stream_ctl;
+
+	struct snd_ice1712_spdif_ops {
+		void (*open)(ice1712_t *, snd_pcm_substream_t *);
+		void (*setup)(ice1712_t *, snd_pcm_substream_t *);
+		void (*close)(ice1712_t *, snd_pcm_substream_t *);
+		void (*default_get)(ice1712_t *, snd_ctl_elem_value_t * ucontrol);
+		int (*default_put)(ice1712_t *, snd_ctl_elem_value_t * ucontrol);
+		void (*stream_get)(ice1712_t *, snd_ctl_elem_value_t * ucontrol);
+		int (*stream_put)(ice1712_t *, snd_ctl_elem_value_t * ucontrol);
+	} ops;
+};
+
+
+struct _snd_ice1712 {
+	unsigned long conp_dma_size;
+	unsigned long conc_dma_size;
+	unsigned long prop_dma_size;
+	unsigned long proc_dma_size;
+	int irq;
+
+	unsigned long port;
+	struct resource *res_port;
+	unsigned long ddma_port;
+	struct resource *res_ddma_port;
+	unsigned long dmapath_port;
+	struct resource *res_dmapath_port;
+	unsigned long profi_port;
+	struct resource *res_profi_port;
+
+	unsigned int config;	/* system configuration */
+
+	struct pci_dev *pci;
+	snd_card_t *card;
+	snd_pcm_t *pcm;
+	snd_pcm_t *pcm_ds;
+	snd_pcm_t *pcm_pro;
+        snd_pcm_substream_t *playback_con_substream;
+        snd_pcm_substream_t *playback_con_substream_ds[6];
+        snd_pcm_substream_t *capture_con_substream;
+        snd_pcm_substream_t *playback_pro_substream;
+        snd_pcm_substream_t *capture_pro_substream;
+	unsigned int playback_pro_size;
+	unsigned int capture_pro_size;
+	unsigned int playback_con_virt_addr[6];
+	unsigned int playback_con_active_buf[6];
+	unsigned int capture_con_virt_addr;
+	unsigned int ac97_ext_id;
+	ac97_t *ac97;
+	snd_rawmidi_t *rmidi[2];
+
+	spinlock_t reg_lock;
+	struct semaphore gpio_mutex;
+	snd_info_entry_t *proc_entry;
+
+	ice1712_eeprom_t eeprom;
+
+	unsigned int pro_volumes[20];
+	int omni: 1;			/* Delta Omni I/O */
+	int num_total_dacs;		/* total DACs */
+	unsigned char hoontech_boxbits[4];
+	unsigned int hoontech_config;
+	unsigned short hoontech_boxconfig[4];
+
+	struct snd_ak4524 ak4524;
+	struct snd_ice1712_spdif spdif;
+
+	snd_i2c_bus_t *i2c;		/* I2C bus */
+	snd_i2c_device_t *cs8404;	/* CS8404A I2C device */
+	snd_i2c_device_t *cs8427;	/* CS8427 I2C device */
+	snd_i2c_device_t *i2cdevs[2];	/* additional i2c devices */
+	
+	unsigned char gpio_direction, gpio_write_mask;
+};
+
+#define chip_t ice1712_t
+
+
+#define ICE1712_GPIO(xiface, xname, xindex, mask, invert, xaccess) \
+{ .iface = xiface, .name = xname, .access = xaccess, .info = snd_ice1712_gpio_info, \
+  .get = snd_ice1712_gpio_get, .put = snd_ice1712_gpio_put, \
+  .private_value = mask | (invert << 24) }
+
+int snd_ice1712_gpio_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
+int snd_ice1712_gpio_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_ice1712_gpio_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+
+void snd_ice1712_gpio_write_bits(ice1712_t *ice, int mask, int bits);
+void snd_ice1712_save_gpio_status(ice1712_t *ice, unsigned char *tmp);
+void snd_ice1712_restore_gpio_status(ice1712_t *ice, unsigned char *tmp);
+
+
+int snd_ice1712_spdif_build_controls(ice1712_t *ice);
+
+void snd_ice1712_ak4524_write(ice1712_t *ice, int chip, unsigned char addr, unsigned char data);
+void snd_ice1712_ak4524_reset(ice1712_t *ice, int state);
+void snd_ice1712_ak4524_init(ice1712_t *ice);
+int snd_ice1712_ak4524_build_controls(ice1712_t *ice);
+
+int snd_ice1712_init_cs8427(ice1712_t *ice, int addr);
+
+static inline void snd_ice1712_write(ice1712_t * ice, u8 addr, u8 data)
+{
+	outb(addr, ICEREG(ice, INDEX));
+	outb(data, ICEREG(ice, DATA));
+}
+
+static inline u8 snd_ice1712_read(ice1712_t * ice, u8 addr)
+{
+	outb(addr, ICEREG(ice, INDEX));
+	return inb(ICEREG(ice, DATA));
+}
+
+
+/*
+ * entry pointer
+ */
+
+struct snd_ice1712_card_info {
+	unsigned int subvendor;
+	char *name;
+	int (*chip_init)(ice1712_t *);
+	int (*build_controls)(ice1712_t *);
+	int no_mpu401: 1;
+};
+
+
+#endif /* __SOUND_ICE1712_H */

===================================================================


This BitKeeper patch contains the following changesets:
1.654
## Wrapped with gzip_uu ##


begin 664 bkpatch23248
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
A#R>Q^K-W@E%L.&SL]/KR"8`M[Y2*_=7_'\Y#L,<'MP(`
`
end
