| /* |
| * 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); |
| } |