All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Support for AD1889 PCI Soundchip
@ 2005-07-29 19:16 Thibaut VARENE
  2005-07-29 19:20 ` [parisc-linux] " Thibaut VARENE
                   ` (4 more replies)
  0 siblings, 5 replies; 35+ messages in thread
From: Thibaut VARENE @ 2005-07-29 19:16 UTC (permalink / raw)
  To: perex; +Cc: alsa-devel, kyle, parisc-linux


[-- Attachment #1.1: Type: text/plain, Size: 994 bytes --]

Hi,

Attached is a patch against 2.6.13-rc4 providing support for Analog
Devices AD1889 PCI Sound chip, which is especially found on some HP
PA-RISC machines.

The driver has been successfully tested on parisc and ppc architectures,
and offers support for full duplex playback (variable rates, mono/stereo
8/16bit) and capture (fixed 48kHz, mono/stereo 8/16bit).

It's developed and maintained in the parisc-linux.org CVS kernel tree
(http://cvs.parisc-linux.org/), and has a status webpage on
http://wiki.parisc-linux.org/AD1889

This patch doesn't yet feature OPL3 code, because it's still work in
progress in our development tree.

Here's the diffstat summary:

 MAINTAINERS        |    9
 sound/pci/Kconfig  |   12
 sound/pci/Makefile |    2
 sound/pci/ad1889.c | 1166
+++++++++++++++++++++++++++++++++++++++++++++++++++++
 sound/pci/ad1889.h |  187 ++++++++
 5 files changed, 1376 insertions(+)

HTH

Thibaut VARENE
The PA/Linux Team
http://www.pateam.org/

[-- Attachment #1.2: analog-devices-ad1889-driver.patch --]
[-- Type: text/plain, Size: 43836 bytes --]

diff -Nru linux-2.6.13-rc4.orig/MAINTAINERS linux-2.6.13-rc4/MAINTAINERS
--- linux-2.6.13-rc4.orig/MAINTAINERS	2005-07-29 19:10:19.000000000 +0200
+++ linux-2.6.13-rc4/MAINTAINERS	2005-07-29 19:33:41.000000000 +0200
@@ -191,6 +191,15 @@
 W:	http://linux.thorsten-knabe.de
 S:	Maintained
 
+AD1889 SOUND DRIVER
+P:      Kyle McMartin
+M:      kyle@parisc-linux.org
+P:      Thibaut Varene
+M:      T-Bone@parisc-linux.org
+W:      http://wiki.parisc-linux.org/AD1889
+L:      parisc-linux@lists.parisc-linux.org
+S:      Maintained
+
 ADM1025 HARDWARE MONITOR DRIVER
 P:	Jean Delvare
 M:	khali@linux-fr.org
diff -Nru linux-2.6.13-rc4.orig/sound/pci/ad1889.c linux-2.6.13-rc4/sound/pci/ad1889.c
--- linux-2.6.13-rc4.orig/sound/pci/ad1889.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.13-rc4/sound/pci/ad1889.c	2005-07-29 19:35:42.000000000 +0200
@@ -0,0 +1,1166 @@
+/* Analog Devices 1889 audio driver
+ *
+ * This is a driver for the AD1889 PCI audio chipset found
+ * on the HP PA-RISC [BCJ]-xxx0 workstations.
+ *
+ * Copyright (C) 2004-2005, Kyle McMartin <kyle@parisc-linux.org>
+ * Copyright (C) 2005, Thibaut Varene <varenet@parisc-linux.org>
+ *   Based on the OSS AD1889 driver by Randolph Chung <tausq@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO:
+ *	Do we need to take care of CCS register?
+ *	Maybe we could use finer grained locking (separate locks for pb/cap)?
+ * Wishlist:
+ *	Control Interface (mixer) support
+ *	Better AC97 support (VSR...)?
+ *	PM support
+ *	MIDI support
+ *	Game Port support
+ *	SG DMA support (this will need *alot* of work)
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+
+#include <asm/io.h>
+
+#include "ad1889.h"
+#include "ac97/ac97_id.h"
+
+#define	AD1889_DRVVER	"$Revision: 1.31 $"
+
+MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>, Thibaut Varene <t-bone@parisc-linux.org>");
+MODULE_DESCRIPTION("Analog Devices AD1889 ALSA sound driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(AD1889_DRVVER);
+MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1889}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for the AD1889 soundcard.");
+
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for the AD1889 soundcard.");
+
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable AD1889 soundcard.");
+
+static char *ac97_quirk[SNDRV_CARDS];
+module_param_array(ac97_quirk, charp, NULL, 0444);
+MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
+
+#define DEVNAME "ad1889"
+#define PFX	DEVNAME ": "
+
+/* let's use the global sound debug interfaces */
+#define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)
+
+/* keep track of each hw register */
+struct ad1889_register_state {
+	u16 reg;	/* reg setup */
+	u32 addr;	/* dma base address */
+	u16 rate;	/* sample rate */
+	unsigned long pos;	/* last recorded DMA buffer position */
+	unsigned long buf;	/* period # */
+	unsigned long size;	/* DMA buffer size */
+	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
+};
+
+struct snd_ad1889 {
+	snd_card_t *card;
+	struct pci_dev *pci;
+
+	int irq;
+	unsigned long bar;
+	void __iomem *iobase;
+
+	ac97_t *ac97;
+	ac97_bus_t *ac97_bus;
+	snd_pcm_t *pcm;
+	snd_info_entry_t *proc;
+
+	struct snd_dma_device dma;
+	snd_pcm_substream_t *psubs;
+	snd_pcm_substream_t *csubs;
+
+	/* playback register state */
+	struct ad1889_register_state wave;
+	struct ad1889_register_state ramc;
+
+	struct {
+		unsigned long wav_intr;
+		unsigned long adc_intr;
+		unsigned long syn_intr;
+		unsigned long res_intr;
+	} stats;
+
+	spinlock_t lock;
+};
+
+static inline u16
+ad1889_readw(struct snd_ad1889 *chip, unsigned reg)
+{
+	return ioread16(chip->iobase + reg);
+}
+
+static inline void
+ad1889_writew(struct snd_ad1889 *chip, unsigned reg, u16 val)
+{
+	iowrite16(val, chip->iobase + reg);
+}
+
+static inline u32
+ad1889_readl(struct snd_ad1889 *chip, unsigned reg)
+{
+	return ioread32(chip->iobase + reg);
+}
+
+static inline void
+ad1889_writel(struct snd_ad1889 *chip, unsigned reg, u32 val)
+{
+	iowrite32(val, chip->iobase + reg);
+}
+
+static inline void
+ad1889_unmute(struct snd_ad1889 *chip)
+{
+	u16 st;
+	st = ad1889_readw(chip, AD_DS_WADA) & 
+		~(AD_DS_WADA_RWAM | AD_DS_WADA_LWAM);
+	ad1889_writew(chip, AD_DS_WADA, st);
+	ad1889_readw(chip, AD_DS_WADA);
+}
+
+static inline void
+ad1889_mute(struct snd_ad1889 *chip)
+{
+	u16 st;
+	st = ad1889_readw(chip, AD_DS_WADA) | AD_DS_WADA_RWAM | AD_DS_WADA_LWAM;
+	ad1889_writew(chip, AD_DS_WADA, st);
+	ad1889_readw(chip, AD_DS_WADA);
+}
+
+static inline void
+ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
+{
+	ad1889_writel(chip, AD_DMA_ADCBC, count);
+	ad1889_writel(chip, AD_DMA_ADCCC, count);
+	ad1889_writel(chip, AD_DMA_ADCIB, count);
+	ad1889_writel(chip, AD_DMA_ADCIC, count);
+}	
+
+static inline void
+ad1889_load_wave_count(struct snd_ad1889 *chip, u32 count)
+{
+	ad1889_writel(chip, AD_DMA_WAVBC, count);
+	ad1889_writel(chip, AD_DMA_WAVCC, count);
+	ad1889_writel(chip, AD_DMA_WAVIB, count);
+	ad1889_writel(chip, AD_DMA_WAVIC, count);
+}	
+
+static void
+ad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel)
+{
+	u16 reg;
+	
+	if (channel & AD_CHAN_WAV) {
+		/* Disable wave channel */
+		reg = ad1889_readw(chip, AD_DS_WSMC) & ~AD_DS_WSMC_WAEN;
+		ad1889_writew(chip, AD_DS_WSMC, reg);
+		chip->wave.reg = reg;
+		
+		/* disable IRQs */
+		reg = ad1889_readw(chip, AD_DMA_WAV);
+		reg &= AD_DMA_IM_DIS;
+		reg &= ~AD_DMA_LOOP;
+		ad1889_writew(chip, AD_DMA_WAV, reg);
+
+		/* clear IRQ and address counters and pointers */
+		ad1889_load_wave_count(chip, 0x0);
+		ad1889_writel(chip, AD_DMA_WAVBA, 0x0);
+		ad1889_writel(chip, AD_DMA_WAVCA, 0x0);
+
+		/* flush */
+		ad1889_readw(chip, AD_DMA_WAV);
+	}
+	
+	if (channel & AD_CHAN_ADC) {
+		/* Disable ADC channel */
+		reg = ad1889_readw(chip, AD_DS_RAMC) & ~AD_DS_RAMC_ADEN;
+		ad1889_writew(chip, AD_DS_RAMC, reg);
+		chip->ramc.reg = reg;
+
+		reg = ad1889_readw(chip, AD_DMA_ADC);
+		reg &= AD_DMA_IM_DIS;
+		reg &= ~AD_DMA_LOOP;
+		ad1889_writew(chip, AD_DMA_ADC, reg);
+	
+		ad1889_load_adc_count(chip, 0x0);
+		ad1889_writel(chip, AD_DMA_ADCBA, 0x0);
+		ad1889_writel(chip, AD_DMA_ADCCA, 0x0);
+
+		/* flush */
+		ad1889_readw(chip, AD_DMA_ADC);
+	}
+}
+
+static inline u16
+snd_ad1889_ac97_read(ac97_t *ac97, unsigned short reg)
+{
+	struct snd_ad1889 *chip = ac97->private_data;
+	return ad1889_readw(chip, AD_AC97_BASE + reg);
+}
+
+static inline void
+snd_ad1889_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
+{
+	struct snd_ad1889 *chip = ac97->private_data;
+	ad1889_writew(chip, AD_AC97_BASE + reg, val);
+}
+
+static int
+snd_ad1889_ac97_ready(struct snd_ad1889 *chip)
+{
+	int retry = 400; /* average needs 352 msec */
+	
+	while (!(ad1889_readw(chip, AD_AC97_ACIC) & AD_AC97_ACIC_ACRDY) 
+			&& --retry)
+		mdelay(1);
+	if (!retry) {
+		snd_printk(KERN_ERR PFX "[%s] Link is not ready.\n",
+		       __FUNCTION__);
+		return -EIO;
+	}
+	ad1889_debug("[%s] ready after %d ms\n", __FUNCTION__, 400 - retry);
+
+	return 0;
+}
+
+static int 
+snd_ad1889_hw_params(snd_pcm_substream_t *substream,
+			snd_pcm_hw_params_t *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream, 
+					params_buffer_bytes(hw_params));
+}
+
+static int
+snd_ad1889_hw_free(snd_pcm_substream_t *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static snd_pcm_hardware_t snd_ad1889_playback_hw = {
+	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rate_min = 8000,	/* docs say 7000, but we're lazy */
+	.rate_max = 48000,
+	.channels_min = 1,
+	.channels_max = 2,
+	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
+	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
+	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
+	.periods_min = 1,		/* min nb of periods in buffer */
+	.periods_max = MAX_BUFS,
+	/*.fifo_size = 0,*/
+};
+
+static snd_pcm_hardware_t snd_ad1889_capture_hw = {
+	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_48000,
+	.rate_min = 48000,	/* docs say we could to VSR, but we're lazy */
+	.rate_max = 48000,
+	.channels_min = 1,
+	.channels_max = 2,
+	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
+	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
+	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
+	.periods_min = 1,		/* min nb of periods in buffer */
+	.periods_max = MAX_BUFS,
+	/*.fifo_size = 0,*/
+};
+
+static int
+snd_ad1889_playback_open(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
+
+	chip->psubs = ss;
+	rt->hw = snd_ad1889_playback_hw;
+
+	return 0;
+}
+
+static int
+snd_ad1889_capture_open(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
+
+	chip->csubs = ss;
+	rt->hw = snd_ad1889_capture_hw;
+
+	return 0;
+}
+
+static int
+snd_ad1889_playback_close(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	chip->psubs = NULL;
+	return 0;
+}
+
+static int
+snd_ad1889_capture_close(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	chip->csubs = NULL;
+	return 0;
+}
+
+static int
+snd_ad1889_playback_prepare(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
+	unsigned int size = snd_pcm_lib_buffer_bytes(ss);
+	unsigned int count = snd_pcm_lib_period_bytes(ss);
+	u16 reg;
+
+	ad1889_channel_reset(chip, AD_CHAN_WAV);
+
+	reg = ad1889_readw(chip, AD_DS_WSMC);
+	
+	/* Mask out 16-bit / Stereo */
+	reg &= ~(AD_DS_WSMC_WA16 | AD_DS_WSMC_WAST);
+
+	if (snd_pcm_format_width(rt->format) == 16)
+		reg |= AD_DS_WSMC_WA16;
+
+	if (rt->channels > 1)
+		reg |= AD_DS_WSMC_WAST;
+
+	/* let's make sure we don't clobber ourselves */
+	spin_lock_irq(&chip->lock);
+	
+	chip->wave.size = size;
+	chip->wave.count = count;
+	chip->wave.reg = reg;
+	chip->wave.buf = 0;
+	chip->wave.pos = 0;
+	chip->wave.rate = rt->rate;
+	chip->wave.addr = rt->dma_addr;
+
+	ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg);
+	
+	/* Set sample rates on the codec */
+	ad1889_writew(chip, AD_DS_WAS, chip->wave.rate);
+
+	/* Set up DMA: first chunk address in curr addr, next one in base addr.
+	   Base will be loaded into curr by the hardware upon interrupt
+	   (as we use LOOP). Count holds the size of the chunk. */
+	ad1889_writel(chip, AD_DMA_WAVCA, chip->wave.addr);
+	ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + (count % size));
+	ad1889_load_wave_count(chip, chip->wave.count);
+
+	/* writes flush */
+	ad1889_readw(chip, AD_DS_WSMC);
+	
+	spin_unlock_irq(&chip->lock);
+	
+	ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
+			"size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
+			count, size, reg, chip->wave.rate);
+	return 0;
+}
+
+static int
+snd_ad1889_capture_prepare(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
+	unsigned int size = snd_pcm_lib_buffer_bytes(ss);
+	unsigned int count = snd_pcm_lib_period_bytes(ss);
+	u16 reg;
+
+	ad1889_channel_reset(chip, AD_CHAN_ADC);
+	
+	reg = ad1889_readw(chip, AD_DS_RAMC);
+
+	/* Mask out 16-bit / Stereo */
+	reg &= ~(AD_DS_RAMC_AD16 | AD_DS_RAMC_ADST);
+
+	if (snd_pcm_format_width(rt->format) == 16)
+		reg |= AD_DS_RAMC_AD16;
+
+	if (rt->channels > 1)
+		reg |= AD_DS_RAMC_ADST;
+
+	/* let's make sure we don't clobber ourselves */
+	spin_lock_irq(&chip->lock);
+	
+	chip->ramc.size = size;
+	chip->ramc.count = count;
+	chip->ramc.reg = reg;
+	chip->ramc.buf = 0;
+	chip->ramc.pos = 0;
+	chip->ramc.rate = rt->rate;
+	chip->ramc.addr = rt->dma_addr;
+
+	ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg);
+
+	/* Set up DMA: first chunk address in curr addr, next one in base addr.
+	   Base will be loaded into curr by the hardware upon interrupt
+	   (as we use LOOP). Count holds the size of the chunk. */
+	ad1889_writel(chip, AD_DMA_ADCCA, chip->ramc.addr);
+	ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + (count % size));
+	ad1889_load_adc_count(chip, chip->ramc.count);
+
+	/* writes flush */
+	ad1889_readw(chip, AD_DS_RAMC);
+	
+	spin_unlock_irq(&chip->lock);
+	
+	ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
+			"size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
+			count, size, reg, chip->ramc.rate);
+	return 0;
+}
+
+/* this is called in atomic context with IRQ disabled.
+   Must be as fast as possible and not sleep.
+   DMA should be *triggered* by this call.
+   The WSMC "WAEN" bit triggers DMA Wave On/Off */
+static int
+snd_ad1889_playback_trigger(snd_pcm_substream_t *ss, int cmd)
+{
+	u16 wsmc;
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	
+	wsmc = ad1889_readw(chip, AD_DS_WSMC);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* enable DMA loop & interrupts */
+		ad1889_writew(chip, AD_DMA_WAV, AD_DMA_LOOP | AD_DMA_IM_CNT);
+		wsmc |= AD_DS_WSMC_WAEN;
+		/* 1 to clear CHSS bit */
+		ad1889_writel(chip, AD_DMA_CHSS, AD_DMA_CHSS_WAVS);
+		ad1889_unmute(chip);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		ad1889_mute(chip);
+		wsmc &= ~AD_DS_WSMC_WAEN;
+		break;
+	default:
+		snd_BUG();
+		return -EINVAL;
+	}
+	
+	chip->wave.reg = wsmc;
+	ad1889_writew(chip, AD_DS_WSMC, wsmc);	
+	ad1889_readw(chip, AD_DS_WSMC);	/* flush */
+
+	/* reset the chip when STOP - will disable IRQs */
+	if (cmd == SNDRV_PCM_TRIGGER_STOP)
+		ad1889_channel_reset(chip, AD_CHAN_WAV);
+
+	return 0;
+}
+
+/* this is called in atomic context with IRQ disabled.
+   Must be as fast as possible and not sleep.
+   DMA should be *triggered* by this call.
+   The RAMC "ADEN" bit triggers DMA ADC On/Off */
+static int
+snd_ad1889_capture_trigger(snd_pcm_substream_t *ss, int cmd)
+{
+	u16 ramc;
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+
+	ramc = ad1889_readw(chip, AD_DS_RAMC);
+	
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* enable DMA loop & interrupts */
+		ad1889_writew(chip, AD_DMA_ADC, AD_DMA_LOOP | AD_DMA_IM_CNT);
+		ramc |= AD_DS_RAMC_ADEN;
+		/* 1 to clear CHSS bit */
+		ad1889_writel(chip, AD_DMA_CHSS, AD_DMA_CHSS_ADCS);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		ramc &= ~AD_DS_RAMC_ADEN;
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	chip->ramc.reg = ramc;
+	ad1889_writew(chip, AD_DS_RAMC, ramc);	
+	ad1889_readw(chip, AD_DS_RAMC);	/* flush */
+	
+	/* reset the chip when STOP - will disable IRQs */
+	if (cmd == SNDRV_PCM_TRIGGER_STOP)
+		ad1889_channel_reset(chip, AD_CHAN_ADC);
+		
+	return 0;
+}
+
+/* Called in atomic context with IRQ disabled */
+static snd_pcm_uframes_t
+snd_ad1889_playback_pointer(snd_pcm_substream_t *ss)
+{
+	size_t ptr = 0;
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+
+	if (unlikely(!(chip->wave.reg & AD_DS_WSMC_WAEN)))
+		return 0;
+
+	ptr = ad1889_readl(chip, AD_DMA_WAVCA);
+	ptr -= chip->wave.addr;
+	
+	snd_assert((ptr >= 0) && (ptr < chip->wave.size), return 0);
+	
+	return bytes_to_frames(ss->runtime, ptr);
+}
+
+/* Called in atomic context with IRQ disabled */
+static snd_pcm_uframes_t
+snd_ad1889_capture_pointer(snd_pcm_substream_t *ss)
+{
+	size_t ptr = 0;
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+
+	if (unlikely(!(chip->ramc.reg & AD_DS_RAMC_ADEN)))
+		return 0;
+
+	ptr = ad1889_readl(chip, AD_DMA_ADCCA);
+	ptr -= chip->ramc.addr;
+
+	snd_assert((ptr >= 0) && (ptr < chip->ramc.size), return 0);
+	
+	return bytes_to_frames(ss->runtime, ptr);
+}
+
+static snd_pcm_ops_t snd_ad1889_playback_ops = {
+	.open = snd_ad1889_playback_open,
+	.close = snd_ad1889_playback_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_ad1889_hw_params,
+	.hw_free = snd_ad1889_hw_free,
+	.prepare = snd_ad1889_playback_prepare,
+	.trigger = snd_ad1889_playback_trigger,
+	.pointer = snd_ad1889_playback_pointer, 
+};
+
+static snd_pcm_ops_t snd_ad1889_capture_ops = {
+	.open = snd_ad1889_capture_open,
+	.close = snd_ad1889_capture_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_ad1889_hw_params,
+	.hw_free = snd_ad1889_hw_free,
+	.prepare = snd_ad1889_capture_prepare,
+	.trigger = snd_ad1889_capture_trigger,
+	.pointer = snd_ad1889_capture_pointer, 
+};
+
+static irqreturn_t
+snd_ad1889_interrupt(int irq, 
+		     void *dev_id, 
+		     struct pt_regs *regs)
+{
+	unsigned long st;
+	unsigned long next;
+	struct snd_ad1889 *chip = dev_id;
+
+	st = ad1889_readl(chip, AD_DMA_DISR);
+
+	/* clear ISR */
+	ad1889_writel(chip, AD_DMA_DISR, st);
+
+	st &= AD_INTR_MASK;
+
+	if (unlikely(!st))
+		return IRQ_NONE;
+
+	if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
+		ad1889_debug("Unexpected master or target abort interrupt!\n");
+
+	if (chip->pcm && (st & AD_DMA_DISR_WAVI) && chip->psubs) {
+		spin_lock(&chip->lock);
+
+		chip->stats.wav_intr++;
+
+		chip->wave.buf++;
+
+		/* calculate the current position: we get interrupts everytime
+		   the buffer empties, thus every wave.count bytes transfered */
+		chip->wave.pos += chip->wave.count;
+		chip->wave.pos %= chip->wave.size;
+
+		/* the next buffer will thus be current position + wave.count
+		   bytes away */
+		next = chip->wave.pos + chip->wave.count;
+		next %= chip->wave.size;
+		
+		/* Load new DMA parameters (aka "the next chunk" in Base
+		   registers: upon next interrupt, they'll be automatically
+		   loaded in the Current registers, and we'll end up here
+		   preparing the new ones. Since "count" never gets modified
+		   elsewhere than in _prepare, we don't need to rewrite it. */
+		ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + next);
+		
+		ad1889_readl(chip, AD_DMA_WAVBA); /* flush all those writes */
+
+		spin_unlock(&chip->lock);
+
+		snd_pcm_period_elapsed(chip->psubs);
+#if 0
+		ad1889_debug("chip->wave.pos = %d, chip->wave.count = %d, "
+				"chip->wave.size = %d\n", chip->wave.pos,
+				chip->wave.count, chip->wave.size);
+		ad1889_debug("chip->wave.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
+				chip->wave.addr, next, chip->wave.addr + next);
+#endif		
+	}
+
+	if (chip->pcm && (st & AD_DMA_DISR_ADCI) && chip->csubs) {
+		spin_lock(&chip->lock);
+		
+		chip->stats.adc_intr++;
+
+		chip->ramc.buf++;
+		
+		/* calculate the current position: we get interrupts everytime
+		   the buffer empties, thus every wave.count bytes transfered */
+		chip->ramc.pos += chip->ramc.count;
+		chip->ramc.pos %= chip->ramc.size;
+
+		/* the next buffer will thus be current position + wave.count
+		   bytes away */
+		next = chip->ramc.pos + chip->ramc.count;
+		next %= chip->ramc.size;
+
+		/* Load new DMA parameters (aka "the next chunk" in Base
+		   registers: upon next interrupt, they'll be automatically
+		   loaded in the Current registers, and we'll end up here
+		   preparing the new ones. Since "count" never gets modified
+		   elsewhere than in _prepare, we don't need to rewrite it. */
+		ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + next);
+		
+		ad1889_readl(chip, AD_DMA_ADCBA); /* flush all those writes */
+
+		spin_unlock(&chip->lock);
+		
+		snd_pcm_period_elapsed(chip->csubs);
+#if 0
+		ad1889_debug("chip->ramc.pos = %d, chip->ramc.count = %d, "
+				"chip->ramc.size = %d\n", chip->ramc.pos,
+				chip->ramc.count, chip->ramc.size);
+		ad1889_debug("chip->ramc.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
+				chip->ramc.addr, next, chip->ramc.addr + next);
+#endif		
+	}
+
+	/* XXX under some circumstances the DISR write flush may not happen */
+
+	return IRQ_HANDLED;
+}
+
+static void 
+snd_ad1889_pcm_free(snd_pcm_t *pcm)
+{
+	struct snd_ad1889 *chip = pcm->private_data;
+	chip->pcm = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int __devinit
+snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, snd_pcm_t **rpcm)
+{
+	int err;
+	snd_pcm_t *pcm;
+
+	if (rpcm)
+		*rpcm = NULL;
+
+	err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 
+			&snd_ad1889_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+			&snd_ad1889_capture_ops);
+
+	pcm->private_data = chip;
+	pcm->private_free = snd_ad1889_pcm_free;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, chip->card->shortname);
+	
+	chip->pcm = pcm;
+	chip->psubs = NULL;
+	chip->csubs = NULL;
+
+	chip->dma.dev = &chip->pci->dev;
+	chip->dma.type = SNDRV_DMA_TYPE_DEV;
+
+	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+						snd_dma_pci_data(chip->pci),
+						DMA_SIZE, DMA_SIZE);
+
+	if (err < 0) {
+		snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);
+		return err;
+	}
+	
+	if (rpcm)
+		*rpcm = pcm;
+	
+	return 0;
+}
+
+static void
+snd_ad1889_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+	struct snd_ad1889 *chip = entry->private_data;
+	u16 reg;
+	int tmp;
+
+	reg = ad1889_readw(chip, AD_DS_WSMC);
+	snd_iprintf(buffer, "Wave output: %s\n",
+			(reg & AD_DS_WSMC_WAEN) ? "enabled" : "disabled");
+	snd_iprintf(buffer, "Wave Channels: %s\n",
+			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");
+	snd_iprintf(buffer, "Wave Quality: %d-bit linear\n",
+			(reg & AD_DS_WSMC_WA16) ? 16 : 8);
+	
+	/* WARQ is at offset 12 */
+	tmp = (reg & AD_DS_WSMC_WARQ) ?
+			(((reg & AD_DS_WSMC_WARQ >> 12) & 0x01) ? 12 : 18) : 4;
+	tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;
+	
+	snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp,
+			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");
+				
+	
+	snd_iprintf(buffer, "Synthesis output: %s\n",
+			reg & AD_DS_WSMC_SYEN ? "enabled" : "disabled");
+	
+	/* SYRQ is at offset 4 */
+	tmp = (reg & AD_DS_WSMC_SYRQ) ?
+			(((reg & AD_DS_WSMC_SYRQ >> 4) & 0x01) ? 12 : 18) : 4;
+	tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;
+	
+	snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp,
+			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");
+
+	reg = ad1889_readw(chip, AD_DS_RAMC);
+	snd_iprintf(buffer, "ADC input: %s\n",
+			(reg & AD_DS_RAMC_ADEN) ? "enabled" : "disabled");
+	snd_iprintf(buffer, "ADC Channels: %s\n",
+			(reg & AD_DS_RAMC_ADST) ? "stereo" : "mono");
+	snd_iprintf(buffer, "ADC Quality: %d-bit linear\n",
+			(reg & AD_DS_RAMC_AD16) ? 16 : 8);
+	
+	/* ACRQ is at offset 4 */
+	tmp = (reg & AD_DS_RAMC_ACRQ) ?
+			(((reg & AD_DS_RAMC_ACRQ >> 4) & 0x01) ? 12 : 18) : 4;
+	tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;
+	
+	snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp,
+			(reg & AD_DS_RAMC_ADST) ? "stereo" : "mono");
+	
+	snd_iprintf(buffer, "Resampler input: %s\n",
+			reg & AD_DS_RAMC_REEN ? "enabled" : "disabled");
+			
+	/* RERQ is at offset 12 */
+	tmp = (reg & AD_DS_RAMC_RERQ) ?
+			(((reg & AD_DS_RAMC_RERQ >> 12) & 0x01) ? 12 : 18) : 4;
+	tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;
+	
+	snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp,
+			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");
+				
+	
+	/* doc says LSB represents -1.5dB, but the max value (-94.5dB)
+	suggests that LSB is -3dB, which is more coherent with the logarithmic
+	nature of the dB scale */
+	reg = ad1889_readw(chip, AD_DS_WADA);
+	snd_iprintf(buffer, "Left: %s, -%d dB\n",
+			(reg & AD_DS_WADA_LWAM) ? "mute" : "unmute",
+			((reg & AD_DS_WADA_LWAA) >> 8) * 3);
+	reg = ad1889_readw(chip, AD_DS_WADA);
+	snd_iprintf(buffer, "Right: %s, -%d dB\n",
+			(reg & AD_DS_WADA_RWAM) ? "mute" : "unmute",
+			((reg & AD_DS_WADA_RWAA) >> 8) * 3);
+	
+	reg = ad1889_readw(chip, AD_DS_WAS);
+	snd_iprintf(buffer, "Wave samplerate: %u Hz\n", reg);
+	reg = ad1889_readw(chip, AD_DS_RES);
+	snd_iprintf(buffer, "Resampler samplerate: %u Hz\n", reg);
+}
+
+static void __devinit
+snd_ad1889_proc_init(struct snd_ad1889 *chip)
+{
+	snd_info_entry_t *entry;
+
+	if (!snd_card_proc_new(chip->card, chip->card->driver, &entry))
+		snd_info_set_text_ops(entry, chip, 1024, snd_ad1889_proc_read);
+}
+
+static struct ac97_quirk ac97_quirks[] = {
+	{
+		.subvendor = 0x11d4,	/* AD */
+		.subdevice = 0x1889,	/* AD1889 */
+		.codec_id = AC97_ID_AD1819,
+		.name = "AD1889",
+		.type = AC97_TUNE_HP_ONLY
+	},
+	{ } /* terminator */
+};
+
+static void __devinit
+snd_ad1889_ac97_xinit(struct snd_ad1889 *chip)
+{
+	u16 reg;
+
+	reg = ad1889_readw(chip, AD_AC97_ACIC);
+	reg |= AD_AC97_ACIC_ACRD;		/* Reset Disable */
+	ad1889_writew(chip, AD_AC97_ACIC, reg);
+	ad1889_readw(chip, AD_AC97_ACIC);	/* flush posted write */
+	udelay(10);
+	/* Interface Enable */
+	reg |= AD_AC97_ACIC_ACIE;
+	ad1889_writew(chip, AD_AC97_ACIC, reg);
+	
+	snd_ad1889_ac97_ready(chip);
+
+	/* Audio Stream Output | Variable Sample Rate Mode */
+	reg = ad1889_readw(chip, AD_AC97_ACIC);
+	reg |= AD_AC97_ACIC_ASOE | AD_AC97_ACIC_VSRM;
+	ad1889_writew(chip, AD_AC97_ACIC, reg);
+	ad1889_readw(chip, AD_AC97_ACIC); /* flush posted write */
+
+}
+
+static void
+snd_ad1889_ac97_bus_free(ac97_bus_t *bus)
+{
+	struct snd_ad1889 *chip = bus->private_data;
+	chip->ac97_bus = NULL;
+}
+
+static void
+snd_ad1889_ac97_free(ac97_t *ac97)
+{
+	struct snd_ad1889 *chip = ac97->private_data;
+	chip->ac97 = NULL;
+}
+
+static int __devinit
+snd_ad1889_ac97_init(struct snd_ad1889 *chip, const char *quirk_override)
+{
+	int err;
+	ac97_template_t ac97;
+	static ac97_bus_ops_t ops = {
+		.write = snd_ad1889_ac97_write,
+		.read = snd_ad1889_ac97_read,
+	};
+
+	/* doing that here, it works. */
+	snd_ad1889_ac97_xinit(chip);
+
+	err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus);
+	if (err < 0)
+		return err;
+	
+	chip->ac97_bus->private_free = snd_ad1889_ac97_bus_free;
+
+	memset(&ac97, 0, sizeof(ac97));
+	ac97.private_data = chip;
+	ac97.private_free = snd_ad1889_ac97_free;
+	ac97.pci = chip->pci;
+
+	err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97);
+	if (err < 0)
+		return err;
+		
+	snd_ac97_tune_hardware(chip->ac97, ac97_quirks, quirk_override);
+	
+	return 0;
+}
+
+static int
+snd_ad1889_free(struct snd_ad1889 *chip)
+{
+	if (chip->irq < 0)
+		goto skip_hw;
+
+	spin_lock_irq(&chip->lock);
+
+	ad1889_mute(chip);
+
+	/* Turn off interrupt on count and zero DMA registers */
+	ad1889_channel_reset(chip, AD_CHAN_WAV | AD_CHAN_ADC);
+
+	/* clear DISR. If we don't, we'd better jump off the Eiffel Tower */
+	ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PTAI | AD_DMA_DISR_PMAI);
+	ad1889_readl(chip, AD_DMA_DISR);	/* flush, dammit! */
+
+	spin_unlock_irq(&chip->lock);
+
+	synchronize_irq(chip->irq);
+	
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void*)chip);
+
+skip_hw:
+	if (chip->iobase)
+		iounmap(chip->iobase);
+
+	pci_release_regions(chip->pci);
+	pci_disable_device(chip->pci);
+
+	kfree(chip);
+	return 0;
+}
+
+static inline int
+snd_ad1889_dev_free(snd_device_t *device) 
+{
+	struct snd_ad1889 *chip = device->device_data;
+	return snd_ad1889_free(chip);
+}
+
+static int __devinit
+snd_ad1889_init(struct snd_ad1889 *chip) 
+{
+	ad1889_writew(chip, AD_DS_CCS, AD_DS_CCS_CLKEN); /* turn on clock */
+	ad1889_readw(chip, AD_DS_CCS);	/* flush posted write */
+
+	mdelay(10);
+
+	/* enable Master and Target abort interrupts */
+	ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PMAE | AD_DMA_DISR_PTAE);
+
+	return 0;
+}
+
+static int __devinit
+snd_ad1889_create(snd_card_t *card,
+		  struct pci_dev *pci,
+		  struct snd_ad1889 **rchip)
+{
+	int err;
+
+	struct snd_ad1889 *chip;
+	static snd_device_ops_t ops = {
+		.dev_free = snd_ad1889_dev_free,
+	};
+
+	*rchip = NULL;
+
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+	
+	/* check PCI availability (32bit DMA) */
+	if (pci_set_dma_mask(pci, 0xffffffff) < 0 ||
+	    pci_set_consistent_dma_mask(pci, 0xffffffff) < 0) {
+		printk(KERN_ERR PFX "error setting 32-bit DMA mask.\n");
+		pci_disable_device(pci);
+		return -ENXIO;
+	}
+
+	/* allocate chip specific data with zero-filled memory */
+	if ((chip = kcalloc(1, sizeof(*chip), GFP_KERNEL)) == NULL) {
+		pci_disable_device(pci);
+		return -ENOMEM;
+	}
+
+	chip->card = card;
+	card->private_data = chip;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	/* (1) PCI resource allocation */
+	if ((err = pci_request_regions(pci, card->driver)) < 0)
+		goto free_and_ret;
+
+	chip->bar = pci_resource_start(pci, 0);
+	chip->iobase = ioremap_nocache(chip->bar, pci_resource_len(pci, 0));
+	if (chip->iobase == NULL) {
+		printk(KERN_ERR PFX "unable to reserve region.\n");
+		err = -EBUSY;
+		goto free_and_ret;
+	}
+	
+	pci_set_master(pci);
+
+	spin_lock_init(&chip->lock);	/* only now can we call ad1889_free */
+
+	if (request_irq(pci->irq, snd_ad1889_interrupt,
+			SA_INTERRUPT|SA_SHIRQ, card->driver, (void*)chip)) {
+		printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq);
+		snd_ad1889_free(chip);
+		return -EBUSY;
+	}
+
+	chip->irq = pci->irq;
+	synchronize_irq(chip->irq);
+
+	/* (2) initialization of the chip hardware */
+	if ((err = snd_ad1889_init(chip)) < 0) {
+		snd_ad1889_free(chip);
+		return err;
+	}
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		snd_ad1889_free(chip);
+		return err;
+	}
+
+	snd_card_set_dev(card, &pci->dev);
+
+	*rchip = chip;
+
+	return 0;
+
+free_and_ret:
+	if (chip)
+		kfree(chip);
+	pci_disable_device(pci);
+
+	return err;
+}
+
+static int __devinit
+snd_ad1889_probe(struct pci_dev *pci,
+		 const struct pci_device_id *pci_id)
+{
+	int err;
+	static int devno;
+	snd_card_t *card;
+	struct snd_ad1889 *chip;
+
+	/* (1) */
+	if (devno >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[devno]) {
+		devno++;
+		return -ENOENT;
+	}
+
+	/* (2) */
+	card = snd_card_new(index[devno], id[devno], THIS_MODULE, 0);
+	/* XXX REVISIT: we can probably allocate chip in this call */
+	if (card == NULL)
+		return -ENOMEM;
+
+	strcpy(card->driver, "AD1889");
+	strcpy(card->shortname, "Analog Devices AD1889");
+
+	/* (3) */
+	err = snd_ad1889_create(card, pci, &chip);
+	if (err < 0)
+		goto free_and_ret;
+
+	/* (4) */
+	sprintf(card->longname, "%s at 0x%lx irq %i",
+		card->shortname, chip->bar, chip->irq);
+
+	/* (5) */
+	/* register AC97 mixer */
+	err = snd_ad1889_ac97_init(chip, ac97_quirk[devno]);
+	if (err < 0)
+		goto free_and_ret;
+	
+	err = snd_ad1889_pcm_init(chip, 0, NULL);
+	if (err < 0)
+		goto free_and_ret;
+
+	/* register proc interface */
+	snd_ad1889_proc_init(chip);
+
+	/* (6) */
+	err = snd_card_register(card);
+	if (err < 0)
+		goto free_and_ret;
+
+	/* (7) */
+	pci_set_drvdata(pci, card);
+
+	devno++;
+	return 0;
+
+free_and_ret:
+	snd_card_free(card);
+	return err;
+}
+
+static void __devexit
+snd_ad1889_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_device_id snd_ad1889_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) },
+	{ 0, },
+};
+MODULE_DEVICE_TABLE(pci, snd_ad1889_ids);
+
+static struct pci_driver ad1889_pci = {
+	.name = "AD1889 Audio",
+	.id_table = snd_ad1889_ids,
+	.probe = snd_ad1889_probe,
+	.remove = __devexit_p(snd_ad1889_remove),
+};
+
+static int __init
+alsa_ad1889_init(void)
+{
+	return pci_register_driver(&ad1889_pci);
+}
+
+static void __exit
+alsa_ad1889_fini(void)
+{
+	pci_unregister_driver(&ad1889_pci);
+}
+
+module_init(alsa_ad1889_init);
+module_exit(alsa_ad1889_fini);
diff -Nru linux-2.6.13-rc4.orig/sound/pci/ad1889.h linux-2.6.13-rc4/sound/pci/ad1889.h
--- linux-2.6.13-rc4.orig/sound/pci/ad1889.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.13-rc4/sound/pci/ad1889.h	2005-06-25 23:15:29.000000000 +0200
@@ -0,0 +1,187 @@
+/* Analog Devices 1889 audio driver
+ * Copyright (C) 2004, Kyle McMartin <kyle@parisc-linux.org>
+ */
+
+#ifndef __AD1889_H__
+#define __AD1889_H__
+
+#define AD_DS_WSMC	0x00 /* wave/synthesis channel mixer control */
+#define  AD_DS_WSMC_SYEN 0x0004 /* synthesis channel enable */
+#define  AD_DS_WSMC_SYRQ 0x0030 /* synth. fifo request point */
+#define  AD_DS_WSMC_WA16 0x0100 /* wave channel 16bit select */
+#define  AD_DS_WSMC_WAST 0x0200 /* wave channel stereo select */
+#define  AD_DS_WSMC_WAEN 0x0400 /* wave channel enable */
+#define  AD_DS_WSMC_WARQ 0x3000 /* wave fifo request point */
+
+#define AD_DS_RAMC	0x02 /* resampler/ADC channel mixer control */
+#define  AD_DS_RAMC_AD16 0x0001 /* ADC channel 16bit select */
+#define  AD_DS_RAMC_ADST 0x0002 /* ADC channel stereo select */
+#define  AD_DS_RAMC_ADEN 0x0004 /* ADC channel enable */
+#define  AD_DS_RAMC_ACRQ 0x0030 /* ADC fifo request point */
+#define  AD_DS_RAMC_REEN 0x0400 /* resampler channel enable */
+#define  AD_DS_RAMC_RERQ 0x3000 /* res. fifo request point */
+
+#define AD_DS_WADA	0x04 /* wave channel mix attenuation */
+#define  AD_DS_WADA_RWAM 0x0080 /* right wave mute */
+#define  AD_DS_WADA_RWAA 0x001f /* right wave attenuation */
+#define  AD_DS_WADA_LWAM 0x8000 /* left wave mute */
+#define  AD_DS_WADA_LWAA 0x3e00 /* left wave attenuation */
+
+#define AD_DS_SYDA	0x06 /* synthesis channel mix attenuation */
+#define  AD_DS_SYDA_RSYM 0x0080 /* right synthesis mute */
+#define  AD_DS_SYDA_RSYA 0x001f /* right synthesis attenuation */
+#define  AD_DS_SYDA_LSYM 0x8000 /* left synthesis mute */
+#define  AD_DS_SYDA_LSYA 0x3e00 /* left synthesis attenuation */
+
+#define AD_DS_WAS	0x08 /* wave channel sample rate */
+#define  AD_DS_WAS_WAS   0xffff /* sample rate mask */
+
+#define AD_DS_RES	0x0a /* resampler channel sample rate */
+#define  AD_DS_RES_RES   0xffff /* sample rate mask */
+
+#define AD_DS_CCS	0x0c /* chip control/status */
+#define  AD_DS_CCS_ADO   0x0001 /* ADC channel overflow */
+#define  AD_DS_CCS_REO   0x0002 /* resampler channel overflow */
+#define  AD_DS_CCS_SYU   0x0004 /* synthesis channel underflow */
+#define  AD_DS_CCS_WAU   0x0008 /* wave channel underflow */
+/* bits 4 -> 7, 9, 11 -> 14 reserved */
+#define  AD_DS_CCS_XTD   0x0100 /* xtd delay control (4096 clock cycles) */
+#define  AD_DS_CCS_PDALL 0x0400 /* power */
+#define  AD_DS_CCS_CLKEN 0x8000 /* clock */
+
+#define AD_DMA_RESBA	0x40 /* RES base address */
+#define AD_DMA_RESCA	0x44 /* RES current address */
+#define AD_DMA_RESBC	0x48 /* RES base count */
+#define AD_DMA_RESCC	0x4c /* RES current count */
+
+#define AD_DMA_ADCBA	0x50 /* ADC base address */
+#define AD_DMA_ADCCA	0x54 /* ADC current address */
+#define AD_DMA_ADCBC	0x58 /* ADC base count */
+#define AD_DMA_ADCCC	0x5c /* ADC current count */
+
+#define AD_DMA_SYNBA	0x60 /* synth base address */
+#define AD_DMA_SYNCA	0x64 /* synth current address */
+#define AD_DMA_SYNBC	0x68 /* synth base count */
+#define AD_DMA_SYNCC	0x6c /* synth current count */
+
+#define AD_DMA_WAVBA	0x70 /* wave base address */
+#define AD_DMA_WAVCA	0x74 /* wave current address */
+#define AD_DMA_WAVBC	0x78 /* wave base count */
+#define AD_DMA_WAVCC	0x7c /* wave current count */
+
+#define AD_DMA_RESIC	0x80 /* RES dma interrupt current byte count */
+#define AD_DMA_RESIB	0x84 /* RES dma interrupt base byte count */
+
+#define AD_DMA_ADCIC	0x88 /* ADC dma interrupt current byte count */
+#define AD_DMA_ADCIB	0x8c /* ADC dma interrupt base byte count */
+
+#define AD_DMA_SYNIC	0x90 /* synth dma interrupt current byte count */
+#define AD_DMA_SYNIB	0x94 /* synth dma interrupt base byte count */
+
+#define AD_DMA_WAVIC	0x98 /* wave dma interrupt current byte count */
+#define AD_DMA_WAVIB	0x9c /* wave dma interrupt base byte count */
+
+#define  AD_DMA_ICC	0xffffff /* current byte count mask */
+#define  AD_DMA_IBC	0xffffff /* base byte count mask */
+/* bits 24 -> 31 reserved */
+
+/* 4 bytes pad */
+#define AD_DMA_ADC	0xa8	/* ADC      dma control and status */
+#define AD_DMA_SYNTH	0xb0	/* Synth    dma control and status */
+#define AD_DMA_WAV	0xb8	/* wave     dma control and status */
+#define AD_DMA_RES	0xa0	/* Resample dma control and status */
+
+#define  AD_DMA_SGDE	0x0001 /* SGD mode enable */
+#define  AD_DMA_LOOP	0x0002 /* loop enable */
+#define  AD_DMA_IM	0x000c /* interrupt mode mask */
+#define  AD_DMA_IM_DIS	(~AD_DMA_IM)	/* disable */
+#define  AD_DMA_IM_CNT	0x0004 /* interrupt on count */
+#define  AD_DMA_IM_SGD	0x0008 /* interrupt on SGD flag */
+#define  AD_DMA_IM_EOL	0x000c /* interrupt on End of Linked List */
+#define  AD_DMA_SGDS	0x0030 /* SGD status */
+#define  AD_DMA_SFLG	0x0040 /* SGD flag */
+#define  AD_DMA_EOL	0x0080 /* SGD end of list */
+/* bits 8 -> 15 reserved */
+
+#define AD_DMA_DISR	0xc0 /* dma interrupt status */
+#define  AD_DMA_DISR_RESI 0x000001 /* resampler channel interrupt */
+#define  AD_DMA_DISR_ADCI 0x000002 /* ADC channel interrupt */
+#define  AD_DMA_DISR_SYNI 0x000004 /* synthesis channel interrupt */
+#define  AD_DMA_DISR_WAVI 0x000008 /* wave channel interrupt */
+/* bits 4, 5 reserved */
+#define  AD_DMA_DISR_SEPS 0x000040 /* serial eeprom status */
+/* bits 7 -> 13 reserved */
+#define  AD_DMA_DISR_PMAI 0x004000 /* pci master abort interrupt */
+#define  AD_DMA_DISR_PTAI 0x008000 /* pci target abort interrupt */
+#define  AD_DMA_DISR_PTAE 0x010000 /* pci target abort interrupt enable */
+#define  AD_DMA_DISR_PMAE 0x020000 /* pci master abort interrupt enable */
+/* bits 19 -> 31 reserved */
+
+/* interrupt mask */
+#define  AD_INTR_MASK     (AD_DMA_DISR_RESI|AD_DMA_DISR_ADCI| \
+                           AD_DMA_DISR_WAVI|AD_DMA_DISR_SYNI| \
+                           AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI)
+
+#define AD_DMA_CHSS	0xc4 /* dma channel stop status */
+#define  AD_DMA_CHSS_RESS 0x000001 /* resampler channel stopped */
+#define  AD_DMA_CHSS_ADCS 0x000002 /* ADC channel stopped */
+#define  AD_DMA_CHSS_SYNS 0x000004 /* synthesis channel stopped */
+#define  AD_DMA_CHSS_WAVS 0x000008 /* wave channel stopped */
+
+#define AD_GPIO_IPC	0xc8	/* gpio port control */
+#define AD_GPIO_OP	0xca	/* gpio output port status */
+#define AD_GPIO_IP	0xcc	/* gpio  input port status */
+
+#define AD_AC97_BASE	0x100	/* ac97 base register */
+
+#define AD_AC97_RESET   0x100   /* reset */
+
+#define AD_AC97_PWR_CTL	0x126	/* == AC97_POWERDOWN */
+#define  AD_AC97_PWR_ADC 0x0001 /* ADC ready status */
+#define  AD_AC97_PWR_DAC 0x0002 /* DAC ready status */
+#define  AD_AC97_PWR_PR0 0x0100 /* PR0 (ADC) powerdown */
+#define  AD_AC97_PWR_PR1 0x0200 /* PR1 (DAC) powerdown */
+
+#define AD_MISC_CTL     0x176 /* misc control */
+#define  AD_MISC_CTL_DACZ   0x8000 /* set for zero fill, unset for repeat */
+#define  AD_MISC_CTL_ARSR   0x0001 /* set for SR1, unset for SR0 */
+#define  AD_MISC_CTL_ALSR   0x0100
+#define  AD_MISC_CTL_DLSR   0x0400
+#define  AD_MISC_CTL_DRSR   0x0004
+
+#define AD_AC97_SR0     0x178 /* sample rate 0, 0xbb80 == 48K */
+#define  AD_AC97_SR0_48K 0xbb80 /* 48KHz */
+#define AD_AC97_SR1     0x17a /* sample rate 1 */
+
+#define AD_AC97_ACIC	0x180 /* ac97 codec interface control */
+#define  AD_AC97_ACIC_ACIE  0x0001 /* analog codec interface enable */
+#define  AD_AC97_ACIC_ACRD  0x0002 /* analog codec reset disable */
+#define  AD_AC97_ACIC_ASOE  0x0004 /* audio stream output enable */
+#define  AD_AC97_ACIC_VSRM  0x0008 /* variable sample rate mode */
+#define  AD_AC97_ACIC_FSDH  0x0100 /* force SDATA_OUT high */
+#define  AD_AC97_ACIC_FSYH  0x0200 /* force sync high */
+#define  AD_AC97_ACIC_ACRDY 0x8000 /* analog codec ready status */
+/* bits 10 -> 14 reserved */
+
+
+#define AD_DS_MEMSIZE	512
+#define AD_OPL_MEMSIZE	16
+#define AD_MIDI_MEMSIZE	16
+
+#define AD_WAV_STATE	0
+#define AD_ADC_STATE	1
+#define AD_MAX_STATES	2
+
+/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
+   But the IOMMU can only map at page size granularity."
+   This affects in particular .period_bytes_min */
+#define BUF_SIZE        PAGE_SIZE
+#define MAX_BUFS        32
+#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
+
+#define AD_CHAN_WAV	0x0001
+#define AD_CHAN_ADC	0x0002
+#define AD_CHAN_RES	0x0004
+#define AD_CHAN_SYN	0x0008
+
+#endif /* __AD1889_H__ */
diff -Nru linux-2.6.13-rc4.orig/sound/pci/Kconfig linux-2.6.13-rc4/sound/pci/Kconfig
--- linux-2.6.13-rc4.orig/sound/pci/Kconfig	2005-07-29 19:12:48.000000000 +0200
+++ linux-2.6.13-rc4/sound/pci/Kconfig	2005-07-29 19:37:04.000000000 +0200
@@ -21,6 +21,18 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-ali5451.
 
