Update of /cvsroot/alsa/alsa-kernel/core
In directory sc8-pr-cvs1:/tmp/cvs-serv14205/core
Modified Files:
pcm.c pcm_memory.c
Log Message:
[PATCH: pcm-memory-fix.dif]
- added UNKNOWN type for dma_type, set as default to check invalid
uses of pre-allocated data.
- clean up the pre-allocation code, added more comments.
- call snd_pcm_lib_preallocate_free_fo_all() in the destructor of
pcm instance, to be sure to release all the buffers.
now, each pcm driver doesn't have to call preallocate_free_*() in
its private_free callback.
Index: pcm.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/pcm.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- pcm.c 7 Jan 2003 10:31:23 -0000 1.21
+++ pcm.c 7 Jan 2003 10:58:51 -0000 1.22
@@ -582,7 +582,7 @@
snd_magic_kfree(substream);
return err;
}
- substream->dma_type = SNDRV_PCM_DMA_TYPE_ISA;
+ substream->dma_type = SNDRV_PCM_DMA_TYPE_UNKNOWN;
substream->dma_private = NULL;
spin_lock_init(&substream->timer_lock);
prev = substream;
@@ -660,6 +660,7 @@
snd_assert(pcm != NULL, return -ENXIO);
if (pcm->private_free)
pcm->private_free(pcm);
+ snd_pcm_lib_preallocate_free_for_all(pcm);
snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]);
snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_CAPTURE]);
snd_magic_kfree(pcm);
Index: pcm_memory.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/pcm_memory.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- pcm_memory.c 21 Oct 2002 18:28:20 -0000 1.13
+++ pcm_memory.c 7 Jan 2003 10:58:51 -0000 1.14
@@ -37,36 +37,116 @@
MODULE_PARM_DESC(maximum_substreams, "Maximum substreams with preallocated DMA
memory.");
MODULE_PARM_SYNTAX(maximum_substreams, SNDRV_BOOLEAN_TRUE_DESC);
-static int snd_minimum_buffer = 16384;
+const static int snd_minimum_buffer = 16384;
-static void snd_pcm_lib_preallocate_dma_free(snd_pcm_substream_t *substream)
+/*
+ * allocate pages on the specified bus
+ */
+static int alloc_pcm_pages(snd_pcm_substream_t *substream, size_t size,
+ void **dma_area, dma_addr_t *dma_addr)
{
- if (substream->dma_area == NULL)
- return;
switch (substream->dma_type) {
case SNDRV_PCM_DMA_TYPE_CONTINUOUS:
- snd_free_pages(substream->dma_area, substream->dma_bytes);
+ *dma_area = snd_malloc_pages(size, (unsigned int)((unsigned
+long)substream->dma_private & 0xffffffff));
+ *dma_addr = 0UL; /* not valid */
break;
#ifdef CONFIG_ISA
case SNDRV_PCM_DMA_TYPE_ISA:
- snd_free_isa_pages(substream->dma_bytes, substream->dma_area,
substream->dma_addr);
+ *dma_area = snd_malloc_isa_pages(size, dma_addr);
break;
#endif
#ifdef CONFIG_PCI
case SNDRV_PCM_DMA_TYPE_PCI:
- snd_free_pci_pages((struct pci_dev *)substream->dma_private,
substream->dma_bytes, substream->dma_area, substream->dma_addr);
+ *dma_area = snd_malloc_pci_pages((struct pci_dev
+*)substream->dma_private, size, dma_addr);
break;
#endif
#ifdef CONFIG_SBUS
case SNDRV_PCM_DMA_TYPE_SBUS:
- snd_free_sbus_pages((struct sbus_dev *)substream->dma_private,
substream->dma_bytes, substream->dma_area, substream->dma_addr);
+ *dma_area = snd_malloc_sbus_pages((struct sbus_dev
+*)substream->dma_private, size, dma_addr);
break;
#endif
+ default:
+ *dma_area = NULL;
+ *dma_addr = 0;
+ return -ENXIO;
}
+ return 0;
+}
+
+/*
+ * try to allocate as the large pages as possible.
+ * stores the resultant memory size in *res_size.
+ *
+ * the minimum size is snd_minimum_buffer. it should be power of 2.
+ */
+static void *alloc_pcm_pages_fallback(snd_pcm_substream_t *substream,
+ size_t size, dma_addr_t *addrp,
+ size_t *res_size)
+{
+ void *res;
+
+ snd_assert(size > 0, return NULL);
+ snd_assert(res_size != NULL, return NULL);
+ do {
+ if (alloc_pcm_pages(substream, size, &res, addrp) < 0)
+ return NULL;
+ if (res) {
+ *res_size = size;
+ return res;
+ }
+ size >>= 1;
+ } while (size >= snd_minimum_buffer);
+ *res_size = 0; /* tell error */
+ return NULL;
+}
+
+/*
+ * release the pages on the specified bus
+ */
+static void free_pcm_pages(snd_pcm_substream_t *substream, size_t size,
+ void *dma_area, dma_addr_t dma_addr)
+{
+ switch (substream->dma_type) {
+ case SNDRV_PCM_DMA_TYPE_CONTINUOUS:
+ snd_free_pages(dma_area, size);
+ break;
+#ifdef CONFIG_ISA
+ case SNDRV_PCM_DMA_TYPE_ISA:
+ snd_free_isa_pages(size, dma_area, dma_addr);
+ break;
+#endif
+#ifdef CONFIG_PCI
+ case SNDRV_PCM_DMA_TYPE_PCI:
+ snd_free_pci_pages((struct pci_dev *)substream->dma_private,
+ size, dma_area, dma_addr);
+ break;
+#endif
+#ifdef CONFIG_SBUS
+ case SNDRV_PCM_DMA_TYPE_SBUS:
+ snd_free_sbus_pages((struct sbus_dev *)substream->dma_private,
+ size, dma_area, dma_addr);
+ break;
+#endif
+ }
+}
+
+/*
+ * release the preallocated buffer if not yet done.
+ */
+static void snd_pcm_lib_preallocate_dma_free(snd_pcm_substream_t *substream)
+{
+ if (substream->dma_area == NULL)
+ return;
+ free_pcm_pages(substream, substream->dma_bytes,
+ substream->dma_area, substream->dma_addr);
substream->dma_area = NULL;
}
+/**
+ * snd_pcm_lib_preallocate_free - release the preallocated buffer
+ * of the specified substream.
+ */
int snd_pcm_lib_preallocate_free(snd_pcm_substream_t *substream)
{
snd_pcm_lib_preallocate_dma_free(substream);
@@ -77,6 +157,10 @@
return 0;
}
+/**
+ * snd_pcm_lib_preallocate_free_for_all - release the preallocated
+ * buffers of the whole substreams on the specified pcm.
+ */
int snd_pcm_lib_preallocate_free_for_all(snd_pcm_t *pcm)
{
snd_pcm_substream_t *substream;
@@ -88,6 +172,11 @@
return 0;
}
+/*
+ * read callback for prealloc proc file
+ *
+ * prints the current allocated size in kB.
+ */
static void snd_pcm_lib_preallocate_proc_read(snd_info_entry_t *entry,
snd_info_buffer_t *buffer)
{
@@ -95,6 +184,11 @@
snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_bytes / 1024);
}
+/*
+ * write callback for prealloc proc file
+ *
+ * accepts the preallocation size in kB.
+ */
static void snd_pcm_lib_preallocate_proc_write(snd_info_entry_t *entry,
snd_info_buffer_t *buffer)
{
@@ -118,27 +212,7 @@
if (substream->dma_bytes == size)
return;
if (size > 0) {
- switch (substream->dma_type) {
- case SNDRV_PCM_DMA_TYPE_CONTINUOUS:
- dma_area = snd_malloc_pages(size, (unsigned
int)((unsigned long)substream->dma_private & 0xffffffff));
- dma_addr = 0UL; /* not valid */
- break;
-#ifdef CONFIG_ISA
- case SNDRV_PCM_DMA_TYPE_ISA:
- dma_area = snd_malloc_isa_pages(size, &dma_addr);
- break;
-#endif
-#ifdef CONFIG_PCI
- case SNDRV_PCM_DMA_TYPE_PCI:
- dma_area = snd_malloc_pci_pages((struct pci_dev
*)substream->dma_private, size, &dma_addr);
- break;
-#endif
-#ifdef CONFIG_SBUS
- case SNDRV_PCM_DMA_TYPE_SBUS:
- dma_area = snd_malloc_sbus_pages((struct sbus_dev
*)substream->dma_private, size, &dma_addr);
- break;
-#endif
- default:
+ if (alloc_pcm_pages(substream, size, &dma_area, &dma_addr) <
+0) {
dma_area = NULL;
dma_addr = 0UL;
}
@@ -160,45 +234,19 @@
}
}
+/*
+ * pre-allocate the buffer and create a proc file for the substream
+ */
static int snd_pcm_lib_preallocate_pages1(snd_pcm_substream_t *substream,
size_t size, size_t max)
{
- unsigned long rsize = 0;
+ size_t rsize = 0;
void *dma_area = NULL;
dma_addr_t dma_addr = 0UL;
snd_info_entry_t *entry;
- if (!size || !preallocate_dma || substream->number >= maximum_substreams) {
- size = 0;
- } else {
- switch (substream->dma_type) {
- case SNDRV_PCM_DMA_TYPE_CONTINUOUS:
- dma_area = snd_malloc_pages_fallback(size, (unsigned
int)((unsigned long)substream->dma_private & 0xffffffff), &rsize);
- dma_addr = 0UL; /* not valid */
- break;
-#ifdef CONFIG_ISA
- case SNDRV_PCM_DMA_TYPE_ISA:
- dma_area = snd_malloc_isa_pages_fallback(size, &dma_addr,
&rsize);
- break;
-#endif
-#ifdef CONFIG_PCI
- case SNDRV_PCM_DMA_TYPE_PCI:
- dma_area = snd_malloc_pci_pages_fallback((struct pci_dev
*)substream->dma_private, size, &dma_addr, &rsize);
- break;
-#endif
-#ifdef CONFIG_SBUS
- case SNDRV_PCM_DMA_TYPE_SBUS:
- dma_area = snd_malloc_sbus_pages_fallback((struct sbus_dev
*)substream->dma_private, size, &dma_addr, &rsize);
- break;
-#endif
- default:
- size = 0;
- }
- if (rsize < snd_minimum_buffer) {
- snd_pcm_lib_preallocate_dma_free(substream);
- size = 0;
- }
- }
+ if (size > 0 && preallocate_dma && substream->number < maximum_substreams)
+ dma_area = alloc_pcm_pages_fallback(substream, size, &dma_addr,
+&rsize);
substream->dma_area = dma_area;
substream->dma_addr = dma_addr;
substream->dma_bytes = rsize;
@@ -220,6 +268,9 @@
return 0;
}
+/*
+ * pre-allocation for the continuous memory type
+ */
int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream,
size_t size, size_t max,
unsigned int flags)
@@ -244,6 +295,13 @@
}
#ifdef CONFIG_ISA
+/**
+ * snd_pcm_lib_preallocate_isa_pages - pre-allocation for the ISA bus
+ *
+ * @substream: substream to assign the buffer
+ * @size: the buffer size to be allocated
+ * @max: max. buffer size acceptable for the changes via proc file
+ */
int snd_pcm_lib_preallocate_isa_pages(snd_pcm_substream_t *substream,
size_t size, size_t max)
{
@@ -252,6 +310,14 @@
return snd_pcm_lib_preallocate_pages1(substream, size, max);
}
+/**
+ * snd_pcm_lib_preallocate_isa_pages_for_all - pre-allocation
+ * for the ISA bus (all substreams)
+ *
+ * @pcm: pcm to assign the buffer
+ * @size: the buffer size to be allocated
+ * @max: max. buffer size acceptable for the changes via proc file
+ */
int snd_pcm_lib_preallocate_isa_pages_for_all(snd_pcm_t *pcm,
size_t size, size_t max)
{
@@ -266,12 +332,20 @@
}
#endif /* CONFIG_ISA */
+/**
+ * snd_pcm_lib_malloc_pages - allocate the DMA buffer on the BUS type
+ * given by snd_pcm_lib_preallocate_xxx_pages().
+ *
+ * @substream: the substream to allocate the DMA buffer to
+ * @size: the requested buffer size in bytes
+ */
int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size)
{
snd_pcm_runtime_t *runtime;
void *dma_area = NULL;
dma_addr_t dma_addr = 0UL;
+ snd_assert(substream->dma_type != SNDRV_PCM_DMA_TYPE_UNKNOWN, return -EINVAL);
snd_assert(substream != NULL, return -EINVAL);
runtime = substream->runtime;
snd_assert(runtime != NULL, return -EINVAL);
@@ -287,29 +361,7 @@
dma_area = substream->dma_area;
dma_addr = substream->dma_addr;
} else {
- switch (substream->dma_type) {
- case SNDRV_PCM_DMA_TYPE_CONTINUOUS:
- dma_area = snd_malloc_pages(size, (unsigned int)((unsigned
long)substream->dma_private & 0xffffffff));
- dma_addr = 0UL; /* not valid */
- break;
-#ifdef CONFIG_ISA
- case SNDRV_PCM_DMA_TYPE_ISA:
- dma_area = snd_malloc_isa_pages(size, &dma_addr);
- break;
-#endif
-#ifdef CONFIG_PCI
- case SNDRV_PCM_DMA_TYPE_PCI:
- dma_area = snd_malloc_pci_pages((struct pci_dev
*)substream->dma_private, size, &dma_addr);
- break;
-#endif
-#ifdef CONFIG_SBUS
- case SNDRV_PCM_DMA_TYPE_SBUS:
- dma_area = snd_malloc_sbus_pages((struct sbus_dev
*)substream->dma_private, size, &dma_addr);
- break;
-#endif
- default:
- return -ENXIO;
- }
+ alloc_pcm_pages(substream, size, &dma_area, &dma_addr);
}
if (! dma_area)
return -ENOMEM;
@@ -319,6 +371,12 @@
return 1; /* area was changed */
}
+/**
+ * snd_pcm_lib_free_pages - release the allocated DMA buffer of
+ * the specified substream
+ *
+ * @substream: the substream to release the DMA buffer
+ */
int snd_pcm_lib_free_pages(snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime;
@@ -328,25 +386,9 @@
snd_assert(runtime != NULL, return -EINVAL);
if (runtime->dma_area == NULL)
return 0;
- if (runtime->dma_area != substream->dma_area) {
- switch (substream->dma_type) {
-#ifdef CONFIG_ISA
- case SNDRV_PCM_DMA_TYPE_ISA:
- snd_free_isa_pages(runtime->dma_bytes, runtime->dma_area,
runtime->dma_addr);
- break;
-#endif
-#ifdef CONFIG_PCI
- case SNDRV_PCM_DMA_TYPE_PCI:
- snd_free_pci_pages((struct pci_dev *)substream->dma_private,
runtime->dma_bytes, runtime->dma_area, runtime->dma_addr);
- break;
-#endif
-#ifdef CONFIG_SBUS
- case SNDRV_PCM_DMA_TYPE_SBUS:
- snd_free_sbus_pages((struct sbus_dev *)substream->dma_private,
runtime->dma_bytes, runtime->dma_area, runtime->dma_addr);
- break;
-#endif
- }
- }
+ if (runtime->dma_area != substream->dma_area)
+ free_pcm_pages(substream, runtime->dma_bytes,
+ runtime->dma_area, runtime->dma_addr);
runtime->dma_area = NULL;
runtime->dma_addr = 0UL;
runtime->dma_bytes = 0;
@@ -354,7 +396,14 @@
}
#ifdef CONFIG_PCI
-
+/**
+ * snd_pcm_lib_preallocate_pci_pages - pre-allocation for the PCI bus
+ *
+ * @pci: pci device
+ * @substream: substream to assign the buffer
+ * @size: the buffer size to be allocated in bytes
+ * @max: max. buffer size acceptable for the changes via proc file
+ */
int snd_pcm_lib_preallocate_pci_pages(struct pci_dev *pci,
snd_pcm_substream_t *substream,
size_t size, size_t max)
@@ -364,6 +413,15 @@
return snd_pcm_lib_preallocate_pages1(substream, size, max);
}
+/**
+ * snd_pcm_lib_preallocate_pci_pages_for_all - pre-allocation
+ * for the PCI bus (all substreams)
+ *
+ * @pci: pci device
+ * @pcm: pcm to assign the buffer
+ * @size: the buffer size to be allocated
+ * @max: max. buffer size acceptable for the changes via proc file
+ */
int snd_pcm_lib_preallocate_pci_pages_for_all(struct pci_dev *pci,
snd_pcm_t *pcm,
size_t size, size_t max)
@@ -381,7 +439,14 @@
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
-
+/**
+ * snd_pcm_lib_preallocate_sbus_pages - pre-allocation for the SBUS bus
+ *
+ * @sbus: SBUS device
+ * @substream: substream to assign the buffer
+ * @size: the buffer size to be allocated
+ * @max: max. buffer size acceptable for the changes via proc file
+ */
int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev,
snd_pcm_substream_t *substream,
size_t size, size_t max)
@@ -391,6 +456,15 @@
return snd_pcm_lib_preallocate_pages1(substream, size, max);
}
+/**
+ * snd_pcm_lib_preallocate_pci_pages_for_all - pre-allocation
+ * for the SBUS bus (all substreams)
+ *
+ * @sbus: SBUS device
+ * @pcm: pcm to assign the buffer
+ * @size: the buffer size to be allocated
+ * @max: max. buffer size acceptable for the changes via proc file
+ */
int snd_pcm_lib_preallocate_sbus_pages_for_all(struct sbus_dev *sdev,
snd_pcm_t *pcm,
size_t size, size_t max)
-------------------------------------------------------
This SF.NET email is sponsored by:
SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See!
http://www.vasoftware.com
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog