|
@@ -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);
|
|
|
|
+}
|