Index: alsa-driver/alsa-kernel/include/emu10k1.h
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/include/emu10k1.h,v
retrieving revision 1.58
diff -u -r1.58 emu10k1.h
--- alsa-driver/alsa-kernel/include/emu10k1.h	1 Mar 2005 08:17:25 -0000	1.58
+++ alsa-driver/alsa-kernel/include/emu10k1.h	12 Mar 2005 19:44:55 -0000
@@ -280,6 +280,46 @@
 #define AC97ADDRESS_READY	0x80		/* Read-only bit, reflects CODEC READY signal	*/
 #define AC97ADDRESS_ADDRESS	0x7f		/* Address of indexed AC97 register		*/
 
+/* Available on the Audigy 2 and Audigy 4 only. This is the P16V chip. */
+#define PTR2			0x20		/* Indexed register set pointer register	*/
+#define DATA2			0x24		/* Indexed register set data register		*/
+#define IPR2			0x28		/* P16V interrupt pending register		*/
+#define IPR2_PLAYBACK_CH_0_LOOP      0x00001000 /* Playback Channel 0 loop                               */
+#define IPR2_PLAYBACK_CH_0_HALF_LOOP 0x00000100 /* Playback Channel 0 half loop                          */
+#define IPR2_CAPTURE_CH_0_LOOP       0x00100000 /* Capture Channel 0 loop                               */
+#define IPR2_CAPTURE_CH_0_HALF_LOOP  0x00010000 /* Capture Channel 0 half loop                          */
+						/* 0x00000100 Playback. Only in once per period.
+						 * 0x00110000 Capture. Int on half buffer.
+						 */
+#define INTE2			0x2c		/* P16V Interrupt enable register. 	*/
+#define INTE2_PLAYBACK_CH_0_LOOP      0x00001000 /* Playback Channel 0 loop                               */
+#define INTE2_PLAYBACK_CH_0_HALF_LOOP 0x00000100 /* Playback Channel 0 half loop                          */
+#define INTE2_PLAYBACK_CH_1_LOOP      0x00002000 /* Playback Channel 1 loop                               */
+#define INTE2_PLAYBACK_CH_1_HALF_LOOP 0x00000200 /* Playback Channel 1 half loop                          */
+#define INTE2_PLAYBACK_CH_2_LOOP      0x00004000 /* Playback Channel 2 loop                               */
+#define INTE2_PLAYBACK_CH_2_HALF_LOOP 0x00000400 /* Playback Channel 2 half loop                          */
+#define INTE2_PLAYBACK_CH_3_LOOP      0x00008000 /* Playback Channel 3 loop                               */
+#define INTE2_PLAYBACK_CH_3_HALF_LOOP 0x00000800 /* Playback Channel 3 half loop                          */
+#define INTE2_CAPTURE_CH_0_LOOP       0x00100000 /* Capture Channel 0 loop                               */
+#define INTE2_CAPTURE_CH_0_HALF_LOOP  0x00010000 /* Caputre Channel 0 half loop                          */
+#define HCFG2			0x34		/* Defaults: 0, win2000 sets it to 00004201 */
+						/* 0x00000000 2-channel output. */
+						/* 0x00000200 8-channel output. */
+						/* 0x00000004 pauses stream/irq fail. */
+						/* Rest of bits no nothing to sound output */
+						/* bit 0: Enable P16V audio.
+						 * bit 1: Lock P16V record memory cache.
+						 * bit 2: Lock P16V playback memory cache.
+						 * bit 3: Dummy record insert zero samples.
+						 * bit 8: Record 8-channel in phase.
+						 * bit 9: Playback 8-channel in phase.
+						 * bit 11-12: Playback mixer attenuation: 0=0dB, 1=-6dB, 2=-12dB, 3=Mute.
+						 * bit 13: Playback mixer enable.
+						 * bit 14: Route SRC48 mixer output to fx engine.
+						 * bit 15: Enable IEEE 1394 chip.
+						 */
+#define IPR3			0x38		/* Cdif interrupt pending register		*/
+#define INTE3			0x3c		/* Cdif interrupt enable register. 	*/
 /************************************************************************************************/
 /* PCI function 1 registers, address = <val> + PCIBASE1						*/
 /************************************************************************************************/