+config SND_AD1889
+	tristate "Analog Devices AD1889"
+	depends on SND
+	select SND_AC97_CODEC
+	help
+	  Say Y here to include support for the integrated AC97 sound
+	  device found in particular on the Hewlett-Packard [BCJ]-xxx0
+	  class PA-RISC workstations, using the AD1819 codec.
+
+	  To compile this as a module, choose M here: the module
+	  will be called snd-ad1889.
+
 config SND_ATIIXP
 	tristate "ATI IXP AC97 Controller"
 	depends on SND
diff -Nru linux-2.6.13-rc4.orig/sound/pci/Makefile linux-2.6.13-rc4/sound/pci/Makefile
--- linux-2.6.13-rc4.orig/sound/pci/Makefile	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.13-rc4/sound/pci/Makefile	2005-04-02 01:02:22.000000000 +0200
@@ -4,6 +4,7 @@
 #
 
 snd-als4000-objs := als4000.o
+snd-ad1889-objs := ad1889.o
 snd-atiixp-objs := atiixp.o
 snd-atiixp-modem-objs := atiixp_modem.o
 snd-azt3328-objs := azt3328.o
@@ -26,6 +27,7 @@
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ALS4000) += snd-als4000.o
+obj-$(CONFIG_SND_AD1889) += snd-ad1889.o
 obj-$(CONFIG_SND_ATIIXP) += snd-atiixp.o
 obj-$(CONFIG_SND_ATIIXP_MODEM) += snd-atiixp-modem.o
 obj-$(CONFIG_SND_AZT3328) += snd-azt3328.o

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
@ 2005-07-29 19:16 Thibaut VARENE
  0 siblings, 0 replies; 35+ messages in thread
From: Thibaut VARENE @ 2005-07-29 19:16 UTC (permalink / raw)
  To: perex; +Cc: alsa-devel, parisc-linux, kyle


[-- Attachment #1.1.1: Type: text/plain, Size: 994 bytes --]

Hi,

Attached is a patch against 2.6.13-rc4 providing support for Analog
Devices AD1889 PCI Sound chip, which is especially found on some HP
PA-RISC machines.

The driver has been successfully tested on parisc and ppc architectures,
and offers support for full duplex playback (variable rates, mono/stereo
8/16bit) and capture (fixed 48kHz, mono/stereo 8/16bit).

It's developed and maintained in the parisc-linux.org CVS kernel tree
(http://cvs.parisc-linux.org/), and has a status webpage on
http://wiki.parisc-linux.org/AD1889

This patch doesn't yet feature OPL3 code, because it's still work in
progress in our development tree.

Here's the diffstat summary:

 MAINTAINERS        |    9
 sound/pci/Kconfig  |   12
 sound/pci/Makefile |    2
 sound/pci/ad1889.c | 1166
+++++++++++++++++++++++++++++++++++++++++++++++++++++
 sound/pci/ad1889.h |  187 ++++++++
 5 files changed, 1376 insertions(+)

HTH

Thibaut VARENE
The PA/Linux Team
http://www.pateam.org/

[-- Attachment #1.1.2: analog-devices-ad1889-driver.patch --]
[-- Type: text/plain, Size: 43836 bytes --]

diff -Nru linux-2.6.13-rc4.orig/MAINTAINERS linux-2.6.13-rc4/MAINTAINERS
--- linux-2.6.13-rc4.orig/MAINTAINERS	2005-07-29 19:10:19.000000000 +0200
+++ linux-2.6.13-rc4/MAINTAINERS	2005-07-29 19:33:41.000000000 +0200
@@ -191,6 +191,15 @@
 W:	http://linux.thorsten-knabe.de
 S:	Maintained
 
+AD1889 SOUND DRIVER
+P:      Kyle McMartin
+M:      kyle@parisc-linux.org
+P:      Thibaut Varene
+M:      T-Bone@parisc-linux.org
+W:      http://wiki.parisc-linux.org/AD1889
+L:      parisc-linux@lists.parisc-linux.org
+S:      Maintained
+
 ADM1025 HARDWARE MONITOR DRIVER
 P:	Jean Delvare
 M:	khali@linux-fr.org
diff -Nru linux-2.6.13-rc4.orig/sound/pci/ad1889.c linux-2.6.13-rc4/sound/pci/ad1889.c
--- linux-2.6.13-rc4.orig/sound/pci/ad1889.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.13-rc4/sound/pci/ad1889.c	2005-07-29 19:35:42.000000000 +0200
@@ -0,0 +1,1166 @@
+/* Analog Devices 1889 audio driver
+ *
+ * This is a driver for the AD1889 PCI audio chipset found
+ * on the HP PA-RISC [BCJ]-xxx0 workstations.
+ *
+ * Copyright (C) 2004-2005, Kyle McMartin <kyle@parisc-linux.org>
+ * Copyright (C) 2005, Thibaut Varene <varenet@parisc-linux.org>
+ *   Based on the OSS AD1889 driver by Randolph Chung <tausq@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO:
+ *	Do we need to take care of CCS register?
+ *	Maybe we could use finer grained locking (separate locks for pb/cap)?
+ * Wishlist:
+ *	Control Interface (mixer) support
+ *	Better AC97 support (VSR...)?
+ *	PM support
+ *	MIDI support
+ *	Game Port support
+ *	SG DMA support (this will need *alot* of work)
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+
+#include <asm/io.h>
+
+#include "ad1889.h"
+#include "ac97/ac97_id.h"
+
+#define	AD1889_DRVVER	"$Revision: 1.31 $"
+
+MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>, Thibaut Varene <t-bone@parisc-linux.org>");
+MODULE_DESCRIPTION("Analog Devices AD1889 ALSA sound driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(AD1889_DRVVER);
+MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1889}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for the AD1889 soundcard.");
+
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for the AD1889 soundcard.");
+
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable AD1889 soundcard.");
+
+static char *ac97_quirk[SNDRV_CARDS];
+module_param_array(ac97_quirk, charp, NULL, 0444);
+MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
+
+#define DEVNAME "ad1889"
+#define PFX	DEVNAME ": "
+
+/* let's use the global sound debug interfaces */
+#define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)
+
+/* keep track of each hw register */
+struct ad1889_register_state {
+	u16 reg;	/* reg setup */
+	u32 addr;	/* dma base address */
+	u16 rate;	/* sample rate */
+	unsigned long pos;	/* last recorded DMA buffer position */
+	unsigned long buf;	/* period # */
+	unsigned long size;	/* DMA buffer size */
+	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
+};
+
+struct snd_ad1889 {
+	snd_card_t *card;
+	struct pci_dev *pci;
+
+	int irq;
+	unsigned long bar;
+	void __iomem *iobase;
+
+	ac97_t *ac97;
+	ac97_bus_t *ac97_bus;
+	snd_pcm_t *pcm;
+	snd_info_entry_t *proc;
+
+	struct snd_dma_device dma;
+	snd_pcm_substream_t *psubs;
+	snd_pcm_substream_t *csubs;
+
+	/* playback register state */
+	struct ad1889_register_state wave;
+	struct ad1889_register_state ramc;
+
+	struct {
+		unsigned long wav_intr;
+		unsigned long adc_intr;
+		unsigned long syn_intr;
+		unsigned long res_intr;
+	} stats;
+
+	spinlock_t lock;
+};
+
+static inline u16
+ad1889_readw(struct snd_ad1889 *chip, unsigned reg)
+{
+	return ioread16(chip->iobase + reg);
+}
+
+static inline void
+ad1889_writew(struct snd_ad1889 *chip, unsigned reg, u16 val)
+{
+	iowrite16(val, chip->iobase + reg);
+}
+
+static inline u32
+ad1889_readl(struct snd_ad1889 *chip, unsigned reg)
+{
+	return ioread32(chip->iobase + reg);
+}
+
+static inline void
+ad1889_writel(struct snd_ad1889 *chip, unsigned reg, u32 val)
+{
+	iowrite32(val, chip->iobase + reg);
+}
+
+static inline void
+ad1889_unmute(struct snd_ad1889 *chip)
+{
+	u16 st;
+	st = ad1889_readw(chip, AD_DS_WADA) & 
+		~(AD_DS_WADA_RWAM | AD_DS_WADA_LWAM);
+	ad1889_writew(chip, AD_DS_WADA, st);
+	ad1889_readw(chip, AD_DS_WADA);
+}
+
+static inline void
+ad1889_mute(struct snd_ad1889 *chip)
+{
+	u16 st;
+	st = ad1889_readw(chip, AD_DS_WADA) | AD_DS_WADA_RWAM | AD_DS_WADA_LWAM;
+	ad1889_writew(chip, AD_DS_WADA, st);
+	ad1889_readw(chip, AD_DS_WADA);
+}
+
+static inline void
+ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
+{
+	ad1889_writel(chip, AD_DMA_ADCBC, count);
+	ad1889_writel(chip, AD_DMA_ADCCC, count);
+	ad1889_writel(chip, AD_DMA_ADCIB, count);
+	ad1889_writel(chip, AD_DMA_ADCIC, count);
+}	
+
+static inline void
+ad1889_load_wave_count(struct snd_ad1889 *chip, u32 count)
+{
+	ad1889_writel(chip, AD_DMA_WAVBC, count);
+	ad1889_writel(chip, AD_DMA_WAVCC, count);
+	ad1889_writel(chip, AD_DMA_WAVIB, count);
+	ad1889_writel(chip, AD_DMA_WAVIC, count);
+}	
+
+static void
+ad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel)
+{
+	u16 reg;
+	
+	if (channel & AD_CHAN_WAV) {
+		/* Disable wave channel */
+		reg = ad1889_readw(chip, AD_DS_WSMC) & ~AD_DS_WSMC_WAEN;
+		ad1889_writew(chip, AD_DS_WSMC, reg);
+		chip->wave.reg = reg;
+		
+		/* disable IRQs */
+		reg = ad1889_readw(chip, AD_DMA_WAV);
+		reg &= AD_DMA_IM_DIS;
+		reg &= ~AD_DMA_LOOP;
+		ad1889_writew(chip, AD_DMA_WAV, reg);
+
+		/* clear IRQ and address counters and pointers */
+		ad1889_load_wave_count(chip, 0x0);
+		ad1889_writel(chip, AD_DMA_WAVBA, 0x0);
+		ad1889_writel(chip, AD_DMA_WAVCA, 0x0);
+
+		/* flush */
+		ad1889_readw(chip, AD_DMA_WAV);
+	}
+	
+	if (channel & AD_CHAN_ADC) {
+		/* Disable ADC channel */
+		reg = ad1889_readw(chip, AD_DS_RAMC) & ~AD_DS_RAMC_ADEN;
+		ad1889_writew(chip, AD_DS_RAMC, reg);
+		chip->ramc.reg = reg;
+
+		reg = ad1889_readw(chip, AD_DMA_ADC);
+		reg &= AD_DMA_IM_DIS;
+		reg &= ~AD_DMA_LOOP;
+		ad1889_writew(chip, AD_DMA_ADC, reg);
+	
+		ad1889_load_adc_count(chip, 0x0);
+		ad1889_writel(chip, AD_DMA_ADCBA, 0x0);
+		ad1889_writel(chip, AD_DMA_ADCCA, 0x0);
+
+		/* flush */
+		ad1889_readw(chip, AD_DMA_ADC);
+	}
+}
+
+static inline u16
+snd_ad1889_ac97_read(ac97_t *ac97, unsigned short reg)
+{
+	struct snd_ad1889 *chip = ac97->private_data;
+	return ad1889_readw(chip, AD_AC97_BASE + reg);
+}
+
+static inline void
+snd_ad1889_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
+{
+	struct snd_ad1889 *chip = ac97->private_data;
+	ad1889_writew(chip, AD_AC97_BASE + reg, val);
+}
+
+static int
+snd_ad1889_ac97_ready(struct snd_ad1889 *chip)
+{
+	int retry = 400; /* average needs 352 msec */
+	
+	while (!(ad1889_readw(chip, AD_AC97_ACIC) & AD_AC97_ACIC_ACRDY) 
+			&& --retry)
+		mdelay(1);
+	if (!retry) {
+		snd_printk(KERN_ERR PFX "[%s] Link is not ready.\n",
+		       __FUNCTION__);
+		return -EIO;
+	}
+	ad1889_debug("[%s] ready after %d ms\n", __FUNCTION__, 400 - retry);
+
+	return 0;
+}
+
+static int 
+snd_ad1889_hw_params(snd_pcm_substream_t *substream,
+			snd_pcm_hw_params_t *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream, 
+					params_buffer_bytes(hw_params));
+}
+
+static int
+snd_ad1889_hw_free(snd_pcm_substream_t *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static snd_pcm_hardware_t snd_ad1889_playback_hw = {
+	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rate_min = 8000,	/* docs say 7000, but we're lazy */
+	.rate_max = 48000,
+	.channels_min = 1,
+	.channels_max = 2,
+	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
+	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
+	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
+	.periods_min = 1,		/* min nb of periods in buffer */
+	.periods_max = MAX_BUFS,
+	/*.fifo_size = 0,*/
+};
+
+static snd_pcm_hardware_t snd_ad1889_capture_hw = {
+	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	.rates = SNDRV_PCM_RATE_48000,
+	.rate_min = 48000,	/* docs say we could to VSR, but we're lazy */
+	.rate_max = 48000,
+	.channels_min = 1,
+	.channels_max = 2,
+	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
+	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
+	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
+	.periods_min = 1,		/* min nb of periods in buffer */
+	.periods_max = MAX_BUFS,
+	/*.fifo_size = 0,*/
+};
+
+static int
+snd_ad1889_playback_open(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
+
+	chip->psubs = ss;
+	rt->hw = snd_ad1889_playback_hw;
+
+	return 0;
+}
+
+static int
+snd_ad1889_capture_open(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
+
+	chip->csubs = ss;
+	rt->hw = snd_ad1889_capture_hw;
+
+	return 0;
+}
+
+static int
+snd_ad1889_playback_close(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	chip->psubs = NULL;
+	return 0;
+}
+
+static int
+snd_ad1889_capture_close(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	chip->csubs = NULL;
+	return 0;
+}
+
+static int
+snd_ad1889_playback_prepare(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
+	unsigned int size = snd_pcm_lib_buffer_bytes(ss);
+	unsigned int count = snd_pcm_lib_period_bytes(ss);
+	u16 reg;
+
+	ad1889_channel_reset(chip, AD_CHAN_WAV);
+
+	reg = ad1889_readw(chip, AD_DS_WSMC);
+	
+	/* Mask out 16-bit / Stereo */
+	reg &= ~(AD_DS_WSMC_WA16 | AD_DS_WSMC_WAST);
+
+	if (snd_pcm_format_width(rt->format) == 16)
+		reg |= AD_DS_WSMC_WA16;
+
+	if (rt->channels > 1)
+		reg |= AD_DS_WSMC_WAST;
+
+	/* let's make sure we don't clobber ourselves */
+	spin_lock_irq(&chip->lock);
+	
+	chip->wave.size = size;
+	chip->wave.count = count;
+	chip->wave.reg = reg;
+	chip->wave.buf = 0;
+	chip->wave.pos = 0;
+	chip->wave.rate = rt->rate;
+	chip->wave.addr = rt->dma_addr;
+
+	ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg);
+	
+	/* Set sample rates on the codec */
+	ad1889_writew(chip, AD_DS_WAS, chip->wave.rate);
+
+	/* Set up DMA: first chunk address in curr addr, next one in base addr.
+	   Base will be loaded into curr by the hardware upon interrupt
+	   (as we use LOOP). Count holds the size of the chunk. */
+	ad1889_writel(chip, AD_DMA_WAVCA, chip->wave.addr);
+	ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + (count % size));
+	ad1889_load_wave_count(chip, chip->wave.count);
+
+	/* writes flush */
+	ad1889_readw(chip, AD_DS_WSMC);
+	
+	spin_unlock_irq(&chip->lock);
+	
+	ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
+			"size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
+			count, size, reg, chip->wave.rate);
+	return 0;
+}
+
+static int
+snd_ad1889_capture_prepare(snd_pcm_substream_t *ss)
+{
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	snd_pcm_runtime_t *rt = ss->runtime;
+	unsigned int size = snd_pcm_lib_buffer_bytes(ss);
+	unsigned int count = snd_pcm_lib_period_bytes(ss);
+	u16 reg;
+
+	ad1889_channel_reset(chip, AD_CHAN_ADC);
+	
+	reg = ad1889_readw(chip, AD_DS_RAMC);
+
+	/* Mask out 16-bit / Stereo */
+	reg &= ~(AD_DS_RAMC_AD16 | AD_DS_RAMC_ADST);
+
+	if (snd_pcm_format_width(rt->format) == 16)
+		reg |= AD_DS_RAMC_AD16;
+
+	if (rt->channels > 1)
+		reg |= AD_DS_RAMC_ADST;
+
+	/* let's make sure we don't clobber ourselves */
+	spin_lock_irq(&chip->lock);
+	
+	chip->ramc.size = size;
+	chip->ramc.count = count;
+	chip->ramc.reg = reg;
+	chip->ramc.buf = 0;
+	chip->ramc.pos = 0;
+	chip->ramc.rate = rt->rate;
+	chip->ramc.addr = rt->dma_addr;
+
+	ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg);
+
+	/* Set up DMA: first chunk address in curr addr, next one in base addr.
+	   Base will be loaded into curr by the hardware upon interrupt
+	   (as we use LOOP). Count holds the size of the chunk. */
+	ad1889_writel(chip, AD_DMA_ADCCA, chip->ramc.addr);
+	ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + (count % size));
+	ad1889_load_adc_count(chip, chip->ramc.count);
+
+	/* writes flush */
+	ad1889_readw(chip, AD_DS_RAMC);
+	
+	spin_unlock_irq(&chip->lock);
+	
+	ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
+			"size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
+			count, size, reg, chip->ramc.rate);
+	return 0;
+}
+
+/* this is called in atomic context with IRQ disabled.
+   Must be as fast as possible and not sleep.
+   DMA should be *triggered* by this call.
+   The WSMC "WAEN" bit triggers DMA Wave On/Off */
+static int
+snd_ad1889_playback_trigger(snd_pcm_substream_t *ss, int cmd)
+{
+	u16 wsmc;
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+	
+	wsmc = ad1889_readw(chip, AD_DS_WSMC);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* enable DMA loop & interrupts */
+		ad1889_writew(chip, AD_DMA_WAV, AD_DMA_LOOP | AD_DMA_IM_CNT);
+		wsmc |= AD_DS_WSMC_WAEN;
+		/* 1 to clear CHSS bit */
+		ad1889_writel(chip, AD_DMA_CHSS, AD_DMA_CHSS_WAVS);
+		ad1889_unmute(chip);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		ad1889_mute(chip);
+		wsmc &= ~AD_DS_WSMC_WAEN;
+		break;
+	default:
+		snd_BUG();
+		return -EINVAL;
+	}
+	
+	chip->wave.reg = wsmc;
+	ad1889_writew(chip, AD_DS_WSMC, wsmc);	
+	ad1889_readw(chip, AD_DS_WSMC);	/* flush */
+
+	/* reset the chip when STOP - will disable IRQs */
+	if (cmd == SNDRV_PCM_TRIGGER_STOP)
+		ad1889_channel_reset(chip, AD_CHAN_WAV);
+
+	return 0;
+}
+
+/* this is called in atomic context with IRQ disabled.
+   Must be as fast as possible and not sleep.
+   DMA should be *triggered* by this call.
+   The RAMC "ADEN" bit triggers DMA ADC On/Off */
+static int
+snd_ad1889_capture_trigger(snd_pcm_substream_t *ss, int cmd)
+{
+	u16 ramc;
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+
+	ramc = ad1889_readw(chip, AD_DS_RAMC);
+	
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* enable DMA loop & interrupts */
+		ad1889_writew(chip, AD_DMA_ADC, AD_DMA_LOOP | AD_DMA_IM_CNT);
+		ramc |= AD_DS_RAMC_ADEN;
+		/* 1 to clear CHSS bit */
+		ad1889_writel(chip, AD_DMA_CHSS, AD_DMA_CHSS_ADCS);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		ramc &= ~AD_DS_RAMC_ADEN;
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	chip->ramc.reg = ramc;
+	ad1889_writew(chip, AD_DS_RAMC, ramc);	
+	ad1889_readw(chip, AD_DS_RAMC);	/* flush */
+	
+	/* reset the chip when STOP - will disable IRQs */
+	if (cmd == SNDRV_PCM_TRIGGER_STOP)
+		ad1889_channel_reset(chip, AD_CHAN_ADC);
+		
+	return 0;
+}
+
+/* Called in atomic context with IRQ disabled */
+static snd_pcm_uframes_t
+snd_ad1889_playback_pointer(snd_pcm_substream_t *ss)
+{
+	size_t ptr = 0;
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+
+	if (unlikely(!(chip->wave.reg & AD_DS_WSMC_WAEN)))
+		return 0;
+
+	ptr = ad1889_readl(chip, AD_DMA_WAVCA);
+	ptr -= chip->wave.addr;
+	
+	snd_assert((ptr >= 0) && (ptr < chip->wave.size), return 0);
+	
+	return bytes_to_frames(ss->runtime, ptr);
+}
+
+/* Called in atomic context with IRQ disabled */
+static snd_pcm_uframes_t
+snd_ad1889_capture_pointer(snd_pcm_substream_t *ss)
+{
+	size_t ptr = 0;
+	struct snd_ad1889 *chip = snd_pcm_substream_chip(ss);
+
+	if (unlikely(!(chip->ramc.reg & AD_DS_RAMC_ADEN)))
+		return 0;
+
+	ptr = ad1889_readl(chip, AD_DMA_ADCCA);
+	ptr -= chip->ramc.addr;
+
+	snd_assert((ptr >= 0) && (ptr < chip->ramc.size), return 0);
+	
+	return bytes_to_frames(ss->runtime, ptr);
+}
+
+static snd_pcm_ops_t snd_ad1889_playback_ops = {
+	.open = snd_ad1889_playback_open,
+	.close = snd_ad1889_playback_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_ad1889_hw_params,
+	.hw_free = snd_ad1889_hw_free,
+	.prepare = snd_ad1889_playback_prepare,
+	.trigger = snd_ad1889_playback_trigger,
+	.pointer = snd_ad1889_playback_pointer, 
+};
+
+static snd_pcm_ops_t snd_ad1889_capture_ops = {
+	.open = snd_ad1889_capture_open,
+	.close = snd_ad1889_capture_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_ad1889_hw_params,
+	.hw_free = snd_ad1889_hw_free,
+	.prepare = snd_ad1889_capture_prepare,
+	.trigger = snd_ad1889_capture_trigger,
+	.pointer = snd_ad1889_capture_pointer, 
+};
+
+static irqreturn_t
+snd_ad1889_interrupt(int irq, 
+		     void *dev_id, 
+		     struct pt_regs *regs)
+{
+	unsigned long st;
+	unsigned long next;
+	struct snd_ad1889 *chip = dev_id;
+
+	st = ad1889_readl(chip, AD_DMA_DISR);
+
+	/* clear ISR */
+	ad1889_writel(chip, AD_DMA_DISR, st);
+
+	st &= AD_INTR_MASK;
+
+	if (unlikely(!st))
+		return IRQ_NONE;
+
+	if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
+		ad1889_debug("Unexpected master or target abort interrupt!\n");
+
+	if (chip->pcm && (st & AD_DMA_DISR_WAVI) && chip->psubs) {
+		spin_lock(&chip->lock);
+
+		chip->stats.wav_intr++;
+
+		chip->wave.buf++;
+
+		/* calculate the current position: we get interrupts everytime
+		   the buffer empties, thus every wave.count bytes transfered */
+		chip->wave.pos += chip->wave.count;
+		chip->wave.pos %= chip->wave.size;
+
+		/* the next buffer will thus be current position + wave.count
+		   bytes away */
+		next = chip->wave.pos + chip->wave.count;
+		next %= chip->wave.size;
+		
+		/* Load new DMA parameters (aka "the next chunk" in Base
+		   registers: upon next interrupt, they'll be automatically
+		   loaded in the Current registers, and we'll end up here
+		   preparing the new ones. Since "count" never gets modified
+		   elsewhere than in _prepare, we don't need to rewrite it. */
+		ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + next);
+		
+		ad1889_readl(chip, AD_DMA_WAVBA); /* flush all those writes */
+
+		spin_unlock(&chip->lock);
+
+		snd_pcm_period_elapsed(chip->psubs);
+#if 0
+		ad1889_debug("chip->wave.pos = %d, chip->wave.count = %d, "
+				"chip->wave.size = %d\n", chip->wave.pos,
+				chip->wave.count, chip->wave.size);
+		ad1889_debug("chip->wave.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
+				chip->wave.addr, next, chip->wave.addr + next);
+#endif		
+	}
+
+	if (chip->pcm && (st & AD_DMA_DISR_ADCI) && chip->csubs) {
+		spin_lock(&chip->lock);
+		
+		chip->stats.adc_intr++;
+
+		chip->ramc.buf++;
+		
+		/* calculate the current position: we get interrupts everytime
+		   the buffer empties, thus every wave.count bytes transfered */
+		chip->ramc.pos += chip->ramc.count;
+		chip->ramc.pos %= chip->ramc.size;
+
+		/* the next buffer will thus be current position + wave.count
+		   bytes away */
+		next = chip->ramc.pos + chip->ramc.count;
+		next %= chip->ramc.size;
+
+		/* Load new DMA parameters (aka "the next chunk" in Base
+		   registers: upon next interrupt, they'll be automatically
+		   loaded in the Current registers, and we'll end up here
+		   preparing the new ones. Since "count" never gets modified
+		   elsewhere than in _prepare, we don't need to rewrite it. */
+		ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + next);
+		
+		ad1889_readl(chip, AD_DMA_ADCBA); /* flush all those writes */
+
+		spin_unlock(&chip->lock);
+		
+		snd_pcm_period_elapsed(chip->csubs);
+#if 0
+		ad1889_debug("chip->ramc.pos = %d, chip->ramc.count = %d, "
+				"chip->ramc.size = %d\n", chip->ramc.pos,
+				chip->ramc.count, chip->ramc.size);
+		ad1889_debug("chip->ramc.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
+				chip->ramc.addr, next, chip->ramc.addr + next);
+#endif		
+	}
+
+	/* XXX under some circumstances the DISR write flush may not happen */
+
+	return IRQ_HANDLED;
+}
+
+static void 
+snd_ad1889_pcm_free(snd_pcm_t *pcm)
+{
+	struct snd_ad1889 *chip = pcm->private_data;
+	chip->pcm = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int __devinit
+snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, snd_pcm_t **rpcm)
+{
+	int err;
+	snd_pcm_t *pcm;
+
+	if (rpcm)
+		*rpcm = NULL;
+
+	err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 
+			&snd_ad1889_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+			&snd_ad1889_capture_ops);
+
+	pcm->private_data = chip;
+	pcm->private_free = snd_ad1889_pcm_free;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, chip->card->shortname);
+	
+	chip->pcm = pcm;
+	chip->psubs = NULL;
+	chip->csubs = NULL;
+
+	chip->dma.dev = &chip->pci->dev;
+	chip->dma.type = SNDRV_DMA_TYPE_DEV;
+
+	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+						snd_dma_pci_data(chip->pci),
+						DMA_SIZE, DMA_SIZE);
+
+	if (err < 0) {
+		snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);
+		return err;
+	}
+	
+	if (rpcm)
+		*rpcm = pcm;
+	
+	return 0;
+}
+
+static void
+snd_ad1889_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+	struct snd_ad1889 *chip = entry->private_data;
+	u16 reg;
+	int tmp;
+
+	reg = ad1889_readw(chip, AD_DS_WSMC);
+	snd_iprintf(buffer, "Wave output: %s\n",
+			(reg & AD_DS_WSMC_WAEN) ? "enabled" : "disabled");
+	snd_iprintf(buffer, "Wave Channels: %s\n",
+			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");
+	snd_iprintf(buffer, "Wave Quality: %d-bit linear\n",
+			(reg & AD_DS_WSMC_WA16) ? 16 : 8);
+	
+	/* WARQ is at offset 12 */
+	tmp = (reg & AD_DS_WSMC_WARQ) ?
+			(((reg & AD_DS_WSMC_WARQ >> 12) & 0x01) ? 12 : 18) : 4;
+	tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;
+	
+	snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp,
+			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");
+				
+	
+	snd_iprintf(buffer, "Synthesis output: %s\n",
+			reg & AD_DS_WSMC_SYEN ? "enabled" : "disabled");
+	
+	/* SYRQ is at offset 4 */
+	tmp = (reg & AD_DS_WSMC_SYRQ) ?
+			(((reg & AD_DS_WSMC_SYRQ >> 4) & 0x01) ? 12 : 18) : 4;
+	tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1;
+	
+	snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp,
+			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");
+
+	reg = ad1889_readw(chip, AD_DS_RAMC);
+	snd_iprintf(buffer, "ADC input: %s\n",
+			(reg & AD_DS_RAMC_ADEN) ? "enabled" : "disabled");
+	snd_iprintf(buffer, "ADC Channels: %s\n",
+			(reg & AD_DS_RAMC_ADST) ? "stereo" : "mono");
+	snd_iprintf(buffer, "ADC Quality: %d-bit linear\n",
+			(reg & AD_DS_RAMC_AD16) ? 16 : 8);
+	
+	/* ACRQ is at offset 4 */
+	tmp = (reg & AD_DS_RAMC_ACRQ) ?
+			(((reg & AD_DS_RAMC_ACRQ >> 4) & 0x01) ? 12 : 18) : 4;
+	tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;
+	
+	snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp,
+			(reg & AD_DS_RAMC_ADST) ? "stereo" : "mono");
+	
+	snd_iprintf(buffer, "Resampler input: %s\n",
+			reg & AD_DS_RAMC_REEN ? "enabled" : "disabled");
+			
+	/* RERQ is at offset 12 */
+	tmp = (reg & AD_DS_RAMC_RERQ) ?
+			(((reg & AD_DS_RAMC_RERQ >> 12) & 0x01) ? 12 : 18) : 4;
+	tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1;
+	
+	snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp,
+			(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");
+				
+	
+	/* doc says LSB represents -1.5dB, but the max value (-94.5dB)
+	suggests that LSB is -3dB, which is more coherent with the logarithmic
+	nature of the dB scale */
+	reg = ad1889_readw(chip, AD_DS_WADA);
+	snd_iprintf(buffer, "Left: %s, -%d dB\n",
+			(reg & AD_DS_WADA_LWAM) ? "mute" : "unmute",
+			((reg & AD_DS_WADA_LWAA) >> 8) * 3);
+	reg = ad1889_readw(chip, AD_DS_WADA);
+	snd_iprintf(buffer, "Right: %s, -%d dB\n",
+			(reg & AD_DS_WADA_RWAM) ? "mute" : "unmute",
+			((reg & AD_DS_WADA_RWAA) >> 8) * 3);
+	
+	reg = ad1889_readw(chip, AD_DS_WAS);
+	snd_iprintf(buffer, "Wave samplerate: %u Hz\n", reg);
+	reg = ad1889_readw(chip, AD_DS_RES);
+	snd_iprintf(buffer, "Resampler samplerate: %u Hz\n", reg);
+}
+
+static void __devinit
+snd_ad1889_proc_init(struct snd_ad1889 *chip)
+{
+	snd_info_entry_t *entry;
+
+	if (!snd_card_proc_new(chip->card, chip->card->driver, &entry))
+		snd_info_set_text_ops(entry, chip, 1024, snd_ad1889_proc_read);
+}
+
+static struct ac97_quirk ac97_quirks[] = {
+	{
+		.subvendor = 0x11d4,	/* AD */
+		.subdevice = 0x1889,	/* AD1889 */
+		.codec_id = AC97_ID_AD1819,
+		.name = "AD1889",
+		.type = AC97_TUNE_HP_ONLY
+	},
+	{ } /* terminator */
+};
+
+static void __devinit
+snd_ad1889_ac97_xinit(struct snd_ad1889 *chip)
+{
+	u16 reg;
+
+	reg = ad1889_readw(chip, AD_AC97_ACIC);
+	reg |= AD_AC97_ACIC_ACRD;		/* Reset Disable */
+	ad1889_writew(chip, AD_AC97_ACIC, reg);
+	ad1889_readw(chip, AD_AC97_ACIC);	/* flush posted write */
+	udelay(10);
+	/* Interface Enable */
+	reg |= AD_AC97_ACIC_ACIE;
+	ad1889_writew(chip, AD_AC97_ACIC, reg);
+	
+	snd_ad1889_ac97_ready(chip);
+
+	/* Audio Stream Output | Variable Sample Rate Mode */
+	reg = ad1889_readw(chip, AD_AC97_ACIC);
+	reg |= AD_AC97_ACIC_ASOE | AD_AC97_ACIC_VSRM;
+	ad1889_writew(chip, AD_AC97_ACIC, reg);
+	ad1889_readw(chip, AD_AC97_ACIC); /* flush posted write */
+
+}
+
+static void
+snd_ad1889_ac97_bus_free(ac97_bus_t *bus)
+{
+	struct snd_ad1889 *chip = bus->private_data;
+	chip->ac97_bus = NULL;
+}
+
+static void
+snd_ad1889_ac97_free(ac97_t *ac97)
+{
+	struct snd_ad1889 *chip = ac97->private_data;
+	chip->ac97 = NULL;
+}
+
+static int __devinit
+snd_ad1889_ac97_init(struct snd_ad1889 *chip, const char *quirk_override)
+{
+	int err;
+	ac97_template_t ac97;
+	static ac97_bus_ops_t ops = {
+		.write = snd_ad1889_ac97_write,
+		.read = snd_ad1889_ac97_read,
+	};
+
+	/* doing that here, it works. */
+	snd_ad1889_ac97_xinit(chip);
+
+	err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus);
+	if (err < 0)
+		return err;
+	
+	chip->ac97_bus->private_free = snd_ad1889_ac97_bus_free;
+
+	memset(&ac97, 0, sizeof(ac97));
+	ac97.private_data = chip;
+	ac97.private_free = snd_ad1889_ac97_free;
+	ac97.pci = chip->pci;
+
+	err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97);
+	if (err < 0)
+		return err;
+		
+	snd_ac97_tune_hardware(chip->ac97, ac97_quirks, quirk_override);
+	
+	return 0;
+}
+
+static int
+snd_ad1889_free(struct snd_ad1889 *chip)
+{
+	if (chip->irq < 0)
+		goto skip_hw;
+
+	spin_lock_irq(&chip->lock);
+
+	ad1889_mute(chip);
+
+	/* Turn off interrupt on count and zero DMA registers */
+	ad1889_channel_reset(chip, AD_CHAN_WAV | AD_CHAN_ADC);
+
+	/* clear DISR. If we don't, we'd better jump off the Eiffel Tower */
+	ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PTAI | AD_DMA_DISR_PMAI);
+	ad1889_readl(chip, AD_DMA_DISR);	/* flush, dammit! */
+
+	spin_unlock_irq(&chip->lock);
+
+	synchronize_irq(chip->irq);
+	
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void*)chip);
+
+skip_hw:
+	if (chip->iobase)
+		iounmap(chip->iobase);
+
+	pci_release_regions(chip->pci);
+	pci_disable_device(chip->pci);
+
+	kfree(chip);
+	return 0;
+}
+
+static inline int
+snd_ad1889_dev_free(snd_device_t *device) 
+{
+	struct snd_ad1889 *chip = device->device_data;
+	return snd_ad1889_free(chip);
+}
+
+static int __devinit
+snd_ad1889_init(struct snd_ad1889 *chip) 
+{
+	ad1889_writew(chip, AD_DS_CCS, AD_DS_CCS_CLKEN); /* turn on clock */
+	ad1889_readw(chip, AD_DS_CCS);	/* flush posted write */
+
+	mdelay(10);
+
+	/* enable Master and Target abort interrupts */
+	ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PMAE | AD_DMA_DISR_PTAE);
+
+	return 0;
+}
+
+static int __devinit
+snd_ad1889_create(snd_card_t *card,
+		  struct pci_dev *pci,
+		  struct snd_ad1889 **rchip)
+{
+	int err;
+
+	struct snd_ad1889 *chip;
+	static snd_device_ops_t ops = {
+		.dev_free = snd_ad1889_dev_free,
+	};
+
+	*rchip = NULL;
+
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+	
+	/* check PCI availability (32bit DMA) */
+	if (pci_set_dma_mask(pci, 0xffffffff) < 0 ||
+	    pci_set_consistent_dma_mask(pci, 0xffffffff) < 0) {
+		printk(KERN_ERR PFX "error setting 32-bit DMA mask.\n");
+		pci_disable_device(pci);
+		return -ENXIO;
+	}
+
+	/* allocate chip specific data with zero-filled memory */
+	if ((chip = kcalloc(1, sizeof(*chip), GFP_KERNEL)) == NULL) {
+		pci_disable_device(pci);
+		return -ENOMEM;
+	}
+
+	chip->card = card;
+	card->private_data = chip;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	/* (1) PCI resource allocation */
+	if ((err = pci_request_regions(pci, card->driver)) < 0)
+		goto free_and_ret;
+
+	chip->bar = pci_resource_start(pci, 0);
+	chip->iobase = ioremap_nocache(chip->bar, pci_resource_len(pci, 0));
+	if (chip->iobase == NULL) {
+		printk(KERN_ERR PFX "unable to reserve region.\n");
+		err = -EBUSY;
+		goto free_and_ret;
+	}
+	
+	pci_set_master(pci);
+
+	spin_lock_init(&chip->lock);	/* only now can we call ad1889_free */
+
+	if (request_irq(pci->irq, snd_ad1889_interrupt,
+			SA_INTERRUPT|SA_SHIRQ, card->driver, (void*)chip)) {
+		printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq);
+		snd_ad1889_free(chip);
+		return -EBUSY;
+	}
+
+	chip->irq = pci->irq;
+	synchronize_irq(chip->irq);
+
+	/* (2) initialization of the chip hardware */
+	if ((err = snd_ad1889_init(chip)) < 0) {
+		snd_ad1889_free(chip);
+		return err;
+	}
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		snd_ad1889_free(chip);
+		return err;
+	}
+
+	snd_card_set_dev(card, &pci->dev);
+
+	*rchip = chip;
+
+	return 0;
+
+free_and_ret:
+	if (chip)
+		kfree(chip);
+	pci_disable_device(pci);
+
+	return err;
+}
+
+static int __devinit
+snd_ad1889_probe(struct pci_dev *pci,
+		 const struct pci_device_id *pci_id)
+{
+	int err;
+	static int devno;
+	snd_card_t *card;
+	struct snd_ad1889 *chip;
+
+	/* (1) */
+	if (devno >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[devno]) {
+		devno++;
+		return -ENOENT;
+	}
+
+	/* (2) */
+	card = snd_card_new(index[devno], id[devno], THIS_MODULE, 0);
+	/* XXX REVISIT: we can probably allocate chip in this call */
+	if (card == NULL)
+		return -ENOMEM;
+
+	strcpy(card->driver, "AD1889");
+	strcpy(card->shortname, "Analog Devices AD1889");
+
+	/* (3) */
+	err = snd_ad1889_create(card, pci, &chip);
+	if (err < 0)
+		goto free_and_ret;
+
+	/* (4) */
+	sprintf(card->longname, "%s at 0x%lx irq %i",
+		card->shortname, chip->bar, chip->irq);
+
+	/* (5) */
+	/* register AC97 mixer */
+	err = snd_ad1889_ac97_init(chip, ac97_quirk[devno]);
+	if (err < 0)
+		goto free_and_ret;
+	
+	err = snd_ad1889_pcm_init(chip, 0, NULL);
+	if (err < 0)
+		goto free_and_ret;
+
+	/* register proc interface */
+	snd_ad1889_proc_init(chip);
+
+	/* (6) */
+	err = snd_card_register(card);
+	if (err < 0)
+		goto free_and_ret;
+
+	/* (7) */
+	pci_set_drvdata(pci, card);
+
+	devno++;
+	return 0;
+
+free_and_ret:
+	snd_card_free(card);
+	return err;
+}
+
+static void __devexit
+snd_ad1889_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_device_id snd_ad1889_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) },
+	{ 0, },
+};
+MODULE_DEVICE_TABLE(pci, snd_ad1889_ids);
+
+static struct pci_driver ad1889_pci = {
+	.name = "AD1889 Audio",
+	.id_table = snd_ad1889_ids,
+	.probe = snd_ad1889_probe,
+	.remove = __devexit_p(snd_ad1889_remove),
+};
+
+static int __init
+alsa_ad1889_init(void)
+{
+	return pci_register_driver(&ad1889_pci);
+}
+
+static void __exit
+alsa_ad1889_fini(void)
+{
+	pci_unregister_driver(&ad1889_pci);
+}
+
+module_init(alsa_ad1889_init);
+module_exit(alsa_ad1889_fini);
diff -Nru linux-2.6.13-rc4.orig/sound/pci/ad1889.h linux-2.6.13-rc4/sound/pci/ad1889.h
--- linux-2.6.13-rc4.orig/sound/pci/ad1889.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.13-rc4/sound/pci/ad1889.h	2005-06-25 23:15:29.000000000 +0200
@@ -0,0 +1,187 @@
+/* Analog Devices 1889 audio driver
+ * Copyright (C) 2004, Kyle McMartin <kyle@parisc-linux.org>
+ */
+
+#ifndef __AD1889_H__
+#define __AD1889_H__
+
+#define AD_DS_WSMC	0x00 /* wave/synthesis channel mixer control */
+#define  AD_DS_WSMC_SYEN 0x0004 /* synthesis channel enable */
+#define  AD_DS_WSMC_SYRQ 0x0030 /* synth. fifo request point */
+#define  AD_DS_WSMC_WA16 0x0100 /* wave channel 16bit select */
+#define  AD_DS_WSMC_WAST 0x0200 /* wave channel stereo select */
+#define  AD_DS_WSMC_WAEN 0x0400 /* wave channel enable */
+#define  AD_DS_WSMC_WARQ 0x3000 /* wave fifo request point */
+
+#define AD_DS_RAMC	0x02 /* resampler/ADC channel mixer control */
+#define  AD_DS_RAMC_AD16 0x0001 /* ADC channel 16bit select */
+#define  AD_DS_RAMC_ADST 0x0002 /* ADC channel stereo select */
+#define  AD_DS_RAMC_ADEN 0x0004 /* ADC channel enable */
+#define  AD_DS_RAMC_ACRQ 0x0030 /* ADC fifo request point */
+#define  AD_DS_RAMC_REEN 0x0400 /* resampler channel enable */
+#define  AD_DS_RAMC_RERQ 0x3000 /* res. fifo request point */
+
+#define AD_DS_WADA	0x04 /* wave channel mix attenuation */
+#define  AD_DS_WADA_RWAM 0x0080 /* right wave mute */
+#define  AD_DS_WADA_RWAA 0x001f /* right wave attenuation */
+#define  AD_DS_WADA_LWAM 0x8000 /* left wave mute */
+#define  AD_DS_WADA_LWAA 0x3e00 /* left wave attenuation */
+
+#define AD_DS_SYDA	0x06 /* synthesis channel mix attenuation */
+#define  AD_DS_SYDA_RSYM 0x0080 /* right synthesis mute */
+#define  AD_DS_SYDA_RSYA 0x001f /* right synthesis attenuation */
+#define  AD_DS_SYDA_LSYM 0x8000 /* left synthesis mute */
+#define  AD_DS_SYDA_LSYA 0x3e00 /* left synthesis attenuation */
+
+#define AD_DS_WAS	0x08 /* wave channel sample rate */
+#define  AD_DS_WAS_WAS   0xffff /* sample rate mask */
+
+#define AD_DS_RES	0x0a /* resampler channel sample rate */
+#define  AD_DS_RES_RES   0xffff /* sample rate mask */
+
+#define AD_DS_CCS	0x0c /* chip control/status */
+#define  AD_DS_CCS_ADO   0x0001 /* ADC channel overflow */
+#define  AD_DS_CCS_REO   0x0002 /* resampler channel overflow */
+#define  AD_DS_CCS_SYU   0x0004 /* synthesis channel underflow */
+#define  AD_DS_CCS_WAU   0x0008 /* wave channel underflow */
+/* bits 4 -> 7, 9, 11 -> 14 reserved */
+#define  AD_DS_CCS_XTD   0x0100 /* xtd delay control (4096 clock cycles) */
+#define  AD_DS_CCS_PDALL 0x0400 /* power */
+#define  AD_DS_CCS_CLKEN 0x8000 /* clock */
+
+#define AD_DMA_RESBA	0x40 /* RES base address */
+#define AD_DMA_RESCA	0x44 /* RES current address */
+#define AD_DMA_RESBC	0x48 /* RES base count */
+#define AD_DMA_RESCC	0x4c /* RES current count */
+
+#define AD_DMA_ADCBA	0x50 /* ADC base address */
+#define AD_DMA_ADCCA	0x54 /* ADC current address */
+#define AD_DMA_ADCBC	0x58 /* ADC base count */
+#define AD_DMA_ADCCC	0x5c /* ADC current count */
+
+#define AD_DMA_SYNBA	0x60 /* synth base address */
+#define AD_DMA_SYNCA	0x64 /* synth current address */
+#define AD_DMA_SYNBC	0x68 /* synth base count */
+#define AD_DMA_SYNCC	0x6c /* synth current count */
+
+#define AD_DMA_WAVBA	0x70 /* wave base address */
+#define AD_DMA_WAVCA	0x74 /* wave current address */
+#define AD_DMA_WAVBC	0x78 /* wave base count */
+#define AD_DMA_WAVCC	0x7c /* wave current count */
+
+#define AD_DMA_RESIC	0x80 /* RES dma interrupt current byte count */
+#define AD_DMA_RESIB	0x84 /* RES dma interrupt base byte count */
+
+#define AD_DMA_ADCIC	0x88 /* ADC dma interrupt current byte count */
+#define AD_DMA_ADCIB	0x8c /* ADC dma interrupt base byte count */
+
+#define AD_DMA_SYNIC	0x90 /* synth dma interrupt current byte count */
+#define AD_DMA_SYNIB	0x94 /* synth dma interrupt base byte count */
+
+#define AD_DMA_WAVIC	0x98 /* wave dma interrupt current byte count */
+#define AD_DMA_WAVIB	0x9c /* wave dma interrupt base byte count */
+
+#define  AD_DMA_ICC	0xffffff /* current byte count mask */
+#define  AD_DMA_IBC	0xffffff /* base byte count mask */
+/* bits 24 -> 31 reserved */
+
+/* 4 bytes pad */
+#define AD_DMA_ADC	0xa8	/* ADC      dma control and status */
+#define AD_DMA_SYNTH	0xb0	/* Synth    dma control and status */
+#define AD_DMA_WAV	0xb8	/* wave     dma control and status */
+#define AD_DMA_RES	0xa0	/* Resample dma control and status */
+
+#define  AD_DMA_SGDE	0x0001 /* SGD mode enable */
+#define  AD_DMA_LOOP	0x0002 /* loop enable */
+#define  AD_DMA_IM	0x000c /* interrupt mode mask */
+#define  AD_DMA_IM_DIS	(~AD_DMA_IM)	/* disable */
+#define  AD_DMA_IM_CNT	0x0004 /* interrupt on count */
+#define  AD_DMA_IM_SGD	0x0008 /* interrupt on SGD flag */
+#define  AD_DMA_IM_EOL	0x000c /* interrupt on End of Linked List */
+#define  AD_DMA_SGDS	0x0030 /* SGD status */
+#define  AD_DMA_SFLG	0x0040 /* SGD flag */
+#define  AD_DMA_EOL	0x0080 /* SGD end of list */
+/* bits 8 -> 15 reserved */
+
+#define AD_DMA_DISR	0xc0 /* dma interrupt status */
+#define  AD_DMA_DISR_RESI 0x000001 /* resampler channel interrupt */
+#define  AD_DMA_DISR_ADCI 0x000002 /* ADC channel interrupt */
+#define  AD_DMA_DISR_SYNI 0x000004 /* synthesis channel interrupt */
+#define  AD_DMA_DISR_WAVI 0x000008 /* wave channel interrupt */
+/* bits 4, 5 reserved */
+#define  AD_DMA_DISR_SEPS 0x000040 /* serial eeprom status */
+/* bits 7 -> 13 reserved */
+#define  AD_DMA_DISR_PMAI 0x004000 /* pci master abort interrupt */
+#define  AD_DMA_DISR_PTAI 0x008000 /* pci target abort interrupt */
+#define  AD_DMA_DISR_PTAE 0x010000 /* pci target abort interrupt enable */
+#define  AD_DMA_DISR_PMAE 0x020000 /* pci master abort interrupt enable */
+/* bits 19 -> 31 reserved */
+
+/* interrupt mask */
+#define  AD_INTR_MASK     (AD_DMA_DISR_RESI|AD_DMA_DISR_ADCI| \
+                           AD_DMA_DISR_WAVI|AD_DMA_DISR_SYNI| \
+                           AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI)
+
+#define AD_DMA_CHSS	0xc4 /* dma channel stop status */
+#define  AD_DMA_CHSS_RESS 0x000001 /* resampler channel stopped */
+#define  AD_DMA_CHSS_ADCS 0x000002 /* ADC channel stopped */
+#define  AD_DMA_CHSS_SYNS 0x000004 /* synthesis channel stopped */
+#define  AD_DMA_CHSS_WAVS 0x000008 /* wave channel stopped */
+
+#define AD_GPIO_IPC	0xc8	/* gpio port control */
+#define AD_GPIO_OP	0xca	/* gpio output port status */
+#define AD_GPIO_IP	0xcc	/* gpio  input port status */
+
+#define AD_AC97_BASE	0x100	/* ac97 base register */
+
+#define AD_AC97_RESET   0x100   /* reset */
+
+#define AD_AC97_PWR_CTL	0x126	/* == AC97_POWERDOWN */
+#define  AD_AC97_PWR_ADC 0x0001 /* ADC ready status */
+#define  AD_AC97_PWR_DAC 0x0002 /* DAC ready status */
+#define  AD_AC97_PWR_PR0 0x0100 /* PR0 (ADC) powerdown */
+#define  AD_AC97_PWR_PR1 0x0200 /* PR1 (DAC) powerdown */
+
+#define AD_MISC_CTL     0x176 /* misc control */
+#define  AD_MISC_CTL_DACZ   0x8000 /* set for zero fill, unset for repeat */
+#define  AD_MISC_CTL_ARSR   0x0001 /* set for SR1, unset for SR0 */
+#define  AD_MISC_CTL_ALSR   0x0100
+#define  AD_MISC_CTL_DLSR   0x0400
+#define  AD_MISC_CTL_DRSR   0x0004
+
+#define AD_AC97_SR0     0x178 /* sample rate 0, 0xbb80 == 48K */
+#define  AD_AC97_SR0_48K 0xbb80 /* 48KHz */
+#define AD_AC97_SR1     0x17a /* sample rate 1 */
+
+#define AD_AC97_ACIC	0x180 /* ac97 codec interface control */
+#define  AD_AC97_ACIC_ACIE  0x0001 /* analog codec interface enable */
+#define  AD_AC97_ACIC_ACRD  0x0002 /* analog codec reset disable */
+#define  AD_AC97_ACIC_ASOE  0x0004 /* audio stream output enable */
+#define  AD_AC97_ACIC_VSRM  0x0008 /* variable sample rate mode */
+#define  AD_AC97_ACIC_FSDH  0x0100 /* force SDATA_OUT high */
+#define  AD_AC97_ACIC_FSYH  0x0200 /* force sync high */
+#define  AD_AC97_ACIC_ACRDY 0x8000 /* analog codec ready status */
+/* bits 10 -> 14 reserved */
+
+
+#define AD_DS_MEMSIZE	512
+#define AD_OPL_MEMSIZE	16
+#define AD_MIDI_MEMSIZE	16
+
+#define AD_WAV_STATE	0
+#define AD_ADC_STATE	1
+#define AD_MAX_STATES	2
+
+/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
+   But the IOMMU can only map at page size granularity."
+   This affects in particular .period_bytes_min */
+#define BUF_SIZE        PAGE_SIZE
+#define MAX_BUFS        32
+#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
+
+#define AD_CHAN_WAV	0x0001
+#define AD_CHAN_ADC	0x0002
+#define AD_CHAN_RES	0x0004
+#define AD_CHAN_SYN	0x0008
+
+#endif /* __AD1889_H__ */
diff -Nru linux-2.6.13-rc4.orig/sound/pci/Kconfig linux-2.6.13-rc4/sound/pci/Kconfig
--- linux-2.6.13-rc4.orig/sound/pci/Kconfig	2005-07-29 19:12:48.000000000 +0200
+++ linux-2.6.13-rc4/sound/pci/Kconfig	2005-07-29 19:37:04.000000000 +0200
@@ -21,6 +21,18 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-ali5451.
 
