Re: alsa on 2.6 kernels, spdif patch

David Pye <[email protected]>
Newsgroups gmane.linux.ports.xbox.devel
Message-ID <[email protected]>
On Tuesday 16 November 2004 14:48, Ilkka Urtamo wrote:

> Hi
>
> Is there later xbox patch for spdif for intel8x0 driver for spdif than one
> in CVS?

No, or if there is, someone is holding onto it very tightly.

> I would like to use 2.6 kernel with spdif output but I dont seem to find
> any indication of spdif patch later than 0.9.1 version.
>
> I could be able to do the patching myself if i could understand a bit what
> the patch is all about.

Well, I can tell you what I learnt, from trying to produce a S/PDIF patch for 
alsa 1.0.5 tonight :) 
>
> If there is no patch, I would like to volunter for developing/testing/etc.
> for the patch. I am not alsa programmer so it might be dificult for me to
> actually make the patch, 

Me neither, but I was sufficiently bored to hack about with it.

> but I would be willing to try out if someone could 
> pass me some insights about what the orginal patch is based on?

The internals of Andy Green's mind, as far as I can tell :)

> ( Naturally I would like to yeal for the orginal author to update the patch
> =P )

He's no longer active within xbox-linux, so I doubt he'll come back now, but 
he might prove me wrong.

Anyhow, seeing as you said you were interested in testing one, give this a 
try. I've hacked about with it, and tried to port the code from the old spdif 
patch to the new alsa, but I haven't got any spdif-capable kit (I just felt 
like a challenge tonight!). It might blow up your children, sacrifice a goat 
on your couch, etc.. but then again, even if it doesnt 'just work' (too much 
to hope!) it might get you closer to your goal somehow :) 

Attached.

David

-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d- s-: a-- C++ UL++++ P L+++ E--- W++ N+ o+ K- w---
O M V- PS+ PE+ Y+ PGP t 5- X+ R- tv+ b+ DI++ D+
G+ e++ h--- r++ y++
------END GEEK CODE BLOCK------
diff (text/x-diff, 5.9 KB)
diff -urN alsa-driver-1.0.5/alsa-kernel/pci/ac97/ac97_codec.c xbox-alsa-1.0.5/alsa-kernel/pci/ac97/ac97_codec.c
--- alsa-driver-1.0.5/alsa-kernel/pci/ac97/ac97_codec.c	2004-05-28 10:27:09.000000000 +0100
+++ xbox-alsa-1.0.5/alsa-kernel/pci/ac97/ac97_codec.c	2004-11-24 00:09:28.000000000 +0000
@@ -1866,8 +1866,9 @@
 	ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
 	if (ac97->id == 0x00000000 || ac97->id == 0xffffffff) {
 		snd_printk(KERN_ERR "AC'97 %d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->id);
-		snd_ac97_free(ac97);
-		return -EIO;
+		//XBOX
+		//snd_ac97_free(ac97);
+		//return -EIO;
 	}
 	
 	/* test for AC'97 */
@@ -1896,8 +1897,9 @@
 	if (!ac97_is_audio(ac97) && !ac97_is_modem(ac97)) {
 		if (!(ac97->scaps & (AC97_SCAP_SKIP_AUDIO|AC97_SCAP_SKIP_MODEM)))
 			snd_printk(KERN_ERR "AC'97 %d access error (not audio or modem codec)\n", ac97->num);
-		snd_ac97_free(ac97);
-		return -EACCES;
+		//XBOX
+		//snd_ac97_free(ac97);
+		//return -EACCES;
 	}
 
 	if (bus->reset) // FIXME: always skipping?
diff -urN alsa-driver-1.0.5/alsa-kernel/pci/intel8x0.c xbox-alsa-1.0.5/alsa-kernel/pci/intel8x0.c
--- alsa-driver-1.0.5/alsa-kernel/pci/intel8x0.c	2004-04-26 08:47:09.000000000 +0100
+++ xbox-alsa-1.0.5/alsa-kernel/pci/intel8x0.c	2004-11-24 00:01:32.000000000 +0000
@@ -25,6 +25,7 @@
 
  *
  */      
+#define XBOX
 
 #include <sound/driver.h>
 #include <asm/io.h>
@@ -393,6 +394,9 @@
 	unsigned int int_sta_mask;		/* interrupt status mask */
 	unsigned int ali_slot;			/* ALI DMA slot */
 	struct ac97_pcm *pcm;
+#ifdef XBOX
+	unsigned int lastRetiredDescriptorIndex;
+#endif
 	int pcm_open_flag;
 } ichdev_t;
 
@@ -748,7 +752,12 @@
 			ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1);
 #endif
 	/* clear interrupts */
+#ifdef XBOX
+	ichdev->lastRetiredDescriptorIndex=0xffffffff;
+	iputbyte(chip,port+0x06,0xff);
+#else
 	iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+#endif
 }
 
 #ifdef __i386__
