forked from Minki/linux
c9bd5e690a
This code sequence is unsafe in modules: static u64 mask = DMA_BIT_MASK(something); ... if (!dev->dma_mask) dev->dma_mask = &mask; as if a module is reloaded, the mask will be pointing at the original module's mask address, and this can lead to oopses. Moreover, they all follow this with: if (!dev->coherent_dma_mask) dev->coherent_dma_mask = mask; where 'mask' is the same value as the statically defined mask, and this bypasses the architecture's check on whether the DMA mask is possible. Fix these issues by using the new dma_coerce_coherent_and_mask() function. Acked-by: Mark Brown <broonie@linaro.org> Acked-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
134 lines
3.1 KiB
C
134 lines
3.1 KiB
C
/*
|
|
* linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
|
|
*
|
|
* Author: Nicolas Pitre
|
|
* Created: Nov 30, 2004
|
|
* Copyright: (C) 2004 MontaVista Software, Inc.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/dmaengine.h>
|
|
|
|
#include <sound/core.h>
|
|
#include <sound/pxa2xx-lib.h>
|
|
#include <sound/dmaengine_pcm.h>
|
|
|
|
#include "pxa2xx-pcm.h"
|
|
|
|
static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
|
|
{
|
|
struct pxa2xx_pcm_client *client = substream->private_data;
|
|
|
|
__pxa2xx_pcm_prepare(substream);
|
|
|
|
return client->prepare(substream);
|
|
}
|
|
|
|
static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
|
|
{
|
|
struct pxa2xx_pcm_client *client = substream->private_data;
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
struct pxa2xx_runtime_data *rtd;
|
|
int ret;
|
|
|
|
ret = __pxa2xx_pcm_open(substream);
|
|
if (ret)
|
|
goto out;
|
|
|
|
rtd = runtime->private_data;
|
|
|
|
rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
|
client->playback_params : client->capture_params;
|
|
ret = pxa_request_dma("dma", DMA_PRIO_LOW,
|
|
pxa2xx_pcm_dma_irq, substream);
|
|
if (ret < 0)
|
|
goto err2;
|
|
rtd->dma_ch = ret;
|
|
|
|
ret = client->startup(substream);
|
|
if (!ret)
|
|
goto out;
|
|
|
|
pxa_free_dma(rtd->dma_ch);
|
|
err2:
|
|
__pxa2xx_pcm_close(substream);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
|
|
{
|
|
struct pxa2xx_pcm_client *client = substream->private_data;
|
|
struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
|
|
|
|
pxa_free_dma(rtd->dma_ch);
|
|
client->shutdown(substream);
|
|
|
|
return __pxa2xx_pcm_close(substream);
|
|
}
|
|
|
|
static struct snd_pcm_ops pxa2xx_pcm_ops = {
|
|
.open = pxa2xx_pcm_open,
|
|
.close = pxa2xx_pcm_close,
|
|
.ioctl = snd_pcm_lib_ioctl,
|
|
.hw_params = __pxa2xx_pcm_hw_params,
|
|
.hw_free = __pxa2xx_pcm_hw_free,
|
|
.prepare = pxa2xx_pcm_prepare,
|
|
.trigger = pxa2xx_pcm_trigger,
|
|
.pointer = pxa2xx_pcm_pointer,
|
|
.mmap = pxa2xx_pcm_mmap,
|
|
};
|
|
|
|
int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client,
|
|
struct snd_pcm **rpcm)
|
|
{
|
|
struct snd_pcm *pcm;
|
|
int play = client->playback_params ? 1 : 0;
|
|
int capt = client->capture_params ? 1 : 0;
|
|
int ret;
|
|
|
|
ret = snd_pcm_new(card, "PXA2xx-PCM", 0, play, capt, &pcm);
|
|
if (ret)
|
|
goto out;
|
|
|
|
pcm->private_data = client;
|
|
pcm->private_free = pxa2xx_pcm_free_dma_buffers;
|
|
|
|
ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
|
|
if (ret)
|
|
goto out;
|
|
|
|
if (play) {
|
|
int stream = SNDRV_PCM_STREAM_PLAYBACK;
|
|
snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
|
|
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
if (capt) {
|
|
int stream = SNDRV_PCM_STREAM_CAPTURE;
|
|
snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
|
|
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
|
|
if (rpcm)
|
|
*rpcm = pcm;
|
|
ret = 0;
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
EXPORT_SYMBOL(pxa2xx_pcm_new);
|
|
|
|
MODULE_AUTHOR("Nicolas Pitre");
|
|
MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
|
|
MODULE_LICENSE("GPL");
|