staticint do_alloc_pages(struct snd_card *card, int type, struct device *dev, int str, size_t size, struct snd_dma_buffer *dmab)
{ enum dma_data_direction dir; int err;
/* check and reserve the requested size */
scoped_guard(mutex, &card->memory_mutex) { if (max_alloc_per_card &&
card->total_pcm_alloc_bytes + size > max_alloc_per_card) return -ENOMEM;
__update_allocated_size(card, size);
}
if (str == SNDRV_PCM_STREAM_PLAYBACK)
dir = DMA_TO_DEVICE; else
dir = DMA_FROM_DEVICE;
err = snd_dma_alloc_dir_pages(type, dev, dir, size, dmab); if (!err) { /* the actual allocation size might be bigger than requested, * and we need to correct the account
*/ if (dmab->bytes != size)
update_allocated_size(card, dmab->bytes - size);
} else { /* take back on allocation failure */
decrease_allocated_size(card, size);
} return err;
}
/* * 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.
*/ staticint preallocate_pcm_pages(struct snd_pcm_substream *substream,
size_t size, bool no_fallback)
{ struct snd_dma_buffer *dmab = &substream->dma_buffer; struct snd_card *card = substream->pcm->card;
size_t orig_size = size; int err;
/** * snd_pcm_lib_preallocate_free - release the preallocated buffer of the specified substream. * @substream: the pcm substream instance * * Releases the pre-allocated buffer of the given substream.
*/ void snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
{
do_free_pages(substream->pcm->card, &substream->dma_buffer);
}
/** * snd_pcm_lib_preallocate_free_for_all - release all pre-allocated buffers on the pcm * @pcm: the pcm instance * * Releases all the pre-allocated buffers on the given pcm.
*/ void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
{ struct snd_pcm_substream *substream; int stream;
/* * pre-allocate the buffer and create a proc file for the substream
*/ staticint preallocate_pages(struct snd_pcm_substream *substream, int type, struct device *data,
size_t size, size_t max, bool managed)
{ int err;
if (snd_BUG_ON(substream->dma_buffer.dev.type)) return -EINVAL;
/** * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type * @substream: the pcm substream instance * @type: DMA type (SNDRV_DMA_TYPE_*) * @data: DMA type dependent data * @size: the requested pre-allocation size in bytes * @max: the max. allowed pre-allocation size * * Do pre-allocation for the given DMA buffer type.
*/ void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, int type, struct device *data,
size_t size, size_t max)
{
preallocate_pages(substream, type, data, size, max, false);
}
EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
/** * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continuous memory type (all substreams) * @pcm: the pcm instance * @type: DMA type (SNDRV_DMA_TYPE_*) * @data: DMA type dependent data * @size: the requested pre-allocation size in bytes * @max: the max. allowed pre-allocation size * * Do pre-allocation to all substreams of the given pcm for the * specified DMA type.
*/ void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int type, void *data,
size_t size, size_t max)
{
preallocate_pages_for_all(pcm, type, data, size, max, false);
}
EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
/** * snd_pcm_set_managed_buffer - set up buffer management for a substream * @substream: the pcm substream instance * @type: DMA type (SNDRV_DMA_TYPE_*) * @data: DMA type dependent data * @size: the requested pre-allocation size in bytes * @max: the max. allowed pre-allocation size * * Do pre-allocation for the given DMA buffer type, and set the managed * buffer allocation mode to the given substream. * In this mode, PCM core will allocate a buffer automatically before PCM * hw_params ops call, and release the buffer after PCM hw_free ops call * as well, so that the driver doesn't need to invoke the allocation and * the release explicitly in its callback. * When a buffer is actually allocated before the PCM hw_params call, it * turns on the runtime buffer_changed flag for drivers changing their h/w * parameters accordingly. * * When @size is non-zero and @max is zero, this tries to allocate for only * the exact buffer size without fallback, and may return -ENOMEM. * Otherwise, the function tries to allocate smaller chunks if the allocation * fails. This is the behavior of snd_pcm_set_fixed_buffer(). * * When both @size and @max are zero, the function only sets up the buffer * for later dynamic allocations. It's used typically for buffers with * SNDRV_DMA_TYPE_VMALLOC type. * * Upon successful buffer allocation and setup, the function returns 0. * * Return: zero if successful, or a negative error code
*/ int snd_pcm_set_managed_buffer(struct snd_pcm_substream *substream, int type, struct device *data, size_t size, size_t max)
{ return preallocate_pages(substream, type, data, size, max, true);
}
EXPORT_SYMBOL(snd_pcm_set_managed_buffer);
/** * snd_pcm_set_managed_buffer_all - set up buffer management for all substreams * for all substreams * @pcm: the pcm instance * @type: DMA type (SNDRV_DMA_TYPE_*) * @data: DMA type dependent data * @size: the requested pre-allocation size in bytes * @max: the max. allowed pre-allocation size * * Do pre-allocation to all substreams of the given pcm for the specified DMA * type and size, and set the managed_buffer_alloc flag to each substream. * * Return: zero if successful, or a negative error code
*/ int snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type, struct device *data,
size_t size, size_t max)
{ return preallocate_pages_for_all(pcm, type, data, size, max, true);
}
EXPORT_SYMBOL(snd_pcm_set_managed_buffer_all);
/** * snd_pcm_lib_malloc_pages - allocate the DMA buffer * @substream: the substream to allocate the DMA buffer to * @size: the requested buffer size in bytes * * Allocates the DMA buffer on the BUS type given earlier to * snd_pcm_lib_preallocate_xxx_pages(). * * Return: 1 if the buffer is changed, 0 if not changed, or a negative * code on failure.
*/ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
{ struct snd_card *card; struct snd_pcm_runtime *runtime; struct snd_dma_buffer *dmab = NULL;
if (PCM_RUNTIME_CHECK(substream)) return -EINVAL; if (snd_BUG_ON(substream->dma_buffer.dev.type ==
SNDRV_DMA_TYPE_UNKNOWN)) return -EINVAL;
runtime = substream->runtime;
card = substream->pcm->card;
if (runtime->dma_buffer_p) { /* perphaps, we might free the large DMA memory region to save some space here, but the actual solution
costs us less time */ if (runtime->dma_buffer_p->bytes >= size) {
runtime->dma_bytes = size; return 0; /* ok, do not change */
}
snd_pcm_lib_free_pages(substream);
} if (substream->dma_buffer.area != NULL &&
substream->dma_buffer.bytes >= size) {
dmab = &substream->dma_buffer; /* use the pre-allocated buffer */
} else { /* dma_max=0 means the fixed size preallocation */ if (substream->dma_buffer.area && !substream->dma_max) return -ENOMEM;
dmab = kzalloc(sizeof(*dmab), GFP_KERNEL); if (! dmab) return -ENOMEM;
dmab->dev = substream->dma_buffer.dev; if (do_alloc_pages(card,
substream->dma_buffer.dev.type,
substream->dma_buffer.dev.dev,
substream->stream,
size, dmab) < 0) {
kfree(dmab);
pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot allocate for size %zu\n",
substream->pcm->card->number, substream->pcm->device,
substream->stream ? 'c' : 'p', substream->number,
substream->pcm->name, size); return -ENOMEM;
}
}
snd_pcm_set_runtime_buffer(substream, dmab);
runtime->dma_bytes = size; return 1; /* area was changed */
}
EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
/** * snd_pcm_lib_free_pages - release the allocated DMA buffer. * @substream: the substream to release the DMA buffer * * Releases the DMA buffer allocated via snd_pcm_lib_malloc_pages(). * * Return: Zero if successful, or a negative error code on failure.
*/ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
{ struct snd_pcm_runtime *runtime;
if (PCM_RUNTIME_CHECK(substream)) return -EINVAL;
runtime = substream->runtime; if (runtime->dma_area == NULL) return 0; if (runtime->dma_buffer_p != &substream->dma_buffer) { struct snd_card *card = substream->pcm->card;
/* it's a newly allocated buffer. release it now. */
do_free_pages(card, runtime->dma_buffer_p);
kfree(runtime->dma_buffer_p);
}
snd_pcm_set_runtime_buffer(substream, NULL); return 0;
}
EXPORT_SYMBOL(snd_pcm_lib_free_pages);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.