linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ALSA update [6/10] - 2002/07/20
@ 2002-09-29 18:51 Jaroslav Kysela
  2002-09-29 19:12 ` Arjan van de Ven
  0 siblings, 1 reply; 11+ messages in thread
From: Jaroslav Kysela @ 2002-09-29 18:51 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: LKML

You can import this changeset into BK by piping this whole message to:
'| bk receive [path to repository]' or apply the patch as usual.

===================================================================


ChangeSet@1.605.2.17, 2002-09-25 17:57:54+02:00, perex@pnote.perex-int.cz
  ALSA update 2002/07/20 :
    - added vfree_nocheck()
    - PCM midlevel & EMU10K1 - added support for SG buffer
    - CS4236 - added new ISA PnP ID
    - HDSP - fixed rate rules (OSS emulation works)


 include/sound/core.h       |    2 
 include/sound/emu10k1.h    |    3 
 include/sound/pcm.h        |    4 
 include/sound/pcm_sgbuf.h  |   60 +++++++
 include/sound/sndmagic.h   |    1 
 include/sound/version.h    |    2 
 sound/core/Makefile        |    5 
 sound/core/control.c       |    1 
 sound/core/pcm_lib.c       |   21 ++
 sound/core/pcm_native.c    |    9 -
 sound/core/pcm_sgbuf.c     |  321 +++++++++++++++++++++++++++++++++++++++
 sound/core/rtctimer.c      |    1 
 sound/core/sound.c         |    2 
 sound/isa/cs423x/cs4236.c  |    2 
 sound/pci/Config.help      |    4 
 sound/pci/Config.in        |    2 
 sound/pci/emu10k1/emupcm.c |   18 +-
 sound/pci/emu10k1/memory.c |   20 +-
 sound/pci/rme9652/hdsp.c   |   20 --
 sound/pci/via686.c         |  366 +++++++++++++++++++--------------------------
 20 files changed, 621 insertions(+), 243 deletions(-)


diff -Nru a/include/sound/core.h b/include/sound/core.h
--- a/include/sound/core.h	Sun Sep 29 20:21:38 2002
+++ b/include/sound/core.h	Sun Sep 29 20:21:38 2002
@@ -243,8 +243,10 @@
 #define kfree_nocheck(obj) snd_wrapper_kfree(obj)
 #define vmalloc(size) snd_hidden_vmalloc(size)
 #define vfree(obj) snd_hidden_vfree(obj)
+#define vfree_nocheck(obj) snd_wrapper_vfree(obj)
 #else
 #define kfree_nocheck(obj) kfree(obj)
+#define vfree_nocheck(obj) vfree(obj)
 #endif
 void *snd_kcalloc(size_t size, int flags);
 char *snd_kmalloc_strdup(const char *string, int flags);
diff -Nru a/include/sound/emu10k1.h b/include/sound/emu10k1.h
--- a/include/sound/emu10k1.h	Sun Sep 29 20:21:38 2002
+++ b/include/sound/emu10k1.h	Sun Sep 29 20:21:38 2002
@@ -26,6 +26,7 @@
 #ifdef __KERNEL__
 
 #include "pcm.h"
+#include "pcm_sgbuf.h"
 #include "rawmidi.h"
 #include "hwdep.h"
 #include "ac97_codec.h"
@@ -1043,7 +1044,7 @@
 unsigned char snd_emu10k1_sum_vol_attn(unsigned int value);
 
 /* memory allocation */
-snd_util_memblk_t *snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size);
+snd_util_memblk_t *snd_emu10k1_alloc_pages(emu10k1_t *emu, struct snd_sg_buf *sgbuf);
 int snd_emu10k1_free_pages(emu10k1_t *emu, snd_util_memblk_t *blk);
 snd_util_memblk_t *snd_emu10k1_synth_alloc(emu10k1_t *emu, unsigned int size);
 int snd_emu10k1_synth_free(emu10k1_t *emu, snd_util_memblk_t *blk);
diff -Nru a/include/sound/pcm.h b/include/sound/pcm.h
--- a/include/sound/pcm.h	Sun Sep 29 20:21:38 2002
+++ b/include/sound/pcm.h	Sun Sep 29 20:21:38 2002
@@ -96,6 +96,7 @@
 		    void *buf, snd_pcm_uframes_t count);
 	int (*silence)(snd_pcm_substream_t *substream, int channel, 
 		       snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
+	void *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
 } snd_pcm_ops_t;
 
 /*
@@ -771,6 +772,9 @@
 			       unsigned int cond,
 			       snd_pcm_hw_param_t var,
 			       unsigned long step);
+int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
+			       unsigned int cond,
+			       snd_pcm_hw_param_t var);
 int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime,
 			unsigned int cond,
 			int var,
diff -Nru a/include/sound/pcm_sgbuf.h b/include/sound/pcm_sgbuf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/sound/pcm_sgbuf.h	Sun Sep 29 20:21:38 2002
@@ -0,0 +1,60 @@
+#ifndef __SOUND_PCM_SGBUF_H
+#define __SOUND_PCM_SGBUF_H
+
+/*
+ * Scatter-Gather PCM access
+ *
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+struct snd_sg_page {
+	void *buf;
+	dma_addr_t addr;
+};
+
+struct snd_sg_buf {
+	int size;	/* allocated byte size (= runtime->dma_bytes) */
+	int pages;	/* allocated pages */
+	int tblsize;	/* allocated table size */
+	struct snd_sg_page *table;
+	struct pci_dev *pci;
+};
+
+typedef struct snd_sg_buf snd_pcm_sgbuf_t; /* for magic cast */
+
+/*
+ * return the pages matching with the given byte size
+ */
+static inline unsigned int snd_pcm_sgbuf_pages(size_t size)
+{
+	return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
+
+int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize);
+int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream);
+int snd_pcm_sgbuf_alloc(snd_pcm_substream_t *substream, size_t size);
+int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream);
+
+int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
+int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
+int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count);
+void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
+
+
+#endif /* __SOUND_PCM_SGBUF_H */
diff -Nru a/include/sound/sndmagic.h b/include/sound/sndmagic.h
--- a/include/sound/sndmagic.h	Sun Sep 29 20:21:38 2002
+++ b/include/sound/sndmagic.h	Sun Sep 29 20:21:38 2002
@@ -61,6 +61,7 @@
 #define snd_pcm_proc_private_t_magic		0xa15a0104
 #define snd_pcm_oss_file_t_magic		0xa15a0105
 #define snd_mixer_oss_t_magic			0xa15a0106
+#define snd_pcm_sgbuf_t_magic			0xa15a0107
 
 #define snd_info_private_data_t_magic		0xa15a0201
 #define snd_ctl_file_t_magic			0xa15a0301
diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h	Sun Sep 29 20:21:38 2002
+++ b/include/sound/version.h	Sun Sep 29 20:21:38 2002
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #define CONFIG_SND_VERSION "0.9.0rc2"
-#define CONFIG_SND_DATE " (Wed Jul 17 10:56:41 2002 UTC)"
+#define CONFIG_SND_DATE " (Sat Jul 20 07:16:41 2002 UTC)"
diff -Nru a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile	Sun Sep 29 20:21:38 2002
+++ b/sound/core/Makefile	Sun Sep 29 20:21:38 2002
@@ -3,7 +3,8 @@
 # Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-export-objs  := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o
+export-objs  := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o \
+                pcm_sgbuf.o
 
 snd-objs     := sound.o init.o isadma.o memory.o info.o control.o misc.o \
                 device.o wrappers.o
@@ -12,7 +13,7 @@
 endif
 
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
-		pcm_memory.o
+		pcm_memory.o pcm_sgbuf.o
 
 snd-rawmidi-objs  := rawmidi.o
 snd-timer-objs    := timer.o
diff -Nru a/sound/core/control.c b/sound/core/control.c
--- a/sound/core/control.c	Sun Sep 29 20:21:38 2002
+++ b/sound/core/control.c	Sun Sep 29 20:21:38 2002
@@ -21,6 +21,7 @@
 
 #define __NO_VERSION__
 #include <sound/driver.h>
+#include <linux/threads.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
diff -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
--- a/sound/core/pcm_lib.c	Sun Sep 29 20:21:38 2002
+++ b/sound/core/pcm_lib.c	Sun Sep 29 20:21:38 2002
@@ -960,6 +960,26 @@
 				   var, -1);
 }
 
+static int snd_pcm_hw_rule_pow2(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule)
+{
+	static int pow2_sizes[] = {
+		1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
+		1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
+		1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
+		1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30
+	};
+	return snd_interval_list(hw_param_interval(params, rule->var),
+				 sizeof(pow2_sizes)/sizeof(int), pow2_sizes, 0);
+}		
+
+int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
+			       unsigned int cond,
+			       snd_pcm_hw_param_t var)
+{
+	return snd_pcm_hw_rule_add(runtime, cond, var, 
+				   snd_pcm_hw_rule_pow2, NULL,
+				   var, -1);
+}
 
 /* To use the same code we have in alsa-lib */
 #define snd_pcm_t snd_pcm_substream_t
@@ -2364,6 +2384,7 @@
 EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
 EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
 EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
+EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
 EXPORT_SYMBOL(snd_pcm_hw_rule_add);
 EXPORT_SYMBOL(snd_pcm_set_ops);
 EXPORT_SYMBOL(snd_pcm_set_sync);
diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c
--- a/sound/core/pcm_native.c	Sun Sep 29 20:21:38 2002
+++ b/sound/core/pcm_native.c	Sun Sep 29 20:21:38 2002
@@ -2631,6 +2631,7 @@
 	snd_pcm_runtime_t *runtime;
 	unsigned long offset;
 	struct page * page;
+	void *vaddr;
 	size_t dma_bytes;
 	
 	if (substream == NULL)
@@ -2646,7 +2647,13 @@
 	dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
 	if (offset > dma_bytes - PAGE_SIZE)
 		return NOPAGE_SIGBUS;
-	page = virt_to_page(runtime->dma_area + offset);
+	if (substream->ops->page) {
+		vaddr = substream->ops->page(substream, offset);
+		if (! vaddr)
+			return NOPAGE_OOM;
+	} else
+		vaddr = runtime->dma_area + offset;
+	page = virt_to_page(vaddr);
 	get_page(page);
 #ifndef LINUX_2_2
 	return page;
diff -Nru a/sound/core/pcm_sgbuf.c b/sound/core/pcm_sgbuf.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/core/pcm_sgbuf.c	Sun Sep 29 20:21:38 2002
@@ -0,0 +1,321 @@
+/*
+ * Scatter-Gather PCM access
+ *
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_sgbuf.h>
+
+
+/* table entries are align to 32 */
+#define SGBUF_TBL_ALIGN		32
+#define sgbuf_align_table(tbl)	((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
+
+/*
+ * shrink to the given pages.
+ * free the unused pages
+ */
+static void sgbuf_shrink(struct snd_sg_buf *sgbuf, int pages)
+{
+	snd_assert(sgbuf, return);
+	if (! sgbuf->table)
+		return;
+	while (sgbuf->pages > pages) {
+		sgbuf->pages--;
+		snd_free_pci_pages(sgbuf->pci, PAGE_SIZE,
+				   sgbuf->table[sgbuf->pages].buf,
+				   sgbuf->table[sgbuf->pages].addr);
+	}
+}
+
+/*
+ * initialize the sg buffer
+ * assigned to substream->dma_private.
+ * initialize the table with the given size.
+ */
+int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize)
+{
+	struct snd_sg_buf *sgbuf;
+
+	tblsize = sgbuf_align_table(tblsize);
+	sgbuf = snd_magic_kcalloc(snd_pcm_sgbuf_t, 0, GFP_KERNEL);
+	if (! sgbuf)
+		return -ENOMEM;
+	substream->dma_private = sgbuf;
+	sgbuf->pci = pci;
+	sgbuf->pages = 0;
+	sgbuf->tblsize = tblsize;
+	sgbuf->table = kmalloc(sizeof(struct snd_sg_page) * tblsize, GFP_KERNEL);
+	if (! sgbuf->table) {
+		snd_pcm_sgbuf_free(substream);
+		return -ENOMEM;
+	}
+	memset(sgbuf->table, 0, sizeof(struct snd_sg_page) * tblsize);
+	return 0;
+}
+
+/*
+ * release all pages and free the sgbuf instance
+ */
+int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream)
+{
+	struct snd_sg_buf *sgbuf;
+
+	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+	sgbuf_shrink(sgbuf, 0);
+	if (sgbuf->table)
+		kfree(sgbuf->table);
+	snd_magic_kfree(sgbuf);
+	substream->dma_private = NULL;
+	return 0;
+}
+
+/*
+ * allocate sg buffer table with the given byte size.
+ * if the buffer table already exists, try to resize it.
+ * call this from hw_params callback.
+ */
+int snd_pcm_sgbuf_alloc(snd_pcm_substream_t *substream, size_t size)
+{
+	struct snd_sg_buf *sgbuf;
+	unsigned int pages;
+	unsigned int tblsize;
+	int changed = 0;
+
+	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+	pages = snd_pcm_sgbuf_pages(size);
+	tblsize = sgbuf_align_table(pages);
+	if (pages < sgbuf->pages) {
+		/* release unsed pages */
+		sgbuf_shrink(sgbuf, pages);
+		substream->runtime->dma_bytes = size;
+		return 1; /* changed */
+	} else if (pages > sgbuf->tblsize) {
+		/* bigger than existing one.  reallocate the table. */
+		struct snd_sg_page *table;
+		table = kmalloc(sizeof(*table) * tblsize, GFP_KERNEL);
+		if (! table)
+			return -ENOMEM;
+		memcpy(table, sgbuf->table, sizeof(*table) * sgbuf->tblsize);
+		kfree(sgbuf->table);
+		sgbuf->table = table;
+		sgbuf->tblsize = tblsize;
+	}
+	/* allocate each page */
+	while (sgbuf->pages < pages) {
+		void *ptr;
+		dma_addr_t addr;
+		ptr = snd_malloc_pci_pages(sgbuf->pci, PAGE_SIZE, &addr);
+		if (! ptr)
+			return -ENOMEM;
+		sgbuf->table[sgbuf->pages].buf = ptr;
+		sgbuf->table[sgbuf->pages].addr = addr;
+		sgbuf->pages++;
+		changed = 1;
+	}
+	sgbuf->size = size;
+	substream->runtime->dma_bytes = size;
+	return changed;
+}
+
+/*
+ * free the sg buffer
+ * the table is kept.
+ * call this from hw_free callback.
+ */
+int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream)
+{
+	struct snd_sg_buf *sgbuf;
+
+	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+	sgbuf_shrink(sgbuf, 0);
+	return 0;
+}
+
+/*
+ * get the page pointer on the given offset
+ * used as the page callback of pcm ops
+ */
+void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
+{
+	struct snd_sg_buf *sgbuf;
+	unsigned int idx;
+
+	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return NULL);
+	idx = offset >> PAGE_SHIFT;
+	if (idx >= sgbuf->pages)
+		return 0;
+	return sgbuf->table[idx].buf;
+}
+
+/*
+ * do copy_from_user to the sg buffer
+ */
+static int copy_from_user_sg_buf(snd_pcm_substream_t *substream,
+				 char *buf, size_t hwoff, ssize_t bytes)
+{
+	int len;
+	char *addr;
+	size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
+	hwoff -= p;
+	len = PAGE_SIZE - hwoff;
+	for (;;) {
+		addr = snd_pcm_sgbuf_ops_page(substream, p);
+		if (! addr)
+			return -EFAULT;
+		if (len > bytes)
+			len = bytes;
+		if (copy_from_user(addr + hwoff, buf, len))
+			return -EFAULT;
+		bytes -= len;
+		if (bytes <= 0)
+			break;
+		buf += len;
+		p += PAGE_SIZE;
+		len = PAGE_SIZE;
+		hwoff = 0;
+	}
+	return 0;
+}
+
+/*
+ * do copy_to_user from the sg buffer
+ */
+static int copy_to_user_sg_buf(snd_pcm_substream_t *substream,
+			       char *buf, size_t hwoff, ssize_t bytes)
+{
+	int len;
+	char *addr;
+	size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
+	hwoff -= p;
+	len = PAGE_SIZE - hwoff;
+	for (;;) {
+		addr = snd_pcm_sgbuf_ops_page(substream, p);
+		if (! addr)
+			return -EFAULT;
+		if (len > bytes)
+			len = bytes;
+		if (copy_to_user(buf, addr + hwoff, len))
+			return -EFAULT;
+		bytes -= len;
+		if (bytes <= 0)
+			break;
+		buf += len;
+		p += PAGE_SIZE;
+		len = PAGE_SIZE;
+		hwoff = 0;
+	}
+	return 0;
+}
+
+/*
+ * set silence on the sg buffer
+ */
+static int set_silence_sg_buf(snd_pcm_substream_t *substream,
+			      size_t hwoff, ssize_t samples)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int len, page_len;
+	char *addr;
+	size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
+	hwoff -= p;
+	len = bytes_to_samples(substream->runtime, PAGE_SIZE - hwoff);
+	page_len = bytes_to_samples(substream->runtime, PAGE_SIZE);
+	for (;;) {
+		addr = snd_pcm_sgbuf_ops_page(substream, p);
+		if (! addr)
+			return -EFAULT;
+		if (len > samples)
+			len = samples;
+		snd_pcm_format_set_silence(runtime->format, addr + hwoff, len);
+		samples -= len;
+		if (samples <= 0)
+			break;
+		p += PAGE_SIZE;
+		len = page_len;
+		hwoff = 0;
+	}
+	return 0;
+}
+
+/*
+ * copy callback for playback pcm ops
+ */
+int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel,
+				    snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	if (channel < 0) {
+		return copy_from_user_sg_buf(substream, buf, frames_to_bytes(runtime, hwoff), frames_to_bytes(runtime, count));
+	} else {
+		size_t dma_csize = runtime->dma_bytes / runtime->channels;
+		size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
+		return copy_from_user_sg_buf(substream, buf, c_ofs, samples_to_bytes(runtime, count));
+	}
+}
+
+/*
+ * copy callback for capture pcm ops
+ */
+int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel,
+				   snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	if (channel < 0) {
+		return copy_to_user_sg_buf(substream, buf, frames_to_bytes(runtime, hwoff), frames_to_bytes(runtime, count));
+	} else {
+		size_t dma_csize = runtime->dma_bytes / runtime->channels;
+		size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
+		return copy_to_user_sg_buf(substream, buf, c_ofs, samples_to_bytes(runtime, count));
+	}
+}
+
+/*
+ * silence callback for pcm ops
+ */
+int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel,
+			      snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	if (channel < 0) {
+		return set_silence_sg_buf(substream, frames_to_bytes(runtime, hwoff),
+					  frames_to_bytes(runtime, count));
+	} else {
+		size_t dma_csize = runtime->dma_bytes / runtime->channels;
+		size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
+		return set_silence_sg_buf(substream, c_ofs, samples_to_bytes(runtime, count));
+	}
+}
+
+
+/*
+ *  Exported symbols
+ */
+EXPORT_SYMBOL(snd_pcm_sgbuf_init);
+EXPORT_SYMBOL(snd_pcm_sgbuf_delete);
+EXPORT_SYMBOL(snd_pcm_sgbuf_alloc);
+EXPORT_SYMBOL(snd_pcm_sgbuf_free);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_copy_playback);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_copy_capture);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_silence);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
diff -Nru a/sound/core/rtctimer.c b/sound/core/rtctimer.c
--- a/sound/core/rtctimer.c	Sun Sep 29 20:21:38 2002
+++ b/sound/core/rtctimer.c	Sun Sep 29 20:21:38 2002
@@ -23,6 +23,7 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/time.h>
+#include <linux/threads.h>
 #include <linux/interrupt.h>
 #include <sound/core.h>
 #include <sound/timer.h>
diff -Nru a/sound/core/sound.c b/sound/core/sound.c
--- a/sound/core/sound.c	Sun Sep 29 20:21:38 2002
+++ b/sound/core/sound.c	Sun Sep 29 20:21:38 2002
@@ -501,6 +501,8 @@
 #ifdef CONFIG_SND_DEBUG_MEMORY
 EXPORT_SYMBOL(snd_wrapper_kmalloc);
 EXPORT_SYMBOL(snd_wrapper_kfree);
+EXPORT_SYMBOL(snd_wrapper_vmalloc);
+EXPORT_SYMBOL(snd_wrapper_vfree);
 #endif
 #ifdef HACK_PCI_ALLOC_CONSISTENT
 EXPORT_SYMBOL(snd_pci_hack_alloc_consistent);
diff -Nru a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
--- a/sound/isa/cs423x/cs4236.c	Sun Sep 29 20:21:38 2002
+++ b/sound/isa/cs423x/cs4236.c	Sun Sep 29 20:21:38 2002
@@ -227,6 +227,8 @@
 	ISAPNP_CS4232('C','S','C',0x4336,0x0000,0x0010,0x0003),
 	/* Typhoon Soundsystem PnP - CS4236B */
 	ISAPNP_CS4232('C','S','C',0x4536,0x0000,0x0010,0x0003),
+	/* Crystal CX4235-XQ3 EP - CS4235 */
+	ISAPNP_CS4232('C','S','C',0x4625,0x0100,0x0110,0x0103),
 	/* TerraTec AudioSystem EWS64XL - CS4236B */
 	ISAPNP_CS4232('C','S','C',0xa836,0xa800,0xa810,0xa803),
 	/* TerraTec AudioSystem EWS64XL - CS4236B */
diff -Nru a/sound/pci/Config.help b/sound/pci/Config.help
--- a/sound/pci/Config.help	Sun Sep 29 20:21:38 2002
+++ b/sound/pci/Config.help	Sun Sep 29 20:21:38 2002
@@ -7,6 +7,10 @@
 
 CONFIG_SND_CS46XX_ACCEPT_VALID
   Say 'Y' to allow sample resolution for mmap() transfers.
+  Note: This can be also specified via module option snd_mmap_valid.
+
+CONFIG_SND_CS4281
+  Say 'Y' or 'M' to include support for Cirrus Logic CS4281.
 
 CONFIG_SND_EMU10K1
   Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!,
diff -Nru a/sound/pci/Config.in b/sound/pci/Config.in
--- a/sound/pci/Config.in	Sun Sep 29 20:21:38 2002
+++ b/sound/pci/Config.in	Sun Sep 29 20:21:38 2002
@@ -8,7 +8,7 @@
 if [ "$CONFIG_SND_CS46XX" != "n" ]; then
   bool       '  Cirrus Logic (Sound Fusion) MMAP support for OSS' CONFIG_SND_CS46XX_ACCEPT_VALID
 fi
-dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND
+dep_tristate 'Cirrus Logic CS4281' CONFIG_SND_CS4281 $CONFIG_SND
 dep_tristate 'EMU10K1 (SB Live!, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND
 dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND
 dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND
diff -Nru a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
--- a/sound/pci/emu10k1/emupcm.c	Sun Sep 29 20:21:38 2002
+++ b/sound/pci/emu10k1/emupcm.c	Sun Sep 29 20:21:38 2002
@@ -32,6 +32,7 @@
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
+#include <sound/pcm_sgbuf.h>
 
 #define chip_t emu10k1_t
 
@@ -358,13 +359,13 @@
 
 	if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0)
 		return err;
-	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+	if ((err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params))) < 0)
 		return err;
 	if (err > 0) {	/* change */
 		snd_util_memblk_t *memblk;
 		if (epcm->memblk != NULL)
 			snd_emu10k1_free_pages(emu, epcm->memblk);
-		memblk = snd_emu10k1_alloc_pages(emu, runtime->dma_addr, runtime->dma_bytes);
+		memblk = snd_emu10k1_alloc_pages(emu, (struct snd_sg_buf *)substream->dma_private);
 		if ((epcm->memblk = memblk) == NULL || ((emu10k1_memblk_t *)memblk)->mapped_page < 0) {
 			epcm->start_addr = 0;
 			return -ENOMEM;
@@ -400,7 +401,7 @@
 		epcm->memblk = NULL;
 		epcm->start_addr = 0;
 	}
-	snd_pcm_lib_free_pages(substream);
+	snd_pcm_sgbuf_free(substream);
 	return 0;
 }
 
@@ -778,6 +779,10 @@
 	runtime->private_data = epcm;
 	runtime->private_free = snd_emu10k1_pcm_free_substream;
 	runtime->hw = snd_emu10k1_playback;
+	if ((err = snd_pcm_sgbuf_init(substream, emu->pci, 32)) < 0) {
+		snd_magic_kfree(epcm);
+		return err;
+	}
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) {
 		snd_magic_kfree(epcm);
 		return err;
@@ -804,6 +809,7 @@
 	emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[substream->number];
 
 	mix->epcm = NULL;
+	snd_pcm_sgbuf_delete(substream);
 	snd_emu10k1_pcm_mixer_notify(emu->card, mix, 0);
 	return 0;
 }
@@ -942,6 +948,9 @@
 	prepare:		snd_emu10k1_playback_prepare,
 	trigger:		snd_emu10k1_playback_trigger,
 	pointer:		snd_emu10k1_playback_pointer,
+	copy:			snd_pcm_sgbuf_ops_copy_playback,
+	silence:		snd_pcm_sgbuf_ops_silence,
+	page:			snd_pcm_sgbuf_ops_page,
 };
 
 static snd_pcm_ops_t snd_emu10k1_capture_ops = {
@@ -959,7 +968,6 @@
 {
 	emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return);
 	emu->pcm = NULL;
-	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
 int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
@@ -983,8 +991,6 @@
 	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
 	strcpy(pcm->name, "EMU10K1");
 	emu->pcm = pcm;
-
-	snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 128*1024);
 
 	if (rpcm)
 		*rpcm = pcm;
diff -Nru a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
--- a/sound/pci/emu10k1/memory.c	Sun Sep 29 20:21:38 2002
+++ b/sound/pci/emu10k1/memory.c	Sun Sep 29 20:21:38 2002
@@ -289,22 +289,19 @@
  * page allocation for DMA
  */
 snd_util_memblk_t *
-snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size)
+snd_emu10k1_alloc_pages(emu10k1_t *emu, struct snd_sg_buf *sgbuf)
 {
 	snd_util_memhdr_t *hdr;
 	emu10k1_memblk_t *blk;
-	int page, err;
+	int page, err, idx;
 
 	snd_assert(emu, return NULL);
-	snd_assert(size > 0 && size < MAXPAGES * EMUPAGESIZE, return NULL);
+	snd_assert(sgbuf->size > 0 && sgbuf->size < MAXPAGES * EMUPAGESIZE, return NULL);
 	hdr = emu->memhdr;
 	snd_assert(hdr, return NULL);
 
-	if (!is_valid_page(addr))
-		return NULL;
-
 	down(&hdr->block_mutex);
-	blk = search_empty(emu, size);
+	blk = search_empty(emu, sgbuf->size);
 	if (blk == NULL) {
 		up(&hdr->block_mutex);
 		return NULL;
@@ -312,10 +309,15 @@
 	/* fill buffer addresses but pointers are not stored so that
 	 * snd_free_pci_pages() is not called in in synth_free()
 	 */
-	for (page = blk->first_page; page <= blk->last_page; page++) {
+	idx = 0;
+	for (page = blk->first_page; page <= blk->last_page; page++, idx++) {
+		dma_addr_t addr = sgbuf->table[idx].addr;
+		if (! is_valid_page(addr)) {
+			up(&hdr->block_mutex);
+			return NULL;
+		}
 		emu->page_addr_table[page] = addr;
 		emu->page_ptr_table[page] = NULL;
-		addr += PAGE_SIZE;
 	}
 
 	/* set PTB entries */
diff -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
--- a/sound/pci/rme9652/hdsp.c	Sun Sep 29 20:21:38 2002
+++ b/sound/pci/rme9652/hdsp.c	Sun Sep 29 20:21:38 2002
@@ -482,7 +482,6 @@
 	if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT)) {
 		return -1;
 	}
-	
 	hdsp_write (hdsp, HDSP_fifoData, ad);
 	hdsp->mixer_matrix[addr] = data;
 
@@ -854,10 +853,7 @@
 		}
 
 		if (clear_timer && hmidi->istimer && --hmidi->istimer <= 0) {
-			printk ("removing timer because there is nothing to do\n");
-			if (del_timer(&hmidi->timer)) {
-				printk ("not removed\n");
-			}
+			del_timer(&hmidi->timer);
 		} 
 	}
 
@@ -956,16 +952,12 @@
 			hmidi->timer.function = snd_hdsp_midi_output_timer;
 			hmidi->timer.data = (unsigned long) hmidi;
 			hmidi->timer.expires = 1 + jiffies;
-			printk ("add timer from output trigger\n");
 			add_timer(&hmidi->timer);
 			hmidi->istimer++;
 		}
 	} else {
 		if (hmidi->istimer && --hmidi->istimer <= 0) {
-			printk ("remove timer in trigger off\n");
-			if (del_timer (&hmidi->timer)) {
-				printk ("not removed\n");
-			}
+			del_timer (&hmidi->timer);
 		}
 	}
 	spin_unlock_irqrestore (&hmidi->lock, flags);
@@ -2560,7 +2552,7 @@
 				 SNDRV_PCM_INFO_SYNC_START |
 				 SNDRV_PCM_INFO_DOUBLE),
 	formats:		SNDRV_PCM_FMTBIT_S32_LE,
-	rates:			(SNDRV_PCM_RATE_32000 | 
+	rates:			(SNDRV_PCM_RATE_32000 |
 				 SNDRV_PCM_RATE_44100 | 
 				 SNDRV_PCM_RATE_48000 | 
 				 SNDRV_PCM_RATE_64000 | 
@@ -2635,7 +2627,7 @@
 			integer: 1,
 		};
 		return snd_interval_refine(c, &t);
-	} else if (r->max < 88200) {
+	} else if (r->max < 64000) {
 		snd_interval_t t = {
 			min: hdsp->ss_channels,
 			max: hdsp->ss_channels,
@@ -2654,14 +2646,14 @@
 	snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 	if (c->min >= hdsp->ss_channels) {
 		snd_interval_t t = {
-			min: 44100,
+			min: 32000,
 			max: 48000,
 			integer: 1,
 		};
 		return snd_interval_refine(r, &t);
 	} else if (c->max <= hdsp->ds_channels) {
 		snd_interval_t t = {
-			min: 88200,
+			min: 64000,
 			max: 96000,
 			integer: 1,
 		};
diff -Nru a/sound/pci/via686.c b/sound/pci/via686.c
--- a/sound/pci/via686.c	Sun Sep 29 20:21:38 2002
+++ b/sound/pci/via686.c	Sun Sep 29 20:21:38 2002
@@ -28,6 +28,8 @@
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/pcm_sgbuf.h>
+#include <sound/pcm_params.h>
 #include <sound/info.h>
 #include <sound/ac97_codec.h>
 #include <sound/mpu401.h>
@@ -135,29 +137,92 @@
 #define   VIA_REG_AC97_DATA_MASK	0xffff
 #define VIA_REG_SGD_SHADOW		0x84	/* dword */
 
-/*
- *
- */
-
-#define VIA_MAX_FRAGS			32
+#define VIA_TBL_BIT_FLAG	0x40000000
+#define VIA_TBL_BIT_EOL		0x80000000
 
 /*
- *  
+ * pcm stream
  */
 
 typedef struct {
 	unsigned long reg_offset;
-	unsigned int *table;
-	dma_addr_t table_addr;
         snd_pcm_substream_t *substream;
-	dma_addr_t physbuf;
+	int running;
         unsigned int size;
         unsigned int fragsize;
 	unsigned int frags;
 	unsigned int lastptr;
 	unsigned int lastcount;
+	unsigned int page_per_frag;
+	unsigned int curidx;
+	unsigned int tbl_entries;	/* number of descriptor table entries */
+	unsigned int tbl_size;		/* size of a table entry */
+	u32 *table; /* physical address + flag */
+	dma_addr_t table_addr;
 } viadev_t;
 
+
+static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+			   struct pci_dev *pci)
+{
+	int i, pages, size;
+	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+
+	if (dev->table) {
+		pages = snd_pcm_sgbuf_pages(dev->tbl_entries * 8);
+		snd_free_pci_pages(pci, pages << PAGE_SHIFT, dev->table, dev->table_addr);
+		dev->table = NULL;
+	}
+
+	/* allocate buffer descriptor lists */
+	if (dev->fragsize < PAGE_SIZE) {
+		dev->tbl_size = dev->fragsize;
+		dev->tbl_entries = dev->frags;
+		dev->page_per_frag = 1;
+	} else {
+		dev->tbl_size = PAGE_SIZE;
+		dev->tbl_entries = sgbuf->pages;
+		dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
+	}
+	/* the start of each lists must be aligned to 8 bytes,
+	 * but the kernel pages are much bigger, so we don't care
+	 */
+	pages = snd_pcm_sgbuf_pages(dev->tbl_entries * 8);
+	dev->table = (u32*)snd_malloc_pci_pages(pci, pages << PAGE_SHIFT, &dev->table_addr);
+	if (! dev->table)
+		return -ENOMEM;
+
+	if (dev->tbl_size < PAGE_SIZE) {
+		for (i = 0; i < dev->tbl_entries; i++)
+			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
+	} else {
+		for (i = 0; i < dev->tbl_entries; i++)
+			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
+	}
+	size = dev->size;
+	for (i = 0; i < dev->tbl_entries - 1; i++) {
+		dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
+		size -= dev->tbl_size;
+	}
+	dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
+
+	return 0;
+}
+
+
+static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+			    struct pci_dev *pci)
+{
+	if (dev->table) {
+		snd_free_pci_pages(pci, snd_pcm_sgbuf_pages(dev->tbl_entries * 8) << PAGE_SHIFT, dev->table, dev->table_addr);
+		dev->table = NULL;
+	}
+}
+
+
+/*
+ */
+
 typedef struct _snd_via686a via686a_t;
 #define chip_t via686a_t
 
@@ -178,7 +243,7 @@
 	snd_pcm_t *pcm_fm;
 	viadev_t playback;
 	viadev_t capture;
-	viadev_t playback_fm;
+	/*viadev_t playback_fm;*/
 
 	snd_rawmidi_t *rmidi;
 
@@ -188,9 +253,6 @@
 
 	spinlock_t reg_lock;
 	snd_info_entry_t *proc_entry;
-
-	void *tables;
-	dma_addr_t tables_addr;
 };
 
 static struct pci_device_id snd_via686a_ids[] __devinitdata = {
@@ -336,15 +398,19 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		val = VIA_REG_CTRL_START;
+		viadev->running = 1;
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		val = VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET;
+		viadev->running = 0;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		val = VIA_REG_CTRL_PAUSE;
+		viadev->running = 1;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		val = 0;
+		viadev->running = 0;
 		break;
 	default:
 		return -EINVAL;
@@ -355,44 +421,43 @@
 	return 0;
 }
 
-static void snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
+
+static int snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
 				      snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	int idx, frags;
-	unsigned int *table = viadev->table;
 	unsigned long port = chip->port + viadev->reg_offset;
+	int v, err;
 
-	viadev->physbuf = runtime->dma_addr;
 	viadev->size = snd_pcm_lib_buffer_bytes(substream);
 	viadev->fragsize = snd_pcm_lib_period_bytes(substream);
 	viadev->frags = runtime->periods;
 	viadev->lastptr = ~0;
 	viadev->lastcount = ~0;
+	viadev->curidx = 0;
+
+	/* the period size must be in power of 2 */
+	v = ld2(viadev->fragsize);
+	if (viadev->fragsize != (1 << v)) {
+		snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
+		return -EINVAL;
+	}
 
 	snd_via686a_channel_reset(chip, viadev);
-	outl(viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
+
+	err = build_via_table(viadev, substream, chip->pci);
+	if (err < 0)
+		return err;
+
+	runtime->dma_bytes = viadev->size;
+	outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
 	outb(VIA_REG_TYPE_AUTOSTART |
 	     (runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
 	     (runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
 	     ((viadev->reg_offset & 0x10) == 0 ? VIA_REG_TYPE_INT_LSAMPLE : 0) |
 	     VIA_REG_TYPE_INT_EOL |
 	     VIA_REG_TYPE_INT_FLAG, port + VIA_REG_OFFSET_TYPE);
-	if (viadev->size == viadev->fragsize) {
-		table[0] = cpu_to_le32(viadev->physbuf);
-		table[1] = cpu_to_le32(0xc0000000 | /* EOL + flag */
-				       viadev->fragsize);
-	} else {
-		frags = viadev->size / viadev->fragsize;
-		for (idx = 0; idx < frags - 1; idx++) {
-			table[(idx << 1) + 0] = cpu_to_le32(viadev->physbuf + (idx * viadev->fragsize));
-			table[(idx << 1) + 1] = cpu_to_le32(0x40000000 |	/* flag */
-							    viadev->fragsize);
-		}
-		table[((frags-1) << 1) + 0] = cpu_to_le32(viadev->physbuf + ((frags-1) * viadev->fragsize));
-		table[((frags-1) << 1) + 1] = cpu_to_le32(0x80000000 |	/* EOL */
-							  viadev->fragsize);
-	}
+	return 0;
 }
 
 /*
@@ -401,8 +466,16 @@
 
 static inline void snd_via686a_update(via686a_t *chip, viadev_t *viadev)
 {
-	snd_pcm_period_elapsed(viadev->substream);
 	outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
+	if (viadev->substream && viadev->running) {
+		viadev->curidx++;
+		if (viadev->curidx >= viadev->page_per_frag) {
+			viadev->curidx = 0;
+			spin_unlock(&chip->reg_lock);
+			snd_pcm_period_elapsed(viadev->substream);
+			spin_lock(&chip->reg_lock);
+		}
+	}
 }
 
 static void snd_via686a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -410,8 +483,10 @@
 	via686a_t *chip = snd_magic_cast(via686a_t, dev_id, return);
 	unsigned int status;
 
+	spin_lock(&chip->reg_lock);
 	status = inl(VIAREG(chip, SGD_SHADOW));
 	if ((status & 0x00000077) == 0) {
+		spin_unlock(&chip->reg_lock);
 		if (chip->rmidi != NULL) {
 			snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
 		}
@@ -419,10 +494,11 @@
 	}
 	if (inb(VIAREG(chip, PLAYBACK_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
 		snd_via686a_update(chip, &chip->playback);
-	if (inb(VIAREG(chip, FM_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
-		snd_via686a_update(chip, &chip->playback_fm);
 	if (inb(VIAREG(chip, CAPTURE_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
 		snd_via686a_update(chip, &chip->capture);
+	/*if (inb(VIAREG(chip, FM_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
+	  snd_via686a_update(chip, &chip->playback_fm);*/
+	spin_unlock(&chip->reg_lock);
 }
 
 /*
@@ -448,12 +524,12 @@
 static int snd_via686a_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));
+	return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
 }
 
 static int snd_via686a_hw_free(snd_pcm_substream_t * substream)
 {
-	return snd_pcm_lib_free_pages(substream);
+	return 0;
 }
 
 static int snd_via686a_playback_prepare(snd_pcm_substream_t * substream)
@@ -462,8 +538,7 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
-	snd_via686a_setup_periods(chip, &chip->playback, substream);
-	return 0;
+	return snd_via686a_setup_periods(chip, &chip->playback, substream);
 }
 
 static int snd_via686a_capture_prepare(snd_pcm_substream_t * substream)
@@ -472,8 +547,7 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
-	snd_via686a_setup_periods(chip, &chip->capture, substream);
-	return 0;
+	return snd_via686a_setup_periods(chip, &chip->capture, substream);
 }
 
 static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev)
@@ -486,9 +560,14 @@
 		ptr += 8;
 	if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
 		return 0;
-	val = (((unsigned int)(ptr - viadev->table_addr) / 8) - 1) % viadev->frags;
-	val *= viadev->fragsize;
-	val += viadev->fragsize - count;
+	snd_assert(viadev->tbl_entries, return 0);
+	/* get index */
+	if (ptr <= (unsigned int)viadev->table_addr)
+		val = 0;
+	else
+		val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
+	val *= viadev->tbl_size;
+	val += viadev->tbl_size - count;
 	viadev->lastptr = ptr;
 	viadev->lastcount = count;
 	// printk("pointer: ptr = 0x%x (%i), count = 0x%x, val = 0x%x\n", ptr, count, val);
@@ -522,8 +601,8 @@
 	buffer_bytes_max:	128 * 1024,
 	period_bytes_min:	32,
 	period_bytes_max:	128 * 1024,
-	periods_min:		1,
-	periods_max:		VIA_MAX_FRAGS,
+	periods_min:		2,
+	periods_max:		1024,
 	fifo_size:		0,
 };
 
@@ -541,8 +620,8 @@
 	buffer_bytes_max:	128 * 1024,
 	period_bytes_min:	32,
 	period_bytes_max:	128 * 1024,
-	periods_min:		1,
-	periods_max:		VIA_MAX_FRAGS,
+	periods_min:		2,
+	periods_max:		1024,
 	fifo_size:		0,
 };
 
@@ -555,10 +634,20 @@
 	chip->playback.substream = substream;
 	runtime->hw = snd_via686a_playback;
 	runtime->hw.rates = chip->ac97->rates_front_dac;
+	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+		return err;
 	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
 		runtime->hw.rate_min = 48000;
+	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+		return err;
+#if 0
+	/* applying the following constraint together with the power-of-2 rule
+	 * above may result in too narrow space.
+	 * this one is not strictly necessary, so let's disable it.
+	 */
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
+#endif
 	return 0;
 }
 
@@ -571,10 +660,16 @@
 	chip->capture.substream = substream;
 	runtime->hw = snd_via686a_capture;
 	runtime->hw.rates = chip->ac97->rates_adc;
+	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+		return err;
 	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
 		runtime->hw.rate_min = 48000;
+	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+		return err;
+#if 0
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
+#endif
 	return 0;
 }
 
@@ -582,6 +677,8 @@
 {
 	via686a_t *chip = snd_pcm_substream_chip(substream);
 
+	clean_via_table(&chip->playback, substream, chip->pci);
+	snd_pcm_sgbuf_delete(substream);
 	chip->playback.substream = NULL;
 	/* disable DAC power */
 	snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
@@ -592,6 +689,8 @@
 {
 	via686a_t *chip = snd_pcm_substream_chip(substream);
 
+	clean_via_table(&chip->capture, substream, chip->pci);
+	snd_pcm_sgbuf_delete(substream);
 	chip->capture.substream = NULL;
 	/* disable ADC power */
 	snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
@@ -607,6 +706,9 @@
 	prepare:	snd_via686a_playback_prepare,
 	trigger:	snd_via686a_playback_trigger,
 	pointer:	snd_via686a_playback_pointer,
+	copy:           snd_pcm_sgbuf_ops_copy_playback,
+	silence:        snd_pcm_sgbuf_ops_silence,
+	page:           snd_pcm_sgbuf_ops_page,
 };
 
 static snd_pcm_ops_t snd_via686a_capture_ops = {
@@ -618,13 +720,15 @@
 	prepare:	snd_via686a_capture_prepare,
 	trigger:	snd_via686a_capture_trigger,
 	pointer:	snd_via686a_capture_pointer,
+	copy:           snd_pcm_sgbuf_ops_copy_capture,
+	silence:        snd_pcm_sgbuf_ops_silence,
+	page:           snd_pcm_sgbuf_ops_page,
 };
 
 static void snd_via686a_pcm_free(snd_pcm_t *pcm)
 {
 	via686a_t *chip = snd_magic_cast(via686a_t, pcm->private_data, return);
 	chip->pcm = NULL;
-	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
 static int __devinit snd_via686a_pcm(via686a_t *chip, int device, snd_pcm_t ** rpcm)
@@ -647,146 +751,11 @@
 	strcpy(pcm->name, "VIA 82C686A");
 	chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024);
-
 	if (rpcm)
 		*rpcm = NULL;
 	return 0;
 }
 
-#if 0
-
-/*
- *  PCM code - FM channel
- */
-
-static int snd_via686a_playback_fm_ioctl(snd_pcm_substream_t * substream,
-					 unsigned int cmd,
-					 void *arg)
-{
-	return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-
-static int snd_via686a_playback_fm_trigger(snd_pcm_substream_t * substream,
-					   int cmd)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-
-	return snd_via686a_trigger(chip, &chip->playback_fm, cmd);
-}
-
-static int snd_via686a_playback_fm_prepare(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-
-	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
-	snd_via686a_setup_periods(chip, &chip->playback_fm, substream);
-	return 0;
-}
-
-static snd_pcm_uframes_t snd_via686a_playback_fm_pointer(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	return bytes_to_frames(substream->runtime, snd_via686a_cur_ptr(chip, &chip->playback_fm));
-}
-
-static snd_pcm_hardware_t snd_via686a_playback_fm =
-{
-	info:			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_PAUSE),
-	formats:		SNDRV_PCM_FMTBIT_S16_LE,
-	rates:			SNDRV_PCM_RATE_KNOT,
-	rate_min:		24000,
-	rate_max:		24000,
-	channels_min:		2,
-	channels_max:		2,
-	buffer_bytes_max:	128 * 1024,
-	period_bytes_min:	32,
-	period_bytes_max:	128 * 1024,
-	periods_min:		1,
-	periods_max:		VIA_MAX_FRAGS,
-	fifo_size:		0,
-};
-
-static int snd_via686a_playback_fm_open(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err;
-
-	if ((runtime->dma_area = snd_malloc_pci_pages_fallback(chip->pci, chip->dma_fm_size, &runtime->dma_addr, &runtime->dma_bytes)) == NULL)
-		return -ENOMEM;
-	chip->playback_fm.substream = substream;
-	runtime->hw = snd_via686a_playback_fm;
-#if 0
-	runtime->hw.rates = chip->ac97->rates_front_dac;
-	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
-		runtime->hw.min_rate = 48000;
-#endif
-	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
-		return err;
-	return 0;
-}
-
-static int snd_via686a_playback_fm_close(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-
-	chip->playback_fm.substream = NULL;
-	snd_free_pci_pages(chip->pci, runtime->dma_bytes, runtime->dma_area, runtime->dma_addr);
-	/* disable DAC power */
-	snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
-	return 0;
-}
-
-static snd_pcm_ops_t snd_via686a_playback_fm_ops = {
-	open:		snd_via686a_playback_fm_open,
-	close:		snd_via686a_playback_fm_close,
-	ioctl:		snd_pcm_lib_ioctl,
-	prepare:	snd_via686a_playback_fm_prepare,
-	trigger:	snd_via686a_playback_fm_trigger,
-	pointer:	snd_via686a_playback_fm_pointer,
-};
-
-static void snd_via686a_pcm_fm_free(void *private_data)
-{
-	via686a_t *chip = snd_magic_cast(via686a_t, private_data, return);
-	chip->pcm_fm = NULL;
-	snd_pcm_lib_preallocate_pci_free_for_all(ensoniq->pci, pcm);
-}
-
-static int __devinit snd_via686a_pcm_fm(via686a_t *chip, int device, snd_pcm_t ** rpcm)
-{
-	snd_pcm_t *pcm;
-	int err;
-
-	if (rpcm)
-		*rpcm = NULL;
-	err = snd_pcm_new(chip->card, "VIA 82C686A - FM DAC", device, 1, 0, &pcm);
-	if (err < 0)
-		return err;
-
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686a_playback_fm_ops);
-
-	pcm->private_data = chip;
-	pcm->private_free = snd_via686a_pcm_fm_free;
-	pcm->info_flags = 0;
-	strcpy(pcm->name, "VIA 82C686A - FM DAC");
-
-	snd_pcm_add_buffer_bytes_controls(pcm);
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024);
-
-	chip->pcm_fm = pcm;
-	if (rpcm)
-		*rpcm = NULL;
-	return 0;
-}
-
-#endif
 
 /*
  *  Mixer part
@@ -979,7 +948,7 @@
 	/* disable interrupts */
 	snd_via686a_channel_reset(chip, &chip->playback);
 	snd_via686a_channel_reset(chip, &chip->capture);
-	snd_via686a_channel_reset(chip, &chip->playback_fm);
+	/*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
 	return 0;
 }
 
@@ -990,13 +959,10 @@
 	/* disable interrupts */
 	snd_via686a_channel_reset(chip, &chip->playback);
 	snd_via686a_channel_reset(chip, &chip->capture);
-	snd_via686a_channel_reset(chip, &chip->playback_fm);
+	/*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
 	/* --- */
+	synchronize_irq(chip->irq);
       __end_hw:
-	if(chip->irq >= 0)
-		synchronize_irq(chip->irq);
-	if (chip->tables)
-		snd_free_pci_pages(chip->pci, 3 * sizeof(unsigned int) * VIA_MAX_FRAGS * 2, chip->tables, chip->tables_addr);
 	if (chip->res_port) {
 		release_resource(chip->res_port);
 		kfree_nocheck(chip->res_port);
@@ -1061,23 +1027,7 @@
 	/* initialize offsets */
 	chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS;
 	chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
-	chip->playback_fm.reg_offset = VIA_REG_FM_STATUS;
-
-	/* allocate buffer descriptor lists */
-	/* the start of each lists must be aligned to 8 bytes */
-	chip->tables = (unsigned int *)snd_malloc_pci_pages(pci, 3 * sizeof(unsigned int) * VIA_MAX_FRAGS * 2, &chip->tables_addr);
-	if (chip->tables == NULL) {
-		snd_via686a_free(chip);
-		return -ENOMEM;
-	}
-	/* tables must be aligned to 8 bytes, but the kernel pages
-	   are much bigger, so we don't care */
-	chip->playback.table = chip->tables;
-	chip->playback.table_addr = chip->tables_addr;
-	chip->capture.table = chip->playback.table + VIA_MAX_FRAGS * 2;
-	chip->capture.table_addr = chip->playback.table_addr + sizeof(unsigned int) * VIA_MAX_FRAGS * 2;
-	chip->playback_fm.table = chip->capture.table + VIA_MAX_FRAGS * 2;
-	chip->playback_fm.table_addr = chip->capture.table_addr + sizeof(unsigned int) * VIA_MAX_FRAGS * 2;
+	/*chip->playback_fm.reg_offset = VIA_REG_FM_STATUS;*/
 
 	if ((err = snd_via686a_chip_init(chip)) < 0) {
 		snd_via686a_free(chip);

===================================================================


This BitKeeper patch contains the following changesets:
1.605.2.17
## Wrapped with gzip_uu ##


begin 664 bkpatch2473
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
C%5/[RMK:#^(,@?&"OC0;S,>_6%!Q:.W7U_X&5>+/!N:&````
`
end