+config SND_AD1889
+	tristate "Analog Devices AD1889"
+	depends on SND
+	select SND_AC97_CODEC
+	help
+	  Say Y here to include support for the integrated AC97 sound
+	  device found in particular on the Hewlett-Packard [BCJ]-xxx0
+	  class PA-RISC workstations, using the AD1819 codec.
+
+	  To compile this as a module, choose M here: the module
+	  will be called snd-ad1889.
+
 config SND_ATIIXP
 	tristate "ATI IXP AC97 Controller"
 	depends on SND
diff -Nru linux-2.6.13-rc4.orig/sound/pci/Makefile linux-2.6.13-rc4/sound/pci/Makefile
--- linux-2.6.13-rc4.orig/sound/pci/Makefile	2005-06-17 21:48:29.000000000 +0200
+++ linux-2.6.13-rc4/sound/pci/Makefile	2005-04-02 01:02:22.000000000 +0200
@@ -4,6 +4,7 @@
 #
 
 snd-als4000-objs := als4000.o
+snd-ad1889-objs := ad1889.o
 snd-atiixp-objs := atiixp.o
 snd-atiixp-modem-objs := atiixp_modem.o
 snd-azt3328-objs := azt3328.o
@@ -26,6 +27,7 @@
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ALS4000) += snd-als4000.o
+obj-$(CONFIG_SND_AD1889) += snd-ad1889.o
 obj-$(CONFIG_SND_ATIIXP) += snd-atiixp.o
 obj-$(CONFIG_SND_ATIIXP_MODEM) += snd-atiixp-modem.o
 obj-$(CONFIG_SND_AZT3328) += snd-azt3328.o

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 169 bytes --]

_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-07-29 19:16 [PATCH] Support for AD1889 PCI Soundchip Thibaut VARENE
@ 2005-07-29 19:20 ` Thibaut VARENE
  2005-07-29 19:20 ` Thibaut VARENE
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 35+ messages in thread
From: Thibaut VARENE @ 2005-07-29 19:20 UTC (permalink / raw)
  To: perex; +Cc: alsa-devel, parisc-linux, kyle

