diff -ru alsa-v009-test/alsa-kernel/include/emu10k1.h alsa-old/alsa-kernel/include/emu10k1.h
--- alsa-v009-test/alsa-kernel/include/emu10k1.h	2005-02-10 16:55:56.000000000 -0500
+++ alsa-old/alsa-kernel/include/emu10k1.h	2005-02-10 22:50:18.000000000 -0500
@@ -279,12 +279,12 @@
 #define A_IOCFG_DISABLE_AC97_FRONT      0x0080  /* turn off ac97 front -> front (10k2.1)	*/
 #define A_IOCFG_GPOUT1		0x0002		/* IR? drive's internal bypass (?)		*/
 #define A_IOCFG_GPOUT2		0x0001		/* IR */
+#define A_IOCFG_DIGITAL_JACK    0x1000          /* digital for a2 platinum			*/
+#define A_IOCFG_REAR_JACK       0x8000		/* analog rear					*/
+#define A_IOCFG_FRONT_JACK      0x4000		/* analog front					*/
 #define A_IOCFG_MULTIPURPOSE_JACK	0x2000  /* center+lfe+rear_center (a2/a2ex)		*/
                                                 /* + digital for generic 10k2			*/
-#define A_IOCFG_DIGITAL_JACK    0x1000          /* digital for a2 platinum			*/
-#define A_IOCFG_FRONT_JACK      0x4000
-#define A_IOCFG_REAR_JACK       0x8000
-#define A_IOCFG_PHONES_JACK     0x0100          /* LiveDrive					*/
+#define A_IOCFG_PHONES_JACK     0x0100          /* LiveDrive headphones				*/
 
 /* outputs:
  *	for audigy2 platinum:	0xa00
@@ -794,9 +794,6 @@
 #define A_SPDIF_44100		0x00000040
 #define A_SPDIF_96000		0x00000080
 
-/* 0x77,0x78,0x79 "something i2s-related" - default to 0x01080000 on my audigy 2 ZS --rlrevell	*/
-/* 0x7a, 0x7b - lookup tables */
-
 #define A_FXRT2			0x7c
 #define A_FXRT_CHANNELE		0x0000003f	/* Effects send bus number for channel's effects send E	*/
 #define A_FXRT_CHANNELF		0x00003f00	/* Effects send bus number for channel's effects send F	*/
@@ -875,7 +872,7 @@
 struct _snd_emu10k1_voice {
 	emu10k1_t *emu;
 	int number;
-	int use: 1,
+	unsigned int use: 1,
 	    pcm: 1,
 	    efx: 1,
 	    synth: 1,
@@ -1099,6 +1096,7 @@
 	emu10k1_midi_t midi2; /* for audigy */
 
 	unsigned int efx_voices_mask[2];
+	unsigned int input_monitor[1];
 	unsigned int next_free_voice;
 };
 
diff -ru alsa-v009-test/alsa-kernel/pci/emu10k1/emufx.c alsa-old/alsa-kernel/pci/emu10k1/emufx.c
--- alsa-v009-test/alsa-kernel/pci/emu10k1/emufx.c	2005-02-02 06:52:46.000000000 -0500
+++ alsa-old/alsa-kernel/pci/emu10k1/emufx.c	2005-02-07 06:59:13.000000000 -0500
@@ -323,6 +323,8 @@
 	return 0;
 }
 
+/* GPR mixer controls */
+
 static int snd_emu10k1_gpr_ctl_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
@@ -1143,7 +1145,7 @@
 					emu->no_ac97 ? "Line Capture Volume" : "Line2 Capture Volume",
 					gpr, 0);
 	gpr += 2;
-        
+
 	/* Philips ADC Playback Volume */
 	A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
 	A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
diff -ru alsa-v009-test/alsa-kernel/pci/emu10k1/emumixer.c alsa-old/alsa-kernel/pci/emu10k1/emumixer.c
--- alsa-v009-test/alsa-kernel/pci/emu10k1/emumixer.c	2005-02-10 16:55:56.000000000 -0500
+++ alsa-old/alsa-kernel/pci/emu10k1/emumixer.c	2005-02-10 22:57:38.000000000 -0500
@@ -161,11 +161,11 @@
 	unsigned int val;
 	unsigned long flags;
 