@@ -774,6 +783,45 @@
 
 static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev)
 {
+#ifdef XBOX
+	unsigned long port = ichdev->reg_offset;
+       	int ack = 0;
+
+	printk("Running snd_intel8x0_update on BMDMA %u\n", ichdev->ichd);
+	spin_lock(&chip->reg_lock);
+	ichdev->lastRetiredDescriptorIndex++; // track last used up buffer
+	if(ichdev->lastRetiredDescriptorIndex==0x7fffffff) ichdev->lastRetiredDescriptorIndex=2;
+	iputbyte(chip, ichdev->reg_offset + ICH_REG_OFF_LVI, (chip->ichd[ICHD_PCMOUT].lvi+1)& ICH_REG_LVI_MASK);
+	if(ichdev->lastRetiredDescriptorIndex>1) {
+		if(chip->ichd[ICHD_PCMOUT].lastRetiredDescriptorIndex 
+				== chip->ichd[NVD_SPBAR].lastRetiredDescriptorIndex) {
+	   		chip->ichd[NVD_PCMOUT].position += chip->ichd[NVD_PCMOUT].fragsize1;
+	       		chip->ichd[NVD_PCMOUT].position %= chip->ichd[NVD_PCMOUT].size;
+	       		chip->ichd[NVD_PCMOUT].lvi++;
+	       		chip->ichd[NVD_PCMOUT].lvi &= ICH_REG_LVI_MASK;
+	       		chip->ichd[NVD_PCMOUT].lvi_frag++;
+	       		chip->ichd[NVD_PCMOUT].lvi_frag %= chip->ichd[NVD_PCMOUT].frags;
+			ichdev->bdbar[chip->ichd[NVD_PCMOUT].lvi * 2] = 
+				cpu_to_le32(chip->ichd[NVD_PCMOUT].physbuf +
+				chip->ichd[NVD_PCMOUT].lvi_frag * 
+				chip->ichd[NVD_PCMOUT].fragsize1
+			);
+	
+			if ((ack = (--chip->ichd[NVD_PCMOUT].ack == 0))) {
+				chip->ichd[NVD_PCMOUT].ack = 
+					chip->ichd[NVD_PCMOUT].ack_reload;
+			}
+			
+			if (ack && chip->ichd[NVD_PCMOUT].substream) {
+				snd_pcm_period_elapsed(chip->ichd[NVD_PCMOUT].substream);
+			}
+		}
+	}
+
+	// clear interrupt from this DMA channel
+	iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+	spin_unlock(&chip->reg_lock);
+#else
 	unsigned long port = ichdev->reg_offset;
 	int status, civ, i, step;
 	int ack = 0;
@@ -818,6 +866,7 @@
 	}
 	iputbyte(chip, port + ichdev->roff_sr,
 		 status & (ICH_FIFOE | ICH_BCIS | ICH_LVBCI));
+#endif
 }
 
 static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -844,15 +893,24 @@
 	}
 
 	for (i = 0; i < chip->bdbars_count; i++) {
+		unsigned char b;
 		ichdev = &chip->ichd[i];
+#ifdef XBOX
+		b=igetbyte(chip, ichdev->reg_offset + 0x06);
+		if (b&0x10) {
+			printk("FIFO underrun ch %d\n",i);
+		}
+		if (b&8) 
+#else
 		if (status & ichdev->int_sta_mask)
+#endif
 			snd_intel8x0_update(chip, ichdev);
 	}
 
 	/* ack them */
 	iputdword(chip, chip->int_sta_reg, status & chip->int_sta_mask);
 	spin_unlock(&chip->reg_lock);
-	
+
 	return IRQ_HANDLED;
 }
 
@@ -886,9 +944,20 @@
 		return -EINVAL;
 	}
 	iputbyte(chip, port + ICH_REG_OFF_CR, val);
+#ifdef XBOX
+	if (ichdev->ichd == NVD_PCMOUT) { 
+		//LOCKSTEP the SPDIF
+		iputbyte(chip,chip->ichd[NVD_SPBAR].reg_offset + ICH_REG_OFF_CR,val);
+	}
+#endif
+	
+	
 	if (cmd == SNDRV_PCM_TRIGGER_STOP) {
 		/* wait until DMA stopped */
+#ifndef XBOX
+		//Seems to hard freeze it!
 		while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) ;
+#endif
 		/* reset whole DMA things */
 		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
 	}
@@ -1051,6 +1120,16 @@
 		}
 	}
 	snd_intel8x0_setup_periods(chip, ichdev);
+#ifdef XBOX
+	if (ichdev->ichd == NVD_PCMOUT) {
+		//Lockstep SPDIF again
+		printk("snd_intel8x0_pcm_prepare doing S/PDIF lockstep\n");
+		chip->ichd[NVD_SPBAR].physbuf = runtime->dma_addr;
+		chip->ichd[NVD_SPBAR].size = snd_pcm_lib_buffer_bytes(substream);
+		 chip->ichd[NVD_SPBAR].fragsize = snd_pcm_lib_period_bytes(substream);
+		snd_intel8x0_setup_periods(chip, &chip->ichd[NVD_SPBAR]);
+	}
+#endif
 	return 0;
 }
 
@@ -2339,8 +2418,12 @@
 		printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos);
 	else if (pos < 47500 || pos > 48500)
 		/* not 48000Hz, tuning the clock.. */
+#ifdef XBOX
+		chip->ac97_bus->clock=48000;
+#else
 		chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
-	printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
+#endif
+		printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
 }
 
 static void snd_intel8x0_proc_read(snd_info_entry_t * entry,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.