ASoC: pcm: Add support for Hostless pcm

Hostless PCM nodes will not exchange data with
the userspace clients.Control paths will
be setup by userspace clients.

Signed-off-by: Gopikrishnaiah Anandan <agopik@codeaurora.org>
This commit is contained in:
Gopikrishnaiah Anandan 2013-02-15 14:26:52 -05:00 committed by Stephen Boyd
parent 1f42244c54
commit 0de64fbea0
3 changed files with 59 additions and 9 deletions

View file

@ -413,6 +413,7 @@ struct snd_pcm_substream {
#endif
/* misc flags */
unsigned int hw_opened: 1;
unsigned int hw_no_buffer: 1; /* substream may not have a buffer */
};
#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0)

View file

@ -567,7 +567,8 @@ int snd_soc_suspend(struct device *dev)
struct snd_soc_dai *dai = card->rtd[i].codec_dai;
struct snd_soc_dai_driver *drv = dai->driver;
if (card->rtd[i].dai_link->ignore_suspend)
if (card->rtd[i].dai_link->ignore_suspend ||
card->rtd[i].dai_link->no_pcm)
continue;
if (card->rtd[i].dai_link->dynamic)
@ -580,7 +581,8 @@ int snd_soc_suspend(struct device *dev)
/* suspend all pcms */
for (i = 0; i < card->num_rtd; i++) {
if (card->rtd[i].dai_link->ignore_suspend)
if (card->rtd[i].dai_link->ignore_suspend ||
card->rtd[i].dai_link->no_pcm)
continue;
snd_pcm_suspend_all(card->rtd[i].pcm);
@ -593,7 +595,8 @@ int snd_soc_suspend(struct device *dev)
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
struct snd_soc_platform *platform = card->rtd[i].platform;
if (card->rtd[i].dai_link->ignore_suspend)
if (card->rtd[i].dai_link->ignore_suspend ||
card->rtd[i].dai_link->no_pcm)
continue;
if (card->rtd[i].dai_link->dynamic) {
@ -618,7 +621,8 @@ int snd_soc_suspend(struct device *dev)
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
if (card->rtd[i].dai_link->ignore_suspend)
if (card->rtd[i].dai_link->ignore_suspend ||
card->rtd[i].dai_link->no_pcm)
continue;
if (driver->playback.stream_name != NULL)
@ -652,7 +656,8 @@ int snd_soc_suspend(struct device *dev)
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
if (card->rtd[i].dai_link->ignore_suspend)
if (card->rtd[i].dai_link->ignore_suspend ||
card->rtd[i].dai_link->no_pcm)
continue;
if (card->rtd[i].dai_link->dynamic)
@ -695,7 +700,8 @@ static void soc_resume_deferred(struct work_struct *work)
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
if (card->rtd[i].dai_link->ignore_suspend)
if (card->rtd[i].dai_link->ignore_suspend ||
card->rtd[i].dai_link->no_pcm)
continue;
if (card->rtd[i].dai_link->dynamic)
@ -727,7 +733,8 @@ static void soc_resume_deferred(struct work_struct *work)
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
if (card->rtd[i].dai_link->ignore_suspend)
if (card->rtd[i].dai_link->ignore_suspend ||
card->rtd[i].dai_link->no_pcm)
continue;
if (driver->playback.stream_name != NULL)
@ -744,7 +751,8 @@ static void soc_resume_deferred(struct work_struct *work)
struct snd_soc_dai *dai = card->rtd[i].codec_dai;
struct snd_soc_dai_driver *drv = dai->driver;
if (card->rtd[i].dai_link->ignore_suspend)
if (card->rtd[i].dai_link->ignore_suspend ||
card->rtd[i].dai_link->no_pcm)
continue;
if (card->rtd[i].dai_link->dynamic)
@ -759,7 +767,8 @@ static void soc_resume_deferred(struct work_struct *work)
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
struct snd_soc_platform *platform = card->rtd[i].platform;
if (card->rtd[i].dai_link->ignore_suspend)
if (card->rtd[i].dai_link->ignore_suspend ||
card->rtd[i].dai_link->no_pcm)
continue;
if (card->rtd[i].dai_link->dynamic) {

View file

@ -31,9 +31,29 @@
#include <sound/soc.h>
#include <sound/soc-dpcm.h>
#include <sound/initval.h>
#define MAX_BE_USERS 8 /* adjust if too low for everday use */
static int soc_dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream);
/* ASoC no host IO hardware.
* TODO: fine tune these values for all host less transfers.
*/
static const struct snd_pcm_hardware no_host_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.period_bytes_min = PAGE_SIZE >> 2,
.period_bytes_max = PAGE_SIZE >> 1,
.periods_min = 2,
.periods_max = 4,
.buffer_bytes_max = PAGE_SIZE,
};
/*
* We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
* are not running, paused or suspended for the specified stream direction.
@ -194,6 +214,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
snd_soc_set_runtime_hwparams(substream, &no_host_hardware);
/* startup the audio subsystem */
if (cpu_dai->driver->ops->startup) {
ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
@ -606,6 +629,20 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
cpu_dai->rate = params_rate(params);
codec_dai->rate = params_rate(params);
/* malloc a page for hostless IO.
* FIXME: rework with alsa-lib changes so that this malloc is not required.
*/
if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) {
substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV;
substream->dma_buffer.dev.dev = rtd->dev;
substream->dma_buffer.dev.dev->coherent_dma_mask = DMA_BIT_MASK(32);
substream->dma_buffer.private_data = NULL;
ret = snd_pcm_lib_malloc_pages(substream, PAGE_SIZE);
if (ret < 0)
goto platform_err;
}
out:
mutex_unlock(&rtd->pcm_mutex);
return ret;
@ -658,6 +695,9 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
if (cpu_dai->driver->ops->hw_free)
cpu_dai->driver->ops->hw_free(substream, cpu_dai);
if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
snd_pcm_lib_free_pages(substream);
mutex_unlock(&rtd->pcm_mutex);
return 0;
}