+	spin_lock_irqsave(&emu->reg_lock, flags);
 	val = (ucontrol->value.iec958.status[0] << 0) |
 	      (ucontrol->value.iec958.status[1] << 8) |
 	      (ucontrol->value.iec958.status[2] << 16) |
 	      (ucontrol->value.iec958.status[3] << 24);
-	spin_lock_irqsave(&emu->reg_lock, flags);
 	change = val != emu->spdif_bits[idx];
 	if (change) {
 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
diff -ru alsa-v009-test/alsa-kernel/pci/emu10k1/emupcm.c alsa-old/alsa-kernel/pci/emu10k1/emupcm.c
--- alsa-v009-test/alsa-kernel/pci/emu10k1/emupcm.c	2005-02-10 16:55:56.000000000 -0500
+++ alsa-old/alsa-kernel/pci/emu10k1/emupcm.c	2005-02-10 22:48:39.000000000 -0500
@@ -235,6 +235,7 @@
 
 static unsigned int emu10k1_select_interprom(unsigned int pitch_target)
 {
+	
 	if (pitch_target == PITCH_48000)
 		return CCCA_INTERPROM_0;
 	else if (pitch_target < PITCH_48000)
@@ -677,7 +678,7 @@
 {
 	snd_pcm_substream_t *substream;
 	snd_pcm_runtime_t *runtime;
-	unsigned int voice, pitch, pitch_target, tmp;
+	unsigned int voice, pitch, pitch_target;
 
 	if (evoice == NULL)	/* skip second voice for mono */
 		return;
@@ -1459,6 +1460,66 @@
 	.put = snd_emu10k1_pcm_efx_voices_mask_put
 };
 
+/*
+ * control for direct monitoring with multichannel PCM.  JACK needs this  
+ * for hardware monitoring.  Although you can do it in the DSP it's nice to 
+ * have ASIO styly zero latency monitoring controlled by the JACK, rather than 
+ * having to manually connect a route in the DSP. 
+ * For now all selected EXTINs will be mixed together to the analog 
+ * capture port.  We will need more flexible send routing control eventually.
+ */
+
+static int snd_emu10k1_pcm_input_monitor_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = NUM_EFX_PLAYBACK;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_emu10k1_pcm_input_monitor_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	int idx;
+	
+	spin_lock_irq(&emu->reg_lock);
+	for (idx = 0; idx < NUM_EFX_PLAYBACK; idx++)
+		ucontrol->value.integer.value[idx] = (emu->input_monitor[idx / 32] & ( 1 << (idx % 32))) ? 1 : 0;
+	spin_unlock_irq(&emu->reg_lock);
+	return 0;
+}
+
+static int snd_emu10k1_pcm_input_monitor_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
+	unsigned int nval[1];
+	int change, idx;
+	
+	nval[0] = 0;
+	for (idx = 0; idx < NUM_EFX_PLAYBACK; idx++) {
+		if (ucontrol->value.integer.value[idx]) {
+			printk("channel %d set\n", idx);
+			nval[idx / 32] |= 1 << ( idx % 32);
+		}
+	}
+		
+	spin_lock_irq(&emu->reg_lock);
+	change = (nval[0] != emu->input_monitor[0]);
+	emu->input_monitor[0] = nval[0];
+	printk("input monitoring activated: %x\n", nval[0]);
+	spin_unlock_irq(&emu->reg_lock);
+	return change;
+}
+
+static snd_kcontrol_new_t snd_emu10k1_pcm_input_monitor = {
+	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+	.name = "Multi Track Input Monitor",
+	.info = snd_emu10k1_pcm_input_monitor_info,
+	.get = snd_emu10k1_pcm_input_monitor_get,
+	.put = snd_emu10k1_pcm_input_monitor_put
+};
+
 static snd_pcm_ops_t snd_emu10k1_capture_efx_ops = {
 	.open =			snd_emu10k1_capture_efx_open,
 	.close =		snd_emu10k1_capture_efx_close,
@@ -1743,6 +1804,9 @@
 	}
 	snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu));
 