@@ -1014,6 +1054,9 @@
 	int max_cache_pages;			/* max memory size / PAGE_SIZE */
 	struct snd_dma_buffer silent_page;	/* silent page */
 	struct snd_dma_buffer ptb_pages;	/* page table pages */
+	struct snd_dma_device p16v_dma_dev;
+	struct snd_dma_buffer p16v_buffer;
+
 	snd_util_memhdr_t *memhdr;		/* page allocation list */
 	emu10k1_memblk_t *reserved_page;	/* reserved page */
 
@@ -1035,6 +1078,7 @@
 	snd_pcm_t *pcm;
 	snd_pcm_t *pcm_mic;
 	snd_pcm_t *pcm_efx;
+	snd_pcm_t *pcm_p16v;
 
 	spinlock_t synth_lock;
 	void *synth;
@@ -1046,6 +1090,8 @@
 	struct semaphore ptb_lock;
 
 	emu10k1_voice_t voices[NUM_G];
+	emu10k1_voice_t p16v_voices[4];
+	int p16v_device_offset;
 	emu10k1_pcm_mixer_t pcm_mixer[32];
 	emu10k1_pcm_mixer_t efx_pcm_mixer[NUM_EFX_PLAYBACK];
 	snd_kcontrol_t *ctl_send_routing;
@@ -1087,6 +1133,9 @@
 int snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_pcm_mic(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
+int snd_p16v_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
+int snd_p16v_free(emu10k1_t * emu);
+int snd_p16v_mixer(emu10k1_t * emu);
 int snd_emu10k1_pcm_multi(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_fx8010_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
 int snd_emu10k1_mixer(emu10k1_t * emu);
@@ -1104,6 +1153,8 @@
 /* I/O functions */
 unsigned int snd_emu10k1_ptr_read(emu10k1_t * emu, unsigned int reg, unsigned int chn);
 void snd_emu10k1_ptr_write(emu10k1_t *emu, unsigned int reg, unsigned int chn, unsigned int data);
+unsigned int snd_emu10k1_ptr20_read(emu10k1_t * emu, unsigned int reg, unsigned int chn);
+void snd_emu10k1_ptr20_write(emu10k1_t *emu, unsigned int reg, unsigned int chn, unsigned int data);
 unsigned int snd_emu10k1_efx_read(emu10k1_t *emu, unsigned int pc);
 void snd_emu10k1_intr_enable(emu10k1_t *emu, unsigned int intrenb);
 void snd_emu10k1_intr_disable(emu10k1_t *emu, unsigned int intrenb);
Index: alsa-driver/alsa-kernel/pci/emu10k1/Makefile
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/Makefile,v
retrieving revision 1.12
diff -u -r1.12 Makefile
--- alsa-driver/alsa-kernel/pci/emu10k1/Makefile	27 Dec 2004 15:18:34 -0000	1.12
+++ alsa-driver/alsa-kernel/pci/emu10k1/Makefile	12 Mar 2005 19:44:55 -0000
@@ -5,7 +5,7 @@
 
 snd-emu10k1-objs := emu10k1.o emu10k1_main.o \
 		    irq.o memory.o voice.o emumpu401.o emupcm.o io.o \
-		    emuproc.o emumixer.o emufx.o timer.o
+		    emuproc.o emumixer.o emufx.o timer.o p16v.o
 snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o
 snd-emu10k1x-objs := emu10k1x.o
 
Index: alsa-driver/alsa-kernel/pci/emu10k1/emu10k1.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/emu10k1.c,v
retrieving revision 1.31
diff -u -r1.31 emu10k1.c
--- alsa-driver/alsa-kernel/pci/emu10k1/emu10k1.c	16 Feb 2005 10:25:36 -0000	1.31
+++ alsa-driver/alsa-kernel/pci/emu10k1/emu10k1.c	12 Mar 2005 19:44:56 -0000
@@ -138,7 +138,13 @@
 	if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0) {
 		snd_card_free(card);
 		return err;
-	}		
+	}
+	/* This stores the periods table. */
+	if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &emu->p16v_buffer) < 0) {
+		snd_p16v_free(emu);
+		return -ENOMEM;
+	}
+
 	if ((err = snd_emu10k1_mixer(emu)) < 0) {
 		snd_card_free(card);
 		return err;
@@ -152,8 +158,13 @@
 	if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0) {
 		snd_card_free(card);
 		return err;
-	}		
-
+	}
+	if (emu->audigy && emu->revision == 4) { /* P16V */	
+		if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) {
+			snd_card_free(card);
+			return err;
+		}
+	}
 	if (emu->audigy) {
 		if ((err = snd_emu10k1_audigy_midi(emu)) < 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.43
diff -u -r1.43 emu10k1_main.c
--- alsa-driver/alsa-kernel/pci/emu10k1/emu10k1_main.c	14 Feb 2005 13:53:40 -0000	1.43
+++ alsa-driver/alsa-kernel/pci/emu10k1/emu10k1_main.c	12 Mar 2005 19:44:56 -0000
@@ -39,6 +39,7 @@
 
 #include <sound/core.h>
 #include <sound/emu10k1.h>
+#include "p16v.h"
 
 #if 0
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Creative Labs, Inc.");
@@ -178,14 +179,17 @@
 		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);
-
+		snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14);
 		/* Setup SRCMulti Input Audio Enable */
