[alsa-devel] [PATCH 0/3] ASoC: add compress stream support
Here is the much delayed support for compress audio streams in ASoC. The v2 incorprates feedback discussed on v1 patches and this also adds the support in Intel drivers.
Namarta Kohli (1): ASoC: add compress stream support
Vinod Koul (2): ASoC: add definations for compressed operations ASoC: mid-x86 - add support for compressed streams
include/sound/compress_driver.h | 1 + include/sound/soc-dai.h | 3 + include/sound/soc.h | 16 ++- sound/soc/Kconfig | 1 + sound/soc/Makefile | 2 +- sound/soc/mid-x86/mfld_machine.c | 9 ++ sound/soc/mid-x86/sst_dsp.h | 134 +++++++++++++++++ sound/soc/mid-x86/sst_platform.c | 204 ++++++++++++++++++++++++++- sound/soc/mid-x86/sst_platform.h | 26 ++++- sound/soc/soc-compress.c | 295 ++++++++++++++++++++++++++++++++++++++ sound/soc/soc-core.c | 57 +++++--- 11 files changed, 721 insertions(+), 27 deletions(-) create mode 100644 sound/soc/mid-x86/sst_dsp.h create mode 100644 sound/soc/soc-compress.c
Here we update the asoc structures to add compress stream definations First the struct snd_soc_dai_driver adds a new member to indicate if the dai is compressed or pcm. Next we add a new structre the struct snd_soc_compr_ops in the struct snd_soc_dai_link. This is to be used for machine driver to perform any opertaions required for setting up compressed audio streams
next is the compressed data operations, they are added using struct snd_compr_ops in the struct snd_soc_platform_driver.
Signed-off-by: Namarta Kohli namartax.kohli@intel.com Signed-off-by: Ramesh Babu K V ramesh.babu@intel.com Signed-off-by: Vinod Koul vinod.koul@linux.intel.com --- include/sound/compress_driver.h | 1 + include/sound/soc-dai.h | 3 +++ include/sound/soc.h | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 1 deletions(-)
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index 48f2a1f..f2912ab 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -61,6 +61,7 @@ struct snd_compr_runtime { u64 total_bytes_available; u64 total_bytes_transferred; wait_queue_head_t sleep; + void *private_data; };
/** diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 1f69e0a..628db7b 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -18,6 +18,7 @@
struct snd_pcm_substream; struct snd_soc_dapm_widget; +struct snd_compr_stream;
/* * DAI hardware audio formats. @@ -205,6 +206,8 @@ struct snd_soc_dai_driver { int (*remove)(struct snd_soc_dai *dai); int (*suspend)(struct snd_soc_dai *dai); int (*resume)(struct snd_soc_dai *dai); + /* compress dai */ + bool compress_dai;
/* ops */ const struct snd_soc_dai_ops *ops; diff --git a/include/sound/soc.h b/include/sound/soc.h index e063380..313b766 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -22,6 +22,7 @@ #include <linux/regmap.h> #include <sound/core.h> #include <sound/pcm.h> +#include <sound/compress_driver.h> #include <sound/control.h> #include <sound/ac97_codec.h>
@@ -399,6 +400,7 @@ int snd_soc_platform_read(struct snd_soc_platform *platform, int snd_soc_platform_write(struct snd_soc_platform *platform, unsigned int reg, unsigned int val); int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); +int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, const char *dai_link, int stream); @@ -632,6 +634,13 @@ struct snd_soc_ops { int (*trigger)(struct snd_pcm_substream *, int); };
+struct snd_soc_compr_ops { + int (*startup)(struct snd_compr_stream *); + void (*shutdown)(struct snd_compr_stream *); + int (*set_params)(struct snd_compr_stream *); + int (*trigger)(struct snd_compr_stream *); +}; + /* SoC cache ops */ struct snd_soc_cache_ops { const char *name; @@ -787,9 +796,12 @@ struct snd_soc_platform_driver { snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, struct snd_soc_dai *);
- /* platform stream ops */ + /* platform stream pcm ops */ struct snd_pcm_ops *ops;
+ /* platform stream compress ops */ + struct snd_compr_ops *compr_ops; + /* platform stream completion event */ int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
@@ -891,6 +903,7 @@ struct snd_soc_dai_link {
/* machine stream operations */ struct snd_soc_ops *ops; + struct snd_soc_compr_ops *compr_ops; };
struct snd_soc_codec_conf { @@ -1027,6 +1040,7 @@ struct snd_soc_pcm_runtime {
/* runtime devices */ struct snd_pcm *pcm; + struct snd_compr *compr; struct snd_soc_codec *codec; struct snd_soc_platform *platform; struct snd_soc_dai *codec_dai;
From: Namarta Kohli namartax.kohli@intel.com
This patch adds the support to parse the compress dai's and then also adds the soc-compress.c file while handles the compress stream operations, mostly analogus to what is done in the soc-pcm.c and aditional handling of the compress opertaions
Signed-off-by: Namarta Kohli namartax.kohli@intel.com Signed-off-by: Ramesh Babu K V ramesh.babu@intel.com Signed-off-by: Vinod Koul vinod.koul@linux.intel.com --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 2 +- sound/soc/soc-compress.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/soc-core.c | 57 ++++++---- 4 files changed, 331 insertions(+), 24 deletions(-) create mode 100644 sound/soc/soc-compress.c
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index c5de0a8..c24de90 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -9,6 +9,7 @@ menuconfig SND_SOC select SND_JACK if INPUT=y || INPUT=SND select REGMAP_I2C if I2C select REGMAP_SPI if SPI_MASTER + select SND_COMPRESS_OFFLOAD ---help---
If you want ASoC support, you should say Y here and also to the diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 00a555a..c126400 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o -snd-soc-core-objs += soc-pcm.o soc-io.o +snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o
snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c new file mode 100644 index 0000000..88d85ba --- /dev/null +++ b/sound/soc/soc-compress.c @@ -0,0 +1,295 @@ +/* + * soc-compress.c -- ALSA SoC Compress + * + * Copyright (C) 2012 Intel Corp. + * + * Authors: Namarta Kohli namartax.kohli@intel.com + * Ramesh Babu K V ramesh.babu@linux.intel.com + * Vinod Koul vinod.koul@linux.intel.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <sound/core.h> +#include <sound/compress_params.h> +#include <sound/compress_driver.h> +#include <sound/soc.h> +#include <sound/initval.h> + +static int soc_compr_open(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->open) { + ret = platform->driver->compr_ops->open(cstream); + if (ret < 0) { + pr_err("compress asoc: can't open platform %s\n", platform->name); + goto out; + } + } + + if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) { + ret = rtd->dai_link->compr_ops->startup(cstream); + if (ret < 0) { + pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name); + goto machine_err; + } + } + + if (cstream->direction == SND_COMPRESS_PLAYBACK) { + cpu_dai->playback_active++; + codec_dai->playback_active++; + } else { + cpu_dai->capture_active++; + codec_dai->capture_active++; + } + + cpu_dai->active++; + codec_dai->active++; + rtd->codec->active++; + + return 0; + +machine_err: + if (platform->driver->compr_ops && platform->driver->compr_ops->free) + platform->driver->compr_ops->free(cstream); +out: + return ret; +} + +static int soc_compr_free(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_codec *codec = rtd->codec; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) { + cpu_dai->playback_active--; + codec_dai->playback_active--; + } else { + cpu_dai->capture_active--; + codec_dai->capture_active--; + } + + snd_soc_dai_digital_mute(codec_dai, 1); + + cpu_dai->active--; + codec_dai->active--; + codec->active--; + + if (!cpu_dai->active) + cpu_dai->rate = 0; + + if (!codec_dai->active) + codec_dai->rate = 0; + + + if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown) + rtd->dai_link->compr_ops->shutdown(cstream); + + if (platform->driver->compr_ops && platform->driver->compr_ops->free) + platform->driver->compr_ops->free(cstream); + cpu_dai->runtime = NULL; + + if (cstream->direction == SND_COMPRESS_PLAYBACK) { + if (!rtd->pmdown_time || codec->ignore_pmdown_time || + rtd->dai_link->ignore_pmdown_time) { + snd_soc_dapm_stream_event(rtd, + SNDRV_PCM_STREAM_PLAYBACK, + SND_SOC_DAPM_STREAM_STOP); + } else + codec_dai->pop_wait = 1; + schedule_delayed_work(&rtd->delayed_work, + msecs_to_jiffies(rtd->pmdown_time)); + } else { + /* capture streams can be powered down now */ + snd_soc_dapm_stream_event(rtd, + SNDRV_PCM_STREAM_CAPTURE, + SND_SOC_DAPM_STREAM_STOP); + } + + return 0; +} + +static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { + ret = platform->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + return ret; + } + + if (cmd == SNDRV_PCM_TRIGGER_START) + snd_soc_dai_digital_mute(codec_dai, 0); + else if (cmd == SNDRV_PCM_TRIGGER_STOP) + snd_soc_dai_digital_mute(codec_dai, 1); + + return ret; +} + +static int soc_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret = 0; + + /* first we call set_params for the platform driver + * this should configure the soc side + * if the machine has compressed ops then we call that as well + * expectation is that platform and machine will configure everything + * for this compress path, like configuring pcm port for codec + */ + if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { + ret = platform->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + return ret; + } + + if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { + ret = rtd->dai_link->compr_ops->set_params(cstream); + if (ret < 0) + return ret; + } + + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, + SND_SOC_DAPM_STREAM_START); + + return ret; +} + +static int soc_compr_get_params(struct snd_compr_stream *cstream, + struct snd_codec *params) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->get_params) + ret = platform->driver->compr_ops->get_params(cstream, params); + + return ret; +} + +static int soc_compr_get_caps(struct snd_compr_stream *cstream, + struct snd_compr_caps *caps) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps) + ret = platform->driver->compr_ops->get_caps(cstream, caps); + + return ret; +} + +static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, + struct snd_compr_codec_caps *codec) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps) + ret = platform->driver->compr_ops->get_codec_caps(cstream, codec); + + return ret; +} + +static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + int ret = 0; + + if (platform->driver->compr_ops && platform->driver->compr_ops->ack) + ret = platform->driver->compr_ops->ack(cstream, bytes); + + return ret; +} + +static int soc_compr_pointer(struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_platform *platform = rtd->platform; + + if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) + platform->driver->compr_ops->pointer(cstream, tstamp); + + return 0; +} + +/* ASoC Compress operations */ +static struct snd_compr_ops soc_compr_ops = { + .open = soc_compr_open, + .free = soc_compr_free, + .set_params = soc_compr_set_params, + .get_params = soc_compr_get_params, + .trigger = soc_compr_trigger, + .pointer = soc_compr_pointer, + .ack = soc_compr_ack, + .get_caps = soc_compr_get_caps, + .get_codec_caps = soc_compr_get_codec_caps +}; + +/* create a new compress */ +int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_compr *compr; + char new_name[64]; + int ret = 0, direction = 0; + + /* check client and interface hw capabilities */ + snprintf(new_name, sizeof(new_name), "%s %s-%d", + rtd->dai_link->stream_name, codec_dai->name, num); + direction = SND_COMPRESS_PLAYBACK; + compr = kzalloc(sizeof(*compr), GFP_KERNEL); + if (compr == NULL) { + snd_printk(KERN_ERR "Cannot allocate compr\n"); + return -ENOMEM; + } + + compr->ops = &soc_compr_ops; + mutex_init(&compr->lock); + ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); + if (ret < 0) { + pr_err("compress asoc: can't create compress for codec %s\n", + codec->name); + kfree(compr); + return ret; + } + + rtd->compr = compr; + compr->private_data = rtd; + + printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name, + cpu_dai->name); + return ret; +} diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f585d02..c7a00fd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1388,37 +1388,48 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (ret < 0) pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret);
- if (!dai_link->params) { - /* create the pcm */ - ret = soc_new_pcm(rtd, num); + if (cpu_dai->driver->compress_dai) { + /*create compress_device"*/ + ret = soc_new_compress(rtd, num); if (ret < 0) { - pr_err("asoc: can't create pcm %s :%d\n", - dai_link->stream_name, ret); + pr_err("asoc: can't create compress %s\n", + dai_link->stream_name); return ret; } } else { - /* link the DAI widgets */ - play_w = codec_dai->playback_widget; - capture_w = cpu_dai->capture_widget; - if (play_w && capture_w) { - ret = snd_soc_dapm_new_pcm(card, dai_link->params, - capture_w, play_w); - if (ret != 0) { - dev_err(card->dev, "Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); + + if (!dai_link->params) { + /* create the pcm */ + ret = soc_new_pcm(rtd, num); + if (ret < 0) { + pr_err("asoc: can't create pcm %s :%d\n", + dai_link->stream_name, ret); return ret; } - } + } else { + /* link the DAI widgets */ + play_w = codec_dai->playback_widget; + capture_w = cpu_dai->capture_widget; + if (play_w && capture_w) { + ret = snd_soc_dapm_new_pcm(card, dai_link->params, + capture_w, play_w); + if (ret != 0) { + dev_err(card->dev, "Can't link %s to %s: %d\n", + play_w->name, capture_w->name, ret); + return ret; + } + }
- play_w = cpu_dai->playback_widget; - capture_w = codec_dai->capture_widget; - if (play_w && capture_w) { - ret = snd_soc_dapm_new_pcm(card, dai_link->params, + play_w = cpu_dai->playback_widget; + capture_w = codec_dai->capture_widget; + if (play_w && capture_w) { + ret = snd_soc_dapm_new_pcm(card, dai_link->params, capture_w, play_w); - if (ret != 0) { - dev_err(card->dev, "Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); - return ret; + if (ret != 0) { + dev_err(card->dev, "Can't link %s to %s: %d\n", + play_w->name, capture_w->name, ret); + return ret; + } } } }
Signed-off-by: Namarta Kohli namartax.kohli@intel.com Signed-off-by: Ramesh Babu K V ramesh.babu@intel.com Signed-off-by: Vinod Koul vinod.koul@linux.intel.com --- sound/soc/mid-x86/mfld_machine.c | 9 ++ sound/soc/mid-x86/sst_dsp.h | 134 +++++++++++++++++++++++++ sound/soc/mid-x86/sst_platform.c | 204 +++++++++++++++++++++++++++++++++++++- sound/soc/mid-x86/sst_platform.h | 26 +++++- 4 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 sound/soc/mid-x86/sst_dsp.h
diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c index 2937e54..2cc7782 100644 --- a/sound/soc/mid-x86/mfld_machine.c +++ b/sound/soc/mid-x86/mfld_machine.c @@ -318,6 +318,15 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = { .platform_name = "sst-platform", .init = NULL, }, + { + .name = "Medfield Compress", + .stream_name = "Speaker", + .cpu_dai_name = "Compress-cpu-dai", + .codec_dai_name = "SN95031 Speaker", + .codec_name = "sn95031", + .platform_name = "sst-platform", + .init = NULL, + }, };
/* SoC card */ diff --git a/sound/soc/mid-x86/sst_dsp.h b/sound/soc/mid-x86/sst_dsp.h new file mode 100644 index 0000000..0fce1de --- /dev/null +++ b/sound/soc/mid-x86/sst_dsp.h @@ -0,0 +1,134 @@ +#ifndef __SST_DSP_H__ +#define __SST_DSP_H__ +/* + * sst_dsp.h - Intel SST Driver for audio engine + * + * Copyright (C) 2008-12 Intel Corporation + * Authors: Vinod Koul vinod.koul@linux.intel.com + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +enum sst_codec_types { + /* AUDIO/MUSIC CODEC Type Definitions */ + SST_CODEC_TYPE_UNKNOWN = 0, + SST_CODEC_TYPE_PCM, /* Pass through Audio codec */ + SST_CODEC_TYPE_MP3, + SST_CODEC_TYPE_MP24, + SST_CODEC_TYPE_AAC, + SST_CODEC_TYPE_AACP, + SST_CODEC_TYPE_eAACP, +}; + +enum stream_type { + SST_STREAM_TYPE_NONE = 0, + SST_STREAM_TYPE_MUSIC = 1, +}; + +struct snd_pcm_params { + u16 codec; /* codec type */ + u8 num_chan; /* 1=Mono, 2=Stereo */ + u8 pcm_wd_sz; /* 16/24 - bit*/ + u32 reserved; /* Bitrate in bits per second */ + u32 sfreq; /* Sampling rate in Hz */ + u8 use_offload_path; + u8 reserved2; + u16 reserved3; + u8 channel_map[8]; +} __packed; + +/* MP3 Music Parameters Message */ +struct snd_mp3_params { + u16 codec; + u8 num_chan; /* 1=Mono, 2=Stereo */ + u8 pcm_wd_sz; /* 16/24 - bit*/ + u8 crc_check; /* crc_check - disable (0) or enable (1) */ + u8 reserved1; /* unused*/ + u16 reserved2; /* Unused */ +} __packed; + +#define AAC_BIT_STREAM_ADTS 0 +#define AAC_BIT_STREAM_ADIF 1 +#define AAC_BIT_STREAM_RAW 2 + +/* AAC Music Parameters Message */ +struct snd_aac_params { + u16 codec; + u8 num_chan; /* 1=Mono, 2=Stereo*/ + u8 pcm_wd_sz; /* 16/24 - bit*/ + u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */ + u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */ + u16 reser2; + u32 externalsr; /*sampling rate of basic AAC raw bit stream*/ + u8 sbr_signalling;/*disable/enable/set automode the SBR tool.AAC+*/ + u8 reser1; + u16 reser3; +} __packed; + +/* WMA Music Parameters Message */ +struct snd_wma_params { + u16 codec; + u8 num_chan; /* 1=Mono, 2=Stereo */ + u8 pcm_wd_sz; /* 16/24 - bit*/ + u32 brate; /* Use the hard coded value. */ + u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */ + u32 channel_mask; /* Channel Mask */ + u16 format_tag; /* Format Tag */ + u16 block_align; /* packet size */ + u16 wma_encode_opt;/* Encoder option */ + u8 op_align; /* op align 0- 16 bit, 1- MSB, 2 LSB */ + u8 reserved; /* reserved */ +} __packed; + +/* Codec params struture */ +union snd_sst_codec_params { + struct snd_pcm_params pcm_params; + struct snd_mp3_params mp3_params; + struct snd_aac_params aac_params; + struct snd_wma_params wma_params; +} __packed; + +/* Address and size info of a frame buffer */ +struct sst_address_info { + u32 addr; /* Address at IA */ + u32 size; /* Size of the buffer */ +}; + +struct snd_sst_alloc_params_ext { + struct sst_address_info ring_buf_info[8]; + u8 sg_count; + u8 reserved; + u16 reserved2; + u32 frag_size; /*Number of samples after which period elapsed + message is sent valid only if path = 0*/ +} __packed; + +struct snd_sst_stream_params { + union snd_sst_codec_params uc; +} __packed; + +struct snd_sst_params { + u32 stream_id; + u8 codec; + u8 ops; + u8 stream_type; + u8 device_type; + struct snd_sst_stream_params sparams; + struct snd_sst_alloc_params_ext aparams; +}; + +#endif /* __SST_DSP_H__ */ diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index d34563b..a263cbe 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c @@ -1,7 +1,7 @@ /* * sst_platform.c - Intel MID Platform driver * - * Copyright (C) 2010 Intel Corp + * Copyright (C) 2010-2012 Intel Corp * Author: Vinod Koul vinod.koul@intel.com * Author: Harsha Priya priya.harsha@intel.com * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -32,6 +32,7 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/compress_driver.h> #include "sst_platform.h"
static struct sst_device *sst; @@ -152,6 +153,16 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S24_LE, }, }, +{ + .name = "Compress-cpu-dai", + .compress_dai = 1, + .playback = { + .channels_min = SST_STEREO, + .channels_max = SST_STEREO, + .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, };
/* helper functions */ @@ -463,8 +474,199 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) } return retval; } + +/* compress stream operations */ +static void sst_compr_fragment_elapsed(void *arg) +{ + struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg; + + pr_debug("fragment elapsed by driver\n"); + if (cstream) + snd_compr_fragment_elapsed(cstream); +} + +static int sst_platform_compr_open(struct snd_compr_stream *cstream) +{ + + int ret_val = 0; + struct snd_compr_runtime *runtime = cstream->runtime; + struct sst_runtime_stream *stream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + spin_lock_init(&stream->status_lock); + + /* get the sst ops */ + if (!sst || !try_module_get(sst->dev->driver->owner)) { + pr_err("no device available to run\n"); + ret_val = -ENODEV; + goto out_ops; + } + stream->compr_ops = sst->compr_ops; + + stream->id = 0; + sst_set_stream_status(stream, SST_PLATFORM_INIT); + runtime->private_data = stream; + return 0; +out_ops: + kfree(stream); + return ret_val; +} + +static int sst_platform_compr_free(struct snd_compr_stream *cstream) +{ + struct sst_runtime_stream *stream; + int ret_val = 0, str_id; + + stream = cstream->runtime->private_data; + /*need to check*/ + str_id = stream->id; + if (str_id) + ret_val = stream->compr_ops->close(str_id); + module_put(sst->dev->driver->owner); + kfree(stream); + pr_debug("%s: %d\n", __func__, ret_val); + return 0; +} + +static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct sst_runtime_stream *stream; + int retval; + struct snd_sst_params str_params; + struct sst_compress_cb cb; + + stream = cstream->runtime->private_data; + /* construct fw structure for this*/ + memset(&str_params, 0, sizeof(str_params)); + + str_params.ops = STREAM_OPS_PLAYBACK; + str_params.stream_type = SST_STREAM_TYPE_MUSIC; + str_params.device_type = SND_SST_DEVICE_COMPRESS; + + switch (params->codec.id) { + case SND_AUDIOCODEC_MP3: { + str_params.codec = SST_CODEC_TYPE_MP3; + str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3; + str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in; + str_params.sparams.uc.mp3_params.pcm_wd_sz = 16; + break; + } + + case SND_AUDIOCODEC_AAC: { + str_params.codec = SST_CODEC_TYPE_AAC; + str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC; + str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in; + str_params.sparams.uc.aac_params.pcm_wd_sz = 16; + if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS) + str_params.sparams.uc.aac_params.bs_format = + AAC_BIT_STREAM_ADTS; + else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW) + str_params.sparams.uc.aac_params.bs_format = + AAC_BIT_STREAM_RAW; + else { + pr_err("Undefined format%d\n", params->codec.format); + return -EINVAL; + } + str_params.sparams.uc.aac_params.externalsr = + params->codec.sample_rate; + break; + } + + default: + pr_err("codec not supported, id =%d\n", params->codec.id); + return -EINVAL; + } + + str_params.aparams.ring_buf_info[0].addr = + virt_to_phys(cstream->runtime->buffer); + str_params.aparams.ring_buf_info[0].size = + cstream->runtime->buffer_size; + str_params.aparams.sg_count = 1; + str_params.aparams.frag_size = cstream->runtime->fragment_size; + + cb.param = cstream; + cb.compr_cb = sst_compr_fragment_elapsed; + + retval = stream->compr_ops->open(&str_params, &cb); + if (retval < 0) { + pr_err("stream allocation failed %d\n", retval); + return retval; + } + + stream->id = retval; + return 0; +} + +static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + struct sst_runtime_stream *stream = + cstream->runtime->private_data; + + return stream->compr_ops->control(cmd, stream->id); +} + +static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp) +{ + struct sst_runtime_stream *stream; + + stream = cstream->runtime->private_data; + stream->compr_ops->tstamp(stream->id, tstamp); + tstamp->byte_offset = tstamp->copied_total % + (u32)cstream->runtime->buffer_size; + pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); + return 0; +} + +static int sst_platform_compr_ack(struct snd_compr_stream *cstream, + size_t bytes) +{ + struct sst_runtime_stream *stream; + + stream = cstream->runtime->private_data; + stream->compr_ops->ack(stream->id, (unsigned long)bytes); + stream->bytes_written += bytes; + + return 0; +} + +static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream, + struct snd_compr_caps *caps) +{ + struct sst_runtime_stream *stream = + cstream->runtime->private_data; + + return stream->compr_ops->get_caps(caps); +} + +static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream, + struct snd_compr_codec_caps *codec) +{ + struct sst_runtime_stream *stream = + cstream->runtime->private_data; + + return stream->compr_ops->get_codec_caps(codec); +} + +static struct snd_compr_ops sst_platform_compr_ops = { + + .open = sst_platform_compr_open, + .free = sst_platform_compr_free, + .set_params = sst_platform_compr_set_params, + .trigger = sst_platform_compr_trigger, + .pointer = sst_platform_compr_pointer, + .ack = sst_platform_compr_ack, + .get_caps = sst_platform_compr_get_caps, + .get_codec_caps = sst_platform_compr_get_codec_caps, +}; + static struct snd_soc_platform_driver sst_soc_platform_drv = { .ops = &sst_platform_ops, + .compr_ops = &sst_platform_compr_ops, .pcm_new = sst_pcm_new, .pcm_free = sst_pcm_free, }; diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h index f04f4f7..d61c5d5 100644 --- a/sound/soc/mid-x86/sst_platform.h +++ b/sound/soc/mid-x86/sst_platform.h @@ -27,6 +27,8 @@ #ifndef __SST_PLATFORMDRV_H__ #define __SST_PLATFORMDRV_H__
+#include "sst_dsp.h" + #define SST_MONO 1 #define SST_STEREO 2 #define SST_MAX_CAP 5 @@ -42,7 +44,6 @@ #define SST_MIN_PERIODS 2 #define SST_MAX_PERIODS (1024*2) #define SST_FIFO_SIZE 0 -#define SST_CODEC_TYPE_PCM 1
struct pcm_stream_info { int str_id; @@ -83,6 +84,7 @@ enum sst_audio_device_type { SND_SST_DEVICE_VIBRA, SND_SST_DEVICE_HAPTIC, SND_SST_DEVICE_CAPTURE, + SND_SST_DEVICE_COMPRESS, };
/* PCM Parameters */ @@ -107,6 +109,24 @@ struct sst_stream_params { struct sst_pcm_params sparams; };
+struct sst_compress_cb { + void *param; + void (*compr_cb)(void *param); +}; + +struct compress_sst_ops { + const char *name; + int (*open) (struct snd_sst_params *str_params, + struct sst_compress_cb *cb); + int (*control) (unsigned int cmd, unsigned int str_id); + int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp); + int (*ack) (unsigned int str_id, unsigned long bytes); + int (*close) (unsigned int str_id); + int (*get_caps) (struct snd_compr_caps *caps); + int (*get_codec_caps) (struct snd_compr_codec_caps *codec); + +}; + struct sst_ops { int (*open) (struct sst_stream_params *str_param); int (*device_control) (int cmd, void *arg); @@ -115,8 +135,11 @@ struct sst_ops {
struct sst_runtime_stream { int stream_status; + unsigned int id; + size_t bytes_written; struct pcm_stream_info stream_info; struct sst_ops *ops; + struct compress_sst_ops *compr_ops; spinlock_t status_lock; };
@@ -124,6 +147,7 @@ struct sst_device { char *name; struct device *dev; struct sst_ops *ops; + struct compress_sst_ops *compr_ops; };
int sst_register_dsp(struct sst_device *sst);
participants (2)
-
Mark Brown
-
Vinod Koul