-----
Jaroslav Kysela <perex@suse.cz>
Linux Kernel Sound Maintainer
ALSA Project  http://www.alsa-project.org
SuSE Linux    http://www.suse.com


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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-29 18:51 [PATCH] ALSA update [6/10] - 2002/07/20 Jaroslav Kysela
@ 2002-09-29 19:12 ` Arjan van de Ven
  2002-09-29 19:28   ` Jaroslav Kysela
  2002-09-30  0:22   ` David S. Miller
  0 siblings, 2 replies; 11+ messages in thread
From: Arjan van de Ven @ 2002-09-29 19:12 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: Linus Torvalds, LKML

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

On Sun, 2002-09-29 at 20:51, Jaroslav Kysela wrote:
> +	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);

hummmm magic casts?? why ?

> +		ptr = snd_malloc_pci_pages(sgbuf->pci, PAGE_SIZE, &addr);

what is wrong with the PCI DMA API that makes ALSA wants a private
interface/implementation ?

>  EXPORT_SYMBOL(snd_wrapper_kmalloc);
>  EXPORT_SYMBOL(snd_wrapper_kfree);
> +EXPORT_SYMBOL(snd_wrapper_vmalloc);
> +EXPORT_SYMBOL(snd_wrapper_vfree);

why do you need a wrapper for vfree? 




[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-29 19:12 ` Arjan van de Ven
@ 2002-09-29 19:28   ` Jaroslav Kysela
  2002-09-29 19:52     ` Jeff Garzik
  2002-09-30  0:22   ` David S. Miller
  1 sibling, 1 reply; 11+ messages in thread
From: Jaroslav Kysela @ 2002-09-29 19:28 UTC (permalink / raw)
  To: Arjan van de Ven; +Cc: LKML

On 29 Sep 2002, Arjan van de Ven wrote:

> On Sun, 2002-09-29 at 20:51, Jaroslav Kysela wrote:
> > +	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
> 
> hummmm magic casts?? why ?

We are trying to check if 'void *' pointers in structures are used 
correctly. It's our tool for debugging.

> > +		ptr = snd_malloc_pci_pages(sgbuf->pci, PAGE_SIZE, &addr);
> 
> what is wrong with the PCI DMA API that makes ALSA wants a private
> interface/implementation ?

These lines (i386 arch):

        if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
                gfp |= GFP_DMA;
        ret = (void *)__get_free_pages(gfp, get_order(size));

Note that some of soundcards have various PCI DMA transfer limits 
(dma_mask is not set to use full 32-bits). In this case, restricting this 
hardware to allocate these buffers in first 16MB is not a very good idea.
Thus, we have own hacks to allocate memory in whole hardware area.

> >  EXPORT_SYMBOL(snd_wrapper_kmalloc);
> >  EXPORT_SYMBOL(snd_wrapper_kfree);
> > +EXPORT_SYMBOL(snd_wrapper_vmalloc);
> > +EXPORT_SYMBOL(snd_wrapper_vfree);
> 
> why do you need a wrapper for vfree? 

Debugging. We enumerate all allocations, so we can check for memory leaks.
I'm happy to say, that our code is very well debugged in this regard.

						Jaroslav

-----
Jaroslav Kysela <perex@suse.cz>
Linux Kernel Sound Maintainer
ALSA Project  http://www.alsa-project.org
SuSE Linux    http://www.suse.com


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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-29 19:28   ` Jaroslav Kysela
@ 2002-09-29 19:52     ` Jeff Garzik
  2002-09-29 20:34       ` Jaroslav Kysela
  0 siblings, 1 reply; 11+ messages in thread