-		outl(0x6E0000, emu->port + 0x20);
-		outl(0xFF00FF00, emu->port + 0x24);
+		/* Use 0xFFFFFFFF to enable P16V sounds. */
+		snd_emu10k1_ptr20_write(emu, SRCMULTI_ENABLE, 0, 0xFFFFFFFF);
+
+		/* Enabled Phased (8-channel) P16V playback */
+		outl(0x0201, emu->port + HCFG2);
+		/* Set playback routing. */
+		snd_emu10k1_ptr_write(emu, CAPTURE_P16V_SOURCE, 0, 78e4);
 	}
 	if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */
 		/* Hacks for Alice3 to work independent of haP16V driver */
@@ -596,6 +600,7 @@
 	if (emu->port)
 		pci_release_regions(emu->pci);
 	pci_disable_device(emu->pci);
+	snd_p16v_free(emu);
 	kfree(emu);
 	return 0;
 }
Index: alsa-driver/alsa-kernel/pci/emu10k1/emumixer.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/emumixer.c,v
retrieving revision 1.30
diff -u -r1.30 emumixer.c
--- alsa-driver/alsa-kernel/pci/emu10k1/emumixer.c	16 Feb 2005 10:25:36 -0000	1.30
+++ alsa-driver/alsa-kernel/pci/emu10k1/emumixer.c	12 Mar 2005 19:44:56 -0000
@@ -939,6 +939,10 @@
 		if ((err = snd_ctl_add(card, kctl)))
 			return err;
 	}
-
+	if (emu->audigy && emu->revision == 4) { /* P16V */
+		if ((err = snd_p16v_mixer(emu)))
+			return err;
+	}
+		
 	return 0;
 }