[-- Attachment #1: Type: text/plain, Size: 556 bytes --]

On Fri, 29 Jul 2005 21:16:34 +0200
Thibaut VARENE <T-Bone@parisc-linux.org> wrote:

> Here's the diffstat summary:
> 
>  MAINTAINERS        |    9
>  sound/pci/Kconfig  |   12
>  sound/pci/Makefile |    2
>  sound/pci/ad1889.c | 1166
> +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  sound/pci/ad1889.h |  187 ++++++++
>  5 files changed, 1376 insertions(+)
> 

Sorry for replying to myself, forgot the:

Signed-off-by: Thibaut VARENE <varenet@parisc-linux.org>

HTH

Thibaut VARENE
The PA/Linux Team
http://www.pateam.org/

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-07-29 19:16 [PATCH] Support for AD1889 PCI Soundchip Thibaut VARENE
  2005-07-29 19:20 ` [parisc-linux] " Thibaut VARENE
@ 2005-07-29 19:20 ` Thibaut VARENE
  2005-08-03 13:46 ` Takashi Iwai
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 35+ messages in thread
From: Thibaut VARENE @ 2005-07-29 19:20 UTC (permalink / raw)
  To: perex; +Cc: alsa-devel, parisc-linux, kyle


[-- Attachment #1.1: Type: text/plain, Size: 556 bytes --]

On Fri, 29 Jul 2005 21:16:34 +0200
Thibaut VARENE <T-Bone@parisc-linux.org> wrote:

> Here's the diffstat summary:
> 
>  MAINTAINERS        |    9
>  sound/pci/Kconfig  |   12
>  sound/pci/Makefile |    2
>  sound/pci/ad1889.c | 1166
> +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  sound/pci/ad1889.h |  187 ++++++++
>  5 files changed, 1376 insertions(+)
> 

Sorry for replying to myself, forgot the:

Signed-off-by: Thibaut VARENE <varenet@parisc-linux.org>

HTH

Thibaut VARENE
The PA/Linux Team
http://www.pateam.org/

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 169 bytes --]

_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH] Support for AD1889 PCI Soundchip
  2005-07-29 19:16 [PATCH] Support for AD1889 PCI Soundchip Thibaut VARENE
  2005-07-29 19:20 ` [parisc-linux] " Thibaut VARENE
  2005-07-29 19:20 ` Thibaut VARENE
@ 2005-08-03 13:46 ` Takashi Iwai
  2005-08-04 13:30 ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
  2005-08-04 13:30 ` [parisc-linux] " Clemens Ladisch
  4 siblings, 0 replies; 35+ messages in thread
From: Takashi Iwai @ 2005-08-03 13:46 UTC (permalink / raw)
  To: Thibaut VARENE; +Cc: alsa-devel, kyle, parisc-linux

At Fri, 29 Jul 2005 21:16:34 +0200,
Thibaut VARENE wrote:
> 
> Hi,
> 
> Attached is a patch against 2.6.13-rc4 providing support for Analog
> Devices AD1889 PCI Sound chip, which is especially found on some HP
> PA-RISC machines.
> 
> The driver has been successfully tested on parisc and ppc architectures,
> and offers support for full duplex playback (variable rates, mono/stereo
> 8/16bit) and capture (fixed 48kHz, mono/stereo 8/16bit).
> 
> It's developed and maintained in the parisc-linux.org CVS kernel tree
> (http://cvs.parisc-linux.org/), and has a status webpage on
> http://wiki.parisc-linux.org/AD1889
> 
> This patch doesn't yet feature OPL3 code, because it's still work in
> progress in our development tree.

Thanks for the patch.

I put your code to alsa-driver for the time being.
Will be moved to alsa-kernel to push to linux-kernel tree later.


Takashi


-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-07-29 19:16 [PATCH] Support for AD1889 PCI Soundchip Thibaut VARENE
                   ` (3 preceding siblings ...)
  2005-08-04 13:30 ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
@ 2005-08-04 13:30 ` Clemens Ladisch
  2005-08-11 15:18   ` Clemens Ladisch
  2005-08-11 15:18   ` Clemens Ladisch
  4 siblings, 2 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-04 13:30 UTC (permalink / raw)
  To: Thibaut VARENE; +Cc: alsa-devel, kyle, parisc-linux

Thibaut VARENE wrote:
> Attached is a patch against 2.6.13-rc4 providing support for Analog
> Devices AD1889 PCI Sound chip, which is especially found on some HP
> PA-RISC machines.

I don't actually have this hardware :-), but the docs don't mention
any dependency between the count registers (BC, CC) and the interrupt
count registers (IC, IB).

So wouldn't it be possible to put the ALSA buffer size into the count
registers and the ALSA period size into the interrupt count registers?

This would make the interrupt handler much simpler, as it wouldn't
have to reprogram any registers.  And it would solve the problem that
the DMA accesses for one period go beyond the buffer when the number
of periods per buffer is not an integer.


Regards,
Clemens



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-07-29 19:16 [PATCH] Support for AD1889 PCI Soundchip Thibaut VARENE
                   ` (2 preceding siblings ...)
  2005-08-03 13:46 ` Takashi Iwai
@ 2005-08-04 13:30 ` Clemens Ladisch
  2005-08-04 13:30 ` [parisc-linux] " Clemens Ladisch
  4 siblings, 0 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-04 13:30 UTC (permalink / raw)
  To: Thibaut VARENE; +Cc: alsa-devel, parisc-linux, kyle

Thibaut VARENE wrote:
> Attached is a patch against 2.6.13-rc4 providing support for Analog
> Devices AD1889 PCI Sound chip, which is especially found on some HP
> PA-RISC machines.

I don't actually have this hardware :-), but the docs don't mention
any dependency between the count registers (BC, CC) and the interrupt
count registers (IC, IB).

So wouldn't it be possible to put the ALSA buffer size into the count
registers and the ALSA period size into the interrupt count registers?

This would make the interrupt handler much simpler, as it wouldn't
have to reprogram any registers.  And it would solve the problem that
the DMA accesses for one period go beyond the buffer when the number
of periods per buffer is not an integer.


Regards,
Clemens

_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-04 13:30 ` [parisc-linux] " Clemens Ladisch
@ 2005-08-11 15:18   ` Clemens Ladisch
  2005-08-12  2:14     ` [parisc-linux] [Alsa-devel] " Kyle McMartin
                       ` (3 more replies)
  2005-08-11 15:18   ` Clemens Ladisch
  1 sibling, 4 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-11 15:18 UTC (permalink / raw)
  To: Thibaut VARENE; +Cc: alsa-devel, kyle, parisc-linux

I wrote:
> Thibaut VARENE wrote:
> > Attached is a patch against 2.6.13-rc4 providing support for Analog
> > Devices AD1889 PCI Sound chip, which is especially found on some HP
> > PA-RISC machines.
>
> I don't actually have this hardware :-), but the docs don't mention
> any dependency between the count registers (BC, CC) and the interrupt
> count registers (IC, IB).
>
> So wouldn't it be possible to put the ALSA buffer size into the count
> registers and the ALSA period size into the interrupt count registers?
>
> This would make the interrupt handler much simpler, as it wouldn't
> have to reprogram any registers.  And it would solve the problem that
> the DMA accesses for one period go beyond the buffer when the number
> of periods per buffer is not an integer.

... something like this (please test):


Index: alsa/alsa-driver/pci/ad1889.h
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.h	2005-08-04 17:56:50.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.h	2005-08-11 11:54:38.000000000 +0200
@@ -172,13 +172,6 @@
 #define AD_ADC_STATE	1
 #define AD_MAX_STATES	2

-/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
-   But the IOMMU can only map at page size granularity."
-   This affects in particular .period_bytes_min */
-#define BUF_SIZE        PAGE_SIZE
-#define MAX_BUFS        32
-#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
-
 #define AD_CHAN_WAV	0x0001
 #define AD_CHAN_ADC	0x0002
 #define AD_CHAN_RES	0x0004
Index: alsa/alsa-driver/pci/ad1889.c
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.c	2005-08-11 10:46:42.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.c	2005-08-11 12:21:21.000000000 +0200
@@ -87,15 +87,11 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 work
 /* let's use the global sound debug interfaces */
 #define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)

-/* keep track of each hw register */
+/* keep track of some hw registers */
 struct ad1889_register_state {
 	u16 reg;	/* reg setup */
 	u32 addr;	/* dma base address */
-	u16 rate;	/* sample rate */
-	unsigned long pos;	/* last recorded DMA buffer position */
-	unsigned long buf;	/* period # */
 	unsigned long size;	/* DMA buffer size */
-	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
 };

 struct snd_ad1889 {
@@ -118,13 +114,6 @@ struct snd_ad1889 {
 	struct ad1889_register_state wave;
 	struct ad1889_register_state ramc;

-	struct {
-		unsigned long wav_intr;
-		unsigned long adc_intr;
-		unsigned long syn_intr;
-		unsigned long res_intr;
-	} stats;
-
 	spinlock_t lock;
 };

@@ -172,22 +161,46 @@ ad1889_mute(struct snd_ad1889 *chip)
 }

 static inline void
-ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_ADCBA, address);
+	ad1889_writel(chip, AD_DMA_ADCCA, address);
+}
+
+static inline void
+ad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_ADCBC, count);
 	ad1889_writel(chip, AD_DMA_ADCCC, count);
+}
+
+static inline void
+ad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_ADCIB, count);
 	ad1889_writel(chip, AD_DMA_ADCIC, count);
-}
+}
+
+static inline void
+ad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_WAVBA, address);
+	ad1889_writel(chip, AD_DMA_WAVCA, address);
+}

 static inline void
-ad1889_load_wave_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_wave_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_WAVBC, count);
 	ad1889_writel(chip, AD_DMA_WAVCC, count);
+}
+
+static inline void
+ad1889_load_wave_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_WAVIB, count);
 	ad1889_writel(chip, AD_DMA_WAVIC, count);
-}
+}

 static void
 ad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel)
@@ -207,9 +220,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		ad1889_writew(chip, AD_DMA_WAV, reg);

 		/* clear IRQ and address counters and pointers */
-		ad1889_load_wave_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVBA, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVCA, 0x0);
+		ad1889_load_wave_buffer_address(chip, 0x0);
+		ad1889_load_wave_buffer_count(chip, 0x0);
+		ad1889_load_wave_interrupt_count(chip, 0x0);

 		/* flush */
 		ad1889_readw(chip, AD_DMA_WAV);
@@ -226,9 +239,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		reg &= ~AD_DMA_LOOP;
 		ad1889_writew(chip, AD_DMA_ADC, reg);

-		ad1889_load_adc_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCBA, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCCA, 0x0);
+		ad1889_load_adc_buffer_address(chip, 0x0);
+		ad1889_load_adc_buffer_count(chip, 0x0);
+		ad1889_load_adc_interrupt_count(chip, 0x0);

 		/* flush */
 		ad1889_readw(chip, AD_DMA_ADC);
@@ -290,11 +303,11 @@ static snd_pcm_hardware_t snd_ad1889_pla
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = 256 * 1024,
+	.period_bytes_min = 32,
+	.period_bytes_max = 128 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
 	/*.fifo_size = 0,*/
 };

@@ -307,11 +320,11 @@ static snd_pcm_hardware_t snd_ad1889_cap
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = 256 * 1024,
+	.period_bytes_min = 32,
+	.period_bytes_max = 128 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
 	/*.fifo_size = 0,*/
 };

@@ -381,24 +394,18 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	spin_lock_irq(&chip->lock);

 	chip->wave.size = size;
-	chip->wave.count = count;
 	chip->wave.reg = reg;
-	chip->wave.buf = 0;
-	chip->wave.pos = 0;
-	chip->wave.rate = rt->rate;
 	chip->wave.addr = rt->dma_addr;

 	ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg);

 	/* Set sample rates on the codec */
-	ad1889_writew(chip, AD_DS_WAS, chip->wave.rate);
+	ad1889_writew(chip, AD_DS_WAS, rt->rate);

-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_WAVCA, chip->wave.addr);
-	ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + (count % size));
-	ad1889_load_wave_count(chip, chip->wave.count);
+	/* Set up DMA */
+	ad1889_load_wave_buffer_address(chip, chip->wave.addr);
+	ad1889_load_wave_buffer_count(chip, size);
+	ad1889_load_wave_interrupt_count(chip, count);

 	/* writes flush */
 	ad1889_readw(chip, AD_DS_WSMC);
@@ -407,7 +414,7 @@ snd_ad1889_playback_prepare(snd_pcm_subs

 	ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
-			count, size, reg, chip->wave.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }

@@ -437,21 +444,15 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	spin_lock_irq(&chip->lock);

 	chip->ramc.size = size;
-	chip->ramc.count = count;
 	chip->ramc.reg = reg;
-	chip->ramc.buf = 0;
-	chip->ramc.pos = 0;
-	chip->ramc.rate = rt->rate;
 	chip->ramc.addr = rt->dma_addr;

 	ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg);

-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_ADCCA, chip->ramc.addr);
-	ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + (count % size));
-	ad1889_load_adc_count(chip, chip->ramc.count);
+	/* Set up DMA */
+	ad1889_load_adc_buffer_address(chip, chip->ramc.addr);
+	ad1889_load_adc_buffer_count(chip, size);
+	ad1889_load_adc_interrupt_count(chip, count);

 	/* writes flush */
 	ad1889_readw(chip, AD_DS_RAMC);
@@ -460,7 +461,7 @@ snd_ad1889_capture_prepare(snd_pcm_subst

 	ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
-			count, size, reg, chip->ramc.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }

@@ -607,7 +608,6 @@ snd_ad1889_interrupt(int irq,
 		     struct pt_regs *regs)
 {
 	unsigned long st;
-	unsigned long next;
 	struct snd_ad1889 *chip = dev_id;

 	st = ad1889_readl(chip, AD_DMA_DISR);
@@ -623,82 +623,12 @@ snd_ad1889_interrupt(int irq,
 	if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
 		ad1889_debug("Unexpected master or target abort interrupt!\n");

-	if (chip->pcm && (st & AD_DMA_DISR_WAVI) && chip->psubs) {
-		spin_lock(&chip->lock);
-
-		chip->stats.wav_intr++;
-
-		chip->wave.buf++;
-
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->wave.pos += chip->wave.count;
-		chip->wave.pos %= chip->wave.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->wave.pos + chip->wave.count;
-		next %= chip->wave.size;
-
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + next);
-
-		ad1889_readl(chip, AD_DMA_WAVBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-
+	if ((st & AD_DMA_DISR_WAVI) && chip->psubs)
 		snd_pcm_period_elapsed(chip->psubs);
-#if 0
-		ad1889_debug("chip->wave.pos = %d, chip->wave.count = %d, "
-				"chip->wave.size = %d\n", chip->wave.pos,
-				chip->wave.count, chip->wave.size);
-		ad1889_debug("chip->wave.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->wave.addr, next, chip->wave.addr + next);
-#endif
-	}
-
-	if (chip->pcm && (st & AD_DMA_DISR_ADCI) && chip->csubs) {
-		spin_lock(&chip->lock);
-
-		chip->stats.adc_intr++;
-
-		chip->ramc.buf++;
-
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->ramc.pos += chip->ramc.count;
-		chip->ramc.pos %= chip->ramc.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->ramc.pos + chip->ramc.count;
-		next %= chip->ramc.size;
-
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + next);
-
-		ad1889_readl(chip, AD_DMA_ADCBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-
+	if ((st & AD_DMA_DISR_ADCI) && chip->csubs)
 		snd_pcm_period_elapsed(chip->csubs);
-#if 0
-		ad1889_debug("chip->ramc.pos = %d, chip->ramc.count = %d, "
-				"chip->ramc.size = %d\n", chip->ramc.pos,
-				chip->ramc.count, chip->ramc.size);
-		ad1889_debug("chip->ramc.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->ramc.addr, next, chip->ramc.addr + next);
-#endif
-	}

+	ad1889_readl(chip, AD_DMA_DISR); /* flush */
 	/* XXX under some circumstances the DISR write flush may not happen */

 	return IRQ_HANDLED;
@@ -741,7 +671,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *c

 	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 						snd_dma_pci_data(chip->pci),
-						DMA_SIZE, DMA_SIZE);
+						128 * 1024, 256 * 1024);

 	if (err < 0) {
 		snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-04 13:30 ` [parisc-linux] " Clemens Ladisch
  2005-08-11 15:18   ` Clemens Ladisch
@ 2005-08-11 15:18   ` Clemens Ladisch
  1 sibling, 0 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-11 15:18 UTC (permalink / raw)
  To: Thibaut VARENE; +Cc: alsa-devel, parisc-linux, kyle

I wrote:
> Thibaut VARENE wrote:
> > Attached is a patch against 2.6.13-rc4 providing support for Analog
> > Devices AD1889 PCI Sound chip, which is especially found on some HP
> > PA-RISC machines.
>
> I don't actually have this hardware :-), but the docs don't mention
> any dependency between the count registers (BC, CC) and the interrupt
> count registers (IC, IB).
>
> So wouldn't it be possible to put the ALSA buffer size into the count
> registers and the ALSA period size into the interrupt count registers?
>
> This would make the interrupt handler much simpler, as it wouldn't
> have to reprogram any registers.  And it would solve the problem that
> the DMA accesses for one period go beyond the buffer when the number
> of periods per buffer is not an integer.

... something like this (please test):


Index: alsa/alsa-driver/pci/ad1889.h
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.h	2005-08-04 17:56:50.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.h	2005-08-11 11:54:38.000000000 +0200
@@ -172,13 +172,6 @@
 #define AD_ADC_STATE	1
 #define AD_MAX_STATES	2

-/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
-   But the IOMMU can only map at page size granularity."
-   This affects in particular .period_bytes_min */
-#define BUF_SIZE        PAGE_SIZE
-#define MAX_BUFS        32
-#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
-
 #define AD_CHAN_WAV	0x0001
 #define AD_CHAN_ADC	0x0002
 #define AD_CHAN_RES	0x0004
Index: alsa/alsa-driver/pci/ad1889.c
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.c	2005-08-11 10:46:42.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.c	2005-08-11 12:21:21.000000000 +0200
@@ -87,15 +87,11 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 work
 /* let's use the global sound debug interfaces */
 #define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)

-/* keep track of each hw register */
+/* keep track of some hw registers */
 struct ad1889_register_state {
 	u16 reg;	/* reg setup */
 	u32 addr;	/* dma base address */
-	u16 rate;	/* sample rate */
-	unsigned long pos;	/* last recorded DMA buffer position */
-	unsigned long buf;	/* period # */
 	unsigned long size;	/* DMA buffer size */
-	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
 };

 struct snd_ad1889 {
@@ -118,13 +114,6 @@ struct snd_ad1889 {
 	struct ad1889_register_state wave;
 	struct ad1889_register_state ramc;

-	struct {
-		unsigned long wav_intr;
-		unsigned long adc_intr;
-		unsigned long syn_intr;
-		unsigned long res_intr;
-	} stats;
-
 	spinlock_t lock;
 };

@@ -172,22 +161,46 @@ ad1889_mute(struct snd_ad1889 *chip)
 }

 static inline void
-ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_ADCBA, address);
+	ad1889_writel(chip, AD_DMA_ADCCA, address);
+}
+
+static inline void
+ad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_ADCBC, count);
 	ad1889_writel(chip, AD_DMA_ADCCC, count);
+}
+
+static inline void
+ad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_ADCIB, count);
 	ad1889_writel(chip, AD_DMA_ADCIC, count);
-}
+}
+
+static inline void
+ad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_WAVBA, address);
+	ad1889_writel(chip, AD_DMA_WAVCA, address);
+}

 static inline void
-ad1889_load_wave_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_wave_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_WAVBC, count);
 	ad1889_writel(chip, AD_DMA_WAVCC, count);
+}
+
+static inline void
+ad1889_load_wave_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_WAVIB, count);
 	ad1889_writel(chip, AD_DMA_WAVIC, count);
-}
+}

 static void
 ad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel)
@@ -207,9 +220,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		ad1889_writew(chip, AD_DMA_WAV, reg);

 		/* clear IRQ and address counters and pointers */
-		ad1889_load_wave_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVBA, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVCA, 0x0);
+		ad1889_load_wave_buffer_address(chip, 0x0);
+		ad1889_load_wave_buffer_count(chip, 0x0);
+		ad1889_load_wave_interrupt_count(chip, 0x0);

 		/* flush */
 		ad1889_readw(chip, AD_DMA_WAV);
@@ -226,9 +239,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		reg &= ~AD_DMA_LOOP;
 		ad1889_writew(chip, AD_DMA_ADC, reg);

-		ad1889_load_adc_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCBA, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCCA, 0x0);
+		ad1889_load_adc_buffer_address(chip, 0x0);
+		ad1889_load_adc_buffer_count(chip, 0x0);
+		ad1889_load_adc_interrupt_count(chip, 0x0);

 		/* flush */
 		ad1889_readw(chip, AD_DMA_ADC);
@@ -290,11 +303,11 @@ static snd_pcm_hardware_t snd_ad1889_pla
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = 256 * 1024,
+	.period_bytes_min = 32,
+	.period_bytes_max = 128 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
 	/*.fifo_size = 0,*/
 };

@@ -307,11 +320,11 @@ static snd_pcm_hardware_t snd_ad1889_cap
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = 256 * 1024,
+	.period_bytes_min = 32,
+	.period_bytes_max = 128 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
 	/*.fifo_size = 0,*/
 };

@@ -381,24 +394,18 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	spin_lock_irq(&chip->lock);

 	chip->wave.size = size;
-	chip->wave.count = count;
 	chip->wave.reg = reg;
-	chip->wave.buf = 0;
-	chip->wave.pos = 0;
-	chip->wave.rate = rt->rate;
 	chip->wave.addr = rt->dma_addr;

 	ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg);

 	/* Set sample rates on the codec */
-	ad1889_writew(chip, AD_DS_WAS, chip->wave.rate);
+	ad1889_writew(chip, AD_DS_WAS, rt->rate);

-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_WAVCA, chip->wave.addr);
-	ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + (count % size));
-	ad1889_load_wave_count(chip, chip->wave.count);
+	/* Set up DMA */
+	ad1889_load_wave_buffer_address(chip, chip->wave.addr);
+	ad1889_load_wave_buffer_count(chip, size);
+	ad1889_load_wave_interrupt_count(chip, count);

 	/* writes flush */
 	ad1889_readw(chip, AD_DS_WSMC);
@@ -407,7 +414,7 @@ snd_ad1889_playback_prepare(snd_pcm_subs

 	ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
-			count, size, reg, chip->wave.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }

@@ -437,21 +444,15 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	spin_lock_irq(&chip->lock);

 	chip->ramc.size = size;
-	chip->ramc.count = count;
 	chip->ramc.reg = reg;
-	chip->ramc.buf = 0;
-	chip->ramc.pos = 0;
-	chip->ramc.rate = rt->rate;
 	chip->ramc.addr = rt->dma_addr;

 	ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg);

-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_ADCCA, chip->ramc.addr);
-	ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + (count % size));
-	ad1889_load_adc_count(chip, chip->ramc.count);
+	/* Set up DMA */
+	ad1889_load_adc_buffer_address(chip, chip->ramc.addr);
+	ad1889_load_adc_buffer_count(chip, size);
+	ad1889_load_adc_interrupt_count(chip, count);

 	/* writes flush */
 	ad1889_readw(chip, AD_DS_RAMC);
@@ -460,7 +461,7 @@ snd_ad1889_capture_prepare(snd_pcm_subst

 	ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
-			count, size, reg, chip->ramc.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }

@@ -607,7 +608,6 @@ snd_ad1889_interrupt(int irq,
 		     struct pt_regs *regs)
 {
 	unsigned long st;
-	unsigned long next;
 	struct snd_ad1889 *chip = dev_id;

 	st = ad1889_readl(chip, AD_DMA_DISR);
@@ -623,82 +623,12 @@ snd_ad1889_interrupt(int irq,
 	if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
 		ad1889_debug("Unexpected master or target abort interrupt!\n");

-	if (chip->pcm && (st & AD_DMA_DISR_WAVI) && chip->psubs) {
-		spin_lock(&chip->lock);
-
-		chip->stats.wav_intr++;
-
-		chip->wave.buf++;
-
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->wave.pos += chip->wave.count;
-		chip->wave.pos %= chip->wave.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->wave.pos + chip->wave.count;
-		next %= chip->wave.size;
-
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + next);
-
-		ad1889_readl(chip, AD_DMA_WAVBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-
+	if ((st & AD_DMA_DISR_WAVI) && chip->psubs)
 		snd_pcm_period_elapsed(chip->psubs);
-#if 0
-		ad1889_debug("chip->wave.pos = %d, chip->wave.count = %d, "
-				"chip->wave.size = %d\n", chip->wave.pos,
-				chip->wave.count, chip->wave.size);
-		ad1889_debug("chip->wave.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->wave.addr, next, chip->wave.addr + next);
-#endif
-	}
-
-	if (chip->pcm && (st & AD_DMA_DISR_ADCI) && chip->csubs) {
-		spin_lock(&chip->lock);
-
-		chip->stats.adc_intr++;
-
-		chip->ramc.buf++;
-
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->ramc.pos += chip->ramc.count;
-		chip->ramc.pos %= chip->ramc.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->ramc.pos + chip->ramc.count;
-		next %= chip->ramc.size;
-
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + next);
-
-		ad1889_readl(chip, AD_DMA_ADCBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-
+	if ((st & AD_DMA_DISR_ADCI) && chip->csubs)
 		snd_pcm_period_elapsed(chip->csubs);
-#if 0
-		ad1889_debug("chip->ramc.pos = %d, chip->ramc.count = %d, "
-				"chip->ramc.size = %d\n", chip->ramc.pos,
-				chip->ramc.count, chip->ramc.size);
-		ad1889_debug("chip->ramc.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->ramc.addr, next, chip->ramc.addr + next);
-#endif
-	}

+	ad1889_readl(chip, AD_DMA_DISR); /* flush */
 	/* XXX under some circumstances the DISR write flush may not happen */

 	return IRQ_HANDLED;
@@ -741,7 +671,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *c

 	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 						snd_dma_pci_data(chip->pci),
-						DMA_SIZE, DMA_SIZE);
+						128 * 1024, 256 * 1024);

 	if (err < 0) {
 		snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);

_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-11 15:18   ` Clemens Ladisch
  2005-08-12  2:14     ` [parisc-linux] [Alsa-devel] " Kyle McMartin
@ 2005-08-12  2:14     ` Kyle McMartin
  2005-08-12  7:17       ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
  2005-08-12  7:17       ` [parisc-linux] " Clemens Ladisch
  2005-08-17  9:10     ` Thibaut VARENE
  2005-08-17  9:10     ` Thibaut VARENE
  3 siblings, 2 replies; 35+ messages in thread
From: Kyle McMartin @ 2005-08-12  2:14 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: Thibaut VARENE, alsa-devel, kyle, parisc-linux

On Thu, Aug 11, 2005 at 05:18:31PM +0200, Clemens Ladisch wrote:
> > This would make the interrupt handler much simpler, as it wouldn't
> > have to reprogram any registers.  And it would solve the problem that
> > the DMA accesses for one period go beyond the buffer when the number
> > of periods per buffer is not an integer.
> 
> ... something like this (please test):
> 

This doesn't apply against PA-RISC Linux CVS head (should have
no changes since submission) nor against ALSA CVS head... care to try
again? I don't have time to clean up the patch right now, it would
have to wait a week or so.

Cheers,
-- 
Kyle McMartin


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-11 15:18   ` Clemens Ladisch
@ 2005-08-12  2:14     ` Kyle McMartin
  2005-08-12  2:14     ` [parisc-linux] " Kyle McMartin
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 35+ messages in thread
From: Kyle McMartin @ 2005-08-12  2:14 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: kyle, alsa-devel, parisc-linux, Thibaut VARENE

On Thu, Aug 11, 2005 at 05:18:31PM +0200, Clemens Ladisch wrote:
> > This would make the interrupt handler much simpler, as it wouldn't
> > have to reprogram any registers.  And it would solve the problem that
> > the DMA accesses for one period go beyond the buffer when the number
> > of periods per buffer is not an integer.
> 
> ... something like this (please test):
> 

This doesn't apply against PA-RISC Linux CVS head (should have
no changes since submission) nor against ALSA CVS head... care to try
again? I don't have time to clean up the patch right now, it would
have to wait a week or so.

Cheers,
-- 
Kyle McMartin
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-12  2:14     ` [parisc-linux] " Kyle McMartin
  2005-08-12  7:17       ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
@ 2005-08-12  7:17       ` Clemens Ladisch
  2005-08-17  1:51         ` [parisc-linux] [Alsa-devel] " Kyle McMartin
  2005-08-17  1:51         ` [parisc-linux] " Kyle McMartin
  1 sibling, 2 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-12  7:17 UTC (permalink / raw)
  To: Kyle McMartin; +Cc: Thibaut VARENE, alsa-devel, parisc-linux

[-- Attachment #1: Type: TEXT/PLAIN, Size: 381 bytes --]

Kyle McMartin wrote:
> On Thu, Aug 11, 2005 at 05:18:31PM +0200, Clemens Ladisch wrote:
> > ... something like this (please test):
>
> This doesn't apply against PA-RISC Linux CVS head (should have
> no changes since submission) nor against ALSA CVS head...

It should apply against both, but it seems somewhere some whitespaces
got lost ...

Here you go again.


Regards,
Clemens

[-- Attachment #2: Type: TEXT/PLAIN, Size: 11785 bytes --]

Index: alsa/alsa-driver/pci/ad1889.h
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.h	2005-08-04 17:56:50.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.h	2005-08-11 11:54:38.000000000 +0200
@@ -172,13 +172,6 @@
 #define AD_ADC_STATE	1
 #define AD_MAX_STATES	2
 
-/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
-   But the IOMMU can only map at page size granularity."
-   This affects in particular .period_bytes_min */
-#define BUF_SIZE        PAGE_SIZE
-#define MAX_BUFS        32
-#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
-
 #define AD_CHAN_WAV	0x0001
 #define AD_CHAN_ADC	0x0002
 #define AD_CHAN_RES	0x0004
Index: alsa/alsa-driver/pci/ad1889.c
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.c	2005-08-11 10:46:42.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.c	2005-08-11 12:21:21.000000000 +0200
@@ -87,15 +87,11 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 work
 /* let's use the global sound debug interfaces */
 #define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)
 
-/* keep track of each hw register */
+/* keep track of some hw registers */
 struct ad1889_register_state {
 	u16 reg;	/* reg setup */
 	u32 addr;	/* dma base address */
-	u16 rate;	/* sample rate */
-	unsigned long pos;	/* last recorded DMA buffer position */
-	unsigned long buf;	/* period # */
 	unsigned long size;	/* DMA buffer size */
-	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
 };
 
 struct snd_ad1889 {
@@ -118,13 +114,6 @@ struct snd_ad1889 {
 	struct ad1889_register_state wave;
 	struct ad1889_register_state ramc;
 
-	struct {
-		unsigned long wav_intr;
-		unsigned long adc_intr;
-		unsigned long syn_intr;
-		unsigned long res_intr;
-	} stats;
-
 	spinlock_t lock;
 };
 
@@ -172,22 +161,46 @@ ad1889_mute(struct snd_ad1889 *chip)
 }
 
 static inline void
-ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_ADCBA, address);
+	ad1889_writel(chip, AD_DMA_ADCCA, address);
+}
+
+static inline void
+ad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_ADCBC, count);
 	ad1889_writel(chip, AD_DMA_ADCCC, count);
+}
+
+static inline void
+ad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_ADCIB, count);
 	ad1889_writel(chip, AD_DMA_ADCIC, count);
-}	
+}
+
+static inline void
+ad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_WAVBA, address);
+	ad1889_writel(chip, AD_DMA_WAVCA, address);
+}
 
 static inline void
-ad1889_load_wave_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_wave_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_WAVBC, count);
 	ad1889_writel(chip, AD_DMA_WAVCC, count);
