1/*
2 *  linux/sound/arm/devdma.c
3 *
4 *  Copyright (C) 2003-2004 Russell King, All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 *  ARM DMA shim for ALSA.
11 */
12#include <linux/device.h>
13#include <linux/dma-mapping.h>
14
15#include <sound/driver.h>
16#include <sound/core.h>
17#include <sound/pcm.h>
18
19#include "devdma.h"
20
21void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream)
22{
23	struct snd_pcm_runtime *runtime = substream->runtime;
24	struct snd_dma_buffer *buf = runtime->dma_buffer_p;
25
26	if (runtime->dma_area == NULL)
27		return;
28
29	if (buf != &substream->dma_buffer) {
30		dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr);
31		kfree(runtime->dma_buffer_p);
32	}
33
34	snd_pcm_set_runtime_buffer(substream, NULL);
35}
36
37int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size)
38{
39	struct snd_pcm_runtime *runtime = substream->runtime;
40	struct snd_dma_buffer *buf = runtime->dma_buffer_p;
41	int ret = 0;
42
43	if (buf) {
44		if (buf->bytes >= size)
45			goto out;
46		devdma_hw_free(dev, substream);
47	}
48
49	if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) {
50		buf = &substream->dma_buffer;
51	} else {
52		buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
53		if (!buf)
54			goto nomem;
55
56		buf->dev.type = SNDRV_DMA_TYPE_DEV;
57		buf->dev.dev = dev;
58		buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL);
59		buf->bytes = size;
60		buf->private_data = NULL;
61
62		if (!buf->area)
63			goto free;
64	}
65	snd_pcm_set_runtime_buffer(substream, buf);
66	ret = 1;
67 out:
68	runtime->dma_bytes = size;
69	return ret;
70
71 free:
72	kfree(buf);
73 nomem:
74	return -ENOMEM;
75}
76
77int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma)
78{
79	struct snd_pcm_runtime *runtime = substream->runtime;
80	return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
81}
82