Index: alsa-driver/alsa-kernel/pci/emu10k1/emuproc.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/emuproc.c,v
retrieving revision 1.24
diff -u -r1.24 emuproc.c
--- alsa-driver/alsa-kernel/pci/emu10k1/emuproc.c	16 Feb 2005 10:27:03 -0000	1.24
+++ alsa-driver/alsa-kernel/pci/emu10k1/emuproc.c	12 Mar 2005 19:44:56 -0000
@@ -413,7 +413,7 @@
 
 
 static void snd_emu_proc_ptr_reg_read(snd_info_entry_t *entry,
-				      snd_info_buffer_t * buffer, int iobase, int offset, int length)
+				      snd_info_buffer_t * buffer, int iobase, int offset, int length, int voices)
 {
 	emu10k1_t *emu = entry->private_data;
 	unsigned long value;
@@ -425,7 +425,7 @@
 	snd_iprintf(buffer, "Registers 0x%x\n", iobase);
 	for(i = offset; i < offset+length; i++) {
 		snd_iprintf(buffer, "%02X: ",i);
-		for (j = 0; j < 64; j++) {
+		for (j = 0; j < voices; j++) {
 			if(iobase == 0)
                 		value = snd_ptr_read(emu, 0, i, j);
 			else
@@ -466,25 +466,25 @@
 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);
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0, 0x40, 64);
 }
 
 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);
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0x40, 0x40, 64);
 }
 
 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);
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0, 0x40, 4);
 }
 
 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);
+	snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0x40, 0x40, 4);
 }
 #endif
 
Index: alsa-driver/alsa-kernel/pci/emu10k1/io.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/io.c,v
retrieving revision 1.9
diff -u -r1.9 io.c
--- alsa-driver/alsa-kernel/pci/emu10k1/io.c	16 Feb 2005 10:25:36 -0000	1.9
+++ alsa-driver/alsa-kernel/pci/emu10k1/io.c	12 Mar 2005 19:44:56 -0000
@@ -91,6 +91,38 @@
 	}
 }
 
+unsigned int snd_emu10k1_ptr20_read(emu10k1_t * emu, 
+					  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 + 0x20 + PTR);
+	val = inl(emu->port + 0x20 + DATA);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+	return val;
+}
+
+void snd_emu10k1_ptr20_write(emu10k1_t *emu, 
+				   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 + 0x20 + PTR);
+	outl(data, emu->port + 0x20 + DATA);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
 void snd_emu10k1_intr_enable(emu10k1_t *emu, unsigned int intrenb)
 {
 	unsigned long flags;
Index: alsa-driver/alsa-kernel/pci/emu10k1/irq.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/pci/emu10k1/irq.c,v
retrieving revision 1.12
diff -u -r1.12 irq.c
--- alsa-driver/alsa-kernel/pci/emu10k1/irq.c	16 Feb 2005 10:25:36 -0000	1.12
+++ alsa-driver/alsa-kernel/pci/emu10k1/irq.c	12 Mar 2005 19:44:56 -0000
@@ -33,7 +33,7 @@
 irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	emu10k1_t *emu = dev_id;
-	unsigned int status, orig_status;
+	unsigned int status, status2, orig_status, orig_status2;
 	int handled = 0;
 
 	while ((status = inl(emu->port + IPR)) != 0) {
@@ -149,7 +149,7 @@
 		}
 		if (status) {
 			unsigned int bits;
-			snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
+			//snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
 			//make sure any interrupts we don't handle are disabled:
 			bits = INTE_FXDSPENABLE |
 				INTE_PCIERRORENABLE |
@@ -170,5 +170,19 @@
 		}
 		outl(orig_status, emu->port + IPR); /* ack all */
 	}
+	while ((status2 = inl(emu->port + IPR2)) != 0) {
+		u32 mask = INTE2_PLAYBACK_CH_0_LOOP;  /* Full Loop */
+		emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]);
+		orig_status2 = status2;
+		if(status2 & mask) {
+			if(pvoice->use) {
+				snd_pcm_period_elapsed(pvoice->epcm->substream);
+			} else { 
+				snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use);
+			}
+		}
+		outl(orig_status2, emu->port + IPR2); /* ack all */
+	}
+
 	return IRQ_RETVAL(handled);
 }

