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

Reply via email to