From: Jeff Garzik @ 2002-09-29 19:52 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: Arjan van de Ven, LKML

Jaroslav Kysela wrote:
> On 29 Sep 2002, Arjan van de Ven wrote:
>>what is wrong with the PCI DMA API that makes ALSA wants a private
>>interface/implementation ?
> 
> 
> These lines (i386 arch):
> 
>         if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
>                 gfp |= GFP_DMA;
>         ret = (void *)__get_free_pages(gfp, get_order(size));
> 
> Note that some of soundcards have various PCI DMA transfer limits 
> (dma_mask is not set to use full 32-bits). In this case, restricting this 
> hardware to allocate these buffers in first 16MB is not a very good idea.
> Thus, we have own hacks to allocate memory in whole hardware area.

It sounds like it would be reasonable to fix the ia32 arch code, would 
it not?


> Debugging. We enumerate all allocations, so we can check for memory leaks.
> I'm happy to say, that our code is very well debugged in this regard.

So are the net drivers, but without wrappers :)


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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-29 19:52     ` Jeff Garzik
@ 2002-09-29 20:34       ` Jaroslav Kysela
  2002-09-29 21:19         ` Alan Cox
  2002-09-30  0:53         ` David S. Miller
  0 siblings, 2 replies; 11+ messages in thread