+	/* don't monitor the inputs by default */
+	snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_input_monitor, emu));
+	
 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
 
 	return 0;
Only in alsa-old/alsa-kernel/pci/emu10k1: emupcm.c~
diff -ru alsa-v009-test/alsa-kernel/pci/emu10k1/emuproc.c alsa-old/alsa-kernel/pci/emu10k1/emuproc.c
--- alsa-v009-test/alsa-kernel/pci/emu10k1/emuproc.c	2005-02-10 16:55:56.000000000 -0500
+++ alsa-old/alsa-kernel/pci/emu10k1/emuproc.c	2005-02-05 23:26:59.000000000 -0500
@@ -140,38 +140,38 @@
 		/* 29 */ "???",
 		/* 30 */ "???",
 		/* 31 */ "???",
-		/* 32 */ "???",
-		/* 33 */ "???",
-		/* 34 */ "???",
-		/* 35 */ "???",
-		/* 36 */ "???",
-		/* 37 */ "???",
-		/* 38 */ "???",
-		/* 39 */ "???",
-		/* 40 */ "???",
-		/* 41 */ "???",
-		/* 42 */ "???",
-		/* 43 */ "???",
-		/* 44 */ "???",
-		/* 45 */ "???",
-		/* 46 */ "???",
-		/* 47 */ "???",
-		/* 48 */ "???",
-		/* 49 */ "???",
-		/* 50 */ "???",
-		/* 51 */ "???",
-		/* 52 */ "???",
-		/* 53 */ "???",
-		/* 54 */ "???",
-		/* 55 */ "???",
-		/* 56 */ "???",
-		/* 57 */ "???",
-		/* 58 */ "???",
-		/* 59 */ "???",
-		/* 60 */ "???",
-		/* 61 */ "???",
-		/* 62 */ "???",
-		/* 33 */ "???"
+		/* 32 */ "FXBUS2_0",
+		/* 33 */ "FXBUS2_1",
+		/* 34 */ "FXBUS2_2",
+		/* 35 */ "FXBUS2_3",
+		/* 36 */ "FXBUS2_4",
+		/* 37 */ "FXBUS2_5",
+		/* 38 */ "FXBUS2_6",
+		/* 39 */ "FXBUS2_7",
+		/* 40 */ "FXBUS2_8",
+		/* 41 */ "FXBUS2_9",
+		/* 42 */ "FXBUS2_10",
+		/* 43 */ "FXBUS2_11",
+		/* 44 */ "FXBUS2_12",
+		/* 45 */ "FXBUS2_13",
+		/* 46 */ "FXBUS2_14",
+		/* 47 */ "FXBUS2_15",
+		/* 48 */ "FXBUS2_16",
+		/* 49 */ "FXBUS2_17",
+		/* 50 */ "FXBUS2_18",
+		/* 51 */ "FXBUS2_19",
+		/* 52 */ "FXBUS2_20",
+		/* 53 */ "FXBUS2_21",
+		/* 54 */ "FXBUS2_22",
+		/* 55 */ "FXBUS2_23",
+		/* 56 */ "FXBUS2_24",
+		/* 57 */ "FXBUS2_25",
+		/* 58 */ "FXBUS2_26",
+		/* 59 */ "FXBUS2_27",
+		/* 60 */ "FXBUS2_28",
+		/* 61 */ "FXBUS2_29",
+		/* 62 */ "FXBUS2_30",
+		/* 63 */ "FXBUS2_31"
 	};
 
 	emu10k1_t *emu = entry->private_data;
@@ -221,7 +221,7 @@
 			snd_iprintf(buffer, "  Output %02i [%s]\n", idx, outputs[idx]);
 	}
 	snd_iprintf(buffer, "\nAll FX Outputs        :\n");
-	for (idx = 0; idx < 32; idx++)
+	for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++)
 		snd_iprintf(buffer, "  Output %02i [%s]\n", idx, outputs[idx]);
 	snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 0", SPCS0, -1);
 	snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 1", SPCS1, -1);
@@ -322,6 +322,26 @@
 	return 0;
 }
 
