Index: alsa-driver/alsa-kernel/include/emu10k1.h
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/include/emu10k1.h,v
retrieving revision 1.51
diff -u -r1.51 emu10k1.h
--- alsa-driver/alsa-kernel/include/emu10k1.h	17 Nov 2004 13:38:10 -0000	1.51
+++ alsa-driver/alsa-kernel/include/emu10k1.h	21 Nov 2004 01:56:37 -0000
@@ -840,10 +840,10 @@
 ((route[0] | (route[1] << 4) | (route[2] << 8) | (route[3] << 12)) << 16)
 
 #define snd_emu10k1_compose_audigy_fxrt1(route) \
-(((unsigned int)route[0] | ((unsigned int)route[1] << 8) | ((unsigned int)route[2] << 16) | ((unsigned int)route[3] << 12)) << 24)
+((unsigned int)route[0] | ((unsigned int)route[1] << 8) | ((unsigned int)route[2] << 16) | ((unsigned int)route[3] << 24))
 
 #define snd_emu10k1_compose_audigy_fxrt2(route) \
-(((unsigned int)route[4] | ((unsigned int)route[5] << 8) | ((unsigned int)route[6] << 16) | ((unsigned int)route[7] << 12)) << 24)
+((unsigned int)route[4] | ((unsigned int)route[5] << 8) | ((unsigned int)route[6] << 16) | ((unsigned int)route[7] << 24))
 
 typedef struct snd_emu10k1_memblk {
 	snd_util_memblk_t mem;
Index: alsa-driver/alsa-kernel/pci/emu10k1/emu10k1.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/emu10k1.c,v
retrieving revision 1.29
diff -u -r1.29 emu10k1.c
--- alsa-driver/alsa-kernel/pci/emu10k1/emu10k1.c	10 Nov 2004 09:49:12 -0000	1.29
+++ alsa-driver/alsa-kernel/pci/emu10k1/emu10k1.c	21 Nov 2004 01:56:37 -0000
@@ -2,6 +2,9 @@
  *  The driver for the EMU10K1 (SB Live!) based soundcards
  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
  *
+ *  Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ *      Added support for Audigy 2 Value.
+ *
  *
  *   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
@@ -17,6 +20,7 @@
  *   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>
@@ -68,12 +72,27 @@
 module_param_array(enable_ir, bool, NULL, 0444);
 MODULE_PARM_DESC(enable_ir, "Enable IR.");
 
+/*
+ * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value  Model:SB0400
+ */
 static struct pci_device_id snd_emu10k1_ids[] = {
 	{ 0x1102, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	/* EMU10K1 */
 	{ 0x1102, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },	/* Audigy */
+	{ 0x1102, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },	/* Audigy 2 Value SB0400 */
 	{ 0, }
 };
 
+/*
+ * Audigy 2 Value notes:
+ * A_IOCFG Input (GPIO)
+ * 0x400  = Front analog jack plugged in. (Green socket)
+ * 0x1000 = Read analog jack plugged in. (Black socket)
+ * 0x2000 = Center/LFE analog jack plugged in. (Orange socket)
+ * A_IOCFG Output (GPIO)
+ * 0x60 = Sound out of front Left.
+ * Win sets it to 0xXX61
+ */
+
 MODULE_DEVICE_TABLE(pci, snd_emu10k1_ids);
 
 static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
@@ -161,7 +180,10 @@
 	}
 #endif
  
-	if (emu->audigy && (emu->revision == 4) ) {
+	if (emu->audigy && (emu->serial == 0x10011102) ) {
+		strcpy(card->driver, "Audigy2");
+		strcpy(card->shortname, "Sound Blaster Audigy2_Value");
+	} else if (emu->audigy && (emu->revision == 4) ) {
 		strcpy(card->driver, "Audigy2");
 		strcpy(card->shortname, "Sound Blaster Audigy2");
 	} else if (emu->audigy) {
@@ -174,7 +196,7 @@
 		strcpy(card->driver, "EMU10K1");
 		strcpy(card->shortname, "Sound Blaster Live!");
 	}
-	sprintf(card->longname, "%s (rev.%d) at 0x%lx, irq %i", card->shortname, emu->revision, emu->port, emu->irq);
+	sprintf(card->longname, "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", card->shortname, emu->revision, emu->serial, emu->port, emu->irq);
 
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
Index: alsa-driver/alsa-kernel/pci/emu10k1/emu10k1_main.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/emu10k1_main.c,v
retrieving revision 1.39
diff -u -r1.39 emu10k1_main.c
--- alsa-driver/alsa-kernel/pci/emu10k1/emu10k1_main.c	18 Nov 2004 14:52:51 -0000	1.39
+++ alsa-driver/alsa-kernel/pci/emu10k1/emu10k1_main.c	21 Nov 2004 01:56:37 -0000
@@ -3,6 +3,10 @@
  *                   Creative Labs, Inc.
  *  Routines for control of EMU10K1 chips
  *
+ *  Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
+ *      Added support for Audigy 2 Value.
+ *
+ *
  *  BUGS:
  *    --
  *
@@ -183,6 +187,26 @@
 		outl(0x6E0000, emu->port + 0x20);
 		outl(0xFF00FF00, emu->port + 0x24);
 	}
+	if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */
+		/* Hacks for Alice3 to work independent of haP16V driver */
+		u32 tmp;
+
+		snd_printk(KERN_ERR "Audigy2 value:Special config.\n");
+		//Setup SRCMulti_I2S SamplingRate
+		tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
+		tmp &= 0xfffff1ff;
+		tmp |= (0x2<<9);
+		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
+
+		/* Setup SRCSel (Enable Spdif,I2S SRCMulti) */
+		outl(0x600000, emu->port + 0x20);
+		outl(0x14, emu->port + 0x24);
+
+		/* Setup SRCMulti Input Audio Enable */
+		outl(0x7b0000, emu->port + 0x20);
+		outl(0xFF000000, emu->port + 0x24);
+	}
+
 
 	/*
 	 *  Clear page with silence & setup all pointers to this page
@@ -267,6 +291,9 @@
 			 * This has to be done after init ALice3 I2SOut beyond 48KHz.
 			 * So, sequence is important. */
 			outl(inl(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG);
+		} else if (emu->serial == 0x10011102) { /* audigy2 value */
+			/* Unmute Analog now. */
+			outl(inl(emu->port + A_IOCFG) | 0x0060, emu->port + A_IOCFG);
 		} else {
 			/* Disable routing from AC97 line out to Front speakers */
 			outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG);
