diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 021b81105c42..40cd9a752c53 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -15,6 +15,7 @@ #define _APR_AUDIO_V2_H_ #include +#include /* size of header needed for passing data out of band */ #define APR_CMD_OB_HDR_SZ 12 @@ -447,6 +448,18 @@ struct adm_param_data_v5 { #define ASM_STREAM_PP_EVENT 0x00013214 #define DSP_STREAM_CMD "ADSP Stream Cmd" #define DSP_STREAM_CALLBACK "ADSP Stream Callback Event" +#define DSP_STREAM_CALLBACK_QUEUE_SIZE 1024 + +struct dsp_stream_callback_list { + struct list_head list; + struct msm_adsp_event_data event; +}; + +struct dsp_stream_callback_prtd { + uint16_t event_count; + struct list_head event_queue; + spinlock_t prtd_spin_lock; +}; /* set customized mixing on matrix mixer */ #define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344 diff --git a/include/uapi/linux/msm_audio.h b/include/uapi/linux/msm_audio.h index 36b66c7cde76..f306949eb5e6 100644 --- a/include/uapi/linux/msm_audio.h +++ b/include/uapi/linux/msm_audio.h @@ -460,4 +460,14 @@ struct msm_hwacc_effects_config { __s32 topology; }; +#define ADSP_STREAM_PP_EVENT 0 +#define ADSP_STREAM_ENCDEC_EVENT 1 +#define ADSP_STREAM_EVENT_MAX 2 + +struct msm_adsp_event_data { + __u32 event_type; + __u32 payload_len; + __u8 payload[0]; +}; + #endif diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index a1cb18f53380..426b4d0b0a35 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -749,8 +749,7 @@ static void compr_event_handler(uint32_t opcode, return; } - ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, - payload); + ret = msm_adsp_inform_mixer_ctl(rtd, payload); if (ret) { pr_err("%s: failed to inform mixer ctrl. err = %d\n", __func__, ret); @@ -1583,6 +1582,7 @@ static int msm_compr_playback_open(struct snd_compr_stream *cstream) pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session); prtd->audio_client->perf_mode = false; prtd->session_id = prtd->audio_client->session; + msm_adsp_init_mixer_ctl_pp_event_queue(rtd); return 0; } @@ -1738,7 +1738,7 @@ static int msm_compr_playback_free(struct snd_compr_stream *cstream) q6asm_audio_client_buf_free_contiguous(dir, ac); q6asm_audio_client_free(ac); - + msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd); kfree(pdata->audio_effects[soc_prtd->dai_link->be_id]); pdata->audio_effects[soc_prtd->dai_link->be_id] = NULL; kfree(pdata->dec_params[soc_prtd->dai_link->be_id]); @@ -3978,7 +3978,6 @@ static int msm_compr_add_audio_adsp_stream_callback_control( .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, } }; @@ -4019,6 +4018,7 @@ static int msm_compr_add_audio_adsp_stream_callback_control( } kctl->private_data = NULL; + free_mixer_str: kfree(mixer_str); done: diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 73eadfa4eebb..8f43aee3974c 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -239,8 +239,7 @@ static void event_handler(uint32_t opcode, return; } - ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK, - payload); + ret = msm_adsp_inform_mixer_ctl(rtd, payload); if (ret) { pr_err("%s: failed to inform mixer ctl. err = %d\n", __func__, ret); @@ -691,6 +690,7 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) prtd->set_channel_map = false; prtd->reset_event = false; runtime->private_data = prtd; + msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd); return 0; } @@ -833,6 +833,7 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) } msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id, SNDRV_PCM_STREAM_PLAYBACK); + msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd); kfree(prtd); runtime->private_data = NULL; @@ -1187,7 +1188,6 @@ static int msm_pcm_add_audio_adsp_stream_callback_control( .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, } }; @@ -1231,6 +1231,7 @@ static int msm_pcm_add_audio_adsp_stream_callback_control( } kctl->private_data = NULL; + free_mixer_str: kfree(mixer_str); done: diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c index d4e78604f868..cac28f43e5ae 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c @@ -45,21 +45,6 @@ enum { EQ_BAND_MAX, }; -struct msm_audio_eq_band { - uint16_t band_idx; /* The band index, 0 .. 11 */ - uint32_t filter_type; /* Filter band type */ - uint32_t center_freq_hz; /* Filter band center frequency */ - uint32_t filter_gain; /* Filter band initial gain (dB) */ - /* Range is +12 dB to -12 dB with 1dB increments. */ - uint32_t q_factor; -} __packed; - -struct msm_audio_eq_stream_config { - uint32_t enable; /* Number of consequtive bands specified */ - uint32_t num_bands; - struct msm_audio_eq_band eq_bands[EQ_BAND_MAX]; -} __packed; - /* Audio Sphere data structures */ struct msm_audio_pp_asphere_state_s { uint32_t enabled; @@ -817,18 +802,133 @@ static int msm_qti_pp_asphere_set(struct snd_kcontrol *kcontrol, return 0; } +int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_kcontrol *kctl; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + + 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 = -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; + } + + if (kctl->private_data != NULL) { + pr_err("%s: kctl_prtd is not NULL at initialization.\n", + __func__); + return -EINVAL; + } + + kctl_prtd = kzalloc(sizeof(struct dsp_stream_callback_prtd), + GFP_KERNEL); + if (!kctl_prtd) { + ret = -ENOMEM; + goto done; + } + + spin_lock_init(&kctl_prtd->prtd_spin_lock); + INIT_LIST_HEAD(&kctl_prtd->event_queue); + kctl_prtd->event_count = 0; + kctl->private_data = kctl_prtd; + +done: + return ret; +} + +int msm_adsp_clean_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_kcontrol *kctl; + const char *deviceNo = "NN"; + char *mixer_str = NULL; + int ctl_len = 0, ret = 0; + struct dsp_stream_callback_list *node, *n; + unsigned long spin_flags; + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + + 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 = -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; + } + + kctl_prtd = (struct dsp_stream_callback_prtd *) + kctl->private_data; + if (kctl_prtd != NULL) { + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + /* clean the queue */ + list_for_each_entry_safe(node, n, + &kctl_prtd->event_queue, list) { + list_del(&node->list); + kctl_prtd->event_count--; + pr_debug("%s: %d remaining events after del.\n", + __func__, kctl_prtd->event_count); + kfree(node); + } + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + } + + kfree(kctl_prtd); + kctl->private_data = NULL; + +done: + return ret; +} 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; + struct dsp_stream_callback_list *new_event; + struct dsp_stream_callback_list *oldest_event; + unsigned long spin_flags; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + struct msm_adsp_event_data *event_data = NULL; + const char *mixer_ctl_name = DSP_STREAM_CALLBACK; + struct snd_ctl_elem_info kctl_info; if (!rtd || !payload) { pr_err("%s: %s is NULL\n", __func__, @@ -837,6 +937,12 @@ int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, goto done; } + if (rtd->card->snd_card == NULL) { + pr_err("%s: snd_card is null.\n", __func__); + ret = -EINVAL; + goto done; + } + ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1; mixer_str = kzalloc(ctl_len, GFP_ATOMIC); if (!mixer_str) { @@ -854,21 +960,59 @@ int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, 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__); + event_data = (struct msm_adsp_event_data *)payload; + kctl->info(kctl, &kctl_info); + if (sizeof(struct msm_adsp_event_data) + + event_data->payload_len > kctl_info.count) { + pr_err("%s: payload length exceeds limit of %u bytes.\n", + __func__, kctl_info.count); ret = -EINVAL; goto done; } + kctl_prtd = (struct dsp_stream_callback_prtd *) + kctl->private_data; + if (kctl_prtd == NULL) { + /* queue is not initialized */ + ret = -EINVAL; + pr_err("%s: event queue is not initialized.\n", __func__); + goto done; + } + + new_event = kzalloc(sizeof(struct dsp_stream_callback_list) + + event_data->payload_len, + GFP_ATOMIC); + if (new_event == NULL) { + ret = -ENOMEM; + goto done; + } + memcpy((void *)&new_event->event, (void *)payload, + event_data->payload_len + + sizeof(struct msm_adsp_event_data)); + + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + while (kctl_prtd->event_count >= DSP_STREAM_CALLBACK_QUEUE_SIZE) { + pr_info("%s: queue of size %d is full. delete oldest one.\n", + __func__, DSP_STREAM_CALLBACK_QUEUE_SIZE); + oldest_event = list_first_entry(&kctl_prtd->event_queue, + struct dsp_stream_callback_list, list); + pr_info("%s: event deleted: type %d length %d\n", + __func__, oldest_event->event.event_type, + oldest_event->event.payload_len); + list_del(&oldest_event->list); + kctl_prtd->event_count--; + kfree(oldest_event); + } + + list_add_tail(&new_event->list, &kctl_prtd->event_queue); + kctl_prtd->event_count++; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + + control.id = kctl->id; snd_ctl_notify(rtd->card->snd_card, SNDRV_CTL_EVENT_MASK_INFO, &control.id); + done: return ret; } @@ -877,44 +1021,8 @@ 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); + uinfo->count = + sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data); return 0; } @@ -923,26 +1031,53 @@ int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { uint32_t payload_size = 0; + struct dsp_stream_callback_list *oldest_event; + unsigned long spin_flags; + struct dsp_stream_callback_prtd *kctl_prtd = NULL; + int ret = 0; - if (kcontrol->private_data == NULL) { - pr_err("%s: ASM Stream PP Event Data Unavailable\n", __func__); - return -EINVAL; + kctl_prtd = (struct dsp_stream_callback_prtd *) + kcontrol->private_data; + if (kctl_prtd == NULL) { + pr_err("%s: ASM Stream PP event queue is not initialized.\n", + __func__); + ret = -EINVAL; + goto done; } - 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; + spin_lock_irqsave(&kctl_prtd->prtd_spin_lock, spin_flags); + pr_debug("%s: %d events in queue.\n", __func__, kctl_prtd->event_count); + if (list_empty(&kctl_prtd->event_queue)) { + pr_err("%s: ASM Stream PP event queue is empty.\n", __func__); + ret = -EINVAL; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + goto done; + } - return 0; + oldest_event = list_first_entry(&kctl_prtd->event_queue, + struct dsp_stream_callback_list, list); + list_del(&oldest_event->list); + kctl_prtd->event_count--; + spin_unlock_irqrestore(&kctl_prtd->prtd_spin_lock, spin_flags); + + payload_size = oldest_event->event.payload_len; + pr_debug("%s: event fetched: type %d length %d\n", + __func__, oldest_event->event.event_type, + oldest_event->event.payload_len); + memcpy(ucontrol->value.bytes.data, &oldest_event->event, + sizeof(struct msm_adsp_event_data) + payload_size); + kfree(oldest_event); + +done: + return ret; } 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; + uinfo->count = + sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data); return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h index 70ce20fbd8f8..6ffcbdbd543e 100644 --- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h +++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h @@ -14,12 +14,11 @@ #include int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd, - const char *mixer_ctl_name, uint32_t *payload); +int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd); +int msm_adsp_clean_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd); 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, diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index d79074d9521b..fe826cbcf111 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1675,7 +1675,7 @@ 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; + struct msm_adsp_event_data *pp_event_package = NULL; uint32_t payload_size = 0; if (ac == NULL) { @@ -2046,17 +2046,18 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) 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 + * package is composed of event type + size + actual payload */ payload_size = data->payload_size; - pp_event_package = - kzalloc(payload_size + sizeof(payload_size), + pp_event_package = kzalloc(payload_size + + sizeof(struct msm_adsp_event_data), 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), + + pp_event_package->event_type = ASM_STREAM_PP_EVENT; + pp_event_package->payload_len = payload_size; + memcpy((void *)pp_event_package->payload, data->payload, payload_size); ac->cb(data->opcode, data->token, (void *)pp_event_package, ac->priv);