From: Jaroslav Kysela @ 2002-09-29 20:34 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: LKML

On Sun, 29 Sep 2002, Jeff Garzik wrote:

> Jaroslav Kysela wrote:
> > On 29 Sep 2002, Arjan van de Ven wrote:
> >>what is wrong with the PCI DMA API that makes ALSA wants a private
> >>interface/implementation ?
> > 
> > 
> > These lines (i386 arch):
> > 
> >         if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
> >                 gfp |= GFP_DMA;
> >         ret = (void *)__get_free_pages(gfp, get_order(size));
> > 
> > Note that some of soundcards have various PCI DMA transfer limits 
> > (dma_mask is not set to use full 32-bits). In this case, restricting this 
> > hardware to allocate these buffers in first 16MB is not a very good idea.
> > Thus, we have own hacks to allocate memory in whole hardware area.
> 
> It sounds like it would be reasonable to fix the ia32 arch code, would 
> it not?

We have simple method in our hack:

  - try to allocate memory anywhere
  - try to allocate memory with GFP DMA if first step fails

Here is updated pci-dma.c code for comments:

===== pci-dma.c 1.8 vs edited =====
--- 1.8/arch/i386/kernel/pci-dma.c	Thu May  9 19:24:12 2002
+++ edited/pci-dma.c	Sun Sep 29 22:26:46 2002
@@ -19,14 +19,24 @@
 	void *ret;
 	int gfp = GFP_ATOMIC;
 