@@ -590,7 +617,7 @@
 	*remu = NULL;
 
 	// is_audigy = (int)pci->driver_data;
-	is_audigy = (pci->device == 0x0004);
+	is_audigy = (pci->device == 0x0004) || ( (pci->device == 0x0008) );
 
 	/* enable PCI device */
 	if ((err = pci_enable_device(pci)) < 0)
Index: alsa-driver/alsa-kernel/pci/emu10k1/emufx.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/emufx.c,v
retrieving revision 1.63
diff -u -r1.63 emufx.c
--- alsa-driver/alsa-kernel/pci/emu10k1/emufx.c	10 Nov 2004 11:54:36 -0000	1.63
+++ alsa-driver/alsa-kernel/pci/emu10k1/emufx.c	21 Nov 2004 01:56:37 -0000
@@ -1351,8 +1351,12 @@
 	A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
 
 	/* ADC buffer */
+#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
+	A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
+#else
 	A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
 	A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
+#endif
 
 	/*
 	 * ok, set up done..
Index: alsa-driver/alsa-kernel/pci/emu10k1/emuproc.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/emuproc.c,v
retrieving revision 1.21
diff -u -r1.21 emuproc.c
--- alsa-driver/alsa-kernel/pci/emu10k1/emuproc.c	6 Sep 2004 15:05:19 -0000	1.21
+++ alsa-driver/alsa-kernel/pci/emu10k1/emuproc.c	21 Nov 2004 01:56:38 -0000
@@ -309,6 +309,153 @@
 	return 0;
 }
 
+#ifdef CONFIG_SND_DEBUG
+static void snd_emu_proc_io_reg_read(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer)
+{
+        emu10k1_t *emu = entry->private_data;
+        unsigned long value;
+        unsigned long flags;
+        int i;
+        snd_iprintf(buffer, "IO Registers:\n\n");
+        for(i = 0; i < 0x40; i+=4) {
+                spin_lock_irqsave(&emu->emu_lock, flags);
+                value = inl(emu->port + i);
+                spin_unlock_irqrestore(&emu->emu_lock, flags);
+                snd_iprintf(buffer, "%02X: %08lX\n", i, value);
+        }
+}
+
+static void snd_emu_proc_io_reg_write(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer)
+{
+        emu10k1_t *emu = entry->private_data;
+        unsigned long flags;
+        char line[64];
+        u32 reg, val;
+        while (!snd_info_get_line(buffer, line, sizeof(line))) {
+                if (sscanf(line, "%x %x", &reg, &val) != 2)
+                        continue;
+                if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) {
+                        spin_lock_irqsave(&emu->emu_lock, flags);
+                        outl(val, emu->port + (reg & 0xfffffffc));
+                        spin_unlock_irqrestore(&emu->emu_lock, flags);
+                }
+        }
+}
+
+static unsigned int snd_ptr_read(emu10k1_t * emu,
+					  unsigned int iobase,
+                                          unsigned int reg,
+                                          unsigned int chn)
+{
+        unsigned long flags;
+        unsigned int regptr, val;
+
+        regptr = (reg << 16) | chn;
+
+        spin_lock_irqsave(&emu->emu_lock, flags);
+        outl(regptr, emu->port + iobase + PTR);
+        val = inl(emu->port + iobase + DATA);
+        spin_unlock_irqrestore(&emu->emu_lock, flags);
+        return val;
+}
+
+static void snd_ptr_write(emu10k1_t *emu,
+				   unsigned int iobase,
+                                   unsigned int reg,
+                                   unsigned int chn,
+                                   unsigned int data)
+{
+        unsigned int regptr;
+        unsigned long flags;
+
+        regptr = (reg << 16) | chn;
+
+        spin_lock_irqsave(&emu->emu_lock, flags);
+        outl(regptr, emu->port + iobase + PTR);
+        outl(data, emu->port + iobase + DATA);
+        spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+
+static void snd_emu_proc_ptr_reg_read(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer, int iobase, int offset, int length)
+{
+        emu10k1_t *emu = entry->private_data;
+        unsigned long value;
+        int i,j;
+        if (offset+length > 0x80) {
+		snd_iprintf(buffer, "Input values out of range\n");
+		return;
+	}
+        snd_iprintf(buffer, "Registers 0x%x\n", iobase);
+        for(i = offset; i < offset+length; i++) {
+                snd_iprintf(buffer, "%02X: ",i);
+                for (j = 0; j < 4; j++) {
+			if(iobase == 0) {
+                		value = snd_ptr_read(emu, 0, i, j);
+			} else {
+                		value = snd_ptr_read(emu, 0x20, i, j);
+			}
+                  snd_iprintf(buffer, "%08lX ", value);
+                }
+                snd_iprintf(buffer, "\n");
+        }
+}
+
+static void snd_emu_proc_ptr_reg_write(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer, int iobase)
+{
+        emu10k1_t *emu = entry->private_data;
+        char line[64];
+        unsigned int reg, channel_id , val;
+        while (!snd_info_get_line(buffer, line, sizeof(line))) {
+                if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
+                        continue;
+                if ((reg < 0x80) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) )
+                        snd_ptr_write(emu, iobase, reg, channel_id, val);
+        }
+}
+static void snd_emu_proc_ptr_reg_write00(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer)
+{
+	snd_emu_proc_ptr_reg_write(entry, buffer, 0);
+}
+
+static void snd_emu_proc_ptr_reg_write20(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer)
+{
+	snd_emu_proc_ptr_reg_write(entry, buffer, 0x20);
+}
+	
+
+
+static void snd_emu_proc_ptr_reg_read00a(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer)
+{
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0, 0x40);
+}
+
+static void snd_emu_proc_ptr_reg_read00b(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer)
+{
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0x40, 0x40);
+}
+
+static void snd_emu_proc_ptr_reg_read20a(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer)
+{
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0, 0x40);
+}
+
+static void snd_emu_proc_ptr_reg_read20b(snd_info_entry_t *entry,
+                                       snd_info_buffer_t * buffer)
+{
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0x40, 0x40);
+}
+#endif
+
 static struct snd_info_entry_ops snd_emu10k1_proc_ops_fx8010 = {
 	.read = snd_emu10k1_fx8010_read,
 };
@@ -316,6 +463,33 @@
 int __devinit snd_emu10k1_proc_init(emu10k1_t * emu)
 {
 	snd_info_entry_t *entry;
+#ifdef CONFIG_SND_DEBUG
+	if(! snd_card_proc_new(emu->card, "io_regs", &entry)) {
+                snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read);
+                entry->c.text.write_size = 64;
+                entry->c.text.write = snd_emu_proc_io_reg_write;
+        }
+	if(! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) {
+                snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_ptr_reg_read00a);
+                entry->c.text.write_size = 64;
+                entry->c.text.write = snd_emu_proc_ptr_reg_write00;
+        }
+	if(! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) {
+                snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_ptr_reg_read00b);
+                entry->c.text.write_size = 64;
+                entry->c.text.write = snd_emu_proc_ptr_reg_write00;
+        }
+	if(! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) {
+                snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_ptr_reg_read20a);
+                entry->c.text.write_size = 64;
+                entry->c.text.write = snd_emu_proc_ptr_reg_write20;
+        }
+	if(! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) {
+                snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_ptr_reg_read20b);
+                entry->c.text.write_size = 64;
+                entry->c.text.write = snd_emu_proc_ptr_reg_write20;
+        }
+#endif
 	
 	if (! snd_card_proc_new(emu->card, "emu10k1", &entry))
 		snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1_proc_read);

