Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 86a3429e authored by Xiaojun Sang's avatar Xiaojun Sang Committed by Banajit Goswami
Browse files

ASoC: msm: enhance ADSP Stream Callback



Implement FIFO queue for multiple callback events. Events are
cleaned at stream close.

Change-Id: Id738326a20613d2f939e45204b2d46448a5b4759
Signed-off-by: default avatarXiaojun Sang <xsang@codeaurora.org>
parent 57ab4fd8
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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
@@ -448,6 +449,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
+4 −4
Original line number Diff line number Diff line
@@ -751,8 +751,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);
@@ -1588,6 +1587,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;
}
@@ -1743,7 +1743,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->id]);
	pdata->audio_effects[soc_prtd->dai_link->id] = NULL;
	kfree(pdata->dec_params[soc_prtd->dai_link->id]);
@@ -3987,7 +3987,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,
		}
	};
@@ -4028,6 +4027,7 @@ static int msm_compr_add_audio_adsp_stream_callback_control(
	}

	kctl->private_data = NULL;

free_mixer_str:
	kfree(mixer_str);
done:
+4 −3
Original line number Diff line number Diff line
@@ -240,8 +240,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->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:
+208 −73
Original line number Diff line number Diff line
@@ -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;
@@ -821,18 +806,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__,
@@ -841,6 +941,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) {
@@ -858,21 +964,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;
}
@@ -881,72 +1025,63 @@ 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;
	uinfo->count =
		sizeof(((struct snd_ctl_elem_value *)0)->value.bytes.data);

	return 0;
}

int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol,
int msm_adsp_stream_callback_get(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));
	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) {
		/* 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;
		}
	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(kcontrol->private_data, ucontrol->value.bytes.data,
			sizeof(uint32_t) + payload_size);

	return 0;
	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;
	}

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

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

	return 0;
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;
}
+2 −3
Original line number Diff line number Diff line
@@ -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,
Loading