+}
+
+static inline void
+ad1889_load_wave_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_WAVIB, count);
 	ad1889_writel(chip, AD_DMA_WAVIC, count);
-}	
+}
 
 static void
 ad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel)
@@ -207,9 +220,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		ad1889_writew(chip, AD_DMA_WAV, reg);
 
 		/* clear IRQ and address counters and pointers */
-		ad1889_load_wave_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVBA, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVCA, 0x0);
+		ad1889_load_wave_buffer_address(chip, 0x0);
+		ad1889_load_wave_buffer_count(chip, 0x0);
+		ad1889_load_wave_interrupt_count(chip, 0x0);
 
 		/* flush */
 		ad1889_readw(chip, AD_DMA_WAV);
@@ -226,9 +239,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		reg &= ~AD_DMA_LOOP;
 		ad1889_writew(chip, AD_DMA_ADC, reg);
 	
-		ad1889_load_adc_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCBA, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCCA, 0x0);
+		ad1889_load_adc_buffer_address(chip, 0x0);
+		ad1889_load_adc_buffer_count(chip, 0x0);
+		ad1889_load_adc_interrupt_count(chip, 0x0);
 
 		/* flush */
 		ad1889_readw(chip, AD_DMA_ADC);
@@ -290,11 +303,11 @@ static snd_pcm_hardware_t snd_ad1889_pla
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = 256 * 1024,
+	.period_bytes_min = 32,
+	.period_bytes_max = 128 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
 	/*.fifo_size = 0,*/
 };
 
@@ -307,11 +320,11 @@ static snd_pcm_hardware_t snd_ad1889_cap
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = 256 * 1024,
+	.period_bytes_min = 32,
+	.period_bytes_max = 128 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
 	/*.fifo_size = 0,*/
 };
 
@@ -381,24 +394,18 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	spin_lock_irq(&chip->lock);
 	
 	chip->wave.size = size;
-	chip->wave.count = count;
 	chip->wave.reg = reg;
-	chip->wave.buf = 0;
-	chip->wave.pos = 0;
-	chip->wave.rate = rt->rate;
 	chip->wave.addr = rt->dma_addr;
 
 	ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg);
 	
 	/* Set sample rates on the codec */
-	ad1889_writew(chip, AD_DS_WAS, chip->wave.rate);
+	ad1889_writew(chip, AD_DS_WAS, rt->rate);
 
-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_WAVCA, chip->wave.addr);
-	ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + (count % size));
-	ad1889_load_wave_count(chip, chip->wave.count);
+	/* Set up DMA */
+	ad1889_load_wave_buffer_address(chip, chip->wave.addr);
+	ad1889_load_wave_buffer_count(chip, size);
+	ad1889_load_wave_interrupt_count(chip, count);
 
 	/* writes flush */
 	ad1889_readw(chip, AD_DS_WSMC);
@@ -407,7 +414,7 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	
 	ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
-			count, size, reg, chip->wave.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }
 
@@ -437,21 +444,15 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	spin_lock_irq(&chip->lock);
 	
 	chip->ramc.size = size;
-	chip->ramc.count = count;
 	chip->ramc.reg = reg;
-	chip->ramc.buf = 0;
-	chip->ramc.pos = 0;
-	chip->ramc.rate = rt->rate;
 	chip->ramc.addr = rt->dma_addr;
 
 	ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg);
 
-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_ADCCA, chip->ramc.addr);
-	ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + (count % size));
-	ad1889_load_adc_count(chip, chip->ramc.count);
+	/* Set up DMA */
+	ad1889_load_adc_buffer_address(chip, chip->ramc.addr);
+	ad1889_load_adc_buffer_count(chip, size);
+	ad1889_load_adc_interrupt_count(chip, count);
 
 	/* writes flush */
 	ad1889_readw(chip, AD_DS_RAMC);
@@ -460,7 +461,7 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	
 	ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
-			count, size, reg, chip->ramc.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }
 
@@ -607,7 +608,6 @@ snd_ad1889_interrupt(int irq, 
 		     struct pt_regs *regs)
 {
 	unsigned long st;
-	unsigned long next;
 	struct snd_ad1889 *chip = dev_id;
 
 	st = ad1889_readl(chip, AD_DMA_DISR);
@@ -623,82 +623,12 @@ snd_ad1889_interrupt(int irq, 
 	if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
 		ad1889_debug("Unexpected master or target abort interrupt!\n");
 
-	if (chip->pcm && (st & AD_DMA_DISR_WAVI) && chip->psubs) {
-		spin_lock(&chip->lock);
-
-		chip->stats.wav_intr++;
-
-		chip->wave.buf++;
-
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->wave.pos += chip->wave.count;
-		chip->wave.pos %= chip->wave.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->wave.pos + chip->wave.count;
-		next %= chip->wave.size;
-		
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + next);
-		
-		ad1889_readl(chip, AD_DMA_WAVBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-
+	if ((st & AD_DMA_DISR_WAVI) && chip->psubs)
 		snd_pcm_period_elapsed(chip->psubs);
-#if 0
-		ad1889_debug("chip->wave.pos = %d, chip->wave.count = %d, "
-				"chip->wave.size = %d\n", chip->wave.pos,
-				chip->wave.count, chip->wave.size);
-		ad1889_debug("chip->wave.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->wave.addr, next, chip->wave.addr + next);
-#endif		
-	}
-
-	if (chip->pcm && (st & AD_DMA_DISR_ADCI) && chip->csubs) {
-		spin_lock(&chip->lock);
-		
-		chip->stats.adc_intr++;
-
-		chip->ramc.buf++;
-		
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->ramc.pos += chip->ramc.count;
-		chip->ramc.pos %= chip->ramc.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->ramc.pos + chip->ramc.count;
-		next %= chip->ramc.size;
-
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + next);
-		
-		ad1889_readl(chip, AD_DMA_ADCBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-		
+	if ((st & AD_DMA_DISR_ADCI) && chip->csubs)
 		snd_pcm_period_elapsed(chip->csubs);
-#if 0
-		ad1889_debug("chip->ramc.pos = %d, chip->ramc.count = %d, "
-				"chip->ramc.size = %d\n", chip->ramc.pos,
-				chip->ramc.count, chip->ramc.size);
-		ad1889_debug("chip->ramc.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->ramc.addr, next, chip->ramc.addr + next);
-#endif		
-	}
 
+	ad1889_readl(chip, AD_DMA_DISR); /* flush */
 	/* XXX under some circumstances the DISR write flush may not happen */
 
 	return IRQ_HANDLED;
@@ -741,7 +671,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *c
 
 	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 						snd_dma_pci_data(chip->pci),
-						DMA_SIZE, DMA_SIZE);
+						128 * 1024, 256 * 1024);
 
 	if (err < 0) {
 		snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-12  2:14     ` [parisc-linux] " Kyle McMartin
@ 2005-08-12  7:17       ` Clemens Ladisch
  2005-08-12  7:17       ` [parisc-linux] " Clemens Ladisch
  1 sibling, 0 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-12  7:17 UTC (permalink / raw)
  To: Kyle McMartin; +Cc: alsa-devel, parisc-linux, Thibaut VARENE

[-- Attachment #1: Type: TEXT/PLAIN, Size: 381 bytes --]

Kyle McMartin wrote:
> On Thu, Aug 11, 2005 at 05:18:31PM +0200, Clemens Ladisch wrote:
> > ... something like this (please test):
>
> This doesn't apply against PA-RISC Linux CVS head (should have
> no changes since submission) nor against ALSA CVS head...

It should apply against both, but it seems somewhere some whitespaces
got lost ...

Here you go again.


Regards,
Clemens

[-- Attachment #2: Type: TEXT/PLAIN, Size: 11785 bytes --]

Index: alsa/alsa-driver/pci/ad1889.h
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.h	2005-08-04 17:56:50.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.h	2005-08-11 11:54:38.000000000 +0200
@@ -172,13 +172,6 @@
 #define AD_ADC_STATE	1
 #define AD_MAX_STATES	2
 
-/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
-   But the IOMMU can only map at page size granularity."
-   This affects in particular .period_bytes_min */
-#define BUF_SIZE        PAGE_SIZE
-#define MAX_BUFS        32
-#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
-
 #define AD_CHAN_WAV	0x0001
 #define AD_CHAN_ADC	0x0002
 #define AD_CHAN_RES	0x0004
Index: alsa/alsa-driver/pci/ad1889.c
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.c	2005-08-11 10:46:42.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.c	2005-08-11 12:21:21.000000000 +0200
@@ -87,15 +87,11 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 work
 /* let's use the global sound debug interfaces */
 #define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)
 
-/* keep track of each hw register */
+/* keep track of some hw registers */
 struct ad1889_register_state {
 	u16 reg;	/* reg setup */
 	u32 addr;	/* dma base address */
-	u16 rate;	/* sample rate */
-	unsigned long pos;	/* last recorded DMA buffer position */
-	unsigned long buf;	/* period # */
 	unsigned long size;	/* DMA buffer size */
-	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
 };
 
 struct snd_ad1889 {
@@ -118,13 +114,6 @@ struct snd_ad1889 {
 	struct ad1889_register_state wave;
 	struct ad1889_register_state ramc;
 
-	struct {
-		unsigned long wav_intr;
-		unsigned long adc_intr;
-		unsigned long syn_intr;
-		unsigned long res_intr;
-	} stats;
-
 	spinlock_t lock;
 };
 
@@ -172,22 +161,46 @@ ad1889_mute(struct snd_ad1889 *chip)
 }
 
 static inline void
-ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_ADCBA, address);
+	ad1889_writel(chip, AD_DMA_ADCCA, address);
+}
+
+static inline void
+ad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_ADCBC, count);
 	ad1889_writel(chip, AD_DMA_ADCCC, count);
+}
+
+static inline void
+ad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_ADCIB, count);
 	ad1889_writel(chip, AD_DMA_ADCIC, count);
-}	
+}
+
+static inline void
+ad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_WAVBA, address);
+	ad1889_writel(chip, AD_DMA_WAVCA, address);
+}
 
 static inline void
-ad1889_load_wave_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_wave_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_WAVBC, count);
 	ad1889_writel(chip, AD_DMA_WAVCC, count);
+}
+
+static inline void
+ad1889_load_wave_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_WAVIB, count);
 	ad1889_writel(chip, AD_DMA_WAVIC, count);
-}	
+}
 
 static void
 ad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel)
@@ -207,9 +220,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		ad1889_writew(chip, AD_DMA_WAV, reg);
 
 		/* clear IRQ and address counters and pointers */
-		ad1889_load_wave_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVBA, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVCA, 0x0);
+		ad1889_load_wave_buffer_address(chip, 0x0);
+		ad1889_load_wave_buffer_count(chip, 0x0);
+		ad1889_load_wave_interrupt_count(chip, 0x0);
 
 		/* flush */
 		ad1889_readw(chip, AD_DMA_WAV);
@@ -226,9 +239,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		reg &= ~AD_DMA_LOOP;
 		ad1889_writew(chip, AD_DMA_ADC, reg);
 	
-		ad1889_load_adc_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCBA, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCCA, 0x0);
+		ad1889_load_adc_buffer_address(chip, 0x0);
+		ad1889_load_adc_buffer_count(chip, 0x0);
+		ad1889_load_adc_interrupt_count(chip, 0x0);
 
 		/* flush */
 		ad1889_readw(chip, AD_DMA_ADC);
@@ -290,11 +303,11 @@ static snd_pcm_hardware_t snd_ad1889_pla
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = 256 * 1024,
+	.period_bytes_min = 32,
+	.period_bytes_max = 128 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
 	/*.fifo_size = 0,*/
 };
 
@@ -307,11 +320,11 @@ static snd_pcm_hardware_t snd_ad1889_cap
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = 256 * 1024,
+	.period_bytes_min = 32,
+	.period_bytes_max = 128 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
 	/*.fifo_size = 0,*/
 };
 
@@ -381,24 +394,18 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	spin_lock_irq(&chip->lock);
 	
 	chip->wave.size = size;
-	chip->wave.count = count;
 	chip->wave.reg = reg;
-	chip->wave.buf = 0;
-	chip->wave.pos = 0;
-	chip->wave.rate = rt->rate;
 	chip->wave.addr = rt->dma_addr;
 
 	ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg);
 	
 	/* Set sample rates on the codec */
-	ad1889_writew(chip, AD_DS_WAS, chip->wave.rate);
+	ad1889_writew(chip, AD_DS_WAS, rt->rate);
 
-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_WAVCA, chip->wave.addr);
-	ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + (count % size));
-	ad1889_load_wave_count(chip, chip->wave.count);
+	/* Set up DMA */
+	ad1889_load_wave_buffer_address(chip, chip->wave.addr);
+	ad1889_load_wave_buffer_count(chip, size);
+	ad1889_load_wave_interrupt_count(chip, count);
 
 	/* writes flush */
 	ad1889_readw(chip, AD_DS_WSMC);
@@ -407,7 +414,7 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	
 	ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
-			count, size, reg, chip->wave.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }
 
@@ -437,21 +444,15 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	spin_lock_irq(&chip->lock);
 	
 	chip->ramc.size = size;
-	chip->ramc.count = count;
 	chip->ramc.reg = reg;
-	chip->ramc.buf = 0;
-	chip->ramc.pos = 0;
-	chip->ramc.rate = rt->rate;
 	chip->ramc.addr = rt->dma_addr;
 
 	ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg);
 
-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_ADCCA, chip->ramc.addr);
-	ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + (count % size));
-	ad1889_load_adc_count(chip, chip->ramc.count);
+	/* Set up DMA */
+	ad1889_load_adc_buffer_address(chip, chip->ramc.addr);
+	ad1889_load_adc_buffer_count(chip, size);
+	ad1889_load_adc_interrupt_count(chip, count);
 
 	/* writes flush */
 	ad1889_readw(chip, AD_DS_RAMC);
@@ -460,7 +461,7 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	
 	ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
-			count, size, reg, chip->ramc.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }
 
@@ -607,7 +608,6 @@ snd_ad1889_interrupt(int irq, 
 		     struct pt_regs *regs)
 {
 	unsigned long st;
-	unsigned long next;
 	struct snd_ad1889 *chip = dev_id;
 
 	st = ad1889_readl(chip, AD_DMA_DISR);
@@ -623,82 +623,12 @@ snd_ad1889_interrupt(int irq, 
 	if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
 		ad1889_debug("Unexpected master or target abort interrupt!\n");
 
-	if (chip->pcm && (st & AD_DMA_DISR_WAVI) && chip->psubs) {
-		spin_lock(&chip->lock);
-
-		chip->stats.wav_intr++;
-
-		chip->wave.buf++;
-
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->wave.pos += chip->wave.count;
-		chip->wave.pos %= chip->wave.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->wave.pos + chip->wave.count;
-		next %= chip->wave.size;
-		
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + next);
-		
-		ad1889_readl(chip, AD_DMA_WAVBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-
+	if ((st & AD_DMA_DISR_WAVI) && chip->psubs)
 		snd_pcm_period_elapsed(chip->psubs);
-#if 0
-		ad1889_debug("chip->wave.pos = %d, chip->wave.count = %d, "
-				"chip->wave.size = %d\n", chip->wave.pos,
-				chip->wave.count, chip->wave.size);
-		ad1889_debug("chip->wave.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->wave.addr, next, chip->wave.addr + next);
-#endif		
-	}
-
-	if (chip->pcm && (st & AD_DMA_DISR_ADCI) && chip->csubs) {
-		spin_lock(&chip->lock);
-		
-		chip->stats.adc_intr++;
-
-		chip->ramc.buf++;
-		
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->ramc.pos += chip->ramc.count;
-		chip->ramc.pos %= chip->ramc.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->ramc.pos + chip->ramc.count;
-		next %= chip->ramc.size;
-
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + next);
-		
-		ad1889_readl(chip, AD_DMA_ADCBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-		
+	if ((st & AD_DMA_DISR_ADCI) && chip->csubs)
 		snd_pcm_period_elapsed(chip->csubs);
-#if 0
-		ad1889_debug("chip->ramc.pos = %d, chip->ramc.count = %d, "
-				"chip->ramc.size = %d\n", chip->ramc.pos,
-				chip->ramc.count, chip->ramc.size);
-		ad1889_debug("chip->ramc.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->ramc.addr, next, chip->ramc.addr + next);
-#endif		
-	}
 
+	ad1889_readl(chip, AD_DMA_DISR); /* flush */
 	/* XXX under some circumstances the DISR write flush may not happen */
 
 	return IRQ_HANDLED;
@@ -741,7 +671,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *c
 
 	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 						snd_dma_pci_data(chip->pci),
-						DMA_SIZE, DMA_SIZE);
+						128 * 1024, 256 * 1024);
 
 	if (err < 0) {
 		snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);

[-- Attachment #3: Type: text/plain, Size: 169 bytes --]

_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-12  7:17       ` [parisc-linux] " Clemens Ladisch
  2005-08-17  1:51         ` [parisc-linux] [Alsa-devel] " Kyle McMartin
@ 2005-08-17  1:51         ` Kyle McMartin
  2005-08-17 13:50           ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
  2005-08-17 13:50           ` [parisc-linux] " Clemens Ladisch
  1 sibling, 2 replies; 35+ messages in thread
From: Kyle McMartin @ 2005-08-17  1:51 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: Thibaut VARENE, alsa-devel, parisc-linux

On Fri, Aug 12, 2005 at 09:17:47AM +0200, Clemens Ladisch wrote:
> It should apply against both, but it seems somewhere some whitespaces
> got lost ...
> 
> Here you go again.

Sorry for taking so long to get back to you. Your patch appears to work
fine in OSS mode, but native ALSA on PA-RISC still seems broken. Thibaut
seems to point out that this is not the driver, but a more deep seated
problem, as the driver seems to function properly in native ALSA playback
mode on powerpc.

I'll keep the patch in my tree, and give it a few days of beating.

Cheers,
-- 
Kyle McMartin


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-12  7:17       ` [parisc-linux] " Clemens Ladisch
@ 2005-08-17  1:51         ` Kyle McMartin
  2005-08-17  1:51         ` [parisc-linux] " Kyle McMartin
  1 sibling, 0 replies; 35+ messages in thread
From: Kyle McMartin @ 2005-08-17  1:51 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel, parisc-linux, Thibaut VARENE

On Fri, Aug 12, 2005 at 09:17:47AM +0200, Clemens Ladisch wrote:
> It should apply against both, but it seems somewhere some whitespaces
> got lost ...
> 
> Here you go again.

Sorry for taking so long to get back to you. Your patch appears to work
fine in OSS mode, but native ALSA on PA-RISC still seems broken. Thibaut
seems to point out that this is not the driver, but a more deep seated
problem, as the driver seems to function properly in native ALSA playback
mode on powerpc.

I'll keep the patch in my tree, and give it a few days of beating.

Cheers,
-- 
Kyle McMartin
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-11 15:18   ` Clemens Ladisch
  2005-08-12  2:14     ` [parisc-linux] [Alsa-devel] " Kyle McMartin
  2005-08-12  2:14     ` [parisc-linux] " Kyle McMartin
@ 2005-08-17  9:10     ` Thibaut VARENE
  2005-08-18 15:35       ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
  2005-08-18 15:35       ` [parisc-linux] " Clemens Ladisch
  2005-08-17  9:10     ` Thibaut VARENE
  3 siblings, 2 replies; 35+ messages in thread
From: Thibaut VARENE @ 2005-08-17  9:10 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: Thibaut VARENE, alsa-devel, parisc-linux, kyle

Hi

quick reply from vacation as there are a few things i'd like to
comment upon.

Clemens Ladisch wrote:

> > I don't actually have this hardware :-), but the docs don't
mention
> > any dependency between the count registers (BC, CC) and the
interrupt
> > count registers (IC, IB).
> >
> > So wouldn't it be possible to put the ALSA buffer size into the
count
> > registers and the ALSA period size into the interrupt count
registers?

yes it would be possible, i believe.

> > This would make the interrupt handler much simpler, as it wouldn't
> > have to reprogram any registers.  And it would solve the problem
that
> > the DMA accesses for one period go beyond the buffer when the
number
> > of periods per buffer is not an integer.

correct, this was something i was planning on trying at some point,
thanks for beating me to it ;)

> ... something like this (please test):

your suggestion is good, but your patch does more than just
implementing, and there are a few things I'm not quite comfortable
with.

> Index: alsa/alsa-driver/pci/ad1889.h
> ===================================================================
> --- alsa.orig/alsa-driver/pci/ad1889.h	2005-08-04 17:56:50.000000000
+0200
> +++ alsa/alsa-driver/pci/ad1889.h	2005-08-11 11:54:38.000000000
+0200
> @@ -172,13 +172,6 @@
>  #define AD_ADC_STATE	1
>  #define AD_MAX_STATES	2
> 
> -/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
> -   But the IOMMU can only map at page size granularity."
> -   This affects in particular .period_bytes_min */
> -#define BUF_SIZE        PAGE_SIZE
> -#define MAX_BUFS        32
> -#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)

don't remove these defines please, i'd rather have every constants
defined in the header file. Personal taste... Besides, the comment is
very relevant to PA-RISC architecture, where no matter what the value
is, the minimum allocated space will always be at page size
granularity.


> ===================================================================
> --- alsa.orig/alsa-driver/pci/ad1889.c	2005-08-11 10:46:42.000000000
+0200
> +++ alsa/alsa-driver/pci/ad1889.c	2005-08-11 12:21:21.000000000
+0200
> @@ -87,15 +87,11 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 work
>  /* let's use the global sound debug interfaces */
>  #define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ##
arg)
> 
> -/* keep track of each hw register */
> +/* keep track of some hw registers */
>  struct ad1889_register_state {
>  	u16 reg;	/* reg setup */
>  	u32 addr;	/* dma base address */
> -	u16 rate;	/* sample rate */
> -	unsigned long pos;	/* last recorded DMA buffer position */
> -	unsigned long buf;	/* period # */
>  	unsigned long size;	/* DMA buffer size */
> -	unsigned long count;	/* period size, aka nb bytes sent in the
current DMA transfer */
>  };
> 
>  struct snd_ad1889 {
> @@ -118,13 +114,6 @@ struct snd_ad1889 {
>  	struct ad1889_register_state wave;
>  	struct ad1889_register_state ramc;
> 
> -	struct {
> -		unsigned long wav_intr;
> -		unsigned long adc_intr;
> -		unsigned long syn_intr;
> -		unsigned long res_intr;
> -	} stats;
> -
>  	spinlock_t lock;
>  };

reading the patch through webmail doesn't help a lot getting a grasp
of its whole but i wonder if we could still find some debugging
purposes for these values. Remember this driver is work in progress ;)

> @@ -172,22 +161,46 @@ ad1889_mute(struct snd_ad1889 *chip)
>  }
> 
>  static inline void
> -ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
> +ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32
address)
> +{
> +	ad1889_writel(chip, AD_DMA_ADCBA, address);
> +	ad1889_writel(chip, AD_DMA_ADCCA, address);
> +}
> +
> +static inline void
> +ad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count)
>  {
>  	ad1889_writel(chip, AD_DMA_ADCBC, count);
>  	ad1889_writel(chip, AD_DMA_ADCCC, count);
> +}
> +
> +static inline void
> +ad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count)
> +{
>  	ad1889_writel(chip, AD_DMA_ADCIB, count);
>  	ad1889_writel(chip, AD_DMA_ADCIC, count);
> -}
> +}
> +
> +static inline void
> +ad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32
address)
> +{
> +	ad1889_writel(chip, AD_DMA_WAVBA, address);
> +	ad1889_writel(chip, AD_DMA_WAVCA, address);
> +}

ok i had removed these because i felt they were just bloating the file
and were sparsely used, but ok, it's nicer that way =)

>  		/* flush */
>  		ad1889_readw(chip, AD_DMA_ADC);
> @@ -290,11 +303,11 @@ static snd_pcm_hardware_t snd_ad1889_pla
>  	.rate_max = 48000,
>  	.channels_min = 1,
>  	.channels_max = 2,
> -	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
> -	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
> -	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
> -	.periods_min = 1,		/* min nb of periods in buffer */
> -	.periods_max = MAX_BUFS,
> +	.buffer_bytes_max = 256 * 1024,
> +	.period_bytes_min = 32,
> +	.period_bytes_max = 128 * 1024,
> +	.periods_min = 2,
> +	.periods_max = 256,
>  	/*.fifo_size = 0,*/
>  };

see the first comment .

> @@ -741,7 +671,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *c
> 
>  	err = snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_DEV,
>  						snd_dma_pci_data(chip->pci),
> -						DMA_SIZE, DMA_SIZE);
> +						128 * 1024, 256 * 1024);

again :)


This looks mostly good to me though I lack time to test and review it
more thoroughly. Hopefully I should be back later this month to give a
better look at it. I'd like to hear from Kyle as well.

Thanks for submitting this anyway.

T-Bone

-- 
Thibaut VARENE
http://www.parisc-linux.org/~varenet/


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-11 15:18   ` Clemens Ladisch
                       ` (2 preceding siblings ...)
  2005-08-17  9:10     ` Thibaut VARENE
@ 2005-08-17  9:10     ` Thibaut VARENE
  3 siblings, 0 replies; 35+ messages in thread
From: Thibaut VARENE @ 2005-08-17  9:10 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: kyle, alsa-devel, parisc-linux, Thibaut VARENE

Hi

quick reply from vacation as there are a few things i'd like to
comment upon.

Clemens Ladisch wrote:

> > I don't actually have this hardware :-), but the docs don't
mention
> > any dependency between the count registers (BC, CC) and the
interrupt
> > count registers (IC, IB).
> >
> > So wouldn't it be possible to put the ALSA buffer size into the
count
> > registers and the ALSA period size into the interrupt count
registers?

yes it would be possible, i believe.

> > This would make the interrupt handler much simpler, as it wouldn't
> > have to reprogram any registers.  And it would solve the problem
that
> > the DMA accesses for one period go beyond the buffer when the
number
> > of periods per buffer is not an integer.

correct, this was something i was planning on trying at some point,
thanks for beating me to it ;)

> ... something like this (please test):

your suggestion is good, but your patch does more than just
implementing, and there are a few things I'm not quite comfortable
with.

> Index: alsa/alsa-driver/pci/ad1889.h
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- alsa.orig/alsa-driver/pci/ad1889.h	2005-08-04 17:56:50.000000000
+0200
> +++ alsa/alsa-driver/pci/ad1889.h	2005-08-11 11:54:38.000000000
+0200
> @@ -172,13 +172,6 @@
>  #define AD_ADC_STATE	1
>  #define AD_MAX_STATES	2
>=20
> -/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
> -   But the IOMMU can only map at page size granularity."
> -   This affects in particular .period_bytes_min */
> -#define BUF_SIZE        PAGE_SIZE
> -#define MAX_BUFS        32
> -#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)

don't remove these defines please, i'd rather have every constants
defined in the header file. Personal taste... Besides, the comment is
very relevant to PA-RISC architecture, where no matter what the value
is, the minimum allocated space will always be at page size
granularity.


> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- alsa.orig/alsa-driver/pci/ad1889.c	2005-08-11 10:46:42.000000000
+0200
> +++ alsa/alsa-driver/pci/ad1889.c	2005-08-11 12:21:21.000000000
+0200
> @@ -87,15 +87,11 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 work
>  /* let's use the global sound debug interfaces */
>  #define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ##
arg)
>=20
> -/* keep track of each hw register */
> +/* keep track of some hw registers */
>  struct ad1889_register_state {
>  	u16 reg;	/* reg setup */
>  	u32 addr;	/* dma base address */
> -	u16 rate;	/* sample rate */
> -	unsigned long pos;	/* last recorded DMA buffer position */
> -	unsigned long buf;	/* period # */
>  	unsigned long size;	/* DMA buffer size */
> -	unsigned long count;	/* period size, aka nb bytes sent in the
current DMA transfer */
>  };
>=20
>  struct snd_ad1889 {
> @@ -118,13 +114,6 @@ struct snd_ad1889 {
>  	struct ad1889_register_state wave;
>  	struct ad1889_register_state ramc;
>=20
> -	struct {
> -		unsigned long wav_intr;
> -		unsigned long adc_intr;
> -		unsigned long syn_intr;
> -		unsigned long res_intr;
> -	} stats;
> -
>  	spinlock_t lock;
>  };

reading the patch through webmail doesn't help a lot getting a grasp
of its whole but i wonder if we could still find some debugging
purposes for these values. Remember this driver is work in progress ;)

> @@ -172,22 +161,46 @@ ad1889_mute(struct snd_ad1889 *chip)
>  }
>=20
>  static inline void
> -ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
> +ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32
address)
> +{
> +	ad1889_writel(chip, AD_DMA_ADCBA, address);
> +	ad1889_writel(chip, AD_DMA_ADCCA, address);
> +}
> +
> +static inline void
> +ad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count)
>  {
>  	ad1889_writel(chip, AD_DMA_ADCBC, count);
>  	ad1889_writel(chip, AD_DMA_ADCCC, count);
> +}
> +
> +static inline void
> +ad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count)
> +{
>  	ad1889_writel(chip, AD_DMA_ADCIB, count);
>  	ad1889_writel(chip, AD_DMA_ADCIC, count);
> -}
> +}
> +
> +static inline void
> +ad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32
address)
> +{
> +	ad1889_writel(chip, AD_DMA_WAVBA, address);
> +	ad1889_writel(chip, AD_DMA_WAVCA, address);
> +}

ok i had removed these because i felt they were just bloating the file
and were sparsely used, but ok, it's nicer that way =3D)

>  		/* flush */
>  		ad1889_readw(chip, AD_DMA_ADC);
> @@ -290,11 +303,11 @@ static snd_pcm_hardware_t snd_ad1889_pla
>  	.rate_max =3D 48000,
>  	.channels_min =3D 1,
>  	.channels_max =3D 2,
> -	.buffer_bytes_max =3D DMA_SIZE,	/* max DMA buffer size in bytes */
> -	.period_bytes_min =3D BUF_SIZE,	/* min size of period in bytes */
> -	.period_bytes_max =3D DMA_SIZE,	/* max size of period in bytes */
> -	.periods_min =3D 1,		/* min nb of periods in buffer */
> -	.periods_max =3D MAX_BUFS,
> +	.buffer_bytes_max =3D 256 * 1024,
> +	.period_bytes_min =3D 32,
> +	.period_bytes_max =3D 128 * 1024,
> +	.periods_min =3D 2,
> +	.periods_max =3D 256,
>  	/*.fifo_size =3D 0,*/
>  };

see the first comment .

> @@ -741,7 +671,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *c
>=20
>  	err =3D snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_DEV,
>  						snd_dma_pci_data(chip->pci),
> -						DMA_SIZE, DMA_SIZE);
> +						128 * 1024, 256 * 1024);

again :)


This looks mostly good to me though I lack time to test and review it
more thoroughly. Hopefully I should be back later this month to give a
better look at it. I'd like to hear from Kyle as well.

Thanks for submitting this anyway.

T-Bone

--=20
Thibaut VARENE
http://www.parisc-linux.org/~varenet/
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-17  1:51         ` [parisc-linux] " Kyle McMartin
  2005-08-17 13:50           ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
@ 2005-08-17 13:50           ` Clemens Ladisch
  1 sibling, 0 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-17 13:50 UTC (permalink / raw)
  To: Kyle McMartin; +Cc: Thibaut VARENE, alsa-devel, parisc-linux

Kyle McMartin wrote:
> Your patch appears to work fine in OSS mode, but native ALSA on
> PA-RISC still seems broken.

The biggest difference may be that OSS uses power-of-two period and
buffer sizes.

Does it work with "aplay --period-size=1024 --buffer-size=8192 ..."?


Regards,
Clemens



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-17  1:51         ` [parisc-linux] " Kyle McMartin
@ 2005-08-17 13:50           ` Clemens Ladisch
  2005-08-17 13:50           ` [parisc-linux] " Clemens Ladisch
  1 sibling, 0 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-17 13:50 UTC (permalink / raw)
  To: Kyle McMartin; +Cc: alsa-devel, parisc-linux, Thibaut VARENE

Kyle McMartin wrote:
> Your patch appears to work fine in OSS mode, but native ALSA on
> PA-RISC still seems broken.

The biggest difference may be that OSS uses power-of-two period and
buffer sizes.

Does it work with "aplay --period-size=1024 --buffer-size=8192 ..."?


Regards,
Clemens

_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-17  9:10     ` Thibaut VARENE
  2005-08-18 15:35       ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
@ 2005-08-18 15:35       ` Clemens Ladisch
  2005-08-18 17:12         ` Lee Revell
                           ` (4 more replies)
  1 sibling, 5 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-18 15:35 UTC (permalink / raw)
  To: Thibaut VARENE; +Cc: alsa-devel, parisc-linux, kyle

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2257 bytes --]

Thibaut VARENE wrote:
> > -/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
> > -   But the IOMMU can only map at page size granularity."
> > -   This affects in particular .period_bytes_min */
> > -#define BUF_SIZE        PAGE_SIZE
> > -#define MAX_BUFS        32
> > -#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
>
> don't remove these defines please, i'd rather have every constants
> defined in the header file.

I removed them because it wouldn't make sense to derive the buffer
size from the period size in the patched driver.  I used some more or
less random values because these values aren't anymore restricted by
the chip's constraints.

> Besides, the comment is very relevant to PA-RISC architecture,
> where no matter what the value is, the minimum allocated space
> will always be at page size granularity.

Most IOMMUs have this restriction.  ALSA's PCM buffer is always page
aligned, so drivers that do DMA over the entire buffer just don't
care.

> > -/* keep track of each hw register */
> > +/* keep track of some hw registers */
> >  struct ad1889_register_state {
> >  	u16 reg;	/* reg setup */
> >  	u32 addr;	/* dma base address */
> > -	u16 rate;	/* sample rate */
> > -	unsigned long pos;	/* last recorded DMA buffer position */
> > -	unsigned long buf;	/* period # */
> >  	unsigned long size;	/* DMA buffer size */
> > -	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
>
> reading the patch through webmail doesn't help a lot getting a grasp
> of its whole but i wonder if we could still find some debugging
> purposes for these values. Remember this driver is work in progress ;)

Those fields just aren't used anymore; anything interesting is in the
chip's registers.

> > +ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address)
> > +{
> > +	ad1889_writel(chip, AD_DMA_ADCBA, address);
> > +	ad1889_writel(chip, AD_DMA_ADCCA, address);
> > +}
> > ...
>
> ok i had removed these because i felt they were just bloating the file
> and were sparsely used, but ok, it's nicer that way =)

I added them only for documentation purposes; those AD_DMA_ADCABC
symbols aren't too easy to distinguish ...


Attached is a new patch with symbols for buffer size etc.


Regards,
Clemens

[-- Attachment #2: Type: TEXT/PLAIN, Size: 12266 bytes --]

Index: alsa/alsa-driver/pci/ad1889.h
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.h	2005-08-11 21:19:33.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.h	2005-08-18 15:06:04.000000000 +0200
@@ -172,16 +172,18 @@
 #define AD_ADC_STATE	1
 #define AD_MAX_STATES	2
 
-/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
-   But the IOMMU can only map at page size granularity."
-   This affects in particular .period_bytes_min */
-#define BUF_SIZE        PAGE_SIZE
-#define MAX_BUFS        32
-#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
-
 #define AD_CHAN_WAV	0x0001
 #define AD_CHAN_ADC	0x0002
 #define AD_CHAN_RES	0x0004
 #define AD_CHAN_SYN	0x0008
 
+
+/* The chip would support 4 GB buffers and 16 MB periods,
+ * but let's not overdo it ... */
+#define BUFFER_BYTES_MAX	(256 * 1024)
+#define PERIOD_BYTES_MIN	32
+#define PERIOD_BYTES_MAX	(BUFFER_BYTES_MAX / 2)
+#define PERIODS_MIN		2
+#define PERIODS_MAX		(BUFFER_BYTES_MAX / PERIOD_BYTES_MIN)
+
 #endif /* __AD1889_H__ */
Index: alsa/alsa-driver/pci/ad1889.c
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.c	2005-08-11 21:19:33.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.c	2005-08-18 15:10:59.000000000 +0200
@@ -87,15 +87,11 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 work
 /* let's use the global sound debug interfaces */
 #define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)
 
-/* keep track of each hw register */
+/* keep track of some hw registers */
 struct ad1889_register_state {
 	u16 reg;	/* reg setup */
 	u32 addr;	/* dma base address */
-	u16 rate;	/* sample rate */
-	unsigned long pos;	/* last recorded DMA buffer position */
-	unsigned long buf;	/* period # */
 	unsigned long size;	/* DMA buffer size */
-	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
 };
 
 struct snd_ad1889 {
@@ -118,13 +114,6 @@ struct snd_ad1889 {
 	struct ad1889_register_state wave;
 	struct ad1889_register_state ramc;
 
-	struct {
-		unsigned long wav_intr;
-		unsigned long adc_intr;
-		unsigned long syn_intr;
-		unsigned long res_intr;
-	} stats;
-
 	spinlock_t lock;
 };
 
@@ -172,22 +161,46 @@ ad1889_mute(struct snd_ad1889 *chip)
 }
 
 static inline void
-ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_ADCBA, address);
+	ad1889_writel(chip, AD_DMA_ADCCA, address);
+}
+
+static inline void
+ad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_ADCBC, count);
 	ad1889_writel(chip, AD_DMA_ADCCC, count);
+}
+
+static inline void
+ad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_ADCIB, count);
 	ad1889_writel(chip, AD_DMA_ADCIC, count);
-}	
+}
+
+static inline void
+ad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_WAVBA, address);
+	ad1889_writel(chip, AD_DMA_WAVCA, address);
+}
 
 static inline void
-ad1889_load_wave_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_wave_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_WAVBC, count);
 	ad1889_writel(chip, AD_DMA_WAVCC, count);
+}
+
+static inline void
+ad1889_load_wave_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_WAVIB, count);
 	ad1889_writel(chip, AD_DMA_WAVIC, count);
-}	
+}
 
 static void
 ad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel)
@@ -207,9 +220,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		ad1889_writew(chip, AD_DMA_WAV, reg);
 
 		/* clear IRQ and address counters and pointers */
-		ad1889_load_wave_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVBA, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVCA, 0x0);
+		ad1889_load_wave_buffer_address(chip, 0x0);
+		ad1889_load_wave_buffer_count(chip, 0x0);
+		ad1889_load_wave_interrupt_count(chip, 0x0);
 
 		/* flush */
 		ad1889_readw(chip, AD_DMA_WAV);
@@ -226,9 +239,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		reg &= ~AD_DMA_LOOP;
 		ad1889_writew(chip, AD_DMA_ADC, reg);
 	
-		ad1889_load_adc_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCBA, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCCA, 0x0);
+		ad1889_load_adc_buffer_address(chip, 0x0);
+		ad1889_load_adc_buffer_count(chip, 0x0);
+		ad1889_load_adc_interrupt_count(chip, 0x0);
 
 		/* flush */
 		ad1889_readw(chip, AD_DMA_ADC);
@@ -290,11 +303,11 @@ static snd_pcm_hardware_t snd_ad1889_pla
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = BUFFER_BYTES_MAX,
+	.period_bytes_min = PERIOD_BYTES_MIN,
+	.period_bytes_max = PERIOD_BYTES_MAX,
+	.periods_min = PERIODS_MIN,
+	.periods_max = PERIODS_MAX,
 	/*.fifo_size = 0,*/
 };
 
@@ -307,11 +320,11 @@ static snd_pcm_hardware_t snd_ad1889_cap
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = BUFFER_BYTES_MAX,
+	.period_bytes_min = PERIOD_BYTES_MIN,
+	.period_bytes_max = PERIOD_BYTES_MAX,
+	.periods_min = PERIODS_MIN,
+	.periods_max = PERIODS_MAX,
 	/*.fifo_size = 0,*/
 };
 
@@ -381,24 +394,18 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	spin_lock_irq(&chip->lock);
 	
 	chip->wave.size = size;
-	chip->wave.count = count;
 	chip->wave.reg = reg;
-	chip->wave.buf = 0;
-	chip->wave.pos = 0;
-	chip->wave.rate = rt->rate;
 	chip->wave.addr = rt->dma_addr;
 
 	ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg);
 	
 	/* Set sample rates on the codec */
-	ad1889_writew(chip, AD_DS_WAS, chip->wave.rate);
+	ad1889_writew(chip, AD_DS_WAS, rt->rate);
 
-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_WAVCA, chip->wave.addr);
-	ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + (count % size));
-	ad1889_load_wave_count(chip, chip->wave.count);
+	/* Set up DMA */
+	ad1889_load_wave_buffer_address(chip, chip->wave.addr);
+	ad1889_load_wave_buffer_count(chip, size);
+	ad1889_load_wave_interrupt_count(chip, count);
 
 	/* writes flush */
 	ad1889_readw(chip, AD_DS_WSMC);
@@ -407,7 +414,7 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	
 	ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
-			count, size, reg, chip->wave.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }
 
@@ -437,21 +444,15 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	spin_lock_irq(&chip->lock);
 	
 	chip->ramc.size = size;
-	chip->ramc.count = count;
 	chip->ramc.reg = reg;
-	chip->ramc.buf = 0;
-	chip->ramc.pos = 0;
-	chip->ramc.rate = rt->rate;
 	chip->ramc.addr = rt->dma_addr;
 
 	ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg);
 
-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_ADCCA, chip->ramc.addr);
-	ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + (count % size));
-	ad1889_load_adc_count(chip, chip->ramc.count);
+	/* Set up DMA */
+	ad1889_load_adc_buffer_address(chip, chip->ramc.addr);
+	ad1889_load_adc_buffer_count(chip, size);
+	ad1889_load_adc_interrupt_count(chip, count);
 
 	/* writes flush */
 	ad1889_readw(chip, AD_DS_RAMC);
@@ -460,7 +461,7 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	
 	ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
-			count, size, reg, chip->ramc.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }
 
@@ -607,7 +608,6 @@ snd_ad1889_interrupt(int irq, 
 		     struct pt_regs *regs)
 {
 	unsigned long st;
-	unsigned long next;
 	struct snd_ad1889 *chip = dev_id;
 
 	st = ad1889_readl(chip, AD_DMA_DISR);
@@ -623,82 +623,12 @@ snd_ad1889_interrupt(int irq, 
 	if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
 		ad1889_debug("Unexpected master or target abort interrupt!\n");
 
-	if (chip->pcm && (st & AD_DMA_DISR_WAVI) && chip->psubs) {
-		spin_lock(&chip->lock);
-
-		chip->stats.wav_intr++;
-
-		chip->wave.buf++;
-
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->wave.pos += chip->wave.count;
-		chip->wave.pos %= chip->wave.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->wave.pos + chip->wave.count;
-		next %= chip->wave.size;
-		
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + next);
-		
-		ad1889_readl(chip, AD_DMA_WAVBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-
+	if ((st & AD_DMA_DISR_WAVI) && chip->psubs)
 		snd_pcm_period_elapsed(chip->psubs);
-#if 0
-		ad1889_debug("chip->wave.pos = %d, chip->wave.count = %d, "
-				"chip->wave.size = %d\n", chip->wave.pos,
-				chip->wave.count, chip->wave.size);
-		ad1889_debug("chip->wave.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->wave.addr, next, chip->wave.addr + next);
-#endif		
-	}
-
-	if (chip->pcm && (st & AD_DMA_DISR_ADCI) && chip->csubs) {
-		spin_lock(&chip->lock);
-		
-		chip->stats.adc_intr++;
-
-		chip->ramc.buf++;
-		
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->ramc.pos += chip->ramc.count;
-		chip->ramc.pos %= chip->ramc.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->ramc.pos + chip->ramc.count;
-		next %= chip->ramc.size;
-
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + next);
-		
-		ad1889_readl(chip, AD_DMA_ADCBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-		
+	if ((st & AD_DMA_DISR_ADCI) && chip->csubs)
 		snd_pcm_period_elapsed(chip->csubs);
-#if 0
-		ad1889_debug("chip->ramc.pos = %d, chip->ramc.count = %d, "
-				"chip->ramc.size = %d\n", chip->ramc.pos,
-				chip->ramc.count, chip->ramc.size);
-		ad1889_debug("chip->ramc.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->ramc.addr, next, chip->ramc.addr + next);
-#endif		
-	}
 
+	ad1889_readl(chip, AD_DMA_DISR); /* flush */
 	/* XXX under some circumstances the DISR write flush may not happen */
 
 	return IRQ_HANDLED;
@@ -741,7 +671,8 @@ snd_ad1889_pcm_init(struct snd_ad1889 *c
 
 	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 						snd_dma_pci_data(chip->pci),
-						DMA_SIZE, DMA_SIZE);
+						BUFFER_BYTES_MAX / 2,
+						BUFFER_BYTES_MAX);
 
 	if (err < 0) {
 		snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-17  9:10     ` Thibaut VARENE
@ 2005-08-18 15:35       ` Clemens Ladisch
  2005-08-18 15:35       ` [parisc-linux] " Clemens Ladisch
  1 sibling, 0 replies; 35+ messages in thread
From: Clemens Ladisch @ 2005-08-18 15:35 UTC (permalink / raw)
  To: Thibaut VARENE; +Cc: alsa-devel, parisc-linux, kyle

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2257 bytes --]

Thibaut VARENE wrote:
> > -/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
> > -   But the IOMMU can only map at page size granularity."
> > -   This affects in particular .period_bytes_min */
> > -#define BUF_SIZE        PAGE_SIZE
> > -#define MAX_BUFS        32
> > -#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
>
> don't remove these defines please, i'd rather have every constants
> defined in the header file.

I removed them because it wouldn't make sense to derive the buffer
size from the period size in the patched driver.  I used some more or
less random values because these values aren't anymore restricted by
the chip's constraints.

> Besides, the comment is very relevant to PA-RISC architecture,
> where no matter what the value is, the minimum allocated space
> will always be at page size granularity.

Most IOMMUs have this restriction.  ALSA's PCM buffer is always page
aligned, so drivers that do DMA over the entire buffer just don't
care.

> > -/* keep track of each hw register */
> > +/* keep track of some hw registers */
> >  struct ad1889_register_state {
> >  	u16 reg;	/* reg setup */
> >  	u32 addr;	/* dma base address */
> > -	u16 rate;	/* sample rate */
> > -	unsigned long pos;	/* last recorded DMA buffer position */
> > -	unsigned long buf;	/* period # */
> >  	unsigned long size;	/* DMA buffer size */
> > -	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
>
> reading the patch through webmail doesn't help a lot getting a grasp
> of its whole but i wonder if we could still find some debugging
> purposes for these values. Remember this driver is work in progress ;)

Those fields just aren't used anymore; anything interesting is in the
chip's registers.

> > +ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address)
> > +{
> > +	ad1889_writel(chip, AD_DMA_ADCBA, address);
> > +	ad1889_writel(chip, AD_DMA_ADCCA, address);
> > +}
> > ...
>
> ok i had removed these because i felt they were just bloating the file
> and were sparsely used, but ok, it's nicer that way =)

I added them only for documentation purposes; those AD_DMA_ADCABC
symbols aren't too easy to distinguish ...


Attached is a new patch with symbols for buffer size etc.


Regards,
Clemens

[-- Attachment #2: Type: TEXT/PLAIN, Size: 12266 bytes --]

Index: alsa/alsa-driver/pci/ad1889.h
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.h	2005-08-11 21:19:33.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.h	2005-08-18 15:06:04.000000000 +0200
@@ -172,16 +172,18 @@
 #define AD_ADC_STATE	1
 #define AD_MAX_STATES	2
 
-/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
-   But the IOMMU can only map at page size granularity."
-   This affects in particular .period_bytes_min */
-#define BUF_SIZE        PAGE_SIZE
-#define MAX_BUFS        32
-#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
-
 #define AD_CHAN_WAV	0x0001
 #define AD_CHAN_ADC	0x0002
 #define AD_CHAN_RES	0x0004
 #define AD_CHAN_SYN	0x0008
 
+
+/* The chip would support 4 GB buffers and 16 MB periods,
+ * but let's not overdo it ... */
+#define BUFFER_BYTES_MAX	(256 * 1024)
+#define PERIOD_BYTES_MIN	32
+#define PERIOD_BYTES_MAX	(BUFFER_BYTES_MAX / 2)
+#define PERIODS_MIN		2
+#define PERIODS_MAX		(BUFFER_BYTES_MAX / PERIOD_BYTES_MIN)
+
 #endif /* __AD1889_H__ */
Index: alsa/alsa-driver/pci/ad1889.c
===================================================================
--- alsa.orig/alsa-driver/pci/ad1889.c	2005-08-11 21:19:33.000000000 +0200
+++ alsa/alsa-driver/pci/ad1889.c	2005-08-18 15:10:59.000000000 +0200
@@ -87,15 +87,11 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 work
 /* let's use the global sound debug interfaces */
 #define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)
 
-/* keep track of each hw register */
+/* keep track of some hw registers */
 struct ad1889_register_state {
 	u16 reg;	/* reg setup */
 	u32 addr;	/* dma base address */
-	u16 rate;	/* sample rate */
-	unsigned long pos;	/* last recorded DMA buffer position */
-	unsigned long buf;	/* period # */
 	unsigned long size;	/* DMA buffer size */
-	unsigned long count;	/* period size, aka nb bytes sent in the current DMA transfer */
 };
 
 struct snd_ad1889 {
@@ -118,13 +114,6 @@ struct snd_ad1889 {
 	struct ad1889_register_state wave;
 	struct ad1889_register_state ramc;
 
-	struct {
-		unsigned long wav_intr;
-		unsigned long adc_intr;
-		unsigned long syn_intr;
-		unsigned long res_intr;
-	} stats;
-
 	spinlock_t lock;
 };
 
@@ -172,22 +161,46 @@ ad1889_mute(struct snd_ad1889 *chip)
 }
 
 static inline void
-ad1889_load_adc_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_ADCBA, address);
+	ad1889_writel(chip, AD_DMA_ADCCA, address);
+}
+
+static inline void
+ad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_ADCBC, count);
 	ad1889_writel(chip, AD_DMA_ADCCC, count);
+}
+
+static inline void
+ad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_ADCIB, count);
 	ad1889_writel(chip, AD_DMA_ADCIC, count);
-}	
+}
+
+static inline void
+ad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32 address)
+{
+	ad1889_writel(chip, AD_DMA_WAVBA, address);
+	ad1889_writel(chip, AD_DMA_WAVCA, address);
+}
 
 static inline void
-ad1889_load_wave_count(struct snd_ad1889 *chip, u32 count)
+ad1889_load_wave_buffer_count(struct snd_ad1889 *chip, u32 count)
 {
 	ad1889_writel(chip, AD_DMA_WAVBC, count);
 	ad1889_writel(chip, AD_DMA_WAVCC, count);
+}
+
+static inline void
+ad1889_load_wave_interrupt_count(struct snd_ad1889 *chip, u32 count)
+{
 	ad1889_writel(chip, AD_DMA_WAVIB, count);
 	ad1889_writel(chip, AD_DMA_WAVIC, count);
-}	
+}
 
 static void
 ad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel)
@@ -207,9 +220,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		ad1889_writew(chip, AD_DMA_WAV, reg);
 
 		/* clear IRQ and address counters and pointers */
-		ad1889_load_wave_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVBA, 0x0);
-		ad1889_writel(chip, AD_DMA_WAVCA, 0x0);
+		ad1889_load_wave_buffer_address(chip, 0x0);
+		ad1889_load_wave_buffer_count(chip, 0x0);
+		ad1889_load_wave_interrupt_count(chip, 0x0);
 
 		/* flush */
 		ad1889_readw(chip, AD_DMA_WAV);
@@ -226,9 +239,9 @@ ad1889_channel_reset(struct snd_ad1889 *
 		reg &= ~AD_DMA_LOOP;
 		ad1889_writew(chip, AD_DMA_ADC, reg);
 	
-		ad1889_load_adc_count(chip, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCBA, 0x0);
-		ad1889_writel(chip, AD_DMA_ADCCA, 0x0);
+		ad1889_load_adc_buffer_address(chip, 0x0);
+		ad1889_load_adc_buffer_count(chip, 0x0);
+		ad1889_load_adc_interrupt_count(chip, 0x0);
 
 		/* flush */
 		ad1889_readw(chip, AD_DMA_ADC);
@@ -290,11 +303,11 @@ static snd_pcm_hardware_t snd_ad1889_pla
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = BUFFER_BYTES_MAX,
+	.period_bytes_min = PERIOD_BYTES_MIN,
+	.period_bytes_max = PERIOD_BYTES_MAX,
+	.periods_min = PERIODS_MIN,
+	.periods_max = PERIODS_MAX,
 	/*.fifo_size = 0,*/
 };
 
@@ -307,11 +320,11 @@ static snd_pcm_hardware_t snd_ad1889_cap
 	.rate_max = 48000,
 	.channels_min = 1,
 	.channels_max = 2,
-	.buffer_bytes_max = DMA_SIZE,	/* max DMA buffer size in bytes */
-	.period_bytes_min = BUF_SIZE,	/* min size of period in bytes */
-	.period_bytes_max = DMA_SIZE,	/* max size of period in bytes */
-	.periods_min = 1,		/* min nb of periods in buffer */
-	.periods_max = MAX_BUFS,
+	.buffer_bytes_max = BUFFER_BYTES_MAX,
+	.period_bytes_min = PERIOD_BYTES_MIN,
+	.period_bytes_max = PERIOD_BYTES_MAX,
+	.periods_min = PERIODS_MIN,
+	.periods_max = PERIODS_MAX,
 	/*.fifo_size = 0,*/
 };
 
@@ -381,24 +394,18 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	spin_lock_irq(&chip->lock);
 	
 	chip->wave.size = size;
-	chip->wave.count = count;
 	chip->wave.reg = reg;
-	chip->wave.buf = 0;
-	chip->wave.pos = 0;
-	chip->wave.rate = rt->rate;
 	chip->wave.addr = rt->dma_addr;
 
 	ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg);
 	
 	/* Set sample rates on the codec */
-	ad1889_writew(chip, AD_DS_WAS, chip->wave.rate);
+	ad1889_writew(chip, AD_DS_WAS, rt->rate);
 
-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_WAVCA, chip->wave.addr);
-	ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + (count % size));
-	ad1889_load_wave_count(chip, chip->wave.count);
+	/* Set up DMA */
+	ad1889_load_wave_buffer_address(chip, chip->wave.addr);
+	ad1889_load_wave_buffer_count(chip, size);
+	ad1889_load_wave_interrupt_count(chip, count);
 
 	/* writes flush */
 	ad1889_readw(chip, AD_DS_WSMC);
@@ -407,7 +414,7 @@ snd_ad1889_playback_prepare(snd_pcm_subs
 	
 	ad1889_debug("prepare playback: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr,
-			count, size, reg, chip->wave.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }
 
@@ -437,21 +444,15 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	spin_lock_irq(&chip->lock);
 	
 	chip->ramc.size = size;
-	chip->ramc.count = count;
 	chip->ramc.reg = reg;
-	chip->ramc.buf = 0;
-	chip->ramc.pos = 0;
-	chip->ramc.rate = rt->rate;
 	chip->ramc.addr = rt->dma_addr;
 
 	ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg);
 
