diff options
author | Russell King <rmk@arm.linux.org.uk> | 2005-05-12 10:25:58 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-05-29 10:06:49 +0200 |
commit | 9b9a5afffd8636a82c6b32970342aef9d1f3d17d (patch) | |
tree | 459b442ae9d43f988c3dcd1b6cf154fd76b1861b | |
parent | f7de9cfd25b6867a2854d98d734e03e1a9fc65fb (diff) |
[ALSA] ARM DMA subsystem
ARM DMA routines
The patch below adds a convenient re-usable shim around the extended
ARM DMA API, and is used by several ARM ALSA drivers.
Signed-off-by: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/arm/devdma.c | 81 | ||||
-rw-r--r-- | sound/arm/devdma.h | 3 |
2 files changed, 84 insertions, 0 deletions
diff --git a/sound/arm/devdma.c b/sound/arm/devdma.c new file mode 100644 index 00000000000..60826a5324b --- /dev/null +++ b/sound/arm/devdma.c @@ -0,0 +1,81 @@ +/* + * linux/sound/arm/devdma.c + * + * Copyright (C) 2003-2004 Russell King, All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ARM DMA shim for ALSA. + */ +#include <linux/device.h> +#include <linux/dma-mapping.h> + +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/pcm.h> + +#include "devdma.h" + +void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct snd_dma_buffer *buf = runtime->dma_buffer_p; + + if (runtime->dma_area == NULL) + return; + + if (buf != &substream->dma_buffer) { + dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr); + kfree(runtime->dma_buffer_p); + } + + snd_pcm_set_runtime_buffer(substream, NULL); +} + +int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + struct snd_dma_buffer *buf = runtime->dma_buffer_p; + int ret = 0; + + if (buf) { + if (buf->bytes >= size) + goto out; + devdma_hw_free(dev, substream); + } + + if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { + buf = &substream->dma_buffer; + } else { + buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); + if (!buf) + goto nomem; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = dev; + buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL); + buf->bytes = size; + buf->private_data = NULL; + + if (!buf->area) + goto free; + } + snd_pcm_set_runtime_buffer(substream, buf); + ret = 1; + out: + runtime->dma_bytes = size; + return ret; + + free: + kfree(buf); + nomem: + return -ENOMEM; +} + +int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); +} diff --git a/sound/arm/devdma.h b/sound/arm/devdma.h new file mode 100644 index 00000000000..5a33b6bacc3 --- /dev/null +++ b/sound/arm/devdma.h @@ -0,0 +1,3 @@ +void devdma_hw_free(struct device *dev, snd_pcm_substream_t *substream); +int devdma_hw_alloc(struct device *dev, snd_pcm_substream_t *substream, size_t size); +int devdma_mmap(struct device *dev, snd_pcm_substream_t *substream, struct vm_area_struct *vma); |