-	if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
+	if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
 		gfp |= GFP_DMA;
 	ret = (void *)__get_free_pages(gfp, get_order(size));
 
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_phys(ret);
+	if (ret == NULL)
+		return NULL;
+
+	/* try to allocate area in first 16MB memory */
+	if ((gfp & GFP_DMA) == 0 && (u32)hwdev->dma_mask != 0xffffffff &&
+	    ((virt_to_phys(ret) + size - 1) & ~(u32)hwdev->dma_mask) != 0) {
+		free_pages(ret, get_order(size));
+		ret = (void *)__get_free_pages(gfp | GFP_DMA, get_order(size));
+		if (ret == NULL)
+			return NULL;
 	}
+
+	memset(ret, 0, size);
+	*dma_handle = virt_to_phys(ret);
 	return ret;
 }
 
						Jaroslav

-----
Jaroslav Kysela <perex@suse.cz>
Linux Kernel Sound Maintainer
ALSA Project  http://www.alsa-project.org
SuSE Linux    http://www.suse.com


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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-29 20:34       ` Jaroslav Kysela
@ 2002-09-29 21:19         ` Alan Cox
  2002-09-30  0:53         ` David S. Miller
  1 sibling, 0 replies; 11+ messages in thread
From: Alan Cox @ 2002-09-29 21:19 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: Jeff Garzik, LKML

On Sun, 2002-09-29 at 21:34, Jaroslav Kysela wrote:
> -	if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
> +	if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
>  		gfp |= GFP_DMA;

This is wrong. You just broke ISA DMA handling, and also blocking of
devices with sub ISA requirements



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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-29 19:12 ` Arjan van de Ven
  2002-09-29 19:28   ` Jaroslav Kysela
@ 2002-09-30  0:22   ` David S. Miller
  1 sibling, 0 replies; 11+ messages in thread
