Merge "ASoC: msm: enhance ADSP Stream Callback"

This commit is contained in:
Linux Build Service Account 2017-05-10 23:03:37 -07:00 committed by Gerrit - the friendly Code Review server
commit d575147a75
7 changed files with 249 additions and 90 deletions

View file

@ -15,6 +15,7 @@
#define _APR_AUDIO_V2_H_
#include <linux/qdsp6v2/apr.h>
#include <linux/msm_audio.h>
/* 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

View file

@ -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

View file

@ -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:

View file

@ -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:

View file

@ -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;
}

View file

@ -14,12 +14,11 @@
#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_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,

View file

@ -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);