diff options
| -rw-r--r-- | include/sound/apr_audio-v2.h | 5 | ||||
| -rw-r--r-- | include/sound/q6asm-v2.h | 3 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 209 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 211 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/msm-qti-pp-config.c | 130 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/msm-qti-pp-config.h | 14 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/q6asm.c | 92 |
7 files changed, 662 insertions, 2 deletions
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 06c273252484..a5ba1496eef7 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -443,6 +443,11 @@ struct adm_param_data_v5 { */ } __packed; +#define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213 +#define ASM_STREAM_PP_EVENT 0x00013214 +#define DSP_STREAM_CMD "ADSP Stream Cmd" +#define DSP_STREAM_CALLBACK "ADSP Stream Callback Event" + /* set customized mixing on matrix mixer */ #define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344 struct adm_cmd_set_pspd_mtmx_strtr_params_v5 { diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index d077827647b5..29707b26644a 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -618,6 +618,9 @@ int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp); int q6asm_send_audio_effects_params(struct audio_client *ac, char *params, uint32_t params_length); +int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode, + void *param, uint32_t params_length); + /* Client can set the IO mode to either AIO/SIO mode */ int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode); diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 8e986a74ffff..2929ea0d735b 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -45,6 +45,7 @@ #include <sound/msm-dts-eagle.h> #include "msm-pcm-routing-v2.h" +#include "msm-qti-pp-config.h" #define DSP_PP_BUFFERING_IN_MSEC 25 #define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC 150 @@ -543,12 +544,19 @@ static void compr_event_handler(uint32_t opcode, unsigned long flags; uint64_t read_size; uint32_t *buff_addr; + struct snd_soc_pcm_runtime *rtd; + int ret = 0; if (!prtd) { pr_err("%s: prtd is NULL\n", __func__); return; } cstream = prtd->cstream; + if (!cstream) { + pr_err("%s: cstream is NULL\n", __func__); + return; + } + ac = prtd->audio_client; /* @@ -716,6 +724,23 @@ static void compr_event_handler(uint32_t opcode, prtd->gapless_state.gapless_transition = 0; spin_unlock_irqrestore(&prtd->lock, flags); break; + case ASM_STREAM_PP_EVENT: + pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__); + rtd = cstream->private_data; + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + return; + } + + ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, + payload); + if (ret) { + pr_err("%s: failed to inform mixer ctrl. err = %d\n", + __func__, ret); + return; + } + + break; case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY: case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: { pr_debug("ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY\n"); @@ -815,6 +840,10 @@ static void compr_event_handler(uint32_t opcode, } atomic_set(&prtd->close, 0); break; + case ASM_STREAM_CMD_REGISTER_PP_EVENTS: + pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:", + __func__); + break; default: break; } @@ -3578,6 +3607,65 @@ end: return rc; } +static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + unsigned long fe_id = kcontrol->private_value; + struct msm_compr_pdata *pdata = (struct msm_compr_pdata *) + snd_soc_component_get_drvdata(comp); + struct snd_compr_stream *cstream = NULL; + struct msm_compr_audio *prtd; + int ret = 0, param_length = 0; + + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received invalid fe_id %lu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + cstream = pdata->cstream[fe_id]; + if (cstream == NULL) { + pr_err("%s cstream is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + prtd = cstream->runtime->private_data; + if (!prtd) { + pr_err("%s: prtd is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + if (prtd->audio_client == NULL) { + pr_err("%s: audio_client is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + memcpy(¶m_length, ucontrol->value.bytes.data, + sizeof(param_length)); + if ((param_length + sizeof(param_length)) + >= sizeof(ucontrol->value.bytes.data)) { + pr_err("%s param length=%d exceeds limit", + __func__, param_length); + ret = -EINVAL; + goto done; + } + + ret = q6asm_send_stream_cmd(prtd->audio_client, + ASM_STREAM_CMD_REGISTER_PP_EVENTS, + ucontrol->value.bytes.data + sizeof(param_length), + param_length); + if (ret < 0) + pr_err("%s: failed to register pp event. err = %d\n", + __func__, ret); +done: + return ret; +} + static int msm_compr_gapless_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3854,6 +3942,117 @@ static int msm_compr_add_query_audio_effect_control( return 0; } +static int msm_compr_add_audio_adsp_stream_cmd_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CMD; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_cmd_info, + .put = msm_compr_adsp_stream_cmd_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str; + fe_audio_adsp_stream_cmd_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_audio_adsp_stream_cmd_config_control, + ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control)); + if (ret < 0) + pr_err("%s: failed to add ctl %s. err = %d\n", + __func__, mixer_str, ret); + + kfree(mixer_str); +done: + return ret; +} + +static int msm_compr_add_audio_adsp_stream_callback_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol *kctl; + + struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_callback_info, + .get = msm_adsp_stream_callback_get, + .put = msm_adsp_stream_callback_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_audio_adsp_callback_config_control[0].name = mixer_str; + fe_audio_adsp_callback_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_audio_adsp_callback_config_control, + ARRAY_SIZE(fe_audio_adsp_callback_config_control)); + if (ret < 0) { + pr_err("%s: failed to add ctl %s. err = %d\n", + __func__, mixer_str, ret); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl->private_data = NULL; +free_mixer_str: + kfree(mixer_str); +done: + return ret; +} + static int msm_compr_add_dec_runtime_params_control( struct snd_soc_pcm_runtime *rtd) { @@ -4048,6 +4247,16 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add Compr Audio Effects Control\n", __func__); + rc = msm_compr_add_audio_adsp_stream_cmd_control(rtd); + if (rc) + pr_err("%s: Could not add Compr ADSP Stream Cmd Control\n", + __func__); + + rc = msm_compr_add_audio_adsp_stream_callback_control(rtd); + if (rc) + pr_err("%s: Could not add Compr ADSP Stream Callback Control\n", + __func__); + rc = msm_compr_add_query_audio_effect_control(rtd); if (rc) pr_err("%s: Could not add Compr Query Audio Effect Control\n", diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 7928c3791f96..73eadfa4eebb 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -37,6 +37,7 @@ #include "msm-pcm-q6-v2.h" #include "msm-pcm-routing-v2.h" +#include "msm-qti-pp-config.h" enum stream_state { IDLE = 0, @@ -147,6 +148,8 @@ static void event_handler(uint32_t opcode, uint32_t idx = 0; uint32_t size = 0; uint8_t buf_index; + struct snd_soc_pcm_runtime *rtd; + int ret = 0; switch (opcode) { case ASM_DATA_EVENT_WRITE_DONE_V2: { @@ -223,6 +226,29 @@ static void event_handler(uint32_t opcode, } break; } + case ASM_STREAM_PP_EVENT: { + pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__); + if (!substream) { + pr_err("%s: substream is NULL.\n", __func__); + return; + } + + rtd = substream->private_data; + if (!rtd) { + pr_err("%s: rtd is NULL\n", __func__); + return; + } + + ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, + payload); + if (ret) { + pr_err("%s: failed to inform mixer ctl. err = %d\n", + __func__, ret); + return; + } + + break; + } case APR_BASIC_RSP_RESULT: { switch (payload[0]) { case ASM_SESSION_CMD_RUN_V2: @@ -252,6 +278,10 @@ static void event_handler(uint32_t opcode, } atomic_set(&prtd->start, 1); break; + case ASM_STREAM_CMD_REGISTER_PP_EVENTS: + pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:", + __func__); + break; default: pr_debug("%s:Payload = [0x%x]stat[0x%x]\n", __func__, payload[0], payload[1]); @@ -1036,6 +1066,177 @@ static struct snd_pcm_ops msm_pcm_ops = { .mmap = msm_pcm_mmap, }; +static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol); + struct snd_soc_platform *platform = snd_soc_component_to_platform(pcm); + struct msm_plat_data *pdata = dev_get_drvdata(platform->dev); + struct snd_pcm_substream *substream; + struct msm_audio *prtd; + int ret = 0, param_length = 0; + + if (!pdata) { + pr_err("%s pdata is NULL\n", __func__); + ret = -ENODEV; + goto done; + } + + substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (!substream) { + pr_err("%s substream not found\n", __func__); + ret = -EINVAL; + goto done; + } + + if (!substream->runtime) { + pr_err("%s substream runtime not found\n", __func__); + ret = -EINVAL; + goto done; + } + + prtd = substream->runtime->private_data; + if (prtd->audio_client == NULL) { + pr_err("%s prtd is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + memcpy(¶m_length, ucontrol->value.bytes.data, + sizeof(param_length)); + if ((param_length + sizeof(param_length)) + >= sizeof(ucontrol->value.bytes.data)) { + pr_err("%s param length=%d exceeds limit", + __func__, param_length); + ret = -EINVAL; + goto done; + } + + ret = q6asm_send_stream_cmd(prtd->audio_client, + ASM_STREAM_CMD_REGISTER_PP_EVENTS, + ucontrol->value.bytes.data + sizeof(param_length), + param_length); + if (ret < 0) + pr_err("%s: failed to register pp event. err = %d\n", + __func__, ret); +done: + return ret; +} + +static int msm_pcm_add_audio_adsp_stream_cmd_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CMD; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_cmd_info, + .put = msm_pcm_adsp_stream_cmd_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s rtd is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str; + fe_audio_adsp_stream_cmd_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("Registering new mixer ctl %s\n", mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_audio_adsp_stream_cmd_config_control, + ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control)); + if (ret < 0) + pr_err("%s: failed add ctl %s. err = %d\n", + __func__, mixer_str, ret); + + kfree(mixer_str); +done: + return ret; +} + +static int msm_pcm_add_audio_adsp_stream_callback_control( + struct snd_soc_pcm_runtime *rtd) +{ + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct snd_kcontrol *kctl; + + struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_adsp_stream_callback_info, + .get = msm_adsp_stream_callback_get, + .put = msm_adsp_stream_callback_put, + .private_value = 0, + } + }; + + if (!rtd) { + pr_err("%s NULL rtd\n", __func__); + ret = -EINVAL; + goto done; + } + + pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n", + __func__, rtd->dai_link->name, rtd->dai_link->be_id, + rtd->dai_link->cpu_dai_name, rtd->pcm->device); + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) { + ret = -ENOMEM; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device); + fe_audio_adsp_callback_config_control[0].name = mixer_str; + fe_audio_adsp_callback_config_control[0].private_value = + rtd->dai_link->be_id; + pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str); + ret = snd_soc_add_platform_controls(rtd->platform, + fe_audio_adsp_callback_config_control, + ARRAY_SIZE(fe_audio_adsp_callback_config_control)); + if (ret < 0) { + pr_err("%s: failed to add ctl %s. err = %d\n", + __func__, mixer_str, ret); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str); + ret = -EINVAL; + goto free_mixer_str; + } + + kctl->private_data = NULL; +free_mixer_str: + kfree(mixer_str); +done: + return ret; +} + static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume) { int rc = 0; @@ -1549,6 +1750,16 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) pr_err("%s: Could not add pcm Compress Control %d\n", __func__, ret); + ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd); + if (ret) + pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n", + __func__); + + ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd); + if (ret) + pr_err("%s: Could not add pcm ADSP Stream Callback Control\n", + __func__); + return ret; } diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index 6f463c079f19..d4e78604f868 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -817,6 +817,136 @@ static int msm_qti_pp_asphere_set(struct snd_kcontrol *kcontrol, return 0; } + +int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, + const char *mixer_ctl_name, + uint32_t *payload) +{ + /* adsp pp event notifier */ + struct snd_kcontrol *kctl; + struct snd_ctl_elem_value control; + uint32_t payload_size = 0; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + + if (!rtd || !payload) { + pr_err("%s: %s is NULL\n", __func__, + (!rtd) ? "rtd" : "payload"); + ret = -EINVAL; + goto done; + } + + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; + mixer_str = kzalloc(ctl_len, GFP_ATOMIC); + if (!mixer_str) { + ret = -EINVAL; + goto done; + } + + snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, + rtd->pcm->device); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + kfree(mixer_str); + if (!kctl) { + pr_err("%s: failed to get kctl.\n", __func__); + ret = -EINVAL; + goto done; + } + + control.id = kctl->id; + payload_size = payload[0]; + /* Copy complete payload */ + memcpy(control.value.bytes.data, (void *)payload, + sizeof(payload_size) + payload_size); + kctl->put(kctl, &control); + if (rtd->card->snd_card == NULL) { + pr_err("%s: snd_card is null.\n", __func__); + ret = -EINVAL; + goto done; + } + + snd_ctl_notify(rtd->card->snd_card, + SNDRV_CTL_EVENT_MASK_INFO, + &control.id); +done: + return ret; +} + +int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = 512; + + return 0; +} + +int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t payload_size = 0, last_payload_size = 0; + + /* fetch payload size in first four bytes */ + memcpy(&payload_size, ucontrol->value.bytes.data, sizeof(uint32_t)); + + if (kcontrol->private_data == NULL) { + /* buffer is empty */ + kcontrol->private_data = + kzalloc(payload_size + sizeof(payload_size), + GFP_ATOMIC); + if (kcontrol->private_data == NULL) + return -ENOMEM; + } else { + memcpy(&last_payload_size, kcontrol->private_data, + sizeof(uint32_t)); + if (last_payload_size < payload_size) { + /* new payload size exceeds old one. + * reallocate buffer + */ + kfree(kcontrol->private_data); + kcontrol->private_data = + kzalloc(payload_size + sizeof(payload_size), + GFP_ATOMIC); + if (kcontrol->private_data == NULL) + return -ENOMEM; + } + } + + memcpy(kcontrol->private_data, ucontrol->value.bytes.data, + sizeof(uint32_t) + payload_size); + + return 0; +} + +int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + uint32_t payload_size = 0; + + if (kcontrol->private_data == NULL) { + pr_err("%s: ASM Stream PP Event Data Unavailable\n", __func__); + return -EINVAL; + } + + memcpy(&payload_size, kcontrol->private_data, sizeof(uint32_t)); + memcpy(ucontrol->value.bytes.data, kcontrol->private_data, + sizeof(uint32_t) + payload_size); + kfree(kcontrol->private_data); + kcontrol->private_data = NULL; + + return 0; +} + +int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = 512; + + return 0; +} + static int msm_multichannel_ec_primary_mic_ch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h index f8a1da5e7702..70ce20fbd8f8 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. 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 and * only version 2 as published by the Free Software Foundation. @@ -13,7 +13,17 @@ #define _MSM_QTI_PP_H_ #include <sound/soc.h> - +int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, + const char *mixer_ctl_name, + uint32_t *payload); +int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); #ifdef CONFIG_QTI_PP void msm_qti_pp_send_eq_values(int fedai_id); int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, int copp_idx, diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 79f27852391f..1ca99c3f9115 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1094,6 +1094,65 @@ fail: return NULL; } +int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode, + void *param, uint32_t params_length) +{ + char *asm_params = NULL; + struct apr_hdr hdr; + int sz, rc; + + if (!param || !ac) { + pr_err("%s: %s is NULL\n", __func__, + (!param) ? "param" : "ac"); + rc = -EINVAL; + goto done; + } + + sz = sizeof(struct apr_hdr) + params_length; + asm_params = kzalloc(sz, GFP_KERNEL); + if (!asm_params) { + rc = -ENOMEM; + goto done; + } + + q6asm_add_hdr_async(ac, &hdr, sizeof(struct apr_hdr) + + params_length, TRUE); + atomic_set(&ac->cmd_state_pp, -1); + hdr.opcode = opcode; + memcpy(asm_params, &hdr, sizeof(struct apr_hdr)); + memcpy(asm_params + sizeof(struct apr_hdr), + param, params_length); + rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params); + if (rc < 0) { + pr_err("%s: audio adsp pp register failed\n", __func__); + rc = -EINVAL; + goto fail_send_param; + } + + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state_pp) >= 0), 1 * HZ); + if (!rc) { + pr_err("%s: timeout, adsp pp register\n", __func__); + rc = -ETIMEDOUT; + goto fail_send_param; + } + + if (atomic_read(&ac->cmd_state_pp) > 0) { + pr_err("%s: DSP returned error[%s] adsp pp register\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state_pp))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state_pp)); + goto fail_send_param; + } + + rc = 0; +fail_send_param: + kfree(asm_params); +done: + return rc; +} + struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv) { struct audio_client *ac; @@ -1615,6 +1674,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) int32_t ret = 0; union asm_token_struct asm_token; uint8_t buf_index; + char *pp_event_package = NULL; + uint32_t payload_size = 0; if (ac == NULL) { pr_err("%s: ac NULL\n", __func__); @@ -1797,6 +1858,17 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) data->payload_size); } break; + case ASM_STREAM_CMD_REGISTER_PP_EVENTS: + pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS session %d opcode 0x%x token 0x%x src %d dest %d\n", + __func__, ac->session, + data->opcode, data->token, + data->src_port, data->dest_port); + if (payload[1] != 0) + pr_err("%s: ASM get param error = %d, resuming\n", + __func__, payload[1]); + atomic_set(&ac->cmd_state_pp, payload[1]); + wake_up(&ac->cmd_wait); + break; default: pr_debug("%s: command[0x%x] not expecting rsp\n", __func__, payload[0]); @@ -1967,6 +2039,26 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2: q6asm_process_mtmx_get_param_rsp(ac, (void *) payload); break; + case ASM_STREAM_PP_EVENT: + pr_debug("%s: ASM_STREAM_PP_EVENT payload[0][0x%x] payload[1][0x%x]", + __func__, payload[0], payload[1]); + /* repack payload for asm_stream_pp_event + * package is composed of size + actual payload + */ + payload_size = data->payload_size; + pp_event_package = + kzalloc(payload_size + sizeof(payload_size), + GFP_ATOMIC); + if (!pp_event_package) + return -ENOMEM; + memcpy((void *)pp_event_package, + &payload_size, sizeof(payload_size)); + memcpy((void *)pp_event_package + sizeof(payload_size), + data->payload, payload_size); + ac->cb(data->opcode, data->token, + (void *)pp_event_package, ac->priv); + kfree(pp_event_package); + return 0; case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2: pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n", __func__, ac->session, payload[0], payload[2], |