From: David S. Miller @ 2002-09-30  0:22 UTC (permalink / raw)
  To: arjanv; +Cc: perex, torvalds, linux-kernel

   From: Arjan van de Ven <arjanv@fenrus.demon.nl>
   Date: 29 Sep 2002 21:12:23 +0200
   
   what is wrong with the PCI DMA API that makes ALSA wants a private
   interface/implementation ?

It makes the layers not have to know what the BUS is, and this can all
be deleted when everything goes through a generic struct device and
assosciated OPS.

I think ALSA is definitely doing the right thing here.

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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-29 20:34       ` Jaroslav Kysela
  2002-09-29 21:19         ` Alan Cox
@ 2002-09-30  0:53         ` David S. Miller
  2002-09-30 12:54           ` Alan Cox
  1 sibling, 1 reply; 11+ messages in thread
From: David S. Miller @ 2002-09-30  0:53 UTC (permalink / raw)
  To: perex; +Cc: jgarzik, linux-kernel, alan

   From: Jaroslav Kysela <perex@suse.cz>
   Date: Sun, 29 Sep 2002 22:34:51 +0200 (CEST)
    
   -	if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
   +	if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
    		gfp |= GFP_DMA;

So alan, why is this really broken?

EISA/ISA DMA is defined as using a hwdev of NULL or requiring
<16MB address, he is preserving GFP_DMA in those cases.