+static void snd_emu10k1_proc_voices_read(snd_info_entry_t *entry, 
+				  snd_info_buffer_t * buffer)
+{
+	emu10k1_t *emu = entry->private_data;
+	emu10k1_voice_t *voice;
+	int idx;
+	
+	snd_iprintf(buffer, "ch\tuse\tpcm\tefx\tsynth\tmidi\n");
+	for (idx = 0; idx < NUM_G; idx++) {
+		voice = &emu->voices[idx];
+		snd_iprintf(buffer, "%i\t%i\t%i\t%i\t%i\t%i\n",
+			idx,
+			voice->use,
+			voice->pcm,
+			voice->efx,
+			voice->synth,
+			voice->midi);
+	}
+}
+
 #ifdef CONFIG_SND_DEBUG
 static void snd_emu_proc_io_reg_read(snd_info_entry_t *entry,
 				     snd_info_buffer_t * buffer)
@@ -506,6 +526,9 @@
 	if (! snd_card_proc_new(emu->card, "emu10k1", &entry))
 		snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read);
 
+	if (! snd_card_proc_new(emu->card, "voices", &entry))
+		snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read);
+
 	if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) {
 		entry->content = SNDRV_INFO_CONTENT_DATA;
 		entry->private_data = emu;
diff -ru alsa-v009-test/alsa-kernel/pci/emu10k1/voice.c alsa-old/alsa-kernel/pci/emu10k1/voice.c
--- alsa-v009-test/alsa-kernel/pci/emu10k1/voice.c	2005-02-10 16:55:56.000000000 -0500
+++ alsa-old/alsa-kernel/pci/emu10k1/voice.c	2005-02-06 05:16:49.000000000 -0500
@@ -48,47 +48,50 @@
 static int voice_alloc(emu10k1_t *emu, emu10k1_voice_type_t type, int number, emu10k1_voice_t **rvoice)
 {
 	emu10k1_voice_t *voice;
-	int idx, pair, i, j, k, first_voice, last_voice, skip;
+	int i, j, k, first_voice, last_voice, skip;
 
-	first_voice = last_voice = skip = 0;	
 	*rvoice = NULL;
-	for (i = emu->next_free_voice, j=0; j < NUM_G ; i += number, j+= number) {
+	first_voice = last_voice = 0;
+	for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) {
 		// printk("i %d j %d next free %d!\n", i, j, emu->next_free_voice);
 		i %= NUM_G;
-		if ((i % 2) && (number == 2)) {
+
+		/* stereo voices must be even/odd */
+		if ((number == 2) && (i % 2)) {
 			i++;
 			continue;
 		}
 			
 		/* make sure the block of voices does not cross the 32 voice boundary */
-		if (((i % 32) + number) > 32)
-			continue;
+		//if (((i % 32) + number) > 32)
+		//	continue;
+
+		skip = 0;
 		for (k = 0; k < number; k++) {
-			voice = &emu->voices[i+k];
+			voice = &emu->voices[(i+k) % NUM_G];
 			if (voice->use) {
-				// printk("voice %d: use=1!\n", i+k);
+				printk("voice %d: use=1!\n", i+k);
 				skip = 1;
 			}
 		}
 		if (!skip) {
 			// printk("allocated voice %d\n", i);
 			first_voice = i;
-			last_voice = i + number;
+			last_voice = (i + number) % NUM_G;
 			emu->next_free_voice = last_voice;
-			emu->next_free_voice %= NUM_G;
 			break;
 		}
 	}
 	
 	if (first_voice == last_voice) {
-		printk("first==last, number %d, next free %d!\n", number, emu->next_free_voice);
-		/* BUG (or not enough voices)! */
+		printk("BUG (or not enough voices), number %d, next free %d!\n",
+				number,
+				emu->next_free_voice);
 		return -ENOMEM;
 	}	
 	
-	pair = ( number == 2 ) ? 1 : 0;
-	for (idx=first_voice; idx < last_voice; idx++) {
-		voice = &emu->voices[idx];
+	for (i=0; i < number; i++) {
+		voice = &emu->voices[(first_voice + i) % NUM_G];
 		// printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number);
 		voice->use = 1;
 		switch (type) {

