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,