The only problem I have with the patch is that it probably isn't
that hard to let the page allocator take some MASK arg (defaults
to all 1's) to implement this in 2.5.x

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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-30  0:53         ` David S. Miller
@ 2002-09-30 12:54           ` Alan Cox
  2002-09-30 16:17             ` Jaroslav Kysela
  2002-09-30 20:33             ` David S. Miller
  0 siblings, 2 replies; 11+ messages in thread
From: Alan Cox @ 2002-09-30 12:54 UTC (permalink / raw)
  To: David S. Miller; +Cc: perex, jgarzik, linux-kernel, alan

On Mon, 2002-09-30 at 01:53, David S. Miller wrote:
>    From: Jaroslav Kysela <perex@suse.cz>
>    Date: Sun, 29 Sep 2002 22:34:51 +0200 (CEST)
>     
>    -	if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
>    +	if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
>     		gfp |= GFP_DMA;
> 
> So alan, why is this really broken?
> 
> EISA/ISA DMA is defined as using a hwdev of NULL or requiring
> <16MB address, he is preserving GFP_DMA in those cases.

Firstly the DMA mask on x86 can't be below 24bits, we don't support
allocation from a smaller zone. Secondly what about PCI for 25-31bits -
there we do need to force gfp_dma to have any chance of getting the
right pages

Giving the page allocator a mask argument does sound a lot nicer


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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-30 12:54           ` Alan Cox
@ 2002-09-30 16:17             ` Jaroslav Kysela
  2002-09-30 20:33             ` David S. Miller
  1 sibling, 0 replies; 11+ messages in thread
From: Jaroslav Kysela @ 2002-09-30 16:17 UTC (permalink / raw)
  To: Alan Cox; +Cc: David S. Miller, jgarzik, linux-kernel, alan

On 30 Sep 2002, Alan Cox wrote:

> On Mon, 2002-09-30 at 01:53, David S. Miller wrote:
> >    From: Jaroslav Kysela <perex@suse.cz>
> >    Date: Sun, 29 Sep 2002 22:34:51 +0200 (CEST)
> >     
> >    -	if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
> >    +	if (hwdev == NULL || (u32)hwdev->dma_mask <= 0x00ffffff)
> >     		gfp |= GFP_DMA;
> > 
> > So alan, why is this really broken?
> > 
> > EISA/ISA DMA is defined as using a hwdev of NULL or requiring
> > <16MB address, he is preserving GFP_DMA in those cases.
> 
> Firstly the DMA mask on x86 can't be below 24bits, we don't support
> allocation from a smaller zone. Secondly what about PCI for 25-31bits -
> there we do need to force gfp_dma to have any chance of getting the
> right pages

Not really. The test in original code - if the page is in right area - was 
bellow first allocation. Sure, it's dirty hack.

> Giving the page allocator a mask argument does sound a lot nicer

Right, my aim was to point to a bug. Let's go to create proper DMA 
allocation for broken hardware. I still wonder why hardware vendors are 
lazy to support full bus addressing. Perhaps, saving few coins per 
chip make them happy.

						Jaroslav

-----
Jaroslav Kysela <perex@suse.cz>
Linux Kernel Sound Maintainer
ALSA Project  http://www.alsa-project.org
SuSE Linux    http://www.suse.com


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

* Re: [PATCH] ALSA update [6/10] - 2002/07/20
  2002-09-30 12:54           ` Alan Cox
  2002-09-30 16:17             ` Jaroslav Kysela
@ 2002-09-30 20:33             ` David S. Miller
  1 sibling, 0 replies; 11+ messages in thread
From: David S. Miller @ 2002-09-30 20:33 UTC (permalink / raw)
  To: alan; +Cc: perex, jgarzik, linux-kernel, alan

   From: Alan Cox <alan@lxorguk.ukuu.org.uk>
   Date: 30 Sep 2002 13:54:11 +0100

   On Mon, 2002-09-30 at 01:53, David S. Miller wrote:
   > EISA/ISA DMA is defined as using a hwdev of NULL or requiring
   > <16MB address, he is preserving GFP_DMA in those cases.
   
   Firstly the DMA mask on x86 can't be below 24bits, we don't support
   allocation from a smaller zone.

Understood.

   Secondly what about PCI for 25-31bits -
   there we do need to force gfp_dma to have any chance of getting the
   right pages
   
Look at what his code does after the GFP_DMA setting, it goes
a non-GFP_DMA setting, and if the 25-31 bits case is not satisfied
it backs down to GFP_DMA.

   Giving the page allocator a mask argument does sound a lot nicer
   
It's pretty simple to implement too since we do have page_to_phys.

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

end of thread, other threads:[~2002-09-30 20:34 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-29 18:51 [PATCH] ALSA update [6/10] - 2002/07/20 Jaroslav Kysela
2002-09-29 19:12 ` Arjan van de Ven
2002-09-29 19:28   ` Jaroslav Kysela
2002-09-29 19:52     ` Jeff Garzik
2002-09-29 20:34       ` Jaroslav Kysela
2002-09-29 21:19         ` Alan Cox
2002-09-30  0:53         ` David S. Miller
2002-09-30 12:54           ` Alan Cox
2002-09-30 16:17             ` Jaroslav Kysela
2002-09-30 20:33             ` David S. Miller
2002-09-30  0:22   ` David S. Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).