-	/* Set up DMA: first chunk address in curr addr, next one in base addr.
-	   Base will be loaded into curr by the hardware upon interrupt
-	   (as we use LOOP). Count holds the size of the chunk. */
-	ad1889_writel(chip, AD_DMA_ADCCA, chip->ramc.addr);
-	ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + (count % size));
-	ad1889_load_adc_count(chip, chip->ramc.count);
+	/* Set up DMA */
+	ad1889_load_adc_buffer_address(chip, chip->ramc.addr);
+	ad1889_load_adc_buffer_count(chip, size);
+	ad1889_load_adc_interrupt_count(chip, count);
 
 	/* writes flush */
 	ad1889_readw(chip, AD_DS_RAMC);
@@ -460,7 +461,7 @@ snd_ad1889_capture_prepare(snd_pcm_subst
 	
 	ad1889_debug("prepare capture: addr = 0x%x, count = %u, "
 			"size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr,
-			count, size, reg, chip->ramc.rate);
+			count, size, reg, rt->rate);
 	return 0;
 }
 
@@ -607,7 +608,6 @@ snd_ad1889_interrupt(int irq, 
 		     struct pt_regs *regs)
 {
 	unsigned long st;
-	unsigned long next;
 	struct snd_ad1889 *chip = dev_id;
 
 	st = ad1889_readl(chip, AD_DMA_DISR);
@@ -623,82 +623,12 @@ snd_ad1889_interrupt(int irq, 
 	if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI))
 		ad1889_debug("Unexpected master or target abort interrupt!\n");
 
-	if (chip->pcm && (st & AD_DMA_DISR_WAVI) && chip->psubs) {
-		spin_lock(&chip->lock);
-
-		chip->stats.wav_intr++;
-
-		chip->wave.buf++;
-
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->wave.pos += chip->wave.count;
-		chip->wave.pos %= chip->wave.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->wave.pos + chip->wave.count;
-		next %= chip->wave.size;
-		
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_WAVBA, chip->wave.addr + next);
-		
-		ad1889_readl(chip, AD_DMA_WAVBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-
+	if ((st & AD_DMA_DISR_WAVI) && chip->psubs)
 		snd_pcm_period_elapsed(chip->psubs);
-#if 0
-		ad1889_debug("chip->wave.pos = %d, chip->wave.count = %d, "
-				"chip->wave.size = %d\n", chip->wave.pos,
-				chip->wave.count, chip->wave.size);
-		ad1889_debug("chip->wave.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->wave.addr, next, chip->wave.addr + next);
-#endif		
-	}
-
-	if (chip->pcm && (st & AD_DMA_DISR_ADCI) && chip->csubs) {
-		spin_lock(&chip->lock);
-		
-		chip->stats.adc_intr++;
-
-		chip->ramc.buf++;
-		
-		/* calculate the current position: we get interrupts everytime
-		   the buffer empties, thus every wave.count bytes transfered */
-		chip->ramc.pos += chip->ramc.count;
-		chip->ramc.pos %= chip->ramc.size;
-
-		/* the next buffer will thus be current position + wave.count
-		   bytes away */
-		next = chip->ramc.pos + chip->ramc.count;
-		next %= chip->ramc.size;
-
-		/* Load new DMA parameters (aka "the next chunk" in Base
-		   registers: upon next interrupt, they'll be automatically
-		   loaded in the Current registers, and we'll end up here
-		   preparing the new ones. Since "count" never gets modified
-		   elsewhere than in _prepare, we don't need to rewrite it. */
-		ad1889_writel(chip, AD_DMA_ADCBA, chip->ramc.addr + next);
-		
-		ad1889_readl(chip, AD_DMA_ADCBA); /* flush all those writes */
-
-		spin_unlock(&chip->lock);
-		
+	if ((st & AD_DMA_DISR_ADCI) && chip->csubs)
 		snd_pcm_period_elapsed(chip->csubs);
-#if 0
-		ad1889_debug("chip->ramc.pos = %d, chip->ramc.count = %d, "
-				"chip->ramc.size = %d\n", chip->ramc.pos,
-				chip->ramc.count, chip->ramc.size);
-		ad1889_debug("chip->ramc.addr (0x%lx) + next (0x%lx) = 0x%lx\n",
-				chip->ramc.addr, next, chip->ramc.addr + next);
-#endif		
-	}
 
+	ad1889_readl(chip, AD_DMA_DISR); /* flush */
 	/* XXX under some circumstances the DISR write flush may not happen */
 
 	return IRQ_HANDLED;
@@ -741,7 +671,8 @@ snd_ad1889_pcm_init(struct snd_ad1889 *c
 
 	err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 						snd_dma_pci_data(chip->pci),
-						DMA_SIZE, DMA_SIZE);
+						BUFFER_BYTES_MAX / 2,
+						BUFFER_BYTES_MAX);
 
 	if (err < 0) {
 		snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err);

[-- Attachment #3: Type: text/plain, Size: 169 bytes --]

_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-18 15:35       ` [parisc-linux] " Clemens Ladisch
@ 2005-08-18 17:12         ` Lee Revell
  2005-08-18 17:12         ` [parisc-linux] [Alsa-devel] " Lee Revell
                           ` (3 subsequent siblings)
  4 siblings, 0 replies; 35+ messages in thread
From: Lee Revell @ 2005-08-18 17:12 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: Thibaut VARENE, alsa-devel, parisc-linux, kyle

On Thu, 2005-08-18 at 17:35 +0200, Clemens Ladisch wrote:
> > > +/* keep track of some hw registers */
> > >  struct ad1889_register_state {
> > >     u16 reg;        /* reg setup */
> > >     u32 addr;       /* dma base address */
> > > -   u16 rate;       /* sample rate */
> > > -   unsigned long pos;      /* last recorded DMA buffer position
> */
> > > -   unsigned long buf;      /* period # */
> > >     unsigned long size;     /* DMA buffer size */
> > > -   unsigned long count;    /* period size, aka nb bytes sent in
> the current DMA transfer */
> >
> > reading the patch through webmail doesn't help a lot getting a grasp
> > of its whole but i wonder if we could still find some debugging
> > purposes for these values. Remember this driver is work in
> progress ;)
> 
> Those fields just aren't used anymore; anything interesting is in the
> chip's registers. 

Isn't it still useful to maintain a cached copy of the register state
for suspend/resume purposes?

Lee



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-18 15:35       ` [parisc-linux] " Clemens Ladisch
  2005-08-18 17:12         ` Lee Revell
@ 2005-08-18 17:12         ` Lee Revell
  2005-08-19 17:46         ` Grant Grundler
                           ` (2 subsequent siblings)
  4 siblings, 0 replies; 35+ messages in thread
From: Lee Revell @ 2005-08-18 17:12 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: kyle, alsa-devel, parisc-linux, Thibaut VARENE

On Thu, 2005-08-18 at 17:35 +0200, Clemens Ladisch wrote:
> > > +/* keep track of some hw registers */
> > >  struct ad1889_register_state {
> > >     u16 reg;        /* reg setup */
> > >     u32 addr;       /* dma base address */
> > > -   u16 rate;       /* sample rate */
> > > -   unsigned long pos;      /* last recorded DMA buffer position
> */
> > > -   unsigned long buf;      /* period # */
> > >     unsigned long size;     /* DMA buffer size */
> > > -   unsigned long count;    /* period size, aka nb bytes sent in
> the current DMA transfer */
> >
> > reading the patch through webmail doesn't help a lot getting a grasp
> > of its whole but i wonder if we could still find some debugging
> > purposes for these values. Remember this driver is work in
> progress ;)
> 
> Those fields just aren't used anymore; anything interesting is in the
> chip's registers. 

Isn't it still useful to maintain a cached copy of the register state
for suspend/resume purposes?

Lee

_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-18 15:35       ` [parisc-linux] " Clemens Ladisch
                           ` (2 preceding siblings ...)
  2005-08-19 17:46         ` Grant Grundler
@ 2005-08-19 17:46         ` Grant Grundler
  2005-08-19 17:53           ` Takashi Iwai
  2005-08-28 12:57         ` [parisc-linux] " Thibaut VARENE
  4 siblings, 1 reply; 35+ messages in thread
From: Grant Grundler @ 2005-08-19 17:46 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: Thibaut VARENE, alsa-devel, parisc-linux, kyle

On Thu, Aug 18, 2005 at 05:35:20PM +0200, Clemens Ladisch wrote:
...
> > reading the patch through webmail doesn't help a lot getting a grasp
> > of its whole but i wonder if we could still find some debugging
> > purposes for these values. Remember this driver is work in progress ;)
> 
> Those fields just aren't used anymore; anything interesting is in the
> chip's registers.

Clemens,
You don't want to be reading chip registers all the time.
It's *very* expensive. Cache any values that don't change
in a local struct if they get referenced regularly.

You might find the mmio_test results interesting.
It would be great if you could add one or two audio devices
to mmio_test program here:
	svn co http://svn.gnumonks.org/trunk/mmio_test/

Please send a patch to Harald Welte <laforge@gnumonks.org>.

thanks,
grant


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-18 15:35       ` [parisc-linux] " Clemens Ladisch
  2005-08-18 17:12         ` Lee Revell
  2005-08-18 17:12         ` [parisc-linux] [Alsa-devel] " Lee Revell
@ 2005-08-19 17:46         ` Grant Grundler
  2005-08-19 17:46         ` [parisc-linux] " Grant Grundler
  2005-08-28 12:57         ` [parisc-linux] " Thibaut VARENE
  4 siblings, 0 replies; 35+ messages in thread
From: Grant Grundler @ 2005-08-19 17:46 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: kyle, alsa-devel, parisc-linux, Thibaut VARENE

On Thu, Aug 18, 2005 at 05:35:20PM +0200, Clemens Ladisch wrote:
...
> > reading the patch through webmail doesn't help a lot getting a grasp
> > of its whole but i wonder if we could still find some debugging
> > purposes for these values. Remember this driver is work in progress ;)
> 
> Those fields just aren't used anymore; anything interesting is in the
> chip's registers.

Clemens,
You don't want to be reading chip registers all the time.
It's *very* expensive. Cache any values that don't change
in a local struct if they get referenced regularly.

You might find the mmio_test results interesting.
It would be great if you could add one or two audio devices
to mmio_test program here:
	svn co http://svn.gnumonks.org/trunk/mmio_test/

Please send a patch to Harald Welte <laforge@gnumonks.org>.

thanks,
grant
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-19 17:46         ` [parisc-linux] " Grant Grundler
@ 2005-08-19 17:53           ` Takashi Iwai
  2005-08-20  1:36             ` Grant Grundler
  0 siblings, 1 reply; 35+ messages in thread
From: Takashi Iwai @ 2005-08-19 17:53 UTC (permalink / raw)
  To: Grant Grundler
  Cc: Clemens Ladisch, Thibaut VARENE, alsa-devel, parisc-linux, kyle

At Fri, 19 Aug 2005 11:46:55 -0600,
Grant Grundler wrote:
> 
> On Thu, Aug 18, 2005 at 05:35:20PM +0200, Clemens Ladisch wrote:
> ...
> > > reading the patch through webmail doesn't help a lot getting a grasp
> > > of its whole but i wonder if we could still find some debugging
> > > purposes for these values. Remember this driver is work in progress ;)
> > 
> > Those fields just aren't used anymore; anything interesting is in the
> > chip's registers.
> 
> Clemens,
> You don't want to be reading chip registers all the time.
> It's *very* expensive. Cache any values that don't change
> in a local struct if they get referenced regularly.

Check his patch carefully.  It doesn't add any extra accesses (except
for one readl to flush in irq handler - I guess it was added to be
sure?).  The original driver didn't use these fields effectively at
all, too.


Takashi


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-19 17:53           ` Takashi Iwai
@ 2005-08-20  1:36             ` Grant Grundler
  2005-08-22 11:03               ` Takashi Iwai
  0 siblings, 1 reply; 35+ messages in thread
From: Grant Grundler @ 2005-08-20  1:36 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Clemens Ladisch, Thibaut VARENE, alsa-devel, parisc-linux, kyle

On Fri, Aug 19, 2005 at 07:53:22PM +0200, Takashi Iwai wrote:
> Check his patch carefully.  It doesn't add any extra accesses (except
> for one readl to flush in irq handler - I guess it was added to be
> sure?).  The original driver didn't use these fields effectively at
> all, too.

Sorry - I didn't look at patch at all.
If the fields were never used, removing them is fine.
If they *could* have been used, then removing them is a bad idea.

In general, referencing parameters in IO device registers is NOT
a good substitute for caching the values "locally" in host mem.

hth,
grant


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-20  1:36             ` Grant Grundler
@ 2005-08-22 11:03               ` Takashi Iwai
  2005-08-23  0:13                 ` Grant Grundler
  2005-08-23  0:13                 ` [parisc-linux] [Alsa-devel] " Grant Grundler
  0 siblings, 2 replies; 35+ messages in thread
From: Takashi Iwai @ 2005-08-22 11:03 UTC (permalink / raw)
  To: Grant Grundler
  Cc: Clemens Ladisch, Thibaut VARENE, alsa-devel, parisc-linux, kyle

At Fri, 19 Aug 2005 19:36:55 -0600,
Grant Grundler wrote:
> 
> On Fri, Aug 19, 2005 at 07:53:22PM +0200, Takashi Iwai wrote:
> > Check his patch carefully.  It doesn't add any extra accesses (except
> > for one readl to flush in irq handler - I guess it was added to be
> > sure?).  The original driver didn't use these fields effectively at
> > all, too.
> 
> Sorry - I didn't look at patch at all.
> If the fields were never used, removing them is fine.
> If they *could* have been used, then removing them is a bad idea.

They won't be used/referred any more at all, so why do you need still
to keep them?

> In general, referencing parameters in IO device registers is NOT
> a good substitute for caching the values "locally" in host mem.

A cached value is not accurate, especially if you want to get a
precise position.  The position callback should return the accurate
position as much as possible since this can be used from the low
latency calculation like dmix.


Takashi


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-22 11:03               ` Takashi Iwai
@ 2005-08-23  0:13                 ` Grant Grundler
  2005-08-23  9:11                   ` [parisc-linux] [Alsa-devel] " Takashi Iwai
  2005-08-23  9:11                   ` [parisc-linux] " Takashi Iwai
  2005-08-23  0:13                 ` [parisc-linux] [Alsa-devel] " Grant Grundler
  1 sibling, 2 replies; 35+ messages in thread
From: Grant Grundler @ 2005-08-23  0:13 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Grant Grundler, Clemens Ladisch, Thibaut VARENE, alsa-devel,
	parisc-linux, kyle

On Mon, Aug 22, 2005 at 01:03:34PM +0200, Takashi Iwai wrote:
> At Fri, 19 Aug 2005 19:36:55 -0600,
> Grant Grundler wrote:
> > 
> > On Fri, Aug 19, 2005 at 07:53:22PM +0200, Takashi Iwai wrote:
> > > Check his patch carefully.  It doesn't add any extra accesses (except
> > > for one readl to flush in irq handler - I guess it was added to be
> > > sure?).  The original driver didn't use these fields effectively at
> > > all, too.
> > 
> > Sorry - I didn't look at patch at all.
> > If the fields were never used, removing them is fine.
> > If they *could* have been used, then removing them is a bad idea.
> 
> They won't be used/referred any more at all, so why do you need still
> to keep them?

I don't - removing them is fine.

> > In general, referencing parameters in IO device registers is NOT
> > a good substitute for caching the values "locally" in host mem.
> 
> A cached value is not accurate, especially if you want to get a
> precise position.

Caching is only possible if the register is "constant" for
the duration of it's use. e.g. offset or "count down" registers
can't be cached.


>   The position callback should return the accurate
> position as much as possible since this can be used from the low
> latency calculation like dmix.

ok - no problem. That's reasonable.

grant


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-22 11:03               ` Takashi Iwai
  2005-08-23  0:13                 ` Grant Grundler
@ 2005-08-23  0:13                 ` Grant Grundler
  1 sibling, 0 replies; 35+ messages in thread
From: Grant Grundler @ 2005-08-23  0:13 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Clemens Ladisch, kyle, Thibaut VARENE, alsa-devel, parisc-linux

On Mon, Aug 22, 2005 at 01:03:34PM +0200, Takashi Iwai wrote:
> At Fri, 19 Aug 2005 19:36:55 -0600,
> Grant Grundler wrote:
> > 
> > On Fri, Aug 19, 2005 at 07:53:22PM +0200, Takashi Iwai wrote:
> > > Check his patch carefully.  It doesn't add any extra accesses (except
> > > for one readl to flush in irq handler - I guess it was added to be
> > > sure?).  The original driver didn't use these fields effectively at
> > > all, too.
> > 
> > Sorry - I didn't look at patch at all.
> > If the fields were never used, removing them is fine.
> > If they *could* have been used, then removing them is a bad idea.
> 
> They won't be used/referred any more at all, so why do you need still
> to keep them?

I don't - removing them is fine.

> > In general, referencing parameters in IO device registers is NOT
> > a good substitute for caching the values "locally" in host mem.
> 
> A cached value is not accurate, especially if you want to get a
> precise position.

Caching is only possible if the register is "constant" for
the duration of it's use. e.g. offset or "count down" registers
can't be cached.


>   The position callback should return the accurate
> position as much as possible since this can be used from the low
> latency calculation like dmix.

ok - no problem. That's reasonable.

grant
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-23  0:13                 ` Grant Grundler
  2005-08-23  9:11                   ` [parisc-linux] [Alsa-devel] " Takashi Iwai
@ 2005-08-23  9:11                   ` Takashi Iwai
  1 sibling, 0 replies; 35+ messages in thread
From: Takashi Iwai @ 2005-08-23  9:11 UTC (permalink / raw)
  To: Grant Grundler
  Cc: Clemens Ladisch, Thibaut VARENE, alsa-devel, parisc-linux, kyle

At Mon, 22 Aug 2005 18:13:25 -0600,
Grant Grundler wrote:
> 
> On Mon, Aug 22, 2005 at 01:03:34PM +0200, Takashi Iwai wrote:
> > At Fri, 19 Aug 2005 19:36:55 -0600,
> > Grant Grundler wrote:
> > > 
> > > On Fri, Aug 19, 2005 at 07:53:22PM +0200, Takashi Iwai wrote:
> > > > Check his patch carefully.  It doesn't add any extra accesses (except
> > > > for one readl to flush in irq handler - I guess it was added to be
> > > > sure?).  The original driver didn't use these fields effectively at
> > > > all, too.
> > > 
> > > Sorry - I didn't look at patch at all.
> > > If the fields were never used, removing them is fine.
> > > If they *could* have been used, then removing them is a bad idea.
> > 
> > They won't be used/referred any more at all, so why do you need still
> > to keep them?
> 
> I don't - removing them is fine.
> 
> > > In general, referencing parameters in IO device registers is NOT
> > > a good substitute for caching the values "locally" in host mem.
> > 
> > A cached value is not accurate, especially if you want to get a
> > precise position.
> 
> Caching is only possible if the register is "constant" for
> the duration of it's use. e.g. offset or "count down" registers
> can't be cached.
> 
> 
> >   The position callback should return the accurate
> > position as much as possible since this can be used from the low
> > latency calculation like dmix.
> 
> ok - no problem. That's reasonable.

Glad to hear we agree :)

BTW, did anyone test Clemens' patch on the real machine?
If it works fine on 2.6, I'd like to push the driver to alsa-kernel
(eventually linux kernel) tree.


Takashi


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-23  0:13                 ` Grant Grundler
@ 2005-08-23  9:11                   ` Takashi Iwai
  2005-08-23  9:11                   ` [parisc-linux] " Takashi Iwai
  1 sibling, 0 replies; 35+ messages in thread
From: Takashi Iwai @ 2005-08-23  9:11 UTC (permalink / raw)
  To: Grant Grundler
  Cc: alsa-devel, kyle, Clemens Ladisch, parisc-linux, Thibaut VARENE

At Mon, 22 Aug 2005 18:13:25 -0600,
Grant Grundler wrote:
> 
> On Mon, Aug 22, 2005 at 01:03:34PM +0200, Takashi Iwai wrote:
> > At Fri, 19 Aug 2005 19:36:55 -0600,
> > Grant Grundler wrote:
> > > 
> > > On Fri, Aug 19, 2005 at 07:53:22PM +0200, Takashi Iwai wrote:
> > > > Check his patch carefully.  It doesn't add any extra accesses (except
> > > > for one readl to flush in irq handler - I guess it was added to be
> > > > sure?).  The original driver didn't use these fields effectively at
> > > > all, too.
> > > 
> > > Sorry - I didn't look at patch at all.
> > > If the fields were never used, removing them is fine.
> > > If they *could* have been used, then removing them is a bad idea.
> > 
> > They won't be used/referred any more at all, so why do you need still
> > to keep them?
> 
> I don't - removing them is fine.
> 
> > > In general, referencing parameters in IO device registers is NOT
> > > a good substitute for caching the values "locally" in host mem.
> > 
> > A cached value is not accurate, especially if you want to get a
> > precise position.
> 
> Caching is only possible if the register is "constant" for
> the duration of it's use. e.g. offset or "count down" registers
> can't be cached.
> 
> 
> >   The position callback should return the accurate
> > position as much as possible since this can be used from the low
> > latency calculation like dmix.
> 
> ok - no problem. That's reasonable.

Glad to hear we agree :)

BTW, did anyone test Clemens' patch on the real machine?
If it works fine on 2.6, I'd like to push the driver to alsa-kernel
(eventually linux kernel) tree.


Takashi
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-18 15:35       ` [parisc-linux] " Clemens Ladisch
                           ` (3 preceding siblings ...)
  2005-08-19 17:46         ` [parisc-linux] " Grant Grundler
@ 2005-08-28 12:57         ` Thibaut VARENE
  2005-08-31  2:26           ` Kyle McMartin
  2005-08-31  2:26           ` [parisc-linux] [Alsa-devel] " Kyle McMartin
  4 siblings, 2 replies; 35+ messages in thread
From: Thibaut VARENE @ 2005-08-28 12:57 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel, parisc-linux, kyle

On Thu, 18 Aug 2005 17:35:20 +0200 (METDST)
Clemens Ladisch <clemens@ladisch.de> wrote:

> Thibaut VARENE wrote:
> > > -/* "<ggg> T-Bone: parisc IOMMU can start DMA at any address.
> > > -   But the IOMMU can only map at page size granularity."
> > > -   This affects in particular .period_bytes_min */
> > > -#define BUF_SIZE        PAGE_SIZE
> > > -#define MAX_BUFS        32
> > > -#define DMA_SIZE	(MAX_BUFS*BUF_SIZE)
> >
> > don't remove these defines please, i'd rather have every constants
> > defined in the header file.
> 
> I removed them because it wouldn't make sense to derive the buffer
> size from the period size in the patched driver.  I used some more or
> less random values because these values aren't anymore restricted by
> the chip's constraints.
> 
> > Besides, the comment is very relevant to PA-RISC architecture,
> > where no matter what the value is, the minimum allocated space
> > will always be at page size granularity.
> 
> Most IOMMUs have this restriction.  ALSA's PCM buffer is always page
> aligned, so drivers that do DMA over the entire buffer just don't
> care.

ok fine then.

> 
> Attached is a new patch with symbols for buffer size etc.

Tested and it works fine, as far as i can tell. I can't see any other
objection against it being merged in our tree and in the patch i sent
upstream ;) As far as I'm concerned, the driver is now ok to be included
in mainline.

kyle: if it's fine for you too, please let us know and commit this patch
to the parisc tree, i'll be offline for yet another bunch of days alas :P

HTH

Thibaut VARENE
The PA/Linux Team
http://www.pateam.org/


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-28 12:57         ` [parisc-linux] " Thibaut VARENE
@ 2005-08-31  2:26           ` Kyle McMartin
  2005-08-31  2:26           ` [parisc-linux] [Alsa-devel] " Kyle McMartin
  1 sibling, 0 replies; 35+ messages in thread
From: Kyle McMartin @ 2005-08-31  2:26 UTC (permalink / raw)
  To: Thibaut VARENE; +Cc: Clemens Ladisch, alsa-devel, parisc-linux, kyle

On Sun, Aug 28, 2005 at 02:57:11PM +0200, Thibaut VARENE wrote:
> kyle: if it's fine for you too, please let us know and commit this patch
> to the parisc tree, i'll be offline for yet another bunch of days alas :P
>

ACK. Will commit tonight. 


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [parisc-linux] [Alsa-devel] [PATCH] Support for AD1889 PCI Soundchip
  2005-08-28 12:57         ` [parisc-linux] " Thibaut VARENE
  2005-08-31  2:26           ` Kyle McMartin
@ 2005-08-31  2:26           ` Kyle McMartin
  1 sibling, 0 replies; 35+ messages in thread
From: Kyle McMartin @ 2005-08-31  2:26 UTC (permalink / raw)
  To: Thibaut VARENE; +Cc: alsa-devel, Clemens Ladisch, parisc-linux, kyle

On Sun, Aug 28, 2005 at 02:57:11PM +0200, Thibaut VARENE wrote:
> kyle: if it's fine for you too, please let us know and commit this patch
> to the parisc tree, i'll be offline for yet another bunch of days alas :P
>

ACK. Will commit tonight. 
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2005-08-31  2:26 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-07-29 19:16 [PATCH] Support for AD1889 PCI Soundchip Thibaut VARENE
2005-07-29 19:20 ` [parisc-linux] " Thibaut VARENE
2005-07-29 19:20 ` Thibaut VARENE
2005-08-03 13:46 ` Takashi Iwai
2005-08-04 13:30 ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
2005-08-04 13:30 ` [parisc-linux] " Clemens Ladisch
2005-08-11 15:18   ` Clemens Ladisch
2005-08-12  2:14     ` [parisc-linux] [Alsa-devel] " Kyle McMartin
2005-08-12  2:14     ` [parisc-linux] " Kyle McMartin
2005-08-12  7:17       ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
2005-08-12  7:17       ` [parisc-linux] " Clemens Ladisch
2005-08-17  1:51         ` [parisc-linux] [Alsa-devel] " Kyle McMartin
2005-08-17  1:51         ` [parisc-linux] " Kyle McMartin
2005-08-17 13:50           ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
2005-08-17 13:50           ` [parisc-linux] " Clemens Ladisch
2005-08-17  9:10     ` Thibaut VARENE
2005-08-18 15:35       ` [parisc-linux] [Alsa-devel] " Clemens Ladisch
2005-08-18 15:35       ` [parisc-linux] " Clemens Ladisch
2005-08-18 17:12         ` Lee Revell
2005-08-18 17:12         ` [parisc-linux] [Alsa-devel] " Lee Revell
2005-08-19 17:46         ` Grant Grundler
2005-08-19 17:46         ` [parisc-linux] " Grant Grundler
2005-08-19 17:53           ` Takashi Iwai
2005-08-20  1:36             ` Grant Grundler
2005-08-22 11:03               ` Takashi Iwai
2005-08-23  0:13                 ` Grant Grundler
2005-08-23  9:11                   ` [parisc-linux] [Alsa-devel] " Takashi Iwai
2005-08-23  9:11                   ` [parisc-linux] " Takashi Iwai
2005-08-23  0:13                 ` [parisc-linux] [Alsa-devel] " Grant Grundler
2005-08-28 12:57         ` [parisc-linux] " Thibaut VARENE
2005-08-31  2:26           ` Kyle McMartin
2005-08-31  2:26           ` [parisc-linux] [Alsa-devel] " Kyle McMartin
2005-08-17  9:10     ` Thibaut VARENE
2005-08-11 15:18   ` Clemens Ladisch
  -- strict thread matches above, loose matches on Subject: below --
2005-07-29 19:16 [parisc-linux] " Thibaut VARENE

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.